| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 1 | -- |
| Nico Huber | abb16d9 | 2018-05-29 01:44:26 +0200 | [diff] [blame] | 2 | -- Copyright (C) 2015-2018 secunet Security Networks AG |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 3 | -- |
| 4 | -- This program is free software; you can redistribute it and/or modify |
| 5 | -- it under the terms of the GNU General Public License as published by |
| 6 | -- the Free Software Foundation; either version 2 of the License, or |
| 7 | -- (at your option) any later version. |
| 8 | -- |
| 9 | -- This program is distributed in the hope that it will be useful, |
| 10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | -- GNU General Public License for more details. |
| 13 | -- |
| 14 | |
| 15 | with HW.Debug; |
| 16 | with GNAT.Source_Info; |
| 17 | |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 18 | with HW.GFX.GMA.DP_Info; |
| 19 | |
| 20 | package body HW.GFX.GMA.Transcoder is |
| 21 | |
| 22 | type Default_Transcoder_Array is array (Pipe_Index) of Transcoder_Index; |
| 23 | Default_Transcoder : constant Default_Transcoder_Array := |
| 24 | (Primary => Trans_A, |
| 25 | Secondary => Trans_B, |
| 26 | Tertiary => Trans_C); |
| 27 | |
| 28 | function Get_Idx (Pipe : Pipe_Index; Port : GPU_Port) return Transcoder_Index |
| 29 | is |
| 30 | begin |
| 31 | return |
| 32 | (if Config.Has_EDP_Transcoder and then Port = DIGI_A then |
| 33 | Trans_EDP |
| 34 | else |
| 35 | Default_Transcoder (Pipe)); |
| 36 | end Get_Idx; |
| 37 | |
| 38 | ---------------------------------------------------------------------------- |
| 39 | |
| 40 | TRANS_CLK_SEL_PORT_NONE : constant := 0 * 2 ** 29; |
| 41 | |
| 42 | type TRANS_CLK_SEL_PORT_Array is |
| 43 | array (Digital_Port) of Word32; |
| 44 | TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array := |
| 45 | (DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable |
| 46 | DIGI_B => 2 * 2 ** 29, |
| 47 | DIGI_C => 3 * 2 ** 29, |
| 48 | DIGI_D => 4 * 2 ** 29, |
| 49 | DIGI_E => 5 * 2 ** 29); |
| 50 | |
| 51 | TRANS_CONF_ENABLE : constant := 1 * 2 ** 31; |
| 52 | TRANS_CONF_ENABLED_STATUS : constant := 1 * 2 ** 30; |
| 53 | TRANS_CONF_ENABLE_DITHER : constant := 1 * 2 ** 4; |
| 54 | |
| 55 | type BPC_Array is array (BPC_Type) of Word32; |
| 56 | TRANS_CONF_BPC : constant BPC_Array := |
| 57 | (6 => 2 * 2 ** 5, |
| 58 | 8 => 0 * 2 ** 5, |
| 59 | 10 => 1 * 2 ** 5, |
| 60 | 12 => 3 * 2 ** 5, |
| 61 | others => 0 * 2 ** 5); -- default to 8 BPC |
| 62 | |
| 63 | function BPC_Conf (BPC : BPC_Type; Dither : Boolean) return Word32 is |
| 64 | begin |
| 65 | return |
| 66 | (if Config.Has_Pipeconf_BPC then TRANS_CONF_BPC (BPC) else 0) or |
| 67 | (if Dither then TRANS_CONF_ENABLE_DITHER else 0); |
| 68 | end BPC_Conf; |
| 69 | |
| 70 | ---------------------------------------------------------------------------- |
| 71 | |
| 72 | DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31; |
| 73 | DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24; |
| 74 | DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24; |
| 75 | DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24; |
| 76 | DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24; |
| 77 | DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24; |
| 78 | DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24; |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 79 | |
| 80 | type DDI_Select_Array is array (Digital_Port) of Word32; |
| 81 | DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array := |
| 82 | (DIGI_A => 0 * 2 ** 28, |
| 83 | DIGI_B => 1 * 2 ** 28, |
| 84 | DIGI_C => 2 * 2 ** 28, |
| 85 | DIGI_D => 3 * 2 ** 28, |
| 86 | DIGI_E => 4 * 2 ** 28); |
| 87 | |
| 88 | type DDI_Mode_Array is array (Display_Type) of Word32; |
| 89 | DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array := |
| 90 | (VGA => DDI_FUNC_CTL_MODE_SELECT_FDI, |
| 91 | HDMI => DDI_FUNC_CTL_MODE_SELECT_DVI, |
| 92 | DP => DDI_FUNC_CTL_MODE_SELECT_DP_SST, |
| 93 | others => 0); |
| 94 | |
| 95 | type HV_Sync_Array is array (Boolean) of Word32; |
| 96 | DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array := |
| 97 | (False => 0 * 2 ** 17, |
| 98 | True => 1 * 2 ** 17); |
| 99 | DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array := |
| 100 | (False => 0 * 2 ** 16, |
| 101 | True => 1 * 2 ** 16); |
| 102 | |
| Nico Huber | abb16d9 | 2018-05-29 01:44:26 +0200 | [diff] [blame] | 103 | DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12; |
| 104 | DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12; |
| 105 | DDI_FUNC_CTL_EDP_SELECT : constant array (Pipe_Index) of Word32 := |
| 106 | (Primary => 4 * 2 ** 12, |
| 107 | Secondary => 5 * 2 ** 12, |
| 108 | Tertiary => 6 * 2 ** 12); |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 109 | |
| 110 | type Port_Width_Array is array (DP_Lane_Count) of Word32; |
| 111 | DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array := |
| 112 | (DP_Lane_Count_1 => 0 * 2 ** 1, |
| 113 | DP_Lane_Count_2 => 1 * 2 ** 1, |
| 114 | DP_Lane_Count_4 => 3 * 2 ** 1); |
| 115 | |
| 116 | DDI_FUNC_CTL_BPC : constant BPC_Array := |
| 117 | (6 => 2 * 2 ** 20, |
| 118 | 8 => 0 * 2 ** 20, |
| 119 | 10 => 1 * 2 ** 20, |
| 120 | 12 => 3 * 2 ** 20, |
| 121 | others => 0 * 2 ** 20); -- default to 8 BPC |
| 122 | |
| 123 | ---------------------------------------------------------------------------- |
| 124 | |
| 125 | TRANS_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0; |
| 126 | TRANS_MSA_MISC_BPC : constant BPC_Array := |
| 127 | (6 => 0 * 2 ** 5, |
| 128 | 8 => 1 * 2 ** 5, |
| 129 | 10 => 2 * 2 ** 5, |
| 130 | 12 => 3 * 2 ** 5, |
| 131 | 16 => 4 * 2 ** 5, |
| 132 | others => 1 * 2 ** 5); -- default to 8 BPC |
| 133 | |
| 134 | function TRANS_DATA_M_TU (Transfer_Unit : Positive) return Word32 is |
| 135 | begin |
| 136 | return Shift_Left (Word32 (Transfer_Unit - 1), 25); |
| 137 | end TRANS_DATA_M_TU; |
| 138 | |
| 139 | ---------------------------------------------------------------------------- |
| 140 | |
| Nico Huber | c5c767a | 2018-06-03 01:09:04 +0200 | [diff] [blame] | 141 | function Encode (LSW, MSW : Pos32) return Word32 is |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 142 | begin |
| 143 | return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1); |
| 144 | end Encode; |
| 145 | |
| 146 | ---------------------------------------------------------------------------- |
| 147 | |
| 148 | procedure Setup_Link |
| 149 | (Trans : Transcoder_Regs; |
| 150 | Link : DP_Link; |
| 151 | Mode : Mode_Type) |
| 152 | with |
| 153 | Global => (In_Out => Registers.Register_State), |
| 154 | Depends => (Registers.Register_State =>+ (Trans, Link, Mode)) |
| 155 | is |
| 156 | Data_M, Link_M : DP_Info.M_Type; |
| 157 | Data_N, Link_N : DP_Info.N_Type; |
| 158 | begin |
| 159 | pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); |
| 160 | |
| 161 | DP_Info.Calculate_M_N |
| 162 | (Link => Link, |
| 163 | Mode => Mode, |
| 164 | Data_M => Data_M, |
| 165 | Data_N => Data_N, |
| 166 | Link_M => Link_M, |
| 167 | Link_N => Link_N); |
| 168 | |
| 169 | Registers.Write |
| 170 | (Register => Trans.DATA_M1, |
| 171 | Value => TRANS_DATA_M_TU (64) or |
| 172 | Word32 (Data_M)); |
| 173 | Registers.Write |
| 174 | (Register => Trans.DATA_N1, |
| 175 | Value => Word32 (Data_N)); |
| 176 | |
| 177 | Registers.Write |
| 178 | (Register => Trans.LINK_M1, |
| 179 | Value => Word32 (Link_M)); |
| 180 | Registers.Write |
| 181 | (Register => Trans.LINK_N1, |
| 182 | Value => Word32 (Link_N)); |
| 183 | |
| 184 | if Config.Has_Pipe_MSA_Misc then |
| 185 | Registers.Write |
| 186 | (Register => Trans.MSA_MISC, |
| 187 | Value => TRANS_MSA_MISC_SYNC_CLK or |
| 188 | TRANS_MSA_MISC_BPC (Mode.BPC)); |
| 189 | end if; |
| 190 | end Setup_Link; |
| 191 | |
| 192 | ---------------------------------------------------------------------------- |
| 193 | |
| 194 | procedure Setup |
| 195 | (Pipe : Pipe_Index; |
| 196 | Port_Cfg : Port_Config) |
| 197 | is |
| 198 | use type HW.GFX.GMA.Registers.Registers_Invalid_Index; |
| 199 | |
| 200 | Trans : Transcoder_Regs renames |
| 201 | Transcoders (Get_Idx (Pipe, Port_Cfg.Port)); |
| 202 | M : constant Mode_Type := Port_Cfg.Mode; |
| 203 | begin |
| 204 | pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); |
| 205 | |
| 206 | if Config.Has_Trans_Clk_Sel and then |
| Arthur Heymans | 5d08a93 | 2018-03-28 17:00:18 +0200 | [diff] [blame] | 207 | Trans.CLK_SEL /= Registers.Invalid_Register and then |
| 208 | Port_Cfg.Port in Digital_Port |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 209 | then |
| 210 | Registers.Write |
| 211 | (Register => Trans.CLK_SEL, |
| 212 | Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port)); |
| 213 | end if; |
| 214 | |
| 215 | if Port_Cfg.Is_FDI then |
| 216 | Setup_Link (Trans, Port_Cfg.FDI, Port_Cfg.Mode); |
| 217 | elsif Port_Cfg.Display = DP then |
| 218 | Setup_Link (Trans, Port_Cfg.DP, Port_Cfg.Mode); |
| 219 | end if; |
| 220 | |
| 221 | Registers.Write (Trans.HTOTAL, Encode (M.H_Visible, M.H_Total)); |
| 222 | Registers.Write (Trans.HBLANK, Encode (M.H_Visible, M.H_Total)); |
| 223 | Registers.Write (Trans.HSYNC, Encode (M.H_Sync_Begin, M.H_Sync_End)); |
| 224 | Registers.Write (Trans.VTOTAL, Encode (M.V_Visible, M.V_Total)); |
| 225 | Registers.Write (Trans.VBLANK, Encode (M.V_Visible, M.V_Total)); |
| 226 | Registers.Write (Trans.VSYNC, Encode (M.V_Sync_Begin, M.V_Sync_End)); |
| 227 | end Setup; |
| 228 | |
| 229 | ---------------------------------------------------------------------------- |
| 230 | |
| 231 | procedure On |
| 232 | (Pipe : Pipe_Index; |
| 233 | Port_Cfg : Port_Config; |
| Nico Huber | abb16d9 | 2018-05-29 01:44:26 +0200 | [diff] [blame] | 234 | Dither : Boolean; |
| 235 | Scale : Boolean) |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 236 | is |
| 237 | Trans : Transcoder_Regs renames |
| 238 | Transcoders (Get_Idx (Pipe, Port_Cfg.Port)); |
| Nico Huber | abb16d9 | 2018-05-29 01:44:26 +0200 | [diff] [blame] | 239 | EDP_Select : constant Word32 := |
| Nico Huber | a815704 | 2019-07-25 14:05:17 +0200 | [diff] [blame] | 240 | (if Pipe = Primary and |
| 241 | (not Config.Use_PDW_For_EDP_Scaling or else not Scale) |
| 242 | then |
| Nico Huber | abb16d9 | 2018-05-29 01:44:26 +0200 | [diff] [blame] | 243 | DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON |
| 244 | else |
| 245 | DDI_FUNC_CTL_EDP_SELECT (Pipe)); |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 246 | begin |
| Arthur Heymans | 5d08a93 | 2018-03-28 17:00:18 +0200 | [diff] [blame] | 247 | if Config.Has_Pipe_DDI_Func and Port_Cfg.Port in Digital_Port then |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 248 | Registers.Write |
| 249 | (Register => Trans.DDI_FUNC_CTL, |
| 250 | Value => DDI_FUNC_CTL_ENABLE or |
| 251 | DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port) or |
| 252 | DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or |
| 253 | DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or |
| 254 | DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or |
| 255 | DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or |
| Nico Huber | abb16d9 | 2018-05-29 01:44:26 +0200 | [diff] [blame] | 256 | EDP_Select or |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 257 | DDI_FUNC_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count)); |
| 258 | end if; |
| 259 | |
| 260 | Registers.Write |
| 261 | (Register => Trans.CONF, |
| 262 | Value => TRANS_CONF_ENABLE or |
| 263 | (if not Config.Has_Pipeconf_Misc then |
| 264 | BPC_Conf (Port_Cfg.Mode.BPC, Dither) else 0)); |
| 265 | Registers.Posting_Read (Trans.CONF); |
| 266 | end On; |
| 267 | |
| 268 | ---------------------------------------------------------------------------- |
| 269 | |
| 270 | procedure Trans_Off (Trans : Transcoder_Regs) |
| 271 | is |
| 272 | Enabled : Boolean; |
| 273 | begin |
| 274 | Registers.Is_Set_Mask (Trans.CONF, TRANS_CONF_ENABLE, Enabled); |
| 275 | |
| 276 | if Enabled then |
| 277 | Registers.Unset_Mask (Trans.CONF, TRANS_CONF_ENABLE); |
| 278 | end if; |
| 279 | |
| 280 | -- Workaround for Broadwell: |
| 281 | -- Status may be wrong if pipe hasn't been enabled since reset. |
| 282 | if not Config.Pipe_Enabled_Workaround or else Enabled then |
| 283 | -- synchronously wait until pipe is truly off |
| 284 | Registers.Wait_Unset_Mask |
| 285 | (Register => Trans.CONF, |
| 286 | Mask => TRANS_CONF_ENABLED_STATUS, |
| 287 | TOut_MS => 40); |
| 288 | end if; |
| 289 | |
| 290 | if Config.Has_Pipe_DDI_Func then |
| 291 | Registers.Write (Trans.DDI_FUNC_CTL, 0); |
| 292 | end if; |
| 293 | end Trans_Off; |
| 294 | |
| 295 | procedure Off (Pipe : Pipe_Index) |
| 296 | is |
| 297 | DDI_Func_Ctl : Word32; |
| 298 | begin |
| 299 | if Config.Has_EDP_Transcoder then |
| 300 | Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, DDI_Func_Ctl); |
| 301 | DDI_Func_Ctl := DDI_Func_Ctl and DDI_FUNC_CTL_EDP_SELECT_MASK; |
| 302 | |
| 303 | if (Pipe = Primary and |
| 304 | DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or |
| Nico Huber | abb16d9 | 2018-05-29 01:44:26 +0200 | [diff] [blame] | 305 | DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT (Pipe) |
| Nico Huber | 7ad2d65 | 2016-12-07 15:19:32 +0100 | [diff] [blame] | 306 | then |
| 307 | Trans_Off (Transcoders (Trans_EDP)); |
| 308 | end if; |
| 309 | end if; |
| 310 | |
| 311 | Trans_Off (Transcoders (Default_Transcoder (Pipe))); |
| 312 | end Off; |
| 313 | |
| 314 | procedure Clk_Off (Pipe : Pipe_Index) |
| 315 | is |
| 316 | use type Registers.Registers_Invalid_Index; |
| 317 | |
| 318 | Trans : Transcoder_Regs renames Transcoders (Default_Transcoder (Pipe)); |
| 319 | begin |
| 320 | if Config.Has_Trans_Clk_Sel and then |
| 321 | Trans.CLK_SEL /= Registers.Invalid_Register |
| 322 | then |
| 323 | Registers.Write (Trans.CLK_SEL, TRANS_CLK_SEL_PORT_NONE); |
| 324 | end if; |
| 325 | end Clk_Off; |
| 326 | |
| 327 | end HW.GFX.GMA.Transcoder; |