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