diff --git a/arch/arm64/boot/dts/rockchip/rk3562-virtual-poweroff.dtsi b/arch/arm64/boot/dts/rockchip/rk3562-virtual-poweroff.dtsi new file mode 100644 index 000000000000..02b616abcedd --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3562-virtual-poweroff.dtsi @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + */ +&rockchip_suspend { + status = "okay"; + rockchip,sleep-debug-en = <1>; + rockchip,virtual-poweroff = <1>; + rockchip,sleep-mode-config = < + (0 + | RKPM_SLP_DEEP1_MODE + | RKPM_SLP_PMIC_LP + | RKPM_SLP_HW_PLLS_OFF + | RKPM_SLP_PMUALIVE_32K + //| RKPM_SLP_OSC_DIS + | RKPM_SLP_32K_PVTM + ) + >; + rockchip,wakeup-config = < + (0 + | RKPM_GPIO0_WKUP_EN + | RKPM_CPU0_WKUP_EN + | RKPM_PWM0_WKUP_EN + | RKPM_PWM0_PWR_WKUP_EN + ) + >; +}; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi index 06a1f3b4fab8..4b189c269450 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi @@ -1494,9 +1494,9 @@ }; }; - audio_codec_pmu: audio-codec@20890000 { + audio_codec_pmu: audio-codec@20898000 { compatible = "rockchip,rv1126b-codec", "rockchip,rk3506-codec"; - reg = <0x20890000 0x1000>; + reg = <0x20898000 0x1000>; #sound-dai-cells = <0>; sound-name-prefix = "ACodec_LP"; clocks = <&cru PCLK_AUDIO_ADC_PMU>, <&cru MCLK_AUDIO_ADC_PMU>; diff --git a/arch/arm64/configs/rv1126b_defconfig b/arch/arm64/configs/rv1126b_defconfig index e400425782ce..a8993723222e 100644 --- a/arch/arm64/configs/rv1126b_defconfig +++ b/arch/arm64/configs/rv1126b_defconfig @@ -303,6 +303,7 @@ CONFIG_COMMON_CLK_RK808=y CONFIG_COMMON_CLK_SCMI=y CONFIG_ROCKCHIP_CLK_OUT=y # CONFIG_ROCKCHIP_CLK_PVTM is not set +CONFIG_ROCKCHIP_CLK_PVTPLL=y # CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set # CONFIG_FSL_ERRATUM_A008585 is not set # CONFIG_HISILICON_ERRATUM_161010101 is not set diff --git a/drivers/clk/rockchip/clk-rv1126b.c b/drivers/clk/rockchip/clk-rv1126b.c index 58bfcfe7fe39..03c42a11db5e 100644 --- a/drivers/clk/rockchip/clk-rv1126b.c +++ b/drivers/clk/rockchip/clk-rv1126b.c @@ -1063,7 +1063,7 @@ static void __init rv1126b_clk_init(struct device_node *np) rv1126b_cpuclk_rates, ARRAY_SIZE(rv1126b_cpuclk_rates)); - rockchip_register_softrst(np, CLK_NR_SRST / 16, reg_base + RV1126B_SOFTRST_CON(0), + rockchip_register_softrst(np, DIV_ROUND_UP(CLK_NR_SRST, 16), reg_base + RV1126B_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); rockchip_register_restart_notifier(ctx, RV1126B_GLB_SRST_FST, NULL); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index dca295af0f6e..81c22c3b89be 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -2885,6 +2885,64 @@ void dw_hdmi_qp_set_allm_enable(struct dw_hdmi_qp *hdmi, bool enable) } EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_allm_enable); +/* + * If userspace don't disable hdmi output when hdmi plug out, + * turn off hdmi signal output. Recovering hdmi status that + * before plug out via turn on hdmi signal output and do scdc + * communication when hdmi plug in. + */ +void dw_hdmi_qp_handle_hpd(struct dw_hdmi_qp *hdmi, bool enable) +{ + bool is_hdmi14 = false; + + mutex_lock(&hdmi->mutex); + /* hdmi2.1 don't support keep vop output in current version */ + if (hdmi->hdmi_data.video_mode.mtmdsclock > 600000000) + goto out; + + mutex_lock(&hdmi->audio_mutex); + if (!hdmi->dclk_en) + goto err_dclk; + + if (!enable && !hdmi->disabled) { + hdmi_writel(hdmi, 1, PKTSCHED_PKT_CONTROL0); + hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); + msleep(50); + hdmi->phy.ops->disable(hdmi, hdmi->phy.data); + hdmi->disabled = true; + goto err_dclk; + } + + if (hdmi->hdmi_data.video_mode.mtmdsclock <= 340000000) + is_hdmi14 = true; + + if (enable && hdmi->disabled) { + if (!is_hdmi14) { + drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1); + drm_scdc_set_scrambling(hdmi->ddc, 1); + hdmi_writel(hdmi, 1, SCRAMB_CONFIG0); + /* Wait for resuming transmission of TMDS clock and data */ + msleep(100); + } else { + drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0); + drm_scdc_set_scrambling(hdmi->ddc, 0); + hdmi_writel(hdmi, 0, SCRAMB_CONFIG0); + } + + hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); + hdmi->disabled = false; + msleep(50); + hdmi_writel(hdmi, 2, PKTSCHED_PKT_CONTROL0); + hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); + } + +err_dclk: + mutex_unlock(&hdmi->audio_mutex); +out: + mutex_unlock(&hdmi->mutex); +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_handle_hpd); + static int dw_hdmi_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index ae7d27beb698..5eabbbd03eee 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -1459,6 +1459,7 @@ static void repo_hpd_event(struct work_struct *p_work) change = drm_helper_hpd_irq_event(hdmi->drm_dev); if (change) { dev_dbg(hdmi->dev, "hpd stat changed:%d\n", hdmi->hpd_stat); + dw_hdmi_qp_handle_hpd(hdmi->hdmi_qp, hdmi->hpd_stat); dw_hdmi_qp_cec_set_hpd(hdmi->hdmi_qp, hdmi->hpd_stat, change); } } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index e7fc1c27facd..f74775464357 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -9207,6 +9207,11 @@ static int vop2_calc_if_clk(struct drm_crtc *crtc, const struct vop2_connector_i if (vcstate->dsc_enable) { hdmi_edp_pixclk = vcstate->dsc_cds_clk_rate << 1; hdmi_edp_dclk = vcstate->dsc_cds_clk_rate; + /* + * For HDMI DSC mode, the dclk_out_rate should be the same + * as dclk_core_rate. + */ + dclk_out_rate = dclk_core_rate; } else { hdmi_edp_pixclk = (dclk_core_rate << 1) / K; hdmi_edp_dclk = dclk_core_rate / K; @@ -9284,13 +9289,19 @@ static int vop2_calc_if_clk(struct drm_crtc *crtc, const struct vop2_connector_i } } + /* + * For RK3588, dclk_out is designed for DP, MIPI(both DSC and non-DSC mode) + * and HDMI in DSC mode. + */ if (dclk_core_rate > if_pixclk->rate) { clk_set_rate(dclk_core->hw.clk, dclk_core_rate); - if (output_if_is_mipi(conn_id)) + if (output_if_is_mipi(conn_id) || + (output_if_is_hdmi(conn_id) && vcstate->dsc_enable)) clk_set_rate(dclk_out->hw.clk, dclk_out_rate); ret = vop2_cru_set_rate(if_pixclk, if_dclk); } else { - if (output_if_is_mipi(conn_id)) + if (output_if_is_mipi(conn_id) || + (output_if_is_hdmi(conn_id) && vcstate->dsc_enable)) clk_set_rate(dclk_out->hw.clk, dclk_out_rate); ret = vop2_cru_set_rate(if_pixclk, if_dclk); clk_set_rate(dclk_core->hw.clk, dclk_core_rate); diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 4eda6213174c..09198cba45eb 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -300,6 +300,7 @@ static const struct mfd_cell rk818s[] = { static const struct rk808_reg_data rk801_pre_init_reg[] = { { RK801_SLEEP_CFG_REG, RK801_SLEEP_FUN_MSK, RK801_NONE_FUN }, { RK801_SYS_CFG2_REG, RK801_SLEEP_POL_MSK, RK801_SLEEP_ACT_H }, + { RK801_SYS_CFG2_REG, RK801_RST_MSK, RK801_RST_RESTART_REG }, { RK801_INT_CONFIG_REG, RK801_INT_POL_MSK, RK801_INT_ACT_L }, { RK801_POWER_FPWM_EN_REG, RK801_PLDO_HRDEC_EN, RK801_PLDO_HRDEC_EN }, { RK801_BUCK_DEBUG5_REG, 0xff, 0x54 }, diff --git a/drivers/regulator/rk801-regulator.c b/drivers/regulator/rk801-regulator.c index fa8aaa549e79..489b5eba0305 100644 --- a/drivers/regulator/rk801-regulator.c +++ b/drivers/regulator/rk801-regulator.c @@ -132,7 +132,7 @@ static unsigned int rk801_get_mode(struct regulator_dev *rdev) if (err) return err; - if ((val & pmw_mode_msk) == RK801_FPWM_MODE) + if (val & pmw_mode_msk) return REGULATOR_MODE_FAST; else return REGULATOR_MODE_NORMAL; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 7415f4f63265..068dbb1c8f54 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1977,8 +1977,20 @@ unknown: memset(buf, 0, w_length); buf[5] = 0x01; switch (ctrl->bRequestType & USB_RECIP_MASK) { + /* + * The Microsoft CompatID OS Descriptor Spec(w_index = 0x4) and + * Extended Prop OS Desc Spec(w_index = 0x5) state that the + * HighByte of wValue is the InterfaceNumber and the LowByte is + * the PageNumber. This high/low byte ordering is incorrectly + * documented in the Spec. USB analyzer output on the below + * request packets show the high/low byte inverted i.e LowByte + * is the InterfaceNumber and the HighByte is the PageNumber. + * Since we dont support >64KB CompatID/ExtendedProp descriptors, + * PageNumber is set to 0. Hence verify that the HighByte is 0 + * for below two cases. + */ case USB_RECIP_DEVICE: - if (w_index != 0x4 || (w_value & 0xff)) + if (w_index != 0x4 || (w_value >> 8)) break; buf[6] = w_index; /* Number of ext compat interfaces */ @@ -1994,9 +2006,9 @@ unknown: } break; case USB_RECIP_INTERFACE: - if (w_index != 0x5 || (w_value & 0xff)) + if (w_index != 0x5 || (w_value >> 8)) break; - interface = w_value >> 8; + interface = w_value & 0xFF; if (interface >= MAX_CONFIG_INTERFACES || !os_desc_cfg->interface[interface]) break; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index baf9fab03ff3..a9b8700f17d6 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -353,6 +353,7 @@ bool dw_hdmi_get_output_whether_hdmi(struct dw_hdmi *hdmi); int dw_hdmi_get_output_type_cap(struct dw_hdmi *hdmi); void dw_hdmi_set_cec_adap(struct dw_hdmi *hdmi, struct cec_adapter *adap); void dw_hdmi_qp_set_allm_enable(struct dw_hdmi_qp *hdmi_qp, bool enable); +void dw_hdmi_qp_handle_hpd(struct dw_hdmi_qp *hdmi, bool enable); void dw_hdmi_qp_unbind(struct dw_hdmi_qp *hdmi); struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index fbffa38b061c..565d8ec8edd7 100644 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -124,6 +124,10 @@ enum rk801_reg { #define RK801_SLEEP_POL_MSK BIT(1) #define RK801_SLEEP_ACT_H BIT(1) #define RK801_SLEEP_ACT_L 0 +#define RK801_RST_MSK (0x3 << 4) +#define RK801_RST_RESTART_PMU (0x0 << 4) +#define RK801_RST_RESTART_REG (0x1 << 4) +#define RK801_RST_RESTART_REG_RESETB (0x2 << 4) /* RK801_INT_CONFIG_REG */ #define RK801_INT_POL_MSK BIT(1)