1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Driver for Renesas R-Car VIN 4 * 5 * Copyright (C) 2016 Renesas Electronics Corp. 6 * Copyright (C) 2011-2013 Renesas Solutions Corp. 7 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> 8 * Copyright (C) 2008 Magnus Damm 9 * 10 * Based on the soc-camera rcar_vin driver 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/interrupt.h> 15 #include <linux/pm_runtime.h> 16 17 #include <media/videobuf2-dma-contig.h> 18 19 #include "rcar-vin.h" 20 21 /* ----------------------------------------------------------------------------- 22 * HW Functions 23 */ 24 25 /* Register offsets for R-Car VIN */ 26 #define VNMC_REG 0x00 /* Video n Main Control Register */ 27 #define VNMS_REG 0x04 /* Video n Module Status Register */ 28 #define VNFC_REG 0x08 /* Video n Frame Capture Register */ 29 #define VNSLPRC_REG 0x0C /* Video n Start Line Pre-Clip Register */ 30 #define VNELPRC_REG 0x10 /* Video n End Line Pre-Clip Register */ 31 #define VNSPPRC_REG 0x14 /* Video n Start Pixel Pre-Clip Register */ 32 #define VNEPPRC_REG 0x18 /* Video n End Pixel Pre-Clip Register */ 33 #define VNIS_REG 0x2C /* Video n Image Stride Register */ 34 #define VNMB_REG(m) (0x30 + ((m) << 2)) /* Video n Memory Base m Register */ 35 #define VNIE_REG 0x40 /* Video n Interrupt Enable Register */ 36 #define VNINTS_REG 0x44 /* Video n Interrupt Status Register */ 37 #define VNSI_REG 0x48 /* Video n Scanline Interrupt Register */ 38 #define VNMTC_REG 0x4C /* Video n Memory Transfer Control Register */ 39 #define VNDMR_REG 0x58 /* Video n Data Mode Register */ 40 #define VNDMR2_REG 0x5C /* Video n Data Mode Register 2 */ 41 #define VNUVAOF_REG 0x60 /* Video n UV Address Offset Register */ 42 43 /* Register offsets specific for Gen2 */ 44 #define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */ 45 #define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */ 46 #define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */ 47 #define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */ 48 #define VNYS_REG 0x50 /* Video n Y Scale Register */ 49 #define VNXS_REG 0x54 /* Video n X Scale Register */ 50 #define VNC1A_REG 0x80 /* Video n Coefficient Set C1A Register */ 51 #define VNC1B_REG 0x84 /* Video n Coefficient Set C1B Register */ 52 #define VNC1C_REG 0x88 /* Video n Coefficient Set C1C Register */ 53 #define VNC2A_REG 0x90 /* Video n Coefficient Set C2A Register */ 54 #define VNC2B_REG 0x94 /* Video n Coefficient Set C2B Register */ 55 #define VNC2C_REG 0x98 /* Video n Coefficient Set C2C Register */ 56 #define VNC3A_REG 0xA0 /* Video n Coefficient Set C3A Register */ 57 #define VNC3B_REG 0xA4 /* Video n Coefficient Set C3B Register */ 58 #define VNC3C_REG 0xA8 /* Video n Coefficient Set C3C Register */ 59 #define VNC4A_REG 0xB0 /* Video n Coefficient Set C4A Register */ 60 #define VNC4B_REG 0xB4 /* Video n Coefficient Set C4B Register */ 61 #define VNC4C_REG 0xB8 /* Video n Coefficient Set C4C Register */ 62 #define VNC5A_REG 0xC0 /* Video n Coefficient Set C5A Register */ 63 #define VNC5B_REG 0xC4 /* Video n Coefficient Set C5B Register */ 64 #define VNC5C_REG 0xC8 /* Video n Coefficient Set C5C Register */ 65 #define VNC6A_REG 0xD0 /* Video n Coefficient Set C6A Register */ 66 #define VNC6B_REG 0xD4 /* Video n Coefficient Set C6B Register */ 67 #define VNC6C_REG 0xD8 /* Video n Coefficient Set C6C Register */ 68 #define VNC7A_REG 0xE0 /* Video n Coefficient Set C7A Register */ 69 #define VNC7B_REG 0xE4 /* Video n Coefficient Set C7B Register */ 70 #define VNC7C_REG 0xE8 /* Video n Coefficient Set C7C Register */ 71 #define VNC8A_REG 0xF0 /* Video n Coefficient Set C8A Register */ 72 #define VNC8B_REG 0xF4 /* Video n Coefficient Set C8B Register */ 73 #define VNC8C_REG 0xF8 /* Video n Coefficient Set C8C Register */ 74 75 /* Register offsets specific for Gen3 */ 76 #define VNCSI_IFMD_REG 0x20 /* Video n CSI2 Interface Mode Register */ 77 #define VNUDS_CTRL_REG 0x80 /* Video n scaling control register */ 78 #define VNUDS_SCALE_REG 0x84 /* Video n scaling factor register */ 79 #define VNUDS_PASS_BWIDTH_REG 0x90 /* Video n passband register */ 80 #define VNUDS_CLIP_SIZE_REG 0xa4 /* Video n UDS output size clipping reg */ 81 82 /* Register bit fields for R-Car VIN */ 83 /* Video n Main Control Register bits */ 84 #define VNMC_INF_MASK (7 << 16) 85 #define VNMC_DPINE (1 << 27) /* Gen3 specific */ 86 #define VNMC_SCLE (1 << 26) /* Gen3 specific */ 87 #define VNMC_FOC (1 << 21) 88 #define VNMC_YCAL (1 << 19) 89 #define VNMC_INF_YUV8_BT656 (0 << 16) 90 #define VNMC_INF_YUV8_BT601 (1 << 16) 91 #define VNMC_INF_YUV10_BT656 (2 << 16) 92 #define VNMC_INF_YUV10_BT601 (3 << 16) 93 #define VNMC_INF_RAW8 (4 << 16) 94 #define VNMC_INF_YUV16 (5 << 16) 95 #define VNMC_INF_RGB888 (6 << 16) 96 #define VNMC_INF_RGB666 (7 << 16) 97 #define VNMC_VUP (1 << 10) 98 #define VNMC_IM_ODD (0 << 3) 99 #define VNMC_IM_ODD_EVEN (1 << 3) 100 #define VNMC_IM_EVEN (2 << 3) 101 #define VNMC_IM_FULL (3 << 3) 102 #define VNMC_BPS (1 << 1) 103 #define VNMC_ME (1 << 0) 104 105 /* Video n Module Status Register bits */ 106 #define VNMS_FBS_MASK (3 << 3) 107 #define VNMS_FBS_SHIFT 3 108 #define VNMS_FS (1 << 2) 109 #define VNMS_AV (1 << 1) 110 #define VNMS_CA (1 << 0) 111 112 /* Video n Frame Capture Register bits */ 113 #define VNFC_C_FRAME (1 << 1) 114 #define VNFC_S_FRAME (1 << 0) 115 116 /* Video n Interrupt Enable Register bits */ 117 #define VNIE_FIE (1 << 4) 118 #define VNIE_EFE (1 << 1) 119 120 /* Video n Interrupt Status Register bits */ 121 #define VNINTS_FIS (1 << 4) 122 123 /* Video n Data Mode Register bits */ 124 #define VNDMR_A8BIT(n) (((n) & 0xff) << 24) 125 #define VNDMR_A8BIT_MASK (0xff << 24) 126 #define VNDMR_RMODE_RAW10 (2 << 19) 127 #define VNDMR_YMODE_Y8 (1 << 12) 128 #define VNDMR_YC_THR (1 << 11) 129 #define VNDMR_EXRGB (1 << 8) 130 #define VNDMR_BPSM (1 << 4) 131 #define VNDMR_ABIT (1 << 2) 132 #define VNDMR_DTMD_YCSEP (1 << 1) 133 #define VNDMR_DTMD_ARGB (1 << 0) 134 #define VNDMR_DTMD_YCSEP_420 (3 << 0) 135 136 /* Video n Data Mode Register 2 bits */ 137 #define VNDMR2_VPS (1 << 30) 138 #define VNDMR2_HPS (1 << 29) 139 #define VNDMR2_CES (1 << 28) 140 #define VNDMR2_YDS (1 << 22) 141 #define VNDMR2_FTEV (1 << 17) 142 #define VNDMR2_VLV(n) ((n & 0xf) << 12) 143 144 /* Video n CSI2 Interface Mode Register (Gen3) */ 145 #define VNCSI_IFMD_DES1 (1 << 26) 146 #define VNCSI_IFMD_DES0 (1 << 25) 147 #define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0) 148 149 /* Video n scaling control register (Gen3) */ 150 #define VNUDS_CTRL_AMD (1 << 30) 151 152 struct rvin_buffer { 153 struct vb2_v4l2_buffer vb; 154 struct list_head list; 155 }; 156 157 #define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \ 158 struct rvin_buffer, \ 159 vb)->list) 160 161 static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset) 162 { 163 iowrite32(value, vin->base + offset); 164 } 165 166 static u32 rvin_read(struct rvin_dev *vin, u32 offset) 167 { 168 return ioread32(vin->base + offset); 169 } 170 171 /* ----------------------------------------------------------------------------- 172 * Crop and Scaling 173 */ 174 175 static bool rvin_scaler_needed(const struct rvin_dev *vin) 176 { 177 return !(vin->crop.width == vin->format.width && 178 vin->compose.width == vin->format.width && 179 vin->crop.height == vin->format.height && 180 vin->compose.height == vin->format.height); 181 } 182 183 struct vin_coeff { 184 unsigned short xs_value; 185 u32 coeff_set[24]; 186 }; 187 188 static const struct vin_coeff vin_coeff_set[] = { 189 { 0x0000, { 190 0x00000000, 0x00000000, 0x00000000, 191 0x00000000, 0x00000000, 0x00000000, 192 0x00000000, 0x00000000, 0x00000000, 193 0x00000000, 0x00000000, 0x00000000, 194 0x00000000, 0x00000000, 0x00000000, 195 0x00000000, 0x00000000, 0x00000000, 196 0x00000000, 0x00000000, 0x00000000, 197 0x00000000, 0x00000000, 0x00000000 }, 198 }, 199 { 0x1000, { 200 0x000fa400, 0x000fa400, 0x09625902, 201 0x000003f8, 0x00000403, 0x3de0d9f0, 202 0x001fffed, 0x00000804, 0x3cc1f9c3, 203 0x001003de, 0x00000c01, 0x3cb34d7f, 204 0x002003d2, 0x00000c00, 0x3d24a92d, 205 0x00200bca, 0x00000bff, 0x3df600d2, 206 0x002013cc, 0x000007ff, 0x3ed70c7e, 207 0x00100fde, 0x00000000, 0x3f87c036 }, 208 }, 209 { 0x1200, { 210 0x002ffff1, 0x002ffff1, 0x02a0a9c8, 211 0x002003e7, 0x001ffffa, 0x000185bc, 212 0x002007dc, 0x000003ff, 0x3e52859c, 213 0x00200bd4, 0x00000002, 0x3d53996b, 214 0x00100fd0, 0x00000403, 0x3d04ad2d, 215 0x00000bd5, 0x00000403, 0x3d35ace7, 216 0x3ff003e4, 0x00000801, 0x3dc674a1, 217 0x3fffe800, 0x00000800, 0x3e76f461 }, 218 }, 219 { 0x1400, { 220 0x00100be3, 0x00100be3, 0x04d1359a, 221 0x00000fdb, 0x002003ed, 0x0211fd93, 222 0x00000fd6, 0x002003f4, 0x0002d97b, 223 0x000007d6, 0x002ffffb, 0x3e93b956, 224 0x3ff003da, 0x001003ff, 0x3db49926, 225 0x3fffefe9, 0x00100001, 0x3d655cee, 226 0x3fffd400, 0x00000003, 0x3d65f4b6, 227 0x000fb421, 0x00000402, 0x3dc6547e }, 228 }, 229 { 0x1600, { 230 0x00000bdd, 0x00000bdd, 0x06519578, 231 0x3ff007da, 0x00000be3, 0x03c24973, 232 0x3ff003d9, 0x00000be9, 0x01b30d5f, 233 0x3ffff7df, 0x001003f1, 0x0003c542, 234 0x000fdfec, 0x001003f7, 0x3ec4711d, 235 0x000fc400, 0x002ffffd, 0x3df504f1, 236 0x001fa81a, 0x002ffc00, 0x3d957cc2, 237 0x002f8c3c, 0x00100000, 0x3db5c891 }, 238 }, 239 { 0x1800, { 240 0x3ff003dc, 0x3ff003dc, 0x0791e558, 241 0x000ff7dd, 0x3ff007de, 0x05328554, 242 0x000fe7e3, 0x3ff00be2, 0x03232546, 243 0x000fd7ee, 0x000007e9, 0x0143bd30, 244 0x001fb800, 0x000007ee, 0x00044511, 245 0x002fa015, 0x000007f4, 0x3ef4bcee, 246 0x002f8832, 0x001003f9, 0x3e4514c7, 247 0x001f7853, 0x001003fd, 0x3de54c9f }, 248 }, 249 { 0x1a00, { 250 0x000fefe0, 0x000fefe0, 0x08721d3c, 251 0x001fdbe7, 0x000ffbde, 0x0652a139, 252 0x001fcbf0, 0x000003df, 0x0463292e, 253 0x002fb3ff, 0x3ff007e3, 0x0293a91d, 254 0x002f9c12, 0x3ff00be7, 0x01241905, 255 0x001f8c29, 0x000007ed, 0x3fe470eb, 256 0x000f7c46, 0x000007f2, 0x3f04b8ca, 257 0x3fef7865, 0x000007f6, 0x3e74e4a8 }, 258 }, 259 { 0x1c00, { 260 0x001fd3e9, 0x001fd3e9, 0x08f23d26, 261 0x002fbff3, 0x001fe3e4, 0x0712ad23, 262 0x002fa800, 0x000ff3e0, 0x05631d1b, 263 0x001f9810, 0x000ffbe1, 0x03b3890d, 264 0x000f8c23, 0x000003e3, 0x0233e8fa, 265 0x3fef843b, 0x000003e7, 0x00f430e4, 266 0x3fbf8456, 0x3ff00bea, 0x00046cc8, 267 0x3f8f8c72, 0x3ff00bef, 0x3f3490ac }, 268 }, 269 { 0x1e00, { 270 0x001fbbf4, 0x001fbbf4, 0x09425112, 271 0x001fa800, 0x002fc7ed, 0x0792b110, 272 0x000f980e, 0x001fdbe6, 0x0613110a, 273 0x3fff8c20, 0x001fe7e3, 0x04a368fd, 274 0x3fcf8c33, 0x000ff7e2, 0x0343b8ed, 275 0x3f9f8c4a, 0x000fffe3, 0x0203f8da, 276 0x3f5f9c61, 0x000003e6, 0x00e428c5, 277 0x3f1fb07b, 0x000003eb, 0x3fe440af }, 278 }, 279 { 0x2000, { 280 0x000fa400, 0x000fa400, 0x09625902, 281 0x3fff980c, 0x001fb7f5, 0x0812b0ff, 282 0x3fdf901c, 0x001fc7ed, 0x06b2fcfa, 283 0x3faf902d, 0x001fd3e8, 0x055348f1, 284 0x3f7f983f, 0x001fe3e5, 0x04038ce3, 285 0x3f3fa454, 0x001fefe3, 0x02e3c8d1, 286 0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0, 287 0x3ecfd880, 0x000fffe6, 0x00c404ac }, 288 }, 289 { 0x2200, { 290 0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4, 291 0x3fbf9818, 0x3fffa400, 0x0842a8f1, 292 0x3f8f9827, 0x000fb3f7, 0x0702f0ec, 293 0x3f5fa037, 0x000fc3ef, 0x05d330e4, 294 0x3f2fac49, 0x001fcfea, 0x04a364d9, 295 0x3effc05c, 0x001fdbe7, 0x038394ca, 296 0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb, 297 0x3ea00083, 0x001fefe6, 0x0183c0a9 }, 298 }, 299 { 0x2400, { 300 0x3f9fa014, 0x3f9fa014, 0x098260e6, 301 0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5, 302 0x3f4fa431, 0x3fefa400, 0x0742d8e1, 303 0x3f1fb440, 0x3fffb3f8, 0x062310d9, 304 0x3eefc850, 0x000fbbf2, 0x050340d0, 305 0x3ecfe062, 0x000fcbec, 0x041364c2, 306 0x3ea00073, 0x001fd3ea, 0x03037cb5, 307 0x3e902086, 0x001fdfe8, 0x022388a5 }, 308 }, 309 { 0x2600, { 310 0x3f5fa81e, 0x3f5fa81e, 0x096258da, 311 0x3f3fac2b, 0x3f8fa412, 0x088290d8, 312 0x3f0fbc38, 0x3fafa408, 0x0772c8d5, 313 0x3eefcc47, 0x3fcfa800, 0x0672f4ce, 314 0x3ecfe456, 0x3fefaffa, 0x05531cc6, 315 0x3eb00066, 0x3fffbbf3, 0x047334bb, 316 0x3ea01c77, 0x000fc7ee, 0x039348ae, 317 0x3ea04486, 0x000fd3eb, 0x02b350a1 }, 318 }, 319 { 0x2800, { 320 0x3f2fb426, 0x3f2fb426, 0x094250ce, 321 0x3f0fc032, 0x3f4fac1b, 0x086284cd, 322 0x3eefd040, 0x3f7fa811, 0x0782acc9, 323 0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4, 324 0x3eb0005b, 0x3fbfac00, 0x05b2f4bc, 325 0x3eb0186a, 0x3fdfb3fa, 0x04c308b4, 326 0x3eb04077, 0x3fefbbf4, 0x03f31ca8, 327 0x3ec06884, 0x000fbff2, 0x03031c9e }, 328 }, 329 { 0x2a00, { 330 0x3f0fc42d, 0x3f0fc42d, 0x090240c4, 331 0x3eefd439, 0x3f2fb822, 0x08526cc2, 332 0x3edfe845, 0x3f4fb018, 0x078294bf, 333 0x3ec00051, 0x3f6fac0f, 0x06b2b4bb, 334 0x3ec0185f, 0x3f8fac07, 0x05e2ccb4, 335 0x3ec0386b, 0x3fafac00, 0x0502e8ac, 336 0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3, 337 0x3ef08482, 0x3fdfbbf6, 0x0372f898 }, 338 }, 339 { 0x2c00, { 340 0x3eefdc31, 0x3eefdc31, 0x08e238b8, 341 0x3edfec3d, 0x3f0fc828, 0x082258b9, 342 0x3ed00049, 0x3f1fc01e, 0x077278b6, 343 0x3ed01455, 0x3f3fb815, 0x06c294b2, 344 0x3ed03460, 0x3f5fb40d, 0x0602acac, 345 0x3ef0506c, 0x3f7fb006, 0x0542c0a4, 346 0x3f107476, 0x3f9fb400, 0x0472c89d, 347 0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 }, 348 }, 349 { 0x2e00, { 350 0x3eefec37, 0x3eefec37, 0x088220b0, 351 0x3ee00041, 0x3effdc2d, 0x07f244ae, 352 0x3ee0144c, 0x3f0fd023, 0x07625cad, 353 0x3ef02c57, 0x3f1fc81a, 0x06c274a9, 354 0x3f004861, 0x3f3fbc13, 0x060288a6, 355 0x3f20686b, 0x3f5fb80c, 0x05529c9e, 356 0x3f408c74, 0x3f6fb805, 0x04b2ac96, 357 0x3f80ac7e, 0x3f8fb800, 0x0402ac8e }, 358 }, 359 { 0x3000, { 360 0x3ef0003a, 0x3ef0003a, 0x084210a6, 361 0x3ef01045, 0x3effec32, 0x07b228a7, 362 0x3f00284e, 0x3f0fdc29, 0x073244a4, 363 0x3f104058, 0x3f0fd420, 0x06a258a2, 364 0x3f305c62, 0x3f2fc818, 0x0612689d, 365 0x3f508069, 0x3f3fc011, 0x05728496, 366 0x3f80a072, 0x3f4fc00a, 0x04d28c90, 367 0x3fc0c07b, 0x3f6fbc04, 0x04429088 }, 368 }, 369 { 0x3200, { 370 0x3f00103e, 0x3f00103e, 0x07f1fc9e, 371 0x3f102447, 0x3f000035, 0x0782149d, 372 0x3f203c4f, 0x3f0ff02c, 0x07122c9c, 373 0x3f405458, 0x3f0fe424, 0x06924099, 374 0x3f607061, 0x3f1fd41d, 0x06024c97, 375 0x3f909068, 0x3f2fcc16, 0x05726490, 376 0x3fc0b070, 0x3f3fc80f, 0x04f26c8a, 377 0x0000d077, 0x3f4fc409, 0x04627484 }, 378 }, 379 { 0x3400, { 380 0x3f202040, 0x3f202040, 0x07a1e898, 381 0x3f303449, 0x3f100c38, 0x0741fc98, 382 0x3f504c50, 0x3f10002f, 0x06e21495, 383 0x3f706459, 0x3f1ff028, 0x06722492, 384 0x3fa08060, 0x3f1fe421, 0x05f2348f, 385 0x3fd09c67, 0x3f1fdc19, 0x05824c89, 386 0x0000bc6e, 0x3f2fd014, 0x04f25086, 387 0x0040dc74, 0x3f3fcc0d, 0x04825c7f }, 388 }, 389 { 0x3600, { 390 0x3f403042, 0x3f403042, 0x0761d890, 391 0x3f504848, 0x3f301c3b, 0x0701f090, 392 0x3f805c50, 0x3f200c33, 0x06a2008f, 393 0x3fa07458, 0x3f10002b, 0x06520c8d, 394 0x3fd0905e, 0x3f1ff424, 0x05e22089, 395 0x0000ac65, 0x3f1fe81d, 0x05823483, 396 0x0030cc6a, 0x3f2fdc18, 0x04f23c81, 397 0x0080e871, 0x3f2fd412, 0x0482407c }, 398 }, 399 { 0x3800, { 400 0x3f604043, 0x3f604043, 0x0721c88a, 401 0x3f80544a, 0x3f502c3c, 0x06d1d88a, 402 0x3fb06851, 0x3f301c35, 0x0681e889, 403 0x3fd08456, 0x3f30082f, 0x0611fc88, 404 0x00009c5d, 0x3f200027, 0x05d20884, 405 0x0030b863, 0x3f2ff421, 0x05621880, 406 0x0070d468, 0x3f2fe81b, 0x0502247c, 407 0x00c0ec6f, 0x3f2fe015, 0x04a22877 }, 408 }, 409 { 0x3a00, { 410 0x3f904c44, 0x3f904c44, 0x06e1b884, 411 0x3fb0604a, 0x3f70383e, 0x0691c885, 412 0x3fe07451, 0x3f502c36, 0x0661d483, 413 0x00009055, 0x3f401831, 0x0601ec81, 414 0x0030a85b, 0x3f300c2a, 0x05b1f480, 415 0x0070c061, 0x3f300024, 0x0562047a, 416 0x00b0d867, 0x3f3ff41e, 0x05020c77, 417 0x00f0f46b, 0x3f2fec19, 0x04a21474 }, 418 }, 419 { 0x3c00, { 420 0x3fb05c43, 0x3fb05c43, 0x06c1b07e, 421 0x3fe06c4b, 0x3f902c3f, 0x0681c081, 422 0x0000844f, 0x3f703838, 0x0631cc7d, 423 0x00309855, 0x3f602433, 0x05d1d47e, 424 0x0060b459, 0x3f50142e, 0x0581e47b, 425 0x00a0c85f, 0x3f400828, 0x0531f078, 426 0x00e0e064, 0x3f300021, 0x0501fc73, 427 0x00b0fc6a, 0x3f3ff41d, 0x04a20873 }, 428 }, 429 { 0x3e00, { 430 0x3fe06444, 0x3fe06444, 0x0681a07a, 431 0x00007849, 0x3fc0503f, 0x0641b07a, 432 0x0020904d, 0x3fa0403a, 0x05f1c07a, 433 0x0060a453, 0x3f803034, 0x05c1c878, 434 0x0090b858, 0x3f70202f, 0x0571d477, 435 0x00d0d05d, 0x3f501829, 0x0531e073, 436 0x0110e462, 0x3f500825, 0x04e1e471, 437 0x01510065, 0x3f40001f, 0x04a1f06d }, 438 }, 439 { 0x4000, { 440 0x00007044, 0x00007044, 0x06519476, 441 0x00208448, 0x3fe05c3f, 0x0621a476, 442 0x0050984d, 0x3fc04c3a, 0x05e1b075, 443 0x0080ac52, 0x3fa03c35, 0x05a1b875, 444 0x00c0c056, 0x3f803030, 0x0561c473, 445 0x0100d45b, 0x3f70202b, 0x0521d46f, 446 0x0140e860, 0x3f601427, 0x04d1d46e, 447 0x01810064, 0x3f500822, 0x0491dc6b }, 448 }, 449 { 0x5000, { 450 0x0110a442, 0x0110a442, 0x0551545e, 451 0x0140b045, 0x00e0983f, 0x0531585f, 452 0x0160c047, 0x00c08c3c, 0x0511645e, 453 0x0190cc4a, 0x00908039, 0x04f1685f, 454 0x01c0dc4c, 0x00707436, 0x04d1705e, 455 0x0200e850, 0x00506833, 0x04b1785b, 456 0x0230f453, 0x00305c30, 0x0491805a, 457 0x02710056, 0x0010542d, 0x04718059 }, 458 }, 459 { 0x6000, { 460 0x01c0bc40, 0x01c0bc40, 0x04c13052, 461 0x01e0c841, 0x01a0b43d, 0x04c13851, 462 0x0210cc44, 0x0180a83c, 0x04a13453, 463 0x0230d845, 0x0160a03a, 0x04913c52, 464 0x0260e047, 0x01409838, 0x04714052, 465 0x0280ec49, 0x01208c37, 0x04514c50, 466 0x02b0f44b, 0x01008435, 0x04414c50, 467 0x02d1004c, 0x00e07c33, 0x0431544f }, 468 }, 469 { 0x7000, { 470 0x0230c83e, 0x0230c83e, 0x04711c4c, 471 0x0250d03f, 0x0210c43c, 0x0471204b, 472 0x0270d840, 0x0200b83c, 0x0451244b, 473 0x0290dc42, 0x01e0b43a, 0x0441244c, 474 0x02b0e443, 0x01c0b038, 0x0441284b, 475 0x02d0ec44, 0x01b0a438, 0x0421304a, 476 0x02f0f445, 0x0190a036, 0x04213449, 477 0x0310f847, 0x01709c34, 0x04213848 }, 478 }, 479 { 0x8000, { 480 0x0280d03d, 0x0280d03d, 0x04310c48, 481 0x02a0d43e, 0x0270c83c, 0x04311047, 482 0x02b0dc3e, 0x0250c83a, 0x04311447, 483 0x02d0e040, 0x0240c03a, 0x04211446, 484 0x02e0e840, 0x0220bc39, 0x04111847, 485 0x0300e842, 0x0210b438, 0x04012445, 486 0x0310f043, 0x0200b037, 0x04012045, 487 0x0330f444, 0x01e0ac36, 0x03f12445 }, 488 }, 489 { 0xefff, { 490 0x0340dc3a, 0x0340dc3a, 0x03b0ec40, 491 0x0340e03a, 0x0330e039, 0x03c0f03e, 492 0x0350e03b, 0x0330dc39, 0x03c0ec3e, 493 0x0350e43a, 0x0320dc38, 0x03c0f43e, 494 0x0360e43b, 0x0320d839, 0x03b0f03e, 495 0x0360e83b, 0x0310d838, 0x03c0fc3b, 496 0x0370e83b, 0x0310d439, 0x03a0f83d, 497 0x0370e83c, 0x0300d438, 0x03b0fc3c }, 498 } 499 }; 500 501 static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs) 502 { 503 int i; 504 const struct vin_coeff *p_prev_set = NULL; 505 const struct vin_coeff *p_set = NULL; 506 507 /* Look for suitable coefficient values */ 508 for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) { 509 p_prev_set = p_set; 510 p_set = &vin_coeff_set[i]; 511 512 if (xs < p_set->xs_value) 513 break; 514 } 515 516 /* Use previous value if its XS value is closer */ 517 if (p_prev_set && 518 xs - p_prev_set->xs_value < p_set->xs_value - xs) 519 p_set = p_prev_set; 520 521 /* Set coefficient registers */ 522 rvin_write(vin, p_set->coeff_set[0], VNC1A_REG); 523 rvin_write(vin, p_set->coeff_set[1], VNC1B_REG); 524 rvin_write(vin, p_set->coeff_set[2], VNC1C_REG); 525 526 rvin_write(vin, p_set->coeff_set[3], VNC2A_REG); 527 rvin_write(vin, p_set->coeff_set[4], VNC2B_REG); 528 rvin_write(vin, p_set->coeff_set[5], VNC2C_REG); 529 530 rvin_write(vin, p_set->coeff_set[6], VNC3A_REG); 531 rvin_write(vin, p_set->coeff_set[7], VNC3B_REG); 532 rvin_write(vin, p_set->coeff_set[8], VNC3C_REG); 533 534 rvin_write(vin, p_set->coeff_set[9], VNC4A_REG); 535 rvin_write(vin, p_set->coeff_set[10], VNC4B_REG); 536 rvin_write(vin, p_set->coeff_set[11], VNC4C_REG); 537 538 rvin_write(vin, p_set->coeff_set[12], VNC5A_REG); 539 rvin_write(vin, p_set->coeff_set[13], VNC5B_REG); 540 rvin_write(vin, p_set->coeff_set[14], VNC5C_REG); 541 542 rvin_write(vin, p_set->coeff_set[15], VNC6A_REG); 543 rvin_write(vin, p_set->coeff_set[16], VNC6B_REG); 544 rvin_write(vin, p_set->coeff_set[17], VNC6C_REG); 545 546 rvin_write(vin, p_set->coeff_set[18], VNC7A_REG); 547 rvin_write(vin, p_set->coeff_set[19], VNC7B_REG); 548 rvin_write(vin, p_set->coeff_set[20], VNC7C_REG); 549 550 rvin_write(vin, p_set->coeff_set[21], VNC8A_REG); 551 rvin_write(vin, p_set->coeff_set[22], VNC8B_REG); 552 rvin_write(vin, p_set->coeff_set[23], VNC8C_REG); 553 } 554 555 void rvin_scaler_gen2(struct rvin_dev *vin) 556 { 557 unsigned int crop_height; 558 u32 xs, ys; 559 560 /* Set scaling coefficient */ 561 crop_height = vin->crop.height; 562 if (V4L2_FIELD_HAS_BOTH(vin->format.field)) 563 crop_height *= 2; 564 565 ys = 0; 566 if (crop_height != vin->compose.height) 567 ys = (4096 * crop_height) / vin->compose.height; 568 rvin_write(vin, ys, VNYS_REG); 569 570 xs = 0; 571 if (vin->crop.width != vin->compose.width) 572 xs = (4096 * vin->crop.width) / vin->compose.width; 573 574 /* Horizontal upscaling is up to double size */ 575 if (xs > 0 && xs < 2048) 576 xs = 2048; 577 578 rvin_write(vin, xs, VNXS_REG); 579 580 /* Horizontal upscaling is done out by scaling down from double size */ 581 if (xs < 4096) 582 xs *= 2; 583 584 rvin_set_coeff(vin, xs); 585 586 /* Set Start/End Pixel/Line Post-Clip */ 587 rvin_write(vin, 0, VNSPPOC_REG); 588 rvin_write(vin, 0, VNSLPOC_REG); 589 rvin_write(vin, vin->format.width - 1, VNEPPOC_REG); 590 591 if (V4L2_FIELD_HAS_BOTH(vin->format.field)) 592 rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG); 593 else 594 rvin_write(vin, vin->format.height - 1, VNELPOC_REG); 595 596 vin_dbg(vin, 597 "Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n", 598 vin->crop.width, vin->crop.height, vin->crop.left, 599 vin->crop.top, ys, xs, vin->format.width, vin->format.height, 600 0, 0); 601 } 602 603 static unsigned int rvin_uds_scale_ratio(unsigned int in, unsigned int out) 604 { 605 unsigned int ratio; 606 607 ratio = in * 4096 / out; 608 return ratio >= 0x10000 ? 0xffff : ratio; 609 } 610 611 static unsigned int rvin_uds_filter_width(unsigned int ratio) 612 { 613 if (ratio >= 0x1000) 614 return 64 * (ratio & 0xf000) / ratio; 615 616 return 64; 617 } 618 619 void rvin_scaler_gen3(struct rvin_dev *vin) 620 { 621 unsigned int ratio_h, ratio_v; 622 unsigned int bwidth_h, bwidth_v; 623 u32 vnmc, clip_size; 624 625 vnmc = rvin_read(vin, VNMC_REG); 626 627 /* Disable scaler if not needed. */ 628 if (!rvin_scaler_needed(vin)) { 629 rvin_write(vin, vnmc & ~VNMC_SCLE, VNMC_REG); 630 return; 631 } 632 633 ratio_h = rvin_uds_scale_ratio(vin->crop.width, vin->compose.width); 634 bwidth_h = rvin_uds_filter_width(ratio_h); 635 636 ratio_v = rvin_uds_scale_ratio(vin->crop.height, vin->compose.height); 637 bwidth_v = rvin_uds_filter_width(ratio_v); 638 639 clip_size = vin->compose.width << 16; 640 641 switch (vin->format.field) { 642 case V4L2_FIELD_INTERLACED_TB: 643 case V4L2_FIELD_INTERLACED_BT: 644 case V4L2_FIELD_INTERLACED: 645 case V4L2_FIELD_SEQ_TB: 646 case V4L2_FIELD_SEQ_BT: 647 clip_size |= vin->compose.height / 2; 648 break; 649 default: 650 clip_size |= vin->compose.height; 651 break; 652 } 653 654 rvin_write(vin, vnmc | VNMC_SCLE, VNMC_REG); 655 rvin_write(vin, VNUDS_CTRL_AMD, VNUDS_CTRL_REG); 656 rvin_write(vin, (ratio_h << 16) | ratio_v, VNUDS_SCALE_REG); 657 rvin_write(vin, (bwidth_h << 16) | bwidth_v, VNUDS_PASS_BWIDTH_REG); 658 rvin_write(vin, clip_size, VNUDS_CLIP_SIZE_REG); 659 660 vin_dbg(vin, "Pre-Clip: %ux%u@%u:%u Post-Clip: %ux%u@%u:%u\n", 661 vin->crop.width, vin->crop.height, vin->crop.left, 662 vin->crop.top, vin->compose.width, vin->compose.height, 663 vin->compose.left, vin->compose.top); 664 } 665 666 void rvin_crop_scale_comp(struct rvin_dev *vin) 667 { 668 const struct rvin_video_format *fmt; 669 u32 stride; 670 671 /* Set Start/End Pixel/Line Pre-Clip */ 672 rvin_write(vin, vin->crop.left, VNSPPRC_REG); 673 rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG); 674 rvin_write(vin, vin->crop.top, VNSLPRC_REG); 675 rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG); 676 677 if (vin->scaler) 678 vin->scaler(vin); 679 680 fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); 681 stride = vin->format.bytesperline / fmt->bpp; 682 683 /* For RAW8 format bpp is 1, but the hardware process RAW8 684 * format in 2 pixel unit hence configure VNIS_REG as stride / 2. 685 */ 686 switch (vin->format.pixelformat) { 687 case V4L2_PIX_FMT_SBGGR8: 688 case V4L2_PIX_FMT_SGBRG8: 689 case V4L2_PIX_FMT_SGRBG8: 690 case V4L2_PIX_FMT_SRGGB8: 691 case V4L2_PIX_FMT_GREY: 692 stride /= 2; 693 break; 694 default: 695 break; 696 } 697 698 rvin_write(vin, stride, VNIS_REG); 699 } 700 701 /* ----------------------------------------------------------------------------- 702 * Hardware setup 703 */ 704 705 static int rvin_setup(struct rvin_dev *vin) 706 { 707 u32 vnmc, dmr, dmr2, interrupts; 708 bool progressive = false, output_is_yuv = false, input_is_yuv = false; 709 710 switch (vin->format.field) { 711 case V4L2_FIELD_TOP: 712 vnmc = VNMC_IM_ODD; 713 break; 714 case V4L2_FIELD_BOTTOM: 715 vnmc = VNMC_IM_EVEN; 716 break; 717 case V4L2_FIELD_INTERLACED: 718 /* Default to TB */ 719 vnmc = VNMC_IM_FULL; 720 /* Use BT if video standard can be read and is 60 Hz format */ 721 if (!vin->info->use_mc && vin->std & V4L2_STD_525_60) 722 vnmc = VNMC_IM_FULL | VNMC_FOC; 723 break; 724 case V4L2_FIELD_INTERLACED_TB: 725 vnmc = VNMC_IM_FULL; 726 break; 727 case V4L2_FIELD_INTERLACED_BT: 728 vnmc = VNMC_IM_FULL | VNMC_FOC; 729 break; 730 case V4L2_FIELD_SEQ_TB: 731 case V4L2_FIELD_SEQ_BT: 732 case V4L2_FIELD_NONE: 733 case V4L2_FIELD_ALTERNATE: 734 vnmc = VNMC_IM_ODD_EVEN; 735 progressive = true; 736 break; 737 default: 738 vnmc = VNMC_IM_ODD; 739 break; 740 } 741 742 /* 743 * Input interface 744 */ 745 switch (vin->mbus_code) { 746 case MEDIA_BUS_FMT_YUYV8_1X16: 747 if (vin->is_csi) 748 /* YCbCr422 8-bit */ 749 vnmc |= VNMC_INF_YUV8_BT601; 750 else 751 /* BT.601/BT.1358 16bit YCbCr422 */ 752 vnmc |= VNMC_INF_YUV16; 753 input_is_yuv = true; 754 break; 755 case MEDIA_BUS_FMT_UYVY8_1X16: 756 if (vin->is_csi) 757 /* YCbCr422 8-bit */ 758 vnmc |= VNMC_INF_YUV8_BT601; 759 else 760 /* BT.601/BT.1358 16bit YCbCr422 */ 761 vnmc |= VNMC_INF_YUV16; 762 vnmc |= VNMC_YCAL; 763 input_is_yuv = true; 764 break; 765 case MEDIA_BUS_FMT_UYVY8_2X8: 766 /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ 767 if (!vin->is_csi && 768 vin->parallel.mbus_type == V4L2_MBUS_BT656) 769 vnmc |= VNMC_INF_YUV8_BT656; 770 else 771 vnmc |= VNMC_INF_YUV8_BT601; 772 773 input_is_yuv = true; 774 break; 775 case MEDIA_BUS_FMT_RGB888_1X24: 776 vnmc |= VNMC_INF_RGB888; 777 break; 778 case MEDIA_BUS_FMT_UYVY10_2X10: 779 /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ 780 if (!vin->is_csi && 781 vin->parallel.mbus_type == V4L2_MBUS_BT656) 782 vnmc |= VNMC_INF_YUV10_BT656; 783 else 784 vnmc |= VNMC_INF_YUV10_BT601; 785 786 input_is_yuv = true; 787 break; 788 case MEDIA_BUS_FMT_SBGGR8_1X8: 789 case MEDIA_BUS_FMT_SGBRG8_1X8: 790 case MEDIA_BUS_FMT_SGRBG8_1X8: 791 case MEDIA_BUS_FMT_SRGGB8_1X8: 792 case MEDIA_BUS_FMT_Y8_1X8: 793 vnmc |= VNMC_INF_RAW8; 794 break; 795 case MEDIA_BUS_FMT_SBGGR10_1X10: 796 case MEDIA_BUS_FMT_SGBRG10_1X10: 797 case MEDIA_BUS_FMT_SGRBG10_1X10: 798 case MEDIA_BUS_FMT_SRGGB10_1X10: 799 vnmc |= VNMC_INF_RGB666; 800 break; 801 default: 802 break; 803 } 804 805 /* Make sure input interface and input format is valid. */ 806 if (vin->info->model == RCAR_GEN3) { 807 switch (vnmc & VNMC_INF_MASK) { 808 case VNMC_INF_YUV8_BT656: 809 case VNMC_INF_YUV10_BT656: 810 case VNMC_INF_YUV16: 811 case VNMC_INF_RGB666: 812 if (vin->is_csi) { 813 vin_err(vin, "Invalid setting in MIPI CSI2\n"); 814 return -EINVAL; 815 } 816 break; 817 case VNMC_INF_RAW8: 818 if (!vin->is_csi) { 819 vin_err(vin, "Invalid setting in Digital Pins\n"); 820 return -EINVAL; 821 } 822 break; 823 default: 824 break; 825 } 826 } 827 828 /* Enable VSYNC Field Toggle mode after one VSYNC input */ 829 if (vin->info->model == RCAR_GEN3) 830 dmr2 = VNDMR2_FTEV; 831 else 832 dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1); 833 834 if (!vin->is_csi) { 835 /* Hsync Signal Polarity Select */ 836 if (!(vin->parallel.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) 837 dmr2 |= VNDMR2_HPS; 838 839 /* Vsync Signal Polarity Select */ 840 if (!(vin->parallel.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) 841 dmr2 |= VNDMR2_VPS; 842 843 /* Data Enable Polarity Select */ 844 if (vin->parallel.bus.flags & V4L2_MBUS_DATA_ENABLE_LOW) 845 dmr2 |= VNDMR2_CES; 846 847 switch (vin->mbus_code) { 848 case MEDIA_BUS_FMT_UYVY8_2X8: 849 if (vin->parallel.bus.bus_width == 8 && 850 vin->parallel.bus.data_shift == 8) 851 dmr2 |= VNDMR2_YDS; 852 break; 853 default: 854 break; 855 } 856 } 857 858 /* 859 * Output format 860 */ 861 switch (vin->format.pixelformat) { 862 case V4L2_PIX_FMT_NV12: 863 case V4L2_PIX_FMT_NV16: 864 rvin_write(vin, 865 ALIGN(vin->format.bytesperline * vin->format.height, 866 0x80), VNUVAOF_REG); 867 dmr = vin->format.pixelformat == V4L2_PIX_FMT_NV12 ? 868 VNDMR_DTMD_YCSEP_420 : VNDMR_DTMD_YCSEP; 869 output_is_yuv = true; 870 break; 871 case V4L2_PIX_FMT_YUYV: 872 dmr = VNDMR_BPSM; 873 output_is_yuv = true; 874 break; 875 case V4L2_PIX_FMT_UYVY: 876 dmr = 0; 877 output_is_yuv = true; 878 break; 879 case V4L2_PIX_FMT_XRGB555: 880 dmr = VNDMR_DTMD_ARGB; 881 break; 882 case V4L2_PIX_FMT_RGB565: 883 dmr = 0; 884 break; 885 case V4L2_PIX_FMT_XBGR32: 886 /* Note: not supported on M1 */ 887 dmr = VNDMR_EXRGB; 888 break; 889 case V4L2_PIX_FMT_ARGB555: 890 dmr = (vin->alpha ? VNDMR_ABIT : 0) | VNDMR_DTMD_ARGB; 891 break; 892 case V4L2_PIX_FMT_ABGR32: 893 dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB; 894 break; 895 case V4L2_PIX_FMT_SBGGR8: 896 case V4L2_PIX_FMT_SGBRG8: 897 case V4L2_PIX_FMT_SGRBG8: 898 case V4L2_PIX_FMT_SRGGB8: 899 dmr = 0; 900 break; 901 case V4L2_PIX_FMT_GREY: 902 if (input_is_yuv) { 903 dmr = VNDMR_DTMD_YCSEP | VNDMR_YMODE_Y8; 904 output_is_yuv = true; 905 } else { 906 dmr = 0; 907 } 908 break; 909 case V4L2_PIX_FMT_SBGGR10: 910 case V4L2_PIX_FMT_SGBRG10: 911 case V4L2_PIX_FMT_SGRBG10: 912 case V4L2_PIX_FMT_SRGGB10: 913 dmr = VNDMR_RMODE_RAW10 | VNDMR_YC_THR; 914 break; 915 default: 916 vin_err(vin, "Invalid pixelformat (0x%x)\n", 917 vin->format.pixelformat); 918 return -EINVAL; 919 } 920 921 /* Always update on field change */ 922 vnmc |= VNMC_VUP; 923 924 if (!vin->info->use_isp) { 925 /* If input and output use the same colorspace, use bypass mode */ 926 if (input_is_yuv == output_is_yuv) 927 vnmc |= VNMC_BPS; 928 929 if (vin->info->model == RCAR_GEN3) { 930 /* Select between CSI-2 and parallel input */ 931 if (vin->is_csi) 932 vnmc &= ~VNMC_DPINE; 933 else 934 vnmc |= VNMC_DPINE; 935 } 936 } 937 938 /* Progressive or interlaced mode */ 939 interrupts = progressive ? VNIE_FIE : VNIE_EFE; 940 941 /* Ack interrupts */ 942 rvin_write(vin, interrupts, VNINTS_REG); 943 /* Enable interrupts */ 944 rvin_write(vin, interrupts, VNIE_REG); 945 /* Start capturing */ 946 rvin_write(vin, dmr, VNDMR_REG); 947 rvin_write(vin, dmr2, VNDMR2_REG); 948 949 /* Enable module */ 950 rvin_write(vin, vnmc | VNMC_ME, VNMC_REG); 951 952 return 0; 953 } 954 955 static void rvin_disable_interrupts(struct rvin_dev *vin) 956 { 957 rvin_write(vin, 0, VNIE_REG); 958 } 959 960 static u32 rvin_get_interrupt_status(struct rvin_dev *vin) 961 { 962 return rvin_read(vin, VNINTS_REG); 963 } 964 965 static void rvin_ack_interrupt(struct rvin_dev *vin) 966 { 967 rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG); 968 } 969 970 static bool rvin_capture_active(struct rvin_dev *vin) 971 { 972 return rvin_read(vin, VNMS_REG) & VNMS_CA; 973 } 974 975 static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) 976 { 977 if (vin->format.field == V4L2_FIELD_ALTERNATE) { 978 /* If FS is set it is an Even field. */ 979 if (vnms & VNMS_FS) 980 return V4L2_FIELD_BOTTOM; 981 return V4L2_FIELD_TOP; 982 } 983 984 return vin->format.field; 985 } 986 987 static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) 988 { 989 const struct rvin_video_format *fmt; 990 int offsetx, offsety; 991 dma_addr_t offset; 992 993 fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); 994 995 /* 996 * There is no HW support for composition do the beast we can 997 * by modifying the buffer offset 998 */ 999 offsetx = vin->compose.left * fmt->bpp; 1000 offsety = vin->compose.top * vin->format.bytesperline; 1001 offset = addr + offsetx + offsety; 1002 1003 /* 1004 * The address needs to be 128 bytes aligned. Driver should never accept 1005 * settings that do not satisfy this in the first place... 1006 */ 1007 if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK)) 1008 return; 1009 1010 rvin_write(vin, offset, VNMB_REG(slot)); 1011 } 1012 1013 /* 1014 * Moves a buffer from the queue to the HW slot. If no buffer is 1015 * available use the scratch buffer. The scratch buffer is never 1016 * returned to userspace, its only function is to enable the capture 1017 * loop to keep running. 1018 */ 1019 static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) 1020 { 1021 struct rvin_buffer *buf; 1022 struct vb2_v4l2_buffer *vbuf; 1023 dma_addr_t phys_addr; 1024 int prev; 1025 1026 /* A already populated slot shall never be overwritten. */ 1027 if (WARN_ON(vin->buf_hw[slot].buffer)) 1028 return; 1029 1030 prev = (slot == 0 ? HW_BUFFER_NUM : slot) - 1; 1031 1032 if (vin->buf_hw[prev].type == HALF_TOP) { 1033 vbuf = vin->buf_hw[prev].buffer; 1034 vin->buf_hw[slot].buffer = vbuf; 1035 vin->buf_hw[slot].type = HALF_BOTTOM; 1036 switch (vin->format.pixelformat) { 1037 case V4L2_PIX_FMT_NV12: 1038 case V4L2_PIX_FMT_NV16: 1039 phys_addr = vin->buf_hw[prev].phys + 1040 vin->format.sizeimage / 4; 1041 break; 1042 default: 1043 phys_addr = vin->buf_hw[prev].phys + 1044 vin->format.sizeimage / 2; 1045 break; 1046 } 1047 } else if ((vin->state != STOPPED && vin->state != RUNNING) || 1048 list_empty(&vin->buf_list)) { 1049 vin->buf_hw[slot].buffer = NULL; 1050 vin->buf_hw[slot].type = FULL; 1051 phys_addr = vin->scratch_phys; 1052 } else { 1053 /* Keep track of buffer we give to HW */ 1054 buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); 1055 vbuf = &buf->vb; 1056 list_del_init(to_buf_list(vbuf)); 1057 vin->buf_hw[slot].buffer = vbuf; 1058 1059 vin->buf_hw[slot].type = 1060 V4L2_FIELD_IS_SEQUENTIAL(vin->format.field) ? 1061 HALF_TOP : FULL; 1062 1063 /* Setup DMA */ 1064 phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); 1065 } 1066 1067 vin_dbg(vin, "Filling HW slot: %d type: %d buffer: %p\n", 1068 slot, vin->buf_hw[slot].type, vin->buf_hw[slot].buffer); 1069 1070 vin->buf_hw[slot].phys = phys_addr; 1071 rvin_set_slot_addr(vin, slot, phys_addr); 1072 } 1073 1074 static int rvin_capture_start(struct rvin_dev *vin) 1075 { 1076 int slot, ret; 1077 1078 for (slot = 0; slot < HW_BUFFER_NUM; slot++) { 1079 vin->buf_hw[slot].buffer = NULL; 1080 vin->buf_hw[slot].type = FULL; 1081 } 1082 1083 for (slot = 0; slot < HW_BUFFER_NUM; slot++) 1084 rvin_fill_hw_slot(vin, slot); 1085 1086 ret = rvin_setup(vin); 1087 if (ret) 1088 return ret; 1089 1090 rvin_crop_scale_comp(vin); 1091 1092 vin_dbg(vin, "Starting to capture\n"); 1093 1094 /* Continuous Frame Capture Mode */ 1095 rvin_write(vin, VNFC_C_FRAME, VNFC_REG); 1096 1097 vin->state = STARTING; 1098 1099 return 0; 1100 } 1101 1102 static void rvin_capture_stop(struct rvin_dev *vin) 1103 { 1104 /* Set continuous & single transfer off */ 1105 rvin_write(vin, 0, VNFC_REG); 1106 1107 /* Disable module */ 1108 rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG); 1109 } 1110 1111 /* ----------------------------------------------------------------------------- 1112 * DMA Functions 1113 */ 1114 1115 #define RVIN_TIMEOUT_MS 100 1116 #define RVIN_RETRIES 10 1117 1118 static irqreturn_t rvin_irq(int irq, void *data) 1119 { 1120 struct rvin_dev *vin = data; 1121 u32 int_status, vnms; 1122 int slot; 1123 unsigned int handled = 0; 1124 unsigned long flags; 1125 1126 spin_lock_irqsave(&vin->qlock, flags); 1127 1128 int_status = rvin_get_interrupt_status(vin); 1129 if (!int_status) 1130 goto done; 1131 1132 rvin_ack_interrupt(vin); 1133 handled = 1; 1134 1135 /* Nothing to do if nothing was captured. */ 1136 if (!(int_status & VNINTS_FIS)) 1137 goto done; 1138 1139 /* Nothing to do if capture status is 'STOPPED' */ 1140 if (vin->state == STOPPED) { 1141 vin_dbg(vin, "IRQ while state stopped\n"); 1142 goto done; 1143 } 1144 1145 /* Prepare for capture and update state */ 1146 vnms = rvin_read(vin, VNMS_REG); 1147 slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; 1148 1149 /* 1150 * To hand buffers back in a known order to userspace start 1151 * to capture first from slot 0. 1152 */ 1153 if (vin->state == STARTING) { 1154 if (slot != 0) { 1155 vin_dbg(vin, "Starting sync slot: %d\n", slot); 1156 goto done; 1157 } 1158 1159 vin_dbg(vin, "Capture start synced!\n"); 1160 vin->state = RUNNING; 1161 } 1162 1163 /* Capture frame */ 1164 if (vin->buf_hw[slot].buffer) { 1165 /* 1166 * Nothing to do but refill the hardware slot if 1167 * capture only filled first half of vb2 buffer. 1168 */ 1169 if (vin->buf_hw[slot].type == HALF_TOP) { 1170 vin->buf_hw[slot].buffer = NULL; 1171 rvin_fill_hw_slot(vin, slot); 1172 goto done; 1173 } 1174 1175 vin->buf_hw[slot].buffer->field = 1176 rvin_get_active_field(vin, vnms); 1177 vin->buf_hw[slot].buffer->sequence = vin->sequence; 1178 vin->buf_hw[slot].buffer->vb2_buf.timestamp = ktime_get_ns(); 1179 vb2_buffer_done(&vin->buf_hw[slot].buffer->vb2_buf, 1180 VB2_BUF_STATE_DONE); 1181 vin->buf_hw[slot].buffer = NULL; 1182 } else { 1183 /* Scratch buffer was used, dropping frame. */ 1184 vin_dbg(vin, "Dropping frame %u\n", vin->sequence); 1185 } 1186 1187 vin->sequence++; 1188 1189 /* Prepare for next frame */ 1190 rvin_fill_hw_slot(vin, slot); 1191 done: 1192 spin_unlock_irqrestore(&vin->qlock, flags); 1193 1194 return IRQ_RETVAL(handled); 1195 } 1196 1197 static void return_unused_buffers(struct rvin_dev *vin, 1198 enum vb2_buffer_state state) 1199 { 1200 struct rvin_buffer *buf, *node; 1201 unsigned long flags; 1202 1203 spin_lock_irqsave(&vin->qlock, flags); 1204 1205 list_for_each_entry_safe(buf, node, &vin->buf_list, list) { 1206 vb2_buffer_done(&buf->vb.vb2_buf, state); 1207 list_del(&buf->list); 1208 } 1209 1210 spin_unlock_irqrestore(&vin->qlock, flags); 1211 } 1212 1213 static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, 1214 unsigned int *nplanes, unsigned int sizes[], 1215 struct device *alloc_devs[]) 1216 1217 { 1218 struct rvin_dev *vin = vb2_get_drv_priv(vq); 1219 1220 /* Make sure the image size is large enough. */ 1221 if (*nplanes) 1222 return sizes[0] < vin->format.sizeimage ? -EINVAL : 0; 1223 1224 *nplanes = 1; 1225 sizes[0] = vin->format.sizeimage; 1226 1227 return 0; 1228 }; 1229 1230 static int rvin_buffer_prepare(struct vb2_buffer *vb) 1231 { 1232 struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue); 1233 unsigned long size = vin->format.sizeimage; 1234 1235 if (vb2_plane_size(vb, 0) < size) { 1236 vin_err(vin, "buffer too small (%lu < %lu)\n", 1237 vb2_plane_size(vb, 0), size); 1238 return -EINVAL; 1239 } 1240 1241 vb2_set_plane_payload(vb, 0, size); 1242 1243 return 0; 1244 } 1245 1246 static void rvin_buffer_queue(struct vb2_buffer *vb) 1247 { 1248 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1249 struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue); 1250 unsigned long flags; 1251 1252 spin_lock_irqsave(&vin->qlock, flags); 1253 1254 list_add_tail(to_buf_list(vbuf), &vin->buf_list); 1255 1256 spin_unlock_irqrestore(&vin->qlock, flags); 1257 } 1258 1259 static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, 1260 struct media_pad *pad) 1261 { 1262 struct v4l2_subdev_format fmt = { 1263 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 1264 }; 1265 1266 fmt.pad = pad->index; 1267 if (v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt)) 1268 return -EPIPE; 1269 1270 switch (fmt.format.code) { 1271 case MEDIA_BUS_FMT_YUYV8_1X16: 1272 case MEDIA_BUS_FMT_UYVY8_1X16: 1273 case MEDIA_BUS_FMT_UYVY8_2X8: 1274 case MEDIA_BUS_FMT_UYVY10_2X10: 1275 case MEDIA_BUS_FMT_RGB888_1X24: 1276 break; 1277 case MEDIA_BUS_FMT_SBGGR8_1X8: 1278 if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR8) 1279 return -EPIPE; 1280 break; 1281 case MEDIA_BUS_FMT_SGBRG8_1X8: 1282 if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG8) 1283 return -EPIPE; 1284 break; 1285 case MEDIA_BUS_FMT_SGRBG8_1X8: 1286 if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG8) 1287 return -EPIPE; 1288 break; 1289 case MEDIA_BUS_FMT_SRGGB8_1X8: 1290 if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8) 1291 return -EPIPE; 1292 break; 1293 case MEDIA_BUS_FMT_Y8_1X8: 1294 if (vin->format.pixelformat != V4L2_PIX_FMT_GREY) 1295 return -EPIPE; 1296 break; 1297 case MEDIA_BUS_FMT_SBGGR10_1X10: 1298 if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR10) 1299 return -EPIPE; 1300 break; 1301 case MEDIA_BUS_FMT_SGBRG10_1X10: 1302 if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG10) 1303 return -EPIPE; 1304 break; 1305 case MEDIA_BUS_FMT_SGRBG10_1X10: 1306 if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG10) 1307 return -EPIPE; 1308 break; 1309 case MEDIA_BUS_FMT_SRGGB10_1X10: 1310 if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB10) 1311 return -EPIPE; 1312 break; 1313 default: 1314 return -EPIPE; 1315 } 1316 vin->mbus_code = fmt.format.code; 1317 1318 switch (fmt.format.field) { 1319 case V4L2_FIELD_TOP: 1320 case V4L2_FIELD_BOTTOM: 1321 case V4L2_FIELD_NONE: 1322 case V4L2_FIELD_INTERLACED_TB: 1323 case V4L2_FIELD_INTERLACED_BT: 1324 case V4L2_FIELD_INTERLACED: 1325 case V4L2_FIELD_SEQ_TB: 1326 case V4L2_FIELD_SEQ_BT: 1327 /* Supported natively */ 1328 break; 1329 case V4L2_FIELD_ALTERNATE: 1330 switch (vin->format.field) { 1331 case V4L2_FIELD_TOP: 1332 case V4L2_FIELD_BOTTOM: 1333 case V4L2_FIELD_NONE: 1334 case V4L2_FIELD_ALTERNATE: 1335 break; 1336 case V4L2_FIELD_INTERLACED_TB: 1337 case V4L2_FIELD_INTERLACED_BT: 1338 case V4L2_FIELD_INTERLACED: 1339 case V4L2_FIELD_SEQ_TB: 1340 case V4L2_FIELD_SEQ_BT: 1341 /* Use VIN hardware to combine the two fields */ 1342 fmt.format.height *= 2; 1343 break; 1344 default: 1345 return -EPIPE; 1346 } 1347 break; 1348 default: 1349 return -EPIPE; 1350 } 1351 1352 if (rvin_scaler_needed(vin)) { 1353 /* Gen3 can't scale NV12 */ 1354 if (vin->info->model == RCAR_GEN3 && 1355 vin->format.pixelformat == V4L2_PIX_FMT_NV12) 1356 return -EPIPE; 1357 1358 if (!vin->scaler) 1359 return -EPIPE; 1360 } else { 1361 if (vin->format.pixelformat == V4L2_PIX_FMT_NV12) { 1362 if (ALIGN(fmt.format.width, 32) != vin->format.width || 1363 ALIGN(fmt.format.height, 32) != vin->format.height) 1364 return -EPIPE; 1365 } else { 1366 if (fmt.format.width != vin->format.width || 1367 fmt.format.height != vin->format.height) 1368 return -EPIPE; 1369 } 1370 } 1371 1372 if (fmt.format.code != vin->mbus_code) 1373 return -EPIPE; 1374 1375 return 0; 1376 } 1377 1378 static int rvin_set_stream(struct rvin_dev *vin, int on) 1379 { 1380 struct v4l2_subdev *sd; 1381 struct media_pad *pad; 1382 int ret; 1383 1384 /* No media controller used, simply pass operation to subdevice. */ 1385 if (!vin->info->use_mc) { 1386 ret = v4l2_subdev_call(vin->parallel.subdev, video, s_stream, 1387 on); 1388 1389 return ret == -ENOIOCTLCMD ? 0 : ret; 1390 } 1391 1392 pad = media_pad_remote_pad_first(&vin->pad); 1393 if (!pad) 1394 return -EPIPE; 1395 1396 sd = media_entity_to_v4l2_subdev(pad->entity); 1397 1398 if (!on) { 1399 video_device_pipeline_stop(&vin->vdev); 1400 return v4l2_subdev_call(sd, video, s_stream, 0); 1401 } 1402 1403 ret = rvin_mc_validate_format(vin, sd, pad); 1404 if (ret) 1405 return ret; 1406 1407 ret = video_device_pipeline_alloc_start(&vin->vdev); 1408 if (ret) 1409 return ret; 1410 1411 ret = v4l2_subdev_call(sd, video, s_stream, 1); 1412 if (ret == -ENOIOCTLCMD) 1413 ret = 0; 1414 if (ret) 1415 video_device_pipeline_stop(&vin->vdev); 1416 1417 return ret; 1418 } 1419 1420 int rvin_start_streaming(struct rvin_dev *vin) 1421 { 1422 unsigned long flags; 1423 int ret; 1424 1425 ret = rvin_set_stream(vin, 1); 1426 if (ret) 1427 return ret; 1428 1429 spin_lock_irqsave(&vin->qlock, flags); 1430 1431 vin->sequence = 0; 1432 1433 ret = rvin_capture_start(vin); 1434 if (ret) 1435 rvin_set_stream(vin, 0); 1436 1437 spin_unlock_irqrestore(&vin->qlock, flags); 1438 1439 return ret; 1440 } 1441 1442 static int rvin_start_streaming_vq(struct vb2_queue *vq, unsigned int count) 1443 { 1444 struct rvin_dev *vin = vb2_get_drv_priv(vq); 1445 int ret = -ENOMEM; 1446 1447 /* Allocate scratch buffer. */ 1448 vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage, 1449 &vin->scratch_phys, GFP_KERNEL); 1450 if (!vin->scratch) 1451 goto err_scratch; 1452 1453 ret = rvin_start_streaming(vin); 1454 if (ret) 1455 goto err_start; 1456 1457 return 0; 1458 err_start: 1459 dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, 1460 vin->scratch_phys); 1461 err_scratch: 1462 return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); 1463 1464 return ret; 1465 } 1466 1467 void rvin_stop_streaming(struct rvin_dev *vin) 1468 { 1469 unsigned int i, retries; 1470 unsigned long flags; 1471 bool buffersFreed; 1472 1473 spin_lock_irqsave(&vin->qlock, flags); 1474 1475 if (vin->state == STOPPED) { 1476 spin_unlock_irqrestore(&vin->qlock, flags); 1477 return; 1478 } 1479 1480 vin->state = STOPPING; 1481 1482 /* Wait until only scratch buffer is used, max 3 interrupts. */ 1483 retries = 0; 1484 while (retries++ < RVIN_RETRIES) { 1485 buffersFreed = true; 1486 for (i = 0; i < HW_BUFFER_NUM; i++) 1487 if (vin->buf_hw[i].buffer) 1488 buffersFreed = false; 1489 1490 if (buffersFreed) 1491 break; 1492 1493 spin_unlock_irqrestore(&vin->qlock, flags); 1494 msleep(RVIN_TIMEOUT_MS); 1495 spin_lock_irqsave(&vin->qlock, flags); 1496 } 1497 1498 /* Wait for streaming to stop */ 1499 retries = 0; 1500 while (retries++ < RVIN_RETRIES) { 1501 1502 rvin_capture_stop(vin); 1503 1504 /* Check if HW is stopped */ 1505 if (!rvin_capture_active(vin)) { 1506 vin->state = STOPPED; 1507 break; 1508 } 1509 1510 spin_unlock_irqrestore(&vin->qlock, flags); 1511 msleep(RVIN_TIMEOUT_MS); 1512 spin_lock_irqsave(&vin->qlock, flags); 1513 } 1514 1515 if (!buffersFreed || vin->state != STOPPED) { 1516 /* 1517 * If this happens something have gone horribly wrong. 1518 * Set state to stopped to prevent the interrupt handler 1519 * to make things worse... 1520 */ 1521 vin_err(vin, "Failed stop HW, something is seriously broken\n"); 1522 vin->state = STOPPED; 1523 } 1524 1525 spin_unlock_irqrestore(&vin->qlock, flags); 1526 1527 /* If something went wrong, free buffers with an error. */ 1528 if (!buffersFreed) { 1529 return_unused_buffers(vin, VB2_BUF_STATE_ERROR); 1530 for (i = 0; i < HW_BUFFER_NUM; i++) { 1531 if (vin->buf_hw[i].buffer) 1532 vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf, 1533 VB2_BUF_STATE_ERROR); 1534 } 1535 } 1536 1537 rvin_set_stream(vin, 0); 1538 1539 /* disable interrupts */ 1540 rvin_disable_interrupts(vin); 1541 } 1542 1543 static void rvin_stop_streaming_vq(struct vb2_queue *vq) 1544 { 1545 struct rvin_dev *vin = vb2_get_drv_priv(vq); 1546 1547 rvin_stop_streaming(vin); 1548 1549 /* Free scratch buffer. */ 1550 dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, 1551 vin->scratch_phys); 1552 1553 return_unused_buffers(vin, VB2_BUF_STATE_ERROR); 1554 } 1555 1556 static const struct vb2_ops rvin_qops = { 1557 .queue_setup = rvin_queue_setup, 1558 .buf_prepare = rvin_buffer_prepare, 1559 .buf_queue = rvin_buffer_queue, 1560 .start_streaming = rvin_start_streaming_vq, 1561 .stop_streaming = rvin_stop_streaming_vq, 1562 }; 1563 1564 void rvin_dma_unregister(struct rvin_dev *vin) 1565 { 1566 mutex_destroy(&vin->lock); 1567 1568 v4l2_device_unregister(&vin->v4l2_dev); 1569 } 1570 1571 int rvin_dma_register(struct rvin_dev *vin, int irq) 1572 { 1573 struct vb2_queue *q = &vin->queue; 1574 int i, ret; 1575 1576 /* Initialize the top-level structure */ 1577 ret = v4l2_device_register(vin->dev, &vin->v4l2_dev); 1578 if (ret) 1579 return ret; 1580 1581 mutex_init(&vin->lock); 1582 INIT_LIST_HEAD(&vin->buf_list); 1583 1584 spin_lock_init(&vin->qlock); 1585 1586 vin->state = STOPPED; 1587 1588 for (i = 0; i < HW_BUFFER_NUM; i++) 1589 vin->buf_hw[i].buffer = NULL; 1590 1591 /* buffer queue */ 1592 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1593 q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; 1594 q->lock = &vin->lock; 1595 q->drv_priv = vin; 1596 q->buf_struct_size = sizeof(struct rvin_buffer); 1597 q->ops = &rvin_qops; 1598 q->mem_ops = &vb2_dma_contig_memops; 1599 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 1600 q->min_queued_buffers = 4; 1601 q->dev = vin->dev; 1602 1603 ret = vb2_queue_init(q); 1604 if (ret < 0) { 1605 vin_err(vin, "failed to initialize VB2 queue\n"); 1606 goto error; 1607 } 1608 1609 /* irq */ 1610 ret = devm_request_irq(vin->dev, irq, rvin_irq, IRQF_SHARED, 1611 KBUILD_MODNAME, vin); 1612 if (ret) { 1613 vin_err(vin, "failed to request irq\n"); 1614 goto error; 1615 } 1616 1617 return 0; 1618 error: 1619 rvin_dma_unregister(vin); 1620 1621 return ret; 1622 } 1623 1624 /* ----------------------------------------------------------------------------- 1625 * Gen3 CHSEL manipulation 1626 */ 1627 1628 /* 1629 * There is no need to have locking around changing the routing 1630 * as it's only possible to do so when no VIN in the group is 1631 * streaming so nothing can race with the VNMC register. 1632 */ 1633 int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) 1634 { 1635 const struct rvin_group_route *route; 1636 u32 ifmd = 0; 1637 u32 vnmc; 1638 int ret; 1639 1640 ret = pm_runtime_resume_and_get(vin->dev); 1641 if (ret < 0) 1642 return ret; 1643 1644 /* Make register writes take effect immediately. */ 1645 vnmc = rvin_read(vin, VNMC_REG); 1646 rvin_write(vin, vnmc & ~VNMC_VUP, VNMC_REG); 1647 1648 /* 1649 * Set data expansion mode to "pad with 0s" by inspecting the routes 1650 * table to find out which bit fields are available in the IFMD 1651 * register. IFMD_DES1 controls data expansion mode for CSI20/21, 1652 * IFMD_DES0 controls data expansion mode for CSI40/41. 1653 */ 1654 for (route = vin->info->routes; route->chsel; route++) { 1655 if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21) 1656 ifmd |= VNCSI_IFMD_DES1; 1657 else 1658 ifmd |= VNCSI_IFMD_DES0; 1659 1660 if (ifmd == (VNCSI_IFMD_DES0 | VNCSI_IFMD_DES1)) 1661 break; 1662 } 1663 1664 if (ifmd) { 1665 ifmd |= VNCSI_IFMD_CSI_CHSEL(chsel); 1666 rvin_write(vin, ifmd, VNCSI_IFMD_REG); 1667 } 1668 1669 vin_dbg(vin, "Set IFMD 0x%x\n", ifmd); 1670 1671 vin->chsel = chsel; 1672 1673 /* Restore VNMC. */ 1674 rvin_write(vin, vnmc, VNMC_REG); 1675 1676 pm_runtime_put(vin->dev); 1677 1678 return 0; 1679 } 1680 1681 void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha) 1682 { 1683 unsigned long flags; 1684 u32 dmr; 1685 1686 spin_lock_irqsave(&vin->qlock, flags); 1687 1688 vin->alpha = alpha; 1689 1690 if (vin->state == STOPPED) 1691 goto out; 1692 1693 switch (vin->format.pixelformat) { 1694 case V4L2_PIX_FMT_ARGB555: 1695 dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_ABIT; 1696 if (vin->alpha) 1697 dmr |= VNDMR_ABIT; 1698 break; 1699 case V4L2_PIX_FMT_ABGR32: 1700 dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_A8BIT_MASK; 1701 dmr |= VNDMR_A8BIT(vin->alpha); 1702 break; 1703 default: 1704 goto out; 1705 } 1706 1707 rvin_write(vin, dmr, VNDMR_REG); 1708 out: 1709 spin_unlock_irqrestore(&vin->qlock, flags); 1710 } 1711