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
|
/*
* Copyright (C) 2010-2012 Google, Inc.
* Copyright (C) 2013-2018, NVIDIA Corporation. All rights reserved.
*
* Author:
* Erik Gilling <konkers@google.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 __MACH_TEGRA_MC_H
#define __MACH_TEGRA_MC_H
#include <linux/platform/tegra/tegra_mc.h>
#define MC_MAX_INTR_COUNT 32
#define MC_MAX_CHANNELS 16
#define MC_MAX_MSSNVLINK_HUBS 4
#define MC_BROADCAST_CHANNEL -1
extern int mc_channels;
extern int mc_err_channel;
extern int mc_intstatus_reg;
extern unsigned int mssnvlink_hubs;
struct mc_client {
const char *name;
const char *swgroup;
const int swgid;
unsigned int intr_counts[MC_MAX_INTR_COUNT];
};
extern void __iomem *mc;
extern void __iomem *mc_regs[MC_MAX_CHANNELS];
extern void __iomem *mssnvlink_regs[MC_MAX_MSSNVLINK_HUBS];
#include <linux/io.h>
#include <linux/debugfs.h>
#include <soc/tegra/chip-id.h>
/**
* Check if the MC has more than 1 channel.
*/
static inline int mc_multi_channel(void)
{
return mc_channels > 1;
}
/**
* Read from the MC.
*
* @idx The MC channel to read from.
* @reg The offset of the register to read.
*
* Read from the specified MC channel: 0 -> MC0, 1 -> MC1, etc. If @idx
* corresponds to a non-existent channel then 0 is returned.
*/
static inline u32 __mc_readl(int idx, u32 reg)
{
if (WARN(!mc, "Read before MC init'ed"))
return 0;
if ((idx != MC_BROADCAST_CHANNEL && idx < 0) || idx > mc_channels)
return 0;
if (idx == MC_BROADCAST_CHANNEL)
return readl(mc + reg);
else
return readl(mc_regs[idx] + reg);
}
/**
* Write to the MC.
*
* @idx The MC channel to write to.
* @val Value to write.
* @reg The offset of the register to write.
*
* Write to the specified MC channel: 0 -> MC0, 1 -> MC1, etc. For writes there
* is a special channel, %MC_BROADCAST_CHANNEL, which writes to all channels. If
* @idx corresponds to a non-existent channel then the write is dropped.
*/
static inline void __mc_writel(int idx, u32 val, u32 reg)
{
if (WARN(!mc, "Write before MC init'ed"))
return;
if ((idx != MC_BROADCAST_CHANNEL && idx < 0) ||
idx > mc_channels)
return;
if (idx == MC_BROADCAST_CHANNEL)
writel(val, mc + reg);
else
writel(val, mc_regs[idx] + reg);
}
static inline u32 __mc_raw_readl(int idx, u32 reg)
{
if (WARN(!mc, "Read before MC init'ed"))
return 0;
if ((idx != MC_BROADCAST_CHANNEL && idx < 0) || idx > mc_channels)
return 0;
if (idx == MC_BROADCAST_CHANNEL)
return __raw_readl(mc + reg);
else
return __raw_readl(mc_regs[idx] + reg);
}
static inline void __mc_raw_writel(int idx, u32 val, u32 reg)
{
if (WARN(!mc, "Write before MC init'ed"))
return;
if ((idx != MC_BROADCAST_CHANNEL && idx < 0) ||
idx > mc_channels)
return;
if (idx == MC_BROADCAST_CHANNEL)
__raw_writel(val, mc + reg);
else
__raw_writel(val, mc_regs[idx] + reg);
}
#define mc_readl(reg) __mc_readl(MC_BROADCAST_CHANNEL, reg)
#define mc_writel(val, reg) __mc_writel(MC_BROADCAST_CHANNEL, val, reg)
/**
* Read from the MSSNVLINK hub.
*
* @idx The mssnvlink hub ID
* @reg The register offset
*
* Read from the specified MSSNVLINK hub. Reads from
* non-existent hubs return 0.
*/
static inline u32 mssnvlink_readl(unsigned int idx, u32 reg)
{
if (mssnvlink_hubs == UINT_MAX)
return 0;
if (idx >= mssnvlink_hubs) {
WARN(1, "mssnvlink read: invalid hub ID - %u\n", idx);
return 0;
}
if (WARN(!mssnvlink_regs[idx], "Read before MSSNVLINK is initialized."))
return 0;
return readl(mssnvlink_regs[idx] + reg);
}
/**
* Write to the MSSNVLINK hub.
*
* @idx ID of MSSNVLINK hub.
* @val Value to write.
* @reg Register offset to write.
*
* Write to the specified MSSNVLINK hub. Writes to
* non-existent hubs are dropped.
*/
static inline void mssnvlink_writel(unsigned int idx, u32 val, u32 reg)
{
if (mssnvlink_hubs == UINT_MAX)
return;
if (idx >= mssnvlink_hubs) {
WARN(1, "mssnvlink write: invalid hub ID - %u\n", idx);
return;
}
if (WARN(!mssnvlink_regs[idx], "Write before MSSNVLINK is initialized."))
return;
writel(val, mssnvlink_regs[idx] + reg);
}
unsigned long tegra_emc_bw_to_freq_req(unsigned long bw);
unsigned long tegra_emc_freq_req_to_bw(unsigned long freq);
/* API to get freqency switch latency at given MC freq.
* freq_khz: Frequncy in KHz.
* retruns latency in microseconds.
*/
static inline unsigned tegra_emc_dvfs_latency(unsigned int freq_khz)
{
/* The latency data is not available based on freq.
* H/W expects it to be around 3 to 4us.
*/
return 4;
}
/*
* On very old chips (T30) this was not always one.
*/
static inline int tegra_mc_get_tiled_memory_bandwidth_multiplier(void)
{
return 1;
}
#define TEGRA_MC_CLIENT_AFI 0
#define TEGRA_MC_CLIENT_DC 2
#define TEGRA_MC_CLIENT_DCB 3
#define TEGRA_MC_CLIENT_EPP 4
#define TEGRA_MC_CLIENT_G2 5
#define TEGRA_MC_CLIENT_ISP 8
#define TEGRA_MC_CLIENT_MSENC 11
#define TEGRA_MC_CLIENT_MPE 11
#define TEGRA_MC_CLIENT_NV 12
#define TEGRA_MC_CLIENT_SATA 15
#define TEGRA_MC_CLIENT_VDE 16
#define TEGRA_MC_CLIENT_VI 17
#define TEGRA_MC_CLIENT_VIC 18
#define TEGRA_MC_CLIENT_XUSB_HOST 19
#define TEGRA_MC_CLIENT_XUSB_DEV 20
#define TEGRA_MC_CLIENT_TSEC 22
#define TEGRA_MC_CLIENT_ISPB 33
#define TEGRA_MC_CLIENT_GPU 34
#define TEGRA_MC_CLIENT_NVDEC 37
#define TEGRA_MC_CLIENT_NVJPG 40
#define TEGRA_MC_CLIENT_TSECB 45
enum {
DRAM_TYPE_DDR3 = 0,
DRAM_TYPE_LPDDR4 = 1,
DRAM_TYPE_LPDDR2 = 2,
DRAM_TYPE_DDR2 = 3,
};
int tegra_mc_flush(int id);
int tegra_mc_flush_done(int id);
/*
* Necessary bit fields for various MC registers. Add to these as
* necessary.
*/
#define MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_BIT (1 << 27)
u32 tegra_get_dvfs_clk_change_latency_nsec(unsigned long emc_freq_khz);
#endif
|