162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * vpif - Video Port Interface driver 362306a36Sopenharmony_ci * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) 462306a36Sopenharmony_ci * that receiving video byte stream and two channels(2, 3) for video output. 562306a36Sopenharmony_ci * The hardware supports SDTV, HDTV formats, raw data capture. 662306a36Sopenharmony_ci * Currently, the driver supports NTSC and PAL standards. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 1162306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License as 1262306a36Sopenharmony_ci * published by the Free Software Foundation version 2. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This program is distributed .as is. WITHOUT ANY WARRANTY of any 1562306a36Sopenharmony_ci * kind, whether express or implied; without even the implied warranty 1662306a36Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1762306a36Sopenharmony_ci * GNU General Public License for more details. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/err.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/io.h> 2362306a36Sopenharmony_ci#include <linux/irq.h> 2462306a36Sopenharmony_ci#include <linux/kernel.h> 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/of.h> 2762306a36Sopenharmony_ci#include <linux/platform_device.h> 2862306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2962306a36Sopenharmony_ci#include <linux/spinlock.h> 3062306a36Sopenharmony_ci#include <linux/v4l2-dv-timings.h> 3162306a36Sopenharmony_ci#include <linux/of_graph.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "vpif.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciMODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); 3662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define VPIF_DRIVER_NAME "vpif" 3962306a36Sopenharmony_ciMODULE_ALIAS("platform:" VPIF_DRIVER_NAME); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define VPIF_CH0_MAX_MODES 22 4262306a36Sopenharmony_ci#define VPIF_CH1_MAX_MODES 2 4362306a36Sopenharmony_ci#define VPIF_CH2_MAX_MODES 15 4462306a36Sopenharmony_ci#define VPIF_CH3_MAX_MODES 2 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct vpif_data { 4762306a36Sopenharmony_ci struct platform_device *capture; 4862306a36Sopenharmony_ci struct platform_device *display; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciDEFINE_SPINLOCK(vpif_lock); 5262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vpif_lock); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_civoid __iomem *vpif_base; 5562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vpif_base); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * vpif_ch_params: video standard configuration parameters for vpif 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * The table must include all presets from supported subdevices. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ciconst struct vpif_channel_config_params vpif_ch_params[] = { 6362306a36Sopenharmony_ci /* HDTV formats */ 6462306a36Sopenharmony_ci { 6562306a36Sopenharmony_ci .name = "480p59_94", 6662306a36Sopenharmony_ci .width = 720, 6762306a36Sopenharmony_ci .height = 480, 6862306a36Sopenharmony_ci .frm_fmt = 1, 6962306a36Sopenharmony_ci .ycmux_mode = 0, 7062306a36Sopenharmony_ci .eav2sav = 138-8, 7162306a36Sopenharmony_ci .sav2eav = 720, 7262306a36Sopenharmony_ci .l1 = 1, 7362306a36Sopenharmony_ci .l3 = 43, 7462306a36Sopenharmony_ci .l5 = 523, 7562306a36Sopenharmony_ci .vsize = 525, 7662306a36Sopenharmony_ci .capture_format = 0, 7762306a36Sopenharmony_ci .vbi_supported = 0, 7862306a36Sopenharmony_ci .hd_sd = 1, 7962306a36Sopenharmony_ci .dv_timings = V4L2_DV_BT_CEA_720X480P59_94, 8062306a36Sopenharmony_ci }, 8162306a36Sopenharmony_ci { 8262306a36Sopenharmony_ci .name = "576p50", 8362306a36Sopenharmony_ci .width = 720, 8462306a36Sopenharmony_ci .height = 576, 8562306a36Sopenharmony_ci .frm_fmt = 1, 8662306a36Sopenharmony_ci .ycmux_mode = 0, 8762306a36Sopenharmony_ci .eav2sav = 144-8, 8862306a36Sopenharmony_ci .sav2eav = 720, 8962306a36Sopenharmony_ci .l1 = 1, 9062306a36Sopenharmony_ci .l3 = 45, 9162306a36Sopenharmony_ci .l5 = 621, 9262306a36Sopenharmony_ci .vsize = 625, 9362306a36Sopenharmony_ci .capture_format = 0, 9462306a36Sopenharmony_ci .vbi_supported = 0, 9562306a36Sopenharmony_ci .hd_sd = 1, 9662306a36Sopenharmony_ci .dv_timings = V4L2_DV_BT_CEA_720X576P50, 9762306a36Sopenharmony_ci }, 9862306a36Sopenharmony_ci { 9962306a36Sopenharmony_ci .name = "720p50", 10062306a36Sopenharmony_ci .width = 1280, 10162306a36Sopenharmony_ci .height = 720, 10262306a36Sopenharmony_ci .frm_fmt = 1, 10362306a36Sopenharmony_ci .ycmux_mode = 0, 10462306a36Sopenharmony_ci .eav2sav = 700-8, 10562306a36Sopenharmony_ci .sav2eav = 1280, 10662306a36Sopenharmony_ci .l1 = 1, 10762306a36Sopenharmony_ci .l3 = 26, 10862306a36Sopenharmony_ci .l5 = 746, 10962306a36Sopenharmony_ci .vsize = 750, 11062306a36Sopenharmony_ci .capture_format = 0, 11162306a36Sopenharmony_ci .vbi_supported = 0, 11262306a36Sopenharmony_ci .hd_sd = 1, 11362306a36Sopenharmony_ci .dv_timings = V4L2_DV_BT_CEA_1280X720P50, 11462306a36Sopenharmony_ci }, 11562306a36Sopenharmony_ci { 11662306a36Sopenharmony_ci .name = "720p60", 11762306a36Sopenharmony_ci .width = 1280, 11862306a36Sopenharmony_ci .height = 720, 11962306a36Sopenharmony_ci .frm_fmt = 1, 12062306a36Sopenharmony_ci .ycmux_mode = 0, 12162306a36Sopenharmony_ci .eav2sav = 370 - 8, 12262306a36Sopenharmony_ci .sav2eav = 1280, 12362306a36Sopenharmony_ci .l1 = 1, 12462306a36Sopenharmony_ci .l3 = 26, 12562306a36Sopenharmony_ci .l5 = 746, 12662306a36Sopenharmony_ci .vsize = 750, 12762306a36Sopenharmony_ci .capture_format = 0, 12862306a36Sopenharmony_ci .vbi_supported = 0, 12962306a36Sopenharmony_ci .hd_sd = 1, 13062306a36Sopenharmony_ci .dv_timings = V4L2_DV_BT_CEA_1280X720P60, 13162306a36Sopenharmony_ci }, 13262306a36Sopenharmony_ci { 13362306a36Sopenharmony_ci .name = "1080I50", 13462306a36Sopenharmony_ci .width = 1920, 13562306a36Sopenharmony_ci .height = 1080, 13662306a36Sopenharmony_ci .frm_fmt = 0, 13762306a36Sopenharmony_ci .ycmux_mode = 0, 13862306a36Sopenharmony_ci .eav2sav = 720 - 8, 13962306a36Sopenharmony_ci .sav2eav = 1920, 14062306a36Sopenharmony_ci .l1 = 1, 14162306a36Sopenharmony_ci .l3 = 21, 14262306a36Sopenharmony_ci .l5 = 561, 14362306a36Sopenharmony_ci .l7 = 563, 14462306a36Sopenharmony_ci .l9 = 584, 14562306a36Sopenharmony_ci .l11 = 1124, 14662306a36Sopenharmony_ci .vsize = 1125, 14762306a36Sopenharmony_ci .capture_format = 0, 14862306a36Sopenharmony_ci .vbi_supported = 0, 14962306a36Sopenharmony_ci .hd_sd = 1, 15062306a36Sopenharmony_ci .dv_timings = V4L2_DV_BT_CEA_1920X1080I50, 15162306a36Sopenharmony_ci }, 15262306a36Sopenharmony_ci { 15362306a36Sopenharmony_ci .name = "1080I60", 15462306a36Sopenharmony_ci .width = 1920, 15562306a36Sopenharmony_ci .height = 1080, 15662306a36Sopenharmony_ci .frm_fmt = 0, 15762306a36Sopenharmony_ci .ycmux_mode = 0, 15862306a36Sopenharmony_ci .eav2sav = 280 - 8, 15962306a36Sopenharmony_ci .sav2eav = 1920, 16062306a36Sopenharmony_ci .l1 = 1, 16162306a36Sopenharmony_ci .l3 = 21, 16262306a36Sopenharmony_ci .l5 = 561, 16362306a36Sopenharmony_ci .l7 = 563, 16462306a36Sopenharmony_ci .l9 = 584, 16562306a36Sopenharmony_ci .l11 = 1124, 16662306a36Sopenharmony_ci .vsize = 1125, 16762306a36Sopenharmony_ci .capture_format = 0, 16862306a36Sopenharmony_ci .vbi_supported = 0, 16962306a36Sopenharmony_ci .hd_sd = 1, 17062306a36Sopenharmony_ci .dv_timings = V4L2_DV_BT_CEA_1920X1080I60, 17162306a36Sopenharmony_ci }, 17262306a36Sopenharmony_ci { 17362306a36Sopenharmony_ci .name = "1080p60", 17462306a36Sopenharmony_ci .width = 1920, 17562306a36Sopenharmony_ci .height = 1080, 17662306a36Sopenharmony_ci .frm_fmt = 1, 17762306a36Sopenharmony_ci .ycmux_mode = 0, 17862306a36Sopenharmony_ci .eav2sav = 280 - 8, 17962306a36Sopenharmony_ci .sav2eav = 1920, 18062306a36Sopenharmony_ci .l1 = 1, 18162306a36Sopenharmony_ci .l3 = 42, 18262306a36Sopenharmony_ci .l5 = 1122, 18362306a36Sopenharmony_ci .vsize = 1125, 18462306a36Sopenharmony_ci .capture_format = 0, 18562306a36Sopenharmony_ci .vbi_supported = 0, 18662306a36Sopenharmony_ci .hd_sd = 1, 18762306a36Sopenharmony_ci .dv_timings = V4L2_DV_BT_CEA_1920X1080P60, 18862306a36Sopenharmony_ci }, 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* SDTV formats */ 19162306a36Sopenharmony_ci { 19262306a36Sopenharmony_ci .name = "NTSC_M", 19362306a36Sopenharmony_ci .width = 720, 19462306a36Sopenharmony_ci .height = 480, 19562306a36Sopenharmony_ci .frm_fmt = 0, 19662306a36Sopenharmony_ci .ycmux_mode = 1, 19762306a36Sopenharmony_ci .eav2sav = 268, 19862306a36Sopenharmony_ci .sav2eav = 1440, 19962306a36Sopenharmony_ci .l1 = 1, 20062306a36Sopenharmony_ci .l3 = 23, 20162306a36Sopenharmony_ci .l5 = 263, 20262306a36Sopenharmony_ci .l7 = 266, 20362306a36Sopenharmony_ci .l9 = 286, 20462306a36Sopenharmony_ci .l11 = 525, 20562306a36Sopenharmony_ci .vsize = 525, 20662306a36Sopenharmony_ci .capture_format = 0, 20762306a36Sopenharmony_ci .vbi_supported = 1, 20862306a36Sopenharmony_ci .hd_sd = 0, 20962306a36Sopenharmony_ci .stdid = V4L2_STD_525_60, 21062306a36Sopenharmony_ci }, 21162306a36Sopenharmony_ci { 21262306a36Sopenharmony_ci .name = "PAL_BDGHIK", 21362306a36Sopenharmony_ci .width = 720, 21462306a36Sopenharmony_ci .height = 576, 21562306a36Sopenharmony_ci .frm_fmt = 0, 21662306a36Sopenharmony_ci .ycmux_mode = 1, 21762306a36Sopenharmony_ci .eav2sav = 280, 21862306a36Sopenharmony_ci .sav2eav = 1440, 21962306a36Sopenharmony_ci .l1 = 1, 22062306a36Sopenharmony_ci .l3 = 23, 22162306a36Sopenharmony_ci .l5 = 311, 22262306a36Sopenharmony_ci .l7 = 313, 22362306a36Sopenharmony_ci .l9 = 336, 22462306a36Sopenharmony_ci .l11 = 624, 22562306a36Sopenharmony_ci .vsize = 625, 22662306a36Sopenharmony_ci .capture_format = 0, 22762306a36Sopenharmony_ci .vbi_supported = 1, 22862306a36Sopenharmony_ci .hd_sd = 0, 22962306a36Sopenharmony_ci .stdid = V4L2_STD_625_50, 23062306a36Sopenharmony_ci }, 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vpif_ch_params); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciconst unsigned int vpif_ch_params_count = ARRAY_SIZE(vpif_ch_params); 23562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vpif_ch_params_count); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci if (val) 24062306a36Sopenharmony_ci vpif_set_bit(reg, bit); 24162306a36Sopenharmony_ci else 24262306a36Sopenharmony_ci vpif_clr_bit(reg, bit); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* This structure is used to keep track of VPIF size register's offsets */ 24662306a36Sopenharmony_cistruct vpif_registers { 24762306a36Sopenharmony_ci u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; 24862306a36Sopenharmony_ci u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; 24962306a36Sopenharmony_ci u32 vanc1_size, width_mask, len_mask; 25062306a36Sopenharmony_ci u8 max_modes; 25162306a36Sopenharmony_ci}; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { 25462306a36Sopenharmony_ci /* Channel0 */ 25562306a36Sopenharmony_ci { 25662306a36Sopenharmony_ci VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, 25762306a36Sopenharmony_ci VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, 25862306a36Sopenharmony_ci VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, 25962306a36Sopenharmony_ci VPIF_CH0_MAX_MODES, 26062306a36Sopenharmony_ci }, 26162306a36Sopenharmony_ci /* Channel1 */ 26262306a36Sopenharmony_ci { 26362306a36Sopenharmony_ci VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, 26462306a36Sopenharmony_ci VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, 26562306a36Sopenharmony_ci VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, 26662306a36Sopenharmony_ci VPIF_CH1_MAX_MODES, 26762306a36Sopenharmony_ci }, 26862306a36Sopenharmony_ci /* Channel2 */ 26962306a36Sopenharmony_ci { 27062306a36Sopenharmony_ci VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, 27162306a36Sopenharmony_ci VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, 27262306a36Sopenharmony_ci VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, 27362306a36Sopenharmony_ci VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, 27462306a36Sopenharmony_ci VPIF_CH2_MAX_MODES 27562306a36Sopenharmony_ci }, 27662306a36Sopenharmony_ci /* Channel3 */ 27762306a36Sopenharmony_ci { 27862306a36Sopenharmony_ci VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, 27962306a36Sopenharmony_ci VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, 28062306a36Sopenharmony_ci VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, 28162306a36Sopenharmony_ci VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, 28262306a36Sopenharmony_ci VPIF_CH3_MAX_MODES 28362306a36Sopenharmony_ci }, 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* vpif_set_mode_info: 28762306a36Sopenharmony_ci * This function is used to set horizontal and vertical config parameters 28862306a36Sopenharmony_ci * As per the standard in the channel, configure the values of L1, L3, 28962306a36Sopenharmony_ci * L5, L7 L9, L11 in VPIF Register , also write width and height 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_cistatic void vpif_set_mode_info(const struct vpif_channel_config_params *config, 29262306a36Sopenharmony_ci u8 channel_id, u8 config_channel_id) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci u32 value; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci value = (config->eav2sav & vpifregs[config_channel_id].width_mask); 29762306a36Sopenharmony_ci value <<= VPIF_CH_LEN_SHIFT; 29862306a36Sopenharmony_ci value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); 29962306a36Sopenharmony_ci regw(value, vpifregs[channel_id].h_cfg); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci value = (config->l1 & vpifregs[config_channel_id].len_mask); 30262306a36Sopenharmony_ci value <<= VPIF_CH_LEN_SHIFT; 30362306a36Sopenharmony_ci value |= (config->l3 & vpifregs[config_channel_id].len_mask); 30462306a36Sopenharmony_ci regw(value, vpifregs[channel_id].v_cfg_00); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci value = (config->l5 & vpifregs[config_channel_id].len_mask); 30762306a36Sopenharmony_ci value <<= VPIF_CH_LEN_SHIFT; 30862306a36Sopenharmony_ci value |= (config->l7 & vpifregs[config_channel_id].len_mask); 30962306a36Sopenharmony_ci regw(value, vpifregs[channel_id].v_cfg_01); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci value = (config->l9 & vpifregs[config_channel_id].len_mask); 31262306a36Sopenharmony_ci value <<= VPIF_CH_LEN_SHIFT; 31362306a36Sopenharmony_ci value |= (config->l11 & vpifregs[config_channel_id].len_mask); 31462306a36Sopenharmony_ci regw(value, vpifregs[channel_id].v_cfg_02); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci value = (config->vsize & vpifregs[config_channel_id].len_mask); 31762306a36Sopenharmony_ci regw(value, vpifregs[channel_id].v_cfg); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* config_vpif_params 32162306a36Sopenharmony_ci * Function to set the parameters of a channel 32262306a36Sopenharmony_ci * Mainly modifies the channel ciontrol register 32362306a36Sopenharmony_ci * It sets frame format, yc mux mode 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_cistatic void config_vpif_params(struct vpif_params *vpifparams, 32662306a36Sopenharmony_ci u8 channel_id, u8 found) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci const struct vpif_channel_config_params *config = &vpifparams->std_info; 32962306a36Sopenharmony_ci u32 value, ch_nip, reg; 33062306a36Sopenharmony_ci u8 start, end; 33162306a36Sopenharmony_ci int i; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci start = channel_id; 33462306a36Sopenharmony_ci end = channel_id + found; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci for (i = start; i < end; i++) { 33762306a36Sopenharmony_ci reg = vpifregs[i].ch_ctrl; 33862306a36Sopenharmony_ci if (channel_id < 2) 33962306a36Sopenharmony_ci ch_nip = VPIF_CAPTURE_CH_NIP; 34062306a36Sopenharmony_ci else 34162306a36Sopenharmony_ci ch_nip = VPIF_DISPLAY_CH_NIP; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci vpif_wr_bit(reg, ch_nip, config->frm_fmt); 34462306a36Sopenharmony_ci vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); 34562306a36Sopenharmony_ci vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, 34662306a36Sopenharmony_ci vpifparams->video_params.storage_mode); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Set raster scanning SDR Format */ 34962306a36Sopenharmony_ci vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); 35062306a36Sopenharmony_ci vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (channel_id > 1) /* Set the Pixel enable bit */ 35362306a36Sopenharmony_ci vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); 35462306a36Sopenharmony_ci else if (config->capture_format) { 35562306a36Sopenharmony_ci /* Set the polarity of various pins */ 35662306a36Sopenharmony_ci vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, 35762306a36Sopenharmony_ci vpifparams->iface.fid_pol); 35862306a36Sopenharmony_ci vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, 35962306a36Sopenharmony_ci vpifparams->iface.vd_pol); 36062306a36Sopenharmony_ci vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, 36162306a36Sopenharmony_ci vpifparams->iface.hd_pol); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci value = regr(reg); 36462306a36Sopenharmony_ci /* Set data width */ 36562306a36Sopenharmony_ci value &= ~(0x3u << 36662306a36Sopenharmony_ci VPIF_CH_DATA_WIDTH_BIT); 36762306a36Sopenharmony_ci value |= ((vpifparams->params.data_sz) << 36862306a36Sopenharmony_ci VPIF_CH_DATA_WIDTH_BIT); 36962306a36Sopenharmony_ci regw(value, reg); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Write the pitch in the driver */ 37362306a36Sopenharmony_ci regw((vpifparams->video_params.hpitch), 37462306a36Sopenharmony_ci vpifregs[i].line_offset); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/* vpif_set_video_params 37962306a36Sopenharmony_ci * This function is used to set video parameters in VPIF register 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ciint vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci const struct vpif_channel_config_params *config = &vpifparams->std_info; 38462306a36Sopenharmony_ci int found = 1; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci vpif_set_mode_info(config, channel_id, channel_id); 38762306a36Sopenharmony_ci if (!config->ycmux_mode) { 38862306a36Sopenharmony_ci /* YC are on separate channels (HDTV formats) */ 38962306a36Sopenharmony_ci vpif_set_mode_info(config, channel_id + 1, channel_id); 39062306a36Sopenharmony_ci found = 2; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci config_vpif_params(vpifparams, channel_id, found); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci regw(0x80, VPIF_REQ_SIZE); 39662306a36Sopenharmony_ci regw(0x01, VPIF_EMULATION_CTRL); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return found; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ciEXPORT_SYMBOL(vpif_set_video_params); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_civoid vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, 40362306a36Sopenharmony_ci u8 channel_id) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci u32 value; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci value = 0x3F8 & (vbiparams->hstart0); 40862306a36Sopenharmony_ci value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); 40962306a36Sopenharmony_ci regw(value, vpifregs[channel_id].vanc0_strt); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci value = 0x3F8 & (vbiparams->hstart1); 41262306a36Sopenharmony_ci value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); 41362306a36Sopenharmony_ci regw(value, vpifregs[channel_id].vanc1_strt); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci value = 0x3F8 & (vbiparams->hsize0); 41662306a36Sopenharmony_ci value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); 41762306a36Sopenharmony_ci regw(value, vpifregs[channel_id].vanc0_size); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci value = 0x3F8 & (vbiparams->hsize1); 42062306a36Sopenharmony_ci value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); 42162306a36Sopenharmony_ci regw(value, vpifregs[channel_id].vanc1_size); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ciEXPORT_SYMBOL(vpif_set_vbi_display_params); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ciint vpif_channel_getfid(u8 channel_id) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) 42962306a36Sopenharmony_ci >> VPIF_CH_FID_SHIFT; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ciEXPORT_SYMBOL(vpif_channel_getfid); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void vpif_pdev_release(struct device *dev) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci kfree(pdev); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic int vpif_probe(struct platform_device *pdev) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci static struct resource res_irq; 44362306a36Sopenharmony_ci struct platform_device *pdev_capture, *pdev_display; 44462306a36Sopenharmony_ci struct device_node *endpoint = NULL; 44562306a36Sopenharmony_ci struct vpif_data *data; 44662306a36Sopenharmony_ci int ret; 44762306a36Sopenharmony_ci int irq; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci vpif_base = devm_platform_ioremap_resource(pdev, 0); 45062306a36Sopenharmony_ci if (IS_ERR(vpif_base)) 45162306a36Sopenharmony_ci return PTR_ERR(vpif_base); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 45462306a36Sopenharmony_ci if (!data) 45562306a36Sopenharmony_ci return -ENOMEM; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci platform_set_drvdata(pdev, data); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 46062306a36Sopenharmony_ci pm_runtime_get(&pdev->dev); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* 46362306a36Sopenharmony_ci * If VPIF Node has endpoints, assume "new" DT support, 46462306a36Sopenharmony_ci * where capture and display drivers don't have DT nodes 46562306a36Sopenharmony_ci * so their devices need to be registered manually here 46662306a36Sopenharmony_ci * for their legacy platform_drivers to work. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, 46962306a36Sopenharmony_ci endpoint); 47062306a36Sopenharmony_ci if (!endpoint) 47162306a36Sopenharmony_ci return 0; 47262306a36Sopenharmony_ci of_node_put(endpoint); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * For DT platforms, manually create platform_devices for 47662306a36Sopenharmony_ci * capture/display drivers. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 47962306a36Sopenharmony_ci if (irq < 0) { 48062306a36Sopenharmony_ci ret = irq; 48162306a36Sopenharmony_ci goto err_put_rpm; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci res_irq = DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node)); 48462306a36Sopenharmony_ci res_irq.flags |= irq_get_trigger_type(irq); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL); 48762306a36Sopenharmony_ci if (!pdev_capture) { 48862306a36Sopenharmony_ci ret = -ENOMEM; 48962306a36Sopenharmony_ci goto err_put_rpm; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci pdev_capture->name = "vpif_capture"; 49362306a36Sopenharmony_ci pdev_capture->id = -1; 49462306a36Sopenharmony_ci pdev_capture->resource = &res_irq; 49562306a36Sopenharmony_ci pdev_capture->num_resources = 1; 49662306a36Sopenharmony_ci pdev_capture->dev.dma_mask = pdev->dev.dma_mask; 49762306a36Sopenharmony_ci pdev_capture->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; 49862306a36Sopenharmony_ci pdev_capture->dev.parent = &pdev->dev; 49962306a36Sopenharmony_ci pdev_capture->dev.release = vpif_pdev_release; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci ret = platform_device_register(pdev_capture); 50262306a36Sopenharmony_ci if (ret) 50362306a36Sopenharmony_ci goto err_put_pdev_capture; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci pdev_display = kzalloc(sizeof(*pdev_display), GFP_KERNEL); 50662306a36Sopenharmony_ci if (!pdev_display) { 50762306a36Sopenharmony_ci ret = -ENOMEM; 50862306a36Sopenharmony_ci goto err_put_pdev_capture; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci pdev_display->name = "vpif_display"; 51262306a36Sopenharmony_ci pdev_display->id = -1; 51362306a36Sopenharmony_ci pdev_display->resource = &res_irq; 51462306a36Sopenharmony_ci pdev_display->num_resources = 1; 51562306a36Sopenharmony_ci pdev_display->dev.dma_mask = pdev->dev.dma_mask; 51662306a36Sopenharmony_ci pdev_display->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; 51762306a36Sopenharmony_ci pdev_display->dev.parent = &pdev->dev; 51862306a36Sopenharmony_ci pdev_display->dev.release = vpif_pdev_release; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci ret = platform_device_register(pdev_display); 52162306a36Sopenharmony_ci if (ret) 52262306a36Sopenharmony_ci goto err_put_pdev_display; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci data->capture = pdev_capture; 52562306a36Sopenharmony_ci data->display = pdev_display; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return 0; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cierr_put_pdev_display: 53062306a36Sopenharmony_ci platform_device_put(pdev_display); 53162306a36Sopenharmony_cierr_put_pdev_capture: 53262306a36Sopenharmony_ci platform_device_put(pdev_capture); 53362306a36Sopenharmony_cierr_put_rpm: 53462306a36Sopenharmony_ci pm_runtime_put(&pdev->dev); 53562306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 53662306a36Sopenharmony_ci kfree(data); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return ret; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic void vpif_remove(struct platform_device *pdev) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct vpif_data *data = platform_get_drvdata(pdev); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (data->capture) 54662306a36Sopenharmony_ci platform_device_unregister(data->capture); 54762306a36Sopenharmony_ci if (data->display) 54862306a36Sopenharmony_ci platform_device_unregister(data->display); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci pm_runtime_put(&pdev->dev); 55162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci kfree(data); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci#ifdef CONFIG_PM 55762306a36Sopenharmony_cistatic int vpif_suspend(struct device *dev) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci pm_runtime_put(dev); 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int vpif_resume(struct device *dev) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci pm_runtime_get(dev); 56662306a36Sopenharmony_ci return 0; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic const struct dev_pm_ops vpif_pm = { 57062306a36Sopenharmony_ci .suspend = vpif_suspend, 57162306a36Sopenharmony_ci .resume = vpif_resume, 57262306a36Sopenharmony_ci}; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci#define vpif_pm_ops (&vpif_pm) 57562306a36Sopenharmony_ci#else 57662306a36Sopenharmony_ci#define vpif_pm_ops NULL 57762306a36Sopenharmony_ci#endif 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_OF) 58062306a36Sopenharmony_cistatic const struct of_device_id vpif_of_match[] = { 58162306a36Sopenharmony_ci { .compatible = "ti,da850-vpif", }, 58262306a36Sopenharmony_ci { /* sentinel */ }, 58362306a36Sopenharmony_ci}; 58462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, vpif_of_match); 58562306a36Sopenharmony_ci#endif 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic struct platform_driver vpif_driver = { 58862306a36Sopenharmony_ci .driver = { 58962306a36Sopenharmony_ci .of_match_table = of_match_ptr(vpif_of_match), 59062306a36Sopenharmony_ci .name = VPIF_DRIVER_NAME, 59162306a36Sopenharmony_ci .pm = vpif_pm_ops, 59262306a36Sopenharmony_ci }, 59362306a36Sopenharmony_ci .remove_new = vpif_remove, 59462306a36Sopenharmony_ci .probe = vpif_probe, 59562306a36Sopenharmony_ci}; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic void vpif_exit(void) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci platform_driver_unregister(&vpif_driver); 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int __init vpif_init(void) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci return platform_driver_register(&vpif_driver); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_cisubsys_initcall(vpif_init); 60762306a36Sopenharmony_cimodule_exit(vpif_exit); 60862306a36Sopenharmony_ci 609