249 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright © 2018-2020 Intel Corporation4 */5 6#include <linux/clk.h>7 8#include <drm/drm_atomic.h>9#include <drm/drm_atomic_helper.h>10#include <drm/drm_crtc.h>11#include <drm/drm_print.h>12#include <drm/drm_vblank.h>13#include <drm/drm_modeset_helper_vtables.h>14 15#include "kmb_drv.h"16#include "kmb_dsi.h"17#include "kmb_plane.h"18#include "kmb_regs.h"19 20struct kmb_crtc_timing {21 u32 vfront_porch;22 u32 vback_porch;23 u32 vsync_len;24 u32 hfront_porch;25 u32 hback_porch;26 u32 hsync_len;27};28 29static int kmb_crtc_enable_vblank(struct drm_crtc *crtc)30{31 struct drm_device *dev = crtc->dev;32 struct kmb_drm_private *kmb = to_kmb(dev);33 34 /* Clear interrupt */35 kmb_write_lcd(kmb, LCD_INT_CLEAR, LCD_INT_VERT_COMP);36 /* Set which interval to generate vertical interrupt */37 kmb_write_lcd(kmb, LCD_VSTATUS_COMPARE,38 LCD_VSTATUS_COMPARE_VSYNC);39 /* Enable vertical interrupt */40 kmb_set_bitmask_lcd(kmb, LCD_INT_ENABLE,41 LCD_INT_VERT_COMP);42 return 0;43}44 45static void kmb_crtc_disable_vblank(struct drm_crtc *crtc)46{47 struct drm_device *dev = crtc->dev;48 struct kmb_drm_private *kmb = to_kmb(dev);49 50 /* Clear interrupt */51 kmb_write_lcd(kmb, LCD_INT_CLEAR, LCD_INT_VERT_COMP);52 /* Disable vertical interrupt */53 kmb_clr_bitmask_lcd(kmb, LCD_INT_ENABLE,54 LCD_INT_VERT_COMP);55}56 57static const struct drm_crtc_funcs kmb_crtc_funcs = {58 .destroy = drm_crtc_cleanup,59 .set_config = drm_atomic_helper_set_config,60 .page_flip = drm_atomic_helper_page_flip,61 .reset = drm_atomic_helper_crtc_reset,62 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,63 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,64 .enable_vblank = kmb_crtc_enable_vblank,65 .disable_vblank = kmb_crtc_disable_vblank,66};67 68static void kmb_crtc_set_mode(struct drm_crtc *crtc,69 struct drm_atomic_state *old_state)70{71 struct drm_device *dev = crtc->dev;72 struct drm_display_mode *m = &crtc->state->adjusted_mode;73 struct kmb_crtc_timing vm;74 struct kmb_drm_private *kmb = to_kmb(dev);75 unsigned int val = 0;76 77 /* Initialize mipi */78 kmb_dsi_mode_set(kmb->kmb_dsi, m, kmb->sys_clk_mhz, old_state);79 drm_info(dev,80 "vfp= %d vbp= %d vsync_len=%d hfp=%d hbp=%d hsync_len=%d\n",81 m->crtc_vsync_start - m->crtc_vdisplay,82 m->crtc_vtotal - m->crtc_vsync_end,83 m->crtc_vsync_end - m->crtc_vsync_start,84 m->crtc_hsync_start - m->crtc_hdisplay,85 m->crtc_htotal - m->crtc_hsync_end,86 m->crtc_hsync_end - m->crtc_hsync_start);87 val = kmb_read_lcd(kmb, LCD_INT_ENABLE);88 kmb_clr_bitmask_lcd(kmb, LCD_INT_ENABLE, val);89 kmb_set_bitmask_lcd(kmb, LCD_INT_CLEAR, ~0x0);90 vm.vfront_porch = 2;91 vm.vback_porch = 2;92 vm.vsync_len = 8;93 vm.hfront_porch = 0;94 vm.hback_porch = 0;95 vm.hsync_len = 28;96 97 drm_dbg(dev, "%s : %dactive height= %d vbp=%d vfp=%d vsync-w=%d h-active=%d h-bp=%d h-fp=%d hsync-l=%d",98 __func__, __LINE__,99 m->crtc_vdisplay, vm.vback_porch, vm.vfront_porch,100 vm.vsync_len, m->crtc_hdisplay, vm.hback_porch,101 vm.hfront_porch, vm.hsync_len);102 kmb_write_lcd(kmb, LCD_V_ACTIVEHEIGHT,103 m->crtc_vdisplay - 1);104 kmb_write_lcd(kmb, LCD_V_BACKPORCH, vm.vback_porch);105 kmb_write_lcd(kmb, LCD_V_FRONTPORCH, vm.vfront_porch);106 kmb_write_lcd(kmb, LCD_VSYNC_WIDTH, vm.vsync_len - 1);107 kmb_write_lcd(kmb, LCD_H_ACTIVEWIDTH,108 m->crtc_hdisplay - 1);109 kmb_write_lcd(kmb, LCD_H_BACKPORCH, vm.hback_porch);110 kmb_write_lcd(kmb, LCD_H_FRONTPORCH, vm.hfront_porch);111 kmb_write_lcd(kmb, LCD_HSYNC_WIDTH, vm.hsync_len - 1);112 /* This is hardcoded as 0 in the Myriadx code */113 kmb_write_lcd(kmb, LCD_VSYNC_START, 0);114 kmb_write_lcd(kmb, LCD_VSYNC_END, 0);115 /* Back ground color */116 kmb_write_lcd(kmb, LCD_BG_COLOUR_LS, 0x4);117 if (m->flags == DRM_MODE_FLAG_INTERLACE) {118 kmb_write_lcd(kmb,119 LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1);120 kmb_write_lcd(kmb,121 LCD_V_BACKPORCH_EVEN, vm.vback_porch);122 kmb_write_lcd(kmb,123 LCD_V_FRONTPORCH_EVEN, vm.vfront_porch);124 kmb_write_lcd(kmb, LCD_V_ACTIVEHEIGHT_EVEN,125 m->crtc_vdisplay - 1);126 /* This is hardcoded as 10 in the Myriadx code */127 kmb_write_lcd(kmb, LCD_VSYNC_START_EVEN, 10);128 kmb_write_lcd(kmb, LCD_VSYNC_END_EVEN, 10);129 }130 kmb_write_lcd(kmb, LCD_TIMING_GEN_TRIG, 1);131 kmb_set_bitmask_lcd(kmb, LCD_CONTROL, LCD_CTRL_ENABLE);132 kmb_set_bitmask_lcd(kmb, LCD_INT_ENABLE, val);133}134 135static void kmb_crtc_atomic_enable(struct drm_crtc *crtc,136 struct drm_atomic_state *state)137{138 struct kmb_drm_private *kmb = crtc_to_kmb_priv(crtc);139 140 clk_prepare_enable(kmb->kmb_clk.clk_lcd);141 kmb_crtc_set_mode(crtc, state);142 drm_crtc_vblank_on(crtc);143}144 145static void kmb_crtc_atomic_disable(struct drm_crtc *crtc,146 struct drm_atomic_state *state)147{148 struct kmb_drm_private *kmb = crtc_to_kmb_priv(crtc);149 struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);150 151 /* due to hw limitations, planes need to be off when crtc is off */152 drm_atomic_helper_disable_planes_on_crtc(old_state, false);153 154 drm_crtc_vblank_off(crtc);155 clk_disable_unprepare(kmb->kmb_clk.clk_lcd);156}157 158static void kmb_crtc_atomic_begin(struct drm_crtc *crtc,159 struct drm_atomic_state *state)160{161 struct drm_device *dev = crtc->dev;162 struct kmb_drm_private *kmb = to_kmb(dev);163 164 kmb_clr_bitmask_lcd(kmb, LCD_INT_ENABLE,165 LCD_INT_VERT_COMP);166}167 168static void kmb_crtc_atomic_flush(struct drm_crtc *crtc,169 struct drm_atomic_state *state)170{171 struct drm_device *dev = crtc->dev;172 struct kmb_drm_private *kmb = to_kmb(dev);173 174 kmb_set_bitmask_lcd(kmb, LCD_INT_ENABLE,175 LCD_INT_VERT_COMP);176 177 spin_lock_irq(&crtc->dev->event_lock);178 if (crtc->state->event) {179 if (drm_crtc_vblank_get(crtc) == 0)180 drm_crtc_arm_vblank_event(crtc, crtc->state->event);181 else182 drm_crtc_send_vblank_event(crtc, crtc->state->event);183 }184 crtc->state->event = NULL;185 spin_unlock_irq(&crtc->dev->event_lock);186}187 188static enum drm_mode_status189 kmb_crtc_mode_valid(struct drm_crtc *crtc,190 const struct drm_display_mode *mode)191{192 int refresh;193 struct drm_device *dev = crtc->dev;194 int vfp = mode->vsync_start - mode->vdisplay;195 196 if (mode->vdisplay < KMB_CRTC_MAX_HEIGHT) {197 drm_dbg(dev, "height = %d less than %d",198 mode->vdisplay, KMB_CRTC_MAX_HEIGHT);199 return MODE_BAD_VVALUE;200 }201 if (mode->hdisplay < KMB_CRTC_MAX_WIDTH) {202 drm_dbg(dev, "width = %d less than %d",203 mode->hdisplay, KMB_CRTC_MAX_WIDTH);204 return MODE_BAD_HVALUE;205 }206 refresh = drm_mode_vrefresh(mode);207 if (refresh < KMB_MIN_VREFRESH || refresh > KMB_MAX_VREFRESH) {208 drm_dbg(dev, "refresh = %d less than %d or greater than %d",209 refresh, KMB_MIN_VREFRESH, KMB_MAX_VREFRESH);210 return MODE_BAD;211 }212 213 if (vfp < KMB_CRTC_MIN_VFP) {214 drm_dbg(dev, "vfp = %d less than %d", vfp, KMB_CRTC_MIN_VFP);215 return MODE_BAD;216 }217 218 return MODE_OK;219}220 221static const struct drm_crtc_helper_funcs kmb_crtc_helper_funcs = {222 .atomic_begin = kmb_crtc_atomic_begin,223 .atomic_enable = kmb_crtc_atomic_enable,224 .atomic_disable = kmb_crtc_atomic_disable,225 .atomic_flush = kmb_crtc_atomic_flush,226 .mode_valid = kmb_crtc_mode_valid,227};228 229int kmb_setup_crtc(struct drm_device *drm)230{231 struct kmb_drm_private *kmb = to_kmb(drm);232 struct kmb_plane *primary;233 int ret;234 235 primary = kmb_plane_init(drm);236 if (IS_ERR(primary))237 return PTR_ERR(primary);238 239 ret = drm_crtc_init_with_planes(drm, &kmb->crtc, &primary->base_plane,240 NULL, &kmb_crtc_funcs, NULL);241 if (ret) {242 kmb_plane_destroy(&primary->base_plane);243 return ret;244 }245 246 drm_crtc_helper_add(&kmb->crtc, &kmb_crtc_helper_funcs);247 return 0;248}249