1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/delay.h> 4 5 #include <drm/drm_atomic_helper.h> 6 #include <drm/drm_edid.h> 7 #include <drm/drm_managed.h> 8 #include <drm/drm_probe_helper.h> 9 10 #include "mgag200_drv.h" 11 12 static struct mgag200_bmc_connector *to_mgag200_bmc_connector(struct drm_connector *connector) 13 { 14 return container_of(connector, struct mgag200_bmc_connector, base); 15 } 16 17 void mgag200_bmc_disable_vidrst(struct mga_device *mdev) 18 { 19 u8 tmp; 20 int iter_max; 21 22 /* 23 * 1 - The first step is to inform the BMC of an upcoming mode 24 * change. We are putting the misc<0> to output. 25 */ 26 27 WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); 28 tmp = RREG8(DAC_DATA); 29 tmp |= 0x10; 30 WREG_DAC(MGA1064_GEN_IO_CTL, tmp); 31 32 /* we are putting a 1 on the misc<0> line */ 33 WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 34 tmp = RREG8(DAC_DATA); 35 tmp |= 0x10; 36 WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 37 38 /* 39 * 2- Second step to mask any further scan request. This is 40 * done by asserting the remfreqmsk bit (XSPAREREG<7>) 41 */ 42 43 WREG8(DAC_INDEX, MGA1064_SPAREREG); 44 tmp = RREG8(DAC_DATA); 45 tmp |= 0x80; 46 WREG_DAC(MGA1064_SPAREREG, tmp); 47 48 /* 49 * 3a- The third step is to verify if there is an active scan. 50 * We are waiting for a 0 on remhsyncsts <XSPAREREG<0>). 51 */ 52 iter_max = 300; 53 while (!(tmp & 0x1) && iter_max) { 54 WREG8(DAC_INDEX, MGA1064_SPAREREG); 55 tmp = RREG8(DAC_DATA); 56 udelay(1000); 57 iter_max--; 58 } 59 60 /* 61 * 3b- This step occurs only if the remove is actually 62 * scanning. We are waiting for the end of the frame which is 63 * a 1 on remvsyncsts (XSPAREREG<1>) 64 */ 65 if (iter_max) { 66 iter_max = 300; 67 while ((tmp & 0x2) && iter_max) { 68 WREG8(DAC_INDEX, MGA1064_SPAREREG); 69 tmp = RREG8(DAC_DATA); 70 udelay(1000); 71 iter_max--; 72 } 73 } 74 } 75 76 void mgag200_bmc_enable_vidrst(struct mga_device *mdev) 77 { 78 u8 tmp; 79 80 /* Ensure that the vrsten and hrsten are set */ 81 WREG8(MGAREG_CRTCEXT_INDEX, 1); 82 tmp = RREG8(MGAREG_CRTCEXT_DATA); 83 WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88); 84 85 /* Assert rstlvl2 */ 86 WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 87 tmp = RREG8(DAC_DATA); 88 tmp |= 0x8; 89 WREG8(DAC_DATA, tmp); 90 91 udelay(10); 92 93 /* Deassert rstlvl2 */ 94 tmp &= ~0x08; 95 WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 96 WREG8(DAC_DATA, tmp); 97 98 /* Remove mask of scan request */ 99 WREG8(DAC_INDEX, MGA1064_SPAREREG); 100 tmp = RREG8(DAC_DATA); 101 tmp &= ~0x80; 102 WREG8(DAC_DATA, tmp); 103 104 /* Put back a 0 on the misc<0> line */ 105 WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 106 tmp = RREG8(DAC_DATA); 107 tmp &= ~0x10; 108 WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 109 } 110 111 static const struct drm_encoder_funcs mgag200_bmc_encoder_funcs = { 112 .destroy = drm_encoder_cleanup, 113 }; 114 115 static int mgag200_bmc_connector_helper_detect_ctx(struct drm_connector *connector, 116 struct drm_modeset_acquire_ctx *ctx, 117 bool force) 118 { 119 struct mgag200_bmc_connector *bmc_connector = to_mgag200_bmc_connector(connector); 120 struct drm_connector *physical_connector = bmc_connector->physical_connector; 121 122 /* 123 * Most user-space compositors cannot handle more than one connected 124 * connector per CRTC. Hence, we only mark the BMC as connected if the 125 * physical connector is disconnected. If the physical connector's status 126 * is connected or unknown, the BMC remains disconnected. This has no 127 * effect on the output of the BMC. 128 * 129 * FIXME: Remove this logic once user-space compositors can handle more 130 * than one connector per CRTC. The BMC should always be connected. 131 */ 132 133 if (physical_connector && physical_connector->status == connector_status_disconnected) 134 return connector_status_connected; 135 136 return connector_status_disconnected; 137 } 138 139 static int mgag200_bmc_connector_helper_get_modes(struct drm_connector *connector) 140 { 141 struct drm_device *dev = connector->dev; 142 struct mga_device *mdev = to_mga_device(dev); 143 const struct mgag200_device_info *minfo = mdev->info; 144 145 return drm_add_modes_noedid(connector, minfo->max_hdisplay, minfo->max_vdisplay); 146 } 147 148 static const struct drm_connector_helper_funcs mgag200_bmc_connector_helper_funcs = { 149 .get_modes = mgag200_bmc_connector_helper_get_modes, 150 .detect_ctx = mgag200_bmc_connector_helper_detect_ctx, 151 }; 152 153 static const struct drm_connector_funcs mgag200_bmc_connector_funcs = { 154 .reset = drm_atomic_helper_connector_reset, 155 .fill_modes = drm_helper_probe_single_connector_modes, 156 .destroy = drm_connector_cleanup, 157 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 158 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 159 }; 160 161 static int mgag200_bmc_connector_init(struct drm_device *dev, 162 struct mgag200_bmc_connector *bmc_connector, 163 struct drm_connector *physical_connector) 164 { 165 struct drm_connector *connector = &bmc_connector->base; 166 int ret; 167 168 ret = drm_connector_init(dev, connector, &mgag200_bmc_connector_funcs, 169 DRM_MODE_CONNECTOR_VIRTUAL); 170 if (ret) 171 return ret; 172 drm_connector_helper_add(connector, &mgag200_bmc_connector_helper_funcs); 173 174 bmc_connector->physical_connector = physical_connector; 175 176 return 0; 177 } 178 179 int mgag200_bmc_output_init(struct mga_device *mdev, struct drm_connector *physical_connector) 180 { 181 struct drm_device *dev = &mdev->base; 182 struct drm_crtc *crtc = &mdev->crtc; 183 struct drm_encoder *encoder; 184 struct mgag200_bmc_connector *bmc_connector; 185 struct drm_connector *connector; 186 int ret; 187 188 encoder = &mdev->output.bmc.encoder; 189 ret = drm_encoder_init(dev, encoder, &mgag200_bmc_encoder_funcs, 190 DRM_MODE_ENCODER_VIRTUAL, NULL); 191 if (ret) 192 return ret; 193 encoder->possible_crtcs = drm_crtc_mask(crtc); 194 195 bmc_connector = &mdev->output.bmc.bmc_connector; 196 ret = mgag200_bmc_connector_init(dev, bmc_connector, physical_connector); 197 if (ret) 198 return ret; 199 connector = &bmc_connector->base; 200 201 ret = drm_connector_attach_encoder(connector, encoder); 202 if (ret) 203 return ret; 204 205 return 0; 206 } 207