summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2011-12-19 16:17:57 -0800
committerSimon Glass <sjg@chromium.org>2012-01-05 15:54:33 -0800
commit7d436642249ec30640a1d23b209214ccf4a2d0b1 (patch)
tree3bc30bdee60692ca65723d3f73be2dcaf6c2df0c /drivers
parent17b3e106d1da893de82dac51888e9515f689ea51 (diff)
tegra: Tidy up LCD init code to use a state machine
The LCD init takes place over five stages. We want to hide this init behind other operations, so turn it into a state machine which we can call at any time. For now, call it in lcd_enable(). BUG=chromium-os:22938 TEST=build and boot on Kaen Change-Id: Ia0b50ec74108ac4e015de12b7a9628426ea17656 Reviewed-on: https://gerrit.chromium.org/gerrit/13211 Reviewed-by: Tom Wai-Hong Tam <waihong@chromium.org> Reviewed-by: Che-Liang Chiou <clchiou@chromium.org> Tested-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/tegra2.c165
1 files changed, 90 insertions, 75 deletions
diff --git a/drivers/video/tegra2.c b/drivers/video/tegra2.c
index b43da981bf2..6a458d139dd 100644
--- a/drivers/video/tegra2.c
+++ b/drivers/video/tegra2.c
@@ -33,7 +33,19 @@
DECLARE_GLOBAL_DATA_PTR;
-unsigned long timer_last;
+/* These are the stages we go throuh in enabling the LCD */
+enum stage_t {
+ STAGE_START,
+ STAGE_LVDS,
+ STAGE_BACKLIGHT_VDD,
+ STAGE_PWFM,
+ STAGE_BACKLIGHT_EN,
+ STAGE_DONE,
+};
+
+static enum stage_t stage; /* Current stage we are at */
+static unsigned long timer_next; /* Time we can move onto next stage */
+static struct fdt_lcd config; /* Our LCD config, set up in handle_stage() */
int lcd_line_length;
int lcd_color_fg;
@@ -109,24 +121,6 @@ struct pingroup_config pinmux_cros_1[] = {
PINMUX(SLXD, SPDIF, NORMAL, NORMAL),
};
-/* Initialize the Tegra LCD pinmuxs */
-static void init_lcd_pinmux(struct fdt_lcd *config)
-{
- /* TODO: put pinmux into the FDT */
- pinmux_config_table(pinmux_cros_1, ARRAY_SIZE(pinmux_cros_1));
-
- fdt_setup_gpio(&config->panel_vdd);
- fdt_setup_gpio(&config->lvds_shutdown);
- fdt_setup_gpio(&config->backlight_vdd);
- fdt_setup_gpio(&config->backlight_en);
-
- gpio_set_value(config->panel_vdd.gpio, 1);
- udelay(config->panel_timings[0] * 1000);
-
- gpio_set_value(config->lvds_shutdown.gpio, 1);
- timer_last = timer_get_us();
-}
-
/* Initialize the Tegra LCD panel and controller */
void init_lcd(struct fdt_lcd *config)
{
@@ -135,35 +129,6 @@ void init_lcd(struct fdt_lcd *config)
tegra2_display_register(config);
}
-static void init_lcd_pwm(struct fdt_lcd *config)
-{
- long pre_delay;
-
- /*
- * Compare the current timer valuse with the timer_last to
- * figure out the pre_delay which is the passed time from
- * the end of init_lcd_pinmux to now.
- * If the required delay(timings[1]) is bigger than pre_delay,
- * we have to do a delay (timings[1] - pre_delay) to make
- * sure the required delay(timings[1]) has passed.
- */
- pre_delay = timer_get_us() - timer_last;
-
- if ((long)(config->panel_timings[1] * 1000) > pre_delay)
- udelay((long)(config->panel_timings[1] * 1000) - pre_delay);
-
- if (fdt_gpio_isvalid(&config->backlight_vdd)) {
- gpio_set_value(config->backlight_vdd.gpio, 1);
- udelay(config->panel_timings[2] * 1000);
- }
-
- /* Enable PWM at 15/16 high, divider 1 */
- pwfm_setup(config->pwfm, 1, 0xdf, 1);
- udelay(config->panel_timings[3] * 1000);
-
- gpio_set_value(config->backlight_en.gpio, 1);
-}
-
void lcd_cursor_size(ushort width, ushort height)
{
lcd_cursor_width = width;
@@ -225,15 +190,8 @@ static void update_panel_size(struct fdt_lcd *config)
void lcd_ctrl_init(void *lcdbase)
{
- struct fdt_lcd config;
int line_length, size;
- /* get panel details */
- if (fdt_decode_lcd(gd->blob, &config)) {
- printf("No LCD information in device tree\n");
- return;
- }
-
/*
* The framebuffer address should be specified in the device tree.
* This FDT value should be the same as the one defined in Linux kernel;
@@ -278,20 +236,6 @@ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
{
}
-void lcd_enable(void)
-{
- struct fdt_lcd config;
-
- /* get panel details */
- if (fdt_decode_lcd(gd->blob, &config)) {
- printf("No LCD information in device tree\n");
- return;
- }
-
- /* call board specific hw init for backlight PWM */
- init_lcd_pwm(&config);
-}
-
void lcd_early_init(const void *blob)
{
struct fdt_lcd config;
@@ -301,14 +245,85 @@ void lcd_early_init(const void *blob)
update_panel_size(&config);
}
-int lcd_pinmux_early_init(const void *blob)
+static int handle_stage(const void *blob)
{
- struct fdt_lcd config;
+ /* do the things for this stage */
+ switch (stage) {
+ case STAGE_START:
+ /* get panel details */
+ if (fdt_decode_lcd(blob, &config)) {
+ printf("No LCD information in device tree\n");
+ return -1;
+ }
- /* get panel details */
- if (fdt_decode_lcd(gd->blob, &config))
- return -1;
+ /* TODO: put pinmux into the FDT */
+ pinmux_config_table(pinmux_cros_1, ARRAY_SIZE(pinmux_cros_1));
+
+ fdt_setup_gpio(&config.panel_vdd);
+ fdt_setup_gpio(&config.lvds_shutdown);
+ fdt_setup_gpio(&config.backlight_vdd);
+ fdt_setup_gpio(&config.backlight_en);
+
+ gpio_set_value(config.panel_vdd.gpio, 1);
+ break;
+
+ case STAGE_LVDS:
+ gpio_set_value(config.lvds_shutdown.gpio, 1);
+ break;
+
+ case STAGE_BACKLIGHT_VDD:
+ if (fdt_gpio_isvalid(&config.backlight_vdd))
+ gpio_set_value(config.backlight_vdd.gpio, 1);
+ break;
+
+ case STAGE_PWFM:
+ /* Enable PWM at 15/16 high, divider 1 */
+ pwfm_setup(config.pwfm, 1, 0xdf, 1);
+ break;
+
+ case STAGE_BACKLIGHT_EN:
+ gpio_set_value(config.backlight_en.gpio, 1);
+ break;
- init_lcd_pinmux(&config);
+ case STAGE_DONE:
+ break;
+ }
+
+ /* set up timer for next stage */
+ timer_next = timer_get_us() + config.panel_timings[stage] * 1000;
+
+ /* move to next stage */
+ stage++;
return 0;
}
+
+int tegra_lcd_check_next_stage(const void *blob, int wait)
+{
+ if (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();
+
+ if (delay > 0) {
+ if (wait)
+ udelay(delay);
+ else
+ return 0;
+ }
+ }
+
+ if (handle_stage(blob))
+ return -1;
+ } while (wait && stage != STAGE_DONE);
+ return 0;
+}
+
+void lcd_enable(void)
+{
+ /* This will be done when tegra_lcd_check_next_stage() is called */
+ tegra_lcd_check_next_stage(gd->blob, 1);
+}