diff options
author | Matt Turner <mattst88@gmail.com> | 2010-08-06 00:42:17 -0400 |
---|---|---|
committer | Matt Turner <mattst88@gmail.com> | 2011-01-25 13:27:09 -0500 |
commit | 68925334b09969f14c16eec0c1cde3a7e7585a52 (patch) | |
tree | 1f3bacb6d9c8434fed46d793200a17216a2a0a78 | |
parent | 87cbc91d27ce87816af6204e1635318ca2cea655 (diff) | |
download | glint-68925334b09969f14c16eec0c1cde3a7e7585a52.tar.gz |
drm/glint: program crtc and dac
Signed-off-by: Matt Turner <mattst88@gmail.com>
-rw-r--r-- | drivers/gpu/drm/glint/glint_crtc.c | 251 | ||||
-rw-r--r-- | drivers/gpu/drm/glint/glint_dac.c | 39 | ||||
-rw-r--r-- | drivers/gpu/drm/glint/glint_drv.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/glint/glint_fbdev.c | 4 |
4 files changed, 276 insertions, 20 deletions
diff --git a/drivers/gpu/drm/glint/glint_crtc.c b/drivers/gpu/drm/glint/glint_crtc.c index ea60d3711d732..4f842245ce7fa 100644 --- a/drivers/gpu/drm/glint/glint_crtc.c +++ b/drivers/gpu/drm/glint/glint_crtc.c @@ -29,8 +29,6 @@ static void glint_crtc_load_lut(struct drm_crtc *crtc) static void glint_crtc_dpms(struct drm_crtc *crtc, int mode) { struct glint_crtc *glint_crtc = to_glint_crtc(crtc); - struct drm_device *dev = crtc->dev; - struct glint_device *gdev = dev->dev_private; if (mode == glint_crtc->last_dpms) /* Don't do unnecesary mode changes. */ return; @@ -57,18 +55,246 @@ static bool glint_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static int glint_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - int x, int y, struct drm_framebuffer *old_fb) +static inline int glint_shift_bpp(unsigned bpp, int v) { /* - struct glint_crtc *glint_crtc = to_glint_crtc(crtc); + * the algorithm is + * (v * bpp) / 128 + * which simplifies to the following + */ + switch (bpp) { + case 8: + return (v >> 4); + case 16: + return (v >> 3); + case 32: + return (v >> 2); + } + GLINT_ERROR("Unsupported depth %u\n", bpp); + return 0; +} + +static void glint_compute_pll(unsigned long reqclock, + u8 *prescale, + u8 *feedback, + u8 *postscale) +{ + int f, pre, post; + unsigned long freq; + long freqerr = 1000; + long currerr; + + for (f = 1; f < 256; f++) { + for (pre = 1; pre < 256; pre++) { + for (post = 0; post < 5; post++) { + freq = ((2*PM3_REF_CLOCK * f) >> post) / pre; + currerr = (reqclock > freq) ? reqclock - freq + : freq - reqclock; + if (currerr < freqerr) { + freqerr = currerr; + *feedback = f; + *prescale = pre; + *postscale = post; + } + } + } + } +} + +static unsigned long +PM3DAC_CalculateClock(unsigned long ReqClock, /* In kHz units */ + unsigned char *prescale, /* ClkPreScale */ + unsigned char *feedback, /* ClkFeedBackScale */ + unsigned char *postscale /* ClkPostScale */ + ) +{ + unsigned long fMinVCO = 2000000; /* min fVCO is 200MHz (in 100Hz units) */ + unsigned long fMaxVCO = 6220000; /* max fVCO is 622MHz (in 100Hz units) */ + unsigned long fMinINTREF = 10000;/* min fINTREF is 1MHz (in 100Hz units) */ + unsigned long fMaxINTREF = 20000;/* max fINTREF is 2MHz (in 100Hz units) */ + unsigned long M, N, P; /* M=feedback, N=prescale, P=postscale */ + unsigned long fINTREF; + unsigned long fVCO; + unsigned long ActualClock; + unsigned long RefClock = PM3_REF_CLOCK; + long Error; + unsigned long LowestError = 1000000; + unsigned int bFoundFreq = false; + int cInnerLoopIterations = 0; + int LoopCount; + unsigned long ClosestClock = 0; + + ReqClock*=10; /* convert into 100Hz units */ + RefClock*=10; /* convert into 100Hz units */ + + for(P = 0; P <= 5; ++P) + { + unsigned long fVCOLowest, fVCOHighest; + + /* it is pointless going through the main loop if all values of + * N produce an fVCO outside the acceptable range */ + N = 1; + M = (N * (1UL << P) * ReqClock) / (2 * RefClock); + fVCOLowest = (2 * RefClock * M) / N; + N = 255; + M = (N * (1UL << P) * ReqClock) / (2 * RefClock); + fVCOHighest = (2 * RefClock * M) / N; + + if(fVCOHighest < fMinVCO || fVCOLowest > fMaxVCO) + { + continue; + } + + for(N = 1; N <= 255; ++N, ++cInnerLoopIterations) + { + fINTREF = RefClock / N; + if(fINTREF < fMinINTREF || fINTREF > fMaxINTREF) + { + if(fINTREF > fMaxINTREF) + { + /* hopefully we will get into range as the prescale + * value increases */ + continue; + } + else + { + /* already below minimum and it will only get worse: + * move to the next postscale value */ + break; + } + } + + M = (N * (1UL << P) * ReqClock) / (2 * RefClock); + if(M > 255) + { + /* M, N & P registers are only 8 bits wide */ + break; + } + + /* we can expect rounding errors in calculating M, which + * will always be rounded down. So we will checkout our + * calculated value of M along with (M+1) */ + for(LoopCount = (M == 255) ? 1 : 2; --LoopCount >= 0; ++M) + { + fVCO = (2 * RefClock * M) / N; + if(fVCO >= fMinVCO && fVCO <= fMaxVCO) + { + ActualClock = fVCO / (1UL << P); + Error = ActualClock - ReqClock; + if(Error < 0) + Error = -Error; + if(Error < LowestError) + { + bFoundFreq = true; + LowestError = Error; + ClosestClock = ActualClock; + *prescale = N; + *feedback = M; + *postscale = P; + if(Error == 0) + goto Done; + } + } + } + } + } +Done: + if(bFoundFreq) + ActualClock = ClosestClock; + else + ActualClock = 0; + + GLINT_INFO("PM3DAC_CalculateClock: Got prescale=%d, feedback=%d, postscale=%d, WantedClock = %lu00Hz ActualClock = %lu00Hz (Error %lu00Hz)\n", + *prescale, *feedback, *postscale, ReqClock, ActualClock, LowestError); + return(ActualClock); +} + +static int glint_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct glint_device *gdev = dev->dev_private; + int bpp = crtc->fb->bits_per_pixel; + + WREG32(PM3MemBypassWriteMask, 0xffffffff); + WREG32(PM3Aperture0, 0x00000000); + WREG32(PM3Aperture1, 0x00000000); + +#define PM3FIFODis_INPUT (1 << 0) +#define PM3FIFODis_OUTPUT (1 << 1) +#define PM3FIFODis_TEXTURE (1 << 2) + WREG32(PM3FIFODis, PM3FIFODis_INPUT | PM3FIFODis_OUTPUT | PM3FIFODis_TEXTURE); + + WREG32(PM3HTotal, glint_shift_bpp(bpp, mode->htotal - 1)); + WREG32(PM3HsEnd, glint_shift_bpp(bpp, mode->hsync_end - mode->hdisplay)); + WREG32(PM3HsStart, glint_shift_bpp(bpp, mode->hsync_start - mode->hdisplay)); + WREG32(PM3HbEnd, glint_shift_bpp(bpp, mode->htotal - mode->hdisplay)); + WREG32(PM3HgEnd, glint_shift_bpp(bpp, mode->htotal - mode->hdisplay)); + WREG32(PM3ScreenStride, glint_shift_bpp(bpp, crtc->fb->width)); + WREG32(PM3VTotal, mode->vtotal - 1); + WREG32(PM3VsEnd, mode->vsync_end - mode->vdisplay - 1); + WREG32(PM3VsStart, mode->vsync_start - mode->vdisplay - 1); + WREG32(PM3VbEnd, mode->vtotal - mode->vdisplay); + + switch (bpp) { + case 8: + WREG32(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_8BIT); + WREG32(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_8BIT); + break; + case 16: +#ifndef __BIG_ENDIAN + WREG32(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_16BIT); + WREG32(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_16BIT); +#else + WREG32(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_16BIT | PM3ByApertureMode_BYTESWAP_BADC); + WREG32(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_16BIT | PM3ByApertureMode_BYTESWAP_BADC); +#endif /* ! __BIG_ENDIAN */ + break; + case 32: +#ifndef __BIG_ENDIAN + WREG32(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_32BIT); + WREG32(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_32BIT); +#else + WREG32(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_32BIT | PM3ByApertureMode_BYTESWAP_DCBA); + WREG32(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_32BIT | PM3ByApertureMode_BYTESWAP_DCBA); +#endif /* ! __BIG_ENDIAN */ + break; + default: + GLINT_ERROR("%s: Unsupported depth %d\n", __func__, bpp); + return -1; + } + + WREG32(PM3VideoControl, PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH | + PM3VideoControl_VSYNC_ACTIVE_HIGH | + PM3VideoControl_PIXELSIZE_32BIT); + WREG32(PM3ScreenBase, 0); +#define PM3ChipConfig_DISABLE_SVGA (0 << 1) +#define PM3ChipConfig_ENABLE_SVGA (1 << 1) + WREG32(PM3ChipConfig, RREG32(PM3ChipConfig) & ~PM3ChipConfig_ENABLE_SVGA); + + wmb(); + { + u8 uninitialized_var(prescale); + u8 uninitialized_var(feedback); + u8 uninitialized_var(postscale); + + { + u8 uninitialized_var(prescale); + u8 uninitialized_var(feedback); + u8 uninitialized_var(postscale); + + glint_compute_pll(adjusted_mode->clock, &prescale, &feedback, &postscale); + GLINT_INFO("glint_compute_pll got prescale=%d feedback=%d postscale=%d\n", prescale, feedback, postscale); + } + PM3DAC_CalculateClock(adjusted_mode->clock, &prescale, &feedback, &postscale); + WREG_DAC(PM3RD_DClk0PreScale, prescale); + WREG_DAC(PM3RD_DClk0FeedbackScale, feedback); + WREG_DAC(PM3RD_DClk0PostScale, postscale); + } - glint_crtc_set_base(crtc, x, y, old_fb); - glint_set_crtc_timing(crtc, adjusted_mode); - glint_set_pll(crtc, adjusted_mode); - */ return 0; } @@ -134,9 +360,6 @@ static const struct drm_crtc_helper_funcs glint_helper_funcs = { .dpms = glint_crtc_dpms, .mode_fixup = glint_crtc_mode_fixup, .mode_set = glint_crtc_mode_set, - /* - .mode_set_base = glint_crtc_set_base, - */ .prepare = glint_crtc_prepare, .commit = glint_crtc_commit, .load_lut = glint_crtc_load_lut, diff --git a/drivers/gpu/drm/glint/glint_dac.c b/drivers/gpu/drm/glint/glint_dac.c index de495f1d0a553..779ef6b7902cc 100644 --- a/drivers/gpu/drm/glint/glint_dac.c +++ b/drivers/gpu/drm/glint/glint_dac.c @@ -26,7 +26,7 @@ static void glint_dac_dpms(struct drm_encoder *encoder, int mode) WREG_DAC(PM3RD_DACControl, PM3RD_DACControl_DAC_POWER_OFF); break; case DRM_MODE_DPMS_ON: - WREG_DAC(PM3RD_DACControl, PM3RD_DACControl_DAC_POWER_OFF); + WREG_DAC(PM3RD_DACControl, PM3RD_DACControl_DAC_POWER_ON); break; } } @@ -42,7 +42,42 @@ static void glint_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct drm_device *dev = encoder->dev; + struct glint_device *gdev = dev->dev_private; + int bpp = encoder->crtc->fb->bits_per_pixel; + u8 uninitialized_var(pixelsize); + u8 uninitialized_var(colorformat); + u8 misccontrol = PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; + + switch (bpp) { + case 8: + pixelsize = PM3RD_PixelSize_8_BIT_PIXELS; + colorformat = PM3RD_ColorFormat_CI8_COLOR | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW; + break; + case 16: + pixelsize = PM3RD_PixelSize_16_BIT_PIXELS; + colorformat = PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE; + if (encoder->crtc->fb->depth == 15) + colorformat |= PM3RD_ColorFormat_5551_FRONT_COLOR; + else + colorformat |= PM3RD_ColorFormat_565_FRONT_COLOR; + misccontrol |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE; + break; + case 32: + pixelsize = PM3RD_PixelSize_32_BIT_PIXELS; + colorformat = PM3RD_ColorFormat_8888_COLOR | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW; + misccontrol |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE; + break; + default: + GLINT_ERROR("%s: Unsupported depth %d\n", __func__, bpp); + return; + } + WREG_DAC(PM3RD_SyncControl, 0); + WREG_DAC(PM3RD_DACControl, PM3RD_DACControl_DAC_POWER_ON); + WREG_DAC(PM3RD_PixelSize, pixelsize); + WREG_DAC(PM3RD_ColorFormat, colorformat); + WREG_DAC(PM3RD_MiscControl, misccontrol); } static void glint_dac_prepare(struct drm_encoder *encoder) @@ -52,7 +87,7 @@ static void glint_dac_prepare(struct drm_encoder *encoder) static void glint_dac_commit(struct drm_encoder *encoder) { - glint_dac_dpms(encoder, DRM_MODE_DPMS_ON); + /* DAC turned back on in glint_dac_mode_set() */ } void glint_encoder_destroy(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/glint/glint_drv.c b/drivers/gpu/drm/glint/glint_drv.c index 24f78a920ff78..361db264181ba 100644 --- a/drivers/gpu/drm/glint/glint_drv.c +++ b/drivers/gpu/drm/glint/glint_drv.c @@ -65,7 +65,6 @@ static struct drm_driver driver = { static int __init glint_init(void) { - printk(KERN_INFO "Hello, GLint\n"); driver.num_ioctls = glint_max_ioctl; return drm_init(&driver); @@ -74,7 +73,6 @@ glint_init(void) static void __exit glint_exit(void) { - printk(KERN_INFO "Bye, GLint\n"); drm_exit(&driver); } diff --git a/drivers/gpu/drm/glint/glint_fbdev.c b/drivers/gpu/drm/glint/glint_fbdev.c index faec453e472b4..0d02b51a82780 100644 --- a/drivers/gpu/drm/glint/glint_fbdev.c +++ b/drivers/gpu/drm/glint/glint_fbdev.c @@ -175,9 +175,9 @@ int glint_fbdev_init(struct glint_device *gdev) int bpp_sel = 32; int ret; - /* select 8 bpp console on <= 32 MB cards */ + /* select 16 bpp console on <= 32 MB cards */ if (gdev->mc.vram_size <= (32 * MB)) - bpp_sel = 8; + bpp_sel = 16; gfbdev = kzalloc(sizeof(struct glint_fbdev), GFP_KERNEL); if (!gfbdev) |