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 21 enum 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 39 static 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 59 struct raspberrypi_clk { 60 struct device *dev; 61 struct rpi_firmware *firmware; 62 struct platform_device *cpufreq; 63 }; 64 65 struct 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 */ 87 struct raspberrypi_firmware_prop { 88 __le32 id; 89 __le32 val; 90 __le32 disable_turbo; 91 } __packed; 92 93 static 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 113 static 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 130 static 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 ret; 143 144 return val; 145 } 146 147 static 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", 160 clk_hw_get_name(hw), ret); 161 162 return ret; 163 } 164 165 static 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 177 static 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 184 static 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", 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 243 struct rpi_firmware_get_clocks_response { 244 u32 parent; 245 u32 id; 246 }; 247 248 static 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 clks = devm_kcalloc(rpi->dev, 255 sizeof(*clks), RPI_FIRMWARE_NUM_CLK_ID, 256 GFP_KERNEL); 257 if (!clks) 258 return -ENOMEM; 259 260 ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS, 261 clks, 262 sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID); 263 if (ret) 264 return ret; 265 266 while (clks->id) { 267 struct clk_hw *hw; 268 269 switch (clks->id) { 270 case RPI_FIRMWARE_ARM_CLK_ID: 271 case RPI_FIRMWARE_CORE_CLK_ID: 272 case RPI_FIRMWARE_M2MC_CLK_ID: 273 case RPI_FIRMWARE_V3D_CLK_ID: 274 hw = raspberrypi_clk_register(rpi, clks->parent, 275 clks->id); 276 if (IS_ERR(hw)) 277 return PTR_ERR(hw); 278 279 data->hws[clks->id] = hw; 280 data->num = clks->id + 1; 281 fallthrough; 282 283 default: 284 clks++; 285 break; 286 } 287 } 288 289 return 0; 290 } 291 292 static int raspberrypi_clk_probe(struct platform_device *pdev) 293 { 294 struct clk_hw_onecell_data *clk_data; 295 struct device_node *firmware_node; 296 struct device *dev = &pdev->dev; 297 struct rpi_firmware *firmware; 298 struct raspberrypi_clk *rpi; 299 int ret; 300 301 /* 302 * We can be probed either through the an old-fashioned 303 * platform device registration or through a DT node that is a 304 * child of the firmware node. Handle both cases. 305 */ 306 if (dev->of_node) 307 firmware_node = of_get_parent(dev->of_node); 308 else 309 firmware_node = of_find_compatible_node(NULL, NULL, 310 "raspberrypi,bcm2835-firmware"); 311 if (!firmware_node) { 312 dev_err(dev, "Missing firmware node\n"); 313 return -ENOENT; 314 } 315 316 firmware = rpi_firmware_get(firmware_node); 317 of_node_put(firmware_node); 318 if (!firmware) 319 return -EPROBE_DEFER; 320 321 rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL); 322 if (!rpi) 323 return -ENOMEM; 324 325 rpi->dev = dev; 326 rpi->firmware = firmware; 327 platform_set_drvdata(pdev, rpi); 328 329 clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, 330 RPI_FIRMWARE_NUM_CLK_ID), 331 GFP_KERNEL); 332 if (!clk_data) 333 return -ENOMEM; 334 335 ret = raspberrypi_discover_clocks(rpi, clk_data); 336 if (ret) 337 return ret; 338 339 ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 340 clk_data); 341 if (ret) 342 return ret; 343 344 rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", 345 -1, NULL, 0); 346 347 return 0; 348 } 349 350 static int raspberrypi_clk_remove(struct platform_device *pdev) 351 { 352 struct raspberrypi_clk *rpi = platform_get_drvdata(pdev); 353 354 platform_device_unregister(rpi->cpufreq); 355 356 return 0; 357 } 358 359 static const struct of_device_id raspberrypi_clk_match[] = { 360 { .compatible = "raspberrypi,firmware-clocks" }, 361 { }, 362 }; 363 MODULE_DEVICE_TABLE(of, raspberrypi_clk_match); 364 365 static struct platform_driver raspberrypi_clk_driver = { 366 .driver = { 367 .name = "raspberrypi-clk", 368 .of_match_table = raspberrypi_clk_match, 369 }, 370 .probe = raspberrypi_clk_probe, 371 .remove = raspberrypi_clk_remove, 372 }; 373 module_platform_driver(raspberrypi_clk_driver); 374 375 MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); 376 MODULE_DESCRIPTION("Raspberry Pi firmware clock driver"); 377 MODULE_LICENSE("GPL"); 378 MODULE_ALIAS("platform:raspberrypi-clk"); 379