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