summaryrefslogtreecommitdiffstats
path: root/include/linux/platform/tegra/emc_bwmgr.h
blob: 64d6f6f899515fadfce7c74330e68d5d2435a64d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
/**
 * Copyright (c) 2015-2018, NVIDIA CORPORATION. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 */

#ifndef __EMC_BWMGR_H
#define __EMC_BWMGR_H

#include <linux/clk.h>
#include <linux/device.h>
#include <linux/of_address.h>
#include <linux/platform/tegra/iso_client.h>

/* keep in sync with tegra_bwmgr_client_names */
enum tegra_bwmgr_client_id {
	TEGRA_BWMGR_CLIENT_CPU_CLUSTER_0,
	TEGRA_BWMGR_CLIENT_CPU_CLUSTER_1,
	TEGRA_BWMGR_CLIENT_CPU_CLUSTER_2,
	TEGRA_BWMGR_CLIENT_CPU_CLUSTER_3,
	TEGRA_BWMGR_CLIENT_DISP0,
	TEGRA_BWMGR_CLIENT_DISP1,
	TEGRA_BWMGR_CLIENT_DISP2,
	TEGRA_BWMGR_CLIENT_DISP1_LA_EMC,
	TEGRA_BWMGR_CLIENT_DISP2_LA_EMC,
	TEGRA_BWMGR_CLIENT_USBD,
	TEGRA_BWMGR_CLIENT_XHCI,
	TEGRA_BWMGR_CLIENT_SDMMC1,
	TEGRA_BWMGR_CLIENT_SDMMC2,
	TEGRA_BWMGR_CLIENT_SDMMC3,
	TEGRA_BWMGR_CLIENT_SDMMC4,
	TEGRA_BWMGR_CLIENT_MON,
	TEGRA_BWMGR_CLIENT_GPU,
	TEGRA_BWMGR_CLIENT_MSENC,
	TEGRA_BWMGR_CLIENT_NVENC1,
	TEGRA_BWMGR_CLIENT_NVJPG,
	TEGRA_BWMGR_CLIENT_NVDEC,
	TEGRA_BWMGR_CLIENT_NVDEC1,
	TEGRA_BWMGR_CLIENT_TSEC,
	TEGRA_BWMGR_CLIENT_TSECB,
	TEGRA_BWMGR_CLIENT_VI,
	TEGRA_BWMGR_CLIENT_ISPA,
	TEGRA_BWMGR_CLIENT_ISPB,
	TEGRA_BWMGR_CLIENT_CAMERA,
	TEGRA_BWMGR_CLIENT_CAMERA_NON_ISO,
	TEGRA_BWMGR_CLIENT_ISOMGR,
	TEGRA_BWMGR_CLIENT_THERMAL_CAP,
	TEGRA_BWMGR_CLIENT_VIC,
	TEGRA_BWMGR_CLIENT_APE_ADSP,
	TEGRA_BWMGR_CLIENT_APE_ADMA,
	TEGRA_BWMGR_CLIENT_PCIE,
	TEGRA_BWMGR_CLIENT_PCIE_1,
	TEGRA_BWMGR_CLIENT_PCIE_2,
	TEGRA_BWMGR_CLIENT_PCIE_3,
	TEGRA_BWMGR_CLIENT_PCIE_4,
	TEGRA_BWMGR_CLIENT_PCIE_5,
	TEGRA_BWMGR_CLIENT_BBC_0,
	TEGRA_BWMGR_CLIENT_EQOS,
	TEGRA_BWMGR_CLIENT_SE0,
	TEGRA_BWMGR_CLIENT_SE1,
	TEGRA_BWMGR_CLIENT_SE2,
	TEGRA_BWMGR_CLIENT_SE3,
	TEGRA_BWMGR_CLIENT_SE4,
	TEGRA_BWMGR_CLIENT_PMQOS,
	TEGRA_BWMGR_CLIENT_NVPMODEL,
	TEGRA_BWMGR_CLIENT_DEBUG,
	TEGRA_BWMGR_CLIENT_COUNT /* Should always be last */
};

