|
@@ -23,6 +23,18 @@
|
|
|
#define HDMI_DEFAULT_REGN 16
|
|
|
#define HDMI_DEFAULT_REGM2 1
|
|
|
|
|
|
+struct hdmi_pll_features {
|
|
|
+ bool sys_reset;
|
|
|
+ /* this is a hack, need to replace it with a better computation of M2 */
|
|
|
+ bool bound_dcofreq;
|
|
|
+ unsigned long fint_min, fint_max;
|
|
|
+ u16 regm_max;
|
|
|
+ unsigned long dcofreq_low_min, dcofreq_low_max;
|
|
|
+ unsigned long dcofreq_high_min, dcofreq_high_max;
|
|
|
+};
|
|
|
+
|
|
|
+static const struct hdmi_pll_features *pll_feat;
|
|
|
+
|
|
|
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
|
|
|
{
|
|
|
#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
|
|
@@ -57,7 +69,11 @@ void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
|
|
|
|
|
|
refclk = clkin / pi->regn;
|
|
|
|
|
|
- pi->regm2 = HDMI_DEFAULT_REGM2;
|
|
|
+ /* temorary hack to make sure DCO freq isn't calculated too low */
|
|
|
+ if (pll_feat->bound_dcofreq && phy <= 65000)
|
|
|
+ pi->regm2 = 3;
|
|
|
+ else
|
|
|
+ pi->regm2 = HDMI_DEFAULT_REGM2;
|
|
|
|
|
|
/*
|
|
|
* multiplier is pixel_clk/ref_clk
|
|
@@ -154,7 +170,7 @@ static int hdmi_pll_config(struct hdmi_pll_data *pll)
|
|
|
static int hdmi_pll_reset(struct hdmi_pll_data *pll)
|
|
|
{
|
|
|
/* SYSRESET controlled by power FSM */
|
|
|
- REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
|
|
|
+ REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3);
|
|
|
|
|
|
/* READ 0x0 reset is in progress */
|
|
|
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
|
|
@@ -197,11 +213,72 @@ void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
|
|
|
#define PLL_OFFSET 0x200
|
|
|
#define PLL_SIZE 0x100
|
|
|
|
|
|
+static const struct hdmi_pll_features omap44xx_pll_feats = {
|
|
|
+ .sys_reset = false,
|
|
|
+ .bound_dcofreq = false,
|
|
|
+ .fint_min = 500000,
|
|
|
+ .fint_max = 2500000,
|
|
|
+ .regm_max = 4095,
|
|
|
+ .dcofreq_low_min = 500000000,
|
|
|
+ .dcofreq_low_max = 1000000000,
|
|
|
+ .dcofreq_high_min = 1000000000,
|
|
|
+ .dcofreq_high_max = 2000000000,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct hdmi_pll_features omap54xx_pll_feats = {
|
|
|
+ .sys_reset = true,
|
|
|
+ .bound_dcofreq = true,
|
|
|
+ .fint_min = 620000,
|
|
|
+ .fint_max = 2500000,
|
|
|
+ .regm_max = 2046,
|
|
|
+ .dcofreq_low_min = 750000000,
|
|
|
+ .dcofreq_low_max = 1500000000,
|
|
|
+ .dcofreq_high_min = 1250000000,
|
|
|
+ .dcofreq_high_max = 2500000000UL,
|
|
|
+};
|
|
|
+
|
|
|
+static int hdmi_pll_init_features(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct hdmi_pll_features *dst;
|
|
|
+ const struct hdmi_pll_features *src;
|
|
|
+
|
|
|
+ dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
|
|
|
+ if (!dst) {
|
|
|
+ dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (omapdss_get_version()) {
|
|
|
+ case OMAPDSS_VER_OMAP4430_ES1:
|
|
|
+ case OMAPDSS_VER_OMAP4430_ES2:
|
|
|
+ case OMAPDSS_VER_OMAP4:
|
|
|
+ src = &omap44xx_pll_feats;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case OMAPDSS_VER_OMAP5:
|
|
|
+ src = &omap54xx_pll_feats;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(dst, src, sizeof(*dst));
|
|
|
+ pll_feat = dst;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
|
|
|
{
|
|
|
+ int r;
|
|
|
struct resource *res;
|
|
|
struct resource temp_res;
|
|
|
|
|
|
+ r = hdmi_pll_init_features(pdev);
|
|
|
+ if (r)
|
|
|
+ return r;
|
|
|
+
|
|
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
|
|
|
if (!res) {
|
|
|
DSSDBG("can't get PLL mem resource by name\n");
|