]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
drm/mgag200: Add BMC output
authorThomas Zimmermann <tzimmermann@suse.de>
Mon, 10 Jun 2024 14:06:05 +0000 (16:06 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Thu, 13 Jun 2024 07:31:31 +0000 (09:31 +0200)
The BMC output can be viewed via the BMC's web interface or a
similar client. Represent it as virtual encoder and connector.
It's attached to the same CRTC as the VGA connector.

The connector's status depends on the physical connector's status.
The BMC is only connected if the physical connector is not. This
is necessary to support userspace clients that can only handle a
single output per CRTC.

The BMC is a server feature. Add a BMC output for all server chips,
but not the desktop models.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240610141141.29527-3-tzimmermann@suse.de
drivers/gpu/drm/mgag200/mgag200_bmc.c
drivers/gpu/drm/mgag200/mgag200_drv.h
drivers/gpu/drm/mgag200/mgag200_g200eh.c
drivers/gpu/drm/mgag200/mgag200_g200eh3.c
drivers/gpu/drm/mgag200/mgag200_g200er.c
drivers/gpu/drm/mgag200/mgag200_g200ev.c
drivers/gpu/drm/mgag200/mgag200_g200ew3.c
drivers/gpu/drm/mgag200/mgag200_g200se.c
drivers/gpu/drm/mgag200/mgag200_g200wb.c

index 2ba2e3c5086a55307d26be090458464f095552a6..23ef85aa7e3786646a57511fed3ec0fa5579c035 100644 (file)
@@ -2,8 +2,18 @@
 
 #include <linux/delay.h>
 
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_probe_helper.h>
+
 #include "mgag200_drv.h"
 
+static struct mgag200_bmc_connector *to_mgag200_bmc_connector(struct drm_connector *connector)
+{
+       return container_of(connector, struct mgag200_bmc_connector, base);
+}
+
 void mgag200_bmc_disable_vidrst(struct mga_device *mdev)
 {
        u8 tmp;
@@ -97,3 +107,100 @@ void mgag200_bmc_enable_vidrst(struct mga_device *mdev)
        tmp &= ~0x10;
        WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
 }
+
+static const struct drm_encoder_funcs mgag200_bmc_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
+};
+
+static int mgag200_bmc_connector_helper_detect_ctx(struct drm_connector *connector,
+                                                  struct drm_modeset_acquire_ctx *ctx,
+                                                  bool force)
+{
+       struct mgag200_bmc_connector *bmc_connector = to_mgag200_bmc_connector(connector);
+       struct drm_connector *physical_connector = bmc_connector->physical_connector;
+
+       /*
+        * Most user-space compositors cannot handle more than one connected
+        * connector per CRTC. Hence, we only mark the BMC as connected if the
+        * physical connector is disconnected. If the physical connector's status
+        * is connected or unknown, the BMC remains disconnected. This has no
+        * effect on the output of the BMC.
+        *
+        * FIXME: Remove this logic once user-space compositors can handle more
+        *        than one connector per CRTC. The BMC should always be connected.
+        */
+
+       if (physical_connector && physical_connector->status == connector_status_disconnected)
+               return connector_status_connected;
+
+       return connector_status_disconnected;
+}
+
+static int mgag200_bmc_connector_helper_get_modes(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct mga_device *mdev = to_mga_device(dev);
+       const struct mgag200_device_info *minfo = mdev->info;
+
+       return drm_add_modes_noedid(connector, minfo->max_hdisplay, minfo->max_vdisplay);
+}
+
+static const struct drm_connector_helper_funcs mgag200_bmc_connector_helper_funcs = {
+       .get_modes = mgag200_bmc_connector_helper_get_modes,
+       .detect_ctx = mgag200_bmc_connector_helper_detect_ctx,
+};
+
+static const struct drm_connector_funcs mgag200_bmc_connector_funcs = {
+       .reset = drm_atomic_helper_connector_reset,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = drm_connector_cleanup,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int mgag200_bmc_connector_init(struct drm_device *dev,
+                                     struct mgag200_bmc_connector *bmc_connector,
+                                     struct drm_connector *physical_connector)
+{
+       struct drm_connector *connector = &bmc_connector->base;
+       int ret;
+
+       ret = drm_connector_init(dev, connector, &mgag200_bmc_connector_funcs,
+                                DRM_MODE_CONNECTOR_VIRTUAL);
+       if (ret)
+               return ret;
+       drm_connector_helper_add(connector, &mgag200_bmc_connector_helper_funcs);
+
+       bmc_connector->physical_connector = physical_connector;
+
+       return 0;
+}
+
+int mgag200_bmc_output_init(struct mga_device *mdev, struct drm_connector *physical_connector)
+{
+       struct drm_device *dev = &mdev->base;
+       struct drm_crtc *crtc = &mdev->crtc;
+       struct drm_encoder *encoder;
+       struct mgag200_bmc_connector *bmc_connector;
+       struct drm_connector *connector;
+       int ret;
+
+       encoder = &mdev->output.bmc.encoder;
+       ret = drm_encoder_init(dev, encoder, &mgag200_bmc_encoder_funcs,
+                              DRM_MODE_ENCODER_VIRTUAL, NULL);
+       if (ret)
+               return ret;
+       encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+       bmc_connector = &mdev->output.bmc.bmc_connector;
+       ret = mgag200_bmc_connector_init(dev, bmc_connector, physical_connector);
+       if (ret)
+               return ret;
+       connector = &bmc_connector->base;
+
+       ret = drm_connector_attach_encoder(connector, encoder);
+       if (ret)
+               return ret;
+
+       return 0;
+}
index db89fddc26dcb918c5b87f4ed8332fa886d3e3ba..7f7dfbd0f0134da64d96110cf5ecb67b8128e4aa 100644 (file)
@@ -186,6 +186,11 @@ static inline struct mgag200_crtc_state *to_mgag200_crtc_state(struct drm_crtc_s
        return container_of(base, struct mgag200_crtc_state, base);
 }
 
+struct mgag200_bmc_connector {
+       struct drm_connector base;
+       struct drm_connector *physical_connector;
+};
+
 enum mga_type {
        G200_PCI,
        G200_AGP,
@@ -288,6 +293,10 @@ struct mga_device {
                        struct drm_encoder encoder;
                        struct drm_connector connector;
                } vga;
+               struct {
+                       struct drm_encoder encoder;
+                       struct mgag200_bmc_connector bmc_connector;
+               } bmc;
        } output;
 };
 
