162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/drivers/video/omap2/dss/overlay.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation 662306a36Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Some code and ideas taken from drivers/video/omap/ driver 962306a36Sopenharmony_ci * by Imre Deak. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define DSS_SUBSYS_NAME "OVERLAY" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/sysfs.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <video/omapfb_dss.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "dss.h" 2562306a36Sopenharmony_ci#include "dss_features.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int num_overlays; 2862306a36Sopenharmony_cistatic struct omap_overlay *overlays; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciint omap_dss_get_num_overlays(void) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci return num_overlays; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ciEXPORT_SYMBOL(omap_dss_get_num_overlays); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct omap_overlay *omap_dss_get_overlay(int num) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci if (num >= num_overlays) 3962306a36Sopenharmony_ci return NULL; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return &overlays[num]; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ciEXPORT_SYMBOL(omap_dss_get_overlay); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_civoid dss_init_overlays(struct platform_device *pdev) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci int i, r; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci num_overlays = dss_feat_get_num_ovls(); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci overlays = kcalloc(num_overlays, sizeof(struct omap_overlay), 5262306a36Sopenharmony_ci GFP_KERNEL); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci BUG_ON(overlays == NULL); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci for (i = 0; i < num_overlays; ++i) { 5762306a36Sopenharmony_ci struct omap_overlay *ovl = &overlays[i]; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci switch (i) { 6062306a36Sopenharmony_ci case 0: 6162306a36Sopenharmony_ci ovl->name = "gfx"; 6262306a36Sopenharmony_ci ovl->id = OMAP_DSS_GFX; 6362306a36Sopenharmony_ci break; 6462306a36Sopenharmony_ci case 1: 6562306a36Sopenharmony_ci ovl->name = "vid1"; 6662306a36Sopenharmony_ci ovl->id = OMAP_DSS_VIDEO1; 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci case 2: 6962306a36Sopenharmony_ci ovl->name = "vid2"; 7062306a36Sopenharmony_ci ovl->id = OMAP_DSS_VIDEO2; 7162306a36Sopenharmony_ci break; 7262306a36Sopenharmony_ci case 3: 7362306a36Sopenharmony_ci ovl->name = "vid3"; 7462306a36Sopenharmony_ci ovl->id = OMAP_DSS_VIDEO3; 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci ovl->caps = dss_feat_get_overlay_caps(ovl->id); 7962306a36Sopenharmony_ci ovl->supported_modes = 8062306a36Sopenharmony_ci dss_feat_get_supported_color_modes(ovl->id); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci r = dss_overlay_kobj_init(ovl, pdev); 8362306a36Sopenharmony_ci if (r) 8462306a36Sopenharmony_ci DSSERR("failed to create sysfs file\n"); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_civoid dss_uninit_overlays(struct platform_device *pdev) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci int i; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci for (i = 0; i < num_overlays; ++i) { 9362306a36Sopenharmony_ci struct omap_overlay *ovl = &overlays[i]; 9462306a36Sopenharmony_ci dss_overlay_kobj_uninit(ovl); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci kfree(overlays); 9862306a36Sopenharmony_ci overlays = NULL; 9962306a36Sopenharmony_ci num_overlays = 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciint dss_ovl_simple_check(struct omap_overlay *ovl, 10362306a36Sopenharmony_ci const struct omap_overlay_info *info) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { 10662306a36Sopenharmony_ci if (info->out_width != 0 && info->width != info->out_width) { 10762306a36Sopenharmony_ci DSSERR("check_overlay: overlay %d doesn't support " 10862306a36Sopenharmony_ci "scaling\n", ovl->id); 10962306a36Sopenharmony_ci return -EINVAL; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (info->out_height != 0 && info->height != info->out_height) { 11362306a36Sopenharmony_ci DSSERR("check_overlay: overlay %d doesn't support " 11462306a36Sopenharmony_ci "scaling\n", ovl->id); 11562306a36Sopenharmony_ci return -EINVAL; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if ((ovl->supported_modes & info->color_mode) == 0) { 12062306a36Sopenharmony_ci DSSERR("check_overlay: overlay %d doesn't support mode %d\n", 12162306a36Sopenharmony_ci ovl->id, info->color_mode); 12262306a36Sopenharmony_ci return -EINVAL; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (info->zorder >= omap_dss_get_num_overlays()) { 12662306a36Sopenharmony_ci DSSERR("check_overlay: zorder %d too high\n", info->zorder); 12762306a36Sopenharmony_ci return -EINVAL; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (dss_feat_rotation_type_supported(info->rotation_type) == 0) { 13162306a36Sopenharmony_ci DSSERR("check_overlay: rotation type %d not supported\n", 13262306a36Sopenharmony_ci info->rotation_type); 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ciint dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, 14062306a36Sopenharmony_ci const struct omap_video_timings *mgr_timings) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci u16 outw, outh; 14362306a36Sopenharmony_ci u16 dw, dh; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci dw = mgr_timings->x_res; 14662306a36Sopenharmony_ci dh = mgr_timings->y_res; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { 14962306a36Sopenharmony_ci outw = info->width; 15062306a36Sopenharmony_ci outh = info->height; 15162306a36Sopenharmony_ci } else { 15262306a36Sopenharmony_ci if (info->out_width == 0) 15362306a36Sopenharmony_ci outw = info->width; 15462306a36Sopenharmony_ci else 15562306a36Sopenharmony_ci outw = info->out_width; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (info->out_height == 0) 15862306a36Sopenharmony_ci outh = info->height; 15962306a36Sopenharmony_ci else 16062306a36Sopenharmony_ci outh = info->out_height; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (dw < info->pos_x + outw) { 16462306a36Sopenharmony_ci DSSERR("overlay %d horizontally not inside the display area " 16562306a36Sopenharmony_ci "(%d + %d >= %d)\n", 16662306a36Sopenharmony_ci ovl->id, info->pos_x, outw, dw); 16762306a36Sopenharmony_ci return -EINVAL; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (dh < info->pos_y + outh) { 17162306a36Sopenharmony_ci DSSERR("overlay %d vertically not inside the display area " 17262306a36Sopenharmony_ci "(%d + %d >= %d)\n", 17362306a36Sopenharmony_ci ovl->id, info->pos_y, outh, dh); 17462306a36Sopenharmony_ci return -EINVAL; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * Checks if replication logic should be used. Only use when overlay is in 18262306a36Sopenharmony_ci * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_cibool dss_ovl_use_replication(struct dss_lcd_mgr_config config, 18562306a36Sopenharmony_ci enum omap_color_mode mode) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) 18862306a36Sopenharmony_ci return false; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return config.video_port_width > 16; 19162306a36Sopenharmony_ci} 192