Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
   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");