From 6255eb30a186191734efc472c35d187fe5dcd101 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Sat, 29 Mar 2025 16:53:24 +0200 Subject: video: move tegra124 into common tegra dir Place Tegra124 SOR and eDP implenetation into common Tegra driver folder until it is integrated into existing setup. Signed-off-by: Svyatoslav Ryhel --- drivers/video/Kconfig | 8 - drivers/video/Makefile | 1 - drivers/video/tegra/Kconfig | 8 + drivers/video/tegra/Makefile | 2 + drivers/video/tegra/TODO | 5 + drivers/video/tegra/tegra124/Makefile | 8 + drivers/video/tegra/tegra124/display.c | 504 +++++++++ drivers/video/tegra/tegra124/displayport.h | 411 +++++++ drivers/video/tegra/tegra124/dp.c | 1624 ++++++++++++++++++++++++++++ drivers/video/tegra/tegra124/sor.c | 1083 +++++++++++++++++++ drivers/video/tegra/tegra124/sor.h | 914 ++++++++++++++++ drivers/video/tegra124/Makefile | 8 - drivers/video/tegra124/display.c | 504 --------- drivers/video/tegra124/displayport.h | 411 ------- drivers/video/tegra124/dp.c | 1624 ---------------------------- drivers/video/tegra124/sor.c | 1083 ------------------- drivers/video/tegra124/sor.h | 914 ---------------- 17 files changed, 4559 insertions(+), 4553 deletions(-) create mode 100644 drivers/video/tegra/TODO create mode 100644 drivers/video/tegra/tegra124/Makefile create mode 100644 drivers/video/tegra/tegra124/display.c create mode 100644 drivers/video/tegra/tegra124/displayport.h create mode 100644 drivers/video/tegra/tegra124/dp.c create mode 100644 drivers/video/tegra/tegra124/sor.c create mode 100644 drivers/video/tegra/tegra124/sor.h delete mode 100644 drivers/video/tegra124/Makefile delete mode 100644 drivers/video/tegra124/display.c delete mode 100644 drivers/video/tegra124/displayport.h delete mode 100644 drivers/video/tegra124/dp.c delete mode 100644 drivers/video/tegra124/sor.c delete mode 100644 drivers/video/tegra124/sor.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index afcdb16c599..d343dfb061b 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -809,14 +809,6 @@ source "drivers/video/stm32/Kconfig" source "drivers/video/tidss/Kconfig" -config VIDEO_TEGRA124 - bool "Enable video support on Tegra124" - help - Tegra124 supports many video output options including eDP and - HDMI. At present only eDP is supported by U-Boot. This option - enables this support which can be used on devices which - have an eDP display connected. - source "drivers/video/bridge/Kconfig" source "drivers/video/tegra/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index a4896c0dfce..74df5711d18 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -34,7 +34,6 @@ obj-$(CONFIG_BACKLIGHT_LP855x) += lp855x_backlight.o obj-${CONFIG_EXYNOS_FB} += exynos/ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/ obj-${CONFIG_VIDEO_STM32} += stm32/ -obj-${CONFIG_VIDEO_TEGRA124} += tegra124/ obj-${CONFIG_$(PHASE_)VIDEO_TIDSS} += tidss/ obj-y += ti/ diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig index 598f9ea1f21..3d610036a1f 100644 --- a/drivers/video/tegra/Kconfig +++ b/drivers/video/tegra/Kconfig @@ -36,3 +36,11 @@ config TEGRA_BACKLIGHT_PWM select VIDEO_TEGRA20 help Tegra DC dependent backlight. + +config VIDEO_TEGRA124 + bool "Enable video support on Tegra124" + help + Tegra124 supports many video output options including eDP and + HDMI. At present only eDP is supported by U-Boot. This option + enables this support which can be used on devices which + have an eDP display connected. diff --git a/drivers/video/tegra/Makefile b/drivers/video/tegra/Makefile index 78521405749..cd4cf72b3e5 100644 --- a/drivers/video/tegra/Makefile +++ b/drivers/video/tegra/Makefile @@ -5,3 +5,5 @@ obj-$(CONFIG_VIDEO_TEGRA20) += tegra-dc.o obj-$(CONFIG_VIDEO_DSI_TEGRA30) += tegra-dsi.o tegra-mipi.o mipi-phy.o obj-$(CONFIG_VIDEO_HDMI_TEGRA) += tegra-hdmi.o obj-$(CONFIG_TEGRA_BACKLIGHT_PWM) += tegra-pwm-backlight.o + +obj-${CONFIG_VIDEO_TEGRA124} += tegra124/ diff --git a/drivers/video/tegra/TODO b/drivers/video/tegra/TODO new file mode 100644 index 00000000000..1c8c2389a18 --- /dev/null +++ b/drivers/video/tegra/TODO @@ -0,0 +1,5 @@ +Existence of separate Tegra124 video implementations is not an ideal solution +since generic video setup for Tegra already has Tegra124 support of some degree. +It is not possible at the time of this note is written to integrate T124 SOR +and DP without possible regressions. Tegra124 setup for SOR and DP should be +incorporated into existing setup once such opportunity occurs. diff --git a/drivers/video/tegra/tegra124/Makefile b/drivers/video/tegra/tegra124/Makefile new file mode 100644 index 00000000000..a378382628c --- /dev/null +++ b/drivers/video/tegra/tegra124/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2014 Google, Inc +# + +obj-y += display.o +obj-y += dp.o +obj-y += sor.o diff --git a/drivers/video/tegra/tegra124/display.c b/drivers/video/tegra/tegra124/display.c new file mode 100644 index 00000000000..abe31e27d84 --- /dev/null +++ b/drivers/video/tegra/tegra124/display.c @@ -0,0 +1,504 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2014 Google Inc. + * + * Extracted from Chromium coreboot commit 3f59b13d + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "displayport.h" + +/* return in 1000ths of a Hertz */ +static int tegra_dc_calc_refresh(const struct display_timing *timing) +{ + int h_total, v_total, refresh; + int pclk = timing->pixelclock.typ; + + h_total = timing->hactive.typ + timing->hfront_porch.typ + + timing->hback_porch.typ + timing->hsync_len.typ; + v_total = timing->vactive.typ + timing->vfront_porch.typ + + timing->vback_porch.typ + timing->vsync_len.typ; + if (!pclk || !h_total || !v_total) + return 0; + refresh = pclk / h_total; + refresh *= 1000; + refresh /= v_total; + + return refresh; +} + +static void print_mode(const struct display_timing *timing) +{ + int refresh = tegra_dc_calc_refresh(timing); + + debug("MODE:%dx%d@%d.%03uHz pclk=%d\n", + timing->hactive.typ, timing->vactive.typ, refresh / 1000, + refresh % 1000, timing->pixelclock.typ); +} + +static int update_display_mode(struct dc_ctlr *disp_ctrl, + const struct display_timing *timing, + int href_to_sync, int vref_to_sync) +{ + print_mode(timing); + + writel(0x1, &disp_ctrl->disp.disp_timing_opt); + + writel(vref_to_sync << 16 | href_to_sync, + &disp_ctrl->disp.ref_to_sync); + + writel(timing->vsync_len.typ << 16 | timing->hsync_len.typ, + &disp_ctrl->disp.sync_width); + + writel(((timing->vback_porch.typ - vref_to_sync) << 16) | + timing->hback_porch.typ, &disp_ctrl->disp.back_porch); + + writel(((timing->vfront_porch.typ + vref_to_sync) << 16) | + timing->hfront_porch.typ, &disp_ctrl->disp.front_porch); + + writel(timing->hactive.typ | (timing->vactive.typ << 16), + &disp_ctrl->disp.disp_active); + + /** + * We want to use PLLD_out0, which is PLLD / 2: + * PixelClock = (PLLD / 2) / ShiftClockDiv / PixelClockDiv. + * + * Currently most panels work inside clock range 50MHz~100MHz, and PLLD + * has some requirements to have VCO in range 500MHz~1000MHz (see + * clock.c for more detail). To simplify calculation, we set + * PixelClockDiv to 1 and ShiftClockDiv to 1. In future these values + * may be calculated by clock_display, to allow wider frequency range. + * + * Note ShiftClockDiv is a 7.1 format value. + */ + const u32 shift_clock_div = 1; + writel((PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT) | + ((shift_clock_div - 1) * 2) << SHIFT_CLK_DIVIDER_SHIFT, + &disp_ctrl->disp.disp_clk_ctrl); + debug("%s: PixelClock=%u, ShiftClockDiv=%u\n", __func__, + timing->pixelclock.typ, shift_clock_div); + return 0; +} + +static u32 tegra_dc_poll_register(void *reg, + u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_us) +{ + u32 temp = timeout_us; + u32 reg_val = 0; + + do { + udelay(poll_interval_us); + reg_val = readl(reg); + if (timeout_us > poll_interval_us) + timeout_us -= poll_interval_us; + else + break; + } while ((reg_val & mask) != exp_val); + + if ((reg_val & mask) == exp_val) + return 0; /* success */ + + return temp; +} + +int tegra_dc_sor_general_act(struct dc_ctlr *disp_ctrl) +{ + writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl); + + if (tegra_dc_poll_register(&disp_ctrl->cmd.state_ctrl, + GENERAL_ACT_REQ, 0, 100, + DC_POLL_TIMEOUT_MS * 1000)) { + debug("dc timeout waiting for DC to stop\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static struct display_timing min_mode = { + .hsync_len = { .typ = 1 }, + .vsync_len = { .typ = 1 }, + .hback_porch = { .typ = 20 }, + .vback_porch = { .typ = 0 }, + .hactive = { .typ = 16 }, + .vactive = { .typ = 16 }, + .hfront_porch = { .typ = 1 }, + .vfront_porch = { .typ = 2 }, +}; + +/* Disable windows and set minimum raster timings */ +void tegra_dc_sor_disable_win_short_raster(struct dc_ctlr *disp_ctrl, + int *dc_reg_ctx) +{ + const int href_to_sync = 0, vref_to_sync = 1; + int selected_windows, i; + + selected_windows = readl(&disp_ctrl->cmd.disp_win_header); + + /* Store and clear window options */ + for (i = 0; i < DC_N_WINDOWS; ++i) { + writel(WINDOW_A_SELECT << i, &disp_ctrl->cmd.disp_win_header); + dc_reg_ctx[i] = readl(&disp_ctrl->win.win_opt); + writel(0, &disp_ctrl->win.win_opt); + writel(WIN_A_ACT_REQ << i, &disp_ctrl->cmd.state_ctrl); + } + + writel(selected_windows, &disp_ctrl->cmd.disp_win_header); + + /* Store current raster timings and set minimum timings */ + dc_reg_ctx[i++] = readl(&disp_ctrl->disp.ref_to_sync); + writel(href_to_sync | (vref_to_sync << 16), + &disp_ctrl->disp.ref_to_sync); + + dc_reg_ctx[i++] = readl(&disp_ctrl->disp.sync_width); + writel(min_mode.hsync_len.typ | (min_mode.vsync_len.typ << 16), + &disp_ctrl->disp.sync_width); + + dc_reg_ctx[i++] = readl(&disp_ctrl->disp.back_porch); + writel(min_mode.hback_porch.typ | (min_mode.vback_porch.typ << 16), + &disp_ctrl->disp.back_porch); + + dc_reg_ctx[i++] = readl(&disp_ctrl->disp.front_porch); + writel(min_mode.hfront_porch.typ | (min_mode.vfront_porch.typ << 16), + &disp_ctrl->disp.front_porch); + + dc_reg_ctx[i++] = readl(&disp_ctrl->disp.disp_active); + writel(min_mode.hactive.typ | (min_mode.vactive.typ << 16), + &disp_ctrl->disp.disp_active); + + writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl); +} + +/* Restore previous windows status and raster timings */ +void tegra_dc_sor_restore_win_and_raster(struct dc_ctlr *disp_ctrl, + int *dc_reg_ctx) +{ + int selected_windows, i; + + selected_windows = readl(&disp_ctrl->cmd.disp_win_header); + + for (i = 0; i < DC_N_WINDOWS; ++i) { + writel(WINDOW_A_SELECT << i, &disp_ctrl->cmd.disp_win_header); + writel(dc_reg_ctx[i], &disp_ctrl->win.win_opt); + writel(WIN_A_ACT_REQ << i, &disp_ctrl->cmd.state_ctrl); + } + + writel(selected_windows, &disp_ctrl->cmd.disp_win_header); + + writel(dc_reg_ctx[i++], &disp_ctrl->disp.ref_to_sync); + writel(dc_reg_ctx[i++], &disp_ctrl->disp.sync_width); + writel(dc_reg_ctx[i++], &disp_ctrl->disp.back_porch); + writel(dc_reg_ctx[i++], &disp_ctrl->disp.front_porch); + writel(dc_reg_ctx[i++], &disp_ctrl->disp.disp_active); + + writel(GENERAL_UPDATE, &disp_ctrl->cmd.state_ctrl); +} + +static int tegra_depth_for_bpp(int bpp) +{ + switch (bpp) { + case 32: + return COLOR_DEPTH_R8G8B8A8; + case 16: + return COLOR_DEPTH_B5G6R5; + default: + debug("Unsupported LCD bit depth"); + return -1; + } +} + +static int update_window(struct dc_ctlr *disp_ctrl, + u32 frame_buffer, int fb_bits_per_pixel, + const struct display_timing *timing) +{ + const u32 colour_white = 0xffffff; + int colour_depth; + u32 val; + + writel(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header); + + writel(((timing->vactive.typ << 16) | timing->hactive.typ), + &disp_ctrl->win.size); + writel(((timing->vactive.typ << 16) | + (timing->hactive.typ * fb_bits_per_pixel / 8)), + &disp_ctrl->win.prescaled_size); + writel(((timing->hactive.typ * fb_bits_per_pixel / 8 + 31) / + 32 * 32), &disp_ctrl->win.line_stride); + + colour_depth = tegra_depth_for_bpp(fb_bits_per_pixel); + if (colour_depth == -1) + return -EINVAL; + + writel(colour_depth, &disp_ctrl->win.color_depth); + + writel(frame_buffer, &disp_ctrl->winbuf.start_addr); + writel(0x1000 << V_DDA_INC_SHIFT | 0x1000 << H_DDA_INC_SHIFT, + &disp_ctrl->win.dda_increment); + + writel(colour_white, &disp_ctrl->disp.blend_background_color); + writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT, + &disp_ctrl->cmd.disp_cmd); + + writel(WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access); + + val = GENERAL_ACT_REQ | WIN_A_ACT_REQ; + val |= GENERAL_UPDATE | WIN_A_UPDATE; + writel(val, &disp_ctrl->cmd.state_ctrl); + + /* Enable win_a */ + val = readl(&disp_ctrl->win.win_opt); + writel(val | WIN_ENABLE, &disp_ctrl->win.win_opt); + + return 0; +} + +static int tegra_dc_init(struct dc_ctlr *disp_ctrl) +{ + /* do not accept interrupts during initialization */ + writel(0x00000000, &disp_ctrl->cmd.int_mask); + writel(WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, + &disp_ctrl->cmd.state_access); + writel(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header); + writel(0x00000000, &disp_ctrl->win.win_opt); + writel(0x00000000, &disp_ctrl->win.byte_swap); + writel(0x00000000, &disp_ctrl->win.buffer_ctrl); + + writel(0x00000000, &disp_ctrl->win.pos); + writel(0x00000000, &disp_ctrl->win.h_initial_dda); + writel(0x00000000, &disp_ctrl->win.v_initial_dda); + writel(0x00000000, &disp_ctrl->win.dda_increment); + writel(0x00000000, &disp_ctrl->win.dv_ctrl); + + writel(0x01000000, &disp_ctrl->win.blend_layer_ctrl); + writel(0x00000000, &disp_ctrl->win.blend_match_select); + writel(0x00000000, &disp_ctrl->win.blend_nomatch_select); + writel(0x00000000, &disp_ctrl->win.blend_alpha_1bit); + + writel(0x00000000, &disp_ctrl->winbuf.start_addr_hi); + writel(0x00000000, &disp_ctrl->winbuf.addr_h_offset); + writel(0x00000000, &disp_ctrl->winbuf.addr_v_offset); + + writel(0x00000000, &disp_ctrl->com.crc_checksum); + writel(0x00000000, &disp_ctrl->com.pin_output_enb[0]); + writel(0x00000000, &disp_ctrl->com.pin_output_enb[1]); + writel(0x00000000, &disp_ctrl->com.pin_output_enb[2]); + writel(0x00000000, &disp_ctrl->com.pin_output_enb[3]); + writel(0x00000000, &disp_ctrl->disp.disp_signal_opt0); + + return 0; +} + +static void dump_config(int panel_bpp, struct display_timing *timing) +{ + printf("timing->hactive.typ = %d\n", timing->hactive.typ); + printf("timing->vactive.typ = %d\n", timing->vactive.typ); + printf("timing->pixelclock.typ = %d\n", timing->pixelclock.typ); + + printf("timing->hfront_porch.typ = %d\n", timing->hfront_porch.typ); + printf("timing->hsync_len.typ = %d\n", timing->hsync_len.typ); + printf("timing->hback_porch.typ = %d\n", timing->hback_porch.typ); + + printf("timing->vfront_porch.typ %d\n", timing->vfront_porch.typ); + printf("timing->vsync_len.typ = %d\n", timing->vsync_len.typ); + printf("timing->vback_porch.typ = %d\n", timing->vback_porch.typ); + + printf("panel_bits_per_pixel = %d\n", panel_bpp); +} + +static int display_update_config_from_edid(struct udevice *dp_dev, + int *panel_bppp, + struct display_timing *timing) +{ + return display_read_timing(dp_dev, timing); +} + +static int display_init(struct udevice *dev, void *lcdbase, + int fb_bits_per_pixel, struct display_timing *timing) +{ + struct display_plat *disp_uc_plat; + struct dc_ctlr *dc_ctlr; + struct udevice *dp_dev; + const int href_to_sync = 1, vref_to_sync = 1; + int panel_bpp = 18; /* default 18 bits per pixel */ + u32 plld_rate; + int ret; + + /* + * Before we probe the display device (eDP), tell it that this device + * is the source of the display data. + */ + ret = uclass_find_first_device(UCLASS_DISPLAY, &dp_dev); + if (ret) { + debug("%s: device '%s' display not found (ret=%d)\n", __func__, + dev->name, ret); + return ret; + } + + disp_uc_plat = dev_get_uclass_plat(dp_dev); + debug("Found device '%s', disp_uc_priv=%p\n", dp_dev->name, + disp_uc_plat); + disp_uc_plat->src_dev = dev; + + ret = uclass_get_device(UCLASS_DISPLAY, 0, &dp_dev); + if (ret) { + debug("%s: Failed to probe eDP, ret=%d\n", __func__, ret); + return ret; + } + + dc_ctlr = dev_read_addr_ptr(dev); + if (ofnode_decode_display_timing(dev_ofnode(dev), 0, timing)) { + debug("%s: Failed to decode display timing\n", __func__); + return -EINVAL; + } + + ret = display_update_config_from_edid(dp_dev, &panel_bpp, timing); + if (ret) { + debug("%s: Failed to decode EDID, using defaults\n", __func__); + dump_config(panel_bpp, timing); + } + + /* + * The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER + * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the + * update_display_mode() for detail. + */ + plld_rate = clock_set_display_rate(timing->pixelclock.typ * 2); + if (plld_rate == 0) { + printf("dc: clock init failed\n"); + return -EIO; + } else if (plld_rate != timing->pixelclock.typ * 2) { + debug("dc: plld rounded to %u\n", plld_rate); + timing->pixelclock.typ = plld_rate / 2; + } + + /* Init dc */ + ret = tegra_dc_init(dc_ctlr); + if (ret) { + debug("dc: init failed\n"); + return ret; + } + + /* Configure dc mode */ + ret = update_display_mode(dc_ctlr, timing, href_to_sync, vref_to_sync); + if (ret) { + debug("dc: failed to configure display mode\n"); + return ret; + } + + /* Enable dp */ + ret = display_enable(dp_dev, panel_bpp, timing); + if (ret) { + debug("dc: failed to enable display: ret=%d\n", ret); + return ret; + } + + ret = update_window(dc_ctlr, (ulong)lcdbase, fb_bits_per_pixel, timing); + if (ret) { + debug("dc: failed to update window\n"); + return ret; + } + debug("%s: ready\n", __func__); + + return 0; +} + +enum { + /* Maximum LCD size we support */ + LCD_MAX_WIDTH = 1920, + LCD_MAX_HEIGHT = 1200, + LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ +}; + +static int tegra124_lcd_init(struct udevice *dev, void *lcdbase, + enum video_log2_bpp l2bpp) +{ + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct display_timing timing; + int ret; + + clock_set_up_plldp(); + clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, 408000000); + + clock_enable(PERIPH_ID_HOST1X); + clock_enable(PERIPH_ID_DISP1); + clock_enable(PERIPH_ID_PWM); + clock_enable(PERIPH_ID_DPAUX); + clock_enable(PERIPH_ID_SOR0); + udelay(2); + + reset_set_enable(PERIPH_ID_HOST1X, 0); + reset_set_enable(PERIPH_ID_DISP1, 0); + reset_set_enable(PERIPH_ID_PWM, 0); + reset_set_enable(PERIPH_ID_DPAUX, 0); + reset_set_enable(PERIPH_ID_SOR0, 0); + + ret = display_init(dev, lcdbase, 1 << l2bpp, &timing); + if (ret) + return ret; + + uc_priv->xsize = roundup(timing.hactive.typ, 16); + uc_priv->ysize = timing.vactive.typ; + uc_priv->bpix = l2bpp; + + video_set_flush_dcache(dev, 1); + debug("%s: done\n", __func__); + + return 0; +} + +static int tegra124_lcd_probe(struct udevice *dev) +{ + struct video_uc_plat *plat = dev_get_uclass_plat(dev); + ulong start; + int ret; + + start = get_timer(0); + bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "lcd"); + ret = tegra124_lcd_init(dev, (void *)plat->base, VIDEO_BPP16); + bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD); + debug("LCD init took %lu ms\n", get_timer(start)); + if (ret) + printf("%s: Error %d\n", __func__, ret); + + return 0; +} + +static int tegra124_lcd_bind(struct udevice *dev) +{ + struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev); + + uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * + (1 << VIDEO_BPP16) / 8; + debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); + + return 0; +} + +static const struct udevice_id tegra124_lcd_ids[] = { + { .compatible = "nvidia,tegra124-dc" }, + { } +}; + +U_BOOT_DRIVER(tegra124_dc) = { + .name = "tegra124-dc", + .id = UCLASS_VIDEO, + .of_match = tegra124_lcd_ids, + .bind = tegra124_lcd_bind, + .probe = tegra124_lcd_probe, +}; diff --git a/drivers/video/tegra/tegra124/displayport.h b/drivers/video/tegra/tegra124/displayport.h new file mode 100644 index 00000000000..a3044475aeb --- /dev/null +++ b/drivers/video/tegra/tegra124/displayport.h @@ -0,0 +1,411 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2014, NVIDIA Corporation. + */ + +#ifndef _TEGRA_DISPLAYPORT_H +#define _TEGRA_DISPLAYPORT_H + +#include + +struct dpaux_ctlr { + u32 reserved0; + u32 intr_en_aux; + u32 reserved2_4; + u32 intr_aux; +}; + +#define DPAUX_INTR_EN_AUX 0x1 +#define DPAUX_INTR_AUX 0x5 +#define DPAUX_DP_AUXDATA_WRITE_W(i) (0x9 + 4 * (i)) +#define DPAUX_DP_AUXDATA_READ_W(i) (0x19 + 4 * (i)) +#define DPAUX_DP_AUXADDR 0x29 +#define DPAUX_DP_AUXCTL 0x2d +#define DPAUX_DP_AUXCTL_CMDLEN_SHIFT 0 +#define DPAUX_DP_AUXCTL_CMDLEN_FIELD 0xff +#define DPAUX_DP_AUXCTL_CMD_SHIFT 12 +#define DPAUX_DP_AUXCTL_CMD_MASK (0xf << 12) +#define DPAUX_DP_AUXCTL_CMD_I2CWR (0 << 12) +#define DPAUX_DP_AUXCTL_CMD_I2CRD (1 << 12) +#define DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT (2 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOTWR (4 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOTRD (5 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOTREQWSTAT (6 << 12) +#define DPAUX_DP_AUXCTL_CMD_AUXWR (8 << 12) +#define DPAUX_DP_AUXCTL_CMD_AUXRD (9 << 12) +#define DPAUX_DP_AUXCTL_TRANSACTREQ_SHIFT 16 +#define DPAUX_DP_AUXCTL_TRANSACTREQ_MASK (0x1 << 16) +#define DPAUX_DP_AUXCTL_TRANSACTREQ_DONE (0 << 16) +#define DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING (1 << 16) +#define DPAUX_DP_AUXCTL_RST_SHIFT 31 +#define DPAUX_DP_AUXCTL_RST_DEASSERT (0 << 31) +#define DPAUX_DP_AUXCTL_RST_ASSERT (1 << 31) +#define DPAUX_DP_AUXSTAT 0x31 +#define DPAUX_DP_AUXSTAT_HPD_STATUS_SHIFT 28 +#define DPAUX_DP_AUXSTAT_HPD_STATUS_UNPLUG (0 << 28) +#define DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED (1 << 28) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_SHIFT 20 +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_MASK (0xf << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_IDLE (0 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_SYNC (1 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_START1 (2 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_COMMAND (3 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_ADDRESS (4 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_LENGTH (5 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_WRITE1 (6 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_READ1 (7 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_GET_M (8 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_STOP1 (9 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_STOP2 (10 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_REPLY (11 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_CLEANUP (12 << 20) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_SHIFT 16 +#define DPAUX_DP_AUXSTAT_REPLYTYPE_MASK (0xf << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_ACK (0 << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_NACK (1 << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER (2 << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_I2CNACK (4 << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER (8 << 16) +#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_SHIFT 11 +#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_NOT_PENDING (0 << 11) +#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING (1 << 11) +#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_SHIFT 10 +#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_NOT_PENDING (0 << 10) +#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING (1 << 10) +#define DPAUX_DP_AUXSTAT_RX_ERROR_SHIFT 9 +#define DPAUX_DP_AUXSTAT_RX_ERROR_NOT_PENDING (0 << 9) +#define DPAUX_DP_AUXSTAT_RX_ERROR_PENDING (1 << 9) +#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_SHIFT 8 +#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_NOT_PENDING (0 << 8) +#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING (1 << 8) +#define DPAUX_DP_AUXSTAT_REPLY_M_SHIFT 0 +#define DPAUX_DP_AUXSTAT_REPLY_M_MASK (0xff << 0) +#define DPAUX_HPD_CONFIG (0x3d) +#define DPAUX_HPD_IRQ_CONFIG 0x41 +#define DPAUX_DP_AUX_CONFIG 0x45 +#define DPAUX_HYBRID_PADCTL 0x49 +#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_SHIFT 15 +#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_DISABLE (0 << 15) +#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_ENABLE (1 << 15) +#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_SHIFT 14 +#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_DISABLE (0 << 14) +#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_ENABLE (1 << 14) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_SHIFT 12 +#define DPAUX_HYBRID_PADCTL_AUX_CMH_DEFAULT_MASK (0x3 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_60 (0 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_64 (1 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 (2 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_56 (3 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_SHIFT 8 +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_DEFAULT_MASK (0x7 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_78 (0 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_60 (1 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_54 (2 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_45 (3 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 (4 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_42 (5 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_39 (6 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_34 (7 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT 2 +#define DPAUX_HYBRID_PADCTL_AUX_DRVI_DEFAULT_MASK (0x3f << 2) +#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_SHIFT 1 +#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_DISABLE (0 << 1) +#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE (1 << 1) +#define DPAUX_HYBRID_PADCTL_MODE_SHIFT 0 +#define DPAUX_HYBRID_PADCTL_MODE_AUX 0 +#define DPAUX_HYBRID_PADCTL_MODE_I2C 1 +#define DPAUX_HYBRID_SPARE 0x4d +#define DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP 0 +#define DPAUX_HYBRID_SPARE_PAD_PWR_POWERDOWN 1 + +#define DP_AUX_DEFER_MAX_TRIES 7 +#define DP_AUX_TIMEOUT_MAX_TRIES 2 +#define DP_POWER_ON_MAX_TRIES 3 + +#define DP_AUX_MAX_BYTES 16 + +#define DP_AUX_TIMEOUT_MS 40 +#define DP_DPCP_RETRY_SLEEP_NS 400 + +static const u32 tegra_dp_vs_regs[][4][4] = { + /* postcursor2 L0 */ + { + /* pre-emphasis: L0, L1, L2, L3 */ + {0x13, 0x19, 0x1e, 0x28}, /* voltage swing: L0 */ + {0x1e, 0x25, 0x2d}, /* L1 */ + {0x28, 0x32}, /* L2 */ + {0x3c}, /* L3 */ + }, + + /* postcursor2 L1 */ + { + {0x12, 0x17, 0x1b, 0x25}, + {0x1c, 0x23, 0x2a}, + {0x25, 0x2f}, + {0x39}, + }, + + /* postcursor2 L2 */ + { + {0x12, 0x16, 0x1a, 0x22}, + {0x1b, 0x20, 0x27}, + {0x24, 0x2d}, + {0x36}, + }, + + /* postcursor2 L3 */ + { + {0x11, 0x14, 0x17, 0x1f}, + {0x19, 0x1e, 0x24}, + {0x22, 0x2a}, + {0x32}, + }, +}; + +static const u32 tegra_dp_pe_regs[][4][4] = { + /* postcursor2 L0 */ + { + /* pre-emphasis: L0, L1, L2, L3 */ + {0x00, 0x09, 0x13, 0x25}, /* voltage swing: L0 */ + {0x00, 0x0f, 0x1e}, /* L1 */ + {0x00, 0x14}, /* L2 */ + {0x00}, /* L3 */ + }, + + /* postcursor2 L1 */ + { + {0x00, 0x0a, 0x14, 0x28}, + {0x00, 0x0f, 0x1e}, + {0x00, 0x14}, + {0x00}, + }, + + /* postcursor2 L2 */ + { + {0x00, 0x0a, 0x14, 0x28}, + {0x00, 0x0f, 0x1e}, + {0x00, 0x14}, + {0x00}, + }, + + /* postcursor2 L3 */ + { + {0x00, 0x0a, 0x14, 0x28}, + {0x00, 0x0f, 0x1e}, + {0x00, 0x14}, + {0x00}, + }, +}; + +static const u32 tegra_dp_pc_regs[][4][4] = { + /* postcursor2 L0 */ + { + /* pre-emphasis: L0, L1, L2, L3 */ + {0x00, 0x00, 0x00, 0x00}, /* voltage swing: L0 */ + {0x00, 0x00, 0x00}, /* L1 */ + {0x00, 0x00}, /* L2 */ + {0x00}, /* L3 */ + }, + + /* postcursor2 L1 */ + { + {0x02, 0x02, 0x04, 0x05}, + {0x02, 0x04, 0x05}, + {0x04, 0x05}, + {0x05}, + }, + + /* postcursor2 L2 */ + { + {0x04, 0x05, 0x08, 0x0b}, + {0x05, 0x09, 0x0b}, + {0x08, 0x0a}, + {0x0b}, + }, + + /* postcursor2 L3 */ + { + {0x05, 0x09, 0x0b, 0x12}, + {0x09, 0x0d, 0x12}, + {0x0b, 0x0f}, + {0x12}, + }, +}; + +static const u32 tegra_dp_tx_pu[][4][4] = { + /* postcursor2 L0 */ + { + /* pre-emphasis: L0, L1, L2, L3 */ + {0x20, 0x30, 0x40, 0x60}, /* voltage swing: L0 */ + {0x30, 0x40, 0x60}, /* L1 */ + {0x40, 0x60}, /* L2 */ + {0x60}, /* L3 */ + }, + + /* postcursor2 L1 */ + { + {0x20, 0x20, 0x30, 0x50}, + {0x30, 0x40, 0x50}, + {0x40, 0x50}, + {0x60}, + }, + + /* postcursor2 L2 */ + { + {0x20, 0x20, 0x30, 0x40}, + {0x30, 0x30, 0x40}, + {0x40, 0x50}, + {0x60}, + }, + + /* postcursor2 L3 */ + { + {0x20, 0x20, 0x20, 0x40}, + {0x30, 0x30, 0x40}, + {0x40, 0x40}, + {0x60}, + }, +}; + +enum { + DRIVECURRENT_LEVEL0 = 0, + DRIVECURRENT_LEVEL1 = 1, + DRIVECURRENT_LEVEL2 = 2, + DRIVECURRENT_LEVEL3 = 3, +}; + +enum { + PREEMPHASIS_DISABLED = 0, + PREEMPHASIS_LEVEL1 = 1, + PREEMPHASIS_LEVEL2 = 2, + PREEMPHASIS_LEVEL3 = 3, +}; + +enum { + POSTCURSOR2_LEVEL0 = 0, + POSTCURSOR2_LEVEL1 = 1, + POSTCURSOR2_LEVEL2 = 2, + POSTCURSOR2_LEVEL3 = 3, + POSTCURSOR2_SUPPORTED +}; + +static inline int tegra_dp_is_max_vs(u32 pe, u32 vs) +{ + return (vs < (DRIVECURRENT_LEVEL3 - pe)) ? 0 : 1; +} + +static inline int tegra_dp_is_max_pe(u32 pe, u32 vs) +{ + return (pe < (PREEMPHASIS_LEVEL3 - vs)) ? 0 : 1; +} + +static inline int tegra_dp_is_max_pc(u32 pc) +{ + return (pc < POSTCURSOR2_LEVEL3) ? 0 : 1; +} + +/* DPCD definitions which are not defined in drm_dp_helper.h */ +#define DP_DPCD_REV_MAJOR_SHIFT 4 +#define DP_DPCD_REV_MAJOR_MASK (0xf << 4) +#define DP_DPCD_REV_MINOR_SHIFT 0 +#define DP_DPCD_REV_MINOR_MASK 0xf + +#define DP_MAX_LINK_RATE_VAL_1_62_GPBS 0x6 +#define DP_MAX_LINK_RATE_VAL_2_70_GPBS 0xa +#define DP_MAX_LINK_RATE_VAL_5_40_GPBS 0x4 + +#define DP_MAX_LANE_COUNT_LANE_1 0x1 +#define DP_MAX_LANE_COUNT_LANE_2 0x2 +#define DP_MAX_LANE_COUNT_LANE_4 0x4 +#define DP_MAX_LANE_COUNT_TPS3_SUPPORTED_YES (1 << 6) +#define DP_MAX_LANE_COUNT_ENHANCED_FRAMING_YES (1 << 7) + +#define NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT 0 +#define NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T (0x00000001 << 2) +#define NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_F (0x00000000 << 2) +#define NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT 3 +#define NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T (0x00000001 << 5) +#define NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_F (0x00000000 << 5) + +#define DP_MAX_DOWNSPREAD_VAL_NONE 0 +#define DP_MAX_DOWNSPREAD_VAL_0_5_PCT 1 +#define DP_MAX_DOWNSPREAD_NO_AUX_HANDSHAKE_LT_T (1 << 6) + +#define DP_EDP_CONFIGURATION_CAP_ASC_RESET_YES 1 +#define DP_EDP_CONFIGURATION_CAP_FRAMING_CHANGE_YES (1 << 1) + +#define DP_LANE_COUNT_SET_ENHANCEDFRAMING_T (1 << 7) + +#define DP_TRAINING_PATTERN_SET_SC_DISABLED_T (1 << 5) +#define NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_F (0x00000000 << 5) +#define NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_T (0x00000001 << 5) + +#define DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_DISABLE 0 +#define DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_ENABLE 1 + +#define NV_DPCD_TRAINING_LANE0_1_SET2 0x10f +#define NV_DPCD_TRAINING_LANE2_3_SET2 0x110 +#define NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T (1 << 2) +#define NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_F (0 << 2) +#define NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T (1 << 6) +#define NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_F (0 << 6) +#define NV_DPCD_LANEX_SET2_PC2_SHIFT 0 +#define NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT 4 + +#define NV_DPCD_STATUS_LANEX_CR_DONE_SHIFT 0 +#define NV_DPCD_STATUS_LANEX_CR_DONE_NO (0x00000000) +#define NV_DPCD_STATUS_LANEX_CR_DONE_YES (0x00000001) +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT 1 +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_NO (0x00000000 << 1) +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES (0x00000001 << 1) +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT 2 +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_NO (0x00000000 << 2) +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES (0x00000001 << 2) +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_SHIFT 4 +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_NO (0x00000000 << 4) +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES (0x00000001 << 4) +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT 5 +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_NO (0x00000000 << 5) +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES (0x00000001 << 5) +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT 6 +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_NO (0x00000000 << 6) +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES (0x00000001 << 6) + +#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED (0x00000204) +#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_NO (0x00000000) +#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES (0x00000001) + +#define NV_DPCD_STATUS_LANEX_CR_DONE_SHIFT 0 +#define NV_DPCD_STATUS_LANEX_CR_DONE_NO (0x00000000) +#define NV_DPCD_STATUS_LANEX_CR_DONE_YES (0x00000001) +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT 1 +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_NO (0x00000000 << 1) +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES (0x00000001 << 1) +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT 2 +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_NO (0x00000000 << 2) +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES (0x00000001 << 2) +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_SHIFT 4 +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_NO (0x00000000 << 4) +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES (0x00000001 << 4) +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT 5 +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_NO (0x00000000 << 5) +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES (0x00000001 << 5) +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT 6 +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_NO (0x00000000 << 6) +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES (0x00000001 << 6) + +#define NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT 0 +#define NV_DPCD_ADJUST_REQ_LANEX_DC_MASK 0x3 +#define NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT 2 +#define NV_DPCD_ADJUST_REQ_LANEX_PE_MASK (0x3 << 2) +#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT 4 +#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK (0x3 << 4) +#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT 6 +#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK (0x3 << 6) +#define NV_DPCD_ADJUST_REQ_POST_CURSOR2 (0x0000020C) +#define NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK 0x3 +#define NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(i) (i*2) + +#define NV_DPCD_TRAINING_AUX_RD_INTERVAL (0x0000000E) +#define NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_F (0x00000000 << 2) +#endif diff --git a/drivers/video/tegra/tegra124/dp.c b/drivers/video/tegra/tegra124/dp.c new file mode 100644 index 00000000000..b95b14da77d --- /dev/null +++ b/drivers/video/tegra/tegra124/dp.c @@ -0,0 +1,1624 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2011-2013, NVIDIA Corporation. + * Copyright 2014 Google Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "display.h" +#include "edid.h" +#include "sor.h" +#include "displayport.h" + +#define DO_FAST_LINK_TRAINING 1 + +struct tegra_dp_plat { + ulong base; +}; + +/** + * struct tegra_dp_priv - private displayport driver info + * + * @dc_dev: Display controller device that is sending the video feed + */ +struct tegra_dp_priv { + struct udevice *sor; + struct udevice *dc_dev; + struct dpaux_ctlr *regs; + u8 revision; + int enabled; +}; + +struct tegra_dp_priv dp_data; + +static inline u32 tegra_dpaux_readl(struct tegra_dp_priv *dp, u32 reg) +{ + return readl((u32 *)dp->regs + reg); +} + +static inline void tegra_dpaux_writel(struct tegra_dp_priv *dp, u32 reg, + u32 val) +{ + writel(val, (u32 *)dp->regs + reg); +} + +static inline u32 tegra_dc_dpaux_poll_register(struct tegra_dp_priv *dp, + u32 reg, u32 mask, u32 exp_val, + u32 poll_interval_us, + u32 timeout_us) +{ + u32 reg_val = 0; + u32 temp = timeout_us; + + do { + udelay(poll_interval_us); + reg_val = tegra_dpaux_readl(dp, reg); + if (timeout_us > poll_interval_us) + timeout_us -= poll_interval_us; + else + break; + } while ((reg_val & mask) != exp_val); + + if ((reg_val & mask) == exp_val) + return 0; /* success */ + debug("dpaux_poll_register 0x%x: timeout: (reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n", + reg, reg_val, mask, exp_val); + return temp; +} + +static inline int tegra_dpaux_wait_transaction(struct tegra_dp_priv *dp) +{ + /* According to DP spec, each aux transaction needs to finish + within 40ms. */ + if (tegra_dc_dpaux_poll_register(dp, DPAUX_DP_AUXCTL, + DPAUX_DP_AUXCTL_TRANSACTREQ_MASK, + DPAUX_DP_AUXCTL_TRANSACTREQ_DONE, + 100, DP_AUX_TIMEOUT_MS * 1000) != 0) { + debug("dp: DPAUX transaction timeout\n"); + return -1; + } + return 0; +} + +static int tegra_dc_dpaux_write_chunk(struct tegra_dp_priv *dp, u32 cmd, + u32 addr, u8 *data, u32 *size, + u32 *aux_stat) +{ + int i; + u32 reg_val; + u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; + u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; + u32 temp_data; + + if (*size > DP_AUX_MAX_BYTES) + return -1; /* only write one chunk of data */ + + /* Make sure the command is write command */ + switch (cmd) { + case DPAUX_DP_AUXCTL_CMD_I2CWR: + case DPAUX_DP_AUXCTL_CMD_MOTWR: + case DPAUX_DP_AUXCTL_CMD_AUXWR: + break; + default: + debug("dp: aux write cmd 0x%x is invalid\n", cmd); + return -EINVAL; + } + + tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); + for (i = 0; i < DP_AUX_MAX_BYTES / 4; ++i) { + memcpy(&temp_data, data, 4); + tegra_dpaux_writel(dp, DPAUX_DP_AUXDATA_WRITE_W(i), temp_data); + data += 4; + } + + reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); + reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; + reg_val |= cmd; + reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; + reg_val |= ((*size - 1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); + + while ((timeout_retries > 0) && (defer_retries > 0)) { + if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) || + (defer_retries != DP_AUX_DEFER_MAX_TRIES)) + udelay(1); + + reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING; + tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val); + + if (tegra_dpaux_wait_transaction(dp)) + debug("dp: aux write transaction timeout\n"); + + *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); + + if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) { + if (timeout_retries-- > 0) { + debug("dp: aux write retry (0x%x) -- %d\n", + *aux_stat, timeout_retries); + /* clear the error bits */ + tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, + *aux_stat); + continue; + } else { + debug("dp: aux write got error (0x%x)\n", + *aux_stat); + return -ETIMEDOUT; + } + } + + if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) || + (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) { + if (defer_retries-- > 0) { + debug("dp: aux write defer (0x%x) -- %d\n", + *aux_stat, defer_retries); + /* clear the error bits */ + tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, + *aux_stat); + continue; + } else { + debug("dp: aux write defer exceeds max retries (0x%x)\n", + *aux_stat); + return -ETIMEDOUT; + } + } + + if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) == + DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) { + *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK); + return 0; + } else { + debug("dp: aux write failed (0x%x)\n", *aux_stat); + return -EIO; + } + } + /* Should never come to here */ + return -EIO; +} + +static int tegra_dc_dpaux_read_chunk(struct tegra_dp_priv *dp, u32 cmd, + u32 addr, u8 *data, u32 *size, + u32 *aux_stat) +{ + u32 reg_val; + u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; + u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; + + if (*size > DP_AUX_MAX_BYTES) { + debug("only read one chunk\n"); + return -EIO; /* only read one chunk */ + } + + /* Check to make sure the command is read command */ + switch (cmd) { + case DPAUX_DP_AUXCTL_CMD_I2CRD: + case DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT: + case DPAUX_DP_AUXCTL_CMD_MOTRD: + case DPAUX_DP_AUXCTL_CMD_AUXRD: + break; + default: + debug("dp: aux read cmd 0x%x is invalid\n", cmd); + return -EIO; + } + + *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); + if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { + debug("dp: HPD is not detected\n"); + return -EIO; + } + + tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); + + reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); + reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; + reg_val |= cmd; + reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; + reg_val |= ((*size - 1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); + while ((timeout_retries > 0) && (defer_retries > 0)) { + if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) || + (defer_retries != DP_AUX_DEFER_MAX_TRIES)) + udelay(DP_DPCP_RETRY_SLEEP_NS * 2); + + reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING; + tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val); + + if (tegra_dpaux_wait_transaction(dp)) + debug("dp: aux read transaction timeout\n"); + + *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); + + if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) { + if (timeout_retries-- > 0) { + debug("dp: aux read retry (0x%x) -- %d\n", + *aux_stat, timeout_retries); + /* clear the error bits */ + tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, + *aux_stat); + continue; /* retry */ + } else { + debug("dp: aux read got error (0x%x)\n", + *aux_stat); + return -ETIMEDOUT; + } + } + + if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) || + (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) { + if (defer_retries-- > 0) { + debug("dp: aux read defer (0x%x) -- %d\n", + *aux_stat, defer_retries); + /* clear the error bits */ + tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, + *aux_stat); + continue; + } else { + debug("dp: aux read defer exceeds max retries (0x%x)\n", + *aux_stat); + return -ETIMEDOUT; + } + } + + if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) == + DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) { + int i; + u32 temp_data[4]; + + for (i = 0; i < DP_AUX_MAX_BYTES / 4; ++i) + temp_data[i] = tegra_dpaux_readl(dp, + DPAUX_DP_AUXDATA_READ_W(i)); + + *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK); + memcpy(data, temp_data, *size); + + return 0; + } else { + debug("dp: aux read failed (0x%x\n", *aux_stat); + return -EIO; + } + } + /* Should never come to here */ + debug("%s: can't\n", __func__); + + return -EIO; +} + +static int tegra_dc_dpaux_read(struct tegra_dp_priv *dp, u32 cmd, u32 addr, + u8 *data, u32 *size, u32 *aux_stat) +{ + u32 finished = 0; + u32 cur_size; + int ret = 0; + + do { + cur_size = *size - finished; + if (cur_size > DP_AUX_MAX_BYTES) + cur_size = DP_AUX_MAX_BYTES; + + ret = tegra_dc_dpaux_read_chunk(dp, cmd, addr, + data, &cur_size, aux_stat); + if (ret) + break; + + /* cur_size should be the real size returned */ + addr += cur_size; + data += cur_size; + finished += cur_size; + + } while (*size > finished); + *size = finished; + + return ret; +} + +static int tegra_dc_dp_dpcd_read(struct tegra_dp_priv *dp, u32 cmd, + u8 *data_ptr) +{ + u32 size = 1; + u32 status = 0; + int ret; + + ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, + cmd, data_ptr, &size, &status); + if (ret) { + debug("dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n", + cmd, status); + } + + return ret; +} + +static int tegra_dc_dp_dpcd_write(struct tegra_dp_priv *dp, u32 cmd, + u8 data) +{ + u32 size = 1; + u32 status = 0; + int ret; + + ret = tegra_dc_dpaux_write_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXWR, + cmd, &data, &size, &status); + if (ret) { + debug("dp: Failed to write DPCD data. CMD 0x%x, Status 0x%x\n", + cmd, status); + } + + return ret; +} + +static int tegra_dc_i2c_aux_read(struct tegra_dp_priv *dp, u32 i2c_addr, + u8 addr, u8 *data, u32 size, u32 *aux_stat) +{ + u32 finished = 0; + int ret = 0; + + do { + u32 cur_size = min((u32)DP_AUX_MAX_BYTES, size - finished); + + u32 len = 1; + ret = tegra_dc_dpaux_write_chunk( + dp, DPAUX_DP_AUXCTL_CMD_MOTWR, i2c_addr, + &addr, &len, aux_stat); + if (ret) { + debug("%s: error sending address to read.\n", + __func__); + return ret; + } + + ret = tegra_dc_dpaux_read_chunk( + dp, DPAUX_DP_AUXCTL_CMD_I2CRD, i2c_addr, + data, &cur_size, aux_stat); + if (ret) { + debug("%s: error reading data.\n", __func__); + return ret; + } + + /* cur_size should be the real size returned */ + addr += cur_size; + data += cur_size; + finished += cur_size; + } while (size > finished); + + return finished; +} + +static void tegra_dc_dpaux_enable(struct tegra_dp_priv *dp) +{ + /* clear interrupt */ + tegra_dpaux_writel(dp, DPAUX_INTR_AUX, 0xffffffff); + /* do not enable interrupt for now. Enable them when Isr in place */ + tegra_dpaux_writel(dp, DPAUX_INTR_EN_AUX, 0x0); + + tegra_dpaux_writel(dp, DPAUX_HYBRID_PADCTL, + DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 | + DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 | + 0x18 << DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT | + DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE); + + tegra_dpaux_writel(dp, DPAUX_HYBRID_SPARE, + DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP); +} + +#ifdef DEBUG +static void tegra_dc_dp_dump_link_cfg(struct tegra_dp_priv *dp, + const struct tegra_dp_link_config *link_cfg) +{ + debug("DP config: cfg_name cfg_value\n"); + debug(" Lane Count %d\n", + link_cfg->max_lane_count); + debug(" SupportEnhancedFraming %s\n", + link_cfg->support_enhanced_framing ? "Y" : "N"); + debug(" Bandwidth %d\n", + link_cfg->max_link_bw); + debug(" bpp %d\n", + link_cfg->bits_per_pixel); + debug(" EnhancedFraming %s\n", + link_cfg->enhanced_framing ? "Y" : "N"); + debug(" Scramble_enabled %s\n", + link_cfg->scramble_ena ? "Y" : "N"); + debug(" LinkBW %d\n", + link_cfg->link_bw); + debug(" lane_count %d\n", + link_cfg->lane_count); + debug(" activespolarity %d\n", + link_cfg->activepolarity); + debug(" active_count %d\n", + link_cfg->active_count); + debug(" tu_size %d\n", + link_cfg->tu_size); + debug(" active_frac %d\n", + link_cfg->active_frac); + debug(" watermark %d\n", + link_cfg->watermark); + debug(" hblank_sym %d\n", + link_cfg->hblank_sym); + debug(" vblank_sym %d\n", + link_cfg->vblank_sym); +} +#endif + +static int _tegra_dp_lower_link_config(struct tegra_dp_priv *dp, + struct tegra_dp_link_config *cfg) +{ + switch (cfg->link_bw) { + case SOR_LINK_SPEED_G1_62: + if (cfg->max_link_bw > SOR_LINK_SPEED_G1_62) + cfg->link_bw = SOR_LINK_SPEED_G2_7; + cfg->lane_count /= 2; + break; + case SOR_LINK_SPEED_G2_7: + cfg->link_bw = SOR_LINK_SPEED_G1_62; + break; + case SOR_LINK_SPEED_G5_4: + if (cfg->lane_count == 1) { + cfg->link_bw = SOR_LINK_SPEED_G2_7; + cfg->lane_count = cfg->max_lane_count; + } else { + cfg->lane_count /= 2; + } + break; + default: + debug("dp: Error link rate %d\n", cfg->link_bw); + return -ENOLINK; + } + + return (cfg->lane_count > 0) ? 0 : -ENOLINK; +} + +/* + * Calcuate if given cfg can meet the mode request. + * Return 0 if mode is possible, -1 otherwise + */ +static int tegra_dc_dp_calc_config(struct tegra_dp_priv *dp, + const struct display_timing *timing, + struct tegra_dp_link_config *link_cfg) +{ + const u32 link_rate = 27 * link_cfg->link_bw * 1000 * 1000; + const u64 f = 100000; /* precision factor */ + u32 num_linkclk_line; /* Number of link clocks per line */ + u64 ratio_f; /* Ratio of incoming to outgoing data rate */ + u64 frac_f; + u64 activesym_f; /* Activesym per TU */ + u64 activecount_f; + u32 activecount; + u32 activepolarity; + u64 approx_value_f; + u32 activefrac = 0; + u64 accumulated_error_f = 0; + u32 lowest_neg_activecount = 0; + u32 lowest_neg_activepolarity = 0; + u32 lowest_neg_tusize = 64; + u32 num_symbols_per_line; + u64 lowest_neg_activefrac = 0; + u64 lowest_neg_error_f = 64 * f; + u64 watermark_f; + int i; + int neg; + + if (!link_rate || !link_cfg->lane_count || !timing->pixelclock.typ || + !link_cfg->bits_per_pixel) + return -1; + + if ((u64)timing->pixelclock.typ * link_cfg->bits_per_pixel >= + (u64)link_rate * 8 * link_cfg->lane_count) + return -1; + + num_linkclk_line = (u32)(lldiv(link_rate * timing->hactive.typ, + timing->pixelclock.typ)); + + ratio_f = (u64)timing->pixelclock.typ * link_cfg->bits_per_pixel * f; + ratio_f /= 8; + do_div(ratio_f, link_rate * link_cfg->lane_count); + + for (i = 64; i >= 32; --i) { + activesym_f = ratio_f * i; + activecount_f = lldiv(activesym_f, (u32)f) * f; + frac_f = activesym_f - activecount_f; + activecount = (u32)(lldiv(activecount_f, (u32)f)); + + if (frac_f < (lldiv(f, 2))) /* fraction < 0.5 */ + activepolarity = 0; + else { + activepolarity = 1; + frac_f = f - frac_f; + } + + if (frac_f != 0) { + /* warning: frac_f should be 64-bit */ + frac_f = lldiv(f * f, frac_f); /* 1 / fraction */ + if (frac_f > (15 * f)) + activefrac = activepolarity ? 1 : 15; + else + activefrac = activepolarity ? + (u32)lldiv(frac_f, (u32)f) + 1 : + (u32)lldiv(frac_f, (u32)f); + } + + if (activefrac == 1) + activepolarity = 0; + + if (activepolarity == 1) + approx_value_f = activefrac ? lldiv( + (activecount_f + (activefrac * f - f) * f), + (activefrac * f)) : + activecount_f + f; + else + approx_value_f = activefrac ? + activecount_f + lldiv(f, activefrac) : + activecount_f; + + if (activesym_f < approx_value_f) { + accumulated_error_f = num_linkclk_line * + lldiv(approx_value_f - activesym_f, i); + neg = 1; + } else { + accumulated_error_f = num_linkclk_line * + lldiv(activesym_f - approx_value_f, i); + neg = 0; + } + + if ((neg && (lowest_neg_error_f > accumulated_error_f)) || + (accumulated_error_f == 0)) { + lowest_neg_error_f = accumulated_error_f; + lowest_neg_tusize = i; + lowest_neg_activecount = activecount; + lowest_neg_activepolarity = activepolarity; + lowest_neg_activefrac = activefrac; + + if (accumulated_error_f == 0) + break; + } + } + + if (lowest_neg_activefrac == 0) { + link_cfg->activepolarity = 0; + link_cfg->active_count = lowest_neg_activepolarity ? + lowest_neg_activecount : lowest_neg_activecount - 1; + link_cfg->tu_size = lowest_neg_tusize; + link_cfg->active_frac = 1; + } else { + link_cfg->activepolarity = lowest_neg_activepolarity; + link_cfg->active_count = (u32)lowest_neg_activecount; + link_cfg->tu_size = lowest_neg_tusize; + link_cfg->active_frac = (u32)lowest_neg_activefrac; + } + + watermark_f = lldiv(ratio_f * link_cfg->tu_size * (f - ratio_f), f); + link_cfg->watermark = (u32)(lldiv(watermark_f + lowest_neg_error_f, + f)) + link_cfg->bits_per_pixel / 4 - 1; + num_symbols_per_line = (timing->hactive.typ * + link_cfg->bits_per_pixel) / + (8 * link_cfg->lane_count); + + if (link_cfg->watermark > 30) { + debug("dp: sor setting: unable to get a good tusize, force watermark to 30\n"); + link_cfg->watermark = 30; + return -1; + } else if (link_cfg->watermark > num_symbols_per_line) { + debug("dp: sor setting: force watermark to the number of symbols in the line\n"); + link_cfg->watermark = num_symbols_per_line; + return -1; + } + + /* + * Refer to dev_disp.ref for more information. + * # symbols/hblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - + * SetRasterBlankStart.X - 7) * link_clk / pclk) + * - 3 * enhanced_framing - Y + * where Y = (# lanes == 4) 3 : (# lanes == 2) ? 6 : 12 + */ + link_cfg->hblank_sym = (int)lldiv(((uint64_t)timing->hback_porch.typ + + timing->hfront_porch.typ + timing->hsync_len.typ - 7) * + link_rate, timing->pixelclock.typ) - + 3 * link_cfg->enhanced_framing - + (12 / link_cfg->lane_count); + + if (link_cfg->hblank_sym < 0) + link_cfg->hblank_sym = 0; + + /* + * Refer to dev_disp.ref for more information. + * # symbols/vblank = ((SetRasterBlankStart.X - + * SetRasterBlankEen.X - 25) * link_clk / pclk) + * - Y - 1; + * where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39 + */ + link_cfg->vblank_sym = (int)lldiv(((uint64_t)timing->hactive.typ - 25) + * link_rate, timing->pixelclock.typ) - (36 / + link_cfg->lane_count) - 4; + + if (link_cfg->vblank_sym < 0) + link_cfg->vblank_sym = 0; + + link_cfg->is_valid = 1; +#ifdef DEBUG + tegra_dc_dp_dump_link_cfg(dp, link_cfg); +#endif + + return 0; +} + +static int tegra_dc_dp_init_max_link_cfg( + const struct display_timing *timing, + struct tegra_dp_priv *dp, + struct tegra_dp_link_config *link_cfg) +{ + const int drive_current = 0x40404040; + const int preemphasis = 0x0f0f0f0f; + const int postcursor = 0; + u8 dpcd_data; + int ret; + + ret = tegra_dc_dp_dpcd_read(dp, DP_MAX_LANE_COUNT, &dpcd_data); + if (ret) + return ret; + link_cfg->max_lane_count = dpcd_data & DP_MAX_LANE_COUNT_MASK; + link_cfg->tps3_supported = (dpcd_data & + DP_MAX_LANE_COUNT_TPS3_SUPPORTED_YES) ? 1 : 0; + + link_cfg->support_enhanced_framing = + (dpcd_data & DP_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ? + 1 : 0; + + ret = tegra_dc_dp_dpcd_read(dp, DP_MAX_DOWNSPREAD, &dpcd_data); + if (ret) + return ret; + link_cfg->downspread = (dpcd_data & DP_MAX_DOWNSPREAD_VAL_0_5_PCT) ? + 1 : 0; + + ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_TRAINING_AUX_RD_INTERVAL, + &link_cfg->aux_rd_interval); + if (ret) + return ret; + ret = tegra_dc_dp_dpcd_read(dp, DP_MAX_LINK_RATE, + &link_cfg->max_link_bw); + if (ret) + return ret; + + /* + * Set to a high value for link training and attach. + * Will be re-programmed when dp is enabled. + */ + link_cfg->drive_current = drive_current; + link_cfg->preemphasis = preemphasis; + link_cfg->postcursor = postcursor; + + ret = tegra_dc_dp_dpcd_read(dp, DP_EDP_CONFIGURATION_CAP, &dpcd_data); + if (ret) + return ret; + + link_cfg->alt_scramber_reset_cap = + (dpcd_data & DP_EDP_CONFIGURATION_CAP_ASC_RESET_YES) ? + 1 : 0; + link_cfg->only_enhanced_framing = + (dpcd_data & DP_EDP_CONFIGURATION_CAP_FRAMING_CHANGE_YES) ? + 1 : 0; + + link_cfg->lane_count = link_cfg->max_lane_count; + link_cfg->link_bw = link_cfg->max_link_bw; + link_cfg->enhanced_framing = link_cfg->support_enhanced_framing; + link_cfg->frame_in_ms = (1000 / 60) + 1; + + tegra_dc_dp_calc_config(dp, timing, link_cfg); + return 0; +} + +static int tegra_dc_dp_set_assr(struct tegra_dp_priv *priv, + struct udevice *sor, int ena) +{ + int ret; + + u8 dpcd_data = ena ? + DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_ENABLE : + DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_DISABLE; + + ret = tegra_dc_dp_dpcd_write(priv, DP_EDP_CONFIGURATION_SET, + dpcd_data); + if (ret) + return ret; + + /* Also reset the scrambler to 0xfffe */ + tegra_dc_sor_set_internal_panel(sor, ena); + return 0; +} + +static int tegra_dp_set_link_bandwidth(struct tegra_dp_priv *dp, + struct udevice *sor, + u8 link_bw) +{ + tegra_dc_sor_set_link_bandwidth(sor, link_bw); + + /* Sink side */ + return tegra_dc_dp_dpcd_write(dp, DP_LINK_BW_SET, link_bw); +} + +static int tegra_dp_set_lane_count(struct tegra_dp_priv *dp, + const struct tegra_dp_link_config *link_cfg, + struct udevice *sor) +{ + u8 dpcd_data; + int ret; + + /* check if panel support enhanched_framing */ + dpcd_data = link_cfg->lane_count; + if (link_cfg->enhanced_framing) + dpcd_data |= DP_LANE_COUNT_SET_ENHANCEDFRAMING_T; + ret = tegra_dc_dp_dpcd_write(dp, DP_LANE_COUNT_SET, dpcd_data); + if (ret) + return ret; + + tegra_dc_sor_set_lane_count(sor, link_cfg->lane_count); + + /* Also power down lanes that will not be used */ + return 0; +} + +static int tegra_dc_dp_link_trained(struct tegra_dp_priv *dp, + const struct tegra_dp_link_config *cfg) +{ + u32 lane; + u8 mask; + u8 data; + int ret; + + for (lane = 0; lane < cfg->lane_count; ++lane) { + ret = tegra_dc_dp_dpcd_read(dp, (lane / 2) ? + DP_LANE2_3_STATUS : DP_LANE0_1_STATUS, + &data); + if (ret) + return ret; + mask = (lane & 1) ? + NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES | + NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES | + NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES : + DP_LANE_CR_DONE | + DP_LANE_CHANNEL_EQ_DONE | + DP_LANE_SYMBOL_LOCKED; + if ((data & mask) != mask) + return -1; + } + return 0; +} + +static int tegra_dp_channel_eq_status(struct tegra_dp_priv *dp, + const struct tegra_dp_link_config *cfg) +{ + u32 cnt; + u32 n_lanes = cfg->lane_count; + u8 data; + u8 ce_done = 1; + int ret; + + for (cnt = 0; cnt < n_lanes / 2; cnt++) { + ret = tegra_dc_dp_dpcd_read(dp, DP_LANE0_1_STATUS + cnt, &data); + if (ret) + return ret; + + if (n_lanes == 1) { + ce_done = (data & (0x1 << + NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT)) && + (data & (0x1 << + NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT)); + break; + } else if (!(data & (0x1 << + NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT)) || + !(data & (0x1 << + NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT)) || + !(data & (0x1 << + NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT)) || + !(data & (0x1 << + NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT))) + return -EIO; + } + + if (ce_done) { + ret = tegra_dc_dp_dpcd_read(dp, + DP_LANE_ALIGN_STATUS_UPDATED, + &data); + if (ret) + return ret; + if (!(data & NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES)) + ce_done = 0; + } + + return ce_done ? 0 : -EIO; +} + +static int tegra_dp_clock_recovery_status(struct tegra_dp_priv *dp, + const struct tegra_dp_link_config *cfg) +{ + u32 cnt; + u32 n_lanes = cfg->lane_count; + u8 data_ptr; + int ret; + + for (cnt = 0; cnt < n_lanes / 2; cnt++) { + ret = tegra_dc_dp_dpcd_read(dp, (DP_LANE0_1_STATUS + cnt), + &data_ptr); + if (ret) + return ret; + + if (n_lanes == 1) + return (data_ptr & NV_DPCD_STATUS_LANEX_CR_DONE_YES) ? + 1 : 0; + else if (!(data_ptr & NV_DPCD_STATUS_LANEX_CR_DONE_YES) || + !(data_ptr & (NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES))) + return 0; + } + + return 1; +} + +static int tegra_dp_lt_adjust(struct tegra_dp_priv *dp, u32 pe[4], u32 vs[4], + u32 pc[4], u8 pc_supported, + const struct tegra_dp_link_config *cfg) +{ + size_t cnt; + u8 data_ptr; + u32 n_lanes = cfg->lane_count; + int ret; + + for (cnt = 0; cnt < n_lanes / 2; cnt++) { + ret = tegra_dc_dp_dpcd_read(dp, DP_ADJUST_REQUEST_LANE0_1 + cnt, + &data_ptr); + if (ret) + return ret; + pe[2 * cnt] = (data_ptr & NV_DPCD_ADJUST_REQ_LANEX_PE_MASK) >> + NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT; + vs[2 * cnt] = (data_ptr & NV_DPCD_ADJUST_REQ_LANEX_DC_MASK) >> + NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT; + pe[1 + 2 * cnt] = + (data_ptr & NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK) >> + NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT; + vs[1 + 2 * cnt] = + (data_ptr & NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK) >> + NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT; + } + if (pc_supported) { + ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_ADJUST_REQ_POST_CURSOR2, + &data_ptr); + if (ret) + return ret; + for (cnt = 0; cnt < n_lanes; cnt++) { + pc[cnt] = (data_ptr >> + NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(cnt)) & + NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK; + } + } + + return 0; +} + +static void tegra_dp_wait_aux_training(struct tegra_dp_priv *dp, + bool is_clk_recovery, + const struct tegra_dp_link_config *cfg) +{ + if (!cfg->aux_rd_interval) + udelay(is_clk_recovery ? 200 : 500); + else + mdelay(cfg->aux_rd_interval * 4); +} + +static void tegra_dp_tpg(struct tegra_dp_priv *dp, u32 tp, u32 n_lanes, + const struct tegra_dp_link_config *cfg) +{ + u8 data = (tp == training_pattern_disabled) + ? (tp | NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_F) + : (tp | NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_T); + + tegra_dc_sor_set_dp_linkctl(dp->sor, 1, tp, cfg); + tegra_dc_dp_dpcd_write(dp, DP_TRAINING_PATTERN_SET, data); +} + +static int tegra_dp_link_config(struct tegra_dp_priv *dp, + const struct tegra_dp_link_config *link_cfg) +{ + u8 dpcd_data; + u32 retry; + int ret; + + if (link_cfg->lane_count == 0) { + debug("dp: error: lane count is 0. Can not set link config.\n"); + return -ENOLINK; + } + + /* Set power state if it is not in normal level */ + ret = tegra_dc_dp_dpcd_read(dp, DP_SET_POWER, &dpcd_data); + if (ret) + return ret; + + if (dpcd_data == DP_SET_POWER_D3) { + dpcd_data = DP_SET_POWER_D0; + + /* DP spec requires 3 retries */ + for (retry = 3; retry > 0; --retry) { + ret = tegra_dc_dp_dpcd_write(dp, DP_SET_POWER, + dpcd_data); + if (!ret) + break; + if (retry == 1) { + debug("dp: Failed to set DP panel power\n"); + return ret; + } + } + } + + /* Enable ASSR if possible */ + if (link_cfg->alt_scramber_reset_cap) { + ret = tegra_dc_dp_set_assr(dp, dp->sor, 1); + if (ret) + return ret; + } + + ret = tegra_dp_set_link_bandwidth(dp, dp->sor, link_cfg->link_bw); + if (ret) { + debug("dp: Failed to set link bandwidth\n"); + return ret; + } + ret = tegra_dp_set_lane_count(dp, link_cfg, dp->sor); + if (ret) { + debug("dp: Failed to set lane count\n"); + return ret; + } + tegra_dc_sor_set_dp_linkctl(dp->sor, 1, training_pattern_none, + link_cfg); + + return 0; +} + +static int tegra_dp_lower_link_config(struct tegra_dp_priv *dp, + const struct display_timing *timing, + struct tegra_dp_link_config *cfg) +{ + struct tegra_dp_link_config tmp_cfg; + int ret; + + tmp_cfg = *cfg; + cfg->is_valid = 0; + + ret = _tegra_dp_lower_link_config(dp, cfg); + if (!ret) + ret = tegra_dc_dp_calc_config(dp, timing, cfg); + if (!ret) + ret = tegra_dp_link_config(dp, cfg); + if (ret) + goto fail; + + return 0; + +fail: + *cfg = tmp_cfg; + tegra_dp_link_config(dp, &tmp_cfg); + return ret; +} + +static int tegra_dp_lt_config(struct tegra_dp_priv *dp, u32 pe[4], u32 vs[4], + u32 pc[4], const struct tegra_dp_link_config *cfg) +{ + struct udevice *sor = dp->sor; + u32 n_lanes = cfg->lane_count; + u8 pc_supported = cfg->tps3_supported; + u32 cnt; + u32 val; + + for (cnt = 0; cnt < n_lanes; cnt++) { + u32 mask = 0; + u32 pe_reg, vs_reg, pc_reg; + u32 shift = 0; + + switch (cnt) { + case 0: + mask = PR_LANE2_DP_LANE0_MASK; + shift = PR_LANE2_DP_LANE0_SHIFT; + break; + case 1: + mask = PR_LANE1_DP_LANE1_MASK; + shift = PR_LANE1_DP_LANE1_SHIFT; + break; + case 2: + mask = PR_LANE0_DP_LANE2_MASK; + shift = PR_LANE0_DP_LANE2_SHIFT; + break; + case 3: + mask = PR_LANE3_DP_LANE3_MASK; + shift = PR_LANE3_DP_LANE3_SHIFT; + break; + default: + debug("dp: incorrect lane cnt\n"); + return -EINVAL; + } + + pe_reg = tegra_dp_pe_regs[pc[cnt]][vs[cnt]][pe[cnt]]; + vs_reg = tegra_dp_vs_regs[pc[cnt]][vs[cnt]][pe[cnt]]; + pc_reg = tegra_dp_pc_regs[pc[cnt]][vs[cnt]][pe[cnt]]; + + tegra_dp_set_pe_vs_pc(sor, mask, pe_reg << shift, + vs_reg << shift, pc_reg << shift, + pc_supported); + } + + tegra_dp_disable_tx_pu(dp->sor); + udelay(20); + + for (cnt = 0; cnt < n_lanes; cnt++) { + u32 max_vs_flag = tegra_dp_is_max_vs(pe[cnt], vs[cnt]); + u32 max_pe_flag = tegra_dp_is_max_pe(pe[cnt], vs[cnt]); + + val = (vs[cnt] << NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT) | + (max_vs_flag ? + NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T : + NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_F) | + (pe[cnt] << NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT) | + (max_pe_flag ? + NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T : + NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_F); + tegra_dc_dp_dpcd_write(dp, (DP_TRAINING_LANE0_SET + cnt), val); + } + + if (pc_supported) { + for (cnt = 0; cnt < n_lanes / 2; cnt++) { + u32 max_pc_flag0 = tegra_dp_is_max_pc(pc[cnt]); + u32 max_pc_flag1 = tegra_dp_is_max_pc(pc[cnt + 1]); + val = (pc[cnt] << NV_DPCD_LANEX_SET2_PC2_SHIFT) | + (max_pc_flag0 ? + NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T : + NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_F) | + (pc[cnt + 1] << + NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT) | + (max_pc_flag1 ? + NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T : + NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_F); + tegra_dc_dp_dpcd_write(dp, + NV_DPCD_TRAINING_LANE0_1_SET2 + + cnt, val); + } + } + + return 0; +} + +static int _tegra_dp_channel_eq(struct tegra_dp_priv *dp, u32 pe[4], + u32 vs[4], u32 pc[4], u8 pc_supported, + u32 n_lanes, + const struct tegra_dp_link_config *cfg) +{ + u32 retry_cnt; + + for (retry_cnt = 0; retry_cnt < 4; retry_cnt++) { + int ret; + + if (retry_cnt) { + ret = tegra_dp_lt_adjust(dp, pe, vs, pc, pc_supported, + cfg); + if (ret) + return ret; + tegra_dp_lt_config(dp, pe, vs, pc, cfg); + } + + tegra_dp_wait_aux_training(dp, false, cfg); + + if (!tegra_dp_clock_recovery_status(dp, cfg)) { + debug("dp: CR failed in channel EQ sequence!\n"); + break; + } + + if (!tegra_dp_channel_eq_status(dp, cfg)) + return 0; + } + + return -EIO; +} + +static int tegra_dp_channel_eq(struct tegra_dp_priv *dp, u32 pe[4], u32 vs[4], + u32 pc[4], + const struct tegra_dp_link_config *cfg) +{ + u32 n_lanes = cfg->lane_count; + u8 pc_supported = cfg->tps3_supported; + int ret; + u32 tp_src = training_pattern_2; + + if (pc_supported) + tp_src = training_pattern_3; + + tegra_dp_tpg(dp, tp_src, n_lanes, cfg); + + ret = _tegra_dp_channel_eq(dp, pe, vs, pc, pc_supported, n_lanes, cfg); + + tegra_dp_tpg(dp, training_pattern_disabled, n_lanes, cfg); + + return ret; +} + +static int _tegra_dp_clk_recovery(struct tegra_dp_priv *dp, u32 pe[4], + u32 vs[4], u32 pc[4], u8 pc_supported, + u32 n_lanes, + const struct tegra_dp_link_config *cfg) +{ + u32 vs_temp[4]; + u32 retry_cnt = 0; + + do { + tegra_dp_lt_config(dp, pe, vs, pc, cfg); + tegra_dp_wait_aux_training(dp, true, cfg); + + if (tegra_dp_clock_recovery_status(dp, cfg)) + return 0; + + memcpy(vs_temp, vs, sizeof(vs_temp)); + tegra_dp_lt_adjust(dp, pe, vs, pc, pc_supported, cfg); + + if (memcmp(vs_temp, vs, sizeof(vs_temp))) + retry_cnt = 0; + else + ++retry_cnt; + } while (retry_cnt < 5); + + return -EIO; +} + +static int tegra_dp_clk_recovery(struct tegra_dp_priv *dp, u32 pe[4], + u32 vs[4], u32 pc[4], + const struct tegra_dp_link_config *cfg) +{ + u32 n_lanes = cfg->lane_count; + u8 pc_supported = cfg->tps3_supported; + int err; + + tegra_dp_tpg(dp, training_pattern_1, n_lanes, cfg); + + err = _tegra_dp_clk_recovery(dp, pe, vs, pc, pc_supported, n_lanes, + cfg); + if (err < 0) + tegra_dp_tpg(dp, training_pattern_disabled, n_lanes, cfg); + + return err; +} + +static int tegra_dc_dp_full_link_training(struct tegra_dp_priv *dp, + const struct display_timing *timing, + struct tegra_dp_link_config *cfg) +{ + struct udevice *sor = dp->sor; + int err; + u32 pe[4], vs[4], pc[4]; + + tegra_sor_precharge_lanes(sor, cfg); + +retry_cr: + memset(pe, PREEMPHASIS_DISABLED, sizeof(pe)); + memset(vs, DRIVECURRENT_LEVEL0, sizeof(vs)); + memset(pc, POSTCURSOR2_LEVEL0, sizeof(pc)); + + err = tegra_dp_clk_recovery(dp, pe, vs, pc, cfg); + if (err) { + if (!tegra_dp_lower_link_config(dp, timing, cfg)) + goto retry_cr; + + debug("dp: clk recovery failed\n"); + goto fail; + } + + err = tegra_dp_channel_eq(dp, pe, vs, pc, cfg); + if (err) { + if (!tegra_dp_lower_link_config(dp, timing, cfg)) + goto retry_cr; + + debug("dp: channel equalization failed\n"); + goto fail; + } +#ifdef DEBUG + tegra_dc_dp_dump_link_cfg(dp, cfg); +#endif + return 0; + +fail: + return err; +} + +/* + * All link training functions are ported from kernel dc driver. + * See more details at drivers/video/tegra/dc/dp.c + */ +static int tegra_dc_dp_fast_link_training(struct tegra_dp_priv *dp, + const struct tegra_dp_link_config *link_cfg, + struct udevice *sor) +{ + u8 link_bw; + u8 lane_count; + u16 data16; + u32 data32; + u32 size; + u32 status; + int j; + u32 mask = 0xffff >> ((4 - link_cfg->lane_count) * 4); + + tegra_dc_sor_set_lane_parm(sor, link_cfg); + tegra_dc_dp_dpcd_write(dp, DP_MAIN_LINK_CHANNEL_CODING_SET, + DP_SET_ANSI_8B10B); + + /* Send TP1 */ + tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_1, link_cfg); + tegra_dc_dp_dpcd_write(dp, DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_1); + + for (j = 0; j < link_cfg->lane_count; ++j) + tegra_dc_dp_dpcd_write(dp, DP_TRAINING_LANE0_SET + j, 0x24); + udelay(520); + + size = sizeof(data16); + tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, + DP_LANE0_1_STATUS, (u8 *)&data16, &size, &status); + status = mask & 0x1111; + if ((data16 & status) != status) { + debug("dp: Link training error for TP1 (%#x, status %#x)\n", + data16, status); + return -EFAULT; + } + + /* enable ASSR */ + tegra_dc_dp_set_assr(dp, sor, link_cfg->scramble_ena); + tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_3, link_cfg); + + tegra_dc_dp_dpcd_write(dp, DP_TRAINING_PATTERN_SET, + link_cfg->link_bw == 20 ? 0x23 : 0x22); + for (j = 0; j < link_cfg->lane_count; ++j) + tegra_dc_dp_dpcd_write(dp, DP_TRAINING_LANE0_SET + j, 0x24); + udelay(520); + + size = sizeof(data32); + tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, DP_LANE0_1_STATUS, + (u8 *)&data32, &size, &status); + if ((data32 & mask) != (0x7777 & mask)) { + debug("dp: Link training error for TP2/3 (0x%x)\n", data32); + return -EFAULT; + } + + tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_disabled, + link_cfg); + tegra_dc_dp_dpcd_write(dp, DP_TRAINING_PATTERN_SET, 0); + + if (tegra_dc_dp_link_trained(dp, link_cfg)) { + tegra_dc_sor_read_link_config(sor, &link_bw, &lane_count); + debug("Fast link training failed, link bw %d, lane # %d\n", + link_bw, lane_count); + return -EFAULT; + } + + debug("Fast link training succeeded, link bw %d, lane %d\n", + link_cfg->link_bw, link_cfg->lane_count); + + return 0; +} + +static int tegra_dp_do_link_training(struct tegra_dp_priv *dp, + struct tegra_dp_link_config *link_cfg, + const struct display_timing *timing, + struct udevice *sor) +{ + u8 link_bw; + u8 lane_count; + int ret; + + if (DO_FAST_LINK_TRAINING) { + ret = tegra_dc_dp_fast_link_training(dp, link_cfg, sor); + if (ret) { + debug("dp: fast link training failed\n"); + } else { + /* + * set to a known-good drive setting if fast link + * succeeded. Ignore any error. + */ + ret = tegra_dc_sor_set_voltage_swing(dp->sor, link_cfg); + if (ret) + debug("Failed to set voltage swing\n"); + } + } else { + ret = -ENOSYS; + } + if (ret) { + /* Try full link training then */ + ret = tegra_dc_dp_full_link_training(dp, timing, link_cfg); + if (ret) { + debug("dp: full link training failed\n"); + return ret; + } + } + + /* Everything is good; double check the link config */ + tegra_dc_sor_read_link_config(sor, &link_bw, &lane_count); + + if ((link_cfg->link_bw == link_bw) && + (link_cfg->lane_count == lane_count)) + return 0; + else + return -EFAULT; +} + +static int tegra_dc_dp_explore_link_cfg(struct tegra_dp_priv *dp, + struct tegra_dp_link_config *link_cfg, + struct udevice *sor, + const struct display_timing *timing) +{ + struct tegra_dp_link_config temp_cfg; + + if (!timing->pixelclock.typ || !timing->hactive.typ || + !timing->vactive.typ) { + debug("dp: error mode configuration"); + return -EINVAL; + } + if (!link_cfg->max_link_bw || !link_cfg->max_lane_count) { + debug("dp: error link configuration"); + return -EINVAL; + } + + link_cfg->is_valid = 0; + + memcpy(&temp_cfg, link_cfg, sizeof(temp_cfg)); + + temp_cfg.link_bw = temp_cfg.max_link_bw; + temp_cfg.lane_count = temp_cfg.max_lane_count; + + /* + * set to max link config + */ + if ((!tegra_dc_dp_calc_config(dp, timing, &temp_cfg)) && + (!tegra_dp_link_config(dp, &temp_cfg)) && + (!tegra_dp_do_link_training(dp, &temp_cfg, timing, sor))) + /* the max link cfg is doable */ + memcpy(link_cfg, &temp_cfg, sizeof(temp_cfg)); + + return link_cfg->is_valid ? 0 : -EFAULT; +} + +static int tegra_dp_hpd_plug(struct tegra_dp_priv *dp) +{ + const int vdd_to_hpd_delay_ms = 200; + u32 val; + ulong start; + + start = get_timer(0); + do { + val = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); + if (val & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED) + return 0; + udelay(100); + } while (get_timer(start) < vdd_to_hpd_delay_ms); + + return -EIO; +} + +static int tegra_dc_dp_sink_out_of_sync(struct tegra_dp_priv *dp, u32 delay_ms) +{ + u8 dpcd_data; + int out_of_sync; + int ret; + + debug("%s: delay=%d\n", __func__, delay_ms); + mdelay(delay_ms); + ret = tegra_dc_dp_dpcd_read(dp, DP_SINK_STATUS, &dpcd_data); + if (ret) + return ret; + + out_of_sync = !(dpcd_data & DP_SINK_STATUS_PORT0_IN_SYNC); + if (out_of_sync) + debug("SINK receive port 0 out of sync, data=%x\n", dpcd_data); + else + debug("SINK is in synchronization\n"); + + return out_of_sync; +} + +static int tegra_dc_dp_check_sink(struct tegra_dp_priv *dp, + struct tegra_dp_link_config *link_cfg, + const struct display_timing *timing) +{ + const int max_retry = 5; + int delay_frame; + int retries; + + /* + * DP TCON may skip some main stream frames, thus we need to wait + * some delay before reading the DPCD SINK STATUS register, starting + * from 5 + */ + delay_frame = 5; + + retries = max_retry; + do { + int ret; + + if (!tegra_dc_dp_sink_out_of_sync(dp, link_cfg->frame_in_ms * + delay_frame)) + return 0; + + debug("%s: retries left %d\n", __func__, retries); + if (!retries--) { + printf("DP: Out of sync after %d retries\n", max_retry); + return -EIO; + } + ret = tegra_dc_sor_detach(dp->dc_dev, dp->sor); + if (ret) + return ret; + if (tegra_dc_dp_explore_link_cfg(dp, link_cfg, dp->sor, + timing)) { + debug("dp: %s: error to configure link\n", __func__); + continue; + } + + tegra_dc_sor_set_power_state(dp->sor, 1); + tegra_dc_sor_attach(dp->dc_dev, dp->sor, link_cfg, timing); + + /* Increase delay_frame for next try in case the sink is + skipping more frames */ + delay_frame += 10; + } while (1); +} + +int tegra_dp_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *timing) +{ + struct tegra_dp_priv *priv = dev_get_priv(dev); + struct tegra_dp_link_config slink_cfg, *link_cfg = &slink_cfg; + struct udevice *sor; + int data; + int retry; + int ret; + + memset(link_cfg, '\0', sizeof(*link_cfg)); + link_cfg->is_valid = 0; + link_cfg->scramble_ena = 1; + + tegra_dc_dpaux_enable(priv); + + if (tegra_dp_hpd_plug(priv) < 0) { + debug("dp: hpd plug failed\n"); + return -EIO; + } + + link_cfg->bits_per_pixel = panel_bpp; + if (tegra_dc_dp_init_max_link_cfg(timing, priv, link_cfg)) { + debug("dp: failed to init link configuration\n"); + return -ENOLINK; + } + + ret = uclass_first_device_err(UCLASS_VIDEO_BRIDGE, &sor); + if (ret) { + debug("dp: failed to find SOR device: ret=%d\n", ret); + return ret; + } + priv->sor = sor; + ret = tegra_dc_sor_enable_dp(sor, link_cfg); + if (ret) + return ret; + + tegra_dc_sor_set_panel_power(sor, 1); + + /* Write power on to DPCD */ + data = DP_SET_POWER_D0; + retry = 0; + do { + ret = tegra_dc_dp_dpcd_write(priv, DP_SET_POWER, data); + } while ((retry++ < DP_POWER_ON_MAX_TRIES) && ret); + + if (ret || retry >= DP_POWER_ON_MAX_TRIES) { + debug("dp: failed to power on panel (0x%x)\n", ret); + return -ENETUNREACH; + goto error_enable; + } + + /* Confirm DP plugging status */ + if (!(tegra_dpaux_readl(priv, DPAUX_DP_AUXSTAT) & + DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { + debug("dp: could not detect HPD\n"); + return -ENXIO; + } + + /* Check DP version */ + if (tegra_dc_dp_dpcd_read(priv, DP_DPCD_REV, &priv->revision)) { + debug("dp: failed to read the revision number from sink\n"); + return -EIO; + } + + if (tegra_dc_dp_explore_link_cfg(priv, link_cfg, sor, timing)) { + debug("dp: error configuring link\n"); + return -ENOMEDIUM; + } + + tegra_dc_sor_set_power_state(sor, 1); + ret = tegra_dc_sor_attach(priv->dc_dev, sor, link_cfg, timing); + if (ret && ret != -EEXIST) + return ret; + + /* + * This takes a long time, but can apparently resolve a failure to + * bring up the display correctly. + */ + if (0) { + ret = tegra_dc_dp_check_sink(priv, link_cfg, timing); + if (ret) + return ret; + } + + /* Power down the unused lanes to save power - a few hundred mW */ + tegra_dc_sor_power_down_unused_lanes(sor, link_cfg); + + ret = video_bridge_set_backlight(sor, 80); + if (ret) { + debug("dp: failed to set backlight\n"); + return ret; + } + + priv->enabled = true; +error_enable: + return 0; +} + +static int tegra_dp_of_to_plat(struct udevice *dev) +{ + struct tegra_dp_plat *plat = dev_get_plat(dev); + + plat->base = dev_read_addr(dev); + + return 0; +} + +static int tegra_dp_read_edid(struct udevice *dev, u8 *buf, int buf_size) +{ + struct tegra_dp_priv *priv = dev_get_priv(dev); + const int tegra_edid_i2c_address = 0x50; + u32 aux_stat = 0; + + tegra_dc_dpaux_enable(priv); + + return tegra_dc_i2c_aux_read(priv, tegra_edid_i2c_address, 0, buf, + buf_size, &aux_stat); +} + +static const struct dm_display_ops dp_tegra_ops = { + .read_edid = tegra_dp_read_edid, + .enable = tegra_dp_enable, +}; + +static int dp_tegra_probe(struct udevice *dev) +{ + struct tegra_dp_plat *plat = dev_get_plat(dev); + struct tegra_dp_priv *priv = dev_get_priv(dev); + struct display_plat *disp_uc_plat = dev_get_uclass_plat(dev); + + priv->regs = (struct dpaux_ctlr *)plat->base; + priv->enabled = false; + + /* Remember the display controller that is sending us video */ + priv->dc_dev = disp_uc_plat->src_dev; + + return 0; +} + +static const struct udevice_id tegra_dp_ids[] = { + { .compatible = "nvidia,tegra124-dpaux" }, + { .compatible = "nvidia,tegra210-dpaux" }, + { } +}; + +U_BOOT_DRIVER(dp_tegra) = { + .name = "dpaux_tegra", + .id = UCLASS_DISPLAY, + .of_match = tegra_dp_ids, + .of_to_plat = tegra_dp_of_to_plat, + .probe = dp_tegra_probe, + .ops = &dp_tegra_ops, + .priv_auto = sizeof(struct tegra_dp_priv), + .plat_auto = sizeof(struct tegra_dp_plat), +}; diff --git a/drivers/video/tegra/tegra124/sor.c b/drivers/video/tegra/tegra124/sor.c new file mode 100644 index 00000000000..1ce5330c6bc --- /dev/null +++ b/drivers/video/tegra/tegra124/sor.c @@ -0,0 +1,1083 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2011-2013, NVIDIA Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "displayport.h" +#include "sor.h" +#include + +#define DEBUG_SOR 0 + +#define APBDEV_PMC_DPD_SAMPLE 0x20 +#define APBDEV_PMC_DPD_SAMPLE_ON_DISABLE 0 +#define APBDEV_PMC_DPD_SAMPLE_ON_ENABLE 1 +#define APBDEV_PMC_SEL_DPD_TIM 0x1c8 +#define APBDEV_PMC_SEL_DPD_TIM_SEL_DPD_TIM_DEFAULT 0x7f +#define APBDEV_PMC_IO_DPD2_REQ 0x1c0 +#define APBDEV_PMC_IO_DPD2_REQ_LVDS_SHIFT 25 +#define APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF (0 << 25) +#define APBDEV_PMC_IO_DPD2_REQ_LVDS_ON (1 << 25) +#define APBDEV_PMC_IO_DPD2_REQ_CODE_SHIFT 30 +#define APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK (0x3 << 30) +#define APBDEV_PMC_IO_DPD2_REQ_CODE_IDLE (0 << 30) +#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF (1 << 30) +#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON (2 << 30) +#define APBDEV_PMC_IO_DPD2_STATUS 0x1c4 +#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_SHIFT 25 +#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF (0 << 25) +#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON (1 << 25) + +struct tegra_dc_sor_data { + void *base; + void *pmc_base; + u8 portnum; /* 0 or 1 */ + int power_is_up; + struct udevice *panel; +}; + +static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg) +{ + return readl((u32 *)sor->base + reg); +} + +static inline void tegra_sor_writel(struct tegra_dc_sor_data *sor, u32 reg, + u32 val) +{ + writel(val, (u32 *)sor->base + reg); +} + +static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor, + u32 reg, u32 mask, u32 val) +{ + u32 reg_val = tegra_sor_readl(sor, reg); + reg_val &= ~mask; + reg_val |= val; + tegra_sor_writel(sor, reg, reg_val); +} + +void tegra_dp_disable_tx_pu(struct udevice *dev) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), + DP_PADCTL_TX_PU_MASK, DP_PADCTL_TX_PU_DISABLE); +} + +void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg, + u32 vs_reg, u32 pc_reg, u8 pc_supported) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + + tegra_sor_write_field(sor, PR(sor->portnum), mask, pe_reg); + tegra_sor_write_field(sor, DC(sor->portnum), mask, vs_reg); + if (pc_supported) { + tegra_sor_write_field(sor, POSTCURSOR(sor->portnum), mask, + pc_reg); + } +} + +static int tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor, u32 reg, + u32 mask, u32 exp_val, + int poll_interval_us, int timeout_ms) +{ + u32 reg_val = 0; + ulong start; + + start = get_timer(0); + do { + reg_val = tegra_sor_readl(sor, reg); + if (((reg_val & mask) == exp_val)) + return 0; + udelay(poll_interval_us); + } while (get_timer(start) < timeout_ms); + + debug("sor_poll_register 0x%x: timeout, (reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n", + reg, reg_val, mask, exp_val); + + return -ETIMEDOUT; +} + +int tegra_dc_sor_set_power_state(struct udevice *dev, int pu_pd) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg_val; + u32 orig_val; + + orig_val = tegra_sor_readl(sor, PWR); + + reg_val = pu_pd ? PWR_NORMAL_STATE_PU : + PWR_NORMAL_STATE_PD; /* normal state only */ + + if (reg_val == orig_val) + return 0; /* No update needed */ + + reg_val |= PWR_SETTING_NEW_TRIGGER; + tegra_sor_writel(sor, PWR, reg_val); + + /* Poll to confirm it is done */ + if (tegra_dc_sor_poll_register(sor, PWR, + PWR_SETTING_NEW_DEFAULT_MASK, + PWR_SETTING_NEW_DONE, + 100, TEGRA_SOR_TIMEOUT_MS)) { + debug("dc timeout waiting for SOR_PWR = NEW_DONE\n"); + return -EFAULT; + } + + return 0; +} + +void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena, + u8 training_pattern, + const struct tegra_dp_link_config *link_cfg) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg_val; + + reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum)); + + if (ena) + reg_val |= DP_LINKCTL_ENABLE_YES; + else + reg_val &= DP_LINKCTL_ENABLE_NO; + + reg_val &= ~DP_LINKCTL_TUSIZE_MASK; + reg_val |= (link_cfg->tu_size << DP_LINKCTL_TUSIZE_SHIFT); + + if (link_cfg->enhanced_framing) + reg_val |= DP_LINKCTL_ENHANCEDFRAME_ENABLE; + + tegra_sor_writel(sor, DP_LINKCTL(sor->portnum), reg_val); + + switch (training_pattern) { + case training_pattern_1: + tegra_sor_writel(sor, DP_TPG, 0x41414141); + break; + case training_pattern_2: + case training_pattern_3: + reg_val = (link_cfg->link_bw == SOR_LINK_SPEED_G5_4) ? + 0x43434343 : 0x42424242; + tegra_sor_writel(sor, DP_TPG, reg_val); + break; + default: + tegra_sor_writel(sor, DP_TPG, 0x50505050); + break; + } +} + +static int tegra_dc_sor_enable_lane_sequencer(struct tegra_dc_sor_data *sor, + int pu, int is_lvds) +{ + u32 reg_val; + + /* SOR lane sequencer */ + if (pu) { + reg_val = LANE_SEQ_CTL_SETTING_NEW_TRIGGER | + LANE_SEQ_CTL_SEQUENCE_DOWN | + LANE_SEQ_CTL_NEW_POWER_STATE_PU; + } else { + reg_val = LANE_SEQ_CTL_SETTING_NEW_TRIGGER | + LANE_SEQ_CTL_SEQUENCE_UP | + LANE_SEQ_CTL_NEW_POWER_STATE_PD; + } + + if (is_lvds) + reg_val |= 15 << LANE_SEQ_CTL_DELAY_SHIFT; + else + reg_val |= 1 << LANE_SEQ_CTL_DELAY_SHIFT; + + tegra_sor_writel(sor, LANE_SEQ_CTL, reg_val); + + if (tegra_dc_sor_poll_register(sor, LANE_SEQ_CTL, + LANE_SEQ_CTL_SETTING_MASK, + LANE_SEQ_CTL_SETTING_NEW_DONE, + 100, TEGRA_SOR_TIMEOUT_MS)) { + debug("dp: timeout while waiting for SOR lane sequencer to power down lanes\n"); + return -1; + } + + return 0; +} + +static int tegra_dc_sor_power_dplanes(struct udevice *dev, + u32 lane_count, int pu) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg_val; + + reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); + + if (pu) { + switch (lane_count) { + case 4: + reg_val |= (DP_PADCTL_PD_TXD_3_NO | + DP_PADCTL_PD_TXD_2_NO); + /* fall through */ + case 2: + reg_val |= DP_PADCTL_PD_TXD_1_NO; + case 1: + reg_val |= DP_PADCTL_PD_TXD_0_NO; + break; + default: + debug("dp: invalid lane number %d\n", lane_count); + return -1; + } + + tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val); + tegra_dc_sor_set_lane_count(dev, lane_count); + } + + return tegra_dc_sor_enable_lane_sequencer(sor, pu, 0); +} + +void tegra_dc_sor_set_panel_power(struct udevice *dev, int power_up) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg_val; + + reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); + + if (power_up) + reg_val |= DP_PADCTL_PAD_CAL_PD_POWERUP; + else + reg_val &= ~DP_PADCTL_PAD_CAL_PD_POWERUP; + + tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val); +} + +static void tegra_dc_sor_config_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div, + u32 pwm_dutycycle) +{ + tegra_sor_writel(sor, PWM_DIV, pwm_div); + tegra_sor_writel(sor, PWM_CTL, + (pwm_dutycycle & PWM_CTL_DUTY_CYCLE_MASK) | + PWM_CTL_SETTING_NEW_TRIGGER); + + if (tegra_dc_sor_poll_register(sor, PWM_CTL, + PWM_CTL_SETTING_NEW_SHIFT, + PWM_CTL_SETTING_NEW_DONE, + 100, TEGRA_SOR_TIMEOUT_MS)) { + debug("dp: timeout while waiting for SOR PWM setting\n"); + } +} + +static void tegra_dc_sor_set_dp_mode(struct udevice *dev, + const struct tegra_dp_link_config *link_cfg) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg_val; + + tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw); + + tegra_dc_sor_set_dp_linkctl(dev, 1, training_pattern_none, link_cfg); + reg_val = tegra_sor_readl(sor, DP_CONFIG(sor->portnum)); + reg_val &= ~DP_CONFIG_WATERMARK_MASK; + reg_val |= link_cfg->watermark; + reg_val &= ~DP_CONFIG_ACTIVESYM_COUNT_MASK; + reg_val |= (link_cfg->active_count << + DP_CONFIG_ACTIVESYM_COUNT_SHIFT); + reg_val &= ~DP_CONFIG_ACTIVESYM_FRAC_MASK; + reg_val |= (link_cfg->active_frac << + DP_CONFIG_ACTIVESYM_FRAC_SHIFT); + if (link_cfg->activepolarity) + reg_val |= DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE; + else + reg_val &= ~DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE; + reg_val |= (DP_CONFIG_ACTIVESYM_CNTL_ENABLE | + DP_CONFIG_RD_RESET_VAL_NEGATIVE); + + tegra_sor_writel(sor, DP_CONFIG(sor->portnum), reg_val); + + /* program h/vblank sym */ + tegra_sor_write_field(sor, DP_AUDIO_HBLANK_SYMBOLS, + DP_AUDIO_HBLANK_SYMBOLS_MASK, + link_cfg->hblank_sym); + + tegra_sor_write_field(sor, DP_AUDIO_VBLANK_SYMBOLS, + DP_AUDIO_VBLANK_SYMBOLS_MASK, + link_cfg->vblank_sym); +} + +static inline void tegra_dc_sor_super_update(struct tegra_dc_sor_data *sor) +{ + tegra_sor_writel(sor, SUPER_STATE0, 0); + tegra_sor_writel(sor, SUPER_STATE0, 1); + tegra_sor_writel(sor, SUPER_STATE0, 0); +} + +static inline void tegra_dc_sor_update(struct tegra_dc_sor_data *sor) +{ + tegra_sor_writel(sor, STATE0, 0); + tegra_sor_writel(sor, STATE0, 1); + tegra_sor_writel(sor, STATE0, 0); +} + +static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up) +{ + u32 reg_val; + void *pmc_base = sor->pmc_base; + + if (up) { + writel(APBDEV_PMC_DPD_SAMPLE_ON_ENABLE, + pmc_base + APBDEV_PMC_DPD_SAMPLE); + writel(10, pmc_base + APBDEV_PMC_SEL_DPD_TIM); + } + + reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_REQ); + reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON || + APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK); + + reg_val = up ? APBDEV_PMC_IO_DPD2_REQ_LVDS_ON | + APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF : + APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF | + APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON; + + writel(reg_val, pmc_base + APBDEV_PMC_IO_DPD2_REQ); + + /* Polling */ + u32 temp = 10 * 1000; + do { + udelay(20); + reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_STATUS); + if (temp > 20) + temp -= 20; + else + break; + } while ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0); + + if ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0) { + debug("PMC_IO_DPD2 polling failed (0x%x)\n", reg_val); + return -EIO; + } + + if (up) { + writel(APBDEV_PMC_DPD_SAMPLE_ON_DISABLE, + pmc_base + APBDEV_PMC_DPD_SAMPLE); + } + + return 0; +} + +void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg_val; + + reg_val = tegra_sor_readl(sor, DP_SPARE(sor->portnum)); + if (is_int) + reg_val |= DP_SPARE_PANEL_INTERNAL; + else + reg_val &= ~DP_SPARE_PANEL_INTERNAL; + + reg_val |= DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK | + DP_SPARE_SEQ_ENABLE_YES; + tegra_sor_writel(sor, DP_SPARE(sor->portnum), reg_val); +} + +void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw, + u8 *lane_count) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg_val; + + reg_val = tegra_sor_readl(sor, CLK_CNTRL); + *link_bw = (reg_val & CLK_CNTRL_DP_LINK_SPEED_MASK) + >> CLK_CNTRL_DP_LINK_SPEED_SHIFT; + reg_val = tegra_sor_readl(sor, + DP_LINKCTL(sor->portnum)); + + switch (reg_val & DP_LINKCTL_LANECOUNT_MASK) { + case DP_LINKCTL_LANECOUNT_ZERO: + *lane_count = 0; + break; + case DP_LINKCTL_LANECOUNT_ONE: + *lane_count = 1; + break; + case DP_LINKCTL_LANECOUNT_TWO: + *lane_count = 2; + break; + case DP_LINKCTL_LANECOUNT_FOUR: + *lane_count = 4; + break; + default: + printf("Unknown lane count\n"); + } +} + +void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + + tegra_sor_write_field(sor, CLK_CNTRL, + CLK_CNTRL_DP_LINK_SPEED_MASK, + link_bw << CLK_CNTRL_DP_LINK_SPEED_SHIFT); +} + +void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg_val; + + reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum)); + reg_val &= ~DP_LINKCTL_LANECOUNT_MASK; + switch (lane_count) { + case 0: + break; + case 1: + reg_val |= DP_LINKCTL_LANECOUNT_ONE; + break; + case 2: + reg_val |= DP_LINKCTL_LANECOUNT_TWO; + break; + case 4: + reg_val |= DP_LINKCTL_LANECOUNT_FOUR; + break; + default: + /* 0 should be handled earlier. */ + printf("dp: Invalid lane count %d\n", lane_count); + return; + } + tegra_sor_writel(sor, DP_LINKCTL(sor->portnum), reg_val); +} + +/* + * The SOR power sequencer does not work for t124 so SW has to + * go through the power sequence manually + * Power up steps from spec: + * STEP PDPORT PDPLL PDBG PLLVCOD PLLCAPD E_DPD PDCAL + * 1 1 1 1 1 1 1 1 + * 2 1 1 1 1 1 0 1 + * 3 1 1 0 1 1 0 1 + * 4 1 0 0 0 0 0 1 + * 5 0 0 0 0 0 0 1 + */ +static int tegra_dc_sor_power_up(struct udevice *dev, int is_lvds) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 reg; + int ret; + + if (sor->power_is_up) + return 0; + + /* + * If for some reason it is already powered up, don't do it again. + * This can happen if U-Boot is the secondary boot loader. + */ + reg = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); + if (reg & DP_PADCTL_PD_TXD_0_NO) + return 0; + + /* Set link bw */ + tegra_dc_sor_set_link_bandwidth(dev, is_lvds ? + CLK_CNTRL_DP_LINK_SPEED_LVDS : + CLK_CNTRL_DP_LINK_SPEED_G1_62); + + /* step 1 */ + tegra_sor_write_field(sor, PLL2, + PLL2_AUX7_PORT_POWERDOWN_MASK | /* PDPORT */ + PLL2_AUX6_BANDGAP_POWERDOWN_MASK | /* PDBG */ + PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, /* PLLCAPD */ + PLL2_AUX7_PORT_POWERDOWN_ENABLE | + PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE | + PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE); + tegra_sor_write_field(sor, PLL0, PLL0_PWR_MASK | /* PDPLL */ + PLL0_VCOPD_MASK, /* PLLVCOPD */ + PLL0_PWR_OFF | PLL0_VCOPD_ASSERT); + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), + DP_PADCTL_PAD_CAL_PD_POWERDOWN, /* PDCAL */ + DP_PADCTL_PAD_CAL_PD_POWERDOWN); + + /* step 2 */ + ret = tegra_dc_sor_io_set_dpd(sor, 1); + if (ret) + return ret; + udelay(15); + + /* step 3 */ + tegra_sor_write_field(sor, PLL2, + PLL2_AUX6_BANDGAP_POWERDOWN_MASK, + PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE); + udelay(25); + + /* step 4 */ + tegra_sor_write_field(sor, PLL0, + PLL0_PWR_MASK | /* PDPLL */ + PLL0_VCOPD_MASK, /* PLLVCOPD */ + PLL0_PWR_ON | PLL0_VCOPD_RESCIND); + /* PLLCAPD */ + tegra_sor_write_field(sor, PLL2, + PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, + PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE); + udelay(225); + + /* step 5 PDPORT */ + tegra_sor_write_field(sor, PLL2, + PLL2_AUX7_PORT_POWERDOWN_MASK, + PLL2_AUX7_PORT_POWERDOWN_DISABLE); + + sor->power_is_up = 1; + + return 0; +} + +#if DEBUG_SOR +static void dump_sor_reg(struct tegra_dc_sor_data *sor) +{ +#define DUMP_REG(a) printk(BIOS_INFO, \ + "%-32s %03x %08x\n", \ + #a, a, tegra_sor_readl(sor, a)); + + DUMP_REG(SUPER_STATE0); + DUMP_REG(SUPER_STATE1); + DUMP_REG(STATE0); + DUMP_REG(STATE1); + DUMP_REG(NV_HEAD_STATE0(0)); + DUMP_REG(NV_HEAD_STATE0(1)); + DUMP_REG(NV_HEAD_STATE1(0)); + DUMP_REG(NV_HEAD_STATE1(1)); + DUMP_REG(NV_HEAD_STATE2(0)); + DUMP_REG(NV_HEAD_STATE2(1)); + DUMP_REG(NV_HEAD_STATE3(0)); + DUMP_REG(NV_HEAD_STATE3(1)); + DUMP_REG(NV_HEAD_STATE4(0)); + DUMP_REG(NV_HEAD_STATE4(1)); + DUMP_REG(NV_HEAD_STATE5(0)); + DUMP_REG(NV_HEAD_STATE5(1)); + DUMP_REG(CRC_CNTRL); + DUMP_REG(CLK_CNTRL); + DUMP_REG(CAP); + DUMP_REG(PWR); + DUMP_REG(TEST); + DUMP_REG(PLL0); + DUMP_REG(PLL1); + DUMP_REG(PLL2); + DUMP_REG(PLL3); + DUMP_REG(CSTM); + DUMP_REG(LVDS); + DUMP_REG(CRCA); + DUMP_REG(CRCB); + DUMP_REG(SEQ_CTL); + DUMP_REG(LANE_SEQ_CTL); + DUMP_REG(SEQ_INST(0)); + DUMP_REG(SEQ_INST(1)); + DUMP_REG(SEQ_INST(2)); + DUMP_REG(SEQ_INST(3)); + DUMP_REG(SEQ_INST(4)); + DUMP_REG(SEQ_INST(5)); + DUMP_REG(SEQ_INST(6)); + DUMP_REG(SEQ_INST(7)); + DUMP_REG(SEQ_INST(8)); + DUMP_REG(PWM_DIV); + DUMP_REG(PWM_CTL); + DUMP_REG(MSCHECK); + DUMP_REG(XBAR_CTRL); + DUMP_REG(DP_LINKCTL(0)); + DUMP_REG(DP_LINKCTL(1)); + DUMP_REG(DC(0)); + DUMP_REG(DC(1)); + DUMP_REG(LANE_DRIVE_CURRENT(0)); + DUMP_REG(PR(0)); + DUMP_REG(LANE4_PREEMPHASIS(0)); + DUMP_REG(POSTCURSOR(0)); + DUMP_REG(DP_CONFIG(0)); + DUMP_REG(DP_CONFIG(1)); + DUMP_REG(DP_MN(0)); + DUMP_REG(DP_MN(1)); + DUMP_REG(DP_PADCTL(0)); + DUMP_REG(DP_PADCTL(1)); + DUMP_REG(DP_DEBUG(0)); + DUMP_REG(DP_DEBUG(1)); + DUMP_REG(DP_SPARE(0)); + DUMP_REG(DP_SPARE(1)); + DUMP_REG(DP_TPG); + + return; +} +#endif + +static void tegra_dc_sor_config_panel(struct tegra_dc_sor_data *sor, + int is_lvds, + const struct tegra_dp_link_config *link_cfg, + const struct display_timing *timing) +{ + const int head_num = 0; + u32 reg_val = STATE1_ASY_OWNER_HEAD0 << head_num; + u32 vtotal, htotal; + u32 vsync_end, hsync_end; + u32 vblank_end, hblank_end; + u32 vblank_start, hblank_start; + + reg_val |= is_lvds ? STATE1_ASY_PROTOCOL_LVDS_CUSTOM : + STATE1_ASY_PROTOCOL_DP_A; + reg_val |= STATE1_ASY_SUBOWNER_NONE | + STATE1_ASY_CRCMODE_COMPLETE_RASTER; + + reg_val |= STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE; + reg_val |= STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE; + reg_val |= (link_cfg->bits_per_pixel > 18) ? + STATE1_ASY_PIXELDEPTH_BPP_24_444 : + STATE1_ASY_PIXELDEPTH_BPP_18_444; + + tegra_sor_writel(sor, STATE1, reg_val); + + /* + * Skipping programming NV_HEAD_STATE0, assuming: + * interlacing: PROGRESSIVE, dynamic range: VESA, colorspace: RGB + */ + vtotal = timing->vsync_len.typ + timing->vback_porch.typ + + timing->vactive.typ + timing->vfront_porch.typ; + htotal = timing->hsync_len.typ + timing->hback_porch.typ + + timing->hactive.typ + timing->hfront_porch.typ; + + tegra_sor_writel(sor, NV_HEAD_STATE1(head_num), + vtotal << NV_HEAD_STATE1_VTOTAL_SHIFT | + htotal << NV_HEAD_STATE1_HTOTAL_SHIFT); + + vsync_end = timing->vsync_len.typ - 1; + hsync_end = timing->hsync_len.typ - 1; + tegra_sor_writel(sor, NV_HEAD_STATE2(head_num), + vsync_end << NV_HEAD_STATE2_VSYNC_END_SHIFT | + hsync_end << NV_HEAD_STATE2_HSYNC_END_SHIFT); + + vblank_end = vsync_end + timing->vback_porch.typ; + hblank_end = hsync_end + timing->hback_porch.typ; + tegra_sor_writel(sor, NV_HEAD_STATE3(head_num), + vblank_end << NV_HEAD_STATE3_VBLANK_END_SHIFT | + hblank_end << NV_HEAD_STATE3_HBLANK_END_SHIFT); + + vblank_start = vblank_end + timing->vactive.typ; + hblank_start = hblank_end + timing->hactive.typ; + tegra_sor_writel(sor, NV_HEAD_STATE4(head_num), + vblank_start << NV_HEAD_STATE4_VBLANK_START_SHIFT | + hblank_start << NV_HEAD_STATE4_HBLANK_START_SHIFT); + + /* TODO: adding interlace mode support */ + tegra_sor_writel(sor, NV_HEAD_STATE5(head_num), 0x1); + + tegra_sor_write_field(sor, CSTM, + CSTM_ROTCLK_DEFAULT_MASK | + CSTM_LVDS_EN_ENABLE, + 2 << CSTM_ROTCLK_SHIFT | + (is_lvds ? CSTM_LVDS_EN_ENABLE : + CSTM_LVDS_EN_DISABLE)); + + tegra_dc_sor_config_pwm(sor, 1024, 1024); +} + +static void tegra_dc_sor_enable_dc(struct dc_ctlr *disp_ctrl) +{ + u32 reg_val = readl(&disp_ctrl->cmd.state_access); + + writel(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access); + writel(VSYNC_H_POSITION(1), &disp_ctrl->disp.disp_timing_opt); + + /* Enable DC now - otherwise pure text console may not show. */ + writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT, + &disp_ctrl->cmd.disp_cmd); + writel(reg_val, &disp_ctrl->cmd.state_access); +} + +int tegra_dc_sor_enable_dp(struct udevice *dev, + const struct tegra_dp_link_config *link_cfg) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + int ret; + + tegra_sor_write_field(sor, CLK_CNTRL, + CLK_CNTRL_DP_CLK_SEL_MASK, + CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK); + + tegra_sor_write_field(sor, PLL2, + PLL2_AUX6_BANDGAP_POWERDOWN_MASK, + PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE); + udelay(25); + + tegra_sor_write_field(sor, PLL3, + PLL3_PLLVDD_MODE_MASK, + PLL3_PLLVDD_MODE_V3_3); + tegra_sor_writel(sor, PLL0, + 0xf << PLL0_ICHPMP_SHFIT | + 0x3 << PLL0_VCOCAP_SHIFT | + PLL0_PLLREG_LEVEL_V45 | + PLL0_RESISTORSEL_EXT | + PLL0_PWR_ON | PLL0_VCOPD_RESCIND); + tegra_sor_write_field(sor, PLL2, + PLL2_AUX1_SEQ_MASK | + PLL2_AUX9_LVDSEN_OVERRIDE | + PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, + PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE | + PLL2_AUX9_LVDSEN_OVERRIDE | + PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE); + tegra_sor_writel(sor, PLL1, PLL1_TERM_COMPOUT_HIGH | + PLL1_TMDS_TERM_ENABLE); + + if (tegra_dc_sor_poll_register(sor, PLL2, + PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, + PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE, + 100, TEGRA_SOR_TIMEOUT_MS)) { + printf("DP failed to lock PLL\n"); + return -EIO; + } + + tegra_sor_write_field(sor, PLL2, PLL2_AUX2_MASK | + PLL2_AUX7_PORT_POWERDOWN_MASK, + PLL2_AUX2_OVERRIDE_POWERDOWN | + PLL2_AUX7_PORT_POWERDOWN_DISABLE); + + ret = tegra_dc_sor_power_up(dev, 0); + if (ret) { + debug("DP failed to power up\n"); + return ret; + } + + /* re-enable SOR clock */ + clock_sor_enable_edp_clock(); + + /* Power up lanes */ + tegra_dc_sor_power_dplanes(dev, link_cfg->lane_count, 1); + + tegra_dc_sor_set_dp_mode(dev, link_cfg); + debug("%s ret\n", __func__); + + return 0; +} + +int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *dev, + const struct tegra_dp_link_config *link_cfg, + const struct display_timing *timing) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + struct dc_ctlr *disp_ctrl; + u32 reg_val; + + /* Use the first display controller */ + debug("%s\n", __func__); + disp_ctrl = dev_read_addr_ptr(dc_dev); + + tegra_dc_sor_enable_dc(disp_ctrl); + tegra_dc_sor_config_panel(sor, 0, link_cfg, timing); + + writel(0x9f00, &disp_ctrl->cmd.state_ctrl); + writel(0x9f, &disp_ctrl->cmd.state_ctrl); + + writel(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | + PW4_ENABLE | PM0_ENABLE | PM1_ENABLE, + &disp_ctrl->cmd.disp_pow_ctrl); + + reg_val = tegra_sor_readl(sor, TEST); + if (reg_val & TEST_ATTACHED_TRUE) + return -EEXIST; + + tegra_sor_writel(sor, SUPER_STATE1, + SUPER_STATE1_ATTACHED_NO); + + /* + * Enable display2sor clock at least 2 cycles before DC start, + * to clear sor internal valid signal. + */ + writel(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt); + writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl); + writel(0, &disp_ctrl->disp.disp_win_opt); + writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl); + + /* Attach head */ + tegra_dc_sor_update(sor); + tegra_sor_writel(sor, SUPER_STATE1, + SUPER_STATE1_ATTACHED_YES); + tegra_sor_writel(sor, SUPER_STATE1, + SUPER_STATE1_ATTACHED_YES | + SUPER_STATE1_ASY_HEAD_OP_AWAKE | + SUPER_STATE1_ASY_ORMODE_NORMAL); + tegra_dc_sor_super_update(sor); + + /* Enable dc */ + reg_val = readl(&disp_ctrl->cmd.state_access); + writel(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access); + writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT, + &disp_ctrl->cmd.disp_cmd); + writel(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt); + writel(reg_val, &disp_ctrl->cmd.state_access); + + if (tegra_dc_sor_poll_register(sor, TEST, + TEST_ACT_HEAD_OPMODE_DEFAULT_MASK, + TEST_ACT_HEAD_OPMODE_AWAKE, + 100, + TEGRA_SOR_ATTACH_TIMEOUT_MS)) { + printf("dc timeout waiting for OPMOD = AWAKE\n"); + return -ETIMEDOUT; + } else { + debug("%s: sor is attached\n", __func__); + } + +#if DEBUG_SOR + dump_sor_reg(sor); +#endif + debug("%s: ret=%d\n", __func__, 0); + + return 0; +} + +void tegra_dc_sor_set_lane_parm(struct udevice *dev, + const struct tegra_dp_link_config *link_cfg) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + + tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), + link_cfg->drive_current); + tegra_sor_writel(sor, PR(sor->portnum), + link_cfg->preemphasis); + tegra_sor_writel(sor, POSTCURSOR(sor->portnum), + link_cfg->postcursor); + tegra_sor_writel(sor, LVDS, 0); + + tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw); + tegra_dc_sor_set_lane_count(dev, link_cfg->lane_count); + + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), + DP_PADCTL_TX_PU_ENABLE | + DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK, + DP_PADCTL_TX_PU_ENABLE | + 2 << DP_PADCTL_TX_PU_VALUE_SHIFT); + + /* Precharge */ + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0xf0); + udelay(20); + + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0x0); +} + +int tegra_dc_sor_set_voltage_swing(struct udevice *dev, + const struct tegra_dp_link_config *link_cfg) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 drive_current = 0; + u32 pre_emphasis = 0; + + /* Set to a known-good pre-calibrated setting */ + switch (link_cfg->link_bw) { + case SOR_LINK_SPEED_G1_62: + case SOR_LINK_SPEED_G2_7: + drive_current = 0x13131313; + pre_emphasis = 0; + break; + case SOR_LINK_SPEED_G5_4: + debug("T124 does not support 5.4G link clock.\n"); + default: + debug("Invalid sor link bandwidth: %d\n", link_cfg->link_bw); + return -ENOLINK; + } + + tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), drive_current); + tegra_sor_writel(sor, PR(sor->portnum), pre_emphasis); + + return 0; +} + +void tegra_dc_sor_power_down_unused_lanes(struct udevice *dev, + const struct tegra_dp_link_config *link_cfg) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 pad_ctrl = 0; + int err = 0; + + switch (link_cfg->lane_count) { + case 4: + pad_ctrl = DP_PADCTL_PD_TXD_0_NO | + DP_PADCTL_PD_TXD_1_NO | + DP_PADCTL_PD_TXD_2_NO | + DP_PADCTL_PD_TXD_3_NO; + break; + case 2: + pad_ctrl = DP_PADCTL_PD_TXD_0_NO | + DP_PADCTL_PD_TXD_1_NO | + DP_PADCTL_PD_TXD_2_YES | + DP_PADCTL_PD_TXD_3_YES; + break; + case 1: + pad_ctrl = DP_PADCTL_PD_TXD_0_NO | + DP_PADCTL_PD_TXD_1_YES | + DP_PADCTL_PD_TXD_2_YES | + DP_PADCTL_PD_TXD_3_YES; + break; + default: + printf("Invalid sor lane count: %u\n", link_cfg->lane_count); + return; + } + + pad_ctrl |= DP_PADCTL_PAD_CAL_PD_POWERDOWN; + tegra_sor_writel(sor, DP_PADCTL(sor->portnum), pad_ctrl); + + err = tegra_dc_sor_enable_lane_sequencer(sor, 0, 0); + if (err) { + debug("Wait for lane power down failed: %d\n", err); + return; + } +} + +int tegra_sor_precharge_lanes(struct udevice *dev, + const struct tegra_dp_link_config *cfg) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + u32 val = 0; + + switch (cfg->lane_count) { + case 4: + val |= (DP_PADCTL_PD_TXD_3_NO | + DP_PADCTL_PD_TXD_2_NO); + /* fall through */ + case 2: + val |= DP_PADCTL_PD_TXD_1_NO; + /* fall through */ + case 1: + val |= DP_PADCTL_PD_TXD_0_NO; + break; + default: + debug("dp: invalid lane number %d\n", cfg->lane_count); + return -EINVAL; + } + + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), + (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT), + (val << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT)); + udelay(100); + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), + (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT), + 0); + + return 0; +} + +static void tegra_dc_sor_enable_sor(struct dc_ctlr *disp_ctrl, bool enable) +{ + u32 reg_val = readl(&disp_ctrl->disp.disp_win_opt); + + reg_val = enable ? reg_val | SOR_ENABLE : reg_val & ~SOR_ENABLE; + writel(reg_val, &disp_ctrl->disp.disp_win_opt); +} + +int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *dev) +{ + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + int dc_reg_ctx[DC_REG_SAVE_SPACE]; + struct dc_ctlr *disp_ctrl; + unsigned long dc_int_mask; + int ret; + + debug("%s\n", __func__); + /* Use the first display controller */ + disp_ctrl = dev_read_addr_ptr(dev); + + /* Sleep mode */ + tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP | + SUPER_STATE1_ASY_ORMODE_SAFE | + SUPER_STATE1_ATTACHED_YES); + tegra_dc_sor_super_update(sor); + + tegra_dc_sor_disable_win_short_raster(disp_ctrl, dc_reg_ctx); + + if (tegra_dc_sor_poll_register(sor, TEST, + TEST_ACT_HEAD_OPMODE_DEFAULT_MASK, + TEST_ACT_HEAD_OPMODE_SLEEP, 100, + TEGRA_SOR_ATTACH_TIMEOUT_MS)) { + debug("dc timeout waiting for OPMOD = SLEEP\n"); + ret = -ETIMEDOUT; + goto err; + } + + tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP | + SUPER_STATE1_ASY_ORMODE_SAFE | + SUPER_STATE1_ATTACHED_NO); + + /* Mask DC interrupts during the 2 dummy frames required for detach */ + dc_int_mask = readl(&disp_ctrl->cmd.int_mask); + writel(0, &disp_ctrl->cmd.int_mask); + + /* Stop DC->SOR path */ + tegra_dc_sor_enable_sor(disp_ctrl, false); + ret = tegra_dc_sor_general_act(disp_ctrl); + if (ret) + goto err; + + /* Stop DC */ + writel(CTRL_MODE_STOP << CTRL_MODE_SHIFT, &disp_ctrl->cmd.disp_cmd); + ret = tegra_dc_sor_general_act(disp_ctrl); + if (ret) + goto err; + + tegra_dc_sor_restore_win_and_raster(disp_ctrl, dc_reg_ctx); + + writel(dc_int_mask, &disp_ctrl->cmd.int_mask); + + return 0; +err: + debug("%s: ret=%d\n", __func__, ret); + + return ret; +} + +static int tegra_sor_set_backlight(struct udevice *dev, int percent) +{ + struct tegra_dc_sor_data *priv = dev_get_priv(dev); + int ret; + + ret = panel_enable_backlight(priv->panel); + if (ret) { + debug("sor: Cannot enable panel backlight\n"); + return ret; + } + + return 0; +} + +static int tegra_sor_of_to_plat(struct udevice *dev) +{ + struct tegra_dc_sor_data *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_read_addr_ptr(dev); + + priv->pmc_base = (void *)syscon_get_first_range(TEGRA_SYSCON_PMC); + if (IS_ERR(priv->pmc_base)) + return PTR_ERR(priv->pmc_base); + + ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "nvidia,panel", + &priv->panel); + if (ret) { + debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, + dev->name, ret); + return ret; + } + + return 0; +} + +static const struct video_bridge_ops tegra_sor_ops = { + .set_backlight = tegra_sor_set_backlight, +}; + +static const struct udevice_id tegra_sor_ids[] = { + { .compatible = "nvidia,tegra124-sor" }, + { } +}; + +U_BOOT_DRIVER(sor_tegra) = { + .name = "sor_tegra", + .id = UCLASS_VIDEO_BRIDGE, + .of_match = tegra_sor_ids, + .of_to_plat = tegra_sor_of_to_plat, + .ops = &tegra_sor_ops, + .priv_auto = sizeof(struct tegra_dc_sor_data), +}; diff --git a/drivers/video/tegra/tegra124/sor.h b/drivers/video/tegra/tegra124/sor.h new file mode 100644 index 00000000000..2fc9a38267d --- /dev/null +++ b/drivers/video/tegra/tegra124/sor.h @@ -0,0 +1,914 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2011-2013, NVIDIA Corporation. + */ + +#ifndef _VIDEO_TEGRA124_SOR_H +#define _VIDEO_TEGRA124_SOR_H + +#define SUPER_STATE0 0x1 +#define SUPER_STATE0_UPDATE_SHIFT 0 +#define SUPER_STATE0_UPDATE_DEFAULT_MASK 0x1 +#define SUPER_STATE1 0x2 +#define SUPER_STATE1_ATTACHED_SHIFT 3 +#define SUPER_STATE1_ATTACHED_NO (0 << 3) +#define SUPER_STATE1_ATTACHED_YES (1 << 3) +#define SUPER_STATE1_ASY_ORMODE_SHIFT 2 +#define SUPER_STATE1_ASY_ORMODE_SAFE (0 << 2) +#define SUPER_STATE1_ASY_ORMODE_NORMAL (1 << 2) +#define SUPER_STATE1_ASY_HEAD_OP_SHIFT 0 +#define SUPER_STATE1_ASY_HEAD_OP_DEFAULT_MASK 0x3 +#define SUPER_STATE1_ASY_HEAD_OP_SLEEP 0 +#define SUPER_STATE1_ASY_HEAD_OP_SNOOZE 1 +#define SUPER_STATE1_ASY_HEAD_OP_AWAKE 2 +#define STATE0 0x3 +#define STATE0_UPDATE_SHIFT 0 +#define STATE0_UPDATE_DEFAULT_MASK 0x1 +#define STATE1 0x4 +#define STATE1_ASY_PIXELDEPTH_SHIFT 17 +#define STATE1_ASY_PIXELDEPTH_DEFAULT_MASK (0xf << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_16_422 (1 << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_18_444 (2 << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_20_422 (3 << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_24_422 (4 << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_24_444 (5 << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_30_444 (6 << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_32_422 (7 << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_36_444 (8 << 17) +#define STATE1_ASY_PIXELDEPTH_BPP_48_444 (9 << 17) +#define STATE1_ASY_REPLICATE_SHIFT 15 +#define STATE1_ASY_REPLICATE_DEFAULT_MASK (3 << 15) +#define STATE1_ASY_REPLICATE_OFF (0 << 15) +#define STATE1_ASY_REPLICATE_X2 (1 << 15) +#define STATE1_ASY_REPLICATE_X4 (2 << 15) +#define STATE1_ASY_DEPOL_SHIFT 14 +#define STATE1_ASY_DEPOL_DEFAULT_MASK (1 << 14) +#define STATE1_ASY_DEPOL_POSITIVE_TRUE (0 << 14) +#define STATE1_ASY_DEPOL_NEGATIVE_TRUE (1 << 14) +#define STATE1_ASY_VSYNCPOL_SHIFT 13 +#define STATE1_ASY_VSYNCPOL_DEFAULT_MASK (1 << 13) +#define STATE1_ASY_VSYNCPOL_POSITIVE_TRUE (0 << 13) +#define STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE (1 << 13) +#define STATE1_ASY_HSYNCPOL_SHIFT 12 +#define STATE1_ASY_HSYNCPOL_DEFAULT_MASK (1 << 12) +#define STATE1_ASY_HSYNCPOL_POSITIVE_TRUE (0 << 12) +#define STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE (1 << 12) +#define STATE1_ASY_PROTOCOL_SHIFT 8 +#define STATE1_ASY_PROTOCOL_DEFAULT_MASK (0xf << 8) +#define STATE1_ASY_PROTOCOL_LVDS_CUSTOM (0 << 8) +#define STATE1_ASY_PROTOCOL_DP_A (8 << 8) +#define STATE1_ASY_PROTOCOL_DP_B (9 << 8) +#define STATE1_ASY_PROTOCOL_CUSTOM (15 << 8) +#define STATE1_ASY_CRCMODE_SHIFT 6 +#define STATE1_ASY_CRCMODE_DEFAULT_MASK (3 << 6) +#define STATE1_ASY_CRCMODE_ACTIVE_RASTER (0 << 6) +#define STATE1_ASY_CRCMODE_COMPLETE_RASTER (1 << 6) +#define STATE1_ASY_CRCMODE_NON_ACTIVE_RASTER (2 << 6) +#define STATE1_ASY_SUBOWNER_SHIFT 4 +#define STATE1_ASY_SUBOWNER_DEFAULT_MASK (3 << 4) +#define STATE1_ASY_SUBOWNER_NONE (0 << 4) +#define STATE1_ASY_SUBOWNER_SUBHEAD0 (1 << 4) +#define STATE1_ASY_SUBOWNER_SUBHEAD1 (2 << 4) +#define STATE1_ASY_SUBOWNER_BOTH (3 << 4) +#define STATE1_ASY_OWNER_SHIFT 0 +#define STATE1_ASY_OWNER_DEFAULT_MASK 0xf +#define STATE1_ASY_OWNER_NONE 0 +#define STATE1_ASY_OWNER_HEAD0 1 +#define STATE1_ASY_OWNER_HEAD1 2 +#define NV_HEAD_STATE0(i) 0x5 +#define NV_HEAD_STATE0_INTERLACED_SHIFT 4 +#define NV_HEAD_STATE0_INTERLACED_DEFAULT_MASK (3 << 4) +#define NV_HEAD_STATE0_INTERLACED_PROGRESSIVE (0 << 4) +#define NV_HEAD_STATE0_INTERLACED_INTERLACED (1 << 4) +#define NV_HEAD_STATE0_RANGECOMPRESS_SHIFT 3 +#define NV_HEAD_STATE0_RANGECOMPRESS_DEFAULT_MASK (1 << 3) +#define NV_HEAD_STATE0_RANGECOMPRESS_DISABLE (0 << 3) +#define NV_HEAD_STATE0_RANGECOMPRESS_ENABLE (1 << 3) +#define NV_HEAD_STATE0_DYNRANGE_SHIFT 2 +#define NV_HEAD_STATE0_DYNRANGE_DEFAULT_MASK (1 << 2) +#define NV_HEAD_STATE0_DYNRANGE_VESA (0 << 2) +#define NV_HEAD_STATE0_DYNRANGE_CEA (1 << 2) +#define NV_HEAD_STATE0_COLORSPACE_SHIFT 0 +#define NV_HEAD_STATE0_COLORSPACE_DEFAULT_MASK 0x3 +#define NV_HEAD_STATE0_COLORSPACE_RGB 0 +#define NV_HEAD_STATE0_COLORSPACE_YUV_601 1 +#define NV_HEAD_STATE0_COLORSPACE_YUV_709 2 +#define NV_HEAD_STATE1(i) (7 + i) +#define NV_HEAD_STATE1_VTOTAL_SHIFT 16 +#define NV_HEAD_STATE1_VTOTAL_DEFAULT_MASK (0x7fff << 16) +#define NV_HEAD_STATE1_HTOTAL_SHIFT 0 +#define NV_HEAD_STATE1_HTOTAL_DEFAULT_MASK 0x7fff +#define NV_HEAD_STATE2(i) (9 + i) +#define NV_HEAD_STATE2_VSYNC_END_SHIFT 16 +#define NV_HEAD_STATE2_VSYNC_END_DEFAULT_MASK (0x7fff << 16) +#define NV_HEAD_STATE2_HSYNC_END_SHIFT 0 +#define NV_HEAD_STATE2_HSYNC_END_DEFAULT_MASK 0x7fff +#define NV_HEAD_STATE3(i) (0xb + i) +#define NV_HEAD_STATE3_VBLANK_END_SHIFT 16 +#define NV_HEAD_STATE3_VBLANK_END_DEFAULT_MASK (0x7fff << 16) +#define NV_HEAD_STATE3_HBLANK_END_SHIFT 0 +#define NV_HEAD_STATE3_HBLANK_END_DEFAULT_MASK 0x7fff +#define NV_HEAD_STATE4(i) (0xd + i) +#define NV_HEAD_STATE4_VBLANK_START_SHIFT 16 +#define NV_HEAD_STATE4_VBLANK_START_DEFAULT_MASK (0x7fff << 16) +#define NV_HEAD_STATE4_HBLANK_START_SHIFT 0 +#define NV_HEAD_STATE4_HBLANK_START_DEFAULT_MASK 0x7fff +#define NV_HEAD_STATE5(i) (0xf + i) +#define CRC_CNTRL 0x11 +#define CRC_CNTRL_ARM_CRC_ENABLE_SHIFT 0 +#define CRC_CNTRL_ARM_CRC_ENABLE_NO 0 +#define CRC_CNTRL_ARM_CRC_ENABLE_YES 1 +#define CRC_CNTRL_ARM_CRC_ENABLE_DIS 0 +#define CRC_CNTRL_ARM_CRC_ENABLE_EN 1 +#define CLK_CNTRL 0x13 +#define CLK_CNTRL_DP_CLK_SEL_SHIFT 0 +#define CLK_CNTRL_DP_CLK_SEL_MASK 0x3 +#define CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK 0 +#define CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK 1 +#define CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK 2 +#define CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK 3 +#define CLK_CNTRL_DP_LINK_SPEED_SHIFT 2 +#define CLK_CNTRL_DP_LINK_SPEED_MASK (0x1f << 2) +#define CLK_CNTRL_DP_LINK_SPEED_G1_62 (6 << 2) +#define CLK_CNTRL_DP_LINK_SPEED_G2_7 (10 << 2) +#define CLK_CNTRL_DP_LINK_SPEED_LVDS (7 << 2) +#define CAP 0x14 +#define CAP_DP_A_SHIFT 24 +#define CAP_DP_A_DEFAULT_MASK (1 << 24) +#define CAP_DP_A_FALSE (0 << 24) +#define CAP_DP_A_TRUE (1 << 24) +#define CAP_DP_B_SHIFT 25 +#define CAP_DP_B_DEFAULT_MASK (1 << 24) +#define CAP_DP_B_FALSE (0 << 24) +#define CAP_DP_B_TRUE (1 << 24) +#define PWR 0x15 +#define PWR_SETTING_NEW_SHIFT 31 +#define PWR_SETTING_NEW_DEFAULT_MASK (1 << 31) +#define PWR_SETTING_NEW_DONE (0 << 31) +#define PWR_SETTING_NEW_PENDING (1 << 31) +#define PWR_SETTING_NEW_TRIGGER (1 << 31) +#define PWR_MODE_SHIFT 28 +#define PWR_MODE_DEFAULT_MASK (1 << 28) +#define PWR_MODE_NORMAL (0 << 28) +#define PWR_MODE_SAFE (1 << 28) +#define PWR_HALT_DELAY_SHIFT 24 +#define PWR_HALT_DELAY_DEFAULT_MASK (1 << 24) +#define PWR_HALT_DELAY_DONE (0 << 24) +#define PWR_HALT_DELAY_ACTIVE (1 << 24) +#define PWR_SAFE_START_SHIFT 17 +#define PWR_SAFE_START_DEFAULT_MASK (1 << 17) +#define PWR_SAFE_START_NORMAL (0 << 17) +#define PWR_SAFE_START_ALT (1 << 17) +#define PWR_SAFE_STATE_SHIFT 16 +#define PWR_SAFE_STATE_DEFAULT_MASK (1 << 16) +#define PWR_SAFE_STATE_PD (0 << 16) +#define PWR_SAFE_STATE_PU (1 << 16) +#define PWR_NORMAL_START_SHIFT 1 +#define PWR_NORMAL_START_DEFAULT_MASK (1 << 1) +#define PWR_NORMAL_START_NORMAL (0 << 16) +#define PWR_NORMAL_START_ALT (1 << 16) +#define PWR_NORMAL_STATE_SHIFT 0 +#define PWR_NORMAL_STATE_DEFAULT_MASK 0x1 +#define PWR_NORMAL_STATE_PD 0 +#define PWR_NORMAL_STATE_PU 1 +#define TEST 0x16 +#define TEST_TESTMUX_SHIFT 24 +#define TEST_TESTMUX_DEFAULT_MASK (0xff << 24) +#define TEST_TESTMUX_AVSS (0 << 24) +#define TEST_TESTMUX_CLOCKIN (2 << 24) +#define TEST_TESTMUX_PLL_VOL (4 << 24) +#define TEST_TESTMUX_SLOWCLKINT (8 << 24) +#define TEST_TESTMUX_AVDD (16 << 24) +#define TEST_TESTMUX_VDDREG (32 << 24) +#define TEST_TESTMUX_REGREF_VDDREG (64 << 24) +#define TEST_TESTMUX_REGREF_AVDD (128 << 24) +#define TEST_CRC_SHIFT 23 +#define TEST_CRC_PRE_SERIALIZE (0 << 23) +#define TEST_CRC_POST_DESERIALIZE (1 << 23) +#define TEST_TPAT_SHIFT 20 +#define TEST_TPAT_DEFAULT_MASK (7 << 20) +#define TEST_TPAT_LO (0 << 20) +#define TEST_TPAT_TDAT (1 << 20) +#define TEST_TPAT_RAMP (2 << 20) +#define TEST_TPAT_WALK (3 << 20) +#define TEST_TPAT_MAXSTEP (4 << 20) +#define TEST_TPAT_MINSTEP (5 << 20) +#define TEST_DSRC_SHIFT 16 +#define TEST_DSRC_DEFAULT_MASK (3 << 16) +#define TEST_DSRC_NORMAL (0 << 16) +#define TEST_DSRC_DEBUG (1 << 16) +#define TEST_DSRC_TGEN (2 << 16) +#define TEST_HEAD_NUMBER_SHIFT 12 +#define TEST_HEAD_NUMBER_DEFAULT_MASK (3 << 12) +#define TEST_HEAD_NUMBER_NONE (0 << 12) +#define TEST_HEAD_NUMBER_HEAD0 (1 << 12) +#define TEST_HEAD_NUMBER_HEAD1 (2 << 12) +#define TEST_ATTACHED_SHIFT 10 +#define TEST_ATTACHED_DEFAULT_MASK (1 << 10) +#define TEST_ATTACHED_FALSE (0 << 10) +#define TEST_ATTACHED_TRUE (1 << 10) +#define TEST_ACT_HEAD_OPMODE_SHIFT 8 +#define TEST_ACT_HEAD_OPMODE_DEFAULT_MASK (3 << 8) +#define TEST_ACT_HEAD_OPMODE_SLEEP (0 << 8) +#define TEST_ACT_HEAD_OPMODE_SNOOZE (1 << 8) +#define TEST_ACT_HEAD_OPMODE_AWAKE (2 << 8) +#define TEST_INVD_SHIFT 6 +#define TEST_INVD_DISABLE (0 << 6) +#define TEST_INVD_ENABLE (1 << 6) +#define TEST_TEST_ENABLE_SHIFT 1 +#define TEST_TEST_ENABLE_DISABLE (0 << 1) +#define TEST_TEST_ENABLE_ENABLE (1 << 1) +#define PLL0 0x17 +#define PLL0_ICHPMP_SHFIT 24 +#define PLL0_ICHPMP_DEFAULT_MASK (0xf << 24) +#define PLL0_VCOCAP_SHIFT 8 +#define PLL0_VCOCAP_DEFAULT_MASK (0xf << 8) +#define PLL0_PLLREG_LEVEL_SHIFT 6 +#define PLL0_PLLREG_LEVEL_DEFAULT_MASK (3 << 6) +#define PLL0_PLLREG_LEVEL_V25 (0 << 6) +#define PLL0_PLLREG_LEVEL_V15 (1 << 6) +#define PLL0_PLLREG_LEVEL_V35 (2 << 6) +#define PLL0_PLLREG_LEVEL_V45 (3 << 6) +#define PLL0_PULLDOWN_SHIFT 5 +#define PLL0_PULLDOWN_DEFAULT_MASK (1 << 5) +#define PLL0_PULLDOWN_DISABLE (0 << 5) +#define PLL0_PULLDOWN_ENABLE (1 << 5) +#define PLL0_RESISTORSEL_SHIFT 4 +#define PLL0_RESISTORSEL_DEFAULT_MASK (1 << 4) +#define PLL0_RESISTORSEL_INT (0 << 4) +#define PLL0_RESISTORSEL_EXT (1 << 4) +#define PLL0_VCOPD_SHIFT 2 +#define PLL0_VCOPD_MASK (1 << 2) +#define PLL0_VCOPD_RESCIND (0 << 2) +#define PLL0_VCOPD_ASSERT (1 << 2) +#define PLL0_PWR_SHIFT 0 +#define PLL0_PWR_MASK 1 +#define PLL0_PWR_ON 0 +#define PLL0_PWR_OFF 1 +#define PLL1_TMDS_TERM_SHIFT 8 +#define PLL1_TMDS_TERM_DISABLE (0 << 8) +#define PLL1_TMDS_TERM_ENABLE (1 << 8) +#define PLL1 0x18 +#define PLL1_TERM_COMPOUT_SHIFT 15 +#define PLL1_TERM_COMPOUT_LOW (0 << 15) +#define PLL1_TERM_COMPOUT_HIGH (1 << 15) +#define PLL2 0x19 +#define PLL2_DCIR_PLL_RESET_SHIFT 0 +#define PLL2_DCIR_PLL_RESET_OVERRIDE (0 << 0) +#define PLL2_DCIR_PLL_RESET_ALLOW (1 << 0) +#define PLL2_AUX1_SHIFT 17 +#define PLL2_AUX1_SEQ_MASK (1 << 17) +#define PLL2_AUX1_SEQ_PLLCAPPD_ALLOW (0 << 17) +#define PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE (1 << 17) +#define PLL2_AUX2_SHIFT 18 +#define PLL2_AUX2_MASK (1 << 18) +#define PLL2_AUX2_OVERRIDE_POWERDOWN (0 << 18) +#define PLL2_AUX2_ALLOW_POWERDOWN (1 << 18) +#define PLL2_AUX6_SHIFT 22 +#define PLL2_AUX6_BANDGAP_POWERDOWN_MASK (1 << 22) +#define PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE (0 << 22) +#define PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE (1 << 22) +#define PLL2_AUX7_SHIFT 23 +#define PLL2_AUX7_PORT_POWERDOWN_MASK (1 << 23) +#define PLL2_AUX7_PORT_POWERDOWN_DISABLE (0 << 23) +#define PLL2_AUX7_PORT_POWERDOWN_ENABLE (1 << 23) +#define PLL2_AUX8_SHIFT 24 +#define PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK (1 << 24) +#define PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE (0 << 24) +#define PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE (1 << 24) +#define PLL2_AUX9_SHIFT 25 +#define PLL2_AUX9_LVDSEN_ALLOW (0 << 25) +#define PLL2_AUX9_LVDSEN_OVERRIDE (1 << 25) +#define PLL3 0x1a +#define PLL3_PLLVDD_MODE_SHIFT 13 +#define PLL3_PLLVDD_MODE_MASK (1 << 13) +#define PLL3_PLLVDD_MODE_V1_8 (0 << 13) +#define PLL3_PLLVDD_MODE_V3_3 (1 << 13) +#define CSTM 0x1b +#define CSTM_ROTDAT_SHIFT 28 +#define CSTM_ROTDAT_DEFAULT_MASK (7 << 28) +#define CSTM_ROTCLK_SHIFT 24 +#define CSTM_ROTCLK_DEFAULT_MASK (0xf << 24) +#define CSTM_LVDS_EN_SHIFT 16 +#define CSTM_LVDS_EN_DISABLE (0 << 16) +#define CSTM_LVDS_EN_ENABLE (1 << 16) +#define CSTM_LINKACTB_SHIFT 15 +#define CSTM_LINKACTB_DISABLE (0 << 15) +#define CSTM_LINKACTB_ENABLE (1 << 15) +#define CSTM_LINKACTA_SHIFT 14 +#define CSTM_LINKACTA_DISABLE (0 << 14) +#define CSTM_LINKACTA_ENABLE (1 << 14) +#define LVDS 0x1c +#define LVDS_ROTDAT_SHIFT 28 +#define LVDS_ROTDAT_DEFAULT_MASK (7 << 28) +#define LVDS_ROTDAT_RST (0 << 28) +#define LVDS_ROTCLK_SHIFT 24 +#define LVDS_ROTCLK_DEFAULT_MASK (0xf << 24) +#define LVDS_ROTCLK_RST (0 << 24) +#define LVDS_PLLDIV_SHIFT 21 +#define LVDS_PLLDIV_DEFAULT_MASK (1 << 21) +#define LVDS_PLLDIV_BY_7 (0 << 21) +#define LVDS_BALANCED_SHIFT 19 +#define LVDS_BALANCED_DEFAULT_MASK (1 << 19) +#define LVDS_BALANCED_DISABLE (0 << 19) +#define LVDS_BALANCED_ENABLE (1 << 19) +#define LVDS_NEW_MODE_SHIFT 18 +#define LVDS_NEW_MODE_DEFAULT_MASK (1 << 18) +#define LVDS_NEW_MODE_DISABLE (0 << 18) +#define LVDS_NEW_MODE_ENABLE (1 << 18) +#define LVDS_DUP_SYNC_SHIFT 17 +#define LVDS_DUP_SYNC_DEFAULT_MASK (1 << 17) +#define LVDS_DUP_SYNC_DISABLE (0 << 17) +#define LVDS_DUP_SYNC_ENABLE (1 << 17) +#define LVDS_LVDS_EN_SHIFT 16 +#define LVDS_LVDS_EN_DEFAULT_MASK (1 << 16) +#define LVDS_LVDS_EN_ENABLE (1 << 16) +#define LVDS_LINKACTB_SHIFT 15 +#define LVDS_LINKACTB_DEFAULT_MASK (1 << 15) +#define LVDS_LINKACTB_DISABLE (0 << 15) +#define LVDS_LINKACTB_ENABLE (1 << 15) +#define LVDS_LINKACTA_SHIFT 14 +#define LVDS_LINKACTA_DEFAULT_MASK (1 << 14) +#define LVDS_LINKACTA_ENABLE (1 << 14) +#define LVDS_MODE_SHIFT 12 +#define LVDS_MODE_DEFAULT_MASK (3 << 12) +#define LVDS_MODE_LVDS (0 << 12) +#define LVDS_UPPER_SHIFT 11 +#define LVDS_UPPER_DEFAULT_MASK (1 << 11) +#define LVDS_UPPER_FALSE (0 << 11) +#define LVDS_UPPER_TRUE (1 << 11) +#define LVDS_PD_TXCB_SHIFT 9 +#define LVDS_PD_TXCB_DEFAULT_MASK (1 << 9) +#define LVDS_PD_TXCB_ENABLE (0 << 9) +#define LVDS_PD_TXCB_DISABLE (1 << 9) +#define LVDS_PD_TXCA_SHIFT 8 +#define LVDS_PD_TXCA_DEFAULT_MASK (1 << 8) +#define LVDS_PD_TXCA_ENABLE (0 << 8) +#define LVDS_PD_TXDB_3_SHIFT 7 +#define LVDS_PD_TXDB_3_DEFAULT_MASK (1 << 7) +#define LVDS_PD_TXDB_3_ENABLE (0 << 7) +#define LVDS_PD_TXDB_3_DISABLE (1 << 7) +#define LVDS_PD_TXDB_2_SHIFT 6 +#define LVDS_PD_TXDB_2_DEFAULT_MASK (1 << 6) +#define LVDS_PD_TXDB_2_ENABLE (0 << 6) +#define LVDS_PD_TXDB_2_DISABLE (1 << 6) +#define LVDS_PD_TXDB_1_SHIFT 5 +#define LVDS_PD_TXDB_1_DEFAULT_MASK (1 << 5) +#define LVDS_PD_TXDB_1_ENABLE (0 << 5) +#define LVDS_PD_TXDB_1_DISABLE (1 << 5) +#define LVDS_PD_TXDB_0_SHIFT 4 +#define LVDS_PD_TXDB_0_DEFAULT_MASK (1 << 4) +#define LVDS_PD_TXDB_0_ENABLE (0 << 4) +#define LVDS_PD_TXDB_0_DISABLE (1 << 4) +#define LVDS_PD_TXDA_3_SHIFT 3 +#define LVDS_PD_TXDA_3_DEFAULT_MASK (1 << 3) +#define LVDS_PD_TXDA_3_ENABLE (0 << 3) +#define LVDS_PD_TXDA_3_DISABLE (1 << 3) +#define LVDS_PD_TXDA_2_SHIFT 2 +#define LVDS_PD_TXDA_2_DEFAULT_MASK (1 << 2) +#define LVDS_PD_TXDA_2_ENABLE (0 << 2) +#define LVDS_PD_TXDA_1_SHIFT 1 +#define LVDS_PD_TXDA_1_DEFAULT_MASK (1 << 1) +#define LVDS_PD_TXDA_1_ENABLE (0 << 1) +#define LVDS_PD_TXDA_0_SHIFT 0 +#define LVDS_PD_TXDA_0_DEFAULT_MASK 0x1 +#define LVDS_PD_TXDA_0_ENABLE 0 +#define CRCA 0x1d +#define CRCA_VALID_FALSE 0 +#define CRCA_VALID_TRUE 1 +#define CRCA_VALID_RST 1 +#define CRCB 0x1e +#define CRCB_CRC_DEFAULT_MASK 0xffffffff +#define SEQ_CTL 0x20 +#define SEQ_CTL_SWITCH_SHIFT 30 +#define SEQ_CTL_SWITCH_MASK (1 << 30) +#define SEQ_CTL_SWITCH_WAIT (0 << 30) +#define SEQ_CTL_SWITCH_FORCE (1 << 30) +#define SEQ_CTL_STATUS_SHIFT 28 +#define SEQ_CTL_STATUS_MASK (1 << 28) +#define SEQ_CTL_STATUS_STOPPED (0 << 28) +#define SEQ_CTL_STATUS_RUNNING (1 << 28) +#define SEQ_CTL_PC_SHIFT 16 +#define SEQ_CTL_PC_MASK (0xf << 16) +#define SEQ_CTL_PD_PC_ALT_SHIFT 12 +#define SEQ_CTL_PD_PC_ALT_MASK (0xf << 12) +#define SEQ_CTL_PD_PC_SHIFT 8 +#define SEQ_CTL_PD_PC_MASK (0xf << 8) +#define SEQ_CTL_PU_PC_ALT_SHIFT 4 +#define SEQ_CTL_PU_PC_ALT_MASK (0xf << 4) +#define SEQ_CTL_PU_PC_SHIFT 0 +#define SEQ_CTL_PU_PC_MASK 0xf +#define LANE_SEQ_CTL 0x21 +#define LANE_SEQ_CTL_SETTING_NEW_SHIFT 31 +#define LANE_SEQ_CTL_SETTING_MASK (1 << 31) +#define LANE_SEQ_CTL_SETTING_NEW_DONE (0 << 31) +#define LANE_SEQ_CTL_SETTING_NEW_PENDING (1 << 31) +#define LANE_SEQ_CTL_SETTING_NEW_TRIGGER (1 << 31) +#define LANE_SEQ_CTL_SEQ_STATE_SHIFT 28 +#define LANE_SEQ_CTL_SEQ_STATE_IDLE (0 << 28) +#define LANE_SEQ_CTL_SEQ_STATE_BUSY (1 << 28) +#define LANE_SEQ_CTL_SEQUENCE_SHIFT 20 +#define LANE_SEQ_CTL_SEQUENCE_UP (0 << 20) +#define LANE_SEQ_CTL_SEQUENCE_DOWN (1 << 20) +#define LANE_SEQ_CTL_NEW_POWER_STATE_SHIFT 16 +#define LANE_SEQ_CTL_NEW_POWER_STATE_PU (0 << 16) +#define LANE_SEQ_CTL_NEW_POWER_STATE_PD (1 << 16) +#define LANE_SEQ_CTL_DELAY_SHIFT 12 +#define LANE_SEQ_CTL_DELAY_DEFAULT_MASK (0xf << 12) +#define LANE_SEQ_CTL_LANE9_STATE_SHIFT 9 +#define LANE_SEQ_CTL_LANE9_STATE_POWERUP (0 << 9) +#define LANE_SEQ_CTL_LANE9_STATE_POWERDOWN (1 << 9) +#define LANE_SEQ_CTL_LANE8_STATE_SHIFT 8 +#define LANE_SEQ_CTL_LANE8_STATE_POWERUP (0 << 8) +#define LANE_SEQ_CTL_LANE8_STATE_POWERDOWN (1 << 8) +#define LANE_SEQ_CTL_LANE7_STATE_SHIFT 7 +#define LANE_SEQ_CTL_LANE7_STATE_POWERUP (0 << 7) +#define LANE_SEQ_CTL_LANE7_STATE_POWERDOWN (1 << 7) +#define LANE_SEQ_CTL_LANE6_STATE_SHIFT 6 +#define LANE_SEQ_CTL_LANE6_STATE_POWERUP (0 << 6) +#define LANE_SEQ_CTL_LANE6_STATE_POWERDOWN (1 << 6) +#define LANE_SEQ_CTL_LANE5_STATE_SHIFT 5 +#define LANE_SEQ_CTL_LANE5_STATE_POWERUP (0 << 5) +#define LANE_SEQ_CTL_LANE5_STATE_POWERDOWN (1 << 5) +#define LANE_SEQ_CTL_LANE4_STATE_SHIFT 4 +#define LANE_SEQ_CTL_LANE4_STATE_POWERUP (0 << 4) +#define LANE_SEQ_CTL_LANE4_STATE_POWERDOWN (1 << 4) +#define LANE_SEQ_CTL_LANE3_STATE_SHIFT 3 +#define LANE_SEQ_CTL_LANE3_STATE_POWERUP (0 << 3) +#define LANE_SEQ_CTL_LANE3_STATE_POWERDOWN (1 << 3) +#define LANE_SEQ_CTL_LANE2_STATE_SHIFT 2 +#define LANE_SEQ_CTL_LANE2_STATE_POWERUP (0 << 2) +#define LANE_SEQ_CTL_LANE2_STATE_POWERDOWN (1 << 2) +#define LANE_SEQ_CTL_LANE1_STATE_SHIFT 1 +#define LANE_SEQ_CTL_LANE1_STATE_POWERUP (0 << 1) +#define LANE_SEQ_CTL_LANE1_STATE_POWERDOWN (1 << 1) +#define LANE_SEQ_CTL_LANE0_STATE_SHIFT 0 +#define LANE_SEQ_CTL_LANE0_STATE_POWERUP 0 +#define LANE_SEQ_CTL_LANE0_STATE_POWERDOWN 1 +#define SEQ_INST(i) (0x22 + i) +#define SEQ_INST_PLL_PULLDOWN_SHIFT 31 +#define SEQ_INST_PLL_PULLDOWN_DISABLE (0 << 31) +#define SEQ_INST_PLL_PULLDOWN_ENABLE (1 << 31) +#define SEQ_INST_POWERDOWN_MACRO_SHIFT 30 +#define SEQ_INST_POWERDOWN_MACRO_NORMAL (0 << 30) +#define SEQ_INST_POWERDOWN_MACRO_POWERDOWN (1 << 30) +#define SEQ_INST_ASSERT_PLL_RESET_SHIFT 29 +#define SEQ_INST_ASSERT_PLL_RESET_NORMAL (0 << 29) +#define SEQ_INST_ASSERT_PLL_RESET_RST (1 << 29) +#define SEQ_INST_BLANK_V_SHIFT 28 +#define SEQ_INST_BLANK_V_NORMAL (0 << 28) +#define SEQ_INST_BLANK_V_INACTIVE (1 << 28) +#define SEQ_INST_BLANK_H_SHIFT 27 +#define SEQ_INST_BLANK_H_NORMAL (0 << 27) +#define SEQ_INST_BLANK_H_INACTIVE (1 << 27) +#define SEQ_INST_BLANK_DE_SHIFT 26 +#define SEQ_INST_BLANK_DE_NORMAL (0 << 26) +#define SEQ_INST_BLANK_DE_INACTIVE (1 << 26) +#define SEQ_INST_BLACK_DATA_SHIFT 25 +#define SEQ_INST_BLACK_DATA_NORMAL (0 << 25) +#define SEQ_INST_BLACK_DATA_BLACK (1 << 25) +#define SEQ_INST_TRISTATE_IOS_SHIFT 24 +#define SEQ_INST_TRISTATE_IOS_ENABLE_PINS (0 << 24) +#define SEQ_INST_TRISTATE_IOS_TRISTATE (1 << 24) +#define SEQ_INST_DRIVE_PWM_OUT_LO_SHIFT 23 +#define SEQ_INST_DRIVE_PWM_OUT_LO_FALSE (0 << 23) +#define SEQ_INST_DRIVE_PWM_OUT_LO_TRUE (1 << 23) +#define SEQ_INST_PIN_B_SHIFT 22 +#define SEQ_INST_PIN_B_LOW (0 << 22) +#define SEQ_INST_PIN_B_HIGH (1 << 22) +#define SEQ_INST_PIN_A_SHIFT 21 +#define SEQ_INST_PIN_A_LOW (0 << 21) +#define SEQ_INST_PIN_A_HIGH (1 << 21) +#define SEQ_INST_SEQUENCE_SHIFT 19 +#define SEQ_INST_SEQUENCE_UP (0 << 19) +#define SEQ_INST_SEQUENCE_DOWN (1 << 19) +#define SEQ_INST_LANE_SEQ_SHIFT 18 +#define SEQ_INST_LANE_SEQ_STOP (0 << 18) +#define SEQ_INST_LANE_SEQ_RUN (1 << 18) +#define SEQ_INST_PDPORT_SHIFT 17 +#define SEQ_INST_PDPORT_NO (0 << 17) +#define SEQ_INST_PDPORT_YES (1 << 17) +#define SEQ_INST_PDPLL_SHIFT 16 +#define SEQ_INST_PDPLL_NO (0 << 16) +#define SEQ_INST_PDPLL_YES (1 << 16) +#define SEQ_INST_HALT_SHIFT 15 +#define SEQ_INST_HALT_FALSE (0 << 15) +#define SEQ_INST_HALT_TRUE (1 << 15) +#define SEQ_INST_WAIT_UNITS_SHIFT 12 +#define SEQ_INST_WAIT_UNITS_DEFAULT_MASK (3 << 12) +#define SEQ_INST_WAIT_UNITS_US (0 << 12) +#define SEQ_INST_WAIT_UNITS_MS (1 << 12) +#define SEQ_INST_WAIT_UNITS_VSYNC (2 << 12) +#define SEQ_INST_WAIT_TIME_SHIFT 0 +#define SEQ_INST_WAIT_TIME_DEFAULT_MASK 0x3ff +#define PWM_DIV 0x32 +#define PWM_DIV_DIVIDE_DEFAULT_MASK 0xffffff +#define PWM_CTL 0x33 +#define PWM_CTL_SETTING_NEW_SHIFT 31 +#define PWM_CTL_SETTING_NEW_DONE (0 << 31) +#define PWM_CTL_SETTING_NEW_PENDING (1 << 31) +#define PWM_CTL_SETTING_NEW_TRIGGER (1 << 31) +#define PWM_CTL_CLKSEL_SHIFT 30 +#define PWM_CTL_CLKSEL_PCLK (0 << 30) +#define PWM_CTL_CLKSEL_XTAL (1 << 30) +#define PWM_CTL_DUTY_CYCLE_SHIFT 0 +#define PWM_CTL_DUTY_CYCLE_MASK 0xffffff +#define MSCHECK 0x49 +#define MSCHECK_CTL_SHIFT 31 +#define MSCHECK_CTL_CLEAR (0 << 31) +#define MSCHECK_CTL_RUN (1 << 31) +#define XBAR_CTRL 0x4a +#define DP_LINKCTL(i) (0x4c + (i)) +#define DP_LINKCTL_FORCE_IDLEPTTRN_SHIFT 31 +#define DP_LINKCTL_FORCE_IDLEPTTRN_NO (0 << 31) +#define DP_LINKCTL_FORCE_IDLEPTTRN_YES (1 << 31) +#define DP_LINKCTL_COMPLIANCEPTTRN_SHIFT 28 +#define DP_LINKCTL_COMPLIANCEPTTRN_NOPATTERN (0 << 28) +#define DP_LINKCTL_COMPLIANCEPTTRN_COLORSQARE (1 << 28) +#define DP_LINKCTL_LANECOUNT_SHIFT 16 +#define DP_LINKCTL_LANECOUNT_MASK (0x1f << 16) +#define DP_LINKCTL_LANECOUNT_ZERO (0 << 16) +#define DP_LINKCTL_LANECOUNT_ONE (1 << 16) +#define DP_LINKCTL_LANECOUNT_TWO (3 << 16) +#define DP_LINKCTL_LANECOUNT_FOUR (15 << 16) +#define DP_LINKCTL_ENHANCEDFRAME_SHIFT 14 +#define DP_LINKCTL_ENHANCEDFRAME_DISABLE (0 << 14) +#define DP_LINKCTL_ENHANCEDFRAME_ENABLE (1 << 14) +#define DP_LINKCTL_SYNCMODE_SHIFT 10 +#define DP_LINKCTL_SYNCMODE_DISABLE (0 << 10) +#define DP_LINKCTL_SYNCMODE_ENABLE (1 << 10) +#define DP_LINKCTL_TUSIZE_SHIFT 2 +#define DP_LINKCTL_TUSIZE_MASK (0x7f << 2) +#define DP_LINKCTL_ENABLE_SHIFT 0 +#define DP_LINKCTL_ENABLE_NO 0 +#define DP_LINKCTL_ENABLE_YES 1 +#define DC(i) (0x4e + (i)) +#define DC_LANE3_DP_LANE3_SHIFT 24 +#define DC_LANE3_DP_LANE3_MASK (0xff << 24) +#define DC_LANE3_DP_LANE3_P0_LEVEL0 (17 << 24) +#define DC_LANE3_DP_LANE3_P1_LEVEL0 (21 << 24) +#define DC_LANE3_DP_LANE3_P2_LEVEL0 (26 << 24) +#define DC_LANE3_DP_LANE3_P3_LEVEL0 (34 << 24) +#define DC_LANE3_DP_LANE3_P0_LEVEL1 (26 << 24) +#define DC_LANE3_DP_LANE3_P1_LEVEL1 (32 << 24) +#define DC_LANE3_DP_LANE3_P2_LEVEL1 (39 << 24) +#define DC_LANE3_DP_LANE3_P0_LEVEL2 (34 << 24) +#define DC_LANE3_DP_LANE3_P1_LEVEL2 (43 << 24) +#define DC_LANE3_DP_LANE3_P0_LEVEL3 (51 << 24) +#define DC_LANE2_DP_LANE0_SHIFT 16 +#define DC_LANE2_DP_LANE0_MASK (0xff << 16) +#define DC_LANE2_DP_LANE0_P0_LEVEL0 (17 << 16) +#define DC_LANE2_DP_LANE0_P1_LEVEL0 (21 << 16) +#define DC_LANE2_DP_LANE0_P2_LEVEL0 (26 << 16) +#define DC_LANE2_DP_LANE0_P3_LEVEL0 (34 << 16) +#define DC_LANE2_DP_LANE0_P0_LEVEL1 (26 << 16) +#define DC_LANE2_DP_LANE0_P1_LEVEL1 (32 << 16) +#define DC_LANE2_DP_LANE0_P2_LEVEL1 (39 << 16) +#define DC_LANE2_DP_LANE0_P0_LEVEL2 (34 << 16) +#define DC_LANE2_DP_LANE0_P1_LEVEL2 (43 << 16) +#define DC_LANE2_DP_LANE0_P0_LEVEL3 (51 << 16) +#define DC_LANE1_DP_LANE1_SHIFT 8 +#define DC_LANE1_DP_LANE1_MASK (0xff << 8) +#define DC_LANE1_DP_LANE1_P0_LEVEL0 (17 << 8) +#define DC_LANE1_DP_LANE1_P1_LEVEL0 (21 << 8) +#define DC_LANE1_DP_LANE1_P2_LEVEL0 (26 << 8) +#define DC_LANE1_DP_LANE1_P3_LEVEL0 (34 << 8) +#define DC_LANE1_DP_LANE1_P0_LEVEL1 (26 << 8) +#define DC_LANE1_DP_LANE1_P1_LEVEL1 (32 << 8) +#define DC_LANE1_DP_LANE1_P2_LEVEL1 (39 << 8) +#define DC_LANE1_DP_LANE1_P0_LEVEL2 (34 << 8) +#define DC_LANE1_DP_LANE1_P1_LEVEL2 (43 << 8) +#define DC_LANE1_DP_LANE1_P0_LEVEL3 (51 << 8) +#define DC_LANE0_DP_LANE2_SHIFT 0 +#define DC_LANE0_DP_LANE2_MASK 0xff +#define DC_LANE0_DP_LANE2_P0_LEVEL0 17 +#define DC_LANE0_DP_LANE2_P1_LEVEL0 21 +#define DC_LANE0_DP_LANE2_P2_LEVEL0 26 +#define DC_LANE0_DP_LANE2_P3_LEVEL0 34 +#define DC_LANE0_DP_LANE2_P0_LEVEL1 26 +#define DC_LANE0_DP_LANE2_P1_LEVEL1 32 +#define DC_LANE0_DP_LANE2_P2_LEVEL1 39 +#define DC_LANE0_DP_LANE2_P0_LEVEL2 34 +#define DC_LANE0_DP_LANE2_P1_LEVEL2 43 +#define DC_LANE0_DP_LANE2_P0_LEVEL3 51 +#define LANE_DRIVE_CURRENT(i) (0x4e + (i)) +#define PR(i) (0x52 + (i)) +#define PR_LANE3_DP_LANE3_SHIFT 24 +#define PR_LANE3_DP_LANE3_MASK (0xff << 24) +#define PR_LANE3_DP_LANE3_D0_LEVEL0 (0 << 24) +#define PR_LANE3_DP_LANE3_D1_LEVEL0 (0 << 24) +#define PR_LANE3_DP_LANE3_D2_LEVEL0 (0 << 24) +#define PR_LANE3_DP_LANE3_D3_LEVEL0 (0 << 24) +#define PR_LANE3_DP_LANE3_D0_LEVEL1 (4 << 24) +#define PR_LANE3_DP_LANE3_D1_LEVEL1 (6 << 24) +#define PR_LANE3_DP_LANE3_D2_LEVEL1 (17 << 24) +#define PR_LANE3_DP_LANE3_D0_LEVEL2 (8 << 24) +#define PR_LANE3_DP_LANE3_D1_LEVEL2 (13 << 24) +#define PR_LANE3_DP_LANE3_D0_LEVEL3 (17 << 24) +#define PR_LANE2_DP_LANE0_SHIFT 16 +#define PR_LANE2_DP_LANE0_MASK (0xff << 16) +#define PR_LANE2_DP_LANE0_D0_LEVEL0 (0 << 16) +#define PR_LANE2_DP_LANE0_D1_LEVEL0 (0 << 16) +#define PR_LANE2_DP_LANE0_D2_LEVEL0 (0 << 16) +#define PR_LANE2_DP_LANE0_D3_LEVEL0 (0 << 16) +#define PR_LANE2_DP_LANE0_D0_LEVEL1 (4 << 16) +#define PR_LANE2_DP_LANE0_D1_LEVEL1 (6 << 16) +#define PR_LANE2_DP_LANE0_D2_LEVEL1 (17 << 16) +#define PR_LANE2_DP_LANE0_D0_LEVEL2 (8 << 16) +#define PR_LANE2_DP_LANE0_D1_LEVEL2 (13 << 16) +#define PR_LANE2_DP_LANE0_D0_LEVEL3 (17 << 16) +#define PR_LANE1_DP_LANE1_SHIFT 8 +#define PR_LANE1_DP_LANE1_MASK (0xff >> 8) +#define PR_LANE1_DP_LANE1_D0_LEVEL0 (0 >> 8) +#define PR_LANE1_DP_LANE1_D1_LEVEL0 (0 >> 8) +#define PR_LANE1_DP_LANE1_D2_LEVEL0 (0 >> 8) +#define PR_LANE1_DP_LANE1_D3_LEVEL0 (0 >> 8) +#define PR_LANE1_DP_LANE1_D0_LEVEL1 (4 >> 8) +#define PR_LANE1_DP_LANE1_D1_LEVEL1 (6 >> 8) +#define PR_LANE1_DP_LANE1_D2_LEVEL1 (17 >> 8) +#define PR_LANE1_DP_LANE1_D0_LEVEL2 (8 >> 8) +#define PR_LANE1_DP_LANE1_D1_LEVEL2 (13 >> 8) +#define PR_LANE1_DP_LANE1_D0_LEVEL3 (17 >> 8) +#define PR_LANE0_DP_LANE2_SHIFT 0 +#define PR_LANE0_DP_LANE2_MASK 0xff +#define PR_LANE0_DP_LANE2_D0_LEVEL0 0 +#define PR_LANE0_DP_LANE2_D1_LEVEL0 0 +#define PR_LANE0_DP_LANE2_D2_LEVEL0 0 +#define PR_LANE0_DP_LANE2_D3_LEVEL0 0 +#define PR_LANE0_DP_LANE2_D0_LEVEL1 4 +#define PR_LANE0_DP_LANE2_D1_LEVEL1 6 +#define PR_LANE0_DP_LANE2_D2_LEVEL1 17 +#define PR_LANE0_DP_LANE2_D0_LEVEL2 8 +#define PR_LANE0_DP_LANE2_D1_LEVEL2 13 +#define PR_LANE0_DP_LANE2_D0_LEVEL3 17 +#define LANE4_PREEMPHASIS(i) (0x54 + (i)) +#define POSTCURSOR(i) (0x56 + (i)) +#define DP_CONFIG(i) (0x58 + (i)) +#define DP_CONFIG_RD_RESET_VAL_SHIFT 31 +#define DP_CONFIG_RD_RESET_VAL_POSITIVE (0 << 31) +#define DP_CONFIG_RD_RESET_VAL_NEGATIVE (1 << 31) +#define DP_CONFIG_IDLE_BEFORE_ATTACH_SHIFT 28 +#define DP_CONFIG_IDLE_BEFORE_ATTACH_DISABLE (0 << 28) +#define DP_CONFIG_IDLE_BEFORE_ATTACH_ENABLE (1 << 28) +#define DP_CONFIG_ACTIVESYM_CNTL_SHIFT 26 +#define DP_CONFIG_ACTIVESYM_CNTL_DISABLE (0 << 26) +#define DP_CONFIG_ACTIVESYM_CNTL_ENABLE (1 << 26) +#define DP_CONFIG_ACTIVESYM_POLARITY_SHIFT 24 +#define DP_CONFIG_ACTIVESYM_POLARITY_NEGATIVE (0 << 24) +#define DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE (1 << 24) +#define DP_CONFIG_ACTIVESYM_FRAC_SHIFT 16 +#define DP_CONFIG_ACTIVESYM_FRAC_MASK (0xf << 16) +#define DP_CONFIG_ACTIVESYM_COUNT_SHIFT 8 +#define DP_CONFIG_ACTIVESYM_COUNT_MASK (0x7f << 8) +#define DP_CONFIG_WATERMARK_SHIFT 0 +#define DP_CONFIG_WATERMARK_MASK 0x3f +#define DP_MN(i) (0x5a + i) +#define DP_MN_M_MOD_SHIFT 30 +#define DP_MN_M_MOD_DEFAULT_MASK (3 << 30) +#define DP_MN_M_MOD_NONE (0 << 30) +#define DP_MN_M_MOD_INC (1 << 30) +#define DP_MN_M_MOD_DEC (2 << 30) +#define DP_MN_M_DELTA_SHIFT 24 +#define DP_MN_M_DELTA_DEFAULT_MASK (0xf << 24) +#define DP_MN_N_VAL_SHIFT 0 +#define DP_MN_N_VAL_DEFAULT_MASK 0xffffff +#define DP_PADCTL(i) (0x5c + (i)) +#define DP_PADCTL_SPARE_SHIFT 25 +#define DP_PADCTL_SPARE_DEFAULT_MASK (0x7f << 25) +#define DP_PADCTL_VCO_2X_SHIFT 24 +#define DP_PADCTL_VCO_2X_DISABLE (0 << 24) +#define DP_PADCTL_VCO_2X_ENABLE (1 << 24) +#define DP_PADCTL_PAD_CAL_PD_SHIFT 23 +#define DP_PADCTL_PAD_CAL_PD_POWERUP (0 << 23) +#define DP_PADCTL_PAD_CAL_PD_POWERDOWN (1 << 23) +#define DP_PADCTL_TX_PU_SHIFT 22 +#define DP_PADCTL_TX_PU_DISABLE (0 << 22) +#define DP_PADCTL_TX_PU_ENABLE (1 << 22) +#define DP_PADCTL_TX_PU_MASK (1 << 22) +#define DP_PADCTL_REG_CTRL_SHIFT 20 +#define DP_PADCTL_REG_CTRL_DEFAULT_MASK (3 << 20) +#define DP_PADCTL_VCMMODE_SHIFT 16 +#define DP_PADCTL_VCMMODE_DEFAULT_MASK (0xf << 16) +#define DP_PADCTL_VCMMODE_TRISTATE (0 << 16) +#define DP_PADCTL_VCMMODE_TEST_MUX (1 << 16) +#define DP_PADCTL_VCMMODE_WEAK_PULLDOWN (2 << 16) +#define DP_PADCTL_VCMMODE_STRONG_PULLDOWN (4 << 16) +#define DP_PADCTL_TX_PU_VALUE_SHIFT 8 +#define DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK (0xff << 8) +#define DP_PADCTL_COMODE_TXD_3_DP_TXD_3_SHIFT 7 +#define DP_PADCTL_COMODE_TXD_3_DP_TXD_3_DISABLE (0 << 7) +#define DP_PADCTL_COMODE_TXD_3_DP_TXD_3_ENABLE (1 << 7) +#define DP_PADCTL_COMODE_TXD_2_DP_TXD_0_SHIFT 6 +#define DP_PADCTL_COMODE_TXD_2_DP_TXD_0_DISABLE (0 << 6) +#define DP_PADCTL_COMODE_TXD_2_DP_TXD_0_ENABLE (1 << 6) +#define DP_PADCTL_COMODE_TXD_1_DP_TXD_1_SHIFT 5 +#define DP_PADCTL_COMODE_TXD_1_DP_TXD_1_DISABLE (0 << 5) +#define DP_PADCTL_COMODE_TXD_1_DP_TXD_1_ENABLE (1 << 5) +#define DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT 4 +#define DP_PADCTL_COMODE_TXD_0_DP_TXD_2_DISABLE (0 << 4) +#define DP_PADCTL_COMODE_TXD_0_DP_TXD_2_ENABLE (1 << 4) +#define DP_PADCTL_PD_TXD_3_SHIFT 3 +#define DP_PADCTL_PD_TXD_3_YES (0 << 3) +#define DP_PADCTL_PD_TXD_3_NO (1 << 3) +#define DP_PADCTL_PD_TXD_0_SHIFT 2 +#define DP_PADCTL_PD_TXD_0_YES (0 << 2) +#define DP_PADCTL_PD_TXD_0_NO (1 << 2) +#define DP_PADCTL_PD_TXD_1_SHIFT 1 +#define DP_PADCTL_PD_TXD_1_YES (0 << 1) +#define DP_PADCTL_PD_TXD_1_NO (1 << 1) +#define DP_PADCTL_PD_TXD_2_SHIFT 0 +#define DP_PADCTL_PD_TXD_2_YES 0 +#define DP_PADCTL_PD_TXD_2_NO 1 +#define DP_DEBUG(i) (0x5e + i) +#define DP_SPARE(i) (0x60 + (i)) +#define DP_SPARE_REG_SHIFT 3 +#define DP_SPARE_REG_DEFAULT_MASK (0x1fffffff << 3) +#define DP_SPARE_SOR_CLK_SEL_SHIFT 2 +#define DP_SPARE_SOR_CLK_SEL_DEFAULT_MASK (1 << 2) +#define DP_SPARE_SOR_CLK_SEL_SAFE_SORCLK (0 << 2) +#define DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK (1 << 2) +#define DP_SPARE_PANEL_SHIFT 1 +#define DP_SPARE_PANEL_EXTERNAL (0 << 1) +#define DP_SPARE_PANEL_INTERNAL (1 << 1) +#define DP_SPARE_SEQ_ENABLE_SHIFT 0 +#define DP_SPARE_SEQ_ENABLE_NO 0 +#define DP_SPARE_SEQ_ENABLE_YES 1 +#define DP_AUDIO_CTRL 0x62 +#define DP_AUDIO_HBLANK_SYMBOLS 0x63 +#define DP_AUDIO_HBLANK_SYMBOLS_MASK 0x1ffff +#define DP_AUDIO_HBLANK_SYMBOLS_VALUE_SHIFT 0 +#define DP_AUDIO_VBLANK_SYMBOLS 0x64 +#define DP_AUDIO_VBLANK_SYMBOLS_MASK 0x1ffff +#define DP_AUDIO_VBLANK_SYMBOLS_SHIFT 0 +#define DP_GENERIC_INFOFRAME_HEADER 0x65 +#define DP_GENERIC_INFOFRAME_SUBPACK(i) (0x66 + (i)) +#define DP_TPG 0x6d +#define DP_TPG_LANE3_CHANNELCODING_SHIFT 30 +#define DP_TPG_LANE3_CHANNELCODING_DISABLE (0 << 30) +#define DP_TPG_LANE3_CHANNELCODING_ENABLE (1 << 30) +#define DP_TPG_LANE3_SCRAMBLEREN_SHIFT 28 +#define DP_TPG_LANE3_SCRAMBLEREN_ENABLE_GALIOS (1 << 28) +#define DP_TPG_LANE3_SCRAMBLEREN_ENABLE_FIBONACCI (2 << 28) +#define DP_TPG_LANE3_PATTERN_SHIFT 24 +#define DP_TPG_LANE3_PATTERN_DEFAULT_MASK (0xf << 24) +#define DP_TPG_LANE3_PATTERN_NOPATTERN (0 << 24) +#define DP_TPG_LANE3_PATTERN_TRAINING1 (1 << 24) +#define DP_TPG_LANE3_PATTERN_TRAINING2 (2 << 24) +#define DP_TPG_LANE3_PATTERN_TRAINING3 (3 << 24) +#define DP_TPG_LANE3_PATTERN_D102 (4 << 24) +#define DP_TPG_LANE3_PATTERN_SBLERRRATE (5 << 24) +#define DP_TPG_LANE3_PATTERN_PRBS7 (6 << 24) +#define DP_TPG_LANE3_PATTERN_CSTM (7 << 24) +#define DP_TPG_LANE3_PATTERN_HBR2_COMPLIANCE (8 << 24) +#define DP_TPG_LANE2_CHANNELCODING_SHIFT 22 +#define DP_TPG_LANE2_CHANNELCODING_DISABLE (0 << 22) +#define DP_TPG_LANE2_CHANNELCODING_ENABLE (1 << 22) +#define DP_TPG_LANE2_SCRAMBLEREN_SHIFT 20 +#define DP_TPG_LANE2_SCRAMBLEREN_DEFAULT_MASK (3 << 20) +#define DP_TPG_LANE2_SCRAMBLEREN_DISABLE (0 << 20) +#define DP_TPG_LANE2_SCRAMBLEREN_ENABLE_GALIOS (1 << 20) +#define DP_TPG_LANE2_SCRAMBLEREN_ENABLE_FIBONACCI (2 << 20) +#define DP_TPG_LANE2_PATTERN_SHIFT 16 +#define DP_TPG_LANE2_PATTERN_DEFAULT_MASK (0xf << 16) +#define DP_TPG_LANE2_PATTERN_NOPATTERN (0 << 16) +#define DP_TPG_LANE2_PATTERN_TRAINING1 (1 << 16) +#define DP_TPG_LANE2_PATTERN_TRAINING2 (2 << 16) +#define DP_TPG_LANE2_PATTERN_TRAINING3 (3 << 16) +#define DP_TPG_LANE2_PATTERN_D102 (4 << 16) +#define DP_TPG_LANE2_PATTERN_SBLERRRATE (5 << 16) +#define DP_TPG_LANE2_PATTERN_PRBS7 (6 << 16) +#define DP_TPG_LANE2_PATTERN_CSTM (7 << 16) +#define DP_TPG_LANE2_PATTERN_HBR2_COMPLIANCE (8 << 16) +#define DP_TPG_LANE1_CHANNELCODING_SHIFT 14 +#define DP_TPG_LANE1_CHANNELCODING_DISABLE (0 << 14) +#define DP_TPG_LANE1_CHANNELCODING_ENABLE (1 << 14) +#define DP_TPG_LANE1_SCRAMBLEREN_SHIFT 12 +#define DP_TPG_LANE1_SCRAMBLEREN_DEFAULT_MASK (3 << 12) +#define DP_TPG_LANE1_SCRAMBLEREN_DISABLE (0 << 12) +#define DP_TPG_LANE1_SCRAMBLEREN_ENABLE_GALIOS (1 << 12) +#define DP_TPG_LANE1_SCRAMBLEREN_ENABLE_FIBONACCI (2 << 12) +#define DP_TPG_LANE1_PATTERN_SHIFT 8 +#define DP_TPG_LANE1_PATTERN_DEFAULT_MASK (0xf << 8) +#define DP_TPG_LANE1_PATTERN_NOPATTERN (0 << 8) +#define DP_TPG_LANE1_PATTERN_TRAINING1 (1 << 8) +#define DP_TPG_LANE1_PATTERN_TRAINING2 (2 << 8) +#define DP_TPG_LANE1_PATTERN_TRAINING3 (3 << 8) +#define DP_TPG_LANE1_PATTERN_D102 (4 << 8) +#define DP_TPG_LANE1_PATTERN_SBLERRRATE (5 << 8) +#define DP_TPG_LANE1_PATTERN_PRBS7 (6 << 8) +#define DP_TPG_LANE1_PATTERN_CSTM (7 << 8) +#define DP_TPG_LANE1_PATTERN_HBR2_COMPLIANCE (8 << 8) +#define DP_TPG_LANE0_CHANNELCODING_SHIFT 6 +#define DP_TPG_LANE0_CHANNELCODING_DISABLE (0 << 6) +#define DP_TPG_LANE0_CHANNELCODING_ENABLE (1 << 6) +#define DP_TPG_LANE0_SCRAMBLEREN_SHIFT 4 +#define DP_TPG_LANE0_SCRAMBLEREN_DEFAULT_MASK (3 << 4) +#define DP_TPG_LANE0_SCRAMBLEREN_DISABLE (0 << 4) +#define DP_TPG_LANE0_SCRAMBLEREN_ENABLE_GALIOS (1 << 4) +#define DP_TPG_LANE0_SCRAMBLEREN_ENABLE_FIBONACCI (2 << 4) +#define DP_TPG_LANE0_PATTERN_SHIFT 0 +#define DP_TPG_LANE0_PATTERN_DEFAULT_MASK 0xf +#define DP_TPG_LANE0_PATTERN_NOPATTERN 0 +#define DP_TPG_LANE0_PATTERN_TRAINING1 1 +#define DP_TPG_LANE0_PATTERN_TRAINING2 2 +#define DP_TPG_LANE0_PATTERN_TRAINING3 3 +#define DP_TPG_LANE0_PATTERN_D102 4 +#define DP_TPG_LANE0_PATTERN_SBLERRRATE 5 +#define DP_TPG_LANE0_PATTERN_PRBS7 6 +#define DP_TPG_LANE0_PATTERN_CSTM 7 +#define DP_TPG_LANE0_PATTERN_HBR2_COMPLIANCE 8 + +enum { + training_pattern_disabled = 0, + training_pattern_1 = 1, + training_pattern_2 = 2, + training_pattern_3 = 3, + training_pattern_none = 0xff +}; + +enum tegra_dc_sor_protocol { + SOR_DP, + SOR_LVDS, +}; + +#define SOR_LINK_SPEED_G1_62 6 +#define SOR_LINK_SPEED_G2_7 10 +#define SOR_LINK_SPEED_G5_4 20 +#define SOR_LINK_SPEED_LVDS 7 + +struct tegra_dp_link_config { + int is_valid; + + /* Supported configuration */ + u8 max_link_bw; + u8 max_lane_count; + int downspread; + int support_enhanced_framing; + u32 bits_per_pixel; + int alt_scramber_reset_cap; /* true for eDP */ + int only_enhanced_framing; /* enhanced_frame_en ignored */ + int frame_in_ms; + + /* Actual configuration */ + u8 link_bw; + u8 lane_count; + int enhanced_framing; + int scramble_ena; + + u32 activepolarity; + u32 active_count; + u32 tu_size; + u32 active_frac; + u32 watermark; + + s32 hblank_sym; + s32 vblank_sym; + + /* Training data */ + u32 drive_current; + u32 preemphasis; + u32 postcursor; + u8 aux_rd_interval; + u8 tps3_supported; +}; + +#define TEGRA_SOR_TIMEOUT_MS 1000 +#define TEGRA_SOR_ATTACH_TIMEOUT_MS 1000 + +int tegra_dc_sor_enable_dp(struct udevice *sor, + const struct tegra_dp_link_config *link_cfg); +int tegra_dc_sor_set_power_state(struct udevice *sor, int pu_pd); +void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena, + u8 training_pattern, const struct tegra_dp_link_config *link_cfg); +void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw); +void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count); +void tegra_dc_sor_set_panel_power(struct udevice *sor, + int power_up); +void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int); +void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw, + u8 *lane_count); +void tegra_dc_sor_set_lane_parm(struct udevice *dev, + const struct tegra_dp_link_config *link_cfg); +void tegra_dc_sor_power_down_unused_lanes(struct udevice *sor, + const struct tegra_dp_link_config *link_cfg); +int tegra_dc_sor_set_voltage_swing(struct udevice *sor, + const struct tegra_dp_link_config *link_cfg); +int tegra_sor_precharge_lanes(struct udevice *dev, + const struct tegra_dp_link_config *cfg); +void tegra_dp_disable_tx_pu(struct udevice *sor); +void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg, + u32 vs_reg, u32 pc_reg, u8 pc_supported); + +int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *sor, + const struct tegra_dp_link_config *link_cfg, + const struct display_timing *timing); +int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *sor); + +void tegra_dc_sor_disable_win_short_raster(struct dc_ctlr *disp_ctrl, + int *dc_reg_ctx); +int tegra_dc_sor_general_act(struct dc_ctlr *disp_ctrl); +void tegra_dc_sor_restore_win_and_raster(struct dc_ctlr *disp_ctrl, + int *dc_reg_ctx); + +int tegra_dc_sor_init(struct udevice **sorp); +#endif diff --git a/drivers/video/tegra124/Makefile b/drivers/video/tegra124/Makefile deleted file mode 100644 index a378382628c..00000000000 --- a/drivers/video/tegra124/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# Copyright (c) 2014 Google, Inc -# - -obj-y += display.o -obj-y += dp.o -obj-y += sor.o diff --git a/drivers/video/tegra124/display.c b/drivers/video/tegra124/display.c deleted file mode 100644 index abe31e27d84..00000000000 --- a/drivers/video/tegra124/display.c +++ /dev/null @@ -1,504 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2014 Google Inc. - * - * Extracted from Chromium coreboot commit 3f59b13d - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "displayport.h" - -/* return in 1000ths of a Hertz */ -static int tegra_dc_calc_refresh(const struct display_timing *timing) -{ - int h_total, v_total, refresh; - int pclk = timing->pixelclock.typ; - - h_total = timing->hactive.typ + timing->hfront_porch.typ + - timing->hback_porch.typ + timing->hsync_len.typ; - v_total = timing->vactive.typ + timing->vfront_porch.typ + - timing->vback_porch.typ + timing->vsync_len.typ; - if (!pclk || !h_total || !v_total) - return 0; - refresh = pclk / h_total; - refresh *= 1000; - refresh /= v_total; - - return refresh; -} - -static void print_mode(const struct display_timing *timing) -{ - int refresh = tegra_dc_calc_refresh(timing); - - debug("MODE:%dx%d@%d.%03uHz pclk=%d\n", - timing->hactive.typ, timing->vactive.typ, refresh / 1000, - refresh % 1000, timing->pixelclock.typ); -} - -static int update_display_mode(struct dc_ctlr *disp_ctrl, - const struct display_timing *timing, - int href_to_sync, int vref_to_sync) -{ - print_mode(timing); - - writel(0x1, &disp_ctrl->disp.disp_timing_opt); - - writel(vref_to_sync << 16 | href_to_sync, - &disp_ctrl->disp.ref_to_sync); - - writel(timing->vsync_len.typ << 16 | timing->hsync_len.typ, - &disp_ctrl->disp.sync_width); - - writel(((timing->vback_porch.typ - vref_to_sync) << 16) | - timing->hback_porch.typ, &disp_ctrl->disp.back_porch); - - writel(((timing->vfront_porch.typ + vref_to_sync) << 16) | - timing->hfront_porch.typ, &disp_ctrl->disp.front_porch); - - writel(timing->hactive.typ | (timing->vactive.typ << 16), - &disp_ctrl->disp.disp_active); - - /** - * We want to use PLLD_out0, which is PLLD / 2: - * PixelClock = (PLLD / 2) / ShiftClockDiv / PixelClockDiv. - * - * Currently most panels work inside clock range 50MHz~100MHz, and PLLD - * has some requirements to have VCO in range 500MHz~1000MHz (see - * clock.c for more detail). To simplify calculation, we set - * PixelClockDiv to 1 and ShiftClockDiv to 1. In future these values - * may be calculated by clock_display, to allow wider frequency range. - * - * Note ShiftClockDiv is a 7.1 format value. - */ - const u32 shift_clock_div = 1; - writel((PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT) | - ((shift_clock_div - 1) * 2) << SHIFT_CLK_DIVIDER_SHIFT, - &disp_ctrl->disp.disp_clk_ctrl); - debug("%s: PixelClock=%u, ShiftClockDiv=%u\n", __func__, - timing->pixelclock.typ, shift_clock_div); - return 0; -} - -static u32 tegra_dc_poll_register(void *reg, - u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_us) -{ - u32 temp = timeout_us; - u32 reg_val = 0; - - do { - udelay(poll_interval_us); - reg_val = readl(reg); - if (timeout_us > poll_interval_us) - timeout_us -= poll_interval_us; - else - break; - } while ((reg_val & mask) != exp_val); - - if ((reg_val & mask) == exp_val) - return 0; /* success */ - - return temp; -} - -int tegra_dc_sor_general_act(struct dc_ctlr *disp_ctrl) -{ - writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl); - - if (tegra_dc_poll_register(&disp_ctrl->cmd.state_ctrl, - GENERAL_ACT_REQ, 0, 100, - DC_POLL_TIMEOUT_MS * 1000)) { - debug("dc timeout waiting for DC to stop\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static struct display_timing min_mode = { - .hsync_len = { .typ = 1 }, - .vsync_len = { .typ = 1 }, - .hback_porch = { .typ = 20 }, - .vback_porch = { .typ = 0 }, - .hactive = { .typ = 16 }, - .vactive = { .typ = 16 }, - .hfront_porch = { .typ = 1 }, - .vfront_porch = { .typ = 2 }, -}; - -/* Disable windows and set minimum raster timings */ -void tegra_dc_sor_disable_win_short_raster(struct dc_ctlr *disp_ctrl, - int *dc_reg_ctx) -{ - const int href_to_sync = 0, vref_to_sync = 1; - int selected_windows, i; - - selected_windows = readl(&disp_ctrl->cmd.disp_win_header); - - /* Store and clear window options */ - for (i = 0; i < DC_N_WINDOWS; ++i) { - writel(WINDOW_A_SELECT << i, &disp_ctrl->cmd.disp_win_header); - dc_reg_ctx[i] = readl(&disp_ctrl->win.win_opt); - writel(0, &disp_ctrl->win.win_opt); - writel(WIN_A_ACT_REQ << i, &disp_ctrl->cmd.state_ctrl); - } - - writel(selected_windows, &disp_ctrl->cmd.disp_win_header); - - /* Store current raster timings and set minimum timings */ - dc_reg_ctx[i++] = readl(&disp_ctrl->disp.ref_to_sync); - writel(href_to_sync | (vref_to_sync << 16), - &disp_ctrl->disp.ref_to_sync); - - dc_reg_ctx[i++] = readl(&disp_ctrl->disp.sync_width); - writel(min_mode.hsync_len.typ | (min_mode.vsync_len.typ << 16), - &disp_ctrl->disp.sync_width); - - dc_reg_ctx[i++] = readl(&disp_ctrl->disp.back_porch); - writel(min_mode.hback_porch.typ | (min_mode.vback_porch.typ << 16), - &disp_ctrl->disp.back_porch); - - dc_reg_ctx[i++] = readl(&disp_ctrl->disp.front_porch); - writel(min_mode.hfront_porch.typ | (min_mode.vfront_porch.typ << 16), - &disp_ctrl->disp.front_porch); - - dc_reg_ctx[i++] = readl(&disp_ctrl->disp.disp_active); - writel(min_mode.hactive.typ | (min_mode.vactive.typ << 16), - &disp_ctrl->disp.disp_active); - - writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl); -} - -/* Restore previous windows status and raster timings */ -void tegra_dc_sor_restore_win_and_raster(struct dc_ctlr *disp_ctrl, - int *dc_reg_ctx) -{ - int selected_windows, i; - - selected_windows = readl(&disp_ctrl->cmd.disp_win_header); - - for (i = 0; i < DC_N_WINDOWS; ++i) { - writel(WINDOW_A_SELECT << i, &disp_ctrl->cmd.disp_win_header); - writel(dc_reg_ctx[i], &disp_ctrl->win.win_opt); - writel(WIN_A_ACT_REQ << i, &disp_ctrl->cmd.state_ctrl); - } - - writel(selected_windows, &disp_ctrl->cmd.disp_win_header); - - writel(dc_reg_ctx[i++], &disp_ctrl->disp.ref_to_sync); - writel(dc_reg_ctx[i++], &disp_ctrl->disp.sync_width); - writel(dc_reg_ctx[i++], &disp_ctrl->disp.back_porch); - writel(dc_reg_ctx[i++], &disp_ctrl->disp.front_porch); - writel(dc_reg_ctx[i++], &disp_ctrl->disp.disp_active); - - writel(GENERAL_UPDATE, &disp_ctrl->cmd.state_ctrl); -} - -static int tegra_depth_for_bpp(int bpp) -{ - switch (bpp) { - case 32: - return COLOR_DEPTH_R8G8B8A8; - case 16: - return COLOR_DEPTH_B5G6R5; - default: - debug("Unsupported LCD bit depth"); - return -1; - } -} - -static int update_window(struct dc_ctlr *disp_ctrl, - u32 frame_buffer, int fb_bits_per_pixel, - const struct display_timing *timing) -{ - const u32 colour_white = 0xffffff; - int colour_depth; - u32 val; - - writel(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header); - - writel(((timing->vactive.typ << 16) | timing->hactive.typ), - &disp_ctrl->win.size); - writel(((timing->vactive.typ << 16) | - (timing->hactive.typ * fb_bits_per_pixel / 8)), - &disp_ctrl->win.prescaled_size); - writel(((timing->hactive.typ * fb_bits_per_pixel / 8 + 31) / - 32 * 32), &disp_ctrl->win.line_stride); - - colour_depth = tegra_depth_for_bpp(fb_bits_per_pixel); - if (colour_depth == -1) - return -EINVAL; - - writel(colour_depth, &disp_ctrl->win.color_depth); - - writel(frame_buffer, &disp_ctrl->winbuf.start_addr); - writel(0x1000 << V_DDA_INC_SHIFT | 0x1000 << H_DDA_INC_SHIFT, - &disp_ctrl->win.dda_increment); - - writel(colour_white, &disp_ctrl->disp.blend_background_color); - writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT, - &disp_ctrl->cmd.disp_cmd); - - writel(WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access); - - val = GENERAL_ACT_REQ | WIN_A_ACT_REQ; - val |= GENERAL_UPDATE | WIN_A_UPDATE; - writel(val, &disp_ctrl->cmd.state_ctrl); - - /* Enable win_a */ - val = readl(&disp_ctrl->win.win_opt); - writel(val | WIN_ENABLE, &disp_ctrl->win.win_opt); - - return 0; -} - -static int tegra_dc_init(struct dc_ctlr *disp_ctrl) -{ - /* do not accept interrupts during initialization */ - writel(0x00000000, &disp_ctrl->cmd.int_mask); - writel(WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, - &disp_ctrl->cmd.state_access); - writel(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header); - writel(0x00000000, &disp_ctrl->win.win_opt); - writel(0x00000000, &disp_ctrl->win.byte_swap); - writel(0x00000000, &disp_ctrl->win.buffer_ctrl); - - writel(0x00000000, &disp_ctrl->win.pos); - writel(0x00000000, &disp_ctrl->win.h_initial_dda); - writel(0x00000000, &disp_ctrl->win.v_initial_dda); - writel(0x00000000, &disp_ctrl->win.dda_increment); - writel(0x00000000, &disp_ctrl->win.dv_ctrl); - - writel(0x01000000, &disp_ctrl->win.blend_layer_ctrl); - writel(0x00000000, &disp_ctrl->win.blend_match_select); - writel(0x00000000, &disp_ctrl->win.blend_nomatch_select); - writel(0x00000000, &disp_ctrl->win.blend_alpha_1bit); - - writel(0x00000000, &disp_ctrl->winbuf.start_addr_hi); - writel(0x00000000, &disp_ctrl->winbuf.addr_h_offset); - writel(0x00000000, &disp_ctrl->winbuf.addr_v_offset); - - writel(0x00000000, &disp_ctrl->com.crc_checksum); - writel(0x00000000, &disp_ctrl->com.pin_output_enb[0]); - writel(0x00000000, &disp_ctrl->com.pin_output_enb[1]); - writel(0x00000000, &disp_ctrl->com.pin_output_enb[2]); - writel(0x00000000, &disp_ctrl->com.pin_output_enb[3]); - writel(0x00000000, &disp_ctrl->disp.disp_signal_opt0); - - return 0; -} - -static void dump_config(int panel_bpp, struct display_timing *timing) -{ - printf("timing->hactive.typ = %d\n", timing->hactive.typ); - printf("timing->vactive.typ = %d\n", timing->vactive.typ); - printf("timing->pixelclock.typ = %d\n", timing->pixelclock.typ); - - printf("timing->hfront_porch.typ = %d\n", timing->hfront_porch.typ); - printf("timing->hsync_len.typ = %d\n", timing->hsync_len.typ); - printf("timing->hback_porch.typ = %d\n", timing->hback_porch.typ); - - printf("timing->vfront_porch.typ %d\n", timing->vfront_porch.typ); - printf("timing->vsync_len.typ = %d\n", timing->vsync_len.typ); - printf("timing->vback_porch.typ = %d\n", timing->vback_porch.typ); - - printf("panel_bits_per_pixel = %d\n", panel_bpp); -} - -static int display_update_config_from_edid(struct udevice *dp_dev, - int *panel_bppp, - struct display_timing *timing) -{ - return display_read_timing(dp_dev, timing); -} - -static int display_init(struct udevice *dev, void *lcdbase, - int fb_bits_per_pixel, struct display_timing *timing) -{ - struct display_plat *disp_uc_plat; - struct dc_ctlr *dc_ctlr; - struct udevice *dp_dev; - const int href_to_sync = 1, vref_to_sync = 1; - int panel_bpp = 18; /* default 18 bits per pixel */ - u32 plld_rate; - int ret; - - /* - * Before we probe the display device (eDP), tell it that this device - * is the source of the display data. - */ - ret = uclass_find_first_device(UCLASS_DISPLAY, &dp_dev); - if (ret) { - debug("%s: device '%s' display not found (ret=%d)\n", __func__, - dev->name, ret); - return ret; - } - - disp_uc_plat = dev_get_uclass_plat(dp_dev); - debug("Found device '%s', disp_uc_priv=%p\n", dp_dev->name, - disp_uc_plat); - disp_uc_plat->src_dev = dev; - - ret = uclass_get_device(UCLASS_DISPLAY, 0, &dp_dev); - if (ret) { - debug("%s: Failed to probe eDP, ret=%d\n", __func__, ret); - return ret; - } - - dc_ctlr = dev_read_addr_ptr(dev); - if (ofnode_decode_display_timing(dev_ofnode(dev), 0, timing)) { - debug("%s: Failed to decode display timing\n", __func__); - return -EINVAL; - } - - ret = display_update_config_from_edid(dp_dev, &panel_bpp, timing); - if (ret) { - debug("%s: Failed to decode EDID, using defaults\n", __func__); - dump_config(panel_bpp, timing); - } - - /* - * The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER - * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the - * update_display_mode() for detail. - */ - plld_rate = clock_set_display_rate(timing->pixelclock.typ * 2); - if (plld_rate == 0) { - printf("dc: clock init failed\n"); - return -EIO; - } else if (plld_rate != timing->pixelclock.typ * 2) { - debug("dc: plld rounded to %u\n", plld_rate); - timing->pixelclock.typ = plld_rate / 2; - } - - /* Init dc */ - ret = tegra_dc_init(dc_ctlr); - if (ret) { - debug("dc: init failed\n"); - return ret; - } - - /* Configure dc mode */ - ret = update_display_mode(dc_ctlr, timing, href_to_sync, vref_to_sync); - if (ret) { - debug("dc: failed to configure display mode\n"); - return ret; - } - - /* Enable dp */ - ret = display_enable(dp_dev, panel_bpp, timing); - if (ret) { - debug("dc: failed to enable display: ret=%d\n", ret); - return ret; - } - - ret = update_window(dc_ctlr, (ulong)lcdbase, fb_bits_per_pixel, timing); - if (ret) { - debug("dc: failed to update window\n"); - return ret; - } - debug("%s: ready\n", __func__); - - return 0; -} - -enum { - /* Maximum LCD size we support */ - LCD_MAX_WIDTH = 1920, - LCD_MAX_HEIGHT = 1200, - LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ -}; - -static int tegra124_lcd_init(struct udevice *dev, void *lcdbase, - enum video_log2_bpp l2bpp) -{ - struct video_priv *uc_priv = dev_get_uclass_priv(dev); - struct display_timing timing; - int ret; - - clock_set_up_plldp(); - clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, 408000000); - - clock_enable(PERIPH_ID_HOST1X); - clock_enable(PERIPH_ID_DISP1); - clock_enable(PERIPH_ID_PWM); - clock_enable(PERIPH_ID_DPAUX); - clock_enable(PERIPH_ID_SOR0); - udelay(2); - - reset_set_enable(PERIPH_ID_HOST1X, 0); - reset_set_enable(PERIPH_ID_DISP1, 0); - reset_set_enable(PERIPH_ID_PWM, 0); - reset_set_enable(PERIPH_ID_DPAUX, 0); - reset_set_enable(PERIPH_ID_SOR0, 0); - - ret = display_init(dev, lcdbase, 1 << l2bpp, &timing); - if (ret) - return ret; - - uc_priv->xsize = roundup(timing.hactive.typ, 16); - uc_priv->ysize = timing.vactive.typ; - uc_priv->bpix = l2bpp; - - video_set_flush_dcache(dev, 1); - debug("%s: done\n", __func__); - - return 0; -} - -static int tegra124_lcd_probe(struct udevice *dev) -{ - struct video_uc_plat *plat = dev_get_uclass_plat(dev); - ulong start; - int ret; - - start = get_timer(0); - bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "lcd"); - ret = tegra124_lcd_init(dev, (void *)plat->base, VIDEO_BPP16); - bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD); - debug("LCD init took %lu ms\n", get_timer(start)); - if (ret) - printf("%s: Error %d\n", __func__, ret); - - return 0; -} - -static int tegra124_lcd_bind(struct udevice *dev) -{ - struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev); - - uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * - (1 << VIDEO_BPP16) / 8; - debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); - - return 0; -} - -static const struct udevice_id tegra124_lcd_ids[] = { - { .compatible = "nvidia,tegra124-dc" }, - { } -}; - -U_BOOT_DRIVER(tegra124_dc) = { - .name = "tegra124-dc", - .id = UCLASS_VIDEO, - .of_match = tegra124_lcd_ids, - .bind = tegra124_lcd_bind, - .probe = tegra124_lcd_probe, -}; diff --git a/drivers/video/tegra124/displayport.h b/drivers/video/tegra124/displayport.h deleted file mode 100644 index a3044475aeb..00000000000 --- a/drivers/video/tegra124/displayport.h +++ /dev/null @@ -1,411 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2014, NVIDIA Corporation. - */ - -#ifndef _TEGRA_DISPLAYPORT_H -#define _TEGRA_DISPLAYPORT_H - -#include - -struct dpaux_ctlr { - u32 reserved0; - u32 intr_en_aux; - u32 reserved2_4; - u32 intr_aux; -}; - -#define DPAUX_INTR_EN_AUX 0x1 -#define DPAUX_INTR_AUX 0x5 -#define DPAUX_DP_AUXDATA_WRITE_W(i) (0x9 + 4 * (i)) -#define DPAUX_DP_AUXDATA_READ_W(i) (0x19 + 4 * (i)) -#define DPAUX_DP_AUXADDR 0x29 -#define DPAUX_DP_AUXCTL 0x2d -#define DPAUX_DP_AUXCTL_CMDLEN_SHIFT 0 -#define DPAUX_DP_AUXCTL_CMDLEN_FIELD 0xff -#define DPAUX_DP_AUXCTL_CMD_SHIFT 12 -#define DPAUX_DP_AUXCTL_CMD_MASK (0xf << 12) -#define DPAUX_DP_AUXCTL_CMD_I2CWR (0 << 12) -#define DPAUX_DP_AUXCTL_CMD_I2CRD (1 << 12) -#define DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT (2 << 12) -#define DPAUX_DP_AUXCTL_CMD_MOTWR (4 << 12) -#define DPAUX_DP_AUXCTL_CMD_MOTRD (5 << 12) -#define DPAUX_DP_AUXCTL_CMD_MOTREQWSTAT (6 << 12) -#define DPAUX_DP_AUXCTL_CMD_AUXWR (8 << 12) -#define DPAUX_DP_AUXCTL_CMD_AUXRD (9 << 12) -#define DPAUX_DP_AUXCTL_TRANSACTREQ_SHIFT 16 -#define DPAUX_DP_AUXCTL_TRANSACTREQ_MASK (0x1 << 16) -#define DPAUX_DP_AUXCTL_TRANSACTREQ_DONE (0 << 16) -#define DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING (1 << 16) -#define DPAUX_DP_AUXCTL_RST_SHIFT 31 -#define DPAUX_DP_AUXCTL_RST_DEASSERT (0 << 31) -#define DPAUX_DP_AUXCTL_RST_ASSERT (1 << 31) -#define DPAUX_DP_AUXSTAT 0x31 -#define DPAUX_DP_AUXSTAT_HPD_STATUS_SHIFT 28 -#define DPAUX_DP_AUXSTAT_HPD_STATUS_UNPLUG (0 << 28) -#define DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED (1 << 28) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_SHIFT 20 -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_MASK (0xf << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_IDLE (0 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_SYNC (1 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_START1 (2 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_COMMAND (3 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_ADDRESS (4 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_LENGTH (5 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_WRITE1 (6 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_READ1 (7 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_GET_M (8 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_STOP1 (9 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_STOP2 (10 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_REPLY (11 << 20) -#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_CLEANUP (12 << 20) -#define DPAUX_DP_AUXSTAT_REPLYTYPE_SHIFT 16 -#define DPAUX_DP_AUXSTAT_REPLYTYPE_MASK (0xf << 16) -#define DPAUX_DP_AUXSTAT_REPLYTYPE_ACK (0 << 16) -#define DPAUX_DP_AUXSTAT_REPLYTYPE_NACK (1 << 16) -#define DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER (2 << 16) -#define DPAUX_DP_AUXSTAT_REPLYTYPE_I2CNACK (4 << 16) -#define DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER (8 << 16) -#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_SHIFT 11 -#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_NOT_PENDING (0 << 11) -#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING (1 << 11) -#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_SHIFT 10 -#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_NOT_PENDING (0 << 10) -#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING (1 << 10) -#define DPAUX_DP_AUXSTAT_RX_ERROR_SHIFT 9 -#define DPAUX_DP_AUXSTAT_RX_ERROR_NOT_PENDING (0 << 9) -#define DPAUX_DP_AUXSTAT_RX_ERROR_PENDING (1 << 9) -#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_SHIFT 8 -#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_NOT_PENDING (0 << 8) -#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING (1 << 8) -#define DPAUX_DP_AUXSTAT_REPLY_M_SHIFT 0 -#define DPAUX_DP_AUXSTAT_REPLY_M_MASK (0xff << 0) -#define DPAUX_HPD_CONFIG (0x3d) -#define DPAUX_HPD_IRQ_CONFIG 0x41 -#define DPAUX_DP_AUX_CONFIG 0x45 -#define DPAUX_HYBRID_PADCTL 0x49 -#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_SHIFT 15 -#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_DISABLE (0 << 15) -#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_ENABLE (1 << 15) -#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_SHIFT 14 -#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_DISABLE (0 << 14) -#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_ENABLE (1 << 14) -#define DPAUX_HYBRID_PADCTL_AUX_CMH_SHIFT 12 -#define DPAUX_HYBRID_PADCTL_AUX_CMH_DEFAULT_MASK (0x3 << 12) -#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_60 (0 << 12) -#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_64 (1 << 12) -#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 (2 << 12) -#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_56 (3 << 12) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_SHIFT 8 -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_DEFAULT_MASK (0x7 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_78 (0 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_60 (1 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_54 (2 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_45 (3 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 (4 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_42 (5 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_39 (6 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_34 (7 << 8) -#define DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT 2 -#define DPAUX_HYBRID_PADCTL_AUX_DRVI_DEFAULT_MASK (0x3f << 2) -#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_SHIFT 1 -#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_DISABLE (0 << 1) -#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE (1 << 1) -#define DPAUX_HYBRID_PADCTL_MODE_SHIFT 0 -#define DPAUX_HYBRID_PADCTL_MODE_AUX 0 -#define DPAUX_HYBRID_PADCTL_MODE_I2C 1 -#define DPAUX_HYBRID_SPARE 0x4d -#define DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP 0 -#define DPAUX_HYBRID_SPARE_PAD_PWR_POWERDOWN 1 - -#define DP_AUX_DEFER_MAX_TRIES 7 -#define DP_AUX_TIMEOUT_MAX_TRIES 2 -#define DP_POWER_ON_MAX_TRIES 3 - -#define DP_AUX_MAX_BYTES 16 - -#define DP_AUX_TIMEOUT_MS 40 -#define DP_DPCP_RETRY_SLEEP_NS 400 - -static const u32 tegra_dp_vs_regs[][4][4] = { - /* postcursor2 L0 */ - { - /* pre-emphasis: L0, L1, L2, L3 */ - {0x13, 0x19, 0x1e, 0x28}, /* voltage swing: L0 */ - {0x1e, 0x25, 0x2d}, /* L1 */ - {0x28, 0x32}, /* L2 */ - {0x3c}, /* L3 */ - }, - - /* postcursor2 L1 */ - { - {0x12, 0x17, 0x1b, 0x25}, - {0x1c, 0x23, 0x2a}, - {0x25, 0x2f}, - {0x39}, - }, - - /* postcursor2 L2 */ - { - {0x12, 0x16, 0x1a, 0x22}, - {0x1b, 0x20, 0x27}, - {0x24, 0x2d}, - {0x36}, - }, - - /* postcursor2 L3 */ - { - {0x11, 0x14, 0x17, 0x1f}, - {0x19, 0x1e, 0x24}, - {0x22, 0x2a}, - {0x32}, - }, -}; - -static const u32 tegra_dp_pe_regs[][4][4] = { - /* postcursor2 L0 */ - { - /* pre-emphasis: L0, L1, L2, L3 */ - {0x00, 0x09, 0x13, 0x25}, /* voltage swing: L0 */ - {0x00, 0x0f, 0x1e}, /* L1 */ - {0x00, 0x14}, /* L2 */ - {0x00}, /* L3 */ - }, - - /* postcursor2 L1 */ - { - {0x00, 0x0a, 0x14, 0x28}, - {0x00, 0x0f, 0x1e}, - {0x00, 0x14}, - {0x00}, - }, - - /* postcursor2 L2 */ - { - {0x00, 0x0a, 0x14, 0x28}, - {0x00, 0x0f, 0x1e}, - {0x00, 0x14}, - {0x00}, - }, - - /* postcursor2 L3 */ - { - {0x00, 0x0a, 0x14, 0x28}, - {0x00, 0x0f, 0x1e}, - {0x00, 0x14}, - {0x00}, - }, -}; - -static const u32 tegra_dp_pc_regs[][4][4] = { - /* postcursor2 L0 */ - { - /* pre-emphasis: L0, L1, L2, L3 */ - {0x00, 0x00, 0x00, 0x00}, /* voltage swing: L0 */ - {0x00, 0x00, 0x00}, /* L1 */ - {0x00, 0x00}, /* L2 */ - {0x00}, /* L3 */ - }, - - /* postcursor2 L1 */ - { - {0x02, 0x02, 0x04, 0x05}, - {0x02, 0x04, 0x05}, - {0x04, 0x05}, - {0x05}, - }, - - /* postcursor2 L2 */ - { - {0x04, 0x05, 0x08, 0x0b}, - {0x05, 0x09, 0x0b}, - {0x08, 0x0a}, - {0x0b}, - }, - - /* postcursor2 L3 */ - { - {0x05, 0x09, 0x0b, 0x12}, - {0x09, 0x0d, 0x12}, - {0x0b, 0x0f}, - {0x12}, - }, -}; - -static const u32 tegra_dp_tx_pu[][4][4] = { - /* postcursor2 L0 */ - { - /* pre-emphasis: L0, L1, L2, L3 */ - {0x20, 0x30, 0x40, 0x60}, /* voltage swing: L0 */ - {0x30, 0x40, 0x60}, /* L1 */ - {0x40, 0x60}, /* L2 */ - {0x60}, /* L3 */ - }, - - /* postcursor2 L1 */ - { - {0x20, 0x20, 0x30, 0x50}, - {0x30, 0x40, 0x50}, - {0x40, 0x50}, - {0x60}, - }, - - /* postcursor2 L2 */ - { - {0x20, 0x20, 0x30, 0x40}, - {0x30, 0x30, 0x40}, - {0x40, 0x50}, - {0x60}, - }, - - /* postcursor2 L3 */ - { - {0x20, 0x20, 0x20, 0x40}, - {0x30, 0x30, 0x40}, - {0x40, 0x40}, - {0x60}, - }, -}; - -enum { - DRIVECURRENT_LEVEL0 = 0, - DRIVECURRENT_LEVEL1 = 1, - DRIVECURRENT_LEVEL2 = 2, - DRIVECURRENT_LEVEL3 = 3, -}; - -enum { - PREEMPHASIS_DISABLED = 0, - PREEMPHASIS_LEVEL1 = 1, - PREEMPHASIS_LEVEL2 = 2, - PREEMPHASIS_LEVEL3 = 3, -}; - -enum { - POSTCURSOR2_LEVEL0 = 0, - POSTCURSOR2_LEVEL1 = 1, - POSTCURSOR2_LEVEL2 = 2, - POSTCURSOR2_LEVEL3 = 3, - POSTCURSOR2_SUPPORTED -}; - -static inline int tegra_dp_is_max_vs(u32 pe, u32 vs) -{ - return (vs < (DRIVECURRENT_LEVEL3 - pe)) ? 0 : 1; -} - -static inline int tegra_dp_is_max_pe(u32 pe, u32 vs) -{ - return (pe < (PREEMPHASIS_LEVEL3 - vs)) ? 0 : 1; -} - -static inline int tegra_dp_is_max_pc(u32 pc) -{ - return (pc < POSTCURSOR2_LEVEL3) ? 0 : 1; -} - -/* DPCD definitions which are not defined in drm_dp_helper.h */ -#define DP_DPCD_REV_MAJOR_SHIFT 4 -#define DP_DPCD_REV_MAJOR_MASK (0xf << 4) -#define DP_DPCD_REV_MINOR_SHIFT 0 -#define DP_DPCD_REV_MINOR_MASK 0xf - -#define DP_MAX_LINK_RATE_VAL_1_62_GPBS 0x6 -#define DP_MAX_LINK_RATE_VAL_2_70_GPBS 0xa -#define DP_MAX_LINK_RATE_VAL_5_40_GPBS 0x4 - -#define DP_MAX_LANE_COUNT_LANE_1 0x1 -#define DP_MAX_LANE_COUNT_LANE_2 0x2 -#define DP_MAX_LANE_COUNT_LANE_4 0x4 -#define DP_MAX_LANE_COUNT_TPS3_SUPPORTED_YES (1 << 6) -#define DP_MAX_LANE_COUNT_ENHANCED_FRAMING_YES (1 << 7) - -#define NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT 0 -#define NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T (0x00000001 << 2) -#define NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_F (0x00000000 << 2) -#define NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT 3 -#define NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T (0x00000001 << 5) -#define NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_F (0x00000000 << 5) - -#define DP_MAX_DOWNSPREAD_VAL_NONE 0 -#define DP_MAX_DOWNSPREAD_VAL_0_5_PCT 1 -#define DP_MAX_DOWNSPREAD_NO_AUX_HANDSHAKE_LT_T (1 << 6) - -#define DP_EDP_CONFIGURATION_CAP_ASC_RESET_YES 1 -#define DP_EDP_CONFIGURATION_CAP_FRAMING_CHANGE_YES (1 << 1) - -#define DP_LANE_COUNT_SET_ENHANCEDFRAMING_T (1 << 7) - -#define DP_TRAINING_PATTERN_SET_SC_DISABLED_T (1 << 5) -#define NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_F (0x00000000 << 5) -#define NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_T (0x00000001 << 5) - -#define DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_DISABLE 0 -#define DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_ENABLE 1 - -#define NV_DPCD_TRAINING_LANE0_1_SET2 0x10f -#define NV_DPCD_TRAINING_LANE2_3_SET2 0x110 -#define NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T (1 << 2) -#define NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_F (0 << 2) -#define NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T (1 << 6) -#define NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_F (0 << 6) -#define NV_DPCD_LANEX_SET2_PC2_SHIFT 0 -#define NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT 4 - -#define NV_DPCD_STATUS_LANEX_CR_DONE_SHIFT 0 -#define NV_DPCD_STATUS_LANEX_CR_DONE_NO (0x00000000) -#define NV_DPCD_STATUS_LANEX_CR_DONE_YES (0x00000001) -#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT 1 -#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_NO (0x00000000 << 1) -#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES (0x00000001 << 1) -#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT 2 -#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_NO (0x00000000 << 2) -#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES (0x00000001 << 2) -#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_SHIFT 4 -#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_NO (0x00000000 << 4) -#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES (0x00000001 << 4) -#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT 5 -#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_NO (0x00000000 << 5) -#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES (0x00000001 << 5) -#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT 6 -#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_NO (0x00000000 << 6) -#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES (0x00000001 << 6) - -#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED (0x00000204) -#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_NO (0x00000000) -#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES (0x00000001) - -#define NV_DPCD_STATUS_LANEX_CR_DONE_SHIFT 0 -#define NV_DPCD_STATUS_LANEX_CR_DONE_NO (0x00000000) -#define NV_DPCD_STATUS_LANEX_CR_DONE_YES (0x00000001) -#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT 1 -#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_NO (0x00000000 << 1) -#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES (0x00000001 << 1) -#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT 2 -#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_NO (0x00000000 << 2) -#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES (0x00000001 << 2) -#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_SHIFT 4 -#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_NO (0x00000000 << 4) -#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES (0x00000001 << 4) -#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT 5 -#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_NO (0x00000000 << 5) -#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES (0x00000001 << 5) -#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT 6 -#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_NO (0x00000000 << 6) -#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES (0x00000001 << 6) - -#define NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT 0 -#define NV_DPCD_ADJUST_REQ_LANEX_DC_MASK 0x3 -#define NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT 2 -#define NV_DPCD_ADJUST_REQ_LANEX_PE_MASK (0x3 << 2) -#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT 4 -#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK (0x3 << 4) -#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT 6 -#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK (0x3 << 6) -#define NV_DPCD_ADJUST_REQ_POST_CURSOR2 (0x0000020C) -#define NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK 0x3 -#define NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(i) (i*2) - -#define NV_DPCD_TRAINING_AUX_RD_INTERVAL (0x0000000E) -#define NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_F (0x00000000 << 2) -#endif diff --git a/drivers/video/tegra124/dp.c b/drivers/video/tegra124/dp.c deleted file mode 100644 index b95b14da77d..00000000000 --- a/drivers/video/tegra124/dp.c +++ /dev/null @@ -1,1624 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2011-2013, NVIDIA Corporation. - * Copyright 2014 Google Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "display.h" -#include "edid.h" -#include "sor.h" -#include "displayport.h" - -#define DO_FAST_LINK_TRAINING 1 - -struct tegra_dp_plat { - ulong base; -}; - -/** - * struct tegra_dp_priv - private displayport driver info - * - * @dc_dev: Display controller device that is sending the video feed - */ -struct tegra_dp_priv { - struct udevice *sor; - struct udevice *dc_dev; - struct dpaux_ctlr *regs; - u8 revision; - int enabled; -}; - -struct tegra_dp_priv dp_data; - -static inline u32 tegra_dpaux_readl(struct tegra_dp_priv *dp, u32 reg) -{ - return readl((u32 *)dp->regs + reg); -} - -static inline void tegra_dpaux_writel(struct tegra_dp_priv *dp, u32 reg, - u32 val) -{ - writel(val, (u32 *)dp->regs + reg); -} - -static inline u32 tegra_dc_dpaux_poll_register(struct tegra_dp_priv *dp, - u32 reg, u32 mask, u32 exp_val, - u32 poll_interval_us, - u32 timeout_us) -{ - u32 reg_val = 0; - u32 temp = timeout_us; - - do { - udelay(poll_interval_us); - reg_val = tegra_dpaux_readl(dp, reg); - if (timeout_us > poll_interval_us) - timeout_us -= poll_interval_us; - else - break; - } while ((reg_val & mask) != exp_val); - - if ((reg_val & mask) == exp_val) - return 0; /* success */ - debug("dpaux_poll_register 0x%x: timeout: (reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n", - reg, reg_val, mask, exp_val); - return temp; -} - -static inline int tegra_dpaux_wait_transaction(struct tegra_dp_priv *dp) -{ - /* According to DP spec, each aux transaction needs to finish - within 40ms. */ - if (tegra_dc_dpaux_poll_register(dp, DPAUX_DP_AUXCTL, - DPAUX_DP_AUXCTL_TRANSACTREQ_MASK, - DPAUX_DP_AUXCTL_TRANSACTREQ_DONE, - 100, DP_AUX_TIMEOUT_MS * 1000) != 0) { - debug("dp: DPAUX transaction timeout\n"); - return -1; - } - return 0; -} - -static int tegra_dc_dpaux_write_chunk(struct tegra_dp_priv *dp, u32 cmd, - u32 addr, u8 *data, u32 *size, - u32 *aux_stat) -{ - int i; - u32 reg_val; - u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; - u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; - u32 temp_data; - - if (*size > DP_AUX_MAX_BYTES) - return -1; /* only write one chunk of data */ - - /* Make sure the command is write command */ - switch (cmd) { - case DPAUX_DP_AUXCTL_CMD_I2CWR: - case DPAUX_DP_AUXCTL_CMD_MOTWR: - case DPAUX_DP_AUXCTL_CMD_AUXWR: - break; - default: - debug("dp: aux write cmd 0x%x is invalid\n", cmd); - return -EINVAL; - } - - tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); - for (i = 0; i < DP_AUX_MAX_BYTES / 4; ++i) { - memcpy(&temp_data, data, 4); - tegra_dpaux_writel(dp, DPAUX_DP_AUXDATA_WRITE_W(i), temp_data); - data += 4; - } - - reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); - reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; - reg_val |= cmd; - reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; - reg_val |= ((*size - 1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); - - while ((timeout_retries > 0) && (defer_retries > 0)) { - if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) || - (defer_retries != DP_AUX_DEFER_MAX_TRIES)) - udelay(1); - - reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING; - tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val); - - if (tegra_dpaux_wait_transaction(dp)) - debug("dp: aux write transaction timeout\n"); - - *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); - - if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || - (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || - (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || - (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) { - if (timeout_retries-- > 0) { - debug("dp: aux write retry (0x%x) -- %d\n", - *aux_stat, timeout_retries); - /* clear the error bits */ - tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, - *aux_stat); - continue; - } else { - debug("dp: aux write got error (0x%x)\n", - *aux_stat); - return -ETIMEDOUT; - } - } - - if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) || - (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) { - if (defer_retries-- > 0) { - debug("dp: aux write defer (0x%x) -- %d\n", - *aux_stat, defer_retries); - /* clear the error bits */ - tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, - *aux_stat); - continue; - } else { - debug("dp: aux write defer exceeds max retries (0x%x)\n", - *aux_stat); - return -ETIMEDOUT; - } - } - - if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) == - DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) { - *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK); - return 0; - } else { - debug("dp: aux write failed (0x%x)\n", *aux_stat); - return -EIO; - } - } - /* Should never come to here */ - return -EIO; -} - -static int tegra_dc_dpaux_read_chunk(struct tegra_dp_priv *dp, u32 cmd, - u32 addr, u8 *data, u32 *size, - u32 *aux_stat) -{ - u32 reg_val; - u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; - u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; - - if (*size > DP_AUX_MAX_BYTES) { - debug("only read one chunk\n"); - return -EIO; /* only read one chunk */ - } - - /* Check to make sure the command is read command */ - switch (cmd) { - case DPAUX_DP_AUXCTL_CMD_I2CRD: - case DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT: - case DPAUX_DP_AUXCTL_CMD_MOTRD: - case DPAUX_DP_AUXCTL_CMD_AUXRD: - break; - default: - debug("dp: aux read cmd 0x%x is invalid\n", cmd); - return -EIO; - } - - *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); - if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { - debug("dp: HPD is not detected\n"); - return -EIO; - } - - tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); - - reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); - reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; - reg_val |= cmd; - reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; - reg_val |= ((*size - 1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); - while ((timeout_retries > 0) && (defer_retries > 0)) { - if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) || - (defer_retries != DP_AUX_DEFER_MAX_TRIES)) - udelay(DP_DPCP_RETRY_SLEEP_NS * 2); - - reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING; - tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val); - - if (tegra_dpaux_wait_transaction(dp)) - debug("dp: aux read transaction timeout\n"); - - *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); - - if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || - (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || - (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || - (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) { - if (timeout_retries-- > 0) { - debug("dp: aux read retry (0x%x) -- %d\n", - *aux_stat, timeout_retries); - /* clear the error bits */ - tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, - *aux_stat); - continue; /* retry */ - } else { - debug("dp: aux read got error (0x%x)\n", - *aux_stat); - return -ETIMEDOUT; - } - } - - if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) || - (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) { - if (defer_retries-- > 0) { - debug("dp: aux read defer (0x%x) -- %d\n", - *aux_stat, defer_retries); - /* clear the error bits */ - tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, - *aux_stat); - continue; - } else { - debug("dp: aux read defer exceeds max retries (0x%x)\n", - *aux_stat); - return -ETIMEDOUT; - } - } - - if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) == - DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) { - int i; - u32 temp_data[4]; - - for (i = 0; i < DP_AUX_MAX_BYTES / 4; ++i) - temp_data[i] = tegra_dpaux_readl(dp, - DPAUX_DP_AUXDATA_READ_W(i)); - - *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK); - memcpy(data, temp_data, *size); - - return 0; - } else { - debug("dp: aux read failed (0x%x\n", *aux_stat); - return -EIO; - } - } - /* Should never come to here */ - debug("%s: can't\n", __func__); - - return -EIO; -} - -static int tegra_dc_dpaux_read(struct tegra_dp_priv *dp, u32 cmd, u32 addr, - u8 *data, u32 *size, u32 *aux_stat) -{ - u32 finished = 0; - u32 cur_size; - int ret = 0; - - do { - cur_size = *size - finished; - if (cur_size > DP_AUX_MAX_BYTES) - cur_size = DP_AUX_MAX_BYTES; - - ret = tegra_dc_dpaux_read_chunk(dp, cmd, addr, - data, &cur_size, aux_stat); - if (ret) - break; - - /* cur_size should be the real size returned */ - addr += cur_size; - data += cur_size; - finished += cur_size; - - } while (*size > finished); - *size = finished; - - return ret; -} - -static int tegra_dc_dp_dpcd_read(struct tegra_dp_priv *dp, u32 cmd, - u8 *data_ptr) -{ - u32 size = 1; - u32 status = 0; - int ret; - - ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, - cmd, data_ptr, &size, &status); - if (ret) { - debug("dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n", - cmd, status); - } - - return ret; -} - -static int tegra_dc_dp_dpcd_write(struct tegra_dp_priv *dp, u32 cmd, - u8 data) -{ - u32 size = 1; - u32 status = 0; - int ret; - - ret = tegra_dc_dpaux_write_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXWR, - cmd, &data, &size, &status); - if (ret) { - debug("dp: Failed to write DPCD data. CMD 0x%x, Status 0x%x\n", - cmd, status); - } - - return ret; -} - -static int tegra_dc_i2c_aux_read(struct tegra_dp_priv *dp, u32 i2c_addr, - u8 addr, u8 *data, u32 size, u32 *aux_stat) -{ - u32 finished = 0; - int ret = 0; - - do { - u32 cur_size = min((u32)DP_AUX_MAX_BYTES, size - finished); - - u32 len = 1; - ret = tegra_dc_dpaux_write_chunk( - dp, DPAUX_DP_AUXCTL_CMD_MOTWR, i2c_addr, - &addr, &len, aux_stat); - if (ret) { - debug("%s: error sending address to read.\n", - __func__); - return ret; - } - - ret = tegra_dc_dpaux_read_chunk( - dp, DPAUX_DP_AUXCTL_CMD_I2CRD, i2c_addr, - data, &cur_size, aux_stat); - if (ret) { - debug("%s: error reading data.\n", __func__); - return ret; - } - - /* cur_size should be the real size returned */ - addr += cur_size; - data += cur_size; - finished += cur_size; - } while (size > finished); - - return finished; -} - -static void tegra_dc_dpaux_enable(struct tegra_dp_priv *dp) -{ - /* clear interrupt */ - tegra_dpaux_writel(dp, DPAUX_INTR_AUX, 0xffffffff); - /* do not enable interrupt for now. Enable them when Isr in place */ - tegra_dpaux_writel(dp, DPAUX_INTR_EN_AUX, 0x0); - - tegra_dpaux_writel(dp, DPAUX_HYBRID_PADCTL, - DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 | - DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 | - 0x18 << DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT | - DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE); - - tegra_dpaux_writel(dp, DPAUX_HYBRID_SPARE, - DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP); -} - -#ifdef DEBUG -static void tegra_dc_dp_dump_link_cfg(struct tegra_dp_priv *dp, - const struct tegra_dp_link_config *link_cfg) -{ - debug("DP config: cfg_name cfg_value\n"); - debug(" Lane Count %d\n", - link_cfg->max_lane_count); - debug(" SupportEnhancedFraming %s\n", - link_cfg->support_enhanced_framing ? "Y" : "N"); - debug(" Bandwidth %d\n", - link_cfg->max_link_bw); - debug(" bpp %d\n", - link_cfg->bits_per_pixel); - debug(" EnhancedFraming %s\n", - link_cfg->enhanced_framing ? "Y" : "N"); - debug(" Scramble_enabled %s\n", - link_cfg->scramble_ena ? "Y" : "N"); - debug(" LinkBW %d\n", - link_cfg->link_bw); - debug(" lane_count %d\n", - link_cfg->lane_count); - debug(" activespolarity %d\n", - link_cfg->activepolarity); - debug(" active_count %d\n", - link_cfg->active_count); - debug(" tu_size %d\n", - link_cfg->tu_size); - debug(" active_frac %d\n", - link_cfg->active_frac); - debug(" watermark %d\n", - link_cfg->watermark); - debug(" hblank_sym %d\n", - link_cfg->hblank_sym); - debug(" vblank_sym %d\n", - link_cfg->vblank_sym); -} -#endif - -static int _tegra_dp_lower_link_config(struct tegra_dp_priv *dp, - struct tegra_dp_link_config *cfg) -{ - switch (cfg->link_bw) { - case SOR_LINK_SPEED_G1_62: - if (cfg->max_link_bw > SOR_LINK_SPEED_G1_62) - cfg->link_bw = SOR_LINK_SPEED_G2_7; - cfg->lane_count /= 2; - break; - case SOR_LINK_SPEED_G2_7: - cfg->link_bw = SOR_LINK_SPEED_G1_62; - break; - case SOR_LINK_SPEED_G5_4: - if (cfg->lane_count == 1) { - cfg->link_bw = SOR_LINK_SPEED_G2_7; - cfg->lane_count = cfg->max_lane_count; - } else { - cfg->lane_count /= 2; - } - break; - default: - debug("dp: Error link rate %d\n", cfg->link_bw); - return -ENOLINK; - } - - return (cfg->lane_count > 0) ? 0 : -ENOLINK; -} - -/* - * Calcuate if given cfg can meet the mode request. - * Return 0 if mode is possible, -1 otherwise - */ -static int tegra_dc_dp_calc_config(struct tegra_dp_priv *dp, - const struct display_timing *timing, - struct tegra_dp_link_config *link_cfg) -{ - const u32 link_rate = 27 * link_cfg->link_bw * 1000 * 1000; - const u64 f = 100000; /* precision factor */ - u32 num_linkclk_line; /* Number of link clocks per line */ - u64 ratio_f; /* Ratio of incoming to outgoing data rate */ - u64 frac_f; - u64 activesym_f; /* Activesym per TU */ - u64 activecount_f; - u32 activecount; - u32 activepolarity; - u64 approx_value_f; - u32 activefrac = 0; - u64 accumulated_error_f = 0; - u32 lowest_neg_activecount = 0; - u32 lowest_neg_activepolarity = 0; - u32 lowest_neg_tusize = 64; - u32 num_symbols_per_line; - u64 lowest_neg_activefrac = 0; - u64 lowest_neg_error_f = 64 * f; - u64 watermark_f; - int i; - int neg; - - if (!link_rate || !link_cfg->lane_count || !timing->pixelclock.typ || - !link_cfg->bits_per_pixel) - return -1; - - if ((u64)timing->pixelclock.typ * link_cfg->bits_per_pixel >= - (u64)link_rate * 8 * link_cfg->lane_count) - return -1; - - num_linkclk_line = (u32)(lldiv(link_rate * timing->hactive.typ, - timing->pixelclock.typ)); - - ratio_f = (u64)timing->pixelclock.typ * link_cfg->bits_per_pixel * f; - ratio_f /= 8; - do_div(ratio_f, link_rate * link_cfg->lane_count); - - for (i = 64; i >= 32; --i) { - activesym_f = ratio_f * i; - activecount_f = lldiv(activesym_f, (u32)f) * f; - frac_f = activesym_f - activecount_f; - activecount = (u32)(lldiv(activecount_f, (u32)f)); - - if (frac_f < (lldiv(f, 2))) /* fraction < 0.5 */ - activepolarity = 0; - else { - activepolarity = 1; - frac_f = f - frac_f; - } - - if (frac_f != 0) { - /* warning: frac_f should be 64-bit */ - frac_f = lldiv(f * f, frac_f); /* 1 / fraction */ - if (frac_f > (15 * f)) - activefrac = activepolarity ? 1 : 15; - else - activefrac = activepolarity ? - (u32)lldiv(frac_f, (u32)f) + 1 : - (u32)lldiv(frac_f, (u32)f); - } - - if (activefrac == 1) - activepolarity = 0; - - if (activepolarity == 1) - approx_value_f = activefrac ? lldiv( - (activecount_f + (activefrac * f - f) * f), - (activefrac * f)) : - activecount_f + f; - else - approx_value_f = activefrac ? - activecount_f + lldiv(f, activefrac) : - activecount_f; - - if (activesym_f < approx_value_f) { - accumulated_error_f = num_linkclk_line * - lldiv(approx_value_f - activesym_f, i); - neg = 1; - } else { - accumulated_error_f = num_linkclk_line * - lldiv(activesym_f - approx_value_f, i); - neg = 0; - } - - if ((neg && (lowest_neg_error_f > accumulated_error_f)) || - (accumulated_error_f == 0)) { - lowest_neg_error_f = accumulated_error_f; - lowest_neg_tusize = i; - lowest_neg_activecount = activecount; - lowest_neg_activepolarity = activepolarity; - lowest_neg_activefrac = activefrac; - - if (accumulated_error_f == 0) - break; - } - } - - if (lowest_neg_activefrac == 0) { - link_cfg->activepolarity = 0; - link_cfg->active_count = lowest_neg_activepolarity ? - lowest_neg_activecount : lowest_neg_activecount - 1; - link_cfg->tu_size = lowest_neg_tusize; - link_cfg->active_frac = 1; - } else { - link_cfg->activepolarity = lowest_neg_activepolarity; - link_cfg->active_count = (u32)lowest_neg_activecount; - link_cfg->tu_size = lowest_neg_tusize; - link_cfg->active_frac = (u32)lowest_neg_activefrac; - } - - watermark_f = lldiv(ratio_f * link_cfg->tu_size * (f - ratio_f), f); - link_cfg->watermark = (u32)(lldiv(watermark_f + lowest_neg_error_f, - f)) + link_cfg->bits_per_pixel / 4 - 1; - num_symbols_per_line = (timing->hactive.typ * - link_cfg->bits_per_pixel) / - (8 * link_cfg->lane_count); - - if (link_cfg->watermark > 30) { - debug("dp: sor setting: unable to get a good tusize, force watermark to 30\n"); - link_cfg->watermark = 30; - return -1; - } else if (link_cfg->watermark > num_symbols_per_line) { - debug("dp: sor setting: force watermark to the number of symbols in the line\n"); - link_cfg->watermark = num_symbols_per_line; - return -1; - } - - /* - * Refer to dev_disp.ref for more information. - * # symbols/hblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - - * SetRasterBlankStart.X - 7) * link_clk / pclk) - * - 3 * enhanced_framing - Y - * where Y = (# lanes == 4) 3 : (# lanes == 2) ? 6 : 12 - */ - link_cfg->hblank_sym = (int)lldiv(((uint64_t)timing->hback_porch.typ + - timing->hfront_porch.typ + timing->hsync_len.typ - 7) * - link_rate, timing->pixelclock.typ) - - 3 * link_cfg->enhanced_framing - - (12 / link_cfg->lane_count); - - if (link_cfg->hblank_sym < 0) - link_cfg->hblank_sym = 0; - - /* - * Refer to dev_disp.ref for more information. - * # symbols/vblank = ((SetRasterBlankStart.X - - * SetRasterBlankEen.X - 25) * link_clk / pclk) - * - Y - 1; - * where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39 - */ - link_cfg->vblank_sym = (int)lldiv(((uint64_t)timing->hactive.typ - 25) - * link_rate, timing->pixelclock.typ) - (36 / - link_cfg->lane_count) - 4; - - if (link_cfg->vblank_sym < 0) - link_cfg->vblank_sym = 0; - - link_cfg->is_valid = 1; -#ifdef DEBUG - tegra_dc_dp_dump_link_cfg(dp, link_cfg); -#endif - - return 0; -} - -static int tegra_dc_dp_init_max_link_cfg( - const struct display_timing *timing, - struct tegra_dp_priv *dp, - struct tegra_dp_link_config *link_cfg) -{ - const int drive_current = 0x40404040; - const int preemphasis = 0x0f0f0f0f; - const int postcursor = 0; - u8 dpcd_data; - int ret; - - ret = tegra_dc_dp_dpcd_read(dp, DP_MAX_LANE_COUNT, &dpcd_data); - if (ret) - return ret; - link_cfg->max_lane_count = dpcd_data & DP_MAX_LANE_COUNT_MASK; - link_cfg->tps3_supported = (dpcd_data & - DP_MAX_LANE_COUNT_TPS3_SUPPORTED_YES) ? 1 : 0; - - link_cfg->support_enhanced_framing = - (dpcd_data & DP_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ? - 1 : 0; - - ret = tegra_dc_dp_dpcd_read(dp, DP_MAX_DOWNSPREAD, &dpcd_data); - if (ret) - return ret; - link_cfg->downspread = (dpcd_data & DP_MAX_DOWNSPREAD_VAL_0_5_PCT) ? - 1 : 0; - - ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_TRAINING_AUX_RD_INTERVAL, - &link_cfg->aux_rd_interval); - if (ret) - return ret; - ret = tegra_dc_dp_dpcd_read(dp, DP_MAX_LINK_RATE, - &link_cfg->max_link_bw); - if (ret) - return ret; - - /* - * Set to a high value for link training and attach. - * Will be re-programmed when dp is enabled. - */ - link_cfg->drive_current = drive_current; - link_cfg->preemphasis = preemphasis; - link_cfg->postcursor = postcursor; - - ret = tegra_dc_dp_dpcd_read(dp, DP_EDP_CONFIGURATION_CAP, &dpcd_data); - if (ret) - return ret; - - link_cfg->alt_scramber_reset_cap = - (dpcd_data & DP_EDP_CONFIGURATION_CAP_ASC_RESET_YES) ? - 1 : 0; - link_cfg->only_enhanced_framing = - (dpcd_data & DP_EDP_CONFIGURATION_CAP_FRAMING_CHANGE_YES) ? - 1 : 0; - - link_cfg->lane_count = link_cfg->max_lane_count; - link_cfg->link_bw = link_cfg->max_link_bw; - link_cfg->enhanced_framing = link_cfg->support_enhanced_framing; - link_cfg->frame_in_ms = (1000 / 60) + 1; - - tegra_dc_dp_calc_config(dp, timing, link_cfg); - return 0; -} - -static int tegra_dc_dp_set_assr(struct tegra_dp_priv *priv, - struct udevice *sor, int ena) -{ - int ret; - - u8 dpcd_data = ena ? - DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_ENABLE : - DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_DISABLE; - - ret = tegra_dc_dp_dpcd_write(priv, DP_EDP_CONFIGURATION_SET, - dpcd_data); - if (ret) - return ret; - - /* Also reset the scrambler to 0xfffe */ - tegra_dc_sor_set_internal_panel(sor, ena); - return 0; -} - -static int tegra_dp_set_link_bandwidth(struct tegra_dp_priv *dp, - struct udevice *sor, - u8 link_bw) -{ - tegra_dc_sor_set_link_bandwidth(sor, link_bw); - - /* Sink side */ - return tegra_dc_dp_dpcd_write(dp, DP_LINK_BW_SET, link_bw); -} - -static int tegra_dp_set_lane_count(struct tegra_dp_priv *dp, - const struct tegra_dp_link_config *link_cfg, - struct udevice *sor) -{ - u8 dpcd_data; - int ret; - - /* check if panel support enhanched_framing */ - dpcd_data = link_cfg->lane_count; - if (link_cfg->enhanced_framing) - dpcd_data |= DP_LANE_COUNT_SET_ENHANCEDFRAMING_T; - ret = tegra_dc_dp_dpcd_write(dp, DP_LANE_COUNT_SET, dpcd_data); - if (ret) - return ret; - - tegra_dc_sor_set_lane_count(sor, link_cfg->lane_count); - - /* Also power down lanes that will not be used */ - return 0; -} - -static int tegra_dc_dp_link_trained(struct tegra_dp_priv *dp, - const struct tegra_dp_link_config *cfg) -{ - u32 lane; - u8 mask; - u8 data; - int ret; - - for (lane = 0; lane < cfg->lane_count; ++lane) { - ret = tegra_dc_dp_dpcd_read(dp, (lane / 2) ? - DP_LANE2_3_STATUS : DP_LANE0_1_STATUS, - &data); - if (ret) - return ret; - mask = (lane & 1) ? - NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES | - NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES | - NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES : - DP_LANE_CR_DONE | - DP_LANE_CHANNEL_EQ_DONE | - DP_LANE_SYMBOL_LOCKED; - if ((data & mask) != mask) - return -1; - } - return 0; -} - -static int tegra_dp_channel_eq_status(struct tegra_dp_priv *dp, - const struct tegra_dp_link_config *cfg) -{ - u32 cnt; - u32 n_lanes = cfg->lane_count; - u8 data; - u8 ce_done = 1; - int ret; - - for (cnt = 0; cnt < n_lanes / 2; cnt++) { - ret = tegra_dc_dp_dpcd_read(dp, DP_LANE0_1_STATUS + cnt, &data); - if (ret) - return ret; - - if (n_lanes == 1) { - ce_done = (data & (0x1 << - NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT)) && - (data & (0x1 << - NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT)); - break; - } else if (!(data & (0x1 << - NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT)) || - !(data & (0x1 << - NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT)) || - !(data & (0x1 << - NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT)) || - !(data & (0x1 << - NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT))) - return -EIO; - } - - if (ce_done) { - ret = tegra_dc_dp_dpcd_read(dp, - DP_LANE_ALIGN_STATUS_UPDATED, - &data); - if (ret) - return ret; - if (!(data & NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES)) - ce_done = 0; - } - - return ce_done ? 0 : -EIO; -} - -static int tegra_dp_clock_recovery_status(struct tegra_dp_priv *dp, - const struct tegra_dp_link_config *cfg) -{ - u32 cnt; - u32 n_lanes = cfg->lane_count; - u8 data_ptr; - int ret; - - for (cnt = 0; cnt < n_lanes / 2; cnt++) { - ret = tegra_dc_dp_dpcd_read(dp, (DP_LANE0_1_STATUS + cnt), - &data_ptr); - if (ret) - return ret; - - if (n_lanes == 1) - return (data_ptr & NV_DPCD_STATUS_LANEX_CR_DONE_YES) ? - 1 : 0; - else if (!(data_ptr & NV_DPCD_STATUS_LANEX_CR_DONE_YES) || - !(data_ptr & (NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES))) - return 0; - } - - return 1; -} - -static int tegra_dp_lt_adjust(struct tegra_dp_priv *dp, u32 pe[4], u32 vs[4], - u32 pc[4], u8 pc_supported, - const struct tegra_dp_link_config *cfg) -{ - size_t cnt; - u8 data_ptr; - u32 n_lanes = cfg->lane_count; - int ret; - - for (cnt = 0; cnt < n_lanes / 2; cnt++) { - ret = tegra_dc_dp_dpcd_read(dp, DP_ADJUST_REQUEST_LANE0_1 + cnt, - &data_ptr); - if (ret) - return ret; - pe[2 * cnt] = (data_ptr & NV_DPCD_ADJUST_REQ_LANEX_PE_MASK) >> - NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT; - vs[2 * cnt] = (data_ptr & NV_DPCD_ADJUST_REQ_LANEX_DC_MASK) >> - NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT; - pe[1 + 2 * cnt] = - (data_ptr & NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK) >> - NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT; - vs[1 + 2 * cnt] = - (data_ptr & NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK) >> - NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT; - } - if (pc_supported) { - ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_ADJUST_REQ_POST_CURSOR2, - &data_ptr); - if (ret) - return ret; - for (cnt = 0; cnt < n_lanes; cnt++) { - pc[cnt] = (data_ptr >> - NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(cnt)) & - NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK; - } - } - - return 0; -} - -static void tegra_dp_wait_aux_training(struct tegra_dp_priv *dp, - bool is_clk_recovery, - const struct tegra_dp_link_config *cfg) -{ - if (!cfg->aux_rd_interval) - udelay(is_clk_recovery ? 200 : 500); - else - mdelay(cfg->aux_rd_interval * 4); -} - -static void tegra_dp_tpg(struct tegra_dp_priv *dp, u32 tp, u32 n_lanes, - const struct tegra_dp_link_config *cfg) -{ - u8 data = (tp == training_pattern_disabled) - ? (tp | NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_F) - : (tp | NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_T); - - tegra_dc_sor_set_dp_linkctl(dp->sor, 1, tp, cfg); - tegra_dc_dp_dpcd_write(dp, DP_TRAINING_PATTERN_SET, data); -} - -static int tegra_dp_link_config(struct tegra_dp_priv *dp, - const struct tegra_dp_link_config *link_cfg) -{ - u8 dpcd_data; - u32 retry; - int ret; - - if (link_cfg->lane_count == 0) { - debug("dp: error: lane count is 0. Can not set link config.\n"); - return -ENOLINK; - } - - /* Set power state if it is not in normal level */ - ret = tegra_dc_dp_dpcd_read(dp, DP_SET_POWER, &dpcd_data); - if (ret) - return ret; - - if (dpcd_data == DP_SET_POWER_D3) { - dpcd_data = DP_SET_POWER_D0; - - /* DP spec requires 3 retries */ - for (retry = 3; retry > 0; --retry) { - ret = tegra_dc_dp_dpcd_write(dp, DP_SET_POWER, - dpcd_data); - if (!ret) - break; - if (retry == 1) { - debug("dp: Failed to set DP panel power\n"); - return ret; - } - } - } - - /* Enable ASSR if possible */ - if (link_cfg->alt_scramber_reset_cap) { - ret = tegra_dc_dp_set_assr(dp, dp->sor, 1); - if (ret) - return ret; - } - - ret = tegra_dp_set_link_bandwidth(dp, dp->sor, link_cfg->link_bw); - if (ret) { - debug("dp: Failed to set link bandwidth\n"); - return ret; - } - ret = tegra_dp_set_lane_count(dp, link_cfg, dp->sor); - if (ret) { - debug("dp: Failed to set lane count\n"); - return ret; - } - tegra_dc_sor_set_dp_linkctl(dp->sor, 1, training_pattern_none, - link_cfg); - - return 0; -} - -static int tegra_dp_lower_link_config(struct tegra_dp_priv *dp, - const struct display_timing *timing, - struct tegra_dp_link_config *cfg) -{ - struct tegra_dp_link_config tmp_cfg; - int ret; - - tmp_cfg = *cfg; - cfg->is_valid = 0; - - ret = _tegra_dp_lower_link_config(dp, cfg); - if (!ret) - ret = tegra_dc_dp_calc_config(dp, timing, cfg); - if (!ret) - ret = tegra_dp_link_config(dp, cfg); - if (ret) - goto fail; - - return 0; - -fail: - *cfg = tmp_cfg; - tegra_dp_link_config(dp, &tmp_cfg); - return ret; -} - -static int tegra_dp_lt_config(struct tegra_dp_priv *dp, u32 pe[4], u32 vs[4], - u32 pc[4], const struct tegra_dp_link_config *cfg) -{ - struct udevice *sor = dp->sor; - u32 n_lanes = cfg->lane_count; - u8 pc_supported = cfg->tps3_supported; - u32 cnt; - u32 val; - - for (cnt = 0; cnt < n_lanes; cnt++) { - u32 mask = 0; - u32 pe_reg, vs_reg, pc_reg; - u32 shift = 0; - - switch (cnt) { - case 0: - mask = PR_LANE2_DP_LANE0_MASK; - shift = PR_LANE2_DP_LANE0_SHIFT; - break; - case 1: - mask = PR_LANE1_DP_LANE1_MASK; - shift = PR_LANE1_DP_LANE1_SHIFT; - break; - case 2: - mask = PR_LANE0_DP_LANE2_MASK; - shift = PR_LANE0_DP_LANE2_SHIFT; - break; - case 3: - mask = PR_LANE3_DP_LANE3_MASK; - shift = PR_LANE3_DP_LANE3_SHIFT; - break; - default: - debug("dp: incorrect lane cnt\n"); - return -EINVAL; - } - - pe_reg = tegra_dp_pe_regs[pc[cnt]][vs[cnt]][pe[cnt]]; - vs_reg = tegra_dp_vs_regs[pc[cnt]][vs[cnt]][pe[cnt]]; - pc_reg = tegra_dp_pc_regs[pc[cnt]][vs[cnt]][pe[cnt]]; - - tegra_dp_set_pe_vs_pc(sor, mask, pe_reg << shift, - vs_reg << shift, pc_reg << shift, - pc_supported); - } - - tegra_dp_disable_tx_pu(dp->sor); - udelay(20); - - for (cnt = 0; cnt < n_lanes; cnt++) { - u32 max_vs_flag = tegra_dp_is_max_vs(pe[cnt], vs[cnt]); - u32 max_pe_flag = tegra_dp_is_max_pe(pe[cnt], vs[cnt]); - - val = (vs[cnt] << NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT) | - (max_vs_flag ? - NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T : - NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_F) | - (pe[cnt] << NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT) | - (max_pe_flag ? - NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T : - NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_F); - tegra_dc_dp_dpcd_write(dp, (DP_TRAINING_LANE0_SET + cnt), val); - } - - if (pc_supported) { - for (cnt = 0; cnt < n_lanes / 2; cnt++) { - u32 max_pc_flag0 = tegra_dp_is_max_pc(pc[cnt]); - u32 max_pc_flag1 = tegra_dp_is_max_pc(pc[cnt + 1]); - val = (pc[cnt] << NV_DPCD_LANEX_SET2_PC2_SHIFT) | - (max_pc_flag0 ? - NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T : - NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_F) | - (pc[cnt + 1] << - NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT) | - (max_pc_flag1 ? - NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T : - NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_F); - tegra_dc_dp_dpcd_write(dp, - NV_DPCD_TRAINING_LANE0_1_SET2 + - cnt, val); - } - } - - return 0; -} - -static int _tegra_dp_channel_eq(struct tegra_dp_priv *dp, u32 pe[4], - u32 vs[4], u32 pc[4], u8 pc_supported, - u32 n_lanes, - const struct tegra_dp_link_config *cfg) -{ - u32 retry_cnt; - - for (retry_cnt = 0; retry_cnt < 4; retry_cnt++) { - int ret; - - if (retry_cnt) { - ret = tegra_dp_lt_adjust(dp, pe, vs, pc, pc_supported, - cfg); - if (ret) - return ret; - tegra_dp_lt_config(dp, pe, vs, pc, cfg); - } - - tegra_dp_wait_aux_training(dp, false, cfg); - - if (!tegra_dp_clock_recovery_status(dp, cfg)) { - debug("dp: CR failed in channel EQ sequence!\n"); - break; - } - - if (!tegra_dp_channel_eq_status(dp, cfg)) - return 0; - } - - return -EIO; -} - -static int tegra_dp_channel_eq(struct tegra_dp_priv *dp, u32 pe[4], u32 vs[4], - u32 pc[4], - const struct tegra_dp_link_config *cfg) -{ - u32 n_lanes = cfg->lane_count; - u8 pc_supported = cfg->tps3_supported; - int ret; - u32 tp_src = training_pattern_2; - - if (pc_supported) - tp_src = training_pattern_3; - - tegra_dp_tpg(dp, tp_src, n_lanes, cfg); - - ret = _tegra_dp_channel_eq(dp, pe, vs, pc, pc_supported, n_lanes, cfg); - - tegra_dp_tpg(dp, training_pattern_disabled, n_lanes, cfg); - - return ret; -} - -static int _tegra_dp_clk_recovery(struct tegra_dp_priv *dp, u32 pe[4], - u32 vs[4], u32 pc[4], u8 pc_supported, - u32 n_lanes, - const struct tegra_dp_link_config *cfg) -{ - u32 vs_temp[4]; - u32 retry_cnt = 0; - - do { - tegra_dp_lt_config(dp, pe, vs, pc, cfg); - tegra_dp_wait_aux_training(dp, true, cfg); - - if (tegra_dp_clock_recovery_status(dp, cfg)) - return 0; - - memcpy(vs_temp, vs, sizeof(vs_temp)); - tegra_dp_lt_adjust(dp, pe, vs, pc, pc_supported, cfg); - - if (memcmp(vs_temp, vs, sizeof(vs_temp))) - retry_cnt = 0; - else - ++retry_cnt; - } while (retry_cnt < 5); - - return -EIO; -} - -static int tegra_dp_clk_recovery(struct tegra_dp_priv *dp, u32 pe[4], - u32 vs[4], u32 pc[4], - const struct tegra_dp_link_config *cfg) -{ - u32 n_lanes = cfg->lane_count; - u8 pc_supported = cfg->tps3_supported; - int err; - - tegra_dp_tpg(dp, training_pattern_1, n_lanes, cfg); - - err = _tegra_dp_clk_recovery(dp, pe, vs, pc, pc_supported, n_lanes, - cfg); - if (err < 0) - tegra_dp_tpg(dp, training_pattern_disabled, n_lanes, cfg); - - return err; -} - -static int tegra_dc_dp_full_link_training(struct tegra_dp_priv *dp, - const struct display_timing *timing, - struct tegra_dp_link_config *cfg) -{ - struct udevice *sor = dp->sor; - int err; - u32 pe[4], vs[4], pc[4]; - - tegra_sor_precharge_lanes(sor, cfg); - -retry_cr: - memset(pe, PREEMPHASIS_DISABLED, sizeof(pe)); - memset(vs, DRIVECURRENT_LEVEL0, sizeof(vs)); - memset(pc, POSTCURSOR2_LEVEL0, sizeof(pc)); - - err = tegra_dp_clk_recovery(dp, pe, vs, pc, cfg); - if (err) { - if (!tegra_dp_lower_link_config(dp, timing, cfg)) - goto retry_cr; - - debug("dp: clk recovery failed\n"); - goto fail; - } - - err = tegra_dp_channel_eq(dp, pe, vs, pc, cfg); - if (err) { - if (!tegra_dp_lower_link_config(dp, timing, cfg)) - goto retry_cr; - - debug("dp: channel equalization failed\n"); - goto fail; - } -#ifdef DEBUG - tegra_dc_dp_dump_link_cfg(dp, cfg); -#endif - return 0; - -fail: - return err; -} - -/* - * All link training functions are ported from kernel dc driver. - * See more details at drivers/video/tegra/dc/dp.c - */ -static int tegra_dc_dp_fast_link_training(struct tegra_dp_priv *dp, - const struct tegra_dp_link_config *link_cfg, - struct udevice *sor) -{ - u8 link_bw; - u8 lane_count; - u16 data16; - u32 data32; - u32 size; - u32 status; - int j; - u32 mask = 0xffff >> ((4 - link_cfg->lane_count) * 4); - - tegra_dc_sor_set_lane_parm(sor, link_cfg); - tegra_dc_dp_dpcd_write(dp, DP_MAIN_LINK_CHANNEL_CODING_SET, - DP_SET_ANSI_8B10B); - - /* Send TP1 */ - tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_1, link_cfg); - tegra_dc_dp_dpcd_write(dp, DP_TRAINING_PATTERN_SET, - DP_TRAINING_PATTERN_1); - - for (j = 0; j < link_cfg->lane_count; ++j) - tegra_dc_dp_dpcd_write(dp, DP_TRAINING_LANE0_SET + j, 0x24); - udelay(520); - - size = sizeof(data16); - tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, - DP_LANE0_1_STATUS, (u8 *)&data16, &size, &status); - status = mask & 0x1111; - if ((data16 & status) != status) { - debug("dp: Link training error for TP1 (%#x, status %#x)\n", - data16, status); - return -EFAULT; - } - - /* enable ASSR */ - tegra_dc_dp_set_assr(dp, sor, link_cfg->scramble_ena); - tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_3, link_cfg); - - tegra_dc_dp_dpcd_write(dp, DP_TRAINING_PATTERN_SET, - link_cfg->link_bw == 20 ? 0x23 : 0x22); - for (j = 0; j < link_cfg->lane_count; ++j) - tegra_dc_dp_dpcd_write(dp, DP_TRAINING_LANE0_SET + j, 0x24); - udelay(520); - - size = sizeof(data32); - tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, DP_LANE0_1_STATUS, - (u8 *)&data32, &size, &status); - if ((data32 & mask) != (0x7777 & mask)) { - debug("dp: Link training error for TP2/3 (0x%x)\n", data32); - return -EFAULT; - } - - tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_disabled, - link_cfg); - tegra_dc_dp_dpcd_write(dp, DP_TRAINING_PATTERN_SET, 0); - - if (tegra_dc_dp_link_trained(dp, link_cfg)) { - tegra_dc_sor_read_link_config(sor, &link_bw, &lane_count); - debug("Fast link training failed, link bw %d, lane # %d\n", - link_bw, lane_count); - return -EFAULT; - } - - debug("Fast link training succeeded, link bw %d, lane %d\n", - link_cfg->link_bw, link_cfg->lane_count); - - return 0; -} - -static int tegra_dp_do_link_training(struct tegra_dp_priv *dp, - struct tegra_dp_link_config *link_cfg, - const struct display_timing *timing, - struct udevice *sor) -{ - u8 link_bw; - u8 lane_count; - int ret; - - if (DO_FAST_LINK_TRAINING) { - ret = tegra_dc_dp_fast_link_training(dp, link_cfg, sor); - if (ret) { - debug("dp: fast link training failed\n"); - } else { - /* - * set to a known-good drive setting if fast link - * succeeded. Ignore any error. - */ - ret = tegra_dc_sor_set_voltage_swing(dp->sor, link_cfg); - if (ret) - debug("Failed to set voltage swing\n"); - } - } else { - ret = -ENOSYS; - } - if (ret) { - /* Try full link training then */ - ret = tegra_dc_dp_full_link_training(dp, timing, link_cfg); - if (ret) { - debug("dp: full link training failed\n"); - return ret; - } - } - - /* Everything is good; double check the link config */ - tegra_dc_sor_read_link_config(sor, &link_bw, &lane_count); - - if ((link_cfg->link_bw == link_bw) && - (link_cfg->lane_count == lane_count)) - return 0; - else - return -EFAULT; -} - -static int tegra_dc_dp_explore_link_cfg(struct tegra_dp_priv *dp, - struct tegra_dp_link_config *link_cfg, - struct udevice *sor, - const struct display_timing *timing) -{ - struct tegra_dp_link_config temp_cfg; - - if (!timing->pixelclock.typ || !timing->hactive.typ || - !timing->vactive.typ) { - debug("dp: error mode configuration"); - return -EINVAL; - } - if (!link_cfg->max_link_bw || !link_cfg->max_lane_count) { - debug("dp: error link configuration"); - return -EINVAL; - } - - link_cfg->is_valid = 0; - - memcpy(&temp_cfg, link_cfg, sizeof(temp_cfg)); - - temp_cfg.link_bw = temp_cfg.max_link_bw; - temp_cfg.lane_count = temp_cfg.max_lane_count; - - /* - * set to max link config - */ - if ((!tegra_dc_dp_calc_config(dp, timing, &temp_cfg)) && - (!tegra_dp_link_config(dp, &temp_cfg)) && - (!tegra_dp_do_link_training(dp, &temp_cfg, timing, sor))) - /* the max link cfg is doable */ - memcpy(link_cfg, &temp_cfg, sizeof(temp_cfg)); - - return link_cfg->is_valid ? 0 : -EFAULT; -} - -static int tegra_dp_hpd_plug(struct tegra_dp_priv *dp) -{ - const int vdd_to_hpd_delay_ms = 200; - u32 val; - ulong start; - - start = get_timer(0); - do { - val = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); - if (val & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED) - return 0; - udelay(100); - } while (get_timer(start) < vdd_to_hpd_delay_ms); - - return -EIO; -} - -static int tegra_dc_dp_sink_out_of_sync(struct tegra_dp_priv *dp, u32 delay_ms) -{ - u8 dpcd_data; - int out_of_sync; - int ret; - - debug("%s: delay=%d\n", __func__, delay_ms); - mdelay(delay_ms); - ret = tegra_dc_dp_dpcd_read(dp, DP_SINK_STATUS, &dpcd_data); - if (ret) - return ret; - - out_of_sync = !(dpcd_data & DP_SINK_STATUS_PORT0_IN_SYNC); - if (out_of_sync) - debug("SINK receive port 0 out of sync, data=%x\n", dpcd_data); - else - debug("SINK is in synchronization\n"); - - return out_of_sync; -} - -static int tegra_dc_dp_check_sink(struct tegra_dp_priv *dp, - struct tegra_dp_link_config *link_cfg, - const struct display_timing *timing) -{ - const int max_retry = 5; - int delay_frame; - int retries; - - /* - * DP TCON may skip some main stream frames, thus we need to wait - * some delay before reading the DPCD SINK STATUS register, starting - * from 5 - */ - delay_frame = 5; - - retries = max_retry; - do { - int ret; - - if (!tegra_dc_dp_sink_out_of_sync(dp, link_cfg->frame_in_ms * - delay_frame)) - return 0; - - debug("%s: retries left %d\n", __func__, retries); - if (!retries--) { - printf("DP: Out of sync after %d retries\n", max_retry); - return -EIO; - } - ret = tegra_dc_sor_detach(dp->dc_dev, dp->sor); - if (ret) - return ret; - if (tegra_dc_dp_explore_link_cfg(dp, link_cfg, dp->sor, - timing)) { - debug("dp: %s: error to configure link\n", __func__); - continue; - } - - tegra_dc_sor_set_power_state(dp->sor, 1); - tegra_dc_sor_attach(dp->dc_dev, dp->sor, link_cfg, timing); - - /* Increase delay_frame for next try in case the sink is - skipping more frames */ - delay_frame += 10; - } while (1); -} - -int tegra_dp_enable(struct udevice *dev, int panel_bpp, - const struct display_timing *timing) -{ - struct tegra_dp_priv *priv = dev_get_priv(dev); - struct tegra_dp_link_config slink_cfg, *link_cfg = &slink_cfg; - struct udevice *sor; - int data; - int retry; - int ret; - - memset(link_cfg, '\0', sizeof(*link_cfg)); - link_cfg->is_valid = 0; - link_cfg->scramble_ena = 1; - - tegra_dc_dpaux_enable(priv); - - if (tegra_dp_hpd_plug(priv) < 0) { - debug("dp: hpd plug failed\n"); - return -EIO; - } - - link_cfg->bits_per_pixel = panel_bpp; - if (tegra_dc_dp_init_max_link_cfg(timing, priv, link_cfg)) { - debug("dp: failed to init link configuration\n"); - return -ENOLINK; - } - - ret = uclass_first_device_err(UCLASS_VIDEO_BRIDGE, &sor); - if (ret) { - debug("dp: failed to find SOR device: ret=%d\n", ret); - return ret; - } - priv->sor = sor; - ret = tegra_dc_sor_enable_dp(sor, link_cfg); - if (ret) - return ret; - - tegra_dc_sor_set_panel_power(sor, 1); - - /* Write power on to DPCD */ - data = DP_SET_POWER_D0; - retry = 0; - do { - ret = tegra_dc_dp_dpcd_write(priv, DP_SET_POWER, data); - } while ((retry++ < DP_POWER_ON_MAX_TRIES) && ret); - - if (ret || retry >= DP_POWER_ON_MAX_TRIES) { - debug("dp: failed to power on panel (0x%x)\n", ret); - return -ENETUNREACH; - goto error_enable; - } - - /* Confirm DP plugging status */ - if (!(tegra_dpaux_readl(priv, DPAUX_DP_AUXSTAT) & - DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { - debug("dp: could not detect HPD\n"); - return -ENXIO; - } - - /* Check DP version */ - if (tegra_dc_dp_dpcd_read(priv, DP_DPCD_REV, &priv->revision)) { - debug("dp: failed to read the revision number from sink\n"); - return -EIO; - } - - if (tegra_dc_dp_explore_link_cfg(priv, link_cfg, sor, timing)) { - debug("dp: error configuring link\n"); - return -ENOMEDIUM; - } - - tegra_dc_sor_set_power_state(sor, 1); - ret = tegra_dc_sor_attach(priv->dc_dev, sor, link_cfg, timing); - if (ret && ret != -EEXIST) - return ret; - - /* - * This takes a long time, but can apparently resolve a failure to - * bring up the display correctly. - */ - if (0) { - ret = tegra_dc_dp_check_sink(priv, link_cfg, timing); - if (ret) - return ret; - } - - /* Power down the unused lanes to save power - a few hundred mW */ - tegra_dc_sor_power_down_unused_lanes(sor, link_cfg); - - ret = video_bridge_set_backlight(sor, 80); - if (ret) { - debug("dp: failed to set backlight\n"); - return ret; - } - - priv->enabled = true; -error_enable: - return 0; -} - -static int tegra_dp_of_to_plat(struct udevice *dev) -{ - struct tegra_dp_plat *plat = dev_get_plat(dev); - - plat->base = dev_read_addr(dev); - - return 0; -} - -static int tegra_dp_read_edid(struct udevice *dev, u8 *buf, int buf_size) -{ - struct tegra_dp_priv *priv = dev_get_priv(dev); - const int tegra_edid_i2c_address = 0x50; - u32 aux_stat = 0; - - tegra_dc_dpaux_enable(priv); - - return tegra_dc_i2c_aux_read(priv, tegra_edid_i2c_address, 0, buf, - buf_size, &aux_stat); -} - -static const struct dm_display_ops dp_tegra_ops = { - .read_edid = tegra_dp_read_edid, - .enable = tegra_dp_enable, -}; - -static int dp_tegra_probe(struct udevice *dev) -{ - struct tegra_dp_plat *plat = dev_get_plat(dev); - struct tegra_dp_priv *priv = dev_get_priv(dev); - struct display_plat *disp_uc_plat = dev_get_uclass_plat(dev); - - priv->regs = (struct dpaux_ctlr *)plat->base; - priv->enabled = false; - - /* Remember the display controller that is sending us video */ - priv->dc_dev = disp_uc_plat->src_dev; - - return 0; -} - -static const struct udevice_id tegra_dp_ids[] = { - { .compatible = "nvidia,tegra124-dpaux" }, - { .compatible = "nvidia,tegra210-dpaux" }, - { } -}; - -U_BOOT_DRIVER(dp_tegra) = { - .name = "dpaux_tegra", - .id = UCLASS_DISPLAY, - .of_match = tegra_dp_ids, - .of_to_plat = tegra_dp_of_to_plat, - .probe = dp_tegra_probe, - .ops = &dp_tegra_ops, - .priv_auto = sizeof(struct tegra_dp_priv), - .plat_auto = sizeof(struct tegra_dp_plat), -}; diff --git a/drivers/video/tegra124/sor.c b/drivers/video/tegra124/sor.c deleted file mode 100644 index 1ce5330c6bc..00000000000 --- a/drivers/video/tegra124/sor.c +++ /dev/null @@ -1,1083 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2011-2013, NVIDIA Corporation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "displayport.h" -#include "sor.h" -#include - -#define DEBUG_SOR 0 - -#define APBDEV_PMC_DPD_SAMPLE 0x20 -#define APBDEV_PMC_DPD_SAMPLE_ON_DISABLE 0 -#define APBDEV_PMC_DPD_SAMPLE_ON_ENABLE 1 -#define APBDEV_PMC_SEL_DPD_TIM 0x1c8 -#define APBDEV_PMC_SEL_DPD_TIM_SEL_DPD_TIM_DEFAULT 0x7f -#define APBDEV_PMC_IO_DPD2_REQ 0x1c0 -#define APBDEV_PMC_IO_DPD2_REQ_LVDS_SHIFT 25 -#define APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF (0 << 25) -#define APBDEV_PMC_IO_DPD2_REQ_LVDS_ON (1 << 25) -#define APBDEV_PMC_IO_DPD2_REQ_CODE_SHIFT 30 -#define APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK (0x3 << 30) -#define APBDEV_PMC_IO_DPD2_REQ_CODE_IDLE (0 << 30) -#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF (1 << 30) -#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON (2 << 30) -#define APBDEV_PMC_IO_DPD2_STATUS 0x1c4 -#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_SHIFT 25 -#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF (0 << 25) -#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON (1 << 25) - -struct tegra_dc_sor_data { - void *base; - void *pmc_base; - u8 portnum; /* 0 or 1 */ - int power_is_up; - struct udevice *panel; -}; - -static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg) -{ - return readl((u32 *)sor->base + reg); -} - -static inline void tegra_sor_writel(struct tegra_dc_sor_data *sor, u32 reg, - u32 val) -{ - writel(val, (u32 *)sor->base + reg); -} - -static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor, - u32 reg, u32 mask, u32 val) -{ - u32 reg_val = tegra_sor_readl(sor, reg); - reg_val &= ~mask; - reg_val |= val; - tegra_sor_writel(sor, reg, reg_val); -} - -void tegra_dp_disable_tx_pu(struct udevice *dev) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - - tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), - DP_PADCTL_TX_PU_MASK, DP_PADCTL_TX_PU_DISABLE); -} - -void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg, - u32 vs_reg, u32 pc_reg, u8 pc_supported) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - - tegra_sor_write_field(sor, PR(sor->portnum), mask, pe_reg); - tegra_sor_write_field(sor, DC(sor->portnum), mask, vs_reg); - if (pc_supported) { - tegra_sor_write_field(sor, POSTCURSOR(sor->portnum), mask, - pc_reg); - } -} - -static int tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor, u32 reg, - u32 mask, u32 exp_val, - int poll_interval_us, int timeout_ms) -{ - u32 reg_val = 0; - ulong start; - - start = get_timer(0); - do { - reg_val = tegra_sor_readl(sor, reg); - if (((reg_val & mask) == exp_val)) - return 0; - udelay(poll_interval_us); - } while (get_timer(start) < timeout_ms); - - debug("sor_poll_register 0x%x: timeout, (reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n", - reg, reg_val, mask, exp_val); - - return -ETIMEDOUT; -} - -int tegra_dc_sor_set_power_state(struct udevice *dev, int pu_pd) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg_val; - u32 orig_val; - - orig_val = tegra_sor_readl(sor, PWR); - - reg_val = pu_pd ? PWR_NORMAL_STATE_PU : - PWR_NORMAL_STATE_PD; /* normal state only */ - - if (reg_val == orig_val) - return 0; /* No update needed */ - - reg_val |= PWR_SETTING_NEW_TRIGGER; - tegra_sor_writel(sor, PWR, reg_val); - - /* Poll to confirm it is done */ - if (tegra_dc_sor_poll_register(sor, PWR, - PWR_SETTING_NEW_DEFAULT_MASK, - PWR_SETTING_NEW_DONE, - 100, TEGRA_SOR_TIMEOUT_MS)) { - debug("dc timeout waiting for SOR_PWR = NEW_DONE\n"); - return -EFAULT; - } - - return 0; -} - -void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena, - u8 training_pattern, - const struct tegra_dp_link_config *link_cfg) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg_val; - - reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum)); - - if (ena) - reg_val |= DP_LINKCTL_ENABLE_YES; - else - reg_val &= DP_LINKCTL_ENABLE_NO; - - reg_val &= ~DP_LINKCTL_TUSIZE_MASK; - reg_val |= (link_cfg->tu_size << DP_LINKCTL_TUSIZE_SHIFT); - - if (link_cfg->enhanced_framing) - reg_val |= DP_LINKCTL_ENHANCEDFRAME_ENABLE; - - tegra_sor_writel(sor, DP_LINKCTL(sor->portnum), reg_val); - - switch (training_pattern) { - case training_pattern_1: - tegra_sor_writel(sor, DP_TPG, 0x41414141); - break; - case training_pattern_2: - case training_pattern_3: - reg_val = (link_cfg->link_bw == SOR_LINK_SPEED_G5_4) ? - 0x43434343 : 0x42424242; - tegra_sor_writel(sor, DP_TPG, reg_val); - break; - default: - tegra_sor_writel(sor, DP_TPG, 0x50505050); - break; - } -} - -static int tegra_dc_sor_enable_lane_sequencer(struct tegra_dc_sor_data *sor, - int pu, int is_lvds) -{ - u32 reg_val; - - /* SOR lane sequencer */ - if (pu) { - reg_val = LANE_SEQ_CTL_SETTING_NEW_TRIGGER | - LANE_SEQ_CTL_SEQUENCE_DOWN | - LANE_SEQ_CTL_NEW_POWER_STATE_PU; - } else { - reg_val = LANE_SEQ_CTL_SETTING_NEW_TRIGGER | - LANE_SEQ_CTL_SEQUENCE_UP | - LANE_SEQ_CTL_NEW_POWER_STATE_PD; - } - - if (is_lvds) - reg_val |= 15 << LANE_SEQ_CTL_DELAY_SHIFT; - else - reg_val |= 1 << LANE_SEQ_CTL_DELAY_SHIFT; - - tegra_sor_writel(sor, LANE_SEQ_CTL, reg_val); - - if (tegra_dc_sor_poll_register(sor, LANE_SEQ_CTL, - LANE_SEQ_CTL_SETTING_MASK, - LANE_SEQ_CTL_SETTING_NEW_DONE, - 100, TEGRA_SOR_TIMEOUT_MS)) { - debug("dp: timeout while waiting for SOR lane sequencer to power down lanes\n"); - return -1; - } - - return 0; -} - -static int tegra_dc_sor_power_dplanes(struct udevice *dev, - u32 lane_count, int pu) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg_val; - - reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); - - if (pu) { - switch (lane_count) { - case 4: - reg_val |= (DP_PADCTL_PD_TXD_3_NO | - DP_PADCTL_PD_TXD_2_NO); - /* fall through */ - case 2: - reg_val |= DP_PADCTL_PD_TXD_1_NO; - case 1: - reg_val |= DP_PADCTL_PD_TXD_0_NO; - break; - default: - debug("dp: invalid lane number %d\n", lane_count); - return -1; - } - - tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val); - tegra_dc_sor_set_lane_count(dev, lane_count); - } - - return tegra_dc_sor_enable_lane_sequencer(sor, pu, 0); -} - -void tegra_dc_sor_set_panel_power(struct udevice *dev, int power_up) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg_val; - - reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); - - if (power_up) - reg_val |= DP_PADCTL_PAD_CAL_PD_POWERUP; - else - reg_val &= ~DP_PADCTL_PAD_CAL_PD_POWERUP; - - tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val); -} - -static void tegra_dc_sor_config_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div, - u32 pwm_dutycycle) -{ - tegra_sor_writel(sor, PWM_DIV, pwm_div); - tegra_sor_writel(sor, PWM_CTL, - (pwm_dutycycle & PWM_CTL_DUTY_CYCLE_MASK) | - PWM_CTL_SETTING_NEW_TRIGGER); - - if (tegra_dc_sor_poll_register(sor, PWM_CTL, - PWM_CTL_SETTING_NEW_SHIFT, - PWM_CTL_SETTING_NEW_DONE, - 100, TEGRA_SOR_TIMEOUT_MS)) { - debug("dp: timeout while waiting for SOR PWM setting\n"); - } -} - -static void tegra_dc_sor_set_dp_mode(struct udevice *dev, - const struct tegra_dp_link_config *link_cfg) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg_val; - - tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw); - - tegra_dc_sor_set_dp_linkctl(dev, 1, training_pattern_none, link_cfg); - reg_val = tegra_sor_readl(sor, DP_CONFIG(sor->portnum)); - reg_val &= ~DP_CONFIG_WATERMARK_MASK; - reg_val |= link_cfg->watermark; - reg_val &= ~DP_CONFIG_ACTIVESYM_COUNT_MASK; - reg_val |= (link_cfg->active_count << - DP_CONFIG_ACTIVESYM_COUNT_SHIFT); - reg_val &= ~DP_CONFIG_ACTIVESYM_FRAC_MASK; - reg_val |= (link_cfg->active_frac << - DP_CONFIG_ACTIVESYM_FRAC_SHIFT); - if (link_cfg->activepolarity) - reg_val |= DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE; - else - reg_val &= ~DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE; - reg_val |= (DP_CONFIG_ACTIVESYM_CNTL_ENABLE | - DP_CONFIG_RD_RESET_VAL_NEGATIVE); - - tegra_sor_writel(sor, DP_CONFIG(sor->portnum), reg_val); - - /* program h/vblank sym */ - tegra_sor_write_field(sor, DP_AUDIO_HBLANK_SYMBOLS, - DP_AUDIO_HBLANK_SYMBOLS_MASK, - link_cfg->hblank_sym); - - tegra_sor_write_field(sor, DP_AUDIO_VBLANK_SYMBOLS, - DP_AUDIO_VBLANK_SYMBOLS_MASK, - link_cfg->vblank_sym); -} - -static inline void tegra_dc_sor_super_update(struct tegra_dc_sor_data *sor) -{ - tegra_sor_writel(sor, SUPER_STATE0, 0); - tegra_sor_writel(sor, SUPER_STATE0, 1); - tegra_sor_writel(sor, SUPER_STATE0, 0); -} - -static inline void tegra_dc_sor_update(struct tegra_dc_sor_data *sor) -{ - tegra_sor_writel(sor, STATE0, 0); - tegra_sor_writel(sor, STATE0, 1); - tegra_sor_writel(sor, STATE0, 0); -} - -static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up) -{ - u32 reg_val; - void *pmc_base = sor->pmc_base; - - if (up) { - writel(APBDEV_PMC_DPD_SAMPLE_ON_ENABLE, - pmc_base + APBDEV_PMC_DPD_SAMPLE); - writel(10, pmc_base + APBDEV_PMC_SEL_DPD_TIM); - } - - reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_REQ); - reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON || - APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK); - - reg_val = up ? APBDEV_PMC_IO_DPD2_REQ_LVDS_ON | - APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF : - APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF | - APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON; - - writel(reg_val, pmc_base + APBDEV_PMC_IO_DPD2_REQ); - - /* Polling */ - u32 temp = 10 * 1000; - do { - udelay(20); - reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_STATUS); - if (temp > 20) - temp -= 20; - else - break; - } while ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0); - - if ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0) { - debug("PMC_IO_DPD2 polling failed (0x%x)\n", reg_val); - return -EIO; - } - - if (up) { - writel(APBDEV_PMC_DPD_SAMPLE_ON_DISABLE, - pmc_base + APBDEV_PMC_DPD_SAMPLE); - } - - return 0; -} - -void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg_val; - - reg_val = tegra_sor_readl(sor, DP_SPARE(sor->portnum)); - if (is_int) - reg_val |= DP_SPARE_PANEL_INTERNAL; - else - reg_val &= ~DP_SPARE_PANEL_INTERNAL; - - reg_val |= DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK | - DP_SPARE_SEQ_ENABLE_YES; - tegra_sor_writel(sor, DP_SPARE(sor->portnum), reg_val); -} - -void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw, - u8 *lane_count) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg_val; - - reg_val = tegra_sor_readl(sor, CLK_CNTRL); - *link_bw = (reg_val & CLK_CNTRL_DP_LINK_SPEED_MASK) - >> CLK_CNTRL_DP_LINK_SPEED_SHIFT; - reg_val = tegra_sor_readl(sor, - DP_LINKCTL(sor->portnum)); - - switch (reg_val & DP_LINKCTL_LANECOUNT_MASK) { - case DP_LINKCTL_LANECOUNT_ZERO: - *lane_count = 0; - break; - case DP_LINKCTL_LANECOUNT_ONE: - *lane_count = 1; - break; - case DP_LINKCTL_LANECOUNT_TWO: - *lane_count = 2; - break; - case DP_LINKCTL_LANECOUNT_FOUR: - *lane_count = 4; - break; - default: - printf("Unknown lane count\n"); - } -} - -void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - - tegra_sor_write_field(sor, CLK_CNTRL, - CLK_CNTRL_DP_LINK_SPEED_MASK, - link_bw << CLK_CNTRL_DP_LINK_SPEED_SHIFT); -} - -void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg_val; - - reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum)); - reg_val &= ~DP_LINKCTL_LANECOUNT_MASK; - switch (lane_count) { - case 0: - break; - case 1: - reg_val |= DP_LINKCTL_LANECOUNT_ONE; - break; - case 2: - reg_val |= DP_LINKCTL_LANECOUNT_TWO; - break; - case 4: - reg_val |= DP_LINKCTL_LANECOUNT_FOUR; - break; - default: - /* 0 should be handled earlier. */ - printf("dp: Invalid lane count %d\n", lane_count); - return; - } - tegra_sor_writel(sor, DP_LINKCTL(sor->portnum), reg_val); -} - -/* - * The SOR power sequencer does not work for t124 so SW has to - * go through the power sequence manually - * Power up steps from spec: - * STEP PDPORT PDPLL PDBG PLLVCOD PLLCAPD E_DPD PDCAL - * 1 1 1 1 1 1 1 1 - * 2 1 1 1 1 1 0 1 - * 3 1 1 0 1 1 0 1 - * 4 1 0 0 0 0 0 1 - * 5 0 0 0 0 0 0 1 - */ -static int tegra_dc_sor_power_up(struct udevice *dev, int is_lvds) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 reg; - int ret; - - if (sor->power_is_up) - return 0; - - /* - * If for some reason it is already powered up, don't do it again. - * This can happen if U-Boot is the secondary boot loader. - */ - reg = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); - if (reg & DP_PADCTL_PD_TXD_0_NO) - return 0; - - /* Set link bw */ - tegra_dc_sor_set_link_bandwidth(dev, is_lvds ? - CLK_CNTRL_DP_LINK_SPEED_LVDS : - CLK_CNTRL_DP_LINK_SPEED_G1_62); - - /* step 1 */ - tegra_sor_write_field(sor, PLL2, - PLL2_AUX7_PORT_POWERDOWN_MASK | /* PDPORT */ - PLL2_AUX6_BANDGAP_POWERDOWN_MASK | /* PDBG */ - PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, /* PLLCAPD */ - PLL2_AUX7_PORT_POWERDOWN_ENABLE | - PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE | - PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE); - tegra_sor_write_field(sor, PLL0, PLL0_PWR_MASK | /* PDPLL */ - PLL0_VCOPD_MASK, /* PLLVCOPD */ - PLL0_PWR_OFF | PLL0_VCOPD_ASSERT); - tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), - DP_PADCTL_PAD_CAL_PD_POWERDOWN, /* PDCAL */ - DP_PADCTL_PAD_CAL_PD_POWERDOWN); - - /* step 2 */ - ret = tegra_dc_sor_io_set_dpd(sor, 1); - if (ret) - return ret; - udelay(15); - - /* step 3 */ - tegra_sor_write_field(sor, PLL2, - PLL2_AUX6_BANDGAP_POWERDOWN_MASK, - PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE); - udelay(25); - - /* step 4 */ - tegra_sor_write_field(sor, PLL0, - PLL0_PWR_MASK | /* PDPLL */ - PLL0_VCOPD_MASK, /* PLLVCOPD */ - PLL0_PWR_ON | PLL0_VCOPD_RESCIND); - /* PLLCAPD */ - tegra_sor_write_field(sor, PLL2, - PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, - PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE); - udelay(225); - - /* step 5 PDPORT */ - tegra_sor_write_field(sor, PLL2, - PLL2_AUX7_PORT_POWERDOWN_MASK, - PLL2_AUX7_PORT_POWERDOWN_DISABLE); - - sor->power_is_up = 1; - - return 0; -} - -#if DEBUG_SOR -static void dump_sor_reg(struct tegra_dc_sor_data *sor) -{ -#define DUMP_REG(a) printk(BIOS_INFO, \ - "%-32s %03x %08x\n", \ - #a, a, tegra_sor_readl(sor, a)); - - DUMP_REG(SUPER_STATE0); - DUMP_REG(SUPER_STATE1); - DUMP_REG(STATE0); - DUMP_REG(STATE1); - DUMP_REG(NV_HEAD_STATE0(0)); - DUMP_REG(NV_HEAD_STATE0(1)); - DUMP_REG(NV_HEAD_STATE1(0)); - DUMP_REG(NV_HEAD_STATE1(1)); - DUMP_REG(NV_HEAD_STATE2(0)); - DUMP_REG(NV_HEAD_STATE2(1)); - DUMP_REG(NV_HEAD_STATE3(0)); - DUMP_REG(NV_HEAD_STATE3(1)); - DUMP_REG(NV_HEAD_STATE4(0)); - DUMP_REG(NV_HEAD_STATE4(1)); - DUMP_REG(NV_HEAD_STATE5(0)); - DUMP_REG(NV_HEAD_STATE5(1)); - DUMP_REG(CRC_CNTRL); - DUMP_REG(CLK_CNTRL); - DUMP_REG(CAP); - DUMP_REG(PWR); - DUMP_REG(TEST); - DUMP_REG(PLL0); - DUMP_REG(PLL1); - DUMP_REG(PLL2); - DUMP_REG(PLL3); - DUMP_REG(CSTM); - DUMP_REG(LVDS); - DUMP_REG(CRCA); - DUMP_REG(CRCB); - DUMP_REG(SEQ_CTL); - DUMP_REG(LANE_SEQ_CTL); - DUMP_REG(SEQ_INST(0)); - DUMP_REG(SEQ_INST(1)); - DUMP_REG(SEQ_INST(2)); - DUMP_REG(SEQ_INST(3)); - DUMP_REG(SEQ_INST(4)); - DUMP_REG(SEQ_INST(5)); - DUMP_REG(SEQ_INST(6)); - DUMP_REG(SEQ_INST(7)); - DUMP_REG(SEQ_INST(8)); - DUMP_REG(PWM_DIV); - DUMP_REG(PWM_CTL); - DUMP_REG(MSCHECK); - DUMP_REG(XBAR_CTRL); - DUMP_REG(DP_LINKCTL(0)); - DUMP_REG(DP_LINKCTL(1)); - DUMP_REG(DC(0)); - DUMP_REG(DC(1)); - DUMP_REG(LANE_DRIVE_CURRENT(0)); - DUMP_REG(PR(0)); - DUMP_REG(LANE4_PREEMPHASIS(0)); - DUMP_REG(POSTCURSOR(0)); - DUMP_REG(DP_CONFIG(0)); - DUMP_REG(DP_CONFIG(1)); - DUMP_REG(DP_MN(0)); - DUMP_REG(DP_MN(1)); - DUMP_REG(DP_PADCTL(0)); - DUMP_REG(DP_PADCTL(1)); - DUMP_REG(DP_DEBUG(0)); - DUMP_REG(DP_DEBUG(1)); - DUMP_REG(DP_SPARE(0)); - DUMP_REG(DP_SPARE(1)); - DUMP_REG(DP_TPG); - - return; -} -#endif - -static void tegra_dc_sor_config_panel(struct tegra_dc_sor_data *sor, - int is_lvds, - const struct tegra_dp_link_config *link_cfg, - const struct display_timing *timing) -{ - const int head_num = 0; - u32 reg_val = STATE1_ASY_OWNER_HEAD0 << head_num; - u32 vtotal, htotal; - u32 vsync_end, hsync_end; - u32 vblank_end, hblank_end; - u32 vblank_start, hblank_start; - - reg_val |= is_lvds ? STATE1_ASY_PROTOCOL_LVDS_CUSTOM : - STATE1_ASY_PROTOCOL_DP_A; - reg_val |= STATE1_ASY_SUBOWNER_NONE | - STATE1_ASY_CRCMODE_COMPLETE_RASTER; - - reg_val |= STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE; - reg_val |= STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE; - reg_val |= (link_cfg->bits_per_pixel > 18) ? - STATE1_ASY_PIXELDEPTH_BPP_24_444 : - STATE1_ASY_PIXELDEPTH_BPP_18_444; - - tegra_sor_writel(sor, STATE1, reg_val); - - /* - * Skipping programming NV_HEAD_STATE0, assuming: - * interlacing: PROGRESSIVE, dynamic range: VESA, colorspace: RGB - */ - vtotal = timing->vsync_len.typ + timing->vback_porch.typ + - timing->vactive.typ + timing->vfront_porch.typ; - htotal = timing->hsync_len.typ + timing->hback_porch.typ + - timing->hactive.typ + timing->hfront_porch.typ; - - tegra_sor_writel(sor, NV_HEAD_STATE1(head_num), - vtotal << NV_HEAD_STATE1_VTOTAL_SHIFT | - htotal << NV_HEAD_STATE1_HTOTAL_SHIFT); - - vsync_end = timing->vsync_len.typ - 1; - hsync_end = timing->hsync_len.typ - 1; - tegra_sor_writel(sor, NV_HEAD_STATE2(head_num), - vsync_end << NV_HEAD_STATE2_VSYNC_END_SHIFT | - hsync_end << NV_HEAD_STATE2_HSYNC_END_SHIFT); - - vblank_end = vsync_end + timing->vback_porch.typ; - hblank_end = hsync_end + timing->hback_porch.typ; - tegra_sor_writel(sor, NV_HEAD_STATE3(head_num), - vblank_end << NV_HEAD_STATE3_VBLANK_END_SHIFT | - hblank_end << NV_HEAD_STATE3_HBLANK_END_SHIFT); - - vblank_start = vblank_end + timing->vactive.typ; - hblank_start = hblank_end + timing->hactive.typ; - tegra_sor_writel(sor, NV_HEAD_STATE4(head_num), - vblank_start << NV_HEAD_STATE4_VBLANK_START_SHIFT | - hblank_start << NV_HEAD_STATE4_HBLANK_START_SHIFT); - - /* TODO: adding interlace mode support */ - tegra_sor_writel(sor, NV_HEAD_STATE5(head_num), 0x1); - - tegra_sor_write_field(sor, CSTM, - CSTM_ROTCLK_DEFAULT_MASK | - CSTM_LVDS_EN_ENABLE, - 2 << CSTM_ROTCLK_SHIFT | - (is_lvds ? CSTM_LVDS_EN_ENABLE : - CSTM_LVDS_EN_DISABLE)); - - tegra_dc_sor_config_pwm(sor, 1024, 1024); -} - -static void tegra_dc_sor_enable_dc(struct dc_ctlr *disp_ctrl) -{ - u32 reg_val = readl(&disp_ctrl->cmd.state_access); - - writel(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access); - writel(VSYNC_H_POSITION(1), &disp_ctrl->disp.disp_timing_opt); - - /* Enable DC now - otherwise pure text console may not show. */ - writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT, - &disp_ctrl->cmd.disp_cmd); - writel(reg_val, &disp_ctrl->cmd.state_access); -} - -int tegra_dc_sor_enable_dp(struct udevice *dev, - const struct tegra_dp_link_config *link_cfg) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - int ret; - - tegra_sor_write_field(sor, CLK_CNTRL, - CLK_CNTRL_DP_CLK_SEL_MASK, - CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK); - - tegra_sor_write_field(sor, PLL2, - PLL2_AUX6_BANDGAP_POWERDOWN_MASK, - PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE); - udelay(25); - - tegra_sor_write_field(sor, PLL3, - PLL3_PLLVDD_MODE_MASK, - PLL3_PLLVDD_MODE_V3_3); - tegra_sor_writel(sor, PLL0, - 0xf << PLL0_ICHPMP_SHFIT | - 0x3 << PLL0_VCOCAP_SHIFT | - PLL0_PLLREG_LEVEL_V45 | - PLL0_RESISTORSEL_EXT | - PLL0_PWR_ON | PLL0_VCOPD_RESCIND); - tegra_sor_write_field(sor, PLL2, - PLL2_AUX1_SEQ_MASK | - PLL2_AUX9_LVDSEN_OVERRIDE | - PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, - PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE | - PLL2_AUX9_LVDSEN_OVERRIDE | - PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE); - tegra_sor_writel(sor, PLL1, PLL1_TERM_COMPOUT_HIGH | - PLL1_TMDS_TERM_ENABLE); - - if (tegra_dc_sor_poll_register(sor, PLL2, - PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, - PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE, - 100, TEGRA_SOR_TIMEOUT_MS)) { - printf("DP failed to lock PLL\n"); - return -EIO; - } - - tegra_sor_write_field(sor, PLL2, PLL2_AUX2_MASK | - PLL2_AUX7_PORT_POWERDOWN_MASK, - PLL2_AUX2_OVERRIDE_POWERDOWN | - PLL2_AUX7_PORT_POWERDOWN_DISABLE); - - ret = tegra_dc_sor_power_up(dev, 0); - if (ret) { - debug("DP failed to power up\n"); - return ret; - } - - /* re-enable SOR clock */ - clock_sor_enable_edp_clock(); - - /* Power up lanes */ - tegra_dc_sor_power_dplanes(dev, link_cfg->lane_count, 1); - - tegra_dc_sor_set_dp_mode(dev, link_cfg); - debug("%s ret\n", __func__); - - return 0; -} - -int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *dev, - const struct tegra_dp_link_config *link_cfg, - const struct display_timing *timing) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - struct dc_ctlr *disp_ctrl; - u32 reg_val; - - /* Use the first display controller */ - debug("%s\n", __func__); - disp_ctrl = dev_read_addr_ptr(dc_dev); - - tegra_dc_sor_enable_dc(disp_ctrl); - tegra_dc_sor_config_panel(sor, 0, link_cfg, timing); - - writel(0x9f00, &disp_ctrl->cmd.state_ctrl); - writel(0x9f, &disp_ctrl->cmd.state_ctrl); - - writel(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | - PW4_ENABLE | PM0_ENABLE | PM1_ENABLE, - &disp_ctrl->cmd.disp_pow_ctrl); - - reg_val = tegra_sor_readl(sor, TEST); - if (reg_val & TEST_ATTACHED_TRUE) - return -EEXIST; - - tegra_sor_writel(sor, SUPER_STATE1, - SUPER_STATE1_ATTACHED_NO); - - /* - * Enable display2sor clock at least 2 cycles before DC start, - * to clear sor internal valid signal. - */ - writel(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt); - writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl); - writel(0, &disp_ctrl->disp.disp_win_opt); - writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl); - - /* Attach head */ - tegra_dc_sor_update(sor); - tegra_sor_writel(sor, SUPER_STATE1, - SUPER_STATE1_ATTACHED_YES); - tegra_sor_writel(sor, SUPER_STATE1, - SUPER_STATE1_ATTACHED_YES | - SUPER_STATE1_ASY_HEAD_OP_AWAKE | - SUPER_STATE1_ASY_ORMODE_NORMAL); - tegra_dc_sor_super_update(sor); - - /* Enable dc */ - reg_val = readl(&disp_ctrl->cmd.state_access); - writel(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access); - writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT, - &disp_ctrl->cmd.disp_cmd); - writel(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt); - writel(reg_val, &disp_ctrl->cmd.state_access); - - if (tegra_dc_sor_poll_register(sor, TEST, - TEST_ACT_HEAD_OPMODE_DEFAULT_MASK, - TEST_ACT_HEAD_OPMODE_AWAKE, - 100, - TEGRA_SOR_ATTACH_TIMEOUT_MS)) { - printf("dc timeout waiting for OPMOD = AWAKE\n"); - return -ETIMEDOUT; - } else { - debug("%s: sor is attached\n", __func__); - } - -#if DEBUG_SOR - dump_sor_reg(sor); -#endif - debug("%s: ret=%d\n", __func__, 0); - - return 0; -} - -void tegra_dc_sor_set_lane_parm(struct udevice *dev, - const struct tegra_dp_link_config *link_cfg) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - - tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), - link_cfg->drive_current); - tegra_sor_writel(sor, PR(sor->portnum), - link_cfg->preemphasis); - tegra_sor_writel(sor, POSTCURSOR(sor->portnum), - link_cfg->postcursor); - tegra_sor_writel(sor, LVDS, 0); - - tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw); - tegra_dc_sor_set_lane_count(dev, link_cfg->lane_count); - - tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), - DP_PADCTL_TX_PU_ENABLE | - DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK, - DP_PADCTL_TX_PU_ENABLE | - 2 << DP_PADCTL_TX_PU_VALUE_SHIFT); - - /* Precharge */ - tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0xf0); - udelay(20); - - tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0x0); -} - -int tegra_dc_sor_set_voltage_swing(struct udevice *dev, - const struct tegra_dp_link_config *link_cfg) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 drive_current = 0; - u32 pre_emphasis = 0; - - /* Set to a known-good pre-calibrated setting */ - switch (link_cfg->link_bw) { - case SOR_LINK_SPEED_G1_62: - case SOR_LINK_SPEED_G2_7: - drive_current = 0x13131313; - pre_emphasis = 0; - break; - case SOR_LINK_SPEED_G5_4: - debug("T124 does not support 5.4G link clock.\n"); - default: - debug("Invalid sor link bandwidth: %d\n", link_cfg->link_bw); - return -ENOLINK; - } - - tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), drive_current); - tegra_sor_writel(sor, PR(sor->portnum), pre_emphasis); - - return 0; -} - -void tegra_dc_sor_power_down_unused_lanes(struct udevice *dev, - const struct tegra_dp_link_config *link_cfg) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 pad_ctrl = 0; - int err = 0; - - switch (link_cfg->lane_count) { - case 4: - pad_ctrl = DP_PADCTL_PD_TXD_0_NO | - DP_PADCTL_PD_TXD_1_NO | - DP_PADCTL_PD_TXD_2_NO | - DP_PADCTL_PD_TXD_3_NO; - break; - case 2: - pad_ctrl = DP_PADCTL_PD_TXD_0_NO | - DP_PADCTL_PD_TXD_1_NO | - DP_PADCTL_PD_TXD_2_YES | - DP_PADCTL_PD_TXD_3_YES; - break; - case 1: - pad_ctrl = DP_PADCTL_PD_TXD_0_NO | - DP_PADCTL_PD_TXD_1_YES | - DP_PADCTL_PD_TXD_2_YES | - DP_PADCTL_PD_TXD_3_YES; - break; - default: - printf("Invalid sor lane count: %u\n", link_cfg->lane_count); - return; - } - - pad_ctrl |= DP_PADCTL_PAD_CAL_PD_POWERDOWN; - tegra_sor_writel(sor, DP_PADCTL(sor->portnum), pad_ctrl); - - err = tegra_dc_sor_enable_lane_sequencer(sor, 0, 0); - if (err) { - debug("Wait for lane power down failed: %d\n", err); - return; - } -} - -int tegra_sor_precharge_lanes(struct udevice *dev, - const struct tegra_dp_link_config *cfg) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - u32 val = 0; - - switch (cfg->lane_count) { - case 4: - val |= (DP_PADCTL_PD_TXD_3_NO | - DP_PADCTL_PD_TXD_2_NO); - /* fall through */ - case 2: - val |= DP_PADCTL_PD_TXD_1_NO; - /* fall through */ - case 1: - val |= DP_PADCTL_PD_TXD_0_NO; - break; - default: - debug("dp: invalid lane number %d\n", cfg->lane_count); - return -EINVAL; - } - - tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), - (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT), - (val << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT)); - udelay(100); - tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), - (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT), - 0); - - return 0; -} - -static void tegra_dc_sor_enable_sor(struct dc_ctlr *disp_ctrl, bool enable) -{ - u32 reg_val = readl(&disp_ctrl->disp.disp_win_opt); - - reg_val = enable ? reg_val | SOR_ENABLE : reg_val & ~SOR_ENABLE; - writel(reg_val, &disp_ctrl->disp.disp_win_opt); -} - -int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *dev) -{ - struct tegra_dc_sor_data *sor = dev_get_priv(dev); - int dc_reg_ctx[DC_REG_SAVE_SPACE]; - struct dc_ctlr *disp_ctrl; - unsigned long dc_int_mask; - int ret; - - debug("%s\n", __func__); - /* Use the first display controller */ - disp_ctrl = dev_read_addr_ptr(dev); - - /* Sleep mode */ - tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP | - SUPER_STATE1_ASY_ORMODE_SAFE | - SUPER_STATE1_ATTACHED_YES); - tegra_dc_sor_super_update(sor); - - tegra_dc_sor_disable_win_short_raster(disp_ctrl, dc_reg_ctx); - - if (tegra_dc_sor_poll_register(sor, TEST, - TEST_ACT_HEAD_OPMODE_DEFAULT_MASK, - TEST_ACT_HEAD_OPMODE_SLEEP, 100, - TEGRA_SOR_ATTACH_TIMEOUT_MS)) { - debug("dc timeout waiting for OPMOD = SLEEP\n"); - ret = -ETIMEDOUT; - goto err; - } - - tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP | - SUPER_STATE1_ASY_ORMODE_SAFE | - SUPER_STATE1_ATTACHED_NO); - - /* Mask DC interrupts during the 2 dummy frames required for detach */ - dc_int_mask = readl(&disp_ctrl->cmd.int_mask); - writel(0, &disp_ctrl->cmd.int_mask); - - /* Stop DC->SOR path */ - tegra_dc_sor_enable_sor(disp_ctrl, false); - ret = tegra_dc_sor_general_act(disp_ctrl); - if (ret) - goto err; - - /* Stop DC */ - writel(CTRL_MODE_STOP << CTRL_MODE_SHIFT, &disp_ctrl->cmd.disp_cmd); - ret = tegra_dc_sor_general_act(disp_ctrl); - if (ret) - goto err; - - tegra_dc_sor_restore_win_and_raster(disp_ctrl, dc_reg_ctx); - - writel(dc_int_mask, &disp_ctrl->cmd.int_mask); - - return 0; -err: - debug("%s: ret=%d\n", __func__, ret); - - return ret; -} - -static int tegra_sor_set_backlight(struct udevice *dev, int percent) -{ - struct tegra_dc_sor_data *priv = dev_get_priv(dev); - int ret; - - ret = panel_enable_backlight(priv->panel); - if (ret) { - debug("sor: Cannot enable panel backlight\n"); - return ret; - } - - return 0; -} - -static int tegra_sor_of_to_plat(struct udevice *dev) -{ - struct tegra_dc_sor_data *priv = dev_get_priv(dev); - int ret; - - priv->base = dev_read_addr_ptr(dev); - - priv->pmc_base = (void *)syscon_get_first_range(TEGRA_SYSCON_PMC); - if (IS_ERR(priv->pmc_base)) - return PTR_ERR(priv->pmc_base); - - ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "nvidia,panel", - &priv->panel); - if (ret) { - debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, - dev->name, ret); - return ret; - } - - return 0; -} - -static const struct video_bridge_ops tegra_sor_ops = { - .set_backlight = tegra_sor_set_backlight, -}; - -static const struct udevice_id tegra_sor_ids[] = { - { .compatible = "nvidia,tegra124-sor" }, - { } -}; - -U_BOOT_DRIVER(sor_tegra) = { - .name = "sor_tegra", - .id = UCLASS_VIDEO_BRIDGE, - .of_match = tegra_sor_ids, - .of_to_plat = tegra_sor_of_to_plat, - .ops = &tegra_sor_ops, - .priv_auto = sizeof(struct tegra_dc_sor_data), -}; diff --git a/drivers/video/tegra124/sor.h b/drivers/video/tegra124/sor.h deleted file mode 100644 index 2fc9a38267d..00000000000 --- a/drivers/video/tegra124/sor.h +++ /dev/null @@ -1,914 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2011-2013, NVIDIA Corporation. - */ - -#ifndef _VIDEO_TEGRA124_SOR_H -#define _VIDEO_TEGRA124_SOR_H - -#define SUPER_STATE0 0x1 -#define SUPER_STATE0_UPDATE_SHIFT 0 -#define SUPER_STATE0_UPDATE_DEFAULT_MASK 0x1 -#define SUPER_STATE1 0x2 -#define SUPER_STATE1_ATTACHED_SHIFT 3 -#define SUPER_STATE1_ATTACHED_NO (0 << 3) -#define SUPER_STATE1_ATTACHED_YES (1 << 3) -#define SUPER_STATE1_ASY_ORMODE_SHIFT 2 -#define SUPER_STATE1_ASY_ORMODE_SAFE (0 << 2) -#define SUPER_STATE1_ASY_ORMODE_NORMAL (1 << 2) -#define SUPER_STATE1_ASY_HEAD_OP_SHIFT 0 -#define SUPER_STATE1_ASY_HEAD_OP_DEFAULT_MASK 0x3 -#define SUPER_STATE1_ASY_HEAD_OP_SLEEP 0 -#define SUPER_STATE1_ASY_HEAD_OP_SNOOZE 1 -#define SUPER_STATE1_ASY_HEAD_OP_AWAKE 2 -#define STATE0 0x3 -#define STATE0_UPDATE_SHIFT 0 -#define STATE0_UPDATE_DEFAULT_MASK 0x1 -#define STATE1 0x4 -#define STATE1_ASY_PIXELDEPTH_SHIFT 17 -#define STATE1_ASY_PIXELDEPTH_DEFAULT_MASK (0xf << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_16_422 (1 << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_18_444 (2 << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_20_422 (3 << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_24_422 (4 << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_24_444 (5 << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_30_444 (6 << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_32_422 (7 << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_36_444 (8 << 17) -#define STATE1_ASY_PIXELDEPTH_BPP_48_444 (9 << 17) -#define STATE1_ASY_REPLICATE_SHIFT 15 -#define STATE1_ASY_REPLICATE_DEFAULT_MASK (3 << 15) -#define STATE1_ASY_REPLICATE_OFF (0 << 15) -#define STATE1_ASY_REPLICATE_X2 (1 << 15) -#define STATE1_ASY_REPLICATE_X4 (2 << 15) -#define STATE1_ASY_DEPOL_SHIFT 14 -#define STATE1_ASY_DEPOL_DEFAULT_MASK (1 << 14) -#define STATE1_ASY_DEPOL_POSITIVE_TRUE (0 << 14) -#define STATE1_ASY_DEPOL_NEGATIVE_TRUE (1 << 14) -#define STATE1_ASY_VSYNCPOL_SHIFT 13 -#define STATE1_ASY_VSYNCPOL_DEFAULT_MASK (1 << 13) -#define STATE1_ASY_VSYNCPOL_POSITIVE_TRUE (0 << 13) -#define STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE (1 << 13) -#define STATE1_ASY_HSYNCPOL_SHIFT 12 -#define STATE1_ASY_HSYNCPOL_DEFAULT_MASK (1 << 12) -#define STATE1_ASY_HSYNCPOL_POSITIVE_TRUE (0 << 12) -#define STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE (1 << 12) -#define STATE1_ASY_PROTOCOL_SHIFT 8 -#define STATE1_ASY_PROTOCOL_DEFAULT_MASK (0xf << 8) -#define STATE1_ASY_PROTOCOL_LVDS_CUSTOM (0 << 8) -#define STATE1_ASY_PROTOCOL_DP_A (8 << 8) -#define STATE1_ASY_PROTOCOL_DP_B (9 << 8) -#define STATE1_ASY_PROTOCOL_CUSTOM (15 << 8) -#define STATE1_ASY_CRCMODE_SHIFT 6 -#define STATE1_ASY_CRCMODE_DEFAULT_MASK (3 << 6) -#define STATE1_ASY_CRCMODE_ACTIVE_RASTER (0 << 6) -#define STATE1_ASY_CRCMODE_COMPLETE_RASTER (1 << 6) -#define STATE1_ASY_CRCMODE_NON_ACTIVE_RASTER (2 << 6) -#define STATE1_ASY_SUBOWNER_SHIFT 4 -#define STATE1_ASY_SUBOWNER_DEFAULT_MASK (3 << 4) -#define STATE1_ASY_SUBOWNER_NONE (0 << 4) -#define STATE1_ASY_SUBOWNER_SUBHEAD0 (1 << 4) -#define STATE1_ASY_SUBOWNER_SUBHEAD1 (2 << 4) -#define STATE1_ASY_SUBOWNER_BOTH (3 << 4) -#define STATE1_ASY_OWNER_SHIFT 0 -#define STATE1_ASY_OWNER_DEFAULT_MASK 0xf -#define STATE1_ASY_OWNER_NONE 0 -#define STATE1_ASY_OWNER_HEAD0 1 -#define STATE1_ASY_OWNER_HEAD1 2 -#define NV_HEAD_STATE0(i) 0x5 -#define NV_HEAD_STATE0_INTERLACED_SHIFT 4 -#define NV_HEAD_STATE0_INTERLACED_DEFAULT_MASK (3 << 4) -#define NV_HEAD_STATE0_INTERLACED_PROGRESSIVE (0 << 4) -#define NV_HEAD_STATE0_INTERLACED_INTERLACED (1 << 4) -#define NV_HEAD_STATE0_RANGECOMPRESS_SHIFT 3 -#define NV_HEAD_STATE0_RANGECOMPRESS_DEFAULT_MASK (1 << 3) -#define NV_HEAD_STATE0_RANGECOMPRESS_DISABLE (0 << 3) -#define NV_HEAD_STATE0_RANGECOMPRESS_ENABLE (1 << 3) -#define NV_HEAD_STATE0_DYNRANGE_SHIFT 2 -#define NV_HEAD_STATE0_DYNRANGE_DEFAULT_MASK (1 << 2) -#define NV_HEAD_STATE0_DYNRANGE_VESA (0 << 2) -#define NV_HEAD_STATE0_DYNRANGE_CEA (1 << 2) -#define NV_HEAD_STATE0_COLORSPACE_SHIFT 0 -#define NV_HEAD_STATE0_COLORSPACE_DEFAULT_MASK 0x3 -#define NV_HEAD_STATE0_COLORSPACE_RGB 0 -#define NV_HEAD_STATE0_COLORSPACE_YUV_601 1 -#define NV_HEAD_STATE0_COLORSPACE_YUV_709 2 -#define NV_HEAD_STATE1(i) (7 + i) -#define NV_HEAD_STATE1_VTOTAL_SHIFT 16 -#define NV_HEAD_STATE1_VTOTAL_DEFAULT_MASK (0x7fff << 16) -#define NV_HEAD_STATE1_HTOTAL_SHIFT 0 -#define NV_HEAD_STATE1_HTOTAL_DEFAULT_MASK 0x7fff -#define NV_HEAD_STATE2(i) (9 + i) -#define NV_HEAD_STATE2_VSYNC_END_SHIFT 16 -#define NV_HEAD_STATE2_VSYNC_END_DEFAULT_MASK (0x7fff << 16) -#define NV_HEAD_STATE2_HSYNC_END_SHIFT 0 -#define NV_HEAD_STATE2_HSYNC_END_DEFAULT_MASK 0x7fff -#define NV_HEAD_STATE3(i) (0xb + i) -#define NV_HEAD_STATE3_VBLANK_END_SHIFT 16 -#define NV_HEAD_STATE3_VBLANK_END_DEFAULT_MASK (0x7fff << 16) -#define NV_HEAD_STATE3_HBLANK_END_SHIFT 0 -#define NV_HEAD_STATE3_HBLANK_END_DEFAULT_MASK 0x7fff -#define NV_HEAD_STATE4(i) (0xd + i) -#define NV_HEAD_STATE4_VBLANK_START_SHIFT 16 -#define NV_HEAD_STATE4_VBLANK_START_DEFAULT_MASK (0x7fff << 16) -#define NV_HEAD_STATE4_HBLANK_START_SHIFT 0 -#define NV_HEAD_STATE4_HBLANK_START_DEFAULT_MASK 0x7fff -#define NV_HEAD_STATE5(i) (0xf + i) -#define CRC_CNTRL 0x11 -#define CRC_CNTRL_ARM_CRC_ENABLE_SHIFT 0 -#define CRC_CNTRL_ARM_CRC_ENABLE_NO 0 -#define CRC_CNTRL_ARM_CRC_ENABLE_YES 1 -#define CRC_CNTRL_ARM_CRC_ENABLE_DIS 0 -#define CRC_CNTRL_ARM_CRC_ENABLE_EN 1 -#define CLK_CNTRL 0x13 -#define CLK_CNTRL_DP_CLK_SEL_SHIFT 0 -#define CLK_CNTRL_DP_CLK_SEL_MASK 0x3 -#define CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK 0 -#define CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK 1 -#define CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK 2 -#define CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK 3 -#define CLK_CNTRL_DP_LINK_SPEED_SHIFT 2 -#define CLK_CNTRL_DP_LINK_SPEED_MASK (0x1f << 2) -#define CLK_CNTRL_DP_LINK_SPEED_G1_62 (6 << 2) -#define CLK_CNTRL_DP_LINK_SPEED_G2_7 (10 << 2) -#define CLK_CNTRL_DP_LINK_SPEED_LVDS (7 << 2) -#define CAP 0x14 -#define CAP_DP_A_SHIFT 24 -#define CAP_DP_A_DEFAULT_MASK (1 << 24) -#define CAP_DP_A_FALSE (0 << 24) -#define CAP_DP_A_TRUE (1 << 24) -#define CAP_DP_B_SHIFT 25 -#define CAP_DP_B_DEFAULT_MASK (1 << 24) -#define CAP_DP_B_FALSE (0 << 24) -#define CAP_DP_B_TRUE (1 << 24) -#define PWR 0x15 -#define PWR_SETTING_NEW_SHIFT 31 -#define PWR_SETTING_NEW_DEFAULT_MASK (1 << 31) -#define PWR_SETTING_NEW_DONE (0 << 31) -#define PWR_SETTING_NEW_PENDING (1 << 31) -#define PWR_SETTING_NEW_TRIGGER (1 << 31) -#define PWR_MODE_SHIFT 28 -#define PWR_MODE_DEFAULT_MASK (1 << 28) -#define PWR_MODE_NORMAL (0 << 28) -#define PWR_MODE_SAFE (1 << 28) -#define PWR_HALT_DELAY_SHIFT 24 -#define PWR_HALT_DELAY_DEFAULT_MASK (1 << 24) -#define PWR_HALT_DELAY_DONE (0 << 24) -#define PWR_HALT_DELAY_ACTIVE (1 << 24) -#define PWR_SAFE_START_SHIFT 17 -#define PWR_SAFE_START_DEFAULT_MASK (1 << 17) -#define PWR_SAFE_START_NORMAL (0 << 17) -#define PWR_SAFE_START_ALT (1 << 17) -#define PWR_SAFE_STATE_SHIFT 16 -#define PWR_SAFE_STATE_DEFAULT_MASK (1 << 16) -#define PWR_SAFE_STATE_PD (0 << 16) -#define PWR_SAFE_STATE_PU (1 << 16) -#define PWR_NORMAL_START_SHIFT 1 -#define PWR_NORMAL_START_DEFAULT_MASK (1 << 1) -#define PWR_NORMAL_START_NORMAL (0 << 16) -#define PWR_NORMAL_START_ALT (1 << 16) -#define PWR_NORMAL_STATE_SHIFT 0 -#define PWR_NORMAL_STATE_DEFAULT_MASK 0x1 -#define PWR_NORMAL_STATE_PD 0 -#define PWR_NORMAL_STATE_PU 1 -#define TEST 0x16 -#define TEST_TESTMUX_SHIFT 24 -#define TEST_TESTMUX_DEFAULT_MASK (0xff << 24) -#define TEST_TESTMUX_AVSS (0 << 24) -#define TEST_TESTMUX_CLOCKIN (2 << 24) -#define TEST_TESTMUX_PLL_VOL (4 << 24) -#define TEST_TESTMUX_SLOWCLKINT (8 << 24) -#define TEST_TESTMUX_AVDD (16 << 24) -#define TEST_TESTMUX_VDDREG (32 << 24) -#define TEST_TESTMUX_REGREF_VDDREG (64 << 24) -#define TEST_TESTMUX_REGREF_AVDD (128 << 24) -#define TEST_CRC_SHIFT 23 -#define TEST_CRC_PRE_SERIALIZE (0 << 23) -#define TEST_CRC_POST_DESERIALIZE (1 << 23) -#define TEST_TPAT_SHIFT 20 -#define TEST_TPAT_DEFAULT_MASK (7 << 20) -#define TEST_TPAT_LO (0 << 20) -#define TEST_TPAT_TDAT (1 << 20) -#define TEST_TPAT_RAMP (2 << 20) -#define TEST_TPAT_WALK (3 << 20) -#define TEST_TPAT_MAXSTEP (4 << 20) -#define TEST_TPAT_MINSTEP (5 << 20) -#define TEST_DSRC_SHIFT 16 -#define TEST_DSRC_DEFAULT_MASK (3 << 16) -#define TEST_DSRC_NORMAL (0 << 16) -#define TEST_DSRC_DEBUG (1 << 16) -#define TEST_DSRC_TGEN (2 << 16) -#define TEST_HEAD_NUMBER_SHIFT 12 -#define TEST_HEAD_NUMBER_DEFAULT_MASK (3 << 12) -#define TEST_HEAD_NUMBER_NONE (0 << 12) -#define TEST_HEAD_NUMBER_HEAD0 (1 << 12) -#define TEST_HEAD_NUMBER_HEAD1 (2 << 12) -#define TEST_ATTACHED_SHIFT 10 -#define TEST_ATTACHED_DEFAULT_MASK (1 << 10) -#define TEST_ATTACHED_FALSE (0 << 10) -#define TEST_ATTACHED_TRUE (1 << 10) -#define TEST_ACT_HEAD_OPMODE_SHIFT 8 -#define TEST_ACT_HEAD_OPMODE_DEFAULT_MASK (3 << 8) -#define TEST_ACT_HEAD_OPMODE_SLEEP (0 << 8) -#define TEST_ACT_HEAD_OPMODE_SNOOZE (1 << 8) -#define TEST_ACT_HEAD_OPMODE_AWAKE (2 << 8) -#define TEST_INVD_SHIFT 6 -#define TEST_INVD_DISABLE (0 << 6) -#define TEST_INVD_ENABLE (1 << 6) -#define TEST_TEST_ENABLE_SHIFT 1 -#define TEST_TEST_ENABLE_DISABLE (0 << 1) -#define TEST_TEST_ENABLE_ENABLE (1 << 1) -#define PLL0 0x17 -#define PLL0_ICHPMP_SHFIT 24 -#define PLL0_ICHPMP_DEFAULT_MASK (0xf << 24) -#define PLL0_VCOCAP_SHIFT 8 -#define PLL0_VCOCAP_DEFAULT_MASK (0xf << 8) -#define PLL0_PLLREG_LEVEL_SHIFT 6 -#define PLL0_PLLREG_LEVEL_DEFAULT_MASK (3 << 6) -#define PLL0_PLLREG_LEVEL_V25 (0 << 6) -#define PLL0_PLLREG_LEVEL_V15 (1 << 6) -#define PLL0_PLLREG_LEVEL_V35 (2 << 6) -#define PLL0_PLLREG_LEVEL_V45 (3 << 6) -#define PLL0_PULLDOWN_SHIFT 5 -#define PLL0_PULLDOWN_DEFAULT_MASK (1 << 5) -#define PLL0_PULLDOWN_DISABLE (0 << 5) -#define PLL0_PULLDOWN_ENABLE (1 << 5) -#define PLL0_RESISTORSEL_SHIFT 4 -#define PLL0_RESISTORSEL_DEFAULT_MASK (1 << 4) -#define PLL0_RESISTORSEL_INT (0 << 4) -#define PLL0_RESISTORSEL_EXT (1 << 4) -#define PLL0_VCOPD_SHIFT 2 -#define PLL0_VCOPD_MASK (1 << 2) -#define PLL0_VCOPD_RESCIND (0 << 2) -#define PLL0_VCOPD_ASSERT (1 << 2) -#define PLL0_PWR_SHIFT 0 -#define PLL0_PWR_MASK 1 -#define PLL0_PWR_ON 0 -#define PLL0_PWR_OFF 1 -#define PLL1_TMDS_TERM_SHIFT 8 -#define PLL1_TMDS_TERM_DISABLE (0 << 8) -#define PLL1_TMDS_TERM_ENABLE (1 << 8) -#define PLL1 0x18 -#define PLL1_TERM_COMPOUT_SHIFT 15 -#define PLL1_TERM_COMPOUT_LOW (0 << 15) -#define PLL1_TERM_COMPOUT_HIGH (1 << 15) -#define PLL2 0x19 -#define PLL2_DCIR_PLL_RESET_SHIFT 0 -#define PLL2_DCIR_PLL_RESET_OVERRIDE (0 << 0) -#define PLL2_DCIR_PLL_RESET_ALLOW (1 << 0) -#define PLL2_AUX1_SHIFT 17 -#define PLL2_AUX1_SEQ_MASK (1 << 17) -#define PLL2_AUX1_SEQ_PLLCAPPD_ALLOW (0 << 17) -#define PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE (1 << 17) -#define PLL2_AUX2_SHIFT 18 -#define PLL2_AUX2_MASK (1 << 18) -#define PLL2_AUX2_OVERRIDE_POWERDOWN (0 << 18) -#define PLL2_AUX2_ALLOW_POWERDOWN (1 << 18) -#define PLL2_AUX6_SHIFT 22 -#define PLL2_AUX6_BANDGAP_POWERDOWN_MASK (1 << 22) -#define PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE (0 << 22) -#define PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE (1 << 22) -#define PLL2_AUX7_SHIFT 23 -#define PLL2_AUX7_PORT_POWERDOWN_MASK (1 << 23) -#define PLL2_AUX7_PORT_POWERDOWN_DISABLE (0 << 23) -#define PLL2_AUX7_PORT_POWERDOWN_ENABLE (1 << 23) -#define PLL2_AUX8_SHIFT 24 -#define PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK (1 << 24) -#define PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE (0 << 24) -#define PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE (1 << 24) -#define PLL2_AUX9_SHIFT 25 -#define PLL2_AUX9_LVDSEN_ALLOW (0 << 25) -#define PLL2_AUX9_LVDSEN_OVERRIDE (1 << 25) -#define PLL3 0x1a -#define PLL3_PLLVDD_MODE_SHIFT 13 -#define PLL3_PLLVDD_MODE_MASK (1 << 13) -#define PLL3_PLLVDD_MODE_V1_8 (0 << 13) -#define PLL3_PLLVDD_MODE_V3_3 (1 << 13) -#define CSTM 0x1b -#define CSTM_ROTDAT_SHIFT 28 -#define CSTM_ROTDAT_DEFAULT_MASK (7 << 28) -#define CSTM_ROTCLK_SHIFT 24 -#define CSTM_ROTCLK_DEFAULT_MASK (0xf << 24) -#define CSTM_LVDS_EN_SHIFT 16 -#define CSTM_LVDS_EN_DISABLE (0 << 16) -#define CSTM_LVDS_EN_ENABLE (1 << 16) -#define CSTM_LINKACTB_SHIFT 15 -#define CSTM_LINKACTB_DISABLE (0 << 15) -#define CSTM_LINKACTB_ENABLE (1 << 15) -#define CSTM_LINKACTA_SHIFT 14 -#define CSTM_LINKACTA_DISABLE (0 << 14) -#define CSTM_LINKACTA_ENABLE (1 << 14) -#define LVDS 0x1c -#define LVDS_ROTDAT_SHIFT 28 -#define LVDS_ROTDAT_DEFAULT_MASK (7 << 28) -#define LVDS_ROTDAT_RST (0 << 28) -#define LVDS_ROTCLK_SHIFT 24 -#define LVDS_ROTCLK_DEFAULT_MASK (0xf << 24) -#define LVDS_ROTCLK_RST (0 << 24) -#define LVDS_PLLDIV_SHIFT 21 -#define LVDS_PLLDIV_DEFAULT_MASK (1 << 21) -#define LVDS_PLLDIV_BY_7 (0 << 21) -#define LVDS_BALANCED_SHIFT 19 -#define LVDS_BALANCED_DEFAULT_MASK (1 << 19) -#define LVDS_BALANCED_DISABLE (0 << 19) -#define LVDS_BALANCED_ENABLE (1 << 19) -#define LVDS_NEW_MODE_SHIFT 18 -#define LVDS_NEW_MODE_DEFAULT_MASK (1 << 18) -#define LVDS_NEW_MODE_DISABLE (0 << 18) -#define LVDS_NEW_MODE_ENABLE (1 << 18) -#define LVDS_DUP_SYNC_SHIFT 17 -#define LVDS_DUP_SYNC_DEFAULT_MASK (1 << 17) -#define LVDS_DUP_SYNC_DISABLE (0 << 17) -#define LVDS_DUP_SYNC_ENABLE (1 << 17) -#define LVDS_LVDS_EN_SHIFT 16 -#define LVDS_LVDS_EN_DEFAULT_MASK (1 << 16) -#define LVDS_LVDS_EN_ENABLE (1 << 16) -#define LVDS_LINKACTB_SHIFT 15 -#define LVDS_LINKACTB_DEFAULT_MASK (1 << 15) -#define LVDS_LINKACTB_DISABLE (0 << 15) -#define LVDS_LINKACTB_ENABLE (1 << 15) -#define LVDS_LINKACTA_SHIFT 14 -#define LVDS_LINKACTA_DEFAULT_MASK (1 << 14) -#define LVDS_LINKACTA_ENABLE (1 << 14) -#define LVDS_MODE_SHIFT 12 -#define LVDS_MODE_DEFAULT_MASK (3 << 12) -#define LVDS_MODE_LVDS (0 << 12) -#define LVDS_UPPER_SHIFT 11 -#define LVDS_UPPER_DEFAULT_MASK (1 << 11) -#define LVDS_UPPER_FALSE (0 << 11) -#define LVDS_UPPER_TRUE (1 << 11) -#define LVDS_PD_TXCB_SHIFT 9 -#define LVDS_PD_TXCB_DEFAULT_MASK (1 << 9) -#define LVDS_PD_TXCB_ENABLE (0 << 9) -#define LVDS_PD_TXCB_DISABLE (1 << 9) -#define LVDS_PD_TXCA_SHIFT 8 -#define LVDS_PD_TXCA_DEFAULT_MASK (1 << 8) -#define LVDS_PD_TXCA_ENABLE (0 << 8) -#define LVDS_PD_TXDB_3_SHIFT 7 -#define LVDS_PD_TXDB_3_DEFAULT_MASK (1 << 7) -#define LVDS_PD_TXDB_3_ENABLE (0 << 7) -#define LVDS_PD_TXDB_3_DISABLE (1 << 7) -#define LVDS_PD_TXDB_2_SHIFT 6 -#define LVDS_PD_TXDB_2_DEFAULT_MASK (1 << 6) -#define LVDS_PD_TXDB_2_ENABLE (0 << 6) -#define LVDS_PD_TXDB_2_DISABLE (1 << 6) -#define LVDS_PD_TXDB_1_SHIFT 5 -#define LVDS_PD_TXDB_1_DEFAULT_MASK (1 << 5) -#define LVDS_PD_TXDB_1_ENABLE (0 << 5) -#define LVDS_PD_TXDB_1_DISABLE (1 << 5) -#define LVDS_PD_TXDB_0_SHIFT 4 -#define LVDS_PD_TXDB_0_DEFAULT_MASK (1 << 4) -#define LVDS_PD_TXDB_0_ENABLE (0 << 4) -#define LVDS_PD_TXDB_0_DISABLE (1 << 4) -#define LVDS_PD_TXDA_3_SHIFT 3 -#define LVDS_PD_TXDA_3_DEFAULT_MASK (1 << 3) -#define LVDS_PD_TXDA_3_ENABLE (0 << 3) -#define LVDS_PD_TXDA_3_DISABLE (1 << 3) -#define LVDS_PD_TXDA_2_SHIFT 2 -#define LVDS_PD_TXDA_2_DEFAULT_MASK (1 << 2) -#define LVDS_PD_TXDA_2_ENABLE (0 << 2) -#define LVDS_PD_TXDA_1_SHIFT 1 -#define LVDS_PD_TXDA_1_DEFAULT_MASK (1 << 1) -#define LVDS_PD_TXDA_1_ENABLE (0 << 1) -#define LVDS_PD_TXDA_0_SHIFT 0 -#define LVDS_PD_TXDA_0_DEFAULT_MASK 0x1 -#define LVDS_PD_TXDA_0_ENABLE 0 -#define CRCA 0x1d -#define CRCA_VALID_FALSE 0 -#define CRCA_VALID_TRUE 1 -#define CRCA_VALID_RST 1 -#define CRCB 0x1e -#define CRCB_CRC_DEFAULT_MASK 0xffffffff -#define SEQ_CTL 0x20 -#define SEQ_CTL_SWITCH_SHIFT 30 -#define SEQ_CTL_SWITCH_MASK (1 << 30) -#define SEQ_CTL_SWITCH_WAIT (0 << 30) -#define SEQ_CTL_SWITCH_FORCE (1 << 30) -#define SEQ_CTL_STATUS_SHIFT 28 -#define SEQ_CTL_STATUS_MASK (1 << 28) -#define SEQ_CTL_STATUS_STOPPED (0 << 28) -#define SEQ_CTL_STATUS_RUNNING (1 << 28) -#define SEQ_CTL_PC_SHIFT 16 -#define SEQ_CTL_PC_MASK (0xf << 16) -#define SEQ_CTL_PD_PC_ALT_SHIFT 12 -#define SEQ_CTL_PD_PC_ALT_MASK (0xf << 12) -#define SEQ_CTL_PD_PC_SHIFT 8 -#define SEQ_CTL_PD_PC_MASK (0xf << 8) -#define SEQ_CTL_PU_PC_ALT_SHIFT 4 -#define SEQ_CTL_PU_PC_ALT_MASK (0xf << 4) -#define SEQ_CTL_PU_PC_SHIFT 0 -#define SEQ_CTL_PU_PC_MASK 0xf -#define LANE_SEQ_CTL 0x21 -#define LANE_SEQ_CTL_SETTING_NEW_SHIFT 31 -#define LANE_SEQ_CTL_SETTING_MASK (1 << 31) -#define LANE_SEQ_CTL_SETTING_NEW_DONE (0 << 31) -#define LANE_SEQ_CTL_SETTING_NEW_PENDING (1 << 31) -#define LANE_SEQ_CTL_SETTING_NEW_TRIGGER (1 << 31) -#define LANE_SEQ_CTL_SEQ_STATE_SHIFT 28 -#define LANE_SEQ_CTL_SEQ_STATE_IDLE (0 << 28) -#define LANE_SEQ_CTL_SEQ_STATE_BUSY (1 << 28) -#define LANE_SEQ_CTL_SEQUENCE_SHIFT 20 -#define LANE_SEQ_CTL_SEQUENCE_UP (0 << 20) -#define LANE_SEQ_CTL_SEQUENCE_DOWN (1 << 20) -#define LANE_SEQ_CTL_NEW_POWER_STATE_SHIFT 16 -#define LANE_SEQ_CTL_NEW_POWER_STATE_PU (0 << 16) -#define LANE_SEQ_CTL_NEW_POWER_STATE_PD (1 << 16) -#define LANE_SEQ_CTL_DELAY_SHIFT 12 -#define LANE_SEQ_CTL_DELAY_DEFAULT_MASK (0xf << 12) -#define LANE_SEQ_CTL_LANE9_STATE_SHIFT 9 -#define LANE_SEQ_CTL_LANE9_STATE_POWERUP (0 << 9) -#define LANE_SEQ_CTL_LANE9_STATE_POWERDOWN (1 << 9) -#define LANE_SEQ_CTL_LANE8_STATE_SHIFT 8 -#define LANE_SEQ_CTL_LANE8_STATE_POWERUP (0 << 8) -#define LANE_SEQ_CTL_LANE8_STATE_POWERDOWN (1 << 8) -#define LANE_SEQ_CTL_LANE7_STATE_SHIFT 7 -#define LANE_SEQ_CTL_LANE7_STATE_POWERUP (0 << 7) -#define LANE_SEQ_CTL_LANE7_STATE_POWERDOWN (1 << 7) -#define LANE_SEQ_CTL_LANE6_STATE_SHIFT 6 -#define LANE_SEQ_CTL_LANE6_STATE_POWERUP (0 << 6) -#define LANE_SEQ_CTL_LANE6_STATE_POWERDOWN (1 << 6) -#define LANE_SEQ_CTL_LANE5_STATE_SHIFT 5 -#define LANE_SEQ_CTL_LANE5_STATE_POWERUP (0 << 5) -#define LANE_SEQ_CTL_LANE5_STATE_POWERDOWN (1 << 5) -#define LANE_SEQ_CTL_LANE4_STATE_SHIFT 4 -#define LANE_SEQ_CTL_LANE4_STATE_POWERUP (0 << 4) -#define LANE_SEQ_CTL_LANE4_STATE_POWERDOWN (1 << 4) -#define LANE_SEQ_CTL_LANE3_STATE_SHIFT 3 -#define LANE_SEQ_CTL_LANE3_STATE_POWERUP (0 << 3) -#define LANE_SEQ_CTL_LANE3_STATE_POWERDOWN (1 << 3) -#define LANE_SEQ_CTL_LANE2_STATE_SHIFT 2 -#define LANE_SEQ_CTL_LANE2_STATE_POWERUP (0 << 2) -#define LANE_SEQ_CTL_LANE2_STATE_POWERDOWN (1 << 2) -#define LANE_SEQ_CTL_LANE1_STATE_SHIFT 1 -#define LANE_SEQ_CTL_LANE1_STATE_POWERUP (0 << 1) -#define LANE_SEQ_CTL_LANE1_STATE_POWERDOWN (1 << 1) -#define LANE_SEQ_CTL_LANE0_STATE_SHIFT 0 -#define LANE_SEQ_CTL_LANE0_STATE_POWERUP 0 -#define LANE_SEQ_CTL_LANE0_STATE_POWERDOWN 1 -#define SEQ_INST(i) (0x22 + i) -#define SEQ_INST_PLL_PULLDOWN_SHIFT 31 -#define SEQ_INST_PLL_PULLDOWN_DISABLE (0 << 31) -#define SEQ_INST_PLL_PULLDOWN_ENABLE (1 << 31) -#define SEQ_INST_POWERDOWN_MACRO_SHIFT 30 -#define SEQ_INST_POWERDOWN_MACRO_NORMAL (0 << 30) -#define SEQ_INST_POWERDOWN_MACRO_POWERDOWN (1 << 30) -#define SEQ_INST_ASSERT_PLL_RESET_SHIFT 29 -#define SEQ_INST_ASSERT_PLL_RESET_NORMAL (0 << 29) -#define SEQ_INST_ASSERT_PLL_RESET_RST (1 << 29) -#define SEQ_INST_BLANK_V_SHIFT 28 -#define SEQ_INST_BLANK_V_NORMAL (0 << 28) -#define SEQ_INST_BLANK_V_INACTIVE (1 << 28) -#define SEQ_INST_BLANK_H_SHIFT 27 -#define SEQ_INST_BLANK_H_NORMAL (0 << 27) -#define SEQ_INST_BLANK_H_INACTIVE (1 << 27) -#define SEQ_INST_BLANK_DE_SHIFT 26 -#define SEQ_INST_BLANK_DE_NORMAL (0 << 26) -#define SEQ_INST_BLANK_DE_INACTIVE (1 << 26) -#define SEQ_INST_BLACK_DATA_SHIFT 25 -#define SEQ_INST_BLACK_DATA_NORMAL (0 << 25) -#define SEQ_INST_BLACK_DATA_BLACK (1 << 25) -#define SEQ_INST_TRISTATE_IOS_SHIFT 24 -#define SEQ_INST_TRISTATE_IOS_ENABLE_PINS (0 << 24) -#define SEQ_INST_TRISTATE_IOS_TRISTATE (1 << 24) -#define SEQ_INST_DRIVE_PWM_OUT_LO_SHIFT 23 -#define SEQ_INST_DRIVE_PWM_OUT_LO_FALSE (0 << 23) -#define SEQ_INST_DRIVE_PWM_OUT_LO_TRUE (1 << 23) -#define SEQ_INST_PIN_B_SHIFT 22 -#define SEQ_INST_PIN_B_LOW (0 << 22) -#define SEQ_INST_PIN_B_HIGH (1 << 22) -#define SEQ_INST_PIN_A_SHIFT 21 -#define SEQ_INST_PIN_A_LOW (0 << 21) -#define SEQ_INST_PIN_A_HIGH (1 << 21) -#define SEQ_INST_SEQUENCE_SHIFT 19 -#define SEQ_INST_SEQUENCE_UP (0 << 19) -#define SEQ_INST_SEQUENCE_DOWN (1 << 19) -#define SEQ_INST_LANE_SEQ_SHIFT 18 -#define SEQ_INST_LANE_SEQ_STOP (0 << 18) -#define SEQ_INST_LANE_SEQ_RUN (1 << 18) -#define SEQ_INST_PDPORT_SHIFT 17 -#define SEQ_INST_PDPORT_NO (0 << 17) -#define SEQ_INST_PDPORT_YES (1 << 17) -#define SEQ_INST_PDPLL_SHIFT 16 -#define SEQ_INST_PDPLL_NO (0 << 16) -#define SEQ_INST_PDPLL_YES (1 << 16) -#define SEQ_INST_HALT_SHIFT 15 -#define SEQ_INST_HALT_FALSE (0 << 15) -#define SEQ_INST_HALT_TRUE (1 << 15) -#define SEQ_INST_WAIT_UNITS_SHIFT 12 -#define SEQ_INST_WAIT_UNITS_DEFAULT_MASK (3 << 12) -#define SEQ_INST_WAIT_UNITS_US (0 << 12) -#define SEQ_INST_WAIT_UNITS_MS (1 << 12) -#define SEQ_INST_WAIT_UNITS_VSYNC (2 << 12) -#define SEQ_INST_WAIT_TIME_SHIFT 0 -#define SEQ_INST_WAIT_TIME_DEFAULT_MASK 0x3ff -#define PWM_DIV 0x32 -#define PWM_DIV_DIVIDE_DEFAULT_MASK 0xffffff -#define PWM_CTL 0x33 -#define PWM_CTL_SETTING_NEW_SHIFT 31 -#define PWM_CTL_SETTING_NEW_DONE (0 << 31) -#define PWM_CTL_SETTING_NEW_PENDING (1 << 31) -#define PWM_CTL_SETTING_NEW_TRIGGER (1 << 31) -#define PWM_CTL_CLKSEL_SHIFT 30 -#define PWM_CTL_CLKSEL_PCLK (0 << 30) -#define PWM_CTL_CLKSEL_XTAL (1 << 30) -#define PWM_CTL_DUTY_CYCLE_SHIFT 0 -#define PWM_CTL_DUTY_CYCLE_MASK 0xffffff -#define MSCHECK 0x49 -#define MSCHECK_CTL_SHIFT 31 -#define MSCHECK_CTL_CLEAR (0 << 31) -#define MSCHECK_CTL_RUN (1 << 31) -#define XBAR_CTRL 0x4a -#define DP_LINKCTL(i) (0x4c + (i)) -#define DP_LINKCTL_FORCE_IDLEPTTRN_SHIFT 31 -#define DP_LINKCTL_FORCE_IDLEPTTRN_NO (0 << 31) -#define DP_LINKCTL_FORCE_IDLEPTTRN_YES (1 << 31) -#define DP_LINKCTL_COMPLIANCEPTTRN_SHIFT 28 -#define DP_LINKCTL_COMPLIANCEPTTRN_NOPATTERN (0 << 28) -#define DP_LINKCTL_COMPLIANCEPTTRN_COLORSQARE (1 << 28) -#define DP_LINKCTL_LANECOUNT_SHIFT 16 -#define DP_LINKCTL_LANECOUNT_MASK (0x1f << 16) -#define DP_LINKCTL_LANECOUNT_ZERO (0 << 16) -#define DP_LINKCTL_LANECOUNT_ONE (1 << 16) -#define DP_LINKCTL_LANECOUNT_TWO (3 << 16) -#define DP_LINKCTL_LANECOUNT_FOUR (15 << 16) -#define DP_LINKCTL_ENHANCEDFRAME_SHIFT 14 -#define DP_LINKCTL_ENHANCEDFRAME_DISABLE (0 << 14) -#define DP_LINKCTL_ENHANCEDFRAME_ENABLE (1 << 14) -#define DP_LINKCTL_SYNCMODE_SHIFT 10 -#define DP_LINKCTL_SYNCMODE_DISABLE (0 << 10) -#define DP_LINKCTL_SYNCMODE_ENABLE (1 << 10) -#define DP_LINKCTL_TUSIZE_SHIFT 2 -#define DP_LINKCTL_TUSIZE_MASK (0x7f << 2) -#define DP_LINKCTL_ENABLE_SHIFT 0 -#define DP_LINKCTL_ENABLE_NO 0 -#define DP_LINKCTL_ENABLE_YES 1 -#define DC(i) (0x4e + (i)) -#define DC_LANE3_DP_LANE3_SHIFT 24 -#define DC_LANE3_DP_LANE3_MASK (0xff << 24) -#define DC_LANE3_DP_LANE3_P0_LEVEL0 (17 << 24) -#define DC_LANE3_DP_LANE3_P1_LEVEL0 (21 << 24) -#define DC_LANE3_DP_LANE3_P2_LEVEL0 (26 << 24) -#define DC_LANE3_DP_LANE3_P3_LEVEL0 (34 << 24) -#define DC_LANE3_DP_LANE3_P0_LEVEL1 (26 << 24) -#define DC_LANE3_DP_LANE3_P1_LEVEL1 (32 << 24) -#define DC_LANE3_DP_LANE3_P2_LEVEL1 (39 << 24) -#define DC_LANE3_DP_LANE3_P0_LEVEL2 (34 << 24) -#define DC_LANE3_DP_LANE3_P1_LEVEL2 (43 << 24) -#define DC_LANE3_DP_LANE3_P0_LEVEL3 (51 << 24) -#define DC_LANE2_DP_LANE0_SHIFT 16 -#define DC_LANE2_DP_LANE0_MASK (0xff << 16) -#define DC_LANE2_DP_LANE0_P0_LEVEL0 (17 << 16) -#define DC_LANE2_DP_LANE0_P1_LEVEL0 (21 << 16) -#define DC_LANE2_DP_LANE0_P2_LEVEL0 (26 << 16) -#define DC_LANE2_DP_LANE0_P3_LEVEL0 (34 << 16) -#define DC_LANE2_DP_LANE0_P0_LEVEL1 (26 << 16) -#define DC_LANE2_DP_LANE0_P1_LEVEL1 (32 << 16) -#define DC_LANE2_DP_LANE0_P2_LEVEL1 (39 << 16) -#define DC_LANE2_DP_LANE0_P0_LEVEL2 (34 << 16) -#define DC_LANE2_DP_LANE0_P1_LEVEL2 (43 << 16) -#define DC_LANE2_DP_LANE0_P0_LEVEL3 (51 << 16) -#define DC_LANE1_DP_LANE1_SHIFT 8 -#define DC_LANE1_DP_LANE1_MASK (0xff << 8) -#define DC_LANE1_DP_LANE1_P0_LEVEL0 (17 << 8) -#define DC_LANE1_DP_LANE1_P1_LEVEL0 (21 << 8) -#define DC_LANE1_DP_LANE1_P2_LEVEL0 (26 << 8) -#define DC_LANE1_DP_LANE1_P3_LEVEL0 (34 << 8) -#define DC_LANE1_DP_LANE1_P0_LEVEL1 (26 << 8) -#define DC_LANE1_DP_LANE1_P1_LEVEL1 (32 << 8) -#define DC_LANE1_DP_LANE1_P2_LEVEL1 (39 << 8) -#define DC_LANE1_DP_LANE1_P0_LEVEL2 (34 << 8) -#define DC_LANE1_DP_LANE1_P1_LEVEL2 (43 << 8) -#define DC_LANE1_DP_LANE1_P0_LEVEL3 (51 << 8) -#define DC_LANE0_DP_LANE2_SHIFT 0 -#define DC_LANE0_DP_LANE2_MASK 0xff -#define DC_LANE0_DP_LANE2_P0_LEVEL0 17 -#define DC_LANE0_DP_LANE2_P1_LEVEL0 21 -#define DC_LANE0_DP_LANE2_P2_LEVEL0 26 -#define DC_LANE0_DP_LANE2_P3_LEVEL0 34 -#define DC_LANE0_DP_LANE2_P0_LEVEL1 26 -#define DC_LANE0_DP_LANE2_P1_LEVEL1 32 -#define DC_LANE0_DP_LANE2_P2_LEVEL1 39 -#define DC_LANE0_DP_LANE2_P0_LEVEL2 34 -#define DC_LANE0_DP_LANE2_P1_LEVEL2 43 -#define DC_LANE0_DP_LANE2_P0_LEVEL3 51 -#define LANE_DRIVE_CURRENT(i) (0x4e + (i)) -#define PR(i) (0x52 + (i)) -#define PR_LANE3_DP_LANE3_SHIFT 24 -#define PR_LANE3_DP_LANE3_MASK (0xff << 24) -#define PR_LANE3_DP_LANE3_D0_LEVEL0 (0 << 24) -#define PR_LANE3_DP_LANE3_D1_LEVEL0 (0 << 24) -#define PR_LANE3_DP_LANE3_D2_LEVEL0 (0 << 24) -#define PR_LANE3_DP_LANE3_D3_LEVEL0 (0 << 24) -#define PR_LANE3_DP_LANE3_D0_LEVEL1 (4 << 24) -#define PR_LANE3_DP_LANE3_D1_LEVEL1 (6 << 24) -#define PR_LANE3_DP_LANE3_D2_LEVEL1 (17 << 24) -#define PR_LANE3_DP_LANE3_D0_LEVEL2 (8 << 24) -#define PR_LANE3_DP_LANE3_D1_LEVEL2 (13 << 24) -#define PR_LANE3_DP_LANE3_D0_LEVEL3 (17 << 24) -#define PR_LANE2_DP_LANE0_SHIFT 16 -#define PR_LANE2_DP_LANE0_MASK (0xff << 16) -#define PR_LANE2_DP_LANE0_D0_LEVEL0 (0 << 16) -#define PR_LANE2_DP_LANE0_D1_LEVEL0 (0 << 16) -#define PR_LANE2_DP_LANE0_D2_LEVEL0 (0 << 16) -#define PR_LANE2_DP_LANE0_D3_LEVEL0 (0 << 16) -#define PR_LANE2_DP_LANE0_D0_LEVEL1 (4 << 16) -#define PR_LANE2_DP_LANE0_D1_LEVEL1 (6 << 16) -#define PR_LANE2_DP_LANE0_D2_LEVEL1 (17 << 16) -#define PR_LANE2_DP_LANE0_D0_LEVEL2 (8 << 16) -#define PR_LANE2_DP_LANE0_D1_LEVEL2 (13 << 16) -#define PR_LANE2_DP_LANE0_D0_LEVEL3 (17 << 16) -#define PR_LANE1_DP_LANE1_SHIFT 8 -#define PR_LANE1_DP_LANE1_MASK (0xff >> 8) -#define PR_LANE1_DP_LANE1_D0_LEVEL0 (0 >> 8) -#define PR_LANE1_DP_LANE1_D1_LEVEL0 (0 >> 8) -#define PR_LANE1_DP_LANE1_D2_LEVEL0 (0 >> 8) -#define PR_LANE1_DP_LANE1_D3_LEVEL0 (0 >> 8) -#define PR_LANE1_DP_LANE1_D0_LEVEL1 (4 >> 8) -#define PR_LANE1_DP_LANE1_D1_LEVEL1 (6 >> 8) -#define PR_LANE1_DP_LANE1_D2_LEVEL1 (17 >> 8) -#define PR_LANE1_DP_LANE1_D0_LEVEL2 (8 >> 8) -#define PR_LANE1_DP_LANE1_D1_LEVEL2 (13 >> 8) -#define PR_LANE1_DP_LANE1_D0_LEVEL3 (17 >> 8) -#define PR_LANE0_DP_LANE2_SHIFT 0 -#define PR_LANE0_DP_LANE2_MASK 0xff -#define PR_LANE0_DP_LANE2_D0_LEVEL0 0 -#define PR_LANE0_DP_LANE2_D1_LEVEL0 0 -#define PR_LANE0_DP_LANE2_D2_LEVEL0 0 -#define PR_LANE0_DP_LANE2_D3_LEVEL0 0 -#define PR_LANE0_DP_LANE2_D0_LEVEL1 4 -#define PR_LANE0_DP_LANE2_D1_LEVEL1 6 -#define PR_LANE0_DP_LANE2_D2_LEVEL1 17 -#define PR_LANE0_DP_LANE2_D0_LEVEL2 8 -#define PR_LANE0_DP_LANE2_D1_LEVEL2 13 -#define PR_LANE0_DP_LANE2_D0_LEVEL3 17 -#define LANE4_PREEMPHASIS(i) (0x54 + (i)) -#define POSTCURSOR(i) (0x56 + (i)) -#define DP_CONFIG(i) (0x58 + (i)) -#define DP_CONFIG_RD_RESET_VAL_SHIFT 31 -#define DP_CONFIG_RD_RESET_VAL_POSITIVE (0 << 31) -#define DP_CONFIG_RD_RESET_VAL_NEGATIVE (1 << 31) -#define DP_CONFIG_IDLE_BEFORE_ATTACH_SHIFT 28 -#define DP_CONFIG_IDLE_BEFORE_ATTACH_DISABLE (0 << 28) -#define DP_CONFIG_IDLE_BEFORE_ATTACH_ENABLE (1 << 28) -#define DP_CONFIG_ACTIVESYM_CNTL_SHIFT 26 -#define DP_CONFIG_ACTIVESYM_CNTL_DISABLE (0 << 26) -#define DP_CONFIG_ACTIVESYM_CNTL_ENABLE (1 << 26) -#define DP_CONFIG_ACTIVESYM_POLARITY_SHIFT 24 -#define DP_CONFIG_ACTIVESYM_POLARITY_NEGATIVE (0 << 24) -#define DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE (1 << 24) -#define DP_CONFIG_ACTIVESYM_FRAC_SHIFT 16 -#define DP_CONFIG_ACTIVESYM_FRAC_MASK (0xf << 16) -#define DP_CONFIG_ACTIVESYM_COUNT_SHIFT 8 -#define DP_CONFIG_ACTIVESYM_COUNT_MASK (0x7f << 8) -#define DP_CONFIG_WATERMARK_SHIFT 0 -#define DP_CONFIG_WATERMARK_MASK 0x3f -#define DP_MN(i) (0x5a + i) -#define DP_MN_M_MOD_SHIFT 30 -#define DP_MN_M_MOD_DEFAULT_MASK (3 << 30) -#define DP_MN_M_MOD_NONE (0 << 30) -#define DP_MN_M_MOD_INC (1 << 30) -#define DP_MN_M_MOD_DEC (2 << 30) -#define DP_MN_M_DELTA_SHIFT 24 -#define DP_MN_M_DELTA_DEFAULT_MASK (0xf << 24) -#define DP_MN_N_VAL_SHIFT 0 -#define DP_MN_N_VAL_DEFAULT_MASK 0xffffff -#define DP_PADCTL(i) (0x5c + (i)) -#define DP_PADCTL_SPARE_SHIFT 25 -#define DP_PADCTL_SPARE_DEFAULT_MASK (0x7f << 25) -#define DP_PADCTL_VCO_2X_SHIFT 24 -#define DP_PADCTL_VCO_2X_DISABLE (0 << 24) -#define DP_PADCTL_VCO_2X_ENABLE (1 << 24) -#define DP_PADCTL_PAD_CAL_PD_SHIFT 23 -#define DP_PADCTL_PAD_CAL_PD_POWERUP (0 << 23) -#define DP_PADCTL_PAD_CAL_PD_POWERDOWN (1 << 23) -#define DP_PADCTL_TX_PU_SHIFT 22 -#define DP_PADCTL_TX_PU_DISABLE (0 << 22) -#define DP_PADCTL_TX_PU_ENABLE (1 << 22) -#define DP_PADCTL_TX_PU_MASK (1 << 22) -#define DP_PADCTL_REG_CTRL_SHIFT 20 -#define DP_PADCTL_REG_CTRL_DEFAULT_MASK (3 << 20) -#define DP_PADCTL_VCMMODE_SHIFT 16 -#define DP_PADCTL_VCMMODE_DEFAULT_MASK (0xf << 16) -#define DP_PADCTL_VCMMODE_TRISTATE (0 << 16) -#define DP_PADCTL_VCMMODE_TEST_MUX (1 << 16) -#define DP_PADCTL_VCMMODE_WEAK_PULLDOWN (2 << 16) -#define DP_PADCTL_VCMMODE_STRONG_PULLDOWN (4 << 16) -#define DP_PADCTL_TX_PU_VALUE_SHIFT 8 -#define DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK (0xff << 8) -#define DP_PADCTL_COMODE_TXD_3_DP_TXD_3_SHIFT 7 -#define DP_PADCTL_COMODE_TXD_3_DP_TXD_3_DISABLE (0 << 7) -#define DP_PADCTL_COMODE_TXD_3_DP_TXD_3_ENABLE (1 << 7) -#define DP_PADCTL_COMODE_TXD_2_DP_TXD_0_SHIFT 6 -#define DP_PADCTL_COMODE_TXD_2_DP_TXD_0_DISABLE (0 << 6) -#define DP_PADCTL_COMODE_TXD_2_DP_TXD_0_ENABLE (1 << 6) -#define DP_PADCTL_COMODE_TXD_1_DP_TXD_1_SHIFT 5 -#define DP_PADCTL_COMODE_TXD_1_DP_TXD_1_DISABLE (0 << 5) -#define DP_PADCTL_COMODE_TXD_1_DP_TXD_1_ENABLE (1 << 5) -#define DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT 4 -#define DP_PADCTL_COMODE_TXD_0_DP_TXD_2_DISABLE (0 << 4) -#define DP_PADCTL_COMODE_TXD_0_DP_TXD_2_ENABLE (1 << 4) -#define DP_PADCTL_PD_TXD_3_SHIFT 3 -#define DP_PADCTL_PD_TXD_3_YES (0 << 3) -#define DP_PADCTL_PD_TXD_3_NO (1 << 3) -#define DP_PADCTL_PD_TXD_0_SHIFT 2 -#define DP_PADCTL_PD_TXD_0_YES (0 << 2) -#define DP_PADCTL_PD_TXD_0_NO (1 << 2) -#define DP_PADCTL_PD_TXD_1_SHIFT 1 -#define DP_PADCTL_PD_TXD_1_YES (0 << 1) -#define DP_PADCTL_PD_TXD_1_NO (1 << 1) -#define DP_PADCTL_PD_TXD_2_SHIFT 0 -#define DP_PADCTL_PD_TXD_2_YES 0 -#define DP_PADCTL_PD_TXD_2_NO 1 -#define DP_DEBUG(i) (0x5e + i) -#define DP_SPARE(i) (0x60 + (i)) -#define DP_SPARE_REG_SHIFT 3 -#define DP_SPARE_REG_DEFAULT_MASK (0x1fffffff << 3) -#define DP_SPARE_SOR_CLK_SEL_SHIFT 2 -#define DP_SPARE_SOR_CLK_SEL_DEFAULT_MASK (1 << 2) -#define DP_SPARE_SOR_CLK_SEL_SAFE_SORCLK (0 << 2) -#define DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK (1 << 2) -#define DP_SPARE_PANEL_SHIFT 1 -#define DP_SPARE_PANEL_EXTERNAL (0 << 1) -#define DP_SPARE_PANEL_INTERNAL (1 << 1) -#define DP_SPARE_SEQ_ENABLE_SHIFT 0 -#define DP_SPARE_SEQ_ENABLE_NO 0 -#define DP_SPARE_SEQ_ENABLE_YES 1 -#define DP_AUDIO_CTRL 0x62 -#define DP_AUDIO_HBLANK_SYMBOLS 0x63 -#define DP_AUDIO_HBLANK_SYMBOLS_MASK 0x1ffff -#define DP_AUDIO_HBLANK_SYMBOLS_VALUE_SHIFT 0 -#define DP_AUDIO_VBLANK_SYMBOLS 0x64 -#define DP_AUDIO_VBLANK_SYMBOLS_MASK 0x1ffff -#define DP_AUDIO_VBLANK_SYMBOLS_SHIFT 0 -#define DP_GENERIC_INFOFRAME_HEADER 0x65 -#define DP_GENERIC_INFOFRAME_SUBPACK(i) (0x66 + (i)) -#define DP_TPG 0x6d -#define DP_TPG_LANE3_CHANNELCODING_SHIFT 30 -#define DP_TPG_LANE3_CHANNELCODING_DISABLE (0 << 30) -#define DP_TPG_LANE3_CHANNELCODING_ENABLE (1 << 30) -#define DP_TPG_LANE3_SCRAMBLEREN_SHIFT 28 -#define DP_TPG_LANE3_SCRAMBLEREN_ENABLE_GALIOS (1 << 28) -#define DP_TPG_LANE3_SCRAMBLEREN_ENABLE_FIBONACCI (2 << 28) -#define DP_TPG_LANE3_PATTERN_SHIFT 24 -#define DP_TPG_LANE3_PATTERN_DEFAULT_MASK (0xf << 24) -#define DP_TPG_LANE3_PATTERN_NOPATTERN (0 << 24) -#define DP_TPG_LANE3_PATTERN_TRAINING1 (1 << 24) -#define DP_TPG_LANE3_PATTERN_TRAINING2 (2 << 24) -#define DP_TPG_LANE3_PATTERN_TRAINING3 (3 << 24) -#define DP_TPG_LANE3_PATTERN_D102 (4 << 24) -#define DP_TPG_LANE3_PATTERN_SBLERRRATE (5 << 24) -#define DP_TPG_LANE3_PATTERN_PRBS7 (6 << 24) -#define DP_TPG_LANE3_PATTERN_CSTM (7 << 24) -#define DP_TPG_LANE3_PATTERN_HBR2_COMPLIANCE (8 << 24) -#define DP_TPG_LANE2_CHANNELCODING_SHIFT 22 -#define DP_TPG_LANE2_CHANNELCODING_DISABLE (0 << 22) -#define DP_TPG_LANE2_CHANNELCODING_ENABLE (1 << 22) -#define DP_TPG_LANE2_SCRAMBLEREN_SHIFT 20 -#define DP_TPG_LANE2_SCRAMBLEREN_DEFAULT_MASK (3 << 20) -#define DP_TPG_LANE2_SCRAMBLEREN_DISABLE (0 << 20) -#define DP_TPG_LANE2_SCRAMBLEREN_ENABLE_GALIOS (1 << 20) -#define DP_TPG_LANE2_SCRAMBLEREN_ENABLE_FIBONACCI (2 << 20) -#define DP_TPG_LANE2_PATTERN_SHIFT 16 -#define DP_TPG_LANE2_PATTERN_DEFAULT_MASK (0xf << 16) -#define DP_TPG_LANE2_PATTERN_NOPATTERN (0 << 16) -#define DP_TPG_LANE2_PATTERN_TRAINING1 (1 << 16) -#define DP_TPG_LANE2_PATTERN_TRAINING2 (2 << 16) -#define DP_TPG_LANE2_PATTERN_TRAINING3 (3 << 16) -#define DP_TPG_LANE2_PATTERN_D102 (4 << 16) -#define DP_TPG_LANE2_PATTERN_SBLERRRATE (5 << 16) -#define DP_TPG_LANE2_PATTERN_PRBS7 (6 << 16) -#define DP_TPG_LANE2_PATTERN_CSTM (7 << 16) -#define DP_TPG_LANE2_PATTERN_HBR2_COMPLIANCE (8 << 16) -#define DP_TPG_LANE1_CHANNELCODING_SHIFT 14 -#define DP_TPG_LANE1_CHANNELCODING_DISABLE (0 << 14) -#define DP_TPG_LANE1_CHANNELCODING_ENABLE (1 << 14) -#define DP_TPG_LANE1_SCRAMBLEREN_SHIFT 12 -#define DP_TPG_LANE1_SCRAMBLEREN_DEFAULT_MASK (3 << 12) -#define DP_TPG_LANE1_SCRAMBLEREN_DISABLE (0 << 12) -#define DP_TPG_LANE1_SCRAMBLEREN_ENABLE_GALIOS (1 << 12) -#define DP_TPG_LANE1_SCRAMBLEREN_ENABLE_FIBONACCI (2 << 12) -#define DP_TPG_LANE1_PATTERN_SHIFT 8 -#define DP_TPG_LANE1_PATTERN_DEFAULT_MASK (0xf << 8) -#define DP_TPG_LANE1_PATTERN_NOPATTERN (0 << 8) -#define DP_TPG_LANE1_PATTERN_TRAINING1 (1 << 8) -#define DP_TPG_LANE1_PATTERN_TRAINING2 (2 << 8) -#define DP_TPG_LANE1_PATTERN_TRAINING3 (3 << 8) -#define DP_TPG_LANE1_PATTERN_D102 (4 << 8) -#define DP_TPG_LANE1_PATTERN_SBLERRRATE (5 << 8) -#define DP_TPG_LANE1_PATTERN_PRBS7 (6 << 8) -#define DP_TPG_LANE1_PATTERN_CSTM (7 << 8) -#define DP_TPG_LANE1_PATTERN_HBR2_COMPLIANCE (8 << 8) -#define DP_TPG_LANE0_CHANNELCODING_SHIFT 6 -#define DP_TPG_LANE0_CHANNELCODING_DISABLE (0 << 6) -#define DP_TPG_LANE0_CHANNELCODING_ENABLE (1 << 6) -#define DP_TPG_LANE0_SCRAMBLEREN_SHIFT 4 -#define DP_TPG_LANE0_SCRAMBLEREN_DEFAULT_MASK (3 << 4) -#define DP_TPG_LANE0_SCRAMBLEREN_DISABLE (0 << 4) -#define DP_TPG_LANE0_SCRAMBLEREN_ENABLE_GALIOS (1 << 4) -#define DP_TPG_LANE0_SCRAMBLEREN_ENABLE_FIBONACCI (2 << 4) -#define DP_TPG_LANE0_PATTERN_SHIFT 0 -#define DP_TPG_LANE0_PATTERN_DEFAULT_MASK 0xf -#define DP_TPG_LANE0_PATTERN_NOPATTERN 0 -#define DP_TPG_LANE0_PATTERN_TRAINING1 1 -#define DP_TPG_LANE0_PATTERN_TRAINING2 2 -#define DP_TPG_LANE0_PATTERN_TRAINING3 3 -#define DP_TPG_LANE0_PATTERN_D102 4 -#define DP_TPG_LANE0_PATTERN_SBLERRRATE 5 -#define DP_TPG_LANE0_PATTERN_PRBS7 6 -#define DP_TPG_LANE0_PATTERN_CSTM 7 -#define DP_TPG_LANE0_PATTERN_HBR2_COMPLIANCE 8 - -enum { - training_pattern_disabled = 0, - training_pattern_1 = 1, - training_pattern_2 = 2, - training_pattern_3 = 3, - training_pattern_none = 0xff -}; - -enum tegra_dc_sor_protocol { - SOR_DP, - SOR_LVDS, -}; - -#define SOR_LINK_SPEED_G1_62 6 -#define SOR_LINK_SPEED_G2_7 10 -#define SOR_LINK_SPEED_G5_4 20 -#define SOR_LINK_SPEED_LVDS 7 - -struct tegra_dp_link_config { - int is_valid; - - /* Supported configuration */ - u8 max_link_bw; - u8 max_lane_count; - int downspread; - int support_enhanced_framing; - u32 bits_per_pixel; - int alt_scramber_reset_cap; /* true for eDP */ - int only_enhanced_framing; /* enhanced_frame_en ignored */ - int frame_in_ms; - - /* Actual configuration */ - u8 link_bw; - u8 lane_count; - int enhanced_framing; - int scramble_ena; - - u32 activepolarity; - u32 active_count; - u32 tu_size; - u32 active_frac; - u32 watermark; - - s32 hblank_sym; - s32 vblank_sym; - - /* Training data */ - u32 drive_current; - u32 preemphasis; - u32 postcursor; - u8 aux_rd_interval; - u8 tps3_supported; -}; - -#define TEGRA_SOR_TIMEOUT_MS 1000 -#define TEGRA_SOR_ATTACH_TIMEOUT_MS 1000 - -int tegra_dc_sor_enable_dp(struct udevice *sor, - const struct tegra_dp_link_config *link_cfg); -int tegra_dc_sor_set_power_state(struct udevice *sor, int pu_pd); -void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena, - u8 training_pattern, const struct tegra_dp_link_config *link_cfg); -void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw); -void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count); -void tegra_dc_sor_set_panel_power(struct udevice *sor, - int power_up); -void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int); -void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw, - u8 *lane_count); -void tegra_dc_sor_set_lane_parm(struct udevice *dev, - const struct tegra_dp_link_config *link_cfg); -void tegra_dc_sor_power_down_unused_lanes(struct udevice *sor, - const struct tegra_dp_link_config *link_cfg); -int tegra_dc_sor_set_voltage_swing(struct udevice *sor, - const struct tegra_dp_link_config *link_cfg); -int tegra_sor_precharge_lanes(struct udevice *dev, - const struct tegra_dp_link_config *cfg); -void tegra_dp_disable_tx_pu(struct udevice *sor); -void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg, - u32 vs_reg, u32 pc_reg, u8 pc_supported); - -int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *sor, - const struct tegra_dp_link_config *link_cfg, - const struct display_timing *timing); -int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *sor); - -void tegra_dc_sor_disable_win_short_raster(struct dc_ctlr *disp_ctrl, - int *dc_reg_ctx); -int tegra_dc_sor_general_act(struct dc_ctlr *disp_ctrl); -void tegra_dc_sor_restore_win_and_raster(struct dc_ctlr *disp_ctrl, - int *dc_reg_ctx); - -int tegra_dc_sor_init(struct udevice **sorp); -#endif -- cgit v1.3.1