linux/drivers/gpu/drm/sun4i/sun4i_tcon.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Free Electrons
   3 * Copyright (C) 2015 NextThing Co
   4 *
   5 * Maxime Ripard <maxime.ripard@free-electrons.com>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of
  10 * the License, or (at your option) any later version.
  11 */
  12
  13#include <drm/drmP.h>
  14#include <drm/drm_atomic_helper.h>
  15#include <drm/drm_crtc.h>
  16#include <drm/drm_crtc_helper.h>
  17#include <drm/drm_encoder.h>
  18#include <drm/drm_modes.h>
  19#include <drm/drm_of.h>
  20
  21#include <uapi/drm/drm_mode.h>
  22
  23#include <linux/component.h>
  24#include <linux/ioport.h>
  25#include <linux/of_address.h>
  26#include <linux/of_device.h>
  27#include <linux/of_irq.h>
  28#include <linux/regmap.h>
  29#include <linux/reset.h>
  30
  31#include "sun4i_crtc.h"
  32#include "sun4i_dotclock.h"
  33#include "sun4i_drv.h"
  34#include "sun4i_lvds.h"
  35#include "sun4i_rgb.h"
  36#include "sun4i_tcon.h"
  37#include "sun6i_mipi_dsi.h"
  38#include "sunxi_engine.h"
  39
  40static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)
  41{
  42        struct drm_connector *connector;
  43        struct drm_connector_list_iter iter;
  44
  45        drm_connector_list_iter_begin(encoder->dev, &iter);
  46        drm_for_each_connector_iter(connector, &iter)
  47                if (connector->encoder == encoder) {
  48                        drm_connector_list_iter_end(&iter);
  49                        return connector;
  50                }
  51        drm_connector_list_iter_end(&iter);
  52
  53        return NULL;
  54}
  55
  56static int sun4i_tcon_get_pixel_depth(const struct drm_encoder *encoder)
  57{
  58        struct drm_connector *connector;
  59        struct drm_display_info *info;
  60
  61        connector = sun4i_tcon_get_connector(encoder);
  62        if (!connector)
  63                return -EINVAL;
  64
  65        info = &connector->display_info;
  66        if (info->num_bus_formats != 1)
  67                return -EINVAL;
  68
  69        switch (info->bus_formats[0]) {
  70        case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
  71                return 18;
  72
  73        case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
  74        case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
  75                return 24;
  76        }
  77
  78        return -EINVAL;
  79}
  80
  81static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
  82                                          bool enabled)
  83{
  84        struct clk *clk;
  85
  86        switch (channel) {
  87        case 0:
  88                WARN_ON(!tcon->quirks->has_channel_0);
  89                regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
  90                                   SUN4I_TCON0_CTL_TCON_ENABLE,
  91                                   enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
  92                clk = tcon->dclk;
  93                break;
  94        case 1:
  95                WARN_ON(!tcon->quirks->has_channel_1);
  96                regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
  97                                   SUN4I_TCON1_CTL_TCON_ENABLE,
  98                                   enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
  99                clk = tcon->sclk1;
 100                break;
 101        default:
 102                DRM_WARN("Unknown channel... doing nothing\n");
 103                return;
 104        }
 105
 106        if (enabled) {
 107                clk_prepare_enable(clk);
 108                clk_rate_exclusive_get(clk);
 109        } else {
 110                clk_rate_exclusive_put(clk);
 111                clk_disable_unprepare(clk);
 112        }
 113}
 114
 115static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
 116                                       const struct drm_encoder *encoder,
 117                                       bool enabled)
 118{
 119        if (enabled) {
 120                u8 val;
 121
 122                regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
 123                                   SUN4I_TCON0_LVDS_IF_EN,
 124                                   SUN4I_TCON0_LVDS_IF_EN);
 125
 126                /*
 127                 * As their name suggest, these values only apply to the A31
 128                 * and later SoCs. We'll have to rework this when merging
 129                 * support for the older SoCs.
 130                 */
 131                regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
 132                             SUN6I_TCON0_LVDS_ANA0_C(2) |
 133                             SUN6I_TCON0_LVDS_ANA0_V(3) |
 134                             SUN6I_TCON0_LVDS_ANA0_PD(2) |
 135                             SUN6I_TCON0_LVDS_ANA0_EN_LDO);
 136                udelay(2);
 137
 138                regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
 139                                   SUN6I_TCON0_LVDS_ANA0_EN_MB,
 140                                   SUN6I_TCON0_LVDS_ANA0_EN_MB);
 141                udelay(2);
 142
 143                regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
 144                                   SUN6I_TCON0_LVDS_ANA0_EN_DRVC,
 145                                   SUN6I_TCON0_LVDS_ANA0_EN_DRVC);
 146
 147                if (sun4i_tcon_get_pixel_depth(encoder) == 18)
 148                        val = 7;
 149                else
 150                        val = 0xf;
 151
 152                regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
 153                                  SUN6I_TCON0_LVDS_ANA0_EN_DRVD(0xf),
 154                                  SUN6I_TCON0_LVDS_ANA0_EN_DRVD(val));
 155        } else {
 156                regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
 157                                   SUN4I_TCON0_LVDS_IF_EN, 0);
 158        }
 159}
 160
 161void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
 162                           const struct drm_encoder *encoder,
 163                           bool enabled)
 164{
 165        bool is_lvds = false;
 166        int channel;
 167
 168        switch (encoder->encoder_type) {
 169        case DRM_MODE_ENCODER_LVDS:
 170                is_lvds = true;
 171                /* Fallthrough */
 172        case DRM_MODE_ENCODER_DSI:
 173        case DRM_MODE_ENCODER_NONE:
 174                channel = 0;
 175                break;
 176        case DRM_MODE_ENCODER_TMDS:
 177        case DRM_MODE_ENCODER_TVDAC:
 178                channel = 1;
 179                break;
 180        default:
 181                DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
 182                return;
 183        }
 184
 185        if (is_lvds && !enabled)
 186                sun4i_tcon_lvds_set_status(tcon, encoder, false);
 187
 188        regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
 189                           SUN4I_TCON_GCTL_TCON_ENABLE,
 190                           enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
 191
 192        if (is_lvds && enabled)
 193                sun4i_tcon_lvds_set_status(tcon, encoder, true);
 194
 195        sun4i_tcon_channel_set_status(tcon, channel, enabled);
 196}
 197
 198void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
 199{
 200        u32 mask, val = 0;
 201
 202        DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
 203
 204        mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
 205                SUN4I_TCON_GINT0_VBLANK_ENABLE(1) |
 206                SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE;
 207
 208        if (enable)
 209                val = mask;
 210
 211        regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val);
 212}
 213EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
 214
 215/*
 216 * This function is a helper for TCON output muxing. The TCON output
 217 * muxing control register in earlier SoCs (without the TCON TOP block)
 218 * are located in TCON0. This helper returns a pointer to TCON0's
 219 * sun4i_tcon structure, or NULL if not found.
 220 */
 221static struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm)
 222{
 223        struct sun4i_drv *drv = drm->dev_private;
 224        struct sun4i_tcon *tcon;
 225
 226        list_for_each_entry(tcon, &drv->tcon_list, list)
 227                if (tcon->id == 0)
 228                        return tcon;
 229
 230        dev_warn(drm->dev,
 231                 "TCON0 not found, display output muxing may not work\n");
 232
 233        return NULL;
 234}
 235
 236void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
 237                        const struct drm_encoder *encoder)
 238{
 239        int ret = -ENOTSUPP;
 240
 241        if (tcon->quirks->set_mux)
 242                ret = tcon->quirks->set_mux(tcon, encoder);
 243
 244        DRM_DEBUG_DRIVER("Muxing encoder %s to CRTC %s: %d\n",
 245                         encoder->name, encoder->crtc->name, ret);
 246}
 247
 248static int sun4i_tcon_get_clk_delay(const struct drm_display_mode *mode,
 249                                    int channel)
 250{
 251        int delay = mode->vtotal - mode->vdisplay;
 252
 253        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 254                delay /= 2;
 255
 256        if (channel == 1)
 257                delay -= 2;
 258
 259        delay = min(delay, 30);
 260
 261        DRM_DEBUG_DRIVER("TCON %d clock delay %u\n", channel, delay);
 262
 263        return delay;
 264}
 265
 266static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
 267                                        const struct drm_display_mode *mode)
 268{
 269        /* Configure the dot clock */
 270        clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
 271
 272        /* Set the resolution */
 273        regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
 274                     SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
 275                     SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
 276}
 277
 278static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
 279                                     struct mipi_dsi_device *device,
 280                                     const struct drm_display_mode *mode)
 281{
 282        u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
 283        u8 lanes = device->lanes;
 284        u32 block_space, start_delay;
 285        u32 tcon_div;
 286
 287        tcon->dclk_min_div = 4;
 288        tcon->dclk_max_div = 127;
 289
 290        sun4i_tcon0_mode_set_common(tcon, mode);
 291
 292        regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
 293                           SUN4I_TCON0_CTL_IF_MASK,
 294                           SUN4I_TCON0_CTL_IF_8080);
 295
 296        regmap_write(tcon->regs, SUN4I_TCON_ECC_FIFO_REG,
 297                     SUN4I_TCON_ECC_FIFO_EN);
 298
 299        regmap_write(tcon->regs, SUN4I_TCON0_CPU_IF_REG,
 300                     SUN4I_TCON0_CPU_IF_MODE_DSI |
 301                     SUN4I_TCON0_CPU_IF_TRI_FIFO_FLUSH |
 302                     SUN4I_TCON0_CPU_IF_TRI_FIFO_EN |
 303                     SUN4I_TCON0_CPU_IF_TRI_EN);
 304
 305        /*
 306         * This looks suspicious, but it works...
 307         *
 308         * The datasheet says that this should be set higher than 20 *
 309         * pixel cycle, but it's not clear what a pixel cycle is.
 310         */
 311        regmap_read(tcon->regs, SUN4I_TCON0_DCLK_REG, &tcon_div);
 312        tcon_div &= GENMASK(6, 0);
 313        block_space = mode->htotal * bpp / (tcon_div * lanes);
 314        block_space -= mode->hdisplay + 40;
 315
 316        regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI0_REG,
 317                     SUN4I_TCON0_CPU_TRI0_BLOCK_SPACE(block_space) |
 318                     SUN4I_TCON0_CPU_TRI0_BLOCK_SIZE(mode->hdisplay));
 319
 320        regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI1_REG,
 321                     SUN4I_TCON0_CPU_TRI1_BLOCK_NUM(mode->vdisplay));
 322
 323        start_delay = (mode->crtc_vtotal - mode->crtc_vdisplay - 10 - 1);
 324        start_delay = start_delay * mode->crtc_htotal * 149;
 325        start_delay = start_delay / (mode->crtc_clock / 1000) / 8;
 326        regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI2_REG,
 327                     SUN4I_TCON0_CPU_TRI2_TRANS_START_SET(10) |
 328                     SUN4I_TCON0_CPU_TRI2_START_DELAY(start_delay));
 329
 330        /*
 331         * The Allwinner BSP has a comment that the period should be
 332         * the display clock * 15, but uses an hardcoded 3000...
 333         */
 334        regmap_write(tcon->regs, SUN4I_TCON_SAFE_PERIOD_REG,
 335                     SUN4I_TCON_SAFE_PERIOD_NUM(3000) |
 336                     SUN4I_TCON_SAFE_PERIOD_MODE(3));
 337
 338        /* Enable the output on the pins */
 339        regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG,
 340                     0xe0000000);
 341}
 342
 343static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
 344                                      const struct drm_encoder *encoder,
 345                                      const struct drm_display_mode *mode)
 346{
 347        unsigned int bp;
 348        u8 clk_delay;
 349        u32 reg, val = 0;
 350
 351        WARN_ON(!tcon->quirks->has_channel_0);
 352
 353        tcon->dclk_min_div = 7;
 354        tcon->dclk_max_div = 7;
 355        sun4i_tcon0_mode_set_common(tcon, mode);
 356
 357        /* Adjust clock delay */
 358        clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
 359        regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
 360                           SUN4I_TCON0_CTL_CLK_DELAY_MASK,
 361                           SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
 362
 363        /*
 364         * This is called a backporch in the register documentation,
 365         * but it really is the back porch + hsync
 366         */
 367        bp = mode->crtc_htotal - mode->crtc_hsync_start;
 368        DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
 369                         mode->crtc_htotal, bp);
 370
 371        /* Set horizontal display timings */
 372        regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
 373                     SUN4I_TCON0_BASIC1_H_TOTAL(mode->htotal) |
 374                     SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
 375
 376        /*
 377         * This is called a backporch in the register documentation,
 378         * but it really is the back porch + hsync
 379         */
 380        bp = mode->crtc_vtotal - mode->crtc_vsync_start;
 381        DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
 382                         mode->crtc_vtotal, bp);
 383
 384        /* Set vertical display timings */
 385        regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
 386                     SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
 387                     SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
 388
 389        reg = SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0 |
 390                SUN4I_TCON0_LVDS_IF_DATA_POL_NORMAL |
 391                SUN4I_TCON0_LVDS_IF_CLK_POL_NORMAL;
 392        if (sun4i_tcon_get_pixel_depth(encoder) == 24)
 393                reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS;
 394        else
 395                reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS;
 396
 397        regmap_write(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, reg);
 398
 399        /* Setup the polarity of the various signals */
 400        if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
 401                val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
 402
 403        if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
 404                val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
 405
 406        regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
 407
 408        /* Map output pins to channel 0 */
 409        regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
 410                           SUN4I_TCON_GCTL_IOMAP_MASK,
 411                           SUN4I_TCON_GCTL_IOMAP_TCON0);
 412
 413        /* Enable the output on the pins */
 414        regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000);
 415}
 416
 417static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
 418                                     const struct drm_display_mode *mode)
 419{
 420        unsigned int bp, hsync, vsync;
 421        u8 clk_delay;
 422        u32 val = 0;
 423
 424        WARN_ON(!tcon->quirks->has_channel_0);
 425
 426        tcon->dclk_min_div = 6;
 427        tcon->dclk_max_div = 127;
 428        sun4i_tcon0_mode_set_common(tcon, mode);
 429
 430        /* Adjust clock delay */
 431        clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
 432        regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
 433                           SUN4I_TCON0_CTL_CLK_DELAY_MASK,
 434                           SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
 435
 436        /*
 437         * This is called a backporch in the register documentation,
 438         * but it really is the back porch + hsync
 439         */
 440        bp = mode->crtc_htotal - mode->crtc_hsync_start;
 441        DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
 442                         mode->crtc_htotal, bp);
 443
 444        /* Set horizontal display timings */
 445        regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
 446                     SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) |
 447                     SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
 448
 449        /*
 450         * This is called a backporch in the register documentation,
 451         * but it really is the back porch + hsync
 452         */
 453        bp = mode->crtc_vtotal - mode->crtc_vsync_start;
 454        DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
 455                         mode->crtc_vtotal, bp);
 456
 457        /* Set vertical display timings */
 458        regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
 459                     SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
 460                     SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
 461
 462        /* Set Hsync and Vsync length */
 463        hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
 464        vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
 465        DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
 466        regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG,
 467                     SUN4I_TCON0_BASIC3_V_SYNC(vsync) |
 468                     SUN4I_TCON0_BASIC3_H_SYNC(hsync));
 469
 470        /* Setup the polarity of the various signals */
 471        if (mode->flags & DRM_MODE_FLAG_PHSYNC)
 472                val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
 473
 474        if (mode->flags & DRM_MODE_FLAG_PVSYNC)
 475                val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
 476
 477        regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
 478                           SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE,
 479                           val);
 480
 481        /* Map output pins to channel 0 */
 482        regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
 483                           SUN4I_TCON_GCTL_IOMAP_MASK,
 484                           SUN4I_TCON_GCTL_IOMAP_TCON0);
 485
 486        /* Enable the output on the pins */
 487        regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
 488}
 489
 490static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 491                                 const struct drm_display_mode *mode)
 492{
 493        unsigned int bp, hsync, vsync, vtotal;
 494        u8 clk_delay;
 495        u32 val;
 496
 497        WARN_ON(!tcon->quirks->has_channel_1);
 498
 499        /* Configure the dot clock */
 500        clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
 501
 502        /* Adjust clock delay */
 503        clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
 504        regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
 505                           SUN4I_TCON1_CTL_CLK_DELAY_MASK,
 506                           SUN4I_TCON1_CTL_CLK_DELAY(clk_delay));
 507
 508        /* Set interlaced mode */
 509        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 510                val = SUN4I_TCON1_CTL_INTERLACE_ENABLE;
 511        else
 512                val = 0;
 513        regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
 514                           SUN4I_TCON1_CTL_INTERLACE_ENABLE,
 515                           val);
 516
 517        /* Set the input resolution */
 518        regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
 519                     SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
 520                     SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
 521
 522        /* Set the upscaling resolution */
 523        regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
 524                     SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
 525                     SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
 526
 527        /* Set the output resolution */
 528        regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
 529                     SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
 530                     SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
 531
 532        /* Set horizontal display timings */
 533        bp = mode->crtc_htotal - mode->crtc_hsync_start;
 534        DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
 535                         mode->htotal, bp);
 536        regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
 537                     SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
 538                     SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
 539
 540        bp = mode->crtc_vtotal - mode->crtc_vsync_start;
 541        DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
 542                         mode->crtc_vtotal, bp);
 543
 544        /*
 545         * The vertical resolution needs to be doubled in all
 546         * cases. We could use crtc_vtotal and always multiply by two,
 547         * but that leads to a rounding error in interlace when vtotal
 548         * is odd.
 549         *
 550         * This happens with TV's PAL for example, where vtotal will
 551         * be 625, crtc_vtotal 312, and thus crtc_vtotal * 2 will be
 552         * 624, which apparently confuses the hardware.
 553         *
 554         * To work around this, we will always use vtotal, and
 555         * multiply by two only if we're not in interlace.
 556         */
 557        vtotal = mode->vtotal;
 558        if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
 559                vtotal = vtotal * 2;
 560
 561        /* Set vertical display timings */
 562        regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG,
 563                     SUN4I_TCON1_BASIC4_V_TOTAL(vtotal) |
 564                     SUN4I_TCON1_BASIC4_V_BACKPORCH(bp));
 565
 566        /* Set Hsync and Vsync length */
 567        hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
 568        vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
 569        DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
 570        regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG,
 571                     SUN4I_TCON1_BASIC5_V_SYNC(vsync) |
 572                     SUN4I_TCON1_BASIC5_H_SYNC(hsync));
 573
 574        /* Map output pins to channel 1 */
 575        regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
 576                           SUN4I_TCON_GCTL_IOMAP_MASK,
 577                           SUN4I_TCON_GCTL_IOMAP_TCON1);
 578}
 579
 580void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
 581                         const struct drm_encoder *encoder,
 582                         const struct drm_display_mode *mode)
 583{
 584        struct sun6i_dsi *dsi;
 585
 586        switch (encoder->encoder_type) {
 587        case DRM_MODE_ENCODER_DSI:
 588                /*
 589                 * This is not really elegant, but it's the "cleaner"
 590                 * way I could think of...
 591                 */
 592                dsi = encoder_to_sun6i_dsi(encoder);
 593                sun4i_tcon0_mode_set_cpu(tcon, dsi->device, mode);
 594                break;
 595        case DRM_MODE_ENCODER_LVDS:
 596                sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
 597                break;
 598        case DRM_MODE_ENCODER_NONE:
 599                sun4i_tcon0_mode_set_rgb(tcon, mode);
 600                sun4i_tcon_set_mux(tcon, 0, encoder);
 601                break;
 602        case DRM_MODE_ENCODER_TVDAC:
 603        case DRM_MODE_ENCODER_TMDS:
 604                sun4i_tcon1_mode_set(tcon, mode);
 605                sun4i_tcon_set_mux(tcon, 1, encoder);
 606                break;
 607        default:
 608                DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
 609        }
 610}
 611EXPORT_SYMBOL(sun4i_tcon_mode_set);
 612
 613static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
 614                                        struct sun4i_crtc *scrtc)
 615{
 616        unsigned long flags;
 617
 618        spin_lock_irqsave(&dev->event_lock, flags);
 619        if (scrtc->event) {
 620                drm_crtc_send_vblank_event(&scrtc->crtc, scrtc->event);
 621                drm_crtc_vblank_put(&scrtc->crtc);
 622                scrtc->event = NULL;
 623        }
 624        spin_unlock_irqrestore(&dev->event_lock, flags);
 625}
 626
 627static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 628{
 629        struct sun4i_tcon *tcon = private;
 630        struct drm_device *drm = tcon->drm;
 631        struct sun4i_crtc *scrtc = tcon->crtc;
 632        struct sunxi_engine *engine = scrtc->engine;
 633        unsigned int status;
 634
 635        regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
 636
 637        if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
 638                        SUN4I_TCON_GINT0_VBLANK_INT(1) |
 639                        SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT)))
 640                return IRQ_NONE;
 641
 642        drm_crtc_handle_vblank(&scrtc->crtc);
 643        sun4i_tcon_finish_page_flip(drm, scrtc);
 644
 645        /* Acknowledge the interrupt */
 646        regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,
 647                           SUN4I_TCON_GINT0_VBLANK_INT(0) |
 648                           SUN4I_TCON_GINT0_VBLANK_INT(1) |
 649                           SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT,
 650                           0);
 651
 652        if (engine->ops->vblank_quirk)
 653                engine->ops->vblank_quirk(engine);
 654
 655        return IRQ_HANDLED;
 656}
 657
 658static int sun4i_tcon_init_clocks(struct device *dev,
 659                                  struct sun4i_tcon *tcon)
 660{
 661        tcon->clk = devm_clk_get(dev, "ahb");
 662        if (IS_ERR(tcon->clk)) {
 663                dev_err(dev, "Couldn't get the TCON bus clock\n");
 664                return PTR_ERR(tcon->clk);
 665        }
 666        clk_prepare_enable(tcon->clk);
 667
 668        if (tcon->quirks->has_channel_0) {
 669                tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
 670                if (IS_ERR(tcon->sclk0)) {
 671                        dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
 672                        return PTR_ERR(tcon->sclk0);
 673                }
 674        }
 675
 676        if (tcon->quirks->has_channel_1) {
 677                tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
 678                if (IS_ERR(tcon->sclk1)) {
 679                        dev_err(dev, "Couldn't get the TCON channel 1 clock\n");
 680                        return PTR_ERR(tcon->sclk1);
 681                }
 682        }
 683
 684        return 0;
 685}
 686
 687static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
 688{
 689        clk_disable_unprepare(tcon->clk);
 690}
 691
 692static int sun4i_tcon_init_irq(struct device *dev,
 693                               struct sun4i_tcon *tcon)
 694{
 695        struct platform_device *pdev = to_platform_device(dev);
 696        int irq, ret;
 697
 698        irq = platform_get_irq(pdev, 0);
 699        if (irq < 0) {
 700                dev_err(dev, "Couldn't retrieve the TCON interrupt\n");
 701                return irq;
 702        }
 703
 704        ret = devm_request_irq(dev, irq, sun4i_tcon_handler, 0,
 705                               dev_name(dev), tcon);
 706        if (ret) {
 707                dev_err(dev, "Couldn't request the IRQ\n");
 708                return ret;
 709        }
 710
 711        return 0;
 712}
 713
 714static struct regmap_config sun4i_tcon_regmap_config = {
 715        .reg_bits       = 32,
 716        .val_bits       = 32,
 717        .reg_stride     = 4,
 718        .max_register   = 0x800,
 719};
 720
 721static int sun4i_tcon_init_regmap(struct device *dev,
 722                                  struct sun4i_tcon *tcon)
 723{
 724        struct platform_device *pdev = to_platform_device(dev);
 725        struct resource *res;
 726        void __iomem *regs;
 727
 728        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 729        regs = devm_ioremap_resource(dev, res);
 730        if (IS_ERR(regs))
 731                return PTR_ERR(regs);
 732
 733        tcon->regs = devm_regmap_init_mmio(dev, regs,
 734                                           &sun4i_tcon_regmap_config);
 735        if (IS_ERR(tcon->regs)) {
 736                dev_err(dev, "Couldn't create the TCON regmap\n");
 737                return PTR_ERR(tcon->regs);
 738        }
 739
 740        /* Make sure the TCON is disabled and all IRQs are off */
 741        regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0);
 742        regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0);
 743        regmap_write(tcon->regs, SUN4I_TCON_GINT1_REG, 0);
 744
 745        /* Disable IO lines and set them to tristate */
 746        regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0);
 747        regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0);
 748
 749        return 0;
 750}
 751
 752/*
 753 * On SoCs with the old display pipeline design (Display Engine 1.0),
 754 * the TCON is always tied to just one backend. Hence we can traverse
 755 * the of_graph upwards to find the backend our tcon is connected to,
 756 * and take its ID as our own.
 757 *
 758 * We can either identify backends from their compatible strings, which
 759 * means maintaining a large list of them. Or, since the backend is
 760 * registered and binded before the TCON, we can just go through the
 761 * list of registered backends and compare the device node.
 762 *
 763 * As the structures now store engines instead of backends, here this
 764 * function in fact searches the corresponding engine, and the ID is
 765 * requested via the get_id function of the engine.
 766 */
 767static struct sunxi_engine *
 768sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv,
 769                                struct device_node *node,
 770                                u32 port_id)
 771{
 772        struct device_node *port, *ep, *remote;
 773        struct sunxi_engine *engine = ERR_PTR(-EINVAL);
 774        u32 reg = 0;
 775
 776        port = of_graph_get_port_by_id(node, port_id);
 777        if (!port)
 778                return ERR_PTR(-EINVAL);
 779
 780        /*
 781         * This only works if there is only one path from the TCON
 782         * to any display engine. Otherwise the probe order of the
 783         * TCONs and display engines is not guaranteed. They may
 784         * either bind to the wrong one, or worse, bind to the same
 785         * one if additional checks are not done.
 786         *
 787         * Bail out if there are multiple input connections.
 788         */
 789        if (of_get_available_child_count(port) != 1)
 790                goto out_put_port;
 791
 792        /* Get the first connection without specifying an ID */
 793        ep = of_get_next_available_child(port, NULL);
 794        if (!ep)
 795                goto out_put_port;
 796
 797        remote = of_graph_get_remote_port_parent(ep);
 798        if (!remote)
 799                goto out_put_ep;
 800
 801        /* does this node match any registered engines? */
 802        list_for_each_entry(engine, &drv->engine_list, list)
 803                if (remote == engine->node)
 804                        goto out_put_remote;
 805
 806        /*
 807         * According to device tree binding input ports have even id
 808         * number and output ports have odd id. Since component with
 809         * more than one input and one output (TCON TOP) exits, correct
 810         * remote input id has to be calculated by subtracting 1 from
 811         * remote output id. If this for some reason can't be done, 0
 812         * is used as input port id.
 813         */
 814        of_node_put(port);
 815        port = of_graph_get_remote_port(ep);
 816        if (!of_property_read_u32(port, "reg", &reg) && reg > 0)
 817                reg -= 1;
 818
 819        /* keep looking through upstream ports */
 820        engine = sun4i_tcon_find_engine_traverse(drv, remote, reg);
 821
 822out_put_remote:
 823        of_node_put(remote);
 824out_put_ep:
 825        of_node_put(ep);
 826out_put_port:
 827        of_node_put(port);
 828
 829        return engine;
 830}
 831
 832/*
 833 * The device tree binding says that the remote endpoint ID of any
 834 * connection between components, up to and including the TCON, of
 835 * the display pipeline should be equal to the actual ID of the local
 836 * component. Thus we can look at any one of the input connections of
 837 * the TCONs, and use that connection's remote endpoint ID as our own.
 838 *
 839 * Since the user of this function already finds the input port,
 840 * the port is passed in directly without further checks.
 841 */
 842static int sun4i_tcon_of_get_id_from_port(struct device_node *port)
 843{
 844        struct device_node *ep;
 845        int ret = -EINVAL;
 846
 847        /* try finding an upstream endpoint */
 848        for_each_available_child_of_node(port, ep) {
 849                struct device_node *remote;
 850                u32 reg;
 851
 852                remote = of_graph_get_remote_endpoint(ep);
 853                if (!remote)
 854                        continue;
 855
 856                ret = of_property_read_u32(remote, "reg", &reg);
 857                if (ret)
 858                        continue;
 859
 860                ret = reg;
 861        }
 862
 863        return ret;
 864}
 865
 866/*
 867 * Once we know the TCON's id, we can look through the list of
 868 * engines to find a matching one. We assume all engines have
 869 * been probed and added to the list.
 870 */
 871static struct sunxi_engine *sun4i_tcon_get_engine_by_id(struct sun4i_drv *drv,
 872                                                        int id)
 873{
 874        struct sunxi_engine *engine;
 875
 876        list_for_each_entry(engine, &drv->engine_list, list)
 877                if (engine->id == id)
 878                        return engine;
 879
 880        return ERR_PTR(-EINVAL);
 881}
 882
 883/*
 884 * On SoCs with the old display pipeline design (Display Engine 1.0),
 885 * we assumed the TCON was always tied to just one backend. However
 886 * this proved not to be the case. On the A31, the TCON can select
 887 * either backend as its source. On the A20 (and likely on the A10),
 888 * the backend can choose which TCON to output to.
 889 *
 890 * The device tree binding says that the remote endpoint ID of any
 891 * connection between components, up to and including the TCON, of
 892 * the display pipeline should be equal to the actual ID of the local
 893 * component. Thus we should be able to look at any one of the input
 894 * connections of the TCONs, and use that connection's remote endpoint
 895 * ID as our own.
 896 *
 897 * However  the connections between the backend and TCON were assumed
 898 * to be always singular, and their endpoit IDs were all incorrectly
 899 * set to 0. This means for these old device trees, we cannot just look
 900 * up the remote endpoint ID of a TCON input endpoint. TCON1 would be
 901 * incorrectly identified as TCON0.
 902 *
 903 * This function first checks if the TCON node has 2 input endpoints.
 904 * If so, then the device tree is a corrected version, and it will use
 905 * sun4i_tcon_of_get_id() and sun4i_tcon_get_engine_by_id() from above
 906 * to fetch the ID and engine directly. If not, then it is likely an
 907 * old device trees, where the endpoint IDs were incorrect, but did not
 908 * have endpoint connections between the backend and TCON across
 909 * different display pipelines. It will fall back to the old method of
 910 * traversing the  of_graph to try and find a matching engine by device
 911 * node.
 912 *
 913 * In the case of single display pipeline device trees, either method
 914 * works.
 915 */
 916static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
 917                                                   struct device_node *node)
 918{
 919        struct device_node *port;
 920        struct sunxi_engine *engine;
 921
 922        port = of_graph_get_port_by_id(node, 0);
 923        if (!port)
 924                return ERR_PTR(-EINVAL);
 925
 926        /*
 927         * Is this a corrected device tree with cross pipeline
 928         * connections between the backend and TCON?
 929         */
 930        if (of_get_child_count(port) > 1) {
 931                /* Get our ID directly from an upstream endpoint */
 932                int id = sun4i_tcon_of_get_id_from_port(port);
 933
 934                /* Get our engine by matching our ID */
 935                engine = sun4i_tcon_get_engine_by_id(drv, id);
 936
 937                of_node_put(port);
 938                return engine;
 939        }
 940
 941        /* Fallback to old method by traversing input endpoints */
 942        of_node_put(port);
 943        return sun4i_tcon_find_engine_traverse(drv, node, 0);
 944}
 945
 946static int sun4i_tcon_bind(struct device *dev, struct device *master,
 947                           void *data)
 948{
 949        struct drm_device *drm = data;
 950        struct sun4i_drv *drv = drm->dev_private;
 951        struct sunxi_engine *engine;
 952        struct device_node *remote;
 953        struct sun4i_tcon *tcon;
 954        struct reset_control *edp_rstc;
 955        bool has_lvds_rst, has_lvds_alt, can_lvds;
 956        int ret;
 957
 958        engine = sun4i_tcon_find_engine(drv, dev->of_node);
 959        if (IS_ERR(engine)) {
 960                dev_err(dev, "Couldn't find matching engine\n");
 961                return -EPROBE_DEFER;
 962        }
 963
 964        tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
 965        if (!tcon)
 966                return -ENOMEM;
 967        dev_set_drvdata(dev, tcon);
 968        tcon->drm = drm;
 969        tcon->dev = dev;
 970        tcon->id = engine->id;
 971        tcon->quirks = of_device_get_match_data(dev);
 972
 973        tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
 974        if (IS_ERR(tcon->lcd_rst)) {
 975                dev_err(dev, "Couldn't get our reset line\n");
 976                return PTR_ERR(tcon->lcd_rst);
 977        }
 978
 979        if (tcon->quirks->needs_edp_reset) {
 980                edp_rstc = devm_reset_control_get_shared(dev, "edp");
 981                if (IS_ERR(edp_rstc)) {
 982                        dev_err(dev, "Couldn't get edp reset line\n");
 983                        return PTR_ERR(edp_rstc);
 984                }
 985
 986                ret = reset_control_deassert(edp_rstc);
 987                if (ret) {
 988                        dev_err(dev, "Couldn't deassert edp reset line\n");
 989                        return ret;
 990                }
 991        }
 992
 993        /* Make sure our TCON is reset */
 994        ret = reset_control_reset(tcon->lcd_rst);
 995        if (ret) {
 996                dev_err(dev, "Couldn't deassert our reset line\n");
 997                return ret;
 998        }
 999
1000        if (tcon->quirks->supports_lvds) {
1001                /*
1002                 * This can only be made optional since we've had DT
1003                 * nodes without the LVDS reset properties.
1004                 *
1005                 * If the property is missing, just disable LVDS, and
1006                 * print a warning.
1007                 */
1008                tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
1009                if (IS_ERR(tcon->lvds_rst)) {
1010                        dev_err(dev, "Couldn't get our reset line\n");
1011                        return PTR_ERR(tcon->lvds_rst);
1012                } else if (tcon->lvds_rst) {
1013                        has_lvds_rst = true;
1014                        reset_control_reset(tcon->lvds_rst);
1015                } else {
1016                        has_lvds_rst = false;
1017                }
1018
1019                /*
1020                 * This can only be made optional since we've had DT
1021                 * nodes without the LVDS reset properties.
1022                 *
1023                 * If the property is missing, just disable LVDS, and
1024                 * print a warning.
1025                 */
1026                if (tcon->quirks->has_lvds_alt) {
1027                        tcon->lvds_pll = devm_clk_get(dev, "lvds-alt");
1028                        if (IS_ERR(tcon->lvds_pll)) {
1029                                if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {
1030                                        has_lvds_alt = false;
1031                                } else {
1032                                        dev_err(dev, "Couldn't get the LVDS PLL\n");
1033                                        return PTR_ERR(tcon->lvds_pll);
1034                                }
1035                        } else {
1036                                has_lvds_alt = true;
1037                        }
1038                }
1039
1040                if (!has_lvds_rst ||
1041                    (tcon->quirks->has_lvds_alt && !has_lvds_alt)) {
1042                        dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n");
1043                        dev_warn(dev, "LVDS output disabled\n");
1044                        can_lvds = false;
1045                } else {
1046                        can_lvds = true;
1047                }
1048        } else {
1049                can_lvds = false;
1050        }
1051
1052        ret = sun4i_tcon_init_clocks(dev, tcon);
1053        if (ret) {
1054                dev_err(dev, "Couldn't init our TCON clocks\n");
1055                goto err_assert_reset;
1056        }
1057
1058        ret = sun4i_tcon_init_regmap(dev, tcon);
1059        if (ret) {
1060                dev_err(dev, "Couldn't init our TCON regmap\n");
1061                goto err_free_clocks;
1062        }
1063
1064        if (tcon->quirks->has_channel_0) {
1065                ret = sun4i_dclk_create(dev, tcon);
1066                if (ret) {
1067                        dev_err(dev, "Couldn't create our TCON dot clock\n");
1068                        goto err_free_clocks;
1069                }
1070        }
1071
1072        ret = sun4i_tcon_init_irq(dev, tcon);
1073        if (ret) {
1074                dev_err(dev, "Couldn't init our TCON interrupts\n");
1075                goto err_free_dotclock;
1076        }
1077
1078        tcon->crtc = sun4i_crtc_init(drm, engine, tcon);
1079        if (IS_ERR(tcon->crtc)) {
1080                dev_err(dev, "Couldn't create our CRTC\n");
1081                ret = PTR_ERR(tcon->crtc);
1082                goto err_free_dotclock;
1083        }
1084
1085        if (tcon->quirks->has_channel_0) {
1086                /*
1087                 * If we have an LVDS panel connected to the TCON, we should
1088                 * just probe the LVDS connector. Otherwise, just probe RGB as
1089                 * we used to.
1090                 */
1091                remote = of_graph_get_remote_node(dev->of_node, 1, 0);
1092                if (of_device_is_compatible(remote, "panel-lvds"))
1093                        if (can_lvds)
1094                                ret = sun4i_lvds_init(drm, tcon);
1095                        else
1096                                ret = -EINVAL;
1097                else
1098                        ret = sun4i_rgb_init(drm, tcon);
1099                of_node_put(remote);
1100
1101                if (ret < 0)
1102                        goto err_free_dotclock;
1103        }
1104
1105        if (tcon->quirks->needs_de_be_mux) {
1106                /*
1107                 * We assume there is no dynamic muxing of backends
1108                 * and TCONs, so we select the backend with same ID.
1109                 *
1110                 * While dynamic selection might be interesting, since
1111                 * the CRTC is tied to the TCON, while the layers are
1112                 * tied to the backends, this means, we will need to
1113                 * switch between groups of layers. There might not be
1114                 * a way to represent this constraint in DRM.
1115                 */
1116                regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
1117                                   SUN4I_TCON0_CTL_SRC_SEL_MASK,
1118                                   tcon->id);
1119                regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
1120                                   SUN4I_TCON1_CTL_SRC_SEL_MASK,
1121                                   tcon->id);
1122        }
1123
1124        list_add_tail(&tcon->list, &drv->tcon_list);
1125
1126        return 0;
1127
1128err_free_dotclock:
1129        if (tcon->quirks->has_channel_0)
1130                sun4i_dclk_free(tcon);
1131err_free_clocks:
1132        sun4i_tcon_free_clocks(tcon);
1133err_assert_reset:
1134        reset_control_assert(tcon->lcd_rst);
1135        return ret;
1136}
1137
1138static void sun4i_tcon_unbind(struct device *dev, struct device *master,
1139                              void *data)
1140{
1141        struct sun4i_tcon *tcon = dev_get_drvdata(dev);
1142
1143        list_del(&tcon->list);
1144        if (tcon->quirks->has_channel_0)
1145                sun4i_dclk_free(tcon);
1146        sun4i_tcon_free_clocks(tcon);
1147}
1148
1149static const struct component_ops sun4i_tcon_ops = {
1150        .bind   = sun4i_tcon_bind,
1151        .unbind = sun4i_tcon_unbind,
1152};
1153
1154static int sun4i_tcon_probe(struct platform_device *pdev)
1155{
1156        struct device_node *node = pdev->dev.of_node;
1157        const struct sun4i_tcon_quirks *quirks;
1158        struct drm_bridge *bridge;
1159        struct drm_panel *panel;
1160        int ret;
1161
1162        quirks = of_device_get_match_data(&pdev->dev);
1163
1164        /* panels and bridges are present only on TCONs with channel 0 */
1165        if (quirks->has_channel_0) {
1166                ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);
1167                if (ret == -EPROBE_DEFER)
1168                        return ret;
1169        }
1170
1171        return component_add(&pdev->dev, &sun4i_tcon_ops);
1172}
1173
1174static int sun4i_tcon_remove(struct platform_device *pdev)
1175{
1176        component_del(&pdev->dev, &sun4i_tcon_ops);
1177
1178        return 0;
1179}
1180
1181/* platform specific TCON muxing callbacks */
1182static int sun4i_a10_tcon_set_mux(struct sun4i_tcon *tcon,
1183                                  const struct drm_encoder *encoder)
1184{
1185        struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
1186        u32 shift;
1187
1188        if (!tcon0)
1189                return -EINVAL;
1190
1191        switch (encoder->encoder_type) {
1192        case DRM_MODE_ENCODER_TMDS:
1193                /* HDMI */
1194                shift = 8;
1195                break;
1196        default:
1197                return -EINVAL;
1198        }
1199
1200        regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
1201                           0x3 << shift, tcon->id << shift);
1202
1203        return 0;
1204}
1205
1206static int sun5i_a13_tcon_set_mux(struct sun4i_tcon *tcon,
1207                                  const struct drm_encoder *encoder)
1208{
1209        u32 val;
1210
1211        if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
1212                val = 1;
1213        else
1214                val = 0;
1215
1216        /*
1217         * FIXME: Undocumented bits
1218         */
1219        return regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
1220}
1221
1222static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
1223                              const struct drm_encoder *encoder)
1224{
1225        struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
1226        u32 shift;
1227
1228        if (!tcon0)
1229                return -EINVAL;
1230
1231        switch (encoder->encoder_type) {
1232        case DRM_MODE_ENCODER_TMDS:
1233                /* HDMI */
1234                shift = 8;
1235                break;
1236        default:
1237                /* TODO A31 has MIPI DSI but A31s does not */
1238                return -EINVAL;
1239        }
1240
1241        regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
1242                           0x3 << shift, tcon->id << shift);
1243
1244        return 0;
1245}
1246
1247static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
1248        .has_channel_0          = true,
1249        .has_channel_1          = true,
1250        .set_mux                = sun4i_a10_tcon_set_mux,
1251};
1252
1253static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
1254        .has_channel_0          = true,
1255        .has_channel_1          = true,
1256        .set_mux                = sun5i_a13_tcon_set_mux,
1257};
1258
1259static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
1260        .has_channel_0          = true,
1261        .has_channel_1          = true,
1262        .has_lvds_alt           = true,
1263        .needs_de_be_mux        = true,
1264        .set_mux                = sun6i_tcon_set_mux,
1265};
1266
1267static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
1268        .has_channel_0          = true,
1269        .has_channel_1          = true,
1270        .needs_de_be_mux        = true,
1271};
1272
1273static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
1274        .has_channel_0          = true,
1275        .has_channel_1          = true,
1276        /* Same display pipeline structure as A10 */
1277        .set_mux                = sun4i_a10_tcon_set_mux,
1278};
1279
1280static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
1281        .has_channel_0          = true,
1282        .has_lvds_alt           = true,
1283};
1284
1285static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
1286        .supports_lvds          = true,
1287        .has_channel_0          = true,
1288};
1289
1290static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
1291        .has_channel_1          = true,
1292};
1293
1294static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
1295        .has_channel_0          = true,
1296};
1297
1298static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = {
1299        .has_channel_0  = true,
1300        .needs_edp_reset = true,
1301};
1302
1303static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = {
1304        .has_channel_1  = true,
1305        .needs_edp_reset = true,
1306};
1307
1308/* sun4i_drv uses this list to check if a device node is a TCON */
1309const struct of_device_id sun4i_tcon_of_table[] = {
1310        { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
1311        { .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
1312        { .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
1313        { .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
1314        { .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
1315        { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
1316        { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
1317        { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
1318        { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
1319        { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },
1320        { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },
1321        { }
1322};
1323MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
1324EXPORT_SYMBOL(sun4i_tcon_of_table);
1325
1326static struct platform_driver sun4i_tcon_platform_driver = {
1327        .probe          = sun4i_tcon_probe,
1328        .remove         = sun4i_tcon_remove,
1329        .driver         = {
1330                .name           = "sun4i-tcon",
1331                .of_match_table = sun4i_tcon_of_table,
1332        },
1333};
1334module_platform_driver(sun4i_tcon_platform_driver);
1335
1336MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1337MODULE_DESCRIPTION("Allwinner A10 Timing Controller Driver");
1338MODULE_LICENSE("GPL");
1339