1d24a170bSMauro Carvalho Chehab /* 2d24a170bSMauro Carvalho Chehab * vpif - Video Port Interface driver 3d24a170bSMauro Carvalho Chehab * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) 4d24a170bSMauro Carvalho Chehab * that receiving video byte stream and two channels(2, 3) for video output. 5d24a170bSMauro Carvalho Chehab * The hardware supports SDTV, HDTV formats, raw data capture. 6d24a170bSMauro Carvalho Chehab * Currently, the driver supports NTSC and PAL standards. 7d24a170bSMauro Carvalho Chehab * 8d24a170bSMauro Carvalho Chehab * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ 9d24a170bSMauro Carvalho Chehab * 10d24a170bSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or 11d24a170bSMauro Carvalho Chehab * modify it under the terms of the GNU General Public License as 12d24a170bSMauro Carvalho Chehab * published by the Free Software Foundation version 2. 13d24a170bSMauro Carvalho Chehab * 14d24a170bSMauro Carvalho Chehab * This program is distributed .as is. WITHOUT ANY WARRANTY of any 15d24a170bSMauro Carvalho Chehab * kind, whether express or implied; without even the implied warranty 16d24a170bSMauro Carvalho Chehab * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17d24a170bSMauro Carvalho Chehab * GNU General Public License for more details. 18d24a170bSMauro Carvalho Chehab */ 19d24a170bSMauro Carvalho Chehab 20d24a170bSMauro Carvalho Chehab #include <linux/err.h> 21d24a170bSMauro Carvalho Chehab #include <linux/init.h> 22d24a170bSMauro Carvalho Chehab #include <linux/io.h> 23d24a170bSMauro Carvalho Chehab #include <linux/irq.h> 24d24a170bSMauro Carvalho Chehab #include <linux/kernel.h> 25d24a170bSMauro Carvalho Chehab #include <linux/module.h> 26d24a170bSMauro Carvalho Chehab #include <linux/of.h> 27d24a170bSMauro Carvalho Chehab #include <linux/platform_device.h> 28d24a170bSMauro Carvalho Chehab #include <linux/pm_runtime.h> 29d24a170bSMauro Carvalho Chehab #include <linux/spinlock.h> 30d24a170bSMauro Carvalho Chehab #include <linux/v4l2-dv-timings.h> 31d24a170bSMauro Carvalho Chehab #include <linux/of_graph.h> 32d24a170bSMauro Carvalho Chehab 33d24a170bSMauro Carvalho Chehab #include "vpif.h" 34d24a170bSMauro Carvalho Chehab 35d24a170bSMauro Carvalho Chehab MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); 36d24a170bSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 37d24a170bSMauro Carvalho Chehab 38d24a170bSMauro Carvalho Chehab #define VPIF_DRIVER_NAME "vpif" 39d24a170bSMauro Carvalho Chehab MODULE_ALIAS("platform:" VPIF_DRIVER_NAME); 40d24a170bSMauro Carvalho Chehab 41d24a170bSMauro Carvalho Chehab #define VPIF_CH0_MAX_MODES 22 42d24a170bSMauro Carvalho Chehab #define VPIF_CH1_MAX_MODES 2 43d24a170bSMauro Carvalho Chehab #define VPIF_CH2_MAX_MODES 15 44d24a170bSMauro Carvalho Chehab #define VPIF_CH3_MAX_MODES 2 45d24a170bSMauro Carvalho Chehab 46d24a170bSMauro Carvalho Chehab struct vpif_data { 47d24a170bSMauro Carvalho Chehab struct platform_device *capture; 48d24a170bSMauro Carvalho Chehab struct platform_device *display; 49d24a170bSMauro Carvalho Chehab }; 50d24a170bSMauro Carvalho Chehab 51d24a170bSMauro Carvalho Chehab DEFINE_SPINLOCK(vpif_lock); 52d24a170bSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(vpif_lock); 53d24a170bSMauro Carvalho Chehab 54d24a170bSMauro Carvalho Chehab void __iomem *vpif_base; 55d24a170bSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(vpif_base); 56d24a170bSMauro Carvalho Chehab 57d24a170bSMauro Carvalho Chehab /* 58d24a170bSMauro Carvalho Chehab * vpif_ch_params: video standard configuration parameters for vpif 59d24a170bSMauro Carvalho Chehab * 60d24a170bSMauro Carvalho Chehab * The table must include all presets from supported subdevices. 61d24a170bSMauro Carvalho Chehab */ 62d24a170bSMauro Carvalho Chehab const struct vpif_channel_config_params vpif_ch_params[] = { 63d24a170bSMauro Carvalho Chehab /* HDTV formats */ 64d24a170bSMauro Carvalho Chehab { 65d24a170bSMauro Carvalho Chehab .name = "480p59_94", 66d24a170bSMauro Carvalho Chehab .width = 720, 67d24a170bSMauro Carvalho Chehab .height = 480, 68d24a170bSMauro Carvalho Chehab .frm_fmt = 1, 69d24a170bSMauro Carvalho Chehab .ycmux_mode = 0, 70d24a170bSMauro Carvalho Chehab .eav2sav = 138-8, 71d24a170bSMauro Carvalho Chehab .sav2eav = 720, 72d24a170bSMauro Carvalho Chehab .l1 = 1, 73d24a170bSMauro Carvalho Chehab .l3 = 43, 74d24a170bSMauro Carvalho Chehab .l5 = 523, 75d24a170bSMauro Carvalho Chehab .vsize = 525, 76d24a170bSMauro Carvalho Chehab .capture_format = 0, 77d24a170bSMauro Carvalho Chehab .vbi_supported = 0, 78d24a170bSMauro Carvalho Chehab .hd_sd = 1, 79d24a170bSMauro Carvalho Chehab .dv_timings = V4L2_DV_BT_CEA_720X480P59_94, 80d24a170bSMauro Carvalho Chehab }, 81d24a170bSMauro Carvalho Chehab { 82d24a170bSMauro Carvalho Chehab .name = "576p50", 83d24a170bSMauro Carvalho Chehab .width = 720, 84d24a170bSMauro Carvalho Chehab .height = 576, 85d24a170bSMauro Carvalho Chehab .frm_fmt = 1, 86d24a170bSMauro Carvalho Chehab .ycmux_mode = 0, 87d24a170bSMauro Carvalho Chehab .eav2sav = 144-8, 88d24a170bSMauro Carvalho Chehab .sav2eav = 720, 89d24a170bSMauro Carvalho Chehab .l1 = 1, 90d24a170bSMauro Carvalho Chehab .l3 = 45, 91d24a170bSMauro Carvalho Chehab .l5 = 621, 92d24a170bSMauro Carvalho Chehab .vsize = 625, 93d24a170bSMauro Carvalho Chehab .capture_format = 0, 94d24a170bSMauro Carvalho Chehab .vbi_supported = 0, 95d24a170bSMauro Carvalho Chehab .hd_sd = 1, 96d24a170bSMauro Carvalho Chehab .dv_timings = V4L2_DV_BT_CEA_720X576P50, 97d24a170bSMauro Carvalho Chehab }, 98d24a170bSMauro Carvalho Chehab { 99d24a170bSMauro Carvalho Chehab .name = "720p50", 100d24a170bSMauro Carvalho Chehab .width = 1280, 101d24a170bSMauro Carvalho Chehab .height = 720, 102d24a170bSMauro Carvalho Chehab .frm_fmt = 1, 103d24a170bSMauro Carvalho Chehab .ycmux_mode = 0, 104d24a170bSMauro Carvalho Chehab .eav2sav = 700-8, 105d24a170bSMauro Carvalho Chehab .sav2eav = 1280, 106d24a170bSMauro Carvalho Chehab .l1 = 1, 107d24a170bSMauro Carvalho Chehab .l3 = 26, 108d24a170bSMauro Carvalho Chehab .l5 = 746, 109d24a170bSMauro Carvalho Chehab .vsize = 750, 110d24a170bSMauro Carvalho Chehab .capture_format = 0, 111d24a170bSMauro Carvalho Chehab .vbi_supported = 0, 112d24a170bSMauro Carvalho Chehab .hd_sd = 1, 113d24a170bSMauro Carvalho Chehab .dv_timings = V4L2_DV_BT_CEA_1280X720P50, 114d24a170bSMauro Carvalho Chehab }, 115d24a170bSMauro Carvalho Chehab { 116d24a170bSMauro Carvalho Chehab .name = "720p60", 117d24a170bSMauro Carvalho Chehab .width = 1280, 118d24a170bSMauro Carvalho Chehab .height = 720, 119d24a170bSMauro Carvalho Chehab .frm_fmt = 1, 120d24a170bSMauro Carvalho Chehab .ycmux_mode = 0, 121d24a170bSMauro Carvalho Chehab .eav2sav = 370 - 8, 122d24a170bSMauro Carvalho Chehab .sav2eav = 1280, 123d24a170bSMauro Carvalho Chehab .l1 = 1, 124d24a170bSMauro Carvalho Chehab .l3 = 26, 125d24a170bSMauro Carvalho Chehab .l5 = 746, 126d24a170bSMauro Carvalho Chehab .vsize = 750, 127d24a170bSMauro Carvalho Chehab .capture_format = 0, 128d24a170bSMauro Carvalho Chehab .vbi_supported = 0, 129d24a170bSMauro Carvalho Chehab .hd_sd = 1, 130d24a170bSMauro Carvalho Chehab .dv_timings = V4L2_DV_BT_CEA_1280X720P60, 131d24a170bSMauro Carvalho Chehab }, 132d24a170bSMauro Carvalho Chehab { 133d24a170bSMauro Carvalho Chehab .name = "1080I50", 134d24a170bSMauro Carvalho Chehab .width = 1920, 135d24a170bSMauro Carvalho Chehab .height = 1080, 136d24a170bSMauro Carvalho Chehab .frm_fmt = 0, 137d24a170bSMauro Carvalho Chehab .ycmux_mode = 0, 138d24a170bSMauro Carvalho Chehab .eav2sav = 720 - 8, 139d24a170bSMauro Carvalho Chehab .sav2eav = 1920, 140d24a170bSMauro Carvalho Chehab .l1 = 1, 141d24a170bSMauro Carvalho Chehab .l3 = 21, 142d24a170bSMauro Carvalho Chehab .l5 = 561, 143d24a170bSMauro Carvalho Chehab .l7 = 563, 144d24a170bSMauro Carvalho Chehab .l9 = 584, 145d24a170bSMauro Carvalho Chehab .l11 = 1124, 146d24a170bSMauro Carvalho Chehab .vsize = 1125, 147d24a170bSMauro Carvalho Chehab .capture_format = 0, 148d24a170bSMauro Carvalho Chehab .vbi_supported = 0, 149d24a170bSMauro Carvalho Chehab .hd_sd = 1, 150d24a170bSMauro Carvalho Chehab .dv_timings = V4L2_DV_BT_CEA_1920X1080I50, 151d24a170bSMauro Carvalho Chehab }, 152d24a170bSMauro Carvalho Chehab { 153d24a170bSMauro Carvalho Chehab .name = "1080I60", 154d24a170bSMauro Carvalho Chehab .width = 1920, 155d24a170bSMauro Carvalho Chehab .height = 1080, 156d24a170bSMauro Carvalho Chehab .frm_fmt = 0, 157d24a170bSMauro Carvalho Chehab .ycmux_mode = 0, 158d24a170bSMauro Carvalho Chehab .eav2sav = 280 - 8, 159d24a170bSMauro Carvalho Chehab .sav2eav = 1920, 160d24a170bSMauro Carvalho Chehab .l1 = 1, 161d24a170bSMauro Carvalho Chehab .l3 = 21, 162d24a170bSMauro Carvalho Chehab .l5 = 561, 163d24a170bSMauro Carvalho Chehab .l7 = 563, 164d24a170bSMauro Carvalho Chehab .l9 = 584, 165d24a170bSMauro Carvalho Chehab .l11 = 1124, 166d24a170bSMauro Carvalho Chehab .vsize = 1125, 167d24a170bSMauro Carvalho Chehab .capture_format = 0, 168d24a170bSMauro Carvalho Chehab .vbi_supported = 0, 169d24a170bSMauro Carvalho Chehab .hd_sd = 1, 170d24a170bSMauro Carvalho Chehab .dv_timings = V4L2_DV_BT_CEA_1920X1080I60, 171d24a170bSMauro Carvalho Chehab }, 172d24a170bSMauro Carvalho Chehab { 173d24a170bSMauro Carvalho Chehab .name = "1080p60", 174d24a170bSMauro Carvalho Chehab .width = 1920, 175d24a170bSMauro Carvalho Chehab .height = 1080, 176d24a170bSMauro Carvalho Chehab .frm_fmt = 1, 177d24a170bSMauro Carvalho Chehab .ycmux_mode = 0, 178d24a170bSMauro Carvalho Chehab .eav2sav = 280 - 8, 179d24a170bSMauro Carvalho Chehab .sav2eav = 1920, 180d24a170bSMauro Carvalho Chehab .l1 = 1, 181d24a170bSMauro Carvalho Chehab .l3 = 42, 182d24a170bSMauro Carvalho Chehab .l5 = 1122, 183d24a170bSMauro Carvalho Chehab .vsize = 1125, 184d24a170bSMauro Carvalho Chehab .capture_format = 0, 185d24a170bSMauro Carvalho Chehab .vbi_supported = 0, 186d24a170bSMauro Carvalho Chehab .hd_sd = 1, 187d24a170bSMauro Carvalho Chehab .dv_timings = V4L2_DV_BT_CEA_1920X1080P60, 188d24a170bSMauro Carvalho Chehab }, 189d24a170bSMauro Carvalho Chehab 190d24a170bSMauro Carvalho Chehab /* SDTV formats */ 191d24a170bSMauro Carvalho Chehab { 192d24a170bSMauro Carvalho Chehab .name = "NTSC_M", 193d24a170bSMauro Carvalho Chehab .width = 720, 194d24a170bSMauro Carvalho Chehab .height = 480, 195d24a170bSMauro Carvalho Chehab .frm_fmt = 0, 196d24a170bSMauro Carvalho Chehab .ycmux_mode = 1, 197d24a170bSMauro Carvalho Chehab .eav2sav = 268, 198d24a170bSMauro Carvalho Chehab .sav2eav = 1440, 199d24a170bSMauro Carvalho Chehab .l1 = 1, 200d24a170bSMauro Carvalho Chehab .l3 = 23, 201d24a170bSMauro Carvalho Chehab .l5 = 263, 202d24a170bSMauro Carvalho Chehab .l7 = 266, 203d24a170bSMauro Carvalho Chehab .l9 = 286, 204d24a170bSMauro Carvalho Chehab .l11 = 525, 205d24a170bSMauro Carvalho Chehab .vsize = 525, 206d24a170bSMauro Carvalho Chehab .capture_format = 0, 207d24a170bSMauro Carvalho Chehab .vbi_supported = 1, 208d24a170bSMauro Carvalho Chehab .hd_sd = 0, 209d24a170bSMauro Carvalho Chehab .stdid = V4L2_STD_525_60, 210d24a170bSMauro Carvalho Chehab }, 211d24a170bSMauro Carvalho Chehab { 212d24a170bSMauro Carvalho Chehab .name = "PAL_BDGHIK", 213d24a170bSMauro Carvalho Chehab .width = 720, 214d24a170bSMauro Carvalho Chehab .height = 576, 215d24a170bSMauro Carvalho Chehab .frm_fmt = 0, 216d24a170bSMauro Carvalho Chehab .ycmux_mode = 1, 217d24a170bSMauro Carvalho Chehab .eav2sav = 280, 218d24a170bSMauro Carvalho Chehab .sav2eav = 1440, 219d24a170bSMauro Carvalho Chehab .l1 = 1, 220d24a170bSMauro Carvalho Chehab .l3 = 23, 221d24a170bSMauro Carvalho Chehab .l5 = 311, 222d24a170bSMauro Carvalho Chehab .l7 = 313, 223d24a170bSMauro Carvalho Chehab .l9 = 336, 224d24a170bSMauro Carvalho Chehab .l11 = 624, 225d24a170bSMauro Carvalho Chehab .vsize = 625, 226d24a170bSMauro Carvalho Chehab .capture_format = 0, 227d24a170bSMauro Carvalho Chehab .vbi_supported = 1, 228d24a170bSMauro Carvalho Chehab .hd_sd = 0, 229d24a170bSMauro Carvalho Chehab .stdid = V4L2_STD_625_50, 230d24a170bSMauro Carvalho Chehab }, 231d24a170bSMauro Carvalho Chehab }; 232d24a170bSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(vpif_ch_params); 233d24a170bSMauro Carvalho Chehab 234d24a170bSMauro Carvalho Chehab const unsigned int vpif_ch_params_count = ARRAY_SIZE(vpif_ch_params); 235d24a170bSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(vpif_ch_params_count); 236d24a170bSMauro Carvalho Chehab 237d24a170bSMauro Carvalho Chehab static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) 238d24a170bSMauro Carvalho Chehab { 239d24a170bSMauro Carvalho Chehab if (val) 240d24a170bSMauro Carvalho Chehab vpif_set_bit(reg, bit); 241d24a170bSMauro Carvalho Chehab else 242d24a170bSMauro Carvalho Chehab vpif_clr_bit(reg, bit); 243d24a170bSMauro Carvalho Chehab } 244d24a170bSMauro Carvalho Chehab 245d24a170bSMauro Carvalho Chehab /* This structure is used to keep track of VPIF size register's offsets */ 246d24a170bSMauro Carvalho Chehab struct vpif_registers { 247d24a170bSMauro Carvalho Chehab u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; 248d24a170bSMauro Carvalho Chehab u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; 249d24a170bSMauro Carvalho Chehab u32 vanc1_size, width_mask, len_mask; 250d24a170bSMauro Carvalho Chehab u8 max_modes; 251d24a170bSMauro Carvalho Chehab }; 252d24a170bSMauro Carvalho Chehab 253d24a170bSMauro Carvalho Chehab static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { 254d24a170bSMauro Carvalho Chehab /* Channel0 */ 255d24a170bSMauro Carvalho Chehab { 256d24a170bSMauro Carvalho Chehab VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, 257d24a170bSMauro Carvalho Chehab VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, 258d24a170bSMauro Carvalho Chehab VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, 259d24a170bSMauro Carvalho Chehab VPIF_CH0_MAX_MODES, 260d24a170bSMauro Carvalho Chehab }, 261d24a170bSMauro Carvalho Chehab /* Channel1 */ 262d24a170bSMauro Carvalho Chehab { 263d24a170bSMauro Carvalho Chehab VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, 264d24a170bSMauro Carvalho Chehab VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, 265d24a170bSMauro Carvalho Chehab VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, 266d24a170bSMauro Carvalho Chehab VPIF_CH1_MAX_MODES, 267d24a170bSMauro Carvalho Chehab }, 268d24a170bSMauro Carvalho Chehab /* Channel2 */ 269d24a170bSMauro Carvalho Chehab { 270d24a170bSMauro Carvalho Chehab VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, 271d24a170bSMauro Carvalho Chehab VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, 272d24a170bSMauro Carvalho Chehab VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, 273d24a170bSMauro Carvalho Chehab VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, 274d24a170bSMauro Carvalho Chehab VPIF_CH2_MAX_MODES 275d24a170bSMauro Carvalho Chehab }, 276d24a170bSMauro Carvalho Chehab /* Channel3 */ 277d24a170bSMauro Carvalho Chehab { 278d24a170bSMauro Carvalho Chehab VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, 279d24a170bSMauro Carvalho Chehab VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, 280d24a170bSMauro Carvalho Chehab VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, 281d24a170bSMauro Carvalho Chehab VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, 282d24a170bSMauro Carvalho Chehab VPIF_CH3_MAX_MODES 283d24a170bSMauro Carvalho Chehab }, 284d24a170bSMauro Carvalho Chehab }; 285d24a170bSMauro Carvalho Chehab 286d24a170bSMauro Carvalho Chehab /* vpif_set_mode_info: 287d24a170bSMauro Carvalho Chehab * This function is used to set horizontal and vertical config parameters 288d24a170bSMauro Carvalho Chehab * As per the standard in the channel, configure the values of L1, L3, 289d24a170bSMauro Carvalho Chehab * L5, L7 L9, L11 in VPIF Register , also write width and height 290d24a170bSMauro Carvalho Chehab */ 291d24a170bSMauro Carvalho Chehab static void vpif_set_mode_info(const struct vpif_channel_config_params *config, 292d24a170bSMauro Carvalho Chehab u8 channel_id, u8 config_channel_id) 293d24a170bSMauro Carvalho Chehab { 294d24a170bSMauro Carvalho Chehab u32 value; 295d24a170bSMauro Carvalho Chehab 296d24a170bSMauro Carvalho Chehab value = (config->eav2sav & vpifregs[config_channel_id].width_mask); 297d24a170bSMauro Carvalho Chehab value <<= VPIF_CH_LEN_SHIFT; 298d24a170bSMauro Carvalho Chehab value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); 299d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].h_cfg); 300d24a170bSMauro Carvalho Chehab 301d24a170bSMauro Carvalho Chehab value = (config->l1 & vpifregs[config_channel_id].len_mask); 302d24a170bSMauro Carvalho Chehab value <<= VPIF_CH_LEN_SHIFT; 303d24a170bSMauro Carvalho Chehab value |= (config->l3 & vpifregs[config_channel_id].len_mask); 304d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].v_cfg_00); 305d24a170bSMauro Carvalho Chehab 306d24a170bSMauro Carvalho Chehab value = (config->l5 & vpifregs[config_channel_id].len_mask); 307d24a170bSMauro Carvalho Chehab value <<= VPIF_CH_LEN_SHIFT; 308d24a170bSMauro Carvalho Chehab value |= (config->l7 & vpifregs[config_channel_id].len_mask); 309d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].v_cfg_01); 310d24a170bSMauro Carvalho Chehab 311d24a170bSMauro Carvalho Chehab value = (config->l9 & vpifregs[config_channel_id].len_mask); 312d24a170bSMauro Carvalho Chehab value <<= VPIF_CH_LEN_SHIFT; 313d24a170bSMauro Carvalho Chehab value |= (config->l11 & vpifregs[config_channel_id].len_mask); 314d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].v_cfg_02); 315d24a170bSMauro Carvalho Chehab 316d24a170bSMauro Carvalho Chehab value = (config->vsize & vpifregs[config_channel_id].len_mask); 317d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].v_cfg); 318d24a170bSMauro Carvalho Chehab } 319d24a170bSMauro Carvalho Chehab 320d24a170bSMauro Carvalho Chehab /* config_vpif_params 321d24a170bSMauro Carvalho Chehab * Function to set the parameters of a channel 322d24a170bSMauro Carvalho Chehab * Mainly modifies the channel ciontrol register 323d24a170bSMauro Carvalho Chehab * It sets frame format, yc mux mode 324d24a170bSMauro Carvalho Chehab */ 325d24a170bSMauro Carvalho Chehab static void config_vpif_params(struct vpif_params *vpifparams, 326d24a170bSMauro Carvalho Chehab u8 channel_id, u8 found) 327d24a170bSMauro Carvalho Chehab { 328d24a170bSMauro Carvalho Chehab const struct vpif_channel_config_params *config = &vpifparams->std_info; 329d24a170bSMauro Carvalho Chehab u32 value, ch_nip, reg; 330d24a170bSMauro Carvalho Chehab u8 start, end; 331d24a170bSMauro Carvalho Chehab int i; 332d24a170bSMauro Carvalho Chehab 333d24a170bSMauro Carvalho Chehab start = channel_id; 334d24a170bSMauro Carvalho Chehab end = channel_id + found; 335d24a170bSMauro Carvalho Chehab 336d24a170bSMauro Carvalho Chehab for (i = start; i < end; i++) { 337d24a170bSMauro Carvalho Chehab reg = vpifregs[i].ch_ctrl; 338d24a170bSMauro Carvalho Chehab if (channel_id < 2) 339d24a170bSMauro Carvalho Chehab ch_nip = VPIF_CAPTURE_CH_NIP; 340d24a170bSMauro Carvalho Chehab else 341d24a170bSMauro Carvalho Chehab ch_nip = VPIF_DISPLAY_CH_NIP; 342d24a170bSMauro Carvalho Chehab 343d24a170bSMauro Carvalho Chehab vpif_wr_bit(reg, ch_nip, config->frm_fmt); 344d24a170bSMauro Carvalho Chehab vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); 345d24a170bSMauro Carvalho Chehab vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, 346d24a170bSMauro Carvalho Chehab vpifparams->video_params.storage_mode); 347d24a170bSMauro Carvalho Chehab 348d24a170bSMauro Carvalho Chehab /* Set raster scanning SDR Format */ 349d24a170bSMauro Carvalho Chehab vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); 350d24a170bSMauro Carvalho Chehab vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); 351d24a170bSMauro Carvalho Chehab 352d24a170bSMauro Carvalho Chehab if (channel_id > 1) /* Set the Pixel enable bit */ 353d24a170bSMauro Carvalho Chehab vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); 354d24a170bSMauro Carvalho Chehab else if (config->capture_format) { 355d24a170bSMauro Carvalho Chehab /* Set the polarity of various pins */ 356d24a170bSMauro Carvalho Chehab vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, 357d24a170bSMauro Carvalho Chehab vpifparams->iface.fid_pol); 358d24a170bSMauro Carvalho Chehab vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, 359d24a170bSMauro Carvalho Chehab vpifparams->iface.vd_pol); 360d24a170bSMauro Carvalho Chehab vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, 361d24a170bSMauro Carvalho Chehab vpifparams->iface.hd_pol); 362d24a170bSMauro Carvalho Chehab 363d24a170bSMauro Carvalho Chehab value = regr(reg); 364d24a170bSMauro Carvalho Chehab /* Set data width */ 365d24a170bSMauro Carvalho Chehab value &= ~(0x3u << 366d24a170bSMauro Carvalho Chehab VPIF_CH_DATA_WIDTH_BIT); 367d24a170bSMauro Carvalho Chehab value |= ((vpifparams->params.data_sz) << 368d24a170bSMauro Carvalho Chehab VPIF_CH_DATA_WIDTH_BIT); 369d24a170bSMauro Carvalho Chehab regw(value, reg); 370d24a170bSMauro Carvalho Chehab } 371d24a170bSMauro Carvalho Chehab 372d24a170bSMauro Carvalho Chehab /* Write the pitch in the driver */ 373d24a170bSMauro Carvalho Chehab regw((vpifparams->video_params.hpitch), 374d24a170bSMauro Carvalho Chehab vpifregs[i].line_offset); 375d24a170bSMauro Carvalho Chehab } 376d24a170bSMauro Carvalho Chehab } 377d24a170bSMauro Carvalho Chehab 378d24a170bSMauro Carvalho Chehab /* vpif_set_video_params 379d24a170bSMauro Carvalho Chehab * This function is used to set video parameters in VPIF register 380d24a170bSMauro Carvalho Chehab */ 381d24a170bSMauro Carvalho Chehab int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) 382d24a170bSMauro Carvalho Chehab { 383d24a170bSMauro Carvalho Chehab const struct vpif_channel_config_params *config = &vpifparams->std_info; 384d24a170bSMauro Carvalho Chehab int found = 1; 385d24a170bSMauro Carvalho Chehab 386d24a170bSMauro Carvalho Chehab vpif_set_mode_info(config, channel_id, channel_id); 387d24a170bSMauro Carvalho Chehab if (!config->ycmux_mode) { 388d24a170bSMauro Carvalho Chehab /* YC are on separate channels (HDTV formats) */ 389d24a170bSMauro Carvalho Chehab vpif_set_mode_info(config, channel_id + 1, channel_id); 390d24a170bSMauro Carvalho Chehab found = 2; 391d24a170bSMauro Carvalho Chehab } 392d24a170bSMauro Carvalho Chehab 393d24a170bSMauro Carvalho Chehab config_vpif_params(vpifparams, channel_id, found); 394d24a170bSMauro Carvalho Chehab 395d24a170bSMauro Carvalho Chehab regw(0x80, VPIF_REQ_SIZE); 396d24a170bSMauro Carvalho Chehab regw(0x01, VPIF_EMULATION_CTRL); 397d24a170bSMauro Carvalho Chehab 398d24a170bSMauro Carvalho Chehab return found; 399d24a170bSMauro Carvalho Chehab } 400d24a170bSMauro Carvalho Chehab EXPORT_SYMBOL(vpif_set_video_params); 401d24a170bSMauro Carvalho Chehab 402d24a170bSMauro Carvalho Chehab void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, 403d24a170bSMauro Carvalho Chehab u8 channel_id) 404d24a170bSMauro Carvalho Chehab { 405d24a170bSMauro Carvalho Chehab u32 value; 406d24a170bSMauro Carvalho Chehab 407d24a170bSMauro Carvalho Chehab value = 0x3F8 & (vbiparams->hstart0); 408d24a170bSMauro Carvalho Chehab value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); 409d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].vanc0_strt); 410d24a170bSMauro Carvalho Chehab 411d24a170bSMauro Carvalho Chehab value = 0x3F8 & (vbiparams->hstart1); 412d24a170bSMauro Carvalho Chehab value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); 413d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].vanc1_strt); 414d24a170bSMauro Carvalho Chehab 415d24a170bSMauro Carvalho Chehab value = 0x3F8 & (vbiparams->hsize0); 416d24a170bSMauro Carvalho Chehab value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); 417d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].vanc0_size); 418d24a170bSMauro Carvalho Chehab 419d24a170bSMauro Carvalho Chehab value = 0x3F8 & (vbiparams->hsize1); 420d24a170bSMauro Carvalho Chehab value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); 421d24a170bSMauro Carvalho Chehab regw(value, vpifregs[channel_id].vanc1_size); 422d24a170bSMauro Carvalho Chehab 423d24a170bSMauro Carvalho Chehab } 424d24a170bSMauro Carvalho Chehab EXPORT_SYMBOL(vpif_set_vbi_display_params); 425d24a170bSMauro Carvalho Chehab 426d24a170bSMauro Carvalho Chehab int vpif_channel_getfid(u8 channel_id) 427d24a170bSMauro Carvalho Chehab { 428d24a170bSMauro Carvalho Chehab return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) 429d24a170bSMauro Carvalho Chehab >> VPIF_CH_FID_SHIFT; 430d24a170bSMauro Carvalho Chehab } 431d24a170bSMauro Carvalho Chehab EXPORT_SYMBOL(vpif_channel_getfid); 432d24a170bSMauro Carvalho Chehab 433d24a170bSMauro Carvalho Chehab static void vpif_pdev_release(struct device *dev) 434d24a170bSMauro Carvalho Chehab { 435d24a170bSMauro Carvalho Chehab struct platform_device *pdev = to_platform_device(dev); 436d24a170bSMauro Carvalho Chehab 437d24a170bSMauro Carvalho Chehab kfree(pdev); 438d24a170bSMauro Carvalho Chehab } 439d24a170bSMauro Carvalho Chehab 440d24a170bSMauro Carvalho Chehab static int vpif_probe(struct platform_device *pdev) 441d24a170bSMauro Carvalho Chehab { 442d24a170bSMauro Carvalho Chehab static struct resource res_irq; 443d24a170bSMauro Carvalho Chehab struct platform_device *pdev_capture, *pdev_display; 444d24a170bSMauro Carvalho Chehab struct device_node *endpoint = NULL; 445d24a170bSMauro Carvalho Chehab struct vpif_data *data; 446d24a170bSMauro Carvalho Chehab int ret; 447d24a170bSMauro Carvalho Chehab int irq; 448d24a170bSMauro Carvalho Chehab 449d24a170bSMauro Carvalho Chehab vpif_base = devm_platform_ioremap_resource(pdev, 0); 450d24a170bSMauro Carvalho Chehab if (IS_ERR(vpif_base)) 451d24a170bSMauro Carvalho Chehab return PTR_ERR(vpif_base); 452d24a170bSMauro Carvalho Chehab 453d24a170bSMauro Carvalho Chehab data = kzalloc(sizeof(*data), GFP_KERNEL); 454d24a170bSMauro Carvalho Chehab if (!data) 455d24a170bSMauro Carvalho Chehab return -ENOMEM; 456d24a170bSMauro Carvalho Chehab 457d24a170bSMauro Carvalho Chehab platform_set_drvdata(pdev, data); 458d24a170bSMauro Carvalho Chehab 459d24a170bSMauro Carvalho Chehab pm_runtime_enable(&pdev->dev); 460d24a170bSMauro Carvalho Chehab pm_runtime_get(&pdev->dev); 461d24a170bSMauro Carvalho Chehab 462d24a170bSMauro Carvalho Chehab /* 463d24a170bSMauro Carvalho Chehab * If VPIF Node has endpoints, assume "new" DT support, 464d24a170bSMauro Carvalho Chehab * where capture and display drivers don't have DT nodes 465d24a170bSMauro Carvalho Chehab * so their devices need to be registered manually here 466d24a170bSMauro Carvalho Chehab * for their legacy platform_drivers to work. 467d24a170bSMauro Carvalho Chehab */ 468d24a170bSMauro Carvalho Chehab endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, 469d24a170bSMauro Carvalho Chehab endpoint); 470d24a170bSMauro Carvalho Chehab if (!endpoint) 471d24a170bSMauro Carvalho Chehab return 0; 472bb45f543SYang Yingliang of_node_put(endpoint); 473d24a170bSMauro Carvalho Chehab 474d24a170bSMauro Carvalho Chehab /* 475d24a170bSMauro Carvalho Chehab * For DT platforms, manually create platform_devices for 476d24a170bSMauro Carvalho Chehab * capture/display drivers. 477d24a170bSMauro Carvalho Chehab */ 478d24a170bSMauro Carvalho Chehab irq = platform_get_irq(pdev, 0); 479d24a170bSMauro Carvalho Chehab if (irq < 0) { 480d24a170bSMauro Carvalho Chehab ret = irq; 481d24a170bSMauro Carvalho Chehab goto err_put_rpm; 482d24a170bSMauro Carvalho Chehab } 483*9996b965SHans Verkuil res_irq = DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node)); 484d24a170bSMauro Carvalho Chehab res_irq.flags |= irq_get_trigger_type(irq); 485d24a170bSMauro Carvalho Chehab 486d24a170bSMauro Carvalho Chehab pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL); 487d24a170bSMauro Carvalho Chehab if (!pdev_capture) { 488d24a170bSMauro Carvalho Chehab ret = -ENOMEM; 489d24a170bSMauro Carvalho Chehab goto err_put_rpm; 490d24a170bSMauro Carvalho Chehab } 491d24a170bSMauro Carvalho Chehab 492d24a170bSMauro Carvalho Chehab pdev_capture->name = "vpif_capture"; 493d24a170bSMauro Carvalho Chehab pdev_capture->id = -1; 494d24a170bSMauro Carvalho Chehab pdev_capture->resource = &res_irq; 495d24a170bSMauro Carvalho Chehab pdev_capture->num_resources = 1; 496d24a170bSMauro Carvalho Chehab pdev_capture->dev.dma_mask = pdev->dev.dma_mask; 497d24a170bSMauro Carvalho Chehab pdev_capture->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; 498d24a170bSMauro Carvalho Chehab pdev_capture->dev.parent = &pdev->dev; 499d24a170bSMauro Carvalho Chehab pdev_capture->dev.release = vpif_pdev_release; 500d24a170bSMauro Carvalho Chehab 501d24a170bSMauro Carvalho Chehab ret = platform_device_register(pdev_capture); 502d24a170bSMauro Carvalho Chehab if (ret) 503d24a170bSMauro Carvalho Chehab goto err_put_pdev_capture; 504d24a170bSMauro Carvalho Chehab 505d24a170bSMauro Carvalho Chehab pdev_display = kzalloc(sizeof(*pdev_display), GFP_KERNEL); 506d24a170bSMauro Carvalho Chehab if (!pdev_display) { 507d24a170bSMauro Carvalho Chehab ret = -ENOMEM; 508d24a170bSMauro Carvalho Chehab goto err_put_pdev_capture; 509d24a170bSMauro Carvalho Chehab } 510d24a170bSMauro Carvalho Chehab 511d24a170bSMauro Carvalho Chehab pdev_display->name = "vpif_display"; 512d24a170bSMauro Carvalho Chehab pdev_display->id = -1; 513d24a170bSMauro Carvalho Chehab pdev_display->resource = &res_irq; 514d24a170bSMauro Carvalho Chehab pdev_display->num_resources = 1; 515d24a170bSMauro Carvalho Chehab pdev_display->dev.dma_mask = pdev->dev.dma_mask; 516d24a170bSMauro Carvalho Chehab pdev_display->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; 517d24a170bSMauro Carvalho Chehab pdev_display->dev.parent = &pdev->dev; 518d24a170bSMauro Carvalho Chehab pdev_display->dev.release = vpif_pdev_release; 519d24a170bSMauro Carvalho Chehab 520d24a170bSMauro Carvalho Chehab ret = platform_device_register(pdev_display); 521d24a170bSMauro Carvalho Chehab if (ret) 522d24a170bSMauro Carvalho Chehab goto err_put_pdev_display; 523d24a170bSMauro Carvalho Chehab 524d24a170bSMauro Carvalho Chehab data->capture = pdev_capture; 525d24a170bSMauro Carvalho Chehab data->display = pdev_display; 526d24a170bSMauro Carvalho Chehab 527d24a170bSMauro Carvalho Chehab return 0; 528d24a170bSMauro Carvalho Chehab 529d24a170bSMauro Carvalho Chehab err_put_pdev_display: 530d24a170bSMauro Carvalho Chehab platform_device_put(pdev_display); 531d24a170bSMauro Carvalho Chehab err_put_pdev_capture: 532d24a170bSMauro Carvalho Chehab platform_device_put(pdev_capture); 533d24a170bSMauro Carvalho Chehab err_put_rpm: 534d24a170bSMauro Carvalho Chehab pm_runtime_put(&pdev->dev); 535d24a170bSMauro Carvalho Chehab pm_runtime_disable(&pdev->dev); 536d24a170bSMauro Carvalho Chehab kfree(data); 537d24a170bSMauro Carvalho Chehab 538d24a170bSMauro Carvalho Chehab return ret; 539d24a170bSMauro Carvalho Chehab } 540d24a170bSMauro Carvalho Chehab 541d24a170bSMauro Carvalho Chehab static int vpif_remove(struct platform_device *pdev) 542d24a170bSMauro Carvalho Chehab { 543d24a170bSMauro Carvalho Chehab struct vpif_data *data = platform_get_drvdata(pdev); 544d24a170bSMauro Carvalho Chehab 545d24a170bSMauro Carvalho Chehab if (data->capture) 546d24a170bSMauro Carvalho Chehab platform_device_unregister(data->capture); 547d24a170bSMauro Carvalho Chehab if (data->display) 548d24a170bSMauro Carvalho Chehab platform_device_unregister(data->display); 549d24a170bSMauro Carvalho Chehab 550d24a170bSMauro Carvalho Chehab pm_runtime_put(&pdev->dev); 551d24a170bSMauro Carvalho Chehab pm_runtime_disable(&pdev->dev); 552d24a170bSMauro Carvalho Chehab 553d24a170bSMauro Carvalho Chehab kfree(data); 554d24a170bSMauro Carvalho Chehab 555d24a170bSMauro Carvalho Chehab return 0; 556d24a170bSMauro Carvalho Chehab } 557d24a170bSMauro Carvalho Chehab 558d24a170bSMauro Carvalho Chehab #ifdef CONFIG_PM 559d24a170bSMauro Carvalho Chehab static int vpif_suspend(struct device *dev) 560d24a170bSMauro Carvalho Chehab { 561d24a170bSMauro Carvalho Chehab pm_runtime_put(dev); 562d24a170bSMauro Carvalho Chehab return 0; 563d24a170bSMauro Carvalho Chehab } 564d24a170bSMauro Carvalho Chehab 565d24a170bSMauro Carvalho Chehab static int vpif_resume(struct device *dev) 566d24a170bSMauro Carvalho Chehab { 567d24a170bSMauro Carvalho Chehab pm_runtime_get(dev); 568d24a170bSMauro Carvalho Chehab return 0; 569d24a170bSMauro Carvalho Chehab } 570d24a170bSMauro Carvalho Chehab 571d24a170bSMauro Carvalho Chehab static const struct dev_pm_ops vpif_pm = { 572d24a170bSMauro Carvalho Chehab .suspend = vpif_suspend, 573d24a170bSMauro Carvalho Chehab .resume = vpif_resume, 574d24a170bSMauro Carvalho Chehab }; 575d24a170bSMauro Carvalho Chehab 576d24a170bSMauro Carvalho Chehab #define vpif_pm_ops (&vpif_pm) 577d24a170bSMauro Carvalho Chehab #else 578d24a170bSMauro Carvalho Chehab #define vpif_pm_ops NULL 579d24a170bSMauro Carvalho Chehab #endif 580d24a170bSMauro Carvalho Chehab 581d24a170bSMauro Carvalho Chehab #if IS_ENABLED(CONFIG_OF) 582d24a170bSMauro Carvalho Chehab static const struct of_device_id vpif_of_match[] = { 583d24a170bSMauro Carvalho Chehab { .compatible = "ti,da850-vpif", }, 584d24a170bSMauro Carvalho Chehab { /* sentinel */ }, 585d24a170bSMauro Carvalho Chehab }; 586d24a170bSMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, vpif_of_match); 587d24a170bSMauro Carvalho Chehab #endif 588d24a170bSMauro Carvalho Chehab 589d24a170bSMauro Carvalho Chehab static struct platform_driver vpif_driver = { 590d24a170bSMauro Carvalho Chehab .driver = { 591d24a170bSMauro Carvalho Chehab .of_match_table = of_match_ptr(vpif_of_match), 592d24a170bSMauro Carvalho Chehab .name = VPIF_DRIVER_NAME, 593d24a170bSMauro Carvalho Chehab .pm = vpif_pm_ops, 594d24a170bSMauro Carvalho Chehab }, 595d24a170bSMauro Carvalho Chehab .remove = vpif_remove, 596d24a170bSMauro Carvalho Chehab .probe = vpif_probe, 597d24a170bSMauro Carvalho Chehab }; 598d24a170bSMauro Carvalho Chehab 599d24a170bSMauro Carvalho Chehab static void vpif_exit(void) 600d24a170bSMauro Carvalho Chehab { 601d24a170bSMauro Carvalho Chehab platform_driver_unregister(&vpif_driver); 602d24a170bSMauro Carvalho Chehab } 603d24a170bSMauro Carvalho Chehab 604d24a170bSMauro Carvalho Chehab static int __init vpif_init(void) 605d24a170bSMauro Carvalho Chehab { 606d24a170bSMauro Carvalho Chehab return platform_driver_register(&vpif_driver); 607d24a170bSMauro Carvalho Chehab } 608d24a170bSMauro Carvalho Chehab subsys_initcall(vpif_init); 609d24a170bSMauro Carvalho Chehab module_exit(vpif_exit); 610d24a170bSMauro Carvalho Chehab 611