Просмотр исходного кода

Merge tag 'video-2021-07-rc1' of https://source.denx.de/u-boot/custodians/u-boot-video

 - rk3399 eDP support
 - pwm backlight without a known period_ns
 - add Chrome OS EC PWM driver
 - Kconfig SIMPLE_PANEL DM_GPIO dependency
 - remove mb862xx driver remnants
 - fix KiB format in reserve_video() debug trace
 - fix tegra124 sor CSTM LVDS_EN_ENABLE/DISABLE config
 - fix line padding calculation for 16 and 24 BPP bitmaps
Tom Rini 3 лет назад
Родитель
Сommit
c6a4ee2aae

+ 4 - 0
arch/arm/dts/rk3399-pinebook-pro-u-boot.dtsi

@@ -16,6 +16,10 @@
 	};
 };
 
+&edp {
+	rockchip,panel = <&edp_panel>;
+};
+
 &i2c0 {
 	u-boot,dm-pre-reloc;
 };

+ 6 - 3
arch/arm/include/asm/arch-rockchip/edp_rk3288.h

@@ -232,8 +232,9 @@ check_member(rk3288_edp, pll_reg_5, 0xa00);
 #define PD_CH0					(0x1 << 0)
 
 /* pll_reg_1 */
-#define REF_CLK_24M				(0x1 << 1)
-#define REF_CLK_27M				(0x0 << 1)
+#define REF_CLK_24M				(0x1 << 0)
+#define REF_CLK_27M				(0x0 << 0)
+#define REF_CLK_MASK				(0x1 << 0)
 
 /* line_map */
 #define LANE3_MAP_LOGIC_LANE_0			(0x0 << 6)
@@ -296,7 +297,9 @@ check_member(rk3288_edp, pll_reg_5, 0xa00);
 
 /* int_ctl */
 #define SOFT_INT_CTRL				(0x1 << 2)
-#define INT_POL					(0x1 << 0)
+#define INT_POL1				(0x1 << 1)
+#define INT_POL0				(0x1 << 0)
+#define INT_POL					(INT_POL0 | INT_POL1)
 
 /* sys_ctl_1 */
 #define DET_STA					(0x1 << 2)

+ 1 - 14
arch/arm/include/asm/arch-rockchip/vop_rk3288.h

@@ -85,26 +85,13 @@ enum {
 	LB_RGB_1280X8 = 0x5
 };
 
-#if defined(CONFIG_ROCKCHIP_RK3399)
 enum vop_modes {
 	VOP_MODE_EDP = 0,
 	VOP_MODE_MIPI,
 	VOP_MODE_HDMI,
-	VOP_MODE_MIPI1,
-	VOP_MODE_DP,
-	VOP_MODE_NONE,
-};
-#else
-enum vop_modes {
-	VOP_MODE_EDP = 0,
-	VOP_MODE_HDMI,
 	VOP_MODE_LVDS,
-	VOP_MODE_MIPI,
-	VOP_MODE_NONE,
-	VOP_MODE_AUTO_DETECT,
-	VOP_MODE_UNKNOWN,
+	VOP_MODE_DP,
 };
-#endif
 
 /* VOP_VERSION_INFO */
 #define M_FPGA_VERSION (0xffff << 16)

+ 1 - 1
common/board_f.c

@@ -394,7 +394,7 @@ static int reserve_video(void)
 	if (ret)
 		return ret;
 	debug("Reserving %luk for video at: %08lx\n",
-	      (unsigned long)gd->relocaddr - addr, addr);
+	      ((unsigned long)gd->relocaddr - addr) >> 10, addr);
 	gd->relocaddr = addr;
 #elif defined(CONFIG_LCD)
 #  ifdef CONFIG_FB_ADDR

+ 23 - 0
doc/device-tree-bindings/pwm/cros-ec-pwm.txt

@@ -0,0 +1,23 @@
+PWM controlled by ChromeOS EC
+
+Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller
+(EC) and controlled via a host-command interface.
+
+An EC PWM node should be only found as a sub-node of the EC node (see
+doc/device-tree-bindings/misc/cros-ec.txt).
+
+Required properties:
+- compatible: Must contain "google,cros-ec-pwm"
+- #pwm-cells: Should be 1. The cell specifies the PWM index.
+
+Example:
+	cros-ec@0 {
+		compatible = "google,cros-ec-spi";
+
+		...
+
+		cros_ec_pwm: ec-pwm {
+			compatible = "google,cros-ec-pwm";
+			#pwm-cells = <1>;
+		};
+	};

+ 17 - 0
drivers/misc/cros_ec.c

@@ -1170,6 +1170,23 @@ int cros_ec_battery_cutoff(struct udevice *dev, uint8_t flags)
 	return 0;
 }
 
