}
 EXPORT_SYMBOL(drm_rect_intersect);
 
+static u32 clip_scaled(u32 src, u32 dst, u32 clip)
+{
+       u64 tmp = mul_u32_u32(src, dst - clip);
+
+       /*
+        * Round toward 1.0 when clipping so that we don't accidentally
+        * change upscaling to downscaling or vice versa.
+        */
+       if (src < (dst << 16))
+               return DIV_ROUND_UP_ULL(tmp, dst);
+       else
+               return DIV_ROUND_DOWN_ULL(tmp, dst);
+}
+
 /**
  * drm_rect_clip_scaled - perform a scaled clip operation
  * @src: source window rectangle
  * @dst: destination window rectangle
  * @clip: clip rectangle
- * @hscale: horizontal scaling factor
- * @vscale: vertical scaling factor
  *
  * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the
  * same amounts multiplied by @hscale and @vscale.
  * %false otherwise
  */
 bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
-                         const struct drm_rect *clip,
-                         int hscale, int vscale)
+                         const struct drm_rect *clip)
 {
        int diff;
 
        diff = clip->x1 - dst->x1;
        if (diff > 0) {
-               int64_t tmp = src->x1 + (int64_t) diff * hscale;
-               src->x1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
+               u32 new_src_w = clip_scaled(drm_rect_width(src),
+                                           drm_rect_width(dst), diff);
+
+               src->x1 = clamp_t(int64_t, src->x2 - new_src_w, INT_MIN, INT_MAX);
+               dst->x1 = clip->x1;
        }
        diff = clip->y1 - dst->y1;
        if (diff > 0) {
-               int64_t tmp = src->y1 + (int64_t) diff * vscale;
-               src->y1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
+               u32 new_src_h = clip_scaled(drm_rect_height(src),
+                                           drm_rect_height(dst), diff);
+
+               src->y1 = clamp_t(int64_t, src->y2 - new_src_h, INT_MIN, INT_MAX);
+               dst->y1 = clip->y1;
        }
        diff = dst->x2 - clip->x2;
        if (diff > 0) {
-               int64_t tmp = src->x2 - (int64_t) diff * hscale;
-               src->x2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
+               u32 new_src_w = clip_scaled(drm_rect_width(src),
+                                           drm_rect_width(dst), diff);
+
+               src->x2 = clamp_t(int64_t, src->x1 + new_src_w, INT_MIN, INT_MAX);
+               dst->x2 = clip->x2;
        }
        diff = dst->y2 - clip->y2;
        if (diff > 0) {
-               int64_t tmp = src->y2 - (int64_t) diff * vscale;
-               src->y2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
+               u32 new_src_h = clip_scaled(drm_rect_height(src),
+                                           drm_rect_height(dst), diff);
+
+               src->y2 = clamp_t(int64_t, src->y1 + new_src_h, INT_MIN, INT_MAX);
+               dst->y2 = clip->y2;
        }
 
-       return drm_rect_intersect(dst, clip);
+       return drm_rect_visible(dst);
 }
 EXPORT_SYMBOL(drm_rect_clip_scaled);