1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 5 */ 6 7 #include <drm/drm_atomic.h> 8 #include <drm/drm_atomic_helper.h> 9 #include <drm/drm_crtc.h> 10 #include <drm/drm_crtc_helper.h> 11 #include <drm/drm_fb_cma_helper.h> 12 #include <drm/drm_gem_cma_helper.h> 13 #include <drm/drm_plane_helper.h> 14 #include <drm/drm_vblank.h> 15 16 #include "tidss_crtc.h" 17 #include "tidss_dispc.h" 18 #include "tidss_drv.h" 19 #include "tidss_irq.h" 20 21 /* Page flip and frame done IRQs */ 22 23 static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc) 24 { 25 struct drm_device *ddev = tcrtc->crtc.dev; 26 struct tidss_device *tidss = ddev->dev_private; 27 struct drm_pending_vblank_event *event; 28 unsigned long flags; 29 bool busy; 30 31 spin_lock_irqsave(&ddev->event_lock, flags); 32 33 /* 34 * New settings are taken into use at VFP, and GO bit is cleared at 35 * the same time. This happens before the vertical blank interrupt. 36 * So there is a small change that the driver sets GO bit after VFP, but 37 * before vblank, and we have to check for that case here. 38 */ 39 busy = dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport); 40 if (busy) { 41 spin_unlock_irqrestore(&ddev->event_lock, flags); 42 return; 43 } 44 45 event = tcrtc->event; 46 tcrtc->event = NULL; 47 48 if (!event) { 49 spin_unlock_irqrestore(&ddev->event_lock, flags); 50 return; 51 } 52 53 drm_crtc_send_vblank_event(&tcrtc->crtc, event); 54 55 spin_unlock_irqrestore(&ddev->event_lock, flags); 56 57 drm_crtc_vblank_put(&tcrtc->crtc); 58 } 59 60 void tidss_crtc_vblank_irq(struct drm_crtc *crtc) 61 { 62 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 63 64 drm_crtc_handle_vblank(crtc); 65 66 tidss_crtc_finish_page_flip(tcrtc); 67 } 68 69 void tidss_crtc_framedone_irq(struct drm_crtc *crtc) 70 { 71 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 72 73 complete(&tcrtc->framedone_completion); 74 } 75 76 void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus) 77 { 78 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 79 80 dev_err_ratelimited(crtc->dev->dev, "CRTC%u SYNC LOST: (irq %llx)\n", 81 tcrtc->hw_videoport, irqstatus); 82 } 83 84 /* drm_crtc_helper_funcs */ 85 86 static int tidss_crtc_atomic_check(struct drm_crtc *crtc, 87 struct drm_crtc_state *state) 88 { 89 struct drm_device *ddev = crtc->dev; 90 struct tidss_device *tidss = ddev->dev_private; 91 struct dispc_device *dispc = tidss->dispc; 92 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 93 u32 hw_videoport = tcrtc->hw_videoport; 94 const struct drm_display_mode *mode; 95 enum drm_mode_status ok; 96 97 dev_dbg(ddev->dev, "%s\n", __func__); 98 99 if (!state->enable) 100 return 0; 101 102 mode = &state->adjusted_mode; 103 104 ok = dispc_vp_mode_valid(dispc, hw_videoport, mode); 105 if (ok != MODE_OK) { 106 dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n", 107 __func__, mode->hdisplay, mode->vdisplay, mode->clock); 108 return -EINVAL; 109 } 110 111 return dispc_vp_bus_check(dispc, hw_videoport, state); 112 } 113 114 static void tidss_crtc_atomic_flush(struct drm_crtc *crtc, 115 struct drm_crtc_state *old_crtc_state) 116 { 117 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 118 struct drm_device *ddev = crtc->dev; 119 struct tidss_device *tidss = ddev->dev_private; 120 unsigned long flags; 121 122 dev_dbg(ddev->dev, 123 "%s: %s enabled %d, needs modeset %d, event %p\n", __func__, 124 crtc->name, drm_atomic_crtc_needs_modeset(crtc->state), 125 crtc->state->enable, crtc->state->event); 126 127 /* There is nothing to do if CRTC is not going to be enabled. */ 128 if (!crtc->state->enable) 129 return; 130 131 /* 132 * Flush CRTC changes with go bit only if new modeset is not 133 * coming, so CRTC is enabled trough out the commit. 134 */ 135 if (drm_atomic_crtc_needs_modeset(crtc->state)) 136 return; 137 138 /* If the GO bit is stuck we better quit here. */ 139 if (WARN_ON(dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport))) 140 return; 141 142 /* We should have event if CRTC is enabled through out this commit. */ 143 if (WARN_ON(!crtc->state->event)) 144 return; 145 146 /* Write vp properties to HW if needed. */ 147 dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false); 148 149 WARN_ON(drm_crtc_vblank_get(crtc) != 0); 150 151 spin_lock_irqsave(&ddev->event_lock, flags); 152 dispc_vp_go(tidss->dispc, tcrtc->hw_videoport); 153 154 WARN_ON(tcrtc->event); 155 156 tcrtc->event = crtc->state->event; 157 crtc->state->event = NULL; 158 159 spin_unlock_irqrestore(&ddev->event_lock, flags); 160 } 161 162 static void tidss_crtc_atomic_enable(struct drm_crtc *crtc, 163 struct drm_crtc_state *old_state) 164 { 165 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 166 struct drm_device *ddev = crtc->dev; 167 struct tidss_device *tidss = ddev->dev_private; 168 const struct drm_display_mode *mode = &crtc->state->adjusted_mode; 169 unsigned long flags; 170 int r; 171 172 dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event); 173 174 tidss_runtime_get(tidss); 175 176 r = dispc_vp_set_clk_rate(tidss->dispc, tcrtc->hw_videoport, 177 mode->clock * 1000); 178 if (r != 0) 179 return; 180 181 r = dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport); 182 if (r != 0) 183 return; 184 185 dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true); 186 187 /* Turn vertical blanking interrupt reporting on. */ 188 drm_crtc_vblank_on(crtc); 189 190 dispc_vp_prepare(tidss->dispc, tcrtc->hw_videoport, crtc->state); 191 192 dispc_vp_enable(tidss->dispc, tcrtc->hw_videoport, crtc->state); 193 194 spin_lock_irqsave(&ddev->event_lock, flags); 195 196 if (crtc->state->event) { 197 drm_crtc_send_vblank_event(crtc, crtc->state->event); 198 crtc->state->event = NULL; 199 } 200 201 spin_unlock_irqrestore(&ddev->event_lock, flags); 202 } 203 204 static void tidss_crtc_atomic_disable(struct drm_crtc *crtc, 205 struct drm_crtc_state *old_state) 206 { 207 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 208 struct drm_device *ddev = crtc->dev; 209 struct tidss_device *tidss = ddev->dev_private; 210 unsigned long flags; 211 212 dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event); 213 214 reinit_completion(&tcrtc->framedone_completion); 215 216 dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport); 217 218 if (!wait_for_completion_timeout(&tcrtc->framedone_completion, 219 msecs_to_jiffies(500))) 220 dev_err(tidss->dev, "Timeout waiting for framedone on crtc %d", 221 tcrtc->hw_videoport); 222 223 dispc_vp_unprepare(tidss->dispc, tcrtc->hw_videoport); 224 225 spin_lock_irqsave(&ddev->event_lock, flags); 226 if (crtc->state->event) { 227 drm_crtc_send_vblank_event(crtc, crtc->state->event); 228 crtc->state->event = NULL; 229 } 230 spin_unlock_irqrestore(&ddev->event_lock, flags); 231 232 drm_crtc_vblank_off(crtc); 233 234 dispc_vp_disable_clk(tidss->dispc, tcrtc->hw_videoport); 235 236 tidss_runtime_put(tidss); 237 } 238 239 static 240 enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc, 241 const struct drm_display_mode *mode) 242 { 243 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 244 struct drm_device *ddev = crtc->dev; 245 struct tidss_device *tidss = ddev->dev_private; 246 247 return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode); 248 } 249 250 static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = { 251 .atomic_check = tidss_crtc_atomic_check, 252 .atomic_flush = tidss_crtc_atomic_flush, 253 .atomic_enable = tidss_crtc_atomic_enable, 254 .atomic_disable = tidss_crtc_atomic_disable, 255 256 .mode_valid = tidss_crtc_mode_valid, 257 }; 258 259 /* drm_crtc_funcs */ 260 261 static int tidss_crtc_enable_vblank(struct drm_crtc *crtc) 262 { 263 struct drm_device *ddev = crtc->dev; 264 struct tidss_device *tidss = ddev->dev_private; 265 266 dev_dbg(ddev->dev, "%s\n", __func__); 267 268 tidss_runtime_get(tidss); 269 270 tidss_irq_enable_vblank(crtc); 271 272 return 0; 273 } 274 275 static void tidss_crtc_disable_vblank(struct drm_crtc *crtc) 276 { 277 struct drm_device *ddev = crtc->dev; 278 struct tidss_device *tidss = ddev->dev_private; 279 280 dev_dbg(ddev->dev, "%s\n", __func__); 281 282 tidss_irq_disable_vblank(crtc); 283 284 tidss_runtime_put(tidss); 285 } 286 287 static void tidss_crtc_reset(struct drm_crtc *crtc) 288 { 289 struct tidss_crtc_state *tcrtc; 290 291 if (crtc->state) 292 __drm_atomic_helper_crtc_destroy_state(crtc->state); 293 294 kfree(crtc->state); 295 296 tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL); 297 if (!tcrtc) { 298 crtc->state = NULL; 299 return; 300 } 301 302 crtc->state = &tcrtc->base; 303 crtc->state->crtc = crtc; 304 } 305 306 static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc) 307 { 308 struct tidss_crtc_state *state, *current_state; 309 310 if (WARN_ON(!crtc->state)) 311 return NULL; 312 313 current_state = to_tidss_crtc_state(crtc->state); 314 315 state = kmalloc(sizeof(*state), GFP_KERNEL); 316 if (!state) 317 return NULL; 318 319 __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); 320 321 state->bus_format = current_state->bus_format; 322 state->bus_flags = current_state->bus_flags; 323 324 return &state->base; 325 } 326 327 static const struct drm_crtc_funcs tidss_crtc_funcs = { 328 .reset = tidss_crtc_reset, 329 .destroy = drm_crtc_cleanup, 330 .set_config = drm_atomic_helper_set_config, 331 .page_flip = drm_atomic_helper_page_flip, 332 .atomic_duplicate_state = tidss_crtc_duplicate_state, 333 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 334 .enable_vblank = tidss_crtc_enable_vblank, 335 .disable_vblank = tidss_crtc_disable_vblank, 336 }; 337 338 struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss, 339 u32 hw_videoport, 340 struct drm_plane *primary) 341 { 342 struct tidss_crtc *tcrtc; 343 struct drm_crtc *crtc; 344 unsigned int gamma_lut_size = 0; 345 bool has_ctm = tidss->feat->vp_feat.color.has_ctm; 346 int ret; 347 348 tcrtc = devm_kzalloc(tidss->dev, sizeof(*tcrtc), GFP_KERNEL); 349 if (!tcrtc) 350 return ERR_PTR(-ENOMEM); 351 352 tcrtc->hw_videoport = hw_videoport; 353 init_completion(&tcrtc->framedone_completion); 354 355 crtc = &tcrtc->crtc; 356 357 ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary, 358 NULL, &tidss_crtc_funcs, NULL); 359 if (ret < 0) 360 return ERR_PTR(ret); 361 362 drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs); 363 364 /* 365 * The dispc gamma functions adapt to what ever size we ask 366 * from it no matter what HW supports. X-server assumes 256 367 * element gamma tables so lets use that. 368 */ 369 if (tidss->feat->vp_feat.color.gamma_size) 370 gamma_lut_size = 256; 371 372 drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size); 373 if (gamma_lut_size) 374 drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size); 375 376 return tcrtc; 377 } 378