linux/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation.
   3 * All rights reserved.
   4 */
   5
   6#include <linux/clk.h>
   7#include <linux/clk/clk-conf.h>
   8#include <linux/err.h>
   9#include <linux/delay.h>
  10#include <linux/of.h>
  11
  12#include <drm/drm_print.h>
  13
  14#include "dpu_io_util.h"
  15
  16void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
  17{
  18        int i;
  19
  20        for (i = num_clk - 1; i >= 0; i--) {
  21                if (clk_arry[i].clk)
  22                        clk_put(clk_arry[i].clk);
  23                clk_arry[i].clk = NULL;
  24        }
  25}
  26
  27int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
  28{
  29        int i, rc = 0;
  30
  31        for (i = 0; i < num_clk; i++) {
  32                clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
  33                rc = PTR_ERR_OR_ZERO(clk_arry[i].clk);
  34                if (rc) {
  35                        DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
  36                                __builtin_return_address(0), __func__,
  37                                clk_arry[i].clk_name, rc);
  38                        goto error;
  39                }
  40        }
  41
  42        return rc;
  43
  44error:
  45        for (i--; i >= 0; i--) {
  46                if (clk_arry[i].clk)
  47                        clk_put(clk_arry[i].clk);
  48                clk_arry[i].clk = NULL;
  49        }
  50
  51        return rc;
  52}
  53
  54int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
  55{
  56        int i, rc = 0;
  57
  58        for (i = 0; i < num_clk; i++) {
  59                if (clk_arry[i].clk) {
  60                        if (clk_arry[i].type != DSS_CLK_AHB) {
  61                                DEV_DBG("%pS->%s: '%s' rate %ld\n",
  62                                        __builtin_return_address(0), __func__,
  63                                        clk_arry[i].clk_name,
  64                                        clk_arry[i].rate);
  65                                rc = clk_set_rate(clk_arry[i].clk,
  66                                        clk_arry[i].rate);
  67                                if (rc) {
  68                                        DEV_ERR("%pS->%s: %s failed. rc=%d\n",
  69                                                __builtin_return_address(0),
  70                                                __func__,
  71                                                clk_arry[i].clk_name, rc);
  72                                        break;
  73                                }
  74                        }
  75                } else {
  76                        DEV_ERR("%pS->%s: '%s' is not available\n",
  77                                __builtin_return_address(0), __func__,
  78                                clk_arry[i].clk_name);
  79                        rc = -EPERM;
  80                        break;
  81                }
  82        }
  83
  84        return rc;
  85}
  86
  87int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
  88{
  89        int i, rc = 0;
  90
  91        if (enable) {
  92                for (i = 0; i < num_clk; i++) {
  93                        DEV_DBG("%pS->%s: enable '%s'\n",
  94                                __builtin_return_address(0), __func__,
  95                                clk_arry[i].clk_name);
  96                        rc = clk_prepare_enable(clk_arry[i].clk);
  97                        if (rc)
  98                                DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
  99                                        __builtin_return_address(0),
 100                                        __func__,
 101                                        clk_arry[i].clk_name, rc);
 102
 103                        if (rc && i) {
 104                                msm_dss_enable_clk(&clk_arry[i - 1],
 105                                        i - 1, false);
 106                                break;
 107                        }
 108                }
 109        } else {
 110                for (i = num_clk - 1; i >= 0; i--) {
 111                        DEV_DBG("%pS->%s: disable '%s'\n",
 112                                __builtin_return_address(0), __func__,
 113                                clk_arry[i].clk_name);
 114
 115                        clk_disable_unprepare(clk_arry[i].clk);
 116                }
 117        }
 118
 119        return rc;
 120}
 121
 122int msm_dss_parse_clock(struct platform_device *pdev,
 123                        struct dss_module_power *mp)
 124{
 125        u32 i, rc = 0;
 126        const char *clock_name;
 127        int num_clk = 0;
 128
 129        if (!pdev || !mp)
 130                return -EINVAL;
 131
 132        mp->num_clk = 0;
 133        num_clk = of_property_count_strings(pdev->dev.of_node, "clock-names");
 134        if (num_clk <= 0) {
 135                pr_debug("clocks are not defined\n");
 136                return 0;
 137        }
 138
 139        mp->clk_config = devm_kcalloc(&pdev->dev,
 140                                      num_clk, sizeof(struct dss_clk),
 141                                      GFP_KERNEL);
 142        if (!mp->clk_config)
 143                return -ENOMEM;
 144
 145        for (i = 0; i < num_clk; i++) {
 146                rc = of_property_read_string_index(pdev->dev.of_node,
 147                                                   "clock-names", i,
 148                                                   &clock_name);
 149                if (rc) {
 150                        DRM_DEV_ERROR(&pdev->dev, "Failed to get clock name for %d\n",
 151                                i);
 152                        break;
 153                }
 154                strlcpy(mp->clk_config[i].clk_name, clock_name,
 155                        sizeof(mp->clk_config[i].clk_name));
 156
 157                mp->clk_config[i].type = DSS_CLK_AHB;
 158        }
 159
 160        rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, num_clk);
 161        if (rc) {
 162                DRM_DEV_ERROR(&pdev->dev, "Failed to get clock refs %d\n", rc);
 163                goto err;
 164        }
 165
 166        rc = of_clk_set_defaults(pdev->dev.of_node, false);
 167        if (rc) {
 168                DRM_DEV_ERROR(&pdev->dev, "Failed to set clock defaults %d\n", rc);
 169                goto err;
 170        }
 171
 172        for (i = 0; i < num_clk; i++) {
 173                u32 rate = clk_get_rate(mp->clk_config[i].clk);
 174                if (!rate)
 175                        continue;
 176                mp->clk_config[i].rate = rate;
 177                mp->clk_config[i].type = DSS_CLK_PCLK;
 178                mp->clk_config[i].max_rate = rate;
 179        }
 180
 181        mp->num_clk = num_clk;
 182        return 0;
 183
 184err:
 185        msm_dss_put_clk(mp->clk_config, num_clk);
 186        return rc;
 187}
 188