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