From 12c90f3f27bb3ad0dd3fad1550fec87091aa3329 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 25 Feb 2022 15:35:30 +0100 Subject: clk: bcm: rpi: Add variant structure We only export a bunch of firmware clocks, and some of them require special treatment. This has been do so far using some tests on the clock id in various places, but this is fairly hard to extend and doesn't scale very well. Since we'll need some more cases in the next patches, let's switch to a variant structure that defines the behaviour we need to have for a given clock. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20220225143534.405820-9-maxime@cerno.tech Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-raspberrypi.c | 64 ++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 17 deletions(-) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index dd3b71eafabf..f7185d421085 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -56,6 +56,8 @@ static char *rpi_firmware_clk_names[] = { #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) #define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1) +struct raspberrypi_clk_variant; + struct raspberrypi_clk { struct device *dev; struct rpi_firmware *firmware; @@ -66,10 +68,36 @@ struct raspberrypi_clk_data { struct clk_hw hw; unsigned int id; + struct raspberrypi_clk_variant *variant; struct raspberrypi_clk *rpi; }; +struct raspberrypi_clk_variant { + bool export; + char *clkdev; +}; + +static struct raspberrypi_clk_variant +raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { + [RPI_FIRMWARE_ARM_CLK_ID] = { + .export = true, + .clkdev = "cpu0", + }, + [RPI_FIRMWARE_CORE_CLK_ID] = { + .export = true, + }, + [RPI_FIRMWARE_M2MC_CLK_ID] = { + .export = true, + }, + [RPI_FIRMWARE_V3D_CLK_ID] = { + .export = true, + }, + [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = { + .export = true, + }, +}; + /* * Structure of the message passed to Raspberry Pi's firmware in order to * change clock rates. The 'disable_turbo' option is only available to the ARM @@ -183,7 +211,8 @@ static const struct clk_ops raspberrypi_firmware_clk_ops = { static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, unsigned int parent, - unsigned int id) + unsigned int id, + struct raspberrypi_clk_variant *variant) { struct raspberrypi_clk_data *data; struct clk_init_data init = {}; @@ -195,6 +224,7 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, return ERR_PTR(-ENOMEM); data->rpi = rpi; data->id = id; + data->variant = variant; init.name = devm_kasprintf(rpi->dev, GFP_KERNEL, "fw-clk-%s", @@ -228,9 +258,9 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, clk_hw_set_rate_range(&data->hw, min_rate, max_rate); - if (id == RPI_FIRMWARE_ARM_CLK_ID) { + if (variant->clkdev) { ret = devm_clk_hw_register_clkdev(rpi->dev, &data->hw, - NULL, "cpu0"); + NULL, variant->clkdev); if (ret) { dev_err(rpi->dev, "Failed to initialize clkdev\n"); return ERR_PTR(ret); @@ -264,27 +294,27 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, return ret; while (clks->id) { - struct clk_hw *hw; - - switch (clks->id) { - case RPI_FIRMWARE_ARM_CLK_ID: - case RPI_FIRMWARE_CORE_CLK_ID: - case RPI_FIRMWARE_M2MC_CLK_ID: - case RPI_FIRMWARE_V3D_CLK_ID: - case RPI_FIRMWARE_PIXEL_BVB_CLK_ID: + struct raspberrypi_clk_variant *variant; + + if (clks->id > RPI_FIRMWARE_NUM_CLK_ID) { + dev_err(rpi->dev, "Unknown clock id: %u", clks->id); + return -EINVAL; + } + + variant = &raspberrypi_clk_variants[clks->id]; + if (variant->export) { + struct clk_hw *hw; + hw = raspberrypi_clk_register(rpi, clks->parent, - clks->id); + clks->id, variant); if (IS_ERR(hw)) return PTR_ERR(hw); data->hws[clks->id] = hw; data->num = clks->id + 1; - fallthrough; - - default: - clks++; - break; } + + clks++; } return 0; -- cgit v1.2.3 From 542acfec4e313c001f9b82332f4fa2848ec7bf58 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 25 Feb 2022 15:35:31 +0100 Subject: clk: bcm: rpi: Set a default minimum rate 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 Link: https://lore.kernel.org/r/20220225143534.405820-10-maxime@cerno.tech Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-raspberrypi.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index f7185d421085..c879f2e9a4a7 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -76,6 +76,7 @@ struct raspberrypi_clk_data { struct raspberrypi_clk_variant { bool export; char *clkdev; + unsigned long min_rate; }; static struct raspberrypi_clk_variant @@ -89,6 +90,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, @@ -267,6 +280,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; } -- cgit v1.2.3 From e9d6cea2af1cf8d84287ff2287b6cd776f7475d2 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 25 Feb 2022 15:35:32 +0100 Subject: clk: bcm: rpi: Run some clocks at the minimum rate allowed The core clock and M2MC clocks are shared between some devices (Unicam controllers and the HVS, and the HDMI controllers, respectively) that will have various, varying, requirements depending on their current work load. Since those loads can require a fairly high clock rate in extreme conditions (up to ~600MHz), we can end up running those clocks at their maximum frequency even though we no longer require such a high rate. Fortunately, those devices don't require an exact rate but a minimum rate, and all the drivers are using clk_set_min_rate. Thus, we can just rely on the fact that the clk_request minimum (which is the aggregated minimum of all the clock users) is what we want at all times. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20220225143534.405820-11-maxime@cerno.tech Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-raspberrypi.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers/clk/bcm') diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index c879f2e9a4a7..9d09621549b9 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -77,6 +77,7 @@ struct raspberrypi_clk_variant { bool export; char *clkdev; unsigned long min_rate; + bool minimize; }; static struct raspberrypi_clk_variant @@ -87,6 +88,18 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { }, [RPI_FIRMWARE_CORE_CLK_ID] = { .export = true, + + /* + * The clock is shared between the HVS and the CSI + * controllers, on the BCM2711 and will change depending + * on the pixels composited on the HVS and the capture + * resolution on Unicam. + * + * Since the rate can get quite large, and we need to + * coordinate between both driver instances, let's + * always use the minimum the drivers will let us. + */ + .minimize = true, }, [RPI_FIRMWARE_M2MC_CLK_ID] = { .export = true, @@ -102,6 +115,16 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { * in this situation. */ .min_rate = 120000000, + + /* + * The clock is shared between the two HDMI controllers + * on the BCM2711 and will change depending on the + * resolution output on each. Since the rate can get + * quite large, and we need to coordinate between both + * driver instances, let's always use the minimum the + * drivers will let us. + */ + .minimize = true, }, [RPI_FIRMWARE_V3D_CLK_ID] = { .export = true, @@ -206,12 +229,26 @@ static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { + struct raspberrypi_clk_data *data = + container_of(hw, struct raspberrypi_clk_data, hw); + struct raspberrypi_clk_variant *variant = data->variant; + /* * The firmware will do the rounding but that isn't part of * the interface with the firmware, so we just do our best * here. */ + req->rate = clamp(req->rate, req->min_rate, req->max_rate); + + /* + * We want to aggressively reduce the clock rate here, so let's + * just ignore the requested rate and return the bare minimum + * rate we can get away with. + */ + if (variant->minimize && req->min_rate > 0) + req->rate = req->min_rate; + return 0; } -- cgit v1.2.3