Line data Source code
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 0 : static void apg31_enable(
48 : struct apg *apg)
49 : {
50 0 : struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
51 :
52 : /* Reset APG */
53 0 : REG_UPDATE(APG_CONTROL, APG_RESET, 1);
54 0 : REG_WAIT(APG_CONTROL,
55 : APG_RESET_DONE, 1,
56 : 1, 10);
57 0 : REG_UPDATE(APG_CONTROL, APG_RESET, 0);
58 0 : REG_WAIT(APG_CONTROL,
59 : APG_RESET_DONE, 0,
60 : 1, 10);
61 :
62 : /* Enable APG */
63 0 : REG_UPDATE(APG_CONTROL2, APG_ENABLE, 1);
64 0 : }
65 :
66 0 : static void apg31_disable(
67 : struct apg *apg)
68 : {
69 0 : struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
70 :
71 : /* Disable APG */
72 0 : REG_UPDATE(APG_CONTROL2, APG_ENABLE, 0);
73 0 : }
74 :
75 : static union audio_cea_channels speakers_to_channels(
76 : struct audio_speaker_flags speaker_flags)
77 : {
78 0 : union audio_cea_channels cea_channels = {0};
79 :
80 : /* these are one to one */
81 0 : cea_channels.channels.FL = speaker_flags.FL_FR;
82 0 : cea_channels.channels.FR = speaker_flags.FL_FR;
83 0 : cea_channels.channels.LFE = speaker_flags.LFE;
84 0 : 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 0 : return cea_channels;
107 : }
108 :
109 0 : static void apg31_se_audio_setup(
110 : struct apg *apg,
111 : unsigned int az_inst,
112 : struct audio_info *audio_info)
113 : {
114 0 : struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
115 :
116 0 : uint32_t speakers = 0;
117 0 : uint32_t channels = 0;
118 :
119 0 : ASSERT(audio_info);
120 : /* This should not happen.it does so we don't get BSOD*/
121 0 : if (audio_info == NULL)
122 : return;
123 :
124 0 : speakers = audio_info->flags.info.ALLSPEAKERS;
125 0 : channels = speakers_to_channels(audio_info->flags.speaker_flags).all;
126 :
127 : /* DisplayPort only allows for one audio stream with stream ID 0 */
128 0 : 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 0 : REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, 0xFF);
133 : // REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, channels);
134 :
135 : /* Disable forced mem power off */
136 0 : REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0);
137 :
138 0 : apg31_enable(apg);
139 : }
140 :
141 0 : static void apg31_audio_mute_control(
142 : struct apg *apg,
143 : bool mute)
144 : {
145 0 : if (mute)
146 0 : apg31_disable(apg);
147 : else
148 0 : apg31_enable(apg);
149 0 : }
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 0 : 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 0 : apg31->base.ctx = ctx;
166 :
167 0 : apg31->base.inst = inst;
168 0 : apg31->base.funcs = &dcn31_apg_funcs;
169 :
170 0 : apg31->regs = apg_regs;
171 0 : apg31->apg_shift = apg_shift;
172 0 : apg31->apg_mask = apg_mask;
173 0 : }
|