1582 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2015 Free Electrons4 * Copyright (C) 2015 NextThing Co5 *6 * Maxime Ripard <maxime.ripard@free-electrons.com>7 */8 9#include <linux/component.h>10#include <linux/ioport.h>11#include <linux/media-bus-format.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/of_platform.h>15#include <linux/platform_device.h>16#include <linux/regmap.h>17#include <linux/reset.h>18 19#include <drm/drm_atomic_helper.h>20#include <drm/drm_bridge.h>21#include <drm/drm_connector.h>22#include <drm/drm_crtc.h>23#include <drm/drm_encoder.h>24#include <drm/drm_modes.h>25#include <drm/drm_of.h>26#include <drm/drm_panel.h>27#include <drm/drm_print.h>28#include <drm/drm_probe_helper.h>29#include <drm/drm_vblank.h>30 31#include <uapi/drm/drm_mode.h>32 33#include "sun4i_crtc.h"34#include "sun4i_drv.h"35#include "sun4i_lvds.h"36#include "sun4i_rgb.h"37#include "sun4i_tcon.h"38#include "sun6i_mipi_dsi.h"39#include "sun4i_tcon_dclk.h"40#include "sun8i_tcon_top.h"41#include "sunxi_engine.h"42 43static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)44{45 struct drm_connector *connector;46 struct drm_connector_list_iter iter;47 48 drm_connector_list_iter_begin(encoder->dev, &iter);49 drm_for_each_connector_iter(connector, &iter)50 if (connector->encoder == encoder) {51 drm_connector_list_iter_end(&iter);52 return connector;53 }54 drm_connector_list_iter_end(&iter);55 56 return NULL;57}58 59static int sun4i_tcon_get_pixel_depth(const struct drm_encoder *encoder)60{61 struct drm_connector *connector;62 struct drm_display_info *info;63 64 connector = sun4i_tcon_get_connector(encoder);65 if (!connector)66 return -EINVAL;67 68 info = &connector->display_info;69 if (info->num_bus_formats != 1)70 return -EINVAL;71 72 switch (info->bus_formats[0]) {73 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:74 return 18;75 76 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:77 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:78 return 24;79 }80 81 return -EINVAL;82}83 84static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,85 bool enabled)86{87 struct clk *clk;88 89 switch (channel) {90 case 0:91 WARN_ON(!tcon->quirks->has_channel_0);92 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,93 SUN4I_TCON0_CTL_TCON_ENABLE,94 enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);95 clk = tcon->dclk;96 break;97 case 1:98 WARN_ON(!tcon->quirks->has_channel_1);99 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,100 SUN4I_TCON1_CTL_TCON_ENABLE,101 enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);102 clk = tcon->sclk1;103 break;104 default:105 DRM_WARN("Unknown channel... doing nothing\n");106 return;107 }108 109 if (enabled) {110 clk_prepare_enable(clk);111 clk_rate_exclusive_get(clk);112 } else {113 clk_rate_exclusive_put(clk);114 clk_disable_unprepare(clk);115 }116}117 118static void sun4i_tcon_setup_lvds_phy(struct sun4i_tcon *tcon,119 const struct drm_encoder *encoder)120{121 regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,122 SUN4I_TCON0_LVDS_ANA0_CK_EN |123 SUN4I_TCON0_LVDS_ANA0_REG_V |124 SUN4I_TCON0_LVDS_ANA0_REG_C |125 SUN4I_TCON0_LVDS_ANA0_EN_MB |126 SUN4I_TCON0_LVDS_ANA0_PD |127 SUN4I_TCON0_LVDS_ANA0_DCHS);128 129 udelay(2); /* delay at least 1200 ns */130 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA1_REG,131 SUN4I_TCON0_LVDS_ANA1_INIT,132 SUN4I_TCON0_LVDS_ANA1_INIT);133 udelay(1); /* delay at least 120 ns */134 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA1_REG,135 SUN4I_TCON0_LVDS_ANA1_UPDATE,136 SUN4I_TCON0_LVDS_ANA1_UPDATE);137 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,138 SUN4I_TCON0_LVDS_ANA0_EN_MB,139 SUN4I_TCON0_LVDS_ANA0_EN_MB);140}141 142static void sun6i_tcon_setup_lvds_phy(struct sun4i_tcon *tcon,143 const struct drm_encoder *encoder)144{145 u8 val;146 147 regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,148 SUN6I_TCON0_LVDS_ANA0_C(2) |149 SUN6I_TCON0_LVDS_ANA0_V(3) |150 SUN6I_TCON0_LVDS_ANA0_PD(2) |151 SUN6I_TCON0_LVDS_ANA0_EN_LDO);152 udelay(2);153 154 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,155 SUN6I_TCON0_LVDS_ANA0_EN_MB,156 SUN6I_TCON0_LVDS_ANA0_EN_MB);157 udelay(2);158 159 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,160 SUN6I_TCON0_LVDS_ANA0_EN_DRVC,161 SUN6I_TCON0_LVDS_ANA0_EN_DRVC);162 163 if (sun4i_tcon_get_pixel_depth(encoder) == 18)164 val = 7;165 else166 val = 0xf;167 168 regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,169 SUN6I_TCON0_LVDS_ANA0_EN_DRVD(0xf),170 SUN6I_TCON0_LVDS_ANA0_EN_DRVD(val));171}172 173static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,174 const struct drm_encoder *encoder,175 bool enabled)176{177 if (enabled) {178 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,179 SUN4I_TCON0_LVDS_IF_EN,180 SUN4I_TCON0_LVDS_IF_EN);181 if (tcon->quirks->setup_lvds_phy)182 tcon->quirks->setup_lvds_phy(tcon, encoder);183 } else {184 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,185 SUN4I_TCON0_LVDS_IF_EN, 0);186 }187}188 189void sun4i_tcon_set_status(struct sun4i_tcon *tcon,190 const struct drm_encoder *encoder,191 bool enabled)192{193 bool is_lvds = false;194 int channel;195 196 switch (encoder->encoder_type) {197 case DRM_MODE_ENCODER_LVDS:198 is_lvds = true;199 fallthrough;200 case DRM_MODE_ENCODER_DSI:201 case DRM_MODE_ENCODER_NONE:202 channel = 0;203 break;204 case DRM_MODE_ENCODER_TMDS:205 case DRM_MODE_ENCODER_TVDAC:206 channel = 1;207 break;208 default:209 DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");210 return;211 }212 213 if (is_lvds && !enabled)214 sun4i_tcon_lvds_set_status(tcon, encoder, false);215 216 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,217 SUN4I_TCON_GCTL_TCON_ENABLE,218 enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);219 220 if (is_lvds && enabled)221 sun4i_tcon_lvds_set_status(tcon, encoder, true);222 223 sun4i_tcon_channel_set_status(tcon, channel, enabled);224}225 226void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)227{228 u32 mask, val = 0;229 230 DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");231 232 mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |233 SUN4I_TCON_GINT0_VBLANK_ENABLE(1) |234 SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE;235 236 if (enable)237 val = mask;238 239 regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val);240}241EXPORT_SYMBOL(sun4i_tcon_enable_vblank);242 243/*244 * This function is a helper for TCON output muxing. The TCON output245 * muxing control register in earlier SoCs (without the TCON TOP block)246 * are located in TCON0. This helper returns a pointer to TCON0's247 * sun4i_tcon structure, or NULL if not found.248 */249static struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm)250{251 struct sun4i_drv *drv = drm->dev_private;252 struct sun4i_tcon *tcon;253 254 list_for_each_entry(tcon, &drv->tcon_list, list)255 if (tcon->id == 0)256 return tcon;257 258 dev_warn(drm->dev,259 "TCON0 not found, display output muxing may not work\n");260 261 return NULL;262}263 264static void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,265 const struct drm_encoder *encoder)266{267 int ret = -ENOTSUPP;268 269 if (tcon->quirks->set_mux)270 ret = tcon->quirks->set_mux(tcon, encoder);271 272 DRM_DEBUG_DRIVER("Muxing encoder %s to CRTC %s: %d\n",273 encoder->name, encoder->crtc->name, ret);274}275 276static int sun4i_tcon_get_clk_delay(const struct drm_display_mode *mode,277 int channel)278{279 int delay = mode->vtotal - mode->vdisplay;280 281 if (mode->flags & DRM_MODE_FLAG_INTERLACE)282 delay /= 2;283 284 if (channel == 1)285 delay -= 2;286 287 delay = min(delay, 30);288 289 DRM_DEBUG_DRIVER("TCON %d clock delay %u\n", channel, delay);290 291 return delay;292}293 294static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon,295 const struct drm_connector *connector)296{297 u32 bus_format = 0;298 u32 val = 0;299 300 /* XXX Would this ever happen? */301 if (!connector)302 return;303 304 /*305 * FIXME: Undocumented bits306 *307 * The whole dithering process and these parameters are not308 * explained in the vendor documents or BSP kernel code.309 */310 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PR_REG, 0x11111111);311 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PG_REG, 0x11111111);312 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PB_REG, 0x11111111);313 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LR_REG, 0x11111111);314 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LG_REG, 0x11111111);315 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LB_REG, 0x11111111);316 regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL0_REG, 0x01010000);317 regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL1_REG, 0x15151111);318 regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL2_REG, 0x57575555);319 regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL3_REG, 0x7f7f7777);320 321 /* Do dithering if panel only supports 6 bits per color */322 if (connector->display_info.bpc == 6)323 val |= SUN4I_TCON0_FRM_CTL_EN;324 325 if (connector->display_info.num_bus_formats == 1)326 bus_format = connector->display_info.bus_formats[0];327 328 /* Check the connection format */329 switch (bus_format) {330 case MEDIA_BUS_FMT_RGB565_1X16:331 /* R and B components are only 5 bits deep */332 val |= SUN4I_TCON0_FRM_CTL_MODE_R;333 val |= SUN4I_TCON0_FRM_CTL_MODE_B;334 fallthrough;335 case MEDIA_BUS_FMT_RGB666_1X18:336 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:337 /* Fall through: enable dithering */338 val |= SUN4I_TCON0_FRM_CTL_EN;339 break;340 }341 342 /* Write dithering settings */343 regmap_write(tcon->regs, SUN4I_TCON_FRM_CTL_REG, val);344}345 346static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,347 const struct drm_encoder *encoder,348 const struct drm_display_mode *mode)349{350 /* TODO support normal CPU interface modes */351 struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);352 struct mipi_dsi_device *device = dsi->device;353 u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);354 u8 lanes = device->lanes;355 u32 block_space, start_delay;356 u32 tcon_div;357 358 /*359 * dclk is required to run at 1/4 the DSI per-lane bit rate.360 */361 tcon->dclk_min_div = SUN6I_DSI_TCON_DIV;362 tcon->dclk_max_div = SUN6I_DSI_TCON_DIV;363 clk_set_rate(tcon->dclk, mode->crtc_clock * 1000 * (bpp / lanes)364 / SUN6I_DSI_TCON_DIV);365 366 /* Set the resolution */367 regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,368 SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |369 SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));370 371 /* Set dithering if needed */372 sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));373 374 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,375 SUN4I_TCON0_CTL_IF_MASK,376 SUN4I_TCON0_CTL_IF_8080);377 378 regmap_write(tcon->regs, SUN4I_TCON_ECC_FIFO_REG,379 SUN4I_TCON_ECC_FIFO_EN);380 381 regmap_write(tcon->regs, SUN4I_TCON0_CPU_IF_REG,382 SUN4I_TCON0_CPU_IF_MODE_DSI |383 SUN4I_TCON0_CPU_IF_TRI_FIFO_FLUSH |384 SUN4I_TCON0_CPU_IF_TRI_FIFO_EN |385 SUN4I_TCON0_CPU_IF_TRI_EN);386 387 /*388 * This looks suspicious, but it works...389 *390 * The datasheet says that this should be set higher than 20 *391 * pixel cycle, but it's not clear what a pixel cycle is.392 */393 regmap_read(tcon->regs, SUN4I_TCON0_DCLK_REG, &tcon_div);394 tcon_div &= GENMASK(6, 0);395 block_space = mode->htotal * bpp / (tcon_div * lanes);396 block_space -= mode->hdisplay + 40;397 398 regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI0_REG,399 SUN4I_TCON0_CPU_TRI0_BLOCK_SPACE(block_space) |400 SUN4I_TCON0_CPU_TRI0_BLOCK_SIZE(mode->hdisplay));401 402 regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI1_REG,403 SUN4I_TCON0_CPU_TRI1_BLOCK_NUM(mode->vdisplay));404 405 start_delay = (mode->crtc_vtotal - mode->crtc_vdisplay - 10 - 1);406 start_delay = start_delay * mode->crtc_htotal * 149;407 start_delay = start_delay / (mode->crtc_clock / 1000) / 8;408 regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI2_REG,409 SUN4I_TCON0_CPU_TRI2_TRANS_START_SET(10) |410 SUN4I_TCON0_CPU_TRI2_START_DELAY(start_delay));411 412 /*413 * The Allwinner BSP has a comment that the period should be414 * the display clock * 15, but uses an hardcoded 3000...415 */416 regmap_write(tcon->regs, SUN4I_TCON_SAFE_PERIOD_REG,417 SUN4I_TCON_SAFE_PERIOD_NUM(3000) |418 SUN4I_TCON_SAFE_PERIOD_MODE(3));419 420 /* Enable the output on the pins */421 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG,422 0xe0000000);423}424 425static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,426 const struct drm_encoder *encoder,427 const struct drm_display_mode *mode)428{429 unsigned int bp;430 u8 clk_delay;431 u32 reg, val = 0;432 433 WARN_ON(!tcon->quirks->has_channel_0);434 435 tcon->dclk_min_div = 7;436 tcon->dclk_max_div = 7;437 clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);438 439 /* Set the resolution */440 regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,441 SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |442 SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));443 444 /* Set dithering if needed */445 sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));446 447 /* Adjust clock delay */448 clk_delay = sun4i_tcon_get_clk_delay(mode, 0);449 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,450 SUN4I_TCON0_CTL_CLK_DELAY_MASK,451 SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));452 453 /*454 * This is called a backporch in the register documentation,455 * but it really is the back porch + hsync456 */457 bp = mode->crtc_htotal - mode->crtc_hsync_start;458 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",459 mode->crtc_htotal, bp);460 461 /* Set horizontal display timings */462 regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,463 SUN4I_TCON0_BASIC1_H_TOTAL(mode->htotal) |464 SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));465 466 /*467 * This is called a backporch in the register documentation,468 * but it really is the back porch + hsync469 */470 bp = mode->crtc_vtotal - mode->crtc_vsync_start;471 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",472 mode->crtc_vtotal, bp);473 474 /* Set vertical display timings */475 regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,476 SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |477 SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));478 479 reg = SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0;480 if (sun4i_tcon_get_pixel_depth(encoder) == 24)481 reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS;482 else483 reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS;484 485 regmap_write(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, reg);486 487 /* Setup the polarity of the various signals */488 if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))489 val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;490 491 if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))492 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;493 494 regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);495 496 /* Map output pins to channel 0 */497 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,498 SUN4I_TCON_GCTL_IOMAP_MASK,499 SUN4I_TCON_GCTL_IOMAP_TCON0);500 501 /* Enable the output on the pins */502 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000);503}504 505static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,506 const struct drm_encoder *encoder,507 const struct drm_display_mode *mode)508{509 struct drm_connector *connector = sun4i_tcon_get_connector(encoder);510 const struct drm_display_info *info = &connector->display_info;511 unsigned int bp, hsync, vsync;512 u8 clk_delay;513 u32 val = 0;514 515 WARN_ON(!tcon->quirks->has_channel_0);516 517 tcon->dclk_min_div = tcon->quirks->dclk_min_div;518 tcon->dclk_max_div = 127;519 clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);520 521 /* Set the resolution */522 regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,523 SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |524 SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));525 526 /* Set dithering if needed */527 sun4i_tcon0_mode_set_dithering(tcon, connector);528 529 /* Adjust clock delay */530 clk_delay = sun4i_tcon_get_clk_delay(mode, 0);531 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,532 SUN4I_TCON0_CTL_CLK_DELAY_MASK,533 SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));534 535 /*536 * This is called a backporch in the register documentation,537 * but it really is the back porch + hsync538 */539 bp = mode->crtc_htotal - mode->crtc_hsync_start;540 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",541 mode->crtc_htotal, bp);542 543 /* Set horizontal display timings */544 regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,545 SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) |546 SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));547 548 /*549 * This is called a backporch in the register documentation,550 * but it really is the back porch + hsync551 */552 bp = mode->crtc_vtotal - mode->crtc_vsync_start;553 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",554 mode->crtc_vtotal, bp);555 556 /* Set vertical display timings */557 regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,558 SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |559 SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));560 561 /* Set Hsync and Vsync length */562 hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;563 vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;564 DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);565 regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG,566 SUN4I_TCON0_BASIC3_V_SYNC(vsync) |567 SUN4I_TCON0_BASIC3_H_SYNC(hsync));568 569 /* Setup the polarity of the various signals */570 if (mode->flags & DRM_MODE_FLAG_PHSYNC)571 val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;572 573 if (mode->flags & DRM_MODE_FLAG_PVSYNC)574 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;575 576 if (info->bus_flags & DRM_BUS_FLAG_DE_LOW)577 val |= SUN4I_TCON0_IO_POL_DE_NEGATIVE;578 579 if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)580 val |= SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE;581 582 regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,583 SUN4I_TCON0_IO_POL_HSYNC_POSITIVE |584 SUN4I_TCON0_IO_POL_VSYNC_POSITIVE |585 SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE |586 SUN4I_TCON0_IO_POL_DE_NEGATIVE,587 val);588 589 /* Map output pins to channel 0 */590 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,591 SUN4I_TCON_GCTL_IOMAP_MASK,592 SUN4I_TCON_GCTL_IOMAP_TCON0);593 594 /* Enable the output on the pins */595 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);596}597 598static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,599 const struct drm_display_mode *mode)600{601 unsigned int bp, hsync, vsync, vtotal;602 u8 clk_delay;603 u32 val;604 605 WARN_ON(!tcon->quirks->has_channel_1);606 607 /* Configure the dot clock */608 clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);609 610 /* Adjust clock delay */611 clk_delay = sun4i_tcon_get_clk_delay(mode, 1);612 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,613 SUN4I_TCON1_CTL_CLK_DELAY_MASK,614 SUN4I_TCON1_CTL_CLK_DELAY(clk_delay));615 616 /* Set interlaced mode */617 if (mode->flags & DRM_MODE_FLAG_INTERLACE)618 val = SUN4I_TCON1_CTL_INTERLACE_ENABLE;619 else620 val = 0;621 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,622 SUN4I_TCON1_CTL_INTERLACE_ENABLE,623 val);624 625 /* Set the input resolution */626 regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,627 SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |628 SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));629 630 /* Set the upscaling resolution */631 regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,632 SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |633 SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));634 635 /* Set the output resolution */636 regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,637 SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |638 SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));639 640 /* Set horizontal display timings */641 bp = mode->crtc_htotal - mode->crtc_hsync_start;642 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",643 mode->htotal, bp);644 regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,645 SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |646 SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));647 648 bp = mode->crtc_vtotal - mode->crtc_vsync_start;649 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",650 mode->crtc_vtotal, bp);651 652 /*653 * The vertical resolution needs to be doubled in all654 * cases. We could use crtc_vtotal and always multiply by two,655 * but that leads to a rounding error in interlace when vtotal656 * is odd.657 *658 * This happens with TV's PAL for example, where vtotal will659 * be 625, crtc_vtotal 312, and thus crtc_vtotal * 2 will be660 * 624, which apparently confuses the hardware.661 *662 * To work around this, we will always use vtotal, and663 * multiply by two only if we're not in interlace.664 */665 vtotal = mode->vtotal;666 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))667 vtotal = vtotal * 2;668 669 /* Set vertical display timings */670 regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG,671 SUN4I_TCON1_BASIC4_V_TOTAL(vtotal) |672 SUN4I_TCON1_BASIC4_V_BACKPORCH(bp));673 674 /* Set Hsync and Vsync length */675 hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;676 vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;677 DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);678 regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG,679 SUN4I_TCON1_BASIC5_V_SYNC(vsync) |680 SUN4I_TCON1_BASIC5_H_SYNC(hsync));681 682 /* Setup the polarity of multiple signals */683 if (tcon->quirks->polarity_in_ch0) {684 val = 0;685 686 if (mode->flags & DRM_MODE_FLAG_PHSYNC)687 val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;688 689 if (mode->flags & DRM_MODE_FLAG_PVSYNC)690 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;691 692 regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);693 } else {694 /* according to vendor driver, this bit must be always set */695 val = SUN4I_TCON1_IO_POL_UNKNOWN;696 697 if (mode->flags & DRM_MODE_FLAG_PHSYNC)698 val |= SUN4I_TCON1_IO_POL_HSYNC_POSITIVE;699 700 if (mode->flags & DRM_MODE_FLAG_PVSYNC)701 val |= SUN4I_TCON1_IO_POL_VSYNC_POSITIVE;702 703 regmap_write(tcon->regs, SUN4I_TCON1_IO_POL_REG, val);704 }705 706 /* Map output pins to channel 1 */707 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,708 SUN4I_TCON_GCTL_IOMAP_MASK,709 SUN4I_TCON_GCTL_IOMAP_TCON1);710}711 712void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,713 const struct drm_encoder *encoder,714 const struct drm_display_mode *mode)715{716 switch (encoder->encoder_type) {717 case DRM_MODE_ENCODER_DSI:718 /* DSI is tied to special case of CPU interface */719 sun4i_tcon0_mode_set_cpu(tcon, encoder, mode);720 break;721 case DRM_MODE_ENCODER_LVDS:722 sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);723 break;724 case DRM_MODE_ENCODER_NONE:725 sun4i_tcon0_mode_set_rgb(tcon, encoder, mode);726 sun4i_tcon_set_mux(tcon, 0, encoder);727 break;728 case DRM_MODE_ENCODER_TVDAC:729 case DRM_MODE_ENCODER_TMDS:730 sun4i_tcon1_mode_set(tcon, mode);731 sun4i_tcon_set_mux(tcon, 1, encoder);732 break;733 default:734 DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");735 }736}737EXPORT_SYMBOL(sun4i_tcon_mode_set);738 739static void sun4i_tcon_finish_page_flip(struct drm_device *dev,740 struct sun4i_crtc *scrtc)741{742 unsigned long flags;743 744 spin_lock_irqsave(&dev->event_lock, flags);745 if (scrtc->event) {746 drm_crtc_send_vblank_event(&scrtc->crtc, scrtc->event);747 drm_crtc_vblank_put(&scrtc->crtc);748 scrtc->event = NULL;749 }750 spin_unlock_irqrestore(&dev->event_lock, flags);751}752 753static irqreturn_t sun4i_tcon_handler(int irq, void *private)754{755 struct sun4i_tcon *tcon = private;756 struct drm_device *drm = tcon->drm;757 struct sun4i_crtc *scrtc = tcon->crtc;758 struct sunxi_engine *engine = scrtc->engine;759 unsigned int status;760 761 regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);762 763 if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |764 SUN4I_TCON_GINT0_VBLANK_INT(1) |765 SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT)))766 return IRQ_NONE;767 768 drm_crtc_handle_vblank(&scrtc->crtc);769 sun4i_tcon_finish_page_flip(drm, scrtc);770 771 /* Acknowledge the interrupt */772 regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,773 SUN4I_TCON_GINT0_VBLANK_INT(0) |774 SUN4I_TCON_GINT0_VBLANK_INT(1) |775 SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT,776 0);777 778 if (engine->ops->vblank_quirk)779 engine->ops->vblank_quirk(engine);780 781 return IRQ_HANDLED;782}783 784static int sun4i_tcon_init_clocks(struct device *dev,785 struct sun4i_tcon *tcon)786{787 tcon->clk = devm_clk_get_enabled(dev, "ahb");788 if (IS_ERR(tcon->clk)) {789 dev_err(dev, "Couldn't get the TCON bus clock\n");790 return PTR_ERR(tcon->clk);791 }792 793 if (tcon->quirks->has_channel_0) {794 tcon->sclk0 = devm_clk_get_enabled(dev, "tcon-ch0");795 if (IS_ERR(tcon->sclk0)) {796 dev_err(dev, "Couldn't get the TCON channel 0 clock\n");797 return PTR_ERR(tcon->sclk0);798 }799 }800 801 if (tcon->quirks->has_channel_1) {802 tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");803 if (IS_ERR(tcon->sclk1)) {804 dev_err(dev, "Couldn't get the TCON channel 1 clock\n");805 return PTR_ERR(tcon->sclk1);806 }807 }808 809 return 0;810}811 812static int sun4i_tcon_init_irq(struct device *dev,813 struct sun4i_tcon *tcon)814{815 struct platform_device *pdev = to_platform_device(dev);816 int irq, ret;817 818 irq = platform_get_irq(pdev, 0);819 if (irq < 0)820 return irq;821 822 ret = devm_request_irq(dev, irq, sun4i_tcon_handler, 0,823 dev_name(dev), tcon);824 if (ret) {825 dev_err(dev, "Couldn't request the IRQ\n");826 return ret;827 }828 829 return 0;830}831 832static const struct regmap_config sun4i_tcon_regmap_config = {833 .reg_bits = 32,834 .val_bits = 32,835 .reg_stride = 4,836 .max_register = 0x800,837};838 839static int sun4i_tcon_init_regmap(struct device *dev,840 struct sun4i_tcon *tcon)841{842 struct platform_device *pdev = to_platform_device(dev);843 void __iomem *regs;844 845 regs = devm_platform_ioremap_resource(pdev, 0);846 if (IS_ERR(regs))847 return PTR_ERR(regs);848 849 tcon->regs = devm_regmap_init_mmio(dev, regs,850 &sun4i_tcon_regmap_config);851 if (IS_ERR(tcon->regs)) {852 dev_err(dev, "Couldn't create the TCON regmap\n");853 return PTR_ERR(tcon->regs);854 }855 856 /* Make sure the TCON is disabled and all IRQs are off */857 regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0);858 regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0);859 regmap_write(tcon->regs, SUN4I_TCON_GINT1_REG, 0);860 861 /* Disable IO lines and set them to tristate */862 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0);863 regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0);864 865 return 0;866}867 868/*869 * On SoCs with the old display pipeline design (Display Engine 1.0),870 * the TCON is always tied to just one backend. Hence we can traverse871 * the of_graph upwards to find the backend our tcon is connected to,872 * and take its ID as our own.873 *874 * We can either identify backends from their compatible strings, which875 * means maintaining a large list of them. Or, since the backend is876 * registered and binded before the TCON, we can just go through the877 * list of registered backends and compare the device node.878 *879 * As the structures now store engines instead of backends, here this880 * function in fact searches the corresponding engine, and the ID is881 * requested via the get_id function of the engine.882 */883static struct sunxi_engine *884sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv,885 struct device_node *node,886 u32 port_id)887{888 struct device_node *port, *ep, *remote;889 struct sunxi_engine *engine = ERR_PTR(-EINVAL);890 u32 reg = 0;891 892 port = of_graph_get_port_by_id(node, port_id);893 if (!port)894 return ERR_PTR(-EINVAL);895 896 /*897 * This only works if there is only one path from the TCON898 * to any display engine. Otherwise the probe order of the899 * TCONs and display engines is not guaranteed. They may900 * either bind to the wrong one, or worse, bind to the same901 * one if additional checks are not done.902 *903 * Bail out if there are multiple input connections.904 */905 if (of_get_available_child_count(port) != 1)906 goto out_put_port;907 908 /* Get the first connection without specifying an ID */909 ep = of_get_next_available_child(port, NULL);910 if (!ep)911 goto out_put_port;912 913 remote = of_graph_get_remote_port_parent(ep);914 if (!remote)915 goto out_put_ep;916 917 /* does this node match any registered engines? */918 list_for_each_entry(engine, &drv->engine_list, list)919 if (remote == engine->node)920 goto out_put_remote;921 922 /*923 * According to device tree binding input ports have even id924 * number and output ports have odd id. Since component with925 * more than one input and one output (TCON TOP) exits, correct926 * remote input id has to be calculated by subtracting 1 from927 * remote output id. If this for some reason can't be done, 0928 * is used as input port id.929 */930 of_node_put(port);931 port = of_graph_get_remote_port(ep);932 if (!of_property_read_u32(port, "reg", ®) && reg > 0)933 reg -= 1;934 935 /* keep looking through upstream ports */936 engine = sun4i_tcon_find_engine_traverse(drv, remote, reg);937 938out_put_remote:939 of_node_put(remote);940out_put_ep:941 of_node_put(ep);942out_put_port:943 of_node_put(port);944 945 return engine;946}947 948/*949 * The device tree binding says that the remote endpoint ID of any950 * connection between components, up to and including the TCON, of951 * the display pipeline should be equal to the actual ID of the local952 * component. Thus we can look at any one of the input connections of953 * the TCONs, and use that connection's remote endpoint ID as our own.954 *955 * Since the user of this function already finds the input port,956 * the port is passed in directly without further checks.957 */958static int sun4i_tcon_of_get_id_from_port(struct device_node *port)959{960 struct device_node *ep;961 int ret = -EINVAL;962 963 /* try finding an upstream endpoint */964 for_each_available_child_of_node(port, ep) {965 struct device_node *remote;966 u32 reg;967 968 remote = of_graph_get_remote_endpoint(ep);969 if (!remote)970 continue;971 972 ret = of_property_read_u32(remote, "reg", ®);973 if (ret)974 continue;975 976 ret = reg;977 }978 979 return ret;980}981 982/*983 * Once we know the TCON's id, we can look through the list of984 * engines to find a matching one. We assume all engines have985 * been probed and added to the list.986 */987static struct sunxi_engine *sun4i_tcon_get_engine_by_id(struct sun4i_drv *drv,988 int id)989{990 struct sunxi_engine *engine;991 992 list_for_each_entry(engine, &drv->engine_list, list)993 if (engine->id == id)994 return engine;995 996 return ERR_PTR(-EINVAL);997}998 999static bool sun4i_tcon_connected_to_tcon_top(struct device_node *node)1000{1001 struct device_node *remote;1002 bool ret = false;1003 1004 remote = of_graph_get_remote_node(node, 0, -1);1005 if (remote) {1006 ret = !!(IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&1007 of_match_node(sun8i_tcon_top_of_table, remote));1008 of_node_put(remote);1009 }1010 1011 return ret;1012}1013 1014static int sun4i_tcon_get_index(struct sun4i_drv *drv)1015{1016 struct list_head *pos;1017 int size = 0;1018 1019 /*1020 * Because TCON is added to the list at the end of the probe1021 * (after this function is called), index of the current TCON1022 * will be same as current TCON list size.1023 */1024 list_for_each(pos, &drv->tcon_list)1025 ++size;1026 1027 return size;1028}1029 1030/*1031 * On SoCs with the old display pipeline design (Display Engine 1.0),1032 * we assumed the TCON was always tied to just one backend. However1033 * this proved not to be the case. On the A31, the TCON can select1034 * either backend as its source. On the A20 (and likely on the A10),1035 * the backend can choose which TCON to output to.1036 *1037 * The device tree binding says that the remote endpoint ID of any1038 * connection between components, up to and including the TCON, of1039 * the display pipeline should be equal to the actual ID of the local1040 * component. Thus we should be able to look at any one of the input1041 * connections of the TCONs, and use that connection's remote endpoint1042 * ID as our own.1043 *1044 * However the connections between the backend and TCON were assumed1045 * to be always singular, and their endpoit IDs were all incorrectly1046 * set to 0. This means for these old device trees, we cannot just look1047 * up the remote endpoint ID of a TCON input endpoint. TCON1 would be1048 * incorrectly identified as TCON0.1049 *1050 * This function first checks if the TCON node has 2 input endpoints.1051 * If so, then the device tree is a corrected version, and it will use1052 * sun4i_tcon_of_get_id() and sun4i_tcon_get_engine_by_id() from above1053 * to fetch the ID and engine directly. If not, then it is likely an1054 * old device trees, where the endpoint IDs were incorrect, but did not1055 * have endpoint connections between the backend and TCON across1056 * different display pipelines. It will fall back to the old method of1057 * traversing the of_graph to try and find a matching engine by device1058 * node.1059 *1060 * In the case of single display pipeline device trees, either method1061 * works.1062 */1063static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,1064 struct device_node *node)1065{1066 struct device_node *port;1067 struct sunxi_engine *engine;1068 1069 port = of_graph_get_port_by_id(node, 0);1070 if (!port)1071 return ERR_PTR(-EINVAL);1072 1073 /*1074 * Is this a corrected device tree with cross pipeline1075 * connections between the backend and TCON?1076 */1077 if (of_get_child_count(port) > 1) {1078 int id;1079 1080 /*1081 * When pipeline has the same number of TCONs and engines which1082 * are represented by frontends/backends (DE1) or mixers (DE2),1083 * we match them by their respective IDs. However, if pipeline1084 * contains TCON TOP, chances are that there are either more1085 * TCONs than engines (R40) or TCONs with non-consecutive ids.1086 * (H6). In that case it's easier just use TCON index in list1087 * as an id. That means that on R40, any 2 TCONs can be enabled1088 * in DT out of 4 (there are 2 mixers). Due to the design of1089 * TCON TOP, remaining 2 TCONs can't be connected to anything1090 * anyway.1091 */1092 if (sun4i_tcon_connected_to_tcon_top(node))1093 id = sun4i_tcon_get_index(drv);1094 else1095 id = sun4i_tcon_of_get_id_from_port(port);1096 1097 /* Get our engine by matching our ID */1098 engine = sun4i_tcon_get_engine_by_id(drv, id);1099 1100 of_node_put(port);1101 return engine;1102 }1103 1104 /* Fallback to old method by traversing input endpoints */1105 of_node_put(port);1106 return sun4i_tcon_find_engine_traverse(drv, node, 0);1107}1108 1109static int sun4i_tcon_bind(struct device *dev, struct device *master,1110 void *data)1111{1112 struct drm_device *drm = data;1113 struct sun4i_drv *drv = drm->dev_private;1114 struct sunxi_engine *engine;1115 struct device_node *remote;1116 struct sun4i_tcon *tcon;1117 struct reset_control *edp_rstc;1118 bool has_lvds_rst, has_lvds_alt, can_lvds;1119 int ret;1120 1121 engine = sun4i_tcon_find_engine(drv, dev->of_node);1122 if (IS_ERR(engine)) {1123 dev_err(dev, "Couldn't find matching engine\n");1124 return -EPROBE_DEFER;1125 }1126 1127 tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);1128 if (!tcon)1129 return -ENOMEM;1130 dev_set_drvdata(dev, tcon);1131 tcon->drm = drm;1132 tcon->dev = dev;1133 tcon->id = engine->id;1134 tcon->quirks = of_device_get_match_data(dev);1135 1136 tcon->lcd_rst = devm_reset_control_get(dev, "lcd");1137 if (IS_ERR(tcon->lcd_rst)) {1138 dev_err(dev, "Couldn't get our reset line\n");1139 return PTR_ERR(tcon->lcd_rst);1140 }1141 1142 if (tcon->quirks->needs_edp_reset) {1143 edp_rstc = devm_reset_control_get_shared(dev, "edp");1144 if (IS_ERR(edp_rstc)) {1145 dev_err(dev, "Couldn't get edp reset line\n");1146 return PTR_ERR(edp_rstc);1147 }1148 1149 ret = reset_control_deassert(edp_rstc);1150 if (ret) {1151 dev_err(dev, "Couldn't deassert edp reset line\n");1152 return ret;1153 }1154 }1155 1156 /* Make sure our TCON is reset */1157 ret = reset_control_reset(tcon->lcd_rst);1158 if (ret) {1159 dev_err(dev, "Couldn't deassert our reset line\n");1160 return ret;1161 }1162 1163 if (tcon->quirks->supports_lvds) {1164 /*1165 * This can only be made optional since we've had DT1166 * nodes without the LVDS reset properties.1167 *1168 * If the property is missing, just disable LVDS, and1169 * print a warning.1170 */1171 tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");1172 if (IS_ERR(tcon->lvds_rst)) {1173 dev_err(dev, "Couldn't get our reset line\n");1174 return PTR_ERR(tcon->lvds_rst);1175 } else if (tcon->lvds_rst) {1176 has_lvds_rst = true;1177 reset_control_reset(tcon->lvds_rst);1178 } else {1179 has_lvds_rst = false;1180 }1181 1182 /*1183 * This can only be made optional since we've had DT1184 * nodes without the LVDS reset properties.1185 *1186 * If the property is missing, just disable LVDS, and1187 * print a warning.1188 */1189 if (tcon->quirks->has_lvds_alt) {1190 tcon->lvds_pll = devm_clk_get(dev, "lvds-alt");1191 if (IS_ERR(tcon->lvds_pll)) {1192 if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {1193 has_lvds_alt = false;1194 } else {1195 dev_err(dev, "Couldn't get the LVDS PLL\n");1196 return PTR_ERR(tcon->lvds_pll);1197 }1198 } else {1199 has_lvds_alt = true;1200 }1201 }1202 1203 if (!has_lvds_rst ||1204 (tcon->quirks->has_lvds_alt && !has_lvds_alt)) {1205 dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n");1206 dev_warn(dev, "LVDS output disabled\n");1207 can_lvds = false;1208 } else {1209 can_lvds = true;1210 }1211 } else {1212 can_lvds = false;1213 }1214 1215 ret = sun4i_tcon_init_clocks(dev, tcon);1216 if (ret) {1217 dev_err(dev, "Couldn't init our TCON clocks\n");1218 goto err_assert_reset;1219 }1220 1221 ret = sun4i_tcon_init_regmap(dev, tcon);1222 if (ret) {1223 dev_err(dev, "Couldn't init our TCON regmap\n");1224 goto err_assert_reset;1225 }1226 1227 if (tcon->quirks->has_channel_0) {1228 ret = sun4i_dclk_create(dev, tcon);1229 if (ret) {1230 dev_err(dev, "Couldn't create our TCON dot clock\n");1231 goto err_assert_reset;1232 }1233 }1234 1235 ret = sun4i_tcon_init_irq(dev, tcon);1236 if (ret) {1237 dev_err(dev, "Couldn't init our TCON interrupts\n");1238 goto err_free_dclk;1239 }1240 1241 tcon->crtc = sun4i_crtc_init(drm, engine, tcon);1242 if (IS_ERR(tcon->crtc)) {1243 dev_err(dev, "Couldn't create our CRTC\n");1244 ret = PTR_ERR(tcon->crtc);1245 goto err_free_dclk;1246 }1247 1248 if (tcon->quirks->has_channel_0) {1249 /*1250 * If we have an LVDS panel connected to the TCON, we should1251 * just probe the LVDS connector. Otherwise, just probe RGB as1252 * we used to.1253 */1254 remote = of_graph_get_remote_node(dev->of_node, 1, 0);1255 if (of_device_is_compatible(remote, "panel-lvds"))1256 if (can_lvds)1257 ret = sun4i_lvds_init(drm, tcon);1258 else1259 ret = -EINVAL;1260 else1261 ret = sun4i_rgb_init(drm, tcon);1262 of_node_put(remote);1263 1264 if (ret < 0)1265 goto err_free_dclk;1266 }1267 1268 if (tcon->quirks->needs_de_be_mux) {1269 /*1270 * We assume there is no dynamic muxing of backends1271 * and TCONs, so we select the backend with same ID.1272 *1273 * While dynamic selection might be interesting, since1274 * the CRTC is tied to the TCON, while the layers are1275 * tied to the backends, this means, we will need to1276 * switch between groups of layers. There might not be1277 * a way to represent this constraint in DRM.1278 */1279 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,1280 SUN4I_TCON0_CTL_SRC_SEL_MASK,1281 tcon->id);1282 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,1283 SUN4I_TCON1_CTL_SRC_SEL_MASK,1284 tcon->id);1285 }1286 1287 list_add_tail(&tcon->list, &drv->tcon_list);1288 1289 return 0;1290 1291err_free_dclk:1292 if (tcon->quirks->has_channel_0)1293 sun4i_dclk_free(tcon);1294err_assert_reset:1295 reset_control_assert(tcon->lcd_rst);1296 return ret;1297}1298 1299static void sun4i_tcon_unbind(struct device *dev, struct device *master,1300 void *data)1301{1302 struct sun4i_tcon *tcon = dev_get_drvdata(dev);1303 1304 list_del(&tcon->list);1305 if (tcon->quirks->has_channel_0)1306 sun4i_dclk_free(tcon);1307}1308 1309static const struct component_ops sun4i_tcon_ops = {1310 .bind = sun4i_tcon_bind,1311 .unbind = sun4i_tcon_unbind,1312};1313 1314static int sun4i_tcon_probe(struct platform_device *pdev)1315{1316 struct device_node *node = pdev->dev.of_node;1317 const struct sun4i_tcon_quirks *quirks;1318 struct drm_bridge *bridge;1319 struct drm_panel *panel;1320 int ret;1321 1322 quirks = of_device_get_match_data(&pdev->dev);1323 1324 /* panels and bridges are present only on TCONs with channel 0 */1325 if (quirks->has_channel_0) {1326 ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);1327 if (ret == -EPROBE_DEFER)1328 return ret;1329 }1330 1331 return component_add(&pdev->dev, &sun4i_tcon_ops);1332}1333 1334static void sun4i_tcon_remove(struct platform_device *pdev)1335{1336 component_del(&pdev->dev, &sun4i_tcon_ops);1337}1338 1339/* platform specific TCON muxing callbacks */1340static int sun4i_a10_tcon_set_mux(struct sun4i_tcon *tcon,1341 const struct drm_encoder *encoder)1342{1343 struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);1344 u32 shift;1345 1346 if (!tcon0)1347 return -EINVAL;1348 1349 switch (encoder->encoder_type) {1350 case DRM_MODE_ENCODER_TMDS:1351 /* HDMI */1352 shift = 8;1353 break;1354 default:1355 return -EINVAL;1356 }1357 1358 regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,1359 0x3 << shift, tcon->id << shift);1360 1361 return 0;1362}1363 1364static int sun5i_a13_tcon_set_mux(struct sun4i_tcon *tcon,1365 const struct drm_encoder *encoder)1366{1367 u32 val;1368 1369 if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)1370 val = 1;1371 else1372 val = 0;1373 1374 /*1375 * FIXME: Undocumented bits1376 */1377 return regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);1378}1379 1380static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,1381 const struct drm_encoder *encoder)1382{1383 struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);1384 u32 shift;1385 1386 if (!tcon0)1387 return -EINVAL;1388 1389 switch (encoder->encoder_type) {1390 case DRM_MODE_ENCODER_TMDS:1391 /* HDMI */1392 shift = 8;1393 break;1394 default:1395 /* TODO A31 has MIPI DSI but A31s does not */1396 return -EINVAL;1397 }1398 1399 regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,1400 0x3 << shift, tcon->id << shift);1401 1402 return 0;1403}1404 1405static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,1406 const struct drm_encoder *encoder)1407{1408 struct device_node *port, *remote;1409 struct platform_device *pdev;1410 int id, ret;1411 1412 /* find TCON TOP platform device and TCON id */1413 1414 port = of_graph_get_port_by_id(tcon->dev->of_node, 0);1415 if (!port)1416 return -EINVAL;1417 1418 id = sun4i_tcon_of_get_id_from_port(port);1419 of_node_put(port);1420 1421 remote = of_graph_get_remote_node(tcon->dev->of_node, 0, -1);1422 if (!remote)1423 return -EINVAL;1424 1425 pdev = of_find_device_by_node(remote);1426 of_node_put(remote);1427 if (!pdev)1428 return -EINVAL;1429 1430 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&1431 encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {1432 ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);1433 if (ret) {1434 put_device(&pdev->dev);1435 return ret;1436 }1437 }1438 1439 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {1440 ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);1441 if (ret) {1442 put_device(&pdev->dev);1443 return ret;1444 }1445 }1446 1447 return 0;1448}1449 1450static const struct sun4i_tcon_quirks sun4i_a10_quirks = {1451 .has_channel_0 = true,1452 .has_channel_1 = true,1453 .dclk_min_div = 4,1454 .set_mux = sun4i_a10_tcon_set_mux,1455};1456 1457static const struct sun4i_tcon_quirks sun5i_a13_quirks = {1458 .has_channel_0 = true,1459 .has_channel_1 = true,1460 .dclk_min_div = 4,1461 .set_mux = sun5i_a13_tcon_set_mux,1462};1463 1464static const struct sun4i_tcon_quirks sun6i_a31_quirks = {1465 .has_channel_0 = true,1466 .has_channel_1 = true,1467 .has_lvds_alt = true,1468 .needs_de_be_mux = true,1469 .dclk_min_div = 1,1470 .set_mux = sun6i_tcon_set_mux,1471};1472 1473static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {1474 .has_channel_0 = true,1475 .has_channel_1 = true,1476 .needs_de_be_mux = true,1477 .dclk_min_div = 1,1478};1479 1480static const struct sun4i_tcon_quirks sun7i_a20_tcon0_quirks = {1481 .supports_lvds = true,1482 .has_channel_0 = true,1483 .has_channel_1 = true,1484 .dclk_min_div = 4,1485 /* Same display pipeline structure as A10 */1486 .set_mux = sun4i_a10_tcon_set_mux,1487 .setup_lvds_phy = sun4i_tcon_setup_lvds_phy,1488};1489 1490static const struct sun4i_tcon_quirks sun7i_a20_quirks = {1491 .has_channel_0 = true,1492 .has_channel_1 = true,1493 .dclk_min_div = 4,1494 /* Same display pipeline structure as A10 */1495 .set_mux = sun4i_a10_tcon_set_mux,1496};1497 1498static const struct sun4i_tcon_quirks sun8i_a33_quirks = {1499 .has_channel_0 = true,1500 .has_lvds_alt = true,1501 .dclk_min_div = 1,1502 .setup_lvds_phy = sun6i_tcon_setup_lvds_phy,1503 .supports_lvds = true,1504};1505 1506static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {1507 .supports_lvds = true,1508 .has_channel_0 = true,1509 .dclk_min_div = 1,1510 .setup_lvds_phy = sun6i_tcon_setup_lvds_phy,1511};1512 1513static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {1514 .has_channel_1 = true,1515};1516 1517static const struct sun4i_tcon_quirks sun8i_r40_tv_quirks = {1518 .has_channel_1 = true,1519 .polarity_in_ch0 = true,1520 .set_mux = sun8i_r40_tcon_tv_set_mux,1521};1522 1523static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {1524 .has_channel_0 = true,1525 .dclk_min_div = 1,1526};1527 1528static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = {1529 .has_channel_0 = true,1530 .needs_edp_reset = true,1531 .dclk_min_div = 1,1532};1533 1534static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = {1535 .has_channel_1 = true,1536 .needs_edp_reset = true,1537};1538 1539static const struct sun4i_tcon_quirks sun20i_d1_lcd_quirks = {1540 .has_channel_0 = true,1541 .dclk_min_div = 1,1542 .set_mux = sun8i_r40_tcon_tv_set_mux,1543};1544 1545/* sun4i_drv uses this list to check if a device node is a TCON */1546const struct of_device_id sun4i_tcon_of_table[] = {1547 { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },1548 { .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },1549 { .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },1550 { .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },1551 { .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },1552 { .compatible = "allwinner,sun7i-a20-tcon0", .data = &sun7i_a20_tcon0_quirks },1553 { .compatible = "allwinner,sun7i-a20-tcon1", .data = &sun7i_a20_quirks },1554 { .compatible = "allwinner,sun8i-a23-tcon", .data = &sun8i_a33_quirks },1555 { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },1556 { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },1557 { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },1558 { .compatible = "allwinner,sun8i-r40-tcon-tv", .data = &sun8i_r40_tv_quirks },1559 { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },1560 { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },1561 { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },1562 { .compatible = "allwinner,sun20i-d1-tcon-lcd", .data = &sun20i_d1_lcd_quirks },1563 { .compatible = "allwinner,sun20i-d1-tcon-tv", .data = &sun8i_r40_tv_quirks },1564 { }1565};1566MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);1567EXPORT_SYMBOL(sun4i_tcon_of_table);1568 1569static struct platform_driver sun4i_tcon_platform_driver = {1570 .probe = sun4i_tcon_probe,1571 .remove_new = sun4i_tcon_remove,1572 .driver = {1573 .name = "sun4i-tcon",1574 .of_match_table = sun4i_tcon_of_table,1575 },1576};1577module_platform_driver(sun4i_tcon_platform_driver);1578 1579MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");1580MODULE_DESCRIPTION("Allwinner A10 Timing Controller Driver");1581MODULE_LICENSE("GPL");1582