Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HDMI support for modes that require the scrambler (4k @ 60Hz, most importantly) #4302

Merged
merged 10 commits into from
Apr 21, 2021
3 changes: 3 additions & 0 deletions drivers/clk/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -2498,6 +2498,9 @@ void clk_request_done(struct clk_request *req)
{
struct clk_core *core = req->clk->core;

if (!req)
return;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor point.
Line 2499 has already dereferenced req->clk->core to assign to core, so it's too late to be checking for NULL here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly it works, but you're totally right, I'll fix it upstream

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compiler reordering might work in your favour here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a blow up on what I presume to be this, hence looking at the code

[    5.794257] 8<--- cut here ---
[    5.794310] Unable to handle kernel NULL pointer dereference at virtual address 00000008
[    5.794362] pgd = (ptrval)
[    5.794403] [00000008] *pgd=03a2e003, *pmd=00000000
[    5.794470] Internal error: Oops: 206 [#1] SMP ARM
[    5.794495] Modules linked in: bcm2835_codec(C) v4l2_mem2mem raspberrypi_hwmon bcm2835_v4l2(C) videobuf2_vmalloc bcm2835_isp(C) bcm2835_mmal_vchiq(C) videobuf2_dma_contig videobuf2_memops videobuf2_v4l2 videobuf2_common brcmfmac brcmutil i2c_mux_pinctrl i2c_mux sha256_generic cfg80211 rfkill v3d gpu_sched dwc2 i2c_brcmstb vc4(+) roles cec i2c_bcm2835 drm_kms_helper videodev drm mc drm_panel_orientation_quirks snd_bcm2835(C) snd_soc_core vc_sm_cma(C) snd_compress snd_pcm_dmaengine snd_pcm snd_timer snd rpivid_mem syscopyarea sysfillrect sysimgblt fb_sys_fops backlight uio_pdrv_genirq uio nvmem_rmem i2c_dev ip_tables x_tables ipv6
[    5.795077] CPU: 2 PID: 166 Comm: systemd-udevd Tainted: G         C        5.10.31-v7l+ #5
[    5.795107] Hardware name: BCM2711
[    5.795144] PC is at clk_request_done+0x14/0xac
[    5.795278] LR is at vc4_hdmi_encoder_post_crtc_powerdown+0x17c/0x230 [vc4]
[    5.795315] pc : [<c07f20e4>]    lr : [<bf39536c>]    psr: 60000113
[    5.795340] sp : c3a4db18  ip : c3a4db30  fp : c3a4db2c
[    5.795368] r10: 0000000a  r9 : 00000014  r8 : 00000000
[    5.795400] r7 : c271d290  r6 : c4164040  r5 : c3af6800  r4 : c271d290
[    5.795431] r3 : 00000000  r2 : 00000000  r1 : 00000000  r0 : 00000000
[    5.795467] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
[    5.795498] Control: 30c5383d  Table: 02fdf980  DAC: 55555555
[    5.795527] Process systemd-udevd (pid: 166, stack limit = 0x(ptrval))
[    5.795551] Stack: (0xc3a4db18 to 0xc3a4e000)
[    5.795586] db00:                                                       c271d290 c3af6800
[    5.795645] db20: c3a4db44 c3a4db30 bf39536c c07f20dc 00000000 c0ebcf84 c3a4db7c c3a4db48
[    5.795701] db40: bf385ee4 bf3951fc 00000001 c271c800 c3a4db7c c4164040 c271c800 c4164040
[    5.795750] db60: c271c9d0 00000001 c12f0a2c c37717c0 c3a4db94 c3a4db80 bf386c14 bf385d7c
[    5.795798] db80: c271c800 c19bb810 c3a4dbbc c3a4db98 bf387574 bf386b94 bf387324 c3af2540
[    5.795832] dba0: c2f07ac0 000000d8 00000009 c3af2800 c3a4dbf4 c3a4dbc0 c0850810 bf387330
[    5.795883] dbc0: c12f0a10 00000000 c0b97714 c12f0a10 c3af2800 c19bb810 bf3ab95c bf3abee0
[    5.795917] dbe0: bf3abee0 c1205048 c3a4dc1c c3a4dbf8 c0850d0c c08506a4 c0c4ce10 c19bb810
[    5.795949] dc00: 00000000 00000000 bf3b87cc c19bb810 c3a4dc5c c3a4dc20 bf38768c c0850c38
[    5.795980] dc20: c19b9810 c19bb810 c37717c0 98d4afc0 c086aa8c 00000000 c19bb810 bf3b8150
[    5.796012] dc40: c1401108 bf3b8150 0000001f 00000000 c3a4dc7c c3a4dc60 c085a750 bf3875f0
[    5.796057] dc60: c085a6d4 c1401100 c19bb810 00000000 c3a4dcac c3a4dc80 c08584ac c085a6e0
[    5.796092] dc80: 00000000 c19bb810 bf3b8150 bf3b8150 c1205048 00000000 00000001 c3b00b08
[    5.796124] dca0: c3a4dcc4 c3a4dcb0 c085896c c08583b4 00000000 c19bb810 c3a4dce4 c3a4dcc8
[    5.796170] dcc0: c0858bbc c085890c c085ae34 00000000 bf3b8150 c19bb810 c3a4dd04 c3a4dce8
[    5.796202] dce0: c0858c54 c0858b60 c19be640 00000000 bf3b8150 c0858bc4 c3a4dd34 c3a4dd08
[    5.796238] dd00: c0856254 c0858bd0 c3a4dd40 c18eca58 c19be634 98d4afc0 bf3b8150 c12f0ff0
[    5.796272] dd20: c3771700 00000000 c3a4dd44 c3a4dd38 c0857e0c c08561e8 c3a4dd6c c3a4dd48
[    5.796305] dd40: c08576b8 c0857dec bf3b1864 c3a4dd58 bf3b8150 bf191000 c3a4c000 c1205048
[    5.796337] dd60: c3a4dd84 c3a4dd70 c0859324 c0857584 bf3b8940 bf191000 c3a4dd94 c3a4dd88
[    5.796392] dd80: c085a680 c08592a4 c3a4dda4 c3a4dd98 bf191040 c085a63c c3a4de1c c3a4dda8
[    5.796433] dda0: c0202430 bf19100c 00000001 c0b97714 00000080 c1801e40 c3a4ddd4 c3a4ddc8
[    5.796467] ddc0: c0b97714 c04243b8 c3a4de1c c3a4ddd8 c04243b8 c03e0f04 c3a4de14 c3a4dde8
[    5.796499] dde0: 00001e29 00000008 c0b90d24 c3b00c00 c3b00b08 98d4afc0 bf3b8940 c3b00bc0
[    5.796531] de00: 00000001 bf3b8940 c3b00b00 00000001 c3a4de44 c3a4de20 c0b90d60 c02023ec
[    5.796563] de20: c3a4de44 c3a4de30 c0405918 c3a4df30 c1205048 00000001 c3a4df14 c3a4de48
[    5.796594] de40: c02cfc1c c0b90cfc bf3b894c 00007fff bf3b8940 c02cc9d0 c3a4de84 bf1a0161
[    5.796626] de60: bf3b8a54 bf3b894c bf3b8b4c 00000000 00000001 c1205048 00000000 00000000
[    5.796657] de80: 00000000 00000000 00000000 00000000 c0e2aa58 00000001 00000000 c0eeb5d4
[    5.796689] dea0: c0ed3d38 00000000 6e72656b 00006c65 00000000 00000000 00000000 00000000
[    5.796720] dec0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    5.796753] dee0: 00000000 98d4afc0 c3a4df2c c1205048 00000000 b6dfe8e0 0000001d c0200204
[    5.796784] df00: c3a4c000 0000017b c3a4dfa4 c3a4df18 c02d04c4 c02cdc50 c3a4df2c 7fffffff
[    5.796817] df20: 00000000 00000002 8000cb00 f12b4000 f12e4c57 f12eb540 f12b4000 000547f4
[    5.796867] df40: f1307fac f12ebd3d f12f4430 00035000 0003b860 0000eb04 0003fba3 00000000
[    5.796915] df60: 00000000 00000000 0000eaf4 00000033 00000034 0000002a 00000018 00000011
[    5.796971] df80: 00000000 98d4afc0 8000cb00 00000000 00000000 0000017b 00000000 c3a4dfa8
[    5.797019] dfa0: c02001e4 c02d041c 8000cb00 00000000 0000001d b6dfe8e0 00000000 b6dff3f4
[    5.797066] dfc0: 8000cb00 00000000 00000000 0000017b 022090f0 00000000 0220c5b8 00000000
[    5.797117] dfe0: beb95180 beb95170 b6df59d8 b6ee5af0 60000010 0000001d 00000000 00000000
[    5.797153] Backtrace: 
[    5.797286] [<c07f20d0>] (clk_request_done) from [<bf39536c>] (vc4_hdmi_encoder_post_crtc_powerdown+0x17c/0x230 [vc4])
[    5.797322]  r5:c3af6800 r4:c271d290
[    5.797539] [<bf3951f0>] (vc4_hdmi_encoder_post_crtc_powerdown [vc4]) from [<bf385ee4>] (vc4_crtc_disable+0x174/0x1b8 [vc4])
[    5.797577]  r5:c0ebcf84 r4:00000000
[    5.797780] [<bf385d70>] (vc4_crtc_disable [vc4]) from [<bf386c14>] (vc4_crtc_disable_at_boot+0x8c/0xb4 [vc4])
[    5.797819]  r10:c37717c0 r9:c12f0a2c r8:00000001 r7:c271c9d0 r6:c4164040 r5:c271c800
[    5.797847]  r4:c4164040
[    5.798027] [<bf386b88>] (vc4_crtc_disable_at_boot [vc4]) from [<bf387574>] (vc4_drm_bind+0x250/0x2c0 [vc4])
[    5.798060]  r5:c19bb810 r4:c271c800
[    5.798173] [<bf387324>] (vc4_drm_bind [vc4]) from [<c0850810>] (try_to_bring_up_master+0x178/0x1c8)
[    5.798211]  r8:c3af2800 r7:00000009 r6:000000d8 r5:c2f07ac0 r4:c3af2540 r3:bf387324
[    5.798263] [<c0850698>] (try_to_bring_up_master) from [<c0850d0c>] (component_master_add_with_match+0xe0/0x114)
[    5.798304]  r10:c1205048 r9:bf3abee0 r8:bf3abee0 r7:bf3ab95c r6:c19bb810 r5:c3af2800
[    5.798340]  r4:c12f0a10
[    5.798460] [<c0850c2c>] (component_master_add_with_match) from [<bf38768c>] (vc4_platform_drm_probe+0xa8/0xc8 [vc4])
[    5.798507]  r7:c19bb810 r6:bf3b87cc r5:00000000 r4:00000000
[    5.798628] [<bf3875e4>] (vc4_platform_drm_probe [vc4]) from [<c085a750>] (platform_drv_probe+0x7c/0xb4)
[    5.798664]  r10:00000000 r9:0000001f r8:bf3b8150 r7:c1401108 r6:bf3b8150 r5:c19bb810
[    5.798691]  r4:00000000
[    5.798716] [<c085a6d4>] (platform_drv_probe) from [<c08584ac>] (really_probe+0x104/0x3d4)
[    5.798748]  r6:00000000 r5:c19bb810 r4:c1401100 r3:c085a6d4
[    5.798776] [<c08583a8>] (really_probe) from [<c085896c>] (driver_probe_device+0x6c/0xc4)
[    5.798808]  r10:c3b00b08 r9:00000001 r8:00000000 r7:c1205048 r6:bf3b8150 r5:bf3b8150
[    5.798837]  r4:c19bb810 r3:00000000
[    5.798863] [<c0858900>] (driver_probe_device) from [<c0858bbc>] (device_driver_attach+0x68/0x70)
[    5.798894]  r5:c19bb810 r4:00000000
[    5.798919] [<c0858b54>] (device_driver_attach) from [<c0858c54>] (__driver_attach+0x90/0xcc)
[    5.798951]  r6:c19bb810 r5:bf3b8150 r4:00000000 r3:c085ae34
[    5.798983] [<c0858bc4>] (__driver_attach) from [<c0856254>] (bus_for_each_dev+0x78/0xc4)
[    5.799014]  r6:c0858bc4 r5:bf3b8150 r4:00000000 r3:c19be640
[    5.799045] [<c08561dc>] (bus_for_each_dev) from [<c0857e0c>] (driver_attach+0x2c/0x30)
[    5.799075]  r7:00000000 r6:c3771700 r5:c12f0ff0 r4:bf3b8150
[    5.799107] [<c0857de0>] (driver_attach) from [<c08576b8>] (bus_add_driver+0x140/0x1f8)
[    5.799143] [<c0857578>] (bus_add_driver) from [<c0859324>] (driver_register+0x8c/0x124)
[    5.799177]  r7:c1205048 r6:c3a4c000 r5:bf191000 r4:bf3b8150
[    5.799207] [<c0859298>] (driver_register) from [<c085a680>] (__platform_driver_register+0x50/0x58)
[    5.799246]  r5:bf191000 r4:bf3b8940
[    5.799370] [<c085a630>] (__platform_driver_register) from [<bf191040>] (vc4_drm_register+0x40/0x1000 [vc4])
[    5.799496] [<bf191000>] (vc4_drm_register [vc4]) from [<c0202430>] (do_one_initcall+0x50/0x254)
[    5.799535] [<c02023e0>] (do_one_initcall) from [<c0b90d60>] (do_init_module+0x70/0x24c)
[    5.799568]  r9:00000001 r8:c3b00b00 r7:bf3b8940 r6:00000001 r5:c3b00bc0 r4:bf3b8940
[    5.799604] [<c0b90cf0>] (do_init_module) from [<c02cfc1c>] (load_module+0x1fd8/0x2640)
[    5.799634]  r6:00000001 r5:c1205048 r4:c3a4df30
[    5.799663] [<c02cdc44>] (load_module) from [<c02d04c4>] (sys_finit_module+0xb4/0xd8)
[    5.799695]  r10:0000017b r9:c3a4c000 r8:c0200204 r7:0000001d r6:b6dfe8e0 r5:00000000
[    5.799723]  r4:c1205048
[    5.799756] [<c02d0410>] (sys_finit_module) from [<c02001e4>] (__sys_trace_return+0x0/0x1c)
[    5.799798] Exception stack(0xc3a4dfa8 to 0xc3a4dff0)
[    5.799833] dfa0:                   8000cb00 00000000 0000001d b6dfe8e0 00000000 b6dff3f4
[    5.799878] dfc0: 8000cb00 00000000 00000000 0000017b 022090f0 00000000 0220c5b8 00000000
[    5.799920] dfe0: beb95180 beb95170 b6df59d8 b6ee5af0
[    5.799961]  r7:0000017b r6:00000000 r5:00000000 r4:8000cb00
[    5.799990] Code: e92dd830 e24cb004 e52de004 e8bd4000 (e5903008) 
[    5.800050] ---[ end trace 50b9549224214350 ]---

clk_prepare_lock();

list_del(&req->list);
Expand Down
28 changes: 26 additions & 2 deletions drivers/gpu/drm/vc4/vc4_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,19 @@ static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc,
PV_CONTROL_FIFO_LEVEL);
}

