aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-11-11 08:49:06 -0500
committerBen Skeggs <bskeggs@redhat.com>2011-12-21 04:01:35 -0500
commit9285462273cbccb27187d5308ed95f94a9ceb1de (patch)
tree6e0387a457a46141dcd65183c679dfa3b38665fb /drivers/gpu/drm/nouveau
parent2d1d898b4684ab86fb27ece7d69e4e145a7be9d2 (diff)
drm/nvd0/disp: scaler updates, overscan compensation etc
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvd0_display.c94
2 files changed, 67 insertions, 33 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 6ac6931624f4..fdeb64a3a84d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -161,9 +161,9 @@ struct drm_prop_enum_list {
161}; 161};
162 162
163static struct drm_prop_enum_list underscan[] = { 163static struct drm_prop_enum_list underscan[] = {
164 { 2, UNDERSCAN_AUTO, "auto" }, 164 { 6, UNDERSCAN_AUTO, "auto" },
165 { 2, UNDERSCAN_OFF, "off" }, 165 { 6, UNDERSCAN_OFF, "off" },
166 { 2, UNDERSCAN_ON, "on" }, 166 { 6, UNDERSCAN_ON, "on" },
167 {} 167 {}
168}; 168};
169 169
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index 7c2defdcc8f3..dcfe6192e5c4 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -160,49 +160,83 @@ nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
160static int 160static int
161nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) 161nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
162{ 162{
163 struct drm_display_mode *mode = &nv_crtc->base.mode; 163 struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
164 struct drm_device *dev = nv_crtc->base.dev; 164 struct drm_device *dev = nv_crtc->base.dev;
165 struct nouveau_connector *nv_connector; 165 struct nouveau_connector *nv_connector;
166 u32 *push, outX, outY; 166 int mode = DRM_MODE_SCALE_NONE;
167 167 u32 oX, oY, *push;
168 outX = mode->hdisplay;
169 outY = mode->vdisplay;
170 168
169 /* start off at the resolution we programmed the crtc for, this
170 * effectively handles NONE/FULL scaling
171 */
171 nv_connector = nouveau_crtc_connector_get(nv_crtc); 172 nv_connector = nouveau_crtc_connector_get(nv_crtc);
172 if (nv_connector && nv_connector->native_mode) { 173 if (nv_connector && nv_connector->native_mode)
173 struct drm_display_mode *native = nv_connector->native_mode; 174 mode = nv_connector->scaling_mode;
174 u32 xratio = (native->hdisplay << 19) / mode->hdisplay; 175
175 u32 yratio = (native->vdisplay << 19) / mode->vdisplay; 176 if (mode != DRM_MODE_SCALE_NONE)
176 177 omode = nv_connector->native_mode;
177 switch (nv_connector->scaling_mode) { 178 else
178 case DRM_MODE_SCALE_ASPECT: 179 omode = umode;
179 if (xratio > yratio) { 180
180 outX = (mode->hdisplay * yratio) >> 19; 181 oX = omode->hdisplay;
181 outY = (mode->vdisplay * yratio) >> 19; 182 oY = omode->vdisplay;
182 } else { 183 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
183 outX = (mode->hdisplay * xratio) >> 19; 184 oY *= 2;
184 outY = (mode->vdisplay * xratio) >> 19; 185
185 } 186 /* add overscan compensation if necessary, will keep the aspect
186 break; 187 * ratio the same as the backend mode unless overridden by the
187 case DRM_MODE_SCALE_FULLSCREEN: 188 * user setting both hborder and vborder properties.
188 outX = native->hdisplay; 189 */
189 outY = native->vdisplay; 190 if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
190 break; 191 (nv_connector->underscan == UNDERSCAN_AUTO &&
191 default: 192 nv_connector->edid &&
192 break; 193 drm_detect_hdmi_monitor(nv_connector->edid)))) {
194 u32 bX = nv_connector->underscan_hborder;
195 u32 bY = nv_connector->underscan_vborder;
196 u32 aspect = (oY << 19) / oX;
197
198 if (bX) {
199 oX -= (bX * 2);
200 if (bY) oY -= (bY * 2);
201 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
202 } else {
203 oX -= (oX >> 4) + 32;
204 if (bY) oY -= (bY * 2);
205 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
193 } 206 }
194 } 207 }
195 208
209 /* handle CENTER/ASPECT scaling, taking into account the areas
210 * removed already for overscan compensation
211 */
212 switch (mode) {
213 case DRM_MODE_SCALE_CENTER:
214 oX = min((u32)umode->hdisplay, oX);
215 oY = min((u32)umode->vdisplay, oY);
216 /* fall-through */
217 case DRM_MODE_SCALE_ASPECT:
218 if (oY < oX) {
219 u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
220 oX = ((oY * aspect) + (aspect / 2)) >> 19;
221 } else {
222 u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
223 oY = ((oX * aspect) + (aspect / 2)) >> 19;
224 }
225 break;
226 default:
227 break;
228 }
229
196 push = evo_wait(dev, 0, 16); 230 push = evo_wait(dev, 0, 16);
197 if (push) { 231 if (push) {
198 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3); 232 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
199 evo_data(push, (outY << 16) | outX); 233 evo_data(push, (oY << 16) | oX);
200 evo_data(push, (outY << 16) | outX); 234 evo_data(push, (oY << 16) | oX);
201 evo_data(push, (outY << 16) | outX); 235 evo_data(push, (oY << 16) | oX);
202 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1); 236 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
203 evo_data(push, 0x00000000); 237 evo_data(push, 0x00000000);
204 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1); 238 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
205 evo_data(push, (mode->vdisplay << 16) | mode->hdisplay); 239 evo_data(push, (umode->vdisplay << 16) | umode->hdisplay);
206 if (update) { 240 if (update) {
207 evo_mthd(push, 0x0080, 1); 241 evo_mthd(push, 0x0080, 1);
208 evo_data(push, 0x00000000); 242 evo_data(push, 0x00000000);