brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 531b36d Raw
236 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HDMI PLL4 *5 * Copyright (C) 2013 Texas Instruments Incorporated6 */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	else74		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}236