linux/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include "dsi_pll.h"
   7
   8static int dsi_pll_enable(struct msm_dsi_pll *pll)
   9{
  10        int i, ret = 0;
  11
  12        /*
  13         * Certain PLLs do not allow VCO rate update when it is on.
  14         * Keep track of their status to turn on/off after set rate success.
  15         */
  16        if (unlikely(pll->pll_on))
  17                return 0;
  18
  19        /* Try all enable sequences until one succeeds */
  20        for (i = 0; i < pll->en_seq_cnt; i++) {
  21                ret = pll->enable_seqs[i](pll);
  22                DBG("DSI PLL %s after sequence #%d",
  23                        ret ? "unlocked" : "locked", i + 1);
  24                if (!ret)
  25                        break;
  26        }
  27
  28        if (ret) {
  29                DRM_ERROR("DSI PLL failed to lock\n");
  30                return ret;
  31        }
  32
  33        pll->pll_on = true;
  34
  35        return 0;
  36}
  37
  38static void dsi_pll_disable(struct msm_dsi_pll *pll)
  39{
  40        if (unlikely(!pll->pll_on))
  41                return;
  42
  43        pll->disable_seq(pll);
  44
  45        pll->pll_on = false;
  46}
  47
  48/*
  49 * DSI PLL Helper functions
  50 */
  51long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
  52                unsigned long rate, unsigned long *parent_rate)
  53{
  54        struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
  55
  56        if      (rate < pll->min_rate)
  57                return  pll->min_rate;
  58        else if (rate > pll->max_rate)
  59                return  pll->max_rate;
  60        else
  61                return rate;
  62}
  63
  64int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw)
  65{
  66        struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
  67
  68        return dsi_pll_enable(pll);
  69}
  70
  71void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw)
  72{
  73        struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
  74
  75        dsi_pll_disable(pll);
  76}
  77
  78void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
  79                                        struct clk **clks, u32 num_clks)
  80{
  81        of_clk_del_provider(pdev->dev.of_node);
  82
  83        if (!num_clks || !clks)
  84                return;
  85
  86        do {
  87                clk_unregister(clks[--num_clks]);
  88                clks[num_clks] = NULL;
  89        } while (num_clks);
  90}
  91
  92/*
  93 * DSI PLL API
  94 */
  95int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
  96        struct clk **byte_clk_provider, struct clk **pixel_clk_provider)
  97{
  98        if (pll->get_provider)
  99                return pll->get_provider(pll,
 100                                        byte_clk_provider,
 101                                        pixel_clk_provider);
 102
 103        return -EINVAL;
 104}
 105
 106void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
 107{
 108        if (pll->destroy)
 109                pll->destroy(pll);
 110}
 111
 112void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
 113{
 114        if (pll->save_state) {
 115                pll->save_state(pll);
 116                pll->state_saved = true;
 117        }
 118}
 119
 120int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
 121{
 122        int ret;
 123
 124        if (pll->restore_state && pll->state_saved) {
 125                ret = pll->restore_state(pll);
 126                if (ret)
 127                        return ret;
 128
 129                pll->state_saved = false;
 130        }
 131
 132        return 0;
 133}
 134
 135int msm_dsi_pll_set_usecase(struct msm_dsi_pll *pll,
 136                            enum msm_dsi_phy_usecase uc)
 137{
 138        if (pll->set_usecase)
 139                return pll->set_usecase(pll, uc);
 140
 141        return 0;
 142}
 143
 144struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
 145                        enum msm_dsi_phy_type type, int id)
 146{
 147        struct device *dev = &pdev->dev;
 148        struct msm_dsi_pll *pll;
 149
 150        switch (type) {
 151        case MSM_DSI_PHY_28NM_HPM:
 152        case MSM_DSI_PHY_28NM_LP:
 153                pll = msm_dsi_pll_28nm_init(pdev, type, id);
 154                break;
 155        case MSM_DSI_PHY_28NM_8960:
 156                pll = msm_dsi_pll_28nm_8960_init(pdev, id);
 157                break;
 158        case MSM_DSI_PHY_14NM:
 159                pll = msm_dsi_pll_14nm_init(pdev, id);
 160                break;
 161        case MSM_DSI_PHY_10NM:
 162                pll = msm_dsi_pll_10nm_init(pdev, id);
 163                break;
 164        default:
 165                pll = ERR_PTR(-ENXIO);
 166                break;
 167        }
 168
 169        if (IS_ERR(pll)) {
 170                DRM_DEV_ERROR(dev, "%s: failed to init DSI PLL\n", __func__);
 171                return pll;
 172        }
 173
 174        pll->type = type;
 175
 176        DBG("DSI:%d PLL registered", id);
 177
 178        return pll;
 179}
 180
 181