1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/drivers/video/omap2/dss/overlay.c 4 * 5 * Copyright (C) 2009 Nokia Corporation 6 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 7 * 8 * Some code and ideas taken from drivers/video/omap/ driver 9 * by Imre Deak. 10 */ 11 12 #define DSS_SUBSYS_NAME "OVERLAY" 13 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/err.h> 17 #include <linux/export.h> 18 #include <linux/sysfs.h> 19 #include <linux/platform_device.h> 20 #include <linux/delay.h> 21 #include <linux/slab.h> 22 23 #include <video/omapfb_dss.h> 24 25 #include "dss.h" 26 #include "dss_features.h" 27 28 static int num_overlays; 29 static struct omap_overlay *overlays; 30 31 int omap_dss_get_num_overlays(void) 32 { 33 return num_overlays; 34 } 35 EXPORT_SYMBOL(omap_dss_get_num_overlays); 36 37 struct omap_overlay *omap_dss_get_overlay(int num) 38 { 39 if (num >= num_overlays) 40 return NULL; 41 42 return &overlays[num]; 43 } 44 EXPORT_SYMBOL(omap_dss_get_overlay); 45 46 void dss_init_overlays(struct platform_device *pdev) 47 { 48 int i, r; 49 50 num_overlays = dss_feat_get_num_ovls(); 51 52 overlays = kcalloc(num_overlays, sizeof(struct omap_overlay), 53 GFP_KERNEL); 54 55 BUG_ON(overlays == NULL); 56 57 for (i = 0; i < num_overlays; ++i) { 58 struct omap_overlay *ovl = &overlays[i]; 59 60 switch (i) { 61 case 0: 62 ovl->name = "gfx"; 63 ovl->id = OMAP_DSS_GFX; 64 break; 65 case 1: 66 ovl->name = "vid1"; 67 ovl->id = OMAP_DSS_VIDEO1; 68 break; 69 case 2: 70 ovl->name = "vid2"; 71 ovl->id = OMAP_DSS_VIDEO2; 72 break; 73 case 3: 74 ovl->name = "vid3"; 75 ovl->id = OMAP_DSS_VIDEO3; 76 break; 77 } 78 79 ovl->caps = dss_feat_get_overlay_caps(ovl->id); 80 ovl->supported_modes = 81 dss_feat_get_supported_color_modes(ovl->id); 82 83 r = dss_overlay_kobj_init(ovl, pdev); 84 if (r) 85 DSSERR("failed to create sysfs file\n"); 86 } 87 } 88 89 void dss_uninit_overlays(struct platform_device *pdev) 90 { 91 int i; 92 93 for (i = 0; i < num_overlays; ++i) { 94 struct omap_overlay *ovl = &overlays[i]; 95 dss_overlay_kobj_uninit(ovl); 96 } 97 98 kfree(overlays); 99 overlays = NULL; 100 num_overlays = 0; 101 } 102 103 int dss_ovl_simple_check(struct omap_overlay *ovl, 104 const struct omap_overlay_info *info) 105 { 106 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { 107 if (info->out_width != 0 && info->width != info->out_width) { 108 DSSERR("check_overlay: overlay %d doesn't support " 109 "scaling\n", ovl->id); 110 return -EINVAL; 111 } 112 113 if (info->out_height != 0 && info->height != info->out_height) { 114 DSSERR("check_overlay: overlay %d doesn't support " 115 "scaling\n", ovl->id); 116 return -EINVAL; 117 } 118 } 119 120 if ((ovl->supported_modes & info->color_mode) == 0) { 121 DSSERR("check_overlay: overlay %d doesn't support mode %d\n", 122 ovl->id, info->color_mode); 123 return -EINVAL; 124 } 125 126 if (info->zorder >= omap_dss_get_num_overlays()) { 127 DSSERR("check_overlay: zorder %d too high\n", info->zorder); 128 return -EINVAL; 129 } 130 131 if (dss_feat_rotation_type_supported(info->rotation_type) == 0) { 132 DSSERR("check_overlay: rotation type %d not supported\n", 133 info->rotation_type); 134 return -EINVAL; 135 } 136 137 return 0; 138 } 139 140 int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, 141 const struct omap_video_timings *mgr_timings) 142 { 143 u16 outw, outh; 144 u16 dw, dh; 145 146 dw = mgr_timings->x_res; 147 dh = mgr_timings->y_res; 148 149 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { 150 outw = info->width; 151 outh = info->height; 152 } else { 153 if (info->out_width == 0) 154 outw = info->width; 155 else 156 outw = info->out_width; 157 158 if (info->out_height == 0) 159 outh = info->height; 160 else 161 outh = info->out_height; 162 } 163 164 if (dw < info->pos_x + outw) { 165 DSSERR("overlay %d horizontally not inside the display area " 166 "(%d + %d >= %d)\n", 167 ovl->id, info->pos_x, outw, dw); 168 return -EINVAL; 169 } 170 171 if (dh < info->pos_y + outh) { 172 DSSERR("overlay %d vertically not inside the display area " 173 "(%d + %d >= %d)\n", 174 ovl->id, info->pos_y, outh, dh); 175 return -EINVAL; 176 } 177 178 return 0; 179 } 180 181 /* 182 * Checks if replication logic should be used. Only use when overlay is in 183 * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp 184 */ 185 bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, 186 enum omap_color_mode mode) 187 { 188 if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) 189 return false; 190 191 return config.video_port_width > 16; 192 } 193