0001
0002
0003
0004
0005
0006
0007 #include <linux/of.h>
0008 #include <linux/of_graph.h>
0009 #include <linux/types.h>
0010 #include <linux/workqueue.h>
0011
0012 #include <drm/drm_atomic_helper.h>
0013 #include <drm/drm_crtc.h>
0014 #include <drm/drm_drv.h>
0015 #include <drm/drm_gem_cma_helper.h>
0016 #include <drm/drm_print.h>
0017 #include <drm/drm_vblank.h>
0018
0019 #include "logicvc_crtc.h"
0020 #include "logicvc_drm.h"
0021 #include "logicvc_interface.h"
0022 #include "logicvc_layer.h"
0023 #include "logicvc_regs.h"
0024
0025 #define logicvc_crtc(c) \
0026 container_of(c, struct logicvc_crtc, drm_crtc)
0027
0028 static enum drm_mode_status
0029 logicvc_crtc_mode_valid(struct drm_crtc *drm_crtc,
0030 const struct drm_display_mode *mode)
0031 {
0032 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
0033 return -EINVAL;
0034
0035 return 0;
0036 }
0037
0038 static void logicvc_crtc_atomic_begin(struct drm_crtc *drm_crtc,
0039 struct drm_atomic_state *state)
0040 {
0041 struct logicvc_crtc *crtc = logicvc_crtc(drm_crtc);
0042 struct drm_crtc_state *old_state =
0043 drm_atomic_get_old_crtc_state(state, drm_crtc);
0044 struct drm_device *drm_dev = drm_crtc->dev;
0045 unsigned long flags;
0046
0047
0048
0049
0050
0051 if (drm_crtc->state->event && old_state->active) {
0052 spin_lock_irqsave(&drm_dev->event_lock, flags);
0053 WARN_ON(drm_crtc_vblank_get(drm_crtc) != 0);
0054
0055 crtc->event = drm_crtc->state->event;
0056 drm_crtc->state->event = NULL;
0057
0058 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
0059 }
0060 }
0061
0062 static void logicvc_crtc_atomic_enable(struct drm_crtc *drm_crtc,
0063 struct drm_atomic_state *state)
0064 {
0065 struct logicvc_crtc *crtc = logicvc_crtc(drm_crtc);
0066 struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);
0067 struct drm_crtc_state *old_state =
0068 drm_atomic_get_old_crtc_state(state, drm_crtc);
0069 struct drm_crtc_state *new_state =
0070 drm_atomic_get_new_crtc_state(state, drm_crtc);
0071 struct drm_display_mode *mode = &new_state->adjusted_mode;
0072
0073 struct drm_device *drm_dev = drm_crtc->dev;
0074 unsigned int hact, hfp, hsl, hbp;
0075 unsigned int vact, vfp, vsl, vbp;
0076 unsigned long flags;
0077 u32 ctrl;
0078
0079
0080
0081 hact = mode->hdisplay;
0082 hfp = mode->hsync_start - mode->hdisplay;
0083 hsl = mode->hsync_end - mode->hsync_start;
0084 hbp = mode->htotal - mode->hsync_end;
0085
0086 vact = mode->vdisplay;
0087 vfp = mode->vsync_start - mode->vdisplay;
0088 vsl = mode->vsync_end - mode->vsync_start;
0089 vbp = mode->vtotal - mode->vsync_end;
0090
0091 regmap_write(logicvc->regmap, LOGICVC_HSYNC_FRONT_PORCH_REG, hfp - 1);
0092 regmap_write(logicvc->regmap, LOGICVC_HSYNC_REG, hsl - 1);
0093 regmap_write(logicvc->regmap, LOGICVC_HSYNC_BACK_PORCH_REG, hbp - 1);
0094 regmap_write(logicvc->regmap, LOGICVC_HRES_REG, hact - 1);
0095
0096 regmap_write(logicvc->regmap, LOGICVC_VSYNC_FRONT_PORCH_REG, vfp - 1);
0097 regmap_write(logicvc->regmap, LOGICVC_VSYNC_REG, vsl - 1);
0098 regmap_write(logicvc->regmap, LOGICVC_VSYNC_BACK_PORCH_REG, vbp - 1);
0099 regmap_write(logicvc->regmap, LOGICVC_VRES_REG, vact - 1);
0100
0101
0102
0103 ctrl = LOGICVC_CTRL_HSYNC_ENABLE | LOGICVC_CTRL_VSYNC_ENABLE |
0104 LOGICVC_CTRL_DE_ENABLE;
0105
0106 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
0107 ctrl |= LOGICVC_CTRL_HSYNC_INVERT;
0108
0109 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
0110 ctrl |= LOGICVC_CTRL_VSYNC_INVERT;
0111
0112 if (logicvc->interface) {
0113 struct drm_connector *connector =
0114 &logicvc->interface->drm_connector;
0115 struct drm_display_info *display_info =
0116 &connector->display_info;
0117
0118 if (display_info->bus_flags & DRM_BUS_FLAG_DE_LOW)
0119 ctrl |= LOGICVC_CTRL_DE_INVERT;
0120
0121 if (display_info->bus_flags &
0122 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
0123 ctrl |= LOGICVC_CTRL_CLOCK_INVERT;
0124 }
0125
0126 regmap_update_bits(logicvc->regmap, LOGICVC_CTRL_REG,
0127 LOGICVC_CTRL_HSYNC_ENABLE |
0128 LOGICVC_CTRL_HSYNC_INVERT |
0129 LOGICVC_CTRL_VSYNC_ENABLE |
0130 LOGICVC_CTRL_VSYNC_INVERT |
0131 LOGICVC_CTRL_DE_ENABLE |
0132 LOGICVC_CTRL_DE_INVERT |
0133 LOGICVC_CTRL_PIXEL_INVERT |
0134 LOGICVC_CTRL_CLOCK_INVERT, ctrl);
0135
0136
0137 regmap_write(logicvc->regmap, LOGICVC_DTYPE_REG, 0);
0138
0139 drm_crtc_vblank_on(drm_crtc);
0140
0141
0142 if (drm_crtc->state->event && !old_state->active) {
0143 spin_lock_irqsave(&drm_dev->event_lock, flags);
0144 WARN_ON(drm_crtc_vblank_get(drm_crtc) != 0);
0145
0146 crtc->event = drm_crtc->state->event;
0147 drm_crtc->state->event = NULL;
0148 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
0149 }
0150 }
0151
0152 static void logicvc_crtc_atomic_disable(struct drm_crtc *drm_crtc,
0153 struct drm_atomic_state *state)
0154 {
0155 struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);
0156 struct drm_device *drm_dev = drm_crtc->dev;
0157
0158 drm_crtc_vblank_off(drm_crtc);
0159
0160
0161 regmap_update_bits(logicvc->regmap, LOGICVC_CTRL_REG,
0162 LOGICVC_CTRL_HSYNC_ENABLE |
0163 LOGICVC_CTRL_HSYNC_INVERT |
0164 LOGICVC_CTRL_VSYNC_ENABLE |
0165 LOGICVC_CTRL_VSYNC_INVERT |
0166 LOGICVC_CTRL_DE_ENABLE |
0167 LOGICVC_CTRL_DE_INVERT |
0168 LOGICVC_CTRL_PIXEL_INVERT |
0169 LOGICVC_CTRL_CLOCK_INVERT, 0);
0170
0171
0172 regmap_write(logicvc->regmap, LOGICVC_DTYPE_REG, 0);
0173
0174
0175 if (drm_crtc->state->event && !drm_crtc->state->active) {
0176 spin_lock_irq(&drm_dev->event_lock);
0177
0178 drm_crtc_send_vblank_event(drm_crtc, drm_crtc->state->event);
0179 drm_crtc->state->event = NULL;
0180 spin_unlock_irq(&drm_dev->event_lock);
0181 }
0182 }
0183
0184 static const struct drm_crtc_helper_funcs logicvc_crtc_helper_funcs = {
0185 .mode_valid = logicvc_crtc_mode_valid,
0186 .atomic_begin = logicvc_crtc_atomic_begin,
0187 .atomic_enable = logicvc_crtc_atomic_enable,
0188 .atomic_disable = logicvc_crtc_atomic_disable,
0189 };
0190
0191 static int logicvc_crtc_enable_vblank(struct drm_crtc *drm_crtc)
0192 {
0193 struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);
0194
0195
0196 regmap_write_bits(logicvc->regmap, LOGICVC_INT_STAT_REG,
0197 LOGICVC_INT_STAT_V_SYNC, LOGICVC_INT_STAT_V_SYNC);
0198
0199
0200 regmap_write_bits(logicvc->regmap, LOGICVC_INT_MASK_REG,
0201 LOGICVC_INT_MASK_V_SYNC, 0);
0202
0203 return 0;
0204 }
0205
0206 static void logicvc_crtc_disable_vblank(struct drm_crtc *drm_crtc)
0207 {
0208 struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);
0209
0210
0211 regmap_write_bits(logicvc->regmap, LOGICVC_INT_MASK_REG,
0212 LOGICVC_INT_MASK_V_SYNC, LOGICVC_INT_MASK_V_SYNC);
0213 }
0214
0215 static const struct drm_crtc_funcs logicvc_crtc_funcs = {
0216 .reset = drm_atomic_helper_crtc_reset,
0217 .destroy = drm_crtc_cleanup,
0218 .set_config = drm_atomic_helper_set_config,
0219 .page_flip = drm_atomic_helper_page_flip,
0220 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0221 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0222 .enable_vblank = logicvc_crtc_enable_vblank,
0223 .disable_vblank = logicvc_crtc_disable_vblank,
0224 };
0225
0226 void logicvc_crtc_vblank_handler(struct logicvc_drm *logicvc)
0227 {
0228 struct drm_device *drm_dev = &logicvc->drm_dev;
0229 struct logicvc_crtc *crtc = logicvc->crtc;
0230 unsigned long flags;
0231
0232 if (!crtc)
0233 return;
0234
0235 drm_crtc_handle_vblank(&crtc->drm_crtc);
0236
0237 if (crtc->event) {
0238 spin_lock_irqsave(&drm_dev->event_lock, flags);
0239 drm_crtc_send_vblank_event(&crtc->drm_crtc, crtc->event);
0240 drm_crtc_vblank_put(&crtc->drm_crtc);
0241 crtc->event = NULL;
0242 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
0243 }
0244 }
0245
0246 int logicvc_crtc_init(struct logicvc_drm *logicvc)
0247 {
0248 struct drm_device *drm_dev = &logicvc->drm_dev;
0249 struct device *dev = drm_dev->dev;
0250 struct device_node *of_node = dev->of_node;
0251 struct logicvc_crtc *crtc;
0252 struct logicvc_layer *layer_primary;
0253 int ret;
0254
0255 crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL);
0256 if (!crtc)
0257 return -ENOMEM;
0258
0259 layer_primary = logicvc_layer_get_primary(logicvc);
0260 if (!layer_primary) {
0261 drm_err(drm_dev, "Failed to get primary layer\n");
0262 return -EINVAL;
0263 }
0264
0265 ret = drm_crtc_init_with_planes(drm_dev, &crtc->drm_crtc,
0266 &layer_primary->drm_plane, NULL,
0267 &logicvc_crtc_funcs, NULL);
0268 if (ret) {
0269 drm_err(drm_dev, "Failed to initialize CRTC\n");
0270 return ret;
0271 }
0272
0273 drm_crtc_helper_add(&crtc->drm_crtc, &logicvc_crtc_helper_funcs);
0274
0275 crtc->drm_crtc.port = of_graph_get_port_by_id(of_node, 1);
0276
0277 logicvc->crtc = crtc;
0278
0279 return 0;
0280 }