diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-11-11 08:49:06 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-12-21 04:01:35 -0500 |
commit | 9285462273cbccb27187d5308ed95f94a9ceb1de (patch) | |
tree | 6e0387a457a46141dcd65183c679dfa3b38665fb /drivers/gpu/drm/nouveau | |
parent | 2d1d898b4684ab86fb27ece7d69e4e145a7be9d2 (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.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvd0_display.c | 94 |
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 | ||
163 | static struct drm_prop_enum_list underscan[] = { | 163 | static 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) | |||
160 | static int | 160 | static int |
161 | nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) | 161 | nvd0_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); |