1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Raspberry Pi driver for firmware controlled clocks 4 * 5 * Even though clk-bcm2835 provides an interface to the hardware registers for 6 * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it. 7 * We're not allowed to change it directly as we might race with the 8 * over-temperature and under-voltage protections provided by the firmware. 9 * 10 * Copyright (C) 2019 Nicolas Saenz Julienne <nsaenzjulienne@suse.de> 11 */ 12 13#include <linux/clkdev.h> 14#include <linux/clk-provider.h> 15#include <linux/io.h> 16#include <linux/module.h> 17#include <linux/platform_device.h> 18 19#include <soc/bcm2835/raspberrypi-firmware.h> 20 21enum rpi_firmware_clk_id { 22 RPI_FIRMWARE_EMMC_CLK_ID = 1, 23 RPI_FIRMWARE_UART_CLK_ID, 24 RPI_FIRMWARE_ARM_CLK_ID, 25 RPI_FIRMWARE_CORE_CLK_ID, 26 RPI_FIRMWARE_V3D_CLK_ID, 27 RPI_FIRMWARE_H264_CLK_ID, 28 RPI_FIRMWARE_ISP_CLK_ID, 29 RPI_FIRMWARE_SDRAM_CLK_ID, 30 RPI_FIRMWARE_PIXEL_CLK_ID, 31 RPI_FIRMWARE_PWM_CLK_ID, 32 RPI_FIRMWARE_HEVC_CLK_ID, 33 RPI_FIRMWARE_EMMC2_CLK_ID, 34 RPI_FIRMWARE_M2MC_CLK_ID, 35 RPI_FIRMWARE_PIXEL_BVB_CLK_ID, 36 RPI_FIRMWARE_NUM_CLK_ID, 37}; 38 39static char *rpi_firmware_clk_names[] = { 40 [RPI_FIRMWARE_EMMC_CLK_ID] = "emmc", 41 [RPI_FIRMWARE_UART_CLK_ID] = "uart", 42 [RPI_FIRMWARE_ARM_CLK_ID] = "arm", 43 [RPI_FIRMWARE_CORE_CLK_ID] = "core", 44 [RPI_FIRMWARE_V3D_CLK_ID] = "v3d", 45 [RPI_FIRMWARE_H264_CLK_ID] = "h264", 46 [RPI_FIRMWARE_ISP_CLK_ID] = "isp", 47 [RPI_FIRMWARE_SDRAM_CLK_ID] = "sdram", 48 [RPI_FIRMWARE_PIXEL_CLK_ID] = "pixel", 49 [RPI_FIRMWARE_PWM_CLK_ID] = "pwm", 50 [RPI_FIRMWARE_HEVC_CLK_ID] = "hevc", 51 [RPI_FIRMWARE_EMMC2_CLK_ID] = "emmc2", 52 [RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc", 53 [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb", 54}; 55 56#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) 57#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1) 58 59struct raspberrypi_clk { 60 struct device *dev; 61 struct rpi_firmware *firmware; 62 struct platform_device *cpufreq; 63}; 64 65struct raspberrypi_clk_data { 66 struct clk_hw hw; 67 68 unsigned int id; 69 70 struct raspberrypi_clk *rpi; 71}; 72 73/* 74 * Structure of the message passed to Raspberry Pi's firmware in order to 75 * change clock rates. The 'disable_turbo' option is only available to the ARM 76 * clock (pllb) which we enable by default as turbo mode will alter multiple 77 * clocks at once. 78 * 79 * Even though we're able to access the clock registers directly we're bound to 80 * use the firmware interface as the firmware ultimately takes care of 81 * mitigating overheating/undervoltage situations and we would be changing 82 * frequencies behind his back. 83 * 84 * For more information on the firmware interface check: 85 * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface 86 */ 87struct raspberrypi_firmware_prop { 88 __le32 id; 89 __le32 val; 90 __le32 disable_turbo; 91} __packed; 92 93static int raspberrypi_clock_property(struct rpi_firmware *firmware, 94 const struct raspberrypi_clk_data *data, 95 u32 tag, u32 *val) 96{ 97 struct raspberrypi_firmware_prop msg = { 98 .id = cpu_to_le32(data->id), 99 .val = cpu_to_le32(*val), 100 .disable_turbo = cpu_to_le32(1), 101 }; 102 int ret; 103 104 ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg)); 105 if (ret) 106 return ret; 107 108 *val = le32_to_cpu(msg.val); 109 110 return 0; 111} 112 113static int raspberrypi_fw_is_prepared(struct clk_hw *hw) 114{ 115 struct raspberrypi_clk_data *data = 116 container_of(hw, struct raspberrypi_clk_data, hw); 117 struct raspberrypi_clk *rpi = data->rpi; 118 u32 val = 0; 119 int ret; 120 121 ret = raspberrypi_clock_property(rpi->firmware, data, 122 RPI_FIRMWARE_GET_CLOCK_STATE, &val); 123 if (ret) 124 return 0; 125 126 return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT); 127} 128 129 130static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, 131 unsigned long parent_rate) 132{ 133 struct raspberrypi_clk_data *data = 134 container_of(hw, struct raspberrypi_clk_data, hw); 135 struct raspberrypi_clk *rpi = data->rpi; 136 u32 val = 0; 137 int ret; 138 139 ret = raspberrypi_clock_property(rpi->firmware, data, 140 RPI_FIRMWARE_GET_CLOCK_RATE, &val); 141 if (ret) 142 return 0; 143 144 return val; 145} 146 147static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, 148 unsigned long parent_rate) 149{ 150 struct raspberrypi_clk_data *data = 151 container_of(hw, struct raspberrypi_clk_data, hw); 152 struct raspberrypi_clk *rpi = data->rpi; 153 u32 _rate = rate; 154 int ret; 155 156 ret = raspberrypi_clock_property(rpi->firmware, data, 157 RPI_FIRMWARE_SET_CLOCK_RATE, &_rate); 158 if (ret) 159 dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d\n", 160 clk_hw_get_name(hw), ret); 161 162 return ret; 163} 164 165static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw, 166 struct clk_rate_request *req) 167{ 168 /* 169 * The firmware will do the rounding but that isn't part of 170 * the interface with the firmware, so we just do our best 171 * here. 172 */ 173 req->rate = clamp(req->rate, req->min_rate, req->max_rate); 174 return 0; 175} 176 177static const struct clk_ops raspberrypi_firmware_clk_ops = { 178 .is_prepared = raspberrypi_fw_is_prepared, 179 .recalc_rate = raspberrypi_fw_get_rate, 180 .determine_rate = raspberrypi_fw_dumb_determine_rate, 181 .set_rate = raspberrypi_fw_set_rate, 182}; 183 184static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, 185 unsigned int parent, 186 unsigned int id) 187{ 188 struct raspberrypi_clk_data *data; 189 struct clk_init_data init = {}; 190 u32 min_rate, max_rate; 191 int ret; 192 193 data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL); 194 if (!data) 195 return ERR_PTR(-ENOMEM); 196 data->rpi = rpi; 197 data->id = id; 198 199 init.name = devm_kasprintf(rpi->dev, GFP_KERNEL, 200 "fw-clk-%s", 201 rpi_firmware_clk_names[id]); 202 init.ops = &raspberrypi_firmware_clk_ops; 203 init.flags = CLK_GET_RATE_NOCACHE; 204 205 data->hw.init = &init; 206 207 ret = raspberrypi_clock_property(rpi->firmware, data, 208 RPI_FIRMWARE_GET_MIN_CLOCK_RATE, 209 &min_rate); 210 if (ret) { 211 dev_err(rpi->dev, "Failed to get clock %d min freq: %d\n", 212 id, ret); 213 return ERR_PTR(ret); 214 } 215 216 ret = raspberrypi_clock_property(rpi->firmware, data, 217 RPI_FIRMWARE_GET_MAX_CLOCK_RATE, 218 &max_rate); 219 if (ret) { 220 dev_err(rpi->dev, "Failed to get clock %d max freq: %d\n", 221 id, ret); 222 return ERR_PTR(ret); 223 } 224 225 ret = devm_clk_hw_register(rpi->dev, &data->hw); 226 if (ret) 227 return ERR_PTR(ret); 228 229 clk_hw_set_rate_range(&data->hw, min_rate, max_rate); 230 231 if (id == RPI_FIRMWARE_ARM_CLK_ID) { 232 ret = devm_clk_hw_register_clkdev(rpi->dev, &data->hw, 233 NULL, "cpu0"); 234 if (ret) { 235 dev_err(rpi->dev, "Failed to initialize clkdev\n"); 236 return ERR_PTR(ret); 237 } 238 } 239 240 return &data->hw; 241} 242 243struct rpi_firmware_get_clocks_response { 244 u32 parent; 245 u32 id; 246}; 247 248static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, 249 struct clk_hw_onecell_data *data) 250{ 251 struct rpi_firmware_get_clocks_response *clks; 252 int ret; 253 254 /* 255 * The firmware doesn't guarantee that the last element of 256 * RPI_FIRMWARE_GET_CLOCKS is zeroed. So allocate an additional 257 * zero element as sentinel. 258 */ 259 clks = devm_kcalloc(rpi->dev, 260 RPI_FIRMWARE_NUM_CLK_ID + 1, sizeof(*clks), 261 GFP_KERNEL); 262 if (!clks) 263 return -ENOMEM; 264 265 ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS, 266 clks, 267 sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID); 268 if (ret) 269 return ret; 270 271 while (clks->id) { 272 struct clk_hw *hw; 273 274 switch (clks->id) { 275 case RPI_FIRMWARE_ARM_CLK_ID: 276 case RPI_FIRMWARE_CORE_CLK_ID: 277 case RPI_FIRMWARE_M2MC_CLK_ID: 278 case RPI_FIRMWARE_V3D_CLK_ID: 279 case RPI_FIRMWARE_PIXEL_BVB_CLK_ID: 280 hw = raspberrypi_clk_register(rpi, clks->parent, 281 clks->id); 282 if (IS_ERR(hw)) 283 return PTR_ERR(hw); 284 285 data->hws[clks->id] = hw; 286 data->num = clks->id + 1; 287 fallthrough; 288 289 default: 290 clks++; 291 break; 292 } 293 } 294 295 return 0; 296} 297 298static int raspberrypi_clk_probe(struct platform_device *pdev) 299{ 300 struct clk_hw_onecell_data *clk_data; 301 struct device_node *firmware_node; 302 struct device *dev = &pdev->dev; 303 struct rpi_firmware *firmware; 304 struct raspberrypi_clk *rpi; 305 int ret; 306 307 /* 308 * We can be probed either through the an old-fashioned 309 * platform device registration or through a DT node that is a 310 * child of the firmware node. Handle both cases. 311 */ 312 if (dev->of_node) 313 firmware_node = of_get_parent(dev->of_node); 314 else 315 firmware_node = of_find_compatible_node(NULL, NULL, 316 "raspberrypi,bcm2835-firmware"); 317 if (!firmware_node) { 318 dev_err(dev, "Missing firmware node\n"); 319 return -ENOENT; 320 } 321 322 firmware = rpi_firmware_get(firmware_node); 323 of_node_put(firmware_node); 324 if (!firmware) 325 return -EPROBE_DEFER; 326 327 rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL); 328 if (!rpi) 329 return -ENOMEM; 330 331 rpi->dev = dev; 332 rpi->firmware = firmware; 333 platform_set_drvdata(pdev, rpi); 334 335 clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, 336 RPI_FIRMWARE_NUM_CLK_ID), 337 GFP_KERNEL); 338 if (!clk_data) 339 return -ENOMEM; 340 341 ret = raspberrypi_discover_clocks(rpi, clk_data); 342 if (ret) 343 return ret; 344 345 ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 346 clk_data); 347 if (ret) 348 return ret; 349 350 rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", 351 -1, NULL, 0); 352 353 return 0; 354} 355 356static int raspberrypi_clk_remove(struct platform_device *pdev) 357{ 358 struct raspberrypi_clk *rpi = platform_get_drvdata(pdev); 359 360 platform_device_unregister(rpi->cpufreq); 361 362 return 0; 363} 364 365static const struct of_device_id raspberrypi_clk_match[] = { 366 { .compatible = "raspberrypi,firmware-clocks" }, 367 { }, 368}; 369MODULE_DEVICE_TABLE(of, raspberrypi_clk_match); 370 371static struct platform_driver raspberrypi_clk_driver = { 372 .driver = { 373 .name = "raspberrypi-clk", 374 .of_match_table = raspberrypi_clk_match, 375 }, 376 .probe = raspberrypi_clk_probe, 377 .remove = raspberrypi_clk_remove, 378}; 379module_platform_driver(raspberrypi_clk_driver); 380 381MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); 382MODULE_DESCRIPTION("Raspberry Pi firmware clock driver"); 383MODULE_LICENSE("GPL"); 384MODULE_ALIAS("platform:raspberrypi-clk"); 385