1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * vsp1_pipe.c -- R-Car VSP1 Pipeline 4 * 5 * Copyright (C) 2013-2015 Renesas Electronics Corporation 6 * 7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 8 */ 9 10 #include <linux/delay.h> 11 #include <linux/list.h> 12 #include <linux/lockdep.h> 13 #include <linux/sched.h> 14 #include <linux/wait.h> 15 16 #include <media/media-entity.h> 17 #include <media/v4l2-subdev.h> 18 19 #include "vsp1.h" 20 #include "vsp1_brx.h" 21 #include "vsp1_dl.h" 22 #include "vsp1_entity.h" 23 #include "vsp1_hgo.h" 24 #include "vsp1_hgt.h" 25 #include "vsp1_pipe.h" 26 #include "vsp1_rwpf.h" 27 #include "vsp1_uds.h" 28 29 /* ----------------------------------------------------------------------------- 30 * Helper Functions 31 */ 32 33 static const struct vsp1_format_info vsp1_video_formats[] = { 34 { V4L2_PIX_FMT_RGB332, MEDIA_BUS_FMT_ARGB8888_1X32, 35 VI6_FMT_RGB_332, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 36 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 37 1, { 8, 0, 0 }, false, false, 1, 1, false }, 38 { V4L2_PIX_FMT_ARGB444, MEDIA_BUS_FMT_ARGB8888_1X32, 39 VI6_FMT_ARGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 40 VI6_RPF_DSWAP_P_WDS, 41 1, { 16, 0, 0 }, false, false, 1, 1, true }, 42 { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32, 43 VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 44 VI6_RPF_DSWAP_P_WDS, 45 1, { 16, 0, 0 }, false, false, 1, 1, false }, 46 { V4L2_PIX_FMT_RGBA444, MEDIA_BUS_FMT_ARGB8888_1X32, 47 VI6_FMT_RGBA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 48 VI6_RPF_DSWAP_P_WDS, 49 1, { 16, 0, 0 }, false, false, 1, 1, true }, 50 { V4L2_PIX_FMT_RGBX444, MEDIA_BUS_FMT_ARGB8888_1X32, 51 VI6_FMT_RGBX_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 52 VI6_RPF_DSWAP_P_WDS, 53 1, { 16, 0, 0 }, false, false, 1, 1, false }, 54 { V4L2_PIX_FMT_ABGR444, MEDIA_BUS_FMT_ARGB8888_1X32, 55 VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 56 VI6_RPF_DSWAP_P_WDS, 57 1, { 16, 0, 0 }, false, false, 1, 1, true }, 58 { V4L2_PIX_FMT_XBGR444, MEDIA_BUS_FMT_ARGB8888_1X32, 59 VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 60 VI6_RPF_DSWAP_P_WDS, 61 1, { 16, 0, 0 }, false, false, 1, 1, false }, 62 { V4L2_PIX_FMT_BGRA444, MEDIA_BUS_FMT_ARGB8888_1X32, 63 VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 64 VI6_RPF_DSWAP_P_WDS, 65 1, { 16, 0, 0 }, false, false, 1, 1, true }, 66 { V4L2_PIX_FMT_BGRX444, MEDIA_BUS_FMT_ARGB8888_1X32, 67 VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 68 VI6_RPF_DSWAP_P_WDS, 69 1, { 16, 0, 0 }, false, false, 1, 1, false }, 70 { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32, 71 VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 72 VI6_RPF_DSWAP_P_WDS, 73 1, { 16, 0, 0 }, false, false, 1, 1, true }, 74 { V4L2_PIX_FMT_XRGB555, MEDIA_BUS_FMT_ARGB8888_1X32, 75 VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 76 VI6_RPF_DSWAP_P_WDS, 77 1, { 16, 0, 0 }, false, false, 1, 1, false }, 78 { V4L2_PIX_FMT_RGBA555, MEDIA_BUS_FMT_ARGB8888_1X32, 79 VI6_FMT_RGBA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 80 VI6_RPF_DSWAP_P_WDS, 81 1, { 16, 0, 0 }, false, false, 1, 1, true }, 82 { V4L2_PIX_FMT_RGBX555, MEDIA_BUS_FMT_ARGB8888_1X32, 83 VI6_FMT_RGBX_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 84 VI6_RPF_DSWAP_P_WDS, 85 1, { 16, 0, 0 }, false, false, 1, 1, false }, 86 { V4L2_PIX_FMT_ABGR555, MEDIA_BUS_FMT_ARGB8888_1X32, 87 VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 88 VI6_RPF_DSWAP_P_WDS, 89 1, { 16, 0, 0 }, false, false, 1, 1, true }, 90 { V4L2_PIX_FMT_XBGR555, MEDIA_BUS_FMT_ARGB8888_1X32, 91 VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 92 VI6_RPF_DSWAP_P_WDS, 93 1, { 16, 0, 0 }, false, false, 1, 1, false }, 94 { V4L2_PIX_FMT_BGRA555, MEDIA_BUS_FMT_ARGB8888_1X32, 95 VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 96 VI6_RPF_DSWAP_P_WDS, 97 1, { 16, 0, 0 }, false, false, 1, 1, true }, 98 { V4L2_PIX_FMT_BGRX555, MEDIA_BUS_FMT_ARGB8888_1X32, 99 VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 100 VI6_RPF_DSWAP_P_WDS, 101 1, { 16, 0, 0 }, false, false, 1, 1, false }, 102 { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32, 103 VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 104 VI6_RPF_DSWAP_P_WDS, 105 1, { 16, 0, 0 }, false, false, 1, 1, false }, 106 { V4L2_PIX_FMT_BGR24, MEDIA_BUS_FMT_ARGB8888_1X32, 107 VI6_FMT_BGR_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 108 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 109 1, { 24, 0, 0 }, false, false, 1, 1, false }, 110 { V4L2_PIX_FMT_RGB24, MEDIA_BUS_FMT_ARGB8888_1X32, 111 VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 112 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 113 1, { 24, 0, 0 }, false, false, 1, 1, false }, 114 { V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32, 115 VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 116 1, { 32, 0, 0 }, false, false, 1, 1, true }, 117 { V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32, 118 VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 119 1, { 32, 0, 0 }, false, false, 1, 1, false }, 120 { V4L2_PIX_FMT_BGRA32, MEDIA_BUS_FMT_ARGB8888_1X32, 121 VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 122 1, { 32, 0, 0 }, false, false, 1, 1, true }, 123 { V4L2_PIX_FMT_BGRX32, MEDIA_BUS_FMT_ARGB8888_1X32, 124 VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 125 1, { 32, 0, 0 }, false, false, 1, 1, false }, 126 { V4L2_PIX_FMT_RGBA32, MEDIA_BUS_FMT_ARGB8888_1X32, 127 VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 128 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 129 1, { 32, 0, 0 }, false, false, 1, 1, true }, 130 { V4L2_PIX_FMT_RGBX32, MEDIA_BUS_FMT_ARGB8888_1X32, 131 VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 132 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 133 1, { 32, 0, 0 }, false, false, 1, 1, false }, 134 { V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32, 135 VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 136 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 137 1, { 32, 0, 0 }, false, false, 1, 1, true }, 138 { V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32, 139 VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 140 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 141 1, { 32, 0, 0 }, false, false, 1, 1, false }, 142 { V4L2_PIX_FMT_RGBX1010102, MEDIA_BUS_FMT_ARGB8888_1X32, 143 VI6_FMT_RGB10_RGB10A2_A2RGB10, 144 VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 145 1, { 32, 0, 0 }, false, false, 1, 1, false }, 146 { V4L2_PIX_FMT_RGBA1010102, MEDIA_BUS_FMT_ARGB8888_1X32, 147 VI6_FMT_RGB10_RGB10A2_A2RGB10, 148 VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 149 1, { 32, 0, 0 }, false, false, 1, 1, false }, 150 { V4L2_PIX_FMT_ARGB2101010, MEDIA_BUS_FMT_ARGB8888_1X32, 151 VI6_FMT_RGB10_RGB10A2_A2RGB10, 152 VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 153 1, { 32, 0, 0 }, false, false, 1, 1, false }, 154 { V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32, 155 VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 156 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 157 1, { 16, 0, 0 }, false, false, 2, 1, false }, 158 { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_AYUV8_1X32, 159 VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 160 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 161 1, { 16, 0, 0 }, true, false, 2, 1, false }, 162 { V4L2_PIX_FMT_YVYU, MEDIA_BUS_FMT_AYUV8_1X32, 163 VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 164 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 165 1, { 16, 0, 0 }, true, true, 2, 1, false }, 166 { V4L2_PIX_FMT_NV12M, MEDIA_BUS_FMT_AYUV8_1X32, 167 VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 168 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 169 2, { 8, 16, 0 }, false, false, 2, 2, false }, 170 { V4L2_PIX_FMT_NV21M, MEDIA_BUS_FMT_AYUV8_1X32, 171 VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 172 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 173 2, { 8, 16, 0 }, false, true, 2, 2, false }, 174 { V4L2_PIX_FMT_NV16M, MEDIA_BUS_FMT_AYUV8_1X32, 175 VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 176 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 177 2, { 8, 16, 0 }, false, false, 2, 1, false }, 178 { V4L2_PIX_FMT_NV61M, MEDIA_BUS_FMT_AYUV8_1X32, 179 VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 180 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 181 2, { 8, 16, 0 }, false, true, 2, 1, false }, 182 { V4L2_PIX_FMT_YUV420M, MEDIA_BUS_FMT_AYUV8_1X32, 183 VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 184 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 185 3, { 8, 8, 8 }, false, false, 2, 2, false }, 186 { V4L2_PIX_FMT_YVU420M, MEDIA_BUS_FMT_AYUV8_1X32, 187 VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 188 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 189 3, { 8, 8, 8 }, false, true, 2, 2, false }, 190 { V4L2_PIX_FMT_YUV422M, MEDIA_BUS_FMT_AYUV8_1X32, 191 VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 192 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 193 3, { 8, 8, 8 }, false, false, 2, 1, false }, 194 { V4L2_PIX_FMT_YVU422M, MEDIA_BUS_FMT_AYUV8_1X32, 195 VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 196 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 197 3, { 8, 8, 8 }, false, true, 2, 1, false }, 198 { V4L2_PIX_FMT_YUV444M, MEDIA_BUS_FMT_AYUV8_1X32, 199 VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 200 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 201 3, { 8, 8, 8 }, false, false, 1, 1, false }, 202 { V4L2_PIX_FMT_YVU444M, MEDIA_BUS_FMT_AYUV8_1X32, 203 VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 204 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 205 3, { 8, 8, 8 }, false, true, 1, 1, false }, 206 { V4L2_PIX_FMT_Y210, MEDIA_BUS_FMT_AYUV8_1X32, 207 VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 208 1, { 32, 0, 0 }, false, false, 2, 1, false }, 209 { V4L2_PIX_FMT_Y212, MEDIA_BUS_FMT_AYUV8_1X32, 210 VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 211 1, { 32, 0, 0 }, false, false, 2, 1, false }, 212 }; 213 214 static const struct vsp1_format_info vsp1_video_gen2_formats[] = { 215 { V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32, 216 VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 217 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 218 1, { 16, 0, 0 }, false, true, 2, 1, false }, 219 }; 220 221 static const struct vsp1_format_info vsp1_video_hsit_formats[] = { 222 { V4L2_PIX_FMT_HSV24, MEDIA_BUS_FMT_AHSV8888_1X32, 223 VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 224 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 225 1, { 24, 0, 0 }, false, false, 1, 1, false }, 226 { V4L2_PIX_FMT_HSV32, MEDIA_BUS_FMT_AHSV8888_1X32, 227 VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | 228 VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 229 1, { 32, 0, 0 }, false, false, 1, 1, false }, 230 }; 231 232 /** 233 * vsp1_get_format_info - Retrieve format information for a 4CC 234 * @vsp1: the VSP1 device 235 * @fourcc: the format 4CC 236 * 237 * Return a pointer to the format information structure corresponding to the 238 * given V4L2 format 4CC, or NULL if no corresponding format can be found. 239 */ 240 const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1, 241 u32 fourcc) 242 { 243 unsigned int i; 244 245 for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) { 246 const struct vsp1_format_info *info = &vsp1_video_formats[i]; 247 248 if (info->fourcc == fourcc) 249 return info; 250 } 251 252 if (vsp1->info->gen == 2) { 253 for (i = 0; i < ARRAY_SIZE(vsp1_video_gen2_formats); ++i) { 254 const struct vsp1_format_info *info = 255 &vsp1_video_gen2_formats[i]; 256 257 if (info->fourcc == fourcc) 258 return info; 259 } 260 } 261 262 if (vsp1_feature(vsp1, VSP1_HAS_HSIT)) { 263 for (i = 0; i < ARRAY_SIZE(vsp1_video_hsit_formats); ++i) { 264 const struct vsp1_format_info *info = 265 &vsp1_video_hsit_formats[i]; 266 267 if (info->fourcc == fourcc) 268 return info; 269 } 270 } 271 272 return NULL; 273 } 274 275 /** 276 * vsp1_get_format_info_by_index - Enumerate format information 277 * @vsp1: the VSP1 device 278 * @index: the format index 279 * @code: media bus code to limit enumeration 280 * 281 * Return a pointer to the format information structure corresponding to the 282 * given index, or NULL if the index exceeds the supported formats list. If the 283 * @code parameter is not zero, only formats compatible with the media bus code 284 * will be enumerated. 285 */ 286 const struct vsp1_format_info * 287 vsp1_get_format_info_by_index(struct vsp1_device *vsp1, unsigned int index, 288 u32 code) 289 { 290 unsigned int i; 291 292 if (!code) { 293 if (index < ARRAY_SIZE(vsp1_video_formats)) 294 return &vsp1_video_formats[index]; 295 296 if (vsp1->info->gen == 2) { 297 index -= ARRAY_SIZE(vsp1_video_formats); 298 if (index < ARRAY_SIZE(vsp1_video_gen2_formats)) 299 return &vsp1_video_gen2_formats[index]; 300 } 301 302 if (vsp1_feature(vsp1, VSP1_HAS_HSIT)) { 303 index -= ARRAY_SIZE(vsp1_video_gen2_formats); 304 if (index < ARRAY_SIZE(vsp1_video_hsit_formats)) 305 return &vsp1_video_hsit_formats[index]; 306 } 307 308 return NULL; 309 } 310 311 for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) { 312 const struct vsp1_format_info *info = &vsp1_video_formats[i]; 313 314 if (info->mbus == code) { 315 if (!index) 316 return info; 317 index--; 318 } 319 } 320 321 if (vsp1->info->gen == 2) { 322 for (i = 0; i < ARRAY_SIZE(vsp1_video_gen2_formats); ++i) { 323 const struct vsp1_format_info *info = 324 &vsp1_video_gen2_formats[i]; 325 326 if (info->mbus == code) { 327 if (!index) 328 return info; 329 index--; 330 } 331 } 332 } 333 334 if (vsp1_feature(vsp1, VSP1_HAS_HSIT)) { 335 for (i = 0; i < ARRAY_SIZE(vsp1_video_hsit_formats); ++i) { 336 const struct vsp1_format_info *info = 337 &vsp1_video_hsit_formats[i]; 338 339 if (info->mbus == code) { 340 if (!index) 341 return info; 342 index--; 343 } 344 } 345 } 346 347 return NULL; 348 } 349 350 /** 351 * vsp1_adjust_color_space - Adjust color space fields in a format 352 * @code: the media bus code 353 * @colorspace: the colorspace 354 * @xfer_func: the transfer function 355 * @encoding: the encoding 356 * @quantization: the quantization 357 * 358 * This function adjusts all color space fields of a video device of subdev 359 * format structure, taking into account the requested format, requested color 360 * space and limitations of the VSP1. It should be used in the video device and 361 * subdev set format handlers. 362 * 363 * The colorspace and xfer_func fields are freely configurable, as they are out 364 * of scope for VSP processing. The encoding and quantization is hardcoded for 365 * non-YUV formats, and can be configured for YUV formats. 366 */ 367 void vsp1_adjust_color_space(u32 code, u32 *colorspace, u8 *xfer_func, 368 u8 *encoding, u8 *quantization) 369 { 370 if (*colorspace == V4L2_COLORSPACE_DEFAULT || 371 *colorspace >= V4L2_COLORSPACE_LAST) 372 *colorspace = code == MEDIA_BUS_FMT_AYUV8_1X32 373 ? V4L2_COLORSPACE_SMPTE170M 374 : V4L2_COLORSPACE_SRGB; 375 376 if (*xfer_func == V4L2_XFER_FUNC_DEFAULT || 377 *xfer_func >= V4L2_XFER_FUNC_LAST) 378 *xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(*colorspace); 379 380 switch (code) { 381 case MEDIA_BUS_FMT_ARGB8888_1X32: 382 default: 383 *encoding = V4L2_YCBCR_ENC_601; 384 *quantization = V4L2_QUANTIZATION_FULL_RANGE; 385 break; 386 387 case MEDIA_BUS_FMT_AHSV8888_1X32: 388 *encoding = V4L2_HSV_ENC_256; 389 *quantization = V4L2_QUANTIZATION_FULL_RANGE; 390 break; 391 392 case MEDIA_BUS_FMT_AYUV8_1X32: 393 if (*encoding != V4L2_YCBCR_ENC_601 && 394 *encoding != V4L2_YCBCR_ENC_709) 395 *encoding = V4L2_YCBCR_ENC_601; 396 if (*quantization != V4L2_QUANTIZATION_FULL_RANGE && 397 *quantization != V4L2_QUANTIZATION_LIM_RANGE) 398 *quantization = V4L2_QUANTIZATION_LIM_RANGE; 399 break; 400 } 401 } 402 403 /* ----------------------------------------------------------------------------- 404 * Pipeline Management 405 */ 406 407 void vsp1_pipeline_reset(struct vsp1_pipeline *pipe) 408 { 409 struct vsp1_entity *entity; 410 unsigned int i; 411 412 if (pipe->brx) { 413 struct vsp1_brx *brx = to_brx(&pipe->brx->subdev); 414 415 for (i = 0; i < ARRAY_SIZE(brx->inputs); ++i) 416 brx->inputs[i].rpf = NULL; 417 } 418 419 for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) 420 pipe->inputs[i] = NULL; 421 422 pipe->output = NULL; 423 424 list_for_each_entry(entity, &pipe->entities, list_pipe) 425 entity->pipe = NULL; 426 427 INIT_LIST_HEAD(&pipe->entities); 428 pipe->state = VSP1_PIPELINE_STOPPED; 429 pipe->buffers_ready = 0; 430 pipe->num_inputs = 0; 431 pipe->brx = NULL; 432 pipe->hgo = NULL; 433 pipe->hgt = NULL; 434 pipe->iif = NULL; 435 pipe->lif = NULL; 436 pipe->uds = NULL; 437 } 438 439 void vsp1_pipeline_init(struct vsp1_pipeline *pipe) 440 { 441 mutex_init(&pipe->lock); 442 spin_lock_init(&pipe->irqlock); 443 init_waitqueue_head(&pipe->wq); 444 kref_init(&pipe->kref); 445 446 INIT_LIST_HEAD(&pipe->entities); 447 pipe->state = VSP1_PIPELINE_STOPPED; 448 } 449 450 void __vsp1_pipeline_dump(struct _ddebug *dbg, struct vsp1_pipeline *pipe, 451 const char *msg) 452 { 453 struct vsp1_device *vsp1 = pipe->output->entity.vsp1; 454 struct vsp1_entity *entity; 455 bool first = true; 456 457 printk(KERN_DEBUG "%s: %s: pipe: ", dev_name(vsp1->dev), msg); 458 459 list_for_each_entry(entity, &pipe->entities, list_pipe) { 460 const char *name; 461 462 name = strchrnul(entity->subdev.name, ' '); 463 name = name ? name + 1 : entity->subdev.name; 464 465 pr_cont("%s%s", first ? "" : ", ", name); 466 first = false; 467 } 468 469 pr_cont("\n"); 470 } 471 472 /* Must be called with the pipe irqlock held. */ 473 void vsp1_pipeline_run(struct vsp1_pipeline *pipe) 474 { 475 struct vsp1_device *vsp1 = pipe->output->entity.vsp1; 476 477 lockdep_assert_held(&pipe->irqlock); 478 479 if (pipe->state == VSP1_PIPELINE_STOPPED) { 480 vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index), 481 VI6_CMD_STRCMD); 482 pipe->state = VSP1_PIPELINE_RUNNING; 483 } 484 485 pipe->buffers_ready = 0; 486 } 487 488 bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) 489 { 490 unsigned long flags; 491 bool stopped; 492 493 spin_lock_irqsave(&pipe->irqlock, flags); 494 stopped = pipe->state == VSP1_PIPELINE_STOPPED; 495 spin_unlock_irqrestore(&pipe->irqlock, flags); 496 497 return stopped; 498 } 499 500 int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) 501 { 502 struct vsp1_device *vsp1 = pipe->output->entity.vsp1; 503 struct vsp1_entity *entity; 504 unsigned long flags; 505 int ret; 506 507 if (pipe->lif) { 508 /* 509 * When using display lists in continuous frame mode the only 510 * way to stop the pipeline is to reset the hardware. 511 */ 512 ret = vsp1_reset_wpf(vsp1, pipe->output->entity.index); 513 if (ret == 0) { 514 spin_lock_irqsave(&pipe->irqlock, flags); 515 pipe->state = VSP1_PIPELINE_STOPPED; 516 spin_unlock_irqrestore(&pipe->irqlock, flags); 517 } 518 } else { 519 /* Otherwise just request a stop and wait. */ 520 spin_lock_irqsave(&pipe->irqlock, flags); 521 if (pipe->state == VSP1_PIPELINE_RUNNING) 522 pipe->state = VSP1_PIPELINE_STOPPING; 523 spin_unlock_irqrestore(&pipe->irqlock, flags); 524 525 ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), 526 msecs_to_jiffies(500)); 527 ret = ret == 0 ? -ETIMEDOUT : 0; 528 } 529 530 list_for_each_entry(entity, &pipe->entities, list_pipe) { 531 if (entity->route && entity->route->reg) 532 vsp1_write(vsp1, entity->route->reg, 533 VI6_DPR_NODE_UNUSED); 534 } 535 536 if (pipe->hgo) 537 vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, 538 (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 539 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 540 541 if (pipe->hgt) 542 vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, 543 (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 544 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 545 546 vsp1_wpf_stop(pipe->output); 547 548 return ret; 549 } 550 551 bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe) 552 { 553 unsigned int mask; 554 555 mask = ((1 << pipe->num_inputs) - 1) << 1; 556 if (!pipe->lif) 557 mask |= 1 << 0; 558 559 return pipe->buffers_ready == mask; 560 } 561 562 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) 563 { 564 unsigned int flags; 565 566 if (pipe == NULL) 567 return; 568 569 /* 570 * If the DL commit raced with the frame end interrupt, the commit ends 571 * up being postponed by one frame. The returned flags tell whether the 572 * active frame was finished or postponed. 573 */ 574 flags = vsp1_dlm_irq_frame_end(pipe->output->dlm); 575 576 if (pipe->hgo) 577 vsp1_hgo_frame_end(pipe->hgo); 578 579 if (pipe->hgt) 580 vsp1_hgt_frame_end(pipe->hgt); 581 582 /* 583 * Regardless of frame completion we still need to notify the pipe 584 * frame_end to account for vblank events. 585 */ 586 if (pipe->frame_end) 587 pipe->frame_end(pipe, flags); 588 589 pipe->sequence++; 590 } 591 592 /* 593 * Propagate the alpha value through the pipeline. 594 * 595 * As the UDS has restricted scaling capabilities when the alpha component needs 596 * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha 597 * value. The UDS then outputs a fixed alpha value which needs to be programmed 598 * from the input RPF alpha. 599 */ 600 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, 601 struct vsp1_dl_body *dlb, unsigned int alpha) 602 { 603 if (!pipe->uds) 604 return; 605 606 /* 607 * The BRU and BRS background color has a fixed alpha value set to 255, 608 * the output alpha value is thus always equal to 255. 609 */ 610 if (pipe->uds_input->type == VSP1_ENTITY_BRU || 611 pipe->uds_input->type == VSP1_ENTITY_BRS) 612 alpha = 255; 613 614 vsp1_uds_set_alpha(pipe->uds, dlb, alpha); 615 } 616 617 /* ----------------------------------------------------------------------------- 618 * VSP1 Partition Algorithm support 619 */ 620 621 /* 622 * Propagate the partition calculations through the pipeline 623 * 624 * Work backwards through the pipe, allowing each entity to update the partition 625 * parameters based on its configuration, and the entity connected to its 626 * source. Each entity must produce the partition required for the previous 627 * entity in the pipeline. 628 */ 629 static void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe, 630 struct vsp1_partition *partition, 631 unsigned int index, 632 struct v4l2_rect *window) 633 { 634 struct vsp1_entity *entity; 635 636 list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) { 637 if (entity->ops->partition) 638 entity->ops->partition(entity, entity->state, pipe, 639 partition, index, window); 640 } 641 } 642 643 /* 644 * vsp1_pipeline_calculate_partition - Calculate pipeline configuration for a 645 * partition 646 * 647 * @pipe: the pipeline 648 * @partition: partition that will hold the calculated values 649 * @div_size: pre-determined maximum partition division size 650 * @index: partition index 651 */ 652 void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe, 653 struct vsp1_partition *partition, 654 unsigned int div_size, 655 unsigned int index) 656 { 657 const struct v4l2_mbus_framefmt *format; 658 struct v4l2_rect window; 659 unsigned int modulus; 660 661 /* 662 * Partitions are computed on the size before rotation, use the format 663 * at the WPF sink. 664 */ 665 format = v4l2_subdev_state_get_format(pipe->output->entity.state, 666 RWPF_PAD_SINK); 667 668 /* Initialise the partition with sane starting conditions. */ 669 window.left = index * div_size; 670 window.width = div_size; 671 window.top = 0; 672 window.height = format->height; 673 674 modulus = format->width % div_size; 675 676 /* 677 * We need to prevent the last partition from being smaller than the 678 * *minimum* width of the hardware capabilities. 679 * 680 * If the modulus is less than half of the partition size, 681 * the penultimate partition is reduced to half, which is added 682 * to the final partition: |1234|1234|1234|12|341| 683 * to prevent this: |1234|1234|1234|1234|1|. 684 */ 685 if (modulus) { 686 /* 687 * pipe->partitions is 1 based, whilst index is a 0 based index. 688 * Normalise this locally. 689 */ 690 unsigned int partitions = pipe->partitions - 1; 691 692 if (modulus < div_size / 2) { 693 if (index == partitions - 1) { 694 /* Halve the penultimate partition. */ 695 window.width = div_size / 2; 696 } else if (index == partitions) { 697 /* Increase the final partition. */ 698 window.width = (div_size / 2) + modulus; 699 window.left -= div_size / 2; 700 } 701 } else if (index == partitions) { 702 window.width = modulus; 703 } 704 } 705 706 vsp1_pipeline_propagate_partition(pipe, partition, index, &window); 707 } 708