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