mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 14:04:54 +02:00
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:
parent
1a798a8e5b
commit
8dc3d77ba5
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user