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