+int cros_ec_set_pwm_duty(struct udevice *dev, uint8_t index, uint16_t duty)
+{
+	struct ec_params_pwm_set_duty p;
+	int ret;
+
+	p.duty = duty;
+	p.pwm_type = EC_PWM_TYPE_GENERIC;
+	p.index = index;
+
+	ret = ec_command(dev, EC_CMD_PWM_SET_DUTY, 0, &p, sizeof(p),
+			 NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 int cros_ec_set_ldo(struct udevice *dev, uint8_t index, uint8_t state)
 {
 	struct ec_params_ldo_set params;

+ 9 - 0
drivers/pwm/Kconfig

@@ -9,6 +9,15 @@ config DM_PWM
 	  frequency/period can be controlled along with the proportion of that
 	  time that the signal is high.
 
+config PWM_CROS_EC
+	bool "Enable support for the Chrome OS EC PWM"
+	depends on DM_PWM
+	help
+	  This PWM is found on several Chrome OS devices and controlled by
+	  the Chrome OS embedded controller. It may be used to control the
+	  screen brightness and/or the keyboard backlight depending on the
+	  device.
+
 config PWM_EXYNOS
 	bool "Enable support for the Exynos PWM"
 	depends on DM_PWM

+ 1 - 0
drivers/pwm/Makefile

@@ -10,6 +10,7 @@
 
 obj-$(CONFIG_DM_PWM)		+= pwm-uclass.o
 
+obj-$(CONFIG_PWM_CROS_EC)	+= cros_ec_pwm.o
 obj-$(CONFIG_PWM_EXYNOS)	+= exynos_pwm.o
 obj-$(CONFIG_PWM_IMX)		+= pwm-imx.o pwm-imx-util.o
 obj-$(CONFIG_PWM_MESON)		+= pwm-meson.o

+ 84 - 0
drivers/pwm/cros_ec_pwm.c

@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <pwm.h>
+
+struct cros_ec_pwm_priv {
+	bool enabled;
+	uint duty;
+};
+
+static int cros_ec_pwm_set_config(struct udevice *dev, uint channel,
+				  uint period_ns, uint duty_ns)
+{
+	struct cros_ec_pwm_priv *priv = dev_get_priv(dev);
+	uint duty;
+	int ret;
+
+	debug("%s: period_ns=%u, duty_ns=%u asked\n", __func__,
+	      period_ns, duty_ns);
+
+	/* No way to set the period, only a relative duty cycle */
+	duty = EC_PWM_MAX_DUTY * duty_ns / period_ns;
+	if (duty > EC_PWM_MAX_DUTY)
+		duty = EC_PWM_MAX_DUTY;
+
+	if (!priv->enabled) {
+		priv->duty = duty;
+		debug("%s: duty=%#x to-be-set\n", __func__, duty);
+		return 0;
+	}
+
+	ret = cros_ec_set_pwm_duty(dev->parent, channel, duty);
+	if (ret) {
+		debug("%s: duty=%#x failed\n", __func__, duty);
+		return ret;
+	}
+
+	priv->duty = duty;
+	debug("%s: duty=%#x set\n", __func__, duty);
+
+	return 0;
+}
+
+static int cros_ec_pwm_set_enable(struct udevice *dev, uint channel,
+				  bool enable)
+{
+	struct cros_ec_pwm_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = cros_ec_set_pwm_duty(dev->parent, channel,
+				   enable ? priv->duty : 0);
+	if (ret) {
+		debug("%s: enable=%d failed\n", __func__, enable);
+		return ret;
+	}
+
+	priv->enabled = enable;
+	debug("%s: enable=%d (duty=%#x) set\n", __func__,
+	      enable, priv->duty);
+
+	return 0;
+}
+
+static const struct pwm_ops cros_ec_pwm_ops = {
+	.set_config	= cros_ec_pwm_set_config,
+	.set_enable	= cros_ec_pwm_set_enable,
+};
+
+static const struct udevice_id cros_ec_pwm_ids[] = {
+	{ .compatible = "google,cros-ec-pwm" },
+	{ }
+};
+
+U_BOOT_DRIVER(cros_ec_pwm) = {
+	.name	= "cros_ec_pwm",
+	.id	= UCLASS_PWM,
+	.of_match = cros_ec_pwm_ids,
+	.ops	= &cros_ec_pwm_ops,
+	.priv_auto_alloc_size	= sizeof(struct cros_ec_pwm_priv),
+};

+ 1 - 1
drivers/pwm/rk_pwm.c

@@ -147,7 +147,7 @@ static int rk_pwm_probe(struct udevice *dev)
 	priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev);
 
 	if (priv->data->supports_polarity)
-		priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
+		priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
 
 	return 0;
 }

+ 9 - 2
drivers/pwm/sandbox_pwm.c

@@ -59,8 +59,15 @@ static int sandbox_pwm_set_config(struct udevice *dev, uint channel,
 	if (channel >= NUM_CHANNELS)
 		return -ENOSPC;
 	chan = &priv->chan[channel];
-	chan->period_ns = period_ns;
-	chan->duty_ns = duty_ns;
+
+	if (channel == 2) {
+		/* Pretend to have some fixed period */
+		chan->period_ns = 4096;
+		chan->duty_ns =  duty_ns * 4096 / period_ns;
+	} else {
+		chan->period_ns = period_ns;
+		chan->duty_ns = duty_ns;
+	}
 
 	return 0;
 }

+ 1 - 1
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

+ 0 - 14
drivers/video/cfb_console.c

@@ -81,20 +81,6 @@
 #define VIDEO_FB_16BPP_WORD_SWAP
 #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)
  */

+ 14 - 6
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];
 

