embox

Форк
0
/
ipu_disp.c 
331 строка · 9.8 Кб
1
/**
2
 * @file ipu_disp.c
3
 * @brief Configure channels, waves etc
4
 * @author Denis Deryugin <deryugin.denis@gmail.com>
5
 * @version
6
 * @date 28.08.2018
7
 */
8

9
#include <util/log.h>
10

11
#include <errno.h>
12
#include <stdint.h>
13

14
#include <drivers/lvds/imx/ldb.h>
15
#include <drivers/clk/ccm_imx6.h>
16
#include <drivers/video/fb.h>
17

18
#include "ipu_regs.h"
19
#include "ipu_priv.h"
20

21
#define SYNC_WAVE 0
22
#define NULL_WAVE (-1)
23

24
#define DC_DISP_ID_SYNC(di)	(di)
25

26
static void _ipu_di_data_wave_config(struct ipu_soc *ipu,
27
				int di, int wave_gen,
28
				int access_size, int component_size)
29
{
30
	uint32_t reg;
31
	reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
32
	    (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
33
	ipu_di_write(ipu, di, reg, DI_DW_GEN(wave_gen));
34
}
35

36
static void _ipu_di_data_pin_config(struct ipu_soc *ipu,
37
			int di, int wave_gen, int di_pin, int set,
38
			int up, int down)
39
{
40
	uint32_t reg;
41

42
	reg = ipu_di_read(ipu, di, DI_DW_GEN(wave_gen));
43
	reg &= ~(0x3 << (di_pin * 2));
44
	reg |= set << (di_pin * 2);
45
	ipu_di_write(ipu, di, reg, DI_DW_GEN(wave_gen));
46

47
	ipu_di_write(ipu, di, (down << 16) | up, DI_DW_SET(wave_gen, set));
48
}
49

50
static void _ipu_di_sync_config(struct ipu_soc *ipu,
51
				int di, int wave_gen,
52
				int run_count, int run_src,
53
				int offset_count, int offset_src,
54
				int repeat_count, int cnt_clr_src,
55
				int cnt_polarity_gen_en,
56
				int cnt_polarity_clr_src,
57
				int cnt_polarity_trigger_src,
58
				int cnt_up, int cnt_down)
59
{
60
	uint32_t reg;
61

62
	reg = (run_count << 19) | (++run_src << 16) |
63
	    (offset_count << 3) | ++offset_src;
64
	ipu_di_write(ipu, di, reg, DI_SW_GEN0(wave_gen));
65
	reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) |
66
	    (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9);
67
	reg |= (cnt_down << 16) | cnt_up;
68
	if (repeat_count == 0) {
69
		/* Enable auto reload */
70
		reg |= 0x10000000;
71
	}
72
	ipu_di_write(ipu, di, reg, DI_SW_GEN1(wave_gen));
73
	reg = ipu_di_read(ipu, di, DI_STP_REP(wave_gen));
74
	reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1)));
75
	reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1));
76
	ipu_di_write(ipu, di, reg, DI_STP_REP(wave_gen));
77
}
78

79
static void _ipu_dc_map_config(struct ipu_soc *ipu,
80
		int map, int byte_num, int offset, int mask)
81
{
82
	log_debug("Enter %s", __func__);
83
	int ptr = map * 3 + byte_num;
84
	uint32_t reg;
85

86
	reg = ipu_dc_read(ipu, DC_MAP_CONF_VAL(ptr));
87
	reg &= ~(0xFFFF << (16 * (ptr & 0x1)));
88
	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
89
	ipu_dc_write(ipu, reg, DC_MAP_CONF_VAL(ptr));
90

91
	reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(map));
92
	reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num)));
93
	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
94
	ipu_dc_write(ipu, reg, DC_MAP_CONF_PTR(map));
95
}
96

97
static void _ipu_dc_map_clear(struct ipu_soc *ipu, int map)
98
{
99
	log_debug("Enter %s", __func__);
100
	uint32_t reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(map));
101
	ipu_dc_write(ipu, reg & ~(0xFFFF << (16 * (map & 0x1))),
102
		     DC_MAP_CONF_PTR(map));
103
}
104

105
static void _ipu_dc_write_tmpl(struct ipu_soc *ipu,
106
			int word, uint32_t opcode, uint32_t operand, int map,
107
			int wave, int glue, int sync, int stop)
