summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/cpu/armv7/omap-common/Makefile6
-rw-r--r--arch/arm/dts/Makefile2
-rw-r--r--arch/arm/dts/am335x-boneblack.dts1
-rw-r--r--arch/arm/dts/am335x-evm.dts1
-rw-r--r--arch/arm/dts/am437x-gp-evm.dts1
-rw-r--r--arch/arm/dts/am437x-sk-evm.dts1
-rw-r--r--arch/arm/dts/dra7-evm.dts1
-rw-r--r--arch/arm/dts/dra72-evm.dts1
-rw-r--r--arch/arm/dts/ls1021a-twr-duart.dts16
-rw-r--r--arch/arm/dts/ls1021a-twr-lpuart.dts16
-rw-r--r--arch/arm/dts/ls1021a-twr.dtsi (renamed from arch/arm/dts/ls1021a-twr.dts)7
-rw-r--r--arch/arm/dts/ls1021a.dtsi4
-rw-r--r--arch/sandbox/dts/sandbox.dts1
-rw-r--r--arch/sandbox/dts/test.dts7
-rw-r--r--board/sandbox/sandbox.c17
-rw-r--r--common/Makefile2
-rw-r--r--common/board_f.c71
-rw-r--r--common/cmd_bmp.c37
-rw-r--r--common/cmd_i2c.c6
-rw-r--r--common/fdt_support.c16
-rw-r--r--common/lcd.c11
-rw-r--r--common/stdio.c19
-rw-r--r--common/usb_storage.c1
-rw-r--r--configs/am335x_boneblack_vboot_defconfig2
-rw-r--r--configs/am335x_gp_evm_defconfig2
-rw-r--r--configs/am437x_gp_evm_defconfig2
-rw-r--r--configs/am437x_sk_evm_defconfig2
-rw-r--r--configs/colibri_vf_defconfig1
-rw-r--r--configs/colibri_vf_dtb_defconfig1
-rw-r--r--configs/dra72_evm_defconfig2
-rw-r--r--configs/dra74_evm_defconfig2
-rw-r--r--configs/ls1021aqds_ddr4_nor_lpuart_defconfig1
-rw-r--r--configs/ls1021aqds_nor_lpuart_defconfig1
-rw-r--r--configs/ls1021atwr_nor_defconfig4
-rw-r--r--configs/ls1021atwr_nor_lpuart_defconfig5
-rw-r--r--configs/ls1021atwr_qspi_defconfig2
-rw-r--r--configs/ls1021atwr_sdcard_qspi_defconfig2
-rw-r--r--configs/pcm052_defconfig1
-rw-r--r--configs/sandbox_defconfig5
-rw-r--r--configs/vf610twr_defconfig1
-rw-r--r--configs/vf610twr_nand_defconfig1
-rw-r--r--doc/device-tree-bindings/chosen.txt43
-rw-r--r--doc/driver-model/serial-howto.txt1
-rw-r--r--drivers/clk/Kconfig4
-rw-r--r--drivers/clk/clk-uclass.c10
-rw-r--r--drivers/clk/clk_rk3036.c2
-rw-r--r--drivers/clk/clk_rk3288.c2
-rw-r--r--drivers/clk/clk_sandbox.c5
-rw-r--r--drivers/core/device.c7
-rw-r--r--drivers/core/uclass.c9
-rw-r--r--drivers/gpio/gpio-uclass.c8
-rw-r--r--drivers/mmc/mmc.c20
-rw-r--r--drivers/pinctrl/pinctrl-uclass.c4
-rw-r--r--drivers/serial/Kconfig6
-rw-r--r--drivers/serial/sandbox.c5
-rw-r--r--drivers/serial/serial_lpuart.c286
-rw-r--r--drivers/timer/Kconfig6
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/omap-timer.c108
-rw-r--r--drivers/timer/sandbox_timer.c10
-rw-r--r--drivers/timer/timer-uclass.c56
-rw-r--r--drivers/video/Kconfig62
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/console_normal.c141
-rw-r--r--drivers/video/console_rotate.c436
-rw-r--r--drivers/video/sandbox_sdl.c90
-rw-r--r--drivers/video/vidconsole-uclass.c239
-rw-r--r--drivers/video/video-uclass.c249
-rw-r--r--drivers/video/video_bmp.c353
-rw-r--r--include/asm-generic/global_data.h4
-rw-r--r--include/bzlib.h3
-rw-r--r--include/clk.h42
-rw-r--r--include/configs/am335x_evm.h1
-rw-r--r--include/configs/am43xx_evm.h1
-rw-r--r--include/configs/colibri_vf.h1
-rw-r--r--include/configs/ls1021aqds.h1
-rw-r--r--include/configs/ls1021atwr.h3
-rw-r--r--include/configs/pcm052.h1
-rw-r--r--include/configs/sandbox.h13
-rw-r--r--include/configs/ti_omap5_common.h1
-rw-r--r--include/configs/vf610twr.h1
-rw-r--r--include/dm/test.h8
-rw-r--r--include/dm/uclass-id.h2
-rw-r--r--include/fdtdec.h1
-rw-r--r--include/lcd.h12
-rw-r--r--include/timer.h9
-rw-r--r--include/video.h168
-rw-r--r--include/video_console.h136
-rw-r--r--lib/bzip2/Makefile1
-rw-r--r--lib/bzip2/bzlib_blocksort.c1134
-rw-r--r--lib/bzip2/bzlib_compress.c714
-rw-r--r--lib/fdtdec.c1
-rw-r--r--lib/time.c17
-rw-r--r--lib/tiny-printf.c22
-rwxr-xr-xtest/cmd_repeat.sh29
-rw-r--r--test/command_ut.c136
-rw-r--r--test/dm/Makefile1
-rw-r--r--test/dm/video.c271
-rw-r--r--test/py/.gitignore1
-rw-r--r--test/py/README.md300
-rw-r--r--test/py/conftest.py422
-rw-r--r--test/py/multiplexed_log.css88
-rw-r--r--test/py/multiplexed_log.py515
-rw-r--r--test/py/pytest.ini11
-rwxr-xr-xtest/py/test.py32
-rw-r--r--test/py/tests/test_000_version.py20
-rw-r--r--test/py/tests/test_env.py221
-rw-r--r--test/py/tests/test_help.py9
-rw-r--r--test/py/tests/test_hush_if_test.py154
-rw-r--r--test/py/tests/test_md.py36
-rw-r--r--test/py/tests/test_sandbox_exit.py24
-rw-r--r--test/py/tests/test_shell_basics.py42
-rw-r--r--test/py/tests/test_sleep.py24
-rw-r--r--test/py/tests/test_ums.py94
-rw-r--r--test/py/tests/test_unknown_cmd.py14
-rw-r--r--test/py/u_boot_console_base.py360
-rw-r--r--test/py/u_boot_console_exec_attach.py65
-rw-r--r--test/py/u_boot_console_sandbox.py79
-rw-r--r--test/py/u_boot_spawn.py174
-rw-r--r--tools/logos/denx-comp.bmpbin0 -> 4148 bytes
-rw-r--r--tools/patman/gitutil.py6
-rwxr-xr-xtools/patman/patman.py4
122 files changed, 7455 insertions, 422 deletions
diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile
index 464a5d1d73..87a7ac03f9 100644
--- a/arch/arm/cpu/armv7/omap-common/Makefile
+++ b/arch/arm/cpu/armv7/omap-common/Makefile
@@ -6,7 +6,13 @@
#
obj-y := reset.o
+ifeq ($(CONFIG_TIMER),)
obj-y += timer.o
+else
+ifdef CONFIG_SPL_BUILD
+obj-y += timer.o
+endif
+endif
obj-y += utils.o
ifneq ($(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),)
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index e4f8aaef55..7706b41b2d 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -93,7 +93,7 @@ dtb-$(CONFIG_TARGET_BEAGLE_X15) += am57xx-beagle-x15.dtb
dtb-$(CONFIG_TARGET_STV0991) += stv0991.dtb
dtb-$(CONFIG_LS102XA) += ls1021a-qds.dtb \
- ls1021a-twr.dtb
+ ls1021a-twr-duart.dtb ls1021a-twr-lpuart.dtb
dtb-$(CONFIG_FSL_LSCH3) += fsl-ls2080a-qds.dtb \
fsl-ls2080a-rdb.dtb
dtb-$(CONFIG_FSL_LSCH2) += fsl-ls1043a-qds.dtb \
diff --git a/arch/arm/dts/am335x-boneblack.dts b/arch/arm/dts/am335x-boneblack.dts
index 679248aa02..27ebe4a65d 100644
--- a/arch/arm/dts/am335x-boneblack.dts
+++ b/arch/arm/dts/am335x-boneblack.dts
@@ -15,6 +15,7 @@
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
chosen {
stdout-path = &uart0;
+ tick-timer = &timer2;
};
};
diff --git a/arch/arm/dts/am335x-evm.dts b/arch/arm/dts/am335x-evm.dts
index e1c5d4f76c..c0bc2af9a5 100644
--- a/arch/arm/dts/am335x-evm.dts
+++ b/arch/arm/dts/am335x-evm.dts
@@ -16,6 +16,7 @@
chosen {
stdout-path = &uart0;
+ tick-timer = &timer2;
};
cpus {
diff --git a/arch/arm/dts/am437x-gp-evm.dts b/arch/arm/dts/am437x-gp-evm.dts
index b5f0b4ee69..8e23b96609 100644
--- a/arch/arm/dts/am437x-gp-evm.dts
+++ b/arch/arm/dts/am437x-gp-evm.dts
@@ -26,6 +26,7 @@
chosen {
stdout-path = &uart0;
+ tick-timer = &timer2;
};
vmmcsd_fixed: fixedregulator-sd {
diff --git a/arch/arm/dts/am437x-sk-evm.dts b/arch/arm/dts/am437x-sk-evm.dts
index 89feaf3eb7..260edb93ec 100644
--- a/arch/arm/dts/am437x-sk-evm.dts
+++ b/arch/arm/dts/am437x-sk-evm.dts
@@ -26,6 +26,7 @@
chosen {
stdout-path = &uart0;
+ tick-timer = &timer2;
};
backlight {
diff --git a/arch/arm/dts/dra7-evm.dts b/arch/arm/dts/dra7-evm.dts
index 797d411d6f..242fd53516 100644
--- a/arch/arm/dts/dra7-evm.dts
+++ b/arch/arm/dts/dra7-evm.dts
@@ -16,6 +16,7 @@
chosen {
stdout-path = &uart1;
+ tick-timer = &timer2;
};
memory {
diff --git a/arch/arm/dts/dra72-evm.dts b/arch/arm/dts/dra72-evm.dts
index a62550f0e0..fc2d167dee 100644
--- a/arch/arm/dts/dra72-evm.dts
+++ b/arch/arm/dts/dra72-evm.dts
@@ -16,6 +16,7 @@
chosen {
stdout-path = &uart1;
+ tick-timer = &timer2;
};
memory {
diff --git a/arch/arm/dts/ls1021a-twr-duart.dts b/arch/arm/dts/ls1021a-twr-duart.dts
new file mode 100644
index 0000000000..aaf72966f9
--- /dev/null
+++ b/arch/arm/dts/ls1021a-twr-duart.dts
@@ -0,0 +1,16 @@
+/*
+ * Freescale ls1021a TWR board device tree source
+ *
+ * Copyright 2013-2015 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "ls1021a-twr.dtsi"
+
+/ {
+ chosen {
+ stdout-path = &uart0;
+ };
+};
diff --git a/arch/arm/dts/ls1021a-twr-lpuart.dts b/arch/arm/dts/ls1021a-twr-lpuart.dts
new file mode 100644
index 0000000000..2941ec0164
--- /dev/null
+++ b/arch/arm/dts/ls1021a-twr-lpuart.dts
@@ -0,0 +1,16 @@
+/*
+ * Freescale ls1021a TWR board device tree source
+ *
+ * Copyright 2013-2015 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "ls1021a-twr.dtsi"
+
+/ {
+ chosen {
+ stdout-path = &lpuart0;
+ };
+};
diff --git a/arch/arm/dts/ls1021a-twr.dts b/arch/arm/dts/ls1021a-twr.dtsi
index 6ccd33279b..d1be9ae5c2 100644
--- a/arch/arm/dts/ls1021a-twr.dts
+++ b/arch/arm/dts/ls1021a-twr.dtsi
@@ -1,12 +1,11 @@
/*
- * Freescale ls1021a TWR board device tree source
+ * Freescale ls1021a TWR board common device tree source
*
* Copyright 2013-2015 Freescale Semiconductor, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
-/dts-v1/;
#include "ls1021a.dtsi"
/ {
@@ -19,6 +18,10 @@
spi0 = &qspi;
spi1 = &dspi1;
};
+
+ chosen {
+ stdout-path = &uart0;
+ };
};
&qspi {
diff --git a/arch/arm/dts/ls1021a.dtsi b/arch/arm/dts/ls1021a.dtsi
index 7fadd7ca57..ee0e55461d 100644
--- a/arch/arm/dts/ls1021a.dtsi
+++ b/arch/arm/dts/ls1021a.dtsi
@@ -218,7 +218,6 @@
compatible = "fsl,16550-FIFO64", "ns16550a";
reg = <0x21c0500 0x100>;
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <0>;
fifo-size = <15>;
status = "disabled";
};
@@ -227,7 +226,6 @@
compatible = "fsl,16550-FIFO64", "ns16550a";
reg = <0x21c0600 0x100>;
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <0>;
fifo-size = <15>;
status = "disabled";
};
@@ -236,7 +234,6 @@
compatible = "fsl,16550-FIFO64", "ns16550a";
reg = <0x21d0500 0x100>;
interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <0>;
fifo-size = <15>;
status = "disabled";
};
@@ -245,7 +242,6 @@
compatible = "fsl,16550-FIFO64", "ns16550a";
reg = <0x21d0600 0x100>;
interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <0>;
fifo-size = <15>;
status = "disabled";
};
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index d2addb4cf0..e3f02bf13c 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -117,6 +117,7 @@
};
lcd {
+ u-boot,dm-pre-reloc;
compatible = "sandbox,lcd-sdl";
xres = <1366>;
yres = <768>;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 2e0d320b1e..9b8d658bf3 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -195,6 +195,13 @@
vss-microvolts = <0>;
};
+ lcd {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,lcd-sdl";
+ xres = <1366>;
+ yres = <768>;
+ };
+
leds {
compatible = "gpio-leds";
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
index 592f7728c0..b41e9decb3 100644
--- a/board/sandbox/sandbox.c
+++ b/board/sandbox/sandbox.c
@@ -47,23 +47,6 @@ int dram_init(void)
return 0;
}
-#ifdef CONFIG_BOARD_EARLY_INIT_F
-int board_early_init_f(void)
-{
-#ifdef CONFIG_VIDEO_SANDBOX_SDL
- int ret;
-
- ret = sandbox_lcd_sdl_early_init();
- if (ret) {
- puts("Could not init sandbox LCD emulation\n");
- return ret;
- }
-#endif
-
- return 0;
-}
-#endif
-
#ifdef CONFIG_BOARD_LATE_INIT
int board_late_init(void)
{
diff --git a/common/Makefile b/common/Makefile
index 2a1d9f8331..249227597a 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -205,7 +205,9 @@ obj-$(CONFIG_I2C_EDID) += edid.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-y += splash.o
obj-$(CONFIG_SPLASH_SOURCE) += splash_source.o
+ifndef CONFIG_DM_VIDEO
obj-$(CONFIG_LCD) += lcd.o lcd_console.o
+endif
obj-$(CONFIG_LCD_ROTATION) += lcd_console_rotation.o
obj-$(CONFIG_LCD_DT_SIMPLEFB) += lcd_simplefb.o
obj-$(CONFIG_LYNXKDI) += lynxkdi.o
diff --git a/common/board_f.c b/common/board_f.c
index 8094ac4efe..c470b5921a 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -46,6 +46,7 @@
#include <spi.h>
#include <status_led.h>
#include <trace.h>
+#include <video.h>
#include <watchdog.h>
#include <asm/errno.h>
#include <asm/io.h>
@@ -437,36 +438,41 @@ static int reserve_mmu(void)
}
#endif
-#ifdef CONFIG_LCD
+#ifdef CONFIG_DM_VIDEO
+static int reserve_video(void)
+{
+ ulong addr;
+ int ret;
+
+ addr = gd->relocaddr;
+ ret = video_reserve(&addr);
+ if (ret)
+ return ret;
+ gd->relocaddr = addr;
+
+ return 0;
+}
+#else
+
+# ifdef CONFIG_LCD
static int reserve_lcd(void)
{
-#ifdef CONFIG_FB_ADDR
+# ifdef CONFIG_FB_ADDR
gd->fb_base = CONFIG_FB_ADDR;
-#else
+# else
/* reserve memory for LCD display (always full pages) */
gd->relocaddr = lcd_setmem(gd->relocaddr);
gd->fb_base = gd->relocaddr;
-#endif /* CONFIG_FB_ADDR */
- return 0;
-}
-#endif /* CONFIG_LCD */
-
-static int reserve_trace(void)
-{
-#ifdef CONFIG_TRACE
- gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE;
- gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE);
- debug("Reserving %dk for trace data at: %08lx\n",
- CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr);
-#endif
+# endif /* CONFIG_FB_ADDR */
return 0;
}
+# endif /* CONFIG_LCD */
-#if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
+# if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
!defined(CONFIG_ARM) && !defined(CONFIG_X86) && \
!defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K)
-static int reserve_video(void)
+static int reserve_legacy_video(void)
{
/* reserve memory for video display (always full pages) */
gd->relocaddr = video_setmem(gd->relocaddr);
@@ -474,8 +480,21 @@ static int reserve_video(void)
return 0;
}
+# endif
+#endif /* !CONFIG_DM_VIDEO */
+
+static int reserve_trace(void)
+{
+#ifdef CONFIG_TRACE
+ gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE;
+ gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE);
+ debug("Reserving %dk for trace data at: %08lx\n",
+ CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr);
#endif
+ return 0;
+}
+
static int reserve_uboot(void)
{
/*
@@ -957,16 +976,20 @@ static init_fnc_t init_sequence_f[] = {
defined(CONFIG_ARM)
reserve_mmu,
#endif
-#ifdef CONFIG_LCD
+#ifdef CONFIG_DM_VIDEO
+ reserve_video,
+#else
+# ifdef CONFIG_LCD
reserve_lcd,
-#endif
- reserve_trace,
+# endif
/* TODO: Why the dependency on CONFIG_8xx? */
-#if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
+# if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
!defined(CONFIG_ARM) && !defined(CONFIG_X86) && \
!defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K)
- reserve_video,
-#endif
+ reserve_legacy_video,
+# endif
+#endif /* CONFIG_DM_VIDEO */
+ reserve_trace,
#if !defined(CONFIG_BLACKFIN)
reserve_uboot,
#endif
diff --git a/common/cmd_bmp.c b/common/cmd_bmp.c
index cb1f07119b..fd5b7db288 100644
--- a/common/cmd_bmp.c
+++ b/common/cmd_bmp.c
@@ -10,11 +10,14 @@
*/
#include <common.h>
+#include <dm.h>
#include <lcd.h>
+#include <mapmem.h>
#include <bmp_layout.h>
#include <command.h>
#include <asm/byteorder.h>
#include <malloc.h>
+#include <mapmem.h>
#include <splash.h>
#include <video.h>
@@ -57,7 +60,8 @@ struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp,
/* align to 32-bit-aligned-address + 2 */
bmp = (struct bmp_image *)((((unsigned int)dst + 1) & ~3) + 2);
- if (gunzip(bmp, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, (uchar *)addr, &len) != 0) {
+ if (gunzip(bmp, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, map_sysmem(addr, 0),
+ &len) != 0) {
free(dst);
return NULL;
}
@@ -187,7 +191,7 @@ U_BOOT_CMD(
*/
static int bmp_info(ulong addr)
{
- struct bmp_image *bmp = (struct bmp_image *)addr;
+ struct bmp_image *bmp = (struct bmp_image *)map_sysmem(addr, 0);
void *bmp_alloc_addr = NULL;
unsigned long len;
@@ -223,8 +227,11 @@ static int bmp_info(ulong addr)
*/
int bmp_display(ulong addr, int x, int y)
{
+#ifdef CONFIG_DM_VIDEO
+ struct udevice *dev;
+#endif
int ret;
- struct bmp_image *bmp = (struct bmp_image *)addr;
+ struct bmp_image *bmp = map_sysmem(addr, 0);
void *bmp_alloc_addr = NULL;
unsigned long len;
@@ -236,11 +243,27 @@ int bmp_display(ulong addr, int x, int y)
printf("There is no valid bmp file at the given address\n");
return 1;
}
-
-#if defined(CONFIG_LCD)
- ret = lcd_display_bitmap((ulong)bmp, x, y);
+ addr = map_to_sysmem(bmp);
+
+#ifdef CONFIG_DM_VIDEO
+ ret = uclass_first_device(UCLASS_VIDEO, &dev);
+ if (!ret) {
+ if (!dev)
+ ret = -ENODEV;
+ if (!ret) {
+ bool align = false;
+
+# ifdef CONFIG_SPLASH_SCREEN_ALIGN
+ align = true;
+# endif /* CONFIG_SPLASH_SCREEN_ALIGN */
+ ret = video_bmp_display(dev, addr, x, y, align);
+ }
+ }
+ return ret ? CMD_RET_FAILURE : 0;
+#elif defined(CONFIG_LCD)
+ ret = lcd_display_bitmap(addr, x, y);
#elif defined(CONFIG_VIDEO)
- ret = video_display_bitmap((unsigned long)bmp, x, y);
+ ret = video_display_bitmap(addr, x, y);
#else
# error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO
#endif
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index 552c875f62..b3bb64408f 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -1809,7 +1809,8 @@ static int do_i2c_bus_num(cmd_tbl_t *cmdtp, int flag, int argc,
if (ret)
printf("Failure changing bus number (%d)\n", ret);
}
- return ret;
+
+ return ret ? CMD_RET_FAILURE : 0;
}
#endif /* defined(CONFIG_SYS_I2C) */
@@ -1852,7 +1853,8 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const
if (ret)
printf("Failure changing bus speed (%d)\n", ret);
}
- return ret;
+
+ return ret ? CMD_RET_FAILURE : 0;
}
/**
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 09f923716c..75d0858e76 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -131,18 +131,6 @@ static int fdt_fixup_stdout(void *fdt, int chosenoff)
OF_STDOUT_PATH, strlen(OF_STDOUT_PATH) + 1);
}
#elif defined(CONFIG_OF_STDOUT_VIA_ALIAS) && defined(CONFIG_CONS_INDEX)
-static void fdt_fill_multisername(char *sername, size_t maxlen)
-{
- const char *outname = stdio_devices[stdout]->name;
-
- if (strcmp(outname, "serial") > 0)
- strncpy(sername, outname, maxlen);
-
- /* eserial? */
- if (strcmp(outname + 1, "serial") > 0)
- strncpy(sername, outname + 1, maxlen);
-}
-
static int fdt_fixup_stdout(void *fdt, int chosenoff)
{
int err;
@@ -152,9 +140,7 @@ static int fdt_fixup_stdout(void *fdt, int chosenoff)
int len;
char tmp[256]; /* long enough */
- fdt_fill_multisername(sername, sizeof(sername) - 1);
- if (!sername[0])
- sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
+ sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
aliasoff = fdt_path_offset(fdt, "/aliases");
if (aliasoff < 0) {
diff --git a/common/lcd.c b/common/lcd.c
index d29308aeb6..2f3594a417 100644
--- a/common/lcd.c
+++ b/common/lcd.c
@@ -31,10 +31,6 @@
#endif
#endif
-#ifdef CONFIG_SANDBOX
-#include <asm/sdl.h>
-#endif
-
#ifndef CONFIG_LCD_ALIGNMENT
#define CONFIG_LCD_ALIGNMENT PAGE_SIZE
#endif
@@ -72,13 +68,6 @@ void lcd_sync(void)
if (lcd_flush_dcache)
flush_dcache_range((u32)lcd_base,
(u32)(lcd_base + lcd_get_size(&line_length)));
-#elif defined(CONFIG_SANDBOX) && defined(CONFIG_VIDEO_SANDBOX_SDL)
- static ulong last_sync;
-
- if (get_timer(last_sync) > 10) {
- sandbox_sdl_sync(lcd_base);
- last_sync = get_timer(0);
- }
#endif
}
diff --git a/common/stdio.c b/common/stdio.c
index 8311ac768c..7252bab1f6 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -281,12 +281,23 @@ int stdio_add_devices(void)
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#endif
-#ifdef CONFIG_LCD
+#ifdef CONFIG_DM_VIDEO
+ struct udevice *vdev;
+
+ for (ret = uclass_first_device(UCLASS_VIDEO, &vdev);
+ vdev;
+ ret = uclass_next_device(&vdev))
+ ;
+ if (ret)
+ printf("%s: Video device failed (ret=%d)\n", __func__, ret);
+#else
+# if defined(CONFIG_LCD)
drv_lcd_init ();
-#endif
-#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
+# endif
+# if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
drv_video_init ();
-#endif
+# endif
+#endif /* CONFIG_DM_VIDEO */
#if defined(CONFIG_KEYBOARD) && !defined(CONFIG_DM_KEYBOARD)
drv_keyboard_init ();
#endif
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 4fdb55f9fa..8737cf7cea 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -65,7 +65,6 @@ static const unsigned char us_direction[256/8] = {
static ccb usb_ccb __attribute__((aligned(ARCH_DMA_MINALIGN)));
static __u32 CBWTag;
-#define USB_MAX_STOR_DEV 7
static int usb_max_devs; /* number of highest available usb device */
static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
diff --git a/configs/am335x_boneblack_vboot_defconfig b/configs/am335x_boneblack_vboot_defconfig
index 5dcb942f39..060aa1cd98 100644
--- a/configs/am335x_boneblack_vboot_defconfig
+++ b/configs/am335x_boneblack_vboot_defconfig
@@ -22,3 +22,5 @@ CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_DM_ETH=y
CONFIG_SYS_NS16550=y
+CONFIG_TIMER=y
+CONFIG_OMAP_TIMER=y
diff --git a/configs/am335x_gp_evm_defconfig b/configs/am335x_gp_evm_defconfig
index 74d9ffb677..49461e2cda 100644
--- a/configs/am335x_gp_evm_defconfig
+++ b/configs/am335x_gp_evm_defconfig
@@ -16,3 +16,5 @@ CONFIG_SPI_FLASH_WINBOND=y
CONFIG_DM_ETH=y
CONFIG_SYS_NS16550=y
CONFIG_RSA=y
+CONFIG_TIMER=y
+CONFIG_OMAP_TIMER=y
diff --git a/configs/am437x_gp_evm_defconfig b/configs/am437x_gp_evm_defconfig
index 7155c98f8f..1d79ba19eb 100644
--- a/configs/am437x_gp_evm_defconfig
+++ b/configs/am437x_gp_evm_defconfig
@@ -18,3 +18,5 @@ CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_SYS_NS16550=y
CONFIG_TI_QSPI=y
+CONFIG_TIMER=y
+CONFIG_OMAP_TIMER=y
diff --git a/configs/am437x_sk_evm_defconfig b/configs/am437x_sk_evm_defconfig
index 8f78eeb8b9..9eb41f9322 100644
--- a/configs/am437x_sk_evm_defconfig
+++ b/configs/am437x_sk_evm_defconfig
@@ -21,3 +21,5 @@ CONFIG_TI_QSPI=y
CONFIG_DM_SPI=y
CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH_BAR=y
+CONFIG_TIMER=y
+CONFIG_OMAP_TIMER=y
diff --git a/configs/colibri_vf_defconfig b/configs/colibri_vf_defconfig
index f8441e351b..45917c837f 100644
--- a/configs/colibri_vf_defconfig
+++ b/configs/colibri_vf_defconfig
@@ -8,3 +8,4 @@ CONFIG_CMD_GPIO=y
CONFIG_DM=y
CONFIG_NAND_VF610_NFC=y
CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES=y
+CONFIG_FSL_LPUART=y
diff --git a/configs/colibri_vf_dtb_defconfig b/configs/colibri_vf_dtb_defconfig
index 3596cecb7d..b1a843a787 100644
--- a/configs/colibri_vf_dtb_defconfig
+++ b/configs/colibri_vf_dtb_defconfig
@@ -11,3 +11,4 @@ CONFIG_OF_CONTROL=y
CONFIG_DM=y
CONFIG_NAND_VF610_NFC=y
CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES=y
+CONFIG_FSL_LPUART=y
diff --git a/configs/dra72_evm_defconfig b/configs/dra72_evm_defconfig
index b57ecca696..32d1dc1d2b 100644
--- a/configs/dra72_evm_defconfig
+++ b/configs/dra72_evm_defconfig
@@ -22,3 +22,5 @@ CONFIG_SYS_NS16550=y
CONFIG_TI_QSPI=y
CONFIG_DM_SPI=y
CONFIG_DM_SPI_FLASH=y
+CONFIG_TIMER=y
+CONFIG_OMAP_TIMER=y
diff --git a/configs/dra74_evm_defconfig b/configs/dra74_evm_defconfig
index 6e5a7051a4..9946261909 100644
--- a/configs/dra74_evm_defconfig
+++ b/configs/dra74_evm_defconfig
@@ -21,3 +21,5 @@ CONFIG_SYS_NS16550=y
CONFIG_TI_QSPI=y
CONFIG_DM_SPI=y
CONFIG_DM_SPI_FLASH=y
+CONFIG_TIMER=y
+CONFIG_OMAP_TIMER=y
diff --git a/configs/ls1021aqds_ddr4_nor_lpuart_defconfig b/configs/ls1021aqds_ddr4_nor_lpuart_defconfig
index 68bd117b1c..44b2a0d1e5 100644
--- a/configs/ls1021aqds_ddr4_nor_lpuart_defconfig
+++ b/configs/ls1021aqds_ddr4_nor_lpuart_defconfig
@@ -4,3 +4,4 @@ CONFIG_SYS_EXTRA_OPTIONS="SYS_FSL_DDR4,LPUART"
# CONFIG_CMD_SETEXPR is not set
CONFIG_NETDEVICES=y
CONFIG_E1000=y
+CONFIG_FSL_LPUART=y
diff --git a/configs/ls1021aqds_nor_lpuart_defconfig b/configs/ls1021aqds_nor_lpuart_defconfig
index b2f6832303..1186af2a14 100644
--- a/configs/ls1021aqds_nor_lpuart_defconfig
+++ b/configs/ls1021aqds_nor_lpuart_defconfig
@@ -4,3 +4,4 @@ CONFIG_SYS_EXTRA_OPTIONS="LPUART"
# CONFIG_CMD_SETEXPR is not set
CONFIG_NETDEVICES=y
CONFIG_E1000=y
+CONFIG_FSL_LPUART=y
diff --git a/configs/ls1021atwr_nor_defconfig b/configs/ls1021atwr_nor_defconfig
index aa874fdcfd..b7b3a8df09 100644
--- a/configs/ls1021atwr_nor_defconfig
+++ b/configs/ls1021atwr_nor_defconfig
@@ -1,6 +1,10 @@
CONFIG_ARM=y
CONFIG_TARGET_LS1021ATWR=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEFAULT_DEVICE_TREE="ls1021a-twr-duart"
# CONFIG_CMD_SETEXPR is not set
+CONFIG_OF_CONTROL=y
+CONFIG_DM=y
CONFIG_NETDEVICES=y
CONFIG_E1000=y
CONFIG_SYS_NS16550=y
diff --git a/configs/ls1021atwr_nor_lpuart_defconfig b/configs/ls1021atwr_nor_lpuart_defconfig
index d7afca9bc5..599342f1e4 100644
--- a/configs/ls1021atwr_nor_lpuart_defconfig
+++ b/configs/ls1021atwr_nor_lpuart_defconfig
@@ -1,6 +1,11 @@
CONFIG_ARM=y
CONFIG_TARGET_LS1021ATWR=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEFAULT_DEVICE_TREE="ls1021a-twr-lpuart"
CONFIG_SYS_EXTRA_OPTIONS="LPUART"
# CONFIG_CMD_SETEXPR is not set
+CONFIG_OF_CONTROL=y
+CONFIG_DM=y
CONFIG_NETDEVICES=y
CONFIG_E1000=y
+CONFIG_FSL_LPUART=y
diff --git a/configs/ls1021atwr_qspi_defconfig b/configs/ls1021atwr_qspi_defconfig
index 0c71df64aa..d7c7e4cc9a 100644
--- a/configs/ls1021atwr_qspi_defconfig
+++ b/configs/ls1021atwr_qspi_defconfig
@@ -1,7 +1,7 @@
CONFIG_ARM=y
CONFIG_TARGET_LS1021ATWR=y
CONFIG_DM_SPI=y
-CONFIG_DEFAULT_DEVICE_TREE="ls1021a-twr"
+CONFIG_DEFAULT_DEVICE_TREE="ls1021a-twr-duart"
CONFIG_SYS_EXTRA_OPTIONS="QSPI_BOOT"
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_SETEXPR is not set
diff --git a/configs/ls1021atwr_sdcard_qspi_defconfig b/configs/ls1021atwr_sdcard_qspi_defconfig
index 2b4ebd9510..453a3bb7a2 100644
--- a/configs/ls1021atwr_sdcard_qspi_defconfig
+++ b/configs/ls1021atwr_sdcard_qspi_defconfig
@@ -1,7 +1,7 @@
CONFIG_ARM=y
CONFIG_TARGET_LS1021ATWR=y
CONFIG_DM_SPI=y
-CONFIG_DEFAULT_DEVICE_TREE="ls1021a-twr"
+CONFIG_DEFAULT_DEVICE_TREE="ls1021a-twr-duart"
CONFIG_SPL=y
CONFIG_SYS_EXTRA_OPTIONS="RAMBOOT_PBL,SPL_FSL_PBL,SD_BOOT,SD_BOOT_QSPI"
CONFIG_OF_CONTROL=y
diff --git a/configs/pcm052_defconfig b/configs/pcm052_defconfig
index 9125645832..26ab733148 100644
--- a/configs/pcm052_defconfig
+++ b/configs/pcm052_defconfig
@@ -3,3 +3,4 @@ CONFIG_TARGET_PCM052=y
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/phytec/pcm052/imximage.cfg,ENV_IS_IN_NAND"
CONFIG_NAND_VF610_NFC=y
CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
+CONFIG_FSL_LPUART=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index caa7336280..09ced0184a 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -1,6 +1,7 @@
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_PCI=y
CONFIG_DEFAULT_DEVICE_TREE="sandbox"
+CONFIG_DM_PCI_COMPAT=y
CONFIG_FIT=y
CONFIG_FIT_VERBOSE=y
CONFIG_FIT_SIGNATURE=y
@@ -51,7 +52,6 @@ CONFIG_SPI_FLASH_SST=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_DM_ETH=y
CONFIG_DM_PCI=y
-CONFIG_DM_PCI_COMPAT=y
CONFIG_PCI_SANDBOX=y
CONFIG_PINCTRL=y
CONFIG_PINCONF=y
@@ -76,6 +76,9 @@ CONFIG_USB_EMUL=y
CONFIG_USB_STORAGE=y
CONFIG_USB_KEYBOARD=y
CONFIG_SYS_USB_EVENT_POLL=y
+CONFIG_DM_VIDEO=y
+CONFIG_VIDEO_ROTATION=y
+CONFIG_VIDEO_SANDBOX_SDL=y
CONFIG_CMD_DHRYSTONE=y
CONFIG_TPM=y
CONFIG_LZ4=y
diff --git a/configs/vf610twr_defconfig b/configs/vf610twr_defconfig
index dc8df5c997..d51c93b477 100644
--- a/configs/vf610twr_defconfig
+++ b/configs/vf610twr_defconfig
@@ -6,3 +6,4 @@ CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/vf610twr/imximage.cfg,ENV_I
CONFIG_NAND_VF610_NFC=y
CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
CONFIG_SPI_FLASH=y
+CONFIG_FSL_LPUART=y
diff --git a/configs/vf610twr_nand_defconfig b/configs/vf610twr_nand_defconfig
index 98880f3a8b..299fa8f916 100644
--- a/configs/vf610twr_nand_defconfig
+++ b/configs/vf610twr_nand_defconfig
@@ -6,3 +6,4 @@ CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/vf610twr/imximage.cfg,ENV_I
CONFIG_NAND_VF610_NFC=y
CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
CONFIG_SPI_FLASH=y
+CONFIG_FSL_LPUART=y
diff --git a/doc/device-tree-bindings/chosen.txt b/doc/device-tree-bindings/chosen.txt
new file mode 100644
index 0000000000..bf9a30a8f9
--- /dev/null
+++ b/doc/device-tree-bindings/chosen.txt
@@ -0,0 +1,43 @@
+The chosen node
+---------------
+The chosen node does not represent a real device, but serves as a place
+for passing data like which serial device to used to print the logs etc
+
+
+stdout-path property
+--------------------
+Device trees may specify the device to be used for boot console output
+with a stdout-path property under /chosen.
+
+Example
+-------
+/ {
+ chosen {
+ stdout-path = "/serial@f00:115200";
+ };
+
+ serial@f00 {
+ compatible = "vendor,some-uart";
+ reg = <0xf00 0x10>;
+ };
+};
+
+tick-timer property
+-------------------
+In a system there are multiple timers, specify which timer to be used
+as the tick-timer. Earlier it was hardcoded in the timer driver now
+since device tree has all the timer nodes. Specify which timer to be
+used as tick timer.
+
+Example
+-------
+/ {
+ chosen {
+ tick-timer = "/timer2@f00";
+ };
+
+ timer2@f00 {
+ compatible = "vendor,some-timer";
+ reg = <0xf00 0x10>;
+ };
+};
diff --git a/doc/driver-model/serial-howto.txt b/doc/driver-model/serial-howto.txt
index 4706d56ea7..c933b9081b 100644
--- a/doc/driver-model/serial-howto.txt
+++ b/doc/driver-model/serial-howto.txt
@@ -11,7 +11,6 @@ is time for maintainers to start converting over the remaining serial drivers:
opencores_yanu.c
serial_bfin.c
serial_imx.c
- serial_lpuart.c
serial_max3100.c
serial_pxa.c
serial_s3c24x0.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 890f22f48e..9fcde39b71 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -1,3 +1,5 @@
+menu "Clock"
+
config CLK
bool "Enable clock driver support"
depends on DM
@@ -17,3 +19,5 @@ config SPL_CLK
SPL, enable this option. It might provide a cleaner interface to
setting up clocks within SPL, and allows the same drivers to be
used as U-Boot proper.
+
+endmenu
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 73dfd7d016..19f6f07c6f 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -32,6 +32,16 @@ ulong clk_set_rate(struct udevice *dev, ulong rate)
return ops->set_rate(dev, rate);
}
+int clk_enable(struct udevice *dev, int periph)
+{
+ struct clk_ops *ops = clk_get_ops(dev);
+
+ if (!ops->enable)
+ return -ENOSYS;
+
+ return ops->enable(dev, periph);
+}
+
ulong clk_get_periph_rate(struct udevice *dev, int periph)
{
struct clk_ops *ops = clk_get_ops(dev);
diff --git a/drivers/clk/clk_rk3036.c b/drivers/clk/clk_rk3036.c
index 6c802b6283..f650810250 100644
--- a/drivers/clk/clk_rk3036.c
+++ b/drivers/clk/clk_rk3036.c
@@ -314,7 +314,7 @@ static ulong rk3036_clk_set_rate(struct udevice *dev, ulong rate)
return 0;
}
-ulong rk3036_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+static ulong rk3036_set_periph_rate(struct udevice *dev, int periph, ulong rate)
{
struct rk3036_clk_priv *priv = dev_get_priv(dev);
ulong new_rate;
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c
index 54d49305b0..0172ad13bb 100644
--- a/drivers/clk/clk_rk3288.c
+++ b/drivers/clk/clk_rk3288.c
@@ -508,7 +508,7 @@ static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint clk_general_rate,
return rockchip_spi_get_clk(cru, clk_general_rate, periph);
}
-ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)
{
struct rk3288_clk_priv *priv = dev_get_priv(dev);
ulong new_rate;
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
index 058225a766..367130f8b7 100644
--- a/drivers/clk/clk_sandbox.c
+++ b/drivers/clk/clk_sandbox.c
@@ -32,7 +32,7 @@ static ulong sandbox_clk_set_rate(struct udevice *dev, ulong rate)
return 0;
}
-ulong sandbox_get_periph_rate(struct udevice *dev, int periph)
+static ulong sandbox_get_periph_rate(struct udevice *dev, int periph)
{
struct sandbox_clk_priv *priv = dev_get_priv(dev);
@@ -41,7 +41,8 @@ ulong sandbox_get_periph_rate(struct udevice *dev, int periph)
return priv->periph_rate[periph];
}
-ulong sandbox_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+static ulong sandbox_set_periph_rate(struct udevice *dev, int periph,
+ ulong rate)
{
struct sandbox_clk_priv *priv = dev_get_priv(dev);
ulong old_rate;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 818d03fac1..1e5584a7ce 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -135,6 +135,11 @@ int device_bind(struct udevice *parent, const struct driver *drv,
if (ret)
goto fail_child_post_bind;
}
+ if (uc->uc_drv->post_bind) {
+ ret = uc->uc_drv->post_bind(dev);
+ if (ret)
+ goto fail_uclass_post_bind;
+ }
if (parent)
dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
@@ -145,6 +150,8 @@ int device_bind(struct udevice *parent, const struct driver *drv,
return 0;
+fail_uclass_post_bind:
+ /* There is no child unbind() method, so no clean-up required */
fail_child_post_bind:
if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
if (drv->unbind && drv->unbind(dev)) {
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 1af09472a2..e1acefe727 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -278,6 +278,7 @@ static int uclass_find_device_by_of_offset(enum uclass_id id, int node,
return -ENODEV;
}
+#if CONFIG_IS_ENABLED(OF_CONTROL)
static int uclass_find_device_by_phandle(enum uclass_id id,
struct udevice *parent,
const char *name,
@@ -308,6 +309,7 @@ static int uclass_find_device_by_phandle(enum uclass_id id,
return -ENODEV;
}
+#endif
int uclass_get_device_tail(struct udevice *dev, int ret,
struct udevice **devp)
@@ -374,6 +376,7 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node,
return uclass_get_device_tail(dev, ret, devp);
}
+#if CONFIG_IS_ENABLED(OF_CONTROL)
int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
const char *name, struct udevice **devp)
{
@@ -384,6 +387,7 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
ret = uclass_find_device_by_phandle(id, parent, name, &dev);
return uclass_get_device_tail(dev, ret, devp);
}
+#endif
int uclass_first_device(enum uclass_id id, struct udevice **devp)
{
@@ -426,11 +430,6 @@ int uclass_bind_device(struct udevice *dev)
goto err;
}
}
- if (uc->uc_drv->post_bind) {
- ret = uc->uc_drv->post_bind(dev);
- if (ret)
- goto err;
- }
return 0;
err:
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 4cce11fe21..3ed4d8914c 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -154,6 +154,7 @@ int dm_gpio_request(struct gpio_desc *desc, const char *label)
static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...)
{
+#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_USE_TINY_PRINTF)
va_list args;
char buf[40];
@@ -161,6 +162,9 @@ static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...)
vscnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
return dm_gpio_request(desc, buf);
+#else
+ return dm_gpio_request(desc, fmt);
+#endif
}
/**
@@ -199,6 +203,7 @@ int gpio_request(unsigned gpio, const char *label)
*/
int gpio_requestf(unsigned gpio, const char *fmt, ...)
{
+#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_USE_TINY_PRINTF)
va_list args;
char buf[40];
@@ -206,6 +211,9 @@ int gpio_requestf(unsigned gpio, const char *fmt, ...)
vscnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
return gpio_request(gpio, buf);
+#else
+ return gpio_request(gpio, fmt);
+#endif
}
int _dm_gpio_free(struct udevice *dev, uint offset)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index e6028d503f..ede5d6eeec 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1780,18 +1780,28 @@ static int mmc_probe(bd_t *bis)
#elif defined(CONFIG_DM_MMC)
static int mmc_probe(bd_t *bis)
{
- int ret;
+ int ret, i;
struct uclass *uc;
- struct udevice *m;
+ struct udevice *dev;
ret = uclass_get(UCLASS_MMC, &uc);
if (ret)
return ret;
- uclass_foreach_dev(m, uc) {
- ret = device_probe(m);
+ /*
+ * Try to add them in sequence order. Really with driver model we
+ * should allow holes, but the current MMC list does not allow that.
+ * So if we request 0, 1, 3 we will get 0, 1, 2.
+ */
+ for (i = 0; ; i++) {
+ ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
+ if (ret == -ENODEV)
+ break;
+ }
+ uclass_foreach_dev(dev, uc) {
+ ret = device_probe(dev);
if (ret)
- printf("%s - probe failed: %d\n", m->name, ret);
+ printf("%s - probe failed: %d\n", dev->name, ret);
}
return 0;
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index b5fdcd12a8..c42b312ddd 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -111,12 +111,16 @@ static int pinconfig_post_bind(struct udevice *dev)
{
const void *fdt = gd->fdt_blob;
int offset = dev->of_offset;
+ bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
const char *name;
int ret;
for (offset = fdt_first_subnode(fdt, offset);
offset > 0;
offset = fdt_next_subnode(fdt, offset)) {
+ if (pre_reloc_only &&
+ !fdt_getprop(fdt, offset, "u-boot,dm-pre-reloc", NULL))
+ continue;
/*
* If this node has "compatible" property, this is not
* a pin configuration node, but a normal device. skip.
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 92084a2908..83068cfd50 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -228,6 +228,12 @@ config ALTERA_UART
Select this to enable an UART for Altera devices. Please find
details on the "Embedded Peripherals IP User Guide" of Altera.
+config FSL_LPUART
+ bool "Freescale LPUART support"
+ help
+ Select this to enable a Low Power UART for Freescale VF610 and
+ QorIQ Layerscape devices.
+
config SYS_NS16550
bool "NS16550 UART or compatible"
help
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c
index cd2f91e28e..45dff98d9d 100644
--- a/drivers/serial/sandbox.c
+++ b/drivers/serial/sandbox.c
@@ -16,6 +16,7 @@
#include <lcd.h>
#include <os.h>
#include <serial.h>
+#include <video.h>
#include <linux/compiler.h>
#include <asm/state.h>
@@ -114,9 +115,7 @@ static int sandbox_serial_pending(struct udevice *dev, bool input)
return 0;
os_usleep(100);
-#ifdef CONFIG_LCD
- lcd_sync();
-#endif
+ video_sync_all();
if (next_index == serial_buf_read)
return 1; /* buffer full */
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index 63fc388b26..3f9c4d14ea 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -5,6 +5,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <watchdog.h>
#include <asm/io.h>
#include <serial.h>
@@ -12,15 +13,15 @@
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
-#define US1_TDRE (1 << 7)
-#define US1_RDRF (1 << 5)
-#define US1_OR (1 << 3)
-#define UC2_TE (1 << 3)
-#define UC2_RE (1 << 2)
-#define CFIFO_TXFLUSH (1 << 7)
-#define CFIFO_RXFLUSH (1 << 6)
-#define SFIFO_RXOF (1 << 2)
-#define SFIFO_RXUF (1 << 0)
+#define US1_TDRE (1 << 7)
+#define US1_RDRF (1 << 5)
+#define US1_OR (1 << 3)
+#define UC2_TE (1 << 3)
+#define UC2_RE (1 << 2)
+#define CFIFO_TXFLUSH (1 << 7)
+#define CFIFO_RXFLUSH (1 << 6)
+#define SFIFO_RXOF (1 << 2)
+#define SFIFO_RXUF (1 << 0)
#define STAT_LBKDIF (1 << 31)
#define STAT_RXEDGIF (1 << 30)
@@ -34,7 +35,7 @@
#define STAT_MA1F (1 << 15)
#define STAT_MA2F (1 << 14)
#define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \
- STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F)
+ STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F)
#define CTRL_TE (1 << 19)
#define CTRL_RE (1 << 18)
@@ -49,23 +50,24 @@ DECLARE_GLOBAL_DATA_PTR;
struct lpuart_fsl *base = (struct lpuart_fsl *)LPUART_BASE;
+struct lpuart_serial_platdata {
+ struct lpuart_fsl *reg;
+};
+
#ifndef CONFIG_LPUART_32B_REG
-static void lpuart_serial_setbrg(void)
+static void _lpuart_serial_setbrg(struct lpuart_fsl *base, int baudrate)
{
u32 clk = mxc_get_clock(MXC_UART_CLK);
u16 sbr;
- if (!gd->baudrate)
- gd->baudrate = CONFIG_BAUDRATE;
+ sbr = (u16)(clk / (16 * baudrate));
- sbr = (u16)(clk / (16 * gd->baudrate));
/* place adjustment later - n/32 BRFA */
-
__raw_writeb(sbr >> 8, &base->ubdh);
__raw_writeb(sbr & 0xff, &base->ubdl);
}
-static int lpuart_serial_getc(void)
+static int _lpuart_serial_getc(struct lpuart_fsl *base)
{
while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR)))
WATCHDOG_RESET();
@@ -75,10 +77,10 @@ static int lpuart_serial_getc(void)
return __raw_readb(&base->ud);
}
-static void lpuart_serial_putc(const char c)
+static void _lpuart_serial_putc(struct lpuart_fsl *base, const char c)
{
if (c == '\n')
- serial_putc('\r');
+ _lpuart_serial_putc(base, '\r');
while (!(__raw_readb(&base->us1) & US1_TDRE))
WATCHDOG_RESET();
@@ -86,10 +88,8 @@ static void lpuart_serial_putc(const char c)
__raw_writeb(c, &base->ud);
}
-/*
- * Test whether a character is in the RX buffer
- */
-static int lpuart_serial_tstc(void)
+/* Test whether a character is in the RX buffer */
+static int _lpuart_serial_tstc(struct lpuart_fsl *base)
{
if (__raw_readb(&base->urcfifo) == 0)
return 0;
@@ -101,7 +101,7 @@ static int lpuart_serial_tstc(void)
* Initialise the serial port with the given baudrate. The settings
* are always 8 data bits, no parity, 1 stop bit, no start bits.
*/
-static int lpuart_serial_init(void)
+static int _lpuart_serial_init(struct lpuart_fsl *base)
{
u8 ctrl;
@@ -120,14 +120,39 @@ static int lpuart_serial_init(void)
__raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo);
/* provide data bits, parity, stop bit, etc */
-
- serial_setbrg();
+ _lpuart_serial_setbrg(base, gd->baudrate);
__raw_writeb(UC2_RE | UC2_TE, &base->uc2);
return 0;
}
+#ifndef CONFIG_DM_SERIAL
+static void lpuart_serial_setbrg(void)
+{
+ _lpuart_serial_setbrg(base, gd->baudrate);
+}
+
+static int lpuart_serial_getc(void)
+{
+ return _lpuart_serial_getc(base);
+}
+
+static void lpuart_serial_putc(const char c)
+{
+ _lpuart_serial_putc(base, c);
+}
+
+static int lpuart_serial_tstc(void)
+{
+ return _lpuart_serial_tstc(base);
+}
+
+static int lpuart_serial_init(void)
+{
+ return _lpuart_serial_init(base);
+}
+
static struct serial_device lpuart_serial_drv = {
.name = "lpuart_serial",
.start = lpuart_serial_init,
@@ -138,22 +163,67 @@ static struct serial_device lpuart_serial_drv = {
.getc = lpuart_serial_getc,
.tstc = lpuart_serial_tstc,
};
+#else /* CONFIG_DM_SERIAL */
+static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ _lpuart_serial_setbrg(reg, baudrate);
+
+ return 0;
+}
+
+static int lpuart_serial_getc(struct udevice *dev)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ return _lpuart_serial_getc(reg);
+}
+
+static int lpuart_serial_putc(struct udevice *dev, const char c)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ _lpuart_serial_putc(reg, c);
+
+ return 0;
+}
+
+static int lpuart_serial_pending(struct udevice *dev, bool input)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ if (input)
+ return _lpuart_serial_tstc(reg);
+ else
+ return __raw_readb(&reg->us1) & US1_TDRE ? 0 : 1;
+}
+
+static int lpuart_serial_probe(struct udevice *dev)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ return _lpuart_serial_init(reg);
+}
+#endif /* CONFIG_DM_SERIAL */
#else
-static void lpuart32_serial_setbrg(void)
+static void _lpuart32_serial_setbrg(struct lpuart_fsl *base, int baudrate)
{
u32 clk = CONFIG_SYS_CLK_FREQ;
u32 sbr;
- if (!gd->baudrate)
- gd->baudrate = CONFIG_BAUDRATE;
+ sbr = (clk / (16 * baudrate));
- sbr = (clk / (16 * gd->baudrate));
/* place adjustment later - n/32 BRFA */
-
out_be32(&base->baud, sbr);
}
-static int lpuart32_serial_getc(void)
+static int _lpuart32_serial_getc(struct lpuart_fsl *base)
{
u32 stat;
@@ -165,10 +235,10 @@ static int lpuart32_serial_getc(void)
return in_be32(&base->data) & 0x3ff;
}
-static void lpuart32_serial_putc(const char c)
+static void _lpuart32_serial_putc(struct lpuart_fsl *base, const char c)
{
if (c == '\n')
- serial_putc('\r');
+ _lpuart32_serial_putc(base, '\r');
while (!(in_be32(&base->stat) & STAT_TDRE))
WATCHDOG_RESET();
@@ -176,10 +246,8 @@ static void lpuart32_serial_putc(const char c)
out_be32(&base->data, c);
}
-/*
- * Test whether a character is in the RX buffer
- */
-static int lpuart32_serial_tstc(void)
+/* Test whether a character is in the RX buffer */
+static int _lpuart32_serial_tstc(struct lpuart_fsl *base)
{
if ((in_be32(&base->water) >> 24) == 0)
return 0;
@@ -191,7 +259,7 @@ static int lpuart32_serial_tstc(void)
* Initialise the serial port with the given baudrate. The settings
* are always 8 data bits, no parity, 1 stop bit, no start bits.
*/
-static int lpuart32_serial_init(void)
+static int _lpuart32_serial_init(struct lpuart_fsl *base)
{
u8 ctrl;
@@ -204,15 +272,41 @@ static int lpuart32_serial_init(void)
out_be32(&base->fifo, ~(FIFO_TXFE | FIFO_RXFE));
out_be32(&base->match, 0);
- /* provide data bits, parity, stop bit, etc */
- serial_setbrg();
+ /* provide data bits, parity, stop bit, etc */
+ _lpuart32_serial_setbrg(base, gd->baudrate);
out_be32(&base->ctrl, CTRL_RE | CTRL_TE);
return 0;
}
+#ifndef CONFIG_DM_SERIAL
+static void lpuart32_serial_setbrg(void)
+{
+ _lpuart32_serial_setbrg(base, gd->baudrate);
+}
+
+static int lpuart32_serial_getc(void)
+{
+ return _lpuart32_serial_getc(base);
+}
+
+static void lpuart32_serial_putc(const char c)
+{
+ _lpuart32_serial_putc(base, c);
+}
+
+static int lpuart32_serial_tstc(void)
+{
+ return _lpuart32_serial_tstc(base);
+}
+
+static int lpuart32_serial_init(void)
+{
+ return _lpuart32_serial_init(base);
+}
+
static struct serial_device lpuart32_serial_drv = {
.name = "lpuart32_serial",
.start = lpuart32_serial_init,
@@ -223,8 +317,57 @@ static struct serial_device lpuart32_serial_drv = {
.getc = lpuart32_serial_getc,
.tstc = lpuart32_serial_tstc,
};
+#else /* CONFIG_DM_SERIAL */
+static int lpuart32_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ _lpuart32_serial_setbrg(reg, baudrate);
+
+ return 0;
+}
+
+static int lpuart32_serial_getc(struct udevice *dev)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ return _lpuart32_serial_getc(reg);
+}
+
+static int lpuart32_serial_putc(struct udevice *dev, const char c)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ _lpuart32_serial_putc(reg, c);
+
+ return 0;
+}
+
+static int lpuart32_serial_pending(struct udevice *dev, bool input)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ if (input)
+ return _lpuart32_serial_tstc(reg);
+ else
+ return in_be32(&reg->stat) & STAT_TDRE ? 0 : 1;
+}
+
+static int lpuart32_serial_probe(struct udevice *dev)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ return _lpuart32_serial_init(reg);
+}
+#endif /* CONFIG_DM_SERIAL */
#endif
+#ifndef CONFIG_DM_SERIAL
void lpuart_serial_initialize(void)
{
#ifdef CONFIG_LPUART_32B_REG
@@ -242,3 +385,66 @@ __weak struct serial_device *default_serial_console(void)
return &lpuart_serial_drv;
#endif
}
+#else /* CONFIG_DM_SERIAL */
+static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ fdt_addr_t addr;
+
+ addr = dev_get_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->reg = (struct lpuart_fsl *)addr;
+
+ return 0;
+}
+
+#ifndef CONFIG_LPUART_32B_REG
+static const struct dm_serial_ops lpuart_serial_ops = {
+ .putc = lpuart_serial_putc,
+ .pending = lpuart_serial_pending,
+ .getc = lpuart_serial_getc,
+ .setbrg = lpuart_serial_setbrg,
+};
+
+static const struct udevice_id lpuart_serial_ids[] = {
+ { .compatible = "fsl,vf610-lpuart" },
+ { }
+};
+
+U_BOOT_DRIVER(serial_lpuart) = {
+ .name = "serial_lpuart",
+ .id = UCLASS_SERIAL,
+ .of_match = lpuart_serial_ids,
+ .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
+ .probe = lpuart_serial_probe,
+ .ops = &lpuart_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+#else /* CONFIG_LPUART_32B_REG */
+static const struct dm_serial_ops lpuart32_serial_ops = {
+ .putc = lpuart32_serial_putc,
+ .pending = lpuart32_serial_pending,
+ .getc = lpuart32_serial_getc,
+ .setbrg = lpuart32_serial_setbrg,
+};
+
+static const struct udevice_id lpuart32_serial_ids[] = {
+ { .compatible = "fsl,ls1021a-lpuart" },
+ { }
+};
+
+U_BOOT_DRIVER(serial_lpuart32) = {
+ .name = "serial_lpuart32",
+ .id = UCLASS_SERIAL,
+ .of_match = lpuart32_serial_ids,
+ .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
+ .probe = lpuart32_serial_probe,
+ .ops = &lpuart32_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+#endif /* CONFIG_LPUART_32B_REG */
+#endif /* CONFIG_DM_SERIAL */
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 2b10d2bc6c..ff65a731de 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -30,4 +30,10 @@ config X86_TSC_TIMER
help
Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config OMAP_TIMER
+ bool "Omap timer support"
+ depends on TIMER
+ help
+ Select this to enable an timer for Omap devices.
+
endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index fe954eca9a..f351fbb4e0 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_TIMER) += timer-uclass.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
+obj-$(CONFIG_OMAP_TIMER) += omap-timer.o
diff --git a/drivers/timer/omap-timer.c b/drivers/timer/omap-timer.c
new file mode 100644
index 0000000000..3bb38c522c
--- /dev/null
+++ b/drivers/timer/omap-timer.c
@@ -0,0 +1,108 @@
+/*
+ * TI OMAP timer driver
+ *
+ * Copyright (C) 2015, Texas Instruments, Incorporated
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Timer register bits */
+#define TCLR_START BIT(0) /* Start=1 */
+#define TCLR_AUTO_RELOAD BIT(1) /* Auto reload */
+#define TCLR_PRE_EN BIT(5) /* Pre-scaler enable */
+#define TCLR_PTV_SHIFT (2) /* Pre-scaler shift value */
+
+#define TIMER_CLOCK (V_SCLK / (2 << CONFIG_SYS_PTV))
+
+struct omap_gptimer_regs {
+ unsigned int tidr; /* offset 0x00 */
+ unsigned char res1[12];
+ unsigned int tiocp_cfg; /* offset 0x10 */
+ unsigned char res2[12];
+ unsigned int tier; /* offset 0x20 */
+ unsigned int tistatr; /* offset 0x24 */
+ unsigned int tistat; /* offset 0x28 */
+ unsigned int tisr; /* offset 0x2c */
+ unsigned int tcicr; /* offset 0x30 */
+ unsigned int twer; /* offset 0x34 */
+ unsigned int tclr; /* offset 0x38 */
+ unsigned int tcrr; /* offset 0x3c */
+ unsigned int tldr; /* offset 0x40 */
+ unsigned int ttgr; /* offset 0x44 */
+ unsigned int twpc; /* offset 0x48 */
+ unsigned int tmar; /* offset 0x4c */
+ unsigned int tcar1; /* offset 0x50 */
+ unsigned int tscir; /* offset 0x54 */
+ unsigned int tcar2; /* offset 0x58 */
+};
+
+/* Omap Timer Priv */
+struct omap_timer_priv {
+ struct omap_gptimer_regs *regs;
+};
+
+static int omap_timer_get_count(struct udevice *dev, u64 *count)
+{
+ struct omap_timer_priv *priv = dev_get_priv(dev);
+
+ *count = readl(&priv->regs->tcrr);
+
+ return 0;
+}
+
+static int omap_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct omap_timer_priv *priv = dev_get_priv(dev);
+
+ uc_priv->clock_rate = TIMER_CLOCK;
+
+ /* start the counter ticking up, reload value on overflow */
+ writel(0, &priv->regs->tldr);
+ /* enable timer */
+ writel((CONFIG_SYS_PTV << 2) | TCLR_PRE_EN | TCLR_AUTO_RELOAD |
+ TCLR_START, &priv->regs->tclr);
+
+ return 0;
+}
+
+static int omap_timer_ofdata_to_platdata(struct udevice *dev)
+{
+ struct omap_timer_priv *priv = dev_get_priv(dev);
+
+ priv->regs = (struct omap_gptimer_regs *)dev_get_addr(dev);
+
+ return 0;
+}
+
+
+static const struct timer_ops omap_timer_ops = {
+ .get_count = omap_timer_get_count,
+};
+
+static const struct udevice_id omap_timer_ids[] = {
+ { .compatible = "ti,am335x-timer" },
+ { .compatible = "ti,am4372-timer" },
+ { .compatible = "ti,omap5430-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(omap_timer) = {
+ .name = "omap_timer",
+ .id = UCLASS_TIMER,
+ .of_match = omap_timer_ids,
+ .ofdata_to_platdata = omap_timer_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct omap_timer_priv),
+ .probe = omap_timer_probe,
+ .ops = &omap_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c
index 00a9944f78..a8da936349 100644
--- a/drivers/timer/sandbox_timer.c
+++ b/drivers/timer/sandbox_timer.c
@@ -27,6 +27,11 @@ static int sandbox_timer_get_count(struct udevice *dev, u64 *count)
static int sandbox_timer_probe(struct udevice *dev)
{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (!uc_priv->clock_rate)
+ uc_priv->clock_rate = 1000000;
+
return 0;
}
@@ -47,3 +52,8 @@ U_BOOT_DRIVER(sandbox_timer) = {
.ops = &sandbox_timer_ops,
.flags = DM_FLAG_PRE_RELOC,
};
+
+/* This is here in case we don't have a device tree */
+U_BOOT_DEVICE(sandbox_timer_non_fdt) = {
+ .name = "sandbox_timer",
+};
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index aca421bdea..83d1a35e06 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -6,6 +6,8 @@
#include <common.h>
#include <dm.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
#include <errno.h>
#include <timer.h>
@@ -47,6 +49,16 @@ static int timer_pre_probe(struct udevice *dev)
return 0;
}
+static int timer_post_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (!uc_priv->clock_rate)
+ return -EINVAL;
+
+ return 0;
+}
+
u64 timer_conv_64(u32 count)
{
/* increment tbh if tbl has rolled over */
@@ -56,9 +68,53 @@ u64 timer_conv_64(u32 count)
return ((u64)gd->timebase_h << 32) | gd->timebase_l;
}
+int notrace dm_timer_init(void)
+{
+ const void *blob = gd->fdt_blob;
+ struct udevice *dev = NULL;
+ int node;
+ int ret;
+
+ if (gd->timer)
+ return 0;
+
+ /* Check for a chosen timer to be used for tick */
+ node = fdtdec_get_chosen_node(blob, "tick-timer");
+ if (node < 0) {
+ /* No chosen timer, trying first available timer */
+ ret = uclass_first_device(UCLASS_TIMER, &dev);
+ if (ret)
+ return ret;
+ if (!dev)
+ return -ENODEV;
+ } else {
+ if (uclass_get_device_by_of_offset(UCLASS_TIMER, node, &dev)) {
+ /*
+ * If the timer is not marked to be bound before
+ * relocation, bind it anyway.
+ */
+ if (node > 0 &&
+ !lists_bind_fdt(gd->dm_root, blob, node, &dev)) {
+ ret = device_probe(dev);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+
+ if (dev) {
+ gd->timer = dev;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
UCLASS_DRIVER(timer) = {
.id = UCLASS_TIMER,
.name = "timer",
.pre_probe = timer_pre_probe,
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .post_probe = timer_post_probe,
.per_device_auto_alloc_size = sizeof(struct timer_dev_priv),
};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index caf1efcbb3..ae122daa04 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -4,6 +4,59 @@
menu "Graphics support"
+config DM_VIDEO
+ bool "Enable driver model support for LCD/video"
+ depends on DM
+ help
+ This enables driver model for LCD and video devices. These support
+ a bitmap display of various sizes and depths which can be drawn on
+ to display a command-line console or splash screen. Enabling this
+ option compiles in the video uclass and routes all LCD/video access
+ through this.
+
+config VIDEO_BPP8
+ bool "Support 8-bit-per-pixel displays"
+ depends on DM_VIDEO
+ default y if DM_VIDEO
+ help
+ Support drawing text and bitmaps onto a 8-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
+config VIDEO_BPP16
+ bool "Support 16-bit-per-pixel displays"
+ depends on DM_VIDEO
+ default y if DM_VIDEO
+ help
+ Support drawing text and bitmaps onto a 16-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
+config VIDEO_BPP32
+ bool "Support 32-bit-per-pixel displays"
+ depends on DM_VIDEO
+ default y if DM_VIDEO
+ help
+ Support drawing text and bitmaps onto a 32-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
+config VIDEO_ROTATION
+ bool "Support rotated displays"
+ depends on DM_VIDEO
+ help
+ Sometimes, for example if the display is mounted in portrait
+ mode or even if it's mounted landscape but rotated by 180degree,
+ we need to rotate our content of the display relative to the
+ framebuffer, so that user can read the messages which are
+ printed out. Enable this option to include a text driver which can
+ support this. The rotation is set by the 'rot' parameter in
+ struct video_priv: 0=unrotated, 1=90 degrees clockwise, 2=180
+ degrees, 3=270 degrees.
+
config VIDEO_VESA
bool "Enable VESA video driver support"
default n
@@ -247,6 +300,15 @@ config DISPLAY_PORT
to drive LCD panels. This framework provides support for enabling
these displays where supported by the video hardware.
+config VIDEO_SANDBOX_SDL
+ bool "Enable sandbox video console using SDL"
+ depends on SANDBOX
+ help
+ When using sandbox you can enable an emulated LCD display which
+ appears as an SDL (Simple DirectMedia Layer) window. This is a
+ console device and can display stdout output. Within U-Boot is is
+ a normal bitmap display and can display images as well as text.
+
config VIDEO_TEGRA124
bool "Enable video support on Tegra124"
help
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index e85fd8a677..ee046296e6 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -7,6 +7,9 @@
ifdef CONFIG_DM
obj-$(CONFIG_DISPLAY_PORT) += dp-uclass.o
+obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o console_normal.o
+obj-$(CONFIG_DM_VIDEO) += video_bmp.o
+obj-$(CONFIG_VIDEO_ROTATION) += console_rotate.o
endif
obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c
new file mode 100644
index 0000000000..d1031c8ed1
--- /dev/null
+++ b/drivers/video/console_normal.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * (C) Copyright 2001-2015
+ * DENX Software Engineering -- wd@denx.de
+ * Compulab Ltd - http://compulab.co.il/
+ * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <video.h>
+#include <video_console.h>
+#include <video_font.h> /* Get font data, width and height */
+
+static int console_normal_set_row(struct udevice *dev, uint row, int clr)
+{
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ void *line;
+ int pixels = VIDEO_FONT_HEIGHT * vid_priv->line_length;
+ int i;
+
+ line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * vid_priv->line_length;
+ switch (vid_priv->bpix) {
+#ifdef CONFIG_VIDEO_BPP8
+ case VIDEO_BPP8: {
+ uint8_t *dst = line;
+
+ for (i = 0; i < pixels; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP16
+ case VIDEO_BPP16: {
+ uint16_t *dst = line;
+
+ for (i = 0; i < pixels; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP32
+ case VIDEO_BPP32: {
+ uint32_t *dst = line;
+
+ for (i = 0; i < pixels; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+static int console_normal_move_rows(struct udevice *dev, uint rowdst,
+ uint rowsrc, uint count)
+{
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ void *dst;
+ void *src;
+
+ dst = vid_priv->fb + rowdst * VIDEO_FONT_HEIGHT * vid_priv->line_length;
+ src = vid_priv->fb + rowsrc * VIDEO_FONT_HEIGHT * vid_priv->line_length;
+ memmove(dst, src, VIDEO_FONT_HEIGHT * vid_priv->line_length * count);
+
+ return 0;
+}
+
+static int console_normal_putc_xy(struct udevice *dev, uint x, uint y, char ch)
+{
+ struct udevice *vid = dev->parent;
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+ int i, row;
+ void *line = vid_priv->fb + y * vid_priv->line_length +
+ x * VNBYTES(vid_priv->bpix);
+
+ for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
+ uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row];
+
+ switch (vid_priv->bpix) {
+#ifdef CONFIG_VIDEO_BPP8
+ case VIDEO_BPP8: {
+ uint8_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
+ *dst++ = (bits & 0x80) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ bits <<= 1;
+ }
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP16
+ case VIDEO_BPP16: {
+ uint16_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
+ *dst++ = (bits & 0x80) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ bits <<= 1;
+ }
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP32
+ case VIDEO_BPP32: {
+ uint32_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
+ *dst++ = (bits & 0x80) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ bits <<= 1;
+ }
+ break;
+ }
+#endif
+ default:
+ return -ENOSYS;
+ }
+ line += vid_priv->line_length;
+ }
+
+ return 0;
+}
+
+struct vidconsole_ops console_normal_ops = {
+ .putc_xy = console_normal_putc_xy,
+ .move_rows = console_normal_move_rows,
+ .set_row = console_normal_set_row,
+};
+
+U_BOOT_DRIVER(vidconsole_normal) = {
+ .name = "vidconsole0",
+ .id = UCLASS_VIDEO_CONSOLE,
+ .ops = &console_normal_ops,
+};
diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c
new file mode 100644
index 0000000000..ebb31d8cd0
--- /dev/null
+++ b/drivers/video/console_rotate.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * (C) Copyright 2015
+ * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <video.h>
+#include <video_console.h>
+#include <video_font.h> /* Get font data, width and height */
+
+static int console_set_row_1(struct udevice *dev, uint row, int clr)
+{
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ int pbytes = VNBYTES(vid_priv->bpix);
+ void *line;
+ int i, j;
+
+ line = vid_priv->fb + vid_priv->line_length -
+ (row + 1) * VIDEO_FONT_HEIGHT * pbytes;
+ for (j = 0; j < vid_priv->ysize; j++) {
+ switch (vid_priv->bpix) {
+#ifdef CONFIG_VIDEO_BPP8
+ case VIDEO_BPP8: {
+ uint8_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP16
+ case VIDEO_BPP16: {
+ uint16_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP32
+ case VIDEO_BPP32: {
+ uint32_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+ default:
+ return -ENOSYS;
+ }
+ line += vid_priv->line_length;
+ }
+
+ return 0;
+}
+
+static int console_move_rows_1(struct udevice *dev, uint rowdst, uint rowsrc,
+ uint count)
+{
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ void *dst;
+ void *src;
+ int pbytes = VNBYTES(vid_priv->bpix);
+ int j;
+
+ dst = vid_priv->fb + vid_priv->line_length -
+ (rowdst + count) * VIDEO_FONT_HEIGHT * pbytes;
+ src = vid_priv->fb + vid_priv->line_length -
+ (rowsrc + count) * VIDEO_FONT_HEIGHT * pbytes;
+
+ for (j = 0; j < vid_priv->ysize; j++) {
+ memmove(dst, src, VIDEO_FONT_HEIGHT * pbytes * count);
+ src += vid_priv->line_length;
+ dst += vid_priv->line_length;
+ }
+
+ return 0;
+}
+
+static int console_putc_xy_1(struct udevice *dev, uint x, uint y, char ch)
+{
+ struct udevice *vid = dev->parent;
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+ int pbytes = VNBYTES(vid_priv->bpix);
+ int i, col;
+ int mask = 0x80;
+ void *line = vid_priv->fb + (x + 1) * vid_priv->line_length -
+ (y + 1) * pbytes;
+ uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT;
+
+ for (col = 0; col < VIDEO_FONT_HEIGHT; col++) {
+ switch (vid_priv->bpix) {
+#ifdef CONFIG_VIDEO_BPP8
+ case VIDEO_BPP8: {
+ uint8_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
+ *dst-- = (pfont[i] & mask) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ }
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP16
+ case VIDEO_BPP16: {
+ uint16_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
+ *dst-- = (pfont[i] & mask) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ }
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP32
+ case VIDEO_BPP32: {
+ uint32_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
+ *dst-- = (pfont[i] & mask) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ }
+ break;
+ }
+#endif
+ default:
+ return -ENOSYS;
+ }
+ line += vid_priv->line_length;
+ mask >>= 1;
+ }
+
+ return 0;
+}
+
+
+static int console_set_row_2(struct udevice *dev, uint row, int clr)
+{
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ void *line;
+ int pixels = VIDEO_FONT_HEIGHT * vid_priv->xsize;
+ int i;
+
+ line = vid_priv->fb + vid_priv->ysize * vid_priv->line_length -
+ (row + 1) * VIDEO_FONT_HEIGHT * vid_priv->line_length;
+ switch (vid_priv->bpix) {
+#ifdef CONFIG_VIDEO_BPP8
+ case VIDEO_BPP8: {
+ uint8_t *dst = line;
+
+ for (i = 0; i < pixels; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP16
+ case VIDEO_BPP16: {
+ uint16_t *dst = line;
+
+ for (i = 0; i < pixels; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP32
+ case VIDEO_BPP32: {
+ uint32_t *dst = line;
+
+ for (i = 0; i < pixels; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+static int console_move_rows_2(struct udevice *dev, uint rowdst, uint rowsrc,
+ uint count)
+{
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ void *dst;
+ void *src;
+ void *end;
+
+ end = vid_priv->fb + vid_priv->ysize * vid_priv->line_length;
+ dst = end - (rowdst + count) * VIDEO_FONT_HEIGHT *
+ vid_priv->line_length;
+ src = end - (rowsrc + count) * VIDEO_FONT_HEIGHT *
+ vid_priv->line_length;
+ memmove(dst, src, VIDEO_FONT_HEIGHT * vid_priv->line_length * count);
+
+ return 0;
+}
+
+static int console_putc_xy_2(struct udevice *dev, uint x, uint y, char ch)
+{
+ struct udevice *vid = dev->parent;
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+ int i, row;
+ void *line;
+
+ line = vid_priv->fb + (vid_priv->ysize - y - 1) *
+ vid_priv->line_length +
+ (vid_priv->xsize - x - VIDEO_FONT_WIDTH - 1) *
+ VNBYTES(vid_priv->bpix);
+
+ for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
+ uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row];
+
+ switch (vid_priv->bpix) {
+#ifdef CONFIG_VIDEO_BPP8
+ case VIDEO_BPP8: {
+ uint8_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
+ *dst-- = (bits & 0x80) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ bits <<= 1;
+ }
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP16
+ case VIDEO_BPP16: {
+ uint16_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
+ *dst-- = (bits & 0x80) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ bits <<= 1;
+ }
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP32
+ case VIDEO_BPP32: {
+ uint32_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
+ *dst-- = (bits & 0x80) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ bits <<= 1;
+ }
+ break;
+ }
+#endif
+ default:
+ return -ENOSYS;
+ }
+ line -= vid_priv->line_length;
+ }
+
+ return 0;
+}
+
+static int console_set_row_3(struct udevice *dev, uint row, int clr)
+{
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ int pbytes = VNBYTES(vid_priv->bpix);
+ void *line;
+ int i, j;
+
+ line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * pbytes;
+ for (j = 0; j < vid_priv->ysize; j++) {
+ switch (vid_priv->bpix) {
+#ifdef CONFIG_VIDEO_BPP8
+ case VIDEO_BPP8: {
+ uint8_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP16
+ case VIDEO_BPP16: {
+ uint16_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP32
+ case VIDEO_BPP32: {
+ uint32_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst++ = clr;
+ break;
+ }
+#endif
+ default:
+ return -ENOSYS;
+ }
+ line += vid_priv->line_length;
+ }
+
+ return 0;
+}
+
+static int console_move_rows_3(struct udevice *dev, uint rowdst, uint rowsrc,
+ uint count)
+{
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ void *dst;
+ void *src;
+ int pbytes = VNBYTES(vid_priv->bpix);
+ int j;
+
+ dst = vid_priv->fb + rowdst * VIDEO_FONT_HEIGHT * pbytes;
+ src = vid_priv->fb + rowsrc * VIDEO_FONT_HEIGHT * pbytes;
+
+ for (j = 0; j < vid_priv->ysize; j++) {
+ memmove(dst, src, VIDEO_FONT_HEIGHT * pbytes * count);
+ src += vid_priv->line_length;
+ dst += vid_priv->line_length;
+ }
+
+ return 0;
+}
+
+static int console_putc_xy_3(struct udevice *dev, uint x, uint y, char ch)
+{
+ struct udevice *vid = dev->parent;
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+ int pbytes = VNBYTES(vid_priv->bpix);
+ int i, col;
+ int mask = 0x80;
+ void *line = vid_priv->fb + (vid_priv->ysize - x - 1) *
+ vid_priv->line_length + y * pbytes;
+ uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT;
+
+ for (col = 0; col < VIDEO_FONT_HEIGHT; col++) {
+ switch (vid_priv->bpix) {
+#ifdef CONFIG_VIDEO_BPP8
+ case VIDEO_BPP8: {
+ uint8_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
+ *dst++ = (pfont[i] & mask) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ }
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP16
+ case VIDEO_BPP16: {
+ uint16_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
+ *dst++ = (pfont[i] & mask) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ }
+ break;
+ }
+#endif
+#ifdef CONFIG_VIDEO_BPP32
+ case VIDEO_BPP32: {
+ uint32_t *dst = line;
+
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
+ *dst++ = (pfont[i] & mask) ? vid_priv->colour_fg
+ : vid_priv->colour_bg;
+ }
+ break;
+ }
+#endif
+ default:
+ return -ENOSYS;
+ }
+ line -= vid_priv->line_length;
+ mask >>= 1;
+ }
+
+ return 0;
+}
+
+
+static int console_probe_1_3(struct udevice *dev)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+
+ priv->cols = vid_priv->ysize / VIDEO_FONT_WIDTH;
+ priv->rows = vid_priv->xsize / VIDEO_FONT_HEIGHT;
+
+ return 0;
+}
+
+struct vidconsole_ops console_ops_1 = {
+ .putc_xy = console_putc_xy_1,
+ .move_rows = console_move_rows_1,
+ .set_row = console_set_row_1,
+};
+
+struct vidconsole_ops console_ops_2 = {
+ .putc_xy = console_putc_xy_2,
+ .move_rows = console_move_rows_2,
+ .set_row = console_set_row_2,
+};
+
+struct vidconsole_ops console_ops_3 = {
+ .putc_xy = console_putc_xy_3,
+ .move_rows = console_move_rows_3,
+ .set_row = console_set_row_3,
+};
+
+U_BOOT_DRIVER(vidconsole_1) = {
+ .name = "vidconsole1",
+ .id = UCLASS_VIDEO_CONSOLE,
+ .ops = &console_ops_1,
+ .probe = console_probe_1_3,
+};
+
+U_BOOT_DRIVER(vidconsole_2) = {
+ .name = "vidconsole2",
+ .id = UCLASS_VIDEO_CONSOLE,
+ .ops = &console_ops_2,
+};
+
+U_BOOT_DRIVER(vidconsole_3) = {
+ .name = "vidconsole3",
+ .id = UCLASS_VIDEO_CONSOLE,
+ .ops = &console_ops_3,
+ .probe = console_probe_1_3,
+};
diff --git a/drivers/video/sandbox_sdl.c b/drivers/video/sandbox_sdl.c
index ba4578e9d1..21448a1411 100644
--- a/drivers/video/sandbox_sdl.c
+++ b/drivers/video/sandbox_sdl.c
@@ -5,75 +5,67 @@
*/
#include <common.h>
+#include <dm.h>
#include <fdtdec.h>
-#include <lcd.h>
-#include <malloc.h>
+#include <video.h>
#include <asm/sdl.h>
#include <asm/u-boot-sandbox.h>
+#include <dm/test.h>
DECLARE_GLOBAL_DATA_PTR;
enum {
- /* Maximum LCD size we support */
+ /* Default LCD size we support */
LCD_MAX_WIDTH = 1366,
LCD_MAX_HEIGHT = 768,
- LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */
};
-vidinfo_t panel_info;
-
-void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+static int sandbox_sdl_probe(struct udevice *dev)
{
-}
+ struct sandbox_sdl_plat *plat = dev_get_platdata(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret;
-void lcd_ctrl_init(void *lcdbase)
-{
- /*
- * Allocate memory to keep BMP color conversion map. This is required
- * for 8 bit BMPs only (hence 256 colors). If malloc fails - keep
- * going, it is not even clear if displyaing the bitmap will be
- * required on the way up.
- */
- panel_info.cmap = malloc(256 * NBITS(panel_info.vl_bpix) / 8);
-}
-
-void lcd_enable(void)
-{
- if (sandbox_sdl_init_display(panel_info.vl_col, panel_info.vl_row,
- panel_info.vl_bpix))
+ ret = sandbox_sdl_init_display(plat->xres, plat->yres, plat->bpix);
+ if (ret) {
puts("LCD init failed\n");
+ return ret;
+ }
+ uc_priv->xsize = plat->xres;
+ uc_priv->ysize = plat->yres;
+ uc_priv->bpix = plat->bpix;
+ uc_priv->rot = plat->rot;
+
+ return 0;
}
-int sandbox_lcd_sdl_early_init(void)
+static int sandbox_sdl_bind(struct udevice *dev)
{
+ struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+ struct sandbox_sdl_plat *plat = dev_get_platdata(dev);
const void *blob = gd->fdt_blob;
- int xres = LCD_MAX_WIDTH, yres = LCD_MAX_HEIGHT;
- int node;
+ int node = dev->of_offset;
int ret = 0;
- /*
- * The code in common/lcd.c does not cope with not being able to
- * set up a frame buffer. It will just happily keep writing to
- * invalid memory. So here we make sure that at least some buffer
- * is available even if it actually won't be displayed.
- */
- node = fdtdec_next_compatible(blob, 0, COMPAT_SANDBOX_LCD_SDL);
- if (node >= 0) {
- xres = fdtdec_get_int(blob, node, "xres", LCD_MAX_WIDTH);
- yres = fdtdec_get_int(blob, node, "yres", LCD_MAX_HEIGHT);
- if (xres < 0 || xres > LCD_MAX_WIDTH) {
- xres = LCD_MAX_WIDTH;
- ret = -EINVAL;
- }
- if (yres < 0 || yres > LCD_MAX_HEIGHT) {
- yres = LCD_MAX_HEIGHT;
- ret = -EINVAL;
- }
- }
-
- panel_info.vl_col = xres;
- panel_info.vl_row = yres;
- panel_info.vl_bpix = LCD_COLOR16;
+ plat->xres = fdtdec_get_int(blob, node, "xres", LCD_MAX_WIDTH);
+ plat->yres = fdtdec_get_int(blob, node, "yres", LCD_MAX_HEIGHT);
+ plat->bpix = VIDEO_BPP16;
+ uc_plat->size = plat->xres * plat->yres * (1 << plat->bpix) / 8;
+ debug("%s: Frame buffer size %x\n", __func__, uc_plat->size);
return ret;
}
+
+static const struct udevice_id sandbox_sdl_ids[] = {
+ { .compatible = "sandbox,lcd-sdl" },
+ { }
+};
+
+U_BOOT_DRIVER(sdl_sandbox) = {
+ .name = "sdl_sandbox",
+ .id = UCLASS_VIDEO,
+ .of_match = sandbox_sdl_ids,
+ .bind = sandbox_sdl_bind,
+ .probe = sandbox_sdl_probe,
+ .platdata_auto_alloc_size = sizeof(struct sandbox_sdl_plat),
+};
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
new file mode 100644
index 0000000000..ea10189432
--- /dev/null
+++ b/drivers/video/vidconsole-uclass.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * (C) Copyright 2001-2015
+ * DENX Software Engineering -- wd@denx.de
+ * Compulab Ltd - http://compulab.co.il/
+ * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <video.h>
+#include <video_console.h>
+#include <video_font.h> /* Get font data, width and height */
+
+/* By default we scroll by a single line */
+#ifndef CONFIG_CONSOLE_SCROLL_LINES
+#define CONFIG_CONSOLE_SCROLL_LINES 1
+#endif
+
+int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch)
+{
+ struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+
+ if (!ops->putc_xy)
+ return -ENOSYS;
+ return ops->putc_xy(dev, x, y, ch);
+}
+
+int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
+ uint count)
+{
+ struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+
+ if (!ops->move_rows)
+ return -ENOSYS;
+ return ops->move_rows(dev, rowdst, rowsrc, count);
+}
+
+int vidconsole_set_row(struct udevice *dev, uint row, int clr)
+{
+ struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+
+ if (!ops->set_row)
+ return -ENOSYS;
+ return ops->set_row(dev, row, clr);
+}
+
+/* Move backwards one space */
+static void vidconsole_back(struct udevice *dev)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+
+ if (--priv->curr_col < 0) {
+ priv->curr_col = priv->cols - 1;
+ if (--priv->curr_row < 0)
+ priv->curr_row = 0;
+ }
+
+ vidconsole_putc_xy(dev, priv->curr_col * VIDEO_FONT_WIDTH,
+ priv->curr_row * VIDEO_FONT_HEIGHT, ' ');
+}
+
+/* Move to a newline, scrolling the display if necessary */
+static void vidconsole_newline(struct udevice *dev)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ struct udevice *vid_dev = dev->parent;
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
+ const int rows = CONFIG_CONSOLE_SCROLL_LINES;
+ int i;
+
+ priv->curr_col = 0;
+
+ /* Check if we need to scroll the terminal */
+ if (++priv->curr_row >= priv->rows) {
+ vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
+ for (i = 0; i < rows; i++)
+ vidconsole_set_row(dev, priv->rows - i - 1,
+ vid_priv->colour_bg);
+ priv->curr_row -= rows;
+ }
+ video_sync(dev->parent);
+}
+
+int vidconsole_put_char(struct udevice *dev, char ch)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ switch (ch) {
+ case '\r':
+ priv->curr_col = 0;
+ break;
+ case '\n':
+ vidconsole_newline(dev);
+ break;
+ case '\t': /* Tab (8 chars alignment) */
+ priv->curr_col += 8;
+ priv->curr_col &= ~7;
+
+ if (priv->curr_col >= priv->cols)
+ vidconsole_newline(dev);
+ break;
+ case '\b':
+ vidconsole_back(dev);
+ break;
+ default:
+ /*
+ * Failure of this function normally indicates an unsupported
+ * colour depth. Check this and return an error to help with
+ * diagnosis.
+ */
+ ret = vidconsole_putc_xy(dev,
+ priv->curr_col * VIDEO_FONT_WIDTH,
+ priv->curr_row * VIDEO_FONT_HEIGHT,
+ ch);
+ if (ret)
+ return ret;
+ if (++priv->curr_col >= priv->cols)
+ vidconsole_newline(dev);
+ break;
+ }
+
+ return 0;
+}
+
+static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
+{
+ struct udevice *dev = sdev->priv;
+
+ vidconsole_put_char(dev, ch);
+}
+
+static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
+{
+ struct udevice *dev = sdev->priv;
+
+ while (*s)
+ vidconsole_put_char(dev, *s++);
+}
+
+/* Set up the number of rows and colours (rotated drivers override this) */
+static int vidconsole_pre_probe(struct udevice *dev)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ struct udevice *vid = dev->parent;
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+
+ priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT;
+ priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH;
+
+ return 0;
+}
+
+/* Register the device with stdio */
+static int vidconsole_post_probe(struct udevice *dev)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ struct stdio_dev *sdev = &priv->sdev;
+ int ret;
+
+ strlcpy(sdev->name, dev->name, sizeof(sdev->name));
+ sdev->flags = DEV_FLAGS_OUTPUT;
+ sdev->putc = vidconsole_putc;
+ sdev->puts = vidconsole_puts;
+ sdev->priv = dev;
+ ret = stdio_register(sdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+UCLASS_DRIVER(vidconsole) = {
+ .id = UCLASS_VIDEO_CONSOLE,
+ .name = "vidconsole0",
+ .pre_probe = vidconsole_pre_probe,
+ .post_probe = vidconsole_post_probe,
+ .per_device_auto_alloc_size = sizeof(struct vidconsole_priv),
+};
+
+void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+
+ priv->curr_col = min_t(short, col, priv->cols - 1);
+ priv->curr_row = min_t(short, row, priv->rows - 1);
+}
+
+static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ unsigned int col, row;
+ struct udevice *dev;
+
+ if (argc != 3)
+ return CMD_RET_USAGE;
+
+ uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev);
+ if (!dev)
+ return CMD_RET_FAILURE;
+ col = simple_strtoul(argv[1], NULL, 10);
+ row = simple_strtoul(argv[2], NULL, 10);
+ vidconsole_position_cursor(dev, col, row);
+
+ return 0;
+}
+
+static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct udevice *dev;
+ const char *s;
+
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev);
+ if (!dev)
+ return CMD_RET_FAILURE;
+ for (s = argv[1]; *s; s++)
+ vidconsole_put_char(dev, *s);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ setcurs, 3, 1, do_video_setcursor,
+ "set cursor position within screen",
+ " <col> <row> in character"
+);
+
+U_BOOT_CMD(
+ lcdputs, 2, 1, do_video_puts,
+ "print string on video framebuffer",
+ " <string>"
+);
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
new file mode 100644
index 0000000000..63d0d9d7d3
--- /dev/null
+++ b/drivers/video/video-uclass.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <stdio_dev.h>
+#include <video.h>
+#include <video_console.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#ifdef CONFIG_SANDBOX
+#include <asm/sdl.h>
+#endif
+
+/*
+ * Theory of operation:
+ *
+ * Before relocation each device is bound. The driver for each device must
+ * set the @align and @size values in struct video_uc_platdata. This
+ * information represents the requires size and alignment of the frame buffer
+ * for the device. The values can be an over-estimate but cannot be too
+ * small. The actual values will be suppled (in the same manner) by the bind()
+ * method after relocation.
+ *
+ * This information is then picked up by video_reserve() which works out how
+ * much memory is needed for all devices. This is allocated between
+ * gd->video_bottom and gd->video_top.
+ *
+ * After relocation the same process occurs. The driver supplies the same
+ * @size and @align information and this time video_post_bind() checks that
+ * the drivers does not overflow the allocated memory.
+ *
+ * The frame buffer address is actually set (to plat->base) in
+ * video_post_probe(). This function also clears the frame buffer and
+ * allocates a suitable text console device. This can then be used to write
+ * text to the video device.
+ */
+DECLARE_GLOBAL_DATA_PTR;
+
+static ulong alloc_fb(struct udevice *dev, ulong *addrp)
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ ulong base, align, size;
+
+ align = plat->align ? plat->align : 1 << 20;
+ base = *addrp - plat->size;
+ base &= ~(align - 1);
+ plat->base = base;
+ size = *addrp - base;
+ *addrp = base;
+
+ return size;
+}
+
+int video_reserve(ulong *addrp)
+{
+ struct udevice *dev;
+ ulong size;
+
+ gd->video_top = *addrp;
+ for (uclass_find_first_device(UCLASS_VIDEO, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ size = alloc_fb(dev, addrp);
+ debug("%s: Reserving %lx bytes at %lx for video device '%s'\n",
+ __func__, size, *addrp, dev->name);
+ }
+ gd->video_bottom = *addrp;
+ debug("Video frame buffers from %lx to %lx\n", gd->video_bottom,
+ gd->video_top);
+
+ return 0;
+}
+
+static int video_clear(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ if (priv->bpix == VIDEO_BPP32) {
+ u32 *ppix = priv->fb;
+ u32 *end = priv->fb + priv->fb_size;
+
+ while (ppix < end)
+ *ppix++ = priv->colour_bg;
+ } else {
+ memset(priv->fb, priv->colour_bg, priv->fb_size);
+ }
+
+ return 0;
+}
+
+/* Flush video activity to the caches */
+void video_sync(struct udevice *vid)
+{
+ /*
+ * flush_dcache_range() is declared in common.h but it seems that some
+ * architectures do not actually implement it. Is there a way to find
+ * out whether it exists? For now, ARM is safe.
+ */
+#if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF)
+ struct video_priv *priv = dev_get_uclass_priv(vid);
+
+ if (priv->flush_dcache) {
+ flush_dcache_range((ulong)priv->fb,
+ (ulong)priv->fb + priv->fb_size);
+ }
+#elif defined(CONFIG_VIDEO_SANDBOX_SDL)
+ struct video_priv *priv = dev_get_uclass_priv(vid);
+ static ulong last_sync;
+
+ if (get_timer(last_sync) > 10) {
+ sandbox_sdl_sync(priv->fb);
+ last_sync = get_timer(0);
+ }
+#endif
+}
+
+void video_sync_all(void)
+{
+ struct udevice *dev;
+
+ for (uclass_find_first_device(UCLASS_VIDEO, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ if (device_active(dev))
+ video_sync(dev);
+ }
+}
+
+int video_get_xsize(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ return priv->xsize;
+}
+
+int video_get_ysize(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ return priv->ysize;
+}
+
+/* Set up the colour map */
+static int video_pre_probe(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ priv->cmap = calloc(256, sizeof(ushort));
+ if (!priv->cmap)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int video_pre_remove(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ free(priv->cmap);
+
+ return 0;
+}
+
+/* Set up the display ready for use */
+static int video_post_probe(struct udevice *dev)
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+ char name[30], drv[15], *str;
+ struct udevice *cons;
+ int ret;
+
+ /* Set up the line and display size */
+ priv->fb = map_sysmem(plat->base, plat->size);
+ priv->line_length = priv->xsize * VNBYTES(priv->bpix);
+ priv->fb_size = priv->line_length * priv->ysize;
+
+ /* Set up colours - we could in future support other colours */
+#ifdef CONFIG_SYS_WHITE_ON_BLACK
+ priv->colour_fg = 0xffffff;
+#else
+ priv->colour_bg = 0xffffff;
+#endif
+ video_clear(dev);
+
+ /*
+ * Create a text console devices. For now we always do this, although
+ * it might be useful to support only bitmap drawing on the device
+ * for boards that don't need to display text.
+ */
+ snprintf(name, sizeof(name), "%s.vidconsole", dev->name);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot);
+ ret = device_bind_driver(dev, drv, str, &cons);
+ if (ret) {
+ debug("%s: Cannot bind console driver\n", __func__);
+ return ret;
+ }
+ ret = device_probe(cons);
+ if (ret) {
+ debug("%s: Cannot probe console driver\n", __func__);
+ return ret;
+ }
+
+ return 0;
+};
+
+/* Post-relocation, allocate memory for the frame buffer */
+static int video_post_bind(struct udevice *dev)
+{
+ ulong addr = gd->video_top;
+ ulong size;
+
+ /* Before relocation there is nothing to do here */
+ if ((!gd->flags & GD_FLG_RELOC))
+ return 0;
+ size = alloc_fb(dev, &addr);
+ if (addr < gd->video_bottom) {
+ /* Device tree node may need the 'u-boot,dm-pre-reloc' tag */
+ printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n",
+ dev->name);
+ return -ENOSPC;
+ }
+ debug("%s: Claiming %lx bytes at %lx for video device '%s'\n",
+ __func__, size, addr, dev->name);
+ gd->video_bottom = addr;
+
+ return 0;
+}
+
+UCLASS_DRIVER(video) = {
+ .id = UCLASS_VIDEO,
+ .name = "video",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .post_bind = video_post_bind,
+ .pre_probe = video_pre_probe,
+ .post_probe = video_post_probe,
+ .pre_remove = video_pre_remove,
+ .per_device_auto_alloc_size = sizeof(struct video_priv),
+ .per_device_platdata_auto_alloc_size = sizeof(struct video_uc_platdata),
+};
diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c
new file mode 100644
index 0000000000..c9075d62dd
--- /dev/null
+++ b/drivers/video/video_bmp.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <bmp_layout.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <video.h>
+#include <watchdog.h>
+#include <asm/unaligned.h>
+
+#ifdef CONFIG_VIDEO_BMP_RLE8
+#define BMP_RLE8_ESCAPE 0
+#define BMP_RLE8_EOL 0
+#define BMP_RLE8_EOBMP 1
+#define BMP_RLE8_DELTA 2
+
+static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
+ int cnt)
+{
+ while (cnt > 0) {
+ *(*fbp)++ = cmap[*bmap++];
+ cnt--;
+ }
+}
+
+static void draw_encoded_bitmap(ushort **fbp, ushort col, int cnt)
+{
+ ushort *fb = *fbp;
+
+ while (cnt > 0) {
+ *fb++ = col;
+ cnt--;
+ }
+ *fbp = fb;
+}
+
+static void video_display_rle8_bitmap(struct udevice *dev,
+ struct bmp_image *bmp, ushort *cmap,
+ uchar *fb, int x_off, int y_off)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+ uchar *bmap;
+ ulong width, height;
+ ulong cnt, runlen;
+ int x, y;
+ int decode = 1;
+
+ debug("%s\n", __func__);
+ width = get_unaligned_le32(&bmp->header.width);
+ height = get_unaligned_le32(&bmp->header.height);
+ bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
+
+ x = 0;
+ y = height - 1;
+
+ while (decode) {
+ if (bmap[0] == BMP_RLE8_ESCAPE) {
+ switch (bmap[1]) {
+ case BMP_RLE8_EOL:
+ /* end of line */
+ bmap += 2;
+ x = 0;
+ y--;
+ /* 16bpix, 2-byte per pixel, width should *2 */
+ fb -= (width * 2 + priv->line_length);
+ break;
+ case BMP_RLE8_EOBMP:
+ /* end of bitmap */
+ decode = 0;
+ break;
+ case BMP_RLE8_DELTA:
+ /* delta run */
+ x += bmap[2];
+ y -= bmap[3];
+ /* 16bpix, 2-byte per pixel, x should *2 */
+ fb = (uchar *)(priv->fb + (y + y_off - 1)
+ * priv->line_length + (x + x_off) * 2);
+ bmap += 4;
+ break;
+ default:
+ /* unencoded run */
+ runlen = bmap[1];
+ bmap += 2;
+ if (y < height) {
+ if (x < width) {
+ if (x + runlen > width)
+ cnt = width - x;
+ else
+ cnt = runlen;
+ draw_unencoded_bitmap(
+ (ushort **)&fb,
+ bmap, cmap, cnt);
+ }
+ x += runlen;
+ }
+ bmap += runlen;
+ if (runlen & 1)
+ bmap++;
+ }
+ } else {
+ /* encoded run */
+ if (y < height) {
+ runlen = bmap[0];
+ if (x < width) {
+ /* aggregate the same code */
+ while (bmap[0] == 0xff &&
+ bmap[2] != BMP_RLE8_ESCAPE &&
+ bmap[1] == bmap[3]) {
+ runlen += bmap[2];
+ bmap += 2;
+ }
+ if (x + runlen > width)
+ cnt = width - x;
+ else
+ cnt = runlen;
+ draw_encoded_bitmap((ushort **)&fb,
+ cmap[bmap[1]], cnt);
+ }
+ x += runlen;
+ }
+ bmap += 2;
+ }
+ }
+}
+#endif
+
+__weak void fb_put_byte(uchar **fb, uchar **from)
+{
+ *(*fb)++ = *(*from)++;
+}
+
+#if defined(CONFIG_BMP_16BPP)
+__weak void fb_put_word(uchar **fb, uchar **from)
+{
+ *(*fb)++ = *(*from)++;
+ *(*fb)++ = *(*from)++;
+}
+#endif /* CONFIG_BMP_16BPP */
+
+#define BMP_ALIGN_CENTER 0x7fff
+
+/**
+ * video_splash_align_axis() - Align a single coordinate
+ *
+ *- if a coordinate is 0x7fff then the image will be centred in
+ * that direction
+ *- if a coordinate is -ve then it will be offset to the
+ * left/top of the centre by that many pixels
+ *- if a coordinate is positive it will be used unchnaged.
+ *
+ * @axis: Input and output coordinate
+ * @panel_size: Size of panel in pixels for that axis
+ * @picture_size: Size of bitmap in pixels for that axis
+ */
+static void video_splash_align_axis(int *axis, unsigned long panel_size,
+ unsigned long picture_size)
+{
+ unsigned long panel_picture_delta = panel_size - picture_size;
+ unsigned long axis_alignment;
+
+ if (*axis == BMP_ALIGN_CENTER)
+ axis_alignment = panel_picture_delta / 2;
+ else if (*axis < 0)
+ axis_alignment = panel_picture_delta + *axis + 1;
+ else
+ return;
+
+ *axis = max(0, (int)axis_alignment);
+}
+
+static void video_set_cmap(struct udevice *dev,
+ struct bmp_color_table_entry *cte, unsigned colours)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+ int i;
+ ushort *cmap = priv->cmap;
+
+ debug("%s: colours=%d\n", __func__, colours);
+ for (i = 0; i < colours; ++i) {
+ *cmap = ((cte->red << 8) & 0xf800) |
+ ((cte->green << 3) & 0x07e0) |
+ ((cte->blue >> 3) & 0x001f);
+ cmap++;
+ cte++;
+ }
+}
+
+int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
+ bool align)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+ ushort *cmap_base = NULL;
+ ushort i, j;
+ uchar *fb;
+ struct bmp_image *bmp = map_sysmem(bmp_image, 0);
+ uchar *bmap;
+ ushort padded_width;
+ unsigned long width, height, byte_width;
+ unsigned long pwidth = priv->xsize;
+ unsigned colours, bpix, bmp_bpix;
+ struct bmp_color_table_entry *palette;
+ int hdr_size;
+
+ if (!bmp || !(bmp->header.signature[0] == 'B' &&
+ bmp->header.signature[1] == 'M')) {
+ printf("Error: no valid bmp image at %lx\n", bmp_image);
+
+ return -EINVAL;
+ }
+
+ width = get_unaligned_le32(&bmp->header.width);
+ height = get_unaligned_le32(&bmp->header.height);
+ bmp_bpix = get_unaligned_le16(&bmp->header.bit_count);
+ hdr_size = get_unaligned_le16(&bmp->header.size);
+ debug("hdr_size=%d, bmp_bpix=%d\n", hdr_size, bmp_bpix);
+ palette = (void *)bmp + 14 + hdr_size;
+
+ colours = 1 << bmp_bpix;
+
+ bpix = VNBITS(priv->bpix);
+
+ if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) {
+ printf("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+ bpix, bmp_bpix);
+
+ return -EINVAL;
+ }
+
+ /*
+ * We support displaying 8bpp BMPs on 16bpp LCDs
+ * and displaying 24bpp BMPs on 32bpp LCDs
+ * */
+ if (bpix != bmp_bpix &&
+ !(bmp_bpix == 8 && bpix == 16) &&
+ !(bmp_bpix == 24 && bpix == 32)) {
+ printf("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+ bpix, get_unaligned_le16(&bmp->header.bit_count));
+ return -EPERM;
+ }
+
+ debug("Display-bmp: %d x %d with %d colours, display %d\n",
+ (int)width, (int)height, (int)colours, 1 << bpix);
+
+ if (bmp_bpix == 8)
+ video_set_cmap(dev, palette, colours);
+
+ padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width);
+
+ if (align) {
+ video_splash_align_axis(&x, priv->xsize, width);
+ video_splash_align_axis(&y, priv->ysize, height);
+ }
+
+ if ((x + width) > pwidth)
+ width = pwidth - x;
+ if ((y + height) > priv->ysize)
+ height = priv->ysize - y;
+
+ bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
+ fb = (uchar *)(priv->fb +
+ (y + height - 1) * priv->line_length + x * bpix / 8);
+
+ switch (bmp_bpix) {
+ case 1:
+ case 8: {
+ cmap_base = priv->cmap;
+#ifdef CONFIG_VIDEO_BMP_RLE8
+ u32 compression = get_unaligned_le32(&bmp->header.compression);
+ debug("compressed %d %d\n", compression, BMP_BI_RLE8);
+ if (compression == BMP_BI_RLE8) {
+ if (bpix != 16) {
+ /* TODO implement render code for bpix != 16 */
+ printf("Error: only support 16 bpix");
+ return -EPROTONOSUPPORT;
+ }
+ video_display_rle8_bitmap(dev, bmp, cmap_base, fb, x,
+ y);
+ break;
+ }
+#endif
+
+ if (bpix != 16)
+ byte_width = width;
+ else
+ byte_width = width * 2;
+
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++) {
+ if (bpix != 16) {
+ fb_put_byte(&fb, &bmap);
+ } else {
+ *(uint16_t *)fb = cmap_base[*bmap];
+ bmap++;
+ fb += sizeof(uint16_t) / sizeof(*fb);
+ }
+ }
+ bmap += (padded_width - width);
+ fb -= byte_width + priv->line_length;
+ }
+ break;
+ }
+#if defined(CONFIG_BMP_16BPP)
+ case 16:
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++)
+ fb_put_word(&fb, &bmap);
+
+ bmap += (padded_width - width) * 2;
+ fb -= width * 2 + lcd_line_length;
+ }
+ break;
+#endif /* CONFIG_BMP_16BPP */
+#if defined(CONFIG_BMP_24BMP)
+ case 24:
+ for (i = 0; i < height; ++i) {
+ for (j = 0; j < width; j++) {
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = 0;
+ }
+ fb -= lcd_line_length + width * (bpix / 8);
+ }
+ break;
+#endif /* CONFIG_BMP_24BMP */
+#if defined(CONFIG_BMP_32BPP)
+ case 32:
+ for (i = 0; i < height; ++i) {
+ for (j = 0; j < width; j++) {
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ }
+ fb -= lcd_line_length + width * (bpix / 8);
+ }
+ break;
+#endif /* CONFIG_BMP_32BPP */
+ default:
+ break;
+ };
+
+ video_sync(dev);
+
+ return 0;
+}
+
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 5d8b043f14..a587d3c203 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -122,6 +122,10 @@ typedef struct global_data {
struct membuff console_out; /* console output */
struct membuff console_in; /* console input */
#endif
+#ifdef CONFIG_DM_VIDEO
+ ulong video_top; /* Top of video frame buffer area */
+ ulong video_bottom; /* Bottom of video frame buffer area */
+#endif
} gd_t;
#endif
diff --git a/include/bzlib.h b/include/bzlib.h
index 2d864d56b7..19314f8f66 100644
--- a/include/bzlib.h
+++ b/include/bzlib.h
@@ -68,7 +68,10 @@
/* Configure for U-Boot environment */
#define BZ_NO_STDIO
+
+#ifndef CONFIG_SANDBOX
#define BZ_NO_COMPRESS
+#endif
/* End of configuration for U-Boot environment */
#ifdef __cplusplus
diff --git a/include/clk.h b/include/clk.h
index 254ad2b876..941808a50e 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -8,6 +8,10 @@
#ifndef _CLK_H_
#define _CLK_H_
+#include <linux/types.h>
+
+struct udevice;
+
int soc_clk_dump(void);
struct clk_ops {
@@ -29,19 +33,28 @@ struct clk_ops {
ulong (*set_rate)(struct udevice *dev, ulong rate);
/**
- * clk_set_periph_rate() - Set clock rate for a peripheral
- *
- * @dev: Device to adjust (UCLASS_CLK)
- * @rate: New clock rate in Hz
- * @return new clock rate in Hz, or -ve error code
- */
+ * enable() - Enable the clock for a peripheral
+ *
+ * @dev: clock provider
+ * @periph: Peripheral ID to enable
+ * @return zero on success, or -ve error code
+ */
+ int (*enable)(struct udevice *dev, int periph);
+
+ /**
+ * get_periph_rate() - Get clock rate for a peripheral
+ *
+ * @dev: Device to check (UCLASS_CLK)
+ * @periph: Peripheral ID to check
+ * @return clock rate in Hz, or -ve error code
+ */
ulong (*get_periph_rate)(struct udevice *dev, int periph);
/**
- * clk_set_periph_rate() - Set current clock rate for a peripheral
+ * set_periph_rate() - Set current clock rate for a peripheral
*
* @dev: Device to update (UCLASS_CLK)
- * @periph: Peripheral ID to cupdate
+ * @periph: Peripheral ID to update
* @return new clock rate in Hz, or -ve error code
*/
ulong (*set_periph_rate)(struct udevice *dev, int periph, ulong rate);
@@ -58,7 +71,7 @@ struct clk_ops {
ulong clk_get_rate(struct udevice *dev);
/**
- * set_rate() - Set current clock rate
+ * clk_set_rate() - Set current clock rate
*
* @dev: Device to adjust
* @rate: New clock rate in Hz
@@ -67,6 +80,15 @@ ulong clk_get_rate(struct udevice *dev);
ulong clk_set_rate(struct udevice *dev, ulong rate);
/**
+ * clk_enable() - Enable the clock for a peripheral
+ *
+ * @dev: clock provider
+ * @periph: Peripheral ID to enable
+ * @return zero on success, or -ve error code
+ */
+int clk_enable(struct udevice *dev, int periph);
+
+/**
* clk_get_periph_rate() - Get current clock rate for a peripheral
*
* @dev: Device to check (UCLASS_CLK)
@@ -78,7 +100,7 @@ ulong clk_get_periph_rate(struct udevice *dev, int periph);
* clk_set_periph_rate() - Set current clock rate for a peripheral
*
* @dev: Device to update (UCLASS_CLK)
- * @periph: Peripheral ID to cupdate
+ * @periph: Peripheral ID to update
* @return new clock rate in Hz, or -ve error code
*/
ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate);
diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h
index cf6a6063b5..6ebe0b3866 100644
--- a/include/configs/am335x_evm.h
+++ b/include/configs/am335x_evm.h
@@ -357,6 +357,7 @@
*/
#ifdef CONFIG_SPL_BUILD
#undef CONFIG_DM_MMC
+#undef CONFIG_TIMER
#endif
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_USBETH_SUPPORT)
diff --git a/include/configs/am43xx_evm.h b/include/configs/am43xx_evm.h
index de7538fc9e..c3867efe9a 100644
--- a/include/configs/am43xx_evm.h
+++ b/include/configs/am43xx_evm.h
@@ -144,6 +144,7 @@
#undef CONFIG_DM_MMC
#undef CONFIG_DM_SPI
#undef CONFIG_DM_SPI_FLASH
+#undef CONFIG_TIMER
#endif
#ifndef CONFIG_SPL_BUILD
diff --git a/include/configs/colibri_vf.h b/include/configs/colibri_vf.h
index 708c79af97..5aed3a5fcd 100644
--- a/include/configs/colibri_vf.h
+++ b/include/configs/colibri_vf.h
@@ -36,7 +36,6 @@
#define CONFIG_BOARD_EARLY_INIT_F
-#define CONFIG_FSL_LPUART
#define LPUART_BASE UART0_BASE
/* Allow to overwrite serial and ethaddr */
diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h
index 2e8dbc7a78..e8b1ecaeb1 100644
--- a/include/configs/ls1021aqds.h
+++ b/include/configs/ls1021aqds.h
@@ -371,7 +371,6 @@ unsigned long get_board_ddr_clk(void);
* Serial Port
*/
#ifdef CONFIG_LPUART
-#define CONFIG_FSL_LPUART
#define CONFIG_LPUART_32B_REG
#else
#define CONFIG_CONS_INDEX 1
diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h
index c12ba3ac91..317ba62d3d 100644
--- a/include/configs/ls1021atwr.h
+++ b/include/configs/ls1021atwr.h
@@ -266,12 +266,13 @@
* Serial Port
*/
#ifdef CONFIG_LPUART
-#define CONFIG_FSL_LPUART
#define CONFIG_LPUART_32B_REG
#else
#define CONFIG_CONS_INDEX 1
#define CONFIG_SYS_NS16550_SERIAL
+#ifndef CONFIG_DM_SERIAL
#define CONFIG_SYS_NS16550_REG_SIZE 1
+#endif
#define CONFIG_SYS_NS16550_CLK get_serial_clock()
#endif
diff --git a/include/configs/pcm052.h b/include/configs/pcm052.h
index b851bba25d..891bdb0ecf 100644
--- a/include/configs/pcm052.h
+++ b/include/configs/pcm052.h
@@ -27,7 +27,6 @@
#define CONFIG_BOARD_EARLY_INIT_F
-#define CONFIG_FSL_LPUART
#define LPUART_BASE UART1_BASE
/* Allow to overwrite serial and ethaddr */
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index d3112e1760..6498981cef 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -158,24 +158,23 @@
/* LCD and keyboard require SDL support */
#ifdef CONFIG_SANDBOX_SDL
-#define CONFIG_LCD
-#define CONFIG_VIDEO_SANDBOX_SDL
#define CONFIG_CMD_BMP
-#define CONFIG_BOARD_EARLY_INIT_F
#define CONFIG_CONSOLE_MUX
#define CONFIG_SYS_CONSOLE_IS_IN_ENV
#define LCD_BPP LCD_COLOR16
#define CONFIG_LCD_BMP_RLE8
+#define CONFIG_VIDEO_BMP_RLE8
+#define CONFIG_SPLASH_SCREEN_ALIGN
#define CONFIG_KEYBOARD
#define SANDBOX_SERIAL_SETTINGS "stdin=serial,cros-ec-keyb,usbkbd\0" \
- "stdout=serial,lcd\0" \
- "stderr=serial,lcd\0"
+ "stdout=serial,lcd.vidconsole\0" \
+ "stderr=serial,lcd.vidconsole\0"
#else
#define SANDBOX_SERIAL_SETTINGS "stdin=serial\0" \
- "stdout=serial,lcd\0" \
- "stderr=serial,lcd\0"
+ "stdout=serial,lcd.vidconsole\0" \
+ "stderr=serial,lcd.vidconsole\0"
#endif
#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \
diff --git a/include/configs/ti_omap5_common.h b/include/configs/ti_omap5_common.h
index 2d492f8ba7..d164e6abd4 100644
--- a/include/configs/ti_omap5_common.h
+++ b/include/configs/ti_omap5_common.h
@@ -164,6 +164,7 @@
*/
#ifdef CONFIG_SPL_BUILD
#undef CONFIG_DM_MMC
+#undef CONFIG_TIMER
#endif
#endif /* __CONFIG_TI_OMAP5_COMMON_H */
diff --git a/include/configs/vf610twr.h b/include/configs/vf610twr.h
index 34df6f0352..dcfafaf631 100644
--- a/include/configs/vf610twr.h
+++ b/include/configs/vf610twr.h
@@ -34,7 +34,6 @@
#define CONFIG_BOARD_EARLY_INIT_F
-#define CONFIG_FSL_LPUART
#define LPUART_BASE UART1_BASE
/* Allow to overwrite serial and ethaddr */
diff --git a/include/dm/test.h b/include/dm/test.h
index a4bc5c8404..ca924d9237 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -155,6 +155,14 @@ enum {
/* Declare a new driver model test */
#define DM_TEST(_name, _flags) UNIT_TEST(_name, _flags, dm_test)
+/* This platform data is needed in tests, so declare it here */
+struct sandbox_sdl_plat {
+ int xres;
+ int yres;
+ int bpix;
+ int rot;
+};
+
/* Declare ping methods for the drivers */
int test_ping(struct udevice *dev, int pingval, int *pingret);
int testfdt_ping(struct udevice *dev, int pingval, int *pingret);
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 27fa0b68db..a0a3a79aac 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -66,7 +66,9 @@ enum uclass_id {
UCLASS_USB, /* USB bus */
UCLASS_USB_DEV_GENERIC, /* USB generic device */
UCLASS_USB_HUB, /* USB hub */
+ UCLASS_VIDEO, /* Video or LCD device */
UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */
+ UCLASS_VIDEO_CONSOLE, /* Text console driver for video device */
UCLASS_COUNT,
UCLASS_INVALID = -1,
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 27b350e241..25e98c9c9e 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -151,7 +151,6 @@ enum fdt_compat_id {
COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */
COMPAT_MAXIM_98095_CODEC, /* MAX98095 Codec */
COMPAT_SAMSUNG_EXYNOS5_I2C, /* Exynos5 High Speed I2C Controller */
- COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */
COMPAT_SAMSUNG_EXYNOS_SYSMMU, /* Exynos sysmmu */
COMPAT_INTEL_MICROCODE, /* Intel microcode update */
COMPAT_MEMORY_SPD, /* Memory SPD information */
diff --git a/include/lcd.h b/include/lcd.h
index 59202b7e59..d7651a8f08 100644
--- a/include/lcd.h
+++ b/include/lcd.h
@@ -18,6 +18,12 @@
#include <asm/byteorder.h>
#endif
+int bmp_display(ulong addr, int x, int y);
+struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp,
+ void **alloc_addr);
+
+#ifndef CONFIG_DM_VIDEO
+
extern char lcd_is_enabled;
extern int lcd_line_length;
extern struct vidinfo panel_info;
@@ -26,10 +32,6 @@ void lcd_ctrl_init(void *lcdbase);
void lcd_enable(void);
void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue);
-struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp,
- void **alloc_addr);
-int bmp_display(ulong addr, int x, int y);
-
/**
* Set whether we need to flush the dcache when changing the LCD image. This
* defaults to off.
@@ -209,4 +211,6 @@ void lcd_sync(void);
#define PAGE_SIZE 4096
#endif
+#endif /* !CONFIG_DM_VIDEO */
+
#endif /* _LCD_H_ */
diff --git a/include/timer.h b/include/timer.h
index 7fee17e3d2..f14725cc28 100644
--- a/include/timer.h
+++ b/include/timer.h
@@ -8,6 +8,15 @@
#define _TIMER_H_
/*
+ * dm_timer_init - initialize a timer for time keeping. On success
+ * initializes gd->timer so that lib/timer can use it for future
+ * referrence.
+ *
+ * @return - 0 on success or error number
+ */
+int dm_timer_init(void);
+
+/*
* timer_conv_64 - convert 32-bit counter value to 64-bit
*
* @count: 32-bit counter value
diff --git a/include/video.h b/include/video.h
index 65e4ec1e1a..b20f06f335 100644
--- a/include/video.h
+++ b/include/video.h
@@ -1,14 +1,167 @@
/*
-** MPC823 Video Controller
-** =======================
-** (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
-** AIRVENT SAM s.p.a - RIMINI(ITALY)
-**
-*/
+ * Video uclass and legacy implementation
+ *
+ * Copyright (c) 2015 Google, Inc
+ *
+ * MPC823 Video Controller
+ * =======================
+ * (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
+ * AIRVENT SAM s.p.a - RIMINI(ITALY)
+ *
+ */
#ifndef _VIDEO_H_
#define _VIDEO_H_
+#ifdef CONFIG_DM_VIDEO
+
+#include <stdio_dev.h>
+
+struct video_uc_platdata {
+ uint align;
+ uint size;
+ ulong base;
+};
+
+/*
+ * Bits per pixel selector. Each value n is such that the bits-per-pixel is
+ * 2 ^ n
+ */
+enum video_log2_bpp {
+ VIDEO_BPP1 = 0,
+ VIDEO_BPP2,
+ VIDEO_BPP4,
+ VIDEO_BPP8,
+ VIDEO_BPP16,
+ VIDEO_BPP32,
+};
+
+/*
+ * Convert enum video_log2_bpp to bytes and bits. Note we omit the outer
+ * brackets to allow multiplication by fractional pixels.
+ */
+#define VNBYTES(bpix) (1 << (bpix)) / 8
+
+#define VNBITS(bpix) (1 << (bpix))
+
+/**
+ * struct video_priv - Device information used by the video uclass
+ *
+ * @xsize: Number of pixel columns (e.g. 1366)
+ * @ysize: Number of pixels rows (e.g.. 768)
+ * @tor: Display rotation (0=none, 1=90 degrees clockwise, etc.)
+ * @bpix: Encoded bits per pixel
+ * @fb: Frame buffer
+ * @fb_size: Frame buffer size
+ * @line_length: Length of each frame buffer line, in bytes
+ * @colour_fg: Foreground colour (pixel value)
+ * @colour_bg: Background colour (pixel value)
+ * @flush_dcache: true to enable flushing of the data cache after
+ * the LCD is updated
+ * @cmap: Colour map for 8-bit-per-pixel displays
+ */
+struct video_priv {
+ /* Things set up by the driver: */
+ ushort xsize;
+ ushort ysize;
+ ushort rot;
+ enum video_log2_bpp bpix;
+
+ /*
+ * Things that are private to the uclass: don't use these in the
+ * driver
+ */
+ void *fb;
+ int fb_size;
+ int line_length;
+ int colour_fg;
+ int colour_bg;
+ bool flush_dcache;
+ ushort *cmap;
+};
+
+/* Placeholder - there are no video operations at present */
+struct video_ops {
+};
+
+#define video_get_ops(dev) ((struct video_ops *)(dev)->driver->ops)
+
+/**
+ * video_reserve() - Reserve frame-buffer memory for video devices
+ *
+ * Note: This function is for internal use.
+ *
+ * This uses the uclass platdata's @size and @align members to figure out
+ * a size and position for each frame buffer as part of the pre-relocation
+ * process of determining the post-relocation memory layout.
+ *
+ * gd->video_top is set to the initial value of *@addrp and gd->video_bottom
+ * is set to the final value.
+ *
+ * @addrp: On entry, the top of available memory. On exit, the new top,
+ * after allocating the required memory.
+ * @return 0
+ */
+int video_reserve(ulong *addrp);
+
+/**
+ * video_sync() - Sync a device's frame buffer with its hardware
+ *
+ * Some frame buffers are cached or have a secondary frame buffer. This
+ * function syncs these up so that the current contents of the U-Boot frame
+ * buffer are displayed to the user.
+ *
+ * @dev: Device to sync
+ */
+void video_sync(struct udevice *vid);
+
+/**
+ * video_sync_all() - Sync all devices' frame buffers with there hardware
+ *
+ * This calls video_sync() on all active video devices.
+ */
+void video_sync_all(void);
+
+/**
+ * video_bmp_display() - Display a BMP file
+ *
+ * @dev: Device to display the bitmap on
+ * @bmp_image: Address of bitmap image to display
+ * @x: X position in pixels from the left
+ * @y: Y position in pixels from the top
+ * @align: true to adjust the coordinates to centre the image. If false
+ * the coordinates are used as is. If true:
+ *
+ * - if a coordinate is 0x7fff then the image will be centred in
+ * that direction
+ * - if a coordinate is -ve then it will be offset to the
+ * left/top of the centre by that many pixels
+ * - if a coordinate is positive it will be used unchnaged.
+ * @return 0 if OK, -ve on error
+ */
+int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
+ bool align);
+
+/**
+ * video_get_xsize() - Get the width of the display in pixels
+ *
+ * @dev: Device to check
+ * @return device frame buffer width in pixels
+ */
+int video_get_xsize(struct udevice *dev);
+
+/**
+ * video_get_ysize() - Get the height of the display in pixels
+ *
+ * @dev: Device to check
+ * @return device frame buffer height in pixels
+ */
+int video_get_ysize(struct udevice *dev);
+
+#endif /* CONFIG_DM_VIDEO */
+
+#ifndef CONFIG_DM_VIDEO
+
/* Video functions */
struct stdio_dev;
@@ -73,4 +226,7 @@ int kwh043st20_f01_spi_startup(unsigned int bus, unsigned int cs,
int lg4573_spi_startup(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int spi_mode);
#endif
+
+#endif /* CONFIG_DM_VIDEO */
+
#endif
diff --git a/include/video_console.h b/include/video_console.h
new file mode 100644
index 0000000000..c0fc79273a
--- /dev/null
+++ b/include/video_console.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __video_console_h
+#define __video_console_h
+
+/**
+ * struct vidconsole_priv - uclass-private data about a console device
+ *
+ * @sdev: stdio device, acting as an output sink
+ * @curr_col: Current text column (0=left)
+ * @curr_row: Current row (0=top)
+ * @rows: Number of text rows
+ * @cols: Number of text columns
+ */
+struct vidconsole_priv {
+ struct stdio_dev sdev;
+ int curr_col;
+ int curr_row;
+ int rows;
+ int cols;
+};
+
+/**
+ * struct vidconsole_ops - Video console operations
+ *
+ * These operations work on either an absolute console position (measured
+ * in pixels) or a text row number (measured in rows, where each row consists
+ * of an entire line of text - typically 16 pixels).
+ */
+struct vidconsole_ops {
+ /**
+ * putc_xy() - write a single character to a position
+ *
+ * @dev: Device to write to
+ * @x: Pixel X position (0=left-most pixel)
+ * @y: Pixel Y position (0=top-most pixel)
+ * @ch: Character to write
+ * @return 0 if OK, -ve on error
+ */
+ int (*putc_xy)(struct udevice *dev, uint x, uint y, char ch);
+
+ /**
+ * move_rows() - Move text rows from one place to another
+ *
+ * @dev: Device to adjust
+ * @rowdst: Destination text row (0=top)
+ * @rowsrc: Source start text row
+ * @count: Number of text rows to move
+ * @return 0 if OK, -ve on error
+ */
+ int (*move_rows)(struct udevice *dev, uint rowdst, uint rowsrc,
+ uint count);
+
+ /**
+ * set_row() - Set the colour of a text row
+ *
+ * Every pixel contained within the text row is adjusted
+ *
+ * @dev: Device to adjust
+ * @row: Text row to adjust (0=top)
+ * @clr: Raw colour (pixel value) to write to each pixel
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_row)(struct udevice *dev, uint row, int clr);
+};
+
+/* Get a pointer to the driver operations for a video console device */
+#define vidconsole_get_ops(dev) ((struct vidconsole_ops *)(dev)->driver->ops)
+
+/**
+ * vidconsole_putc_xy() - write a single character to a position
+ *
+ * @dev: Device to write to
+ * @x: Pixel X position (0=left-most pixel)
+ * @y: Pixel Y position (0=top-most pixel)
+ * @ch: Character to write
+ * @return 0 if OK, -ve on error
+ */
+int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch);
+
+/**
+ * vidconsole_move_rows() - Move text rows from one place to another
+ *
+ * @dev: Device to adjust
+ * @rowdst: Destination text row (0=top)
+ * @rowsrc: Source start text row
+ * @count: Number of text rows to move
+ * @return 0 if OK, -ve on error
+ */
+int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
+ uint count);
+
+/**
+ * vidconsole_set_row() - Set the colour of a text row
+ *
+ * Every pixel contained within the text row is adjusted
+ *
+ * @dev: Device to adjust
+ * @row: Text row to adjust (0=top)
+ * @clr: Raw colour (pixel value) to write to each pixel
+ * @return 0 if OK, -ve on error
+ */
+int vidconsole_set_row(struct udevice *dev, uint row, int clr);
+
+/**
+ * vidconsole_put_char() - Output a character to the current console position
+ *
+ * Outputs a character to the console and advances the cursor. This function
+ * handles wrapping to new lines and scrolling the console. Special
+ * characters are handled also: \n, \r, \b and \t.
+ *
+ * The device always starts with the cursor at position 0,0 (top left). It
+ * can be adjusted manually using vidconsole_position_cursor().
+ *
+ * @dev: Device to adjust
+ * @ch: Character to write
+ * @return 0 if OK, -ve on error
+ */
+int vidconsole_put_char(struct udevice *dev, char ch);
+
+/**
+ * vidconsole_position_cursor() - Move the text cursor
+ *
+ * @dev: Device to adjust
+ * @col: New cursor text column
+ * @row: New cursor text row
+ * @return 0 if OK, -ve on error
+ */
+void vidconsole_position_cursor(struct udevice *dev, unsigned col,
+ unsigned row);
+
+#endif
diff --git a/lib/bzip2/Makefile b/lib/bzip2/Makefile
index f0b81ad2c2..585d776ba8 100644
--- a/lib/bzip2/Makefile
+++ b/lib/bzip2/Makefile
@@ -4,3 +4,4 @@
obj-y += bzlib.o bzlib_crctable.o bzlib_decompress.o \
bzlib_randtable.o bzlib_huffman.o
+obj-$(CONFIG_SANDBOX) += bzlib_compress.o bzlib_blocksort.o
diff --git a/lib/bzip2/bzlib_blocksort.c b/lib/bzip2/bzlib_blocksort.c
new file mode 100644
index 0000000000..2785521502
--- /dev/null
+++ b/lib/bzip2/bzlib_blocksort.c
@@ -0,0 +1,1134 @@
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery ---*/
+/*--- blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/*--
+ This file is a part of bzip2 and/or libbzip2, a program and
+ library for lossless, block-sorting data compression.
+
+ Copyright (C) 1996-2002 Julian R Seward. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Julian Seward, Cambridge, UK.
+ jseward@acm.org
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ This program is based on (at least) the work of:
+ Mike Burrows
+ David Wheeler
+ Peter Fenwick
+ Alistair Moffat
+ Radford Neal
+ Ian H. Witten
+ Robert Sedgewick
+ Jon L. Bentley
+
+ For more information on these sources, see the manual.
+--*/
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting ---*/
+/*--- algorithm, for repetitive blocks ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+void fallbackSimpleSort ( UInt32* fmap,
+ UInt32* eclass,
+ Int32 lo,
+ Int32 hi )
+{
+ Int32 i, j, tmp;
+ UInt32 ec_tmp;
+
+ if (lo == hi) return;
+
+ if (hi - lo > 3) {
+ for ( i = hi-4; i >= lo; i-- ) {
+ tmp = fmap[i];
+ ec_tmp = eclass[tmp];
+ for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 )
+ fmap[j-4] = fmap[j];
+ fmap[j-4] = tmp;
+ }
+ }
+
+ for ( i = hi-1; i >= lo; i-- ) {
+ tmp = fmap[i];
+ ec_tmp = eclass[tmp];
+ for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ )
+ fmap[j-1] = fmap[j];
+ fmap[j-1] = tmp;
+ }
+}
+
+
+/*---------------------------------------------*/
+#define fswap(zz1, zz2) \
+ { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define fvswap(zzp1, zzp2, zzn) \
+{ \
+ Int32 yyp1 = (zzp1); \
+ Int32 yyp2 = (zzp2); \
+ Int32 yyn = (zzn); \
+ while (yyn > 0) { \
+ fswap(fmap[yyp1], fmap[yyp2]); \
+ yyp1++; yyp2++; yyn--; \
+ } \
+}
+
+
+#define fmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define fpush(lz,hz) { stackLo[sp] = lz; \
+ stackHi[sp] = hz; \
+ sp++; }
+
+#define fpop(lz,hz) { sp--; \
+ lz = stackLo[sp]; \
+ hz = stackHi[sp]; }
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE 100
+
+
+static
+void fallbackQSort3 ( UInt32* fmap,
+ UInt32* eclass,
+ Int32 loSt,
+ Int32 hiSt )
+{
+ Int32 unLo, unHi, ltLo, gtHi, n, m;
+ Int32 sp, lo, hi;
+ UInt32 med, r, r3;
+ Int32 stackLo[FALLBACK_QSORT_STACK_SIZE];
+ Int32 stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+ r = 0;
+
+ sp = 0;
+ fpush ( loSt, hiSt );
+
+ while (sp > 0) {
+
+ AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
+
+ fpop ( lo, hi );
+ if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+ fallbackSimpleSort ( fmap, eclass, lo, hi );
+ continue;
+ }
+
+ /* Random partitioning. Median of 3 sometimes fails to
+ avoid bad cases. Median of 9 seems to help but
+ looks rather expensive. This too seems to work but
+ is cheaper. Guidance for the magic constants
+ 7621 and 32768 is taken from Sedgewick's algorithms
+ book, chapter 35.
+ */
+ r = ((r * 7621) + 1) % 32768;
+ r3 = r % 3;
+ if (r3 == 0) med = eclass[fmap[lo]]; else
+ if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else
+ med = eclass[fmap[hi]];
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (1) {
+ while (1) {
+ if (unLo > unHi) break;
+ n = (Int32)eclass[fmap[unLo]] - (Int32)med;
+ if (n == 0) {
+ fswap(fmap[unLo], fmap[ltLo]);
+ ltLo++; unLo++;
+ continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (1) {
+ if (unLo > unHi) break;
+ n = (Int32)eclass[fmap[unHi]] - (Int32)med;
+ if (n == 0) {
+ fswap(fmap[unHi], fmap[gtHi]);
+ gtHi--; unHi--;
+ continue;
+ };
+ if (n < 0) break;
+ unHi--;
+ }
+ if (unLo > unHi) break;
+ fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+ }
+
+ AssertD ( unHi == unLo-1, "fallbackQSort3(2)" );
+
+ if (gtHi < ltLo) continue;
+
+ n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n);
+ m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ if (n - lo > hi - m) {
+ fpush ( lo, n );
+ fpush ( m, hi );
+ } else {
+ fpush ( m, hi );
+ fpush ( lo, n );
+ }
+ }
+}
+
+#undef fmin
+#undef fpush
+#undef fpop
+#undef fswap
+#undef fvswap
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > 0
+ eclass exists for [0 .. nblock-1]
+ ((UChar*)eclass) [0 .. nblock-1] holds block
+ ptr exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)eclass) [0 .. nblock-1] holds block
+ All other areas of eclass destroyed
+ fmap [0 .. nblock-1] holds sorted order
+ bhtab [ 0 .. 2+(nblock/32) ] destroyed
+*/
+
+#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31))
+#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31))
+#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31)))
+#define WORD_BH(zz) bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz) ((zz) & 0x01f)
+
+static
+void fallbackSort ( UInt32* fmap,
+ UInt32* eclass,
+ UInt32* bhtab,
+ Int32 nblock,
+ Int32 verb )
+{
+ Int32 ftab[257];
+ Int32 ftabCopy[256];
+ Int32 H, i, j, k, l, r, cc, cc1;
+ Int32 nNotDone;
+ Int32 nBhtab;
+ UChar* eclass8 = (UChar*)eclass;
+
+ /*--
+ Initial 1-char radix sort to generate
+ initial fmap and initial BH bits.
+ --*/
+ if (verb >= 4)
+ VPrintf0 ( " bucket sorting ...\n" );
+ for (i = 0; i < 257; i++) ftab[i] = 0;
+ for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+ for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i];
+ for (i = 1; i < 257; i++) ftab[i] += ftab[i-1];
+
+ for (i = 0; i < nblock; i++) {
+ j = eclass8[i];
+ k = ftab[j] - 1;
+ ftab[j] = k;
+ fmap[k] = i;
+ }
+
+ nBhtab = 2 + (nblock / 32);
+ for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+ for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+ /*--
+ Inductively refine the buckets. Kind-of an
+ "exponential radix sort" (!), inspired by the
+ Manber-Myers suffix array construction algorithm.
+ --*/
+
+ /*-- set sentinel bits for block-end detection --*/
+ for (i = 0; i < 32; i++) {
+ SET_BH(nblock + 2*i);
+ CLEAR_BH(nblock + 2*i + 1);
+ }
+
+ /*-- the log(N) loop --*/
+ H = 1;
+ while (1) {
+
+ if (verb >= 4)
+ VPrintf1 ( " depth %6d has ", H );
+
+ j = 0;
+ for (i = 0; i < nblock; i++) {
+ if (ISSET_BH(i)) j = i;
+ k = fmap[i] - H; if (k < 0) k += nblock;
+ eclass[k] = j;
+ }
+
+ nNotDone = 0;
+ r = -1;
+ while (1) {
+
+ /*-- find the next non-singleton bucket --*/
+ k = r + 1;
+ while (ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+ if (ISSET_BH(k)) {
+ while (WORD_BH(k) == 0xffffffff) k += 32;
+ while (ISSET_BH(k)) k++;
+ }
+ l = k - 1;
+ if (l >= nblock) break;
+ while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+ if (!ISSET_BH(k)) {
+ while (WORD_BH(k) == 0x00000000) k += 32;
+ while (!ISSET_BH(k)) k++;
+ }
+ r = k - 1;
+ if (r >= nblock) break;
+
+ /*-- now [l, r] bracket current bucket --*/
+ if (r > l) {
+ nNotDone += (r - l + 1);
+ fallbackQSort3 ( fmap, eclass, l, r );
+
+ /*-- scan bucket and generate header bits-- */
+ cc = -1;
+ for (i = l; i <= r; i++) {
+ cc1 = eclass[fmap[i]];
+ if (cc != cc1) { SET_BH(i); cc = cc1; };
+ }
+ }
+ }
+
+ if (verb >= 4)
+ VPrintf1 ( "%6d unresolved strings\n", nNotDone );
+
+ H *= 2;
+ if (H > nblock || nNotDone == 0) break;
+ }
+
+ /*--
+ Reconstruct the original block in
+ eclass8 [0 .. nblock-1], since the
+ previous phase destroyed it.
+ --*/
+ if (verb >= 4)
+ VPrintf0 ( " reconstructing block ...\n" );
+ j = 0;
+ for (i = 0; i < nblock; i++) {
+ while (ftabCopy[j] == 0) j++;
+ ftabCopy[j]--;
+ eclass8[fmap[i]] = (UChar)j;
+ }
+ AssertH ( j < 256, 1005 );
+}
+
+#undef SET_BH
+#undef CLEAR_BH
+#undef ISSET_BH
+#undef WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting ---*/
+/*--- algorithm. Faster for "normal" ---*/
+/*--- non-repetitive blocks. ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+Bool mainGtU ( UInt32 i1,
+ UInt32 i2,
+ UChar* block,
+ UInt16* quadrant,
+ UInt32 nblock,
+ Int32* budget )
+{
+ Int32 k;
+ UChar c1, c2;
+ UInt16 s1, s2;
+
+ AssertD ( i1 != i2, "mainGtU" );
+ /* 1 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 2 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 3 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 4 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 5 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 6 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 7 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 8 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 9 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 10 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 11 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 12 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+
+ k = nblock + 8;
+
+ do {
+ /* 1 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 2 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 3 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 4 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 5 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 6 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 7 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 8 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+
+ if (i1 >= nblock) i1 -= nblock;
+ if (i2 >= nblock) i2 -= nblock;
+
+ k -= 8;
+ (*budget)--;
+ }
+ while (k >= 0);
+
+ return False;
+}
+
+
+/*---------------------------------------------*/
+/*--
+ Knuth's increments seem to work better
+ than Incerpi-Sedgewick here. Possibly
+ because the number of elems to sort is
+ usually small, typically <= 20.
+--*/
+static
+Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720,
+ 797161, 2391484 };
+
+static
+void mainSimpleSort ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ Int32 nblock,
+ Int32 lo,
+ Int32 hi,
+ Int32 d,
+ Int32* budget )
+{
+ Int32 i, j, h, bigN, hp;
+ UInt32 v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2) return;
+
+ hp = 0;
+ while (incs[hp] < bigN) hp++;
+ hp--;
+
+ for (; hp >= 0; hp--) {
+ h = incs[hp];
+
+ i = lo + h;
+ while (True) {
+
+ /*-- copy 1 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 2 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 3 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ if (*budget < 0) return;
+ }
+ }
+}
+
+
+/*---------------------------------------------*/
+/*--
+ The following is an implementation of
+ an elegant 3-way quicksort for strings,
+ described in a paper "Fast Algorithms for
+ Sorting and Searching Strings", by Robert
+ Sedgewick and Jon L. Bentley.
+--*/
+
+#define mswap(zz1, zz2) \
+ { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define mvswap(zzp1, zzp2, zzn) \
+{ \
+ Int32 yyp1 = (zzp1); \
+ Int32 yyp2 = (zzp2); \
+ Int32 yyn = (zzn); \
+ while (yyn > 0) { \
+ mswap(ptr[yyp1], ptr[yyp2]); \
+ yyp1++; yyp2++; yyn--; \
+ } \
+}
+
+static
+__inline__
+UChar mmed3 ( UChar a, UChar b, UChar c )
+{
+ UChar t;
+ if (a > b) { t = a; a = b; b = t; };
+ if (b > c) {
+ b = c;
+ if (a > b) b = a;
+ }
+ return b;
+}
+
+#define mmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define mpush(lz,hz,dz) { stackLo[sp] = lz; \
+ stackHi[sp] = hz; \
+ stackD [sp] = dz; \
+ sp++; }
+
+#define mpop(lz,hz,dz) { sp--; \
+ lz = stackLo[sp]; \
+ hz = stackHi[sp]; \
+ dz = stackD [sp]; }
+
+
+#define mnextsize(az) (nextHi[az]-nextLo[az])
+
+#define mnextswap(az,bz) \
+ { Int32 tz; \
+ tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+ tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+ tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; }
+
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE 100
+
+static
+void mainQSort3 ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ Int32 nblock,
+ Int32 loSt,
+ Int32 hiSt,
+ Int32 dSt,
+ Int32* budget )
+{
+ Int32 unLo, unHi, ltLo, gtHi, n, m, med;
+ Int32 sp, lo, hi, d;
+
+ Int32 stackLo[MAIN_QSORT_STACK_SIZE];
+ Int32 stackHi[MAIN_QSORT_STACK_SIZE];
+ Int32 stackD [MAIN_QSORT_STACK_SIZE];
+
+ Int32 nextLo[3];
+ Int32 nextHi[3];
+ Int32 nextD [3];
+
+ sp = 0;
+ mpush ( loSt, hiSt, dSt );
+
+ while (sp > 0) {
+
+ AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
+
+ mpop ( lo, hi, d );
+ if (hi - lo < MAIN_QSORT_SMALL_THRESH ||
+ d > MAIN_QSORT_DEPTH_THRESH) {
+ mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget );
+ if (*budget < 0) return;
+ continue;
+ }
+
+ med = (Int32)
+ mmed3 ( block[ptr[ lo ]+d],
+ block[ptr[ hi ]+d],
+ block[ptr[ (lo+hi)>>1 ]+d] );
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (True) {
+ while (True) {
+ if (unLo > unHi) break;
+ n = ((Int32)block[ptr[unLo]+d]) - med;
+ if (n == 0) {
+ mswap(ptr[unLo], ptr[ltLo]);
+ ltLo++; unLo++; continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (True) {
+ if (unLo > unHi) break;
+ n = ((Int32)block[ptr[unHi]+d]) - med;
+ if (n == 0) {
+ mswap(ptr[unHi], ptr[gtHi]);
+ gtHi--; unHi--; continue;
+ };
+ if (n < 0) break;
+ unHi--;
+ }
+ if (unLo > unHi) break;
+ mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--;
+ }
+
+ AssertD ( unHi == unLo-1, "mainQSort3(2)" );
+
+ if (gtHi < ltLo) {
+ mpush(lo, hi, d+1 );
+ continue;
+ }
+
+ n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n);
+ m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ nextLo[0] = lo; nextHi[0] = n; nextD[0] = d;
+ nextLo[1] = m; nextHi[1] = hi; nextD[1] = d;
+ nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+ if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+ if (mnextsize(1) < mnextsize(2)) mnextswap(1,2);
+ if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+
+ AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" );
+ AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" );
+
+ mpush (nextLo[0], nextHi[0], nextD[0]);
+ mpush (nextLo[1], nextHi[1], nextD[1]);
+ mpush (nextLo[2], nextHi[2], nextD[2]);
+ }
+}
+
+#undef mswap
+#undef mvswap
+#undef mpush
+#undef mpop
+#undef mmin
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > N_OVERSHOOT
+ block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ ((UChar*)block32) [0 .. nblock-1] holds block
+ ptr exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)block32) [0 .. nblock-1] holds block
+ All other areas of block32 destroyed
+ ftab [0 .. 65536 ] destroyed
+ ptr [0 .. nblock-1] holds sorted order
+ if (*budget < 0), sorting was abandoned
+*/
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static
+void mainSort ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ UInt32* ftab,
+ Int32 nblock,
+ Int32 verb,
+ Int32* budget )
+{
+ Int32 i, j, k, ss, sb;
+ Int32 runningOrder[256];
+ Bool bigDone[256];
+ Int32 copyStart[256];
+ Int32 copyEnd [256];
+ UChar c1;
+ Int32 numQSorted;
+ UInt16 s;
+ if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" );
+
+ /*-- set up the 2-byte frequency table --*/
+ for (i = 65536; i >= 0; i--) ftab[i] = 0;
+
+ j = block[0] << 8;
+ i = nblock-1;
+ for (; i >= 3; i -= 4) {
+ quadrant[i] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+ ftab[j]++;
+ quadrant[i-1] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-1]) << 8);
+ ftab[j]++;
+ quadrant[i-2] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-2]) << 8);
+ ftab[j]++;
+ quadrant[i-3] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-3]) << 8);
+ ftab[j]++;
+ }
+ for (; i >= 0; i--) {
+ quadrant[i] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+ ftab[j]++;
+ }
+
+ /*-- (emphasises close relationship of block & quadrant) --*/
+ for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+ block [nblock+i] = block[i];
+ quadrant[nblock+i] = 0;
+ }
+
+ if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" );
+
+ /*-- Complete the initial radix sort --*/
+ for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1];
+
+ s = block[0] << 8;
+ i = nblock-1;
+ for (; i >= 3; i -= 4) {
+ s = (s >> 8) | (block[i] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i;
+ s = (s >> 8) | (block[i-1] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-1;
+ s = (s >> 8) | (block[i-2] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-2;
+ s = (s >> 8) | (block[i-3] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-3;
+ }
+ for (; i >= 0; i--) {
+ s = (s >> 8) | (block[i] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i;
+ }
+
+ /*--
+ Now ftab contains the first loc of every small bucket.
+ Calculate the running order, from smallest to largest
+ big bucket.
+ --*/
+ for (i = 0; i <= 255; i++) {
+ bigDone [i] = False;
+ runningOrder[i] = i;
+ }
+
+ {
+ Int32 vv;
+ Int32 h = 1;
+ do h = 3 * h + 1; while (h <= 256);
+ do {
+ h = h / 3;
+ for (i = h; i <= 255; i++) {
+ vv = runningOrder[i];
+ j = i;
+ while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) {
+ runningOrder[j] = runningOrder[j-h];
+ j = j - h;
+ if (j <= (h - 1)) goto zero;
+ }
+ zero:
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+ }
+
+ /*--
+ The main sorting loop.
+ --*/
+
+ numQSorted = 0;
+
+ for (i = 0; i <= 255; i++) {
+
+ /*--
+ Process big buckets, starting with the least full.
+ Basically this is a 3-step process in which we call
+ mainQSort3 to sort the small buckets [ss, j], but
+ also make a big effort to avoid the calls if we can.
+ --*/
+ ss = runningOrder[i];
+
+ /*--
+ Step 1:
+ Complete the big bucket [ss] by quicksorting
+ any unsorted small buckets [ss, j], for j != ss.
+ Hopefully previous pointer-scanning phases have already
+ completed many of the small buckets [ss, j], so
+ we don't have to sort them at all.
+ --*/
+ for (j = 0; j <= 255; j++) {
+ if (j != ss) {
+ sb = (ss << 8) + j;
+ if ( ! (ftab[sb] & SETMASK) ) {
+ Int32 lo = ftab[sb] & CLEARMASK;
+ Int32 hi = (ftab[sb+1] & CLEARMASK) - 1;
+ if (hi > lo) {
+ if (verb >= 4)
+ VPrintf4 ( " qsort [0x%x, 0x%x] "
+ "done %d this %d\n",
+ ss, j, numQSorted, hi - lo + 1 );
+ mainQSort3 (
+ ptr, block, quadrant, nblock,
+ lo, hi, BZ_N_RADIX, budget
+ );
+ numQSorted += (hi - lo + 1);
+ if (*budget < 0) return;
+ }
+ }
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ AssertH ( !bigDone[ss], 1006 );
+
+ /*--
+ Step 2:
+ Now scan this big bucket [ss] so as to synthesise the
+ sorted order for small buckets [t, ss] for all t,
+ including, magically, the bucket [ss,ss] too.
+ This will avoid doing Real Work in subsequent Step 1's.
+ --*/
+ {
+ for (j = 0; j <= 255; j++) {
+ copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK;
+ copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+ }
+ for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+ k = ptr[j]-1; if (k < 0) k += nblock;
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[ copyStart[c1]++ ] = k;
+ }
+ for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+ k = ptr[j]-1; if (k < 0) k += nblock;
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[ copyEnd[c1]-- ] = k;
+ }
+ }
+
+ AssertH ( (copyStart[ss]-1 == copyEnd[ss])
+ ||
+ /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+ Necessity for this case is demonstrated by compressing
+ a sequence of approximately 48.5 million of character
+ 251; 1.0.0/1.0.1 will then die here. */
+ (copyStart[ss] == 0 && copyEnd[ss] == nblock-1),
+ 1007 )
+
+ for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK;
+
+ /*--
+ Step 3:
+ The [ss] big bucket is now done. Record this fact,
+ and update the quadrant descriptors. Remember to
+ update quadrants in the overshoot area too, if
+ necessary. The "if (i < 255)" test merely skips
+ this updating for the last bucket processed, since
+ updating for the last bucket is pointless.
+
+ The quadrant array provides a way to incrementally
+ cache sort orderings, as they appear, so as to
+ make subsequent comparisons in fullGtU() complete
+ faster. For repetitive blocks this makes a big
+ difference (but not big enough to be able to avoid
+ the fallback sorting mechanism, exponential radix sort).
+
+ The precise meaning is: at all times:
+
+ for 0 <= i < nblock and 0 <= j <= nblock
+
+ if block[i] != block[j],
+
+ then the relative values of quadrant[i] and
+ quadrant[j] are meaningless.
+
+ else {
+ if quadrant[i] < quadrant[j]
+ then the string starting at i lexicographically
+ precedes the string starting at j
+
+ else if quadrant[i] > quadrant[j]
+ then the string starting at j lexicographically
+ precedes the string starting at i
+
+ else
+ the relative ordering of the strings starting
+ at i and j has not yet been determined.
+ }
+ --*/
+ bigDone[ss] = True;
+
+ if (i < 255) {
+ Int32 bbStart = ftab[ss << 8] & CLEARMASK;
+ Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+ Int32 shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) shifts++;
+
+ for (j = bbSize-1; j >= 0; j--) {
+ Int32 a2update = ptr[bbStart + j];
+ UInt16 qVal = (UInt16)(j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZ_N_OVERSHOOT)
+ quadrant[a2update + nblock] = qVal;
+ }
+ AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 );
+ }
+
+ }
+
+ if (verb >= 4)
+ VPrintf3 ( " %d pointers, %d sorted, %d scanned\n",
+ nblock, numQSorted, nblock - numQSorted );
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > 0
+ arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ ((UChar*)arr2) [0 .. nblock-1] holds block
+ arr1 exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)arr2) [0 .. nblock-1] holds block
+ All other areas of block destroyed
+ ftab [ 0 .. 65536 ] destroyed
+ arr1 [0 .. nblock-1] holds sorted order
+*/
+void BZ2_blockSort ( EState* s )
+{
+ UInt32* ptr = s->ptr;
+ UChar* block = s->block;
+ UInt32* ftab = s->ftab;
+ Int32 nblock = s->nblock;
+ Int32 verb = s->verbosity;
+ Int32 wfact = s->workFactor;
+ UInt16* quadrant;
+ Int32 budget;
+ Int32 budgetInit;
+ Int32 i;
+
+ if (nblock < 10000) {
+ fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+ } else {
+ /* Calculate the location for quadrant, remembering to get
+ the alignment right. Assumes that &(block[0]) is at least
+ 2-byte aligned -- this should be ok since block is really
+ the first section of arr2.
+ */
+ i = nblock+BZ_N_OVERSHOOT;
+ if (i & 1) i++;
+ quadrant = (UInt16*)(&(block[i]));
+
+ /* (wfact-1) / 3 puts the default-factor-30
+ transition point at very roughly the same place as
+ with v0.1 and v0.9.0.
+ Not that it particularly matters any more, since the
+ resulting compressed stream is now the same regardless
+ of whether or not we use the main sort or fallback sort.
+ */
+ if (wfact < 1 ) wfact = 1;
+ if (wfact > 100) wfact = 100;
+ budgetInit = nblock * ((wfact-1) / 3);
+ budget = budgetInit;
+
+ mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget );
+ if (verb >= 3)
+ VPrintf3 ( " %d work, %d block, ratio %5.2f\n",
+ budgetInit - budget,
+ nblock,
+ (float)(budgetInit - budget) /
+ (float)(nblock==0 ? 1 : nblock) );
+ if (budget < 0) {
+ if (verb >= 2)
+ VPrintf0 ( " too repetitive; using fallback"
+ " sorting algorithm\n" );
+ fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+ }
+ }
+
+ s->origPtr = -1;
+ for (i = 0; i < s->nblock; i++)
+ if (ptr[i] == 0)
+ { s->origPtr = i; break; };
+
+ AssertH( s->origPtr != -1, 1003 );
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/lib/bzip2/bzlib_compress.c b/lib/bzip2/bzlib_compress.c
new file mode 100644
index 0000000000..c8da1c72e9
--- /dev/null
+++ b/lib/bzip2/bzlib_compress.c
@@ -0,0 +1,714 @@
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting) ---*/
+/*--- compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/*--
+ This file is a part of bzip2 and/or libbzip2, a program and
+ library for lossless, block-sorting data compression.
+
+ Copyright (C) 1996-2002 Julian R Seward. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Julian Seward, Cambridge, UK.
+ jseward@acm.org
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ This program is based on (at least) the work of:
+ Mike Burrows
+ David Wheeler
+ Peter Fenwick
+ Alistair Moffat
+ Radford Neal
+ Ian H. Witten
+ Robert Sedgewick
+ Jon L. Bentley
+
+ For more information on these sources, see the manual.
+--*/
+
+/* CHANGES
+ 0.9.0 -- original version.
+ 0.9.0a/b -- no changes in this file.
+ 0.9.0c -- changed setting of nGroups in sendMTFValues()
+ so as to do a bit better on small files
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+void BZ2_bsInitWrite ( EState* s )
+{
+ s->bsLive = 0;
+ s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsFinishWrite ( EState* s )
+{
+ while (s->bsLive > 0) {
+ s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
+ s->numZ++;
+ s->bsBuff <<= 8;
+ s->bsLive -= 8;
+ }
+}
+
+
+/*---------------------------------------------------*/
+#define bsNEEDW(nz) \
+{ \
+ while (s->bsLive >= 8) { \
+ s->zbits[s->numZ] \
+ = (UChar)(s->bsBuff >> 24); \
+ s->numZ++; \
+ s->bsBuff <<= 8; \
+ s->bsLive -= 8; \
+ } \
+}
+
+
+/*---------------------------------------------------*/
+static
+__inline__
+void bsW ( EState* s, Int32 n, UInt32 v )
+{
+ bsNEEDW ( n );
+ s->bsBuff |= (v << (32 - s->bsLive - n));
+ s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUInt32 ( EState* s, UInt32 u )
+{
+ bsW ( s, 8, (u >> 24) & 0xffL );
+ bsW ( s, 8, (u >> 16) & 0xffL );
+ bsW ( s, 8, (u >> 8) & 0xffL );
+ bsW ( s, 8, u & 0xffL );
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUChar ( EState* s, UChar c )
+{
+ bsW( s, 8, (UInt32)c );
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e ( EState* s )
+{
+ Int32 i;
+ s->nInUse = 0;
+ for (i = 0; i < 256; i++)
+ if (s->inUse[i]) {
+ s->unseqToSeq[i] = s->nInUse;
+ s->nInUse++;
+ }
+}
+
+
+/*---------------------------------------------------*/
+static
+void generateMTFValues ( EState* s )
+{
+ UChar yy[256];
+ Int32 i, j;
+ Int32 zPend;
+ Int32 wr;
+ Int32 EOB;
+
+ /*
+ After sorting (eg, here),
+ s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
+ and
+ ((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
+ holds the original block data.
+
+ The first thing to do is generate the MTF values,
+ and put them in
+ ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
+ Because there are strictly fewer or equal MTF values
+ than block values, ptr values in this area are overwritten
+ with MTF values only when they are no longer needed.
+
+ The final compressed bitstream is generated into the
+ area starting at
+ (UChar*) (&((UChar*)s->arr2)[s->nblock])
+
+ These storage aliases are set up in bzCompressInit(),
+ except for the last one, which is arranged in
+ compressBlock().
+ */
+ UInt32* ptr = s->ptr;
+ UChar* block = s->block;
+ UInt16* mtfv = s->mtfv;
+
+ makeMaps_e ( s );
+ EOB = s->nInUse+1;
+
+ for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
+
+ wr = 0;
+ zPend = 0;
+ for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
+
+ for (i = 0; i < s->nblock; i++) {
+ UChar ll_i;
+ AssertD ( wr <= i, "generateMTFValues(1)" );
+ j = ptr[i]-1; if (j < 0) j += s->nblock;
+ ll_i = s->unseqToSeq[block[j]];
+ AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
+
+ if (yy[0] == ll_i) {
+ zPend++;
+ } else {
+
+ if (zPend > 0) {
+ zPend--;
+ while (True) {
+ if (zPend & 1) {
+ mtfv[wr] = BZ_RUNB; wr++;
+ s->mtfFreq[BZ_RUNB]++;
+ } else {
+ mtfv[wr] = BZ_RUNA; wr++;
+ s->mtfFreq[BZ_RUNA]++;
+ }
+ if (zPend < 2) break;
+ zPend = (zPend - 2) / 2;
+ };
+ zPend = 0;
+ }
+ {
+ register UChar rtmp;
+ register UChar* ryy_j;
+ register UChar rll_i;
+ rtmp = yy[1];
+ yy[1] = yy[0];
+ ryy_j = &(yy[1]);
+ rll_i = ll_i;
+ while ( rll_i != rtmp ) {
+ register UChar rtmp2;
+ ryy_j++;
+ rtmp2 = rtmp;
+ rtmp = *ryy_j;
+ *ryy_j = rtmp2;
+ };
+ yy[0] = rtmp;
+ j = ryy_j - &(yy[0]);
+ mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
+ }
+
+ }
+ }
+
+ if (zPend > 0) {
+ zPend--;
+ while (True) {
+ if (zPend & 1) {
+ mtfv[wr] = BZ_RUNB; wr++;
+ s->mtfFreq[BZ_RUNB]++;
+ } else {
+ mtfv[wr] = BZ_RUNA; wr++;
+ s->mtfFreq[BZ_RUNA]++;
+ }
+ if (zPend < 2) break;
+ zPend = (zPend - 2) / 2;
+ };
+ zPend = 0;
+ }
+
+ mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
+
+ s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST 0
+#define BZ_GREATER_ICOST 15
+
+static
+void sendMTFValues ( EState* s )
+{
+ Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
+ Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
+ Int32 nGroups, nBytes;
+
+ /*--
+ UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ is a global since the decoder also needs it.
+
+ Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ are also globals only used in this proc.
+ Made global to keep stack frame size small.
+ --*/
+
+
+ UInt16 cost[BZ_N_GROUPS];
+ Int32 fave[BZ_N_GROUPS];
+
+ UInt16* mtfv = s->mtfv;
+
+ if (s->verbosity >= 3)
+ VPrintf3( " %d in block, %d after MTF & 1-2 coding, "
+ "%d+2 syms in use\n",
+ s->nblock, s->nMTF, s->nInUse );
+
+ alphaSize = s->nInUse+2;
+ for (t = 0; t < BZ_N_GROUPS; t++)
+ for (v = 0; v < alphaSize; v++)
+ s->len[t][v] = BZ_GREATER_ICOST;
+
+ /*--- Decide how many coding tables to use ---*/
+ AssertH ( s->nMTF > 0, 3001 );
+ if (s->nMTF < 200) nGroups = 2; else
+ if (s->nMTF < 600) nGroups = 3; else
+ if (s->nMTF < 1200) nGroups = 4; else
+ if (s->nMTF < 2400) nGroups = 5; else
+ nGroups = 6;
+
+ /*--- Generate an initial set of coding tables ---*/
+ {
+ Int32 nPart, remF, tFreq, aFreq;
+
+ nPart = nGroups;
+ remF = s->nMTF;
+ gs = 0;
+ while (nPart > 0) {
+ tFreq = remF / nPart;
+ ge = gs-1;
+ aFreq = 0;
+ while (aFreq < tFreq && ge < alphaSize-1) {
+ ge++;
+ aFreq += s->mtfFreq[ge];
+ }
+
+ if (ge > gs
+ && nPart != nGroups && nPart != 1
+ && ((nGroups-nPart) % 2 == 1)) {
+ aFreq -= s->mtfFreq[ge];
+ ge--;
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf5( " initial group %d, [%d .. %d], "
+ "has %d syms (%4.1f%%)\n",
+ nPart, gs, ge, aFreq,
+ (100.0 * (float)aFreq) / (float)(s->nMTF) );
+
+ for (v = 0; v < alphaSize; v++)
+ if (v >= gs && v <= ge)
+ s->len[nPart-1][v] = BZ_LESSER_ICOST; else
+ s->len[nPart-1][v] = BZ_GREATER_ICOST;
+
+ nPart--;
+ gs = ge+1;
+ remF -= aFreq;
+ }
+ }
+
+ /*---
+ Iterate up to BZ_N_ITERS times to improve the tables.
+ ---*/
+ for (iter = 0; iter < BZ_N_ITERS; iter++) {
+
+ for (t = 0; t < nGroups; t++) fave[t] = 0;
+
+ for (t = 0; t < nGroups; t++)
+ for (v = 0; v < alphaSize; v++)
+ s->rfreq[t][v] = 0;
+
+ /*---
+ Set up an auxiliary length table which is used to fast-track
+ the common case (nGroups == 6).
+ ---*/
+ if (nGroups == 6) {
+ for (v = 0; v < alphaSize; v++) {
+ s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+ s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+ s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+ }
+ }
+
+ nSelectors = 0;
+ totc = 0;
+ gs = 0;
+ while (True) {
+
+ /*--- Set group start & end marks. --*/
+ if (gs >= s->nMTF) break;
+ ge = gs + BZ_G_SIZE - 1;
+ if (ge >= s->nMTF) ge = s->nMTF-1;
+
+ /*--
+ Calculate the cost of this group as coded
+ by each of the coding tables.
+ --*/
+ for (t = 0; t < nGroups; t++) cost[t] = 0;
+
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+ register UInt32 cost01, cost23, cost45;
+ register UInt16 icv;
+ cost01 = cost23 = cost45 = 0;
+
+# define BZ_ITER(nn) \
+ icv = mtfv[gs+(nn)]; \
+ cost01 += s->len_pack[icv][0]; \
+ cost23 += s->len_pack[icv][1]; \
+ cost45 += s->len_pack[icv][2]; \
+
+ BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
+ BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
+ BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+ BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+ BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+ BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+ BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+ BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+ BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+ BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+
+# undef BZ_ITER
+
+ cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+ cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+ cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++) {
+ UInt16 icv = mtfv[i];
+ for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
+ }
+ }
+
+ /*--
+ Find the coding table which is best for this group,
+ and record its identity in the selector table.
+ --*/
+ bc = 999999999; bt = -1;
+ for (t = 0; t < nGroups; t++)
+ if (cost[t] < bc) { bc = cost[t]; bt = t; };
+ totc += bc;
+ fave[bt]++;
+ s->selector[nSelectors] = bt;
+ nSelectors++;
+
+ /*--
+ Increment the symbol frequencies for the selected table.
+ --*/
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+
+# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
+
+ BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
+ BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
+ BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+ BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+ BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+ BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+ BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+ BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+ BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+ BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+
+# undef BZ_ITUR
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++)
+ s->rfreq[bt][ mtfv[i] ]++;
+ }
+
+ gs = ge+1;
+ }
+ if (s->verbosity >= 3) {
+ VPrintf2 ( " pass %d: size is %d, grp uses are ",
+ iter+1, totc/8 );
+ for (t = 0; t < nGroups; t++)
+ VPrintf1 ( "%d ", fave[t] );
+ VPrintf0 ( "\n" );
+ }
+
+ /*--
+ Recompute the tables based on the accumulated frequencies.
+ --*/
+ /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
+ comment in huffman.c for details. */
+ for (t = 0; t < nGroups; t++)
+ BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]),
+ alphaSize, 17 /*20*/ );
+ }
+
+
+ AssertH( nGroups < 8, 3002 );
+ AssertH( nSelectors < 32768 &&
+ nSelectors <= (2 + (900000 / BZ_G_SIZE)),
+ 3003 );
+
+
+ /*--- Compute MTF values for the selectors. ---*/
+ {
+ UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+ for (i = 0; i < nGroups; i++) pos[i] = i;
+ for (i = 0; i < nSelectors; i++) {
+ ll_i = s->selector[i];
+ j = 0;
+ tmp = pos[j];
+ while ( ll_i != tmp ) {
+ j++;
+ tmp2 = tmp;
+ tmp = pos[j];
+ pos[j] = tmp2;
+ };
+ pos[0] = tmp;
+ s->selectorMtf[i] = j;
+ }
+ };
+
+ /*--- Assign actual codes for the tables. --*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+ if (s->len[t][i] < minLen) minLen = s->len[t][i];
+ }
+ AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
+ AssertH ( !(minLen < 1), 3005 );
+ BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]),
+ minLen, maxLen, alphaSize );
+ }
+
+ /*--- Transmit the mapping table. ---*/
+ {
+ Bool inUse16[16];
+ for (i = 0; i < 16; i++) {
+ inUse16[i] = False;
+ for (j = 0; j < 16; j++)
+ if (s->inUse[i * 16 + j]) inUse16[i] = True;
+ }
+
+ nBytes = s->numZ;
+ for (i = 0; i < 16; i++)
+ if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
+
+ for (i = 0; i < 16; i++)
+ if (inUse16[i])
+ for (j = 0; j < 16; j++) {
+ if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes );
+ }
+
+ /*--- Now the selectors. ---*/
+ nBytes = s->numZ;
+ bsW ( s, 3, nGroups );
+ bsW ( s, 15, nSelectors );
+ for (i = 0; i < nSelectors; i++) {
+ for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
+ bsW(s,1,0);
+ }
+ if (s->verbosity >= 3)
+ VPrintf1( "selectors %d, ", s->numZ-nBytes );
+
+ /*--- Now the coding tables. ---*/
+ nBytes = s->numZ;
+
+ for (t = 0; t < nGroups; t++) {
+ Int32 curr = s->len[t][0];
+ bsW ( s, 5, curr );
+ for (i = 0; i < alphaSize; i++) {
+ while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
+ while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
+ bsW ( s, 1, 0 );
+ }
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
+
+ /*--- And finally, the block data proper ---*/
+ nBytes = s->numZ;
+ selCtr = 0;
+ gs = 0;
+ while (True) {
+ if (gs >= s->nMTF) break;
+ ge = gs + BZ_G_SIZE - 1;
+ if (ge >= s->nMTF) ge = s->nMTF-1;
+ AssertH ( s->selector[selCtr] < nGroups, 3006 );
+
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+ UInt16 mtfv_i;
+ UChar* s_len_sel_selCtr
+ = &(s->len[s->selector[selCtr]][0]);
+ Int32* s_code_sel_selCtr
+ = &(s->code[s->selector[selCtr]][0]);
+
+# define BZ_ITAH(nn) \
+ mtfv_i = mtfv[gs+(nn)]; \
+ bsW ( s, \
+ s_len_sel_selCtr[mtfv_i], \
+ s_code_sel_selCtr[mtfv_i] )
+
+ BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
+ BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
+ BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+ BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+ BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+ BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+ BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+ BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+ BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+ BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+
+# undef BZ_ITAH
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++) {
+ bsW ( s,
+ s->len [s->selector[selCtr]] [mtfv[i]],
+ s->code [s->selector[selCtr]] [mtfv[i]] );
+ }
+ }
+
+
+ gs = ge+1;
+ selCtr++;
+ }
+ AssertH( selCtr == nSelectors, 3007 );
+
+ if (s->verbosity >= 3)
+ VPrintf1( "codes %d\n", s->numZ-nBytes );
+ else /* squash compiler 'used but not set' warning */
+ nBytes = nBytes;
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_compressBlock ( EState* s, Bool is_last_block )
+{
+ if (s->nblock > 0) {
+
+ BZ_FINALISE_CRC ( s->blockCRC );
+ s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+ s->combinedCRC ^= s->blockCRC;
+ if (s->blockNo > 1) s->numZ = 0;
+
+ if (s->verbosity >= 2)
+ VPrintf4( " block %d: crc = 0x%08x, "
+ "combined CRC = 0x%08x, size = %d\n",
+ s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
+
+ BZ2_blockSort ( s );
+ }
+
+ s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
+
+ /*-- If this is the first block, create the stream header. --*/
+ if (s->blockNo == 1) {
+ BZ2_bsInitWrite ( s );
+ bsPutUChar ( s, BZ_HDR_B );
+ bsPutUChar ( s, BZ_HDR_Z );
+ bsPutUChar ( s, BZ_HDR_h );
+ bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
+ }
+
+ if (s->nblock > 0) {
+
+ bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
+ bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
+ bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
+
+ /*-- Now the block's CRC, so it is in a known place. --*/
+ bsPutUInt32 ( s, s->blockCRC );
+
+ /*--
+ Now a single bit indicating (non-)randomisation.
+ As of version 0.9.5, we use a better sorting algorithm
+ which makes randomisation unnecessary. So always set
+ the randomised bit to 'no'. Of course, the decoder
+ still needs to be able to handle randomised blocks
+ so as to maintain backwards compatibility with
+ older versions of bzip2.
+ --*/
+ bsW(s,1,0);
+
+ bsW ( s, 24, s->origPtr );
+ generateMTFValues ( s );
+ sendMTFValues ( s );
+ }
+
+
+ /*-- If this is the last block, add the stream trailer. --*/
+ if (is_last_block) {
+
+ bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
+ bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
+ bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
+ bsPutUInt32 ( s, s->combinedCRC );
+ if (s->verbosity >= 2)
+ VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC );
+ bsFinishWrite ( s );
+ }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index b50d105161..d56e1b11f0 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -56,7 +56,6 @@ static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
- COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"),
COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
COMPAT(INTEL_MICROCODE, "intel,microcode"),
COMPAT(MEMORY_SPD, "memory-spd"),
diff --git a/lib/time.c b/lib/time.c
index f37a6628d6..e9f6861b98 100644
--- a/lib/time.c
+++ b/lib/time.c
@@ -41,23 +41,6 @@ extern unsigned long __weak timer_read_counter(void);
#endif
#ifdef CONFIG_TIMER
-static int notrace dm_timer_init(void)
-{
- struct udevice *dev;
- int ret;
-
- if (!gd->timer) {
- ret = uclass_first_device(UCLASS_TIMER, &dev);
- if (ret)
- return ret;
- if (!dev)
- return -ENODEV;
- gd->timer = dev;
- }
-
- return 0;
-}
-
ulong notrace get_tbclk(void)
{
int ret;
diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c
index 403b134cd1..a06abed495 100644
--- a/lib/tiny-printf.c
+++ b/lib/tiny-printf.c
@@ -82,13 +82,21 @@ int vprintf(const char *fmt, va_list va)
num = -(int)num;
out('-');
}
- for (div = 1000000000; div; div /= 10)
- div_out(&num, div);
+ if (!num) {
+ out_dgt(0);
+ } else {
+ for (div = 1000000000; div; div /= 10)
+ div_out(&num, div);
+ }
break;
case 'x':
num = va_arg(va, unsigned int);
- for (div = 0x10000000; div; div /= 0x10)
- div_out(&num, div);
+ if (!num) {
+ out_dgt(0);
+ } else {
+ for (div = 0x10000000; div; div /= 0x10)
+ div_out(&num, div);
+ }
break;
case 'c':
out((char)(va_arg(va, int)));
@@ -108,8 +116,10 @@ int vprintf(const char *fmt, va_list va)
w--;
while (w-- > 0)
putc(lz ? '0' : ' ');
- while ((ch = *p++))
- putc(ch);
+ if (p) {
+ while ((ch = *p++))
+ putc(ch);
+ }
}
}
diff --git a/test/cmd_repeat.sh b/test/cmd_repeat.sh
deleted file mode 100755
index 990e79900f..0000000000
--- a/test/cmd_repeat.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-
-# Test for U-Boot cli including command repeat
-
-BASE="$(dirname $0)"
-. $BASE/common.sh
-
-run_test() {
- ./${OUTPUT_DIR}/u-boot <<END
-setenv ctrlc_ignore y
-md 0
-
-reset
-END
-}
-check_results() {
- echo "Check results"
-
- grep -q 00000100 ${tmp} || fail "Command did not repeat"
-}
-
-echo "Test CLI repeat"
-echo
-tmp="$(tempfile)"
-build_uboot
-run_test >${tmp}
-check_results ${tmp}
-rm ${tmp}
-echo "Test passed"
diff --git a/test/command_ut.c b/test/command_ut.c
index 926573a395..54bf62b9bc 100644
--- a/test/command_ut.c
+++ b/test/command_ut.c
@@ -7,9 +7,6 @@
#define DEBUG
#include <common.h>
-#ifdef CONFIG_SANDBOX
-#include <os.h>
-#endif
static const char test_cmd[] = "setenv list 1\n setenv list ${list}2; "
"setenv list ${list}3\0"
@@ -20,21 +17,6 @@ static int do_ut_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
printf("%s: Testing commands\n", __func__);
run_command("env default -f -a", 0);
- /* run a single command */
- run_command("setenv single 1", 0);
- assert(!strcmp("1", getenv("single")));
-
- /* make sure that compound statements work */
-#ifdef CONFIG_SYS_HUSH_PARSER
- run_command("if test -n ${single} ; then setenv check 1; fi", 0);
- assert(!strcmp("1", getenv("check")));
- run_command("setenv check", 0);
-#endif
-
- /* commands separated by ; */
- run_command_list("setenv list 1; setenv list ${list}1", -1, 0);
- assert(!strcmp("11", getenv("list")));
-
/* commands separated by \n */
run_command_list("setenv list 1\n setenv list ${list}1", -1, 0);
assert(!strcmp("11", getenv("list")));
@@ -43,11 +25,6 @@ static int do_ut_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
run_command_list("setenv list 1${list}\n", -1, 0);
assert(!strcmp("111", getenv("list")));
- /* three commands in a row */
- run_command_list("setenv list 1\n setenv list ${list}2; "
- "setenv list ${list}3", -1, 0);
- assert(!strcmp("123", getenv("list")));
-
/* a command string with \0 in it. Stuff after \0 should be ignored */
run_command("setenv list", 0);
run_command_list(test_cmd, sizeof(test_cmd), 0);
@@ -66,13 +43,6 @@ static int do_ut_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
assert(run_command_list("false", -1, 0) == 1);
assert(run_command_list("echo", -1, 0) == 0);
- run_command("setenv foo 'setenv monty 1; setenv python 2'", 0);
- run_command("run foo", 0);
- assert(getenv("monty") != NULL);
- assert(!strcmp("1", getenv("monty")));
- assert(getenv("python") != NULL);
- assert(!strcmp("2", getenv("python")));
-
#ifdef CONFIG_SYS_HUSH_PARSER
run_command("setenv foo 'setenv black 1\nsetenv adder 2'", 0);
run_command("run foo", 0);
@@ -80,112 +50,6 @@ static int do_ut_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
assert(!strcmp("1", getenv("black")));
assert(getenv("adder") != NULL);
assert(!strcmp("2", getenv("adder")));
-
- /* Test the 'test' command */
-
-#define HUSH_TEST(name, expr, expected_result) \
- run_command("if test " expr " ; then " \
- "setenv " #name "_" #expected_result " y; else " \
- "setenv " #name "_" #expected_result " n; fi", 0); \
- assert(!strcmp(#expected_result, getenv(#name "_" #expected_result))); \
- setenv(#name "_" #expected_result, NULL);
-
- /* Basic operators */
- HUSH_TEST(streq, "aaa = aaa", y);
- HUSH_TEST(streq, "aaa = bbb", n);
-
- HUSH_TEST(strneq, "aaa != bbb", y);
- HUSH_TEST(strneq, "aaa != aaa", n);
-
- HUSH_TEST(strlt, "aaa < bbb", y);
- HUSH_TEST(strlt, "bbb < aaa", n);
-
- HUSH_TEST(strgt, "bbb > aaa", y);
- HUSH_TEST(strgt, "aaa > bbb", n);
-
- HUSH_TEST(eq, "123 -eq 123", y);
- HUSH_TEST(eq, "123 -eq 456", n);
-
- HUSH_TEST(ne, "123 -ne 456", y);
- HUSH_TEST(ne, "123 -ne 123", n);
-
- HUSH_TEST(lt, "123 -lt 456", y);
- HUSH_TEST(lt_eq, "123 -lt 123", n);
- HUSH_TEST(lt, "456 -lt 123", n);
-
- HUSH_TEST(le, "123 -le 456", y);
- HUSH_TEST(le_eq, "123 -le 123", y);
- HUSH_TEST(le, "456 -le 123", n);
-
- HUSH_TEST(gt, "456 -gt 123", y);
- HUSH_TEST(gt_eq, "123 -gt 123", n);
- HUSH_TEST(gt, "123 -gt 456", n);
-
- HUSH_TEST(ge, "456 -ge 123", y);
- HUSH_TEST(ge_eq, "123 -ge 123", y);
- HUSH_TEST(ge, "123 -ge 456", n);
-
- HUSH_TEST(z, "-z \"\"", y);
- HUSH_TEST(z, "-z \"aaa\"", n);
-
- HUSH_TEST(n, "-n \"aaa\"", y);
- HUSH_TEST(n, "-n \"\"", n);
-
- /* Inversion of simple tests */
- HUSH_TEST(streq_inv, "! aaa = aaa", n);
- HUSH_TEST(streq_inv, "! aaa = bbb", y);
-
- HUSH_TEST(streq_inv_inv, "! ! aaa = aaa", y);
- HUSH_TEST(streq_inv_inv, "! ! aaa = bbb", n);
-
- /* Binary operators */
- HUSH_TEST(or_0_0, "aaa != aaa -o bbb != bbb", n);
- HUSH_TEST(or_0_1, "aaa != aaa -o bbb = bbb", y);
- HUSH_TEST(or_1_0, "aaa = aaa -o bbb != bbb", y);
- HUSH_TEST(or_1_1, "aaa = aaa -o bbb = bbb", y);
-
- HUSH_TEST(and_0_0, "aaa != aaa -a bbb != bbb", n);
- HUSH_TEST(and_0_1, "aaa != aaa -a bbb = bbb", n);
- HUSH_TEST(and_1_0, "aaa = aaa -a bbb != bbb", n);
- HUSH_TEST(and_1_1, "aaa = aaa -a bbb = bbb", y);
-
- /* Inversion within binary operators */
- HUSH_TEST(or_0_0_inv, "! aaa != aaa -o ! bbb != bbb", y);
- HUSH_TEST(or_0_1_inv, "! aaa != aaa -o ! bbb = bbb", y);
- HUSH_TEST(or_1_0_inv, "! aaa = aaa -o ! bbb != bbb", y);
- HUSH_TEST(or_1_1_inv, "! aaa = aaa -o ! bbb = bbb", n);
-
- HUSH_TEST(or_0_0_inv_inv, "! ! aaa != aaa -o ! ! bbb != bbb", n);
- HUSH_TEST(or_0_1_inv_inv, "! ! aaa != aaa -o ! ! bbb = bbb", y);
- HUSH_TEST(or_1_0_inv_inv, "! ! aaa = aaa -o ! ! bbb != bbb", y);
- HUSH_TEST(or_1_1_inv_inv, "! ! aaa = aaa -o ! ! bbb = bbb", y);
-
- setenv("ut_var_nonexistent", NULL);
- setenv("ut_var_exists", "1");
- HUSH_TEST(z_varexp_quoted, "-z \"$ut_var_nonexistent\"", y);
- HUSH_TEST(z_varexp_quoted, "-z \"$ut_var_exists\"", n);
- setenv("ut_var_exists", NULL);
-
- run_command("setenv ut_var_space \" \"", 0);
- assert(!strcmp(getenv("ut_var_space"), " "));
- run_command("setenv ut_var_test $ut_var_space", 0);
- assert(!getenv("ut_var_test"));
- run_command("setenv ut_var_test \"$ut_var_space\"", 0);
- assert(!strcmp(getenv("ut_var_test"), " "));
- run_command("setenv ut_var_test \" 1${ut_var_space}${ut_var_space} 2 \"", 0);
- assert(!strcmp(getenv("ut_var_test"), " 1 2 "));
- setenv("ut_var_space", NULL);
- setenv("ut_var_test", NULL);
-
-#ifdef CONFIG_SANDBOX
- /* File existence */
- HUSH_TEST(e, "-e hostfs - creating_this_file_breaks_uboot_unit_test", n);
- run_command("sb save hostfs - creating_this_file_breaks_uboot_unit_test 0 1", 0);
- HUSH_TEST(e, "-e hostfs - creating_this_file_breaks_uboot_unit_test", y);
- /* Perhaps this could be replaced by an "rm" shell command one day */
- assert(!os_unlink("creating_this_file_breaks_uboot_unit_test"));
- HUSH_TEST(e, "-e hostfs - creating_this_file_breaks_uboot_unit_test", n);
-#endif
#endif
assert(run_command("", 0) == 0);
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 3ff1b75e6f..d4f3f22e58 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -34,5 +34,6 @@ obj-$(CONFIG_DM_USB) += usb.o
obj-$(CONFIG_DM_PMIC) += pmic.o
obj-$(CONFIG_DM_REGULATOR) += regulator.o
obj-$(CONFIG_TIMER) += timer.o
+obj-$(CONFIG_DM_VIDEO) += video.o
obj-$(CONFIG_ADC) += adc.o
endif
diff --git a/test/dm/video.c b/test/dm/video.c
new file mode 100644
index 0000000000..9f5e7fce37
--- /dev/null
+++ b/test/dm/video.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <bzlib.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <os.h>
+#include <video.h>
+#include <video_console.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <test/ut.h>
+
+/*
+ * These tests use the standard sandbox frame buffer, the resolution of which
+ * is defined in the device tree. This only supports 16bpp so the tests only
+ * test that code path. It would be possible to adjust this fairly easily,
+ * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
+ * in sandbox_sdl_sync() would also need to change to handle the different
+ * surface depth.
+ */
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Basic test of the video uclass */
+static int dm_test_video_base(struct unit_test_state *uts)
+{
+ struct video_priv *priv;
+ struct udevice *dev;
+
+ ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
+ ut_asserteq(1366, video_get_xsize(dev));
+ ut_asserteq(768, video_get_ysize(dev));
+ priv = dev_get_uclass_priv(dev);
+ ut_asserteq(priv->fb_size, 1366 * 768 * 2);
+
+ return 0;
+}
+DM_TEST(dm_test_video_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/**
+ * compress_frame_buffer() - Compress the frame buffer and return its size
+ *
+ * We want to write tests which perform operations on the video console and
+ * check that the frame buffer ends up with the correct contents. But it is
+ * painful to store 'known good' images for comparison with the frame
+ * buffer. As an alternative, we can compress the frame buffer and check the
+ * size of the compressed data. This provides a pretty good level of
+ * certainty and the resulting tests need only check a single value.
+ *
+ * @dev: Video device
+ * @return compressed size of the frame buffer, or -ve on error
+ */
+static int compress_frame_buffer(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+ uint destlen;
+ void *dest;
+ int ret;
+
+ destlen = priv->fb_size;
+ dest = malloc(priv->fb_size);
+ if (!dest)
+ return -ENOMEM;
+ ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
+ priv->fb, priv->fb_size,
+ 3, 0, 0);
+ free(dest);
+ if (ret)
+ return ret;
+
+ return destlen;
+}
+
+/*
+ * Call this function at any point to halt and show the current display. Be
+ * sure to run the test with the -l flag.
+ */
+static void __maybe_unused see_output(void)
+{
+ video_sync_all();
+ while (1);
+}
+
+/* Test text output works on the video console */
+static int dm_test_video_text(struct unit_test_state *uts)
+{
+ struct udevice *dev, *con;
+ int i;
+
+#define WHITE 0xffff
+#define SCROLL_LINES 100
+
+ ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
+ ut_asserteq(46, compress_frame_buffer(dev));
+
+ ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
+ vidconsole_putc_xy(con, 0, 0, 'a');
+ ut_asserteq(79, compress_frame_buffer(dev));
+
+ vidconsole_putc_xy(con, 0, 0, ' ');
+ ut_asserteq(46, compress_frame_buffer(dev));
+
+ for (i = 0; i < 20; i++)
+ vidconsole_putc_xy(con, i * 8, 0, ' ' + i);
+ ut_asserteq(273, compress_frame_buffer(dev));
+
+ vidconsole_set_row(con, 0, WHITE);
+ ut_asserteq(46, compress_frame_buffer(dev));
+
+ for (i = 0; i < 20; i++)
+ vidconsole_putc_xy(con, i * 8, 0, ' ' + i);
+ ut_asserteq(273, compress_frame_buffer(dev));
+
+ return 0;
+}
+DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test handling of special characters in the console */
+static int dm_test_video_chars(struct unit_test_state *uts)
+{
+ struct udevice *dev, *con;
+ const char *test_string = "Well\b\b\b\bxhe is\r \n\ta very modest \bman\n\t\tand Has much to\b\bto be modest about.";
+ const char *s;
+
+ ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
+ ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
+ for (s = test_string; *s; s++)
+ vidconsole_put_char(con, *s);
+ ut_asserteq(466, compress_frame_buffer(dev));
+
+ return 0;
+}
+DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/**
+ * check_vidconsole_output() - Run a text console test
+ *
+ * @uts: Test state
+ * @rot: Console rotation (0, 90, 180, 270)
+ * @wrap_size: Expected size of compressed frame buffer for the wrap test
+ * @scroll_size: Same for the scroll test
+ * @return 0 on success
+ */
+static int check_vidconsole_output(struct unit_test_state *uts, int rot,
+ int wrap_size, int scroll_size)
+{
+ struct udevice *dev, *con;
+ struct sandbox_sdl_plat *plat;
+ int i;
+
+ ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
+ ut_assert(!device_active(dev));
+ plat = dev_get_platdata(dev);
+ plat->rot = rot;
+
+ ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
+ ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
+ ut_asserteq(46, compress_frame_buffer(dev));
+
+ /* Check display wrap */
+ for (i = 0; i < 120; i++)
+ vidconsole_put_char(con, 'A' + i % 50);
+ ut_asserteq(wrap_size, compress_frame_buffer(dev));
+
+ /* Check display scrolling */
+ for (i = 0; i < SCROLL_LINES; i++) {
+ vidconsole_put_char(con, 'A' + i % 50);
+ vidconsole_put_char(con, '\n');
+ }
+ ut_asserteq(scroll_size, compress_frame_buffer(dev));
+
+ /* If we scroll enough, the screen becomes blank again */
+ for (i = 0; i < SCROLL_LINES; i++)
+ vidconsole_put_char(con, '\n');
+ ut_asserteq(46, compress_frame_buffer(dev));
+
+ return 0;
+}
+
+/* Test text output through the console uclass */
+static int dm_test_video_context(struct unit_test_state *uts)
+{
+ return check_vidconsole_output(uts, 0, 788, 453);
+}
+DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test rotated text output through the console uclass */
+static int dm_test_video_rotation1(struct unit_test_state *uts)
+{
+ ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
+
+ return 0;
+}
+DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test rotated text output through the console uclass */
+static int dm_test_video_rotation2(struct unit_test_state *uts)
+{
+ ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
+
+ return 0;
+}
+DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test rotated text output through the console uclass */
+static int dm_test_video_rotation3(struct unit_test_state *uts)
+{
+ ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
+
+ return 0;
+}
+DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Read a file into memory and return a pointer to it */
+static int read_file(struct unit_test_state *uts, const char *fname,
+ ulong *addrp)
+{
+ int buf_size = 100000;
+ ulong addr = 0;
+ int size, fd;
+ char *buf;
+
+ buf = map_sysmem(addr, 0);
+ ut_assert(buf != NULL);
+ fd = os_open(fname, OS_O_RDONLY);
+ ut_assert(fd >= 0);
+ size = os_read(fd, buf, buf_size);
+ ut_assert(size >= 0);
+ ut_assert(size < buf_size);
+ os_close(fd);
+ *addrp = addr;
+
+ return 0;
+}
+
+/* Test drawing a bitmap file */
+static int dm_test_video_bmp(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ ulong addr;
+
+ ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
+ ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
+
+ ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
+ ut_asserteq(1368, compress_frame_buffer(dev));
+
+ return 0;
+}
+DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test drawing a compressed bitmap file */
+static int dm_test_video_bmp_comp(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ ulong addr;
+
+ ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
+ ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
+
+ ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
+ ut_asserteq(1368, compress_frame_buffer(dev));
+
+ return 0;
+}
+DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/py/.gitignore b/test/py/.gitignore
new file mode 100644
index 0000000000..0d20b6487c
--- /dev/null
+++ b/test/py/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/test/py/README.md b/test/py/README.md
new file mode 100644
index 0000000000..8036299d07
--- /dev/null
+++ b/test/py/README.md
@@ -0,0 +1,300 @@
+# U-Boot pytest suite
+
+## Introduction
+
+This tool aims to test U-Boot by executing U-Boot shell commands using the
+console interface. A single top-level script exists to execute or attach to the
+U-Boot console, run the entire script of tests against it, and summarize the
+results. Advantages of this approach are:
+
+- Testing is performed in the same way a user or script would interact with
+ U-Boot; there can be no disconnect.
+- There is no need to write or embed test-related code into U-Boot itself.
+ It is asserted that writing test-related code in Python is simpler and more
+ flexible that writing it all in C.
+- It is reasonably simple to interact with U-Boot in this way.
+
+## Requirements
+
+The test suite is implemented using pytest. Interaction with the U-Boot console
+involves executing some binary and interacting with its stdin/stdout. You will
+need to implement various "hook" scripts that are called by the test suite at
+the appropriate time.
+
+On Debian or Debian-like distributions, the following packages are required.
+Similar package names should exist in other distributions.
+
+| Package | Version tested (Ubuntu 14.04) |
+| -------------- | ----------------------------- |
+| python | 2.7.5-5ubuntu3 |
+| python-pytest | 2.5.1-1 |
+
+The test script supports either:
+
+- Executing a sandbox port of U-Boot on the local machine as a sub-process,
+ and interacting with it over stdin/stdout.
+- Executing an external "hook" scripts to flash a U-Boot binary onto a
+ physical board, attach to the board's console stream, and reset the board.
+ Further details are described later.
+
+### Using `virtualenv` to provide requirements
+
+Older distributions (e.g. Ubuntu 10.04) may not provide all the required
+packages, or may provide versions that are too old to run the test suite. One
+can use the Python `virtualenv` script to locally install more up-to-date
+versions of the required packages without interfering with the OS installation.
+For example:
+
+```bash
+$ cd /path/to/u-boot
+$ sudo apt-get install python python-virtualenv
+$ virtualenv venv
+$ . ./venv/bin/activate
+$ pip install pytest
+```
+
+## Testing sandbox
+
+To run the testsuite on the sandbox port (U-Boot built as a native user-space
+application), simply execute:
+
+```
+./test/py/test.py --bd sandbox --build
+```
+
+The `--bd` option tells the test suite which board type is being tested. This
+lets the test suite know which features the board has, and hence exactly what
+can be tested.
+
+The `--build` option tells U-Boot to compile U-Boot. Alternatively, you may
+omit this option and build U-Boot yourself, in whatever way you choose, before
+running the test script.
+
+The test script will attach to U-Boot, execute all valid tests for the board,
+then print a summary of the test process. A complete log of the test session
+will be written to `${build_dir}/test-log.html`. This is best viewed in a web
+browser, but may be read directly as plain text, perhaps with the aid of the
+`html2text` utility.
+
+## Command-line options
+
+- `--board-type`, `--bd`, `-B` set the type of the board to be tested. For
+ example, `sandbox` or `seaboard`.
+- `--board-identity`, `--id` set the identity of the board to be tested.
+ This allows differentiation between multiple instances of the same type of
+ physical board that are attached to the same host machine. This parameter is
+ not interpreted by the test script in any way, but rather is simply passed
+ to the hook scripts described below, and may be used in any site-specific
+ way deemed necessary.
+- `--build` indicates that the test script should compile U-Boot itself
+ before running the tests. If using this option, make sure that any
+ environment variables required by the build process are already set, such as
+ `$CROSS_COMPILE`.
+- `--build-dir` sets the directory containing the compiled U-Boot binaries.
+ If omitted, this is `${source_dir}/build-${board_type}`.
+- `--result-dir` sets the directory to write results, such as log files,
+ into. If omitted, the build directory is used.
+- `--persistent-data-dir` sets the directory used to store persistent test
+ data. This is test data that may be re-used across test runs, such as file-
+ system images.
+
+`pytest` also implements a number of its own command-line options. Please see
+`pytest` documentation for complete details. Execute `py.test --version` for
+a brief summary. Note that U-Boot's test.py script passes all command-line
+arguments directly to `pytest` for processing.
+
+## Testing real hardware
+
+The tools and techniques used to interact with real hardware will vary
+radically between different host and target systems, and the whims of the user.
+For this reason, the test suite does not attempt to directly interact with real
+hardware in any way. Rather, it executes a standardized set of "hook" scripts
+via `$PATH`. These scripts implement certain actions on behalf of the test
+suite. This keeps the test suite simple and isolated from system variances
+unrelated to U-Boot features.
+
+### Hook scripts
+
+#### Environment variables
+
+The following environment variables are set when running hook scripts:
+
+- `UBOOT_BOARD_TYPE` the board type being tested.
+- `UBOOT_BOARD_IDENTITY` the board identity being tested, or `na` if none was
+ specified.
+- `UBOOT_SOURCE_DIR` the U-Boot source directory.
+- `UBOOT_TEST_PY_DIR` the full path to `test/py/` in the source directory.
+- `UBOOT_BUILD_DIR` the U-Boot build directory.
+- `UBOOT_RESULT_DIR` the test result directory.
+- `UBOOT_PERSISTENT_DATA_DIR` the test peristent data directory.
+
+#### `u-boot-test-console`
+
+This script provides access to the U-Boot console. The script's stdin/stdout
+should be connected to the board's console. This process should continue to run
+indefinitely, until killed. The test suite will run this script in parallel
+with all other hooks.
+
+This script may be implemented e.g. by exec()ing `cu`, `kermit`, `conmux`, etc.
+
+If you are able to run U-Boot under a hardware simulator such as qemu, then
+you would likely spawn that simulator from this script. However, note that
+`u-boot-test-reset` may be called multiple times per test script run, and must
+cause U-Boot to start execution from scratch each time. Hopefully your
+simulator includes a virtual reset button! If not, you can launch the
+simulator from `u-boot-test-reset` instead, while arranging for this console
+process to always communicate with the current simulator instance.
+
+#### `u-boot-test-flash`
+
+Prior to running the test suite against a board, some arrangement must be made
+so that the board executes the particular U-Boot binary to be tested. Often,
+this involves writing the U-Boot binary to the board's flash ROM. The test
+suite calls this hook script for that purpose.
+
+This script should perform the entire flashing process synchronously; the
+script should only exit once flashing is complete, and a board reset will
+cause the newly flashed U-Boot binary to be executed.
+
+It is conceivable that this script will do nothing. This might be useful in
+the following cases:
+
+- Some other process has already written the desired U-Boot binary into the
+ board's flash prior to running the test suite.
+- The board allows U-Boot to be downloaded directly into RAM, and executed
+ from there. Use of this feature will reduce wear on the board's flash, so
+ may be preferable if available, and if cold boot testing of U-Boot is not
+ required. If this feature is used, the `u-boot-test-reset` script should
+ peform this download, since the board could conceivably be reset multiple
+ times in a single test run.
+
+It is up to the user to determine if those situations exist, and to code this
+hook script appropriately.
+
+This script will typically be implemented by calling out to some SoC- or
+board-specific vendor flashing utility.
+
+#### `u-boot-test-reset`
+
+Whenever the test suite needs to reset the target board, this script is
+executed. This is guaranteed to happen at least once, prior to executing the
+first test function. If any test fails, the test infra-structure will execute
+this script again to restore U-Boot to an operational state before running the
+next test function.
+
+This script will likely be implemented by communicating with some form of
+relay or electronic switch attached to the board's reset signal.
+
+The semantics of this script require that when it is executed, U-Boot will
+start running from scratch. If the U-Boot binary to be tested has been written
+to flash, pulsing the board's reset signal is likely all this script need do.
+However, in some scenarios, this script may perform other actions. For
+example, it may call out to some SoC- or board-specific vendor utility in order
+to download the U-Boot binary directly into RAM and execute it. This would
+avoid the need for `u-boot-test-flash` to actually write U-Boot to flash, thus
+saving wear on the flash chip(s).
+
+### Board-type-specific configuration
+
+Each board has a different configuration and behaviour. Many of these
+differences can be automatically detected by parsing the `.config` file in the
+build directory. However, some differences can't yet be handled automatically.
+
+For each board, an optional Python module `u_boot_board_${board_type}` may exist
+to provide board-specific information to the test script. Any global value
+defined in these modules is available for use by any test function. The data
+contained in these scripts must be purely derived from U-Boot source code.
+Hence, these configuration files are part of the U-Boot source tree too.
+
+### Execution environment configuration
+
+Each user's hardware setup may enable testing different subsets of the features
+implemented by a particular board's configuration of U-Boot. For example, a
+U-Boot configuration may support USB device mode and USB Mass Storage, but this
+can only be tested if a USB cable is connected between the board and the host
+machine running the test script.
+
+For each board, optional Python modules `u_boot_boardenv_${board_type}` and
+`u_boot_boardenv_${board_type}_${board_identity}` may exist to provide
+board-specific and board-identity-specific information to the test script. Any
+global value defined in these modules is available for use by any test
+function. The data contained in these is specific to a particular user's
+hardware configuration. Hence, these configuration files are not part of the
+U-Boot source tree, and should be installed outside of the source tree. Users
+should set `$PYTHONPATH` prior to running the test script to allow these
+modules to be loaded.
+
+### Board module parameter usage
+
+The test scripts rely on the following variables being defined by the board
+module:
+
+- None at present.
+
+### U-Boot `.config` feature usage
+
+The test scripts rely on various U-Boot `.config` features, either directly in
+order to test those features, or indirectly in order to query information from
+the running U-Boot instance in order to test other features.
+
+One example is that testing of the `md` command requires knowledge of a RAM
+address to use for the test. This data is parsed from the output of the
+`bdinfo` command, and hence relies on CONFIG_CMD_BDI being enabled.
+
+For a complete list of dependencies, please search the test scripts for
+instances of:
+
+- `buildconfig.get(...`
+- `@pytest.mark.buildconfigspec(...`
+
+### Complete invocation example
+
+Assuming that you have installed the hook scripts into $HOME/ubtest/bin, and
+any required environment configuration Python modules into $HOME/ubtest/py,
+then you would likely invoke the test script as follows:
+
+If U-Boot has already been built:
+
+```bash
+PATH=$HOME/ubtest/bin:$PATH \
+ PYTHONPATH=${HOME}/ubtest/py:${PYTHONPATH} \
+ ./test/py/test.py --bd seaboard
+```
+
+If you want the test script to compile U-Boot for you too, then you likely
+need to set `$CROSS_COMPILE` to allow this, and invoke the test script as
+follow:
+
+```bash
+CROSS_COMPILE=arm-none-eabi- \
+ PATH=$HOME/ubtest/bin:$PATH \
+ PYTHONPATH=${HOME}/ubtest/py:${PYTHONPATH} \
+ ./test/py/test.py --bd seaboard --build
+```
+
+## Writing tests
+
+Please refer to the pytest documentation for details of writing pytest tests.
+Details specific to the U-Boot test suite are described below.
+
+A test fixture named `u_boot_console` should be used by each test function. This
+provides the means to interact with the U-Boot console, and retrieve board and
+environment configuration information.
+
+The function `u_boot_console.run_command()` executes a shell command on the
+U-Boot console, and returns all output from that command. This allows
+validation or interpretation of the command output. This function validates
+that certain strings are not seen on the U-Boot console. These include shell
+error messages and the U-Boot sign-on message (in order to detect unexpected
+board resets). See the source of `u_boot_console_base.py` for a complete list of
+"bad" strings. Some test scenarios are expected to trigger these strings. Use
+`u_boot_console.disable_check()` to temporarily disable checking for specific
+strings. See `test_unknown_cmd.py` for an example.
+
+Board- and board-environment configuration values may be accessed as sub-fields
+of the `u_boot_console.config` object, for example
+`u_boot_console.config.ram_base`.
+
+Build configuration values (from `.config`) may be accessed via the dictionary
+`u_boot_console.config.buildconfig`, with keys equal to the Kconfig variable
+names.
diff --git a/test/py/conftest.py b/test/py/conftest.py
new file mode 100644
index 0000000000..e1674dfce0
--- /dev/null
+++ b/test/py/conftest.py
@@ -0,0 +1,422 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Implementation of pytest run-time hook functions. These are invoked by
+# pytest at certain points during operation, e.g. startup, for each executed
+# test, at shutdown etc. These hooks perform functions such as:
+# - Parsing custom command-line options.
+# - Pullilng in user-specified board configuration.
+# - Creating the U-Boot console test fixture.
+# - Creating the HTML log file.
+# - Monitoring each test's results.
+# - Implementing custom pytest markers.
+
+import atexit
+import errno
+import os
+import os.path
+import pexpect
+import pytest
+from _pytest.runner import runtestprotocol
+import ConfigParser
+import StringIO
+import sys
+
+# Globals: The HTML log file, and the connection to the U-Boot console.
+log = None
+console = None
+
+def mkdir_p(path):
+ '''Create a directory path.
+
+ This includes creating any intermediate/parent directories. Any errors
+ caused due to already extant directories are ignored.
+
+ Args:
+ path: The directory path to create.
+
+ Returns:
+ Nothing.
+ '''
+
+ try:
+ os.makedirs(path)
+ except OSError as exc:
+ if exc.errno == errno.EEXIST and os.path.isdir(path):
+ pass
+ else:
+ raise
+
+def pytest_addoption(parser):
+ '''pytest hook: Add custom command-line options to the cmdline parser.
+
+ Args:
+ parser: The pytest command-line parser.
+
+ Returns:
+ Nothing.
+ '''
+
+ parser.addoption('--build-dir', default=None,
+ help='U-Boot build directory (O=)')
+ parser.addoption('--result-dir', default=None,
+ help='U-Boot test result/tmp directory')
+ parser.addoption('--persistent-data-dir', default=None,
+ help='U-Boot test persistent generated data directory')
+ parser.addoption('--board-type', '--bd', '-B', default='sandbox',
+ help='U-Boot board type')
+ parser.addoption('--board-identity', '--id', default='na',
+ help='U-Boot board identity/instance')
+ parser.addoption('--build', default=False, action='store_true',
+ help='Compile U-Boot before running tests')
+
+def pytest_configure(config):
+ '''pytest hook: Perform custom initialization at startup time.
+
+ Args:
+ config: The pytest configuration.
+
+ Returns:
+ Nothing.
+ '''
+
+ global log
+ global console
+ global ubconfig
+
+ test_py_dir = os.path.dirname(os.path.abspath(__file__))
+ source_dir = os.path.dirname(os.path.dirname(test_py_dir))
+
+ board_type = config.getoption('board_type')
+ board_type_filename = board_type.replace('-', '_')
+
+ board_identity = config.getoption('board_identity')
+ board_identity_filename = board_identity.replace('-', '_')
+
+ build_dir = config.getoption('build_dir')
+ if not build_dir:
+ build_dir = source_dir + '/build-' + board_type
+ mkdir_p(build_dir)
+
+ result_dir = config.getoption('result_dir')
+ if not result_dir:
+ result_dir = build_dir
+ mkdir_p(result_dir)
+
+ persistent_data_dir = config.getoption('persistent_data_dir')
+ if not persistent_data_dir:
+ persistent_data_dir = build_dir + '/persistent-data'
+ mkdir_p(persistent_data_dir)
+
+ import multiplexed_log
+ log = multiplexed_log.Logfile(result_dir + '/test-log.html')
+
+ if config.getoption('build'):
+ if build_dir != source_dir:
+ o_opt = 'O=%s' % build_dir
+ else:
+ o_opt = ''
+ cmds = (
+ ['make', o_opt, '-s', board_type + '_defconfig'],
+ ['make', o_opt, '-s', '-j8'],
+ )
+ runner = log.get_runner('make', sys.stdout)
+ for cmd in cmds:
+ runner.run(cmd, cwd=source_dir)
+ runner.close()
+
+ class ArbitraryAttributeContainer(object):
+ pass
+
+ ubconfig = ArbitraryAttributeContainer()
+ ubconfig.brd = dict()
+ ubconfig.env = dict()
+
+ modules = [
+ (ubconfig.brd, 'u_boot_board_' + board_type_filename),
+ (ubconfig.env, 'u_boot_boardenv_' + board_type_filename),
+ (ubconfig.env, 'u_boot_boardenv_' + board_type_filename + '_' +
+ board_identity_filename),
+ ]
+ for (dict_to_fill, module_name) in modules:
+ try:
+ module = __import__(module_name)
+ except ImportError:
+ continue
+ dict_to_fill.update(module.__dict__)
+
+ ubconfig.buildconfig = dict()
+
+ for conf_file in ('.config', 'include/autoconf.mk'):
+ dot_config = build_dir + '/' + conf_file
+ if not os.path.exists(dot_config):
+ raise Exception(conf_file + ' does not exist; ' +
+ 'try passing --build option?')
+
+ with open(dot_config, 'rt') as f:
+ ini_str = '[root]\n' + f.read()
+ ini_sio = StringIO.StringIO(ini_str)
+ parser = ConfigParser.RawConfigParser()
+ parser.readfp(ini_sio)
+ ubconfig.buildconfig.update(parser.items('root'))
+
+ ubconfig.test_py_dir = test_py_dir
+ ubconfig.source_dir = source_dir
+ ubconfig.build_dir = build_dir
+ ubconfig.result_dir = result_dir
+ ubconfig.persistent_data_dir = persistent_data_dir
+ ubconfig.board_type = board_type
+ ubconfig.board_identity = board_identity
+
+ env_vars = (
+ 'board_type',
+ 'board_identity',
+ 'source_dir',
+ 'test_py_dir',
+ 'build_dir',
+ 'result_dir',
+ 'persistent_data_dir',
+ )
+ for v in env_vars:
+ os.environ['U_BOOT_' + v.upper()] = getattr(ubconfig, v)
+
+ if board_type == 'sandbox':
+ import u_boot_console_sandbox
+ console = u_boot_console_sandbox.ConsoleSandbox(log, ubconfig)
+ else:
+ import u_boot_console_exec_attach
+ console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig)
+
+def pytest_generate_tests(metafunc):
+ '''pytest hook: parameterize test functions based on custom rules.
+
+ If a test function takes parameter(s) (fixture names) of the form brd__xxx
+ or env__xxx, the brd and env configuration dictionaries are consulted to
+ find the list of values to use for those parameters, and the test is
+ parametrized so that it runs once for each combination of values.
+
+ Args:
+ metafunc: The pytest test function.
+
+ Returns:
+ Nothing.
+ '''
+
+ subconfigs = {
+ 'brd': console.config.brd,
+ 'env': console.config.env,
+ }
+ for fn in metafunc.fixturenames:
+ parts = fn.split('__')
+ if len(parts) < 2:
+ continue
+ if parts[0] not in subconfigs:
+ continue
+ subconfig = subconfigs[parts[0]]
+ vals = []
+ val = subconfig.get(fn, [])
+ # If that exact name is a key in the data source:
+ if val:
+ # ... use the dict value as a single parameter value.
+ vals = (val, )
+ else:
+ # ... otherwise, see if there's a key that contains a list of
+ # values to use instead.
+ vals = subconfig.get(fn + 's', [])
+ metafunc.parametrize(fn, vals)
+
+@pytest.fixture(scope='session')
+def u_boot_console(request):
+ '''Generate the value of a test's u_boot_console fixture.
+
+ Args:
+ request: The pytest request.
+
+ Returns:
+ The fixture value.
+ '''
+
+ return console
+
+tests_not_run = set()
+tests_failed = set()
+tests_skipped = set()
+tests_passed = set()
+
+def pytest_itemcollected(item):
+ '''pytest hook: Called once for each test found during collection.
+
+ This enables our custom result analysis code to see the list of all tests
+ that should eventually be run.
+
+ Args:
+ item: The item that was collected.
+
+ Returns:
+ Nothing.
+ '''
+
+ tests_not_run.add(item.name)
+
+def cleanup():
+ '''Clean up all global state.
+
+ Executed (via atexit) once the entire test process is complete. This
+ includes logging the status of all tests, and the identity of any failed
+ or skipped tests.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ if console:
+ console.close()
+ if log:
+ log.status_pass('%d passed' % len(tests_passed))
+ if tests_skipped:
+ log.status_skipped('%d skipped' % len(tests_skipped))
+ for test in tests_skipped:
+ log.status_skipped('... ' + test)
+ if tests_failed:
+ log.status_fail('%d failed' % len(tests_failed))
+ for test in tests_failed:
+ log.status_fail('... ' + test)
+ if tests_not_run:
+ log.status_fail('%d not run' % len(tests_not_run))
+ for test in tests_not_run:
+ log.status_fail('... ' + test)
+ log.close()
+atexit.register(cleanup)
+
+def setup_boardspec(item):
+ '''Process any 'boardspec' marker for a test.
+
+ Such a marker lists the set of board types that a test does/doesn't
+ support. If tests are being executed on an unsupported board, the test is
+ marked to be skipped.
+
+ Args:
+ item: The pytest test item.
+
+ Returns:
+ Nothing.
+ '''
+
+ mark = item.get_marker('boardspec')
+ if not mark:
+ return
+ required_boards = []
+ for board in mark.args:
+ if board.startswith('!'):
+ if ubconfig.board_type == board[1:]:
+ pytest.skip('board not supported')
+ return
+ else:
+ required_boards.append(board)
+ if required_boards and ubconfig.board_type not in required_boards:
+ pytest.skip('board not supported')
+
+def setup_buildconfigspec(item):
+ '''Process any 'buildconfigspec' marker for a test.
+
+ Such a marker lists some U-Boot configuration feature that the test
+ requires. If tests are being executed on an U-Boot build that doesn't
+ have the required feature, the test is marked to be skipped.
+
+ Args:
+ item: The pytest test item.
+
+ Returns:
+ Nothing.
+ '''
+
+ mark = item.get_marker('buildconfigspec')
+ if not mark:
+ return
+ for option in mark.args:
+ if not ubconfig.buildconfig.get('config_' + option.lower(), None):
+ pytest.skip('.config feature not enabled')
+
+def pytest_runtest_setup(item):
+ '''pytest hook: Configure (set up) a test item.
+
+ Called once for each test to perform any custom configuration. This hook
+ is used to skip the test if certain conditions apply.
+
+ Args:
+ item: The pytest test item.
+
+ Returns:
+ Nothing.
+ '''
+
+ log.start_section(item.name)
+ setup_boardspec(item)
+ setup_buildconfigspec(item)
+
+def pytest_runtest_protocol(item, nextitem):
+ '''pytest hook: Called to execute a test.
+
+ This hook wraps the standard pytest runtestprotocol() function in order
+ to acquire visibility into, and record, each test function's result.
+
+ Args:
+ item: The pytest test item to execute.
+ nextitem: The pytest test item that will be executed after this one.
+
+ Returns:
+ A list of pytest reports (test result data).
+ '''
+
+ reports = runtestprotocol(item, nextitem=nextitem)
+ failed = None
+ skipped = None
+ for report in reports:
+ if report.outcome == 'failed':
+ failed = report
+ break
+ if report.outcome == 'skipped':
+ if not skipped:
+ skipped = report
+
+ if failed:
+ tests_failed.add(item.name)
+ elif skipped:
+ tests_skipped.add(item.name)
+ else:
+ tests_passed.add(item.name)
+ tests_not_run.remove(item.name)
+
+ try:
+ if failed:
+ msg = 'FAILED:\n' + str(failed.longrepr)
+ log.status_fail(msg)
+ elif skipped:
+ msg = 'SKIPPED:\n' + str(skipped.longrepr)
+ log.status_skipped(msg)
+ else:
+ log.status_pass('OK')
+ except:
+ # If something went wrong with logging, it's better to let the test
+ # process continue, which may report other exceptions that triggered
+ # the logging issue (e.g. console.log wasn't created). Hence, just
+ # squash the exception. If the test setup failed due to e.g. syntax
+ # error somewhere else, this won't be seen. However, once that issue
+ # is fixed, if this exception still exists, it will then be logged as
+ # part of the test's stdout.
+ import traceback
+ print 'Exception occurred while logging runtest status:'
+ traceback.print_exc()
+ # FIXME: Can we force a test failure here?
+
+ log.end_section(item.name)
+
+ if failed:
+ console.cleanup_spawn()
+
+ return reports
diff --git a/test/py/multiplexed_log.css b/test/py/multiplexed_log.css
new file mode 100644
index 0000000000..50f7b90929
--- /dev/null
+++ b/test/py/multiplexed_log.css
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015 Stephen Warren
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+/*
+ * This provides pretty formatting of the HTML log file, e.g.
+ * - colored bars beside/above log sections for easily parsed delineation.
+ * - color highlighting of various messages.
+ */
+
+body {
+ background-color: black;
+ color: #ffffff;
+}
+
+pre {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+.implicit {
+ color: #808080;
+}
+
+.section {
+ border-style: solid;
+ border-color: #303030;
+ border-width: 0px 0px 0px 5px;
+ padding-left: 5px
+}
+
+.section-header {
+ background-color: #303030;
+ margin-left: -5px;
+ margin-top: 5px;
+}
+
+.section-trailer {
+ display: none;
+}
+
+.stream {
+ border-style: solid;
+ border-color: #303030;
+ border-width: 0px 0px 0px 5px;
+ padding-left: 5px
+}
+
+.stream-header {
+ background-color: #303030;
+ margin-left: -5px;
+ margin-top: 5px;
+}
+
+.stream-trailer {
+ display: none;
+}
+
+.error {
+ color: #ff0000
+}
+
+.warning {
+ color: #ffff00
+}
+
+.info {
+ color: #808080
+}
+
+.action {
+ color: #8080ff
+}
+
+.status-pass {
+ color: #00ff00
+}
+
+.status-skipped {
+ color: #ffff00
+}
+
+.status-fail {
+ color: #ff0000
+}
diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py
new file mode 100644
index 0000000000..48f2b51de1
--- /dev/null
+++ b/test/py/multiplexed_log.py
@@ -0,0 +1,515 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Generate an HTML-formatted log file containing multiple streams of data,
+# each represented in a well-delineated/-structured fashion.
+
+import cgi
+import os.path
+import shutil
+import subprocess
+
+mod_dir = os.path.dirname(os.path.abspath(__file__))
+
+class LogfileStream(object):
+ '''A file-like object used to write a single logical stream of data into
+ a multiplexed log file. Objects of this type should be created by factory
+ functions in the Logfile class rather than directly.'''
+
+ def __init__(self, logfile, name, chained_file):
+ '''Initialize a new object.
+
+ Args:
+ logfile: The Logfile object to log to.
+ name: The name of this log stream.
+ chained_file: The file-like object to which all stream data should be
+ logged to in addition to logfile. Can be None.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.logfile = logfile
+ self.name = name
+ self.chained_file = chained_file
+
+ def close(self):
+ '''Dummy function so that this class is "file-like".
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ pass
+
+ def write(self, data, implicit=False):
+ '''Write data to the log stream.
+
+ Args:
+ data: The data to write tot he file.
+ implicit: Boolean indicating whether data actually appeared in the
+ stream, or was implicitly generated. A valid use-case is to
+ repeat a shell prompt at the start of each separate log
+ section, which makes the log sections more readable in
+ isolation.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.logfile.write(self, data, implicit)
+ if self.chained_file:
+ self.chained_file.write(data)
+
+ def flush(self):
+ '''Flush the log stream, to ensure correct log interleaving.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.logfile.flush()
+ if self.chained_file:
+ self.chained_file.flush()
+
+class RunAndLog(object):
+ '''A utility object used to execute sub-processes and log their output to
+ a multiplexed log file. Objects of this type should be created by factory
+ functions in the Logfile class rather than directly.'''
+
+ def __init__(self, logfile, name, chained_file):
+ '''Initialize a new object.
+
+ Args:
+ logfile: The Logfile object to log to.
+ name: The name of this log stream or sub-process.
+ chained_file: The file-like object to which all stream data should
+ be logged to in addition to logfile. Can be None.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.logfile = logfile
+ self.name = name
+ self.chained_file = chained_file
+
+ def close(self):
+ '''Clean up any resources managed by this object.'''
+ pass
+
+ def run(self, cmd, cwd=None):
+ '''Run a command as a sub-process, and log the results.
+
+ Args:
+ cmd: The command to execute.
+ cwd: The directory to run the command in. Can be None to use the
+ current directory.
+
+ Returns:
+ Nothing.
+ '''
+
+ msg = "+" + " ".join(cmd) + "\n"
+ if self.chained_file:
+ self.chained_file.write(msg)
+ self.logfile.write(self, msg)
+
+ try:
+ p = subprocess.Popen(cmd, cwd=cwd,
+ stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ (stdout, stderr) = p.communicate()
+ output = ''
+ if stdout:
+ if stderr:
+ output += 'stdout:\n'
+ output += stdout
+ if stderr:
+ if stdout:
+ output += 'stderr:\n'
+ output += stderr
+ exit_status = p.returncode
+ exception = None
+ except subprocess.CalledProcessError as cpe:
+ output = cpe.output
+ exit_status = cpe.returncode
+ exception = cpe
+ except Exception as e:
+ output = ''
+ exit_status = 0
+ exception = e
+ if output and not output.endswith('\n'):
+ output += '\n'
+ if exit_status and not exception:
+ exception = Exception('Exit code: ' + str(exit_status))
+ if exception:
+ output += str(exception) + '\n'
+ self.logfile.write(self, output)
+ if self.chained_file:
+ self.chained_file.write(output)
+ if exception:
+ raise exception
+
+class SectionCtxMgr(object):
+ '''A context manager for Python's "with" statement, which allows a certain
+ portion of test code to be logged to a separate section of the log file.
+ Objects of this type should be created by factory functions in the Logfile
+ class rather than directly.'''
+
+ def __init__(self, log, marker):
+ '''Initialize a new object.
+
+ Args:
+ log: The Logfile object to log to.
+ marker: The name of the nested log section.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.log = log
+ self.marker = marker
+
+ def __enter__(self):
+ self.log.start_section(self.marker)
+
+ def __exit__(self, extype, value, traceback):
+ self.log.end_section(self.marker)
+
+class Logfile(object):
+ '''Generates an HTML-formatted log file containing multiple streams of
+ data, each represented in a well-delineated/-structured fashion.'''
+
+ def __init__(self, fn):
+ '''Initialize a new object.
+
+ Args:
+ fn: The filename to write to.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.f = open(fn, "wt")
+ self.last_stream = None
+ self.blocks = []
+ self.cur_evt = 1
+ shutil.copy(mod_dir + "/multiplexed_log.css", os.path.dirname(fn))
+ self.f.write("""\
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="multiplexed_log.css">
+</head>
+<body>
+<tt>
+""")
+
+ def close(self):
+ '''Close the log file.
+
+ After calling this function, no more data may be written to the log.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.f.write("""\
+</tt>
+</body>
+</html>
+""")
+ self.f.close()
+
+ # The set of characters that should be represented as hexadecimal codes in
+ # the log file.
+ _nonprint = ("%" + "".join(chr(c) for c in range(0, 32) if c not in (9, 10)) +
+ "".join(chr(c) for c in range(127, 256)))
+
+ def _escape(self, data):
+ '''Render data format suitable for inclusion in an HTML document.
+
+ This includes HTML-escaping certain characters, and translating
+ control characters to a hexadecimal representation.
+
+ Args:
+ data: The raw string data to be escaped.
+
+ Returns:
+ An escaped version of the data.
+ '''
+
+ data = data.replace(chr(13), "")
+ data = "".join((c in self._nonprint) and ("%%%02x" % ord(c)) or
+ c for c in data)
+ data = cgi.escape(data)
+ return data
+
+ def _terminate_stream(self):
+ '''Write HTML to the log file to terminate the current stream's data.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.cur_evt += 1
+ if not self.last_stream:
+ return
+ self.f.write("</pre>\n")
+ self.f.write("<div class=\"stream-trailer\" id=\"" +
+ self.last_stream.name + "\">End stream: " +
+ self.last_stream.name + "</div>\n")
+ self.f.write("</div>\n")
+ self.last_stream = None
+
+ def _note(self, note_type, msg):
+ '''Write a note or one-off message to the log file.
+
+ Args:
+ note_type: The type of note. This must be a value supported by the
+ accompanying multiplexed_log.css.
+ msg: The note/message to log.
+
+ Returns:
+ Nothing.
+ '''
+
+ self._terminate_stream()
+ self.f.write("<div class=\"" + note_type + "\">\n<pre>")
+ self.f.write(self._escape(msg))
+ self.f.write("\n</pre></div>\n")
+
+ def start_section(self, marker):
+ '''Begin a new nested section in the log file.
+
+ Args:
+ marker: The name of the section that is starting.
+
+ Returns:
+ Nothing.
+ '''
+
+ self._terminate_stream()
+ self.blocks.append(marker)
+ blk_path = "/".join(self.blocks)
+ self.f.write("<div class=\"section\" id=\"" + blk_path + "\">\n")
+ self.f.write("<div class=\"section-header\" id=\"" + blk_path +
+ "\">Section: " + blk_path + "</div>\n")
+
+ def end_section(self, marker):
+ '''Terminate the current nested section in the log file.
+
+ This function validates proper nesting of start_section() and
+ end_section() calls. If a mismatch is found, an exception is raised.
+
+ Args:
+ marker: The name of the section that is ending.
+
+ Returns:
+ Nothing.
+ '''
+
+ if (not self.blocks) or (marker != self.blocks[-1]):
+ raise Exception("Block nesting mismatch: \"%s\" \"%s\"" %
+ (marker, "/".join(self.blocks)))
+ self._terminate_stream()
+ blk_path = "/".join(self.blocks)
+ self.f.write("<div class=\"section-trailer\" id=\"section-trailer-" +
+ blk_path + "\">End section: " + blk_path + "</div>\n")
+ self.f.write("</div>\n")
+ self.blocks.pop()
+
+ def section(self, marker):
+ '''Create a temporary section in the log file.
+
+ This function creates a context manager for Python's "with" statement,
+ which allows a certain portion of test code to be logged to a separate
+ section of the log file.
+
+ Usage:
+ with log.section("somename"):
+ some test code
+
+ Args:
+ marker: The name of the nested section.
+
+ Returns:
+ A context manager object.
+ '''
+
+ return SectionCtxMgr(self, marker)
+
+ def error(self, msg):
+ '''Write an error note to the log file.
+
+ Args:
+ msg: A message describing the error.
+
+ Returns:
+ Nothing.
+ '''
+
+ self._note("error", msg)
+
+ def warning(self, msg):
+ '''Write an warning note to the log file.
+
+ Args:
+ msg: A message describing the warning.
+
+ Returns:
+ Nothing.
+ '''
+
+ self._note("warning", msg)
+
+ def info(self, msg):
+ '''Write an informational note to the log file.
+
+ Args:
+ msg: An informational message.
+
+ Returns:
+ Nothing.
+ '''
+
+ self._note("info", msg)
+
+ def action(self, msg):
+ '''Write an action note to the log file.
+
+ Args:
+ msg: A message describing the action that is being logged.
+
+ Returns:
+ Nothing.
+ '''
+
+ self._note("action", msg)
+
+ def status_pass(self, msg):
+ '''Write a note to the log file describing test(s) which passed.
+
+ Args:
+ msg: A message describing passed test(s).
+
+ Returns:
+ Nothing.
+ '''
+
+ self._note("status-pass", msg)
+
+ def status_skipped(self, msg):
+ '''Write a note to the log file describing skipped test(s).
+
+ Args:
+ msg: A message describing passed test(s).
+
+ Returns:
+ Nothing.
+ '''
+
+ self._note("status-skipped", msg)
+
+ def status_fail(self, msg):
+ '''Write a note to the log file describing failed test(s).
+
+ Args:
+ msg: A message describing passed test(s).
+
+ Returns:
+ Nothing.
+ '''
+
+ self._note("status-fail", msg)
+
+ def get_stream(self, name, chained_file=None):
+ '''Create an object to log a single stream's data into the log file.
+
+ This creates a "file-like" object that can be written to in order to
+ write a single stream's data to the log file. The implementation will
+ handle any required interleaving of data (from multiple streams) in
+ the log, in a way that makes it obvious which stream each bit of data
+ came from.
+
+ Args:
+ name: The name of the stream.
+ chained_file: The file-like object to which all stream data should
+ be logged to in addition to this log. Can be None.
+
+ Returns:
+ A file-like object.
+ '''
+
+ return LogfileStream(self, name, chained_file)
+
+ def get_runner(self, name, chained_file=None):
+ '''Create an object that executes processes and logs their output.
+
+ Args:
+ name: The name of this sub-process.
+ chained_file: The file-like object to which all stream data should
+ be logged to in addition to logfile. Can be None.
+
+ Returns:
+ A RunAndLog object.
+ '''
+
+ return RunAndLog(self, name, chained_file)
+
+ def write(self, stream, data, implicit=False):
+ '''Write stream data into the log file.
+
+ This function should only be used by instances of LogfileStream or
+ RunAndLog.
+
+ Args:
+ stream: The stream whose data is being logged.
+ data: The data to log.
+ implicit: Boolean indicating whether data actually appeared in the
+ stream, or was implicitly generated. A valid use-case is to
+ repeat a shell prompt at the start of each separate log
+ section, which makes the log sections more readable in
+ isolation.
+
+ Returns:
+ Nothing.
+ '''
+
+ if stream != self.last_stream:
+ self._terminate_stream()
+ self.f.write("<div class=\"stream\" id=\"%s\">\n" % stream.name)
+ self.f.write("<div class=\"stream-header\" id=\"" + stream.name +
+ "\">Stream: " + stream.name + "</div>\n")
+ self.f.write("<pre>")
+ if implicit:
+ self.f.write("<span class=\"implicit\">")
+ self.f.write(self._escape(data))
+ if implicit:
+ self.f.write("</span>")
+ self.last_stream = stream
+
+ def flush(self):
+ '''Flush the log stream, to ensure correct log interleaving.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.f.flush()
diff --git a/test/py/pytest.ini b/test/py/pytest.ini
new file mode 100644
index 0000000000..67e514f420
--- /dev/null
+++ b/test/py/pytest.ini
@@ -0,0 +1,11 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Static configuration data for pytest. pytest reads this at startup time.
+
+[pytest]
+markers =
+ boardspec: U-Boot: Describes the set of boards a test can/can't run on.
+ buildconfigspec: U-Boot: Describes Kconfig/config-header constraints.
diff --git a/test/py/test.py b/test/py/test.py
new file mode 100755
index 0000000000..9c23898774
--- /dev/null
+++ b/test/py/test.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Wrapper script to invoke pytest with the directory name that contains the
+# U-Boot tests.
+
+import os
+import os.path
+import sys
+
+# Get rid of argv[0]
+sys.argv.pop(0)
+
+# argv; py.test test_directory_name user-supplied-arguments
+args = ["py.test", os.path.dirname(__file__) + "/tests"]
+args.extend(sys.argv)
+
+try:
+ os.execvp("py.test", args)
+except:
+ # Log full details of any exception for detailed analysis
+ import traceback
+ traceback.print_exc()
+ # Hint to the user that they likely simply haven't installed the required
+ # dependencies.
+ print >>sys.stderr, """
+exec(py.test) failed; perhaps you are missing some dependencies?
+See test/py/README.md for the list."""
diff --git a/test/py/tests/test_000_version.py b/test/py/tests/test_000_version.py
new file mode 100644
index 0000000000..d262f0534e
--- /dev/null
+++ b/test/py/tests/test_000_version.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# pytest runs tests the order of their module path, which is related to the
+# filename containing the test. This file is named such that it is sorted
+# first, simply as a very basic sanity check of the functionality of the U-Boot
+# command prompt.
+
+def test_version(u_boot_console):
+ '''Test that the "version" command prints the U-Boot version.'''
+
+ # "version" prints the U-Boot sign-on message. This is usually considered
+ # an error, so that any unexpected reboot causes an error. Here, this
+ # error detection is disabled since the sign-on message is expected.
+ with u_boot_console.disable_check('main_signon'):
+ response = u_boot_console.run_command('version')
+ # Ensure "version" printed what we expected.
+ u_boot_console.validate_version_string_in_text(response)
diff --git a/test/py/tests/test_env.py b/test/py/tests/test_env.py
new file mode 100644
index 0000000000..a3e8dd3033
--- /dev/null
+++ b/test/py/tests/test_env.py
@@ -0,0 +1,221 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Test operation of shell commands relating to environment variables.
+
+import pytest
+
+# FIXME: This might be useful for other tests;
+# perhaps refactor it into ConsoleBase or some other state object?
+class StateTestEnv(object):
+ '''Container that represents the state of all U-Boot environment variables.
+ This enables quick determination of existant/non-existant variable
+ names.
+ '''
+
+ def __init__(self, u_boot_console):
+ '''Initialize a new StateTestEnv object.
+
+ Args:
+ u_boot_console: A U-Boot console.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.u_boot_console = u_boot_console
+ self.get_env()
+ self.set_var = self.get_non_existent_var()
+
+ def get_env(self):
+ '''Read all current environment variables from U-Boot.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ response = self.u_boot_console.run_command('printenv')
+ self.env = {}
+ for l in response.splitlines():
+ if not '=' in l:
+ continue
+ (var, value) = l.strip().split('=', 1)
+ self.env[var] = value
+
+ def get_existent_var(self):
+ '''Return the name of an environment variable that exists.
+
+ Args:
+ None.
+
+ Returns:
+ The name of an environment variable.
+ '''
+
+ for var in self.env:
+ return var
+
+ def get_non_existent_var(self):
+ '''Return the name of an environment variable that does not exist.
+
+ Args:
+ None.
+
+ Returns:
+ The name of an environment variable.
+ '''
+
+ n = 0
+ while True:
+ var = 'test_env_' + str(n)
+ if var not in self.env:
+ return var
+ n += 1
+
+@pytest.fixture(scope='module')
+def state_test_env(u_boot_console):
+ '''pytest fixture to provide a StateTestEnv object to tests.'''
+
+ return StateTestEnv(u_boot_console)
+
+def unset_var(state_test_env, var):
+ '''Unset an environment variable.
+
+ This both executes a U-Boot shell command and updates a StateTestEnv
+ object.
+
+ Args:
+ state_test_env: The StateTestEnv object to updata.
+ var: The variable name to unset.
+
+ Returns:
+ Nothing.
+ '''
+
+ state_test_env.u_boot_console.run_command('setenv %s' % var)
+ if var in state_test_env.env:
+ del state_test_env.env[var]
+
+def set_var(state_test_env, var, value):
+ '''Set an environment variable.
+
+ This both executes a U-Boot shell command and updates a StateTestEnv
+ object.
+
+ Args:
+ state_test_env: The StateTestEnv object to updata.
+ var: The variable name to set.
+ value: The value to set the variable to.
+
+ Returns:
+ Nothing.
+ '''
+
+ state_test_env.u_boot_console.run_command('setenv %s "%s"' % (var, value))
+ state_test_env.env[var] = value
+
+def validate_empty(state_test_env, var):
+ '''Validate that a variable is not set, using U-Boot shell commands.
+
+ Args:
+ var: The variable name to test.
+
+ Returns:
+ Nothing.
+ '''
+
+ response = state_test_env.u_boot_console.run_command('echo $%s' % var)
+ assert response == ''
+
+def validate_set(state_test_env, var, value):
+ '''Validate that a variable is set, using U-Boot shell commands.
+
+ Args:
+ var: The variable name to test.
+ value: The value the variable is expected to have.
+
+ Returns:
+ Nothing.
+ '''
+
+ # echo does not preserve leading, internal, or trailing whitespace in the
+ # value. printenv does, and hence allows more complete testing.
+ response = state_test_env.u_boot_console.run_command('printenv %s' % var)
+ assert response == ('%s=%s' % (var, value))
+
+def test_env_echo_exists(state_test_env):
+ '''Test echoing a variable that exists.'''
+
+ var = state_test_env.get_existent_var()
+ value = state_test_env.env[var]
+ validate_set(state_test_env, var, value)
+
+def test_env_echo_non_existent(state_test_env):
+ '''Test echoing a variable that doesn't exist.'''
+
+ var = state_test_env.set_var
+ validate_empty(state_test_env, var)
+
+def test_env_printenv_non_existent(state_test_env):
+ '''Test printenv error message for non-existant variables.'''
+
+ var = state_test_env.set_var
+ c = state_test_env.u_boot_console
+ with c.disable_check('error_notification'):
+ response = c.run_command('printenv %s' % var)
+ assert(response == '## Error: "%s" not defined' % var)
+
+def test_env_unset_non_existent(state_test_env):
+ '''Test unsetting a nonexistent variable.'''
+
+ var = state_test_env.get_non_existent_var()
+ unset_var(state_test_env, var)
+ validate_empty(state_test_env, var)
+
+def test_env_set_non_existent(state_test_env):
+ '''Test set a non-existant variable.'''
+
+ var = state_test_env.set_var
+ value = 'foo'
+ set_var(state_test_env, var, value)
+ validate_set(state_test_env, var, value)
+
+def test_env_set_existing(state_test_env):
+ '''Test setting an existant variable.'''
+
+ var = state_test_env.set_var
+ value = 'bar'
+ set_var(state_test_env, var, value)
+ validate_set(state_test_env, var, value)
+
+def test_env_unset_existing(state_test_env):
+ '''Test unsetting a variable.'''
+
+ var = state_test_env.set_var
+ unset_var(state_test_env, var)
+ validate_empty(state_test_env, var)
+
+def test_env_expansion_spaces(state_test_env):
+ '''Test expanding a variable that contains a space in its value.'''
+
+ var_space = None
+ var_test = None
+ try:
+ var_space = state_test_env.get_non_existent_var()
+ set_var(state_test_env, var_space, ' ')
+
+ var_test = state_test_env.get_non_existent_var()
+ value = ' 1${%(var_space)s}${%(var_space)s} 2 ' % locals()
+ set_var(state_test_env, var_test, value)
+ value = ' 1 2 '
+ validate_set(state_test_env, var_test, value)
+ finally:
+ if var_space:
+ unset_var(state_test_env, var_space)
+ if var_test:
+ unset_var(state_test_env, var_test)
diff --git a/test/py/tests/test_help.py b/test/py/tests/test_help.py
new file mode 100644
index 0000000000..894f3b5f17
--- /dev/null
+++ b/test/py/tests/test_help.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+def test_help(u_boot_console):
+ '''Test that the "help" command can be executed.'''
+
+ u_boot_console.run_command('help')
diff --git a/test/py/tests/test_hush_if_test.py b/test/py/tests/test_hush_if_test.py
new file mode 100644
index 0000000000..cf4c3aeeb7
--- /dev/null
+++ b/test/py/tests/test_hush_if_test.py
@@ -0,0 +1,154 @@
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Test operation of the "if" shell command.
+
+import os
+import os.path
+import pytest
+
+# The list of "if test" conditions to test.
+subtests = (
+ # Base if functionality.
+
+ ('true', True),
+ ('false', False),
+
+ # Basic operators.
+
+ ('test aaa = aaa', True),
+ ('test aaa = bbb', False),
+
+ ('test aaa != bbb', True),
+ ('test aaa != aaa', False),
+
+ ('test aaa < bbb', True),
+ ('test bbb < aaa', False),
+
+ ('test bbb > aaa', True),
+ ('test aaa > bbb', False),
+
+ ('test 123 -eq 123', True),
+ ('test 123 -eq 456', False),
+
+ ('test 123 -ne 456', True),
+ ('test 123 -ne 123', False),
+
+ ('test 123 -lt 456', True),
+ ('test 123 -lt 123', False),
+ ('test 456 -lt 123', False),
+
+ ('test 123 -le 456', True),
+ ('test 123 -le 123', True),
+ ('test 456 -le 123', False),
+
+ ('test 456 -gt 123', True),
+ ('test 123 -gt 123', False),
+ ('test 123 -gt 456', False),
+
+ ('test 456 -ge 123', True),
+ ('test 123 -ge 123', True),
+ ('test 123 -ge 456', False),
+
+ ('test -z ""', True),
+ ('test -z "aaa"', False),
+
+ ('test -n "aaa"', True),
+ ('test -n ""', False),
+
+ # Inversion of simple tests.
+
+ ('test ! aaa = aaa', False),
+ ('test ! aaa = bbb', True),
+ ('test ! ! aaa = aaa', True),
+ ('test ! ! aaa = bbb', False),
+
+ # Binary operators.
+
+ ('test aaa != aaa -o bbb != bbb', False),
+ ('test aaa != aaa -o bbb = bbb', True),
+ ('test aaa = aaa -o bbb != bbb', True),
+ ('test aaa = aaa -o bbb = bbb', True),
+
+ ('test aaa != aaa -a bbb != bbb', False),
+ ('test aaa != aaa -a bbb = bbb', False),
+ ('test aaa = aaa -a bbb != bbb', False),
+ ('test aaa = aaa -a bbb = bbb', True),
+
+ # Inversion within binary operators.
+
+ ('test ! aaa != aaa -o ! bbb != bbb', True),
+ ('test ! aaa != aaa -o ! bbb = bbb', True),
+ ('test ! aaa = aaa -o ! bbb != bbb', True),
+ ('test ! aaa = aaa -o ! bbb = bbb', False),
+
+ ('test ! ! aaa != aaa -o ! ! bbb != bbb', False),
+ ('test ! ! aaa != aaa -o ! ! bbb = bbb', True),
+ ('test ! ! aaa = aaa -o ! ! bbb != bbb', True),
+ ('test ! ! aaa = aaa -o ! ! bbb = bbb', True),
+
+ # -z operator.
+
+ ('test -z "$ut_var_nonexistent"', True),
+ ('test -z "$ut_var_exists"', False),
+)
+
+def exec_hush_if(u_boot_console, expr, result):
+ '''Execute a shell "if" command, and validate its result.'''
+
+ cmd = 'if ' + expr + '; then echo true; else echo false; fi'
+ response = u_boot_console.run_command(cmd)
+ assert response.strip() == str(result).lower()
+
+@pytest.mark.buildconfigspec('sys_hush_parser')
+def test_hush_if_test_setup(u_boot_console):
+ '''Set up environment variables used during the "if" tests.'''
+
+ u_boot_console.run_command('setenv ut_var_nonexistent')
+ u_boot_console.run_command('setenv ut_var_exists 1')
+
+@pytest.mark.buildconfigspec('sys_hush_parser')
+@pytest.mark.parametrize('expr,result', subtests)
+def test_hush_if_test(u_boot_console, expr, result):
+ '''Test a single "if test" condition.'''
+
+ exec_hush_if(u_boot_console, expr, result)
+
+@pytest.mark.buildconfigspec('sys_hush_parser')
+def test_hush_if_test_teardown(u_boot_console):
+ '''Clean up environment variables used during the "if" tests.'''
+
+ u_boot_console.run_command('setenv ut_var_exists')
+
+@pytest.mark.buildconfigspec('sys_hush_parser')
+# We might test this on real filesystems via UMS, DFU, 'save', etc.
+# Of those, only UMS currently allows file removal though.
+@pytest.mark.boardspec('sandbox')
+def test_hush_if_test_host_file_exists(u_boot_console):
+ '''Test the "if test -e" shell command.'''
+
+ test_file = u_boot_console.config.result_dir + \
+ '/creating_this_file_breaks_u_boot_tests'
+
+ try:
+ os.unlink(test_file)
+ except:
+ pass
+ assert not os.path.exists(test_file)
+
+ expr = 'test -e hostfs - ' + test_file
+ exec_hush_if(u_boot_console, expr, False)
+
+ try:
+ with file(test_file, 'wb'):
+ pass
+ assert os.path.exists(test_file)
+
+ expr = 'test -e hostfs - ' + test_file
+ exec_hush_if(u_boot_console, expr, True)
+ finally:
+ os.unlink(test_file)
+
+ expr = 'test -e hostfs - ' + test_file
+ exec_hush_if(u_boot_console, expr, False)
diff --git a/test/py/tests/test_md.py b/test/py/tests/test_md.py
new file mode 100644
index 0000000000..94603c7df6
--- /dev/null
+++ b/test/py/tests/test_md.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import pytest
+
+@pytest.mark.buildconfigspec('cmd_memory')
+def test_md(u_boot_console):
+ '''Test that md reads memory as expected, and that memory can be modified
+ using the mw command.'''
+
+ ram_base = u_boot_console.find_ram_base()
+ addr = '%08x' % ram_base
+ val = 'a5f09876'
+ expected_response = addr + ': ' + val
+ u_boot_console.run_command('mw ' + addr + ' 0 10')
+ response = u_boot_console.run_command('md ' + addr + ' 10')
+ assert(not (expected_response in response))
+ u_boot_console.run_command('mw ' + addr + ' ' + val)
+ response = u_boot_console.run_command('md ' + addr + ' 10')
+ assert(expected_response in response)
+
+@pytest.mark.buildconfigspec('cmd_memory')
+def test_md_repeat(u_boot_console):
+ '''Test command repeat (via executing an empty command) operates correctly
+ for "md"; the command must repeat and dump an incrementing address.'''
+
+ ram_base = u_boot_console.find_ram_base()
+ addr_base = '%08x' % ram_base
+ words = 0x10
+ addr_repeat = '%08x' % (ram_base + (words * 4))
+ u_boot_console.run_command('md %s %x' % (addr_base, words))
+ response = u_boot_console.run_command('')
+ expected_response = addr_repeat + ': '
+ assert(expected_response in response)
diff --git a/test/py/tests/test_sandbox_exit.py b/test/py/tests/test_sandbox_exit.py
new file mode 100644
index 0000000000..2aa8eb4abc
--- /dev/null
+++ b/test/py/tests/test_sandbox_exit.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import pytest
+import signal
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('reset')
+def test_reset(u_boot_console):
+ '''Test that the "reset" command exits sandbox process.'''
+
+ u_boot_console.run_command('reset', wait_for_prompt=False)
+ assert(u_boot_console.validate_exited())
+ u_boot_console.ensure_spawned()
+
+@pytest.mark.boardspec('sandbox')
+def test_ctrl_c(u_boot_console):
+ '''Test that sending SIGINT to sandbox causes it to exit.'''
+
+ u_boot_console.kill(signal.SIGINT)
+ assert(u_boot_console.validate_exited())
+ u_boot_console.ensure_spawned()
diff --git a/test/py/tests/test_shell_basics.py b/test/py/tests/test_shell_basics.py
new file mode 100644
index 0000000000..719ce611d7
--- /dev/null
+++ b/test/py/tests/test_shell_basics.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Test basic shell functionality, such as commands separate by semi-colons.
+
+def test_shell_execute(u_boot_console):
+ '''Test any shell command.'''
+
+ response = u_boot_console.run_command('echo hello')
+ assert response.strip() == 'hello'
+
+def test_shell_semicolon_two(u_boot_console):
+ '''Test two shell commands separate by a semi-colon.'''
+
+ cmd = 'echo hello; echo world'
+ response = u_boot_console.run_command(cmd)
+ # This validation method ignores the exact whitespace between the strings
+ assert response.index('hello') < response.index('world')
+
+def test_shell_semicolon_three(u_boot_console):
+ '''Test three shell commands separate by a semi-colon, with variable
+ expansion dependencies between them.'''
+
+ cmd = 'setenv list 1; setenv list ${list}2; setenv list ${list}3; ' + \
+ 'echo ${list}'
+ response = u_boot_console.run_command(cmd)
+ assert response.strip() == '123'
+ u_boot_console.run_command('setenv list')
+
+def test_shell_run(u_boot_console):
+ '''Test the "run" shell command.'''
+
+ u_boot_console.run_command('setenv foo \"setenv monty 1; setenv python 2\"')
+ u_boot_console.run_command('run foo')
+ response = u_boot_console.run_command('echo $monty')
+ assert response.strip() == '1'
+ response = u_boot_console.run_command('echo $python')
+ assert response.strip() == '2'
+ u_boot_console.run_command('setenv foo')
+ u_boot_console.run_command('setenv monty')
+ u_boot_console.run_command('setenv python')
diff --git a/test/py/tests/test_sleep.py b/test/py/tests/test_sleep.py
new file mode 100644
index 0000000000..64f1ddf9a0
--- /dev/null
+++ b/test/py/tests/test_sleep.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import pytest
+import time
+
+def test_sleep(u_boot_console):
+ '''Test the sleep command, and validate that it sleeps for approximately
+ the correct amount of time.'''
+
+ # Do this before we time anything, to make sure U-Boot is already running.
+ # Otherwise, the system boot time is included in the time measurement.
+ u_boot_console.ensure_spawned()
+
+ # 3s isn't too long, but is enough to cross a few second boundaries.
+ sleep_time = 3
+ tstart = time.time()
+ u_boot_console.run_command('sleep %d' % sleep_time)
+ tend = time.time()
+ elapsed = tend - tstart
+ delta_to_expected = abs(elapsed - sleep_time)
+ # 0.25s margin is hopefully enough to account for any system overhead.
+ assert delta_to_expected < 0.25
diff --git a/test/py/tests/test_ums.py b/test/py/tests/test_ums.py
new file mode 100644
index 0000000000..a137221c7a
--- /dev/null
+++ b/test/py/tests/test_ums.py
@@ -0,0 +1,94 @@
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Test U-Boot's "ums" command. At present, this test only ensures that a UMS
+# device can be enumerated by the host/test machine. In the future, this test
+# should be enhanced to validate disk IO.
+
+import os
+import pytest
+import time
+
+'''
+Note: This test relies on:
+
+a) boardenv_* to contain configuration values to define which USB ports are
+available for testing. Without this, this test will be automatically skipped.
+For example:
+
+env__usb_dev_ports = (
+ {'tgt_usb_ctlr': '0', 'host_ums_dev_node': '/dev/disk/by-path/pci-0000:00:14.0-usb-0:13:1.0-scsi-0:0:0:0'},
+)
+
+env__block_devs = (
+ {'type': 'mmc', 'id': '0'}, # eMMC; always present
+ {'type': 'mmc', 'id': '1'}, # SD card; present since I plugged one in
+)
+
+b) udev rules to set permissions on devices nodes, so that sudo is not
+required. For example:
+
+ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb", KERNELS=="3-13", MODE:="666"
+
+(You may wish to change the group ID instead of setting the permissions wide
+open. All that matters is that the user ID running the test can access the
+device.)
+'''
+
+def open_ums_device(host_ums_dev_node):
+ '''Attempt to open a device node, returning either the opened file handle,
+ or None on any error.'''
+
+ try:
+ return open(host_ums_dev_node, 'rb')
+ except:
+ return None
+
+def wait_for_ums_device(host_ums_dev_node):
+ '''Continually attempt to open the device node exported by the "ums"
+ command, and either return the opened file handle, or raise an exception
+ after a timeout.'''
+
+ for i in xrange(100):
+ fh = open_ums_device(host_ums_dev_node)
+ if fh:
+ return fh
+ time.sleep(0.1)
+ raise Exception('UMS device did not appear')
+
+def wait_for_ums_device_gone(host_ums_dev_node):
+ '''Continually attempt to open the device node exported by the "ums"
+ command, and either return once the device has disappeared, or raise an
+ exception if it does not before a timeout occurs.'''
+
+ for i in xrange(100):
+ fh = open_ums_device(host_ums_dev_node)
+ if not fh:
+ return
+ fh.close()
+ time.sleep(0.1)
+ raise Exception('UMS device did not disappear')
+
+@pytest.mark.buildconfigspec('cmd_usb_mass_storage')
+def test_ums(u_boot_console, env__usb_dev_port, env__block_devs):
+ '''Test the "ums" command; the host system must be able to enumerate a UMS
+ device when "ums" is running, and this device must disappear when "ums" is
+ aborted.'''
+
+ tgt_usb_ctlr = env__usb_dev_port['tgt_usb_ctlr']
+ host_ums_dev_node = env__usb_dev_port['host_ums_dev_node']
+
+ # We're interested in testing USB device mode on each port, not the cross-
+ # product of that with each device. So, just pick the first entry in the
+ # device list here. We'll test each block device somewhere else.
+ tgt_dev_type = env__block_devs[0]['type']
+ tgt_dev_id = env__block_devs[0]['id']
+
+ cmd = 'ums %s %s %s' % (tgt_usb_ctlr, tgt_dev_type, tgt_dev_id)
+ u_boot_console.run_command('ums 0 mmc 0', wait_for_prompt=False)
+ fh = wait_for_ums_device(host_ums_dev_node)
+ fh.read(4096)
+ fh.close()
+ u_boot_console.ctrlc()
+ wait_for_ums_device_gone(host_ums_dev_node)
diff --git a/test/py/tests/test_unknown_cmd.py b/test/py/tests/test_unknown_cmd.py
new file mode 100644
index 0000000000..2de93e0026
--- /dev/null
+++ b/test/py/tests/test_unknown_cmd.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+def test_unknown_command(u_boot_console):
+ '''Test that executing an unknown command causes U-Boot to print an
+ error.'''
+
+ # The "unknown command" error is actively expected here,
+ # so error detection for it is disabled.
+ with u_boot_console.disable_check('unknown_command'):
+ response = u_boot_console.run_command('non_existent_cmd')
+ assert('Unknown command \'non_existent_cmd\' - try \'help\'' in response)
diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py
new file mode 100644
index 0000000000..520f9a9e9f
--- /dev/null
+++ b/test/py/u_boot_console_base.py
@@ -0,0 +1,360 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Common logic to interact with U-Boot via the console. This class provides
+# the interface that tests use to execute U-Boot shell commands and wait for
+# their results. Sub-classes exist to perform board-type-specific setup
+# operations, such as spawning a sub-process for Sandbox, or attaching to the
+# serial console of real hardware.
+
+import multiplexed_log
+import os
+import pytest
+import re
+import sys
+
+# Regexes for text we expect U-Boot to send to the console.
+pattern_u_boot_spl_signon = re.compile('(U-Boot SPL \\d{4}\\.\\d{2}-[^\r\n]*)')
+pattern_u_boot_main_signon = re.compile('(U-Boot \\d{4}\\.\\d{2}-[^\r\n]*)')
+pattern_stop_autoboot_prompt = re.compile('Hit any key to stop autoboot: ')
+pattern_unknown_command = re.compile('Unknown command \'.*\' - try \'help\'')
+pattern_error_notification = re.compile('## Error: ')
+
+class ConsoleDisableCheck(object):
+ '''Context manager (for Python's with statement) that temporarily disables
+ the specified console output error check. This is useful when deliberately
+ executing a command that is known to trigger one of the error checks, in
+ order to test that the error condition is actually raised. This class is
+ used internally by ConsoleBase::disable_check(); it is not intended for
+ direct usage.'''
+
+ def __init__(self, console, check_type):
+ self.console = console
+ self.check_type = check_type
+
+ def __enter__(self):
+ self.console.disable_check_count[self.check_type] += 1
+
+ def __exit__(self, extype, value, traceback):
+ self.console.disable_check_count[self.check_type] -= 1
+
+class ConsoleBase(object):
+ '''The interface through which test functions interact with the U-Boot
+ console. This primarily involves executing shell commands, capturing their
+ results, and checking for common error conditions. Some common utilities
+ are also provided too.'''
+
+ def __init__(self, log, config, max_fifo_fill):
+ '''Initialize a U-Boot console connection.
+
+ Can only usefully be called by sub-classes.
+
+ Args:
+ log: A mulptiplex_log.Logfile object, to which the U-Boot output
+ will be logged.
+ config: A configuration data structure, as built by conftest.py.
+ max_fifo_fill: The maximum number of characters to send to U-Boot
+ command-line before waiting for U-Boot to echo the characters
+ back. For UART-based HW without HW flow control, this value
+ should be set less than the UART RX FIFO size to avoid
+ overflow, assuming that U-Boot can't keep up with full-rate
+ traffic at the baud rate.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.log = log
+ self.config = config
+ self.max_fifo_fill = max_fifo_fill
+
+ self.logstream = self.log.get_stream('console', sys.stdout)
+
+ # Array slice removes leading/trailing quotes
+ self.prompt = self.config.buildconfig['config_sys_prompt'][1:-1]
+ self.prompt_escaped = re.escape(self.prompt)
+ self.p = None
+ self.disable_check_count = {
+ 'spl_signon': 0,
+ 'main_signon': 0,
+ 'unknown_command': 0,
+ 'error_notification': 0,
+ }
+
+ self.at_prompt = False
+ self.at_prompt_logevt = None
+ self.ram_base = None
+
+ def close(self):
+ '''Terminate the connection to the U-Boot console.
+
+ This function is only useful once all interaction with U-Boot is
+ complete. Once this function is called, data cannot be sent to or
+ received from U-Boot.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ if self.p:
+ self.p.close()
+ self.logstream.close()
+
+ def run_command(self, cmd, wait_for_echo=True, send_nl=True,
+ wait_for_prompt=True):
+ '''Execute a command via the U-Boot console.
+
+ The command is always sent to U-Boot.
+
+ U-Boot echoes any command back to its output, and this function
+ typically waits for that to occur. The wait can be disabled by setting
+ wait_for_echo=False, which is useful e.g. when sending CTRL-C to
+ interrupt a long-running command such as "ums".
+
+ Command execution is typically triggered by sending a newline
+ character. This can be disabled by setting send_nl=False, which is
+ also useful when sending CTRL-C.
+
+ This function typically waits for the command to finish executing, and
+ returns the console output that it generated. This can be disabled by
+ setting wait_for_prompt=False, which is useful when invoking a long-
+ running command such as "ums".
+
+ Args:
+ cmd: The command to send.
+ wait_for_each: Boolean indicating whether to wait for U-Boot to
+ echo the command text back to its output.
+ send_nl: Boolean indicating whether to send a newline character
+ after the command string.
+ wait_for_prompt: Boolean indicating whether to wait for the
+ command prompt to be sent by U-Boot. This typically occurs
+ immediately after the command has been executed.
+
+ Returns:
+ If wait_for_prompt == False:
+ Nothing.
+ Else:
+ The output from U-Boot during command execution. In other
+ words, the text U-Boot emitted between the point it echod the
+ command string and emitted the subsequent command prompts.
+ '''
+
+ self.ensure_spawned()
+
+ if self.at_prompt and \
+ self.at_prompt_logevt != self.logstream.logfile.cur_evt:
+ self.logstream.write(self.prompt, implicit=True)
+
+ bad_patterns = []
+ bad_pattern_ids = []
+ if (self.disable_check_count['spl_signon'] == 0 and
+ self.u_boot_spl_signon):
+ bad_patterns.append(self.u_boot_spl_signon_escaped)
+ bad_pattern_ids.append('SPL signon')
+ if self.disable_check_count['main_signon'] == 0:
+ bad_patterns.append(self.u_boot_main_signon_escaped)
+ bad_pattern_ids.append('U-Boot main signon')
+ if self.disable_check_count['unknown_command'] == 0:
+ bad_patterns.append(pattern_unknown_command)
+ bad_pattern_ids.append('Unknown command')
+ if self.disable_check_count['error_notification'] == 0:
+ bad_patterns.append(pattern_error_notification)
+ bad_pattern_ids.append('Error notification')
+ try:
+ self.at_prompt = False
+ if send_nl:
+ cmd += '\n'
+ while cmd:
+ # Limit max outstanding data, so UART FIFOs don't overflow
+ chunk = cmd[:self.max_fifo_fill]
+ cmd = cmd[self.max_fifo_fill:]
+ self.p.send(chunk)
+ if not wait_for_echo:
+ continue
+ chunk = re.escape(chunk)
+ chunk = chunk.replace('\\\n', '[\r\n]')
+ m = self.p.expect([chunk] + bad_patterns)
+ if m != 0:
+ self.at_prompt = False
+ raise Exception('Bad pattern found on console: ' +
+ bad_pattern_ids[m - 1])
+ if not wait_for_prompt:
+ return
+ m = self.p.expect([self.prompt_escaped] + bad_patterns)
+ if m != 0:
+ self.at_prompt = False
+ raise Exception('Bad pattern found on console: ' +
+ bad_pattern_ids[m - 1])
+ self.at_prompt = True
+ self.at_prompt_logevt = self.logstream.logfile.cur_evt
+ # Only strip \r\n; space/TAB might be significant if testing
+ # indentation.
+ return self.p.before.strip('\r\n')
+ except Exception as ex:
+ self.log.error(str(ex))
+ self.cleanup_spawn()
+ raise
+
+ def ctrlc(self):
+ '''Send a CTRL-C character to U-Boot.
+
+ This is useful in order to stop execution of long-running synchronous
+ commands such as "ums".
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.run_command(chr(3), wait_for_echo=False, send_nl=False)
+
+ def ensure_spawned(self):
+ '''Ensure a connection to a correctly running U-Boot instance.
+
+ This may require spawning a new Sandbox process or resetting target
+ hardware, as defined by the implementation sub-class.
+
+ This is an internal function and should not be called directly.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ if self.p:
+ return
+ try:
+ self.at_prompt = False
+ self.log.action('Starting U-Boot')
+ self.p = self.get_spawn()
+ # Real targets can take a long time to scroll large amounts of
+ # text if LCD is enabled. This value may need tweaking in the
+ # future, possibly per-test to be optimal. This works for 'help'
+ # on board 'seaboard'.
+ self.p.timeout = 30000
+ self.p.logfile_read = self.logstream
+ if self.config.buildconfig.get('CONFIG_SPL', False) == 'y':
+ self.p.expect([pattern_u_boot_spl_signon])
+ self.u_boot_spl_signon = self.p.after
+ self.u_boot_spl_signon_escaped = re.escape(self.p.after)
+ else:
+ self.u_boot_spl_signon = None
+ self.p.expect([pattern_u_boot_main_signon])
+ self.u_boot_main_signon = self.p.after
+ self.u_boot_main_signon_escaped = re.escape(self.p.after)
+ build_idx = self.u_boot_main_signon.find(', Build:')
+ if build_idx == -1:
+ self.u_boot_version_string = self.u_boot_main_signon
+ else:
+ self.u_boot_version_string = self.u_boot_main_signon[:build_idx]
+ while True:
+ match = self.p.expect([self.prompt_escaped,
+ pattern_stop_autoboot_prompt])
+ if match == 1:
+ self.p.send(chr(3)) # CTRL-C
+ continue
+ break
+ self.at_prompt = True
+ self.at_prompt_logevt = self.logstream.logfile.cur_evt
+ except Exception as ex:
+ self.log.error(str(ex))
+ self.cleanup_spawn()
+ raise
+
+ def cleanup_spawn(self):
+ '''Shut down all interaction with the U-Boot instance.
+
+ This is used when an error is detected prior to re-establishing a
+ connection with a fresh U-Boot instance.
+
+ This is an internal function and should not be called directly.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ try:
+ if self.p:
+ self.p.close()
+ except:
+ pass
+ self.p = None
+
+ def validate_version_string_in_text(self, text):
+ '''Assert that a command's output includes the U-Boot signon message.
+
+ This is primarily useful for validating the "version" command without
+ duplicating the signon text regex in a test function.
+
+ Args:
+ text: The command output text to check.
+
+ Returns:
+ Nothing. An exception is raised if the validation fails.
+ '''
+
+ assert(self.u_boot_version_string in text)
+
+ def disable_check(self, check_type):
+ '''Temporarily disable an error check of U-Boot's output.
+
+ Create a new context manager (for use with the "with" statement) which
+ temporarily disables a particular console output error check.
+
+ Args:
+ check_type: The type of error-check to disable. Valid values may
+ be found in self.disable_check_count above.
+
+ Returns:
+ A context manager object.
+ '''
+
+ return ConsoleDisableCheck(self, check_type)
+
+ def find_ram_base(self):
+ '''Find the running U-Boot's RAM location.
+
+ Probe the running U-Boot to determine the address of the first bank
+ of RAM. This is useful for tests that test reading/writing RAM, or
+ load/save files that aren't associated with some standard address
+ typically represented in an environment variable such as
+ ${kernel_addr_r}. The value is cached so that it only needs to be
+ actively read once.
+
+ Args:
+ None.
+
+ Returns:
+ The address of U-Boot's first RAM bank, as an integer.
+ '''
+
+ if self.config.buildconfig.get('config_cmd_bdi', 'n') != 'y':
+ pytest.skip('bdinfo command not supported')
+ if self.ram_base == -1:
+ pytest.skip('Previously failed to find RAM bank start')
+ if self.ram_base is not None:
+ return self.ram_base
+
+ with self.log.section('find_ram_base'):
+ response = self.run_command('bdinfo')
+ for l in response.split('\n'):
+ if '-> start' in l:
+ self.ram_base = int(l.split('=')[1].strip(), 16)
+ break
+ if self.ram_base is None:
+ self.ram_base = -1
+ raise Exception('Failed to find RAM bank start in `bdinfo`')
+
+ return self.ram_base
diff --git a/test/py/u_boot_console_exec_attach.py b/test/py/u_boot_console_exec_attach.py
new file mode 100644
index 0000000000..0ca9e7c178
--- /dev/null
+++ b/test/py/u_boot_console_exec_attach.py
@@ -0,0 +1,65 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Logic to interact with U-Boot running on real hardware, typically via a
+# physical serial port.
+
+import sys
+from u_boot_spawn import Spawn
+from u_boot_console_base import ConsoleBase
+
+class ConsoleExecAttach(ConsoleBase):
+ '''Represents a physical connection to a U-Boot console, typically via a
+ serial port. This implementation executes a sub-process to attach to the
+ console, expecting that the stdin/out of the sub-process will be forwarded
+ to/from the physical hardware. This approach isolates the test infra-
+ structure from the user-/installation-specific details of how to
+ communicate with, and the identity of, serial ports etc.'''
+
+ def __init__(self, log, config):
+ '''Initialize a U-Boot console connection.
+
+ Args:
+ log: A multiplexed_log.Logfile instance.
+ config: A "configuration" object as defined in conftest.py.
+
+ Returns:
+ Nothing.
+ '''
+
+ # The max_fifo_fill value might need tweaking per-board/-SoC?
+ # 1 would be safe anywhere, but is very slow (a pexpect issue?).
+ # 16 is a common FIFO size.
+ # HW flow control would mean this could be infinite.
+ super(ConsoleExecAttach, self).__init__(log, config, max_fifo_fill=16)
+
+ self.log.action('Flashing U-Boot')
+ cmd = ['u-boot-test-flash', config.board_type, config.board_identity]
+ runner = self.log.get_runner(cmd[0], sys.stdout)
+ runner.run(cmd)
+ runner.close()
+
+ def get_spawn(self):
+ '''Connect to a fresh U-Boot instance.
+
+ The target board is reset, so that U-Boot begins running from scratch.
+
+ Args:
+ None.
+
+ Returns:
+ A u_boot_spawn.Spawn object that is attached to U-Boot.
+ '''
+
+ args = [self.config.board_type, self.config.board_identity]
+ s = Spawn(['u-boot-test-console'] + args)
+
+ self.log.action('Resetting board')
+ cmd = ['u-boot-test-reset'] + args
+ runner = self.log.get_runner(cmd[0], sys.stdout)
+ runner.run(cmd)
+ runner.close()
+
+ return s
diff --git a/test/py/u_boot_console_sandbox.py b/test/py/u_boot_console_sandbox.py
new file mode 100644
index 0000000000..88b137e8c3
--- /dev/null
+++ b/test/py/u_boot_console_sandbox.py
@@ -0,0 +1,79 @@
+# Copyright (c) 2015 Stephen Warren
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Logic to interact with the sandbox port of U-Boot, running as a sub-process.
+
+import time
+from u_boot_spawn import Spawn
+from u_boot_console_base import ConsoleBase
+
+class ConsoleSandbox(ConsoleBase):
+ '''Represents a connection to a sandbox U-Boot console, executed as a sub-
+ process.'''
+
+ def __init__(self, log, config):
+ '''Initialize a U-Boot console connection.
+
+ Args:
+ log: A multiplexed_log.Logfile instance.
+ config: A "configuration" object as defined in conftest.py.
+
+ Returns:
+ Nothing.
+ '''
+
+ super(ConsoleSandbox, self).__init__(log, config, max_fifo_fill=1024)
+
+ def get_spawn(self):
+ '''Connect to a fresh U-Boot instance.
+
+ A new sandbox process is created, so that U-Boot begins running from
+ scratch.
+
+ Args:
+ None.
+
+ Returns:
+ A u_boot_spawn.Spawn object that is attached to U-Boot.
+ '''
+
+ return Spawn([self.config.build_dir + '/u-boot'])
+
+ def kill(self, sig):
+ '''Send a specific Unix signal to the sandbox process.
+
+ Args:
+ sig: The Unix signal to send to the process.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.ensure_spawned()
+ self.log.action('kill %d' % sig)
+ self.p.kill(sig)
+
+ def validate_exited(self):
+ '''Determine whether the sandbox process has exited.
+
+ If required, this function waits a reasonable time for the process to
+ exit.
+
+ Args:
+ None.
+
+ Returns:
+ Boolean indicating whether the process has exited.
+ '''
+
+ p = self.p
+ self.p = None
+ for i in xrange(100):
+ ret = not p.isalive()
+ if ret:
+ break
+ time.sleep(0.1)
+ p.close()
+ return ret
diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py
new file mode 100644
index 0000000000..1baee63df2
--- /dev/null
+++ b/test/py/u_boot_spawn.py
@@ -0,0 +1,174 @@
+# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Logic to spawn a sub-process and interact with its stdio.
+
+import os
+import re
+import pty
+import signal
+import select
+import time
+
+class Timeout(Exception):
+ '''An exception sub-class that indicates that a timeout occurred.'''
+ pass
+
+class Spawn(object):
+ '''Represents the stdio of a freshly created sub-process. Commands may be
+ sent to the process, and responses waited for.
+ '''
+
+ def __init__(self, args):
+ '''Spawn (fork/exec) the sub-process.
+
+ Args:
+ args: array of processs arguments. argv[0] is the command to execute.
+
+ Returns:
+ Nothing.
+ '''
+
+ self.waited = False
+ self.buf = ''
+ self.logfile_read = None
+ self.before = ''
+ self.after = ''
+ self.timeout = None
+
+ (self.pid, self.fd) = pty.fork()
+ if self.pid == 0:
+ try:
+ # For some reason, SIGHUP is set to SIG_IGN at this point when
+ # run under "go" (www.go.cd). Perhaps this happens under any
+ # background (non-interactive) system?
+ signal.signal(signal.SIGHUP, signal.SIG_DFL)
+ os.execvp(args[0], args)
+ except:
+ print 'CHILD EXECEPTION:'
+ import traceback
+ traceback.print_exc()
+ finally:
+ os._exit(255)
+
+ self.poll = select.poll()
+ self.poll.register(self.fd, select.POLLIN | select.POLLPRI | select.POLLERR | select.POLLHUP | select.POLLNVAL)
+
+ def kill(self, sig):
+ '''Send unix signal "sig" to the child process.
+
+ Args:
+ sig: The signal number to send.
+
+ Returns:
+ Nothing.
+ '''
+
+ os.kill(self.pid, sig)
+
+ def isalive(self):
+ '''Determine whether the child process is still running.
+
+ Args:
+ None.
+
+ Returns:
+ Boolean indicating whether process is alive.
+ '''
+
+ if self.waited:
+ return False
+
+ w = os.waitpid(self.pid, os.WNOHANG)
+ if w[0] == 0:
+ return True
+
+ self.waited = True
+ return False
+
+ def send(self, data):
+ '''Send data to the sub-process's stdin.
+
+ Args:
+ data: The data to send to the process.
+
+ Returns:
+ Nothing.
+ '''
+
+ os.write(self.fd, data)
+
+ def expect(self, patterns):
+ '''Wait for the sub-process to emit specific data.
+
+ This function waits for the process to emit one pattern from the
+ supplied list of patterns, or for a timeout to occur.
+
+ Args:
+ patterns: A list of strings or regex objects that we expect to
+ see in the sub-process' stdout.
+
+ Returns:
+ The index within the patterns array of the pattern the process
+ emitted.
+
+ Notable exceptions:
+ Timeout, if the process did not emit any of the patterns within
+ the expected time.
+ '''
+
+ for pi in xrange(len(patterns)):
+ if type(patterns[pi]) == type(''):
+ patterns[pi] = re.compile(patterns[pi])
+
+ try:
+ while True:
+ earliest_m = None
+ earliest_pi = None
+ for pi in xrange(len(patterns)):
+ pattern = patterns[pi]
+ m = pattern.search(self.buf)
+ if not m:
+ continue
+ if earliest_m and m.start() > earliest_m.start():
+ continue
+ earliest_m = m
+ earliest_pi = pi
+ if earliest_m:
+ pos = earliest_m.start()
+ posafter = earliest_m.end() + 1
+ self.before = self.buf[:pos]
+ self.after = self.buf[pos:posafter]
+ self.buf = self.buf[posafter:]
+ return earliest_pi
+ events = self.poll.poll(self.timeout)
+ if not events:
+ raise Timeout()
+ c = os.read(self.fd, 1024)
+ if not c:
+ raise EOFError()
+ if self.logfile_read:
+ self.logfile_read.write(c)
+ self.buf += c
+ finally:
+ if self.logfile_read:
+ self.logfile_read.flush()
+
+ def close(self):
+ '''Close the stdio connection to the sub-process.
+
+ This also waits a reasonable time for the sub-process to stop running.
+
+ Args:
+ None.
+
+ Returns:
+ Nothing.
+ '''
+
+ os.close(self.fd)
+ for i in xrange(100):
+ if not self.isalive():
+ break
+ time.sleep(0.1)
diff --git a/tools/logos/denx-comp.bmp b/tools/logos/denx-comp.bmp
new file mode 100644
index 0000000000..89d0f471c8
--- /dev/null
+++ b/tools/logos/denx-comp.bmp
Binary files differ
diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py
index 9e739d89b6..5f1b4f6e76 100644
--- a/tools/patman/gitutil.py
+++ b/tools/patman/gitutil.py
@@ -328,7 +328,7 @@ def BuildEmailList(in_list, tag=None, alias=None, raise_on_error=True):
return result
def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
- self_only=False, alias=None, in_reply_to=None):
+ self_only=False, alias=None, in_reply_to=None, thread=False):
"""Email a patch series.
Args:
@@ -342,6 +342,8 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
self_only: True to just email to yourself as a test
in_reply_to: If set we'll pass this to git as --in-reply-to.
Should be a message ID that this is in reply to.
+ thread: True to add --thread to git send-email (make
+ all patches reply to cover-letter or first patch in series)
Returns:
Git command that was/would be run
@@ -400,6 +402,8 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
cmd = ['git', 'send-email', '--annotate']
if in_reply_to:
cmd.append('--in-reply-to="%s"' % in_reply_to)
+ if thread:
+ cmd.append('--thread')
cmd += to
cmd += cc
diff --git a/tools/patman/patman.py b/tools/patman/patman.py
index 6fe8fe068c..d05c5ff8e1 100755
--- a/tools/patman/patman.py
+++ b/tools/patman/patman.py
@@ -61,6 +61,8 @@ parser.add_option('--no-check', action='store_false', dest='check_patch',
help="Don't check for patch compliance")
parser.add_option('--no-tags', action='store_false', dest='process_tags',
default=True, help="Don't process subject tags as aliaes")
+parser.add_option('-T', '--thread', action='store_true', dest='thread',
+ default=False, help='Create patches as a single thread')
parser.usage += """
@@ -161,7 +163,7 @@ else:
if its_a_go:
cmd = gitutil.EmailPatches(series, cover_fname, args,
options.dry_run, not options.ignore_bad_tags, cc_file,
- in_reply_to=options.in_reply_to)
+ in_reply_to=options.in_reply_to, thread=options.thread)
else:
print col.Color(col.RED, "Not sending emails due to errors/warnings")