// SPDX-License-Identifier: GPL-2.0 /* * ATI Mach64 CT/VT/GT/LT Support */ #include <linux/fb.h> #include <linux/delay.h> #include <asm/io.h> #include <video/mach64.h> #include "atyfb.h" #ifdef CONFIG_PPC #include <asm/machdep.h> #endif #undef DEBUG static int aty_valid_pll_ct (const struct fb_info *info, u32 vclk_per, struct pll_ct *pll); static int aty_dsp_gt (const struct fb_info *info, u32 bpp, struct pll_ct *pll); static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll); static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll); u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par) { … } static void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par) { … } /* * by Daniel Mantione * <[email protected]> * * * ATI Mach64 CT clock synthesis description. * * All clocks on the Mach64 can be calculated using the same principle: * * XTALIN * x * FB_DIV * CLK = ---------------------- * PLL_REF_DIV * POST_DIV * * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz. * PLL_REF_DIV can be set by the user, but is the same for all clocks. * FB_DIV can be set by the user for each clock individually, it should be set * between 128 and 255, the chip will generate a bad clock signal for too low * values. * x depends on the type of clock; usually it is 2, but for the MCLK it can also * be set to 4. * POST_DIV can be set by the user for each clock individually, Possible values * are 1,2,4,8 and for some clocks other values are available too. * CLK is of course the clock speed that is generated. * * The Mach64 has these clocks: * * MCLK The clock rate of the chip * XCLK The clock rate of the on-chip memory * VCLK0 First pixel clock of first CRT controller * VCLK1 Second pixel clock of first CRT controller * VCLK2 Third pixel clock of first CRT controller * VCLK3 Fourth pixel clock of first CRT controller * VCLK Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3 * V2CLK Pixel clock of the second CRT controller. * SCLK Multi-purpose clock * * - MCLK and XCLK use the same FB_DIV * - VCLK0 .. VCLK3 use the same FB_DIV * - V2CLK is needed when the second CRTC is used (can be used for dualhead); * i.e. CRT monitor connected to laptop has different resolution than built * in LCD monitor. * - SCLK is not available on all cards; it is know to exist on the Rage LT-PRO, * Rage XL and Rage Mobility. It is know not to exist on the Mach64 VT. * - V2CLK is not available on all cards, most likely only the Rage LT-PRO, * the Rage XL and the Rage Mobility * * SCLK can be used to: * - Clock the chip instead of MCLK * - Replace XTALIN with a user defined frequency * - Generate the pixel clock for the LCD monitor (instead of VCLK) */ /* * It can be quite hard to calculate XCLK and MCLK if they don't run at the * same frequency. Luckily, until now all cards that need asynchrone clock * speeds seem to have SCLK. * So this driver uses SCLK to clock the chip and XCLK to clock the memory. */ /* ------------------------------------------------------------------------- */ /* * PLL programming (Mach64 CT family) * * * This procedure sets the display fifo. The display fifo is a buffer that * contains data read from the video memory that waits to be processed by * the CRT controller. * * On the more modern Mach64 variants, the chip doesn't calculate the * interval after which the display fifo has to be reloaded from memory * automatically, the driver has to do it instead. */ #define Maximum_DSP_PRECISION … const u8 aty_postdividers[8] = …; static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll) { … } static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll_ct *pll) { … } static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll) { … } static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll) { … } void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll) { … } static void aty_get_pll_ct(const struct fb_info *info, union aty_pll *pll) { … } static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll) { … } static void aty_resume_pll_ct(const struct fb_info *info, union aty_pll *pll) { … } static int dummy(void) { … } const struct aty_dac_ops aty_dac_ct = …; const struct aty_pll_ops aty_pll_ct = …;