162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> 462306a36Sopenharmony_ci * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/export.h> 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <video/imx-ipu-v3.h> 1262306a36Sopenharmony_ci#include "ipu-prv.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define DMFC_RD_CHAN 0x0000 1562306a36Sopenharmony_ci#define DMFC_WR_CHAN 0x0004 1662306a36Sopenharmony_ci#define DMFC_WR_CHAN_DEF 0x0008 1762306a36Sopenharmony_ci#define DMFC_DP_CHAN 0x000c 1862306a36Sopenharmony_ci#define DMFC_DP_CHAN_DEF 0x0010 1962306a36Sopenharmony_ci#define DMFC_GENERAL1 0x0014 2062306a36Sopenharmony_ci#define DMFC_GENERAL2 0x0018 2162306a36Sopenharmony_ci#define DMFC_IC_CTRL 0x001c 2262306a36Sopenharmony_ci#define DMFC_WR_CHAN_ALT 0x0020 2362306a36Sopenharmony_ci#define DMFC_WR_CHAN_DEF_ALT 0x0024 2462306a36Sopenharmony_ci#define DMFC_DP_CHAN_ALT 0x0028 2562306a36Sopenharmony_ci#define DMFC_DP_CHAN_DEF_ALT 0x002c 2662306a36Sopenharmony_ci#define DMFC_GENERAL1_ALT 0x0030 2762306a36Sopenharmony_ci#define DMFC_STAT 0x0034 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define DMFC_WR_CHAN_1_28 0 3062306a36Sopenharmony_ci#define DMFC_WR_CHAN_2_41 8 3162306a36Sopenharmony_ci#define DMFC_WR_CHAN_1C_42 16 3262306a36Sopenharmony_ci#define DMFC_WR_CHAN_2C_43 24 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define DMFC_DP_CHAN_5B_23 0 3562306a36Sopenharmony_ci#define DMFC_DP_CHAN_5F_27 8 3662306a36Sopenharmony_ci#define DMFC_DP_CHAN_6B_24 16 3762306a36Sopenharmony_ci#define DMFC_DP_CHAN_6F_29 24 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct dmfc_channel_data { 4062306a36Sopenharmony_ci int ipu_channel; 4162306a36Sopenharmony_ci unsigned long channel_reg; 4262306a36Sopenharmony_ci unsigned long shift; 4362306a36Sopenharmony_ci unsigned eot_shift; 4462306a36Sopenharmony_ci unsigned max_fifo_lines; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic const struct dmfc_channel_data dmfcdata[] = { 4862306a36Sopenharmony_ci { 4962306a36Sopenharmony_ci .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC, 5062306a36Sopenharmony_ci .channel_reg = DMFC_DP_CHAN, 5162306a36Sopenharmony_ci .shift = DMFC_DP_CHAN_5B_23, 5262306a36Sopenharmony_ci .eot_shift = 20, 5362306a36Sopenharmony_ci .max_fifo_lines = 3, 5462306a36Sopenharmony_ci }, { 5562306a36Sopenharmony_ci .ipu_channel = 24, 5662306a36Sopenharmony_ci .channel_reg = DMFC_DP_CHAN, 5762306a36Sopenharmony_ci .shift = DMFC_DP_CHAN_6B_24, 5862306a36Sopenharmony_ci .eot_shift = 22, 5962306a36Sopenharmony_ci .max_fifo_lines = 1, 6062306a36Sopenharmony_ci }, { 6162306a36Sopenharmony_ci .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC, 6262306a36Sopenharmony_ci .channel_reg = DMFC_DP_CHAN, 6362306a36Sopenharmony_ci .shift = DMFC_DP_CHAN_5F_27, 6462306a36Sopenharmony_ci .eot_shift = 21, 6562306a36Sopenharmony_ci .max_fifo_lines = 2, 6662306a36Sopenharmony_ci }, { 6762306a36Sopenharmony_ci .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC, 6862306a36Sopenharmony_ci .channel_reg = DMFC_WR_CHAN, 6962306a36Sopenharmony_ci .shift = DMFC_WR_CHAN_1_28, 7062306a36Sopenharmony_ci .eot_shift = 16, 7162306a36Sopenharmony_ci .max_fifo_lines = 2, 7262306a36Sopenharmony_ci }, { 7362306a36Sopenharmony_ci .ipu_channel = 29, 7462306a36Sopenharmony_ci .channel_reg = DMFC_DP_CHAN, 7562306a36Sopenharmony_ci .shift = DMFC_DP_CHAN_6F_29, 7662306a36Sopenharmony_ci .eot_shift = 23, 7762306a36Sopenharmony_ci .max_fifo_lines = 1, 7862306a36Sopenharmony_ci }, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct ipu_dmfc_priv; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct dmfc_channel { 8662306a36Sopenharmony_ci unsigned slots; 8762306a36Sopenharmony_ci struct ipu_soc *ipu; 8862306a36Sopenharmony_ci struct ipu_dmfc_priv *priv; 8962306a36Sopenharmony_ci const struct dmfc_channel_data *data; 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistruct ipu_dmfc_priv { 9362306a36Sopenharmony_ci struct ipu_soc *ipu; 9462306a36Sopenharmony_ci struct device *dev; 9562306a36Sopenharmony_ci struct dmfc_channel channels[DMFC_NUM_CHANNELS]; 9662306a36Sopenharmony_ci struct mutex mutex; 9762306a36Sopenharmony_ci void __iomem *base; 9862306a36Sopenharmony_ci int use_count; 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciint ipu_dmfc_enable_channel(struct dmfc_channel *dmfc) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct ipu_dmfc_priv *priv = dmfc->priv; 10462306a36Sopenharmony_ci mutex_lock(&priv->mutex); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (!priv->use_count) 10762306a36Sopenharmony_ci ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci priv->use_count++; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_civoid ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct ipu_dmfc_priv *priv = dmfc->priv; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci mutex_lock(&priv->mutex); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci priv->use_count--; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (!priv->use_count) 12662306a36Sopenharmony_ci ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (priv->use_count < 0) 12962306a36Sopenharmony_ci priv->use_count = 0; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_civoid ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct ipu_dmfc_priv *priv = dmfc->priv; 13862306a36Sopenharmony_ci u32 dmfc_gen1; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci mutex_lock(&priv->mutex); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci dmfc_gen1 = readl(priv->base + DMFC_GENERAL1); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines) 14562306a36Sopenharmony_ci dmfc_gen1 |= 1 << dmfc->data->eot_shift; 14662306a36Sopenharmony_ci else 14762306a36Sopenharmony_ci dmfc_gen1 &= ~(1 << dmfc->data->eot_shift); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci writel(dmfc_gen1, priv->base + DMFC_GENERAL1); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistruct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct ipu_dmfc_priv *priv = ipu->dmfc_priv; 15862306a36Sopenharmony_ci int i; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci for (i = 0; i < DMFC_NUM_CHANNELS; i++) 16162306a36Sopenharmony_ci if (dmfcdata[i].ipu_channel == ipu_channel) 16262306a36Sopenharmony_ci return &priv->channels[i]; 16362306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_get); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_civoid ipu_dmfc_put(struct dmfc_channel *dmfc) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_put); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciint ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, 17362306a36Sopenharmony_ci struct clk *ipu_clk) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct ipu_dmfc_priv *priv; 17662306a36Sopenharmony_ci int i; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 17962306a36Sopenharmony_ci if (!priv) 18062306a36Sopenharmony_ci return -ENOMEM; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci priv->base = devm_ioremap(dev, base, PAGE_SIZE); 18362306a36Sopenharmony_ci if (!priv->base) 18462306a36Sopenharmony_ci return -ENOMEM; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci priv->dev = dev; 18762306a36Sopenharmony_ci priv->ipu = ipu; 18862306a36Sopenharmony_ci mutex_init(&priv->mutex); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ipu->dmfc_priv = priv; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci for (i = 0; i < DMFC_NUM_CHANNELS; i++) { 19362306a36Sopenharmony_ci priv->channels[i].priv = priv; 19462306a36Sopenharmony_ci priv->channels[i].ipu = ipu; 19562306a36Sopenharmony_ci priv->channels[i].data = &dmfcdata[i]; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC || 19862306a36Sopenharmony_ci dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC || 19962306a36Sopenharmony_ci dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC) 20062306a36Sopenharmony_ci priv->channels[i].slots = 2; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci writel(0x00000050, priv->base + DMFC_WR_CHAN); 20462306a36Sopenharmony_ci writel(0x00005654, priv->base + DMFC_DP_CHAN); 20562306a36Sopenharmony_ci writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF); 20662306a36Sopenharmony_ci writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF); 20762306a36Sopenharmony_ci writel(0x00000003, priv->base + DMFC_GENERAL1); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_civoid ipu_dmfc_exit(struct ipu_soc *ipu) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci} 215