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 40 #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) 41 42 #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) 43 44 /** 45 * struct rockchip_dp_chip_data - splite the grf setting of kind of chips 46 * @lcdsel_grf_reg: grf register offset of lcdc select 47 * @lcdsel_big: reg value of selecting vop big for eDP 48 * @lcdsel_lit: reg value of selecting vop little for eDP 49 * @chip_type: specific chip type 50 */ 51 struct rockchip_dp_chip_data { 52 u32 lcdsel_grf_reg; 53 u32 lcdsel_big; 54 u32 lcdsel_lit; 55 u32 chip_type; 56 }; 57 58 struct rockchip_dp_device { 59 struct drm_device *drm_dev; 60 struct device *dev; 61 struct drm_encoder encoder; 62 struct drm_display_mode mode; 63 64 struct clk *pclk; 65 struct regmap *grf; 66 struct reset_control *rst; 67 68 const struct rockchip_dp_chip_data *data; 69 70 struct analogix_dp_plat_data plat_data; 71 }; 72 73 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) 74 { 75 reset_control_assert(dp->rst); 76 usleep_range(10, 20); 77 reset_control_deassert(dp->rst); 78 79 return 0; 80 } 81 82 static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) 83 { 84 struct rockchip_dp_device *dp = to_dp(plat_data); 85 int ret; 86 87 ret = clk_prepare_enable(dp->pclk); 88 if (ret < 0) { 89 dev_err(dp->dev, "failed to enable pclk %d\n", ret); 90 return ret; 91 } 92 93 ret = rockchip_dp_pre_init(dp); 94 if (ret < 0) { 95 dev_err(dp->dev, "failed to dp pre init %d\n", ret); 96 return ret; 97 } 98 99 return 0; 100 } 101 102 static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) 103 { 104 struct rockchip_dp_device *dp = to_dp(plat_data); 105 106 clk_disable_unprepare(dp->pclk); 107 108 return 0; 109 } 110 111 static bool 112 rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder, 113 const struct drm_display_mode *mode, 114 struct drm_display_mode *adjusted_mode) 115 { 116 /* do nothing */ 117 return true; 118 } 119 120 static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder, 121 struct drm_display_mode *mode, 122 struct drm_display_mode *adjusted) 123 { 124 /* do nothing */ 125 } 126 127 static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) 128 { 129 struct rockchip_dp_device *dp = to_dp(encoder); 130 int ret; 131 u32 val; 132 133 ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); 134 if (ret < 0) 135 return; 136 137 if (ret) 138 val = dp->data->lcdsel_lit; 139 else 140 val = dp->data->lcdsel_big; 141 142 dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); 143 144 ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); 145 if (ret != 0) { 146 dev_err(dp->dev, "Could not write to GRF: %d\n", ret); 147 return; 148 } 149 } 150 151 static void rockchip_dp_drm_encoder_nop(struct drm_encoder *encoder) 152 { 153 /* do nothing */ 154 } 155 156 static int 157 rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, 158 struct drm_crtc_state *crtc_state, 159 struct drm_connector_state *conn_state) 160 { 161 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 162 163 /* 164 * FIXME(Yakir): driver should configure the CRTC output video 165 * mode with the display information which indicated the monitor 166 * support colorimetry. 167 * 168 * But don't know why the CRTC driver seems could only output the 169 * RGBaaa rightly. For example, if connect the "innolux,n116bge" 170 * eDP screen, EDID would indicated that screen only accepted the 171 * 6bpc mode. But if I configure CRTC to RGB666 output, then eDP 172 * screen would show a blue picture (RGB888 show a green picture). 173 * But if I configure CTRC to RGBaaa, and eDP driver still keep 174 * RGB666 input video mode, then screen would works prefect. 175 */ 176 s->output_mode = ROCKCHIP_OUT_MODE_AAAA; 177 s->output_type = DRM_MODE_CONNECTOR_eDP; 178 179 return 0; 180 } 181 182 static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = { 183 .mode_fixup = rockchip_dp_drm_encoder_mode_fixup, 184 .mode_set = rockchip_dp_drm_encoder_mode_set, 185 .enable = rockchip_dp_drm_encoder_enable, 186 .disable = rockchip_dp_drm_encoder_nop, 187 .atomic_check = rockchip_dp_drm_encoder_atomic_check, 188 }; 189 190 static void rockchip_dp_drm_encoder_destroy(struct drm_encoder *encoder) 191 { 192 drm_encoder_cleanup(encoder); 193 } 194 195 static struct drm_encoder_funcs rockchip_dp_encoder_funcs = { 196 .destroy = rockchip_dp_drm_encoder_destroy, 197 }; 198 199 static int rockchip_dp_init(struct rockchip_dp_device *dp) 200 { 201 struct device *dev = dp->dev; 202 struct device_node *np = dev->of_node; 203 int ret; 204 205 dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 206 if (IS_ERR(dp->grf)) { 207 dev_err(dev, "failed to get rockchip,grf property\n"); 208 return PTR_ERR(dp->grf); 209 } 210 211 dp->pclk = devm_clk_get(dev, "pclk"); 212 if (IS_ERR(dp->pclk)) { 213 dev_err(dev, "failed to get pclk property\n"); 214 return PTR_ERR(dp->pclk); 215 } 216 217 dp->rst = devm_reset_control_get(dev, "dp"); 218 if (IS_ERR(dp->rst)) { 219 dev_err(dev, "failed to get dp reset control\n"); 220 return PTR_ERR(dp->rst); 221 } 222 223 ret = clk_prepare_enable(dp->pclk); 224 if (ret < 0) { 225 dev_err(dp->dev, "failed to enable pclk %d\n", ret); 226 return ret; 227 } 228 229 ret = rockchip_dp_pre_init(dp); 230 if (ret < 0) { 231 dev_err(dp->dev, "failed to pre init %d\n", ret); 232 return ret; 233 } 234 235 return 0; 236 } 237 238 static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp) 239 { 240 struct drm_encoder *encoder = &dp->encoder; 241 struct drm_device *drm_dev = dp->drm_dev; 242 struct device *dev = dp->dev; 243 int ret; 244 245 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, 246 dev->of_node); 247 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); 248 249 ret = drm_encoder_init(drm_dev, encoder, &rockchip_dp_encoder_funcs, 250 DRM_MODE_ENCODER_TMDS, NULL); 251 if (ret) { 252 DRM_ERROR("failed to initialize encoder with drm\n"); 253 return ret; 254 } 255 256 drm_encoder_helper_add(encoder, &rockchip_dp_encoder_helper_funcs); 257 258 return 0; 259 } 260 261 static int rockchip_dp_bind(struct device *dev, struct device *master, 262 void *data) 263 { 264 struct rockchip_dp_device *dp = dev_get_drvdata(dev); 265 const struct rockchip_dp_chip_data *dp_data; 266 struct drm_device *drm_dev = data; 267 int ret; 268 269 /* 270 * Just like the probe function said, we don't need the 271 * device drvrate anymore, we should leave the charge to 272 * analogix dp driver, set the device drvdata to NULL. 273 */ 274 dev_set_drvdata(dev, NULL); 275 276 dp_data = of_device_get_match_data(dev); 277 if (!dp_data) 278 return -ENODEV; 279 280 ret = rockchip_dp_init(dp); 281 if (ret < 0) 282 return ret; 283 284 dp->data = dp_data; 285 dp->drm_dev = drm_dev; 286 287 ret = rockchip_dp_drm_create_encoder(dp); 288 if (ret) { 289 DRM_ERROR("failed to create drm encoder\n"); 290 return ret; 291 } 292 293 dp->plat_data.encoder = &dp->encoder; 294 295 dp->plat_data.dev_type = dp->data->chip_type; 296 dp->plat_data.power_on = rockchip_dp_poweron; 297 dp->plat_data.power_off = rockchip_dp_powerdown; 298 299 return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); 300 } 301 302 static void rockchip_dp_unbind(struct device *dev, struct device *master, 303 void *data) 304 { 305 return analogix_dp_unbind(dev, master, data); 306 } 307 308 static const struct component_ops rockchip_dp_component_ops = { 309 .bind = rockchip_dp_bind, 310 .unbind = rockchip_dp_unbind, 311 }; 312 313 static int rockchip_dp_probe(struct platform_device *pdev) 314 { 315 struct device *dev = &pdev->dev; 316 struct device_node *panel_node, *port, *endpoint; 317 struct rockchip_dp_device *dp; 318 struct drm_panel *panel; 319 320 port = of_graph_get_port_by_id(dev->of_node, 1); 321 if (!port) { 322 dev_err(dev, "can't find output port\n"); 323 return -EINVAL; 324 } 325 326 endpoint = of_get_child_by_name(port, "endpoint"); 327 of_node_put(port); 328 if (!endpoint) { 329 dev_err(dev, "no output endpoint found\n"); 330 return -EINVAL; 331 } 332 333 panel_node = of_graph_get_remote_port_parent(endpoint); 334 of_node_put(endpoint); 335 if (!panel_node) { 336 dev_err(dev, "no output node found\n"); 337 return -EINVAL; 338 } 339 340 panel = of_drm_find_panel(panel_node); 341 if (!panel) { 342 DRM_ERROR("failed to find panel\n"); 343 of_node_put(panel_node); 344 return -EPROBE_DEFER; 345 } 346 347 of_node_put(panel_node); 348 349 dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); 350 if (!dp) 351 return -ENOMEM; 352 353 dp->dev = dev; 354 355 dp->plat_data.panel = panel; 356 357 /* 358 * We just use the drvdata until driver run into component 359 * add function, and then we would set drvdata to null, so 360 * that analogix dp driver could take charge of the drvdata. 361 */ 362 platform_set_drvdata(pdev, dp); 363 364 return component_add(dev, &rockchip_dp_component_ops); 365 } 366 367 static int rockchip_dp_remove(struct platform_device *pdev) 368 { 369 component_del(&pdev->dev, &rockchip_dp_component_ops); 370 371 return 0; 372 } 373 374 static const struct dev_pm_ops rockchip_dp_pm_ops = { 375 #ifdef CONFIG_PM_SLEEP 376 .suspend = analogix_dp_suspend, 377 .resume_early = analogix_dp_resume, 378 #endif 379 }; 380 381 static const struct rockchip_dp_chip_data rk3288_dp = { 382 .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, 383 .lcdsel_big = HIWORD_UPDATE(0, RK3288_EDP_LCDC_SEL), 384 .lcdsel_lit = HIWORD_UPDATE(RK3288_EDP_LCDC_SEL, RK3288_EDP_LCDC_SEL), 385 .chip_type = RK3288_DP, 386 }; 387 388 static const struct of_device_id rockchip_dp_dt_ids[] = { 389 {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, 390 {} 391 }; 392 MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); 393 394 static struct platform_driver rockchip_dp_driver = { 395 .probe = rockchip_dp_probe, 396 .remove = rockchip_dp_remove, 397 .driver = { 398 .name = "rockchip-dp", 399 .owner = THIS_MODULE, 400 .pm = &rockchip_dp_pm_ops, 401 .of_match_table = of_match_ptr(rockchip_dp_dt_ids), 402 }, 403 }; 404 405 module_platform_driver(rockchip_dp_driver); 406 407 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); 408 MODULE_AUTHOR("Jeff chen <jeff.chen@rock-chips.com>"); 409 MODULE_DESCRIPTION("Rockchip Specific Analogix-DP Driver Extension"); 410 MODULE_LICENSE("GPL v2"); 411