Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / tegra / vic.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015, NVIDIA Corporation.
4  */
5
6 #include <linux/clk.h>
7 #include <linux/host1x.h>
8 #include <linux/iommu.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/of_device.h>
12 #include <linux/of_platform.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/reset.h>
16
17 #include <soc/tegra/pmc.h>
18
19 #include "drm.h"
20 #include "falcon.h"
21 #include "vic.h"
22
23 struct vic_config {
24         const char *firmware;
25         unsigned int version;
26         bool supports_sid;
27 };
28
29 struct vic {
30         struct falcon falcon;
31         bool booted;
32
33         void __iomem *regs;
34         struct tegra_drm_client client;
35         struct host1x_channel *channel;
36         struct iommu_domain *domain;
37         struct device *dev;
38         struct clk *clk;
39         struct reset_control *rst;
40
41         /* Platform configuration */
42         const struct vic_config *config;
43 };
44
45 static inline struct vic *to_vic(struct tegra_drm_client *client)
46 {
47         return container_of(client, struct vic, client);
48 }
49
50 static void vic_writel(struct vic *vic, u32 value, unsigned int offset)
51 {
52         writel(value, vic->regs + offset);
53 }
54
55 static int vic_runtime_resume(struct device *dev)
56 {
57         struct vic *vic = dev_get_drvdata(dev);
58         int err;
59
60         err = clk_prepare_enable(vic->clk);
61         if (err < 0)
62                 return err;
63
64         usleep_range(10, 20);
65
66         err = reset_control_deassert(vic->rst);
67         if (err < 0)
68                 goto disable;
69
70         usleep_range(10, 20);
71
72         return 0;
73
74 disable:
75         clk_disable_unprepare(vic->clk);
76         return err;
77 }
78
79 static int vic_runtime_suspend(struct device *dev)
80 {
81         struct vic *vic = dev_get_drvdata(dev);
82         int err;
83
84         err = reset_control_assert(vic->rst);
85         if (err < 0)
86                 return err;
87
88         usleep_range(2000, 4000);
89
90         clk_disable_unprepare(vic->clk);
91
92         vic->booted = false;
93
94         return 0;
95 }
96
97 static int vic_boot(struct vic *vic)
98 {
99         u32 fce_ucode_size, fce_bin_data_offset;
100         void *hdr;
101         int err = 0;
102
103         if (vic->booted)
104                 return 0;
105
106 #ifdef CONFIG_IOMMU_API
107         if (vic->config->supports_sid) {
108                 struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev);
109                 u32 value;
110
111                 value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) |
112                         TRANSCFG_ATT(0, TRANSCFG_SID_HW);
113                 vic_writel(vic, value, VIC_TFBIF_TRANSCFG);
114
115                 if (spec && spec->num_ids > 0) {
116                         value = spec->ids[0] & 0xffff;
117
118                         vic_writel(vic, value, VIC_THI_STREAMID0);
119                         vic_writel(vic, value, VIC_THI_STREAMID1);
120                 }
121         }
122 #endif
123
124         /* setup clockgating registers */
125         vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) |
126                         CG_IDLE_CG_EN |
127                         CG_WAKEUP_DLY_CNT(4),
128                    NV_PVIC_MISC_PRI_VIC_CG);
129
130         err = falcon_boot(&vic->falcon);
131         if (err < 0)
132                 return err;
133
134         hdr = vic->falcon.firmware.vaddr;
135         fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET);
136         hdr = vic->falcon.firmware.vaddr +
137                 *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET);
138         fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET);
139
140         falcon_execute_method(&vic->falcon, VIC_SET_APPLICATION_ID, 1);
141         falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE,
142                               fce_ucode_size);
143         falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_OFFSET,
144                               (vic->falcon.firmware.paddr + fce_bin_data_offset)
145                                 >> 8);
146
147         err = falcon_wait_idle(&vic->falcon);
148         if (err < 0) {
149                 dev_err(vic->dev,
150                         "failed to set application ID and FCE base\n");
151                 return err;
152         }
153
154         vic->booted = true;
155
156         return 0;
157 }
158
159 static void *vic_falcon_alloc(struct falcon *falcon, size_t size,
160                               dma_addr_t *iova)
161 {
162         struct tegra_drm *tegra = falcon->data;
163
164         return tegra_drm_alloc(tegra, size, iova);
165 }
166
167 static void vic_falcon_free(struct falcon *falcon, size_t size,
168                             dma_addr_t iova, void *va)
169 {
170         struct tegra_drm *tegra = falcon->data;
171
172         return tegra_drm_free(tegra, size, va, iova);
173 }
174
175 static const struct falcon_ops vic_falcon_ops = {
176         .alloc = vic_falcon_alloc,
177         .free = vic_falcon_free
178 };
179
180 static int vic_init(struct host1x_client *client)
181 {
182         struct tegra_drm_client *drm = host1x_to_drm_client(client);
183         struct iommu_group *group = iommu_group_get(client->dev);
184         struct drm_device *dev = dev_get_drvdata(client->parent);
185         struct tegra_drm *tegra = dev->dev_private;
186         struct vic *vic = to_vic(drm);
187         int err;
188
189         if (group && tegra->domain) {
190                 err = iommu_attach_group(tegra->domain, group);
191                 if (err < 0) {
192                         dev_err(vic->dev, "failed to attach to domain: %d\n",
193                                 err);
194                         return err;
195                 }
196
197                 vic->domain = tegra->domain;
198         }
199
200         vic->channel = host1x_channel_request(client->dev);
201         if (!vic->channel) {
202                 err = -ENOMEM;
203                 goto detach;
204         }
205
206         client->syncpts[0] = host1x_syncpt_request(client, 0);
207         if (!client->syncpts[0]) {
208                 err = -ENOMEM;
209                 goto free_channel;
210         }
211
212         err = tegra_drm_register_client(tegra, drm);
213         if (err < 0)
214                 goto free_syncpt;
215
216         return 0;
217
218 free_syncpt:
219         host1x_syncpt_free(client->syncpts[0]);
220 free_channel:
221         host1x_channel_put(vic->channel);
222 detach:
223         if (group && tegra->domain)
224                 iommu_detach_group(tegra->domain, group);
225
226         return err;
227 }
228
229 static int vic_exit(struct host1x_client *client)
230 {
231         struct tegra_drm_client *drm = host1x_to_drm_client(client);
232         struct iommu_group *group = iommu_group_get(client->dev);
233         struct drm_device *dev = dev_get_drvdata(client->parent);
234         struct tegra_drm *tegra = dev->dev_private;
235         struct vic *vic = to_vic(drm);
236         int err;
237
238         err = tegra_drm_unregister_client(tegra, drm);
239         if (err < 0)
240                 return err;
241
242         host1x_syncpt_free(client->syncpts[0]);
243         host1x_channel_put(vic->channel);
244
245         if (vic->domain) {
246                 iommu_detach_group(vic->domain, group);
247                 vic->domain = NULL;
248         }
249
250         return 0;
251 }
252
253 static const struct host1x_client_ops vic_client_ops = {
254         .init = vic_init,
255         .exit = vic_exit,
256 };
257
258 static int vic_load_firmware(struct vic *vic)
259 {
260         int err;
261
262         if (vic->falcon.data)
263                 return 0;
264
265         vic->falcon.data = vic->client.drm;
266
267         err = falcon_read_firmware(&vic->falcon, vic->config->firmware);
268         if (err < 0)
269                 goto cleanup;
270
271         err = falcon_load_firmware(&vic->falcon);
272         if (err < 0)
273                 goto cleanup;
274
275         return 0;
276
277 cleanup:
278         vic->falcon.data = NULL;
279         return err;
280 }
281
282 static int vic_open_channel(struct tegra_drm_client *client,
283                             struct tegra_drm_context *context)
284 {
285         struct vic *vic = to_vic(client);
286         int err;
287
288         err = pm_runtime_get_sync(vic->dev);
289         if (err < 0)
290                 return err;
291
292         err = vic_load_firmware(vic);
293         if (err < 0)
294                 goto rpm_put;
295
296         err = vic_boot(vic);
297         if (err < 0)
298                 goto rpm_put;
299
300         context->channel = host1x_channel_get(vic->channel);
301         if (!context->channel) {
302                 err = -ENOMEM;
303                 goto rpm_put;
304         }
305
306         return 0;
307
308 rpm_put:
309         pm_runtime_put(vic->dev);
310         return err;
311 }
312
313 static void vic_close_channel(struct tegra_drm_context *context)
314 {
315         struct vic *vic = to_vic(context->client);
316
317         host1x_channel_put(context->channel);
318
319         pm_runtime_put(vic->dev);
320 }
321
322 static const struct tegra_drm_client_ops vic_ops = {
323         .open_channel = vic_open_channel,
324         .close_channel = vic_close_channel,
325         .submit = tegra_drm_submit,
326 };
327
328 #define NVIDIA_TEGRA_124_VIC_FIRMWARE "/*(DEBLOBBED)*/"
329
330 static const struct vic_config vic_t124_config = {
331         .firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE,
332         .version = 0x40,
333         .supports_sid = false,
334 };
335
336 #define NVIDIA_TEGRA_210_VIC_FIRMWARE "/*(DEBLOBBED)*/"
337
338 static const struct vic_config vic_t210_config = {
339         .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE,
340         .version = 0x21,
341         .supports_sid = false,
342 };
343
344 #define NVIDIA_TEGRA_186_VIC_FIRMWARE "/*(DEBLOBBED)*/"
345
346 static const struct vic_config vic_t186_config = {
347         .firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE,
348         .version = 0x18,
349         .supports_sid = true,
350 };
351
352 #define NVIDIA_TEGRA_194_VIC_FIRMWARE "/*(DEBLOBBED)*/"
353
354 static const struct vic_config vic_t194_config = {
355         /*(DEBLOBBED)*/NVIDIA_TEGRA_194_VIC_FIRMWARE,
356         .version = 0x19,
357         .supports_sid = true,
358 };
359
360 static const struct of_device_id vic_match[] = {
361         { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
362         { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
363         { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config },
364         { .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config },
365         { },
366 };
367
368 static int vic_probe(struct platform_device *pdev)
369 {
370         struct device *dev = &pdev->dev;
371         struct host1x_syncpt **syncpts;
372         struct resource *regs;
373         struct vic *vic;
374         int err;
375
376         vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL);
377         if (!vic)
378                 return -ENOMEM;
379
380         vic->config = of_device_get_match_data(dev);
381
382         syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
383         if (!syncpts)
384                 return -ENOMEM;
385
386         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
387         if (!regs) {
388                 dev_err(&pdev->dev, "failed to get registers\n");
389                 return -ENXIO;
390         }
391
392         vic->regs = devm_ioremap_resource(dev, regs);
393         if (IS_ERR(vic->regs))
394                 return PTR_ERR(vic->regs);
395
396         vic->clk = devm_clk_get(dev, NULL);
397         if (IS_ERR(vic->clk)) {
398                 dev_err(&pdev->dev, "failed to get clock\n");
399                 return PTR_ERR(vic->clk);
400         }
401
402         if (!dev->pm_domain) {
403                 vic->rst = devm_reset_control_get(dev, "vic");
404                 if (IS_ERR(vic->rst)) {
405                         dev_err(&pdev->dev, "failed to get reset\n");
406                         return PTR_ERR(vic->rst);
407                 }
408         }
409
410         vic->falcon.dev = dev;
411         vic->falcon.regs = vic->regs;
412         vic->falcon.ops = &vic_falcon_ops;
413
414         err = falcon_init(&vic->falcon);
415         if (err < 0)
416                 return err;
417
418         platform_set_drvdata(pdev, vic);
419
420         INIT_LIST_HEAD(&vic->client.base.list);
421         vic->client.base.ops = &vic_client_ops;
422         vic->client.base.dev = dev;
423         vic->client.base.class = HOST1X_CLASS_VIC;
424         vic->client.base.syncpts = syncpts;
425         vic->client.base.num_syncpts = 1;
426         vic->dev = dev;
427
428         INIT_LIST_HEAD(&vic->client.list);
429         vic->client.version = vic->config->version;
430         vic->client.ops = &vic_ops;
431
432         err = host1x_client_register(&vic->client.base);
433         if (err < 0) {
434                 dev_err(dev, "failed to register host1x client: %d\n", err);
435                 goto exit_falcon;
436         }
437
438         pm_runtime_enable(&pdev->dev);
439         if (!pm_runtime_enabled(&pdev->dev)) {
440                 err = vic_runtime_resume(&pdev->dev);
441                 if (err < 0)
442                         goto unregister_client;
443         }
444
445         return 0;
446
447 unregister_client:
448         host1x_client_unregister(&vic->client.base);
449 exit_falcon:
450         falcon_exit(&vic->falcon);
451
452         return err;
453 }
454
455 static int vic_remove(struct platform_device *pdev)
456 {
457         struct vic *vic = platform_get_drvdata(pdev);
458         int err;
459
460         err = host1x_client_unregister(&vic->client.base);
461         if (err < 0) {
462                 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
463                         err);
464                 return err;
465         }
466
467         if (pm_runtime_enabled(&pdev->dev))
468                 pm_runtime_disable(&pdev->dev);
469         else
470                 vic_runtime_suspend(&pdev->dev);
471
472         falcon_exit(&vic->falcon);
473
474         return 0;
475 }
476
477 static const struct dev_pm_ops vic_pm_ops = {
478         SET_RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL)
479 };
480
481 struct platform_driver tegra_vic_driver = {
482         .driver = {
483                 .name = "tegra-vic",
484                 .of_match_table = vic_match,
485                 .pm = &vic_pm_ops
486         },
487         .probe = vic_probe,
488         .remove = vic_remove,
489 };
490
491 #if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)
492 /*(DEBLOBBED)*/
493 #endif
494 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
495 /*(DEBLOBBED)*/
496 #endif
497 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
498 /*(DEBLOBBED)*/
499 #endif
500 #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
501 /*(DEBLOBBED)*/
502 #endif