summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2015-08-08 20:20:17 -0400
committerTom Rini <trini@konsulko.com>2015-08-08 20:20:17 -0400
commit15f8876b1dd95dd6bcee686ada36369871bbcdc9 (patch)
tree8695ca6182a99fea5a4f79ab67e9ec5b015069ac /drivers
parentbd48c0617b5c7212e5bf22169e716da878842da4 (diff)
parent39920c81ce4431b7ea08f5e80feb5ec8b156864e (diff)
downloadu-boot-imx-15f8876b1dd95dd6bcee686ada36369871bbcdc9.zip
u-boot-imx-15f8876b1dd95dd6bcee686ada36369871bbcdc9.tar.gz
u-boot-imx-15f8876b1dd95dd6bcee686ada36369871bbcdc9.tar.bz2
Merge branch 'master' of http://git.denx.de/u-boot-sunxi
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/Kconfig40
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/sunxi_nand_spl.c353
-rw-r--r--drivers/usb/host/ehci-sunxi.c1
-rw-r--r--drivers/usb/host/ohci-sunxi.c1
-rw-r--r--drivers/usb/musb-new/sunxi.c28
-rw-r--r--drivers/video/sunxi_display.c334
7 files changed, 672 insertions, 86 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 3024357..41ebfea 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -85,6 +85,46 @@ config SPL_NAND_DENALI
This is a small implementation of the Denali NAND controller
for use on SPL.
+config SPL_NAND_SUNXI
+ bool "Support for NAND on Allwinner A20 in SPL"
+ depends on MACH_SUN7I
+ ---help---
+ Enable support for NAND. This option allows SPL to read from
+ sunxi NAND using DMA transfers.
+ Depending on the NAND chip, values like ECC strength and page sizes
+ have to be configured.
+
+config NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END
+ hex "Size of syndrome partitions in sunxi NAND"
+ default 0x400000
+ depends on SPL_NAND_SUNXI
+ ---help---
+ End address for boot partitions on NAND. Those partitions have a
+ different random seed that has to match the sunxi BROM setting.
+
+config NAND_SUNXI_SPL_ECC_STRENGTH
+ int "ECC Strength for sunxi NAND"
+ default 40
+ depends on SPL_NAND_SUNXI
+ ---help---
+ ECC strength used by the sunxi NAND SPL driver. This is specific to the
+ chosen NAND chip and has to match the value used by the sunxi BROM.
+
+config NAND_SUNXI_SPL_ECC_PAGE_SIZE
+ hex "ECC page size for sunxi NAND"
+ default 0x400
+ depends on SPL_NAND_SUNXI
+ ---help---
+ ECC page size used by the sunxi NAND SPL driver for syndrome partitions.
+ This setting has to match the value used by the sunxi BROM.
+
+config NAND_SUNXI_SPL_PAGE_SIZE
+ hex "Page size for sunxi NAND"
+ default 0x2000
+ depends on SPL_NAND_SUNXI
+ ---help---
+ Page size of the NAND flash used by the sunxi NAND SPL driver. This is
+ specific to the chosen NAND chip.
endif
endmenu
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 347ea62..b40dda8 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -12,6 +12,7 @@ NORMAL_DRIVERS=y
endif
obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o
+obj-$(CONFIG_SPL_NAND_SUNXI) += sunxi_nand_spl.o
obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c
new file mode 100644
index 0000000..ac5f56d
--- /dev/null
+++ b/drivers/mtd/nand/sunxi_nand_spl.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2014-2015, Antmicro Ltd <www.antmicro.com>
+ * Copyright (c) 2015, AW-SOM Technologies <www.aw-som.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <nand.h>
+
+/* registers */
+#define NFC_CTL 0x00000000
+#define NFC_ST 0x00000004
+#define NFC_INT 0x00000008
+#define NFC_TIMING_CTL 0x0000000C
+#define NFC_TIMING_CFG 0x00000010
+#define NFC_ADDR_LOW 0x00000014
+#define NFC_ADDR_HIGH 0x00000018
+#define NFC_SECTOR_NUM 0x0000001C
+#define NFC_CNT 0x00000020
+#define NFC_CMD 0x00000024
+#define NFC_RCMD_SET 0x00000028
+#define NFC_WCMD_SET 0x0000002C
+#define NFC_IO_DATA 0x00000030
+#define NFC_ECC_CTL 0x00000034
+#define NFC_ECC_ST 0x00000038
+#define NFC_DEBUG 0x0000003C
+#define NFC_ECC_CNT0 0x00000040
+#define NFC_ECC_CNT1 0x00000044
+#define NFC_ECC_CNT2 0x00000048
+#define NFC_ECC_CNT3 0x0000004C
+#define NFC_USER_DATA_BASE 0x00000050
+#define NFC_EFNAND_STATUS 0x00000090
+#define NFC_SPARE_AREA 0x000000A0
+#define NFC_PATTERN_ID 0x000000A4
+#define NFC_RAM0_BASE 0x00000400
+#define NFC_RAM1_BASE 0x00000800
+
+#define NFC_CTL_EN (1 << 0)
+#define NFC_CTL_RESET (1 << 1)
+#define NFC_CTL_RAM_METHOD (1 << 14)
+
+
+#define NFC_ECC_EN (1 << 0)
+#define NFC_ECC_PIPELINE (1 << 3)
+#define NFC_ECC_EXCEPTION (1 << 4)
+#define NFC_ECC_BLOCK_SIZE (1 << 5)
+#define NFC_ECC_RANDOM_EN (1 << 9)
+#define NFC_ECC_RANDOM_DIRECTION (1 << 10)
+
+
+#define NFC_ADDR_NUM_OFFSET 16
+#define NFC_SEND_ADR (1 << 19)
+#define NFC_ACCESS_DIR (1 << 20)
+#define NFC_DATA_TRANS (1 << 21)
+#define NFC_SEND_CMD1 (1 << 22)
+#define NFC_WAIT_FLAG (1 << 23)
+#define NFC_SEND_CMD2 (1 << 24)
+#define NFC_SEQ (1 << 25)
+#define NFC_DATA_SWAP_METHOD (1 << 26)
+#define NFC_ROW_AUTO_INC (1 << 27)
+#define NFC_SEND_CMD3 (1 << 28)
+#define NFC_SEND_CMD4 (1 << 29)
+
+#define NFC_CMD_INT_FLAG (1 << 1)
+
+#define NFC_READ_CMD_OFFSET 0
+#define NFC_RANDOM_READ_CMD0_OFFSET 8
+#define NFC_RANDOM_READ_CMD1_OFFSET 16
+
+#define NFC_CMD_RNDOUTSTART 0xE0
+#define NFC_CMD_RNDOUT 0x05
+#define NFC_CMD_READSTART 0x30
+
+
+#define NFC_PAGE_CMD (2 << 30)
+
+#define SUNXI_DMA_CFG_REG0 0x300
+#define SUNXI_DMA_SRC_START_ADDR_REG0 0x304
+#define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308
+#define SUNXI_DMA_DDMA_BC_REG0 0x30C
+#define SUNXI_DMA_DDMA_PARA_REG0 0x318
+
+#define SUNXI_DMA_DDMA_CFG_REG_LOADING (1 << 31)
+#define SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 (2 << 25)
+#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 (2 << 9)
+#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO (1 << 5)
+#define SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC (3 << 0)
+
+#define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0)
+#define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8)
+
+/* minimal "boot0" style NAND support for Allwinner A20 */
+
+/* temporary buffer in internal ram */
+unsigned char temp_buf[CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE]
+ __aligned(0x10) __section(".text#");
+
+/* random seed used by linux */
+const uint16_t random_seed[128] = {
+ 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
+ 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
+ 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
+ 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
+ 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
+ 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
+ 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
+ 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
+ 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
+ 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
+ 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
+ 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
+ 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
+ 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
+ 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
+ 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
+};
+
+/* random seed used for syndrome calls */
+const uint16_t random_seed_syndrome = 0x4a80;
+
+#define MAX_RETRIES 10
+
+static int check_value_inner(int offset, int expected_bits,
+ int max_number_of_retries, int negation)
+{
+ int retries = 0;
+ do {
+ int val = readl(offset) & expected_bits;
+ if (negation ? !val : val)
+ return 1;
+ mdelay(1);
+ retries++;
+ } while (retries < max_number_of_retries);
+
+ return 0;
+}
+
+static inline int check_value(int offset, int expected_bits,
+ int max_number_of_retries)
+{
+ return check_value_inner(offset, expected_bits,
+ max_number_of_retries, 0);
+}
+
+static inline int check_value_negated(int offset, int unexpected_bits,
+ int max_number_of_retries)
+{
+ return check_value_inner(offset, unexpected_bits,
+ max_number_of_retries, 1);
+}
+
+void nand_init(void)
+{
+ uint32_t val;
+
+ val = readl(SUNXI_NFC_BASE + NFC_CTL);
+ /* enable and reset CTL */
+ writel(val | NFC_CTL_EN | NFC_CTL_RESET,
+ SUNXI_NFC_BASE + NFC_CTL);
+
+ if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL,
+ NFC_CTL_RESET, MAX_RETRIES)) {
+ printf("Couldn't initialize nand\n");
+ }
+}
+
+static void nand_read_page(unsigned int real_addr, int syndrome,
+ uint32_t *ecc_errors)
+{
+ uint32_t val;
+ int ecc_off = 0;
+ uint16_t ecc_mode = 0;
+ uint16_t rand_seed;
+ uint32_t page;
+ uint16_t column;
+ uint32_t oob_offset;
+
+ switch (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH) {
+ case 16:
+ ecc_mode = 0;
+ ecc_off = 0x20;
+ break;
+ case 24:
+ ecc_mode = 1;
+ ecc_off = 0x2e;
+ break;
+ case 28:
+ ecc_mode = 2;
+ ecc_off = 0x32;
+ break;
+ case 32:
+ ecc_mode = 3;
+ ecc_off = 0x3c;
+ break;
+ case 40:
+ ecc_mode = 4;
+ ecc_off = 0x4a;
+ break;
+ case 48:
+ ecc_mode = 4;
+ ecc_off = 0x52;
+ break;
+ case 56:
+ ecc_mode = 4;
+ ecc_off = 0x60;
+ break;
+ case 60:
+ ecc_mode = 4;
+ ecc_off = 0x0;
+ break;
+ case 64:
+ ecc_mode = 4;
+ ecc_off = 0x0;
+ break;
+ default:
+ ecc_mode = 0;
+ ecc_off = 0;
+ }
+
+ if (ecc_off == 0) {
+ printf("Unsupported ECC strength (%d)!\n",
+ CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH);
+ return;
+ }
+
+ /* clear temp_buf */
+ memset(temp_buf, 0, CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE);
+
+ /* set CMD */
+ writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET,
+ SUNXI_NFC_BASE + NFC_CMD);
+
+ if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_CMD_INT_FLAG,
+ MAX_RETRIES)) {
+ printf("Error while initilizing command interrupt\n");
+ return;
+ }
+
+ page = real_addr / CONFIG_NAND_SUNXI_SPL_PAGE_SIZE;
+ column = real_addr % CONFIG_NAND_SUNXI_SPL_PAGE_SIZE;
+
+ if (syndrome)
+ column += (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
+ * ecc_off;
+
+ /* clear ecc status */
+ writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
+
+ /* Choose correct seed */
+ if (syndrome)
+ rand_seed = random_seed_syndrome;
+ else
+ rand_seed = random_seed[page % 128];
+
+ writel((rand_seed << 16) | NFC_ECC_RANDOM_EN | NFC_ECC_EN
+ | NFC_ECC_PIPELINE | (ecc_mode << 12),
+ SUNXI_NFC_BASE + NFC_ECC_CTL);
+
+ val = readl(SUNXI_NFC_BASE + NFC_CTL);
+ writel(val | NFC_CTL_RAM_METHOD, SUNXI_NFC_BASE + NFC_CTL);
+
+ if (syndrome) {
+ writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE,
+ SUNXI_NFC_BASE + NFC_SPARE_AREA);
+ } else {
+ oob_offset = CONFIG_NAND_SUNXI_SPL_PAGE_SIZE
+ + (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
+ * ecc_off;
+ writel(oob_offset, SUNXI_NFC_BASE + NFC_SPARE_AREA);
+ }
+
+ /* SUNXI_DMA */
+ writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
+ /* read from REG_IO_DATA */
+ writel(SUNXI_NFC_BASE + NFC_IO_DATA,
+ SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0);
+ /* read to RAM */
+ writel((uint32_t)temp_buf,
+ SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0);
+ writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC
+ | SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
+ SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
+ writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE,
+ SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); /* 1kB */
+ writel(SUNXI_DMA_DDMA_CFG_REG_LOADING
+ | SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32
+ | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32
+ | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO
+ | SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
+ SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
+
+ writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET)
+ | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET)
+ | (NFC_CMD_READSTART | NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE
+ + NFC_RCMD_SET);
+ writel(1, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
+ writel(((page & 0xFFFF) << 16) | column,
+ SUNXI_NFC_BASE + NFC_ADDR_LOW);
+ writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
+ writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_DATA_TRANS |
+ NFC_PAGE_CMD | NFC_WAIT_FLAG | (4 << NFC_ADDR_NUM_OFFSET) |
+ NFC_SEND_ADR | NFC_DATA_SWAP_METHOD | (syndrome ? NFC_SEQ : 0),
+ SUNXI_NFC_BASE + NFC_CMD);
+
+ if (!check_value(SUNXI_NFC_BASE + NFC_ST, (1 << 2),
+ MAX_RETRIES)) {
+ printf("Error while initializing dma interrupt\n");
+ return;
+ }
+
+ if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0,
+ SUNXI_DMA_DDMA_CFG_REG_LOADING, MAX_RETRIES)) {
+ printf("Error while waiting for dma transfer to finish\n");
+ return;
+ }
+
+ if (readl(SUNXI_NFC_BASE + NFC_ECC_ST))
+ (*ecc_errors)++;
+}
+
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
+{
+ void *current_dest;
+ uint32_t count;
+ uint32_t current_count;
+ uint32_t ecc_errors = 0;
+
+ memset(dest, 0x0, size); /* clean destination memory */
+ for (current_dest = dest;
+ current_dest < (dest + size);
+ current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
+ nand_read_page(offs, offs
+ < CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
+ &ecc_errors);
+ count = current_dest - dest;
+
+ if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
+ current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
+ else
+ current_count = size - count;
+
+ memcpy(current_dest,
+ temp_buf,
+ current_count);
+ offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
+ }
+ return ecc_errors ? -1 : 0;
+}
+
+void nand_deselect(void) {}
diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c
index 34130f8..38d5f92 100644
--- a/drivers/usb/host/ehci-sunxi.c
+++ b/drivers/usb/host/ehci-sunxi.c
@@ -67,7 +67,6 @@ static int ehci_usb_remove(struct udevice *dev)
if (ret)
return ret;
- sunxi_usb_phy_power_off(priv->phy_index);
sunxi_usb_phy_exit(priv->phy_index);
#ifdef CONFIG_SUNXI_GEN_SUN6I
diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c
index e33a8f7..6079272 100644
--- a/drivers/usb/host/ohci-sunxi.c
+++ b/drivers/usb/host/ohci-sunxi.c
@@ -69,7 +69,6 @@ static int ohci_usb_remove(struct udevice *dev)
if (ret)
return ret;
- sunxi_usb_phy_power_off(priv->phy_index);
sunxi_usb_phy_exit(priv->phy_index);
#ifdef CONFIG_SUNXI_GEN_SUN6I
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 16a264a..a146c08 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -196,8 +196,6 @@ static bool enabled = false;
static int sunxi_musb_enable(struct musb *musb)
{
- int ret;
-
pr_debug("%s():\n", __func__);
musb_ep_select(musb->mregs, 0);
@@ -210,17 +208,26 @@ static int sunxi_musb_enable(struct musb *musb)
musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
if (is_host_enabled(musb)) {
- ret = sunxi_usb_phy_vbus_detect(0);
- if (ret == 1) {
- printf("A charger is plugged into the OTG: ");
- return -ENODEV;
+ int id = sunxi_usb_phy_id_detect(0);
+
+ if (id == 1 && sunxi_usb_phy_power_is_on(0))
+ sunxi_usb_phy_power_off(0);
+
+ if (!sunxi_usb_phy_power_is_on(0)) {
+ int vbus = sunxi_usb_phy_vbus_detect(0);
+ if (vbus == 1) {
+ printf("A charger is plugged into the OTG: ");
+ return -ENODEV;
+ }
}
- ret = sunxi_usb_phy_id_detect(0);
- if (ret == 1) {
+
+ if (id == 1) {
printf("No host cable detected: ");
return -ENODEV;
}
- sunxi_usb_phy_power_on(0); /* port power on */
+
+ if (!sunxi_usb_phy_power_is_on(0))
+ sunxi_usb_phy_power_on(0);
}
USBC_ForceVbusValidToHigh(musb->mregs);
@@ -236,9 +243,6 @@ static void sunxi_musb_disable(struct musb *musb)
if (!enabled)
return;
- if (is_host_enabled(musb))
- sunxi_usb_phy_power_off(0); /* port power off */
-
USBC_ForceVbusValidToLow(musb->mregs);
mdelay(200); /* Wait for the current session to timeout */
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
index 269083b..1868185 100644
--- a/drivers/video/sunxi_display.c
+++ b/drivers/video/sunxi_display.c
@@ -2,7 +2,7 @@
* Display driver for Allwinner SoCs.
*
* (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
- * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -40,8 +40,12 @@ enum sunxi_monitor {
sunxi_monitor_hdmi,
sunxi_monitor_lcd,
sunxi_monitor_vga,
+ sunxi_monitor_composite_pal,
+ sunxi_monitor_composite_ntsc,
+ sunxi_monitor_composite_pal_m,
+ sunxi_monitor_composite_pal_nc,
};
-#define SUNXI_MONITOR_LAST sunxi_monitor_vga
+#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
struct sunxi_display {
GraphicDevice graphic_device;
@@ -50,6 +54,12 @@ struct sunxi_display {
unsigned int fb_size;
} sunxi_display;
+const struct ctfb_res_modes composite_video_modes[2] = {
+ /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
+ { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
+ { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
+};
+
#ifdef CONFIG_VIDEO_HDMI
/*
@@ -390,6 +400,25 @@ static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
static void sunxi_frontend_enable(void) {}
#endif
+static bool sunxi_is_composite(void)
+{
+ switch (sunxi_display.monitor) {
+ case sunxi_monitor_none:
+ case sunxi_monitor_dvi:
+ case sunxi_monitor_hdmi:
+ case sunxi_monitor_lcd:
+ case sunxi_monitor_vga:
+ return false;
+ case sunxi_monitor_composite_pal:
+ case sunxi_monitor_composite_ntsc:
+ case sunxi_monitor_composite_pal_m:
+ case sunxi_monitor_composite_pal_nc:
+ return true;
+ }
+
+ return false; /* Never reached */
+}
+
/*
* This is the entity that mixes and matches the different layers and inputs.
* Allwinner calls it the back-end, but i like composer better.
@@ -423,11 +452,18 @@ static void sunxi_composer_init(void)
setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
}
+static u32 sunxi_rgb2yuv_coef[12] = {
+ 0x00000107, 0x00000204, 0x00000064, 0x00000108,
+ 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
+ 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
+};
+
static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
unsigned int address)
{
struct sunxi_de_be_reg * const de_be =
(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+ int i;
sunxi_frontend_mode_set(mode, address);
@@ -445,6 +481,18 @@ static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
+ if (mode->vmode == FB_VMODE_INTERLACED)
+ setbits_le32(&de_be->mode,
+ SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
+ SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
+
+ if (sunxi_is_composite()) {
+ writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
+ &de_be->output_color_ctrl);
+ for (i = 0; i < 12; i++)
+ writel(sunxi_rgb2yuv_coef[i],
+ &de_be->output_color_coef[i]);
+ }
}
static void sunxi_composer_enable(void)
@@ -535,6 +583,9 @@ static void sunxi_lcdc_pll_set(int tcon, int dotclock,
(best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
CCM_LCD_CH1_CTRL_PLL3) |
CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
+ if (sunxi_is_composite())
+ setbits_le32(&ccm->lcd0_ch1_clk_cfg,
+ CCM_LCD_CH1_CTRL_HALF_SCLK1);
}
*clk_div = best_m;
@@ -663,11 +714,16 @@ static void sunxi_lcdc_backlight_enable(void)
gpio_direction_output(pin, PWM_ON);
}
-static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
+static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
{
int delay;
- delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
+ delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
+ if (mode->vmode == FB_VMODE_INTERLACED)
+ delay /= 2;
+ if (tcon == 1)
+ delay -= 2;
+
return (delay > 30) ? 30 : delay;
}
@@ -692,7 +748,7 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
SUNXI_LCDC_CTRL_IO_MAP_TCON0);
- clk_delay = sunxi_lcdc_get_clk_delay(mode);
+ clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
@@ -757,28 +813,33 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
writel(0, &lcdc->tcon0_io_tristate);
}
-#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
+#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
int *clk_div, int *clk_double,
bool use_portd_hvsync)
{
struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
- int bp, clk_delay, total, val;
+ int bp, clk_delay, total, val, yres;
/* Use tcon1 */
clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
SUNXI_LCDC_CTRL_IO_MAP_TCON1);
- clk_delay = sunxi_lcdc_get_clk_delay(mode);
+ clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
+ ((mode->vmode == FB_VMODE_INTERLACED) ?
+ SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
- writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+ yres = mode->yres;
+ if (mode->vmode == FB_VMODE_INTERLACED)
+ yres /= 2;
+ writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
&lcdc->tcon1_timing_source);
- writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+ writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
&lcdc->tcon1_timing_scale);
- writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+ writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
&lcdc->tcon1_timing_out);
bp = mode->hsync_len + mode->left_margin;
@@ -788,6 +849,8 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
bp = mode->vsync_len + mode->upper_margin;
total = mode->yres + mode->lower_margin + bp;
+ if (mode->vmode == FB_VMODE_NONINTERLACED)
+ total *= 2;
writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
@@ -811,7 +874,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
}
sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
}
-#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
+#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
#ifdef CONFIG_VIDEO_HDMI
@@ -925,9 +988,9 @@ static void sunxi_hdmi_enable(void)
#endif /* CONFIG_VIDEO_HDMI */
-#ifdef CONFIG_VIDEO_VGA
+#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
-static void sunxi_vga_mode_set(void)
+static void sunxi_tvencoder_mode_set(void)
{
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
@@ -937,16 +1000,75 @@ static void sunxi_vga_mode_set(void)
/* Clock on */
setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
- /* Set TVE in VGA mode */
- writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
- SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
- SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
- writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
- writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
- writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
+ switch (sunxi_display.monitor) {
+ case sunxi_monitor_vga:
+ writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
+ writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
+ writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
+ writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
+ break;
+ case sunxi_monitor_composite_pal_nc:
+ writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
+ /* Fall through */
+ case sunxi_monitor_composite_pal:
+ writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
+ writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
+ writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
+ writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
+ writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
+ writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
+ writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
+ writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
+ writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
+ writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
+ writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
+ writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
+ writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
+ writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
+ writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
+ writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
+ break;
+ case sunxi_monitor_composite_pal_m:
+ writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
+ writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
+ /* Fall through */
+ case sunxi_monitor_composite_ntsc:
+ writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
+ writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
+ writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
+ writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
+ writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
+ writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
+ writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
+ writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
+ writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
+ writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
+ writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
+ writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
+ writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
+ writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
+ writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
+ writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
+ writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
+ writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
+ break;
+ case sunxi_monitor_none:
+ case sunxi_monitor_dvi:
+ case sunxi_monitor_hdmi:
+ case sunxi_monitor_lcd:
+ break;
+ }
}
-static void sunxi_vga_enable(void)
+static void sunxi_tvencoder_enable(void)
{
struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
@@ -954,7 +1076,7 @@ static void sunxi_vga_enable(void)
setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
}
-#endif /* CONFIG_VIDEO_VGA */
+#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
static void sunxi_drc_init(void)
{
@@ -1069,10 +1191,10 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
#ifdef CONFIG_VIDEO_VGA
sunxi_composer_mode_set(mode, address);
sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
- sunxi_vga_mode_set();
+ sunxi_tvencoder_mode_set();
sunxi_composer_enable();
sunxi_lcdc_enable();
- sunxi_vga_enable();
+ sunxi_tvencoder_enable();
#elif defined CONFIG_VIDEO_VGA_VIA_LCD
sunxi_composer_mode_set(mode, address);
sunxi_lcdc_tcon0_mode_set(mode, true);
@@ -1081,17 +1203,34 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
sunxi_vga_external_dac_enable();
#endif
break;
+ case sunxi_monitor_composite_pal:
+ case sunxi_monitor_composite_ntsc:
+ case sunxi_monitor_composite_pal_m:
+ case sunxi_monitor_composite_pal_nc:
+#ifdef CONFIG_VIDEO_COMPOSITE
+ sunxi_composer_mode_set(mode, address);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
+ sunxi_tvencoder_mode_set();
+ sunxi_composer_enable();
+ sunxi_lcdc_enable();
+ sunxi_tvencoder_enable();
+#endif
+ break;
}
}
static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
{
switch (monitor) {
- case sunxi_monitor_none: return "none";
- case sunxi_monitor_dvi: return "dvi";
- case sunxi_monitor_hdmi: return "hdmi";
- case sunxi_monitor_lcd: return "lcd";
- case sunxi_monitor_vga: return "vga";
+ case sunxi_monitor_none: return "none";
+ case sunxi_monitor_dvi: return "dvi";
+ case sunxi_monitor_hdmi: return "hdmi";
+ case sunxi_monitor_lcd: return "lcd";
+ case sunxi_monitor_vga: return "vga";
+ case sunxi_monitor_composite_pal: return "composite-pal";
+ case sunxi_monitor_composite_ntsc: return "composite-ntsc";
+ case sunxi_monitor_composite_pal_m: return "composite-pal-m";
+ case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
}
return NULL; /* never reached */
}
@@ -1101,6 +1240,54 @@ ulong board_get_usable_ram_top(ulong total_size)
return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
}
+static bool sunxi_has_hdmi(void)
+{
+#ifdef CONFIG_VIDEO_HDMI
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool sunxi_has_lcd(void)
+{
+ char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
+
+ return lcd_mode[0] != 0;
+}
+
+static bool sunxi_has_vga(void)
+{
+#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool sunxi_has_composite(void)
+{
+#ifdef CONFIG_VIDEO_COMPOSITE
+ return true;
+#else
+ return false;
+#endif
+}
+
+static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
+{
+ if (allow_hdmi && sunxi_has_hdmi())
+ return sunxi_monitor_dvi;
+ else if (sunxi_has_lcd())
+ return sunxi_monitor_lcd;
+ else if (sunxi_has_vga())
+ return sunxi_monitor_vga;
+ else if (sunxi_has_composite())
+ return sunxi_monitor_composite_pal;
+ else
+ return sunxi_monitor_none;
+}
+
void *video_hw_init(void)
{
static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
@@ -1122,12 +1309,8 @@ void *video_hw_init(void)
hpd = video_get_option_int(options, "hpd", 1);
hpd_delay = video_get_option_int(options, "hpd_delay", 500);
edid = video_get_option_int(options, "edid", 1);
- sunxi_display.monitor = sunxi_monitor_dvi;
-#elif defined CONFIG_VIDEO_VGA_VIA_LCD
- sunxi_display.monitor = sunxi_monitor_vga;
-#else
- sunxi_display.monitor = sunxi_monitor_lcd;
#endif
+ sunxi_display.monitor = sunxi_get_default_mon(true);
video_get_option_string(options, "monitor", mon, sizeof(mon),
sunxi_get_mon_desc(sunxi_display.monitor));
for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
@@ -1152,16 +1335,7 @@ void *video_hw_init(void)
mode = &custom;
} else if (hpd) {
sunxi_hdmi_shutdown();
- /* Fallback to lcd / vga / none */
- if (lcd_mode[0]) {
- sunxi_display.monitor = sunxi_monitor_lcd;
- } else {
-#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
- sunxi_display.monitor = sunxi_monitor_vga;
-#else
- sunxi_display.monitor = sunxi_monitor_none;
-#endif
- }
+ sunxi_display.monitor = sunxi_get_default_mon(false);
} /* else continue with hdmi/dvi without a cable connected */
}
#endif
@@ -1171,39 +1345,45 @@ void *video_hw_init(void)
return NULL;
case sunxi_monitor_dvi:
case sunxi_monitor_hdmi:
-#ifdef CONFIG_VIDEO_HDMI
+ if (!sunxi_has_hdmi()) {
+ printf("HDMI/DVI not supported on this board\n");
+ sunxi_display.monitor = sunxi_monitor_none;
+ return NULL;
+ }
break;
-#else
- printf("HDMI/DVI not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
-#endif
case sunxi_monitor_lcd:
- if (lcd_mode[0]) {
- sunxi_display.depth = video_get_params(&custom, lcd_mode);
- mode = &custom;
- break;
+ if (!sunxi_has_lcd()) {
+ printf("LCD not supported on this board\n");
+ sunxi_display.monitor = sunxi_monitor_none;
+ return NULL;
}
- printf("LCD not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display.depth = video_get_params(&custom, lcd_mode);
+ mode = &custom;
+ break;
case sunxi_monitor_vga:
-#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
+ if (!sunxi_has_vga()) {
+ printf("VGA not supported on this board\n");
+ sunxi_display.monitor = sunxi_monitor_none;
+ return NULL;
+ }
sunxi_display.depth = 18;
break;
-#else
- printf("VGA not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
-#endif
- }
-
- if (mode->vmode != FB_VMODE_NONINTERLACED) {
- printf("Only non-interlaced modes supported, falling back to 1024x768\n");
- mode = &res_mode_init[RES_MODE_1024x768];
- } else {
- printf("Setting up a %dx%d %s console\n", mode->xres,
- mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
+ case sunxi_monitor_composite_pal:
+ case sunxi_monitor_composite_ntsc:
+ case sunxi_monitor_composite_pal_m:
+ case sunxi_monitor_composite_pal_nc:
+ if (!sunxi_has_composite()) {
+ printf("Composite video not supported on this board\n");
+ sunxi_display.monitor = sunxi_monitor_none;
+ return NULL;
+ }
+ if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
+ sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
+ mode = &composite_video_modes[0];
+ else
+ mode = &composite_video_modes[1];
+ sunxi_display.depth = 24;
+ break;
}
sunxi_display.fb_size =
@@ -1215,6 +1395,10 @@ void *video_hw_init(void)
return NULL;
}
+ printf("Setting up a %dx%d%s %s console\n", mode->xres, mode->yres,
+ (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
+ sunxi_get_mon_desc(sunxi_display.monitor));
+
gd->fb_base = gd->bd->bi_dram[0].start +
gd->bd->bi_dram[0].size - sunxi_display.fb_size;
sunxi_engines_init();
@@ -1268,6 +1452,12 @@ int sunxi_simplefb_setup(void *blob)
pipeline = PIPELINE_PREFIX "de_be0-lcd0";
#endif
break;
+ case sunxi_monitor_composite_pal:
+ case sunxi_monitor_composite_ntsc:
+ case sunxi_monitor_composite_pal_m:
+ case sunxi_monitor_composite_pal_nc:
+ pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
+ break;
}
/* Find a prefilled simpefb node, matching out pipeline config */