Initial upstream commit

The history contained unlicensed code so everything got squashed, sorry.

Change-Id: I9f5775208f9df6fb29074bf3bc498f68cb17b3a0
Signed-off-by: Nico Huber <nico.huber@secunet.com>
This commit is contained in:
Nico Huber 2016-10-08 22:17:55 +02:00 committed by Nico Huber
commit 83693c8d7d
102 changed files with 13351 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/proof-allconfigs/
/build/
/dest/
/*.gpr
/.config

339
COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

6
Makefile Normal file
View File

@ -0,0 +1,6 @@
name := gfxinit
gfxinit-deplibs := libhw
libhw-dir ?= ../libhwbase/dest
include $(libhw-dir)/Makefile

1
Makefile.inc Normal file
View File

@ -0,0 +1 @@
subdirs-y += common

5
TODO Normal file
View File

@ -0,0 +1,5 @@
medium DP re-read status if updated bit isn't set
medium DP honor adjust requests also if training succeeded?
unknown DP honor SINK_STATUS after training
low LVDS sync polarity, 8bit colors, data format???

57
common/Makefile.inc Normal file
View File

@ -0,0 +1,57 @@
gfxinit-y += hw-gfx-dp_aux_ch.adb
gfxinit-y += hw-gfx-dp_aux_ch.ads
gfxinit-y += hw-gfx-dp_defs.ads
gfxinit-y += hw-gfx-dp_info.adb
gfxinit-y += hw-gfx-dp_info.ads
gfxinit-y += hw-gfx-dp_training.adb
gfxinit-y += hw-gfx-dp_training.ads
gfxinit-y += hw-gfx-edid.adb
gfxinit-y += hw-gfx-edid.ads
gfxinit-y += hw-gfx-gma-connector_info.adb
gfxinit-y += hw-gfx-gma-connector_info.ads
gfxinit-y += hw-gfx-gma-connectors.ads
gfxinit-y += hw-gfx-gma-dp_aux_ch.ads
gfxinit-y += hw-gfx-gma-dp_aux_request.adb
gfxinit-y += hw-gfx-gma-dp_aux_request.ads
gfxinit-y += hw-gfx-gma-dp_info.ads
gfxinit-y += hw-gfx-gma-i2c.adb
gfxinit-y += hw-gfx-gma-i2c.ads
gfxinit-y += hw-gfx-gma-panel.adb
gfxinit-y += hw-gfx-gma-panel.ads
gfxinit-y += hw-gfx-gma-pch-fdi.adb
gfxinit-y += hw-gfx-gma-pch-fdi.ads
gfxinit-y += hw-gfx-gma-pch-sideband.adb
gfxinit-y += hw-gfx-gma-pch-sideband.ads
gfxinit-y += hw-gfx-gma-pch-transcoder.adb
gfxinit-y += hw-gfx-gma-pch-transcoder.ads
gfxinit-y += hw-gfx-gma-pch-vga.adb
gfxinit-y += hw-gfx-gma-pch-vga.ads
gfxinit-y += hw-gfx-gma-pch.ads
gfxinit-y += hw-gfx-gma-pipe_setup.adb
gfxinit-y += hw-gfx-gma-pipe_setup.ads
gfxinit-y += hw-gfx-gma-port_detect.ads
gfxinit-y += hw-gfx-gma-registers.adb
gfxinit-y += hw-gfx-gma-registers.ads
gfxinit-y += hw-gfx-gma.adb
gfxinit-y += hw-gfx-gma.ads
gfxinit-y += hw-gfx-i2c.ads
gfxinit-y += hw-gfx.ads
gfxinit-$(CONFIG_HWBASE_DYNAMIC_MMIO) += hw-gfx-framebuffer_filler.adb
gfxinit-$(CONFIG_HWBASE_DYNAMIC_MMIO) += hw-gfx-framebuffer_filler.ads
$(call src-to-obj,,$(dir)/hw-gfx-gma-config).ads: $(dir)/hw-gfx-gma-config.ads.template $(cnf)
printf " GENERATE $(patsubst /%,%,$(subst $(obj)/,,$@))\n"
sed -e's/<<CPU>>/$(CONFIG_GFX_GMA_CPU)/' \
-e's/<<CPU_VARIANT>>/$(CONFIG_GFX_GMA_CPU_VARIANT)/' \
-e's/<<INTERNAL_PORT>>/$(CONFIG_GFX_GMA_INTERNAL_PORT)/' \
-e's/<<DEFAULT_MMIO_BASE>>/$(CONFIG_GFX_GMA_DEFAULT_MMIO)/' \
$< >$@
gfxinit-gen-y += $(call src-to-obj,,$(dir)/hw-gfx-gma-config).ads
ifneq ($(filter Ironlake Sandybridge Ivybridge,$(CONFIG_GFX_GMA_CPU)),)
subdirs-y += ironlake
else ifneq ($(filter Haswell Broadwell,$(CONFIG_GFX_GMA_CPU)),)
subdirs-y += haswell_shared haswell
else
subdirs-y += haswell_shared skylake
endif

View File

@ -0,0 +1,8 @@
gfxinit-y += hw-gfx-gma-plls-lcpll.ads
gfxinit-y += hw-gfx-gma-plls-wrpll.adb
gfxinit-y += hw-gfx-gma-plls-wrpll.ads
gfxinit-y += hw-gfx-gma-plls.adb
gfxinit-y += hw-gfx-gma-plls.ads
gfxinit-y += hw-gfx-gma-power_and_clocks.ads
gfxinit-y += hw-gfx-gma-spll.adb
gfxinit-y += hw-gfx-gma-spll.ads

View File

@ -0,0 +1,28 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.PLLs.LCPLL
is
type Fixed_LCPLLs_Array is array (HW.GFX.DP_Bandwidth) of LCPLLs;
Fixed_LCPLLs : constant Fixed_LCPLLs_Array := Fixed_LCPLLs_Array'
(DP_Bandwidth_5_4 => LCPLL0,
DP_Bandwidth_2_7 => LCPLL1,
DP_Bandwidth_1_62 => LCPLL2);
type Value_Array is array (LCPLLs) of Word32;
Register_Value : constant Value_Array := Value_Array'
(LCPLL0 => 0 * 2 ** 29, LCPLL1 => 1 * 2 ** 29, LCPLL2 => 2 * 2 ** 29);
end HW.GFX.GMA.PLLs.LCPLL;

View File

@ -0,0 +1,351 @@
--
-- Copyright (C) 2015 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.PLLs.WRPLL is
----------------------------------------------------------------------------
--
-- Divider calculation as found in Linux' i915 driver
--
-- Copyright (C) 2012 Intel Corporation
--
-- Permission is hereby granted, free of charge, to any person obtaining a
-- copy of this software and associated documentation files (the "Software"),
-- to deal in the Software without restriction, including without limitation
-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
-- and/or sell copies of the Software, and to permit persons to whom the
-- Software is furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice (including the next
-- paragraph) shall be included in all copies or substantial portions of the
-- Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-- IN THE SOFTWARE.
--
-- Authors:
-- Eugeni Dodonov <eugeni.dodonov@intel.com>
--
LC_FREQ : constant := 2700; -- in MHz
LC_FREQ_2K : constant := LC_FREQ * 2000; -- in 500Hz
P_MIN : constant := 2;
P_MAX : constant := 62; -- i915 says 64, but this would overflow 6-bit
P_INC : constant := 2;
-- Constraints for PLL good behavior
REF_MIN : constant := 48;
REF_MAX : constant := 400;
VCO_MIN : constant := 2400;
VCO_MAX : constant := 4800;
type R2_Range is new Natural range 0 .. LC_FREQ * 2 / REF_MIN;
type N2_Range is new Natural range 0 .. VCO_MAX * Natural (R2_Range'Last) / LC_FREQ;
type P_Range is new Natural range 0 .. P_MAX;
type RNP is record
P : P_Range;
N2 : N2_Range;
R2 : R2_Range;
end record;
Invalid_RNP : constant RNP := RNP'(0, 0, 0);
function Get_Budget_For_Freq
(Clock : HW.GFX.Frequency_Type)
return Word64
is
Result : Word64;
begin
case Clock is
when 25175000 |
25200000 |
27000000 |
27027000 |
37762500 |
37800000 |
40500000 |
40541000 |
54000000 |
54054000 |
59341000 |
59400000 |
72000000 |
74176000 |
74250000 |
81000000 |
81081000 |
89012000 |
89100000 |
108000000 |
108108000 |
111264000 |
111375000 |
148352000 |
148500000 |
162000000 |
162162000 |
222525000 |
222750000 |
296703000 |
297000000 =>
Result := 0;
when 233500000 |
245250000 |
247750000 |
253250000 |
298000000 =>
Result := 1500;
when 169128000 |
169500000 |
179500000 |
202000000 =>
Result := 2000;
when 256250000 |
262500000 |
270000000 |
272500000 |
273750000 |
280750000 |
281250000 |
286000000 |
291750000 =>
Result := 4000;
when 267250000 |
268500000 =>
Result := 5000;
when others =>
Result := 1000;
end case;
return Result;
end Get_Budget_For_Freq;
procedure Update_RNP
(Freq_2K : in Word64;
Budget : in Word64;
R2 : in R2_Range;
N2 : in N2_Range;
P : in P_Range;
Best : in out RNP)
with
Depends => (Best =>+ (Freq_2K, Budget, R2, N2, P))
is
use type HW.Word64;
function Abs_Diff (A, B : Word64) return Word64
is
Result : Word64;
begin
if A > B then
Result := A - B;
else
Result := B - A;
end if;
return Result;
end Abs_Diff;
A, B, C, D, Diff, Diff_Best : Word64;
begin
-- No best (r,n,p) yet */
if Best.P = 0 then
Best.P := P;
Best.N2 := N2;
Best.R2 := R2;
else
-- Config clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
-- freq2k.
--
-- delta = 1e6 *
-- abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
-- freq2k;
--
-- and we would like delta <= budget.
--
-- If the discrepancy is above the PPM-based budget, always prefer to
-- improve upon the previous solution. However, if you're within the
-- budget, try to maximize Ref * VCO, that is N / (P * R^2).
A := Freq_2K * Budget * Word64 (P) * Word64 (R2);
B := Freq_2K * Budget * Word64 (Best.P) * Word64 (Best.R2);
Diff := Abs_Diff
(Freq_2K * Word64 (P) * Word64 (R2),
LC_FREQ_2K * Word64 (N2));
Diff_Best := Abs_Diff
(Freq_2K * Word64 (Best.P) * Word64 (Best.R2),
LC_FREQ_2K * Word64 (Best.N2));
C := 1000000 * Diff;
D := 1000000 * Diff_Best;
if A < C and B < D then
-- If both are above the Budget, pick the closer
if Word64 (Best.P) * Word64 (Best.R2) * Diff
< Word64 (P) * Word64 (R2) * Diff_Best
then
Best.P := P;
Best.N2 := N2;
Best.R2 := R2;
end if;
elsif A >= C and B < D then
-- If A is below the threshold but B is above it? Update.
Best.P := P;
Best.N2 := N2;
Best.R2 := R2;
elsif A >= C and B >= D then
-- Both are below the limit, so pick the higher N2/(R2*R2)
if Word64 (N2) * Word64 (Best.R2) * Word64 (Best.R2)
> Word64 (Best.N2) * Word64 (R2) * Word64 (R2)
then
Best.P := P;
Best.N2 := N2;
Best.R2 := R2;
end if;
end if;
-- Otherwise A < C && B >= D, do nothing
end if;
end Update_RNP;
procedure Calculate_WRPLL
(Clock : in HW.GFX.Frequency_Type;
R2_Out : out R2_Range;
N2_Out : out N2_Range;
P_Out : out P_Range)
with
Global => null,
Pre => True,
Post => True
is
use type HW.Word64;
Freq_2K : Word64;
Budget : Word64;
Best : RNP := Invalid_RNP;
begin
Freq_2K := Word64 (Clock) / 100; -- PLL output should be 5x
-- the pixel clock
Budget := Get_Budget_For_Freq (Clock);
-- Special case handling for 540MHz pixel clock: bypass WR PLL entirely
-- and directly pass the LC PLL to it. */
if Freq_2K = 5400000 then
N2_Out := 2;
P_Out := 1;
R2_Out := 2;
else
-- Ref = LC_FREQ / R, where Ref is the actual reference input seen by
-- the WR PLL.
--
-- We want R so that REF_MIN <= Ref <= REF_MAX.
-- Injecting R2 = 2 * R gives:
-- REF_MAX * r2 > LC_FREQ * 2 and
-- REF_MIN * r2 < LC_FREQ * 2
--
-- Which means the desired boundaries for r2 are:
-- LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
--
for R2 in R2_Range range
LC_FREQ * 2 / REF_MAX + 1 .. LC_FREQ * 2 / REF_MIN
loop
-- VCO = N * Ref, that is: VCO = N * LC_FREQ / R
--
-- Once again we want VCO_MIN <= VCO <= VCO_MAX.
-- Injecting R2 = 2 * R and N2 = 2 * N, we get:
-- VCO_MAX * r2 > n2 * LC_FREQ and
-- VCO_MIN * r2 < n2 * LC_FREQ)
--
-- Which means the desired boundaries for n2 are:
-- VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
for N2 in N2_Range range
N2_Range (VCO_MIN * Natural (R2) / LC_FREQ + 1)
.. N2_Range (VCO_MAX * Natural (R2) / LC_FREQ)
loop
for P_Fract in Natural range P_MIN / P_INC .. P_MAX / P_INC
loop
Update_RNP
(Freq_2K, Budget, R2, N2, P_Range (P_Fract * P_INC), Best);
end loop;
end loop;
end loop;
N2_Out := Best.N2;
P_Out := Best.P;
R2_Out := Best.R2;
end if;
end Calculate_WRPLL;
--
----------------------------------------------------------------------------
type Regs is array (WRPLLs) of Registers.Registers_Index;
WRPLL_CTL : constant Regs := Regs'(Registers.WRPLL_CTL_1, Registers.WRPLL_CTL_2);
WRPLL_CTL_PLL_ENABLE : constant := 1 * 2 ** 31;
WRPLL_CTL_SELECT_LCPLL : constant := 3 * 2 ** 28;
function WRPLL_CTL_DIVIDER_FEEDBACK (N2 : N2_Range) return Word32
is
begin
return Word32 (N2) * 2 ** 16;
end WRPLL_CTL_DIVIDER_FEEDBACK;
function WRPLL_CTL_DIVIDER_POST (P : P_Range) return Word32
is
begin
return Word32 (P) * 2 ** 8;
end WRPLL_CTL_DIVIDER_POST;
function WRPLL_CTL_DIVIDER_REFERENCE (R2 : R2_Range) return Word32
is
begin
return Word32 (R2) * 2 ** 0;
end WRPLL_CTL_DIVIDER_REFERENCE;
----------------------------------------------------------------------------
procedure On
(PLL : in WRPLLs;
Target_Clock : in Frequency_Type;
Success : out Boolean)
is
R2 : R2_Range;
N2 : N2_Range;
P : P_Range;
begin
Calculate_WRPLL (Target_Clock, R2, N2, P);
Registers.Write
(Register => WRPLL_CTL (PLL),
Value => WRPLL_CTL_PLL_ENABLE or
WRPLL_CTL_SELECT_LCPLL or
WRPLL_CTL_DIVIDER_FEEDBACK (N2) or
WRPLL_CTL_DIVIDER_POST (P) or
WRPLL_CTL_DIVIDER_REFERENCE (R2));
Registers.Posting_Read (WRPLL_CTL (PLL));
Time.U_Delay (20);
Success := True;
end On;
procedure Off (PLL : WRPLLs)
is
begin
Registers.Unset_Mask (WRPLL_CTL (PLL), WRPLL_CTL_PLL_ENABLE);
end Off;
end HW.GFX.GMA.PLLs.WRPLL;

View File

@ -0,0 +1,28 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.PLLs.WRPLL
is
type Value_Array is array (WRPLLs) of Word32;
Register_Value : constant Value_Array := Value_Array'
(WRPLL0 => 4 * 2 ** 29, WRPLL1 => 5 * 2 ** 29);
procedure On
(PLL : in WRPLLs;
Target_Clock : in Frequency_Type;
Success : out Boolean);
procedure Off (PLL : WRPLLs);
end HW.GFX.GMA.PLLs.WRPLL;

View File

@ -0,0 +1,130 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.PLLs.LCPLL;
with HW.GFX.GMA.PLLs.WRPLL;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.PLLs
with
Refined_State => (State => PLLs)
is
type Count_Range is new Natural range 0 .. 2;
type PLL_State is record
Use_Count : Count_Range;
Mode : Mode_Type;
end record;
type PLL_State_Array is array (WRPLLs) of PLL_State;
PLLs : PLL_State_Array;
procedure Initialize
is
begin
PLLs := (WRPLLs => (Use_Count => 0, Mode => Invalid_Mode));
end Initialize;
procedure Alloc_Configurable
(Mode : in Mode_Type;
PLL : out T;
Success : out Boolean)
with
Pre => True
is
begin
-- try to find shareable PLL
for P in WRPLLs loop
Success := PLLs (P).Use_Count /= 0 and
PLLs (P).Use_Count /= Count_Range'Last and
PLLs (P).Mode = Mode;
if Success then
PLL := P;
PLLs (PLL).Use_Count := PLLs (PLL).Use_Count + 1;
return;
end if;
end loop;
-- try to find free PLL
for P in WRPLLs loop
if PLLs (P).Use_Count = 0 then
PLL := P;
WRPLL.On (PLL, Mode.Dotclock, Success);
if Success then
PLLs (PLL) := (Use_Count => 1, Mode => Mode);
end if;
return;
end if;
end loop;
PLL := Invalid;
end Alloc_Configurable;
procedure Alloc
(Port_Cfg : in Port_Config;
PLL : out T;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Port = DIGI_E then
PLL := Invalid;
Success := True;
elsif Port_Cfg.Display = DP then
PLL := LCPLL.Fixed_LCPLLs (Port_Cfg.DP.Bandwidth);
Success := True;
else
Alloc_Configurable (Port_Cfg.Mode, PLL, Success);
end if;
end Alloc;
procedure Free (PLL : T)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if PLL in WRPLLs then
if PLLs (PLL).Use_Count /= 0 then
PLLs (PLL).Use_Count := PLLs (PLL).Use_Count - 1;
if PLLs (PLL).Use_Count = 0 then
WRPLL.Off (PLL);
end if;
end if;
end if;
end Free;
procedure All_Off
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
for PLL in WRPLLs loop
WRPLL.Off (PLL);
end loop;
end All_Off;
function Register_Value (PLL : T) return Word32
is
begin
return
(if PLL in LCPLLs then LCPLL.Register_Value (PLL)
elsif PLL in WRPLLs then WRPLL.Register_Value (PLL)
else 0);
end Register_Value;
end HW.GFX.GMA.PLLs;

View File

@ -0,0 +1,40 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.PLLs
with
Abstract_State => (State with Part_Of => GMA.State)
is
-- XXX: Types should be private (but that triggers a bug in SPARK GPL 2016)
type T is (Invalid_PLL, LCPLL0, LCPLL1, LCPLL2, WRPLL0, WRPLL1);
subtype LCPLLs is T range LCPLL0 .. LCPLL2;
subtype WRPLLs is T range WRPLL0 .. WRPLL1;
Invalid : constant T := Invalid_PLL;
procedure Initialize
with
Global => (Output => State);
procedure Alloc
(Port_Cfg : in Port_Config;
PLL : out T;
Success : out Boolean);
procedure Free (PLL : T);
procedure All_Off;
function Register_Value (PLL : T) return Word32;
end HW.GFX.GMA.PLLs;

View File

@ -0,0 +1,17 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Power_And_Clocks_Haswell;
private package HW.GFX.GMA.Power_And_Clocks
renames HW.GFX.GMA.Power_And_Clocks_Haswell;

View File

@ -0,0 +1,43 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.SPLL is
SPLL_CTL_PLL_ENABLE : constant := 1 * 2 ** 31;
SPLL_CTL_REF_SEL_MASK : constant := 3 * 2 ** 28;
SPLL_CTL_REF_SEL_SSC : constant := 1 * 2 ** 28;
SPLL_CTL_REF_SEL_NON_SSC : constant := 2 * 2 ** 28;
SPLL_CTL_FREQ_SEL_MASK : constant := 3 * 2 ** 26;
SPLL_CTL_FREQ_SEL_810 : constant := 0 * 2 ** 26;
SPLL_CTL_FREQ_SEL_1350 : constant := 1 * 2 ** 26;
procedure On is
begin
Registers.Write
(Register => Registers.SPLL_CTL,
Value => SPLL_CTL_PLL_ENABLE or
SPLL_CTL_REF_SEL_SSC or
SPLL_CTL_FREQ_SEL_1350);
Registers.Posting_Read (Registers.SPLL_CTL);
Time.U_Delay (20);
end On;
procedure Off is
begin
Registers.Unset_Mask (Registers.SPLL_CTL, SPLL_CTL_PLL_ENABLE);
end Off;
end HW.GFX.GMA.SPLL;

View File

@ -0,0 +1,20 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.GMA.SPLL is
procedure On;
procedure Off;
end HW.GFX.GMA.SPLL;

View File

@ -0,0 +1,6 @@
gfxinit-y += hw-gfx-gma-connectors-ddi.adb
gfxinit-y += hw-gfx-gma-connectors-ddi.ads
gfxinit-y += hw-gfx-gma-connectors.adb
gfxinit-y += hw-gfx-gma-port_detect.adb
gfxinit-y += hw-gfx-gma-power_and_clocks_haswell.adb
gfxinit-y += hw-gfx-gma-power_and_clocks_haswell.ads

View File

@ -0,0 +1,554 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.DP_Training;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.PCH.FDI;
with HW.GFX.GMA.PCH.Transcoder;
with HW.GFX.GMA.PCH.VGA;
with HW.GFX.GMA.DP_Info;
with HW.GFX.GMA.DP_Aux_Ch;
with HW.GFX.GMA.SPLL;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.Connectors.DDI is
DDI_BUF_CTL_BUFFER_ENABLE : constant := 1 * 2 ** 31;
DDI_BUF_CTL_TRANS_SELECT_MASK : constant := 15 * 2 ** 24;
DDI_BUF_CTL_PORT_REVERSAL : constant := 1 * 2 ** 16;
DDI_BUF_CTL_IDLE_STATUS : constant := 1 * 2 ** 7;
DDI_BUF_CTL_DDI_A_LANE_CAP : constant := 1 * 2 ** 4;
DDI_BUF_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1;
DDI_BUF_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1;
DDI_BUF_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1;
DDI_BUF_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1;
DDI_BUF_CTL_INIT_DISPLAY_DETECT : constant := 1 * 2 ** 0;
subtype DDI_BUF_CTL_TRANS_SELECT_T is Natural range 0 .. 9;
function DDI_BUF_CTL_TRANS_SELECT
(Sel : DDI_BUF_CTL_TRANS_SELECT_T)
return Word32;
type DDI_BUF_CTL_PORT_WIDTH_T is array (HW.GFX.DP_Lane_Count) of Word32;
DDI_BUF_CTL_PORT_WIDTH : constant DDI_BUF_CTL_PORT_WIDTH_T :=
DDI_BUF_CTL_PORT_WIDTH_T'
(HW.GFX.DP_Lane_Count_1 => DDI_BUF_CTL_PORT_WIDTH_1_LANE,
HW.GFX.DP_Lane_Count_2 => DDI_BUF_CTL_PORT_WIDTH_2_LANES,
HW.GFX.DP_Lane_Count_4 => DDI_BUF_CTL_PORT_WIDTH_4_LANES);
DP_TP_CTL_TRANSPORT_ENABLE : constant := 1 * 2 ** 31;
DP_TP_CTL_MODE_SST : constant := 0 * 2 ** 27;
DP_TP_CTL_MODE_MST : constant := 1 * 2 ** 27;
DP_TP_CTL_FORCE_ACT : constant := 1 * 2 ** 25;
DP_TP_CTL_ENHANCED_FRAME_ENABLE : constant := 1 * 2 ** 18;
DP_TP_CTL_FDI_AUTOTRAIN : constant := 1 * 2 ** 15;
DP_TP_CTL_LINK_TRAIN_MASK : constant := 7 * 2 ** 8;
DP_TP_CTL_LINK_TRAIN_PAT1 : constant := 0 * 2 ** 8;
DP_TP_CTL_LINK_TRAIN_PAT2 : constant := 1 * 2 ** 8;
DP_TP_CTL_LINK_TRAIN_PAT3 : constant := 4 * 2 ** 8;
DP_TP_CTL_LINK_TRAIN_IDLE : constant := 2 * 2 ** 8;
DP_TP_CTL_LINK_TRAIN_NORMAL : constant := 3 * 2 ** 8;
DP_TP_CTL_SCRAMBLE_DISABLE : constant := 1 * 2 ** 7;
DP_TP_CTL_ALT_SCRAMBLER_RESET : constant := 1 * 2 ** 6;
type DP_TP_CTL_LINK_TRAIN_Array is
array (DP_Info.Training_Pattern) of Word32;
DP_TP_CTL_LINK_TRAIN : constant DP_TP_CTL_LINK_TRAIN_Array :=
DP_TP_CTL_LINK_TRAIN_Array'
(DP_Info.TP_1 => DP_TP_CTL_LINK_TRAIN_PAT1 or DP_TP_CTL_SCRAMBLE_DISABLE,
DP_Info.TP_2 => DP_TP_CTL_LINK_TRAIN_PAT2 or DP_TP_CTL_SCRAMBLE_DISABLE,
DP_Info.TP_3 => DP_TP_CTL_LINK_TRAIN_PAT3 or DP_TP_CTL_SCRAMBLE_DISABLE,
DP_Info.TP_Idle => DP_TP_CTL_LINK_TRAIN_IDLE,
DP_Info.TP_None => DP_TP_CTL_LINK_TRAIN_NORMAL);
DP_TP_STATUS_MIN_IDLES_SENT : constant := 1 * 2 ** 25;
DP_TP_STATUS_FDI_AUTO_TRAIN_DONE : constant := 1 * 2 ** 12;
PORT_CLK_SEL_LCPLL2700 : constant := 0 * 2 ** 29; -- not on ULX
PORT_CLK_SEL_LCPLL1350 : constant := 1 * 2 ** 29;
PORT_CLK_SEL_LCPLL810 : constant := 2 * 2 ** 29;
PORT_CLK_SEL_SPLL : constant := 3 * 2 ** 29;
PORT_CLK_SEL_WRPLL1 : constant := 4 * 2 ** 29;
PORT_CLK_SEL_WRPLL2 : constant := 5 * 2 ** 29;
PORT_CLK_SEL_NONE : constant := 7 * 2 ** 29;
type PORT_CLK_SEL_LCPLL_T is array (HW.GFX.DP_Bandwidth) of Word32;
PORT_CLK_SEL_LCPLL : constant PORT_CLK_SEL_LCPLL_T :=
PORT_CLK_SEL_LCPLL_T'
(HW.GFX.DP_Bandwidth_1_62 => PORT_CLK_SEL_LCPLL810,
HW.GFX.DP_Bandwidth_2_7 => PORT_CLK_SEL_LCPLL1350,
HW.GFX.DP_Bandwidth_5_4 => PORT_CLK_SEL_LCPLL2700);
type DDI_Registers is record
BUF_CTL : Registers.Registers_Index;
DP_TP_CTL : Registers.Registers_Index;
DP_TP_STATUS : Registers.Registers_Invalid_Index;
PORT_CLK_SEL : Registers.Registers_Index;
end record;
type DDI_Registers_Array is array (Digital_Port) of DDI_Registers;
DDI_Regs : constant DDI_Registers_Array := DDI_Registers_Array'
(DIGI_A => DDI_Registers'
(BUF_CTL => Registers.DDI_BUF_CTL_A,
DP_TP_CTL => Registers.DP_TP_CTL_A,
DP_TP_STATUS => Registers.Invalid_Register,
PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIA),
DIGI_B => DDI_Registers'
(BUF_CTL => Registers.DDI_BUF_CTL_B,
DP_TP_CTL => Registers.DP_TP_CTL_B,
DP_TP_STATUS => Registers.DP_TP_STATUS_B,
PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIB),
DIGI_C => DDI_Registers'
(BUF_CTL => Registers.DDI_BUF_CTL_C,
DP_TP_CTL => Registers.DP_TP_CTL_C,
DP_TP_STATUS => Registers.DP_TP_STATUS_C,
PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIC),
DIGI_D => DDI_Registers'
(BUF_CTL => Registers.DDI_BUF_CTL_D,
DP_TP_CTL => Registers.DP_TP_CTL_D,
DP_TP_STATUS => Registers.DP_TP_STATUS_D,
PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDID),
DIGI_E => DDI_Registers'
(BUF_CTL => Registers.DDI_BUF_CTL_E,
DP_TP_CTL => Registers.DP_TP_CTL_E,
DP_TP_STATUS => Registers.DP_TP_STATUS_E,
PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIE));
----------------------------------------------------------------------------
type Values is array (Digital_Port) of Word32;
type Shifts is array (Digital_Port) of Natural;
DPLL_CTRL2_DDIx_CLOCK_OFF : constant Values := Values'
(DIGI_A => 1 * 2 ** 15,
DIGI_B => 1 * 2 ** 16,
DIGI_C => 1 * 2 ** 17,
DIGI_D => 1 * 2 ** 18,
DIGI_E => 1 * 2 ** 19);
DPLL_CTRL2_DDIx_SELECT_MASK : constant Values := Values'
(DIGI_A => 3 * 2 ** 1,
DIGI_B => 3 * 2 ** 4,
DIGI_C => 3 * 2 ** 7,
DIGI_D => 3 * 2 ** 10,
DIGI_E => 3 * 2 ** 13);
DPLL_CTRL2_DDIx_SELECT_SHIFT : constant Shifts := Shifts'
(DIGI_A => 1,
DIGI_B => 4,
DIGI_C => 7,
DIGI_D => 10,
DIGI_E => 13);
DPLL_CTRL2_DDIx_SELECT_OVERRIDE : constant Values := Values'
(DIGI_A => 1 * 2 ** 0,
DIGI_B => 1 * 2 ** 3,
DIGI_C => 1 * 2 ** 6,
DIGI_D => 1 * 2 ** 9,
DIGI_E => 1 * 2 ** 12);
----------------------------------------------------------------------------
function DDI_BUF_CTL_TRANS_SELECT
(Sel : DDI_BUF_CTL_TRANS_SELECT_T)
return Word32
is
begin
return Word32 (Sel) * 2 ** 24;
end DDI_BUF_CTL_TRANS_SELECT;
----------------------------------------------------------------------------
function Max_V_Swing
(Port : Digital_Port)
return DP_Info.DP_Voltage_Swing
is
begin
return
(if (Config.Has_Low_Voltage_Swing and Config.EDP_Low_Voltage_Swing)
and then Port = DIGI_A
then
DP_Info.VS_Level_3
else
DP_Info.VS_Level_2);
end Max_V_Swing;
pragma Warnings (GNATprove, Off, "unused variable ""Port""",
Reason => "Needed for a common interface");
function Max_Pre_Emph
(Port : Digital_Port;
Train_Set : DP_Info.Train_Set)
return DP_Info.DP_Pre_Emph
is
begin
return
(case Train_Set.Voltage_Swing is
when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
when others => DP_Info.Emph_Level_0);
end Max_Pre_Emph;
pragma Warnings (GNATprove, On, "unused variable ""Port""");
----------------------------------------------------------------------------
procedure Set_TP_CTL
(Port : Digital_Port;
Link : DP_Link;
Pattern : DP_Info.Training_Pattern)
is
DP_TP_CTL_Enhanced_Frame : Word32 := 0;
begin
if Link.Enhanced_Framing then
DP_TP_CTL_Enhanced_Frame := DP_TP_CTL_ENHANCED_FRAME_ENABLE;
end if;
Registers.Write
(Register => DDI_Regs (Port).DP_TP_CTL,
Value => DP_TP_CTL_TRANSPORT_ENABLE or
DP_TP_CTL_Enhanced_Frame or
DP_TP_CTL_LINK_TRAIN (Pattern));
end Set_TP_CTL;
procedure Set_Training_Pattern
(Port : Digital_Port;
Link : DP_Link;
Pattern : DP_Info.Training_Pattern)
is
use type DP_Info.Training_Pattern;
begin
if Pattern < DP_Info.TP_Idle then
Set_TP_CTL (Port, Link, Pattern);
else
-- send at least 5 idle patterns
Set_TP_CTL (Port, Link, DP_Info.TP_Idle);
-- switch to normal frame delivery
if Config.End_EDP_Training_Late and then Port = DIGI_A then
null; -- do it later in Post_On procedure
-- TODO: if there are problems getting the pipe up,
-- wait here some time
-- Time.U_Delay (100);
else
if Port /= DIGI_A then
Registers.Wait_Set_Mask
(Register => DDI_Regs (Port).DP_TP_STATUS,
Mask => DP_TP_STATUS_MIN_IDLES_SENT);
end if;
Set_TP_CTL (Port, Link, DP_Info.TP_None);
end if;
end if;
end Set_Training_Pattern;
procedure Set_Signal_Levels
(Port : Digital_Port;
Link : DP_Link;
Train_Set : DP_Info.Train_Set)
is
Was_Enabled : Boolean;
Trans_Select : DDI_BUF_CTL_TRANS_SELECT_T;
begin
case Train_Set.Voltage_Swing is
when DP_Info.VS_Level_0 =>
case Train_Set.Pre_Emph is
when DP_Info.Emph_Level_0 => Trans_Select := 0;
when DP_Info.Emph_Level_1 => Trans_Select := 1;
when DP_Info.Emph_Level_2 => Trans_Select := 2;
when DP_Info.Emph_Level_3 => Trans_Select := 3;
end case;
when DP_Info.VS_Level_1 =>
case Train_Set.Pre_Emph is
when DP_Info.Emph_Level_0 => Trans_Select := 4;
when DP_Info.Emph_Level_1 => Trans_Select := 5;
when DP_Info.Emph_Level_2 => Trans_Select := 6;
when others => Trans_Select := 0;
end case;
when DP_Info.VS_Level_2 =>
case Train_Set.Pre_Emph is
when DP_Info.Emph_Level_0 => Trans_Select := 7;
when DP_Info.Emph_Level_1 => Trans_Select := 8;
when others => Trans_Select := 0;
end case;
when DP_Info.VS_Level_3 =>
case Train_Set.Pre_Emph is
when DP_Info.Emph_Level_0 => Trans_Select := 9;
when others => Trans_Select := 0;
end case;
end case;
Registers.Is_Set_Mask
(Register => DDI_Regs (Port).BUF_CTL,
Mask => DDI_BUF_CTL_BUFFER_ENABLE,
Result => Was_Enabled);
-- enable DDI buffer
Registers.Unset_And_Set_Mask
(Register => DDI_Regs (Port).BUF_CTL,
Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
DDI_BUF_CTL_PORT_REVERSAL or
DDI_BUF_CTL_PORT_WIDTH_MASK,
Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
DDI_BUF_CTL_TRANS_SELECT (Trans_Select) or
DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count));
Registers.Posting_Read (DDI_Regs (Port).BUF_CTL);
if not Was_Enabled then
Time.U_Delay (600); -- wait >= 518us (intel spec)
end if;
end Set_Signal_Levels;
----------------------------------------------------------------------------
procedure Digital_Off (Port : Digital_Port)
is
Enabled : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Is_Set_Mask
(Register => DDI_Regs (Port).BUF_CTL,
Mask => DDI_BUF_CTL_BUFFER_ENABLE,
Result => Enabled);
if Enabled then
Registers.Unset_Mask
(Register => DDI_Regs (Port).BUF_CTL,
Mask => DDI_BUF_CTL_BUFFER_ENABLE);
end if;
Registers.Unset_Mask
(Register => DDI_Regs (Port).DP_TP_CTL,
Mask => DP_TP_CTL_TRANSPORT_ENABLE);
if Enabled then
Registers.Wait_Set_Mask
(Register => DDI_Regs (Port).BUF_CTL,
Mask => DDI_BUF_CTL_IDLE_STATUS);
end if;
if Config.Has_Per_DDI_Clock_Sel then
Registers.Write
(Register => DDI_Regs (Port).PORT_CLK_SEL,
Value => PORT_CLK_SEL_NONE);
else
Registers.Set_Mask
(Register => Registers.DPLL_CTRL2,
Mask => DPLL_CTRL2_DDIx_CLOCK_OFF (Port));
end if;
end Digital_Off;
----------------------------------------------------------------------------
procedure Train_FDI
(Port_Cfg : in Port_Config;
Success : out Boolean)
is
begin
PCH.FDI.Pre_Train (PCH.FDI_A, Port_Cfg);
-- always use SPLL for FDI
SPLL.On;
Registers.Write
(Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
Value => PORT_CLK_SEL_SPLL);
-- try each preemph/voltage pair twice
for Trans2 in Natural range 0 .. DDI_BUF_CTL_TRANS_SELECT_T'Last * 2 + 1
loop
Registers.Write
(Register => DDI_Regs (DIGI_E).DP_TP_CTL,
Value => DP_TP_CTL_TRANSPORT_ENABLE or
DP_TP_CTL_ENHANCED_FRAME_ENABLE or
DP_TP_CTL_FDI_AUTOTRAIN or
DP_TP_CTL_LINK_TRAIN_PAT1);
Registers.Unset_And_Set_Mask
(Register => DDI_Regs (DIGI_E).BUF_CTL,
Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
DDI_BUF_CTL_PORT_REVERSAL or
DDI_BUF_CTL_PORT_WIDTH_MASK,
Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
DDI_BUF_CTL_TRANS_SELECT (Trans2 / 2) or
DDI_BUF_CTL_PORT_WIDTH (Port_Cfg.FDI.Lane_Count));
Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
Time.U_Delay (600); -- wait >= 518us (intel spec)
PCH.FDI.Auto_Train (PCH.FDI_A);
Registers.Is_Set_Mask
(Register => DDI_Regs (DIGI_E).DP_TP_STATUS,
Mask => DP_TP_STATUS_FDI_AUTO_TRAIN_DONE,
Result => Success);
exit when Success;
Registers.Unset_Mask
(Register => DDI_Regs (DIGI_E).BUF_CTL,
Mask => DDI_BUF_CTL_BUFFER_ENABLE);
Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
Registers.Unset_And_Set_Mask
(Register => DDI_Regs (DIGI_E).DP_TP_CTL,
Mask_Unset => DP_TP_CTL_TRANSPORT_ENABLE or
DP_TP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_TP_CTL_LINK_TRAIN_PAT1);
Registers.Posting_Read (DDI_Regs (DIGI_E).DP_TP_CTL);
Registers.Wait_Set_Mask
(Register => DDI_Regs (DIGI_E).BUF_CTL,
Mask => DDI_BUF_CTL_IDLE_STATUS);
PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Lanes_Off);
end loop;
if Success then
-- start normal frame delivery
Registers.Write
(Register => DDI_Regs (DIGI_E).DP_TP_CTL,
Value => DP_TP_CTL_TRANSPORT_ENABLE or
DP_TP_CTL_ENHANCED_FRAME_ENABLE or
DP_TP_CTL_FDI_AUTOTRAIN or
DP_TP_CTL_LINK_TRAIN_NORMAL);
else
Registers.Write
(Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
Value => PORT_CLK_SEL_NONE);
SPLL.Off;
PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
end if;
end Train_FDI;
----------------------------------------------------------------------------
procedure Pre_On
(Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Success : out Boolean)
is
function To_DP (Port : Digital_Port) return DP_Port
is
begin
return
(case Port is
when DIGI_A => DP_A,
when DIGI_B => DP_B,
when DIGI_C => DP_C,
when DIGI_D => DP_D,
when others => DP_Port'First);
end To_DP;
package Training is new DP_Training
(TPS3_Supported => True,
T => Digital_Port,
Aux_T => DP_Port,
Aux_Ch => DP_Aux_Ch,
DP_Info => DP_Info,
To_Aux => To_DP,
Max_V_Swing => Max_V_Swing,
Max_Pre_Emph => Max_Pre_Emph,
Set_Pattern => Set_Training_Pattern,
Set_Signal_Levels => Set_Signal_Levels,
Off => Digital_Off);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Display = VGA then
Train_FDI (Port_Cfg, Success);
else
-- direct configured PLL output to this port
if Config.Has_Per_DDI_Clock_Sel then
Registers.Write
(Register => DDI_Regs (Port_Cfg.Port).PORT_CLK_SEL,
Value => PLL_Hint);
else
Registers.Unset_And_Set_Mask
(Register => Registers.DPLL_CTRL2,
Mask_Unset => DPLL_CTRL2_DDIx_CLOCK_OFF (Port_Cfg.Port) or
DPLL_CTRL2_DDIx_SELECT_MASK (Port_Cfg.Port),
Mask_Set => Shift_Left
(PLL_Hint,
DPLL_CTRL2_DDIx_SELECT_SHIFT (Port_Cfg.Port))
or
DPLL_CTRL2_DDIx_SELECT_OVERRIDE (Port_Cfg.Port));
end if;
if Port_Cfg.Display = DP then
Training.Train_DP
(Port => Port_Cfg.Port,
Link => Port_Cfg.DP,
Success => Success);
else
Success := True;
end if;
end if;
end Pre_On;
----------------------------------------------------------------------------
procedure Post_On (Port_Cfg : Port_Config)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Port = DIGI_A then
if Config.End_EDP_Training_Late then
Registers.Unset_And_Set_Mask
(Register => DDI_Regs (DIGI_A).DP_TP_CTL,
Mask_Unset => DP_TP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_TP_CTL_LINK_TRAIN_NORMAL);
end if;
end if;
case Port_Cfg.Display is
when HDMI =>
Registers.Unset_And_Set_Mask
(Register => DDI_Regs (Port_Cfg.Port).BUF_CTL,
Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
DDI_BUF_CTL_PORT_REVERSAL,
Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE);
Time.U_Delay (600); -- wait >= 518us (intel spec)
when VGA =>
PCH.VGA.Clock_On (Port_Cfg.Mode);
PCH.Transcoder.On (Port_Cfg, PCH.FDI_A, 0);
PCH.VGA.On
(Port => PCH.FDI_A,
Mode => Port_Cfg.Mode);
when others =>
null;
end case;
end Post_On;
----------------------------------------------------------------------------
procedure Off (Port : Digital_Port)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port = DIGI_E then
PCH.VGA.Off;
PCH.Transcoder.Off (PCH.FDI_A);
-- PCH.VGA.Clock_Off; -- Can't tell what Linux does, if anything.
PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Rx_Off);
end if;
Digital_Off (Port);
if Port = DIGI_E then
SPLL.Off;
PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
end if;
end Off;
end HW.GFX.GMA.Connectors.DDI;

View File

@ -0,0 +1,28 @@
--
-- Copyright (C) 2015 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Registers;
private package HW.GFX.GMA.Connectors.DDI
is
procedure Pre_On
(Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Success : out Boolean);
procedure Post_On (Port_Cfg : Port_Config);
procedure Off (Port : Digital_Port);
end HW.GFX.GMA.Connectors.DDI;

View File

@ -0,0 +1,93 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Panel;
with HW.GFX.GMA.Connectors.DDI;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.Connectors is
procedure Pre_On
(Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Pipe_Hint : in Word32;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
DDI.Pre_On (Port_Cfg, PLL_Hint, Success);
end Pre_On;
procedure Post_On
(Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
DDI.Post_On (Port_Cfg);
if Port_Cfg.Port = DIGI_A then
Panel.Backlight_On;
end if;
Success := True;
end Post_On;
----------------------------------------------------------------------------
procedure Pre_Off (Port_Cfg : Port_Config)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Port = DIGI_A then
Panel.Backlight_Off;
Panel.Off;
end if;
end Pre_Off;
procedure Post_Off (Port_Cfg : Port_Config)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
DDI.Off (Port_Cfg.Port);
end Post_Off;
----------------------------------------------------------------------------
procedure Pre_All_Off
is
begin
Panel.Backlight_Off;
Panel.Off;
end Pre_All_Off;
procedure Post_All_Off
is
begin
for Port in Digital_Port range DIGI_A .. DIGI_D loop
DDI.Off (Port);
end loop;
if Config.FDI_Port (DIGI_E) then
DDI.Off (DIGI_E);
end if;
end Post_All_Off;
end HW.GFX.GMA.Connectors;

View File

@ -0,0 +1,189 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.Port_Detect
is
PCH_ADPA_CRT_HPD_CHANNEL_MASK : constant := 3 * 2 ** 24;
PCH_ADPA_CRT_HPD_ENABLE : constant := 1 * 2 ** 23;
SFUSE_STRAP_CRT_DAC_CAP_DISABLE : constant := 1 * 2 ** 6;
HOTPLUG_CTL_DDI_A_HPD_INPUT_ENABLE : constant := 1 * 2 ** 4;
HOTPLUG_CTL_DDI_A_HPD_STATUS : constant := 3 * 2 ** 0;
HOTPLUG_CTL_DDI_A_HPD_LONG_DETECT : constant := 1 * 2 ** 1;
SHOTPLUG_CTL_DETECT_MASK : constant := 16#0303_0303#;
type Digital_Port_Value is array (Digital_Port) of Word32;
DDI_PORT_DETECTED : constant Digital_Port_Value :=
(DIGI_B => 1 * 2 ** 2,
DIGI_C => 1 * 2 ** 1,
DIGI_D => 1 * 2 ** 0,
DIGI_A => 1 * 2 ** 0,
others => 0);
SHOTPLUG_CTL_HPD_INPUT_ENABLE : constant Digital_Port_Value :=
(DIGI_B => 1 * 2 ** 4,
DIGI_C => 1 * 2 ** 12,
DIGI_D => 1 * 2 ** 20,
DIGI_A => 1 * 2 ** 28,
others => 0);
SHOTPLUG_CTL_HPD_STATUS : constant Digital_Port_Value :=
(DIGI_B => 3 * 2 ** 0,
DIGI_C => 3 * 2 ** 8,
DIGI_D => 3 * 2 ** 16,
DIGI_A => 3 * 2 ** 24,
others => 0);
SHOTPLUG_CTL_LONG_DETECT : constant Digital_Port_Value :=
(DIGI_B => 1 * 2 ** 1,
DIGI_C => 1 * 2 ** 9,
DIGI_D => 1 * 2 ** 17,
DIGI_A => 1 * 2 ** 25,
others => 0);
procedure Initialize
is
DAC_Disabled,
Internal_Detected,
DDI_Detected : Boolean;
Last_Digital_Port : constant Digital_Port :=
(if Config.Has_DDI_D then DIGI_D else DIGI_C);
subtype Ext_Digital_Port is
Digital_Port range DIGI_B .. DIGI_D;
type Digital_Port_To_GMA_Port is array (Ext_Digital_Port) of Port_Type;
To_HDMI_Port : constant Digital_Port_To_GMA_Port :=
(DIGI_B => Digital1,
DIGI_C => Digital2,
DIGI_D => Digital3);
To_DP_Port : constant Digital_Port_To_GMA_Port :=
(DIGI_B => DP1,
DIGI_C => DP2,
DIGI_D => DP3);
begin
if Config.Has_PCH_DAC then
-- PCH_DAC (_A)
Registers.Is_Set_Mask
(Register => Registers.SFUSE_STRAP,
Mask => SFUSE_STRAP_CRT_DAC_CAP_DISABLE,
Result => DAC_Disabled);
if not DAC_Disabled then
Registers.Set_Mask
(Register => Registers.PCH_ADPA,
Mask => PCH_ADPA_CRT_HPD_CHANNEL_MASK or -- clear status
PCH_ADPA_CRT_HPD_ENABLE);
end if;
Config.Valid_Port (Analog) := not DAC_Disabled;
end if;
if Config.Internal_Is_EDP then
-- DDI_A
Registers.Is_Set_Mask
(Register => Registers.DDI_BUF_CTL_A,
Mask => DDI_PORT_DETECTED (DIGI_A),
Result => Internal_Detected);
if Internal_Detected then
if Config.Has_HOTPLUG_CTL then
Registers.Set_Mask
(Register => Registers.HOTPLUG_CTL,
Mask => HOTPLUG_CTL_DDI_A_HPD_INPUT_ENABLE or
HOTPLUG_CTL_DDI_A_HPD_STATUS); -- clear status
if Config.Has_SHOTPLUG_CTL_A then
-- Have to enable south hotplug too on SoCs.
Registers.Unset_And_Set_Mask
(Register => Registers.SHOTPLUG_CTL,
Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
Mask_Set => SHOTPLUG_CTL_HPD_INPUT_ENABLE (DIGI_A));
end if;
else
Registers.Unset_And_Set_Mask
(Register => Registers.SHOTPLUG_CTL,
Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
Mask_Set => SHOTPLUG_CTL_HPD_INPUT_ENABLE (DIGI_A) or
SHOTPLUG_CTL_HPD_STATUS (DIGI_A)); -- clear
end if;
end if;
else
Internal_Detected := False;
end if;
Config.Valid_Port (Internal) := Internal_Detected;
-- DDI_[BCD]
for Port in Ext_Digital_Port range DIGI_B .. Last_Digital_Port loop
Registers.Is_Set_Mask
(Register => Registers.SFUSE_STRAP,
Mask => DDI_PORT_DETECTED (Port),
Result => DDI_Detected);
Config.Valid_Port (To_HDMI_Port (Port)) :=
Config.Valid_Port (To_HDMI_Port (Port)) and DDI_Detected;
Config.Valid_Port (To_DP_Port (Port)) :=
Config.Valid_Port (To_DP_Port (Port)) and DDI_Detected;
if DDI_Detected then
Registers.Unset_And_Set_Mask
(Register => Registers.SHOTPLUG_CTL,
Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
Mask_Set => SHOTPLUG_CTL_HPD_INPUT_ENABLE (Port) or
SHOTPLUG_CTL_HPD_STATUS (Port)); -- clear status
else
Registers.Unset_Mask
(Register => Registers.SHOTPLUG_CTL,
Mask => SHOTPLUG_CTL_DETECT_MASK or
SHOTPLUG_CTL_HPD_INPUT_ENABLE (Port));
end if;
end loop;
end Initialize;
procedure Hotplug_Detect (Port_Cfg : in Port_Config; Detected : out Boolean)
is
Ctl32 : Word32;
begin
if Port_Cfg.Display = VGA then
Registers.Read (Registers.PCH_ADPA, Ctl32, Verbose => False);
Ctl32 := Ctl32 and PCH_ADPA_CRT_HPD_CHANNEL_MASK;
Detected := Ctl32 = PCH_ADPA_CRT_HPD_CHANNEL_MASK;
if Ctl32 /= 0 then
Registers.Set_Mask
(Register => Registers.PCH_ADPA,
Mask => PCH_ADPA_CRT_HPD_CHANNEL_MASK);
end if;
elsif Config.Has_HOTPLUG_CTL and then Port_Cfg.Port = DIGI_A then
Registers.Read (Registers.HOTPLUG_CTL, Ctl32, Verbose => False);
Detected := (Ctl32 and HOTPLUG_CTL_DDI_A_HPD_LONG_DETECT) /= 0;
if (Ctl32 and HOTPLUG_CTL_DDI_A_HPD_STATUS) /= 0 then
Registers.Set_Mask
(Register => Registers.HOTPLUG_CTL,
Mask => HOTPLUG_CTL_DDI_A_HPD_STATUS);
end if;
elsif Port_Cfg.Port in DIGI_A .. DIGI_D then
Registers.Read (Registers.SHOTPLUG_CTL, Ctl32, Verbose => False);
Detected :=
(Ctl32 and SHOTPLUG_CTL_LONG_DETECT (Port_Cfg.Port)) /= 0;
if (Ctl32 and SHOTPLUG_CTL_HPD_STATUS (Port_Cfg.Port)) /= 0 then
Registers.Unset_And_Set_Mask
(Register => Registers.SHOTPLUG_CTL,
Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
Mask_Set => SHOTPLUG_CTL_HPD_STATUS (Port_Cfg.Port));
end if;
else
Detected := False;
end if;
end Hotplug_Detect;
end HW.GFX.GMA.Port_Detect;

View File

@ -0,0 +1,235 @@
--
-- Copyright (C) 2014-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with GNAT.Source_Info;
with HW.Time;
with HW.Debug;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.Power_And_Clocks_Haswell is
PWR_WELL_CTL_ENABLE_REQUEST : constant := 1 * 2 ** 31;
PWR_WELL_CTL_DISABLE_REQUEST : constant := 0 * 2 ** 31;
PWR_WELL_CTL_STATE_ENABLED : constant := 1 * 2 ** 30;
----------------------------------------------------------------------------
SRD_CTL_ENABLE : constant := 1 * 2 ** 31;
SRD_STATUS_STATE_MASK : constant := 7 * 2 ** 29;
type Pipe is (EDP, A, B, C);
type SRD_Regs is record
CTL : Registers.Registers_Index;
STATUS : Registers.Registers_Index;
end record;
type SRD_Per_Pipe_Regs is array (Pipe) of SRD_Regs;
SRD : constant SRD_Per_Pipe_Regs := SRD_Per_Pipe_Regs'
(A => SRD_Regs'
(CTL => Registers.SRD_CTL_A,
STATUS => Registers.SRD_STATUS_A),
B => SRD_Regs'
(CTL => Registers.SRD_CTL_B,
STATUS => Registers.SRD_STATUS_B),
C => SRD_Regs'
(CTL => Registers.SRD_CTL_C,
STATUS => Registers.SRD_STATUS_C),
EDP => SRD_Regs'
(CTL => Registers.SRD_CTL_EDP,
STATUS => Registers.SRD_STATUS_EDP));
----------------------------------------------------------------------------
IPS_CTL_ENABLE : constant := 1 * 2 ** 31;
DISPLAY_IPS_CONTROL : constant := 16#19#;
GT_MAILBOX_READY : constant := 1 * 2 ** 31;
----------------------------------------------------------------------------
procedure PSR_Off
is
Enabled : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.Has_Per_Pipe_SRD then
for P in Pipe loop
Registers.Is_Set_Mask (SRD (P).CTL, SRD_CTL_ENABLE, Enabled);
if Enabled then
Registers.Unset_Mask (SRD (P).CTL, SRD_CTL_ENABLE);
Registers.Wait_Unset_Mask (SRD (P).STATUS, SRD_STATUS_STATE_MASK);
pragma Debug (Debug.Put_Line ("Disabled PSR."));
end if;
end loop;
else
Registers.Is_Set_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE, Enabled);
if Enabled then
Registers.Unset_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE);
Registers.Wait_Unset_Mask (Registers.SRD_STATUS, SRD_STATUS_STATE_MASK);
pragma Debug (Debug.Put_Line ("Disabled PSR."));
end if;
end if;
end PSR_Off;
----------------------------------------------------------------------------
procedure GT_Mailbox_Write (MBox : Word32; Value : Word32) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
Registers.Write (Registers.GT_MAILBOX_DATA, Value);
Registers.Write (Registers.GT_MAILBOX, GT_MAILBOX_READY or MBox);
Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
Registers.Write (Registers.GT_MAILBOX_DATA, 0);
end GT_Mailbox_Write;
procedure IPS_Off
is
Enabled : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.Has_IPS then
Registers.Is_Set_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE, Enabled);
if Enabled then
if Config.Has_IPS_CTL_Mailbox then
GT_Mailbox_Write (DISPLAY_IPS_CONTROL, 0);
-- May take up to 42ms.
Registers.Wait_Unset_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE);
else
Registers.Unset_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE);
end if;
pragma Debug (Debug.Put_Line ("Disabled IPS."));
-- We have to wait until the next vblank here.
-- 20ms should be enough.
Time.M_Delay (20);
end if;
end if;
end IPS_Off;
----------------------------------------------------------------------------
procedure PDW_Off
is
Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); -- Result for debugging only
pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); -- Result for debugging only
if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
PWR_WELL_CTL_ENABLE_REQUEST) /= 0
then
Registers.Wait_Set_Mask
(Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
end if;
if (Ctl1 and PWR_WELL_CTL_ENABLE_REQUEST) /= 0 then
Registers.Write (Registers.PWR_WELL_CTL_BIOS, PWR_WELL_CTL_DISABLE_REQUEST);
end if;
if (Ctl2 and PWR_WELL_CTL_ENABLE_REQUEST) /= 0 then
Registers.Write (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_DISABLE_REQUEST);
end if;
end PDW_Off;
procedure PDW_On
is
Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); -- Result for debugging only
pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); -- Result for debugging only
if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
PWR_WELL_CTL_ENABLE_REQUEST) = 0
then
Registers.Wait_Unset_Mask
(Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
end if;
if (Ctl2 and PWR_WELL_CTL_ENABLE_REQUEST) = 0 then
Registers.Write (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_ENABLE_REQUEST);
Registers.Wait_Set_Mask
(Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
end if;
end PDW_On;
function Need_PDW (Checked_Configs : Configs_Type) return Boolean is
begin
return (Checked_Configs (Primary).Port /= Disabled and
Checked_Configs (Primary).Port /= Internal) or
Checked_Configs (Secondary).Port /= Disabled or
Checked_Configs (Tertiary).Port /= Disabled;
end Need_PDW;
----------------------------------------------------------------------------
procedure Pre_All_Off is
begin
-- HSW: disable panel self refresh (PSR) on eDP if enabled
-- wait for PSR idling
PSR_Off;
IPS_Off;
end Pre_All_Off;
procedure Initialize is
begin
-- HSW: disable power down well
PDW_Off;
end Initialize;
procedure Power_Set_To (Configs : Configs_Type) is
begin
if Need_PDW (Configs) then
PDW_On;
else
PDW_Off;
end if;
end Power_Set_To;
procedure Power_Up (Old_Configs, New_Configs : Configs_Type) is
begin
if not Need_PDW (Old_Configs) and Need_PDW (New_Configs) then
PDW_On;
end if;
end Power_Up;
procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type)
is
begin
if (Need_PDW (Old_Configs) or Need_PDW (Tmp_Configs)) and
not Need_PDW (New_Configs)
then
PDW_Off;
end if;
end Power_Down;
end HW.GFX.GMA.Power_And_Clocks_Haswell;

View File

@ -0,0 +1,27 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.Power_And_Clocks_Haswell is
procedure PSR_Off;
procedure Pre_All_Off;
procedure Post_All_Off is null;
procedure Initialize;
procedure Power_Set_To (Configs : Configs_Type);
procedure Power_Up (Old_Configs, New_Configs : Configs_Type);
procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type);
end HW.GFX.GMA.Power_And_Clocks_Haswell;

392
common/hw-gfx-dp_aux_ch.adb Normal file
View File

@ -0,0 +1,392 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.DP_Defs;
use type HW.Word8;
use type HW.GFX.DP_Defs.Aux_Message_Command;
package body HW.GFX.DP_Aux_Ch is
DP_AUX_I2C_WRITE : constant := 16#0#;
DP_AUX_I2C_READ : constant := 16#1#;
DP_AUX_I2C_WR_STATUS_REQ : constant := 16#2#;
DP_AUX_I2C_MOT : constant := 16#4#;
DP_AUX_NATIVE_WRITE : constant := 16#8#;
DP_AUX_NATIVE_READ : constant := 16#9#;
procedure Fill_Aux_Request
(Request : out DP_Defs.Aux_Request;
Command : in DP_Defs.Aux_Message_Command;
Address : in DP_Defs.Aux_Message_Address;
Length : in DP_Defs.Aux_Payload_Length)
is
begin
Request :=
(0 => Shift_Left (Word8 (Command), 4) or
Word8 (Shift_Right (Word32 (Address), 16)),
1 => Word8 (Shift_Right (Word32 (Address), 8) and 16#ff#),
2 => Word8 (Shift_Right (Word32 (Address), 0) and 16#ff#),
3 => Word8 (Length) - 1,
others => 0); -- Don't care
end Fill_Aux_Request;
function Is_Empty (Request : DP_Defs.Aux_Request) return Boolean is
begin
return Request (3) = 16#ff#;
end Is_Empty;
function Is_Aux_Ack (Response : DP_Defs.Aux_Response) return Boolean
with
Depends => (Is_Aux_Ack'Result => Response)
is
begin
return (Response (0) and 16#30#) = 16#00#;
end Is_Aux_Ack;
function Is_Aux_Defer (Response : DP_Defs.Aux_Response) return Boolean is
begin
return (Response (0) and 16#30#) = 16#20#;
end Is_Aux_Defer;
function Is_I2C_Ack (Response : DP_Defs.Aux_Response) return Boolean
with
Depends => (Is_I2C_Ack'Result => Response)
is
begin
return (Response (0) and 16#c0#) = 16#00#;
end Is_I2C_Ack;
function Is_I2C_Defer (Response : DP_Defs.Aux_Response) return Boolean is
begin
return (Response (0) and 16#c0#) = 16#80#;
end Is_I2C_Defer;
----------------------------------------------------------------------------
procedure Do_Aux_Request
(Port : in T;
Request : in DP_Defs.Aux_Request;
Request_Length : in DP_Defs.Aux_Request_Length;
Response : out DP_Defs.Aux_Response;
Response_Length : out DP_Defs.Aux_Response_Length;
Success : out Boolean)
is
begin
for Try in Positive range 1 .. 32 loop
Aux_Request
(Port => Port,
Request => Request,
Request_Length => Request_Length,
Response => Response,
Response_Length => Response_Length,
Success => Success);
exit when not (Success and Is_Aux_Defer (Response));
Time.U_Delay (500);
end loop;
Success := Success and then Is_Aux_Ack (Response);
end Do_Aux_Request;
----------------------------------------------------------------------------
procedure Aux_Read
(Port : in T;
Address : in DP_Defs.Aux_Message_Address;
Length : in out DP_Defs.Aux_Payload_Length;
Data : out DP_Defs.Aux_Payload;
Success : out Boolean)
is
Request : DP_Defs.Aux_Request;
Response : DP_Defs.Aux_Response;
Response_Length : DP_Defs.Aux_Response_Length;
begin
Data := (others => 0); -- Initialize
Fill_Aux_Request
(Request => Request,
Command => DP_AUX_NATIVE_READ,
Address => Address,
Length => Length);
Do_Aux_Request
(Port => Port,
Request => Request,
Request_Length => 4,
Response => Response,
Response_Length => Response_Length,
Success => Success);
Success := Success and then Response_Length > 1;
if Success then
pragma Assert (Response_Length > 1);
Length := Response_Length - 1;
Data (0 .. Length - 1) := Response (1 .. Length);
end if;
end Aux_Read;
procedure Aux_Write
(Port : in T;
Address : in DP_Defs.Aux_Message_Address;
Length : in DP_Defs.Aux_Payload_Length;
Data : in DP_Defs.Aux_Payload;
Success : out Boolean)
is
Request : DP_Defs.Aux_Request;
Ignored_Response : DP_Defs.Aux_Response;
Ignored_Response_Length : DP_Defs.Aux_Response_Length;
begin
Fill_Aux_Request
(Request => Request,
Command => DP_AUX_NATIVE_WRITE,
Address => Address,
Length => Length);
Request (4 .. Length + 4 - 1) := Data (0 .. Length - 1);
pragma Warnings (GNATprove, Off,
"unused assignment to ""Ignored_Response*""",
Reason => "No response expected here");
Do_Aux_Request
(Port => Port,
Request => Request,
Request_Length => 4 + Length,
Response => Ignored_Response,
Response_Length => Ignored_Response_Length,
Success => Success);
end Aux_Write;
----------------------------------------------------------------------------
procedure I2C_Out_Packet
(Port : in T;
Command : in DP_Defs.Aux_Message_Command;
Address : in DP_Defs.Aux_Message_Address;
Length : in DP_Defs.Aux_Payload_Length;
Data : in DP_Defs.Aux_Payload;
Success : out Boolean)
is
Request : DP_Defs.Aux_Request;
Response : DP_Defs.Aux_Response;
Ignored_Response_Length : DP_Defs.Aux_Response_Length;
begin
Fill_Aux_Request
(Request => Request,
Command => Command,
Address => Address,
Length => Length);
Request (4 .. Length + 4 - 1) := Data (0 .. Length - 1);
for Try in Positive range 1 .. 7 loop
pragma Warnings (GNATprove, Off,
"unused assignment to ""Ignored_Response_Length""",
Reason => "No response expected here");
Do_Aux_Request
(Port => Port,
Request => Request,
Request_Length => (if Is_Empty (Request) then 3 else 4 + Length),
Response => Response,
Response_Length => Ignored_Response_Length,
Success => Success);
exit when not (Success and Is_I2C_Defer (Response));
-- Command was already AUX-acked. Thus, only query for
-- new status from now on until we get I2C-acked too.
Fill_Aux_Request
(Request => Request,
Command => (Command and DP_AUX_I2C_MOT) or DP_AUX_I2C_WR_STATUS_REQ,
Address => Address,
Length => 0);
Time.U_Delay (500);
end loop;
Success := Success and then Is_I2C_Ack (Response);
end I2C_Out_Packet;
procedure I2C_In_Packet
(Port : in T;
Command : in DP_Defs.Aux_Message_Command;
Address : in DP_Defs.Aux_Message_Address;
Length : in DP_Defs.Aux_Payload_Length;
Response : out DP_Defs.Aux_Response;
Response_Length : out DP_Defs.Aux_Response_Length;
Success : out Boolean)
is
Request : DP_Defs.Aux_Request;
begin
Fill_Aux_Request
(Request => Request,
Command => Command,
Address => Address,
Length => Length);
for Try in Positive range 1 .. 7 loop
Do_Aux_Request
(Port => Port,
Request => Request,
Request_Length => (if Is_Empty (Request) then 3 else 4),
Response => Response,
Response_Length => Response_Length,
Success => Success);
exit when not (Success and Is_I2C_Defer (Response));
Time.U_Delay (500);
end loop;
Success := Success and then Is_I2C_Ack (Response);
end I2C_In_Packet;
procedure I2C_Empty_Packet
(Port : in T;
Command : in DP_Defs.Aux_Message_Command;
Address : in DP_Defs.Aux_Message_Address;
Success : out Boolean)
is
Ignored_Response : DP_Defs.Aux_Response;
Ignored_Response_Length : DP_Defs.Aux_Response_Length;
begin
pragma Warnings (GNATprove, Off,
"unused assignment to ""Ignored_Response*""",
Reason => "No response expected here");
I2C_In_Packet
(Port => Port,
Command => Command,
Address => Address,
Length => 0,
Response => Ignored_Response,
Response_Length => Ignored_Response_Length,
Success => Success);
end I2C_Empty_Packet;
----------------------------------------------------------------------------
procedure Do_I2C_Write
(Port : in T;
Address : in I2C.Transfer_Address;
Length : in DP_Defs.Aux_Payload_Length;
Data : in DP_Defs.Aux_Payload;
Success : out Boolean)
is
Ignored_Success : Boolean;
begin
-- I2C address "start" packet
I2C_Empty_Packet
(Port => Port,
Command => DP_AUX_I2C_WRITE or DP_AUX_I2C_MOT,
Address => DP_Defs.Aux_Message_Address (Address),
Success => Success);
if Success then
I2C_Out_Packet
(Port => Port,
Command => DP_AUX_I2C_WRITE or DP_AUX_I2C_MOT,
Address => DP_Defs.Aux_Message_Address (Address),
Length => Length,
Data => Data,
Success => Success);
pragma Warnings
(GNATprove, Off, "unused assignment to ""Ignored_Success""",
Reason => "Doesn't matter as long as the transfer itself succeeds");
-- I2C address "stop" packet
I2C_Empty_Packet
(Port => Port,
Command => DP_AUX_I2C_WRITE,
Address => DP_Defs.Aux_Message_Address (Address),
Success => Ignored_Success);
end if;
end Do_I2C_Write;
procedure Do_I2C_Read
(Port : in T;
Address : in I2C.Transfer_Address;
Length : in out I2C.Transfer_Length;
Data : in out I2C.Transfer_Data;
Success : out Boolean)
is
Xfered : Natural := 0;
Chunk : DP_Defs.Aux_Payload_Length := DP_Defs.Aux_Payload_Length'Last;
Tries : Natural := 0;
Max_Tries : constant := 4;
Response : DP_Defs.Aux_Response;
Response_Length : DP_Defs.Aux_Response_Length;
Ignored_Success : Boolean;
begin
-- I2C address "start" packet
I2C_Empty_Packet
(Port => Port,
Command => DP_AUX_I2C_READ or DP_AUX_I2C_MOT,
Address => DP_Defs.Aux_Message_Address (Address),
Success => Success);
while Success and then (Xfered < Length and Tries < Max_Tries) loop
I2C_In_Packet
(Port => Port,
Command => DP_AUX_I2C_READ or DP_AUX_I2C_MOT,
Address => DP_Defs.Aux_Message_Address (Address),
Length => Natural'Min (Chunk, Length - Xfered),
Response => Response,
Response_Length => Response_Length,
Success => Success);
if Success and then Response_Length >= 2 then
Chunk := Natural'Min (Response_Length - 1, Length - Xfered);
Data (Xfered .. Xfered + Chunk - 1) := Response (1 .. Chunk);
Xfered := Xfered + Chunk;
Tries := 0;
else
Tries := Tries + 1;
end if;
pragma Loop_Invariant (Xfered <= Length);
end loop;
if Success then
pragma Warnings
(GNATprove, Off, "unused assignment to ""Ignored_Success""",
Reason => "Doesn't matter as long as the transfer itself succeeds");
-- I2C address "stop" packet
I2C_Empty_Packet
(Port => Port,
Command => DP_AUX_I2C_READ,
Address => DP_Defs.Aux_Message_Address (Address),
Success => Ignored_Success);
end if;
Success := Success and then Tries < Max_Tries;
Length := Xfered;
end Do_I2C_Read;
----------------------------------------------------------------------------
procedure I2C_Read
(Port : in T;
Address : in I2C.Transfer_Address;
Length : in out I2C.Transfer_Length;
Data : out I2C.Transfer_Data;
Success : out Boolean)
is
Index_Payload : DP_Defs.Aux_Payload;
begin
Data := (others => 16#00#);
Index_Payload := (others => 16#00#); -- send index 0
Do_I2C_Write (Port, Address, 1, Index_Payload, Success);
if Success then
Do_I2C_Read (Port, Address, Length, Data, Success);
end if;
end I2C_Read;
end HW.GFX.DP_Aux_Ch;

View File

@ -0,0 +1,54 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.I2C;
with HW.GFX.DP_Defs;
private generic
type T (<>) is limited private;
with procedure Aux_Request
(Port : in T;
Request : in DP_Defs.Aux_Request;
Request_Length : in DP_Defs.Aux_Request_Length;
Response : out DP_Defs.Aux_Response;
Response_Length : out DP_Defs.Aux_Response_Length;
Success : out Boolean);
package HW.GFX.DP_Aux_Ch is
procedure Aux_Read
(Port : in T;
Address : in DP_Defs.Aux_Message_Address;
Length : in out DP_Defs.Aux_Payload_Length;
Data : out DP_Defs.Aux_Payload;
Success : out Boolean);
procedure Aux_Write
(Port : in T;
Address : in DP_Defs.Aux_Message_Address;
Length : in DP_Defs.Aux_Payload_Length;
Data : in DP_Defs.Aux_Payload;
Success : out Boolean);
----------------------------------------------------------------------------
procedure I2C_Read
(Port : in T;
Address : in I2C.Transfer_Address;
Length : in out I2C.Transfer_Length;
Data : out I2C.Transfer_Data;
Success : out Boolean);
end HW.GFX.DP_Aux_Ch;

32
common/hw-gfx-dp_defs.ads Normal file
View File

@ -0,0 +1,32 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.DP_Defs is
type Aux_Message_Command is mod 2 ** 4;
type Aux_Message_Address is mod 2 ** 20;
subtype Aux_Payload_Length is Natural range 0 .. 16;
subtype Aux_Payload_Index is Natural range 0 .. Aux_Payload_Length'Last - 1;
subtype Aux_Payload is Buffer (Aux_Payload_Index);
subtype Aux_Request_Length is Natural range 3 .. 20;
subtype Aux_Request_Index is Natural range 0 .. Aux_Request_Length'Last - 1;
subtype Aux_Request is Buffer (Aux_Request_Index);
subtype Aux_Response_Length is Natural range 1 .. 17;
subtype Aux_Response_Index is
Natural range 0 .. Aux_Response_Length'Last - 1;
subtype Aux_Response is Buffer (Aux_Response_Index);
end HW.GFX.DP_Defs;

380
common/hw-gfx-dp_info.adb Normal file
View File

@ -0,0 +1,380 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with Ada.Unchecked_Conversion;
with HW.Debug;
with GNAT.Source_Info;
with HW.GFX.DP_Defs;
use type HW.Word8;
package body HW.GFX.DP_Info is
procedure Read_Caps
(Link : in out DP_Link;
Port : in T;
Success : out Boolean)
is
Data : DP_Defs.Aux_Payload;
Length : DP_Defs.Aux_Payload_Length;
Caps_Size : constant := 15;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Length := Caps_Size;
Aux_Ch.Aux_Read
(Port => Port,
Address => 16#00000#,
Length => Length,
Data => Data,
Success => Success);
Success := Success and Length = Caps_Size;
if Length = Caps_Size then
Link.Receiver_Caps.Rev := Data (0);
case Data (1) is
when 16#06# =>
Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_1_62;
when 16#0a# =>
Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
when 16#14# =>
Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_5_4;
when others =>
if Data (1) > 16#14# then
Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_5_4;
else
Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_1_62;
end if;
end case;
case Data (2) and 16#1f# is
when 0 | 1 =>
Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_1;
when 2 | 3 =>
Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
when others =>
Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_4;
end case;
Link.Receiver_Caps.TPS3_Supported := (Data (2) and 16#40#) /= 0;
Link.Receiver_Caps.Enhanced_Framing := (Data (2) and 16#80#) /= 0;
Link.Receiver_Caps.No_Aux_Handshake := (Data (3) and 16#40#) /= 0;
Link.Receiver_Caps.Aux_RD_Interval := Data (14);
pragma Debug (Debug.New_Line);
pragma Debug (Debug.Put_Line ("DPCD:"));
pragma Debug (Debug.Put_Reg8 (" Rev ", Data (0)));
pragma Debug (Debug.Put_Reg8 (" Max_Link_Rate ", Data (1)));
pragma Debug (Debug.Put_Reg8 (" Max_Lane_Count ", Data (2) and 16#1f#));
pragma Debug (Debug.Put_Reg8 (" TPS3_Supported ", Data (2) and 16#40#));
pragma Debug (Debug.Put_Reg8 (" Enhanced_Framing", Data (2) and 16#80#));
pragma Debug (Debug.Put_Reg8 (" No_Aux_Handshake", Data (3) and 16#40#));
pragma Debug (Debug.Put_Reg8 (" Aux_RD_Interval ", Data (14)));
pragma Debug (Debug.New_Line);
end if;
end Read_Caps;
procedure Minimum_Lane_Count
(Link : in out DP_Link;
Mode : in Mode_Type;
Success : out Boolean)
with
Depends => ((Link, Success) => (Link, Mode))
is
function Link_Pixel_Per_Second
(Link_Rate : DP_Bandwidth)
return Positive
with
Post => Pos64 (Link_Pixel_Per_Second'Result) <=
((DP_Symbol_Rate_Type'Last * 8) / 3) / BPC_Type'First
is
begin
-- Link_Rate is brutto with 8/10 bit symbols; three colors
pragma Assert (Positive (DP_Symbol_Rate (Link_Rate)) <= (Positive'Last / 8) * 3);
pragma Assert ((Int64 (DP_Symbol_Rate (Link_Rate)) * 8) / 3
>= Int64 (BPC_Type'Last));
return Positive
(((Int64 (DP_Symbol_Rate (Link_Rate)) * 8) / 3)
/ Int64 (Mode.BPC));
end Link_Pixel_Per_Second;
Count : Natural;
begin
Count := Link_Pixel_Per_Second (Link.Bandwidth);
Count := (Positive (Mode.Dotclock) + Count - 1) / Count;
Success := True;
case Count is
when 1 => Link.Lane_Count := DP_Lane_Count_1;
when 2 => Link.Lane_Count := DP_Lane_Count_2;
when 3 | 4 => Link.Lane_Count := DP_Lane_Count_4;
when others => Success := False;
end case;
end Minimum_Lane_Count;
procedure Preferred_Link_Setting
(Link : in out DP_Link;
Mode : in Mode_Type;
Success : out Boolean)
is
begin
Link.Bandwidth := Link.Receiver_Caps.Max_Link_Rate;
Link.Enhanced_Framing := Link.Receiver_Caps.Enhanced_Framing;
Minimum_Lane_Count (Link, Mode, Success);
Success := Success and
Link.Lane_Count <= Link.Receiver_Caps.Max_Lane_Count;
pragma Debug (Success, Debug.Put ("Trying DP settings: Symbol Rate = "));
pragma Debug (Success, Debug.Put_Int32
(Int32 (DP_Symbol_Rate (Link.Bandwidth))));
pragma Debug (Success, Debug.Put ("; Lane Count = "));
pragma Debug (Success, Debug.Put_Int32
(Int32 (Lane_Count_As_Integer (Link.Lane_Count))));
pragma Debug (Success, Debug.New_Line);
pragma Debug (Success, Debug.New_Line);
pragma Debug (not Success, Debug.Put_Line
("Mode requirements exceed available bandwidth!"));
end Preferred_Link_Setting;
procedure Next_Link_Setting
(Link : in out DP_Link;
Mode : in Mode_Type;
Success : out Boolean)
is
begin
if Link.Bandwidth > DP_Bandwidth'First then
Link.Bandwidth := DP_Bandwidth'Pred (Link.Bandwidth);
Minimum_Lane_Count (Link, Mode, Success);
Success := Success and
Link.Lane_Count <= Link.Receiver_Caps.Max_Lane_Count;
else
Success := False;
end if;
pragma Debug (Success, Debug.Put ("Trying DP settings: Symbol Rate = "));
pragma Debug (Success, Debug.Put_Int32
(Int32 (DP_Symbol_Rate (Link.Bandwidth))));
pragma Debug (Success, Debug.Put ("; Lane Count = "));
pragma Debug (Success, Debug.Put_Int32
(Int32 (Lane_Count_As_Integer (Link.Lane_Count))));
pragma Debug (Success, Debug.New_Line);
pragma Debug (Success, Debug.New_Line);
end Next_Link_Setting;
----------------------------------------------------------------------------
procedure Calculate_M_N
(Link : in DP_Link;
Mode : in Mode_Type;
Data_M : out M_Type;
Data_N : out N_Type;
Link_M : out M_Type;
Link_N : out N_Type)
is
DATA_N_MAX : constant := 16#800000#;
LINK_N_MAX : constant := 16#100000#;
subtype Calc_M_Type is Int64 range 0 .. 2 ** 36;
subtype Calc_N_Type is Int64 range 0 .. 2 ** 36;
subtype N_Rounded_Type is Int64 range
0 .. Int64'Max (DATA_N_MAX, LINK_N_MAX);
M : Calc_M_Type;
N : Calc_N_Type;
procedure Cancel_M_N
(M : in out Calc_M_Type;
N : in out Calc_N_Type;
N_Max : in N_Rounded_Type)
with
Depends => ((M, N) => (M, N, N_max)),
Pre => (N > 0 and M in 0 .. Calc_M_Type'Last / 2),
Post => (M <= M_N_Max and N <= M_N_Max)
is
Orig_N : constant Calc_N_Type := N;
function Round_N (N : Calc_N_Type) return N_Rounded_Type
with
Post => (Round_N'Result <= N * 2)
is
RN : Calc_N_Type;
RN2 : Calc_N_Type := N_Max;
begin
loop
RN := RN2;
RN2 := RN2 / 2;
exit when RN2 < N;
pragma Loop_Invariant (RN2 = RN / 2 and RN2 in N .. N_Max);
end loop;
return RN;
end Round_N;
begin
N := Round_N (N);
-- The automatic provers need a little nudge here.
pragma Assert
(if M <= Calc_M_Type'Last/2 and
N <= Orig_N * 2 and
Orig_N > 0 and
M > 0
then
M * N / Orig_N <= Calc_M_Type'Last);
pragma Annotate (GNATprove, False_Positive,
"assertion might fail",
"The property cannot be proven automatically. An Isabelle proof is included as an axiom");
M := M * N / Orig_N;
-- This loop is never hit for sane values (i.e. M <= N) but
-- we have to make sure returned values are always in range.
while M > M_N_Max loop
pragma Loop_Invariant (N <= M_N_Max);
M := M / 2;
N := N / 2;
end loop;
end Cancel_M_N;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
pragma Assert (3
* Mode.BPC
* Mode.Dotclock
in Pos64);
M := 3
* Mode.BPC
* Mode.Dotclock;
pragma Assert (8
* DP_Symbol_Rate (Link.Bandwidth)
* Lane_Count_As_Integer (Link.Lane_Count)
in Pos64);
N := 8
* DP_Symbol_Rate (Link.Bandwidth)
* Lane_Count_As_Integer (Link.Lane_Count);
Cancel_M_N (M, N, DATA_N_MAX);
Data_M := M;
Data_N := N;
-------------------------------------------------------------------
M := Pos64 (Mode.Dotclock);
N := Pos64 (DP_Symbol_Rate (Link.Bandwidth));
Cancel_M_N (M, N, LINK_N_MAX);
Link_M := M;
Link_N := N;
end Calculate_M_N;
----------------------------------------------------------------------------
procedure Read_Link_Status
(Port : in T;
Status : out Link_Status;
Success : out Boolean)
is
subtype Status_Index is DP_Defs.Aux_Payload_Index range 0 .. 5;
subtype Status_Buffer is Buffer (Status_Index);
function Buffer_As_Status is new Ada.Unchecked_Conversion
(Source => Status_Buffer, Target => Link_Status);
Data : DP_Defs.Aux_Payload;
Length : DP_Defs.Aux_Payload_Length;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Length := Status_Index'Last + 1;
Aux_Ch.Aux_Read
(Port => Port,
Address => 16#00202#,
Length => Length,
Data => Data,
Success => Success);
Success := Success and Length = Status_Index'Last + 1;
Status := Buffer_As_Status (Data (Status_Index));
end Read_Link_Status;
function All_CR_Done
(Status : Link_Status;
Link : DP_Link)
return Boolean
is
CR_Done : Boolean := True;
begin
for Lane in Lane_Index
range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
loop
CR_Done := CR_Done and Status.Lanes (Lane).CR_Done;
end loop;
return CR_Done;
end All_CR_Done;
function All_EQ_Done
(Status : Link_Status;
Link : DP_Link)
return Boolean
is
EQ_Done : Boolean := True;
begin
for Lane in Lane_Index
range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
loop
EQ_Done := EQ_Done and Status.Lanes (Lane).CR_Done
and Status.Lanes (Lane).Channel_EQ_Done
and Status.Lanes (Lane).Symbol_Locked;
end loop;
return EQ_Done and Status.Interlane_Align_Done;
end All_EQ_Done;
function Max_Requested_VS
(Status : Link_Status;
Link : DP_Link)
return DP_Voltage_Swing
is
VS : DP_Voltage_Swing := DP_Voltage_Swing'First;
begin
for Lane in Lane_Index
range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
loop
if Status.Adjust_Requests (Lane).Voltage_Swing > VS then
VS := Status.Adjust_Requests (Lane).Voltage_Swing;
end if;
end loop;
return VS;
end Max_Requested_VS;
function Max_Requested_Emph
(Status : Link_Status;
Link : DP_Link)
return DP_Pre_Emph
is
Emph : DP_Pre_Emph := DP_Pre_Emph'First;
begin
for Lane in Lane_Index
range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
loop
if Status.Adjust_Requests (Lane).Pre_Emph > Emph then
Emph := Status.Adjust_Requests (Lane).Pre_Emph;
end if;
end loop;
return Emph;
end Max_Requested_Emph;
end HW.GFX.DP_Info;

135
common/hw-gfx-dp_info.ads Normal file
View File

@ -0,0 +1,135 @@
--
-- Copyright (C) 2015 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.DP_Aux_Ch;
private generic
type T (<>) is limited private;
with package Aux_Ch is new DP_Aux_Ch (T => T, others => <>);
package HW.GFX.DP_Info is
type DP_Voltage_Swing is (VS_Level_0, VS_Level_1, VS_Level_2, VS_Level_3);
type DP_Pre_Emph is (Emph_Level_0, Emph_Level_1, Emph_Level_2, Emph_Level_3);
type Train_Set is record
Voltage_Swing : DP_Voltage_Swing;
Pre_Emph : DP_Pre_Emph;
end record;
type Training_Pattern is (TP_1, TP_2, TP_3, TP_Idle, TP_None);
----------------------------------------------------------------------------
type Lane_Index is new Natural range 0 .. 3;
type Lane_Status is record
CR_Done : Boolean;
Channel_EQ_Done : Boolean;
Symbol_Locked : Boolean;
Reserved : Boolean;
end record;
for Lane_Status use record
CR_Done at 16#00# range 0 .. 0;
Channel_EQ_Done at 16#00# range 1 .. 1;
Symbol_Locked at 16#00# range 2 .. 2;
Reserved at 16#00# range 3 .. 3;
end record;
type Lanes_Status is array (Lane_Index) of Lane_Status;
pragma Pack (Lanes_Status);
type Adjust_Request is record
Voltage_Swing : DP_Voltage_Swing;
Pre_Emph : DP_Pre_Emph;
end record;
for Adjust_Request use record
Voltage_Swing at 16#00# range 0 .. 1;
Pre_Emph at 16#00# range 2 .. 3;
end record;
type Adjust_Requests_Array is array (Lane_Index) of Adjust_Request;
pragma Pack (Adjust_Requests_Array);
type Link_Status is record
Lanes : Lanes_Status;
Interlane_Align_Done : Boolean;
Adjust_Requests : Adjust_Requests_Array;
end record;
for Link_Status use record
Lanes at 16#00# range 0 .. 15;
Interlane_Align_Done at 16#02# range 0 .. 0;
Adjust_Requests at 16#04# range 0 .. 15;
end record;
----------------------------------------------------------------------------
procedure Read_Caps
(Link : in out DP_Link;
Port : in T;
Success : out Boolean);
procedure Preferred_Link_Setting
(Link : in out DP_Link;
Mode : in Mode_Type;
Success : out Boolean);
procedure Next_Link_Setting
(Link : in out DP_Link;
Mode : in Mode_Type;
Success : out Boolean);
----------------------------------------------------------------------------
M_N_Max : constant := 2 ** 24 - 1;
subtype M_Type is Int64 range 0 .. M_N_Max;
subtype N_Type is Int64 range 0 .. M_N_Max;
procedure Calculate_M_N
(Link : in DP_Link;
Mode : in Mode_Type;
Data_M : out M_Type;
Data_N : out N_Type;
Link_M : out M_Type;
Link_N : out N_Type);
----------------------------------------------------------------------------
procedure Read_Link_Status
(Port : in T;
Status : out Link_Status;
Success : out Boolean);
function All_CR_Done
(Status : Link_Status;
Link : DP_Link)
return Boolean;
function All_EQ_Done
(Status : Link_Status;
Link : DP_Link)
return Boolean;
function Max_Requested_VS
(Status : Link_Status;
Link : DP_Link)
return DP_Voltage_Swing;
function Max_Requested_Emph
(Status : Link_Status;
Link : DP_Link)
return DP_Pre_Emph;
end HW.GFX.DP_Info;

View File

@ -0,0 +1,412 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with Ada.Unchecked_Conversion;
with HW.Debug;
with GNAT.Source_Info;
with HW.Time;
with HW.GFX.DP_Defs;
package body HW.GFX.DP_Training is
pragma Warnings (GNATprove, Off, "unused initial value of ""Port""*",
Reason => "Needed for a common interface");
function Training_Set
(Port : T;
Train_Set : DP_Info.Train_Set)
return Word8
is
use type DP_Info.DP_Voltage_Swing;
use type DP_Info.DP_Pre_Emph;
use type Word8;
Value : Word8;
begin
case Train_Set.Voltage_Swing is
when DP_Info.VS_Level_0 => Value := 16#00#;
when DP_Info.VS_Level_1 => Value := 16#01#;
when DP_Info.VS_Level_2 => Value := 16#02#;
when DP_Info.VS_Level_3 => Value := 16#03#;
end case;
if Train_Set.Voltage_Swing = Max_V_Swing (Port) then
Value := Value or 16#04#;
end if;
case Train_Set.Pre_Emph is
when DP_Info.Emph_Level_0 => Value := Value or 16#00#;
when DP_Info.Emph_Level_1 => Value := Value or 16#08#;
when DP_Info.Emph_Level_2 => Value := Value or 16#10#;
when DP_Info.Emph_Level_3 => Value := Value or 16#18#;
end case;
if Train_Set.Pre_Emph = Max_Pre_Emph (Port, Train_Set) then
Value := Value or 16#20#;
end if;
return Value;
end Training_Set;
pragma Warnings (GNATprove, On, "unused initial value of ""Port""*");
----------------------------------------------------------------------------
function Lane_Count (Link : DP_Link) return Positive
with
Post => Lane_Count'Result <= 4
is
begin
return Positive (Lane_Count_As_Integer (Link.Lane_Count));
end Lane_Count;
procedure Sink_Init
(Port : in Aux_T;
Link : in DP_Link;
Success : out Boolean)
is
use type Word8;
function Link_Rate_As_Word8 is new Ada.Unchecked_Conversion
(Source => DP_Bandwidth, Target => Word8);
Data : DP_Defs.Aux_Payload;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Data :=
(0 => Link_Rate_As_Word8 (Link.Bandwidth),
1 => Word8 (Lane_Count (Link)),
others => 0); -- Don't care
if Link.Enhanced_Framing then
Data (1) := Data (1) or 16#80#;
end if;
Aux_Ch.Aux_Write
(Port => Port,
Address => 16#00100#, -- LINK_BW_SET, LANE_COUNT_SET
Length => 2,
Data => Data,
Success => Success);
Success := Success or Link.Opportunistic_Training;
if Success then
Data (0) := 16#00#; -- no downspread
Data (1) := 16#01#; -- ANSI8B10B coding
Aux_Ch.Aux_Write
(Port => Port,
Address => 16#00107#, -- DOWNSPREAD_CTRL,
Length => 2, -- MAIN_LINK_CHANNEL_CODING_SET
Data => Data,
Success => Success);
Success := Success or Link.Opportunistic_Training;
end if;
end Sink_Init;
procedure Sink_Set_Training_Pattern
(DP : in Aux_T;
Link : in DP_Link;
Pattern : in DP_Info.Training_Pattern;
Success : out Boolean)
is
use type DP_Info.Training_Pattern;
type TP_Array is array (DP_Info.Training_Pattern) of Word8;
TP : constant TP_Array := TP_Array'
(DP_Info.TP_1 => 16#21#, DP_Info.TP_2 => 16#22#, DP_Info.TP_3 => 16#23#,
DP_Info.TP_Idle => 16#00#, DP_Info.TP_None => 16#00#);
Data : DP_Defs.Aux_Payload;
Length : Positive := 1;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Data :=
(0 => TP (Pattern),
others => 0); -- Don't care
if Pattern < DP_Info.TP_Idle then
Length := Length + Lane_Count (Link);
end if;
Aux_Ch.Aux_Write
(Port => DP,
Address => 16#00102#, -- TRAINING_PATTERN_SET
Length => Length,
Data => Data,
Success => Success);
end Sink_Set_Training_Pattern;
procedure Sink_Set_Signal_Levels
(Port : in T;
DP : in Aux_T;
Link : in DP_Link;
Train_Set : in DP_Info.Train_Set;
Success : out Boolean)
is
Data : DP_Defs.Aux_Payload;
T_Set : constant Word8 := Training_Set (Port, Train_Set);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Data := (others => 0); -- Initialize
Data (0 .. Lane_Count (Link) - 1) := (others => T_Set);
Aux_Ch.Aux_Write
(Port => DP,
Address => 16#00103#, -- TRAINING_LANEx_SET
Length => Lane_Count (Link),
Data => Data,
Success => Success);
end Sink_Set_Signal_Levels;
pragma Warnings (GNATprove, Off, "unused initial value of ""Port""*",
Reason => "Needed for a common interface");
procedure Sink_Adjust_Training
(Port : in T;
DP : in Aux_T;
Link : in DP_Link;
Train_Set : in out DP_Info.Train_Set;
CR_Done : in out Boolean;
EQ_Done : out Boolean;
Success : out Boolean)
is
use type DP_Info.DP_Voltage_Swing;
use type DP_Info.DP_Pre_Emph;
Status : DP_Info.Link_Status;
CR_Was_Done : constant Boolean := CR_Done;
pragma Warnings
(GNATprove, Off, "subprogram ""Dump_Link_Status"" has no effect*",
Reason => "It's only used for debugging");
procedure Dump_Link_Status
is
begin
Debug.New_Line;
Debug.Put_Line ("Link Status:");
for Lane in DP_Info.Lane_Index range 0
.. DP_Info.Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
loop
Debug.Put (" Lane");
Debug.Put_Int8 (Int8 (Lane));
Debug.Put_Line (":");
Debug.Put_Line (" CR_Done : " &
(if Status.Lanes (Lane).CR_Done then "1" else "0"));
Debug.Put_Line (" Channel_EQ_Done: " &
(if Status.Lanes (Lane).Channel_EQ_Done then "1" else "0"));
Debug.Put_Line (" Symbol_Locked : " &
(if Status.Lanes (Lane).Symbol_Locked then "1" else "0"));
end loop;
Debug.Put_Line (" Interlane_Align_Done: " &
(if Status.Interlane_Align_Done then "1" else "0"));
for Lane in DP_Info.Lane_Index range 0
.. DP_Info.Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
loop
Debug.Put (" Adjust");
Debug.Put_Int8 (Int8 (Lane));
Debug.Put_Line (":");
Debug.Put (" Voltage_Swing: ");
Debug.Put_Int8 (Int8 (DP_Info.DP_Voltage_Swing'Pos
(Status.Adjust_Requests (Lane).Voltage_Swing)));
Debug.New_Line;
Debug.Put (" Pre_Emph : ");
Debug.Put_Int8 (Int8 (DP_Info.DP_Pre_Emph'Pos
(Status.Adjust_Requests (Lane).Pre_Emph)));
Debug.New_Line;
end loop;
Debug.New_Line;
end Dump_Link_Status;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
DP_Info.Read_Link_Status
(Port => DP,
Status => Status,
Success => Success);
pragma Debug (Success, Dump_Link_Status);
CR_Done := Success and then DP_Info.All_CR_Done (Status, Link);
EQ_Done := Success and then DP_Info.All_EQ_Done (Status, Link);
Success := Success and then (CR_Done or not CR_Was_Done);
if Success and not CR_Done then
Train_Set.Voltage_Swing :=
DP_Info.Max_Requested_VS (Status, Link);
if Train_Set.Voltage_Swing > Max_V_Swing (Port)
then
Train_Set.Voltage_Swing := Max_V_Swing (Port);
end if;
end if;
-- According to DP spec, only change preemphasis during channel
-- equalization. What to do if sink requests it during clock recovery?
-- Linux always accepts new values from the sink, we don't, for now.
if Success and then (CR_Was_Done and not EQ_Done) then
Train_Set.Pre_Emph :=
DP_Info.Max_Requested_Emph (Status, Link);
if Train_Set.Pre_Emph > Max_Pre_Emph (Port, Train_Set)
then
Train_Set.Pre_Emph := Max_Pre_Emph (Port, Train_Set);
end if;
end if;
end Sink_Adjust_Training;
pragma Warnings (GNATprove, On, "unused initial value of ""Port""*");
----------------------------------------------------------------------------
procedure Train_DP
(Port : in T;
Link : in DP_Link;
Success : out Boolean)
is
use type DP_Info.DP_Voltage_Swing;
use type DP_Info.DP_Pre_Emph;
use type Word8;
DP : constant Aux_T := To_Aux (Port);
Retries : Natural;
Max_Retry : constant := 4;
CR_Done, EQ_Done : Boolean := False;
EQ_Pattern : constant DP_Info.Training_Pattern :=
(if TPS3_Supported and Link.Receiver_Caps.TPS3_Supported then
DP_Info.TP_3
else
DP_Info.TP_2);
Train_Set, Last_Train_Set : DP_Info.Train_Set;
function CR_Delay return Natural is
Result : Natural := 100; -- DP spec: 100us
begin
if Link.Bandwidth = DP_Bandwidth_5_4 and
Link.Receiver_Caps.Aux_RD_Interval /= 0
then
Result := Natural (Link.Receiver_Caps.Aux_RD_Interval) * 4_000;
end if;
return Result;
end CR_Delay;
function EQ_Delay return Natural is
Result : Natural := 400; -- DP spec: 400us
begin
if Link.Bandwidth = DP_Bandwidth_5_4 and
Link.Receiver_Caps.Aux_RD_Interval /= 0
then
Result := Natural (Link.Receiver_Caps.Aux_RD_Interval) * 4_000;
end if;
return Result;
end EQ_Delay;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Train_Set.Voltage_Swing := DP_Info.DP_Voltage_Swing'First;
Train_Set.Pre_Emph := DP_Info.DP_Pre_Emph'First;
Set_Pattern (Port, Link, DP_Info.TP_1);
Set_Signal_Levels (Port, Link, Train_Set);
pragma Warnings
(GNATprove, Off, """Success"" modified by call, but value overwritten*",
Reason => "Read first, then overwritten, looks like a false positive");
Sink_Init (DP, Link, Success);
pragma Warnings
(GNATprove, On, """Success"" modified by call, but value overwritten*");
if Success then
Sink_Set_Training_Pattern (DP, Link, DP_Info.TP_1, Success);
end if;
if Success then
Retries := 0;
for Tries in 1 .. 32 loop
pragma Loop_Invariant (Retries <= Max_Retry);
Time.U_Delay (CR_Delay);
Last_Train_Set := Train_Set;
Sink_Adjust_Training
(Port, DP, Link, Train_Set, CR_Done, EQ_Done, Success);
exit when CR_Done or not Success;
if Train_Set.Voltage_Swing = Last_Train_Set.Voltage_Swing then
exit when Retries = Max_Retry;
Retries := Retries + 1;
else
exit when Last_Train_Set.Voltage_Swing = Max_V_Swing (Port);
Retries := 0;
end if;
Set_Signal_Levels (Port, Link, Train_Set);
Sink_Set_Signal_Levels (Port, DP, Link, Train_Set, Success);
exit when not Success;
end loop;
end if;
Success := Success and CR_Done;
if Success then
Set_Pattern (Port, Link, EQ_Pattern);
Sink_Set_Training_Pattern (DP, Link, EQ_Pattern, Success);
end if;
if Success then
Retries := 0;
for Tries in 1 .. 32 loop
pragma Loop_Invariant (Retries <= Max_Retry);
Time.U_Delay (EQ_Delay);
Last_Train_Set := Train_Set;
Sink_Adjust_Training
(Port, DP, Link, Train_Set, CR_Done, EQ_Done, Success);
exit when EQ_Done or not Success;
if Train_Set.Pre_Emph = Last_Train_Set.Pre_Emph then
exit when Retries = Max_Retry;
Retries := Retries + 1;
else
exit when Last_Train_Set.Pre_Emph =
Max_Pre_Emph (Port, Last_Train_Set);
Retries := 0;
end if;
Set_Signal_Levels (Port, Link, Train_Set);
Sink_Set_Signal_Levels (Port, DP, Link, Train_Set, Success);
exit when not Success;
end loop;
end if;
if Success then
if EQ_Done then
-- Set_Pattern (TP_None) includes sending the Idle Pattern,
-- so tell sink first.
Sink_Set_Training_Pattern
(DP, Link, DP_Info.TP_None, Success);
else
Success := False;
end if;
end if;
if Success then
Set_Pattern (Port, Link, DP_Info.TP_None);
else
Off (Port);
end if;
end Train_DP;
end HW.GFX.DP_Training;

View File

@ -0,0 +1,57 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.DP_Info;
with HW.GFX.DP_Aux_Ch;
private generic
TPS3_Supported : Boolean;
type T (<>) is limited private;
type Aux_T (<>) is limited private;
with package Aux_Ch is new DP_Aux_Ch (T => Aux_T, others => <>);
with package DP_Info is new GFX.DP_Info (T => Aux_T, Aux_Ch => Aux_Ch);
with function To_Aux (Port : T) return Aux_T;
with function Max_V_Swing (Port : T) return DP_Info.DP_Voltage_Swing;
with function Max_Pre_Emph
(Port : T;
Train_Set : DP_Info.Train_Set)
return DP_Info.DP_Pre_Emph;
with procedure Set_Pattern
(Port : T;
Link : DP_Link;
Pattern : DP_Info.Training_Pattern);
with procedure Set_Signal_Levels
(Port : T;
Link : DP_Link;
Train_Set : DP_Info.Train_Set);
with procedure Off (Connector : T);
package HW.GFX.DP_Training
is
procedure Train_DP
(Port : in T;
Link : in DP_Link;
Success : out Boolean);
end HW.GFX.DP_Training;

180
common/hw-gfx-edid.adb Normal file
View File

@ -0,0 +1,180 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW;
with HW.Debug;
with GNAT.Source_Info;
use type HW.Byte;
use type HW.Pos16;
use type HW.Word16;
package body HW.GFX.EDID is
function Checksum_Valid (Raw_EDID : Raw_EDID_Data) return Boolean
with
Pre => True
is
Sum : Byte := 16#00#;
begin
for I in Raw_EDID_Index loop
Sum := Sum + Raw_EDID (I);
end loop;
pragma Debug (Sum /= 16#00#, Debug.Put_Line
(GNAT.Source_Info.Enclosing_Entity & ": EDID checksum invalid!"));
return Sum = 16#00#;
end Checksum_Valid;
function Valid (Raw_EDID : Raw_EDID_Data) return Boolean
is
Header_Valid : Boolean;
begin
Header_Valid :=
Raw_EDID (0) = 16#00# and
Raw_EDID (1) = 16#ff# and
Raw_EDID (2) = 16#ff# and
Raw_EDID (3) = 16#ff# and
Raw_EDID (4) = 16#ff# and
Raw_EDID (5) = 16#ff# and
Raw_EDID (6) = 16#ff# and
Raw_EDID (7) = 16#00#;
pragma Debug (not Header_Valid, Debug.Put_Line
(GNAT.Source_Info.Enclosing_Entity & ": EDID header pattern mismatch!"));
return Header_Valid and then Checksum_Valid (Raw_EDID);
end Valid;
----------------------------------------------------------------------------
REVISION : constant := 19;
INPUT : constant := 20;
INPUT_DIGITAL : constant := 1 * 2 ** 7;
INPUT_DIGITAL_DEPTH_SHIFT : constant := 4;
INPUT_DIGITAL_DEPTH_MASK : constant := 7 * 2 ** 4;
INPUT_DIGITAL_DEPTH_UNDEF : constant := 0 * 2 ** 4;
INPUT_DIGITAL_DEPTH_RESERVED : constant := 7 * 2 ** 4;
----------------------------------------------------------------------------
function Read_LE16
(Raw_EDID : Raw_EDID_Data;
Offset : Raw_EDID_Index)
return Word16
is
begin
return Shift_Left (Word16 (Raw_EDID (Offset + 1)), 8) or
Word16 (Raw_EDID (Offset));
end Read_LE16;
function Has_Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Boolean
is
begin
return
Int64 (Read_LE16 (Raw_EDID, DESCRIPTOR_1)) * 10_000
in Frequency_Type and
( Raw_EDID (DESCRIPTOR_1 + 2) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 4) and 16#f0#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 8) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#c0#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 9) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#30#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 3) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 4) and 16#0f#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 5) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 7) and 16#f0#) /= 0) and
((Raw_EDID (DESCRIPTOR_1 + 10) and 16#f0#) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#0c#) /= 0) and
((Raw_EDID (DESCRIPTOR_1 + 10) and 16#0f#) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#03#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 6) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 7) and 16#0f#) /= 0);
end Has_Preferred_Mode;
function Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Mode_Type
is
Base : constant := DESCRIPTOR_1;
Mode : Mode_Type;
function Read_12
(Lower_8, Upper_4 : Raw_EDID_Index;
Shift : Natural)
return Word16
is
begin
return
Word16 (Raw_EDID (Lower_8)) or
(Shift_Left (Word16 (Raw_EDID (Upper_4)), Shift) and 16#0f00#);
end Read_12;
function Read_10
(Lower_8, Upper_2 : Raw_EDID_Index;
Shift : Natural)
return Word16
is
begin
return
Word16 (Raw_EDID (Lower_8)) or
(Shift_Left (Word16 (Raw_EDID (Upper_2)), Shift) and 16#0300#);
end Read_10;
function Read_6
(Lower_4 : Raw_EDID_Index;
Lower_Shift : Natural;
Upper_2 : Raw_EDID_Index;
Upper_Shift : Natural)
return Word8
is
begin
return
(Shift_Right (Word8 (Raw_EDID (Lower_4)), Lower_Shift) and 16#0f#)
or
(Shift_Left (Word8 (Raw_EDID (Upper_2)), Upper_Shift) and 16#30#);
end Read_6;
begin
Mode := Mode_Type'
(Dotclock => Pos64 (Read_LE16 (Raw_EDID, Base)) * 10_000,
H_Visible => Pos16 (Read_12 (Base + 2, Base + 4, 4)),
H_Sync_Begin => Pos16 (Read_10 (Base + 8, Base + 11, 2)),
H_Sync_End => Pos16 (Read_10 (Base + 9, Base + 11, 4)),
H_Total => Pos16 (Read_12 (Base + 3, Base + 4, 8)),
V_Visible => Pos16 (Read_12 (Base + 5, Base + 7, 4)),
V_Sync_Begin => Pos16 (Read_6 (Base + 10, 4, Base + 11, 2)),
V_Sync_End => Pos16 (Read_6 (Base + 10, 0, Base + 11, 4)),
V_Total => Pos16 (Read_12 (Base + 6, Base + 7, 8)),
H_Sync_Active_High => (Raw_EDID (Base + 17) and 16#02#) /= 0,
V_Sync_Active_High => (Raw_EDID (Base + 17) and 16#04#) /= 0,
BPC =>
(if Raw_EDID (REVISION) < 4 or
(Raw_EDID (INPUT) and INPUT_DIGITAL) = 16#00# or
(Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_UNDEF or
(Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_RESERVED
then
0
else
4 + 2 * Pos64 (Shift_Right
(Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK,
INPUT_DIGITAL_DEPTH_SHIFT))));
-- Calculate absolute values from EDID relative values.
Mode.H_Sync_Begin := Mode.H_Visible + Mode.H_Sync_Begin;
Mode.H_Sync_End := Mode.H_Sync_Begin + Mode.H_Sync_End;
Mode.H_Total := Mode.H_Visible + Mode.H_Total;
Mode.V_Sync_Begin := Mode.V_Visible + Mode.V_Sync_Begin;
Mode.V_Sync_End := Mode.V_Sync_Begin + Mode.V_Sync_End;
Mode.V_Total := Mode.V_Visible + Mode.V_Total;
return Mode;
end Preferred_Mode;
end HW.GFX.EDID;

79
common/hw-gfx-edid.ads Normal file
View File

@ -0,0 +1,79 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.EDID
is
use type Word8;
use type Word16;
subtype Raw_EDID_Index is Natural range 0 .. 127;
subtype Raw_EDID_Data is Buffer (Raw_EDID_Index);
function Valid (Raw_EDID : Raw_EDID_Data) return Boolean;
DESCRIPTOR_1 : constant := 54;
function Read_LE16
(Raw_EDID : Raw_EDID_Data;
Offset : Raw_EDID_Index)
return Word16
with
Pre => Offset < Raw_EDID_Index'Last;
function Has_Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Boolean
with
Pre => Valid (Raw_EDID),
Post =>
(Has_Preferred_Mode'Result =
(Int64 (Read_LE16 (Raw_EDID, DESCRIPTOR_1)) * 10_000
in Frequency_Type and
( Raw_EDID (DESCRIPTOR_1 + 2) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 4) and 16#f0#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 8) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#c0#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 9) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#30#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 3) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 4) and 16#0f#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 5) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 7) and 16#f0#) /= 0) and
((Raw_EDID (DESCRIPTOR_1 + 10) and 16#f0#) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#0c#) /= 0) and
((Raw_EDID (DESCRIPTOR_1 + 10) and 16#0f#) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#03#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 6) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 7) and 16#0f#) /= 0)));
function Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Mode_Type
with
Pre =>
Int64 (Read_LE16 (Raw_EDID, DESCRIPTOR_1)) * 10_000
in Frequency_Type and
( Raw_EDID (DESCRIPTOR_1 + 2) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 4) and 16#f0#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 8) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#c0#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 9) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#30#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 3) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 4) and 16#0f#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 5) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 7) and 16#f0#) /= 0) and
((Raw_EDID (DESCRIPTOR_1 + 10) and 16#f0#) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#0c#) /= 0) and
((Raw_EDID (DESCRIPTOR_1 + 10) and 16#0f#) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 11) and 16#03#) /= 0) and
( Raw_EDID (DESCRIPTOR_1 + 6) /= 0 or
(Raw_EDID (DESCRIPTOR_1 + 7) and 16#0f#) /= 0);
end HW.GFX.EDID;

View File

@ -0,0 +1,40 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.MMIO_Range;
pragma Elaborate_All (HW.MMIO_Range);
package body HW.GFX.Framebuffer_Filler
is
type FB_Index is new Natural range
0 .. Natural (Width_Type'Last * Height_Type'Last) - 1;
type FB_Range is array (FB_Index) of Word32 with Pack;
package FB is new MMIO_Range (0, Word32, FB_Index, FB_Range);
procedure Fill (Linear_FB : Word64; Framebuffer : Framebuffer_Type)
is
Line_Start : Int32 := 0;
begin
FB.Set_Base_Address (Linear_FB);
for Line in 0 .. Framebuffer.Height - 1 loop
pragma Loop_Invariant (Line_Start = Line * Framebuffer.Stride);
for Col in 0 .. Framebuffer.Width - 1 loop
pragma Loop_Invariant (Line_Start = Line * Framebuffer.Stride);
FB.Write (FB_Index (Line_Start + Col), 16#ff000000#);
end loop;
Line_Start := Line_Start + Framebuffer.Stride;
end loop;
end Fill;
end HW.GFX.Framebuffer_Filler;

View File

@ -0,0 +1,28 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with System;
with HW;
use type HW.Int32;
package HW.GFX.Framebuffer_Filler
is
procedure Fill (Linear_FB : Word64; Framebuffer : Framebuffer_Type)
with
Pre =>
Framebuffer.Width <= Framebuffer.Stride;
end HW.GFX.Framebuffer_Filler;

View File

@ -0,0 +1,205 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.Config
with
Initializes => Valid_Port_GPU
is
CPU : constant CPU_Type := <<CPU>>;
CPU_Var : constant CPU_Variant := <<CPU_VARIANT>>;
Internal_Display : constant Internal_Type := <<INTERNAL_PORT>>;
EDP_Low_Voltage_Swing : constant Boolean := False;
Default_MMIO_Base : constant := <<DEFAULT_MMIO_BASE>>;
LVDS_Dual_Threshold : constant := 95_000_000;
----------------------------------------------------------------------------
Has_Internal_Display : constant Boolean := Internal_Display /= None;
Internal_Is_EDP : constant Boolean := Internal_Display = DP;
----- CPU pipe: --------
Disable_Trickle_Feed : constant Boolean := not
(CPU in Haswell .. Broadwell);
Pipe_Enabled_Workaround : constant Boolean := CPU = Broadwell;
Has_EDP_Pipe : constant Boolean := CPU >= Haswell;
Has_Pipe_DDI_Func : constant Boolean := CPU >= Haswell;
Has_Trans_Clk_Sel : constant Boolean := CPU >= Haswell;
Has_Pipe_MSA_Misc : constant Boolean := CPU >= Haswell;
Has_Pipeconf_Misc : constant Boolean := CPU >= Broadwell;
Has_Pipeconf_BPC : constant Boolean := CPU /= Haswell;
Has_Plane_Control : constant Boolean := CPU >= Skylake;
Has_DSP_Linoff : constant Boolean := CPU <= Ivybridge;
----- Panel power: -----
Has_PP_Write_Protection : constant Boolean := CPU <= Ivybridge;
Has_PP_Port_Select : constant Boolean := CPU <= Ivybridge;
Use_PP_VDD_Override : constant Boolean := CPU <= Ivybridge;
----- PCH/FDI: ---------
Has_PCH_DAC : constant Boolean := CPU in Ironlake .. Ivybridge or
(CPU in Broadwell .. Haswell
and CPU_Var = Normal);
Has_PCH_Aux_Channels : constant Boolean := CPU in Ironlake .. Broadwell;
VGA_Has_Sync_Disable : constant Boolean := CPU <= Ivybridge;
Has_Trans_Timing_Ovrrde : constant Boolean := CPU >= Sandybridge;
Has_DPLL_SEL : constant Boolean := CPU in Ironlake .. Ivybridge;
Has_FDI_BPC : constant Boolean := CPU in Ironlake .. Ivybridge;
Has_FDI_Composite_Sel : constant Boolean := CPU = Ivybridge;
Has_Trans_DP_Ctl : constant Boolean := CPU in
Sandybridge .. Ivybridge;
Has_FDI_C : constant Boolean := CPU = Ivybridge;
Has_FDI_RX_Power_Down : constant Boolean := CPU in Haswell .. Broadwell;
----- DDI: -------------
End_EDP_Training_Late : constant Boolean := CPU in Haswell .. Broadwell;
Has_Per_DDI_Clock_Sel : constant Boolean := CPU in Haswell .. Broadwell;
Has_HOTPLUG_CTL : constant Boolean := CPU in Haswell .. Broadwell;
Has_SHOTPLUG_CTL_A : constant Boolean := (CPU in Haswell .. Broadwell
and CPU_Var = ULT) or
CPU >= Skylake;
Has_DDI_D : constant Boolean := (CPU in Haswell .. Broadwell
and CPU_Var = Normal)
or CPU >= Skylake;
Has_Low_Voltage_Swing : constant Boolean := CPU >= Skylake;
Need_DP_Aux_Mutex : constant Boolean := False; -- Skylake & (PSR | GTC)
Ungate_GMBUS_Unit_Level : constant Boolean := CPU >= Skylake;
----- Power: -----------
Has_IPS : constant Boolean := (CPU = Haswell and
CPU_Var = ULT) or
CPU = Broadwell;
Has_IPS_CTL_Mailbox : constant Boolean := CPU = Broadwell;
Has_Per_Pipe_SRD : constant Boolean := CPU >= Broadwell;
----- GTT: -----
Fold_39Bit_GTT_PTE : constant Boolean := CPU <= Haswell;
----------------------------------------------------------------------------
type Supported_Pipe_Array is array (Config_Index) of Boolean;
Supported_Pipe : constant Supported_Pipe_Array :=
(Primary => True,
Secondary => True,
Tertiary => CPU >= Ivybridge);
type Valid_Per_Port is array (Port_Type) of Boolean;
type Valid_Per_GPU is array (CPU_Type) of Valid_Per_Port;
Valid_Port_GPU : Valid_Per_GPU :=
(Ironlake => Valid_Per_Port'
(Disabled => False,
Internal => Config.Internal_Display = LVDS,
others => True),
Sandybridge => Valid_Per_Port'
(Disabled => False,
Internal => Config.Internal_Display = LVDS,
others => True),
Ivybridge => Valid_Per_Port'
(Disabled => False,
Internal => Config.Internal_Display /= None,
others => True),
Haswell => Valid_Per_Port'
(Disabled => False,
Internal => Config.Internal_Display = DP,
Digital3 => CPU_Var = Normal,
DP3 => CPU_Var = Normal,
Analog => CPU_Var = Normal,
others => True),
Broadwell => Valid_Per_Port'
(Disabled => False,
Internal => Config.Internal_Display = DP,
Digital3 => CPU_Var = Normal,
DP3 => CPU_Var = Normal,
Analog => CPU_Var = Normal,
others => True),
Skylake => Valid_Per_Port'
(Disabled => False,
Internal => Config.Internal_Display = DP,
Analog => False,
others => True))
with
Part_Of => GMA.Config_State;
Valid_Port : Valid_Per_Port renames Valid_Port_GPU (CPU);
----------------------------------------------------------------------------
type FDI_Per_Port is array (GPU_Port) of Boolean;
type FDI_Per_GPU is array (CPU_Type) of FDI_Per_Port;
FDI_GPU : constant FDI_Per_GPU :=
(Ironlake => FDI_Per_Port'
(DIGI_A => False, -- directly connected eDP
DIGI_B => True,
DIGI_C => True,
DIGI_D => True,
others => False),
Sandybridge => FDI_Per_Port'
(DIGI_A => False, -- directly connected eDP
DIGI_B => True,
DIGI_C => True,
DIGI_D => True,
others => False),
Ivybridge => FDI_Per_Port'
(DIGI_A => False, -- directly connected eDP
DIGI_B => True,
DIGI_C => True,
DIGI_D => True,
others => False),
Haswell => FDI_Per_Port'
(DIGI_A => False,
DIGI_B => False,
DIGI_C => False,
DIGI_D => False,
DIGI_E => True, -- VGA option through FDI
others => False),
Broadwell => FDI_Per_Port'
(DIGI_A => False,
DIGI_B => False,
DIGI_C => False,
DIGI_D => False,
DIGI_E => CPU_Var = Normal, -- VGA option through FDI
others => False),
Skylake => FDI_Per_Port'
(others => False));
FDI_Port : FDI_Per_Port renames FDI_GPU (CPU);
type FDI_Lanes_Per_Port is array (GPU_Port) of DP_Lane_Count;
FDI_Lane_Count : constant FDI_Lanes_Per_Port :=
(DIGI_D => DP_Lane_Count_2,
others =>
(if CPU in Ironlake .. Ivybridge then
DP_Lane_Count_4
else
DP_Lane_Count_2));
FDI_Training : constant FDI_Training_Type :=
(case CPU is
when Ironlake => Simple_Training,
when Sandybridge => Full_Training,
when others => Auto_Training);
end HW.GFX.GMA.Config;

View File

@ -0,0 +1,136 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.I2C;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Panel;
with HW.GFX.GMA.I2C;
with HW.GFX.GMA.DP_Info;
with HW.GFX.GMA.DP_Aux_Ch;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.Connector_Info is
function To_DP (Port_Cfg : Port_Config) return DP_Port
is
begin
return
(if Port_Cfg.Port = DIGI_A then
DP_A
else
(case Port_Cfg.PCH_Port is
when PCH_DP_B => DP_B,
when PCH_DP_C => DP_C,
when PCH_DP_D => DP_D,
when others => DP_Port'First));
end To_DP;
----------------------------------------------------------------------------
procedure Read_EDID
(Raw_EDID : out EDID.Raw_EDID_Data;
Port_Cfg : in Port_Config;
Success : out Boolean)
is
Raw_EDID_Length : GFX.I2C.Transfer_Length := Raw_EDID'Length;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
for I in 1 .. 2 loop
if Port_Cfg.Display = DP then
DP_Aux_Ch.I2C_Read
(Port => To_DP (Port_Cfg),
Address => 16#50#,
Length => Raw_EDID_Length,
Data => Raw_EDID,
Success => Success);
else
I2C.I2C_Read
(Port => Port_Cfg.PCH_Port,
Address => 16#50#,
Length => Raw_EDID_Length,
Data => Raw_EDID,
Success => Success);
end if;
exit when not Success; -- don't retry if reading itself failed
pragma Debug (Debug.Put_Buffer ("EDID", Raw_EDID, Raw_EDID_Length));
Success := EDID.Valid (Raw_EDID);
exit when Success;
end loop;
end Read_EDID;
----------------------------------------------------------------------------
procedure Preferred_Link_Setting
(Port_Cfg : in out Port_Config;
Success : out Boolean) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Display = DP then
if Port_Cfg.Port = DIGI_A then
if GMA.Config.Use_PP_VDD_Override then
Panel.VDD_Override;
else
Panel.On;
end if;
end if;
DP_Info.Read_Caps
(Link => Port_Cfg.DP,
Port => To_DP (Port_Cfg),
Success => Success);
if Success then
DP_Info.Preferred_Link_Setting
(Link => Port_Cfg.DP,
Mode => Port_Cfg.Mode,
Success => Success);
end if;
else
Success := True;
end if;
end Preferred_Link_Setting;
procedure Next_Link_Setting
(Port_Cfg : in out Port_Config;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Display = DP then
DP_Info.Next_Link_Setting
(Link => Port_Cfg.DP,
Mode => Port_Cfg.Mode,
Success => Success);
else
Success := False;
end if;
end Next_Link_Setting;
----------------------------------------------------------------------------
function Default_BPC (Port_Cfg : Port_Config) return HW.GFX.BPC_Type
is
begin
return
(if Port_Cfg.Port = DIGI_A or
(Port_Cfg.Is_FDI and Port_Cfg.PCH_Port = PCH_LVDS)
then 6
else 8);
end Default_BPC;
end HW.GFX.GMA.Connector_Info;

View File

@ -0,0 +1,39 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.EDID;
private package HW.GFX.GMA.Connector_Info is
procedure Read_EDID
(Raw_EDID : out EDID.Raw_EDID_Data;
Port_Cfg : in Port_Config;
Success : out Boolean)
with
Post => (if Success then EDID.Valid (Raw_EDID));
procedure Preferred_Link_Setting
(Port_Cfg : in out Port_Config;
Success : out Boolean)
with
Post => (Port_Cfg.Port = Port_Cfg.Port'Old);
procedure Next_Link_Setting
(Port_Cfg : in out Port_Config;
Success : out Boolean)
with
Post => (Port_Cfg.Port = Port_Cfg.Port'Old);
function Default_BPC (Port_Cfg : Port_Config) return BPC_Type;
end HW.GFX.GMA.Connector_Info;

View File

@ -0,0 +1,36 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.Connectors is
pragma Warnings (GNATprove, Off, "unused variable ""P*""",
Reason => "Needed for a common interface");
procedure Pre_On
(Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Pipe_Hint : in Word32;
Success : out Boolean);
procedure Post_On
(Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Success : out Boolean);
pragma Warnings (GNATprove, On, "unused variable ""P*""");
procedure Pre_Off (Port_Cfg : Port_Config);
procedure Post_Off (Port_Cfg : Port_Config);
procedure Pre_All_Off;
procedure Post_All_Off;
end HW.GFX.GMA.Connectors;

View File

@ -0,0 +1,21 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.DP_Aux_Ch;
pragma Elaborate_All (HW.GFX.DP_Aux_Ch);
with HW.GFX.GMA.DP_Aux_Request;
private package HW.GFX.GMA.DP_Aux_Ch
is new HW.GFX.DP_Aux_Ch
(T => DP_Port,
Aux_Request => DP_Aux_Request.Do_Aux_Request);

View File

@ -0,0 +1,330 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.Debug;
with GNAT.Source_Info;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
use type HW.Word8;
use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
package body HW.GFX.GMA.DP_Aux_Request is
DP_AUX_CTL_SEND_BUSY : constant := 1 * 2 ** 31;
DP_AUX_CTL_DONE : constant := 1 * 2 ** 30;
DP_AUX_CTL_INTERRUPT_ON_DONE : constant := 1 * 2 ** 29;
DP_AUX_CTL_TIME_OUT_ERROR : constant := 1 * 2 ** 28;
DP_AUX_CTL_TIME_OUT_TIMER_MASK : constant := 3 * 2 ** 26;
DP_AUX_CTL_TIME_OUT_TIMER_400US : constant := 0 * 2 ** 26;
DP_AUX_CTL_TIME_OUT_TIMER_600US : constant := 1 * 2 ** 26;
DP_AUX_CTL_TIME_OUT_TIMER_800US : constant := 2 * 2 ** 26;
DP_AUX_CTL_TIME_OUT_TIMER_1600US : constant := 3 * 2 ** 26;
DP_AUX_CTL_RECEIVE_ERROR : constant := 1 * 2 ** 25;
DP_AUX_CTL_MESSAGE_SIZE_MASK : constant := 31 * 2 ** 20;
DP_AUX_CTL_MESSAGE_SIZE_SHIFT : constant := 2 ** 20;
DP_AUX_CTL_PRECHARGE_TIME_MASK : constant := 15 * 2 ** 16;
DP_AUX_CTL_PRECHARGE_TIME_SHIFT : constant := 2 ** 16;
DP_AUX_CTL_2X_BIT_CLOCK_DIV_MASK : constant := 2047 * 2 ** 0;
-- TODO: 2x bit clock divider should be programmed once before any training.
subtype DP_AUX_CTL_MESSAGE_SIZE_T is Natural range 1 .. 20;
function DP_AUX_CTL_MESSAGE_SIZE
(Message_Length : DP_AUX_CTL_MESSAGE_SIZE_T)
return Word32;
DDI_AUX_MUTEX_MUTEX_ENABLE : constant := 1 * 2 ** 31;
DDI_AUX_MUTEX_MUTEX_STATUS : constant := 1 * 2 ** 30;
type AUX_CH_Data_Regs is new Positive range 1 .. 5;
type AUX_CH_Data_Regs_Array is
array (AUX_CH_Data_Regs) of Registers.Registers_Index;
type AUX_CH_Registers is record
CTL : Registers.Registers_Index;
DATA : AUX_CH_Data_Regs_Array;
MUTEX : Registers.Registers_Invalid_Index;
end record;
type AUX_CH_Registers_Array is array (DP_Port) of AUX_CH_Registers;
AUX_CH : constant AUX_CH_Registers_Array :=
(if Config.Has_PCH_Aux_Channels then
AUX_CH_Registers_Array'
(DP_A => AUX_CH_Registers'
(CTL => Registers.DP_AUX_CTL_A,
DATA => AUX_CH_Data_Regs_Array'
(1 => Registers.DP_AUX_DATA_A_1,
2 => Registers.DP_AUX_DATA_A_2,
3 => Registers.DP_AUX_DATA_A_3,
4 => Registers.DP_AUX_DATA_A_4,
5 => Registers.DP_AUX_DATA_A_5),
MUTEX => Registers.Invalid_Register),
DP_B => AUX_CH_Registers'
(CTL => Registers.PCH_DP_AUX_CTL_B,
DATA => AUX_CH_Data_Regs_Array'
(1 => Registers.PCH_DP_AUX_DATA_B_1,
2 => Registers.PCH_DP_AUX_DATA_B_2,
3 => Registers.PCH_DP_AUX_DATA_B_3,
4 => Registers.PCH_DP_AUX_DATA_B_4,
5 => Registers.PCH_DP_AUX_DATA_B_5),
MUTEX => Registers.Invalid_Register),
DP_C => AUX_CH_Registers'
(CTL => Registers.PCH_DP_AUX_CTL_C,
DATA => AUX_CH_Data_Regs_Array'
(1 => Registers.PCH_DP_AUX_DATA_C_1,
2 => Registers.PCH_DP_AUX_DATA_C_2,
3 => Registers.PCH_DP_AUX_DATA_C_3,
4 => Registers.PCH_DP_AUX_DATA_C_4,
5 => Registers.PCH_DP_AUX_DATA_C_5),
MUTEX => Registers.Invalid_Register),
DP_D => AUX_CH_Registers'
(CTL => Registers.PCH_DP_AUX_CTL_D,
DATA => AUX_CH_Data_Regs_Array'
(1 => Registers.PCH_DP_AUX_DATA_D_1,
2 => Registers.PCH_DP_AUX_DATA_D_2,
3 => Registers.PCH_DP_AUX_DATA_D_3,
4 => Registers.PCH_DP_AUX_DATA_D_4,
5 => Registers.PCH_DP_AUX_DATA_D_5),
MUTEX => Registers.Invalid_Register))
else
AUX_CH_Registers_Array'
(DP_A => AUX_CH_Registers'
(CTL => Registers.DDI_AUX_CTL_A,
DATA => AUX_CH_Data_Regs_Array'
(1 => Registers.DDI_AUX_DATA_A_1,
2 => Registers.DDI_AUX_DATA_A_2,
3 => Registers.DDI_AUX_DATA_A_3,
4 => Registers.DDI_AUX_DATA_A_4,
5 => Registers.DDI_AUX_DATA_A_5),
MUTEX => Registers.DDI_AUX_MUTEX_A),
DP_B => AUX_CH_Registers'
(CTL => Registers.DDI_AUX_CTL_B,
DATA => AUX_CH_Data_Regs_Array'
(1 => Registers.DDI_AUX_DATA_B_1,
2 => Registers.DDI_AUX_DATA_B_2,
3 => Registers.DDI_AUX_DATA_B_3,
4 => Registers.DDI_AUX_DATA_B_4,
5 => Registers.DDI_AUX_DATA_B_5),
MUTEX => Registers.DDI_AUX_MUTEX_B),
DP_C => AUX_CH_Registers'
(CTL => Registers.DDI_AUX_CTL_C,
DATA => AUX_CH_Data_Regs_Array'
(1 => Registers.DDI_AUX_DATA_C_1,
2 => Registers.DDI_AUX_DATA_C_2,
3 => Registers.DDI_AUX_DATA_C_3,
4 => Registers.DDI_AUX_DATA_C_4,
5 => Registers.DDI_AUX_DATA_C_5),
MUTEX => Registers.DDI_AUX_MUTEX_C),
DP_D => AUX_CH_Registers'
(CTL => Registers.DDI_AUX_CTL_D,
DATA => AUX_CH_Data_Regs_Array'
(1 => Registers.DDI_AUX_DATA_D_1,
2 => Registers.DDI_AUX_DATA_D_2,
3 => Registers.DDI_AUX_DATA_D_3,
4 => Registers.DDI_AUX_DATA_D_4,
5 => Registers.DDI_AUX_DATA_D_5),
MUTEX => Registers.DDI_AUX_MUTEX_D)));
----------------------------------------------------------------------------
function DP_AUX_CTL_MESSAGE_SIZE
(Message_Length : DP_AUX_CTL_MESSAGE_SIZE_T)
return Word32
is
begin
return Word32 (Message_Length) * DP_AUX_CTL_MESSAGE_SIZE_SHIFT;
end DP_AUX_CTL_MESSAGE_SIZE;
----------------------------------------------------------------------------
procedure Aux_Request_Low
(Port : in DP_Port;
Request : in DP_Defs.Aux_Request;
Request_Length : in DP_Defs.Aux_Request_Length;
Response : out DP_Defs.Aux_Response;
Response_Length : out DP_Defs.Aux_Response_Length;
Success : out Boolean)
with
Global => (In_Out => Registers.Register_State,
Input => Time.State),
Depends =>
((Registers.Register_State,
Response,
Response_Length,
Success)
=>
(Registers.Register_State,
Time.State,
Port,
Request,
Request_Length))
is
procedure Write_Data_Reg
(Register : in Registers.Registers_Index;
Buf : in DP_Defs.Aux_Request;
Length : in DP_Defs.Aux_Request_Length;
Offset : in DP_Defs.Aux_Request_Index)
is
Value : Word32;
Count : Natural;
begin
if Offset < Length then
if Length - Offset > 4 then
Count := 4;
else
Count := Length - Offset;
end if;
Value := 0;
for Idx in DP_Defs.Aux_Request_Index range 0 .. Count - 1 loop
Value := Value or
Shift_Left (Word32 (Buf (Offset + Idx)), (3 - Idx) * 8);
end loop;
Registers.Write (Register => Register, Value => Value);
end if;
end Write_Data_Reg;
procedure Read_Data_Reg
(Register : in Registers.Registers_Index;
Buf : in out DP_Defs.Aux_Response;
Length : in DP_Defs.Aux_Response_Length;
Offset : in DP_Defs.Aux_Response_Index)
is
Value : Word32;
Count : DP_Defs.Aux_Response_Length;
begin
if Offset < Length then
if Length - Offset > 4 then
Count := 4;
else
Count := Length - Offset;
end if;
Registers.Read (Register => Register, Value => Value);
for Idx in 0 .. Count - 1 loop
Buf (Offset + Idx) :=
Word8 (Shift_Right (Value, (3 - Idx) * 8) and 16#ff#);
end loop;
end if;
end Read_Data_Reg;
Busy : Boolean;
Status : Word32;
begin
Response := (others => 0); -- Don't care
Response_Length := DP_Defs.Aux_Response_Length'First;
if Config.Need_DP_Aux_Mutex then
Registers.Set_Mask
(Register => AUX_CH (Port).MUTEX,
Mask => DDI_AUX_MUTEX_MUTEX_ENABLE);
Registers.Wait_Set_Mask
(Register => AUX_CH (Port).MUTEX,
Mask => DDI_AUX_MUTEX_MUTEX_STATUS);
end if;
Registers.Is_Set_Mask
(Register => AUX_CH (Port).CTL,
Mask => DP_AUX_CTL_SEND_BUSY,
Result => Busy);
if Busy then
Success := False;
else
for Idx in AUX_CH_Data_Regs loop
Write_Data_Reg
(Register => AUX_CH (Port).DATA (Idx),
Buf => Request,
Length => Request_Length,
Offset => (Natural (Idx) - 1) * 4);
end loop;
Registers.Unset_And_Set_Mask
(Register => AUX_CH (Port).CTL,
Mask_Unset => DP_AUX_CTL_INTERRUPT_ON_DONE or
DP_AUX_CTL_TIME_OUT_TIMER_MASK or
DP_AUX_CTL_MESSAGE_SIZE_MASK,
Mask_Set => DP_AUX_CTL_SEND_BUSY or -- starts transfer
DP_AUX_CTL_DONE or -- clears the status
DP_AUX_CTL_TIME_OUT_ERROR or -- clears the status
DP_AUX_CTL_RECEIVE_ERROR or -- clears the status
DP_AUX_CTL_TIME_OUT_TIMER_600US or
DP_AUX_CTL_MESSAGE_SIZE (Request_Length));
Registers.Wait_Unset_Mask
(Register => AUX_CH (Port).CTL,
Mask => DP_AUX_CTL_SEND_BUSY);
Registers.Read (Register => AUX_CH (Port).CTL, Value => Status);
Success := (Status and
(DP_AUX_CTL_TIME_OUT_ERROR or DP_AUX_CTL_RECEIVE_ERROR))
= 0;
if Success then
Status := (Status and DP_AUX_CTL_MESSAGE_SIZE_MASK)
/ DP_AUX_CTL_MESSAGE_SIZE_SHIFT;
if Natural (Status) < DP_Defs.Aux_Response_Length'First then
Success := False;
elsif Natural (Status) > DP_Defs.Aux_Response_Length'Last then
Response_Length := DP_Defs.Aux_Response_Length'Last;
else
Response_Length := Natural (Status);
end if;
end if;
if Success then
for Idx in AUX_CH_Data_Regs loop
Read_Data_Reg
(Register => AUX_CH (Port).DATA (Idx),
Buf => Response,
Length => Response_Length,
Offset => (Natural (Idx) - 1) * 4);
end loop;
end if;
end if;
if Config.Need_DP_Aux_Mutex then
Registers.Unset_And_Set_Mask
(Register => AUX_CH (Port).MUTEX,
Mask_Unset => DDI_AUX_MUTEX_MUTEX_ENABLE,
Mask_Set => DDI_AUX_MUTEX_MUTEX_STATUS); -- frees the mutex
end if;
end Aux_Request_Low;
----------------------------------------------------------------------------
procedure Do_Aux_Request
(Port : in DP_Port;
Request : in DP_Defs.Aux_Request;
Request_Length : in DP_Defs.Aux_Request_Length;
Response : out DP_Defs.Aux_Response;
Response_Length : out DP_Defs.Aux_Response_Length;
Success : out Boolean)
is
begin
for Try in Positive range 1 .. 3 loop
Aux_Request_Low
(Port => Port,
Request => Request,
Request_Length => Request_Length,
Response => Response,
Response_Length => Response_Length,
Success => Success);
exit when Success;
end loop;
end Do_Aux_Request;
end HW.GFX.GMA.DP_Aux_Request;

View File

@ -0,0 +1,26 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.DP_Defs;
private package HW.GFX.GMA.DP_Aux_Request is
procedure Do_Aux_Request
(Port : in DP_Port;
Request : in DP_Defs.Aux_Request;
Request_Length : in DP_Defs.Aux_Request_Length;
Response : out DP_Defs.Aux_Response;
Response_Length : out DP_Defs.Aux_Response_Length;
Success : out Boolean);
end HW.GFX.GMA.DP_Aux_Request;

View File

@ -0,0 +1,21 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.DP_Info;
pragma Elaborate_All (HW.GFX.DP_Info);
with HW.GFX.GMA.DP_Aux_Ch;
private package HW.GFX.GMA.DP_Info
is new HW.GFX.DP_Info
(T => DP_Port,
Aux_Ch => DP_Aux_Ch);

234
common/hw-gfx-gma-i2c.adb Normal file
View File

@ -0,0 +1,234 @@
--
-- Copyright (C) 2015 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.Debug;
with GNAT.Source_Info;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
use type HW.Word8;
package body HW.GFX.GMA.I2C is
PCH_DSPCLK_GATE_D_GMBUS_UNIT_LVL : constant := 1 * 2 ** 31;
GMBUS0_GMBUS_RATE_SELECT_MASK : constant := 7 * 2 ** 8;
GMBUS0_GMBUS_RATE_SELECT_100KHZ : constant := 0 * 2 ** 8;
GMBUS0_GMBUS_RATE_SELECT_50KHZ : constant := 1 * 2 ** 8;
GMBUS0_PIN_PAIR_SELECT_MASK : constant := 7 * 2 ** 0;
GMBUS0_PIN_PAIR_SELECT_NONE : constant := 0 * 2 ** 0;
GMBUS0_PIN_PAIR_SELECT_DAC : constant := 2 * 2 ** 0;
GMBUS0_PIN_PAIR_SELECT_LVDS : constant := 3 * 2 ** 0;
-- Order is C, B, D: no typo!
GMBUS0_PIN_PAIR_SELECT_DIGI_C : constant := 4 * 2 ** 0;
GMBUS0_PIN_PAIR_SELECT_DIGI_B : constant := 5 * 2 ** 0;
GMBUS0_PIN_PAIR_SELECT_DIGI_D : constant := 6 * 2 ** 0;
GMBUS1_SOFTWARE_CLEAR_INTERRUPT : constant := 1 * 2 ** 31;
GMBUS1_SOFTWARE_READY : constant := 1 * 2 ** 30;
GMBUS1_ENABLE_TIMEOUT : constant := 1 * 2 ** 29;
GMBUS1_BUS_CYCLE_SELECT_MASK : constant := 7 * 2 ** 25;
GMBUS1_BUS_CYCLE_STOP : constant := 1 * 2 ** 27;
GMBUS1_BUS_CYCLE_INDEX : constant := 1 * 2 ** 26;
GMBUS1_BUS_CYCLE_WAIT : constant := 1 * 2 ** 25;
GMBUS1_TOTAL_BYTE_COUNT_MASK : constant := 511 * 2 ** 16;
GMBUS1_TOTAL_BYTE_COUNT_SHIFT : constant := 16;
GMBUS1_8BIT_SLAVE_INDEX_MASK : constant := 255 * 2 ** 8;
GMBUS1_8BIT_SLAVE_INDEX_SHIFT : constant := 8;
GMBUS1_SLAVE_ADDRESS_MASK : constant := 127 * 2 ** 1;
GMBUS1_SLAVE_ADDRESS_SHIFT : constant := 1;
GMBUS1_DIRECTION_MASK : constant := 1 * 2 ** 0;
GMBUS1_DIRECTION_WRITE : constant := 0 * 2 ** 0;
GMBUS1_DIRECTION_READ : constant := 1 * 2 ** 0;
GMBUS2_INUSE : constant := 1 * 2 ** 15;
GMBUS2_HARDWARE_WAIT_PHASE : constant := 1 * 2 ** 14;
GMBUS2_SLAVE_STALL_TIMEOUT_ERROR : constant := 1 * 2 ** 13;
GMBUS2_GMBUS_INTERRUPT_STATUS : constant := 1 * 2 ** 12;
GMBUS2_HARDWARE_READY : constant := 1 * 2 ** 11;
GMBUS2_NAK_INDICATOR : constant := 1 * 2 ** 10;
GMBUS2_GMBUS_ACTIVE : constant := 1 * 2 ** 9;
GMBUS2_CURRENT_BYTE_COUNT_MASK : constant := 511 * 2 ** 0;
GMBUS4_INTERRUPT_MASK : constant := 31 * 2 ** 0;
GMBUS5_2BYTE_INDEX_ENABLE : constant := 1 * 2 ** 31;
function GMBUS1_TOTAL_BYTE_COUNT
(Count : HW.GFX.I2C.Transfer_Length)
return Word32 is
begin
return Shift_Left (Word32 (Count), GMBUS1_TOTAL_BYTE_COUNT_SHIFT);
end GMBUS1_TOTAL_BYTE_COUNT;
function GMBUS1_SLAVE_ADDRESS
(Address : HW.GFX.I2C.Transfer_Address)
return Word32 is
begin
return Shift_Left (Word32 (Address), GMBUS1_SLAVE_ADDRESS_SHIFT);
end GMBUS1_SLAVE_ADDRESS;
function GMBUS0_PIN_PAIR_SELECT (Port : PCH_Port) return Word32 is
begin
return
(case Port is
when PCH_DAC => GMBUS0_PIN_PAIR_SELECT_DAC,
when PCH_LVDS => GMBUS0_PIN_PAIR_SELECT_LVDS,
when PCH_HDMI_B => GMBUS0_PIN_PAIR_SELECT_DIGI_B,
when PCH_HDMI_C => GMBUS0_PIN_PAIR_SELECT_DIGI_C,
when PCH_HDMI_D => GMBUS0_PIN_PAIR_SELECT_DIGI_D,
when others => GMBUS0_PIN_PAIR_SELECT_NONE);
end GMBUS0_PIN_PAIR_SELECT;
----------------------------------------------------------------------------
procedure GMBUS_Ready (Result : out Boolean)
is
GMBUS2 : Word32;
begin
Registers.Read (Registers.PCH_GMBUS2, GMBUS2);
Result := (GMBUS2 and (GMBUS2_HARDWARE_WAIT_PHASE or
GMBUS2_SLAVE_STALL_TIMEOUT_ERROR or
GMBUS2_GMBUS_INTERRUPT_STATUS or
GMBUS2_NAK_INDICATOR)) = 0;
end GMBUS_Ready;
procedure Reset_GMBUS (Success : out Boolean) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Write (Registers.PCH_GMBUS1, GMBUS1_SOFTWARE_CLEAR_INTERRUPT);
Registers.Write (Registers.PCH_GMBUS1, 0);
Registers.Write (Registers.PCH_GMBUS0, GMBUS0_PIN_PAIR_SELECT_NONE);
GMBUS_Ready (Success);
end Reset_GMBUS;
procedure Init_GMBUS (Port : PCH_Port; Success : out Boolean) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.Ungate_GMBUS_Unit_Level then
Registers.Set_Mask
(Register => Registers.PCH_DSPCLK_GATE_D,
Mask => PCH_DSPCLK_GATE_D_GMBUS_UNIT_LVL);
end if;
-- TODO: Refactor + check for timeout.
Registers.Wait_Unset_Mask (Registers.PCH_GMBUS2, GMBUS2_INUSE);
GMBUS_Ready (Success);
if not Success then
Reset_GMBUS (Success);
end if;
if Success then
Registers.Write
(Register => Registers.PCH_GMBUS0,
Value => GMBUS0_GMBUS_RATE_SELECT_100KHZ or
GMBUS0_PIN_PAIR_SELECT (Port));
Registers.Write
(Register => Registers.PCH_GMBUS4,
Value => 0);
Registers.Write
(Register => Registers.PCH_GMBUS5,
Value => 0);
end if;
end Init_GMBUS;
procedure Release_GMBUS
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Write (Registers.PCH_GMBUS0, GMBUS0_PIN_PAIR_SELECT_NONE);
-- Clear INUSE. TODO: Don't do it, if timeout occured (see above).
Registers.Write (Registers.PCH_GMBUS2, GMBUS2_INUSE);
if Config.Ungate_GMBUS_Unit_Level then
Registers.Unset_Mask
(Register => Registers.PCH_DSPCLK_GATE_D,
Mask => PCH_DSPCLK_GATE_D_GMBUS_UNIT_LVL);
end if;
end Release_GMBUS;
procedure I2C_Read
(Port : in PCH_Port;
Address : in HW.GFX.I2C.Transfer_Address;
Length : in out HW.GFX.I2C.Transfer_Length;
Data : out HW.GFX.I2C.Transfer_Data;
Success : out Boolean)
is
GMBUS2,
GMBUS3 : Word32;
Current : HW.GFX.I2C.Transfer_Length;
Transfered : HW.GFX.I2C.Transfer_Length := 0;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Data := (others => 0);
Init_GMBUS (Port, Success);
if Success then
Registers.Write
(Register => Registers.PCH_GMBUS1,
Value => GMBUS1_SOFTWARE_READY or
GMBUS1_BUS_CYCLE_INDEX or
GMBUS1_BUS_CYCLE_WAIT or
GMBUS1_TOTAL_BYTE_COUNT (Length) or
GMBUS1_SLAVE_ADDRESS (Address) or
GMBUS1_DIRECTION_READ);
while Success and then Transfered < Length loop
Registers.Wait_Set_Mask
(Register => Registers.PCH_GMBUS2,
Mask => GMBUS2_HARDWARE_READY,
TOut_MS => 55);
Registers.Read (Registers.PCH_GMBUS2, GMBUS2);
Success := (GMBUS2 and GMBUS2_HARDWARE_READY) /= 0 and
(GMBUS2 and GMBUS2_NAK_INDICATOR) = 0;
if Success then
Current := GFX.I2C.Transfer_Length'Min (Length, Transfered + 4);
Registers.Read (Registers.PCH_GMBUS3, GMBUS3);
for I in Transfered .. Current - 1 loop
Data (I) := Byte (GMBUS3 and 16#ff#);
GMBUS3 := Shift_Right (GMBUS3, 8);
end loop;
Transfered := Current;
end if;
end loop;
if Success then
Registers.Wait_Set_Mask
(Register => Registers.PCH_GMBUS2,
Mask => GMBUS2_HARDWARE_WAIT_PHASE);
Registers.Write
(Register => Registers.PCH_GMBUS1,
Value => GMBUS1_SOFTWARE_READY or GMBUS1_BUS_CYCLE_STOP);
Registers.Wait_Unset_Mask
(Register => Registers.PCH_GMBUS2,
Mask => GMBUS2_GMBUS_ACTIVE);
end if;
end if;
Length := Transfered;
Release_GMBUS;
end I2C_Read;
end HW.GFX.GMA.I2C;

25
common/hw-gfx-gma-i2c.ads Normal file
View File

@ -0,0 +1,25 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.I2C;
private package HW.GFX.GMA.I2C is
procedure I2C_Read
(Port : in PCH_Port;
Address : in HW.GFX.I2C.Transfer_Address;
Length : in out HW.GFX.I2C.Transfer_Length;
Data : out HW.GFX.I2C.Transfer_Data;
Success : out Boolean);
end HW.GFX.GMA.I2C;

358
common/hw-gfx-gma-panel.adb Normal file
View File

@ -0,0 +1,358 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.Panel
with
Refined_State =>
(Panel_State =>
(Delays_US, Power_Cycle_Timer, Power_Up_Timer))
is
type Delays_Enum is
(Power_Up_Delay,
Power_Up_To_BL_On,
Power_Down_Delay,
BL_Off_To_Power_Down,
Power_Cycle_Delay);
type Panel_Power_Delays is array (Delays_Enum) of Natural;
Default_EDP_Delays_US : constant Panel_Power_Delays := Panel_Power_Delays'
(Power_Up_Delay => 210_000,
Power_Up_To_BL_On => 50_000,
Power_Down_Delay => 500_000,
BL_Off_To_Power_Down => 50_000,
Power_Cycle_Delay => 510_000);
Delays_US : Panel_Power_Delays;
----------------------------------------------------------------------------
-- And here the mess starts: We have this pretty hardware power sequencer
-- that should ensure the panel's timing constraints are satisfied. But
-- (at least on some generations) it doesn't do it's job. On Haswell, it
-- seems to ignore the Power_Cycle_Delay, so we ensure the delay in soft-
-- ware. On at least Ivy Bridge and Broadwell Power_Up_Delay is ignored.
--
-- If we ever do all delays in software, there are two ways: Either confi-
-- gure the hardware to zero delays or wait for both the software timeout
-- and the hardware power sequencer. The latter option would be less error
-- prone, as the hardware might just don't work as expected.
Power_Cycle_Timer : Time.T;
Power_Up_Timer : Time.T;
----------------------------------------------------------------------------
function Div_Round_Up32 (Numerator, Denominator : Natural) return Word32 is
begin
return (Word32 (Numerator) + Word32 (Denominator) - 1)
/ Word32 (Denominator);
end Div_Round_Up32;
PCH_PP_STATUS_ENABLED : constant := 16#00_0001# * 2 ** 31;
PCH_PP_STATUS_REQUIRE_ASSET : constant := 16#00_0001# * 2 ** 30;
PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK : constant := 16#00_0003# * 2 ** 28;
PCH_PP_STATUS_PWR_SEQ_PROGRESS_NONE : constant := 16#00_0000# * 2 ** 28;
PCH_PP_STATUS_PWR_SEQ_PROGRESS_UP : constant := 16#00_0001# * 2 ** 28;
PCH_PP_STATUS_PWR_SEQ_PROGRESS_DOWN : constant := 16#00_0002# * 2 ** 28;
PCH_PP_STATUS_PWR_CYC_DELAY_ACTIVE : constant := 16#00_0001# * 2 ** 27;
PCH_PP_CONTROL_WRITE_PROTECT_MASK : constant := 16#00_ffff# * 2 ** 16;
PCH_PP_CONTROL_WRITE_PROTECT_KEY : constant := 16#00_abcd# * 2 ** 16;
PCH_PP_CONTROL_VDD_OVERRIDE : constant := 16#00_0001# * 2 ** 3;
PCH_PP_CONTROL_BACKLIGHT_ENABLE : constant := 16#00_0001# * 2 ** 2;
PCH_PP_CONTROL_POWER_DOWN_ON_RESET : constant := 16#00_0001# * 2 ** 1;
PCH_PP_CONTROL_TARGET_ON : constant := 16#00_0001# * 2 ** 0;
PCH_PP_ON_DELAYS_PORT_SELECT_MASK : constant := 16#00_0003# * 2 ** 30;
PCH_PP_ON_DELAYS_PORT_SELECT_LVDS : constant := 16#00_0000# * 2 ** 30;
PCH_PP_ON_DELAYS_PORT_SELECT_DP_A : constant := 16#00_0001# * 2 ** 30;
PCH_PP_ON_DELAYS_PORT_SELECT_DP_C : constant := 16#00_0002# * 2 ** 30;
PCH_PP_ON_DELAYS_PORT_SELECT_DP_D : constant := 16#00_0003# * 2 ** 30;
PCH_PP_ON_DELAYS_PWR_UP_MASK : constant := 16#00_1fff# * 2 ** 16;
PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK : constant := 16#00_1fff# * 2 ** 0;
function PCH_PP_ON_DELAYS_PWR_UP (US : Natural) return Word32 is
begin
return Shift_Left (Div_Round_Up32 (US, 100), 16);
end PCH_PP_ON_DELAYS_PWR_UP;
function PCH_PP_ON_DELAYS_PWR_UP_BL_ON (US : Natural) return Word32 is
begin
return Div_Round_Up32 (US, 100);
end PCH_PP_ON_DELAYS_PWR_UP_BL_ON;
PCH_PP_OFF_DELAYS_PWR_DOWN_MASK : constant := 16#1fff# * 2 ** 16;
PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK : constant := 16#1fff# * 2 ** 0;
function PCH_PP_OFF_DELAYS_PWR_DOWN (US : Natural) return Word32 is
begin
return Shift_Left (Div_Round_Up32 (US, 100), 16);
end PCH_PP_OFF_DELAYS_PWR_DOWN;
function PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN (US : Natural) return Word32 is
begin
return Div_Round_Up32 (US, 100);
end PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN;
PCH_PP_DIVISOR_REF_DIVIDER_MASK : constant := 16#ff_ffff# * 2 ** 8;
PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK : constant := 16#00_001f# * 2 ** 0;
function PCH_PP_DIVISOR_PWR_CYC_DELAY (US : Natural) return Word32 is
begin
return Div_Round_Up32 (US, 100_000) + 1;
end PCH_PP_DIVISOR_PWR_CYC_DELAY;
CPU_BLC_PWM_CTL_ENABLE : constant := 16#00_0001# * 2 ** 31;
CPU_BLC_PWM_CTL_PIPE_SELECT_MASK : constant := 16#00_0003# * 2 ** 29;
CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_A : constant := 16#00_0000# * 2 ** 29;
CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_B : constant := 16#00_0001# * 2 ** 29;
CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_C : constant := 16#00_0002# * 2 ** 29;
CPU_BLC_PWM_DATA_BL_DUTY_CYC_MASK : constant := 16#00_ffff# * 2 ** 0;
PCH_BLC_PWM_CTL1_ENABLE : constant := 16#00_0001# * 2 ** 31;
PCH_BLC_PWM_CTL1_BL_POLARITY_MASK : constant := 16#00_0001# * 2 ** 29;
PCH_BLC_PWM_CTL1_PHASE_IN_INTR_STAT : constant := 16#00_0001# * 2 ** 26;
PCH_BLC_PWM_CTL1_PHASE_IN_ENABLE : constant := 16#00_0001# * 2 ** 25;
PCH_BLC_PWM_CTL1_PHASE_IN_INTR_EN : constant := 16#00_0001# * 2 ** 24;
PCH_BLC_PWM_CTL1_PHASE_IN_TIME_BASE : constant := 16#00_00ff# * 2 ** 16;
PCH_BLC_PWM_CTL1_PHASE_IN_COUNT : constant := 16#00_00ff# * 2 ** 8;
PCH_BLC_PWM_CTL1_PHASE_IN_INCREMENT : constant := 16#00_00ff# * 2 ** 0;
PCH_BLC_PWM_CTL2_BL_MOD_FREQ_MASK : constant := 16#00_ffff# * 2 ** 16;
PCH_BLC_PWM_CTL2_BL_DUTY_CYC_MASK : constant := 16#00_ffff# * 2 ** 0;
----------------------------------------------------------------------------
procedure Static_Init
with
Refined_Global =>
(Output => (Power_Cycle_Timer, Power_Up_Timer, Delays_US),
Input => (Time.State))
is
begin
Power_Cycle_Timer := Time.Now;
Power_Up_Timer := Power_Cycle_Timer;
Delays_US := Default_EDP_Delays_US;
end Static_Init;
----------------------------------------------------------------------------
procedure Check_PP_Delays
(Delays : in out Panel_Power_Delays;
Override : in out Boolean) is
begin
for D in Delays_Enum loop
if Delays (D) = 0 then
Delays (D) := Default_EDP_Delays_US (D);
Override := True;
end if;
end loop;
end Check_PP_Delays;
procedure Setup_PP_Sequencer (Default_Delays : Boolean := False)
is
Power_Delay, Port_Select : Word32;
Override_Delays : Boolean := False;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Static_Init;
if Default_Delays then
Override_Delays := True;
else
Registers.Read (Registers.PCH_PP_ON_DELAYS, Power_Delay);
Delays_US (Power_Up_Delay) := 100 * Natural
(Shift_Right (Power_Delay and PCH_PP_ON_DELAYS_PWR_UP_MASK, 16));
Delays_US (Power_Up_To_BL_On) := 100 * Natural
(Power_Delay and PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK);
Registers.Read (Registers.PCH_PP_OFF_DELAYS, Power_Delay);
Delays_US (Power_Down_Delay) := 100 * Natural
(Shift_Right (Power_Delay and PCH_PP_OFF_DELAYS_PWR_DOWN_MASK, 16));
Delays_US (BL_Off_To_Power_Down) := 100 * Natural
(Power_Delay and PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK);
Registers.Read (Registers.PCH_PP_DIVISOR, Power_Delay);
if (Power_Delay and PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK) > 1 then
Delays_US (Power_Cycle_Delay) := 100_000 * (Natural
(Power_Delay and PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK) - 1);
end if;
Check_PP_Delays (Delays_US, Override_Delays);
end if;
if Override_Delays then
if Config.Has_PP_Port_Select then
if Config.Internal_Is_EDP then
Port_Select := PCH_PP_ON_DELAYS_PORT_SELECT_DP_A;
else
Port_Select := PCH_PP_ON_DELAYS_PORT_SELECT_LVDS;
end if;
else
Port_Select := 0;
end if;
-- Force power-up to backlight-on delay to 100us as recommended by PRM.
Registers.Unset_And_Set_Mask
(Register => Registers.PCH_PP_ON_DELAYS,
Mask_Unset => PCH_PP_ON_DELAYS_PORT_SELECT_MASK or
PCH_PP_ON_DELAYS_PWR_UP_MASK or
PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK,
Mask_Set => Port_Select or
PCH_PP_ON_DELAYS_PWR_UP (Delays_US (Power_Up_Delay))
or PCH_PP_ON_DELAYS_PWR_UP_BL_ON (100));
Registers.Unset_And_Set_Mask
(Register => Registers.PCH_PP_OFF_DELAYS,
Mask_Unset => PCH_PP_OFF_DELAYS_PWR_DOWN_MASK or
PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK,
Mask_Set => PCH_PP_OFF_DELAYS_PWR_DOWN
(Delays_US (Power_Down_Delay)) or
PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN
(Delays_US (BL_Off_To_Power_Down)));
Registers.Unset_And_Set_Mask
(Register => Registers.PCH_PP_DIVISOR,
Mask_Unset => PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK,
Mask_Set => PCH_PP_DIVISOR_PWR_CYC_DELAY
(Delays_US (Power_Cycle_Delay)));
end if;
if Config.Has_PP_Write_Protection then
Registers.Unset_And_Set_Mask
(Register => Registers.PCH_PP_CONTROL,
Mask_Unset => PCH_PP_CONTROL_WRITE_PROTECT_MASK,
Mask_Set => PCH_PP_CONTROL_WRITE_PROTECT_KEY or
PCH_PP_CONTROL_POWER_DOWN_ON_RESET);
else
Registers.Set_Mask
(Register => Registers.PCH_PP_CONTROL,
Mask => PCH_PP_CONTROL_POWER_DOWN_ON_RESET);
end if;
end Setup_PP_Sequencer;
----------------------------------------------------------------------------
procedure VDD_Override is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
-- Yeah, We could do, what we are supposed to do here. But OTOH, we
-- are should wait for the full Power Up Delay, which we would have
-- to do later again. And just powering on the display seems to work
-- too. Also this function vanished on newer hardware.
On;
end VDD_Override;
procedure On (Wait : Boolean := True)
is
Was_On : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Is_Set_Mask (Registers.PCH_PP_CONTROL, PCH_PP_CONTROL_TARGET_ON, Was_On);
if not Was_On then
Time.Delay_Until (Power_Cycle_Timer);
end if;
Registers.Set_Mask (Registers.PCH_PP_CONTROL, PCH_PP_CONTROL_TARGET_ON);
if not Was_On then
Power_Up_Timer := Time.US_From_Now (Delays_US (Power_Up_Delay));
end if;
if Wait then
Wait_On;
end if;
end On;
procedure Wait_On is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Time.Delay_Until (Power_Up_Timer);
Registers.Wait_Unset_Mask
(Register => Registers.PCH_PP_STATUS,
Mask => PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK,
TOut_MS => 300);
Registers.Unset_Mask (Registers.PCH_PP_CONTROL, PCH_PP_CONTROL_VDD_OVERRIDE);
end Wait_On;
procedure Off
is
Was_On : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Is_Set_Mask (Registers.PCH_PP_CONTROL, PCH_PP_CONTROL_TARGET_ON, Was_On);
Registers.Unset_Mask
(Register => Registers.PCH_PP_CONTROL,
Mask => PCH_PP_CONTROL_TARGET_ON or
PCH_PP_CONTROL_VDD_OVERRIDE);
if Was_On then
Time.U_Delay (Delays_US (Power_Down_Delay));
end if;
Registers.Wait_Unset_Mask
(Register => Registers.PCH_PP_STATUS,
Mask => PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK,
TOut_MS => 600);
if Was_On then
Power_Cycle_Timer := Time.US_From_Now (Delays_US (Power_Cycle_Delay));
end if;
end Off;
----------------------------------------------------------------------------
procedure Backlight_On is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Set_Mask
(Register => Registers.PCH_PP_CONTROL,
Mask => PCH_PP_CONTROL_BACKLIGHT_ENABLE);
end Backlight_On;
procedure Backlight_Off is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_Mask
(Register => Registers.PCH_PP_CONTROL,
Mask => PCH_PP_CONTROL_BACKLIGHT_ENABLE);
end Backlight_Off;
procedure Set_Backlight (Level : Word16) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_And_Set_Mask
(Register => Registers.BLC_PWM_CPU_CTL,
Mask_Unset => CPU_BLC_PWM_DATA_BL_DUTY_CYC_MASK,
Mask_Set => Word32 (Level));
end Set_Backlight;
procedure Get_Max_Backlight (Level : out Word16)
is
Reg : Word32;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Read (Registers.BLC_PWM_PCH_CTL2, Reg);
Level := Word16
(Shift_Right (Reg and PCH_BLC_PWM_CTL2_BL_MOD_FREQ_MASK, 16));
end Get_Max_Backlight;
end HW.GFX.GMA.Panel;

View File

@ -0,0 +1,60 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.GMA.Registers;
private package HW.GFX.GMA.Panel
with
Abstract_State => (Panel_State with Part_Of => GMA.State)
is
procedure Static_Init
with
Global =>
(Output => Panel_State,
Input => Time.State);
procedure Setup_PP_Sequencer (Default_Delays : Boolean := False)
with
Global =>
(Input => Time.State,
In_Out => Registers.Register_State,
Output => Panel_State),
Depends =>
((Panel_State, Registers.Register_State) =>
(Time.State, Registers.Register_State, Default_Delays)),
Pre => True,
Post => True;
----------------------------------------------------------------------------
procedure VDD_Override;
procedure On (Wait : Boolean := True);
procedure Wait_On;
procedure Off;
----------------------------------------------------------------------------
procedure Backlight_On;
procedure Backlight_Off;
procedure Set_Backlight (Level : Word16);
procedure Get_Max_Backlight (Level : out Word16);
end HW.GFX.GMA.Panel;

View File

@ -0,0 +1,293 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.PCH.FDI is
FDI_RX_CTL_FDI_RX_ENABLE : constant := 1 * 2 ** 31;
FDI_RX_CTL_FS_ERROR_CORRECTION_ENABLE : constant := 1 * 2 ** 27;
FDI_RX_CTL_FE_ERROR_CORRECTION_ENABLE : constant := 1 * 2 ** 26;
FDI_RX_CTL_PORT_WIDTH_SEL_SHIFT : constant := 19;
FDI_RX_CTL_FDI_PLL_ENABLE : constant := 1 * 2 ** 13;
FDI_RX_CTL_COMPOSITE_SYNC_SELECT : constant := 1 * 2 ** 11;
FDI_RX_CTL_FDI_AUTO_TRAIN : constant := 1 * 2 ** 10;
FDI_RX_CTL_ENHANCED_FRAMING_ENABLE : constant := 1 * 2 ** 6;
FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_MASK : constant := 1 * 2 ** 4;
FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_RAWCLK : constant := 0 * 2 ** 4;
FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_PCDCLK : constant := 1 * 2 ** 4;
TP_SHIFT : constant := (if Config.CPU = Ironlake then 28 else 8);
FDI_RX_CTL_TRAINING_PATTERN_MASK : constant := 3 * 2 ** TP_SHIFT;
type TP_Array is array (Training_Pattern) of Word32;
FDI_RX_CTL_TRAINING_PATTERN : constant TP_Array :=
(TP_1 => 0 * 2 ** TP_SHIFT,
TP_2 => 1 * 2 ** TP_SHIFT,
TP_Idle => 2 * 2 ** TP_SHIFT,
TP_None => 3 * 2 ** TP_SHIFT);
function FDI_RX_CTL_PORT_WIDTH_SEL (Lane_Count : DP_Lane_Count) return Word32
is
begin
return Shift_Left
(Word32 (Lane_Count_As_Integer (Lane_Count)) - 1,
FDI_RX_CTL_PORT_WIDTH_SEL_SHIFT);
end FDI_RX_CTL_PORT_WIDTH_SEL;
function FDI_RX_CTL_BPC (BPC : BPC_Type) return Word32
with Pre => True
is
begin
return
(case BPC is
when 6 => 2 * 2 ** 16,
when 10 => 1 * 2 ** 16,
when 12 => 3 * 2 ** 16,
when others => 0 * 2 ** 16);
end FDI_RX_CTL_BPC;
FDI_RX_MISC_FDI_RX_PWRDN_LANE1_SHIFT : constant := 26;
FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK : constant := 3 * 2 ** 26;
FDI_RX_MISC_FDI_RX_PWRDN_LANE0_SHIFT : constant := 24;
FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK : constant := 3 * 2 ** 24;
FDI_RX_MISC_TP1_TO_TP2_TIME_48 : constant := 2 * 2 ** 20;
FDI_RX_MISC_FDI_DELAY_90 : constant := 16#90# * 2 ** 0;
function FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (Value : Word32) return Word32
with Pre => True
is
begin
return Shift_Left (Value, FDI_RX_MISC_FDI_RX_PWRDN_LANE1_SHIFT);
end FDI_RX_MISC_FDI_RX_PWRDN_LANE1;
function FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (Value : Word32) return Word32
with Pre => True
is
begin
return Shift_Left (Value, FDI_RX_MISC_FDI_RX_PWRDN_LANE0_SHIFT);
end FDI_RX_MISC_FDI_RX_PWRDN_LANE0;
FDI_RX_TUSIZE_SHIFT : constant := 25;
function FDI_RX_TUSIZE (Value : Word32) return Word32 is
begin
return Shift_Left (Value - 1, FDI_RX_TUSIZE_SHIFT);
end FDI_RX_TUSIZE;
FDI_RX_INTERLANE_ALIGNMENT : constant := 1 * 2 ** 10;
FDI_RX_SYMBOL_LOCK : constant := 1 * 2 ** 9;
FDI_RX_BIT_LOCK : constant := 1 * 2 ** 8;
----------------------------------------------------------------------------
type FDI_Registers is record
RX_CTL : Registers.Registers_Index;
RX_MISC : Registers.Registers_Index;
RX_TUSIZE : Registers.Registers_Index;
RX_IMR : Registers.Registers_Index;
RX_IIR : Registers.Registers_Index;
end record;
type FDI_Registers_Array is array (PCH.FDI_Port_Type) of FDI_Registers;
FDI_Regs : constant FDI_Registers_Array := FDI_Registers_Array'
(PCH.FDI_A => FDI_Registers'
(RX_CTL => Registers.FDI_RXA_CTL,
RX_MISC => Registers.FDI_RX_MISC_A,
RX_TUSIZE => Registers.FDI_RXA_TUSIZE1,
RX_IMR => Registers.FDI_RXA_IMR,
RX_IIR => Registers.FDI_RXA_IIR),
PCH.FDI_B => FDI_Registers'
(RX_CTL => Registers.FDI_RXB_CTL,
RX_MISC => Registers.FDI_RX_MISC_B,
RX_TUSIZE => Registers.FDI_RXB_TUSIZE1,
RX_IMR => Registers.FDI_RXB_IMR,
RX_IIR => Registers.FDI_RXB_IIR),
PCH.FDI_C => FDI_Registers'
(RX_CTL => Registers.FDI_RXC_CTL,
RX_MISC => Registers.FDI_RX_MISC_C,
RX_TUSIZE => Registers.FDI_RXC_TUSIZE1,
RX_IMR => Registers.FDI_RXC_IMR,
RX_IIR => Registers.FDI_RXC_IIR));
----------------------------------------------------------------------------
procedure Pre_Train (Port : PCH.FDI_Port_Type; Port_Cfg : Port_Config)
is
Power_Down_Lane_Bits : constant Word32 :=
(if Config.Has_FDI_RX_Power_Down then
FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (2) or
FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (2)
else 0);
RX_CTL_Settings : constant Word32 :=
FDI_RX_CTL_PORT_WIDTH_SEL (Port_Cfg.FDI.Lane_Count) or
(if Config.Has_FDI_BPC then
FDI_RX_CTL_BPC (Port_Cfg.Mode.BPC) else 0) or
(if Config.Has_FDI_Composite_Sel then
FDI_RX_CTL_COMPOSITE_SYNC_SELECT else 0) or
(if Port_Cfg.FDI.Enhanced_Framing then
FDI_RX_CTL_ENHANCED_FRAMING_ENABLE else 0);
begin
-- TODO: HSW: check DISPIO_CR_TX_BMU_CR4, seems Linux doesn't know it
Registers.Write
(Register => FDI_Regs (Port).RX_MISC,
Value => Power_Down_Lane_Bits or
FDI_RX_MISC_TP1_TO_TP2_TIME_48 or
FDI_RX_MISC_FDI_DELAY_90);
Registers.Write
(Register => FDI_Regs (Port).RX_TUSIZE,
Value => FDI_RX_TUSIZE (64));
Registers.Unset_Mask
(Register => FDI_Regs (Port).RX_IMR,
Mask => FDI_RX_INTERLANE_ALIGNMENT or
FDI_RX_SYMBOL_LOCK or
FDI_RX_BIT_LOCK);
Registers.Posting_Read (FDI_Regs (Port).RX_IMR);
-- clear stale lock bits
Registers.Write
(Register => FDI_Regs (Port).RX_IIR,
Value => FDI_RX_INTERLANE_ALIGNMENT or
FDI_RX_SYMBOL_LOCK or
FDI_RX_BIT_LOCK);
Registers.Write
(Register => FDI_Regs (Port).RX_CTL,
Value => FDI_RX_CTL_FDI_PLL_ENABLE or
RX_CTL_Settings);
Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
Time.U_Delay (220);
Registers.Set_Mask
(Register => FDI_Regs (Port).RX_CTL,
Mask => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_PCDCLK);
end Pre_Train;
procedure Train
(Port : in PCH.FDI_Port_Type;
TP : in Training_Pattern;
Success : out Boolean)
is
Lock_Bit : constant Word32 :=
(if TP = TP_1 then FDI_RX_BIT_LOCK else FDI_RX_SYMBOL_LOCK);
procedure Check_Lock (Lock_Bit : Word32)
is
begin
for I in 1 .. 5 loop
Registers.Is_Set_Mask
(Register => FDI_Regs (Port).RX_IIR,
Mask => Lock_Bit,
Result => Success);
if Success then
-- clear the lock bit
Registers.Write
(Register => FDI_Regs (Port).RX_IIR,
Value => Lock_Bit);
end if;
exit when Success;
Time.U_Delay (1);
end loop;
end Check_Lock;
begin
Registers.Unset_And_Set_Mask
(Register => FDI_Regs (Port).RX_CTL,
Mask_Unset => FDI_RX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_RX_CTL_FDI_RX_ENABLE or
FDI_RX_CTL_TRAINING_PATTERN (TP));
Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
if TP <= TP_2 then
Time.U_Delay (1);
if TP = TP_1 then
Check_Lock (FDI_RX_BIT_LOCK);
else
Check_Lock (FDI_RX_SYMBOL_LOCK);
if Success then
Check_Lock (FDI_RX_INTERLANE_ALIGNMENT);
end if;
end if;
else
Time.U_Delay (31);
Success := True;
end if;
end Train;
procedure Auto_Train (Port : PCH.FDI_Port_Type)
is
begin
Registers.Set_Mask
(Register => FDI_Regs (Port).RX_CTL,
Mask => FDI_RX_CTL_FDI_RX_ENABLE or
FDI_RX_CTL_FDI_AUTO_TRAIN);
Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
if Config.Has_FDI_RX_Power_Down then
Time.U_Delay (30);
Registers.Unset_And_Set_Mask
(Register => FDI_Regs (Port).RX_MISC,
Mask_Unset => FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK or
FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK,
Mask_Set => FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (0) or
FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (0));
Registers.Posting_Read (FDI_Regs (Port).RX_MISC);
end if;
Time.U_Delay (5);
end Auto_Train;
procedure Enable_EC (Port : PCH.FDI_Port_Type)
is
begin
Registers.Set_Mask
(Register => FDI_Regs (Port).RX_CTL,
Mask => FDI_RX_CTL_FS_ERROR_CORRECTION_ENABLE or
FDI_RX_CTL_FE_ERROR_CORRECTION_ENABLE);
end Enable_EC;
----------------------------------------------------------------------------
procedure Off (Port : PCH.FDI_Port_Type; OT : Off_Type)
is
begin
Registers.Unset_Mask
(Register => FDI_Regs (Port).RX_CTL,
Mask => FDI_RX_CTL_FDI_RX_ENABLE or
FDI_RX_CTL_FDI_AUTO_TRAIN);
if Config.Has_FDI_RX_Power_Down and then OT >= Lanes_Off then
Registers.Unset_And_Set_Mask
(Register => FDI_Regs (Port).RX_MISC,
Mask_Unset => FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK or
FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK,
Mask_Set => FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (2) or
FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (2));
Registers.Posting_Read (FDI_Regs (Port).RX_MISC);
end if;
if OT >= Clock_Off then
Registers.Unset_And_Set_Mask
(Register => FDI_Regs (Port).RX_CTL,
Mask_Unset => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_MASK,
Mask_Set => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_RAWCLK);
Registers.Unset_Mask
(Register => FDI_Regs (Port).RX_CTL,
Mask => FDI_RX_CTL_FDI_PLL_ENABLE);
end if;
end Off;
end HW.GFX.GMA.PCH.FDI;

View File

@ -0,0 +1,29 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.GMA.PCH.FDI is
type Training_Pattern is (TP_1, TP_2, TP_Idle, TP_None);
procedure Pre_Train (Port : PCH.FDI_Port_Type; Port_Cfg : Port_Config);
procedure Train
(Port : in PCH.FDI_Port_Type;
TP : in Training_Pattern;
Success : out Boolean);
procedure Auto_Train (Port : PCH.FDI_Port_Type);
procedure Enable_EC (Port : PCH.FDI_Port_Type);
type Off_Type is (Rx_Off, Lanes_Off, Clock_Off);
procedure Off (Port : PCH.FDI_Port_Type; OT : Off_Type);
end HW.GFX.GMA.PCH.FDI;

View File

@ -0,0 +1,137 @@
--
-- Copyright (C) 2015 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.PCH.Sideband is
SBI_CTL_DEST_ICLK : constant := 0 * 2 ** 16;
SBI_CTL_DEST_MPHY : constant := 1 * 2 ** 16;
SBI_CTL_OP_IORD : constant := 2 * 2 ** 8;
SBI_CTL_OP_IOWR : constant := 3 * 2 ** 8;
SBI_CTL_OP_CRRD : constant := 6 * 2 ** 8;
SBI_CTL_OP_CRWR : constant := 7 * 2 ** 8;
SBI_RESPONSE_FAIL : constant := 1 * 2 ** 1;
SBI_BUSY : constant := 1 * 2 ** 0;
type Register_Array is array (Register_Type) of Word32;
Register_Addr : constant Register_Array := Register_Array'
(SBI_SSCDIVINTPHASE6 => 16#0600_0000#,
SBI_SSCCTL6 => 16#060c_0000#,
SBI_SSCAUXDIV => 16#0610_0000#);
----------------------------------------------------------------------------
procedure Read
(Dest : in Destination_Type;
Register : in Register_Type;
Value : out Word32)
is
begin
Registers.Wait_Unset_Mask
(Register => Registers.SBI_CTL_STAT,
Mask => SBI_BUSY);
Registers.Write
(Register => Registers.SBI_ADDR,
Value => Register_Addr (Register));
if Dest = SBI_ICLK then
Registers.Write
(Register => Registers.SBI_CTL_STAT,
Value => SBI_CTL_DEST_ICLK or SBI_CTL_OP_CRRD or SBI_BUSY);
else
Registers.Write
(Register => Registers.SBI_CTL_STAT,
Value => SBI_CTL_DEST_MPHY or SBI_CTL_OP_IORD or SBI_BUSY);
end if;
Registers.Wait_Unset_Mask
(Register => Registers.SBI_CTL_STAT,
Mask => SBI_BUSY);
Registers.Read
(Register => Registers.SBI_DATA,
Value => Value);
end Read;
procedure Write
(Dest : in Destination_Type;
Register : in Register_Type;
Value : in Word32)
is
begin
Registers.Wait_Unset_Mask
(Register => Registers.SBI_CTL_STAT,
Mask => SBI_BUSY);
Registers.Write
(Register => Registers.SBI_ADDR,
Value => Register_Addr (Register));
Registers.Write
(Register => Registers.SBI_DATA,
Value => Value);
if Dest = SBI_ICLK then
Registers.Write
(Register => Registers.SBI_CTL_STAT,
Value => SBI_CTL_DEST_ICLK or SBI_CTL_OP_CRWR or SBI_BUSY);
else
Registers.Write
(Register => Registers.SBI_CTL_STAT,
Value => SBI_CTL_DEST_MPHY or SBI_CTL_OP_IOWR or SBI_BUSY);
end if;
Registers.Wait_Unset_Mask
(Register => Registers.SBI_CTL_STAT,
Mask => SBI_BUSY);
end Write;
----------------------------------------------------------------------------
procedure Unset_Mask
(Dest : in Destination_Type;
Register : in Register_Type;
Mask : in Word32)
is
Value : Word32;
begin
Read (Dest, Register, Value);
Write (Dest, Register, Value and not Mask);
end Unset_Mask;
procedure Set_Mask
(Dest : in Destination_Type;
Register : in Register_Type;
Mask : in Word32)
is
Value : Word32;
begin
Read (Dest, Register, Value);
Write (Dest, Register, Value or Mask);
end Set_Mask;
procedure Unset_And_Set_Mask
(Dest : in Destination_Type;
Register : in Register_Type;
Mask_Unset : in Word32;
Mask_Set : in Word32)
is
Value : Word32;
begin
Read (Dest, Register, Value);
Write (Dest, Register, (Value and not Mask_Unset) or Mask_Set);
end Unset_And_Set_Mask;
end HW.GFX.GMA.PCH.Sideband;

View File

@ -0,0 +1,49 @@
--
-- Copyright (C) 2015 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.PCH.Sideband is
type Destination_Type is (SBI_ICLK, SBI_MPHY);
type Register_Type is
(SBI_SSCDIVINTPHASE6,
SBI_SSCCTL6,
SBI_SSCAUXDIV);
procedure Read
(Dest : in Destination_Type;
Register : in Register_Type;
Value : out Word32);
procedure Write
(Dest : in Destination_Type;
Register : in Register_Type;
Value : in Word32);
procedure Unset_Mask
(Dest : in Destination_Type;
Register : in Register_Type;
Mask : in Word32);
procedure Set_Mask
(Dest : in Destination_Type;
Register : in Register_Type;
Mask : in Word32);
procedure Unset_And_Set_Mask
(Dest : in Destination_Type;
Register : in Register_Type;
Mask_Unset : in Word32;
Mask_Set : in Word32);
end HW.GFX.GMA.PCH.Sideband;

View File

@ -0,0 +1,280 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
-- Copyright (C) 2016 Nico Huber <nico.h@gmx.de>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
with HW.GFX.GMA.DP_Info;
with HW.GFX.GMA.Registers;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.PCH.Transcoder is
type DPLL_SEL_Array is array (FDI_Port_Type) of Word32;
DPLL_SEL_TRANSCODER_x_DPLL_ENABLE : constant DPLL_SEL_Array :=
(FDI_A => 1 * 2 ** 3,
FDI_B => 1 * 2 ** 7,
FDI_C => 1 * 2 ** 11);
DPLL_SEL_TRANSCODER_x_DPLL_SEL_MASK : constant DPLL_SEL_Array :=
(FDI_A => 1 * 2 ** 0,
FDI_B => 1 * 2 ** 4,
FDI_C => 1 * 2 ** 8);
function DPLL_SEL_TRANSCODER_x_DPLL_SEL
(Port : FDI_Port_Type;
PLL : Word32)
return Word32
is
begin
return Shift_Left (PLL,
(case Port is
when FDI_A => 0,
when FDI_B => 4,
when FDI_C => 8));
end DPLL_SEL_TRANSCODER_x_DPLL_SEL;
TRANS_CONF_TRANSCODER_ENABLE : constant := 1 * 2 ** 31;
TRANS_CONF_TRANSCODER_STATE : constant := 1 * 2 ** 30;
TRANS_CHICKEN2_TIMING_OVERRIDE : constant := 1 * 2 ** 31;
TRANS_DP_CTL_OUTPUT_ENABLE : constant := 1 * 2 ** 31;
TRANS_DP_CTL_PORT_SELECT_MASK : constant := 3 * 2 ** 29;
TRANS_DP_CTL_PORT_SELECT_NONE : constant := 3 * 2 ** 29;
TRANS_DP_CTL_ENHANCED_FRAMING : constant := 1 * 2 ** 18;
TRANS_DP_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4;
TRANS_DP_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3;
type TRANS_DP_CTL_PORT_SELECT_Array is array (PCH_Port) of Word32;
TRANS_DP_CTL_PORT_SELECT : constant TRANS_DP_CTL_PORT_SELECT_Array :=
(PCH_DP_B => 0 * 2 ** 29,
PCH_DP_C => 1 * 2 ** 29,
PCH_DP_D => 2 * 2 ** 29,
others => 0);
function TRANS_DP_CTL_BPC (BPC : BPC_Type) return Word32
is
begin
return
(case BPC is
when 6 => 2 * 2 ** 9,
when 10 => 1 * 2 ** 9,
when 12 => 3 * 2 ** 9,
when others => 0 * 2 ** 9);
end TRANS_DP_CTL_BPC;
function TRANS_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
begin
return Shift_Left (Word32 (Transfer_Unit - 1), 25);
end TRANS_DATA_M_TU;
----------------------------------------------------------------------------
type Transcoder_Registers is record
HTOTAL : Registers.Registers_Index;
HBLANK : Registers.Registers_Index;
HSYNC : Registers.Registers_Index;
VTOTAL : Registers.Registers_Index;
VBLANK : Registers.Registers_Index;
VSYNC : Registers.Registers_Index;
CONF : Registers.Registers_Index;
DP_CTL : Registers.Registers_Index;
DATA_M : Registers.Registers_Index;
DATA_N : Registers.Registers_Index;
LINK_M : Registers.Registers_Index;
LINK_N : Registers.Registers_Index;
CHICKEN2 : Registers.Registers_Index;
end record;
type Transcoder_Registers_Array is
array (FDI_Port_Type) of Transcoder_Registers;
TRANS : constant Transcoder_Registers_Array := Transcoder_Registers_Array'
(FDI_A =>
(HTOTAL => Registers.TRANS_HTOTAL_A,
HBLANK => Registers.TRANS_HBLANK_A,
HSYNC => Registers.TRANS_HSYNC_A,
VTOTAL => Registers.TRANS_VTOTAL_A,
VBLANK => Registers.TRANS_VBLANK_A,
VSYNC => Registers.TRANS_VSYNC_A,
CONF => Registers.TRANSACONF,
DP_CTL => Registers.TRANS_DP_CTL_A,
DATA_M => Registers.TRANSA_DATA_M1,
DATA_N => Registers.TRANSA_DATA_N1,
LINK_M => Registers.TRANSA_DP_LINK_M1,
LINK_N => Registers.TRANSA_DP_LINK_N1,
CHICKEN2 => Registers.TRANSA_CHICKEN2),
FDI_B =>
(HTOTAL => Registers.TRANS_HTOTAL_B,
HBLANK => Registers.TRANS_HBLANK_B,
HSYNC => Registers.TRANS_HSYNC_B,
VTOTAL => Registers.TRANS_VTOTAL_B,
VBLANK => Registers.TRANS_VBLANK_B,
VSYNC => Registers.TRANS_VSYNC_B,
CONF => Registers.TRANSBCONF,
DP_CTL => Registers.TRANS_DP_CTL_B,
DATA_M => Registers.TRANSB_DATA_M1,
DATA_N => Registers.TRANSB_DATA_N1,
LINK_M => Registers.TRANSB_DP_LINK_M1,
LINK_N => Registers.TRANSB_DP_LINK_N1,
CHICKEN2 => Registers.TRANSB_CHICKEN2),
FDI_C =>
(HTOTAL => Registers.TRANS_HTOTAL_C,
HBLANK => Registers.TRANS_HBLANK_C,
HSYNC => Registers.TRANS_HSYNC_C,
VTOTAL => Registers.TRANS_VTOTAL_C,
VBLANK => Registers.TRANS_VBLANK_C,
VSYNC => Registers.TRANS_VSYNC_C,
CONF => Registers.TRANSCCONF,
DP_CTL => Registers.TRANS_DP_CTL_C,
DATA_M => Registers.TRANSC_DATA_M1,
DATA_N => Registers.TRANSC_DATA_N1,
LINK_M => Registers.TRANSC_DP_LINK_M1,
LINK_N => Registers.TRANSC_DP_LINK_N1,
CHICKEN2 => Registers.TRANSC_CHICKEN2));
----------------------------------------------------------------------------
procedure On
(Port_Cfg : Port_Config;
Port : FDI_Port_Type;
PLL : Word32)
is
Mode : constant Mode_Type := Port_Cfg.Mode;
function Encode (LSW, MSW : Pos16) return Word32 is
begin
return (Word32 (LSW) - 1) or ((Word32 (MSW) - 1) * 2 ** 16);
end Encode;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.Has_DPLL_SEL then
Registers.Unset_And_Set_Mask
(Register => Registers.PCH_DPLL_SEL,
Mask_Unset => DPLL_SEL_TRANSCODER_x_DPLL_SEL_MASK (Port),
Mask_Set => DPLL_SEL_TRANSCODER_x_DPLL_ENABLE (Port) or
DPLL_SEL_TRANSCODER_x_DPLL_SEL (Port, PLL));
end if;
Registers.Write
(Register => TRANS (Port).HTOTAL,
Value => Encode (Mode.H_Visible, Mode.H_Total));
Registers.Write
(Register => TRANS (Port).HBLANK,
Value => Encode (Mode.H_Visible, Mode.H_Total));
Registers.Write
(Register => TRANS (Port).HSYNC,
Value => Encode (Mode.H_Sync_Begin, Mode.H_Sync_End));
Registers.Write
(Register => TRANS (Port).VTOTAL,
Value => Encode (Mode.V_Visible, Mode.V_Total));
Registers.Write
(Register => TRANS (Port).VBLANK,
Value => Encode (Mode.V_Visible, Mode.V_Total));
Registers.Write
(Register => TRANS (Port).VSYNC,
Value => Encode (Mode.V_Sync_Begin, Mode.V_Sync_End));
if Port_Cfg.Display = DP then
declare
Data_M, Link_M : DP_Info.M_Type;
Data_N, Link_N : DP_Info.N_Type;
begin
DP_Info.Calculate_M_N
(Link => Port_Cfg.DP,
Mode => Port_Cfg.Mode,
Data_M => Data_M,
Data_N => Data_N,
Link_M => Link_M,
Link_N => Link_N);
Registers.Write
(Register => TRANS (Port).DATA_M,
Value => TRANS_DATA_M_TU (64) or
Word32 (Data_M));
Registers.Write
(Register => TRANS (Port).DATA_N,
Value => Word32 (Data_N));
Registers.Write
(Register => TRANS (Port).LINK_M,
Value => Word32 (Link_M));
Registers.Write
(Register => TRANS (Port).LINK_N,
Value => Word32 (Link_N));
end;
if Config.Has_Trans_DP_Ctl then
declare
Polarity : constant Word32 :=
(if Port_Cfg.Mode.H_Sync_Active_High then
TRANS_DP_CTL_HSYNC_ACTIVE_HIGH else 0) or
(if Port_Cfg.Mode.V_Sync_Active_High then
TRANS_DP_CTL_VSYNC_ACTIVE_HIGH else 0);
Enhanced_Framing : constant Word32 :=
(if Port_Cfg.DP.Enhanced_Framing then
TRANS_DP_CTL_ENHANCED_FRAMING else 0);
begin
Registers.Write
(Register => TRANS (Port).DP_CTL,
Value => TRANS_DP_CTL_OUTPUT_ENABLE or
TRANS_DP_CTL_PORT_SELECT (Port_Cfg.PCH_Port) or
Enhanced_Framing or
TRANS_DP_CTL_BPC (Port_Cfg.Mode.BPC) or
Polarity);
end;
end if;
end if;
if Config.Has_Trans_Timing_Ovrrde then
Registers.Set_Mask
(Register => TRANS (Port).CHICKEN2,
Mask => TRANS_CHICKEN2_TIMING_OVERRIDE);
end if;
Registers.Write
(Register => TRANS (Port).CONF,
Value => TRANS_CONF_TRANSCODER_ENABLE);
end On;
procedure Off (Port : FDI_Port_Type) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_Mask
(Register => TRANS (Port).CONF,
Mask => TRANS_CONF_TRANSCODER_ENABLE);
Registers.Wait_Unset_Mask
(Register => TRANS (Port).CONF,
Mask => TRANS_CONF_TRANSCODER_STATE,
TOut_MS => 50);
if Config.Has_Trans_Timing_Ovrrde then
Registers.Unset_Mask
(Register => TRANS (Port).CHICKEN2,
Mask => TRANS_CHICKEN2_TIMING_OVERRIDE);
end if;
if Config.Has_Trans_DP_Ctl then
Registers.Write
(Register => TRANS (Port).DP_CTL,
Value => TRANS_DP_CTL_PORT_SELECT_NONE);
end if;
if Config.Has_DPLL_SEL then
Registers.Unset_Mask
(Register => Registers.PCH_DPLL_SEL,
Mask => DPLL_SEL_TRANSCODER_x_DPLL_ENABLE (Port));
end if;
end Off;
end HW.GFX.GMA.PCH.Transcoder;

View File

@ -0,0 +1,24 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.GMA.PCH.Transcoder is
procedure On
(Port_Cfg : Port_Config;
Port : FDI_Port_Type;
PLL : Word32);
procedure Off
(Port : FDI_Port_Type);
end HW.GFX.GMA.PCH.Transcoder;

View File

@ -0,0 +1,171 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
with HW.GFX.GMA.PCH.Sideband;
with HW.Debug;
with GNAT.Source_Info;
use type HW.Word64;
package body HW.GFX.GMA.PCH.VGA is
PCH_ADPA_DAC_ENABLE : constant := 1 * 2 ** 31;
PCH_ADPA_VSYNC_DISABLE : constant := 1 * 2 ** 11;
PCH_ADPA_HSYNC_DISABLE : constant := 1 * 2 ** 10;
PCH_ADPA_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4;
PCH_ADPA_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3;
PCH_ADPA_MASK : constant Word32 :=
PCH_TRANSCODER_SELECT_MASK or
PCH_ADPA_DAC_ENABLE or
PCH_ADPA_VSYNC_DISABLE or
PCH_ADPA_HSYNC_DISABLE or
PCH_ADPA_VSYNC_ACTIVE_HIGH or
PCH_ADPA_HSYNC_ACTIVE_HIGH;
----------------------------------------------------------------------------
procedure On
(Port : FDI_Port_Type;
Mode : Mode_Type)
is
Polarity : Word32 := 0;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Mode.H_Sync_Active_High then
Polarity := Polarity or PCH_ADPA_HSYNC_ACTIVE_HIGH;
end if;
if Mode.V_Sync_Active_High then
Polarity := Polarity or PCH_ADPA_VSYNC_ACTIVE_HIGH;
end if;
Registers.Unset_And_Set_Mask
(Register => Registers.PCH_ADPA,
Mask_Unset => PCH_ADPA_MASK,
Mask_Set => PCH_ADPA_DAC_ENABLE or
PCH_TRANSCODER_SELECT (Port) or
Polarity);
end On;
----------------------------------------------------------------------------
procedure Off
is
Sync_Disable : Word32 := 0;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.VGA_Has_Sync_Disable then
Sync_Disable := PCH_ADPA_HSYNC_DISABLE or PCH_ADPA_VSYNC_DISABLE;
end if;
Registers.Unset_And_Set_Mask
(Register => Registers.PCH_ADPA,
Mask_Unset => PCH_ADPA_DAC_ENABLE,
Mask_Set => Sync_Disable);
end Off;
----------------------------------------------------------------------------
PCH_PIXCLK_GATE_GATE : constant := 0 * 2 ** 0;
PCH_PIXCLK_GATE_UNGATE : constant := 1 * 2 ** 0;
SBI_SSCCTL_DISABLE : constant := 1 * 2 ** 0;
SBI_SSCDIVINTPHASE_DIVSEL_SHIFT : constant := 1;
SBI_SSCDIVINTPHASE_DIVSEL_MASK : constant := 16#7f# * 2 ** 1;
SBI_SSCDIVINTPHASE_INCVAL_SHIFT : constant := 8;
SBI_SSCDIVINTPHASE_INCVAL_MASK : constant := 16#7f# * 2 ** 8;
SBI_SSCDIVINTPHASE_DIR_SHIFT : constant := 15;
SBI_SSCDIVINTPHASE_DIR_MASK : constant := 16#01# * 2 ** 15;
SBI_SSCDIVINTPHASE_PROPAGATE : constant := 1 * 2 ** 0;
SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT : constant := 4;
SBI_SSCAUXDIV_FINALDIV2SEL_MASK : constant := 16#01# * 2 ** 4;
function SBI_SSCDIVINTPHASE_DIVSEL (Val : Word32) return Word32 is
begin
return Shift_Left (Val, SBI_SSCDIVINTPHASE_DIVSEL_SHIFT);
end SBI_SSCDIVINTPHASE_DIVSEL;
function SBI_SSCDIVINTPHASE_INCVAL (Val : Word32) return Word32 is
begin
return Shift_Left (Val, SBI_SSCDIVINTPHASE_INCVAL_SHIFT);
end SBI_SSCDIVINTPHASE_INCVAL;
function SBI_SSCDIVINTPHASE_DIR (Val : Word32) return Word32 is
begin
return Shift_Left (Val, SBI_SSCDIVINTPHASE_DIR_SHIFT);
end SBI_SSCDIVINTPHASE_DIR;
function SBI_SSCAUXDIV_FINALDIV2SEL (Val : Word32) return Word32 is
begin
return Shift_Left (Val, SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT);
end SBI_SSCAUXDIV_FINALDIV2SEL;
procedure Clock_On (Mode : Mode_Type)
is
Refclock : constant := 2_700_000_000;
Aux_Div,
Div_Sel,
Phase_Inc,
Phase_Dir : Word32;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Write (Registers.PCH_PIXCLK_GATE, PCH_PIXCLK_GATE_GATE);
Sideband.Set_Mask
(Dest => Sideband.SBI_ICLK,
Register => Sideband.SBI_SSCCTL6,
Mask => SBI_SSCCTL_DISABLE);
Aux_Div := 16#0000_0000#;
Div_Sel := Word32 (Refclock / Mode.Dotclock - 2);
Phase_Inc := Word32 ((Refclock * 64) / Mode.Dotclock) and 16#0000_003f#;
Phase_Dir := 16#0000_0000#;
pragma Debug (Debug.Put_Reg32 ("Aux_Div ", Aux_Div));
pragma Debug (Debug.Put_Reg32 ("Div_Sel ", Div_Sel));
pragma Debug (Debug.Put_Reg32 ("Phase_Inc", Phase_Inc));
pragma Debug (Debug.Put_Reg32 ("Phase_Dir", Phase_Dir));
Sideband.Unset_And_Set_Mask
(Dest => Sideband.SBI_ICLK,
Register => Sideband.SBI_SSCDIVINTPHASE6,
Mask_Unset => SBI_SSCDIVINTPHASE_DIVSEL_MASK or
SBI_SSCDIVINTPHASE_INCVAL_MASK or
SBI_SSCDIVINTPHASE_DIR_MASK,
Mask_Set => SBI_SSCDIVINTPHASE_DIVSEL (Div_Sel) or
SBI_SSCDIVINTPHASE_INCVAL (Phase_Inc) or
SBI_SSCDIVINTPHASE_DIR (Phase_Dir) or
SBI_SSCDIVINTPHASE_PROPAGATE);
Sideband.Unset_And_Set_Mask
(Dest => Sideband.SBI_ICLK,
Register => Sideband.SBI_SSCAUXDIV,
Mask_Unset => SBI_SSCAUXDIV_FINALDIV2SEL_MASK,
Mask_Set => SBI_SSCAUXDIV_FINALDIV2SEL (Aux_Div));
Sideband.Unset_Mask
(Dest => Sideband.SBI_ICLK,
Register => Sideband.SBI_SSCCTL6,
Mask => SBI_SSCCTL_DISABLE);
Registers.Write (Registers.PCH_PIXCLK_GATE, PCH_PIXCLK_GATE_UNGATE);
end Clock_On;
end HW.GFX.GMA.PCH.VGA;

View File

@ -0,0 +1,24 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.GMA.PCH.VGA is
procedure On
(Port : FDI_Port_Type;
Mode : Mode_Type);
procedure Off;
procedure Clock_On (Mode : Mode_Type);
end HW.GFX.GMA.PCH.VGA;

42
common/hw-gfx-gma-pch.ads Normal file
View File

@ -0,0 +1,42 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
private package HW.GFX.GMA.PCH is
type FDI_Port_Type is (FDI_A, FDI_B, FDI_C);
----------------------------------------------------------------------------
-- common to all PCH outputs
PCH_TRANSCODER_SELECT_SHIFT : constant :=
(case Config.CPU is
when Ironlake => 30,
when Sandybridge | Ivybridge => 29,
when Haswell | Broadwell | Skylake => 0);
PCH_TRANSCODER_SELECT_MASK : constant :=
(case Config.CPU is
when Ironlake => 1 * 2 ** 30,
when Sandybridge | Ivybridge => 3 * 2 ** 29,
when Haswell | Broadwell | Skylake => 0);
type PCH_TRANSCODER_SELECT_Array is array (FDI_Port_Type) of Word32;
PCH_TRANSCODER_SELECT : constant PCH_TRANSCODER_SELECT_Array :=
(FDI_A => 0 * 2 ** PCH_TRANSCODER_SELECT_SHIFT,
FDI_B => 1 * 2 ** PCH_TRANSCODER_SELECT_SHIFT,
FDI_C => 2 * 2 ** PCH_TRANSCODER_SELECT_SHIFT);
end HW.GFX.GMA.PCH;

View File

@ -0,0 +1,610 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Debug;
with GNAT.Source_Info;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.DP_Info;
with HW.GFX.GMA.Registers;
use type HW.Word64;
use type HW.Pos16;
use type HW.Int32;
use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
package body HW.GFX.GMA.Pipe_Setup is
DSPCNTR_ENABLE : constant := 1 * 2 ** 31;
DSPCNTR_GAMMA_CORRECTION : constant := 1 * 2 ** 30;
DSPCNTR_DISABLE_TRICKLE_FEED : constant := 1 * 2 ** 14;
DSPCNTR_FORMAT_MASK : constant := 15 * 2 ** 26;
DSPCNTR_MASK : constant Word32 :=
DSPCNTR_ENABLE or
DSPCNTR_GAMMA_CORRECTION or
DSPCNTR_FORMAT_MASK or
DSPCNTR_DISABLE_TRICKLE_FEED;
PLANE_CTL_PLANE_ENABLE : constant := 1 * 2 ** 31;
PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 : constant := 4 * 2 ** 24;
PLANE_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
PLANE_WM_LINES_SHIFT : constant := 14;
PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
PLANE_WM_BLOCKS_MASK : constant := 16#03ff# * 2 ** 0;
SPCNTR_ENABLE : constant := 1 * 2 ** 31;
TRANS_CLK_SEL_PORT_NONE : constant := 0 * 2 ** 29;
type TRANS_CLK_SEL_PORT_Array is
array (Digital_Port) of Word32;
TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array :=
TRANS_CLK_SEL_PORT_Array'
(DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable
DIGI_B => 2 * 2 ** 29,
DIGI_C => 3 * 2 ** 29,
DIGI_D => 4 * 2 ** 29,
DIGI_E => 5 * 2 ** 29);
PIPECONF_ENABLE : constant := 1 * 2 ** 31;
PIPECONF_ENABLED_STATUS : constant := 1 * 2 ** 30;
PIPECONF_ENABLE_DITHER : constant := 1 * 2 ** 4;
PIPECONF_DITHER_TEMPORAL : constant := 1 * 2 ** 2;
PF_CTL_1_ENABLE : constant Word32 := 1 * 2 ** 31;
PS_CTRL_ENABLE_SCALER : constant Word32 := 1 * 2 ** 31;
PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant Word32 := 1 * 2 ** 28;
PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant Word32 := 1 * 2 ** 23;
PIPE_DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31;
PIPE_DDI_FUNC_CTL_DDI_SELECT_MASK : constant := 7 * 2 ** 28;
PIPE_DDI_FUNC_CTL_DDI_SELECT_NONE : constant := 0 * 2 ** 28;
PIPE_DDI_FUNC_CTL_DDI_SELECT_B : constant := 1 * 2 ** 28;
PIPE_DDI_FUNC_CTL_DDI_SELECT_C : constant := 2 * 2 ** 28;
PIPE_DDI_FUNC_CTL_DDI_SELECT_D : constant := 3 * 2 ** 28;
PIPE_DDI_FUNC_CTL_DDI_SELECT_E : constant := 4 * 2 ** 28;
PIPE_DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24;
PIPE_DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24;
PIPE_DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24;
PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24;
PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24;
PIPE_DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24;
PIPE_DDI_FUNC_CTL_BPC_MASK : constant := 7 * 2 ** 20;
PIPE_DDI_FUNC_CTL_BPC_8BITS : constant := 0 * 2 ** 20;
PIPE_DDI_FUNC_CTL_BPC_10BITS : constant := 1 * 2 ** 20;
PIPE_DDI_FUNC_CTL_BPC_6BITS : constant := 2 * 2 ** 20;
PIPE_DDI_FUNC_CTL_BPC_12BITS : constant := 3 * 2 ** 20;
PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_LOW : constant := 0 * 2 ** 17;
PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 17;
PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_LOW : constant := 0 * 2 ** 16;
PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 16;
PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12;
PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12;
PIPE_DDI_FUNC_CTL_EDP_SELECT_A : constant := 4 * 2 ** 12;
PIPE_DDI_FUNC_CTL_EDP_SELECT_B : constant := 5 * 2 ** 12;
PIPE_DDI_FUNC_CTL_EDP_SELECT_C : constant := 6 * 2 ** 12;
PIPE_DDI_FUNC_CTL_DP_VC_PAYLOAD_ALLOC : constant := 1 * 2 ** 8;
PIPE_DDI_FUNC_CTL_BFI_ENABLE : constant := 1 * 2 ** 4;
PIPE_DDI_FUNC_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1;
PIPE_DDI_FUNC_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1;
PIPE_DDI_FUNC_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1;
PIPE_DDI_FUNC_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1;
type DDI_Select_Array is array (Digital_Port) of Word32;
PIPE_DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array :=
DDI_Select_Array'
(DIGI_A => PIPE_DDI_FUNC_CTL_DDI_SELECT_NONE,
DIGI_B => PIPE_DDI_FUNC_CTL_DDI_SELECT_B,
DIGI_C => PIPE_DDI_FUNC_CTL_DDI_SELECT_C,
DIGI_D => PIPE_DDI_FUNC_CTL_DDI_SELECT_D,
DIGI_E => PIPE_DDI_FUNC_CTL_DDI_SELECT_E);
type DDI_Mode_Array is array (Display_Type) of Word32;
PIPE_DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array :=
DDI_Mode_Array'
(VGA => PIPE_DDI_FUNC_CTL_MODE_SELECT_FDI,
HDMI => PIPE_DDI_FUNC_CTL_MODE_SELECT_DVI,
DP => PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_SST,
others => 0);
type HV_Sync_Array is array (Boolean) of Word32;
PIPE_DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array := HV_Sync_Array'
(False => PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_LOW,
True => PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_HIGH);
PIPE_DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array := HV_Sync_Array'
(False => PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_LOW,
True => PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_HIGH);
type EDP_Select_Array is array (Controller_Kind) of Word32;
PIPE_DDI_FUNC_CTL_EDP_SELECT : constant EDP_Select_Array :=
EDP_Select_Array'
(A => PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON, -- we never use panel fitter
B => PIPE_DDI_FUNC_CTL_EDP_SELECT_B,
C => PIPE_DDI_FUNC_CTL_EDP_SELECT_C);
PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF : constant EDP_Select_Array :=
EDP_Select_Array'
(A => PIPE_DDI_FUNC_CTL_EDP_SELECT_A,
B => PIPE_DDI_FUNC_CTL_EDP_SELECT_B,
C => PIPE_DDI_FUNC_CTL_EDP_SELECT_C);
type Port_Width_Array is array (HW.GFX.DP_Lane_Count) of Word32;
PIPE_DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array :=
Port_Width_Array'
(HW.GFX.DP_Lane_Count_1 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_1_LANE,
HW.GFX.DP_Lane_Count_2 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_2_LANES,
HW.GFX.DP_Lane_Count_4 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_4_LANES);
function PIPE_DDI_FUNC_CTL_BPC (BPC : HW.GFX.BPC_Type) return Word32
is
Result : Word32;
begin
case BPC is
when 6 => Result := PIPE_DDI_FUNC_CTL_BPC_6BITS;
when 8 => Result := PIPE_DDI_FUNC_CTL_BPC_8BITS;
when 10 => Result := PIPE_DDI_FUNC_CTL_BPC_10BITS;
when 12 => Result := PIPE_DDI_FUNC_CTL_BPC_12BITS;
when others => Result := PIPE_DDI_FUNC_CTL_BPC_8BITS;
end case;
return Result;
end PIPE_DDI_FUNC_CTL_BPC;
function PIPE_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
begin
return Shift_Left (Word32 (Transfer_Unit - 1), 25);
end PIPE_DATA_M_TU;
PIPE_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0;
PIPE_MSA_MISC_BPC_6BITS : constant := 0 * 2 ** 5;
PIPE_MSA_MISC_BPC_8BITS : constant := 1 * 2 ** 5;
PIPE_MSA_MISC_BPC_10BITS : constant := 2 * 2 ** 5;
PIPE_MSA_MISC_BPC_12BITS : constant := 3 * 2 ** 5;
PIPE_MSA_MISC_BPC_16BITS : constant := 4 * 2 ** 5;
function PIPE_MSA_MISC_BPC (BPC : HW.GFX.BPC_Type) return Word32 is
Result : Word32;
begin
case BPC is
when 6 => Result := PIPE_MSA_MISC_BPC_6BITS;
when 8 => Result := PIPE_MSA_MISC_BPC_8BITS;
when 10 => Result := PIPE_MSA_MISC_BPC_10BITS;
when 12 => Result := PIPE_MSA_MISC_BPC_12BITS;
--when 16 => Result := PIPE_MSA_MISC_BPC_16BITS;
when others => Result := PIPE_MSA_MISC_BPC_8BITS;
end case;
return Result;
end PIPE_MSA_MISC_BPC;
---------------------------------------------------------------------------
function PIPECONF_BPC_MAP (Bits_Per_Color : HW.GFX.BPC_Type) return Word32
is
Result : Word32;
begin
if Bits_Per_Color = 6 then
Result := 2 * 2 ** 5;
elsif Bits_Per_Color = 10 then
Result := 1 * 2 ** 5;
elsif Bits_Per_Color = 12 then
Result := 3 * 2 ** 5;
else
Result := 0;
end if;
return Result;
end PIPECONF_BPC_MAP;
---------------------------------------------------------------------------
function PLANE_WM_LINES (Lines : Natural) return Word32 is
begin
return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
and PLANE_WM_LINES_MASK;
end PLANE_WM_LINES;
function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
begin
return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
end PLANE_WM_BLOCKS;
---------------------------------------------------------------------------
function Encode (LSW, MSW : Pos16) return Word32 is
begin
return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1);
end Encode;
----------------------------------------------------------------------------
procedure Setup_Link
(Head : Head_Type;
Link : DP_Link;
Mode : Mode_Type)
with
Global => (In_Out => Registers.Register_State),
Depends => (Registers.Register_State =>+ (Head, Link, Mode))
is
Data_M, Link_M : DP_Info.M_Type;
Data_N, Link_N : DP_Info.N_Type;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
DP_Info.Calculate_M_N
(Link => Link,
Mode => Mode,
Data_M => Data_M,
Data_N => Data_N,
Link_M => Link_M,
Link_N => Link_N);
Registers.Write
(Register => Head.PIPE_DATA_M1,
Value => PIPE_DATA_M_TU (64) or
Word32 (Data_M));
Registers.Write
(Register => Head.PIPE_DATA_N1,
Value => Word32 (Data_N));
Registers.Write
(Register => Head.PIPE_LINK_M1,
Value => Word32 (Link_M));
Registers.Write
(Register => Head.PIPE_LINK_N1,
Value => Word32 (Link_N));
if Config.Has_Pipe_MSA_Misc then
Registers.Write
(Register => Head.PIPE_MSA_MISC,
Value => PIPE_MSA_MISC_SYNC_CLK or
PIPE_MSA_MISC_BPC (Mode.BPC));
end if;
end Setup_Link;
----------------------------------------------------------------------------
procedure Clear_Watermarks (Controller : Controller_Type) is
begin
Registers.Write
(Register => Controller.PLANE_BUF_CFG,
Value => 16#0000_0000#);
for Level in WM_Levels range 0 .. WM_Levels'Last loop
Registers.Write
(Register => Controller.PLANE_WM (Level),
Value => 16#0000_0000#);
end loop;
Registers.Write
(Register => Controller.WM_LINETIME,
Value => 16#0000_0000#);
end Clear_Watermarks;
procedure Setup_Watermarks (Controller : Controller_Type)
is
type Per_Plane_Buffer_Range is array (Controller_Kind) of Word32;
Buffer_Range : constant Per_Plane_Buffer_Range := Per_Plane_Buffer_Range'
(A => Shift_Left (159, 16) or 0,
B => Shift_Left (319, 16) or 160,
C => Shift_Left (479, 16) or 320);
begin
Registers.Write
(Register => Controller.PLANE_BUF_CFG,
Value => Buffer_Range (Controller.Kind));
Registers.Write
(Register => Controller.PLANE_WM (0),
Value => PLANE_WM_ENABLE or
PLANE_WM_LINES (2) or
PLANE_WM_BLOCKS (160));
end Setup_Watermarks;
----------------------------------------------------------------------------
procedure Setup_Display
(Controller : in Controller_Type;
Head : in Head_Type;
Mode : in HW.GFX.Mode_Type;
Framebuffer : in HW.GFX.Framebuffer_Type)
with
Global => (In_Out => Registers.Register_State),
Depends =>
(Registers.Register_State
=>+
(Registers.Register_State,
Controller,
Head,
Mode,
Framebuffer))
is
-- FIXME: setup correct format, based on framebuffer RGB format
Format : constant Word32 := 6 * 2 ** 26;
PRI : Word32 := DSPCNTR_ENABLE or Format;
function To_Bytes (Pixels : Width_Type) return Word32
with
Pre => (Word32 (Pixels) <= Word32'Last / 4 / Word32 (BPC_Type'Last) * 8)
is
begin
return Word32 (Pos64 (Pixels) * 4 * Framebuffer.BPC / 8);
end To_Bytes;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Write (Controller.PIPESRC, Encode (Mode.V_Visible, Mode.H_Visible));
if Config.Has_Plane_Control then
Setup_Watermarks (Controller);
Registers.Write
(Register => Controller.PLANE_CTL,
Value => PLANE_CTL_PLANE_ENABLE or
PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
PLANE_CTL_PLANE_GAMMA_DISABLE);
Registers.Write (Controller.PLANE_OFFSET, 16#0000_0000#);
Registers.Write (Controller.PLANE_SIZE, Encode (Mode.H_Visible, Mode.V_Visible));
Registers.Write (Controller.PLANE_STRIDE, To_Bytes (Framebuffer.Stride) / 64);
Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
Registers.Write (Controller.PLANE_SURF, Framebuffer.Offset and 16#ffff_f000#);
else
if Config.Disable_Trickle_Feed then
PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
end if;
-- for now, just disable gamma LUT (can't do anything
-- useful without colorimetry information from display)
Registers.Unset_And_Set_Mask
(Register => Controller.DSPCNTR,
Mask_Unset => DSPCNTR_MASK,
Mask_Set => PRI);
Registers.Write (Controller.DSPSTRIDE, To_Bytes (Framebuffer.Stride));
Registers.Write (Controller.DSPSURF, Framebuffer.Offset and 16#ffff_f000#);
if Config.Has_DSP_Linoff then
Registers.Write (Controller.DSPLINOFF, 0);
end if;
Registers.Write (Controller.DSPTILEOFF, 0);
end if;
Registers.Write (Head.HTOTAL, Encode (Mode.H_Visible, Mode.H_Total));
Registers.Write (Head.HBLANK, Encode (Mode.H_Visible, Mode.H_Total));
Registers.Write (Head.HSYNC, Encode (Mode.H_Sync_Begin, Mode.H_Sync_End));
Registers.Write (Head.VTOTAL, Encode (Mode.V_Visible, Mode.V_Total));
Registers.Write (Head.VBLANK, Encode (Mode.V_Visible, Mode.V_Total));
Registers.Write (Head.VSYNC, Encode (Mode.V_Sync_Begin, Mode.V_Sync_End));
end Setup_Display;
----------------------------------------------------------------------------
procedure Setup_Head
(Controller : Controller_Type;
Head : Head_Type;
Port_Cfg : Port_Config;
Framebuffer : Framebuffer_Type)
is
PIPECONF_Options : Word32 := 0;
begin
if Config.Has_Pipe_DDI_Func then
Registers.Write
(Register => Head.PIPE_DDI_FUNC_CTL,
Value => PIPE_DDI_FUNC_CTL_ENABLE or
PIPE_DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port) or
PIPE_DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or
PIPE_DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or
PIPE_DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or
PIPE_DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or
PIPE_DDI_FUNC_CTL_EDP_SELECT (Controller.Kind) or
PIPE_DDI_FUNC_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count));
end if;
if Config.Has_Pipeconf_BPC then
PIPECONF_Options := PIPECONF_BPC_MAP (Port_Cfg.Mode.BPC);
end if;
-- Enable dithering if framebuffer BPC differs from connector BPC,
-- as smooth gradients look really bad without
if Framebuffer.BPC /= Port_Cfg.Mode.BPC then
PIPECONF_Options := PIPECONF_Options or PIPECONF_ENABLE_DITHER;
end if;
if not Config.Has_Pipeconf_Misc then
Registers.Write
(Register => Head.PIPECONF,
Value => PIPECONF_ENABLE or PIPECONF_Options);
else
Registers.Write
(Register => Controller.PIPEMISC,
Value => PIPECONF_Options);
Registers.Write
(Register => Head.PIPECONF,
Value => PIPECONF_ENABLE);
end if;
Registers.Posting_Read (Head.PIPECONF);
end Setup_Head;
----------------------------------------------------------------------------
procedure On
(Controller : Controller_Type;
Head : Head_Type;
Port_Cfg : Port_Config;
Framebuffer : Framebuffer_Type)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.Has_Trans_Clk_Sel then
Registers.Write
(Register => Controller.TRANS_CLK_SEL,
Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
end if;
if Port_Cfg.Is_FDI then
Setup_Link (Head, Port_Cfg.FDI, Port_Cfg.Mode);
elsif Port_Cfg.Display = DP then
Setup_Link (Head, Port_Cfg.DP, Port_Cfg.Mode);
end if;
Setup_Display (Controller, Head, Port_Cfg.Mode, Framebuffer);
Setup_Head (Controller, Head, Port_Cfg, Framebuffer);
end On;
----------------------------------------------------------------------------
procedure Planes_Off (Controller : Controller_Type) is
begin
Registers.Unset_Mask (Controller.SPCNTR, SPCNTR_ENABLE);
if Config.Has_Plane_Control then
Clear_Watermarks (Controller);
Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
else
Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
end if;
end Planes_Off;
procedure Head_Off (Head : Head_Type)
is
Enabled : Boolean;
begin
Registers.Is_Set_Mask (Head.PIPECONF, PIPECONF_ENABLE, Enabled);
if Enabled then
Registers.Unset_Mask (Head.PIPECONF, PIPECONF_ENABLE);
end if;
-- Workaround for Broadwell:
-- Status may be wrong if pipe hasn't been enabled since reset.
if not Config.Pipe_Enabled_Workaround or else Enabled then
-- synchronously wait until pipe is truly off
Registers.Wait_Unset_Mask
(Register => Head.PIPECONF,
Mask => PIPECONF_ENABLED_STATUS,
TOut_MS => 40);
end if;
if Config.Has_Pipe_DDI_Func then
Registers.Write (Head.PIPE_DDI_FUNC_CTL, 0);
end if;
end Head_Off;
procedure Panel_Fitter_Off (Controller : Controller_Type) is
begin
-- Writes to WIN_SZ arm the PS/PF registers.
if Config.Has_Plane_Control then
Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
then
Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
end if;
else
Registers.Unset_Mask (Controller.PF_CTL_1, PF_CTL_1_ENABLE);
Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
end if;
end Panel_Fitter_Off;
procedure Trans_Clk_Off (Controller : Controller_Type) is
begin
if Config.Has_Trans_Clk_Sel then
Registers.Write (Controller.TRANS_CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
end if;
end Trans_Clk_Off;
procedure Off (Controller : Controller_Type; Head : Head_Type) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Planes_Off (Controller);
Head_Off (Head);
Panel_Fitter_Off (Controller);
Trans_Clk_Off (Controller);
end Off;
procedure All_Off
is
EDP_Enabled, EDP_Piped : Boolean;
procedure EDP_Piped_To (Kind : Controller_Kind; Piped_To : out Boolean)
is
Pipe_DDI_Func_Ctl : Word32;
begin
Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, Pipe_DDI_Func_Ctl);
Pipe_DDI_Func_Ctl :=
Pipe_DDI_Func_Ctl and PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK;
Piped_To := (Kind = A and Pipe_DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
Pipe_DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF (Kind);
end EDP_Piped_To;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.Has_EDP_Pipe then
Registers.Is_Set_Mask
(Registers.PIPE_EDP_CONF, PIPECONF_ENABLE, EDP_Enabled);
else
EDP_Enabled := False;
end if;
for Kind in Controller_Kind loop
Planes_Off (Controllers (Kind));
if EDP_Enabled then
EDP_Piped_To (Kind, EDP_Piped);
if EDP_Piped then
Head_Off (Heads (Head_EDP));
EDP_Enabled := False;
end if;
end if;
Head_Off (Default_Pipe_Head (Kind));
Panel_Fitter_Off (Controllers (Kind));
Trans_Clk_Off (Controllers (Kind));
end loop;
if EDP_Enabled then
Head_Off (Heads (Head_EDP));
end if;
end All_Off;
----------------------------------------------------------------------------
procedure Update_Offset
(Controller : Controller_Type;
Framebuffer : HW.GFX.Framebuffer_Type) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Write (Controller.DSPSURF, Framebuffer.Offset and 16#ffff_f000#);
end Update_Offset;
----------------------------------------------------------------------------
function Get_Pipe_Hint (Head : Head_Type) return Word32
is
type Pipe_Hint_Array is array (Pipe_Head) of Word32;
Pipe_Hint : constant Pipe_Hint_Array := Pipe_Hint_Array'
(Head_EDP => 0, Head_A => 0, Head_B => 1, Head_C => 2);
begin
return Pipe_Hint (Head.Head);
end Get_Pipe_Hint;
----------------------------------------------------------------------------
function Default_Pipe_Head (Kind : Controller_Kind) return Head_Type
is
type Default_Head_Array is array (Controller_Kind) of Head_Type;
Default_Head : constant Default_Head_Array := Default_Head_Array'
(A => Heads (Head_A), B => Heads (Head_B), C => Heads (Head_C));
begin
return Default_Head (Kind);
end Default_Pipe_Head;
end HW.GFX.GMA.Pipe_Setup;

View File

@ -0,0 +1,274 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Registers;
private package HW.GFX.GMA.Pipe_Setup
is
type Controller_Kind is (A, B, C);
type Controller_Type is private;
type Controller_Array is array (Controller_Kind) of Controller_Type;
type Pipe_Head is (Head_EDP, Head_A, Head_B, Head_C);
type Head_Type is private;
type Head_Array is array (Pipe_Head) of Head_Type;
procedure On
(Controller : Controller_Type;
Head : Head_Type;
Port_Cfg : Port_Config;
Framebuffer : Framebuffer_Type);
procedure Off
(Controller : Controller_Type;
Head : Head_Type);
procedure All_Off;
function Get_Pipe_Hint (Head : Head_Type) return Word32;
procedure Update_Offset
(Controller : Controller_Type;
Framebuffer : HW.GFX.Framebuffer_Type);
Controllers : constant Controller_Array;
Heads : constant Head_Array;
function Default_Pipe_Head (Kind : Controller_Kind) return Head_Type;
private
subtype WM_Levels is Natural range 0 .. 7;
type PLANE_WM_Type is array (WM_Levels) of Registers.Registers_Index;
type Controller_Type is
record
Kind : Controller_Kind;
PIPESRC : Registers.Registers_Index;
PIPEMISC : Registers.Registers_Index;
PF_CTL_1 : Registers.Registers_Index;
PF_WIN_POS : Registers.Registers_Index;
PF_WIN_SZ : Registers.Registers_Index;
DSPCNTR : Registers.Registers_Index;
DSPLINOFF : Registers.Registers_Index;
DSPSTRIDE : Registers.Registers_Index;
DSPSURF : Registers.Registers_Index;
DSPTILEOFF : Registers.Registers_Index;
SPCNTR : Registers.Registers_Index;
TRANS_CLK_SEL : Registers.Registers_Index;
-- Skylake registers (partially aliased)
PLANE_CTL : Registers.Registers_Index;
PLANE_OFFSET : Registers.Registers_Index;
PLANE_POS : Registers.Registers_Index;
PLANE_SIZE : Registers.Registers_Index;
PLANE_STRIDE : Registers.Registers_Index;
PLANE_SURF : Registers.Registers_Index;
PS_CTRL_1 : Registers.Registers_Index;
PS_CTRL_2 : Registers.Registers_Invalid_Index;
PS_WIN_SZ_1 : Registers.Registers_Index;
PS_WIN_SZ_2 : Registers.Registers_Invalid_Index;
WM_LINETIME : Registers.Registers_Index;
PLANE_BUF_CFG : Registers.Registers_Index;
PLANE_WM : PLANE_WM_Type;
end record;
type Head_Type is
record
Head : Pipe_Head;
HTOTAL : Registers.Registers_Index;
HBLANK : Registers.Registers_Index;
HSYNC : Registers.Registers_Index;
VTOTAL : Registers.Registers_Index;
VBLANK : Registers.Registers_Index;
VSYNC : Registers.Registers_Index;
PIPECONF : Registers.Registers_Index;
PIPE_DATA_M1 : Registers.Registers_Index;
PIPE_DATA_N1 : Registers.Registers_Index;
PIPE_LINK_M1 : Registers.Registers_Index;
PIPE_LINK_N1 : Registers.Registers_Index;
PIPE_DDI_FUNC_CTL : Registers.Registers_Index;
PIPE_MSA_MISC : Registers.Registers_Index;
end record;
Controllers : constant Controller_Array := Controller_Array'
(A => Controller_Type'
(Kind => A,
PIPESRC => Registers.PIPEASRC,
PIPEMISC => Registers.PIPEAMISC,
PF_CTL_1 => Registers.PFA_CTL_1,
PF_WIN_POS => Registers.PFA_WIN_POS,
PF_WIN_SZ => Registers.PFA_WIN_SZ,
DSPCNTR => Registers.DSPACNTR,
DSPLINOFF => Registers.DSPALINOFF,
DSPSTRIDE => Registers.DSPASTRIDE,
DSPSURF => Registers.DSPASURF,
DSPTILEOFF => Registers.DSPATILEOFF,
SPCNTR => Registers.SPACNTR,
TRANS_CLK_SEL => Registers.TRANSA_CLK_SEL,
PLANE_CTL => Registers.DSPACNTR,
PLANE_OFFSET => Registers.DSPATILEOFF,
PLANE_POS => Registers.PLANE_POS_1_A,
PLANE_SIZE => Registers.PLANE_SIZE_1_A,
PLANE_STRIDE => Registers.DSPASTRIDE,
PLANE_SURF => Registers.DSPASURF,
PS_CTRL_1 => Registers.PS_CTRL_1_A,
PS_CTRL_2 => Registers.PS_CTRL_2_A,
PS_WIN_SZ_1 => Registers.PS_WIN_SZ_1_A,
PS_WIN_SZ_2 => Registers.PS_WIN_SZ_2_A,
WM_LINETIME => Registers.WM_LINETIME_A,
PLANE_BUF_CFG => Registers.PLANE_BUF_CFG_1_A,
PLANE_WM => PLANE_WM_Type'(
Registers.PLANE_WM_1_A_0,
Registers.PLANE_WM_1_A_1,
Registers.PLANE_WM_1_A_2,
Registers.PLANE_WM_1_A_3,
Registers.PLANE_WM_1_A_4,
Registers.PLANE_WM_1_A_5,
Registers.PLANE_WM_1_A_6,
Registers.PLANE_WM_1_A_7)),
B => Controller_Type'
(Kind => B,
PIPESRC => Registers.PIPEBSRC,
PIPEMISC => Registers.PIPEBMISC,
PF_CTL_1 => Registers.PFB_CTL_1,
PF_WIN_POS => Registers.PFB_WIN_POS,
PF_WIN_SZ => Registers.PFB_WIN_SZ,
DSPCNTR => Registers.DSPBCNTR,
DSPLINOFF => Registers.DSPBLINOFF,
DSPSTRIDE => Registers.DSPBSTRIDE,
DSPSURF => Registers.DSPBSURF,
DSPTILEOFF => Registers.DSPBTILEOFF,
SPCNTR => Registers.SPBCNTR,
TRANS_CLK_SEL => Registers.TRANSB_CLK_SEL,
PLANE_CTL => Registers.DSPBCNTR,
PLANE_OFFSET => Registers.DSPBTILEOFF,
PLANE_POS => Registers.PLANE_POS_1_B,
PLANE_SIZE => Registers.PLANE_SIZE_1_B,
PLANE_STRIDE => Registers.DSPBSTRIDE,
PLANE_SURF => Registers.DSPBSURF,
PS_CTRL_1 => Registers.PS_CTRL_1_B,
PS_CTRL_2 => Registers.PS_CTRL_2_B,
PS_WIN_SZ_1 => Registers.PS_WIN_SZ_1_B,
PS_WIN_SZ_2 => Registers.PS_WIN_SZ_2_B,
WM_LINETIME => Registers.WM_LINETIME_B,
PLANE_BUF_CFG => Registers.PLANE_BUF_CFG_1_B,
PLANE_WM => PLANE_WM_Type'(
Registers.PLANE_WM_1_B_0,
Registers.PLANE_WM_1_B_1,
Registers.PLANE_WM_1_B_2,
Registers.PLANE_WM_1_B_3,
Registers.PLANE_WM_1_B_4,
Registers.PLANE_WM_1_B_5,
Registers.PLANE_WM_1_B_6,
Registers.PLANE_WM_1_B_7)),
C => Controller_Type'
(Kind => C,
PIPESRC => Registers.PIPECSRC,
PIPEMISC => Registers.PIPECMISC,
PF_CTL_1 => Registers.PFC_CTL_1,
PF_WIN_POS => Registers.PFC_WIN_POS,
PF_WIN_SZ => Registers.PFC_WIN_SZ,
DSPCNTR => Registers.DSPCCNTR,
DSPLINOFF => Registers.DSPCLINOFF,
DSPSTRIDE => Registers.DSPCSTRIDE,
DSPSURF => Registers.DSPCSURF,
DSPTILEOFF => Registers.DSPCTILEOFF,
SPCNTR => Registers.SPCCNTR,
TRANS_CLK_SEL => Registers.TRANSC_CLK_SEL,
PLANE_CTL => Registers.DSPCCNTR,
PLANE_OFFSET => Registers.DSPCTILEOFF,
PLANE_POS => Registers.PLANE_POS_1_C,
PLANE_SIZE => Registers.PLANE_SIZE_1_C,
PLANE_STRIDE => Registers.DSPCSTRIDE,
PLANE_SURF => Registers.DSPCSURF,
PS_CTRL_1 => Registers.PS_CTRL_1_C,
PS_CTRL_2 => Registers.Invalid_Register,
PS_WIN_SZ_1 => Registers.PS_WIN_SZ_1_C,
PS_WIN_SZ_2 => Registers.Invalid_Register,
WM_LINETIME => Registers.WM_LINETIME_C,
PLANE_BUF_CFG => Registers.PLANE_BUF_CFG_1_C,
PLANE_WM => PLANE_WM_Type'(
Registers.PLANE_WM_1_C_0,
Registers.PLANE_WM_1_C_1,
Registers.PLANE_WM_1_C_2,
Registers.PLANE_WM_1_C_3,
Registers.PLANE_WM_1_C_4,
Registers.PLANE_WM_1_C_5,
Registers.PLANE_WM_1_C_6,
Registers.PLANE_WM_1_C_7)));
Heads : constant Head_Array := Head_Array'
(Head_EDP => Head_Type'
(Head => Head_EDP,
HTOTAL => Registers.HTOTAL_EDP,
HBLANK => Registers.HBLANK_EDP,
HSYNC => Registers.HSYNC_EDP,
VTOTAL => Registers.VTOTAL_EDP,
VBLANK => Registers.VBLANK_EDP,
VSYNC => Registers.VSYNC_EDP,
PIPECONF => Registers.PIPE_EDP_CONF,
PIPE_DATA_M1 => Registers.PIPE_EDP_DATA_M1,
PIPE_DATA_N1 => Registers.PIPE_EDP_DATA_N1,
PIPE_LINK_M1 => Registers.PIPE_EDP_LINK_M1,
PIPE_LINK_N1 => Registers.PIPE_EDP_LINK_N1,
PIPE_DDI_FUNC_CTL => Registers.PIPE_EDP_DDI_FUNC_CTL,
PIPE_MSA_MISC => Registers.PIPE_EDP_MSA_MISC),
Head_A => Head_Type'
(Head => Head_A,
HTOTAL => Registers.HTOTAL_A,
HBLANK => Registers.HBLANK_A,
HSYNC => Registers.HSYNC_A,
VTOTAL => Registers.VTOTAL_A,
VBLANK => Registers.VBLANK_A,
VSYNC => Registers.VSYNC_A,
PIPECONF => Registers.PIPEACONF,
PIPE_DATA_M1 => Registers.PIPEA_DATA_M1,
PIPE_DATA_N1 => Registers.PIPEA_DATA_N1,
PIPE_LINK_M1 => Registers.PIPEA_LINK_M1,
PIPE_LINK_N1 => Registers.PIPEA_LINK_N1,
PIPE_DDI_FUNC_CTL => Registers.PIPEA_DDI_FUNC_CTL,
PIPE_MSA_MISC => Registers.PIPEA_MSA_MISC),
Head_B => Head_Type'
(Head => Head_B,
HTOTAL => Registers.HTOTAL_B,
HBLANK => Registers.HBLANK_B,
HSYNC => Registers.HSYNC_B,
VTOTAL => Registers.VTOTAL_B,
VBLANK => Registers.VBLANK_B,
VSYNC => Registers.VSYNC_B,
PIPECONF => Registers.PIPEBCONF,
PIPE_DATA_M1 => Registers.PIPEB_DATA_M1,
PIPE_DATA_N1 => Registers.PIPEB_DATA_N1,
PIPE_LINK_M1 => Registers.PIPEB_LINK_M1,
PIPE_LINK_N1 => Registers.PIPEB_LINK_N1,
PIPE_DDI_FUNC_CTL => Registers.PIPEB_DDI_FUNC_CTL,
PIPE_MSA_MISC => Registers.PIPEB_MSA_MISC),
Head_C => Head_Type'
(Head => Head_C,
HTOTAL => Registers.HTOTAL_C,
HBLANK => Registers.HBLANK_C,
HSYNC => Registers.HSYNC_C,
VTOTAL => Registers.VTOTAL_C,
VBLANK => Registers.VBLANK_C,
VSYNC => Registers.VSYNC_C,
PIPECONF => Registers.PIPECCONF,
PIPE_DATA_M1 => Registers.PIPEC_DATA_M1,
PIPE_DATA_N1 => Registers.PIPEC_DATA_N1,
PIPE_LINK_M1 => Registers.PIPEC_LINK_M1,
PIPE_LINK_N1 => Registers.PIPEC_LINK_N1,
PIPE_DDI_FUNC_CTL => Registers.PIPEC_DDI_FUNC_CTL,
PIPE_MSA_MISC => Registers.PIPEC_MSA_MISC));
end HW.GFX.GMA.Pipe_Setup;

View File

@ -0,0 +1,20 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.Port_Detect is
procedure Initialize;
procedure Hotplug_Detect (Port_Cfg : in Port_Config; Detected : out Boolean);
end HW.GFX.GMA.Port_Detect;

View File

@ -0,0 +1,312 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with System.Storage_Elements;
with HW.Time;
with HW.MMIO_Range;
pragma Elaborate_All (HW.MMIO_Range);
with HW.Debug;
with GNAT.Source_Info;
use type System.Address;
use type HW.Word64;
package body HW.GFX.GMA.Registers
with
Refined_State =>
(Address_State => (Regs.Base_Address, GTT.Base_Address),
Register_State => Regs.State,
GTT_State => GTT.State)
is
pragma Disable_Atomic_Synchronization;
type Registers_Range is
new Natural range 0 .. 16#0020_0000# / Register_Width - 1;
type Registers_Type is array (Registers_Range) of Word32
with
Atomic_Components,
Size => 16#20_0000# * 8;
package Regs is new MMIO_Range
(Base_Addr => Config.Default_MMIO_Base,
Element_T => Word32,
Index_T => Registers_Range,
Array_T => Registers_Type);
----------------------------------------------------------------------------
GTT_Offset : constant := (case Config.CPU is
when Ironlake .. Haswell => 16#0020_0000#,
when Broadwell .. Skylake => 16#0080_0000#);
GTT_Size : constant := (case Config.CPU is
when Ironlake .. Haswell => 16#0020_0000#,
-- Limit Broadwell to 4MiB to have a stable
-- interface (i.e. same number of entries):
when Broadwell .. Skylake => 16#0040_0000#);
GTT_PTE_Size : constant := (case Config.CPU is
when Ironlake .. Haswell => 4,
when Broadwell .. Skylake => 8);
type GTT_PTE_Type is mod 2 ** (GTT_PTE_Size * 8);
type GTT_Registers_Type is array (GTT_Range) of GTT_PTE_Type
with
Volatile_Components,
Size => GTT_Size * 8;
package GTT is new MMIO_Range
(Base_Addr => Config.Default_MMIO_Base + GTT_Offset,
Element_T => GTT_PTE_Type,
Index_T => GTT_Range,
Array_T => GTT_Registers_Type);
GTT_PTE_Valid : constant Word32 := 1;
----------------------------------------------------------------------------
procedure Write_GTT
(GTT_Page : GTT_Range;
Device_Address : GTT_Address_Type;
Valid : Boolean)
is
begin
if Config.Fold_39Bit_GTT_PTE then
GTT.Write
(Index => GTT_Page,
Value => GTT_PTE_Type (Device_Address and 16#ffff_f000#) or
GTT_PTE_Type (Shift_Right (Word64 (Device_Address), 32 - 4)
and 16#0000_07f0#) or
Boolean'Pos (Valid));
else
GTT.Write
(Index => GTT_Page,
Value => GTT_PTE_Type (Device_Address and 16#7f_ffff_f000#) or
Boolean'Pos (Valid));
end if;
end Write_GTT;
----------------------------------------------------------------------------
package Rep is
function Index (Reg : Registers_Index) return Registers_Range;
end Rep;
package body Rep is
function Index (Reg : Registers_Index) return Registers_Range
with
SPARK_Mode => Off
is
begin
return Reg'Enum_Rep;
end Index;
end Rep;
-- Read a specific register
procedure Read
(Register : in Registers_Index;
Value : out Word32;
Verbose : in Boolean := True)
is
begin
Regs.Read (Value, Rep.Index (Register));
pragma Debug (Verbose, Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
pragma Debug (Verbose, Debug.Put_Word32 (Value));
pragma Debug (Verbose, Debug.Put (" <- "));
pragma Debug (Verbose, Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
pragma Debug (Verbose, Debug.Put (":"));
pragma Debug (Verbose, Debug.Put_Line (Registers_Index'Image (Register)));
end Read;
----------------------------------------------------------------------------
-- Read a specific register to post a previous write
procedure Posting_Read (Register : Registers_Index)
is
Discard_Value : Word32;
begin
pragma Warnings
(Off, "unused assignment to ""Discard_Value""",
Reason => "Intentional dummy read to affect hardware.");
Read (Register, Discard_Value);
pragma Warnings
(On, "unused assignment to ""Discard_Value""");
end Posting_Read;
----------------------------------------------------------------------------
-- Write a specific register
procedure Write (Register : Registers_Index; Value : Word32)
is
begin
pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
pragma Debug (Debug.Put_Word32 (Value));
pragma Debug (Debug.Put (" -> "));
pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
pragma Debug (Debug.Put (":"));
pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
Regs.Write (Rep.Index (Register), Value);
pragma Debug (Debug.Register_Write_Wait);
end Write;
----------------------------------------------------------------------------
-- Check whether all bits in @Register@ indicated by @Mask@ are set
procedure Is_Set_Mask
(Register : in Registers_Index;
Mask : in Word32;
Result : out Boolean)
is
Value : Word32;
begin
pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
Read (Register, Value);
Result := (Value and Mask) = Mask;
end Is_Set_Mask;
----------------------------------------------------------------------------
-- TODO: Should have Success parameter
-- Wait for all bits in @Register@ indicated by @Mask@ to be set
procedure Wait_Set_Mask
(Register : in Registers_Index;
Mask : in Word32;
TOut_MS : in Natural := Default_Timeout_MS;
Verbose : in Boolean := False)
is
Value : Word32;
Timeout : Time.T;
Timed_Out : Boolean;
begin
pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
Timeout := Time.MS_From_Now (TOut_MS);
loop
Timed_Out := Time.Timed_Out (Timeout);
Read (Register, Value, Verbose);
if (Value and Mask) = Mask then
exit;
end if;
pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
exit when Timed_Out;
end loop;
end Wait_Set_Mask;
----------------------------------------------------------------------------
-- TODO: Should have Success parameter
-- Wait for bits in @Register@ indicated by @Mask@ to be clear
procedure Wait_Unset_Mask
(Register : Registers_Index;
Mask : Word32;
TOut_MS : in Natural := Default_Timeout_MS;
Verbose : in Boolean := False)
is
Value : Word32;
Timeout : Time.T;
Timed_Out : Boolean;
begin
pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
Timeout := Time.MS_From_Now (TOut_MS);
loop
Timed_Out := Time.Timed_Out (Timeout);
Read (Register, Value, Verbose);
if (Value and Mask) = 0 then
exit;
end if;
pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
exit when Timed_Out;
end loop;
end Wait_Unset_Mask;
----------------------------------------------------------------------------
-- Set bits from @Mask@ in @Register@
procedure Set_Mask
(Register : Registers_Index;
Mask : Word32)
is
Value : Word32;
begin
pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
pragma Debug (Debug.Put_Word32 (Mask));
pragma Debug (Debug.Put (" .S "));
pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
Read (Register, Value);
Value := Value or Mask;
Write (Register, Value);
end Set_Mask;
----------------------------------------------------------------------------
-- Mask out @Mask@ in @Register@
procedure Unset_Mask
(Register : Registers_Index;
Mask : Word32)
is
Value : Word32;
begin
pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
pragma Debug (Debug.Put_Word32 (Mask));
pragma Debug (Debug.Put (" !S "));
pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
Read (Register, Value);
Value := Value and not Mask;
Write (Register, Value);
end Unset_Mask;
----------------------------------------------------------------------------
-- Mask out @Unset_Mask@ and set @Set_Mask@ in @Register@
procedure Unset_And_Set_Mask
(Register : Registers_Index;
Mask_Unset : Word32;
Mask_Set : Word32)
is
Value : Word32;
begin
pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
Read (Register, Value);
Value := (Value and not Mask_Unset) or Mask_Set;
Write (Register, Value);
end Unset_And_Set_Mask;
----------------------------------------------------------------------------
procedure Set_Register_Base (Base : Word64)
is
begin
Regs.Set_Base_Address (Base);
GTT.Set_Base_Address (Base + GTT_Offset);
end Set_Register_Base;
end HW.GFX.GMA.Registers;

File diff suppressed because it is too large Load Diff

836
common/hw-gfx-gma.adb Normal file
View File

@ -0,0 +1,836 @@
--
-- Copyright (C) 2014-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.EDID;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.DP_Info;
with HW.GFX.GMA.Registers;
with HW.GFX.GMA.Power_And_Clocks;
with HW.GFX.GMA.Panel;
with HW.GFX.GMA.PLLs;
with HW.GFX.GMA.Port_Detect;
with HW.GFX.GMA.Connectors;
with HW.GFX.GMA.Connector_Info;
with HW.GFX.GMA.Pipe_Setup;
with System;
with HW.Debug;
with GNAT.Source_Info;
use type HW.Word8;
use type HW.Int32;
package body HW.GFX.GMA
with Refined_State =>
(State =>
(Registers.Address_State,
PLLs.State, Panel.Panel_State,
Cur_Configs, Allocated_PLLs, DP_Links,
HPD_Delay, Wait_For_HPD),
Init_State => Initialized,
Config_State => Config.Valid_Port_GPU,
Device_State =>
(Registers.Register_State, Registers.GTT_State))
is
subtype Port_Name is String (1 .. 8);
type Port_Name_Array is array (Port_Type) of Port_Name;
Port_Names : constant Port_Name_Array :=
(Disabled => "Disabled",
Internal => "Internal",
DP1 => "DP1 ",
DP2 => "DP2 ",
DP3 => "DP3 ",
Digital1 => "Digital1",
Digital2 => "Digital2",
Digital3 => "Digital3",
Analog => "Analog ");
package Display_Controller renames Pipe_Setup;
type PLLs_Type is array (Config_Index) of PLLs.T;
type Links_Type is array (Config_Index) of DP_Link;
type HPD_Type is array (Port_Type) of Boolean;
type HPD_Delay_Type is array (Port_Type) of Time.T;
Cur_Configs : Configs_Type;
Allocated_PLLs : PLLs_Type;
DP_Links : Links_Type;
HPD_Delay : HPD_Delay_Type;
Wait_For_HPD : HPD_Type;
Initialized : Boolean := False;
subtype Active_Port_Type is Port_Type range Port_Type'Succ (Disabled) .. Port_Type'Last;
----------------------------------------------------------------------------
function To_GPU_Port
(Configs : Configs_Type;
Idx : Config_Index)
return GPU_Port
is
begin
return
(case Config.CPU is
when Ironlake .. Ivybridge => -- everything but eDP through FDI/PCH
(if Config.Internal_Is_EDP and then Configs (Idx).Port = Internal
then
DIGI_A
else
(case Idx is
-- FDIs are fixed to the CPU pipe
when Primary => DIGI_B,
when Secondary => DIGI_C,
when Tertiary => DIGI_D)),
when Haswell .. Skylake => -- everything but VGA directly on CPU
(case Configs (Idx).Port is
when Disabled => GPU_Port'First,
when Internal => DIGI_A, -- LVDS not available
when Digital1 | DP1 => DIGI_B,
when Digital2 | DP2 => DIGI_C,
when Digital3 | DP3 => DIGI_D,
when Analog => DIGI_E));
end To_GPU_Port;
function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
is
begin
return
(case Port is
when Internal => PCH_LVDS, -- will be ignored if Internal is DP
when Analog => PCH_DAC,
when Digital1 => PCH_HDMI_B,
when Digital2 => PCH_HDMI_C,
when Digital3 => PCH_HDMI_D,
when DP1 => PCH_DP_B,
when DP2 => PCH_DP_C,
when DP3 => PCH_DP_D);
end To_PCH_Port;
function To_Display_Type (Port : Active_Port_Type) return Display_Type
with Pre => True
is
begin
return
(case Port is
when Internal => Config.Internal_Display,
when Analog => VGA,
when Digital1 |
Digital2 |
Digital3 => HDMI,
when DP1 |
DP2 |
DP3 => DP);
end To_Display_Type;
procedure Configure_FDI_Link
(Port_Cfg : in out Port_Config;
Success : out Boolean)
with Pre => True
is
procedure Limit_Lane_Count
is
FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
Enabled : Boolean;
begin
-- if DIGI_D enabled: (FDI names are off by one)
Registers.Is_Set_Mask
(Register => Registers.FDI_TX_CTL_C,
Mask => FDI_TX_CTL_FDI_TX_ENABLE,
Result => Enabled);
if Enabled then
Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
end if;
end Limit_Lane_Count;
begin
Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
Config.FDI_Lane_Count (Port_Cfg.Port);
Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
Limit_Lane_Count;
end if;
DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
end Configure_FDI_Link;
procedure Fill_Port_Config
(Port_Cfg : out Port_Config;
Configs : in Configs_Type;
Idx : in Config_Index;
Success : out Boolean)
with Pre => True
is
begin
Success :=
Config.Supported_Pipe (Idx) and then
Config.Valid_Port (Configs (Idx).Port) and then
Configs (Idx).Port /= Disabled;
if Success then
declare
Port : constant Port_Type := Configs (Idx).Port;
Mode : constant Mode_Type := Configs (Idx).Mode;
Link : constant DP_Link := DP_Links (Idx);
begin
Port_Cfg := Port_Config'
(Port => To_GPU_Port (Configs, Idx),
PCH_Port => To_PCH_Port (Port),
Display => To_Display_Type (Port),
Mode => Mode,
Is_FDI => Config.FDI_Port (To_GPU_Port (Configs, Idx)),
FDI => Default_DP,
DP => Link);
if Port_Cfg.Mode.BPC = Auto_BPC then
Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
end if;
end;
else
Port_Cfg := Port_Config'
(Port => GPU_Port'First,
PCH_Port => PCH_Port'First,
Display => Display_Type'First,
Mode => Invalid_Mode,
Is_FDI => False,
FDI => Default_DP,
DP => Default_DP);
end if;
end Fill_Port_Config;
----------------------------------------------------------------------------
function To_Controller
(Dsp_Config : Config_Index) return Display_Controller.Controller_Type
is
Result : Display_Controller.Controller_Type;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
case Dsp_Config is
when Primary =>
Result := Display_Controller.Controllers (Display_Controller.A);
when Secondary =>
Result := Display_Controller.Controllers (Display_Controller.B);
when Tertiary =>
Result := Display_Controller.Controllers (Display_Controller.C);
end case;
return Result;
end To_Controller;
----------------------------------------------------------------------------
function To_Head
(N_Config : Config_Index;
Port : Active_Port_Type)
return Display_Controller.Head_Type
is
Result : Display_Controller.Head_Type;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.Has_EDP_Pipe and then Port = Internal then
Result := Display_Controller.Heads (Display_Controller.Head_EDP);
else
case N_Config is
when Primary =>
Result := Display_Controller.Heads (Display_Controller.Head_A);
when Secondary =>
Result := Display_Controller.Heads (Display_Controller.Head_B);
when Tertiary =>
Result := Display_Controller.Heads (Display_Controller.Head_C);
end case;
end if;
return Result;
end To_Head;
----------------------------------------------------------------------------
procedure Legacy_VGA_Off
is
Reg8 : Word8;
begin
-- disable legacy VGA plane, taking over control now
Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
Port_IO.InB (Reg8, VGA_SR_DATA);
Port_IO.OutB (VGA_SR_DATA, Reg8 or 1 * 2 ** 5);
Time.U_Delay (100); -- PRM says 100us, Linux does 300
Registers.Set_Mask (Registers.VGACNTRL, 1 * 2 ** 31);
end Legacy_VGA_Off;
----------------------------------------------------------------------------
function Port_Configured
(Configs : Configs_Type;
Port : Port_Type)
return Boolean
with
Global => null
is
begin
return Configs (Primary).Port = Port or
Configs (Secondary).Port = Port or
Configs (Tertiary).Port = Port;
end Port_Configured;
procedure Scan_Ports
(Configs : out Configs_Type;
Ports : in Port_List)
is
Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
Port_Idx : Port_List_Range := Port_List_Range'First;
Port_Cfg : Port_Config;
Success : Boolean := False;
begin
Configs := (Config_Index =>
(Port => Disabled,
Mode => Invalid_Mode,
Framebuffer => Default_FB));
for Config_Idx in Config_Index loop
while Ports (Port_Idx) /= Disabled loop
if not Port_Configured (Configs, Ports (Port_Idx)) then
Configs (Config_Idx).Port := Ports (Port_Idx);
Fill_Port_Config (Port_Cfg, Configs, Config_Idx, Success);
if Success then
-- May need power to probe port
if Port_Cfg.Display = DP then
Power_And_Clocks.Power_Up (Cur_Configs, Configs);
end if;
if Ports (Port_Idx) = Internal then
Panel.On;
end if;
Connector_Info.Read_EDID (Raw_EDID, Port_Cfg, Success);
end if;
if Success and then EDID.Has_Preferred_Mode (Raw_EDID) then
Configs (Config_Idx).Mode := EDID.Preferred_Mode (Raw_EDID);
else
Configs (Config_Idx).Port := Disabled;
if Ports (Port_Idx) = Internal and
not Port_Configured (Cur_Configs, Internal)
then
Panel.Off;
end if;
end if;
end if;
exit when Port_Idx = Port_List_Range'Last;
Port_Idx := Port_List_Range'Succ (Port_Idx);
exit when Success;
end loop;
end loop;
Power_And_Clocks.Power_Set_To (Cur_Configs);
end Scan_Ports;
procedure Auto_Configure
(Configs : in out Configs_Type;
Keep_Power : in Boolean := False)
is
Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
Success : Boolean;
Config_Idx : Config_Index;
Port_Cfg : Port_Config;
function Free_Config return Boolean
with
Pre => True
is
begin
return Port_Configured (Configs, Disabled);
end Free_Config;
function First_Free_Config return Config_Index
with
Pre => Free_Config
is
begin
return (if Configs (Primary).Port = Disabled then Primary else
(if Configs (Secondary).Port = Disabled then Secondary
else Tertiary));
end First_Free_Config;
begin
-- TODO: Only check ports with hot-plug event?
if Config.Has_Internal_Display and then
not Keep_Power and then
not Port_Configured (Cur_Configs, Internal)
then
Panel.On (Wait => False);
end if;
-- Check if displays are still connected
for I in Config_Index loop
if Configs (I).Port /= Disabled then
Fill_Port_Config (Port_Cfg, Configs, I, Success);
if Success then
Connector_Info.Read_EDID
(Raw_EDID => Raw_EDID,
Port_Cfg => Port_Cfg,
Success => Success);
end if;
if not Success or else
not EDID.Has_Preferred_Mode (Raw_EDID) or else
Configs (I).Mode /= EDID.Preferred_Mode (Raw_EDID)
then
Configs (I).Port := Disabled;
end if;
end if;
end loop;
-- Add new displays as long as there is a free pipe config
for Port in Active_Port_Type loop
if Free_Config and then not Port_Configured (Configs, Port) then
Config_Idx := First_Free_Config;
Configs (Config_Idx).Port := Port;
Fill_Port_Config (Port_Cfg, Configs, Config_Idx, Success);
if Success then
-- Need power to probe port
if not Keep_Power and then To_Display_Type (Port) = DP then
Power_And_Clocks.Power_Up (Cur_Configs, Configs);
end if;
if not Keep_Power and then Port = Internal then
Panel.Wait_On;
end if;
Connector_Info.Read_EDID
(Raw_EDID => Raw_EDID,
Port_Cfg => Port_Cfg,
Success => Success);
end if;
if Success and then EDID.Has_Preferred_Mode (Raw_EDID) then
Configs (Config_Idx) := Config_Type'
(Port => Port,
Framebuffer => Configs (Config_Idx).Framebuffer,
Mode => EDID.Preferred_Mode (Raw_EDID));
else
Configs (Config_Idx).Port := Disabled;
end if;
end if;
end loop;
if not Keep_Power then
Power_And_Clocks.Power_Set_To (Cur_Configs);
if Config.Has_Internal_Display and then
not Port_Configured (Cur_Configs, Internal)
then
Panel.Off;
end if;
end if;
end Auto_Configure;
----------------------------------------------------------------------------
procedure Update_Outputs (Configs : Configs_Type)
is
Did_Power_Up : Boolean := False;
HPD, HPD_Delay_Over, Success : Boolean;
Old_Config, New_Config : Config_Type;
Old_Configs : Configs_Type;
Port_Cfg : Port_Config;
procedure Check_HPD
(Port_Cfg : in Port_Config;
Port : in Port_Type;
Detected : out Boolean)
is
begin
HPD_Delay_Over := Time.Timed_Out (HPD_Delay (Port));
if HPD_Delay_Over then
Port_Detect.Hotplug_Detect (Port_Cfg, Detected);
HPD_Delay (Port) := Time.MS_From_Now (333);
else
Detected := False;
end if;
end Check_HPD;
begin
Old_Configs := Cur_Configs;
for I in Config_Index loop
HPD := False;
Old_Config := Cur_Configs (I);
New_Config := Configs (I);
Fill_Port_Config (Port_Cfg, Old_Configs, I, Success);
if Success then
Check_HPD (Port_Cfg, Old_Config.Port, HPD);
end if;
-- Connector changed?
if (Success and then HPD) or
Old_Config.Port /= New_Config.Port or
Old_Config.Mode /= New_Config.Mode
then
if Old_Config.Port /= Disabled then
if Success then
pragma Debug (Debug.New_Line);
pragma Debug (Debug.Put_Line
("Disabling port " & Port_Names (Old_Config.Port)));
Connectors.Pre_Off (Port_Cfg);
Display_Controller.Off
(To_Controller (I), To_Head (I, Old_Config.Port));
Connectors.Post_Off (Port_Cfg);
end if;
-- Free PLL
PLLs.Free (Allocated_PLLs (I));
Cur_Configs (I).Port := Disabled;
end if;
if New_Config.Port /= Disabled then
Fill_Port_Config (Port_Cfg, Configs, I, Success);
if Success and then Wait_For_HPD (New_Config.Port) then
Check_HPD (Port_Cfg, New_Config.Port, Success);
Wait_For_HPD (New_Config.Port) := not Success;
end if;
if Success then
pragma Debug (Debug.New_Line);
pragma Debug (Debug.Put_Line
("Trying to enable port " & Port_Names (New_Config.Port)));
if not Did_Power_Up then
Power_And_Clocks.Power_Up (Old_Configs, Configs);
Did_Power_Up := True;
end if;
if Port_Cfg.Is_FDI then
Configure_FDI_Link (Port_Cfg, Success);
end if;
end if;
if Success then
Connector_Info.Preferred_Link_Setting
(Port_Cfg => Port_Cfg,
Success => Success);
end if;
while Success loop
pragma Loop_Invariant (New_Config.Port in Active_Port_Type);
PLLs.Alloc
(Port_Cfg => Port_Cfg,
PLL => Allocated_PLLs (I),
Success => Success);
if Success then
for Try in 1 .. 2 loop
pragma Loop_Invariant
(New_Config.Port in Active_Port_Type);
Connectors.Pre_On
(Port_Cfg => Port_Cfg,
PLL_Hint => PLLs.Register_Value
(Allocated_PLLs (I)),
Pipe_Hint => Display_Controller.Get_Pipe_Hint
(To_Head (I, New_Config.Port)),
Success => Success);
if Success then
Display_Controller.On
(Controller => To_Controller (I),
Head => To_Head (I, New_Config.Port),
Port_Cfg => Port_Cfg,
Framebuffer => New_Config.Framebuffer);
Connectors.Post_On
(Port_Cfg => Port_Cfg,
PLL_Hint => PLLs.Register_Value
(Allocated_PLLs (I)),
Success => Success);
if not Success then
Display_Controller.Off
(To_Controller (I),
To_Head (I, New_Config.Port));
Connectors.Post_Off (Port_Cfg);
end if;
end if;
exit when Success;
end loop;
exit when Success; -- connection established => stop loop
-- connection failed
PLLs.Free (Allocated_PLLs (I));
end if;
Connector_Info.Next_Link_Setting
(Port_Cfg => Port_Cfg,
Success => Success);
end loop;
if Success then
pragma Debug (Debug.Put_Line
("Enabled port " & Port_Names (New_Config.Port)));
Cur_Configs (I) := New_Config;
DP_Links (I) := Port_Cfg.DP;
else
Wait_For_HPD (New_Config.Port) := True;
if New_Config.Port = Internal then
Panel.Off;
end if;
end if;
else
Cur_Configs (I) := New_Config;
end if;
elsif Old_Config.Framebuffer /= New_Config.Framebuffer and
Old_Config.Port /= Disabled
then
Display_Controller.Update_Offset
(Controller => To_Controller (I),
Framebuffer => New_Config.Framebuffer);
Cur_Configs (I) := New_Config;
end if;
end loop;
if Did_Power_Up then
Power_And_Clocks.Power_Down (Old_Configs, Configs, Cur_Configs);
end if;
end Update_Outputs;
----------------------------------------------------------------------------
procedure Initialize
(MMIO_Base : in Word64 := 0;
Write_Delay : in Word64 := 0;
Success : out Boolean)
with
Refined_Global =>
(In_Out =>
(Config.Valid_Port_GPU,
Registers.Register_State, Port_IO.State),
Input =>
(Time.State),
Output =>
(Registers.Address_State,
PLLs.State, Panel.Panel_State,
Cur_Configs, Allocated_PLLs, DP_Links,
HPD_Delay, Wait_For_HPD, Initialized))
is
use type HW.Word64;
Now : constant Time.T := Time.Now;
procedure Check_Platform (Success : out Boolean)
is
Audio_VID_DID : Word32;
begin
case Config.CPU is
when Haswell .. Skylake =>
Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
when Ironlake .. Ivybridge =>
Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
end case;
Success :=
(case Config.CPU is
when Skylake => Audio_VID_DID = 16#8086_2809#,
when Broadwell => Audio_VID_DID = 16#8086_2808#,
when Haswell => Audio_VID_DID = 16#8086_2807#,
when Ivybridge |
Sandybridge => Audio_VID_DID = 16#8086_2806# or
Audio_VID_DID = 16#8086_2805#,
when Ironlake => Audio_VID_DID = 16#8086_2804#); -- not sure
end Check_Platform;
begin
pragma Warnings (GNATprove, Off, "unused variable ""Write_Delay""",
Reason => "Write_Delay is used for debugging only");
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
pragma Debug (Debug.Set_Register_Write_Delay (Write_Delay));
Wait_For_HPD := HPD_Type'(others => False);
HPD_Delay := HPD_Delay_Type'(others => Now);
DP_Links := Links_Type'(others => HW.GFX.Default_DP);
Allocated_PLLs := (others => PLLs.Invalid);
Cur_Configs := Configs_Type'
(others => Config_Type'
(Port => Disabled,
Framebuffer => HW.GFX.Default_FB,
Mode => HW.GFX.Invalid_Mode));
Registers.Set_Register_Base
(if MMIO_Base /= 0 then
MMIO_Base
else
Config.Default_MMIO_Base);
PLLs.Initialize;
Check_Platform (Success);
if not Success then
pragma Debug (Debug.Put_Line ("ERROR: Incompatible CPU or PCH."));
Panel.Static_Init; -- for flow analysis
Initialized := False;
return;
end if;
Panel.Setup_PP_Sequencer;
Port_Detect.Initialize;
Power_And_Clocks.Pre_All_Off;
Legacy_VGA_Off;
Connectors.Pre_All_Off;
Display_Controller.All_Off;
Connectors.Post_All_Off;
PLLs.All_Off;
Power_And_Clocks.Post_All_Off;
-------------------- Now restart from a clean state ---------------------
Power_And_Clocks.Initialize;
Initialized := True;
end Initialize;
function Is_Initialized return Boolean
with
Refined_Post => Is_Initialized'Result = Initialized
is
begin
return Initialized;
end Is_Initialized;
----------------------------------------------------------------------------
procedure Write_GTT
(GTT_Page : GTT_Range;
Device_Address : GTT_Address_Type;
Valid : Boolean) is
begin
Registers.Write_GTT (GTT_Page, Device_Address, Valid);
end Write_GTT;
procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_FB : Word32)
is
FB_Size : constant Pos32 :=
FB.Stride * FB.Height * Pos32 (((FB.BPC * 4) / 8));
Phys_Addr : GTT_Address_Type := GTT_Address_Type (Phys_FB);
begin
for Idx in GTT_Range range 0 .. GTT_Range (((FB_Size + 4095) / 4096) - 1)
loop
Registers.Write_GTT
(GTT_Page => Idx,
Device_Address => Phys_Addr,
Valid => True);
Phys_Addr := Phys_Addr + 4096;
end loop;
end Setup_Default_GTT;
----------------------------------------------------------------------------
procedure Dump_Configs (Configs : Configs_Type)
is
subtype Pipe_Name is String (1 .. 9);
type Pipe_Name_Array is array (Config_Index) of Pipe_Name;
Pipe_Names : constant Pipe_Name_Array :=
(Primary => "Primary ",
Secondary => "Secondary",
Tertiary => "Tertiary ");
begin
Debug.New_Line;
Debug.Put_Line ("CONFIG => ");
for Pipe in Config_Index loop
if Pipe = Config_Index'First then
Debug.Put (" (");
else
Debug.Put (" ");
end if;
Debug.Put_Line (Pipe_Names (Pipe) & " =>");
Debug.Put_Line
(" (Port => " & Port_Names (Configs (Pipe).Port) & ",");
Debug.Put_Line (" Framebuffer =>");
Debug.Put (" (Width => ");
Debug.Put_Int32 (Configs (Pipe).Framebuffer.Width);
Debug.Put_Line (",");
Debug.Put (" Height => ");
Debug.Put_Int32 (Configs (Pipe).Framebuffer.Height);
Debug.Put_Line (",");
Debug.Put (" Stride => ");
Debug.Put_Int32 (Configs (Pipe).Framebuffer.Stride);
Debug.Put_Line (",");
Debug.Put (" Offset => ");
Debug.Put_Word32 (Configs (Pipe).Framebuffer.Offset);
Debug.Put_Line (",");
Debug.Put (" BPC => ");
Debug.Put_Int64 (Configs (Pipe).Framebuffer.BPC);
Debug.Put_Line ("),");
Debug.Put_Line (" Mode =>");
Debug.Put (" (Dotclock => ");
Debug.Put_Int64 (Configs (Pipe).Mode.Dotclock);
Debug.Put_Line (",");
Debug.Put (" H_Visible => ");
Debug.Put_Int16 (Configs (Pipe).Mode.H_Visible);
Debug.Put_Line (",");
Debug.Put (" H_Sync_Begin => ");
Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_Begin);
Debug.Put_Line (",");
Debug.Put (" H_Sync_End => ");
Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_End);
Debug.Put_Line (",");
Debug.Put (" H_Total => ");
Debug.Put_Int16 (Configs (Pipe).Mode.H_Total);
Debug.Put_Line (",");
Debug.Put (" V_Visible => ");
Debug.Put_Int16 (Configs (Pipe).Mode.V_Visible);
Debug.Put_Line (",");
Debug.Put (" V_Sync_Begin => ");
Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_Begin);
Debug.Put_Line (",");
Debug.Put (" V_Sync_End => ");
Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_End);
Debug.Put_Line (",");
Debug.Put (" V_Total => ");
Debug.Put_Int16 (Configs (Pipe).Mode.V_Total);
Debug.Put_Line (",");
Debug.Put_Line (" H_Sync_Active_High => " &
(if Configs (Pipe).Mode.H_Sync_Active_High
then "True,"
else "False,"));
Debug.Put_Line (" V_Sync_Active_High => " &
(if Configs (Pipe).Mode.V_Sync_Active_High
then "True,"
else "False,"));
Debug.Put (" BPC => ");
Debug.Put_Int64 (Configs (Pipe).Mode.BPC);
if Pipe /= Config_Index'Last then
Debug.Put_Line (")),");
else
Debug.Put_Line (")));");
end if;
end loop;
end Dump_Configs;
end HW.GFX.GMA;

138
common/hw-gfx-gma.ads Normal file
View File

@ -0,0 +1,138 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.Port_IO;
package HW.GFX.GMA
with
Abstract_State =>
(State,
Init_State,
Config_State,
(Device_State with External)),
Initializes =>
(Init_State,
Config_State)
is
type CPU_Type is
(Ironlake,
Sandybridge,
Ivybridge,
Haswell,
Broadwell,
Skylake);
type CPU_Variant is (Normal, ULT);
type Port_Type is
(Disabled,
Internal,
DP1,
DP2,
DP3,
Digital1,
Digital2,
Digital3,
Analog);
type Port_List_Range is range 0 .. 7;
type Port_List is array (Port_List_Range) of Port_Type;
type Config_Type is record
Port : Port_Type;
Framebuffer : Framebuffer_Type;
Mode : Mode_Type;
end record;
type Config_Index is (Primary, Secondary, Tertiary);
type Configs_Type is array (Config_Index) of Config_Type;
procedure Initialize
(MMIO_Base : in Word64 := 0;
Write_Delay : in Word64 := 0;
Success : out Boolean)
with
Global =>
(In_Out => (Config_State, Device_State, Port_IO.State),
Output => (State, Init_State),
Input => (Time.State)),
Post => Success = Is_Initialized;
function Is_Initialized return Boolean
with
Global => (Input => Init_State);
procedure Legacy_VGA_Off;
procedure Scan_Ports
(Configs : out Configs_Type;
Ports : in Port_List);
procedure Auto_Configure
(Configs : in out Configs_Type;
Keep_Power : in Boolean := False);
procedure Update_Outputs (Configs : Configs_Type);
pragma Warnings (GNATprove, Off, "subprogram ""Dump_Configs"" has no effect",
Reason => "It's only used for debugging");
procedure Dump_Configs (Configs : Configs_Type);
type GTT_Address_Type is mod 2 ** 39;
type GTT_Range is range 0 .. 16#8_0000# - 1;
procedure Write_GTT
(GTT_Page : GTT_Range;
Device_Address : GTT_Address_Type;
Valid : Boolean);
procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_FB : Word32);
private
type GPU_Port is (DIGI_A, DIGI_B, DIGI_C, DIGI_D, DIGI_E);
subtype Digital_Port is GPU_Port range DIGI_A .. DIGI_E;
type PCH_Port is
(PCH_DAC, PCH_LVDS,
PCH_HDMI_B, PCH_HDMI_C, PCH_HDMI_D,
PCH_DP_B, PCH_DP_C, PCH_DP_D);
subtype PCH_HDMI_Port is PCH_Port range PCH_HDMI_B .. PCH_HDMI_D;
subtype PCH_DP_Port is PCH_Port range PCH_DP_B .. PCH_DP_D;
type Display_Type is (None, LVDS, DP, HDMI, VGA);
subtype Internal_Type is Display_Type range None .. DP;
type Port_Config is
record
Port : GPU_Port;
PCH_Port : GMA.PCH_Port;
Display : Display_Type;
Mode : Mode_Type;
Is_FDI : Boolean;
FDI : DP_Link;
DP : DP_Link;
end record;
type FDI_Training_Type is (Simple_Training, Full_Training, Auto_Training);
----------------------------------------------------------------------------
type DP_Port is (DP_A, DP_B, DP_C, DP_D);
----------------------------------------------------------------------------
VGA_SR_INDEX : constant Port_IO.Port_Type := 16#03c4#;
VGA_SR_DATA : constant Port_IO.Port_Type := 16#03c5#;
VGA_SR01 : constant Word8 := 16#01#;
end HW.GFX.GMA;

21
common/hw-gfx-i2c.ads Normal file
View File

@ -0,0 +1,21 @@
--
-- Copyright (C) 2015 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.I2C is
type Transfer_Address is mod 2 ** 7;
subtype Transfer_Length is Natural range 0 .. 128;
subtype Transfer_Index is Natural range 0 .. Transfer_Length'Last - 1;
subtype Transfer_Data is Buffer (Transfer_Index);
end HW.GFX.I2C;

155
common/hw-gfx.ads Normal file
View File

@ -0,0 +1,155 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW;
use type HW.Pos64;
use type HW.Word32;
package HW.GFX is
-- implementation only supports 4800p for now ;-)
subtype Width_Type is Pos32 range 1 .. 4800;
subtype Height_Type is Pos32 range 1 .. 7680;
Auto_BPC : constant := 5;
subtype BPC_Type is Int64 range Auto_BPC .. 16;
type Framebuffer_Type is
record
Width : Width_Type;
Height : Height_Type;
BPC : BPC_Type;
Stride : Width_Type;
Offset : Word32;
end record;
Default_FB : constant Framebuffer_Type := Framebuffer_Type'
(Width => 1,
Height => 1,
BPC => 8,
Stride => 1,
Offset => 0);
subtype Frequency_Type is Pos64 range 25_000_000 .. 600_000_000;
type DP_Lane_Count is (DP_Lane_Count_1, DP_Lane_Count_2, DP_Lane_Count_4);
subtype DP_Lane_Count_Type is Pos64 range 1 .. 4;
type DP_Lane_Count_Integers is array (DP_Lane_Count) of DP_Lane_Count_Type;
Lane_Count_As_Integer : constant DP_Lane_Count_Integers :=
DP_Lane_Count_Integers'
(DP_Lane_Count_1 => 1, DP_Lane_Count_2 => 2, DP_Lane_Count_4 => 4);
type DP_Bandwidth is (DP_Bandwidth_1_62, DP_Bandwidth_2_7, DP_Bandwidth_5_4);
for DP_Bandwidth use
(DP_Bandwidth_1_62 => 6, DP_Bandwidth_2_7 => 10, DP_Bandwidth_5_4 => 20);
for DP_Bandwidth'Size use 8;
subtype DP_Symbol_Rate_Type is Pos64 range 1 .. 810_000_000;
type DP_Symbol_Rate_Array is array (DP_Bandwidth) of DP_Symbol_Rate_Type;
DP_Symbol_Rate : constant DP_Symbol_Rate_Array := DP_Symbol_Rate_Array'
(DP_Bandwidth_1_62 => 162_000_000,
DP_Bandwidth_2_7 => 270_000_000,
DP_Bandwidth_5_4 => 540_000_000);
type DP_Caps is record
Rev : Word8;
Max_Link_Rate : DP_Bandwidth;
Max_Lane_Count : DP_Lane_Count;
TPS3_Supported : Boolean;
Enhanced_Framing : Boolean;
No_Aux_Handshake : Boolean;
Aux_RD_Interval : Word8;
end record;
type DP_Link is
record
Receiver_Caps : DP_Caps;
Lane_Count : DP_Lane_Count;
Bandwidth : DP_Bandwidth;
Enhanced_Framing : Boolean;
Opportunistic_Training : Boolean;
end record;
Default_DP : constant DP_Link := DP_Link'
(Receiver_Caps => DP_Caps'
(Rev => 16#00#,
Max_Link_Rate => DP_Bandwidth'First,
Max_Lane_Count => DP_Lane_Count'First,
TPS3_Supported => False,
Enhanced_Framing => False,
No_Aux_Handshake => False,
Aux_RD_Interval => 16#00#),
Lane_Count => DP_Lane_Count'First,
Bandwidth => DP_Bandwidth'First,
Enhanced_Framing => False,
Opportunistic_Training => False);
type Mode_Type is
record
Dotclock : Frequency_Type;
H_Visible : Pos16;
H_Sync_Begin : Pos16;
H_Sync_End : Pos16;
H_Total : Pos16;
V_Visible : Pos16;
V_Sync_Begin : Pos16;
V_Sync_End : Pos16;
V_Total : Pos16;
H_Sync_Active_High : Boolean;
V_Sync_Active_High : Boolean;
BPC : BPC_Type;
end record;
----------------------------------------------------------------------------
-- Constants
----------------------------------------------------------------------------
-- modeline constants
-- Dotclock is calculated using: Refresh_Rate * H_Total * V_Total
M2560x1600_60 : constant Mode_Type := Mode_Type'
(60*(2720*1646), 2560, 2608, 2640, 2720, 1600, 1603, 1609, 1646, True, True, Auto_BPC);
M2560x1440_60 : constant Mode_Type := Mode_Type'
(60*(2720*1481), 2560, 2608, 2640, 2720, 1440, 1443, 1448, 1481, True, False, Auto_BPC);
M1920x1200_60 : constant Mode_Type := Mode_Type'
(60*(2080*1235), 1920, 1968, 2000, 2080, 1200, 1203, 1209, 1235, False, False, Auto_BPC);
M1920x1080_60 : constant Mode_Type := Mode_Type'
(60*(2185*1135), 1920, 2008, 2052, 2185, 1080, 1084, 1089, 1135, False, False, Auto_BPC);
M1680x1050_60 : constant Mode_Type := Mode_Type'
(60*(2256*1087), 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, False, True, Auto_BPC);
M1600x1200_60 : constant Mode_Type := Mode_Type'
(60*(2160*1250), 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, True, True, Auto_BPC);
M1600x900_60 : constant Mode_Type := Mode_Type'
(60*(2010*912), 1600, 1664, 1706, 2010, 900, 903, 906, 912, False, False, Auto_BPC);
M1440x900_60 : constant Mode_Type := Mode_Type'
(60*(1834*920), 1440, 1488, 1520, 1834, 900, 903, 909, 920, False, False, Auto_BPC);
M1366x768_60 : constant Mode_Type := Mode_Type'
(60*(1446*788), 1366, 1414, 1446, 1466, 768, 769, 773, 788, False, False, Auto_BPC);
M1280x1024_60 : constant Mode_Type := Mode_Type'
(60*(1712*1063), 1280, 1368, 1496, 1712, 1024, 1027, 1034, 1063, False, True, Auto_BPC);
M1024x768_60 : constant Mode_Type := Mode_Type'
(60*(1344*806), 1024, 1048, 1184, 1344, 768, 771, 777, 806, False, False, Auto_BPC);
Invalid_Mode : constant Mode_Type := Mode_Type'
(Frequency_Type'First, 1, 1, 1, 1, 1, 1, 1, 1, False, False, Auto_BPC);
end HW.GFX;

View File

@ -0,0 +1,17 @@
gfxinit-y += hw-gfx-gma-connectors-edp.adb
gfxinit-y += hw-gfx-gma-connectors-edp.ads
gfxinit-y += hw-gfx-gma-connectors-fdi.adb
gfxinit-y += hw-gfx-gma-connectors-fdi.ads
gfxinit-y += hw-gfx-gma-connectors.adb
gfxinit-y += hw-gfx-gma-pch-dp.adb
gfxinit-y += hw-gfx-gma-pch-dp.ads
gfxinit-y += hw-gfx-gma-pch-hdmi.adb
gfxinit-y += hw-gfx-gma-pch-hdmi.ads
gfxinit-y += hw-gfx-gma-pch-lvds.adb
gfxinit-y += hw-gfx-gma-pch-lvds.ads
gfxinit-y += hw-gfx-gma-plls.adb
gfxinit-y += hw-gfx-gma-plls.ads
gfxinit-y += hw-gfx-gma-port_detect.adb
gfxinit-y += hw-gfx-gma-power_and_clocks.ads
gfxinit-y += hw-gfx-gma-power_and_clocks_ironlake.adb
gfxinit-y += hw-gfx-gma-power_and_clocks_ironlake.ads

View File

@ -0,0 +1,297 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.DP_Training;
with HW.GFX.GMA.DP_Info;
with HW.GFX.GMA.DP_Aux_Ch;
with HW.GFX.GMA.Registers;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.Connectors.EDP
is
DP_CTL_DISPLAYPORT_ENABLE : constant := 1 * 2 ** 31;
DP_CTL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
DP_CTL_PIPE_SELECT_SHIFT : constant := 29;
DP_CTL_VSWING_EMPH_SET_MASK : constant := 63 * 2 ** 22;
DP_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 19;
DP_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 19;
DP_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 19;
DP_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 19;
DP_CTL_ENHANCED_FRAMING_ENABLE : constant := 1 * 2 ** 18;
DP_CTL_PLL_FREQUENCY_MASK : constant := 3 * 2 ** 16;
DP_CTL_PLL_FREQUENCY_270 : constant := 0 * 2 ** 16;
DP_CTL_PLL_FREQUENCY_162 : constant := 1 * 2 ** 16;
DP_CTL_PORT_REVERSAL : constant := 1 * 2 ** 15;
DP_CTL_PLL_ENABLE : constant := 1 * 2 ** 14;
DP_CTL_LINK_TRAIN_MASK : constant := 3 * 2 ** 8;
DP_CTL_LINK_TRAIN_PAT1 : constant := 0 * 2 ** 8;
DP_CTL_LINK_TRAIN_PAT2 : constant := 1 * 2 ** 8;
DP_CTL_LINK_TRAIN_IDLE : constant := 2 * 2 ** 8;
DP_CTL_LINK_TRAIN_NORMAL : constant := 3 * 2 ** 8;
DP_CTL_ALT_SCRAMBLER_RESET : constant := 1 * 2 ** 6;
DP_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4;
DP_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3;
DP_CTL_PORT_DETECT : constant := 1 * 2 ** 2;
-- TODO? Values are for Ivy Bridge only
DP_CTL_VSWING_0_EMPH_0 : constant := 1 * 2 ** 27 + 1 * 2 ** 24 + 0 * 2 ** 22;
DP_CTL_VSWING_0_EMPH_1 : constant := 1 * 2 ** 27 + 2 * 2 ** 24 + 2 * 2 ** 22;
DP_CTL_VSWING_0_EMPH_2 : constant := 1 * 2 ** 27 + 3 * 2 ** 24 + 3 * 2 ** 22;
DP_CTL_VSWING_1_EMPH_0 : constant := 1 * 2 ** 27 + 4 * 2 ** 24 + 0 * 2 ** 22;
DP_CTL_VSWING_1_EMPH_1 : constant := 1 * 2 ** 27 + 5 * 2 ** 24 + 2 * 2 ** 22;
DP_CTL_VSWING_2_EMPH_0 : constant := 1 * 2 ** 27 + 6 * 2 ** 24 + 0 * 2 ** 22;
DP_CTL_VSWING_2_EMPH_1 : constant := 1 * 2 ** 27 + 7 * 2 ** 24 + 2 * 2 ** 22;
type DP_CTL_PORT_WIDTH_T is array (DP_Lane_Count) of Word32;
DP_CTL_PORT_WIDTH : constant DP_CTL_PORT_WIDTH_T :=
DP_CTL_PORT_WIDTH_T'
(DP_Lane_Count_1 => DP_CTL_PORT_WIDTH_1_LANE,
DP_Lane_Count_2 => DP_CTL_PORT_WIDTH_2_LANES,
DP_Lane_Count_4 => DP_CTL_PORT_WIDTH_4_LANES);
type DP_CTL_LINK_TRAIN_Array is array (DP_Info.Training_Pattern) of Word32;
DP_CTL_LINK_TRAIN : constant DP_CTL_LINK_TRAIN_Array :=
DP_CTL_LINK_TRAIN_Array'
(DP_Info.TP_1 => DP_CTL_LINK_TRAIN_PAT1,
DP_Info.TP_2 => DP_CTL_LINK_TRAIN_PAT2,
DP_Info.TP_3 => DP_CTL_LINK_TRAIN_PAT2,
DP_Info.TP_Idle => DP_CTL_LINK_TRAIN_IDLE,
DP_Info.TP_None => DP_CTL_LINK_TRAIN_NORMAL);
----------------------------------------------------------------------------
procedure Pre_Training is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_And_Set_Mask
(Register => Registers.DP_CTL_A,
Mask_Unset => DP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_CTL_LINK_TRAIN (DP_Info.TP_1) or
DP_CTL_DISPLAYPORT_ENABLE);
end Pre_Training;
----------------------------------------------------------------------------
pragma Warnings (GNATprove, Off, "unused variable ""Port""",
Reason => "Needed for a common interface");
function Max_V_Swing
(Port : Digital_Port)
return DP_Info.DP_Voltage_Swing
is
begin
return DP_Info.VS_Level_2;
end Max_V_Swing;
function Max_Pre_Emph
(Port : Digital_Port;
Train_Set : DP_Info.Train_Set)
return DP_Info.DP_Pre_Emph
is
begin
return
(case Train_Set.Voltage_Swing is
when DP_Info.VS_Level_0 => DP_Info.Emph_Level_2,
when DP_Info.VS_Level_1 |
DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
when others => DP_Info.Emph_Level_0);
end Max_Pre_Emph;
----------------------------------------------------------------------------
pragma Warnings (GNATprove, Off, "unused variable ""Link""",
Reason => "Needed for a common interface");
procedure Set_Training_Pattern
(Port : Digital_Port;
Link : DP_Link;
Pattern : DP_Info.Training_Pattern)
is
use type DP_Info.Training_Pattern;
begin
if Pattern < DP_Info.TP_Idle then
Registers.Unset_And_Set_Mask
(Register => Registers.DP_CTL_A,
Mask_Unset => DP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_CTL_LINK_TRAIN (Pattern));
else
-- send at least 5 idle patterns
Registers.Unset_And_Set_Mask
(Register => Registers.DP_CTL_A,
Mask_Unset => DP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_CTL_LINK_TRAIN (DP_Info.TP_Idle));
-- we switch to normal frame delivery later in Post_On procedure
end if;
end Set_Training_Pattern;
procedure Set_Signal_Levels
(Port : Digital_Port;
Link : DP_Link;
Train_Set : DP_Info.Train_Set)
is
VSwing_Emph : Word32;
begin
VSwing_Emph :=
(case Train_Set.Voltage_Swing is
when DP_Info.VS_Level_0 =>
(case Train_Set.Pre_Emph is
when DP_Info.Emph_Level_0 => DP_CTL_VSWING_0_EMPH_0,
when DP_Info.Emph_Level_1 => DP_CTL_VSWING_0_EMPH_1,
when DP_Info.Emph_Level_2 => DP_CTL_VSWING_0_EMPH_2,
when others => DP_CTL_VSWING_0_EMPH_0),
when DP_Info.VS_Level_1 =>
(case Train_Set.Pre_Emph is
when DP_Info.Emph_Level_0 => DP_CTL_VSWING_1_EMPH_0,
when DP_Info.Emph_Level_1 => DP_CTL_VSWING_1_EMPH_1,
when others => DP_CTL_VSWING_1_EMPH_0),
when DP_Info.VS_Level_2 =>
(case Train_Set.Pre_Emph is
when DP_Info.Emph_Level_0 => DP_CTL_VSWING_2_EMPH_0,
when DP_Info.Emph_Level_1 => DP_CTL_VSWING_2_EMPH_1,
when others => DP_CTL_VSWING_2_EMPH_0),
when others => DP_CTL_VSWING_0_EMPH_0);
Registers.Unset_And_Set_Mask
(Register => Registers.DP_CTL_A,
Mask_Unset => DP_CTL_VSWING_EMPH_SET_MASK,
Mask_Set => VSwing_Emph);
end Set_Signal_Levels;
pragma Warnings (GNATprove, On, "unused variable ""Port""");
pragma Warnings (GNATprove, On, "unused variable ""Link""");
----------------------------------------------------------------------------
procedure Pre_On
(Port_Cfg : Port_Config;
Pipe_Hint : Word32)
is
DP_CTL_Set : Word32;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
DP_CTL_Set :=
Shift_Left (Pipe_Hint, DP_CTL_PIPE_SELECT_SHIFT) or
DP_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count);
if Port_Cfg.DP.Enhanced_Framing then
DP_CTL_Set := DP_CTL_Set or DP_CTL_ENHANCED_FRAMING_ENABLE;
end if;
case Port_Cfg.DP.Bandwidth is
when DP_Bandwidth_1_62 =>
DP_CTL_Set := DP_CTL_Set or DP_CTL_PLL_FREQUENCY_162;
when DP_Bandwidth_2_7 =>
DP_CTL_Set := DP_CTL_Set or DP_CTL_PLL_FREQUENCY_270;
when others =>
null;
end case;
if Port_Cfg.Mode.V_Sync_Active_High then
DP_CTL_Set := DP_CTL_Set or DP_CTL_VSYNC_ACTIVE_HIGH;
end if;
if Port_Cfg.Mode.H_Sync_Active_High then
DP_CTL_Set := DP_CTL_Set or DP_CTL_HSYNC_ACTIVE_HIGH;
end if;
Registers.Write
(Register => Registers.DP_CTL_A,
Value => DP_CTL_Set);
Registers.Write
(Register => Registers.DP_CTL_A,
Value => DP_CTL_PLL_ENABLE or DP_CTL_Set);
Registers.Posting_Read (Registers.DP_CTL_A);
Time.U_Delay (20);
end Pre_On;
----------------------------------------------------------------------------
procedure Post_On
(Link : in DP_Link;
Success : out Boolean)
is
pragma Warnings (GNATprove, Off, "unused variable ""Port""",
Reason => "Needed for a common interface");
function To_DP (Port : Digital_Port) return DP_Port
is
begin
return DP_A;
end To_DP;
pragma Warnings (GNATprove, On, "unused variable ""Port""");
package Training is new DP_Training
(TPS3_Supported => False,
T => Digital_Port,
Aux_T => DP_Port,
Aux_Ch => DP_Aux_Ch,
DP_Info => DP_Info,
To_Aux => To_DP,
Max_V_Swing => Max_V_Swing,
Max_Pre_Emph => Max_Pre_Emph,
Set_Pattern => Set_Training_Pattern,
Set_Signal_Levels => Set_Signal_Levels,
Off => Off);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Training.Train_DP
(Port => DIGI_A,
Link => Link,
Success => Success);
if Success then
Registers.Unset_And_Set_Mask
(Register => Registers.DP_CTL_A,
Mask_Unset => DP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_CTL_LINK_TRAIN_NORMAL);
end if;
end Post_On;
----------------------------------------------------------------------------
procedure Off (Port : Digital_Port)
is
Enabled : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_And_Set_Mask
(Register => Registers.DP_CTL_A,
Mask_Unset => DP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_CTL_LINK_TRAIN_IDLE);
Registers.Posting_Read (Registers.DP_CTL_A);
Registers.Unset_Mask
(Register => Registers.DP_CTL_A,
Mask => DP_CTL_DISPLAYPORT_ENABLE);
-- implicit Posting_Read below
Registers.Is_Set_Mask
(Register => Registers.DP_CTL_A,
Mask => DP_CTL_PLL_ENABLE,
Result => Enabled);
Registers.Write
(Register => Registers.DP_CTL_A,
Value => 16#0000_0000#);
Registers.Posting_Read (Registers.DP_CTL_A);
if Enabled then
Time.U_Delay (20);
end if;
end Off;
end HW.GFX.GMA.Connectors.EDP;

View File

@ -0,0 +1,32 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.Connectors.EDP
is
procedure Pre_On
(Port_Cfg : Port_Config;
Pipe_Hint : Word32);
procedure Post_On
(Link : in DP_Link;
Success : out Boolean);
pragma Warnings (GNATprove, Off, "unused variable ""Port""",
Reason => "Needed for a common interface");
procedure Off (Port : Digital_Port);
pragma Warnings (GNATprove, On, "unused variable ""Port""");
procedure Pre_Training;
end HW.GFX.GMA.Connectors.EDP;

View File

@ -0,0 +1,342 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.PCH.FDI;
with HW.GFX.GMA.Registers;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.Connectors.FDI
is
PCH_FDI_CHICKEN_B_AND_C : constant := 1 * 2 ** 12;
type TX_CTL_Regs is array (GPU_FDI_Port) of Registers.Registers_Index;
TX_CTL : constant TX_CTL_Regs :=
(DIGI_B => Registers.FDI_TX_CTL_A,
DIGI_C => Registers.FDI_TX_CTL_B,
DIGI_D => Registers.FDI_TX_CTL_C);
FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
FDI_TX_CTL_VP_MASK : constant := 16#3f# * 2 ** 22;
FDI_TX_CTL_PORT_WIDTH_SEL_SHIFT : constant := 19;
FDI_TX_CTL_ENHANCED_FRAMING_ENABLE : constant := 1 * 2 ** 18;
FDI_TX_CTL_FDI_PLL_ENABLE : constant := 1 * 2 ** 14;
FDI_TX_CTL_COMPOSITE_SYNC_SELECT : constant := 1 * 2 ** 11;
FDI_TX_CTL_AUTO_TRAIN_ENABLE : constant := 1 * 2 ** 10;
FDI_TX_CTL_AUTO_TRAIN_DONE : constant := 1 * 2 ** 1;
TP_SHIFT : constant := (if Config.CPU <= Sandybridge then 28 else 8);
FDI_TX_CTL_TRAINING_PATTERN_MASK : constant := 3 * 2 ** TP_SHIFT;
FDI_TX_CTL_TRAINING_PATTERN_1 : constant := 0 * 2 ** TP_SHIFT;
FDI_TX_CTL_TRAINING_PATTERN_2 : constant := 1 * 2 ** TP_SHIFT;
FDI_TX_CTL_TRAINING_PATTERN_IDLE : constant := 2 * 2 ** TP_SHIFT;
FDI_TX_CTL_TRAINING_PATTERN_NORMAL : constant := 3 * 2 ** TP_SHIFT;
subtype FDI_TX_CTL_VP_T is Natural range 0 .. 3;
type Vswing_Preemph_Values is array (FDI_TX_CTL_VP_T) of Word32;
FDI_TX_CTL_VSWING_PREEMPH : constant Vswing_Preemph_Values :=
(0 => 16#00# * 2 ** 22,
1 => 16#3a# * 2 ** 22,
2 => 16#39# * 2 ** 22,
3 => 16#38# * 2 ** 22);
function FDI_TX_CTL_PORT_WIDTH_SEL (Lane_Count : DP_Lane_Count) return Word32
is
begin
return Shift_Left
(Word32 (Lane_Count_As_Integer (Lane_Count)) - 1,
FDI_TX_CTL_PORT_WIDTH_SEL_SHIFT);
end FDI_TX_CTL_PORT_WIDTH_SEL;
----------------------------------------------------------------------------
--
-- This is usually used with Ivy Bridge.
--
procedure Auto_Training
(Port_Cfg : in Port_Config;
Success : out Boolean)
with
Pre => Port_Cfg.Port in GPU_FDI_Port
is
PCH_FDI_Port : constant PCH.FDI_Port_Type := PCH_FDIs (Port_Cfg.Port);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
-- try each preemph/voltage pair twice
for VP2 in Natural range 0 .. FDI_TX_CTL_VP_T'Last * 2 + 1
loop
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_VP_MASK or
FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_FDI_TX_ENABLE or
FDI_TX_CTL_VSWING_PREEMPH (VP2 / 2) or
FDI_TX_CTL_AUTO_TRAIN_ENABLE or
FDI_TX_CTL_TRAINING_PATTERN_1);
Registers.Posting_Read (TX_CTL (Port_Cfg.Port));
PCH.FDI.Auto_Train (PCH_FDI_Port);
-- read at least twice
for I in 0 .. 3 loop
Registers.Is_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask => FDI_TX_CTL_AUTO_TRAIN_DONE,
Result => Success);
exit when Success or I = 3;
Time.U_Delay (1);
end loop;
exit when Success;
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_FDI_TX_ENABLE or
FDI_TX_CTL_AUTO_TRAIN_ENABLE or
FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_TRAINING_PATTERN_1);
PCH.FDI.Off (PCH_FDI_Port, PCH.FDI.Rx_Off);
end loop;
if Success then
PCH.FDI.Enable_EC (PCH_FDI_Port);
else
Registers.Unset_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask => FDI_TX_CTL_FDI_PLL_ENABLE);
PCH.FDI.Off (PCH_FDI_Port, PCH.FDI.Clock_Off);
end if;
end Auto_Training;
----------------------------------------------------------------------------
--
-- Used with Sandy Bridge (should work with Ivy Bridge too)
--
procedure Full_Training
(Port_Cfg : in Port_Config;
Success : out Boolean)
with
Pre => Port_Cfg.Port in GPU_FDI_Port
is
PCH_FDI_Port : constant PCH.FDI_Port_Type := PCH_FDIs (Port_Cfg.Port);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
-- try each preemph/voltage pair twice
for VP2 in Natural range 0 .. FDI_TX_CTL_VP_T'Last * 2 + 1
loop
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_VP_MASK or
FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_FDI_TX_ENABLE or
FDI_TX_CTL_VSWING_PREEMPH (VP2 / 2) or
FDI_TX_CTL_TRAINING_PATTERN_1);
Registers.Posting_Read (TX_CTL (Port_Cfg.Port));
PCH.FDI.Train (PCH_FDI_Port, PCH.FDI.TP_1, Success);
if Success then
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_TRAINING_PATTERN_2);
Registers.Posting_Read (TX_CTL (Port_Cfg.Port));
PCH.FDI.Train (PCH_FDI_Port, PCH.FDI.TP_2, Success);
end if;
exit when Success;
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_FDI_TX_ENABLE or
FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_TRAINING_PATTERN_1);
PCH.FDI.Off (PCH_FDI_Port, PCH.FDI.Rx_Off);
end loop;
if Success then
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_TRAINING_PATTERN_NORMAL);
Registers.Posting_Read (TX_CTL (Port_Cfg.Port));
PCH.FDI.Train (PCH_FDI_Port, PCH.FDI.TP_None, Success);
else
Registers.Unset_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask => FDI_TX_CTL_FDI_PLL_ENABLE);
PCH.FDI.Off (PCH_FDI_Port, PCH.FDI.Clock_Off);
end if;
end Full_Training;
----------------------------------------------------------------------------
--
-- Used with original Ironlake (Nehalem CPU)
--
-- This is close to what Linux' i915 does. A comment in i915_reg.h
-- states that it uses only the lowest voltage / pre-emphasis levels
-- which is why we leave them at zero here and don't try different
-- values.
--
-- It's actually not clear from i915's code if the values really are
-- at zero or if it's just reusing what the Video BIOS set. Some code
-- in coreboot sets them to zero explicitly.
--
procedure Simple_Training
(Port_Cfg : in Port_Config;
Success : out Boolean)
with
Pre => Port_Cfg.Port in GPU_FDI_Port
is
PCH_FDI_Port : constant PCH.FDI_Port_Type := PCH_FDIs (Port_Cfg.Port);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_FDI_TX_ENABLE or
FDI_TX_CTL_TRAINING_PATTERN_1);
Registers.Posting_Read (TX_CTL (Port_Cfg.Port));
PCH.FDI.Train (PCH_FDI_Port, PCH.FDI.TP_1, Success);
if Success then
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_TRAINING_PATTERN_2);
Registers.Posting_Read (TX_CTL (Port_Cfg.Port));
PCH.FDI.Train (PCH_FDI_Port, PCH.FDI.TP_2, Success);
end if;
if Success then
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_TRAINING_PATTERN_NORMAL);
Registers.Posting_Read (TX_CTL (Port_Cfg.Port));
PCH.FDI.Train (PCH_FDI_Port, PCH.FDI.TP_None, Success);
else
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask_Unset => FDI_TX_CTL_FDI_TX_ENABLE or
FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_TRAINING_PATTERN_1);
PCH.FDI.Off (PCH_FDI_Port, PCH.FDI.Rx_Off);
Registers.Unset_Mask
(Register => TX_CTL (Port_Cfg.Port),
Mask => FDI_TX_CTL_FDI_PLL_ENABLE);
PCH.FDI.Off (PCH_FDI_Port, PCH.FDI.Clock_Off);
end if;
end Simple_Training;
----------------------------------------------------------------------------
procedure Pre_On (Port_Cfg : Port_Config)
is
Composite_Sel : constant :=
(if Config.Has_FDI_Composite_Sel then
FDI_TX_CTL_COMPOSITE_SYNC_SELECT else 0);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
-- The PCH_FDI_CHICKEN_B_AND_C bit may not be changed when any of
-- both ports is active. Bandwidth calculations before calling us
-- should ensure this.
if Config.Has_FDI_C then
if Port_Cfg.Port = DIGI_D or
(Port_Cfg.Port = DIGI_C and
Port_Cfg.FDI.Lane_Count <= DP_Lane_Count_2)
then
Registers.Set_Mask
(Register => Registers.PCH_FDI_CHICKEN_B_C,
Mask => PCH_FDI_CHICKEN_B_AND_C);
elsif Port_Cfg.Port = DIGI_C then
Registers.Unset_Mask
(Register => Registers.PCH_FDI_CHICKEN_B_C,
Mask => PCH_FDI_CHICKEN_B_AND_C);
end if;
end if;
PCH.FDI.Pre_Train (PCH_FDIs (Port_Cfg.Port), Port_Cfg);
Registers.Write
(Register => TX_CTL (Port_Cfg.Port),
Value => FDI_TX_CTL_PORT_WIDTH_SEL (Port_Cfg.FDI.Lane_Count) or
FDI_TX_CTL_ENHANCED_FRAMING_ENABLE or
FDI_TX_CTL_FDI_PLL_ENABLE or
Composite_Sel or
FDI_TX_CTL_TRAINING_PATTERN_1);
Registers.Posting_Read (TX_CTL (Port_Cfg.Port));
Time.U_Delay (100);
end Pre_On;
----------------------------------------------------------------------------
procedure Post_On
(Port_Cfg : in Port_Config;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
case Config.FDI_Training is
when GMA.Simple_Training => Simple_Training (Port_Cfg, Success);
when GMA.Full_Training => Full_Training (Port_Cfg, Success);
when GMA.Auto_Training => Auto_Training (Port_Cfg, Success);
end case;
end Post_On;
----------------------------------------------------------------------------
procedure Off (Port : GPU_FDI_Port; OT : Off_Type)
is
PCH_FDI_Port : constant PCH.FDI_Port_Type := PCH_FDIs (Port);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_And_Set_Mask
(Register => TX_CTL (Port),
Mask_Unset => FDI_TX_CTL_FDI_TX_ENABLE or
FDI_TX_CTL_AUTO_TRAIN_ENABLE or
FDI_TX_CTL_TRAINING_PATTERN_MASK,
Mask_Set => FDI_TX_CTL_TRAINING_PATTERN_1);
PCH.FDI.Off (PCH_FDI_Port, PCH.FDI.Rx_Off);
if OT >= Clock_Off then
Registers.Unset_Mask
(Register => TX_CTL (Port),
Mask => FDI_TX_CTL_FDI_PLL_ENABLE);
PCH.FDI.Off (PCH_FDI_Port, PCH.FDI.Clock_Off);
end if;
end Off;
end HW.GFX.GMA.Connectors.FDI;

View File

@ -0,0 +1,43 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.PCH;
private package HW.GFX.GMA.Connectors.FDI
is
subtype GPU_FDI_Port is GPU_Port range DIGI_B .. DIGI_D;
type PCH_FDI_Mapping is array (GPU_FDI_Port) of PCH.FDI_Port_Type;
PCH_FDIs : constant PCH_FDI_Mapping :=
(DIGI_B => PCH.FDI_A,
DIGI_C => PCH.FDI_B,
DIGI_D => PCH.FDI_C);
type Off_Type is (Link_Off, Clock_Off);
----------------------------------------------------------------------------
procedure Pre_On (Port_Cfg : Port_Config)
with
Pre => Port_Cfg.Port in GPU_FDI_Port;
procedure Post_On
(Port_Cfg : in Port_Config;
Success : out Boolean)
with
Pre => Port_Cfg.Port in GPU_FDI_Port;
procedure Off (Port : GPU_FDI_Port; OT : Off_Type);
end HW.GFX.GMA.Connectors.FDI;

View File

@ -0,0 +1,184 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
-- Copyright (C) 2016 Nico Huber <nico.h@gmx.de>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Panel;
with HW.GFX.GMA.Connectors.EDP;
with HW.GFX.GMA.Connectors.FDI;
with HW.GFX.GMA.PCH.VGA;
with HW.GFX.GMA.PCH.LVDS;
with HW.GFX.GMA.PCH.HDMI;
with HW.GFX.GMA.PCH.DP;
with HW.GFX.GMA.PCH.Transcoder;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.Connectors
is
function Is_Internal (Port_Cfg : Port_Config) return Boolean
is
begin
return
Port_Cfg.Port = DIGI_A or
(Port_Cfg.Is_FDI and Port_Cfg.PCH_Port = PCH_LVDS);
end Is_Internal;
----------------------------------------------------------------------------
procedure Pre_On
(Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Pipe_Hint : in Word32;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Port = DIGI_A then
EDP.Pre_On (Port_Cfg, Pipe_Hint);
elsif Port_Cfg.Port in FDI.GPU_FDI_Port then
FDI.Pre_On (Port_Cfg);
end if;
Success := True;
end Pre_On;
procedure Post_On
(Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Port = DIGI_A then
EDP.Pre_Training;
Success := True;
elsif Port_Cfg.Port in FDI.GPU_FDI_Port then
declare
FDI_Port : constant PCH.FDI_Port_Type :=
FDI.PCH_FDIs (Port_Cfg.Port);
begin
FDI.Post_On (Port_Cfg, Success);
if Success then
PCH.Transcoder.On (Port_Cfg, FDI_Port, PLL_Hint);
if Port_Cfg.PCH_Port = PCH_DAC then
PCH.VGA.On (FDI_Port, Port_Cfg.Mode);
elsif Port_Cfg.PCH_Port = PCH_LVDS then
PCH.LVDS.On (Port_Cfg, FDI_Port);
elsif Port_Cfg.PCH_Port in PCH_HDMI_Port then
PCH.HDMI.On (Port_Cfg, FDI_Port);
elsif Port_Cfg.PCH_Port in PCH_DP_Port then
PCH.DP.On (Port_Cfg, Success);
end if;
end if;
end;
else
Success := False;
end if;
if Success and Is_Internal (Port_Cfg) then
Panel.On;
end if;
if Port_Cfg.Port = DIGI_A then
EDP.Post_On (Port_Cfg.DP, Success);
end if;
if Success and Is_Internal (Port_Cfg) then
Panel.Backlight_On;
end if;
end Post_On;
----------------------------------------------------------------------------
procedure Pre_Off (Port_Cfg : Port_Config)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Is_Internal (Port_Cfg) then
Panel.Backlight_Off;
Panel.Off;
end if;
end Pre_Off;
procedure Post_Off (Port_Cfg : Port_Config)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Port = DIGI_A then
EDP.Off (Port_Cfg.Port);
elsif Port_Cfg.Port in FDI.GPU_FDI_Port then
declare
FDI_Port : constant PCH.FDI_Port_Type :=
FDI.PCH_FDIs (Port_Cfg.Port);
begin
if Port_Cfg.PCH_Port in PCH_DP_Port then
PCH.DP.Off (Port_Cfg.PCH_Port);
end if;
FDI.Off (Port_Cfg.Port, FDI.Link_Off);
if Port_Cfg.PCH_Port = PCH_DAC then
PCH.VGA.Off;
elsif Port_Cfg.PCH_Port = PCH_LVDS then
PCH.LVDS.Off;
elsif Port_Cfg.PCH_Port in PCH_HDMI_Port then
PCH.HDMI.Off (Port_Cfg.PCH_Port);
end if;
PCH.Transcoder.Off (FDI_Port);
FDI.Off (Port_Cfg.Port, FDI.Clock_Off);
end;
end if;
end Post_Off;
----------------------------------------------------------------------------
procedure Pre_All_Off
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Panel.Backlight_Off;
Panel.Off;
end Pre_All_Off;
procedure Post_All_Off
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
EDP.Off (DIGI_A);
for Port in FDI.GPU_FDI_Port loop
FDI.Off (Port, FDI.Link_Off);
end loop;
PCH.VGA.Off;
PCH.LVDS.Off;
PCH.HDMI.All_Off;
PCH.DP.All_Off;
for Port in PCH.FDI_Port_Type loop
PCH.Transcoder.Off (Port);
end loop;
for Port in FDI.GPU_FDI_Port loop
FDI.Off (Port, FDI.Clock_Off);
end loop;
end Post_All_Off;
end HW.GFX.GMA.Connectors;

View File

@ -0,0 +1,205 @@
--
-- Copyright (C) 2016 Nico Huber <nico.h@gmx.de>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.DP_Training;
with HW.GFX.GMA.DP_Aux_Ch;
with HW.GFX.GMA.DP_Info;
with HW.GFX.GMA.Registers;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.PCH.DP is
type DP_Array is array (PCH_DP_Port) of Registers.Registers_Index;
DP_CTL : constant DP_Array :=
(PCH_DP_B => Registers.PCH_DP_B,
PCH_DP_C => Registers.PCH_DP_C,
PCH_DP_D => Registers.PCH_DP_D);
DP_CTL_DISPLAY_PORT_ENABLE : constant := 1 * 2 ** 31;
DP_CTL_VSWING_LEVEL_SET_SHIFT : constant := 25;
DP_CTL_VSWING_LEVEL_SET_MASK : constant := 7 * 2 ** 25;
DP_CTL_PREEMPH_LEVEL_SET_SHIFT : constant := 22;
DP_CTL_PREEMPH_LEVEL_SET_MASK : constant := 7 * 2 ** 22;
DP_CTL_PORT_WIDTH_SHIFT : constant := 19;
DP_CTL_PORT_REVERSAL : constant := 1 * 2 ** 15;
DP_CTL_LINK_TRAIN_MASK : constant := 7 * 2 ** 8;
DP_CTL_LINK_TRAIN_PAT1 : constant := 0 * 2 ** 8;
DP_CTL_LINK_TRAIN_PAT2 : constant := 1 * 2 ** 8;
DP_CTL_LINK_TRAIN_IDLE : constant := 2 * 2 ** 8;
DP_CTL_LINK_TRAIN_NORMAL : constant := 3 * 2 ** 8;
DP_CTL_AUDIO_OUTPUT_ENABLE : constant := 1 * 2 ** 6;
DP_CTL_PORT_DETECT : constant := 1 * 2 ** 2;
function DP_CTL_VSWING_LEVEL_SET
(VS : DP_Info.DP_Voltage_Swing)
return Word32
is
begin
return Shift_Left
(Word32 (DP_Info.DP_Voltage_Swing'Pos (VS)),
DP_CTL_VSWING_LEVEL_SET_SHIFT);
end DP_CTL_VSWING_LEVEL_SET;
function DP_CTL_PREEMPH_LEVEL_SET (PE : DP_Info.DP_Pre_Emph) return Word32
is
begin
return Shift_Left
(Word32 (DP_Info.DP_Pre_Emph'Pos (PE)), DP_CTL_PREEMPH_LEVEL_SET_SHIFT);
end DP_CTL_PREEMPH_LEVEL_SET;
function DP_CTL_PORT_WIDTH (Lane_Count : DP_Lane_Count) return Word32
is
begin
return Shift_Left
(Word32 (Lane_Count_As_Integer (Lane_Count)) - 1,
DP_CTL_PORT_WIDTH_SHIFT);
end DP_CTL_PORT_WIDTH;
type DP_CTL_LINK_TRAIN_Array is array (DP_Info.Training_Pattern) of Word32;
DP_CTL_LINK_TRAIN : constant DP_CTL_LINK_TRAIN_Array :=
(DP_Info.TP_1 => DP_CTL_LINK_TRAIN_PAT1,
DP_Info.TP_2 => DP_CTL_LINK_TRAIN_PAT2,
DP_Info.TP_3 => DP_CTL_LINK_TRAIN_PAT2,
DP_Info.TP_Idle => DP_CTL_LINK_TRAIN_IDLE,
DP_Info.TP_None => DP_CTL_LINK_TRAIN_NORMAL);
----------------------------------------------------------------------------
pragma Warnings (GNATprove, Off, "unused variable ""Port""",
Reason => "Needed for a common interface");
function Max_V_Swing
(Port : PCH_DP_Port)
return DP_Info.DP_Voltage_Swing
is
begin
return DP_Info.VS_Level_3;
end Max_V_Swing;
function Max_Pre_Emph
(Port : PCH_DP_Port;
Train_Set : DP_Info.Train_Set)
return DP_Info.DP_Pre_Emph
is
begin
return
(case Train_Set.Voltage_Swing is
when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
when DP_Info.VS_Level_3 => DP_Info.Emph_Level_0);
end Max_Pre_Emph;
----------------------------------------------------------------------------
pragma Warnings (GNATprove, Off, "unused variable ""Link""",
Reason => "Needed for a common interface");
procedure Set_Training_Pattern
(Port : PCH_DP_Port;
Link : DP_Link;
Pattern : DP_Info.Training_Pattern)
is
begin
Registers.Unset_And_Set_Mask
(Register => DP_CTL (Port),
Mask_Unset => DP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_CTL_LINK_TRAIN (Pattern));
end Set_Training_Pattern;
procedure Set_Signal_Levels
(Port : PCH_DP_Port;
Link : DP_Link;
Train_Set : DP_Info.Train_Set)
is
begin
Registers.Unset_And_Set_Mask
(Register => DP_CTL (Port),
Mask_Unset => DP_CTL_VSWING_LEVEL_SET_MASK or
DP_CTL_PREEMPH_LEVEL_SET_MASK,
Mask_Set => DP_CTL_VSWING_LEVEL_SET (Train_Set.Voltage_Swing) or
DP_CTL_PREEMPH_LEVEL_SET (Train_Set.Pre_Emph));
end Set_Signal_Levels;
procedure Off (Port : PCH_DP_Port)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_And_Set_Mask
(Register => DP_CTL (Port),
Mask_Unset => DP_CTL_LINK_TRAIN_MASK,
Mask_Set => DP_CTL_LINK_TRAIN_IDLE);
Registers.Posting_Read (DP_CTL (Port));
Registers.Write (DP_CTL (Port), 0);
Registers.Posting_Read (DP_CTL (Port));
end Off;
pragma Warnings (GNATprove, On, "unused variable ""Port""");
pragma Warnings (GNATprove, On, "unused variable ""Link""");
----------------------------------------------------------------------------
procedure On
(Port_Cfg : in Port_Config;
Success : out Boolean)
is
function To_DP (Port : PCH_DP_Port) return DP_Port
is
begin
return
(case Port is
when PCH_DP_B => DP_B,
when PCH_DP_C => DP_C,
when PCH_DP_D => DP_D);
end To_DP;
package Training is new DP_Training
(TPS3_Supported => False,
T => PCH_DP_Port,
Aux_T => DP_Port,
Aux_Ch => DP_Aux_Ch,
DP_Info => DP_Info,
To_Aux => To_DP,
Max_V_Swing => Max_V_Swing,
Max_Pre_Emph => Max_Pre_Emph,
Set_Pattern => Set_Training_Pattern,
Set_Signal_Levels => Set_Signal_Levels,
Off => Off);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Write
(Register => DP_CTL (Port_Cfg.PCH_Port),
Value => DP_CTL_DISPLAY_PORT_ENABLE or
DP_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count) or
DP_CTL_LINK_TRAIN_PAT1);
Training.Train_DP
(Port => Port_Cfg.PCH_Port,
Link => Port_Cfg.DP,
Success => Success);
end On;
----------------------------------------------------------------------------
procedure All_Off
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
for Port in PCH_DP_Port loop
Off (Port);
end loop;
end All_Off;
end HW.GFX.GMA.PCH.DP;

View File

@ -0,0 +1,26 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.GMA.PCH.DP
is
procedure On
(Port_Cfg : in Port_Config;
Success : out Boolean)
with
Pre => Port_Cfg.PCH_Port in PCH_DP_Port;
procedure Off (Port : PCH_DP_Port);
procedure All_Off;
end HW.GFX.GMA.PCH.DP;

View File

@ -0,0 +1,94 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Registers;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.PCH.HDMI
is
PCH_HDMI_ENABLE : constant := 1 * 2 ** 31;
PCH_HDMI_COLOR_FORMAT_8BPC : constant := 0 * 2 ** 26;
PCH_HDMI_COLOR_FORMAT_12BPC : constant := 3 * 2 ** 26;
PCH_HDMI_COLOR_FORMAT_MASK : constant := 7 * 2 ** 26;
PCH_HDMI_SDVO_ENCODING_SDVO : constant := 0 * 2 ** 10;
PCH_HDMI_SDVO_ENCODING_HDMI : constant := 2 * 2 ** 10;
PCH_HDMI_SDVO_ENCODING_MASK : constant := 3 * 2 ** 10;
PCH_HDMI_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4;
PCH_HDMI_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3;
PCH_HDMI_PORT_DETECT : constant := 1 * 2 ** 2;
PCH_HDMI_MASK : constant Word32 :=
PCH_TRANSCODER_SELECT_MASK or
PCH_HDMI_ENABLE or
PCH_HDMI_COLOR_FORMAT_MASK or
PCH_HDMI_SDVO_ENCODING_MASK or
PCH_HDMI_HSYNC_ACTIVE_HIGH or
PCH_HDMI_VSYNC_ACTIVE_HIGH;
type PCH_HDMI_Array is array (PCH_HDMI_Port) of Registers.Registers_Index;
PCH_HDMI : constant PCH_HDMI_Array := PCH_HDMI_Array'
(PCH_HDMI_B => Registers.PCH_HDMIB,
PCH_HDMI_C => Registers.PCH_HDMIC,
PCH_HDMI_D => Registers.PCH_HDMID);
----------------------------------------------------------------------------
procedure On (Port_Cfg : Port_Config; FDI_Port : FDI_Port_Type)
is
Polarity : constant Word32 :=
(if Port_Cfg.Mode.H_Sync_Active_High then
PCH_HDMI_HSYNC_ACTIVE_HIGH else 0) or
(if Port_Cfg.Mode.V_Sync_Active_High then
PCH_HDMI_VSYNC_ACTIVE_HIGH else 0);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
-- registers are just sufficient for setup with DVI adaptor
Registers.Unset_And_Set_Mask
(Register => PCH_HDMI (Port_Cfg.PCH_Port),
Mask_Unset => PCH_HDMI_MASK,
Mask_Set => PCH_HDMI_ENABLE or
PCH_TRANSCODER_SELECT (FDI_Port) or
PCH_HDMI_SDVO_ENCODING_HDMI or
Polarity);
end On;
----------------------------------------------------------------------------
procedure Off (Port : PCH_HDMI_Port)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_And_Set_Mask
(Register => PCH_HDMI (Port),
Mask_Unset => PCH_HDMI_MASK,
Mask_Set => PCH_HDMI_HSYNC_ACTIVE_HIGH or
PCH_HDMI_VSYNC_ACTIVE_HIGH);
end Off;
procedure All_Off
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
for Port in PCH_HDMI_Port loop
Off (Port);
end loop;
end All_Off;
end HW.GFX.GMA.PCH.HDMI;

View File

@ -0,0 +1,24 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.GMA.PCH.HDMI
is
procedure On (Port_Cfg : Port_Config; FDI_Port : FDI_Port_Type)
with
Pre => Port_Cfg.PCH_Port in PCH_HDMI_Port;
procedure Off (Port : PCH_HDMI_Port);
procedure All_Off;
end HW.GFX.GMA.PCH.HDMI;

View File

@ -0,0 +1,58 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.PCH.LVDS is
PCH_LVDS_ENABLE : constant := 1 * 2 ** 31;
PCH_LVDS_TWO_CHANNEL : constant := 15 * 2 ** 2;
PCH_LVDS_MASK : constant Word32 :=
PCH_TRANSCODER_SELECT_MASK or
PCH_LVDS_ENABLE or
PCH_LVDS_TWO_CHANNEL;
----------------------------------------------------------------------------
procedure On (Port_Cfg : Port_Config; FDI_Port : FDI_Port_Type)
is
Two_Channel : constant Word32 :=
(if Port_Cfg.Mode.Dotclock >= Config.LVDS_Dual_Threshold then
PCH_LVDS_TWO_CHANNEL else 0);
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_And_Set_Mask
(Register => Registers.PCH_LVDS,
Mask_Unset => PCH_LVDS_MASK,
Mask_Set => PCH_LVDS_ENABLE or
PCH_TRANSCODER_SELECT (FDI_Port) or
Two_Channel);
end On;
----------------------------------------------------------------------------
procedure Off
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Unset_Mask (Registers.PCH_LVDS, PCH_LVDS_ENABLE);
end Off;
end HW.GFX.GMA.PCH.LVDS;

View File

@ -0,0 +1,21 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.GMA.PCH.LVDS
is
procedure On (Port_Cfg : Port_Config; FDI_Port : FDI_Port_Type);
procedure Off;
end HW.GFX.GMA.PCH.LVDS;

View File

@ -0,0 +1,570 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.PLLs
with
Refined_State => (State => PLLs)
is
Debug_Clocks : constant Boolean := False;
type Count_Range is new Natural range 0 .. 2;
type PLL_State is record
Use_Count : Count_Range;
Used_For_DP : Boolean;
Link_Rate : DP_Bandwidth;
Mode : Mode_Type;
end record;
type PLL_State_Array is array (DPLLs) of PLL_State;
PLLs : PLL_State_Array;
----------------------------------------------------------------------------
subtype N_Range is Int64 range 3 .. 8;
subtype M_Range is Int64 range 79 .. 128;
subtype M1_Range is Int64 range 14 .. 25;
subtype M2_Range is Int64 range 7 .. 12;
subtype P_Range is Int64 range 5 .. 112;
subtype P1_Range is Int64 range 1 .. 8;
subtype P2_Range is Int64 range 5 .. 14;
subtype VCO_Range is Int64 range 1760000000 .. 3510000000;
subtype Clock_Range is HW.GFX.Frequency_Type;
type Clock_Type is
record
N : N_Range;
M1 : M1_Range;
M2 : M2_Range;
P1 : P1_Range;
P2 : P2_Range;
M : M_Range;
P : P_Range;
VCO : VCO_Range;
Reference_Clock : Clock_Range;
Dotclock : Clock_Range;
end record;
Invalid_Clock : constant Clock_Type := Clock_Type'
(N => N_Range'Last,
M1 => M1_Range'Last,
M2 => M2_Range'Last,
P1 => P1_Range'Last,
P2 => P2_Range'Last,
Reference_Clock => Clock_Range'Last,
M => M_Range'Last,
P => P_Range'Last,
VCO => VCO_Range'Last,
Dotclock => Clock_Range'Last);
type Limits_Type is
record
N_Lower : N_Range;
N_Upper : N_Range;
M_Lower : M_Range;
M_Upper : M_Range;
M1_Lower : M1_Range;
M1_Upper : M1_Range;
M2_Lower : M2_Range;
M2_Upper : M2_Range;
P_Lower : P_Range;
P_Upper : P_Range;
P1_Lower : P1_Range;
P1_Upper : P1_Range;
P2_Fast : P2_Range;
P2_Slow : P2_Range;
P2_Threshold : Clock_Range;
VCO_Lower : VCO_Range;
VCO_Upper : VCO_Range;
end record;
LVDS_Single_Limits : constant Limits_Type := Limits_Type'
(N_Lower => 3, N_Upper => 5,
M_Lower => 79, M_Upper => 118,
M1_Lower => 14, M1_Upper => 22, -- this is capped by M_Upper >= 5 * M1 + M2_Lower
M2_Lower => 7, M2_Upper => 11,
P_Lower => 28, P_Upper => 112,
P1_Lower => 2, P1_Upper => 8,
P2_Fast => 14, P2_Slow => 14,
P2_Threshold => Clock_Range'First,
VCO_Lower => 1_760_000_000, VCO_Upper => 3_510_000_000);
LVDS_Dual_Limits : constant Limits_Type := Limits_Type'
(N_Lower => 3, N_Upper => 5,
M_Lower => 79, M_Upper => 127,
M1_Lower => 14, M1_Upper => 24,
M2_Lower => 7, M2_Upper => 11,
P_Lower => 14, P_Upper => 56,
P1_Lower => 2, P1_Upper => 8,
P2_Fast => 7, P2_Slow => 7,
P2_Threshold => Clock_Range'First,
VCO_Lower => 1_760_000_000, VCO_Upper => 3_510_000_000);
All_Other_Limits : constant Limits_Type := Limits_Type'
(N_Lower => 3, N_Upper => 7,
M_Lower => 79, M_Upper => 127,
M1_Lower => 14, M1_Upper => 24,
M2_Lower => 7, M2_Upper => 11,
P_Lower => 5, P_Upper => 80,
P1_Lower => 1, P1_Upper => 8,
-- use P2_Slow if Dotclock <= P2_Threshold, P2_Fast otherwise
P2_Fast => 5, P2_Slow => 10,
P2_Threshold => 225_000_000,
VCO_Lower => 1_760_000_000, VCO_Upper => 3_510_000_000);
----------------------------------------------------------------------------
type Regs is array (DPLLs) of Registers.Registers_Index;
DPLL : constant Regs := Regs'(Registers.PCH_DPLL_A, Registers.PCH_DPLL_B);
DPLL_VCO_ENABLE : constant := 1 * 2 ** 31;
DPLL_P2_10_OR_14 : constant := 0 * 2 ** 24;
DPLL_P2_5_OR_7 : constant := 1 * 2 ** 24;
DPLL_P1_DIVIDER_SHIFT : constant := 16;
DPLL_SDVOCLK : constant := 2 * 2 ** 13;
DPLL_HIGH_SPEED : constant := 1 * 2 ** 30;
DPLL_MODE_LVDS : constant := 2 * 2 ** 26;
DPLL_MODE_DAC : constant := 1 * 2 ** 26;
DPLL_DREFCLK : constant := 0 * 2 ** 13;
DPLL_SSC : constant := 3 * 2 ** 13;
MODE_DPLL_DAC_HDMI : constant Word32 := Word32'
(DPLL_MODE_DAC or DPLL_DREFCLK or DPLL_HIGH_SPEED);
MODE_DPLL_LVDS : constant Word32 := Word32'
(DPLL_MODE_LVDS or DPLL_SSC);
MODE_DPLL_DP : constant Word32 := Word32'
(DPLL_MODE_DAC or DPLL_SSC or DPLL_HIGH_SPEED);
type DPLL_Mode_Array is array (Display_Type) of Word32;
DPLL_Mode : constant DPLL_Mode_Array := DPLL_Mode_Array'
(LVDS => MODE_DPLL_LVDS,
DP => MODE_DPLL_DP,
others => MODE_DPLL_DAC_HDMI);
FP0 : constant Regs := Regs'(Registers.PCH_FPA0, Registers.PCH_FPB0);
FP1 : constant Regs := Regs'(Registers.PCH_FPA1, Registers.PCH_FPB1);
FP_DOUBLE_CLOCK : constant := 1 * 2 ** 27;
FP_N_SHIFT : constant := 16;
FP_M1_SHIFT : constant := 8;
FP_M2_SHIFT : constant := 0;
----------------------------------------------------------------------------
procedure Verify_Parameters
(N : in N_Range;
M1 : in M1_Range;
M2 : in M2_Range;
P1 : in P1_Range;
P2 : in P2_Range;
Reference_Clock : in Clock_Range;
Current_Limits : in Limits_Type;
Result : out Clock_Type;
Valid : out Boolean)
with
Global => null,
Pre => True,
Post => True
is
M : Int64;
P : Int64;
VCO : Int64;
Dotclock : Int64;
begin
pragma Debug (Debug_Clocks, Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
M := 5 * M1 + M2;
P := P1 * P2;
VCO := (Int64 (Reference_Clock) * M) / N;
Dotclock := VCO / P;
pragma Debug (Debug_Clocks and not (Current_Limits.P1_Lower <= P1 and P1 <= Current_Limits.P1_Upper ), Debug.Put_Line ("P1 out of range."));
pragma Debug (Debug_Clocks and (Current_Limits.P2_Fast /= P2 and P2 /= Current_Limits.P2_Slow ), Debug.Put_Line ("P2 out of range."));
pragma Debug (Debug_Clocks and not (Current_Limits.P_Lower <= P and P <= Current_Limits.P_Upper ), Debug.Put_Line ("P out of range."));
pragma Debug (Debug_Clocks and not (Current_Limits.M1_Lower <= M1 and M1 <= Current_Limits.M1_Upper ), Debug.Put_Line ("M1 out of range."));
pragma Debug (Debug_Clocks and not (Current_Limits.M2_Lower <= M2 and M2 <= Current_Limits.M2_Upper ), Debug.Put_Line ("M2 out of range."));
-- pragma Debug (Debug_Clocks and not (M2 <= M1 ), Debug.Put_Line ("M1 greater thant M2."));
pragma Debug (Debug_Clocks and not (Current_Limits.N_Lower <= N and N <= Current_Limits.N_Upper ), Debug.Put_Line ("N out of range."));
pragma Debug (Debug_Clocks and not (Current_Limits.M_Lower <= M and M <= Current_Limits.M_Upper ), Debug.Put_Line ("M out of range."));
pragma Debug (Debug_Clocks and not (Current_Limits.VCO_Lower <= VCO and VCO <= Current_Limits.VCO_Upper), Debug.Put_Line ("VCO out of range."));
pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.Put_Line ("Dotclock too low."));
pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.Put_Int64 (Dotclock));
pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.New_Line);
pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.Put_Line ("Dotclock too high."));
pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.Put_Int64 (Dotclock));
pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.New_Line);
Valid :=
Current_Limits.P1_Lower <= P1 and P1 <= Current_Limits.P1_Upper and
(Current_Limits.P2_Fast = P2 or P2 = Current_Limits.P2_Slow) and
Current_Limits.P_Lower <= P and P <= Current_Limits.P_Upper and
Current_Limits.M1_Lower <= M1 and M1 <= Current_Limits.M1_Upper and
Current_Limits.M2_Lower <= M2 and M2 <= Current_Limits.M2_Upper and
-- M2 <= M1 and
Current_Limits.N_Lower <= N and N <= Current_Limits.N_Upper and
Current_Limits.M_Lower <= M and M <= Current_Limits.M_Upper and
Current_Limits.VCO_Lower <= VCO and VCO <= Current_Limits.VCO_Upper and
Int64 (Clock_Range'First) <= Dotclock and
Dotclock <= Int64 (Clock_Range'Last);
if Valid
then
Result := Clock_Type'
(N => N,
M1 => M1,
M2 => M2,
P1 => P1,
P2 => P2,
Reference_Clock => Reference_Clock,
M => M,
P => P,
VCO => VCO,
Dotclock => Clock_Range (Dotclock));
else
Result := Invalid_Clock;
end if;
end Verify_Parameters;
procedure Calculate_Clock_Parameters
(Display : in Display_Type;
Target_Dotclock : in Clock_Range;
Reference_Clock : in Clock_Range;
Best_Clock : out Clock_Type;
Valid : out Boolean)
with
Global => null,
Pre => True,
Post => True
is
Limits : constant Limits_Type :=
(if Display = LVDS then
(if Target_Dotclock >= Config.LVDS_Dual_Threshold then
LVDS_Dual_Limits
else
LVDS_Single_Limits)
else
All_Other_Limits);
P2 : P2_Range;
Best_Delta : Int64 := Int64'Last;
Current_Delta : Int64;
Current_Clock : Clock_Type;
Registers_Valid : Boolean;
begin
pragma Debug (Debug_Clocks, Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Valid := False;
Best_Clock := Invalid_Clock;
if Target_Dotclock <= Limits.P2_Threshold then
P2 := Limits.P2_Slow;
else
P2 := Limits.P2_Fast;
end if;
for N in N_Range range Limits.N_Lower .. Limits.N_Upper
loop
-- reverse loops as hardware prefers higher values
for M1 in reverse M1_Range range Limits.M1_Lower .. Limits.M1_Upper
loop
for M2 in reverse M2_Range range Limits.M2_Lower .. Limits.M2_Upper
loop
for P1 in reverse P1_Range range Limits.P1_Lower .. Limits.P1_Upper
loop
Verify_Parameters
(N => N,
M1 => M1,
M2 => M2,
P1 => P1,
P2 => P2,
Reference_Clock => Reference_Clock,
Current_Limits => Limits,
Result => Current_Clock,
Valid => Registers_Valid);
if Registers_Valid
then
if Current_Clock.Dotclock > Target_Dotclock
then
Current_Delta := Current_Clock.Dotclock - Target_Dotclock;
else
Current_Delta := Target_Dotclock - Current_Clock.Dotclock;
end if;
if Current_Delta < Best_Delta
then
Best_Delta := Current_Delta;
Best_Clock := Current_Clock;
Valid := True;
end if;
pragma Debug (Debug_Clocks, Debug.Put ("Current/Target/Best_Delta: "));
pragma Debug (Debug_Clocks, Debug.Put_Int64 (Current_Clock.Dotclock));
pragma Debug (Debug_Clocks, Debug.Put ("/"));
pragma Debug (Debug_Clocks, Debug.Put_Int64 (Target_Dotclock));
pragma Debug (Debug_Clocks, Debug.Put ("/"));
pragma Debug (Debug_Clocks, Debug.Put_Int64 (Best_Delta));
pragma Debug (Debug_Clocks, Debug.Put_Line ("."));
end if;
end loop;
end loop;
end loop;
end loop;
pragma Debug (Valid, Debug.Put_Line ("Valid clock found."));
pragma Debug (Valid, Debug.Put ("Best/Target/Delta: "));
pragma Debug (Valid, Debug.Put_Int64 (Best_Clock.Dotclock));
pragma Debug (Valid, Debug.Put ("/"));
pragma Debug (Valid, Debug.Put_Int64 (Target_Dotclock));
pragma Debug (Valid, Debug.Put ("/"));
pragma Debug (Valid, Debug.Put_Int64 (Best_Delta));
pragma Debug (Valid, Debug.Put_Line ("."));
pragma Debug (not Valid, Debug.Put_Line ("No valid clock found."));
end Calculate_Clock_Parameters;
procedure Program_DPLL
(PLL : DPLLs;
Display : Display_Type;
Clk : Clock_Type)
with
Global => (In_Out => Registers.Register_State),
Pre => True,
Post => True
is
FP, Encoded_P1, Encoded_P2 : Word32;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
FP :=
Shift_Left (Word32 (Clk.N - 2), FP_N_SHIFT) or
Shift_Left (Word32 (Clk.M1 - 2), FP_M1_SHIFT) or
Shift_Left (Word32 (Clk.M2 - 2), FP_M2_SHIFT);
Registers.Write (FP0 (PLL), FP);
Registers.Write (FP1 (PLL), FP);
Encoded_P1 := Shift_Left (1, Natural (Clk.P1) - 1);
if Clk.P2 = 5 or Clk.P2 = 7
then
Encoded_P2 := DPLL_P2_5_OR_7;
else
Encoded_P2 := DPLL_P2_10_OR_14;
end if;
Registers.Write
(Register => DPLL (PLL),
Value => DPLL_Mode (Display) or
Encoded_P2 or
Shift_Left (Encoded_P1, DPLL_P1_DIVIDER_SHIFT) or
Encoded_P1);
end Program_DPLL;
procedure On
(PLL : in T;
Port_Cfg : in Port_Config;
Success : out Boolean)
is
Target_Clock : constant Frequency_Type :=
(if Port_Cfg.Display = DP then
DP_Symbol_Rate (Port_Cfg.DP.Bandwidth)
else
Port_Cfg.Mode.Dotclock);
Clk : Clock_Type;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Success := PLL in DPLLs;
Clk := Invalid_Clock;
if Success then
if Port_Cfg.Display = DP then
Success := True;
-- we use static values for DP
case Port_Cfg.DP.Bandwidth is
when DP_Bandwidth_1_62 =>
Clk.N := 3;
Clk.M1 := 14;
Clk.M2 := 11;
Clk.P1 := 2;
Clk.P2 := 10;
when DP_Bandwidth_2_7 =>
Clk.N := 4;
Clk.M1 := 16;
Clk.M2 := 10;
Clk.P1 := 1;
Clk.P2 := 10;
when others =>
Success := False;
end case;
elsif Target_Clock <= 340_000_000 then
Calculate_Clock_Parameters
(Display => Port_Cfg.Display,
Target_Dotclock => Target_Clock,
-- should be, but doesn't has to be always the same:
Reference_Clock => 120_000_000,
Best_Clock => Clk,
Valid => Success);
else
Success := False;
pragma Debug (Debug.Put ("WARNING: Targeted clock too high: "));
pragma Debug (Debug.Put_Int64 (Target_Clock));
pragma Debug (Debug.Put (" > "));
pragma Debug (Debug.Put_Int32 (340_000_000));
pragma Debug (Debug.New_Line);
pragma Debug (Debug.New_Line);
end if;
end if;
if Success then
Program_DPLL (PLL, Port_Cfg.Display, Clk);
Registers.Set_Mask (DPLL (PLL), DPLL_VCO_ENABLE);
Registers.Posting_Read (DPLL (PLL));
Time.U_Delay (150);
end if;
end On;
procedure Off (PLL : T)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if PLL in DPLLs then
Registers.Unset_Mask (DPLL (PLL), DPLL_VCO_ENABLE);
end if;
end Off;
----------------------------------------------------------------------------
procedure Initialize
is
begin
PLLs :=
(DPLLs =>
(Use_Count => 0,
Used_For_DP => False,
Link_Rate => DP_Bandwidth'First,
Mode => Invalid_Mode));
end Initialize;
procedure Alloc_Configurable
(Port_Cfg : in Port_Config;
PLL : out T;
Success : out Boolean)
with
Pre => True
is
function Config_Matches (PE : PLL_State) return Boolean
is
begin
return
PE.Used_For_DP = (Port_Cfg.Display = DP) and
((PE.Used_For_DP and PE.Link_Rate = Port_Cfg.DP.Bandwidth) or
(not PE.Used_For_DP and PE.Mode = Port_Cfg.Mode));
end Config_Matches;
begin
-- try to find shareable PLL
for P in DPLLs loop
Success := PLLs (P).Use_Count /= 0 and
PLLs (P).Use_Count /= Count_Range'Last and
Config_Matches (PLLs (P));
if Success then
PLL := P;
PLLs (PLL).Use_Count := PLLs (PLL).Use_Count + 1;
return;
end if;
end loop;
-- try to find free PLL
for P in DPLLs loop
if PLLs (P).Use_Count = 0 then
PLL := P;
On (PLL, Port_Cfg, Success);
if Success then
PLLs (PLL) :=
(Use_Count => 1,
Used_For_DP => Port_Cfg.Display = DP,
Link_Rate => Port_Cfg.DP.Bandwidth,
Mode => Port_Cfg.Mode);
end if;
return;
end if;
end loop;
PLL := Invalid;
end Alloc_Configurable;
procedure Alloc
(Port_Cfg : in Port_Config;
PLL : out T;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Port = DIGI_A then
PLL := Invalid;
Success := True;
else
Alloc_Configurable (Port_Cfg, PLL, Success);
end if;
end Alloc;
procedure Free (PLL : T)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if PLL in DPLLs then
if PLLs (PLL).Use_Count /= 0 then
PLLs (PLL).Use_Count := PLLs (PLL).Use_Count - 1;
if PLLs (PLL).Use_Count = 0 then
Off (PLL);
end if;
end if;
end if;
end Free;
procedure All_Off
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
for PLL in DPLLs loop
Off (PLL);
end loop;
end All_Off;
function Register_Value (PLL : T) return Word32
is
begin
return (if PLL = DPLL_B then 1 else 0);
end Register_Value;
end HW.GFX.GMA.PLLs;

View File

@ -0,0 +1,39 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.PLLs
with
Abstract_State => (State with Part_Of => GMA.State)
is
-- XXX: Types should be private (but that triggers a bug in SPARK GPL 2016)
type T is (Invalid_PLL, DPLL_A, DPLL_B);
subtype DPLLs is T range DPLL_A .. DPLL_B;
Invalid : constant T := Invalid_PLL;
procedure Initialize
with
Global => (Output => State);
procedure Alloc
(Port_Cfg : in Port_Config;
PLL : out T;
Success : out Boolean);
procedure Free (PLL : T);
procedure All_Off;
function Register_Value (PLL : T) return Word32;
end HW.GFX.GMA.PLLs;

View File

@ -0,0 +1,160 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.Port_Detect
is
PCH_ADPA_CRT_HPD_CHANNEL_MASK : constant := 3 * 2 ** 24;
PCH_ADPA_CRT_HPD_ENABLE : constant := 1 * 2 ** 23;
DP_PORT_DETECTED : constant := 1 * 2 ** 2;
PCH_DIGI_PORT_DETECTED : constant := 1 * 2 ** 2;
PCH_LVDS_PORT_DETECTED : constant := 1 * 2 ** 1;
SHOTPLUG_CTL_DETECT_MASK : constant := 16#0003_0303#;
type PCH_Digital_Port_Value is array (PCH_HDMI_Port) of Word32;
SHOTPLUG_CTL_HPD_INPUT_ENABLE : constant PCH_Digital_Port_Value :=
(PCH_HDMI_B => 1 * 2 ** 4,
PCH_HDMI_C => 1 * 2 ** 12,
PCH_HDMI_D => 1 * 2 ** 20);
SHOTPLUG_CTL_SHORT_PULSE_MASK : constant PCH_Digital_Port_Value :=
(PCH_HDMI_B => 3 * 2 ** 2,
PCH_HDMI_C => 3 * 2 ** 10,
PCH_HDMI_D => 3 * 2 ** 18);
SHOTPLUG_CTL_HPD_STATUS : constant PCH_Digital_Port_Value :=
(PCH_HDMI_B => 3 * 2 ** 0,
PCH_HDMI_C => 3 * 2 ** 8,
PCH_HDMI_D => 3 * 2 ** 16);
SHOTPLUG_CTL_LONG_DETECT : constant PCH_Digital_Port_Value :=
(PCH_HDMI_B => 1 * 2 ** 1,
PCH_HDMI_C => 1 * 2 ** 9,
PCH_HDMI_D => 1 * 2 ** 17);
type PCH_Digital_Regs is array (PCH_HDMI_Port) of Registers.Registers_Index;
PCH_HDMI : constant PCH_Digital_Regs :=
(PCH_HDMI_B => Registers.PCH_HDMIB,
PCH_HDMI_C => Registers.PCH_HDMIC,
PCH_HDMI_D => Registers.PCH_HDMID);
PCH_DP : constant PCH_Digital_Regs :=
(PCH_HDMI_B => Registers.PCH_DP_B,
PCH_HDMI_C => Registers.PCH_DP_C,
PCH_HDMI_D => Registers.PCH_DP_D);
procedure Initialize
is
Internal_Detected,
HDMI_Detected,
DP_Detected : Boolean;
type PCH_Port_To_GMA_Port is array (PCH_HDMI_Port) of Port_Type;
To_Digital_Port : constant PCH_Port_To_GMA_Port :=
(PCH_HDMI_B => Digital1,
PCH_HDMI_C => Digital2,
PCH_HDMI_D => Digital3);
To_DP_Port : constant PCH_Port_To_GMA_Port :=
(PCH_HDMI_B => DP1,
PCH_HDMI_C => DP2,
PCH_HDMI_D => DP3);
begin
-- PCH_DAC (_A)
Registers.Set_Mask
(Register => Registers.PCH_ADPA,
Mask => PCH_ADPA_CRT_HPD_CHANNEL_MASK or -- clear status
PCH_ADPA_CRT_HPD_ENABLE);
case Config.Internal_Display is
when LVDS =>
-- PCH_LVDS
Registers.Is_Set_Mask
(Register => Registers.PCH_LVDS,
Mask => PCH_LVDS_PORT_DETECTED,
Result => Internal_Detected);
when DP =>
-- eDP
Registers.Is_Set_Mask
(Register => Registers.DP_CTL_A,
Mask => DP_PORT_DETECTED,
Result => Internal_Detected);
when None =>
Internal_Detected := False;
end case;
Config.Valid_Port (Internal) := Internal_Detected;
-- PCH_HDMI_[BCD], PCH_DP_[BCD] share hotplug registers
for PCH_Port in PCH_HDMI_Port loop
Registers.Is_Set_Mask
(Register => PCH_HDMI (PCH_Port),
Mask => PCH_DIGI_PORT_DETECTED,
Result => HDMI_Detected);
Config.Valid_Port (To_Digital_Port (PCH_Port)) := HDMI_Detected;
Registers.Is_Set_Mask
(Register => PCH_DP (PCH_Port),
Mask => PCH_DIGI_PORT_DETECTED,
Result => DP_Detected);
Config.Valid_Port (To_DP_Port (PCH_Port)) := DP_Detected;
if HDMI_Detected or DP_Detected then
Registers.Unset_And_Set_Mask
(Register => Registers.SHOTPLUG_CTL,
Mask_Unset => SHOTPLUG_CTL_DETECT_MASK or
SHOTPLUG_CTL_SHORT_PULSE_MASK (PCH_Port),
Mask_Set => SHOTPLUG_CTL_HPD_INPUT_ENABLE (PCH_Port) or
SHOTPLUG_CTL_HPD_STATUS (PCH_Port)); -- clear
else
Registers.Unset_Mask
(Register => Registers.SHOTPLUG_CTL,
Mask => SHOTPLUG_CTL_DETECT_MASK or
SHOTPLUG_CTL_HPD_INPUT_ENABLE (PCH_Port));
end if;
end loop;
end Initialize;
procedure Hotplug_Detect (Port_Cfg : in Port_Config; Detected : out Boolean)
is
Ctl32 : Word32;
PCH_Port : constant GMA.PCH_Port :=
(case Port_Cfg.PCH_Port is
when PCH_DP_B => PCH_HDMI_B,
when PCH_DP_C => PCH_HDMI_C,
when PCH_DP_D => PCH_HDMI_D,
when others => Port_Cfg.PCH_Port);
begin
case PCH_Port is
when PCH_DAC =>
Registers.Read (Registers.PCH_ADPA, Ctl32, Verbose => False);
Ctl32 := Ctl32 and PCH_ADPA_CRT_HPD_CHANNEL_MASK;
Detected := Ctl32 = PCH_ADPA_CRT_HPD_CHANNEL_MASK;
if Ctl32 /= 0 then
Registers.Set_Mask (Registers.PCH_ADPA, Ctl32);
end if;
when PCH_HDMI_B .. PCH_HDMI_D =>
Registers.Read (Registers.SHOTPLUG_CTL, Ctl32, Verbose => False);
Detected := (Ctl32 and SHOTPLUG_CTL_LONG_DETECT (PCH_Port)) /= 0;
if (Ctl32 and SHOTPLUG_CTL_HPD_STATUS (PCH_Port)) /= 0 then
Registers.Unset_And_Set_Mask
(Register => Registers.SHOTPLUG_CTL,
Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
Mask_Set => SHOTPLUG_CTL_HPD_STATUS (PCH_Port));
end if;
when others =>
Detected := False;
end case;
end Hotplug_Detect;
end HW.GFX.GMA.Port_Detect;

View File

@ -0,0 +1,17 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Power_And_Clocks_Ironlake;
private package HW.GFX.GMA.Power_And_Clocks
renames HW.GFX.GMA.Power_And_Clocks_Ironlake;

View File

@ -0,0 +1,54 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.Time;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.Power_And_Clocks_Ironlake is
PCH_DREF_CONTROL_120MHZ_CPU_OUTPUT_MASK : constant := 3 * 2 ** 13;
PCH_DREF_CONTROL_120MHZ_CPU_OUTPUT_SSC : constant := 2 * 2 ** 13;
PCH_DREF_CONTROL_120MHZ_CPU_OUTPUT_NONSSC : constant := 3 * 2 ** 13;
PCH_DREF_CONTROL_120MHZ_SSC_EN_MASK : constant := 3 * 2 ** 11;
PCH_DREF_CONTROL_120MHZ_SSC_EN : constant := 2 * 2 ** 11;
PCH_DREF_CONTROL_120MHZ_NONSSC_EN_MASK : constant := 3 * 2 ** 9;
PCH_DREF_CONTROL_120MHZ_NONSSC_EN : constant := 2 * 2 ** 9;
PCH_DREF_CONTROL_120MHZ_SSC4_EN_MASK : constant := 3 * 2 ** 7;
PCH_DREF_CONTROL_120MHZ_SSC4_EN : constant := 2 * 2 ** 7;
PCH_DREF_CONTROL_120MHZ_SSC4_DOWNSPREAD : constant := 0 * 2 ** 6;
PCH_DREF_CONTROL_120MHZ_SSC4_CENTERSPREAD : constant := 1 * 2 ** 6;
PCH_DREF_CONTROL_120MHZ_SSC_MODULATION_EN : constant := 1 * 2 ** 1;
PCH_DREF_CONTROL_120MHZ_SSC4_MODULATION_EN : constant := 1 * 2 ** 0;
procedure Initialize is
begin
-- ILK: enable non-spread spectrum clock, enable spread spectrum clock
Registers.Write
(Register => Registers.PCH_DREF_CONTROL,
Value => PCH_DREF_CONTROL_120MHZ_SSC_EN or
PCH_DREF_CONTROL_120MHZ_NONSSC_EN or
PCH_DREF_CONTROL_120MHZ_SSC_MODULATION_EN);
Registers.Posting_Read (Registers.PCH_DREF_CONTROL);
Time.U_Delay (1);
if Config.Internal_Is_EDP then -- TODO: check for presence
-- always use spread spectrum clock for CPU output
Registers.Set_Mask
(Register => Registers.PCH_DREF_CONTROL,
Mask => PCH_DREF_CONTROL_120MHZ_CPU_OUTPUT_SSC);
Registers.Posting_Read (Registers.PCH_DREF_CONTROL);
Time.U_Delay (20); -- DMI latency
end if;
end Initialize;
end HW.GFX.GMA.Power_And_Clocks_Ironlake;

View File

@ -0,0 +1,29 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.Power_And_Clocks_Ironlake is
procedure Initialize;
procedure Pre_All_Off is null;
procedure Post_All_Off is null;
procedure Power_Set_To (Configs : Configs_Type) is null;
procedure Power_Up (Old_Configs, New_Configs : Configs_Type) is null;
procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type)
is null;
end HW.GFX.GMA.Power_And_Clocks_Ironlake;

View File

@ -0,0 +1,10 @@
gfxinit-y += hw-gfx-gma-plls-dpll.adb
gfxinit-y += hw-gfx-gma-plls-dpll.ads
gfxinit-y += hw-gfx-gma-plls-dpll_0.adb
gfxinit-y += hw-gfx-gma-plls-dpll_0.ads
gfxinit-y += hw-gfx-gma-plls.adb
gfxinit-y += hw-gfx-gma-plls.ads
gfxinit-y += hw-gfx-gma-power_and_clocks.ads
gfxinit-y += hw-gfx-gma-power_and_clocks_skylake.adb
gfxinit-y += hw-gfx-gma-power_and_clocks_skylake.ads
gfxinit-y += hw-gfx-gma-spll.ads

View File

@ -0,0 +1,357 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.PLLs.DPLL is
-- NOTE: Order of DPLLs is twisted => always use named associations!
type Regs is array (Configurable_DPLLs) of Registers.Registers_Index;
DPLL_CTL : constant Regs := Regs'
(DPLL1 => Registers.LCPLL2_CTL,
DPLL2 => Registers.WRPLL_CTL_1,
DPLL3 => Registers.WRPLL_CTL_2);
DPLL_CTL_PLL_ENABLE : constant := 1 * 2 ** 31;
----------------------------------------------------------------------------
DPLL_CFGR1 : constant Regs := Regs'
(DPLL1 => Registers.DPLL1_CFGR1,
DPLL2 => Registers.DPLL2_CFGR1,
DPLL3 => Registers.DPLL3_CFGR1);
DPLL_CFGR1_FREQUENCY_ENABLE : constant := 1 * 2 ** 31;
DPLL_CFGR1_DCO_FRACTION_SHIFT : constant := 9;
DPLL_CFGR1_DCO_FRACTION_MASK : constant := 16#7fff# * 2 ** 9;
DPLL_CFGR1_DCO_INTEGER_MASK : constant := 16#01ff# * 2 ** 0;
DPLL_CFGR2 : constant Regs := Regs'
(DPLL1 => Registers.DPLL1_CFGR2,
DPLL2 => Registers.DPLL2_CFGR2,
DPLL3 => Registers.DPLL3_CFGR2);
DPLL_CFGR2_QDIV_RATIO_SHIFT : constant := 8;
DPLL_CFGR2_QDIV_RATIO_MASK : constant := 255 * 2 ** 8;
DPLL_CFGR2_QDIV_MODE : constant := 1 * 2 ** 7;
DPLL_CFGR2_KDIV_SHIFT : constant := 5;
DPLL_CFGR2_KDIV_MASK : constant := 3 * 2 ** 5;
DPLL_CFGR2_PDIV_SHIFT : constant := 2;
DPLL_CFGR2_PDIV_MASK : constant := 7 * 2 ** 2;
DPLL_CFGR2_CENTRAL_FREQ_MASK : constant := 3 * 2 ** 0;
DPLL_CFGR2_CENTRAL_FREQ_9600MHZ : constant := 0 * 2 ** 0;
DPLL_CFGR2_CENTRAL_FREQ_9000MHZ : constant := 1 * 2 ** 0;
DPLL_CFGR2_CENTRAL_FREQ_8400MHZ : constant := 3 * 2 ** 0;
----------------------------------------------------------------------------
HDMI_MODE : constant := 1 * 2 ** 5;
SSC : constant := 1 * 2 ** 4;
LINK_RATE_MASK : constant := 7 * 2 ** 1;
LINK_RATE_2700MHZ : constant := 0 * 2 ** 1;
LINK_RATE_1350MHZ : constant := 1 * 2 ** 1;
LINK_RATE_810MHZ : constant := 2 * 2 ** 1;
LINK_RATE_1620MHZ : constant := 3 * 2 ** 1;
LINK_RATE_1080MHZ : constant := 4 * 2 ** 1;
LINK_RATE_2160MHZ : constant := 5 * 2 ** 1;
OVERRIDE : constant := 1 * 2 ** 0;
LOCK : constant := 1 * 2 ** 0;
type Shifts is array (Configurable_DPLLs) of Natural;
DPLL_CTRL1_SHIFT : constant Shifts :=
(DPLL1 => 6, DPLL2 => 12, DPLL3 => 18);
DPLL_STATUS_SHIFT : constant Shifts :=
(DPLL1 => 8, DPLL2 => 16, DPLL3 => 24);
function LINK_RATE (Link_Rate : DP_Bandwidth) return Word32 is
begin
return (case Link_Rate is
when DP_Bandwidth_5_4 => LINK_RATE_2700MHZ,
when DP_Bandwidth_2_7 => LINK_RATE_1350MHZ,
when DP_Bandwidth_1_62 => LINK_RATE_810MHZ);
end LINK_RATE;
function DPLL_CTRL1_DPLLx
(Value : Word32;
PLL : Configurable_DPLLs)
return Word32 is
begin
return Shift_Left (Value, DPLL_CTRL1_SHIFT (PLL));
end DPLL_CTRL1_DPLLx;
function DPLL_STATUS_DPLLx_LOCK (PLL : Configurable_DPLLs) return Word32 is
begin
return Shift_Left (LOCK, DPLL_STATUS_SHIFT (PLL));
end DPLL_STATUS_DPLLx_LOCK;
----------------------------------------------------------------------------
subtype PDiv_Range is Pos64 range 1 .. 7;
subtype QDiv_Range is Pos64 range 1 .. 255;
subtype KDiv_Range is Pos64 range 1 .. 5;
type Central_Frequency is (CF_INVALID, CF_9600MHZ, CF_9000MHZ, CF_8400MHZ);
subtype Valid_Central_Freq is
Central_Frequency range CF_9600MHZ .. CF_8400MHZ;
type CF_Pos is array (Valid_Central_Freq) of Pos64;
CF_Pos64 : constant CF_Pos := CF_Pos'
(CF_9600MHZ => 9_600_000_000,
CF_9000MHZ => 9_000_000_000,
CF_8400MHZ => 8_400_000_000);
subtype DCO_Frequency is
Pos64 range 1 .. CF_Pos64 (CF_9600MHZ) + CF_Pos64 (CF_9600MHZ) / 100;
function DPLL_CFGR1_DCO_FRACTION (DCO_Freq : DCO_Frequency) return Word32
with
Pre => True
is
begin
return Shift_Left
(Word32 ((DCO_Freq * 2 ** 15) / 24_000_000) and 16#7fff#,
DPLL_CFGR1_DCO_FRACTION_SHIFT);
end DPLL_CFGR1_DCO_FRACTION;
function DPLL_CFGR1_DCO_INTEGER (DCO_Freq : DCO_Frequency) return Word32
with
Pre => True
is
begin
return Word32 (DCO_Freq / 24_000_000);
end DPLL_CFGR1_DCO_INTEGER;
function DPLL_CFGR2_PDIV (PDiv : PDiv_Range) return Word32 is
begin
return Shift_Left
((case PDiv is
when 1 => 0,
when 2 => 1,
when 3 => 2,
when 7 => 4,
when others => 4),
DPLL_CFGR2_PDIV_SHIFT);
end DPLL_CFGR2_PDIV;
function DPLL_CFGR2_QDIV (QDiv : QDiv_Range) return Word32 is
begin
return Shift_Left (Word32 (QDiv), DPLL_CFGR2_QDIV_RATIO_SHIFT) or
(if QDiv /= 1 then DPLL_CFGR2_QDIV_MODE else 0);
end DPLL_CFGR2_QDIV;
function DPLL_CFGR2_KDIV (KDiv : KDiv_Range) return Word32 is
begin
return Shift_Left
((case KDiv is
when 5 => 0,
when 2 => 1,
when 3 => 2,
when 1 => 3,
when others => 0),
DPLL_CFGR2_KDIV_SHIFT);
end DPLL_CFGR2_KDIV;
function DPLL_CFGR2_CENTRAL_FREQ (CF : Valid_Central_Freq) return Word32 is
begin
return (case CF is
when CF_9600MHZ => DPLL_CFGR2_CENTRAL_FREQ_9600MHZ,
when CF_9000MHZ => DPLL_CFGR2_CENTRAL_FREQ_9000MHZ,
when CF_8400MHZ => DPLL_CFGR2_CENTRAL_FREQ_8400MHZ);
end DPLL_CFGR2_CENTRAL_FREQ;
----------------------------------------------------------------------------
procedure Calculate_DPLL
(Dotclock : in Frequency_Type;
Central_Freq : out Central_Frequency;
DCO_Freq : out DCO_Frequency;
PDiv : out PDiv_Range;
QDiv : out QDiv_Range;
KDiv : out KDiv_Range)
with
Pre => True
is
Max_Pos_Deviation : constant := 1;
Max_Neg_Deviation : constant := 6;
subtype Div_Range is Pos64 range 1 .. 98;
subtype Candidate_Index is Positive range 1 .. 36;
type Candidate_Array is array (Candidate_Index) of Div_Range;
type Candidate_List is record
Divs : Candidate_Array;
Count : Candidate_Index;
end record;
type Parity_Type is (Even, Odd);
type Candidates_Type is array (Parity_Type) of Candidate_List;
Candidates : constant Candidates_Type := Candidates_Type'
(Even => Candidate_List'
(Divs => Candidate_Array'
(4, 6, 8, 10, 12, 14, 16, 18, 20, 24, 28, 30, 32, 36, 40, 42, 44,
48, 52, 54, 56, 60, 64, 66, 68, 70, 72, 76, 78, 80, 84, 88, 90,
92, 96, 98),
Count => 36),
Odd => Candidate_List'
(Divs => Candidate_Array'(3, 5, 7, 9, 15, 21, 35, others => 1),
Count => 7));
Temp_Freq,
Allowed_Deviation : Pos64;
Deviation : Int64;
Temp_Central : DCO_Frequency;
Min_Deviation : Int64 := Int64'Last;
Div : Div_Range := Div_Range'Last;
begin
Central_Freq := CF_INVALID;
DCO_Freq := 1;
PDiv := 1;
QDiv := 1;
KDiv := 1;
for Parity in Parity_Type loop
for CF in Valid_Central_Freq loop
Temp_Central := CF_Pos64 (CF);
for I in Candidate_Index range 1 .. Candidates (Parity).Count loop
Temp_Freq := Candidates (Parity).Divs (I) * 5 * Dotclock;
if Temp_Freq > Temp_Central then
Deviation := Temp_Freq - Temp_Central;
Allowed_Deviation := (Max_Pos_Deviation * Temp_Central) / 100;
else
Deviation := Temp_Central - Temp_Freq;
Allowed_Deviation := (Max_Neg_Deviation * Temp_Central) / 100;
end if;
if Deviation < Min_Deviation and
Deviation < Allowed_Deviation
then
Min_Deviation := Deviation;
Central_Freq := CF;
DCO_Freq := Temp_Freq;
Div := Candidates (Parity).Divs (I);
end if;
end loop;
end loop;
exit when Central_Freq /= CF_INVALID;
end loop;
if Central_Freq /= CF_INVALID then
if Div mod 2 = 0 then
pragma Assert (Div /= 1);
pragma Assert (Div > 1);
Div := Div / 2;
if Div = 1 or Div = 3 or Div = 5 then
-- 2, 6 and 10
PDiv := 2;
QDiv := 1;
KDiv := Div;
elsif Div mod 2 = 0 then
-- divisible by 4
PDiv := 2;
QDiv := Div / 2;
KDiv := 2;
elsif Div mod 3 = 0 then
-- divisible by 6
PDiv := 3;
QDiv := Div / 3;
KDiv := 2;
elsif Div mod 7 = 0 then
-- divisible by 14
PDiv := 7;
QDiv := Div / 7;
KDiv := 2;
end if;
elsif Div = 7 or Div = 21 or Div = 35 then
-- 7, 21 and 35
PDiv := 7;
QDiv := 1;
KDiv := Div / 7;
elsif Div = 3 or Div = 9 or Div = 15 then
-- 3, 9 and 15
PDiv := 3;
QDiv := 1;
KDiv := Div / 3;
elsif Div = 5 then
-- 5
PDiv := 5;
QDiv := 1;
KDiv := 1;
end if;
end if;
end Calculate_DPLL;
----------------------------------------------------------------------------
procedure On
(PLL : in Configurable_DPLLs;
Port_Cfg : in Port_Config;
Success : out Boolean)
is
Central_Freq : Central_Frequency;
DCO_Freq : DCO_Frequency;
PDiv : PDiv_Range;
QDiv : QDiv_Range;
KDiv : KDiv_Range;
begin
if Port_Cfg.Display = DP then
Registers.Unset_And_Set_Mask
(Register => Registers.DPLL_CTRL1,
Mask_Unset => DPLL_CTRL1_DPLLx (HDMI_MODE, PLL) or
DPLL_CTRL1_DPLLx (SSC, PLL) or
DPLL_CTRL1_DPLLx (LINK_RATE_MASK, PLL),
Mask_Set => DPLL_CTRL1_DPLLx (LINK_RATE
(Port_Cfg.DP.Bandwidth), PLL) or
DPLL_CTRL1_DPLLx (OVERRIDE, PLL));
Registers.Posting_Read (Registers.DPLL_CTRL1);
Success := True;
else
Calculate_DPLL
(Port_Cfg.Mode.Dotclock, Central_Freq, DCO_Freq, PDiv, QDiv, KDiv);
Success := Central_Freq /= CF_INVALID;
if Success then
Registers.Unset_And_Set_Mask
(Register => Registers.DPLL_CTRL1,
Mask_Unset => DPLL_CTRL1_DPLLx (SSC, PLL),
Mask_Set => DPLL_CTRL1_DPLLx (HDMI_MODE, PLL) or
DPLL_CTRL1_DPLLx (OVERRIDE, PLL));
Registers.Write
(Register => DPLL_CFGR1 (PLL),
Value => DPLL_CFGR1_FREQUENCY_ENABLE or
DPLL_CFGR1_DCO_FRACTION (DCO_Freq) or
DPLL_CFGR1_DCO_INTEGER (DCO_Freq));
Registers.Write
(Register => DPLL_CFGR2 (PLL),
Value => DPLL_CFGR2_QDIV (QDiv) or
DPLL_CFGR2_KDIV (KDiv) or
DPLL_CFGR2_PDIV (PDiv) or
DPLL_CFGR2_CENTRAL_FREQ (Central_Freq));
Registers.Posting_Read (Registers.DPLL_CTRL1);
Registers.Posting_Read (DPLL_CFGR1 (PLL));
Registers.Posting_Read (DPLL_CFGR2 (PLL));
end if;
end if;
if Success then
Registers.Write
(Register => DPLL_CTL (PLL),
Value => DPLL_CTL_PLL_ENABLE);
Registers.Wait_Set_Mask
(Register => Registers.DPLL_STATUS,
Mask => DPLL_STATUS_DPLLx_LOCK (PLL));
end if;
end On;
procedure Off (PLL : Configurable_DPLLs) is
begin
Registers.Unset_Mask (DPLL_CTL (PLL), DPLL_CTL_PLL_ENABLE);
end Off;
end HW.GFX.GMA.PLLs.DPLL;

View File

@ -0,0 +1,27 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.PLLs.DPLL is
type Value_Array is array (Configurable_DPLLs) of Word32;
Register_Value : constant Value_Array := Value_Array'
(DPLL1 => 1, DPLL2 => 2, DPLL3 => 3);
procedure On
(PLL : in Configurable_DPLLs;
Port_Cfg : in Port_Config;
Success : out Boolean);
procedure Off (PLL : Configurable_DPLLs);
end HW.GFX.GMA.PLLs.DPLL;

View File

@ -0,0 +1,48 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Registers;
package body HW.GFX.GMA.PLLs.DPLL_0 is
DPLL_CTRL1_DPLL0_LINK_RATE_MASK : constant := 7 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_2700MHZ : constant := 0 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_1350MHZ : constant := 1 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_810MHZ : constant := 2 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_1620MHZ : constant := 3 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_1080MHZ : constant := 4 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_2160MHZ : constant := 5 * 2 ** 1;
DPLL_CTRL1_DPLL0_OVERRIDE : constant := 1 * 2 ** 0;
procedure Check_Link_Rate
(Link_Rate : in DP_Bandwidth;
Success : out Boolean)
is
DPLL_Ctrl1 : Word32;
begin
Registers.Read (Registers.DPLL_CTRL1, DPLL_Ctrl1);
case DPLL_Ctrl1 and DPLL_CTRL1_DPLL0_LINK_RATE_MASK is
when DPLL_CTRL1_DPLL0_LINK_RATE_2700MHZ =>
Success := Link_Rate = DP_Bandwidth_5_4;
when DPLL_CTRL1_DPLL0_LINK_RATE_1350MHZ =>
Success := Link_Rate = DP_Bandwidth_2_7;
when DPLL_CTRL1_DPLL0_LINK_RATE_810MHZ =>
Success := Link_Rate = DP_Bandwidth_1_62;
when others =>
Success := False;
end case;
Success := Success and (DPLL_Ctrl1 and DPLL_CTRL1_DPLL0_OVERRIDE) /= 0;
end Check_Link_Rate;
end HW.GFX.GMA.PLLs.DPLL_0;

View File

@ -0,0 +1,22 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.PLLs.DPLL_0 is
Register_Value : constant Word32 := 0;
procedure Check_Link_Rate
(Link_Rate : in DP_Bandwidth;
Success : out Boolean);
end HW.GFX.GMA.PLLs.DPLL_0;

View File

@ -0,0 +1,151 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.PLLs.DPLL_0;
with HW.GFX.GMA.PLLs.DPLL;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.PLLs
with
Refined_State => (State => PLLs)
is
type Count_Range is new Natural range 0 .. 2;
type PLL_State is record
Use_Count : Count_Range;
Used_For_DP : Boolean;
Link_Rate : DP_Bandwidth;
Mode : Mode_Type;
end record;
type PLL_State_Array is array (Configurable_DPLLs) of PLL_State;
PLLs : PLL_State_Array;
procedure Initialize
is
begin
PLLs :=
(Configurable_DPLLs =>
(Use_Count => 0,
Used_For_DP => False,
Link_Rate => DP_Bandwidth'First,
Mode => Invalid_Mode));
end Initialize;
procedure Alloc_Configurable
(Port_Cfg : in Port_Config;
PLL : out T;
Success : out Boolean)
with
Pre => True
is
function Config_Matches (PE : PLL_State) return Boolean
is
begin
return
PE.Used_For_DP = (Port_Cfg.Display = DP) and
((PE.Used_For_DP and PE.Link_Rate = Port_Cfg.DP.Bandwidth) or
(not PE.Used_For_DP and PE.Mode = Port_Cfg.Mode));
end Config_Matches;
begin
-- try to find shareable PLL
for P in Configurable_DPLLs loop
Success := PLLs (P).Use_Count /= 0 and
PLLs (P).Use_Count /= Count_Range'Last and
Config_Matches (PLLs (P));
if Success then
PLL := P;
PLLs (PLL).Use_Count := PLLs (PLL).Use_Count + 1;
return;
end if;
end loop;
-- try to find free PLL
for P in Configurable_DPLLs loop
if PLLs (P).Use_Count = 0 then
PLL := P;
DPLL.On (PLL, Port_Cfg, Success);
if Success then
PLLs (PLL) :=
(Use_Count => 1,
Used_For_DP => Port_Cfg.Display = DP,
Link_Rate => Port_Cfg.DP.Bandwidth,
Mode => Port_Cfg.Mode);
end if;
return;
end if;
end loop;
PLL := Invalid;
end Alloc_Configurable;
procedure Alloc
(Port_Cfg : in Port_Config;
PLL : out T;
Success : out Boolean)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Port_Cfg.Port = DIGI_A then
DPLL_0.Check_Link_Rate (Port_Cfg.DP.Bandwidth, Success);
else
Success := False;
end if;
if Success then
PLL := DPLL0;
else
Alloc_Configurable (Port_Cfg, PLL, Success);
end if;
end Alloc;
procedure Free (PLL : T)
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if PLL in Configurable_DPLLs then
if PLLs (PLL).Use_Count /= 0 then
PLLs (PLL).Use_Count := PLLs (PLL).Use_Count - 1;
if PLLs (PLL).Use_Count = 0 then
DPLL.Off (PLL);
end if;
end if;
end if;
end Free;
procedure All_Off
is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
for PLL in Configurable_DPLLs loop
DPLL.Off (PLL);
end loop;
end All_Off;
function Register_Value (PLL : T) return Word32
is
begin
return
(if PLL = DPLL0 then DPLL_0.Register_Value
elsif PLL in Configurable_DPLLs then DPLL.Register_Value (PLL)
else 0);
end Register_Value;
end HW.GFX.GMA.PLLs;

View File

@ -0,0 +1,42 @@
--
-- Copyright (C) 2015-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.PLLs
with
Abstract_State => (State with Part_Of => GMA.State)
is
-- NOTE: Order of DPLLs is twisted, as DPLL2 (WRPLL1)
-- should be selected as last choice.
-- XXX: Types should be private (but that triggers a bug in SPARK GPL 2016)
type T is (Invalid_PLL, DPLL0, DPLL1, DPLL3, DPLL2);
subtype Configurable_DPLLs is T range DPLL1 .. DPLL2;
Invalid : constant T := Invalid_PLL;
procedure Initialize
with
Global => (Output => State);
procedure Alloc
(Port_Cfg : in Port_Config;
PLL : out T;
Success : out Boolean);
procedure Free (PLL : T);
procedure All_Off;
function Register_Value (PLL : T) return Word32;
end HW.GFX.GMA.PLLs;

View File

@ -0,0 +1,17 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with HW.GFX.GMA.Power_And_Clocks_Skylake;
private package HW.GFX.GMA.Power_And_Clocks
renames HW.GFX.GMA.Power_And_Clocks_Skylake;

View File

@ -0,0 +1,351 @@
--
-- Copyright (C) 2014-2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with GNAT.Source_Info;
with HW.Time;
with HW.Debug;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
with HW.GFX.GMA.Power_And_Clocks_Haswell;
use type HW.Word64;
package body HW.GFX.GMA.Power_And_Clocks_Skylake is
type Power_Domain is (MISC_IO, PW1, PW2, DDI_AE, DDI_B, DDI_C, DDI_D);
subtype Power_Well is Power_Domain range PW1 .. PW2;
subtype Dynamic_Domain is Power_Domain range PW2 .. DDI_D;
NDE_RSTWRN_OPT_RST_PCH_Handshake_En : constant := 1 * 2 ** 4;
FUSE_STATUS_DOWNLOAD_STATUS : constant := 1 * 2 ** 31;
FUSE_STATUS_PG0_DIST_STATUS : constant := 1 * 2 ** 27;
type Power_Domain_Values is array (Power_Domain) of Word32;
PWR_WELL_CTL_POWER_REQUEST : constant Power_Domain_Values :=
(MISC_IO => 1 * 2 ** 1,
DDI_AE => 1 * 2 ** 3,
DDI_B => 1 * 2 ** 5,
DDI_C => 1 * 2 ** 7,
DDI_D => 1 * 2 ** 9,
PW1 => 1 * 2 ** 29,
PW2 => 1 * 2 ** 31);
PWR_WELL_CTL_POWER_STATE : constant Power_Domain_Values :=
(MISC_IO => 1 * 2 ** 0,
DDI_AE => 1 * 2 ** 2,
DDI_B => 1 * 2 ** 4,
DDI_C => 1 * 2 ** 6,
DDI_D => 1 * 2 ** 8,
PW1 => 1 * 2 ** 28,
PW2 => 1 * 2 ** 30);
type Power_Well_Values is array (Power_Well) of Word32;
FUSE_STATUS_PGx_DIST_STATUS : constant Power_Well_Values :=
(PW1 => 1 * 2 ** 26,
PW2 => 1 * 2 ** 25);
DBUF_CTL_DBUF_POWER_REQUEST : constant := 1 * 2 ** 31;
DBUF_CTL_DBUF_POWER_STATE : constant := 1 * 2 ** 30;
----------------------------------------------------------------------------
DPLL_CTRL1_DPLL0_LINK_RATE_MASK : constant := 7 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_2700MHZ : constant := 0 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_1350MHZ : constant := 1 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_810MHZ : constant := 2 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_1620MHZ : constant := 3 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_1080MHZ : constant := 4 * 2 ** 1;
DPLL_CTRL1_DPLL0_LINK_RATE_2160MHZ : constant := 5 * 2 ** 1;
DPLL_CTRL1_DPLL0_OVERRIDE : constant := 1 * 2 ** 0;
LCPLL1_CTL_PLL_ENABLE : constant := 1 * 2 ** 31;
LCPLL1_CTL_PLL_LOCK : constant := 1 * 2 ** 30;
----------------------------------------------------------------------------
CDCLK_CTL_CD_FREQ_SELECT_MASK : constant := 3 * 2 ** 26;
CDCLK_CTL_CD_FREQ_SELECT_450MHZ : constant := 0 * 2 ** 26;
CDCLK_CTL_CD_FREQ_SELECT_540MHZ : constant := 1 * 2 ** 26;
CDCLK_CTL_CD_FREQ_SELECT_337_5MHZ : constant := 2 * 2 ** 26;
CDCLK_CTL_CD_FREQ_SELECT_675MHZ : constant := 3 * 2 ** 26;
CDCLK_CTL_CD_FREQ_DECIMAL_MASK : constant := 16#7ff#;
SKL_PCODE_CDCLK_CONTROL : constant := 7;
SKL_CDCLK_PREPARE_FOR_CHANGE : constant := 3;
SKL_CDCLK_READY_FOR_CHANGE : constant := 1;
GT_MAILBOX_READY : constant := 1 * 2 ** 31;
function CDCLK_CTL_CD_FREQ_DECIMAL
(Freq : Positive;
Plus_Half : Boolean)
return Word32 is
begin
return Word32 (2 * (Freq - 1)) or (if Plus_Half then 1 else 0);
end CDCLK_CTL_CD_FREQ_DECIMAL;
----------------------------------------------------------------------------
procedure GT_Mailbox_Write (MBox : Word32; Value : Word64) is
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
Registers.Write
(Registers.GT_MAILBOX_DATA, Word32 (Value and 16#ffff_ffff#));
Registers.Write
(Registers.GT_MAILBOX_DATA_1, Word32 (Shift_Right (Value, 32)));
Registers.Write (Registers.GT_MAILBOX, GT_MAILBOX_READY or MBox);
Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
end GT_Mailbox_Write;
----------------------------------------------------------------------------
procedure PD_Off (PD : Power_Domain)
is
Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); -- Result for debugging only
pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); -- Result for debugging only
if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
PWR_WELL_CTL_POWER_REQUEST (PD)) /= 0
then
Registers.Wait_Set_Mask
(Register => Registers.PWR_WELL_CTL_DRIVER,
Mask => PWR_WELL_CTL_POWER_STATE (PD));
end if;
if (Ctl1 and PWR_WELL_CTL_POWER_REQUEST (PD)) /= 0 then
Registers.Unset_Mask
(Register => Registers.PWR_WELL_CTL_BIOS,
Mask => PWR_WELL_CTL_POWER_REQUEST (PD));
end if;
if (Ctl2 and PWR_WELL_CTL_POWER_REQUEST (PD)) /= 0 then
Registers.Unset_Mask
(Register => Registers.PWR_WELL_CTL_DRIVER,
Mask => PWR_WELL_CTL_POWER_REQUEST (PD));
end if;
end PD_Off;
procedure PD_On (PD : Power_Domain)
with
Pre => True
is
Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); -- Result for debugging only
pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); -- Result for debugging only
if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
PWR_WELL_CTL_POWER_REQUEST (PD)) = 0
then
Registers.Wait_Unset_Mask
(Register => Registers.PWR_WELL_CTL_DRIVER,
Mask => PWR_WELL_CTL_POWER_STATE (PD));
end if;
if (Ctl2 and PWR_WELL_CTL_POWER_REQUEST (PD)) = 0 then
Registers.Set_Mask
(Register => Registers.PWR_WELL_CTL_DRIVER,
Mask => PWR_WELL_CTL_POWER_REQUEST (PD));
Registers.Wait_Set_Mask
(Register => Registers.PWR_WELL_CTL_DRIVER,
Mask => PWR_WELL_CTL_POWER_STATE (PD));
if PD in Power_Well then
Registers.Wait_Set_Mask
(Register => Registers.FUSE_STATUS,
Mask => FUSE_STATUS_PGx_DIST_STATUS (PD));
end if;
end if;
end PD_On;
function Need_PD (PD : Dynamic_Domain; Configs : Configs_Type) return Boolean
is
begin
return (case PD is
when DDI_AE => Configs (Primary).Port = Internal or
Configs (Secondary).Port = Internal or
Configs (Tertiary).Port = Internal,
when DDI_B => Configs (Primary).Port = Digital1 or
Configs (Primary).Port = DP1 or
Configs (Secondary).Port = Digital1 or
Configs (Secondary).Port = DP1 or
Configs (Tertiary).Port = Digital1 or
Configs (Tertiary).Port = DP1,
when DDI_C => Configs (Primary).Port = Digital2 or
Configs (Primary).Port = DP2 or
Configs (Secondary).Port = Digital2 or
Configs (Secondary).Port = DP2 or
Configs (Tertiary).Port = Digital2 or
Configs (Tertiary).Port = DP2,
when DDI_D => Configs (Primary).Port = Digital3 or
Configs (Primary).Port = DP3 or
Configs (Secondary).Port = Digital3 or
Configs (Secondary).Port = DP3 or
Configs (Tertiary).Port = Digital3 or
Configs (Tertiary).Port = DP3,
when PW2 => (Configs (Primary).Port /= Disabled and
Configs (Primary).Port /= Internal) or
Configs (Secondary).Port /= Disabled or
Configs (Tertiary).Port /= Disabled);
end Need_PD;
----------------------------------------------------------------------------
procedure Pre_All_Off is
begin
Power_And_Clocks_Haswell.PSR_Off;
end Pre_All_Off;
procedure Post_All_Off is
begin
for PD in reverse Dynamic_Domain loop
PD_Off (PD);
end loop;
Registers.Unset_Mask
(Register => Registers.DBUF_CTL,
Mask => DBUF_CTL_DBUF_POWER_REQUEST);
Registers.Wait_Unset_Mask
(Register => Registers.DBUF_CTL,
Mask => DBUF_CTL_DBUF_POWER_STATE);
Registers.Unset_Mask
(Register => Registers.LCPLL1_CTL,
Mask => LCPLL1_CTL_PLL_ENABLE);
Registers.Wait_Unset_Mask
(Register => Registers.LCPLL1_CTL,
Mask => LCPLL1_CTL_PLL_LOCK);
PD_Off (MISC_IO);
PD_Off (PW1);
end Post_All_Off;
procedure Initialize
is
CDClk_Change_Timeout : Time.T;
Timed_Out : Boolean;
MBox_Data0 : Word32;
begin
Registers.Set_Mask
(Register => Registers.NDE_RSTWRN_OPT,
Mask => NDE_RSTWRN_OPT_RST_PCH_Handshake_En);
Registers.Wait_Set_Mask
(Register => Registers.FUSE_STATUS,
Mask => FUSE_STATUS_PG0_DIST_STATUS);
PD_On (PW1);
PD_On (MISC_IO);
Registers.Write
(Register => Registers.CDCLK_CTL,
Value => CDCLK_CTL_CD_FREQ_SELECT_337_5MHZ or
CDCLK_CTL_CD_FREQ_DECIMAL (337, True));
-- TODO: Set to preferred eDP rate:
-- Registers.Unset_And_Set_Mask
-- (Register => Registers.DPLL_CTRL1,
-- Unset_Mask => DPLL_CTRL1_DPLL0_LINK_RATE_MASK,
-- Set_Mask => DPLL_CTRL1_DPLL0_LINK_RATE_...);
Registers.Set_Mask
(Register => Registers.LCPLL1_CTL,
Mask => LCPLL1_CTL_PLL_ENABLE);
Registers.Wait_Set_Mask
(Register => Registers.LCPLL1_CTL,
Mask => LCPLL1_CTL_PLL_LOCK);
CDClk_Change_Timeout := Time.MS_From_Now (3);
loop
GT_Mailbox_Write
(MBox => SKL_PCODE_CDCLK_CONTROL,
Value => SKL_CDCLK_PREPARE_FOR_CHANGE);
Timed_Out := Time.Timed_Out (CDClk_Change_Timeout);
Registers.Read (Registers.GT_MAILBOX_DATA, MBox_Data0);
if (MBox_Data0 and SKL_CDCLK_READY_FOR_CHANGE) =
SKL_CDCLK_READY_FOR_CHANGE
then
Timed_Out := False;
exit;
end if;
exit when Timed_Out;
end loop;
if not Timed_Out then
GT_Mailbox_Write
(MBox => SKL_PCODE_CDCLK_CONTROL,
Value => 16#0000_0000#); -- 0 - 337.5MHz
-- 1 - 450.0MHz
-- 2 - 540.0MHz
-- 3 - 675.0MHz
Registers.Set_Mask
(Register => Registers.DBUF_CTL,
Mask => DBUF_CTL_DBUF_POWER_REQUEST);
Registers.Wait_Set_Mask
(Register => Registers.DBUF_CTL,
Mask => DBUF_CTL_DBUF_POWER_STATE);
end if;
end Initialize;
procedure Power_Set_To (Configs : Configs_Type) is
begin
for PD in reverse Dynamic_Domain loop
if not Need_PD (PD, Configs) then
PD_Off (PD);
end if;
end loop;
for PD in Dynamic_Domain loop
if Need_PD (PD, Configs) then
PD_On (PD);
end if;
end loop;
end Power_Set_To;
procedure Power_Up (Old_Configs, New_Configs : Configs_Type) is
begin
for PD in Dynamic_Domain loop
if not Need_PD (PD, Old_Configs) and Need_PD (PD, New_Configs) then
PD_On (PD);
end if;
end loop;
end Power_Up;
procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type)
is
begin
for PD in reverse Dynamic_Domain loop
if (Need_PD (PD, Old_Configs) or Need_PD (PD, Tmp_Configs)) and
not Need_PD (PD, New_Configs)
then
PD_Off (PD);
end if;
end loop;
end Power_Down;
end HW.GFX.GMA.Power_And_Clocks_Skylake;

View File

@ -0,0 +1,25 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
private package HW.GFX.GMA.Power_And_Clocks_Skylake is
procedure Pre_All_Off;
procedure Post_All_Off;
procedure Initialize;
procedure Power_Set_To (Configs : Configs_Type);
procedure Power_Up (Old_Configs, New_Configs : Configs_Type);
procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type);
end HW.GFX.GMA.Power_And_Clocks_Skylake;

View File

@ -0,0 +1,23 @@
--
-- Copyright (C) 2016 secunet Security Networks AG
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.GFX.GMA.SPLL is
-- Just for a common interface with Haswell's DDI.
-- There is no SPLL (no FDI) on Skylake.
procedure On is null;
procedure Off is null;
end HW.GFX.GMA.SPLL;

4
configs/broadwell Normal file
View File

@ -0,0 +1,4 @@
CONFIG_GFX_GMA_CPU = Broadwell
CONFIG_GFX_GMA_CPU_VARIANT = Normal
CONFIG_GFX_GMA_INTERNAL_PORT = DP
CONFIG_GFX_GMA_DEFAULT_MMIO = 16#e000_0000#

4
configs/broadwell_ult Normal file
View File

@ -0,0 +1,4 @@
CONFIG_GFX_GMA_CPU = Broadwell
CONFIG_GFX_GMA_CPU_VARIANT = ULT
CONFIG_GFX_GMA_INTERNAL_PORT = DP
CONFIG_GFX_GMA_DEFAULT_MMIO = 16#e000_0000#

4
configs/haswell Normal file
View File

@ -0,0 +1,4 @@
CONFIG_GFX_GMA_CPU = Haswell
CONFIG_GFX_GMA_CPU_VARIANT = Normal
CONFIG_GFX_GMA_INTERNAL_PORT = DP
CONFIG_GFX_GMA_DEFAULT_MMIO = 16#e000_0000#

4
configs/haswell_ult Normal file
View File

@ -0,0 +1,4 @@
CONFIG_GFX_GMA_CPU = Haswell
CONFIG_GFX_GMA_CPU_VARIANT = ULT
CONFIG_GFX_GMA_INTERNAL_PORT = DP
CONFIG_GFX_GMA_DEFAULT_MMIO = 16#e000_0000#

4
configs/ironlake Normal file
View File

@ -0,0 +1,4 @@
CONFIG_GFX_GMA_CPU = Ironlake
CONFIG_GFX_GMA_CPU_VARIANT = Normal
CONFIG_GFX_GMA_INTERNAL_PORT = LVDS
CONFIG_GFX_GMA_DEFAULT_MMIO = 16#e000_0000#

4
configs/ivybridge_edp Normal file
View File

@ -0,0 +1,4 @@
CONFIG_GFX_GMA_CPU = Ivybridge
CONFIG_GFX_GMA_CPU_VARIANT = Normal
CONFIG_GFX_GMA_INTERNAL_PORT = DP
CONFIG_GFX_GMA_DEFAULT_MMIO = 16#e000_0000#

4
configs/ivybridge_lvds Normal file
View File

@ -0,0 +1,4 @@
CONFIG_GFX_GMA_CPU = Ivybridge
CONFIG_GFX_GMA_CPU_VARIANT = Normal
CONFIG_GFX_GMA_INTERNAL_PORT = LVDS
CONFIG_GFX_GMA_DEFAULT_MMIO = 16#e000_0000#

4
configs/sandybridge Normal file
View File

@ -0,0 +1,4 @@
CONFIG_GFX_GMA_CPU = Sandybridge
CONFIG_GFX_GMA_CPU_VARIANT = Normal
CONFIG_GFX_GMA_INTERNAL_PORT = LVDS
CONFIG_GFX_GMA_DEFAULT_MMIO = 16#e000_0000#

Some files were not shown because too many files have changed in this diff Show More