aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2018-08-17 15:19:37 -0400
committerDavid S. Miller <davem@davemloft.net>2018-10-08 01:41:05 -0400
commit76ebebd2464c5c8a4453c98b6dbf9c95a599e810 (patch)
treeaf8ce763bef242472331fbca5805b8066dbcde73
parentc1d84a1b42ef70d8ae601df9cadedc7ed4f1beb1 (diff)
mach64: detect the dot clock divider correctly on sparc
On Sun Ultra 5, it happens that the dot clock is not set up properly for some videomodes. For example, if we set the videomode "r1024x768x60" in the firmware, Linux would incorrectly set a videomode with refresh rate 180Hz when booting (suprisingly, my LCD monitor can display it, although display quality is very low). The reason is this: Older mach64 cards set the divider in the register VCLK_POST_DIV. The register has four 2-bit fields (the field that is actually used is specified in the lowest two bits of the register CLOCK_CNTL). The 2 bits select divider "1, 2, 4, 8". On newer mach64 cards, there's another bit added - the top four bits of PLL_EXT_CNTL extend the divider selection, so we have possible dividers "1, 2, 4, 8, 3, 5, 6, 12". The Linux driver clears the top four bits of PLL_EXT_CNTL and never sets them, so it can work regardless if the card supports them. However, the sparc64 firmware may set these extended dividers during boot - and the mach64 driver detects incorrect dot clock in this case. This patch makes the driver read the additional divider bit from PLL_EXT_CNTL and calculate the initial refresh rate properly. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org Acked-by: David S. Miller <davem@davemloft.net> Reviewed-by: Ville Syrjälä <syrjala@sci.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/video/fbdev/aty/atyfb.h3
-rw-r--r--drivers/video/fbdev/aty/atyfb_base.c7
-rw-r--r--drivers/video/fbdev/aty/mach64_ct.c10
3 files changed, 11 insertions, 9 deletions
diff --git a/drivers/video/fbdev/aty/atyfb.h b/drivers/video/fbdev/aty/atyfb.h
index 8235b285dbb2..d09bab3bf224 100644
--- a/drivers/video/fbdev/aty/atyfb.h
+++ b/drivers/video/fbdev/aty/atyfb.h
@@ -333,6 +333,8 @@ extern const struct aty_pll_ops aty_pll_ct; /* Integrated */
333extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll); 333extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll);
334extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par); 334extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
335 335
336extern const u8 aty_postdividers[8];
337
336 338
337 /* 339 /*
338 * Hardware cursor support 340 * Hardware cursor support
@@ -359,7 +361,6 @@ static inline void wait_for_idle(struct atyfb_par *par)
359 361
360extern void aty_reset_engine(const struct atyfb_par *par); 362extern void aty_reset_engine(const struct atyfb_par *par);
361extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info); 363extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info);
362extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
363 364
364void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); 365void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
365void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); 366void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index a9a8272f7a6e..05111e90f168 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -3087,17 +3087,18 @@ static int atyfb_setup_sparc(struct pci_dev *pdev, struct fb_info *info,
3087 /* 3087 /*
3088 * PLL Reference Divider M: 3088 * PLL Reference Divider M:
3089 */ 3089 */
3090 M = pll_regs[2]; 3090 M = pll_regs[PLL_REF_DIV];
3091 3091
3092 /* 3092 /*
3093 * PLL Feedback Divider N (Dependent on CLOCK_CNTL): 3093 * PLL Feedback Divider N (Dependent on CLOCK_CNTL):
3094 */ 3094 */
3095 N = pll_regs[7 + (clock_cntl & 3)]; 3095 N = pll_regs[VCLK0_FB_DIV + (clock_cntl & 3)];
3096 3096
3097 /* 3097 /*
3098 * PLL Post Divider P (Dependent on CLOCK_CNTL): 3098 * PLL Post Divider P (Dependent on CLOCK_CNTL):
3099 */ 3099 */
3100 P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); 3100 P = aty_postdividers[((pll_regs[VCLK_POST_DIV] >> ((clock_cntl & 3) << 1)) & 3) |
3101 ((pll_regs[PLL_EXT_CNTL] >> (2 + (clock_cntl & 3))) & 4)];
3101 3102
3102 /* 3103 /*
3103 * PLL Divider Q: 3104 * PLL Divider Q:
diff --git a/drivers/video/fbdev/aty/mach64_ct.c b/drivers/video/fbdev/aty/mach64_ct.c
index 74a62aa193c0..f87cc81f4fa2 100644
--- a/drivers/video/fbdev/aty/mach64_ct.c
+++ b/drivers/video/fbdev/aty/mach64_ct.c
@@ -115,7 +115,7 @@ static void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
115 */ 115 */
116 116
117#define Maximum_DSP_PRECISION 7 117#define Maximum_DSP_PRECISION 7
118static u8 postdividers[] = {1,2,4,8,3}; 118const u8 aty_postdividers[8] = {1,2,4,8,3,5,6,12};
119 119
120static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll) 120static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
121{ 121{
@@ -222,7 +222,7 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll
222 pll->vclk_post_div += (q < 64*8); 222 pll->vclk_post_div += (q < 64*8);
223 pll->vclk_post_div += (q < 32*8); 223 pll->vclk_post_div += (q < 32*8);
224 } 224 }
225 pll->vclk_post_div_real = postdividers[pll->vclk_post_div]; 225 pll->vclk_post_div_real = aty_postdividers[pll->vclk_post_div];
226 // pll->vclk_post_div <<= 6; 226 // pll->vclk_post_div <<= 6;
227 pll->vclk_fb_div = q * pll->vclk_post_div_real / 8; 227 pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
228 pllvclk = (1000000 * 2 * pll->vclk_fb_div) / 228 pllvclk = (1000000 * 2 * pll->vclk_fb_div) /
@@ -513,7 +513,7 @@ static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
513 u8 mclk_fb_div, pll_ext_cntl; 513 u8 mclk_fb_div, pll_ext_cntl;
514 pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par); 514 pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
515 pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par); 515 pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
516 pll->ct.xclk_post_div_real = postdividers[pll_ext_cntl & 0x07]; 516 pll->ct.xclk_post_div_real = aty_postdividers[pll_ext_cntl & 0x07];
517 mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par); 517 mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
518 if (pll_ext_cntl & PLL_MFB_TIMES_4_2B) 518 if (pll_ext_cntl & PLL_MFB_TIMES_4_2B)
519 mclk_fb_div <<= 1; 519 mclk_fb_div <<= 1;
@@ -535,7 +535,7 @@ static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
535 xpost_div += (q < 64*8); 535 xpost_div += (q < 64*8);
536 xpost_div += (q < 32*8); 536 xpost_div += (q < 32*8);
537 } 537 }
538 pll->ct.xclk_post_div_real = postdividers[xpost_div]; 538 pll->ct.xclk_post_div_real = aty_postdividers[xpost_div];
539 pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8; 539 pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;
540 540
541#ifdef CONFIG_PPC 541#ifdef CONFIG_PPC
@@ -584,7 +584,7 @@ static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
584 mpost_div += (q < 64*8); 584 mpost_div += (q < 64*8);
585 mpost_div += (q < 32*8); 585 mpost_div += (q < 32*8);
586 } 586 }
587 sclk_post_div_real = postdividers[mpost_div]; 587 sclk_post_div_real = aty_postdividers[mpost_div];
588 pll->ct.sclk_fb_div = q * sclk_post_div_real / 8; 588 pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
589 pll->ct.spll_cntl2 = mpost_div << 4; 589 pll->ct.spll_cntl2 = mpost_div << 4;
590#ifdef DEBUG 590#ifdef DEBUG