Merge tag 'ovl-update-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
[linux-2.6-microblaze.git] / drivers / memory / tegra / tegra20.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2012 NVIDIA CORPORATION.  All rights reserved.
4  */
5
6 #include <linux/of_device.h>
7 #include <linux/slab.h>
8 #include <linux/string.h>
9
10 #include <dt-bindings/memory/tegra20-mc.h>
11
12 #include "mc.h"
13
14 static const struct tegra_mc_client tegra20_mc_clients[] = {
15         {
16                 .id = 0x00,
17                 .name = "display0a",
18         }, {
19                 .id = 0x01,
20                 .name = "display0ab",
21         }, {
22                 .id = 0x02,
23                 .name = "display0b",
24         }, {
25                 .id = 0x03,
26                 .name = "display0bb",
27         }, {
28                 .id = 0x04,
29                 .name = "display0c",
30         }, {
31                 .id = 0x05,
32                 .name = "display0cb",
33         }, {
34                 .id = 0x06,
35                 .name = "display1b",
36         }, {
37                 .id = 0x07,
38                 .name = "display1bb",
39         }, {
40                 .id = 0x08,
41                 .name = "eppup",
42         }, {
43                 .id = 0x09,
44                 .name = "g2pr",
45         }, {
46                 .id = 0x0a,
47                 .name = "g2sr",
48         }, {
49                 .id = 0x0b,
50                 .name = "mpeunifbr",
51         }, {
52                 .id = 0x0c,
53                 .name = "viruv",
54         }, {
55                 .id = 0x0d,
56                 .name = "avpcarm7r",
57         }, {
58                 .id = 0x0e,
59                 .name = "displayhc",
60         }, {
61                 .id = 0x0f,
62                 .name = "displayhcb",
63         }, {
64                 .id = 0x10,
65                 .name = "fdcdrd",
66         }, {
67                 .id = 0x11,
68                 .name = "g2dr",
69         }, {
70                 .id = 0x12,
71                 .name = "host1xdmar",
72         }, {
73                 .id = 0x13,
74                 .name = "host1xr",
75         }, {
76                 .id = 0x14,
77                 .name = "idxsrd",
78         }, {
79                 .id = 0x15,
80                 .name = "mpcorer",
81         }, {
82                 .id = 0x16,
83                 .name = "mpe_ipred",
84         }, {
85                 .id = 0x17,
86                 .name = "mpeamemrd",
87         }, {
88                 .id = 0x18,
89                 .name = "mpecsrd",
90         }, {
91                 .id = 0x19,
92                 .name = "ppcsahbdmar",
93         }, {
94                 .id = 0x1a,
95                 .name = "ppcsahbslvr",
96         }, {
97                 .id = 0x1b,
98                 .name = "texsrd",
99         }, {
100                 .id = 0x1c,
101                 .name = "vdebsevr",
102         }, {
103                 .id = 0x1d,
104                 .name = "vdember",
105         }, {
106                 .id = 0x1e,
107                 .name = "vdemcer",
108         }, {
109                 .id = 0x1f,
110                 .name = "vdetper",
111         }, {
112                 .id = 0x20,
113                 .name = "eppu",
114         }, {
115                 .id = 0x21,
116                 .name = "eppv",
117         }, {
118                 .id = 0x22,
119                 .name = "eppy",
120         }, {
121                 .id = 0x23,
122                 .name = "mpeunifbw",
123         }, {
124                 .id = 0x24,
125                 .name = "viwsb",
126         }, {
127                 .id = 0x25,
128                 .name = "viwu",
129         }, {
130                 .id = 0x26,
131                 .name = "viwv",
132         }, {
133                 .id = 0x27,
134                 .name = "viwy",
135         }, {
136                 .id = 0x28,
137                 .name = "g2dw",
138         }, {
139                 .id = 0x29,
140                 .name = "avpcarm7w",
141         }, {
142                 .id = 0x2a,
143                 .name = "fdcdwr",
144         }, {
145                 .id = 0x2b,
146                 .name = "host1xw",
147         }, {
148                 .id = 0x2c,
149                 .name = "ispw",
150         }, {
151                 .id = 0x2d,
152                 .name = "mpcorew",
153         }, {
154                 .id = 0x2e,
155                 .name = "mpecswr",
156         }, {
157                 .id = 0x2f,
158                 .name = "ppcsahbdmaw",
159         }, {
160                 .id = 0x30,
161                 .name = "ppcsahbslvw",
162         }, {
163                 .id = 0x31,
164                 .name = "vdebsevw",
165         }, {
166                 .id = 0x32,
167                 .name = "vdembew",
168         }, {
169                 .id = 0x33,
170                 .name = "vdetpmw",
171         },
172 };
173
174 #define TEGRA20_MC_RESET(_name, _control, _status, _reset, _bit)        \
175         {                                                               \
176                 .name = #_name,                                         \
177                 .id = TEGRA20_MC_RESET_##_name,                         \
178                 .control = _control,                                    \
179                 .status = _status,                                      \
180                 .reset = _reset,                                        \
181                 .bit = _bit,                                            \
182         }
183
184 static const struct tegra_mc_reset tegra20_mc_resets[] = {
185         TEGRA20_MC_RESET(AVPC,   0x100, 0x140, 0x104,  0),
186         TEGRA20_MC_RESET(DC,     0x100, 0x144, 0x104,  1),
187         TEGRA20_MC_RESET(DCB,    0x100, 0x148, 0x104,  2),
188         TEGRA20_MC_RESET(EPP,    0x100, 0x14c, 0x104,  3),
189         TEGRA20_MC_RESET(2D,     0x100, 0x150, 0x104,  4),
190         TEGRA20_MC_RESET(HC,     0x100, 0x154, 0x104,  5),
191         TEGRA20_MC_RESET(ISP,    0x100, 0x158, 0x104,  6),
192         TEGRA20_MC_RESET(MPCORE, 0x100, 0x15c, 0x104,  7),
193         TEGRA20_MC_RESET(MPEA,   0x100, 0x160, 0x104,  8),
194         TEGRA20_MC_RESET(MPEB,   0x100, 0x164, 0x104,  9),
195         TEGRA20_MC_RESET(MPEC,   0x100, 0x168, 0x104, 10),
196         TEGRA20_MC_RESET(3D,     0x100, 0x16c, 0x104, 11),
197         TEGRA20_MC_RESET(PPCS,   0x100, 0x170, 0x104, 12),
198         TEGRA20_MC_RESET(VDE,    0x100, 0x174, 0x104, 13),
199         TEGRA20_MC_RESET(VI,     0x100, 0x178, 0x104, 14),
200 };
201
202 static int tegra20_mc_hotreset_assert(struct tegra_mc *mc,
203                                       const struct tegra_mc_reset *rst)
204 {
205         unsigned long flags;
206         u32 value;
207
208         spin_lock_irqsave(&mc->lock, flags);
209
210         value = mc_readl(mc, rst->reset);
211         mc_writel(mc, value & ~BIT(rst->bit), rst->reset);
212
213         spin_unlock_irqrestore(&mc->lock, flags);
214
215         return 0;
216 }
217
218 static int tegra20_mc_hotreset_deassert(struct tegra_mc *mc,
219                                         const struct tegra_mc_reset *rst)
220 {
221         unsigned long flags;
222         u32 value;
223
224         spin_lock_irqsave(&mc->lock, flags);
225
226         value = mc_readl(mc, rst->reset);
227         mc_writel(mc, value | BIT(rst->bit), rst->reset);
228
229         spin_unlock_irqrestore(&mc->lock, flags);
230
231         return 0;
232 }
233
234 static int tegra20_mc_block_dma(struct tegra_mc *mc,
235                                 const struct tegra_mc_reset *rst)
236 {
237         unsigned long flags;
238         u32 value;
239
240         spin_lock_irqsave(&mc->lock, flags);
241
242         value = mc_readl(mc, rst->control) & ~BIT(rst->bit);
243         mc_writel(mc, value, rst->control);
244
245         spin_unlock_irqrestore(&mc->lock, flags);
246
247         return 0;
248 }
249
250 static bool tegra20_mc_dma_idling(struct tegra_mc *mc,
251                                   const struct tegra_mc_reset *rst)
252 {
253         return mc_readl(mc, rst->status) == 0;
254 }
255
256 static int tegra20_mc_reset_status(struct tegra_mc *mc,
257                                    const struct tegra_mc_reset *rst)
258 {
259         return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0;
260 }
261
262 static int tegra20_mc_unblock_dma(struct tegra_mc *mc,
263                                   const struct tegra_mc_reset *rst)
264 {
265         unsigned long flags;
266         u32 value;
267
268         spin_lock_irqsave(&mc->lock, flags);
269
270         value = mc_readl(mc, rst->control) | BIT(rst->bit);
271         mc_writel(mc, value, rst->control);
272
273         spin_unlock_irqrestore(&mc->lock, flags);
274
275         return 0;
276 }
277
278 static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = {
279         .hotreset_assert = tegra20_mc_hotreset_assert,
280         .hotreset_deassert = tegra20_mc_hotreset_deassert,
281         .block_dma = tegra20_mc_block_dma,
282         .dma_idling = tegra20_mc_dma_idling,
283         .unblock_dma = tegra20_mc_unblock_dma,
284         .reset_status = tegra20_mc_reset_status,
285 };
286
287 static int tegra20_mc_icc_set(struct icc_node *src, struct icc_node *dst)
288 {
289         /*
290          * It should be possible to tune arbitration knobs here, but the
291          * default values are known to work well on all devices. Hence
292          * nothing to do here so far.
293          */
294         return 0;
295 }
296
297 static int tegra20_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
298                                    u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
299 {
300         /*
301          * ISO clients need to reserve extra bandwidth up-front because
302          * there could be high bandwidth pressure during initial filling
303          * of the client's FIFO buffers.  Secondly, we need to take into
304          * account impurities of the memory subsystem.
305          */
306         if (tag & TEGRA_MC_ICC_TAG_ISO)
307                 peak_bw = tegra_mc_scale_percents(peak_bw, 300);
308
309         *agg_avg += avg_bw;
310         *agg_peak = max(*agg_peak, peak_bw);
311
312         return 0;
313 }
314
315 static struct icc_node_data *
316 tegra20_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
317 {
318         struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
319         unsigned int i, idx = spec->args[0];
320         struct icc_node_data *ndata;
321         struct icc_node *node;
322
323         list_for_each_entry(node, &mc->provider.nodes, node_list) {
324                 if (node->id != idx)
325                         continue;
326
327                 ndata = kzalloc(sizeof(*ndata), GFP_KERNEL);
328                 if (!ndata)
329                         return ERR_PTR(-ENOMEM);
330
331                 ndata->node = node;
332
333                 /* these clients are isochronous by default */
334                 if (strstarts(node->name, "display") ||
335                     strstarts(node->name, "vi"))
336                         ndata->tag = TEGRA_MC_ICC_TAG_ISO;
337                 else
338                         ndata->tag = TEGRA_MC_ICC_TAG_DEFAULT;
339
340                 return ndata;
341         }
342
343         for (i = 0; i < mc->soc->num_clients; i++) {
344                 if (mc->soc->clients[i].id == idx)
345                         return ERR_PTR(-EPROBE_DEFER);
346         }
347
348         dev_err(mc->dev, "invalid ICC client ID %u\n", idx);
349
350         return ERR_PTR(-EINVAL);
351 }
352
353 static const struct tegra_mc_icc_ops tegra20_mc_icc_ops = {
354         .xlate_extended = tegra20_mc_of_icc_xlate_extended,
355         .aggregate = tegra20_mc_icc_aggreate,
356         .set = tegra20_mc_icc_set,
357 };
358
359 const struct tegra_mc_soc tegra20_mc_soc = {
360         .clients = tegra20_mc_clients,
361         .num_clients = ARRAY_SIZE(tegra20_mc_clients),
362         .num_address_bits = 32,
363         .client_id_mask = 0x3f,
364         .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
365                    MC_INT_DECERR_EMEM,
366         .reset_ops = &tegra20_mc_reset_ops,
367         .resets = tegra20_mc_resets,
368         .num_resets = ARRAY_SIZE(tegra20_mc_resets),
369         .icc_ops = &tegra20_mc_icc_ops,
370 };