1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. 4 * Copyright (c) 2024 Collabora Ltd. 5 * 6 * Author: Algea Cao <algea.cao@rock-chips.com> 7 * Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> 8 */ 9 10 #include <linux/clk.h> 11 #include <linux/gpio/consumer.h> 12 #include <linux/mfd/syscon.h> 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 #include <linux/phy/phy.h> 16 #include <linux/regmap.h> 17 #include <linux/workqueue.h> 18 19 #include <drm/bridge/dw_hdmi_qp.h> 20 #include <drm/display/drm_hdmi_helper.h> 21 #include <drm/drm_bridge_connector.h> 22 #include <drm/drm_of.h> 23 #include <drm/drm_probe_helper.h> 24 #include <drm/drm_simple_kms_helper.h> 25 26 #include "rockchip_drm_drv.h" 27 28 #define RK3588_GRF_SOC_CON2 0x0308 29 #define RK3588_HDMI0_HPD_INT_MSK BIT(13) 30 #define RK3588_HDMI0_HPD_INT_CLR BIT(12) 31 #define RK3588_HDMI1_HPD_INT_MSK BIT(15) 32 #define RK3588_HDMI1_HPD_INT_CLR BIT(14) 33 #define RK3588_GRF_SOC_CON7 0x031c 34 #define RK3588_SET_HPD_PATH_MASK GENMASK(13, 12) 35 #define RK3588_GRF_SOC_STATUS1 0x0384 36 #define RK3588_HDMI0_LEVEL_INT BIT(16) 37 #define RK3588_HDMI1_LEVEL_INT BIT(24) 38 #define RK3588_GRF_VO1_CON3 0x000c 39 #define RK3588_GRF_VO1_CON6 0x0018 40 #define RK3588_SCLIN_MASK BIT(9) 41 #define RK3588_SDAIN_MASK BIT(10) 42 #define RK3588_MODE_MASK BIT(11) 43 #define RK3588_I2S_SEL_MASK BIT(13) 44 #define RK3588_GRF_VO1_CON9 0x0024 45 #define RK3588_HDMI0_GRANT_SEL BIT(10) 46 #define RK3588_HDMI1_GRANT_SEL BIT(12) 47 48 #define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) 49 #define HOTPLUG_DEBOUNCE_MS 150 50 #define MAX_HDMI_PORT_NUM 2 51 52 struct rockchip_hdmi_qp { 53 struct device *dev; 54 struct regmap *regmap; 55 struct regmap *vo_regmap; 56 struct rockchip_encoder encoder; 57 struct clk *ref_clk; 58 struct dw_hdmi_qp *hdmi; 59 struct phy *phy; 60 struct gpio_desc *enable_gpio; 61 struct delayed_work hpd_work; 62 int port_id; 63 }; 64 65 static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder) 66 { 67 struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); 68 69 return container_of(rkencoder, struct rockchip_hdmi_qp, encoder); 70 } 71 72 static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder) 73 { 74 struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder); 75 struct drm_crtc *crtc = encoder->crtc; 76 unsigned long long rate; 77 78 /* Unconditionally switch to TMDS as FRL is not yet supported */ 79 gpiod_set_value(hdmi->enable_gpio, 1); 80 81 if (crtc && crtc->state) { 82 rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode, 83 8, HDMI_COLORSPACE_RGB); 84 clk_set_rate(hdmi->ref_clk, rate); 85 /* 86 * FIXME: Temporary workaround to pass pixel clock rate 87 * to the PHY driver until phy_configure_opts_hdmi 88 * becomes available in the PHY API. See also the related 89 * comment in rk_hdptx_phy_power_on() from 90 * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c 91 */ 92 phy_set_bus_width(hdmi->phy, div_u64(rate, 100)); 93 } 94 } 95 96 static int 97 dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder, 98 struct drm_crtc_state *crtc_state, 99 struct drm_connector_state *conn_state) 100 { 101 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 102 103 s->output_mode = ROCKCHIP_OUT_MODE_AAAA; 104 s->output_type = DRM_MODE_CONNECTOR_HDMIA; 105 106 return 0; 107 } 108 109 static const struct 110 drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = { 111 .enable = dw_hdmi_qp_rockchip_encoder_enable, 112 .atomic_check = dw_hdmi_qp_rockchip_encoder_atomic_check, 113 }; 114 115 static int dw_hdmi_qp_rk3588_phy_init(struct dw_hdmi_qp *dw_hdmi, void *data) 116 { 117 struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; 118 119 return phy_power_on(hdmi->phy); 120 } 121 122 static void dw_hdmi_qp_rk3588_phy_disable(struct dw_hdmi_qp *dw_hdmi, 123 void *data) 124 { 125 struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; 126 127 phy_power_off(hdmi->phy); 128 } 129 130 static enum drm_connector_status 131 dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) 132 { 133 struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; 134 u32 val; 135 136 regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val); 137 val &= hdmi->port_id ? RK3588_HDMI1_LEVEL_INT : RK3588_HDMI0_LEVEL_INT; 138 139 return val ? connector_status_connected : connector_status_disconnected; 140 } 141 142 static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) 143 { 144 struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; 145 u32 val; 146 147 if (hdmi->port_id) 148 val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR, 149 RK3588_HDMI1_HPD_INT_CLR | RK3588_HDMI1_HPD_INT_MSK); 150 else 151 val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, 152 RK3588_HDMI0_HPD_INT_CLR | RK3588_HDMI0_HPD_INT_MSK); 153 154 regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 155 } 156 157 static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = { 158 .init = dw_hdmi_qp_rk3588_phy_init, 159 .disable = dw_hdmi_qp_rk3588_phy_disable, 160 .read_hpd = dw_hdmi_qp_rk3588_read_hpd, 161 .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd, 162 }; 163 164 static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work) 165 { 166 struct rockchip_hdmi_qp *hdmi = container_of(work, 167 struct rockchip_hdmi_qp, 168 hpd_work.work); 169 struct drm_device *drm = hdmi->encoder.encoder.dev; 170 bool changed; 171 172 if (drm) { 173 changed = drm_helper_hpd_irq_event(drm); 174 if (changed) 175 drm_dbg(hdmi, "connector status changed\n"); 176 } 177 } 178 179 static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id) 180 { 181 struct rockchip_hdmi_qp *hdmi = dev_id; 182 u32 intr_stat, val; 183 184 regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); 185 186 if (intr_stat) { 187 if (hdmi->port_id) 188 val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, 189 RK3588_HDMI1_HPD_INT_MSK); 190 else 191 val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, 192 RK3588_HDMI0_HPD_INT_MSK); 193 regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 194 return IRQ_WAKE_THREAD; 195 } 196 197 return IRQ_NONE; 198 } 199 200 static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id) 201 { 202 struct rockchip_hdmi_qp *hdmi = dev_id; 203 u32 intr_stat, val; 204 205 regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); 206 if (!intr_stat) 207 return IRQ_NONE; 208 209 if (hdmi->port_id) 210 val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR, 211 RK3588_HDMI1_HPD_INT_CLR); 212 else 213 val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, 214 RK3588_HDMI0_HPD_INT_CLR); 215 regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 216 217 mod_delayed_work(system_wq, &hdmi->hpd_work, 218 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); 219 220 if (hdmi->port_id) 221 val |= HIWORD_UPDATE(0, RK3588_HDMI1_HPD_INT_MSK); 222 else 223 val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK); 224 regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 225 226 return IRQ_HANDLED; 227 } 228 229 struct rockchip_hdmi_qp_cfg { 230 unsigned int num_ports; 231 unsigned int port_ids[MAX_HDMI_PORT_NUM]; 232 const struct dw_hdmi_qp_phy_ops *phy_ops; 233 }; 234 235 static const struct rockchip_hdmi_qp_cfg rk3588_hdmi_cfg = { 236 .num_ports = 2, 237 .port_ids = { 238 0xfde80000, 239 0xfdea0000, 240 }, 241 .phy_ops = &rk3588_hdmi_phy_ops, 242 }; 243 244 static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = { 245 { .compatible = "rockchip,rk3588-dw-hdmi-qp", 246 .data = &rk3588_hdmi_cfg }, 247 {}, 248 }; 249 MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids); 250 251 static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, 252 void *data) 253 { 254 struct platform_device *pdev = to_platform_device(dev); 255 const struct rockchip_hdmi_qp_cfg *cfg; 256 struct dw_hdmi_qp_plat_data plat_data; 257 struct drm_device *drm = data; 258 struct drm_connector *connector; 259 struct drm_encoder *encoder; 260 struct rockchip_hdmi_qp *hdmi; 261 struct resource *res; 262 struct clk_bulk_data *clks; 263 int ret, irq, i; 264 u32 val; 265 266 if (!pdev->dev.of_node) 267 return -ENODEV; 268 269 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); 270 if (!hdmi) 271 return -ENOMEM; 272 273 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 274 if (!res) 275 return -ENODEV; 276 277 cfg = of_device_get_match_data(dev); 278 if (!cfg) 279 return -ENODEV; 280 281 hdmi->dev = &pdev->dev; 282 hdmi->port_id = -ENODEV; 283 284 /* Identify port ID by matching base IO address */ 285 for (i = 0; i < cfg->num_ports; i++) { 286 if (res->start == cfg->port_ids[i]) { 287 hdmi->port_id = i; 288 break; 289 } 290 } 291 if (hdmi->port_id < 0) { 292 drm_err(hdmi, "Failed to match HDMI port ID\n"); 293 return hdmi->port_id; 294 } 295 296 plat_data.phy_ops = cfg->phy_ops; 297 plat_data.phy_data = hdmi; 298 299 encoder = &hdmi->encoder.encoder; 300 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); 301 302 rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder, 303 dev->of_node, 0, 0); 304 /* 305 * If we failed to find the CRTC(s) which this encoder is 306 * supposed to be connected to, it's because the CRTC has 307 * not been registered yet. Defer probing, and hope that 308 * the required CRTC is added later. 309 */ 310 if (encoder->possible_crtcs == 0) 311 return -EPROBE_DEFER; 312 313 hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, 314 "rockchip,grf"); 315 if (IS_ERR(hdmi->regmap)) { 316 drm_err(hdmi, "Unable to get rockchip,grf\n"); 317 return PTR_ERR(hdmi->regmap); 318 } 319 320 hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, 321 "rockchip,vo-grf"); 322 if (IS_ERR(hdmi->vo_regmap)) { 323 drm_err(hdmi, "Unable to get rockchip,vo-grf\n"); 324 return PTR_ERR(hdmi->vo_regmap); 325 } 326 327 ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks); 328 if (ret < 0) { 329 drm_err(hdmi, "Failed to get clocks: %d\n", ret); 330 return ret; 331 } 332 333 for (i = 0; i < ret; i++) { 334 if (!strcmp(clks[i].id, "ref")) { 335 hdmi->ref_clk = clks[1].clk; 336 break; 337 } 338 } 339 if (!hdmi->ref_clk) { 340 drm_err(hdmi, "Missing ref clock\n"); 341 return -EINVAL; 342 } 343 344 hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable", 345 GPIOD_OUT_HIGH); 346 if (IS_ERR(hdmi->enable_gpio)) { 347 ret = PTR_ERR(hdmi->enable_gpio); 348 drm_err(hdmi, "Failed to request enable GPIO: %d\n", ret); 349 return ret; 350 } 351 352 hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0); 353 if (IS_ERR(hdmi->phy)) { 354 ret = PTR_ERR(hdmi->phy); 355 if (ret != -EPROBE_DEFER) 356 drm_err(hdmi, "failed to get phy: %d\n", ret); 357 return ret; 358 } 359 360 val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | 361 HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | 362 HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | 363 HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); 364 regmap_write(hdmi->vo_regmap, 365 hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3, 366 val); 367 368 val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, 369 RK3588_SET_HPD_PATH_MASK); 370 regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); 371 372 if (hdmi->port_id) 373 val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL, 374 RK3588_HDMI1_GRANT_SEL); 375 else 376 val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, 377 RK3588_HDMI0_GRANT_SEL); 378 regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); 379 380 if (hdmi->port_id) 381 val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, RK3588_HDMI1_HPD_INT_MSK); 382 else 383 val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK); 384 regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 385 386 INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work); 387 388 plat_data.main_irq = platform_get_irq_byname(pdev, "main"); 389 if (plat_data.main_irq < 0) 390 return plat_data.main_irq; 391 392 irq = platform_get_irq_byname(pdev, "hpd"); 393 if (irq < 0) 394 return irq; 395 396 ret = devm_request_threaded_irq(hdmi->dev, irq, 397 dw_hdmi_qp_rk3588_hardirq, 398 dw_hdmi_qp_rk3588_irq, 399 IRQF_SHARED, "dw-hdmi-qp-hpd", 400 hdmi); 401 if (ret) 402 return ret; 403 404 drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs); 405 drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); 406 407 platform_set_drvdata(pdev, hdmi); 408 409 hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data); 410 if (IS_ERR(hdmi->hdmi)) { 411 ret = PTR_ERR(hdmi->hdmi); 412 drm_encoder_cleanup(encoder); 413 return ret; 414 } 415 416 connector = drm_bridge_connector_init(drm, encoder); 417 if (IS_ERR(connector)) { 418 ret = PTR_ERR(connector); 419 drm_err(hdmi, "failed to init bridge connector: %d\n", ret); 420 return ret; 421 } 422 423 return drm_connector_attach_encoder(connector, encoder); 424 } 425 426 static void dw_hdmi_qp_rockchip_unbind(struct device *dev, 427 struct device *master, 428 void *data) 429 { 430 struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); 431 432 cancel_delayed_work_sync(&hdmi->hpd_work); 433 434 drm_encoder_cleanup(&hdmi->encoder.encoder); 435 } 436 437 static const struct component_ops dw_hdmi_qp_rockchip_ops = { 438 .bind = dw_hdmi_qp_rockchip_bind, 439 .unbind = dw_hdmi_qp_rockchip_unbind, 440 }; 441 442 static int dw_hdmi_qp_rockchip_probe(struct platform_device *pdev) 443 { 444 return component_add(&pdev->dev, &dw_hdmi_qp_rockchip_ops); 445 } 446 447 static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev) 448 { 449 component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops); 450 } 451 452 static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) 453 { 454 struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); 455 u32 val; 456 457 val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | 458 HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | 459 HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | 460 HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); 461 regmap_write(hdmi->vo_regmap, 462 hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3, 463 val); 464 465 val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, 466 RK3588_SET_HPD_PATH_MASK); 467 regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); 468 469 if (hdmi->port_id) 470 val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL, 471 RK3588_HDMI1_GRANT_SEL); 472 else 473 val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, 474 RK3588_HDMI0_GRANT_SEL); 475 regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); 476 477 dw_hdmi_qp_resume(dev, hdmi->hdmi); 478 479 if (hdmi->encoder.encoder.dev) 480 drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev); 481 482 return 0; 483 } 484 485 static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = { 486 SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume) 487 }; 488 489 struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = { 490 .probe = dw_hdmi_qp_rockchip_probe, 491 .remove = dw_hdmi_qp_rockchip_remove, 492 .driver = { 493 .name = "dwhdmiqp-rockchip", 494 .pm = &dw_hdmi_qp_rockchip_pm, 495 .of_match_table = dw_hdmi_qp_rockchip_dt_ids, 496 }, 497 }; 498