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 #include "rockchip_display.h" 22 #include "rockchip_crtc.h" 23 #include "rockchip_connector.h" 24 #include "rockchip_lvds.h" 25 26 enum rockchip_lvds_sub_devtype { 27 RK3288_LVDS, 28 RK3366_LVDS, 29 RK3368_LVDS, 30 RK3126_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 void *regbase; 45 void *grf; 46 void *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((void *)LVDS_PMUGRF_BASE + offset); 115 } 116 117 static inline void lvds_pmugrf_writel(u32 offset, u32 val) 118 { 119 writel(val, (void *)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 + MIPIC_PHY_STATUS); 126 return (val & m_PHY_LOCK_STATUS) ? 1 : 0; 127 } 128 129 static int rockchip_lvds_clk_enable(struct rockchip_lvds_device *lvds) 130 { 131 return 0; 132 } 133 134 const struct rockchip_lvds_chip_data rk3126_lvds_drv_data = { 135 .chip_type = RK3126_LVDS, 136 .grf_soc_con7 = RK3126_GRF_LVDS_CON0, 137 .grf_soc_con15 = RK3126_GRF_CON1, 138 .has_vop_sel = true, 139 }; 140 141 const struct rockchip_lvds_chip_data rk3366_lvds_drv_data = { 142 .chip_type = RK3366_LVDS, 143 .grf_soc_con7 = RK3366_GRF_SOC_CON5, 144 .grf_soc_con15 = RK3366_GRF_SOC_CON6, 145 .has_vop_sel = true, 146 }; 147 148 const struct rockchip_lvds_chip_data rk3368_lvds_drv_data = { 149 .chip_type = RK3368_LVDS, 150 .grf_soc_con7 = RK3368_GRF_SOC_CON7, 151 .grf_soc_con15 = RK3368_GRF_SOC_CON15, 152 .has_vop_sel = false, 153 }; 154 155 const struct rockchip_lvds_chip_data rk3288_lvds_drv_data = { 156 .chip_type = RK3288_LVDS, 157 .has_vop_sel = true, 158 .grf_soc_con6 = 0x025c, 159 .grf_soc_con7 = 0x0260, 160 .grf_gpio1d_iomux = 0x000c, 161 }; 162 163 static int rk336x_lvds_pwr_off(struct display_state *state) 164 { 165 struct connector_state *conn_state = &state->conn_state; 166 struct rockchip_lvds_device *lvds = conn_state->private; 167 168 /* disable lvds lane and power off pll */ 169 lvds_writel(lvds, MIPIPHY_REGEB, 170 v_LANE0_EN(0) | v_LANE1_EN(0) | v_LANE2_EN(0) | 171 v_LANE3_EN(0) | v_LANECLK_EN(0) | v_PLL_PWR_OFF(1)); 172 173 /* power down lvds pll and bandgap */ 174 lvds_msk_reg(lvds, MIPIPHY_REG1, 175 m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN, 176 v_SYNC_RST(1) | v_LDO_PWR_DOWN(1) | v_PLL_PWR_DOWN(1)); 177 178 /* disable lvds */ 179 lvds_msk_reg(lvds, MIPIPHY_REGE3, m_LVDS_EN | m_TTL_EN, 180 v_LVDS_EN(0) | v_TTL_EN(0)); 181 182 return 0; 183 } 184 185 static int rk3288_lvds_pwr_off(struct display_state *state) 186 { 187 struct connector_state *conn_state = &state->conn_state; 188 struct rockchip_lvds_device *lvds = conn_state->private; 189 190 lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_DISABLE); 191 lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_DISABLE); 192 193 writel(0xffff8000, lvds->grf + lvds->pdata->grf_soc_con7); 194 195 return 0; 196 } 197 198 static int rk336x_lvds_pwr_on(struct display_state *state) 199 { 200 struct connector_state *conn_state = &state->conn_state; 201 struct rockchip_lvds_device *lvds = conn_state->private; 202 u32 delay_times = 20; 203 204 if (lvds->output == DISPLAY_OUTPUT_LVDS) { 205 /* set VOCM 900 mv and V-DIFF 350 mv */ 206 lvds_msk_reg(lvds, MIPIPHY_REGE4, m_VOCM | m_DIFF_V, 207 v_VOCM(0) | v_DIFF_V(2)); 208 /* power up lvds pll and ldo */ 209 lvds_msk_reg(lvds, MIPIPHY_REG1, 210 m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN, 211 v_SYNC_RST(0) | v_LDO_PWR_DOWN(0) | 212 v_PLL_PWR_DOWN(0)); 213 /* enable lvds lane and power on pll */ 214 lvds_writel(lvds, MIPIPHY_REGEB, 215 v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | 216 v_LANE3_EN(1) | v_LANECLK_EN(1) | v_PLL_PWR_OFF(0)); 217 218 /* enable lvds */ 219 lvds_msk_reg(lvds, MIPIPHY_REGE3, 220 m_MIPI_EN | m_LVDS_EN | m_TTL_EN, 221 v_MIPI_EN(0) | v_LVDS_EN(1) | v_TTL_EN(0)); 222 } else { 223 lvds_msk_reg(lvds, MIPIPHY_REGE3, 224 m_MIPI_EN | m_LVDS_EN | m_TTL_EN, 225 v_MIPI_EN(0) | v_LVDS_EN(0) | v_TTL_EN(1)); 226 } 227 /* delay for waitting pll lock on */ 228 while (delay_times--) { 229 if (lvds_phy_lock(lvds)) 230 break; 231 udelay(100); 232 } 233 234 if (delay_times <= 0) 235 printf("wait lvds phy lock failed, please check the hardware!\n"); 236 237 return 0; 238 } 239 240 static void rk3126_output_ttl(struct display_state *state) 241 { 242 struct connector_state *conn_state = &state->conn_state; 243 struct rockchip_lvds_device *lvds = conn_state->private; 244 u32 val = 0; 245 246 /* iomux to lcdc */ 247 writel(0xffc35541, lvds->grf + RK3126_GRF_GPIO2B_IOMUX); 248 writel(0xffff5555, lvds->grf + RK3126_GRF_GPIO2C_IOMUX); 249 writel(0x700c1004, lvds->grf + RK3126_GRF_GPIO2D_IOMUX); 250 251 /* enable lvds mode */ 252 val = v_RK3126_LVDSMODE_EN(0) | 253 v_RK3126_MIPIPHY_TTL_EN(1) | 254 v_RK3126_MIPIPHY_LANE0_EN(1) | 255 v_RK3126_MIPIDPI_FORCEX_EN(1); 256 writel(val, lvds->grf + lvds->pdata->grf_soc_con7); 257 val = v_RK3126_MIPITTL_CLK_EN(1) | 258 v_RK3126_MIPITTL_LANE0_EN(1) | 259 v_RK3126_MIPITTL_LANE1_EN(1) | 260 v_RK3126_MIPITTL_LANE2_EN(1) | 261 v_RK3126_MIPITTL_LANE3_EN(1); 262 writel(val, lvds->grf + lvds->pdata->grf_soc_con15); 263 /* enable lane */ 264 lvds_writel(lvds, MIPIPHY_REG0, 0x7f); 265 val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) | 266 v_LANECLK_EN(1) | v_PLL_PWR_OFF(1); 267 lvds_writel(lvds, MIPIPHY_REGEB, val); 268 /* set ttl mode and reset phy config */ 269 val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) | 270 v_MSB_SEL(1) | v_DIG_INTER_RST(1); 271 lvds_writel(lvds, MIPIPHY_REGE0, val); 272 rk336x_lvds_pwr_on(state); 273 } 274 275 static void rk336x_output_ttl(struct display_state *state) 276 { 277 struct connector_state *conn_state = &state->conn_state; 278 struct rockchip_lvds_device *lvds = conn_state->private; 279 u32 val = 0; 280 281 /* iomux to lcdc */ 282 if (lvds->pdata->chip_type == RK3368_LVDS) { 283 /* lcdc data 11 10 */ 284 lvds_pmugrf_writel(0x04, 0xf0005000); 285 /* lcdc data 12 13 14 15 16 17 18 19 */ 286 lvds_pmugrf_writel(0x08, 0xFFFF5555); 287 /* lcdc data 20 21 22 23 HSYNC VSYNC DEN DCLK */ 288 lvds_pmugrf_writel(0x0c, 0xFFFF5555); 289 /* set clock lane enable */ 290 lvds_ctrl_writel(lvds, 0x0, 0x4); 291 } else { 292 /* lcdc data 15 ... 10, vsync, hsync */ 293 lvds_pmugrf_writel(0x0c, 0xffff555a); 294 /* lcdc data 23 ... 16 */ 295 lvds_pmugrf_writel(0x30, 0xffff5555); 296 /* lcdc dclk, den */ 297 lvds_pmugrf_writel(0x34, 0x000f0005); 298 } 299 300 /* enable lvds mode */ 301 val = v_RK336X_LVDSMODE_EN(0) | v_RK336X_MIPIPHY_TTL_EN(1) | 302 v_RK336X_MIPIPHY_LANE0_EN(1) | 303 v_RK336X_MIPIDPI_FORCEX_EN(1); 304 writel(val, lvds->grf + lvds->pdata->grf_soc_con7); 305 val = v_RK336X_FORCE_JETAG(0); 306 writel(val, lvds->grf + lvds->pdata->grf_soc_con15); 307 308 /* enable lane */ 309 lvds_writel(lvds, MIPIPHY_REG0, 0x7f); 310 val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) | 311 v_LANECLK_EN(1) | v_PLL_PWR_OFF(1); 312 lvds_writel(lvds, MIPIPHY_REGEB, val); 313 314 /* set ttl mode and reset phy config */ 315 val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) | 316 v_MSB_SEL(1) | v_DIG_INTER_RST(1); 317 lvds_writel(lvds, MIPIPHY_REGE0, val); 318 319 rk336x_lvds_pwr_on(state); 320 } 321 322 static void rk3126_output_lvds(struct display_state *state) 323 { 324 struct connector_state *conn_state = &state->conn_state; 325 struct rockchip_lvds_device *lvds = conn_state->private; 326 u32 val = 0; 327 328 /* enable lvds mode */ 329 val = v_RK3126_LVDSMODE_EN(1) | 330 v_RK3126_MIPIPHY_TTL_EN(0); 331 /* config lvds_format */ 332 val |= v_RK3126_LVDS_OUTPUT_FORMAT(lvds->format); 333 /* LSB receive mode */ 334 val |= v_RK3126_LVDS_MSBSEL(LVDS_MSB_D7); 335 val |= v_RK3126_MIPIPHY_LANE0_EN(1) | 336 v_RK3126_MIPIDPI_FORCEX_EN(1); 337 writel(val, lvds->grf + lvds->pdata->grf_soc_con7); 338 339 /* digital internal disable */ 340 lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(0)); 341 342 /* set pll prediv and fbdiv */ 343 lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(2) | v_FBDIV_MSB(0)); 344 lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(28)); 345 346 lvds_writel(lvds, MIPIPHY_REGE8, 0xfc); 347 348 /* set lvds mode and reset phy config */ 349 lvds_msk_reg(lvds, MIPIPHY_REGE0, 350 m_MSB_SEL | m_DIG_INTER_RST, 351 v_MSB_SEL(1) | v_DIG_INTER_RST(1)); 352 353 rk336x_lvds_pwr_on(state); 354 lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(1)); 355 } 356 357 static void rk336x_output_lvds(struct display_state *state) 358 { 359 struct connector_state *conn_state = &state->conn_state; 360 struct rockchip_lvds_device *lvds = conn_state->private; 361 u32 val = 0; 362 363 /* enable lvds mode */ 364 val |= v_RK336X_LVDSMODE_EN(1) | v_RK336X_MIPIPHY_TTL_EN(0); 365 /* config lvds_format */ 366 val |= v_RK336X_LVDS_OUTPUT_FORMAT(lvds->format); 367 /* LSB receive mode */ 368 val |= v_RK336X_LVDS_MSBSEL(LVDS_MSB_D7); 369 val |= v_RK336X_MIPIPHY_LANE0_EN(1) | 370 v_RK336X_MIPIDPI_FORCEX_EN(1); 371 writel(val, lvds->grf + lvds->pdata->grf_soc_con7); 372 /* digital internal disable */ 373 lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(0)); 374 375 /* set pll prediv and fbdiv */ 376 lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(2) | v_FBDIV_MSB(0)); 377 lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(28)); 378 379 lvds_writel(lvds, MIPIPHY_REGE8, 0xfc); 380 381 /* set lvds mode and reset phy config */ 382 lvds_msk_reg(lvds, MIPIPHY_REGE0, 383 m_MSB_SEL | m_DIG_INTER_RST, 384 v_MSB_SEL(1) | v_DIG_INTER_RST(1)); 385 386 rk336x_lvds_pwr_on(state); 387 lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(1)); 388 } 389 390 static int rk3288_lvds_pwr_on(struct display_state *state) 391 { 392 struct connector_state *conn_state = &state->conn_state; 393 struct rockchip_lvds_device *lvds = conn_state->private; 394 struct drm_display_mode *mode = &conn_state->mode; 395 u32 val; 396 u32 h_bp = mode->htotal - mode->hsync_start; 397 u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0; 398 u8 pin_dclk = (mode->flags & DRM_MODE_FLAG_PCSYNC) ? 1 : 0; 399 400 val = lvds->format; 401 if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS) 402 val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN; 403 else if (lvds->output == DISPLAY_OUTPUT_LVDS) 404 val |= LVDS_CH0_EN; 405 else if (lvds->output == DISPLAY_OUTPUT_RGB) 406 val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN; 407 408 if (h_bp & 0x01) 409 val |= LVDS_START_PHASE_RST_1; 410 411 val |= (pin_dclk << 8) | (pin_hsync << 9); 412 val |= (0xffff << 16); 413 writel(val, lvds->grf + lvds->pdata->grf_soc_con7); 414 415 return 0; 416 } 417 418 static void rk3288_output_ttl(struct display_state *state) 419 { 420 struct connector_state *conn_state = &state->conn_state; 421 struct rockchip_lvds_device *lvds = conn_state->private; 422 423 rk3288_lvds_pwr_on(state); 424 /* iomux: dclk den hsync vsync */ 425 writel(0x00550055, lvds->grf + lvds->pdata->grf_gpio1d_iomux); 426 lvds_writel(lvds, RK3288_LVDS_CH0_REG0, 427 RK3288_LVDS_CH0_REG0_TTL_EN | 428 RK3288_LVDS_CH0_REG0_LANECK_EN | 429 RK3288_LVDS_CH0_REG0_LANE4_EN | 430 RK3288_LVDS_CH0_REG0_LANE3_EN | 431 RK3288_LVDS_CH0_REG0_LANE2_EN | 432 RK3288_LVDS_CH0_REG0_LANE1_EN | 433 RK3288_LVDS_CH0_REG0_LANE0_EN); 434 lvds_writel(lvds, RK3288_LVDS_CH0_REG2, 435 RK3288_LVDS_PLL_FBDIV_REG2(0x46)); 436 437 lvds_writel(lvds, RK3288_LVDS_CH0_REG3, 438 RK3288_LVDS_PLL_FBDIV_REG3(0x46)); 439 lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 440 RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE | 441 RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE | 442 RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE | 443 RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE | 444 RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE | 445 RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE); 446 lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 447 RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA | 448 RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA | 449 RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA | 450 RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA | 451 RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA | 452 RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA); 453 lvds_writel(lvds, RK3288_LVDS_CH0_REGD, 454 RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); 455 lvds_writel(lvds, RK3288_LVDS_CH0_REG20, 456 RK3288_LVDS_CH0_REG20_LSB); 457 458 lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); 459 lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); 460 } 461 462 static void rk3288_output_lvds(struct display_state *state) 463 { 464 struct connector_state *conn_state = &state->conn_state; 465 struct rockchip_lvds_device *lvds = conn_state->private; 466 467 rk3288_lvds_pwr_on(state); 468 469 lvds_writel(lvds, RK3288_LVDS_CH0_REG0, 470 RK3288_LVDS_CH0_REG0_LVDS_EN | 471 RK3288_LVDS_CH0_REG0_LANECK_EN | 472 RK3288_LVDS_CH0_REG0_LANE4_EN | 473 RK3288_LVDS_CH0_REG0_LANE3_EN | 474 RK3288_LVDS_CH0_REG0_LANE2_EN | 475 RK3288_LVDS_CH0_REG0_LANE1_EN | 476 RK3288_LVDS_CH0_REG0_LANE0_EN); 477 lvds_writel(lvds, RK3288_LVDS_CH0_REG1, 478 RK3288_LVDS_CH0_REG1_LANECK_BIAS | 479 RK3288_LVDS_CH0_REG1_LANE4_BIAS | 480 RK3288_LVDS_CH0_REG1_LANE3_BIAS | 481 RK3288_LVDS_CH0_REG1_LANE2_BIAS | 482 RK3288_LVDS_CH0_REG1_LANE1_BIAS | 483 RK3288_LVDS_CH0_REG1_LANE0_BIAS); 484 lvds_writel(lvds, RK3288_LVDS_CH0_REG2, 485 RK3288_LVDS_CH0_REG2_RESERVE_ON | 486 RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE | 487 RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE | 488 RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE | 489 RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE | 490 RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE | 491 RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE | 492 RK3288_LVDS_PLL_FBDIV_REG2(0x46)); 493 lvds_writel(lvds, RK3288_LVDS_CH0_REG3, 494 RK3288_LVDS_PLL_FBDIV_REG3(0x46)); 495 lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00); 496 lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00); 497 lvds_writel(lvds, RK3288_LVDS_CH0_REGD, 498 RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); 499 lvds_writel(lvds, RK3288_LVDS_CH0_REG20, 500 RK3288_LVDS_CH0_REG20_LSB); 501 502 lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); 503 lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); 504 } 505 506 static int rockchip_lvds_init(struct display_state *state) 507 { 508 struct connector_state *conn_state = &state->conn_state; 509 const struct rockchip_connector *connector = conn_state->connector; 510 const struct rockchip_lvds_chip_data *pdata = connector->data; 511 int lvds_node = conn_state->node; 512 struct rockchip_lvds_device *lvds; 513 const char *name; 514 int i, width; 515 struct fdt_resource lvds_phy, lvds_ctrl; 516 struct panel_state *panel_state = &state->panel_state; 517 int panel_node = panel_state->node; 518 519 lvds = malloc(sizeof(*lvds)); 520 if (!lvds) 521 return -ENOMEM; 522 lvds->pdata = pdata; 523 524 if (pdata->chip_type == RK3288_LVDS) { 525 lvds->regbase = (void *)fdtdec_get_addr_size_auto_noparent(state->blob, 526 lvds_node, "reg", 0, NULL, false); 527 } else { 528 i = fdt_get_named_resource(state->blob, lvds_node, "reg", "reg-names", 529 "mipi_lvds_phy", &lvds_phy); 530 if (i) { 531 printf("can't get regs lvds_phy addresses!\n"); 532 free(lvds); 533 return -ENOMEM; 534 } 535 536 i = fdt_get_named_resource(state->blob, lvds_node, "reg", "reg-names", 537 "mipi_lvds_ctl", &lvds_ctrl); 538 if (i) { 539 printf("can't get regs lvds_ctrl addresses!\n"); 540 free(lvds); 541 return -ENOMEM; 542 } 543 544 lvds->regbase = (void *)lvds_phy.start; 545 lvds->ctrl_reg = (void *)lvds_ctrl.start; 546 } 547 548 lvds->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); 549 if (lvds->grf <= 0) { 550 printf("%s: Get syscon grf failed (ret=%p)\n", 551 __func__, lvds->grf); 552 return -ENXIO; 553 } 554 555 name = fdt_stringlist_get(state->blob, panel_node, "rockchip,output", 0, NULL); 556 if (!name) 557 /* default set it as output rgb */ 558 lvds->output = DISPLAY_OUTPUT_RGB; 559 else 560 lvds->output = lvds_name_to_output(name); 561 if (lvds->output < 0) { 562 printf("invalid output type [%s]\n", name); 563 free(lvds); 564 return lvds->output; 565 } 566 name = fdt_stringlist_get(state->blob, panel_node, "rockchip,data-mapping", 0, NULL); 567 if (!name) 568 /* default set it as format jeida */ 569 lvds->format = LVDS_FORMAT_JEIDA; 570 else 571 lvds->format = lvds_name_to_format(name); 572 573 if (lvds->format < 0) { 574 printf("invalid data-mapping format [%s]\n", name); 575 free(lvds); 576 return lvds->format; 577 } 578 width = fdtdec_get_int(state->blob, panel_node, "rockchip,data-width", 24); 579 if (width == 24) { 580 lvds->format |= LVDS_24BIT; 581 } else if (width == 18) { 582 lvds->format |= LVDS_18BIT; 583 } else { 584 printf("rockchip-lvds unsupport data-width[%d]\n", width); 585 free(lvds); 586 return -EINVAL; 587 } 588 589 printf("LVDS: data mapping: %s, data-width:%d, format:%d,\n", 590 name, width, lvds->format); 591 conn_state->private = lvds; 592 conn_state->type = DRM_MODE_CONNECTOR_LVDS; 593 594 if ((lvds->output == DISPLAY_OUTPUT_RGB) && (width == 18)) 595 conn_state->output_mode = ROCKCHIP_OUT_MODE_P666; 596 else 597 conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; 598 599 return 0; 600 } 601 602 static void rockchip_lvds_deinit(struct display_state *state) 603 { 604 struct connector_state *conn_state = &state->conn_state; 605 struct rockchip_lvds_device *lvds = conn_state->private; 606 607 free(lvds); 608 } 609 610 static int rockchip_lvds_prepare(struct display_state *state) 611 { 612 struct connector_state *conn_state = &state->conn_state; 613 struct rockchip_lvds_device *lvds = conn_state->private; 614 lvds->mode = &conn_state->mode; 615 616 rockchip_lvds_clk_enable(lvds); 617 618 return 0; 619 } 620 621 static void rockchip_lvds_vop_routing(struct rockchip_lvds_device *lvds, int pipe) 622 { 623 u32 val; 624 625 if (lvds->pdata->chip_type == RK3288_LVDS) { 626 if (pipe) 627 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT | 628 (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16); 629 else 630 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16; 631 writel(val, lvds->grf + lvds->pdata->grf_soc_con6); 632 } else { 633 if (pipe) 634 val = RK3366_LVDS_VOP_SEL_LIT; 635 else 636 val = RK3366_LVDS_VOP_SEL_BIG; 637 638 writel(val, lvds->grf + RK3366_GRF_SOC_CON0); 639 } 640 } 641 642 static int rockchip_lvds_enable(struct display_state *state) 643 { 644 struct connector_state *conn_state = &state->conn_state; 645 struct rockchip_lvds_device *lvds = conn_state->private; 646 struct crtc_state *crtc_state = &state->crtc_state; 647 648 if (lvds->pdata->has_vop_sel) 649 rockchip_lvds_vop_routing(lvds, crtc_state->crtc_id); 650 651 if (lvds->output == DISPLAY_OUTPUT_LVDS) { 652 if (lvds->pdata->chip_type == RK3288_LVDS) 653 rk3288_output_lvds(state); 654 else if (lvds->pdata->chip_type == RK3126_LVDS) 655 rk3126_output_lvds(state); 656 else 657 rk336x_output_lvds(state); 658 } else { 659 if (lvds->pdata->chip_type == RK3288_LVDS) 660 rk3288_output_ttl(state); 661 else if (lvds->pdata->chip_type == RK3126_LVDS) 662 rk3126_output_ttl(state); 663 else 664 rk336x_output_ttl(state); 665 } 666 667 return 0; 668 } 669 670 static int rockchip_lvds_disable(struct display_state *state) 671 { 672 struct connector_state *conn_state = &state->conn_state; 673 struct rockchip_lvds_device *lvds = conn_state->private; 674 675 if (lvds->pdata->chip_type == RK3288_LVDS) 676 rk3288_lvds_pwr_off(state); 677 else 678 rk336x_lvds_pwr_off(state); 679 680 return 0; 681 } 682 683 const struct rockchip_connector_funcs rockchip_lvds_funcs = { 684 .init = rockchip_lvds_init, 685 .deinit = rockchip_lvds_deinit, 686 .prepare = rockchip_lvds_prepare, 687 .enable = rockchip_lvds_enable, 688 .disable = rockchip_lvds_disable, 689 }; 690 691 static const struct rockchip_connector rk3366_lvds_data = { 692 .funcs = &rockchip_lvds_funcs, 693 .data = &rk3366_lvds_drv_data, 694 }; 695 696 static const struct rockchip_connector rk3368_lvds_data = { 697 .funcs = &rockchip_lvds_funcs, 698 .data = &rk3368_lvds_drv_data, 699 }; 700 701 static const struct rockchip_connector rk3288_lvds_data = { 702 .funcs = &rockchip_lvds_funcs, 703 .data = &rk3288_lvds_drv_data, 704 }; 705 706 static const struct rockchip_connector rk3126_lvds_data = { 707 .funcs = &rockchip_lvds_funcs, 708 .data = &rk3126_lvds_drv_data, 709 }; 710 711 static const struct udevice_id rockchip_lvds_ids[] = { 712 { 713 .compatible = "rockchip,rk3366-lvds", 714 .data = (ulong)&rk3366_lvds_data, 715 }, { 716 .compatible = "rockchip,rk3368-lvds", 717 .data = (ulong)&rk3368_lvds_data, 718 }, { 719 .compatible = "rockchip,rk3288-lvds", 720 .data = (ulong)&rk3288_lvds_data, 721 }, { 722 .compatible = "rockchip,rk3126-lvds", 723 .data = (ulong)&rk3126_lvds_data, 724 }, {} 725 }; 726 727 U_BOOT_DRIVER(rockchip_lvds) = { 728 .name = "rockchip_lvds", 729 .id = UCLASS_DISPLAY, 730 .of_match = rockchip_lvds_ids, 731 }; 732