123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907 |
- From d91a953904e1aeddf24a95af40fc1ae7ba2319fd Mon Sep 17 00:00:00 2001
- From: Maxime Ripard <[email protected]>
- 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/[email protected]
- Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.")
- Acked-by: Daniel Vetter <[email protected]>
- Signed-off-by: Maxime Ripard <[email protected]>
- ---
- 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) {
|