static struct drm_encoder *vc4_get_connector_encoder(struct drm_connector *connector)
{
struct drm_encoder *encoder;

if (drm_WARN_ON(connector->dev, hweight32(connector->possible_encoders) != 1))
return NULL;

drm_connector_for_each_possible_encoder(connector, encoder)
return encoder;

return NULL;
}

/*
* Returns the encoder attached to the CRTC.
*
Expand All @@ -286,9 +299,17 @@ static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc)

drm_connector_list_iter_begin(crtc->dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->state->crtc == crtc) {
struct drm_encoder *encoder;
struct vc4_encoder *vc4_encoder;

encoder = vc4_get_connector_encoder(connector);
if (!encoder)
continue;

vc4_encoder = to_vc4_encoder(encoder);
if (vc4_encoder->crtc == crtc) {
drm_connector_list_iter_end(&conn_iter);
return connector->encoder;
return encoder;
}
}
drm_connector_list_iter_end(&conn_iter);
Expand Down Expand Up @@ -1049,6 +1070,9 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
struct vc4_encoder *vc4_encoder;
int i;

if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL)
continue;

vc4_encoder = to_vc4_encoder(encoder);
for (i = 0; i < ARRAY_SIZE(pv_data->encoder_types); i++) {
if (vc4_encoder->type == encoder_types[i]) {
Expand Down
47 changes: 46 additions & 1 deletion drivers/gpu/drm/vc4/vc4_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,41 @@ static int compare_dev(struct device *dev, void *data)
return dev == data;
}

static struct drm_crtc *vc4_drv_find_crtc(struct drm_device *drm,
struct drm_encoder *encoder)
{
struct drm_crtc *crtc;

if (WARN_ON(hweight32(encoder->possible_crtcs) != 1))
return NULL;

drm_for_each_crtc(crtc, drm) {
if (!drm_encoder_crtc_ok(encoder, crtc))
continue;

return crtc;
}

return NULL;
}

static void vc4_drv_set_encoder_data(struct drm_device *drm)
{
struct drm_encoder *encoder;

drm_for_each_encoder(encoder, drm) {
struct vc4_encoder *vc4_encoder;
struct drm_crtc *crtc;

crtc = vc4_drv_find_crtc(drm, encoder);
if (WARN_ON(!crtc))
return;

vc4_encoder = to_vc4_encoder(encoder);
vc4_encoder->crtc = crtc;
}
}

static void vc4_match_add_drivers(struct device *dev,
struct component_match **match,
struct platform_driver *const *drivers,
Expand Down Expand Up @@ -308,6 +343,7 @@ static int vc4_drm_bind(struct device *dev)
ret = component_bind_all(dev, drm);
if (ret)
return ret;
vc4_drv_set_encoder_data(drm);

if (!vc4->firmware_kms) {
ret = vc4_plane_create_additional_planes(drm);
Expand Down Expand Up @@ -354,12 +390,21 @@ static const struct component_master_ops vc4_drm_ops = {
.unbind = vc4_drm_unbind,
};

/*
* This list determines the binding order of our components, and we have
* a few constraints:
* - The TXP driver needs to be bound before the PixelValves (CRTC)
* but after the HVS to set the possible_crtc field properly
* - The HDMI driver needs to be bound after the HVS so that we can
* lookup the HVS maximum core clock rate and figure out if we
* support 4kp60 or not.
*/
static struct platform_driver *const component_drivers[] = {
&vc4_hvs_driver,
&vc4_hdmi_driver,
&vc4_vec_driver,
&vc4_dpi_driver,
&vc4_dsi_driver,
&vc4_hvs_driver,
&vc4_txp_driver,
&vc4_crtc_driver,
&vc4_firmware_kms_driver,
Expand Down
10 changes: 10 additions & 0 deletions drivers/gpu/drm/vc4/vc4_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,16 @@ enum vc4_encoder_type {

struct vc4_encoder {
struct drm_encoder base;

/*
* At boot time, we need to be able to retrieve the CRTC for a given
* connector in order to run the disable hooks below to avoid the stuck
* pixel issue. Unfortunately the drm_connector->encoder pointer is
* NULL at that time so we can't move up the chain, so we'll store it
* ourselves here.
*/
struct drm_crtc *crtc;

enum vc4_encoder_type type;
u32 clock_select;

Expand Down
122 changes: 113 additions & 9 deletions drivers/gpu/drm/vc4/vc4_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_scdc_helper.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/i2c.h>
Expand Down Expand Up @@ -78,6 +79,8 @@
#define VC5_HDMI_VERTB_VSPO_SHIFT 16
#define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16)

#define VC5_HDMI_SCRAMBLER_CTL_ENABLE BIT(0)

#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT 8
#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK VC4_MASK(10, 8)

Expand All @@ -93,7 +96,6 @@
# define VC4_HD_M_ENABLE BIT(0)

#define CEC_CLOCK_FREQ 40000
#define VC4_HSM_MID_CLOCK 149985000

#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1

Expand Down Expand Up @@ -402,6 +404,11 @@ static void hdmi_codec_eld_chmap(struct vc4_hdmi *vc4_hdmi)

#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)

static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode)
{
return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK;
}

static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *)m->private;
Expand Down Expand Up @@ -524,6 +531,18 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
ret = drm_add_edid_modes(connector, edid);
kfree(edid);

if (vc4_hdmi->disable_4kp60) {
struct drm_device *drm = connector->dev;
struct drm_display_mode *mode;

list_for_each_entry(mode, &connector->probed_modes, head) {
if (vc4_hdmi_mode_needs_scrambling(mode)) {
drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
}
}
}

return ret;
}

