1*b843c749SSergey Zigachev /*
2*b843c749SSergey Zigachev * Copyright 2007-8 Advanced Micro Devices, Inc.
3*b843c749SSergey Zigachev * Copyright 2008 Red Hat Inc.
4*b843c749SSergey Zigachev *
5*b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a
6*b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"),
7*b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation
8*b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the
10*b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions:
11*b843c749SSergey Zigachev *
12*b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in
13*b843c749SSergey Zigachev * all copies or substantial portions of the Software.
14*b843c749SSergey Zigachev *
15*b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19*b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20*b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21*b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE.
22*b843c749SSergey Zigachev *
23*b843c749SSergey Zigachev * Authors: Dave Airlie
24*b843c749SSergey Zigachev * Alex Deucher
25*b843c749SSergey Zigachev */
26*b843c749SSergey Zigachev #include <drm/drmP.h>
27*b843c749SSergey Zigachev #include <drm/drm_crtc_helper.h>
28*b843c749SSergey Zigachev #include <drm/amdgpu_drm.h>
29*b843c749SSergey Zigachev #include <drm/drm_fixed.h>
30*b843c749SSergey Zigachev #include "amdgpu.h"
31*b843c749SSergey Zigachev #include "atom.h"
32*b843c749SSergey Zigachev #include "atom-bits.h"
33*b843c749SSergey Zigachev #include "atombios_encoders.h"
34*b843c749SSergey Zigachev #include "atombios_crtc.h"
35*b843c749SSergey Zigachev #include "amdgpu_atombios.h"
36*b843c749SSergey Zigachev #include "amdgpu_pll.h"
37*b843c749SSergey Zigachev #include "amdgpu_connectors.h"
38*b843c749SSergey Zigachev
amdgpu_atombios_crtc_overscan_setup(struct drm_crtc * crtc,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)39*b843c749SSergey Zigachev void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc,
40*b843c749SSergey Zigachev struct drm_display_mode *mode,
41*b843c749SSergey Zigachev struct drm_display_mode *adjusted_mode)
42*b843c749SSergey Zigachev {
43*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
44*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
45*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
46*b843c749SSergey Zigachev SET_CRTC_OVERSCAN_PS_ALLOCATION args;
47*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
48*b843c749SSergey Zigachev int a1, a2;
49*b843c749SSergey Zigachev
50*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
51*b843c749SSergey Zigachev
52*b843c749SSergey Zigachev args.ucCRTC = amdgpu_crtc->crtc_id;
53*b843c749SSergey Zigachev
54*b843c749SSergey Zigachev switch (amdgpu_crtc->rmx_type) {
55*b843c749SSergey Zigachev case RMX_CENTER:
56*b843c749SSergey Zigachev args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
57*b843c749SSergey Zigachev args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
58*b843c749SSergey Zigachev args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
59*b843c749SSergey Zigachev args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
60*b843c749SSergey Zigachev break;
61*b843c749SSergey Zigachev case RMX_ASPECT:
62*b843c749SSergey Zigachev a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
63*b843c749SSergey Zigachev a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
64*b843c749SSergey Zigachev
65*b843c749SSergey Zigachev if (a1 > a2) {
66*b843c749SSergey Zigachev args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
67*b843c749SSergey Zigachev args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
68*b843c749SSergey Zigachev } else if (a2 > a1) {
69*b843c749SSergey Zigachev args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
70*b843c749SSergey Zigachev args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
71*b843c749SSergey Zigachev }
72*b843c749SSergey Zigachev break;
73*b843c749SSergey Zigachev case RMX_FULL:
74*b843c749SSergey Zigachev default:
75*b843c749SSergey Zigachev args.usOverscanRight = cpu_to_le16(amdgpu_crtc->h_border);
76*b843c749SSergey Zigachev args.usOverscanLeft = cpu_to_le16(amdgpu_crtc->h_border);
77*b843c749SSergey Zigachev args.usOverscanBottom = cpu_to_le16(amdgpu_crtc->v_border);
78*b843c749SSergey Zigachev args.usOverscanTop = cpu_to_le16(amdgpu_crtc->v_border);
79*b843c749SSergey Zigachev break;
80*b843c749SSergey Zigachev }
81*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
82*b843c749SSergey Zigachev }
83*b843c749SSergey Zigachev
amdgpu_atombios_crtc_scaler_setup(struct drm_crtc * crtc)84*b843c749SSergey Zigachev void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc)
85*b843c749SSergey Zigachev {
86*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
87*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
88*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
89*b843c749SSergey Zigachev ENABLE_SCALER_PS_ALLOCATION args;
90*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
91*b843c749SSergey Zigachev
92*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
93*b843c749SSergey Zigachev
94*b843c749SSergey Zigachev args.ucScaler = amdgpu_crtc->crtc_id;
95*b843c749SSergey Zigachev
96*b843c749SSergey Zigachev switch (amdgpu_crtc->rmx_type) {
97*b843c749SSergey Zigachev case RMX_FULL:
98*b843c749SSergey Zigachev args.ucEnable = ATOM_SCALER_EXPANSION;
99*b843c749SSergey Zigachev break;
100*b843c749SSergey Zigachev case RMX_CENTER:
101*b843c749SSergey Zigachev args.ucEnable = ATOM_SCALER_CENTER;
102*b843c749SSergey Zigachev break;
103*b843c749SSergey Zigachev case RMX_ASPECT:
104*b843c749SSergey Zigachev args.ucEnable = ATOM_SCALER_EXPANSION;
105*b843c749SSergey Zigachev break;
106*b843c749SSergey Zigachev default:
107*b843c749SSergey Zigachev args.ucEnable = ATOM_SCALER_DISABLE;
108*b843c749SSergey Zigachev break;
109*b843c749SSergey Zigachev }
110*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
111*b843c749SSergey Zigachev }
112*b843c749SSergey Zigachev
amdgpu_atombios_crtc_lock(struct drm_crtc * crtc,int lock)113*b843c749SSergey Zigachev void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock)
114*b843c749SSergey Zigachev {
115*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
116*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
117*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
118*b843c749SSergey Zigachev int index =
119*b843c749SSergey Zigachev GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
120*b843c749SSergey Zigachev ENABLE_CRTC_PS_ALLOCATION args;
121*b843c749SSergey Zigachev
122*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
123*b843c749SSergey Zigachev
124*b843c749SSergey Zigachev args.ucCRTC = amdgpu_crtc->crtc_id;
125*b843c749SSergey Zigachev args.ucEnable = lock;
126*b843c749SSergey Zigachev
127*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
128*b843c749SSergey Zigachev }
129*b843c749SSergey Zigachev
amdgpu_atombios_crtc_enable(struct drm_crtc * crtc,int state)130*b843c749SSergey Zigachev void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state)
131*b843c749SSergey Zigachev {
132*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
133*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
134*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
135*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
136*b843c749SSergey Zigachev ENABLE_CRTC_PS_ALLOCATION args;
137*b843c749SSergey Zigachev
138*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
139*b843c749SSergey Zigachev
140*b843c749SSergey Zigachev args.ucCRTC = amdgpu_crtc->crtc_id;
141*b843c749SSergey Zigachev args.ucEnable = state;
142*b843c749SSergey Zigachev
143*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
144*b843c749SSergey Zigachev }
145*b843c749SSergey Zigachev
amdgpu_atombios_crtc_blank(struct drm_crtc * crtc,int state)146*b843c749SSergey Zigachev void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state)
147*b843c749SSergey Zigachev {
148*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
149*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
150*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
151*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
152*b843c749SSergey Zigachev BLANK_CRTC_PS_ALLOCATION args;
153*b843c749SSergey Zigachev
154*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
155*b843c749SSergey Zigachev
156*b843c749SSergey Zigachev args.ucCRTC = amdgpu_crtc->crtc_id;
157*b843c749SSergey Zigachev args.ucBlanking = state;
158*b843c749SSergey Zigachev
159*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
160*b843c749SSergey Zigachev }
161*b843c749SSergey Zigachev
amdgpu_atombios_crtc_powergate(struct drm_crtc * crtc,int state)162*b843c749SSergey Zigachev void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state)
163*b843c749SSergey Zigachev {
164*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
165*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
166*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
167*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
168*b843c749SSergey Zigachev ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
169*b843c749SSergey Zigachev
170*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
171*b843c749SSergey Zigachev
172*b843c749SSergey Zigachev args.ucDispPipeId = amdgpu_crtc->crtc_id;
173*b843c749SSergey Zigachev args.ucEnable = state;
174*b843c749SSergey Zigachev
175*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
176*b843c749SSergey Zigachev }
177*b843c749SSergey Zigachev
amdgpu_atombios_crtc_powergate_init(struct amdgpu_device * adev)178*b843c749SSergey Zigachev void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev)
179*b843c749SSergey Zigachev {
180*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
181*b843c749SSergey Zigachev ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
182*b843c749SSergey Zigachev
183*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
184*b843c749SSergey Zigachev
185*b843c749SSergey Zigachev args.ucEnable = ATOM_INIT;
186*b843c749SSergey Zigachev
187*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
188*b843c749SSergey Zigachev }
189*b843c749SSergey Zigachev
amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc * crtc,struct drm_display_mode * mode)190*b843c749SSergey Zigachev void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc,
191*b843c749SSergey Zigachev struct drm_display_mode *mode)
192*b843c749SSergey Zigachev {
193*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
194*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
195*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
196*b843c749SSergey Zigachev SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
197*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
198*b843c749SSergey Zigachev u16 misc = 0;
199*b843c749SSergey Zigachev
200*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
201*b843c749SSergey Zigachev args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (amdgpu_crtc->h_border * 2));
202*b843c749SSergey Zigachev args.usH_Blanking_Time =
203*b843c749SSergey Zigachev cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (amdgpu_crtc->h_border * 2));
204*b843c749SSergey Zigachev args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (amdgpu_crtc->v_border * 2));
205*b843c749SSergey Zigachev args.usV_Blanking_Time =
206*b843c749SSergey Zigachev cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (amdgpu_crtc->v_border * 2));
207*b843c749SSergey Zigachev args.usH_SyncOffset =
208*b843c749SSergey Zigachev cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + amdgpu_crtc->h_border);
209*b843c749SSergey Zigachev args.usH_SyncWidth =
210*b843c749SSergey Zigachev cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
211*b843c749SSergey Zigachev args.usV_SyncOffset =
212*b843c749SSergey Zigachev cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + amdgpu_crtc->v_border);
213*b843c749SSergey Zigachev args.usV_SyncWidth =
214*b843c749SSergey Zigachev cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
215*b843c749SSergey Zigachev args.ucH_Border = amdgpu_crtc->h_border;
216*b843c749SSergey Zigachev args.ucV_Border = amdgpu_crtc->v_border;
217*b843c749SSergey Zigachev
218*b843c749SSergey Zigachev if (mode->flags & DRM_MODE_FLAG_NVSYNC)
219*b843c749SSergey Zigachev misc |= ATOM_VSYNC_POLARITY;
220*b843c749SSergey Zigachev if (mode->flags & DRM_MODE_FLAG_NHSYNC)
221*b843c749SSergey Zigachev misc |= ATOM_HSYNC_POLARITY;
222*b843c749SSergey Zigachev if (mode->flags & DRM_MODE_FLAG_CSYNC)
223*b843c749SSergey Zigachev misc |= ATOM_COMPOSITESYNC;
224*b843c749SSergey Zigachev if (mode->flags & DRM_MODE_FLAG_INTERLACE)
225*b843c749SSergey Zigachev misc |= ATOM_INTERLACE;
226*b843c749SSergey Zigachev if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
227*b843c749SSergey Zigachev misc |= ATOM_DOUBLE_CLOCK_MODE;
228*b843c749SSergey Zigachev
229*b843c749SSergey Zigachev args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
230*b843c749SSergey Zigachev args.ucCRTC = amdgpu_crtc->crtc_id;
231*b843c749SSergey Zigachev
232*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
233*b843c749SSergey Zigachev }
234*b843c749SSergey Zigachev
235*b843c749SSergey Zigachev union atom_enable_ss {
236*b843c749SSergey Zigachev ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
237*b843c749SSergey Zigachev ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
238*b843c749SSergey Zigachev ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
239*b843c749SSergey Zigachev };
240*b843c749SSergey Zigachev
amdgpu_atombios_crtc_program_ss(struct amdgpu_device * adev,int enable,int pll_id,int crtc_id,struct amdgpu_atom_ss * ss)241*b843c749SSergey Zigachev static void amdgpu_atombios_crtc_program_ss(struct amdgpu_device *adev,
242*b843c749SSergey Zigachev int enable,
243*b843c749SSergey Zigachev int pll_id,
244*b843c749SSergey Zigachev int crtc_id,
245*b843c749SSergey Zigachev struct amdgpu_atom_ss *ss)
246*b843c749SSergey Zigachev {
247*b843c749SSergey Zigachev unsigned i;
248*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
249*b843c749SSergey Zigachev union atom_enable_ss args;
250*b843c749SSergey Zigachev
251*b843c749SSergey Zigachev if (enable) {
252*b843c749SSergey Zigachev /* Don't mess with SS if percentage is 0 or external ss.
253*b843c749SSergey Zigachev * SS is already disabled previously, and disabling it
254*b843c749SSergey Zigachev * again can cause display problems if the pll is already
255*b843c749SSergey Zigachev * programmed.
256*b843c749SSergey Zigachev */
257*b843c749SSergey Zigachev if (ss->percentage == 0)
258*b843c749SSergey Zigachev return;
259*b843c749SSergey Zigachev if (ss->type & ATOM_EXTERNAL_SS_MASK)
260*b843c749SSergey Zigachev return;
261*b843c749SSergey Zigachev } else {
262*b843c749SSergey Zigachev for (i = 0; i < adev->mode_info.num_crtc; i++) {
263*b843c749SSergey Zigachev if (adev->mode_info.crtcs[i] &&
264*b843c749SSergey Zigachev adev->mode_info.crtcs[i]->enabled &&
265*b843c749SSergey Zigachev i != crtc_id &&
266*b843c749SSergey Zigachev pll_id == adev->mode_info.crtcs[i]->pll_id) {
267*b843c749SSergey Zigachev /* one other crtc is using this pll don't turn
268*b843c749SSergey Zigachev * off spread spectrum as it might turn off
269*b843c749SSergey Zigachev * display on active crtc
270*b843c749SSergey Zigachev */
271*b843c749SSergey Zigachev return;
272*b843c749SSergey Zigachev }
273*b843c749SSergey Zigachev }
274*b843c749SSergey Zigachev }
275*b843c749SSergey Zigachev
276*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
277*b843c749SSergey Zigachev
278*b843c749SSergey Zigachev args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
279*b843c749SSergey Zigachev args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
280*b843c749SSergey Zigachev switch (pll_id) {
281*b843c749SSergey Zigachev case ATOM_PPLL1:
282*b843c749SSergey Zigachev args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
283*b843c749SSergey Zigachev break;
284*b843c749SSergey Zigachev case ATOM_PPLL2:
285*b843c749SSergey Zigachev args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
286*b843c749SSergey Zigachev break;
287*b843c749SSergey Zigachev case ATOM_DCPLL:
288*b843c749SSergey Zigachev args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
289*b843c749SSergey Zigachev break;
290*b843c749SSergey Zigachev case ATOM_PPLL_INVALID:
291*b843c749SSergey Zigachev return;
292*b843c749SSergey Zigachev }
293*b843c749SSergey Zigachev args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
294*b843c749SSergey Zigachev args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
295*b843c749SSergey Zigachev args.v3.ucEnable = enable;
296*b843c749SSergey Zigachev
297*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
298*b843c749SSergey Zigachev }
299*b843c749SSergey Zigachev
300*b843c749SSergey Zigachev union adjust_pixel_clock {
301*b843c749SSergey Zigachev ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
302*b843c749SSergey Zigachev ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
303*b843c749SSergey Zigachev };
304*b843c749SSergey Zigachev
amdgpu_atombios_crtc_adjust_pll(struct drm_crtc * crtc,struct drm_display_mode * mode)305*b843c749SSergey Zigachev static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
306*b843c749SSergey Zigachev struct drm_display_mode *mode)
307*b843c749SSergey Zigachev {
308*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
309*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
310*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
311*b843c749SSergey Zigachev struct drm_encoder *encoder = amdgpu_crtc->encoder;
312*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
313*b843c749SSergey Zigachev struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
314*b843c749SSergey Zigachev u32 adjusted_clock = mode->clock;
315*b843c749SSergey Zigachev int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
316*b843c749SSergey Zigachev u32 dp_clock = mode->clock;
317*b843c749SSergey Zigachev u32 clock = mode->clock;
318*b843c749SSergey Zigachev int bpc = amdgpu_crtc->bpc;
319*b843c749SSergey Zigachev bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, mode->clock);
320*b843c749SSergey Zigachev union adjust_pixel_clock args;
321*b843c749SSergey Zigachev u8 frev, crev;
322*b843c749SSergey Zigachev int index;
323*b843c749SSergey Zigachev
324*b843c749SSergey Zigachev amdgpu_crtc->pll_flags = AMDGPU_PLL_USE_FRAC_FB_DIV;
325*b843c749SSergey Zigachev
326*b843c749SSergey Zigachev if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
327*b843c749SSergey Zigachev (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
328*b843c749SSergey Zigachev if (connector) {
329*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
330*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *dig_connector =
331*b843c749SSergey Zigachev amdgpu_connector->con_priv;
332*b843c749SSergey Zigachev
333*b843c749SSergey Zigachev dp_clock = dig_connector->dp_clock;
334*b843c749SSergey Zigachev }
335*b843c749SSergey Zigachev }
336*b843c749SSergey Zigachev
337*b843c749SSergey Zigachev /* use recommended ref_div for ss */
338*b843c749SSergey Zigachev if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
339*b843c749SSergey Zigachev if (amdgpu_crtc->ss_enabled) {
340*b843c749SSergey Zigachev if (amdgpu_crtc->ss.refdiv) {
341*b843c749SSergey Zigachev amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
342*b843c749SSergey Zigachev amdgpu_crtc->pll_reference_div = amdgpu_crtc->ss.refdiv;
343*b843c749SSergey Zigachev amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
344*b843c749SSergey Zigachev }
345*b843c749SSergey Zigachev }
346*b843c749SSergey Zigachev }
347*b843c749SSergey Zigachev
348*b843c749SSergey Zigachev /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
349*b843c749SSergey Zigachev if (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
350*b843c749SSergey Zigachev adjusted_clock = mode->clock * 2;
351*b843c749SSergey Zigachev if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
352*b843c749SSergey Zigachev amdgpu_crtc->pll_flags |= AMDGPU_PLL_PREFER_CLOSEST_LOWER;
353*b843c749SSergey Zigachev if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
354*b843c749SSergey Zigachev amdgpu_crtc->pll_flags |= AMDGPU_PLL_IS_LCD;
355*b843c749SSergey Zigachev
356*b843c749SSergey Zigachev
357*b843c749SSergey Zigachev /* adjust pll for deep color modes */
358*b843c749SSergey Zigachev if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
359*b843c749SSergey Zigachev switch (bpc) {
360*b843c749SSergey Zigachev case 8:
361*b843c749SSergey Zigachev default:
362*b843c749SSergey Zigachev break;
363*b843c749SSergey Zigachev case 10:
364*b843c749SSergey Zigachev clock = (clock * 5) / 4;
365*b843c749SSergey Zigachev break;
366*b843c749SSergey Zigachev case 12:
367*b843c749SSergey Zigachev clock = (clock * 3) / 2;
368*b843c749SSergey Zigachev break;
369*b843c749SSergey Zigachev case 16:
370*b843c749SSergey Zigachev clock = clock * 2;
371*b843c749SSergey Zigachev break;
372*b843c749SSergey Zigachev }
373*b843c749SSergey Zigachev }
374*b843c749SSergey Zigachev
375*b843c749SSergey Zigachev /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
376*b843c749SSergey Zigachev * accordingly based on the encoder/transmitter to work around
377*b843c749SSergey Zigachev * special hw requirements.
378*b843c749SSergey Zigachev */
379*b843c749SSergey Zigachev index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
380*b843c749SSergey Zigachev if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
381*b843c749SSergey Zigachev &crev))
382*b843c749SSergey Zigachev return adjusted_clock;
383*b843c749SSergey Zigachev
384*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
385*b843c749SSergey Zigachev
386*b843c749SSergey Zigachev switch (frev) {
387*b843c749SSergey Zigachev case 1:
388*b843c749SSergey Zigachev switch (crev) {
389*b843c749SSergey Zigachev case 1:
390*b843c749SSergey Zigachev case 2:
391*b843c749SSergey Zigachev args.v1.usPixelClock = cpu_to_le16(clock / 10);
392*b843c749SSergey Zigachev args.v1.ucTransmitterID = amdgpu_encoder->encoder_id;
393*b843c749SSergey Zigachev args.v1.ucEncodeMode = encoder_mode;
394*b843c749SSergey Zigachev if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
395*b843c749SSergey Zigachev args.v1.ucConfig |=
396*b843c749SSergey Zigachev ADJUST_DISPLAY_CONFIG_SS_ENABLE;
397*b843c749SSergey Zigachev
398*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context,
399*b843c749SSergey Zigachev index, (uint32_t *)&args);
400*b843c749SSergey Zigachev adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
401*b843c749SSergey Zigachev break;
402*b843c749SSergey Zigachev case 3:
403*b843c749SSergey Zigachev args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
404*b843c749SSergey Zigachev args.v3.sInput.ucTransmitterID = amdgpu_encoder->encoder_id;
405*b843c749SSergey Zigachev args.v3.sInput.ucEncodeMode = encoder_mode;
406*b843c749SSergey Zigachev args.v3.sInput.ucDispPllConfig = 0;
407*b843c749SSergey Zigachev if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
408*b843c749SSergey Zigachev args.v3.sInput.ucDispPllConfig |=
409*b843c749SSergey Zigachev DISPPLL_CONFIG_SS_ENABLE;
410*b843c749SSergey Zigachev if (ENCODER_MODE_IS_DP(encoder_mode)) {
411*b843c749SSergey Zigachev args.v3.sInput.ucDispPllConfig |=
412*b843c749SSergey Zigachev DISPPLL_CONFIG_COHERENT_MODE;
413*b843c749SSergey Zigachev /* 16200 or 27000 */
414*b843c749SSergey Zigachev args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
415*b843c749SSergey Zigachev } else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
416*b843c749SSergey Zigachev struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
417*b843c749SSergey Zigachev if (dig->coherent_mode)
418*b843c749SSergey Zigachev args.v3.sInput.ucDispPllConfig |=
419*b843c749SSergey Zigachev DISPPLL_CONFIG_COHERENT_MODE;
420*b843c749SSergey Zigachev if (is_duallink)
421*b843c749SSergey Zigachev args.v3.sInput.ucDispPllConfig |=
422*b843c749SSergey Zigachev DISPPLL_CONFIG_DUAL_LINK;
423*b843c749SSergey Zigachev }
424*b843c749SSergey Zigachev if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) !=
425*b843c749SSergey Zigachev ENCODER_OBJECT_ID_NONE)
426*b843c749SSergey Zigachev args.v3.sInput.ucExtTransmitterID =
427*b843c749SSergey Zigachev amdgpu_encoder_get_dp_bridge_encoder_id(encoder);
428*b843c749SSergey Zigachev else
429*b843c749SSergey Zigachev args.v3.sInput.ucExtTransmitterID = 0;
430*b843c749SSergey Zigachev
431*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context,
432*b843c749SSergey Zigachev index, (uint32_t *)&args);
433*b843c749SSergey Zigachev adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
434*b843c749SSergey Zigachev if (args.v3.sOutput.ucRefDiv) {
435*b843c749SSergey Zigachev amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
436*b843c749SSergey Zigachev amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
437*b843c749SSergey Zigachev amdgpu_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv;
438*b843c749SSergey Zigachev }
439*b843c749SSergey Zigachev if (args.v3.sOutput.ucPostDiv) {
440*b843c749SSergey Zigachev amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
441*b843c749SSergey Zigachev amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_POST_DIV;
442*b843c749SSergey Zigachev amdgpu_crtc->pll_post_div = args.v3.sOutput.ucPostDiv;
443*b843c749SSergey Zigachev }
444*b843c749SSergey Zigachev break;
445*b843c749SSergey Zigachev default:
446*b843c749SSergey Zigachev DRM_ERROR("Unknown table version %d %d\n", frev, crev);
447*b843c749SSergey Zigachev return adjusted_clock;
448*b843c749SSergey Zigachev }
449*b843c749SSergey Zigachev break;
450*b843c749SSergey Zigachev default:
451*b843c749SSergey Zigachev DRM_ERROR("Unknown table version %d %d\n", frev, crev);
452*b843c749SSergey Zigachev return adjusted_clock;
453*b843c749SSergey Zigachev }
454*b843c749SSergey Zigachev
455*b843c749SSergey Zigachev return adjusted_clock;
456*b843c749SSergey Zigachev }
457*b843c749SSergey Zigachev
458*b843c749SSergey Zigachev union set_pixel_clock {
459*b843c749SSergey Zigachev SET_PIXEL_CLOCK_PS_ALLOCATION base;
460*b843c749SSergey Zigachev PIXEL_CLOCK_PARAMETERS v1;
461*b843c749SSergey Zigachev PIXEL_CLOCK_PARAMETERS_V2 v2;
462*b843c749SSergey Zigachev PIXEL_CLOCK_PARAMETERS_V3 v3;
463*b843c749SSergey Zigachev PIXEL_CLOCK_PARAMETERS_V5 v5;
464*b843c749SSergey Zigachev PIXEL_CLOCK_PARAMETERS_V6 v6;
465*b843c749SSergey Zigachev PIXEL_CLOCK_PARAMETERS_V7 v7;
466*b843c749SSergey Zigachev };
467*b843c749SSergey Zigachev
468*b843c749SSergey Zigachev /* on DCE5, make sure the voltage is high enough to support the
469*b843c749SSergey Zigachev * required disp clk.
470*b843c749SSergey Zigachev */
amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device * adev,u32 dispclk)471*b843c749SSergey Zigachev void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev,
472*b843c749SSergey Zigachev u32 dispclk)
473*b843c749SSergey Zigachev {
474*b843c749SSergey Zigachev u8 frev, crev;
475*b843c749SSergey Zigachev int index;
476*b843c749SSergey Zigachev union set_pixel_clock args;
477*b843c749SSergey Zigachev
478*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
479*b843c749SSergey Zigachev
480*b843c749SSergey Zigachev index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
481*b843c749SSergey Zigachev if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
482*b843c749SSergey Zigachev &crev))
483*b843c749SSergey Zigachev return;
484*b843c749SSergey Zigachev
485*b843c749SSergey Zigachev switch (frev) {
486*b843c749SSergey Zigachev case 1:
487*b843c749SSergey Zigachev switch (crev) {
488*b843c749SSergey Zigachev case 5:
489*b843c749SSergey Zigachev /* if the default dcpll clock is specified,
490*b843c749SSergey Zigachev * SetPixelClock provides the dividers
491*b843c749SSergey Zigachev */
492*b843c749SSergey Zigachev args.v5.ucCRTC = ATOM_CRTC_INVALID;
493*b843c749SSergey Zigachev args.v5.usPixelClock = cpu_to_le16(dispclk);
494*b843c749SSergey Zigachev args.v5.ucPpll = ATOM_DCPLL;
495*b843c749SSergey Zigachev break;
496*b843c749SSergey Zigachev case 6:
497*b843c749SSergey Zigachev /* if the default dcpll clock is specified,
498*b843c749SSergey Zigachev * SetPixelClock provides the dividers
499*b843c749SSergey Zigachev */
500*b843c749SSergey Zigachev args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
501*b843c749SSergey Zigachev if (adev->asic_type == CHIP_TAHITI ||
502*b843c749SSergey Zigachev adev->asic_type == CHIP_PITCAIRN ||
503*b843c749SSergey Zigachev adev->asic_type == CHIP_VERDE ||
504*b843c749SSergey Zigachev adev->asic_type == CHIP_OLAND)
505*b843c749SSergey Zigachev args.v6.ucPpll = ATOM_PPLL0;
506*b843c749SSergey Zigachev else
507*b843c749SSergey Zigachev args.v6.ucPpll = ATOM_EXT_PLL1;
508*b843c749SSergey Zigachev break;
509*b843c749SSergey Zigachev default:
510*b843c749SSergey Zigachev DRM_ERROR("Unknown table version %d %d\n", frev, crev);
511*b843c749SSergey Zigachev return;
512*b843c749SSergey Zigachev }
513*b843c749SSergey Zigachev break;
514*b843c749SSergey Zigachev default:
515*b843c749SSergey Zigachev DRM_ERROR("Unknown table version %d %d\n", frev, crev);
516*b843c749SSergey Zigachev return;
517*b843c749SSergey Zigachev }
518*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
519*b843c749SSergey Zigachev }
520*b843c749SSergey Zigachev
521*b843c749SSergey Zigachev union set_dce_clock {
522*b843c749SSergey Zigachev SET_DCE_CLOCK_PS_ALLOCATION_V1_1 v1_1;
523*b843c749SSergey Zigachev SET_DCE_CLOCK_PS_ALLOCATION_V2_1 v2_1;
524*b843c749SSergey Zigachev };
525*b843c749SSergey Zigachev
amdgpu_atombios_crtc_set_dce_clock(struct amdgpu_device * adev,u32 freq,u8 clk_type,u8 clk_src)526*b843c749SSergey Zigachev u32 amdgpu_atombios_crtc_set_dce_clock(struct amdgpu_device *adev,
527*b843c749SSergey Zigachev u32 freq, u8 clk_type, u8 clk_src)
528*b843c749SSergey Zigachev {
529*b843c749SSergey Zigachev u8 frev, crev;
530*b843c749SSergey Zigachev int index;
531*b843c749SSergey Zigachev union set_dce_clock args;
532*b843c749SSergey Zigachev u32 ret_freq = 0;
533*b843c749SSergey Zigachev
534*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
535*b843c749SSergey Zigachev
536*b843c749SSergey Zigachev index = GetIndexIntoMasterTable(COMMAND, SetDCEClock);
537*b843c749SSergey Zigachev if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
538*b843c749SSergey Zigachev &crev))
539*b843c749SSergey Zigachev return 0;
540*b843c749SSergey Zigachev
541*b843c749SSergey Zigachev switch (frev) {
542*b843c749SSergey Zigachev case 2:
543*b843c749SSergey Zigachev switch (crev) {
544*b843c749SSergey Zigachev case 1:
545*b843c749SSergey Zigachev args.v2_1.asParam.ulDCEClkFreq = cpu_to_le32(freq); /* 10kHz units */
546*b843c749SSergey Zigachev args.v2_1.asParam.ucDCEClkType = clk_type;
547*b843c749SSergey Zigachev args.v2_1.asParam.ucDCEClkSrc = clk_src;
548*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
549*b843c749SSergey Zigachev ret_freq = le32_to_cpu(args.v2_1.asParam.ulDCEClkFreq) * 10;
550*b843c749SSergey Zigachev break;
551*b843c749SSergey Zigachev default:
552*b843c749SSergey Zigachev DRM_ERROR("Unknown table version %d %d\n", frev, crev);
553*b843c749SSergey Zigachev return 0;
554*b843c749SSergey Zigachev }
555*b843c749SSergey Zigachev break;
556*b843c749SSergey Zigachev default:
557*b843c749SSergey Zigachev DRM_ERROR("Unknown table version %d %d\n", frev, crev);
558*b843c749SSergey Zigachev return 0;
559*b843c749SSergey Zigachev }
560*b843c749SSergey Zigachev
561*b843c749SSergey Zigachev return ret_freq;
562*b843c749SSergey Zigachev }
563*b843c749SSergey Zigachev
is_pixel_clock_source_from_pll(u32 encoder_mode,int pll_id)564*b843c749SSergey Zigachev static bool is_pixel_clock_source_from_pll(u32 encoder_mode, int pll_id)
565*b843c749SSergey Zigachev {
566*b843c749SSergey Zigachev if (ENCODER_MODE_IS_DP(encoder_mode)) {
567*b843c749SSergey Zigachev if (pll_id < ATOM_EXT_PLL1)
568*b843c749SSergey Zigachev return true;
569*b843c749SSergey Zigachev else
570*b843c749SSergey Zigachev return false;
571*b843c749SSergey Zigachev } else {
572*b843c749SSergey Zigachev return true;
573*b843c749SSergey Zigachev }
574*b843c749SSergey Zigachev }
575*b843c749SSergey Zigachev
amdgpu_atombios_crtc_program_pll(struct drm_crtc * crtc,u32 crtc_id,int pll_id,u32 encoder_mode,u32 encoder_id,u32 clock,u32 ref_div,u32 fb_div,u32 frac_fb_div,u32 post_div,int bpc,bool ss_enabled,struct amdgpu_atom_ss * ss)576*b843c749SSergey Zigachev void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc,
577*b843c749SSergey Zigachev u32 crtc_id,
578*b843c749SSergey Zigachev int pll_id,
579*b843c749SSergey Zigachev u32 encoder_mode,
580*b843c749SSergey Zigachev u32 encoder_id,
581*b843c749SSergey Zigachev u32 clock,
582*b843c749SSergey Zigachev u32 ref_div,
583*b843c749SSergey Zigachev u32 fb_div,
584*b843c749SSergey Zigachev u32 frac_fb_div,
585*b843c749SSergey Zigachev u32 post_div,
586*b843c749SSergey Zigachev int bpc,
587*b843c749SSergey Zigachev bool ss_enabled,
588*b843c749SSergey Zigachev struct amdgpu_atom_ss *ss)
589*b843c749SSergey Zigachev {
590*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
591*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
592*b843c749SSergey Zigachev u8 frev, crev;
593*b843c749SSergey Zigachev int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
594*b843c749SSergey Zigachev union set_pixel_clock args;
595*b843c749SSergey Zigachev
596*b843c749SSergey Zigachev memset(&args, 0, sizeof(args));
597*b843c749SSergey Zigachev
598*b843c749SSergey Zigachev if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
599*b843c749SSergey Zigachev &crev))
600*b843c749SSergey Zigachev return;
601*b843c749SSergey Zigachev
602*b843c749SSergey Zigachev switch (frev) {
603*b843c749SSergey Zigachev case 1:
604*b843c749SSergey Zigachev switch (crev) {
605*b843c749SSergey Zigachev case 1:
606*b843c749SSergey Zigachev if (clock == ATOM_DISABLE)
607*b843c749SSergey Zigachev return;
608*b843c749SSergey Zigachev args.v1.usPixelClock = cpu_to_le16(clock / 10);
609*b843c749SSergey Zigachev args.v1.usRefDiv = cpu_to_le16(ref_div);
610*b843c749SSergey Zigachev args.v1.usFbDiv = cpu_to_le16(fb_div);
611*b843c749SSergey Zigachev args.v1.ucFracFbDiv = frac_fb_div;
612*b843c749SSergey Zigachev args.v1.ucPostDiv = post_div;
613*b843c749SSergey Zigachev args.v1.ucPpll = pll_id;
614*b843c749SSergey Zigachev args.v1.ucCRTC = crtc_id;
615*b843c749SSergey Zigachev args.v1.ucRefDivSrc = 1;
616*b843c749SSergey Zigachev break;
617*b843c749SSergey Zigachev case 2:
618*b843c749SSergey Zigachev args.v2.usPixelClock = cpu_to_le16(clock / 10);
619*b843c749SSergey Zigachev args.v2.usRefDiv = cpu_to_le16(ref_div);
620*b843c749SSergey Zigachev args.v2.usFbDiv = cpu_to_le16(fb_div);
621*b843c749SSergey Zigachev args.v2.ucFracFbDiv = frac_fb_div;
622*b843c749SSergey Zigachev args.v2.ucPostDiv = post_div;
623*b843c749SSergey Zigachev args.v2.ucPpll = pll_id;
624*b843c749SSergey Zigachev args.v2.ucCRTC = crtc_id;
625*b843c749SSergey Zigachev args.v2.ucRefDivSrc = 1;
626*b843c749SSergey Zigachev break;
627*b843c749SSergey Zigachev case 3:
628*b843c749SSergey Zigachev args.v3.usPixelClock = cpu_to_le16(clock / 10);
629*b843c749SSergey Zigachev args.v3.usRefDiv = cpu_to_le16(ref_div);
630*b843c749SSergey Zigachev args.v3.usFbDiv = cpu_to_le16(fb_div);
631*b843c749SSergey Zigachev args.v3.ucFracFbDiv = frac_fb_div;
632*b843c749SSergey Zigachev args.v3.ucPostDiv = post_div;
633*b843c749SSergey Zigachev args.v3.ucPpll = pll_id;
634*b843c749SSergey Zigachev if (crtc_id == ATOM_CRTC2)
635*b843c749SSergey Zigachev args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
636*b843c749SSergey Zigachev else
637*b843c749SSergey Zigachev args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1;
638*b843c749SSergey Zigachev if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
639*b843c749SSergey Zigachev args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
640*b843c749SSergey Zigachev args.v3.ucTransmitterId = encoder_id;
641*b843c749SSergey Zigachev args.v3.ucEncoderMode = encoder_mode;
642*b843c749SSergey Zigachev break;
643*b843c749SSergey Zigachev case 5:
644*b843c749SSergey Zigachev args.v5.ucCRTC = crtc_id;
645*b843c749SSergey Zigachev args.v5.usPixelClock = cpu_to_le16(clock / 10);
646*b843c749SSergey Zigachev args.v5.ucRefDiv = ref_div;
647*b843c749SSergey Zigachev args.v5.usFbDiv = cpu_to_le16(fb_div);
648*b843c749SSergey Zigachev args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
649*b843c749SSergey Zigachev args.v5.ucPostDiv = post_div;
650*b843c749SSergey Zigachev args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
651*b843c749SSergey Zigachev if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
652*b843c749SSergey Zigachev (pll_id < ATOM_EXT_PLL1))
653*b843c749SSergey Zigachev args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
654*b843c749SSergey Zigachev if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
655*b843c749SSergey Zigachev switch (bpc) {
656*b843c749SSergey Zigachev case 8:
657*b843c749SSergey Zigachev default:
658*b843c749SSergey Zigachev args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
659*b843c749SSergey Zigachev break;
660*b843c749SSergey Zigachev case 10:
661*b843c749SSergey Zigachev /* yes this is correct, the atom define is wrong */
662*b843c749SSergey Zigachev args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
663*b843c749SSergey Zigachev break;
664*b843c749SSergey Zigachev case 12:
665*b843c749SSergey Zigachev /* yes this is correct, the atom define is wrong */
666*b843c749SSergey Zigachev args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
667*b843c749SSergey Zigachev break;
668*b843c749SSergey Zigachev }
669*b843c749SSergey Zigachev }
670*b843c749SSergey Zigachev args.v5.ucTransmitterID = encoder_id;
671*b843c749SSergey Zigachev args.v5.ucEncoderMode = encoder_mode;
672*b843c749SSergey Zigachev args.v5.ucPpll = pll_id;
673*b843c749SSergey Zigachev break;
674*b843c749SSergey Zigachev case 6:
675*b843c749SSergey Zigachev args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10);
676*b843c749SSergey Zigachev args.v6.ucRefDiv = ref_div;
677*b843c749SSergey Zigachev args.v6.usFbDiv = cpu_to_le16(fb_div);
678*b843c749SSergey Zigachev args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
679*b843c749SSergey Zigachev args.v6.ucPostDiv = post_div;
680*b843c749SSergey Zigachev args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
681*b843c749SSergey Zigachev if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
682*b843c749SSergey Zigachev (pll_id < ATOM_EXT_PLL1) &&
683*b843c749SSergey Zigachev !is_pixel_clock_source_from_pll(encoder_mode, pll_id))
684*b843c749SSergey Zigachev args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
685*b843c749SSergey Zigachev if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
686*b843c749SSergey Zigachev switch (bpc) {
687*b843c749SSergey Zigachev case 8:
688*b843c749SSergey Zigachev default:
689*b843c749SSergey Zigachev args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
690*b843c749SSergey Zigachev break;
691*b843c749SSergey Zigachev case 10:
692*b843c749SSergey Zigachev args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
693*b843c749SSergey Zigachev break;
694*b843c749SSergey Zigachev case 12:
695*b843c749SSergey Zigachev args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
696*b843c749SSergey Zigachev break;
697*b843c749SSergey Zigachev case 16:
698*b843c749SSergey Zigachev args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
699*b843c749SSergey Zigachev break;
700*b843c749SSergey Zigachev }
701*b843c749SSergey Zigachev }
702*b843c749SSergey Zigachev args.v6.ucTransmitterID = encoder_id;
703*b843c749SSergey Zigachev args.v6.ucEncoderMode = encoder_mode;
704*b843c749SSergey Zigachev args.v6.ucPpll = pll_id;
705*b843c749SSergey Zigachev break;
706*b843c749SSergey Zigachev case 7:
707*b843c749SSergey Zigachev args.v7.ulPixelClock = cpu_to_le32(clock * 10); /* 100 hz units */
708*b843c749SSergey Zigachev args.v7.ucMiscInfo = 0;
709*b843c749SSergey Zigachev if ((encoder_mode == ATOM_ENCODER_MODE_DVI) &&
710*b843c749SSergey Zigachev (clock > 165000))
711*b843c749SSergey Zigachev args.v7.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN;
712*b843c749SSergey Zigachev args.v7.ucCRTC = crtc_id;
713*b843c749SSergey Zigachev if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
714*b843c749SSergey Zigachev switch (bpc) {
715*b843c749SSergey Zigachev case 8:
716*b843c749SSergey Zigachev default:
717*b843c749SSergey Zigachev args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS;
718*b843c749SSergey Zigachev break;
719*b843c749SSergey Zigachev case 10:
720*b843c749SSergey Zigachev args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4;
721*b843c749SSergey Zigachev break;
722*b843c749SSergey Zigachev case 12:
723*b843c749SSergey Zigachev args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2;
724*b843c749SSergey Zigachev break;
725*b843c749SSergey Zigachev case 16:
726*b843c749SSergey Zigachev args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1;
727*b843c749SSergey Zigachev break;
728*b843c749SSergey Zigachev }
729*b843c749SSergey Zigachev }
730*b843c749SSergey Zigachev args.v7.ucTransmitterID = encoder_id;
731*b843c749SSergey Zigachev args.v7.ucEncoderMode = encoder_mode;
732*b843c749SSergey Zigachev args.v7.ucPpll = pll_id;
733*b843c749SSergey Zigachev break;
734*b843c749SSergey Zigachev default:
735*b843c749SSergey Zigachev DRM_ERROR("Unknown table version %d %d\n", frev, crev);
736*b843c749SSergey Zigachev return;
737*b843c749SSergey Zigachev }
738*b843c749SSergey Zigachev break;
739*b843c749SSergey Zigachev default:
740*b843c749SSergey Zigachev DRM_ERROR("Unknown table version %d %d\n", frev, crev);
741*b843c749SSergey Zigachev return;
742*b843c749SSergey Zigachev }
743*b843c749SSergey Zigachev
744*b843c749SSergey Zigachev amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
745*b843c749SSergey Zigachev }
746*b843c749SSergey Zigachev
amdgpu_atombios_crtc_prepare_pll(struct drm_crtc * crtc,struct drm_display_mode * mode)747*b843c749SSergey Zigachev int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
748*b843c749SSergey Zigachev struct drm_display_mode *mode)
749*b843c749SSergey Zigachev {
750*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
751*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
752*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
753*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder =
754*b843c749SSergey Zigachev to_amdgpu_encoder(amdgpu_crtc->encoder);
755*b843c749SSergey Zigachev int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
756*b843c749SSergey Zigachev
757*b843c749SSergey Zigachev amdgpu_crtc->bpc = 8;
758*b843c749SSergey Zigachev amdgpu_crtc->ss_enabled = false;
759*b843c749SSergey Zigachev
760*b843c749SSergey Zigachev if ((amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
761*b843c749SSergey Zigachev (amdgpu_encoder_get_dp_bridge_encoder_id(amdgpu_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
762*b843c749SSergey Zigachev struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
763*b843c749SSergey Zigachev struct drm_connector *connector =
764*b843c749SSergey Zigachev amdgpu_get_connector_for_encoder(amdgpu_crtc->encoder);
765*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector =
766*b843c749SSergey Zigachev to_amdgpu_connector(connector);
767*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *dig_connector =
768*b843c749SSergey Zigachev amdgpu_connector->con_priv;
769*b843c749SSergey Zigachev int dp_clock;
770*b843c749SSergey Zigachev
771*b843c749SSergey Zigachev /* Assign mode clock for hdmi deep color max clock limit check */
772*b843c749SSergey Zigachev amdgpu_connector->pixelclock_for_modeset = mode->clock;
773*b843c749SSergey Zigachev amdgpu_crtc->bpc = amdgpu_connector_get_monitor_bpc(connector);
774*b843c749SSergey Zigachev
775*b843c749SSergey Zigachev switch (encoder_mode) {
776*b843c749SSergey Zigachev case ATOM_ENCODER_MODE_DP_MST:
777*b843c749SSergey Zigachev case ATOM_ENCODER_MODE_DP:
778*b843c749SSergey Zigachev /* DP/eDP */
779*b843c749SSergey Zigachev dp_clock = dig_connector->dp_clock / 10;
780*b843c749SSergey Zigachev amdgpu_crtc->ss_enabled =
781*b843c749SSergey Zigachev amdgpu_atombios_get_asic_ss_info(adev, &amdgpu_crtc->ss,
782*b843c749SSergey Zigachev ASIC_INTERNAL_SS_ON_DP,
783*b843c749SSergey Zigachev dp_clock);
784*b843c749SSergey Zigachev break;
785*b843c749SSergey Zigachev case ATOM_ENCODER_MODE_LVDS:
786*b843c749SSergey Zigachev amdgpu_crtc->ss_enabled =
787*b843c749SSergey Zigachev amdgpu_atombios_get_asic_ss_info(adev,
788*b843c749SSergey Zigachev &amdgpu_crtc->ss,
789*b843c749SSergey Zigachev dig->lcd_ss_id,
790*b843c749SSergey Zigachev mode->clock / 10);
791*b843c749SSergey Zigachev break;
792*b843c749SSergey Zigachev case ATOM_ENCODER_MODE_DVI:
793*b843c749SSergey Zigachev amdgpu_crtc->ss_enabled =
794*b843c749SSergey Zigachev amdgpu_atombios_get_asic_ss_info(adev,
795*b843c749SSergey Zigachev &amdgpu_crtc->ss,
796*b843c749SSergey Zigachev ASIC_INTERNAL_SS_ON_TMDS,
797*b843c749SSergey Zigachev mode->clock / 10);
798*b843c749SSergey Zigachev break;
799*b843c749SSergey Zigachev case ATOM_ENCODER_MODE_HDMI:
800*b843c749SSergey Zigachev amdgpu_crtc->ss_enabled =
801*b843c749SSergey Zigachev amdgpu_atombios_get_asic_ss_info(adev,
802*b843c749SSergey Zigachev &amdgpu_crtc->ss,
803*b843c749SSergey Zigachev ASIC_INTERNAL_SS_ON_HDMI,
804*b843c749SSergey Zigachev mode->clock / 10);
805*b843c749SSergey Zigachev break;
806*b843c749SSergey Zigachev default:
807*b843c749SSergey Zigachev break;
808*b843c749SSergey Zigachev }
809*b843c749SSergey Zigachev }
810*b843c749SSergey Zigachev
811*b843c749SSergey Zigachev /* adjust pixel clock as needed */
812*b843c749SSergey Zigachev amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, mode);
813*b843c749SSergey Zigachev
814*b843c749SSergey Zigachev return 0;
815*b843c749SSergey Zigachev }
816*b843c749SSergey Zigachev
amdgpu_atombios_crtc_set_pll(struct drm_crtc * crtc,struct drm_display_mode * mode)817*b843c749SSergey Zigachev void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
818*b843c749SSergey Zigachev {
819*b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
820*b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
821*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
822*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder =
823*b843c749SSergey Zigachev to_amdgpu_encoder(amdgpu_crtc->encoder);
824*b843c749SSergey Zigachev u32 pll_clock = mode->clock;
825*b843c749SSergey Zigachev u32 clock = mode->clock;
826*b843c749SSergey Zigachev u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
827*b843c749SSergey Zigachev struct amdgpu_pll *pll;
828*b843c749SSergey Zigachev int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
829*b843c749SSergey Zigachev
830*b843c749SSergey Zigachev /* pass the actual clock to amdgpu_atombios_crtc_program_pll for HDMI */
831*b843c749SSergey Zigachev if ((encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
832*b843c749SSergey Zigachev (amdgpu_crtc->bpc > 8))
833*b843c749SSergey Zigachev clock = amdgpu_crtc->adjusted_clock;
834*b843c749SSergey Zigachev
835*b843c749SSergey Zigachev switch (amdgpu_crtc->pll_id) {
836*b843c749SSergey Zigachev case ATOM_PPLL1:
837*b843c749SSergey Zigachev pll = &adev->clock.ppll[0];
838*b843c749SSergey Zigachev break;
839*b843c749SSergey Zigachev case ATOM_PPLL2:
840*b843c749SSergey Zigachev pll = &adev->clock.ppll[1];
841*b843c749SSergey Zigachev break;
842*b843c749SSergey Zigachev case ATOM_PPLL0:
843*b843c749SSergey Zigachev case ATOM_PPLL_INVALID:
844*b843c749SSergey Zigachev default:
845*b843c749SSergey Zigachev pll = &adev->clock.ppll[2];
846*b843c749SSergey Zigachev break;
847*b843c749SSergey Zigachev }
848*b843c749SSergey Zigachev
849*b843c749SSergey Zigachev /* update pll params */
850*b843c749SSergey Zigachev pll->flags = amdgpu_crtc->pll_flags;
851*b843c749SSergey Zigachev pll->reference_div = amdgpu_crtc->pll_reference_div;
852*b843c749SSergey Zigachev pll->post_div = amdgpu_crtc->pll_post_div;
853*b843c749SSergey Zigachev
854*b843c749SSergey Zigachev amdgpu_pll_compute(pll, amdgpu_crtc->adjusted_clock, &pll_clock,
855*b843c749SSergey Zigachev &fb_div, &frac_fb_div, &ref_div, &post_div);
856*b843c749SSergey Zigachev
857*b843c749SSergey Zigachev amdgpu_atombios_crtc_program_ss(adev, ATOM_DISABLE, amdgpu_crtc->pll_id,
858*b843c749SSergey Zigachev amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
859*b843c749SSergey Zigachev
860*b843c749SSergey Zigachev amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
861*b843c749SSergey Zigachev encoder_mode, amdgpu_encoder->encoder_id, clock,
862*b843c749SSergey Zigachev ref_div, fb_div, frac_fb_div, post_div,
863*b843c749SSergey Zigachev amdgpu_crtc->bpc, amdgpu_crtc->ss_enabled, &amdgpu_crtc->ss);
864*b843c749SSergey Zigachev
865*b843c749SSergey Zigachev if (amdgpu_crtc->ss_enabled) {
866*b843c749SSergey Zigachev /* calculate ss amount and step size */
867*b843c749SSergey Zigachev u32 step_size;
868*b843c749SSergey Zigachev u32 amount = (((fb_div * 10) + frac_fb_div) *
869*b843c749SSergey Zigachev (u32)amdgpu_crtc->ss.percentage) /
870*b843c749SSergey Zigachev (100 * (u32)amdgpu_crtc->ss.percentage_divider);
871*b843c749SSergey Zigachev amdgpu_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
872*b843c749SSergey Zigachev amdgpu_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
873*b843c749SSergey Zigachev ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
874*b843c749SSergey Zigachev if (amdgpu_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
875*b843c749SSergey Zigachev step_size = (4 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
876*b843c749SSergey Zigachev (125 * 25 * pll->reference_freq / 100);
877*b843c749SSergey Zigachev else
878*b843c749SSergey Zigachev step_size = (2 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
879*b843c749SSergey Zigachev (125 * 25 * pll->reference_freq / 100);
880*b843c749SSergey Zigachev amdgpu_crtc->ss.step = step_size;
881*b843c749SSergey Zigachev
882*b843c749SSergey Zigachev amdgpu_atombios_crtc_program_ss(adev, ATOM_ENABLE, amdgpu_crtc->pll_id,
883*b843c749SSergey Zigachev amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
884*b843c749SSergey Zigachev }
885*b843c749SSergey Zigachev }
886*b843c749SSergey Zigachev
887