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