linux/drivers/gpu/ipu-v3/ipu-dmfc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
   4 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
   5 */
   6#include <linux/export.h>
   7#include <linux/types.h>
   8#include <linux/errno.h>
   9#include <linux/io.h>
  10
  11#include <video/imx-ipu-v3.h>
  12#include "ipu-prv.h"
  13
  14#define DMFC_RD_CHAN            0x0000
  15#define DMFC_WR_CHAN            0x0004
  16#define DMFC_WR_CHAN_DEF        0x0008
  17#define DMFC_DP_CHAN            0x000c
  18#define DMFC_DP_CHAN_DEF        0x0010
  19#define DMFC_GENERAL1           0x0014
  20#define DMFC_GENERAL2           0x0018
  21#define DMFC_IC_CTRL            0x001c
  22#define DMFC_WR_CHAN_ALT        0x0020
  23#define DMFC_WR_CHAN_DEF_ALT    0x0024
  24#define DMFC_DP_CHAN_ALT        0x0028
  25#define DMFC_DP_CHAN_DEF_ALT    0x002c
  26#define DMFC_GENERAL1_ALT       0x0030
  27#define DMFC_STAT               0x0034
  28
  29#define DMFC_WR_CHAN_1_28               0
  30#define DMFC_WR_CHAN_2_41               8
  31#define DMFC_WR_CHAN_1C_42              16
  32#define DMFC_WR_CHAN_2C_43              24
  33
  34#define DMFC_DP_CHAN_5B_23              0
  35#define DMFC_DP_CHAN_5F_27              8
  36#define DMFC_DP_CHAN_6B_24              16
  37#define DMFC_DP_CHAN_6F_29              24
  38
  39struct dmfc_channel_data {
  40        int             ipu_channel;
  41        unsigned long   channel_reg;
  42        unsigned long   shift;
  43        unsigned        eot_shift;
  44        unsigned        max_fifo_lines;
  45};
  46
  47static const struct dmfc_channel_data dmfcdata[] = {
  48        {
  49                .ipu_channel    = IPUV3_CHANNEL_MEM_BG_SYNC,
  50                .channel_reg    = DMFC_DP_CHAN,
  51                .shift          = DMFC_DP_CHAN_5B_23,
  52                .eot_shift      = 20,
  53                .max_fifo_lines = 3,
  54        }, {
  55                .ipu_channel    = 24,
  56                .channel_reg    = DMFC_DP_CHAN,
  57                .shift          = DMFC_DP_CHAN_6B_24,
  58                .eot_shift      = 22,
  59                .max_fifo_lines = 1,
  60        }, {
  61                .ipu_channel    = IPUV3_CHANNEL_MEM_FG_SYNC,
  62                .channel_reg    = DMFC_DP_CHAN,
  63                .shift          = DMFC_DP_CHAN_5F_27,
  64                .eot_shift      = 21,
  65                .max_fifo_lines = 2,
  66        }, {
  67                .ipu_channel    = IPUV3_CHANNEL_MEM_DC_SYNC,
  68                .channel_reg    = DMFC_WR_CHAN,
  69                .shift          = DMFC_WR_CHAN_1_28,
  70                .eot_shift      = 16,
  71                .max_fifo_lines = 2,
  72        }, {
  73                .ipu_channel    = 29,
  74                .channel_reg    = DMFC_DP_CHAN,
  75                .shift          = DMFC_DP_CHAN_6F_29,
  76                .eot_shift      = 23,
  77                .max_fifo_lines = 1,
  78        },
  79};
  80
  81#define DMFC_NUM_CHANNELS       ARRAY_SIZE(dmfcdata)
  82
  83struct ipu_dmfc_priv;
  84
  85struct dmfc_channel {
  86        unsigned                        slots;
  87        struct ipu_soc                  *ipu;
  88        struct ipu_dmfc_priv            *priv;
  89        const struct dmfc_channel_data  *data;
  90};
  91
  92struct ipu_dmfc_priv {
  93        struct ipu_soc *ipu;
  94        struct device *dev;
  95        struct dmfc_channel channels[DMFC_NUM_CHANNELS];
  96        struct mutex mutex;
  97        void __iomem *base;
  98        int use_count;
  99};
 100
 101int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
 102{
 103        struct ipu_dmfc_priv *priv = dmfc->priv;
 104        mutex_lock(&priv->mutex);
 105
 106        if (!priv->use_count)
 107                ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
 108
 109        priv->use_count++;
 110
 111        mutex_unlock(&priv->mutex);
 112
 113        return 0;
 114}
 115EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
 116
 117void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
 118{
 119        struct ipu_dmfc_priv *priv = dmfc->priv;
 120
 121        mutex_lock(&priv->mutex);
 122
 123        priv->use_count--;
 124
 125        if (!priv->use_count)
 126                ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
 127
 128        if (priv->use_count < 0)
 129                priv->use_count = 0;
 130
 131        mutex_unlock(&priv->mutex);
 132}
 133EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
 134
 135void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
 136{
 137        struct ipu_dmfc_priv *priv = dmfc->priv;
 138        u32 dmfc_gen1;
 139
 140        mutex_lock(&priv->mutex);
 141
 142        dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
 143
 144        if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
 145                dmfc_gen1 |= 1 << dmfc->data->eot_shift;
 146        else
 147                dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
 148
 149        writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
 150
 151        mutex_unlock(&priv->mutex);
 152}
 153EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
 154
 155struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
 156{
 157        struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
 158        int i;
 159
 160        for (i = 0; i < DMFC_NUM_CHANNELS; i++)
 161                if (dmfcdata[i].ipu_channel == ipu_channel)
 162                        return &priv->channels[i];
 163        return ERR_PTR(-ENODEV);
 164}
 165EXPORT_SYMBOL_GPL(ipu_dmfc_get);
 166
 167void ipu_dmfc_put(struct dmfc_channel *dmfc)
 168{
 169}
 170EXPORT_SYMBOL_GPL(ipu_dmfc_put);
 171
 172int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
 173                struct clk *ipu_clk)
 174{
 175        struct ipu_dmfc_priv *priv;
 176        int i;
 177
 178        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 179        if (!priv)
 180                return -ENOMEM;
 181
 182        priv->base = devm_ioremap(dev, base, PAGE_SIZE);
 183        if (!priv->base)
 184                return -ENOMEM;
 185
 186        priv->dev = dev;
 187        priv->ipu = ipu;
 188        mutex_init(&priv->mutex);
 189
 190        ipu->dmfc_priv = priv;
 191
 192        for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
 193                priv->channels[i].priv = priv;
 194                priv->channels[i].ipu = ipu;
 195                priv->channels[i].data = &dmfcdata[i];
 196
 197                if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
 198                    dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
 199                    dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
 200                        priv->channels[i].slots = 2;
 201        }
 202
 203        writel(0x00000050, priv->base + DMFC_WR_CHAN);
 204        writel(0x00005654, priv->base + DMFC_DP_CHAN);
 205        writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
 206        writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
 207        writel(0x00000003, priv->base + DMFC_GENERAL1);
 208
 209        return 0;
 210}
 211
 212void ipu_dmfc_exit(struct ipu_soc *ipu)
 213{
 214}
 215