14e85e535SNicolas Saenz Julienne // SPDX-License-Identifier: GPL-2.0+ 24e85e535SNicolas Saenz Julienne /* 34e85e535SNicolas Saenz Julienne * Raspberry Pi driver for firmware controlled clocks 44e85e535SNicolas Saenz Julienne * 54e85e535SNicolas Saenz Julienne * Even though clk-bcm2835 provides an interface to the hardware registers for 64e85e535SNicolas Saenz Julienne * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it. 74e85e535SNicolas Saenz Julienne * We're not allowed to change it directly as we might race with the 84e85e535SNicolas Saenz Julienne * over-temperature and under-voltage protections provided by the firmware. 94e85e535SNicolas Saenz Julienne * 104e85e535SNicolas Saenz Julienne * Copyright (C) 2019 Nicolas Saenz Julienne <nsaenzjulienne@suse.de> 114e85e535SNicolas Saenz Julienne */ 124e85e535SNicolas Saenz Julienne 134e85e535SNicolas Saenz Julienne #include <linux/clkdev.h> 144e85e535SNicolas Saenz Julienne #include <linux/clk-provider.h> 154e85e535SNicolas Saenz Julienne #include <linux/io.h> 164e85e535SNicolas Saenz Julienne #include <linux/module.h> 174e85e535SNicolas Saenz Julienne #include <linux/platform_device.h> 184e85e535SNicolas Saenz Julienne 194e85e535SNicolas Saenz Julienne #include <soc/bcm2835/raspberrypi-firmware.h> 204e85e535SNicolas Saenz Julienne 21be1559f6SMaxime Ripard enum rpi_firmware_clk_id { 22be1559f6SMaxime Ripard RPI_FIRMWARE_EMMC_CLK_ID = 1, 23be1559f6SMaxime Ripard RPI_FIRMWARE_UART_CLK_ID, 24be1559f6SMaxime Ripard RPI_FIRMWARE_ARM_CLK_ID, 25be1559f6SMaxime Ripard RPI_FIRMWARE_CORE_CLK_ID, 26be1559f6SMaxime Ripard RPI_FIRMWARE_V3D_CLK_ID, 27be1559f6SMaxime Ripard RPI_FIRMWARE_H264_CLK_ID, 28be1559f6SMaxime Ripard RPI_FIRMWARE_ISP_CLK_ID, 29be1559f6SMaxime Ripard RPI_FIRMWARE_SDRAM_CLK_ID, 30be1559f6SMaxime Ripard RPI_FIRMWARE_PIXEL_CLK_ID, 31be1559f6SMaxime Ripard RPI_FIRMWARE_PWM_CLK_ID, 32be1559f6SMaxime Ripard RPI_FIRMWARE_HEVC_CLK_ID, 33be1559f6SMaxime Ripard RPI_FIRMWARE_EMMC2_CLK_ID, 34be1559f6SMaxime Ripard RPI_FIRMWARE_M2MC_CLK_ID, 35be1559f6SMaxime Ripard RPI_FIRMWARE_PIXEL_BVB_CLK_ID, 36*1777cb60SDom Cobley RPI_FIRMWARE_VEC_CLK_ID, 37be1559f6SMaxime Ripard RPI_FIRMWARE_NUM_CLK_ID, 38be1559f6SMaxime Ripard }; 394e85e535SNicolas Saenz Julienne 407dad8a61SMaxime Ripard static char *rpi_firmware_clk_names[] = { 417dad8a61SMaxime Ripard [RPI_FIRMWARE_EMMC_CLK_ID] = "emmc", 427dad8a61SMaxime Ripard [RPI_FIRMWARE_UART_CLK_ID] = "uart", 437dad8a61SMaxime Ripard [RPI_FIRMWARE_ARM_CLK_ID] = "arm", 447dad8a61SMaxime Ripard [RPI_FIRMWARE_CORE_CLK_ID] = "core", 457dad8a61SMaxime Ripard [RPI_FIRMWARE_V3D_CLK_ID] = "v3d", 467dad8a61SMaxime Ripard [RPI_FIRMWARE_H264_CLK_ID] = "h264", 477dad8a61SMaxime Ripard [RPI_FIRMWARE_ISP_CLK_ID] = "isp", 487dad8a61SMaxime Ripard [RPI_FIRMWARE_SDRAM_CLK_ID] = "sdram", 497dad8a61SMaxime Ripard [RPI_FIRMWARE_PIXEL_CLK_ID] = "pixel", 507dad8a61SMaxime Ripard [RPI_FIRMWARE_PWM_CLK_ID] = "pwm", 517dad8a61SMaxime Ripard [RPI_FIRMWARE_HEVC_CLK_ID] = "hevc", 527dad8a61SMaxime Ripard [RPI_FIRMWARE_EMMC2_CLK_ID] = "emmc2", 537dad8a61SMaxime Ripard [RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc", 547dad8a61SMaxime Ripard [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb", 55*1777cb60SDom Cobley [RPI_FIRMWARE_VEC_CLK_ID] = "vec", 567dad8a61SMaxime Ripard }; 577dad8a61SMaxime Ripard 584e85e535SNicolas Saenz Julienne #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) 594e85e535SNicolas Saenz Julienne #define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1) 604e85e535SNicolas Saenz Julienne 6112c90f3fSMaxime Ripard struct raspberrypi_clk_variant; 6212c90f3fSMaxime Ripard 634e85e535SNicolas Saenz Julienne struct raspberrypi_clk { 644e85e535SNicolas Saenz Julienne struct device *dev; 654e85e535SNicolas Saenz Julienne struct rpi_firmware *firmware; 66e2bb1834SNicolas Saenz Julienne struct platform_device *cpufreq; 67f922c560SMaxime Ripard }; 684e85e535SNicolas Saenz Julienne 69f922c560SMaxime Ripard struct raspberrypi_clk_data { 70f922c560SMaxime Ripard struct clk_hw hw; 718a1f3ebcSMaxime Ripard 728a1f3ebcSMaxime Ripard unsigned int id; 7312c90f3fSMaxime Ripard struct raspberrypi_clk_variant *variant; 748a1f3ebcSMaxime Ripard 75f922c560SMaxime Ripard struct raspberrypi_clk *rpi; 764e85e535SNicolas Saenz Julienne }; 774e85e535SNicolas Saenz Julienne 7812c90f3fSMaxime Ripard struct raspberrypi_clk_variant { 7912c90f3fSMaxime Ripard bool export; 8012c90f3fSMaxime Ripard char *clkdev; 81542acfecSMaxime Ripard unsigned long min_rate; 82e9d6cea2SMaxime Ripard bool minimize; 8312c90f3fSMaxime Ripard }; 8412c90f3fSMaxime Ripard 8512c90f3fSMaxime Ripard static struct raspberrypi_clk_variant 8612c90f3fSMaxime Ripard raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { 8712c90f3fSMaxime Ripard [RPI_FIRMWARE_ARM_CLK_ID] = { 8812c90f3fSMaxime Ripard .export = true, 8912c90f3fSMaxime Ripard .clkdev = "cpu0", 9012c90f3fSMaxime Ripard }, 9112c90f3fSMaxime Ripard [RPI_FIRMWARE_CORE_CLK_ID] = { 9212c90f3fSMaxime Ripard .export = true, 93e9d6cea2SMaxime Ripard 94e9d6cea2SMaxime Ripard /* 95e9d6cea2SMaxime Ripard * The clock is shared between the HVS and the CSI 96e9d6cea2SMaxime Ripard * controllers, on the BCM2711 and will change depending 97e9d6cea2SMaxime Ripard * on the pixels composited on the HVS and the capture 98e9d6cea2SMaxime Ripard * resolution on Unicam. 99e9d6cea2SMaxime Ripard * 100e9d6cea2SMaxime Ripard * Since the rate can get quite large, and we need to 101e9d6cea2SMaxime Ripard * coordinate between both driver instances, let's 102e9d6cea2SMaxime Ripard * always use the minimum the drivers will let us. 103e9d6cea2SMaxime Ripard */ 104e9d6cea2SMaxime Ripard .minimize = true, 10512c90f3fSMaxime Ripard }, 10612c90f3fSMaxime Ripard [RPI_FIRMWARE_M2MC_CLK_ID] = { 10712c90f3fSMaxime Ripard .export = true, 108542acfecSMaxime Ripard 109542acfecSMaxime Ripard /* 110542acfecSMaxime Ripard * If we boot without any cable connected to any of the 111542acfecSMaxime Ripard * HDMI connector, the firmware will skip the HSM 112542acfecSMaxime Ripard * initialization and leave it with a rate of 0, 113542acfecSMaxime Ripard * resulting in a bus lockup when we're accessing the 114542acfecSMaxime Ripard * registers even if it's enabled. 115542acfecSMaxime Ripard * 116542acfecSMaxime Ripard * Let's put a sensible default so that we don't end up 117542acfecSMaxime Ripard * in this situation. 118542acfecSMaxime Ripard */ 119542acfecSMaxime Ripard .min_rate = 120000000, 120e9d6cea2SMaxime Ripard 121e9d6cea2SMaxime Ripard /* 122e9d6cea2SMaxime Ripard * The clock is shared between the two HDMI controllers 123e9d6cea2SMaxime Ripard * on the BCM2711 and will change depending on the 124e9d6cea2SMaxime Ripard * resolution output on each. Since the rate can get 125e9d6cea2SMaxime Ripard * quite large, and we need to coordinate between both 126e9d6cea2SMaxime Ripard * driver instances, let's always use the minimum the 127e9d6cea2SMaxime Ripard * drivers will let us. 128e9d6cea2SMaxime Ripard */ 129e9d6cea2SMaxime Ripard .minimize = true, 13012c90f3fSMaxime Ripard }, 13112c90f3fSMaxime Ripard [RPI_FIRMWARE_V3D_CLK_ID] = { 13212c90f3fSMaxime Ripard .export = true, 13312c90f3fSMaxime Ripard }, 13416baa8c1SIvan T. Ivanov [RPI_FIRMWARE_PIXEL_CLK_ID] = { 13516baa8c1SIvan T. Ivanov .export = true, 13616baa8c1SIvan T. Ivanov }, 1374c68a345SIvan T. Ivanov [RPI_FIRMWARE_HEVC_CLK_ID] = { 1384c68a345SIvan T. Ivanov .export = true, 1394c68a345SIvan T. Ivanov }, 14012c90f3fSMaxime Ripard [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = { 14112c90f3fSMaxime Ripard .export = true, 14212c90f3fSMaxime Ripard }, 143*1777cb60SDom Cobley [RPI_FIRMWARE_VEC_CLK_ID] = { 144*1777cb60SDom Cobley .export = true, 145*1777cb60SDom Cobley }, 14612c90f3fSMaxime Ripard }; 14712c90f3fSMaxime Ripard 1484e85e535SNicolas Saenz Julienne /* 1494e85e535SNicolas Saenz Julienne * Structure of the message passed to Raspberry Pi's firmware in order to 1504e85e535SNicolas Saenz Julienne * change clock rates. The 'disable_turbo' option is only available to the ARM 1514e85e535SNicolas Saenz Julienne * clock (pllb) which we enable by default as turbo mode will alter multiple 1524e85e535SNicolas Saenz Julienne * clocks at once. 1534e85e535SNicolas Saenz Julienne * 1544e85e535SNicolas Saenz Julienne * Even though we're able to access the clock registers directly we're bound to 1554e85e535SNicolas Saenz Julienne * use the firmware interface as the firmware ultimately takes care of 1564e85e535SNicolas Saenz Julienne * mitigating overheating/undervoltage situations and we would be changing 1574e85e535SNicolas Saenz Julienne * frequencies behind his back. 1584e85e535SNicolas Saenz Julienne * 1594e85e535SNicolas Saenz Julienne * For more information on the firmware interface check: 1604e85e535SNicolas Saenz Julienne * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface 1614e85e535SNicolas Saenz Julienne */ 1624e85e535SNicolas Saenz Julienne struct raspberrypi_firmware_prop { 1634e85e535SNicolas Saenz Julienne __le32 id; 1644e85e535SNicolas Saenz Julienne __le32 val; 1654e85e535SNicolas Saenz Julienne __le32 disable_turbo; 1664e85e535SNicolas Saenz Julienne } __packed; 1674e85e535SNicolas Saenz Julienne 16881df0151SMaxime Ripard static int raspberrypi_clock_property(struct rpi_firmware *firmware, 16981df0151SMaxime Ripard const struct raspberrypi_clk_data *data, 17081df0151SMaxime Ripard u32 tag, u32 *val) 1714e85e535SNicolas Saenz Julienne { 1724e85e535SNicolas Saenz Julienne struct raspberrypi_firmware_prop msg = { 17381df0151SMaxime Ripard .id = cpu_to_le32(data->id), 1744e85e535SNicolas Saenz Julienne .val = cpu_to_le32(*val), 1754e85e535SNicolas Saenz Julienne .disable_turbo = cpu_to_le32(1), 1764e85e535SNicolas Saenz Julienne }; 1774e85e535SNicolas Saenz Julienne int ret; 1784e85e535SNicolas Saenz Julienne 1794e85e535SNicolas Saenz Julienne ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg)); 1804e85e535SNicolas Saenz Julienne if (ret) 1814e85e535SNicolas Saenz Julienne return ret; 1824e85e535SNicolas Saenz Julienne 1834e85e535SNicolas Saenz Julienne *val = le32_to_cpu(msg.val); 1844e85e535SNicolas Saenz Julienne 1854e85e535SNicolas Saenz Julienne return 0; 1864e85e535SNicolas Saenz Julienne } 1874e85e535SNicolas Saenz Julienne 188c1ce3509SMaxime Ripard static int raspberrypi_fw_is_prepared(struct clk_hw *hw) 1894e85e535SNicolas Saenz Julienne { 190f922c560SMaxime Ripard struct raspberrypi_clk_data *data = 191f922c560SMaxime Ripard container_of(hw, struct raspberrypi_clk_data, hw); 192f922c560SMaxime Ripard struct raspberrypi_clk *rpi = data->rpi; 1934e85e535SNicolas Saenz Julienne u32 val = 0; 1944e85e535SNicolas Saenz Julienne int ret; 1954e85e535SNicolas Saenz Julienne 19681df0151SMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 19781df0151SMaxime Ripard RPI_FIRMWARE_GET_CLOCK_STATE, &val); 1984e85e535SNicolas Saenz Julienne if (ret) 1994e85e535SNicolas Saenz Julienne return 0; 2004e85e535SNicolas Saenz Julienne 2014e85e535SNicolas Saenz Julienne return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT); 2024e85e535SNicolas Saenz Julienne } 2034e85e535SNicolas Saenz Julienne 2044e85e535SNicolas Saenz Julienne 2053ea59aceSMaxime Ripard static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, 2064e85e535SNicolas Saenz Julienne unsigned long parent_rate) 2074e85e535SNicolas Saenz Julienne { 208f922c560SMaxime Ripard struct raspberrypi_clk_data *data = 209f922c560SMaxime Ripard container_of(hw, struct raspberrypi_clk_data, hw); 210f922c560SMaxime Ripard struct raspberrypi_clk *rpi = data->rpi; 2114e85e535SNicolas Saenz Julienne u32 val = 0; 2124e85e535SNicolas Saenz Julienne int ret; 2134e85e535SNicolas Saenz Julienne 21481df0151SMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 21581df0151SMaxime Ripard RPI_FIRMWARE_GET_CLOCK_RATE, &val); 2164e85e535SNicolas Saenz Julienne if (ret) 2174e85e535SNicolas Saenz Julienne return ret; 2184e85e535SNicolas Saenz Julienne 2193ea59aceSMaxime Ripard return val; 2204e85e535SNicolas Saenz Julienne } 2214e85e535SNicolas Saenz Julienne 2223ea59aceSMaxime Ripard static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, 2234e85e535SNicolas Saenz Julienne unsigned long parent_rate) 2244e85e535SNicolas Saenz Julienne { 225f922c560SMaxime Ripard struct raspberrypi_clk_data *data = 226f922c560SMaxime Ripard container_of(hw, struct raspberrypi_clk_data, hw); 227f922c560SMaxime Ripard struct raspberrypi_clk *rpi = data->rpi; 2283ea59aceSMaxime Ripard u32 _rate = rate; 2294e85e535SNicolas Saenz Julienne int ret; 2304e85e535SNicolas Saenz Julienne 23181df0151SMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 2323ea59aceSMaxime Ripard RPI_FIRMWARE_SET_CLOCK_RATE, &_rate); 2334e85e535SNicolas Saenz Julienne if (ret) 2344e85e535SNicolas Saenz Julienne dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", 2354e85e535SNicolas Saenz Julienne clk_hw_get_name(hw), ret); 2364e85e535SNicolas Saenz Julienne 2374e85e535SNicolas Saenz Julienne return ret; 2384e85e535SNicolas Saenz Julienne } 2394e85e535SNicolas Saenz Julienne 24093d2725aSMaxime Ripard static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw, 24193d2725aSMaxime Ripard struct clk_rate_request *req) 24293d2725aSMaxime Ripard { 243e9d6cea2SMaxime Ripard struct raspberrypi_clk_data *data = 244e9d6cea2SMaxime Ripard container_of(hw, struct raspberrypi_clk_data, hw); 245e9d6cea2SMaxime Ripard struct raspberrypi_clk_variant *variant = data->variant; 246e9d6cea2SMaxime Ripard 24793d2725aSMaxime Ripard /* 24893d2725aSMaxime Ripard * The firmware will do the rounding but that isn't part of 24993d2725aSMaxime Ripard * the interface with the firmware, so we just do our best 25093d2725aSMaxime Ripard * here. 25193d2725aSMaxime Ripard */ 252e9d6cea2SMaxime Ripard 25393d2725aSMaxime Ripard req->rate = clamp(req->rate, req->min_rate, req->max_rate); 254e9d6cea2SMaxime Ripard 255e9d6cea2SMaxime Ripard /* 256e9d6cea2SMaxime Ripard * We want to aggressively reduce the clock rate here, so let's 257e9d6cea2SMaxime Ripard * just ignore the requested rate and return the bare minimum 258e9d6cea2SMaxime Ripard * rate we can get away with. 259e9d6cea2SMaxime Ripard */ 260e9d6cea2SMaxime Ripard if (variant->minimize && req->min_rate > 0) 261e9d6cea2SMaxime Ripard req->rate = req->min_rate; 262e9d6cea2SMaxime Ripard 26393d2725aSMaxime Ripard return 0; 26493d2725aSMaxime Ripard } 26593d2725aSMaxime Ripard 26693d2725aSMaxime Ripard static const struct clk_ops raspberrypi_firmware_clk_ops = { 26793d2725aSMaxime Ripard .is_prepared = raspberrypi_fw_is_prepared, 26893d2725aSMaxime Ripard .recalc_rate = raspberrypi_fw_get_rate, 26993d2725aSMaxime Ripard .determine_rate = raspberrypi_fw_dumb_determine_rate, 27093d2725aSMaxime Ripard .set_rate = raspberrypi_fw_set_rate, 27193d2725aSMaxime Ripard }; 27293d2725aSMaxime Ripard 27393d2725aSMaxime Ripard static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, 27493d2725aSMaxime Ripard unsigned int parent, 27512c90f3fSMaxime Ripard unsigned int id, 27612c90f3fSMaxime Ripard struct raspberrypi_clk_variant *variant) 27793d2725aSMaxime Ripard { 27893d2725aSMaxime Ripard struct raspberrypi_clk_data *data; 27993d2725aSMaxime Ripard struct clk_init_data init = {}; 28093d2725aSMaxime Ripard u32 min_rate, max_rate; 28193d2725aSMaxime Ripard int ret; 28293d2725aSMaxime Ripard 28393d2725aSMaxime Ripard data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL); 28493d2725aSMaxime Ripard if (!data) 28593d2725aSMaxime Ripard return ERR_PTR(-ENOMEM); 28693d2725aSMaxime Ripard data->rpi = rpi; 28793d2725aSMaxime Ripard data->id = id; 28812c90f3fSMaxime Ripard data->variant = variant; 28993d2725aSMaxime Ripard 2907dad8a61SMaxime Ripard init.name = devm_kasprintf(rpi->dev, GFP_KERNEL, 2917dad8a61SMaxime Ripard "fw-clk-%s", 2927dad8a61SMaxime Ripard rpi_firmware_clk_names[id]); 29393d2725aSMaxime Ripard init.ops = &raspberrypi_firmware_clk_ops; 29493d2725aSMaxime Ripard init.flags = CLK_GET_RATE_NOCACHE; 29593d2725aSMaxime Ripard 29693d2725aSMaxime Ripard data->hw.init = &init; 29793d2725aSMaxime Ripard 29893d2725aSMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 29993d2725aSMaxime Ripard RPI_FIRMWARE_GET_MIN_CLOCK_RATE, 30093d2725aSMaxime Ripard &min_rate); 30193d2725aSMaxime Ripard if (ret) { 30293d2725aSMaxime Ripard dev_err(rpi->dev, "Failed to get clock %d min freq: %d", 30393d2725aSMaxime Ripard id, ret); 30493d2725aSMaxime Ripard return ERR_PTR(ret); 30593d2725aSMaxime Ripard } 30693d2725aSMaxime Ripard 30793d2725aSMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 30893d2725aSMaxime Ripard RPI_FIRMWARE_GET_MAX_CLOCK_RATE, 30993d2725aSMaxime Ripard &max_rate); 31093d2725aSMaxime Ripard if (ret) { 31193d2725aSMaxime Ripard dev_err(rpi->dev, "Failed to get clock %d max freq: %d\n", 31293d2725aSMaxime Ripard id, ret); 31393d2725aSMaxime Ripard return ERR_PTR(ret); 31493d2725aSMaxime Ripard } 31593d2725aSMaxime Ripard 31693d2725aSMaxime Ripard ret = devm_clk_hw_register(rpi->dev, &data->hw); 31793d2725aSMaxime Ripard if (ret) 31893d2725aSMaxime Ripard return ERR_PTR(ret); 31993d2725aSMaxime Ripard 32093d2725aSMaxime Ripard clk_hw_set_rate_range(&data->hw, min_rate, max_rate); 32193d2725aSMaxime Ripard 32212c90f3fSMaxime Ripard if (variant->clkdev) { 32393d2725aSMaxime Ripard ret = devm_clk_hw_register_clkdev(rpi->dev, &data->hw, 32412c90f3fSMaxime Ripard NULL, variant->clkdev); 32593d2725aSMaxime Ripard if (ret) { 32693d2725aSMaxime Ripard dev_err(rpi->dev, "Failed to initialize clkdev\n"); 32793d2725aSMaxime Ripard return ERR_PTR(ret); 32893d2725aSMaxime Ripard } 32993d2725aSMaxime Ripard } 33093d2725aSMaxime Ripard 331542acfecSMaxime Ripard if (variant->min_rate) { 332542acfecSMaxime Ripard unsigned long rate; 333542acfecSMaxime Ripard 334542acfecSMaxime Ripard clk_hw_set_rate_range(&data->hw, variant->min_rate, max_rate); 335542acfecSMaxime Ripard 336542acfecSMaxime Ripard rate = raspberrypi_fw_get_rate(&data->hw, 0); 337542acfecSMaxime Ripard if (rate < variant->min_rate) { 338542acfecSMaxime Ripard ret = raspberrypi_fw_set_rate(&data->hw, variant->min_rate, 0); 339542acfecSMaxime Ripard if (ret) 340542acfecSMaxime Ripard return ERR_PTR(ret); 341542acfecSMaxime Ripard } 342542acfecSMaxime Ripard } 343542acfecSMaxime Ripard 34493d2725aSMaxime Ripard return &data->hw; 34593d2725aSMaxime Ripard } 34693d2725aSMaxime Ripard 34793d2725aSMaxime Ripard struct rpi_firmware_get_clocks_response { 34893d2725aSMaxime Ripard u32 parent; 34993d2725aSMaxime Ripard u32 id; 35093d2725aSMaxime Ripard }; 35193d2725aSMaxime Ripard 35293d2725aSMaxime Ripard static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, 35393d2725aSMaxime Ripard struct clk_hw_onecell_data *data) 35493d2725aSMaxime Ripard { 35593d2725aSMaxime Ripard struct rpi_firmware_get_clocks_response *clks; 35693d2725aSMaxime Ripard int ret; 35793d2725aSMaxime Ripard 35893d2725aSMaxime Ripard clks = devm_kcalloc(rpi->dev, 359b7fa6242SChristophe JAILLET RPI_FIRMWARE_NUM_CLK_ID, sizeof(*clks), 36093d2725aSMaxime Ripard GFP_KERNEL); 36193d2725aSMaxime Ripard if (!clks) 36293d2725aSMaxime Ripard return -ENOMEM; 36393d2725aSMaxime Ripard 36493d2725aSMaxime Ripard ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS, 36593d2725aSMaxime Ripard clks, 36693d2725aSMaxime Ripard sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID); 36793d2725aSMaxime Ripard if (ret) 36893d2725aSMaxime Ripard return ret; 36993d2725aSMaxime Ripard 37093d2725aSMaxime Ripard while (clks->id) { 37112c90f3fSMaxime Ripard struct raspberrypi_clk_variant *variant; 37212c90f3fSMaxime Ripard 37312c90f3fSMaxime Ripard if (clks->id > RPI_FIRMWARE_NUM_CLK_ID) { 37412c90f3fSMaxime Ripard dev_err(rpi->dev, "Unknown clock id: %u", clks->id); 37512c90f3fSMaxime Ripard return -EINVAL; 37612c90f3fSMaxime Ripard } 37712c90f3fSMaxime Ripard 37812c90f3fSMaxime Ripard variant = &raspberrypi_clk_variants[clks->id]; 37912c90f3fSMaxime Ripard if (variant->export) { 38093d2725aSMaxime Ripard struct clk_hw *hw; 38193d2725aSMaxime Ripard 38293d2725aSMaxime Ripard hw = raspberrypi_clk_register(rpi, clks->parent, 38312c90f3fSMaxime Ripard clks->id, variant); 38493d2725aSMaxime Ripard if (IS_ERR(hw)) 38593d2725aSMaxime Ripard return PTR_ERR(hw); 38693d2725aSMaxime Ripard 38793d2725aSMaxime Ripard data->hws[clks->id] = hw; 38893d2725aSMaxime Ripard data->num = clks->id + 1; 38993d2725aSMaxime Ripard } 39012c90f3fSMaxime Ripard 39112c90f3fSMaxime Ripard clks++; 39293d2725aSMaxime Ripard } 39393d2725aSMaxime Ripard 39493d2725aSMaxime Ripard return 0; 39593d2725aSMaxime Ripard } 39693d2725aSMaxime Ripard 3974e85e535SNicolas Saenz Julienne static int raspberrypi_clk_probe(struct platform_device *pdev) 3984e85e535SNicolas Saenz Julienne { 399d4b4f1b6SMaxime Ripard struct clk_hw_onecell_data *clk_data; 4004e85e535SNicolas Saenz Julienne struct device_node *firmware_node; 4014e85e535SNicolas Saenz Julienne struct device *dev = &pdev->dev; 4024e85e535SNicolas Saenz Julienne struct rpi_firmware *firmware; 4034e85e535SNicolas Saenz Julienne struct raspberrypi_clk *rpi; 404d4b4f1b6SMaxime Ripard int ret; 4054e85e535SNicolas Saenz Julienne 406fbac2e77SMaxime Ripard /* 407fbac2e77SMaxime Ripard * We can be probed either through the an old-fashioned 408fbac2e77SMaxime Ripard * platform device registration or through a DT node that is a 409fbac2e77SMaxime Ripard * child of the firmware node. Handle both cases. 410fbac2e77SMaxime Ripard */ 411fbac2e77SMaxime Ripard if (dev->of_node) 412fbac2e77SMaxime Ripard firmware_node = of_get_parent(dev->of_node); 413fbac2e77SMaxime Ripard else 4144e85e535SNicolas Saenz Julienne firmware_node = of_find_compatible_node(NULL, NULL, 4154e85e535SNicolas Saenz Julienne "raspberrypi,bcm2835-firmware"); 4164e85e535SNicolas Saenz Julienne if (!firmware_node) { 4174e85e535SNicolas Saenz Julienne dev_err(dev, "Missing firmware node\n"); 4184e85e535SNicolas Saenz Julienne return -ENOENT; 4194e85e535SNicolas Saenz Julienne } 4204e85e535SNicolas Saenz Julienne 4213c4084f9SNicolas Saenz Julienne firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); 4224e85e535SNicolas Saenz Julienne of_node_put(firmware_node); 4234e85e535SNicolas Saenz Julienne if (!firmware) 4244e85e535SNicolas Saenz Julienne return -EPROBE_DEFER; 4254e85e535SNicolas Saenz Julienne 4264e85e535SNicolas Saenz Julienne rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL); 4274e85e535SNicolas Saenz Julienne if (!rpi) 4284e85e535SNicolas Saenz Julienne return -ENOMEM; 4294e85e535SNicolas Saenz Julienne 4304e85e535SNicolas Saenz Julienne rpi->dev = dev; 4314e85e535SNicolas Saenz Julienne rpi->firmware = firmware; 432e2bb1834SNicolas Saenz Julienne platform_set_drvdata(pdev, rpi); 4334e85e535SNicolas Saenz Julienne 434be1559f6SMaxime Ripard clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, 435be1559f6SMaxime Ripard RPI_FIRMWARE_NUM_CLK_ID), 436d4b4f1b6SMaxime Ripard GFP_KERNEL); 437d4b4f1b6SMaxime Ripard if (!clk_data) 438d4b4f1b6SMaxime Ripard return -ENOMEM; 439d4b4f1b6SMaxime Ripard 44093d2725aSMaxime Ripard ret = raspberrypi_discover_clocks(rpi, clk_data); 44193d2725aSMaxime Ripard if (ret) 44293d2725aSMaxime Ripard return ret; 443d4b4f1b6SMaxime Ripard 444d4b4f1b6SMaxime Ripard ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 445d4b4f1b6SMaxime Ripard clk_data); 446d4b4f1b6SMaxime Ripard if (ret) 447d4b4f1b6SMaxime Ripard return ret; 4484e85e535SNicolas Saenz Julienne 449e2bb1834SNicolas Saenz Julienne rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", 450e2bb1834SNicolas Saenz Julienne -1, NULL, 0); 451e2bb1834SNicolas Saenz Julienne 452e2bb1834SNicolas Saenz Julienne return 0; 453e2bb1834SNicolas Saenz Julienne } 454e2bb1834SNicolas Saenz Julienne 455e2bb1834SNicolas Saenz Julienne static int raspberrypi_clk_remove(struct platform_device *pdev) 456e2bb1834SNicolas Saenz Julienne { 457e2bb1834SNicolas Saenz Julienne struct raspberrypi_clk *rpi = platform_get_drvdata(pdev); 458e2bb1834SNicolas Saenz Julienne 459e2bb1834SNicolas Saenz Julienne platform_device_unregister(rpi->cpufreq); 460e2bb1834SNicolas Saenz Julienne 4614e85e535SNicolas Saenz Julienne return 0; 4624e85e535SNicolas Saenz Julienne } 4634e85e535SNicolas Saenz Julienne 464fbac2e77SMaxime Ripard static const struct of_device_id raspberrypi_clk_match[] = { 465fbac2e77SMaxime Ripard { .compatible = "raspberrypi,firmware-clocks" }, 466fbac2e77SMaxime Ripard { }, 467fbac2e77SMaxime Ripard }; 468fbac2e77SMaxime Ripard MODULE_DEVICE_TABLE(of, raspberrypi_clk_match); 469fbac2e77SMaxime Ripard 4704e85e535SNicolas Saenz Julienne static struct platform_driver raspberrypi_clk_driver = { 4714e85e535SNicolas Saenz Julienne .driver = { 4724e85e535SNicolas Saenz Julienne .name = "raspberrypi-clk", 473fbac2e77SMaxime Ripard .of_match_table = raspberrypi_clk_match, 4744e85e535SNicolas Saenz Julienne }, 4754e85e535SNicolas Saenz Julienne .probe = raspberrypi_clk_probe, 476e2bb1834SNicolas Saenz Julienne .remove = raspberrypi_clk_remove, 4774e85e535SNicolas Saenz Julienne }; 4784e85e535SNicolas Saenz Julienne module_platform_driver(raspberrypi_clk_driver); 4794e85e535SNicolas Saenz Julienne 4804e85e535SNicolas Saenz Julienne MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); 4814e85e535SNicolas Saenz Julienne MODULE_DESCRIPTION("Raspberry Pi firmware clock driver"); 4824e85e535SNicolas Saenz Julienne MODULE_LICENSE("GPL"); 4834e85e535SNicolas Saenz Julienne MODULE_ALIAS("platform:raspberrypi-clk"); 484