1*b843c749SSergey Zigachev /*
2*b843c749SSergey Zigachev  * Copyright 2015 Advanced Micro Devices, Inc.
3*b843c749SSergey Zigachev  *
4*b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
5*b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
6*b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
7*b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
9*b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
10*b843c749SSergey Zigachev  *
11*b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
12*b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
13*b843c749SSergey Zigachev  *
14*b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
21*b843c749SSergey Zigachev  *
22*b843c749SSergey Zigachev  * Authors: AMD
23*b843c749SSergey Zigachev  *
24*b843c749SSergey Zigachev  */
25*b843c749SSergey Zigachev 
26*b843c749SSergey Zigachev #include <drm/drm_crtc.h>
27*b843c749SSergey Zigachev 
28*b843c749SSergey Zigachev #include "amdgpu.h"
29*b843c749SSergey Zigachev #include "amdgpu_dm.h"
30*b843c749SSergey Zigachev #include "dc.h"
31*b843c749SSergey Zigachev 
32*b843c749SSergey Zigachev enum amdgpu_dm_pipe_crc_source {
33*b843c749SSergey Zigachev 	AMDGPU_DM_PIPE_CRC_SOURCE_NONE = 0,
34*b843c749SSergey Zigachev 	AMDGPU_DM_PIPE_CRC_SOURCE_AUTO,
35*b843c749SSergey Zigachev 	AMDGPU_DM_PIPE_CRC_SOURCE_MAX,
36*b843c749SSergey Zigachev 	AMDGPU_DM_PIPE_CRC_SOURCE_INVALID = -1,
37*b843c749SSergey Zigachev };
38*b843c749SSergey Zigachev 
dm_parse_crc_source(const char * source)39*b843c749SSergey Zigachev static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
40*b843c749SSergey Zigachev {
41*b843c749SSergey Zigachev 	if (!source || !strcmp(source, "none"))
42*b843c749SSergey Zigachev 		return AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
43*b843c749SSergey Zigachev 	if (!strcmp(source, "auto"))
44*b843c749SSergey Zigachev 		return AMDGPU_DM_PIPE_CRC_SOURCE_AUTO;
45*b843c749SSergey Zigachev 
46*b843c749SSergey Zigachev 	return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID;
47*b843c749SSergey Zigachev }
48*b843c749SSergey Zigachev 
amdgpu_dm_crtc_set_crc_source(struct drm_crtc * crtc,const char * src_name,size_t * values_cnt)49*b843c749SSergey Zigachev int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name,
50*b843c749SSergey Zigachev 			   size_t *values_cnt)
51*b843c749SSergey Zigachev {
52*b843c749SSergey Zigachev 	struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state);
53*b843c749SSergey Zigachev 	struct dc_stream_state *stream_state = crtc_state->stream;
54*b843c749SSergey Zigachev 	bool enable;
55*b843c749SSergey Zigachev 
56*b843c749SSergey Zigachev 	enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
57*b843c749SSergey Zigachev 
58*b843c749SSergey Zigachev 	if (source < 0) {
59*b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n",
60*b843c749SSergey Zigachev 				 src_name, crtc->index);
61*b843c749SSergey Zigachev 		return -EINVAL;
62*b843c749SSergey Zigachev 	}
63*b843c749SSergey Zigachev 
64*b843c749SSergey Zigachev 	if (!stream_state) {
65*b843c749SSergey Zigachev 		DRM_ERROR("No stream state for CRTC%d\n", crtc->index);
66*b843c749SSergey Zigachev 		return -EINVAL;
67*b843c749SSergey Zigachev 	}
68*b843c749SSergey Zigachev 
69*b843c749SSergey Zigachev 	enable = (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO);
70*b843c749SSergey Zigachev 
71*b843c749SSergey Zigachev 	if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
72*b843c749SSergey Zigachev 				     enable, enable))
73*b843c749SSergey Zigachev 		return -EINVAL;
74*b843c749SSergey Zigachev 
75*b843c749SSergey Zigachev 	/* When enabling CRC, we should also disable dithering. */
76*b843c749SSergey Zigachev 	dc_stream_set_dither_option(stream_state,
77*b843c749SSergey Zigachev 				    enable ? DITHER_OPTION_TRUN8
78*b843c749SSergey Zigachev 					   : DITHER_OPTION_DEFAULT);
79*b843c749SSergey Zigachev 
80*b843c749SSergey Zigachev 	/*
81*b843c749SSergey Zigachev 	 * Reading the CRC requires the vblank interrupt handler to be
82*b843c749SSergey Zigachev 	 * enabled. Keep a reference until CRC capture stops.
83*b843c749SSergey Zigachev 	 */
84*b843c749SSergey Zigachev 	if (!crtc_state->crc_enabled && enable)
85*b843c749SSergey Zigachev 		drm_crtc_vblank_get(crtc);
86*b843c749SSergey Zigachev 	else if (crtc_state->crc_enabled && !enable)
87*b843c749SSergey Zigachev 		drm_crtc_vblank_put(crtc);
88*b843c749SSergey Zigachev 
89*b843c749SSergey Zigachev 	crtc_state->crc_enabled = enable;
90*b843c749SSergey Zigachev 
91*b843c749SSergey Zigachev 	*values_cnt = 3;
92*b843c749SSergey Zigachev 	/* Reset crc_skipped on dm state */
93*b843c749SSergey Zigachev 	crtc_state->crc_skip_count = 0;
94*b843c749SSergey Zigachev 	return 0;
95*b843c749SSergey Zigachev }
96*b843c749SSergey Zigachev 
97*b843c749SSergey Zigachev /**
98*b843c749SSergey Zigachev  * amdgpu_dm_crtc_handle_crc_irq: Report to DRM the CRC on given CRTC.
99*b843c749SSergey Zigachev  * @crtc: DRM CRTC object.
100*b843c749SSergey Zigachev  *
101*b843c749SSergey Zigachev  * This function should be called at the end of a vblank, when the fb has been
102*b843c749SSergey Zigachev  * fully processed through the pipe.
103*b843c749SSergey Zigachev  */
amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc * crtc)104*b843c749SSergey Zigachev void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
105*b843c749SSergey Zigachev {
106*b843c749SSergey Zigachev 	struct dm_crtc_state *crtc_state;
107*b843c749SSergey Zigachev 	struct dc_stream_state *stream_state;
108*b843c749SSergey Zigachev 	uint32_t crcs[3];
109*b843c749SSergey Zigachev 
110*b843c749SSergey Zigachev 	if (crtc == NULL)
111*b843c749SSergey Zigachev 		return;
112*b843c749SSergey Zigachev 
113*b843c749SSergey Zigachev 	crtc_state = to_dm_crtc_state(crtc->state);
114*b843c749SSergey Zigachev 	stream_state = crtc_state->stream;
115*b843c749SSergey Zigachev 
116*b843c749SSergey Zigachev 	/* Early return if CRC capture is not enabled. */
117*b843c749SSergey Zigachev 	if (!crtc_state->crc_enabled)
118*b843c749SSergey Zigachev 		return;
119*b843c749SSergey Zigachev 
120*b843c749SSergey Zigachev 	/*
121*b843c749SSergey Zigachev 	 * Since flipping and crc enablement happen asynchronously, we - more
122*b843c749SSergey Zigachev 	 * often than not - will be returning an 'uncooked' crc on first frame.
123*b843c749SSergey Zigachev 	 * Probably because hw isn't ready yet. For added security, skip the
124*b843c749SSergey Zigachev 	 * first two CRC values.
125*b843c749SSergey Zigachev 	 */
126*b843c749SSergey Zigachev 	if (crtc_state->crc_skip_count < 2) {
127*b843c749SSergey Zigachev 		crtc_state->crc_skip_count += 1;
128*b843c749SSergey Zigachev 		return;
129*b843c749SSergey Zigachev 	}
130*b843c749SSergey Zigachev 
131*b843c749SSergey Zigachev 	if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
132*b843c749SSergey Zigachev 			       &crcs[0], &crcs[1], &crcs[2]))
133*b843c749SSergey Zigachev 		return;
134*b843c749SSergey Zigachev 
135*b843c749SSergey Zigachev 	drm_crtc_add_crc_entry(crtc, true,
136*b843c749SSergey Zigachev 			       drm_crtc_accurate_vblank_count(crtc), crcs);
137*b843c749SSergey Zigachev }
138