1 /* 2 * Copyright 2015 Freescale Semiconductor, Inc. 3 * 4 * Freescale DCU drm device driver 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 12 #include <linux/clk.h> 13 #include <linux/regmap.h> 14 15 #include <drm/drmP.h> 16 #include <drm/drm_atomic.h> 17 #include <drm/drm_atomic_helper.h> 18 #include <drm/drm_crtc.h> 19 #include <drm/drm_crtc_helper.h> 20 #include <video/videomode.h> 21 22 #include "fsl_dcu_drm_crtc.h" 23 #include "fsl_dcu_drm_drv.h" 24 #include "fsl_dcu_drm_plane.h" 25 26 static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, 27 struct drm_crtc_state *old_crtc_state) 28 { 29 struct drm_device *dev = crtc->dev; 30 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 31 struct drm_pending_vblank_event *event = crtc->state->event; 32 33 regmap_write(fsl_dev->regmap, 34 DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); 35 36 if (event) { 37 crtc->state->event = NULL; 38 39 spin_lock_irq(&crtc->dev->event_lock); 40 if (drm_crtc_vblank_get(crtc) == 0) 41 drm_crtc_arm_vblank_event(crtc, event); 42 else 43 drm_crtc_send_vblank_event(crtc, event); 44 spin_unlock_irq(&crtc->dev->event_lock); 45 } 46 } 47 48 static void fsl_dcu_drm_crtc_atomic_disable(struct drm_crtc *crtc, 49 struct drm_crtc_state *old_crtc_state) 50 { 51 struct drm_device *dev = crtc->dev; 52 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 53 54 /* always disable planes on the CRTC */ 55 drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, true); 56 57 drm_crtc_vblank_off(crtc); 58 59 regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, 60 DCU_MODE_DCU_MODE_MASK, 61 DCU_MODE_DCU_MODE(DCU_MODE_OFF)); 62 regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, 63 DCU_UPDATE_MODE_READREG); 64 clk_disable_unprepare(fsl_dev->pix_clk); 65 } 66 67 static void fsl_dcu_drm_crtc_atomic_enable(struct drm_crtc *crtc, 68 struct drm_crtc_state *old_state) 69 { 70 struct drm_device *dev = crtc->dev; 71 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 72 73 clk_prepare_enable(fsl_dev->pix_clk); 74 regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, 75 DCU_MODE_DCU_MODE_MASK, 76 DCU_MODE_DCU_MODE(DCU_MODE_NORMAL)); 77 regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, 78 DCU_UPDATE_MODE_READREG); 79 80 drm_crtc_vblank_on(crtc); 81 } 82 83 static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) 84 { 85 struct drm_device *dev = crtc->dev; 86 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 87 struct drm_connector *con = &fsl_dev->connector.base; 88 struct drm_display_mode *mode = &crtc->state->mode; 89 unsigned int pol = 0; 90 struct videomode vm; 91 92 clk_set_rate(fsl_dev->pix_clk, mode->clock * 1000); 93 94 drm_display_mode_to_videomode(mode, &vm); 95 96 /* INV_PXCK as default (most display sample data on rising edge) */ 97 if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)) 98 pol |= DCU_SYN_POL_INV_PXCK; 99 100 if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW) 101 pol |= DCU_SYN_POL_INV_HS_LOW; 102 103 if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW) 104 pol |= DCU_SYN_POL_INV_VS_LOW; 105 106 regmap_write(fsl_dev->regmap, DCU_HSYN_PARA, 107 DCU_HSYN_PARA_BP(vm.hback_porch) | 108 DCU_HSYN_PARA_PW(vm.hsync_len) | 109 DCU_HSYN_PARA_FP(vm.hfront_porch)); 110 regmap_write(fsl_dev->regmap, DCU_VSYN_PARA, 111 DCU_VSYN_PARA_BP(vm.vback_porch) | 112 DCU_VSYN_PARA_PW(vm.vsync_len) | 113 DCU_VSYN_PARA_FP(vm.vfront_porch)); 114 regmap_write(fsl_dev->regmap, DCU_DISP_SIZE, 115 DCU_DISP_SIZE_DELTA_Y(vm.vactive) | 116 DCU_DISP_SIZE_DELTA_X(vm.hactive)); 117 regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol); 118 regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) | 119 DCU_BGND_G(0) | DCU_BGND_B(0)); 120 regmap_write(fsl_dev->regmap, DCU_DCU_MODE, 121 DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN); 122 regmap_write(fsl_dev->regmap, DCU_THRESHOLD, 123 DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) | 124 DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) | 125 DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL)); 126 return; 127 } 128 129 static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = { 130 .atomic_disable = fsl_dcu_drm_crtc_atomic_disable, 131 .atomic_flush = fsl_dcu_drm_crtc_atomic_flush, 132 .atomic_enable = fsl_dcu_drm_crtc_atomic_enable, 133 .mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb, 134 }; 135 136 static int fsl_dcu_drm_crtc_enable_vblank(struct drm_crtc *crtc) 137 { 138 struct drm_device *dev = crtc->dev; 139 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 140 unsigned int value; 141 142 regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); 143 value &= ~DCU_INT_MASK_VBLANK; 144 regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); 145 146 return 0; 147 } 148 149 static void fsl_dcu_drm_crtc_disable_vblank(struct drm_crtc *crtc) 150 { 151 struct drm_device *dev = crtc->dev; 152 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 153 unsigned int value; 154 155 regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); 156 value |= DCU_INT_MASK_VBLANK; 157 regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); 158 } 159 160 static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = { 161 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 162 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 163 .destroy = drm_crtc_cleanup, 164 .page_flip = drm_atomic_helper_page_flip, 165 .reset = drm_atomic_helper_crtc_reset, 166 .set_config = drm_atomic_helper_set_config, 167 .enable_vblank = fsl_dcu_drm_crtc_enable_vblank, 168 .disable_vblank = fsl_dcu_drm_crtc_disable_vblank, 169 }; 170 171 int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev) 172 { 173 struct drm_plane *primary; 174 struct drm_crtc *crtc = &fsl_dev->crtc; 175 int ret; 176 177 fsl_dcu_drm_init_planes(fsl_dev->drm); 178 179 primary = fsl_dcu_drm_primary_create_plane(fsl_dev->drm); 180 if (!primary) 181 return -ENOMEM; 182 183 ret = drm_crtc_init_with_planes(fsl_dev->drm, crtc, primary, NULL, 184 &fsl_dcu_drm_crtc_funcs, NULL); 185 if (ret) { 186 primary->funcs->destroy(primary); 187 return ret; 188 } 189 190 drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs); 191 192 return 0; 193 } 194