From: Dave Airlie <airl...@redhat.com>

Some GPUs (mostly in the lower server end of the market) have memory
bandwidth limitations that hit in the real world, however memory
bw calcs require bit depth to be worked out and at the moment, the
KMS interface doesn't know about bit depth until we set the mode.

This "overloads" the connector_type_id in the get connector ioctl
to pass a depth value to the kernel code. A new libdrm API is added
to utilise this. libdrm has always set this to 0 up until now.

This depth value is what the kms user proposed to use, the actual
API in libdrm is drmModeGetConnectorWithDepth and will follow
along.

This patch also adds RN50 support to the radeon kms to check
the memory bandwidth calcs and refuse the higher modes on these
chips.

Signed-off-by: Dave Airlie <airl...@redhat.com>
---
 drivers/gpu/drm/drm_crtc.c                 |    3 ++
 drivers/gpu/drm/drm_modes.c                |   16 +++++++++++
 drivers/gpu/drm/radeon/radeon_connectors.c |   39 ++++++++++++---------------
 include/drm/drm_crtc.h                     |    4 +++
 include/drm/drm_mode.h                     |    2 +
 5 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5cae0b3..c86a99b 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1296,6 +1296,9 @@ int drm_mode_getconnector(struct drm_device *dev, void 
*data,
        }
 
        if (out_resp->count_modes == 0) {
+               /* set the proposed depth up */
+               if (out_resp->connector_type_id)
+                       connector->proposed_depth = out_resp->connector_type_id;
                connector->funcs->fill_modes(connector,
                                             dev->mode_config.max_width,
                                             dev->mode_config.max_height);
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 51f6772..2cd9d9d 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -553,6 +553,22 @@ int drm_mode_height(struct drm_display_mode *mode)
 }
 EXPORT_SYMBOL(drm_mode_height);
 
