1aa7b8278SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0+ 2f00add96SNiklas Söderlund /* 3f00add96SNiklas Söderlund * Driver for Renesas R-Car VIN 4f00add96SNiklas Söderlund * 5f00add96SNiklas Söderlund * Copyright (C) 2016 Renesas Electronics Corp. 6f00add96SNiklas Söderlund * Copyright (C) 2011-2013 Renesas Solutions Corp. 7f00add96SNiklas Söderlund * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> 8f00add96SNiklas Söderlund * Copyright (C) 2008 Magnus Damm 9f00add96SNiklas Söderlund * 10f00add96SNiklas Söderlund * Based on the soc-camera rcar_vin driver 11f00add96SNiklas Söderlund */ 12f00add96SNiklas Söderlund 13f00add96SNiklas Söderlund #include <linux/delay.h> 14f00add96SNiklas Söderlund #include <linux/interrupt.h> 1590dedce9SNiklas Söderlund #include <linux/pm_runtime.h> 16f00add96SNiklas Söderlund 17f00add96SNiklas Söderlund #include <media/videobuf2-dma-contig.h> 18f00add96SNiklas Söderlund 19f00add96SNiklas Söderlund #include "rcar-vin.h" 20f00add96SNiklas Söderlund 21f00add96SNiklas Söderlund /* ----------------------------------------------------------------------------- 22f00add96SNiklas Söderlund * HW Functions 23f00add96SNiklas Söderlund */ 24f00add96SNiklas Söderlund 25f00add96SNiklas Söderlund /* Register offsets for R-Car VIN */ 26f00add96SNiklas Söderlund #define VNMC_REG 0x00 /* Video n Main Control Register */ 27f00add96SNiklas Söderlund #define VNMS_REG 0x04 /* Video n Module Status Register */ 28f00add96SNiklas Söderlund #define VNFC_REG 0x08 /* Video n Frame Capture Register */ 29f00add96SNiklas Söderlund #define VNSLPRC_REG 0x0C /* Video n Start Line Pre-Clip Register */ 30f00add96SNiklas Söderlund #define VNELPRC_REG 0x10 /* Video n End Line Pre-Clip Register */ 31f00add96SNiklas Söderlund #define VNSPPRC_REG 0x14 /* Video n Start Pixel Pre-Clip Register */ 32f00add96SNiklas Söderlund #define VNEPPRC_REG 0x18 /* Video n End Pixel Pre-Clip Register */ 33f00add96SNiklas Söderlund #define VNIS_REG 0x2C /* Video n Image Stride Register */ 34f00add96SNiklas Söderlund #define VNMB_REG(m) (0x30 + ((m) << 2)) /* Video n Memory Base m Register */ 35f00add96SNiklas Söderlund #define VNIE_REG 0x40 /* Video n Interrupt Enable Register */ 36f00add96SNiklas Söderlund #define VNINTS_REG 0x44 /* Video n Interrupt Status Register */ 37f00add96SNiklas Söderlund #define VNSI_REG 0x48 /* Video n Scanline Interrupt Register */ 38f00add96SNiklas Söderlund #define VNMTC_REG 0x4C /* Video n Memory Transfer Control Register */ 39f00add96SNiklas Söderlund #define VNDMR_REG 0x58 /* Video n Data Mode Register */ 40f00add96SNiklas Söderlund #define VNDMR2_REG 0x5C /* Video n Data Mode Register 2 */ 41f00add96SNiklas Söderlund #define VNUVAOF_REG 0x60 /* Video n UV Address Offset Register */ 424394eb24SNiklas Söderlund 434394eb24SNiklas Söderlund /* Register offsets specific for Gen2 */ 444394eb24SNiklas Söderlund #define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */ 454394eb24SNiklas Söderlund #define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */ 464394eb24SNiklas Söderlund #define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */ 474394eb24SNiklas Söderlund #define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */ 484394eb24SNiklas Söderlund #define VNYS_REG 0x50 /* Video n Y Scale Register */ 494394eb24SNiklas Söderlund #define VNXS_REG 0x54 /* Video n X Scale Register */ 50f00add96SNiklas Söderlund #define VNC1A_REG 0x80 /* Video n Coefficient Set C1A Register */ 51f00add96SNiklas Söderlund #define VNC1B_REG 0x84 /* Video n Coefficient Set C1B Register */ 52f00add96SNiklas Söderlund #define VNC1C_REG 0x88 /* Video n Coefficient Set C1C Register */ 53f00add96SNiklas Söderlund #define VNC2A_REG 0x90 /* Video n Coefficient Set C2A Register */ 54f00add96SNiklas Söderlund #define VNC2B_REG 0x94 /* Video n Coefficient Set C2B Register */ 55f00add96SNiklas Söderlund #define VNC2C_REG 0x98 /* Video n Coefficient Set C2C Register */ 56f00add96SNiklas Söderlund #define VNC3A_REG 0xA0 /* Video n Coefficient Set C3A Register */ 57f00add96SNiklas Söderlund #define VNC3B_REG 0xA4 /* Video n Coefficient Set C3B Register */ 58f00add96SNiklas Söderlund #define VNC3C_REG 0xA8 /* Video n Coefficient Set C3C Register */ 59f00add96SNiklas Söderlund #define VNC4A_REG 0xB0 /* Video n Coefficient Set C4A Register */ 60f00add96SNiklas Söderlund #define VNC4B_REG 0xB4 /* Video n Coefficient Set C4B Register */ 61f00add96SNiklas Söderlund #define VNC4C_REG 0xB8 /* Video n Coefficient Set C4C Register */ 62f00add96SNiklas Söderlund #define VNC5A_REG 0xC0 /* Video n Coefficient Set C5A Register */ 63f00add96SNiklas Söderlund #define VNC5B_REG 0xC4 /* Video n Coefficient Set C5B Register */ 64f00add96SNiklas Söderlund #define VNC5C_REG 0xC8 /* Video n Coefficient Set C5C Register */ 65f00add96SNiklas Söderlund #define VNC6A_REG 0xD0 /* Video n Coefficient Set C6A Register */ 66f00add96SNiklas Söderlund #define VNC6B_REG 0xD4 /* Video n Coefficient Set C6B Register */ 67f00add96SNiklas Söderlund #define VNC6C_REG 0xD8 /* Video n Coefficient Set C6C Register */ 68f00add96SNiklas Söderlund #define VNC7A_REG 0xE0 /* Video n Coefficient Set C7A Register */ 69f00add96SNiklas Söderlund #define VNC7B_REG 0xE4 /* Video n Coefficient Set C7B Register */ 70f00add96SNiklas Söderlund #define VNC7C_REG 0xE8 /* Video n Coefficient Set C7C Register */ 71f00add96SNiklas Söderlund #define VNC8A_REG 0xF0 /* Video n Coefficient Set C8A Register */ 72f00add96SNiklas Söderlund #define VNC8B_REG 0xF4 /* Video n Coefficient Set C8B Register */ 73f00add96SNiklas Söderlund #define VNC8C_REG 0xF8 /* Video n Coefficient Set C8C Register */ 74f00add96SNiklas Söderlund 754394eb24SNiklas Söderlund /* Register offsets specific for Gen3 */ 764394eb24SNiklas Söderlund #define VNCSI_IFMD_REG 0x20 /* Video n CSI2 Interface Mode Register */ 77f00add96SNiklas Söderlund 78f00add96SNiklas Söderlund /* Register bit fields for R-Car VIN */ 79f00add96SNiklas Söderlund /* Video n Main Control Register bits */ 8078b3f9d7SNiklas Söderlund #define VNMC_INF_MASK (7 << 16) 814394eb24SNiklas Söderlund #define VNMC_DPINE (1 << 27) /* Gen3 specific */ 824394eb24SNiklas Söderlund #define VNMC_SCLE (1 << 26) /* Gen3 specific */ 83f00add96SNiklas Söderlund #define VNMC_FOC (1 << 21) 84f00add96SNiklas Söderlund #define VNMC_YCAL (1 << 19) 85f00add96SNiklas Söderlund #define VNMC_INF_YUV8_BT656 (0 << 16) 86f00add96SNiklas Söderlund #define VNMC_INF_YUV8_BT601 (1 << 16) 87f00add96SNiklas Söderlund #define VNMC_INF_YUV10_BT656 (2 << 16) 88f00add96SNiklas Söderlund #define VNMC_INF_YUV10_BT601 (3 << 16) 89e87c1a81SLad Prabhakar #define VNMC_INF_RAW8 (4 << 16) 90f00add96SNiklas Söderlund #define VNMC_INF_YUV16 (5 << 16) 91f00add96SNiklas Söderlund #define VNMC_INF_RGB888 (6 << 16) 9278b3f9d7SNiklas Söderlund #define VNMC_INF_RGB666 (7 << 16) 93f00add96SNiklas Söderlund #define VNMC_VUP (1 << 10) 94f00add96SNiklas Söderlund #define VNMC_IM_ODD (0 << 3) 95f00add96SNiklas Söderlund #define VNMC_IM_ODD_EVEN (1 << 3) 96f00add96SNiklas Söderlund #define VNMC_IM_EVEN (2 << 3) 97f00add96SNiklas Söderlund #define VNMC_IM_FULL (3 << 3) 98f00add96SNiklas Söderlund #define VNMC_BPS (1 << 1) 99f00add96SNiklas Söderlund #define VNMC_ME (1 << 0) 100f00add96SNiklas Söderlund 101f00add96SNiklas Söderlund /* Video n Module Status Register bits */ 102f00add96SNiklas Söderlund #define VNMS_FBS_MASK (3 << 3) 103f00add96SNiklas Söderlund #define VNMS_FBS_SHIFT 3 104b6f556cbSNiklas Söderlund #define VNMS_FS (1 << 2) 105f00add96SNiklas Söderlund #define VNMS_AV (1 << 1) 106f00add96SNiklas Söderlund #define VNMS_CA (1 << 0) 107f00add96SNiklas Söderlund 108f00add96SNiklas Söderlund /* Video n Frame Capture Register bits */ 109f00add96SNiklas Söderlund #define VNFC_C_FRAME (1 << 1) 110f00add96SNiklas Söderlund #define VNFC_S_FRAME (1 << 0) 111f00add96SNiklas Söderlund 112f00add96SNiklas Söderlund /* Video n Interrupt Enable Register bits */ 113f00add96SNiklas Söderlund #define VNIE_FIE (1 << 4) 114f00add96SNiklas Söderlund #define VNIE_EFE (1 << 1) 115f00add96SNiklas Söderlund 11630334d3dSNiklas Söderlund /* Video n Interrupt Status Register bits */ 11730334d3dSNiklas Söderlund #define VNINTS_FIS (1 << 4) 11830334d3dSNiklas Söderlund 119f00add96SNiklas Söderlund /* Video n Data Mode Register bits */ 1201d99e68cSNiklas Söderlund #define VNDMR_A8BIT(n) (((n) & 0xff) << 24) 1211d99e68cSNiklas Söderlund #define VNDMR_A8BIT_MASK (0xff << 24) 122c93beb52SVladimir Barinov #define VNDMR_YMODE_Y8 (1 << 12) 123f00add96SNiklas Söderlund #define VNDMR_EXRGB (1 << 8) 124f00add96SNiklas Söderlund #define VNDMR_BPSM (1 << 4) 1251d99e68cSNiklas Söderlund #define VNDMR_ABIT (1 << 2) 126f00add96SNiklas Söderlund #define VNDMR_DTMD_YCSEP (1 << 1) 12719ab1f64SNiklas Söderlund #define VNDMR_DTMD_ARGB (1 << 0) 1289b744a3eSNiklas Söderlund #define VNDMR_DTMD_YCSEP_420 (3 << 0) 129f00add96SNiklas Söderlund 130f00add96SNiklas Söderlund /* Video n Data Mode Register 2 bits */ 131f00add96SNiklas Söderlund #define VNDMR2_VPS (1 << 30) 132f00add96SNiklas Söderlund #define VNDMR2_HPS (1 << 29) 13353cf3100SJacopo Mondi #define VNDMR2_CES (1 << 28) 134e8834943SLad Prabhakar #define VNDMR2_YDS (1 << 22) 135f00add96SNiklas Söderlund #define VNDMR2_FTEV (1 << 17) 136f00add96SNiklas Söderlund #define VNDMR2_VLV(n) ((n & 0xf) << 12) 137f00add96SNiklas Söderlund 1384394eb24SNiklas Söderlund /* Video n CSI2 Interface Mode Register (Gen3) */ 1394394eb24SNiklas Söderlund #define VNCSI_IFMD_DES1 (1 << 26) 1404394eb24SNiklas Söderlund #define VNCSI_IFMD_DES0 (1 << 25) 1414394eb24SNiklas Söderlund #define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0) 1424394eb24SNiklas Söderlund 1439e921447SNiklas Söderlund struct rvin_buffer { 1449e921447SNiklas Söderlund struct vb2_v4l2_buffer vb; 1459e921447SNiklas Söderlund struct list_head list; 1469e921447SNiklas Söderlund }; 1479e921447SNiklas Söderlund 1489e921447SNiklas Söderlund #define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \ 1499e921447SNiklas Söderlund struct rvin_buffer, \ 1509e921447SNiklas Söderlund vb)->list) 1519e921447SNiklas Söderlund 152f00add96SNiklas Söderlund static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset) 153f00add96SNiklas Söderlund { 154f00add96SNiklas Söderlund iowrite32(value, vin->base + offset); 155f00add96SNiklas Söderlund } 156f00add96SNiklas Söderlund 157f00add96SNiklas Söderlund static u32 rvin_read(struct rvin_dev *vin, u32 offset) 158f00add96SNiklas Söderlund { 159f00add96SNiklas Söderlund return ioread32(vin->base + offset); 160f00add96SNiklas Söderlund } 161f00add96SNiklas Söderlund 162f00add96SNiklas Söderlund /* ----------------------------------------------------------------------------- 163*3ad69c61SNiklas Söderlund * Crop and Scaling 164f00add96SNiklas Söderlund */ 165f00add96SNiklas Söderlund 166*3ad69c61SNiklas Söderlund static bool rvin_scaler_needed(const struct rvin_dev *vin) 167*3ad69c61SNiklas Söderlund { 168*3ad69c61SNiklas Söderlund return !(vin->crop.width == vin->format.width && 169*3ad69c61SNiklas Söderlund vin->compose.width == vin->format.width && 170*3ad69c61SNiklas Söderlund vin->crop.height == vin->format.height && 171*3ad69c61SNiklas Söderlund vin->compose.height == vin->format.height); 172*3ad69c61SNiklas Söderlund } 173*3ad69c61SNiklas Söderlund 174f00add96SNiklas Söderlund struct vin_coeff { 175f00add96SNiklas Söderlund unsigned short xs_value; 176f00add96SNiklas Söderlund u32 coeff_set[24]; 177f00add96SNiklas Söderlund }; 178f00add96SNiklas Söderlund 179f00add96SNiklas Söderlund static const struct vin_coeff vin_coeff_set[] = { 180f00add96SNiklas Söderlund { 0x0000, { 181f00add96SNiklas Söderlund 0x00000000, 0x00000000, 0x00000000, 182f00add96SNiklas Söderlund 0x00000000, 0x00000000, 0x00000000, 183f00add96SNiklas Söderlund 0x00000000, 0x00000000, 0x00000000, 184f00add96SNiklas Söderlund 0x00000000, 0x00000000, 0x00000000, 185f00add96SNiklas Söderlund 0x00000000, 0x00000000, 0x00000000, 186f00add96SNiklas Söderlund 0x00000000, 0x00000000, 0x00000000, 187f00add96SNiklas Söderlund 0x00000000, 0x00000000, 0x00000000, 188f00add96SNiklas Söderlund 0x00000000, 0x00000000, 0x00000000 }, 189f00add96SNiklas Söderlund }, 190f00add96SNiklas Söderlund { 0x1000, { 191f00add96SNiklas Söderlund 0x000fa400, 0x000fa400, 0x09625902, 192f00add96SNiklas Söderlund 0x000003f8, 0x00000403, 0x3de0d9f0, 193f00add96SNiklas Söderlund 0x001fffed, 0x00000804, 0x3cc1f9c3, 194f00add96SNiklas Söderlund 0x001003de, 0x00000c01, 0x3cb34d7f, 195f00add96SNiklas Söderlund 0x002003d2, 0x00000c00, 0x3d24a92d, 196f00add96SNiklas Söderlund 0x00200bca, 0x00000bff, 0x3df600d2, 197f00add96SNiklas Söderlund 0x002013cc, 0x000007ff, 0x3ed70c7e, 198f00add96SNiklas Söderlund 0x00100fde, 0x00000000, 0x3f87c036 }, 199f00add96SNiklas Söderlund }, 200f00add96SNiklas Söderlund { 0x1200, { 201f00add96SNiklas Söderlund 0x002ffff1, 0x002ffff1, 0x02a0a9c8, 202f00add96SNiklas Söderlund 0x002003e7, 0x001ffffa, 0x000185bc, 203f00add96SNiklas Söderlund 0x002007dc, 0x000003ff, 0x3e52859c, 204f00add96SNiklas Söderlund 0x00200bd4, 0x00000002, 0x3d53996b, 205f00add96SNiklas Söderlund 0x00100fd0, 0x00000403, 0x3d04ad2d, 206f00add96SNiklas Söderlund 0x00000bd5, 0x00000403, 0x3d35ace7, 207f00add96SNiklas Söderlund 0x3ff003e4, 0x00000801, 0x3dc674a1, 208f00add96SNiklas Söderlund 0x3fffe800, 0x00000800, 0x3e76f461 }, 209f00add96SNiklas Söderlund }, 210f00add96SNiklas Söderlund { 0x1400, { 211f00add96SNiklas Söderlund 0x00100be3, 0x00100be3, 0x04d1359a, 212f00add96SNiklas Söderlund 0x00000fdb, 0x002003ed, 0x0211fd93, 213f00add96SNiklas Söderlund 0x00000fd6, 0x002003f4, 0x0002d97b, 214f00add96SNiklas Söderlund 0x000007d6, 0x002ffffb, 0x3e93b956, 215f00add96SNiklas Söderlund 0x3ff003da, 0x001003ff, 0x3db49926, 216f00add96SNiklas Söderlund 0x3fffefe9, 0x00100001, 0x3d655cee, 217f00add96SNiklas Söderlund 0x3fffd400, 0x00000003, 0x3d65f4b6, 218f00add96SNiklas Söderlund 0x000fb421, 0x00000402, 0x3dc6547e }, 219f00add96SNiklas Söderlund }, 220f00add96SNiklas Söderlund { 0x1600, { 221f00add96SNiklas Söderlund 0x00000bdd, 0x00000bdd, 0x06519578, 222f00add96SNiklas Söderlund 0x3ff007da, 0x00000be3, 0x03c24973, 223f00add96SNiklas Söderlund 0x3ff003d9, 0x00000be9, 0x01b30d5f, 224f00add96SNiklas Söderlund 0x3ffff7df, 0x001003f1, 0x0003c542, 225f00add96SNiklas Söderlund 0x000fdfec, 0x001003f7, 0x3ec4711d, 226f00add96SNiklas Söderlund 0x000fc400, 0x002ffffd, 0x3df504f1, 227f00add96SNiklas Söderlund 0x001fa81a, 0x002ffc00, 0x3d957cc2, 228f00add96SNiklas Söderlund 0x002f8c3c, 0x00100000, 0x3db5c891 }, 229f00add96SNiklas Söderlund }, 230f00add96SNiklas Söderlund { 0x1800, { 231f00add96SNiklas Söderlund 0x3ff003dc, 0x3ff003dc, 0x0791e558, 232f00add96SNiklas Söderlund 0x000ff7dd, 0x3ff007de, 0x05328554, 233f00add96SNiklas Söderlund 0x000fe7e3, 0x3ff00be2, 0x03232546, 234f00add96SNiklas Söderlund 0x000fd7ee, 0x000007e9, 0x0143bd30, 235f00add96SNiklas Söderlund 0x001fb800, 0x000007ee, 0x00044511, 236f00add96SNiklas Söderlund 0x002fa015, 0x000007f4, 0x3ef4bcee, 237f00add96SNiklas Söderlund 0x002f8832, 0x001003f9, 0x3e4514c7, 238f00add96SNiklas Söderlund 0x001f7853, 0x001003fd, 0x3de54c9f }, 239f00add96SNiklas Söderlund }, 240f00add96SNiklas Söderlund { 0x1a00, { 241f00add96SNiklas Söderlund 0x000fefe0, 0x000fefe0, 0x08721d3c, 242f00add96SNiklas Söderlund 0x001fdbe7, 0x000ffbde, 0x0652a139, 243f00add96SNiklas Söderlund 0x001fcbf0, 0x000003df, 0x0463292e, 244f00add96SNiklas Söderlund 0x002fb3ff, 0x3ff007e3, 0x0293a91d, 245f00add96SNiklas Söderlund 0x002f9c12, 0x3ff00be7, 0x01241905, 246f00add96SNiklas Söderlund 0x001f8c29, 0x000007ed, 0x3fe470eb, 247f00add96SNiklas Söderlund 0x000f7c46, 0x000007f2, 0x3f04b8ca, 248f00add96SNiklas Söderlund 0x3fef7865, 0x000007f6, 0x3e74e4a8 }, 249f00add96SNiklas Söderlund }, 250f00add96SNiklas Söderlund { 0x1c00, { 251f00add96SNiklas Söderlund 0x001fd3e9, 0x001fd3e9, 0x08f23d26, 252f00add96SNiklas Söderlund 0x002fbff3, 0x001fe3e4, 0x0712ad23, 253f00add96SNiklas Söderlund 0x002fa800, 0x000ff3e0, 0x05631d1b, 254f00add96SNiklas Söderlund 0x001f9810, 0x000ffbe1, 0x03b3890d, 255f00add96SNiklas Söderlund 0x000f8c23, 0x000003e3, 0x0233e8fa, 256f00add96SNiklas Söderlund 0x3fef843b, 0x000003e7, 0x00f430e4, 257f00add96SNiklas Söderlund 0x3fbf8456, 0x3ff00bea, 0x00046cc8, 258f00add96SNiklas Söderlund 0x3f8f8c72, 0x3ff00bef, 0x3f3490ac }, 259f00add96SNiklas Söderlund }, 260f00add96SNiklas Söderlund { 0x1e00, { 261f00add96SNiklas Söderlund 0x001fbbf4, 0x001fbbf4, 0x09425112, 262f00add96SNiklas Söderlund 0x001fa800, 0x002fc7ed, 0x0792b110, 263f00add96SNiklas Söderlund 0x000f980e, 0x001fdbe6, 0x0613110a, 264f00add96SNiklas Söderlund 0x3fff8c20, 0x001fe7e3, 0x04a368fd, 265f00add96SNiklas Söderlund 0x3fcf8c33, 0x000ff7e2, 0x0343b8ed, 266f00add96SNiklas Söderlund 0x3f9f8c4a, 0x000fffe3, 0x0203f8da, 267f00add96SNiklas Söderlund 0x3f5f9c61, 0x000003e6, 0x00e428c5, 268f00add96SNiklas Söderlund 0x3f1fb07b, 0x000003eb, 0x3fe440af }, 269f00add96SNiklas Söderlund }, 270f00add96SNiklas Söderlund { 0x2000, { 271f00add96SNiklas Söderlund 0x000fa400, 0x000fa400, 0x09625902, 272f00add96SNiklas Söderlund 0x3fff980c, 0x001fb7f5, 0x0812b0ff, 273f00add96SNiklas Söderlund 0x3fdf901c, 0x001fc7ed, 0x06b2fcfa, 274f00add96SNiklas Söderlund 0x3faf902d, 0x001fd3e8, 0x055348f1, 275f00add96SNiklas Söderlund 0x3f7f983f, 0x001fe3e5, 0x04038ce3, 276f00add96SNiklas Söderlund 0x3f3fa454, 0x001fefe3, 0x02e3c8d1, 277f00add96SNiklas Söderlund 0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0, 278f00add96SNiklas Söderlund 0x3ecfd880, 0x000fffe6, 0x00c404ac }, 279f00add96SNiklas Söderlund }, 280f00add96SNiklas Söderlund { 0x2200, { 281f00add96SNiklas Söderlund 0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4, 282f00add96SNiklas Söderlund 0x3fbf9818, 0x3fffa400, 0x0842a8f1, 283f00add96SNiklas Söderlund 0x3f8f9827, 0x000fb3f7, 0x0702f0ec, 284f00add96SNiklas Söderlund 0x3f5fa037, 0x000fc3ef, 0x05d330e4, 285f00add96SNiklas Söderlund 0x3f2fac49, 0x001fcfea, 0x04a364d9, 286f00add96SNiklas Söderlund 0x3effc05c, 0x001fdbe7, 0x038394ca, 287f00add96SNiklas Söderlund 0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb, 288f00add96SNiklas Söderlund 0x3ea00083, 0x001fefe6, 0x0183c0a9 }, 289f00add96SNiklas Söderlund }, 290f00add96SNiklas Söderlund { 0x2400, { 291f00add96SNiklas Söderlund 0x3f9fa014, 0x3f9fa014, 0x098260e6, 292f00add96SNiklas Söderlund 0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5, 293f00add96SNiklas Söderlund 0x3f4fa431, 0x3fefa400, 0x0742d8e1, 294f00add96SNiklas Söderlund 0x3f1fb440, 0x3fffb3f8, 0x062310d9, 295f00add96SNiklas Söderlund 0x3eefc850, 0x000fbbf2, 0x050340d0, 296f00add96SNiklas Söderlund 0x3ecfe062, 0x000fcbec, 0x041364c2, 297f00add96SNiklas Söderlund 0x3ea00073, 0x001fd3ea, 0x03037cb5, 298f00add96SNiklas Söderlund 0x3e902086, 0x001fdfe8, 0x022388a5 }, 299f00add96SNiklas Söderlund }, 300f00add96SNiklas Söderlund { 0x2600, { 301f00add96SNiklas Söderlund 0x3f5fa81e, 0x3f5fa81e, 0x096258da, 302f00add96SNiklas Söderlund 0x3f3fac2b, 0x3f8fa412, 0x088290d8, 303f00add96SNiklas Söderlund 0x3f0fbc38, 0x3fafa408, 0x0772c8d5, 304f00add96SNiklas Söderlund 0x3eefcc47, 0x3fcfa800, 0x0672f4ce, 305f00add96SNiklas Söderlund 0x3ecfe456, 0x3fefaffa, 0x05531cc6, 306f00add96SNiklas Söderlund 0x3eb00066, 0x3fffbbf3, 0x047334bb, 307f00add96SNiklas Söderlund 0x3ea01c77, 0x000fc7ee, 0x039348ae, 308f00add96SNiklas Söderlund 0x3ea04486, 0x000fd3eb, 0x02b350a1 }, 309f00add96SNiklas Söderlund }, 310f00add96SNiklas Söderlund { 0x2800, { 311f00add96SNiklas Söderlund 0x3f2fb426, 0x3f2fb426, 0x094250ce, 312f00add96SNiklas Söderlund 0x3f0fc032, 0x3f4fac1b, 0x086284cd, 313f00add96SNiklas Söderlund 0x3eefd040, 0x3f7fa811, 0x0782acc9, 314f00add96SNiklas Söderlund 0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4, 315f00add96SNiklas Söderlund 0x3eb0005b, 0x3fbfac00, 0x05b2f4bc, 316f00add96SNiklas Söderlund 0x3eb0186a, 0x3fdfb3fa, 0x04c308b4, 317f00add96SNiklas Söderlund 0x3eb04077, 0x3fefbbf4, 0x03f31ca8, 318f00add96SNiklas Söderlund 0x3ec06884, 0x000fbff2, 0x03031c9e }, 319f00add96SNiklas Söderlund }, 320f00add96SNiklas Söderlund { 0x2a00, { 321f00add96SNiklas Söderlund 0x3f0fc42d, 0x3f0fc42d, 0x090240c4, 322f00add96SNiklas Söderlund 0x3eefd439, 0x3f2fb822, 0x08526cc2, 323f00add96SNiklas Söderlund 0x3edfe845, 0x3f4fb018, 0x078294bf, 324f00add96SNiklas Söderlund 0x3ec00051, 0x3f6fac0f, 0x06b2b4bb, 325f00add96SNiklas Söderlund 0x3ec0185f, 0x3f8fac07, 0x05e2ccb4, 326f00add96SNiklas Söderlund 0x3ec0386b, 0x3fafac00, 0x0502e8ac, 327f00add96SNiklas Söderlund 0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3, 328f00add96SNiklas Söderlund 0x3ef08482, 0x3fdfbbf6, 0x0372f898 }, 329f00add96SNiklas Söderlund }, 330f00add96SNiklas Söderlund { 0x2c00, { 331f00add96SNiklas Söderlund 0x3eefdc31, 0x3eefdc31, 0x08e238b8, 332f00add96SNiklas Söderlund 0x3edfec3d, 0x3f0fc828, 0x082258b9, 333f00add96SNiklas Söderlund 0x3ed00049, 0x3f1fc01e, 0x077278b6, 334f00add96SNiklas Söderlund 0x3ed01455, 0x3f3fb815, 0x06c294b2, 335f00add96SNiklas Söderlund 0x3ed03460, 0x3f5fb40d, 0x0602acac, 336f00add96SNiklas Söderlund 0x3ef0506c, 0x3f7fb006, 0x0542c0a4, 337f00add96SNiklas Söderlund 0x3f107476, 0x3f9fb400, 0x0472c89d, 338f00add96SNiklas Söderlund 0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 }, 339f00add96SNiklas Söderlund }, 340f00add96SNiklas Söderlund { 0x2e00, { 341f00add96SNiklas Söderlund 0x3eefec37, 0x3eefec37, 0x088220b0, 342f00add96SNiklas Söderlund 0x3ee00041, 0x3effdc2d, 0x07f244ae, 343f00add96SNiklas Söderlund 0x3ee0144c, 0x3f0fd023, 0x07625cad, 344f00add96SNiklas Söderlund 0x3ef02c57, 0x3f1fc81a, 0x06c274a9, 345f00add96SNiklas Söderlund 0x3f004861, 0x3f3fbc13, 0x060288a6, 346f00add96SNiklas Söderlund 0x3f20686b, 0x3f5fb80c, 0x05529c9e, 347f00add96SNiklas Söderlund 0x3f408c74, 0x3f6fb805, 0x04b2ac96, 348f00add96SNiklas Söderlund 0x3f80ac7e, 0x3f8fb800, 0x0402ac8e }, 349f00add96SNiklas Söderlund }, 350f00add96SNiklas Söderlund { 0x3000, { 351f00add96SNiklas Söderlund 0x3ef0003a, 0x3ef0003a, 0x084210a6, 352f00add96SNiklas Söderlund 0x3ef01045, 0x3effec32, 0x07b228a7, 353f00add96SNiklas Söderlund 0x3f00284e, 0x3f0fdc29, 0x073244a4, 354f00add96SNiklas Söderlund 0x3f104058, 0x3f0fd420, 0x06a258a2, 355f00add96SNiklas Söderlund 0x3f305c62, 0x3f2fc818, 0x0612689d, 356f00add96SNiklas Söderlund 0x3f508069, 0x3f3fc011, 0x05728496, 357f00add96SNiklas Söderlund 0x3f80a072, 0x3f4fc00a, 0x04d28c90, 358f00add96SNiklas Söderlund 0x3fc0c07b, 0x3f6fbc04, 0x04429088 }, 359f00add96SNiklas Söderlund }, 360f00add96SNiklas Söderlund { 0x3200, { 361f00add96SNiklas Söderlund 0x3f00103e, 0x3f00103e, 0x07f1fc9e, 362f00add96SNiklas Söderlund 0x3f102447, 0x3f000035, 0x0782149d, 363f00add96SNiklas Söderlund 0x3f203c4f, 0x3f0ff02c, 0x07122c9c, 364f00add96SNiklas Söderlund 0x3f405458, 0x3f0fe424, 0x06924099, 365f00add96SNiklas Söderlund 0x3f607061, 0x3f1fd41d, 0x06024c97, 366f00add96SNiklas Söderlund 0x3f909068, 0x3f2fcc16, 0x05726490, 367f00add96SNiklas Söderlund 0x3fc0b070, 0x3f3fc80f, 0x04f26c8a, 368f00add96SNiklas Söderlund 0x0000d077, 0x3f4fc409, 0x04627484 }, 369f00add96SNiklas Söderlund }, 370f00add96SNiklas Söderlund { 0x3400, { 371f00add96SNiklas Söderlund 0x3f202040, 0x3f202040, 0x07a1e898, 372f00add96SNiklas Söderlund 0x3f303449, 0x3f100c38, 0x0741fc98, 373f00add96SNiklas Söderlund 0x3f504c50, 0x3f10002f, 0x06e21495, 374f00add96SNiklas Söderlund 0x3f706459, 0x3f1ff028, 0x06722492, 375f00add96SNiklas Söderlund 0x3fa08060, 0x3f1fe421, 0x05f2348f, 376f00add96SNiklas Söderlund 0x3fd09c67, 0x3f1fdc19, 0x05824c89, 377f00add96SNiklas Söderlund 0x0000bc6e, 0x3f2fd014, 0x04f25086, 378f00add96SNiklas Söderlund 0x0040dc74, 0x3f3fcc0d, 0x04825c7f }, 379f00add96SNiklas Söderlund }, 380f00add96SNiklas Söderlund { 0x3600, { 381f00add96SNiklas Söderlund 0x3f403042, 0x3f403042, 0x0761d890, 382f00add96SNiklas Söderlund 0x3f504848, 0x3f301c3b, 0x0701f090, 383f00add96SNiklas Söderlund 0x3f805c50, 0x3f200c33, 0x06a2008f, 384f00add96SNiklas Söderlund 0x3fa07458, 0x3f10002b, 0x06520c8d, 385f00add96SNiklas Söderlund 0x3fd0905e, 0x3f1ff424, 0x05e22089, 386f00add96SNiklas Söderlund 0x0000ac65, 0x3f1fe81d, 0x05823483, 387f00add96SNiklas Söderlund 0x0030cc6a, 0x3f2fdc18, 0x04f23c81, 388f00add96SNiklas Söderlund 0x0080e871, 0x3f2fd412, 0x0482407c }, 389f00add96SNiklas Söderlund }, 390f00add96SNiklas Söderlund { 0x3800, { 391f00add96SNiklas Söderlund 0x3f604043, 0x3f604043, 0x0721c88a, 392f00add96SNiklas Söderlund 0x3f80544a, 0x3f502c3c, 0x06d1d88a, 393f00add96SNiklas Söderlund 0x3fb06851, 0x3f301c35, 0x0681e889, 394f00add96SNiklas Söderlund 0x3fd08456, 0x3f30082f, 0x0611fc88, 395f00add96SNiklas Söderlund 0x00009c5d, 0x3f200027, 0x05d20884, 396f00add96SNiklas Söderlund 0x0030b863, 0x3f2ff421, 0x05621880, 397f00add96SNiklas Söderlund 0x0070d468, 0x3f2fe81b, 0x0502247c, 398f00add96SNiklas Söderlund 0x00c0ec6f, 0x3f2fe015, 0x04a22877 }, 399f00add96SNiklas Söderlund }, 400f00add96SNiklas Söderlund { 0x3a00, { 401f00add96SNiklas Söderlund 0x3f904c44, 0x3f904c44, 0x06e1b884, 402f00add96SNiklas Söderlund 0x3fb0604a, 0x3f70383e, 0x0691c885, 403f00add96SNiklas Söderlund 0x3fe07451, 0x3f502c36, 0x0661d483, 404f00add96SNiklas Söderlund 0x00009055, 0x3f401831, 0x0601ec81, 405f00add96SNiklas Söderlund 0x0030a85b, 0x3f300c2a, 0x05b1f480, 406f00add96SNiklas Söderlund 0x0070c061, 0x3f300024, 0x0562047a, 407f00add96SNiklas Söderlund 0x00b0d867, 0x3f3ff41e, 0x05020c77, 408f00add96SNiklas Söderlund 0x00f0f46b, 0x3f2fec19, 0x04a21474 }, 409f00add96SNiklas Söderlund }, 410f00add96SNiklas Söderlund { 0x3c00, { 411f00add96SNiklas Söderlund 0x3fb05c43, 0x3fb05c43, 0x06c1b07e, 412f00add96SNiklas Söderlund 0x3fe06c4b, 0x3f902c3f, 0x0681c081, 413f00add96SNiklas Söderlund 0x0000844f, 0x3f703838, 0x0631cc7d, 414f00add96SNiklas Söderlund 0x00309855, 0x3f602433, 0x05d1d47e, 415f00add96SNiklas Söderlund 0x0060b459, 0x3f50142e, 0x0581e47b, 416f00add96SNiklas Söderlund 0x00a0c85f, 0x3f400828, 0x0531f078, 417f00add96SNiklas Söderlund 0x00e0e064, 0x3f300021, 0x0501fc73, 418f00add96SNiklas Söderlund 0x00b0fc6a, 0x3f3ff41d, 0x04a20873 }, 419f00add96SNiklas Söderlund }, 420f00add96SNiklas Söderlund { 0x3e00, { 421f00add96SNiklas Söderlund 0x3fe06444, 0x3fe06444, 0x0681a07a, 422f00add96SNiklas Söderlund 0x00007849, 0x3fc0503f, 0x0641b07a, 423f00add96SNiklas Söderlund 0x0020904d, 0x3fa0403a, 0x05f1c07a, 424f00add96SNiklas Söderlund 0x0060a453, 0x3f803034, 0x05c1c878, 425f00add96SNiklas Söderlund 0x0090b858, 0x3f70202f, 0x0571d477, 426f00add96SNiklas Söderlund 0x00d0d05d, 0x3f501829, 0x0531e073, 427f00add96SNiklas Söderlund 0x0110e462, 0x3f500825, 0x04e1e471, 428f00add96SNiklas Söderlund 0x01510065, 0x3f40001f, 0x04a1f06d }, 429f00add96SNiklas Söderlund }, 430f00add96SNiklas Söderlund { 0x4000, { 431f00add96SNiklas Söderlund 0x00007044, 0x00007044, 0x06519476, 432f00add96SNiklas Söderlund 0x00208448, 0x3fe05c3f, 0x0621a476, 433f00add96SNiklas Söderlund 0x0050984d, 0x3fc04c3a, 0x05e1b075, 434f00add96SNiklas Söderlund 0x0080ac52, 0x3fa03c35, 0x05a1b875, 435f00add96SNiklas Söderlund 0x00c0c056, 0x3f803030, 0x0561c473, 436f00add96SNiklas Söderlund 0x0100d45b, 0x3f70202b, 0x0521d46f, 437f00add96SNiklas Söderlund 0x0140e860, 0x3f601427, 0x04d1d46e, 438f00add96SNiklas Söderlund 0x01810064, 0x3f500822, 0x0491dc6b }, 439f00add96SNiklas Söderlund }, 440f00add96SNiklas Söderlund { 0x5000, { 441f00add96SNiklas Söderlund 0x0110a442, 0x0110a442, 0x0551545e, 442f00add96SNiklas Söderlund 0x0140b045, 0x00e0983f, 0x0531585f, 443f00add96SNiklas Söderlund 0x0160c047, 0x00c08c3c, 0x0511645e, 444f00add96SNiklas Söderlund 0x0190cc4a, 0x00908039, 0x04f1685f, 445f00add96SNiklas Söderlund 0x01c0dc4c, 0x00707436, 0x04d1705e, 446f00add96SNiklas Söderlund 0x0200e850, 0x00506833, 0x04b1785b, 447f00add96SNiklas Söderlund 0x0230f453, 0x00305c30, 0x0491805a, 448f00add96SNiklas Söderlund 0x02710056, 0x0010542d, 0x04718059 }, 449f00add96SNiklas Söderlund }, 450f00add96SNiklas Söderlund { 0x6000, { 451f00add96SNiklas Söderlund 0x01c0bc40, 0x01c0bc40, 0x04c13052, 452f00add96SNiklas Söderlund 0x01e0c841, 0x01a0b43d, 0x04c13851, 453f00add96SNiklas Söderlund 0x0210cc44, 0x0180a83c, 0x04a13453, 454f00add96SNiklas Söderlund 0x0230d845, 0x0160a03a, 0x04913c52, 455f00add96SNiklas Söderlund 0x0260e047, 0x01409838, 0x04714052, 456f00add96SNiklas Söderlund 0x0280ec49, 0x01208c37, 0x04514c50, 457f00add96SNiklas Söderlund 0x02b0f44b, 0x01008435, 0x04414c50, 458f00add96SNiklas Söderlund 0x02d1004c, 0x00e07c33, 0x0431544f }, 459f00add96SNiklas Söderlund }, 460f00add96SNiklas Söderlund { 0x7000, { 461f00add96SNiklas Söderlund 0x0230c83e, 0x0230c83e, 0x04711c4c, 462f00add96SNiklas Söderlund 0x0250d03f, 0x0210c43c, 0x0471204b, 463f00add96SNiklas Söderlund 0x0270d840, 0x0200b83c, 0x0451244b, 464f00add96SNiklas Söderlund 0x0290dc42, 0x01e0b43a, 0x0441244c, 465f00add96SNiklas Söderlund 0x02b0e443, 0x01c0b038, 0x0441284b, 466f00add96SNiklas Söderlund 0x02d0ec44, 0x01b0a438, 0x0421304a, 467f00add96SNiklas Söderlund 0x02f0f445, 0x0190a036, 0x04213449, 468f00add96SNiklas Söderlund 0x0310f847, 0x01709c34, 0x04213848 }, 469f00add96SNiklas Söderlund }, 470f00add96SNiklas Söderlund { 0x8000, { 471f00add96SNiklas Söderlund 0x0280d03d, 0x0280d03d, 0x04310c48, 472f00add96SNiklas Söderlund 0x02a0d43e, 0x0270c83c, 0x04311047, 473f00add96SNiklas Söderlund 0x02b0dc3e, 0x0250c83a, 0x04311447, 474f00add96SNiklas Söderlund 0x02d0e040, 0x0240c03a, 0x04211446, 475f00add96SNiklas Söderlund 0x02e0e840, 0x0220bc39, 0x04111847, 476f00add96SNiklas Söderlund 0x0300e842, 0x0210b438, 0x04012445, 477f00add96SNiklas Söderlund 0x0310f043, 0x0200b037, 0x04012045, 478f00add96SNiklas Söderlund 0x0330f444, 0x01e0ac36, 0x03f12445 }, 479f00add96SNiklas Söderlund }, 480f00add96SNiklas Söderlund { 0xefff, { 481f00add96SNiklas Söderlund 0x0340dc3a, 0x0340dc3a, 0x03b0ec40, 482f00add96SNiklas Söderlund 0x0340e03a, 0x0330e039, 0x03c0f03e, 483f00add96SNiklas Söderlund 0x0350e03b, 0x0330dc39, 0x03c0ec3e, 484f00add96SNiklas Söderlund 0x0350e43a, 0x0320dc38, 0x03c0f43e, 485f00add96SNiklas Söderlund 0x0360e43b, 0x0320d839, 0x03b0f03e, 486f00add96SNiklas Söderlund 0x0360e83b, 0x0310d838, 0x03c0fc3b, 487f00add96SNiklas Söderlund 0x0370e83b, 0x0310d439, 0x03a0f83d, 488f00add96SNiklas Söderlund 0x0370e83c, 0x0300d438, 0x03b0fc3c }, 489f00add96SNiklas Söderlund } 490f00add96SNiklas Söderlund }; 491f00add96SNiklas Söderlund 492f00add96SNiklas Söderlund static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs) 493f00add96SNiklas Söderlund { 494f00add96SNiklas Söderlund int i; 495f00add96SNiklas Söderlund const struct vin_coeff *p_prev_set = NULL; 496f00add96SNiklas Söderlund const struct vin_coeff *p_set = NULL; 497f00add96SNiklas Söderlund 498f00add96SNiklas Söderlund /* Look for suitable coefficient values */ 499f00add96SNiklas Söderlund for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) { 500f00add96SNiklas Söderlund p_prev_set = p_set; 501f00add96SNiklas Söderlund p_set = &vin_coeff_set[i]; 502f00add96SNiklas Söderlund 503f00add96SNiklas Söderlund if (xs < p_set->xs_value) 504f00add96SNiklas Söderlund break; 505f00add96SNiklas Söderlund } 506f00add96SNiklas Söderlund 507f00add96SNiklas Söderlund /* Use previous value if its XS value is closer */ 508bf78f23aSMauro Carvalho Chehab if (p_prev_set && 509f00add96SNiklas Söderlund xs - p_prev_set->xs_value < p_set->xs_value - xs) 510f00add96SNiklas Söderlund p_set = p_prev_set; 511f00add96SNiklas Söderlund 512f00add96SNiklas Söderlund /* Set coefficient registers */ 513f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[0], VNC1A_REG); 514f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[1], VNC1B_REG); 515f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[2], VNC1C_REG); 516f00add96SNiklas Söderlund 517f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[3], VNC2A_REG); 518f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[4], VNC2B_REG); 519f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[5], VNC2C_REG); 520f00add96SNiklas Söderlund 521f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[6], VNC3A_REG); 522f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[7], VNC3B_REG); 523f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[8], VNC3C_REG); 524f00add96SNiklas Söderlund 525f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[9], VNC4A_REG); 526f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[10], VNC4B_REG); 527f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[11], VNC4C_REG); 528f00add96SNiklas Söderlund 529f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[12], VNC5A_REG); 530f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[13], VNC5B_REG); 531f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[14], VNC5C_REG); 532f00add96SNiklas Söderlund 533f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[15], VNC6A_REG); 534f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[16], VNC6B_REG); 535f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[17], VNC6C_REG); 536f00add96SNiklas Söderlund 537f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[18], VNC7A_REG); 538f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[19], VNC7B_REG); 539f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[20], VNC7C_REG); 540f00add96SNiklas Söderlund 541f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[21], VNC8A_REG); 542f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[22], VNC8B_REG); 543f00add96SNiklas Söderlund rvin_write(vin, p_set->coeff_set[23], VNC8C_REG); 544f00add96SNiklas Söderlund } 545f00add96SNiklas Söderlund 546*3ad69c61SNiklas Söderlund void rvin_scaler_gen2(struct rvin_dev *vin) 547f00add96SNiklas Söderlund { 54808369321SNiklas Söderlund unsigned int crop_height; 549f00add96SNiklas Söderlund u32 xs, ys; 550f00add96SNiklas Söderlund 551f00add96SNiklas Söderlund /* Set scaling coefficient */ 55208369321SNiklas Söderlund crop_height = vin->crop.height; 5537e0cfdadSNiklas Söderlund if (V4L2_FIELD_HAS_BOTH(vin->format.field)) 55408369321SNiklas Söderlund crop_height *= 2; 55508369321SNiklas Söderlund 556f00add96SNiklas Söderlund ys = 0; 55708369321SNiklas Söderlund if (crop_height != vin->compose.height) 55808369321SNiklas Söderlund ys = (4096 * crop_height) / vin->compose.height; 559f00add96SNiklas Söderlund rvin_write(vin, ys, VNYS_REG); 560f00add96SNiklas Söderlund 561f00add96SNiklas Söderlund xs = 0; 562f00add96SNiklas Söderlund if (vin->crop.width != vin->compose.width) 563f00add96SNiklas Söderlund xs = (4096 * vin->crop.width) / vin->compose.width; 564f00add96SNiklas Söderlund 565f00add96SNiklas Söderlund /* Horizontal upscaling is up to double size */ 566f00add96SNiklas Söderlund if (xs > 0 && xs < 2048) 567f00add96SNiklas Söderlund xs = 2048; 568f00add96SNiklas Söderlund 569f00add96SNiklas Söderlund rvin_write(vin, xs, VNXS_REG); 570f00add96SNiklas Söderlund 571f00add96SNiklas Söderlund /* Horizontal upscaling is done out by scaling down from double size */ 572f00add96SNiklas Söderlund if (xs < 4096) 573f00add96SNiklas Söderlund xs *= 2; 574f00add96SNiklas Söderlund 575f00add96SNiklas Söderlund rvin_set_coeff(vin, xs); 576f00add96SNiklas Söderlund 577f00add96SNiklas Söderlund /* Set Start/End Pixel/Line Post-Clip */ 578f00add96SNiklas Söderlund rvin_write(vin, 0, VNSPPOC_REG); 579f00add96SNiklas Söderlund rvin_write(vin, 0, VNSLPOC_REG); 580f00add96SNiklas Söderlund rvin_write(vin, vin->format.width - 1, VNEPPOC_REG); 581d23e12dcSNiklas Söderlund 5827e0cfdadSNiklas Söderlund if (V4L2_FIELD_HAS_BOTH(vin->format.field)) 583f00add96SNiklas Söderlund rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG); 584d23e12dcSNiklas Söderlund else 585f00add96SNiklas Söderlund rvin_write(vin, vin->format.height - 1, VNELPOC_REG); 586f00add96SNiklas Söderlund 587f00add96SNiklas Söderlund vin_dbg(vin, 588f00add96SNiklas Söderlund "Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n", 589f00add96SNiklas Söderlund vin->crop.width, vin->crop.height, vin->crop.left, 590f00add96SNiklas Söderlund vin->crop.top, ys, xs, vin->format.width, vin->format.height, 591f00add96SNiklas Söderlund 0, 0); 592f00add96SNiklas Söderlund } 593f00add96SNiklas Söderlund 5944394eb24SNiklas Söderlund void rvin_crop_scale_comp(struct rvin_dev *vin) 5954394eb24SNiklas Söderlund { 59684246ae3SNiklas Söderlund const struct rvin_video_format *fmt; 59784246ae3SNiklas Söderlund u32 stride; 59884246ae3SNiklas Söderlund 5994394eb24SNiklas Söderlund /* Set Start/End Pixel/Line Pre-Clip */ 6004394eb24SNiklas Söderlund rvin_write(vin, vin->crop.left, VNSPPRC_REG); 6014394eb24SNiklas Söderlund rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG); 6024394eb24SNiklas Söderlund rvin_write(vin, vin->crop.top, VNSLPRC_REG); 60308369321SNiklas Söderlund rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG); 60408369321SNiklas Söderlund 605*3ad69c61SNiklas Söderlund if (vin->scaler) 606*3ad69c61SNiklas Söderlund vin->scaler(vin); 6074394eb24SNiklas Söderlund 60884246ae3SNiklas Söderlund fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); 60984246ae3SNiklas Söderlund stride = vin->format.bytesperline / fmt->bpp; 610e87c1a81SLad Prabhakar 611e87c1a81SLad Prabhakar /* For RAW8 format bpp is 1, but the hardware process RAW8 612e87c1a81SLad Prabhakar * format in 2 pixel unit hence configure VNIS_REG as stride / 2. 613e87c1a81SLad Prabhakar */ 6148c3e0f67SNiklas Söderlund switch (vin->format.pixelformat) { 615811b8d66SLad Prabhakar case V4L2_PIX_FMT_SBGGR8: 616811b8d66SLad Prabhakar case V4L2_PIX_FMT_SGBRG8: 617811b8d66SLad Prabhakar case V4L2_PIX_FMT_SGRBG8: 618811b8d66SLad Prabhakar case V4L2_PIX_FMT_SRGGB8: 619c93beb52SVladimir Barinov case V4L2_PIX_FMT_GREY: 620e87c1a81SLad Prabhakar stride /= 2; 6218c3e0f67SNiklas Söderlund break; 6228c3e0f67SNiklas Söderlund default: 6238c3e0f67SNiklas Söderlund break; 6248c3e0f67SNiklas Söderlund } 625e87c1a81SLad Prabhakar 62684246ae3SNiklas Söderlund rvin_write(vin, stride, VNIS_REG); 6274394eb24SNiklas Söderlund } 6284394eb24SNiklas Söderlund 629f00add96SNiklas Söderlund /* ----------------------------------------------------------------------------- 6300f4b3378SNiklas Söderlund * Hardware setup 6310f4b3378SNiklas Söderlund */ 6320f4b3378SNiklas Söderlund 6330f4b3378SNiklas Söderlund static int rvin_setup(struct rvin_dev *vin) 6340f4b3378SNiklas Söderlund { 635d73c3357SNiklas Söderlund u32 vnmc, dmr, dmr2, interrupts; 6360f4b3378SNiklas Söderlund bool progressive = false, output_is_yuv = false, input_is_yuv = false; 6370f4b3378SNiklas Söderlund 6380f4b3378SNiklas Söderlund switch (vin->format.field) { 6390f4b3378SNiklas Söderlund case V4L2_FIELD_TOP: 6400f4b3378SNiklas Söderlund vnmc = VNMC_IM_ODD; 6410f4b3378SNiklas Söderlund break; 6420f4b3378SNiklas Söderlund case V4L2_FIELD_BOTTOM: 6430f4b3378SNiklas Söderlund vnmc = VNMC_IM_EVEN; 6440f4b3378SNiklas Söderlund break; 6450f4b3378SNiklas Söderlund case V4L2_FIELD_INTERLACED: 6460f4b3378SNiklas Söderlund /* Default to TB */ 6470f4b3378SNiklas Söderlund vnmc = VNMC_IM_FULL; 6480f4b3378SNiklas Söderlund /* Use BT if video standard can be read and is 60 Hz format */ 6495e7c6236SNiklas Söderlund if (!vin->info->use_mc && vin->std & V4L2_STD_525_60) 6500f4b3378SNiklas Söderlund vnmc = VNMC_IM_FULL | VNMC_FOC; 6510f4b3378SNiklas Söderlund break; 6520f4b3378SNiklas Söderlund case V4L2_FIELD_INTERLACED_TB: 6530f4b3378SNiklas Söderlund vnmc = VNMC_IM_FULL; 6540f4b3378SNiklas Söderlund break; 6550f4b3378SNiklas Söderlund case V4L2_FIELD_INTERLACED_BT: 6560f4b3378SNiklas Söderlund vnmc = VNMC_IM_FULL | VNMC_FOC; 6570f4b3378SNiklas Söderlund break; 6587e0cfdadSNiklas Söderlund case V4L2_FIELD_SEQ_TB: 6597e0cfdadSNiklas Söderlund case V4L2_FIELD_SEQ_BT: 6600f4b3378SNiklas Söderlund case V4L2_FIELD_NONE: 6610f4b3378SNiklas Söderlund vnmc = VNMC_IM_ODD_EVEN; 6620f4b3378SNiklas Söderlund progressive = true; 6630f4b3378SNiklas Söderlund break; 66408369321SNiklas Söderlund case V4L2_FIELD_ALTERNATE: 66508369321SNiklas Söderlund vnmc = VNMC_IM_ODD_EVEN; 66608369321SNiklas Söderlund break; 6670f4b3378SNiklas Söderlund default: 6680f4b3378SNiklas Söderlund vnmc = VNMC_IM_ODD; 6690f4b3378SNiklas Söderlund break; 6700f4b3378SNiklas Söderlund } 6710f4b3378SNiklas Söderlund 6720f4b3378SNiklas Söderlund /* 6730f4b3378SNiklas Söderlund * Input interface 6740f4b3378SNiklas Söderlund */ 675c65c99b4SNiklas Söderlund switch (vin->mbus_code) { 6760f4b3378SNiklas Söderlund case MEDIA_BUS_FMT_YUYV8_1X16: 6770f4b3378SNiklas Söderlund /* BT.601/BT.1358 16bit YCbCr422 */ 6780f4b3378SNiklas Söderlund vnmc |= VNMC_INF_YUV16; 6790f4b3378SNiklas Söderlund input_is_yuv = true; 6800f4b3378SNiklas Söderlund break; 68101d72e9dSNiklas Söderlund case MEDIA_BUS_FMT_UYVY8_1X16: 68201d72e9dSNiklas Söderlund vnmc |= VNMC_INF_YUV16 | VNMC_YCAL; 68301d72e9dSNiklas Söderlund input_is_yuv = true; 68401d72e9dSNiklas Söderlund break; 6850f4b3378SNiklas Söderlund case MEDIA_BUS_FMT_UYVY8_2X8: 6860f4b3378SNiklas Söderlund /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ 687158e2a53SJacopo Mondi if (!vin->is_csi && 688d7592b2eSNiklas Söderlund vin->parallel.mbus_type == V4L2_MBUS_BT656) 689158e2a53SJacopo Mondi vnmc |= VNMC_INF_YUV8_BT656; 690158e2a53SJacopo Mondi else 691158e2a53SJacopo Mondi vnmc |= VNMC_INF_YUV8_BT601; 692158e2a53SJacopo Mondi 6930f4b3378SNiklas Söderlund input_is_yuv = true; 6940f4b3378SNiklas Söderlund break; 6950f4b3378SNiklas Söderlund case MEDIA_BUS_FMT_RGB888_1X24: 6960f4b3378SNiklas Söderlund vnmc |= VNMC_INF_RGB888; 6970f4b3378SNiklas Söderlund break; 6980f4b3378SNiklas Söderlund case MEDIA_BUS_FMT_UYVY10_2X10: 6990f4b3378SNiklas Söderlund /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ 700158e2a53SJacopo Mondi if (!vin->is_csi && 701d7592b2eSNiklas Söderlund vin->parallel.mbus_type == V4L2_MBUS_BT656) 702158e2a53SJacopo Mondi vnmc |= VNMC_INF_YUV10_BT656; 703158e2a53SJacopo Mondi else 704158e2a53SJacopo Mondi vnmc |= VNMC_INF_YUV10_BT601; 705158e2a53SJacopo Mondi 7060f4b3378SNiklas Söderlund input_is_yuv = true; 7070f4b3378SNiklas Söderlund break; 7088c3e0f67SNiklas Söderlund case MEDIA_BUS_FMT_SBGGR8_1X8: 7098c3e0f67SNiklas Söderlund case MEDIA_BUS_FMT_SGBRG8_1X8: 7108c3e0f67SNiklas Söderlund case MEDIA_BUS_FMT_SGRBG8_1X8: 711e87c1a81SLad Prabhakar case MEDIA_BUS_FMT_SRGGB8_1X8: 712c93beb52SVladimir Barinov case MEDIA_BUS_FMT_Y8_1X8: 713e87c1a81SLad Prabhakar vnmc |= VNMC_INF_RAW8; 714e87c1a81SLad Prabhakar break; 7150f4b3378SNiklas Söderlund default: 7160f4b3378SNiklas Söderlund break; 7170f4b3378SNiklas Söderlund } 7180f4b3378SNiklas Söderlund 71978b3f9d7SNiklas Söderlund /* Make sure input interface and input format is valid. */ 72078b3f9d7SNiklas Söderlund if (vin->info->model == RCAR_GEN3) { 72178b3f9d7SNiklas Söderlund switch (vnmc & VNMC_INF_MASK) { 72278b3f9d7SNiklas Söderlund case VNMC_INF_YUV8_BT656: 72378b3f9d7SNiklas Söderlund case VNMC_INF_YUV10_BT656: 72478b3f9d7SNiklas Söderlund case VNMC_INF_YUV16: 72578b3f9d7SNiklas Söderlund case VNMC_INF_RGB666: 72678b3f9d7SNiklas Söderlund if (vin->is_csi) { 72778b3f9d7SNiklas Söderlund vin_err(vin, "Invalid setting in MIPI CSI2\n"); 72878b3f9d7SNiklas Söderlund return -EINVAL; 72978b3f9d7SNiklas Söderlund } 73078b3f9d7SNiklas Söderlund break; 73178b3f9d7SNiklas Söderlund case VNMC_INF_RAW8: 73278b3f9d7SNiklas Söderlund if (!vin->is_csi) { 73378b3f9d7SNiklas Söderlund vin_err(vin, "Invalid setting in Digital Pins\n"); 73478b3f9d7SNiklas Söderlund return -EINVAL; 73578b3f9d7SNiklas Söderlund } 73678b3f9d7SNiklas Söderlund break; 73778b3f9d7SNiklas Söderlund default: 73878b3f9d7SNiklas Söderlund break; 73978b3f9d7SNiklas Söderlund } 74078b3f9d7SNiklas Söderlund } 74178b3f9d7SNiklas Söderlund 7428b72c18dSMauro Carvalho Chehab /* Enable VSYNC Field Toggle mode after one VSYNC input */ 743d73c3357SNiklas Söderlund if (vin->info->model == RCAR_GEN3) 744d73c3357SNiklas Söderlund dmr2 = VNDMR2_FTEV; 745d73c3357SNiklas Söderlund else 7460f4b3378SNiklas Söderlund dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1); 7470f4b3378SNiklas Söderlund 748158e2a53SJacopo Mondi if (!vin->is_csi) { 7490f4b3378SNiklas Söderlund /* Hsync Signal Polarity Select */ 750d7592b2eSNiklas Söderlund if (!(vin->parallel.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) 7510f4b3378SNiklas Söderlund dmr2 |= VNDMR2_HPS; 7520f4b3378SNiklas Söderlund 7530f4b3378SNiklas Söderlund /* Vsync Signal Polarity Select */ 754d7592b2eSNiklas Söderlund if (!(vin->parallel.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) 7550f4b3378SNiklas Söderlund dmr2 |= VNDMR2_VPS; 75653cf3100SJacopo Mondi 75753cf3100SJacopo Mondi /* Data Enable Polarity Select */ 758d7592b2eSNiklas Söderlund if (vin->parallel.bus.flags & V4L2_MBUS_DATA_ENABLE_LOW) 75953cf3100SJacopo Mondi dmr2 |= VNDMR2_CES; 760e8834943SLad Prabhakar 761e8834943SLad Prabhakar switch (vin->mbus_code) { 762e8834943SLad Prabhakar case MEDIA_BUS_FMT_UYVY8_2X8: 763d7592b2eSNiklas Söderlund if (vin->parallel.bus.bus_width == 8 && 764d7592b2eSNiklas Söderlund vin->parallel.bus.data_shift == 8) 765e8834943SLad Prabhakar dmr2 |= VNDMR2_YDS; 766e8834943SLad Prabhakar break; 767e8834943SLad Prabhakar default: 768e8834943SLad Prabhakar break; 769e8834943SLad Prabhakar } 770158e2a53SJacopo Mondi } 7710f4b3378SNiklas Söderlund 7720f4b3378SNiklas Söderlund /* 7730f4b3378SNiklas Söderlund * Output format 7740f4b3378SNiklas Söderlund */ 7750f4b3378SNiklas Söderlund switch (vin->format.pixelformat) { 7769b744a3eSNiklas Söderlund case V4L2_PIX_FMT_NV12: 7770f4b3378SNiklas Söderlund case V4L2_PIX_FMT_NV16: 7780f4b3378SNiklas Söderlund rvin_write(vin, 7795c9de1faSNiklas Söderlund ALIGN(vin->format.bytesperline * vin->format.height, 7805c9de1faSNiklas Söderlund 0x80), VNUVAOF_REG); 7819b744a3eSNiklas Söderlund dmr = vin->format.pixelformat == V4L2_PIX_FMT_NV12 ? 7829b744a3eSNiklas Söderlund VNDMR_DTMD_YCSEP_420 : VNDMR_DTMD_YCSEP; 7830f4b3378SNiklas Söderlund output_is_yuv = true; 7840f4b3378SNiklas Söderlund break; 7850f4b3378SNiklas Söderlund case V4L2_PIX_FMT_YUYV: 7860f4b3378SNiklas Söderlund dmr = VNDMR_BPSM; 7870f4b3378SNiklas Söderlund output_is_yuv = true; 7880f4b3378SNiklas Söderlund break; 7890f4b3378SNiklas Söderlund case V4L2_PIX_FMT_UYVY: 7900f4b3378SNiklas Söderlund dmr = 0; 7910f4b3378SNiklas Söderlund output_is_yuv = true; 7920f4b3378SNiklas Söderlund break; 7930f4b3378SNiklas Söderlund case V4L2_PIX_FMT_XRGB555: 79419ab1f64SNiklas Söderlund dmr = VNDMR_DTMD_ARGB; 7950f4b3378SNiklas Söderlund break; 7960f4b3378SNiklas Söderlund case V4L2_PIX_FMT_RGB565: 7970f4b3378SNiklas Söderlund dmr = 0; 7980f4b3378SNiklas Söderlund break; 7990f4b3378SNiklas Söderlund case V4L2_PIX_FMT_XBGR32: 8000f4b3378SNiklas Söderlund /* Note: not supported on M1 */ 8010f4b3378SNiklas Söderlund dmr = VNDMR_EXRGB; 8020f4b3378SNiklas Söderlund break; 8031d99e68cSNiklas Söderlund case V4L2_PIX_FMT_ARGB555: 8041d99e68cSNiklas Söderlund dmr = (vin->alpha ? VNDMR_ABIT : 0) | VNDMR_DTMD_ARGB; 8051d99e68cSNiklas Söderlund break; 8061d99e68cSNiklas Söderlund case V4L2_PIX_FMT_ABGR32: 8071d99e68cSNiklas Söderlund dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB; 8081d99e68cSNiklas Söderlund break; 8098c3e0f67SNiklas Söderlund case V4L2_PIX_FMT_SBGGR8: 8108c3e0f67SNiklas Söderlund case V4L2_PIX_FMT_SGBRG8: 8118c3e0f67SNiklas Söderlund case V4L2_PIX_FMT_SGRBG8: 812e87c1a81SLad Prabhakar case V4L2_PIX_FMT_SRGGB8: 813e87c1a81SLad Prabhakar dmr = 0; 814e87c1a81SLad Prabhakar break; 815c93beb52SVladimir Barinov case V4L2_PIX_FMT_GREY: 816c93beb52SVladimir Barinov if (input_is_yuv) { 817c93beb52SVladimir Barinov dmr = VNDMR_DTMD_YCSEP | VNDMR_YMODE_Y8; 818c93beb52SVladimir Barinov output_is_yuv = true; 819c93beb52SVladimir Barinov } else { 820c93beb52SVladimir Barinov dmr = 0; 821c93beb52SVladimir Barinov } 822c93beb52SVladimir Barinov break; 8230f4b3378SNiklas Söderlund default: 8240f4b3378SNiklas Söderlund vin_err(vin, "Invalid pixelformat (0x%x)\n", 8250f4b3378SNiklas Söderlund vin->format.pixelformat); 8260f4b3378SNiklas Söderlund return -EINVAL; 8270f4b3378SNiklas Söderlund } 8280f4b3378SNiklas Söderlund 8290f4b3378SNiklas Söderlund /* Always update on field change */ 8300f4b3378SNiklas Söderlund vnmc |= VNMC_VUP; 8310f4b3378SNiklas Söderlund 832406bb586SNiklas Söderlund if (!vin->info->use_isp) { 8330f4b3378SNiklas Söderlund /* If input and output use the same colorspace, use bypass mode */ 8340f4b3378SNiklas Söderlund if (input_is_yuv == output_is_yuv) 8350f4b3378SNiklas Söderlund vnmc |= VNMC_BPS; 8360f4b3378SNiklas Söderlund 8374394eb24SNiklas Söderlund if (vin->info->model == RCAR_GEN3) { 838d24c029eSJacopo Mondi /* Select between CSI-2 and parallel input */ 839158e2a53SJacopo Mondi if (vin->is_csi) 8404394eb24SNiklas Söderlund vnmc &= ~VNMC_DPINE; 8414394eb24SNiklas Söderlund else 8424394eb24SNiklas Söderlund vnmc |= VNMC_DPINE; 8434394eb24SNiklas Söderlund } 844406bb586SNiklas Söderlund } 8454394eb24SNiklas Söderlund 8460f4b3378SNiklas Söderlund /* Progressive or interlaced mode */ 8470f4b3378SNiklas Söderlund interrupts = progressive ? VNIE_FIE : VNIE_EFE; 8480f4b3378SNiklas Söderlund 8490f4b3378SNiklas Söderlund /* Ack interrupts */ 8500f4b3378SNiklas Söderlund rvin_write(vin, interrupts, VNINTS_REG); 8510f4b3378SNiklas Söderlund /* Enable interrupts */ 8520f4b3378SNiklas Söderlund rvin_write(vin, interrupts, VNIE_REG); 8530f4b3378SNiklas Söderlund /* Start capturing */ 8540f4b3378SNiklas Söderlund rvin_write(vin, dmr, VNDMR_REG); 8550f4b3378SNiklas Söderlund rvin_write(vin, dmr2, VNDMR2_REG); 8560f4b3378SNiklas Söderlund 8570f4b3378SNiklas Söderlund /* Enable module */ 8580f4b3378SNiklas Söderlund rvin_write(vin, vnmc | VNMC_ME, VNMC_REG); 8590f4b3378SNiklas Söderlund 8600f4b3378SNiklas Söderlund return 0; 8610f4b3378SNiklas Söderlund } 8620f4b3378SNiklas Söderlund 8630f4b3378SNiklas Söderlund static void rvin_disable_interrupts(struct rvin_dev *vin) 8640f4b3378SNiklas Söderlund { 8650f4b3378SNiklas Söderlund rvin_write(vin, 0, VNIE_REG); 8660f4b3378SNiklas Söderlund } 8670f4b3378SNiklas Söderlund 8680f4b3378SNiklas Söderlund static u32 rvin_get_interrupt_status(struct rvin_dev *vin) 8690f4b3378SNiklas Söderlund { 8700f4b3378SNiklas Söderlund return rvin_read(vin, VNINTS_REG); 8710f4b3378SNiklas Söderlund } 8720f4b3378SNiklas Söderlund 8730f4b3378SNiklas Söderlund static void rvin_ack_interrupt(struct rvin_dev *vin) 8740f4b3378SNiklas Söderlund { 8750f4b3378SNiklas Söderlund rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG); 8760f4b3378SNiklas Söderlund } 8770f4b3378SNiklas Söderlund 8780f4b3378SNiklas Söderlund static bool rvin_capture_active(struct rvin_dev *vin) 8790f4b3378SNiklas Söderlund { 8800f4b3378SNiklas Söderlund return rvin_read(vin, VNMS_REG) & VNMS_CA; 8810f4b3378SNiklas Söderlund } 8820f4b3378SNiklas Söderlund 88308369321SNiklas Söderlund static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) 88408369321SNiklas Söderlund { 88508369321SNiklas Söderlund if (vin->format.field == V4L2_FIELD_ALTERNATE) { 88608369321SNiklas Söderlund /* If FS is set it is an Even field. */ 88708369321SNiklas Söderlund if (vnms & VNMS_FS) 88808369321SNiklas Söderlund return V4L2_FIELD_BOTTOM; 88908369321SNiklas Söderlund return V4L2_FIELD_TOP; 89008369321SNiklas Söderlund } 89108369321SNiklas Söderlund 89208369321SNiklas Söderlund return vin->format.field; 89308369321SNiklas Söderlund } 89408369321SNiklas Söderlund 8950f4b3378SNiklas Söderlund static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) 8960f4b3378SNiklas Söderlund { 8970f4b3378SNiklas Söderlund const struct rvin_video_format *fmt; 8980f4b3378SNiklas Söderlund int offsetx, offsety; 8990f4b3378SNiklas Söderlund dma_addr_t offset; 9000f4b3378SNiklas Söderlund 90121a816e7SNiklas Söderlund fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); 9020f4b3378SNiklas Söderlund 9030f4b3378SNiklas Söderlund /* 9040f4b3378SNiklas Söderlund * There is no HW support for composition do the beast we can 9050f4b3378SNiklas Söderlund * by modifying the buffer offset 9060f4b3378SNiklas Söderlund */ 9070f4b3378SNiklas Söderlund offsetx = vin->compose.left * fmt->bpp; 9080f4b3378SNiklas Söderlund offsety = vin->compose.top * vin->format.bytesperline; 9090f4b3378SNiklas Söderlund offset = addr + offsetx + offsety; 9100f4b3378SNiklas Söderlund 9110f4b3378SNiklas Söderlund /* 9120f4b3378SNiklas Söderlund * The address needs to be 128 bytes aligned. Driver should never accept 9130f4b3378SNiklas Söderlund * settings that do not satisfy this in the first place... 9140f4b3378SNiklas Söderlund */ 9150f4b3378SNiklas Söderlund if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK)) 9160f4b3378SNiklas Söderlund return; 9170f4b3378SNiklas Söderlund 9180f4b3378SNiklas Söderlund rvin_write(vin, offset, VNMB_REG(slot)); 9190f4b3378SNiklas Söderlund } 9200f4b3378SNiklas Söderlund 9210f4b3378SNiklas Söderlund /* 9220f4b3378SNiklas Söderlund * Moves a buffer from the queue to the HW slot. If no buffer is 9230f4b3378SNiklas Söderlund * available use the scratch buffer. The scratch buffer is never 9240f4b3378SNiklas Söderlund * returned to userspace, its only function is to enable the capture 9250f4b3378SNiklas Söderlund * loop to keep running. 9260f4b3378SNiklas Söderlund */ 9270f4b3378SNiklas Söderlund static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) 9280f4b3378SNiklas Söderlund { 9290f4b3378SNiklas Söderlund struct rvin_buffer *buf; 9300f4b3378SNiklas Söderlund struct vb2_v4l2_buffer *vbuf; 9310f4b3378SNiklas Söderlund dma_addr_t phys_addr; 9327e0cfdadSNiklas Söderlund int prev; 9330f4b3378SNiklas Söderlund 9340f4b3378SNiklas Söderlund /* A already populated slot shall never be overwritten. */ 935e72b7359SNiklas Söderlund if (WARN_ON(vin->buf_hw[slot].buffer)) 9360f4b3378SNiklas Söderlund return; 9370f4b3378SNiklas Söderlund 9387e0cfdadSNiklas Söderlund prev = (slot == 0 ? HW_BUFFER_NUM : slot) - 1; 9390f4b3378SNiklas Söderlund 9407e0cfdadSNiklas Söderlund if (vin->buf_hw[prev].type == HALF_TOP) { 9417e0cfdadSNiklas Söderlund vbuf = vin->buf_hw[prev].buffer; 9427e0cfdadSNiklas Söderlund vin->buf_hw[slot].buffer = vbuf; 9437e0cfdadSNiklas Söderlund vin->buf_hw[slot].type = HALF_BOTTOM; 9447e0cfdadSNiklas Söderlund switch (vin->format.pixelformat) { 9457e0cfdadSNiklas Söderlund case V4L2_PIX_FMT_NV12: 9467e0cfdadSNiklas Söderlund case V4L2_PIX_FMT_NV16: 9477e0cfdadSNiklas Söderlund phys_addr = vin->buf_hw[prev].phys + 9487e0cfdadSNiklas Söderlund vin->format.sizeimage / 4; 9497e0cfdadSNiklas Söderlund break; 9507e0cfdadSNiklas Söderlund default: 9517e0cfdadSNiklas Söderlund phys_addr = vin->buf_hw[prev].phys + 9527e0cfdadSNiklas Söderlund vin->format.sizeimage / 2; 9537e0cfdadSNiklas Söderlund break; 9547e0cfdadSNiklas Söderlund } 955a5991c4eSNiklas Söderlund } else if ((vin->state != STOPPED && vin->state != RUNNING) || 956a5991c4eSNiklas Söderlund list_empty(&vin->buf_list)) { 957e72b7359SNiklas Söderlund vin->buf_hw[slot].buffer = NULL; 9587e0cfdadSNiklas Söderlund vin->buf_hw[slot].type = FULL; 9590f4b3378SNiklas Söderlund phys_addr = vin->scratch_phys; 9600f4b3378SNiklas Söderlund } else { 9610f4b3378SNiklas Söderlund /* Keep track of buffer we give to HW */ 9620f4b3378SNiklas Söderlund buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); 9630f4b3378SNiklas Söderlund vbuf = &buf->vb; 9640f4b3378SNiklas Söderlund list_del_init(to_buf_list(vbuf)); 965e72b7359SNiklas Söderlund vin->buf_hw[slot].buffer = vbuf; 9660f4b3378SNiklas Söderlund 9677e0cfdadSNiklas Söderlund vin->buf_hw[slot].type = 9687e0cfdadSNiklas Söderlund V4L2_FIELD_IS_SEQUENTIAL(vin->format.field) ? 9697e0cfdadSNiklas Söderlund HALF_TOP : FULL; 9707e0cfdadSNiklas Söderlund 9710f4b3378SNiklas Söderlund /* Setup DMA */ 9720f4b3378SNiklas Söderlund phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); 9730f4b3378SNiklas Söderlund } 9740f4b3378SNiklas Söderlund 9757e0cfdadSNiklas Söderlund vin_dbg(vin, "Filling HW slot: %d type: %d buffer: %p\n", 9767e0cfdadSNiklas Söderlund slot, vin->buf_hw[slot].type, vin->buf_hw[slot].buffer); 9777e0cfdadSNiklas Söderlund 9787e0cfdadSNiklas Söderlund vin->buf_hw[slot].phys = phys_addr; 9790f4b3378SNiklas Söderlund rvin_set_slot_addr(vin, slot, phys_addr); 9800f4b3378SNiklas Söderlund } 9810f4b3378SNiklas Söderlund 9820f4b3378SNiklas Söderlund static int rvin_capture_start(struct rvin_dev *vin) 9830f4b3378SNiklas Söderlund { 9840f4b3378SNiklas Söderlund int slot, ret; 9850f4b3378SNiklas Söderlund 9867e0cfdadSNiklas Söderlund for (slot = 0; slot < HW_BUFFER_NUM; slot++) { 9877e0cfdadSNiklas Söderlund vin->buf_hw[slot].buffer = NULL; 9887e0cfdadSNiklas Söderlund vin->buf_hw[slot].type = FULL; 9897e0cfdadSNiklas Söderlund } 9907e0cfdadSNiklas Söderlund 9910f4b3378SNiklas Söderlund for (slot = 0; slot < HW_BUFFER_NUM; slot++) 9920f4b3378SNiklas Söderlund rvin_fill_hw_slot(vin, slot); 9930f4b3378SNiklas Söderlund 9940f4b3378SNiklas Söderlund ret = rvin_setup(vin); 9950f4b3378SNiklas Söderlund if (ret) 9960f4b3378SNiklas Söderlund return ret; 9970f4b3378SNiklas Söderlund 998*3ad69c61SNiklas Söderlund rvin_crop_scale_comp(vin); 999*3ad69c61SNiklas Söderlund 10000f4b3378SNiklas Söderlund vin_dbg(vin, "Starting to capture\n"); 10010f4b3378SNiklas Söderlund 10020f4b3378SNiklas Söderlund /* Continuous Frame Capture Mode */ 10030f4b3378SNiklas Söderlund rvin_write(vin, VNFC_C_FRAME, VNFC_REG); 10040f4b3378SNiklas Söderlund 100523689ab1SNiklas Söderlund vin->state = STARTING; 10060f4b3378SNiklas Söderlund 10070f4b3378SNiklas Söderlund return 0; 10080f4b3378SNiklas Söderlund } 10090f4b3378SNiklas Söderlund 10100f4b3378SNiklas Söderlund static void rvin_capture_stop(struct rvin_dev *vin) 10110f4b3378SNiklas Söderlund { 10120f4b3378SNiklas Söderlund /* Set continuous & single transfer off */ 10130f4b3378SNiklas Söderlund rvin_write(vin, 0, VNFC_REG); 10140f4b3378SNiklas Söderlund 10150f4b3378SNiklas Söderlund /* Disable module */ 10160f4b3378SNiklas Söderlund rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG); 10170f4b3378SNiklas Söderlund } 10180f4b3378SNiklas Söderlund 10190f4b3378SNiklas Söderlund /* ----------------------------------------------------------------------------- 1020f00add96SNiklas Söderlund * DMA Functions 1021f00add96SNiklas Söderlund */ 1022f00add96SNiklas Söderlund 1023f00add96SNiklas Söderlund #define RVIN_TIMEOUT_MS 100 1024f00add96SNiklas Söderlund #define RVIN_RETRIES 10 1025f00add96SNiklas Söderlund 1026f00add96SNiklas Söderlund static irqreturn_t rvin_irq(int irq, void *data) 1027f00add96SNiklas Söderlund { 1028f00add96SNiklas Söderlund struct rvin_dev *vin = data; 1029b6f556cbSNiklas Söderlund u32 int_status, vnms; 1030f00add96SNiklas Söderlund int slot; 1031dc9aec79SNiklas Söderlund unsigned int handled = 0; 1032f00add96SNiklas Söderlund unsigned long flags; 1033f00add96SNiklas Söderlund 1034f00add96SNiklas Söderlund spin_lock_irqsave(&vin->qlock, flags); 1035f00add96SNiklas Söderlund 1036f00add96SNiklas Söderlund int_status = rvin_get_interrupt_status(vin); 1037f00add96SNiklas Söderlund if (!int_status) 1038f00add96SNiklas Söderlund goto done; 1039f00add96SNiklas Söderlund 1040f00add96SNiklas Söderlund rvin_ack_interrupt(vin); 1041f00add96SNiklas Söderlund handled = 1; 1042f00add96SNiklas Söderlund 104330334d3dSNiklas Söderlund /* Nothing to do if nothing was captured. */ 104430334d3dSNiklas Söderlund if (!(int_status & VNINTS_FIS)) 104530334d3dSNiklas Söderlund goto done; 104630334d3dSNiklas Söderlund 1047f00add96SNiklas Söderlund /* Nothing to do if capture status is 'STOPPED' */ 1048f00add96SNiklas Söderlund if (vin->state == STOPPED) { 1049f00add96SNiklas Söderlund vin_dbg(vin, "IRQ while state stopped\n"); 1050f00add96SNiklas Söderlund goto done; 1051f00add96SNiklas Söderlund } 1052f00add96SNiklas Söderlund 1053f00add96SNiklas Söderlund /* Prepare for capture and update state */ 1054b6f556cbSNiklas Söderlund vnms = rvin_read(vin, VNMS_REG); 1055dc9aec79SNiklas Söderlund slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; 1056f00add96SNiklas Söderlund 105723689ab1SNiklas Söderlund /* 105823689ab1SNiklas Söderlund * To hand buffers back in a known order to userspace start 105923689ab1SNiklas Söderlund * to capture first from slot 0. 106023689ab1SNiklas Söderlund */ 106123689ab1SNiklas Söderlund if (vin->state == STARTING) { 106223689ab1SNiklas Söderlund if (slot != 0) { 106323689ab1SNiklas Söderlund vin_dbg(vin, "Starting sync slot: %d\n", slot); 106423689ab1SNiklas Söderlund goto done; 106523689ab1SNiklas Söderlund } 106623689ab1SNiklas Söderlund 106723689ab1SNiklas Söderlund vin_dbg(vin, "Capture start synced!\n"); 106823689ab1SNiklas Söderlund vin->state = RUNNING; 106923689ab1SNiklas Söderlund } 107023689ab1SNiklas Söderlund 1071f00add96SNiklas Söderlund /* Capture frame */ 1072e72b7359SNiklas Söderlund if (vin->buf_hw[slot].buffer) { 10737e0cfdadSNiklas Söderlund /* 10747e0cfdadSNiklas Söderlund * Nothing to do but refill the hardware slot if 10757e0cfdadSNiklas Söderlund * capture only filled first half of vb2 buffer. 10767e0cfdadSNiklas Söderlund */ 10777e0cfdadSNiklas Söderlund if (vin->buf_hw[slot].type == HALF_TOP) { 10787e0cfdadSNiklas Söderlund vin->buf_hw[slot].buffer = NULL; 10797e0cfdadSNiklas Söderlund rvin_fill_hw_slot(vin, slot); 10807e0cfdadSNiklas Söderlund goto done; 10817e0cfdadSNiklas Söderlund } 10827e0cfdadSNiklas Söderlund 1083e72b7359SNiklas Söderlund vin->buf_hw[slot].buffer->field = 1084e72b7359SNiklas Söderlund rvin_get_active_field(vin, vnms); 1085e72b7359SNiklas Söderlund vin->buf_hw[slot].buffer->sequence = vin->sequence; 1086e72b7359SNiklas Söderlund vin->buf_hw[slot].buffer->vb2_buf.timestamp = ktime_get_ns(); 1087e72b7359SNiklas Söderlund vb2_buffer_done(&vin->buf_hw[slot].buffer->vb2_buf, 1088dc9aec79SNiklas Söderlund VB2_BUF_STATE_DONE); 1089e72b7359SNiklas Söderlund vin->buf_hw[slot].buffer = NULL; 1090dc9aec79SNiklas Söderlund } else { 1091dc9aec79SNiklas Söderlund /* Scratch buffer was used, dropping frame. */ 1092dc9aec79SNiklas Söderlund vin_dbg(vin, "Dropping frame %u\n", vin->sequence); 1093dc9aec79SNiklas Söderlund } 1094dc9aec79SNiklas Söderlund 1095dc9aec79SNiklas Söderlund vin->sequence++; 1096f00add96SNiklas Söderlund 1097f00add96SNiklas Söderlund /* Prepare for next frame */ 1098dc9aec79SNiklas Söderlund rvin_fill_hw_slot(vin, slot); 1099f00add96SNiklas Söderlund done: 1100f00add96SNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 1101f00add96SNiklas Söderlund 1102f00add96SNiklas Söderlund return IRQ_RETVAL(handled); 1103f00add96SNiklas Söderlund } 1104f00add96SNiklas Söderlund 1105b83a18ccSNiklas Söderlund static void return_unused_buffers(struct rvin_dev *vin, 1106f00add96SNiklas Söderlund enum vb2_buffer_state state) 1107f00add96SNiklas Söderlund { 1108f00add96SNiklas Söderlund struct rvin_buffer *buf, *node; 110963a71dd8SNiklas Söderlund unsigned long flags; 111063a71dd8SNiklas Söderlund 111163a71dd8SNiklas Söderlund spin_lock_irqsave(&vin->qlock, flags); 11127e0cfdadSNiklas Söderlund 1113f00add96SNiklas Söderlund list_for_each_entry_safe(buf, node, &vin->buf_list, list) { 1114f00add96SNiklas Söderlund vb2_buffer_done(&buf->vb.vb2_buf, state); 1115f00add96SNiklas Söderlund list_del(&buf->list); 1116f00add96SNiklas Söderlund } 111763a71dd8SNiklas Söderlund 111863a71dd8SNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 1119f00add96SNiklas Söderlund } 1120f00add96SNiklas Söderlund 1121f00add96SNiklas Söderlund static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, 1122f00add96SNiklas Söderlund unsigned int *nplanes, unsigned int sizes[], 112336c0f8b3SHans Verkuil struct device *alloc_devs[]) 1124f00add96SNiklas Söderlund 1125f00add96SNiklas Söderlund { 1126f00add96SNiklas Söderlund struct rvin_dev *vin = vb2_get_drv_priv(vq); 1127f00add96SNiklas Söderlund 1128f00add96SNiklas Söderlund /* Make sure the image size is large enough. */ 1129f00add96SNiklas Söderlund if (*nplanes) 1130f00add96SNiklas Söderlund return sizes[0] < vin->format.sizeimage ? -EINVAL : 0; 1131f00add96SNiklas Söderlund 1132f00add96SNiklas Söderlund *nplanes = 1; 1133f00add96SNiklas Söderlund sizes[0] = vin->format.sizeimage; 1134f00add96SNiklas Söderlund 1135f00add96SNiklas Söderlund return 0; 1136f00add96SNiklas Söderlund }; 1137f00add96SNiklas Söderlund 1138f00add96SNiklas Söderlund static int rvin_buffer_prepare(struct vb2_buffer *vb) 1139f00add96SNiklas Söderlund { 1140f00add96SNiklas Söderlund struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue); 1141f00add96SNiklas Söderlund unsigned long size = vin->format.sizeimage; 1142f00add96SNiklas Söderlund 1143f00add96SNiklas Söderlund if (vb2_plane_size(vb, 0) < size) { 1144f00add96SNiklas Söderlund vin_err(vin, "buffer too small (%lu < %lu)\n", 1145f00add96SNiklas Söderlund vb2_plane_size(vb, 0), size); 1146f00add96SNiklas Söderlund return -EINVAL; 1147f00add96SNiklas Söderlund } 1148f00add96SNiklas Söderlund 1149f00add96SNiklas Söderlund vb2_set_plane_payload(vb, 0, size); 1150f00add96SNiklas Söderlund 1151f00add96SNiklas Söderlund return 0; 1152f00add96SNiklas Söderlund } 1153f00add96SNiklas Söderlund 1154f00add96SNiklas Söderlund static void rvin_buffer_queue(struct vb2_buffer *vb) 1155f00add96SNiklas Söderlund { 1156f00add96SNiklas Söderlund struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1157f00add96SNiklas Söderlund struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue); 1158f00add96SNiklas Söderlund unsigned long flags; 1159f00add96SNiklas Söderlund 1160f00add96SNiklas Söderlund spin_lock_irqsave(&vin->qlock, flags); 1161f00add96SNiklas Söderlund 1162f00add96SNiklas Söderlund list_add_tail(to_buf_list(vbuf), &vin->buf_list); 1163f00add96SNiklas Söderlund 1164f00add96SNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 1165f00add96SNiklas Söderlund } 1166f00add96SNiklas Söderlund 11677b7eb115SNiklas Söderlund static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, 11687b7eb115SNiklas Söderlund struct media_pad *pad) 11697b7eb115SNiklas Söderlund { 11707b7eb115SNiklas Söderlund struct v4l2_subdev_format fmt = { 11717b7eb115SNiklas Söderlund .which = V4L2_SUBDEV_FORMAT_ACTIVE, 11727b7eb115SNiklas Söderlund }; 11737b7eb115SNiklas Söderlund 11747b7eb115SNiklas Söderlund fmt.pad = pad->index; 11757b7eb115SNiklas Söderlund if (v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt)) 11767b7eb115SNiklas Söderlund return -EPIPE; 11777b7eb115SNiklas Söderlund 11787b7eb115SNiklas Söderlund switch (fmt.format.code) { 11797b7eb115SNiklas Söderlund case MEDIA_BUS_FMT_YUYV8_1X16: 118001d72e9dSNiklas Söderlund case MEDIA_BUS_FMT_UYVY8_1X16: 11817b7eb115SNiklas Söderlund case MEDIA_BUS_FMT_UYVY8_2X8: 11827b7eb115SNiklas Söderlund case MEDIA_BUS_FMT_UYVY10_2X10: 11837b7eb115SNiklas Söderlund case MEDIA_BUS_FMT_RGB888_1X24: 1184fd22e8ebSLad Prabhakar break; 11858c3e0f67SNiklas Söderlund case MEDIA_BUS_FMT_SBGGR8_1X8: 11868c3e0f67SNiklas Söderlund if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR8) 11878c3e0f67SNiklas Söderlund return -EPIPE; 11888c3e0f67SNiklas Söderlund break; 11898c3e0f67SNiklas Söderlund case MEDIA_BUS_FMT_SGBRG8_1X8: 11908c3e0f67SNiklas Söderlund if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG8) 11918c3e0f67SNiklas Söderlund return -EPIPE; 11928c3e0f67SNiklas Söderlund break; 11938c3e0f67SNiklas Söderlund case MEDIA_BUS_FMT_SGRBG8_1X8: 11948c3e0f67SNiklas Söderlund if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG8) 11958c3e0f67SNiklas Söderlund return -EPIPE; 11968c3e0f67SNiklas Söderlund break; 1197fd22e8ebSLad Prabhakar case MEDIA_BUS_FMT_SRGGB8_1X8: 1198fd22e8ebSLad Prabhakar if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8) 1199fd22e8ebSLad Prabhakar return -EPIPE; 12007b7eb115SNiklas Söderlund break; 1201c93beb52SVladimir Barinov case MEDIA_BUS_FMT_Y8_1X8: 1202c93beb52SVladimir Barinov if (vin->format.pixelformat != V4L2_PIX_FMT_GREY) 1203c93beb52SVladimir Barinov return -EPIPE; 1204c93beb52SVladimir Barinov break; 12057b7eb115SNiklas Söderlund default: 12067b7eb115SNiklas Söderlund return -EPIPE; 12077b7eb115SNiklas Söderlund } 1208fd22e8ebSLad Prabhakar vin->mbus_code = fmt.format.code; 12097b7eb115SNiklas Söderlund 12107b7eb115SNiklas Söderlund switch (fmt.format.field) { 12117b7eb115SNiklas Söderlund case V4L2_FIELD_TOP: 12127b7eb115SNiklas Söderlund case V4L2_FIELD_BOTTOM: 12137b7eb115SNiklas Söderlund case V4L2_FIELD_NONE: 12147b7eb115SNiklas Söderlund case V4L2_FIELD_INTERLACED_TB: 12157b7eb115SNiklas Söderlund case V4L2_FIELD_INTERLACED_BT: 12167b7eb115SNiklas Söderlund case V4L2_FIELD_INTERLACED: 12177b7eb115SNiklas Söderlund case V4L2_FIELD_SEQ_TB: 12187b7eb115SNiklas Söderlund case V4L2_FIELD_SEQ_BT: 12197b7eb115SNiklas Söderlund /* Supported natively */ 12207b7eb115SNiklas Söderlund break; 12217b7eb115SNiklas Söderlund case V4L2_FIELD_ALTERNATE: 12227b7eb115SNiklas Söderlund switch (vin->format.field) { 12237b7eb115SNiklas Söderlund case V4L2_FIELD_TOP: 12247b7eb115SNiklas Söderlund case V4L2_FIELD_BOTTOM: 12257b7eb115SNiklas Söderlund case V4L2_FIELD_NONE: 122608369321SNiklas Söderlund case V4L2_FIELD_ALTERNATE: 12277b7eb115SNiklas Söderlund break; 12287b7eb115SNiklas Söderlund case V4L2_FIELD_INTERLACED_TB: 12297b7eb115SNiklas Söderlund case V4L2_FIELD_INTERLACED_BT: 12307b7eb115SNiklas Söderlund case V4L2_FIELD_INTERLACED: 12317b7eb115SNiklas Söderlund case V4L2_FIELD_SEQ_TB: 12327b7eb115SNiklas Söderlund case V4L2_FIELD_SEQ_BT: 12337b7eb115SNiklas Söderlund /* Use VIN hardware to combine the two fields */ 12347b7eb115SNiklas Söderlund fmt.format.height *= 2; 12357b7eb115SNiklas Söderlund break; 12367b7eb115SNiklas Söderlund default: 12377b7eb115SNiklas Söderlund return -EPIPE; 12387b7eb115SNiklas Söderlund } 12397b7eb115SNiklas Söderlund break; 12407b7eb115SNiklas Söderlund default: 12417b7eb115SNiklas Söderlund return -EPIPE; 12427b7eb115SNiklas Söderlund } 12437b7eb115SNiklas Söderlund 1244*3ad69c61SNiklas Söderlund if (rvin_scaler_needed(vin)) { 1245*3ad69c61SNiklas Söderlund if (!vin->scaler) 1246*3ad69c61SNiklas Söderlund return -EPIPE; 1247*3ad69c61SNiklas Söderlund } else { 12487b7eb115SNiklas Söderlund if (fmt.format.width != vin->format.width || 1249*3ad69c61SNiklas Söderlund fmt.format.height != vin->format.height) 1250*3ad69c61SNiklas Söderlund return -EPIPE; 1251*3ad69c61SNiklas Söderlund } 1252*3ad69c61SNiklas Söderlund 1253*3ad69c61SNiklas Söderlund if (fmt.format.code != vin->mbus_code) 12547b7eb115SNiklas Söderlund return -EPIPE; 12557b7eb115SNiklas Söderlund 12567b7eb115SNiklas Söderlund return 0; 12577b7eb115SNiklas Söderlund } 12587b7eb115SNiklas Söderlund 12597b7eb115SNiklas Söderlund static int rvin_set_stream(struct rvin_dev *vin, int on) 12607b7eb115SNiklas Söderlund { 12617b7eb115SNiklas Söderlund struct v4l2_subdev *sd; 12627b7eb115SNiklas Söderlund struct media_pad *pad; 12637b7eb115SNiklas Söderlund int ret; 12647b7eb115SNiklas Söderlund 12657b7eb115SNiklas Söderlund /* No media controller used, simply pass operation to subdevice. */ 12667b7eb115SNiklas Söderlund if (!vin->info->use_mc) { 1267d7592b2eSNiklas Söderlund ret = v4l2_subdev_call(vin->parallel.subdev, video, s_stream, 12687b7eb115SNiklas Söderlund on); 12697b7eb115SNiklas Söderlund 12707b7eb115SNiklas Söderlund return ret == -ENOIOCTLCMD ? 0 : ret; 12717b7eb115SNiklas Söderlund } 12727b7eb115SNiklas Söderlund 1273b2e44430SLaurent Pinchart pad = media_pad_remote_pad_first(&vin->pad); 12747b7eb115SNiklas Söderlund if (!pad) 12757b7eb115SNiklas Söderlund return -EPIPE; 12767b7eb115SNiklas Söderlund 12777b7eb115SNiklas Söderlund sd = media_entity_to_v4l2_subdev(pad->entity); 12787b7eb115SNiklas Söderlund 12797b7eb115SNiklas Söderlund if (!on) { 128012cecbf9STomi Valkeinen video_device_pipeline_stop(&vin->vdev); 12817b7eb115SNiklas Söderlund return v4l2_subdev_call(sd, video, s_stream, 0); 12827b7eb115SNiklas Söderlund } 12837b7eb115SNiklas Söderlund 12847b7eb115SNiklas Söderlund ret = rvin_mc_validate_format(vin, sd, pad); 12857b7eb115SNiklas Söderlund if (ret) 12867b7eb115SNiklas Söderlund return ret; 12877b7eb115SNiklas Söderlund 12886eaff06aSTomi Valkeinen ret = video_device_pipeline_alloc_start(&vin->vdev); 12897b7eb115SNiklas Söderlund if (ret) 12907b7eb115SNiklas Söderlund return ret; 12917b7eb115SNiklas Söderlund 12927b7eb115SNiklas Söderlund ret = v4l2_subdev_call(sd, video, s_stream, 1); 12937b7eb115SNiklas Söderlund if (ret == -ENOIOCTLCMD) 12947b7eb115SNiklas Söderlund ret = 0; 12957b7eb115SNiklas Söderlund if (ret) 129612cecbf9STomi Valkeinen video_device_pipeline_stop(&vin->vdev); 12977b7eb115SNiklas Söderlund 12987b7eb115SNiklas Söderlund return ret; 12997b7eb115SNiklas Söderlund } 13007b7eb115SNiklas Söderlund 130163a71dd8SNiklas Söderlund int rvin_start_streaming(struct rvin_dev *vin) 1302f00add96SNiklas Söderlund { 1303f00add96SNiklas Söderlund unsigned long flags; 1304f00add96SNiklas Söderlund int ret; 1305f00add96SNiklas Söderlund 13067b7eb115SNiklas Söderlund ret = rvin_set_stream(vin, 1); 130763a71dd8SNiklas Söderlund if (ret) 130863a71dd8SNiklas Söderlund return ret; 1309f00add96SNiklas Söderlund 1310f00add96SNiklas Söderlund spin_lock_irqsave(&vin->qlock, flags); 1311f00add96SNiklas Söderlund 1312f00add96SNiklas Söderlund vin->sequence = 0; 1313f00add96SNiklas Söderlund 1314f00add96SNiklas Söderlund ret = rvin_capture_start(vin); 131563a71dd8SNiklas Söderlund if (ret) 13167b7eb115SNiklas Söderlund rvin_set_stream(vin, 0); 1317f00add96SNiklas Söderlund 1318f00add96SNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 13196a8ffa8bSNiklas Söderlund 1320f00add96SNiklas Söderlund return ret; 1321f00add96SNiklas Söderlund } 1322f00add96SNiklas Söderlund 132363a71dd8SNiklas Söderlund static int rvin_start_streaming_vq(struct vb2_queue *vq, unsigned int count) 1324f00add96SNiklas Söderlund { 1325f00add96SNiklas Söderlund struct rvin_dev *vin = vb2_get_drv_priv(vq); 132663a71dd8SNiklas Söderlund int ret = -ENOMEM; 132763a71dd8SNiklas Söderlund 132863a71dd8SNiklas Söderlund /* Allocate scratch buffer. */ 132963a71dd8SNiklas Söderlund vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage, 133063a71dd8SNiklas Söderlund &vin->scratch_phys, GFP_KERNEL); 133163a71dd8SNiklas Söderlund if (!vin->scratch) 133263a71dd8SNiklas Söderlund goto err_scratch; 133363a71dd8SNiklas Söderlund 133463a71dd8SNiklas Söderlund ret = rvin_start_streaming(vin); 133563a71dd8SNiklas Söderlund if (ret) 133663a71dd8SNiklas Söderlund goto err_start; 133763a71dd8SNiklas Söderlund 133863a71dd8SNiklas Söderlund return 0; 133963a71dd8SNiklas Söderlund err_start: 134063a71dd8SNiklas Söderlund dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, 134163a71dd8SNiklas Söderlund vin->scratch_phys); 134263a71dd8SNiklas Söderlund err_scratch: 134363a71dd8SNiklas Söderlund return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); 134463a71dd8SNiklas Söderlund 134563a71dd8SNiklas Söderlund return ret; 134663a71dd8SNiklas Söderlund } 134763a71dd8SNiklas Söderlund 134863a71dd8SNiklas Söderlund void rvin_stop_streaming(struct rvin_dev *vin) 134963a71dd8SNiklas Söderlund { 135090ed5785SNiklas Söderlund unsigned int i, retries; 1351f00add96SNiklas Söderlund unsigned long flags; 135290ed5785SNiklas Söderlund bool buffersFreed; 1353f00add96SNiklas Söderlund 1354f00add96SNiklas Söderlund spin_lock_irqsave(&vin->qlock, flags); 1355f00add96SNiklas Söderlund 1356c4f11535SNiklas Söderlund if (vin->state == STOPPED) { 1357c4f11535SNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 1358c4f11535SNiklas Söderlund return; 1359c4f11535SNiklas Söderlund } 1360c4f11535SNiklas Söderlund 1361f00add96SNiklas Söderlund vin->state = STOPPING; 1362f00add96SNiklas Söderlund 136390ed5785SNiklas Söderlund /* Wait until only scratch buffer is used, max 3 interrupts. */ 136490ed5785SNiklas Söderlund retries = 0; 136590ed5785SNiklas Söderlund while (retries++ < RVIN_RETRIES) { 136690ed5785SNiklas Söderlund buffersFreed = true; 136790ed5785SNiklas Söderlund for (i = 0; i < HW_BUFFER_NUM; i++) 136890ed5785SNiklas Söderlund if (vin->buf_hw[i].buffer) 136990ed5785SNiklas Söderlund buffersFreed = false; 137090ed5785SNiklas Söderlund 137190ed5785SNiklas Söderlund if (buffersFreed) 137290ed5785SNiklas Söderlund break; 137390ed5785SNiklas Söderlund 137490ed5785SNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 137590ed5785SNiklas Söderlund msleep(RVIN_TIMEOUT_MS); 137690ed5785SNiklas Söderlund spin_lock_irqsave(&vin->qlock, flags); 137790ed5785SNiklas Söderlund } 137890ed5785SNiklas Söderlund 1379f00add96SNiklas Söderlund /* Wait for streaming to stop */ 138090ed5785SNiklas Söderlund retries = 0; 1381f00add96SNiklas Söderlund while (retries++ < RVIN_RETRIES) { 1382f00add96SNiklas Söderlund 1383f00add96SNiklas Söderlund rvin_capture_stop(vin); 1384f00add96SNiklas Söderlund 1385f00add96SNiklas Söderlund /* Check if HW is stopped */ 1386f00add96SNiklas Söderlund if (!rvin_capture_active(vin)) { 1387f00add96SNiklas Söderlund vin->state = STOPPED; 1388f00add96SNiklas Söderlund break; 1389f00add96SNiklas Söderlund } 1390f00add96SNiklas Söderlund 1391f00add96SNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 1392f00add96SNiklas Söderlund msleep(RVIN_TIMEOUT_MS); 1393f00add96SNiklas Söderlund spin_lock_irqsave(&vin->qlock, flags); 1394f00add96SNiklas Söderlund } 1395f00add96SNiklas Söderlund 139690ed5785SNiklas Söderlund if (!buffersFreed || vin->state != STOPPED) { 1397f00add96SNiklas Söderlund /* 1398f00add96SNiklas Söderlund * If this happens something have gone horribly wrong. 1399f00add96SNiklas Söderlund * Set state to stopped to prevent the interrupt handler 1400f00add96SNiklas Söderlund * to make things worse... 1401f00add96SNiklas Söderlund */ 1402f00add96SNiklas Söderlund vin_err(vin, "Failed stop HW, something is seriously broken\n"); 1403f00add96SNiklas Söderlund vin->state = STOPPED; 1404f00add96SNiklas Söderlund } 1405f00add96SNiklas Söderlund 1406f00add96SNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 1407f00add96SNiklas Söderlund 1408dca7cc1cSNiklas Söderlund /* If something went wrong, free buffers with an error. */ 1409dca7cc1cSNiklas Söderlund if (!buffersFreed) { 1410dca7cc1cSNiklas Söderlund return_unused_buffers(vin, VB2_BUF_STATE_ERROR); 1411dca7cc1cSNiklas Söderlund for (i = 0; i < HW_BUFFER_NUM; i++) { 1412dca7cc1cSNiklas Söderlund if (vin->buf_hw[i].buffer) 1413dca7cc1cSNiklas Söderlund vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf, 1414dca7cc1cSNiklas Söderlund VB2_BUF_STATE_ERROR); 1415dca7cc1cSNiklas Söderlund } 1416dca7cc1cSNiklas Söderlund } 1417dca7cc1cSNiklas Söderlund 14187b7eb115SNiklas Söderlund rvin_set_stream(vin, 0); 1419f00add96SNiklas Söderlund 1420f00add96SNiklas Söderlund /* disable interrupts */ 1421f00add96SNiklas Söderlund rvin_disable_interrupts(vin); 142263a71dd8SNiklas Söderlund } 142363a71dd8SNiklas Söderlund 142463a71dd8SNiklas Söderlund static void rvin_stop_streaming_vq(struct vb2_queue *vq) 142563a71dd8SNiklas Söderlund { 142663a71dd8SNiklas Söderlund struct rvin_dev *vin = vb2_get_drv_priv(vq); 142763a71dd8SNiklas Söderlund 142863a71dd8SNiklas Söderlund rvin_stop_streaming(vin); 14296a8ffa8bSNiklas Söderlund 14306a8ffa8bSNiklas Söderlund /* Free scratch buffer. */ 14316a8ffa8bSNiklas Söderlund dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, 14326a8ffa8bSNiklas Söderlund vin->scratch_phys); 143363a71dd8SNiklas Söderlund 143463a71dd8SNiklas Söderlund return_unused_buffers(vin, VB2_BUF_STATE_ERROR); 1435f00add96SNiklas Söderlund } 1436f00add96SNiklas Söderlund 1437b7b361f0SJulia Lawall static const struct vb2_ops rvin_qops = { 1438f00add96SNiklas Söderlund .queue_setup = rvin_queue_setup, 1439f00add96SNiklas Söderlund .buf_prepare = rvin_buffer_prepare, 1440f00add96SNiklas Söderlund .buf_queue = rvin_buffer_queue, 144163a71dd8SNiklas Söderlund .start_streaming = rvin_start_streaming_vq, 144263a71dd8SNiklas Söderlund .stop_streaming = rvin_stop_streaming_vq, 1443f00add96SNiklas Söderlund .wait_prepare = vb2_ops_wait_prepare, 1444f00add96SNiklas Söderlund .wait_finish = vb2_ops_wait_finish, 1445f00add96SNiklas Söderlund }; 1446f00add96SNiklas Söderlund 1447d6ad012eSNiklas Söderlund void rvin_dma_unregister(struct rvin_dev *vin) 1448f00add96SNiklas Söderlund { 1449f00add96SNiklas Söderlund mutex_destroy(&vin->lock); 1450f00add96SNiklas Söderlund 1451f00add96SNiklas Söderlund v4l2_device_unregister(&vin->v4l2_dev); 1452f00add96SNiklas Söderlund } 1453f00add96SNiklas Söderlund 1454d6ad012eSNiklas Söderlund int rvin_dma_register(struct rvin_dev *vin, int irq) 1455f00add96SNiklas Söderlund { 1456f00add96SNiklas Söderlund struct vb2_queue *q = &vin->queue; 1457f00add96SNiklas Söderlund int i, ret; 1458f00add96SNiklas Söderlund 1459f00add96SNiklas Söderlund /* Initialize the top-level structure */ 1460f00add96SNiklas Söderlund ret = v4l2_device_register(vin->dev, &vin->v4l2_dev); 1461f00add96SNiklas Söderlund if (ret) 1462f00add96SNiklas Söderlund return ret; 1463f00add96SNiklas Söderlund 1464f00add96SNiklas Söderlund mutex_init(&vin->lock); 1465f00add96SNiklas Söderlund INIT_LIST_HEAD(&vin->buf_list); 1466f00add96SNiklas Söderlund 1467f00add96SNiklas Söderlund spin_lock_init(&vin->qlock); 1468f00add96SNiklas Söderlund 1469f00add96SNiklas Söderlund vin->state = STOPPED; 1470f00add96SNiklas Söderlund 1471f00add96SNiklas Söderlund for (i = 0; i < HW_BUFFER_NUM; i++) 1472e72b7359SNiklas Söderlund vin->buf_hw[i].buffer = NULL; 1473f00add96SNiklas Söderlund 1474f00add96SNiklas Söderlund /* buffer queue */ 1475f00add96SNiklas Söderlund q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1476f00add96SNiklas Söderlund q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; 1477f00add96SNiklas Söderlund q->lock = &vin->lock; 1478f00add96SNiklas Söderlund q->drv_priv = vin; 1479f00add96SNiklas Söderlund q->buf_struct_size = sizeof(struct rvin_buffer); 1480f00add96SNiklas Söderlund q->ops = &rvin_qops; 1481f00add96SNiklas Söderlund q->mem_ops = &vb2_dma_contig_memops; 1482f00add96SNiklas Söderlund q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 1483dc9aec79SNiklas Söderlund q->min_buffers_needed = 4; 148453ddcc68SHans Verkuil q->dev = vin->dev; 1485f00add96SNiklas Söderlund 1486f00add96SNiklas Söderlund ret = vb2_queue_init(q); 1487f00add96SNiklas Söderlund if (ret < 0) { 1488f00add96SNiklas Söderlund vin_err(vin, "failed to initialize VB2 queue\n"); 1489f00add96SNiklas Söderlund goto error; 1490f00add96SNiklas Söderlund } 1491f00add96SNiklas Söderlund 1492f00add96SNiklas Söderlund /* irq */ 1493f00add96SNiklas Söderlund ret = devm_request_irq(vin->dev, irq, rvin_irq, IRQF_SHARED, 1494f00add96SNiklas Söderlund KBUILD_MODNAME, vin); 1495f00add96SNiklas Söderlund if (ret) { 1496f00add96SNiklas Söderlund vin_err(vin, "failed to request irq\n"); 1497f00add96SNiklas Söderlund goto error; 1498f00add96SNiklas Söderlund } 1499f00add96SNiklas Söderlund 1500f00add96SNiklas Söderlund return 0; 1501f00add96SNiklas Söderlund error: 1502d6ad012eSNiklas Söderlund rvin_dma_unregister(vin); 1503f00add96SNiklas Söderlund 1504f00add96SNiklas Söderlund return ret; 1505f00add96SNiklas Söderlund } 150690dedce9SNiklas Söderlund 150790dedce9SNiklas Söderlund /* ----------------------------------------------------------------------------- 150890dedce9SNiklas Söderlund * Gen3 CHSEL manipulation 150990dedce9SNiklas Söderlund */ 151090dedce9SNiklas Söderlund 151190dedce9SNiklas Söderlund /* 151290dedce9SNiklas Söderlund * There is no need to have locking around changing the routing 151390dedce9SNiklas Söderlund * as it's only possible to do so when no VIN in the group is 151490dedce9SNiklas Söderlund * streaming so nothing can race with the VNMC register. 151590dedce9SNiklas Söderlund */ 151690dedce9SNiklas Söderlund int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) 151790dedce9SNiklas Söderlund { 1518fb25ca37SJacopo Mondi const struct rvin_group_route *route; 1519fb25ca37SJacopo Mondi u32 ifmd = 0; 1520fb25ca37SJacopo Mondi u32 vnmc; 152190dedce9SNiklas Söderlund int ret; 152290dedce9SNiklas Söderlund 1523334fe327SMauro Carvalho Chehab ret = pm_runtime_resume_and_get(vin->dev); 1524334fe327SMauro Carvalho Chehab if (ret < 0) 152590dedce9SNiklas Söderlund return ret; 152690dedce9SNiklas Söderlund 152790dedce9SNiklas Söderlund /* Make register writes take effect immediately. */ 152890dedce9SNiklas Söderlund vnmc = rvin_read(vin, VNMC_REG); 152990dedce9SNiklas Söderlund rvin_write(vin, vnmc & ~VNMC_VUP, VNMC_REG); 153090dedce9SNiklas Söderlund 1531fb25ca37SJacopo Mondi /* 1532fb25ca37SJacopo Mondi * Set data expansion mode to "pad with 0s" by inspecting the routes 1533fb25ca37SJacopo Mondi * table to find out which bit fields are available in the IFMD 1534fb25ca37SJacopo Mondi * register. IFMD_DES1 controls data expansion mode for CSI20/21, 1535fb25ca37SJacopo Mondi * IFMD_DES0 controls data expansion mode for CSI40/41. 1536fb25ca37SJacopo Mondi */ 15373e52419eSNiklas Söderlund for (route = vin->info->routes; route->chsel; route++) { 1538fb25ca37SJacopo Mondi if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21) 1539fb25ca37SJacopo Mondi ifmd |= VNCSI_IFMD_DES1; 1540fb25ca37SJacopo Mondi else 1541fb25ca37SJacopo Mondi ifmd |= VNCSI_IFMD_DES0; 154290dedce9SNiklas Söderlund 1543fb25ca37SJacopo Mondi if (ifmd == (VNCSI_IFMD_DES0 | VNCSI_IFMD_DES1)) 1544fb25ca37SJacopo Mondi break; 1545fb25ca37SJacopo Mondi } 1546fb25ca37SJacopo Mondi 1547fb25ca37SJacopo Mondi if (ifmd) { 1548fb25ca37SJacopo Mondi ifmd |= VNCSI_IFMD_CSI_CHSEL(chsel); 154990dedce9SNiklas Söderlund rvin_write(vin, ifmd, VNCSI_IFMD_REG); 1550fb25ca37SJacopo Mondi } 155190dedce9SNiklas Söderlund 155290dedce9SNiklas Söderlund vin_dbg(vin, "Set IFMD 0x%x\n", ifmd); 155390dedce9SNiklas Söderlund 155443e36a22SNiklas Söderlund vin->chsel = chsel; 155543e36a22SNiklas Söderlund 155690dedce9SNiklas Söderlund /* Restore VNMC. */ 155790dedce9SNiklas Söderlund rvin_write(vin, vnmc, VNMC_REG); 155890dedce9SNiklas Söderlund 155990dedce9SNiklas Söderlund pm_runtime_put(vin->dev); 156090dedce9SNiklas Söderlund 15618d19d5d0SNiklas Söderlund return 0; 156290dedce9SNiklas Söderlund } 15635720c733SNiklas Söderlund 15645720c733SNiklas Söderlund void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha) 15655720c733SNiklas Söderlund { 15661d99e68cSNiklas Söderlund unsigned long flags; 15671d99e68cSNiklas Söderlund u32 dmr; 15681d99e68cSNiklas Söderlund 15691d99e68cSNiklas Söderlund spin_lock_irqsave(&vin->qlock, flags); 15701d99e68cSNiklas Söderlund 15715720c733SNiklas Söderlund vin->alpha = alpha; 15721d99e68cSNiklas Söderlund 15731d99e68cSNiklas Söderlund if (vin->state == STOPPED) 15741d99e68cSNiklas Söderlund goto out; 15751d99e68cSNiklas Söderlund 15761d99e68cSNiklas Söderlund switch (vin->format.pixelformat) { 15771d99e68cSNiklas Söderlund case V4L2_PIX_FMT_ARGB555: 15781d99e68cSNiklas Söderlund dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_ABIT; 15791d99e68cSNiklas Söderlund if (vin->alpha) 15801d99e68cSNiklas Söderlund dmr |= VNDMR_ABIT; 15811d99e68cSNiklas Söderlund break; 15821d99e68cSNiklas Söderlund case V4L2_PIX_FMT_ABGR32: 15831d99e68cSNiklas Söderlund dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_A8BIT_MASK; 15841d99e68cSNiklas Söderlund dmr |= VNDMR_A8BIT(vin->alpha); 15851d99e68cSNiklas Söderlund break; 15861d99e68cSNiklas Söderlund default: 15871d99e68cSNiklas Söderlund goto out; 15881d99e68cSNiklas Söderlund } 15891d99e68cSNiklas Söderlund 15901d99e68cSNiklas Söderlund rvin_write(vin, dmr, VNDMR_REG); 15911d99e68cSNiklas Söderlund out: 15921d99e68cSNiklas Söderlund spin_unlock_irqrestore(&vin->qlock, flags); 15935720c733SNiklas Söderlund } 1594