diff options
author | Simon Glass <sjg@chromium.org> | 2016-01-30 16:37:50 -0700 |
---|---|---|
committer | Tom Warren <twarren@nvidia.com> | 2016-02-16 09:17:51 -0700 |
commit | d76592122b347473f09a440702cc3be03e368511 (patch) | |
tree | b826b9e3566253e8a3f326bd0e46200a841f5f70 /drivers | |
parent | 135a87ef43566cdd592fa9fd899bf435aa14aaa3 (diff) |
tegra: nyan-big: Move the LCD driver to driver model
Adjust the driver to use driver model. The SOR becomes a bridge device. We
use the normal simple_panel driver to handle the display itself. We also
need to enable some options such as regulators, PWMs and DM_VIDEO itself.
Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Anatolij Gustschin <agust@denx.de>
Signed-off-by: Tom Warren <twarren@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/Kconfig | 1 | ||||
-rw-r--r-- | drivers/video/simple_panel.c | 1 | ||||
-rw-r--r-- | drivers/video/tegra124/display.c | 169 | ||||
-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 |
6 files changed, 237 insertions, 194 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 19f9429cce7..72afae0d26a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -383,6 +383,7 @@ config VIDEO_SANDBOX_SDL 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/simple_panel.c b/drivers/video/simple_panel.c index b1615176748..c73f24295a4 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/tegra124/display.c b/drivers/video/tegra124/display.c index b4c4093694a..2f1f0df20eb 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; -} - -static 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 @@ static 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,21 +412,15 @@ static 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) + if (ret) { + debug("dc: failed to update window\n"); return ret; - - /* Set up Tegra PWM to drive the panel backlight */ - pwm_enable(pwm, 0, 220, 0x2e); - udelay(10 * 1000); - - 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); } return 0; @@ -470,29 +433,10 @@ enum { 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) +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; @@ -512,30 +456,55 @@ static int tegra124_lcd_init(void *lcdbase) reset_set_enable(PERIPH_ID_DPAUX, 0); reset_set_enable(PERIPH_ID_SOR0, 0); - ret = display_init(lcdbase, 1 << LCD_BPP, &timing); + ret = display_init(dev, lcdbase, 1 << l2bpp, &timing); if (ret) return ret; - panel_info.vl_col = roundup(timing.hactive.typ, 16); - panel_info.vl_row = timing.vactive.typ; + uc_priv->xsize = roundup(timing.hactive.typ, 16); + uc_priv->ysize = timing.vactive.typ; + uc_priv->bpix = l2bpp; - lcd_set_flush_dcache(1); + video_set_flush_dcache(dev, 1); + debug("%s: done\n", __func__); return 0; } -void lcd_ctrl_init(void *lcdbase) +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(lcdbase); + 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; } -void lcd_enable(void) +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 bb1805a2482..5bf8524a5e8 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 aa3d80c4c0f..e5cea51d48c 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 dc8fd03d808..e854bef17d1 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 |