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 40 static 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 56 static 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 81 static 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 115 static 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 161 void 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 197 void 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 } 211 EXPORT_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 */ 219 static 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 234 void 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 246 static 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 264 static 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 276 static 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 350 static 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 447 static 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 537 void 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 } 558 EXPORT_SYMBOL(sun4i_tcon_mode_set); 559 560 static 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 574 static 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 603 static 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 632 static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon) 633 { 634 clk_disable_unprepare(tcon->clk); 635 } 636 637 static 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 659 static 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 666 static 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 */ 712 static struct sunxi_engine * 713 sun4i_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 752 out_put_remote: 753 of_node_put(remote); 754 out_put_ep: 755 of_node_put(ep); 756 out_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 */ 772 static 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", ®); 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 */ 801 static 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 */ 846 static 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 876 static 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 1056 err_free_dotclock: 1057 if (tcon->quirks->has_channel_0) 1058 sun4i_dclk_free(tcon); 1059 err_free_clocks: 1060 sun4i_tcon_free_clocks(tcon); 1061 err_assert_reset: 1062 reset_control_assert(tcon->lcd_rst); 1063 return ret; 1064 } 1065 1066 static 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 1077 static const struct component_ops sun4i_tcon_ops = { 1078 .bind = sun4i_tcon_bind, 1079 .unbind = sun4i_tcon_unbind, 1080 }; 1081 1082 static 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 1096 static 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 */ 1104 static 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 1128 static 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 1144 static 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 1169 static 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 1175 static 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 1181 static 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 1189 static 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 1195 static 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 1202 static const struct sun4i_tcon_quirks sun8i_a33_quirks = { 1203 .has_channel_0 = true, 1204 .has_lvds_alt = true, 1205 }; 1206 1207 static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { 1208 .supports_lvds = true, 1209 .has_channel_0 = true, 1210 }; 1211 1212 static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = { 1213 .has_channel_1 = true, 1214 }; 1215 1216 static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { 1217 .has_channel_0 = true, 1218 }; 1219 1220 static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = { 1221 .has_channel_0 = true, 1222 .needs_edp_reset = true, 1223 }; 1224 1225 static 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 */ 1231 const 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 }; 1245 MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table); 1246 EXPORT_SYMBOL(sun4i_tcon_of_table); 1247 1248 static 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 }; 1256 module_platform_driver(sun4i_tcon_platform_driver); 1257 1258 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 1259 MODULE_DESCRIPTION("Allwinner A10 Timing Controller Driver"); 1260 MODULE_LICENSE("GPL"); 1261