aboutsummaryrefslogtreecommitdiff
path: root/board/freescale/common/dcu_sii9022a.c
blob: 9137d246ea0398ebc4091445378ac9ae4929bf0b (plain)
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2014 Freescale Semiconductor, Inc.
 * Copyright 2019 NXP
 */

#include <asm/io.h>
#include <common.h>
#include <fsl_dcu_fb.h>
#include <i2c.h>
#include <linux/fb.h>

#define PIXEL_CLK_LSB_REG		0x00
#define PIXEL_CLK_MSB_REG		0x01
#define VERT_FREQ_LSB_REG		0x02
#define VERT_FREQ_MSB_REG		0x03
#define TOTAL_PIXELS_LSB_REG		0x04
#define TOTAL_PIXELS_MSB_REG		0x05
#define TOTAL_LINES_LSB_REG		0x06
#define TOTAL_LINES_MSB_REG		0x07
#define TPI_INBUS_FMT_REG		0x08
#define TPI_INPUT_FMT_REG		0x09
#define TPI_OUTPUT_FMT_REG		0x0A
#define TPI_SYS_CTRL_REG		0x1A
#define TPI_PWR_STAT_REG		0x1E
#define TPI_AUDIO_HANDING_REG		0x25
#define TPI_AUDIO_INTF_REG		0x26
#define TPI_AUDIO_FREQ_REG		0x27
#define TPI_SET_PAGE_REG		0xBC
#define TPI_SET_OFFSET_REG		0xBD
#define TPI_RW_ACCESS_REG		0xBE
#define TPI_TRANS_MODE_REG		0xC7

#define TPI_INBUS_CLOCK_RATIO_1		(1 << 6)
#define TPI_INBUS_FULL_PIXEL_WIDE	(1 << 5)
#define TPI_INBUS_RISING_EDGE		(1 << 4)
#define TPI_INPUT_CLR_DEPTH_8BIT	(0 << 6)
#define TPI_INPUT_VRANGE_EXPAN_AUTO	(0 << 2)
#define TPI_INPUT_CLR_RGB		(0 << 0)
#define TPI_OUTPUT_CLR_DEPTH_8BIT	(0 << 6)
#define TPI_OUTPUT_VRANGE_COMPRE_AUTO	(0 << 2)
#define TPI_OUTPUT_CLR_HDMI_RGB		(0 << 0)
#define TPI_SYS_TMDS_OUTPUT		(0 << 4)
#define TPI_SYS_AV_NORAML		(0 << 3)
#define TPI_SYS_AV_MUTE			(1 << 3)
#define TPI_SYS_DVI_MODE		(0 << 0)
#define TPI_SYS_HDMI_MODE		(1 << 0)
#define TPI_PWR_STAT_MASK		(3 << 0)
#define TPI_PWR_STAT_D0			(0 << 0)
#define TPI_AUDIO_PASS_BASIC		(0 << 0)
#define TPI_AUDIO_INTF_I2S		(2 << 6)
#define TPI_AUDIO_INTF_NORMAL		(0 << 4)
#define TPI_AUDIO_TYPE_PCM		(1 << 0)
#define TPI_AUDIO_SAMP_SIZE_16BIT	(1 << 6)
#define TPI_AUDIO_SAMP_FREQ_44K		(2 << 3)
#define TPI_SET_PAGE_SII9022A		0x01
#define TPI_SET_OFFSET_SII9022A		0x82
#define TPI_RW_EN_SRC_TERMIN		(1 << 0)
#define TPI_TRANS_MODE_ENABLE		(0 << 7)