enum tegra_bwmgr_request_type {
	TEGRA_BWMGR_SET_EMC_FLOOR, /* lower bound */
	TEGRA_BWMGR_SET_EMC_CAP, /* upper bound */
	TEGRA_BWMGR_SET_EMC_ISO_CAP, /* upper bound that affects ISO Bw */
	TEGRA_BWMGR_SET_EMC_SHARED_BW, /* shared bw request */
	TEGRA_BWMGR_SET_EMC_SHARED_BW_ISO, /* for use by ISO Mgr only */
	TEGRA_BWMGR_SET_EMC_REQ_COUNT /* Should always be last */
};

enum bwmgr_dram_types {
	DRAM_TYPE_NONE,
	DRAM_TYPE_LPDDR4_16CH_ECC,
	DRAM_TYPE_LPDDR4_8CH_ECC,
	DRAM_TYPE_LPDDR4_4CH_ECC,
	DRAM_TYPE_LPDDR4_2CH_ECC,
	DRAM_TYPE_LPDDR4_16CH,
	DRAM_TYPE_LPDDR4_8CH,
	DRAM_TYPE_LPDDR4_4CH,
	DRAM_TYPE_LPDDR4_2CH,
	DRAM_TYPE_LPDDR3_2CH,
	DRAM_TYPE_DDR3_2CH
};

extern u8 bwmgr_dram_efficiency;
extern u8 bwmgr_dram_num_channels;
/* flag to determine supported memory and channel configuration */
extern u8 bwmgr_dram_config_supported;
extern u32 *bwmgr_dram_iso_eff_table;
extern u32 *bwmgr_dram_noniso_eff_table;
extern u32 *bwmgr_max_nvdis_bw_reqd;
extern u32 *bwmgr_max_vi_bw_reqd;
extern int *bwmgr_slope;
extern u32 *bwmgr_vi_bw_reqd_offset;
extern int bwmgr_iso_bw_percentage;
extern enum bwmgr_dram_types bwmgr_dram_type;
extern int emc_to_dram_freq_factor;

struct tegra_bwmgr_client;

struct bwmgr_ops {
	unsigned long (*freq_to_bw)(unsigned long freq);
	unsigned long (*bw_to_freq)(unsigned long bw);
	u32 (*dvfs_latency)(u32 ufreq);
	unsigned long (*bwmgr_apply_efficiency)(
		unsigned long total_bw, unsigned long iso_bw,
		unsigned long max_rate, u64 usage_flags,
		unsigned long *iso_bw_min, unsigned long iso_bw_nvdis,
		unsigned long iso_bw_vi);
	unsigned long (*get_best_iso_freq)(long iso_bw,
		long iso_bw_nvdis, long iso_bw_vi);
	void (*update_efficiency)(unsigned long dram_refresh_rate);
	u32 (*get_max_iso_bw)(enum tegra_iso_client client);
};

struct bwmgr_ops *bwmgr_eff_init_t21x(void);
struct bwmgr_ops *bwmgr_eff_init_t18x(void);
struct bwmgr_ops *bwmgr_eff_init_t19x(void);

#if defined(CONFIG_TEGRA_BWMGR)
/**
 * tegra_bwmgr_register - register an EMC Bandwidth Manager client.
 *			  Also see tegra_bwmgr_unregister().
 * @client      client id from tegra_bwmgr_client_id
 *
 * Returns a valid handle on successful registration, NULL on error.
 */
struct tegra_bwmgr_client *tegra_bwmgr_register(
		enum tegra_bwmgr_client_id client);

/**
 * tegra_bwmgr_unregister - unregister an EMC Bandwidth Manager client.
 *			    Callers should match register/unregister calls.
 *			    Persistence of old requests across
 *			    register/unregister calls is undefined.
 *			    Also see tegra_bwmgr_set_emc()
 *
 * @handle      handle acquired during tegra_bwmgr_register
 */
