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:
commit
83693c8d7d
|
@ -0,0 +1,5 @@
|
|||
/proof-allconfigs/
|
||||
/build/
|
||||
/dest/
|
||||
/*.gpr
|
||||
/.config
|
|
@ -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.
|
|
@ -0,0 +1,6 @@
|
|||
name := gfxinit
|
||||
|
||||
gfxinit-deplibs := libhw
|
||||
|
||||
libhw-dir ?= ../libhwbase/dest
|
||||
include $(libhw-dir)/Makefile
|
|
@ -0,0 +1 @@
|
|||
subdirs-y += common
|
|
@ -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???
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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#
|
|
@ -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#
|
|
@ -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#
|
|
@ -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#
|
|
@ -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#
|
|
@ -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#
|
|
@ -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#
|
|
@ -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
Loading…
Reference in New Issue