root/drivers/gpu/drm/msm/msm_io_utils.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2016-2018, 2020-2021 The Linux Foundation. All rights reserved.
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 */

#include <linux/interconnect.h>
#include <linux/io.h>

#include "msm_drv.h"

/*
 * Util/helpers:
 */

struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count,
                const char *name)
{
        int i;
        char n[32];

        snprintf(n, sizeof(n), "%s_clk", name);

        for (i = 0; bulk && i < count; i++) {
                if (!strcmp(bulk[i].id, name) || !strcmp(bulk[i].id, n))
                        return bulk[i].clk;
        }


        return NULL;
}

struct clk *msm_clk_get(struct platform_device *pdev, const char *name)
{
        struct clk *clk;
        char name2[32];

        clk = devm_clk_get(&pdev->dev, name);
        if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
                return clk;

        snprintf(name2, sizeof(name2), "%s_clk", name);

        clk = devm_clk_get(&pdev->dev, name2);
        if (!IS_ERR(clk))
                dev_warn(&pdev->dev, "Using legacy clk name binding.  Use "
                                "\"%s\" instead of \"%s\"\n", name, name2);

        return clk;
}

void __iomem *msm_ioremap_mdss(struct platform_device *mdss_pdev,
                               struct platform_device *pdev,
                               const char *name)
{
        struct resource *res;

        res = platform_get_resource_byname(mdss_pdev, IORESOURCE_MEM, name);
        if (!res)
                return ERR_PTR(-EINVAL);

        return devm_ioremap_resource(&pdev->dev, res);
}

static void __iomem *_msm_ioremap(struct platform_device *pdev, const char *name,
                                  bool quiet, phys_addr_t *psize)
{
        struct resource *res;
        unsigned long size;
        void __iomem *ptr;

        if (name)
                res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
        else
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

        if (!res) {
                if (!quiet)
                        DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n", name);
                return ERR_PTR(-EINVAL);
        }

        size = resource_size(res);

        ptr = devm_ioremap(&pdev->dev, res->start, size);
        if (!ptr) {
                if (!quiet)
                        DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n", name);
                return ERR_PTR(-ENOMEM);
        }

        if (psize)
                *psize = size;

        return ptr;
}

void __iomem *msm_ioremap(struct platform_device *pdev, const char *name)
{
        return _msm_ioremap(pdev, name, false, NULL);
}

void __iomem *msm_ioremap_quiet(struct platform_device *pdev, const char *name)
{
        return _msm_ioremap(pdev, name, true, NULL);
}

void __iomem *msm_ioremap_size(struct platform_device *pdev, const char *name,
                          phys_addr_t *psize)
{
        return _msm_ioremap(pdev, name, false, psize);
}

static enum hrtimer_restart msm_hrtimer_worktimer(struct hrtimer *t)
{
        struct msm_hrtimer_work *work = container_of(t,
                        struct msm_hrtimer_work, timer);

        kthread_queue_work(work->worker, &work->work);

        return HRTIMER_NORESTART;
}

void msm_hrtimer_queue_work(struct msm_hrtimer_work *work,
                            ktime_t wakeup_time,
                            enum hrtimer_mode mode)
{
        hrtimer_start(&work->timer, wakeup_time, mode);
}

void 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)
{
        hrtimer_setup(&work->timer, msm_hrtimer_worktimer, clock_id, mode);
        work->worker = worker;
        kthread_init_work(&work->work, fn);
}

struct icc_path *msm_icc_get(struct device *dev, const char *name)
{
        struct device *mdss_dev = dev->parent;
        struct icc_path *path;

        path = of_icc_get(dev, name);
        if (path)
                return path;

        /*
         * If there are no interconnects attached to the corresponding device
         * node, of_icc_get() will return NULL.
         *
         * If the MDP5/DPU device node doesn't have interconnects, lookup the
         * path in the parent (MDSS) device.
         */
        return of_icc_get(mdss_dev, name);

}