Merge tag 'mips_6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / msm / msm_io_utils.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2016-2018, 2020-2021 The Linux Foundation. All rights reserved.
4  * Copyright (C) 2013 Red Hat
5  * Author: Rob Clark <robdclark@gmail.com>
6  */
7
8 #include <linux/interconnect.h>
9 #include <linux/io.h>
10
11 #include "msm_drv.h"
12
13 /*
14  * Util/helpers:
15  */
16
17 struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count,
18                 const char *name)
19 {
20         int i;
21         char n[32];
22
23         snprintf(n, sizeof(n), "%s_clk", name);
24
25         for (i = 0; bulk && i < count; i++) {
26                 if (!strcmp(bulk[i].id, name) || !strcmp(bulk[i].id, n))
27                         return bulk[i].clk;
28         }
29
30
31         return NULL;
32 }
33
34 struct clk *msm_clk_get(struct platform_device *pdev, const char *name)
35 {
36         struct clk *clk;
37         char name2[32];
38
39         clk = devm_clk_get(&pdev->dev, name);
40         if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
41                 return clk;
42
43         snprintf(name2, sizeof(name2), "%s_clk", name);
44
45         clk = devm_clk_get(&pdev->dev, name2);
46         if (!IS_ERR(clk))
47                 dev_warn(&pdev->dev, "Using legacy clk name binding.  Use "
48                                 "\"%s\" instead of \"%s\"\n", name, name2);
49
50         return clk;
51 }
52
53 static void __iomem *_msm_ioremap(struct platform_device *pdev, const char *name,
54                                   bool quiet, phys_addr_t *psize)
55 {
56         struct resource *res;
57         unsigned long size;
58         void __iomem *ptr;
59
60         if (name)
61                 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
62         else
63                 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
64
65         if (!res) {
66                 if (!quiet)
67                         DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n", name);
68                 return ERR_PTR(-EINVAL);
69         }
70
71         size = resource_size(res);
72
73         ptr = devm_ioremap(&pdev->dev, res->start, size);
74         if (!ptr) {
75                 if (!quiet)
76                         DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n", name);
77                 return ERR_PTR(-ENOMEM);
78         }
79
80         if (psize)
81                 *psize = size;
82
83         return ptr;
84 }
85
86 void __iomem *msm_ioremap(struct platform_device *pdev, const char *name)
87 {
88         return _msm_ioremap(pdev, name, false, NULL);
89 }
90
91 void __iomem *msm_ioremap_quiet(struct platform_device *pdev, const char *name)
92 {
93         return _msm_ioremap(pdev, name, true, NULL);
94 }
95
96 void __iomem *msm_ioremap_size(struct platform_device *pdev, const char *name,
97                           phys_addr_t *psize)
98 {
99         return _msm_ioremap(pdev, name, false, psize);
100 }
101
102 static enum hrtimer_restart msm_hrtimer_worktimer(struct hrtimer *t)
103 {
104         struct msm_hrtimer_work *work = container_of(t,
105                         struct msm_hrtimer_work, timer);
106
107         kthread_queue_work(work->worker, &work->work);
108
109         return HRTIMER_NORESTART;
110 }
111
112 void msm_hrtimer_queue_work(struct msm_hrtimer_work *work,
113                             ktime_t wakeup_time,
114                             enum hrtimer_mode mode)
115 {
116         hrtimer_start(&work->timer, wakeup_time, mode);
117 }
118
119 void msm_hrtimer_work_init(struct msm_hrtimer_work *work,
120                            struct kthread_worker *worker,
121                            kthread_work_func_t fn,
122                            clockid_t clock_id,
123                            enum hrtimer_mode mode)
124 {
125         hrtimer_init(&work->timer, clock_id, mode);
126         work->timer.function = msm_hrtimer_worktimer;
127         work->worker = worker;
128         kthread_init_work(&work->work, fn);
129 }
130
131 struct icc_path *msm_icc_get(struct device *dev, const char *name)
132 {
133         struct device *mdss_dev = dev->parent;
134         struct icc_path *path;
135
136         path = of_icc_get(dev, name);
137         if (path)
138                 return path;
139
140         /*
141          * If there are no interconnects attached to the corresponding device
142          * node, of_icc_get() will return NULL.
143          *
144          * If the MDP5/DPU device node doesn't have interconnects, lookup the
145          * path in the parent (MDSS) device.
146          */
147         return of_icc_get(mdss_dev, name);
148
149 }