[patch 2/8] RFC: drivers/video/rockchip/rk_edp.c: Add rk3399 support
Arnaud Patard (Rtp)
arnaud.patard at rtp-net.org
Fri Oct 23 10:49:47 CEST 2020
Alper Nebi Yasak <alpernebiyasak at gmail.com> writes:
Hi,
> On 25/09/2020 21:36, Arnaud Patard (Rtp) wrote:
>> 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 <arnaud.patard at rtp-net.org>
>> Index: u-boot/drivers/video/rockchip/rk_edp.c
>> ===================================================================
>
> I think instead of supporting both devices in the same driver, it'd be
> cleaner to split chip-specific parts into rk3288_edp.c and rk3399_edp.c
> like the other ones for vop, hdmi, etc; the common parts would stay here
> in rk_edp.c, and maybe a new rk_edp.h.
>From what I understand the 3288 and 3399 are using the same HW IP and
there's no other rk SoC using it. At the beginning of this work I used
#ifdef but in the end I found it was making the code harder to read (and
checkpatch.pl unhappy iirc). I'm also not convinced that splitting for
only two SoCs worths it.
btw, code inside #ifdef tends to bitrot so using runtime detection
will at least give build testing.
>
>> --- u-boot.orig/drivers/video/rockchip/rk_edp.c
>> +++ u-boot/drivers/video/rockchip/rk_edp.c
>> @@ -17,11 +17,10 @@
>> #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 +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
>
> The chip-specific parts could cast the *grf to rk3288_grf/rk3399_grf
> struct pointer and use &grf->soc_con6, &grf->soc_con25 etc. in the
> chip-specific drivers.
>
>> +
>> +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;
>> +};
>
> These wouldn't be necessary as you could hard-code things per-chip, like
> the current code does.
>
>> +
>> 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];
>> };
>
> This would go to a rk_edp.h which would be included from both
> chip-specific .c files.
>
>>
>> -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);
>> +
>
> You can delegate this to the chip-specific drivers with something like
> what rkvop_set_pin_polarity() does. Or you could keep it in the common
> code and just change the definition of the constants with #if based on
> the chip.
>
>>
>> writel(LDO_OUTPUT_V_SEL_145 | KVCO_DEFALUT | CHG_PUMP_CUR_SEL_5US |
>> V2L_CUR_SEL_1MA, ®s->pll_reg_2);
>> @@ -1023,6 +1046,8 @@ static int rk_edp_probe(struct udevice *
>> struct display_plat *uc_plat = dev_get_uclass_platdata(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;
>>
>> @@ -1037,16 +1062,17 @@ static int rk_edp_probe(struct udevice *
>> 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 (ret) {
>> - debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
>> - return ret;
>> + 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;
>> + }
>
> Both these clocks don't look like they're unique to rk3288 but the
> current code that sets them definitely is, could be split out to
> chip-specific drivers.
>
> Maybe you could get and set the clocks by name for both devices in the
> common part while checking at least one of the equivalent clocks were
> set (but the clock driver currently ignores some clocks and e.g. sets
> them to a known constant).
>
I've been wondering a lot about this clock stuff and in the end, choose
to not modify current behaviour. For instance, I'm not sure to
understand why the clock rate is set to 0 and in linux, there's no
difference between 3288 and 3399 clocks handling. I really think that if
the clock part has to change, it has to be in a different patchset than
here.
>> }
>> -
>> ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
>> if (ret >= 0) {
>> ret = clk_set_rate(&clk, 192000000);
>> @@ -1059,15 +1085,17 @@ static int rk_edp_probe(struct udevice *
>> }
>>
>> /* 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);
>>
>
> I think probe() parts upto here would be chip-specific and parts after
> this would be common, but there's also the panel thing at the top...
>
> (You'd also just change the some numbers here with chip-specific
> drivers.)
>
>> 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);
>> @@ -1083,8 +1111,25 @@ static const struct dm_display_ops dp_ro
>> .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 },
>> { }
>> };
>>
>> Index: u-boot/arch/arm/include/asm/arch-rockchip/edp_rk3288.h
>> ===================================================================
>> --- u-boot.orig/arch/arm/include/asm/arch-rockchip/edp_rk3288.h
>> +++ u-boot/arch/arm/include/asm/arch-rockchip/edp_rk3288.h
>> @@ -232,8 +232,9 @@ check_member(rk3288_edp, pll_reg_5, 0xa0
>> #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)
>
> AFAIK the old definitions were already wrong and just happened to work
> because both set bit-0 to 0, which chooses 24M on rk3288, which is what
> was requested anyway. As I said above, you might define the two
> constants here differently with #if defined(CONFIG_ROCKCHIP_RK3399).
why using two set of constants ? there's no difference on linux for
this between rk3399 and rk3288. I'm only fixing things according to
what's done in linux. See
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.{c,h}.
Arnaud
More information about the U-Boot
mailing list