linux/drivers/gpu/ipu-v3/ipu-vdi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2012-2016 Mentor Graphics Inc.
   4 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
   5 */
   6#include <linux/io.h>
   7#include "ipu-prv.h"
   8
   9struct ipu_vdi {
  10        void __iomem *base;
  11        u32 module;
  12        spinlock_t lock;
  13        int use_count;
  14        struct ipu_soc *ipu;
  15};
  16
  17
  18/* VDI Register Offsets */
  19#define VDI_FSIZE 0x0000
  20#define VDI_C     0x0004
  21
  22/* VDI Register Fields */
  23#define VDI_C_CH_420             (0 << 1)
  24#define VDI_C_CH_422             (1 << 1)
  25#define VDI_C_MOT_SEL_MASK       (0x3 << 2)
  26#define VDI_C_MOT_SEL_FULL       (2 << 2)
  27#define VDI_C_MOT_SEL_LOW        (1 << 2)
  28#define VDI_C_MOT_SEL_MED        (0 << 2)
  29#define VDI_C_BURST_SIZE1_4      (3 << 4)
  30#define VDI_C_BURST_SIZE2_4      (3 << 8)
  31#define VDI_C_BURST_SIZE3_4      (3 << 12)
  32#define VDI_C_BURST_SIZE_MASK    0xF
  33#define VDI_C_BURST_SIZE1_OFFSET 4
  34#define VDI_C_BURST_SIZE2_OFFSET 8
  35#define VDI_C_BURST_SIZE3_OFFSET 12
  36#define VDI_C_VWM1_SET_1         (0 << 16)
  37#define VDI_C_VWM1_SET_2         (1 << 16)
  38#define VDI_C_VWM1_CLR_2         (1 << 19)
  39#define VDI_C_VWM3_SET_1         (0 << 22)
  40#define VDI_C_VWM3_SET_2         (1 << 22)
  41#define VDI_C_VWM3_CLR_2         (1 << 25)
  42#define VDI_C_TOP_FIELD_MAN_1    (1 << 30)
  43#define VDI_C_TOP_FIELD_AUTO_1   (1 << 31)
  44
  45static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
  46{
  47        return readl(vdi->base + offset);
  48}
  49
  50static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
  51                                 unsigned int offset)
  52{
  53        writel(value, vdi->base + offset);
  54}
  55
  56void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
  57{
  58        bool top_field_0 = false;
  59        unsigned long flags;
  60        u32 reg;
  61
  62        switch (field) {
  63        case V4L2_FIELD_INTERLACED_TB:
  64        case V4L2_FIELD_SEQ_TB:
  65        case V4L2_FIELD_TOP:
  66                top_field_0 = true;
  67                break;
  68        case V4L2_FIELD_INTERLACED_BT:
  69        case V4L2_FIELD_SEQ_BT:
  70        case V4L2_FIELD_BOTTOM:
  71                top_field_0 = false;
  72                break;
  73        default:
  74                top_field_0 = (std & V4L2_STD_525_60) ? true : false;
  75                break;
  76        }
  77
  78        spin_lock_irqsave(&vdi->lock, flags);
  79
  80        reg = ipu_vdi_read(vdi, VDI_C);
  81        if (top_field_0)
  82                reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
  83        else
  84                reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
  85        ipu_vdi_write(vdi, reg, VDI_C);
  86
  87        spin_unlock_irqrestore(&vdi->lock, flags);
  88}
  89EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
  90
  91void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
  92{
  93        unsigned long flags;
  94        u32 reg;
  95
  96        spin_lock_irqsave(&vdi->lock, flags);
  97
  98        reg = ipu_vdi_read(vdi, VDI_C);
  99
 100        reg &= ~VDI_C_MOT_SEL_MASK;
 101
 102        switch (motion_sel) {
 103        case MED_MOTION:
 104                reg |= VDI_C_MOT_SEL_MED;
 105                break;
 106        case HIGH_MOTION:
 107                reg |= VDI_C_MOT_SEL_FULL;
 108                break;
 109        default:
 110                reg |= VDI_C_MOT_SEL_LOW;
 111                break;
 112        }
 113
 114        ipu_vdi_write(vdi, reg, VDI_C);
 115
 116        spin_unlock_irqrestore(&vdi->lock, flags);
 117}
 118EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
 119
 120void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
 121{
 122        unsigned long flags;
 123        u32 pixel_fmt, reg;
 124
 125        spin_lock_irqsave(&vdi->lock, flags);
 126
 127        reg = ((yres - 1) << 16) | (xres - 1);
 128        ipu_vdi_write(vdi, reg, VDI_FSIZE);
 129
 130        /*
 131         * Full motion, only vertical filter is used.
 132         * Burst size is 4 accesses
 133         */
 134        if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
 135            code == MEDIA_BUS_FMT_UYVY8_1X16 ||
 136            code == MEDIA_BUS_FMT_YUYV8_2X8 ||
 137            code == MEDIA_BUS_FMT_YUYV8_1X16)
 138                pixel_fmt = VDI_C_CH_422;
 139        else
 140                pixel_fmt = VDI_C_CH_420;
 141
 142        reg = ipu_vdi_read(vdi, VDI_C);
 143        reg |= pixel_fmt;
 144        reg |= VDI_C_BURST_SIZE2_4;
 145        reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
 146        reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
 147        ipu_vdi_write(vdi, reg, VDI_C);
 148
 149        spin_unlock_irqrestore(&vdi->lock, flags);
 150}
 151EXPORT_SYMBOL_GPL(ipu_vdi_setup);
 152
 153void ipu_vdi_unsetup(struct ipu_vdi *vdi)
 154{
 155        unsigned long flags;
 156
 157        spin_lock_irqsave(&vdi->lock, flags);
 158        ipu_vdi_write(vdi, 0, VDI_FSIZE);
 159        ipu_vdi_write(vdi, 0, VDI_C);
 160        spin_unlock_irqrestore(&vdi->lock, flags);
 161}
 162EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
 163
 164int ipu_vdi_enable(struct ipu_vdi *vdi)
 165{
 166        unsigned long flags;
 167
 168        spin_lock_irqsave(&vdi->lock, flags);
 169
 170        if (!vdi->use_count)
 171                ipu_module_enable(vdi->ipu, vdi->module);
 172
 173        vdi->use_count++;
 174
 175        spin_unlock_irqrestore(&vdi->lock, flags);
 176
 177        return 0;
 178}
 179EXPORT_SYMBOL_GPL(ipu_vdi_enable);
 180
 181int ipu_vdi_disable(struct ipu_vdi *vdi)
 182{
 183        unsigned long flags;
 184
 185        spin_lock_irqsave(&vdi->lock, flags);
 186
 187        if (vdi->use_count) {
 188                if (!--vdi->use_count)
 189                        ipu_module_disable(vdi->ipu, vdi->module);
 190        }
 191
 192        spin_unlock_irqrestore(&vdi->lock, flags);
 193
 194        return 0;
 195}
 196EXPORT_SYMBOL_GPL(ipu_vdi_disable);
 197
 198struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
 199{
 200        return ipu->vdi_priv;
 201}
 202EXPORT_SYMBOL_GPL(ipu_vdi_get);
 203
 204void ipu_vdi_put(struct ipu_vdi *vdi)
 205{
 206}
 207EXPORT_SYMBOL_GPL(ipu_vdi_put);
 208
 209int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
 210                 unsigned long base, u32 module)
 211{
 212        struct ipu_vdi *vdi;
 213
 214        vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
 215        if (!vdi)
 216                return -ENOMEM;
 217
 218        ipu->vdi_priv = vdi;
 219
 220        spin_lock_init(&vdi->lock);
 221        vdi->module = module;
 222        vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
 223        if (!vdi->base)
 224                return -ENOMEM;
 225
 226        dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
 227        vdi->ipu = ipu;
 228
 229        return 0;
 230}
 231
 232void ipu_vdi_exit(struct ipu_soc *ipu)
 233{
 234}
 235