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