Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 21#include "fsl_dcu_drm_crtc.h"
 22#include "fsl_dcu_drm_drv.h"
 23#include "fsl_dcu_drm_plane.h"
 24
 25static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc,
 26					  struct drm_crtc_state *old_crtc_state)
 27{
 28	struct drm_device *dev = crtc->dev;
 29	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 30	struct drm_pending_vblank_event *event = crtc->state->event;
 31
 32	regmap_write(fsl_dev->regmap,
 33		     DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
 34
 35	if (event) {
 36		crtc->state->event = NULL;
 37
 38		spin_lock_irq(&crtc->dev->event_lock);
 39		if (drm_crtc_vblank_get(crtc) == 0)
 40			drm_crtc_arm_vblank_event(crtc, event);
 41		else
 42			drm_crtc_send_vblank_event(crtc, event);
 43		spin_unlock_irq(&crtc->dev->event_lock);
 44	}
 45}
 46
 47static void fsl_dcu_drm_crtc_atomic_disable(struct drm_crtc *crtc,
 48					struct drm_crtc_state *old_crtc_state)
 49{
 50	struct drm_device *dev = crtc->dev;
 51	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 52
 53	/* always disable planes on the CRTC */
 54	drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, true);
 55
 56	drm_crtc_vblank_off(crtc);
 57
 58	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
 59			   DCU_MODE_DCU_MODE_MASK,
 60			   DCU_MODE_DCU_MODE(DCU_MODE_OFF));
 61	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
 62		     DCU_UPDATE_MODE_READREG);
 63	clk_disable_unprepare(fsl_dev->pix_clk);
 64}
 65
 66static void fsl_dcu_drm_crtc_atomic_enable(struct drm_crtc *crtc,
 67					   struct drm_crtc_state *old_state)
 68{
 69	struct drm_device *dev = crtc->dev;
 70	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 71
 72	clk_prepare_enable(fsl_dev->pix_clk);
 73	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
 74			   DCU_MODE_DCU_MODE_MASK,
 75			   DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
 76	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
 77		     DCU_UPDATE_MODE_READREG);
 78
 79	drm_crtc_vblank_on(crtc);
 80}
 81
 82static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
 83{
 84	struct drm_device *dev = crtc->dev;
 85	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 86	struct drm_connector *con = &fsl_dev->connector.base;
 87	struct drm_display_mode *mode = &crtc->state->mode;
 88	unsigned int hbp, hfp, hsw, vbp, vfp, vsw, index, pol = 0;
 89
 90	index = drm_crtc_index(crtc);
 91	clk_set_rate(fsl_dev->pix_clk, mode->clock * 1000);
 92
 93	/* Configure timings: */
 94	hbp = mode->htotal - mode->hsync_end;
 95	hfp = mode->hsync_start - mode->hdisplay;
 96	hsw = mode->hsync_end - mode->hsync_start;
 97	vbp = mode->vtotal - mode->vsync_end;
 98	vfp = mode->vsync_start - mode->vdisplay;
 99	vsw = mode->vsync_end - mode->vsync_start;
100
101	/* INV_PXCK as default (most display sample data on rising edge) */
102	if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE))
103		pol |= DCU_SYN_POL_INV_PXCK;
104
105	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
106		pol |= DCU_SYN_POL_INV_HS_LOW;
107
108	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
109		pol |= DCU_SYN_POL_INV_VS_LOW;
110
111	regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
112		     DCU_HSYN_PARA_BP(hbp) |
113		     DCU_HSYN_PARA_PW(hsw) |
114		     DCU_HSYN_PARA_FP(hfp));
115	regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
116		     DCU_VSYN_PARA_BP(vbp) |
117		     DCU_VSYN_PARA_PW(vsw) |
118		     DCU_VSYN_PARA_FP(vfp));
119	regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
120		     DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
121		     DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
122	regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol);
123	regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
124		     DCU_BGND_G(0) | DCU_BGND_B(0));
125	regmap_write(fsl_dev->regmap, DCU_DCU_MODE,
126		     DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN);
127	regmap_write(fsl_dev->regmap, DCU_THRESHOLD,
128		     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |
129		     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |
130		     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));
131	return;
132}
133
134static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = {
135	.atomic_disable = fsl_dcu_drm_crtc_atomic_disable,
136	.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
137	.atomic_enable = fsl_dcu_drm_crtc_atomic_enable,
138	.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
139};
140
141static int fsl_dcu_drm_crtc_enable_vblank(struct drm_crtc *crtc)
142{
143	struct drm_device *dev = crtc->dev;
144	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
145	unsigned int value;
146
147	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value);
148	value &= ~DCU_INT_MASK_VBLANK;
149	regmap_write(fsl_dev->regmap, DCU_INT_MASK, value);
150
151	return 0;
152}
153
154static void fsl_dcu_drm_crtc_disable_vblank(struct drm_crtc *crtc)
155{
156	struct drm_device *dev = crtc->dev;
157	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
158	unsigned int value;
159
160	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value);
161	value |= DCU_INT_MASK_VBLANK;
162	regmap_write(fsl_dev->regmap, DCU_INT_MASK, value);
163}
164
165static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {
166	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
167	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
168	.destroy = drm_crtc_cleanup,
169	.page_flip = drm_atomic_helper_page_flip,
170	.reset = drm_atomic_helper_crtc_reset,
171	.set_config = drm_atomic_helper_set_config,
172	.enable_vblank = fsl_dcu_drm_crtc_enable_vblank,
173	.disable_vblank = fsl_dcu_drm_crtc_disable_vblank,
174};
175
176int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
177{
178	struct drm_plane *primary;
179	struct drm_crtc *crtc = &fsl_dev->crtc;
180	int ret;
181
182	fsl_dcu_drm_init_planes(fsl_dev->drm);
183
184	primary = fsl_dcu_drm_primary_create_plane(fsl_dev->drm);
185	if (!primary)
186		return -ENOMEM;
187
188	ret = drm_crtc_init_with_planes(fsl_dev->drm, crtc, primary, NULL,
189					&fsl_dcu_drm_crtc_funcs, NULL);
190	if (ret) {
191		primary->funcs->destroy(primary);
192		return ret;
193	}
194
195	drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs);
196
197	return 0;
198}