blob: b37367300cf0c92e7c56840f7fdbdd947086737f [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2017 FriendlyARM (www.arm9.net)
*/
#include <config.h>
#include <errno.h>
#include <fdtdec.h>
#include <fdt_support.h>
#include <asm/io.h>
#include <asm/arch/nexell.h>
#include <asm/arch/display.h>
#include <asm/arch/nx_gpio.h>
#include "nxp-fb.h"
/*
* param @module_index for nx_gpio APIs and will be removed
* after support pinctrl
*/
#ifndef PAD_GPIO_A
#define PAD_GPIO_A 0
#endif
static inline void common_gpio_init(void)
{
/* PVCLK */
nx_gpio_set_fast_slew(PAD_GPIO_A, 0, 1);
}
static void s70_gpio_init(void)
{
int i;
/* PVCLK */
nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 1);
/* RGB24 */
for (i = 1; i < 25; i++)
nx_gpio_set_drive_strength(PAD_GPIO_A, i, 2);
/* HS/VS/DE */
for (; i < 28; i++)
nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
}
static void s702_gpio_init(void)
{
int i;
common_gpio_init();
nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2);
for (i = 1; i < 25; i++)
nx_gpio_set_drive_strength(PAD_GPIO_A, i, 0);
for (; i < 28; i++)
nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
}
static void s430_gpio_init(void)
{
int i;
for (i = 0; i < 28; i++)
nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
}
static void hd101_gpio_init(void)
{
int i;
common_gpio_init();
nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2);
for (i = 1; i < 25; i++)
nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
nx_gpio_set_drive_strength(PAD_GPIO_A, 27, 1);
}
static void hd700_gpio_init(void)
{
hd101_gpio_init();
}
/* NXP display configs for supported LCD */
static struct nxp_lcd wxga_hd700 = {
.width = 800,
.height = 1280,
.p_width = 94,
.p_height = 151,
.bpp = 24,
.freq = 60,
.timing = {
.h_fp = 20,
.h_bp = 20,
.h_sw = 24,
.v_fp = 4,
.v_fpe = 1,
.v_bp = 4,
.v_bpe = 1,
.v_sw = 8,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 0,
.inv_vsync = 0,
.inv_vden = 0,
},
.gpio_init = hd700_gpio_init,
};
static struct nxp_lcd wvga_s70 = {
.width = 800,
.height = 480,
.p_width = 155,
.p_height = 93,
.bpp = 24,
.freq = 61,
.timing = {
.h_fp = 48,
.h_bp = 36,
.h_sw = 10,
.v_fp = 22,
.v_fpe = 1,
.v_bp = 15,
.v_bpe = 1,
.v_sw = 8,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
.gpio_init = s70_gpio_init,
};
static struct nxp_lcd wvga_s702 = {
.width = 800,
.height = 480,
.p_width = 155,
.p_height = 93,
.bpp = 24,
.freq = 61,
.timing = {
.h_fp = 44,
.h_bp = 26,
.h_sw = 20,
.v_fp = 22,
.v_fpe = 1,
.v_bp = 15,
.v_bpe = 1,
.v_sw = 8,
},
.polarity = {
.rise_vclk = 1,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
.gpio_init = s702_gpio_init,
};
static struct nxp_lcd wvga_s70d = {
.width = 800,
.height = 480,
.p_width = 155,
.p_height = 93,
.bpp = 24,
.freq = 61,
.timing = {
.h_fp = 80,
.h_bp = 78,
.h_sw = 10,
.v_fp = 22,
.v_fpe = 1,
.v_bp = 24,
.v_bpe = 1,
.v_sw = 8,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
.gpio_init = s702_gpio_init,
};
static struct nxp_lcd wvga_w50 = {
.width = 800,
.height = 480,
.p_width = 108,
.p_height = 64,
.bpp = 24,
.freq = 61,
.timing = {
.h_fp = 40,
.h_bp = 40,
.h_sw = 48,
.v_fp = 20,
.v_fpe = 1,
.v_bp = 20,
.v_bpe = 1,
.v_sw = 12,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
.gpio_init = s70_gpio_init,
};
static struct nxp_lcd wvga_s430 = {
.width = 480,
.height = 800,
.p_width = 108,
.p_height = 64,
.bpp = 24,
.freq = 60,
.timing = {
.h_fp = 64,
.h_bp = 0,
.h_sw = 16,
.v_fp = 32,
.v_fpe = 1,
.v_bp = 0,
.v_bpe = 1,
.v_sw = 16,
},
.polarity = {
.rise_vclk = 1,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
.gpio_init = s430_gpio_init,
};
static struct nxp_lcd wsvga_w101 = {
.width = 1024,
.height = 600,
.p_width = 204,
.p_height = 120,
.bpp = 24,
.freq = 60,
.timing = {
.h_fp = 40,
.h_bp = 40,
.h_sw = 200,
.v_fp = 8,
.v_fpe = 1,
.v_bp = 8,
.v_bpe = 1,
.v_sw = 16,
},
.polarity = {
.rise_vclk = 1,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static struct nxp_lcd wsvga_x710 = {
.width = 1024,
.height = 600,
.p_width = 154,
.p_height = 90,
.bpp = 24,
.freq = 61,
.timing = {
.h_fp = 84,
.h_bp = 84,
.h_sw = 88,
.v_fp = 10,
.v_fpe = 1,
.v_bp = 10,
.v_bpe = 1,
.v_sw = 20,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
.gpio_init = hd101_gpio_init,
};
static struct nxp_lcd xga_a97 = {
.width = 1024,
.height = 768,
.p_width = 200,
.p_height = 150,
.bpp = 24,
.freq = 61,
.timing = {
.h_fp = 12,
.h_bp = 12,
.h_sw = 4,
.v_fp = 8,
.v_fpe = 1,
.v_bp = 8,
.v_bpe = 1,
.v_sw = 4,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static struct nxp_lcd xga_lq150 = {
.width = 1024,
.height = 768,
.p_width = 304,
.p_height = 228,
.bpp = 24,
.freq = 60,
.timing = {
.h_fp = 12,
.h_bp = 12,
.h_sw = 40,
.v_fp = 8,
.v_fpe = 1,
.v_bp = 8,
.v_bpe = 1,
.v_sw = 40,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static struct nxp_lcd vga_l80 = {
.width = 640,
.height = 480,
.p_width = 160,
.p_height = 120,
.bpp = 32,
.freq = 60,
.timing = {
.h_fp = 35,
.h_bp = 53,
.h_sw = 73,
.v_fp = 3,
.v_fpe = 1,
.v_bp = 29,
.v_bpe = 1,
.v_sw = 6,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static struct nxp_lcd wxga_bp101 = {
.width = 1280,
.height = 800,
.p_width = 218,
.p_height = 136,
.bpp = 24,
.freq = 60,
.timing = {
.h_fp = 20,
.h_bp = 20,
.h_sw = 24,
.v_fp = 4,
.v_fpe = 1,
.v_bp = 4,
.v_bpe = 1,
.v_sw = 8,
},
.polarity = {
.rise_vclk = 1,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static struct nxp_lcd wxga_hd101 = {
.width = 1280,
.height = 800,
.p_width = 218,
.p_height = 136,
.bpp = 24,
.freq = 60,
.timing = {
.h_fp = 16,
.h_bp = 16,
.h_sw = 30,
.v_fp = 8,
.v_fpe = 1,
.v_bp = 8,
.v_bpe = 1,
.v_sw = 12,
},
.polarity = {
.rise_vclk = 1,
.inv_hsync = 0,
.inv_vsync = 0,
.inv_vden = 0,
},
.gpio_init = hd101_gpio_init,
};
static struct nxp_lcd hvga_h43 = {
.width = 480,
.height = 272,
.p_width = 96,
.p_height = 54,
.bpp = 32,
.freq = 65,
.timing = {
.h_fp = 5,
.h_bp = 40,
.h_sw = 2,
.v_fp = 8,
.v_fpe = 1,
.v_bp = 8,
.v_bpe = 1,
.v_sw = 2,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static struct nxp_lcd hvga_p43 = {
.width = 480,
.height = 272,
.p_width = 96,
.p_height = 54,
.bpp = 32,
.freq = 65,
.timing = {
.h_fp = 5,
.h_bp = 40,
.h_sw = 2,
.v_fp = 8,
.v_fpe = 1,
.v_bp = 9,
.v_bpe = 1,
.v_sw = 2,
},
.polarity = {
.rise_vclk = 1,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static struct nxp_lcd qvga_w35 = {
.width = 320,
.height = 240,
.p_width = 70,
.p_height = 52,
.bpp = 16,
.freq = 65,
.timing = {
.h_fp = 4,
.h_bp = 70,
.h_sw = 4,
.v_fp = 4,
.v_fpe = 1,
.v_bp = 12,
.v_bpe = 1,
.v_sw = 4,
},
.polarity = {
.rise_vclk = 1,
.inv_hsync = 0,
.inv_vsync = 0,
.inv_vden = 0,
},
};
/* HDMI */
static struct nxp_lcd hdmi_def = {
.width = 1920,
.height = 1080,
.p_width = 480,
.p_height = 320,
.bpp = 24,
.freq = 60,
.timing = {
.h_fp = 12,
.h_bp = 12,
.h_sw = 4,
.v_fp = 8,
.v_fpe = 1,
.v_bp = 8,
.v_bpe = 1,
.v_sw = 4,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static struct hdmi_config {
char *name;
int width;
int height;
} bd_hdmi_config[] = {
{ "HDMI1080P60", 1920, 1080 },
{ "HDMI1080I60", 1920, 1080 },
{ "HDMI1080P30", 1920, 1080 },
{ "HDMI1080P50", 1920, 1080 },
{ "HDMI1080I50", 1920, 1080 },
{ "HDMI1080P60D", 960, 536 },
{ "HDMI1080I60D", 960, 536 },
{ "HDMI1080P30D", 960, 536 },
{ "HDMI1080P50D", 960, 536 },
{ "HDMI1080I50D", 960, 536 },
{ "HDMI720P60", 1280, 720 },
{ "HDMI720P60D", 640, 360 },
{ "HDMI720P50", 1280, 720 },
{ "HDMI720P50D", 640, 360 },
{ "HDMI576P16X9", 720, 576 },
{ "HDMI576P16X9D", 720, 576 },
{ "HDMI576P4X3", 720, 576 },
{ "HDMI576P4X3D", 720, 576 },
{ "HDMI480P16X9", 720, 480 },
{ "HDMI480P16X9D", 720, 480 },
{ "HDMI480P4X3", 720, 480 },
{ "HDMI480P4X3D", 720, 480 },
};
/* Try to guess LCD panel by kernel command line, or
* using *HD101* as default
*/
static struct {
int id;
char *name;
struct nxp_lcd *lcd;
int dpi;
int ctp;
enum lcd_format fmt;
} bd_lcd_config[] = {
{ 25, "HD101", &wxga_hd101, 0, 1, LCD_RGB },
{ 32, "HD101B", &wxga_hd101, 0, 1, LCD_RGB },
{ 18, "HD700", &wxga_hd700, 213, 1, LCD_RGB },
{ 30, "HD702", &wxga_hd700, 213, 1, LCD_RGB },
{ 33, "H70", &wxga_hd700, 213, 0, LCD_VESA },
{ 3, "S70", &wvga_s70, 128, 1, LCD_RGB },
{ 36, "S701", &wvga_s70, 128, 1, LCD_RGB },
{ 24, "S702", &wvga_s702, 128, 3, LCD_RGB },
{ 26, "S70D", &wvga_s70d, 128, 0, LCD_RGB },
{ 14, "H43", &hvga_h43, 0, 0, LCD_RGB },
{ 19, "P43", &hvga_p43, 0, 0, LCD_RGB },
{ 8, "W35", &qvga_w35, 0, 0, LCD_RGB },
{ 28, "X710", &wsvga_x710, 0, 1, LCD_RGB },
{ 31, "S430", &wvga_s430, 180, 1, LCD_RGB },
{ 4, "W50", &wvga_w50, 0, 0, LCD_RGB },
/* TODO: Testing */
{ 15, "W101", &wsvga_w101, 0, 1, LCD_RGB },
{ 5, "L80", &vga_l80, 0, 1, LCD_RGB },
{ -1, "A97", &xga_a97, 0, 0, LCD_RGB },
{ -1, "LQ150", &xga_lq150, 0, 1, LCD_RGB },
{ -1, "BP101", &wxga_bp101, 0, 1, LCD_RGB },
/* Pls keep it at last */
{ 128, "HDMI", &hdmi_def, 0, 0, LCD_HDMI },
};
static int lcd_idx;
int bd_setup_lcd_by_id(int id)
{
int i;
for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) {
if (bd_lcd_config[i].id == id) {
lcd_idx = i;
break;
}
}
if (i >= ARRAY_SIZE(bd_lcd_config)) {
/* NOT found */
return -19;
}
return bd_lcd_config[i].id;
}
int bd_setup_lcd_by_name(char *str)
{
char *delim;
int i;
delim = strchr(str, ',');
if (delim)
*delim++ = '\0';
if (!strncasecmp("HDMI", str, 4)) {
struct hdmi_config *cfg = &bd_hdmi_config[0];
struct nxp_lcd *lcd;
lcd_idx = ARRAY_SIZE(bd_lcd_config) - 1;
lcd = bd_lcd_config[lcd_idx].lcd;
for (i = 0; i < ARRAY_SIZE(bd_hdmi_config); i++, cfg++) {
if (!strcasecmp(cfg->name, str)) {
lcd->width = cfg->width;
lcd->height = cfg->height;
bd_lcd_config[lcd_idx].name = cfg->name;
goto __ret;
}
}
}
for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) {
if (!strcasecmp(bd_lcd_config[i].name, str)) {
lcd_idx = i;
break;
}
}
__ret:
return 0;
}
struct nxp_lcd *bd_get_lcd(void)
{
return bd_lcd_config[lcd_idx].lcd;
}
const char *bd_get_lcd_name(void)
{
return bd_lcd_config[lcd_idx].name;
}
enum lcd_format bd_get_lcd_format(void)
{
return bd_lcd_config[lcd_idx].fmt;
}
int bd_get_lcd_density(void)
{
return bd_lcd_config[lcd_idx].dpi;
}
#if CONFIG_IS_ENABLED(OF_CONTROL)
int bd_fixup_lcd_fdt(void *blob, struct nxp_lcd *lcd)
{
return 0;
}
#endif