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