Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2015 Free Electrons
0004  * Copyright (C) 2015 NextThing Co
0005  *
0006  * Maxime Ripard <maxime.ripard@free-electrons.com>
0007  */
0008 
0009 #include <linux/clk-provider.h>
0010 #include <linux/ioport.h>
0011 #include <linux/of_address.h>
0012 #include <linux/of_graph.h>
0013 #include <linux/of_irq.h>
0014 #include <linux/regmap.h>
0015 
0016 #include <video/videomode.h>
0017 
0018 #include <drm/drm_atomic.h>
0019 #include <drm/drm_atomic_helper.h>
0020 #include <drm/drm_crtc.h>
0021 #include <drm/drm_modes.h>
0022 #include <drm/drm_print.h>
0023 #include <drm/drm_probe_helper.h>
0024 #include <drm/drm_vblank.h>
0025 
0026 #include "sun4i_backend.h"
0027 #include "sun4i_crtc.h"
0028 #include "sun4i_drv.h"
0029 #include "sunxi_engine.h"
0030 #include "sun4i_tcon.h"
0031 
0032 /*
0033  * While this isn't really working in the DRM theory, in practice we
0034  * can only ever have one encoder per TCON since we have a mux in our
0035  * TCON.
0036  */
0037 static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
0038 {
0039     struct drm_encoder *encoder;
0040 
0041     drm_for_each_encoder(encoder, crtc->dev)
0042         if (encoder->crtc == crtc)
0043             return encoder;
0044 
0045     return NULL;
0046 }
0047 
0048 static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
0049                     struct drm_atomic_state *state)
0050 {
0051     struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
0052                                       crtc);
0053     struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
0054     struct sunxi_engine *engine = scrtc->engine;
0055     int ret = 0;
0056 
0057     if (engine && engine->ops && engine->ops->atomic_check)
0058         ret = engine->ops->atomic_check(engine, crtc_state);
0059 
0060     return ret;
0061 }
0062 
0063 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
0064                     struct drm_atomic_state *state)
0065 {
0066     struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
0067                                      crtc);
0068     struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
0069     struct drm_device *dev = crtc->dev;
0070     struct sunxi_engine *engine = scrtc->engine;
0071     unsigned long flags;
0072 
0073     if (crtc->state->event) {
0074         WARN_ON(drm_crtc_vblank_get(crtc) != 0);
0075 
0076         spin_lock_irqsave(&dev->event_lock, flags);
0077         scrtc->event = crtc->state->event;
0078         spin_unlock_irqrestore(&dev->event_lock, flags);
0079         crtc->state->event = NULL;
0080     }
0081 
0082     if (engine->ops->atomic_begin)
0083         engine->ops->atomic_begin(engine, old_state);
0084 }
0085 
0086 static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
0087                     struct drm_atomic_state *state)
0088 {
0089     struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
0090     struct drm_pending_vblank_event *event = crtc->state->event;
0091 
0092     DRM_DEBUG_DRIVER("Committing plane changes\n");
0093 
0094     sunxi_engine_commit(scrtc->engine);
0095 
0096     if (event) {
0097         crtc->state->event = NULL;
0098 
0099         spin_lock_irq(&crtc->dev->event_lock);
0100         if (drm_crtc_vblank_get(crtc) == 0)
0101             drm_crtc_arm_vblank_event(crtc, event);
0102         else
0103             drm_crtc_send_vblank_event(crtc, event);
0104         spin_unlock_irq(&crtc->dev->event_lock);
0105     }
0106 }
0107 
0108 static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc,
0109                       struct drm_atomic_state *state)
0110 {
0111     struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
0112     struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
0113 
0114     DRM_DEBUG_DRIVER("Disabling the CRTC\n");
0115 
0116     drm_crtc_vblank_off(crtc);
0117 
0118     sun4i_tcon_set_status(scrtc->tcon, encoder, false);
0119 
0120     if (crtc->state->event && !crtc->state->active) {
0121         spin_lock_irq(&crtc->dev->event_lock);
0122         drm_crtc_send_vblank_event(crtc, crtc->state->event);
0123         spin_unlock_irq(&crtc->dev->event_lock);
0124 
0125         crtc->state->event = NULL;
0126     }
0127 }
0128 
0129 static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc,
0130                      struct drm_atomic_state *state)
0131 {
0132     struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
0133     struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
0134 
0135     DRM_DEBUG_DRIVER("Enabling the CRTC\n");
0136 
0137     sun4i_tcon_set_status(scrtc->tcon, encoder, true);
0138 
0139     drm_crtc_vblank_on(crtc);
0140 }
0141 
0142 static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
0143 {
0144     struct drm_display_mode *mode = &crtc->state->adjusted_mode;
0145     struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
0146     struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
0147 
0148     sun4i_tcon_mode_set(scrtc->tcon, encoder, mode);
0149     sunxi_engine_mode_set(scrtc->engine, mode);
0150 }
0151 
0152 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
0153     .atomic_check   = sun4i_crtc_atomic_check,
0154     .atomic_begin   = sun4i_crtc_atomic_begin,
0155     .atomic_flush   = sun4i_crtc_atomic_flush,
0156     .atomic_enable  = sun4i_crtc_atomic_enable,
0157     .atomic_disable = sun4i_crtc_atomic_disable,
0158     .mode_set_nofb  = sun4i_crtc_mode_set_nofb,
0159 };
0160 
0161 static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
0162 {
0163     struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
0164 
0165     DRM_DEBUG_DRIVER("Enabling VBLANK on crtc %p\n", crtc);
0166 
0167     sun4i_tcon_enable_vblank(scrtc->tcon, true);
0168 
0169     return 0;
0170 }
0171 
0172 static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc)
0173 {
0174     struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
0175 
0176     DRM_DEBUG_DRIVER("Disabling VBLANK on crtc %p\n", crtc);
0177 
0178     sun4i_tcon_enable_vblank(scrtc->tcon, false);
0179 }
0180 
0181 static const struct drm_crtc_funcs sun4i_crtc_funcs = {
0182     .atomic_destroy_state   = drm_atomic_helper_crtc_destroy_state,
0183     .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0184     .destroy        = drm_crtc_cleanup,
0185     .page_flip      = drm_atomic_helper_page_flip,
0186     .reset          = drm_atomic_helper_crtc_reset,
0187     .set_config     = drm_atomic_helper_set_config,
0188     .enable_vblank      = sun4i_crtc_enable_vblank,
0189     .disable_vblank     = sun4i_crtc_disable_vblank,
0190 };
0191 
0192 struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
0193                    struct sunxi_engine *engine,
0194                    struct sun4i_tcon *tcon)
0195 {
0196     struct sun4i_crtc *scrtc;
0197     struct drm_plane **planes;
0198     struct drm_plane *primary = NULL, *cursor = NULL;
0199     int ret, i;
0200 
0201     scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
0202     if (!scrtc)
0203         return ERR_PTR(-ENOMEM);
0204     scrtc->engine = engine;
0205     scrtc->tcon = tcon;
0206 
0207     /* Create our layers */
0208     planes = sunxi_engine_layers_init(drm, engine);
0209     if (IS_ERR(planes)) {
0210         dev_err(drm->dev, "Couldn't create the planes\n");
0211         return NULL;
0212     }
0213 
0214     /* find primary and cursor planes for drm_crtc_init_with_planes */
0215     for (i = 0; planes[i]; i++) {
0216         struct drm_plane *plane = planes[i];
0217 
0218         switch (plane->type) {
0219         case DRM_PLANE_TYPE_PRIMARY:
0220             primary = plane;
0221             break;
0222         case DRM_PLANE_TYPE_CURSOR:
0223             cursor = plane;
0224             break;
0225         default:
0226             break;
0227         }
0228     }
0229 
0230     ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
0231                     primary,
0232                     cursor,
0233                     &sun4i_crtc_funcs,
0234                     NULL);
0235     if (ret) {
0236         dev_err(drm->dev, "Couldn't init DRM CRTC\n");
0237         return ERR_PTR(ret);
0238     }
0239 
0240     drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs);
0241 
0242     /* Set crtc.port to output port node of the tcon */
0243     scrtc->crtc.port = of_graph_get_port_by_id(scrtc->tcon->dev->of_node,
0244                            1);
0245 
0246     /* Set possible_crtcs to this crtc for overlay planes */
0247     for (i = 0; planes[i]; i++) {
0248         uint32_t possible_crtcs = drm_crtc_mask(&scrtc->crtc);
0249         struct drm_plane *plane = planes[i];
0250 
0251         if (plane->type == DRM_PLANE_TYPE_OVERLAY)
0252             plane->possible_crtcs = possible_crtcs;
0253     }
0254 
0255     return scrtc;
0256 }