188 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HDMI PLL4 *5 * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/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#include <linux/pm_runtime.h>18 19#include "omapdss.h"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 39static int hdmi_pll_enable(struct dss_pll *dsspll)40{41 struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);42 struct hdmi_wp_data *wp = pll->wp;43 int r;44 45 r = pm_runtime_get_sync(&pll->pdev->dev);46 WARN_ON(r < 0);47 48 dss_ctrl_pll_enable(dsspll, true);49 50 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);51 if (r)52 return r;53 54 return 0;55}56 57static void hdmi_pll_disable(struct dss_pll *dsspll)58{59 struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);60 struct hdmi_wp_data *wp = pll->wp;61 int r;62 63 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);64 65 dss_ctrl_pll_enable(dsspll, false);66 67 r = pm_runtime_put_sync(&pll->pdev->dev);68 WARN_ON(r < 0 && r != -ENOSYS);69}70 71static const struct dss_pll_ops hdmi_pll_ops = {72 .enable = hdmi_pll_enable,73 .disable = hdmi_pll_disable,74 .set_config = dss_pll_write_config_type_b,75};76 77static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {78 .type = DSS_PLL_TYPE_B,79 80 .n_max = 255,81 .m_min = 20,82 .m_max = 4095,83 .mX_max = 127,84 .fint_min = 500000,85 .fint_max = 2500000,86 87 .clkdco_min = 500000000,88 .clkdco_low = 1000000000,89 .clkdco_max = 2000000000,90 91 .n_msb = 8,92 .n_lsb = 1,93 .m_msb = 20,94 .m_lsb = 9,95 96 .mX_msb[0] = 24,97 .mX_lsb[0] = 18,98 99 .has_selfreqdco = true,100};101 102static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {103 .type = DSS_PLL_TYPE_B,104 105 .n_max = 255,106 .m_min = 20,107 .m_max = 2045,108 .mX_max = 127,109 .fint_min = 620000,110 .fint_max = 2500000,111 112 .clkdco_min = 750000000,113 .clkdco_low = 1500000000,114 .clkdco_max = 2500000000UL,115 116 .n_msb = 8,117 .n_lsb = 1,118 .m_msb = 20,119 .m_lsb = 9,120 121 .mX_msb[0] = 24,122 .mX_lsb[0] = 18,123 124 .has_selfreqdco = true,125 .has_refsel = true,126};127 128static int hdmi_init_pll_data(struct dss_device *dss,129 struct platform_device *pdev,130 struct hdmi_pll_data *hpll)131{132 struct dss_pll *pll = &hpll->pll;133 struct clk *clk;134 int r;135 136 clk = devm_clk_get(&pdev->dev, "sys_clk");137 if (IS_ERR(clk)) {138 DSSERR("can't get sys_clk\n");139 return PTR_ERR(clk);140 }141 142 pll->name = "hdmi";143 pll->id = DSS_PLL_HDMI;144 pll->base = hpll->base;145 pll->clkin = clk;146 147 if (hpll->wp->version == 4)148 pll->hw = &dss_omap4_hdmi_pll_hw;149 else150 pll->hw = &dss_omap5_hdmi_pll_hw;151 152 pll->ops = &hdmi_pll_ops;153 154 r = dss_pll_register(dss, pll);155 if (r)156 return r;157 158 return 0;159}160 161int hdmi_pll_init(struct dss_device *dss, struct platform_device *pdev,162 struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)163{164 int r;165 166 pll->pdev = pdev;167 pll->wp = wp;168 169 pll->base = devm_platform_ioremap_resource_byname(pdev, "pll");170 if (IS_ERR(pll->base))171 return PTR_ERR(pll->base);172 173 r = hdmi_init_pll_data(dss, pdev, pll);174 if (r) {175 DSSERR("failed to init HDMI PLL\n");176 return r;177 }178 179 return 0;180}181 182void hdmi_pll_uninit(struct hdmi_pll_data *hpll)183{184 struct dss_pll *pll = &hpll->pll;185 186 dss_pll_unregister(pll);187}188