linux/drivers/gpu/drm/rockchip/rockchip_lvds.c
<<
>>
Prefs
   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/phy/phy.h>
  14#include <linux/pinctrl/devinfo.h>
  15#include <linux/platform_device.h>
  16#include <linux/pm_runtime.h>
  17#include <linux/regmap.h>
  18#include <linux/reset.h>
  19
  20#include <drm/drm_atomic_helper.h>
  21#include <drm/drm_bridge.h>
  22#include <drm/drm_dp_helper.h>
  23#include <drm/drm_of.h>
  24#include <drm/drm_panel.h>
  25#include <drm/drm_probe_helper.h>
  26#include <drm/drm_simple_kms_helper.h>
  27
  28#include "rockchip_drm_drv.h"
  29#include "rockchip_drm_vop.h"
  30#include "rockchip_lvds.h"
  31
  32#define DISPLAY_OUTPUT_RGB              0
  33#define DISPLAY_OUTPUT_LVDS             1
  34#define DISPLAY_OUTPUT_DUAL_LVDS        2
  35
  36struct rockchip_lvds;
  37
  38#define connector_to_lvds(c) \
  39                container_of(c, struct rockchip_lvds, connector)
  40
  41#define encoder_to_lvds(c) \
  42                container_of(c, struct rockchip_lvds, encoder)
  43
  44/**
  45 * struct rockchip_lvds_soc_data - rockchip lvds Soc private data
  46 * @probe: LVDS platform probe function
  47 * @helper_funcs: LVDS connector helper functions
  48 */
  49struct rockchip_lvds_soc_data {
  50        int (*probe)(struct platform_device *pdev, struct rockchip_lvds *lvds);
  51        const struct drm_encoder_helper_funcs *helper_funcs;
  52};
  53
  54struct rockchip_lvds {
  55        struct device *dev;
  56        void __iomem *regs;
  57        struct regmap *grf;
  58        struct clk *pclk;
  59        struct phy *dphy;
  60        const struct rockchip_lvds_soc_data *soc_data;
  61        int output; /* rgb lvds or dual lvds output */
  62        int format; /* vesa or jeida format */
  63        struct drm_device *drm_dev;
  64        struct drm_panel *panel;
  65        struct drm_bridge *bridge;
  66        struct drm_connector connector;
  67        struct drm_encoder encoder;
  68        struct dev_pin_info *pins;
  69};
  70
  71static inline void rk3288_writel(struct rockchip_lvds *lvds, u32 offset,
  72                                 u32 val)
  73{
  74        writel_relaxed(val, lvds->regs + offset);
  75        if (lvds->output == DISPLAY_OUTPUT_LVDS)
  76                return;
  77        writel_relaxed(val, lvds->regs + offset + RK3288_LVDS_CH1_OFFSET);
  78}
  79
  80static inline int rockchip_lvds_name_to_format(const char *s)
  81{
  82        if (strncmp(s, "jeida-18", 8) == 0)
  83                return LVDS_JEIDA_18;
  84        else if (strncmp(s, "jeida-24", 8) == 0)
  85                return LVDS_JEIDA_24;
  86        else if (strncmp(s, "vesa-24", 7) == 0)
  87                return LVDS_VESA_24;
  88
  89        return -EINVAL;
  90}
  91
  92static inline int rockchip_lvds_name_to_output(const char *s)
  93{
  94        if (strncmp(s, "rgb", 3) == 0)
  95                return DISPLAY_OUTPUT_RGB;
  96        else if (strncmp(s, "lvds", 4) == 0)
  97                return DISPLAY_OUTPUT_LVDS;
  98        else if (strncmp(s, "duallvds", 8) == 0)
  99                return DISPLAY_OUTPUT_DUAL_LVDS;
 100
 101        return -EINVAL;
 102}
 103
 104static const struct drm_connector_funcs rockchip_lvds_connector_funcs = {
 105        .fill_modes = drm_helper_probe_single_connector_modes,
 106        .destroy = drm_connector_cleanup,
 107        .reset = drm_atomic_helper_connector_reset,
 108        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 109        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 110};
 111
 112static int rockchip_lvds_connector_get_modes(struct drm_connector *connector)
 113{
 114        struct rockchip_lvds *lvds = connector_to_lvds(connector);
 115        struct drm_panel *panel = lvds->panel;
 116
 117        return drm_panel_get_modes(panel, connector);
 118}
 119
 120static const
 121struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = {
 122        .get_modes = rockchip_lvds_connector_get_modes,
 123};
 124
 125static int
 126rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder,
 127                                   struct drm_crtc_state *crtc_state,
 128                                   struct drm_connector_state *conn_state)
 129{
 130        struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
 131
 132        s->output_mode = ROCKCHIP_OUT_MODE_P888;
 133        s->output_type = DRM_MODE_CONNECTOR_LVDS;
 134
 135        return 0;
 136}
 137
 138static int rk3288_lvds_poweron(struct rockchip_lvds *lvds)
 139{
 140        int ret;
 141        u32 val;
 142
 143        ret = clk_enable(lvds->pclk);
 144        if (ret < 0) {
 145                DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret);
 146                return ret;
 147        }
 148        ret = pm_runtime_get_sync(lvds->dev);
 149        if (ret < 0) {
 150                DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret);
 151                clk_disable(lvds->pclk);
 152                return ret;
 153        }
 154        val = RK3288_LVDS_CH0_REG0_LANE4_EN | RK3288_LVDS_CH0_REG0_LANE3_EN |
 155                RK3288_LVDS_CH0_REG0_LANE2_EN | RK3288_LVDS_CH0_REG0_LANE1_EN |
 156                RK3288_LVDS_CH0_REG0_LANE0_EN;
 157        if (lvds->output == DISPLAY_OUTPUT_RGB) {
 158                val |= RK3288_LVDS_CH0_REG0_TTL_EN |
 159                        RK3288_LVDS_CH0_REG0_LANECK_EN;
 160                rk3288_writel(lvds, RK3288_LVDS_CH0_REG0, val);
 161                rk3288_writel(lvds, RK3288_LVDS_CH0_REG2,
 162                              RK3288_LVDS_PLL_FBDIV_REG2(0x46));
 163                rk3288_writel(lvds, RK3288_LVDS_CH0_REG4,
 164                              RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
 165                              RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
 166                              RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
 167                              RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
 168                              RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
 169                              RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
 170                rk3288_writel(lvds, RK3288_LVDS_CH0_REG5,
 171                              RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
 172                              RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
 173                              RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
 174                              RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
 175                              RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
 176                              RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
 177        } else {
 178                val |= RK3288_LVDS_CH0_REG0_LVDS_EN |
 179                            RK3288_LVDS_CH0_REG0_LANECK_EN;
 180                rk3288_writel(lvds, RK3288_LVDS_CH0_REG0, val);
 181                rk3288_writel(lvds, RK3288_LVDS_CH0_REG1,
 182                              RK3288_LVDS_CH0_REG1_LANECK_BIAS |
 183                              RK3288_LVDS_CH0_REG1_LANE4_BIAS |
 184                              RK3288_LVDS_CH0_REG1_LANE3_BIAS |
 185                              RK3288_LVDS_CH0_REG1_LANE2_BIAS |
 186                              RK3288_LVDS_CH0_REG1_LANE1_BIAS |
 187                              RK3288_LVDS_CH0_REG1_LANE0_BIAS);
 188                rk3288_writel(lvds, RK3288_LVDS_CH0_REG2,
 189                              RK3288_LVDS_CH0_REG2_RESERVE_ON |
 190                              RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
 191                              RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
 192                              RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
 193                              RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
 194                              RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
 195                              RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
 196                              RK3288_LVDS_PLL_FBDIV_REG2(0x46));
 197                rk3288_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00);
 198                rk3288_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00);
 199        }
 200        rk3288_writel(lvds, RK3288_LVDS_CH0_REG3,
 201                      RK3288_LVDS_PLL_FBDIV_REG3(0x46));
 202        rk3288_writel(lvds, RK3288_LVDS_CH0_REGD,
 203                      RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
 204        rk3288_writel(lvds, RK3288_LVDS_CH0_REG20,
 205                      RK3288_LVDS_CH0_REG20_LSB);
 206
 207        rk3288_writel(lvds, RK3288_LVDS_CFG_REGC,
 208                      RK3288_LVDS_CFG_REGC_PLL_ENABLE);
 209        rk3288_writel(lvds, RK3288_LVDS_CFG_REG21,
 210                      RK3288_LVDS_CFG_REG21_TX_ENABLE);
 211
 212        return 0;
 213}
 214
 215static void rk3288_lvds_poweroff(struct rockchip_lvds *lvds)
 216{
 217        int ret;
 218        u32 val;
 219
 220        rk3288_writel(lvds, RK3288_LVDS_CFG_REG21,
 221                      RK3288_LVDS_CFG_REG21_TX_ENABLE);
 222        rk3288_writel(lvds, RK3288_LVDS_CFG_REGC,
 223                      RK3288_LVDS_CFG_REGC_PLL_ENABLE);
 224        val = LVDS_DUAL | LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN | LVDS_PWRDN;
 225        val |= val << 16;
 226        ret = regmap_write(lvds->grf, RK3288_LVDS_GRF_SOC_CON7, val);
 227        if (ret != 0)
 228                DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret);
 229
 230        pm_runtime_put(lvds->dev);
 231        clk_disable(lvds->pclk);
 232}
 233
 234static int rk3288_lvds_grf_config(struct drm_encoder *encoder,
 235                                  struct drm_display_mode *mode)
 236{
 237        struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
 238        u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0;
 239        u8 pin_dclk = (mode->flags & DRM_MODE_FLAG_PCSYNC) ? 1 : 0;
 240        u32 val;
 241        int ret;
 242
 243        /* iomux to LCD data/sync mode */
 244        if (lvds->output == DISPLAY_OUTPUT_RGB)
 245                if (lvds->pins && !IS_ERR(lvds->pins->default_state))
 246                        pinctrl_select_state(lvds->pins->p,
 247                                             lvds->pins->default_state);
 248        val = lvds->format | LVDS_CH0_EN;
 249        if (lvds->output == DISPLAY_OUTPUT_RGB)
 250                val |= LVDS_TTL_EN | LVDS_CH1_EN;
 251        else if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS)
 252                val |= LVDS_DUAL | LVDS_CH1_EN;
 253
 254        if ((mode->htotal - mode->hsync_start) & 0x01)
 255                val |= LVDS_START_PHASE_RST_1;
 256
 257        val |= (pin_dclk << 8) | (pin_hsync << 9);
 258        val |= (0xffff << 16);
 259        ret = regmap_write(lvds->grf, RK3288_LVDS_GRF_SOC_CON7, val);
 260        if (ret)
 261                DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret);
 262
 263        return ret;
 264}
 265
 266static int rk3288_lvds_set_vop_source(struct rockchip_lvds *lvds,
 267                                      struct drm_encoder *encoder)
 268{
 269        u32 val;
 270        int ret;
 271
 272        ret = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder);
 273        if (ret < 0)
 274                return ret;
 275
 276        val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
 277        if (ret)
 278                val |= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT;
 279
 280        ret = regmap_write(lvds->grf, RK3288_LVDS_GRF_SOC_CON6, val);
 281        if (ret < 0)
 282                return ret;
 283
 284        return 0;
 285}
 286
 287static void rk3288_lvds_encoder_enable(struct drm_encoder *encoder)
 288{
 289        struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
 290        struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
 291        int ret;
 292
 293        drm_panel_prepare(lvds->panel);
 294
 295        ret = rk3288_lvds_poweron(lvds);
 296        if (ret < 0) {
 297                DRM_DEV_ERROR(lvds->dev, "failed to power on LVDS: %d\n", ret);
 298                drm_panel_unprepare(lvds->panel);
 299                return;
 300        }
 301
 302        ret = rk3288_lvds_grf_config(encoder, mode);
 303        if (ret) {
 304                DRM_DEV_ERROR(lvds->dev, "failed to configure LVDS: %d\n", ret);
 305                drm_panel_unprepare(lvds->panel);
 306                return;
 307        }
 308
 309        ret = rk3288_lvds_set_vop_source(lvds, encoder);
 310        if (ret) {
 311                DRM_DEV_ERROR(lvds->dev, "failed to set VOP source: %d\n", ret);
 312                drm_panel_unprepare(lvds->panel);
 313                return;
 314        }
 315
 316        drm_panel_enable(lvds->panel);
 317}
 318
 319static void rk3288_lvds_encoder_disable(struct drm_encoder *encoder)
 320{
 321        struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
 322
 323        drm_panel_disable(lvds->panel);
 324        rk3288_lvds_poweroff(lvds);
 325        drm_panel_unprepare(lvds->panel);
 326}
 327
 328static int px30_lvds_poweron(struct rockchip_lvds *lvds)
 329{
 330        int ret;
 331
 332        ret = pm_runtime_get_sync(lvds->dev);
 333        if (ret < 0) {
 334                DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret);
 335                return ret;
 336        }
 337
 338        /* Enable LVDS mode */
 339        return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
 340                                  PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1),
 341                                  PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1));
 342}
 343
 344static void px30_lvds_poweroff(struct rockchip_lvds *lvds)
 345{
 346        regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
 347                           PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1),
 348                           PX30_LVDS_MODE_EN(0) | PX30_LVDS_P2S_EN(0));
 349
 350        pm_runtime_put(lvds->dev);
 351}
 352
 353static int px30_lvds_grf_config(struct drm_encoder *encoder,
 354                                struct drm_display_mode *mode)
 355{
 356        struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
 357
 358        if (lvds->output != DISPLAY_OUTPUT_LVDS) {
 359                DRM_DEV_ERROR(lvds->dev, "Unsupported display output %d\n",
 360                              lvds->output);
 361                return -EINVAL;
 362        }
 363
 364        /* Set format */
 365        return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
 366                                  PX30_LVDS_FORMAT(lvds->format),
 367                                  PX30_LVDS_FORMAT(lvds->format));
 368}
 369
 370static int px30_lvds_set_vop_source(struct rockchip_lvds *lvds,
 371                                    struct drm_encoder *encoder)
 372{
 373        int vop;
 374
 375        vop = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder);
 376        if (vop < 0)
 377                return vop;
 378
 379        return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
 380                                  PX30_LVDS_VOP_SEL(1),
 381                                  PX30_LVDS_VOP_SEL(vop));
 382}
 383
 384static void px30_lvds_encoder_enable(struct drm_encoder *encoder)
 385{
 386        struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
 387        struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
 388        int ret;
 389
 390        drm_panel_prepare(lvds->panel);
 391
 392        ret = px30_lvds_poweron(lvds);
 393        if (ret) {
 394                DRM_DEV_ERROR(lvds->dev, "failed to power on LVDS: %d\n", ret);
 395                drm_panel_unprepare(lvds->panel);
 396                return;
 397        }
 398
 399        ret = px30_lvds_grf_config(encoder, mode);
 400        if (ret) {
 401                DRM_DEV_ERROR(lvds->dev, "failed to configure LVDS: %d\n", ret);
 402                drm_panel_unprepare(lvds->panel);
 403                return;
 404        }
 405
 406        ret = px30_lvds_set_vop_source(lvds, encoder);
 407        if (ret) {
 408                DRM_DEV_ERROR(lvds->dev, "failed to set VOP source: %d\n", ret);
 409                drm_panel_unprepare(lvds->panel);
 410                return;
 411        }
 412
 413        drm_panel_enable(lvds->panel);
 414}
 415
 416static void px30_lvds_encoder_disable(struct drm_encoder *encoder)
 417{
 418        struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
 419
 420        drm_panel_disable(lvds->panel);
 421        px30_lvds_poweroff(lvds);
 422        drm_panel_unprepare(lvds->panel);
 423}
 424
 425static const
 426struct drm_encoder_helper_funcs rk3288_lvds_encoder_helper_funcs = {
 427        .enable = rk3288_lvds_encoder_enable,
 428        .disable = rk3288_lvds_encoder_disable,
 429        .atomic_check = rockchip_lvds_encoder_atomic_check,
 430};
 431
 432static const
 433struct drm_encoder_helper_funcs px30_lvds_encoder_helper_funcs = {
 434        .enable = px30_lvds_encoder_enable,
 435        .disable = px30_lvds_encoder_disable,
 436        .atomic_check = rockchip_lvds_encoder_atomic_check,
 437};
 438
 439static int rk3288_lvds_probe(struct platform_device *pdev,
 440                             struct rockchip_lvds *lvds)
 441{
 442        struct resource *res;
 443        int ret;
 444
 445        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 446        lvds->regs = devm_ioremap_resource(lvds->dev, res);
 447        if (IS_ERR(lvds->regs))
 448                return PTR_ERR(lvds->regs);
 449
 450        lvds->pclk = devm_clk_get(lvds->dev, "pclk_lvds");
 451        if (IS_ERR(lvds->pclk)) {
 452                DRM_DEV_ERROR(lvds->dev, "could not get pclk_lvds\n");
 453                return PTR_ERR(lvds->pclk);
 454        }
 455
 456        lvds->pins = devm_kzalloc(lvds->dev, sizeof(*lvds->pins),
 457                                  GFP_KERNEL);
 458        if (!lvds->pins)
 459                return -ENOMEM;
 460
 461        lvds->pins->p = devm_pinctrl_get(lvds->dev);
 462        if (IS_ERR(lvds->pins->p)) {
 463                DRM_DEV_ERROR(lvds->dev, "no pinctrl handle\n");
 464                devm_kfree(lvds->dev, lvds->pins);
 465                lvds->pins = NULL;
 466        } else {
 467                lvds->pins->default_state =
 468                        pinctrl_lookup_state(lvds->pins->p, "lcdc");
 469                if (IS_ERR(lvds->pins->default_state)) {
 470                        DRM_DEV_ERROR(lvds->dev, "no default pinctrl state\n");
 471                        devm_kfree(lvds->dev, lvds->pins);
 472                        lvds->pins = NULL;
 473                }
 474        }
 475
 476        ret = clk_prepare(lvds->pclk);
 477        if (ret < 0) {
 478                DRM_DEV_ERROR(lvds->dev, "failed to prepare pclk_lvds\n");
 479                return ret;
 480        }
 481
 482        return 0;
 483}
 484
 485static int px30_lvds_probe(struct platform_device *pdev,
 486                           struct rockchip_lvds *lvds)
 487{
 488        int ret;
 489
 490        /* MSB */
 491        ret =  regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
 492                                  PX30_LVDS_MSBSEL(1),
 493                                  PX30_LVDS_MSBSEL(1));
 494        if (ret)
 495                return ret;
 496
 497        /* PHY */
 498        lvds->dphy = devm_phy_get(&pdev->dev, "dphy");
 499        if (IS_ERR(lvds->dphy))
 500                return PTR_ERR(lvds->dphy);
 501
 502        ret = phy_init(lvds->dphy);
 503        if (ret)
 504                return ret;
 505
 506        ret = phy_set_mode(lvds->dphy, PHY_MODE_LVDS);
 507        if (ret)
 508                return ret;
 509
 510        return phy_power_on(lvds->dphy);
 511}
 512
 513static const struct rockchip_lvds_soc_data rk3288_lvds_data = {
 514        .probe = rk3288_lvds_probe,
 515        .helper_funcs = &rk3288_lvds_encoder_helper_funcs,
 516};
 517
 518static const struct rockchip_lvds_soc_data px30_lvds_data = {
 519        .probe = px30_lvds_probe,
 520        .helper_funcs = &px30_lvds_encoder_helper_funcs,
 521};
 522
 523static const struct of_device_id rockchip_lvds_dt_ids[] = {
 524        {
 525                .compatible = "rockchip,rk3288-lvds",
 526                .data = &rk3288_lvds_data
 527        },
 528        {
 529                .compatible = "rockchip,px30-lvds",
 530                .data = &px30_lvds_data
 531        },
 532        {}
 533};
 534MODULE_DEVICE_TABLE(of, rockchip_lvds_dt_ids);
 535
 536static int rockchip_lvds_bind(struct device *dev, struct device *master,
 537                              void *data)
 538{
 539        struct rockchip_lvds *lvds = dev_get_drvdata(dev);
 540        struct drm_device *drm_dev = data;
 541        struct drm_encoder *encoder;
 542        struct drm_connector *connector;
 543        struct device_node *remote = NULL;
 544        struct device_node  *port, *endpoint;
 545        int ret = 0, child_count = 0;
 546        const char *name;
 547        u32 endpoint_id = 0;
 548
 549        lvds->drm_dev = drm_dev;
 550        port = of_graph_get_port_by_id(dev->of_node, 1);
 551        if (!port) {
 552                DRM_DEV_ERROR(dev,
 553                              "can't found port point, please init lvds panel port!\n");
 554                return -EINVAL;
 555        }
 556        for_each_child_of_node(port, endpoint) {
 557                child_count++;
 558                of_property_read_u32(endpoint, "reg", &endpoint_id);
 559                ret = drm_of_find_panel_or_bridge(dev->of_node, 1, endpoint_id,
 560                                                  &lvds->panel, &lvds->bridge);
 561                if (!ret) {
 562                        of_node_put(endpoint);
 563                        break;
 564                }
 565        }
 566        if (!child_count) {
 567                DRM_DEV_ERROR(dev, "lvds port does not have any children\n");
 568                ret = -EINVAL;
 569                goto err_put_port;
 570        } else if (ret) {
 571                DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n");
 572                ret = -EPROBE_DEFER;
 573                goto err_put_port;
 574        }
 575        if (lvds->panel)
 576                remote = lvds->panel->dev->of_node;
 577        else
 578                remote = lvds->bridge->of_node;
 579        if (of_property_read_string(dev->of_node, "rockchip,output", &name))
 580                /* default set it as output rgb */
 581                lvds->output = DISPLAY_OUTPUT_RGB;
 582        else
 583                lvds->output = rockchip_lvds_name_to_output(name);
 584
 585        if (lvds->output < 0) {
 586                DRM_DEV_ERROR(dev, "invalid output type [%s]\n", name);
 587                ret = lvds->output;
 588                goto err_put_remote;
 589        }
 590
 591        if (of_property_read_string(remote, "data-mapping", &name))
 592                /* default set it as format vesa 18 */
 593                lvds->format = LVDS_VESA_18;
 594        else
 595                lvds->format = rockchip_lvds_name_to_format(name);
 596
 597        if (lvds->format < 0) {
 598                DRM_DEV_ERROR(dev, "invalid data-mapping format [%s]\n", name);
 599                ret = lvds->format;
 600                goto err_put_remote;
 601        }
 602
 603        encoder = &lvds->encoder;
 604        encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 605                                                             dev->of_node);
 606
 607        ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_LVDS);
 608        if (ret < 0) {
 609                DRM_DEV_ERROR(drm_dev->dev,
 610                              "failed to initialize encoder: %d\n", ret);
 611                goto err_put_remote;
 612        }
 613
 614        drm_encoder_helper_add(encoder, lvds->soc_data->helper_funcs);
 615
 616        if (lvds->panel) {
 617                connector = &lvds->connector;
 618                connector->dpms = DRM_MODE_DPMS_OFF;
 619                ret = drm_connector_init(drm_dev, connector,
 620                                         &rockchip_lvds_connector_funcs,
 621                                         DRM_MODE_CONNECTOR_LVDS);
 622                if (ret < 0) {
 623                        DRM_DEV_ERROR(drm_dev->dev,
 624                                      "failed to initialize connector: %d\n", ret);
 625                        goto err_free_encoder;
 626                }
 627
 628                drm_connector_helper_add(connector,
 629                                         &rockchip_lvds_connector_helper_funcs);
 630
 631                ret = drm_connector_attach_encoder(connector, encoder);
 632                if (ret < 0) {
 633                        DRM_DEV_ERROR(drm_dev->dev,
 634                                      "failed to attach encoder: %d\n", ret);
 635                        goto err_free_connector;
 636                }
 637        } else {
 638                ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0);
 639                if (ret) {
 640                        DRM_DEV_ERROR(drm_dev->dev,
 641                                      "failed to attach bridge: %d\n", ret);
 642                        goto err_free_encoder;
 643                }
 644        }
 645
 646        pm_runtime_enable(dev);
 647        of_node_put(remote);
 648        of_node_put(port);
 649
 650        return 0;
 651
 652err_free_connector:
 653        drm_connector_cleanup(connector);
 654err_free_encoder:
 655        drm_encoder_cleanup(encoder);
 656err_put_remote:
 657        of_node_put(remote);
 658err_put_port:
 659        of_node_put(port);
 660
 661        return ret;
 662}
 663
 664static void rockchip_lvds_unbind(struct device *dev, struct device *master,
 665                                void *data)
 666{
 667        struct rockchip_lvds *lvds = dev_get_drvdata(dev);
 668        const struct drm_encoder_helper_funcs *encoder_funcs;
 669
 670        encoder_funcs = lvds->soc_data->helper_funcs;
 671        encoder_funcs->disable(&lvds->encoder);
 672        pm_runtime_disable(dev);
 673        drm_connector_cleanup(&lvds->connector);
 674        drm_encoder_cleanup(&lvds->encoder);
 675}
 676
 677static const struct component_ops rockchip_lvds_component_ops = {
 678        .bind = rockchip_lvds_bind,
 679        .unbind = rockchip_lvds_unbind,
 680};
 681
 682static int rockchip_lvds_probe(struct platform_device *pdev)
 683{
 684        struct device *dev = &pdev->dev;
 685        struct rockchip_lvds *lvds;
 686        const struct of_device_id *match;
 687        int ret;
 688
 689        if (!dev->of_node)
 690                return -ENODEV;
 691
 692        lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
 693        if (!lvds)
 694                return -ENOMEM;
 695
 696        lvds->dev = dev;
 697        match = of_match_node(rockchip_lvds_dt_ids, dev->of_node);
 698        if (!match)
 699                return -ENODEV;
 700        lvds->soc_data = match->data;
 701
 702        lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
 703                                                    "rockchip,grf");
 704        if (IS_ERR(lvds->grf)) {
 705                DRM_DEV_ERROR(dev, "missing rockchip,grf property\n");
 706                return PTR_ERR(lvds->grf);
 707        }
 708
 709        ret = lvds->soc_data->probe(pdev, lvds);
 710        if (ret) {
 711                DRM_DEV_ERROR(dev, "Platform initialization failed\n");
 712                return ret;
 713        }
 714
 715        dev_set_drvdata(dev, lvds);
 716
 717        ret = component_add(&pdev->dev, &rockchip_lvds_component_ops);
 718        if (ret < 0) {
 719                DRM_DEV_ERROR(dev, "failed to add component\n");
 720                clk_unprepare(lvds->pclk);
 721        }
 722
 723        return ret;
 724}
 725
 726static int rockchip_lvds_remove(struct platform_device *pdev)
 727{
 728        struct rockchip_lvds *lvds = platform_get_drvdata(pdev);
 729
 730        component_del(&pdev->dev, &rockchip_lvds_component_ops);
 731        clk_unprepare(lvds->pclk);
 732
 733        return 0;
 734}
 735
 736struct platform_driver rockchip_lvds_driver = {
 737        .probe = rockchip_lvds_probe,
 738        .remove = rockchip_lvds_remove,
 739        .driver = {
 740                   .name = "rockchip-lvds",
 741                   .of_match_table = of_match_ptr(rockchip_lvds_dt_ids),
 742        },
 743};
 744