18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012-2016 Mentor Graphics Inc. 48c2ecf20Sopenharmony_ci * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/io.h> 78c2ecf20Sopenharmony_ci#include "ipu-prv.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_cistruct ipu_vdi { 108c2ecf20Sopenharmony_ci void __iomem *base; 118c2ecf20Sopenharmony_ci u32 module; 128c2ecf20Sopenharmony_ci spinlock_t lock; 138c2ecf20Sopenharmony_ci int use_count; 148c2ecf20Sopenharmony_ci struct ipu_soc *ipu; 158c2ecf20Sopenharmony_ci}; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* VDI Register Offsets */ 198c2ecf20Sopenharmony_ci#define VDI_FSIZE 0x0000 208c2ecf20Sopenharmony_ci#define VDI_C 0x0004 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* VDI Register Fields */ 238c2ecf20Sopenharmony_ci#define VDI_C_CH_420 (0 << 1) 248c2ecf20Sopenharmony_ci#define VDI_C_CH_422 (1 << 1) 258c2ecf20Sopenharmony_ci#define VDI_C_MOT_SEL_MASK (0x3 << 2) 268c2ecf20Sopenharmony_ci#define VDI_C_MOT_SEL_FULL (2 << 2) 278c2ecf20Sopenharmony_ci#define VDI_C_MOT_SEL_LOW (1 << 2) 288c2ecf20Sopenharmony_ci#define VDI_C_MOT_SEL_MED (0 << 2) 298c2ecf20Sopenharmony_ci#define VDI_C_BURST_SIZE1_4 (3 << 4) 308c2ecf20Sopenharmony_ci#define VDI_C_BURST_SIZE2_4 (3 << 8) 318c2ecf20Sopenharmony_ci#define VDI_C_BURST_SIZE3_4 (3 << 12) 328c2ecf20Sopenharmony_ci#define VDI_C_BURST_SIZE_MASK 0xF 338c2ecf20Sopenharmony_ci#define VDI_C_BURST_SIZE1_OFFSET 4 348c2ecf20Sopenharmony_ci#define VDI_C_BURST_SIZE2_OFFSET 8 358c2ecf20Sopenharmony_ci#define VDI_C_BURST_SIZE3_OFFSET 12 368c2ecf20Sopenharmony_ci#define VDI_C_VWM1_SET_1 (0 << 16) 378c2ecf20Sopenharmony_ci#define VDI_C_VWM1_SET_2 (1 << 16) 388c2ecf20Sopenharmony_ci#define VDI_C_VWM1_CLR_2 (1 << 19) 398c2ecf20Sopenharmony_ci#define VDI_C_VWM3_SET_1 (0 << 22) 408c2ecf20Sopenharmony_ci#define VDI_C_VWM3_SET_2 (1 << 22) 418c2ecf20Sopenharmony_ci#define VDI_C_VWM3_CLR_2 (1 << 25) 428c2ecf20Sopenharmony_ci#define VDI_C_TOP_FIELD_MAN_1 (1 << 30) 438c2ecf20Sopenharmony_ci#define VDI_C_TOP_FIELD_AUTO_1 (1 << 31) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return readl(vdi->base + offset); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value, 518c2ecf20Sopenharmony_ci unsigned int offset) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci writel(value, vdi->base + offset); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_civoid ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci bool top_field_0 = false; 598c2ecf20Sopenharmony_ci unsigned long flags; 608c2ecf20Sopenharmony_ci u32 reg; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci switch (field) { 638c2ecf20Sopenharmony_ci case V4L2_FIELD_INTERLACED_TB: 648c2ecf20Sopenharmony_ci case V4L2_FIELD_SEQ_TB: 658c2ecf20Sopenharmony_ci case V4L2_FIELD_TOP: 668c2ecf20Sopenharmony_ci top_field_0 = true; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case V4L2_FIELD_INTERLACED_BT: 698c2ecf20Sopenharmony_ci case V4L2_FIELD_SEQ_BT: 708c2ecf20Sopenharmony_ci case V4L2_FIELD_BOTTOM: 718c2ecf20Sopenharmony_ci top_field_0 = false; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci default: 748c2ecf20Sopenharmony_ci top_field_0 = (std & V4L2_STD_525_60) ? true : false; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci reg = ipu_vdi_read(vdi, VDI_C); 818c2ecf20Sopenharmony_ci if (top_field_0) 828c2ecf20Sopenharmony_ci reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1); 838c2ecf20Sopenharmony_ci else 848c2ecf20Sopenharmony_ci reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1; 858c2ecf20Sopenharmony_ci ipu_vdi_write(vdi, reg, VDI_C); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_set_field_order); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_civoid ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci unsigned long flags; 948c2ecf20Sopenharmony_ci u32 reg; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci reg = ipu_vdi_read(vdi, VDI_C); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci reg &= ~VDI_C_MOT_SEL_MASK; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci switch (motion_sel) { 1038c2ecf20Sopenharmony_ci case MED_MOTION: 1048c2ecf20Sopenharmony_ci reg |= VDI_C_MOT_SEL_MED; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case HIGH_MOTION: 1078c2ecf20Sopenharmony_ci reg |= VDI_C_MOT_SEL_FULL; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci default: 1108c2ecf20Sopenharmony_ci reg |= VDI_C_MOT_SEL_LOW; 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ipu_vdi_write(vdi, reg, VDI_C); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_set_motion); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_civoid ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci unsigned long flags; 1238c2ecf20Sopenharmony_ci u32 pixel_fmt, reg; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci reg = ((yres - 1) << 16) | (xres - 1); 1288c2ecf20Sopenharmony_ci ipu_vdi_write(vdi, reg, VDI_FSIZE); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * Full motion, only vertical filter is used. 1328c2ecf20Sopenharmony_ci * Burst size is 4 accesses 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci if (code == MEDIA_BUS_FMT_UYVY8_2X8 || 1358c2ecf20Sopenharmony_ci code == MEDIA_BUS_FMT_UYVY8_1X16 || 1368c2ecf20Sopenharmony_ci code == MEDIA_BUS_FMT_YUYV8_2X8 || 1378c2ecf20Sopenharmony_ci code == MEDIA_BUS_FMT_YUYV8_1X16) 1388c2ecf20Sopenharmony_ci pixel_fmt = VDI_C_CH_422; 1398c2ecf20Sopenharmony_ci else 1408c2ecf20Sopenharmony_ci pixel_fmt = VDI_C_CH_420; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci reg = ipu_vdi_read(vdi, VDI_C); 1438c2ecf20Sopenharmony_ci reg |= pixel_fmt; 1448c2ecf20Sopenharmony_ci reg |= VDI_C_BURST_SIZE2_4; 1458c2ecf20Sopenharmony_ci reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2; 1468c2ecf20Sopenharmony_ci reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2; 1478c2ecf20Sopenharmony_ci ipu_vdi_write(vdi, reg, VDI_C); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_setup); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_civoid ipu_vdi_unsetup(struct ipu_vdi *vdi) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci unsigned long flags; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 1588c2ecf20Sopenharmony_ci ipu_vdi_write(vdi, 0, VDI_FSIZE); 1598c2ecf20Sopenharmony_ci ipu_vdi_write(vdi, 0, VDI_C); 1608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_unsetup); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ciint ipu_vdi_enable(struct ipu_vdi *vdi) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci unsigned long flags; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (!vdi->use_count) 1718c2ecf20Sopenharmony_ci ipu_module_enable(vdi->ipu, vdi->module); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci vdi->use_count++; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_enable); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ciint ipu_vdi_disable(struct ipu_vdi *vdi) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci unsigned long flags; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdi->lock, flags); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (vdi->use_count) { 1888c2ecf20Sopenharmony_ci if (!--vdi->use_count) 1898c2ecf20Sopenharmony_ci ipu_module_disable(vdi->ipu, vdi->module); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdi->lock, flags); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_disable); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistruct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci return ipu->vdi_priv; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_get); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_civoid ipu_vdi_put(struct ipu_vdi *vdi) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_vdi_put); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciint ipu_vdi_init(struct ipu_soc *ipu, struct device *dev, 2108c2ecf20Sopenharmony_ci unsigned long base, u32 module) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct ipu_vdi *vdi; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL); 2158c2ecf20Sopenharmony_ci if (!vdi) 2168c2ecf20Sopenharmony_ci return -ENOMEM; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ipu->vdi_priv = vdi; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci spin_lock_init(&vdi->lock); 2218c2ecf20Sopenharmony_ci vdi->module = module; 2228c2ecf20Sopenharmony_ci vdi->base = devm_ioremap(dev, base, PAGE_SIZE); 2238c2ecf20Sopenharmony_ci if (!vdi->base) 2248c2ecf20Sopenharmony_ci return -ENOMEM; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base); 2278c2ecf20Sopenharmony_ci vdi->ipu = ipu; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_civoid ipu_vdi_exit(struct ipu_soc *ipu) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci} 235