xref: /linux/drivers/gpu/drm/sysfb/drm_sysfb_modeset.c (revision 314c45e39e9abcaf2fe5449a11b6d9ad3b2c7dbc)
1*314c45e3SThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only
2*314c45e3SThomas Zimmermann 
3*314c45e3SThomas Zimmermann #include <linux/export.h>
4*314c45e3SThomas Zimmermann #include <linux/slab.h>
5*314c45e3SThomas Zimmermann 
6*314c45e3SThomas Zimmermann #include <drm/drm_atomic.h>
7*314c45e3SThomas Zimmermann #include <drm/drm_atomic_helper.h>
8*314c45e3SThomas Zimmermann #include <drm/drm_atomic_state_helper.h>
9*314c45e3SThomas Zimmermann #include <drm/drm_damage_helper.h>
10*314c45e3SThomas Zimmermann #include <drm/drm_drv.h>
11*314c45e3SThomas Zimmermann #include <drm/drm_edid.h>
12*314c45e3SThomas Zimmermann #include <drm/drm_fourcc.h>
13*314c45e3SThomas Zimmermann #include <drm/drm_framebuffer.h>
14*314c45e3SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
15*314c45e3SThomas Zimmermann #include <drm/drm_gem_framebuffer_helper.h>
16*314c45e3SThomas Zimmermann #include <drm/drm_panic.h>
17*314c45e3SThomas Zimmermann #include <drm/drm_print.h>
18*314c45e3SThomas Zimmermann #include <drm/drm_probe_helper.h>
19*314c45e3SThomas Zimmermann 
20*314c45e3SThomas Zimmermann #include "drm_sysfb_helper.h"
21*314c45e3SThomas Zimmermann 
22*314c45e3SThomas Zimmermann struct drm_display_mode drm_sysfb_mode(unsigned int width,
23*314c45e3SThomas Zimmermann 				       unsigned int height,
24*314c45e3SThomas Zimmermann 				       unsigned int width_mm,
25*314c45e3SThomas Zimmermann 				       unsigned int height_mm)
26*314c45e3SThomas Zimmermann {
27*314c45e3SThomas Zimmermann 	/*
28*314c45e3SThomas Zimmermann 	 * Assume a monitor resolution of 96 dpi to
29*314c45e3SThomas Zimmermann 	 * get a somewhat reasonable screen size.
30*314c45e3SThomas Zimmermann 	 */
31*314c45e3SThomas Zimmermann 	if (!width_mm)
32*314c45e3SThomas Zimmermann 		width_mm = DRM_MODE_RES_MM(width, 96ul);
33*314c45e3SThomas Zimmermann 	if (!height_mm)
34*314c45e3SThomas Zimmermann 		height_mm = DRM_MODE_RES_MM(height, 96ul);
35*314c45e3SThomas Zimmermann 
36*314c45e3SThomas Zimmermann 	{
37*314c45e3SThomas Zimmermann 		const struct drm_display_mode mode = {
38*314c45e3SThomas Zimmermann 			DRM_MODE_INIT(60, width, height, width_mm, height_mm)
39*314c45e3SThomas Zimmermann 		};
40*314c45e3SThomas Zimmermann 
41*314c45e3SThomas Zimmermann 		return mode;
42*314c45e3SThomas Zimmermann 	}
43*314c45e3SThomas Zimmermann }
44*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_mode);
45*314c45e3SThomas Zimmermann 
46*314c45e3SThomas Zimmermann /*
47*314c45e3SThomas Zimmermann  * Plane
48*314c45e3SThomas Zimmermann  */
49*314c45e3SThomas Zimmermann 
50*314c45e3SThomas Zimmermann int drm_sysfb_plane_helper_atomic_check(struct drm_plane *plane,
51*314c45e3SThomas Zimmermann 					struct drm_atomic_state *new_state)
52*314c45e3SThomas Zimmermann {
53*314c45e3SThomas Zimmermann 	struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
54*314c45e3SThomas Zimmermann 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
55*314c45e3SThomas Zimmermann 	struct drm_shadow_plane_state *new_shadow_plane_state =
56*314c45e3SThomas Zimmermann 		to_drm_shadow_plane_state(new_plane_state);
57*314c45e3SThomas Zimmermann 	struct drm_framebuffer *new_fb = new_plane_state->fb;
58*314c45e3SThomas Zimmermann 	struct drm_crtc *new_crtc = new_plane_state->crtc;
59*314c45e3SThomas Zimmermann 	struct drm_crtc_state *new_crtc_state = NULL;
60*314c45e3SThomas Zimmermann 	struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
61*314c45e3SThomas Zimmermann 	int ret;
62*314c45e3SThomas Zimmermann 
63*314c45e3SThomas Zimmermann 	if (new_crtc)
64*314c45e3SThomas Zimmermann 		new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
65*314c45e3SThomas Zimmermann 
66*314c45e3SThomas Zimmermann 	ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
67*314c45e3SThomas Zimmermann 						  DRM_PLANE_NO_SCALING,
68*314c45e3SThomas Zimmermann 						  DRM_PLANE_NO_SCALING,
69*314c45e3SThomas Zimmermann 						  false, false);
70*314c45e3SThomas Zimmermann 	if (ret)
71*314c45e3SThomas Zimmermann 		return ret;
72*314c45e3SThomas Zimmermann 	else if (!new_plane_state->visible)
73*314c45e3SThomas Zimmermann 		return 0;
74*314c45e3SThomas Zimmermann 
75*314c45e3SThomas Zimmermann 	if (new_fb->format != sysfb->fb_format) {
76*314c45e3SThomas Zimmermann 		void *buf;
77*314c45e3SThomas Zimmermann 
78*314c45e3SThomas Zimmermann 		/* format conversion necessary; reserve buffer */
79*314c45e3SThomas Zimmermann 		buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state,
80*314c45e3SThomas Zimmermann 						    sysfb->fb_pitch, GFP_KERNEL);
81*314c45e3SThomas Zimmermann 		if (!buf)
82*314c45e3SThomas Zimmermann 			return -ENOMEM;
83*314c45e3SThomas Zimmermann 	}
84*314c45e3SThomas Zimmermann 
85*314c45e3SThomas Zimmermann 	new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
86*314c45e3SThomas Zimmermann 
87*314c45e3SThomas Zimmermann 	new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state);
88*314c45e3SThomas Zimmermann 	new_sysfb_crtc_state->format = new_fb->format;
89*314c45e3SThomas Zimmermann 
90*314c45e3SThomas Zimmermann 	return 0;
91*314c45e3SThomas Zimmermann }
92*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_check);
93*314c45e3SThomas Zimmermann 
94*314c45e3SThomas Zimmermann void drm_sysfb_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
95*314c45e3SThomas Zimmermann {
96*314c45e3SThomas Zimmermann 	struct drm_device *dev = plane->dev;
97*314c45e3SThomas Zimmermann 	struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
98*314c45e3SThomas Zimmermann 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
99*314c45e3SThomas Zimmermann 	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
100*314c45e3SThomas Zimmermann 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
101*314c45e3SThomas Zimmermann 	struct drm_framebuffer *fb = plane_state->fb;
102*314c45e3SThomas Zimmermann 	unsigned int dst_pitch = sysfb->fb_pitch;
103*314c45e3SThomas Zimmermann 	const struct drm_format_info *dst_format = sysfb->fb_format;
104*314c45e3SThomas Zimmermann 	struct drm_atomic_helper_damage_iter iter;
105*314c45e3SThomas Zimmermann 	struct drm_rect damage;
106*314c45e3SThomas Zimmermann 	int ret, idx;
107*314c45e3SThomas Zimmermann 
108*314c45e3SThomas Zimmermann 	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
109*314c45e3SThomas Zimmermann 	if (ret)
110*314c45e3SThomas Zimmermann 		return;
111*314c45e3SThomas Zimmermann 
112*314c45e3SThomas Zimmermann 	if (!drm_dev_enter(dev, &idx))
113*314c45e3SThomas Zimmermann 		goto out_drm_gem_fb_end_cpu_access;
114*314c45e3SThomas Zimmermann 
115*314c45e3SThomas Zimmermann 	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
116*314c45e3SThomas Zimmermann 	drm_atomic_for_each_plane_damage(&iter, &damage) {
117*314c45e3SThomas Zimmermann 		struct iosys_map dst = sysfb->fb_addr;
118*314c45e3SThomas Zimmermann 		struct drm_rect dst_clip = plane_state->dst;
119*314c45e3SThomas Zimmermann 
120*314c45e3SThomas Zimmermann 		if (!drm_rect_intersect(&dst_clip, &damage))
121*314c45e3SThomas Zimmermann 			continue;
122*314c45e3SThomas Zimmermann 
123*314c45e3SThomas Zimmermann 		iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip));
124*314c45e3SThomas Zimmermann 		drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb,
125*314c45e3SThomas Zimmermann 			    &damage, &shadow_plane_state->fmtcnv_state);
126*314c45e3SThomas Zimmermann 	}
127*314c45e3SThomas Zimmermann 
128*314c45e3SThomas Zimmermann 	drm_dev_exit(idx);
129*314c45e3SThomas Zimmermann out_drm_gem_fb_end_cpu_access:
130*314c45e3SThomas Zimmermann 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
131*314c45e3SThomas Zimmermann }
132*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_update);
133*314c45e3SThomas Zimmermann 
134*314c45e3SThomas Zimmermann void drm_sysfb_plane_helper_atomic_disable(struct drm_plane *plane,
135*314c45e3SThomas Zimmermann 					   struct drm_atomic_state *state)
136*314c45e3SThomas Zimmermann {
137*314c45e3SThomas Zimmermann 	struct drm_device *dev = plane->dev;
138*314c45e3SThomas Zimmermann 	struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
139*314c45e3SThomas Zimmermann 	struct iosys_map dst = sysfb->fb_addr;
140*314c45e3SThomas Zimmermann 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
141*314c45e3SThomas Zimmermann 	void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */
142*314c45e3SThomas Zimmermann 	unsigned int dst_pitch = sysfb->fb_pitch;
143*314c45e3SThomas Zimmermann 	const struct drm_format_info *dst_format = sysfb->fb_format;
144*314c45e3SThomas Zimmermann 	struct drm_rect dst_clip;
145*314c45e3SThomas Zimmermann 	unsigned long lines, linepixels, i;
146*314c45e3SThomas Zimmermann 	int idx;
147*314c45e3SThomas Zimmermann 
148*314c45e3SThomas Zimmermann 	drm_rect_init(&dst_clip,
149*314c45e3SThomas Zimmermann 		      plane_state->src_x >> 16, plane_state->src_y >> 16,
150*314c45e3SThomas Zimmermann 		      plane_state->src_w >> 16, plane_state->src_h >> 16);
151*314c45e3SThomas Zimmermann 
152*314c45e3SThomas Zimmermann 	lines = drm_rect_height(&dst_clip);
153*314c45e3SThomas Zimmermann 	linepixels = drm_rect_width(&dst_clip);
154*314c45e3SThomas Zimmermann 
155*314c45e3SThomas Zimmermann 	if (!drm_dev_enter(dev, &idx))
156*314c45e3SThomas Zimmermann 		return;
157*314c45e3SThomas Zimmermann 
158*314c45e3SThomas Zimmermann 	/* Clear buffer to black if disabled */
159*314c45e3SThomas Zimmermann 	dst_vmap += drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip);
160*314c45e3SThomas Zimmermann 	for (i = 0; i < lines; ++i) {
161*314c45e3SThomas Zimmermann 		memset_io(dst_vmap, 0, linepixels * dst_format->cpp[0]);
162*314c45e3SThomas Zimmermann 		dst_vmap += dst_pitch;
163*314c45e3SThomas Zimmermann 	}
164*314c45e3SThomas Zimmermann 
165*314c45e3SThomas Zimmermann 	drm_dev_exit(idx);
166*314c45e3SThomas Zimmermann }
167*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_disable);
168*314c45e3SThomas Zimmermann 
169*314c45e3SThomas Zimmermann int drm_sysfb_plane_helper_get_scanout_buffer(struct drm_plane *plane,
170*314c45e3SThomas Zimmermann 					      struct drm_scanout_buffer *sb)
171*314c45e3SThomas Zimmermann {
172*314c45e3SThomas Zimmermann 	struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
173*314c45e3SThomas Zimmermann 
174*314c45e3SThomas Zimmermann 	sb->width = sysfb->fb_mode.hdisplay;
175*314c45e3SThomas Zimmermann 	sb->height = sysfb->fb_mode.vdisplay;
176*314c45e3SThomas Zimmermann 	sb->format = sysfb->fb_format;
177*314c45e3SThomas Zimmermann 	sb->pitch[0] = sysfb->fb_pitch;
178*314c45e3SThomas Zimmermann 	sb->map[0] = sysfb->fb_addr;
179*314c45e3SThomas Zimmermann 
180*314c45e3SThomas Zimmermann 	return 0;
181*314c45e3SThomas Zimmermann }
182*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_plane_helper_get_scanout_buffer);
183*314c45e3SThomas Zimmermann 
184*314c45e3SThomas Zimmermann /*
185*314c45e3SThomas Zimmermann  * CRTC
186*314c45e3SThomas Zimmermann  */
187*314c45e3SThomas Zimmermann 
188*314c45e3SThomas Zimmermann static void drm_sysfb_crtc_state_destroy(struct drm_sysfb_crtc_state *sysfb_crtc_state)
189*314c45e3SThomas Zimmermann {
190*314c45e3SThomas Zimmermann 	__drm_atomic_helper_crtc_destroy_state(&sysfb_crtc_state->base);
191*314c45e3SThomas Zimmermann 
192*314c45e3SThomas Zimmermann 	kfree(sysfb_crtc_state);
193*314c45e3SThomas Zimmermann }
194*314c45e3SThomas Zimmermann 
195*314c45e3SThomas Zimmermann enum drm_mode_status drm_sysfb_crtc_helper_mode_valid(struct drm_crtc *crtc,
196*314c45e3SThomas Zimmermann 						      const struct drm_display_mode *mode)
197*314c45e3SThomas Zimmermann {
198*314c45e3SThomas Zimmermann 	struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
199*314c45e3SThomas Zimmermann 
200*314c45e3SThomas Zimmermann 	return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sysfb->fb_mode);
201*314c45e3SThomas Zimmermann }
202*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_crtc_helper_mode_valid);
203*314c45e3SThomas Zimmermann 
204*314c45e3SThomas Zimmermann int drm_sysfb_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
205*314c45e3SThomas Zimmermann {
206*314c45e3SThomas Zimmermann 	struct drm_device *dev = crtc->dev;
207*314c45e3SThomas Zimmermann 	struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
208*314c45e3SThomas Zimmermann 	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
209*314c45e3SThomas Zimmermann 	int ret;
210*314c45e3SThomas Zimmermann 
211*314c45e3SThomas Zimmermann 	if (!new_crtc_state->enable)
212*314c45e3SThomas Zimmermann 		return 0;
213*314c45e3SThomas Zimmermann 
214*314c45e3SThomas Zimmermann 	ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
215*314c45e3SThomas Zimmermann 	if (ret)
216*314c45e3SThomas Zimmermann 		return ret;
217*314c45e3SThomas Zimmermann 
218*314c45e3SThomas Zimmermann 	if (new_crtc_state->color_mgmt_changed) {
219*314c45e3SThomas Zimmermann 		const size_t gamma_lut_length =
220*314c45e3SThomas Zimmermann 			sysfb->fb_gamma_lut_size * sizeof(struct drm_color_lut);
221*314c45e3SThomas Zimmermann 		const struct drm_property_blob *gamma_lut = new_crtc_state->gamma_lut;
222*314c45e3SThomas Zimmermann 
223*314c45e3SThomas Zimmermann 		if (gamma_lut && (gamma_lut->length != gamma_lut_length)) {
224*314c45e3SThomas Zimmermann 			drm_dbg(dev, "Incorrect gamma_lut length %zu\n", gamma_lut->length);
225*314c45e3SThomas Zimmermann 			return -EINVAL;
226*314c45e3SThomas Zimmermann 		}
227*314c45e3SThomas Zimmermann 	}
228*314c45e3SThomas Zimmermann 
229*314c45e3SThomas Zimmermann 	return 0;
230*314c45e3SThomas Zimmermann }
231*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_crtc_helper_atomic_check);
232*314c45e3SThomas Zimmermann 
233*314c45e3SThomas Zimmermann void drm_sysfb_crtc_reset(struct drm_crtc *crtc)
234*314c45e3SThomas Zimmermann {
235*314c45e3SThomas Zimmermann 	struct drm_sysfb_crtc_state *sysfb_crtc_state;
236*314c45e3SThomas Zimmermann 
237*314c45e3SThomas Zimmermann 	if (crtc->state)
238*314c45e3SThomas Zimmermann 		drm_sysfb_crtc_state_destroy(to_drm_sysfb_crtc_state(crtc->state));
239*314c45e3SThomas Zimmermann 
240*314c45e3SThomas Zimmermann 	sysfb_crtc_state = kzalloc(sizeof(*sysfb_crtc_state), GFP_KERNEL);
241*314c45e3SThomas Zimmermann 	if (sysfb_crtc_state)
242*314c45e3SThomas Zimmermann 		__drm_atomic_helper_crtc_reset(crtc, &sysfb_crtc_state->base);
243*314c45e3SThomas Zimmermann 	else
244*314c45e3SThomas Zimmermann 		__drm_atomic_helper_crtc_reset(crtc, NULL);
245*314c45e3SThomas Zimmermann }
246*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_crtc_reset);
247*314c45e3SThomas Zimmermann 
248*314c45e3SThomas Zimmermann struct drm_crtc_state *drm_sysfb_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
249*314c45e3SThomas Zimmermann {
250*314c45e3SThomas Zimmermann 	struct drm_device *dev = crtc->dev;
251*314c45e3SThomas Zimmermann 	struct drm_crtc_state *crtc_state = crtc->state;
252*314c45e3SThomas Zimmermann 	struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
253*314c45e3SThomas Zimmermann 	struct drm_sysfb_crtc_state *sysfb_crtc_state;
254*314c45e3SThomas Zimmermann 
255*314c45e3SThomas Zimmermann 	if (drm_WARN_ON(dev, !crtc_state))
256*314c45e3SThomas Zimmermann 		return NULL;
257*314c45e3SThomas Zimmermann 
258*314c45e3SThomas Zimmermann 	new_sysfb_crtc_state = kzalloc(sizeof(*new_sysfb_crtc_state), GFP_KERNEL);
259*314c45e3SThomas Zimmermann 	if (!new_sysfb_crtc_state)
260*314c45e3SThomas Zimmermann 		return NULL;
261*314c45e3SThomas Zimmermann 
262*314c45e3SThomas Zimmermann 	sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
263*314c45e3SThomas Zimmermann 
264*314c45e3SThomas Zimmermann 	__drm_atomic_helper_crtc_duplicate_state(crtc, &new_sysfb_crtc_state->base);
265*314c45e3SThomas Zimmermann 	new_sysfb_crtc_state->format = sysfb_crtc_state->format;
266*314c45e3SThomas Zimmermann 
267*314c45e3SThomas Zimmermann 	return &new_sysfb_crtc_state->base;
268*314c45e3SThomas Zimmermann }
269*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_crtc_atomic_duplicate_state);
270*314c45e3SThomas Zimmermann 
271*314c45e3SThomas Zimmermann void drm_sysfb_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
272*314c45e3SThomas Zimmermann {
273*314c45e3SThomas Zimmermann 	drm_sysfb_crtc_state_destroy(to_drm_sysfb_crtc_state(crtc_state));
274*314c45e3SThomas Zimmermann }
275*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_crtc_atomic_destroy_state);
276*314c45e3SThomas Zimmermann 
277*314c45e3SThomas Zimmermann /*
278*314c45e3SThomas Zimmermann  * Connector
279*314c45e3SThomas Zimmermann  */
280*314c45e3SThomas Zimmermann 
281*314c45e3SThomas Zimmermann static int drm_sysfb_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
282*314c45e3SThomas Zimmermann {
283*314c45e3SThomas Zimmermann 	struct drm_sysfb_device *sysfb = data;
284*314c45e3SThomas Zimmermann 	const u8 *edid = sysfb->edid;
285*314c45e3SThomas Zimmermann 	size_t off = block * EDID_LENGTH;
286*314c45e3SThomas Zimmermann 	size_t end = off + len;
287*314c45e3SThomas Zimmermann 
288*314c45e3SThomas Zimmermann 	if (!edid)
289*314c45e3SThomas Zimmermann 		return -EINVAL;
290*314c45e3SThomas Zimmermann 	if (end > EDID_LENGTH)
291*314c45e3SThomas Zimmermann 		return -EINVAL;
292*314c45e3SThomas Zimmermann 	memcpy(buf, &edid[off], len);
293*314c45e3SThomas Zimmermann 
294*314c45e3SThomas Zimmermann 	/*
295*314c45e3SThomas Zimmermann 	 * We don't have EDID extensions available and reporting them
296*314c45e3SThomas Zimmermann 	 * will upset DRM helpers. Thus clear the extension field and
297*314c45e3SThomas Zimmermann 	 * update the checksum. Adding the extension flag to the checksum
298*314c45e3SThomas Zimmermann 	 * does this.
299*314c45e3SThomas Zimmermann 	 */
300*314c45e3SThomas Zimmermann 	buf[127] += buf[126];
301*314c45e3SThomas Zimmermann 	buf[126] = 0;
302*314c45e3SThomas Zimmermann 
303*314c45e3SThomas Zimmermann 	return 0;
304*314c45e3SThomas Zimmermann }
305*314c45e3SThomas Zimmermann 
306*314c45e3SThomas Zimmermann int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector)
307*314c45e3SThomas Zimmermann {
308*314c45e3SThomas Zimmermann 	struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
309*314c45e3SThomas Zimmermann 	const struct drm_edid *drm_edid;
310*314c45e3SThomas Zimmermann 
311*314c45e3SThomas Zimmermann 	if (sysfb->edid) {
312*314c45e3SThomas Zimmermann 		drm_edid = drm_edid_read_custom(connector, drm_sysfb_get_edid_block, sysfb);
313*314c45e3SThomas Zimmermann 		drm_edid_connector_update(connector, drm_edid);
314*314c45e3SThomas Zimmermann 		drm_edid_free(drm_edid);
315*314c45e3SThomas Zimmermann 	}
316*314c45e3SThomas Zimmermann 
317*314c45e3SThomas Zimmermann 	/* Return the fixed mode even with EDID */
318*314c45e3SThomas Zimmermann 	return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
319*314c45e3SThomas Zimmermann }
320*314c45e3SThomas Zimmermann EXPORT_SYMBOL(drm_sysfb_connector_helper_get_modes);
321