| .. | .. |
|---|
| 13 | 13 | #include <mali_kbase.h> |
|---|
| 14 | 14 | #include <mali_kbase_defs.h> |
|---|
| 15 | 15 | #include <mali_kbase_config.h> |
|---|
| 16 | +#include <backend/gpu/mali_kbase_devfreq.h> |
|---|
| 16 | 17 | #include <backend/gpu/mali_kbase_pm_internal.h> |
|---|
| 17 | 18 | #include <backend/gpu/mali_kbase_pm_defs.h> |
|---|
| 18 | 19 | |
|---|
| 20 | +#if MALI_USE_CSF |
|---|
| 21 | +#include <asm/arch_timer.h> |
|---|
| 22 | +#endif |
|---|
| 23 | + |
|---|
| 24 | +#include <linux/clk.h> |
|---|
| 19 | 25 | #include <linux/pm_runtime.h> |
|---|
| 20 | 26 | #include <linux/suspend.h> |
|---|
| 21 | 27 | #include <linux/of.h> |
|---|
| 22 | 28 | #include <linux/delay.h> |
|---|
| 29 | +#include <linux/mfd/syscon.h> |
|---|
| 23 | 30 | #include <linux/nvmem-consumer.h> |
|---|
| 31 | +#include <linux/regmap.h> |
|---|
| 24 | 32 | #include <linux/soc/rockchip/pvtm.h> |
|---|
| 25 | 33 | #include <linux/thermal.h> |
|---|
| 26 | 34 | #include <soc/rockchip/rockchip_opp_select.h> |
|---|
| 35 | +#include <soc/rockchip/rockchip_system_monitor.h> |
|---|
| 27 | 36 | |
|---|
| 37 | +#include "mali_kbase_config_platform.h" |
|---|
| 28 | 38 | #include "mali_kbase_rk.h" |
|---|
| 39 | + |
|---|
| 40 | +#define POWER_DOWN_FREQ 200000000 |
|---|
| 29 | 41 | |
|---|
| 30 | 42 | /** |
|---|
| 31 | 43 | * @file mali_kbase_config_rk.c |
|---|
| .. | .. |
|---|
| 45 | 57 | */ |
|---|
| 46 | 58 | |
|---|
| 47 | 59 | /*---------------------------------------------------------------------------*/ |
|---|
| 60 | +#ifndef CONFIG_MALI_BIFROST_DEVFREQ |
|---|
| 61 | +static inline void kbase_pm_get_dvfs_metrics(struct kbase_device *kbdev, |
|---|
| 62 | + struct kbasep_pm_metrics *last, |
|---|
| 63 | + struct kbasep_pm_metrics *diff) |
|---|
| 64 | +{ |
|---|
| 65 | +} |
|---|
| 66 | +#endif |
|---|
| 48 | 67 | |
|---|
| 49 | 68 | #ifdef CONFIG_REGULATOR |
|---|
| 50 | 69 | static int rk_pm_enable_regulator(struct kbase_device *kbdev); |
|---|
| .. | .. |
|---|
| 76 | 95 | container_of(to_delayed_work(work), struct rk_context, work); |
|---|
| 77 | 96 | struct kbase_device *kbdev = platform->kbdev; |
|---|
| 78 | 97 | |
|---|
| 98 | + mutex_lock(&platform->lock); |
|---|
| 99 | + |
|---|
| 79 | 100 | if (!platform->is_powered) { |
|---|
| 80 | 101 | D("mali_dev is already powered off."); |
|---|
| 102 | + mutex_unlock(&platform->lock); |
|---|
| 81 | 103 | return; |
|---|
| 82 | 104 | } |
|---|
| 83 | 105 | |
|---|
| 106 | + rockchip_monitor_volt_adjust_lock(kbdev->mdev_info); |
|---|
| 84 | 107 | if (pm_runtime_enabled(kbdev->dev)) { |
|---|
| 85 | 108 | D("to put_sync_suspend mali_dev."); |
|---|
| 86 | 109 | pm_runtime_put_sync_suspend(kbdev->dev); |
|---|
| 87 | 110 | } |
|---|
| 111 | + rockchip_monitor_volt_adjust_unlock(kbdev->mdev_info); |
|---|
| 88 | 112 | |
|---|
| 89 | | - rk_pm_disable_regulator(kbdev); |
|---|
| 113 | + rk_pm_disable_clk(kbdev); |
|---|
| 114 | + |
|---|
| 115 | + if (pm_runtime_suspended(kbdev->dev)) { |
|---|
| 116 | + rk_pm_disable_regulator(kbdev); |
|---|
| 117 | + platform->is_regulator_on = false; |
|---|
| 118 | + } |
|---|
| 90 | 119 | |
|---|
| 91 | 120 | platform->is_powered = false; |
|---|
| 92 | 121 | wake_unlock(&platform->wake_lock); |
|---|
| 122 | + |
|---|
| 123 | + mutex_unlock(&platform->lock); |
|---|
| 93 | 124 | } |
|---|
| 94 | 125 | |
|---|
| 95 | 126 | static int kbase_platform_rk_init(struct kbase_device *kbdev) |
|---|
| .. | .. |
|---|
| 117 | 148 | ret = -ENOMEM; |
|---|
| 118 | 149 | goto err_wq; |
|---|
| 119 | 150 | } |
|---|
| 120 | | - INIT_DELAYED_WORK(&platform->work, rk_pm_power_off_delay_work); |
|---|
| 151 | + INIT_DEFERRABLE_WORK(&platform->work, rk_pm_power_off_delay_work); |
|---|
| 121 | 152 | |
|---|
| 122 | 153 | wake_lock_init(&platform->wake_lock, WAKE_LOCK_SUSPEND, "gpu"); |
|---|
| 123 | 154 | |
|---|
| .. | .. |
|---|
| 131 | 162 | |
|---|
| 132 | 163 | kbdev->platform_context = (void *)platform; |
|---|
| 133 | 164 | pm_runtime_enable(kbdev->dev); |
|---|
| 165 | + |
|---|
| 166 | + mutex_init(&platform->lock); |
|---|
| 134 | 167 | |
|---|
| 135 | 168 | return 0; |
|---|
| 136 | 169 | |
|---|
| .. | .. |
|---|
| 169 | 202 | |
|---|
| 170 | 203 | static int rk_pm_callback_runtime_on(struct kbase_device *kbdev) |
|---|
| 171 | 204 | { |
|---|
| 205 | + struct rockchip_opp_info *opp_info = &kbdev->opp_info; |
|---|
| 206 | + int ret = 0; |
|---|
| 207 | + |
|---|
| 208 | + if (!kbdev->current_nominal_freq) |
|---|
| 209 | + return 0; |
|---|
| 210 | + |
|---|
| 211 | + ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks); |
|---|
| 212 | + if (ret) { |
|---|
| 213 | + dev_err(kbdev->dev, "failed to enable opp clks\n"); |
|---|
| 214 | + return ret; |
|---|
| 215 | + } |
|---|
| 216 | + if (opp_info->data && opp_info->data->set_read_margin) |
|---|
| 217 | + opp_info->data->set_read_margin(kbdev->dev, opp_info, |
|---|
| 218 | + opp_info->target_rm); |
|---|
| 219 | + if (opp_info->scmi_clk) { |
|---|
| 220 | + if (clk_set_rate(opp_info->scmi_clk, |
|---|
| 221 | + kbdev->current_nominal_freq)) |
|---|
| 222 | + dev_err(kbdev->dev, "failed to restore clk rate\n"); |
|---|
| 223 | + } |
|---|
| 224 | + clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks); |
|---|
| 225 | + |
|---|
| 172 | 226 | return 0; |
|---|
| 173 | 227 | } |
|---|
| 174 | 228 | |
|---|
| 175 | 229 | static void rk_pm_callback_runtime_off(struct kbase_device *kbdev) |
|---|
| 176 | 230 | { |
|---|
| 231 | + struct rockchip_opp_info *opp_info = &kbdev->opp_info; |
|---|
| 232 | + |
|---|
| 233 | + if (opp_info->scmi_clk) { |
|---|
| 234 | + if (clk_set_rate(opp_info->scmi_clk, POWER_DOWN_FREQ)) |
|---|
| 235 | + dev_err(kbdev->dev, "failed to set power down rate\n"); |
|---|
| 236 | + } |
|---|
| 237 | + opp_info->current_rm = UINT_MAX; |
|---|
| 177 | 238 | } |
|---|
| 178 | 239 | |
|---|
| 179 | 240 | static int rk_pm_callback_power_on(struct kbase_device *kbdev) |
|---|
| .. | .. |
|---|
| 184 | 245 | |
|---|
| 185 | 246 | cancel_delayed_work_sync(&platform->work); |
|---|
| 186 | 247 | |
|---|
| 187 | | - err = rk_pm_enable_clk(kbdev); |
|---|
| 188 | | - if (err) { |
|---|
| 189 | | - E("failed to enable clk: %d", err); |
|---|
| 190 | | - return err; |
|---|
| 191 | | - } |
|---|
| 248 | + mutex_lock(&platform->lock); |
|---|
| 192 | 249 | |
|---|
| 193 | 250 | if (platform->is_powered) { |
|---|
| 194 | 251 | D("mali_device is already powered."); |
|---|
| 195 | | - return 0; |
|---|
| 252 | + ret = 0; |
|---|
| 253 | + goto out; |
|---|
| 196 | 254 | } |
|---|
| 197 | 255 | |
|---|
| 198 | 256 | /* we must enable vdd_gpu before pd_gpu_in_chip. */ |
|---|
| 199 | | - err = rk_pm_enable_regulator(kbdev); |
|---|
| 200 | | - if (err) { |
|---|
| 201 | | - E("fail to enable regulator, err : %d.", err); |
|---|
| 202 | | - return err; |
|---|
| 257 | + if (!platform->is_regulator_on) { |
|---|
| 258 | + err = rk_pm_enable_regulator(kbdev); |
|---|
| 259 | + if (err) { |
|---|
| 260 | + E("fail to enable regulator, err : %d.", err); |
|---|
| 261 | + ret = err; |
|---|
| 262 | + goto out; |
|---|
| 263 | + } |
|---|
| 264 | + platform->is_regulator_on = true; |
|---|
| 203 | 265 | } |
|---|
| 204 | 266 | |
|---|
| 267 | + err = rk_pm_enable_clk(kbdev); |
|---|
| 268 | + if (err) { |
|---|
| 269 | + E("failed to enable clk: %d", err); |
|---|
| 270 | + ret = err; |
|---|
| 271 | + goto out; |
|---|
| 272 | + } |
|---|
| 273 | + |
|---|
| 274 | + rockchip_monitor_volt_adjust_lock(kbdev->mdev_info); |
|---|
| 205 | 275 | /* 若 mali_dev 的 runtime_pm 是 enabled 的, 则... */ |
|---|
| 206 | 276 | if (pm_runtime_enabled(kbdev->dev)) { |
|---|
| 207 | 277 | D("to resume mali_dev syncly."); |
|---|
| .. | .. |
|---|
| 211 | 281 | err = pm_runtime_get_sync(kbdev->dev); |
|---|
| 212 | 282 | if (err < 0) { |
|---|
| 213 | 283 | E("failed to runtime resume device: %d.", err); |
|---|
| 214 | | - return err; |
|---|
| 284 | + ret = err; |
|---|
| 285 | + goto out; |
|---|
| 215 | 286 | } else if (err == 1) { /* runtime_pm_status is still active */ |
|---|
| 216 | 287 | D("chip has NOT been powered off, no need to re-init."); |
|---|
| 217 | 288 | ret = 0; |
|---|
| 218 | 289 | } |
|---|
| 219 | 290 | } |
|---|
| 291 | + rockchip_monitor_volt_adjust_unlock(kbdev->mdev_info); |
|---|
| 220 | 292 | |
|---|
| 221 | 293 | platform->is_powered = true; |
|---|
| 222 | 294 | wake_lock(&platform->wake_lock); |
|---|
| 223 | 295 | |
|---|
| 296 | +out: |
|---|
| 297 | + mutex_unlock(&platform->lock); |
|---|
| 224 | 298 | return ret; |
|---|
| 225 | 299 | } |
|---|
| 226 | 300 | |
|---|
| .. | .. |
|---|
| 228 | 302 | { |
|---|
| 229 | 303 | struct rk_context *platform = get_rk_context(kbdev); |
|---|
| 230 | 304 | |
|---|
| 231 | | - rk_pm_disable_clk(kbdev); |
|---|
| 305 | + D("enter"); |
|---|
| 306 | + |
|---|
| 232 | 307 | queue_delayed_work(platform->power_off_wq, &platform->work, |
|---|
| 233 | 308 | msecs_to_jiffies(platform->delay_ms)); |
|---|
| 234 | 309 | } |
|---|
| 235 | 310 | |
|---|
| 236 | | -int rk_kbase_device_runtime_init(struct kbase_device *kbdev) |
|---|
| 311 | +static int rk_kbase_device_runtime_init(struct kbase_device *kbdev) |
|---|
| 237 | 312 | { |
|---|
| 238 | 313 | return 0; |
|---|
| 239 | 314 | } |
|---|
| 240 | 315 | |
|---|
| 241 | | -void rk_kbase_device_runtime_disable(struct kbase_device *kbdev) |
|---|
| 316 | +static void rk_kbase_device_runtime_disable(struct kbase_device *kbdev) |
|---|
| 242 | 317 | { |
|---|
| 243 | 318 | } |
|---|
| 244 | 319 | |
|---|
| .. | .. |
|---|
| 257 | 332 | .power_runtime_off_callback = NULL, |
|---|
| 258 | 333 | #endif /* CONFIG_PM */ |
|---|
| 259 | 334 | }; |
|---|
| 260 | | - |
|---|
| 261 | | -int kbase_platform_early_init(void) |
|---|
| 262 | | -{ |
|---|
| 263 | | - /* Nothing needed at this stage */ |
|---|
| 264 | | - return 0; |
|---|
| 265 | | -} |
|---|
| 266 | | - |
|---|
| 267 | | -/*---------------------------------------------------------------------------*/ |
|---|
| 268 | | - |
|---|
| 269 | | -void kbase_platform_rk_shutdown(struct kbase_device *kbdev) |
|---|
| 270 | | -{ |
|---|
| 271 | | - I("to make vdd_gpu enabled for turning off pd_gpu in pm_framework."); |
|---|
| 272 | | - rk_pm_enable_regulator(kbdev); |
|---|
| 273 | | -} |
|---|
| 274 | 335 | |
|---|
| 275 | 336 | /*---------------------------------------------------------------------------*/ |
|---|
| 276 | 337 | |
|---|
| .. | .. |
|---|
| 398 | 459 | unsigned long period_in_us = platform->utilisation_period * 1000; |
|---|
| 399 | 460 | u32 utilisation; |
|---|
| 400 | 461 | struct kbasep_pm_metrics metrics_when_start; |
|---|
| 401 | | - struct kbasep_pm_metrics metrics_diff; /* between start and end. */ |
|---|
| 462 | + struct kbasep_pm_metrics metrics_diff = {}; /* between start and end. */ |
|---|
| 402 | 463 | u32 total_time = 0; |
|---|
| 403 | 464 | u32 busy_time = 0; |
|---|
| 404 | 465 | |
|---|
| .. | .. |
|---|
| 452 | 513 | device_remove_file(dev, &dev_attr_utilisation); |
|---|
| 453 | 514 | } |
|---|
| 454 | 515 | |
|---|
| 516 | +static int rk3588_gpu_get_soc_info(struct device *dev, struct device_node *np, |
|---|
| 517 | + int *bin, int *process) |
|---|
| 518 | +{ |
|---|
| 519 | + int ret = 0; |
|---|
| 520 | + u8 value = 0; |
|---|
| 521 | + |
|---|
| 522 | + if (!bin) |
|---|
| 523 | + return 0; |
|---|
| 524 | + |
|---|
| 525 | + if (of_property_match_string(np, "nvmem-cell-names", |
|---|
| 526 | + "specification_serial_number") >= 0) { |
|---|
| 527 | + ret = rockchip_nvmem_cell_read_u8(np, |
|---|
| 528 | + "specification_serial_number", |
|---|
| 529 | + &value); |
|---|
| 530 | + if (ret) { |
|---|
| 531 | + dev_err(dev, |
|---|
| 532 | + "Failed to get specification_serial_number\n"); |
|---|
| 533 | + return ret; |
|---|
| 534 | + } |
|---|
| 535 | + /* RK3588M */ |
|---|
| 536 | + if (value == 0xd) |
|---|
| 537 | + *bin = 1; |
|---|
| 538 | + /* RK3588J */ |
|---|
| 539 | + else if (value == 0xa) |
|---|
| 540 | + *bin = 2; |
|---|
| 541 | + } |
|---|
| 542 | + if (*bin < 0) |
|---|
| 543 | + *bin = 0; |
|---|
| 544 | + dev_info(dev, "bin=%d\n", *bin); |
|---|
| 545 | + |
|---|
| 546 | + return ret; |
|---|
| 547 | +} |
|---|
| 548 | + |
|---|
| 549 | +static int rk3588_gpu_set_soc_info(struct device *dev, struct device_node *np, |
|---|
| 550 | + int bin, int process, int volt_sel) |
|---|
| 551 | +{ |
|---|
| 552 | + struct opp_table *opp_table; |
|---|
| 553 | + u32 supported_hw[2]; |
|---|
| 554 | + |
|---|
| 555 | + if (volt_sel < 0) |
|---|
| 556 | + return 0; |
|---|
| 557 | + if (bin < 0) |
|---|
| 558 | + bin = 0; |
|---|
| 559 | + |
|---|
| 560 | + if (!of_property_read_bool(np, "rockchip,supported-hw")) |
|---|
| 561 | + return 0; |
|---|
| 562 | + |
|---|
| 563 | + /* SoC Version */ |
|---|
| 564 | + supported_hw[0] = BIT(bin); |
|---|
| 565 | + /* Speed Grade */ |
|---|
| 566 | + supported_hw[1] = BIT(volt_sel); |
|---|
| 567 | + opp_table = dev_pm_opp_set_supported_hw(dev, supported_hw, 2); |
|---|
| 568 | + if (IS_ERR(opp_table)) { |
|---|
| 569 | + dev_err(dev, "failed to set supported opp\n"); |
|---|
| 570 | + return PTR_ERR(opp_table); |
|---|
| 571 | + } |
|---|
| 572 | + |
|---|
| 573 | + return 0; |
|---|
| 574 | +} |
|---|
| 575 | + |
|---|
| 576 | +static int rk3588_gpu_set_read_margin(struct device *dev, |
|---|
| 577 | + struct rockchip_opp_info *opp_info, |
|---|
| 578 | + u32 rm) |
|---|
| 579 | +{ |
|---|
| 580 | + int ret = 0; |
|---|
| 581 | + u32 val; |
|---|
| 582 | + |
|---|
| 583 | + if (!opp_info->grf || !opp_info->volt_rm_tbl) |
|---|
| 584 | + return 0; |
|---|
| 585 | + if (rm == opp_info->current_rm || rm == UINT_MAX) |
|---|
| 586 | + return 0; |
|---|
| 587 | + |
|---|
| 588 | + dev_dbg(dev, "set rm to %d\n", rm); |
|---|
| 589 | + |
|---|
| 590 | + ret = regmap_read(opp_info->grf, 0x24, &val); |
|---|
| 591 | + if (ret < 0) { |
|---|
| 592 | + dev_err(dev, "failed to get rm from 0x24\n"); |
|---|
| 593 | + return ret; |
|---|
| 594 | + } |
|---|
| 595 | + val &= ~0x1c; |
|---|
| 596 | + regmap_write(opp_info->grf, 0x24, val | (rm << 2)); |
|---|
| 597 | + |
|---|
| 598 | + ret = regmap_read(opp_info->grf, 0x28, &val); |
|---|
| 599 | + if (ret < 0) { |
|---|
| 600 | + dev_err(dev, "failed to get rm from 0x28\n"); |
|---|
| 601 | + return ret; |
|---|
| 602 | + } |
|---|
| 603 | + val &= ~0x1c; |
|---|
| 604 | + regmap_write(opp_info->grf, 0x28, val | (rm << 2)); |
|---|
| 605 | + |
|---|
| 606 | + opp_info->current_rm = rm; |
|---|
| 607 | + |
|---|
| 608 | + return 0; |
|---|
| 609 | +} |
|---|
| 610 | + |
|---|
| 611 | +static const struct rockchip_opp_data rk3588_gpu_opp_data = { |
|---|
| 612 | + .get_soc_info = rk3588_gpu_get_soc_info, |
|---|
| 613 | + .set_soc_info = rk3588_gpu_set_soc_info, |
|---|
| 614 | + .set_read_margin = rk3588_gpu_set_read_margin, |
|---|
| 615 | +}; |
|---|
| 616 | + |
|---|
| 617 | +static const struct of_device_id rockchip_mali_of_match[] = { |
|---|
| 618 | + { |
|---|
| 619 | + .compatible = "rockchip,rk3588", |
|---|
| 620 | + .data = (void *)&rk3588_gpu_opp_data, |
|---|
| 621 | + }, |
|---|
| 622 | + {}, |
|---|
| 623 | +}; |
|---|
| 624 | + |
|---|
| 455 | 625 | int kbase_platform_rk_init_opp_table(struct kbase_device *kbdev) |
|---|
| 456 | 626 | { |
|---|
| 457 | | - return rockchip_init_opp_table(kbdev->dev, NULL, |
|---|
| 627 | + rockchip_get_opp_data(rockchip_mali_of_match, &kbdev->opp_info); |
|---|
| 628 | + |
|---|
| 629 | + return rockchip_init_opp_table(kbdev->dev, &kbdev->opp_info, |
|---|
| 458 | 630 | "gpu_leakage", "mali"); |
|---|
| 459 | 631 | } |
|---|
| 632 | + |
|---|
| 633 | +int kbase_platform_rk_enable_regulator(struct kbase_device *kbdev) |
|---|
| 634 | +{ |
|---|
| 635 | + struct rk_context *platform = get_rk_context(kbdev); |
|---|
| 636 | + int err = 0; |
|---|
| 637 | + |
|---|
| 638 | + if (!platform->is_regulator_on) { |
|---|
| 639 | + err = rk_pm_enable_regulator(kbdev); |
|---|
| 640 | + if (err) { |
|---|
| 641 | + E("fail to enable regulator, err : %d.", err); |
|---|
| 642 | + return err; |
|---|
| 643 | + } |
|---|
| 644 | + platform->is_regulator_on = true; |
|---|
| 645 | + } |
|---|
| 646 | + |
|---|
| 647 | + return 0; |
|---|
| 648 | +} |
|---|
| 649 | + |
|---|
| 650 | +/*---------------------------------------------------------------------------*/ |
|---|
| 651 | + |
|---|
| 652 | +static void *enumerate_gpu_clk(struct kbase_device *kbdev, |
|---|
| 653 | + unsigned int index) |
|---|
| 654 | +{ |
|---|
| 655 | + if (index >= kbdev->nr_clocks) |
|---|
| 656 | + return NULL; |
|---|
| 657 | + |
|---|
| 658 | + return kbdev->clocks[index]; |
|---|
| 659 | +} |
|---|
| 660 | + |
|---|
| 661 | +static unsigned long get_gpu_clk_rate(struct kbase_device *kbdev, |
|---|
| 662 | + void *gpu_clk_handle) |
|---|
| 663 | +{ |
|---|
| 664 | + return clk_get_rate((struct clk *)gpu_clk_handle); |
|---|
| 665 | +} |
|---|
| 666 | + |
|---|
| 667 | +static int gpu_clk_notifier_register(struct kbase_device *kbdev, |
|---|
| 668 | + void *gpu_clk_handle, struct notifier_block *nb) |
|---|
| 669 | +{ |
|---|
| 670 | + compiletime_assert(offsetof(struct clk_notifier_data, clk) == |
|---|
| 671 | + offsetof(struct kbase_gpu_clk_notifier_data, gpu_clk_handle), |
|---|
| 672 | + "mismatch in the offset of clk member"); |
|---|
| 673 | + |
|---|
| 674 | + compiletime_assert(sizeof(((struct clk_notifier_data *)0)->clk) == |
|---|
| 675 | + sizeof(((struct kbase_gpu_clk_notifier_data *)0)->gpu_clk_handle), |
|---|
| 676 | + "mismatch in the size of clk member"); |
|---|
| 677 | + |
|---|
| 678 | + return clk_notifier_register((struct clk *)gpu_clk_handle, nb); |
|---|
| 679 | +} |
|---|
| 680 | + |
|---|
| 681 | +static void gpu_clk_notifier_unregister(struct kbase_device *kbdev, |
|---|
| 682 | + void *gpu_clk_handle, struct notifier_block *nb) |
|---|
| 683 | +{ |
|---|
| 684 | + clk_notifier_unregister((struct clk *)gpu_clk_handle, nb); |
|---|
| 685 | +} |
|---|
| 686 | + |
|---|
| 687 | +struct kbase_clk_rate_trace_op_conf clk_rate_trace_ops = { |
|---|
| 688 | + .get_gpu_clk_rate = get_gpu_clk_rate, |
|---|
| 689 | + .enumerate_gpu_clk = enumerate_gpu_clk, |
|---|
| 690 | + .gpu_clk_notifier_register = gpu_clk_notifier_register, |
|---|
| 691 | + .gpu_clk_notifier_unregister = gpu_clk_notifier_unregister, |
|---|
| 692 | +}; |
|---|