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