18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/drivers/video/omap2/dss/overlay.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation 68c2ecf20Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Some code and ideas taken from drivers/video/omap/ driver 98c2ecf20Sopenharmony_ci * by Imre Deak. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define DSS_SUBSYS_NAME "OVERLAY" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <video/omapfb_dss.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "dss.h" 258c2ecf20Sopenharmony_ci#include "dss_features.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int num_overlays; 288c2ecf20Sopenharmony_cistatic struct omap_overlay *overlays; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciint omap_dss_get_num_overlays(void) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci return num_overlays; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_dss_get_num_overlays); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct omap_overlay *omap_dss_get_overlay(int num) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci if (num >= num_overlays) 398c2ecf20Sopenharmony_ci return NULL; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return &overlays[num]; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_dss_get_overlay); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_civoid dss_init_overlays(struct platform_device *pdev) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int i, r; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci num_overlays = dss_feat_get_num_ovls(); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci overlays = kcalloc(num_overlays, sizeof(struct omap_overlay), 528c2ecf20Sopenharmony_ci GFP_KERNEL); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci BUG_ON(overlays == NULL); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci for (i = 0; i < num_overlays; ++i) { 578c2ecf20Sopenharmony_ci struct omap_overlay *ovl = &overlays[i]; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci switch (i) { 608c2ecf20Sopenharmony_ci case 0: 618c2ecf20Sopenharmony_ci ovl->name = "gfx"; 628c2ecf20Sopenharmony_ci ovl->id = OMAP_DSS_GFX; 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci case 1: 658c2ecf20Sopenharmony_ci ovl->name = "vid1"; 668c2ecf20Sopenharmony_ci ovl->id = OMAP_DSS_VIDEO1; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case 2: 698c2ecf20Sopenharmony_ci ovl->name = "vid2"; 708c2ecf20Sopenharmony_ci ovl->id = OMAP_DSS_VIDEO2; 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci case 3: 738c2ecf20Sopenharmony_ci ovl->name = "vid3"; 748c2ecf20Sopenharmony_ci ovl->id = OMAP_DSS_VIDEO3; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ovl->caps = dss_feat_get_overlay_caps(ovl->id); 798c2ecf20Sopenharmony_ci ovl->supported_modes = 808c2ecf20Sopenharmony_ci dss_feat_get_supported_color_modes(ovl->id); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci r = dss_overlay_kobj_init(ovl, pdev); 838c2ecf20Sopenharmony_ci if (r) 848c2ecf20Sopenharmony_ci DSSERR("failed to create sysfs file\n"); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_civoid dss_uninit_overlays(struct platform_device *pdev) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci int i; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci for (i = 0; i < num_overlays; ++i) { 938c2ecf20Sopenharmony_ci struct omap_overlay *ovl = &overlays[i]; 948c2ecf20Sopenharmony_ci dss_overlay_kobj_uninit(ovl); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci kfree(overlays); 988c2ecf20Sopenharmony_ci overlays = NULL; 998c2ecf20Sopenharmony_ci num_overlays = 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ciint dss_ovl_simple_check(struct omap_overlay *ovl, 1038c2ecf20Sopenharmony_ci const struct omap_overlay_info *info) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { 1068c2ecf20Sopenharmony_ci if (info->out_width != 0 && info->width != info->out_width) { 1078c2ecf20Sopenharmony_ci DSSERR("check_overlay: overlay %d doesn't support " 1088c2ecf20Sopenharmony_ci "scaling\n", ovl->id); 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (info->out_height != 0 && info->height != info->out_height) { 1138c2ecf20Sopenharmony_ci DSSERR("check_overlay: overlay %d doesn't support " 1148c2ecf20Sopenharmony_ci "scaling\n", ovl->id); 1158c2ecf20Sopenharmony_ci return -EINVAL; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if ((ovl->supported_modes & info->color_mode) == 0) { 1208c2ecf20Sopenharmony_ci DSSERR("check_overlay: overlay %d doesn't support mode %d\n", 1218c2ecf20Sopenharmony_ci ovl->id, info->color_mode); 1228c2ecf20Sopenharmony_ci return -EINVAL; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (info->zorder >= omap_dss_get_num_overlays()) { 1268c2ecf20Sopenharmony_ci DSSERR("check_overlay: zorder %d too high\n", info->zorder); 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (dss_feat_rotation_type_supported(info->rotation_type) == 0) { 1318c2ecf20Sopenharmony_ci DSSERR("check_overlay: rotation type %d not supported\n", 1328c2ecf20Sopenharmony_ci info->rotation_type); 1338c2ecf20Sopenharmony_ci return -EINVAL; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciint dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, 1408c2ecf20Sopenharmony_ci const struct omap_video_timings *mgr_timings) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci u16 outw, outh; 1438c2ecf20Sopenharmony_ci u16 dw, dh; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci dw = mgr_timings->x_res; 1468c2ecf20Sopenharmony_ci dh = mgr_timings->y_res; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { 1498c2ecf20Sopenharmony_ci outw = info->width; 1508c2ecf20Sopenharmony_ci outh = info->height; 1518c2ecf20Sopenharmony_ci } else { 1528c2ecf20Sopenharmony_ci if (info->out_width == 0) 1538c2ecf20Sopenharmony_ci outw = info->width; 1548c2ecf20Sopenharmony_ci else 1558c2ecf20Sopenharmony_ci outw = info->out_width; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (info->out_height == 0) 1588c2ecf20Sopenharmony_ci outh = info->height; 1598c2ecf20Sopenharmony_ci else 1608c2ecf20Sopenharmony_ci outh = info->out_height; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (dw < info->pos_x + outw) { 1648c2ecf20Sopenharmony_ci DSSERR("overlay %d horizontally not inside the display area " 1658c2ecf20Sopenharmony_ci "(%d + %d >= %d)\n", 1668c2ecf20Sopenharmony_ci ovl->id, info->pos_x, outw, dw); 1678c2ecf20Sopenharmony_ci return -EINVAL; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (dh < info->pos_y + outh) { 1718c2ecf20Sopenharmony_ci DSSERR("overlay %d vertically not inside the display area " 1728c2ecf20Sopenharmony_ci "(%d + %d >= %d)\n", 1738c2ecf20Sopenharmony_ci ovl->id, info->pos_y, outh, dh); 1748c2ecf20Sopenharmony_ci return -EINVAL; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* 1818c2ecf20Sopenharmony_ci * Checks if replication logic should be used. Only use when overlay is in 1828c2ecf20Sopenharmony_ci * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cibool dss_ovl_use_replication(struct dss_lcd_mgr_config config, 1858c2ecf20Sopenharmony_ci enum omap_color_mode mode) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) 1888c2ecf20Sopenharmony_ci return false; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return config.video_port_width > 16; 1918c2ecf20Sopenharmony_ci} 192