u-boot-brain/board/cm_t35/display.c
Jeroen Hofstee f1d205a19c common/lcd.c: cleanup use of global variables
console_col, console_row, lcd_line_length, lcd_console_address had
to be declared in board / driver specific code, but were not actually
used there on many boards. Get rid of the global variables.

for completeness, the ack of Bo Shen is for the atmel part
Cc: Alessandro Rubini <rubini@unipv.it>
Cc: Anatolij Gustschin <agust@denx.de>
Cc: Bo Shen <voice.shen@atmel.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Vasut <marek.vasut@gmail.com>
Cc: Minkyu Kang <mk7.kang@samsung.com>
Cc: Nikita Kiryanov <nikita@compulab.co.il>
Cc: Simon Glass <sjg@chromium.org>
Cc: Stelian Pop <stelian@popies.net>
Cc: Tom Warren <twarren@nvidia.com>
Acked-by: Bo Shen <voice.shen@atmel.com>
Signed-off-by: Jeroen Hofstee <jeroen@myspectrum.nl>
[agust: rebased and fixed cm_t35 board]
Signed-off-by: Anatolij Gustschin <agust@denx.de>
2013-03-21 10:11:17 +01:00

423 lines
12 KiB
C

/*
* (C) Copyright 2012 CompuLab, Ltd. <www.compulab.co.il>
*
* Authors: Nikita Kiryanov <nikita@compulab.co.il>
*
* Parsing code based on linux/drivers/video/pxafb.c
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc.
*/
#include <common.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <stdio_dev.h>
#include <asm/arch/dss.h>
#include <lcd.h>
#include <asm/arch-omap3/dss.h>
DECLARE_GLOBAL_DATA_PTR;
enum display_type {
NONE,
DVI,
DVI_CUSTOM,
};
#define CMAP_ADDR 0x80100000
/*
* The frame buffer is allocated before we have the chance to parse user input.
* To make sure enough memory is allocated for all resolutions, we define
* vl_{col | row} to the maximal resolution supported by OMAP3.
*/
vidinfo_t panel_info = {
.vl_col = 1400,
.vl_row = 1050,
.vl_bpix = LCD_BPP,
.cmap = (ushort *)CMAP_ADDR,
};
static struct panel_config panel_cfg;
static enum display_type lcd_def;
/*
* A note on DVI presets;
* U-Boot can convert 8 bit BMP data to 16 bit BMP data, and OMAP DSS can
* convert 16 bit data into 24 bit data. Thus, GFXFORMAT_RGB16 allows us to
* support two BMP types with one setting.
*/
static const struct panel_config preset_dvi_640X480 = {
.lcd_size = PANEL_LCD_SIZE(640, 480),
.timing_h = DSS_HBP(48) | DSS_HFP(16) | DSS_HSW(96),
.timing_v = DSS_VBP(33) | DSS_VFP(10) | DSS_VSW(2),
.divisor = 12 | (1 << 16),
.data_lines = LCD_INTERFACE_24_BIT,
.panel_type = ACTIVE_DISPLAY,
.load_mode = 2,
.gfx_format = GFXFORMAT_RGB16,
};
static const struct panel_config preset_dvi_800X600 = {
.lcd_size = PANEL_LCD_SIZE(800, 600),
.timing_h = DSS_HBP(88) | DSS_HFP(40) | DSS_HSW(128),
.timing_v = DSS_VBP(23) | DSS_VFP(1) | DSS_VSW(4),
.divisor = 8 | (1 << 16),
.data_lines = LCD_INTERFACE_24_BIT,
.panel_type = ACTIVE_DISPLAY,
.load_mode = 2,
.gfx_format = GFXFORMAT_RGB16,
};
static const struct panel_config preset_dvi_1024X768 = {
.lcd_size = PANEL_LCD_SIZE(1024, 768),
.timing_h = DSS_HBP(160) | DSS_HFP(24) | DSS_HSW(136),
.timing_v = DSS_VBP(29) | DSS_VFP(3) | DSS_VSW(6),
.divisor = 5 | (1 << 16),
.data_lines = LCD_INTERFACE_24_BIT,
.panel_type = ACTIVE_DISPLAY,
.load_mode = 2,
.gfx_format = GFXFORMAT_RGB16,
};
static const struct panel_config preset_dvi_1152X864 = {
.lcd_size = PANEL_LCD_SIZE(1152, 864),
.timing_h = DSS_HBP(256) | DSS_HFP(64) | DSS_HSW(128),
.timing_v = DSS_VBP(32) | DSS_VFP(1) | DSS_VSW(3),
.divisor = 3 | (1 << 16),
.data_lines = LCD_INTERFACE_24_BIT,
.panel_type = ACTIVE_DISPLAY,
.load_mode = 2,
.gfx_format = GFXFORMAT_RGB16,
};
static const struct panel_config preset_dvi_1280X960 = {
.lcd_size = PANEL_LCD_SIZE(1280, 960),
.timing_h = DSS_HBP(312) | DSS_HFP(96) | DSS_HSW(112),
.timing_v = DSS_VBP(36) | DSS_VFP(1) | DSS_VSW(3),
.divisor = 3 | (1 << 16),
.data_lines = LCD_INTERFACE_24_BIT,
.panel_type = ACTIVE_DISPLAY,
.load_mode = 2,
.gfx_format = GFXFORMAT_RGB16,
};
static const struct panel_config preset_dvi_1280X1024 = {
.lcd_size = PANEL_LCD_SIZE(1280, 1024),
.timing_h = DSS_HBP(248) | DSS_HFP(48) | DSS_HSW(112),
.timing_v = DSS_VBP(38) | DSS_VFP(1) | DSS_VSW(3),
.divisor = 3 | (1 << 16),
.data_lines = LCD_INTERFACE_24_BIT,
.panel_type = ACTIVE_DISPLAY,
.load_mode = 2,
.gfx_format = GFXFORMAT_RGB16,
};
/*
* set_resolution_params()
*
* Due to usage of multiple display related APIs resolution data is located in
* more than one place. This function updates them all.
*/
static void set_resolution_params(int x, int y)
{
panel_cfg.lcd_size = PANEL_LCD_SIZE(x, y);
panel_info.vl_col = x;
panel_info.vl_row = y;
lcd_line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
}
static void set_preset(const struct panel_config preset, int x_res, int y_res)
{
panel_cfg = preset;
set_resolution_params(x_res, y_res);
}
static enum display_type set_dvi_preset(const struct panel_config preset,
int x_res, int y_res)
{
set_preset(preset, x_res, y_res);
return DVI;
}
/*
* parse_mode() - parse the mode parameter of custom lcd settings
*
* @mode: <res_x>x<res_y>
*
* Returns -1 on error, 0 on success.
*/
static int parse_mode(const char *mode)
{
unsigned int modelen = strlen(mode);
int res_specified = 0;
unsigned int xres = 0, yres = 0;
int yres_specified = 0;
int i;
for (i = modelen - 1; i >= 0; i--) {
switch (mode[i]) {
case 'x':
if (!yres_specified) {
yres = simple_strtoul(&mode[i + 1], NULL, 0);
yres_specified = 1;
} else {
goto done_parsing;
}
break;
case '0' ... '9':
break;
default:
goto done_parsing;
}
}
if (i < 0 && yres_specified) {
xres = simple_strtoul(mode, NULL, 0);
res_specified = 1;
}
done_parsing:
if (res_specified) {
set_resolution_params(xres, yres);
} else {
printf("LCD: invalid mode: %s\n", mode);
return -1;
}
return 0;
}
#define PIXEL_CLK_NUMERATOR (26 * 432 / 39)
/*
* parse_pixclock() - Parse the pixclock parameter of custom lcd settings
*
* @pixclock: the desired pixel clock
*
* Returns -1 on error, 0 on success.
*
* Handling the pixel_clock:
*
* Pixel clock is defined in the OMAP35x TRM as follows:
* pixel_clock =
* (SYS_CLK * 2 * PRCM.CM_CLKSEL2_PLL[18:8]) /
* (DSS.DISPC_DIVISOR[23:16] * DSS.DISPC_DIVISOR[6:0] *
* PRCM.CM_CLKSEL_DSS[4:0] * (PRCM.CM_CLKSEL2_PLL[6:0] + 1))
*
* In practice, this means that in order to set the
* divisor for the desired pixel clock one needs to
* solve the following equation:
*
* 26 * 432 / (39 * <pixel_clock>) = DSS.DISPC_DIVISOR[6:0]
*
* NOTE: the explicit equation above is reduced. Do not
* try to infer anything from these numbers.
*/
static int parse_pixclock(char *pixclock)
{
int divisor, pixclock_val;
char *pixclk_start = pixclock;
pixclock_val = simple_strtoul(pixclock, &pixclock, 10);
divisor = DIV_ROUND_UP(PIXEL_CLK_NUMERATOR, pixclock_val);
/* 0 and 1 are illegal values for PCD */
if (divisor <= 1)
divisor = 2;
panel_cfg.divisor = divisor | (1 << 16);
if (pixclock[0] != '\0') {
printf("LCD: invalid value for pixclock:%s\n", pixclk_start);
return -1;
}
return 0;
}
/*
* parse_setting() - parse a single setting of custom lcd parameters
*
* @setting: The custom lcd setting <name>:<value>
*
* Returns -1 on failure, 0 on success.
*/
static int parse_setting(char *setting)
{
int num_val;
char *setting_start = setting;
if (!strncmp(setting, "mode:", 5)) {
return parse_mode(setting + 5);
} else if (!strncmp(setting, "pixclock:", 9)) {
return parse_pixclock(setting + 9);
} else if (!strncmp(setting, "left:", 5)) {
num_val = simple_strtoul(setting + 5, &setting, 0);
panel_cfg.timing_h |= DSS_HBP(num_val);
} else if (!strncmp(setting, "right:", 6)) {
num_val = simple_strtoul(setting + 6, &setting, 0);
panel_cfg.timing_h |= DSS_HFP(num_val);
} else if (!strncmp(setting, "upper:", 6)) {
num_val = simple_strtoul(setting + 6, &setting, 0);
panel_cfg.timing_v |= DSS_VBP(num_val);
} else if (!strncmp(setting, "lower:", 6)) {
num_val = simple_strtoul(setting + 6, &setting, 0);
panel_cfg.timing_v |= DSS_VFP(num_val);
} else if (!strncmp(setting, "hsynclen:", 9)) {
num_val = simple_strtoul(setting + 9, &setting, 0);
panel_cfg.timing_h |= DSS_HSW(num_val);
} else if (!strncmp(setting, "vsynclen:", 9)) {
num_val = simple_strtoul(setting + 9, &setting, 0);
panel_cfg.timing_v |= DSS_VSW(num_val);
} else if (!strncmp(setting, "hsync:", 6)) {
if (simple_strtoul(setting + 6, &setting, 0) == 0)
panel_cfg.pol_freq |= DSS_IHS;
else
panel_cfg.pol_freq &= ~DSS_IHS;
} else if (!strncmp(setting, "vsync:", 6)) {
if (simple_strtoul(setting + 6, &setting, 0) == 0)
panel_cfg.pol_freq |= DSS_IVS;
else
panel_cfg.pol_freq &= ~DSS_IVS;
} else if (!strncmp(setting, "outputen:", 9)) {
if (simple_strtoul(setting + 9, &setting, 0) == 0)
panel_cfg.pol_freq |= DSS_IEO;
else
panel_cfg.pol_freq &= ~DSS_IEO;
} else if (!strncmp(setting, "pixclockpol:", 12)) {
if (simple_strtoul(setting + 12, &setting, 0) == 0)
panel_cfg.pol_freq |= DSS_IPC;
else
panel_cfg.pol_freq &= ~DSS_IPC;
} else if (!strncmp(setting, "active", 6)) {
panel_cfg.panel_type = ACTIVE_DISPLAY;
return 0; /* Avoid sanity check below */
} else if (!strncmp(setting, "passive", 7)) {
panel_cfg.panel_type = PASSIVE_DISPLAY;
return 0; /* Avoid sanity check below */
} else if (!strncmp(setting, "display:", 8)) {
if (!strncmp(setting + 8, "dvi", 3)) {
lcd_def = DVI_CUSTOM;
return 0; /* Avoid sanity check below */
}
} else {
printf("LCD: unknown option %s\n", setting_start);
return -1;
}
if (setting[0] != '\0') {
printf("LCD: invalid value for %s\n", setting_start);
return -1;
}
return 0;
}
/*
* env_parse_customlcd() - parse custom lcd params from an environment variable.
*
* @custom_lcd_params: The environment variable containing the lcd params.
*
* Returns -1 on failure, 0 on success.
*/
static int parse_customlcd(char *custom_lcd_params)
{
char params_cpy[160];
char *setting;
strncpy(params_cpy, custom_lcd_params, 160);
setting = strtok(params_cpy, ",");
while (setting) {
if (parse_setting(setting) < 0)
return -1;
setting = strtok(NULL, ",");
}
/* Currently we don't support changing this via custom lcd params */
panel_cfg.data_lines = LCD_INTERFACE_24_BIT;
panel_cfg.gfx_format = GFXFORMAT_RGB16; /* See dvi predefines note */
return 0;
}
/*
* env_parse_displaytype() - parse display type.
*
* Parses the environment variable "displaytype", which contains the
* name of the display type or preset, in which case it applies its
* configurations.
*
* Returns the type of display that was specified.
*/
static enum display_type env_parse_displaytype(char *displaytype)
{
if (!strncmp(displaytype, "dvi640x480", 10))
return set_dvi_preset(preset_dvi_640X480, 640, 480);
else if (!strncmp(displaytype, "dvi800x600", 10))
return set_dvi_preset(preset_dvi_800X600, 800, 600);
else if (!strncmp(displaytype, "dvi1024x768", 11))
return set_dvi_preset(preset_dvi_1024X768, 1024, 768);
else if (!strncmp(displaytype, "dvi1152x864", 11))
return set_dvi_preset(preset_dvi_1152X864, 1152, 864);
else if (!strncmp(displaytype, "dvi1280x960", 11))
return set_dvi_preset(preset_dvi_1280X960, 1280, 960);
else if (!strncmp(displaytype, "dvi1280x1024", 12))
return set_dvi_preset(preset_dvi_1280X1024, 1280, 1024);
return NONE;
}
void *lcd_base;
void lcd_ctrl_init(void *lcdbase)
{
struct prcm *prcm = (struct prcm *)PRCM_BASE;
char *custom_lcd;
char *displaytype = getenv("displaytype");
if (displaytype == NULL)
return;
lcd_def = env_parse_displaytype(displaytype);
/* If we did not recognize the preset, check if it's an env variable */
if (lcd_def == NONE) {
custom_lcd = getenv(displaytype);
if (custom_lcd == NULL || parse_customlcd(custom_lcd) < 0)
return;
}
panel_cfg.frame_buffer = lcdbase;
omap3_dss_panel_config(&panel_cfg);
/*
* Pixel clock is defined with many divisions and only few
* multiplications of the system clock. Since DSS FCLK divisor is set
* to 16 by default, we need to set it to a smaller value, like 3
* (chosen via trial and error).
*/
clrsetbits_le32(&prcm->clksel_dss, 0xF, 3);
}
void lcd_enable(void)
{
if (lcd_def == DVI || lcd_def == DVI_CUSTOM) {
gpio_direction_output(54, 0); /* Turn on DVI */
omap3_dss_enable();
}
}
void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) {}