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 | VDI_C_TOP_FIELD_AUTO_1); 92 else 93 reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_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 } 244