bcm27xx: update patches from RPi foundation
[openwrt/staging/luka.git] / target / linux / bcm27xx / patches-5.4 / 950-0533-clk-bcm-rpi-Discover-the-firmware-clocks.patch
diff --git a/target/linux/bcm27xx/patches-5.4/950-0533-clk-bcm-rpi-Discover-the-firmware-clocks.patch b/target/linux/bcm27xx/patches-5.4/950-0533-clk-bcm-rpi-Discover-the-firmware-clocks.patch
new file mode 100644 (file)
index 0000000..eaa4a81
--- /dev/null
@@ -0,0 +1,173 @@
+From 54276fe20c0735dd18d298891b71b664ea54962d Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime@cerno.tech>
+Date: Mon, 10 Feb 2020 14:06:09 +0100
+Subject: [PATCH] clk: bcm: rpi: Discover the firmware clocks
+
+The RaspberryPi4 firmware actually exposes more clocks than are currently
+handled by the driver and we will need to change some of them directly
+based on the pixel rate for the display related clocks, or the load for the
+GPU.
+
+This rate change can have a number of side-effects, including adjusting the
+various PLL voltages or the PLL parents. The firmware will also update
+those clocks by itself for example if the SoC runs too hot.
+
+In order to make Linux play as nice as possible with those constraints, it
+makes sense to rely on the firmware clocks as much as possible.
+
+Fortunately,t he firmware has an interface to discover the clocks it
+exposes.
+
+Let's use it to discover, register the clocks in the clocks framework and
+then expose them through the device tree for consumers to use them.
+
+Cc: Michael Turquette <mturquette@baylibre.com>
+Cc: Stephen Boyd <sboyd@kernel.org>
+Cc: linux-clk@vger.kernel.org
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+---
+ drivers/clk/bcm/clk-raspberrypi.c          | 104 ++++++++++++++++++---
+ include/soc/bcm2835/raspberrypi-firmware.h |   5 +
+ 2 files changed, 97 insertions(+), 12 deletions(-)
+
+--- a/drivers/clk/bcm/clk-raspberrypi.c
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -285,6 +285,95 @@ static struct clk_hw *raspberrypi_regist
+       return &raspberrypi_clk_pllb_arm.hw;
+ }
++static long raspberrypi_fw_dumb_round_rate(struct clk_hw *hw,
++                                         unsigned long rate,
++                                         unsigned long *parent_rate)
++{
++      /*
++       * The firmware will do the rounding but that isn't part of
++       * the interface with the firmware, so we just do our best
++       * here.
++       */
++      return rate;
++}
++
++static const struct clk_ops raspberrypi_firmware_clk_ops = {
++      .is_prepared    = raspberrypi_fw_is_prepared,
++      .recalc_rate    = raspberrypi_fw_get_rate,
++      .round_rate     = raspberrypi_fw_dumb_round_rate,
++      .set_rate       = raspberrypi_fw_set_rate,
++};
++
++static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
++                                             unsigned int parent,
++                                             unsigned int id)
++{
++      struct raspberrypi_clk_data *data;
++      struct clk_init_data init = {};
++      int ret;
++
++      if (id == RPI_FIRMWARE_ARM_CLK_ID) {
++              struct clk_hw *hw;
++
++              hw = raspberrypi_register_pllb(rpi);
++              if (IS_ERR(hw)) {
++                      dev_err(rpi->dev, "Failed to initialize pllb, %ld\n",
++                              PTR_ERR(hw));
++                      return hw;
++              }
++
++              return raspberrypi_register_pllb_arm(rpi);
++      }
++
++      data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL);
++      if (!data)
++              return ERR_PTR(-ENOMEM);
++      data->rpi = rpi;
++      data->id = id;
++
++      init.name = devm_kasprintf(rpi->dev, GFP_KERNEL, "fw-clk-%u", id);
++      init.ops = &raspberrypi_firmware_clk_ops;
++      init.flags = CLK_GET_RATE_NOCACHE;
++
++      data->hw.init = &init;
++
++      ret = devm_clk_hw_register(rpi->dev, &data->hw);
++      if (ret)
++              return ERR_PTR(ret);
++
++      return &data->hw;
++}
++
++static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
++                                     struct clk_hw_onecell_data *data)
++{
++      struct rpi_firmware_get_clocks_response *clks;
++      int ret;
++
++      clks = devm_kcalloc(rpi->dev, sizeof(*clks), NUM_FW_CLKS, GFP_KERNEL);
++      if (!clks)
++              return -ENOMEM;
++
++      ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS,
++                                  clks, sizeof(*clks) * NUM_FW_CLKS);
++      if (ret)
++              return ret;
++
++      while (clks->id) {
++              struct clk_hw *hw;
++
++              hw = raspberrypi_clk_register(rpi, clks->parent, clks->id);
++              if (IS_ERR(hw))
++                      return PTR_ERR(hw);
++
++              data->hws[clks->id] = hw;
++              data->num = clks->id + 1;
++              clks++;
++      }
++
++      return 0;
++}
++
+ static int raspberrypi_clk_probe(struct platform_device *pdev)
+ {
+       struct clk_hw_onecell_data *clk_data;
+@@ -292,7 +381,6 @@ static int raspberrypi_clk_probe(struct
+       struct device *dev = &pdev->dev;
+       struct rpi_firmware *firmware;
+       struct raspberrypi_clk *rpi;
+-      struct clk_hw *hw;
+       int ret;
+       firmware_node = of_parse_phandle(dev->of_node, "raspberrypi,firmware", 0);
+@@ -318,17 +406,9 @@ static int raspberrypi_clk_probe(struct
+       if (!clk_data)
+               return -ENOMEM;
+-      hw = raspberrypi_register_pllb(rpi);
+-      if (IS_ERR(hw)) {
+-              dev_err(dev, "Failed to initialize pllb, %ld\n", PTR_ERR(hw));
+-              return PTR_ERR(hw);
+-      }
+-
+-      hw = raspberrypi_register_pllb_arm(rpi);
+-      if (IS_ERR(hw))
+-              return PTR_ERR(hw);
+-      clk_data->hws[RPI_FIRMWARE_ARM_CLK_ID] = hw;
+-      clk_data->num = RPI_FIRMWARE_ARM_CLK_ID + 1;
++      ret = raspberrypi_discover_clocks(rpi, clk_data);
++      if (ret)
++              return ret;
+       ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+                                         clk_data);
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -160,6 +160,11 @@ enum rpi_firmware_property_tag {
+ #define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64
++struct rpi_firmware_get_clocks_response {
++      __le32 parent;
++      __le32 id;
++};
++
+ #if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
+ int rpi_firmware_property(struct rpi_firmware *fw,
+                         u32 tag, void *data, size_t len);