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