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