summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig4
-rw-r--r--drivers/video/cfb_console.c14
-rw-r--r--drivers/video/coreboot.c18
-rw-r--r--drivers/video/pwm_backlight.c20
-rw-r--r--drivers/video/rockchip/rk_edp.c103
-rw-r--r--drivers/video/rockchip/rk_vop.c84
-rw-r--r--drivers/video/sunxi/Makefile2
-rw-r--r--drivers/video/sunxi/sunxi_display.c268
-rw-r--r--drivers/video/tegra124/sor.c4
-rw-r--r--drivers/video/video_bmp.c4
10 files changed, 350 insertions, 171 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 667157c2e97..b69ffcae4b2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -209,7 +209,7 @@ config PANEL
config SIMPLE_PANEL
bool "Enable simple panel support"
- depends on PANEL && BACKLIGHT
+ depends on PANEL && BACKLIGHT && DM_GPIO
default y
help
This turns on a simple panel driver that enables a compatible
@@ -241,7 +241,7 @@ config VIDCONSOLE_AS_NAME
config VIDEO_COREBOOT
bool "Enable coreboot framebuffer driver support"
- depends on X86 && SYS_COREBOOT
+ depends on X86
help
Turn on this option to enable a framebuffer driver when U-Boot is
loaded by coreboot where the graphics device is configured by
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 27ff7163f34..1f491a48d6a 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -82,20 +82,6 @@
#endif
/*
- * Defines for the MB862xx driver
- */
-#ifdef CONFIG_VIDEO_MB862xx
-
-#ifdef CONFIG_VIDEO_CORALP
-#define VIDEO_FB_LITTLE_ENDIAN
-#endif
-#ifdef CONFIG_VIDEO_MB862xx_ACCEL
-#define VIDEO_HW_RECTFILL
-#define VIDEO_HW_BITBLT
-#endif
-#endif
-
-/*
* Defines for the i.MX31 driver (mx3fb.c)
*/
#if defined(CONFIG_VIDEO_MX3) || defined(CONFIG_VIDEO_IPUV3)
diff --git a/drivers/video/coreboot.c b/drivers/video/coreboot.c
index 0a5fb08dc8a..7237542c076 100644
--- a/drivers/video/coreboot.c
+++ b/drivers/video/coreboot.c
@@ -5,9 +5,10 @@
#include <common.h>
#include <dm.h>
+#include <init.h>
#include <vbe.h>
#include <video.h>
-#include <asm/arch/sysinfo.h>
+#include <asm/cb_sysinfo.h>
static int save_vesa_mode(struct cb_framebuffer *fb,
struct vesa_mode_info *vesa)
@@ -17,7 +18,7 @@ static int save_vesa_mode(struct cb_framebuffer *fb,
* running on the serial console.
*/
if (!fb)
- return -ENXIO;
+ return log_msg_ret("save", -ENXIO);
vesa->x_resolution = fb->x_resolution;
vesa->y_resolution = fb->y_resolution;
@@ -44,16 +45,23 @@ static int coreboot_video_probe(struct udevice *dev)
struct vesa_mode_info *vesa = &mode_info.vesa;
int ret;
+ if (ll_boot_init())
+ return log_msg_ret("ll", -ENODEV);
+
printf("Video: ");
/* Initialize vesa_mode_info structure */
ret = save_vesa_mode(fb, vesa);
- if (ret)
+ if (ret) {
+ ret = log_msg_ret("save", ret);
goto err;
+ }
ret = vbe_setup_video_priv(vesa, uc_priv, plat);
- if (ret)
+ if (ret) {
+ ret = log_msg_ret("setup", ret);
goto err;
+ }
printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize,
vesa->bits_per_pixel);
@@ -61,7 +69,7 @@ static int coreboot_video_probe(struct udevice *dev)
return 0;
err:
- printf("No video mode configured in coreboot!\n");
+ printf("No video mode configured in coreboot (err=%d)\n", ret);
return ret;
}
diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index 9e32bc47cff..4c86215bd73 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -62,10 +62,17 @@ static int set_pwm(struct pwm_backlight_priv *priv)
uint duty_cycle;
int ret;
- duty_cycle = priv->period_ns * (priv->cur_level - priv->min_level) /
- (priv->max_level - priv->min_level);
- ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
- duty_cycle);
+ if (priv->period_ns) {
+ duty_cycle = priv->period_ns * (priv->cur_level - priv->min_level) /
+ (priv->max_level - priv->min_level);
+ ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
+ duty_cycle);
+ } else {
+ /* PWM driver will internally scale these like the above. */
+ ret = pwm_set_config(priv->pwm, priv->channel,
+ priv->max_level - priv->min_level,
+ priv->cur_level - priv->min_level);
+ }
if (ret)
return log_ret(ret);
@@ -213,10 +220,11 @@ static int pwm_backlight_of_to_plat(struct udevice *dev)
log_debug("Cannot get PWM: ret=%d\n", ret);
return log_ret(ret);
}
- if (args.args_count < 2)
+ if (args.args_count < 1)
return log_msg_ret("Not enough arguments to pwm\n", -EINVAL);
priv->channel = args.args[0];
- priv->period_ns = args.args[1];
+ if (args.args_count > 1)
+ priv->period_ns = args.args[1];
if (args.args_count > 2)
priv->polarity = args.args[2];
diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c
index 0be60e169e3..0ddf5e02d69 100644
--- a/drivers/video/rockchip/rk_edp.c
+++ b/drivers/video/rockchip/rk_edp.c
@@ -8,20 +8,21 @@
#include <clk.h>
#include <display.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <edid.h>
#include <log.h>
#include <malloc.h>
#include <panel.h>
#include <regmap.h>
+#include <reset.h>
#include <syscon.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
#include <asm/arch-rockchip/edp_rk3288.h>
#include <asm/arch-rockchip/grf_rk3288.h>
-#include <asm/arch-rockchip/hardware.h>
-#include <dt-bindings/clock/rk3288-cru.h>
-#include <linux/delay.h>
+#include <asm/arch-rockchip/grf_rk3399.h>
#define MAX_CR_LOOP 5
#define MAX_EQ_LOOP 5
@@ -37,18 +38,42 @@ static const char * const pre_emph_names[] = {
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5
+#define RK3288_GRF_SOC_CON6 0x025c
+#define RK3288_GRF_SOC_CON12 0x0274
+#define RK3399_GRF_SOC_CON20 0x6250
+#define RK3399_GRF_SOC_CON25 0x6264
+
+enum rockchip_dp_types {
+ RK3288_DP = 0,
+ RK3399_EDP
+};
+
+struct rockchip_dp_data {
+ unsigned long reg_vop_big_little;
+ unsigned long reg_vop_big_little_sel;
+ unsigned long reg_ref_clk_sel;
+ unsigned long ref_clk_sel_bit;
+ enum rockchip_dp_types chip_type;
+};
+
struct rk_edp_priv {
struct rk3288_edp *regs;
- struct rk3288_grf *grf;
+ void *grf;
struct udevice *panel;
struct link_train link_train;
u8 train_set[4];
};
-static void rk_edp_init_refclk(struct rk3288_edp *regs)
+static void rk_edp_init_refclk(struct rk3288_edp *regs, enum rockchip_dp_types chip_type)
{
writel(SEL_24M, &regs->analog_ctl_2);
- writel(REF_CLK_24M, &regs->pll_reg_1);
+ u32 reg;
+
+ reg = REF_CLK_24M;
+ if (chip_type == RK3288_DP)
+ reg ^= REF_CLK_MASK;
+ writel(reg, &regs->pll_reg_1);
+
writel(LDO_OUTPUT_V_SEL_145 | KVCO_DEFALUT | CHG_PUMP_CUR_SEL_5US |
V2L_CUR_SEL_1MA, &regs->pll_reg_2);
@@ -1029,6 +1054,9 @@ static int rk_edp_probe(struct udevice *dev)
struct display_plat *uc_plat = dev_get_uclass_plat(dev);
struct rk_edp_priv *priv = dev_get_priv(dev);
struct rk3288_edp *regs = priv->regs;
+ struct rockchip_dp_data *edp_data = (struct rockchip_dp_data *)dev_get_driver_data(dev);
+ struct reset_ctl dp_rst;
+
struct clk clk;
int ret;
@@ -1040,19 +1068,39 @@ static int rk_edp_probe(struct udevice *dev)
return ret;
}
- int vop_id = uc_plat->source_id;
- debug("%s, uc_plat=%p, vop_id=%u\n", __func__, uc_plat, vop_id);
+ ret = reset_get_by_name(dev, "dp", &dp_rst);
+ if (ret) {
+ dev_err(dev, "failed to get dp reset (ret=%d)\n", ret);
+ return ret;
+ }
- ret = clk_get_by_index(dev, 1, &clk);
- if (ret >= 0) {
- ret = clk_set_rate(&clk, 0);
- clk_free(&clk);
+ ret = reset_assert(&dp_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert dp reset (ret=%d)\n", ret);
+ return ret;
}
+ udelay(20);
+
+ ret = reset_deassert(&dp_rst);
if (ret) {
- debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
+ dev_err(dev, "failed to deassert dp reset (ret=%d)\n", ret);
return ret;
}
+ int vop_id = uc_plat->source_id;
+ debug("%s, uc_plat=%p, vop_id=%u\n", __func__, uc_plat, vop_id);
+
+ if (edp_data->chip_type == RK3288_DP) {
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret >= 0) {
+ ret = clk_set_rate(&clk, 0);
+ clk_free(&clk);
+ }
+ if (ret) {
+ debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
+ return ret;
+ }
+ }
ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
if (ret >= 0) {
ret = clk_set_rate(&clk, 192000000);
@@ -1065,15 +1113,17 @@ static int rk_edp_probe(struct udevice *dev)
}
/* grf_edp_ref_clk_sel: from internal 24MHz or 27MHz clock */
- rk_setreg(&priv->grf->soc_con12, 1 << 4);
+ rk_setreg(priv->grf + edp_data->reg_ref_clk_sel,
+ edp_data->ref_clk_sel_bit);
/* select epd signal from vop0 or vop1 */
- rk_clrsetreg(&priv->grf->soc_con6, (1 << 5),
- (vop_id == 1) ? (1 << 5) : (0 << 5));
+ rk_clrsetreg(priv->grf + edp_data->reg_vop_big_little,
+ edp_data->reg_vop_big_little_sel,
+ (vop_id == 1) ? edp_data->reg_vop_big_little_sel : 0);
rockchip_edp_wait_hpd(priv);
- rk_edp_init_refclk(regs);
+ rk_edp_init_refclk(regs, edp_data->chip_type);
rk_edp_init_interrupt(regs);
rk_edp_enable_sw_function(regs);
ret = rk_edp_init_analog_func(regs);
@@ -1089,8 +1139,25 @@ static const struct dm_display_ops dp_rockchip_ops = {
.enable = rk_edp_enable,
};
+static const struct rockchip_dp_data rk3399_edp = {
+ .reg_vop_big_little = RK3399_GRF_SOC_CON20,
+ .reg_vop_big_little_sel = BIT(5),
+ .reg_ref_clk_sel = RK3399_GRF_SOC_CON25,
+ .ref_clk_sel_bit = BIT(11),
+ .chip_type = RK3399_EDP,
+};
+
+static const struct rockchip_dp_data rk3288_dp = {
+ .reg_vop_big_little = RK3288_GRF_SOC_CON6,
+ .reg_vop_big_little_sel = BIT(5),
+ .reg_ref_clk_sel = RK3288_GRF_SOC_CON12,
+ .ref_clk_sel_bit = BIT(4),
+ .chip_type = RK3288_DP,
+};
+
static const struct udevice_id rockchip_dp_ids[] = {
- { .compatible = "rockchip,rk3288-edp" },
+ { .compatible = "rockchip,rk3288-edp", .data = (ulong)&rk3288_dp },
+ { .compatible = "rockchip,rk3399-edp", .data = (ulong)&rk3399_edp },
{ }
};
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
index 145c3330203..fe0574870f9 100644
--- a/drivers/video/rockchip/rk_vop.c
+++ b/drivers/video/rockchip/rk_vop.c
@@ -8,9 +8,11 @@
#include <clk.h>
#include <display.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <edid.h>
#include <log.h>
#include <regmap.h>
+#include <reset.h>
#include <syscon.h>
#include <video.h>
#include <asm/global_data.h>
@@ -21,6 +23,8 @@
#include <asm/arch-rockchip/vop_rk3288.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
+#include <efi.h>
+#include <efi_loader.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <power/regulator.h>
@@ -35,14 +39,16 @@ enum vop_pol {
DCLK_INVERT = 3
};
-static void rkvop_enable(struct rk3288_vop *regs, ulong fbbase,
+static void rkvop_enable(struct udevice *dev, struct rk3288_vop *regs, ulong fbbase,
int fb_bits_per_pixel,
- const struct display_timing *edid)
+ const struct display_timing *edid,
+ struct reset_ctl *dclk_rst)
{
u32 lb_mode;
u32 rgb_mode;
u32 hactive = edid->hactive.typ;
u32 vactive = edid->vactive.typ;
+ int ret;
writel(V_ACT_WIDTH(hactive - 1) | V_ACT_HEIGHT(vactive - 1),
&regs->win0_act_info);
@@ -90,6 +96,18 @@ static void rkvop_enable(struct rk3288_vop *regs, ulong fbbase,
writel(fbbase, &regs->win0_yrgb_mst);
writel(0x01, &regs->reg_cfg_done); /* enable reg config */
+
+ ret = reset_assert(dclk_rst);
+ if (ret) {
+ dev_warn(dev, "failed to assert dclk reset (ret=%d)\n", ret);
+ return;
+ }
+ udelay(20);
+
+ ret = reset_deassert(dclk_rst);
+ if (ret)
+ dev_warn(dev, "failed to deassert dclk reset (ret=%d)\n", ret);
+
}
static void rkvop_set_pin_polarity(struct udevice *dev,
@@ -236,12 +254,12 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
struct clk clk;
enum video_log2_bpp l2bpp;
ofnode remote;
+ const char *compat;
+ struct reset_ctl dclk_rst;
- debug("%s(%s, %lu, %s)\n", __func__,
+ debug("%s(%s, 0x%lx, %s)\n", __func__,
dev_read_name(dev), fbbase, ofnode_get_name(ep_node));
- vop_id = ofnode_read_s32_default(ep_node, "reg", -1);
- debug("vop_id=%d\n", vop_id);
ret = ofnode_read_u32(ep_node, "remote-endpoint", &remote_phandle);
if (ret)
return ret;
@@ -283,6 +301,28 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
if (disp)
break;
};
+ compat = ofnode_get_property(remote, "compatible", NULL);
+ if (!compat) {
+ debug("%s(%s): Failed to find compatible property\n",
+ __func__, dev_read_name(dev));
+ return -EINVAL;
+ }
+ if (strstr(compat, "edp")) {
+ vop_id = VOP_MODE_EDP;
+ } else if (strstr(compat, "mipi")) {
+ vop_id = VOP_MODE_MIPI;
+ } else if (strstr(compat, "hdmi")) {
+ vop_id = VOP_MODE_HDMI;
+ } else if (strstr(compat, "cdn-dp")) {
+ vop_id = VOP_MODE_DP;
+ } else if (strstr(compat, "lvds")) {
+ vop_id = VOP_MODE_LVDS;
+ } else {
+ debug("%s(%s): Failed to find vop mode for %s\n",
+ __func__, dev_read_name(dev), compat);
+ return -EINVAL;
+ }
+ debug("vop_id=%d\n", vop_id);
disp_uc_plat = dev_get_uclass_plat(disp);
debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
@@ -332,7 +372,14 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
}
rkvop_mode_set(dev, &timing, vop_id);
- rkvop_enable(regs, fbbase, 1 << l2bpp, &timing);
+
+ ret = reset_get_by_name(dev, "dclk", &dclk_rst);
+ if (ret) {
+ dev_err(dev, "failed to get dclk reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ rkvop_enable(dev, regs, fbbase, 1 << l2bpp, &timing, &dclk_rst);
ret = display_enable(disp, 1 << l2bpp, &timing);
if (ret)
@@ -369,11 +416,36 @@ int rk_vop_probe(struct udevice *dev)
struct rk_vop_priv *priv = dev_get_priv(dev);
int ret = 0;
ofnode port, node;
+ struct reset_ctl ahb_rst;
/* Before relocation we don't need to do anything */
if (!(gd->flags & GD_FLG_RELOC))
return 0;
+ ret = reset_get_by_name(dev, "ahb", &ahb_rst);
+ if (ret) {
+ dev_err(dev, "failed to get ahb reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_assert(&ahb_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert ahb reset (ret=%d)\n", ret);
+ return ret;
+ }
+ udelay(20);
+
+ ret = reset_deassert(&ahb_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert ahb reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+#if defined(CONFIG_EFI_LOADER)
+ debug("Adding to EFI map %d @ %lx\n", plat->size, plat->base);
+ efi_add_memory_map(plat->base, plat->size, EFI_RESERVED_MEMORY_TYPE);
+#endif
+
priv->regs = (struct rk3288_vop *)dev_read_addr(dev);
/*
diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile
index 147e1879922..4321673312b 100644
--- a/drivers/video/sunxi/Makefile
+++ b/drivers/video/sunxi/Makefile
@@ -4,4 +4,4 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o
-obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o ../dw_hdmi.o sunxi_lcd.o
+obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o sunxi_lcd.o
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index f52aba4d21c..4361a58cd7e 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -7,6 +7,8 @@
*/
#include <common.h>
+#include <display.h>
+#include <dm.h>
#include <cpu_func.h>
#include <efi_loader.h>
#include <init.h>
@@ -28,7 +30,9 @@
#include <fdt_support.h>
#include <i2c.h>
#include <malloc.h>
+#include <video.h>
#include <video_fb.h>
+#include <dm/uclass-internal.h>
#include "../videomodes.h"
#include "../anx9804.h"
#include "../hitachi_tx18d42vm_lcd.h"
@@ -45,6 +49,11 @@
DECLARE_GLOBAL_DATA_PTR;
+/* Maximum LCD size we support */
+#define LCD_MAX_WIDTH 3840
+#define LCD_MAX_HEIGHT 2160
+#define LCD_MAX_LOG2_BPP VIDEO_BPP32
+
enum sunxi_monitor {
sunxi_monitor_none,
sunxi_monitor_dvi,
@@ -58,13 +67,12 @@ enum sunxi_monitor {
};
#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
-struct sunxi_display {
- GraphicDevice graphic_device;
+struct sunxi_display_priv {
enum sunxi_monitor monitor;
unsigned int depth;
unsigned int fb_addr;
unsigned int fb_size;
-} sunxi_display;
+};
const struct ctfb_res_modes composite_video_modes[2] = {
/* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
@@ -214,7 +222,8 @@ static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
return r;
}
-static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
+static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display,
+ struct ctfb_res_modes *mode,
bool verbose_mode)
{
struct edid1_info edid1;
@@ -291,14 +300,14 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
}
/* Check for basic audio support, if found enable hdmi output */
- sunxi_display.monitor = sunxi_monitor_dvi;
+ sunxi_display->monitor = sunxi_monitor_dvi;
for (i = 0; i < ext_blocks; i++) {
if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
cea681[i].revision < 2)
continue;
if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
- sunxi_display.monitor = sunxi_monitor_hdmi;
+ sunxi_display->monitor = sunxi_monitor_hdmi;
}
return 0;
@@ -414,9 +423,9 @@ static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
static void sunxi_frontend_enable(void) {}
#endif
-static bool sunxi_is_composite(void)
+static bool sunxi_is_composite(enum sunxi_monitor monitor)
{
- switch (sunxi_display.monitor) {
+ switch (monitor) {
case sunxi_monitor_none:
case sunxi_monitor_dvi:
case sunxi_monitor_hdmi:
@@ -473,7 +482,8 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
};
static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
- unsigned int address)
+ unsigned int address,
+ enum sunxi_monitor monitor)
{
struct sunxi_de_be_reg * const de_be =
(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
@@ -502,7 +512,7 @@ static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
#endif
SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
- if (sunxi_is_composite()) {
+ if (sunxi_is_composite(monitor)) {
writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
&de_be->output_color_ctrl);
for (i = 0; i < 12; i++)
@@ -616,7 +626,8 @@ static void sunxi_lcdc_backlight_enable(void)
gpio_direction_output(pin, PWM_ON);
}
-static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
+static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display,
+ const struct ctfb_res_modes *mode,
bool for_ext_vga_dac)
{
struct sunxi_lcdc_reg * const lcdc =
@@ -643,17 +654,18 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
}
lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
- sunxi_is_composite());
+ sunxi_is_composite(sunxi_display->monitor));
video_ctfb_mode_to_display_timing(mode, &timing);
lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
- sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
+ sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
}
#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
int *clk_div, int *clk_double,
- bool use_portd_hvsync)
+ bool use_portd_hvsync,
+ enum sunxi_monitor monitor)
{
struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
@@ -663,7 +675,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
video_ctfb_mode_to_display_timing(mode, &timing);
lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
- sunxi_is_composite());
+ sunxi_is_composite(monitor));
if (use_portd_hvsync) {
sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
@@ -671,7 +683,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
}
lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
- sunxi_is_composite());
+ sunxi_is_composite(monitor));
}
#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
@@ -725,7 +737,8 @@ static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
}
static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
- int clk_div, int clk_double)
+ int clk_div, int clk_double,
+ enum sunxi_monitor monitor)
{
struct sunxi_hdmi_reg * const hdmi =
(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
@@ -734,7 +747,7 @@ static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
/* Write clear interrupt status bits */
writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
- if (sunxi_display.monitor == sunxi_monitor_hdmi)
+ if (monitor == sunxi_monitor_hdmi)
sunxi_hdmi_setup_info_frames(mode);
/* Set input sync enable */
@@ -789,7 +802,7 @@ static void sunxi_hdmi_enable(void)
#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
-static void sunxi_tvencoder_mode_set(void)
+static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
{
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
@@ -801,7 +814,7 @@ static void sunxi_tvencoder_mode_set(void)
/* Clock on */
setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
- switch (sunxi_display.monitor) {
+ switch (monitor) {
case sunxi_monitor_vga:
tvencoder_mode_set(tve, tve_mode_vga);
break;
@@ -896,26 +909,28 @@ static void sunxi_engines_init(void)
sunxi_drc_init();
}
-static void sunxi_mode_set(const struct ctfb_res_modes *mode,
+static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display,
+ const struct ctfb_res_modes *mode,
unsigned int address)
{
+ enum sunxi_monitor monitor = sunxi_display->monitor;
int __maybe_unused clk_div, clk_double;
struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
struct sunxi_tve_reg * __maybe_unused const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- switch (sunxi_display.monitor) {
+ switch (sunxi_display->monitor) {
case sunxi_monitor_none:
break;
case sunxi_monitor_dvi:
case sunxi_monitor_hdmi:
#ifdef CONFIG_VIDEO_HDMI
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
- sunxi_hdmi_mode_set(mode, clk_div, clk_double);
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
+ sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
sunxi_hdmi_enable();
#endif
break;
@@ -930,7 +945,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
axp_set_eldo(3, 1800);
anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
ANX9804_DATA_RATE_1620M,
- sunxi_display.depth);
+ sunxi_display->depth);
}
if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
mdelay(50); /* Wait for lcd controller power on */
@@ -942,10 +957,10 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
i2c_set_bus_num(orig_i2c_bus);
}
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon0_mode_set(mode, false);
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
#ifdef CONFIG_VIDEO_LCD_SSD2828
sunxi_ssd2828_init(mode);
#endif
@@ -953,17 +968,17 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
break;
case sunxi_monitor_vga:
#ifdef CONFIG_VIDEO_VGA
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
- sunxi_tvencoder_mode_set();
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
+ sunxi_tvencoder_mode_set(monitor);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
tvencoder_enable(tve);
#elif defined CONFIG_VIDEO_VGA_VIA_LCD
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon0_mode_set(mode, true);
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
sunxi_vga_external_dac_enable();
#endif
break;
@@ -972,11 +987,11 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
case sunxi_monitor_composite_pal_m:
case sunxi_monitor_composite_pal_nc:
#ifdef CONFIG_VIDEO_COMPOSITE
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
- sunxi_tvencoder_mode_set();
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
+ sunxi_tvencoder_mode_set(monitor);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
tvencoder_enable(tve);
#endif
break;
@@ -999,11 +1014,6 @@ static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
}
}
-ulong board_get_usable_ram_top(ulong total_size)
-{
- return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
-}
-
static bool sunxi_has_hdmi(void)
{
#ifdef CONFIG_VIDEO_HDMI
@@ -1052,9 +1062,11 @@ static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
return sunxi_monitor_none;
}
-void *video_hw_init(void)
+static int sunxi_de_probe(struct udevice *dev)
{
- static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct sunxi_display_priv *sunxi_display = dev_get_priv(dev);
const struct ctfb_res_modes *mode;
struct ctfb_res_modes custom;
const char *options;
@@ -1067,10 +1079,8 @@ void *video_hw_init(void)
char mon[16];
char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
- memset(&sunxi_display, 0, sizeof(struct sunxi_display));
-
video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
- &sunxi_display.depth, &options);
+ &sunxi_display->depth, &options);
#ifdef CONFIG_VIDEO_HDMI
hpd = video_get_option_int(options, "hpd", 1);
hpd_delay = video_get_option_int(options, "hpd_delay", 500);
@@ -1078,35 +1088,35 @@ void *video_hw_init(void)
#endif
overscan_x = video_get_option_int(options, "overscan_x", -1);
overscan_y = video_get_option_int(options, "overscan_y", -1);
- sunxi_display.monitor = sunxi_get_default_mon(true);
+ sunxi_display->monitor = sunxi_get_default_mon(true);
video_get_option_string(options, "monitor", mon, sizeof(mon),
- sunxi_get_mon_desc(sunxi_display.monitor));
+ sunxi_get_mon_desc(sunxi_display->monitor));
for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
- sunxi_display.monitor = i;
+ sunxi_display->monitor = i;
break;
}
}
if (i > SUNXI_MONITOR_LAST)
printf("Unknown monitor: '%s', falling back to '%s'\n",
- mon, sunxi_get_mon_desc(sunxi_display.monitor));
+ mon, sunxi_get_mon_desc(sunxi_display->monitor));
#ifdef CONFIG_VIDEO_HDMI
/* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
- if (sunxi_display.monitor == sunxi_monitor_dvi ||
- sunxi_display.monitor == sunxi_monitor_hdmi) {
+ if (sunxi_display->monitor == sunxi_monitor_dvi ||
+ sunxi_display->monitor == sunxi_monitor_hdmi) {
/* Always call hdp_detect, as it also enables clocks, etc. */
hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
if (hdmi_present && edid) {
printf("HDMI connected: ");
- if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
+ if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
mode = &custom;
else
hdmi_present = false;
}
/* Fall back to EDID in case HPD failed */
if (edid && !hdmi_present) {
- if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
+ if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
mode = &custom;
hdmi_present = true;
}
@@ -1114,38 +1124,39 @@ void *video_hw_init(void)
/* Shut down when display was not found */
if ((hpd || edid) && !hdmi_present) {
sunxi_hdmi_shutdown();
- sunxi_display.monitor = sunxi_get_default_mon(false);
+ sunxi_display->monitor = sunxi_get_default_mon(false);
} /* else continue with hdmi/dvi without a cable connected */
}
#endif
- switch (sunxi_display.monitor) {
+ switch (sunxi_display->monitor) {
case sunxi_monitor_none:
- return NULL;
+ printf("Unknown monitor\n");
+ return -EINVAL;
case sunxi_monitor_dvi:
case sunxi_monitor_hdmi:
if (!sunxi_has_hdmi()) {
printf("HDMI/DVI not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display->monitor = sunxi_monitor_none;
+ return -EINVAL;
}
break;
case sunxi_monitor_lcd:
if (!sunxi_has_lcd()) {
printf("LCD not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display->monitor = sunxi_monitor_none;
+ return -EINVAL;
}
- sunxi_display.depth = video_get_params(&custom, lcd_mode);
+ sunxi_display->depth = video_get_params(&custom, lcd_mode);
mode = &custom;
break;
case sunxi_monitor_vga:
if (!sunxi_has_vga()) {
printf("VGA not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display->monitor = sunxi_monitor_none;
+ return -EINVAL;
}
- sunxi_display.depth = 18;
+ sunxi_display->depth = 18;
break;
case sunxi_monitor_composite_pal:
case sunxi_monitor_composite_ntsc:
@@ -1153,85 +1164,99 @@ void *video_hw_init(void)
case sunxi_monitor_composite_pal_nc:
if (!sunxi_has_composite()) {
printf("Composite video not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display->monitor = sunxi_monitor_none;
+ return -EINVAL;
}
- if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
- sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
+ if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
+ sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
mode = &composite_video_modes[0];
else
mode = &composite_video_modes[1];
- sunxi_display.depth = 24;
+ sunxi_display->depth = 24;
break;
}
/* Yes these defaults are quite high, overscan on composite sucks... */
if (overscan_x == -1)
- overscan_x = sunxi_is_composite() ? 32 : 0;
+ overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
if (overscan_y == -1)
- overscan_y = sunxi_is_composite() ? 20 : 0;
+ overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
- sunxi_display.fb_size =
- (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
+ sunxi_display->fb_size = plat->size;
overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
/* We want to keep the fb_base for simplefb page aligned, where as
* the sunxi dma engines will happily accept an unaligned address. */
if (overscan_offset)
- sunxi_display.fb_size += 0x1000;
-
- if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
- printf("Error need %dkB for fb, but only %dkB is reserved\n",
- sunxi_display.fb_size >> 10,
- CONFIG_SUNXI_MAX_FB_SIZE >> 10);
- return NULL;
- }
+ sunxi_display->fb_size += 0x1000;
printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
mode->xres, mode->yres,
(mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
- sunxi_get_mon_desc(sunxi_display.monitor),
+ sunxi_get_mon_desc(sunxi_display->monitor),
overscan_x, overscan_y);
- gd->fb_base = gd->bd->bi_dram[0].start +
- gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+ sunxi_display->fb_addr = plat->base;
sunxi_engines_init();
#ifdef CONFIG_EFI_LOADER
- efi_add_memory_map(gd->fb_base, sunxi_display.fb_size,
+ efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
EFI_RESERVED_MEMORY_TYPE);
#endif
- fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
- sunxi_display.fb_addr = gd->fb_base;
+ fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE;
if (overscan_offset) {
fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
- sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
- memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
- flush_cache(gd->fb_base, sunxi_display.fb_size);
+ sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000);
+ memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
+ flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
}
- sunxi_mode_set(mode, fb_dma_addr);
+ sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
- /*
- * These are the only members of this structure that are used. All the
- * others are driver specific. The pitch is stored in plnSizeX.
- */
- graphic_device->frameAdrs = sunxi_display.fb_addr;
- graphic_device->gdfIndex = GDF_32BIT_X888RGB;
- graphic_device->gdfBytesPP = 4;
- graphic_device->winSizeX = mode->xres - 2 * overscan_x;
- graphic_device->winSizeY = mode->yres - 2 * overscan_y;
- graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
-
- return graphic_device;
+ /* The members of struct video_priv to be set by the driver. */
+ uc_priv->bpix = VIDEO_BPP32;
+ uc_priv->xsize = mode->xres;
+ uc_priv->ysize = mode->yres;
+
+ video_set_flush_dcache(dev, true);
+
+ return 0;
}
+static int sunxi_de_bind(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP);
+
+ return 0;
+}
+
+static const struct video_ops sunxi_de_ops = {
+};
+
+U_BOOT_DRIVER(sunxi_de) = {
+ .name = "sunxi_de",
+ .id = UCLASS_VIDEO,
+ .ops = &sunxi_de_ops,
+ .bind = sunxi_de_bind,
+ .probe = sunxi_de_probe,
+ .priv_auto = sizeof(struct sunxi_display_priv),
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRVINFO(sunxi_de) = {
+ .name = "sunxi_de"
+};
+
/*
* Simplefb support.
*/
#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
int sunxi_simplefb_setup(void *blob)
{
- static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+ struct sunxi_display_priv *sunxi_display;
+ struct video_priv *uc_priv;
+ struct udevice *de;
int offset, ret;
u64 start, size;
const char *pipeline = NULL;
@@ -1242,7 +1267,19 @@ int sunxi_simplefb_setup(void *blob)
#define PIPELINE_PREFIX
#endif
- switch (sunxi_display.monitor) {
+ ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
+ if (ret) {
+ printf("DE not present\n");
+ return 0;
+ } else if (!device_active(de)) {
+ printf("DE is present but not probed\n");
+ return 0;
+ }
+
+ uc_priv = dev_get_uclass_priv(de);
+ sunxi_display = dev_get_priv(de);
+
+ switch (sunxi_display->monitor) {
case sunxi_monitor_none:
return 0;
case sunxi_monitor_dvi:
@@ -1280,16 +1317,17 @@ int sunxi_simplefb_setup(void *blob)
* linux/arch/arm/mm/ioremap.c around line 301.
*/
start = gd->bd->bi_dram[0].start;
- size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+ size = sunxi_display->fb_addr - start;
ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
if (ret) {
eprintf("Cannot setup simplefb: Error reserving memory\n");
return ret;
}
- ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
- graphic_device->winSizeX, graphic_device->winSizeY,
- graphic_device->plnSizeX, "x8r8g8b8");
+ ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
+ uc_priv->xsize, uc_priv->ysize,
+ VNBYTES(uc_priv->bpix) * uc_priv->xsize,
+ "x8r8g8b8");
if (ret)
eprintf("Cannot setup simplefb: Error setting properties\n");
diff --git a/drivers/video/tegra124/sor.c b/drivers/video/tegra124/sor.c
index 95976ee5735..ef1a2e6dc0f 100644
--- a/drivers/video/tegra124/sor.c
+++ b/drivers/video/tegra124/sor.c
@@ -671,8 +671,8 @@ static void tegra_dc_sor_config_panel(struct tegra_dc_sor_data *sor,
CSTM_ROTCLK_DEFAULT_MASK |
CSTM_LVDS_EN_ENABLE,
2 << CSTM_ROTCLK_SHIFT |
- is_lvds ? CSTM_LVDS_EN_ENABLE :
- CSTM_LVDS_EN_DISABLE);
+ (is_lvds ? CSTM_LVDS_EN_ENABLE :
+ CSTM_LVDS_EN_DISABLE));
tegra_dc_sor_config_pwm(sor, 1024, 1024);
}
diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c
index 66de22318f2..1e6f07ff4b0 100644
--- a/drivers/video/video_bmp.c
+++ b/drivers/video/video_bmp.c
@@ -328,7 +328,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
for (j = 0; j < width; j++)
fb_put_word(&fb, &bmap);
- bmap += (padded_width - width) * 2;
+ bmap += (padded_width - width);
fb -= width * 2 + priv->line_length;
}
break;
@@ -352,7 +352,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
}
}
fb -= priv->line_length + width * (bpix / 8);
- bmap += (padded_width - width) * 3;
+ bmap += (padded_width - width);
}
break;
#endif /* CONFIG_BMP_24BPP */