diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss/hdmi_pll.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi_pll.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c new file mode 100644 index 000000000..eea719243 --- /dev/null +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * HDMI PLL + * + * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#define DSS_SUBSYS_NAME "HDMIPLL" + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/seq_file.h> +#include <linux/pm_runtime.h> + +#include "omapdss.h" +#include "dss.h" +#include "hdmi.h" + +void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) +{ +#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ + hdmi_read_reg(pll->base, r)) + + DUMPPLL(PLLCTRL_PLL_CONTROL); + DUMPPLL(PLLCTRL_PLL_STATUS); + DUMPPLL(PLLCTRL_PLL_GO); + DUMPPLL(PLLCTRL_CFG1); + DUMPPLL(PLLCTRL_CFG2); + DUMPPLL(PLLCTRL_CFG3); + DUMPPLL(PLLCTRL_SSC_CFG1); + DUMPPLL(PLLCTRL_SSC_CFG2); + DUMPPLL(PLLCTRL_CFG4); +} + +static int hdmi_pll_enable(struct dss_pll *dsspll) +{ + struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); + struct hdmi_wp_data *wp = pll->wp; + int r; + + r = pm_runtime_get_sync(&pll->pdev->dev); + WARN_ON(r < 0); + + dss_ctrl_pll_enable(dsspll, true); + + r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); + if (r) + return r; + + return 0; +} + +static void hdmi_pll_disable(struct dss_pll *dsspll) +{ + struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); + struct hdmi_wp_data *wp = pll->wp; + int r; + + hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); + + dss_ctrl_pll_enable(dsspll, false); + + r = pm_runtime_put_sync(&pll->pdev->dev); + WARN_ON(r < 0 && r != -ENOSYS); +} + +static const struct dss_pll_ops hdmi_pll_ops = { + .enable = hdmi_pll_enable, + .disable = hdmi_pll_disable, + .set_config = dss_pll_write_config_type_b, +}; + +static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = { + .type = DSS_PLL_TYPE_B, + + .n_max = 255, + .m_min = 20, + .m_max = 4095, + .mX_max = 127, + .fint_min = 500000, + .fint_max = 2500000, + + .clkdco_min = 500000000, + .clkdco_low = 1000000000, + .clkdco_max = 2000000000, + + .n_msb = 8, + .n_lsb = 1, + .m_msb = 20, + .m_lsb = 9, + + .mX_msb[0] = 24, + .mX_lsb[0] = 18, + + .has_selfreqdco = true, +}; + +static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = { + .type = DSS_PLL_TYPE_B, + + .n_max = 255, + .m_min = 20, + .m_max = 2045, + .mX_max = 127, + .fint_min = 620000, + .fint_max = 2500000, + + .clkdco_min = 750000000, + .clkdco_low = 1500000000, + .clkdco_max = 2500000000UL, + + .n_msb = 8, + .n_lsb = 1, + .m_msb = 20, + .m_lsb = 9, + + .mX_msb[0] = 24, + .mX_lsb[0] = 18, + + .has_selfreqdco = true, + .has_refsel = true, +}; + +static int hdmi_init_pll_data(struct dss_device *dss, + struct platform_device *pdev, + struct hdmi_pll_data *hpll) +{ + struct dss_pll *pll = &hpll->pll; + struct clk *clk; + int r; + + clk = devm_clk_get(&pdev->dev, "sys_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get sys_clk\n"); + return PTR_ERR(clk); + } + + pll->name = "hdmi"; + pll->id = DSS_PLL_HDMI; + pll->base = hpll->base; + pll->clkin = clk; + + if (hpll->wp->version == 4) + pll->hw = &dss_omap4_hdmi_pll_hw; + else + pll->hw = &dss_omap5_hdmi_pll_hw; + + pll->ops = &hdmi_pll_ops; + + r = dss_pll_register(dss, pll); + if (r) + return r; + + return 0; +} + +int hdmi_pll_init(struct dss_device *dss, struct platform_device *pdev, + struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) +{ + int r; + + pll->pdev = pdev; + pll->wp = wp; + + pll->base = devm_platform_ioremap_resource_byname(pdev, "pll"); + if (IS_ERR(pll->base)) + return PTR_ERR(pll->base); + + r = hdmi_init_pll_data(dss, pdev, pll); + if (r) { + DSSERR("failed to init HDMI PLL\n"); + return r; + } + + return 0; +} + +void hdmi_pll_uninit(struct hdmi_pll_data *hpll) +{ + struct dss_pll *pll = &hpll->pll; + + dss_pll_unregister(pll); +} |