diff --git a/drivers/gpu/drm/mgag200/mgag200_bmc.c b/drivers/gpu/drm/mgag200/mgag200_bmc.c index 2ba2e3c5086a..23ef85aa7e37 100644 --- a/drivers/gpu/drm/mgag200/mgag200_bmc.c +++ b/drivers/gpu/drm/mgag200/mgag200_bmc.c @@ -2,8 +2,18 @@ #include +#include +#include +#include +#include + #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; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index db89fddc26dc..7f7dfbd0f013 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -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__ */ diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index df00b25efb89..6f31c5249f0b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -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; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index be42b1291e35..5befe8da4beb 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -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; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index 6f2c07af38c4..55c275180cde 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -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; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index 908d04d4c862..2466126140db 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -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; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 8b69af543e2b..a52e60609c3d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -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; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index 6d7fbdf62b97..212770acdd47 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -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; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index 564d1f3ecc10..cb6daa0426fb 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -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; }