cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mdp4_lvds_pll.c (3808B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014 Red Hat
      4 * Author: Rob Clark <robdclark@gmail.com>
      5 */
      6
      7#include <linux/clk.h>
      8#include <linux/clk-provider.h>
      9
     10#include "mdp4_kms.h"
     11
     12struct mdp4_lvds_pll {
     13	struct clk_hw pll_hw;
     14	struct drm_device *dev;
     15	unsigned long pixclk;
     16};
     17#define to_mdp4_lvds_pll(x) container_of(x, struct mdp4_lvds_pll, pll_hw)
     18
     19static struct mdp4_kms *get_kms(struct mdp4_lvds_pll *lvds_pll)
     20{
     21	struct msm_drm_private *priv = lvds_pll->dev->dev_private;
     22	return to_mdp4_kms(to_mdp_kms(priv->kms));
     23}
     24
     25struct pll_rate {
     26	unsigned long rate;
     27	struct {
     28		uint32_t val;
     29		uint32_t reg;
     30	} conf[32];
     31};
     32
     33/* NOTE: keep sorted highest freq to lowest: */
     34static const struct pll_rate freqtbl[] = {
     35	{ 72000000, {
     36		{ 0x8f, REG_MDP4_LVDS_PHY_PLL_CTRL_1 },
     37		{ 0x30, REG_MDP4_LVDS_PHY_PLL_CTRL_2 },
     38		{ 0xc6, REG_MDP4_LVDS_PHY_PLL_CTRL_3 },
     39		{ 0x10, REG_MDP4_LVDS_PHY_PLL_CTRL_5 },
     40		{ 0x07, REG_MDP4_LVDS_PHY_PLL_CTRL_6 },
     41		{ 0x62, REG_MDP4_LVDS_PHY_PLL_CTRL_7 },
     42		{ 0x41, REG_MDP4_LVDS_PHY_PLL_CTRL_8 },
     43		{ 0x0d, REG_MDP4_LVDS_PHY_PLL_CTRL_9 },
     44		{ 0, 0 } }
     45	},
     46};
     47
     48static const struct pll_rate *find_rate(unsigned long rate)
     49{
     50	int i;
     51	for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
     52		if (rate > freqtbl[i].rate)
     53			return &freqtbl[i-1];
     54	return &freqtbl[i-1];
     55}
     56
     57static int mpd4_lvds_pll_enable(struct clk_hw *hw)
     58{
     59	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
     60	struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
     61	const struct pll_rate *pll_rate = find_rate(lvds_pll->pixclk);
     62	int i;
     63
     64	DBG("pixclk=%lu (%lu)", lvds_pll->pixclk, pll_rate->rate);
     65
     66	if (WARN_ON(!pll_rate))
     67		return -EINVAL;
     68
     69	mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_PHY_RESET, 0x33);
     70
     71	for (i = 0; pll_rate->conf[i].reg; i++)
     72		mdp4_write(mdp4_kms, pll_rate->conf[i].reg, pll_rate->conf[i].val);
     73
     74	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x01);
     75
     76	/* Wait until LVDS PLL is locked and ready */
     77	while (!mdp4_read(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_LOCKED))
     78		cpu_relax();
     79
     80	return 0;
     81}
     82
     83static void mpd4_lvds_pll_disable(struct clk_hw *hw)
     84{
     85	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
     86	struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
     87
     88	DBG("");
     89
     90	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, 0x0);
     91	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x0);
     92}
     93
     94static unsigned long mpd4_lvds_pll_recalc_rate(struct clk_hw *hw,
     95				unsigned long parent_rate)
     96{
     97	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
     98	return lvds_pll->pixclk;
     99}
    100
    101static long mpd4_lvds_pll_round_rate(struct clk_hw *hw, unsigned long rate,
    102		unsigned long *parent_rate)
    103{
    104	const struct pll_rate *pll_rate = find_rate(rate);
    105	return pll_rate->rate;
    106}
    107
    108static int mpd4_lvds_pll_set_rate(struct clk_hw *hw, unsigned long rate,
    109		unsigned long parent_rate)
    110{
    111	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
    112	lvds_pll->pixclk = rate;
    113	return 0;
    114}
    115
    116
    117static const struct clk_ops mpd4_lvds_pll_ops = {
    118	.enable = mpd4_lvds_pll_enable,
    119	.disable = mpd4_lvds_pll_disable,
    120	.recalc_rate = mpd4_lvds_pll_recalc_rate,
    121	.round_rate = mpd4_lvds_pll_round_rate,
    122	.set_rate = mpd4_lvds_pll_set_rate,
    123};
    124
    125static const char *mpd4_lvds_pll_parents[] = {
    126	"pxo",
    127};
    128
    129static struct clk_init_data pll_init = {
    130	.name = "mpd4_lvds_pll",
    131	.ops = &mpd4_lvds_pll_ops,
    132	.parent_names = mpd4_lvds_pll_parents,
    133	.num_parents = ARRAY_SIZE(mpd4_lvds_pll_parents),
    134};
    135
    136struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
    137{
    138	struct mdp4_lvds_pll *lvds_pll;
    139	struct clk *clk;
    140	int ret;
    141
    142	lvds_pll = devm_kzalloc(dev->dev, sizeof(*lvds_pll), GFP_KERNEL);
    143	if (!lvds_pll) {
    144		ret = -ENOMEM;
    145		goto fail;
    146	}
    147
    148	lvds_pll->dev = dev;
    149
    150	lvds_pll->pll_hw.init = &pll_init;
    151	clk = devm_clk_register(dev->dev, &lvds_pll->pll_hw);
    152	if (IS_ERR(clk)) {
    153		ret = PTR_ERR(clk);
    154		goto fail;
    155	}
    156
    157	return clk;
    158
    159fail:
    160	return ERR_PTR(ret);
    161}