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, 36be1559f6SMaxime Ripard RPI_FIRMWARE_NUM_CLK_ID, 37be1559f6SMaxime Ripard }; 384e85e535SNicolas Saenz Julienne 397dad8a61SMaxime Ripard static char *rpi_firmware_clk_names[] = { 407dad8a61SMaxime Ripard [RPI_FIRMWARE_EMMC_CLK_ID] = "emmc", 417dad8a61SMaxime Ripard [RPI_FIRMWARE_UART_CLK_ID] = "uart", 427dad8a61SMaxime Ripard [RPI_FIRMWARE_ARM_CLK_ID] = "arm", 437dad8a61SMaxime Ripard [RPI_FIRMWARE_CORE_CLK_ID] = "core", 447dad8a61SMaxime Ripard [RPI_FIRMWARE_V3D_CLK_ID] = "v3d", 457dad8a61SMaxime Ripard [RPI_FIRMWARE_H264_CLK_ID] = "h264", 467dad8a61SMaxime Ripard [RPI_FIRMWARE_ISP_CLK_ID] = "isp", 477dad8a61SMaxime Ripard [RPI_FIRMWARE_SDRAM_CLK_ID] = "sdram", 487dad8a61SMaxime Ripard [RPI_FIRMWARE_PIXEL_CLK_ID] = "pixel", 497dad8a61SMaxime Ripard [RPI_FIRMWARE_PWM_CLK_ID] = "pwm", 507dad8a61SMaxime Ripard [RPI_FIRMWARE_HEVC_CLK_ID] = "hevc", 517dad8a61SMaxime Ripard [RPI_FIRMWARE_EMMC2_CLK_ID] = "emmc2", 527dad8a61SMaxime Ripard [RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc", 537dad8a61SMaxime Ripard [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb", 547dad8a61SMaxime Ripard }; 557dad8a61SMaxime Ripard 564e85e535SNicolas Saenz Julienne #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) 574e85e535SNicolas Saenz Julienne #define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1) 584e85e535SNicolas Saenz Julienne 5912c90f3fSMaxime Ripard struct raspberrypi_clk_variant; 6012c90f3fSMaxime Ripard 614e85e535SNicolas Saenz Julienne struct raspberrypi_clk { 624e85e535SNicolas Saenz Julienne struct device *dev; 634e85e535SNicolas Saenz Julienne struct rpi_firmware *firmware; 64e2bb1834SNicolas Saenz Julienne struct platform_device *cpufreq; 65f922c560SMaxime Ripard }; 664e85e535SNicolas Saenz Julienne 67f922c560SMaxime Ripard struct raspberrypi_clk_data { 68f922c560SMaxime Ripard struct clk_hw hw; 698a1f3ebcSMaxime Ripard 708a1f3ebcSMaxime Ripard unsigned int id; 7112c90f3fSMaxime Ripard struct raspberrypi_clk_variant *variant; 728a1f3ebcSMaxime Ripard 73f922c560SMaxime Ripard struct raspberrypi_clk *rpi; 744e85e535SNicolas Saenz Julienne }; 754e85e535SNicolas Saenz Julienne 7612c90f3fSMaxime Ripard struct raspberrypi_clk_variant { 7712c90f3fSMaxime Ripard bool export; 7812c90f3fSMaxime Ripard char *clkdev; 79542acfecSMaxime Ripard unsigned long min_rate; 80e9d6cea2SMaxime Ripard bool minimize; 8112c90f3fSMaxime Ripard }; 8212c90f3fSMaxime Ripard 8312c90f3fSMaxime Ripard static struct raspberrypi_clk_variant 8412c90f3fSMaxime Ripard raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { 8512c90f3fSMaxime Ripard [RPI_FIRMWARE_ARM_CLK_ID] = { 8612c90f3fSMaxime Ripard .export = true, 8712c90f3fSMaxime Ripard .clkdev = "cpu0", 8812c90f3fSMaxime Ripard }, 8912c90f3fSMaxime Ripard [RPI_FIRMWARE_CORE_CLK_ID] = { 9012c90f3fSMaxime Ripard .export = true, 91e9d6cea2SMaxime Ripard 92e9d6cea2SMaxime Ripard /* 93e9d6cea2SMaxime Ripard * The clock is shared between the HVS and the CSI 94e9d6cea2SMaxime Ripard * controllers, on the BCM2711 and will change depending 95e9d6cea2SMaxime Ripard * on the pixels composited on the HVS and the capture 96e9d6cea2SMaxime Ripard * resolution on Unicam. 97e9d6cea2SMaxime Ripard * 98e9d6cea2SMaxime Ripard * Since the rate can get quite large, and we need to 99e9d6cea2SMaxime Ripard * coordinate between both driver instances, let's 100e9d6cea2SMaxime Ripard * always use the minimum the drivers will let us. 101e9d6cea2SMaxime Ripard */ 102e9d6cea2SMaxime Ripard .minimize = true, 10312c90f3fSMaxime Ripard }, 10412c90f3fSMaxime Ripard [RPI_FIRMWARE_M2MC_CLK_ID] = { 10512c90f3fSMaxime Ripard .export = true, 106542acfecSMaxime Ripard 107542acfecSMaxime Ripard /* 108542acfecSMaxime Ripard * If we boot without any cable connected to any of the 109542acfecSMaxime Ripard * HDMI connector, the firmware will skip the HSM 110542acfecSMaxime Ripard * initialization and leave it with a rate of 0, 111542acfecSMaxime Ripard * resulting in a bus lockup when we're accessing the 112542acfecSMaxime Ripard * registers even if it's enabled. 113542acfecSMaxime Ripard * 114542acfecSMaxime Ripard * Let's put a sensible default so that we don't end up 115542acfecSMaxime Ripard * in this situation. 116542acfecSMaxime Ripard */ 117542acfecSMaxime Ripard .min_rate = 120000000, 118e9d6cea2SMaxime Ripard 119e9d6cea2SMaxime Ripard /* 120e9d6cea2SMaxime Ripard * The clock is shared between the two HDMI controllers 121e9d6cea2SMaxime Ripard * on the BCM2711 and will change depending on the 122e9d6cea2SMaxime Ripard * resolution output on each. Since the rate can get 123e9d6cea2SMaxime Ripard * quite large, and we need to coordinate between both 124e9d6cea2SMaxime Ripard * driver instances, let's always use the minimum the 125e9d6cea2SMaxime Ripard * drivers will let us. 126e9d6cea2SMaxime Ripard */ 127e9d6cea2SMaxime Ripard .minimize = true, 12812c90f3fSMaxime Ripard }, 12912c90f3fSMaxime Ripard [RPI_FIRMWARE_V3D_CLK_ID] = { 13012c90f3fSMaxime Ripard .export = true, 13112c90f3fSMaxime Ripard }, 13212c90f3fSMaxime Ripard [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = { 13312c90f3fSMaxime Ripard .export = true, 13412c90f3fSMaxime Ripard }, 13512c90f3fSMaxime Ripard }; 13612c90f3fSMaxime Ripard 1374e85e535SNicolas Saenz Julienne /* 1384e85e535SNicolas Saenz Julienne * Structure of the message passed to Raspberry Pi's firmware in order to 1394e85e535SNicolas Saenz Julienne * change clock rates. The 'disable_turbo' option is only available to the ARM 1404e85e535SNicolas Saenz Julienne * clock (pllb) which we enable by default as turbo mode will alter multiple 1414e85e535SNicolas Saenz Julienne * clocks at once. 1424e85e535SNicolas Saenz Julienne * 1434e85e535SNicolas Saenz Julienne * Even though we're able to access the clock registers directly we're bound to 1444e85e535SNicolas Saenz Julienne * use the firmware interface as the firmware ultimately takes care of 1454e85e535SNicolas Saenz Julienne * mitigating overheating/undervoltage situations and we would be changing 1464e85e535SNicolas Saenz Julienne * frequencies behind his back. 1474e85e535SNicolas Saenz Julienne * 1484e85e535SNicolas Saenz Julienne * For more information on the firmware interface check: 1494e85e535SNicolas Saenz Julienne * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface 1504e85e535SNicolas Saenz Julienne */ 1514e85e535SNicolas Saenz Julienne struct raspberrypi_firmware_prop { 1524e85e535SNicolas Saenz Julienne __le32 id; 1534e85e535SNicolas Saenz Julienne __le32 val; 1544e85e535SNicolas Saenz Julienne __le32 disable_turbo; 1554e85e535SNicolas Saenz Julienne } __packed; 1564e85e535SNicolas Saenz Julienne 15781df0151SMaxime Ripard static int raspberrypi_clock_property(struct rpi_firmware *firmware, 15881df0151SMaxime Ripard const struct raspberrypi_clk_data *data, 15981df0151SMaxime Ripard u32 tag, u32 *val) 1604e85e535SNicolas Saenz Julienne { 1614e85e535SNicolas Saenz Julienne struct raspberrypi_firmware_prop msg = { 16281df0151SMaxime Ripard .id = cpu_to_le32(data->id), 1634e85e535SNicolas Saenz Julienne .val = cpu_to_le32(*val), 1644e85e535SNicolas Saenz Julienne .disable_turbo = cpu_to_le32(1), 1654e85e535SNicolas Saenz Julienne }; 1664e85e535SNicolas Saenz Julienne int ret; 1674e85e535SNicolas Saenz Julienne 1684e85e535SNicolas Saenz Julienne ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg)); 1694e85e535SNicolas Saenz Julienne if (ret) 1704e85e535SNicolas Saenz Julienne return ret; 1714e85e535SNicolas Saenz Julienne 1724e85e535SNicolas Saenz Julienne *val = le32_to_cpu(msg.val); 1734e85e535SNicolas Saenz Julienne 1744e85e535SNicolas Saenz Julienne return 0; 1754e85e535SNicolas Saenz Julienne } 1764e85e535SNicolas Saenz Julienne 177c1ce3509SMaxime Ripard static int raspberrypi_fw_is_prepared(struct clk_hw *hw) 1784e85e535SNicolas Saenz Julienne { 179f922c560SMaxime Ripard struct raspberrypi_clk_data *data = 180f922c560SMaxime Ripard container_of(hw, struct raspberrypi_clk_data, hw); 181f922c560SMaxime Ripard struct raspberrypi_clk *rpi = data->rpi; 1824e85e535SNicolas Saenz Julienne u32 val = 0; 1834e85e535SNicolas Saenz Julienne int ret; 1844e85e535SNicolas Saenz Julienne 18581df0151SMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 18681df0151SMaxime Ripard RPI_FIRMWARE_GET_CLOCK_STATE, &val); 1874e85e535SNicolas Saenz Julienne if (ret) 1884e85e535SNicolas Saenz Julienne return 0; 1894e85e535SNicolas Saenz Julienne 1904e85e535SNicolas Saenz Julienne return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT); 1914e85e535SNicolas Saenz Julienne } 1924e85e535SNicolas Saenz Julienne 1934e85e535SNicolas Saenz Julienne 1943ea59aceSMaxime Ripard static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, 1954e85e535SNicolas Saenz Julienne unsigned long parent_rate) 1964e85e535SNicolas Saenz Julienne { 197f922c560SMaxime Ripard struct raspberrypi_clk_data *data = 198f922c560SMaxime Ripard container_of(hw, struct raspberrypi_clk_data, hw); 199f922c560SMaxime Ripard struct raspberrypi_clk *rpi = data->rpi; 2004e85e535SNicolas Saenz Julienne u32 val = 0; 2014e85e535SNicolas Saenz Julienne int ret; 2024e85e535SNicolas Saenz Julienne 20381df0151SMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 20481df0151SMaxime Ripard RPI_FIRMWARE_GET_CLOCK_RATE, &val); 2054e85e535SNicolas Saenz Julienne if (ret) 20635f73ccaSStefan Wahren return 0; 2074e85e535SNicolas Saenz Julienne 2083ea59aceSMaxime Ripard return val; 2094e85e535SNicolas Saenz Julienne } 2104e85e535SNicolas Saenz Julienne 2113ea59aceSMaxime Ripard static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, 2124e85e535SNicolas Saenz Julienne unsigned long parent_rate) 2134e85e535SNicolas Saenz Julienne { 214f922c560SMaxime Ripard struct raspberrypi_clk_data *data = 215f922c560SMaxime Ripard container_of(hw, struct raspberrypi_clk_data, hw); 216f922c560SMaxime Ripard struct raspberrypi_clk *rpi = data->rpi; 2173ea59aceSMaxime Ripard u32 _rate = rate; 2184e85e535SNicolas Saenz Julienne int ret; 2194e85e535SNicolas Saenz Julienne 22081df0151SMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 2213ea59aceSMaxime Ripard RPI_FIRMWARE_SET_CLOCK_RATE, &_rate); 2224e85e535SNicolas Saenz Julienne if (ret) 223*13b5cf8dSStefan Wahren dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d\n", 2244e85e535SNicolas Saenz Julienne clk_hw_get_name(hw), ret); 2254e85e535SNicolas Saenz Julienne 2264e85e535SNicolas Saenz Julienne return ret; 2274e85e535SNicolas Saenz Julienne } 2284e85e535SNicolas Saenz Julienne 22993d2725aSMaxime Ripard static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw, 23093d2725aSMaxime Ripard struct clk_rate_request *req) 23193d2725aSMaxime Ripard { 232e9d6cea2SMaxime Ripard struct raspberrypi_clk_data *data = 233e9d6cea2SMaxime Ripard container_of(hw, struct raspberrypi_clk_data, hw); 234e9d6cea2SMaxime Ripard struct raspberrypi_clk_variant *variant = data->variant; 235e9d6cea2SMaxime Ripard 23693d2725aSMaxime Ripard /* 23793d2725aSMaxime Ripard * The firmware will do the rounding but that isn't part of 23893d2725aSMaxime Ripard * the interface with the firmware, so we just do our best 23993d2725aSMaxime Ripard * here. 24093d2725aSMaxime Ripard */ 241e9d6cea2SMaxime Ripard 24293d2725aSMaxime Ripard req->rate = clamp(req->rate, req->min_rate, req->max_rate); 243e9d6cea2SMaxime Ripard 244e9d6cea2SMaxime Ripard /* 245e9d6cea2SMaxime Ripard * We want to aggressively reduce the clock rate here, so let's 246e9d6cea2SMaxime Ripard * just ignore the requested rate and return the bare minimum 247e9d6cea2SMaxime Ripard * rate we can get away with. 248e9d6cea2SMaxime Ripard */ 249e9d6cea2SMaxime Ripard if (variant->minimize && req->min_rate > 0) 250e9d6cea2SMaxime Ripard req->rate = req->min_rate; 251e9d6cea2SMaxime Ripard 25293d2725aSMaxime Ripard return 0; 25393d2725aSMaxime Ripard } 25493d2725aSMaxime Ripard 25593d2725aSMaxime Ripard static const struct clk_ops raspberrypi_firmware_clk_ops = { 25693d2725aSMaxime Ripard .is_prepared = raspberrypi_fw_is_prepared, 25793d2725aSMaxime Ripard .recalc_rate = raspberrypi_fw_get_rate, 25893d2725aSMaxime Ripard .determine_rate = raspberrypi_fw_dumb_determine_rate, 25993d2725aSMaxime Ripard .set_rate = raspberrypi_fw_set_rate, 26093d2725aSMaxime Ripard }; 26193d2725aSMaxime Ripard 26293d2725aSMaxime Ripard static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, 26393d2725aSMaxime Ripard unsigned int parent, 26412c90f3fSMaxime Ripard unsigned int id, 26512c90f3fSMaxime Ripard struct raspberrypi_clk_variant *variant) 26693d2725aSMaxime Ripard { 26793d2725aSMaxime Ripard struct raspberrypi_clk_data *data; 26893d2725aSMaxime Ripard struct clk_init_data init = {}; 26993d2725aSMaxime Ripard u32 min_rate, max_rate; 27093d2725aSMaxime Ripard int ret; 27193d2725aSMaxime Ripard 27293d2725aSMaxime Ripard data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL); 27393d2725aSMaxime Ripard if (!data) 27493d2725aSMaxime Ripard return ERR_PTR(-ENOMEM); 27593d2725aSMaxime Ripard data->rpi = rpi; 27693d2725aSMaxime Ripard data->id = id; 27712c90f3fSMaxime Ripard data->variant = variant; 27893d2725aSMaxime Ripard 2797dad8a61SMaxime Ripard init.name = devm_kasprintf(rpi->dev, GFP_KERNEL, 2807dad8a61SMaxime Ripard "fw-clk-%s", 2817dad8a61SMaxime Ripard rpi_firmware_clk_names[id]); 28293d2725aSMaxime Ripard init.ops = &raspberrypi_firmware_clk_ops; 28393d2725aSMaxime Ripard init.flags = CLK_GET_RATE_NOCACHE; 28493d2725aSMaxime Ripard 28593d2725aSMaxime Ripard data->hw.init = &init; 28693d2725aSMaxime Ripard 28793d2725aSMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 28893d2725aSMaxime Ripard RPI_FIRMWARE_GET_MIN_CLOCK_RATE, 28993d2725aSMaxime Ripard &min_rate); 29093d2725aSMaxime Ripard if (ret) { 291*13b5cf8dSStefan Wahren dev_err(rpi->dev, "Failed to get clock %d min freq: %d\n", 29293d2725aSMaxime Ripard id, ret); 29393d2725aSMaxime Ripard return ERR_PTR(ret); 29493d2725aSMaxime Ripard } 29593d2725aSMaxime Ripard 29693d2725aSMaxime Ripard ret = raspberrypi_clock_property(rpi->firmware, data, 29793d2725aSMaxime Ripard RPI_FIRMWARE_GET_MAX_CLOCK_RATE, 29893d2725aSMaxime Ripard &max_rate); 29993d2725aSMaxime Ripard if (ret) { 30093d2725aSMaxime Ripard dev_err(rpi->dev, "Failed to get clock %d max freq: %d\n", 30193d2725aSMaxime Ripard id, ret); 30293d2725aSMaxime Ripard return ERR_PTR(ret); 30393d2725aSMaxime Ripard } 30493d2725aSMaxime Ripard 30593d2725aSMaxime Ripard ret = devm_clk_hw_register(rpi->dev, &data->hw); 30693d2725aSMaxime Ripard if (ret) 30793d2725aSMaxime Ripard return ERR_PTR(ret); 30893d2725aSMaxime Ripard 30993d2725aSMaxime Ripard clk_hw_set_rate_range(&data->hw, min_rate, max_rate); 31093d2725aSMaxime Ripard 31112c90f3fSMaxime Ripard if (variant->clkdev) { 31293d2725aSMaxime Ripard ret = devm_clk_hw_register_clkdev(rpi->dev, &data->hw, 31312c90f3fSMaxime Ripard NULL, variant->clkdev); 31493d2725aSMaxime Ripard if (ret) { 31593d2725aSMaxime Ripard dev_err(rpi->dev, "Failed to initialize clkdev\n"); 31693d2725aSMaxime Ripard return ERR_PTR(ret); 31793d2725aSMaxime Ripard } 31893d2725aSMaxime Ripard } 31993d2725aSMaxime Ripard 320542acfecSMaxime Ripard if (variant->min_rate) { 321542acfecSMaxime Ripard unsigned long rate; 322542acfecSMaxime Ripard 323542acfecSMaxime Ripard clk_hw_set_rate_range(&data->hw, variant->min_rate, max_rate); 324542acfecSMaxime Ripard 325542acfecSMaxime Ripard rate = raspberrypi_fw_get_rate(&data->hw, 0); 326542acfecSMaxime Ripard if (rate < variant->min_rate) { 327542acfecSMaxime Ripard ret = raspberrypi_fw_set_rate(&data->hw, variant->min_rate, 0); 328542acfecSMaxime Ripard if (ret) 329542acfecSMaxime Ripard return ERR_PTR(ret); 330542acfecSMaxime Ripard } 331542acfecSMaxime Ripard } 332542acfecSMaxime Ripard 33393d2725aSMaxime Ripard return &data->hw; 33493d2725aSMaxime Ripard } 33593d2725aSMaxime Ripard 33693d2725aSMaxime Ripard struct rpi_firmware_get_clocks_response { 33793d2725aSMaxime Ripard u32 parent; 33893d2725aSMaxime Ripard u32 id; 33993d2725aSMaxime Ripard }; 34093d2725aSMaxime Ripard 34193d2725aSMaxime Ripard static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, 34293d2725aSMaxime Ripard struct clk_hw_onecell_data *data) 34393d2725aSMaxime Ripard { 34493d2725aSMaxime Ripard struct rpi_firmware_get_clocks_response *clks; 34593d2725aSMaxime Ripard int ret; 34693d2725aSMaxime Ripard 347bc163555SStefan Wahren /* 348bc163555SStefan Wahren * The firmware doesn't guarantee that the last element of 349bc163555SStefan Wahren * RPI_FIRMWARE_GET_CLOCKS is zeroed. So allocate an additional 350bc163555SStefan Wahren * zero element as sentinel. 351bc163555SStefan Wahren */ 35293d2725aSMaxime Ripard clks = devm_kcalloc(rpi->dev, 353bc163555SStefan Wahren RPI_FIRMWARE_NUM_CLK_ID + 1, sizeof(*clks), 35493d2725aSMaxime Ripard GFP_KERNEL); 35593d2725aSMaxime Ripard if (!clks) 35693d2725aSMaxime Ripard return -ENOMEM; 35793d2725aSMaxime Ripard 35893d2725aSMaxime Ripard ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS, 35993d2725aSMaxime Ripard clks, 36093d2725aSMaxime Ripard sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID); 36193d2725aSMaxime Ripard if (ret) 36293d2725aSMaxime Ripard return ret; 36393d2725aSMaxime Ripard 36493d2725aSMaxime Ripard while (clks->id) { 36512c90f3fSMaxime Ripard struct raspberrypi_clk_variant *variant; 36612c90f3fSMaxime Ripard 36712c90f3fSMaxime Ripard if (clks->id > RPI_FIRMWARE_NUM_CLK_ID) { 368*13b5cf8dSStefan Wahren dev_err(rpi->dev, "Unknown clock id: %u\n", clks->id); 36912c90f3fSMaxime Ripard return -EINVAL; 37012c90f3fSMaxime Ripard } 37112c90f3fSMaxime Ripard 37212c90f3fSMaxime Ripard variant = &raspberrypi_clk_variants[clks->id]; 37312c90f3fSMaxime Ripard if (variant->export) { 37493d2725aSMaxime Ripard struct clk_hw *hw; 37593d2725aSMaxime Ripard 37693d2725aSMaxime Ripard hw = raspberrypi_clk_register(rpi, clks->parent, 37712c90f3fSMaxime Ripard clks->id, variant); 37893d2725aSMaxime Ripard if (IS_ERR(hw)) 37993d2725aSMaxime Ripard return PTR_ERR(hw); 38093d2725aSMaxime Ripard 38193d2725aSMaxime Ripard data->hws[clks->id] = hw; 38293d2725aSMaxime Ripard data->num = clks->id + 1; 38393d2725aSMaxime Ripard } 38412c90f3fSMaxime Ripard 38512c90f3fSMaxime Ripard clks++; 38693d2725aSMaxime Ripard } 38793d2725aSMaxime Ripard 38893d2725aSMaxime Ripard return 0; 38993d2725aSMaxime Ripard } 39093d2725aSMaxime Ripard 3914e85e535SNicolas Saenz Julienne static int raspberrypi_clk_probe(struct platform_device *pdev) 3924e85e535SNicolas Saenz Julienne { 393d4b4f1b6SMaxime Ripard struct clk_hw_onecell_data *clk_data; 3944e85e535SNicolas Saenz Julienne struct device_node *firmware_node; 3954e85e535SNicolas Saenz Julienne struct device *dev = &pdev->dev; 3964e85e535SNicolas Saenz Julienne struct rpi_firmware *firmware; 3974e85e535SNicolas Saenz Julienne struct raspberrypi_clk *rpi; 398d4b4f1b6SMaxime Ripard int ret; 3994e85e535SNicolas Saenz Julienne 400fbac2e77SMaxime Ripard /* 401fbac2e77SMaxime Ripard * We can be probed either through the an old-fashioned 402fbac2e77SMaxime Ripard * platform device registration or through a DT node that is a 403fbac2e77SMaxime Ripard * child of the firmware node. Handle both cases. 404fbac2e77SMaxime Ripard */ 405fbac2e77SMaxime Ripard if (dev->of_node) 406fbac2e77SMaxime Ripard firmware_node = of_get_parent(dev->of_node); 407fbac2e77SMaxime Ripard else 4084e85e535SNicolas Saenz Julienne firmware_node = of_find_compatible_node(NULL, NULL, 4094e85e535SNicolas Saenz Julienne "raspberrypi,bcm2835-firmware"); 4104e85e535SNicolas Saenz Julienne if (!firmware_node) { 4114e85e535SNicolas Saenz Julienne dev_err(dev, "Missing firmware node\n"); 4124e85e535SNicolas Saenz Julienne return -ENOENT; 4134e85e535SNicolas Saenz Julienne } 4144e85e535SNicolas Saenz Julienne 4153c4084f9SNicolas Saenz Julienne firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); 4164e85e535SNicolas Saenz Julienne of_node_put(firmware_node); 4174e85e535SNicolas Saenz Julienne if (!firmware) 4184e85e535SNicolas Saenz Julienne return -EPROBE_DEFER; 4194e85e535SNicolas Saenz Julienne 4204e85e535SNicolas Saenz Julienne rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL); 4214e85e535SNicolas Saenz Julienne if (!rpi) 4224e85e535SNicolas Saenz Julienne return -ENOMEM; 4234e85e535SNicolas Saenz Julienne 4244e85e535SNicolas Saenz Julienne rpi->dev = dev; 4254e85e535SNicolas Saenz Julienne rpi->firmware = firmware; 426e2bb1834SNicolas Saenz Julienne platform_set_drvdata(pdev, rpi); 4274e85e535SNicolas Saenz Julienne 428be1559f6SMaxime Ripard clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, 429be1559f6SMaxime Ripard RPI_FIRMWARE_NUM_CLK_ID), 430d4b4f1b6SMaxime Ripard GFP_KERNEL); 431d4b4f1b6SMaxime Ripard if (!clk_data) 432d4b4f1b6SMaxime Ripard return -ENOMEM; 433d4b4f1b6SMaxime Ripard 43493d2725aSMaxime Ripard ret = raspberrypi_discover_clocks(rpi, clk_data); 43593d2725aSMaxime Ripard if (ret) 43693d2725aSMaxime Ripard return ret; 437d4b4f1b6SMaxime Ripard 438d4b4f1b6SMaxime Ripard ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 439d4b4f1b6SMaxime Ripard clk_data); 440d4b4f1b6SMaxime Ripard if (ret) 441d4b4f1b6SMaxime Ripard return ret; 4424e85e535SNicolas Saenz Julienne 443e2bb1834SNicolas Saenz Julienne rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", 444e2bb1834SNicolas Saenz Julienne -1, NULL, 0); 445e2bb1834SNicolas Saenz Julienne 446e2bb1834SNicolas Saenz Julienne return 0; 447e2bb1834SNicolas Saenz Julienne } 448e2bb1834SNicolas Saenz Julienne 449e2bb1834SNicolas Saenz Julienne static int raspberrypi_clk_remove(struct platform_device *pdev) 450e2bb1834SNicolas Saenz Julienne { 451e2bb1834SNicolas Saenz Julienne struct raspberrypi_clk *rpi = platform_get_drvdata(pdev); 452e2bb1834SNicolas Saenz Julienne 453e2bb1834SNicolas Saenz Julienne platform_device_unregister(rpi->cpufreq); 454e2bb1834SNicolas Saenz Julienne 4554e85e535SNicolas Saenz Julienne return 0; 4564e85e535SNicolas Saenz Julienne } 4574e85e535SNicolas Saenz Julienne 458fbac2e77SMaxime Ripard static const struct of_device_id raspberrypi_clk_match[] = { 459fbac2e77SMaxime Ripard { .compatible = "raspberrypi,firmware-clocks" }, 460fbac2e77SMaxime Ripard { }, 461fbac2e77SMaxime Ripard }; 462fbac2e77SMaxime Ripard MODULE_DEVICE_TABLE(of, raspberrypi_clk_match); 463fbac2e77SMaxime Ripard 4644e85e535SNicolas Saenz Julienne static struct platform_driver raspberrypi_clk_driver = { 4654e85e535SNicolas Saenz Julienne .driver = { 4664e85e535SNicolas Saenz Julienne .name = "raspberrypi-clk", 467fbac2e77SMaxime Ripard .of_match_table = raspberrypi_clk_match, 4684e85e535SNicolas Saenz Julienne }, 4694e85e535SNicolas Saenz Julienne .probe = raspberrypi_clk_probe, 470e2bb1834SNicolas Saenz Julienne .remove = raspberrypi_clk_remove, 4714e85e535SNicolas Saenz Julienne }; 4724e85e535SNicolas Saenz Julienne module_platform_driver(raspberrypi_clk_driver); 4734e85e535SNicolas Saenz Julienne 4744e85e535SNicolas Saenz Julienne MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); 4754e85e535SNicolas Saenz Julienne MODULE_DESCRIPTION("Raspberry Pi firmware clock driver"); 4764e85e535SNicolas Saenz Julienne MODULE_LICENSE("GPL"); 4774e85e535SNicolas Saenz Julienne MODULE_ALIAS("platform:raspberrypi-clk"); 478