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