1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2019-2022 Bootlin 4 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> 5 */ 6 7 #include <linux/of.h> 8 #include <linux/of_graph.h> 9 #include <linux/types.h> 10 #include <linux/workqueue.h> 11 12 #include <drm/drm_atomic_helper.h> 13 #include <drm/drm_crtc.h> 14 #include <drm/drm_drv.h> 15 #include <drm/drm_gem_cma_helper.h> 16 #include <drm/drm_print.h> 17 #include <drm/drm_vblank.h> 18 19 #include "logicvc_crtc.h" 20 #include "logicvc_drm.h" 21 #include "logicvc_interface.h" 22 #include "logicvc_layer.h" 23 #include "logicvc_regs.h" 24 25 #define logicvc_crtc(c) \ 26 container_of(c, struct logicvc_crtc, drm_crtc) 27 28 static enum drm_mode_status 29 logicvc_crtc_mode_valid(struct drm_crtc *drm_crtc, 30 const struct drm_display_mode *mode) 31 { 32 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 33 return -EINVAL; 34 35 return 0; 36 } 37 38 static void logicvc_crtc_atomic_begin(struct drm_crtc *drm_crtc, 39 struct drm_atomic_state *state) 40 { 41 struct logicvc_crtc *crtc = logicvc_crtc(drm_crtc); 42 struct drm_crtc_state *old_state = 43 drm_atomic_get_old_crtc_state(state, drm_crtc); 44 struct drm_device *drm_dev = drm_crtc->dev; 45 unsigned long flags; 46 47 /* 48 * We need to grab the pending event here if vblank was already enabled 49 * since we won't get a call to atomic_enable to grab it. 50 */ 51 if (drm_crtc->state->event && old_state->active) { 52 spin_lock_irqsave(&drm_dev->event_lock, flags); 53 WARN_ON(drm_crtc_vblank_get(drm_crtc) != 0); 54 55 crtc->event = drm_crtc->state->event; 56 drm_crtc->state->event = NULL; 57 58 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 59 } 60 } 61 62 static void logicvc_crtc_atomic_enable(struct drm_crtc *drm_crtc, 63 struct drm_atomic_state *state) 64 { 65 struct logicvc_crtc *crtc = logicvc_crtc(drm_crtc); 66 struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev); 67 struct drm_crtc_state *old_state = 68 drm_atomic_get_old_crtc_state(state, drm_crtc); 69 struct drm_crtc_state *new_state = 70 drm_atomic_get_new_crtc_state(state, drm_crtc); 71 struct drm_display_mode *mode = &new_state->adjusted_mode; 72 73 struct drm_device *drm_dev = drm_crtc->dev; 74 unsigned int hact, hfp, hsl, hbp; 75 unsigned int vact, vfp, vsl, vbp; 76 unsigned long flags; 77 u32 ctrl; 78 79 /* Timings */ 80 81 hact = mode->hdisplay; 82 hfp = mode->hsync_start - mode->hdisplay; 83 hsl = mode->hsync_end - mode->hsync_start; 84 hbp = mode->htotal - mode->hsync_end; 85 86 vact = mode->vdisplay; 87 vfp = mode->vsync_start - mode->vdisplay; 88 vsl = mode->vsync_end - mode->vsync_start; 89 vbp = mode->vtotal - mode->vsync_end; 90 91 regmap_write(logicvc->regmap, LOGICVC_HSYNC_FRONT_PORCH_REG, hfp - 1); 92 regmap_write(logicvc->regmap, LOGICVC_HSYNC_REG, hsl - 1); 93 regmap_write(logicvc->regmap, LOGICVC_HSYNC_BACK_PORCH_REG, hbp - 1); 94 regmap_write(logicvc->regmap, LOGICVC_HRES_REG, hact - 1); 95 96 regmap_write(logicvc->regmap, LOGICVC_VSYNC_FRONT_PORCH_REG, vfp - 1); 97 regmap_write(logicvc->regmap, LOGICVC_VSYNC_REG, vsl - 1); 98 regmap_write(logicvc->regmap, LOGICVC_VSYNC_BACK_PORCH_REG, vbp - 1); 99 regmap_write(logicvc->regmap, LOGICVC_VRES_REG, vact - 1); 100 101 /* Signals */ 102 103 ctrl = LOGICVC_CTRL_HSYNC_ENABLE | LOGICVC_CTRL_VSYNC_ENABLE | 104 LOGICVC_CTRL_DE_ENABLE; 105 106 if (mode->flags & DRM_MODE_FLAG_NHSYNC) 107 ctrl |= LOGICVC_CTRL_HSYNC_INVERT; 108 109 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 110 ctrl |= LOGICVC_CTRL_VSYNC_INVERT; 111 112 if (logicvc->interface) { 113 struct drm_connector *connector = 114 &logicvc->interface->drm_connector; 115 struct drm_display_info *display_info = 116 &connector->display_info; 117 118 if (display_info->bus_flags & DRM_BUS_FLAG_DE_LOW) 119 ctrl |= LOGICVC_CTRL_DE_INVERT; 120 121 if (display_info->bus_flags & 122 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) 123 ctrl |= LOGICVC_CTRL_CLOCK_INVERT; 124 } 125 126 regmap_update_bits(logicvc->regmap, LOGICVC_CTRL_REG, 127 LOGICVC_CTRL_HSYNC_ENABLE | 128 LOGICVC_CTRL_HSYNC_INVERT | 129 LOGICVC_CTRL_VSYNC_ENABLE | 130 LOGICVC_CTRL_VSYNC_INVERT | 131 LOGICVC_CTRL_DE_ENABLE | 132 LOGICVC_CTRL_DE_INVERT | 133 LOGICVC_CTRL_PIXEL_INVERT | 134 LOGICVC_CTRL_CLOCK_INVERT, ctrl); 135 136 /* Generate internal state reset. */ 137 regmap_write(logicvc->regmap, LOGICVC_DTYPE_REG, 0); 138 139 drm_crtc_vblank_on(drm_crtc); 140 141 /* Register our event after vblank is enabled. */ 142 if (drm_crtc->state->event && !old_state->active) { 143 spin_lock_irqsave(&drm_dev->event_lock, flags); 144 WARN_ON(drm_crtc_vblank_get(drm_crtc) != 0); 145 146 crtc->event = drm_crtc->state->event; 147 drm_crtc->state->event = NULL; 148 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 149 } 150 } 151 152 static void logicvc_crtc_atomic_disable(struct drm_crtc *drm_crtc, 153 struct drm_atomic_state *state) 154 { 155 struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev); 156 struct drm_device *drm_dev = drm_crtc->dev; 157 158 drm_crtc_vblank_off(drm_crtc); 159 160 /* Disable and clear CRTC bits. */ 161 regmap_update_bits(logicvc->regmap, LOGICVC_CTRL_REG, 162 LOGICVC_CTRL_HSYNC_ENABLE | 163 LOGICVC_CTRL_HSYNC_INVERT | 164 LOGICVC_CTRL_VSYNC_ENABLE | 165 LOGICVC_CTRL_VSYNC_INVERT | 166 LOGICVC_CTRL_DE_ENABLE | 167 LOGICVC_CTRL_DE_INVERT | 168 LOGICVC_CTRL_PIXEL_INVERT | 169 LOGICVC_CTRL_CLOCK_INVERT, 0); 170 171 /* Generate internal state reset. */ 172 regmap_write(logicvc->regmap, LOGICVC_DTYPE_REG, 0); 173 174 /* Consume any leftover event since vblank is now disabled. */ 175 if (drm_crtc->state->event && !drm_crtc->state->active) { 176 spin_lock_irq(&drm_dev->event_lock); 177 178 drm_crtc_send_vblank_event(drm_crtc, drm_crtc->state->event); 179 drm_crtc->state->event = NULL; 180 spin_unlock_irq(&drm_dev->event_lock); 181 } 182 } 183 184 static const struct drm_crtc_helper_funcs logicvc_crtc_helper_funcs = { 185 .mode_valid = logicvc_crtc_mode_valid, 186 .atomic_begin = logicvc_crtc_atomic_begin, 187 .atomic_enable = logicvc_crtc_atomic_enable, 188 .atomic_disable = logicvc_crtc_atomic_disable, 189 }; 190 191 static int logicvc_crtc_enable_vblank(struct drm_crtc *drm_crtc) 192 { 193 struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev); 194 195 /* Clear any pending V_SYNC interrupt. */ 196 regmap_write_bits(logicvc->regmap, LOGICVC_INT_STAT_REG, 197 LOGICVC_INT_STAT_V_SYNC, LOGICVC_INT_STAT_V_SYNC); 198 199 /* Unmask V_SYNC interrupt. */ 200 regmap_write_bits(logicvc->regmap, LOGICVC_INT_MASK_REG, 201 LOGICVC_INT_MASK_V_SYNC, 0); 202 203 return 0; 204 } 205 206 static void logicvc_crtc_disable_vblank(struct drm_crtc *drm_crtc) 207 { 208 struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev); 209 210 /* Mask V_SYNC interrupt. */ 211 regmap_write_bits(logicvc->regmap, LOGICVC_INT_MASK_REG, 212 LOGICVC_INT_MASK_V_SYNC, LOGICVC_INT_MASK_V_SYNC); 213 } 214 215 static const struct drm_crtc_funcs logicvc_crtc_funcs = { 216 .reset = drm_atomic_helper_crtc_reset, 217 .destroy = drm_crtc_cleanup, 218 .set_config = drm_atomic_helper_set_config, 219 .page_flip = drm_atomic_helper_page_flip, 220 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 221 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 222 .enable_vblank = logicvc_crtc_enable_vblank, 223 .disable_vblank = logicvc_crtc_disable_vblank, 224 }; 225 226 void logicvc_crtc_vblank_handler(struct logicvc_drm *logicvc) 227 { 228 struct drm_device *drm_dev = &logicvc->drm_dev; 229 struct logicvc_crtc *crtc = logicvc->crtc; 230 unsigned long flags; 231 232 if (!crtc) 233 return; 234 235 drm_crtc_handle_vblank(&crtc->drm_crtc); 236 237 if (crtc->event) { 238 spin_lock_irqsave(&drm_dev->event_lock, flags); 239 drm_crtc_send_vblank_event(&crtc->drm_crtc, crtc->event); 240 drm_crtc_vblank_put(&crtc->drm_crtc); 241 crtc->event = NULL; 242 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 243 } 244 } 245 246 int logicvc_crtc_init(struct logicvc_drm *logicvc) 247 { 248 struct drm_device *drm_dev = &logicvc->drm_dev; 249 struct device *dev = drm_dev->dev; 250 struct device_node *of_node = dev->of_node; 251 struct logicvc_crtc *crtc; 252 struct logicvc_layer *layer_primary; 253 int ret; 254 255 crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL); 256 if (!crtc) 257 return -ENOMEM; 258 259 layer_primary = logicvc_layer_get_primary(logicvc); 260 if (!layer_primary) { 261 drm_err(drm_dev, "Failed to get primary layer\n"); 262 return -EINVAL; 263 } 264 265 ret = drm_crtc_init_with_planes(drm_dev, &crtc->drm_crtc, 266 &layer_primary->drm_plane, NULL, 267 &logicvc_crtc_funcs, NULL); 268 if (ret) { 269 drm_err(drm_dev, "Failed to initialize CRTC\n"); 270 return ret; 271 } 272 273 drm_crtc_helper_add(&crtc->drm_crtc, &logicvc_crtc_helper_funcs); 274 275 crtc->drm_crtc.port = of_graph_get_port_by_id(of_node, 1); 276 277 logicvc->crtc = crtc; 278 279 return 0; 280 } 281