1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
|
/*
* Copyright (C) 2017 NXP
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <linux/device.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <video/videomode.h>
#include <drm/drm_fourcc.h>
#include <video/imx-dcss.h>
#include "dcss-prv.h"
#define USE_CTXLD
#define DCSS_SS_SYS_CTRL 0x00
#define RUN_EN BIT(0)
#define DCSS_SS_DISPLAY 0x10
#define LRC_X_POS 0
#define LRC_X_MASK GENMASK(12, 0)
#define LRC_Y_POS 16
#define LRC_Y_MASK GENMASK(28, 16)
#define DCSS_SS_HSYNC 0x20
#define DCSS_SS_VSYNC 0x30
#define SYNC_START_POS 0
#define SYNC_START_MASK GENMASK(12, 0)
#define SYNC_END_POS 16
#define SYNC_END_MASK GENMASK(28, 16)
#define SYNC_POL BIT(31)
#define DCSS_SS_DE_ULC 0x40
#define ULC_X_POS 0
#define ULC_X_MASK GENMASK(12, 0)
#define ULC_Y_POS 16
#define ULC_Y_MASK GENMASK(28, 16)
#define ULC_POL BIT(31)
#define DCSS_SS_DE_LRC 0x50
#define DCSS_SS_MODE 0x60
#define PIPE_MODE_POS 0
#define PIPE_MODE_MASK GENMASK(1, 0)
#define DCSS_SS_COEFF 0x70
#define HORIZ_A_POS 0
#define HORIZ_A_MASK GENMASK(3, 0)
#define HORIZ_B_POS 4
#define HORIZ_B_MASK GENMASK(7, 4)
#define HORIZ_C_POS 8
#define HORIZ_C_MASK GENMASK(11, 8)
#define HORIZ_H_NORM_POS 12
#define HORIZ_H_NORM_MASK GENMASK(14, 12)
#define VERT_A_POS 16
#define VERT_A_MASK GENMASK(19, 16)
#define VERT_B_POS 20
#define VERT_B_MASK GENMASK(23, 20)
#define VERT_C_POS 24
#define VERT_C_MASK GENMASK(27, 24)
#define VERT_H_NORM_POS 28
#define VERT_H_NORM_MASK GENMASK(30, 28)
#define DCSS_SS_CLIP_CB 0x80
#define DCSS_SS_CLIP_CR 0x90
#define CLIP_MIN_POS 0
#define CLIP_MIN_MASK GENMASK(9, 0)
#define CLIP_MAX_POS 0
#define CLIP_MAX_MASK GENMASK(23, 16)
#define DCSS_SS_INTER_MODE 0xA0
#define INT_EN BIT(0)
#define VSYNC_SHIFT BIT(1)
static struct dcss_debug_reg ss_debug_reg[] = {
DCSS_DBG_REG(DCSS_SS_SYS_CTRL),
DCSS_DBG_REG(DCSS_SS_DISPLAY),
DCSS_DBG_REG(DCSS_SS_HSYNC),
DCSS_DBG_REG(DCSS_SS_VSYNC),
DCSS_DBG_REG(DCSS_SS_DE_ULC),
DCSS_DBG_REG(DCSS_SS_DE_LRC),
DCSS_DBG_REG(DCSS_SS_MODE),
DCSS_DBG_REG(DCSS_SS_COEFF),
DCSS_DBG_REG(DCSS_SS_CLIP_CB),
DCSS_DBG_REG(DCSS_SS_CLIP_CR),
DCSS_DBG_REG(DCSS_SS_INTER_MODE),
};
struct dcss_ss_priv {
struct dcss_soc *dcss;
void __iomem *base_reg;
u32 base_ofs;
u32 ctx_id;
bool in_use;
};
static void dcss_ss_write(struct dcss_ss_priv *ss, u32 val, u32 ofs)
{
if (!ss->in_use)
dcss_writel(val, ss->base_reg + ofs);
#if defined(USE_CTXLD)
dcss_ctxld_write(ss->dcss, ss->ctx_id, val,
ss->base_ofs + ofs);
#endif
}
#ifdef CONFIG_DEBUG_FS
void dcss_ss_dump_regs(struct seq_file *s, void *data)
{
struct dcss_soc *dcss = data;
int j;
seq_puts(s, ">> Dumping SUBSAM:\n");
for (j = 0; j < ARRAY_SIZE(ss_debug_reg); j++)
seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
ss_debug_reg[j].name,
ss_debug_reg[j].ofs,
dcss_readl(dcss->ss_priv->base_reg +
ss_debug_reg[j].ofs));
}
#endif
int dcss_ss_init(struct dcss_soc *dcss, unsigned long ss_base)
{
struct dcss_ss_priv *ss;
ss = devm_kzalloc(dcss->dev, sizeof(*ss), GFP_KERNEL);
if (!ss)
return -ENOMEM;
dcss->ss_priv = ss;
ss->dcss = dcss;
ss->base_reg = devm_ioremap(dcss->dev, ss_base, SZ_4K);
if (!ss->base_reg) {
dev_err(dcss->dev, "ss: unable to remap ss base\n");
return -ENOMEM;
}
ss->base_ofs = ss_base;
#if defined(USE_CTXLD)
ss->ctx_id = CTX_SB_HP;
#endif
return 0;
}
void dcss_ss_exit(struct dcss_soc *dcss)
{
dcss_writel(0, dcss->ss_priv->base_reg + DCSS_SS_SYS_CTRL);
}
void dcss_ss_subsam_set(struct dcss_soc *dcss, u32 pix_format)
{
if (pix_format == DRM_FORMAT_P010) {
dcss_ss_write(dcss->ss_priv, 0x21612161, DCSS_SS_COEFF);
dcss_ss_write(dcss->ss_priv, 2, DCSS_SS_MODE);
dcss_ss_write(dcss->ss_priv, 0x03c00040, DCSS_SS_CLIP_CB);
dcss_ss_write(dcss->ss_priv, 0x03c00040, DCSS_SS_CLIP_CR);
return;
}
dcss_ss_write(dcss->ss_priv, 0x41614161, DCSS_SS_COEFF);
dcss_ss_write(dcss->ss_priv, 0, DCSS_SS_MODE);
dcss_ss_write(dcss->ss_priv, 0x03ff0000, DCSS_SS_CLIP_CB);
dcss_ss_write(dcss->ss_priv, 0x03ff0000, DCSS_SS_CLIP_CR);
}
void dcss_ss_sync_set(struct dcss_soc *dcss, struct videomode *vm,
bool phsync, bool pvsync)
{
struct dcss_ss_priv *ss = dcss->ss_priv;
u16 lrc_x, lrc_y;
u16 hsync_start, hsync_end;
u16 vsync_start, vsync_end;
u16 de_ulc_x, de_ulc_y;
u16 de_lrc_x, de_lrc_y;
lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
vm->hactive - 1;
lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
vm->vactive - 1;
dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
vm->hactive - 1;
hsync_end = vm->hsync_len - 1;
dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
(hsync_end << SYNC_END_POS) | hsync_start,
DCSS_SS_HSYNC);
vsync_start = vm->vfront_porch - 1;
vsync_end = vm->vfront_porch + vm->vsync_len - 1;
dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
(vsync_end << SYNC_END_POS) | vsync_start, DCSS_SS_VSYNC);
de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
dcss_ss_write(ss, SYNC_POL | (de_ulc_y << ULC_Y_POS) | de_ulc_x,
DCSS_SS_DE_ULC);
de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
vm->vactive - 1;
dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
}
EXPORT_SYMBOL(dcss_ss_sync_set);
void dcss_ss_enable(struct dcss_soc *dcss, bool en)
{
struct dcss_ss_priv *ss = dcss->ss_priv;
dcss_ss_write(ss, en ? RUN_EN : 0, DCSS_SS_SYS_CTRL);
}
EXPORT_SYMBOL(dcss_ss_enable);
|