Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/ipu-v3/ipu-dmfc.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) 2010 Sascha Hauer <[email protected]>
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
39
struct 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
47
static 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
83
struct ipu_dmfc_priv;
84
85
struct 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
92
struct 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
101
int 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
}
115
EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
116
117
void 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
}
133
EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
134
135
void 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
}
153
EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
154
155
struct 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
}
165
EXPORT_SYMBOL_GPL(ipu_dmfc_get);
166
167
void ipu_dmfc_put(struct dmfc_channel *dmfc)
168
{
169
}
170
EXPORT_SYMBOL_GPL(ipu_dmfc_put);
171
172
int 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
212
void ipu_dmfc_exit(struct ipu_soc *ipu)
213
{
214
}
215
216