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