Merge tag 'amd-drm-next-5.16-2021-09-27' of https://gitlab.freedesktop.org/agd5f...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / display / dc / dcn31 / dcn31_apg.c
1 /*
2  * Copyright 2019 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  *  and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25
26
27 #include "dc_bios_types.h"
28 #include "hw_shared.h"
29 #include "dcn31_apg.h"
30 #include "reg_helper.h"
31
32 #define DC_LOGGER \
33                 apg31->base.ctx->logger
34
35 #define REG(reg)\
36         (apg31->regs->reg)
37
38 #undef FN
39 #define FN(reg_name, field_name) \
40         apg31->apg_shift->field_name, apg31->apg_mask->field_name
41
42
43 #define CTX \
44         apg31->base.ctx
45
46
47 static void apg31_enable(
48         struct apg *apg)
49 {
50         struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
51
52         /* Reset APG */
53         REG_UPDATE(APG_CONTROL, APG_RESET, 1);
54         REG_WAIT(APG_CONTROL,
55                         APG_RESET_DONE, 1,
56                         1, 10);
57         REG_UPDATE(APG_CONTROL, APG_RESET, 0);
58         REG_WAIT(APG_CONTROL,
59                         APG_RESET_DONE, 0,
60                         1, 10);
61
62         /* Enable APG */
63         REG_UPDATE(APG_CONTROL2, APG_ENABLE, 1);
64 }
65
66 static void apg31_disable(
67         struct apg *apg)
68 {
69         struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
70
71         /* Disable APG */
72         REG_UPDATE(APG_CONTROL2, APG_ENABLE, 0);
73 }
74
75 static union audio_cea_channels speakers_to_channels(
76         struct audio_speaker_flags speaker_flags)
77 {
78         union audio_cea_channels cea_channels = {0};
79
80         /* these are one to one */
81         cea_channels.channels.FL = speaker_flags.FL_FR;
82         cea_channels.channels.FR = speaker_flags.FL_FR;
83         cea_channels.channels.LFE = speaker_flags.LFE;
84         cea_channels.channels.FC = speaker_flags.FC;
85
86         /* if Rear Left and Right exist move RC speaker to channel 7
87          * otherwise to channel 5
88          */
89         if (speaker_flags.RL_RR) {
90                 cea_channels.channels.RL_RC = speaker_flags.RL_RR;
91                 cea_channels.channels.RR = speaker_flags.RL_RR;
92                 cea_channels.channels.RC_RLC_FLC = speaker_flags.RC;
93         } else {
94                 cea_channels.channels.RL_RC = speaker_flags.RC;
95         }
96
97         /* FRONT Left Right Center and REAR Left Right Center are exclusive */
98         if (speaker_flags.FLC_FRC) {
99                 cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC;
100                 cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC;
101         } else {
102                 cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC;
103                 cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC;
104         }
105
106         return cea_channels;
107 }
108
109 static void apg31_se_audio_setup(
110         struct apg *apg,
111         unsigned int az_inst,
112         struct audio_info *audio_info)
113 {
114         struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
115
116         uint32_t speakers = 0;
117         uint32_t channels = 0;
118
119         ASSERT(audio_info);
120         /* This should not happen.it does so we don't get BSOD*/
121         if (audio_info == NULL)
122                 return;
123
124         speakers = audio_info->flags.info.ALLSPEAKERS;
125         channels = speakers_to_channels(audio_info->flags.speaker_flags).all;
126
127         /* DisplayPort only allows for one audio stream with stream ID 0 */
128         REG_UPDATE(APG_CONTROL2, APG_DP_AUDIO_STREAM_ID, 0);
129
130         /* When running in "pair mode", pairs of audio channels have their own enable
131          * this is for really old audio drivers */
132         REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, 0xF);
133         // REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, channels);
134
135         /* Disable forced mem power off */
136         REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0);
137
138         apg31_enable(apg);
139 }
140
141 static void apg31_audio_mute_control(
142         struct apg *apg,
143         bool mute)
144 {
145         if (mute)
146                 apg31_disable(apg);
147         else
148                 apg31_enable(apg);
149 }
150
151 static struct apg_funcs dcn31_apg_funcs = {
152         .se_audio_setup                 = apg31_se_audio_setup,
153         .audio_mute_control             = apg31_audio_mute_control,
154         .enable_apg                     = apg31_enable,
155         .disable_apg                    = apg31_disable,
156 };
157
158 void apg31_construct(struct dcn31_apg *apg31,
159         struct dc_context *ctx,
160         uint32_t inst,
161         const struct dcn31_apg_registers *apg_regs,
162         const struct dcn31_apg_shift *apg_shift,
163         const struct dcn31_apg_mask *apg_mask)
164 {
165         apg31->base.ctx = ctx;
166
167         apg31->base.inst = inst;
168         apg31->base.funcs = &dcn31_apg_funcs;
169
170         apg31->regs = apg_regs;
171         apg31->apg_shift = apg_shift;
172         apg31->apg_mask = apg_mask;
173 }