mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 14:23:38 +00:00
908 lines
28 KiB
Diff
908 lines
28 KiB
Diff
From d91a953904e1aeddf24a95af40fc1ae7ba2319fd Mon Sep 17 00:00:00 2001
|
|
From: Maxime Ripard <maxime@cerno.tech>
|
|
Date: Mon, 25 Oct 2021 16:11:08 +0200
|
|
Subject: [PATCH] drm/vc4: hdmi: Add a spinlock to protect register
|
|
access
|
|
|
|
The vc4 HDMI driver has multiple path shared between the CEC, ALSA and
|
|
KMS frameworks, plus two interrupt handlers (CEC and hotplug) that will
|
|
read and modify a number of registers.
|
|
|
|
Even though not bug has been reported so far, it's definitely unsafe, so
|
|
let's just add a spinlock to protect the register access of the HDMI
|
|
controller.
|
|
|
|
Link: https://lore.kernel.org/r/20211025141113.702757-5-maxime@cerno.tech
|
|
Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.")
|
|
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
|
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
|
---
|
|
drivers/gpu/drm/vc4/vc4_hdmi.c | 202 ++++++++++++++++++++++++++--
|
|
drivers/gpu/drm/vc4/vc4_hdmi.h | 5 +
|
|
drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 37 +++++
|
|
drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 2 +
|
|
4 files changed, 236 insertions(+), 10 deletions(-)
|
|
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
@@ -122,6 +122,10 @@ static int vc4_hdmi_debugfs_regs(struct
|
|
|
|
static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST);
|
|
udelay(1);
|
|
HDMI_WRITE(HDMI_M_CTL, 0);
|
|
@@ -133,24 +137,36 @@ static void vc4_hdmi_reset(struct vc4_hd
|
|
VC4_HDMI_SW_RESET_FORMAT_DETECT);
|
|
|
|
HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
reset_control_reset(vc4_hdmi->reset);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
HDMI_WRITE(HDMI_DVP_CTL, 0);
|
|
|
|
HDMI_WRITE(HDMI_CLOCK_STOP,
|
|
HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
#ifdef CONFIG_DRM_VC4_HDMI_CEC
|
|
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long cec_rate = clk_get_rate(vc4_hdmi->cec_clock);
|
|
+ unsigned long flags;
|
|
u16 clk_cnt;
|
|
u32 value;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
value = HDMI_READ(HDMI_CEC_CNTRL_1);
|
|
value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
|
|
|
|
@@ -158,9 +174,11 @@ static void vc4_hdmi_cec_update_clk_div(
|
|
* Set the clock divider: the hsm_clock rate and this divider
|
|
* setting will give a 40 kHz CEC clock.
|
|
*/
|
|
- clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ;
|
|
+ clk_cnt = cec_rate / CEC_CLOCK_FREQ;
|
|
value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT;
|
|
HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
#else
|
|
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
|
|
@@ -179,8 +197,16 @@ vc4_hdmi_connector_detect(struct drm_con
|
|
if (vc4_hdmi->hpd_gpio) {
|
|
if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio))
|
|
connected = true;
|
|
- } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
|
|
- connected = true;
|
|
+ } else {
|
|
+ unsigned long flags;
|
|
+ u32 hotplug;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+ hotplug = HDMI_READ(HDMI_HOTPLUG);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
+ if (hotplug & VC4_HDMI_HOTPLUG_CONNECTED)
|
|
+ connected = true;
|
|
}
|
|
|
|
if (connected) {
|
|
@@ -374,9 +400,12 @@ static int vc4_hdmi_stop_packet(struct d
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
|
u32 packet_id = type - 0x80;
|
|
+ unsigned long flags;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
|
HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
|
|
if (!poll)
|
|
return 0;
|
|
@@ -396,6 +425,7 @@ static void vc4_hdmi_write_infoframe(str
|
|
void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi,
|
|
ram_packet_start->reg);
|
|
uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
|
|
+ unsigned long flags;
|
|
ssize_t len, i;
|
|
int ret;
|
|
|
|
@@ -413,6 +443,8 @@ static void vc4_hdmi_write_infoframe(str
|
|
return;
|
|
}
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
for (i = 0; i < len; i += 7) {
|
|
writel(buffer[i + 0] << 0 |
|
|
buffer[i + 1] << 8 |
|
|
@@ -430,6 +462,9 @@ static void vc4_hdmi_write_infoframe(str
|
|
|
|
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
|
HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) &
|
|
BIT(packet_id)), 100);
|
|
if (ret)
|
|
@@ -549,6 +584,7 @@ static void vc4_hdmi_enable_scrambling(s
|
|
{
|
|
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
|
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
|
+ unsigned long flags;
|
|
|
|
if (!vc4_hdmi_supports_scrambling(encoder, mode))
|
|
return;
|
|
@@ -559,8 +595,10 @@ static void vc4_hdmi_enable_scrambling(s
|
|
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
|
|
drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
|
|
VC5_HDMI_SCRAMBLER_CTL_ENABLE);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
|
|
queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
|
|
msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
|
|
@@ -570,6 +608,7 @@ static void vc4_hdmi_disable_scrambling(
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
|
struct drm_crtc *crtc = encoder->crtc;
|
|
+ unsigned long flags;
|
|
|
|
/*
|
|
* At boot, encoder->crtc will be NULL. Since we don't know the
|
|
@@ -585,8 +624,10 @@ static void vc4_hdmi_disable_scrambling(
|
|
if (delayed_work_pending(&vc4_hdmi->scrambling_work))
|
|
cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
|
|
~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
|
|
drm_scdc_set_scrambling(vc4_hdmi->ddc, false);
|
|
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
|
|
@@ -612,15 +653,23 @@ static void vc4_hdmi_encoder_post_crtc_d
|
|
struct drm_atomic_state *state)
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
|
|
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
|
|
|
|
HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
mdelay(1);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_VID_CTL,
|
|
HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
vc4_hdmi_disable_scrambling(encoder);
|
|
}
|
|
|
|
@@ -628,10 +677,13 @@ static void vc4_hdmi_encoder_post_crtc_p
|
|
struct drm_atomic_state *state)
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
|
+ unsigned long flags;
|
|
int ret;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_VID_CTL,
|
|
HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
|
|
if (vc4_hdmi->variant->phy_disable)
|
|
vc4_hdmi->variant->phy_disable(vc4_hdmi);
|
|
@@ -650,8 +702,11 @@ static void vc4_hdmi_encoder_disable(str
|
|
|
|
static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
|
{
|
|
+ unsigned long flags;
|
|
u32 csc_ctl;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
|
|
VC4_HD_CSC_CTL_ORDER);
|
|
|
|
@@ -681,14 +736,19 @@ static void vc4_hdmi_csc_setup(struct vc
|
|
|
|
/* The RGB order applies even when CSC is disabled. */
|
|
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
|
{
|
|
+ unsigned long flags;
|
|
u32 csc_ctl;
|
|
|
|
csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
if (enable) {
|
|
/* CEA VICs other than #1 requre limited range RGB
|
|
* output unless overridden by an AVI infoframe.
|
|
@@ -720,6 +780,8 @@ static void vc5_hdmi_csc_setup(struct vc
|
|
}
|
|
|
|
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
|
@@ -743,6 +805,9 @@ static void vc4_hdmi_set_timings(struct
|
|
VC4_SET_FIELD(mode->crtc_vtotal -
|
|
mode->crtc_vsync_end,
|
|
VC4_HDMI_VERTB_VBP));
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
|
|
HDMI_WRITE(HDMI_HORZA,
|
|
(vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
|
|
@@ -766,6 +831,8 @@ static void vc4_hdmi_set_timings(struct
|
|
|
|
HDMI_WRITE(HDMI_VERTB0, vertb_even);
|
|
HDMI_WRITE(HDMI_VERTB1, vertb);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
|
@@ -790,10 +857,13 @@ static void vc5_hdmi_set_timings(struct
|
|
VC4_SET_FIELD(mode->crtc_vtotal -
|
|
mode->crtc_vsync_end,
|
|
VC4_HDMI_VERTB_VBP));
|
|
+ unsigned long flags;
|
|
unsigned char gcp;
|
|
bool gcp_en;
|
|
u32 reg;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
|
|
HDMI_WRITE(HDMI_HORZA,
|
|
(vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) |
|
|
@@ -857,13 +927,18 @@ static void vc5_hdmi_set_timings(struct
|
|
HDMI_WRITE(HDMI_MISC_CONTROL, reg);
|
|
|
|
HDMI_WRITE(HDMI_CLOCK_STOP, 0);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
u32 drift;
|
|
int ret;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
drift = HDMI_READ(HDMI_FIFO_CTL);
|
|
drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
|
|
|
|
@@ -871,12 +946,20 @@ static void vc4_hdmi_recenter_fifo(struc
|
|
drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
|
|
HDMI_WRITE(HDMI_FIFO_CTL,
|
|
drift | VC4_HDMI_FIFO_CTL_RECENTER);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
usleep_range(1000, 1100);
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
HDMI_WRITE(HDMI_FIFO_CTL,
|
|
drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
|
|
HDMI_WRITE(HDMI_FIFO_CTL,
|
|
drift | VC4_HDMI_FIFO_CTL_RECENTER);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) &
|
|
VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1);
|
|
WARN_ONCE(ret, "Timeout waiting for "
|
|
@@ -910,6 +993,7 @@ static void vc4_hdmi_encoder_pre_crtc_co
|
|
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
|
unsigned long pixel_rate = vc4_conn_state->pixel_rate;
|
|
unsigned long bvb_rate, hsm_rate;
|
|
+ unsigned long flags;
|
|
int ret;
|
|
|
|
/*
|
|
@@ -978,11 +1062,15 @@ static void vc4_hdmi_encoder_pre_crtc_co
|
|
if (vc4_hdmi->variant->phy_init)
|
|
vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
|
|
HDMI_READ(HDMI_SCHEDULER_CONTROL) |
|
|
VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT |
|
|
VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
if (vc4_hdmi->variant->set_timings)
|
|
vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
|
|
|
|
@@ -1002,6 +1090,7 @@ static void vc4_hdmi_encoder_pre_crtc_en
|
|
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
|
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
|
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
|
+ unsigned long flags;
|
|
|
|
if (vc4_encoder->hdmi_monitor &&
|
|
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
|
|
@@ -1016,7 +1105,9 @@ static void vc4_hdmi_encoder_pre_crtc_en
|
|
vc4_encoder->limited_rgb_range = false;
|
|
}
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
|
@@ -1027,8 +1118,11 @@ static void vc4_hdmi_encoder_post_crtc_e
|
|
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
|
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
|
|
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
|
|
+ unsigned long flags;
|
|
int ret;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
HDMI_WRITE(HDMI_VID_CTL,
|
|
VC4_HD_VID_CTL_ENABLE |
|
|
VC4_HD_VID_CTL_CLRRGB |
|
|
@@ -1045,6 +1139,8 @@ static void vc4_hdmi_encoder_post_crtc_e
|
|
HDMI_READ(HDMI_SCHEDULER_CONTROL) |
|
|
VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
|
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
|
|
WARN_ONCE(ret, "Timeout waiting for "
|
|
@@ -1057,6 +1153,8 @@ static void vc4_hdmi_encoder_post_crtc_e
|
|
HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
|
~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
|
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
|
|
WARN_ONCE(ret, "Timeout waiting for "
|
|
@@ -1064,6 +1162,8 @@ static void vc4_hdmi_encoder_post_crtc_e
|
|
}
|
|
|
|
if (vc4_encoder->hdmi_monitor) {
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
|
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE));
|
|
HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
|
|
@@ -1073,6 +1173,8 @@ static void vc4_hdmi_encoder_post_crtc_e
|
|
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
|
VC4_HDMI_RAM_PACKET_ENABLE);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
vc4_hdmi_set_infoframes(encoder);
|
|
}
|
|
|
|
@@ -1196,6 +1298,7 @@ static void vc4_hdmi_audio_set_mai_clock
|
|
unsigned int samplerate)
|
|
{
|
|
u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock);
|
|
+ unsigned long flags;
|
|
unsigned long n, m;
|
|
|
|
rational_best_approximation(hsm_clock, samplerate,
|
|
@@ -1205,9 +1308,11 @@ static void vc4_hdmi_audio_set_mai_clock
|
|
VC4_HD_MAI_SMP_M_SHIFT) + 1,
|
|
&n, &m);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_MAI_SMP,
|
|
VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) |
|
|
VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate)
|
|
@@ -1218,6 +1323,8 @@ static void vc4_hdmi_set_n_cts(struct vc
|
|
u32 n, cts;
|
|
u64 tmp;
|
|
|
|
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
|
+
|
|
n = 128 * samplerate / 1000;
|
|
tmp = (u64)(mode->clock * 1000) * n;
|
|
do_div(tmp, 128 * samplerate);
|
|
@@ -1247,6 +1354,7 @@ static int vc4_hdmi_audio_startup(struct
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
|
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
|
+ unsigned long flags;
|
|
|
|
/*
|
|
* If the HDMI encoder hasn't probed, or the encoder is
|
|
@@ -1258,12 +1366,14 @@ static int vc4_hdmi_audio_startup(struct
|
|
|
|
vc4_hdmi->audio.streaming = true;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_MAI_CTL,
|
|
VC4_HD_MAI_CTL_RESET |
|
|
VC4_HD_MAI_CTL_FLUSH |
|
|
VC4_HD_MAI_CTL_DLATE |
|
|
VC4_HD_MAI_CTL_ERRORE |
|
|
VC4_HD_MAI_CTL_ERRORF);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
|
|
if (vc4_hdmi->variant->phy_rng_enable)
|
|
vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
|
|
@@ -1275,6 +1385,7 @@ static void vc4_hdmi_audio_reset(struct
|
|
{
|
|
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
|
struct device *dev = &vc4_hdmi->pdev->dev;
|
|
+ unsigned long flags;
|
|
int ret;
|
|
|
|
vc4_hdmi->audio.streaming = false;
|
|
@@ -1282,20 +1393,29 @@ static void vc4_hdmi_audio_reset(struct
|
|
if (ret)
|
|
dev_err(dev, "Failed to stop audio infoframe: %d\n", ret);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET);
|
|
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF);
|
|
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
|
|
HDMI_WRITE(HDMI_MAI_CTL,
|
|
VC4_HD_MAI_CTL_DLATE |
|
|
VC4_HD_MAI_CTL_ERRORE |
|
|
VC4_HD_MAI_CTL_ERRORF);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
if (vc4_hdmi->variant->phy_rng_disable)
|
|
vc4_hdmi->variant->phy_rng_disable(vc4_hdmi);
|
|
|
|
@@ -1350,6 +1470,7 @@ static int vc4_hdmi_audio_prepare(struct
|
|
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
|
unsigned int sample_rate = params->sample_rate;
|
|
unsigned int channels = params->channels;
|
|
+ unsigned long flags;
|
|
u32 audio_packet_config, channel_mask;
|
|
u32 channel_map;
|
|
u32 mai_audio_format;
|
|
@@ -1358,14 +1479,15 @@ static int vc4_hdmi_audio_prepare(struct
|
|
dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
|
|
sample_rate, params->sample_width, channels);
|
|
|
|
+ vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_MAI_CTL,
|
|
VC4_SET_FIELD(channels, VC4_HD_MAI_CTL_CHNUM) |
|
|
VC4_HD_MAI_CTL_WHOLSMP |
|
|
VC4_HD_MAI_CTL_CHALIGN |
|
|
VC4_HD_MAI_CTL_ENABLE);
|
|
|
|
- vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
|
-
|
|
mai_sample_rate = sample_rate_to_mai_fmt(sample_rate);
|
|
if (params->iec.status[0] & IEC958_AES0_NONAUDIO &&
|
|
params->channels == 8)
|
|
@@ -1403,8 +1525,11 @@ static int vc4_hdmi_audio_prepare(struct
|
|
channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask);
|
|
HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map);
|
|
HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
|
|
+
|
|
vc4_hdmi_set_n_cts(vc4_hdmi, sample_rate);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea));
|
|
vc4_hdmi_set_audio_infoframe(encoder);
|
|
|
|
@@ -1678,6 +1803,8 @@ static void vc4_cec_read_msg(struct vc4_
|
|
struct cec_msg *msg = &vc4_hdmi->cec_rx_msg;
|
|
unsigned int i;
|
|
|
|
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
|
+
|
|
msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >>
|
|
VC4_HDMI_CEC_REC_WRD_CNT_SHIFT);
|
|
|
|
@@ -1696,11 +1823,12 @@ static void vc4_cec_read_msg(struct vc4_
|
|
}
|
|
}
|
|
|
|
-static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
|
+static irqreturn_t vc4_cec_irq_handler_tx_bare_locked(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
- struct vc4_hdmi *vc4_hdmi = priv;
|
|
u32 cntrl1;
|
|
|
|
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
|
+
|
|
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
|
vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
|
|
cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
|
|
@@ -1709,11 +1837,24 @@ static irqreturn_t vc4_cec_irq_handler_t
|
|
return IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
-static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
|
+static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = priv;
|
|
+ irqreturn_t ret;
|
|
+
|
|
+ spin_lock(&vc4_hdmi->hw_lock);
|
|
+ ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi);
|
|
+ spin_unlock(&vc4_hdmi->hw_lock);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static irqreturn_t vc4_cec_irq_handler_rx_bare_locked(struct vc4_hdmi *vc4_hdmi)
|
|
+{
|
|
u32 cntrl1;
|
|
|
|
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
|
+
|
|
vc4_hdmi->cec_rx_msg.len = 0;
|
|
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
|
vc4_cec_read_msg(vc4_hdmi, cntrl1);
|
|
@@ -1726,6 +1867,18 @@ static irqreturn_t vc4_cec_irq_handler_r
|
|
return IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
+static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
|
+{
|
|
+ struct vc4_hdmi *vc4_hdmi = priv;
|
|
+ irqreturn_t ret;
|
|
+
|
|
+ spin_lock(&vc4_hdmi->hw_lock);
|
|
+ ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi);
|
|
+ spin_unlock(&vc4_hdmi->hw_lock);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = priv;
|
|
@@ -1736,14 +1889,17 @@ static irqreturn_t vc4_cec_irq_handler(i
|
|
if (!(stat & VC4_HDMI_CPU_CEC))
|
|
return IRQ_NONE;
|
|
|
|
+ spin_lock(&vc4_hdmi->hw_lock);
|
|
cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
|
|
vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
|
|
if (vc4_hdmi->cec_irq_was_rx)
|
|
- ret = vc4_cec_irq_handler_rx_bare(irq, priv);
|
|
+ ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi);
|
|
else
|
|
- ret = vc4_cec_irq_handler_tx_bare(irq, priv);
|
|
+ ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi);
|
|
|
|
HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
|
|
+ spin_unlock(&vc4_hdmi->hw_lock);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
@@ -1752,6 +1908,7 @@ static int vc4_hdmi_cec_enable(struct ce
|
|
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
|
/* clock period in microseconds */
|
|
const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
|
|
+ unsigned long flags;
|
|
u32 val;
|
|
int ret;
|
|
|
|
@@ -1759,6 +1916,8 @@ static int vc4_hdmi_cec_enable(struct ce
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
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 |
|
|
@@ -1789,12 +1948,17 @@ static int vc4_hdmi_cec_enable(struct ce
|
|
if (!vc4_hdmi->variant->external_irq_controller)
|
|
HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
|
|
if (!vc4_hdmi->variant->external_irq_controller)
|
|
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
|
@@ -1802,6 +1966,8 @@ static int vc4_hdmi_cec_disable(struct c
|
|
HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) |
|
|
VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
|
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
|
|
|
return 0;
|
|
@@ -1818,10 +1984,14 @@ static int vc4_hdmi_cec_adap_enable(stru
|
|
static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
|
+ unsigned long flags;
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_CEC_CNTRL_1,
|
|
(HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
|
|
(log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1830,6 +2000,7 @@ static int vc4_hdmi_cec_adap_transmit(st
|
|
{
|
|
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
|
struct drm_device *dev = vc4_hdmi->connector.dev;
|
|
+ unsigned long flags;
|
|
u32 val;
|
|
unsigned int i;
|
|
|
|
@@ -1838,6 +2009,8 @@ static int vc4_hdmi_cec_adap_transmit(st
|
|
return -ENOMEM;
|
|
}
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
for (i = 0; i < msg->len; i += 4)
|
|
HDMI_WRITE(HDMI_CEC_TX_DATA_1 + (i >> 2),
|
|
(msg->msg[i]) |
|
|
@@ -1853,6 +2026,9 @@ static int vc4_hdmi_cec_adap_transmit(st
|
|
val |= VC4_HDMI_CEC_START_XMIT_BEGIN;
|
|
|
|
HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1867,6 +2043,7 @@ static int vc4_hdmi_cec_init(struct vc4_
|
|
struct cec_connector_info conn_info;
|
|
struct platform_device *pdev = vc4_hdmi->pdev;
|
|
struct device *dev = &pdev->dev;
|
|
+ unsigned long flags;
|
|
u32 value;
|
|
int ret;
|
|
|
|
@@ -1887,10 +2064,12 @@ static int vc4_hdmi_cec_init(struct vc4_
|
|
cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
|
|
cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
value = HDMI_READ(HDMI_CEC_CNTRL_1);
|
|
/* Set the logical address to Unregistered */
|
|
value |= VC4_HDMI_CEC_ADDR_MASK;
|
|
HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
|
|
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
|
|
|
|
@@ -1909,7 +2088,9 @@ static int vc4_hdmi_cec_init(struct vc4_
|
|
if (ret)
|
|
goto err_remove_cec_rx_handler;
|
|
} else {
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
|
|
ret = request_threaded_irq(platform_get_irq(pdev, 0),
|
|
vc4_cec_irq_handler,
|
|
@@ -2179,6 +2360,7 @@ static int vc4_hdmi_bind(struct device *
|
|
vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
|
|
if (!vc4_hdmi)
|
|
return -ENOMEM;
|
|
+ spin_lock_init(&vc4_hdmi->hw_lock);
|
|
INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
|
|
|
|
dev_set_drvdata(dev, vc4_hdmi);
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
|
@@ -179,6 +179,11 @@ struct vc4_hdmi {
|
|
|
|
struct debugfs_regset32 hdmi_regset;
|
|
struct debugfs_regset32 hd_regset;
|
|
+
|
|
+ /**
|
|
+ * @hw_lock: Spinlock protecting device register access.
|
|
+ */
|
|
+ spinlock_t hw_lock;
|
|
};
|
|
|
|
static inline struct vc4_hdmi *
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
|
|
@@ -130,31 +130,49 @@
|
|
void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
|
|
struct vc4_hdmi_connector_state *conn_state)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
/* PHY should be in reset, like
|
|
* vc4_hdmi_encoder_disable() does.
|
|
*/
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
|
|
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_TX_PHY_CTL_0,
|
|
HDMI_READ(HDMI_TX_PHY_CTL_0) &
|
|
~VC4_HDMI_TX_PHY_RNG_PWRDN);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_TX_PHY_CTL_0,
|
|
HDMI_READ(HDMI_TX_PHY_CTL_0) |
|
|
VC4_HDMI_TX_PHY_RNG_PWRDN);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
static unsigned long long
|
|
@@ -336,6 +354,8 @@ phy_get_channel_settings(enum vc4_hdmi_p
|
|
|
|
static void vc5_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
|
+
|
|
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x0f);
|
|
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10));
|
|
}
|
|
@@ -348,10 +368,13 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *
|
|
unsigned long long pixel_freq = conn_state->pixel_rate;
|
|
unsigned long long vco_freq;
|
|
unsigned char word_sel;
|
|
+ unsigned long flags;
|
|
u8 vco_sel, vco_div;
|
|
|
|
vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div);
|
|
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
+
|
|
vc5_hdmi_reset_phy(vc4_hdmi);
|
|
|
|
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
|
@@ -501,23 +524,37 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *
|
|
HDMI_READ(HDMI_TX_PHY_RESET_CTL) |
|
|
VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB |
|
|
VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB);
|
|
+
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
vc5_hdmi_reset_phy(vc4_hdmi);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
|
HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) &
|
|
~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
|
|
void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
|
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
|
HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) |
|
|
VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
|
|
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
}
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
|
@@ -445,6 +445,8 @@ static inline void vc4_hdmi_write(struct
|
|
const struct vc4_hdmi_variant *variant = hdmi->variant;
|
|
void __iomem *base;
|
|
|
|
+ lockdep_assert_held(&hdmi->hw_lock);
|
|
+
|
|
WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
|
|
|
|
if (reg >= variant->num_registers) {
|