1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 4 * Author: 5 * Mark Yao <mark.yao@rock-chips.com> 6 * Sandy Huang <hjc@rock-chips.com> 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/component.h> 11 #include <linux/mfd/syscon.h> 12 #include <linux/of_graph.h> 13 #include <linux/pinctrl/devinfo.h> 14 #include <linux/platform_device.h> 15 #include <linux/pm_runtime.h> 16 #include <linux/regmap.h> 17 #include <linux/reset.h> 18 #include <drm/drm_atomic_helper.h> 19 #include <drm/drm_bridge.h> 20 21 #include <drm/drm_dp_helper.h> 22 #include <drm/drm_of.h> 23 #include <drm/drm_panel.h> 24 #include <drm/drm_probe_helper.h> 25 26 #include "rockchip_drm_drv.h" 27 #include "rockchip_drm_vop.h" 28 #include "rockchip_lvds.h" 29 30 #define DISPLAY_OUTPUT_RGB 0 31 #define DISPLAY_OUTPUT_LVDS 1 32 #define DISPLAY_OUTPUT_DUAL_LVDS 2 33 34 #define connector_to_lvds(c) \ 35 container_of(c, struct rockchip_lvds, connector) 36 37 #define encoder_to_lvds(c) \ 38 container_of(c, struct rockchip_lvds, encoder) 39 40 /** 41 * rockchip_lvds_soc_data - rockchip lvds Soc private data 42 * @ch1_offset: lvds channel 1 registe offset 43 * grf_soc_con6: general registe offset for LVDS contrl 44 * grf_soc_con7: general registe offset for LVDS contrl 45 * has_vop_sel: to indicate whether need to choose from different VOP. 46 */ 47 struct rockchip_lvds_soc_data { 48 u32 ch1_offset; 49 int grf_soc_con6; 50 int grf_soc_con7; 51 bool has_vop_sel; 52 }; 53 54 struct rockchip_lvds { 55 struct device *dev; 56 void __iomem *regs; 57 struct regmap *grf; 58 struct clk *pclk; 59 const struct rockchip_lvds_soc_data *soc_data; 60 int output; /* rgb lvds or dual lvds output */ 61 int format; /* vesa or jeida format */ 62 struct drm_device *drm_dev; 63 struct drm_panel *panel; 64 struct drm_bridge *bridge; 65 struct drm_connector connector; 66 struct drm_encoder encoder; 67 struct dev_pin_info *pins; 68 }; 69 70 static inline void lvds_writel(struct rockchip_lvds *lvds, u32 offset, u32 val) 71 { 72 writel_relaxed(val, lvds->regs + offset); 73 if (lvds->output == DISPLAY_OUTPUT_LVDS) 74 return; 75 writel_relaxed(val, lvds->regs + offset + lvds->soc_data->ch1_offset); 76 } 77 78 static inline int lvds_name_to_format(const char *s) 79 { 80 if (strncmp(s, "jeida-18", 8) == 0) 81 return LVDS_JEIDA_18; 82 else if (strncmp(s, "jeida-24", 8) == 0) 83 return LVDS_JEIDA_24; 84 else if (strncmp(s, "vesa-24", 7) == 0) 85 return LVDS_VESA_24; 86 87 return -EINVAL; 88 } 89 90 static inline int lvds_name_to_output(const char *s) 91 { 92 if (strncmp(s, "rgb", 3) == 0) 93 return DISPLAY_OUTPUT_RGB; 94 else if (strncmp(s, "lvds", 4) == 0) 95 return DISPLAY_OUTPUT_LVDS; 96 else if (strncmp(s, "duallvds", 8) == 0) 97 return DISPLAY_OUTPUT_DUAL_LVDS; 98 99 return -EINVAL; 100 } 101 102 static int rockchip_lvds_poweron(struct rockchip_lvds *lvds) 103 { 104 int ret; 105 u32 val; 106 107 ret = clk_enable(lvds->pclk); 108 if (ret < 0) { 109 DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret); 110 return ret; 111 } 112 ret = pm_runtime_get_sync(lvds->dev); 113 if (ret < 0) { 114 DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret); 115 clk_disable(lvds->pclk); 116 return ret; 117 } 118 val = RK3288_LVDS_CH0_REG0_LANE4_EN | RK3288_LVDS_CH0_REG0_LANE3_EN | 119 RK3288_LVDS_CH0_REG0_LANE2_EN | RK3288_LVDS_CH0_REG0_LANE1_EN | 120 RK3288_LVDS_CH0_REG0_LANE0_EN; 121 if (lvds->output == DISPLAY_OUTPUT_RGB) { 122 val |= RK3288_LVDS_CH0_REG0_TTL_EN | 123 RK3288_LVDS_CH0_REG0_LANECK_EN; 124 lvds_writel(lvds, RK3288_LVDS_CH0_REG0, val); 125 lvds_writel(lvds, RK3288_LVDS_CH0_REG2, 126 RK3288_LVDS_PLL_FBDIV_REG2(0x46)); 127 lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 128 RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE | 129 RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE | 130 RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE | 131 RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE | 132 RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE | 133 RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE); 134 lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 135 RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA | 136 RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA | 137 RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA | 138 RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA | 139 RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA | 140 RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA); 141 } else { 142 val |= RK3288_LVDS_CH0_REG0_LVDS_EN | 143 RK3288_LVDS_CH0_REG0_LANECK_EN; 144 lvds_writel(lvds, RK3288_LVDS_CH0_REG0, val); 145 lvds_writel(lvds, RK3288_LVDS_CH0_REG1, 146 RK3288_LVDS_CH0_REG1_LANECK_BIAS | 147 RK3288_LVDS_CH0_REG1_LANE4_BIAS | 148 RK3288_LVDS_CH0_REG1_LANE3_BIAS | 149 RK3288_LVDS_CH0_REG1_LANE2_BIAS | 150 RK3288_LVDS_CH0_REG1_LANE1_BIAS | 151 RK3288_LVDS_CH0_REG1_LANE0_BIAS); 152 lvds_writel(lvds, RK3288_LVDS_CH0_REG2, 153 RK3288_LVDS_CH0_REG2_RESERVE_ON | 154 RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE | 155 RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE | 156 RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE | 157 RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE | 158 RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE | 159 RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE | 160 RK3288_LVDS_PLL_FBDIV_REG2(0x46)); 161 lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00); 162 lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00); 163 } 164 lvds_writel(lvds, RK3288_LVDS_CH0_REG3, RK3288_LVDS_PLL_FBDIV_REG3(0x46)); 165 lvds_writel(lvds, RK3288_LVDS_CH0_REGD, RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); 166 lvds_writel(lvds, RK3288_LVDS_CH0_REG20, RK3288_LVDS_CH0_REG20_LSB); 167 168 lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); 169 lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); 170 171 return 0; 172 } 173 174 static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds) 175 { 176 int ret; 177 u32 val; 178 179 lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); 180 lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); 181 val = LVDS_DUAL | LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN | LVDS_PWRDN; 182 val |= val << 16; 183 ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val); 184 if (ret != 0) 185 DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret); 186 187 pm_runtime_put(lvds->dev); 188 clk_disable(lvds->pclk); 189 } 190 191 static const struct drm_connector_funcs rockchip_lvds_connector_funcs = { 192 .fill_modes = drm_helper_probe_single_connector_modes, 193 .destroy = drm_connector_cleanup, 194 .reset = drm_atomic_helper_connector_reset, 195 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 196 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 197 }; 198 199 static int rockchip_lvds_connector_get_modes(struct drm_connector *connector) 200 { 201 struct rockchip_lvds *lvds = connector_to_lvds(connector); 202 struct drm_panel *panel = lvds->panel; 203 204 return drm_panel_get_modes(panel); 205 } 206 207 static const 208 struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = { 209 .get_modes = rockchip_lvds_connector_get_modes, 210 }; 211 212 static void rockchip_lvds_grf_config(struct drm_encoder *encoder, 213 struct drm_display_mode *mode) 214 { 215 struct rockchip_lvds *lvds = encoder_to_lvds(encoder); 216 u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0; 217 u8 pin_dclk = (mode->flags & DRM_MODE_FLAG_PCSYNC) ? 1 : 0; 218 u32 val; 219 int ret; 220 221 /* iomux to LCD data/sync mode */ 222 if (lvds->output == DISPLAY_OUTPUT_RGB) 223 if (lvds->pins && !IS_ERR(lvds->pins->default_state)) 224 pinctrl_select_state(lvds->pins->p, 225 lvds->pins->default_state); 226 val = lvds->format | LVDS_CH0_EN; 227 if (lvds->output == DISPLAY_OUTPUT_RGB) 228 val |= LVDS_TTL_EN | LVDS_CH1_EN; 229 else if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS) 230 val |= LVDS_DUAL | LVDS_CH1_EN; 231 232 if ((mode->htotal - mode->hsync_start) & 0x01) 233 val |= LVDS_START_PHASE_RST_1; 234 235 val |= (pin_dclk << 8) | (pin_hsync << 9); 236 val |= (0xffff << 16); 237 ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val); 238 if (ret != 0) { 239 DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret); 240 return; 241 } 242 } 243 244 static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds, 245 struct drm_encoder *encoder) 246 { 247 u32 val; 248 int ret; 249 250 if (!lvds->soc_data->has_vop_sel) 251 return 0; 252 253 ret = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder); 254 if (ret < 0) 255 return ret; 256 257 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16; 258 if (ret) 259 val |= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT; 260 261 ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val); 262 if (ret < 0) 263 return ret; 264 265 return 0; 266 } 267 268 static int 269 rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder, 270 struct drm_crtc_state *crtc_state, 271 struct drm_connector_state *conn_state) 272 { 273 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 274 275 s->output_mode = ROCKCHIP_OUT_MODE_P888; 276 s->output_type = DRM_MODE_CONNECTOR_LVDS; 277 278 return 0; 279 } 280 281 static void rockchip_lvds_encoder_enable(struct drm_encoder *encoder) 282 { 283 struct rockchip_lvds *lvds = encoder_to_lvds(encoder); 284 struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; 285 int ret; 286 287 drm_panel_prepare(lvds->panel); 288 ret = rockchip_lvds_poweron(lvds); 289 if (ret < 0) { 290 DRM_DEV_ERROR(lvds->dev, "failed to power on lvds: %d\n", ret); 291 drm_panel_unprepare(lvds->panel); 292 } 293 rockchip_lvds_grf_config(encoder, mode); 294 rockchip_lvds_set_vop_source(lvds, encoder); 295 drm_panel_enable(lvds->panel); 296 } 297 298 static void rockchip_lvds_encoder_disable(struct drm_encoder *encoder) 299 { 300 struct rockchip_lvds *lvds = encoder_to_lvds(encoder); 301 302 drm_panel_disable(lvds->panel); 303 rockchip_lvds_poweroff(lvds); 304 drm_panel_unprepare(lvds->panel); 305 } 306 307 static const 308 struct drm_encoder_helper_funcs rockchip_lvds_encoder_helper_funcs = { 309 .enable = rockchip_lvds_encoder_enable, 310 .disable = rockchip_lvds_encoder_disable, 311 .atomic_check = rockchip_lvds_encoder_atomic_check, 312 }; 313 314 static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs = { 315 .destroy = drm_encoder_cleanup, 316 }; 317 318 static const struct rockchip_lvds_soc_data rk3288_lvds_data = { 319 .ch1_offset = 0x100, 320 .grf_soc_con6 = 0x025c, 321 .grf_soc_con7 = 0x0260, 322 .has_vop_sel = true, 323 }; 324 325 static const struct of_device_id rockchip_lvds_dt_ids[] = { 326 { 327 .compatible = "rockchip,rk3288-lvds", 328 .data = &rk3288_lvds_data 329 }, 330 {} 331 }; 332 MODULE_DEVICE_TABLE(of, rockchip_lvds_dt_ids); 333 334 static int rockchip_lvds_bind(struct device *dev, struct device *master, 335 void *data) 336 { 337 struct rockchip_lvds *lvds = dev_get_drvdata(dev); 338 struct drm_device *drm_dev = data; 339 struct drm_encoder *encoder; 340 struct drm_connector *connector; 341 struct device_node *remote = NULL; 342 struct device_node *port, *endpoint; 343 int ret = 0, child_count = 0; 344 const char *name; 345 u32 endpoint_id; 346 347 lvds->drm_dev = drm_dev; 348 port = of_graph_get_port_by_id(dev->of_node, 1); 349 if (!port) { 350 DRM_DEV_ERROR(dev, 351 "can't found port point, please init lvds panel port!\n"); 352 return -EINVAL; 353 } 354 for_each_child_of_node(port, endpoint) { 355 child_count++; 356 of_property_read_u32(endpoint, "reg", &endpoint_id); 357 ret = drm_of_find_panel_or_bridge(dev->of_node, 1, endpoint_id, 358 &lvds->panel, &lvds->bridge); 359 if (!ret) { 360 of_node_put(endpoint); 361 break; 362 } 363 } 364 if (!child_count) { 365 DRM_DEV_ERROR(dev, "lvds port does not have any children\n"); 366 ret = -EINVAL; 367 goto err_put_port; 368 } else if (ret) { 369 DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); 370 ret = -EPROBE_DEFER; 371 goto err_put_port; 372 } 373 if (lvds->panel) 374 remote = lvds->panel->dev->of_node; 375 else 376 remote = lvds->bridge->of_node; 377 if (of_property_read_string(dev->of_node, "rockchip,output", &name)) 378 /* default set it as output rgb */ 379 lvds->output = DISPLAY_OUTPUT_RGB; 380 else 381 lvds->output = lvds_name_to_output(name); 382 383 if (lvds->output < 0) { 384 DRM_DEV_ERROR(dev, "invalid output type [%s]\n", name); 385 ret = lvds->output; 386 goto err_put_remote; 387 } 388 389 if (of_property_read_string(remote, "data-mapping", &name)) 390 /* default set it as format vesa 18 */ 391 lvds->format = LVDS_VESA_18; 392 else 393 lvds->format = lvds_name_to_format(name); 394 395 if (lvds->format < 0) { 396 DRM_DEV_ERROR(dev, "invalid data-mapping format [%s]\n", name); 397 ret = lvds->format; 398 goto err_put_remote; 399 } 400 401 encoder = &lvds->encoder; 402 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, 403 dev->of_node); 404 405 ret = drm_encoder_init(drm_dev, encoder, &rockchip_lvds_encoder_funcs, 406 DRM_MODE_ENCODER_LVDS, NULL); 407 if (ret < 0) { 408 DRM_DEV_ERROR(drm_dev->dev, 409 "failed to initialize encoder: %d\n", ret); 410 goto err_put_remote; 411 } 412 413 drm_encoder_helper_add(encoder, &rockchip_lvds_encoder_helper_funcs); 414 415 if (lvds->panel) { 416 connector = &lvds->connector; 417 connector->dpms = DRM_MODE_DPMS_OFF; 418 ret = drm_connector_init(drm_dev, connector, 419 &rockchip_lvds_connector_funcs, 420 DRM_MODE_CONNECTOR_LVDS); 421 if (ret < 0) { 422 DRM_DEV_ERROR(drm_dev->dev, 423 "failed to initialize connector: %d\n", ret); 424 goto err_free_encoder; 425 } 426 427 drm_connector_helper_add(connector, 428 &rockchip_lvds_connector_helper_funcs); 429 430 ret = drm_connector_attach_encoder(connector, encoder); 431 if (ret < 0) { 432 DRM_DEV_ERROR(drm_dev->dev, 433 "failed to attach encoder: %d\n", ret); 434 goto err_free_connector; 435 } 436 437 ret = drm_panel_attach(lvds->panel, connector); 438 if (ret < 0) { 439 DRM_DEV_ERROR(drm_dev->dev, 440 "failed to attach panel: %d\n", ret); 441 goto err_free_connector; 442 } 443 } else { 444 ret = drm_bridge_attach(encoder, lvds->bridge, NULL); 445 if (ret) { 446 DRM_DEV_ERROR(drm_dev->dev, 447 "failed to attach bridge: %d\n", ret); 448 goto err_free_encoder; 449 } 450 } 451 452 pm_runtime_enable(dev); 453 of_node_put(remote); 454 of_node_put(port); 455 456 return 0; 457 458 err_free_connector: 459 drm_connector_cleanup(connector); 460 err_free_encoder: 461 drm_encoder_cleanup(encoder); 462 err_put_remote: 463 of_node_put(remote); 464 err_put_port: 465 of_node_put(port); 466 467 return ret; 468 } 469 470 static void rockchip_lvds_unbind(struct device *dev, struct device *master, 471 void *data) 472 { 473 struct rockchip_lvds *lvds = dev_get_drvdata(dev); 474 475 rockchip_lvds_encoder_disable(&lvds->encoder); 476 if (lvds->panel) 477 drm_panel_detach(lvds->panel); 478 pm_runtime_disable(dev); 479 drm_connector_cleanup(&lvds->connector); 480 drm_encoder_cleanup(&lvds->encoder); 481 } 482 483 static const struct component_ops rockchip_lvds_component_ops = { 484 .bind = rockchip_lvds_bind, 485 .unbind = rockchip_lvds_unbind, 486 }; 487 488 static int rockchip_lvds_probe(struct platform_device *pdev) 489 { 490 struct device *dev = &pdev->dev; 491 struct rockchip_lvds *lvds; 492 const struct of_device_id *match; 493 struct resource *res; 494 int ret; 495 496 if (!dev->of_node) 497 return -ENODEV; 498 499 lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL); 500 if (!lvds) 501 return -ENOMEM; 502 503 lvds->dev = dev; 504 match = of_match_node(rockchip_lvds_dt_ids, dev->of_node); 505 if (!match) 506 return -ENODEV; 507 lvds->soc_data = match->data; 508 509 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 510 lvds->regs = devm_ioremap_resource(&pdev->dev, res); 511 if (IS_ERR(lvds->regs)) 512 return PTR_ERR(lvds->regs); 513 514 lvds->pclk = devm_clk_get(&pdev->dev, "pclk_lvds"); 515 if (IS_ERR(lvds->pclk)) { 516 DRM_DEV_ERROR(dev, "could not get pclk_lvds\n"); 517 return PTR_ERR(lvds->pclk); 518 } 519 520 lvds->pins = devm_kzalloc(lvds->dev, sizeof(*lvds->pins), 521 GFP_KERNEL); 522 if (!lvds->pins) 523 return -ENOMEM; 524 525 lvds->pins->p = devm_pinctrl_get(lvds->dev); 526 if (IS_ERR(lvds->pins->p)) { 527 DRM_DEV_ERROR(dev, "no pinctrl handle\n"); 528 devm_kfree(lvds->dev, lvds->pins); 529 lvds->pins = NULL; 530 } else { 531 lvds->pins->default_state = 532 pinctrl_lookup_state(lvds->pins->p, "lcdc"); 533 if (IS_ERR(lvds->pins->default_state)) { 534 DRM_DEV_ERROR(dev, "no default pinctrl state\n"); 535 devm_kfree(lvds->dev, lvds->pins); 536 lvds->pins = NULL; 537 } 538 } 539 540 lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node, 541 "rockchip,grf"); 542 if (IS_ERR(lvds->grf)) { 543 DRM_DEV_ERROR(dev, "missing rockchip,grf property\n"); 544 return PTR_ERR(lvds->grf); 545 } 546 547 dev_set_drvdata(dev, lvds); 548 549 ret = clk_prepare(lvds->pclk); 550 if (ret < 0) { 551 DRM_DEV_ERROR(dev, "failed to prepare pclk_lvds\n"); 552 return ret; 553 } 554 ret = component_add(&pdev->dev, &rockchip_lvds_component_ops); 555 if (ret < 0) { 556 DRM_DEV_ERROR(dev, "failed to add component\n"); 557 clk_unprepare(lvds->pclk); 558 } 559 560 return ret; 561 } 562 563 static int rockchip_lvds_remove(struct platform_device *pdev) 564 { 565 struct rockchip_lvds *lvds = dev_get_drvdata(&pdev->dev); 566 567 component_del(&pdev->dev, &rockchip_lvds_component_ops); 568 clk_unprepare(lvds->pclk); 569 570 return 0; 571 } 572 573 struct platform_driver rockchip_lvds_driver = { 574 .probe = rockchip_lvds_probe, 575 .remove = rockchip_lvds_remove, 576 .driver = { 577 .name = "rockchip-lvds", 578 .of_match_table = of_match_ptr(rockchip_lvds_dt_ids), 579 }, 580 }; 581