blob: ff4ff887f5c2e34948752bb4b1870425b9416777 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
Nico Huber3be61d42017-01-09 13:58:18 +01002-- Copyright (C) 2016-2017 secunet Security Networks AG
Nico Huber83693c82016-10-08 22:17:55 +02003--
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
Nico Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
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
15with HW.GFX.GMA.Config;
16with HW.GFX.GMA.Registers;
Nico Huber3be61d42017-01-09 13:58:18 +010017with HW.GFX.GMA.Config_Helpers;
Nico Huber83693c82016-10-08 22:17:55 +020018
19package body HW.GFX.GMA.Port_Detect
20is
21
22 PCH_ADPA_CRT_HPD_CHANNEL_MASK : constant := 3 * 2 ** 24;
23 PCH_ADPA_CRT_HPD_ENABLE : constant := 1 * 2 ** 23;
24
25 DP_PORT_DETECTED : constant := 1 * 2 ** 2;
26 PCH_DIGI_PORT_DETECTED : constant := 1 * 2 ** 2;
27 PCH_LVDS_PORT_DETECTED : constant := 1 * 2 ** 1;
28
29 SHOTPLUG_CTL_DETECT_MASK : constant := 16#0003_0303#;
30
31 type PCH_Digital_Port_Value is array (PCH_HDMI_Port) of Word32;
32 SHOTPLUG_CTL_HPD_INPUT_ENABLE : constant PCH_Digital_Port_Value :=
33 (PCH_HDMI_B => 1 * 2 ** 4,
34 PCH_HDMI_C => 1 * 2 ** 12,
35 PCH_HDMI_D => 1 * 2 ** 20);
36 SHOTPLUG_CTL_SHORT_PULSE_MASK : constant PCH_Digital_Port_Value :=
37 (PCH_HDMI_B => 3 * 2 ** 2,
38 PCH_HDMI_C => 3 * 2 ** 10,
39 PCH_HDMI_D => 3 * 2 ** 18);
40 SHOTPLUG_CTL_HPD_STATUS : constant PCH_Digital_Port_Value :=
41 (PCH_HDMI_B => 3 * 2 ** 0,
42 PCH_HDMI_C => 3 * 2 ** 8,
43 PCH_HDMI_D => 3 * 2 ** 16);
44 SHOTPLUG_CTL_LONG_DETECT : constant PCH_Digital_Port_Value :=
45 (PCH_HDMI_B => 1 * 2 ** 1,
46 PCH_HDMI_C => 1 * 2 ** 9,
47 PCH_HDMI_D => 1 * 2 ** 17);
48
49 type PCH_Digital_Regs is array (PCH_HDMI_Port) of Registers.Registers_Index;
50 PCH_HDMI : constant PCH_Digital_Regs :=
51 (PCH_HDMI_B => Registers.PCH_HDMIB,
52 PCH_HDMI_C => Registers.PCH_HDMIC,
53 PCH_HDMI_D => Registers.PCH_HDMID);
54 PCH_DP : constant PCH_Digital_Regs :=
55 (PCH_HDMI_B => Registers.PCH_DP_B,
56 PCH_HDMI_C => Registers.PCH_DP_C,
57 PCH_HDMI_D => Registers.PCH_DP_D);
58
59 procedure Initialize
60 is
61 Internal_Detected,
62 HDMI_Detected,
63 DP_Detected : Boolean;
64
65 type PCH_Port_To_GMA_Port is array (PCH_HDMI_Port) of Port_Type;
66 To_Digital_Port : constant PCH_Port_To_GMA_Port :=
Nico Huber0d454cd2016-11-21 13:33:43 +010067 (PCH_HDMI_B => HDMI1,
68 PCH_HDMI_C => HDMI2,
69 PCH_HDMI_D => HDMI3);
Nico Huber83693c82016-10-08 22:17:55 +020070 To_DP_Port : constant PCH_Port_To_GMA_Port :=
71 (PCH_HDMI_B => DP1,
72 PCH_HDMI_C => DP2,
73 PCH_HDMI_D => DP3);
74 begin
75 -- PCH_DAC (_A)
76 Registers.Set_Mask
77 (Register => Registers.PCH_ADPA,
78 Mask => PCH_ADPA_CRT_HPD_CHANNEL_MASK or -- clear status
79 PCH_ADPA_CRT_HPD_ENABLE);
80
81 case Config.Internal_Display is
82 when LVDS =>
83 -- PCH_LVDS
84 Registers.Is_Set_Mask
85 (Register => Registers.PCH_LVDS,
86 Mask => PCH_LVDS_PORT_DETECTED,
87 Result => Internal_Detected);
88 when DP =>
89 -- eDP
90 Registers.Is_Set_Mask
91 (Register => Registers.DP_CTL_A,
92 Mask => DP_PORT_DETECTED,
93 Result => Internal_Detected);
94 when None =>
95 Internal_Detected := False;
96 end case;
97 Config.Valid_Port (Internal) := Internal_Detected;
98
99 -- PCH_HDMI_[BCD], PCH_DP_[BCD] share hotplug registers
100 for PCH_Port in PCH_HDMI_Port loop
101 Registers.Is_Set_Mask
102 (Register => PCH_HDMI (PCH_Port),
103 Mask => PCH_DIGI_PORT_DETECTED,
104 Result => HDMI_Detected);
105 Config.Valid_Port (To_Digital_Port (PCH_Port)) := HDMI_Detected;
106
107 Registers.Is_Set_Mask
108 (Register => PCH_DP (PCH_Port),
109 Mask => PCH_DIGI_PORT_DETECTED,
110 Result => DP_Detected);
111 Config.Valid_Port (To_DP_Port (PCH_Port)) := DP_Detected;
112
113 if HDMI_Detected or DP_Detected then
114 Registers.Unset_And_Set_Mask
115 (Register => Registers.SHOTPLUG_CTL,
116 Mask_Unset => SHOTPLUG_CTL_DETECT_MASK or
117 SHOTPLUG_CTL_SHORT_PULSE_MASK (PCH_Port),
118 Mask_Set => SHOTPLUG_CTL_HPD_INPUT_ENABLE (PCH_Port) or
119 SHOTPLUG_CTL_HPD_STATUS (PCH_Port)); -- clear
120 else
121 Registers.Unset_Mask
122 (Register => Registers.SHOTPLUG_CTL,
123 Mask => SHOTPLUG_CTL_DETECT_MASK or
124 SHOTPLUG_CTL_HPD_INPUT_ENABLE (PCH_Port));
125 end if;
126 end loop;
127 end Initialize;
128
Nico Huber3be61d42017-01-09 13:58:18 +0100129 procedure Hotplug_Detect (Port : in Active_Port_Type; Detected : out Boolean)
Nico Huber83693c82016-10-08 22:17:55 +0200130 is
131 Ctl32 : Word32;
132 PCH_Port : constant GMA.PCH_Port :=
Nico Huber3be61d42017-01-09 13:58:18 +0100133 (case Port is
134 when DP1 => PCH_HDMI_B,
135 when DP2 => PCH_HDMI_C,
136 when DP3 => PCH_HDMI_D,
137 when others => Config_Helpers.To_PCH_Port (Port));
Nico Huber83693c82016-10-08 22:17:55 +0200138 begin
139 case PCH_Port is
140 when PCH_DAC =>
141 Registers.Read (Registers.PCH_ADPA, Ctl32, Verbose => False);
142 Ctl32 := Ctl32 and PCH_ADPA_CRT_HPD_CHANNEL_MASK;
143 Detected := Ctl32 = PCH_ADPA_CRT_HPD_CHANNEL_MASK;
144 if Ctl32 /= 0 then
145 Registers.Set_Mask (Registers.PCH_ADPA, Ctl32);
146 end if;
147 when PCH_HDMI_B .. PCH_HDMI_D =>
148 Registers.Read (Registers.SHOTPLUG_CTL, Ctl32, Verbose => False);
149 Detected := (Ctl32 and SHOTPLUG_CTL_LONG_DETECT (PCH_Port)) /= 0;
150
151 if (Ctl32 and SHOTPLUG_CTL_HPD_STATUS (PCH_Port)) /= 0 then
152 Registers.Unset_And_Set_Mask
153 (Register => Registers.SHOTPLUG_CTL,
154 Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
155 Mask_Set => SHOTPLUG_CTL_HPD_STATUS (PCH_Port));
156 end if;
157 when others =>
158 Detected := False;
159 end case;
160 end Hotplug_Detect;
161
162end HW.GFX.GMA.Port_Detect;