162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012-2016 Mentor Graphics Inc. 462306a36Sopenharmony_ci * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/io.h> 762306a36Sopenharmony_ci#include "ipu-prv.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_cistruct ipu_vdi { 1062306a36Sopenharmony_ci void __iomem *base; 1162306a36Sopenharmony_ci u32 module; 1262306a36Sopenharmony_ci spinlock_t lock; 1362306a36Sopenharmony_ci int use_count; 1462306a36Sopenharmony_ci struct ipu_soc *ipu; 1562306a36Sopenharmony_ci}; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* VDI Register Offsets */ 1962306a36Sopenharmony_ci#define VDI_FSIZE 0x0000 2062306a36Sopenharmony_ci#define VDI_C 0x0004 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* VDI Register Fields */ 2362306a36Sopenharmony_ci#define VDI_C_CH_420 (0 << 1) 2462306a36Sopenharmony_ci#define VDI_C_CH_422 (1 << 1) 2562306a36Sopenharmony_ci#define VDI_C_MOT_SEL_MASK (0x3 << 2) 2662306a36Sopenharmony_ci#define VDI_C_MOT_SEL_FULL (2 << 2) 2762306a36Sopenharmony_ci#define VDI_C_MOT_SEL_LOW (1 << 2) 2862306a36Sopenharmony_ci#define VDI_C_MOT_SEL_MED (0 << 2) 2962306a36Sopenharmony_ci#define VDI_C_BURST_SIZE1_4 (3 << 4) 3062306a36Sopenharmony_ci#define VDI_C_BURST_SIZE2_4 (3 << 8) 3162306a36Sopenharmony_ci#define VDI_C_BURST_SIZE3_4 (3 << 12) 3262306a36Sopenharmony_ci#define VDI_C_BURST_SIZE_MASK 0xF 3362306a36Sopenharmony_ci#define VDI_C_BURST_SIZE1_OFFSET 4 3462306a36Sopenharmony_ci#define VDI_C_BURST_SIZE2_OFFSET 8 3562306a36Sopenharmony_ci#define VDI_C_BURST_SIZE3_OFFSET 12 3662306a36Sopenharmony_ci#define VDI_C_VWM1_SET_1 (0 << 16) 3762306a36Sopenharmony_ci#define VDI_C_VWM1_SET_2 (1 << 16) 3862306a36Sopenharmony_ci#define VDI_C_VWM1_CLR_2 (1 << 19) 3962306a36Sopenharmony_ci#define VDI_C_VWM3_SET_1 (0 << 22) 4062306a36Sopenharmony_ci#define VDI_C_VWM3_SET_2 (1 << 22) 4162306a36Sopenharmony_ci#define VDI_C_VWM3_CLR_2 (1 << 25) 4262306a36Sopenharmony_ci#define VDI_C_TOP_FIELD_MAN_1 (1 << 30) 4362306a36Sopenharmony_ci#define VDI_C_TOP_FIELD_AUTO_1 (1 << 31) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci return readl(vdi->base + offset); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value, 5162306a36Sopenharmony_ci unsigned int offset) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci writel(value, vdi->base + offset); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_civoid ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci bool top_field_0 = false; 5962306a36Sopenharmony_ci unsigned long flags; 6062306a36Sopenharmony_ci u32 reg; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci switch (field) { 6362306a36Sopenharmony_ci case V4L2_FIELD_INTERLACED_TB: 6462306a36Sopenharmony_ci case V4L2_FIELD_SEQ_TB: 6562306a36Sopenharmony_ci case V4L2_FIELD_TOP: 6662306a36Sopenharmony_ci top_field_0 = true; 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci case V4L2_FIELD_INTERLACED_BT: 6962306a36Sopenharmony_ci case V4L2_FIELD_SEQ_BT: 7062306a36Sopenharmony_ci case V4L2_FIELD_BOTTOM: 7162306a36Sopenharmony_ci top_field_0 = false; 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci default: 7462306a36Sopenharmony_ci top_field_0 = (std & V4L2_STD_525_60) ? true : false; 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci reg = ipu_vdi_read(vdi, VDI_C); 8162306a36Sopenharmony_ci if (top_field_0) 8262306a36Sopenharmony_ci reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1); 8362306a36Sopenharmony_ci else 8462306a36Sopenharmony_ci reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1; 8562306a36Sopenharmony_ci ipu_vdi_write(vdi, reg, VDI_C); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_set_field_order); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_civoid ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci unsigned long flags; 9462306a36Sopenharmony_ci u32 reg; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci reg = ipu_vdi_read(vdi, VDI_C); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci reg &= ~VDI_C_MOT_SEL_MASK; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci switch (motion_sel) { 10362306a36Sopenharmony_ci case MED_MOTION: 10462306a36Sopenharmony_ci reg |= VDI_C_MOT_SEL_MED; 10562306a36Sopenharmony_ci break; 10662306a36Sopenharmony_ci case HIGH_MOTION: 10762306a36Sopenharmony_ci reg |= VDI_C_MOT_SEL_FULL; 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci default: 11062306a36Sopenharmony_ci reg |= VDI_C_MOT_SEL_LOW; 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ipu_vdi_write(vdi, reg, VDI_C); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_set_motion); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_civoid ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci unsigned long flags; 12362306a36Sopenharmony_ci u32 pixel_fmt, reg; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci reg = ((yres - 1) << 16) | (xres - 1); 12862306a36Sopenharmony_ci ipu_vdi_write(vdi, reg, VDI_FSIZE); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * Full motion, only vertical filter is used. 13262306a36Sopenharmony_ci * Burst size is 4 accesses 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci if (code == MEDIA_BUS_FMT_UYVY8_2X8 || 13562306a36Sopenharmony_ci code == MEDIA_BUS_FMT_UYVY8_1X16 || 13662306a36Sopenharmony_ci code == MEDIA_BUS_FMT_YUYV8_2X8 || 13762306a36Sopenharmony_ci code == MEDIA_BUS_FMT_YUYV8_1X16) 13862306a36Sopenharmony_ci pixel_fmt = VDI_C_CH_422; 13962306a36Sopenharmony_ci else 14062306a36Sopenharmony_ci pixel_fmt = VDI_C_CH_420; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci reg = ipu_vdi_read(vdi, VDI_C); 14362306a36Sopenharmony_ci reg |= pixel_fmt; 14462306a36Sopenharmony_ci reg |= VDI_C_BURST_SIZE2_4; 14562306a36Sopenharmony_ci reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2; 14662306a36Sopenharmony_ci reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2; 14762306a36Sopenharmony_ci ipu_vdi_write(vdi, reg, VDI_C); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_setup); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_civoid ipu_vdi_unsetup(struct ipu_vdi *vdi) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci unsigned long flags; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 15862306a36Sopenharmony_ci ipu_vdi_write(vdi, 0, VDI_FSIZE); 15962306a36Sopenharmony_ci ipu_vdi_write(vdi, 0, VDI_C); 16062306a36Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_unsetup); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ciint ipu_vdi_enable(struct ipu_vdi *vdi) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci unsigned long flags; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!vdi->use_count) 17162306a36Sopenharmony_ci ipu_module_enable(vdi->ipu, vdi->module); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci vdi->use_count++; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_enable); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciint ipu_vdi_disable(struct ipu_vdi *vdi) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci unsigned long flags; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (vdi->use_count) { 18862306a36Sopenharmony_ci if (!--vdi->use_count) 18962306a36Sopenharmony_ci ipu_module_disable(vdi->ipu, vdi->module); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_disable); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistruct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci return ipu->vdi_priv; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_get); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_civoid ipu_vdi_put(struct ipu_vdi *vdi) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_put); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ciint ipu_vdi_init(struct ipu_soc *ipu, struct device *dev, 21062306a36Sopenharmony_ci unsigned long base, u32 module) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct ipu_vdi *vdi; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL); 21562306a36Sopenharmony_ci if (!vdi) 21662306a36Sopenharmony_ci return -ENOMEM; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci ipu->vdi_priv = vdi; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci spin_lock_init(&vdi->lock); 22162306a36Sopenharmony_ci vdi->module = module; 22262306a36Sopenharmony_ci vdi->base = devm_ioremap(dev, base, PAGE_SIZE); 22362306a36Sopenharmony_ci if (!vdi->base) 22462306a36Sopenharmony_ci return -ENOMEM; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base); 22762306a36Sopenharmony_ci vdi->ipu = ipu; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_civoid ipu_vdi_exit(struct ipu_soc *ipu) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci} 235