+u32 drm_mode_bandwidth(struct drm_display_mode *mode, int depth)
+{
+       u32 a_active, a_total, active_percent, pixels_per_second;
+       int bytes_per_pixel = depth / 8;
+
+       if (!mode->htotal || !mode->vtotal || !mode->clock)
+               return 0;
+
+       a_active = mode->hdisplay * mode->vdisplay;
+       a_total = mode->htotal * mode->vtotal;
+       active_percent = (a_active * 1000) / a_total;
+       pixels_per_second = active_percent * mode->clock;
+       return (u32)(pixels_per_second * bytes_per_pixel / (1024 * 1024));
+}
+EXPORT_SYMBOL(drm_mode_bandwidth);
+
 /**
  * drm_mode_vrefresh - get the vrefresh of a mode
  * @mode: mode
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c 
b/drivers/gpu/drm/radeon/radeon_connectors.c
index 17d5659..35b3858 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -40,6 +40,19 @@ radeon_atombios_connected_scratch_regs(struct drm_connector 
*connector,
                                       struct drm_encoder *encoder,
                                       bool connected);
 
+static int radeon_connector_mode_valid(struct drm_connector *connector,
+                                      struct drm_display_mode *mode)
+{
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+       if (ASIC_IS_RN50(rdev)) {
+               if (drm_mode_bandwidth(mode, connector->proposed_depth) > 300)
+                       return MODE_BANDWIDTH;
+       }
+       return MODE_OK;
+}
+
 static void radeon_property_change_mode(struct drm_encoder *encoder)
 {
        struct drm_crtc *crtc = encoder->crtc;
@@ -390,12 +403,6 @@ static int radeon_lvds_get_modes(struct drm_connector 
*connector)
        return ret;
 }
 
-static int radeon_lvds_mode_valid(struct drm_connector *connector,
-                                 struct drm_display_mode *mode)
-{
-       return MODE_OK;
-}
-
 static enum drm_connector_status radeon_lvds_detect(struct drm_connector 
*connector)
 {
        struct radeon_connector *radeon_connector = 
to_radeon_connector(connector);
@@ -477,7 +484,7 @@ static int radeon_lvds_set_property(struct drm_connector 
*connector,
 
 struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
        .get_modes = radeon_lvds_get_modes,
-       .mode_valid = radeon_lvds_mode_valid,
+       .mode_valid = radeon_connector_mode_valid,
        .best_encoder = radeon_best_single_encoder,
 };
 
@@ -499,12 +506,6 @@ static int radeon_vga_get_modes(struct drm_connector 
*connector)
        return ret;
 }
 
-static int radeon_vga_mode_valid(struct drm_connector *connector,
-                                 struct drm_display_mode *mode)
-{
-       return MODE_OK;
-}
-
 static enum drm_connector_status radeon_vga_detect(struct drm_connector 
*connector)
 {
        struct radeon_connector *radeon_connector = 
to_radeon_connector(connector);
@@ -537,7 +538,7 @@ static enum drm_connector_status radeon_vga_detect(struct 
drm_connector *connect
 
 struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
        .get_modes = radeon_vga_get_modes,
-       .mode_valid = radeon_vga_mode_valid,
+       .mode_valid = radeon_connector_mode_valid,
        .best_encoder = radeon_best_single_encoder,
 };
 
@@ -573,12 +574,6 @@ static int radeon_tv_get_modes(struct drm_connector 
*connector)
        return 1;
 }
 
-static int radeon_tv_mode_valid(struct drm_connector *connector,
-                               struct drm_display_mode *mode)
-{
-       return MODE_OK;
-}
-
 static enum drm_connector_status radeon_tv_detect(struct drm_connector 
*connector)
 {
        struct drm_encoder *encoder;
@@ -604,7 +599,7 @@ static enum drm_connector_status radeon_tv_detect(struct 
drm_connector *connecto
 
 struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
        .get_modes = radeon_tv_get_modes,
-       .mode_valid = radeon_tv_mode_valid,
+       .mode_valid = radeon_connector_mode_valid,
        .best_encoder = radeon_best_single_encoder,
 };
 
@@ -761,7 +756,7 @@ static void radeon_dvi_force(struct drm_connector 
*connector)
 
 struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
        .get_modes = radeon_dvi_get_modes,
-       .mode_valid = radeon_vga_mode_valid,
+       .mode_valid = radeon_connector_mode_valid,
        .best_encoder = radeon_dvi_encoder,
 };
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index b69347b..754af06 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -94,6 +94,7 @@ enum drm_mode_status {
     MODE_ONE_HEIGHT,    /* only one height is supported */
     MODE_ONE_SIZE,      /* only one resolution is supported */
     MODE_NO_REDUCED,    /* monitor doesn't accept reduced blanking */
+    MODE_BANDWIDTH,    /* mode requires too much memory bandwidth */
     MODE_UNVERIFIED = -3, /* mode needs to reverified */
     MODE_BAD = -2,     /* unspecified reason */
     MODE_ERROR = -1    /* error condition */
@@ -493,6 +494,8 @@ struct drm_connector {
        uint32_t force_encoder_id;
        struct drm_encoder *encoder; /* currently active encoder */
        void *fb_helper_private;
+
+       uint32_t proposed_depth; /* depth to be used in mode bw calcs */
 };
 
 /**
@@ -650,6 +653,7 @@ extern void drm_mode_set_name(struct drm_display_mode 
*mode);
 extern bool drm_mode_equal(struct drm_display_mode *mode1, struct 
drm_display_mode *mode2);
 extern int drm_mode_width(struct drm_display_mode *mode);
 extern int drm_mode_height(struct drm_display_mode *mode);
+extern u32 drm_mode_bandwidth(struct drm_display_mode *mode, int depth);
 
 /* for us by fb module */
 extern int drm_mode_attachmode_crtc(struct drm_device *dev,
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 1f90841..c14dba2 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -173,6 +173,8 @@ struct drm_mode_get_connector {
        __u32 encoder_id; /**< Current Encoder */
        __u32 connector_id; /**< Id */
        __u32 connector_type;
+       /* connector type id is also used an input for the proposed
+          depth - all libdrm pass in 0 for this up until this change */
        __u32 connector_type_id;
 
        __u32 connection;
-- 
1.6.5.rc2


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to