tree: drop last paragraph of GPL copyright header
[coreboot.git] / src / soc / samsung / exynos5250 / fb.c
blob4091900fbc089e085c488c54594d1e3f9c199583
1 /*
2 * This file is part of the coreboot project.
4 * Copyright 2013 Google Inc.
5 * Copyright (C) 2012 Samsung Electronics
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 /* LCD driver for Exynos */
19 #include <arch/io.h>
20 #include <console/console.h>
21 #include <delay.h>
22 #include <soc/dp.h>
23 #include <soc/dp-core.h>
24 #include <soc/fimd.h>
25 #include <soc/i2c.h>
26 #include <soc/power.h>
27 #include <soc/sysreg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <timer.h>
33 * Here is the rough outline of how we bring up the display:
34 * 1. Upon power-on Sink generates a hot plug detection pulse thru HPD
35 * 2. Source determines video mode by reading DPCD receiver capability field
36 * (DPCD 00000h to 0000Dh) including eDP CP capability register (DPCD
37 * 0000Dh).
38 * 3. Sink replies DPCD receiver capability field.
39 * 4. Source starts EDID read thru I2C-over-AUX.
40 * 5. Sink replies EDID thru I2C-over-AUX.
41 * 6. Source determines link configuration, such as MAX_LINK_RATE and
42 * MAX_LANE_COUNT. Source also determines which type of eDP Authentication
43 * method to use and writes DPCD link configuration field (DPCD 00100h to
44 * 0010Ah) including eDP configuration set (DPCD 0010Ah).
45 * 7. Source starts link training. Sink does clock recovery and equalization.
46 * 8. Source reads DPCD link status field (DPCD 00200h to 0020Bh).
47 * 9. Sink replies DPCD link status field. If main link is not stable, Source
48 * repeats Step 7.
49 * 10. Source sends MSA (Main Stream Attribute) data. Sink extracts video
50 * parameters and recovers stream clock.
51 * 11. Source sends video data.
54 /* To help debug any init errors here, define a list of possible errors */
55 enum {
56 ERR_PLL_NOT_UNLOCKED = 2,
57 ERR_VIDEO_CLOCK_BAD,
58 ERR_VIDEO_STREAM_BAD,
59 ERR_DPCD_READ_ERROR1, /* 5 */
61 ERR_DPCD_WRITE_ERROR1,
62 ERR_DPCD_READ_ERROR2,
63 ERR_DPCD_WRITE_ERROR2,
64 ERR_INVALID_LANE,
65 ERR_PLL_NOT_LOCKED, /* 10 */
67 ERR_PRE_EMPHASIS_LEVELS,
68 ERR_LINK_RATE_ABNORMAL,
69 ERR_MAX_LANE_COUNT_ABNORMAL,
70 ERR_LINK_TRAINING_FAILURE,
71 ERR_MISSING_DP_BASE, /* 15 */
73 ERR_NO_FDT_NODE,
75 /* ok, this is stupid, but we're going to leave the variables in here until we
76 * know it works. One cleanup task at a time.
78 enum stage_t {
79 STAGE_START = 0,
80 STAGE_LCD_VDD,
81 STAGE_BRIDGE_SETUP,
82 STAGE_BRIDGE_INIT,
83 STAGE_BRIDGE_RESET,
84 STAGE_HOTPLUG,
85 STAGE_DP_CONTROLLER,
86 STAGE_BACKLIGHT_VDD,
87 STAGE_BACKLIGHT_PWM,
88 STAGE_BACKLIGHT_EN,
89 STAGE_DONE,
92 int lcd_line_length;
93 int lcd_color_fg;
94 int lcd_color_bg;
96 void *lcd_console_address; /* Start of console buffer */
98 short console_col;
99 short console_row;
101 /* Bypass FIMD of DISP1_BLK */
102 static void fimd_bypass(void)
104 setbits_le32(&exynos_sysreg->disp1blk_cfg, FIMDBYPASS_DISP1);
105 exynos_sysreg->disp1blk_cfg &= ~FIMDBYPASS_DISP1;
109 * Initialize display controller.
111 * @param lcdbase pointer to the base address of framebuffer.
112 * @param pd pointer to the main panel_data structure
114 void fb_init(unsigned long int fb_size, void *lcdbase,
115 struct exynos5_fimd_panel *pd)
117 unsigned int val;
119 fb_size = ALIGN(fb_size, 4096);
121 write32(&exynos_disp_ctrl->vidcon1, pd->ivclk | pd->fixvclk);
122 val = ENVID_ON | ENVID_F_ON | (pd->clkval_f << CLKVAL_F_OFFSET);
123 write32(&exynos_fimd->vidcon0, val);
125 val = (pd->vsync << VSYNC_PULSE_WIDTH_OFFSET) |
126 (pd->lower_margin << V_FRONT_PORCH_OFFSET) |
127 (pd->upper_margin << V_BACK_PORCH_OFFSET);
128 write32(&exynos_disp_ctrl->vidtcon0, val);
130 val = (pd->hsync << HSYNC_PULSE_WIDTH_OFFSET) |
131 (pd->right_margin << H_FRONT_PORCH_OFFSET) |
132 (pd->left_margin << H_BACK_PORCH_OFFSET);
133 write32(&exynos_disp_ctrl->vidtcon1, val);
135 val = ((pd->xres - 1) << HOZVAL_OFFSET) |
136 ((pd->yres - 1) << LINEVAL_OFFSET);
137 write32(&exynos_disp_ctrl->vidtcon2, val);
139 write32(&exynos_fimd->vidw00add0b0, (unsigned int)lcdbase);
140 write32(&exynos_fimd->vidw00add1b0, (unsigned int)lcdbase + fb_size);
142 write32(&exynos_fimd->vidw00add2, pd->xres * 2);
144 val = ((pd->xres - 1) << OSD_RIGHTBOTX_F_OFFSET);
145 val |= ((pd->yres - 1) << OSD_RIGHTBOTY_F_OFFSET);
146 write32(&exynos_fimd->vidosd0b, val);
147 write32(&exynos_fimd->vidosd0c, pd->xres * pd->yres);
149 setbits_le32(&exynos_fimd->shadowcon, CHANNEL0_EN);
151 val = BPPMODE_F_RGB_16BIT_565 << BPPMODE_F_OFFSET;
152 val |= ENWIN_F_ENABLE | HALF_WORD_SWAP_EN;
153 write32(&exynos_fimd->wincon0, val);
155 /* DPCLKCON_ENABLE */
156 write32(&exynos_fimd->dpclkcon, 1 << 1);
159 #ifdef UNUSED_CODE
160 void exynos_fimd_disable(void)
162 write32(&exynos_fimd->wincon0, 0);
163 clrbits_le32(&exynos_fimd->shadowcon, CHANNEL0_EN);
165 #endif
168 * Configure DP in slave mode and wait for video stream.
170 * param dp pointer to main s5p-dp structure
171 * param video_info pointer to main video_info structure.
172 * return status
174 static int s5p_dp_config_video(struct s5p_dp_device *dp,
175 struct video_info *video_info)
177 int timeout = 0;
178 struct exynos5_dp *base = dp->base;
179 struct stopwatch sw;
180 s5p_dp_config_video_slave_mode(dp, video_info);
182 s5p_dp_set_video_color_format(dp, video_info->color_depth,
183 video_info->color_space,
184 video_info->dynamic_range,
185 video_info->ycbcr_coeff);
187 if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
188 printk(BIOS_DEBUG, "PLL is not locked yet.\n");
189 return -ERR_PLL_NOT_UNLOCKED;
192 stopwatch_init_msecs_expire(&sw, STREAM_ON_TIMEOUT);
193 do {
194 if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) {
195 timeout++;
196 break;
198 } while (!stopwatch_expired(&sw));
200 if (!timeout) {
201 printk(BIOS_ERR, "Video Clock Not ok after %ldus.\n",
202 stopwatch_duration_usecs(&sw));
203 return -ERR_VIDEO_CLOCK_BAD;
206 /* Set to use the register calculated M/N video */
207 s5p_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
209 clrbits_le32(&base->video_ctl_10, FORMAT_SEL);
211 /* Disable video mute */
212 clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE);
214 /* Configure video slave mode */
215 s5p_dp_enable_video_master(dp);
217 /* Enable video */
218 setbits_le32(&base->video_ctl_1, VIDEO_EN);
219 timeout = s5p_dp_is_video_stream_on(dp);
221 if (timeout) {
222 printk(BIOS_DEBUG, "Video Stream Not on\n");
223 return -ERR_VIDEO_STREAM_BAD;
226 return 0;
230 * Set DP to enhanced mode. We use this for EVT1
231 * param dp pointer to main s5p-dp structure
232 * return status
234 static int s5p_dp_enable_rx_to_enhanced_mode(struct s5p_dp_device *dp)
236 u8 data;
238 if (s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data)) {
239 printk(BIOS_DEBUG, "DPCD read error\n");
240 return -ERR_DPCD_READ_ERROR1;
242 if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
243 DPCD_ENHANCED_FRAME_EN |
244 (data & DPCD_LANE_COUNT_SET_MASK))) {
245 printk(BIOS_DEBUG, "DPCD write error\n");
246 return -ERR_DPCD_WRITE_ERROR1;
249 return 0;
253 * Enable scrambles mode. We use this for EVT1
254 * param dp pointer to main s5p-dp structure
255 * return status
257 static int s5p_dp_enable_scramble(struct s5p_dp_device *dp)
259 u8 data;
260 struct exynos5_dp *base = dp->base;
262 clrbits_le32(&base->dp_training_ptn_set, SCRAMBLING_DISABLE);
264 if (s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET,
265 &data)) {
266 printk(BIOS_DEBUG, "DPCD read error\n");
267 return -ERR_DPCD_READ_ERROR2;
270 if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET,
271 (u8)(data & ~DPCD_SCRAMBLING_DISABLED))) {
272 printk(BIOS_DEBUG, "DPCD write error\n");
273 return -ERR_DPCD_WRITE_ERROR2;
276 return 0;
280 * Reset DP and prepare DP for init training
281 * param dp pointer to main s5p-dp structure
283 static int s5p_dp_init_dp(struct s5p_dp_device *dp)
285 int ret, i;
286 struct exynos5_dp *base = dp->base;
288 for (i = 0; i < DP_INIT_TRIES; i++) {
289 s5p_dp_reset(dp);
291 /* SW defined function Normal operation */
292 clrbits_le32(&base->func_en_1, SW_FUNC_EN_N);
294 ret = s5p_dp_init_analog_func(dp);
295 if (!ret)
296 break;
298 udelay(5000);
299 printk(BIOS_DEBUG, "LCD retry init, attempt=%d ret=%d\n", i, ret);
301 if (i == DP_INIT_TRIES) {
302 printk(BIOS_DEBUG, "LCD initialization failed, ret=%d\n", ret);
303 return ret;
306 s5p_dp_init_aux(dp);
308 return ret;
312 * Set pre-emphasis level
313 * param dp pointer to main s5p-dp structure
314 * param pre_emphasis pre-emphasis level
315 * param lane lane number(0 - 3)
316 * return status
318 static int s5p_dp_set_lane_lane_pre_emphasis(struct s5p_dp_device *dp,
319 int pre_emphasis, int lane)
321 u32 reg;
322 struct exynos5_dp *base = dp->base;
324 reg = pre_emphasis << PRE_EMPHASIS_SET_SHIFT;
325 switch (lane) {
326 case 0:
327 write32(&base->ln0_link_trn_ctl, reg);
328 break;
329 case 1:
330 write32(&base->ln1_link_trn_ctl, reg);
331 break;
333 case 2:
334 write32(&base->ln2_link_trn_ctl, reg);
335 break;
337 case 3:
338 write32(&base->ln3_link_trn_ctl, reg);
339 break;
340 default:
341 printk(BIOS_DEBUG, "%s: Invalid lane %d\n", __func__, lane);
342 return -ERR_INVALID_LANE;
344 return 0;
348 * Read supported bandwidth type
349 * param dp pointer to main s5p-dp structure
350 * param bandwidth pointer to variable holding bandwidth type
352 static void s5p_dp_get_max_rx_bandwidth(struct s5p_dp_device *dp,
353 u8 *bandwidth)
355 u8 data;
358 * For DP rev.1.1, Maximum link rate of Main Link lanes
359 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
361 s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
362 *bandwidth = data;
366 * Reset DP and prepare DP for init training
367 * param dp pointer to main s5p-dp structure
368 * param lane_count pointer to variable holding no of lanes
370 static void s5p_dp_get_max_rx_lane_count(struct s5p_dp_device *dp,
371 u8 *lane_count)
373 u8 data;
376 * For DP rev.1.1, Maximum number of Main Link lanes
377 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
379 s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
380 *lane_count = data & DPCD_MAX_LANE_COUNT_MASK;
384 * DP H/w Link Training. Set DPCD link rate and bandwidth.
385 * param dp pointer to main s5p-dp structure
386 * param max_lane No of lanes
387 * param max_rate bandwidth
388 * return status
390 static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
391 unsigned int max_lane,
392 unsigned int max_rate)
394 int pll_is_locked = 0;
395 u32 data;
396 int lane;
397 struct stopwatch sw;
398 struct exynos5_dp *base = dp->base;
400 /* Stop Video */
401 clrbits_le32(&base->video_ctl_1, VIDEO_EN);
403 stopwatch_init_msecs_expire(&sw, PLL_LOCK_TIMEOUT);
405 while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) {
406 if (stopwatch_expired(&sw)) {
407 /* Ignore this error, and try to continue */
408 printk(BIOS_ERR, "PLL is not locked yet.\n");
409 break;
412 printk(BIOS_SPEW, "PLL is %slocked\n",
413 pll_is_locked == PLL_LOCKED ? "": "not ");
414 /* Reset Macro */
415 setbits_le32(&base->dp_phy_test, MACRO_RST);
417 /* 10 us is the minimum reset time. */
418 udelay(10);
420 clrbits_le32(&base->dp_phy_test, MACRO_RST);
422 /* Set TX pre-emphasis to minimum */
423 for (lane = 0; lane < max_lane; lane++)
424 if (s5p_dp_set_lane_lane_pre_emphasis(dp,
425 PRE_EMPHASIS_LEVEL_0, lane)) {
426 printk(BIOS_DEBUG, "Unable to set pre emphasis level\n");
427 return -ERR_PRE_EMPHASIS_LEVELS;
430 /* All DP analog module power up */
431 write32(&base->dp_phy_pd, 0x00);
433 /* Initialize by reading RX's DPCD */
434 s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
435 s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
437 printk(BIOS_SPEW, "%s: rate 0x%x, lane_count %d\n", __func__,
438 dp->link_train.link_rate, dp->link_train.lane_count);
440 if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
441 (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
442 printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n",
443 dp->link_train.link_rate);
444 /* Not Retrying */
445 return -ERR_LINK_RATE_ABNORMAL;
448 if (dp->link_train.lane_count == 0) {
449 printk(BIOS_DEBUG, "Rx Max Lane count is abnormal :%x !\n",
450 dp->link_train.lane_count);
451 /* Not retrying */
452 return -ERR_MAX_LANE_COUNT_ABNORMAL;
455 /* Setup TX lane count & rate */
456 if (dp->link_train.lane_count > max_lane)
457 dp->link_train.lane_count = max_lane;
458 if (dp->link_train.link_rate > max_rate)
459 dp->link_train.link_rate = max_rate;
461 /* Set link rate and count as you want to establish*/
462 write32(&base->lane_count_set, dp->link_train.lane_count);
463 write32(&base->link_bw_set, dp->link_train.link_rate);
465 /* Set sink to D0 (Sink Not Ready) mode. */
466 s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE,
467 DPCD_SET_POWER_STATE_D0);
469 /* Start HW link training */
470 write32(&base->dp_hw_link_training, HW_TRAINING_EN);
472 /* Wait until HW link training done */
473 s5p_dp_wait_hw_link_training_done(dp);
475 /* Get hardware link training status */
476 data = read32(&base->dp_hw_link_training);
477 printk(BIOS_SPEW, "hardware link training status: 0x%08x\n", data);
478 if (data != 0) {
479 printk(BIOS_ERR, " H/W link training failure: 0x%x\n", data);
480 return -ERR_LINK_TRAINING_FAILURE;
483 /* Get Link Bandwidth */
484 data = read32(&base->link_bw_set);
486 dp->link_train.link_rate = data;
488 data = read32(&base->lane_count_set);
489 dp->link_train.lane_count = data;
490 printk(BIOS_SPEW, "Done training: Link bandwidth: 0x%x, lane_count: %d\n",
491 dp->link_train.link_rate, data);
493 return 0;
497 * Initialize DP display
499 int dp_controller_init(struct s5p_dp_device *dp_device)
501 int ret;
502 struct s5p_dp_device *dp = dp_device;
503 struct exynos5_dp *base;
505 clock_init_dp_clock();
507 power_enable_dp_phy();
508 ret = s5p_dp_init_dp(dp);
509 if (ret) {
510 printk(BIOS_ERR, "%s: Could not initialize dp\n", __func__);
511 return ret;
514 ret = s5p_dp_hw_link_training(dp, dp->video_info->lane_count,
515 dp->video_info->link_rate);
516 if (ret) {
517 printk(BIOS_ERR, "unable to do link train\n");
518 return ret;
520 /* Minimum delay after H/w Link training */
521 udelay(1000);
523 ret = s5p_dp_enable_scramble(dp);
524 if (ret) {
525 printk(BIOS_ERR, "unable to set scramble mode\n");
526 return ret;
529 ret = s5p_dp_enable_rx_to_enhanced_mode(dp);
530 if (ret) {
531 printk(BIOS_ERR, "unable to set enhanced mode\n");
532 return ret;
536 base = dp->base;
537 /* Enable enhanced mode */
538 setbits_le32(&base->sys_ctl_4, ENHANCED);
540 write32(&base->lane_count_set, dp->link_train.lane_count);
541 write32(&base->link_bw_set, dp->link_train.link_rate);
543 s5p_dp_init_video(dp);
544 ret = s5p_dp_config_video(dp, dp->video_info);
545 if (ret) {
546 printk(BIOS_ERR, "unable to config video\n");
547 return ret;
550 return 0;
554 * Init the LCD controller
556 * @param lcdbase Base address of LCD frame buffer
557 * @return 0 if ok, -ve error code on error
559 int lcd_ctrl_init(unsigned long int fb_size,
560 struct exynos5_fimd_panel *panel_data, void *lcdbase)
562 int ret = 0;
564 fimd_bypass();
565 fb_init(fb_size, lcdbase, panel_data);
566 return ret;