summaryrefslogtreecommitdiff
path: root/src/soc/nvidia/tegra124
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/nvidia/tegra124')
-rw-r--r--src/soc/nvidia/tegra124/Makefile.inc2
-rw-r--r--src/soc/nvidia/tegra124/chip.h48
-rw-r--r--src/soc/nvidia/tegra124/clock.c24
-rw-r--r--src/soc/nvidia/tegra124/display.c356
-rw-r--r--src/soc/nvidia/tegra124/displayhack.c738
-rw-r--r--src/soc/nvidia/tegra124/dp.c555
-rw-r--r--src/soc/nvidia/tegra124/include/soc/display.h175
-rw-r--r--src/soc/nvidia/tegra124/soc.c2
-rw-r--r--src/soc/nvidia/tegra124/sor.c702
-rw-r--r--src/soc/nvidia/tegra124/sor.h55
10 files changed, 1227 insertions, 1430 deletions
diff --git a/src/soc/nvidia/tegra124/Makefile.inc b/src/soc/nvidia/tegra124/Makefile.inc
index 07184f88b0..8d5fb26eb2 100644
--- a/src/soc/nvidia/tegra124/Makefile.inc
+++ b/src/soc/nvidia/tegra124/Makefile.inc
@@ -38,7 +38,7 @@ romstage-$(CONFIG_CONSOLE_SERIAL) += uart.c
ramstage-y += cbfs.c
ramstage-y += cbmem.c
ramstage-y += clock.c
-ramstage-y += display.c displayhack.c
+ramstage-y += display.c
ramstage-y += dma.c
ramstage-y += i2c.c
ramstage-y += maincpu.S
diff --git a/src/soc/nvidia/tegra124/chip.h b/src/soc/nvidia/tegra124/chip.h
index b05bcc7cba..87d043a8ca 100644
--- a/src/soc/nvidia/tegra124/chip.h
+++ b/src/soc/nvidia/tegra124/chip.h
@@ -23,14 +23,19 @@
#include <soc/addressmap.h>
#include "gpio.h"
+#define EFAULT 1
+#define EINVAL 2
+
/* this is a misuse of the device tree. We're going to let it go for now but
* we should at minimum have a struct for the display controller, since
* the chip supports two.
*/
struct soc_nvidia_tegra124_config {
- int xres;
- int yres;
- int framebuffer_bits_per_pixel;
+ u32 xres;
+ u32 yres;
+ u32 framebuffer_bits_per_pixel;
+ u32 color_depth;
+ u32 panel_bits_per_pixel;
int cache_policy;
/* there are two. It's not unimaginable that we might someday
* have two of these structs in a single mainboard.
@@ -60,32 +65,41 @@ struct soc_nvidia_tegra124_config {
* This is stated to be four timings in the
* u-boot docs. In any event, in coreboot, we generally
* only delay long enough to let the panel wake up and then
- * do the control operations -- meaming, for *coreboot*
+ * do the control operations -- meaning, for *coreboot*
* we probably only need the vdd_delay, but payloads may
* need the other info.
*/
/* Delay before from power on asserting vdd */
- int vdd_delay;
- /* delay between panel_vdd-rise and data-rise*/
- int vdd_data_delay;
- /* delay between data-rise and backlight_vdd-rise */
- int data_backlight_delay;
- /* delay between backlight_vdd and pwm-rise */
- int backlight_pwm_delay;
- /* delay between pwm-rise and backlight_en-rise */
- int pwm_backlight_en_delay;
- /* display timing.
- * we have not found a dts in which these are set */
- int href_to_sync; /* u-boot code says 'set to 1' */
+ int vdd_delay_ms;
+
+ /* Delay before HPD high */
+ int vdd_to_hpd_delay_ms;
+
+ int hpd_unplug_min_us;
+ int hpd_plug_min_us;
+ int hpd_irq_min_us;
+
+ int href_to_sync;
int hsync_width;
int hback_porch;
int hfront_porch;
- int vref_to_sync; /* u-boot code says 'set to 1' */
+ int vref_to_sync;
int vsync_width;
int vback_porch;
int vfront_porch;
int pixel_clock;
+ int pll_div;;
+
+ /* The minimum link configuraton settings */
+ u32 lane_count;
+ u32 enhanced_framing;
+ u32 link_bw;
+ u32 drive_current;
+ u32 preemphasis;
+ u32 postcursor;
+
+ void *dc_data;
};
#endif /* __SOC_NVIDIA_TEGRA124_CHIP_H__ */
diff --git a/src/soc/nvidia/tegra124/clock.c b/src/soc/nvidia/tegra124/clock.c
index c292355f33..cef4262f99 100644
--- a/src/soc/nvidia/tegra124/clock.c
+++ b/src/soc/nvidia/tegra124/clock.c
@@ -88,10 +88,9 @@ struct {
int khz;
struct pllcx_dividers pllx; /* target: CONFIG_PLLX_KHZ */
struct pllcx_dividers pllc; /* target: 600 MHz */
- struct pllpad_dividers plld; /* target: 925 MHz */
+ struct pllpad_dividers plld; /* target: 306 MHz */
struct pllu_dividers pllu; /* target; 960 MHz */
struct pllcx_dividers plldp; /* target; 270 MHz */
- struct pllcx_dividers plld2; /* target; 570 MHz */
/* Based on T124 TRM (to be updatd), PLLP is set to 408MHz in HW.
* Unless configuring PLLP to a frequency other than 408MHz,
* software configuration on PLLP is unneeded. */
@@ -100,46 +99,41 @@ struct {
.khz = 12000,
.pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0},
.pllc = {.n = 50, .m = 1, .p = 0},
- .plld = {.n = 283, .m = 12, .p = 0, .cpcon = 8}, /* 283 MHz */
+ .plld = {.n = 306, .m = 12, .p = 0, .cpcon = 8},
.pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2},
.plldp = {.n = 90, .m = 1, .p = 3},
- .plld2 = {.n = 95, .m = 1, .p = 1},
},
[OSC_FREQ_OSC13]{
.khz = 13000,
.pllx = {.n = TEGRA_PLLX_KHZ / 13000, .m = 1, .p = 0},
.pllc = {.n = 231, .m = 5, .p = 0}, /* 600.6 MHz */
- .plld = {.n = 283, .m = 13, .p = 0, .cpcon = 8}, /* 283 MHz*/
+ .plld = {.n = 306, .m = 13, .p = 0, .cpcon = 8},
.pllu = {.n = 960, .m = 13, .p = 0, .cpcon = 12, .lfcon = 2},
.plldp = {.n = 83, .m = 1, .p = 3}, /* 269.75 MHz */
- .plld2 = {.n = 88, .m = 1, .p = 1}, /* 572 MHz */
},
[OSC_FREQ_OSC16P8]{
.khz = 16800,
.pllx = {.n = TEGRA_PLLX_KHZ / 16800, .m = 1, .p = 0},
.pllc = {.n = 250, .m = 7, .p = 0},
- .plld = {.n = 286, .m = 17, .p = 0, .cpcon = 8}, /* 282.6 MHz*/
+ .plld = {.n = 309, .m = 17, .p = 0, .cpcon = 8}, /* 305.4 MHz*/
.pllu = {.n = 400, .m = 7, .p = 0, .cpcon = 5, .lfcon = 2},
.plldp = {.n = 64, .m = 1, .p = 3}, /* 268.8 MHz */
- .plld2 = {.n = 68, .m = 1, .p = 1}, /* 571.2 MHz */
},
[OSC_FREQ_OSC19P2]{
.khz = 19200,
.pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0},
.pllc = {.n = 125, .m = 4, .p = 0},
- .plld = {.n = 251, .m = 17, .p = 0, .cpcon = 8}, /* 283.5 MHz */
+ .plld = {.n = 271, .m = 17, .p = 0, .cpcon = 8}, /* 306.1 MHz */
.pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2},
.plldp = {.n = 56, .m = 1, .p = 3}, /* 270.75 MHz */
- .plld2 = {.n = 59, .m = 1, .p = 1}, /* 566.4 MHz */
},
[OSC_FREQ_OSC26]{
.khz = 26000,
.pllx = {.n = TEGRA_PLLX_KHZ / 26000, .m = 1, .p = 0},
.pllc = {.n = 23, .m = 1, .p = 0}, /* 598 MHz */
- .plld = {.n = 283, .m = 26, .p = 0, .cpcon = 8}, /* 283 MHz */
+ .plld = {.n = 306, .m = 26, .p = 0, .cpcon = 8},
.pllu = {.n = 960, .m = 26, .p = 0, .cpcon = 12, .lfcon = 2},
.plldp = {.n = 83, .m = 2, .p = 3}, /* 266.50 MHz */
- .plld2 = {.n = 88, .m = 2, .p = 1}, /* 572 MHz */
},
[OSC_FREQ_OSC38P4]{
.khz = 38400,
@@ -149,10 +143,9 @@ struct {
*/
.pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0},
.pllc = {.n = 125, .m = 4, .p = 0},
- .plld = {.n = 125, .m = 17, .p = 0, .cpcon = 8}, /* 282.4 MHz */
+ .plld = {.n = 271, .m = 17, .p = 0, .cpcon = 8}, /* 306.1 MHz */
.pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2},
.plldp = {.n = 56, .m = 2, .p = 3}, /* 268 MHz */
- .plld2 = {.n = 59, .m = 2, .p = 1}, /* 566 MHz */
},
[OSC_FREQ_OSC48]{
.khz = 48000,
@@ -162,10 +155,9 @@ struct {
*/
.pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0},
.pllc = {.n = 50, .m = 1, .p = 0},
- .plld = {.n = 71, .m = 12, .p = 0, .cpcon = 8}, /* 284 MHz */
+ .plld = {.n = 306, .m = 12, .p = 0, .cpcon = 8},
.pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2},
.plldp = {.n = 90, .m = 4, .p = 3}, /* 264 MHz */
- .plld2 = {.n = 95, .m = 4, .p = 1},
},
};
diff --git a/src/soc/nvidia/tegra124/display.c b/src/soc/nvidia/tegra124/display.c
index 8c4e8232dd..4a0f4501a2 100644
--- a/src/soc/nvidia/tegra124/display.c
+++ b/src/soc/nvidia/tegra124/display.c
@@ -38,18 +38,26 @@
#include "chip.h"
#include <soc/display.h>
+struct tegra_dc dc_data;
+
int dump = 0;
-unsigned long READL(void * p);
-void WRITEL(unsigned long value, void * p);
unsigned long READL(void * p)
{
- unsigned long value = readl(p);
+ unsigned long value;
+
+ /*
+ * In case of hard hung on readl(p), we can set dump > 1 to print out
+ * the address accessed.
+ */
+ if (dump > 1)
+ printk(BIOS_SPEW, "readl %p\n", p);
+
+ value = readl(p);
if (dump)
printk(BIOS_SPEW, "readl %p %08lx\n", p, value);
return value;
}
-
void WRITEL(unsigned long value, void * p)
{
if (dump)
@@ -57,174 +65,133 @@ void WRITEL(unsigned long value, void * p)
writel(value, p);
}
-static const u32 rgb_enb_tab[PIN_REG_COUNT] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-static const u32 rgb_polarity_tab[PIN_REG_COUNT] = {
- 0x00000000,
- 0x01000000,
- 0x00000000,
- 0x00000000,
-};
-
-static const u32 rgb_data_tab[PIN_REG_COUNT] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-static const u32 rgb_sel_tab[PIN_OUTPUT_SEL_COUNT] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00210222,
- 0x00002200,
- 0x00020000,
-};
-
-static int update_display_mode(struct dc_disp_reg *disp,
- struct soc_nvidia_tegra124_config *config)
+/* return in 1000ths of a Hertz */
+static int tegra_dc_calc_refresh(const struct soc_nvidia_tegra124_config *config)
{
- u32 val;
- u32 rate;
- u32 div;
-
- WRITEL(0x0, &disp->disp_timing_opt);
+ int h_total, v_total, refresh;
+ int pclk = config->pixel_clock;
+
+ h_total = config->xres + config->hfront_porch + config->hback_porch +
+ config->hsync_width;
+ v_total = config->yres + config->vfront_porch + config->vback_porch +
+ config->vsync_width;
+ if (!pclk || !h_total || !v_total)
+ return 0;
+ refresh = pclk / h_total;
+ refresh *= 1000;
+ refresh /= v_total;
+ return refresh;
+}
- WRITEL(config->vref_to_sync << 16 | config->href_to_sync,
- &disp->ref_to_sync);
- WRITEL(config->vsync_width << 16 | config->hsync_width, &disp->sync_width);
- WRITEL(config->vback_porch << 16 | config->hback_porch, &disp->back_porch);
- WRITEL(config->vfront_porch << 16 | config->hfront_porch,
- &disp->front_porch);
+static void print_mode(const struct soc_nvidia_tegra124_config *config)
+{
+ if (config) {
+ int refresh = tegra_dc_calc_refresh(config);
+ printk(BIOS_ERR,
+ "MODE:%dx%d@%d.%03uHz pclk=%d\n",
+ config->xres, config->yres,
+ refresh / 1000, refresh % 1000,
+ config->pixel_clock);
+ }
+}
- WRITEL(config->xres | (config->yres << 16), &disp->disp_active);
+static int update_display_mode(struct display_controller *disp_ctrl,
+ struct soc_nvidia_tegra124_config *config)
+{
+ unsigned long div = config->pll_div;
- val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT;
- val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT;
- WRITEL(val, &disp->data_enable_opt);
+ print_mode(config);
- val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT;
- val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT;
- val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT;
- WRITEL(val, &disp->disp_interface_ctrl);
+ WRITEL(0x1, &disp_ctrl->disp.disp_timing_opt);
- /*
- * The pixel clock divider is in 7.1 format (where the bottom bit
- * represents 0.5). Here we calculate the divider needed to get from
- * the display clock (typically 600MHz) to the pixel clock. We round
- * up or down as requried.
- * We use pllp for now.
- */
- rate = 600 * 1000000;
- div = ((rate * 2 + config->pixel_clock / 2) / config->pixel_clock) - 2;
- printk(BIOS_SPEW, "Display clock %d, divider %d\n", rate, div);
+ WRITEL(config->vref_to_sync << 16 | config->href_to_sync,
+ &disp_ctrl->disp.ref_to_sync);
- WRITEL(0x00010001, &disp->shift_clk_opt);
+ WRITEL(config->vsync_width << 16 | config->hsync_width,
+ &disp_ctrl->disp.sync_width);
- val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT;
- val |= div << SHIFT_CLK_DIVIDER_SHIFT;
- WRITEL(val, &disp->disp_clk_ctrl);
+ WRITEL(((config->vback_porch - config->vref_to_sync) << 16) | config->hback_porch,
+ &disp_ctrl->disp.back_porch);
- return 0;
-}
+ WRITEL(((config->vfront_porch + config->vref_to_sync) << 16) | config->hfront_porch,
+ &disp_ctrl->disp.front_porch);
-static int setup_window(struct disp_ctl_win *win,
- struct soc_nvidia_tegra124_config *config)
-{
- int log2_bpp = log2(config->framebuffer_bits_per_pixel);
- win->x = 0;
- win->y = 0;
- win->w = config->xres;
- win->h = config->yres;
- win->out_x = 0;
- win->out_y = 0;
- win->out_w = config->xres;
- win->out_h = config->yres;
- win->phys_addr = config->framebuffer_base;
- win->stride = config->xres * (1 << log2_bpp) / 8;
- printk(BIOS_SPEW, "%s: depth = %d\n", __func__, log2_bpp);
- switch (log2_bpp) {
- case 5:
- case 24:
- win->fmt = COLOR_DEPTH_R8G8B8A8;
- win->bpp = 32;
- break;
- case 4:
- win->fmt = COLOR_DEPTH_B5G6R5;
- win->bpp = 16;
- break;
-
- default:
- printk(BIOS_SPEW, "Unsupported LCD bit depth");
- return -1;
- }
+ WRITEL(config->xres | (config->yres << 16),
+ &disp_ctrl->disp.disp_active);
+ WRITEL((PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT) |
+ SHIFT_CLK_DIVIDER(div),
+ &disp_ctrl->disp.disp_clk_ctrl);
return 0;
}
-static void update_window(struct display_controller *dc,
- struct disp_ctl_win *win,
- struct soc_nvidia_tegra124_config *config)
+static void update_window(struct display_controller *disp_ctrl,
+ struct soc_nvidia_tegra124_config *config)
{
- u32 h_dda, v_dda;
u32 val;
- val = READL(&dc->cmd.disp_win_header);
- val |= WINDOW_A_SELECT;
- WRITEL(val, &dc->cmd.disp_win_header);
-
- WRITEL(win->fmt, &dc->win.color_depth);
-
- clrsetbits_le32(&dc->win.byte_swap, BYTE_SWAP_MASK,
- BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT);
+ WRITEL(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header);
- val = win->out_x << H_POSITION_SHIFT;
- val |= win->out_y << V_POSITION_SHIFT;
- WRITEL(val, &dc->win.pos);
+ WRITEL(((config->yres << 16) | config->xres), &disp_ctrl->win.size);
+ WRITEL(((config->yres << 16) |
+ (config->xres * config->framebuffer_bits_per_pixel / 8)),
+ &disp_ctrl->win.prescaled_size);
+ WRITEL(((config->xres * config->framebuffer_bits_per_pixel / 8 + 31) /
+ 32 * 32), &disp_ctrl->win.line_stride);
- val = win->out_w << H_SIZE_SHIFT;
- val |= win->out_h << V_SIZE_SHIFT;
- WRITEL(val, &dc->win.size);
+ WRITEL(config->color_depth, &disp_ctrl->win.color_depth);
- val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT;
- val |= win->h << V_PRESCALED_SIZE_SHIFT;
- WRITEL(val, &dc->win.prescaled_size);
+ WRITEL(config->framebuffer_base, &disp_ctrl->winbuf.start_addr);
+ WRITEL((V_DDA_INC(0x1000) | H_DDA_INC(0x1000)), &disp_ctrl->win.dda_increment);
- WRITEL(0, &dc->win.h_initial_dda);
- WRITEL(0, &dc->win.v_initial_dda);
+ WRITEL(COLOR_WHITE, &disp_ctrl->disp.blend_background_color);
+ WRITEL(DISP_CTRL_MODE_C_DISPLAY, &disp_ctrl->cmd.disp_cmd);
- h_dda = (win->w * 0x1000) / MAX(win->out_w - 1, 1);
- v_dda = (win->h * 0x1000) / MAX(win->out_h - 1, 1);
+ WRITEL(WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access);
- val = h_dda << H_DDA_INC_SHIFT;
- val |= v_dda << V_DDA_INC_SHIFT;
- WRITEL(val, &dc->win.dda_increment);
-
- WRITEL(win->stride, &dc->win.line_stride);
- WRITEL(0, &dc->win.buf_stride);
-
- val = WIN_ENABLE;
- if (win->bpp < 24)
- val |= COLOR_EXPAND;
- WRITEL(val, &dc->win.win_opt);
+ val = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
+ val |= GENERAL_UPDATE | WIN_A_UPDATE;
+ WRITEL(val, &disp_ctrl->cmd.state_ctrl);
- WRITEL((u32) win->phys_addr, &dc->winbuf.start_addr);
- WRITEL(win->x, &dc->winbuf.addr_h_offset);
- WRITEL(win->y, &dc->winbuf.addr_v_offset);
+ // Enable win_a
+ val = READL(&disp_ctrl->win.win_opt);
+ WRITEL(val | WIN_ENABLE, &disp_ctrl->win.win_opt);
+}
- WRITEL(0xff00, &dc->win.blend_nokey);
- WRITEL(0xff00, &dc->win.blend_1win);
+static int tegra_dc_init(struct display_controller *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);
- val = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
- val |= GENERAL_UPDATE | WIN_A_UPDATE;
- WRITEL(val, &dc->cmd.state_ctrl);
+ return 0;
}
uint32_t fb_base_mb(void)
@@ -237,16 +204,22 @@ uint32_t fb_base_mb(void)
*/
void display_startup(device_t dev)
{
- u32 val;
- int i;
struct soc_nvidia_tegra124_config *config = dev->chip_info;
- struct display_controller *dc = (void *)config->display_controller;
- struct pwm_controller *pwm = (void *)TEGRA_PWM_BASE;
- struct disp_ctl_win window;
+ struct display_controller *disp_ctrl = (void *)config->display_controller;
+ struct pwm_controller *pwm = (void *)TEGRA_PWM_BASE;
+ struct tegra_dc *dc = &dc_data;
/* should probably just make it all MiB ... in future */
u32 framebuffer_size_mb = config->framebuffer_size / MiB;
u32 framebuffer_base_mb= config->framebuffer_base / MiB;
+
+ /* init dc */
+ dc->base = (void *)TEGRA_ARM_DISPLAYA;
+ dc->config = config;
+ config->dc_data = dc;
+
+ dp_init(config);
+
/* light it all up */
/* This one may have been done in romstage but that's ok for now. */
if (config->panel_vdd_gpio){
@@ -254,13 +227,12 @@ void display_startup(device_t dev)
printk(BIOS_SPEW,"%s: panel_vdd setting gpio %08x to %d\n",
__func__, config->panel_vdd_gpio, 1);
}
- delay(1);
+ udelay(config->vdd_delay_ms * 1000);
if (config->backlight_vdd_gpio){
gpio_output(config->backlight_vdd_gpio, 1);
printk(BIOS_SPEW,"%s: backlight vdd setting gpio %08x to %d\n",
__func__, config->backlight_vdd_gpio, 1);
}
- delay(1);
if (config->lvds_shutdown_gpio){
gpio_output(config->lvds_shutdown_gpio, 0);
printk(BIOS_SPEW,"%s: lvds shutdown setting gpio %08x to %d\n",
@@ -281,10 +253,6 @@ void display_startup(device_t dev)
0x02e), /* frequency divider */
&pwm->pwm[config->pwm].csr);
- printk(BIOS_SPEW,
- "%s: xres %d yres %d framebuffer_bits_per_pixel %d\n",
- __func__,
- config->xres, config->yres, config->framebuffer_bits_per_pixel);
if (framebuffer_size_mb == 0){
framebuffer_size_mb = ALIGN_UP(config->xres * config->yres *
(config->framebuffer_bits_per_pixel / 8), MiB)/MiB;
@@ -293,13 +261,12 @@ void display_startup(device_t dev)
if (! framebuffer_base_mb)
framebuffer_base_mb = fb_base_mb();
+ config->framebuffer_size = framebuffer_size_mb * MiB;
+ config->framebuffer_base = framebuffer_base_mb * MiB;
+
mmu_config_range(framebuffer_base_mb, framebuffer_size_mb,
config->cache_policy);
- /* Enable flushing after LCD writes if requested */
- /* I don't understand this part yet.
- lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH);
- */
printk(BIOS_SPEW, "LCD frame buffer at %dMiB to %dMiB\n", framebuffer_base_mb,
framebuffer_base_mb + framebuffer_size_mb);
@@ -311,63 +278,34 @@ void display_startup(device_t dev)
* light things up here once we're sure it's all working.
*/
- /* init dc_a */
- init_dca_regs();
+ /* Init dc */
+ if (tegra_dc_init(disp_ctrl)) {
+ printk(BIOS_ERR, "dc: init failed\n");
+ return;
+ }
- /* power up perip */
- dp_io_powerup();
+ /* Configure dc mode */
+ update_display_mode(disp_ctrl, config);
- /* bringup dp */
- dp_bringup(framebuffer_base_mb*MiB);
+ /* Enable dp */
+ dp_enable(dc->out);
- /* init frame buffer */
+ /* Init frame buffer */
memset((void *)(framebuffer_base_mb*MiB), 0x00,
framebuffer_size_mb*MiB);
+ update_window(disp_ctrl, config);
+
+ printk(BIOS_INFO, "%s: display init done.\n", __func__);
+
/* tell depthcharge ...
*/
struct edid edid;
- edid.x_resolution = 1376;
- edid.y_resolution = 768;
- edid.bytes_per_line = 1376 * 2;
- edid.framebuffer_bits_per_pixel = 16;
+ edid.bytes_per_line = ((config->xres * config->framebuffer_bits_per_pixel / 8 + 31) /
+ 32 * 32);
+ edid.x_resolution = edid.bytes_per_line / (config->framebuffer_bits_per_pixel / 8);
+ edid.y_resolution = config->yres;
+ edid.framebuffer_bits_per_pixel = config->framebuffer_bits_per_pixel;
set_vbe_mode_info_valid(&edid, (uintptr_t)(framebuffer_base_mb*MiB));
-
- if (0){
-/* do we still need these? */
- WRITEL(0x00000100, &dc->cmd.gen_incr_syncpt_ctrl);
- WRITEL(0x0000011a, &dc->cmd.cont_syncpt_vsync);
- WRITEL(0x00000000, &dc->cmd.int_type);
- WRITEL(0x00000000, &dc->cmd.int_polarity);
- WRITEL(0x00000000, &dc->cmd.int_mask);
- WRITEL(0x00000000, &dc->cmd.int_enb);
-
- val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE;
- val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE;
- val |= PM1_ENABLE;
- WRITEL(val, &dc->cmd.disp_pow_ctrl);
-
- val = READL(&dc->cmd.disp_cmd);
- val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT;
- WRITEL(val, &dc->cmd.disp_cmd);
-
- WRITEL(0x00000020, &dc->disp.mem_high_pri);
- WRITEL(0x00000001, &dc->disp.mem_high_pri_timer);
-
- for (i = 0; i < PIN_REG_COUNT; i++) {
- WRITEL(rgb_enb_tab[i], &dc->com.pin_output_enb[i]);
- WRITEL(rgb_polarity_tab[i], &dc->com.pin_output_polarity[i]);
- WRITEL(rgb_data_tab[i], &dc->com.pin_output_data[i]);
- }
-
- for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++)
- WRITEL(rgb_sel_tab[i], &dc->com.pin_output_sel[i]);
-
- if (config->pixel_clock)
- update_display_mode(&dc->disp, config);
-
- if (!setup_window(&window, config))
- update_window(dc, &window, config);
- }
}
diff --git a/src/soc/nvidia/tegra124/displayhack.c b/src/soc/nvidia/tegra124/displayhack.c
deleted file mode 100644
index af0ac16673..0000000000
--- a/src/soc/nvidia/tegra124/displayhack.c
+++ /dev/null
@@ -1,738 +0,0 @@
-/* this is too ugly to be allowed to live. But it's what works for now. */
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2013 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <console/console.h>
-#include <arch/io.h>
-#include <stdint.h>
-#include <lib.h>
-#include <stdlib.h>
-#include <delay.h>
-#include <soc/addressmap.h>
-#include <device/device.h>
-#include <stdlib.h>
-#include <string.h>
-#include <cpu/cpu.h>
-#include <boot/tables.h>
-#include <cbmem.h>
-#include <soc/nvidia/tegra/dc.h>
-#include "clk_rst.h"
-#include <soc/clock.h>
-#include "chip.h"
-#include "sor.h"
-#include <soc/display.h>
-
-//#include <soc/nvidia/tegra/displayport.h>
-extern int dump;
-unsigned long READL(void *p);
-void WRITEL(unsigned long value, void *p);
-void debug_dpaux_print(u32 addr, u32 size);
-int dpaux_write(u32 addr, u32 size, u32 data);
-int dpaux_read(u32 addr, u32 size, u8 * data);
-
-#define DCA_WRITE(reg, val) \
- { \
- WRITEL(val, (void *)(TEGRA_ARM_DISPLAYA + (reg<<2))); \
- }
-#define DCA_READ_M_WRITE(reg, mask, val) \
- { \
- u32 _reg_val; \
- _reg_val = READL( (void *)(TEGRA_ARM_DISPLAYA + (reg<<2))); \
- _reg_val &= ~mask; \
- _reg_val |= val; \
- WRITEL(_reg_val, (void *)(TEGRA_ARM_DISPLAYA + (reg<<2))); \
- }
-
-#define SOR_WRITE(reg, val) \
- { \
- WRITEL(val, (void *)(TEGRA_ARM_SOR + (reg<<2))); \
- }
-
-#define SOR_READ(reg) READL((void *)(TEGRA_ARM_SOR + (reg<<2)))
-
-#define SOR_READ_M_WRITE(reg, mask, val) \
- { \
- u32 _reg_val; \
- _reg_val = READL((void *)(TEGRA_ARM_SOR + (reg<<2))); \
- _reg_val &= ~mask; \
- _reg_val |= val; \
- WRITEL(_reg_val, (void *)(TEGRA_ARM_SOR + (reg<<2))); \
- }
-
-#define DPAUX_WRITE(reg, val) \
- { \
- WRITEL(val, (void *)(TEGRA_ARM_DPAUX + (reg<<2))); \
- }
-#define DPAUX_READ(reg) READL((void *)(TEGRA_ARM_DPAUX + (reg<<2)))
-
-void init_dca_regs(void)
-{
- DCA_WRITE (DC_CMD_DISPLAY_WINDOW_HEADER_0, 0x000000F0);
- DCA_WRITE (DC_WIN_A_WIN_OPTIONS_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_BYTE_SWAP_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_BUFFER_CONTROL_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_COLOR_DEPTH_0, 0x0000000C);
-
- DCA_WRITE (DC_WIN_A_POSITION_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_SIZE_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_PRESCALED_SIZE_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_H_INITIAL_DDA_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_V_INITIAL_DDA_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_DDA_INCREMENT_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_LINE_STRIDE_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_DV_CONTROL_0, 0x00000000);
-
- DCA_WRITE (DC_WIN_A_BLEND_LAYER_CONTROL_0, 0x01000000);
- DCA_WRITE (DC_WIN_A_BLEND_MATCH_SELECT_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_BLEND_NOMATCH_SELECT_0, 0x00000000);
- DCA_WRITE (DC_WIN_A_BLEND_ALPHA_1BIT_0, 0x00000000);
-
- DCA_WRITE (DC_WINBUF_A_START_ADDR_HI_0, 0x00000000);
- DCA_WRITE (DC_WINBUF_A_ADDR_H_OFFSET_0, 0x00000000);
- DCA_WRITE (DC_WINBUF_A_ADDR_V_OFFSET_0, 0x00000000);
- DCA_WRITE (DC_CMD_DISPLAY_WINDOW_HEADER_0, 0x00000000);
-
- DCA_WRITE (DC_COM_CRC_CONTROL_0, 0x00000000);
- DCA_WRITE (DC_COM_CRC_CHECKSUM_0, 0x00000000);
- DCA_WRITE (DC_COM_PIN_OUTPUT_ENABLE0_0, 0x00000000);
- DCA_WRITE (DC_COM_PIN_OUTPUT_ENABLE1_0, 0x00000000);
- DCA_WRITE (DC_COM_PIN_OUTPUT_ENABLE2_0, 0x00510104);
- DCA_WRITE (DC_COM_PIN_OUTPUT_ENABLE3_0, 0x00000555);
-}
-
-static int dp_poll_register(void *addr, u32 exp_val, u32 mask, u32 timeout_ms)
-{
- u32 reg_val = 0;
-
- do {
- udelay(1000);
- reg_val = READL(addr);
- } while (((reg_val & mask) != exp_val) && (--timeout_ms > 0));
-
- if ((reg_val & mask) == exp_val)
- return 0; /* success */
- printk(BIOS_WARNING, "poll_register %p: timeout\n", addr);
- return timeout_ms;
-}
-
-static void dp_io_set_dpd(u32 power_down)
-{
- /*
- * power_down:
- * 0: out of Deep power down
- * 1: into deep power down
- */
- u32 val_reg;
-
- val_reg = READL((void *)(0x7000e400 + 0x1c4)); /* APBDEV_PMC_IO_DPD2_STATUS_0 */
- if ((((val_reg & DP_LVDS) >> DP_LVDS_SHIFT) & 1) == power_down) {
- printk(BIOS_DEBUG, "PAD already POWER=%d\n", 1 - power_down);
- return;
- }
-
- /* APBDEV_PMC_IO_DPD2_REQ_0: E_DPD = power on */
- WRITEL((DP_LVDS | ((1 + power_down) << 30)), (void *)(0x7000e400 + 0x1c0));
-
- dp_poll_register((void *)(0x7000e400 + 0x1C4), 0, DP_LVDS, 1000);
- /* APBDEV_PMC_IO_DPD2_STATUS_0 */
-}
-
-void dp_io_powerup(void)
-{
- SOR_WRITE(SOR_NV_PDISP_SOR_CLK_CNTRL_0, (6 << 2) | 2);//select PLLDP, lowest speed(6x)
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, 0x00800000); //set PDCAL
- SOR_WRITE(SOR_NV_PDISP_SOR_PLL0_0, 0x050003D5); //set PWR,VCOPD
- SOR_WRITE(SOR_NV_PDISP_SOR_PLL1_0, 0x00001100); //default
- SOR_WRITE(SOR_NV_PDISP_SOR_PLL2_0, 0x01C20000); //set AUX1,6,7,8; clr AUX2
- SOR_WRITE(SOR_NV_PDISP_SOR_PLL3_0, 0x38002220);
-
- /* Deassert E_DPD to enable core logic circuits, and wait for > 5us */
- dp_io_set_dpd(0);
- udelay(10);
-
- /* Deassert PDBG to enable bandgap, and wait for > 20us. */
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL2_0,
- SOR_NV_PDISP_SOR_PLL2_0_AUX6_FIELD,
- (0 << SOR_NV_PDISP_SOR_PLL2_0_AUX6_SHIFT));
- udelay(25);
-
- /*
- * Enable the PLL/charge-pump/VCO, and wait for >200us for the PLL to
- * lock. Input Clock must be running and stable before PDPLL
- * de-assertion.
- */
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL0_0,
- SOR_NV_PDISP_SOR_PLL0_0_PWR_FIELD,
- (0 << SOR_NV_PDISP_SOR_PLL0_0_PWR_SHIFT));
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL0_0,
- SOR_NV_PDISP_SOR_PLL0_0_VCOPD_FIELD,
- (0 << SOR_NV_PDISP_SOR_PLL0_0_VCOPD_SHIFT));
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL2_0,
- SOR_NV_PDISP_SOR_PLL2_0_AUX8_FIELD,
- (0 << SOR_NV_PDISP_SOR_PLL2_0_AUX8_SHIFT));
- udelay(210);
-
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL2_0,
- SOR_NV_PDISP_SOR_PLL2_0_AUX7_FIELD,
- (0 << SOR_NV_PDISP_SOR_PLL2_0_AUX7_SHIFT));
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL2_0,
- SOR_NV_PDISP_SOR_PLL2_0_AUX9_FIELD,
- (1 << SOR_NV_PDISP_SOR_PLL2_0_AUX9_SHIFT));
- udelay(100);
-
-}
-
-static int dpaux_check(u32 bytes, u32 data, u32 mask)
-{
- u32 status = 0;
- u8 buf[16];
- u32 temp;
-
- DPAUX_WRITE(DPAUX_DP_AUXDATA_READ_W0, 0);
- status = dpaux_read(0x202, bytes, buf);
- if (status != 0)
- printk(BIOS_ERR, "******AuxRead Error:%04x: status %08x\n",
- 0x202, status);
- else {
- temp = DPAUX_READ(DPAUX_DP_AUXDATA_READ_W0);
- if ((temp & mask) != (data & mask)) {
- printk(BIOS_ERR, "AuxCheck ERROR:(r_data) %08x &"
- " (mask) %08x != (data) %08x & (mask) %08x\n",
- temp, mask, data, mask);
- return -1;
- } else {
- printk(BIOS_DEBUG, "AuxCheck PASS:(bytes=%d, "
- "data=%08x, mask=%08x):0x%08x\n",
- bytes, data, mask, temp);
- return 0;
- }
- }
- return -1;
-}
-
-/* Modify the drive parameters for DP. There are up to four DP
- * lanes. In principle, each lane can have different current,
- * pre-emphasis, and postcur values. Nobody individualizes them; every
- * single driver I've seen drives all the lanes to the same value
- * (across x86 and ARM code). Actualy adjusting them individually and
- * getting it all to work is probably a PhD thesis anyway. So, rather
- * than the very complex code we see many places, the people who wrote
- * this code realize: we can represent the 'volume' as a number in the
- * range 0..3, with '0' as the base and '3' as being 'not to exceed'.
- *
- * So they abstract the values away, take care of the proper values,
- * and set it all in one blow. Very nice. By far the easiest one of
- * these functions we've seen. Sure, they could have constants, but
- * nobody knows what PRE_EMPHASIS_3_5 and the other values actually
- * *mean* anyway. Well, the hardware guys might.
- */
-static void pattern_level(u32 current, u32 preemph, u32 postcur)
-{
- //calibrating required
- if (current == 0)
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x20202020);
- if (current == 1)
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x24242424);
- if (current == 2)
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x30303030);
- if (current == 3)
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x40404040);
- if (preemph == 0)
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x00000000);
- if (preemph == 1)
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x08080808);
- if (preemph == 2)
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x10101010);
- if (preemph == 3)
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x18181818);
- if (postcur == 0)
- SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x00000000);
- if (postcur == 1)
- SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x04040404);
- if (postcur == 2)
- SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x08080808);
- if (postcur == 3)
- SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x10101010);
-}
-
-static int dp_training(u32 level, u32 check, u32 speed)
-{
- /* The levels are one of four choices. This code
- * packs them into the three lowest nibl's. We may change this.
- */
- u32 dc_lv = level & 0x0f;
- u32 pe_lv = (level >> 4) & 0x0f;
- u32 pc_lv = (level >> 8) & 0x0f;
- u32 cnt = 0;
- u32 cfg, cfg_d = 0;
- u32 wcfg;
- u8 buf[16];
-
- while (cnt <= 5) {
- pattern_level(dc_lv, pe_lv, pc_lv);
- wcfg = (pe_lv << 3) | dc_lv;
- if (dc_lv == 3)
- wcfg = wcfg | 0x04;
- if (pe_lv == 3)
- wcfg = wcfg | 0x20;
- wcfg = wcfg | (wcfg << 8) | (wcfg << 16) | (wcfg << 24);
- dpaux_write(0x103, 4, wcfg);
- udelay(100);
- DPAUX_WRITE(DPAUX_DP_AUXDATA_READ_W0, 0);
- if (!dpaux_check(2, check, check))
- cnt = 100;
- else {
- dpaux_read(0x206, 1, buf);
- cfg = DPAUX_READ(DPAUX_DP_AUXDATA_READ_W0);
- cfg &= 0x00ff;
- if (cfg == cfg_d) {
- ++cnt;
- if (cnt > 5)
- printk(BIOS_ERR, "Error: link training FAILED\n");
- } else {
- cnt = 0;
- cfg_d = cfg;
- dc_lv = cfg & 0x3;
- pe_lv = (cfg >> 2) & 0x3;
- if (speed == 20) {
- dpaux_read(0x20C, 1, buf);
- cfg = DPAUX_READ(DPAUX_DP_AUXDATA_READ_W0);
- pc_lv = cfg & 0x3;
- } else {
- pc_lv = 0;
- }
- }
-
- }
- debug_dpaux_print(0x200, 16);
- }
-
- return ((pc_lv << 8) | (pe_lv << 4) | (dc_lv));
-
-}
-
-void dp_link_training(u32 lanes, u32 speed);
-void dp_link_training(u32 lanes, u32 speed)
-{
- u32 lane_on;
- u32 mask, level;
- u32 reg_val;
-
- printk(BIOS_DEBUG, "\nLink training start\n");
-
- switch (lanes) {
- case 1:
- lane_on = 0x04;
- break;
- case 2:
- lane_on = 0x06;
- break;
- case 4:
- lane_on = 0x0f;
- break;
- default:
- printk(BIOS_DEBUG, "dp: invalid lane count: %d\n",
- lanes);
- return;
- }
-
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, (0x008000000 | lane_on));
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0,
- SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_FIELD,
- (6 << SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_SHIFT));
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0,
- SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_FIELD,
- (1 << SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_SHIFT));
- SOR_WRITE(SOR_NV_PDISP_SOR_LVDS_0, 0);
-
- SOR_WRITE(SOR_NV_PDISP_SOR_CLK_CNTRL_0, ((speed << 2) | 2));
- udelay(100 * 1000);
-
- sor_clock_start();
-
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL0_0,
- (((0xF >> (4 - lanes)) << 16) | 1));
-
- SOR_WRITE(SOR_NV_PDISP_SOR_LANE_SEQ_CTL_0, 0x80100000);
- printk(BIOS_DEBUG, "Polling SOR_NV_PDISP_SOR_LANE_SEQ_CTL_0.DONE\n");
-
- dp_poll_register((void *)0x54540084, 0x00000000, 0x80000000, 1000);
-
- debug_dpaux_print(0x202, 4);
-
- printk(BIOS_DEBUG, "set link rate and lane number: %dMHz, %d lanes\n",
- (speed * 27), lanes);
-
- dpaux_write(0x100, 2, ((lanes << 8) | speed));
- printk(BIOS_DEBUG, "precharge lane 10us\n");
- reg_val = SOR_READ(SOR_NV_PDISP_SOR_DP_PADCTL0_0);
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, (0x000000f0 | reg_val));
- udelay(100 * 1000);
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, reg_val);
-
- printk(BIOS_DEBUG, "link training cr start\n");
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x41414141);
- dpaux_write(0x102, 1, 0x21);
-
- mask = 0x0000ffff >> ((4 - lanes) * 4);
- level = 0;
- level = dp_training(level, 0x1111 & mask, speed);
- printk(BIOS_DEBUG, "level:%x\n", level);
-
- debug_dpaux_print(0x210, 16);
-
- printk(BIOS_DEBUG, "link training eq start\n");
- if (speed == 20) {
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x43434343);
- dpaux_write(0x102, 1, 0x23);
- } else {
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x42424242);
- dpaux_write(0x102, 1, 0x22);
- }
-
- level = dp_training(level, (0x7777 & mask) | 0x10000, speed);
- printk(BIOS_DEBUG, "level:%x\n", level);
-
- debug_dpaux_print(0x210, 16);
-
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x50505050);
- dpaux_write(0x102, 1, 0);
- dpaux_write(0x600, 1, 1);
-
- debug_dpaux_print(0x200, 16);
- debug_dpaux_print(0x210, 16);
-
- printk(BIOS_DEBUG, "Link training done\n\n");
-}
-
-static u32 div_f(u32 a, u32 b, u32 one)
-{
- u32 d = (((a - (a / b * b)) * one) + (b / 2)) / b;
- return (d);
-}
-
-u32 dp_setup_timing(u32 width, u32 height)
-{
- u32 pclk_freq = 0;
-
- u32 PLL_FREQ = (12 / 12 * 283) / 1 / 2; /* 141.5 */
- u32 PLL_DIV = 2;
- u32 SYNC_WIDTH = (8 << 16) | 46;
- u32 BACK_PORCH = (6 << 16) | 44;
- u32 FRONT_PORCH = (6 << 16) | 44;
- u32 HSYNC_NEG = 1;
- u32 VSYNC_NEG = 1;
-
- u32 SHIFT_CLK_DIVIDER = PLL_DIV * 2 - 2;
- u32 DISP_ACTIVE = (height << 16) | width;
- u32 DISP_TOTAL = DISP_ACTIVE + SYNC_WIDTH + BACK_PORCH + FRONT_PORCH;
- u32 SYNC_END = SYNC_WIDTH - 0x10001;
- u32 BLANK_END = SYNC_END + BACK_PORCH;
- u32 BLANK_START = BLANK_END + DISP_ACTIVE;
- u32 TOTAL_PIXELS = (DISP_TOTAL & 0xffff) * (DISP_TOTAL >> 16);
-
- u32 PLL_FREQ_I, PLL_FREQ_F;
- u32 PCLK_FREQ_I, PCLK_FREQ_F;
- u32 FRATE_I, FRATE_F;
-
- PLL_FREQ = PLL_FREQ * 1000000;
- pclk_freq = PLL_FREQ / PLL_DIV;
- PLL_FREQ_I = PLL_FREQ / 1000000;
- PLL_FREQ_F = div_f(PLL_FREQ, 1000000, 100);
- PCLK_FREQ_I = PLL_FREQ / (PLL_DIV * 1000000);
- PCLK_FREQ_F = div_f(PLL_FREQ, PLL_DIV * 1000000, 100);
- FRATE_I = PLL_FREQ / (PLL_DIV * TOTAL_PIXELS);
- FRATE_F = div_f(PLL_FREQ, (PLL_DIV * TOTAL_PIXELS), 100);
- /* nv_bug 1021453 */
- BACK_PORCH = BACK_PORCH - 0x10000;
- FRONT_PORCH = FRONT_PORCH + 0x10000;
-
- printk(BIOS_DEBUG, "ACTIVE: %dx%d\n", (DISP_ACTIVE & 0xFFFF),
- (DISP_ACTIVE >> 16));
- printk(BIOS_DEBUG, "TOTAL: %dx%d\n", (DISP_TOTAL & 0xffff),
- (DISP_TOTAL >> 16));
- printk(BIOS_DEBUG, "PLL Freq: %d.%d MHz\n", PLL_FREQ_I, PLL_FREQ_F);
- printk(BIOS_DEBUG, "Pclk Freq: %d.%d MHz\n", PCLK_FREQ_I,
- PCLK_FREQ_F);
- printk(BIOS_DEBUG, "Frame Rate: %d.%d Hz\n", FRATE_I, FRATE_F);
- printk(BIOS_DEBUG, "\n");
-
- DCA_WRITE(DC_CMD_STATE_ACCESS_0, 0x00000004);
- DCA_WRITE(DC_DISP_DISP_CLOCK_CONTROL_0, SHIFT_CLK_DIVIDER);
- //Raster Timing
- DCA_WRITE(DC_DISP_DISP_TIMING_OPTIONS_0, 0x00000001);
- DCA_WRITE(DC_DISP_REF_TO_SYNC_0, 0x00010001);
- DCA_WRITE(DC_DISP_SYNC_WIDTH_0, SYNC_WIDTH);
- DCA_WRITE(DC_DISP_BACK_PORCH_0, BACK_PORCH);
- DCA_WRITE(DC_DISP_DISP_ACTIVE_0, DISP_ACTIVE);
- DCA_WRITE(DC_DISP_FRONT_PORCH_0, FRONT_PORCH);
-
- //REG(DC_DISP_DISP_WIN_OPTIONS_0, SOR_ENABLE , 1)
- DCA_READ_M_WRITE(DC_DISP_DISP_WIN_OPTIONS_0,
- DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_FIELD,
- (1 << DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_SHIFT));
-
- SOR_WRITE(SOR_NV_PDISP_HEAD_STATE1_0, DISP_TOTAL);
- SOR_WRITE(SOR_NV_PDISP_HEAD_STATE2_0, SYNC_END);
- SOR_WRITE(SOR_NV_PDISP_HEAD_STATE3_0, BLANK_END);
- SOR_WRITE(SOR_NV_PDISP_HEAD_STATE4_0, BLANK_START);
-
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0,
- SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_FIELD,
- (HSYNC_NEG <<
- SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_SHIFT));
-
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0,
- SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_FIELD,
- (VSYNC_NEG <<
- SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_SHIFT));
-
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0,
- SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_FIELD,
- (SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_DP_A <<
- SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_SHIFT));
-
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0,
- SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_FIELD,
- (SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_COMPLETE_RASTER <<
- SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_SHIFT));
-
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0,
- SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_FIELD,
- (SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_NONE <<
- SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SHIFT));
-
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0,
- SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_FIELD,
- (SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_HEAD0 <<
- SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_SHIFT));
- return pclk_freq;
-}
-
-static u32 calc_config(u32 ts, u32 a, u32 b, u32 bpp)
-{
- u32 act_cnt = (ts * a) / b;
- u32 diff = (ts * a) - (act_cnt * b);
- u32 act_pol;
- u32 act_frac;
- u32 err;
- u32 water_mark;
-
- printk(BIOS_DEBUG, "calc_config ts %d a %d b %d bpp %d\n",
- ts, a, b, bpp);
- if (diff != 0) {
- if (diff > (b / 2)) {
- diff = b - diff;
- act_pol = 1;
- act_frac = (b + diff - 1) / diff;
- err = diff * act_frac - b;
- } else {
- act_pol = 0;
- act_frac = b / diff;
- err = b - (diff * act_frac);
- }
- if (act_frac > 15) {
- act_pol = 1 - act_pol;
- act_frac = 1;
- err = diff;
- }
- } else {
- act_pol = 1;
- act_frac = 1;
- err = 0;
- }
-
- if (bpp) {
- water_mark = (a * (b - a) * ts / (b * b)) + (2 * bpp / 8);
- if (water_mark > 30)
- water_mark = 30;
-
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0, 0x84000000);
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0,
- SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_FIELD,
- (act_pol <<
- SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_SHIFT));
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0,
- SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_FIELD,
- (act_frac <<
- SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_SHIFT));
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0,
- SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_FIELD,
- (act_cnt <<
- SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_SHIFT));
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0,
- SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_FIELD,
- (water_mark <<
- SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_SHIFT));
-
- printk(BIOS_DEBUG,
- "SOR_DP_CONFIG0:TU,CNT,POL,FRAC,WMK,ERR=%d,%d,%d,%d,%d,%d/%d\n",
- ts, act_cnt, act_pol, act_frac, water_mark, err, b);
- }
- return (err);
-}
-
-static u32 dp_buf_config(u32 pclkfreq, u32 linkfreq, u32 lanes, u32 bpp)
-{
- //to avoid 32bit overflow
- u32 tusize = 0;
- u32 pf = pclkfreq;
- u32 lf = linkfreq;
- u32 i;
- u32 a, b;
- u32 min_err = 1000000000;
- u32 ts = 64;
- u32 c_err;
-
- printk(BIOS_DEBUG, "dp buf config pclkfreq %d linkfreq %d lanes %d bpp %d\n",
- pclkfreq, linkfreq, lanes, bpp);
- for (i = 2; i <= 7; ++i) {
- while (((pf / i * i) == pf) && ((lf / i * i) == lf)) {
- pf = pf / i;
- lf = lf / i;
- }
- }
-
- a = pf * bpp / 8;
- b = lf * lanes;
- printk(BIOS_DEBUG, "ratio:%d/%d\n", a, b);
- if (a > (b * 98 / 100))
- printk(BIOS_ERR, "Error:link speed not enough\n");
-
- //search best tusize
- //min_err = 1000000000;
- //ts = 64;
- while (ts >= 32) {
- c_err = calc_config(ts, a, b, 0);
- if (c_err < min_err) {
- if (c_err == 0) {
- tusize = ts;
- ts = 1;
- } else {
- min_err = c_err;
- tusize = ts;
- }
- }
- --ts;
- }
-
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL0_0,
- SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_FIELD,
- (tusize << SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_SHIFT));
- calc_config(tusize, a, b, bpp);
-
- return (tusize);
-}
-
-/*
-void dp_misc_setting(u32 panel_bpp, u32 width, u32 height, u32 winb_addr,
- u32 lane_count, u32 enhanced_framing, u32 panel_edp,
- u32 pclkfreq, u32 linkfreq);
-*/
-void dp_misc_setting(u32 panel_bpp, u32 width, u32 height, u32 winb_addr,
- u32 lane_count, u32 enhanced_framing, u32 panel_edp,
- u32 pclkfreq, u32 linkfreq)
-{
- u32 tusize;
- u32 linkctl;
-
- printk(BIOS_DEBUG, "%s: winb: 0x%08x, panel_bpp %d ",
- __func__, winb_addr, panel_bpp);
-
- if (panel_bpp == 18) {
- //0x54540010
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0,
- SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_FIELD,
- (SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_18_444 <<
- SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_SHIFT));
- }
- if (panel_bpp == 24) {
- SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0,
- SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_FIELD,
- (SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_24_444 <<
- SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_SHIFT));
- }
-
- DCA_WRITE(DC_CMD_DISPLAY_WINDOW_HEADER_0, 0x00000010);
- DCA_WRITE(DC_WIN_A_SIZE_0, ((height << 16) | width));
- DCA_WRITE(DC_WIN_A_PRESCALED_SIZE_0,
- ((height << 16) | (width * SRC_BPP / 8)));
- DCA_WRITE(DC_WIN_A_LINE_STRIDE_0,
- ((width * SRC_BPP / 8 + 31) / 32 * 32));
- DCA_WRITE(DC_WIN_A_COLOR_DEPTH_0, COLORDEPTH);
- DCA_WRITE(DC_WINBUF_A_START_ADDR_LO_0, winb_addr);
- DCA_WRITE(DC_WIN_A_DDA_INCREMENT_0, 0x10001000);
-
- SOR_WRITE(SOR_NV_PDISP_SOR_CRC_CNTRL_0, 0x00000001);
- DCA_WRITE(DC_COM_CRC_CONTROL_0, 0x00000009); //CRC_ALWAYS+CRC_ENABLE
- DCA_WRITE(DC_COM_PIN_OUTPUT_ENABLE2_0, 0x00000000);
- DCA_WRITE(DC_COM_PIN_OUTPUT_ENABLE3_0, 0x00000000);
- DCA_WRITE(DC_DISP_DISP_SIGNAL_OPTIONS0_0, 0x00000000);
- DCA_WRITE(DC_DISP_BLEND_BACKGROUND_COLOR_0, COLOR_WHITE);
- DCA_WRITE(DC_CMD_DISPLAY_COMMAND_0, 0x00000020);
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_AUDIO_VBLANK_SYMBOLS_0, 0x00000e48);
-
- dpaux_write(0x101, 1, (enhanced_framing << 7) | lane_count);
- if (panel_edp)
- dpaux_write(0x10A, 1, 1);
-
- tusize =
- dp_buf_config(pclkfreq, (linkfreq * 1000000), lane_count, panel_bpp);
-
- linkctl =
- ((0xF >> (4 - lane_count)) << 16) | (enhanced_framing << 14) | (tusize
- << 2) |
- 1;
-
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL0_0, linkctl);
- SOR_WRITE(SOR_NV_PDISP_SOR_DP_SPARE0_0, ((panel_edp << 1) | 0x05));
-
- SOR_WRITE(SOR_NV_PDISP_SOR_PWR_0, 0x80000001);
- printk(BIOS_DEBUG, "Polling SOR_NV_PDISP_SOR_PWR_0.DONE\n");
- dp_poll_register((void *)0x54540054, 0x00000000, 0x80000000, 1000);
- //SOR_NV_PDISP_SOR_PWR_0
- //sor_update
- SOR_WRITE(SOR_NV_PDISP_SOR_STATE0_0, 0x00000000);
- SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE1_0, 0x00000006);
- //sor_super_update
- SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE0_0, 0x00000000);
- SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE1_0, 0x0000000e);
- //sor_super_update
- SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE0_0, 0x00000000);
- printk(BIOS_DEBUG, "Polling SOR_NV_PDISP_SOR_TEST_0.ATTACHED\n");
- dp_poll_register((void *)0x54540058, 0x00000400, 0x00000400, 1000);
- //SOR_NV_PDISP_SOR_TEST_0
-
- DCA_WRITE(DC_CMD_STATE_CONTROL_0, 0x00009f00);
- DCA_WRITE(DC_CMD_STATE_CONTROL_0, 0x0000009f);
- DCA_WRITE(DC_CMD_DISPLAY_POWER_CONTROL_0, 0x00050155);
-
- printk(BIOS_DEBUG, "Polling SOR_NV_PDISP_SOR_TEST_0.AWAKE\n");
- dp_poll_register((void *)0x54540058, 0x00000200, 0x00000300, 1000);
- //SOR_NV_PDISP_SOR_TEST_0
-
- // DCA_WRITE (DC_CMD_STATE_ACCESS_0 ,0);
- DCA_WRITE(DC_CMD_STATE_ACCESS_0, 4);
- DCA_WRITE(DC_CMD_STATE_CONTROL_0, 0x0000ffff);
-
- DCA_READ_M_WRITE(DC_WIN_A_WIN_OPTIONS_0,
- DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_FIELD,
- (DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_ENABLE <<
- DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_SHIFT));
-}
diff --git a/src/soc/nvidia/tegra124/dp.c b/src/soc/nvidia/tegra124/dp.c
index 6b0f4c8698..a9da269da9 100644
--- a/src/soc/nvidia/tegra124/dp.c
+++ b/src/soc/nvidia/tegra124/dp.c
@@ -24,12 +24,11 @@
#include <soc/addressmap.h>
#include <soc/nvidia/tegra/i2c.h>
#include <soc/nvidia/tegra/dc.h>
+#include "chip.h"
#include "sor.h"
#include <soc/nvidia/tegra/displayport.h>
-extern int dump;
-unsigned long READL(void *p);
-void WRITEL(unsigned long value, void *p);
+struct tegra_dc_dp_data dp_data;
static inline u32 tegra_dpaux_readl(struct tegra_dc_dp_data *dp, u32 reg)
{
@@ -182,35 +181,6 @@ static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
return -1;
}
-static int tegra_dc_dpaux_write(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr,
- u8 *data, u32 *size, u32 *aux_stat)
-{
- u32 cur_size = 0;
- u32 finished = 0;
- u32 cur_left;
- int ret = 0;
-
- do {
- cur_size = *size - finished;
- if (cur_size > DP_AUX_MAX_BYTES)
- cur_size = DP_AUX_MAX_BYTES;
- cur_left = cur_size;
- ret = tegra_dc_dpaux_write_chunk(dp, cmd, addr,
- data, &cur_left, aux_stat);
-
- cur_size -= cur_left;
- finished += cur_size;
- addr += cur_size;
- data += cur_size;
-
- if (ret)
- break;
- } while (*size > finished);
-
- *size = finished;
- return ret;
-}
-
static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
u32 addr, u8 *data, u32 *size,
u32 *aux_stat)
@@ -235,12 +205,10 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
return -1;
}
- if (0) {
- *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
- if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
- printk(BIOS_SPEW, "dp: HPD is not detected\n");
- //return EFAULT;
- }
+ *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+ if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
+ printk(BIOS_SPEW, "dp: HPD is not detected\n");
+ return -1;
}
tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr);
@@ -262,8 +230,6 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
printk(BIOS_INFO, "dp: aux read transaction timeout\n");
*aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
- printk(BIOS_DEBUG, "dp: %s: aux stat: 0x%08x\n", __func__,
- *aux_stat);
if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) ||
(*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) ||
@@ -309,8 +275,6 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
DPAUX_DP_AUXDATA_READ_W(i));
*size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK);
- printk(BIOS_INFO, "dp: aux read data %d bytes\n",
- *size);
memcpy(data, temp_data, *size);
return 0;
@@ -325,230 +289,407 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
return -1;
}
-int tegra_dc_dpaux_read(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr,
- u8 * data, u32 * size, u32 * aux_stat)
+static int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd,
+ u8 * data_ptr)
{
- 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);
-
- /* cur_size should be the real size returned */
- addr += cur_size;
- data += cur_size;
- finished += cur_size;
-
- if (ret)
- break;
+ u32 size = 1;
+ u32 status = 0;
+ int ret;
- } while (*size > finished);
+ ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+ cmd, data_ptr, &size, &status);
+ if (ret)
+ printk(BIOS_ERR,
+ "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n",
+ cmd, status);
- *size = finished;
return ret;
}
-static int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd,
- u8 * data_ptr)
+static int tegra_dc_dp_dpcd_write(struct tegra_dc_dp_data *dp, u32 cmd,
+ u8 data)
{
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);
+ ret = tegra_dc_dpaux_write_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXWR,
+ cmd, &data, &size, &status);
if (ret)
printk(BIOS_ERR,
- "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n", cmd,
- status);
-
+ "dp: Failed to write DPCD data. CMD 0x%x, Status 0x%x\n",
+ cmd, status);
return ret;
}
-static int tegra_dc_dp_init_max_link_cfg(struct tegra_dc_dp_data *dp,
- struct tegra_dc_dp_link_config *cfg)
+static void tegra_dc_dpaux_enable(struct tegra_dc_dp_data *dp)
{
- u8 dpcd_data;
- int ret;
+ /* 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);
+}
- ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LANE_COUNT, &dpcd_data);
- if (ret)
- return ret;
+static void tegra_dc_dp_dump_link_cfg(struct tegra_dc_dp_data *dp,
+ const struct tegra_dc_dp_link_config *link_cfg)
+{
+ printk(BIOS_INFO, "DP config: cfg_name "
+ "cfg_value\n");
+ printk(BIOS_INFO, " Lane Count %d\n",
+ link_cfg->max_lane_count);
+ printk(BIOS_INFO, " SupportEnhancedFraming %s\n",
+ link_cfg->support_enhanced_framing ? "Y" : "N");
+ printk(BIOS_INFO, " Bandwidth %d\n",
+ link_cfg->max_link_bw);
+ printk(BIOS_INFO, " bpp %d\n",
+ link_cfg->bits_per_pixel);
+ printk(BIOS_INFO, " EnhancedFraming %s\n",
+ link_cfg->enhanced_framing ? "Y" : "N");
+ printk(BIOS_INFO, " Scramble_enabled %s\n",
+ link_cfg->scramble_ena ? "Y" : "N");
+ printk(BIOS_INFO, " LinkBW %d\n",
+ link_cfg->link_bw);
+ printk(BIOS_INFO, " lane_count %d\n",
+ link_cfg->lane_count);
+ printk(BIOS_INFO, " activespolarity %d\n",
+ link_cfg->activepolarity);
+ printk(BIOS_INFO, " active_count %d\n",
+ link_cfg->active_count);
+ printk(BIOS_INFO, " tu_size %d\n",
+ link_cfg->tu_size);
+ printk(BIOS_INFO, " active_frac %d\n",
+ link_cfg->active_frac);
+ printk(BIOS_INFO, " watermark %d\n",
+ link_cfg->watermark);
+ printk(BIOS_INFO, " hblank_sym %d\n",
+ link_cfg->hblank_sym);
+ printk(BIOS_INFO, " vblank_sym %d\n",
+ link_cfg->vblank_sym);
+};
+
+/* Calcuate if given cfg can meet the mode request. */
+/* Return true if mode is possible, false otherwise. */
+static int tegra_dc_dp_calc_config(struct tegra_dc_dp_data *dp,
+ const struct soc_nvidia_tegra124_config *config,
+ struct tegra_dc_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 || !config->pixel_clock ||
+ !link_cfg->bits_per_pixel)
+ return -1;
- cfg->max_lane_count = dpcd_data & NV_DPCD_MAX_LANE_COUNT_MASK;
- printk(BIOS_INFO, "%s: max_lane_count: %d\n", __func__,
- cfg->max_lane_count);
+ if ((u64)config->pixel_clock * link_cfg->bits_per_pixel >=
+ (u64)link_rate * 8 * link_cfg->lane_count)
+ return -1;
- cfg->support_enhanced_framing =
- (dpcd_data & NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ? 1 : 0;
- printk(BIOS_INFO, "%s: enh-framing: %d\n", __func__,
- cfg->support_enhanced_framing);
+ num_linkclk_line = (u32)((u64)link_rate * (u64)config->xres / config->pixel_clock);
- ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_DOWNSPREAD, &dpcd_data);
- if (ret)
- return ret;
- cfg->downspread = (dpcd_data & NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT) ? 1 : 0;
- printk(BIOS_INFO, "%s: downspread: %d\n", __func__, cfg->downspread);
+ ratio_f = (u64)config->pixel_clock * link_cfg->bits_per_pixel * f;
+ ratio_f /= 8;
+ ratio_f = (u64)(ratio_f / (link_rate * link_cfg->lane_count));
- ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LINK_BANDWIDTH,
- &cfg->max_link_bw);
- if (ret)
- return ret;
- printk(BIOS_INFO, "%s: max_link_bw: %d\n", __func__, cfg->max_link_bw);
+ for (i = 64; i >= 32; --i) {
+ activesym_f = ratio_f * i;
+ activecount_f = (u64)(activesym_f / (u32)f) * f;
+ frac_f = activesym_f - activecount_f;
+ activecount = (u32)((u64)(activecount_f / (u32)f));
- // cfg->bits_per_pixel = dp->dc->pdata->default_out->depth;
- cfg->bits_per_pixel = 18;
+ if (frac_f < (f / 2)) /* fraction < 0.5 */
+ activepolarity = 0;
+ else {
+ activepolarity = 1;
+ frac_f = f - frac_f;
+ }
- /* TODO: need to come from the board file */
- /* Venice2 settings */
- cfg->drive_current = 0x20202020;
- cfg->preemphasis = 0;
- cfg->postcursor = 0;
+ if (frac_f != 0) {
+ frac_f = (u64)((f * f) / frac_f); /* 1/fraction */
+ if (frac_f > (15 * f))
+ activefrac = activepolarity ? 1 : 15;
+ else
+ activefrac = activepolarity ?
+ (u32)((u64)(frac_f / (u32)f)) + 1 :
+ (u32)((u64)(frac_f / (u32)f));
+ }
+
+ if (activefrac == 1)
+ activepolarity = 0;
+
+ if (activepolarity == 1)
+ approx_value_f = activefrac ? (u64)(
+ (activecount_f + (activefrac * f - f) * f) /
+ (activefrac * f)) :
+ activecount_f + f;
+ else
+ approx_value_f = activefrac ?
+ activecount_f + (u64)(f / activefrac) :
+ activecount_f;
+
+ if (activesym_f < approx_value_f) {
+ accumulated_error_f = num_linkclk_line *
+ (u64)((approx_value_f - activesym_f) / i);
+ neg = 1;
+ } else {
+ accumulated_error_f = num_linkclk_line *
+ (u64)((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 = (u64)((ratio_f * link_cfg->tu_size * (f - ratio_f)) / f);
+ link_cfg->watermark = (u32)((u64)((watermark_f + lowest_neg_error_f) /
+ f)) + link_cfg->bits_per_pixel / 4 - 1;
+ num_symbols_per_line = (config->xres * link_cfg->bits_per_pixel) /
+ (8 * link_cfg->lane_count);
+
+ if (link_cfg->watermark > 30) {
+ printk(BIOS_INFO,
+ "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) {
+ printk(BIOS_INFO,
+ "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)((u64)(((u64)(config->hback_porch +
+ config->hfront_porch + config->hsync_width - 7) *
+ link_rate) / config->pixel_clock)) -
+ 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)((u64)((u64)(config->xres - 25)
+ * link_rate / config->pixel_clock)) - (36 /
+ link_cfg->lane_count) - 4;
+
+ if (link_cfg->vblank_sym < 0)
+ link_cfg->vblank_sym = 0;
+
+ link_cfg->is_valid = 1;
+ tegra_dc_dp_dump_link_cfg(dp, link_cfg);
- ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_EDP_CONFIG_CAP, &dpcd_data);
- if (ret)
- return ret;
- cfg->alt_scramber_reset_cap =
- (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES) ? 1 : 0;
- cfg->only_enhanced_framing =
- (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES) ? 1 : 0;
- printk(BIOS_DEBUG, "%s: alt_reset_cap: %d, only_enh_framing: %d\n",
- __func__, cfg->alt_scramber_reset_cap, cfg->only_enhanced_framing);
-
- cfg->lane_count = cfg->max_lane_count;
- cfg->link_bw = NV_SOR_LINK_SPEED_G1_62;
- cfg->enhanced_framing = cfg->support_enhanced_framing;
return 0;
}
-struct tegra_dc_dp_data dp_data;
-
-static int tegra_dc_dpcd_read_rev(struct tegra_dc_dp_data *dp, u8 * rev)
+static int tegra_dc_dp_init_link_cfg(
+ struct soc_nvidia_tegra124_config *config,
+ struct tegra_dc_dp_data *dp,
+ struct tegra_dc_dp_link_config *link_cfg)
{
- u32 size;
+ u8 dpcd_data;
int ret;
- u32 status = 0;
- size = 3;
- ret = tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
- NV_DPCD_REV, rev, &size, &status);
- if (ret) {
- printk(BIOS_WARNING, "dp: Failed to read NV_DPCD_REV\n");
- return ret;
- }
+ link_cfg->max_lane_count = config->lane_count;
+ link_cfg->support_enhanced_framing = config->enhanced_framing;
+ link_cfg->max_link_bw = config->link_bw;
+ link_cfg->drive_current = config->drive_current;
+ link_cfg->preemphasis = config->preemphasis;
+ link_cfg->postcursor = config->postcursor;
+ link_cfg->bits_per_pixel = config->panel_bits_per_pixel;
+
+ CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_EDP_CONFIG_CAP,
+ &dpcd_data));
+ link_cfg->alt_scramber_reset_cap =
+ (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES) ?
+ 1 : 0;
+ link_cfg->only_enhanced_framing =
+ (dpcd_data & NV_DPCD_EDP_CONFIG_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;
+
+ tegra_dc_dp_calc_config(dp, config, link_cfg);
return 0;
}
-u32 dp_setup_timing(u32 width, u32 height);
-void dp_bringup(u32 winb_addr)
+void dp_init(void * _config)
{
+ struct soc_nvidia_tegra124_config *config = (void *)_config;
+ struct tegra_dc *dc = config->dc_data;
struct tegra_dc_dp_data *dp = &dp_data;
- u32 dpcd_rev;
- u32 pclk_freq;
-
- u32 xres = 1366; /* norrin display */
- u32 yres = 768;
+ // set up links among config, dc, dp and sor
+ dp->dc = dc;
+ dc->out = dp;
+ dp->sor.dc = dc;
+ dp->sor.power_is_up = 0;
dp->sor.base = (void *)TEGRA_ARM_SOR;
+ dp->sor.pmc_base = (void *)TEGRA_PMC_BASE;
dp->sor.portnum = 0;
-
+ dp->sor.link_cfg = &dp->link_cfg;
dp->aux_base = (void *)TEGRA_ARM_DPAUX;
+ dp->link_cfg.is_valid = 0;
+ dp->enabled = 0;
+}
- /* read panel info */
- if (!tegra_dc_dpcd_read_rev(dp, (u8 *)&dpcd_rev)) {
- printk(BIOS_INFO, "PANEL info:\n");
- printk(BIOS_INFO, "--DPCP version(%#x): %d.%d\n",
- dpcd_rev, (dpcd_rev >> 4) & 0x0f,
- (dpcd_rev & 0x0f));
- }
-
- if (tegra_dc_dp_init_max_link_cfg(dp, &dp->link_cfg))
- printk(BIOS_ERR, "dp: failed to init link configuration\n");
-
- dp_link_training((u32) (dp->link_cfg.lane_count),
- (u32) (dp->link_cfg.link_bw));
-
- pclk_freq = dp_setup_timing(xres, yres);
- printk(BIOS_DEBUG, "%s: pclk_freq: %d\n", __func__, pclk_freq);
+static void tegra_dp_hpd_config(struct tegra_dc_dp_data *dp,
+ struct soc_nvidia_tegra124_config *config)
+{
+ u32 val;
+ val = config->hpd_plug_min_us |
+ (config->hpd_unplug_min_us <<
+ DPAUX_HPD_CONFIG_UNPLUG_MIN_TIME_SHIFT);
+ tegra_dpaux_writel(dp, DPAUX_HPD_CONFIG, val);
- void dp_misc_setting(u32 panel_bpp, u32 width, u32 height,
- u32 winb_addr, u32 lane_count,
- u32 enhanced_framing, u32 panel_edp,
- u32 pclkfreq, u32 linkfreq);
+ tegra_dpaux_writel(dp, DPAUX_HPD_IRQ_CONFIG, config->hpd_irq_min_us);
+}
- dp_misc_setting(dp->link_cfg.bits_per_pixel,
- xres, yres, winb_addr,
- (u32) dp->link_cfg.lane_count,
- (u32) dp->link_cfg.enhanced_framing,
- (u32) dp->link_cfg.alt_scramber_reset_cap,
- pclk_freq, dp->link_cfg.link_bw * 27);
+static int tegra_dp_hpd_plug(struct tegra_dc_dp_data *dp, int timeout_ms)
+{
+ u32 val;
+ u32 timeout = timeout_ms * 1000;
+ do {
+ val = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+ if (val & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)
+ return 0;
+ udelay(100);
+ timeout -= 100;
+ } while (timeout > 0);
+ return -1;
}
-void debug_dpaux_print(u32 addr, u32 size)
+void dp_enable(void * _dp)
{
- struct tegra_dc_dp_data *dp = &dp_data;
- u32 status = 0;
- u8 buf[16];
- int i;
+ struct tegra_dc_dp_data *dp = _dp;
+ struct tegra_dc *dc = dp->dc;
+ struct soc_nvidia_tegra124_config *config = dc->config;
- if ((size == 0) || (size > 16)) {
- printk(BIOS_ERR, "dp: %s: invalid size %d\n", __func__, size);
- return;
- }
+ u8 data;
+ u32 retry;
+ int ret;
+
+ tegra_dc_dpaux_enable(dp);
- if (tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
- addr, buf, &size, &status)) {
- printk(BIOS_ERR, "******AuxRead Error: 0x%04x: status 0x%08x\n",
- addr, status);
- return;
+ tegra_dp_hpd_config(dp, config);
+ if (tegra_dp_hpd_plug(dp, config->vdd_to_hpd_delay_ms) < 0) {
+ printk(BIOS_ERR, "dp: hpd plug failed\n");
+ goto error_enable;
}
- printk(BIOS_DEBUG, "%s: addr: 0x%04x, size: %d\n", __func__,
- addr, size);
- for (i = 0; i < size; ++i)
- printk(BIOS_DEBUG, " %02x", buf[i]);
- printk(BIOS_DEBUG, "\n");
-}
+ if (tegra_dc_dp_init_link_cfg(config, dp, &dp->link_cfg)) {
+ printk(BIOS_ERR, "dp: failed to init link configuration\n");
+ goto error_enable;
+ }
-int dpaux_read(u32 addr, u32 size, u8 * data)
-{
+ tegra_dc_sor_enable_dp(&dp->sor);
- struct tegra_dc_dp_data *dp = &dp_data;
- u32 status = 0;
+ tegra_dc_sor_set_panel_power(&dp->sor, 1);
- if ((size == 0) || (size > 16)) {
- printk(BIOS_ERR, "dp: %s: invalid size %d\n", __func__, size);
- return -1;
+ /* Write power on to DPCD */
+ data = NV_DPCD_SET_POWER_VAL_D0_NORMAL;
+ retry = 0;
+ do {
+ ret = tegra_dc_dp_dpcd_write(dp,
+ NV_DPCD_SET_POWER, data);
+ } while ((retry++ < DP_POWER_ON_MAX_TRIES) && ret);
+
+ if (ret || retry >= DP_POWER_ON_MAX_TRIES) {
+ printk(BIOS_ERR,
+ "dp: failed to power on panel (0x%x)\n", ret);
+ goto error_enable;
}
- if (tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
- addr, data, &size, &status)) {
- printk(BIOS_ERR, "dp: Failed to read reg %#x, status: %#x\n",
- addr, status);
- return -1;
+ /* Confirm DP is plugging status */
+ if (!(tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT) &
+ DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
+ printk(BIOS_ERR, "dp: could not detect HPD\n");
+ goto error_enable;
}
- return 0;
-}
+ /* Check DP version */
+ if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_REV, &dp->revision))
+ printk(BIOS_ERR,
+ "dp: failed to read the revision number from sink\n");
-int dpaux_write(u32 addr, u32 size, u32 data)
-{
- struct tegra_dc_dp_data *dp = &dp_data;
- u32 status = 0;
- int ret;
+ tegra_dc_sor_set_power_state(&dp->sor, 1);
+ tegra_dc_sor_attach(&dp->sor);
- ret = tegra_dc_dpaux_write(dp, DPAUX_DP_AUXCTL_CMD_AUXWR,
- addr, (u8 *) & data, &size, &status);
- if (ret)
- printk(BIOS_ERR, "dp: Failed to write to reg %#x, status: 0x%x\n",
- addr, status);
- return ret;
+ /*
+ * Power down the unused lanes to save power
+ * (about hundreds milli-watts, varies from boards).
+ */
+ tegra_dc_sor_power_down_unused_lanes(&dp->sor);
+
+ dp->enabled = 1;
+error_enable:
+ return;
}
diff --git a/src/soc/nvidia/tegra124/include/soc/display.h b/src/soc/nvidia/tegra124/include/soc/display.h
index 36348ff0c3..980d2b38db 100644
--- a/src/soc/nvidia/tegra124/include/soc/display.h
+++ b/src/soc/nvidia/tegra124/include/soc/display.h
@@ -17,185 +17,10 @@
#ifndef __SOC_NVIDIA_TEGRA124_INCLUDE_SOC_DISPLAY_H__
#define __SOC_NVIDIA_TEGRA124_INCLUDE_SOC_DISPLAY_H__
-/* ardisplay.h */
-#define DC_CMD_DISPLAY_WINDOW_HEADER_0 0x42
-#define DC_COM_CRC_CONTROL_0 0x300
-#define DC_COM_CRC_CHECKSUM_0 0x301
-#define DC_COM_PIN_OUTPUT_ENABLE0_0 0x302
-#define DC_COM_PIN_OUTPUT_ENABLE1_0 0x303
-#define DC_COM_PIN_OUTPUT_ENABLE2_0 0x304
-#define DC_COM_PIN_OUTPUT_ENABLE3_0 0x305
-#define DC_CMD_STATE_ACCESS_0 0x40
-#define DC_DISP_DISP_CLOCK_CONTROL_0 0x42e
-#define DC_DISP_DISP_TIMING_OPTIONS_0 0x405
-#define DC_DISP_REF_TO_SYNC_0 0x406
-#define DC_DISP_SYNC_WIDTH_0 0x407
-#define DC_DISP_BACK_PORCH_0 0x408
-#define DC_DISP_DISP_ACTIVE_0 0x409
-#define DC_DISP_FRONT_PORCH_0 0x40a
-#define DC_DISP_DISP_WIN_OPTIONS_0 0x402
-#define DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_SHIFT 25
-#define DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_FIELD (0x1 << DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_SHIFT)
-#define DC_DISP_DISP_SIGNAL_OPTIONS0_0 0x400
-#define DC_DISP_BLEND_BACKGROUND_COLOR_0 0x4e4
-#define DC_CMD_DISPLAY_COMMAND_0 0x32
-#define DC_CMD_STATE_CONTROL_0 0x41
-#define DC_CMD_DISPLAY_POWER_CONTROL_0 0x36
-
-/* ardisplay_a.h */
-#define DC_WIN_A_WIN_OPTIONS_0 0x700
-#define DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_SHIFT 30
-#define DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_FIELD (0x1 << DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_SHIFT)
-#define DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_ENABLE (1)
-#define DC_WIN_A_BYTE_SWAP_0 0x701
-#define DC_WIN_A_BUFFER_CONTROL_0 0x702
-#define DC_WIN_A_COLOR_DEPTH_0 0x703
-#define DC_WIN_A_POSITION_0 0x704
-#define DC_WIN_A_SIZE_0 0x705
-#define DC_WIN_A_PRESCALED_SIZE_0 0x706
-#define DC_WIN_A_H_INITIAL_DDA_0 0x707
-#define DC_WIN_A_V_INITIAL_DDA_0 0x708
-#define DC_WIN_A_DDA_INCREMENT_0 0x709
-#define DC_WIN_A_LINE_STRIDE_0 0x70a
-#define DC_WIN_A_DV_CONTROL_0 0x70e
-#define DC_WIN_A_BLEND_LAYER_CONTROL_0 0x716
-#define DC_WIN_A_BLEND_MATCH_SELECT_0 0x717
-#define DC_WIN_A_BLEND_NOMATCH_SELECT_0 0x718
-#define DC_WIN_A_BLEND_ALPHA_1BIT_0 0x719
-#define DC_WINBUF_A_START_ADDR_LO_0 0x800
-#define DC_WINBUF_A_START_ADDR_HI_0 0x80d
-#define DC_WINBUF_A_ADDR_H_OFFSET_0 0x806
-#define DC_WINBUF_A_ADDR_V_OFFSET_0 0x808
-
-/* ardisplay_bd.h */
-#define DC_B_WIN_BD_SIZE_0 0xd85
-#define DC_B_WIN_BD_PRESCALED_SIZE_0 0xd86
-#define DC_B_WIN_BD_LINE_STRIDE_0 0xd8a
-#define DC_B_WIN_BD_COLOR_DEPTH_0 0xd83
-#define DC_B_WINBUF_BD_START_ADDR_0 0xdc0
-#define DC_B_WIN_BD_DDA_INCREMENT_0 0xd89
-#define DC_B_WIN_BD_WIN_OPTIONS_0 0xd80
-#define DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_SHIFT 30
-#define DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_FIELD (0x1 << DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_SHIFT)
-#define DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_ENABLE (1)
-
-/* arsor.h */
-#define SOR_NV_PDISP_SOR_CLK_CNTRL_0 0x13
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0 0x5c
-#define SOR_NV_PDISP_SOR_PLL0_0 0x17
-#define SOR_NV_PDISP_SOR_PLL1_0 0x18
-#define SOR_NV_PDISP_SOR_PLL2_0 0x19
-#define SOR_NV_PDISP_SOR_PLL3_0 0x1a
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX6_SHIFT 22
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX6_FIELD (0x1 << SOR_NV_PDISP_SOR_PLL2_0_AUX6_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL0_0_PWR_SHIFT 0
-#define SOR_NV_PDISP_SOR_PLL0_0_PWR_FIELD (0x1 << SOR_NV_PDISP_SOR_PLL0_0_PWR_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL0_0_VCOPD_SHIFT 2
-#define SOR_NV_PDISP_SOR_PLL0_0_VCOPD_FIELD (0x1 << SOR_NV_PDISP_SOR_PLL0_0_VCOPD_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX8_SHIFT 24
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX8_FIELD (0x1 << SOR_NV_PDISP_SOR_PLL2_0_AUX8_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX7_SHIFT 23
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX7_FIELD (0x1 << SOR_NV_PDISP_SOR_PLL2_0_AUX7_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX9_SHIFT 25
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX9_FIELD (0x1 << SOR_NV_PDISP_SOR_PLL2_0_AUX9_SHIFT)
-#define SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0 0x4e
-#define SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0 0x52
-#define SOR_NV_PDISP_SOR_POSTCURSOR0_0 0x56
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0 0x5c
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_SHIFT 8
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_FIELD (0xff << SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_SHIFT 22
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_FIELD (0x1 << SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_SHIFT)
-#define SOR_NV_PDISP_SOR_LVDS_0 0x1c
-#define SOR_NV_PDISP_SOR_CLK_CNTRL_0 0x13
-#define SOR_NV_PDISP_SOR_DP_LINKCTL0_0 0x4c
-#define SOR_NV_PDISP_SOR_LANE_SEQ_CTL_0 0x21
-#define SOR_NV_PDISP_SOR_DP_TPG_0 0x6d
-#define SOR_NV_PDISP_HEAD_STATE1_0 0x7
-#define SOR_NV_PDISP_HEAD_STATE2_0 0x9
-#define SOR_NV_PDISP_HEAD_STATE3_0 0xb
-#define SOR_NV_PDISP_HEAD_STATE4_0 0xd
-#define SOR_NV_PDISP_SOR_STATE1_0 0x4
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_SHIFT 12
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_FIELD (0x1 << SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_SHIFT 13
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_FIELD (0x1 << SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_SHIFT 8
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_FIELD (0xf << SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_LVDS_CUSTOM (0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_DP_A (8)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_DP_B (9)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_CUSTOM (15)
-
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_ACTIVE_RASTER (0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_COMPLETE_RASTER (1)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_NON_ACTIVE_RASTER (2)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_SHIFT 6
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_FIELD (0x3 << SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SHIFT 4
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_FIELD (0x3 << SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_NONE (0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SUBHEAD0 (1)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SUBHEAD1 (2)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_BOTH (3)
-
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_SHIFT 0
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_FIELD (0xf << SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_NONE (0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_HEAD0 (1)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_HEAD1 (2)
-
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0 0x58
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_SHIFT 24
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_FIELD (0x1 << SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_SHIFT 16
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_FIELD (0xf << SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_SHIFT 8
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_FIELD (0x7f << SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_SHIFT 0
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_FIELD (0x3f << SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_SHIFT 2
-#define SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_FIELD (0x7f << SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_SHIFT 17
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_FIELD (0xf << SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_SHIFT)
-
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_DEFAULTVAL (0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_16_422 (1)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_18_444 (2)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_20_422 (3)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_24_422 (4)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_24_444 (5)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_30_444 (6)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_32_422 (7)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_36_444 (8)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_48_444 (9)
-
-#define SOR_NV_PDISP_SOR_CRC_CNTRL_0 0x11
-#define SOR_NV_PDISP_SOR_DP_AUDIO_VBLANK_SYMBOLS_0 0x64
-#define SOR_NV_PDISP_SOR_DP_SPARE0_0 0x60
-#define SOR_NV_PDISP_SOR_PWR_0 0x15
-#define SOR_NV_PDISP_SOR_STATE0_0 0x3
-#define SOR_NV_PDISP_SOR_SUPER_STATE1_0 0x2
-#define SOR_NV_PDISP_SOR_SUPER_STATE0_0 0x1
-
-/* ardpaux.h */
-#define DPAUX_DP_AUXDATA_READ_W0 0x19
-
-#define DP_LVDS_SHIFT 25
-#define DP_LVDS (1 << DP_LVDS_SHIFT)
-
-#define SRC_BPP 16
-#define COLORDEPTH 0x6
#define COLOR_WHITE 0xFFFFFF
struct soc_nvidia_tegra124_config; /* forward declaration */
void setup_display(struct soc_nvidia_tegra124_config *config);
-void init_dca_regs(void);
-void dp_io_powerup(void);
-u32 dp_setup_timing(u32 width, u32 height);
-void dp_misc_setting(u32 panel_bpp, u32 width, u32 height, u32 winb_addr,
- u32 lane_count, u32 enhanced_framing, u32 panel_edp,
- u32 pclkfreq, u32 linkfreq);
#define FB_SIZE_MB (32)
diff --git a/src/soc/nvidia/tegra124/soc.c b/src/soc/nvidia/tegra124/soc.c
index bc47954790..08a4cf8e13 100644
--- a/src/soc/nvidia/tegra124/soc.c
+++ b/src/soc/nvidia/tegra124/soc.c
@@ -21,8 +21,10 @@
#include <console/console.h>
#include <device/device.h>
+#include <arch/io.h>
#include <soc/nvidia/tegra/dc.h>
#include <soc/nvidia/tegra124/sdram.h>
+#include "chip.h"
#include <soc/display.h>
/* this sucks, but for now, fb size/location are hardcoded.
diff --git a/src/soc/nvidia/tegra124/sor.c b/src/soc/nvidia/tegra124/sor.c
index 6a47833bef..3ff39ed0f2 100644
--- a/src/soc/nvidia/tegra124/sor.c
+++ b/src/soc/nvidia/tegra124/sor.c
@@ -54,17 +54,18 @@
#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF (0 << 25)
#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON (1 << 25)
-
static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg)
{
- u32 reg_val = readl((sor->base + reg * 4));
+ void *addr = sor->base + (u32) (reg << 2);
+ u32 reg_val = READL(addr);
return reg_val;
}
static inline void tegra_sor_writel(struct tegra_dc_sor_data *sor,
u32 reg, u32 val)
{
- writel(val, (sor->base + reg * 4));
+ void *addr = sor->base + (u32) (reg << 2);
+ WRITEL(val, addr);
}
static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor,
@@ -76,8 +77,61 @@ static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor,
tegra_sor_writel(sor, reg, reg_val);
}
+static u32 tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor,
+ u32 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 = tegra_sor_readl(sor, 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 */
+ printk(BIOS_ERR,
+ "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 temp;
+}
+
+int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd)
+{
+ u32 reg_val;
+ u32 orig_val;
+
+ orig_val = tegra_sor_readl(sor, NV_SOR_PWR);
+
+ reg_val = pu_pd ? NV_SOR_PWR_NORMAL_STATE_PU :
+ NV_SOR_PWR_NORMAL_STATE_PD; /* normal state only */
+
+ if (reg_val == orig_val)
+ return 0; /* No update needed */
+
+ reg_val |= NV_SOR_PWR_SETTING_NEW_TRIGGER;
+ tegra_sor_writel(sor, NV_SOR_PWR, reg_val);
+
+ /* Poll to confirm it is done */
+ if (tegra_dc_sor_poll_register(sor, NV_SOR_PWR,
+ NV_SOR_PWR_SETTING_NEW_DEFAULT_MASK,
+ NV_SOR_PWR_SETTING_NEW_DONE,
+ 100, TEGRA_SOR_TIMEOUT_MS * 1000)) {
+ printk(BIOS_ERR,
+ "dc timeout waiting for SOR_PWR = NEW_DONE\n");
+ return -EFAULT;
+ }
+ return 0;
+}
+
void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena,
- u8 training_pattern, const struct tegra_dc_dp_link_config *cfg)
+ u8 training_pattern, const struct tegra_dc_dp_link_config *link_cfg)
{
u32 reg_val;
@@ -89,20 +143,20 @@ void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena,
reg_val &= NV_SOR_DP_LINKCTL_ENABLE_NO;
reg_val &= ~NV_SOR_DP_LINKCTL_TUSIZE_MASK;
- reg_val |= (cfg->tu_size << NV_SOR_DP_LINKCTL_TUSIZE_SHIFT);
+ reg_val |= (link_cfg->tu_size << NV_SOR_DP_LINKCTL_TUSIZE_SHIFT);
- if (cfg->enhanced_framing)
+ if (link_cfg->enhanced_framing)
reg_val |= NV_SOR_DP_LINKCTL_ENHANCEDFRAME_ENABLE;
tegra_sor_writel(sor, NV_SOR_DP_LINKCTL(sor->portnum), reg_val);
switch (training_pattern) {
- case trainingPattern_1:
+ case training_pattern_1:
tegra_sor_writel(sor, NV_SOR_DP_TPG, 0x41414141);
break;
- case trainingPattern_2:
- case trainingPattern_3:
- reg_val = (cfg->link_bw == NV_SOR_LINK_SPEED_G5_4) ?
+ 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, NV_SOR_DP_TPG, reg_val);
break;
@@ -112,58 +166,612 @@ void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena,
}
}
-void tegra_dc_sor_set_dp_lanedata(struct tegra_dc_sor_data *sor,
- u32 lane, u32 pre_emphasis, u32 drive_current, u32 tx_pu)
+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 = NV_SOR_LANE_SEQ_CTL_SETTING_NEW_TRIGGER |
+ NV_SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
+ NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_PU;
+ else
+ reg_val = NV_SOR_LANE_SEQ_CTL_SETTING_NEW_TRIGGER |
+ NV_SOR_LANE_SEQ_CTL_SEQUENCE_UP |
+ NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_PD;
+
+ if (is_lvds)
+ reg_val |= 15 << NV_SOR_LANE_SEQ_CTL_DELAY_SHIFT;
+ else
+ reg_val |= 1 << NV_SOR_LANE_SEQ_CTL_DELAY_SHIFT;
+
+ tegra_sor_writel(sor, NV_SOR_LANE_SEQ_CTL, reg_val);
+
+ if (tegra_dc_sor_poll_register(sor, NV_SOR_LANE_SEQ_CTL,
+ NV_SOR_LANE_SEQ_CTL_SETTING_MASK,
+ NV_SOR_LANE_SEQ_CTL_SETTING_NEW_DONE,
+ 100, TEGRA_SOR_TIMEOUT_MS*1000)) {
+ printk(BIOS_ERR,
+ "dp: timeout while waiting for SOR lane sequencer "
+ "to power down langes\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int tegra_dc_sor_power_dplanes(struct tegra_dc_sor_data *sor,
+ u32 lane_count, int pu)
+{
+ u32 reg_val;
+
+ reg_val = tegra_sor_readl(sor, NV_SOR_DP_PADCTL(sor->portnum));
+
+ if (pu) {
+ switch (lane_count) {
+ case 4:
+ reg_val |= (NV_SOR_DP_PADCTL_PD_TXD_3_NO |
+ NV_SOR_DP_PADCTL_PD_TXD_2_NO);
+ /* fall through */
+ case 2:
+ reg_val |= NV_SOR_DP_PADCTL_PD_TXD_1_NO;
+ case 1:
+ reg_val |= NV_SOR_DP_PADCTL_PD_TXD_0_NO;
+ break;
+ default:
+ printk(BIOS_ERR,
+ "dp: invalid lane number %d\n", lane_count);
+ return -1;
+ }
+
+ tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum), reg_val);
+ tegra_dc_sor_set_lane_count(sor, lane_count);
+ }
+ return tegra_dc_sor_enable_lane_sequencer(sor, pu, 0);
+}
+
+void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor,
+ int power_up)
+{
+ u32 reg_val;
+
+ /* !!TODO: need to enable panel power through GPIO operations */
+ /* Check bug 790854 for HW progress */
+
+ reg_val = tegra_sor_readl(sor, NV_SOR_DP_PADCTL(sor->portnum));
+
+ if (power_up)
+ reg_val |= NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERUP;
+ else
+ reg_val &= ~NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERUP;
+
+ tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum), reg_val);
+}
+
+static void tegra_dc_sor_set_dp_mode(struct tegra_dc_sor_data *sor,
+ const struct tegra_dc_dp_link_config *link_cfg)
+{
+ u32 reg_val;
+
+ tegra_dc_sor_set_link_bandwidth(sor, link_cfg->link_bw);
+
+ tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_none, link_cfg);
+ reg_val = tegra_sor_readl(sor, NV_SOR_DP_CONFIG(sor->portnum));
+ reg_val &= ~NV_SOR_DP_CONFIG_WATERMARK_MASK;
+ reg_val |= link_cfg->watermark;
+ reg_val &= ~NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_MASK;
+ reg_val |= (link_cfg->active_count <<
+ NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_SHIFT);
+ reg_val &= ~NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_MASK;
+ reg_val |= (link_cfg->active_frac <<
+ NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_SHIFT);
+ if (link_cfg->activepolarity)
+ reg_val |= NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
+ else
+ reg_val &= ~NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
+ reg_val |= (NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_ENABLE |
+ NV_SOR_DP_CONFIG_RD_RESET_VAL_NEGATIVE);
+
+ tegra_sor_writel(sor, NV_SOR_DP_CONFIG(sor->portnum), reg_val);
+
+ /* enable CRC */
+ reg_val = NV_SOR_CRC_CNTRL_ARM_CRC_ENABLE_EN <<
+ NV_SOR_CRC_CNTRL_ARM_CRC_ENABLE_SHIFT;
+ tegra_sor_writel(sor, NV_SOR_CRC_CNTRL, reg_val);
+
+ /* program h/vblank sym */
+ tegra_sor_write_field(sor, NV_SOR_DP_AUDIO_HBLANK_SYMBOLS,
+ NV_SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK, link_cfg->hblank_sym);
+
+ tegra_sor_write_field(sor, NV_SOR_DP_AUDIO_VBLANK_SYMBOLS,
+ NV_SOR_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, NV_SOR_SUPER_STATE0, 0);
+ tegra_sor_writel(sor, NV_SOR_SUPER_STATE0, 1);
+ tegra_sor_writel(sor, NV_SOR_SUPER_STATE0, 0);
+}
+
+static inline void tegra_dc_sor_update(struct tegra_dc_sor_data *sor)
+{
+ tegra_sor_writel(sor, NV_SOR_STATE0, 0);
+ tegra_sor_writel(sor, NV_SOR_STATE0, 1);
+ tegra_sor_writel(sor, NV_SOR_STATE0, 0);
+}
+
+static void 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)
+ printk(BIOS_ERR,
+ "PMC_IO_DPD2 polling failed (0x%x)\n", reg_val);
+
+ if (up)
+ WRITEL(APBDEV_PMC_DPD_SAMPLE_ON_DISABLE,
+ pmc_base + APBDEV_PMC_DPD_SAMPLE);
+}
+
+void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int)
{
- u32 d_cur;
- u32 p_emp;
+ u32 reg_val;
+ reg_val = tegra_sor_readl(sor, NV_SOR_DP_SPARE(sor->portnum));
+ if (is_int)
+ reg_val |= NV_SOR_DP_SPARE_PANEL_INTERNAL;
+ else
+ reg_val &= ~NV_SOR_DP_SPARE_PANEL_INTERNAL;
+
+ reg_val |= NV_SOR_DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK |
+ NV_SOR_DP_SPARE_SEQ_ENABLE_YES;
+ tegra_sor_writel(sor, NV_SOR_DP_SPARE(sor->portnum), reg_val);
+}
+
+void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw,
+ u8 *lane_count)
+{
+ u32 reg_val;
+
+ reg_val = tegra_sor_readl(sor, NV_SOR_CLK_CNTRL);
+ *link_bw = (reg_val & NV_SOR_CLK_CNTRL_DP_LINK_SPEED_MASK)
+ >> NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT;
+ reg_val = tegra_sor_readl(sor,
+ NV_SOR_DP_LINKCTL(sor->portnum));
+
+ switch (reg_val & NV_SOR_DP_LINKCTL_LANECOUNT_MASK) {
+ case NV_SOR_DP_LINKCTL_LANECOUNT_ZERO:
+ *lane_count = 0;
+ break;
+ case NV_SOR_DP_LINKCTL_LANECOUNT_ONE:
+ *lane_count = 1;
+ break;
+ case NV_SOR_DP_LINKCTL_LANECOUNT_TWO:
+ *lane_count = 2;
+ break;
+ case NV_SOR_DP_LINKCTL_LANECOUNT_FOUR:
+ *lane_count = 4;
+ break;
+ default:
+ printk(BIOS_ERR, "Unknown lane count\n");
+ }
+}
+
+void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor, u8 link_bw)
+{
+ tegra_sor_write_field(sor, NV_SOR_CLK_CNTRL,
+ NV_SOR_CLK_CNTRL_DP_LINK_SPEED_MASK,
+ link_bw << NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT);
+}
- d_cur = tegra_sor_readl(sor, NV_SOR_DC(sor->portnum));
- p_emp = tegra_sor_readl(sor, NV_SOR_PR(sor->portnum));
+void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count)
+{
+ u32 reg_val;
- switch (lane) {
+ reg_val = tegra_sor_readl(sor, NV_SOR_DP_LINKCTL(sor->portnum));
+ reg_val &= ~NV_SOR_DP_LINKCTL_LANECOUNT_MASK;
+ switch (lane_count) {
case 0:
- p_emp &= ~NV_SOR_PR_LANE2_DP_LANE0_MASK;
- p_emp |= (pre_emphasis <<
- NV_SOR_PR_LANE2_DP_LANE0_SHIFT);
- d_cur &= ~NV_SOR_DC_LANE2_DP_LANE0_MASK;
- d_cur |= (drive_current <<
- NV_SOR_DC_LANE2_DP_LANE0_SHIFT);
break;
case 1:
- p_emp &= ~NV_SOR_PR_LANE1_DP_LANE1_MASK;
- p_emp |= (pre_emphasis <<
- NV_SOR_PR_LANE1_DP_LANE1_SHIFT);
- d_cur &= ~NV_SOR_DC_LANE1_DP_LANE1_MASK;
- d_cur |= (drive_current <<
- NV_SOR_DC_LANE1_DP_LANE1_SHIFT);
+ reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_ONE;
break;
case 2:
- p_emp &= ~NV_SOR_PR_LANE0_DP_LANE2_MASK;
- p_emp |= (pre_emphasis <<
- NV_SOR_PR_LANE0_DP_LANE2_SHIFT);
- d_cur &= ~NV_SOR_DC_LANE0_DP_LANE2_MASK;
- d_cur |= (drive_current <<
- NV_SOR_DC_LANE0_DP_LANE2_SHIFT);
+ reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_TWO;
break;
- case 3:
- p_emp &= ~NV_SOR_PR_LANE3_DP_LANE3_MASK;
- p_emp |= (pre_emphasis <<
- NV_SOR_PR_LANE3_DP_LANE3_SHIFT);
- d_cur &= ~NV_SOR_DC_LANE3_DP_LANE3_MASK;
- d_cur |= (drive_current <<
- NV_SOR_DC_LANE3_DP_LANE3_SHIFT);
+ case 4:
+ reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_FOUR;
break;
default:
- printk(BIOS_SPEW, "dp: sor lane count %d is invalid\n", lane);
+ /* 0 should be handled earlier. */
+ printk(BIOS_ERR, "dp: Invalid lane count %d\n",
+ lane_count);
+ return;
+ }
+ tegra_sor_writel(sor, NV_SOR_DP_LINKCTL(sor->portnum), reg_val);
+}
+
+static void tegra_sor_enable_edp_clock(struct tegra_dc_sor_data *sor)
+{
+ sor_clock_start();
+}
+
+/* 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 void tegra_dc_sor_power_up(struct tegra_dc_sor_data *sor,
+ int is_lvds)
+{
+ if (sor->power_is_up)
+ return;
+
+ /* Set link bw */
+ tegra_dc_sor_set_link_bandwidth(sor,
+ is_lvds ? NV_SOR_CLK_CNTRL_DP_LINK_SPEED_LVDS :
+ NV_SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62);
+
+ /* step 1 */
+ tegra_sor_write_field(sor, NV_SOR_PLL2,
+ NV_SOR_PLL2_AUX7_PORT_POWERDOWN_MASK | /* PDPORT */
+ NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_MASK | /* PDBG */
+ NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, /* PLLCAPD */
+ NV_SOR_PLL2_AUX7_PORT_POWERDOWN_ENABLE |
+ NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE |
+ NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE);
+ tegra_sor_write_field(sor, NV_SOR_PLL0,
+ NV_SOR_PLL0_PWR_MASK | /* PDPLL */
+ NV_SOR_PLL0_VCOPD_MASK, /* PLLVCOPD */
+ NV_SOR_PLL0_PWR_OFF |
+ NV_SOR_PLL0_VCOPD_ASSERT);
+ tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+ NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN, /* PDCAL */
+ NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN);
+
+ /* step 2 */
+ tegra_dc_sor_io_set_dpd(sor, 1);
+ udelay(15);
+
+ /* step 3 */
+ tegra_sor_write_field(sor, NV_SOR_PLL2,
+ NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_MASK,
+ NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE);
+ udelay(25);
+
+ /* step 4 */
+ tegra_sor_write_field(sor, NV_SOR_PLL0,
+ NV_SOR_PLL0_PWR_MASK | /* PDPLL */
+ NV_SOR_PLL0_VCOPD_MASK, /* PLLVCOPD */
+ NV_SOR_PLL0_PWR_ON | NV_SOR_PLL0_VCOPD_RESCIND);
+ tegra_sor_write_field(sor, NV_SOR_PLL2,
+ NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, /* PLLCAPD */
+ NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE);
+ udelay(225);
+
+ /* step 5 */
+ tegra_sor_write_field(sor, NV_SOR_PLL2,
+ NV_SOR_PLL2_AUX7_PORT_POWERDOWN_MASK, /* PDPORT */
+ NV_SOR_PLL2_AUX7_PORT_POWERDOWN_DISABLE);
+
+ sor->power_is_up = 1;
+}
+
+static void tegra_dc_sor_config_panel(struct tegra_dc_sor_data *sor,
+ int is_lvds)
+{
+ const struct tegra_dc *dc = sor->dc;
+ const struct tegra_dc_dp_data *dp = dc->out;
+ const struct tegra_dc_dp_link_config *link_cfg = &dp->link_cfg;
+ const struct soc_nvidia_tegra124_config *config = dc->config;
+
+ const int head_num = 0; // based on kernel dc driver
+ u32 reg_val = NV_SOR_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 ? NV_SOR_STATE1_ASY_PROTOCOL_LVDS_CUSTOM :
+ NV_SOR_STATE1_ASY_PROTOCOL_DP_A;
+ reg_val |= NV_SOR_STATE1_ASY_SUBOWNER_NONE |
+ NV_SOR_STATE1_ASY_CRCMODE_COMPLETE_RASTER;
+
+ reg_val |= NV_SOR_STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE;
+ reg_val |= NV_SOR_STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE;
+ reg_val |= (link_cfg->bits_per_pixel > 18) ?
+ NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_24_444 :
+ NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_18_444;
+
+ tegra_sor_writel(sor, NV_SOR_STATE1, reg_val);
+
+ /* Skipping programming NV_HEAD_STATE0, assuming:
+ interlacing: PROGRESSIVE, dynamic range: VESA, colorspace: RGB */
+
+ vtotal = config->vsync_width + config->vback_porch +
+ config->yres + config->vfront_porch;
+ htotal = config->hsync_width + config->hback_porch +
+ config->xres + config->hfront_porch;
+
+ tegra_sor_writel(sor, NV_HEAD_STATE1(head_num),
+ vtotal << NV_HEAD_STATE1_VTOTAL_SHIFT |
+ htotal << NV_HEAD_STATE1_HTOTAL_SHIFT);
+
+ vsync_end = config->vsync_width - 1;
+ hsync_end = config->hsync_width - 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 + config->vback_porch;
+ hblank_end = hsync_end + config->hback_porch;
+ 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 + config->yres;
+ hblank_start = hblank_end + config->xres;
+ 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, NV_SOR_CSTM,
+ NV_SOR_CSTM_ROTCLK_DEFAULT_MASK |
+ NV_SOR_CSTM_LVDS_EN_ENABLE,
+ 2 << NV_SOR_CSTM_ROTCLK_SHIFT |
+ is_lvds ? NV_SOR_CSTM_LVDS_EN_ENABLE :
+ NV_SOR_CSTM_LVDS_EN_DISABLE);
+}
+
+static void tegra_dc_sor_enable_dc(struct tegra_dc_sor_data *sor)
+{
+ struct tegra_dc *dc = sor->dc;
+ struct display_controller *disp_ctrl = (void *)dc->base;
+
+ 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 */
+ WRITEL(DISP_CTRL_MODE_C_DISPLAY, &disp_ctrl->cmd.disp_cmd);
+ WRITEL(reg_val, &disp_ctrl->cmd.state_access);
+}
+
+void tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor)
+{
+ const struct tegra_dc_dp_link_config *link_cfg = sor->link_cfg;
+
+ tegra_sor_write_field(sor, NV_SOR_CLK_CNTRL,
+ NV_SOR_CLK_CNTRL_DP_CLK_SEL_MASK,
+ NV_SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK);
+
+ tegra_sor_write_field(sor, NV_SOR_PLL2,
+ NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_MASK,
+ NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE);
+ udelay(25);
+
+ tegra_sor_write_field(sor, NV_SOR_PLL3,
+ NV_SOR_PLL3_PLLVDD_MODE_MASK,
+ NV_SOR_PLL3_PLLVDD_MODE_V3_3);
+ tegra_sor_writel(sor, NV_SOR_PLL0,
+ 0xf << NV_SOR_PLL0_ICHPMP_SHFIT |
+ 0x3 << NV_SOR_PLL0_VCOCAP_SHIFT |
+ NV_SOR_PLL0_PLLREG_LEVEL_V45 |
+ NV_SOR_PLL0_RESISTORSEL_EXT |
+ NV_SOR_PLL0_PWR_ON | NV_SOR_PLL0_VCOPD_RESCIND);
+ tegra_sor_write_field(sor, NV_SOR_PLL2,
+ NV_SOR_PLL2_AUX1_SEQ_MASK | NV_SOR_PLL2_AUX9_LVDSEN_OVERRIDE |
+ NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
+ NV_SOR_PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE |
+ NV_SOR_PLL2_AUX9_LVDSEN_OVERRIDE |
+ NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE);
+ tegra_sor_writel(sor, NV_SOR_PLL1,
+ NV_SOR_PLL1_TERM_COMPOUT_HIGH | NV_SOR_PLL1_TMDS_TERM_ENABLE);
+
+ if (tegra_dc_sor_poll_register(sor, NV_SOR_PLL2,
+ NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
+ NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE,
+ 100, TEGRA_SOR_TIMEOUT_MS * 1000)) {
+ printk(BIOS_ERR, "DP failed to lock PLL\n");
+ return;
+ }
+
+ tegra_sor_write_field(sor, NV_SOR_PLL2,
+ NV_SOR_PLL2_AUX2_MASK | NV_SOR_PLL2_AUX7_PORT_POWERDOWN_MASK,
+ NV_SOR_PLL2_AUX2_OVERRIDE_POWERDOWN |
+ NV_SOR_PLL2_AUX7_PORT_POWERDOWN_DISABLE);
+
+ tegra_dc_sor_power_up(sor, 0);
+
+ /* re-enable SOR clock */
+ tegra_sor_enable_edp_clock(sor); // select pll_dp as clock source
+
+ /* Power up lanes */
+ tegra_dc_sor_power_dplanes(sor, link_cfg->lane_count, 1);
+
+ tegra_dc_sor_set_dp_mode(sor, link_cfg);
+
+}
+
+void tegra_dc_sor_attach(struct tegra_dc_sor_data *sor)
+{
+
+ u32 reg_val;
+ struct display_controller *disp_ctrl = (void *)sor->dc->base;
+
+ tegra_dc_sor_enable_dc(sor);
+ tegra_dc_sor_config_panel(sor, 0);
+
+ WRITEL(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt);
+
+ reg_val = tegra_sor_readl(sor, NV_SOR_TEST);
+ if (reg_val & NV_SOR_TEST_ATTACHED_TRUE) {
+ printk(BIOS_INFO, "sor: Attached\n");
+ return;
+ }
+
+ /* Attach head */
+ tegra_dc_sor_update(sor);
+ reg_val = NV_SOR_SUPER_STATE1_ASY_HEAD_OP_AWAKE |
+ NV_SOR_SUPER_STATE1_ASY_ORMODE_NORMAL |
+ NV_SOR_SUPER_STATE1_ATTACHED_NO;
+ tegra_sor_writel(sor, NV_SOR_SUPER_STATE1, reg_val);
+ tegra_dc_sor_super_update(sor);
+
+ reg_val |= NV_SOR_SUPER_STATE1_ATTACHED_YES;
+ tegra_sor_writel(sor, NV_SOR_SUPER_STATE1, reg_val);
+ tegra_dc_sor_super_update(sor);
+
+ if (tegra_dc_sor_poll_register(sor, NV_SOR_TEST,
+ NV_SOR_TEST_ATTACHED_DEFAULT_MASK,
+ NV_SOR_TEST_ATTACHED_TRUE,
+ 100, TEGRA_SOR_ATTACH_TIMEOUT_MS * 1000)) {
+ printk(BIOS_ERR,
+ "dc timeout waiting for ATTACHED = TRUE\n");
+ }
+
+ /* Enable dc after attaching head */
+ 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);
+
+ if (tegra_dc_sor_poll_register(sor, NV_SOR_TEST,
+ NV_SOR_TEST_ACT_HEAD_OPMODE_DEFAULT_MASK,
+ NV_SOR_TEST_ACT_HEAD_OPMODE_AWAKE,
+ 100, TEGRA_SOR_ATTACH_TIMEOUT_MS * 1000)) {
+ printk(BIOS_ERR,
+ "dc timeout waiting for OPMOD = AWAKE\n");
}
+}
+
+void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor,
+ const struct tegra_dc_dp_link_config *link_cfg)
+{
+ tegra_sor_writel(sor, NV_SOR_LANE_DRIVE_CURRENT(sor->portnum),
+ link_cfg->drive_current);
+ tegra_sor_writel(sor, NV_SOR_PR(sor->portnum),
+ link_cfg->preemphasis);
+ tegra_sor_writel(sor, NV_SOR_POSTCURSOR(sor->portnum),
+ link_cfg->postcursor);
+ tegra_sor_writel(sor, NV_SOR_LVDS, 0);
- tegra_sor_write_field(sor, NV_SOR_DP_LINKCTL(sor->portnum),
+ tegra_dc_sor_set_link_bandwidth(sor, link_cfg->link_bw);
+ tegra_dc_sor_set_lane_count(sor, link_cfg->lane_count);
+
+ tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+ NV_SOR_DP_PADCTL_TX_PU_ENABLE |
NV_SOR_DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK,
- tx_pu << NV_SOR_DP_PADCTL_TX_PU_VALUE_SHIFT);
+ NV_SOR_DP_PADCTL_TX_PU_ENABLE |
+ 2 << NV_SOR_DP_PADCTL_TX_PU_VALUE_SHIFT);
+
+ /* Precharge */
+ tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+ 0xf0, 0xf0);
+ udelay(20);
- tegra_sor_writel(sor, NV_SOR_DC(sor->portnum), d_cur);
- tegra_sor_writel(sor, NV_SOR_PR(sor->portnum), p_emp);
+ tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+ 0xf0, 0x0);
}
+void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor)
+{
+ u32 pad_ctrl = 0;
+ u32 drive_current = 0;
+ u32 pre_emphasis = 0;
+ int err = 0;
+
+ switch (sor->link_cfg->lane_count) {
+ case 4:
+ pad_ctrl = (NV_SOR_DP_PADCTL_PD_TXD_0_NO |
+ NV_SOR_DP_PADCTL_PD_TXD_1_NO |
+ NV_SOR_DP_PADCTL_PD_TXD_2_NO |
+ NV_SOR_DP_PADCTL_PD_TXD_3_NO);
+ break;
+ case 2:
+ pad_ctrl = (NV_SOR_DP_PADCTL_PD_TXD_0_NO |
+ NV_SOR_DP_PADCTL_PD_TXD_1_NO |
+ NV_SOR_DP_PADCTL_PD_TXD_2_YES |
+ NV_SOR_DP_PADCTL_PD_TXD_3_YES);
+ break;
+ case 1:
+ pad_ctrl = (NV_SOR_DP_PADCTL_PD_TXD_0_NO |
+ NV_SOR_DP_PADCTL_PD_TXD_1_YES |
+ NV_SOR_DP_PADCTL_PD_TXD_2_YES |
+ NV_SOR_DP_PADCTL_PD_TXD_3_YES);
+ break;
+ default:
+ printk(BIOS_ERR, "Invalid sor lane count: %u\n",
+ sor->link_cfg->lane_count);
+ return;
+ }
+
+ pad_ctrl |= NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN;
+ tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum), pad_ctrl);
+
+ err = tegra_dc_sor_enable_lane_sequencer(sor, 0, 0);
+ if (err) {
+ printk(BIOS_ERR,
+ "Wait for lane power down failed: %d\n", err);
+ return;
+ }
+
+ /* Set to a known-good pre-calibrated setting */
+ switch (sor->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:
+ drive_current = 0x19191919;
+ pre_emphasis = 0x09090909;
+ default:
+ printk(BIOS_ERR, "Invalid sor link bandwidth: %d\n",
+ sor->link_cfg->link_bw);
+ return;
+ }
+
+ tegra_sor_writel(sor, NV_SOR_LANE_DRIVE_CURRENT(sor->portnum),
+ drive_current);
+ tegra_sor_writel(sor, NV_SOR_PR(sor->portnum), pre_emphasis);
+}
diff --git a/src/soc/nvidia/tegra124/sor.h b/src/soc/nvidia/tegra124/sor.h
index 1f885eaa17..bf6286871e 100644
--- a/src/soc/nvidia/tegra124/sor.h
+++ b/src/soc/nvidia/tegra124/sor.h
@@ -17,7 +17,6 @@
#ifndef __TEGRA124_SOR_H__
#define __TEGRA124_SOR_H__
-
#define NV_SOR_SUPER_STATE0 (0x1)
#define NV_SOR_SUPER_STATE0_UPDATE_SHIFT (0)
#define NV_SOR_SUPER_STATE0_UPDATE_DEFAULT_MASK (0x1)
@@ -830,11 +829,11 @@
#define NV_SOR_DP_TPG_LANE0_PATTERN_HBR2_COMPLIANCE (8)
enum {
- trainingPattern_Disabled = 0,
- trainingPattern_1 = 1,
- trainingPattern_2 = 2,
- trainingPattern_3 = 3,
- trainingPattern_None = 0xff
+ 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 {
@@ -842,10 +841,10 @@ enum tegra_dc_sor_protocol {
SOR_LVDS,
};
-#define NV_SOR_LINK_SPEED_G1_62 6
-#define NV_SOR_LINK_SPEED_G2_7 10
-#define NV_SOR_LINK_SPEED_G5_4 20
-#define NV_SOR_LINK_SPEED_LVDS 7
+#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
/* todo: combine this and the intel_dp struct into one struct. */
struct tegra_dc_dp_link_config {
@@ -885,21 +884,37 @@ struct tegra_dc_dp_link_config {
* having two channels.
*/
struct tegra_dc_sor_data {
- void *base;
- u8 portnum; /* 0 or 1 */
+ struct tegra_dc *dc;
+ void *base;
+ void *pmc_base;
+ u8 portnum; /* 0 or 1 */
+ struct tegra_dc_dp_link_config *link_cfg;
int power_is_up;
};
#define TEGRA_SOR_TIMEOUT_MS 1000
#define TEGRA_SOR_ATTACH_TIMEOUT_MS 100000
-void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor,
- int ena,
- u8 training_pattern,
- const struct tegra_dc_dp_link_config *cfg);
-void tegra_dc_sor_set_dp_lanedata(struct tegra_dc_sor_data *sor,
- u32 lane, u32 pre_emphasis,
- u32 drive_current, u32 tx_pu);
-
+#define CHECK_RET(x) \
+ do { \
+ ret = (x); \
+ if (ret != 0) \
+ return ret; \
+ } while (0)
+void tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor);
+int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd);
+void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena,
+ u8 training_pattern, const struct tegra_dc_dp_link_config *link_cfg);
+void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor, u8 link_bw);
+void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count);
+void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor,
+ int power_up);
+void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int);
+void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw,
+ u8 *lane_count);
+void tegra_dc_sor_attach(struct tegra_dc_sor_data *sor);
+void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor,
+ const struct tegra_dc_dp_link_config *link_cfg);
+void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor);
#endif /*__TEGRA124_SOR_H__ */