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