Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpu: ipu-v3: Add Video Deinterlacer unit

Adds the Video Deinterlacer (VDIC) unit.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

authored by

Steve Longerbeam and committed by
Philipp Zabel
2d2ead45 a40e65b7

+284 -1
+1 -1
drivers/gpu/ipu-v3/Makefile
··· 1 1 obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o 2 2 3 3 imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \ 4 - ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o 4 + ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o ipu-vdi.o
+11
drivers/gpu/ipu-v3/ipu-common.c
··· 839 839 goto err_ic; 840 840 } 841 841 842 + ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs, 843 + IPU_CONF_VDI_EN | IPU_CONF_ISP_EN | 844 + IPU_CONF_IC_INPUT); 845 + if (ret) { 846 + unit = "vdi"; 847 + goto err_vdi; 848 + } 849 + 842 850 ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, 843 851 IPU_CONF_DI0_EN, ipu_clk); 844 852 if (ret) { ··· 901 893 err_di_1: 902 894 ipu_di_exit(ipu, 0); 903 895 err_di_0: 896 + ipu_vdi_exit(ipu); 897 + err_vdi: 904 898 ipu_ic_exit(ipu); 905 899 err_ic: 906 900 ipu_csi_exit(ipu, 1); ··· 987 977 ipu_dc_exit(ipu); 988 978 ipu_di_exit(ipu, 1); 989 979 ipu_di_exit(ipu, 0); 980 + ipu_vdi_exit(ipu); 990 981 ipu_ic_exit(ipu); 991 982 ipu_csi_exit(ipu, 1); 992 983 ipu_csi_exit(ipu, 0);
+6
drivers/gpu/ipu-v3/ipu-prv.h
··· 138 138 struct ipu_dmfc_priv; 139 139 struct ipu_di; 140 140 struct ipu_ic_priv; 141 + struct ipu_vdi; 141 142 struct ipu_smfc_priv; 142 143 143 144 struct ipu_devtype; ··· 171 170 struct ipu_di *di_priv[2]; 172 171 struct ipu_csi *csi_priv[2]; 173 172 struct ipu_ic_priv *ic_priv; 173 + struct ipu_vdi *vdi_priv; 174 174 struct ipu_smfc_priv *smfc_priv; 175 175 }; 176 176 ··· 201 199 int ipu_ic_init(struct ipu_soc *ipu, struct device *dev, 202 200 unsigned long base, unsigned long tpmem_base); 203 201 void ipu_ic_exit(struct ipu_soc *ipu); 202 + 203 + int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev, 204 + unsigned long base, u32 module); 205 + void ipu_vdi_exit(struct ipu_soc *ipu); 204 206 205 207 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, 206 208 unsigned long base, u32 module, struct clk *ipu_clk);
+243
drivers/gpu/ipu-v3/ipu-vdi.c
··· 1 + /* 2 + * Copyright (C) 2012-2016 Mentor Graphics Inc. 3 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms of the GNU General Public License as published by the 7 + * Free Software Foundation; either version 2 of the License, or (at your 8 + * option) any later version. 9 + * 10 + * This program is distributed in the hope that it will be useful, but 11 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 + * for more details. 14 + */ 15 + #include <linux/io.h> 16 + #include "ipu-prv.h" 17 + 18 + struct ipu_vdi { 19 + void __iomem *base; 20 + u32 module; 21 + spinlock_t lock; 22 + int use_count; 23 + struct ipu_soc *ipu; 24 + }; 25 + 26 + 27 + /* VDI Register Offsets */ 28 + #define VDI_FSIZE 0x0000 29 + #define VDI_C 0x0004 30 + 31 + /* VDI Register Fields */ 32 + #define VDI_C_CH_420 (0 << 1) 33 + #define VDI_C_CH_422 (1 << 1) 34 + #define VDI_C_MOT_SEL_MASK (0x3 << 2) 35 + #define VDI_C_MOT_SEL_FULL (2 << 2) 36 + #define VDI_C_MOT_SEL_LOW (1 << 2) 37 + #define VDI_C_MOT_SEL_MED (0 << 2) 38 + #define VDI_C_BURST_SIZE1_4 (3 << 4) 39 + #define VDI_C_BURST_SIZE2_4 (3 << 8) 40 + #define VDI_C_BURST_SIZE3_4 (3 << 12) 41 + #define VDI_C_BURST_SIZE_MASK 0xF 42 + #define VDI_C_BURST_SIZE1_OFFSET 4 43 + #define VDI_C_BURST_SIZE2_OFFSET 8 44 + #define VDI_C_BURST_SIZE3_OFFSET 12 45 + #define VDI_C_VWM1_SET_1 (0 << 16) 46 + #define VDI_C_VWM1_SET_2 (1 << 16) 47 + #define VDI_C_VWM1_CLR_2 (1 << 19) 48 + #define VDI_C_VWM3_SET_1 (0 << 22) 49 + #define VDI_C_VWM3_SET_2 (1 << 22) 50 + #define VDI_C_VWM3_CLR_2 (1 << 25) 51 + #define VDI_C_TOP_FIELD_MAN_1 (1 << 30) 52 + #define VDI_C_TOP_FIELD_AUTO_1 (1 << 31) 53 + 54 + static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset) 55 + { 56 + return readl(vdi->base + offset); 57 + } 58 + 59 + static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value, 60 + unsigned int offset) 61 + { 62 + writel(value, vdi->base + offset); 63 + } 64 + 65 + void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field) 66 + { 67 + bool top_field_0 = false; 68 + unsigned long flags; 69 + u32 reg; 70 + 71 + switch (field) { 72 + case V4L2_FIELD_INTERLACED_TB: 73 + case V4L2_FIELD_SEQ_TB: 74 + case V4L2_FIELD_TOP: 75 + top_field_0 = true; 76 + break; 77 + case V4L2_FIELD_INTERLACED_BT: 78 + case V4L2_FIELD_SEQ_BT: 79 + case V4L2_FIELD_BOTTOM: 80 + top_field_0 = false; 81 + break; 82 + default: 83 + top_field_0 = (std & V4L2_STD_525_60) ? true : false; 84 + break; 85 + } 86 + 87 + spin_lock_irqsave(&vdi->lock, flags); 88 + 89 + reg = ipu_vdi_read(vdi, VDI_C); 90 + if (top_field_0) 91 + reg &= ~VDI_C_TOP_FIELD_MAN_1; 92 + else 93 + reg |= VDI_C_TOP_FIELD_MAN_1; 94 + ipu_vdi_write(vdi, reg, VDI_C); 95 + 96 + spin_unlock_irqrestore(&vdi->lock, flags); 97 + } 98 + EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order); 99 + 100 + void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel) 101 + { 102 + unsigned long flags; 103 + u32 reg; 104 + 105 + spin_lock_irqsave(&vdi->lock, flags); 106 + 107 + reg = ipu_vdi_read(vdi, VDI_C); 108 + 109 + reg &= ~VDI_C_MOT_SEL_MASK; 110 + 111 + switch (motion_sel) { 112 + case MED_MOTION: 113 + reg |= VDI_C_MOT_SEL_MED; 114 + break; 115 + case HIGH_MOTION: 116 + reg |= VDI_C_MOT_SEL_FULL; 117 + break; 118 + default: 119 + reg |= VDI_C_MOT_SEL_LOW; 120 + break; 121 + } 122 + 123 + ipu_vdi_write(vdi, reg, VDI_C); 124 + 125 + spin_unlock_irqrestore(&vdi->lock, flags); 126 + } 127 + EXPORT_SYMBOL_GPL(ipu_vdi_set_motion); 128 + 129 + void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres) 130 + { 131 + unsigned long flags; 132 + u32 pixel_fmt, reg; 133 + 134 + spin_lock_irqsave(&vdi->lock, flags); 135 + 136 + reg = ((yres - 1) << 16) | (xres - 1); 137 + ipu_vdi_write(vdi, reg, VDI_FSIZE); 138 + 139 + /* 140 + * Full motion, only vertical filter is used. 141 + * Burst size is 4 accesses 142 + */ 143 + if (code == MEDIA_BUS_FMT_UYVY8_2X8 || 144 + code == MEDIA_BUS_FMT_UYVY8_1X16 || 145 + code == MEDIA_BUS_FMT_YUYV8_2X8 || 146 + code == MEDIA_BUS_FMT_YUYV8_1X16) 147 + pixel_fmt = VDI_C_CH_422; 148 + else 149 + pixel_fmt = VDI_C_CH_420; 150 + 151 + reg = ipu_vdi_read(vdi, VDI_C); 152 + reg |= pixel_fmt; 153 + reg |= VDI_C_BURST_SIZE2_4; 154 + reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2; 155 + reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2; 156 + ipu_vdi_write(vdi, reg, VDI_C); 157 + 158 + spin_unlock_irqrestore(&vdi->lock, flags); 159 + } 160 + EXPORT_SYMBOL_GPL(ipu_vdi_setup); 161 + 162 + void ipu_vdi_unsetup(struct ipu_vdi *vdi) 163 + { 164 + unsigned long flags; 165 + 166 + spin_lock_irqsave(&vdi->lock, flags); 167 + ipu_vdi_write(vdi, 0, VDI_FSIZE); 168 + ipu_vdi_write(vdi, 0, VDI_C); 169 + spin_unlock_irqrestore(&vdi->lock, flags); 170 + } 171 + EXPORT_SYMBOL_GPL(ipu_vdi_unsetup); 172 + 173 + int ipu_vdi_enable(struct ipu_vdi *vdi) 174 + { 175 + unsigned long flags; 176 + 177 + spin_lock_irqsave(&vdi->lock, flags); 178 + 179 + if (!vdi->use_count) 180 + ipu_module_enable(vdi->ipu, vdi->module); 181 + 182 + vdi->use_count++; 183 + 184 + spin_unlock_irqrestore(&vdi->lock, flags); 185 + 186 + return 0; 187 + } 188 + EXPORT_SYMBOL_GPL(ipu_vdi_enable); 189 + 190 + int ipu_vdi_disable(struct ipu_vdi *vdi) 191 + { 192 + unsigned long flags; 193 + 194 + spin_lock_irqsave(&vdi->lock, flags); 195 + 196 + if (vdi->use_count) { 197 + if (!--vdi->use_count) 198 + ipu_module_disable(vdi->ipu, vdi->module); 199 + } 200 + 201 + spin_unlock_irqrestore(&vdi->lock, flags); 202 + 203 + return 0; 204 + } 205 + EXPORT_SYMBOL_GPL(ipu_vdi_disable); 206 + 207 + struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu) 208 + { 209 + return ipu->vdi_priv; 210 + } 211 + EXPORT_SYMBOL_GPL(ipu_vdi_get); 212 + 213 + void ipu_vdi_put(struct ipu_vdi *vdi) 214 + { 215 + } 216 + EXPORT_SYMBOL_GPL(ipu_vdi_put); 217 + 218 + int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev, 219 + unsigned long base, u32 module) 220 + { 221 + struct ipu_vdi *vdi; 222 + 223 + vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL); 224 + if (!vdi) 225 + return -ENOMEM; 226 + 227 + ipu->vdi_priv = vdi; 228 + 229 + spin_lock_init(&vdi->lock); 230 + vdi->module = module; 231 + vdi->base = devm_ioremap(dev, base, PAGE_SIZE); 232 + if (!vdi->base) 233 + return -ENOMEM; 234 + 235 + dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base); 236 + vdi->ipu = ipu; 237 + 238 + return 0; 239 + } 240 + 241 + void ipu_vdi_exit(struct ipu_soc *ipu) 242 + { 243 + }
+23
include/video/imx-ipu-v3.h
··· 80 80 IPUV3_COLORSPACE_UNKNOWN, 81 81 }; 82 82 83 + /* 84 + * Enumeration of VDI MOTION select 85 + */ 86 + enum ipu_motion_sel { 87 + MOTION_NONE = 0, 88 + LOW_MOTION, 89 + MED_MOTION, 90 + HIGH_MOTION, 91 + }; 92 + 83 93 struct ipuv3_channel; 84 94 85 95 enum ipu_channel_irq { ··· 343 333 struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task); 344 334 void ipu_ic_put(struct ipu_ic *ic); 345 335 void ipu_ic_dump(struct ipu_ic *ic); 336 + 337 + /* 338 + * IPU Video De-Interlacer (vdi) functions 339 + */ 340 + struct ipu_vdi; 341 + void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field); 342 + void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel); 343 + void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres); 344 + void ipu_vdi_unsetup(struct ipu_vdi *vdi); 345 + int ipu_vdi_enable(struct ipu_vdi *vdi); 346 + int ipu_vdi_disable(struct ipu_vdi *vdi); 347 + struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu); 348 + void ipu_vdi_put(struct ipu_vdi *vdi); 346 349 347 350 /* 348 351 * IPU Sensor Multiple FIFO Controller (SMFC) functions