aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Turner <mattst88@gmail.com>2010-08-06 00:42:17 -0400
committerMatt Turner <mattst88@gmail.com>2011-01-25 13:27:09 -0500
commit68925334b09969f14c16eec0c1cde3a7e7585a52 (patch)
tree1f3bacb6d9c8434fed46d793200a17216a2a0a78
parent87cbc91d27ce87816af6204e1635318ca2cea655 (diff)
downloadglint-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.c251
-rw-r--r--drivers/gpu/drm/glint/glint_dac.c39
-rw-r--r--drivers/gpu/drm/glint/glint_drv.c2
-rw-r--r--drivers/gpu/drm/glint/glint_fbdev.c4
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)