xref: /linux/drivers/gpu/drm/msm/msm_io_utils.c (revision e6a901a00822659181c93c86d8bbc2a17779fddc)
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 void __iomem *msm_ioremap_mdss(struct platform_device *mdss_pdev,
54 			       struct platform_device *pdev,
55 			       const char *name)
56 {
57 	struct resource *res;
58 
59 	res = platform_get_resource_byname(mdss_pdev, IORESOURCE_MEM, name);
60 	if (!res)
61 		return ERR_PTR(-EINVAL);
62 
63 	return devm_ioremap_resource(&pdev->dev, res);
64 }
65 
66 static void __iomem *_msm_ioremap(struct platform_device *pdev, const char *name,
67 				  bool quiet, phys_addr_t *psize)
68 {
69 	struct resource *res;
70 	unsigned long size;
71 	void __iomem *ptr;
72 
73 	if (name)
74 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
75 	else
76 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
77 
78 	if (!res) {
79 		if (!quiet)
80 			DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n", name);
81 		return ERR_PTR(-EINVAL);
82 	}
83 
84 	size = resource_size(res);
85 
86 	ptr = devm_ioremap(&pdev->dev, res->start, size);
87 	if (!ptr) {
88 		if (!quiet)
89 			DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n", name);
90 		return ERR_PTR(-ENOMEM);
91 	}
92 
93 	if (psize)
94 		*psize = size;
95 
96 	return ptr;
97 }
98 
99 void __iomem *msm_ioremap(struct platform_device *pdev, const char *name)
100 {
101 	return _msm_ioremap(pdev, name, false, NULL);
102 }
103 
104 void __iomem *msm_ioremap_quiet(struct platform_device *pdev, const char *name)
105 {
106 	return _msm_ioremap(pdev, name, true, NULL);
107 }
108 
109 void __iomem *msm_ioremap_size(struct platform_device *pdev, const char *name,
110 			  phys_addr_t *psize)
111 {
112 	return _msm_ioremap(pdev, name, false, psize);
113 }
114 
115 static enum hrtimer_restart msm_hrtimer_worktimer(struct hrtimer *t)
116 {
117 	struct msm_hrtimer_work *work = container_of(t,
118 			struct msm_hrtimer_work, timer);
119 
120 	kthread_queue_work(work->worker, &work->work);
121 
122 	return HRTIMER_NORESTART;
123 }
124 
125 void msm_hrtimer_queue_work(struct msm_hrtimer_work *work,
126 			    ktime_t wakeup_time,
127 			    enum hrtimer_mode mode)
128 {
129 	hrtimer_start(&work->timer, wakeup_time, mode);
130 }
131 
132 void msm_hrtimer_work_init(struct msm_hrtimer_work *work,
133 			   struct kthread_worker *worker,
134 			   kthread_work_func_t fn,
135 			   clockid_t clock_id,
136 			   enum hrtimer_mode mode)
137 {
138 	hrtimer_init(&work->timer, clock_id, mode);
139 	work->timer.function = msm_hrtimer_worktimer;
140 	work->worker = worker;
141 	kthread_init_work(&work->work, fn);
142 }
143 
144 struct icc_path *msm_icc_get(struct device *dev, const char *name)
145 {
146 	struct device *mdss_dev = dev->parent;
147 	struct icc_path *path;
148 
149 	path = of_icc_get(dev, name);
150 	if (path)
151 		return path;
152 
153 	/*
154 	 * If there are no interconnects attached to the corresponding device
155 	 * node, of_icc_get() will return NULL.
156 	 *
157 	 * If the MDP5/DPU device node doesn't have interconnects, lookup the
158 	 * path in the parent (MDSS) device.
159 	 */
160 	return of_icc_get(mdss_dev, name);
161 
162 }
163