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