summaryrefslogtreecommitdiff
path: root/board/friendlyarm/nanopi2/lcds.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/friendlyarm/nanopi2/lcds.c')
-rw-r--r--board/friendlyarm/nanopi2/lcds.c697
1 files changed, 697 insertions, 0 deletions
diff --git a/board/friendlyarm/nanopi2/lcds.c b/board/friendlyarm/nanopi2/lcds.c
new file mode 100644
index 0000000000..7303e53af9
--- /dev/null
+++ b/board/friendlyarm/nanopi2/lcds.c
@@ -0,0 +1,697 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 FriendlyARM (www.arm9.net)
+ */
+
+#include <config.h>
+#include <common.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