Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2007-8 Advanced Micro Devices, Inc.
0003  * Copyright 2008 Red Hat Inc.
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining a
0006  * copy of this software and associated documentation files (the "Software"),
0007  * to deal in the Software without restriction, including without limitation
0008  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0009  * and/or sell copies of the Software, and to permit persons to whom the
0010  * Software is furnished to do so, subject to the following conditions:
0011  *
0012  * The above copyright notice and this permission notice shall be included in
0013  * all copies or substantial portions of the Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0019  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0020  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0021  * OTHER DEALINGS IN THE SOFTWARE.
0022  *
0023  * Authors: Dave Airlie
0024  *          Alex Deucher
0025  */
0026 
0027 #include <drm/drm_crtc_helper.h>
0028 #include <drm/amdgpu_drm.h>
0029 #include <drm/drm_fixed.h>
0030 #include "amdgpu.h"
0031 #include "atom.h"
0032 #include "atom-bits.h"
0033 #include "atombios_encoders.h"
0034 #include "atombios_crtc.h"
0035 #include "amdgpu_atombios.h"
0036 #include "amdgpu_pll.h"
0037 #include "amdgpu_connectors.h"
0038 
0039 void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc,
0040                   struct drm_display_mode *mode,
0041                   struct drm_display_mode *adjusted_mode)
0042 {
0043     struct drm_device *dev = crtc->dev;
0044     struct amdgpu_device *adev = drm_to_adev(dev);
0045     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0046     SET_CRTC_OVERSCAN_PS_ALLOCATION args;
0047     int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
0048     int a1, a2;
0049 
0050     memset(&args, 0, sizeof(args));
0051 
0052     args.ucCRTC = amdgpu_crtc->crtc_id;
0053 
0054     switch (amdgpu_crtc->rmx_type) {
0055     case RMX_CENTER:
0056         args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
0057         args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
0058         args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
0059         args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
0060         break;
0061     case RMX_ASPECT:
0062         a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
0063         a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
0064 
0065         if (a1 > a2) {
0066             args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
0067             args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
0068         } else if (a2 > a1) {
0069             args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
0070             args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
0071         }
0072         break;
0073     case RMX_FULL:
0074     default:
0075         args.usOverscanRight = cpu_to_le16(amdgpu_crtc->h_border);
0076         args.usOverscanLeft = cpu_to_le16(amdgpu_crtc->h_border);
0077         args.usOverscanBottom = cpu_to_le16(amdgpu_crtc->v_border);
0078         args.usOverscanTop = cpu_to_le16(amdgpu_crtc->v_border);
0079         break;
0080     }
0081     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0082 }
0083 
0084 void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc)
0085 {
0086     struct drm_device *dev = crtc->dev;
0087     struct amdgpu_device *adev = drm_to_adev(dev);
0088     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0089     ENABLE_SCALER_PS_ALLOCATION args;
0090     int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
0091 
0092     memset(&args, 0, sizeof(args));
0093 
0094     args.ucScaler = amdgpu_crtc->crtc_id;
0095 
0096     switch (amdgpu_crtc->rmx_type) {
0097     case RMX_FULL:
0098         args.ucEnable = ATOM_SCALER_EXPANSION;
0099         break;
0100     case RMX_CENTER:
0101         args.ucEnable = ATOM_SCALER_CENTER;
0102         break;
0103     case RMX_ASPECT:
0104         args.ucEnable = ATOM_SCALER_EXPANSION;
0105         break;
0106     default:
0107         args.ucEnable = ATOM_SCALER_DISABLE;
0108         break;
0109     }
0110     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0111 }
0112 
0113 void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock)
0114 {
0115     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0116     struct drm_device *dev = crtc->dev;
0117     struct amdgpu_device *adev = drm_to_adev(dev);
0118     int index =
0119         GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
0120     ENABLE_CRTC_PS_ALLOCATION args;
0121 
0122     memset(&args, 0, sizeof(args));
0123 
0124     args.ucCRTC = amdgpu_crtc->crtc_id;
0125     args.ucEnable = lock;
0126 
0127     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0128 }
0129 
0130 void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state)
0131 {
0132     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0133     struct drm_device *dev = crtc->dev;
0134     struct amdgpu_device *adev = drm_to_adev(dev);
0135     int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
0136     ENABLE_CRTC_PS_ALLOCATION args;
0137 
0138     memset(&args, 0, sizeof(args));
0139 
0140     args.ucCRTC = amdgpu_crtc->crtc_id;
0141     args.ucEnable = state;
0142 
0143     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0144 }
0145 
0146 void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state)
0147 {
0148     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0149     struct drm_device *dev = crtc->dev;
0150     struct amdgpu_device *adev = drm_to_adev(dev);
0151     int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
0152     BLANK_CRTC_PS_ALLOCATION args;
0153 
0154     memset(&args, 0, sizeof(args));
0155 
0156     args.ucCRTC = amdgpu_crtc->crtc_id;
0157     args.ucBlanking = state;
0158 
0159     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0160 }
0161 
0162 void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state)
0163 {
0164     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0165     struct drm_device *dev = crtc->dev;
0166     struct amdgpu_device *adev = drm_to_adev(dev);
0167     int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
0168     ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
0169 
0170     memset(&args, 0, sizeof(args));
0171 
0172     args.ucDispPipeId = amdgpu_crtc->crtc_id;
0173     args.ucEnable = state;
0174 
0175     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0176 }
0177 
0178 void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev)
0179 {
0180     int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
0181     ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
0182 
0183     memset(&args, 0, sizeof(args));
0184 
0185     args.ucEnable = ATOM_INIT;
0186 
0187     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0188 }
0189 
0190 void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc,
0191                   struct drm_display_mode *mode)
0192 {
0193     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0194     struct drm_device *dev = crtc->dev;
0195     struct amdgpu_device *adev = drm_to_adev(dev);
0196     SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
0197     int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
0198     u16 misc = 0;
0199 
0200     memset(&args, 0, sizeof(args));
0201     args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (amdgpu_crtc->h_border * 2));
0202     args.usH_Blanking_Time =
0203         cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (amdgpu_crtc->h_border * 2));
0204     args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (amdgpu_crtc->v_border * 2));
0205     args.usV_Blanking_Time =
0206         cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (amdgpu_crtc->v_border * 2));
0207     args.usH_SyncOffset =
0208         cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + amdgpu_crtc->h_border);
0209     args.usH_SyncWidth =
0210         cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
0211     args.usV_SyncOffset =
0212         cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + amdgpu_crtc->v_border);
0213     args.usV_SyncWidth =
0214         cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
0215     args.ucH_Border = amdgpu_crtc->h_border;
0216     args.ucV_Border = amdgpu_crtc->v_border;
0217 
0218     if (mode->flags & DRM_MODE_FLAG_NVSYNC)
0219         misc |= ATOM_VSYNC_POLARITY;
0220     if (mode->flags & DRM_MODE_FLAG_NHSYNC)
0221         misc |= ATOM_HSYNC_POLARITY;
0222     if (mode->flags & DRM_MODE_FLAG_CSYNC)
0223         misc |= ATOM_COMPOSITESYNC;
0224     if (mode->flags & DRM_MODE_FLAG_INTERLACE)
0225         misc |= ATOM_INTERLACE;
0226     if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
0227         misc |= ATOM_DOUBLE_CLOCK_MODE;
0228 
0229     args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
0230     args.ucCRTC = amdgpu_crtc->crtc_id;
0231 
0232     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0233 }
0234 
0235 union atom_enable_ss {
0236     ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
0237     ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
0238     ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
0239 };
0240 
0241 static void amdgpu_atombios_crtc_program_ss(struct amdgpu_device *adev,
0242                      int enable,
0243                      int pll_id,
0244                      int crtc_id,
0245                      struct amdgpu_atom_ss *ss)
0246 {
0247     unsigned i;
0248     int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
0249     union atom_enable_ss args;
0250 
0251     if (enable) {
0252         /* Don't mess with SS if percentage is 0 or external ss.
0253          * SS is already disabled previously, and disabling it
0254          * again can cause display problems if the pll is already
0255          * programmed.
0256          */
0257         if (ss->percentage == 0)
0258             return;
0259         if (ss->type & ATOM_EXTERNAL_SS_MASK)
0260             return;
0261     } else {
0262         for (i = 0; i < adev->mode_info.num_crtc; i++) {
0263             if (adev->mode_info.crtcs[i] &&
0264                 adev->mode_info.crtcs[i]->enabled &&
0265                 i != crtc_id &&
0266                 pll_id == adev->mode_info.crtcs[i]->pll_id) {
0267                 /* one other crtc is using this pll don't turn
0268                  * off spread spectrum as it might turn off
0269                  * display on active crtc
0270                  */
0271                 return;
0272             }
0273         }
0274     }
0275 
0276     memset(&args, 0, sizeof(args));
0277 
0278     args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
0279     args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
0280     switch (pll_id) {
0281     case ATOM_PPLL1:
0282         args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
0283         break;
0284     case ATOM_PPLL2:
0285         args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
0286         break;
0287     case ATOM_DCPLL:
0288         args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
0289         break;
0290     case ATOM_PPLL_INVALID:
0291         return;
0292     }
0293     args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
0294     args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
0295     args.v3.ucEnable = enable;
0296 
0297     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0298 }
0299 
0300 union adjust_pixel_clock {
0301     ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
0302     ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
0303 };
0304 
0305 static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
0306                     struct drm_display_mode *mode)
0307 {
0308     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0309     struct drm_device *dev = crtc->dev;
0310     struct amdgpu_device *adev = drm_to_adev(dev);
0311     struct drm_encoder *encoder = amdgpu_crtc->encoder;
0312     struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
0313     struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
0314     u32 adjusted_clock = mode->clock;
0315     int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
0316     u32 dp_clock = mode->clock;
0317     u32 clock = mode->clock;
0318     int bpc = amdgpu_crtc->bpc;
0319     bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, mode->clock);
0320     union adjust_pixel_clock args;
0321     u8 frev, crev;
0322     int index;
0323 
0324     amdgpu_crtc->pll_flags = AMDGPU_PLL_USE_FRAC_FB_DIV;
0325 
0326     if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
0327         (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
0328         if (connector) {
0329             struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
0330             struct amdgpu_connector_atom_dig *dig_connector =
0331                 amdgpu_connector->con_priv;
0332 
0333             dp_clock = dig_connector->dp_clock;
0334         }
0335     }
0336 
0337     /* use recommended ref_div for ss */
0338     if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
0339         if (amdgpu_crtc->ss_enabled) {
0340             if (amdgpu_crtc->ss.refdiv) {
0341                 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
0342                 amdgpu_crtc->pll_reference_div = amdgpu_crtc->ss.refdiv;
0343                 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
0344             }
0345         }
0346     }
0347 
0348     /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
0349     if (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
0350         adjusted_clock = mode->clock * 2;
0351     if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
0352         amdgpu_crtc->pll_flags |= AMDGPU_PLL_PREFER_CLOSEST_LOWER;
0353     if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
0354         amdgpu_crtc->pll_flags |= AMDGPU_PLL_IS_LCD;
0355 
0356 
0357     /* adjust pll for deep color modes */
0358     if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
0359         switch (bpc) {
0360         case 8:
0361         default:
0362             break;
0363         case 10:
0364             clock = (clock * 5) / 4;
0365             break;
0366         case 12:
0367             clock = (clock * 3) / 2;
0368             break;
0369         case 16:
0370             clock = clock * 2;
0371             break;
0372         }
0373     }
0374 
0375     /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
0376      * accordingly based on the encoder/transmitter to work around
0377      * special hw requirements.
0378      */
0379     index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
0380     if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
0381                    &crev))
0382         return adjusted_clock;
0383 
0384     memset(&args, 0, sizeof(args));
0385 
0386     switch (frev) {
0387     case 1:
0388         switch (crev) {
0389         case 1:
0390         case 2:
0391             args.v1.usPixelClock = cpu_to_le16(clock / 10);
0392             args.v1.ucTransmitterID = amdgpu_encoder->encoder_id;
0393             args.v1.ucEncodeMode = encoder_mode;
0394             if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
0395                 args.v1.ucConfig |=
0396                     ADJUST_DISPLAY_CONFIG_SS_ENABLE;
0397 
0398             amdgpu_atom_execute_table(adev->mode_info.atom_context,
0399                        index, (uint32_t *)&args);
0400             adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
0401             break;
0402         case 3:
0403             args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
0404             args.v3.sInput.ucTransmitterID = amdgpu_encoder->encoder_id;
0405             args.v3.sInput.ucEncodeMode = encoder_mode;
0406             args.v3.sInput.ucDispPllConfig = 0;
0407             if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
0408                 args.v3.sInput.ucDispPllConfig |=
0409                     DISPPLL_CONFIG_SS_ENABLE;
0410             if (ENCODER_MODE_IS_DP(encoder_mode)) {
0411                 args.v3.sInput.ucDispPllConfig |=
0412                     DISPPLL_CONFIG_COHERENT_MODE;
0413                 /* 16200 or 27000 */
0414                 args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
0415             } else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
0416                 struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
0417                 if (dig->coherent_mode)
0418                     args.v3.sInput.ucDispPllConfig |=
0419                         DISPPLL_CONFIG_COHERENT_MODE;
0420                 if (is_duallink)
0421                     args.v3.sInput.ucDispPllConfig |=
0422                         DISPPLL_CONFIG_DUAL_LINK;
0423             }
0424             if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) !=
0425                 ENCODER_OBJECT_ID_NONE)
0426                 args.v3.sInput.ucExtTransmitterID =
0427                     amdgpu_encoder_get_dp_bridge_encoder_id(encoder);
0428             else
0429                 args.v3.sInput.ucExtTransmitterID = 0;
0430 
0431             amdgpu_atom_execute_table(adev->mode_info.atom_context,
0432                        index, (uint32_t *)&args);
0433             adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
0434             if (args.v3.sOutput.ucRefDiv) {
0435                 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
0436                 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
0437                 amdgpu_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv;
0438             }
0439             if (args.v3.sOutput.ucPostDiv) {
0440                 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
0441                 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_POST_DIV;
0442                 amdgpu_crtc->pll_post_div = args.v3.sOutput.ucPostDiv;
0443             }
0444             break;
0445         default:
0446             DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0447             return adjusted_clock;
0448         }
0449         break;
0450     default:
0451         DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0452         return adjusted_clock;
0453     }
0454 
0455     return adjusted_clock;
0456 }
0457 
0458 union set_pixel_clock {
0459     SET_PIXEL_CLOCK_PS_ALLOCATION base;
0460     PIXEL_CLOCK_PARAMETERS v1;
0461     PIXEL_CLOCK_PARAMETERS_V2 v2;
0462     PIXEL_CLOCK_PARAMETERS_V3 v3;
0463     PIXEL_CLOCK_PARAMETERS_V5 v5;
0464     PIXEL_CLOCK_PARAMETERS_V6 v6;
0465     PIXEL_CLOCK_PARAMETERS_V7 v7;
0466 };
0467 
0468 /* on DCE5, make sure the voltage is high enough to support the
0469  * required disp clk.
0470  */
0471 void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev,
0472                        u32 dispclk)
0473 {
0474     u8 frev, crev;
0475     int index;
0476     union set_pixel_clock args;
0477 
0478     memset(&args, 0, sizeof(args));
0479 
0480     index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
0481     if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
0482                    &crev))
0483         return;
0484 
0485     switch (frev) {
0486     case 1:
0487         switch (crev) {
0488         case 5:
0489             /* if the default dcpll clock is specified,
0490              * SetPixelClock provides the dividers
0491              */
0492             args.v5.ucCRTC = ATOM_CRTC_INVALID;
0493             args.v5.usPixelClock = cpu_to_le16(dispclk);
0494             args.v5.ucPpll = ATOM_DCPLL;
0495             break;
0496         case 6:
0497             /* if the default dcpll clock is specified,
0498              * SetPixelClock provides the dividers
0499              */
0500             args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
0501             if (adev->asic_type == CHIP_TAHITI ||
0502                 adev->asic_type == CHIP_PITCAIRN ||
0503                 adev->asic_type == CHIP_VERDE ||
0504                 adev->asic_type == CHIP_OLAND)
0505                 args.v6.ucPpll = ATOM_PPLL0;
0506             else
0507                 args.v6.ucPpll = ATOM_EXT_PLL1;
0508             break;
0509         default:
0510             DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0511             return;
0512         }
0513         break;
0514     default:
0515         DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0516         return;
0517     }
0518     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0519 }
0520 
0521 union set_dce_clock {
0522     SET_DCE_CLOCK_PS_ALLOCATION_V1_1 v1_1;
0523     SET_DCE_CLOCK_PS_ALLOCATION_V2_1 v2_1;
0524 };
0525 
0526 u32 amdgpu_atombios_crtc_set_dce_clock(struct amdgpu_device *adev,
0527                        u32 freq, u8 clk_type, u8 clk_src)
0528 {
0529     u8 frev, crev;
0530     int index;
0531     union set_dce_clock args;
0532     u32 ret_freq = 0;
0533 
0534     memset(&args, 0, sizeof(args));
0535 
0536     index = GetIndexIntoMasterTable(COMMAND, SetDCEClock);
0537     if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
0538                    &crev))
0539         return 0;
0540 
0541     switch (frev) {
0542     case 2:
0543         switch (crev) {
0544         case 1:
0545             args.v2_1.asParam.ulDCEClkFreq = cpu_to_le32(freq); /* 10kHz units */
0546             args.v2_1.asParam.ucDCEClkType = clk_type;
0547             args.v2_1.asParam.ucDCEClkSrc = clk_src;
0548             amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0549             ret_freq = le32_to_cpu(args.v2_1.asParam.ulDCEClkFreq) * 10;
0550             break;
0551         default:
0552             DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0553             return 0;
0554         }
0555         break;
0556     default:
0557         DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0558         return 0;
0559     }
0560 
0561     return ret_freq;
0562 }
0563 
0564 static bool is_pixel_clock_source_from_pll(u32 encoder_mode, int pll_id)
0565 {
0566     if (ENCODER_MODE_IS_DP(encoder_mode)) {
0567         if (pll_id < ATOM_EXT_PLL1)
0568             return true;
0569         else
0570             return false;
0571     } else {
0572         return true;
0573     }
0574 }
0575 
0576 void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc,
0577                       u32 crtc_id,
0578                       int pll_id,
0579                       u32 encoder_mode,
0580                       u32 encoder_id,
0581                       u32 clock,
0582                       u32 ref_div,
0583                       u32 fb_div,
0584                       u32 frac_fb_div,
0585                       u32 post_div,
0586                       int bpc,
0587                       bool ss_enabled,
0588                       struct amdgpu_atom_ss *ss)
0589 {
0590     struct drm_device *dev = crtc->dev;
0591     struct amdgpu_device *adev = drm_to_adev(dev);
0592     u8 frev, crev;
0593     int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
0594     union set_pixel_clock args;
0595 
0596     memset(&args, 0, sizeof(args));
0597 
0598     if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
0599                    &crev))
0600         return;
0601 
0602     switch (frev) {
0603     case 1:
0604         switch (crev) {
0605         case 1:
0606             if (clock == ATOM_DISABLE)
0607                 return;
0608             args.v1.usPixelClock = cpu_to_le16(clock / 10);
0609             args.v1.usRefDiv = cpu_to_le16(ref_div);
0610             args.v1.usFbDiv = cpu_to_le16(fb_div);
0611             args.v1.ucFracFbDiv = frac_fb_div;
0612             args.v1.ucPostDiv = post_div;
0613             args.v1.ucPpll = pll_id;
0614             args.v1.ucCRTC = crtc_id;
0615             args.v1.ucRefDivSrc = 1;
0616             break;
0617         case 2:
0618             args.v2.usPixelClock = cpu_to_le16(clock / 10);
0619             args.v2.usRefDiv = cpu_to_le16(ref_div);
0620             args.v2.usFbDiv = cpu_to_le16(fb_div);
0621             args.v2.ucFracFbDiv = frac_fb_div;
0622             args.v2.ucPostDiv = post_div;
0623             args.v2.ucPpll = pll_id;
0624             args.v2.ucCRTC = crtc_id;
0625             args.v2.ucRefDivSrc = 1;
0626             break;
0627         case 3:
0628             args.v3.usPixelClock = cpu_to_le16(clock / 10);
0629             args.v3.usRefDiv = cpu_to_le16(ref_div);
0630             args.v3.usFbDiv = cpu_to_le16(fb_div);
0631             args.v3.ucFracFbDiv = frac_fb_div;
0632             args.v3.ucPostDiv = post_div;
0633             args.v3.ucPpll = pll_id;
0634             if (crtc_id == ATOM_CRTC2)
0635                 args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
0636             else
0637                 args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1;
0638             if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
0639                 args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
0640             args.v3.ucTransmitterId = encoder_id;
0641             args.v3.ucEncoderMode = encoder_mode;
0642             break;
0643         case 5:
0644             args.v5.ucCRTC = crtc_id;
0645             args.v5.usPixelClock = cpu_to_le16(clock / 10);
0646             args.v5.ucRefDiv = ref_div;
0647             args.v5.usFbDiv = cpu_to_le16(fb_div);
0648             args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
0649             args.v5.ucPostDiv = post_div;
0650             args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
0651             if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
0652                 (pll_id < ATOM_EXT_PLL1))
0653                 args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
0654             if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
0655                 switch (bpc) {
0656                 case 8:
0657                 default:
0658                     args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
0659                     break;
0660                 case 10:
0661                     /* yes this is correct, the atom define is wrong */
0662                     args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
0663                     break;
0664                 case 12:
0665                     /* yes this is correct, the atom define is wrong */
0666                     args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
0667                     break;
0668                 }
0669             }
0670             args.v5.ucTransmitterID = encoder_id;
0671             args.v5.ucEncoderMode = encoder_mode;
0672             args.v5.ucPpll = pll_id;
0673             break;
0674         case 6:
0675             args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10);
0676             args.v6.ucRefDiv = ref_div;
0677             args.v6.usFbDiv = cpu_to_le16(fb_div);
0678             args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
0679             args.v6.ucPostDiv = post_div;
0680             args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
0681             if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
0682                 (pll_id < ATOM_EXT_PLL1) &&
0683                 !is_pixel_clock_source_from_pll(encoder_mode, pll_id))
0684                 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
0685             if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
0686                 switch (bpc) {
0687                 case 8:
0688                 default:
0689                     args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
0690                     break;
0691                 case 10:
0692                     args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
0693                     break;
0694                 case 12:
0695                     args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
0696                     break;
0697                 case 16:
0698                     args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
0699                     break;
0700                 }
0701             }
0702             args.v6.ucTransmitterID = encoder_id;
0703             args.v6.ucEncoderMode = encoder_mode;
0704             args.v6.ucPpll = pll_id;
0705             break;
0706         case 7:
0707             args.v7.ulPixelClock = cpu_to_le32(clock * 10); /* 100 hz units */
0708             args.v7.ucMiscInfo = 0;
0709             if ((encoder_mode == ATOM_ENCODER_MODE_DVI) &&
0710                 (clock > 165000))
0711                 args.v7.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN;
0712             args.v7.ucCRTC = crtc_id;
0713             if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
0714                 switch (bpc) {
0715                 case 8:
0716                 default:
0717                     args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS;
0718                     break;
0719                 case 10:
0720                     args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4;
0721                     break;
0722                 case 12:
0723                     args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2;
0724                     break;
0725                 case 16:
0726                     args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1;
0727                     break;
0728                 }
0729             }
0730             args.v7.ucTransmitterID = encoder_id;
0731             args.v7.ucEncoderMode = encoder_mode;
0732             args.v7.ucPpll = pll_id;
0733             break;
0734         default:
0735             DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0736             return;
0737         }
0738         break;
0739     default:
0740         DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0741         return;
0742     }
0743 
0744     amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0745 }
0746 
0747 int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
0748                   struct drm_display_mode *mode)
0749 {
0750     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0751     struct drm_device *dev = crtc->dev;
0752     struct amdgpu_device *adev = drm_to_adev(dev);
0753     struct amdgpu_encoder *amdgpu_encoder =
0754         to_amdgpu_encoder(amdgpu_crtc->encoder);
0755     int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
0756 
0757     amdgpu_crtc->bpc = 8;
0758     amdgpu_crtc->ss_enabled = false;
0759 
0760     if ((amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
0761         (amdgpu_encoder_get_dp_bridge_encoder_id(amdgpu_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
0762         struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
0763         struct drm_connector *connector =
0764             amdgpu_get_connector_for_encoder(amdgpu_crtc->encoder);
0765         struct amdgpu_connector *amdgpu_connector =
0766             to_amdgpu_connector(connector);
0767         struct amdgpu_connector_atom_dig *dig_connector =
0768             amdgpu_connector->con_priv;
0769         int dp_clock;
0770 
0771         /* Assign mode clock for hdmi deep color max clock limit check */
0772         amdgpu_connector->pixelclock_for_modeset = mode->clock;
0773         amdgpu_crtc->bpc = amdgpu_connector_get_monitor_bpc(connector);
0774 
0775         switch (encoder_mode) {
0776         case ATOM_ENCODER_MODE_DP_MST:
0777         case ATOM_ENCODER_MODE_DP:
0778             /* DP/eDP */
0779             dp_clock = dig_connector->dp_clock / 10;
0780             amdgpu_crtc->ss_enabled =
0781                 amdgpu_atombios_get_asic_ss_info(adev, &amdgpu_crtc->ss,
0782                                  ASIC_INTERNAL_SS_ON_DP,
0783                                  dp_clock);
0784             break;
0785         case ATOM_ENCODER_MODE_LVDS:
0786             amdgpu_crtc->ss_enabled =
0787                 amdgpu_atombios_get_asic_ss_info(adev,
0788                                  &amdgpu_crtc->ss,
0789                                  dig->lcd_ss_id,
0790                                  mode->clock / 10);
0791             break;
0792         case ATOM_ENCODER_MODE_DVI:
0793             amdgpu_crtc->ss_enabled =
0794                 amdgpu_atombios_get_asic_ss_info(adev,
0795                                  &amdgpu_crtc->ss,
0796                                  ASIC_INTERNAL_SS_ON_TMDS,
0797                                  mode->clock / 10);
0798             break;
0799         case ATOM_ENCODER_MODE_HDMI:
0800             amdgpu_crtc->ss_enabled =
0801                 amdgpu_atombios_get_asic_ss_info(adev,
0802                                  &amdgpu_crtc->ss,
0803                                  ASIC_INTERNAL_SS_ON_HDMI,
0804                                  mode->clock / 10);
0805             break;
0806         default:
0807             break;
0808         }
0809     }
0810 
0811     /* adjust pixel clock as needed */
0812     amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, mode);
0813 
0814     return 0;
0815 }
0816 
0817 void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
0818 {
0819     struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0820     struct drm_device *dev = crtc->dev;
0821     struct amdgpu_device *adev = drm_to_adev(dev);
0822     struct amdgpu_encoder *amdgpu_encoder =
0823         to_amdgpu_encoder(amdgpu_crtc->encoder);
0824     u32 pll_clock = mode->clock;
0825     u32 clock = mode->clock;
0826     u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
0827     struct amdgpu_pll *pll;
0828     int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
0829 
0830     /* pass the actual clock to amdgpu_atombios_crtc_program_pll for HDMI */
0831     if ((encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
0832         (amdgpu_crtc->bpc > 8))
0833         clock = amdgpu_crtc->adjusted_clock;
0834 
0835     switch (amdgpu_crtc->pll_id) {
0836     case ATOM_PPLL1:
0837         pll = &adev->clock.ppll[0];
0838         break;
0839     case ATOM_PPLL2:
0840         pll = &adev->clock.ppll[1];
0841         break;
0842     case ATOM_PPLL0:
0843     case ATOM_PPLL_INVALID:
0844     default:
0845         pll = &adev->clock.ppll[2];
0846         break;
0847     }
0848 
0849     /* update pll params */
0850     pll->flags = amdgpu_crtc->pll_flags;
0851     pll->reference_div = amdgpu_crtc->pll_reference_div;
0852     pll->post_div = amdgpu_crtc->pll_post_div;
0853 
0854     amdgpu_pll_compute(adev, pll, amdgpu_crtc->adjusted_clock, &pll_clock,
0855                 &fb_div, &frac_fb_div, &ref_div, &post_div);
0856 
0857     amdgpu_atombios_crtc_program_ss(adev, ATOM_DISABLE, amdgpu_crtc->pll_id,
0858                  amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
0859 
0860     amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
0861                   encoder_mode, amdgpu_encoder->encoder_id, clock,
0862                   ref_div, fb_div, frac_fb_div, post_div,
0863                   amdgpu_crtc->bpc, amdgpu_crtc->ss_enabled, &amdgpu_crtc->ss);
0864 
0865     if (amdgpu_crtc->ss_enabled) {
0866         /* calculate ss amount and step size */
0867         u32 step_size;
0868         u32 amount = (((fb_div * 10) + frac_fb_div) *
0869                   (u32)amdgpu_crtc->ss.percentage) /
0870             (100 * (u32)amdgpu_crtc->ss.percentage_divider);
0871         amdgpu_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
0872         amdgpu_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
0873             ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
0874         if (amdgpu_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
0875             step_size = (4 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
0876                 (125 * 25 * pll->reference_freq / 100);
0877         else
0878             step_size = (2 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
0879                 (125 * 25 * pll->reference_freq / 100);
0880         amdgpu_crtc->ss.step = step_size;
0881 
0882         amdgpu_atombios_crtc_program_ss(adev, ATOM_ENABLE, amdgpu_crtc->pll_id,
0883                      amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
0884     }
0885 }
0886