+ 85 - 18
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 },
 	{ }
 };
 

+ 78 - 6
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);
 
 	/*

+ 2 - 2
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);
 }

+ 2 - 2
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 */

+ 13 - 0
include/cros_ec.h

@@ -512,6 +512,19 @@ int cros_ec_efs_verify(struct udevice *dev, enum ec_flash_region region);
  */
 int cros_ec_battery_cutoff(struct udevice *dev, uint8_t flags);
 
+/**
+ * cros_ec_set_pwm_duty() - Set duty cycle of a generic pwm
+ *
+ * Note that duty value needs to be passed to the EC as a 16 bit number
+ * for increased precision.
+ *
+ * @param dev		CROS-EC device
+ * @param index		Index of the pwm
+ * @param duty		Desired duty cycle, in 0..EC_PWM_MAX_DUTY range.
+ * @return 0 if OK, -ve on error
+ */
+int cros_ec_set_pwm_duty(struct udevice *dev, uint8_t index, uint16_t duty);
+
 /**
  * cros_ec_read_limit_power() - Check if power is limited by batter/charger
  *

+ 8 - 0
include/pwm.h

@@ -17,6 +17,10 @@ struct pwm_ops {
 	/**
 	 * set_config() - Set the PWM configuration
 	 *
+	 * Change both the PWM device's period and it's duty period if
+	 * possible. Otherwise, set an appropriate duty period that best
+	 * matches the given period_ns / duty_ns ratio for the device.
+	 *
 	 * @dev:	PWM device to update
 	 * @channel:	PWM channel to update
 	 * @period_ns:	PWM period in nanoseconds
@@ -51,6 +55,10 @@ struct pwm_ops {
 /**
  * pwm_set_config() - Set the PWM configuration
  *
+ * Change both the PWM device's period and it's duty period if
+ * possible. Otherwise, set an appropriate duty period that best
+ * matches the given period_ns / duty_ns ratio for the device.
+ *
  * @dev:	PWM device to update
  * @channel:	PWM channel to update
  * @period_ns:	PWM period in nanoseconds

+ 0 - 1
scripts/config_whitelist.txt

@@ -3939,7 +3939,6 @@ CONFIG_VEXPRESS_EXTENDED_MEMORY_MAP
 CONFIG_VEXPRESS_ORIGINAL_MEMORY_MAP
 CONFIG_VIDEO_BCM2835
 CONFIG_VIDEO_BMP_LOGO
-CONFIG_VIDEO_CORALP
 CONFIG_VIDEO_DA8XX
 CONFIG_VIDEO_FONT_4X6
 CONFIG_VIDEO_LCD_I2C_BUS

+ 11 - 0
test/dm/pwm.c

@@ -6,6 +6,7 @@
 #include <common.h>
 #include <dm.h>
 #include <pwm.h>
+#include <asm/test.h>
 #include <dm/test.h>
 #include <test/test.h>
 #include <test/ut.h>
@@ -14,6 +15,10 @@
 static int dm_test_pwm_base(struct unit_test_state *uts)
 {
 	struct udevice *dev;
+	uint period_ns;
+	uint duty_ns;
+	bool enable;
+	bool polarity;
 
 	ut_assertok(uclass_get_device(UCLASS_PWM, 0, &dev));
 	ut_assertnonnull(dev);
@@ -24,6 +29,12 @@ static int dm_test_pwm_base(struct unit_test_state *uts)
 	ut_asserteq(-ENOSPC, pwm_set_enable(dev, 3, true));
 	ut_assertok(pwm_set_invert(dev, 0, true));
 
+	ut_assertok(pwm_set_config(dev, 2, 100, 50));
+	ut_assertok(sandbox_pwm_get_config(dev, 2, &period_ns, &duty_ns,
+					   &enable, &polarity));
+	ut_asserteq(period_ns, 4096);
+	ut_asserteq(duty_ns, 50 * 4096 / 100);
+
 	ut_assertok(uclass_get_device(UCLASS_PWM, 1, &dev));
 	ut_asserteq(-ENODEV, uclass_get_device(UCLASS_PWM, 2, &dev));