From 7fe2ebf3a326026b9ab80ed94da3cd217c84724d Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:46 +0100 Subject: [PATCH 01/16] rockchip: video: vop: Use endpoint compatible string to find VOP mode The current code is using an hard coded enum and the of node reg value of endpoint to find out if the endpoint is mipi/hdmi/lvds/edp/dp. The order is different between rk3288, rk3399 vop little, rk3399 vop big. A possible solution would be to make sure that the rk3288.dtsi and rk3399.dtsi files have "expected" reg value or an other solution is to find the kind of endpoint by comparing the endpoint compatible value. This patch is implementing the more flexible second solution. Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- .../include/asm/arch-rockchip/vop_rk3288.h | 15 +---------- drivers/video/rockchip/rk_vop.c | 25 +++++++++++++++++-- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h index 52446e97c6..49a7141437 100644 --- a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h +++ b/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) diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index 145c333020..145a34084c 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -236,12 +236,11 @@ 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; debug("%s(%s, %lu, %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 +282,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); From 04d67ceb1c62012822430135be31e18c9c176d85 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:47 +0100 Subject: [PATCH 02/16] rockchip: video: edp: Add rk3399 support According to linux commit "drm/rockchip: analogix_dp: add rk3399 eDP support" (82872e42bb1501dd9e60ca430f4bae45a469aa64), rk3288 and rk3399 eDP IPs are nearly the same, the difference is in the grf register (SOC_CON6 versus SOC_CON20). So, change the code to use the right register on each IP. The clocks don't seem to be the same, the eDP clock is not at index 1 on rk3399, so don't try changing the clock at index 1 to rate 0 on rk3399. Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- .../include/asm/arch-rockchip/edp_rk3288.h | 5 +- drivers/video/rockchip/rk_edp.c | 85 ++++++++++++++----- 2 files changed, 68 insertions(+), 22 deletions(-) diff --git a/arch/arm/include/asm/arch-rockchip/edp_rk3288.h b/arch/arm/include/asm/arch-rockchip/edp_rk3288.h index 94e5bb674f..26ab9b7225 100644 --- a/arch/arm/include/asm/arch-rockchip/edp_rk3288.h +++ b/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) diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c index 0be60e169e..6baee7b890 100644 --- a/drivers/video/rockchip/rk_edp.c +++ b/drivers/video/rockchip/rk_edp.c @@ -17,11 +17,10 @@ #include #include #include +#include #include #include -#include -#include -#include +#include #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 @@ -37,18 +36,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, ®s->analog_ctl_2); - writel(REF_CLK_24M, ®s->pll_reg_1); + u32 reg; + + reg = REF_CLK_24M; + if (chip_type == RK3288_DP) + reg ^= REF_CLK_MASK; + writel(reg, ®s->pll_reg_1); + writel(LDO_OUTPUT_V_SEL_145 | KVCO_DEFALUT | CHG_PUMP_CUR_SEL_5US | V2L_CUR_SEL_1MA, ®s->pll_reg_2); @@ -1029,6 +1052,8 @@ 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 clk clk; int ret; @@ -1043,16 +1068,17 @@ static int rk_edp_probe(struct udevice *dev) int vop_id = uc_plat->source_id; debug("%s, uc_plat=%p, vop_id=%u\n", __func__, uc_plat, vop_id); - ret = clk_get_by_index(dev, 1, &clk); - if (ret >= 0) { - ret = clk_set_rate(&clk, 0); - clk_free(&clk); + 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; + } } - 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 +1091,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 +1117,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 }, { } }; From ead61b8f7331ecbe95e0345365a1f1094465b6b4 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:48 +0100 Subject: [PATCH 03/16] Rockchip: video: edp: Change interrupt polarity configuration The linux code is setting polarity configuration to 3 but uboot code is setting it to 1. Change the configuration to match the linux configuration Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- arch/arm/include/asm/arch-rockchip/edp_rk3288.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/arch-rockchip/edp_rk3288.h b/arch/arm/include/asm/arch-rockchip/edp_rk3288.h index 26ab9b7225..9559813e52 100644 --- a/arch/arm/include/asm/arch-rockchip/edp_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/edp_rk3288.h @@ -297,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) From decbc18ed2a9788fcaad3ca349def7bad36741f4 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:49 +0100 Subject: [PATCH 04/16] Rockchip: video: vop: Reserve efi fb memory When booting with EFI and graphics, the memory used for framebuffer has to be reserved, otherwise it may leads to kernel memory overwrite. Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- drivers/video/rockchip/rk_vop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index 145a34084c..3eb5e8c25c 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -395,6 +397,11 @@ int rk_vop_probe(struct udevice *dev) if (!(gd->flags & GD_FLG_RELOC)) return 0; +#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); /* From a0c248ef0844da239096ecb4a83f9fa2b0535117 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:50 +0100 Subject: [PATCH 05/16] rockchip: Pinebook Pro: Enable edp - uboot rockchip edp code is looking for a rockchip,panel property for the edp dts node, so add it. Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- arch/arm/dts/rk3399-pinebook-pro-u-boot.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/dts/rk3399-pinebook-pro-u-boot.dtsi b/arch/arm/dts/rk3399-pinebook-pro-u-boot.dtsi index 1eafb40ce3..2d87bea933 100644 --- a/arch/arm/dts/rk3399-pinebook-pro-u-boot.dtsi +++ b/arch/arm/dts/rk3399-pinebook-pro-u-boot.dtsi @@ -16,6 +16,10 @@ }; }; +&edp { + rockchip,panel = <&edp_panel>; +}; + &i2c0 { u-boot,dm-pre-reloc; }; From 4db3926874a6a17cca1f97a4fd92e58e9182a272 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:51 +0100 Subject: [PATCH 06/16] rockchip: pwm: Fix default polarity In the code, the default polarity is set to positive/positive, which is neither normal polarity or inverted polarity. It's only the hardware default. This leads to booting linux with wrong polarity setting. Update the code to use PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE by default instead. Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- drivers/pwm/rk_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c index 9cf0980345..071eb04fda 100644 --- a/drivers/pwm/rk_pwm.c +++ b/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; } From 3fd64112cea5d5182e08698fb53ffd1589896086 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:52 +0100 Subject: [PATCH 07/16] rockchip: video: vop: Fix format of fbbase in debug string The debug string printing the device name, framebuffer address and of node is using %lu as format for the framebuffer address, which is not so nice. Change it to %lx. Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- drivers/video/rockchip/rk_vop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index 3eb5e8c25c..030fc5e66c 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -240,7 +240,7 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) ofnode remote; const char *compat; - 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)); ret = ofnode_read_u32(ep_node, "remote-endpoint", &remote_phandle); From cd529f7ad628f0632313082e237352392e0a47a3 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:53 +0100 Subject: [PATCH 08/16] rockchip: video: edp: Add missing reset support In order to ensure that the eDP registers are in correct state, add missing support for the eDP reset lines found in the device-tree. Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- drivers/video/rockchip/rk_edp.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c index 6baee7b890..0ddf5e02d6 100644 --- a/drivers/video/rockchip/rk_edp.c +++ b/drivers/video/rockchip/rk_edp.c @@ -8,11 +8,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -1053,6 +1055,7 @@ static int rk_edp_probe(struct udevice *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; @@ -1065,6 +1068,25 @@ static int rk_edp_probe(struct udevice *dev) return ret; } + 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 = 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) { + 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); From 9749d2ea29e1a535c9ea8f850db8b6abe6df7b15 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 5 Mar 2021 11:27:54 +0100 Subject: [PATCH 09/16] rockchip: video: vop: Add reset support In order to ensure that the VOP registers are in correct state, add missing support for the VOP reset lines found in the device-tree Signed-off-by: Arnaud Patard Tested-by: Peter Robinson --- drivers/video/rockchip/rk_vop.c | 50 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index 030fc5e66c..fe0574870f 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -8,9 +8,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -37,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), ®s->win0_act_info); @@ -92,6 +96,18 @@ static void rkvop_enable(struct rk3288_vop *regs, ulong fbbase, writel(fbbase, ®s->win0_yrgb_mst); writel(0x01, ®s->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, @@ -239,6 +255,7 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node) enum video_log2_bpp l2bpp; ofnode remote; const char *compat; + struct reset_ctl dclk_rst; debug("%s(%s, 0x%lx, %s)\n", __func__, dev_read_name(dev), fbbase, ofnode_get_name(ep_node)); @@ -355,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) @@ -392,11 +416,31 @@ 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); From fefa713b1843cf13d3132bfe0cf27710938c5d92 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Thu, 22 Oct 2020 23:49:26 +0300 Subject: [PATCH 10/16] video: backlight: Support PWMs without a known period_ns The PWM device provided by Chrome OS EC doesn't really support anything other than setting a relative duty cycle. To support it as a backlight, this patch makes the PWM period optional in the device tree and pretends the valid brightness range is its period_ns. Also adds a sandbox test for a PWM channel that has a fixed period, checking that the resulting duty_cycle matches on a set_config() even if the requested period_ns can't be set. Signed-off-by: Alper Nebi Yasak Reviewed-by: Simon Glass --- drivers/pwm/sandbox_pwm.c | 11 +++++++++-- drivers/video/pwm_backlight.c | 20 ++++++++++++++------ include/pwm.h | 8 ++++++++ test/dm/pwm.c | 11 +++++++++++ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/drivers/pwm/sandbox_pwm.c b/drivers/pwm/sandbox_pwm.c index 318dce7c14..4df15f0a2e 100644 --- a/drivers/pwm/sandbox_pwm.c +++ b/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; } diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c index 9e32bc47cf..4c86215bd7 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/include/pwm.h b/include/pwm.h index f9959706ce..668551e4b8 100644 --- a/include/pwm.h +++ b/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 diff --git a/test/dm/pwm.c b/test/dm/pwm.c index 0de6dba1ba..b624cf3d65 100644 --- a/test/dm/pwm.c +++ b/test/dm/pwm.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -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)); From 1b9ee2882e6bd1c17ab2ec86249aa0347af68242 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Thu, 22 Oct 2020 23:49:27 +0300 Subject: [PATCH 11/16] pwm: Add a driver for Chrome OS EC PWM This PWM is used in rk3399-gru-bob and rk3399-gru-kevin to control the display brightness. We can only change the duty cycle, so on set_config() we just try to match the duty cycle that dividing duty_ns by period_ns gives us. To disable, we set the duty cycle to zero while keeping the old value for when we want to re-enable it. The cros_ec_set_pwm_duty() function is taken from Depthcharge's cros_ec_set_bl_pwm_duty() but modified to use the generic pwm type. The driver itself is very loosely based on rk_pwm.c for the general pwm driver structure. The devicetree binding file is from Linux, before it was converted to YAML at 5df5a577a6b4 ("dt-bindings: pwm: Convert google,cros-ec-pwm.txt to YAML format") in their repo. Signed-off-by: Alper Nebi Yasak Reviewed-by: Simon Glass --- doc/device-tree-bindings/pwm/cros-ec-pwm.txt | 23 ++++++ drivers/misc/cros_ec.c | 17 ++++ drivers/pwm/Kconfig | 9 +++ drivers/pwm/Makefile | 1 + drivers/pwm/cros_ec_pwm.c | 84 ++++++++++++++++++++ include/cros_ec.h | 13 +++ 6 files changed, 147 insertions(+) create mode 100644 doc/device-tree-bindings/pwm/cros-ec-pwm.txt create mode 100644 drivers/pwm/cros_ec_pwm.c diff --git a/doc/device-tree-bindings/pwm/cros-ec-pwm.txt b/doc/device-tree-bindings/pwm/cros-ec-pwm.txt new file mode 100644 index 0000000000..f198d08891 --- /dev/null +++ b/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>; + }; + }; diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index ebfa7c41c2..7904d5cc72 100644 --- a/drivers/misc/cros_ec.c +++ b/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; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index ccf81abbe9..cf7f4c6840 100644 --- a/drivers/pwm/Kconfig +++ b/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 diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 0b9d2698a3..10d244bfb7 100644 --- a/drivers/pwm/Makefile +++ b/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 diff --git a/drivers/pwm/cros_ec_pwm.c b/drivers/pwm/cros_ec_pwm.c new file mode 100644 index 0000000000..44f4105dfd --- /dev/null +++ b/drivers/pwm/cros_ec_pwm.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include +#include + +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), +}; diff --git a/include/cros_ec.h b/include/cros_ec.h index eddc23d48f..9396b4d246 100644 --- a/include/cros_ec.h +++ b/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 * From 1bed576d4144236f280427420296c3590d360729 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Wed, 3 Mar 2021 14:46:47 +1100 Subject: [PATCH 12/16] video: SIMPLE_PANEL depends on DM_GPIO SIMPLE_PANEL currently only depends on PANEL && BACKLIGHT, but the code makes references to dm_gpio_set_value and gpio_request_by_name. These are defined in drivers/gpio/gpio-uclass.c, so a dependency on DM_GPIO corrects these link errors: aarch64-linux-gnu-ld.bfd: drivers/built-in.o: in function `simple_panel_set_backlight': /home/kameliya/u-boot/drivers/video/simple_panel.c:42: undefined reference to `dm_gpio_set_value' aarch64-linux-gnu-ld.bfd: drivers/built-in.o: in function `simple_panel_enable_backlight': /home/kameliya/u-boot/drivers/video/simple_panel.c:27: undefined reference to `dm_gpio_set_value' aarch64-linux-gnu-ld.bfd: drivers/built-in.o: in function `simple_panel_of_to_plat': /home/kameliya/u-boot/drivers/video/simple_panel.c:72: undefined reference to `gpio_request_by_name' This issue is only exposed if you have a board which enables CONFIG_DM_VIDEO without CONFIG_DM_GPIO; so far, none do, but soon a QEMU board may. Signed-off-by: Asherah Connor --- drivers/video/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 63ae2ba43c..b69ffcae4b 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 From ff4e1e277f99109fb7ec9a94d075025c38479f87 Mon Sep 17 00:00:00 2001 From: Trevor Woerner Date: Mon, 15 Mar 2021 18:52:45 -0400 Subject: [PATCH 13/16] finish removing mb862xx video driver drivers/video/mb862xx.c was removed in commit 9c1e098fb92de38f0017585658dd50c3009c84ab from December 2020, however, this last little remnant in drivers/video/cfb_console.c remained. Signed-off-by: Trevor Woerner --- drivers/video/cfb_console.c | 14 -------------- scripts/config_whitelist.txt | 1 - 2 files changed, 15 deletions(-) diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 27ff7163f3..1f491a48d6 100644 --- a/drivers/video/cfb_console.c +++ b/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) */ diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 6859d17654..39e6416afc 100644 --- a/scripts/config_whitelist.txt +++ b/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 From 83064c27063dbc969477eda6a924f1418dc63991 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 9 Apr 2021 18:02:06 +0200 Subject: [PATCH 14/16] board_f: cosmetic: change the debug trace to KB in reserve_video Update the debug trace for the reserved video memory to KB as indicated in the message with "%luk"; before the patch the computed size gd->relocaddr - addr is in bytes. This patch aligns the debug trace in reserve_video() with others functions, for example on stm32mp157c-dk2: - Reserving 3080192k for video at: dfd00000 + Reserving 3008k for video at: dfd00000 Reserving 873k for U-Boot at: dfc25000 Reserving 32776k for malloc() at: ddc23000 Reserving 72 Bytes for Board Info at: ddc22fb0 Reserving 280 Bytes for Global Data at: ddc22e90 Reserving 119072 Bytes for FDT at: ddc05d70 Reserving 0x278 Bytes for bootstage at: ddc05af0 Fixes: 5630d2fbc50f3035 ("board: Show memory for frame buffers") Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- common/board_f.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/board_f.c b/common/board_f.c index 0cddf0359d..203e965799 100644 --- a/common/board_f.c +++ b/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 From 131c224168c63e22570b84f757ccf2c8898a1a1a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 5 Apr 2021 01:48:51 +0200 Subject: [PATCH 15/16] tegra: video: fix tegra_dc_sor_config_panel() Bitwise OR has a higher operator precedence than the ternary conditional. Add the missing parentheses. Signed-off-by: Heinrich Schuchardt --- drivers/video/tegra124/sor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/tegra124/sor.c b/drivers/video/tegra124/sor.c index 95976ee573..ef1a2e6dc0 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); } From 38e18d6392fca9f6809cb3079af3069efc3d181f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 1 Dec 2020 12:30:50 +0100 Subject: [PATCH 16/16] video: Fix line padding calculation for 16 and 24 BPP bitmaps Each row in the pixel array in the bitmap file is padded if necessary so the row size is always a multiple of 4 bytes. In current code the complement of row size to a multiple of 4 bytes is further unnecessarily multiplied by the pixel size. This results in incorrect displaying of bitmaps having row size that is not a multiple of 4 bytes. Fix this by removing the unnecessary multiplication. Tested with 24BPP bitmap and XRGB32 display. Signed-off-by: Sylwester Nawrocki Tested-by: Jaehoon Chung --- drivers/video/video_bmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c index 66de22318f..1e6f07ff4b 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 */