diff options
author | Tom Rini <trini@konsulko.com> | 2016-02-19 14:25:09 (GMT) |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2016-02-19 14:25:09 (GMT) |
commit | cf432dd5953e9ddf06759565c80fed470882da6d (patch) | |
tree | f0b5ee32047f37eb87e6e5ba537a50fb0babc1cb /drivers | |
parent | a8c3eca43393cffef16a40e683f7a4d45b37e6ed (diff) | |
parent | 5589bc2770a7d7fe346f5972596f26d1ddf57bba (diff) | |
download | u-boot-cf432dd5953e9ddf06759565c80fed470882da6d.tar.xz |
Merge branch 'master' of git://git.denx.de/u-boot-tegra
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/tegra_gpio.c | 5 | ||||
-rw-r--r-- | drivers/input/tegra-kbc.c | 2 | ||||
-rw-r--r-- | drivers/mmc/tegra_mmc.c | 4 | ||||
-rw-r--r-- | drivers/pwm/Kconfig | 9 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 3 | ||||
-rw-r--r-- | drivers/pwm/tegra_pwm.c | 85 | ||||
-rw-r--r-- | drivers/video/Kconfig | 10 | ||||
-rw-r--r-- | drivers/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/simple_panel.c | 1 | ||||
-rw-r--r-- | drivers/video/tegra.c | 658 | ||||
-rw-r--r-- | drivers/video/tegra124/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/tegra124/display.c | 184 | ||||
-rw-r--r-- | drivers/video/tegra124/dp.c | 53 | ||||
-rw-r--r-- | drivers/video/tegra124/sor.c | 162 | ||||
-rw-r--r-- | drivers/video/tegra124/sor.h | 45 | ||||
-rw-r--r-- | drivers/video/tegra124/tegra124-lcd.c | 95 | ||||
-rw-r--r-- | drivers/video/vidconsole-uclass.c | 1 |
17 files changed, 908 insertions, 412 deletions
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 8e880e2..5a03115 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -177,7 +177,10 @@ static int tegra_gpio_get_value(struct udevice *dev, unsigned offset) debug("%s: pin = %d (port %d:bit %d)\n", __func__, gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); - val = readl(&state->bank->gpio_in[GPIO_PORT(gpio)]); + if (get_direction(gpio) == DIRECTION_INPUT) + val = readl(&state->bank->gpio_in[GPIO_PORT(gpio)]); + else + val = readl(&state->bank->gpio_out[GPIO_PORT(gpio)]); return (val >> GPIO_BIT(gpio)) & 1; } diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c index 951cbb4..c77f610 100644 --- a/drivers/input/tegra-kbc.c +++ b/drivers/input/tegra-kbc.c @@ -312,6 +312,7 @@ static int tegra_kbd_probe(struct udevice *dev) __func__, ret); return ret; } + input_add_tables(input, false); if (priv->matrix.fn_keycode) { ret = input_add_table(input, KEY_FN, -1, priv->matrix.fn_keycode, @@ -326,7 +327,6 @@ static int tegra_kbd_probe(struct udevice *dev) priv->input = input; input->dev = dev; input->read_keys = tegra_kbc_check; - input_add_tables(input, false); strcpy(sdev->name, "tegra-kbc"); ret = input_stdio_register(sdev); if (ret) { diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index 1584865..573819a 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -674,7 +674,7 @@ void tegra_mmc_init(void) CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of Tegra210 sdhci nodes is %d\n", __func__, count); if (process_nodes(blob, node_list, count)) { - printf("%s: Error processing T30 mmc node(s)!\n", __func__); + printf("%s: Error processing T210 mmc node(s)!\n", __func__); return; } @@ -684,7 +684,7 @@ void tegra_mmc_init(void) CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of Tegra124 sdhci nodes is %d\n", __func__, count); if (process_nodes(blob, node_list, count)) { - printf("%s: Error processing T30 mmc node(s)!\n", __func__); + printf("%s: Error processing T124 mmc node(s)!\n", __func__); return; } diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index cd8f357..6f0d61e 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -17,3 +17,12 @@ config PWM_ROCKCHIP programmable period and duty cycle. A 32-bit counter is used. Various options provided in the hardware (such as capture mode and continuous/single-shot) are not supported by the driver. + +config PWM_TEGRA + bool "Enable support for the Tegra PWM" + depends on DM_PWM + help + This PWM is found on Tegra 20 and other Nvidia SoCs. It supports + four channels with a programmable period and duty cycle. Only a + 32KHz clock is supported by the driver but the duty cycle is + configurable. diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index b6d8c16..fd414b1 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_DM_PWM) += pwm-uclass.o obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o +ifdef CONFIG_DM_PWM +obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o +endif diff --git a/drivers/pwm/tegra_pwm.c b/drivers/pwm/tegra_pwm.c new file mode 100644 index 0000000..10e1fdc --- /dev/null +++ b/drivers/pwm/tegra_pwm.c @@ -0,0 +1,85 @@ +/* + * Copyright 2016 Google Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <pwm.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/pwm.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct tegra_pwm_priv { + struct pwm_ctlr *regs; +}; + +static int tegra_pwm_set_config(struct udevice *dev, uint channel, + uint period_ns, uint duty_ns) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + struct pwm_ctlr *regs = priv->regs; + uint pulse_width; + u32 reg; + + if (channel >= 4) + return -EINVAL; + debug("%s: Configure '%s' channel %u\n", __func__, dev->name, channel); + /* We ignore the period here and just use 32KHz */ + clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, 32768); + + pulse_width = duty_ns * 255 / period_ns; + + reg = pulse_width << PWM_WIDTH_SHIFT; + reg |= 1 << PWM_DIVIDER_SHIFT; + writel(reg, ®s[channel].control); + debug("%s: pulse_width=%u\n", __func__, pulse_width); + + return 0; +} + +static int tegra_pwm_set_enable(struct udevice *dev, uint channel, bool enable) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + struct pwm_ctlr *regs = priv->regs; + + if (channel >= 4) + return -EINVAL; + debug("%s: Enable '%s' channel %u\n", __func__, dev->name, channel); + clrsetbits_le32(®s[channel].control, PWM_ENABLE_MASK, + enable ? PWM_ENABLE_MASK : 0); + + return 0; +} + +static int tegra_pwm_ofdata_to_platdata(struct udevice *dev) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + + priv->regs = (struct pwm_ctlr *)dev_get_addr(dev); + + return 0; +} + +static const struct pwm_ops tegra_pwm_ops = { + .set_config = tegra_pwm_set_config, + .set_enable = tegra_pwm_set_enable, +}; + +static const struct udevice_id tegra_pwm_ids[] = { + { .compatible = "nvidia,tegra124-pwm" }, + { .compatible = "nvidia,tegra20-pwm" }, + { } +}; + +U_BOOT_DRIVER(tegra_pwm) = { + .name = "tegra_pwm", + .id = UCLASS_PWM, + .of_match = tegra_pwm_ids, + .ops = &tegra_pwm_ops, + .ofdata_to_platdata = tegra_pwm_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct tegra_pwm_priv), +}; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 19f9429..ff4179f 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -381,8 +381,18 @@ config VIDEO_SANDBOX_SDL console device and can display stdout output. Within U-Boot is is a normal bitmap display and can display images as well as text. +config VIDEO_TEGRA20 + bool "Enable LCD support on Tegra20" + depends on OF_CONTROL + help + Tegra20 supports video output to an attached LCD panel as well as + other options such as HDMI. Only the LCD is supported in U-Boot. + This option enables this support which can be used on devices which + have an LCD display connected. + config VIDEO_TEGRA124 bool "Enable video support on Tegra124" + depends on DM_VIDEO help Tegra124 supports many video output options including eDP and HDMI. At present only eDP is supported by U-Boot. This option diff --git a/drivers/video/Makefile b/drivers/video/Makefile index c55e6ed..d19a1d9 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -57,7 +57,7 @@ obj-$(CONFIG_VIDEO_SED13806) += sed13806.o obj-$(CONFIG_VIDEO_SM501) += sm501.o obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o videomodes.o -obj-$(CONFIG_VIDEO_TEGRA) += tegra.o +obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o obj-$(CONFIG_VIDEO_VESA) += vesa_fb.o obj-$(CONFIG_FORMIKE) += formike.o diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c index b161517..c73f242 100644 --- a/drivers/video/simple_panel.c +++ b/drivers/video/simple_panel.c @@ -85,6 +85,7 @@ static const struct panel_ops simple_panel_ops = { static const struct udevice_id simple_panel_ids[] = { { .compatible = "simple-panel" }, + { .compatible = "auo,b133xtn01" }, { } }; diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c index 8e81346..7fd10e6 100644 --- a/drivers/video/tegra.c +++ b/drivers/video/tegra.c @@ -4,11 +4,13 @@ */ #include <common.h> +#include <dm.h> #include <fdtdec.h> -#include <lcd.h> - +#include <pwm.h> +#include <video.h> #include <asm/system.h> #include <asm/gpio.h> +#include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> @@ -30,165 +32,347 @@ enum stage_t { STAGE_DONE, }; -static enum stage_t stage; /* Current stage we are at */ -static unsigned long timer_next; /* Time we can move onto next stage */ +#define FDT_LCD_TIMINGS 4 + +enum { + FDT_LCD_TIMING_REF_TO_SYNC, + FDT_LCD_TIMING_SYNC_WIDTH, + FDT_LCD_TIMING_BACK_PORCH, + FDT_LCD_TIMING_FRONT_PORCH, + + FDT_LCD_TIMING_COUNT, +}; + +enum lcd_cache_t { + FDT_LCD_CACHE_OFF = 0, + FDT_LCD_CACHE_WRITE_THROUGH = 1 << 0, + FDT_LCD_CACHE_WRITE_BACK = 1 << 1, + FDT_LCD_CACHE_FLUSH = 1 << 2, + FDT_LCD_CACHE_WRITE_BACK_FLUSH = FDT_LCD_CACHE_WRITE_BACK | + FDT_LCD_CACHE_FLUSH, +}; + +/* Information about the display controller */ +struct tegra_lcd_priv { + enum stage_t stage; /* Current stage we are at */ + unsigned long timer_next; /* Time we can move onto next stage */ + int width; /* width in pixels */ + int height; /* height in pixels */ -/* Our LCD config, set up in handle_stage() */ -static struct fdt_panel_config config; -struct fdt_disp_config *disp_config; /* Display controller config */ + /* + * log2 of number of bpp, in general, unless it bpp is 24 in which + * case this field holds 24 also! This is a U-Boot thing. + */ + int log2_bpp; + struct disp_ctlr *disp; /* Display controller to use */ + fdt_addr_t frame_buffer; /* Address of frame buffer */ + unsigned pixel_clock; /* Pixel clock in Hz */ + uint horiz_timing[FDT_LCD_TIMING_COUNT]; /* Horizontal timing */ + uint vert_timing[FDT_LCD_TIMING_COUNT]; /* Vertical timing */ + struct udevice *pwm; + int pwm_channel; /* PWM channel to use for backlight */ + enum lcd_cache_t cache_type; + + struct gpio_desc backlight_en; /* GPIO for backlight enable */ + struct gpio_desc lvds_shutdown; /* GPIO for lvds shutdown */ + struct gpio_desc backlight_vdd; /* GPIO for backlight vdd */ + struct gpio_desc panel_vdd; /* GPIO for panel vdd */ + /* + * Panel required timings + * Timing 1: delay between panel_vdd-rise and data-rise + * Timing 2: delay between data-rise and backlight_vdd-rise + * Timing 3: delay between backlight_vdd and pwm-rise + * Timing 4: delay between pwm-rise and backlight_en-rise + */ + uint panel_timings[FDT_LCD_TIMINGS]; +}; enum { /* Maximum LCD size we support */ LCD_MAX_WIDTH = 1366, LCD_MAX_HEIGHT = 768, - LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ + LCD_MAX_LOG2_BPP = VIDEO_BPP16, }; -vidinfo_t panel_info = { - /* Insert a value here so that we don't end up in the BSS */ - .vl_col = -1, -}; +static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win) +{ + unsigned h_dda, v_dda; + unsigned long val; -#if !CONFIG_IS_ENABLED(OF_CONTROL) -#error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support" -#endif + val = readl(&dc->cmd.disp_win_header); + val |= WINDOW_A_SELECT; + writel(val, &dc->cmd.disp_win_header); -static void update_panel_size(struct fdt_disp_config *config) -{ - panel_info.vl_col = config->width; - panel_info.vl_row = config->height; - panel_info.vl_bpix = config->log2_bpp; + writel(win->fmt, &dc->win.color_depth); + + clrsetbits_le32(&dc->win.byte_swap, BYTE_SWAP_MASK, + BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT); + + val = win->out_x << H_POSITION_SHIFT; + val |= win->out_y << V_POSITION_SHIFT; + writel(val, &dc->win.pos); + + val = win->out_w << H_SIZE_SHIFT; + val |= win->out_h << V_SIZE_SHIFT; + writel(val, &dc->win.size); + + val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT; + val |= win->h << V_PRESCALED_SIZE_SHIFT; + writel(val, &dc->win.prescaled_size); + + writel(0, &dc->win.h_initial_dda); + writel(0, &dc->win.v_initial_dda); + + h_dda = (win->w * 0x1000) / max(win->out_w - 1, 1U); + v_dda = (win->h * 0x1000) / max(win->out_h - 1, 1U); + + 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); + + writel((unsigned long)win->phys_addr, &dc->winbuf.start_addr); + writel(win->x, &dc->winbuf.addr_h_offset); + writel(win->y, &dc->winbuf.addr_v_offset); + + writel(0xff00, &dc->win.blend_nokey); + writel(0xff00, &dc->win.blend_1win); + + val = GENERAL_ACT_REQ | WIN_A_ACT_REQ; + val |= GENERAL_UPDATE | WIN_A_UPDATE; + writel(val, &dc->cmd.state_ctrl); } -/* - * Main init function called by lcd driver. - * Inits and then prints test pattern if required. - */ +static void write_pair(struct tegra_lcd_priv *priv, int item, u32 *reg) +{ + writel(priv->horiz_timing[item] | + (priv->vert_timing[item] << 16), reg); +} -void lcd_ctrl_init(void *lcdbase) +static int update_display_mode(struct dc_disp_reg *disp, + struct tegra_lcd_priv *priv) { - int type = DCACHE_OFF; - int size; + unsigned long val; + unsigned long rate; + unsigned long div; - assert(disp_config); + writel(0x0, &disp->disp_timing_opt); + write_pair(priv, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync); + write_pair(priv, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width); + write_pair(priv, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch); + write_pair(priv, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch); - /* Make sure that we can acommodate the selected LCD */ - assert(disp_config->width <= LCD_MAX_WIDTH); - assert(disp_config->height <= LCD_MAX_HEIGHT); - assert(disp_config->log2_bpp <= LCD_MAX_LOG2_BPP); - if (disp_config->width <= LCD_MAX_WIDTH - && disp_config->height <= LCD_MAX_HEIGHT - && disp_config->log2_bpp <= LCD_MAX_LOG2_BPP) - update_panel_size(disp_config); - size = lcd_get_size(&lcd_line_length); + writel(priv->width | (priv->height << 16), &disp->disp_active); - /* Set up the LCD caching as requested */ - if (config.cache_type & FDT_LCD_CACHE_WRITE_THROUGH) - type = DCACHE_WRITETHROUGH; - else if (config.cache_type & FDT_LCD_CACHE_WRITE_BACK) - type = DCACHE_WRITEBACK; - mmu_set_region_dcache_behaviour(disp_config->frame_buffer, size, type); + val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT; + val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT; + writel(val, &disp->data_enable_opt); - /* Enable flushing after LCD writes if requested */ - lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH); + 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); + + /* + * 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. + */ + rate = clock_get_periph_rate(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL); + div = ((rate * 2 + priv->pixel_clock / 2) / priv->pixel_clock) - 2; + debug("Display clock %lu, divider %lu\n", rate, div); + + writel(0x00010001, &disp->shift_clk_opt); - debug("LCD frame buffer at %pa\n", &disp_config->frame_buffer); + val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT; + val |= div << SHIFT_CLK_DIVIDER_SHIFT; + writel(val, &disp->disp_clk_ctrl); + + return 0; } -ulong calc_fbsize(void) +/* Start up the display and turn on power to PWMs */ +static void basic_init(struct dc_cmd_reg *cmd) { - return (panel_info.vl_col * panel_info.vl_row * - NBITS(panel_info.vl_bpix)) / 8; + u32 val; + + writel(0x00000100, &cmd->gen_incr_syncpt_ctrl); + writel(0x0000011a, &cmd->cont_syncpt_vsync); + writel(0x00000000, &cmd->int_type); + writel(0x00000000, &cmd->int_polarity); + writel(0x00000000, &cmd->int_mask); + writel(0x00000000, &cmd->int_enb); + + val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE; + val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE; + val |= PM1_ENABLE; + writel(val, &cmd->disp_pow_ctrl); + + val = readl(&cmd->disp_cmd); + val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT; + writel(val, &cmd->disp_cmd); } -void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +static void basic_init_timer(struct dc_disp_reg *disp) { + writel(0x00000020, &disp->mem_high_pri); + writel(0x00000001, &disp->mem_high_pri_timer); } -void tegra_lcd_early_init(const void *blob) +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 void rgb_enable(struct dc_com_reg *com) { - /* - * Go with the maximum size for now. We will fix this up after - * relocation. These values are only used for memory alocation. - */ - panel_info.vl_col = LCD_MAX_WIDTH; - panel_info.vl_row = LCD_MAX_HEIGHT; - panel_info.vl_bpix = LCD_MAX_LOG2_BPP; + int i; + + for (i = 0; i < PIN_REG_COUNT; i++) { + writel(rgb_enb_tab[i], &com->pin_output_enb[i]); + writel(rgb_polarity_tab[i], &com->pin_output_polarity[i]); + writel(rgb_data_tab[i], &com->pin_output_data[i]); + } + + for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++) + writel(rgb_sel_tab[i], &com->pin_output_sel[i]); +} + +static int setup_window(struct disp_ctl_win *win, + struct tegra_lcd_priv *priv) +{ + win->x = 0; + win->y = 0; + win->w = priv->width; + win->h = priv->height; + win->out_x = 0; + win->out_y = 0; + win->out_w = priv->width; + win->out_h = priv->height; + win->phys_addr = priv->frame_buffer; + win->stride = priv->width * (1 << priv->log2_bpp) / 8; + debug("%s: depth = %d\n", __func__, priv->log2_bpp); + switch (priv->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: + debug("Unsupported LCD bit depth"); + return -1; + } + + return 0; +} + +static void debug_timing(const char *name, unsigned int timing[]) +{ +#ifdef DEBUG + int i; + + debug("%s timing: ", name); + for (i = 0; i < FDT_LCD_TIMING_COUNT; i++) + debug("%d ", timing[i]); + debug("\n"); +#endif } /** - * Decode the panel information from the fdt. + * Register a new display based on device tree configuration. * - * @param blob fdt blob - * @param config structure to store fdt config into - * @return 0 if ok, -ve on error + * The frame buffer can be positioned by U-Boot or overriden by the fdt. + * You should pass in the U-Boot address here, and check the contents of + * struct tegra_lcd_priv to see what was actually chosen. + * + * @param blob Device tree blob + * @param priv Driver's private data + * @param default_lcd_base Default address of LCD frame buffer + * @return 0 if ok, -1 on error (unsupported bits per pixel) */ -static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config) +static int tegra_display_probe(const void *blob, struct tegra_lcd_priv *priv, + void *default_lcd_base) { - int display_node; + struct disp_ctl_win window; + struct dc_ctlr *dc; - disp_config = tegra_display_get_config(); - if (!disp_config) { - debug("%s: Display controller is not configured\n", __func__); - return -1; - } - display_node = disp_config->panel_node; - if (display_node < 0) { - debug("%s: No panel configuration available\n", __func__); - return -1; - } + priv->frame_buffer = (u32)default_lcd_base; - config->pwm_channel = pwm_request(blob, display_node, "nvidia,pwm"); - if (config->pwm_channel < 0) { - debug("%s: Unable to request PWM channel\n", __func__); - return -1; - } + dc = (struct dc_ctlr *)priv->disp; - config->cache_type = fdtdec_get_int(blob, display_node, - "nvidia,cache-type", - FDT_LCD_CACHE_WRITE_BACK_FLUSH); + /* + * A header file for clock constants was NAKed upstream. + * TODO: Put this into the FDT and fdt_lcd struct when we have clock + * support there + */ + clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, + 144 * 1000000); + clock_start_periph_pll(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL, + 600 * 1000000); + basic_init(&dc->cmd); + basic_init_timer(&dc->disp); + rgb_enable(&dc->com); + + if (priv->pixel_clock) + update_display_mode(&dc->disp, priv); + + if (setup_window(&window, priv)) + return -1; - /* These GPIOs are all optional */ - gpio_request_by_name_nodev(blob, display_node, - "nvidia,backlight-enable-gpios", 0, - &config->backlight_en, GPIOD_IS_OUT); - gpio_request_by_name_nodev(blob, display_node, - "nvidia,lvds-shutdown-gpios", 0, - &config->lvds_shutdown, GPIOD_IS_OUT); - gpio_request_by_name_nodev(blob, display_node, - "nvidia,backlight-vdd-gpios", 0, - &config->backlight_vdd, GPIOD_IS_OUT); - gpio_request_by_name_nodev(blob, display_node, - "nvidia,panel-vdd-gpios", 0, - &config->panel_vdd, GPIOD_IS_OUT); + update_window(dc, &window); - return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings", - config->panel_timings, FDT_LCD_TIMINGS); + return 0; } /** * Handle the next stage of device init */ -static int handle_stage(const void *blob) +static int handle_stage(const void *blob, struct tegra_lcd_priv *priv) { - debug("%s: stage %d\n", __func__, stage); + debug("%s: stage %d\n", __func__, priv->stage); /* do the things for this stage */ - switch (stage) { + switch (priv->stage) { case STAGE_START: - /* Initialize the Tegra display controller */ - if (tegra_display_probe(gd->fdt_blob, (void *)gd->fb_base)) { - printf("%s: Failed to probe display driver\n", - __func__); - return -1; - } - - /* get panel details */ - if (fdt_decode_lcd(blob, &config)) { - printf("No valid LCD information in device tree\n"); - return -1; - } - /* * It is possible that the FDT has requested that the LCD be * disabled. We currently don't support this. It would require @@ -202,52 +386,71 @@ static int handle_stage(const void *blob) funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT); break; case STAGE_PANEL_VDD: - if (dm_gpio_is_valid(&config.panel_vdd)) - dm_gpio_set_value(&config.panel_vdd, 1); + if (dm_gpio_is_valid(&priv->panel_vdd)) + dm_gpio_set_value(&priv->panel_vdd, 1); break; case STAGE_LVDS: - if (dm_gpio_is_valid(&config.lvds_shutdown)) - dm_gpio_set_value(&config.lvds_shutdown, 1); + if (dm_gpio_is_valid(&priv->lvds_shutdown)) + dm_gpio_set_value(&priv->lvds_shutdown, 1); break; case STAGE_BACKLIGHT_VDD: - if (dm_gpio_is_valid(&config.backlight_vdd)) - dm_gpio_set_value(&config.backlight_vdd, 1); + if (dm_gpio_is_valid(&priv->backlight_vdd)) + dm_gpio_set_value(&priv->backlight_vdd, 1); break; case STAGE_PWM: /* Enable PWM at 15/16 high, 32768 Hz with divider 1 */ pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM); pinmux_tristate_disable(PMUX_PINGRP_GPU); - pwm_enable(config.pwm_channel, 32768, 0xdf, 1); + pwm_set_config(priv->pwm, priv->pwm_channel, 0xdf, 0xff); + pwm_set_enable(priv->pwm, priv->pwm_channel, true); break; case STAGE_BACKLIGHT_EN: - if (dm_gpio_is_valid(&config.backlight_en)) - dm_gpio_set_value(&config.backlight_en, 1); + if (dm_gpio_is_valid(&priv->backlight_en)) + dm_gpio_set_value(&priv->backlight_en, 1); break; case STAGE_DONE: break; } /* set up timer for next stage */ - timer_next = timer_get_us(); - if (stage < FDT_LCD_TIMINGS) - timer_next += config.panel_timings[stage] * 1000; + priv->timer_next = timer_get_us(); + if (priv->stage < FDT_LCD_TIMINGS) + priv->timer_next += priv->panel_timings[priv->stage] * 1000; /* move to next stage */ - stage++; + priv->stage++; return 0; } -int tegra_lcd_check_next_stage(const void *blob, int wait) +/** + * Perform the next stage of the LCD init if it is time to do so. + * + * LCD init can be time-consuming because of the number of delays we need + * while waiting for the backlight power supply, etc. This function can + * be called at various times during U-Boot operation to advance the + * initialization of the LCD to the next stage if sufficient time has + * passed since the last stage. It keeps track of what stage it is up to + * and the time that it is permitted to move to the next stage. + * + * The final call should have wait=1 to complete the init. + * + * @param blob fdt blob containing LCD information + * @param wait 1 to wait until all init is complete, and then return + * 0 to return immediately, potentially doing nothing if it is + * not yet time for the next init. + */ +static int tegra_lcd_check_next_stage(const void *blob, + struct tegra_lcd_priv *priv, int wait) { - if (stage == STAGE_DONE) + if (priv->stage == STAGE_DONE) return 0; do { /* wait if we need to */ - debug("%s: stage %d\n", __func__, stage); - if (stage != STAGE_START) { - int delay = timer_next - timer_get_us(); + debug("%s: stage %d\n", __func__, priv->stage); + if (priv->stage != STAGE_START) { + int delay = priv->timer_next - timer_get_us(); if (delay > 0) { if (wait) @@ -257,29 +460,188 @@ int tegra_lcd_check_next_stage(const void *blob, int wait) } } - if (handle_stage(blob)) + if (handle_stage(blob, priv)) return -1; - } while (wait && stage != STAGE_DONE); - if (stage == STAGE_DONE) + } while (wait && priv->stage != STAGE_DONE); + if (priv->stage == STAGE_DONE) debug("%s: LCD init complete\n", __func__); return 0; } -void lcd_enable(void) +static int tegra_lcd_probe(struct udevice *dev) { - /* - * Backlight and power init will be done separately in - * tegra_lcd_check_next_stage(), which should be called in - * board_late_init(). - * - * U-Boot code supports only colour depth, selected at compile time. - * The device tree setting should match this. Otherwise the display - * will not look right, and U-Boot may crash. - */ - if (disp_config->log2_bpp != LCD_BPP) { - printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)" - " must match setting of LCD_BPP (%d)\n", __func__, - disp_config->log2_bpp, disp_config->bpp, LCD_BPP); + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct tegra_lcd_priv *priv = dev_get_priv(dev); + const void *blob = gd->fdt_blob; + int type = DCACHE_OFF; + + /* Initialize the Tegra display controller */ + if (tegra_display_probe(blob, priv, (void *)plat->base)) { + printf("%s: Failed to probe display driver\n", __func__); + return -1; } + + tegra_lcd_check_next_stage(blob, priv, 1); + + /* Set up the LCD caching as requested */ + if (priv->cache_type & FDT_LCD_CACHE_WRITE_THROUGH) + type = DCACHE_WRITETHROUGH; + else if (priv->cache_type & FDT_LCD_CACHE_WRITE_BACK) + type = DCACHE_WRITEBACK; + mmu_set_region_dcache_behaviour(priv->frame_buffer, plat->size, type); + + /* Enable flushing after LCD writes if requested */ + video_set_flush_dcache(dev, priv->cache_type & FDT_LCD_CACHE_FLUSH); + + uc_priv->xsize = priv->width; + uc_priv->ysize = priv->height; + uc_priv->bpix = priv->log2_bpp; + debug("LCD frame buffer at %pa, size %x\n", &priv->frame_buffer, + plat->size); + + return 0; } + +static int tegra_lcd_ofdata_to_platdata(struct udevice *dev) +{ + struct tegra_lcd_priv *priv = dev_get_priv(dev); + struct fdtdec_phandle_args args; + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + int front, back, ref; + int panel_node; + int rgb; + int bpp, bit; + int ret; + + priv->disp = (struct disp_ctlr *)dev_get_addr(dev); + if (!priv->disp) { + debug("%s: No display controller address\n", __func__); + return -EINVAL; + } + + rgb = fdt_subnode_offset(blob, node, "rgb"); + + panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel"); + if (panel_node < 0) { + debug("%s: Cannot find panel information\n", __func__); + return -EINVAL; + } + + priv->width = fdtdec_get_int(blob, panel_node, "xres", -1); + priv->height = fdtdec_get_int(blob, panel_node, "yres", -1); + priv->pixel_clock = fdtdec_get_int(blob, panel_node, "clock", 0); + if (!priv->pixel_clock || priv->width == -1 || priv->height == -1) { + debug("%s: Pixel parameters missing\n", __func__); + return -EINVAL; + } + + back = fdtdec_get_int(blob, panel_node, "left-margin", -1); + front = fdtdec_get_int(blob, panel_node, "right-margin", -1); + ref = fdtdec_get_int(blob, panel_node, "hsync-len", -1); + if ((back | front | ref) == -1) { + debug("%s: Horizontal parameters missing\n", __func__); + return -EINVAL; + } + + /* Use a ref-to-sync of 1 always, and take this from the front porch */ + priv->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1; + priv->horiz_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref; + priv->horiz_timing[FDT_LCD_TIMING_BACK_PORCH] = back; + priv->horiz_timing[FDT_LCD_TIMING_FRONT_PORCH] = front - + priv->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC]; + debug_timing("horiz", priv->horiz_timing); + + back = fdtdec_get_int(blob, panel_node, "upper-margin", -1); + front = fdtdec_get_int(blob, panel_node, "lower-margin", -1); + ref = fdtdec_get_int(blob, panel_node, "vsync-len", -1); + if ((back | front | ref) == -1) { + debug("%s: Vertical parameters missing\n", __func__); + return -EINVAL; + } + + priv->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1; + priv->vert_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref; + priv->vert_timing[FDT_LCD_TIMING_BACK_PORCH] = back; + priv->vert_timing[FDT_LCD_TIMING_FRONT_PORCH] = front - + priv->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC]; + debug_timing("vert", priv->vert_timing); + + bpp = fdtdec_get_int(blob, panel_node, "nvidia,bits-per-pixel", -1); + bit = ffs(bpp) - 1; + if (bpp == (1 << bit)) + priv->log2_bpp = bit; + else + priv->log2_bpp = bpp; + if (bpp == -1) { + debug("%s: Pixel bpp parameters missing\n", __func__); + return -EINVAL; + } + + if (fdtdec_parse_phandle_with_args(blob, panel_node, "nvidia,pwm", + "#pwm-cells", 0, 0, &args)) { + debug("%s: Unable to decode PWM\n", __func__); + return -EINVAL; + } + + ret = uclass_get_device_by_of_offset(UCLASS_PWM, args.node, &priv->pwm); + if (ret) { + debug("%s: Unable to find PWM\n", __func__); + return -EINVAL; + } + priv->pwm_channel = args.args[0]; + + priv->cache_type = fdtdec_get_int(blob, panel_node, "nvidia,cache-type", + FDT_LCD_CACHE_WRITE_BACK_FLUSH); + + /* These GPIOs are all optional */ + gpio_request_by_name_nodev(blob, panel_node, + "nvidia,backlight-enable-gpios", 0, + &priv->backlight_en, GPIOD_IS_OUT); + gpio_request_by_name_nodev(blob, panel_node, + "nvidia,lvds-shutdown-gpios", 0, + &priv->lvds_shutdown, GPIOD_IS_OUT); + gpio_request_by_name_nodev(blob, panel_node, + "nvidia,backlight-vdd-gpios", 0, + &priv->backlight_vdd, GPIOD_IS_OUT); + gpio_request_by_name_nodev(blob, panel_node, + "nvidia,panel-vdd-gpios", 0, + &priv->panel_vdd, GPIOD_IS_OUT); + + if (fdtdec_get_int_array(blob, panel_node, "nvidia,panel-timings", + priv->panel_timings, FDT_LCD_TIMINGS)) + return -EINVAL; + + return 0; +} + +static int tegra_lcd_bind(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + + plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * + (1 << LCD_MAX_LOG2_BPP) / 8; + + return 0; +} + +static const struct video_ops tegra_lcd_ops = { +}; + +static const struct udevice_id tegra_lcd_ids[] = { + { .compatible = "nvidia,tegra20-dc" }, + { } +}; + +U_BOOT_DRIVER(tegra_lcd) = { + .name = "tegra_lcd", + .id = UCLASS_VIDEO, + .of_match = tegra_lcd_ids, + .ops = &tegra_lcd_ops, + .bind = tegra_lcd_bind, + .probe = tegra_lcd_probe, + .ofdata_to_platdata = tegra_lcd_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct tegra_lcd_priv), +}; diff --git a/drivers/video/tegra124/Makefile b/drivers/video/tegra124/Makefile index 52eedb0..4287b9a 100644 --- a/drivers/video/tegra124/Makefile +++ b/drivers/video/tegra124/Makefile @@ -7,4 +7,3 @@ obj-y += display.o obj-y += dp.o obj-y += sor.o -obj-y += tegra124-lcd.o diff --git a/drivers/video/tegra124/display.c b/drivers/video/tegra124/display.c index 610ffa9..2f1f0df 100644 --- a/drivers/video/tegra124/display.c +++ b/drivers/video/tegra124/display.c @@ -14,11 +14,13 @@ #include <edid.h> #include <fdtdec.h> #include <lcd.h> +#include <video.h> #include <asm/gpio.h> #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/pwm.h> #include <asm/arch-tegra/dc.h> +#include <dm/uclass-internal.h> #include "displayport.h" DECLARE_GLOBAL_DATA_PTR; @@ -333,73 +335,46 @@ static int display_update_config_from_edid(struct udevice *dp_dev, return 0; } -/* Somewhat torturous method */ -static int get_backlight_info(const void *blob, struct gpio_desc *vdd, - struct gpio_desc *enable, int *pwmp) -{ - int sor, panel, backlight, power; - const u32 *prop; - int len; - int ret; - - *pwmp = 0; - sor = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_SOR); - if (sor < 0) - return -ENOENT; - panel = fdtdec_lookup_phandle(blob, sor, "nvidia,panel"); - if (panel < 0) - return -ENOENT; - backlight = fdtdec_lookup_phandle(blob, panel, "backlight"); - if (backlight < 0) - return -ENOENT; - ret = gpio_request_by_name_nodev(blob, backlight, "enable-gpios", 0, - enable, GPIOD_IS_OUT); - if (ret) - return ret; - prop = fdt_getprop(blob, backlight, "pwms", &len); - if (!prop || len != 3 * sizeof(u32)) - return -EINVAL; - *pwmp = fdt32_to_cpu(prop[1]); - - power = fdtdec_lookup_phandle(blob, backlight, "power-supply"); - if (power < 0) - return -ENOENT; - ret = gpio_request_by_name_nodev(blob, power, "gpio", 0, vdd, - GPIOD_IS_OUT); - if (ret) - goto err; - - return 0; - -err: - dm_gpio_free(NULL, enable); - return ret; -} - -int display_init(void *lcdbase, int fb_bits_per_pixel, - struct display_timing *timing) +static int display_init(struct udevice *dev, void *lcdbase, + int fb_bits_per_pixel, struct display_timing *timing) { + struct display_plat *disp_uc_plat; struct dc_ctlr *dc_ctlr; const void *blob = gd->fdt_blob; struct udevice *dp_dev; const int href_to_sync = 1, vref_to_sync = 1; int panel_bpp = 18; /* default 18 bits per pixel */ u32 plld_rate; - struct gpio_desc vdd_gpio, enable_gpio; - int pwm; - int node; int ret; + /* + * Before we probe the display device (eDP), tell it that this device + * is are the source of the display data. + */ + ret = uclass_find_first_device(UCLASS_DISPLAY, &dp_dev); + if (ret) { + debug("%s: device '%s' display not found (ret=%d)\n", __func__, + dev->name, ret); + return ret; + } + + disp_uc_plat = dev_get_uclass_platdata(dp_dev); + debug("Found device '%s', disp_uc_priv=%p\n", dp_dev->name, + disp_uc_plat); + disp_uc_plat->src_dev = dev; + ret = uclass_get_device(UCLASS_DISPLAY, 0, &dp_dev); - if (ret) + if (ret) { + debug("%s: Failed to probe eDP, ret=%d\n", __func__, ret); return ret; + } - node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_DC); - if (node < 0) - return -ENOENT; - dc_ctlr = (struct dc_ctlr *)fdtdec_get_addr(blob, node, "reg"); - if (fdtdec_decode_display_timing(blob, node, 0, timing)) + dc_ctlr = (struct dc_ctlr *)fdtdec_get_addr(blob, dev->of_offset, + "reg"); + if (fdtdec_decode_display_timing(blob, dev->of_offset, 0, timing)) { + debug("%s: Failed to decode display timing\n", __func__); return -EINVAL; + } ret = display_update_config_from_edid(dp_dev, &panel_bpp, timing); if (ret) { @@ -407,12 +382,6 @@ int display_init(void *lcdbase, int fb_bits_per_pixel, dump_config(panel_bpp, timing); } - if (!get_backlight_info(blob, &vdd_gpio, &enable_gpio, &pwm)) { - dm_gpio_set_value(&vdd_gpio, 1); - debug("%s: backlight vdd setting gpio %08x to %d\n", - __func__, gpio_get_number(&vdd_gpio), 1); - } - /* * The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the @@ -443,22 +412,99 @@ int display_init(void *lcdbase, int fb_bits_per_pixel, /* Enable dp */ ret = display_enable(dp_dev, panel_bpp, timing); - if (ret) + if (ret) { + debug("dc: failed to enable display: ret=%d\n", ret); return ret; + } ret = update_window(dc_ctlr, (ulong)lcdbase, fb_bits_per_pixel, timing); + if (ret) { + debug("dc: failed to update window\n"); + return ret; + } + + return 0; +} + +enum { + /* Maximum LCD size we support */ + LCD_MAX_WIDTH = 1920, + LCD_MAX_HEIGHT = 1200, + LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ +}; + +static int tegra124_lcd_init(struct udevice *dev, void *lcdbase, + enum video_log2_bpp l2bpp) +{ + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct display_timing timing; + int ret; + + clock_set_up_plldp(); + clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, 408000000); + + clock_enable(PERIPH_ID_HOST1X); + clock_enable(PERIPH_ID_DISP1); + clock_enable(PERIPH_ID_PWM); + clock_enable(PERIPH_ID_DPAUX); + clock_enable(PERIPH_ID_SOR0); + udelay(2); + + reset_set_enable(PERIPH_ID_HOST1X, 0); + reset_set_enable(PERIPH_ID_DISP1, 0); + reset_set_enable(PERIPH_ID_PWM, 0); + reset_set_enable(PERIPH_ID_DPAUX, 0); + reset_set_enable(PERIPH_ID_SOR0, 0); + + ret = display_init(dev, lcdbase, 1 << l2bpp, &timing); if (ret) return ret; - /* Set up Tegra PWM to drive the panel backlight */ - pwm_enable(pwm, 0, 220, 0x2e); - udelay(10 * 1000); + uc_priv->xsize = roundup(timing.hactive.typ, 16); + uc_priv->ysize = timing.vactive.typ; + uc_priv->bpix = l2bpp; - if (dm_gpio_is_valid(&enable_gpio)) { - dm_gpio_set_value(&enable_gpio, 1); - debug("%s: backlight enable setting gpio %08x to %d\n", - __func__, gpio_get_number(&enable_gpio), 1); - } + video_set_flush_dcache(dev, 1); + debug("%s: done\n", __func__); return 0; } + +static int tegra124_lcd_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + ulong start; + int ret; + + start = get_timer(0); + ret = tegra124_lcd_init(dev, (void *)plat->base, VIDEO_BPP16); + debug("LCD init took %lu ms\n", get_timer(start)); + if (ret) + printf("%s: Error %d\n", __func__, ret); + + return 0; +} + +static int tegra124_lcd_bind(struct udevice *dev) +{ + struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); + + uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * + (1 << VIDEO_BPP16) / 8; + debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); + + return 0; +} + +static const struct udevice_id tegra124_lcd_ids[] = { + { .compatible = "nvidia,tegra124-dc" }, + { } +}; + +U_BOOT_DRIVER(tegra124_dc) = { + .name = "tegra124-dc", + .id = UCLASS_VIDEO, + .of_match = tegra124_lcd_ids, + .bind = tegra124_lcd_bind, + .probe = tegra124_lcd_probe, +}; diff --git a/drivers/video/tegra124/dp.c b/drivers/video/tegra124/dp.c index bb1805a..5bf8524 100644 --- a/drivers/video/tegra124/dp.c +++ b/drivers/video/tegra124/dp.c @@ -11,6 +11,7 @@ #include <div64.h> #include <errno.h> #include <fdtdec.h> +#include <video_bridge.h> #include <asm/io.h> #include <asm/arch-tegra/dc.h> #include "display.h" @@ -26,9 +27,15 @@ struct tegra_dp_plat { ulong base; }; +/** + * struct tegra_dp_priv - private displayport driver info + * + * @dc_dev: Display controller device that is sending the video feed + */ struct tegra_dp_priv { + struct udevice *sor; + struct udevice *dc_dev; struct dpaux_ctlr *regs; - struct tegra_dc_sor_data *sor; u8 revision; int enabled; }; @@ -710,8 +717,8 @@ static int tegra_dc_dp_init_max_link_cfg( return 0; } -static int tegra_dc_dp_set_assr(struct tegra_dp_priv *dp, - struct tegra_dc_sor_data *sor, int ena) +static int tegra_dc_dp_set_assr(struct tegra_dp_priv *priv, + struct udevice *sor, int ena) { int ret; @@ -719,7 +726,7 @@ static int tegra_dc_dp_set_assr(struct tegra_dp_priv *dp, DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_ENABLE : DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_DISABLE; - ret = tegra_dc_dp_dpcd_write(dp, DP_EDP_CONFIGURATION_SET, + ret = tegra_dc_dp_dpcd_write(priv, DP_EDP_CONFIGURATION_SET, dpcd_data); if (ret) return ret; @@ -730,7 +737,7 @@ static int tegra_dc_dp_set_assr(struct tegra_dp_priv *dp, } static int tegra_dp_set_link_bandwidth(struct tegra_dp_priv *dp, - struct tegra_dc_sor_data *sor, + struct udevice *sor, u8 link_bw) { tegra_dc_sor_set_link_bandwidth(sor, link_bw); @@ -741,7 +748,7 @@ static int tegra_dp_set_link_bandwidth(struct tegra_dp_priv *dp, static int tegra_dp_set_lane_count(struct tegra_dp_priv *dp, const struct tegra_dp_link_config *link_cfg, - struct tegra_dc_sor_data *sor) + struct udevice *sor) { u8 dpcd_data; int ret; @@ -1002,7 +1009,7 @@ fail: static int tegra_dp_lt_config(struct tegra_dp_priv *dp, u32 pe[4], u32 vs[4], u32 pc[4], const struct tegra_dp_link_config *cfg) { - struct tegra_dc_sor_data *sor = dp->sor; + struct udevice *sor = dp->sor; u32 n_lanes = cfg->lane_count; u8 pc_supported = cfg->tps3_supported; u32 cnt; @@ -1186,7 +1193,7 @@ static int tegra_dc_dp_full_link_training(struct tegra_dp_priv *dp, const struct display_timing *timing, struct tegra_dp_link_config *cfg) { - struct tegra_dc_sor_data *sor = dp->sor; + struct udevice *sor = dp->sor; int err; u32 pe[4], vs[4], pc[4]; @@ -1229,7 +1236,7 @@ fail: */ static int tegra_dc_dp_fast_link_training(struct tegra_dp_priv *dp, const struct tegra_dp_link_config *link_cfg, - struct tegra_dc_sor_data *sor) + struct udevice *sor) { u8 link_bw; u8 lane_count; @@ -1301,7 +1308,7 @@ static int tegra_dc_dp_fast_link_training(struct tegra_dp_priv *dp, static int tegra_dp_do_link_training(struct tegra_dp_priv *dp, struct tegra_dp_link_config *link_cfg, const struct display_timing *timing, - struct tegra_dc_sor_data *sor) + struct udevice *sor) { u8 link_bw; u8 lane_count; @@ -1344,7 +1351,7 @@ static int tegra_dp_do_link_training(struct tegra_dp_priv *dp, static int tegra_dc_dp_explore_link_cfg(struct tegra_dp_priv *dp, struct tegra_dp_link_config *link_cfg, - struct tegra_dc_sor_data *sor, + struct udevice *sor, const struct display_timing *timing) { struct tegra_dp_link_config temp_cfg; @@ -1444,7 +1451,7 @@ static int tegra_dc_dp_check_sink(struct tegra_dp_priv *dp, printf("DP: Out of sync after %d retries\n", max_retry); return -EIO; } - ret = tegra_dc_sor_detach(dp->sor); + ret = tegra_dc_sor_detach(dp->dc_dev, dp->sor); if (ret) return ret; if (tegra_dc_dp_explore_link_cfg(dp, link_cfg, dp->sor, @@ -1454,7 +1461,7 @@ static int tegra_dc_dp_check_sink(struct tegra_dp_priv *dp, } tegra_dc_sor_set_power_state(dp->sor, 1); - tegra_dc_sor_attach(dp->sor, link_cfg, timing); + tegra_dc_sor_attach(dp->dc_dev, dp->sor, link_cfg, timing); /* Increase delay_frame for next try in case the sink is skipping more frames */ @@ -1467,7 +1474,7 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, { struct tegra_dp_priv *priv = dev_get_priv(dev); struct tegra_dp_link_config slink_cfg, *link_cfg = &slink_cfg; - struct tegra_dc_sor_data *sor; + struct udevice *sor; int data; int retry; int ret; @@ -1489,9 +1496,11 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, return -ENOLINK; } - ret = tegra_dc_sor_init(&sor); - if (ret) + ret = uclass_first_device(UCLASS_VIDEO_BRIDGE, &sor); + if (ret || !sor) { + debug("dp: failed to find SOR device: ret=%d\n", ret); return ret; + } priv->sor = sor; ret = tegra_dc_sor_enable_dp(sor, link_cfg); if (ret) @@ -1531,7 +1540,7 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, } tegra_dc_sor_set_power_state(sor, 1); - ret = tegra_dc_sor_attach(sor, link_cfg, timing); + ret = tegra_dc_sor_attach(priv->dc_dev, sor, link_cfg, timing); if (ret && ret != -EEXIST) return ret; @@ -1548,6 +1557,12 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, /* Power down the unused lanes to save power - a few hundred mW */ tegra_dc_sor_power_down_unused_lanes(sor, link_cfg); + ret = video_bridge_set_backlight(sor, 80); + if (ret) { + debug("dp: failed to set backlight\n"); + return ret; + } + priv->enabled = true; error_enable: return 0; @@ -1583,10 +1598,14 @@ static int dp_tegra_probe(struct udevice *dev) { struct tegra_dp_plat *plat = dev_get_platdata(dev); struct tegra_dp_priv *priv = dev_get_priv(dev); + struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev); priv->regs = (struct dpaux_ctlr *)plat->base; priv->enabled = false; + /* Remember the display controller that is sending us video */ + priv->dc_dev = disp_uc_plat->src_dev; + return 0; } diff --git a/drivers/video/tegra124/sor.c b/drivers/video/tegra124/sor.c index aa3d80c..e5cea51 100644 --- a/drivers/video/tegra124/sor.c +++ b/drivers/video/tegra124/sor.c @@ -5,9 +5,12 @@ */ #include <common.h> +#include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> +#include <panel.h> +#include <video_bridge.h> #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch-tegra/dc.h> @@ -37,6 +40,14 @@ DECLARE_GLOBAL_DATA_PTR; #define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF (0 << 25) #define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON (1 << 25) +struct tegra_dc_sor_data { + void *base; + void *pmc_base; + u8 portnum; /* 0 or 1 */ + int power_is_up; + struct udevice *panel; +}; + static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg) { return readl((u32 *)sor->base + reg); @@ -57,15 +68,19 @@ static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor, tegra_sor_writel(sor, reg, reg_val); } -void tegra_dp_disable_tx_pu(struct tegra_dc_sor_data *sor) +void tegra_dp_disable_tx_pu(struct udevice *dev) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), DP_PADCTL_TX_PU_MASK, DP_PADCTL_TX_PU_DISABLE); } -void tegra_dp_set_pe_vs_pc(struct tegra_dc_sor_data *sor, u32 mask, u32 pe_reg, +void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg, u32 vs_reg, u32 pc_reg, u8 pc_supported) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + tegra_sor_write_field(sor, PR(sor->portnum), mask, pe_reg); tegra_sor_write_field(sor, DC(sor->portnum), mask, vs_reg); if (pc_supported) { @@ -95,8 +110,9 @@ static int tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor, u32 reg, return -ETIMEDOUT; } -int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd) +int tegra_dc_sor_set_power_state(struct udevice *dev, int pu_pd) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; u32 orig_val; @@ -123,10 +139,11 @@ int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd) return 0; } -void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena, +void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena, u8 training_pattern, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum)); @@ -194,9 +211,10 @@ static int tegra_dc_sor_enable_lane_sequencer(struct tegra_dc_sor_data *sor, return 0; } -static int tegra_dc_sor_power_dplanes(struct tegra_dc_sor_data *sor, +static int tegra_dc_sor_power_dplanes(struct udevice *dev, u32 lane_count, int pu) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); @@ -218,15 +236,15 @@ static int tegra_dc_sor_power_dplanes(struct tegra_dc_sor_data *sor, } tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val); - tegra_dc_sor_set_lane_count(sor, lane_count); + tegra_dc_sor_set_lane_count(dev, lane_count); } return tegra_dc_sor_enable_lane_sequencer(sor, pu, 0); } -void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor, - int power_up) +void tegra_dc_sor_set_panel_power(struct udevice *dev, int power_up) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); @@ -255,14 +273,15 @@ static void tegra_dc_sor_config_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div, } } -static void tegra_dc_sor_set_dp_mode(struct tegra_dc_sor_data *sor, +static void tegra_dc_sor_set_dp_mode(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; - tegra_dc_sor_set_link_bandwidth(sor, link_cfg->link_bw); + tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw); - tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_none, link_cfg); + tegra_dc_sor_set_dp_linkctl(dev, 1, training_pattern_none, link_cfg); reg_val = tegra_sor_readl(sor, DP_CONFIG(sor->portnum)); reg_val &= ~DP_CONFIG_WATERMARK_MASK; reg_val |= link_cfg->watermark; @@ -351,8 +370,9 @@ static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up) return 0; } -void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int) +void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_SPARE(sor->portnum)); @@ -366,9 +386,10 @@ void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int) tegra_sor_writel(sor, DP_SPARE(sor->portnum), reg_val); } -void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw, +void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw, u8 *lane_count) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, CLK_CNTRL); @@ -395,15 +416,18 @@ void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw, } } -void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor, u8 link_bw) +void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + tegra_sor_write_field(sor, CLK_CNTRL, CLK_CNTRL_DP_LINK_SPEED_MASK, link_bw << CLK_CNTRL_DP_LINK_SPEED_SHIFT); } -void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count) +void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum)); @@ -439,15 +463,16 @@ void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count) * 4 1 0 0 0 0 0 1 * 5 0 0 0 0 0 0 1 */ -static int tegra_dc_sor_power_up(struct tegra_dc_sor_data *sor, int is_lvds) +static int tegra_dc_sor_power_up(struct udevice *dev, int is_lvds) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); int ret; if (sor->power_is_up) return 0; /* Set link bw */ - tegra_dc_sor_set_link_bandwidth(sor, is_lvds ? + tegra_dc_sor_set_link_bandwidth(dev, is_lvds ? CLK_CNTRL_DP_LINK_SPEED_LVDS : CLK_CNTRL_DP_LINK_SPEED_G1_62); @@ -655,9 +680,10 @@ static void tegra_dc_sor_enable_dc(struct dc_ctlr *disp_ctrl) writel(reg_val, &disp_ctrl->cmd.state_access); } -int tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_enable_dp(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); int ret; tegra_sor_write_field(sor, CLK_CNTRL, @@ -701,7 +727,7 @@ int tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor, PLL2_AUX2_OVERRIDE_POWERDOWN | PLL2_AUX7_PORT_POWERDOWN_DISABLE); - ret = tegra_dc_sor_power_up(sor, 0); + ret = tegra_dc_sor_power_up(dev, 0); if (ret) { debug("DP failed to power up\n"); return ret; @@ -711,18 +737,19 @@ int tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor, clock_sor_enable_edp_clock(); /* Power up lanes */ - tegra_dc_sor_power_dplanes(sor, link_cfg->lane_count, 1); + tegra_dc_sor_power_dplanes(dev, link_cfg->lane_count, 1); - tegra_dc_sor_set_dp_mode(sor, link_cfg); + tegra_dc_sor_set_dp_mode(dev, link_cfg); debug("%s ret\n", __func__); return 0; } -int tegra_dc_sor_attach(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *dev, const struct tegra_dp_link_config *link_cfg, const struct display_timing *timing) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); const void *blob = gd->fdt_blob; struct dc_ctlr *disp_ctrl; u32 reg_val; @@ -730,9 +757,7 @@ int tegra_dc_sor_attach(struct tegra_dc_sor_data *sor, /* Use the first display controller */ debug("%s\n", __func__); - node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_DC); - if (node < 0) - return -ENOENT; + node = dc_dev->of_offset; disp_ctrl = (struct dc_ctlr *)fdtdec_get_addr(blob, node, "reg"); tegra_dc_sor_enable_dc(disp_ctrl); @@ -798,9 +823,11 @@ int tegra_dc_sor_attach(struct tegra_dc_sor_data *sor, return 0; } -void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, +void tegra_dc_sor_set_lane_parm(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), link_cfg->drive_current); tegra_sor_writel(sor, PR(sor->portnum), @@ -809,8 +836,8 @@ void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, link_cfg->postcursor); tegra_sor_writel(sor, LVDS, 0); - tegra_dc_sor_set_link_bandwidth(sor, link_cfg->link_bw); - tegra_dc_sor_set_lane_count(sor, link_cfg->lane_count); + tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw); + tegra_dc_sor_set_lane_count(dev, link_cfg->lane_count); tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), DP_PADCTL_TX_PU_ENABLE | @@ -825,9 +852,10 @@ void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0x0); } -int tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_set_voltage_swing(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 drive_current = 0; u32 pre_emphasis = 0; @@ -851,9 +879,10 @@ int tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor, return 0; } -void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor, +void tegra_dc_sor_power_down_unused_lanes(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 pad_ctrl = 0; int err = 0; @@ -891,9 +920,10 @@ void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor, } } -int tegra_sor_precharge_lanes(struct tegra_dc_sor_data *sor, +int tegra_sor_precharge_lanes(struct udevice *dev, const struct tegra_dp_link_config *cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 val = 0; switch (cfg->lane_count) { @@ -931,8 +961,9 @@ static void tegra_dc_sor_enable_sor(struct dc_ctlr *disp_ctrl, bool enable) writel(reg_val, &disp_ctrl->disp.disp_win_opt); } -int tegra_dc_sor_detach(struct tegra_dc_sor_data *sor) +int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *dev) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); int dc_reg_ctx[DC_REG_SAVE_SPACE]; const void *blob = gd->fdt_blob; struct dc_ctlr *disp_ctrl; @@ -942,11 +973,7 @@ int tegra_dc_sor_detach(struct tegra_dc_sor_data *sor) debug("%s\n", __func__); /* Use the first display controller */ - node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_DC); - if (node < 0) { - ret = -ENOENT; - goto err; - } + node = dc_dev->of_offset; disp_ctrl = (struct dc_ctlr *)fdtdec_get_addr(blob, node, "reg"); /* Sleep mode */ @@ -997,28 +1024,61 @@ err: return ret; } -int tegra_dc_sor_init(struct tegra_dc_sor_data **sorp) +static int tegra_sor_set_backlight(struct udevice *dev, int percent) { + struct tegra_dc_sor_data *priv = dev_get_priv(dev); + int ret; + + ret = panel_enable_backlight(priv->panel); + if (ret) { + debug("sor: Cannot enable panel backlight\n"); + return ret; + } + + return 0; +} + +static int tegra_sor_ofdata_to_platdata(struct udevice *dev) +{ + struct tegra_dc_sor_data *priv = dev_get_priv(dev); const void *blob = gd->fdt_blob; - struct tegra_dc_sor_data *sor; int node; + int ret; - node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_SOR); - if (node < 0) - return -ENOENT; - sor = calloc(1, sizeof(*sor)); - if (!sor) - return -ENOMEM; - sor->base = (void *)fdtdec_get_addr(blob, node, "reg"); + priv->base = (void *)fdtdec_get_addr(blob, dev->of_offset, "reg"); node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_PMC); - if (node < 0) + if (node < 0) { + debug("%s: Cannot find PMC\n", __func__); return -ENOENT; - sor->pmc_base = (void *)fdtdec_get_addr(blob, node, "reg"); + } + priv->pmc_base = (void *)fdtdec_get_addr(blob, node, "reg"); - sor->power_is_up = 0; - sor->portnum = 0; - *sorp = sor; + ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "nvidia,panel", + &priv->panel); + if (ret) { + debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, + dev->name, ret); + return ret; + } return 0; } + +static const struct video_bridge_ops tegra_sor_ops = { + .set_backlight = tegra_sor_set_backlight, +}; + +static const struct udevice_id tegra_sor_ids[] = { + { .compatible = "nvidia,tegra124-sor" }, + { } +}; + +U_BOOT_DRIVER(sor_tegra) = { + .name = "sor_tegra", + .id = UCLASS_VIDEO_BRIDGE, + .of_match = tegra_sor_ids, + .ofdata_to_platdata = tegra_sor_ofdata_to_platdata, + .ops = &tegra_sor_ops, + .priv_auto_alloc_size = sizeof(struct tegra_dc_sor_data), +}; diff --git a/drivers/video/tegra124/sor.h b/drivers/video/tegra124/sor.h index dc8fd03..e854bef 100644 --- a/drivers/video/tegra124/sor.h +++ b/drivers/video/tegra124/sor.h @@ -873,44 +873,37 @@ struct tegra_dp_link_config { u8 tps3_supported; }; -struct tegra_dc_sor_data { - void *base; - void *pmc_base; - u8 portnum; /* 0 or 1 */ - int power_is_up; -}; - #define TEGRA_SOR_TIMEOUT_MS 1000 #define TEGRA_SOR_ATTACH_TIMEOUT_MS 1000 -int tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_enable_dp(struct udevice *sor, const struct tegra_dp_link_config *link_cfg); -int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd); -void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena, +int tegra_dc_sor_set_power_state(struct udevice *sor, int pu_pd); +void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena, u8 training_pattern, const struct tegra_dp_link_config *link_cfg); -void tegra_dc_sor_set_link_bandwidth(struct 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, +void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw); +void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count); +void tegra_dc_sor_set_panel_power(struct udevice *sor, int power_up); -void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int); -void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw, +void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int); +void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw, u8 *lane_count); -void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, - const struct tegra_dp_link_config *link_cfg); -void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor, +void tegra_dc_sor_set_lane_parm(struct udevice *dev, + const struct tegra_dp_link_config *link_cfg); +void tegra_dc_sor_power_down_unused_lanes(struct udevice *sor, const struct tegra_dp_link_config *link_cfg); -int tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_set_voltage_swing(struct udevice *sor, const struct tegra_dp_link_config *link_cfg); -int tegra_sor_precharge_lanes(struct tegra_dc_sor_data *sor, +int tegra_sor_precharge_lanes(struct udevice *dev, const struct tegra_dp_link_config *cfg); -void tegra_dp_disable_tx_pu(struct tegra_dc_sor_data *sor); -void tegra_dp_set_pe_vs_pc(struct tegra_dc_sor_data *sor, u32 mask, - u32 pe_reg, u32 vs_reg, u32 pc_reg, u8 pc_supported); +void tegra_dp_disable_tx_pu(struct udevice *sor); +void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg, + u32 vs_reg, u32 pc_reg, u8 pc_supported); -int tegra_dc_sor_attach(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *sor, const struct tegra_dp_link_config *link_cfg, const struct display_timing *timing); -int tegra_dc_sor_detach(struct tegra_dc_sor_data *sor); +int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *sor); void tegra_dc_sor_disable_win_short_raster(struct dc_ctlr *disp_ctrl, int *dc_reg_ctx); @@ -918,5 +911,5 @@ int tegra_dc_sor_general_act(struct dc_ctlr *disp_ctrl); void tegra_dc_sor_restore_win_and_raster(struct dc_ctlr *disp_ctrl, int *dc_reg_ctx); -int tegra_dc_sor_init(struct tegra_dc_sor_data **sorp); +int tegra_dc_sor_init(struct udevice **sorp); #endif diff --git a/drivers/video/tegra124/tegra124-lcd.c b/drivers/video/tegra124/tegra124-lcd.c deleted file mode 100644 index cfdc77f..0000000 --- a/drivers/video/tegra124/tegra124-lcd.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * SPDX-License-Identifier: GPL-2.0+ - * - */ - -#include <common.h> -#include <errno.h> -#include <fdtdec.h> -#include <lcd.h> -#include <asm/gpio.h> -#include <asm/arch-tegra/clk_rst.h> -#include <asm/arch/clock.h> -#include <asm/arch-tegra/dc.h> -#include <asm/io.h> - -DECLARE_GLOBAL_DATA_PTR; - -enum { - /* Maximum LCD size we support */ - LCD_MAX_WIDTH = 1920, - LCD_MAX_HEIGHT = 1200, - LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ -}; - -vidinfo_t panel_info = { - /* Insert a value here so that we don't end up in the BSS */ - .vl_col = -1, -}; - -int tegra_lcd_check_next_stage(const void *blob, int wait) -{ - return 0; -} - -void tegra_lcd_early_init(const void *blob) -{ - /* - * Go with the maximum size for now. We will fix this up after - * relocation. These values are only used for memory alocation. - */ - panel_info.vl_col = LCD_MAX_WIDTH; - panel_info.vl_row = LCD_MAX_HEIGHT; - panel_info.vl_bpix = LCD_MAX_LOG2_BPP; -} - -static int tegra124_lcd_init(void *lcdbase) -{ - struct display_timing timing; - int ret; - - clock_set_up_plldp(); - clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, 408000000); - - clock_enable(PERIPH_ID_HOST1X); - clock_enable(PERIPH_ID_DISP1); - clock_enable(PERIPH_ID_PWM); - clock_enable(PERIPH_ID_DPAUX); - clock_enable(PERIPH_ID_SOR0); - udelay(2); - - reset_set_enable(PERIPH_ID_HOST1X, 0); - reset_set_enable(PERIPH_ID_DISP1, 0); - reset_set_enable(PERIPH_ID_PWM, 0); - reset_set_enable(PERIPH_ID_DPAUX, 0); - reset_set_enable(PERIPH_ID_SOR0, 0); - - ret = display_init(lcdbase, 1 << LCD_BPP, &timing); - if (ret) - return ret; - - panel_info.vl_col = roundup(timing.hactive.typ, 16); - panel_info.vl_row = timing.vactive.typ; - - lcd_set_flush_dcache(1); - - return 0; -} - -void lcd_ctrl_init(void *lcdbase) -{ - ulong start; - int ret; - - start = get_timer(0); - ret = tegra124_lcd_init(lcdbase); - debug("LCD init took %lu ms\n", get_timer(start)); - if (ret) - printf("%s: Error %d\n", __func__, ret); -} - -void lcd_enable(void) -{ -} diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index f6326b6..832e90a 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -170,6 +170,7 @@ static void vidconsole_puts(struct stdio_dev *sdev, const char *s) while (*s) vidconsole_put_char(dev, *s++); + video_sync(dev->parent); } /* Set up the number of rows and colours (rotated drivers override this) */ |