Expand Down Expand Up @@ -825,6 +844,64 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
vc4_hdmi_set_hdr_infoframe(encoder);
}

static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
struct drm_display_mode *mode)
{
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_display_info *display = &vc4_hdmi->connector.display_info;

if (!vc4_encoder->hdmi_monitor)
return false;

if (!display->hdmi.scdc.supported ||
!display->hdmi.scdc.scrambling.supported)
return false;

return true;
}

static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
{
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);

if (!vc4_hdmi_supports_scrambling(encoder, mode))
return;

if (!vc4_hdmi_mode_needs_scrambling(mode))
return;

drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
drm_scdc_set_scrambling(vc4_hdmi->ddc, true);

HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
VC5_HDMI_SCRAMBLER_CTL_ENABLE);
}

static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_crtc *crtc = encoder->crtc;

/*
* At boot, encoder->crtc will be NULL. Since we don't know the
* state of the scrambler and in order to avoid any
* inconsistency, let's disable it all the time.
*/
if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode))
return;

if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode))
return;

HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
~VC5_HDMI_SCRAMBLER_CTL_ENABLE);

drm_scdc_set_scrambling(vc4_hdmi->ddc, false);
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
}

static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
struct drm_atomic_state *state)
{
Expand All @@ -837,6 +914,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,

HDMI_WRITE(HDMI_VID_CTL,
HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);

vc4_hdmi_disable_scrambling(encoder);
}

