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
17struct 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
34struct 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
53static 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
86void __iomem *msm_ioremap(struct platform_device *pdev, const char *name)
87{
88	return _msm_ioremap(pdev, name, false, NULL);
89}
90
91void __iomem *msm_ioremap_quiet(struct platform_device *pdev, const char *name)
92{
93	return _msm_ioremap(pdev, name, true, NULL);
94}
95
96void __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
102static 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
112void 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
119void 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
131struct 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}
150