@@ -433,5 +442,6 @@ int mgag200_vga_output_init(struct mga_device *mdev);
                                /* mgag200_bmc.c */
 void mgag200_bmc_disable_vidrst(struct mga_device *mdev);
 void mgag200_bmc_enable_vidrst(struct mga_device *mdev);
+int mgag200_bmc_output_init(struct mga_device *mdev, struct drm_connector *physical_connector);
 
 #endif                         /* __MGAG200_DRV_H__ */
index df00b25efb895b7bb2ff503946d75ac721d9cbe5..6f31c5249f0b1ea16e656da7b6fd73bc3e01f330 100644 (file)
@@ -218,6 +218,10 @@ static int mgag200_g200eh_pipeline_init(struct mga_device *mdev)
        if (ret)
                return ret;
 
+       ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
index be42b1291e35754fe45eb9a55fc135ffdae5eb30..5befe8da4beb2032b809ab53d758927885828726 100644 (file)
@@ -122,6 +122,10 @@ static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev)
        if (ret)
                return ret;
 
+       ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
index 6f2c07af38c4f7df7ad686d8da0c98fabc5c0429..55c275180cde240f6b570b56769e1c65a7d29e12 100644 (file)
@@ -261,6 +261,10 @@ static int mgag200_g200er_pipeline_init(struct mga_device *mdev)
        if (ret)
                return ret;
 
+       ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
index 908d04d4c862c16a08b5d71d6ee37cc59440e241..2466126140db6c46de0505c2daa0e32133ad28b0 100644 (file)
@@ -262,6 +262,10 @@ static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)
        if (ret)
                return ret;
 
+       ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
index 8b69af543e2be9e8f27f020786f054c2396beeec..a52e60609c3de9d0db653c4786316dee94e3a62e 100644 (file)
@@ -131,6 +131,10 @@ static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
        if (ret)
                return ret;
 
+       ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
index 6d7fbdf62b97a10ae26822278a9c00bf1e99eb87..212770acdd477dc8ee7da2d3c8142071ea700ba1 100644 (file)
@@ -393,6 +393,10 @@ static int mgag200_g200se_pipeline_init(struct mga_device *mdev)
        if (ret)
                return ret;
 
+       ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
index 564d1f3ecc1087bc994d1500665900c409203e7f..cb6daa0426fbc41f8a8c6c2997961cc9f9f87cf5 100644 (file)
@@ -265,6 +265,10 @@ static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
        if (ret)
                return ret;
 
+       ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+       if (ret)
+               return ret;
+
        return 0;
 }