static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
Expand Down Expand Up @@ -1120,7 +1199,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
conn_state_to_vc4_hdmi_conn_state(conn_state);
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
unsigned long pixel_rate, hsm_rate;
unsigned long bvb_rate, pixel_rate, hsm_rate;
int ret;

ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev);
Expand Down Expand Up @@ -1174,12 +1253,14 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,

vc4_hdmi_cec_update_clk_div(vc4_hdmi);

/*
* FIXME: When the pixel freq is 594MHz (4k60), this needs to be setup
* at 300MHz.
*/
vc4_hdmi->bvb_req = clk_request_start(vc4_hdmi->pixel_bvb_clock,
(hsm_rate > VC4_HSM_MID_CLOCK ? 150000000 : 75000000));
if (pixel_rate > 297000000)
bvb_rate = 300000000;
else if (pixel_rate > 148500000)
bvb_rate = 150000000;
else
bvb_rate = 75000000;

vc4_hdmi->bvb_req = clk_request_start(vc4_hdmi->pixel_bvb_clock, bvb_rate);
if (IS_ERR(vc4_hdmi->bvb_req)) {
DRM_ERROR("Failed to set pixel bvb clock rate: %ld\n", PTR_ERR(vc4_hdmi->bvb_req));
clk_request_done(vc4_hdmi->hsm_req);
Expand Down Expand Up @@ -1290,6 +1371,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
}

