summaryrefslogtreecommitdiffstats
path: root/src/soc/qualcomm/sc7180/display/dsi.c
blob: e9bd702159981fee52729e9391d3d05acb313294 (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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/* SPDX-License-Identifier: GPL-2.0-only */

#include <mipi/panel.h>
#include <device/mmio.h>
#include <console/console.h>
#include <assert.h>
#include <edid.h>
#include <delay.h>
#include <symbols.h>
#include <types.h>
#include <string.h>
#include <soc/display/mipi_dsi.h>
#include <soc/display/mdssreg.h>
#include <soc/display/dsi_phy.h>

#define DSI_DMA_STREAM1 0x0
#define DSI_EMBED_MODE1 0x1
#define DSI_POWER_MODE2 0x1
#define DSI_PACK_TYPE1 0x0
#define DSI_VC1 0x0
#define DSI_DT1 0x0
#define DSI_WC1 0x0
#define DSI_EOF_BLLP_PWR 0x9
#define DSI_DMA_TRIGGER_SEL 0x4
#define TRAFFIC_MODE 0x1

#define DSI_EN 0x1
#define DSI_CLKLN_EN 0x1
#define DSI_VIDEO_EN 0x1

#define HS_TX_TO 0xEA60
#define TIMER_RESOLUTION 0x4
#define DSI_PAYLOAD_BYTE_BOUND 256
#define DSI_PAYLOAD_SIZE_ALIGN 4
#define DSI_CMD_DMA_TPG_EN  BIT(1)
#define DSI_TPG_DMA_FIFO_MODE BIT(2)
#define DSI_CMD_DMA_PATTERN_SEL (BIT(16) | BIT(17))

static void mdss_dsi_host_init(int num_of_lanes)
{
	uint8_t dlnx_en;
	uint32_t ctrl_mode = BIT(8) | BIT(0); /* Enable DSI and CLKlane. */

	switch (num_of_lanes) {
	default:
	case 1:
		dlnx_en = 1;
		break;

	case 2:
		dlnx_en = 3;
		break;

	case 3:
		dlnx_en = 7;
		break;

	case 4:
		dlnx_en = 0x0F;
		break;
	}

	/*
	 * Need to send pixel data before sending the ON commands
	 * so need to configure controller to VIDEO MODE.
	 */
	ctrl_mode |= BIT(1);

	mdss_dsi_clock_config();
	write32(&dsi0->trig_ctrl, DSI_DMA_STREAM1 << 8 | DSI_DMA_TRIGGER_SEL);
	write32(&dsi0->ctrl, dlnx_en << 4 | ctrl_mode);
	write32(&dsi0->cmd_mode_dma_ctrl,
		DSI_EMBED_MODE1 << 28 | DSI_POWER_MODE2 << 26 |
		DSI_PACK_TYPE1 << 24 | DSI_VC1 << 22 | DSI_DT1 << 16 | DSI_WC1);
	write32(&dsi0->eot_packet_ctrl, 0x1);
}

static void mdss_dsi_reset(void)
{
	/*
	 * Disable DSI Controller, DSI lane states,
	 * DSI command-mode and DSI video-mode engines
	 */
	write32(&dsi0->ctrl, 0x0);

	/* DSI soft reset */
	write32(&dsi0->soft_reset, 0x1);
	write32(&dsi0->soft_reset, 0x0);

	/* set hs timer count speed */
	write32(&dsi0->hs_timer_ctrl, HS_TX_TO | TIMER_RESOLUTION << 16);

	/* dma fifo reset */
	write32(&dsi0->tpg_dma_fifo_reset, 0x1);
	write32(&dsi0->tpg_dma_fifo_reset, 0x0);
}

void mdss_dsi_video_mode_config(struct edid *edid, uint32_t bpp)
{
	uint16_t dst_format;
	uint8_t lane_en = 15; /* Enable 4 lanes by default */
	uint16_t hfp, hbp, vfp, vbp;

	switch (bpp) {
	case 16:
		dst_format = DSI_VIDEO_DST_FORMAT_RGB565;
		break;
	case 18:
		dst_format = DSI_VIDEO_DST_FORMAT_RGB666;
		break;
	case 24:
	default:
		dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
		break;
	}

	hfp = edid->mode.hso;
	hbp = edid->mode.hbl - edid->mode.hso;
	vfp = edid->mode.vso;
	vbp = edid->mode.vbl - edid->mode.vso;

	write32(&dsi0->video_mode_active_h,
		((edid->mode.ha + hbp) << 16) |
		hbp);

	write32(&dsi0->video_mode_active_v,
		((edid->mode.va + vbp) << 16) | (vbp));

	write32(&dsi0->video_mode_active_total,
		((edid->mode.va + vfp +
		 vbp - 1) << 16) |
		(edid->mode.ha + hfp +
		 hbp - 1));

	write32(&dsi0->video_mode_active_hsync, (edid->mode.hspw << 16));
	write32(&dsi0->video_mode_active_vsync, 0x0);
	write32(&dsi0->video_mode_active_vsync_vpos, edid->mode.vspw << 16);

	write32(&dsi0->video_mode_ctrl,
			DSI_EOF_BLLP_PWR << 12 | dst_format << 4 | TRAFFIC_MODE << 8);

	write32(&dsi0->hs_timer_ctrl, HS_TX_TO | TIMER_RESOLUTION << 16);

	write32(&dsi0->ctrl, lane_en << 4 | DSI_VIDEO_EN << 1 | DSI_EN | DSI_CLKLN_EN << 8);
}

enum cb_err mdss_dsi_config(struct edid *edid, uint32_t num_of_lanes, uint32_t bpp)
{
	mdss_dsi_reset();
	if ((mdss_dsi_phy_10nm_init(edid, num_of_lanes, bpp)) != 0) {
		printk(BIOS_ERR, "dsi phy setup returned error\n");
		return CB_ERR;
	}

	mdss_dsi_host_init(num_of_lanes);

	return CB_SUCCESS;
}

void mdss_dsi_clock_config(void)
{
	/* Clock for AHI Bus Master, for DMA out from memory */
	write32(&dsi0->clk_ctrl, 0);
	setbits32(&dsi0->clk_ctrl, DSI_AHBM_SCLK_ON | DSI_FORCE_ON_DYN_AHBM_HCLK);

	/* Clock for MDP/DSI, for DMA out from MDP */
	setbits32(&dsi0->clk_ctrl, DSI_PCLK_ON);

	/* Clock for rest of DSI */
	setbits32(&dsi0->clk_ctrl, DSI_AHBS_HCLK_ON | DSI_DSICLK_ON |
		  DSI_BYTECLK_ON | DSI_ESCCLK_ON);
}

static void mdss_dsi_set_intr(void)
{
	write32(&dsi0->int_ctrl, 0x0);

	/* Enable all HW interrupts. */
	setbits32(&dsi0->int_ctrl, DSI_CMD_MODE_DMA_DONE_MASK | DSI_CMD_MODE_MDP_DONE_MASK |
			DSI_VIDEO_MODE_DONE_MASK | DSI_ERROR_MASK | DSI_BTA_DONE_MASK);
}

static int mdss_dsi_cmd_dma_trigger_for_panel(void)
{
	uint32_t read_value;
	uint32_t count = 0;
	int status = 0;

	mdss_dsi_set_intr();
	write32(&dsi0->cmd_mode_dma_sw_trigger, 0x1);
	dsb();

	read_value = read32(&dsi0->int_ctrl) & 0x1;

	while (read_value != 0x1) {
		read_value = read32(&dsi0->int_ctrl) & 0x1;
		count++;
		if (count > 0xffff) {
			status = -1;
			printk(BIOS_ERR,
				"Panel CMD: count :%d command mode dma test failed\n", count);
			printk(BIOS_ERR,
			       "Panel CMD: read value = %x, addr=%p\n",
			       read_value, (&dsi0->int_ctrl));
			return status;
		}
	}

	write32(&dsi0->int_ctrl, (read32(&dsi0->int_ctrl) | 0x01000001));
	return status;
}

static cb_err_t mdss_dsi_send_init_cmd(enum panel_init_cmd cmd, const u8 *body, u8 len)
{
	uint8_t *pload = _dma_coherent;
	uint32_t size;
	cb_err_t ret = CB_SUCCESS;
	int data = 0;
	uint32_t *bp = NULL;

	/* This implementation only supports DCS commands (I think?). */
	assert(cmd == PANEL_CMD_DCS);

	/* The payload size has to be a multiple of 4 */
	memcpy(pload, body, len);
	size = ALIGN_UP(len, DSI_PAYLOAD_SIZE_ALIGN);
	memset(pload + len, 0xff, size - len);
	assert(size < DSI_PAYLOAD_BYTE_BOUND);

	bp = (uint32_t *)pload;

	/* Enable custom pattern stored in TPG DMA FIFO */
	data = DSI_CMD_DMA_PATTERN_SEL;

	/* select CMD_DMA_FIFO_MODE to 1 */
	data |= DSI_TPG_DMA_FIFO_MODE;
	data |= DSI_CMD_DMA_TPG_EN;

	write32(&dsi0->test_pattern_gen_ctrl, data);
	for (int j = 0; j < size; j += 4) {
		write32(&dsi0->test_pattern_gen_cmd_dma_init_val, *bp);
		bp++;
	}

	if ((size % 8) != 0)
		write32(&dsi0->test_pattern_gen_cmd_dma_init_val, 0x0);

	write32(&dsi0->dma_cmd_length, size);
	write32(&dsi0->cmd_mode_dma_sw_trigger, 0x1);
	if (mdss_dsi_cmd_dma_trigger_for_panel())
		ret = CB_ERR;

	/* Reset the DMA TPG FIFO */
	write32(&dsi0->tpg_dma_fifo_reset, 0x1);
	write32(&dsi0->tpg_dma_fifo_reset, 0x0);

	/* Disable CMD_DMA_TPG */
	write32(&dsi0->test_pattern_gen_ctrl, 0x0);

	udelay(80);

	return ret;
}

static void mdss_dsi_clear_intr(void)
{
	write32(&dsi0->int_ctrl, 0x0);

	/* Clear all the hardware interrupts */
	setbits32(&dsi0->int_ctrl, DSI_CMD_MODE_DMA_DONE_AK | DSI_CMD_MODE_MDP_DONE_AK |
			DSI_VIDEO_MODE_DONE_AK |  DSI_BTA_DONE_AK | DSI_ERROR_AK);
	write32(&dsi0->err_int_mask0, 0x13FF3BFF);
}

cb_err_t mdss_dsi_panel_initialize(const u8 *init_cmds)
{
	uint32_t ctrl_mode = 0;

	assert(init_cmds != NULL);
	ctrl_mode = read32(&dsi0->ctrl);

	/* Enable command mode before sending the commands */
	write32(&dsi0->ctrl, ctrl_mode | 0x04);

	cb_err_t ret = mipi_panel_parse_init_commands(init_cmds, mdss_dsi_send_init_cmd);
	write32(&dsi0->ctrl, ctrl_mode);
	mdss_dsi_clear_intr();

	return ret;
}