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