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

hdmi_pll.c (4855B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * HDMI PLL
      4 *
      5 * Copyright (C) 2013 Texas Instruments Incorporated
      6 */
      7
      8#define DSS_SUBSYS_NAME "HDMIPLL"
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/err.h>
     13#include <linux/io.h>
     14#include <linux/platform_device.h>
     15#include <linux/clk.h>
     16#include <linux/seq_file.h>
     17
     18#include <video/omapfb_dss.h>
     19
     20#include "dss.h"
     21#include "hdmi.h"
     22
     23void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
     24{
     25#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
     26		hdmi_read_reg(pll->base, r))
     27
     28	DUMPPLL(PLLCTRL_PLL_CONTROL);
     29	DUMPPLL(PLLCTRL_PLL_STATUS);
     30	DUMPPLL(PLLCTRL_PLL_GO);
     31	DUMPPLL(PLLCTRL_CFG1);
     32	DUMPPLL(PLLCTRL_CFG2);
     33	DUMPPLL(PLLCTRL_CFG3);
     34	DUMPPLL(PLLCTRL_SSC_CFG1);
     35	DUMPPLL(PLLCTRL_SSC_CFG2);
     36	DUMPPLL(PLLCTRL_CFG4);
     37}
     38
     39void hdmi_pll_compute(struct hdmi_pll_data *pll,
     40	unsigned long target_tmds, struct dss_pll_clock_info *pi)
     41{
     42	unsigned long fint, clkdco, clkout;
     43	unsigned long target_bitclk, target_clkdco;
     44	unsigned long min_dco;
     45	unsigned n, m, mf, m2, sd;
     46	unsigned long clkin;
     47	const struct dss_pll_hw *hw = pll->pll.hw;
     48
     49	clkin = clk_get_rate(pll->pll.clkin);
     50
     51	DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
     52
     53	target_bitclk = target_tmds * 10;
     54
     55	/* Fint */
     56	n = DIV_ROUND_UP(clkin, hw->fint_max);
     57	fint = clkin / n;
     58
     59	/* adjust m2 so that the clkdco will be high enough */
     60	min_dco = roundup(hw->clkdco_min, fint);
     61	m2 = DIV_ROUND_UP(min_dco, target_bitclk);
     62	if (m2 == 0)
     63		m2 = 1;
     64
     65	target_clkdco = target_bitclk * m2;
     66	m = target_clkdco / fint;
     67
     68	clkdco = fint * m;
     69
     70	/* adjust clkdco with fractional mf */
     71	if (WARN_ON(target_clkdco - clkdco > fint))
     72		mf = 0;
     73	else
     74		mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
     75
     76	if (mf > 0)
     77		clkdco += (u32)div_u64((u64)mf * fint, 262144);
     78
     79	clkout = clkdco / m2;
     80
     81	/* sigma-delta */
     82	sd = DIV_ROUND_UP(fint * m, 250000000);
     83
     84	DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
     85		n, m, mf, m2, sd);
     86	DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
     87
     88	pi->n = n;
     89	pi->m = m;
     90	pi->mf = mf;
     91	pi->mX[0] = m2;
     92	pi->sd = sd;
     93
     94	pi->fint = fint;
     95	pi->clkdco = clkdco;
     96	pi->clkout[0] = clkout;
     97}
     98
     99static int hdmi_pll_enable(struct dss_pll *dsspll)
    100{
    101	struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
    102	struct hdmi_wp_data *wp = pll->wp;
    103
    104	dss_ctrl_pll_enable(DSS_PLL_HDMI, true);
    105
    106	return hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
    107}
    108
    109static void hdmi_pll_disable(struct dss_pll *dsspll)
    110{
    111	struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
    112	struct hdmi_wp_data *wp = pll->wp;
    113
    114	hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
    115
    116	dss_ctrl_pll_enable(DSS_PLL_HDMI, false);
    117}
    118
    119static const struct dss_pll_ops dsi_pll_ops = {
    120	.enable = hdmi_pll_enable,
    121	.disable = hdmi_pll_disable,
    122	.set_config = dss_pll_write_config_type_b,
    123};
    124
    125static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
    126	.n_max = 255,
    127	.m_min = 20,
    128	.m_max = 4095,
    129	.mX_max = 127,
    130	.fint_min = 500000,
    131	.fint_max = 2500000,
    132
    133	.clkdco_min = 500000000,
    134	.clkdco_low = 1000000000,
    135	.clkdco_max = 2000000000,
    136
    137	.n_msb = 8,
    138	.n_lsb = 1,
    139	.m_msb = 20,
    140	.m_lsb = 9,
    141
    142	.mX_msb[0] = 24,
    143	.mX_lsb[0] = 18,
    144
    145	.has_selfreqdco = true,
    146};
    147
    148static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
    149	.n_max = 255,
    150	.m_min = 20,
    151	.m_max = 2045,
    152	.mX_max = 127,
    153	.fint_min = 620000,
    154	.fint_max = 2500000,
    155
    156	.clkdco_min = 750000000,
    157	.clkdco_low = 1500000000,
    158	.clkdco_max = 2500000000UL,
    159
    160	.n_msb = 8,
    161	.n_lsb = 1,
    162	.m_msb = 20,
    163	.m_lsb = 9,
    164
    165	.mX_msb[0] = 24,
    166	.mX_lsb[0] = 18,
    167
    168	.has_selfreqdco = true,
    169	.has_refsel = true,
    170};
    171
    172static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll)
    173{
    174	struct dss_pll *pll = &hpll->pll;
    175	struct clk *clk;
    176
    177	clk = devm_clk_get(&pdev->dev, "sys_clk");
    178	if (IS_ERR(clk)) {
    179		DSSERR("can't get sys_clk\n");
    180		return PTR_ERR(clk);
    181	}
    182
    183	pll->name = "hdmi";
    184	pll->id = DSS_PLL_HDMI;
    185	pll->base = hpll->base;
    186	pll->clkin = clk;
    187
    188	switch (omapdss_get_version()) {
    189	case OMAPDSS_VER_OMAP4430_ES1:
    190	case OMAPDSS_VER_OMAP4430_ES2:
    191	case OMAPDSS_VER_OMAP4:
    192		pll->hw = &dss_omap4_hdmi_pll_hw;
    193		break;
    194
    195	case OMAPDSS_VER_OMAP5:
    196	case OMAPDSS_VER_DRA7xx:
    197		pll->hw = &dss_omap5_hdmi_pll_hw;
    198		break;
    199
    200	default:
    201		return -ENODEV;
    202	}
    203
    204	pll->ops = &dsi_pll_ops;
    205	return dss_pll_register(pll);
    206}
    207
    208int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
    209	struct hdmi_wp_data *wp)
    210{
    211	int r;
    212
    213	pll->wp = wp;
    214
    215	pll->base = devm_platform_ioremap_resource_byname(pdev, "pll");
    216	if (IS_ERR(pll->base)) {
    217		DSSERR("can't ioremap PLLCTRL\n");
    218		return PTR_ERR(pll->base);
    219	}
    220
    221	r = dsi_init_pll_data(pdev, pll);
    222	if (r) {
    223		DSSERR("failed to init HDMI PLL\n");
    224		return r;
    225	}
    226
    227	return 0;
    228}
    229
    230void hdmi_pll_uninit(struct hdmi_pll_data *hpll)
    231{
    232	struct dss_pll *pll = &hpll->pll;
    233
    234	dss_pll_unregister(pll);
    235}