1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/mfd/syscon.h> 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/phy/phy.h> 11 #include <linux/regmap.h> 12 #include <linux/regulator/consumer.h> 13 14 #include <drm/bridge/dw_hdmi.h> 15 #include <drm/drm_edid.h> 16 #include <drm/drm_of.h> 17 #include <drm/drm_probe_helper.h> 18 #include <drm/drm_simple_kms_helper.h> 19 20 #include "rockchip_drm_drv.h" 21 22 #define RK3228_GRF_SOC_CON2 0x0408 23 #define RK3228_HDMI_SDAIN_MSK BIT(14) 24 #define RK3228_HDMI_SCLIN_MSK BIT(13) 25 #define RK3228_GRF_SOC_CON6 0x0418 26 #define RK3228_HDMI_HPD_VSEL BIT(6) 27 #define RK3228_HDMI_SDA_VSEL BIT(5) 28 #define RK3228_HDMI_SCL_VSEL BIT(4) 29 30 #define RK3288_GRF_SOC_CON6 0x025C 31 #define RK3288_HDMI_LCDC_SEL BIT(4) 32 #define RK3328_GRF_SOC_CON2 0x0408 33 34 #define RK3328_HDMI_SDAIN_MSK BIT(11) 35 #define RK3328_HDMI_SCLIN_MSK BIT(10) 36 #define RK3328_HDMI_HPD_IOE BIT(2) 37 #define RK3328_GRF_SOC_CON3 0x040c 38 /* need to be unset if hdmi or i2c should control voltage */ 39 #define RK3328_HDMI_SDA5V_GRF BIT(15) 40 #define RK3328_HDMI_SCL5V_GRF BIT(14) 41 #define RK3328_HDMI_HPD5V_GRF BIT(13) 42 #define RK3328_HDMI_CEC5V_GRF BIT(12) 43 #define RK3328_GRF_SOC_CON4 0x0410 44 #define RK3328_HDMI_HPD_SARADC BIT(13) 45 #define RK3328_HDMI_CEC_5V BIT(11) 46 #define RK3328_HDMI_SDA_5V BIT(10) 47 #define RK3328_HDMI_SCL_5V BIT(9) 48 #define RK3328_HDMI_HPD_5V BIT(8) 49 50 #define RK3399_GRF_SOC_CON20 0x6250 51 #define RK3399_HDMI_LCDC_SEL BIT(6) 52 53 #define RK3568_GRF_VO_CON1 0x0364 54 #define RK3568_HDMI_SDAIN_MSK BIT(15) 55 #define RK3568_HDMI_SCLIN_MSK BIT(14) 56 57 #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) 58 59 /** 60 * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips 61 * @lcdsel_grf_reg: grf register offset of lcdc select 62 * @lcdsel_big: reg value of selecting vop big for HDMI 63 * @lcdsel_lit: reg value of selecting vop little for HDMI 64 */ 65 struct rockchip_hdmi_chip_data { 66 int lcdsel_grf_reg; 67 u32 lcdsel_big; 68 u32 lcdsel_lit; 69 }; 70 71 struct rockchip_hdmi { 72 struct device *dev; 73 struct regmap *regmap; 74 struct rockchip_encoder encoder; 75 const struct rockchip_hdmi_chip_data *chip_data; 76 const struct dw_hdmi_plat_data *plat_data; 77 struct clk *ref_clk; 78 struct clk *grf_clk; 79 struct dw_hdmi *hdmi; 80 struct regulator *avdd_0v9; 81 struct regulator *avdd_1v8; 82 struct phy *phy; 83 }; 84 85 static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder) 86 { 87 struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); 88 89 return container_of(rkencoder, struct rockchip_hdmi, encoder); 90 } 91 92 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { 93 { 94 27000000, { 95 { 0x00b3, 0x0000}, 96 { 0x2153, 0x0000}, 97 { 0x40f3, 0x0000} 98 }, 99 }, { 100 36000000, { 101 { 0x00b3, 0x0000}, 102 { 0x2153, 0x0000}, 103 { 0x40f3, 0x0000} 104 }, 105 }, { 106 40000000, { 107 { 0x00b3, 0x0000}, 108 { 0x2153, 0x0000}, 109 { 0x40f3, 0x0000} 110 }, 111 }, { 112 54000000, { 113 { 0x0072, 0x0001}, 114 { 0x2142, 0x0001}, 115 { 0x40a2, 0x0001}, 116 }, 117 }, { 118 65000000, { 119 { 0x0072, 0x0001}, 120 { 0x2142, 0x0001}, 121 { 0x40a2, 0x0001}, 122 }, 123 }, { 124 66000000, { 125 { 0x013e, 0x0003}, 126 { 0x217e, 0x0002}, 127 { 0x4061, 0x0002} 128 }, 129 }, { 130 74250000, { 131 { 0x0072, 0x0001}, 132 { 0x2145, 0x0002}, 133 { 0x4061, 0x0002} 134 }, 135 }, { 136 83500000, { 137 { 0x0072, 0x0001}, 138 }, 139 }, { 140 108000000, { 141 { 0x0051, 0x0002}, 142 { 0x2145, 0x0002}, 143 { 0x4061, 0x0002} 144 }, 145 }, { 146 106500000, { 147 { 0x0051, 0x0002}, 148 { 0x2145, 0x0002}, 149 { 0x4061, 0x0002} 150 }, 151 }, { 152 146250000, { 153 { 0x0051, 0x0002}, 154 { 0x2145, 0x0002}, 155 { 0x4061, 0x0002} 156 }, 157 }, { 158 148500000, { 159 { 0x0051, 0x0003}, 160 { 0x214c, 0x0003}, 161 { 0x4064, 0x0003} 162 }, 163 }, { 164 340000000, { 165 { 0x0040, 0x0003 }, 166 { 0x3b4c, 0x0003 }, 167 { 0x5a64, 0x0003 }, 168 }, 169 }, { 170 ~0UL, { 171 { 0x00a0, 0x000a }, 172 { 0x2001, 0x000f }, 173 { 0x4002, 0x000f }, 174 }, 175 } 176 }; 177 178 static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { 179 /* pixelclk bpp8 bpp10 bpp12 */ 180 { 181 40000000, { 0x0018, 0x0018, 0x0018 }, 182 }, { 183 65000000, { 0x0028, 0x0028, 0x0028 }, 184 }, { 185 66000000, { 0x0038, 0x0038, 0x0038 }, 186 }, { 187 74250000, { 0x0028, 0x0038, 0x0038 }, 188 }, { 189 83500000, { 0x0028, 0x0038, 0x0038 }, 190 }, { 191 146250000, { 0x0038, 0x0038, 0x0038 }, 192 }, { 193 148500000, { 0x0000, 0x0038, 0x0038 }, 194 }, { 195 600000000, { 0x0000, 0x0000, 0x0000 }, 196 }, { 197 ~0UL, { 0x0000, 0x0000, 0x0000}, 198 } 199 }; 200 201 static const struct dw_hdmi_phy_config rockchip_phy_config[] = { 202 /*pixelclk symbol term vlev*/ 203 { 74250000, 0x8009, 0x0004, 0x0272}, 204 { 148500000, 0x802b, 0x0004, 0x028d}, 205 { 297000000, 0x8039, 0x0005, 0x028d}, 206 { ~0UL, 0x0000, 0x0000, 0x0000} 207 }; 208 209 static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) 210 { 211 struct device_node *np = hdmi->dev->of_node; 212 213 hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 214 if (IS_ERR(hdmi->regmap)) { 215 DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,grf\n"); 216 return PTR_ERR(hdmi->regmap); 217 } 218 219 hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "ref"); 220 if (!hdmi->ref_clk) 221 hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "vpll"); 222 223 if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) { 224 return -EPROBE_DEFER; 225 } else if (IS_ERR(hdmi->ref_clk)) { 226 DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n"); 227 return PTR_ERR(hdmi->ref_clk); 228 } 229 230 hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf"); 231 if (PTR_ERR(hdmi->grf_clk) == -ENOENT) { 232 hdmi->grf_clk = NULL; 233 } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) { 234 return -EPROBE_DEFER; 235 } else if (IS_ERR(hdmi->grf_clk)) { 236 DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n"); 237 return PTR_ERR(hdmi->grf_clk); 238 } 239 240 hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9"); 241 if (IS_ERR(hdmi->avdd_0v9)) 242 return PTR_ERR(hdmi->avdd_0v9); 243 244 hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8"); 245 if (IS_ERR(hdmi->avdd_1v8)) 246 return PTR_ERR(hdmi->avdd_1v8); 247 248 return 0; 249 } 250 251 static enum drm_mode_status 252 dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data, 253 const struct drm_display_info *info, 254 const struct drm_display_mode *mode) 255 { 256 struct rockchip_hdmi *hdmi = data; 257 const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; 258 int pclk = mode->clock * 1000; 259 bool exact_match = hdmi->plat_data->phy_force_vendor; 260 int i; 261 262 if (hdmi->ref_clk) { 263 int rpclk = clk_round_rate(hdmi->ref_clk, pclk); 264 265 if (abs(rpclk - pclk) > pclk / 1000) 266 return MODE_NOCLOCK; 267 } 268 269 for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { 270 /* 271 * For vendor specific phys force an exact match of the pixelclock 272 * to preserve the original behaviour of the driver. 273 */ 274 if (exact_match && pclk == mpll_cfg[i].mpixelclock) 275 return MODE_OK; 276 /* 277 * The Synopsys phy can work with pixelclocks up to the value given 278 * in the corresponding mpll_cfg entry. 279 */ 280 if (!exact_match && pclk <= mpll_cfg[i].mpixelclock) 281 return MODE_OK; 282 } 283 284 return MODE_BAD; 285 } 286 287 static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) 288 { 289 } 290 291 static bool 292 dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, 293 const struct drm_display_mode *mode, 294 struct drm_display_mode *adj_mode) 295 { 296 return true; 297 } 298 299 static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, 300 struct drm_display_mode *mode, 301 struct drm_display_mode *adj_mode) 302 { 303 struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); 304 305 clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000); 306 } 307 308 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) 309 { 310 struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); 311 u32 val; 312 int ret; 313 314 if (hdmi->chip_data->lcdsel_grf_reg < 0) 315 return; 316 317 ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); 318 if (ret) 319 val = hdmi->chip_data->lcdsel_lit; 320 else 321 val = hdmi->chip_data->lcdsel_big; 322 323 ret = clk_prepare_enable(hdmi->grf_clk); 324 if (ret < 0) { 325 DRM_DEV_ERROR(hdmi->dev, "failed to enable grfclk %d\n", ret); 326 return; 327 } 328 329 ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val); 330 if (ret != 0) 331 DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret); 332 333 clk_disable_unprepare(hdmi->grf_clk); 334 DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n", 335 ret ? "LIT" : "BIG"); 336 } 337 338 static int 339 dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, 340 struct drm_crtc_state *crtc_state, 341 struct drm_connector_state *conn_state) 342 { 343 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 344 345 s->output_mode = ROCKCHIP_OUT_MODE_AAAA; 346 s->output_type = DRM_MODE_CONNECTOR_HDMIA; 347 348 return 0; 349 } 350 351 static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { 352 .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, 353 .mode_set = dw_hdmi_rockchip_encoder_mode_set, 354 .enable = dw_hdmi_rockchip_encoder_enable, 355 .disable = dw_hdmi_rockchip_encoder_disable, 356 .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, 357 }; 358 359 static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, 360 const struct drm_display_info *display, 361 const struct drm_display_mode *mode) 362 { 363 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 364 365 return phy_power_on(hdmi->phy); 366 } 367 368 static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data) 369 { 370 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 371 372 phy_power_off(hdmi->phy); 373 } 374 375 static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) 376 { 377 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 378 379 dw_hdmi_phy_setup_hpd(dw_hdmi, data); 380 381 regmap_write(hdmi->regmap, 382 RK3228_GRF_SOC_CON6, 383 HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL | 384 RK3228_HDMI_SCL_VSEL, 385 RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL | 386 RK3228_HDMI_SCL_VSEL)); 387 388 regmap_write(hdmi->regmap, 389 RK3228_GRF_SOC_CON2, 390 HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK, 391 RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK)); 392 } 393 394 static enum drm_connector_status 395 dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data) 396 { 397 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 398 enum drm_connector_status status; 399 400 status = dw_hdmi_phy_read_hpd(dw_hdmi, data); 401 402 if (status == connector_status_connected) 403 regmap_write(hdmi->regmap, 404 RK3328_GRF_SOC_CON4, 405 HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V, 406 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V)); 407 else 408 regmap_write(hdmi->regmap, 409 RK3328_GRF_SOC_CON4, 410 HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V | 411 RK3328_HDMI_SCL_5V)); 412 return status; 413 } 414 415 static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) 416 { 417 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 418 419 dw_hdmi_phy_setup_hpd(dw_hdmi, data); 420 421 /* Enable and map pins to 3V grf-controlled io-voltage */ 422 regmap_write(hdmi->regmap, 423 RK3328_GRF_SOC_CON4, 424 HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V | 425 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V | 426 RK3328_HDMI_HPD_5V)); 427 regmap_write(hdmi->regmap, 428 RK3328_GRF_SOC_CON3, 429 HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF | 430 RK3328_HDMI_HPD5V_GRF | 431 RK3328_HDMI_CEC5V_GRF)); 432 regmap_write(hdmi->regmap, 433 RK3328_GRF_SOC_CON2, 434 HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK, 435 RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK | 436 RK3328_HDMI_HPD_IOE)); 437 } 438 439 static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = { 440 .init = dw_hdmi_rockchip_genphy_init, 441 .disable = dw_hdmi_rockchip_genphy_disable, 442 .read_hpd = dw_hdmi_phy_read_hpd, 443 .update_hpd = dw_hdmi_phy_update_hpd, 444 .setup_hpd = dw_hdmi_rk3228_setup_hpd, 445 }; 446 447 static struct rockchip_hdmi_chip_data rk3228_chip_data = { 448 .lcdsel_grf_reg = -1, 449 }; 450 451 static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { 452 .mode_valid = dw_hdmi_rockchip_mode_valid, 453 .mpll_cfg = rockchip_mpll_cfg, 454 .cur_ctr = rockchip_cur_ctr, 455 .phy_config = rockchip_phy_config, 456 .phy_data = &rk3228_chip_data, 457 .phy_ops = &rk3228_hdmi_phy_ops, 458 .phy_name = "inno_dw_hdmi_phy2", 459 .phy_force_vendor = true, 460 }; 461 462 static struct rockchip_hdmi_chip_data rk3288_chip_data = { 463 .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, 464 .lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL), 465 .lcdsel_lit = HIWORD_UPDATE(RK3288_HDMI_LCDC_SEL, RK3288_HDMI_LCDC_SEL), 466 }; 467 468 static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = { 469 .mode_valid = dw_hdmi_rockchip_mode_valid, 470 .mpll_cfg = rockchip_mpll_cfg, 471 .cur_ctr = rockchip_cur_ctr, 472 .phy_config = rockchip_phy_config, 473 .phy_data = &rk3288_chip_data, 474 }; 475 476 static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = { 477 .init = dw_hdmi_rockchip_genphy_init, 478 .disable = dw_hdmi_rockchip_genphy_disable, 479 .read_hpd = dw_hdmi_rk3328_read_hpd, 480 .update_hpd = dw_hdmi_phy_update_hpd, 481 .setup_hpd = dw_hdmi_rk3328_setup_hpd, 482 }; 483 484 static struct rockchip_hdmi_chip_data rk3328_chip_data = { 485 .lcdsel_grf_reg = -1, 486 }; 487 488 static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { 489 .mode_valid = dw_hdmi_rockchip_mode_valid, 490 .mpll_cfg = rockchip_mpll_cfg, 491 .cur_ctr = rockchip_cur_ctr, 492 .phy_config = rockchip_phy_config, 493 .phy_data = &rk3328_chip_data, 494 .phy_ops = &rk3328_hdmi_phy_ops, 495 .phy_name = "inno_dw_hdmi_phy2", 496 .phy_force_vendor = true, 497 .use_drm_infoframe = true, 498 }; 499 500 static struct rockchip_hdmi_chip_data rk3399_chip_data = { 501 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, 502 .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL), 503 .lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL), 504 }; 505 506 static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { 507 .mode_valid = dw_hdmi_rockchip_mode_valid, 508 .mpll_cfg = rockchip_mpll_cfg, 509 .cur_ctr = rockchip_cur_ctr, 510 .phy_config = rockchip_phy_config, 511 .phy_data = &rk3399_chip_data, 512 .use_drm_infoframe = true, 513 }; 514 515 static struct rockchip_hdmi_chip_data rk3568_chip_data = { 516 .lcdsel_grf_reg = -1, 517 }; 518 519 static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = { 520 .mode_valid = dw_hdmi_rockchip_mode_valid, 521 .mpll_cfg = rockchip_mpll_cfg, 522 .cur_ctr = rockchip_cur_ctr, 523 .phy_config = rockchip_phy_config, 524 .phy_data = &rk3568_chip_data, 525 .use_drm_infoframe = true, 526 }; 527 528 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { 529 { .compatible = "rockchip,rk3228-dw-hdmi", 530 .data = &rk3228_hdmi_drv_data 531 }, 532 { .compatible = "rockchip,rk3288-dw-hdmi", 533 .data = &rk3288_hdmi_drv_data 534 }, 535 { .compatible = "rockchip,rk3328-dw-hdmi", 536 .data = &rk3328_hdmi_drv_data 537 }, 538 { .compatible = "rockchip,rk3399-dw-hdmi", 539 .data = &rk3399_hdmi_drv_data 540 }, 541 { .compatible = "rockchip,rk3568-dw-hdmi", 542 .data = &rk3568_hdmi_drv_data 543 }, 544 {}, 545 }; 546 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids); 547 548 static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, 549 void *data) 550 { 551 struct platform_device *pdev = to_platform_device(dev); 552 struct dw_hdmi_plat_data *plat_data; 553 const struct of_device_id *match; 554 struct drm_device *drm = data; 555 struct drm_encoder *encoder; 556 struct rockchip_hdmi *hdmi; 557 int ret; 558 559 if (!pdev->dev.of_node) 560 return -ENODEV; 561 562 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); 563 if (!hdmi) 564 return -ENOMEM; 565 566 match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node); 567 plat_data = devm_kmemdup(&pdev->dev, match->data, 568 sizeof(*plat_data), GFP_KERNEL); 569 if (!plat_data) 570 return -ENOMEM; 571 572 hdmi->dev = &pdev->dev; 573 hdmi->plat_data = plat_data; 574 hdmi->chip_data = plat_data->phy_data; 575 plat_data->phy_data = hdmi; 576 plat_data->priv_data = hdmi; 577 encoder = &hdmi->encoder.encoder; 578 579 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); 580 rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder, 581 dev->of_node, 0, 0); 582 583 /* 584 * If we failed to find the CRTC(s) which this encoder is 585 * supposed to be connected to, it's because the CRTC has 586 * not been registered yet. Defer probing, and hope that 587 * the required CRTC is added later. 588 */ 589 if (encoder->possible_crtcs == 0) 590 return -EPROBE_DEFER; 591 592 ret = rockchip_hdmi_parse_dt(hdmi); 593 if (ret) { 594 if (ret != -EPROBE_DEFER) 595 DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n"); 596 return ret; 597 } 598 599 hdmi->phy = devm_phy_optional_get(dev, "hdmi"); 600 if (IS_ERR(hdmi->phy)) { 601 ret = PTR_ERR(hdmi->phy); 602 if (ret != -EPROBE_DEFER) 603 DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); 604 return ret; 605 } 606 607 ret = regulator_enable(hdmi->avdd_0v9); 608 if (ret) { 609 DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret); 610 goto err_avdd_0v9; 611 } 612 613 ret = regulator_enable(hdmi->avdd_1v8); 614 if (ret) { 615 DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret); 616 goto err_avdd_1v8; 617 } 618 619 ret = clk_prepare_enable(hdmi->ref_clk); 620 if (ret) { 621 DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n", 622 ret); 623 goto err_clk; 624 } 625 626 if (hdmi->chip_data == &rk3568_chip_data) { 627 regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1, 628 HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK | 629 RK3568_HDMI_SCLIN_MSK, 630 RK3568_HDMI_SDAIN_MSK | 631 RK3568_HDMI_SCLIN_MSK)); 632 } 633 634 drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); 635 drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); 636 637 platform_set_drvdata(pdev, hdmi); 638 639 hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); 640 641 /* 642 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), 643 * which would have called the encoder cleanup. Do it manually. 644 */ 645 if (IS_ERR(hdmi->hdmi)) { 646 ret = PTR_ERR(hdmi->hdmi); 647 goto err_bind; 648 } 649 650 return 0; 651 652 err_bind: 653 drm_encoder_cleanup(encoder); 654 clk_disable_unprepare(hdmi->ref_clk); 655 err_clk: 656 regulator_disable(hdmi->avdd_1v8); 657 err_avdd_1v8: 658 regulator_disable(hdmi->avdd_0v9); 659 err_avdd_0v9: 660 return ret; 661 } 662 663 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, 664 void *data) 665 { 666 struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); 667 668 dw_hdmi_unbind(hdmi->hdmi); 669 drm_encoder_cleanup(&hdmi->encoder.encoder); 670 clk_disable_unprepare(hdmi->ref_clk); 671 672 regulator_disable(hdmi->avdd_1v8); 673 regulator_disable(hdmi->avdd_0v9); 674 } 675 676 static const struct component_ops dw_hdmi_rockchip_ops = { 677 .bind = dw_hdmi_rockchip_bind, 678 .unbind = dw_hdmi_rockchip_unbind, 679 }; 680 681 static int dw_hdmi_rockchip_probe(struct platform_device *pdev) 682 { 683 return component_add(&pdev->dev, &dw_hdmi_rockchip_ops); 684 } 685 686 static void dw_hdmi_rockchip_remove(struct platform_device *pdev) 687 { 688 component_del(&pdev->dev, &dw_hdmi_rockchip_ops); 689 } 690 691 static int __maybe_unused dw_hdmi_rockchip_resume(struct device *dev) 692 { 693 struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); 694 695 dw_hdmi_resume(hdmi->hdmi); 696 697 return 0; 698 } 699 700 static const struct dev_pm_ops dw_hdmi_rockchip_pm = { 701 SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_rockchip_resume) 702 }; 703 704 struct platform_driver dw_hdmi_rockchip_pltfm_driver = { 705 .probe = dw_hdmi_rockchip_probe, 706 .remove_new = dw_hdmi_rockchip_remove, 707 .driver = { 708 .name = "dwhdmi-rockchip", 709 .pm = &dw_hdmi_rockchip_pm, 710 .of_match_table = dw_hdmi_rockchip_dt_ids, 711 }, 712 }; 713