Linux Audio

Check our new training course

Loading...
v5.4
  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}
v6.13.7
  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}