Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* exynos_drm_crtc.c
0003  *
0004  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
0005  * Authors:
0006  *  Inki Dae <inki.dae@samsung.com>
0007  *  Joonyoung Shim <jy0922.shim@samsung.com>
0008  *  Seung-Woo Kim <sw0312.kim@samsung.com>
0009  */
0010 
0011 #include <drm/drm_atomic.h>
0012 #include <drm/drm_atomic_helper.h>
0013 #include <drm/drm_encoder.h>
0014 #include <drm/drm_probe_helper.h>
0015 #include <drm/drm_vblank.h>
0016 
0017 #include "exynos_drm_crtc.h"
0018 #include "exynos_drm_drv.h"
0019 #include "exynos_drm_plane.h"
0020 
0021 static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc,
0022                       struct drm_atomic_state *state)
0023 {
0024     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0025 
0026     if (exynos_crtc->ops->atomic_enable)
0027         exynos_crtc->ops->atomic_enable(exynos_crtc);
0028 
0029     drm_crtc_vblank_on(crtc);
0030 }
0031 
0032 static void exynos_drm_crtc_atomic_disable(struct drm_crtc *crtc,
0033                        struct drm_atomic_state *state)
0034 {
0035     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0036 
0037     drm_crtc_vblank_off(crtc);
0038 
0039     if (exynos_crtc->ops->atomic_disable)
0040         exynos_crtc->ops->atomic_disable(exynos_crtc);
0041 
0042     if (crtc->state->event && !crtc->state->active) {
0043         spin_lock_irq(&crtc->dev->event_lock);
0044         drm_crtc_send_vblank_event(crtc, crtc->state->event);
0045         spin_unlock_irq(&crtc->dev->event_lock);
0046 
0047         crtc->state->event = NULL;
0048     }
0049 }
0050 
0051 static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
0052                      struct drm_atomic_state *state)
0053 {
0054     struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
0055                                       crtc);
0056     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0057 
0058     if (!crtc_state->enable)
0059         return 0;
0060 
0061     if (exynos_crtc->ops->atomic_check)
0062         return exynos_crtc->ops->atomic_check(exynos_crtc, crtc_state);
0063 
0064     return 0;
0065 }
0066 
0067 static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
0068                      struct drm_atomic_state *state)
0069 {
0070     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0071 
0072     if (exynos_crtc->ops->atomic_begin)
0073         exynos_crtc->ops->atomic_begin(exynos_crtc);
0074 }
0075 
0076 static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
0077                      struct drm_atomic_state *state)
0078 {
0079     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0080 
0081     if (exynos_crtc->ops->atomic_flush)
0082         exynos_crtc->ops->atomic_flush(exynos_crtc);
0083 }
0084 
0085 static enum drm_mode_status exynos_crtc_mode_valid(struct drm_crtc *crtc,
0086     const struct drm_display_mode *mode)
0087 {
0088     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0089 
0090     if (exynos_crtc->ops->mode_valid)
0091         return exynos_crtc->ops->mode_valid(exynos_crtc, mode);
0092 
0093     return MODE_OK;
0094 }
0095 
0096 static bool exynos_crtc_mode_fixup(struct drm_crtc *crtc,
0097         const struct drm_display_mode *mode,
0098         struct drm_display_mode *adjusted_mode)
0099 {
0100     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0101 
0102     if (exynos_crtc->ops->mode_fixup)
0103         return exynos_crtc->ops->mode_fixup(exynos_crtc, mode,
0104                 adjusted_mode);
0105 
0106     return true;
0107 }
0108 
0109 
0110 static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
0111     .mode_valid = exynos_crtc_mode_valid,
0112     .mode_fixup = exynos_crtc_mode_fixup,
0113     .atomic_check   = exynos_crtc_atomic_check,
0114     .atomic_begin   = exynos_crtc_atomic_begin,
0115     .atomic_flush   = exynos_crtc_atomic_flush,
0116     .atomic_enable  = exynos_drm_crtc_atomic_enable,
0117     .atomic_disable = exynos_drm_crtc_atomic_disable,
0118 };
0119 
0120 void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc)
0121 {
0122     struct drm_crtc *crtc = &exynos_crtc->base;
0123     struct drm_pending_vblank_event *event = crtc->state->event;
0124     unsigned long flags;
0125 
0126     if (!event)
0127         return;
0128     crtc->state->event = NULL;
0129 
0130     WARN_ON(drm_crtc_vblank_get(crtc) != 0);
0131 
0132     spin_lock_irqsave(&crtc->dev->event_lock, flags);
0133     drm_crtc_arm_vblank_event(crtc, event);
0134     spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
0135 }
0136 
0137 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
0138 {
0139     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0140 
0141     drm_crtc_cleanup(crtc);
0142     kfree(exynos_crtc);
0143 }
0144 
0145 static int exynos_drm_crtc_enable_vblank(struct drm_crtc *crtc)
0146 {
0147     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0148 
0149     if (exynos_crtc->ops->enable_vblank)
0150         return exynos_crtc->ops->enable_vblank(exynos_crtc);
0151 
0152     return 0;
0153 }
0154 
0155 static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc)
0156 {
0157     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0158 
0159     if (exynos_crtc->ops->disable_vblank)
0160         exynos_crtc->ops->disable_vblank(exynos_crtc);
0161 }
0162 
0163 static const struct drm_crtc_funcs exynos_crtc_funcs = {
0164     .set_config = drm_atomic_helper_set_config,
0165     .page_flip  = drm_atomic_helper_page_flip,
0166     .destroy    = exynos_drm_crtc_destroy,
0167     .reset = drm_atomic_helper_crtc_reset,
0168     .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0169     .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0170     .enable_vblank = exynos_drm_crtc_enable_vblank,
0171     .disable_vblank = exynos_drm_crtc_disable_vblank,
0172 };
0173 
0174 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
0175                     struct drm_plane *plane,
0176                     enum exynos_drm_output_type type,
0177                     const struct exynos_drm_crtc_ops *ops,
0178                     void *ctx)
0179 {
0180     struct exynos_drm_crtc *exynos_crtc;
0181     struct drm_crtc *crtc;
0182     int ret;
0183 
0184     exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
0185     if (!exynos_crtc)
0186         return ERR_PTR(-ENOMEM);
0187 
0188     exynos_crtc->type = type;
0189     exynos_crtc->ops = ops;
0190     exynos_crtc->ctx = ctx;
0191 
0192     crtc = &exynos_crtc->base;
0193 
0194     ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
0195                     &exynos_crtc_funcs, NULL);
0196     if (ret < 0)
0197         goto err_crtc;
0198 
0199     drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
0200 
0201     return exynos_crtc;
0202 
0203 err_crtc:
0204     plane->funcs->destroy(plane);
0205     kfree(exynos_crtc);
0206     return ERR_PTR(ret);
0207 }
0208 
0209 struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev,
0210                        enum exynos_drm_output_type out_type)
0211 {
0212     struct drm_crtc *crtc;
0213 
0214     drm_for_each_crtc(crtc, drm_dev)
0215         if (to_exynos_crtc(crtc)->type == out_type)
0216             return to_exynos_crtc(crtc);
0217 
0218     return ERR_PTR(-ENODEV);
0219 }
0220 
0221 int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder,
0222         enum exynos_drm_output_type out_type)
0223 {
0224     struct exynos_drm_crtc *crtc = exynos_drm_crtc_get_by_type(encoder->dev,
0225                         out_type);
0226 
0227     if (IS_ERR(crtc))
0228         return PTR_ERR(crtc);
0229 
0230     encoder->possible_crtcs = drm_crtc_mask(&crtc->base);
0231 
0232     return 0;
0233 }
0234 
0235 void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
0236 {
0237     struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
0238 
0239     if (exynos_crtc->ops->te_handler)
0240         exynos_crtc->ops->te_handler(exynos_crtc);
0241 }