mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 02:21:52 +09:00
Merge commit '4f0e1facb7edb345cf802a564c64dd1300b63308'
* commit '4f0e1facb7edb345cf802a564c64dd1300b63308': drm/rockchip: vop2: Support hdmi fva drm/bridge: synopsys: dw-hdmi-qp: Support qms-vrr drm/rockchip: vop2: Support hdmi qms-vrr drm/rockchip: drv: Support parse vrr capbility in edid scds ARM: dts: rockchip: add rv1126b-evb2-v12-fastboot-spi-nor.dts arm64: dts: rockchip: add rv1126b-evb2-v12-fastboot-spi-nor.dts video: rockchip: rga3: remove useless mutex_unlock ARM: dts: rockchip: add rv1126b-evb2-v12-fastboot-spi-nand.dts arm64: dts: rockchip: add rv1126b-evb2-v12-fastboot-spi-nand.dts net: mac80211: Added p2p0 for ap mode in softmac Change-Id: I26058540b6c918251e8da9791b56491d2aacf5d8
This commit is contained in:
@@ -1202,6 +1202,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
|
||||
rv1126b-evb2-v12.dtb \
|
||||
rv1126b-evb2-v12-aov-dual-cam.dtb \
|
||||
rv1126b-evb2-v12-fastboot-emmc.dtb \
|
||||
rv1126b-evb2-v12-fastboot-spi-nand.dtb \
|
||||
rv1126b-evb2-v12-fastboot-spi-nor.dtb \
|
||||
rv1126b-evb3-v10.dtb \
|
||||
rv1126b-evb4-v10.dtb \
|
||||
rv1126b-iotest-v10.dtb \
|
||||
|
||||
23
arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nand.dts
Normal file
23
arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nand.dts
Normal file
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include "arm64/rockchip/rv1126b-evb2-v12-fastboot-spi-nand.dts"
|
||||
|
||||
/ {
|
||||
model = "Rockchip RV1126B EVB2 V12 Board";
|
||||
compatible = "rockchip,rv1126b-evb2-v12-fastboot-spi-nand", "rockchip,rv1126b";
|
||||
|
||||
chosen {
|
||||
bootargs = "loglevel=0 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K";
|
||||
};
|
||||
};
|
||||
|
||||
&ramdisk_r {
|
||||
reg = <0x48c40000 (40 * 0x00100000)>;
|
||||
};
|
||||
|
||||
&ramdisk_c {
|
||||
reg = <0x4b440000 (20 * 0x00100000)>;
|
||||
};
|
||||
23
arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nor.dts
Normal file
23
arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nor.dts
Normal file
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include "arm64/rockchip/rv1126b-evb2-v12-fastboot-spi-nor.dts"
|
||||
|
||||
/ {
|
||||
model = "Rockchip RV1126B EVB2 V12 Board";
|
||||
compatible = "rockchip,rv1126b-evb2-v12-fastboot-spi-nor", "rockchip,rv1126b";
|
||||
|
||||
chosen {
|
||||
bootargs = "loglevel=0 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K";
|
||||
};
|
||||
};
|
||||
|
||||
&ramdisk_r {
|
||||
reg = <0x48c40000 (20 * 0x00100000)>;
|
||||
};
|
||||
|
||||
&ramdisk_c {
|
||||
reg = <0x4a040000 (10 * 0x00100000)>;
|
||||
};
|
||||
@@ -403,6 +403,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-rgb-Q7050ITH2641AA1T.dtb
|
||||
dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-sii9022-bt1120-to-hdmi.dtb
|
||||
dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12.dtb
|
||||
dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12-fastboot-emmc.dtb
|
||||
dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12-fastboot-spi-nand.dtb
|
||||
dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12-fastboot-spi-nor.dtb
|
||||
dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb3-v10.dtb
|
||||
dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb4-v10.dtb
|
||||
dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-iotest-v10.dtb
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include "rv1126b-evb2-v12.dts"
|
||||
#include "rv1126b-fastboot-spi-nand.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Rockchip RV1126B EVB2 V12 Arm64 Board";
|
||||
compatible = "rockchip,rv1126b-evb2-v12-fastboot-spi-nand", "rockchip,rv1126b";
|
||||
|
||||
chosen {
|
||||
bootargs = "loglevel=0 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K";
|
||||
};
|
||||
};
|
||||
|
||||
&ramdisk_r {
|
||||
reg = <0x48c40000 (40 * 0x00100000)>;
|
||||
};
|
||||
|
||||
&ramdisk_c {
|
||||
reg = <0x4b440000 (20 * 0x00100000)>;
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
#include "rv1126b-evb2-v12.dts"
|
||||
#include "rv1126b-fastboot-spi-nor.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Rockchip RV1126B EVB2 V12 Arm64 Board";
|
||||
compatible = "rockchip,rv1126b-evb2-v12-fastboot-spi-nor", "rockchip,rv1126b";
|
||||
|
||||
chosen {
|
||||
bootargs = "loglevel=0 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K";
|
||||
};
|
||||
};
|
||||
|
||||
&fspi0 {
|
||||
status = "okay";
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <750000000>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-tx-bus-width = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
&ramdisk_r {
|
||||
reg = <0x48c40000 (20 * 0x00100000)>;
|
||||
};
|
||||
|
||||
&ramdisk_c {
|
||||
reg = <0x4a040000 (10 * 0x00100000)>;
|
||||
};
|
||||
@@ -327,6 +327,8 @@ struct dw_hdmi_qp {
|
||||
bool hdr2sdr;
|
||||
bool flt_no_timeout;
|
||||
|
||||
u8 next_tfr;
|
||||
bool m_const;
|
||||
u32 scdc_intr;
|
||||
u32 flt_intr;
|
||||
u32 earc_intr;
|
||||
@@ -1768,6 +1770,67 @@ static void hdmi_config_CVTEM(struct dw_hdmi_qp *hdmi)
|
||||
PKTSCHED_PKT_EN);
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_config_vtem_class1(struct dw_hdmi_qp *hdmi, bool m_const, u8 next_tfr)
|
||||
{
|
||||
struct drm_display_mode *mode = &hdmi->previous_mode;
|
||||
u8 ds_type = 0;
|
||||
u8 sync = 1;
|
||||
u8 vfr = 1;
|
||||
u8 afr = 0;
|
||||
u8 new = 1;
|
||||
u8 end = 1;
|
||||
u8 data_set_length = 4;
|
||||
u8 base_vfp;
|
||||
u16 base_refresh_l, base_refresh_h;
|
||||
u32 val, i;
|
||||
|
||||
if (!next_tfr) {
|
||||
hdmi_modb(hdmi, 0, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_PKT_EN);
|
||||
return;
|
||||
}
|
||||
|
||||
val = 0xc0 << 8;
|
||||
hdmi_writel(hdmi, val, PKT_EMP_VTEM_CONTENTS0);
|
||||
|
||||
val = new << 7 | end << 6 | ds_type << 4 | afr << 3 |
|
||||
vfr << 2 | sync << 1;
|
||||
hdmi_writel(hdmi, val, PKT_EMP_VTEM_CONTENTS1);
|
||||
|
||||
if (m_const)
|
||||
val = 0x6 << 24;
|
||||
else
|
||||
val = 0x4 << 24;
|
||||
|
||||
val |= data_set_length << 16;
|
||||
hdmi_writel(hdmi, val, PKT_EMP_VTEM_CONTENTS2);
|
||||
|
||||
base_vfp = mode->vsync_start - mode->vdisplay;
|
||||
base_refresh_l = drm_mode_vrefresh(mode);
|
||||
base_refresh_h = (base_refresh_l >> 8) & 0x3;
|
||||
base_refresh_l &= 0xff;
|
||||
|
||||
val = base_refresh_l << 16 | next_tfr << 11 | base_refresh_h << 8 | base_vfp;
|
||||
hdmi_writel(hdmi, val, PKT_EMP_VTEM_CONTENTS3);
|
||||
|
||||
for (i = PKT_EMP_VTEM_CONTENTS4; i <= PKT_EMP_VTEM_CONTENTS7; i += 4)
|
||||
hdmi_writel(hdmi, 0, i);
|
||||
|
||||
hdmi_modb(hdmi, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_PKT_EN);
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_config_vtem(struct dw_hdmi_qp *hdmi)
|
||||
{
|
||||
if (hdmi->disabled || !hdmi->dclk_en)
|
||||
return;
|
||||
|
||||
if (!hdmi->next_tfr) {
|
||||
hdmi_modb(hdmi, 0, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_PKT_EN);
|
||||
return;
|
||||
}
|
||||
|
||||
dw_hdmi_qp_config_vtem_class1(hdmi, hdmi->m_const, hdmi->next_tfr);
|
||||
}
|
||||
|
||||
static void hdmi_config_drm_infoframe(struct dw_hdmi_qp *hdmi,
|
||||
const struct drm_connector *connector)
|
||||
{
|
||||
@@ -2588,6 +2651,7 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi,
|
||||
hdmi_config_AVI(hdmi, connector, mode);
|
||||
hdmi_config_vendor_specific_infoframe(hdmi, connector, mode);
|
||||
hdmi_config_CVTEM(hdmi);
|
||||
dw_hdmi_qp_config_vtem_class1(hdmi, hdmi->m_const, hdmi->next_tfr);
|
||||
hdmi_config_drm_infoframe(hdmi, connector);
|
||||
ret = hdmi_set_op_mode(hdmi, link_cfg, connector);
|
||||
if (ret) {
|
||||
@@ -2963,6 +3027,24 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_qp_handle_hpd);
|
||||
|
||||
void dw_hdmi_qp_set_qms(struct dw_hdmi_qp *hdmi, u8 next_tfr, u8 m_const)
|
||||
{
|
||||
if (!hdmi)
|
||||
return;
|
||||
|
||||
hdmi->next_tfr = next_tfr;
|
||||
hdmi->m_const = m_const;
|
||||
|
||||
dw_hdmi_qp_config_vtem(hdmi);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_qms);
|
||||
|
||||
u8 dw_hdmi_qp_get_next_tfr(struct dw_hdmi_qp *hdmi)
|
||||
{
|
||||
return hdmi->next_tfr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_qp_get_next_tfr);
|
||||
|
||||
static int
|
||||
dw_hdmi_atomic_connector_set_property(struct drm_connector *connector,
|
||||
struct drm_connector_state *state,
|
||||
@@ -3468,6 +3550,7 @@ static void dw_hdmi_connector_atomic_commit(struct drm_connector *connector,
|
||||
if (hdmi->hdmi_changed_status & HDMI_VSIF_CHANGED)
|
||||
hdmi_config_vendor_specific_infoframe(hdmi, hdmi->curr_conn,
|
||||
&hdmi->previous_mode);
|
||||
dw_hdmi_qp_config_vtem_class1(hdmi, hdmi->m_const, hdmi->next_tfr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,7 @@
|
||||
#define PKTSCHED_AVI_TX_EN BIT(13)
|
||||
#define PKTSCHED_VSI_TX_EN BIT(12)
|
||||
#define PKTSCHED_EMP_CVTEM_TX_EN BIT(10)
|
||||
#define PKTSCHED_EMP_VTEM_TX_EN BIT(9)
|
||||
#define PKTSCHED_AMD_TX_EN BIT(8)
|
||||
#define PKTSCHED_GCP_TX_EN BIT(3)
|
||||
#define PKTSCHED_AUDS_TX_EN BIT(2)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include <video/display_timing.h>
|
||||
#include <video/videomode.h>
|
||||
@@ -202,6 +203,9 @@
|
||||
#define HDMI20_MAX_RATE 600000
|
||||
#define HDMI_8K60_RATE 2376000
|
||||
|
||||
#define HDMI_MAX_VRR_REFRESH_RATE 120
|
||||
#define HDMI_MIN_VRR_REFRESH_RATE 24
|
||||
|
||||
struct rockchip_hdmi;
|
||||
|
||||
struct rockchip_hdmi_chip_ops {
|
||||
@@ -232,6 +236,15 @@ struct rockchip_hdmi_chip_data {
|
||||
const struct rockchip_hdmi_chip_ops *ops;
|
||||
};
|
||||
|
||||
enum hdmi_vrr_state {
|
||||
VRR_IS_DISABLED = 0,
|
||||
VRR_GOTO_ENABLE,
|
||||
VRR_GOTO_DISABLE,
|
||||
VRR_RATE_CHANGED,
|
||||
VRR_IS_STABLE,
|
||||
VRR_WAIT_REFRESH_CHANGE,
|
||||
};
|
||||
|
||||
enum hdmi_frl_rate_per_lane {
|
||||
FRL_12G_PER_LANE = 12,
|
||||
FRL_10G_PER_LANE = 10,
|
||||
@@ -317,6 +330,7 @@ struct rockchip_hdmi {
|
||||
struct drm_property *hdr_panel_dovi_vsdb;
|
||||
struct drm_property *vsif_data;
|
||||
struct drm_property *hdr10_plus_vsdb;
|
||||
struct drm_property *next_tfr;
|
||||
|
||||
struct drm_property_blob *mode_color_caps_ptr;
|
||||
struct drm_property_blob *hdr_panel_blob_ptr;
|
||||
@@ -329,6 +343,10 @@ struct rockchip_hdmi {
|
||||
unsigned int hdmi_quant_range;
|
||||
unsigned int phy_bus_width;
|
||||
unsigned int enable_allm;
|
||||
u8 next_tfr_val;
|
||||
enum hdmi_vrr_state vrr_state;
|
||||
enum hdmi_vrr_state old_vrr_state;
|
||||
enum TARGET_FRAME_RATE brr_tfr;
|
||||
enum rk_if_color_format hdmi_output;
|
||||
struct rockchip_drm_sub_dev sub_dev;
|
||||
|
||||
@@ -340,7 +358,8 @@ struct rockchip_hdmi {
|
||||
struct dw_hdmi_link_config link_cfg;
|
||||
struct gpio_desc *enable_gpio;
|
||||
|
||||
struct delayed_work work;
|
||||
struct delayed_work hpd_work;
|
||||
struct work_struct qms_vrr_work;
|
||||
struct workqueue_struct *workqueue;
|
||||
struct gpio_desc *hpd_gpiod;
|
||||
struct pinctrl *p;
|
||||
@@ -1466,7 +1485,7 @@ static int rockchip_hdmi_update_phy_table(struct rockchip_hdmi *hdmi,
|
||||
|
||||
static void repo_hpd_event(struct work_struct *p_work)
|
||||
{
|
||||
struct rockchip_hdmi *hdmi = container_of(p_work, struct rockchip_hdmi, work.work);
|
||||
struct rockchip_hdmi *hdmi = container_of(p_work, struct rockchip_hdmi, hpd_work.work);
|
||||
bool change;
|
||||
|
||||
change = drm_helper_hpd_irq_event(hdmi->drm_dev);
|
||||
@@ -1550,7 +1569,7 @@ static irqreturn_t rk3576_hdmi_thread(int irq, void *dev_id)
|
||||
hdmi->hpd_stat = false;
|
||||
msecs = 20;
|
||||
}
|
||||
mod_delayed_work(hdmi->workqueue, &hdmi->work, msecs_to_jiffies(msecs));
|
||||
mod_delayed_work(hdmi->workqueue, &hdmi->hpd_work, msecs_to_jiffies(msecs));
|
||||
|
||||
val = HIWORD_UPDATE(RK3576_HDMITX_HPD_INT_CLR,
|
||||
RK3576_HDMITX_HPD_INT_CLR) |
|
||||
@@ -1595,7 +1614,7 @@ static irqreturn_t rk3588_hdmi_thread(int irq, void *dev_id)
|
||||
hdmi->hpd_stat = false;
|
||||
msecs = 20;
|
||||
}
|
||||
mod_delayed_work(hdmi->workqueue, &hdmi->work, msecs_to_jiffies(msecs));
|
||||
mod_delayed_work(hdmi->workqueue, &hdmi->hpd_work, msecs_to_jiffies(msecs));
|
||||
|
||||
if (!hdmi->id) {
|
||||
val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
|
||||
@@ -1612,10 +1631,217 @@ static irqreturn_t rk3588_hdmi_thread(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void init_hpd_work(struct rockchip_hdmi *hdmi)
|
||||
static int rockchip_hdmi_set_qms_next_tfr(struct rockchip_hdmi *hdmi, u64 val)
|
||||
{
|
||||
hdmi->workqueue = create_workqueue("hpd_queue");
|
||||
INIT_DELAYED_WORK(&hdmi->work, repo_hpd_event);
|
||||
if (!hdmi->next_tfr_val && val) {
|
||||
hdmi->vrr_state = VRR_GOTO_ENABLE;
|
||||
} else if (hdmi->next_tfr_val && !val) {
|
||||
if (hdmi->vrr_state != VRR_IS_STABLE) {
|
||||
DRM_ERROR("qms-vrr is switching, can't disable qms-vrr\n");
|
||||
return -EPERM;
|
||||
}
|
||||
hdmi->vrr_state = VRR_GOTO_DISABLE;
|
||||
} else if (hdmi->next_tfr_val && val && hdmi->next_tfr_val != val) {
|
||||
if (hdmi->vrr_state != VRR_IS_STABLE) {
|
||||
DRM_ERROR("qms-vrr is switching, can't set new next_tfr\n");
|
||||
return -EPERM;
|
||||
}
|
||||
hdmi->vrr_state = VRR_RATE_CHANGED;
|
||||
} else {
|
||||
/* new next_tfr value is the same as the old one */
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdmi->next_tfr_val = (u8)val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_hdmi_get_next_tfr_val(struct drm_display_mode *mode)
|
||||
{
|
||||
u64 val = 0;
|
||||
int i;
|
||||
|
||||
val = (u64)mode->clock * 100000;
|
||||
val = DIV_ROUND_CLOSEST_ULL(val, (mode->htotal * mode->vtotal));
|
||||
|
||||
for (i = 0; i < TFR_MAX; i++) {
|
||||
if (rockchip_hdmi_vrr_tfr_match_to_vrefresh(i) == val)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u32 rockchip_hdmi_get_next_tfr_refresh_val(u8 next_tfr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < TFR_MAX; i++) {
|
||||
if (rockchip_hdmi_vrr_tfr_match_to_vrefresh(i) == next_tfr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == TFR_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return rockchip_hdmi_vrr_tfr_match_to_vrefresh(i);
|
||||
}
|
||||
|
||||
static int rockchip_hdmi_wait_vsync(struct rockchip_hdmi *hdmi, struct drm_crtc *crtc,
|
||||
struct drm_vblank_crtc *vblank, u8 vsync_num, u32 timeout)
|
||||
{
|
||||
int ret, i;
|
||||
u64 last;
|
||||
|
||||
ret = drm_crtc_vblank_get(crtc);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(hdmi->dev, "failed to get vblank\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < vsync_num; i++) {
|
||||
last = drm_crtc_vblank_count(crtc);
|
||||
ret = wait_event_timeout(vblank->queue, last != drm_crtc_vblank_count(crtc),
|
||||
msecs_to_jiffies(timeout));
|
||||
if (!ret) {
|
||||
DRM_DEV_ERROR(hdmi->dev, "vblank wait timed out\n");
|
||||
drm_crtc_vblank_put(crtc);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
drm_crtc_vblank_put(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_hdmi_qms_vrr_enable(struct rockchip_hdmi *hdmi, struct drm_crtc *crtc,
|
||||
struct drm_vblank_crtc *vblank)
|
||||
{
|
||||
u32 timeout = DIV_ROUND_CLOSEST_ULL(1000, drm_mode_vrefresh(&crtc->state->adjusted_mode));
|
||||
int ret;
|
||||
enum TARGET_FRAME_RATE brr_tfr;
|
||||
|
||||
/* init brr */
|
||||
brr_tfr = rockchip_hdmi_get_next_tfr_val(&crtc->state->adjusted_mode);
|
||||
hdmi->brr_tfr = brr_tfr;
|
||||
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, brr_tfr, 1);
|
||||
ret = rockchip_hdmi_wait_vsync(hdmi, crtc, vblank, 2, timeout);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, brr_tfr, 0);
|
||||
ret = rockchip_hdmi_wait_vsync(hdmi, crtc, vblank, 1, timeout);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hdmi->vrr_state = VRR_WAIT_REFRESH_CHANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_hdmi_qms_vrr_set_refresh(struct rockchip_hdmi *hdmi,
|
||||
struct rockchip_crtc_state *vcstate)
|
||||
{
|
||||
if (!vcstate) {
|
||||
DRM_DEV_ERROR(hdmi->dev, "failed to get vcstate\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, hdmi->next_tfr_val, 0);
|
||||
vcstate->hdmi_vrr.refresh_rate_ready_to_change = true;
|
||||
vcstate->hdmi_vrr.next_tfr_val = hdmi->next_tfr_val;
|
||||
|
||||
hdmi->vrr_state = VRR_IS_STABLE;
|
||||
}
|
||||
|
||||
static int rockchip_hdmi_qms_vrr_rate_change(struct rockchip_hdmi *hdmi, struct drm_crtc *crtc,
|
||||
struct drm_vblank_crtc *vblank)
|
||||
{
|
||||
u8 current_tfr = dw_hdmi_qp_get_next_tfr(hdmi->hdmi_qp);
|
||||
u32 next_tfr_refresh_val = rockchip_hdmi_get_next_tfr_refresh_val(current_tfr);
|
||||
u32 timeout = DIV_ROUND_CLOSEST_ULL(100000, next_tfr_refresh_val);
|
||||
int ret;
|
||||
|
||||
ret = rockchip_hdmi_wait_vsync(hdmi, crtc, vblank, 1, timeout);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, current_tfr, 0);
|
||||
|
||||
ret = rockchip_hdmi_wait_vsync(hdmi, crtc, vblank, 1, timeout);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, hdmi->next_tfr_val, 0);
|
||||
hdmi->vrr_state = VRR_WAIT_REFRESH_CHANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_hdmi_qms_vrr_disable(struct rockchip_hdmi *hdmi, struct drm_crtc *crtc,
|
||||
struct drm_vblank_crtc *vblank)
|
||||
{
|
||||
u8 current_tfr = dw_hdmi_qp_get_next_tfr(hdmi->hdmi_qp);
|
||||
u32 next_tfr_refresh_val = rockchip_hdmi_get_next_tfr_refresh_val(current_tfr);
|
||||
u32 timeout = DIV_ROUND_CLOSEST_ULL(100000, next_tfr_refresh_val);
|
||||
int ret;
|
||||
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, hdmi->brr_tfr, 0);
|
||||
hdmi->next_tfr_val = hdmi->brr_tfr;
|
||||
|
||||
hdmi->vrr_state = VRR_WAIT_REFRESH_CHANGE;
|
||||
|
||||
ret = rockchip_hdmi_wait_vsync(hdmi, crtc, vblank, 3, timeout);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, hdmi->brr_tfr, 1);
|
||||
|
||||
ret = rockchip_hdmi_wait_vsync(hdmi, crtc, vblank, 1, timeout);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, 0, 0);
|
||||
|
||||
hdmi->vrr_state = VRR_IS_DISABLED;
|
||||
hdmi->next_tfr_val = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_hdmi_qms_vrr_work(struct work_struct *p_work)
|
||||
{
|
||||
struct rockchip_hdmi *hdmi = container_of(p_work, struct rockchip_hdmi, qms_vrr_work);
|
||||
struct drm_encoder *encoder = &hdmi->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_vblank_crtc *vblank;
|
||||
int pipe = 0;
|
||||
|
||||
if (!encoder || !encoder->crtc) {
|
||||
DRM_DEV_ERROR(hdmi->dev, "can't get crtc\n");
|
||||
return;
|
||||
}
|
||||
|
||||
crtc = encoder->crtc;
|
||||
pipe = drm_crtc_index(crtc);
|
||||
vblank = &crtc->dev->vblank[pipe];
|
||||
|
||||
if (hdmi->vrr_state == VRR_GOTO_ENABLE)
|
||||
rockchip_hdmi_qms_vrr_enable(hdmi, crtc, vblank);
|
||||
else if (hdmi->vrr_state == VRR_GOTO_DISABLE)
|
||||
rockchip_hdmi_qms_vrr_disable(hdmi, crtc, vblank);
|
||||
else
|
||||
rockchip_hdmi_qms_vrr_rate_change(hdmi, crtc, vblank);
|
||||
}
|
||||
|
||||
static void init_hdmi_work(struct rockchip_hdmi *hdmi)
|
||||
{
|
||||
hdmi->workqueue = create_workqueue("hdmi_queue");
|
||||
INIT_DELAYED_WORK(&hdmi->hpd_work, repo_hpd_event);
|
||||
INIT_WORK(&hdmi->qms_vrr_work, dw_hdmi_qms_vrr_work);
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_hdmi_hpd_irq_handler(int irq, void *arg)
|
||||
@@ -2072,6 +2298,10 @@ static void dw_hdmi_rockchip_encoder_atomic_disable(struct drm_encoder *encoder,
|
||||
}
|
||||
s->output_if_left_panel &= ~(hdmi->id ? VOP_OUTPUT_IF_HDMI1 : VOP_OUTPUT_IF_HDMI0);
|
||||
}
|
||||
|
||||
hdmi->next_tfr_val = 0;
|
||||
hdmi->vrr_state = VRR_IS_DISABLED;
|
||||
|
||||
/*
|
||||
* when plug out hdmi it will be switch cvbs and then phy bus width
|
||||
* must be set as 8
|
||||
@@ -2718,6 +2948,40 @@ dw_hdmi_get_lane_cfg_by_frl_rate(struct rockchip_hdmi *hdmi, u64 rate,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_hdmi_qms_vrr_state(struct rockchip_hdmi *hdmi,
|
||||
struct rockchip_crtc_state *vcstate)
|
||||
{
|
||||
switch (hdmi->vrr_state) {
|
||||
case VRR_GOTO_ENABLE:
|
||||
case VRR_RATE_CHANGED:
|
||||
vcstate->max_refresh_rate = HDMI_MAX_VRR_REFRESH_RATE;
|
||||
vcstate->min_refresh_rate = HDMI_MIN_VRR_REFRESH_RATE;
|
||||
vcstate->hdmi_vrr.m_const = 0;
|
||||
vcstate->vrr_type = ROCKCHIP_VRR_VFP_MODE;
|
||||
queue_work(hdmi->workqueue, &hdmi->qms_vrr_work);
|
||||
break;
|
||||
case VRR_GOTO_DISABLE:
|
||||
vcstate->max_refresh_rate = 0;
|
||||
vcstate->min_refresh_rate = 0;
|
||||
vcstate->hdmi_vrr.m_const = 0;
|
||||
vcstate->vrr_type = 0;
|
||||
vcstate->hdmi_vrr.next_tfr_val = hdmi->brr_tfr;
|
||||
vcstate->hdmi_vrr.refresh_rate_ready_to_change = true;
|
||||
queue_work(hdmi->workqueue, &hdmi->qms_vrr_work);
|
||||
break;
|
||||
case VRR_WAIT_REFRESH_CHANGE:
|
||||
vcstate->hdmi_vrr.m_const = 0;
|
||||
rockchip_hdmi_qms_vrr_set_refresh(hdmi, vcstate);
|
||||
break;
|
||||
case VRR_IS_STABLE:
|
||||
vcstate->hdmi_vrr.m_const = 1;
|
||||
dw_hdmi_qp_set_qms(hdmi->hdmi_qp, hdmi->next_tfr_val, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
@@ -2749,6 +3013,13 @@ secondary:
|
||||
|
||||
s->bus_format = bus_format;
|
||||
if (hdmi->is_hdmi_qp) {
|
||||
s->hdmi_vrr.next_tfr_val = hdmi->next_tfr_val;
|
||||
|
||||
if (hdmi->vrr_state != hdmi->old_vrr_state) {
|
||||
hdmi->old_vrr_state = hdmi->vrr_state;
|
||||
rockchip_hdmi_qms_vrr_state(hdmi, s);
|
||||
}
|
||||
|
||||
color_depth = hdmi_bus_fmt_color_depth(bus_format);
|
||||
tmdsclk = hdmi_get_tmdsclock(hdmi, crtc_state->mode.clock);
|
||||
if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format))
|
||||
@@ -3410,6 +3681,23 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_prop_enum_list next_tfr_list[] = {
|
||||
{ 0, "disable" },
|
||||
{ 1, "23.97Hz" },
|
||||
{ 2, "24Hz" },
|
||||
{ 3, "25Hz" },
|
||||
{ 4, "29.97Hz" },
|
||||
{ 5, "30Hz" },
|
||||
{ 6, "47.95Hz" },
|
||||
{ 7, "48Hz" },
|
||||
{ 8, "50Hz" },
|
||||
{ 9, "59.94Hz" },
|
||||
{ 10, "60Hz" },
|
||||
{ 11, "100Hz" },
|
||||
{ 12, "119.88Hz" },
|
||||
{ 13, "120Hz" },
|
||||
};
|
||||
|
||||
static void
|
||||
dw_hdmi_rockchip_attach_properties(struct drm_connector *connector,
|
||||
unsigned int color, int version,
|
||||
@@ -3525,6 +3813,15 @@ dw_hdmi_rockchip_attach_properties(struct drm_connector *connector,
|
||||
hdmi->hdr10_plus_vsdb = prop;
|
||||
drm_object_attach_property(&connector->base, prop, 0);
|
||||
}
|
||||
|
||||
prop = drm_property_create_enum(connector->dev, 0,
|
||||
"next_tfr",
|
||||
next_tfr_list,
|
||||
ARRAY_SIZE(next_tfr_list));
|
||||
if (prop) {
|
||||
hdmi->next_tfr = prop;
|
||||
drm_object_attach_property(&connector->base, prop, 0);
|
||||
}
|
||||
}
|
||||
|
||||
prop = drm_property_create_enum(connector->dev, 0,
|
||||
@@ -3684,6 +3981,11 @@ dw_hdmi_rockchip_destroy_properties(struct drm_connector *connector,
|
||||
drm_property_destroy(connector->dev, hdmi->hdr10_plus_vsdb);
|
||||
hdmi->hdr10_plus_vsdb = NULL;
|
||||
}
|
||||
|
||||
if (hdmi->next_tfr) {
|
||||
drm_property_destroy(connector->dev, hdmi->next_tfr);
|
||||
hdmi->next_tfr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3757,6 +4059,8 @@ dw_hdmi_rockchip_set_property(struct drm_connector *connector,
|
||||
return ret;
|
||||
} else if (property == hdmi->hdr10_plus_vsdb) {
|
||||
return 0;
|
||||
} else if (property == hdmi->next_tfr) {
|
||||
return rockchip_hdmi_set_qms_next_tfr(hdmi, val);
|
||||
}
|
||||
|
||||
DRM_ERROR("Unknown property [PROP:%d:%s]\n",
|
||||
@@ -3852,6 +4156,9 @@ dw_hdmi_rockchip_get_property(struct drm_connector *connector,
|
||||
} else if (property == hdmi->hdr10_plus_vsdb) {
|
||||
*val = (hdmi->hdr10_plus_vsdb_ptr) ? hdmi->hdr10_plus_vsdb_ptr->base.id : 0;
|
||||
return 0;
|
||||
} else if (property == hdmi->next_tfr) {
|
||||
*val = hdmi->next_tfr_val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DRM_ERROR("Unknown property [PROP:%d:%s]\n",
|
||||
@@ -4712,7 +5019,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
|
||||
if (hdmi->is_hdmi_qp) {
|
||||
hdmi->chip_data->ops->io_path_init(hdmi);
|
||||
init_hpd_work(hdmi);
|
||||
init_hdmi_work(hdmi);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(hdmi->phyref_clk);
|
||||
@@ -4851,7 +5158,8 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
|
||||
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
if (hdmi->is_hdmi_qp) {
|
||||
cancel_delayed_work(&hdmi->work);
|
||||
cancel_delayed_work(&hdmi->hpd_work);
|
||||
cancel_work_sync(&hdmi->qms_vrr_work);
|
||||
flush_workqueue(hdmi->workqueue);
|
||||
destroy_workqueue(hdmi->workqueue);
|
||||
}
|
||||
@@ -4930,7 +5238,8 @@ static void dw_hdmi_rockchip_shutdown(struct platform_device *pdev)
|
||||
if (hdmi->is_hdmi_qp) {
|
||||
if (hdmi->hpd_irq)
|
||||
disable_irq(hdmi->hpd_irq);
|
||||
cancel_delayed_work(&hdmi->work);
|
||||
cancel_delayed_work(&hdmi->hpd_work);
|
||||
cancel_work_sync(&hdmi->qms_vrr_work);
|
||||
flush_workqueue(hdmi->workqueue);
|
||||
dw_hdmi_qp_suspend(hdmi->dev, hdmi->hdmi_qp);
|
||||
} else {
|
||||
|
||||
@@ -78,6 +78,502 @@ static const struct drm_driver rockchip_drm_driver;
|
||||
static unsigned int drm_debug;
|
||||
module_param_named(debug, drm_debug, int, 0600);
|
||||
|
||||
static const u16 tfr_vrefresh_table[TFR_MAX] = {
|
||||
[TFR_QMSVRR_INACTIVE] = 0,
|
||||
[TFR_23P97] = 2397,
|
||||
[TFR_24] = 2400,
|
||||
[TFR_25] = 2500,
|
||||
[TFR_29P97] = 2997,
|
||||
[TFR_30] = 3000,
|
||||
[TFR_47P95] = 4795,
|
||||
[TFR_48] = 4800,
|
||||
[TFR_50] = 5000,
|
||||
[TFR_59P94] = 5994,
|
||||
[TFR_60] = 6000,
|
||||
[TFR_100] = 10000,
|
||||
[TFR_119P88] = 11988,
|
||||
[TFR_120] = 12000,
|
||||
};
|
||||
|
||||
/* BRR 720p60hz */
|
||||
static const struct mvrr_const_val const_hdmi720p60_6000 = {
|
||||
.vrefresh_khz = 6000,
|
||||
.vtotal_fixed = 750,
|
||||
};
|
||||
|
||||
/**
|
||||
* @vrefresh_khz: qms-vrr target refresh rate is 59.94Hz
|
||||
* @vtotal_fixed: When switch to target refresh rate, vtotal is 750
|
||||
* @bit_len: frac_array's bit length
|
||||
* @frac_array: Sources may also alternate between two sequential values
|
||||
* of actual vtotal to better approximate the target refresh
|
||||
* rate when target vtotal is fractional. For this example,
|
||||
* the source vtotal would vary between 750 and 751.
|
||||
* The value in frac_array indicates the order in which the
|
||||
* vtotal changes during this process. Each bit of 0 indicates
|
||||
* that the current frame vtotal is 750, and each bit of 1
|
||||
* indicates that the current frame vtotal is 751.
|
||||
* Take 0x3f(00111111B) as an example, it represents a vtotal
|
||||
* of 750 for the first and second frames, and 751 for the
|
||||
* remaining six frames. 0xe3 and 0xfe also have the same meaning.
|
||||
* The current frac_array represents the value of vtotal for 24
|
||||
* consecutive frames.
|
||||
*/
|
||||
static const struct mvrr_const_val const_hdmi720p60_5994 = {
|
||||
.vrefresh_khz = 5994,
|
||||
.vtotal_fixed = 750, /* 0.75 */
|
||||
.bit_len = 24,
|
||||
.frac_array = {0x3f, 0xe3, 0xfe},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p60_5000 = {
|
||||
.vrefresh_khz = 5000,
|
||||
.vtotal_fixed = 900,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p60_4800 = {
|
||||
.vrefresh_khz = 4800,
|
||||
.vtotal_fixed = 937, /* 0.5 */
|
||||
.bit_len = 8,
|
||||
.frac_array = {0x3c},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p60_4795 = {
|
||||
.vrefresh_khz = 4795,
|
||||
.vtotal_fixed = 938, /* 0.4375 */
|
||||
.bit_len = 16,
|
||||
.frac_array = {0x1e, 0x0e},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p60_3000 = {
|
||||
.vrefresh_khz = 3000,
|
||||
.vtotal_fixed = 1500,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p60_2997 = {
|
||||
.vrefresh_khz = 2997,
|
||||
.vtotal_fixed = 1501, /* 0.5 */
|
||||
.bit_len = 56,
|
||||
.frac_array = {0x1f, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xf8},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p60_2500 = {
|
||||
.vrefresh_khz = 2500,
|
||||
.vtotal_fixed = 1800,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p60_2400 = {
|
||||
.vrefresh_khz = 2400,
|
||||
.vtotal_fixed = 1875,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p60_2397 = {
|
||||
.vrefresh_khz = 2397,
|
||||
.vtotal_fixed = 1876, /* 0.875 */
|
||||
.bit_len = 40,
|
||||
.frac_array = {0x1f, 0xff, 0xff, 0xff, 0xfc},
|
||||
};
|
||||
|
||||
/* BRR 720p120hz */
|
||||
static const struct mvrr_const_val const_hdmi720p120_12000 = {
|
||||
.vrefresh_khz = 12000,
|
||||
.vtotal_fixed = 750,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_11988 = {
|
||||
.vrefresh_khz = 11988,
|
||||
.vtotal_fixed = 750, /* 0.75 */
|
||||
.bit_len = 24,
|
||||
.frac_array = {0x3f, 0xe3, 0xfe},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_10000 = {
|
||||
.vrefresh_khz = 10000,
|
||||
.vtotal_fixed = 900,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_6000 = {
|
||||
.vrefresh_khz = 6000,
|
||||
.vtotal_fixed = 1500,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_5994 = {
|
||||
.vrefresh_khz = 5994,
|
||||
.vtotal_fixed = 1501, /* 0.5 */
|
||||
.bit_len = 56,
|
||||
.frac_array = {0x0f, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xf8},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_5000 = {
|
||||
.vrefresh_khz = 5000,
|
||||
.vtotal_fixed = 1800,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_4800 = {
|
||||
.vrefresh_khz = 4800,
|
||||
.vtotal_fixed = 1875,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_4795 = {
|
||||
.vrefresh_khz = 4795,
|
||||
.vtotal_fixed = 1876, /* 0.875 */
|
||||
.bit_len = 40,
|
||||
.frac_array = {0x1f, 0xff, 0xff, 0xff, 0xfc},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_3000 = {
|
||||
.vrefresh_khz = 3000,
|
||||
.vtotal_fixed = 3000,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_2997 = {
|
||||
.vrefresh_khz = 2997,
|
||||
.vtotal_fixed = 3003,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_2500 = {
|
||||
.vrefresh_khz = 2500,
|
||||
.vtotal_fixed = 3600,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_2400 = {
|
||||
.vrefresh_khz = 2400,
|
||||
.vtotal_fixed = 3750,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi720p120_2397 = {
|
||||
.vrefresh_khz = 2397,
|
||||
.vtotal_fixed = 3753, /* 0.75 */
|
||||
.bit_len = 88,
|
||||
.frac_array = {
|
||||
0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0
|
||||
},
|
||||
};
|
||||
|
||||
/* BRR 1080p60hz */
|
||||
static const struct mvrr_const_val const_hdmi1080p60_6000 = {
|
||||
.vrefresh_khz = 6000,
|
||||
.vtotal_fixed = 1125,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_5994 = {
|
||||
.vrefresh_khz = 5994,
|
||||
.vtotal_fixed = 1126, /* 0.125 */
|
||||
.bit_len = 24,
|
||||
.frac_array = {0x00, 0x38, 0x00},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_5000 = {
|
||||
.vrefresh_khz = 5000,
|
||||
.vtotal_fixed = 1350,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_4800 = {
|
||||
.vrefresh_khz = 4800,
|
||||
.vtotal_fixed = 1406, /* 0.25 */
|
||||
.bit_len = 16,
|
||||
.frac_array = {0x03, 0xc0},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_4795 = {
|
||||
.vrefresh_khz = 4795,
|
||||
.vtotal_fixed = 1407, /* 0.65625 */
|
||||
.bit_len = 32,
|
||||
.frac_array = {0x1f, 0xf1, 0x7f, 0xf0},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_3000 = {
|
||||
.vrefresh_khz = 3000,
|
||||
.vtotal_fixed = 2250,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_2997 = {
|
||||
.vrefresh_khz = 2997,
|
||||
.vtotal_fixed = 2252, /* 0.25 */
|
||||
.bit_len = 56,
|
||||
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_2500 = {
|
||||
.vrefresh_khz = 2500,
|
||||
.vtotal_fixed = 2700,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_2400 = {
|
||||
.vrefresh_khz = 2400,
|
||||
.vtotal_fixed = 2812, /* 0.5 */
|
||||
.bit_len = 24,
|
||||
.frac_array = {0x03, 0xff, 0xc0},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p60_2397 = {
|
||||
.vrefresh_khz = 2397,
|
||||
.vtotal_fixed = 2815, /* 0.3125 */
|
||||
.bit_len = 128,
|
||||
.frac_array = {
|
||||
0x00, 0x7f, 0x80, 0x00, 0x3f, 0xc0, 0x00, 0x0f,
|
||||
0xf0, 0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00,
|
||||
},
|
||||
};
|
||||
|
||||
/* BRR 1080p120hz */
|
||||
static const struct mvrr_const_val const_hdmi1080p120_12000 = {
|
||||
.vrefresh_khz = 12000,
|
||||
.vtotal_fixed = 1125,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_11988 = {
|
||||
.vrefresh_khz = 11988,
|
||||
.vtotal_fixed = 1126, /* 0.125 */
|
||||
.bit_len = 24,
|
||||
.frac_array = {0x00, 0x38, 0x00},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_10000 = {
|
||||
.vrefresh_khz = 10000,
|
||||
.vtotal_fixed = 1350,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_6000 = {
|
||||
.vrefresh_khz = 6000,
|
||||
.vtotal_fixed = 2250,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_5994 = {
|
||||
.vrefresh_khz = 5994,
|
||||
.vtotal_fixed = 2252, /* 0.25 */
|
||||
.bit_len = 56,
|
||||
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_5000 = {
|
||||
.vrefresh_khz = 5000,
|
||||
.vtotal_fixed = 2700,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_4800 = {
|
||||
.vrefresh_khz = 4800,
|
||||
.vtotal_fixed = 2812, /* 0.5 */
|
||||
.bit_len = 24,
|
||||
.frac_array = {0x03, 0xff, 0xc0},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_4795 = {
|
||||
.vrefresh_khz = 4795,
|
||||
.vtotal_fixed = 2812, /* 0.3125 */
|
||||
.bit_len = 48,
|
||||
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x3f, 0xc0},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_3000 = {
|
||||
.vrefresh_khz = 3000,
|
||||
.vtotal_fixed = 4500,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_2997 = {
|
||||
.vrefresh_khz = 2997,
|
||||
.vtotal_fixed = 4504, /* 0.5 */
|
||||
.bit_len = 32,
|
||||
.frac_array = {0x00, 0xff, 0xff, 0x00},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_2500 = {
|
||||
.vrefresh_khz = 2500,
|
||||
.vtotal_fixed = 5400,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_2400 = {
|
||||
.vrefresh_khz = 2400,
|
||||
.vtotal_fixed = 5625,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi1080p120_2397 = {
|
||||
.vrefresh_khz = 2397,
|
||||
.vtotal_fixed = 5630, /* 0.625 */
|
||||
.bit_len = 48,
|
||||
.frac_array = {0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00},
|
||||
};
|
||||
|
||||
/* BRR 2160p60hz */
|
||||
static const struct mvrr_const_val const_hdmi2160p60_6000 = {
|
||||
.vrefresh_khz = 6000,
|
||||
.vtotal_fixed = 2250,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_5994 = {
|
||||
.vrefresh_khz = 5994,
|
||||
.vtotal_fixed = 2252, /* 0.25 */
|
||||
.bit_len = 56,
|
||||
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_5000 = {
|
||||
.vrefresh_khz = 5000,
|
||||
.vtotal_fixed = 2700,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_4800 = {
|
||||
.vrefresh_khz = 4800,
|
||||
.vtotal_fixed = 2812, /* 0.5 */
|
||||
.bit_len = 24,
|
||||
.frac_array = {0x03, 0xff, 0xc0},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_4795 = {
|
||||
.vrefresh_khz = 4795,
|
||||
.vtotal_fixed = 2815, /* 0.3125 */
|
||||
.bit_len = 48,
|
||||
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x3f, 0xc0},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_3000 = {
|
||||
.vrefresh_khz = 3000,
|
||||
.vtotal_fixed = 4500,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_2997 = {
|
||||
.vrefresh_khz = 2997,
|
||||
.vtotal_fixed = 4504, /* 0.5 */
|
||||
.bit_len = 32,
|
||||
.frac_array = {0x00, 0xff, 0xff, 0x00},
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_2500 = {
|
||||
.vrefresh_khz = 2500,
|
||||
.vtotal_fixed = 5400,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_2400 = {
|
||||
.vrefresh_khz = 2400,
|
||||
.vtotal_fixed = 5625,
|
||||
};
|
||||
|
||||
static const struct mvrr_const_val const_hdmi2160p60_2397 = {
|
||||
.vrefresh_khz = 2397,
|
||||
.vtotal_fixed = 5630, /* 0.625 */
|
||||
.bit_len = 48,
|
||||
.frac_array = {0x00, 0x3f, 0xff, 0xff, 0xff, 0x00},
|
||||
};
|
||||
|
||||
const struct mvrr_const_st const_hdmi1080p60_val = {
|
||||
.brr_vic = HDMI_16_1920x1080P60_16x9,
|
||||
.val = {
|
||||
&const_hdmi1080p60_6000,
|
||||
&const_hdmi1080p60_5994,
|
||||
&const_hdmi1080p60_5000,
|
||||
&const_hdmi1080p60_4800,
|
||||
&const_hdmi1080p60_4795,
|
||||
&const_hdmi1080p60_3000,
|
||||
&const_hdmi1080p60_2997,
|
||||
&const_hdmi1080p60_2500,
|
||||
&const_hdmi1080p60_2400,
|
||||
&const_hdmi1080p60_2397,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
const struct mvrr_const_st const_hdmi1080p120_val = {
|
||||
.brr_vic = HDMI_63_1920x1080P120_16x9,
|
||||
.val = {
|
||||
&const_hdmi1080p120_12000,
|
||||
&const_hdmi1080p120_11988,
|
||||
&const_hdmi1080p120_10000,
|
||||
&const_hdmi1080p120_6000,
|
||||
&const_hdmi1080p120_5994,
|
||||
&const_hdmi1080p120_5000,
|
||||
&const_hdmi1080p120_4800,
|
||||
&const_hdmi1080p120_4795,
|
||||
&const_hdmi1080p120_3000,
|
||||
&const_hdmi1080p120_2997,
|
||||
&const_hdmi1080p120_2500,
|
||||
&const_hdmi1080p120_2400,
|
||||
&const_hdmi1080p120_2397,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
const struct mvrr_const_st const_hdmi720p60_val = {
|
||||
.brr_vic = HDMI_4_1280x720P60_16x9,
|
||||
.val = {
|
||||
&const_hdmi720p60_6000,
|
||||
&const_hdmi720p60_5994,
|
||||
&const_hdmi720p60_5000,
|
||||
&const_hdmi720p60_4800,
|
||||
&const_hdmi720p60_4795,
|
||||
&const_hdmi720p60_3000,
|
||||
&const_hdmi720p60_2997,
|
||||
&const_hdmi720p60_2500,
|
||||
&const_hdmi720p60_2400,
|
||||
&const_hdmi720p60_2397,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
const struct mvrr_const_st const_hdmi720p120_val = {
|
||||
.brr_vic = HDMI_47_1280x720P120_16x9,
|
||||
.val = {
|
||||
&const_hdmi720p120_12000,
|
||||
&const_hdmi720p120_11988,
|
||||
&const_hdmi720p120_10000,
|
||||
&const_hdmi720p120_6000,
|
||||
&const_hdmi720p120_5994,
|
||||
&const_hdmi720p120_5000,
|
||||
&const_hdmi720p120_4800,
|
||||
&const_hdmi720p120_4795,
|
||||
&const_hdmi720p120_3000,
|
||||
&const_hdmi720p120_2997,
|
||||
&const_hdmi720p120_2500,
|
||||
&const_hdmi720p120_2400,
|
||||
&const_hdmi720p120_2397,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
const struct mvrr_const_st const_hdmi2160p60_val = {
|
||||
.brr_vic = HDMI_97_3840x2160P60_16x9,
|
||||
.val = {
|
||||
&const_hdmi2160p60_6000,
|
||||
&const_hdmi2160p60_5994,
|
||||
&const_hdmi2160p60_5000,
|
||||
&const_hdmi2160p60_4800,
|
||||
&const_hdmi2160p60_4795,
|
||||
&const_hdmi2160p60_3000,
|
||||
&const_hdmi2160p60_2997,
|
||||
&const_hdmi2160p60_2500,
|
||||
&const_hdmi2160p60_2400,
|
||||
&const_hdmi2160p60_2397,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
/* The vtotal parameters of 4096x2160p60hz are the same as 3840x2160p60hz */
|
||||
const struct mvrr_const_st const_hdmismpte60_val = {
|
||||
.brr_vic = HDMI_102_4096x2160P60_256x135,
|
||||
.val = {
|
||||
&const_hdmi2160p60_6000,
|
||||
&const_hdmi2160p60_5994,
|
||||
&const_hdmi2160p60_5000,
|
||||
&const_hdmi2160p60_4800,
|
||||
&const_hdmi2160p60_4795,
|
||||
&const_hdmi2160p60_3000,
|
||||
&const_hdmi2160p60_2997,
|
||||
&const_hdmi2160p60_2500,
|
||||
&const_hdmi2160p60_2400,
|
||||
&const_hdmi2160p60_2397,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
const struct mvrr_const_st *qms_const[] = {
|
||||
&const_hdmi1080p60_val,
|
||||
&const_hdmi1080p120_val,
|
||||
&const_hdmi2160p60_val,
|
||||
&const_hdmi720p60_val,
|
||||
&const_hdmi720p120_val,
|
||||
&const_hdmismpte60_val,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static inline bool rockchip_drm_debug_enabled(enum rockchip_drm_debug_category category)
|
||||
{
|
||||
return unlikely(drm_debug & category);
|
||||
@@ -885,7 +1381,16 @@ void get_max_frl_rate(int max_frl_rate, u8 *max_lanes, u8 *max_rate_per_lane)
|
||||
#define EDID_DSC_TOTAL_CHUNK_KBYTES 0x3f
|
||||
#define EDID_MAX_FRL_RATE_MASK 0xf0
|
||||
|
||||
/* Sink Capability Data Structure, for compatibility with linux version < linux kernel 6.1 */
|
||||
#define DRM_EDID_FAPA_START (1 << 0)
|
||||
#define DRM_EDID_ALLM (1 << 1)
|
||||
#define DRM_EDID_FVA (1 << 2)
|
||||
#define DRM_EDID_QMS (1 << 6)
|
||||
#define DRM_EDID_VRR_MIN_MASK 0x3f
|
||||
#define DRM_EDID_VRR_MAX_UPPER_MASK 0xc0
|
||||
#define DRM_EDID_QMS_TFR_MIN (1 << 4)
|
||||
#define DRM_EDID_QMS_TFR_MAX (1 << 5)
|
||||
|
||||
/* Sink Capability Data Structure */
|
||||
static void parse_hdmi_forum_scds(struct rockchip_drm_hdmi21_data *hdmi21_data, const u8 *hf_scds)
|
||||
{
|
||||
if (hf_scds[7]) {
|
||||
@@ -893,9 +1398,9 @@ static void parse_hdmi_forum_scds(struct rockchip_drm_hdmi21_data *hdmi21_data,
|
||||
u8 dsc_max_frl_rate;
|
||||
u8 dsc_max_slices;
|
||||
|
||||
DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n");
|
||||
max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4;
|
||||
hdmi21_data->allm_supported = hf_scds[8] & DRM_EDID_ALLM;
|
||||
if (max_frl_rate)
|
||||
DRM_DEBUG_KMS("hdmi21 FRL detected. parsing edid....\n");
|
||||
get_max_frl_rate(max_frl_rate, &hdmi21_data->max_lanes,
|
||||
&hdmi21_data->max_frl_rate_per_lane);
|
||||
hdmi21_data->dsc_cap.v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2;
|
||||
@@ -957,6 +1462,27 @@ static void parse_hdmi_forum_scds(struct rockchip_drm_hdmi21_data *hdmi21_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parse additional bytes */
|
||||
if (cea_db_payload_len(hf_scds) >= 9) {
|
||||
hdmi21_data->allm_supported = hf_scds[8] & DRM_EDID_ALLM;
|
||||
hdmi21_data->vrr_cap.qms = hf_scds[8] & DRM_EDID_QMS;
|
||||
hdmi21_data->vrr_cap.fva = hf_scds[8] & DRM_EDID_FVA;
|
||||
hdmi21_data->vrr_cap.m_delta = hf_scds[8] & DRM_EDID_MDELTA;
|
||||
hdmi21_data->vrr_cap.negm_vrr = hf_scds[8] & DRM_EDID_CNMVRR;
|
||||
hdmi21_data->vrr_cap.cinema_vrr = hf_scds[8] & DRM_EDID_CINEMA_VRR;
|
||||
}
|
||||
|
||||
if (cea_db_payload_len(hf_scds) >= 11) {
|
||||
hdmi21_data->vrr_cap.vrr_min = hf_scds[9] & DRM_EDID_VRR_MIN_MASK;
|
||||
hdmi21_data->vrr_cap.vrr_max =
|
||||
(hf_scds[9] & DRM_EDID_VRR_MAX_UPPER_MASK) << 2 | hf_scds[10];
|
||||
}
|
||||
|
||||
if (cea_db_payload_len(hf_scds) >= 12) {
|
||||
hdmi21_data->vrr_cap.qms_tfr_min = hf_scds[11] & DRM_EDID_QMS_TFR_MIN;
|
||||
hdmi21_data->vrr_cap.qms_tfr_max = hf_scds[11] & DRM_EDID_QMS_TFR_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
@@ -1229,6 +1755,63 @@ void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc)
|
||||
priv->crtc_funcs[pipe] = NULL;
|
||||
}
|
||||
|
||||
u16 rockchip_hdmi_vrr_tfr_match_to_vrefresh(u8 tfr)
|
||||
{
|
||||
if (tfr < 0 || tfr >= TFR_MAX) {
|
||||
DRM_ERROR("qms-vrr tfr is out of range\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tfr_vrefresh_table[tfr];
|
||||
}
|
||||
|
||||
const struct
|
||||
mvrr_const_val *rockchip_hdmi_vrr_get_vrrconf_mconst(enum hdmi_brr_vic brr_vic, u16 vrefresh_khz)
|
||||
{
|
||||
const struct mvrr_const_st **table_vic = NULL;
|
||||
const struct mvrr_const_val *const *table_val = NULL;
|
||||
|
||||
for (table_vic = qms_const; table_vic; table_vic++) {
|
||||
if ((*table_vic)->brr_vic == brr_vic) {
|
||||
table_val = (*table_vic)->val;
|
||||
for (; table_val; table_val++) {
|
||||
if ((*table_val)->vrefresh_khz == vrefresh_khz)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!table_val) {
|
||||
DRM_ERROR("%s[%d] not find brr_vic: %d vrefresh_khz: %d\n",
|
||||
__func__, __LINE__, brr_vic, vrefresh_khz);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return *table_val;
|
||||
}
|
||||
|
||||
u16 rockchip_hdmi_vrr_calc_new_vtotal(const struct mvrr_const_val *mvrr, u32 frame_cnt)
|
||||
{
|
||||
u32 pos;
|
||||
u16 vtotal = 0;
|
||||
|
||||
if (!mvrr)
|
||||
return vtotal;
|
||||
|
||||
vtotal = mvrr->vtotal_fixed;
|
||||
/* if bit_len is 0, then means there is no fraction */
|
||||
if (!mvrr->bit_len)
|
||||
return vtotal;
|
||||
|
||||
/* calculate the fraction number */
|
||||
pos = frame_cnt % mvrr->bit_len;
|
||||
if (mvrr->frac_array[pos / 8] & (1 << (7 - (pos % 8))))
|
||||
vtotal++;
|
||||
|
||||
return vtotal;
|
||||
}
|
||||
|
||||
/*
|
||||
* a high frequency of page faults will follow up, if
|
||||
* there is a iommu fault, so it's better to limit the
|
||||
|
||||
@@ -266,6 +266,15 @@ struct post_sharp {
|
||||
u32 regs[SHARP_REG_LENGTH / 4];
|
||||
};
|
||||
|
||||
struct rockchip_hdmi_vrr_state {
|
||||
bool refresh_rate_ready_to_change;
|
||||
bool m_const;
|
||||
u8 next_tfr_val;
|
||||
u8 fva_factor_m1_val;
|
||||
unsigned int vrr_frame_cnt;
|
||||
const struct mvrr_const_val *mconst_val;
|
||||
};
|
||||
|
||||
struct rockchip_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
int vp_id;
|
||||
@@ -344,6 +353,7 @@ struct rockchip_crtc_state {
|
||||
struct drm_dsc_picture_parameter_set pps;
|
||||
struct rockchip_dsc_sink_cap dsc_sink_cap;
|
||||
struct rockchip_hdr_state hdr;
|
||||
struct rockchip_hdmi_vrr_state hdmi_vrr;
|
||||
struct drm_property_blob *hdr_ext_data;
|
||||
struct drm_property_blob *acm_lut_data;
|
||||
struct drm_property_blob *post_csc_data;
|
||||
@@ -494,6 +504,47 @@ struct next_hdr_sink_data {
|
||||
struct ver_12_v2 ver_12_v2;
|
||||
} __packed;
|
||||
|
||||
/* refer to HDMI2.1B P453 */
|
||||
enum TARGET_FRAME_RATE {
|
||||
TFR_QMSVRR_INACTIVE = 0,
|
||||
TFR_23P97,
|
||||
TFR_24,
|
||||
TFR_25,
|
||||
TFR_29P97,
|
||||
TFR_30,
|
||||
TFR_47P95,
|
||||
TFR_48,
|
||||
TFR_50,
|
||||
TFR_59P94,
|
||||
TFR_60,
|
||||
TFR_100,
|
||||
TFR_119P88,
|
||||
TFR_120,
|
||||
TFR_MAX,
|
||||
};
|
||||
|
||||
enum hdmi_brr_vic {
|
||||
HDMI_16_1920x1080P60_16x9 = 16,
|
||||
HDMI_63_1920x1080P120_16x9 = 63,
|
||||
HDMI_4_1280x720P60_16x9 = 4,
|
||||
HDMI_47_1280x720P120_16x9 = 47,
|
||||
HDMI_97_3840x2160P60_16x9 = 97,
|
||||
HDMI_102_4096x2160P60_256x135 = 102,
|
||||
};
|
||||
|
||||
struct mvrr_const_val {
|
||||
/* unit: 100 6000, 5994, 5000, 3000, 2997, 2500, 2400, 2397 */
|
||||
u16 vrefresh_khz;
|
||||
u16 vtotal_fixed; /* vtotal_fixed is mutex with bit_len */
|
||||
u8 bit_len; /* current max value is 16 * 8, 128 */
|
||||
u8 frac_array[16];
|
||||
};
|
||||
|
||||
struct mvrr_const_st {
|
||||
enum hdmi_brr_vic brr_vic; /* the vic of brr */
|
||||
const struct mvrr_const_val *val[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Rockchip drm private crtc funcs.
|
||||
* @loader_protect: protect loader logo crtc's power
|
||||
@@ -626,11 +677,24 @@ struct rockchip_encoder {
|
||||
struct drm_encoder encoder;
|
||||
};
|
||||
|
||||
struct rockchip_drm_vrr_cap {
|
||||
bool qms;
|
||||
bool m_delta;
|
||||
bool cinema_vrr;
|
||||
bool negm_vrr;
|
||||
bool fva;
|
||||
bool qms_tfr_max;
|
||||
bool qms_tfr_min;
|
||||
u8 vrr_min;
|
||||
u16 vrr_max;
|
||||
};
|
||||
|
||||
struct rockchip_drm_hdmi21_data {
|
||||
u8 max_frl_rate_per_lane;
|
||||
u8 max_lanes;
|
||||
bool allm_supported;
|
||||
struct rockchip_drm_dsc_cap dsc_cap;
|
||||
struct rockchip_drm_vrr_cap vrr_cap;
|
||||
};
|
||||
|
||||
void rockchip_connector_update_vfp_for_vrr(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
@@ -708,6 +772,10 @@ __printf(3, 4)
|
||||
void rockchip_drm_dbg_thread_info(const struct device *dev,
|
||||
enum rockchip_drm_debug_category category,
|
||||
const char *format, ...);
|
||||
u16 rockchip_hdmi_vrr_tfr_match_to_vrefresh(u8 tfr);
|
||||
const struct
|
||||
mvrr_const_val *rockchip_hdmi_vrr_get_vrrconf_mconst(enum hdmi_brr_vic brr_vic, u16 vrefresh_khz);
|
||||
u16 rockchip_hdmi_vrr_calc_new_vtotal(const struct mvrr_const_val *mvrr, u32 frame_cnt);
|
||||
|
||||
extern struct platform_driver cdn_dp_driver;
|
||||
extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
|
||||
|
||||
@@ -5955,6 +5955,9 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
vcstate->splice_mode = false;
|
||||
vcstate->output_flags = 0;
|
||||
vcstate->output_type = 0;
|
||||
vcstate->hdmi_vrr.m_const = 0;
|
||||
vcstate->hdmi_vrr.next_tfr_val = 0;
|
||||
vcstate->hdmi_vrr.refresh_rate_ready_to_change = false;
|
||||
vp->splice_mode_right = false;
|
||||
vp->loader_protect = false;
|
||||
vp->enabled_win_mask = 0;
|
||||
@@ -9025,6 +9028,7 @@ static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(new_crtc_state);
|
||||
|
||||
drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
|
||||
|
||||
/*
|
||||
* For RK3568 and RK3588, the hactive of video timing must
|
||||
* be 4-pixel aligned.
|
||||
@@ -10682,10 +10686,15 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta
|
||||
|
||||
VOP_MODULE_SET(vop2, vp, dsp_vtotal, vtotal);
|
||||
VOP_MODULE_SET(vop2, vp, dsp_vs_end, vsync_len);
|
||||
/**
|
||||
* when display interface support vrr, config vtotal valid immediately
|
||||
/*
|
||||
* when display interface support vrr, config vtotal
|
||||
* valid immediately except HDMI QMS-VRR. HDMI QMS-VRR
|
||||
* requires cfg done to accurately handle the vrr process.
|
||||
* Fixme: HDMI GAMING-VRR needs to config vtotal valid immediately,
|
||||
* the next version will be implemented.
|
||||
*/
|
||||
if (vcstate->max_refresh_rate && vcstate->min_refresh_rate)
|
||||
if (vcstate->max_refresh_rate && vcstate->min_refresh_rate &&
|
||||
!output_if_is_hdmi(vcstate->output_if))
|
||||
VOP_MODULE_SET(vop2, vp, sw_dsp_vtotal_imd, 1);
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "dclk_out%d", vp->id);
|
||||
@@ -12502,22 +12511,13 @@ static void vop2_crtc_hfp_seamless_switch(struct drm_crtc *crtc)
|
||||
VOP_MODULE_SET(vop2, vp, htotal_pw, (new_htotal << 16) | hsync_len);
|
||||
}
|
||||
|
||||
static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc)
|
||||
static void
|
||||
vop2_crtc_update_vrr_timing(struct drm_crtc *crtc, unsigned int new_vtotal, unsigned int new_vfp)
|
||||
{
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
struct drm_display_mode *adjust_mode = &crtc->state->adjusted_mode;
|
||||
unsigned int vrefresh;
|
||||
unsigned int new_vtotal, vfp, new_vfp;
|
||||
|
||||
DRM_DEV_INFO(vop2->dev, "change refresh rate by changing vfp\n");
|
||||
vrefresh = drm_mode_vrefresh(adjust_mode);
|
||||
|
||||
/* calculate new vfp for new refresh rate */
|
||||
new_vtotal = adjust_mode->vtotal * vrefresh / vcstate->request_refresh_rate;
|
||||
vfp = adjust_mode->vsync_start - adjust_mode->vdisplay;
|
||||
new_vfp = vfp + new_vtotal - adjust_mode->vtotal;
|
||||
|
||||
/* config vop2 vtotal register */
|
||||
VOP_MODULE_SET(vop2, vp, dsp_vtotal, new_vtotal);
|
||||
@@ -12539,13 +12539,81 @@ static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc)
|
||||
rockchip_connector_update_vfp_for_vrr(crtc, adjust_mode, new_vfp);
|
||||
}
|
||||
|
||||
static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc)
|
||||
{
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
struct drm_display_mode *adjust_mode = &crtc->state->adjusted_mode;
|
||||
struct rockchip_hdmi_vrr_state *hdmi_vrr = &vcstate->hdmi_vrr;
|
||||
unsigned int vrefresh, vrefresh_khz;
|
||||
unsigned int new_vtotal, vfp, new_vfp;
|
||||
u8 brr_vic;
|
||||
|
||||
DRM_DEV_DEBUG(vop2->dev, "change refresh rate by changing vfp\n");
|
||||
/*
|
||||
* If next_tfr_val is no zero, current mode is hdmi qms-vrr.
|
||||
* If next_tfr_val is 0, it indicates that current mode is hdmi
|
||||
* gaming-vrr/fva, or eDP/DSI vrr.
|
||||
*/
|
||||
if (hdmi_vrr->next_tfr_val) {
|
||||
brr_vic = drm_match_cea_mode(adjust_mode);
|
||||
if (!brr_vic) {
|
||||
DRM_ERROR("qms vrr can't support resolution:\n");
|
||||
DRM_ERROR(DRM_MODE_FMT "\n", DRM_MODE_ARG(adjust_mode));
|
||||
return;
|
||||
}
|
||||
|
||||
vrefresh_khz = rockchip_hdmi_vrr_tfr_match_to_vrefresh(hdmi_vrr->next_tfr_val);
|
||||
if (!vrefresh_khz) {
|
||||
DRM_ERROR("qms vrr unsupported tfr:%d\n", hdmi_vrr->next_tfr_val);
|
||||
return;
|
||||
}
|
||||
|
||||
hdmi_vrr->mconst_val = rockchip_hdmi_vrr_get_vrrconf_mconst(brr_vic, vrefresh_khz);
|
||||
if (!hdmi_vrr->mconst_val) {
|
||||
DRM_ERROR("qms vrr can't find mconst_val\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdmi_vrr->vrr_frame_cnt = 0;
|
||||
new_vtotal = rockchip_hdmi_vrr_calc_new_vtotal(hdmi_vrr->mconst_val,
|
||||
hdmi_vrr->vrr_frame_cnt);
|
||||
if (!new_vtotal) {
|
||||
DRM_ERROR("qms vrr invalid vtotal\n");
|
||||
return;
|
||||
}
|
||||
hdmi_vrr->vrr_frame_cnt++;
|
||||
vfp = adjust_mode->vsync_start - adjust_mode->vdisplay;
|
||||
new_vfp = vfp + new_vtotal - adjust_mode->vtotal;
|
||||
hdmi_vrr->refresh_rate_ready_to_change = false;
|
||||
} else {
|
||||
vrefresh = drm_mode_vrefresh(adjust_mode);
|
||||
|
||||
/* calculate new vfp for new refresh rate */
|
||||
new_vtotal = adjust_mode->crtc_vtotal * vrefresh / vcstate->request_refresh_rate;
|
||||
vfp = adjust_mode->crtc_vsync_start - adjust_mode->crtc_vdisplay;
|
||||
new_vfp = vfp + new_vtotal - adjust_mode->crtc_vtotal;
|
||||
}
|
||||
vop2_crtc_update_vrr_timing(crtc, new_vtotal, new_vfp);
|
||||
}
|
||||
|
||||
static void vop2_crtc_update_vrr(struct drm_crtc *crtc)
|
||||
{
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
|
||||
if (!vp->refresh_rate_change)
|
||||
return;
|
||||
/*
|
||||
* In hdmi qms vrr scenarios, it is possible to switch
|
||||
* timing several frames after refresh rate is configured
|
||||
*/
|
||||
if (output_if_is_hdmi(vcstate->output_if)) {
|
||||
if (!vcstate->hdmi_vrr.refresh_rate_ready_to_change)
|
||||
return;
|
||||
} else {
|
||||
if (!vp->refresh_rate_change)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vcstate->min_refresh_rate || !vcstate->max_refresh_rate)
|
||||
return;
|
||||
@@ -12722,7 +12790,7 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat
|
||||
vop2_wait_for_scan_timing_max_to_assigned_line(vp, current_line, assigned_line);
|
||||
}
|
||||
|
||||
if (vop2->version == VOP_VERSION_RK3588)
|
||||
if (vop2->version == VOP_VERSION_RK3588 || vop2->version == VOP_VERSION_RK3576)
|
||||
vop2_crtc_update_vrr(crtc);
|
||||
|
||||
/* Process cluster sub windows overlay. */
|
||||
@@ -14249,6 +14317,34 @@ static void vop2_dsc_isr(struct vop2 *vop2)
|
||||
}
|
||||
}
|
||||
|
||||
static void vop2_frac_mvrr_update(struct drm_crtc *crtc, struct vop2_video_port *vp)
|
||||
{
|
||||
struct rockchip_crtc_state *vcstate;
|
||||
struct drm_display_mode *adjust_mode;
|
||||
unsigned int new_vtotal, vfp, new_vfp;
|
||||
|
||||
vcstate = to_rockchip_crtc_state(crtc->state);
|
||||
/*
|
||||
* When hdmi qms-vrr is enabled and M_VRR(The difference between
|
||||
* current refresh rate vfp and the vfp of the base fresh rate)
|
||||
* is fractional. Sources should alternate between two sequential
|
||||
* values of M_VRR to better approximate the fractional M_VRR.
|
||||
*/
|
||||
if (vcstate->hdmi_vrr.next_tfr_val && vcstate->hdmi_vrr.m_const) {
|
||||
adjust_mode = &crtc->state->adjusted_mode;
|
||||
new_vtotal = rockchip_hdmi_vrr_calc_new_vtotal(vcstate->hdmi_vrr.mconst_val,
|
||||
vcstate->hdmi_vrr.vrr_frame_cnt);
|
||||
if (!new_vtotal) {
|
||||
DRM_ERROR("qms vrr invalid vtotal\n");
|
||||
} else {
|
||||
vfp = adjust_mode->vsync_start - adjust_mode->vdisplay;
|
||||
new_vfp = vfp + new_vtotal - adjust_mode->vtotal;
|
||||
vop2_crtc_update_vrr_timing(crtc, new_vtotal, new_vfp);
|
||||
vcstate->hdmi_vrr.vrr_frame_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t vop2_isr(int irq, void *data)
|
||||
{
|
||||
struct vop2 *vop2 = data;
|
||||
@@ -14340,6 +14436,7 @@ static irqreturn_t vop2_isr(int irq, void *data)
|
||||
drm_crtc_handle_vblank(crtc);
|
||||
vop2_handle_vblank(vop2, crtc);
|
||||
}
|
||||
vop2_frac_mvrr_update(crtc, vp);
|
||||
active_irqs &= ~FS_FIELD_INTR;
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
@@ -14544,6 +14641,7 @@ static irqreturn_t vop3_vp_isr(int irq, void *data)
|
||||
rockchip_drm_dbg(vop2->dev, VOP_DEBUG_VSYNC, "vsync_vp%d", vp->id);
|
||||
drm_crtc_handle_vblank(crtc);
|
||||
vop2_handle_vblank(vop2, crtc);
|
||||
vop2_frac_mvrr_update(crtc, vp);
|
||||
active_irqs &= ~FS_FIELD_INTR;
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -2385,8 +2385,6 @@ int rga_mm_import_buffer(struct rga_external_buffer *external_buffer,
|
||||
internal_buffer = kzalloc(sizeof(struct rga_internal_buffer), GFP_KERNEL);
|
||||
if (internal_buffer == NULL) {
|
||||
rga_err("%s alloc internal_buffer error!\n", __func__);
|
||||
|
||||
mutex_unlock(&mm->lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
@@ -357,6 +357,9 @@ 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_set_gaming_vrr_enable(struct dw_hdmi_qp *hdmi_qp, bool enable);
|
||||
void dw_hdmi_qp_set_qms(struct dw_hdmi_qp *hdmi, u8 next_tfr, u8 m_const);
|
||||
u8 dw_hdmi_qp_get_next_tfr(struct dw_hdmi_qp *hdmi);
|
||||
|
||||
void dw_hdmi_qp_unbind(struct dw_hdmi_qp *hdmi);
|
||||
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
|
||||
|
||||
@@ -1406,6 +1406,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
"Failed to add default virtual iface\n");
|
||||
}
|
||||
|
||||
/* add one default AP interface if supported */
|
||||
if (local->hw.wiphy->interface_modes & (BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT)) && !ieee80211_hw_check(hw, NO_AUTO_VIF)) {
|
||||
struct vif_params params = {0};
|
||||
|
||||
result = ieee80211_if_add(local, "p2p%d", NET_NAME_ENUM, NULL,
|
||||
NL80211_IFTYPE_STATION, ¶ms);
|
||||
if (result)
|
||||
wiphy_warn(local->hw.wiphy,
|
||||
"Failed to add p2p virtual iface\n");
|
||||
}
|
||||
|
||||
wiphy_unlock(hw->wiphy);
|
||||
rtnl_unlock();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user