clk: bcm: rpi: Set a default minimum rate
authorMaxime Ripard <maxime@cerno.tech>
Mon, 17 Jan 2022 16:31:06 +0000 (17:31 +0100)
committerPhil Elwell <8911409+pelwell@users.noreply.github.com>
Fri, 22 Apr 2022 09:17:27 +0000 (10:17 +0100)
The M2MC clock provides the state machine clock for both HDMI
controllers.

However, if no HDMI monitor is plugged in at boot, its clock rate will
be left at 0 by the firmware and will make any register access end up in
a CPU stall, even though the clock was enabled.

We had some code in the HDMI controller to deal with this before, but it
makes more sense to have it in the clock driver. Move it there.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
drivers/clk/bcm/clk-raspberrypi.c

index edc052c3303001b2621dc1b950128413480d9f6e..70bacccc1b5aae14f19ee5c612fead62ec9bac3c 100644 (file)
@@ -78,6 +78,7 @@ struct raspberrypi_clk_data {
 struct raspberrypi_clk_variant {
        bool            export;
        char            *clkdev;
+       unsigned long   min_rate;
 };
 
 static struct raspberrypi_clk_variant
@@ -91,6 +92,18 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = {
        },
        [RPI_FIRMWARE_M2MC_CLK_ID] = {
                .export = true,
+
+               /*
+                * If we boot without any cable connected to any of the
+                * HDMI connector, the firmware will skip the HSM
+                * initialization and leave it with a rate of 0,
+                * resulting in a bus lockup when we're accessing the
+                * registers even if it's enabled.
+                *
+                * Let's put a sensible default so that we don't end up
+                * in this situation.
+                */
+               .min_rate = 120000000,
        },
        [RPI_FIRMWARE_V3D_CLK_ID] = {
                .export = true,
@@ -278,6 +291,19 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
                }
        }
 
+       if (variant->min_rate) {
+               unsigned long rate;
+
+               clk_hw_set_rate_range(&data->hw, variant->min_rate, max_rate);
+
+               rate = raspberrypi_fw_get_rate(&data->hw, 0);
+               if (rate < variant->min_rate) {
+                       ret = raspberrypi_fw_set_rate(&data->hw, variant->min_rate, 0);
+                       if (ret)
+                               return ERR_PTR(ret);
+               }
+       }
+
        return &data->hw;
 }