void tegra_bwmgr_unregister(struct tegra_bwmgr_client *handle);

/**
 * tegra_bwmgr_get_dram_num_channels - get the number of DRAM channels
 *
 * Returns the number of DRAM channels that are configured on the underlying
 * platform.
 */
u8 tegra_bwmgr_get_dram_num_channels(void);

/**
 * tegra_bwmgr_get_emc_rate - get the current EMC rate.
 *
 * Returns current memory clock rate in Hz.
 */
unsigned long tegra_bwmgr_get_emc_rate(void);

/**
 * tegra_bwmgr_get_max_emc_rate - get the max EMC rate.
 *
 * Returns the max memory clock rate in Hz.
 */
unsigned long tegra_bwmgr_get_max_emc_rate(void);

/**
 * tegra_bwmgr_get_core_emc_rate - get the actual emc frequency calculated
 *			using the dram frequency and emc_to_dram
 *			conversion factor.
 *
 * Returns the core emc rate in Hz.
 */
unsigned long tegra_bwmgr_get_core_emc_rate(void);

/**
 * tegra_bwmgr_round_rate - round up to next EMC rate which can be provided
 *
 * @bw		Input rate
 *
 * Returns the next higher rate from the Input rate that EMC can run at.
 */
unsigned long tegra_bwmgr_round_rate(unsigned long bw);

/**
 * tegra_bwmgr_set_emc - request to bwmgr to set an EMC rate parameter.
 *			 Actual clock rate depends on aggregation of
 *			 requests by all clients. If needed, use
 *			 tegra_bwmgr_get_emc_rate() to get the rate after
 *			 a tegra_bwmgr_set_emc() call.
 *
 *			 Call tegra_bwmgr_set_emc() with same request type and
 *			 val = 0 to clear request.
 *
 * @handle      handle acquired during tegra_bwmgr_register
 * @val         value to be set in Hz, 0 to clear old request of the same type
 * @req         chosen type from tegra_bwmgr_request_type
 *
 * Returns success (0) or negative errno.
 */
int tegra_bwmgr_set_emc(struct tegra_bwmgr_client *handle, unsigned long val,
		enum tegra_bwmgr_request_type req);

/**
 * tegra_bwmgr_get_client_info - outputs the value previously set with
 *                       tegra_bwmgr_set_emc or 0 if no value has been set.
 *
 * @handle      handle acquired during tegra_bwmgr_register
 * @out_val     bandwidth value in Hz
 * @req         chosen type from tegra_bwmgr_request_type
 *
 * Returns success (0) or negative errno.
 */
int tegra_bwmgr_get_client_info(struct tegra_bwmgr_client *handle,
		unsigned long *out_val,
		enum tegra_bwmgr_request_type req);

/**
 * tegra_bwmgr_notifier_register - register a notifier callback when
 *		emc rate changes. Must be called from non-atomic
 *		context. The callback must not call any bwmgr API.
 * @nb		linux notifier block
 *
 * Returns success (0) or negative errno.
 */
int tegra_bwmgr_notifier_register(struct notifier_block *nb);

/**
 * tegra_bwmgr_notifier_unregister - unregister a notifier callback.
 * @nb		linux notifier block
 *
 * Returns success (0) or negative errno.
 */
int tegra_bwmgr_notifier_unregister(struct notifier_block *nb);

/*
 * Initialize bwmgr.
 * This api would be called by .init_machine during boot.
 * bwmgr clients, don't call this api.
 */
int __init bwmgr_init(void);

void __exit bwmgr_exit(void);

/*
 * Initialize pmqos bwmgr code which registers pmqos as bwmgr client and
 * registers a notifier which gets called on update to PMQOS_EMC_FREQ_MIN.
 */
int __init pmqos_bwmgr_init(void);

#else /* CONFIG_TEGRA_BWMGR */

