1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015 Free Electrons 4 * Copyright (C) 2015 NextThing Co 5 * 6 * Maxime Ripard <maxime.ripard@free-electrons.com> 7 */ 8 9 #include <linux/clk-provider.h> 10 #include <linux/ioport.h> 11 #include <linux/of_address.h> 12 #include <linux/of_graph.h> 13 #include <linux/of_irq.h> 14 #include <linux/regmap.h> 15 16 #include <video/videomode.h> 17 18 #include <drm/drm_atomic_helper.h> 19 #include <drm/drm_crtc.h> 20 #include <drm/drm_modes.h> 21 #include <drm/drm_print.h> 22 #include <drm/drm_probe_helper.h> 23 #include <drm/drm_vblank.h> 24 25 #include "sun4i_backend.h" 26 #include "sun4i_crtc.h" 27 #include "sun4i_drv.h" 28 #include "sunxi_engine.h" 29 #include "sun4i_tcon.h" 30 31 /* 32 * While this isn't really working in the DRM theory, in practice we 33 * can only ever have one encoder per TCON since we have a mux in our 34 * TCON. 35 */ 36 static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc) 37 { 38 struct drm_encoder *encoder; 39 40 drm_for_each_encoder(encoder, crtc->dev) 41 if (encoder->crtc == crtc) 42 return encoder; 43 44 return NULL; 45 } 46 47 static int sun4i_crtc_atomic_check(struct drm_crtc *crtc, 48 struct drm_crtc_state *state) 49 { 50 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 51 struct sunxi_engine *engine = scrtc->engine; 52 int ret = 0; 53 54 if (engine && engine->ops && engine->ops->atomic_check) 55 ret = engine->ops->atomic_check(engine, state); 56 57 return ret; 58 } 59 60 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, 61 struct drm_crtc_state *old_state) 62 { 63 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 64 struct drm_device *dev = crtc->dev; 65 struct sunxi_engine *engine = scrtc->engine; 66 unsigned long flags; 67 68 if (crtc->state->event) { 69 WARN_ON(drm_crtc_vblank_get(crtc) != 0); 70 71 spin_lock_irqsave(&dev->event_lock, flags); 72 scrtc->event = crtc->state->event; 73 spin_unlock_irqrestore(&dev->event_lock, flags); 74 crtc->state->event = NULL; 75 } 76 77 if (engine->ops->atomic_begin) 78 engine->ops->atomic_begin(engine, old_state); 79 } 80 81 static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, 82 struct drm_crtc_state *old_state) 83 { 84 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 85 struct drm_pending_vblank_event *event = crtc->state->event; 86 87 DRM_DEBUG_DRIVER("Committing plane changes\n"); 88 89 sunxi_engine_commit(scrtc->engine); 90 91 if (event) { 92 crtc->state->event = NULL; 93 94 spin_lock_irq(&crtc->dev->event_lock); 95 if (drm_crtc_vblank_get(crtc) == 0) 96 drm_crtc_arm_vblank_event(crtc, event); 97 else 98 drm_crtc_send_vblank_event(crtc, event); 99 spin_unlock_irq(&crtc->dev->event_lock); 100 } 101 } 102 103 static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, 104 struct drm_crtc_state *old_state) 105 { 106 struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc); 107 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 108 109 DRM_DEBUG_DRIVER("Disabling the CRTC\n"); 110 111 drm_crtc_vblank_off(crtc); 112 113 sun4i_tcon_set_status(scrtc->tcon, encoder, false); 114 115 if (crtc->state->event && !crtc->state->active) { 116 spin_lock_irq(&crtc->dev->event_lock); 117 drm_crtc_send_vblank_event(crtc, crtc->state->event); 118 spin_unlock_irq(&crtc->dev->event_lock); 119 120 crtc->state->event = NULL; 121 } 122 } 123 124 static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc, 125 struct drm_crtc_state *old_state) 126 { 127 struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc); 128 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 129 130 DRM_DEBUG_DRIVER("Enabling the CRTC\n"); 131 132 sun4i_tcon_set_status(scrtc->tcon, encoder, true); 133 134 drm_crtc_vblank_on(crtc); 135 } 136 137 static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) 138 { 139 struct drm_display_mode *mode = &crtc->state->adjusted_mode; 140 struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc); 141 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 142 143 sun4i_tcon_mode_set(scrtc->tcon, encoder, mode); 144 } 145 146 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { 147 .atomic_check = sun4i_crtc_atomic_check, 148 .atomic_begin = sun4i_crtc_atomic_begin, 149 .atomic_flush = sun4i_crtc_atomic_flush, 150 .atomic_enable = sun4i_crtc_atomic_enable, 151 .atomic_disable = sun4i_crtc_atomic_disable, 152 .mode_set_nofb = sun4i_crtc_mode_set_nofb, 153 }; 154 155 static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc) 156 { 157 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 158 159 DRM_DEBUG_DRIVER("Enabling VBLANK on crtc %p\n", crtc); 160 161 sun4i_tcon_enable_vblank(scrtc->tcon, true); 162 163 return 0; 164 } 165 166 static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc) 167 { 168 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 169 170 DRM_DEBUG_DRIVER("Disabling VBLANK on crtc %p\n", crtc); 171 172 sun4i_tcon_enable_vblank(scrtc->tcon, false); 173 } 174 175 static const struct drm_crtc_funcs sun4i_crtc_funcs = { 176 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 177 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 178 .destroy = drm_crtc_cleanup, 179 .page_flip = drm_atomic_helper_page_flip, 180 .reset = drm_atomic_helper_crtc_reset, 181 .set_config = drm_atomic_helper_set_config, 182 .enable_vblank = sun4i_crtc_enable_vblank, 183 .disable_vblank = sun4i_crtc_disable_vblank, 184 }; 185 186 struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, 187 struct sunxi_engine *engine, 188 struct sun4i_tcon *tcon) 189 { 190 struct sun4i_crtc *scrtc; 191 struct drm_plane **planes; 192 struct drm_plane *primary = NULL, *cursor = NULL; 193 int ret, i; 194 195 scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL); 196 if (!scrtc) 197 return ERR_PTR(-ENOMEM); 198 scrtc->engine = engine; 199 scrtc->tcon = tcon; 200 201 /* Create our layers */ 202 planes = sunxi_engine_layers_init(drm, engine); 203 if (IS_ERR(planes)) { 204 dev_err(drm->dev, "Couldn't create the planes\n"); 205 return NULL; 206 } 207 208 /* find primary and cursor planes for drm_crtc_init_with_planes */ 209 for (i = 0; planes[i]; i++) { 210 struct drm_plane *plane = planes[i]; 211 212 switch (plane->type) { 213 case DRM_PLANE_TYPE_PRIMARY: 214 primary = plane; 215 break; 216 case DRM_PLANE_TYPE_CURSOR: 217 cursor = plane; 218 break; 219 default: 220 break; 221 } 222 } 223 224 ret = drm_crtc_init_with_planes(drm, &scrtc->crtc, 225 primary, 226 cursor, 227 &sun4i_crtc_funcs, 228 NULL); 229 if (ret) { 230 dev_err(drm->dev, "Couldn't init DRM CRTC\n"); 231 return ERR_PTR(ret); 232 } 233 234 drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs); 235 236 /* Set crtc.port to output port node of the tcon */ 237 scrtc->crtc.port = of_graph_get_port_by_id(scrtc->tcon->dev->of_node, 238 1); 239 240 /* Set possible_crtcs to this crtc for overlay planes */ 241 for (i = 0; planes[i]; i++) { 242 uint32_t possible_crtcs = drm_crtc_mask(&scrtc->crtc); 243 struct drm_plane *plane = planes[i]; 244 245 if (plane->type == DRM_PLANE_TYPE_OVERLAY) 246 plane->possible_crtcs = possible_crtcs; 247 } 248 249 return scrtc; 250 } 251