vc4_hdmi_recenter_fifo(vc4_hdmi);
vc4_hdmi_enable_scrambling(encoder);
}

static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
Expand Down Expand Up @@ -1342,6 +1424,9 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
if (pixel_rate > vc4_hdmi->variant->max_pixel_clock)
return -EINVAL;

if (vc4_hdmi->disable_4kp60 && (pixel_rate > HDMI_14_MAX_TMDS_CLK))
return -EINVAL;

vc4_state->pixel_rate = pixel_rate;

return 0;
Expand All @@ -1361,6 +1446,9 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock)
return MODE_CLOCK_HIGH;

if (vc4_hdmi->disable_4kp60 && vc4_hdmi_mode_needs_scrambling(mode))
return MODE_CLOCK_HIGH;

return MODE_OK;
}

Expand Down Expand Up @@ -2623,9 +2711,25 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
vc4_hdmi->disable_wifi_frequencies =
of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence");

if (variant->max_pixel_clock == 600000000) {
struct vc4_dev *vc4 = to_vc4_dev(drm);
long max_rate = clk_round_rate(vc4->hvs->core_clk, 550000000);

if (max_rate < 550000000)
vc4_hdmi->disable_4kp60 = true;
}

if (vc4_hdmi->variant->reset)
vc4_hdmi->variant->reset(vc4_hdmi);

if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") ||
of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) &&
HDMI_READ(HDMI_VID_CTL) & VC4_HD_VID_CTL_ENABLE) {
clk_prepare_enable(vc4_hdmi->pixel_clock);
clk_prepare_enable(vc4_hdmi->hsm_clock);
clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
}

pm_runtime_enable(dev);

drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
Expand Down Expand Up @@ -2740,7 +2844,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
.max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
.max_pixel_clock = 600000000,
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
Expand Down
8 changes: 8 additions & 0 deletions drivers/gpu/drm/vc4/vc4_hdmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ struct vc4_hdmi {
*/
bool disable_wifi_frequencies;

/*
* Even if HDMI0 on the RPi4 can output modes requiring a pixel
* rate higher than 297MHz, it needs some adjustments in the
* config.txt file to be able to do so and thus won't always be
* available.
*/
bool disable_4kp60;

struct cec_adapter *cec_adap;
struct cec_msg cec_rx_msg;
bool cec_tx_ok;
Expand Down
Loading