Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.17-rc4 291 lines 7.0 kB view raw
1/* 2 * HDMI PLL 3 * 4 * Copyright (C) 2013 Texas Instruments Incorporated 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published by 8 * the Free Software Foundation. 9 */ 10 11#define DSS_SUBSYS_NAME "HDMIPLL" 12 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/err.h> 16#include <linux/io.h> 17#include <linux/platform_device.h> 18#include <video/omapdss.h> 19 20#include "dss.h" 21#include "hdmi.h" 22 23#define HDMI_DEFAULT_REGN 16 24#define HDMI_DEFAULT_REGM2 1 25 26struct hdmi_pll_features { 27 bool sys_reset; 28 /* this is a hack, need to replace it with a better computation of M2 */ 29 bool bound_dcofreq; 30 unsigned long fint_min, fint_max; 31 u16 regm_max; 32 unsigned long dcofreq_low_min, dcofreq_low_max; 33 unsigned long dcofreq_high_min, dcofreq_high_max; 34}; 35 36static const struct hdmi_pll_features *pll_feat; 37 38void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) 39{ 40#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ 41 hdmi_read_reg(pll->base, r)) 42 43 DUMPPLL(PLLCTRL_PLL_CONTROL); 44 DUMPPLL(PLLCTRL_PLL_STATUS); 45 DUMPPLL(PLLCTRL_PLL_GO); 46 DUMPPLL(PLLCTRL_CFG1); 47 DUMPPLL(PLLCTRL_CFG2); 48 DUMPPLL(PLLCTRL_CFG3); 49 DUMPPLL(PLLCTRL_SSC_CFG1); 50 DUMPPLL(PLLCTRL_SSC_CFG2); 51 DUMPPLL(PLLCTRL_CFG4); 52} 53 54void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy) 55{ 56 struct hdmi_pll_info *pi = &pll->info; 57 unsigned long refclk; 58 u32 mf; 59 60 /* use our funky units */ 61 clkin /= 10000; 62 63 /* 64 * Input clock is predivided by N + 1 65 * out put of which is reference clk 66 */ 67 68 pi->regn = HDMI_DEFAULT_REGN; 69 70 refclk = clkin / pi->regn; 71 72 /* temorary hack to make sure DCO freq isn't calculated too low */ 73 if (pll_feat->bound_dcofreq && phy <= 65000) 74 pi->regm2 = 3; 75 else 76 pi->regm2 = HDMI_DEFAULT_REGM2; 77 78 /* 79 * multiplier is pixel_clk/ref_clk 80 * Multiplying by 100 to avoid fractional part removal 81 */ 82 pi->regm = phy * pi->regm2 / refclk; 83 84 /* 85 * fractional multiplier is remainder of the difference between 86 * multiplier and actual phy(required pixel clock thus should be 87 * multiplied by 2^18(262144) divided by the reference clock 88 */ 89 mf = (phy - pi->regm / pi->regm2 * refclk) * 262144; 90 pi->regmf = pi->regm2 * mf / refclk; 91 92 /* 93 * Dcofreq should be set to 1 if required pixel clock 94 * is greater than 1000MHz 95 */ 96 pi->dcofreq = phy > 1000 * 100; 97 pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10; 98 99 /* Set the reference clock to sysclk reference */ 100 pi->refsel = HDMI_REFSEL_SYSCLK; 101 102 DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf); 103 DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); 104} 105 106 107static int hdmi_pll_config(struct hdmi_pll_data *pll) 108{ 109 u32 r; 110 struct hdmi_pll_info *fmt = &pll->info; 111 112 /* PLL start always use manual mode */ 113 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0); 114 115 r = hdmi_read_reg(pll->base, PLLCTRL_CFG1); 116 r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */ 117 r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */ 118 hdmi_write_reg(pll->base, PLLCTRL_CFG1, r); 119 120 r = hdmi_read_reg(pll->base, PLLCTRL_CFG2); 121 122 r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ 123 r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */ 124 r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */ 125 r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */ 126 127 if (fmt->dcofreq) { 128 /* divider programming for frequency beyond 1000Mhz */ 129 REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10); 130 r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ 131 } else { 132 r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ 133 } 134 135 hdmi_write_reg(pll->base, PLLCTRL_CFG2, r); 136 137 r = hdmi_read_reg(pll->base, PLLCTRL_CFG4); 138 r = FLD_MOD(r, fmt->regm2, 24, 18); 139 r = FLD_MOD(r, fmt->regmf, 17, 0); 140 hdmi_write_reg(pll->base, PLLCTRL_CFG4, r); 141 142 /* go now */ 143 REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0); 144 145 /* wait for bit change */ 146 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO, 147 0, 0, 1) != 1) { 148 DSSERR("PLL GO bit not set\n"); 149 return -ETIMEDOUT; 150 } 151 152 /* Wait till the lock bit is set in PLL status */ 153 if (hdmi_wait_for_bit_change(pll->base, 154 PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { 155 DSSERR("cannot lock PLL\n"); 156 DSSERR("CFG1 0x%x\n", 157 hdmi_read_reg(pll->base, PLLCTRL_CFG1)); 158 DSSERR("CFG2 0x%x\n", 159 hdmi_read_reg(pll->base, PLLCTRL_CFG2)); 160 DSSERR("CFG4 0x%x\n", 161 hdmi_read_reg(pll->base, PLLCTRL_CFG4)); 162 return -ETIMEDOUT; 163 } 164 165 DSSDBG("PLL locked!\n"); 166 167 return 0; 168} 169 170static int hdmi_pll_reset(struct hdmi_pll_data *pll) 171{ 172 /* SYSRESET controlled by power FSM */ 173 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3); 174 175 /* READ 0x0 reset is in progress */ 176 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1) 177 != 1) { 178 DSSERR("Failed to sysreset PLL\n"); 179 return -ETIMEDOUT; 180 } 181 182 return 0; 183} 184 185int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) 186{ 187 u16 r = 0; 188 189 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); 190 if (r) 191 return r; 192 193 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); 194 if (r) 195 return r; 196 197 r = hdmi_pll_reset(pll); 198 if (r) 199 return r; 200 201 r = hdmi_pll_config(pll); 202 if (r) 203 return r; 204 205 return 0; 206} 207 208void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) 209{ 210 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); 211} 212 213static const struct hdmi_pll_features omap44xx_pll_feats = { 214 .sys_reset = false, 215 .bound_dcofreq = false, 216 .fint_min = 500000, 217 .fint_max = 2500000, 218 .regm_max = 4095, 219 .dcofreq_low_min = 500000000, 220 .dcofreq_low_max = 1000000000, 221 .dcofreq_high_min = 1000000000, 222 .dcofreq_high_max = 2000000000, 223}; 224 225static const struct hdmi_pll_features omap54xx_pll_feats = { 226 .sys_reset = true, 227 .bound_dcofreq = true, 228 .fint_min = 620000, 229 .fint_max = 2500000, 230 .regm_max = 2046, 231 .dcofreq_low_min = 750000000, 232 .dcofreq_low_max = 1500000000, 233 .dcofreq_high_min = 1250000000, 234 .dcofreq_high_max = 2500000000UL, 235}; 236 237static int hdmi_pll_init_features(struct platform_device *pdev) 238{ 239 struct hdmi_pll_features *dst; 240 const struct hdmi_pll_features *src; 241 242 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); 243 if (!dst) { 244 dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n"); 245 return -ENOMEM; 246 } 247 248 switch (omapdss_get_version()) { 249 case OMAPDSS_VER_OMAP4430_ES1: 250 case OMAPDSS_VER_OMAP4430_ES2: 251 case OMAPDSS_VER_OMAP4: 252 src = &omap44xx_pll_feats; 253 break; 254 255 case OMAPDSS_VER_OMAP5: 256 src = &omap54xx_pll_feats; 257 break; 258 259 default: 260 return -ENODEV; 261 } 262 263 memcpy(dst, src, sizeof(*dst)); 264 pll_feat = dst; 265 266 return 0; 267} 268 269int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) 270{ 271 int r; 272 struct resource *res; 273 274 r = hdmi_pll_init_features(pdev); 275 if (r) 276 return r; 277 278 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); 279 if (!res) { 280 DSSERR("can't get PLL mem resource\n"); 281 return -EINVAL; 282 } 283 284 pll->base = devm_ioremap_resource(&pdev->dev, res); 285 if (IS_ERR(pll->base)) { 286 DSSERR("can't ioremap PLLCTRL\n"); 287 return PTR_ERR(pll->base); 288 } 289 290 return 0; 291}