cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kmb_crtc.c (7489B)


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