1/* 2 * Copyright (C) STMicroelectronics SA 2014 3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * for STMicroelectronics. 6 * License terms: GNU General Public License (GPL), version 2 7 */ 8 9#include <linux/clk.h> 10 11#include <drm/drmP.h> 12#include <drm/drm_atomic.h> 13#include <drm/drm_atomic_helper.h> 14#include <drm/drm_crtc_helper.h> 15#include <drm/drm_plane_helper.h> 16 17#include "sti_compositor.h" 18#include "sti_drm_drv.h" 19#include "sti_drm_crtc.h" 20#include "sti_vtg.h" 21 22static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 23{ 24 DRM_DEBUG_KMS("\n"); 25} 26 27static void sti_drm_crtc_prepare(struct drm_crtc *crtc) 28{ 29 struct sti_mixer *mixer = to_sti_mixer(crtc); 30 struct device *dev = mixer->dev; 31 struct sti_compositor *compo = dev_get_drvdata(dev); 32 33 mixer->enabled = true; 34 35 /* Prepare and enable the compo IP clock */ 36 if (mixer->id == STI_MIXER_MAIN) { 37 if (clk_prepare_enable(compo->clk_compo_main)) 38 DRM_INFO("Failed to prepare/enable compo_main clk\n"); 39 } else { 40 if (clk_prepare_enable(compo->clk_compo_aux)) 41 DRM_INFO("Failed to prepare/enable compo_aux clk\n"); 42 } 43 44 sti_mixer_clear_all_layers(mixer); 45} 46 47static void sti_drm_crtc_commit(struct drm_crtc *crtc) 48{ 49 struct sti_mixer *mixer = to_sti_mixer(crtc); 50 struct device *dev = mixer->dev; 51 struct sti_compositor *compo = dev_get_drvdata(dev); 52 struct sti_layer *layer; 53 54 if ((!mixer || !compo)) { 55 DRM_ERROR("Can not find mixer or compositor)\n"); 56 return; 57 } 58 59 /* get GDP which is reserved to the CRTC FB */ 60 layer = to_sti_layer(crtc->primary); 61 if (layer) 62 sti_layer_commit(layer); 63 else 64 DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n"); 65 66 /* Enable layer on mixer */ 67 if (sti_mixer_set_layer_status(mixer, layer, true)) 68 DRM_ERROR("Can not enable layer at mixer\n"); 69 70 drm_crtc_vblank_on(crtc); 71} 72 73static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc, 74 const struct drm_display_mode *mode, 75 struct drm_display_mode *adjusted_mode) 76{ 77 /* accept the provided drm_display_mode, do not fix it up */ 78 return true; 79} 80 81static int 82sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) 83{ 84 struct sti_mixer *mixer = to_sti_mixer(crtc); 85 struct device *dev = mixer->dev; 86 struct sti_compositor *compo = dev_get_drvdata(dev); 87 struct clk *clk; 88 int rate = mode->clock * 1000; 89 int res; 90 91 DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", 92 crtc->base.id, sti_mixer_to_str(mixer), 93 mode->base.id, mode->name); 94 95 DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", 96 mode->vrefresh, mode->clock, 97 mode->hdisplay, 98 mode->hsync_start, mode->hsync_end, 99 mode->htotal, 100 mode->vdisplay, 101 mode->vsync_start, mode->vsync_end, 102 mode->vtotal, mode->type, mode->flags); 103 104 /* Set rate and prepare/enable pixel clock */ 105 if (mixer->id == STI_MIXER_MAIN) 106 clk = compo->clk_pix_main; 107 else 108 clk = compo->clk_pix_aux; 109 110 res = clk_set_rate(clk, rate); 111 if (res < 0) { 112 DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); 113 return -EINVAL; 114 } 115 if (clk_prepare_enable(clk)) { 116 DRM_ERROR("Failed to prepare/enable pix clk\n"); 117 return -EINVAL; 118 } 119 120 sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? 121 compo->vtg_main : compo->vtg_aux, &crtc->mode); 122 123 res = sti_mixer_active_video_area(mixer, &crtc->mode); 124 if (res) { 125 DRM_ERROR("Can not set active video area\n"); 126 return -EINVAL; 127 } 128 129 return res; 130} 131 132static void sti_drm_crtc_disable(struct drm_crtc *crtc) 133{ 134 struct sti_mixer *mixer = to_sti_mixer(crtc); 135 struct device *dev = mixer->dev; 136 struct sti_compositor *compo = dev_get_drvdata(dev); 137 138 if (!mixer->enabled) 139 return; 140 141 DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); 142 143 /* Disable Background */ 144 sti_mixer_set_background_status(mixer, false); 145 146 drm_crtc_vblank_off(crtc); 147 148 /* Disable pixel clock and compo IP clocks */ 149 if (mixer->id == STI_MIXER_MAIN) { 150 clk_disable_unprepare(compo->clk_pix_main); 151 clk_disable_unprepare(compo->clk_compo_main); 152 } else { 153 clk_disable_unprepare(compo->clk_pix_aux); 154 clk_disable_unprepare(compo->clk_compo_aux); 155 } 156 157 mixer->enabled = false; 158} 159 160static void 161sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) 162{ 163 sti_drm_crtc_prepare(crtc); 164 sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode); 165} 166 167static void sti_drm_atomic_begin(struct drm_crtc *crtc) 168{ 169 struct sti_mixer *mixer = to_sti_mixer(crtc); 170 171 if (crtc->state->event) { 172 crtc->state->event->pipe = drm_crtc_index(crtc); 173 174 WARN_ON(drm_crtc_vblank_get(crtc) != 0); 175 176 mixer->pending_event = crtc->state->event; 177 crtc->state->event = NULL; 178 } 179} 180 181static void sti_drm_atomic_flush(struct drm_crtc *crtc) 182{ 183} 184 185static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { 186 .dpms = sti_drm_crtc_dpms, 187 .prepare = sti_drm_crtc_prepare, 188 .commit = sti_drm_crtc_commit, 189 .mode_fixup = sti_drm_crtc_mode_fixup, 190 .mode_set = drm_helper_crtc_mode_set, 191 .mode_set_nofb = sti_drm_crtc_mode_set_nofb, 192 .mode_set_base = drm_helper_crtc_mode_set_base, 193 .disable = sti_drm_crtc_disable, 194 .atomic_begin = sti_drm_atomic_begin, 195 .atomic_flush = sti_drm_atomic_flush, 196}; 197 198static void sti_drm_crtc_destroy(struct drm_crtc *crtc) 199{ 200 DRM_DEBUG_KMS("\n"); 201 drm_crtc_cleanup(crtc); 202} 203 204static int sti_drm_crtc_set_property(struct drm_crtc *crtc, 205 struct drm_property *property, 206 uint64_t val) 207{ 208 DRM_DEBUG_KMS("\n"); 209 return 0; 210} 211 212int sti_drm_crtc_vblank_cb(struct notifier_block *nb, 213 unsigned long event, void *data) 214{ 215 struct drm_device *drm_dev; 216 struct sti_compositor *compo = 217 container_of(nb, struct sti_compositor, vtg_vblank_nb); 218 int *crtc = data; 219 unsigned long flags; 220 struct sti_drm_private *priv; 221 222 drm_dev = compo->mixer[*crtc]->drm_crtc.dev; 223 priv = drm_dev->dev_private; 224 225 if ((event != VTG_TOP_FIELD_EVENT) && 226 (event != VTG_BOTTOM_FIELD_EVENT)) { 227 DRM_ERROR("unknown event: %lu\n", event); 228 return -EINVAL; 229 } 230 231 drm_handle_vblank(drm_dev, *crtc); 232 233 spin_lock_irqsave(&drm_dev->event_lock, flags); 234 if (compo->mixer[*crtc]->pending_event) { 235 drm_send_vblank_event(drm_dev, -1, 236 compo->mixer[*crtc]->pending_event); 237 drm_vblank_put(drm_dev, *crtc); 238 compo->mixer[*crtc]->pending_event = NULL; 239 } 240 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 241 242 return 0; 243} 244 245int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) 246{ 247 struct sti_drm_private *dev_priv = dev->dev_private; 248 struct sti_compositor *compo = dev_priv->compo; 249 struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; 250 251 if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? 252 compo->vtg_main : compo->vtg_aux, 253 vtg_vblank_nb, crtc)) { 254 DRM_ERROR("Cannot register VTG notifier\n"); 255 return -EINVAL; 256 } 257 258 return 0; 259} 260EXPORT_SYMBOL(sti_drm_crtc_enable_vblank); 261 262void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) 263{ 264 struct sti_drm_private *priv = dev->dev_private; 265 struct sti_compositor *compo = priv->compo; 266 struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; 267 268 DRM_DEBUG_DRIVER("\n"); 269 270 if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? 271 compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) 272 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); 273 274 /* free the resources of the pending requests */ 275 if (compo->mixer[crtc]->pending_event) { 276 drm_vblank_put(dev, crtc); 277 compo->mixer[crtc]->pending_event = NULL; 278 } 279} 280EXPORT_SYMBOL(sti_drm_crtc_disable_vblank); 281 282static struct drm_crtc_funcs sti_crtc_funcs = { 283 .set_config = drm_atomic_helper_set_config, 284 .page_flip = drm_atomic_helper_page_flip, 285 .destroy = sti_drm_crtc_destroy, 286 .set_property = sti_drm_crtc_set_property, 287 .reset = drm_atomic_helper_crtc_reset, 288 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 289 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 290}; 291 292bool sti_drm_crtc_is_main(struct drm_crtc *crtc) 293{ 294 struct sti_mixer *mixer = to_sti_mixer(crtc); 295 296 if (mixer->id == STI_MIXER_MAIN) 297 return true; 298 299 return false; 300} 301EXPORT_SYMBOL(sti_drm_crtc_is_main); 302 303int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, 304 struct drm_plane *primary, struct drm_plane *cursor) 305{ 306 struct drm_crtc *crtc = &mixer->drm_crtc; 307 int res; 308 309 res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, 310 &sti_crtc_funcs); 311 if (res) { 312 DRM_ERROR("Can not initialze CRTC\n"); 313 return -EINVAL; 314 } 315 316 drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs); 317 318 DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n", 319 crtc->base.id, sti_mixer_to_str(mixer)); 320 321 return 0; 322} 323