linux/drivers/gpu/drm/rcar-du/rcar_lvds.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * rcar_lvds.c  --  R-Car LVDS Encoder
   4 *
   5 * Copyright (C) 2013-2018 Renesas Electronics Corporation
   6 *
   7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   8 */
   9
  10#include <linux/clk.h>
  11#include <linux/delay.h>
  12#include <linux/io.h>
  13#include <linux/of.h>
  14#include <linux/of_device.h>
  15#include <linux/of_graph.h>
  16#include <linux/platform_device.h>
  17#include <linux/slab.h>
  18
  19#include <drm/drm_atomic.h>
  20#include <drm/drm_atomic_helper.h>
  21#include <drm/drm_bridge.h>
  22#include <drm/drm_crtc_helper.h>
  23#include <drm/drm_panel.h>
  24
  25#include "rcar_lvds_regs.h"
  26
  27/* Keep in sync with the LVDCR0.LVMD hardware register values. */
  28enum rcar_lvds_mode {
  29        RCAR_LVDS_MODE_JEIDA = 0,
  30        RCAR_LVDS_MODE_MIRROR = 1,
  31        RCAR_LVDS_MODE_VESA = 4,
  32};
  33
  34#define RCAR_LVDS_QUIRK_LANES   (1 << 0)        /* LVDS lanes 1 and 3 inverted */
  35#define RCAR_LVDS_QUIRK_GEN2_PLLCR (1 << 1)     /* LVDPLLCR has gen2 layout */
  36#define RCAR_LVDS_QUIRK_GEN3_LVEN (1 << 2)      /* LVEN bit needs to be set */
  37                                                /* on R8A77970/R8A7799x */
  38
  39struct rcar_lvds_device_info {
  40        unsigned int gen;
  41        unsigned int quirks;
  42};
  43
  44struct rcar_lvds {
  45        struct device *dev;
  46        const struct rcar_lvds_device_info *info;
  47
  48        struct drm_bridge bridge;
  49
  50        struct drm_bridge *next_bridge;
  51        struct drm_connector connector;
  52        struct drm_panel *panel;
  53
  54        void __iomem *mmio;
  55        struct clk *clock;
  56        bool enabled;
  57
  58        struct drm_display_mode display_mode;
  59        enum rcar_lvds_mode mode;
  60};
  61
  62#define bridge_to_rcar_lvds(bridge) \
  63        container_of(bridge, struct rcar_lvds, bridge)
  64
  65#define connector_to_rcar_lvds(connector) \
  66        container_of(connector, struct rcar_lvds, connector)
  67
  68static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data)
  69{
  70        iowrite32(data, lvds->mmio + reg);
  71}
  72
  73/* -----------------------------------------------------------------------------
  74 * Connector & Panel
  75 */
  76
  77static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
  78{
  79        struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
  80
  81        return drm_panel_get_modes(lvds->panel);
  82}
  83
  84static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
  85                                            struct drm_connector_state *state)
  86{
  87        struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
  88        const struct drm_display_mode *panel_mode;
  89        struct drm_crtc_state *crtc_state;
  90
  91        if (!state->crtc)
  92                return 0;
  93
  94        if (list_empty(&connector->modes)) {
  95                dev_dbg(lvds->dev, "connector: empty modes list\n");
  96                return -EINVAL;
  97        }
  98
  99        panel_mode = list_first_entry(&connector->modes,
 100                                      struct drm_display_mode, head);
 101
 102        /* We're not allowed to modify the resolution. */
 103        crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
 104        if (IS_ERR(crtc_state))
 105                return PTR_ERR(crtc_state);
 106
 107        if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
 108            crtc_state->mode.vdisplay != panel_mode->vdisplay)
 109                return -EINVAL;
 110
 111        /* The flat panel mode is fixed, just copy it to the adjusted mode. */
 112        drm_mode_copy(&crtc_state->adjusted_mode, panel_mode);
 113
 114        return 0;
 115}
 116
 117static const struct drm_connector_helper_funcs rcar_lvds_conn_helper_funcs = {
 118        .get_modes = rcar_lvds_connector_get_modes,
 119        .atomic_check = rcar_lvds_connector_atomic_check,
 120};
 121
 122static const struct drm_connector_funcs rcar_lvds_conn_funcs = {
 123        .reset = drm_atomic_helper_connector_reset,
 124        .fill_modes = drm_helper_probe_single_connector_modes,
 125        .destroy = drm_connector_cleanup,
 126        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 127        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 128};
 129
 130/* -----------------------------------------------------------------------------
 131 * Bridge
 132 */
 133
 134static u32 rcar_lvds_lvdpllcr_gen2(unsigned int freq)
 135{
 136        if (freq < 39000)
 137                return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
 138        else if (freq < 61000)
 139                return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
 140        else if (freq < 121000)
 141                return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
 142        else
 143                return LVDPLLCR_PLLDLYCNT_150M;
 144}
 145
 146static u32 rcar_lvds_lvdpllcr_gen3(unsigned int freq)
 147{
 148        if (freq < 42000)
 149                return LVDPLLCR_PLLDIVCNT_42M;
 150        else if (freq < 85000)
 151                return LVDPLLCR_PLLDIVCNT_85M;
 152        else if (freq < 128000)
 153                return LVDPLLCR_PLLDIVCNT_128M;
 154        else
 155                return LVDPLLCR_PLLDIVCNT_148M;
 156}
 157
 158static void rcar_lvds_enable(struct drm_bridge *bridge)
 159{
 160        struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
 161        const struct drm_display_mode *mode = &lvds->display_mode;
 162        /*
 163         * FIXME: We should really retrieve the CRTC through the state, but how
 164         * do we get a state pointer?
 165         */
 166        struct drm_crtc *crtc = lvds->bridge.encoder->crtc;
 167        u32 lvdpllcr;
 168        u32 lvdhcr;
 169        u32 lvdcr0;
 170        int ret;
 171
 172        WARN_ON(lvds->enabled);
 173
 174        ret = clk_prepare_enable(lvds->clock);
 175        if (ret < 0)
 176                return;
 177
 178        /*
 179         * Hardcode the channels and control signals routing for now.
 180         *
 181         * HSYNC -> CTRL0
 182         * VSYNC -> CTRL1
 183         * DISP  -> CTRL2
 184         * 0     -> CTRL3
 185         */
 186        rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
 187                        LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
 188                        LVDCTRCR_CTR0SEL_HSYNC);
 189
 190        if (lvds->info->quirks & RCAR_LVDS_QUIRK_LANES)
 191                lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
 192                       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
 193        else
 194                lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
 195                       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
 196
 197        rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
 198
 199        /* PLL clock configuration. */
 200        if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN2_PLLCR)
 201                lvdpllcr = rcar_lvds_lvdpllcr_gen2(mode->clock);
 202        else
 203                lvdpllcr = rcar_lvds_lvdpllcr_gen3(mode->clock);
 204        rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
 205
 206        /* Set the LVDS mode and select the input. */
 207        lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT;
 208        if (drm_crtc_index(crtc) == 2)
 209                lvdcr0 |= LVDCR0_DUSEL;
 210        rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 211
 212        /* Turn all the channels on. */
 213        rcar_lvds_write(lvds, LVDCR1,
 214                        LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
 215                        LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
 216
 217        if (lvds->info->gen < 3) {
 218                /* Enable LVDS operation and turn the bias circuitry on. */
 219                lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN;
 220                rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 221        }
 222
 223        /* Turn the PLL on. */
 224        lvdcr0 |= LVDCR0_PLLON;
 225        rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 226
 227        if (lvds->info->gen > 2) {
 228                /* Set LVDS normal mode. */
 229                lvdcr0 |= LVDCR0_PWD;
 230                rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 231        }
 232
 233        if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) {
 234                /* Turn on the LVDS PHY. */
 235                lvdcr0 |= LVDCR0_LVEN;
 236                rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 237        }
 238
 239        /* Wait for the startup delay. */
 240        usleep_range(100, 150);
 241
 242        /* Turn the output on. */
 243        lvdcr0 |= LVDCR0_LVRES;
 244        rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 245
 246        if (lvds->panel) {
 247                drm_panel_prepare(lvds->panel);
 248                drm_panel_enable(lvds->panel);
 249        }
 250
 251        lvds->enabled = true;
 252}
 253
 254static void rcar_lvds_disable(struct drm_bridge *bridge)
 255{
 256        struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
 257
 258        WARN_ON(!lvds->enabled);
 259
 260        if (lvds->panel) {
 261                drm_panel_disable(lvds->panel);
 262                drm_panel_unprepare(lvds->panel);
 263        }
 264
 265        rcar_lvds_write(lvds, LVDCR0, 0);
 266        rcar_lvds_write(lvds, LVDCR1, 0);
 267
 268        clk_disable_unprepare(lvds->clock);
 269
 270        lvds->enabled = false;
 271}
 272
 273static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge,
 274                                 const struct drm_display_mode *mode,
 275                                 struct drm_display_mode *adjusted_mode)
 276{
 277        /*
 278         * The internal LVDS encoder has a restricted clock frequency operating
 279         * range (31MHz to 148.5MHz). Clamp the clock accordingly.
 280         */
 281        adjusted_mode->clock = clamp(adjusted_mode->clock, 31000, 148500);
 282
 283        return true;
 284}
 285
 286static void rcar_lvds_get_lvds_mode(struct rcar_lvds *lvds)
 287{
 288        struct drm_display_info *info = &lvds->connector.display_info;
 289        enum rcar_lvds_mode mode;
 290
 291        /*
 292         * There is no API yet to retrieve LVDS mode from a bridge, only panels
 293         * are supported.
 294         */
 295        if (!lvds->panel)
 296                return;
 297
 298        if (!info->num_bus_formats || !info->bus_formats) {
 299                dev_err(lvds->dev, "no LVDS bus format reported\n");
 300                return;
 301        }
 302
 303        switch (info->bus_formats[0]) {
 304        case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
 305        case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
 306                mode = RCAR_LVDS_MODE_JEIDA;
 307                break;
 308        case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
 309                mode = RCAR_LVDS_MODE_VESA;
 310                break;
 311        default:
 312                dev_err(lvds->dev, "unsupported LVDS bus format 0x%04x\n",
 313                        info->bus_formats[0]);
 314                return;
 315        }
 316
 317        if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
 318                mode |= RCAR_LVDS_MODE_MIRROR;
 319
 320        lvds->mode = mode;
 321}
 322
 323static void rcar_lvds_mode_set(struct drm_bridge *bridge,
 324                               struct drm_display_mode *mode,
 325                               struct drm_display_mode *adjusted_mode)
 326{
 327        struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
 328
 329        WARN_ON(lvds->enabled);
 330
 331        lvds->display_mode = *adjusted_mode;
 332
 333        rcar_lvds_get_lvds_mode(lvds);
 334}
 335
 336static int rcar_lvds_attach(struct drm_bridge *bridge)
 337{
 338        struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
 339        struct drm_connector *connector = &lvds->connector;
 340        struct drm_encoder *encoder = bridge->encoder;
 341        int ret;
 342
 343        /* If we have a next bridge just attach it. */
 344        if (lvds->next_bridge)
 345                return drm_bridge_attach(bridge->encoder, lvds->next_bridge,
 346                                         bridge);
 347
 348        /* Otherwise we have a panel, create a connector. */
 349        ret = drm_connector_init(bridge->dev, connector, &rcar_lvds_conn_funcs,
 350                                 DRM_MODE_CONNECTOR_LVDS);
 351        if (ret < 0)
 352                return ret;
 353
 354        drm_connector_helper_add(connector, &rcar_lvds_conn_helper_funcs);
 355
 356        ret = drm_mode_connector_attach_encoder(connector, encoder);
 357        if (ret < 0)
 358                return ret;
 359
 360        return drm_panel_attach(lvds->panel, connector);
 361}
 362
 363static void rcar_lvds_detach(struct drm_bridge *bridge)
 364{
 365        struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
 366
 367        if (lvds->panel)
 368                drm_panel_detach(lvds->panel);
 369}
 370
 371static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
 372        .attach = rcar_lvds_attach,
 373        .detach = rcar_lvds_detach,
 374        .enable = rcar_lvds_enable,
 375        .disable = rcar_lvds_disable,
 376        .mode_fixup = rcar_lvds_mode_fixup,
 377        .mode_set = rcar_lvds_mode_set,
 378};
 379
 380/* -----------------------------------------------------------------------------
 381 * Probe & Remove
 382 */
 383
 384static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
 385{
 386        struct device_node *local_output = NULL;
 387        struct device_node *remote_input = NULL;
 388        struct device_node *remote = NULL;
 389        struct device_node *node;
 390        bool is_bridge = false;
 391        int ret = 0;
 392
 393        local_output = of_graph_get_endpoint_by_regs(lvds->dev->of_node, 1, 0);
 394        if (!local_output) {
 395                dev_dbg(lvds->dev, "unconnected port@1\n");
 396                return -ENODEV;
 397        }
 398
 399        /*
 400         * Locate the connected entity and infer its type from the number of
 401         * endpoints.
 402         */
 403        remote = of_graph_get_remote_port_parent(local_output);
 404        if (!remote) {
 405                dev_dbg(lvds->dev, "unconnected endpoint %pOF\n", local_output);
 406                ret = -ENODEV;
 407                goto done;
 408        }
 409
 410        if (!of_device_is_available(remote)) {
 411                dev_dbg(lvds->dev, "connected entity %pOF is disabled\n",
 412                        remote);
 413                ret = -ENODEV;
 414                goto done;
 415        }
 416
 417        remote_input = of_graph_get_remote_endpoint(local_output);
 418
 419        for_each_endpoint_of_node(remote, node) {
 420                if (node != remote_input) {
 421                        /*
 422                         * We've found one endpoint other than the input, this
 423                         * must be a bridge.
 424                         */
 425                        is_bridge = true;
 426                        of_node_put(node);
 427                        break;
 428                }
 429        }
 430
 431        if (is_bridge) {
 432                lvds->next_bridge = of_drm_find_bridge(remote);
 433                if (!lvds->next_bridge)
 434                        ret = -EPROBE_DEFER;
 435        } else {
 436                lvds->panel = of_drm_find_panel(remote);
 437                if (!lvds->panel)
 438                        ret = -EPROBE_DEFER;
 439        }
 440
 441done:
 442        of_node_put(local_output);
 443        of_node_put(remote_input);
 444        of_node_put(remote);
 445
 446        return ret;
 447}
 448
 449static int rcar_lvds_probe(struct platform_device *pdev)
 450{
 451        struct rcar_lvds *lvds;
 452        struct resource *mem;
 453        int ret;
 454
 455        lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
 456        if (lvds == NULL)
 457                return -ENOMEM;
 458
 459        platform_set_drvdata(pdev, lvds);
 460
 461        lvds->dev = &pdev->dev;
 462        lvds->info = of_device_get_match_data(&pdev->dev);
 463        lvds->enabled = false;
 464
 465        ret = rcar_lvds_parse_dt(lvds);
 466        if (ret < 0)
 467                return ret;
 468
 469        lvds->bridge.driver_private = lvds;
 470        lvds->bridge.funcs = &rcar_lvds_bridge_ops;
 471        lvds->bridge.of_node = pdev->dev.of_node;
 472
 473        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 474        lvds->mmio = devm_ioremap_resource(&pdev->dev, mem);
 475        if (IS_ERR(lvds->mmio))
 476                return PTR_ERR(lvds->mmio);
 477
 478        lvds->clock = devm_clk_get(&pdev->dev, NULL);
 479        if (IS_ERR(lvds->clock)) {
 480                dev_err(&pdev->dev, "failed to get clock\n");
 481                return PTR_ERR(lvds->clock);
 482        }
 483
 484        drm_bridge_add(&lvds->bridge);
 485
 486        return 0;
 487}
 488
 489static int rcar_lvds_remove(struct platform_device *pdev)
 490{
 491        struct rcar_lvds *lvds = platform_get_drvdata(pdev);
 492
 493        drm_bridge_remove(&lvds->bridge);
 494
 495        return 0;
 496}
 497
 498static const struct rcar_lvds_device_info rcar_lvds_gen2_info = {
 499        .gen = 2,
 500        .quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR,
 501};
 502
 503static const struct rcar_lvds_device_info rcar_lvds_r8a7790_info = {
 504        .gen = 2,
 505        .quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR | RCAR_LVDS_QUIRK_LANES,
 506};
 507
 508static const struct rcar_lvds_device_info rcar_lvds_gen3_info = {
 509        .gen = 3,
 510};
 511
 512static const struct rcar_lvds_device_info rcar_lvds_r8a77970_info = {
 513        .gen = 3,
 514        .quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR | RCAR_LVDS_QUIRK_GEN3_LVEN,
 515};
 516
 517static const struct of_device_id rcar_lvds_of_table[] = {
 518        { .compatible = "renesas,r8a7743-lvds", .data = &rcar_lvds_gen2_info },
 519        { .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_r8a7790_info },
 520        { .compatible = "renesas,r8a7791-lvds", .data = &rcar_lvds_gen2_info },
 521        { .compatible = "renesas,r8a7793-lvds", .data = &rcar_lvds_gen2_info },
 522        { .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info },
 523        { .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info },
 524        { .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info },
 525        { }
 526};
 527
 528MODULE_DEVICE_TABLE(of, rcar_lvds_of_table);
 529
 530static struct platform_driver rcar_lvds_platform_driver = {
 531        .probe          = rcar_lvds_probe,
 532        .remove         = rcar_lvds_remove,
 533        .driver         = {
 534                .name   = "rcar-lvds",
 535                .of_match_table = rcar_lvds_of_table,
 536        },
 537};
 538
 539module_platform_driver(rcar_lvds_platform_driver);
 540
 541MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 542MODULE_DESCRIPTION("Renesas R-Car LVDS Encoder Driver");
 543MODULE_LICENSE("GPL");
 544