+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2014 Google Inc.
*
- * SPDX-License-Identifier: GPL-2.0+
- *
* Extracted from Chromium coreboot commit 3f59b13d
*/
#include <errno.h>
#include <display.h>
#include <edid.h>
-#include <fdtdec.h>
#include <lcd.h>
+#include <part.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;
-
/* return in 1000ths of a Hertz */
static int tegra_dc_calc_refresh(const struct display_timing *timing)
{
int *panel_bppp,
struct display_timing *timing)
{
- int ret;
-
- ret = display_read_timing(dp_dev, timing);
- if (ret)
- return ret;
-
- return 0;
+ return display_read_timing(dp_dev, timing);
}
-/* 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 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 *)dev_read_addr(dev);
+ if (ofnode_decode_display_timing(dev_ofnode(dev), 0, timing)) {
+ debug("%s: Failed to decode display timing\n", __func__);
return -EINVAL;
+ }
ret = display_update_config_from_edid(dp_dev, &panel_bpp, timing);
if (ret) {
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
/* 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);
}
+ debug("%s: ready\n", __func__);
return 0;
}
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;
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);
+ bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "lcd");
+ ret = tegra124_lcd_init(dev, (void *)plat->base, VIDEO_BPP16);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD);
debug("LCD init took %lu ms\n", get_timer(start));
if (ret)
printf("%s: Error %d\n", __func__, ret);
+
+ return 0;
}
-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,
+};