215 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 0x000015#define DMFC_WR_CHAN 0x000416#define DMFC_WR_CHAN_DEF 0x000817#define DMFC_DP_CHAN 0x000c18#define DMFC_DP_CHAN_DEF 0x001019#define DMFC_GENERAL1 0x001420#define DMFC_GENERAL2 0x001821#define DMFC_IC_CTRL 0x001c22#define DMFC_WR_CHAN_ALT 0x002023#define DMFC_WR_CHAN_DEF_ALT 0x002424#define DMFC_DP_CHAN_ALT 0x002825#define DMFC_DP_CHAN_DEF_ALT 0x002c26#define DMFC_GENERAL1_ALT 0x003027#define DMFC_STAT 0x003428 29#define DMFC_WR_CHAN_1_28 030#define DMFC_WR_CHAN_2_41 831#define DMFC_WR_CHAN_1C_42 1632#define DMFC_WR_CHAN_2C_43 2433 34#define DMFC_DP_CHAN_5B_23 035#define DMFC_DP_CHAN_5F_27 836#define DMFC_DP_CHAN_6B_24 1637#define DMFC_DP_CHAN_6F_29 2438 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 else147 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