Commit b2eab3b8 authored by Vladimir Bashkirtsev's avatar Vladimir Bashkirtsev

Fixed VC4 driver in Raspberry Pi patch

parent d9237d13
......@@ -74298,7 +74298,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/Makefile linux-5.12.10-rpi/drivers/g
vc4_hdmi.o \
diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_crtc.c
--- linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c 2021-06-10 11:41:49.000000000 +0000
+++ linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_crtc.c 2025-06-20 00:09:07.027997723 +0000
+++ linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_crtc.c 2025-06-19 12:13:33.443261180 +0000
@@ -279,19 +279,15 @@
* allows drivers to push pixels to more than one encoder from the
* same CRTC.
......@@ -74326,7 +74326,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.12.10-rpi/drivers
return NULL;
}
@@ -305,11 +301,11 @@
@@ -305,22 +301,29 @@
CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_FIFO_CLR);
}
......@@ -74340,7 +74340,11 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.12.10-rpi/drivers
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
@@ -319,8 +315,15 @@
- struct drm_crtc_state *state = crtc->state;
- struct drm_display_mode *mode = &state->adjusted_mode;
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct drm_display_mode *mode = &crtc_state->adjusted_mode;
bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
......@@ -74443,7 +74447,68 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.12.10-rpi/drivers
if (is_dsi)
CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
@@ -496,8 +510,12 @@
@@ -421,10 +435,10 @@
}
static int vc4_crtc_disable(struct drm_crtc *crtc,
+ struct drm_encoder *encoder,
struct drm_atomic_state *state,
unsigned int channel)
{
- struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -465,10 +479,29 @@
return 0;
}
+static struct drm_encoder *vc4_crtc_get_encoder_by_type(struct drm_crtc *crtc,
+ enum vc4_encoder_type type)
+{
+ struct drm_encoder *encoder;
+
+ drm_for_each_encoder(encoder, crtc->dev) {
+ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
+
+ if (vc4_encoder->type == type)
+ return encoder;
+ }
+
+ return NULL;
+}
+
int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
{
struct drm_device *drm = crtc->dev;
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ enum vc4_encoder_type encoder_type;
+ const struct vc4_pv_data *pv_data;
+ struct drm_encoder *encoder;
+ unsigned encoder_sel;
int channel;
if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
@@ -487,7 +520,17 @@
if (channel < 0)
return 0;
- return vc4_crtc_disable(crtc, NULL, channel);
+ encoder_sel = VC4_GET_FIELD(CRTC_READ(PV_CONTROL), PV_CONTROL_CLK_SELECT);
+ if (WARN_ON(encoder_sel != 0))
+ return 0;
+
+ pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
+ encoder_type = pv_data->encoder_types[encoder_sel];
+ encoder = vc4_crtc_get_encoder_by_type(crtc, encoder_type);
+ if (WARN_ON(!encoder))
+ return 0;
+
+ return vc4_crtc_disable(crtc, encoder, NULL, channel);
}
static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -496,14 +539,18 @@
struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
crtc);
struct vc4_crtc_state *old_vc4_state = to_vc4_crtc_state(old_state);
......@@ -74456,7 +74521,14 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.12.10-rpi/drivers
require_hvs_enabled(dev);
/* Disable vblank irq handling before crtc is disabled. */
@@ -522,11 +540,16 @@
drm_crtc_vblank_off(crtc);
- vc4_crtc_disable(crtc, state, old_vc4_state->assigned_channel);
+ vc4_crtc_disable(crtc, encoder, state, old_vc4_state->assigned_channel);
/*
* Make sure we issue a vblank event after disabling the CRTC if
@@ -522,11 +569,16 @@
static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
......@@ -74474,7 +74546,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.12.10-rpi/drivers
require_hvs_enabled(dev);
/* Enable vblank irq handling before crtc is started otherwise
@@ -539,7 +562,7 @@
@@ -539,7 +591,7 @@
if (vc4_encoder->pre_crtc_configure)
vc4_encoder->pre_crtc_configure(encoder, state);
......@@ -74483,7 +74555,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.12.10-rpi/drivers
CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_EN);
@@ -608,12 +631,27 @@
@@ -608,12 +660,27 @@
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
struct drm_connector *conn;
struct drm_connector_state *conn_state;
......@@ -74511,6 +74583,25 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.12.10-rpi/drivers
for_each_new_connector_in_state(state, conn, conn_state,
i) {
if (conn_state->crtc != crtc)
@@ -994,7 +1061,7 @@
.fifo_depth = 64,
.pixels_per_clock = 1,
.encoder_types = {
- [0] = VC4_ENCODER_TYPE_VEC,
+ [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
},
};
@@ -1035,6 +1102,9 @@
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]) {
diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_debugfs.c linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_debugfs.c
--- linux-5.12.10/drivers/gpu/drm/vc4/vc4_debugfs.c 2021-06-10 11:41:49.000000000 +0000
+++ linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_debugfs.c 2025-06-19 19:37:20.021894985 +0000
......@@ -77103,7 +77194,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_firmware_kms.c linux-5.12.10-rpi
+};
diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_hdmi.c
--- linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c 2021-06-10 11:41:49.000000000 +0000
+++ linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_hdmi.c 2025-06-20 00:26:58.693402678 +0000
+++ linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_hdmi.c 2025-06-19 12:13:33.455261053 +0000
@@ -35,6 +35,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_probe_helper.h>
......@@ -77169,7 +77260,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
return 0;
}
@@ -153,6 +172,8 @@
@@ -153,18 +172,20 @@
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
#endif
......@@ -77178,7 +77269,12 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
static enum drm_connector_status
vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
@@ -163,8 +184,6 @@
struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
bool connected = false;
+ WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
+
if (vc4_hdmi->hpd_gpio) {
if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^
vc4_hdmi->hpd_active_low)
connected = true;
......@@ -77187,16 +77283,22 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
} else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
connected = true;
}
@@ -180,6 +199,8 @@
@@ -180,10 +201,14 @@
}
}
+ vc4_hdmi_enable_scrambling(&vc4_hdmi->encoder.base.base);
+
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
return connector_status_connected;
}
@@ -211,9 +232,47 @@
cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
return connector_status_disconnected;
}
@@ -211,9 +236,47 @@
ret = drm_add_edid_modes(connector, edid);
kfree(edid);
......@@ -77244,7 +77346,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
static void vc4_hdmi_connector_reset(struct drm_connector *connector)
{
struct vc4_hdmi_connector_state *old_state =
@@ -263,6 +322,7 @@
@@ -263,6 +326,7 @@
static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
.get_modes = vc4_hdmi_connector_get_modes,
......@@ -77252,7 +77354,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
};
static int vc4_hdmi_connector_init(struct drm_device *dev,
@@ -290,6 +350,11 @@
@@ -290,6 +354,11 @@
if (ret)
return ret;
......@@ -77264,7 +77366,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
drm_connector_attach_tv_margin_properties(connector);
drm_connector_attach_max_bpc_property(connector, 8, 12);
@@ -298,6 +363,10 @@
@@ -298,6 +367,10 @@
connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
......@@ -77275,7 +77377,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
drm_connector_attach_encoder(connector, encoder);
@@ -329,9 +398,11 @@
@@ -329,9 +402,11 @@
const struct vc4_hdmi_register *ram_packet_start =
&vc4_hdmi->variant->registers[HDMI_RAM_PACKET_START];
u32 packet_reg = ram_packet_start->offset + VC4_HDMI_PACKET_STRIDE * packet_id;
......@@ -77288,7 +77390,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
ssize_t len, i;
int ret;
@@ -364,6 +435,13 @@
@@ -364,6 +439,13 @@
packet_reg += 4;
}
......@@ -77302,7 +77404,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) &
@@ -395,7 +473,7 @@
@@ -395,7 +477,7 @@
vc4_encoder->limited_rgb_range ?
HDMI_QUANTIZATION_RANGE_LIMITED :
HDMI_QUANTIZATION_RANGE_FULL);
......@@ -77311,32 +77413,32 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
drm_hdmi_avi_infoframe_bars(&frame.avi, cstate);
vc4_hdmi_write_infoframe(encoder, &frame);
@@ -420,14 +498,28 @@
@@ -420,14 +502,28 @@
static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+ struct hdmi_audio_infoframe *audio = &vc4_hdmi->audio.infoframe;
union hdmi_infoframe frame;
- hdmi_audio_infoframe_init(&frame.audio);
+ union hdmi_infoframe frame;
+
+ memcpy(&frame.audio, audio, sizeof(*audio));
+ vc4_hdmi_write_infoframe(encoder, &frame);
+}
- frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
- frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
- frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
- frame.audio.channels = vc4_hdmi->audio.channels;
+
+static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder)
+{
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+ struct drm_connector *connector = &vc4_hdmi->connector;
+ struct drm_connector_state *conn_state = connector->state;
+ union hdmi_infoframe frame;
+
union hdmi_infoframe frame;
- hdmi_audio_infoframe_init(&frame.audio);
+ if (!vc4_hdmi->variant->supports_hdr)
+ return;
+
- frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
- frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
- frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
- frame.audio.channels = vc4_hdmi->audio.channels;
+ if (!conn_state->hdr_output_metadata)
+ return;
+
......@@ -77345,7 +77447,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
vc4_hdmi_write_infoframe(encoder, &frame);
}
@@ -444,6 +536,94 @@
@@ -444,6 +540,94 @@
*/
if (vc4_hdmi->audio.streaming)
vc4_hdmi_set_audio_infoframe(encoder);
......@@ -77440,7 +77542,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
}
static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
@@ -453,11 +633,13 @@
@@ -453,11 +637,13 @@
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
......@@ -77457,7 +77559,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
}
static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
@@ -466,13 +648,16 @@
@@ -466,14 +652,16 @@
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
int ret;
......@@ -77471,13 +77573,14 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
- HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
-
clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
+ if (vc4_hdmi->bvb_req)
+ clk_request_done(vc4_hdmi->bvb_req);
+ clk_request_done(vc4_hdmi->hsm_req);
clk_disable_unprepare(vc4_hdmi->hsm_clock);
clk_disable_unprepare(vc4_hdmi->pixel_clock);
@@ -573,12 +758,12 @@
ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
@@ -573,12 +761,12 @@
VC4_HDMI_VERTA_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL));
u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
......@@ -77493,7 +77596,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
VC4_HDMI_VERTB_VBP));
HDMI_WRITE(HDMI_HORZA,
@@ -619,12 +804,12 @@
@@ -619,12 +807,12 @@
VC5_HDMI_VERTA_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL));
u32 vertb = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
......@@ -77509,7 +77612,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
VC4_HDMI_VERTB_VBP));
unsigned char gcp;
bool gcp_en;
@@ -687,6 +872,11 @@
@@ -687,6 +875,11 @@
reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0;
HDMI_WRITE(HDMI_GCP_CONFIG, reg);
......@@ -77521,7 +77624,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
HDMI_WRITE(HDMI_CLOCK_STOP, 0);
}
@@ -714,32 +904,17 @@
@@ -714,32 +907,17 @@
"VC4_HDMI_FIFO_CTL_RECENTER_DONE");
}
......@@ -77558,7 +77661,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
int ret;
ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev);
@@ -752,36 +927,20 @@
@@ -752,66 +930,42 @@
ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
if (ret) {
DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
......@@ -77594,6 +77697,13 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
- if (ret) {
- DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
- return;
- }
-
- ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
- if (ret) {
- DRM_ERROR("Failed to turn on HSM clock: %d\n", ret);
- clk_disable_unprepare(vc4_hdmi->pixel_clock);
- return;
+ hsm_rate = vc4_hdmi->variant->calc_hsm_clock(vc4_hdmi, pixel_rate);
+ vc4_hdmi->hsm_req = clk_request_start(vc4_hdmi->hsm_clock, hsm_rate);
+ if (IS_ERR(vc4_hdmi->hsm_req)) {
......@@ -77601,9 +77711,6 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
+ goto err_disable_pixel_clk;
}
ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
@@ -793,25 +952,24 @@
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
- /*
......@@ -77641,7 +77748,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
}
if (vc4_hdmi->variant->phy_init)
@@ -824,6 +982,19 @@
@@ -824,6 +978,19 @@
if (vc4_hdmi->variant->set_timings)
vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
......@@ -77661,7 +77768,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
}
static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
@@ -861,6 +1032,7 @@
@@ -861,6 +1028,7 @@
HDMI_WRITE(HDMI_VID_CTL,
VC4_HD_VID_CTL_ENABLE |
......@@ -77669,7 +77776,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
VC4_HD_VID_CTL_UNDERFLOW_ENABLE |
VC4_HD_VID_CTL_FRAME_COUNTER_RESET |
(vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
@@ -906,6 +1078,7 @@
@@ -906,6 +1074,7 @@
}
vc4_hdmi_recenter_fifo(vc4_hdmi);
......@@ -77677,7 +77784,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
}
static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
@@ -926,6 +1099,7 @@
@@ -926,6 +1095,7 @@
unsigned long long tmds_rate;
if (vc4_hdmi->variant->unsupported_odd_h_timings &&
......@@ -77685,7 +77792,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
(mode->hsync_end % 2) || (mode->htotal % 2)))
return -EINVAL;
@@ -958,6 +1132,9 @@
@@ -958,6 +1128,9 @@
if (pixel_rate > vc4_hdmi->variant->max_pixel_clock)
return -EINVAL;
......@@ -77695,7 +77802,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
vc4_state->pixel_rate = pixel_rate;
return 0;
@@ -970,6 +1147,7 @@
@@ -970,6 +1143,7 @@
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
if (vc4_hdmi->variant->unsupported_odd_h_timings &&
......@@ -77703,7 +77810,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
(mode->hsync_end % 2) || (mode->htotal % 2)))
return MODE_H_ILLEGAL;
@@ -977,6 +1155,9 @@
@@ -977,6 +1151,9 @@
if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock)
return MODE_CLOCK_HIGH;
......@@ -77713,7 +77820,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
return MODE_OK;
}
@@ -987,6 +1168,39 @@
@@ -987,6 +1164,39 @@
.enable = vc4_hdmi_encoder_enable,
};
......@@ -77753,7 +77860,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
{
int i;
@@ -1012,12 +1226,13 @@
@@ -1012,12 +1222,13 @@
}
/* HDMI audio codec callbacks */
......@@ -77769,7 +77876,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
VC4_HD_MAI_SMP_N_MASK >>
VC4_HD_MAI_SMP_N_SHIFT,
(VC4_HD_MAI_SMP_M_MASK >>
@@ -1029,12 +1244,11 @@
@@ -1029,12 +1240,11 @@
VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
}
......@@ -77783,7 +77890,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
u32 n, cts;
u64 tmp;
@@ -1063,18 +1277,10 @@
@@ -1063,18 +1273,10 @@
return snd_soc_card_get_drvdata(card);
}
......@@ -77804,7 +77911,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
/*
* If the HDMI encoder hasn't probed, or the encoder is
@@ -1084,15 +1290,18 @@
@@ -1084,15 +1286,18 @@
VC4_HDMI_RAM_PACKET_ENABLE))
return -ENODEV;
......@@ -77830,7 +77937,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
return 0;
}
@@ -1112,48 +1321,96 @@
@@ -1112,48 +1317,96 @@
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
}
......@@ -77847,10 +77954,10 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
+ VC4_HD_MAI_CTL_DLATE |
+ VC4_HD_MAI_CTL_ERRORE |
+ VC4_HD_MAI_CTL_ERRORF);
+
+ if (vc4_hdmi->variant->phy_rng_disable)
+ vc4_hdmi->variant->phy_rng_disable(vc4_hdmi);
+
+ vc4_hdmi->audio.streaming = false;
vc4_hdmi_audio_reset(vc4_hdmi);
+}
......@@ -77953,7 +78060,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
/* The B frame identifier should match the value used by alsa-lib (8) */
audio_packet_config =
@@ -1161,122 +1418,33 @@
@@ -1161,122 +1414,33 @@
VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS |
VC4_SET_FIELD(0x8, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER);
......@@ -78086,7 +78193,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
static const struct snd_soc_dapm_widget vc4_hdmi_audio_widgets[] = {
SND_SOC_DAPM_OUTPUT("TX"),
};
@@ -1287,8 +1455,6 @@
@@ -1287,8 +1451,6 @@
static const struct snd_soc_component_driver vc4_hdmi_audio_component_drv = {
.name = "vc4-hdmi-codec-dai-component",
......@@ -78095,7 +78202,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
.dapm_widgets = vc4_hdmi_audio_widgets,
.num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets),
.dapm_routes = vc4_hdmi_audio_routes,
@@ -1299,28 +1465,6 @@
@@ -1299,28 +1461,6 @@
.non_legacy_dai_naming = 1,
};
......@@ -78124,7 +78231,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = {
.name = "vc4-hdmi-cpu-dai-component",
};
@@ -1347,7 +1491,6 @@
@@ -1347,7 +1487,6 @@
SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
},
......@@ -78132,7 +78239,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
};
static const struct snd_dmaengine_pcm_config pcm_conf = {
@@ -1355,6 +1498,31 @@
@@ -1355,6 +1494,31 @@
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
};
......@@ -78164,7 +78271,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
{
const struct vc4_hdmi_register *mai_data =
@@ -1362,13 +1530,16 @@
@@ -1362,13 +1526,16 @@
struct snd_soc_dai_link *dai_link = &vc4_hdmi->audio.link;
struct snd_soc_card *card = &vc4_hdmi->audio.card;
struct device *dev = &vc4_hdmi->pdev->dev;
......@@ -78183,7 +78290,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
return 0;
}
@@ -1408,12 +1579,13 @@
@@ -1408,12 +1575,13 @@
return ret;
}
......@@ -78203,7 +78310,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
}
dai_link->cpus = &vc4_hdmi->audio.cpu;
@@ -1426,9 +1598,9 @@
@@ -1426,9 +1594,9 @@
dai_link->name = "MAI";
dai_link->stream_name = "MAI PCM";
......@@ -78215,7 +78322,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
dai_link->platforms->name = dev_name(dev);
card->dai_link = dai_link;
@@ -1454,6 +1626,60 @@
@@ -1454,6 +1622,60 @@
}
......@@ -78276,7 +78383,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
#ifdef CONFIG_DRM_VC4_HDMI_CEC
static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv)
{
@@ -1572,51 +1798,74 @@
@@ -1572,51 +1794,74 @@
return ret;
}
......@@ -78289,11 +78396,11 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
- u32 val = HDMI_READ(HDMI_CEC_CNTRL_5);
+ u32 val;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
+ if (ret)
+ return ret;
+
+ val = HDMI_READ(HDMI_CEC_CNTRL_5);
val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
......@@ -78381,7 +78488,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
{
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
@@ -1696,38 +1945,46 @@
@@ -1696,38 +1941,46 @@
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
if (vc4_hdmi->variant->external_irq_controller) {
......@@ -78444,7 +78551,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
err_delete_cec_adap:
cec_delete_adapter(vc4_hdmi->cec_adap);
@@ -1736,6 +1993,15 @@
@@ -1736,6 +1989,15 @@
static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi)
{
......@@ -78460,7 +78567,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
cec_unregister_adapter(vc4_hdmi->cec_adap);
}
#else
@@ -1830,6 +2096,7 @@
@@ -1830,6 +2092,7 @@
struct platform_device *pdev = vc4_hdmi->pdev;
struct device *dev = &pdev->dev;
struct resource *res;
......@@ -78468,7 +78575,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi");
if (!res)
@@ -1926,6 +2193,38 @@
@@ -1926,9 +2189,64 @@
return PTR_ERR(vc4_hdmi->reset);
}
......@@ -78503,11 +78610,37 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->rm_regset, VC5_RM);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int vc4_hdmi_runtime_suspend(struct device *dev)
+{
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(vc4_hdmi->hsm_clock);
+
return 0;
}
@@ -1943,6 +2242,7 @@
+static int vc4_hdmi_runtime_resume(struct device *dev)
+{
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif
+
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
{
const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
@@ -1943,6 +2261,7 @@
vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
if (!vc4_hdmi)
return -ENOMEM;
......@@ -78515,12 +78648,19 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
dev_set_drvdata(dev, vc4_hdmi);
encoder = &vc4_hdmi->encoder.base.base;
@@ -1992,11 +2292,55 @@
@@ -1983,7 +2302,7 @@
&hpd_gpio_flags);
if (vc4_hdmi->hpd_gpio < 0) {
ret = vc4_hdmi->hpd_gpio;
- goto err_unprepare_hsm;
+ goto err_put_ddc;
}
vc4_hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW;
@@ -1992,10 +2311,62 @@
vc4_hdmi->disable_wifi_frequencies =
of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence");
- if (vc4_hdmi->variant->reset)
- vc4_hdmi->variant->reset(vc4_hdmi);
+ 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);
......@@ -78562,18 +78702,26 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
+ ret = vc4_hdmi_runtime_resume(dev);
+ if (ret)
+ goto err_put_ddc;
+
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
pm_runtime_enable(dev);
+ if (vc4_hdmi->variant->reset)
+ vc4_hdmi->variant->reset(vc4_hdmi);
+ pm_runtime_enable(dev);
+
if (vc4_hdmi->variant->reset)
vc4_hdmi->variant->reset(vc4_hdmi);
- pm_runtime_enable(dev);
+ 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);
+ }
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs);
@@ -2004,10 +2348,14 @@
@@ -2004,10 +2375,14 @@
if (ret)
goto err_destroy_encoder;
......@@ -78589,7 +78737,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
ret = vc4_hdmi_audio_init(vc4_hdmi);
if (ret)
goto err_free_cec;
@@ -2016,14 +2364,19 @@
@@ -2016,16 +2391,21 @@
vc4_hdmi_debugfs_regs,
vc4_hdmi);
......@@ -78605,11 +78753,14 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
err_destroy_encoder:
drm_encoder_cleanup(encoder);
-err_unprepare_hsm:
+ pm_runtime_put_sync(dev);
err_unprepare_hsm:
pm_runtime_disable(dev);
+err_put_ddc:
put_device(&vc4_hdmi->ddc->dev);
@@ -2061,6 +2414,7 @@
return ret;
@@ -2061,6 +2441,7 @@
kfree(vc4_hdmi->hd_regset.regs);
vc4_hdmi_cec_exit(vc4_hdmi);
......@@ -78617,7 +78768,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
drm_encoder_cleanup(&vc4_hdmi->encoder.base.base);
@@ -2101,14 +2455,16 @@
@@ -2101,14 +2482,16 @@
.phy_disable = vc4_hdmi_phy_disable,
.phy_rng_enable = vc4_hdmi_phy_rng_enable,
.phy_rng_disable = vc4_hdmi_phy_rng_disable,
......@@ -78635,7 +78786,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -2128,7 +2484,9 @@
@@ -2128,7 +2511,9 @@
.phy_disable = vc5_hdmi_phy_disable,
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
......@@ -78645,7 +78796,7 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
};
static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
@@ -2155,7 +2513,9 @@
@@ -2155,7 +2540,9 @@
.phy_disable = vc5_hdmi_phy_disable,
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
......@@ -78655,6 +78806,25 @@ diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.12.10-rpi/drivers
};
static const struct of_device_id vc4_hdmi_dt_match[] = {
@@ -2165,11 +2552,18 @@
{}
};
+static const struct dev_pm_ops vc4_hdmi_pm_ops = {
+ SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend,
+ vc4_hdmi_runtime_resume,
+ NULL)
+};
+
struct platform_driver vc4_hdmi_driver = {
.probe = vc4_hdmi_dev_probe,
.remove = vc4_hdmi_dev_remove,
.driver = {
.name = "vc4_hdmi",
.of_match_table = vc4_hdmi_dt_match,
+ .pm = &vc4_hdmi_pm_ops,
},
};
diff -uNr linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.h linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_hdmi.h
--- linux-5.12.10/drivers/gpu/drm/vc4/vc4_hdmi.h 2021-06-10 11:41:49.000000000 +0000
+++ linux-5.12.10-rpi/drivers/gpu/drm/vc4/vc4_hdmi.h 2025-06-19 19:37:20.049894724 +0000
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment