xref: /linux/drivers/gpu/drm/mgag200/mgag200_bmc.c (revision ee057c8c194b9283f4137b253b70e292693a39f0)
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