brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 43a675d Raw
281 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2019-2022 Bootlin4 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>5 */6 7#include <linux/of.h>8#include <linux/of_graph.h>9#include <linux/types.h>10#include <linux/workqueue.h>11 12#include <drm/drm_atomic_helper.h>13#include <drm/drm_crtc.h>14#include <drm/drm_drv.h>15#include <drm/drm_gem_dma_helper.h>16#include <drm/drm_print.h>17#include <drm/drm_vblank.h>18 19#include "logicvc_crtc.h"20#include "logicvc_drm.h"21#include "logicvc_interface.h"22#include "logicvc_layer.h"23#include "logicvc_regs.h"24 25#define logicvc_crtc(c) \26	container_of(c, struct logicvc_crtc, drm_crtc)27 28static enum drm_mode_status29logicvc_crtc_mode_valid(struct drm_crtc *drm_crtc,30			const struct drm_display_mode *mode)31{32	if (mode->flags & DRM_MODE_FLAG_INTERLACE)33		return -EINVAL;34 35	return 0;36}37 38static void logicvc_crtc_atomic_begin(struct drm_crtc *drm_crtc,39				      struct drm_atomic_state *state)40{41	struct logicvc_crtc *crtc = logicvc_crtc(drm_crtc);42	struct drm_crtc_state *old_state =43		drm_atomic_get_old_crtc_state(state, drm_crtc);44	struct drm_device *drm_dev = drm_crtc->dev;45	unsigned long flags;46 47	/*48	 * We need to grab the pending event here if vblank was already enabled49	 * since we won't get a call to atomic_enable to grab it.50	 */51	if (drm_crtc->state->event && old_state->active) {52		spin_lock_irqsave(&drm_dev->event_lock, flags);53		WARN_ON(drm_crtc_vblank_get(drm_crtc) != 0);54 55		crtc->event = drm_crtc->state->event;56		drm_crtc->state->event = NULL;57 58		spin_unlock_irqrestore(&drm_dev->event_lock, flags);59	}60}61 62static void logicvc_crtc_atomic_enable(struct drm_crtc *drm_crtc,63				       struct drm_atomic_state *state)64{65	struct logicvc_crtc *crtc = logicvc_crtc(drm_crtc);66	struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);67	struct drm_crtc_state *old_state =68		drm_atomic_get_old_crtc_state(state, drm_crtc);69	struct drm_crtc_state *new_state =70		drm_atomic_get_new_crtc_state(state, drm_crtc);71	struct drm_display_mode *mode = &new_state->adjusted_mode;72 73	struct drm_device *drm_dev = drm_crtc->dev;74	unsigned int hact, hfp, hsl, hbp;75	unsigned int vact, vfp, vsl, vbp;76	unsigned long flags;77	u32 ctrl;78 79	/* Timings */80 81	hact = mode->hdisplay;82	hfp = mode->hsync_start - mode->hdisplay;83	hsl = mode->hsync_end - mode->hsync_start;84	hbp = mode->htotal - mode->hsync_end;85 86	vact = mode->vdisplay;87	vfp = mode->vsync_start - mode->vdisplay;88	vsl = mode->vsync_end - mode->vsync_start;89	vbp = mode->vtotal - mode->vsync_end;90 91	regmap_write(logicvc->regmap, LOGICVC_HSYNC_FRONT_PORCH_REG, hfp - 1);92	regmap_write(logicvc->regmap, LOGICVC_HSYNC_REG, hsl - 1);93	regmap_write(logicvc->regmap, LOGICVC_HSYNC_BACK_PORCH_REG, hbp - 1);94	regmap_write(logicvc->regmap, LOGICVC_HRES_REG, hact - 1);95 96	regmap_write(logicvc->regmap, LOGICVC_VSYNC_FRONT_PORCH_REG, vfp - 1);97	regmap_write(logicvc->regmap, LOGICVC_VSYNC_REG, vsl - 1);98	regmap_write(logicvc->regmap, LOGICVC_VSYNC_BACK_PORCH_REG, vbp - 1);99	regmap_write(logicvc->regmap, LOGICVC_VRES_REG, vact - 1);100 101	/* Signals */102 103	ctrl = LOGICVC_CTRL_HSYNC_ENABLE | LOGICVC_CTRL_VSYNC_ENABLE |104	       LOGICVC_CTRL_DE_ENABLE;105 106	if (mode->flags & DRM_MODE_FLAG_NHSYNC)107		ctrl |= LOGICVC_CTRL_HSYNC_INVERT;108 109	if (mode->flags & DRM_MODE_FLAG_NVSYNC)110		ctrl |= LOGICVC_CTRL_VSYNC_INVERT;111 112	if (logicvc->interface) {113		struct drm_connector *connector =114			&logicvc->interface->drm_connector;115		struct drm_display_info *display_info =116			&connector->display_info;117 118		if (display_info->bus_flags & DRM_BUS_FLAG_DE_LOW)119			ctrl |= LOGICVC_CTRL_DE_INVERT;120 121		if (display_info->bus_flags &122		    DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)123			ctrl |= LOGICVC_CTRL_CLOCK_INVERT;124	}125 126	regmap_update_bits(logicvc->regmap, LOGICVC_CTRL_REG,127			   LOGICVC_CTRL_HSYNC_ENABLE |128			   LOGICVC_CTRL_HSYNC_INVERT |129			   LOGICVC_CTRL_VSYNC_ENABLE |130			   LOGICVC_CTRL_VSYNC_INVERT |131			   LOGICVC_CTRL_DE_ENABLE |132			   LOGICVC_CTRL_DE_INVERT |133			   LOGICVC_CTRL_PIXEL_INVERT |134			   LOGICVC_CTRL_CLOCK_INVERT, ctrl);135 136	/* Generate internal state reset. */137	regmap_write(logicvc->regmap, LOGICVC_DTYPE_REG, 0);138 139	drm_crtc_vblank_on(drm_crtc);140 141	/* Register our event after vblank is enabled. */142	if (drm_crtc->state->event && !old_state->active) {143		spin_lock_irqsave(&drm_dev->event_lock, flags);144		WARN_ON(drm_crtc_vblank_get(drm_crtc) != 0);145 146		crtc->event = drm_crtc->state->event;147		drm_crtc->state->event = NULL;148		spin_unlock_irqrestore(&drm_dev->event_lock, flags);149	}150}151 152static void logicvc_crtc_atomic_disable(struct drm_crtc *drm_crtc,153					struct drm_atomic_state *state)154{155	struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);156	struct drm_device *drm_dev = drm_crtc->dev;157 158	drm_crtc_vblank_off(drm_crtc);159 160	/* Disable and clear CRTC bits. */161	regmap_update_bits(logicvc->regmap, LOGICVC_CTRL_REG,162			   LOGICVC_CTRL_HSYNC_ENABLE |163			   LOGICVC_CTRL_HSYNC_INVERT |164			   LOGICVC_CTRL_VSYNC_ENABLE |165			   LOGICVC_CTRL_VSYNC_INVERT |166			   LOGICVC_CTRL_DE_ENABLE |167			   LOGICVC_CTRL_DE_INVERT |168			   LOGICVC_CTRL_PIXEL_INVERT |169			   LOGICVC_CTRL_CLOCK_INVERT, 0);170 171	/* Generate internal state reset. */172	regmap_write(logicvc->regmap, LOGICVC_DTYPE_REG, 0);173 174	/* Consume any leftover event since vblank is now disabled. */175	if (drm_crtc->state->event && !drm_crtc->state->active) {176		spin_lock_irq(&drm_dev->event_lock);177 178		drm_crtc_send_vblank_event(drm_crtc, drm_crtc->state->event);179		drm_crtc->state->event = NULL;180		spin_unlock_irq(&drm_dev->event_lock);181	}182}183 184static const struct drm_crtc_helper_funcs logicvc_crtc_helper_funcs = {185	.mode_valid		= logicvc_crtc_mode_valid,186	.atomic_begin		= logicvc_crtc_atomic_begin,187	.atomic_enable		= logicvc_crtc_atomic_enable,188	.atomic_disable		= logicvc_crtc_atomic_disable,189};190 191static int logicvc_crtc_enable_vblank(struct drm_crtc *drm_crtc)192{193	struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);194 195	/* Clear any pending V_SYNC interrupt. */196	regmap_write_bits(logicvc->regmap, LOGICVC_INT_STAT_REG,197			  LOGICVC_INT_STAT_V_SYNC, LOGICVC_INT_STAT_V_SYNC);198 199	/* Unmask V_SYNC interrupt. */200	regmap_write_bits(logicvc->regmap, LOGICVC_INT_MASK_REG,201			  LOGICVC_INT_MASK_V_SYNC, 0);202 203	return 0;204}205 206static void logicvc_crtc_disable_vblank(struct drm_crtc *drm_crtc)207{208	struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);209 210	/* Mask V_SYNC interrupt. */211	regmap_write_bits(logicvc->regmap, LOGICVC_INT_MASK_REG,212			  LOGICVC_INT_MASK_V_SYNC, LOGICVC_INT_MASK_V_SYNC);213}214 215static const struct drm_crtc_funcs logicvc_crtc_funcs = {216	.reset			= drm_atomic_helper_crtc_reset,217	.destroy		= drm_crtc_cleanup,218	.set_config		= drm_atomic_helper_set_config,219	.page_flip		= drm_atomic_helper_page_flip,220	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,221	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,222	.enable_vblank		= logicvc_crtc_enable_vblank,223	.disable_vblank		= logicvc_crtc_disable_vblank,224};225 226void logicvc_crtc_vblank_handler(struct logicvc_drm *logicvc)227{228	struct drm_device *drm_dev = &logicvc->drm_dev;229	struct logicvc_crtc *crtc = logicvc->crtc;230	unsigned long flags;231 232	if (!crtc)233		return;234 235	drm_crtc_handle_vblank(&crtc->drm_crtc);236 237	if (crtc->event) {238		spin_lock_irqsave(&drm_dev->event_lock, flags);239		drm_crtc_send_vblank_event(&crtc->drm_crtc, crtc->event);240		drm_crtc_vblank_put(&crtc->drm_crtc);241		crtc->event = NULL;242		spin_unlock_irqrestore(&drm_dev->event_lock, flags);243	}244}245 246int logicvc_crtc_init(struct logicvc_drm *logicvc)247{248	struct drm_device *drm_dev = &logicvc->drm_dev;249	struct device *dev = drm_dev->dev;250	struct device_node *of_node = dev->of_node;251	struct logicvc_crtc *crtc;252	struct logicvc_layer *layer_primary;253	int ret;254 255	crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL);256	if (!crtc)257		return -ENOMEM;258 259	layer_primary = logicvc_layer_get_primary(logicvc);260	if (!layer_primary) {261		drm_err(drm_dev, "Failed to get primary layer\n");262		return -EINVAL;263	}264 265	ret = drm_crtc_init_with_planes(drm_dev, &crtc->drm_crtc,266					&layer_primary->drm_plane, NULL,267					&logicvc_crtc_funcs, NULL);268	if (ret) {269		drm_err(drm_dev, "Failed to initialize CRTC\n");270		return ret;271	}272 273	drm_crtc_helper_add(&crtc->drm_crtc, &logicvc_crtc_helper_funcs);274 275	crtc->drm_crtc.port = of_graph_get_port_by_id(of_node, 1);276 277	logicvc->crtc = crtc;278 279	return 0;280}281