| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From 9667f053b5015bfb486e16d3c88a79b961395876 Mon Sep 17 00:00:00 2001 |
| 2 | From: Phil Elwell <phil@raspberrypi.org> |
| 3 | Date: Mon, 6 Mar 2017 09:06:18 +0000 |
| 4 | Subject: [PATCH] clk-bcm2835: Read max core clock from firmware |
| 5 | |
| 6 | The VPU is responsible for managing the core clock, usually under |
| 7 | direction from the bcm2835-cpufreq driver but not via the clk-bcm2835 |
| 8 | driver. Since the core frequency can change without warning, it is |
| 9 | safer to report the maximum clock rate to users of the core clock - |
| 10 | I2C, SPI and the mini UART - to err on the safe side when calculating |
| 11 | clock divisors. |
| 12 | |
| 13 | If the DT node for the clock driver includes a reference to the |
| 14 | firmware node, use the firmware API to query the maximum core clock |
| 15 | instead of reading the divider registers. |
| 16 | |
| 17 | Prior to this patch, a "100KHz" I2C bus was sometimes clocked at about |
| 18 | 160KHz. In particular, switching to the 4.9 kernel was likely to break |
| 19 | SenseHAT usage on a Pi3. |
| 20 | |
| 21 | Signed-off-by: Phil Elwell <phil@raspberrypi.org> |
| 22 | --- |
| 23 | drivers/clk/bcm/clk-bcm2835.c | 39 ++++++++++++++++++++++++++++++++++- |
| 24 | 1 file changed, 38 insertions(+), 1 deletion(-) |
| 25 | |
| 26 | --- a/drivers/clk/bcm/clk-bcm2835.c |
| 27 | +++ b/drivers/clk/bcm/clk-bcm2835.c |
| 28 | @@ -35,6 +35,7 @@ |
| 29 | #include <linux/platform_device.h> |
| 30 | #include <linux/slab.h> |
| 31 | #include <dt-bindings/clock/bcm2835.h> |
| 32 | +#include <soc/bcm2835/raspberrypi-firmware.h> |
| 33 | |
| 34 | #define CM_PASSWORD 0x5a000000 |
| 35 | |
| 36 | @@ -295,6 +296,8 @@ |
| 37 | #define SOC_BCM2711 BIT(1) |
| 38 | #define SOC_ALL (SOC_BCM2835 | SOC_BCM2711) |
| 39 | |
| 40 | +#define VCMSG_ID_CORE_CLOCK 4 |
| 41 | + |
| 42 | /* |
| 43 | * Names of clocks used within the driver that need to be replaced |
| 44 | * with an external parent's name. This array is in the order that |
| 45 | @@ -313,6 +316,7 @@ static const char *const cprman_parent_n |
| 46 | struct bcm2835_cprman { |
| 47 | struct device *dev; |
| 48 | void __iomem *regs; |
| 49 | + struct rpi_firmware *fw; |
| 50 | spinlock_t regs_lock; /* spinlock for all clocks */ |
| 51 | unsigned int soc; |
| 52 | |
| 53 | @@ -1010,6 +1014,30 @@ static unsigned long bcm2835_clock_get_r |
| 54 | return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); |
| 55 | } |
| 56 | |
| 57 | +static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw, |
| 58 | + unsigned long parent_rate) |
| 59 | +{ |
| 60 | + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); |
| 61 | + struct bcm2835_cprman *cprman = clock->cprman; |
| 62 | + |
| 63 | + if (cprman->fw) { |
| 64 | + struct { |
| 65 | + u32 id; |
| 66 | + u32 val; |
| 67 | + } packet; |
| 68 | + |
| 69 | + packet.id = VCMSG_ID_CORE_CLOCK; |
| 70 | + packet.val = 0; |
| 71 | + |
| 72 | + if (!rpi_firmware_property(cprman->fw, |
| 73 | + RPI_FIRMWARE_GET_MAX_CLOCK_RATE, |
| 74 | + &packet, sizeof(packet))) |
| 75 | + return packet.val; |
| 76 | + } |
| 77 | + |
| 78 | + return bcm2835_clock_get_rate(hw, parent_rate); |
| 79 | +} |
| 80 | + |
| 81 | static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock) |
| 82 | { |
| 83 | struct bcm2835_cprman *cprman = clock->cprman; |
| 84 | @@ -1298,7 +1326,7 @@ static int bcm2835_vpu_clock_is_on(struc |
| 85 | */ |
| 86 | static const struct clk_ops bcm2835_vpu_clock_clk_ops = { |
| 87 | .is_prepared = bcm2835_vpu_clock_is_on, |
| 88 | - .recalc_rate = bcm2835_clock_get_rate, |
| 89 | + .recalc_rate = bcm2835_clock_get_rate_vpu, |
| 90 | .set_rate = bcm2835_clock_set_rate, |
| 91 | .determine_rate = bcm2835_clock_determine_rate, |
| 92 | .set_parent = bcm2835_clock_set_parent, |
| 93 | @@ -2236,6 +2264,7 @@ static int bcm2835_clk_probe(struct plat |
| 94 | const struct bcm2835_clk_desc *desc; |
| 95 | const size_t asize = ARRAY_SIZE(clk_desc_array); |
| 96 | const struct cprman_plat_data *pdata; |
| 97 | + struct device_node *fw_node; |
| 98 | size_t i; |
| 99 | u32 clk_id; |
| 100 | int ret; |
| 101 | @@ -2257,6 +2286,14 @@ static int bcm2835_clk_probe(struct plat |
| 102 | if (IS_ERR(cprman->regs)) |
| 103 | return PTR_ERR(cprman->regs); |
| 104 | |
| 105 | + fw_node = of_parse_phandle(dev->of_node, "firmware", 0); |
| 106 | + if (fw_node) { |
| 107 | + struct rpi_firmware *fw = rpi_firmware_get(NULL); |
| 108 | + if (!fw) |
| 109 | + return -EPROBE_DEFER; |
| 110 | + cprman->fw = fw; |
| 111 | + } |
| 112 | + |
| 113 | memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed)); |
| 114 | for (i = 0; |
| 115 | !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", |