Message ID | 20220728124103.30159-8-tzimmermann@suse.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/mgag200: Move model-specific code into separate functions | expand |
On 28/07/2022 14:40, Thomas Zimmermann wrote: > Drop simple-KMS in favor of regular atomic helpers. Makes the code > more modular and hence better to adapt to per-model requirements. > > The simple-KMS helpers provide few extra features, so the patch is > mostly about open-coding what simple-KMS does. The simple-KMS helpers > do mix up plane and CRTC state. Changing to regular atomic helpers > requires to split some of the simple-pipe functions into per-plane > and per-CRTC code > > No functional changes. > > v3: > * always run drm_atomic_helper_check_plane_state() > * clean up style > > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> > Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com> > Tested-by: Jocelyn Falempe <jfalempe@redhat.com> > Acked-by: Sam Ravnborg <sam@ravnborg.org> > --- > drivers/gpu/drm/mgag200/mgag200_drv.h | 8 +- > drivers/gpu/drm/mgag200/mgag200_mode.c | 382 +++++++++++++++---------- > 2 files changed, 233 insertions(+), 157 deletions(-) > > diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h > index bf6a01ff9719..b0433985ec0d 100644 > --- a/drivers/gpu/drm/mgag200/mgag200_drv.h > +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h > @@ -15,11 +15,13 @@ > > #include <video/vga.h> > > +#include <drm/drm_connector.h> > +#include <drm/drm_crtc.h> > #include <drm/drm_encoder.h> > #include <drm/drm_fb_helper.h> > #include <drm/drm_gem.h> > #include <drm/drm_gem_shmem_helper.h> > -#include <drm/drm_simple_kms_helper.h> > +#include <drm/drm_plane.h> > > #include "mgag200_reg.h" > > @@ -276,9 +278,11 @@ struct mga_device { > enum mga_type type; > > struct mgag200_pll pixpll; > + struct drm_plane primary_plane; > + struct drm_crtc crtc; > + struct drm_encoder encoder; > struct mga_i2c_chan i2c; > struct drm_connector connector; > - struct drm_simple_display_pipe display_pipe; > }; > > static inline struct mga_device *to_mga_device(struct drm_device *dev) > diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c > index 67795135d4dd..b524c1c5f032 100644 > --- a/drivers/gpu/drm/mgag200/mgag200_mode.c > +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c > @@ -23,7 +23,6 @@ > #include <drm/drm_gem_framebuffer_helper.h> > #include <drm/drm_print.h> > #include <drm/drm_probe_helper.h> > -#include <drm/drm_simple_kms_helper.h> > > #include "mgag200_drv.h" > > @@ -614,25 +613,106 @@ static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_ma > } > > /* > - * Simple Display Pipe > + * Primary plane > */ > > -static const uint32_t mgag200_simple_display_pipe_formats[] = { > +static const uint32_t mgag200_primary_plane_formats[] = { > DRM_FORMAT_XRGB8888, > DRM_FORMAT_RGB565, > DRM_FORMAT_RGB888, > }; > > -static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { > +static const uint64_t mgag200_primary_plane_fmtmods[] = { > DRM_FORMAT_MOD_LINEAR, > DRM_FORMAT_MOD_INVALID > }; > > -static enum drm_mode_status > -mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, > - const struct drm_display_mode *mode) > +static int mgag200_primary_plane_helper_atomic_check(struct drm_plane *plane, > + struct drm_atomic_state *new_state) > { > - struct mga_device *mdev = to_mga_device(pipe->crtc.dev); > + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); > + struct drm_framebuffer *new_fb = new_plane_state->fb; > + struct drm_framebuffer *fb = NULL; > + struct drm_crtc *new_crtc = new_plane_state->crtc; > + struct drm_crtc_state *new_crtc_state = NULL; > + struct mgag200_crtc_state *new_mgag200_crtc_state; > + int ret; > + > + if (new_crtc) > + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc); If new_crtc is NULL, then new_crtc_state will be NULL too, and it's dereferenced in drm_atomic_helper_check_plane_state() and later in this function. So either there is a garantee that new_crtc is never NULL when calling this function, or it should return before trying to access it. > + > + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, > + DRM_PLANE_NO_SCALING, > + DRM_PLANE_NO_SCALING, > + false, true); > + if (ret) > + return ret; > + else if (!new_plane_state->visible) > + return 0; > + > + if (plane->state) > + fb = plane->state->fb; > + > + if (!fb || (fb->format != new_fb->format)) > + new_crtc_state->mode_changed = true; /* update PLL settings */ > + > + new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); > + new_mgag200_crtc_state->format = new_fb->format; > + > + return 0; > +} > + > +static void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane, > + struct drm_atomic_state *old_state) > +{ > + struct drm_device *dev = plane->dev; > + struct mga_device *mdev = to_mga_device(dev); > + struct drm_plane_state *plane_state = plane->state; > + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane); > + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); > + struct drm_framebuffer *fb = plane_state->fb; > + struct drm_atomic_helper_damage_iter iter; > + struct drm_rect damage; > + > + if (!fb) > + return; > + > + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); > + drm_atomic_for_each_plane_damage(&iter, &damage) { > + mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); > + } > + > + /* Always scanout image at VRAM offset 0 */ > + mgag200_set_startadd(mdev, (u32)0); > + mgag200_set_offset(mdev, fb); > +} > + > +static void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, > + struct drm_atomic_state *old_state) > +{ } > + > +static const struct drm_plane_helper_funcs mgag200_primary_plane_helper_funcs = { > + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, > + .atomic_check = mgag200_primary_plane_helper_atomic_check, > + .atomic_update = mgag200_primary_plane_helper_atomic_update, > + .atomic_disable = mgag200_primary_plane_helper_atomic_disable, > +}; > + > +static const struct drm_plane_funcs mgag200_primary_plane_funcs = { > + .update_plane = drm_atomic_helper_update_plane, > + .disable_plane = drm_atomic_helper_disable_plane, > + .destroy = drm_plane_cleanup, > + DRM_GEM_SHADOW_PLANE_FUNCS, > +}; > + > +/* > + * CRTC > + */ > + > +static enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc, > + const struct drm_display_mode *mode) > +{ > + struct mga_device *mdev = to_mga_device(crtc->dev); > const struct mgag200_device_info *info = mdev->info; > > /* > @@ -659,26 +739,69 @@ mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, > return MODE_OK; > } > > -static void > -mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, > - struct drm_crtc_state *crtc_state, > - struct drm_plane_state *plane_state) > +static int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, > + struct drm_atomic_state *new_state) > { > - struct drm_crtc *crtc = &pipe->crtc; > struct drm_device *dev = crtc->dev; > struct mga_device *mdev = to_mga_device(dev); > + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); > struct mgag200_pll *pixpll = &mdev->pixpll; > + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); > + struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut; > + int ret; > + > + ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); > + if (ret) > + return ret; > + > + if (!new_crtc_state->enable) > + return 0; > + > + if (new_crtc_state->mode_changed) { > + ret = pixpll->funcs->compute(pixpll, new_crtc_state->mode.clock, > + &mgag200_crtc_state->pixpllc); > + if (ret) > + return ret; > + } > + > + if (new_crtc_state->color_mgmt_changed && new_gamma_lut) { > + if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) { > + drm_dbg(dev, "Wrong size for gamma_lut %zu\n", new_gamma_lut->length); > + return -EINVAL; > + } > + } > + > + return drm_atomic_add_affected_planes(new_state, crtc); > +} > + > +static void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, > + struct drm_atomic_state *old_state) > +{ > + struct drm_crtc_state *crtc_state = crtc->state; > + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); > + struct drm_device *dev = crtc->dev; > + struct mga_device *mdev = to_mga_device(dev); > + > + if (crtc_state->enable && crtc_state->color_mgmt_changed) { > + const struct drm_format_info *format = mgag200_crtc_state->format; > + > + if (crtc_state->gamma_lut) > + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); > + else > + mgag200_crtc_set_gamma_linear(mdev, format); > + } > +} > + > +static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, > + struct drm_atomic_state *old_state) > +{ > + struct drm_device *dev = crtc->dev; > + struct mga_device *mdev = to_mga_device(dev); > + struct drm_crtc_state *crtc_state = crtc->state; > struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; > struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); > - struct drm_framebuffer *fb = plane_state->fb; > const struct drm_format_info *format = mgag200_crtc_state->format; > - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); > - struct drm_rect fullscreen = { > - .x1 = 0, > - .x2 = fb->width, > - .y1 = 0, > - .y2 = fb->height, > - }; > + struct mgag200_pll *pixpll = &mdev->pixpll; > > if (mdev->type == G200_WB || mdev->type == G200_EW3) > mgag200_g200wb_hold_bmc(mdev); > @@ -696,108 +819,50 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, > else if (mdev->type == G200_EV) > mgag200_g200ev_set_hiprilvl(mdev); > > - if (mdev->type == G200_WB || mdev->type == G200_EW3) > - mgag200_g200wb_release_bmc(mdev); > - > - if (crtc_state->gamma_lut) > - mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); > - else > - mgag200_crtc_set_gamma_linear(mdev, format); > - > mgag200_enable_display(mdev); > > - mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &fullscreen); > - > - /* Always scanout image at VRAM offset 0 */ > - mgag200_set_startadd(mdev, (u32)0); > - mgag200_set_offset(mdev, fb); > + if (mdev->type == G200_WB || mdev->type == G200_EW3) > + mgag200_g200wb_release_bmc(mdev); > } > > -static void > -mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) > +static void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, > + struct drm_atomic_state *old_state) > { > - struct drm_crtc *crtc = &pipe->crtc; > struct mga_device *mdev = to_mga_device(crtc->dev); > > - mgag200_disable_display(mdev); > -} > - > -static int > -mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, > - struct drm_plane_state *plane_state, > - struct drm_crtc_state *crtc_state) > -{ > - struct drm_plane *plane = plane_state->plane; > - struct drm_device *dev = plane->dev; > - struct mga_device *mdev = to_mga_device(dev); > - struct mgag200_pll *pixpll = &mdev->pixpll; > - struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); > - struct drm_framebuffer *new_fb = plane_state->fb; > - struct drm_framebuffer *fb = NULL; > - int ret; > - > - if (!new_fb) > - return 0; > - > - if (plane->state) > - fb = plane->state->fb; > - > - if (!fb || (fb->format != new_fb->format)) > - crtc_state->mode_changed = true; /* update PLL settings */ > - > - mgag200_crtc_state->format = new_fb->format; > + if (mdev->type == G200_WB || mdev->type == G200_EW3) > + mgag200_g200wb_hold_bmc(mdev); > > - if (crtc_state->mode_changed) { > - ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock, > - &mgag200_crtc_state->pixpllc); > - if (ret) > - return ret; > - } > + mgag200_disable_display(mdev); > > - if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { > - if (crtc_state->gamma_lut->length != > - MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) { > - drm_err(dev, "Wrong size for gamma_lut %zu\n", > - crtc_state->gamma_lut->length); > - return -EINVAL; > - } > - } > - return 0; > + if (mdev->type == G200_WB || mdev->type == G200_EW3) > + mgag200_g200wb_release_bmc(mdev); > } > > -static void > -mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, > - struct drm_plane_state *old_state) > -{ > - struct drm_plane *plane = &pipe->plane; > - struct drm_crtc *crtc = &pipe->crtc; > - struct drm_device *dev = plane->dev; > - struct mga_device *mdev = to_mga_device(dev); > - struct drm_plane_state *state = plane->state; > - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); > - struct drm_framebuffer *fb = state->fb; > - struct drm_rect damage; > - struct drm_atomic_helper_damage_iter iter; > +static const struct drm_crtc_helper_funcs mgag200_crtc_helper_funcs = { > + .mode_valid = mgag200_crtc_helper_mode_valid, > + .atomic_check = mgag200_crtc_helper_atomic_check, > + .atomic_flush = mgag200_crtc_helper_atomic_flush, > + .atomic_enable = mgag200_crtc_helper_atomic_enable, > + .atomic_disable = mgag200_crtc_helper_atomic_disable, > +}; > > - if (!fb) > - return; > +static void mgag200_crtc_reset(struct drm_crtc *crtc) > +{ > + struct mgag200_crtc_state *mgag200_crtc_state; > > - if (crtc->state->color_mgmt_changed && crtc->state->gamma_lut) > - mgag200_crtc_set_gamma(mdev, fb->format, crtc->state->gamma_lut->data); > + if (crtc->state) > + crtc->funcs->atomic_destroy_state(crtc, crtc->state); > > - drm_atomic_helper_damage_iter_init(&iter, old_state, state); > - drm_atomic_for_each_plane_damage(&iter, &damage) { > - mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); > - } > - /* Always scanout image at VRAM offset 0 */ > - mgag200_set_startadd(mdev, (u32)0); > - mgag200_set_offset(mdev, fb); > + mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL); > + if (mgag200_crtc_state) > + __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); > + else > + __drm_atomic_helper_crtc_reset(crtc, NULL); > } > > -static struct drm_crtc_state * > -mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe *pipe) > +static struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc) > { > - struct drm_crtc *crtc = &pipe->crtc; > struct drm_crtc_state *crtc_state = crtc->state; > struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); > struct mgag200_crtc_state *new_mgag200_crtc_state; > @@ -817,8 +882,8 @@ mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe > return &new_mgag200_crtc_state->base; > } > > -static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_display_pipe *pipe, > - struct drm_crtc_state *crtc_state) > +static void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, > + struct drm_crtc_state *crtc_state) > { > struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); > > @@ -826,33 +891,21 @@ static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_dis > kfree(mgag200_crtc_state); > } > > -static void mgag200_simple_display_pipe_reset_crtc(struct drm_simple_display_pipe *pipe) > -{ > - struct drm_crtc *crtc = &pipe->crtc; > - struct mgag200_crtc_state *mgag200_crtc_state; > - > - if (crtc->state) { > - mgag200_simple_display_pipe_destroy_crtc_state(pipe, crtc->state); > - crtc->state = NULL; /* must be set to NULL here */ > - } > +static const struct drm_crtc_funcs mgag200_crtc_funcs = { > + .reset = mgag200_crtc_reset, > + .destroy = drm_crtc_cleanup, > + .set_config = drm_atomic_helper_set_config, > + .page_flip = drm_atomic_helper_page_flip, > + .atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state, > + .atomic_destroy_state = mgag200_crtc_atomic_destroy_state, > +}; > > - mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL); > - if (!mgag200_crtc_state) > - return; > - __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); > -} > +/* > + * Encoder > + */ > > -static const struct drm_simple_display_pipe_funcs > -mgag200_simple_display_pipe_funcs = { > - .mode_valid = mgag200_simple_display_pipe_mode_valid, > - .enable = mgag200_simple_display_pipe_enable, > - .disable = mgag200_simple_display_pipe_disable, > - .check = mgag200_simple_display_pipe_check, > - .update = mgag200_simple_display_pipe_update, > - .reset_crtc = mgag200_simple_display_pipe_reset_crtc, > - .duplicate_crtc_state = mgag200_simple_display_pipe_duplicate_crtc_state, > - .destroy_crtc_state = mgag200_simple_display_pipe_destroy_crtc_state, > - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, > +static const struct drm_encoder_funcs mgag200_dac_encoder_funcs = { > + .destroy = drm_encoder_cleanup, > }; > > /* > @@ -999,12 +1052,49 @@ static int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vra > static int mgag200_pipeline_init(struct mga_device *mdev) > { > struct drm_device *dev = &mdev->base; > + struct drm_plane *primary_plane = &mdev->primary_plane; > + struct drm_crtc *crtc = &mdev->crtc; > + struct drm_encoder *encoder = &mdev->encoder; > struct mga_i2c_chan *i2c = &mdev->i2c; > struct drm_connector *connector = &mdev->connector; > - struct drm_simple_display_pipe *pipe = &mdev->display_pipe; > - size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats); > int ret; > > + ret = mgag200_pixpll_init(&mdev->pixpll, mdev); > + if (ret) > + return ret; > + > + ret = drm_universal_plane_init(dev, primary_plane, 0, > + &mgag200_primary_plane_funcs, > + mgag200_primary_plane_formats, > + ARRAY_SIZE(mgag200_primary_plane_formats), > + mgag200_primary_plane_fmtmods, > + DRM_PLANE_TYPE_PRIMARY, NULL); > + if (ret) { > + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); > + return ret; > + } > + drm_plane_helper_add(primary_plane, &mgag200_primary_plane_helper_funcs); > + drm_plane_enable_fb_damage_clips(primary_plane); > + > + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, &mgag200_crtc_funcs, NULL); > + if (ret) { > + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); > + return ret; > + } > + drm_crtc_helper_add(crtc, &mgag200_crtc_helper_funcs); > + > + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ > + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); > + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); > + > + encoder->possible_crtcs = drm_crtc_mask(crtc); > + ret = drm_encoder_init(dev, encoder, &mgag200_dac_encoder_funcs, > + DRM_MODE_ENCODER_DAC, NULL); > + if (ret) { > + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); > + return ret; > + } > + > ret = mgag200_i2c_init(mdev, i2c); > if (ret) { > drm_err(dev, "failed to add DDC bus: %d\n", ret); > @@ -1021,30 +1111,12 @@ static int mgag200_pipeline_init(struct mga_device *mdev) > } > drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); > > - ret = mgag200_pixpll_init(&mdev->pixpll, mdev); > - if (ret) > - return ret; > - > - ret = drm_simple_display_pipe_init(dev, pipe, > - &mgag200_simple_display_pipe_funcs, > - mgag200_simple_display_pipe_formats, > - format_count, > - mgag200_simple_display_pipe_fmtmods, > - connector); > + ret = drm_connector_attach_encoder(connector, encoder); > if (ret) { > - drm_err(dev, > - "drm_simple_display_pipe_init() failed, error %d\n", > - ret); > + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); > return ret; > } > > - drm_plane_enable_fb_damage_clips(&pipe->plane); > - > - /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ > - drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE); > - > - drm_crtc_enable_color_mgmt(&pipe->crtc, 0, false, MGAG200_LUT_SIZE); > - > return 0; > } > Everything else looks good to me. Thanks,
Hi Jocelyn Am 28.07.22 um 17:09 schrieb Jocelyn Falempe: > On 28/07/2022 14:40, Thomas Zimmermann wrote: >> Drop simple-KMS in favor of regular atomic helpers. Makes the code >> more modular and hence better to adapt to per-model requirements. >> >> The simple-KMS helpers provide few extra features, so the patch is >> mostly about open-coding what simple-KMS does. The simple-KMS helpers >> do mix up plane and CRTC state. Changing to regular atomic helpers >> requires to split some of the simple-pipe functions into per-plane >> and per-CRTC code >> >> No functional changes. >> >> v3: >> * always run drm_atomic_helper_check_plane_state() >> * clean up style >> >> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> >> Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com> >> Tested-by: Jocelyn Falempe <jfalempe@redhat.com> >> Acked-by: Sam Ravnborg <sam@ravnborg.org> >> --- >> drivers/gpu/drm/mgag200/mgag200_drv.h | 8 +- >> drivers/gpu/drm/mgag200/mgag200_mode.c | 382 +++++++++++++++---------- >> 2 files changed, 233 insertions(+), 157 deletions(-) >> >> diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h >> b/drivers/gpu/drm/mgag200/mgag200_drv.h >> index bf6a01ff9719..b0433985ec0d 100644 >> --- a/drivers/gpu/drm/mgag200/mgag200_drv.h >> +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h >> @@ -15,11 +15,13 @@ >> #include <video/vga.h> >> +#include <drm/drm_connector.h> >> +#include <drm/drm_crtc.h> >> #include <drm/drm_encoder.h> >> #include <drm/drm_fb_helper.h> >> #include <drm/drm_gem.h> >> #include <drm/drm_gem_shmem_helper.h> >> -#include <drm/drm_simple_kms_helper.h> >> +#include <drm/drm_plane.h> >> #include "mgag200_reg.h" >> @@ -276,9 +278,11 @@ struct mga_device { >> enum mga_type type; >> struct mgag200_pll pixpll; >> + struct drm_plane primary_plane; >> + struct drm_crtc crtc; >> + struct drm_encoder encoder; >> struct mga_i2c_chan i2c; >> struct drm_connector connector; >> - struct drm_simple_display_pipe display_pipe; >> }; >> static inline struct mga_device *to_mga_device(struct drm_device *dev) >> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c >> b/drivers/gpu/drm/mgag200/mgag200_mode.c >> index 67795135d4dd..b524c1c5f032 100644 >> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c >> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c >> @@ -23,7 +23,6 @@ >> #include <drm/drm_gem_framebuffer_helper.h> >> #include <drm/drm_print.h> >> #include <drm/drm_probe_helper.h> >> -#include <drm/drm_simple_kms_helper.h> >> #include "mgag200_drv.h" >> @@ -614,25 +613,106 @@ static void mgag200_handle_damage(struct >> mga_device *mdev, const struct iosys_ma >> } >> /* >> - * Simple Display Pipe >> + * Primary plane >> */ >> -static const uint32_t mgag200_simple_display_pipe_formats[] = { >> +static const uint32_t mgag200_primary_plane_formats[] = { >> DRM_FORMAT_XRGB8888, >> DRM_FORMAT_RGB565, >> DRM_FORMAT_RGB888, >> }; >> -static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { >> +static const uint64_t mgag200_primary_plane_fmtmods[] = { >> DRM_FORMAT_MOD_LINEAR, >> DRM_FORMAT_MOD_INVALID >> }; >> -static enum drm_mode_status >> -mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe >> *pipe, >> - const struct drm_display_mode *mode) >> +static int mgag200_primary_plane_helper_atomic_check(struct drm_plane >> *plane, >> + struct drm_atomic_state *new_state) >> { >> - struct mga_device *mdev = to_mga_device(pipe->crtc.dev); >> + struct drm_plane_state *new_plane_state = >> drm_atomic_get_new_plane_state(new_state, plane); >> + struct drm_framebuffer *new_fb = new_plane_state->fb; >> + struct drm_framebuffer *fb = NULL; >> + struct drm_crtc *new_crtc = new_plane_state->crtc; >> + struct drm_crtc_state *new_crtc_state = NULL; >> + struct mgag200_crtc_state *new_mgag200_crtc_state; >> + int ret; >> + >> + if (new_crtc) >> + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, >> new_crtc); > > If new_crtc is NULL, then new_crtc_state will be NULL too, and it's > dereferenced in drm_atomic_helper_check_plane_state() and later in this > function. > So either there is a garantee that new_crtc is never NULL when calling > this function, or it should return before trying to access it. That's a good observation. Luckily it's not a problem in practice. The logic in the DRM code is confusing, however. Near the top of the function, drm_atomic_check_planes_state() will only deref crtc_state if the plane has a CRTC set, [1] so we're safe here. That will work because every CRTC/plane/connector/encoder always has an associated state; even if it's disabled. Hence if the plane has a crtc, that crtc will have a state. Or else, both will be NULL. Further down, drm_atomic_helper_check_plane_state() first tests for !plane->fb [2] and then for !plane->crtc. [3] In both cases, drm_atomic_helper_check_plane_state() clears the visibility field to 0 and returns 0. Our code in mgag200_primary_plane_helper_atomic_check() will return early for invisible planes before deref'ing new_crtc_state, so we're safe here as well. Best regards Thomas [1] https://elixir.bootlin.com/linux/v5.18.14/source/drivers/gpu/drm/drm_atomic_helper.c#L814 [2] https://elixir.bootlin.com/linux/v5.18.14/source/drivers/gpu/drm/drm_atomic_helper.c#L819 [3] https://elixir.bootlin.com/linux/v5.18.14/source/drivers/gpu/drm/drm_atomic_helper.c#L825 > >> + >> + ret = drm_atomic_helper_check_plane_state(new_plane_state, >> new_crtc_state, >> + DRM_PLANE_NO_SCALING, >> + DRM_PLANE_NO_SCALING, >> + false, true); >> + if (ret) >> + return ret; >> + else if (!new_plane_state->visible) >> + return 0; >> + >> + if (plane->state) >> + fb = plane->state->fb; >> + >> + if (!fb || (fb->format != new_fb->format)) >> + new_crtc_state->mode_changed = true; /* update PLL settings */ >> + >> + new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); >> + new_mgag200_crtc_state->format = new_fb->format; >> + >> + return 0; >> +} >> + >> +static void mgag200_primary_plane_helper_atomic_update(struct >> drm_plane *plane, >> + struct drm_atomic_state *old_state) >> +{ >> + struct drm_device *dev = plane->dev; >> + struct mga_device *mdev = to_mga_device(dev); >> + struct drm_plane_state *plane_state = plane->state; >> + struct drm_plane_state *old_plane_state = >> drm_atomic_get_old_plane_state(old_state, plane); >> + struct drm_shadow_plane_state *shadow_plane_state = >> to_drm_shadow_plane_state(plane_state); >> + struct drm_framebuffer *fb = plane_state->fb; >> + struct drm_atomic_helper_damage_iter iter; >> + struct drm_rect damage; >> + >> + if (!fb) >> + return; >> + >> + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, >> plane_state); >> + drm_atomic_for_each_plane_damage(&iter, &damage) { >> + mgag200_handle_damage(mdev, shadow_plane_state->data, fb, >> &damage); >> + } >> + >> + /* Always scanout image at VRAM offset 0 */ >> + mgag200_set_startadd(mdev, (u32)0); >> + mgag200_set_offset(mdev, fb); >> +} >> + >> +static void mgag200_primary_plane_helper_atomic_disable(struct >> drm_plane *plane, >> + struct drm_atomic_state *old_state) >> +{ } >> + >> +static const struct drm_plane_helper_funcs >> mgag200_primary_plane_helper_funcs = { >> + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, >> + .atomic_check = mgag200_primary_plane_helper_atomic_check, >> + .atomic_update = mgag200_primary_plane_helper_atomic_update, >> + .atomic_disable = mgag200_primary_plane_helper_atomic_disable, >> +}; >> + >> +static const struct drm_plane_funcs mgag200_primary_plane_funcs = { >> + .update_plane = drm_atomic_helper_update_plane, >> + .disable_plane = drm_atomic_helper_disable_plane, >> + .destroy = drm_plane_cleanup, >> + DRM_GEM_SHADOW_PLANE_FUNCS, >> +}; >> + >> +/* >> + * CRTC >> + */ >> + >> +static enum drm_mode_status mgag200_crtc_helper_mode_valid(struct >> drm_crtc *crtc, >> + const struct drm_display_mode *mode) >> +{ >> + struct mga_device *mdev = to_mga_device(crtc->dev); >> const struct mgag200_device_info *info = mdev->info; >> /* >> @@ -659,26 +739,69 @@ mgag200_simple_display_pipe_mode_valid(struct >> drm_simple_display_pipe *pipe, >> return MODE_OK; >> } >> -static void >> -mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, >> - struct drm_crtc_state *crtc_state, >> - struct drm_plane_state *plane_state) >> +static int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, >> + struct drm_atomic_state *new_state) >> { >> - struct drm_crtc *crtc = &pipe->crtc; >> struct drm_device *dev = crtc->dev; >> struct mga_device *mdev = to_mga_device(dev); >> + struct drm_crtc_state *new_crtc_state = >> drm_atomic_get_new_crtc_state(new_state, crtc); >> struct mgag200_pll *pixpll = &mdev->pixpll; >> + struct mgag200_crtc_state *mgag200_crtc_state = >> to_mgag200_crtc_state(new_crtc_state); >> + struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut; >> + int ret; >> + >> + ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); >> + if (ret) >> + return ret; >> + >> + if (!new_crtc_state->enable) >> + return 0; >> + >> + if (new_crtc_state->mode_changed) { >> + ret = pixpll->funcs->compute(pixpll, new_crtc_state->mode.clock, >> + &mgag200_crtc_state->pixpllc); >> + if (ret) >> + return ret; >> + } >> + >> + if (new_crtc_state->color_mgmt_changed && new_gamma_lut) { >> + if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct >> drm_color_lut)) { >> + drm_dbg(dev, "Wrong size for gamma_lut %zu\n", >> new_gamma_lut->length); >> + return -EINVAL; >> + } >> + } >> + >> + return drm_atomic_add_affected_planes(new_state, crtc); >> +} >> + >> +static void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, >> + struct drm_atomic_state *old_state) >> +{ >> + struct drm_crtc_state *crtc_state = crtc->state; >> + struct mgag200_crtc_state *mgag200_crtc_state = >> to_mgag200_crtc_state(crtc_state); >> + struct drm_device *dev = crtc->dev; >> + struct mga_device *mdev = to_mga_device(dev); >> + >> + if (crtc_state->enable && crtc_state->color_mgmt_changed) { >> + const struct drm_format_info *format = >> mgag200_crtc_state->format; >> + >> + if (crtc_state->gamma_lut) >> + mgag200_crtc_set_gamma(mdev, format, >> crtc_state->gamma_lut->data); >> + else >> + mgag200_crtc_set_gamma_linear(mdev, format); >> + } >> +} >> + >> +static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, >> + struct drm_atomic_state *old_state) >> +{ >> + struct drm_device *dev = crtc->dev; >> + struct mga_device *mdev = to_mga_device(dev); >> + struct drm_crtc_state *crtc_state = crtc->state; >> struct drm_display_mode *adjusted_mode = >> &crtc_state->adjusted_mode; >> struct mgag200_crtc_state *mgag200_crtc_state = >> to_mgag200_crtc_state(crtc_state); >> - struct drm_framebuffer *fb = plane_state->fb; >> const struct drm_format_info *format = mgag200_crtc_state->format; >> - struct drm_shadow_plane_state *shadow_plane_state = >> to_drm_shadow_plane_state(plane_state); >> - struct drm_rect fullscreen = { >> - .x1 = 0, >> - .x2 = fb->width, >> - .y1 = 0, >> - .y2 = fb->height, >> - }; >> + struct mgag200_pll *pixpll = &mdev->pixpll; >> if (mdev->type == G200_WB || mdev->type == G200_EW3) >> mgag200_g200wb_hold_bmc(mdev); >> @@ -696,108 +819,50 @@ mgag200_simple_display_pipe_enable(struct >> drm_simple_display_pipe *pipe, >> else if (mdev->type == G200_EV) >> mgag200_g200ev_set_hiprilvl(mdev); >> - if (mdev->type == G200_WB || mdev->type == G200_EW3) >> - mgag200_g200wb_release_bmc(mdev); >> - >> - if (crtc_state->gamma_lut) >> - mgag200_crtc_set_gamma(mdev, format, >> crtc_state->gamma_lut->data); >> - else >> - mgag200_crtc_set_gamma_linear(mdev, format); >> - >> mgag200_enable_display(mdev); >> - mgag200_handle_damage(mdev, shadow_plane_state->data, fb, >> &fullscreen); >> - >> - /* Always scanout image at VRAM offset 0 */ >> - mgag200_set_startadd(mdev, (u32)0); >> - mgag200_set_offset(mdev, fb); >> + if (mdev->type == G200_WB || mdev->type == G200_EW3) >> + mgag200_g200wb_release_bmc(mdev); >> } >> -static void >> -mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe >> *pipe) >> +static void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, >> + struct drm_atomic_state *old_state) >> { >> - struct drm_crtc *crtc = &pipe->crtc; >> struct mga_device *mdev = to_mga_device(crtc->dev); >> - mgag200_disable_display(mdev); >> -} >> - >> -static int >> -mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, >> - struct drm_plane_state *plane_state, >> - struct drm_crtc_state *crtc_state) >> -{ >> - struct drm_plane *plane = plane_state->plane; >> - struct drm_device *dev = plane->dev; >> - struct mga_device *mdev = to_mga_device(dev); >> - struct mgag200_pll *pixpll = &mdev->pixpll; >> - struct mgag200_crtc_state *mgag200_crtc_state = >> to_mgag200_crtc_state(crtc_state); >> - struct drm_framebuffer *new_fb = plane_state->fb; >> - struct drm_framebuffer *fb = NULL; >> - int ret; >> - >> - if (!new_fb) >> - return 0; >> - >> - if (plane->state) >> - fb = plane->state->fb; >> - >> - if (!fb || (fb->format != new_fb->format)) >> - crtc_state->mode_changed = true; /* update PLL settings */ >> - >> - mgag200_crtc_state->format = new_fb->format; >> + if (mdev->type == G200_WB || mdev->type == G200_EW3) >> + mgag200_g200wb_hold_bmc(mdev); >> - if (crtc_state->mode_changed) { >> - ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock, >> - &mgag200_crtc_state->pixpllc); >> - if (ret) >> - return ret; >> - } >> + mgag200_disable_display(mdev); >> - if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { >> - if (crtc_state->gamma_lut->length != >> - MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) { >> - drm_err(dev, "Wrong size for gamma_lut %zu\n", >> - crtc_state->gamma_lut->length); >> - return -EINVAL; >> - } >> - } >> - return 0; >> + if (mdev->type == G200_WB || mdev->type == G200_EW3) >> + mgag200_g200wb_release_bmc(mdev); >> } >> -static void >> -mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, >> - struct drm_plane_state *old_state) >> -{ >> - struct drm_plane *plane = &pipe->plane; >> - struct drm_crtc *crtc = &pipe->crtc; >> - struct drm_device *dev = plane->dev; >> - struct mga_device *mdev = to_mga_device(dev); >> - struct drm_plane_state *state = plane->state; >> - struct drm_shadow_plane_state *shadow_plane_state = >> to_drm_shadow_plane_state(state); >> - struct drm_framebuffer *fb = state->fb; >> - struct drm_rect damage; >> - struct drm_atomic_helper_damage_iter iter; >> +static const struct drm_crtc_helper_funcs mgag200_crtc_helper_funcs = { >> + .mode_valid = mgag200_crtc_helper_mode_valid, >> + .atomic_check = mgag200_crtc_helper_atomic_check, >> + .atomic_flush = mgag200_crtc_helper_atomic_flush, >> + .atomic_enable = mgag200_crtc_helper_atomic_enable, >> + .atomic_disable = mgag200_crtc_helper_atomic_disable, >> +}; >> - if (!fb) >> - return; >> +static void mgag200_crtc_reset(struct drm_crtc *crtc) >> +{ >> + struct mgag200_crtc_state *mgag200_crtc_state; >> - if (crtc->state->color_mgmt_changed && crtc->state->gamma_lut) >> - mgag200_crtc_set_gamma(mdev, fb->format, >> crtc->state->gamma_lut->data); >> + if (crtc->state) >> + crtc->funcs->atomic_destroy_state(crtc, crtc->state); >> - drm_atomic_helper_damage_iter_init(&iter, old_state, state); >> - drm_atomic_for_each_plane_damage(&iter, &damage) { >> - mgag200_handle_damage(mdev, shadow_plane_state->data, fb, >> &damage); >> - } >> - /* Always scanout image at VRAM offset 0 */ >> - mgag200_set_startadd(mdev, (u32)0); >> - mgag200_set_offset(mdev, fb); >> + mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), >> GFP_KERNEL); >> + if (mgag200_crtc_state) >> + __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); >> + else >> + __drm_atomic_helper_crtc_reset(crtc, NULL); >> } >> -static struct drm_crtc_state * >> -mgag200_simple_display_pipe_duplicate_crtc_state(struct >> drm_simple_display_pipe *pipe) >> +static struct drm_crtc_state >> *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc) >> { >> - struct drm_crtc *crtc = &pipe->crtc; >> struct drm_crtc_state *crtc_state = crtc->state; >> struct mgag200_crtc_state *mgag200_crtc_state = >> to_mgag200_crtc_state(crtc_state); >> struct mgag200_crtc_state *new_mgag200_crtc_state; >> @@ -817,8 +882,8 @@ >> mgag200_simple_display_pipe_duplicate_crtc_state(struct >> drm_simple_display_pipe >> return &new_mgag200_crtc_state->base; >> } >> -static void mgag200_simple_display_pipe_destroy_crtc_state(struct >> drm_simple_display_pipe *pipe, >> - struct drm_crtc_state *crtc_state) >> +static void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, >> + struct drm_crtc_state *crtc_state) >> { >> struct mgag200_crtc_state *mgag200_crtc_state = >> to_mgag200_crtc_state(crtc_state); >> @@ -826,33 +891,21 @@ static void >> mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_dis >> kfree(mgag200_crtc_state); >> } >> -static void mgag200_simple_display_pipe_reset_crtc(struct >> drm_simple_display_pipe *pipe) >> -{ >> - struct drm_crtc *crtc = &pipe->crtc; >> - struct mgag200_crtc_state *mgag200_crtc_state; >> - >> - if (crtc->state) { >> - mgag200_simple_display_pipe_destroy_crtc_state(pipe, >> crtc->state); >> - crtc->state = NULL; /* must be set to NULL here */ >> - } >> +static const struct drm_crtc_funcs mgag200_crtc_funcs = { >> + .reset = mgag200_crtc_reset, >> + .destroy = drm_crtc_cleanup, >> + .set_config = drm_atomic_helper_set_config, >> + .page_flip = drm_atomic_helper_page_flip, >> + .atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state, >> + .atomic_destroy_state = mgag200_crtc_atomic_destroy_state, >> +}; >> - mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), >> GFP_KERNEL); >> - if (!mgag200_crtc_state) >> - return; >> - __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); >> -} >> +/* >> + * Encoder >> + */ >> -static const struct drm_simple_display_pipe_funcs >> -mgag200_simple_display_pipe_funcs = { >> - .mode_valid = mgag200_simple_display_pipe_mode_valid, >> - .enable = mgag200_simple_display_pipe_enable, >> - .disable = mgag200_simple_display_pipe_disable, >> - .check = mgag200_simple_display_pipe_check, >> - .update = mgag200_simple_display_pipe_update, >> - .reset_crtc = mgag200_simple_display_pipe_reset_crtc, >> - .duplicate_crtc_state = >> mgag200_simple_display_pipe_duplicate_crtc_state, >> - .destroy_crtc_state = >> mgag200_simple_display_pipe_destroy_crtc_state, >> - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, >> +static const struct drm_encoder_funcs mgag200_dac_encoder_funcs = { >> + .destroy = drm_encoder_cleanup, >> }; >> /* >> @@ -999,12 +1052,49 @@ static int mgag200_mode_config_init(struct >> mga_device *mdev, resource_size_t vra >> static int mgag200_pipeline_init(struct mga_device *mdev) >> { >> struct drm_device *dev = &mdev->base; >> + struct drm_plane *primary_plane = &mdev->primary_plane; >> + struct drm_crtc *crtc = &mdev->crtc; >> + struct drm_encoder *encoder = &mdev->encoder; >> struct mga_i2c_chan *i2c = &mdev->i2c; >> struct drm_connector *connector = &mdev->connector; >> - struct drm_simple_display_pipe *pipe = &mdev->display_pipe; >> - size_t format_count = >> ARRAY_SIZE(mgag200_simple_display_pipe_formats); >> int ret; >> + ret = mgag200_pixpll_init(&mdev->pixpll, mdev); >> + if (ret) >> + return ret; >> + >> + ret = drm_universal_plane_init(dev, primary_plane, 0, >> + &mgag200_primary_plane_funcs, >> + mgag200_primary_plane_formats, >> + ARRAY_SIZE(mgag200_primary_plane_formats), >> + mgag200_primary_plane_fmtmods, >> + DRM_PLANE_TYPE_PRIMARY, NULL); >> + if (ret) { >> + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); >> + return ret; >> + } >> + drm_plane_helper_add(primary_plane, >> &mgag200_primary_plane_helper_funcs); >> + drm_plane_enable_fb_damage_clips(primary_plane); >> + >> + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, >> &mgag200_crtc_funcs, NULL); >> + if (ret) { >> + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); >> + return ret; >> + } >> + drm_crtc_helper_add(crtc, &mgag200_crtc_helper_funcs); >> + >> + /* FIXME: legacy gamma tables, but atomic gamma doesn't work >> without */ >> + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); >> + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); >> + >> + encoder->possible_crtcs = drm_crtc_mask(crtc); >> + ret = drm_encoder_init(dev, encoder, &mgag200_dac_encoder_funcs, >> + DRM_MODE_ENCODER_DAC, NULL); >> + if (ret) { >> + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); >> + return ret; >> + } >> + >> ret = mgag200_i2c_init(mdev, i2c); >> if (ret) { >> drm_err(dev, "failed to add DDC bus: %d\n", ret); >> @@ -1021,30 +1111,12 @@ static int mgag200_pipeline_init(struct >> mga_device *mdev) >> } >> drm_connector_helper_add(connector, >> &mga_vga_connector_helper_funcs); >> - ret = mgag200_pixpll_init(&mdev->pixpll, mdev); >> - if (ret) >> - return ret; >> - >> - ret = drm_simple_display_pipe_init(dev, pipe, >> - &mgag200_simple_display_pipe_funcs, >> - mgag200_simple_display_pipe_formats, >> - format_count, >> - mgag200_simple_display_pipe_fmtmods, >> - connector); >> + ret = drm_connector_attach_encoder(connector, encoder); >> if (ret) { >> - drm_err(dev, >> - "drm_simple_display_pipe_init() failed, error %d\n", >> - ret); >> + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", >> ret); >> return ret; >> } >> - drm_plane_enable_fb_damage_clips(&pipe->plane); >> - >> - /* FIXME: legacy gamma tables, but atomic gamma doesn't work >> without */ >> - drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE); >> - >> - drm_crtc_enable_color_mgmt(&pipe->crtc, 0, false, MGAG200_LUT_SIZE); >> - >> return 0; >> } > > Everything else looks good to me. > > Thanks, >
On 28/07/2022 20:31, Thomas Zimmermann wrote: > Hi Jocelyn > > Am 28.07.22 um 17:09 schrieb Jocelyn Falempe: >> On 28/07/2022 14:40, Thomas Zimmermann wrote: >>> Drop simple-KMS in favor of regular atomic helpers. Makes the code >>> more modular and hence better to adapt to per-model requirements. >>> >>> The simple-KMS helpers provide few extra features, so the patch is >>> mostly about open-coding what simple-KMS does. The simple-KMS helpers >>> do mix up plane and CRTC state. Changing to regular atomic helpers >>> requires to split some of the simple-pipe functions into per-plane >>> and per-CRTC code >>> >>> No functional changes. >>> >>> v3: >>> * always run drm_atomic_helper_check_plane_state() >>> * clean up style >>> >>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> >>> Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com> >>> Tested-by: Jocelyn Falempe <jfalempe@redhat.com> >>> Acked-by: Sam Ravnborg <sam@ravnborg.org> >>> --- >>> drivers/gpu/drm/mgag200/mgag200_drv.h | 8 +- >>> drivers/gpu/drm/mgag200/mgag200_mode.c | 382 +++++++++++++++---------- >>> 2 files changed, 233 insertions(+), 157 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h >>> b/drivers/gpu/drm/mgag200/mgag200_drv.h >>> index bf6a01ff9719..b0433985ec0d 100644 >>> --- a/drivers/gpu/drm/mgag200/mgag200_drv.h >>> +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h >>> @@ -15,11 +15,13 @@ >>> #include <video/vga.h> >>> +#include <drm/drm_connector.h> >>> +#include <drm/drm_crtc.h> >>> #include <drm/drm_encoder.h> >>> #include <drm/drm_fb_helper.h> >>> #include <drm/drm_gem.h> >>> #include <drm/drm_gem_shmem_helper.h> >>> -#include <drm/drm_simple_kms_helper.h> >>> +#include <drm/drm_plane.h> >>> #include "mgag200_reg.h" >>> @@ -276,9 +278,11 @@ struct mga_device { >>> enum mga_type type; >>> struct mgag200_pll pixpll; >>> + struct drm_plane primary_plane; >>> + struct drm_crtc crtc; >>> + struct drm_encoder encoder; >>> struct mga_i2c_chan i2c; >>> struct drm_connector connector; >>> - struct drm_simple_display_pipe display_pipe; >>> }; >>> static inline struct mga_device *to_mga_device(struct drm_device *dev) >>> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c >>> b/drivers/gpu/drm/mgag200/mgag200_mode.c >>> index 67795135d4dd..b524c1c5f032 100644 >>> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c >>> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c >>> @@ -23,7 +23,6 @@ >>> #include <drm/drm_gem_framebuffer_helper.h> >>> #include <drm/drm_print.h> >>> #include <drm/drm_probe_helper.h> >>> -#include <drm/drm_simple_kms_helper.h> >>> #include "mgag200_drv.h" >>> @@ -614,25 +613,106 @@ static void mgag200_handle_damage(struct >>> mga_device *mdev, const struct iosys_ma >>> } >>> /* >>> - * Simple Display Pipe >>> + * Primary plane >>> */ >>> -static const uint32_t mgag200_simple_display_pipe_formats[] = { >>> +static const uint32_t mgag200_primary_plane_formats[] = { >>> DRM_FORMAT_XRGB8888, >>> DRM_FORMAT_RGB565, >>> DRM_FORMAT_RGB888, >>> }; >>> -static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { >>> +static const uint64_t mgag200_primary_plane_fmtmods[] = { >>> DRM_FORMAT_MOD_LINEAR, >>> DRM_FORMAT_MOD_INVALID >>> }; >>> -static enum drm_mode_status >>> -mgag200_simple_display_pipe_mode_valid(struct >>> drm_simple_display_pipe *pipe, >>> - const struct drm_display_mode *mode) >>> +static int mgag200_primary_plane_helper_atomic_check(struct >>> drm_plane *plane, >>> + struct drm_atomic_state *new_state) >>> { >>> - struct mga_device *mdev = to_mga_device(pipe->crtc.dev); >>> + struct drm_plane_state *new_plane_state = >>> drm_atomic_get_new_plane_state(new_state, plane); >>> + struct drm_framebuffer *new_fb = new_plane_state->fb; >>> + struct drm_framebuffer *fb = NULL; >>> + struct drm_crtc *new_crtc = new_plane_state->crtc; >>> + struct drm_crtc_state *new_crtc_state = NULL; >>> + struct mgag200_crtc_state *new_mgag200_crtc_state; >>> + int ret; >>> + >>> + if (new_crtc) >>> + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, >>> new_crtc); >> >> If new_crtc is NULL, then new_crtc_state will be NULL too, and it's >> dereferenced in drm_atomic_helper_check_plane_state() and later in >> this function. >> So either there is a garantee that new_crtc is never NULL when calling >> this function, or it should return before trying to access it. > > That's a good observation. Luckily it's not a problem in practice. The > logic in the DRM code is confusing, however. > > Near the top of the function, drm_atomic_check_planes_state() will only > deref crtc_state if the plane has a CRTC set, [1] so we're safe here. > > That will work because every CRTC/plane/connector/encoder always has an > associated state; even if it's disabled. Hence if the plane has a crtc, > that crtc will have a state. Or else, both will be NULL. > > Further down, drm_atomic_helper_check_plane_state() first tests for > !plane->fb [2] and then for !plane->crtc. [3] In both cases, > drm_atomic_helper_check_plane_state() clears the visibility field to 0 > and returns 0. Our code in mgag200_primary_plane_helper_atomic_check() > will return early for invisible planes before deref'ing new_crtc_state, > so we're safe here as well. > > Best regards > Thomas > > [1] > https://elixir.bootlin.com/linux/v5.18.14/source/drivers/gpu/drm/drm_atomic_helper.c#L814 > > [2] > https://elixir.bootlin.com/linux/v5.18.14/source/drivers/gpu/drm/drm_atomic_helper.c#L819 > > [3] > https://elixir.bootlin.com/linux/v5.18.14/source/drivers/gpu/drm/drm_atomic_helper.c#L825 > > Thanks a lot for the detailed explanation, I agree that it's safe now. Best regards,
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index bf6a01ff9719..b0433985ec0d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -15,11 +15,13 @@ #include <video/vga.h> +#include <drm/drm_connector.h> +#include <drm/drm_crtc.h> #include <drm/drm_encoder.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> #include <drm/drm_gem_shmem_helper.h> -#include <drm/drm_simple_kms_helper.h> +#include <drm/drm_plane.h> #include "mgag200_reg.h" @@ -276,9 +278,11 @@ struct mga_device { enum mga_type type; struct mgag200_pll pixpll; + struct drm_plane primary_plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct mga_i2c_chan i2c; struct drm_connector connector; - struct drm_simple_display_pipe display_pipe; }; static inline struct mga_device *to_mga_device(struct drm_device *dev) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 67795135d4dd..b524c1c5f032 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -23,7 +23,6 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include "mgag200_drv.h" @@ -614,25 +613,106 @@ static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_ma } /* - * Simple Display Pipe + * Primary plane */ -static const uint32_t mgag200_simple_display_pipe_formats[] = { +static const uint32_t mgag200_primary_plane_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_RGB888, }; -static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { +static const uint64_t mgag200_primary_plane_fmtmods[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID }; -static enum drm_mode_status -mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +static int mgag200_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *new_state) { - struct mga_device *mdev = to_mga_device(pipe->crtc.dev); + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); + struct drm_framebuffer *new_fb = new_plane_state->fb; + struct drm_framebuffer *fb = NULL; + struct drm_crtc *new_crtc = new_plane_state->crtc; + struct drm_crtc_state *new_crtc_state = NULL; + struct mgag200_crtc_state *new_mgag200_crtc_state; + int ret; + + if (new_crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc); + + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, true); + if (ret) + return ret; + else if (!new_plane_state->visible) + return 0; + + if (plane->state) + fb = plane->state->fb; + + if (!fb || (fb->format != new_fb->format)) + new_crtc_state->mode_changed = true; /* update PLL settings */ + + new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + new_mgag200_crtc_state->format = new_fb->format; + + return 0; +} + +static void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = plane->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_plane_state *plane_state = plane->state; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect damage; + + if (!fb) + return; + + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); + } + + /* Always scanout image at VRAM offset 0 */ + mgag200_set_startadd(mdev, (u32)0); + mgag200_set_offset(mdev, fb); +} + +static void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *old_state) +{ } + +static const struct drm_plane_helper_funcs mgag200_primary_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = mgag200_primary_plane_helper_atomic_check, + .atomic_update = mgag200_primary_plane_helper_atomic_update, + .atomic_disable = mgag200_primary_plane_helper_atomic_disable, +}; + +static const struct drm_plane_funcs mgag200_primary_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +/* + * CRTC + */ + +static enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + struct mga_device *mdev = to_mga_device(crtc->dev); const struct mgag200_device_info *info = mdev->info; /* @@ -659,26 +739,69 @@ mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, return MODE_OK; } -static void -mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *dev = crtc->dev; struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); struct mgag200_pll *pixpll = &mdev->pixpll; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut; + int ret; + + ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); + if (ret) + return ret; + + if (!new_crtc_state->enable) + return 0; + + if (new_crtc_state->mode_changed) { + ret = pixpll->funcs->compute(pixpll, new_crtc_state->mode.clock, + &mgag200_crtc_state->pixpllc); + if (ret) + return ret; + } + + if (new_crtc_state->color_mgmt_changed && new_gamma_lut) { + if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) { + drm_dbg(dev, "Wrong size for gamma_lut %zu\n", new_gamma_lut->length); + return -EINVAL; + } + } + + return drm_atomic_add_affected_planes(new_state, crtc); +} + +static void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + + if (crtc_state->enable && crtc_state->color_mgmt_changed) { + const struct drm_format_info *format = mgag200_crtc_state->format; + + if (crtc_state->gamma_lut) + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); + else + mgag200_crtc_set_gamma_linear(mdev, format); + } +} + +static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *crtc_state = crtc->state; struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); - struct drm_framebuffer *fb = plane_state->fb; const struct drm_format_info *format = mgag200_crtc_state->format; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); - struct drm_rect fullscreen = { - .x1 = 0, - .x2 = fb->width, - .y1 = 0, - .y2 = fb->height, - }; + struct mgag200_pll *pixpll = &mdev->pixpll; if (mdev->type == G200_WB || mdev->type == G200_EW3) mgag200_g200wb_hold_bmc(mdev); @@ -696,108 +819,50 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, else if (mdev->type == G200_EV) mgag200_g200ev_set_hiprilvl(mdev); - if (mdev->type == G200_WB || mdev->type == G200_EW3) - mgag200_g200wb_release_bmc(mdev); - - if (crtc_state->gamma_lut) - mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); - else - mgag200_crtc_set_gamma_linear(mdev, format); - mgag200_enable_display(mdev); - mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &fullscreen); - - /* Always scanout image at VRAM offset 0 */ - mgag200_set_startadd(mdev, (u32)0); - mgag200_set_offset(mdev, fb); + if (mdev->type == G200_WB || mdev->type == G200_EW3) + mgag200_g200wb_release_bmc(mdev); } -static void -mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) +static void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) { - struct drm_crtc *crtc = &pipe->crtc; struct mga_device *mdev = to_mga_device(crtc->dev); - mgag200_disable_display(mdev); -} - -static int -mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state, - struct drm_crtc_state *crtc_state) -{ - struct drm_plane *plane = plane_state->plane; - struct drm_device *dev = plane->dev; - struct mga_device *mdev = to_mga_device(dev); - struct mgag200_pll *pixpll = &mdev->pixpll; - struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); - struct drm_framebuffer *new_fb = plane_state->fb; - struct drm_framebuffer *fb = NULL; - int ret; - - if (!new_fb) - return 0; - - if (plane->state) - fb = plane->state->fb; - - if (!fb || (fb->format != new_fb->format)) - crtc_state->mode_changed = true; /* update PLL settings */ - - mgag200_crtc_state->format = new_fb->format; + if (mdev->type == G200_WB || mdev->type == G200_EW3) + mgag200_g200wb_hold_bmc(mdev); - if (crtc_state->mode_changed) { - ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock, - &mgag200_crtc_state->pixpllc); - if (ret) - return ret; - } + mgag200_disable_display(mdev); - if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { - if (crtc_state->gamma_lut->length != - MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) { - drm_err(dev, "Wrong size for gamma_lut %zu\n", - crtc_state->gamma_lut->length); - return -EINVAL; - } - } - return 0; + if (mdev->type == G200_WB || mdev->type == G200_EW3) + mgag200_g200wb_release_bmc(mdev); } -static void -mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) -{ - struct drm_plane *plane = &pipe->plane; - struct drm_crtc *crtc = &pipe->crtc; - struct drm_device *dev = plane->dev; - struct mga_device *mdev = to_mga_device(dev); - struct drm_plane_state *state = plane->state; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); - struct drm_framebuffer *fb = state->fb; - struct drm_rect damage; - struct drm_atomic_helper_damage_iter iter; +static const struct drm_crtc_helper_funcs mgag200_crtc_helper_funcs = { + .mode_valid = mgag200_crtc_helper_mode_valid, + .atomic_check = mgag200_crtc_helper_atomic_check, + .atomic_flush = mgag200_crtc_helper_atomic_flush, + .atomic_enable = mgag200_crtc_helper_atomic_enable, + .atomic_disable = mgag200_crtc_helper_atomic_disable, +}; - if (!fb) - return; +static void mgag200_crtc_reset(struct drm_crtc *crtc) +{ + struct mgag200_crtc_state *mgag200_crtc_state; - if (crtc->state->color_mgmt_changed && crtc->state->gamma_lut) - mgag200_crtc_set_gamma(mdev, fb->format, crtc->state->gamma_lut->data); + if (crtc->state) + crtc->funcs->atomic_destroy_state(crtc, crtc->state); - drm_atomic_helper_damage_iter_init(&iter, old_state, state); - drm_atomic_for_each_plane_damage(&iter, &damage) { - mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); - } - /* Always scanout image at VRAM offset 0 */ - mgag200_set_startadd(mdev, (u32)0); - mgag200_set_offset(mdev, fb); + mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL); + if (mgag200_crtc_state) + __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); } -static struct drm_crtc_state * -mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe *pipe) +static struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_crtc_state *crtc_state = crtc->state; struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); struct mgag200_crtc_state *new_mgag200_crtc_state; @@ -817,8 +882,8 @@ mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe return &new_mgag200_crtc_state->base; } -static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state) +static void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) { struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); @@ -826,33 +891,21 @@ static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_dis kfree(mgag200_crtc_state); } -static void mgag200_simple_display_pipe_reset_crtc(struct drm_simple_display_pipe *pipe) -{ - struct drm_crtc *crtc = &pipe->crtc; - struct mgag200_crtc_state *mgag200_crtc_state; - - if (crtc->state) { - mgag200_simple_display_pipe_destroy_crtc_state(pipe, crtc->state); - crtc->state = NULL; /* must be set to NULL here */ - } +static const struct drm_crtc_funcs mgag200_crtc_funcs = { + .reset = mgag200_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state, + .atomic_destroy_state = mgag200_crtc_atomic_destroy_state, +}; - mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL); - if (!mgag200_crtc_state) - return; - __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); -} +/* + * Encoder + */ -static const struct drm_simple_display_pipe_funcs -mgag200_simple_display_pipe_funcs = { - .mode_valid = mgag200_simple_display_pipe_mode_valid, - .enable = mgag200_simple_display_pipe_enable, - .disable = mgag200_simple_display_pipe_disable, - .check = mgag200_simple_display_pipe_check, - .update = mgag200_simple_display_pipe_update, - .reset_crtc = mgag200_simple_display_pipe_reset_crtc, - .duplicate_crtc_state = mgag200_simple_display_pipe_duplicate_crtc_state, - .destroy_crtc_state = mgag200_simple_display_pipe_destroy_crtc_state, - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +static const struct drm_encoder_funcs mgag200_dac_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; /* @@ -999,12 +1052,49 @@ static int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vra static int mgag200_pipeline_init(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; struct mga_i2c_chan *i2c = &mdev->i2c; struct drm_connector *connector = &mdev->connector; - struct drm_simple_display_pipe *pipe = &mdev->display_pipe; - size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats); int ret; + ret = mgag200_pixpll_init(&mdev->pixpll, mdev); + if (ret) + return ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_primary_plane_funcs, + mgag200_primary_plane_formats, + ARRAY_SIZE(mgag200_primary_plane_formats), + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, &mgag200_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + ret = mgag200_i2c_init(mdev, i2c); if (ret) { drm_err(dev, "failed to add DDC bus: %d\n", ret); @@ -1021,30 +1111,12 @@ static int mgag200_pipeline_init(struct mga_device *mdev) } drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); - ret = mgag200_pixpll_init(&mdev->pixpll, mdev); - if (ret) - return ret; - - ret = drm_simple_display_pipe_init(dev, pipe, - &mgag200_simple_display_pipe_funcs, - mgag200_simple_display_pipe_formats, - format_count, - mgag200_simple_display_pipe_fmtmods, - connector); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) { - drm_err(dev, - "drm_simple_display_pipe_init() failed, error %d\n", - ret); + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); return ret; } - drm_plane_enable_fb_damage_clips(&pipe->plane); - - /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ - drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE); - - drm_crtc_enable_color_mgmt(&pipe->crtc, 0, false, MGAG200_LUT_SIZE); - return 0; }