1 /* 2 * Rockchip SoC DP (Display Port) interface driver. 3 * 4 * Copyright (C) Fuzhou Rockchip Electronics Co., Ltd. 5 * Author: Andy Yan <andy.yan@rock-chips.com> 6 * Yakir Yang <ykk@rock-chips.com> 7 * Jeff Chen <jeff.chen@rock-chips.com> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 15 #include <linux/component.h> 16 #include <linux/mfd/syscon.h> 17 #include <linux/of_device.h> 18 #include <linux/of_graph.h> 19 #include <linux/regmap.h> 20 #include <linux/reset.h> 21 #include <linux/clk.h> 22 23 #include <drm/drmP.h> 24 #include <drm/drm_crtc_helper.h> 25 #include <drm/drm_dp_helper.h> 26 #include <drm/drm_of.h> 27 #include <drm/drm_panel.h> 28 29 #include <video/of_videomode.h> 30 #include <video/videomode.h> 31 32 #include <drm/bridge/analogix_dp.h> 33 34 #include "rockchip_drm_drv.h" 35 #include "rockchip_drm_vop.h" 36 37 #define RK3288_GRF_SOC_CON6 0x25c 38 #define RK3288_EDP_LCDC_SEL BIT(5) 39 #define RK3399_GRF_SOC_CON20 0x6250 40 #define RK3399_EDP_LCDC_SEL BIT(5) 41 42 #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) 43 44 #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) 45 46 /** 47 * struct rockchip_dp_chip_data - splite the grf setting of kind of chips 48 * @lcdsel_grf_reg: grf register offset of lcdc select 49 * @lcdsel_big: reg value of selecting vop big for eDP 50 * @lcdsel_lit: reg value of selecting vop little for eDP 51 * @chip_type: specific chip type 52 */ 53 struct rockchip_dp_chip_data { 54 u32 lcdsel_grf_reg; 55 u32 lcdsel_big; 56 u32 lcdsel_lit; 57 u32 chip_type; 58 }; 59 60 struct rockchip_dp_device { 61 struct drm_device *drm_dev; 62 struct device *dev; 63 struct drm_encoder encoder; 64 struct drm_display_mode mode; 65 66 struct clk *pclk; 67 struct clk *grfclk; 68 struct regmap *grf; 69 struct reset_control *rst; 70 71 const struct rockchip_dp_chip_data *data; 72 73 struct analogix_dp_plat_data plat_data; 74 }; 75 76 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) 77 { 78 reset_control_assert(dp->rst); 79 usleep_range(10, 20); 80 reset_control_deassert(dp->rst); 81 82 return 0; 83 } 84 85 static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) 86 { 87 struct rockchip_dp_device *dp = to_dp(plat_data); 88 int ret; 89 90 ret = clk_prepare_enable(dp->pclk); 91 if (ret < 0) { 92 dev_err(dp->dev, "failed to enable pclk %d\n", ret); 93 return ret; 94 } 95 96 ret = rockchip_dp_pre_init(dp); 97 if (ret < 0) { 98 dev_err(dp->dev, "failed to dp pre init %d\n", ret); 99 clk_disable_unprepare(dp->pclk); 100 return ret; 101 } 102 103 return 0; 104 } 105 106 static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) 107 { 108 struct rockchip_dp_device *dp = to_dp(plat_data); 109 110 clk_disable_unprepare(dp->pclk); 111 112 return 0; 113 } 114 115 static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, 116 struct drm_connector *connector) 117 { 118 struct drm_display_info *di = &connector->display_info; 119 /* VOP couldn't output YUV video format for eDP rightly */ 120 u32 mask = DRM_COLOR_FORMAT_YCRCB444 | DRM_COLOR_FORMAT_YCRCB422; 121 122 if ((di->color_formats & mask)) { 123 DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); 124 di->color_formats &= ~mask; 125 di->color_formats |= DRM_COLOR_FORMAT_RGB444; 126 di->bpc = 8; 127 } 128 129 return 0; 130 } 131 132 static bool 133 rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder, 134 const struct drm_display_mode *mode, 135 struct drm_display_mode *adjusted_mode) 136 { 137 /* do nothing */ 138 return true; 139 } 140 141 static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder, 142 struct drm_display_mode *mode, 143 struct drm_display_mode *adjusted) 144 { 145 /* do nothing */ 146 } 147 148 static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) 149 { 150 struct rockchip_dp_device *dp = to_dp(encoder); 151 int ret; 152 u32 val; 153 154 ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); 155 if (ret < 0) 156 return; 157 158 if (ret) 159 val = dp->data->lcdsel_lit; 160 else 161 val = dp->data->lcdsel_big; 162 163 dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); 164 165 ret = clk_prepare_enable(dp->grfclk); 166 if (ret < 0) { 167 dev_err(dp->dev, "failed to enable grfclk %d\n", ret); 168 return; 169 } 170 171 ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); 172 if (ret != 0) 173 dev_err(dp->dev, "Could not write to GRF: %d\n", ret); 174 175 clk_disable_unprepare(dp->grfclk); 176 } 177 178 static void rockchip_dp_drm_encoder_nop(struct drm_encoder *encoder) 179 { 180 /* do nothing */ 181 } 182 183 static int 184 rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, 185 struct drm_crtc_state *crtc_state, 186 struct drm_connector_state *conn_state) 187 { 188 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 189 struct rockchip_dp_device *dp = to_dp(encoder); 190 int ret; 191 192 /* 193 * The hardware IC designed that VOP must output the RGB10 video 194 * format to eDP controller, and if eDP panel only support RGB8, 195 * then eDP controller should cut down the video data, not via VOP 196 * controller, that's why we need to hardcode the VOP output mode 197 * to RGA10 here. 198 */ 199 200 s->output_mode = ROCKCHIP_OUT_MODE_AAAA; 201 s->output_type = DRM_MODE_CONNECTOR_eDP; 202 if (dp->data->chip_type == RK3399_EDP) { 203 /* 204 * For RK3399, VOP Lit must code the out mode to RGB888, 205 * VOP Big must code the out mode to RGB10. 206 */ 207 ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, 208 encoder); 209 if (ret > 0) 210 s->output_mode = ROCKCHIP_OUT_MODE_P888; 211 } 212 213 return 0; 214 } 215 216 static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = { 217 .mode_fixup = rockchip_dp_drm_encoder_mode_fixup, 218 .mode_set = rockchip_dp_drm_encoder_mode_set, 219 .enable = rockchip_dp_drm_encoder_enable, 220 .disable = rockchip_dp_drm_encoder_nop, 221 .atomic_check = rockchip_dp_drm_encoder_atomic_check, 222 }; 223 224 static void rockchip_dp_drm_encoder_destroy(struct drm_encoder *encoder) 225 { 226 drm_encoder_cleanup(encoder); 227 } 228 229 static struct drm_encoder_funcs rockchip_dp_encoder_funcs = { 230 .destroy = rockchip_dp_drm_encoder_destroy, 231 }; 232 233 static int rockchip_dp_init(struct rockchip_dp_device *dp) 234 { 235 struct device *dev = dp->dev; 236 struct device_node *np = dev->of_node; 237 int ret; 238 239 dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 240 if (IS_ERR(dp->grf)) { 241 dev_err(dev, "failed to get rockchip,grf property\n"); 242 return PTR_ERR(dp->grf); 243 } 244 245 dp->grfclk = devm_clk_get(dev, "grf"); 246 if (PTR_ERR(dp->grfclk) == -ENOENT) { 247 dp->grfclk = NULL; 248 } else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) { 249 return -EPROBE_DEFER; 250 } else if (IS_ERR(dp->grfclk)) { 251 dev_err(dev, "failed to get grf clock\n"); 252 return PTR_ERR(dp->grfclk); 253 } 254 255 dp->pclk = devm_clk_get(dev, "pclk"); 256 if (IS_ERR(dp->pclk)) { 257 dev_err(dev, "failed to get pclk property\n"); 258 return PTR_ERR(dp->pclk); 259 } 260 261 dp->rst = devm_reset_control_get(dev, "dp"); 262 if (IS_ERR(dp->rst)) { 263 dev_err(dev, "failed to get dp reset control\n"); 264 return PTR_ERR(dp->rst); 265 } 266 267 ret = clk_prepare_enable(dp->pclk); 268 if (ret < 0) { 269 dev_err(dp->dev, "failed to enable pclk %d\n", ret); 270 return ret; 271 } 272 273 ret = rockchip_dp_pre_init(dp); 274 if (ret < 0) { 275 dev_err(dp->dev, "failed to pre init %d\n", ret); 276 clk_disable_unprepare(dp->pclk); 277 return ret; 278 } 279 280 return 0; 281 } 282 283 static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp) 284 { 285 struct drm_encoder *encoder = &dp->encoder; 286 struct drm_device *drm_dev = dp->drm_dev; 287 struct device *dev = dp->dev; 288 int ret; 289 290 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, 291 dev->of_node); 292 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); 293 294 ret = drm_encoder_init(drm_dev, encoder, &rockchip_dp_encoder_funcs, 295 DRM_MODE_ENCODER_TMDS, NULL); 296 if (ret) { 297 DRM_ERROR("failed to initialize encoder with drm\n"); 298 return ret; 299 } 300 301 drm_encoder_helper_add(encoder, &rockchip_dp_encoder_helper_funcs); 302 303 return 0; 304 } 305 306 static int rockchip_dp_bind(struct device *dev, struct device *master, 307 void *data) 308 { 309 struct rockchip_dp_device *dp = dev_get_drvdata(dev); 310 const struct rockchip_dp_chip_data *dp_data; 311 struct drm_device *drm_dev = data; 312 int ret; 313 314 /* 315 * Just like the probe function said, we don't need the 316 * device drvrate anymore, we should leave the charge to 317 * analogix dp driver, set the device drvdata to NULL. 318 */ 319 dev_set_drvdata(dev, NULL); 320 321 dp_data = of_device_get_match_data(dev); 322 if (!dp_data) 323 return -ENODEV; 324 325 ret = rockchip_dp_init(dp); 326 if (ret < 0) 327 return ret; 328 329 dp->data = dp_data; 330 dp->drm_dev = drm_dev; 331 332 ret = rockchip_dp_drm_create_encoder(dp); 333 if (ret) { 334 DRM_ERROR("failed to create drm encoder\n"); 335 return ret; 336 } 337 338 dp->plat_data.encoder = &dp->encoder; 339 340 dp->plat_data.dev_type = dp->data->chip_type; 341 dp->plat_data.power_on = rockchip_dp_poweron; 342 dp->plat_data.power_off = rockchip_dp_powerdown; 343 dp->plat_data.get_modes = rockchip_dp_get_modes; 344 345 return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); 346 } 347 348 static void rockchip_dp_unbind(struct device *dev, struct device *master, 349 void *data) 350 { 351 return analogix_dp_unbind(dev, master, data); 352 } 353 354 static const struct component_ops rockchip_dp_component_ops = { 355 .bind = rockchip_dp_bind, 356 .unbind = rockchip_dp_unbind, 357 }; 358 359 static int rockchip_dp_probe(struct platform_device *pdev) 360 { 361 struct device *dev = &pdev->dev; 362 struct device_node *panel_node, *port, *endpoint; 363 struct drm_panel *panel = NULL; 364 struct rockchip_dp_device *dp; 365 366 port = of_graph_get_port_by_id(dev->of_node, 1); 367 if (port) { 368 endpoint = of_get_child_by_name(port, "endpoint"); 369 of_node_put(port); 370 if (!endpoint) { 371 dev_err(dev, "no output endpoint found\n"); 372 return -EINVAL; 373 } 374 375 panel_node = of_graph_get_remote_port_parent(endpoint); 376 of_node_put(endpoint); 377 if (!panel_node) { 378 dev_err(dev, "no output node found\n"); 379 return -EINVAL; 380 } 381 382 panel = of_drm_find_panel(panel_node); 383 of_node_put(panel_node); 384 if (!panel) { 385 DRM_ERROR("failed to find panel\n"); 386 return -EPROBE_DEFER; 387 } 388 } 389 390 dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); 391 if (!dp) 392 return -ENOMEM; 393 394 dp->dev = dev; 395 396 dp->plat_data.panel = panel; 397 398 /* 399 * We just use the drvdata until driver run into component 400 * add function, and then we would set drvdata to null, so 401 * that analogix dp driver could take charge of the drvdata. 402 */ 403 platform_set_drvdata(pdev, dp); 404 405 return component_add(dev, &rockchip_dp_component_ops); 406 } 407 408 static int rockchip_dp_remove(struct platform_device *pdev) 409 { 410 component_del(&pdev->dev, &rockchip_dp_component_ops); 411 412 return 0; 413 } 414 415 static const struct dev_pm_ops rockchip_dp_pm_ops = { 416 #ifdef CONFIG_PM_SLEEP 417 .suspend = analogix_dp_suspend, 418 .resume_early = analogix_dp_resume, 419 #endif 420 }; 421 422 static const struct rockchip_dp_chip_data rk3399_edp = { 423 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, 424 .lcdsel_big = HIWORD_UPDATE(0, RK3399_EDP_LCDC_SEL), 425 .lcdsel_lit = HIWORD_UPDATE(RK3399_EDP_LCDC_SEL, RK3399_EDP_LCDC_SEL), 426 .chip_type = RK3399_EDP, 427 }; 428 429 static const struct rockchip_dp_chip_data rk3288_dp = { 430 .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, 431 .lcdsel_big = HIWORD_UPDATE(0, RK3288_EDP_LCDC_SEL), 432 .lcdsel_lit = HIWORD_UPDATE(RK3288_EDP_LCDC_SEL, RK3288_EDP_LCDC_SEL), 433 .chip_type = RK3288_DP, 434 }; 435 436 static const struct of_device_id rockchip_dp_dt_ids[] = { 437 {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, 438 {.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp }, 439 {} 440 }; 441 MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); 442 443 static struct platform_driver rockchip_dp_driver = { 444 .probe = rockchip_dp_probe, 445 .remove = rockchip_dp_remove, 446 .driver = { 447 .name = "rockchip-dp", 448 .owner = THIS_MODULE, 449 .pm = &rockchip_dp_pm_ops, 450 .of_match_table = of_match_ptr(rockchip_dp_dt_ids), 451 }, 452 }; 453 454 module_platform_driver(rockchip_dp_driver); 455 456 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); 457 MODULE_AUTHOR("Jeff chen <jeff.chen@rock-chips.com>"); 458 MODULE_DESCRIPTION("Rockchip Specific Analogix-DP Driver Extension"); 459 MODULE_LICENSE("GPL v2"); 460