1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/device.h> 4 #include <linux/module.h> 5 #include <linux/mutex.h> 6 #include <linux/pm_opp.h> 7 8 #include "tegra-emc-common.h" 9 10 /** 11 * tegra_emc_rate_requests_init() - Initialize EMC rate request tracking 12 * @reqs: struct tegra_emc_rate_requests to initialize. 13 * @dev: EMC device. 14 * 15 * Initializes the rate request tracking state with default state 16 * (no active requests). Must be called before using @reqs with 17 * other functions. 18 */ 19 void tegra_emc_rate_requests_init(struct tegra_emc_rate_requests *reqs, 20 struct device *dev) 21 { 22 unsigned int i; 23 24 mutex_init(&reqs->rate_lock); 25 reqs->dev = dev; 26 27 for (i = 0; i < TEGRA_EMC_RATE_TYPE_MAX; i++) { 28 reqs->requested_rate[i].min_rate = 0; 29 reqs->requested_rate[i].max_rate = ULONG_MAX; 30 } 31 } 32 EXPORT_SYMBOL_GPL(tegra_emc_rate_requests_init); 33 34 /* Caller must hold reqs->rate_lock. */ 35 static int tegra_emc_request_rate(struct tegra_emc_rate_requests *reqs, 36 unsigned long new_min_rate, 37 unsigned long new_max_rate, 38 enum tegra_emc_rate_request_type type) 39 { 40 struct tegra_emc_rate_request *req = reqs->requested_rate; 41 unsigned long min_rate = 0, max_rate = ULONG_MAX; 42 unsigned int i; 43 int err; 44 45 lockdep_assert_held(&reqs->rate_lock); 46 47 /* select minimum and maximum rates among the requested rates */ 48 for (i = 0; i < TEGRA_EMC_RATE_TYPE_MAX; i++, req++) { 49 if (i == type) { 50 min_rate = max(new_min_rate, min_rate); 51 max_rate = min(new_max_rate, max_rate); 52 } else { 53 min_rate = max(req->min_rate, min_rate); 54 max_rate = min(req->max_rate, max_rate); 55 } 56 } 57 58 if (min_rate > max_rate) { 59 dev_err_ratelimited(reqs->dev, "%s: type %u: out of range: %lu %lu\n", 60 __func__, type, min_rate, max_rate); 61 return -ERANGE; 62 } 63 64 /* 65 * EMC rate-changes should go via OPP API because it manages voltage 66 * changes. 67 */ 68 err = dev_pm_opp_set_rate(reqs->dev, min_rate); 69 if (err) 70 return err; 71 72 reqs->requested_rate[type].min_rate = new_min_rate; 73 reqs->requested_rate[type].max_rate = new_max_rate; 74 75 return 0; 76 } 77 78 /** 79 * tegra_emc_set_min_rate() - Update minimum rate request for a request type 80 * @reqs: rate request tracking state 81 * @rate: new minimum rate in Hz requested by @type 82 * @type: type of request 83 * 84 * Records @rate as the new minimum rate request for @type, recalculates target 85 * rate based on all requests and applies new rate through the OPP API. 86 * 87 * Context: Sleeps. Requests to same @reqs are synchronized via mutex. 88 * 89 * Return: 90 * * %0 - success 91 * * %-ERANGE - request would cause minimum rate request to be higher than 92 * maximum rate request 93 * * other - setting new rate failed 94 */ 95 int tegra_emc_set_min_rate(struct tegra_emc_rate_requests *reqs, 96 unsigned long rate, 97 enum tegra_emc_rate_request_type type) 98 { 99 struct tegra_emc_rate_request *req = &reqs->requested_rate[type]; 100 int ret; 101 102 mutex_lock(&reqs->rate_lock); 103 ret = tegra_emc_request_rate(reqs, rate, req->max_rate, type); 104 mutex_unlock(&reqs->rate_lock); 105 106 return ret; 107 } 108 EXPORT_SYMBOL_GPL(tegra_emc_set_min_rate); 109 110 /** 111 * tegra_emc_set_max_rate() - Update maximum rate request for a request type 112 * @reqs: rate request tracking state 113 * @rate: new maximum rate in Hz requested by @type 114 * @type: type of request 115 * 116 * Records @rate as the new maximum rate request for @type, recalculates target 117 * rate based on all requests and applies new rate through the OPP API. 118 * 119 * Context: Sleeps. Requests to same @reqs are synchronized via mutex. 120 * 121 * Return: 122 * * %0 - success 123 * * %-ERANGE - request would cause minimum rate request to be higher than 124 * maximum rate request 125 * * other - setting new rate failed 126 */ 127 int tegra_emc_set_max_rate(struct tegra_emc_rate_requests *reqs, 128 unsigned long rate, 129 enum tegra_emc_rate_request_type type) 130 { 131 struct tegra_emc_rate_request *req = &reqs->requested_rate[type]; 132 int ret; 133 134 mutex_lock(&reqs->rate_lock); 135 ret = tegra_emc_request_rate(reqs, req->min_rate, rate, type); 136 mutex_unlock(&reqs->rate_lock); 137 138 return ret; 139 } 140 EXPORT_SYMBOL_GPL(tegra_emc_set_max_rate); 141 142 MODULE_DESCRIPTION("NVIDIA Tegra EMC common code"); 143 MODULE_LICENSE("GPL"); 144