1 /* 2 * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <config.h> 8 #include <common.h> 9 #include <errno.h> 10 #include <malloc.h> 11 #include <fdtdec.h> 12 #include <fdt_support.h> 13 #include <asm/unaligned.h> 14 #include <linux/list.h> 15 #include <asm/io.h> 16 #include <dm/device.h> 17 #include <syscon.h> 18 #include <asm/arch-rockchip/clock.h> 19 #include <asm/gpio.h> 20 21 22 #include "rockchip_display.h" 23 #include "rockchip_crtc.h" 24 #include "rockchip_connector.h" 25 #include "rockchip_lvds.h" 26 27 enum rockchip_lvds_sub_devtype { 28 RK3288_LVDS, 29 RK3366_LVDS, 30 RK3368_LVDS, 31 }; 32 33 struct rockchip_lvds_chip_data { 34 u32 chip_type; 35 bool has_vop_sel; 36 u32 grf_soc_con5; 37 u32 grf_soc_con6; 38 u32 grf_soc_con7; 39 u32 grf_soc_con15; 40 u32 grf_gpio1d_iomux; 41 }; 42 43 struct rockchip_lvds_device { 44 u32 regbase; 45 void *grf; 46 u32 ctrl_reg; 47 u32 channel; 48 u32 output; 49 u32 format; 50 struct drm_display_mode *mode; 51 const struct rockchip_lvds_chip_data *pdata; 52 }; 53 54 static inline int lvds_name_to_format(const char *s) 55 { 56 if (!s) 57 return -EINVAL; 58 59 if (strncmp(s, "jeida", 6) == 0) 60 return LVDS_FORMAT_JEIDA; 61 else if (strncmp(s, "vesa", 5) == 0) 62 return LVDS_FORMAT_VESA; 63 64 return -EINVAL; 65 } 66 67 static inline int lvds_name_to_output(const char *s) 68 { 69 if (!s) 70 return -EINVAL; 71 72 if (strncmp(s, "rgb", 3) == 0) 73 return DISPLAY_OUTPUT_RGB; 74 else if (strncmp(s, "lvds", 4) == 0) 75 return DISPLAY_OUTPUT_LVDS; 76 else if (strncmp(s, "duallvds", 8) == 0) 77 return DISPLAY_OUTPUT_DUAL_LVDS; 78 79 return -EINVAL; 80 } 81 82 static inline void lvds_writel(struct rockchip_lvds_device *lvds, 83 u32 offset, u32 val) 84 { 85 writel(val, lvds->regbase + offset); 86 87 if ((lvds->pdata->chip_type == RK3288_LVDS) && 88 (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS)) 89 writel(val, lvds->regbase + offset + 0x100); 90 } 91 92 static inline void lvds_msk_reg(struct rockchip_lvds_device *lvds, u32 offset, 93 u32 msk, u32 val) 94 { 95 u32 temp; 96 97 temp = readl(lvds->regbase + offset) & (0xFF - (msk)); 98 writel(temp | ((val) & (msk)), lvds->regbase + offset); 99 } 100 101 static inline u32 lvds_readl(struct rockchip_lvds_device *lvds, u32 offset) 102 { 103 return readl(lvds->regbase + offset); 104 } 105 106 static inline void lvds_ctrl_writel(struct rockchip_lvds_device *lvds, 107 u32 offset, u32 val) 108 { 109 writel(val, lvds->ctrl_reg + offset); 110 } 111 112 static inline u32 lvds_pmugrf_readl(u32 offset) 113 { 114 return readl(LVDS_PMUGRF_BASE + offset); 115 } 116 117 static inline void lvds_pmugrf_writel(u32 offset, u32 val) 118 { 119 writel(val, LVDS_PMUGRF_BASE + offset); 120 } 121 122 static inline u32 lvds_phy_lock(struct rockchip_lvds_device *lvds) 123 { 124 u32 val = 0; 125 val = readl(lvds->ctrl_reg + 0x10); 126 val &= 0x1; 127 return val; 128 } 129 130 static int rockchip_lvds_clk_enable(struct rockchip_lvds_device *lvds) 131 { 132 return 0; 133 } 134 135 const struct rockchip_lvds_chip_data rk3366_lvds_drv_data = { 136 .chip_type = RK3366_LVDS, 137 .grf_soc_con7 = RK3366_GRF_SOC_CON5, 138 .grf_soc_con15 = RK3366_GRF_SOC_CON6, 139 .has_vop_sel = true, 140 }; 141 142 const struct rockchip_lvds_chip_data rk3368_lvds_drv_data = { 143 .chip_type = RK3368_LVDS, 144 .grf_soc_con7 = RK3368_GRF_SOC_CON7, 145 .grf_soc_con15 = RK3368_GRF_SOC_CON15, 146 .has_vop_sel = false, 147 }; 148 149 const struct rockchip_lvds_chip_data rk3288_lvds_drv_data = { 150 .chip_type = RK3288_LVDS, 151 .has_vop_sel = true, 152 .grf_soc_con6 = 0x025c, 153 .grf_soc_con7 = 0x0260, 154 .grf_gpio1d_iomux = 0x000c, 155 }; 156 157 static int rk336x_lvds_pwr_off(struct display_state *state) 158 { 159 struct connector_state *conn_state = &state->conn_state; 160 struct rockchip_lvds_device *lvds = conn_state->private; 161 162 /* disable lvds lane and power off pll */ 163 lvds_writel(lvds, MIPIPHY_REGEB, 164 v_LANE0_EN(0) | v_LANE1_EN(0) | v_LANE2_EN(0) | 165 v_LANE3_EN(0) | v_LANECLK_EN(0) | v_PLL_PWR_OFF(1)); 166 167 /* power down lvds pll and bandgap */ 168 lvds_msk_reg(lvds, MIPIPHY_REG1, 169 m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN, 170 v_SYNC_RST(1) | v_LDO_PWR_DOWN(1) | v_PLL_PWR_DOWN(1)); 171 172 /* disable lvds */ 173 lvds_msk_reg(lvds, MIPIPHY_REGE3, m_LVDS_EN | m_TTL_EN, 174 v_LVDS_EN(0) | v_TTL_EN(0)); 175 176 return 0; 177 } 178 179 static int rk3288_lvds_pwr_off(struct display_state *state) 180 { 181 struct connector_state *conn_state = &state->conn_state; 182 struct rockchip_lvds_device *lvds = conn_state->private; 183 184 lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_DISABLE); 185 lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_DISABLE); 186 187 writel(0xffff8000, lvds->grf + lvds->pdata->grf_soc_con7); 188 189 return 0; 190 } 191 192 static int rk336x_lvds_pwr_on(struct display_state *state) 193 { 194 struct connector_state *conn_state = &state->conn_state; 195 struct rockchip_lvds_device *lvds = conn_state->private; 196 u32 delay_times = 20; 197 198 if (lvds->output == DISPLAY_OUTPUT_LVDS) { 199 /* set VOCM 900 mv and V-DIFF 350 mv */ 200 lvds_msk_reg(lvds, MIPIPHY_REGE4, m_VOCM | m_DIFF_V, 201 v_VOCM(0) | v_DIFF_V(2)); 202 /* power up lvds pll and ldo */ 203 lvds_msk_reg(lvds, MIPIPHY_REG1, 204 m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN, 205 v_SYNC_RST(0) | v_LDO_PWR_DOWN(0) | 206 v_PLL_PWR_DOWN(0)); 207 /* enable lvds lane and power on pll */ 208 lvds_writel(lvds, MIPIPHY_REGEB, 209 v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | 210 v_LANE3_EN(1) | v_LANECLK_EN(1) | v_PLL_PWR_OFF(0)); 211 212 /* enable lvds */ 213 lvds_msk_reg(lvds, MIPIPHY_REGE3, 214 m_MIPI_EN | m_LVDS_EN | m_TTL_EN, 215 v_MIPI_EN(0) | v_LVDS_EN(1) | v_TTL_EN(0)); 216 } else { 217 lvds_msk_reg(lvds, MIPIPHY_REGE3, 218 m_MIPI_EN | m_LVDS_EN | m_TTL_EN, 219 v_MIPI_EN(0) | v_LVDS_EN(0) | v_TTL_EN(1)); 220 } 221 /* delay for waitting pll lock on */ 222 while (delay_times--) { 223 if (lvds_phy_lock(lvds)) 224 break; 225 udelay(100); 226 } 227 228 if (delay_times <= 0) 229 printf("wait lvds phy lock failed, please check the hardware!\n"); 230 231 return 0; 232 } 233 234 235 static void rk336x_output_ttl(struct display_state *state) 236 { 237 struct connector_state *conn_state = &state->conn_state; 238 struct rockchip_lvds_device *lvds = conn_state->private; 239 u32 val = 0; 240 241 /* iomux to lcdc */ 242 if (lvds->pdata->chip_type == RK3368_LVDS) { 243 /* lcdc data 11 10 */ 244 lvds_pmugrf_writel(0x04, 0xf0005000); 245 /* lcdc data 12 13 14 15 16 17 18 19 */ 246 lvds_pmugrf_writel(0x08, 0xFFFF5555); 247 /* lcdc data 20 21 22 23 HSYNC VSYNC DEN DCLK */ 248 lvds_pmugrf_writel(0x0c, 0xFFFF5555); 249 /* set clock lane enable */ 250 lvds_ctrl_writel(lvds, 0x0, 0x4); 251 } else { 252 /* lcdc data 15 ... 10, vsync, hsync */ 253 lvds_pmugrf_writel(0x0c, 0xffff555a); 254 /* lcdc data 23 ... 16 */ 255 lvds_pmugrf_writel(0x30, 0xffff5555); 256 /* lcdc dclk, den */ 257 lvds_pmugrf_writel(0x34, 0x000f0005); 258 } 259 260 /* enable lvds mode */ 261 val = v_RK336X_LVDSMODE_EN(0) | v_RK336X_MIPIPHY_TTL_EN(1) | 262 v_RK336X_MIPIPHY_LANE0_EN(1) | 263 v_RK336X_MIPIDPI_FORCEX_EN(1); 264 writel(val, lvds->grf + lvds->pdata->grf_soc_con7); 265 val = v_RK336X_FORCE_JETAG(0); 266 writel(val, lvds->grf + lvds->pdata->grf_soc_con15); 267 268 /* enable lane */ 269 lvds_writel(lvds, MIPIPHY_REG0, 0x7f); 270 val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) | 271 v_LANECLK_EN(1) | v_PLL_PWR_OFF(1); 272 lvds_writel(lvds, MIPIPHY_REGEB, val); 273 274 /* set ttl mode and reset phy config */ 275 val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) | 276 v_MSB_SEL(1) | v_DIG_INTER_RST(1); 277 lvds_writel(lvds, MIPIPHY_REGE0, val); 278 279 rk336x_lvds_pwr_on(state); 280 } 281 282 static void rk336x_output_lvds(struct display_state *state) 283 { 284 struct connector_state *conn_state = &state->conn_state; 285 struct rockchip_lvds_device *lvds = conn_state->private; 286 u32 val = 0; 287 288 /* enable lvds mode */ 289 val |= v_RK336X_LVDSMODE_EN(1) | v_RK336X_MIPIPHY_TTL_EN(0); 290 /* config lvds_format */ 291 val |= v_RK336X_LVDS_OUTPUT_FORMAT(lvds->format); 292 /* LSB receive mode */ 293 val |= v_RK336X_LVDS_MSBSEL(LVDS_MSB_D7); 294 val |= v_RK336X_MIPIPHY_LANE0_EN(1) | 295 v_RK336X_MIPIDPI_FORCEX_EN(1); 296 writel(val, lvds->grf + lvds->pdata->grf_soc_con7); 297 /* digital internal disable */ 298 lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(0)); 299 300 /* set pll prediv and fbdiv */ 301 lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(2) | v_FBDIV_MSB(0)); 302 lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(28)); 303 304 lvds_writel(lvds, MIPIPHY_REGE8, 0xfc); 305 306 /* set lvds mode and reset phy config */ 307 lvds_msk_reg(lvds, MIPIPHY_REGE0, 308 m_MSB_SEL | m_DIG_INTER_RST, 309 v_MSB_SEL(1) | v_DIG_INTER_RST(1)); 310 311 rk336x_lvds_pwr_on(state); 312 lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(1)); 313 } 314 315 static int rk3288_lvds_pwr_on(struct display_state *state) 316 { 317 struct connector_state *conn_state = &state->conn_state; 318 struct rockchip_lvds_device *lvds = conn_state->private; 319 struct drm_display_mode *mode = &conn_state->mode; 320 u32 val; 321 u32 h_bp = mode->htotal - mode->hsync_start; 322 u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0; 323 u8 pin_dclk = (mode->flags & DRM_MODE_FLAG_PCSYNC) ? 1 : 0; 324 325 val = lvds->format; 326 if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS) 327 val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN; 328 else if (lvds->output == DISPLAY_OUTPUT_LVDS) 329 val |= LVDS_CH0_EN; 330 else if (lvds->output == DISPLAY_OUTPUT_RGB) 331 val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN; 332 333 if (h_bp & 0x01) 334 val |= LVDS_START_PHASE_RST_1; 335 336 val |= (pin_dclk << 8) | (pin_hsync << 9); 337 val |= (0xffff << 16); 338 writel(val, lvds->grf + lvds->pdata->grf_soc_con7); 339 340 return 0; 341 } 342 343 static void rk3288_output_ttl(struct display_state *state) 344 { 345 struct connector_state *conn_state = &state->conn_state; 346 struct rockchip_lvds_device *lvds = conn_state->private; 347 348 rk3288_lvds_pwr_on(state); 349 /* iomux: dclk den hsync vsync */ 350 writel(0x00550055, lvds->grf + lvds->pdata->grf_gpio1d_iomux); 351 lvds_writel(lvds, RK3288_LVDS_CH0_REG0, 352 RK3288_LVDS_CH0_REG0_TTL_EN | 353 RK3288_LVDS_CH0_REG0_LANECK_EN | 354 RK3288_LVDS_CH0_REG0_LANE4_EN | 355 RK3288_LVDS_CH0_REG0_LANE3_EN | 356 RK3288_LVDS_CH0_REG0_LANE2_EN | 357 RK3288_LVDS_CH0_REG0_LANE1_EN | 358 RK3288_LVDS_CH0_REG0_LANE0_EN); 359 lvds_writel(lvds, RK3288_LVDS_CH0_REG2, 360 RK3288_LVDS_PLL_FBDIV_REG2(0x46)); 361 362 lvds_writel(lvds, RK3288_LVDS_CH0_REG3, 363 RK3288_LVDS_PLL_FBDIV_REG3(0x46)); 364 lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 365 RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE | 366 RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE | 367 RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE | 368 RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE | 369 RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE | 370 RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE); 371 lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 372 RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA | 373 RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA | 374 RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA | 375 RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA | 376 RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA | 377 RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA); 378 lvds_writel(lvds, RK3288_LVDS_CH0_REGD, 379 RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); 380 lvds_writel(lvds, RK3288_LVDS_CH0_REG20, 381 RK3288_LVDS_CH0_REG20_LSB); 382 383 lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); 384 lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); 385 } 386 387 static void rk3288_output_lvds(struct display_state *state) 388 { 389 struct connector_state *conn_state = &state->conn_state; 390 struct rockchip_lvds_device *lvds = conn_state->private; 391 392 rk3288_lvds_pwr_on(state); 393 394 lvds_writel(lvds, RK3288_LVDS_CH0_REG0, 395 RK3288_LVDS_CH0_REG0_LVDS_EN | 396 RK3288_LVDS_CH0_REG0_LANECK_EN | 397 RK3288_LVDS_CH0_REG0_LANE4_EN | 398 RK3288_LVDS_CH0_REG0_LANE3_EN | 399 RK3288_LVDS_CH0_REG0_LANE2_EN | 400 RK3288_LVDS_CH0_REG0_LANE1_EN | 401 RK3288_LVDS_CH0_REG0_LANE0_EN); 402 lvds_writel(lvds, RK3288_LVDS_CH0_REG1, 403 RK3288_LVDS_CH0_REG1_LANECK_BIAS | 404 RK3288_LVDS_CH0_REG1_LANE4_BIAS | 405 RK3288_LVDS_CH0_REG1_LANE3_BIAS | 406 RK3288_LVDS_CH0_REG1_LANE2_BIAS | 407 RK3288_LVDS_CH0_REG1_LANE1_BIAS | 408 RK3288_LVDS_CH0_REG1_LANE0_BIAS); 409 lvds_writel(lvds, RK3288_LVDS_CH0_REG2, 410 RK3288_LVDS_CH0_REG2_RESERVE_ON | 411 RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE | 412 RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE | 413 RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE | 414 RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE | 415 RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE | 416 RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE | 417 RK3288_LVDS_PLL_FBDIV_REG2(0x46)); 418 lvds_writel(lvds, RK3288_LVDS_CH0_REG3, 419 RK3288_LVDS_PLL_FBDIV_REG3(0x46)); 420 lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00); 421 lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00); 422 lvds_writel(lvds, RK3288_LVDS_CH0_REGD, 423 RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); 424 lvds_writel(lvds, RK3288_LVDS_CH0_REG20, 425 RK3288_LVDS_CH0_REG20_LSB); 426 427 lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); 428 lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); 429 } 430 431 static int rockchip_lvds_init(struct display_state *state) 432 { 433 struct connector_state *conn_state = &state->conn_state; 434 const struct rockchip_connector *connector = conn_state->connector; 435 const struct rockchip_lvds_chip_data *pdata = connector->data; 436 int lvds_node = conn_state->node; 437 struct rockchip_lvds_device *lvds; 438 const char *name; 439 int i; 440 struct fdt_resource lvds_phy, lvds_ctrl; 441 struct panel_state *panel_state = &state->panel_state; 442 int panel_node = panel_state->node; 443 444 lvds = malloc(sizeof(*lvds)); 445 if (!lvds) 446 return -ENOMEM; 447 lvds->pdata = pdata; 448 449 if (pdata->chip_type == RK3288_LVDS) { 450 lvds->regbase = (u32)fdtdec_get_addr_size_auto_noparent(state->blob, 451 lvds_node, "reg", 0, NULL, false); 452 } else { 453 i = fdt_get_named_resource(state->blob, lvds_node, "reg", "reg-names", 454 "mipi_lvds_phy", &lvds_phy); 455 if (i) { 456 printf("can't get regs lvds_phy addresses!\n"); 457 free(lvds); 458 return -ENOMEM; 459 } 460 461 i = fdt_get_named_resource(state->blob, lvds_node, "reg", "reg-names", 462 "mipi_lvds_ctl", &lvds_ctrl); 463 if (i) { 464 printf("can't get regs lvds_ctrl addresses!\n"); 465 free(lvds); 466 return -ENOMEM; 467 } 468 469 lvds->regbase = lvds_phy.start; 470 lvds->ctrl_reg = lvds_ctrl.start; 471 } 472 473 lvds->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); 474 if (lvds->grf <= 0) { 475 printf("%s: Get syscon grf failed (ret=%p)\n", 476 __func__, lvds->grf); 477 return -ENXIO; 478 } 479 480 name = fdt_stringlist_get(state->blob, panel_node, "rockchip,output", 0, NULL); 481 if (!name) 482 /* default set it as output rgb */ 483 lvds->output = DISPLAY_OUTPUT_RGB; 484 else 485 lvds->output = lvds_name_to_output(name); 486 if (lvds->output < 0) { 487 printf("invalid output type [%s]\n", name); 488 free(lvds); 489 return lvds->output; 490 } 491 name = fdt_stringlist_get(state->blob, panel_node, "rockchip,data-mapping", 0, NULL); 492 if (!name) 493 /* default set it as format jeida */ 494 lvds->format = LVDS_FORMAT_JEIDA; 495 else 496 lvds->format = lvds_name_to_format(name); 497 498 if (lvds->format < 0) { 499 printf("invalid data-mapping format [%s]\n", name); 500 free(lvds); 501 return lvds->format; 502 } 503 i = fdtdec_get_int(state->blob, panel_node, "rockchip,data-width", 24); 504 if (i == 24) { 505 lvds->format |= LVDS_24BIT; 506 } else if (i == 18) { 507 lvds->format |= LVDS_18BIT; 508 } else { 509 printf("rockchip-lvds unsupport data-width[%d]\n", i); 510 free(lvds); 511 return -EINVAL; 512 } 513 printf("LVDS: data mapping: %s, data-width:%d, format:%d,\n", 514 name, i, lvds->format); 515 conn_state->private = lvds; 516 conn_state->type = DRM_MODE_CONNECTOR_LVDS; 517 conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; 518 519 return 0; 520 } 521 522 static void rockchip_lvds_deinit(struct display_state *state) 523 { 524 struct connector_state *conn_state = &state->conn_state; 525 struct rockchip_lvds_device *lvds = conn_state->private; 526 527 free(lvds); 528 } 529 530 static int rockchip_lvds_prepare(struct display_state *state) 531 { 532 struct connector_state *conn_state = &state->conn_state; 533 struct rockchip_lvds_device *lvds = conn_state->private; 534 lvds->mode = &conn_state->mode; 535 536 rockchip_lvds_clk_enable(lvds); 537 538 return 0; 539 } 540 541 static void rockchip_lvds_vop_routing(struct rockchip_lvds_device *lvds, int pipe) 542 { 543 u32 val; 544 545 if (lvds->pdata->chip_type == RK3288_LVDS) { 546 if (pipe) 547 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT | 548 (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16); 549 else 550 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16; 551 writel(val, lvds->grf + lvds->pdata->grf_soc_con6); 552 } else { 553 if (pipe) 554 val = RK3366_LVDS_VOP_SEL_LIT; 555 else 556 val = RK3366_LVDS_VOP_SEL_BIG; 557 558 writel(val, lvds->grf + RK3366_GRF_SOC_CON0); 559 } 560 } 561 562 static int rockchip_lvds_enable(struct display_state *state) 563 { 564 struct connector_state *conn_state = &state->conn_state; 565 struct rockchip_lvds_device *lvds = conn_state->private; 566 struct crtc_state *crtc_state = &state->crtc_state; 567 568 if (lvds->pdata->has_vop_sel) 569 rockchip_lvds_vop_routing(lvds, crtc_state->crtc_id); 570 571 if (lvds->output == DISPLAY_OUTPUT_LVDS) { 572 if (lvds->pdata->chip_type == RK3288_LVDS) 573 rk3288_output_lvds(state); 574 else 575 rk336x_output_lvds(state); 576 } else { 577 if (lvds->pdata->chip_type == RK3288_LVDS) 578 rk3288_output_ttl(state); 579 else 580 rk336x_output_ttl(state); 581 } 582 583 return 0; 584 } 585 586 static int rockchip_lvds_disable(struct display_state *state) 587 { 588 struct connector_state *conn_state = &state->conn_state; 589 struct rockchip_lvds_device *lvds = conn_state->private; 590 591 if (lvds->pdata->chip_type == RK3288_LVDS) 592 rk3288_lvds_pwr_off(state); 593 else 594 rk336x_lvds_pwr_off(state); 595 596 return 0; 597 } 598 599 const struct rockchip_connector_funcs rockchip_lvds_funcs = { 600 .init = rockchip_lvds_init, 601 .deinit = rockchip_lvds_deinit, 602 .prepare = rockchip_lvds_prepare, 603 .enable = rockchip_lvds_enable, 604 .disable = rockchip_lvds_disable, 605 }; 606 607 static const struct rockchip_connector rk3366_lvds_data = { 608 .funcs = &rockchip_analogix_dp_funcs, 609 .data = &rk3366_lvds_drv_data, 610 }; 611 612 static const struct rockchip_connector rk3368_lvds_data = { 613 .funcs = &rockchip_lvds_funcs, 614 .data = &rk3368_lvds_drv_data, 615 }; 616 617 static const struct rockchip_connector rk3288_lvds_data = { 618 .funcs = &rockchip_lvds_funcs, 619 .data = &rk3288_lvds_drv_data, 620 }; 621 622 static const struct udevice_id rockchip_lvds_ids[] = { 623 { 624 .compatible = "rockchip,rk3366-lvds", 625 .data = (ulong)&rk3366_lvds_data, 626 }, { 627 .compatible = "rockchip,rk3368-lvds", 628 .data = (ulong)&rk3368_lvds_data, 629 }, { 630 .compatible = "rockchip,rk3288-lvds", 631 .data = (ulong)&rk3288_lvds_data, 632 }, {} 633 }; 634 635 U_BOOT_DRIVER(rockchip_lvds) = { 636 .name = "rockchip_lvds", 637 .id = UCLASS_DISPLAY, 638 .of_match = rockchip_lvds_ids, 639 }; 640