Hi!
I've written a small amount of code that gets the randr 1.2 branch much
closer to working for me on a laptop. Most of the changes are fairly
obvious, but a couple of comments:
1) The changes to nv_crtc.c are clearly bogus, but I'm not sure what on
earth these registers do. I need to set them to get a moderately
sane-looking picture
2) The fp registers poked in nv_output.c don't seem to do anything on
lvds. No matter what I set them to, the picture is identical
3) This doesn't /quite/ work for me yet. I have a solid and recognisable
picture, but it's only about the left two thirds of my screen, centred
on the display with black borders. Clearly the panel programming isn't
/quite/ right yet...
Signed-off-by: Matthew Garrett <mjg59 at srcf.ucam.org>
diff --git a/src/nv_crtc.c b/src/nv_crtc.c
index 5b646d0..3388a3a 100644
--- a/src/nv_crtc.c
+++ b/src/nv_crtc.c
@@ -945,8 +945,9 @@ nv_crtc_mode_set_regs(xf86CrtcPtr crtc, DisplayModePtr mode)
} else
regp->cursorConfig |= 0x02000000;
- regp->CRTC[NV_VGA_CRTCX_FP_HTIMING] = 0;
- regp->CRTC[NV_VGA_CRTCX_FP_VTIMING] = 0;
+ // FIXME: Figure out what these actually do
+ regp->CRTC[NV_VGA_CRTCX_FP_HTIMING] = 0xa;
+ regp->CRTC[NV_VGA_CRTCX_FP_VTIMING] = 0x2;
regp->unk830 = mode->CrtcVDisplay - 3;
regp->unk834 = mode->CrtcVDisplay - 1;
diff --git a/src/nv_output.c b/src/nv_output.c
index 9f72fd3..558aa5c 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -287,6 +287,23 @@ nv_output_mode_valid(xf86OutputPtr output, DisplayModePtr
pMode)
return MODE_OK;
}
+static int
+nv_output_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
+{
+ NVOutputPrivatePtr nv_output = output->driver_private;
+
+ if (pMode->Flags & V_DBLSCAN)
+ return MODE_NO_DBLESCAN;
+
+ if (pMode->Clock > 400000 || pMode->Clock < 25000)
+ return MODE_CLOCK_RANGE;
+
+ if (pMode->HDisplay > nv_output->fpWidth
+ || pMode->VDisplay > nv_output->fpHeight)
+ return MODE_PANEL;
+
+ return MODE_OK;
+}
static Bool
nv_output_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
@@ -351,27 +368,28 @@ nv_output_mode_set_regs(xf86OutputPtr output,
DisplayModePtr mode)
{
is_fp = TRUE;
- for (i = 0; i < 7; i++) {
+ if (nv_output->type == OUTPUT_DIGITAL) {
+ for (i = 0; i < 7; i++) {
regp->fp_horiz_regs[i] = savep->fp_horiz_regs[i];
regp->fp_vert_regs[i] = savep->fp_vert_regs[i];
+ }
+
+ regp->fp_horiz_regs[REG_DISP_END] = mode->CrtcHDisplay - 1;
+ regp->fp_horiz_regs[REG_DISP_TOTAL] = mode->CrtcHTotal - 1;
+ regp->fp_horiz_regs[REG_DISP_CRTC] = mode->CrtcHDisplay;
+ regp->fp_horiz_regs[REG_DISP_SYNC_START] = mode->CrtcHSyncStart - 1;
+ regp->fp_horiz_regs[REG_DISP_SYNC_END] = mode->CrtcHSyncEnd - 1;
+ regp->fp_horiz_regs[REG_DISP_VALID_START] = mode->CrtcHSkew;
+ regp->fp_horiz_regs[REG_DISP_VALID_END] = mode->CrtcHDisplay - 1;
+
+ regp->fp_vert_regs[REG_DISP_END] = mode->CrtcVDisplay - 1;
+ regp->fp_vert_regs[REG_DISP_TOTAL] = mode->CrtcVTotal - 1;
+ regp->fp_vert_regs[REG_DISP_CRTC] = mode->CrtcVDisplay;
+ regp->fp_vert_regs[REG_DISP_SYNC_START] = mode->CrtcVSyncStart - 1;
+ regp->fp_vert_regs[REG_DISP_SYNC_END] = mode->CrtcVSyncEnd - 1;
+ regp->fp_vert_regs[REG_DISP_VALID_START] = 0;
+ regp->fp_vert_regs[REG_DISP_VALID_END] = mode->CrtcVDisplay - 1;
}
-
- regp->fp_horiz_regs[REG_DISP_END] = mode->CrtcHDisplay - 1;
- regp->fp_horiz_regs[REG_DISP_TOTAL] = mode->CrtcHTotal - 1;
- regp->fp_horiz_regs[REG_DISP_CRTC] = mode->CrtcHDisplay;
- regp->fp_horiz_regs[REG_DISP_SYNC_START] = mode->CrtcHSyncStart - 1;
- regp->fp_horiz_regs[REG_DISP_SYNC_END] = mode->CrtcHSyncEnd - 1;
- regp->fp_horiz_regs[REG_DISP_VALID_START] = mode->CrtcHSkew;
- regp->fp_horiz_regs[REG_DISP_VALID_END] = mode->CrtcHDisplay - 1;
-
- regp->fp_vert_regs[REG_DISP_END] = mode->CrtcVDisplay - 1;
- regp->fp_vert_regs[REG_DISP_TOTAL] = mode->CrtcVTotal - 1;
- regp->fp_vert_regs[REG_DISP_CRTC] = mode->CrtcVDisplay;
- regp->fp_vert_regs[REG_DISP_SYNC_START] = mode->CrtcVSyncStart - 1;
- regp->fp_vert_regs[REG_DISP_SYNC_END] = mode->CrtcVSyncEnd - 1;
- regp->fp_vert_regs[REG_DISP_VALID_START] = 0;
- regp->fp_vert_regs[REG_DISP_VALID_END] = mode->CrtcVDisplay - 1;
-
}
if (pNv->Architecture >= NV_ARCH_10)
@@ -650,11 +668,11 @@ nv_output_lvds_get_modes(xf86OutputPtr output)
ScrnInfoPtr pScrn = output->scrn;
NVOutputPrivatePtr nv_output = output->driver_private;
- // nv_output->fpWidth = NVOutputReadRAMDAC(output,
NV_RAMDAC_FP_HDISP_END) + 1;
- // nv_output->fpHeight = NVOutputReadRAMDAC(output,
NV_RAMDAC_FP_VDISP_END) + 1;
+ nv_output->fpWidth = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_HDISP_END)
+ 1;
+ nv_output->fpHeight = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_VDISP_END)
+ 1;
nv_output->fpSyncs = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_CONTROL)
& 0x30000033;
- // xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x
%i\n",
- // nv_output->fpWidth, nv_output->fpHeight);
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x
%i\n",
+ nv_output->fpWidth, nv_output->fpHeight);
return NULL;
@@ -664,7 +682,7 @@ static const xf86OutputFuncsRec nv_lvds_output_funcs = {
.dpms = nv_panel_output_dpms,
.save = nv_output_save,
.restore = nv_output_restore,
- .mode_valid = nv_output_mode_valid,
+ .mode_valid = nv_output_lvds_mode_valid,
.mode_fixup = nv_output_mode_fixup,
.mode_set = nv_output_mode_set,
.detect = nv_output_lvds_detect,
@@ -707,6 +725,37 @@ static void nv_add_analog_output(ScrnInfoPtr pScrn, int
i2c_index)
pNv->analog_count++;
}
+static void nv_add_lvds_output(ScrnInfoPtr pScrn, int i2c_index)
+{
+ NVPtr pNv = NVPTR(pScrn);
+ xf86OutputPtr output;
+ NVOutputPrivatePtr nv_output;
+ char outputname[20];
+ int crtc_mask = (1<<0) | (1<<1);
+
+ sprintf(outputname, "LVDS-%d", pNv->lvds_count);
+ output = xf86OutputCreate (pScrn, &nv_lvds_output_funcs, outputname);
+ if (!output)
+ return;
+ nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
+ if (!nv_output)
+ {
+ xf86OutputDestroy (output);
+ return;
+ }
+
+ output->driver_private = nv_output;
+ nv_output->type = OUTPUT_PANEL;
+
+ nv_output->ramdac = pNv->lvds_count;
+
+ nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
+
+ output->possible_crtcs = crtc_mask;
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n",
outputname);
+
+ pNv->lvds_count++;
+}
static void nv_add_digital_output(ScrnInfoPtr pScrn, int i2c_index)
{
@@ -784,6 +833,9 @@ void NvDCBSetupOutputs(ScrnInfoPtr pScrn)
case 0: /* analog */
nv_add_analog_output(pScrn, port);
break;
+ case 1: /* panel */
+ nv_add_lvds_output(pScrn, port);
+ break;
case 2:
nv_add_digital_output(pScrn, port);
default:
diff --git a/src/nv_type.h b/src/nv_type.h
index fd5054f..fe18e38 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -309,6 +309,7 @@ typedef struct _NVRec {
int dcb_entries;
int analog_count;
+ int lvds_count;
int digital_count;
CARD32 dcb_table[NV40_NUM_DCB_ENTRIES]; /* 10 is a good limit */
} NVRec;
--
Matthew Garrett | mjg59 at srcf.ucam.org