108
{
109
	log_debug("Enter %s", __func__);
110
	uint32_t reg;
111

112
	if (opcode == WRG) {
113
		reg = sync;
114
		reg |= (glue << 4);
115
		reg |= (++wave << 11);
116
		reg |= ((operand & 0x1FFFF) << 15);
117
		ipu_dc_tmpl_write(ipu, reg, word * 8);
118

119
		reg = (operand >> 17);
120
		reg |= opcode << 7;
121
		reg |= (stop << 9);
122
		ipu_dc_tmpl_write(ipu, reg, word * 8 + 4);
123
	} else {
124
		reg = sync;
125
		reg |= (glue << 4);
126
		reg |= (++wave << 11);
127
		reg |= (++map << 15);
128
		reg |= (operand << 20) & 0xFFF00000;
129
		ipu_dc_tmpl_write(ipu, reg, word * 8);
130

131
		reg = (operand >> 12);
132
		reg |= opcode << 4;
133
		reg |= (stop << 9);
134
		ipu_dc_tmpl_write(ipu, reg, word * 8 + 4);
135
	}
136

137
	log_debug("Exit %s", __func__);
138
}
139

140
static void _ipu_dc_link_event(struct ipu_soc *ipu,
141
		int chan, int event, int addr, int priority)
142
{
143
	uint32_t reg;
144
	reg = ipu_dc_read(ipu, DC_RL_CH(chan, event));
145
	reg &= ~(0xFFFF << (16 * (event & 0x1)));
146
	reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
147
	ipu_dc_write(ipu, reg, DC_RL_CH(chan, event));
148
}
149

150
void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt)
151
{
152
	log_debug("enter %s, dc_chan=%d, di=%d\n", __func__, dc_chan, di);
153
	uint32_t reg;
154

155
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 5, 3);
156
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 6, 2);
157
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 12, 1);
158
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NF, 0, 0);
159
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NFIELD, 0, 0);
160
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOF, 0, 0);
161
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOFIELD, 0, 0);
162
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN, 0, 0);
163
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR, 0, 0);
164

165
	reg = 0x2;
166
	reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
167
	reg |= di << 2;
168

169
	ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
170

171
	ipu_dc_write(ipu, 0x00000000, DC_WR_CH_ADDR(dc_chan));
172

173
	ipu_dc_write(ipu, 0x00000084, DC_GEN);
174
}
175

176
void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan)
177
{
178
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 0, 0);
179
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 0, 0);
180
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 0, 0);
181
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NF, 0, 0);
182
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NFIELD, 0, 0);
183
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOF, 0, 0);
184
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOFIELD, 0, 0);
185
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN, 0, 0);
186
	_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR, 0, 0);
187
}
188

189
void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel)
190
{
191
	uint32_t reg;
192
	uint32_t dc_chan = 5;
193

194
	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
195
	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
196

197
	reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
198
	reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
199
	ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
200

201
	clk_enable("ipu1_di0");
202
}
203

204
enum {
205
	IPU_RGB24_MAP = 0,
206
	IPU_RGB565_MAP = 1,
207
};
208

209
void _ipu_init_dc_mappings(struct ipu_soc *ipu) {
210
	/* Configure maps (used in ipu_init_sync_panel)
211
	 *
212
	 * Configuration is done in the following way:
213
	 *	_ipu_dc_map_config(ipu, MAP, COLOR, OFFSET, CONST)
214
	 *
215
	 *	last const is currently unknown
216
	 *
217
	 *	MAP is just a number 0 ... 5
218
	 *
219
	 *	COLOR is: 0 for RED
220
	 *	          1 for GREEN
221
	 *	          2 for BLUE
222
	 *
223
	 *	OFFSET is the highest bit of the color
224
	 * */
225
	/* RGB24 */
226
	_ipu_dc_map_clear(ipu, IPU_RGB24_MAP);
227
	_ipu_dc_map_config(ipu, IPU_RGB24_MAP, 0, 7, 0xFF);
228
	_ipu_dc_map_config(ipu, IPU_RGB24_MAP, 1, 15, 0xFF);
229
	_ipu_dc_map_config(ipu, IPU_RGB24_MAP, 2, 23, 0xFF);
230
	/* RGB565 */
231
	_ipu_dc_map_clear(ipu, IPU_RGB565_MAP);
232
	_ipu_dc_map_config(ipu, IPU_RGB565_MAP, 0, 5, 0xFC);
233
	_ipu_dc_map_config(ipu, IPU_RGB565_MAP, 1, 11, 0xFC);
234
	_ipu_dc_map_config(ipu, IPU_RGB565_MAP, 2, 17, 0xFC);
235
}
236

237
int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp,
238
			    struct fb_info *fbi,
