fusee: update display code for mariko

This commit is contained in:
hexkyz 2020-11-30 19:05:39 +00:00 committed by SciresM
parent 3b05315616
commit 3e8688e19e
15 changed files with 3347 additions and 1818 deletions

View file

@ -26,28 +26,37 @@
#include "gpio.h"
#include "pinmux.h"
#include "car.h"
#include "apb_misc.h"
#include "di.inl"
static uint32_t _display_ver = 0;
static uint32_t g_lcd_vendor = 0;
static void exec_cfg(uint32_t *base, const cfg_op_t *ops, uint32_t num_ops)
{
for (uint32_t i = 0; i < num_ops; i++)
base[ops[i].off] = ops[i].val;
static void do_dsi_sleep_or_register_writes(const dsi_sleep_or_register_write_t *writes, uint32_t num_writes) {
for (uint32_t i = 0; i < num_writes; i++) {
if (writes[i].kind == 1) {
udelay(1000 * writes[i].offset);
} else {
*(volatile uint32_t *)(DSI_BASE + sizeof(uint32_t) * writes[i].offset) = writes[i].value;
}
}
}
static void _display_dsi_wait(uint32_t timeout, uint32_t off, uint32_t mask)
{
static void do_register_writes(uint32_t base_address, const register_write_t *writes, uint32_t num_writes) {
for (uint32_t i = 0; i < num_writes; i++) {
*(volatile uint32_t *)(base_address + writes[i].offset) = writes[i].value;
}
}
static void dsi_wait(uint32_t timeout, uint32_t offset, uint32_t mask, uint32_t delay) {
uint32_t end = get_time_us() + timeout;
while ((get_time_us() < end) && (MAKE_DSI_REG(off) & mask)) {
while ((get_time_us() < end) && (MAKE_DSI_REG(offset) & mask)) {
/* Wait. */
}
udelay(5);
udelay(delay);
}
void display_init()
{
void display_init_erista(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pmc_t *pmc = pmc_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
@ -55,8 +64,6 @@ void display_init()
/* Power on. */
uint8_t val = 0xD0;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_LDO0_CFG, &val, 1);
val = 0x09;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_GPIO7, &val, 1);
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
car->rst_dev_h_clr = 0x1010000;
@ -107,11 +114,19 @@ void display_init()
gpio_write(GPIO_LCD_BL_EN, GPIO_LEVEL_HIGH);
/* Configure display interface and display. */
MAKE_MIPI_CAL_REG(0x60) = 0;
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
exec_cfg((uint32_t *)CAR_BASE, _display_config_1, 4);
exec_cfg((uint32_t *)DI_BASE, _display_config_2, 94);
exec_cfg((uint32_t *)DSI_BASE, _display_config_3, 60);
do_register_writes(CAR_BASE, display_config_plld_01_erista, 4);
do_register_writes(DI_BASE, display_config_dc_01, 94);
do_register_writes(DSI_BASE, display_config_dsi_01_init_01, 8);
do_register_writes(DSI_BASE, display_config_dsi_01_init_02_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_03, 13);
do_register_writes(DSI_BASE, display_config_dsi_01_init_04_erista, 0);
do_register_writes(DSI_BASE, display_config_dsi_01_init_05, 11);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_06, 12);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_07, 14);
udelay(10000);
@ -123,57 +138,235 @@ void display_init()
MAKE_DSI_REG(DSI_BTA_TIMING) = 0x50204;
MAKE_DSI_REG(DSI_WR_DATA) = 0x337;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO));
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_WR_DATA) = 0x406;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO));
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_HOST_CONTROL) = (DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
_display_dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA);
dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA, 5000);
udelay(5000);
/* Parse LCD vendor. */
uint32_t host_response[3];
for (uint32_t i = 0; i < 3; i++) {
host_response[i] = MAKE_DSI_REG(DSI_RD_DATA);
}
_display_ver = MAKE_DSI_REG(DSI_RD_DATA);
/* The last word from host response is:
Bits 0-7: FAB
Bits 8-15: REV
Bits 16-23: Minor REV
*/
if ((host_response[2] & 0xFF) == 0x10) {
g_lcd_vendor = 0;
} else {
g_lcd_vendor = (host_response[2] >> 8) & 0xFF00;
}
g_lcd_vendor = (g_lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
if (_display_ver == 0x10)
exec_cfg((uint32_t *)DSI_BASE, _display_config_4, 43);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1105;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
udelay(180000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x2905;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
/* LCD vendor specific configuration. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_init_01, 48);
break;
case 0xF20: /* Innolux first revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev1_specific_init_01, 14);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_init_01, 14);
break;
default:
/* Innolux and AUO second revision screens. */
if ((g_lcd_vendor | 0x10) == 0x1030) {
do_dsi_sleep_or_register_writes(display_config_innolux_auo_rev2_specific_init_01, 5);
}
break;
}
udelay(20000);
exec_cfg((uint32_t *)DSI_BASE, _display_config_5, 21);
exec_cfg((uint32_t *)CAR_BASE, _display_config_6, 3);
do_register_writes(CAR_BASE, display_config_plld_02_erista, 3);
do_register_writes(DSI_BASE, display_config_dsi_01_init_08, 1);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_09, 19);
MAKE_DI_REG(DC_DISP_DISP_CLOCK_CONTROL) = 4;
exec_cfg((uint32_t *)DSI_BASE, _display_config_7, 10);
do_register_writes(DSI_BASE, display_config_dsi_01_init_10, 10);
udelay(10000);
exec_cfg((uint32_t *)MIPI_CAL_BASE, _display_config_8, 6);
exec_cfg((uint32_t *)DSI_BASE, _display_config_9, 4);
exec_cfg((uint32_t *)MIPI_CAL_BASE, _display_config_10, 16);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_01, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_erista, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_erista, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_erista, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
udelay(10000);
exec_cfg((uint32_t *)DI_BASE, _display_config_11, 113);
do_register_writes(DI_BASE, display_config_dc_02, 113);
}
void display_backlight(bool enable)
{
/* Enable Backlight PWM. */
gpio_write(GPIO_LCD_BL_PWM, enable ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW);
void display_init_mariko(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pmc_t *pmc = pmc_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
/* Power on. */
uint8_t val = 0x3A;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_SD2, &val, 1);
val = 0x71;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_SD2_CFG, &val, 1);
val = 0xD0;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_LDO0_CFG, &val, 1);
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
car->rst_dev_h_clr = 0x1010000;
car->clk_enb_h_set = 0x1010000;
car->rst_dev_l_clr = 0x18000000;
car->clk_enb_l_set = 0x18000000;
car->clk_enb_x_set = 0x20000;
car->clk_source_uart_fst_mipi_cal = 0xA;
car->clk_enb_w_set = 0x80000;
car->clk_source_dsia_lp = 0xA;
/* DPD idle. */
pmc->io_dpd_req = 0x40000000;
pmc->io_dpd2_req = 0x40000000;
/* Configure pins. */
pinmux->nfc_en &= ~PINMUX_TRISTATE;
pinmux->nfc_int &= ~PINMUX_TRISTATE;
pinmux->lcd_bl_pwm &= ~PINMUX_TRISTATE;
pinmux->lcd_bl_en &= ~PINMUX_TRISTATE;
pinmux->lcd_rst &= ~PINMUX_TRISTATE;
/* Configure Backlight +-5V GPIOs. */
gpio_configure_mode(GPIO_LCD_BL_P5V, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_N5V, GPIO_MODE_GPIO);
gpio_configure_direction(GPIO_LCD_BL_P5V, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_N5V, GPIO_DIRECTION_OUTPUT);
/* Enable Backlight +5V. */
gpio_write(GPIO_LCD_BL_P5V, GPIO_LEVEL_HIGH);
udelay(10000);
/* Enable Backlight -5V. */
gpio_write(GPIO_LCD_BL_N5V, GPIO_LEVEL_HIGH);
udelay(10000);
/* Configure Backlight PWM, EN and RST GPIOs. */
gpio_configure_mode(GPIO_LCD_BL_PWM, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_EN, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_RST, GPIO_MODE_GPIO);
gpio_configure_direction(GPIO_LCD_BL_PWM, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_EN, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_RST, GPIO_DIRECTION_OUTPUT);
/* Enable Backlight EN. */
gpio_write(GPIO_LCD_BL_EN, GPIO_LEVEL_HIGH);
/* Configure display interface and display. */
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG0) = 0;
MAKE_APB_MISC_REG(0xAC0) = 0;
do_register_writes(CAR_BASE, display_config_plld_01_mariko, 4);
do_register_writes(DI_BASE, display_config_dc_01, 94);
do_register_writes(DSI_BASE, display_config_dsi_01_init_01, 8);
do_register_writes(DSI_BASE, display_config_dsi_01_init_02_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_03, 13);
do_register_writes(DSI_BASE, display_config_dsi_01_init_04_mariko, 7);
do_register_writes(DSI_BASE, display_config_dsi_01_init_05, 11);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_06, 12);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_07, 14);
udelay(10000);
/* Enable Backlight RST. */
gpio_write(GPIO_LCD_BL_RST, GPIO_LEVEL_HIGH);
udelay(60000);
MAKE_DSI_REG(DSI_BTA_TIMING) = 0x50204;
MAKE_DSI_REG(DSI_WR_DATA) = 0x337;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_WR_DATA) = 0x406;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_HOST_CONTROL) = (DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA, 5000);
/* Parse LCD vendor. */
uint32_t host_response[3];
for (uint32_t i = 0; i < 3; i++) {
host_response[i] = MAKE_DSI_REG(DSI_RD_DATA);
}
/* The last word from host response is:
Bits 0-7: FAB
Bits 8-15: REV
Bits 16-23: Minor REV
*/
if ((host_response[2] & 0xFF) == 0x10) {
g_lcd_vendor = 0;
} else {
g_lcd_vendor = (host_response[2] >> 8) & 0xFF00;
}
g_lcd_vendor = (g_lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
/* LCD vendor specific configuration. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_init_01, 48);
break;
case 0xF20: /* Innolux first revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev1_specific_init_01, 14);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_init_01, 14);
break;
default:
/* Innolux and AUO second revision screens. */
if ((g_lcd_vendor | 0x10) == 0x1030) {
do_dsi_sleep_or_register_writes(display_config_innolux_auo_rev2_specific_init_01, 5);
}
break;
}
udelay(20000);
do_register_writes(CAR_BASE, display_config_plld_02_mariko, 3);
do_register_writes(DSI_BASE, display_config_dsi_01_init_08, 1);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_09, 19);
MAKE_DI_REG(DC_DISP_DISP_CLOCK_CONTROL) = 4;
do_register_writes(DSI_BASE, display_config_dsi_01_init_10, 10);
udelay(10000);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_01, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_mariko, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_mariko, 7);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_mariko, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_mariko, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_mariko, 7);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_mariko, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
udelay(10000);
do_register_writes(DI_BASE, display_config_dc_02, 113);
}
void display_end()
{
void display_end_erista(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
@ -183,16 +376,41 @@ void display_end()
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 1;
MAKE_DSI_REG(DSI_WR_DATA) = 0x2805;
/* Wait 5 frames. */
uint32_t start_val = MAKE_HOST1X_REG(0x30A4);
while (MAKE_HOST1X_REG(0x30A4) < start_val + 5) {
/* Wait. */
}
MAKE_DI_REG(DC_CMD_STATE_ACCESS) = (READ_MUX | WRITE_MUX);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 0;
exec_cfg((uint32_t *)DI_BASE, _display_config_12, 17);
exec_cfg((uint32_t *)DSI_BASE, _display_config_13, 16);
do_register_writes(CAR_BASE, display_config_plld_01_erista, 4);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_01, 2);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_02, 13);
udelay(10000);
if (_display_ver == 0x10)
exec_cfg((uint32_t *)DSI_BASE, _display_config_14, 22);
/* LCD vendor specific shutdown. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_fini_01, 22);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_fini_01, 38);
break;
case 0x1020: /* Innolux second revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev2_specific_fini_01, 10);
break;
case 0x1030: /* AUO second revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev2_specific_fini_01, 10);
break;
default:
break;
}
udelay(5000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1005;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
@ -230,9 +448,95 @@ void display_end()
pinmux->lcd_bl_pwm = (((pinmux->lcd_bl_pwm >> 2) << 2) | 1);
}
void display_color_screen(uint32_t color)
{
exec_cfg((uint32_t *)DI_BASE, cfg_display_one_color, 8);
void display_end_mariko(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
/* Disable Backlight. */
display_backlight(false);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 1;
MAKE_DSI_REG(DSI_WR_DATA) = 0x2805;
/* Wait 5 frames. */
uint32_t start_val = MAKE_HOST1X_REG(0x30A4);
while (MAKE_HOST1X_REG(0x30A4) < start_val + 5) {
/* Wait. */
}
MAKE_DI_REG(DC_CMD_STATE_ACCESS) = (READ_MUX | WRITE_MUX);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 0;
do_register_writes(CAR_BASE, display_config_plld_01_mariko, 4);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_01, 2);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_02, 13);
udelay(10000);
/* LCD vendor specific shutdown. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_fini_01, 22);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_fini_01, 38);
break;
case 0x1020: /* Innolux second revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev2_specific_fini_01, 10);
break;
case 0x1030: /* AUO second revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev2_specific_fini_01, 10);
break;
default:
break;
}
udelay(5000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1005;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
udelay(50000);
/* Disable Backlight RST. */
gpio_write(GPIO_LCD_BL_RST, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable Backlight -5V. */
gpio_write(GPIO_LCD_BL_N5V, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable Backlight +5V. */
gpio_write(GPIO_LCD_BL_P5V, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable clocks. */
car->rst_dev_h_set = 0x1010000;
car->clk_enb_h_clr = 0x1010000;
car->rst_dev_l_set = 0x18000000;
car->clk_enb_l_clr = 0x18000000;
MAKE_DSI_REG(DSI_PAD_CONTROL_0) = (DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF));
MAKE_DSI_REG(DSI_POWER_CONTROL) = 0;
/* Backlight PWM. */
gpio_configure_mode(GPIO_LCD_BL_PWM, GPIO_MODE_SFIO);
pinmux->lcd_bl_pwm = ((pinmux->lcd_bl_pwm & ~PINMUX_TRISTATE) | PINMUX_TRISTATE);
pinmux->lcd_bl_pwm = (((pinmux->lcd_bl_pwm >> 2) << 2) | 1);
}
void display_backlight(bool enable) {
/* Enable Backlight PWM. */
gpio_write(GPIO_LCD_BL_PWM, enable ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW);
}
void display_color_screen(uint32_t color) {
do_register_writes(DI_BASE, display_config_solid_color, 8);
/* Configure display to show single color. */
MAKE_DI_REG(DC_WIN_AD_WIN_OPTIONS) = 0;
@ -246,20 +550,19 @@ void display_color_screen(uint32_t color)
display_backlight(true);
}
uint32_t *display_init_framebuffer(void *address)
{
static cfg_op_t conf[sizeof(cfg_display_framebuffer)/sizeof(cfg_op_t)] = {0};
if (conf[0].val == 0) {
for (uint32_t i = 0; i < sizeof(cfg_display_framebuffer)/sizeof(cfg_op_t); i++) {
conf[i] = cfg_display_framebuffer[i];
uint32_t *display_init_framebuffer(void *address) {
static register_write_t conf[sizeof(display_config_frame_buffer)/sizeof(register_write_t)] = {0};
if (conf[0].value == 0) {
for (uint32_t i = 0; i < sizeof(display_config_frame_buffer)/sizeof(register_write_t); i++) {
conf[i] = display_config_frame_buffer[i];
}
}
uint32_t *lfb_addr = (uint32_t *)address;
conf[19].val = (uint32_t)address;
conf[19].value = (uint32_t)address;
/* This configures the framebuffer @ address with a resolution of 1280x720 (line stride 768). */
exec_cfg((uint32_t *)DI_BASE, conf, 32);
do_register_writes(DI_BASE, conf, 32);
udelay(35000);

View file

@ -33,6 +33,12 @@
#define MAKE_MIPI_CAL_REG(n) MAKE_REG32(MIPI_CAL_BASE + n)
#define MAKE_VIC_REG(n) MAKE_REG32(VIC_BASE + n)
/* Clock and reset registers. */
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
/* Display registers. */
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00
@ -238,6 +244,7 @@
#define DC_WIN_LINE_STRIDE 0x70A
#define DC_WIN_DV_CONTROL 0x70E
#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716
/* The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
#define DC_WINBUF_START_ADDR 0x800
@ -333,7 +340,7 @@
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
#define DSI_PAD_CONTROL_CD 0x4c
#define DSI_PAD_CONTROL_CD 0x4C
#define DSI_VIDEO_MODE_CONTROL 0x4E
#define DSI_PAD_CONTROL_1 0x4F
@ -346,22 +353,46 @@
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
#define DSI_PAD_CONTROL_4 0x52
#define DSI_PAD_CONTROL_5_MARIKO 0x53
#define DSI_PAD_CONTROL_6_MARIKO 0x54
#define DSI_PAD_CONTROL_7_MARIKO 0x55
#define DSI_INIT_SEQ_DATA_15 0x5F
#define DSI_INIT_SEQ_DATA_15_MARIKO 0x62
typedef struct _cfg_op_t
{
uint32_t off;
uint32_t val;
} cfg_op_t;
/* MIPI calibration registers. */
#define MIPI_CAL_MIPI_CAL_CTRL 0x0
#define MIPI_CAL_MIPI_CAL_AUTOCAL_CTRL0 0x4
#define MIPI_CAL_CIL_MIPI_CAL_STATUS 0x8
#define MIPI_CAL_CIL_MIPI_CAL_STATUS_2 0xC
#define MIPI_CAL_CILA_MIPI_CAL_CONFIG 0x14
#define MIPI_CAL_CILB_MIPI_CAL_CONFIG 0x18
#define MIPI_CAL_CILC_MIPI_CAL_CONFIG 0x1C
#define MIPI_CAL_CILD_MIPI_CAL_CONFIG 0x20
#define MIPI_CAL_CILE_MIPI_CAL_CONFIG 0x24
#define MIPI_CAL_CILF_MIPI_CAL_CONFIG 0x28
#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG 0x38
#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG 0x3C
#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG 0x40
#define MIPI_CAL_DSID_MIPI_CAL_CONFIG 0x44
#define MIPI_CAL_MIPI_BIAS_PAD_CFG0 0x58
#define MIPI_CAL_MIPI_BIAS_PAD_CFG1 0x5C
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 0x64
#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 0x68
#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 0x70
#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 0x74
void display_init();
void display_end();
/* Show one single color on the display. */
void display_color_screen(uint32_t color);
void display_init_erista(void);
void display_init_mariko(void);
void display_end_erista(void);
void display_end_mariko(void);
/* Switches screen backlight ON/OFF. */
void display_backlight(bool enable);
/* Show one single color on the display. */
void display_color_screen(uint32_t color);
/* Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */
uint32_t *display_init_framebuffer(void *address);

File diff suppressed because it is too large Load diff

View file

@ -99,7 +99,11 @@ static void setup_display(void) {
video_init(g_framebuffer);
/* Initialize the display. */
display_init();
if (fuse_get_soc_type() == 1) {
display_init_mariko();
} else {
display_init_erista();
}
/* Set the framebuffer. */
display_init_framebuffer(g_framebuffer);
@ -114,7 +118,11 @@ static void cleanup_display(void) {
display_backlight(false);
/* Terminate the display. */
display_end();
if (fuse_get_soc_type() == 1) {
display_end_mariko();
} else {
display_end_erista();
}
}
static void setup_env(void) {

View file

@ -125,7 +125,11 @@ static void _check_and_display_atmosphere_fatal_error(void) {
video_init((void *)0xC0000000);
/* Initialize the display. */
display_init();
if (fuse_get_soc_type() == 1) {
display_init_mariko();
} else {
display_init_erista();
}
/* Set the framebuffer. */
display_init_framebuffer((void *)0xC0000000);
@ -221,7 +225,11 @@ void check_and_display_panic(void) {
}
/* Initialize the display. */
display_init();
if (fuse_get_soc_type() == 1) {
display_init_mariko();
} else {
display_init_erista();
}
/* Fill the screen. */
display_color_screen(color);

View file

@ -130,7 +130,11 @@ __attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
video_init((void *)0xC0000000);
/* Initialize the display. */
display_init();
if (fuse_get_soc_type() == 1) {
display_init_mariko();
} else {
display_init_erista();
}
/* Set the framebuffer. */
display_init_framebuffer((void *)0xC0000000);

View file

@ -98,7 +98,11 @@ static ssize_t decode_utf8(uint32_t *out, const uint8_t *in) {
static void console_init_display(void) {
/* Initialize the display. */
display_init();
if (fuse_get_soc_type() == 1) {
display_init_mariko();
} else {
display_init_erista();
}
/* Set the framebuffer. */
display_init_framebuffer(g_framebuffer);
@ -198,7 +202,11 @@ int console_end(void) {
display_backlight(false);
/* Terminate the display. */
display_end();
if (fuse_get_soc_type() == 1) {
display_end_mariko();
} else {
display_end_erista();
}
/* Display is terminated. */
g_display_initialized = false;

View file

@ -26,28 +26,37 @@
#include "gpio.h"
#include "pinmux.h"
#include "car.h"
#include "apb_misc.h"
#include "di.inl"
static uint32_t _display_ver = 0;
static uint32_t g_lcd_vendor = 0;
static void exec_cfg(uint32_t *base, const cfg_op_t *ops, uint32_t num_ops)
{
for (uint32_t i = 0; i < num_ops; i++)
base[ops[i].off] = ops[i].val;
static void do_dsi_sleep_or_register_writes(const dsi_sleep_or_register_write_t *writes, uint32_t num_writes) {
for (uint32_t i = 0; i < num_writes; i++) {
if (writes[i].kind == 1) {
udelay(1000 * writes[i].offset);
} else {
*(volatile uint32_t *)(DSI_BASE + sizeof(uint32_t) * writes[i].offset) = writes[i].value;
}
}
}
static void _display_dsi_wait(uint32_t timeout, uint32_t off, uint32_t mask)
{
static void do_register_writes(uint32_t base_address, const register_write_t *writes, uint32_t num_writes) {
for (uint32_t i = 0; i < num_writes; i++) {
*(volatile uint32_t *)(base_address + writes[i].offset) = writes[i].value;
}
}
static void dsi_wait(uint32_t timeout, uint32_t offset, uint32_t mask, uint32_t delay) {
uint32_t end = get_time_us() + timeout;
while ((get_time_us() < end) && (MAKE_DSI_REG(off) & mask)) {
while ((get_time_us() < end) && (MAKE_DSI_REG(offset) & mask)) {
/* Wait. */
}
udelay(5);
udelay(delay);
}
void display_init()
{
void display_init_erista(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pmc_t *pmc = pmc_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
@ -55,8 +64,6 @@ void display_init()
/* Power on. */
uint8_t val = 0xD0;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_LDO0_CFG, &val, 1);
val = 0x09;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_GPIO7, &val, 1);
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
car->rst_dev_h_clr = 0x1010000;
@ -107,11 +114,19 @@ void display_init()
gpio_write(GPIO_LCD_BL_EN, GPIO_LEVEL_HIGH);
/* Configure display interface and display. */
MAKE_MIPI_CAL_REG(0x60) = 0;
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
exec_cfg((uint32_t *)CAR_BASE, _display_config_1, 4);
exec_cfg((uint32_t *)DI_BASE, _display_config_2, 94);
exec_cfg((uint32_t *)DSI_BASE, _display_config_3, 60);
do_register_writes(CAR_BASE, display_config_plld_01_erista, 4);
do_register_writes(DI_BASE, display_config_dc_01, 94);
do_register_writes(DSI_BASE, display_config_dsi_01_init_01, 8);
do_register_writes(DSI_BASE, display_config_dsi_01_init_02_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_03, 13);
do_register_writes(DSI_BASE, display_config_dsi_01_init_04_erista, 0);
do_register_writes(DSI_BASE, display_config_dsi_01_init_05, 11);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_06, 12);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_07, 14);
udelay(10000);
@ -123,57 +138,235 @@ void display_init()
MAKE_DSI_REG(DSI_BTA_TIMING) = 0x50204;
MAKE_DSI_REG(DSI_WR_DATA) = 0x337;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO));
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_WR_DATA) = 0x406;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO));
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_HOST_CONTROL) = (DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
_display_dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA);
dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA, 5000);
udelay(5000);
/* Parse LCD vendor. */
uint32_t host_response[3];
for (uint32_t i = 0; i < 3; i++) {
host_response[i] = MAKE_DSI_REG(DSI_RD_DATA);
}
_display_ver = MAKE_DSI_REG(DSI_RD_DATA);
/* The last word from host response is:
Bits 0-7: FAB
Bits 8-15: REV
Bits 16-23: Minor REV
*/
if ((host_response[2] & 0xFF) == 0x10) {
g_lcd_vendor = 0;
} else {
g_lcd_vendor = (host_response[2] >> 8) & 0xFF00;
}
g_lcd_vendor = (g_lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
if (_display_ver == 0x10)
exec_cfg((uint32_t *)DSI_BASE, _display_config_4, 43);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1105;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
udelay(180000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x2905;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
/* LCD vendor specific configuration. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_init_01, 48);
break;
case 0xF20: /* Innolux first revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev1_specific_init_01, 14);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_init_01, 14);
break;
default:
/* Innolux and AUO second revision screens. */
if ((g_lcd_vendor | 0x10) == 0x1030) {
do_dsi_sleep_or_register_writes(display_config_innolux_auo_rev2_specific_init_01, 5);
}
break;
}
udelay(20000);
exec_cfg((uint32_t *)DSI_BASE, _display_config_5, 21);
exec_cfg((uint32_t *)CAR_BASE, _display_config_6, 3);
do_register_writes(CAR_BASE, display_config_plld_02_erista, 3);
do_register_writes(DSI_BASE, display_config_dsi_01_init_08, 1);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_09, 19);
MAKE_DI_REG(DC_DISP_DISP_CLOCK_CONTROL) = 4;
exec_cfg((uint32_t *)DSI_BASE, _display_config_7, 10);
do_register_writes(DSI_BASE, display_config_dsi_01_init_10, 10);
udelay(10000);
exec_cfg((uint32_t *)MIPI_CAL_BASE, _display_config_8, 6);
exec_cfg((uint32_t *)DSI_BASE, _display_config_9, 4);
exec_cfg((uint32_t *)MIPI_CAL_BASE, _display_config_10, 16);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_01, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_erista, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_erista, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_erista, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
udelay(10000);
exec_cfg((uint32_t *)DI_BASE, _display_config_11, 113);
do_register_writes(DI_BASE, display_config_dc_02, 113);
}
void display_backlight(bool enable)
{
/* Enable Backlight PWM. */
gpio_write(GPIO_LCD_BL_PWM, enable ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW);
void display_init_mariko(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pmc_t *pmc = pmc_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
/* Power on. */
uint8_t val = 0x3A;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_SD2, &val, 1);
val = 0x71;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_SD2_CFG, &val, 1);
val = 0xD0;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_LDO0_CFG, &val, 1);
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
car->rst_dev_h_clr = 0x1010000;
car->clk_enb_h_set = 0x1010000;
car->rst_dev_l_clr = 0x18000000;
car->clk_enb_l_set = 0x18000000;
car->clk_enb_x_set = 0x20000;
car->clk_source_uart_fst_mipi_cal = 0xA;
car->clk_enb_w_set = 0x80000;
car->clk_source_dsia_lp = 0xA;
/* DPD idle. */
pmc->io_dpd_req = 0x40000000;
pmc->io_dpd2_req = 0x40000000;
/* Configure pins. */
pinmux->nfc_en &= ~PINMUX_TRISTATE;
pinmux->nfc_int &= ~PINMUX_TRISTATE;
pinmux->lcd_bl_pwm &= ~PINMUX_TRISTATE;
pinmux->lcd_bl_en &= ~PINMUX_TRISTATE;
pinmux->lcd_rst &= ~PINMUX_TRISTATE;
/* Configure Backlight +-5V GPIOs. */
gpio_configure_mode(GPIO_LCD_BL_P5V, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_N5V, GPIO_MODE_GPIO);
gpio_configure_direction(GPIO_LCD_BL_P5V, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_N5V, GPIO_DIRECTION_OUTPUT);
/* Enable Backlight +5V. */
gpio_write(GPIO_LCD_BL_P5V, GPIO_LEVEL_HIGH);
udelay(10000);
/* Enable Backlight -5V. */
gpio_write(GPIO_LCD_BL_N5V, GPIO_LEVEL_HIGH);
udelay(10000);
/* Configure Backlight PWM, EN and RST GPIOs. */
gpio_configure_mode(GPIO_LCD_BL_PWM, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_EN, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_RST, GPIO_MODE_GPIO);
gpio_configure_direction(GPIO_LCD_BL_PWM, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_EN, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_RST, GPIO_DIRECTION_OUTPUT);
/* Enable Backlight EN. */
gpio_write(GPIO_LCD_BL_EN, GPIO_LEVEL_HIGH);
/* Configure display interface and display. */
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG0) = 0;
MAKE_APB_MISC_REG(0xAC0) = 0;
do_register_writes(CAR_BASE, display_config_plld_01_mariko, 4);
do_register_writes(DI_BASE, display_config_dc_01, 94);
do_register_writes(DSI_BASE, display_config_dsi_01_init_01, 8);
do_register_writes(DSI_BASE, display_config_dsi_01_init_02_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_03, 13);
do_register_writes(DSI_BASE, display_config_dsi_01_init_04_mariko, 7);
do_register_writes(DSI_BASE, display_config_dsi_01_init_05, 11);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_06, 12);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_07, 14);
udelay(10000);
/* Enable Backlight RST. */
gpio_write(GPIO_LCD_BL_RST, GPIO_LEVEL_HIGH);
udelay(60000);
MAKE_DSI_REG(DSI_BTA_TIMING) = 0x50204;
MAKE_DSI_REG(DSI_WR_DATA) = 0x337;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_WR_DATA) = 0x406;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_HOST_CONTROL) = (DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA, 5000);
/* Parse LCD vendor. */
uint32_t host_response[3];
for (uint32_t i = 0; i < 3; i++) {
host_response[i] = MAKE_DSI_REG(DSI_RD_DATA);
}
/* The last word from host response is:
Bits 0-7: FAB
Bits 8-15: REV
Bits 16-23: Minor REV
*/
if ((host_response[2] & 0xFF) == 0x10) {
g_lcd_vendor = 0;
} else {
g_lcd_vendor = (host_response[2] >> 8) & 0xFF00;
}
g_lcd_vendor = (g_lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
/* LCD vendor specific configuration. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_init_01, 48);
break;
case 0xF20: /* Innolux first revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev1_specific_init_01, 14);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_init_01, 14);
break;
default:
/* Innolux and AUO second revision screens. */
if ((g_lcd_vendor | 0x10) == 0x1030) {
do_dsi_sleep_or_register_writes(display_config_innolux_auo_rev2_specific_init_01, 5);
}
break;
}
udelay(20000);
do_register_writes(CAR_BASE, display_config_plld_02_mariko, 3);
do_register_writes(DSI_BASE, display_config_dsi_01_init_08, 1);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_09, 19);
MAKE_DI_REG(DC_DISP_DISP_CLOCK_CONTROL) = 4;
do_register_writes(DSI_BASE, display_config_dsi_01_init_10, 10);
udelay(10000);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_01, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_mariko, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_mariko, 7);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_mariko, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_mariko, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_mariko, 7);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_mariko, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
udelay(10000);
do_register_writes(DI_BASE, display_config_dc_02, 113);
}
void display_end()
{
void display_end_erista(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
@ -183,16 +376,41 @@ void display_end()
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 1;
MAKE_DSI_REG(DSI_WR_DATA) = 0x2805;
/* Wait 5 frames. */
uint32_t start_val = MAKE_HOST1X_REG(0x30A4);
while (MAKE_HOST1X_REG(0x30A4) < start_val + 5) {
/* Wait. */
}
MAKE_DI_REG(DC_CMD_STATE_ACCESS) = (READ_MUX | WRITE_MUX);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 0;
exec_cfg((uint32_t *)DI_BASE, _display_config_12, 17);
exec_cfg((uint32_t *)DSI_BASE, _display_config_13, 16);
do_register_writes(CAR_BASE, display_config_plld_01_erista, 4);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_01, 2);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_02, 13);
udelay(10000);
if (_display_ver == 0x10)
exec_cfg((uint32_t *)DSI_BASE, _display_config_14, 22);
/* LCD vendor specific shutdown. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_fini_01, 22);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_fini_01, 38);
break;
case 0x1020: /* Innolux second revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev2_specific_fini_01, 10);
break;
case 0x1030: /* AUO second revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev2_specific_fini_01, 10);
break;
default:
break;
}
udelay(5000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1005;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
@ -230,9 +448,95 @@ void display_end()
pinmux->lcd_bl_pwm = (((pinmux->lcd_bl_pwm >> 2) << 2) | 1);
}
void display_color_screen(uint32_t color)
{
exec_cfg((uint32_t *)DI_BASE, cfg_display_one_color, 8);
void display_end_mariko(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
/* Disable Backlight. */
display_backlight(false);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 1;
MAKE_DSI_REG(DSI_WR_DATA) = 0x2805;
/* Wait 5 frames. */
uint32_t start_val = MAKE_HOST1X_REG(0x30A4);
while (MAKE_HOST1X_REG(0x30A4) < start_val + 5) {
/* Wait. */
}
MAKE_DI_REG(DC_CMD_STATE_ACCESS) = (READ_MUX | WRITE_MUX);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 0;
do_register_writes(CAR_BASE, display_config_plld_01_mariko, 4);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_01, 2);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_02, 13);
udelay(10000);
/* LCD vendor specific shutdown. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_fini_01, 22);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_fini_01, 38);
break;
case 0x1020: /* Innolux second revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev2_specific_fini_01, 10);
break;
case 0x1030: /* AUO second revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev2_specific_fini_01, 10);
break;
default:
break;
}
udelay(5000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1005;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
udelay(50000);
/* Disable Backlight RST. */
gpio_write(GPIO_LCD_BL_RST, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable Backlight -5V. */
gpio_write(GPIO_LCD_BL_N5V, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable Backlight +5V. */
gpio_write(GPIO_LCD_BL_P5V, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable clocks. */
car->rst_dev_h_set = 0x1010000;
car->clk_enb_h_clr = 0x1010000;
car->rst_dev_l_set = 0x18000000;
car->clk_enb_l_clr = 0x18000000;
MAKE_DSI_REG(DSI_PAD_CONTROL_0) = (DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF));
MAKE_DSI_REG(DSI_POWER_CONTROL) = 0;
/* Backlight PWM. */
gpio_configure_mode(GPIO_LCD_BL_PWM, GPIO_MODE_SFIO);
pinmux->lcd_bl_pwm = ((pinmux->lcd_bl_pwm & ~PINMUX_TRISTATE) | PINMUX_TRISTATE);
pinmux->lcd_bl_pwm = (((pinmux->lcd_bl_pwm >> 2) << 2) | 1);
}
void display_backlight(bool enable) {
/* Enable Backlight PWM. */
gpio_write(GPIO_LCD_BL_PWM, enable ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW);
}
void display_color_screen(uint32_t color) {
do_register_writes(DI_BASE, display_config_solid_color, 8);
/* Configure display to show single color. */
MAKE_DI_REG(DC_WIN_AD_WIN_OPTIONS) = 0;
@ -246,20 +550,19 @@ void display_color_screen(uint32_t color)
display_backlight(true);
}
uint32_t *display_init_framebuffer(void *address)
{
static cfg_op_t conf[sizeof(cfg_display_framebuffer)/sizeof(cfg_op_t)] = {0};
if (conf[0].val == 0) {
for (uint32_t i = 0; i < sizeof(cfg_display_framebuffer)/sizeof(cfg_op_t); i++) {
conf[i] = cfg_display_framebuffer[i];
uint32_t *display_init_framebuffer(void *address) {
static register_write_t conf[sizeof(display_config_frame_buffer)/sizeof(register_write_t)] = {0};
if (conf[0].value == 0) {
for (uint32_t i = 0; i < sizeof(display_config_frame_buffer)/sizeof(register_write_t); i++) {
conf[i] = display_config_frame_buffer[i];
}
}
uint32_t *lfb_addr = (uint32_t *)address;
conf[19].val = (uint32_t)address;
conf[19].value = (uint32_t)address;
/* This configures the framebuffer @ address with a resolution of 1280x720 (line stride 768). */
exec_cfg((uint32_t *)DI_BASE, conf, 32);
do_register_writes(DI_BASE, conf, 32);
udelay(35000);

View file

@ -33,6 +33,12 @@
#define MAKE_MIPI_CAL_REG(n) MAKE_REG32(MIPI_CAL_BASE + n)
#define MAKE_VIC_REG(n) MAKE_REG32(VIC_BASE + n)
/* Clock and reset registers. */
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
/* Display registers. */
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00
@ -238,6 +244,7 @@
#define DC_WIN_LINE_STRIDE 0x70A
#define DC_WIN_DV_CONTROL 0x70E
#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716
/* The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
#define DC_WINBUF_START_ADDR 0x800
@ -333,7 +340,7 @@
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
#define DSI_PAD_CONTROL_CD 0x4c
#define DSI_PAD_CONTROL_CD 0x4C
#define DSI_VIDEO_MODE_CONTROL 0x4E
#define DSI_PAD_CONTROL_1 0x4F
@ -346,22 +353,46 @@
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
#define DSI_PAD_CONTROL_4 0x52
#define DSI_PAD_CONTROL_5_MARIKO 0x53
#define DSI_PAD_CONTROL_6_MARIKO 0x54
#define DSI_PAD_CONTROL_7_MARIKO 0x55
#define DSI_INIT_SEQ_DATA_15 0x5F
#define DSI_INIT_SEQ_DATA_15_MARIKO 0x62
typedef struct _cfg_op_t
{
uint32_t off;
uint32_t val;
} cfg_op_t;
/* MIPI calibration registers. */
#define MIPI_CAL_MIPI_CAL_CTRL 0x0
#define MIPI_CAL_MIPI_CAL_AUTOCAL_CTRL0 0x4
#define MIPI_CAL_CIL_MIPI_CAL_STATUS 0x8
#define MIPI_CAL_CIL_MIPI_CAL_STATUS_2 0xC
#define MIPI_CAL_CILA_MIPI_CAL_CONFIG 0x14
#define MIPI_CAL_CILB_MIPI_CAL_CONFIG 0x18
#define MIPI_CAL_CILC_MIPI_CAL_CONFIG 0x1C
#define MIPI_CAL_CILD_MIPI_CAL_CONFIG 0x20
#define MIPI_CAL_CILE_MIPI_CAL_CONFIG 0x24
#define MIPI_CAL_CILF_MIPI_CAL_CONFIG 0x28
#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG 0x38
#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG 0x3C
#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG 0x40
#define MIPI_CAL_DSID_MIPI_CAL_CONFIG 0x44
#define MIPI_CAL_MIPI_BIAS_PAD_CFG0 0x58
#define MIPI_CAL_MIPI_BIAS_PAD_CFG1 0x5C
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 0x64
#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 0x68
#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 0x70
#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 0x74
void display_init();
void display_end();
/* Show one single color on the display. */
void display_color_screen(uint32_t color);
void display_init_erista(void);
void display_init_mariko(void);
void display_end_erista(void);
void display_end_mariko(void);
/* Switches screen backlight ON/OFF. */
void display_backlight(bool enable);
/* Show one single color on the display. */
void display_color_screen(uint32_t color);
/* Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */
uint32_t *display_init_framebuffer(void *address);

File diff suppressed because it is too large Load diff

View file

@ -70,7 +70,11 @@ void check_and_display_panic(void) {
}
/* Initialize the display. */
display_init();
if (fuse_get_soc_type() == 1) {
display_init_mariko();
} else {
display_init_erista();
}
/* Fill the screen. */
display_color_screen(color);

View file

@ -26,28 +26,37 @@
#include "gpio.h"
#include "pinmux.h"
#include "car.h"
#include "apb_misc.h"
#include "di.inl"
static uint32_t _display_ver = 0;
static uint32_t g_lcd_vendor = 0;
static void exec_cfg(uint32_t *base, const cfg_op_t *ops, uint32_t num_ops)
{
for (uint32_t i = 0; i < num_ops; i++)
base[ops[i].off] = ops[i].val;
static void do_dsi_sleep_or_register_writes(const dsi_sleep_or_register_write_t *writes, uint32_t num_writes) {
for (uint32_t i = 0; i < num_writes; i++) {
if (writes[i].kind == 1) {
udelay(1000 * writes[i].offset);
} else {
*(volatile uint32_t *)(DSI_BASE + sizeof(uint32_t) * writes[i].offset) = writes[i].value;
}
}
}
static void _display_dsi_wait(uint32_t timeout, uint32_t off, uint32_t mask)
{
static void do_register_writes(uint32_t base_address, const register_write_t *writes, uint32_t num_writes) {
for (uint32_t i = 0; i < num_writes; i++) {
*(volatile uint32_t *)(base_address + writes[i].offset) = writes[i].value;
}
}
static void dsi_wait(uint32_t timeout, uint32_t offset, uint32_t mask, uint32_t delay) {
uint32_t end = get_time_us() + timeout;
while ((get_time_us() < end) && (MAKE_DSI_REG(off) & mask)) {
while ((get_time_us() < end) && (MAKE_DSI_REG(offset) & mask)) {
/* Wait. */
}
udelay(5);
udelay(delay);
}
void display_init()
{
void display_init_erista(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pmc_t *pmc = pmc_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
@ -55,8 +64,6 @@ void display_init()
/* Power on. */
uint8_t val = 0xD0;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_LDO0_CFG, &val, 1);
val = 0x09;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_GPIO7, &val, 1);
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
car->rst_dev_h_clr = 0x1010000;
@ -107,11 +114,19 @@ void display_init()
gpio_write(GPIO_LCD_BL_EN, GPIO_LEVEL_HIGH);
/* Configure display interface and display. */
MAKE_MIPI_CAL_REG(0x60) = 0;
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
exec_cfg((uint32_t *)CAR_BASE, _display_config_1, 4);
exec_cfg((uint32_t *)DI_BASE, _display_config_2, 94);
exec_cfg((uint32_t *)DSI_BASE, _display_config_3, 60);
do_register_writes(CAR_BASE, display_config_plld_01_erista, 4);
do_register_writes(DI_BASE, display_config_dc_01, 94);
do_register_writes(DSI_BASE, display_config_dsi_01_init_01, 8);
do_register_writes(DSI_BASE, display_config_dsi_01_init_02_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_03, 13);
do_register_writes(DSI_BASE, display_config_dsi_01_init_04_erista, 0);
do_register_writes(DSI_BASE, display_config_dsi_01_init_05, 11);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_06, 12);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_07, 14);
udelay(10000);
@ -123,57 +138,235 @@ void display_init()
MAKE_DSI_REG(DSI_BTA_TIMING) = 0x50204;
MAKE_DSI_REG(DSI_WR_DATA) = 0x337;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO));
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_WR_DATA) = 0x406;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO));
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_HOST_CONTROL) = (DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
_display_dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA);
dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA, 5000);
udelay(5000);
/* Parse LCD vendor. */
uint32_t host_response[3];
for (uint32_t i = 0; i < 3; i++) {
host_response[i] = MAKE_DSI_REG(DSI_RD_DATA);
}
_display_ver = MAKE_DSI_REG(DSI_RD_DATA);
/* The last word from host response is:
Bits 0-7: FAB
Bits 8-15: REV
Bits 16-23: Minor REV
*/
if ((host_response[2] & 0xFF) == 0x10) {
g_lcd_vendor = 0;
} else {
g_lcd_vendor = (host_response[2] >> 8) & 0xFF00;
}
g_lcd_vendor = (g_lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
if (_display_ver == 0x10)
exec_cfg((uint32_t *)DSI_BASE, _display_config_4, 43);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1105;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
udelay(180000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x2905;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
/* LCD vendor specific configuration. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_init_01, 48);
break;
case 0xF20: /* Innolux first revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev1_specific_init_01, 14);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_init_01, 14);
break;
default:
/* Innolux and AUO second revision screens. */
if ((g_lcd_vendor | 0x10) == 0x1030) {
do_dsi_sleep_or_register_writes(display_config_innolux_auo_rev2_specific_init_01, 5);
}
break;
}
udelay(20000);
exec_cfg((uint32_t *)DSI_BASE, _display_config_5, 21);
exec_cfg((uint32_t *)CAR_BASE, _display_config_6, 3);
do_register_writes(CAR_BASE, display_config_plld_02_erista, 3);
do_register_writes(DSI_BASE, display_config_dsi_01_init_08, 1);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_09, 19);
MAKE_DI_REG(DC_DISP_DISP_CLOCK_CONTROL) = 4;
exec_cfg((uint32_t *)DSI_BASE, _display_config_7, 10);
do_register_writes(DSI_BASE, display_config_dsi_01_init_10, 10);
udelay(10000);
exec_cfg((uint32_t *)MIPI_CAL_BASE, _display_config_8, 6);
exec_cfg((uint32_t *)DSI_BASE, _display_config_9, 4);
exec_cfg((uint32_t *)MIPI_CAL_BASE, _display_config_10, 16);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_01, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_erista, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_erista, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_erista, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
udelay(10000);
exec_cfg((uint32_t *)DI_BASE, _display_config_11, 113);
do_register_writes(DI_BASE, display_config_dc_02, 113);
}
void display_backlight(bool enable)
{
/* Enable Backlight PWM. */
gpio_write(GPIO_LCD_BL_PWM, enable ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW);
void display_init_mariko(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pmc_t *pmc = pmc_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
/* Power on. */
uint8_t val = 0x3A;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_SD2, &val, 1);
val = 0x71;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_SD2_CFG, &val, 1);
val = 0xD0;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_LDO0_CFG, &val, 1);
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
car->rst_dev_h_clr = 0x1010000;
car->clk_enb_h_set = 0x1010000;
car->rst_dev_l_clr = 0x18000000;
car->clk_enb_l_set = 0x18000000;
car->clk_enb_x_set = 0x20000;
car->clk_source_uart_fst_mipi_cal = 0xA;
car->clk_enb_w_set = 0x80000;
car->clk_source_dsia_lp = 0xA;
/* DPD idle. */
pmc->io_dpd_req = 0x40000000;
pmc->io_dpd2_req = 0x40000000;
/* Configure pins. */
pinmux->nfc_en &= ~PINMUX_TRISTATE;
pinmux->nfc_int &= ~PINMUX_TRISTATE;
pinmux->lcd_bl_pwm &= ~PINMUX_TRISTATE;
pinmux->lcd_bl_en &= ~PINMUX_TRISTATE;
pinmux->lcd_rst &= ~PINMUX_TRISTATE;
/* Configure Backlight +-5V GPIOs. */
gpio_configure_mode(GPIO_LCD_BL_P5V, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_N5V, GPIO_MODE_GPIO);
gpio_configure_direction(GPIO_LCD_BL_P5V, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_N5V, GPIO_DIRECTION_OUTPUT);
/* Enable Backlight +5V. */
gpio_write(GPIO_LCD_BL_P5V, GPIO_LEVEL_HIGH);
udelay(10000);
/* Enable Backlight -5V. */
gpio_write(GPIO_LCD_BL_N5V, GPIO_LEVEL_HIGH);
udelay(10000);
/* Configure Backlight PWM, EN and RST GPIOs. */
gpio_configure_mode(GPIO_LCD_BL_PWM, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_EN, GPIO_MODE_GPIO);
gpio_configure_mode(GPIO_LCD_BL_RST, GPIO_MODE_GPIO);
gpio_configure_direction(GPIO_LCD_BL_PWM, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_EN, GPIO_DIRECTION_OUTPUT);
gpio_configure_direction(GPIO_LCD_BL_RST, GPIO_DIRECTION_OUTPUT);
/* Enable Backlight EN. */
gpio_write(GPIO_LCD_BL_EN, GPIO_LEVEL_HIGH);
/* Configure display interface and display. */
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
MAKE_MIPI_CAL_REG(MIPI_CAL_MIPI_BIAS_PAD_CFG0) = 0;
MAKE_APB_MISC_REG(0xAC0) = 0;
do_register_writes(CAR_BASE, display_config_plld_01_mariko, 4);
do_register_writes(DI_BASE, display_config_dc_01, 94);
do_register_writes(DSI_BASE, display_config_dsi_01_init_01, 8);
do_register_writes(DSI_BASE, display_config_dsi_01_init_02_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_03, 13);
do_register_writes(DSI_BASE, display_config_dsi_01_init_04_mariko, 7);
do_register_writes(DSI_BASE, display_config_dsi_01_init_05, 11);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_06, 12);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_07, 14);
udelay(10000);
/* Enable Backlight RST. */
gpio_write(GPIO_LCD_BL_RST, GPIO_LEVEL_HIGH);
udelay(60000);
MAKE_DSI_REG(DSI_BTA_TIMING) = 0x50204;
MAKE_DSI_REG(DSI_WR_DATA) = 0x337;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_WR_DATA) = 0x406;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
dsi_wait(250000, DSI_TRIGGER, (DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO), 5);
MAKE_DSI_REG(DSI_HOST_CONTROL) = (DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
dsi_wait(150000, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA, 5000);
/* Parse LCD vendor. */
uint32_t host_response[3];
for (uint32_t i = 0; i < 3; i++) {
host_response[i] = MAKE_DSI_REG(DSI_RD_DATA);
}
/* The last word from host response is:
Bits 0-7: FAB
Bits 8-15: REV
Bits 16-23: Minor REV
*/
if ((host_response[2] & 0xFF) == 0x10) {
g_lcd_vendor = 0;
} else {
g_lcd_vendor = (host_response[2] >> 8) & 0xFF00;
}
g_lcd_vendor = (g_lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
/* LCD vendor specific configuration. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_init_01, 48);
break;
case 0xF20: /* Innolux first revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev1_specific_init_01, 14);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_init_01, 14);
break;
default:
/* Innolux and AUO second revision screens. */
if ((g_lcd_vendor | 0x10) == 0x1030) {
do_dsi_sleep_or_register_writes(display_config_innolux_auo_rev2_specific_init_01, 5);
}
break;
}
udelay(20000);
do_register_writes(CAR_BASE, display_config_plld_02_mariko, 3);
do_register_writes(DSI_BASE, display_config_dsi_01_init_08, 1);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_init_09, 19);
MAKE_DI_REG(DC_DISP_DISP_CLOCK_CONTROL) = 4;
do_register_writes(DSI_BASE, display_config_dsi_01_init_10, 10);
udelay(10000);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_01, 4);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_mariko, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_mariko, 7);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_mariko, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_02_mariko, 2);
do_register_writes(DSI_BASE, display_config_dsi_01_init_11_mariko, 7);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_03_mariko, 6);
do_register_writes(MIPI_CAL_BASE, display_config_mipi_cal_04, 10);
udelay(10000);
do_register_writes(DI_BASE, display_config_dc_02, 113);
}
void display_end()
{
void display_end_erista(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
@ -183,16 +376,41 @@ void display_end()
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 1;
MAKE_DSI_REG(DSI_WR_DATA) = 0x2805;
/* Wait 5 frames. */
uint32_t start_val = MAKE_HOST1X_REG(0x30A4);
while (MAKE_HOST1X_REG(0x30A4) < start_val + 5) {
/* Wait. */
}
MAKE_DI_REG(DC_CMD_STATE_ACCESS) = (READ_MUX | WRITE_MUX);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 0;
exec_cfg((uint32_t *)DI_BASE, _display_config_12, 17);
exec_cfg((uint32_t *)DSI_BASE, _display_config_13, 16);
do_register_writes(CAR_BASE, display_config_plld_01_erista, 4);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_01, 2);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_erista, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_02, 13);
udelay(10000);
if (_display_ver == 0x10)
exec_cfg((uint32_t *)DSI_BASE, _display_config_14, 22);
/* LCD vendor specific shutdown. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_fini_01, 22);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_fini_01, 38);
break;
case 0x1020: /* Innolux second revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev2_specific_fini_01, 10);
break;
case 0x1030: /* AUO second revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev2_specific_fini_01, 10);
break;
default:
break;
}
udelay(5000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1005;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
@ -230,9 +448,95 @@ void display_end()
pinmux->lcd_bl_pwm = (((pinmux->lcd_bl_pwm >> 2) << 2) | 1);
}
void display_color_screen(uint32_t color)
{
exec_cfg((uint32_t *)DI_BASE, cfg_display_one_color, 8);
void display_end_mariko(void) {
volatile tegra_car_t *car = car_get_regs();
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
/* Disable Backlight. */
display_backlight(false);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 1;
MAKE_DSI_REG(DSI_WR_DATA) = 0x2805;
/* Wait 5 frames. */
uint32_t start_val = MAKE_HOST1X_REG(0x30A4);
while (MAKE_HOST1X_REG(0x30A4) < start_val + 5) {
/* Wait. */
}
MAKE_DI_REG(DC_CMD_STATE_ACCESS) = (READ_MUX | WRITE_MUX);
MAKE_DSI_REG(DSI_VIDEO_MODE_CONTROL) = 0;
do_register_writes(CAR_BASE, display_config_plld_01_mariko, 4);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_01, 2);
do_register_writes(DSI_BASE, display_config_dsi_phy_timing_mariko, 1);
do_register_writes(DSI_BASE, display_config_dsi_01_fini_02, 13);
udelay(10000);
/* LCD vendor specific shutdown. */
switch (g_lcd_vendor) {
case 0x10: /* Japan Display Inc screens. */
do_dsi_sleep_or_register_writes(display_config_jdi_specific_fini_01, 22);
break;
case 0xF30: /* AUO first revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev1_specific_fini_01, 38);
break;
case 0x1020: /* Innolux second revision screens. */
do_dsi_sleep_or_register_writes(display_config_innolux_rev2_specific_fini_01, 10);
break;
case 0x1030: /* AUO second revision screens. */
do_dsi_sleep_or_register_writes(display_config_auo_rev2_specific_fini_01, 10);
break;
default:
break;
}
udelay(5000);
MAKE_DSI_REG(DSI_WR_DATA) = 0x1005;
MAKE_DSI_REG(DSI_TRIGGER) = DSI_TRIGGER_HOST;
udelay(50000);
/* Disable Backlight RST. */
gpio_write(GPIO_LCD_BL_RST, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable Backlight -5V. */
gpio_write(GPIO_LCD_BL_N5V, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable Backlight +5V. */
gpio_write(GPIO_LCD_BL_P5V, GPIO_LEVEL_LOW);
udelay(10000);
/* Disable clocks. */
car->rst_dev_h_set = 0x1010000;
car->clk_enb_h_clr = 0x1010000;
car->rst_dev_l_set = 0x18000000;
car->clk_enb_l_clr = 0x18000000;
MAKE_DSI_REG(DSI_PAD_CONTROL_0) = (DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF));
MAKE_DSI_REG(DSI_POWER_CONTROL) = 0;
/* Backlight PWM. */
gpio_configure_mode(GPIO_LCD_BL_PWM, GPIO_MODE_SFIO);
pinmux->lcd_bl_pwm = ((pinmux->lcd_bl_pwm & ~PINMUX_TRISTATE) | PINMUX_TRISTATE);
pinmux->lcd_bl_pwm = (((pinmux->lcd_bl_pwm >> 2) << 2) | 1);
}
void display_backlight(bool enable) {
/* Enable Backlight PWM. */
gpio_write(GPIO_LCD_BL_PWM, enable ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW);
}
void display_color_screen(uint32_t color) {
do_register_writes(DI_BASE, display_config_solid_color, 8);
/* Configure display to show single color. */
MAKE_DI_REG(DC_WIN_AD_WIN_OPTIONS) = 0;
@ -246,20 +550,19 @@ void display_color_screen(uint32_t color)
display_backlight(true);
}
uint32_t *display_init_framebuffer(void *address)
{
static cfg_op_t conf[sizeof(cfg_display_framebuffer)/sizeof(cfg_op_t)] = {0};
if (conf[0].val == 0) {
for (uint32_t i = 0; i < sizeof(cfg_display_framebuffer)/sizeof(cfg_op_t); i++) {
conf[i] = cfg_display_framebuffer[i];
uint32_t *display_init_framebuffer(void *address) {
static register_write_t conf[sizeof(display_config_frame_buffer)/sizeof(register_write_t)] = {0};
if (conf[0].value == 0) {
for (uint32_t i = 0; i < sizeof(display_config_frame_buffer)/sizeof(register_write_t); i++) {
conf[i] = display_config_frame_buffer[i];
}
}
uint32_t *lfb_addr = (uint32_t *)address;
conf[19].val = (uint32_t)address;
conf[19].value = (uint32_t)address;
/* This configures the framebuffer @ address with a resolution of 1280x720 (line stride 768). */
exec_cfg((uint32_t *)DI_BASE, conf, 32);
do_register_writes(DI_BASE, conf, 32);
udelay(35000);

View file

@ -33,6 +33,12 @@
#define MAKE_MIPI_CAL_REG(n) MAKE_REG32(MIPI_CAL_BASE + n)
#define MAKE_VIC_REG(n) MAKE_REG32(VIC_BASE + n)
/* Clock and reset registers. */
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
/* Display registers. */
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00
@ -238,6 +244,7 @@
#define DC_WIN_LINE_STRIDE 0x70A
#define DC_WIN_DV_CONTROL 0x70E
#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716
/* The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
#define DC_WINBUF_START_ADDR 0x800
@ -333,7 +340,7 @@
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
#define DSI_PAD_CONTROL_CD 0x4c
#define DSI_PAD_CONTROL_CD 0x4C
#define DSI_VIDEO_MODE_CONTROL 0x4E
#define DSI_PAD_CONTROL_1 0x4F
@ -346,22 +353,46 @@
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
#define DSI_PAD_CONTROL_4 0x52
#define DSI_PAD_CONTROL_5_MARIKO 0x53
#define DSI_PAD_CONTROL_6_MARIKO 0x54
#define DSI_PAD_CONTROL_7_MARIKO 0x55
#define DSI_INIT_SEQ_DATA_15 0x5F
#define DSI_INIT_SEQ_DATA_15_MARIKO 0x62
typedef struct _cfg_op_t
{
uint32_t off;
uint32_t val;
} cfg_op_t;
/* MIPI calibration registers. */
#define MIPI_CAL_MIPI_CAL_CTRL 0x0
#define MIPI_CAL_MIPI_CAL_AUTOCAL_CTRL0 0x4
#define MIPI_CAL_CIL_MIPI_CAL_STATUS 0x8
#define MIPI_CAL_CIL_MIPI_CAL_STATUS_2 0xC
#define MIPI_CAL_CILA_MIPI_CAL_CONFIG 0x14
#define MIPI_CAL_CILB_MIPI_CAL_CONFIG 0x18
#define MIPI_CAL_CILC_MIPI_CAL_CONFIG 0x1C
#define MIPI_CAL_CILD_MIPI_CAL_CONFIG 0x20
#define MIPI_CAL_CILE_MIPI_CAL_CONFIG 0x24
#define MIPI_CAL_CILF_MIPI_CAL_CONFIG 0x28
#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG 0x38
#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG 0x3C
#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG 0x40
#define MIPI_CAL_DSID_MIPI_CAL_CONFIG 0x44
#define MIPI_CAL_MIPI_BIAS_PAD_CFG0 0x58
#define MIPI_CAL_MIPI_BIAS_PAD_CFG1 0x5C
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 0x64
#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 0x68
#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 0x70
#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 0x74
void display_init();
void display_end();
/* Show one single color on the display. */
void display_color_screen(uint32_t color);
void display_init_erista(void);
void display_init_mariko(void);
void display_end_erista(void);
void display_end_mariko(void);
/* Switches screen backlight ON/OFF. */
void display_backlight(bool enable);
/* Show one single color on the display. */
void display_color_screen(uint32_t color);
/* Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */
uint32_t *display_init_framebuffer(void *address);

File diff suppressed because it is too large Load diff

View file

@ -114,7 +114,7 @@ static void setup_env(void) {
video_init(g_framebuffer);
/* Initialize the display. */
display_init();
display_init_erista();
/* Set the framebuffer. */
display_init_framebuffer(g_framebuffer);
@ -131,7 +131,7 @@ static void cleanup_env(void) {
unmount_sd();
/* Terminate the display. */
display_end();
display_end_erista();
}
static void exit_callback(int rc) {