static inline struct tegra_bwmgr_client *tegra_bwmgr_register(
		enum tegra_bwmgr_client_id client_id)
{
	static int i;
	/* return a dummy handle to allow client to function
	 * as if bwmgr were enabled.
	 */
	return (struct tegra_bwmgr_client *) &i;
}

static inline void tegra_bwmgr_unregister(struct tegra_bwmgr_client *handle) {}

static inline int bwmgr_init(void)
{
	return 0;
}

static inline void bwmgr_exit(void) {}

static inline u8 tegra_bwmgr_get_dram_num_channels(void)
{
	return 0;
}

static inline unsigned long tegra_bwmgr_get_emc_rate(void)
{
	static struct clk *bwmgr_emc_clk;
	struct device_node *dn;

	if (!bwmgr_emc_clk) {
		dn = of_find_compatible_node(NULL, NULL, "nvidia,bwmgr");
		if (dn == NULL) {
			pr_err("bwmgr: dt node not found.\n");
			return 0;
		}

		bwmgr_emc_clk = of_clk_get(dn, 0);
		if (IS_ERR_OR_NULL(bwmgr_emc_clk)) {
			pr_err("bwmgr: couldn't find emc clock.\n");
			bwmgr_emc_clk = NULL;
			WARN_ON(true);
			return 0;
		}
	}

	return clk_get_rate(bwmgr_emc_clk);
}

static inline unsigned long tegra_bwmgr_get_max_emc_rate(void)
{
	static struct clk *bwmgr_emc_clk;
	struct device_node *dn;

	if (!bwmgr_emc_clk) {
		dn = of_find_compatible_node(NULL, NULL, "nvidia,bwmgr");
		if (dn == NULL) {
			pr_err("bwmgr: dt node not found.\n");
			return 0;
		}

		bwmgr_emc_clk = of_clk_get(dn, 0);
		if (IS_ERR_OR_NULL(bwmgr_emc_clk)) {
			pr_err("bwmgr: couldn't find emc clock.\n");
			bwmgr_emc_clk = NULL;
			WARN_ON(true);
			return 0;
		}
	}

	/* Use LONG_MAX as clk_round_rate treats rate argument as signed */
	return clk_round_rate(bwmgr_emc_clk, LONG_MAX);
}

static inline unsigned long tegra_bwmgr_get_core_emc_rate(void)
{
	return 0;
}
static inline unsigned long tegra_bwmgr_round_rate(unsigned long bw)
{
	static struct clk *bwmgr_emc_clk;
	struct device_node *dn;

	if (!bwmgr_emc_clk) {
		dn = of_find_compatible_node(NULL, NULL, "nvidia,bwmgr");
		if (dn == NULL) {
			pr_err("bwmgr: dt node not found.\n");
			return 0;
		}

		bwmgr_emc_clk = of_clk_get(dn, 0);
		if (IS_ERR_OR_NULL(bwmgr_emc_clk)) {
			pr_err("bwmgr: couldn't find emc clock.\n");
			bwmgr_emc_clk = NULL;
			WARN_ON(true);
			return 0;
		}
	}

	return clk_round_rate(bwmgr_emc_clk, bw);
}

static inline int tegra_bwmgr_set_emc(struct tegra_bwmgr_client *handle,
		unsigned long val, enum tegra_bwmgr_request_type req)
{
	return 0;
}

static inline int tegra_bwmgr_get_client_info(struct tegra_bwmgr_client *handle,
		unsigned long *out_val,
		enum tegra_bwmgr_request_type req)
{
	if (!out_val)
		return -EINVAL;
	*out_val = 0;
	return 0;
}

static inline int tegra_bwmgr_notifier_register(struct notifier_block *nb)
{
	return 0;
}

static inline int tegra_bwmgr_notifier_unregister(struct notifier_block *nb)
{
	return 0;
}

#endif /* CONFIG_TEGRA_BWMGR */
#endif /* __EMC_BWMGR_H */