1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 239b9004dSPhilipp Zabel /* 339b9004dSPhilipp Zabel * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> 439b9004dSPhilipp Zabel * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. 539b9004dSPhilipp Zabel */ 639b9004dSPhilipp Zabel #include <linux/export.h> 739b9004dSPhilipp Zabel #include <linux/types.h> 839b9004dSPhilipp Zabel #include <linux/errno.h> 939b9004dSPhilipp Zabel #include <linux/io.h> 1039b9004dSPhilipp Zabel 1139b9004dSPhilipp Zabel #include <video/imx-ipu-v3.h> 1239b9004dSPhilipp Zabel #include "ipu-prv.h" 1339b9004dSPhilipp Zabel 1439b9004dSPhilipp Zabel #define DMFC_RD_CHAN 0x0000 1539b9004dSPhilipp Zabel #define DMFC_WR_CHAN 0x0004 1639b9004dSPhilipp Zabel #define DMFC_WR_CHAN_DEF 0x0008 1739b9004dSPhilipp Zabel #define DMFC_DP_CHAN 0x000c 1839b9004dSPhilipp Zabel #define DMFC_DP_CHAN_DEF 0x0010 1939b9004dSPhilipp Zabel #define DMFC_GENERAL1 0x0014 2039b9004dSPhilipp Zabel #define DMFC_GENERAL2 0x0018 2139b9004dSPhilipp Zabel #define DMFC_IC_CTRL 0x001c 22682b7c1cSLinus Torvalds #define DMFC_WR_CHAN_ALT 0x0020 23682b7c1cSLinus Torvalds #define DMFC_WR_CHAN_DEF_ALT 0x0024 24682b7c1cSLinus Torvalds #define DMFC_DP_CHAN_ALT 0x0028 25682b7c1cSLinus Torvalds #define DMFC_DP_CHAN_DEF_ALT 0x002c 26682b7c1cSLinus Torvalds #define DMFC_GENERAL1_ALT 0x0030 27682b7c1cSLinus Torvalds #define DMFC_STAT 0x0034 2839b9004dSPhilipp Zabel 2939b9004dSPhilipp Zabel #define DMFC_WR_CHAN_1_28 0 3039b9004dSPhilipp Zabel #define DMFC_WR_CHAN_2_41 8 3139b9004dSPhilipp Zabel #define DMFC_WR_CHAN_1C_42 16 3239b9004dSPhilipp Zabel #define DMFC_WR_CHAN_2C_43 24 3339b9004dSPhilipp Zabel 3439b9004dSPhilipp Zabel #define DMFC_DP_CHAN_5B_23 0 3539b9004dSPhilipp Zabel #define DMFC_DP_CHAN_5F_27 8 3639b9004dSPhilipp Zabel #define DMFC_DP_CHAN_6B_24 16 3739b9004dSPhilipp Zabel #define DMFC_DP_CHAN_6F_29 24 3839b9004dSPhilipp Zabel 3939b9004dSPhilipp Zabel struct dmfc_channel_data { 4039b9004dSPhilipp Zabel int ipu_channel; 4139b9004dSPhilipp Zabel unsigned long channel_reg; 4239b9004dSPhilipp Zabel unsigned long shift; 4339b9004dSPhilipp Zabel unsigned eot_shift; 4439b9004dSPhilipp Zabel unsigned max_fifo_lines; 4539b9004dSPhilipp Zabel }; 4639b9004dSPhilipp Zabel 4739b9004dSPhilipp Zabel static const struct dmfc_channel_data dmfcdata[] = { 4839b9004dSPhilipp Zabel { 4939b9004dSPhilipp Zabel .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC, 5039b9004dSPhilipp Zabel .channel_reg = DMFC_DP_CHAN, 5139b9004dSPhilipp Zabel .shift = DMFC_DP_CHAN_5B_23, 5239b9004dSPhilipp Zabel .eot_shift = 20, 5339b9004dSPhilipp Zabel .max_fifo_lines = 3, 5439b9004dSPhilipp Zabel }, { 5539b9004dSPhilipp Zabel .ipu_channel = 24, 5639b9004dSPhilipp Zabel .channel_reg = DMFC_DP_CHAN, 5739b9004dSPhilipp Zabel .shift = DMFC_DP_CHAN_6B_24, 5839b9004dSPhilipp Zabel .eot_shift = 22, 5939b9004dSPhilipp Zabel .max_fifo_lines = 1, 6039b9004dSPhilipp Zabel }, { 6139b9004dSPhilipp Zabel .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC, 6239b9004dSPhilipp Zabel .channel_reg = DMFC_DP_CHAN, 6339b9004dSPhilipp Zabel .shift = DMFC_DP_CHAN_5F_27, 6439b9004dSPhilipp Zabel .eot_shift = 21, 6539b9004dSPhilipp Zabel .max_fifo_lines = 2, 6639b9004dSPhilipp Zabel }, { 6739b9004dSPhilipp Zabel .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC, 6839b9004dSPhilipp Zabel .channel_reg = DMFC_WR_CHAN, 6939b9004dSPhilipp Zabel .shift = DMFC_WR_CHAN_1_28, 7039b9004dSPhilipp Zabel .eot_shift = 16, 7139b9004dSPhilipp Zabel .max_fifo_lines = 2, 7239b9004dSPhilipp Zabel }, { 7339b9004dSPhilipp Zabel .ipu_channel = 29, 7439b9004dSPhilipp Zabel .channel_reg = DMFC_DP_CHAN, 7539b9004dSPhilipp Zabel .shift = DMFC_DP_CHAN_6F_29, 7639b9004dSPhilipp Zabel .eot_shift = 23, 7739b9004dSPhilipp Zabel .max_fifo_lines = 1, 7839b9004dSPhilipp Zabel }, 7939b9004dSPhilipp Zabel }; 8039b9004dSPhilipp Zabel 8139b9004dSPhilipp Zabel #define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata) 8239b9004dSPhilipp Zabel 8339b9004dSPhilipp Zabel struct ipu_dmfc_priv; 8439b9004dSPhilipp Zabel 8539b9004dSPhilipp Zabel struct dmfc_channel { 8639b9004dSPhilipp Zabel unsigned slots; 8739b9004dSPhilipp Zabel struct ipu_soc *ipu; 8839b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv; 8939b9004dSPhilipp Zabel const struct dmfc_channel_data *data; 9039b9004dSPhilipp Zabel }; 9139b9004dSPhilipp Zabel 9239b9004dSPhilipp Zabel struct ipu_dmfc_priv { 9339b9004dSPhilipp Zabel struct ipu_soc *ipu; 9439b9004dSPhilipp Zabel struct device *dev; 9539b9004dSPhilipp Zabel struct dmfc_channel channels[DMFC_NUM_CHANNELS]; 9639b9004dSPhilipp Zabel struct mutex mutex; 9739b9004dSPhilipp Zabel void __iomem *base; 9839b9004dSPhilipp Zabel int use_count; 9939b9004dSPhilipp Zabel }; 10039b9004dSPhilipp Zabel 10139b9004dSPhilipp Zabel int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc) 10239b9004dSPhilipp Zabel { 10339b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 10439b9004dSPhilipp Zabel mutex_lock(&priv->mutex); 10539b9004dSPhilipp Zabel 10639b9004dSPhilipp Zabel if (!priv->use_count) 10739b9004dSPhilipp Zabel ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN); 10839b9004dSPhilipp Zabel 10939b9004dSPhilipp Zabel priv->use_count++; 11039b9004dSPhilipp Zabel 11139b9004dSPhilipp Zabel mutex_unlock(&priv->mutex); 11239b9004dSPhilipp Zabel 11339b9004dSPhilipp Zabel return 0; 11439b9004dSPhilipp Zabel } 11539b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); 11639b9004dSPhilipp Zabel 11739b9004dSPhilipp Zabel void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) 11839b9004dSPhilipp Zabel { 11939b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 12039b9004dSPhilipp Zabel 12139b9004dSPhilipp Zabel mutex_lock(&priv->mutex); 12239b9004dSPhilipp Zabel 12339b9004dSPhilipp Zabel priv->use_count--; 12439b9004dSPhilipp Zabel 125448ae8eaSLiu Ying if (!priv->use_count) 12639b9004dSPhilipp Zabel ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); 12739b9004dSPhilipp Zabel 12839b9004dSPhilipp Zabel if (priv->use_count < 0) 12939b9004dSPhilipp Zabel priv->use_count = 0; 13039b9004dSPhilipp Zabel 13139b9004dSPhilipp Zabel mutex_unlock(&priv->mutex); 13239b9004dSPhilipp Zabel } 13339b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel); 13439b9004dSPhilipp Zabel 13527630c20SLiu Ying void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width) 13639b9004dSPhilipp Zabel { 13739b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = dmfc->priv; 13839b9004dSPhilipp Zabel u32 dmfc_gen1; 13939b9004dSPhilipp Zabel 14032c26a56SLiu Ying mutex_lock(&priv->mutex); 14132c26a56SLiu Ying 14239b9004dSPhilipp Zabel dmfc_gen1 = readl(priv->base + DMFC_GENERAL1); 14339b9004dSPhilipp Zabel 14439b9004dSPhilipp Zabel if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines) 14539b9004dSPhilipp Zabel dmfc_gen1 |= 1 << dmfc->data->eot_shift; 14639b9004dSPhilipp Zabel else 14739b9004dSPhilipp Zabel dmfc_gen1 &= ~(1 << dmfc->data->eot_shift); 14839b9004dSPhilipp Zabel 14939b9004dSPhilipp Zabel writel(dmfc_gen1, priv->base + DMFC_GENERAL1); 15039b9004dSPhilipp Zabel 15132c26a56SLiu Ying mutex_unlock(&priv->mutex); 15239b9004dSPhilipp Zabel } 15327630c20SLiu Ying EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot); 15439b9004dSPhilipp Zabel 15539b9004dSPhilipp Zabel struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel) 15639b9004dSPhilipp Zabel { 15739b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv = ipu->dmfc_priv; 15839b9004dSPhilipp Zabel int i; 15939b9004dSPhilipp Zabel 16039b9004dSPhilipp Zabel for (i = 0; i < DMFC_NUM_CHANNELS; i++) 16139b9004dSPhilipp Zabel if (dmfcdata[i].ipu_channel == ipu_channel) 16239b9004dSPhilipp Zabel return &priv->channels[i]; 16339b9004dSPhilipp Zabel return ERR_PTR(-ENODEV); 16439b9004dSPhilipp Zabel } 16539b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_get); 16639b9004dSPhilipp Zabel 16739b9004dSPhilipp Zabel void ipu_dmfc_put(struct dmfc_channel *dmfc) 16839b9004dSPhilipp Zabel { 16939b9004dSPhilipp Zabel } 17039b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_put); 17139b9004dSPhilipp Zabel 17239b9004dSPhilipp Zabel int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, 17339b9004dSPhilipp Zabel struct clk *ipu_clk) 17439b9004dSPhilipp Zabel { 17539b9004dSPhilipp Zabel struct ipu_dmfc_priv *priv; 17639b9004dSPhilipp Zabel int i; 17739b9004dSPhilipp Zabel 17839b9004dSPhilipp Zabel priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 17939b9004dSPhilipp Zabel if (!priv) 18039b9004dSPhilipp Zabel return -ENOMEM; 18139b9004dSPhilipp Zabel 18239b9004dSPhilipp Zabel priv->base = devm_ioremap(dev, base, PAGE_SIZE); 18339b9004dSPhilipp Zabel if (!priv->base) 18439b9004dSPhilipp Zabel return -ENOMEM; 18539b9004dSPhilipp Zabel 18639b9004dSPhilipp Zabel priv->dev = dev; 18739b9004dSPhilipp Zabel priv->ipu = ipu; 18839b9004dSPhilipp Zabel mutex_init(&priv->mutex); 18939b9004dSPhilipp Zabel 19039b9004dSPhilipp Zabel ipu->dmfc_priv = priv; 19139b9004dSPhilipp Zabel 19239b9004dSPhilipp Zabel for (i = 0; i < DMFC_NUM_CHANNELS; i++) { 19339b9004dSPhilipp Zabel priv->channels[i].priv = priv; 19439b9004dSPhilipp Zabel priv->channels[i].ipu = ipu; 19539b9004dSPhilipp Zabel priv->channels[i].data = &dmfcdata[i]; 196d7868cb7SLiu Ying 197d7868cb7SLiu Ying if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC || 198d7868cb7SLiu Ying dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC || 199d7868cb7SLiu Ying dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC) 200d7868cb7SLiu Ying priv->channels[i].slots = 2; 20139b9004dSPhilipp Zabel } 20239b9004dSPhilipp Zabel 203d7868cb7SLiu Ying writel(0x00000050, priv->base + DMFC_WR_CHAN); 204d7868cb7SLiu Ying writel(0x00005654, priv->base + DMFC_DP_CHAN); 20539b9004dSPhilipp Zabel writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF); 20639b9004dSPhilipp Zabel writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF); 20739b9004dSPhilipp Zabel writel(0x00000003, priv->base + DMFC_GENERAL1); 20839b9004dSPhilipp Zabel 20939b9004dSPhilipp Zabel return 0; 21039b9004dSPhilipp Zabel } 21139b9004dSPhilipp Zabel 21239b9004dSPhilipp Zabel void ipu_dmfc_exit(struct ipu_soc *ipu) 21339b9004dSPhilipp Zabel { 21439b9004dSPhilipp Zabel } 215