1/* 2 * vpif - DM646x Video Port Interface driver 3 * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) 4 * that receiveing video byte stream and two channels(2, 3) for video output. 5 * The hardware supports SDTV, HDTV formats, raw data capture. 6 * Currently, the driver supports NTSC and PAL standards. 7 * 8 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation version 2. 13 * 14 * This program is distributed .as is. WITHOUT ANY WARRANTY of any 15 * kind, whether express or implied; without even the implied warranty 16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20#include <linux/init.h> 21#include <linux/module.h> 22#include <linux/platform_device.h> 23#include <linux/spinlock.h> 24#include <linux/kernel.h> 25#include <linux/io.h> 26#include <mach/hardware.h> 27 28#include "vpif.h" 29 30MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); 31MODULE_LICENSE("GPL"); 32 33#define VPIF_CH0_MAX_MODES (22) 34#define VPIF_CH1_MAX_MODES (02) 35#define VPIF_CH2_MAX_MODES (15) 36#define VPIF_CH3_MAX_MODES (02) 37 38static resource_size_t res_len; 39static struct resource *res; 40spinlock_t vpif_lock; 41 42void __iomem *vpif_base; 43 44static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) 45{ 46 if (val) 47 vpif_set_bit(reg, bit); 48 else 49 vpif_clr_bit(reg, bit); 50} 51 52/* This structure is used to keep track of VPIF size register's offsets */ 53struct vpif_registers { 54 u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; 55 u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; 56 u32 vanc1_size, width_mask, len_mask; 57 u8 max_modes; 58}; 59 60static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { 61 /* Channel0 */ 62 { 63 VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, 64 VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, 65 VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, 66 VPIF_CH0_MAX_MODES, 67 }, 68 /* Channel1 */ 69 { 70 VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, 71 VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, 72 VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, 73 VPIF_CH1_MAX_MODES, 74 }, 75 /* Channel2 */ 76 { 77 VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, 78 VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, 79 VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, 80 VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, 81 VPIF_CH2_MAX_MODES 82 }, 83 /* Channel3 */ 84 { 85 VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, 86 VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, 87 VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, 88 VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, 89 VPIF_CH3_MAX_MODES 90 }, 91}; 92 93/* vpif_set_mode_info: 94 * This function is used to set horizontal and vertical config parameters 95 * As per the standard in the channel, configure the values of L1, L3, 96 * L5, L7 L9, L11 in VPIF Register , also write width and height 97 */ 98static void vpif_set_mode_info(const struct vpif_channel_config_params *config, 99 u8 channel_id, u8 config_channel_id) 100{ 101 u32 value; 102 103 value = (config->eav2sav & vpifregs[config_channel_id].width_mask); 104 value <<= VPIF_CH_LEN_SHIFT; 105 value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); 106 regw(value, vpifregs[channel_id].h_cfg); 107 108 value = (config->l1 & vpifregs[config_channel_id].len_mask); 109 value <<= VPIF_CH_LEN_SHIFT; 110 value |= (config->l3 & vpifregs[config_channel_id].len_mask); 111 regw(value, vpifregs[channel_id].v_cfg_00); 112 113 value = (config->l5 & vpifregs[config_channel_id].len_mask); 114 value <<= VPIF_CH_LEN_SHIFT; 115 value |= (config->l7 & vpifregs[config_channel_id].len_mask); 116 regw(value, vpifregs[channel_id].v_cfg_01); 117 118 value = (config->l9 & vpifregs[config_channel_id].len_mask); 119 value <<= VPIF_CH_LEN_SHIFT; 120 value |= (config->l11 & vpifregs[config_channel_id].len_mask); 121 regw(value, vpifregs[channel_id].v_cfg_02); 122 123 value = (config->vsize & vpifregs[config_channel_id].len_mask); 124 regw(value, vpifregs[channel_id].v_cfg); 125} 126 127/* config_vpif_params 128 * Function to set the parameters of a channel 129 * Mainly modifies the channel ciontrol register 130 * It sets frame format, yc mux mode 131 */ 132static void config_vpif_params(struct vpif_params *vpifparams, 133 u8 channel_id, u8 found) 134{ 135 const struct vpif_channel_config_params *config = &vpifparams->std_info; 136 u32 value, ch_nip, reg; 137 u8 start, end; 138 int i; 139 140 start = channel_id; 141 end = channel_id + found; 142 143 for (i = start; i < end; i++) { 144 reg = vpifregs[i].ch_ctrl; 145 if (channel_id < 2) 146 ch_nip = VPIF_CAPTURE_CH_NIP; 147 else 148 ch_nip = VPIF_DISPLAY_CH_NIP; 149 150 vpif_wr_bit(reg, ch_nip, config->frm_fmt); 151 vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); 152 vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, 153 vpifparams->video_params.storage_mode); 154 155 /* Set raster scanning SDR Format */ 156 vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); 157 vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); 158 159 if (channel_id > 1) /* Set the Pixel enable bit */ 160 vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); 161 else if (config->capture_format) { 162 /* Set the polarity of various pins */ 163 vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, 164 vpifparams->iface.fid_pol); 165 vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, 166 vpifparams->iface.vd_pol); 167 vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, 168 vpifparams->iface.hd_pol); 169 170 value = regr(reg); 171 /* Set data width */ 172 value &= ((~(unsigned int)(0x3)) << 173 VPIF_CH_DATA_WIDTH_BIT); 174 value |= ((vpifparams->params.data_sz) << 175 VPIF_CH_DATA_WIDTH_BIT); 176 regw(value, reg); 177 } 178 179 /* Write the pitch in the driver */ 180 regw((vpifparams->video_params.hpitch), 181 vpifregs[i].line_offset); 182 } 183} 184 185/* vpif_set_video_params 186 * This function is used to set video parameters in VPIF register 187 */ 188int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) 189{ 190 const struct vpif_channel_config_params *config = &vpifparams->std_info; 191 int found = 1; 192 193 vpif_set_mode_info(config, channel_id, channel_id); 194 if (!config->ycmux_mode) { 195 /* YC are on separate channels (HDTV formats) */ 196 vpif_set_mode_info(config, channel_id + 1, channel_id); 197 found = 2; 198 } 199 200 config_vpif_params(vpifparams, channel_id, found); 201 202 regw(0x80, VPIF_REQ_SIZE); 203 regw(0x01, VPIF_EMULATION_CTRL); 204 205 return found; 206} 207EXPORT_SYMBOL(vpif_set_video_params); 208 209void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, 210 u8 channel_id) 211{ 212 u32 value; 213 214 value = 0x3F8 & (vbiparams->hstart0); 215 value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); 216 regw(value, vpifregs[channel_id].vanc0_strt); 217 218 value = 0x3F8 & (vbiparams->hstart1); 219 value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); 220 regw(value, vpifregs[channel_id].vanc1_strt); 221 222 value = 0x3F8 & (vbiparams->hsize0); 223 value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); 224 regw(value, vpifregs[channel_id].vanc0_size); 225 226 value = 0x3F8 & (vbiparams->hsize1); 227 value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); 228 regw(value, vpifregs[channel_id].vanc1_size); 229 230} 231EXPORT_SYMBOL(vpif_set_vbi_display_params); 232 233int vpif_channel_getfid(u8 channel_id) 234{ 235 return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) 236 >> VPIF_CH_FID_SHIFT; 237} 238EXPORT_SYMBOL(vpif_channel_getfid); 239 240static int __init vpif_probe(struct platform_device *pdev) 241{ 242 int status = 0; 243 244 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 245 if (!res) 246 return -ENOENT; 247 248 res_len = res->end - res->start + 1; 249 250 res = request_mem_region(res->start, res_len, res->name); 251 if (!res) 252 return -EBUSY; 253 254 vpif_base = ioremap(res->start, res_len); 255 if (!vpif_base) { 256 status = -EBUSY; 257 goto fail; 258 } 259 260 spin_lock_init(&vpif_lock); 261 dev_info(&pdev->dev, "vpif probe success\n"); 262 return 0; 263 264fail: 265 release_mem_region(res->start, res_len); 266 return status; 267} 268 269static int __devexit vpif_remove(struct platform_device *pdev) 270{ 271 iounmap(vpif_base); 272 release_mem_region(res->start, res_len); 273 return 0; 274} 275 276static struct platform_driver vpif_driver = { 277 .driver = { 278 .name = "vpif", 279 .owner = THIS_MODULE, 280 }, 281 .remove = __devexit_p(vpif_remove), 282 .probe = vpif_probe, 283}; 284 285static void vpif_exit(void) 286{ 287 platform_driver_unregister(&vpif_driver); 288} 289 290static int __init vpif_init(void) 291{ 292 return platform_driver_register(&vpif_driver); 293} 294subsys_initcall(vpif_init); 295module_exit(vpif_exit); 296