239
			    uint32_t pixel_fmt) {
240
	uint16_t width = fbi->var.xres;
241
	uint16_t height = fbi->var.yres;
242
	uint16_t h_start_width = fbi->var.left_margin;
243
	uint16_t h_sync_width = fbi->var.hsync_len;
244
	uint16_t h_end_width = fbi->var.right_margin;
245
	uint16_t v_start_width = fbi->var.upper_margin;
246
	uint16_t v_sync_width = fbi->var.vsync_len;
247
	uint16_t v_end_width = fbi->var.lower_margin;
248
	uint32_t reg;
249
	uint32_t di_gen;
250
	uint32_t div;
251
	uint32_t h_total, v_total;
252
	int map;
253

254
	if ((v_sync_width == 0) || (h_sync_width == 0))
255
		return -EINVAL;
256

257
	if (v_end_width < 2) {
258
		v_end_width = 2;
259
		log_debug("Adjusted v_end_width");
260
	}
261

262
	h_total = width + h_sync_width + h_start_width + h_end_width;
263
	v_total = height + v_sync_width + v_start_width + v_end_width;
264

265
	/* try ipu clk first*/
266
	ipu_di_write(ipu, disp, 3 << 20, DI_GENERAL);
267

268
	div = 1;
269

270
	ipu_di_write(ipu, 0, div << 4, DI_BS_CLKGEN0);
271
	ipu_di_write(ipu, 0, div << 16, DI_BS_CLKGEN1);
272

273
	_ipu_di_data_wave_config(ipu, disp, SYNC_WAVE, div - 1, div - 1);
274
	_ipu_di_data_pin_config(ipu, disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
275

276
	/* XXX hardcoded for use with LVDS */
277
	if (ldb_bits() == 18) {
278
		map = IPU_RGB565_MAP;
279
	} else { /* Assume 24 bits */
280
		map = IPU_RGB24_MAP;
281
	}
282

283
	/*clear DI*/
284
	di_gen = ipu_di_read(ipu, disp, DI_GENERAL);
285
	di_gen &= (0x3 << 20);
286
	ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
287
	/* Setup internal HSYNC waveform */
288
	_ipu_di_sync_config(ipu, disp, 1, h_total - 1, DI_SYNC_CLK,
289
				0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
290
				DI_SYNC_NONE, 0, 0);
291
	/* Setup external (delayed) HSYNC waveform */
292
	_ipu_di_sync_config(ipu, disp, DI_SYNC_HSYNC, h_total - 1,
293
			    DI_SYNC_CLK, div * 0, DI_SYNC_CLK,
294
			    0, DI_SYNC_NONE, 1, DI_SYNC_NONE,
295
			    DI_SYNC_CLK, 0, h_sync_width * 2);
296
	/* Setup VSYNC waveform */
297
	_ipu_di_sync_config(ipu, disp, DI_SYNC_VSYNC, v_total - 1,
298
			    DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0,
299
			    DI_SYNC_NONE, 1, DI_SYNC_NONE,
300
			    DI_SYNC_INT_HSYNC, 0, v_sync_width * 2);
301
	ipu_di_write(ipu, disp, v_total - 1, DI_SCR_CONF);
302

303
	/* Setup active data waveform to sync with DC */
304
	_ipu_di_sync_config(ipu, disp, 4, 0, DI_SYNC_HSYNC,
305
			    v_sync_width + v_start_width, DI_SYNC_HSYNC, height,
306
			    DI_SYNC_VSYNC, 0, DI_SYNC_NONE,
307
			    DI_SYNC_NONE, 0, 0);
308
	_ipu_di_sync_config(ipu, disp, 5, 0, DI_SYNC_CLK,
309
			    h_sync_width + h_start_width, DI_SYNC_CLK,
310
			    width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
311

312
	_ipu_dc_write_tmpl(ipu, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
313
	_ipu_dc_write_tmpl(ipu, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
314
	_ipu_dc_write_tmpl(ipu, 7, WRG, 0, map, NULL_WAVE, 0, 0, 1);
315
	_ipu_dc_write_tmpl(ipu, 12, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
316

317
	di_gen |= DI_GEN_POLARITY_DISP_CLK;
318
	di_gen |= (1 << 20);
319
	ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
320

321
	ipu_di_write(ipu, disp, (DI_SYNC_HSYNC << DI_VSYNC_SEL_OFFSET) |
322
			0x00000002, DI_SYNC_AS_GEN);
323
	reg = ipu_di_read(ipu, disp, DI_POL);
324
	reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
325
	reg |= DI_POL_DRDY_POLARITY_15;
326
	ipu_di_write(ipu, disp, reg, DI_POL);
327

328
	ipu_dc_write(ipu, width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));
329

330
	return 0;
331
}
332

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.