/* Programming of Silicon SIi9022a HDMI Transmitter */
int dcu_set_dvi_encoder(struct fb_videomode *videomode)
{
	u8 temp;
	u16 temp1, temp2;
	u32 temp3;
#if CONFIG_IS_ENABLED(DM_I2C)
	struct udevice *dev;
	int ret;

	ret = i2c_get_chip_for_busnum(CONFIG_SYS_I2C_DVI_BUS_NUM,
				      CONFIG_SYS_I2C_DVI_ADDR,
				      1, &dev);
	if (ret) {
		printf("%s: Cannot find udev for a bus %d\n", __func__,
		       CONFIG_SYS_I2C_DVI_BUS_NUM);
		return ret;
	}

	/* Enable TPI transmitter mode */
	temp = TPI_TRANS_MODE_ENABLE;
	dm_i2c_write(dev, TPI_TRANS_MODE_REG, &temp, 1);

	/* Enter into D0 state, full operation */
	dm_i2c_read(dev, TPI_PWR_STAT_REG, &temp, 1);
	temp &= ~TPI_PWR_STAT_MASK;
	temp |= TPI_PWR_STAT_D0;
	dm_i2c_write(dev, TPI_PWR_STAT_REG, &temp, 1);

	/* Enable source termination */
	temp = TPI_SET_PAGE_SII9022A;
	dm_i2c_write(dev, TPI_SET_PAGE_REG, &temp, 1);
	temp = TPI_SET_OFFSET_SII9022A;
	dm_i2c_write(dev, TPI_SET_OFFSET_REG, &temp, 1);

	dm_i2c_read(dev, TPI_RW_ACCESS_REG, &temp, 1);
	temp |= TPI_RW_EN_SRC_TERMIN;
	dm_i2c_write(dev, TPI_RW_ACCESS_REG, &temp, 1);

	/* Set TPI system control */
	temp = TPI_SYS_TMDS_OUTPUT | TPI_SYS_AV_NORAML | TPI_SYS_DVI_MODE;
	dm_i2c_write(dev, TPI_SYS_CTRL_REG, &temp, 1);

	/* Set pixel clock */
	temp1 = PICOS2KHZ(videomode->pixclock) / 10;
	temp = (u8)(temp1 & 0xFF);
	dm_i2c_write(dev, PIXEL_CLK_LSB_REG, &temp, 1);
	temp = (u8)(temp1 >> 8);
	dm_i2c_write(dev, PIXEL_CLK_MSB_REG, &temp, 1);

	/* Set total pixels per line */
	temp1 = videomode->hsync_len + videomode->left_margin +
		videomode->xres + videomode->right_margin;
	temp = (u8)(temp1 & 0xFF);
	dm_i2c_write(dev, TOTAL_PIXELS_LSB_REG, &temp, 1);
	temp = (u8)(temp1 >> 8);
	dm_i2c_write(dev, TOTAL_PIXELS_MSB_REG, &temp, 1);

	/* Set total lines */
	temp2 = videomode->vsync_len + videomode->upper_margin +
		videomode->yres + videomode->lower_margin;
	temp = (u8)(temp2 & 0xFF);
	dm_i2c_write(dev, TOTAL_LINES_LSB_REG, &temp, 1);
	temp = (u8)(temp2 >> 8);
	dm_i2c_write(dev, TOTAL_LINES_MSB_REG, &temp, 1);

	/* Set vertical frequency in Hz */
	temp3 = temp1 * temp2;
	temp3 = (PICOS2KHZ(videomode->pixclock) * 1000) / temp3;
	temp1 = (u16)temp3 * 100;
	temp = (u8)(temp1 & 0xFF);
	dm_i2c_write(dev, VERT_FREQ_LSB_REG, &temp, 1);
	temp = (u8)(temp1 >> 8);
	dm_i2c_write(dev, VERT_FREQ_MSB_REG, &temp, 1);

	/* Set TPI input bus and pixel repetition data */
	temp = TPI_INBUS_CLOCK_RATIO_1 | TPI_INBUS_FULL_PIXEL_WIDE |
		TPI_INBUS_RISING_EDGE;
	dm_i2c_write(dev, TPI_INBUS_FMT_REG, &temp, 1);

	/* Set TPI AVI Input format data */
	temp = TPI_INPUT_CLR_DEPTH_8BIT | TPI_INPUT_VRANGE_EXPAN_AUTO |
		TPI_INPUT_CLR_RGB;
	dm_i2c_write(dev, TPI_INPUT_FMT_REG, &temp, 1);

	/* Set TPI AVI Output format data */
	temp = TPI_OUTPUT_CLR_DEPTH_8BIT | TPI_OUTPUT_VRANGE_COMPRE_AUTO |
		TPI_OUTPUT_CLR_HDMI_RGB;
	dm_i2c_write(dev, TPI_OUTPUT_FMT_REG, &temp, 1);

	/* Set TPI audio configuration write data */
	temp = TPI_AUDIO_PASS_BASIC;
	dm_i2c_write(dev, TPI_AUDIO_HANDING_REG, &temp, 1);

	temp = TPI_AUDIO_INTF_I2S | TPI_AUDIO_INTF_NORMAL |
		TPI_AUDIO_TYPE_PCM;
	dm_i2c_write(dev, TPI_AUDIO_INTF_REG, &temp, 1);

	temp = TPI_AUDIO_SAMP_SIZE_16BIT | TPI_AUDIO_SAMP_FREQ_44K;
	dm_i2c_write(dev, TPI_AUDIO_FREQ_REG, &temp, 1);
#else
	i2c_set_bus_num(CONFIG_SYS_I2C_DVI_BUS_NUM);

	/* Enable TPI transmitter mode */
	temp = TPI_TRANS_MODE_ENABLE;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_TRANS_MODE_REG, 1, &temp, 1);

	/* Enter into D0 state, full operation */
	i2c_read(CONFIG_SYS_I2C_DVI_ADDR, TPI_PWR_STAT_REG, 1, &temp, 1);
	temp &= ~TPI_PWR_STAT_MASK;
	temp |= TPI_PWR_STAT_D0;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_PWR_STAT_REG, 1, &temp, 1);

	/* Enable source termination */
	temp = TPI_SET_PAGE_SII9022A;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_SET_PAGE_REG, 1, &temp, 1);
	temp = TPI_SET_OFFSET_SII9022A;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_SET_OFFSET_REG, 1, &temp, 1);

	i2c_read(CONFIG_SYS_I2C_DVI_ADDR, TPI_RW_ACCESS_REG, 1, &temp, 1);
	temp |= TPI_RW_EN_SRC_TERMIN;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_RW_ACCESS_REG, 1, &temp, 1);

	/* Set TPI system control */
	temp = TPI_SYS_TMDS_OUTPUT | TPI_SYS_AV_NORAML | TPI_SYS_DVI_MODE;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_SYS_CTRL_REG, 1, &temp, 1);

	/* Set pixel clock */
	temp1 = PICOS2KHZ(videomode->pixclock) / 10;
	temp = (u8)(temp1 & 0xFF);
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, PIXEL_CLK_LSB_REG, 1, &temp, 1);
	temp = (u8)(temp1 >> 8);
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, PIXEL_CLK_MSB_REG, 1, &temp, 1);

	/* Set total pixels per line */
	temp1 = videomode->hsync_len + videomode->left_margin +
		videomode->xres + videomode->right_margin;
	temp = (u8)(temp1 & 0xFF);
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TOTAL_PIXELS_LSB_REG, 1, &temp, 1);
	temp = (u8)(temp1 >> 8);
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TOTAL_PIXELS_MSB_REG, 1, &temp, 1);

	/* Set total lines */
	temp2 = videomode->vsync_len + videomode->upper_margin +
		videomode->yres + videomode->lower_margin;
	temp = (u8)(temp2 & 0xFF);
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TOTAL_LINES_LSB_REG, 1, &temp, 1);
	temp = (u8)(temp2 >> 8);
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TOTAL_LINES_MSB_REG, 1, &temp, 1);

	/* Set vertical frequency in Hz */
	temp3 = temp1 * temp2;
	temp3 = (PICOS2KHZ(videomode->pixclock) * 1000) / temp3;
	temp1 = (u16)temp3 * 100;
	temp = (u8)(temp1 & 0xFF);
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, VERT_FREQ_LSB_REG, 1, &temp, 1);
	temp = (u8)(temp1 >> 8);
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, VERT_FREQ_MSB_REG, 1, &temp, 1);

	/* Set TPI input bus and pixel repetition data */
	temp = TPI_INBUS_CLOCK_RATIO_1 | TPI_INBUS_FULL_PIXEL_WIDE |
		TPI_INBUS_RISING_EDGE;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_INBUS_FMT_REG, 1, &temp, 1);

	/* Set TPI AVI Input format data */
	temp = TPI_INPUT_CLR_DEPTH_8BIT | TPI_INPUT_VRANGE_EXPAN_AUTO |
		TPI_INPUT_CLR_RGB;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_INPUT_FMT_REG, 1, &temp, 1);

	/* Set TPI AVI Output format data */
	temp = TPI_OUTPUT_CLR_DEPTH_8BIT | TPI_OUTPUT_VRANGE_COMPRE_AUTO |
		TPI_OUTPUT_CLR_HDMI_RGB;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_OUTPUT_FMT_REG, 1, &temp, 1);

	/* Set TPI audio configuration write data */
	temp = TPI_AUDIO_PASS_BASIC;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_AUDIO_HANDING_REG, 1, &temp, 1);

	temp = TPI_AUDIO_INTF_I2S | TPI_AUDIO_INTF_NORMAL |
		TPI_AUDIO_TYPE_PCM;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_AUDIO_INTF_REG, 1, &temp, 1);

	temp = TPI_AUDIO_SAMP_SIZE_16BIT | TPI_AUDIO_SAMP_FREQ_44K;
	i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_AUDIO_FREQ_REG, 1, &temp, 1);
#endif

	return 0;
}