drm/rockchip: vop: move plane calculate to atomic_check

Change-Id: Icb5ff0ae4290720e8b288f839df4c010eed72d18
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Sandy Huang <hjc@rock-chips.com>
This commit is contained in:
Sandy Huang
2019-06-06 18:06:38 +08:00
committed by Tao Huang
parent 1a798a8e5b
commit 8dc3d77ba5
8 changed files with 514 additions and 84 deletions

View File

@@ -62,8 +62,17 @@ struct rockchip_drm_mode_set {
int hdisplay;
int vdisplay;
int vrefresh;
int flags;
int crtc_hsync_end;
int crtc_vsync_end;
int left_margin;
int right_margin;
int top_margin;
int bottom_margin;
bool mode_changed;
bool ymirror;
int ratio;
};
@@ -108,24 +117,206 @@ static struct drm_connector *find_connector_by_node(struct drm_device *drm_dev,
return NULL;
}
static
struct drm_connector *find_connector_by_bridge(struct drm_device *drm_dev,
struct device_node *node)
{
struct device_node *np_encoder, *np_connector = NULL;
struct drm_encoder *encoder;
struct drm_connector *connector = NULL;
struct device_node *port, *endpoint;
bool encoder_bridge = false;
bool found_connector = false;
struct drm_connector_list_iter conn_iter;
np_encoder = of_graph_get_remote_port_parent(node);
if (!np_encoder || !of_device_is_available(np_encoder))
goto err_put_encoder;
drm_for_each_encoder(encoder, drm_dev) {
if (encoder->port == np_encoder && encoder->bridge) {
encoder_bridge = true;
break;
}
}
if (!encoder_bridge) {
dev_err(drm_dev->dev, "can't found encoder bridge!\n");
goto err_put_encoder;
}
port = of_graph_get_port_by_id(np_encoder, 1);
if (!port) {
dev_err(drm_dev->dev, "can't found port point!\n");
goto err_put_encoder;
}
for_each_child_of_node(port, endpoint) {
np_connector = of_graph_get_remote_port_parent(endpoint);
if (!np_connector) {
dev_err(drm_dev->dev,
"can't found connector node, please init!\n");
goto err_put_port;
}
if (!of_device_is_available(np_connector)) {
of_node_put(np_connector);
np_connector = NULL;
continue;
} else {
break;
}
}
if (!np_connector) {
dev_err(drm_dev->dev, "can't found available connector node!\n");
goto err_put_port;
}
drm_connector_list_iter_begin(drm_dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->port == np_connector) {
drm_connector_list_iter_end(&conn_iter);
found_connector = true;
break;
}
}
drm_connector_list_iter_end(&conn_iter);
if (!found_connector)
connector = NULL;
of_node_put(np_connector);
err_put_port:
of_node_put(port);
err_put_encoder:
of_node_put(np_encoder);
return connector;
}
static void rockchip_free_loader_memory(struct drm_device *drm)
{
struct rockchip_drm_private *private = drm->dev_private;
struct rockchip_logo *logo;
void *start, *end;
if (!private || !private->logo/* || --private->logo->count*/)
return;
logo = private->logo;
start = phys_to_virt(logo->start);
end = phys_to_virt(logo->start + logo->size);
if (private->domain) {
iommu_unmap(private->domain, logo->dma_addr,
logo->iommu_map_size);
drm_mm_remove_node(&logo->mm);
} else {
dma_unmap_sg(drm->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");
kfree(logo);
private->logo = NULL;
}
static int init_loader_memory(struct drm_device *drm_dev)
{
struct rockchip_drm_private *private = drm_dev->dev_private;
struct rockchip_logo *logo;
struct device_node *np = drm_dev->dev->of_node;
struct device_node *node;
unsigned long nr_pages;
struct page **pages;
struct sg_table *sgt;
phys_addr_t start, size;
struct resource res;
int i, ret;
node = of_parse_phandle(np, "logo-memory-region", 0);
if (!node)
return -ENOMEM;
ret = of_address_to_resource(node, 0, &res);
if (ret)
return ret;
start = res.start;
size = resource_size(&res);
if (!size)
return -ENOMEM;
logo = kmalloc(sizeof(*logo), GFP_KERNEL);
if (!logo)
return -ENOMEM;
logo->kvaddr = phys_to_virt(start);
nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
pages = kmalloc_array(nr_pages, sizeof(*pages), GFP_KERNEL);
if (!pages)
goto err_free_logo;
i = 0;
while (i < nr_pages) {
pages[i] = phys_to_page(start);
start += PAGE_SIZE;
i++;
}
sgt = drm_prime_pages_to_sg(pages, nr_pages);
if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto err_free_pages;
}
if (private->domain) {
memset(&logo->mm, 0, sizeof(logo->mm));
ret = drm_mm_insert_node_generic(&private->mm, &logo->mm,
size, PAGE_SIZE,
0, 0);
if (ret < 0) {
DRM_ERROR("out of I/O virtual memory: %d\n", ret);
goto err_free_pages;
}
logo->dma_addr = logo->mm.start;
logo->iommu_map_size = iommu_map_sg(private->domain,
logo->dma_addr, sgt->sgl,
sgt->nents, IOMMU_READ);
if (logo->iommu_map_size < size) {
DRM_ERROR("failed to map buffer");
ret = -ENOMEM;
goto err_remove_node;
}
} else {
dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE);
logo->dma_addr = sg_dma_address(sgt->sgl);
}
logo->sgt = sgt;
logo->start = res.start;
logo->size = size;
logo->count = 1;
private->logo = logo;
return 0;
err_remove_node:
drm_mm_remove_node(&logo->mm);
err_free_pages:
kfree(pages);
err_free_logo:
kfree(logo);
return ret;
}
static struct drm_framebuffer *
get_framebuffer_by_node(struct drm_device *drm_dev, struct device_node *node)
{
struct rockchip_drm_private *private = drm_dev->dev_private;
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct device_node *memory;
struct resource res;
u32 val;
int bpp;
memory = of_parse_phandle(node, "logo,mem", 0);
if (!memory)
if (WARN_ON(!private->logo))
return NULL;
if (of_address_to_resource(memory, 0, &res)) {
pr_err("%s: could not get bootram phy addr\n", __func__);
return NULL;
}
if (of_property_read_u32(node, "logo,offset", &val)) {
pr_err("%s: failed to get logo,offset\n", __func__);
return NULL;
@@ -150,10 +341,24 @@ get_framebuffer_by_node(struct drm_device *drm_dev, struct device_node *node)
}
bpp = val;
mode_cmd.pitches[0] = mode_cmd.width * bpp / 8;
mode_cmd.pixel_format = DRM_FORMAT_BGR888;
mode_cmd.pitches[0] = ALIGN(mode_cmd.width * bpp, 32) / 8;
return rockchip_fb_alloc(drm_dev, &mode_cmd, NULL, &res, 1);
switch (bpp) {
case 16:
mode_cmd.pixel_format = DRM_FORMAT_BGR565;
break;
case 24:
mode_cmd.pixel_format = DRM_FORMAT_BGR888;
break;
case 32:
mode_cmd.pixel_format = DRM_FORMAT_XRGB8888;
break;
default:
pr_err("%s: unsupported to logo bpp %d\n", __func__, bpp);
return NULL;
}
return rockchip_fb_alloc(drm_dev, &mode_cmd, NULL, private->logo, 1);
}
static struct rockchip_drm_mode_set *
@@ -164,6 +369,7 @@ of_parse_display_resource(struct drm_device *drm_dev, struct device_node *route)
struct drm_framebuffer *fb;
struct drm_connector *connector;
struct drm_crtc *crtc;
const char *string;
u32 val;
connect = of_parse_phandle(route, "connect", 0);
@@ -176,6 +382,8 @@ of_parse_display_resource(struct drm_device *drm_dev, struct device_node *route)
crtc = find_crtc_by_node(drm_dev, connect);
connector = find_connector_by_node(drm_dev, connect);
if (!connector)
connector = find_connector_by_bridge(drm_dev, connect);
if (!crtc || !connector) {
dev_warn(drm_dev->dev,
"No available crtc or connector for display");
@@ -193,14 +401,41 @@ of_parse_display_resource(struct drm_device *drm_dev, struct device_node *route)
if (!of_property_read_u32(route, "video,vdisplay", &val))
set->vdisplay = val;
if (!of_property_read_u32(route, "video,crtc_hsync_end", &val))
set->crtc_hsync_end = val;
if (!of_property_read_u32(route, "video,crtc_vsync_end", &val))
set->crtc_vsync_end = val;
if (!of_property_read_u32(route, "video,vrefresh", &val))
set->vrefresh = val;
if (!of_property_read_u32(route, "video,flags", &val))
set->flags = val;
if (!of_property_read_u32(route, "logo,ymirror", &val))
set->ymirror = val;
if (!of_property_read_u32(route, "overscan,left_margin", &val))
set->left_margin = val;
if (!of_property_read_u32(route, "overscan,right_margin", &val))
set->right_margin = val;
if (!of_property_read_u32(route, "overscan,top_margin", &val))
set->top_margin = val;
if (!of_property_read_u32(route, "overscan,bottom_margin", &val))
set->bottom_margin = val;
set->ratio = 1;
if (!of_property_read_string(route, "logo,mode", &string) &&
!strcmp(string, "fullscreen"))
set->ratio = 0;
set->fb = fb;
set->crtc = crtc;
set->connector = connector;
/* TODO: set display fullscreen or center */
set->ratio = 0;
return set;
}
@@ -407,12 +642,13 @@ static int update_state(struct drm_device *drm_dev,
static void show_loader_logo(struct drm_device *drm_dev)
{
struct drm_atomic_state *state;
struct drm_atomic_state *state, *old_state;
struct device_node *np = drm_dev->dev->of_node;
struct drm_mode_config *mode_config = &drm_dev->mode_config;
struct device_node *root, *route;
struct rockchip_drm_mode_set *set, *tmp;
struct rockchip_drm_mode_set *set, *tmp, *unset;
struct list_head mode_set_list;
struct list_head mode_unset_list;
unsigned int plane_mask = 0;
int ret;
@@ -422,7 +658,13 @@ static void show_loader_logo(struct drm_device *drm_dev)
return;
}
if (init_loader_memory(drm_dev)) {
dev_warn(drm_dev->dev, "failed to parse loader memory\n");
return;
}
INIT_LIST_HEAD(&mode_set_list);
INIT_LIST_HEAD(&mode_unset_list);
drm_modeset_lock_all(drm_dev);
state = drm_atomic_state_alloc(drm_dev);
if (!state) {
@@ -439,13 +681,44 @@ static void show_loader_logo(struct drm_device *drm_dev)
if (setup_initial_state(drm_dev, state, set)) {
drm_framebuffer_put(set->fb);
kfree(set);
INIT_LIST_HEAD(&set->head);
list_add_tail(&set->head, &mode_unset_list);
continue;
}
INIT_LIST_HEAD(&set->head);
list_add_tail(&set->head, &mode_set_list);
}
/*
* the mode_unset_list store the unconnected route, if route's crtc
* isn't used, we should close it.
*/
list_for_each_entry_safe(unset, tmp, &mode_unset_list, head) {
struct rockchip_drm_mode_set *tmp_set;
int find_used_crtc = 0;
list_for_each_entry_safe(set, tmp_set, &mode_set_list, head) {
if (set->crtc == unset->crtc) {
find_used_crtc = 1;
continue;
}
}
#if 0
//todo
if (!find_used_crtc) {
struct drm_crtc *crtc = unset->crtc;
int pipe = drm_crtc_index(crtc);
struct rockchip_drm_private *priv =
drm_dev->dev_private;
if (unset->hdisplay && unset->vdisplay)
priv->crtc_funcs[pipe]->crtc_close(crtc);
}
#endif
list_del(&unset->head);
kfree(unset);
}
if (list_empty(&mode_set_list)) {
dev_warn(drm_dev->dev, "can't not find any loader display\n");
ret = -ENXIO;
@@ -459,12 +732,20 @@ static void show_loader_logo(struct drm_device *drm_dev)
*/
WARN_ON(drm_atomic_helper_swap_state(state, false));
drm_atomic_state_put(state);
old_state = drm_atomic_helper_duplicate_state(drm_dev,
mode_config->acquire_ctx);
if (IS_ERR(old_state)) {
dev_err(drm_dev->dev, "failed to duplicate atomic state\n");
ret = PTR_ERR_OR_ZERO(old_state);
goto err_free_state;
}
state = drm_atomic_helper_duplicate_state(drm_dev,
mode_config->acquire_ctx);
if (IS_ERR(state)) {
dev_err(drm_dev->dev, "failed to duplicate atomic state\n");
ret = PTR_ERR_OR_ZERO(state);
goto err_unlock;
goto err_free_old_state;
}
state->acquire_ctx = mode_config->acquire_ctx;
list_for_each_entry(set, &mode_set_list, head)
@@ -480,27 +761,8 @@ static void show_loader_logo(struct drm_device *drm_dev)
*/
list_for_each_entry_safe(set, tmp, &mode_set_list, head) {
struct drm_crtc *crtc = set->crtc;
list_del(&set->head);
kfree(set);
/* FIXME:
* primary plane state rotation is not BIT(0), but we only want
* it effect on logo display, userspace may not known to clean
* this property, would get unexpect display, so force set
* primary rotation to BIT(0).
*/
if (!crtc->primary || !crtc->primary->state)
continue;
/**
* todo
* drm_atomic_plane_set_property(crtc->primary,
* crtc->primary->state,
* mode_config->rotation_property,
* BIT(0));
*/
}
/*
@@ -508,12 +770,21 @@ static void show_loader_logo(struct drm_device *drm_dev)
*/
WARN_ON(ret == -EDEADLK);
if (ret)
if (ret) {
/*
* restore display status if atomic commit failed.
*/
WARN_ON(drm_atomic_helper_swap_state(old_state, false));
goto err_free_state;
}
rockchip_free_loader_memory(drm_dev);
drm_atomic_state_put(old_state);
drm_modeset_unlock_all(drm_dev);
return;
err_free_old_state:
drm_atomic_state_put(old_state);
err_free_state:
drm_atomic_state_put(state);
err_unlock:

View File

@@ -42,6 +42,17 @@ struct rockchip_crtc_state {
#define to_rockchip_crtc_state(s) \
container_of(s, struct rockchip_crtc_state, base)
struct rockchip_logo {
struct sg_table *sgt;
struct drm_mm_node mm;
dma_addr_t dma_addr;
void *kvaddr;
phys_addr_t start;
phys_addr_t size;
size_t iommu_map_size;
int count;
};
/*
* Rockchip drm private structure.
*
@@ -50,6 +61,7 @@ struct rockchip_crtc_state {
* @mm_lock: protect drm_mm on multi-threads.
*/
struct rockchip_drm_private {
struct rockchip_logo *logo;
struct drm_fb_helper *fbdev_helper;
struct drm_gem_object *fbdev_bo;
struct drm_atomic_state *state;

View File

@@ -27,15 +27,22 @@
#include "rockchip_drm_psr.h"
#define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
struct rockchip_drm_fb {
struct drm_framebuffer fb;
dma_addr_t dma_addr[ROCKCHIP_MAX_FB_BUFFER];
void *kvaddr[ROCKCHIP_MAX_FB_BUFFER];
struct drm_gem_object *obj[ROCKCHIP_MAX_FB_BUFFER];
struct sg_table *sgt;
phys_addr_t start;
phys_addr_t size;
struct rockchip_logo *logo;
};
bool rockchip_fb_is_logo(struct drm_framebuffer *fb)
{
struct rockchip_drm_fb *rk_fb = to_rockchip_fb(fb);
return rk_fb && rk_fb->logo;
}
dma_addr_t rockchip_fb_get_dma_addr(struct drm_framebuffer *fb,
unsigned int plane)
{
@@ -47,6 +54,16 @@ dma_addr_t rockchip_fb_get_dma_addr(struct drm_framebuffer *fb,
return rk_fb->dma_addr[plane];
}
void *rockchip_fb_get_kvaddr(struct drm_framebuffer *fb, unsigned int plane)
{
struct rockchip_drm_fb *rk_fb = to_rockchip_fb(fb);
if (WARN_ON(plane >= ROCKCHIP_MAX_FB_BUFFER))
return 0;
return rk_fb->kvaddr[plane];
}
static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
{
struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
@@ -73,11 +90,13 @@ static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
struct drm_framebuffer *
rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **obj, struct resource *res,
struct drm_gem_object **obj, struct rockchip_logo *logo,
unsigned int num_planes)
{
struct rockchip_drm_fb *rockchip_fb;
struct rockchip_gem_object *rk_obj;
struct rockchip_drm_private *private = dev->dev_private;
struct drm_fb_helper *fb_helper = private->fbdev_helper;
int ret = 0;
int i;
@@ -102,9 +121,16 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
for (i = 0; i < num_planes; i++) {
rk_obj = to_rockchip_obj(obj[i]);
rockchip_fb->dma_addr[i] = rk_obj->dma_addr;
rockchip_fb->kvaddr[i] = rk_obj->kvaddr;
private->fbdev_bo = &rk_obj->base;
if (fb_helper && fb_helper->fbdev && rk_obj->kvaddr)
fb_helper->fbdev->screen_base = rk_obj->kvaddr;
}
} else if (res) {
/* todo for kernel logo */
} else if (logo) {
rockchip_fb->dma_addr[0] = logo->dma_addr;
rockchip_fb->kvaddr[0] = logo->kvaddr;
rockchip_fb->logo = logo;
logo->count++;
} else {
ret = -EINVAL;
dev_err(dev->dev, "Failed to find available buffer\n");

View File

@@ -15,6 +15,7 @@
#ifndef _ROCKCHIP_DRM_FB_H
#define _ROCKCHIP_DRM_FB_H
bool rockchip_fb_is_logo(struct drm_framebuffer *fb);
struct drm_framebuffer *
rockchip_drm_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd,
@@ -25,9 +26,10 @@ void rockchip_drm_mode_config_init(struct drm_device *dev);
struct drm_framebuffer *
rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **obj, struct resource *res,
struct drm_gem_object **obj, struct rockchip_logo *logo,
unsigned int num_planes);
dma_addr_t rockchip_fb_get_dma_addr(struct drm_framebuffer *fb,
unsigned int plane);
void *rockchip_fb_get_kvaddr(struct drm_framebuffer *fb, unsigned int plane);
#endif /* _ROCKCHIP_DRM_FB_H */

View File

@@ -101,6 +101,7 @@
#define to_vop(x) container_of(x, struct vop, crtc)
#define to_vop_win(x) container_of(x, struct vop_win, base)
#define to_vop_plane_state(x) container_of(x, struct vop_plane_state, base)
/*
* The coefficients of the following matrix are all fixed points.
@@ -124,7 +125,29 @@ struct vop_zpos {
};
struct vop_plane_state {
struct drm_plane_state base;
int format;
int zpos;
unsigned int logo_ymirror;
struct drm_rect src;
struct drm_rect dest;
dma_addr_t yrgb_mst;
dma_addr_t uv_mst;
void *yrgb_kvaddr;
const uint32_t *y2r_table;
const uint32_t *r2r_table;
const uint32_t *r2y_table;
int eotf;
bool y2r_en;
bool r2r_en;
bool r2y_en;
int color_space;
unsigned int csc_mode;
bool enable;
int global_alpha;
int blend_mode;
unsigned long offset;
int pdaf_data_type;
};
struct vop_win {
@@ -703,11 +726,19 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
struct drm_crtc_state *crtc_state;
struct drm_framebuffer *fb = state->fb;
struct vop_win *win = to_vop_win(plane);
struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
const struct vop_data *vop_data;
struct vop *vop;
int ret;
struct drm_rect *dest = &vop_plane_state->dest;
struct drm_rect *src = &vop_plane_state->src;
int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
DRM_PLANE_HELPER_NO_SCALING;
int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
DRM_PLANE_HELPER_NO_SCALING;
unsigned long offset;
dma_addr_t dma_addr;
void *kvaddr;
if (!crtc || !fb)
return 0;
@@ -716,6 +747,15 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
if (WARN_ON(!crtc_state))
return -EINVAL;
src->x1 = state->src_x;
src->y1 = state->src_y;
src->x2 = state->src_x + state->src_w;
src->y2 = state->src_y + state->src_h;
dest->x1 = state->crtc_x;
dest->y1 = state->crtc_y;
dest->x2 = state->crtc_x + state->crtc_w;
dest->y2 = state->crtc_y + state->crtc_h;
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
min_scale, max_scale,
true, true);
@@ -725,9 +765,22 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
if (!state->visible)
return 0;
ret = vop_convert_format(fb->format->format);
if (ret < 0)
return ret;
vop_plane_state->format = vop_convert_format(fb->format->format);
if (vop_plane_state->format < 0)
return vop_plane_state->format;
vop = to_vop(crtc);
vop_data = vop->data;
if (drm_rect_width(src) >> 16 > vop_data->max_input.width ||
drm_rect_height(src) >> 16 > vop_data->max_input.height) {
DRM_ERROR("Invalid source: %dx%d. max input: %dx%d\n",
drm_rect_width(src) >> 16,
drm_rect_height(src) >> 16,
vop_data->max_input.width,
vop_data->max_input.height);
return -EINVAL;
}
/*
* Src.x1 can be odd when do clip, but yuv plane start point
@@ -743,6 +796,30 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
return -EINVAL;
}
offset = (src->x1 >> 16) * fb->format->cpp[0];
vop_plane_state->offset = offset + fb->offsets[0];
if (state->rotation & DRM_MODE_REFLECT_Y ||
(rockchip_fb_is_logo(fb) && vop_plane_state->logo_ymirror))
offset += ((src->y2 >> 16) - 1) * fb->pitches[0];
else
offset += (src->y1 >> 16) * fb->pitches[0];
dma_addr = rockchip_fb_get_dma_addr(fb, 0);
kvaddr = rockchip_fb_get_kvaddr(fb, 0);
vop_plane_state->yrgb_mst = dma_addr + offset + fb->offsets[0];
vop_plane_state->yrgb_kvaddr = kvaddr + offset + fb->offsets[0];
if (fb->format->is_yuv) {
int hsub = drm_format_horz_chroma_subsampling(fb->format->format);
int vsub = drm_format_vert_chroma_subsampling(fb->format->format);
offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub;
offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
dma_addr = rockchip_fb_get_dma_addr(fb, 1);
dma_addr += offset + fb->offsets[1];
vop_plane_state->uv_mst = dma_addr;
}
return 0;
}
@@ -768,20 +845,18 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *state = plane->state;
struct drm_crtc *crtc = state->crtc;
const struct vop_win *win = to_vop_win(plane);
struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
const struct vop_win_yuv2yuv_data *win_yuv2yuv = win->yuv2yuv_data;
struct vop *vop = to_vop(state->crtc);
struct drm_framebuffer *fb = state->fb;
unsigned int actual_w, actual_h;
unsigned int dsp_stx, dsp_sty;
uint32_t act_info, dsp_info, dsp_st;
struct drm_rect *src = &state->src;
struct drm_rect *dest = &state->dst;
unsigned long offset;
dma_addr_t dma_addr;
struct drm_rect *src = &vop_plane_state->src;
struct drm_rect *dest = &vop_plane_state->dest;
uint32_t val;
bool rb_swap;
int win_index = VOP_WIN_TO_INDEX(win);
int format;
int is_yuv = fb->format->is_yuv;
int i;
@@ -810,25 +885,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start;
dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff);
offset = (src->x1 >> 16) * fb->format->cpp[0];
offset += (src->y1 >> 16) * fb->pitches[0];
dma_addr = rockchip_fb_get_dma_addr(fb, 0);
dma_addr += offset + fb->offsets[0];
/*
* For y-mirroring we need to move address
* to the beginning of the last line.
*/
if (state->rotation & DRM_MODE_REFLECT_Y)
dma_addr += (actual_h - 1) * fb->pitches[0];
format = vop_convert_format(fb->format->format);
spin_lock(&vop->reg_lock);
VOP_WIN_SET(vop, win, format, format);
VOP_WIN_SET(vop, win, format, vop_plane_state->format);
VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
VOP_WIN_SET(vop, win, yrgb_mst, vop_plane_state->yrgb_mst);
VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv);
VOP_WIN_SET(vop, win, y_mir_en,
(state->rotation & DRM_MODE_REFLECT_Y) ? 1 : 0);
@@ -836,18 +897,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
(state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0);
if (is_yuv) {
int hsub = drm_format_horz_chroma_subsampling(fb->format->format);
int vsub = drm_format_vert_chroma_subsampling(fb->format->format);
int bpp = fb->format->cpp[1];
offset = (src->x1 >> 16) * bpp / hsub;
offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
dma_addr = rockchip_fb_get_dma_addr(fb, 1);
dma_addr += offset + fb->offsets[1];
VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4));
VOP_WIN_SET(vop, win, uv_mst, dma_addr);
VOP_WIN_SET(vop, win, uv_mst, vop_plane_state->yrgb_mst);
for (i = 0; i < NUM_YUV2YUV_COEFFICIENTS; i++) {
VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop,
@@ -906,10 +957,51 @@ static void vop_plane_destroy(struct drm_plane *plane)
static void vop_plane_reset(struct drm_plane *plane)
{
struct vop_plane_state *vop_plane_state =
to_vop_plane_state(plane->state);
struct vop_win *win = to_vop_win(plane);
drm_atomic_helper_plane_reset(plane);
kfree(vop_plane_state);
vop_plane_state = kzalloc(sizeof(*vop_plane_state), GFP_KERNEL);
if (!vop_plane_state)
return;
win->state.zpos = win->win_id;
vop_plane_state->global_alpha = 0xff;
plane->state = &vop_plane_state->base;
plane->state->plane = plane;
}
static struct drm_plane_state *
vop_atomic_plane_duplicate_state(struct drm_plane *plane)
{
struct vop_plane_state *old_vop_plane_state;
struct vop_plane_state *vop_plane_state;
if (WARN_ON(!plane->state))
return NULL;
old_vop_plane_state = to_vop_plane_state(plane->state);
vop_plane_state = kmemdup(old_vop_plane_state,
sizeof(*vop_plane_state), GFP_KERNEL);
if (!vop_plane_state)
return NULL;
__drm_atomic_helper_plane_duplicate_state(plane,
&vop_plane_state->base);
return &vop_plane_state->base;
}
static void vop_atomic_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct vop_plane_state *vop_state = to_vop_plane_state(state);
__drm_atomic_helper_plane_destroy_state(state);
kfree(vop_state);
}
static int vop_atomic_plane_set_property(struct drm_plane *plane,
@@ -951,8 +1043,8 @@ static const struct drm_plane_funcs vop_plane_funcs = {
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = vop_plane_destroy,
.reset = vop_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.atomic_duplicate_state = vop_atomic_plane_duplicate_state,
.atomic_destroy_state = vop_atomic_plane_destroy_state,
.atomic_set_property = vop_atomic_plane_set_property,
.atomic_get_property = vop_atomic_plane_get_property,
};

View File

@@ -169,6 +169,11 @@ struct vop_win_data {
unsigned int area_size;
};
struct vop_rect {
int width;
int height;
};
struct vop_data {
uint32_t version;
const struct vop_intr *intr;
@@ -180,6 +185,9 @@ struct vop_data {
const struct vop_win_data *win;
unsigned int win_size;
struct vop_rect max_input;
struct vop_rect max_output;
#define VOP_FEATURE_OUTPUT_RGB10 BIT(0)
u64 feature;
};

View File

@@ -142,6 +142,8 @@ static const struct vop_common rk3036_common = {
};
static const struct vop_data rk3036_vop = {
.max_input = {1920, 8192},
.max_output = {1920, 1080},
.intr = &rk3036_intr,
.common = &rk3036_common,
.modeset = &rk3036_modeset,
@@ -170,6 +172,8 @@ static const struct vop_win_data rk3126_vop_win_data[] = {
};
static const struct vop_data rk3126_vop = {
.max_input = {1920, 8192},
.max_output = {1920, 1080},
.intr = &rk3036_intr,
.common = &rk3036_common,
.modeset = &rk3036_modeset,
@@ -344,6 +348,8 @@ static const struct vop_intr rk3288_vop_intr = {
static const struct vop_data rk3288_vop = {
.version = VOP_VERSION(3, 1),
.max_input = {4096, 8192},
.max_output = {4096, 2160},
.feature = VOP_FEATURE_OUTPUT_RGB10,
.intr = &rk3288_vop_intr,
.common = &rk3288_common,
@@ -457,6 +463,8 @@ static const struct vop_misc rk3368_misc = {
static const struct vop_data rk3368_vop = {
.version = VOP_VERSION(3, 2),
.max_input = {4096, 8192},
.max_output = {4096, 2160},
.intr = &rk3368_vop_intr,
.common = &rk3288_common,
.modeset = &rk3288_modeset,
@@ -478,6 +486,8 @@ static const struct vop_intr rk3366_vop_intr = {
static const struct vop_data rk3366_vop = {
.version = VOP_VERSION(3, 4),
.max_input = {4096, 8192},
.max_output = {4096, 2160},
.intr = &rk3366_vop_intr,
.common = &rk3288_common,
.modeset = &rk3288_modeset,
@@ -596,6 +606,8 @@ static const struct vop_win_data rk3399_vop_win_data[] = {
static const struct vop_data rk3399_vop_big = {
.version = VOP_VERSION(3, 5),
.feature = VOP_FEATURE_OUTPUT_RGB10,
.max_input = {4096, 8192},
.max_output = {4096, 2160},
.intr = &rk3366_vop_intr,
.common = &rk3288_common,
.modeset = &rk3288_modeset,
@@ -625,6 +637,8 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = {
static const struct vop_data rk3399_vop_lit = {
.version = VOP_VERSION(3, 6),
.max_input = {4096, 8192},
.max_output = {2560, 1600},
.intr = &rk3366_vop_intr,
.common = &rk3288_common,
.modeset = &rk3288_modeset,
@@ -645,6 +659,8 @@ static const struct vop_win_data rk3228_vop_win_data[] = {
static const struct vop_data rk3228_vop = {
.version = VOP_VERSION(3, 7),
.feature = VOP_FEATURE_OUTPUT_RGB10,
.max_input = {4096, 8192},
.max_output = {4096, 2160},
.intr = &rk3366_vop_intr,
.common = &rk3288_common,
.modeset = &rk3288_modeset,
@@ -711,6 +727,8 @@ static const struct vop_win_data rk3328_vop_win_data[] = {
static const struct vop_data rk3328_vop = {
.version = VOP_VERSION(3, 8),
.feature = VOP_FEATURE_OUTPUT_RGB10,
.max_input = {4096, 8192},
.max_output = {4096, 2160},
.intr = &rk3328_vop_intr,
.common = &rk3328_common,
.modeset = &rk3328_modeset,

View File

@@ -98,7 +98,8 @@ struct drm_encoder_funcs {
struct drm_encoder {
struct drm_device *dev;
struct list_head head;
/* @port: encoder device node */
struct device_node *port;
struct drm_mode_object base;
char *name;
/**