diff --git a/Documentation/devicetree/bindings/xlnx,v-hdmi-rx-ss.txt b/Documentation/devicetree/bindings/xlnx,v-hdmi-rx-ss.txt index 07788d1..378c20b 100644 --- a/Documentation/devicetree/bindings/xlnx,v-hdmi-rx-ss.txt +++ b/Documentation/devicetree/bindings/xlnx,v-hdmi-rx-ss.txt @@ -6,13 +6,13 @@ V4L2 video-capture sub-device for the Xilinx Video IP Pipeline device (xilinx-vipp). There are 2 optional HDCP cores that can be included in the IP configuration. -Below provided sample device tree depicts the configuration when both cores are -included. If an optional core is included then corresponding entries for the +Below provided sample device tree depicts the configuration when both cores are +included. If an optional core is included then corresponding entries for the core parameters (interrupts, key-management block address) must be included in the device tree Note: If HDCP cores are included in the design, the user must provide valid - HDCP keys for the encryption to work. + HDCP keys for the encryption to work. Refer to xlnx,vphy.txt for the phy specifics. @@ -25,71 +25,92 @@ Required Properties: hdcp1x. [Optional] - interrupts-parent: phandle for interrupt controller. - interrupts: Interrupt numbers for mandatory and optional blocks - - interrupt-names: Identification string that binds irq number to block + - interrupt-names: Identification string that binds irq number to block generating the interrupt - "hdmirx": interrupt for rx subcore [always present] - "hdcp1x": interrupt for hdcp1.4 core [optional] - "hdcp1x-timer": interrupt for hdcp1.4 timer [present if hdcp1x is - included] - "hdcp22": interrupt for hdcp22 core [optional] - "hdcp22-timer": interrupt for hdcp2.2 timer [present if hdcp22 is - included] - - - clocks: phandle for axi-lite, video stream - - clock-names: The identification string, "axi-lite", is always required for - the axi-lite clock, "video" is always required for video stream - clock - - - phys: phandle for phy lanes registered for hdmi protocol. HDMI always + "irq": interrupt for tx subcore [always present] + "hdcp14_irq": interrupt for hdcp1.4 core [optional - present if hdcp1x + is included] + "hdcp14_timer_irq": interrupt for hdcp1.4 timer [optional - present if + hdcp1x is included] + "hdcp22_irq": interrupt for hdcp22 core [optional - present if hdcp22 + is included] + "hdcp22_timer_irq": interrupt for hdcp2.2 timer [optional - present if + hdcp22 is included] + + - clocks: phandle of all the clocks required by IP are listed here. + - clock-names: names of all the clocks required by IP are listed here. + NOTE: Auto generated DT is providing all the clock names and handles + reuired by the IP. + NOTE: Below are the identification string that are always required. + "s_axi_cpu_aclk", is always required for the axi-lite clock + "s_axis_video_aclk" is always required for video stream clock + + - phys: phandle for phy lanes registered for hdmi protocol. HDMI always require 3 lanes - phy-names: The identification string, "hdmi-phy0" and so on - + - xlnx,input-pixels-per-clock: IP configuration for samples/clk (2, 4) Note: Only 2 is supported at this time - - xlnx,edid-ram-size: Denotes amount of BRAM allocated for EDID in IP + - xlnx,max-bits-per-component: The data width per video component (8,10,12,16) + Note: Only 8 & 10 is supported at this time + - xlnx,edid-ram-size: Denotes amount of BRAM allocated for EDID in IP - xlnx,include-hdcp-1-4: Boolean parameter that denotes if hdcp14 is included. If present indicates inclusion of the optional core - xlnx,include-hdcp-2-2: Boolean parameter that denotes if hdcp22 is included. If present indicates inclusion of the optional core + - xlnx,audio-enabled: Boolean parameter to convey that design has audio + functionality. + If present, indicates optional audio core needed for audio + usecase is included. + - xlnx,snd-pcm: Reference to audio formatter block. Add this if, audio formatter + is going to be used for HDMI audio. + Needed only if "xlnx,audio-enabled" is included. - ports: Video ports, using the DT bindings defined in ../video-interfaces.txt. The Rx only has an output port (0). - + ==Example== If hdcp1.4 is included in the design then key management block node should be added to the device tree - hdmi_input_hdcp_keymngmt_blk_top_1: hdcp_keymngmt_blk_top@a0270000 { + hdcp_keymngmt_blk_1: hdcp_keymngmt_blk_top@88000000 { + clock-names = "s_axi_aclk", "m_axis_aclk"; + clocks = <&zynqmp_clk 71>, <&misc_clk_0>; compatible = "xlnx,hdcp-keymngmt-blk-top-1.0"; - reg = <0x0 0xa0270000 0x0 0x10000>; + reg = <0x0 0x88000000 0x0 0x10000>; }; - hdmi_input_v_hdmi_rx_ss_0: v_hdmi_rx_ss@a0000000 { + v_hdmi_rx_ss: v_hdmi_rx_ss@80000000 { compatible = "xlnx,v-hdmi-rx-ss-3.1"; reg = <0x0 0xa0000000 0x0 0x100000>, <0x0 0xa0270000 0x0 0x10000>; - reg-names = "hdmi-rxss", "hdcp1x-keymngmt"; + reg-names = "hdmi-rxss", "hdcp1x-keymngmt"; interrupt-parent = <&gic>; - interrupts = <0 91 4>, <0 108 4>, <0 109 4>, <0 110 4>, <0 111 4>; - interrupt-names = "hdmirx", "hdcp1x", "hdcp1x-timer", "hdcp22", "hdcp22-timer"; - clocks = <&vid_s_axi_clk>, <&vid_stream_clk>; - clock-names = "axi-lite", "video"; + interrupts = <0 90 4 0 104 4 0 105 4 0 108 4 0 109 4>; + interrupt-names = "irq", "hdcp14_irq", "hdcp14_timer_irq", "hdcp22_irq", "hdcp22_timer_irq"; + clock-names = "s_axi_cpu_aclk", "link_clk", "s_axis_audio_aclk", "video_clk", "s_axis_video_aclk"; + clocks = <&zynqmp_clk 71>, <&misc_clk_1>, <&zynqmp_clk 71>, <&misc_clk_2>, <&zynqmp_clk 72>; phy-names = "hdmi-phy0", "hdmi-phy1", "hdmi-phy2"; phys = <&vphy_lane0 0 1 1 0>, <&vphy_lane1 0 1 1 0>, <&vphy_lane2 0 1 1 0>; - + xlnx,input-pixels-per-clock = <0x2>; + xlnx,max-bits-per-component = <0xa>; xlnx,edid-ram-size = <0x100>; xlnx,include-hdcp-1-4; xlnx,include-hdcp-2-2; - + xlnx,audio-enabled; + xlnx,snd-pcm = <&audio_ss_0_audio_formatter_0>; ports { #address-cells = <1>; #size-cells = <0>; port@0 { reg = <0>; - + /* HDMI RX SS -> FB-WR */ hdmi_rxss_out: endpoint { remote-endpoint = <&vcap_hdmi_in>; }; }; - }; + }; }; + + Documentation of "audio_ss_0_audio_formatter_0" node is located + at Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt diff --git a/Documentation/devicetree/bindings/xlnx,v-hdmi-tx-ss.txt b/Documentation/devicetree/bindings/xlnx,v-hdmi-tx-ss.txt index f83083d..7eee5fb 100644 --- a/Documentation/devicetree/bindings/xlnx,v-hdmi-tx-ss.txt +++ b/Documentation/devicetree/bindings/xlnx,v-hdmi-tx-ss.txt @@ -5,13 +5,13 @@ a HDMI Transmitter. xilinx_drm_hdmi.c implements a DRM/KMS driver encoder/connector interface in the output pipeline. There are 2 optional HDCP cores that can be included in the IP configuration. -Below provided sample device tree depicts the configuration when both cores are -included. If an optional core is included then corresponding entries for the +Below provided sample device tree depicts the configuration when both cores are +included. If an optional core is included then corresponding entries for the core parameters (interrupts, key-management block address) must be included in the device tree Note: If HDCP cores are included in the design, the user must provide valid - HDCP keys for the encryption to work. + HDCP keys for the encryption to work. Note: This version of the driver interfaces with the new Xilinx DRM component framework and is not backward compatible with the earlier encoder-slave @@ -19,7 +19,7 @@ Note: This version of the driver interfaces with the new Xilinx DRM component new interface. Refer to xlnx,vphy.txt for the phy specifics. - + Required properties: - compatible: Should be "xlnx,v-hdmi-tx-ss-3.1". - reg: Base address and size of the IP core and hdcp1x key management block @@ -30,27 +30,35 @@ Required properties: - interrupts-parent: phandle for interrupt controller. - interrupts: Interrupt numbers for mandatory and optional blocks - - interrupt-names: Identification string that binds irq number to block + - interrupt-names: Identification string that binds irq number to block generating the interrupt - "hdmitx": interrupt for tx subcore [always present] - "hdcp1x": interrupt for hdcp1.4 core [optional] - "hdcp1x-timer": interrupt for hdcp1.4 timer [present if hdcp1x is - included] - "hdcp22": interrupt for hdcp22 core [optional] - "hdcp22-timer": interrupt for hdcp2.2 timer [present if hdcp22 is - included] - - - clocks: phandle for axi-lite, video stream, tmds and retimer clock - - clock-names: The identification string for various clock inputs - "axi-lite", is always required for the axi-lite clock - "video" is always required for video stream clock - "txref-clk" is always required for tmds clock - "retimer-clk" is required only when retimer is being used - - - phys: phandle for phy lanes registered for hdmi protocol. HDMI always + "irq": interrupt for tx subcore [always present] + "hdcp14_irq": interrupt for hdcp1.4 core [optional - present if hdcp1x + is included] + "hdcp14_timer_irq": interrupt for hdcp1.4 timer [optional - present if + hdcp1x is included] + "hdcp22_irq": interrupt for hdcp22 core [optional - present if hdcp22 + is included] + "hdcp22_timer_irq": interrupt for hdcp2.2 timer [optional - present if + hdcp22 is included] + + - clocks: phandle of all the clocks required by IP are listed here. + - clock-names: names of all the clocks required by IP are listed here. + NOTE: Auto generated DT is providing all the clock names and handles + reuired by the IP. + NOTE: Below are the identification string that are always required. + "s_axi_cpu_aclk", is always required for the axi-lite clock + "s_axis_video_aclk" is always required for video stream clock + "txref-clk" is always required for tmds clock + "retimer-clk" is required only when retimer is being used + NOTE: "txref-clk" and "retimer-clk" needs to be explicitly added in + the list of clock-names and its phandle in clocks as its derived by + external clock. + + - phys: phandle for phy lanes registered for hdmi protocol. HDMI always require 3 lanes - phy-names: The identification string, "hdmi-phy0" and so on - + - xlnx,input-pixels-per-clock: IP configuration for samples/clk (2, 4) Note: Only 2 is supported at this time - xlnx,max-bits-per-component: The data width per video component (8,10,12,16) @@ -59,11 +67,22 @@ Required properties: If present indicates inclusion of the optional core - xlnx,include-hdcp-2-2: Boolean parameter that denotes if hdcp22 is included. If present indicates inclusion of the optional core - - xlnx,hdcp-authenticate: Flag to enable/disable hdcp authentication. + - xlnx,hdcp-authenticate: Flag to enable/disable hdcp authentication. Applicable when either hdcp14 or hdcp22 is included in the design - xlnx,hdcp-encrypt: Flag to enable/disable stream encryption Applicable when either hdcp14 or hdcp22 is included in the design - + - xlnx,audio-enabled: Boolean parameter to convey that design has audio + functionality. + If present, indicates optional audio core needed for audio + usecase is included. + - xlnx,aes_parser: Alias to audio channel status extractor block. + Needed only if "xlnx,audio-enabled" is included. + - xlnx,snd-pcm: Reference to audio formatter block. Add this if, audio formatter + is going to be used for HDMI audio. + Needed only if "xlnx,audio-enabled" is included. + - xlnx,xlnx-hdmi-acr-ctrl: Alias to audio clock recovery block. + Needed only if "xlnx,audio-enabled" is included. + Sub-Node Properties: The device tree will need to include a sub-node for the encoder endpoint interface. This port will bind the hdmi encoder with the crtc being used @@ -82,21 +101,29 @@ depending on the TX clock line rate. Tested with dp159.c driver. If hdcp1.4 is included in the design then key management block node should be added to the device tree - hdmi_output_hdcp_keymngmt_blk_top_0: hdcp_keymngmt_blk_top@a0280000 { + hdcp_keymngmt_blk_0: hdcp_keymngmt_blk_top@90000000 { + clock-names = "s_axi_aclk", "m_axis_aclk"; + clocks = <&zynqmp_clk 71>, <&misc_clk_0>; compatible = "xlnx,hdcp-keymngmt-blk-top-1.0"; - reg = <0x0 0xa0280000 0x0 0x10000>; + reg = <0x0 0x90000000 0x0 0x10000>; }; - hdmi_output_v_hdmi_tx_ss_0: v_hdmi_tx_ss@a0080000 { + hdmi_acr_ctrl_0: hdmi_acr_ctrl@a0059000 { + /* This is a place holder node for a custom IP, user may need to update the entries */ + compatible = "xlnx,hdmi-acr-ctrl-1.0"; + reg = <0x0 0xa0059000 0x0 0x1000>; + }; + + v_hdmi_tx_ss: v_hdmi_tx_ss@80080000 { compatible = "xlnx,v-hdmi-tx-ss-3.1"; reg = <0x0 0xa0080000 0x0 0x80000>, <0x0 0xa0280000 0x0 0x10000>; - reg-names = "hdmi-txss", "hdcp1x-keymngmt"; + reg-names = "hdmi-txss", "hdcp1x-keymngmt"; interrupt-parent = <&gic>; - interrupts = <0 93 4>, <0 104 4>, <0 105 4>, <0 106 4>, <0 107 4>; - interrupt-names = "hdmitx", "hdcp1x", "hdcp1x-timer", "hdcp22", "hdcp22-timer"; - - clocks = <&axi_lite_clk>, <&axi_stream_clk>, <&si5324 0>, <&dp159>; - clock-names = "axi-lite", "video", "txref-clk", "retimer-clk"; + interrupts = <0 91 4 0 106 4 0 107 4 0 110 4 0 111 4>; + interrupt-names = "irq", "hdcp14_irq", "hdcp14_timer_irq", "hdcp22_irq", "hdcp22_timer_irq"; + + clock-names = "s_axi_cpu_aclk", "link_clk", "s_axis_audio_aclk", "video_clk", "s_axis_video_aclk", "txref-clk", "retimer-clk"; + clocks = <&zynqmp_clk 71>, <&misc_clk_1>, <&zynqmp_clk 71>, <&misc_clk_2>, <&zynqmp_clk 72>, <&si5324 0>, <&dp159>; phy-names = "hdmi-phy0", "hdmi-phy1", "hdmi-phy2"; phys = <&vphy_lane0 0 1 1 1>, <&vphy_lane1 0 1 1 1>, <&vphy_lane2 0 1 1 1>; @@ -107,6 +134,9 @@ added to the device tree /* settings for HDCP */ xlnx,hdcp-authenticate = <0x1>; xlnx,hdcp-encrypt = <0x1>; + xlnx,audio-enabled; + xlnx,xlnx-hdmi-acr-ctrl = <&hdmi_acr_ctrl_0>; + xlnx,snd-pcm = <&audio_ss_0_audio_formatter_0>; ports { #address-cells = <1>; @@ -134,3 +164,6 @@ added to the device tree }; }; }; + + Documentation of "audio_ss_0_audio_formatter_0" node is located + at Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt diff --git a/Documentation/devicetree/bindings/xlnx,vphy.txt b/Documentation/devicetree/bindings/xlnx,vphy.txt index 4941fb8..4fd6adb 100644 --- a/Documentation/devicetree/bindings/xlnx,vphy.txt +++ b/Documentation/devicetree/bindings/xlnx,vphy.txt @@ -2,6 +2,7 @@ Xilinx VPHY (Staging) The Xilinx Video PHY is a high-level video-specific wrapper around different versions of the GT PHY. Its driver is phy/phy-xilinx-vphy.c +This now supports HDMI on Versal too. It offers the PHY driver interface as well as higher-level video specific support functions. @@ -12,18 +13,25 @@ Its current users are Xilinx HDMI RX/TX SS. Required Properties: - compatible: Should be "xlnx,vid-phy-controller-2.2". + For Versal it should be "xlnx,hdmi-gt-controller-1.0". - reg: Base address and size of the IP core. - interrupts: Interrupt number. - interrupts-parent: phandle for interrupt controller. - - - clocks: phandle for axi-lite clock and dru clock - - clock-names: The identification string, "axi-lite", is always required - and "dru-clk" is required for NI DRU clock for phy - + + - clocks: phandle of all the clocks required by IP are listed here. + - clock-names: names of all the clocks required by IP are listed here. + NOTE: Auto generated DT is providing all the clock names and handles + reuired by the IP. + NOTE: The identification string, "vid_phy_axi4lite_aclk", is always + required in non Versal mode. In Versal, the string is "axi4lite_aclk". + NOTE: The identification string "dru-clk" is always required if + NI DRU (nidru parameter) is selected for phy. This needs to be + explicitly added in the list of clock-names and its phandle in clocks + as its derived by external clock. + - xlnx,input-pixels-per-clock: IP configuration for samples/clk (1, 2, 4) Note: Only 2 is supported at this time - - - xlnx,nidru: flag to indicate if DRU is present + - xlnx,nidru: flag to indicate if DRU is present. - xlnx,nidru-refclk-sel: DRU clock selector - xlnx,rx-no-of-channels: Required Rx channels for registered protocol - xlnx,rx-pll-selection: Rx pll selector @@ -38,6 +46,11 @@ Required Properties: - xlnx,tx-buffer-bypass: Flag to indicate buffer bypass logic availability - xlnx,transceiver-width: Defines 4 Byte or 2 Byte mode (Note: Only 2 byte is supported at this time) + - xlnx,use-gt-ch4-hdmi: Enables the usage of 4th TX GT channel. + (Default value is 0. + If selected in GUI, then value will be 1) + - xlnx,rx-frl-refclk-sel: Reference clock for Rx in FRL mode in Versal only + - xlnx,tx-frl-refclk-sel: Reference clock for Tx in FRL mode in Versal only - lane: (port (child) nodes) lane0: @@ -47,23 +60,23 @@ Required Properties: controller_type = 0 for HDMI controller_instance = [0, ...] indexes the instance of the protocol - controller - is_shared = 1 if the RX and TX can be shared across the same + controller + is_shared = 1 if the RX and TX can be shared across the same protocol/controller direction_tx = 0 for RX and 1 for TX -(These properties are intended for future steering of multiple protocols +(These properties are intended for future steering of multiple protocols sharing VPHYs, and are therefore subject to change.) ==Example== - vid_phy_controller_0: vid_phy_controller@a0090000 { + vid_phy_controller: vid_phy_controller@80120000 { compatible = "xlnx,vid-phy-controller-2.2"; reg = <0x0 0xa0090000 0x0 0x10000>; interrupts = <0 92 4>; interrupt-parent = <&gic>; - clocks = <&vid_s_axi_clk>, <&si570_2>; - clock-names = "axi-lite", "dru-clk"; + clock-names = "mgtrefclk0_pad_p_in", "mgtrefclk0_pad_n_in", "mgtrefclk1_pad_p_in", "mgtrefclk1_pad_n_in", "gtsouthrefclk0_in", "gtsouthrefclk0_odiv2_in", "vid_phy_tx_axi4s_aclk", "vid_phy_rx_axi4s_aclk", "vid_phy_sb_aclk", "vid_phy_axi4lite_aclk", "drpclk", "dru-clk"; + clocks = <&misc_clk_0>, <&misc_clk_0>, <&misc_clk_0>, <&misc_clk_0>, <&misc_clk_3>, <&misc_clk_3>, <&misc_clk_1>, <&misc_clk_1>, <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&si570_2>; xlnx,input-pixels-per-clock = <0x2>; xlnx,nidru = <0x1>; @@ -80,6 +93,7 @@ sharing VPHYs, and are therefore subject to change.) xlnx,transceiver-type = <0x5>; xlnx,tx-buffer-bypass = <0x1>; xlnx,transceiver-width = <0x2>; + xlnx,use-gt-ch4-hdmi = <0>; vphy_lane0: vphy_lane@0 { #phy-cells = <4>; @@ -94,3 +108,46 @@ sharing VPHYs, and are therefore subject to change.) #phy-cells = <4>; }; }; + +==Example for Versal== + + hdmi_gt_controller_1: hdmi_gt_controller@a4080000 { + clock-names = "gt_refclk1_odiv2", "sb_aclk", "axi4lite_aclk", "apb_clk", "dru-clk"; + clocks = <&misc_clk_0>, <&versal_clk 65>, <&versal_clk 65>, <&versal_clk 65>, <&si570_2>; + compatible = "xlnx,hdmi-gt-controller-1.0"; + interrupt-names = "irq"; + interrupt-parent = <&gic>; + interrupts = <0 84 4>; + reg = <0x0 0xa4080000 0x0 0x10000>; + xlnx,err-irq-en = <0>; + xlnx,hdmi-fast-switch = <0>; + xlnx,input-pixels-per-clock = <2>; + xlnx,nidru = <1>; + xlnx,nidru-refclk-sel = <2>; + xlnx,rx-frl-refclk-sel = <2>; + xlnx,rx-no-of-channels = <4>; + xlnx,rx-pll-selection = <8>; + xlnx,rx-protocol = <3>; + xlnx,rx-refclk-sel = <0>; + xlnx,transceiver-type = <7>; + xlnx,transceiver-width = <2>; + xlnx,tx-buffer-bypass = <1>; + xlnx,tx-frl-refclk-sel = <2>; + xlnx,tx-no-of-channels = <4>; + xlnx,tx-pll-selection = <7>; + xlnx,tx-protocol = <1>; + xlnx,tx-refclk-sel = <1>; + xlnx,use-gt-ch4-hdmi = <1>; + vphy_lane0: vphy_lane@0 { + #phy-cells = <4>; + }; + vphy_lane1: vphy_lane@1 { + #phy-cells = <4>; + }; + vphy_lane2: vphy_lane@2 { + #phy-cells = <4>; + }; + vphy_lane3: vphy_lane@3 { + #phy-cells = <4>; + }; + }; diff --git a/Kbuild b/Kbuild index 7ef8e47..6c9d391 100644 --- a/Kbuild +++ b/Kbuild @@ -1,3 +1,2 @@ -obj-m += clk/ obj-m += hdmi/ obj-m += misc/ diff --git a/LICENSE.md b/LICENSE.md index 3912109..66111db 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,340 +1,692 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, 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 Library 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. +Components: xhdmi 2020.1 - 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. - - - Copyright (C) - - 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 St, 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. - - , 1 April 1989 - Ty Coon, President of Vice + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, 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 Library 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. + + + Copyright (C) + + 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 St, 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. + + , 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 Library General +Public License instead of this License. + + + +Copyright 2001 D.I. Management Services Pty Ltd +Copyright 2007-2009 Ilya O. Levin +Copyright 2018 Rohit Consul +Copyright 1989, 1991 Free Software Foundation Inc +Copyright 2001 David Ireland D.I. Management Services Pty Ltd +Copyright 2007 Hans Verkuil +Copyright 2016-2017 Leon Woestenberg +Copyright 2014-2019 Xilinx Inc + + +Components: di_bigdigits 2.5.0 + + +*/ + +/***** BEGIN LICENSE BLOCK ***** + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2001-15 David Ireland, D.I. Management Services Pty Limited + * . All rights reserved. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2, as described below: + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * + ***** END LICENSE BLOCK *****/ +/* + * Last updated: + * $Date: 2015-10-22 10:23:00 $ + * $Revision: 2.5.0 $ + * $Author: dai $ + */ + + +Mozilla Public License +Version 2.0 +1. Definitions +1.1. ?Contributor? +means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. + +1.2. ?Contributor Version? +means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor?s Contribution. + +1.3. ?Contribution? +means Covered Software of a particular Contributor. + +1.4. ?Covered Software? +means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. + +1.5. ?Incompatible With Secondary Licenses? +means + +that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or + +that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. + +1.6. ?Executable Form? +means any form of the work other than Source Code Form. + +1.7. ?Larger Work? +means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. + +1.8. ?License? +means this document. + +1.9. ?Licensable? +means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. + +1.10. ?Modifications? +means any of the following: + +any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or + +any new file in Source Code Form that contains any Covered Software. + +1.11. ?Patent Claims? of a Contributor +means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. + +1.12. ?Secondary License? +means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. + +1.13. ?Source Code Form? +means the form of the work preferred for making modifications. + +1.14. ?You? (or ?Your?) +means an individual or a legal entity exercising rights under this License. For legal entities, ?You? includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, ?control? means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants and Conditions +2.1. Grants +Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + +under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and + +under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. + +2.2. Effective Date +The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. + +2.3. Limitations on Grant Scope +The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: + +for any code that a Contributor has removed from Covered Software; or + +for infringements caused by: (i) Your and any other third party?s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or + +under Patent Claims infringed by Covered Software in the absence of its Contributions. + +This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). + +2.4. Subsequent Licenses +No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). + +2.5. Representation +Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use +This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. + +3. Responsibilities +3.1. Distribution of Source Form +All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients? rights in the Source Code Form. + +3.2. Distribution of Executable Form +If You distribute Covered Software in Executable Form then: + +such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and + +You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients? rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work +You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). + +3.4. Notices +You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms +You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. + +5. Termination +5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. + +6. Disclaimer of Warranty +Covered Software is provided under this License on an ?as is? basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. + +7. Limitation of Liability +Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party?s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation +Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party?s ability to bring cross-claims or counter-claims. + +9. Miscellaneous +This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. + +10. Versions of the License +10.1. New Versions +Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. + +10.2. Effect of New Versions +You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. + +10.3. Modified Versions +If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses +If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - ?Incompatible With Secondary Licenses? Notice +This Source Code Form is ?Incompatible With Secondary Licenses?, as defined by the Mozilla Public License, v. 2.0. + + +copyright (c) 2001-15 by D.I. Management Services Pty Limited +Copyright 2001 David Ireland D.I. Management Services Pty Ltd + + +Components: dp159 + + +GNU General Public License, version 2 +The latest version of the GPL, version 3 +What to do if you see a possible GPL violation +Translations of GPLv2 +GPLv2 Frequently Asked Questions +The GNU General Public License version 2 (GPLv2) in other formats: plain text, Texinfo, LaTeX, standalone HTML, Docbook, Markdown, ODF, RTF +Table of Contents +GNU GENERAL PUBLIC LICENSE +Preamble +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +How to Apply These Terms to Your New Programs +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. + +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 an idea of what it does. +Copyright (C) yyyy 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. + + +Copyright (C) 2007 Hans Verkuil +Copyright 2016-2017 Leon Woestenberg -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 Library General -Public License instead of this License. diff --git a/Makefile b/Makefile index bb52865..cda7c67 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ SRC := $(shell pwd) -obj-m += clk/ obj-m += hdmi/ obj-m += misc/ diff --git a/clk/Makefile b/clk/Makefile deleted file mode 100644 index adbdf0b..0000000 --- a/clk/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# status: implements/tested only features required by Xilinx HDMI - -ccflags-y += -Iinclude -ccflags-y += -DFALSE=0 -Dllabs=abs -ccflags-y += -Wno-unused-variable - -obj-m += si5324.o - -si5324-y := clk-si5324.o si5324drv.o - diff --git a/clk/clk-si5324.c b/clk/clk-si5324.c deleted file mode 100644 index 739af90..0000000 --- a/clk/clk-si5324.c +++ /dev/null @@ -1,1509 +0,0 @@ -/* - * clk-si5324.c: Silicon Laboratories Si5324 Clock Multiplier / Jitter Attenuator - * - * Leon Woestenberg - * - * References: - * [1] "Si5324 Data Sheet" - * https://www.silabs.com/Support%20Documents/TechnicalDocs/Si5324.pdf - * [2] http://www.silabs.com/Support%20Documents/TechnicalDocs/Si53xxReferenceManual.pdf - * - * 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. - */ - - -/* if both both DEBUG and DEBUG_TRACE are defined, trace_printk() is used */ -//#define DEBUG -//#define DEBUG_TRACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk-si5324.h" -#include "si5324drv.h" -#include "include/si5324.h" - -/* select either trace or printk logging */ -#ifdef DEBUG_TRACE -#define do_si5324_dbg(format, ...) do { \ - trace_printk("si5324: " format, ##__VA_ARGS__); \ -} while(0) -#else -#define do_si5324_dbg(format, ...) do { \ - printk(KERN_DEBUG "si5324: " format, ##__VA_ARGS__); \ -} while(0) -#endif - -/* either enable or disable debugging */ -#ifdef DEBUG -# define si5324_dbg(x...) do_si5324_dbg(x) -#else -# define si5324_dbg(x...) -#endif - -/* bypass is a hardware debug function, but can be useful in applications, - * @TODO consider support through device-tree option later */ -#define FORCE_BYPASS 0 -#define NUM_NAME_IDS 6 //3 clkin, 1 pll, 2 clkout -#define MAX_NAME_LEN 11 - -struct si5324_driver_data; - -struct si5324_parameters { - // Current Si5342 parameters - - /* high-speed output divider */ - u32 n1_hs_min; - u32 n1_hs_max; - u32 n1_hs; - - /* low-speed output divider for clkout1 */ - u32 nc1_ls_min; - u32 nc1_ls_max; - u32 nc1_ls; - - /* low-speed output divider for clkout2 */ - u32 nc2_ls_min; - u32 nc2_ls_max; - u32 nc2_ls; - - /* high-speed feedback divider (PLL multiplier) */ - u32 n2_hs; - /* low-speed feedback divider (PLL multiplier) */ - u32 n2_ls_min; - u32 n2_ls_max; - u32 n2_ls; - - /* input divider for clk1 */ - u32 n31_min; - u32 n31_max; - u32 n31; - - /* input divider for clk1 */ - u32 n32_min; - u32 n32_max; - u32 n32; - - // Current frequencies (fixed point 36.28 notation) - u64 fin; - u64 fout; - u64 fosc; - // Best settings found - u64 best_delta_fout; - u64 best_fout; - u32 best_n1_hs; - u32 best_nc1_ls; - u32 best_n2_hs; - u32 best_n2_ls; - u32 best_n3; - int valid; -}; - -struct si5324_hw_data { - struct clk_hw hw; - struct si5324_driver_data *drvdata; - unsigned char num; -}; - -struct si5324_driver_data { - struct i2c_client *client; - struct regmap *regmap; - struct clk_onecell_data onecell; - - struct si5324_parameters params; - - struct clk *pxtal; - const char *pxtal_name; - struct clk_hw xtal; - - struct clk *pclkin1; - const char *pclkin1_name; - struct clk_hw clkin1; - - struct clk *pclkin2; - const char *pclkin2_name; - struct clk_hw clkin2; - - struct si5324_hw_data pll; - struct si5324_hw_data *clkout; - - /* temporary solution to provide actual rates */ - unsigned long rate_clkout0; - unsigned long rate_clkout1; -}; - -static const char * const si5324_input_names[] = { - "xtal", "clkin1", "clkin2" -}; - -static const char * const si5324_pll_name = "pll"; - -static const char * const si5324_clkout_names[] = { - "clk0", "clk1" -}; - -enum si53xx_variant { - si5319, - si5324, - si5328 -}; - -static const char * const si53xx_variant_name[] = { - "si5319", "si5324", "si5328" -}; - -/* - * Si5324 i2c regmap - */ -static inline u8 si5324_reg_read(struct si5324_driver_data *drvdata, u8 reg) -{ - u32 val; - int ret; - - ret = regmap_read(drvdata->regmap, reg, &val); - if (ret) { - dev_err(&drvdata->client->dev, - "unable to read from reg%02x\n", reg); - return 0; - } else { - dev_dbg(&drvdata->client->dev, "Read value 0x%02x @%02d\n", - (int)val, (int)reg); - } - - return (u8)val; -} - -static inline int si5324_bulk_read(struct si5324_driver_data *drvdata, - u8 reg, u8 count, u8 *buf) -{ - return regmap_bulk_read(drvdata->regmap, reg, buf, count); -} - -static inline int si5324_reg_write(struct si5324_driver_data *drvdata, - u8 reg, u8 val) -{ - u8 readback_val; - int ret = regmap_write(drvdata->regmap, reg, val); - dev_dbg(&drvdata->client->dev, "si5324_reg_write() 0x%02x @%02d\n", (int)val, (int)reg); -#if 0 - readback_val = si5324_reg_read(drvdata, reg); - if (readback_val != val) { - dev_err(&drvdata->client->dev, "readback 0x%02x @%02d, expected 0x%02x\n", (int)readback_val, (int)reg, (int)val); - } -#endif - return ret; -} - -static inline int si5324_bulk_write(struct si5324_driver_data *drvdata, - u8 reg, u8 count, const u8 *buf) -{ - return regmap_raw_write(drvdata->regmap, reg, buf, count); -} - -static inline int si5324_set_bits(struct si5324_driver_data *drvdata, - u8 reg, u8 mask, u8 val) -{ - return regmap_update_bits(drvdata->regmap, reg, mask, val); -} - -/* similar to Si5324_DoSettings() */ -static inline int si5324_bulk_scatter_write(struct si5324_driver_data *drvdata, - u8 count/*number of reg/val pairs*/, const u8 *buf) -{ - int i; - int result = 0; - for (i = 0; i < count; i++) { - result = si5324_reg_write(drvdata, buf[i * 2]/*reg*/, buf[i * 2 + 1]/*val*/); - if (result) return result; - } - return result; -} - -/* bare-metal: SI5324_DEFAULTS[] */ -static void si5324_initialize(struct si5324_driver_data *drvdata) -{ - /* keep RST_REG asserted for 10 ms */ - si5324_set_bits(drvdata, SI5324_RESET, - SI5324_RST_REG, SI5324_RST_REG); - msleep(10); - si5324_set_bits(drvdata, SI5324_RESET, - SI5324_RST_REG, 0); - /* wait 10 ms after de-assert */ - msleep(10); - - /* enable free-run */ - si5324_reg_write(drvdata, 0, 0x54); - - // Disable output clocks during calibration (bit 4 SQ_ICAL=1), - // other bits are default - si5324_reg_write(drvdata, 3, 0x15); - - /* clock selection mode: manual */ - si5324_reg_write(drvdata, 4, 0x12); - - // Disable CKOUT2 (SFOUT2_REG=001) - // set CKOUT1 to LVDS (SFOUT1_REG=111) - // (default is LVPECL for both) - si5324_reg_write(drvdata, 6, 0x0F); - // enable CKOUT1 output (bit 2 DSBL1_REG=0) - // disable CKOUT2 output (bit 3 DSBL2_REG=1) - si5324_reg_write(drvdata, 10, 0x08); - // Disable CKIN2 input buffer (bit 1 PD_CK2=1) - // enable CKIN1 buffer (bit 0 PD_CK1=0) - // (bit 6 is reserved, write default value) - si5324_reg_write(drvdata, 11, 0x42); - // XPAR_VID_PHY_CONTROLLER_HDMI_FAST_SWITCH - // Set lock time to 13.3ms (bits 2:0 LOCKT=011) - // and set valid time to 2ms (bits 4:3 VALTIME=00) - // other bits are default - si5324_reg_write(drvdata, 19, 0x23); - - /* bare-metal does not set this */ - /* ignore pin control CS_CA pin is ignored, CS_CA output pin tristated */ - si5324_reg_write(drvdata, 21, 0xfc); - - // Enable fast locking (bit 0 FASTLOCK=1) - si5324_reg_write(drvdata, 137, 0x01); -} - -#define SI5324_PARAMETERS_REG 25 -#define SI5324_PARAMETERS_LENGTH 24 - -/* - * 0 25 N1_HS[2:0] - * 6 31 NC1_LS[19:16] - * 7 32 NC1_LS[15:8] - * 8 33 NC1_LS[7:0] - * 9 34 NC2_LS[19:16] - * 10 35 NC2_LS[15:8] - * 11 36 NC2_LS[7:0] - * 15 40 N2_HS[2:0] N2_LS[19:16] - * 16 41 N2_LS[15:8] - * 17 42 N2_LS[7:0] - * 18 43 N31[18:16] - * 19 44 N31[15:8] - * 20 45 N31[7:0] - * 21 46 N32[18:16] - * 22 47 N32[15:8] - * 23 48 N32[7:0] - */ - -static void si5324_read_parameters(struct si5324_driver_data *drvdata) -{ - u8 buf[SI5324_PARAMETERS_LENGTH]; - - si5324_bulk_read(drvdata, 25, 1, &buf[0]); - si5324_bulk_read(drvdata, 31, 6, &buf[6]); - si5324_bulk_read(drvdata, 40, 9, &buf[15]); - - /* high-speed output divider */ - drvdata->params.n1_hs = (buf[0] >> 5); - drvdata->params.n1_hs += 4; - si5324_dbg("N1_HS = %u\n", drvdata->params.n1_hs); - /* low-speed output divider for clkout1 */ - drvdata->params.nc1_ls = ((buf[6] & 0x0f) << 16) | (buf[ 7] << 8) | buf[ 8]; - drvdata->params.nc1_ls += 1; - si5324_dbg("NC1_LS = %u\n", drvdata->params.nc1_ls); - /* low-speed output divider for clkout2 */ - drvdata->params.nc2_ls = ((buf[9] & 0x0f) << 16) | (buf[10] << 8) | buf[11]; - drvdata->params.nc2_ls += 1; - si5324_dbg("NC2_LS = %u\n", drvdata->params.nc2_ls); - /* low-speed feedback divider (PLL multiplier) */ - drvdata->params.n2_ls = ((buf[15] & 0x0f) << 16) | (buf[16] << 8) | buf[17]; - drvdata->params.n2_ls += 1; - si5324_dbg("N2_LS = %u\n", drvdata->params.n2_ls); - /* high-speed feedback divider (PLL multiplier) */ - drvdata->params.n2_hs = buf[15] >> 5; - drvdata->params.n2_hs += 4; - si5324_dbg("N2_HS = %u\n", drvdata->params.n2_hs); - /* input divider for clk1 */ - drvdata->params.n31 = ((buf[18] & 0x0f) << 16) | (buf[19] << 8) | buf[20]; - drvdata->params.n31 += 1; - si5324_dbg("N31 = %u\n", drvdata->params.n31); - /* input divider for clk2 */ - drvdata->params.n32 = ((buf[21] & 0x0f) << 16) | (buf[22] << 8) | buf[23]; - drvdata->params.n32 += 1; - si5324_dbg("N32 = %u\n", drvdata->params.n32); - drvdata->params.valid = 1; -} - -#if 0 -static void si5324_write_parameters(struct si5324_driver_data *drvdata) -{ - u8 buf[SI5324_PARAMETERS_LENGTH]; - u32 reg_val; - /* high-speed output divider */ - reg_val = drvdata->params.n1_hs - 4; - buf[0] = reg_val << 5; - /* low-speed output divider for clkout1 */ - reg_val = drvdata->params.nc1_ls - 1; - buf[6] = (reg_val >> 16) & 0x0f; - buf[7] = (reg_val >> 8) & 0xff; - buf[8] = reg_val & 0xff; - /* low-speed output divider for clkout2 */ - reg_val = drvdata->params.nc2_ls; - buf[ 9] = (reg_val >> 16) & 0x0f; - buf[10] = (reg_val >> 8) & 0xff; - buf[11] = reg_val & 0xff; - /* low-speed feedback divider (PLL multiplier) */ - reg_val = drvdata->params.n2_ls + 1; - buf[15] = (reg_val >> 16) & 0x0f; - buf[16] = (reg_val >> 8) & 0xff; - buf[17] = reg_val & 0xff; - /* high-speed feedback divider (PLL multiplier) */ - reg_val = drvdata->params.n2_hs - 4; - buf[15] |= reg_val << 5; - /* input divider for clk1 */ - reg_val = drvdata->params.n31; - buf[18] = (reg_val >> 16) & 0x0f; - buf[19] = (reg_val >> 8) & 0xff; - buf[20] = reg_val & 0xff; - /* input divider for clk2 */ - reg_val = drvdata->params.n31; - buf[21] = (reg_val >> 16) & 0x0f; - buf[22] = (reg_val >> 8) & 0xff; - buf[23] = reg_val & 0xff; - si5324_bulk_write(drvdata, 25, 1, &buf[0]); - si5324_bulk_write(drvdata, 31, 6, &buf[6]); - si5324_bulk_write(drvdata, 40, 9, &buf[15]); - -} -#endif - -static bool si5324_regmap_is_volatile(struct device *dev, unsigned int reg) -{ - return true; -#if 0/*@TODO */ - return false; -#endif -} - -static bool si5324_regmap_is_readable(struct device *dev, unsigned int reg) -{ - bool result = true; - /* reserved registers */ - if (reg >= 12 && reg <= 18) - result = false; - else if (reg >= 26 && reg <= 30) - result = false; - else if (reg >= 37 && reg <= 39) - result = false; - else if (reg >= 49 && reg <= 54) - result = false; - else if (reg >= 56 && reg <= 127) - result = false; - else if (reg >= 144) - result = false; -#if 0 - si5324_dbg("si5324_regmap_is_readable(reg0x%02x) = %u\n", reg, result); -#endif - return result; -} - -static bool si5324_regmap_is_writeable(struct device *dev, unsigned int reg) -{ - bool result = true; - /* reserved registers */ - if (reg >= 12 && reg <= 18) - result = false; - else if (reg >= 26 && reg <= 30) - result = false; - else if (reg >= 37 && reg <= 39) - result = false; - else if (reg >= 49 && reg <= 54) - result = false; - else if (reg >= 56 && reg <= 127) - result = false; - else if (reg >= 144) - result = false; - /* read-only */ - else if (reg >= 128 && reg <= 130) - result = false; - else if (reg >= 134 && reg <= 135) - result = false; -#if 0 - si5324_dbg("si5324_regmap_is_writeable(reg0x%02x) = %u\n", reg, result); -#endif - return result; -} - -static const struct regmap_config si5324_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .cache_type = REGCACHE_RBTREE, - .max_register = 144, - .writeable_reg = si5324_regmap_is_writeable, - .readable_reg = si5324_regmap_is_readable, - .volatile_reg = si5324_regmap_is_volatile, -}; - -/* - * Si5324 xtal clock input - */ -static int si5324_xtal_prepare(struct clk_hw *hw) -{ - struct si5324_driver_data *drvdata = - container_of(hw, struct si5324_driver_data, xtal); - - si5324_dbg("si5324_xtal_prepare-nop; set to free-running mode from xtal\n"); - return 0; -} - -static void si5324_xtal_unprepare(struct clk_hw *hw) -{ - struct si5324_driver_data *drvdata = - container_of(hw, struct si5324_driver_data, xtal); - si5324_dbg("si5324_xtal_unprepare - nop\n"); -} - -static const struct clk_ops si5324_xtal_ops = { - .prepare = si5324_xtal_prepare, - .unprepare = si5324_xtal_unprepare, -}; - -/* - * Si5324 clkin1/clkin2 clock input - */ -static int si5324_clkin_prepare(struct clk_hw *hw) -{ - struct si5324_driver_data *drvdata; - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - si5324_dbg("si5324_clkin_prepare() for hwdata->num = %d\n", hwdata->num); - - /* clkin1? */ - if (hwdata->num == 0/*@TODO: verify if this should be 1*/) { - drvdata = container_of(hw, struct si5324_driver_data, clkin1); - /* disable free-run */ - si5324_set_bits(drvdata, SI5324_REG0, SI5324_REG0_FREE_RUN, 0); - /* clkin1 powered, clkin2 powered-down*/ - si5324_set_bits(drvdata, SI5324_POWERDOWN, - SI5324_PD_CK1 | SI5324_PD_CK2, SI5324_PD_CK2); - } else if (hwdata->num == 1/*@TODO: verify if this should be 2*/) { - drvdata = container_of(hw, struct si5324_driver_data, clkin2); - /* disable free-run */ - si5324_set_bits(drvdata, SI5324_REG0, SI5324_REG0_FREE_RUN, 0); - /* clkin2 powered, clkin1 powered-down*/ - si5324_set_bits(drvdata, SI5324_POWERDOWN, - SI5324_PD_CK1 | SI5324_PD_CK2, SI5324_PD_CK1); - } else { - } - return 0; -} - -static void si5324_clkin_unprepare(struct clk_hw *hw) -{ - struct si5324_driver_data *drvdata; - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - si5324_dbg("si5324_clkin_unprepare\n"); - if (hwdata->num == 0/*@TODO:1?*/) { - drvdata = container_of(hw, struct si5324_driver_data, clkin1); - } else if (hwdata->num == 1/*@TODO:2?*/) { - drvdata = container_of(hw, struct si5324_driver_data, clkin2); - } else { - } -} - -/* - * @recalc_rate Recalculate the rate of this clock, by querying hardware. The - * parent rate is an input parameter. It is up to the caller to - * ensure that the prepare_mutex is held across this call. - * Returns the calculated rate. - */ -static unsigned long si5324_clkin_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - return 0; -#if 0 - struct si5324_driver_data *drvdata = NULL; - unsigned long rate; - unsigned char idiv; - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - idiv = 1; - - si5324_dbg("si5324_clkin_recalc_rate() hwdata->num = %d\n", hwdata->num); - if (hwdata->num == 0) { - drvdata = container_of(hw, struct si5324_driver_data, xtal); - si5324_dbg("si5324_clkin_recalc_rate(parent_rate=%lu for xtal)\n", parent_rate); - } else if (hwdata->num == 1) { - drvdata = container_of(hw, struct si5324_driver_data, clkin1); - si5324_dbg("si5324_clkin_recalc_rate(parent_rate=%lu for clkin1)\n", parent_rate); - } else if (hwdata->num == 2) { - drvdata = container_of(hw, struct si5324_driver_data, clkin2); - si5324_dbg("si5324_clkin_recalc_rate(parent_rate=%lu for clkin2)\n", parent_rate); - } else { - si5324_dbg("si5324_clkin_recalc_rate() hwdata->num = %d\n", hwdata->num); - return 0; - } - - rate = parent_rate; - - /* f3 (behind /N3x) is out of range, i,e, >2MHz? */ - if (rate > 2000000) { - /* set input divider */ - idiv = (rate + 2000000 - 1) / 2000000; - rate = parent_rate / idiv; - } -/* - si5324_set_bits(drvdata, SI5324_PLL_INPUT_SOURCE, - SI5324_CLKIN_DIV_MASK, idiv); -*/ - if (drvdata) - dev_dbg(&drvdata->client->dev, "%s - clkin div = %d, rate = %lu\n", - __func__, (1 << (idiv >> 6)), rate); - return rate; -#endif -} - -static const struct clk_ops si5324_clkin_ops = { - .prepare = si5324_clkin_prepare, - .unprepare = si5324_clkin_unprepare, - .recalc_rate = si5324_clkin_recalc_rate, -}; - -/* Select other clock input to the PLL - */ -static int _si5324_pll_reparent(struct si5324_driver_data *drvdata, - int num, enum si5324_pll_src parent) -{ - si5324_dbg("_si5324_pll_reparent() for parent = %d\n", (int)parent); - - if (parent == SI5324_PLL_SRC_XTAL) { - /* enable free-run */ - si5324_set_bits(drvdata, SI5324_REG0, - SI5324_REG0_FREE_RUN, SI5324_REG0_FREE_RUN); - /* clkin2 powered, clkin1 powered-down, xtal connects to clkin2 */ - si5324_set_bits(drvdata, SI5324_POWERDOWN, - SI5324_PD_CK1 | SI5324_PD_CK2, SI5324_PD_CK1); - /* select clkin2 */ - si5324_set_bits(drvdata, SI5324_CKSEL, - 3 << 6, 1 << 6); - } else if (parent == SI5324_PLL_SRC_CLKIN1) { - /* disable free-run */ - si5324_set_bits(drvdata, SI5324_REG0, - SI5324_REG0_FREE_RUN, 0); - /* clkin1 powered, clkin2 powered-down */ - si5324_set_bits(drvdata, SI5324_POWERDOWN, - SI5324_PD_CK1 | SI5324_PD_CK2, SI5324_PD_CK2); - /* select clkin1 */ - si5324_set_bits(drvdata, SI5324_CKSEL, - 3 << 6, 0); - } else if (parent == SI5324_PLL_SRC_CLKIN2) { - /* disable free-run */ - si5324_set_bits(drvdata, SI5324_REG0, - SI5324_REG0_FREE_RUN, 0); - /* clkin2 powered, clkin1 powered-down */ - si5324_set_bits(drvdata, SI5324_POWERDOWN, - SI5324_PD_CK1 | SI5324_PD_CK2, SI5324_PD_CK1); - /* select clkin2 */ - si5324_set_bits(drvdata, SI5324_CKSEL, - 3 << 6, 1 << 6); - } - dev_dbg(&drvdata->client->dev, "_si5324_pll_reparent()\n"); - si5324_reg_read(drvdata, 0); - si5324_reg_read(drvdata, 4); - si5324_reg_read(drvdata, 3); - return 0; -} - -static unsigned char si5324_pll_get_parent(struct clk_hw *hw) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - return 0; -} - -static int si5324_pll_set_parent(struct clk_hw *hw, u8 index) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - enum si5324_pll_src parent; - si5324_dbg("si5324_pll_set_parent(index=%d)\n", index); - - if (index == 0) - parent = SI5324_PLL_SRC_XTAL; - else if (index == 1) - parent = SI5324_PLL_SRC_CLKIN1; - else if (index == 2) - parent = SI5324_PLL_SRC_CLKIN2; - else - return -EINVAL; - - return _si5324_pll_reparent(hwdata->drvdata, hwdata->num, parent); -} - -static unsigned long si5324_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - unsigned long rate; - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - si5324_dbg("si5324_pll_recalc_rate(parent_rate=%lu)\n", - parent_rate); - - if (!hwdata->drvdata->params.valid) - si5324_read_parameters(hwdata->drvdata); - WARN_ON(!hwdata->drvdata->params.valid); - - rate = parent_rate * hwdata->drvdata->params.n2_ls * hwdata->drvdata->params.n2_hs; - - dev_dbg(&hwdata->drvdata->client->dev, - "%s - %s: n2_ls = %u, n2_hs = %u, parent_rate = %lu, rate = %lu\n", - __func__, clk_hw_get_name(hw), - hwdata->drvdata->params.n2_ls, hwdata->drvdata->params.n2_hs, - parent_rate, (unsigned long)rate); - return rate; -} - -static long si5324_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - si5324_dbg("si5324_pll_round_rate(rate=%lu, parent_rate=%lu)\n", - rate, *parent_rate); - -#if 0 - unsigned long rfrac, denom, a, b, c; - unsigned long long lltmp; - - if (rate < SI5324_PLL_VCO_MIN) - rate = SI5324_PLL_VCO_MIN; - if (rate > SI5324_PLL_VCO_MAX) - rate = SI5324_PLL_VCO_MAX; - - /* determine integer part of feedback equation */ - a = rate / *parent_rate; - - if (a < SI5324_PLL_A_MIN) - rate = *parent_rate * SI5324_PLL_A_MIN; - if (a > SI5324_PLL_A_MAX) - rate = *parent_rate * SI5324_PLL_A_MAX; - - /* find best approximation for b/c = fVCO mod fIN */ - denom = 1000 * 1000; - lltmp = rate % (*parent_rate); - lltmp *= denom; - do_div(lltmp, *parent_rate); - rfrac = (unsigned long)lltmp; - - b = 0; - c = 1; - if (rfrac) - rational_best_approximation(rfrac, denom, - SI5324_PLL_B_MAX, SI5324_PLL_C_MAX, &b, &c); - - /* calculate parameters */ - hwdata->drvdata->params.p3 = c; - hwdata->drvdata->params.p2 = (128 * b) % c; - hwdata->drvdata->params.p1 = 128 * a; - hwdata->drvdata->params.p1 += (128 * b / c); - hwdata->drvdata->params.p1 -= 512; - - /* recalculate rate by fIN * (a + b/c) */ - lltmp = *parent_rate; - lltmp *= b; - do_div(lltmp, c); - - rate = (unsigned long)lltmp; - rate += *parent_rate * a; - - dev_dbg(&hwdata->drvdata->client->dev, - "%s - %s: a = %lu, b = %lu, c = %lu, parent_rate = %lu, rate = %lu\n", - __func__, clk_hw_get_name(hw), a, b, c, - *parent_rate, rate); -#endif - return rate; -} - -static int si5324_pll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - si5324_dbg("si5324_pll_set_rate(rate=%lu, parent_rate=%lu)\n", - rate, parent_rate); -#if 0 - u8 reg = (hwdata->num == 0) ? SI5324_PLLA_PARAMETERS : - SI5324_PLLB_PARAMETERS; - - /* write multisynth parameters */ - si5324_write_parameters(hwdata->drvdata, reg, &hwdata->drvdata->params); - - /* plla/pllb ctrl is in clk6/clk7 ctrl registers */ - si5324_set_bits(hwdata->drvdata, SI5324_CLK6_CTRL + hwdata->num, - SI5324_CLK_INTEGER_MODE, - (hwdata->drvdata->params.p2 == 0) ? SI5324_CLK_INTEGER_MODE : 0); - - dev_dbg(&hwdata->drvdata->client->dev, - "%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n", - __func__, clk_hw_get_name(hw), - hwdata->drvdata->params.p1, hwdata->drvdata->params.p2, hwdata->drvdata->params.p3, - parent_rate, rate); -#endif - return 0; -} - -static const struct clk_ops si5324_pll_ops = { - .set_parent = si5324_pll_set_parent, - .get_parent = si5324_pll_get_parent, - .recalc_rate = si5324_pll_recalc_rate, - .round_rate = si5324_pll_round_rate, - .set_rate = si5324_pll_set_rate, -}; - -static int _si5324_clkout_set_drive_strength( - struct si5324_driver_data *drvdata, int num, - enum si5324_drive_strength drive) -{ -#if 0 - u8 mask; - - if (num > 8) - return -EINVAL; - - switch (drive) { - case SI5324_DRIVE_2MA: - mask = SI5324_CLK_DRIVE_STRENGTH_2MA; - break; - case SI5324_DRIVE_4MA: - mask = SI5324_CLK_DRIVE_STRENGTH_4MA; - break; - case SI5324_DRIVE_6MA: - mask = SI5324_CLK_DRIVE_STRENGTH_6MA; - break; - case SI5324_DRIVE_8MA: - mask = SI5324_CLK_DRIVE_STRENGTH_8MA; - break; - default: - return 0; - } - - si5324_set_bits(drvdata, SI5324_CLK0_CTRL + num, - SI5324_CLK_DRIVE_STRENGTH_MASK, mask); -#endif - return 0; -} - -static int _si5324_clkout_set_disable_state( - struct si5324_driver_data *drvdata, int num, - enum si5324_disable_state state) -{ -#if 0 - u8 reg = (num < 4) ? SI5324_CLK3_0_DISABLE_STATE : - SI5324_CLK7_4_DISABLE_STATE; - u8 shift = (num < 4) ? (2 * num) : (2 * (num-4)); - u8 mask = SI5324_CLK_DISABLE_STATE_MASK << shift; - u8 val; - - if (num > 8) - return -EINVAL; - - switch (state) { - case SI5324_DISABLE_LOW: - val = SI5324_CLK_DISABLE_STATE_LOW; - break; - case SI5324_DISABLE_HIGH: - val = SI5324_CLK_DISABLE_STATE_HIGH; - break; - case SI5324_DISABLE_FLOATING: - val = SI5324_CLK_DISABLE_STATE_FLOAT; - break; - case SI5324_DISABLE_NEVER: - val = SI5324_CLK_DISABLE_STATE_NEVER; - break; - default: - return 0; - } - - si5324_set_bits(drvdata, reg, mask, val << shift); -#endif - return 0; -} - -static int si5324_clkout_prepare(struct clk_hw *hw) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - - si5324_dbg("si5324_clkout_prepare for hwdata->num=%d - NOP\n",hwdata->num); -#if 0 //clock always enabled for xilinx vphy operation - /* clear power-down bit for output clock num */ - si5324_set_bits(hwdata->drvdata, SI5324_DSBL_CLKOUT, - 1 << (hwdata->num + 2), 0); -#endif - return 0; -} - -static void si5324_clkout_unprepare(struct clk_hw *hw) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - - si5324_dbg("si5324_clkout_unprepare for hwdata->num=%d - NOP\n",hwdata->num); -#if 0 //do not disable clocks for xilinx vphy operation - /* set power-down bit for output clock num */ - si5324_set_bits(hwdata->drvdata, SI5324_DSBL_CLKOUT, - 1 << (hwdata->num + 2), 1 << (hwdata->num + 2)); -#endif -} - -/* - * Si5324 clkout divider - */ -static unsigned long si5324_clkout_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - unsigned long rate = 0; - - si5324_dbg("si5324_clkout_recalc_rate(parent_rate=%lu)\n", parent_rate); -#if 0 - si5324_dbg("si5324_clkout_recalc_rate(parent_rate=%lu) clkout%d\n", - parent_rate, hwdata->num); - - //if (!hwdata->drvdata->params.valid) - si5324_read_parameters(hwdata->drvdata, 24); - WARN_ON(!hwdata->drvdata->params.valid); - - /* clkout1? */ - if (hwdata->num == 0) - rate = (parent_rate / hwdata->drvdata->params.n1_hs) / hwdata->drvdata->params.nc1_ls; - /* clkout2? */ - else if (hwdata->num == 1) - rate = (parent_rate / hwdata->drvdata->params.n1_hs) / hwdata->drvdata->params.nc2_ls; - - si5324_dbg("si5324_clkout_recalc_rate(parent_rate=%lu) => clkout%d=%lu (invalid)\n", - parent_rate, hwdata->num, rate); -#endif - - rate = hwdata->drvdata->rate_clkout0; - - si5324_dbg("si5324_clkout_recalc_rate() = %lu\n", rate); - return rate; -} - -/* round_rate selects the rate closest to the requested one. -determine_rate does the same but even better by changing the clock’s -parent. The actual setting is done by set_rate. recalc_rate is called -when a parent changes rate. */ -static long si5324_clkout_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - unsigned char rdiv; - u32 NCn_ls, N2_ls, N3n; - u8 N1_hs, N2_hs, BwSel; - u32 actual_rate; - int result; - si5324_dbg("si5324_clkout_round_rate(rate=%lu, parent_rate=%lu)\n", - rate, *parent_rate); - - si5324_dbg("%s - %s: parent_rate = %lu, rate = %lu\n", - __func__, clk_hw_get_name(hw), *parent_rate, rate); - - // Calculate the frequency settings for the Si5324 - result = Si5324_CalcFreqSettings(114285000, rate, &actual_rate, - &N1_hs, &NCn_ls, &N2_hs, &N2_ls, &N3n, &BwSel); - -#if 0 - if (rate > SI5324_CLKOUT_MAX_FREQ) - rate = SI5324_CLKOUT_MAX_FREQ; - if (rate < SI5324_CLKOUT_MIN_FREQ) - rate = SI5324_CLKOUT_MIN_FREQ; - - /* request frequency if multisync master */ - if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { - /* use r divider for frequencies below 1MHz */ - rdiv = SI5324_OUTPUT_CLK_DIV_1; - while (rate < SI5324_MULTISYNTH_MIN_FREQ && - rdiv < SI5324_OUTPUT_CLK_DIV_128) { - rdiv += 1; - rate *= 2; - } - *parent_rate = rate; - } else { - unsigned long new_rate, new_err, err; - - /* round to closed rdiv */ - rdiv = SI5324_OUTPUT_CLK_DIV_1; - new_rate = *parent_rate; - err = abs(new_rate - rate); - do { - new_rate >>= 1; - new_err = abs(new_rate - rate); - if (new_err > err || rdiv == SI5324_OUTPUT_CLK_DIV_128) - break; - rdiv++; - err = new_err; - } while (1); - } - rate = *parent_rate >> rdiv; - - dev_dbg(&hwdata->drvdata->client->dev, - "%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n", - __func__, clk_hw_get_name(hw), (1 << rdiv), - *parent_rate, rate); -#endif - - si5324_dbg("si5324_clkout_round_rate() = %lu\n", actual_rate); - return actual_rate; -} - -static int si5324_clkout_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct si5324_hw_data *hwdata = - container_of(hw, struct si5324_hw_data, hw); - - u32 NCn_ls, N2_ls, N3n; - u8 N1_hs, N2_hs, BwSel; - u32 actual_rate; - int result; - u8 buf[14*2]; // Need to set 14 registers - int i; - int rc; - - si5324_dbg("si5324_clkout_set_rate(rate = %lu)\n", rate); - - // Calculate the frequency settings for the Si5324 - result = Si5324_CalcFreqSettings(114285000, rate, &actual_rate, - &N1_hs, &NCn_ls, &N2_hs, &N2_ls, &N3n, - &BwSel); - si5324_dbg("N1_HS = %u\n", (unsigned int)N1_hs + 4); - si5324_dbg("NC1_LS = %u\n", (unsigned int)NCn_ls + 1); - si5324_dbg("N2_HS = %u\n", (unsigned int)N2_hs + 4); - si5324_dbg("N2_LS = %u\n", (unsigned int)N2_ls + 1); - si5324_dbg("N3 = %u\n", (unsigned int)N3n + 1); - si5324_dbg("actual rate = %u\n", actual_rate); - - /* remember actual clkout0 output rate */ - hwdata->drvdata->rate_clkout0 = rate; - - i = 0; - - // Free running mode or use a reference clock - buf[i] = 0; - // Enable free running mode - buf[i+1] = 0x54; - i += 2; - - // Loop bandwidth - buf[i] = 2; - buf[i+1] = (BwSel << 4) | 0x02; - i += 2; - - // Enable reference clock 2 in free running mode - buf[i] = 11; - //Enable input clock 2, Disable input clock 1 - buf[i+1] = 0x41; - i += 2; - - // N1_HS - buf[i] = 25; - buf[i+1] = N1_hs << 5; - i += 2; - - // NC1_LS - buf[i] = 31; - buf[i+1] = (u8)((NCn_ls & 0x000F0000) >> 16); - buf[i+2] = 32; - buf[i+3] = (u8)((NCn_ls & 0x0000FF00) >> 8); - buf[i+4] = 33; - buf[i+5] = (u8)( NCn_ls & 0x000000FF ); - i += 6; - - // N2_HS and N2_LS - buf[i] = 40; - buf[i+1] = (N2_hs << 5); - // N2_LS upper bits (same register as N2_HS) - buf[i+1] |= (u8)((N2_ls & 0x000F0000) >> 16); - buf[i+2] = 41; - buf[i+3] = (u8)((N2_ls & 0x0000FF00) >> 8); - buf[i+4] = 42; - buf[i+5] = (u8)( N2_ls & 0x000000FF ); - i += 6; - - // N32 (CLKIN2 or XTAL in FREERUNNING mode) - buf[i] = 46; - buf[i+2] = 47; - buf[i+4] = 48; - buf[i+1] = (u8)((N3n & 0x00070000) >> 16); - buf[i+3] = (u8)((N3n & 0x0000FF00) >> 8); - buf[i+5] = (u8)( N3n & 0x000000FF ); - i += 6; - - // Start calibration - buf[i] = 136; - buf[i+1] = 0x40; - i += 2; - - hwdata->drvdata->params.valid = 0; - // disable CKOUT1 output (bit 2 DSBL1_REG=1) - // disable CKOUT2 output (bit 3 DSBL2_REG=1) - //si5324_reg_write(hwdata->drvdata, 10, 0x0c); - si5324_reg_read(hwdata->drvdata, 0); - si5324_reg_read(hwdata->drvdata, 3); - si5324_reg_read(hwdata->drvdata, 4); - si5324_reg_read(hwdata->drvdata, 11); - si5324_reg_read(hwdata->drvdata, 21); - rc = si5324_bulk_scatter_write(hwdata->drvdata, 14, buf); - // enable CKOUT1 output (bit 2 DSBL1_REG=1) - // disable CKOUT2 output (bit 3 DSBL2_REG=1) - //si5324_reg_write(hwdata->drvdata, 10, 0x08); - -#if 0 - /* dump all registers */ - for (i = 0; i < 145; i++) - si5324_reg_read(hwdata->drvdata, i); -#endif - return rc; -} - -static const struct clk_ops si5324_clkout_ops = { - .prepare = si5324_clkout_prepare, - .unprepare = si5324_clkout_unprepare, - .recalc_rate = si5324_clkout_recalc_rate, - .round_rate = si5324_clkout_round_rate, - .set_rate = si5324_clkout_set_rate, -}; - -/* - * Si5324 i2c probe and DT - */ -#ifdef CONFIG_OF -static const struct of_device_id si5324_dt_ids[] = { - { .compatible = "silabs,si5319" }, - { .compatible = "silabs,si5324" }, - { .compatible = "silabs,si5328" }, - { } -}; -MODULE_DEVICE_TABLE(of, si5324_dt_ids); - -static int si5324_dt_parse(struct i2c_client *client) -{ - struct device_node *child, *np = client->dev.of_node; - struct si5324_platform_data *pdata; - struct property *prop; - const __be32 *p; - int num = 0; - u32 val; - - if (np == NULL) - return 0; - - pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - /* - * property silabs,pll-source : , [<..>] - * allow to selectively set pll source - */ - of_property_for_each_u32(np, "silabs,pll-source", prop, p, num) { - if (num >= 1) { - dev_err(&client->dev, - "invalid pll %d on pll-source prop\n", num); - return -EINVAL; - } - p = of_prop_next_u32(prop, p, &val); - if (!p) { - dev_err(&client->dev, - "missing pll-source for pll %d\n", num); - return -EINVAL; - } - - switch (val) { - case 0: - dev_dbg(&client->dev, "using xtal as parent for pll\n"); - pdata->pll_src = SI5324_PLL_SRC_XTAL; - break; - case 1: - dev_dbg(&client->dev, "using clkin1 as parent for pll\n"); - pdata->pll_src = SI5324_PLL_SRC_CLKIN1; - break; - case 2: - dev_dbg(&client->dev, "using clkin2 as parent for pll\n"); - pdata->pll_src = SI5324_PLL_SRC_CLKIN2; - break; - default: - dev_err(&client->dev, - "invalid parent %d for pll %d\n", val, num); - return -EINVAL; - } - } - /* per clkout properties */ - for_each_child_of_node(np, child) { - if (of_property_read_u32(child, "reg", &num)) { - dev_err(&client->dev, "missing reg property of %s\n", - child->name); - goto put_child; - } - - if (num >= 2) { - dev_err(&client->dev, "invalid clkout %d\n", num); - goto put_child; - } - - if (!of_property_read_u32(child, "silabs,drive-strength", - &val)) { - switch (val) { - case SI5324_DRIVE_2MA: - case SI5324_DRIVE_4MA: - case SI5324_DRIVE_6MA: - case SI5324_DRIVE_8MA: - pdata->clkout[num].drive = val; - break; - default: - dev_err(&client->dev, - "invalid drive strength %d for clkout %d\n", - val, num); - goto put_child; - } - } - - if (!of_property_read_u32(child, "silabs,disable-state", - &val)) { - switch (val) { - case 0: - pdata->clkout[num].disable_state = - SI5324_DISABLE_LOW; - break; - case 1: - pdata->clkout[num].disable_state = - SI5324_DISABLE_HIGH; - break; - case 2: - pdata->clkout[num].disable_state = - SI5324_DISABLE_FLOATING; - break; - case 3: - pdata->clkout[num].disable_state = - SI5324_DISABLE_NEVER; - break; - default: - dev_err(&client->dev, - "invalid disable state %d for clkout %d\n", - val, num); - goto put_child; - } - } - - if (!of_property_read_u32(child, "clock-frequency", &val)) { - dev_dbg(&client->dev, "clock-frequency = %u\n", val); - pdata->clkout[num].rate = val; - } - - pdata->clkout[num].pll_master = - of_property_read_bool(child, "silabs,pll-master"); - } - client->dev.platform_data = pdata; - - return 0; -put_child: - of_node_put(child); - return -EINVAL; -} -#else -static int si5324_dt_parse(struct i2c_client *client) -{ - return 0; -} -#endif /* CONFIG_OF */ - -static u8 instance = 0; - -static int si5324_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct si5324_platform_data *pdata; - struct si5324_driver_data *drvdata; - struct clk_init_data init; - struct clk *clk; - const char *parent_names[3]; - char inst_names[NUM_NAME_IDS][MAX_NAME_LEN]; - u8 val; - u8 num_parents, num_clocks; - int ret, n; - enum si53xx_variant variant = id->driver_data; - - if (variant > si5328) { - dev_err(&client->dev, "si53xx device tree entry do not indicate \ - presence of Si5319 or Si5324 or Si5328.\n"); - return -ENODEV; - } - - dev_info(&client->dev, "%s probed\n", si53xx_variant_name[variant]); - ret = si5324_dt_parse(client); - if (ret) - return ret; - - pdata = client->dev.platform_data; - if (!pdata) - return -EINVAL; - - drvdata = devm_kzalloc(&client->dev, sizeof(*drvdata), GFP_KERNEL); - if (drvdata == NULL) { - dev_err(&client->dev, "unable to allocate driver data\n"); - return -ENOMEM; - } - - drvdata->client = client; - drvdata->pxtal = devm_clk_get(&client->dev, "xtal"); - drvdata->pclkin1 = devm_clk_get(&client->dev, "clkin1"); - drvdata->pclkin2 = devm_clk_get(&client->dev, "clkin2"); - - if (PTR_ERR(drvdata->pxtal) == -EPROBE_DEFER || - PTR_ERR(drvdata->pclkin1) == -EPROBE_DEFER || - PTR_ERR(drvdata->pclkin2) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - drvdata->regmap = devm_regmap_init_i2c(client, &si5324_regmap_config); - if (IS_ERR(drvdata->regmap)) { - dev_err(&client->dev, "failed to allocate register map\n"); - return PTR_ERR(drvdata->regmap); - } - - i2c_set_clientdata(client, drvdata); - si5324_initialize(drvdata); - -#if (!defined(FORCE_BYPASS) || !FORCE_BYPASS) - /* setup input clock configuration */ - ret = _si5324_pll_reparent(drvdata, 0, pdata->pll_src); - if (ret) { - dev_err(&client->dev, - "failed to reparent pll to %d\n", - pdata->pll_src); - return ret; - } -#endif - - for (n = 0; n < 2; n++) { - - ret = _si5324_clkout_set_drive_strength(drvdata, n, - pdata->clkout[n].drive); - if (ret) { - dev_err(&client->dev, - "failed set drive strength of clkout%d to %d\n", - n, pdata->clkout[n].drive); - return ret; - } - - ret = _si5324_clkout_set_disable_state(drvdata, n, - pdata->clkout[n].disable_state); - if (ret) { - dev_err(&client->dev, - "failed set disable state of clkout%d to %d\n", - n, pdata->clkout[n].disable_state); - return ret; - } - } - - if (!IS_ERR(drvdata->pxtal)) { - si5324_dbg("Enabling xtal clock\n"); - clk_prepare_enable(drvdata->pxtal); - } - if (!IS_ERR(drvdata->pclkin1)) - clk_prepare_enable(drvdata->pclkin1); - if (!IS_ERR(drvdata->pclkin2)) - clk_prepare_enable(drvdata->pclkin2); - - /* create instance names by appending instance id */ - for (n = 0; n < 3; n++) { //clk_in - sprintf(inst_names[n], "%s_%d", si5324_input_names[n], instance); - } - sprintf(inst_names[3], "%s_%d", si5324_pll_name, instance); //pll - for (n = 0; n < 2; n++) { //clkout - sprintf(inst_names[n+4], "%s_%d", si5324_clkout_names[n], instance); - } - - /* register xtal input clock gate */ - memset(&init, 0, sizeof(init)); - init.name = inst_names[0]; - init.ops = &si5324_xtal_ops; - init.flags = 0; - if (!IS_ERR(drvdata->pxtal)) { - drvdata->pxtal_name = __clk_get_name(drvdata->pxtal); - init.parent_names = &drvdata->pxtal_name; - si5324_dbg("xtal parent name: %s\n", init.parent_names[0]); - init.num_parents = 1; - } - drvdata->xtal.init = &init; - clk = devm_clk_register(&client->dev, &drvdata->xtal); - if (IS_ERR(clk)) { - dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); - goto err_clk; - } - - /* register clkin1 input clock gate */ - memset(&init, 0, sizeof(init)); - init.name = inst_names[1]; - init.ops = &si5324_clkin_ops; - if (!IS_ERR(drvdata->pclkin1)) { - drvdata->pclkin1_name = __clk_get_name(drvdata->pclkin1); - init.parent_names = &drvdata->pclkin1_name; - init.num_parents = 1; - } - drvdata->clkin1.init = &init; - clk = devm_clk_register(&client->dev, &drvdata->clkin1); - if (IS_ERR(clk)) { - dev_err(&client->dev, "unable to register %s\n", - init.name); - ret = PTR_ERR(clk); - goto err_clk; - } - - /* register clkin2 input clock gate */ - memset(&init, 0, sizeof(init)); - init.name = inst_names[2]; - init.ops = &si5324_clkin_ops; - if (!IS_ERR(drvdata->pclkin2)) { - drvdata->pclkin2_name = __clk_get_name(drvdata->pclkin2); - init.parent_names = &drvdata->pclkin2_name; - init.num_parents = 1; - } - drvdata->clkin2.init = &init; - clk = devm_clk_register(&client->dev, &drvdata->clkin2); - if (IS_ERR(clk)) { - dev_err(&client->dev, "unable to register %s\n", - init.name); - ret = PTR_ERR(clk); - goto err_clk; - } - - /* Si5324 allows to mux xtal or clkin1 or clkin2 to PLL input */ - num_parents = 3; - parent_names[0] = inst_names[0]; - parent_names[1] = inst_names[1]; - parent_names[2] = inst_names[2]; - - /* register PLL */ - drvdata->pll.num = 0; - drvdata->pll.drvdata = drvdata; - drvdata->pll.hw.init = &init; - memset(&init, 0, sizeof(init)); - init.name = inst_names[3]; - init.ops = &si5324_pll_ops; - init.flags = 0; - init.flags |= CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE; - init.parent_names = parent_names; - init.num_parents = num_parents; - clk = devm_clk_register(&client->dev, &drvdata->pll.hw); - if (IS_ERR(clk)) { - dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); - goto err_clk; - } - - /* register clk multisync and clk out divider */ - num_clocks = 2; - num_parents = 1; - parent_names[0] = inst_names[3]; - - drvdata->clkout = devm_kzalloc(&client->dev, num_clocks * - sizeof(*drvdata->clkout), GFP_KERNEL); - - drvdata->onecell.clk_num = num_clocks; - drvdata->onecell.clks = devm_kzalloc(&client->dev, - num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL); - - if (WARN_ON(!drvdata->clkout) || (!drvdata->onecell.clks)) { - ret = -ENOMEM; - goto err_clk; - } - - for (n = 0; n < num_clocks; n++) { - drvdata->clkout[n].num = n; - drvdata->clkout[n].drvdata = drvdata; - drvdata->clkout[n].hw.init = &init; - memset(&init, 0, sizeof(init)); - init.name = inst_names[4+n]; - init.ops = &si5324_clkout_ops; - init.flags = 0; - init.flags |= CLK_SET_RATE_PARENT; - init.parent_names = parent_names; - init.num_parents = num_parents; - clk = devm_clk_register(&client->dev, &drvdata->clkout[n].hw); - if (IS_ERR(clk)) { - dev_err(&client->dev, "unable to register %s\n", - init.name); - ret = PTR_ERR(clk); - goto err_clk; - } - /* refer to output clock in onecell */ - drvdata->onecell.clks[n] = clk; - - /* set initial clkout rate */ - if (pdata->clkout[n].rate != 0) { - int ret; - si5324_dbg("Initializing clkout%d for DT specified frequency %d Hz.\n", n, pdata->clkout[n].rate); - ret = clk_set_rate(clk, pdata->clkout[n].rate); - if (ret != 0) { - dev_err(&client->dev, "Cannot set rate : %d\n", - ret); - } - } - } - - ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, - &drvdata->onecell); - if (ret) { - dev_err(&client->dev, "unable to add clk provider\n"); - goto err_clk; - } - - dev_info(&client->dev, "%s probe successful\n", si53xx_variant_name[variant]); - instance++; - return 0; - -err_clk: - if (!IS_ERR(drvdata->pxtal)) - clk_disable_unprepare(drvdata->pxtal); - if (!IS_ERR(drvdata->pclkin1)) - clk_disable_unprepare(drvdata->pclkin1); - if (!IS_ERR(drvdata->pclkin2)) - clk_disable_unprepare(drvdata->pclkin2); - return ret; -} - -static const struct i2c_device_id si5324_i2c_ids[] = { - { "si5319", si5319 }, - { "si5324", si5324 }, - { "si5328", si5328 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, si5324_i2c_ids); - -static struct i2c_driver si5324_driver = { - .driver = { - .name = "si5324", - .of_match_table = of_match_ptr(si5324_dt_ids), - }, - .probe = si5324_i2c_probe, - .id_table = si5324_i2c_ids, -}; -module_i2c_driver(si5324_driver); - -MODULE_AUTHOR("Leon Woestenberg "); -MODULE_DESCRIPTION("Silicon Labs Si5324 jitter attenuating clock multiplier driver"); -MODULE_LICENSE("GPL"); diff --git a/clk/clk-si5324.h b/clk/clk-si5324.h deleted file mode 100644 index 9e57495..0000000 --- a/clk/clk-si5324.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * clk-si5324.h: Silicon Laboratories Si5324A/B/C I2C Clock Generator - * - * Leon Woestenberg - * - * 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. - */ - -#ifndef _CLK_SI5324_H_ -#define _CLK_SI5324_H_ - -#define SI5324_BUS_BASE_ADDR 0x68 - -#define SI5324_REG0 0 -#define SI5324_REG0_FREE_RUN (1<<6) - -#define SI5324_CKSEL 3 - -#define SI5324_DSBL_CLKOUT 10 - -#define SI5324_POWERDOWN 11 -#define SI5324_PD_CK1 (1<<0) -#define SI5324_PD_CK2 (1<<1) - -/* output clock dividers */ -#define SI5324_N1_HS_OUTPUT_DIVIDER 25 -#define SI5324_NC1_LS_H 31 -#define SI5324_NC1_LS_M 32 -#define SI5324_NC1_LS_L 33 - -#define SI5324_NC2_LS_H 34 -#define SI5324_NC2_LS_M 35 -#define SI5324_NC2_LS_L 36 - -#define SI5324_RESET 136 -#define SI5324_RST_REG (1<<7) - -/* selects 2kHz to 710 MHz */ -#define SI5324_CLKIN_MIN_FREQ 2000 -#define SI5324_CLKIN_MAX_FREQ (710 * 1000 * 1000) - - -/* generates 2kHz to 945 MHz */ -#define SI5324_CLKOUT_MIN_FREQ 2000 -#define SI5324_CLKOUT_MAX_FREQ (945 * 1000 * 1000) - -/** - * The following constants define the limits of the divider settings. - */ -#define SI5324_N1_HS_MIN 6 /**< Minimum N1_HS setting (4 and 5 are for higher output frequencies than we support */ -#define SI5324_N1_HS_MAX 11 /**< Maximum N1_HS setting */ -#define SI5324_NC_LS_MIN 1 /**< Minimum NCn_LS setting (1 and even values) */ -#define SI5324_NC_LS_MAX 0x100000 /**< Maximum NCn_LS setting (1 and even values) */ -#define SI5324_N2_HS_MIN 4 /**< Minimum NC2_HS setting */ -#define SI5324_N2_HS_MAX 11 /**< Maximum NC2_HS setting */ -#define SI5324_N2_LS_MIN 2 /**< Minimum NC2_LS setting (even values only) */ -#define SI5324_N2_LS_MAX 0x100000 /**< Maximum NC2_LS setting (even values only) */ -#define SI5324_N3_MIN 1 /**< Minimum N3n setting */ -#define SI5324_N3_MAX 0x080000 /**< Maximum N3n setting */ - -#endif diff --git a/clk/include/si5324.h b/clk/include/si5324.h deleted file mode 100644 index 95d6ef5..0000000 --- a/clk/include/si5324.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Si5324A/B/C programmable clock generator platform_data. - */ - -#ifndef __LINUX_PLATFORM_DATA_SI5324_H__ -#define __LINUX_PLATFORM_DATA_SI5324_H__ - -/** - * enum si5324_pll_src - Si5324 pll clock source - * @SI5324_PLL_SRC_DEFAULT: default, do not change eeprom config - * @SI5324_PLL_SRC_XTAL: pll source clock is XTAL input - * @SI5324_PLL_SRC_CLKIN1: pll source clock is CLKIN1 input - * @SI5324_PLL_SRC_CLKIN2: pll source clock is CLKIN2 input - */ -enum si5324_pll_src { - SI5324_PLL_SRC_XTAL = 0, - SI5324_PLL_SRC_CLKIN1 = 1, - SI5324_PLL_SRC_CLKIN2 = 2, -}; - -/** - * enum si5324_drive_strength - Si5324 clock output drive strength - * @SI5324_DRIVE_DEFAULT: default, do not change eeprom config - * @SI5324_DRIVE_2MA: 2mA clock output drive strength - * @SI5324_DRIVE_4MA: 4mA clock output drive strength - * @SI5324_DRIVE_6MA: 6mA clock output drive strength - * @SI5324_DRIVE_8MA: 8mA clock output drive strength - */ -enum si5324_drive_strength { - SI5324_DRIVE_DEFAULT = 0, - SI5324_DRIVE_2MA = 2, - SI5324_DRIVE_4MA = 4, - SI5324_DRIVE_6MA = 6, - SI5324_DRIVE_8MA = 8, -}; - -/** - * enum si5324_disable_state - Si5324 clock output disable state - * @SI5324_DISABLE_DEFAULT: default, do not change eeprom config - * @SI5324_DISABLE_LOW: CLKx is set to a LOW state when disabled - * @SI5324_DISABLE_HIGH: CLKx is set to a HIGH state when disabled - * @SI5324_DISABLE_FLOATING: CLKx is set to a FLOATING state when - * disabled - * @SI5324_DISABLE_NEVER: CLKx is NEVER disabled - */ -enum si5324_disable_state { - SI5324_DISABLE_DEFAULT = 0, - SI5324_DISABLE_LOW, - SI5324_DISABLE_HIGH, - SI5324_DISABLE_FLOATING, - SI5324_DISABLE_NEVER, -}; - -/** - * struct si5324_clkout_config - Si5324 clock output configuration - * @clkout: clkout number - * @multisynth_src: multisynth source clock - * @clkout_src: clkout source clock - * @pll_master: if true, clkout can also change pll rate - * @drive: output drive strength - * @rate: initial clkout rate, or default if 0 - */ -struct si5324_clkout_config { - enum si5324_drive_strength drive; - enum si5324_disable_state disable_state; - bool pll_master; - unsigned long rate; -}; - -/** - * struct si5324_platform_data - Platform data for the Si5324 clock driver - * @clk_xtal: xtal input clock - * @clk_clkin: clkin input clock - * @pll_src: pll source clock setting - * @clkout: array of clkout configuration - */ -struct si5324_platform_data { - enum si5324_pll_src pll_src; - struct si5324_clkout_config clkout[2]; -}; - -#endif diff --git a/clk/si5324drv.c b/clk/si5324drv.c deleted file mode 100644 index 9e2a519..0000000 --- a/clk/si5324drv.c +++ /dev/null @@ -1,380 +0,0 @@ -#include -#include - -#include "si5324drv.h" - -#define xil_printf(format, ...) printk(KERN_INFO format, ## __VA_ARGS__) - -/*****************************************************************************/ -/** - * Find the closest rational approximation for the N2_LS/N3 fraction. - * - * @param f Holds the N2_LS/N3 fraction in 36.28 fixed point notation. - * @param md Holds the maximum denominator (N3) value allowed. - * @param num Will store the numinator (N2_LS) found. - * @param denom Will store the denominator (N3) found. - */ -void Si5324_RatApprox(u64 f, u64 md, u32 *num, u32 *denom) -{ - /* a: Continued fraction coefficients. */ - u64 a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 }; - u64 x, d, n = 1; - int i = 0; - - // Degenerate case: only n/1 solution allowed. Return trunc(f)/1. - if (md <= 1) { - *denom = 1; - *num = (u32)(f >> 28); - return; - } - - // Multiply fraction until there are no more digits after the decimal point - n <<= 28; - for (i = 0; i < 28; i++) { - if ((f & 0x1) == 0) { - n >>= 1; - f >>= 1; - } else { - break; - } - } - d = f; - - /* Continued fraction and check denominator each step */ - for (i = 0; i < 64; i++) { - a = n ? d / n : 0; - if (i && !a) { - break; - } - - x = d; - d = n; - n = x % n; - - x = a; - if (k[1] * a + k[0] >= md) { - x = (md - k[0]) / k[1]; - if (x * 2 >= a || k[1] >= md) { - i = 65; - } else { - break; - } - } - - h[2] = x * h[1] + h[0]; - h[0] = h[1]; - h[1] = h[2]; - k[2] = x * k[1] + k[0]; - k[0] = k[1]; - k[1] = k[2]; - } - *denom = (u32)k[1]; - *num = (u32)h[1]; -} - - -/*****************************************************************************/ -/** - * Search through the possible settings for the N2_LS parameter. Finds the best - * setting for N2_LS and N3n with the values for N1_HS, NCn_LS, and N2_HS - * already set in settings. - * - * @param settings Holds the settings up till now. - * @return 1 when the best possible result has been found. - * @note Private function. - */ -int Si5324_FindN2ls(si5324_settings_t *settings) { - u32 result = 0; - u64 f3_actual; - u64 fosc_actual; - u64 fout_actual; - u64 delta_fout; - u64 n2_ls_div_n3; - u32 mult; - - n2_ls_div_n3 = settings->fosc / (settings->fin >> 28) / settings->n2_hs / 2; - Si5324_RatApprox(n2_ls_div_n3, settings->n31_max, &(settings->n2_ls), &(settings->n31)); - settings->n2_ls *= 2; - // Rational approximation returns the smalles ratio possible. Upscaling - // might be needed when when one or both of the numbers are too low. - if (settings->n2_ls < settings->n2_ls_min) { - mult = settings->n2_ls_min / settings->n2_ls; - mult = (settings->n2_ls_min % settings->n2_ls) ? mult + 1 : mult; - settings->n2_ls *= mult; - settings->n31 *= mult; - } - if (settings->n31 < settings->n31_min) { - mult = settings->n31_min / settings->n31; - mult = (settings->n31_min % settings->n31) ? mult + 1 : mult; - settings->n2_ls *= mult; - settings->n31 *= mult; - } - if (SI5324_DEBUG) { - printk(KERN_INFO "Trying N2_LS = %d N3 = %d.\n", - settings->n2_ls, settings->n31); - } - // Check if N2_LS and N3 are within the required ranges - if ((settings->n2_ls < settings->n2_ls_min) || (settings->n2_ls > settings->n2_ls_max)) { - printk(KERN_INFO "N2_LS out of range.\n"); - } else if ((settings->n31 < settings->n31_min) || (settings->n31 > settings->n31_max)) { - printk(KERN_INFO "N3 out of range.\n"); - } - else { - // N2_LS and N3 values within range: check actual output frequency - f3_actual = settings->fin / settings->n31; - fosc_actual = f3_actual * settings->n2_hs * settings->n2_ls; - fout_actual = fosc_actual / (settings->n1_hs * settings->nc1_ls); - delta_fout = fout_actual - settings->fout; - // Check actual frequencies for validity - if ((f3_actual < ((u64)SI5324_F3_MIN) << 28) || (f3_actual > ((u64)SI5324_F3_MAX) << 28)) { - if (SI5324_DEBUG) { - printk(KERN_INFO "F3 frequency out of range.\n"); - } - } else if ((fosc_actual < ((u64)SI5324_FOSC_MIN) << 28) || (fosc_actual > ((u64)SI5324_FOSC_MAX) << 28)) { - if (SI5324_DEBUG) { - printk(KERN_INFO "Fosc frequency out of range.\n"); - } - } else if ((fout_actual < ((u64)SI5324_FOUT_MIN) << 28) || (fout_actual >((u64)SI5324_FOUT_MAX) << 28)) { - if (SI5324_DEBUG) { - printk(KERN_INFO "Fout frequency out of range.\n"); - } - } else { - if (SI5324_DEBUG) { - printk(KERN_INFO "Found solution: fout = %dHz delta = %dHz.\n", - (u32)(fout_actual >> 28), (u32)(delta_fout >> 28)); - printk(KERN_INFO " fosc = %dkHz f3 = %dHz.\n", - (u32)((fosc_actual >> 28) / 1000), (u32)(f3_actual >> 28)); - } - if (((u64)llabs(delta_fout)) < settings->best_delta_fout) { - // Found a better solution: remember this one! - if (SI5324_DEBUG) { - printk(KERN_INFO "This solution is the best yet!\n"); - } - settings->best_n1_hs = settings->n1_hs; - settings->best_nc1_ls = settings->nc1_ls; - settings->best_n2_hs = settings->n2_hs; - settings->best_n2_ls = settings->n2_ls; - settings->best_n3 = settings->n31; - settings->best_fout = fout_actual; - settings->best_delta_fout = llabs(delta_fout); - if (delta_fout == 0) { - // Best possible result found. Skip the rest of the possibilities. - result = 1; - } - } - } - } - return result; -} - - -/*****************************************************************************/ -/** - * Find a valid setting for N2_HS and N2_LS. Finds the best - * setting for N2_HS, N2_LS, and N3n with the values for N1_HS, and NCn_LS - * already set in settings. Iterates over all possibilities - * of N2_HS and then performs a binary search over the N2_LS values. - * - * @param settings Holds the settings up till now. - * @return 1 when the best possible result has been found. - * @note Private function. - */ -int Si5324_FindN2(si5324_settings_t *settings) { - u32 result; - - for (settings->n2_hs = SI5324_N2_HS_MAX; settings->n2_hs >= SI5324_N2_HS_MIN; settings->n2_hs--) { - if (SI5324_DEBUG) { - printk(KERN_INFO "Trying N2_HS = %d.\n", settings->n2_hs); - } - settings->n2_ls_min = (u32)(settings->fosc / ((u64)(SI5324_F3_MAX * settings->n2_hs) << 28)); - if (settings->n2_ls_min < SI5324_N2_LS_MIN) { - settings->n2_ls_min = SI5324_N2_LS_MIN; - } - settings->n2_ls_max = (u32)(settings->fosc / ((u64)(SI5324_F3_MIN * settings->n2_hs) << 28)); - if (settings->n2_ls_max > SI5324_N2_LS_MAX) { - settings->n2_ls_max = SI5324_N2_LS_MAX; - } - result = Si5324_FindN2ls(settings); - if (result) { - // Best possible result found. Skip the rest of the possibilities. - break; - } - } - return result; -} - - -/*****************************************************************************/ -/** - * Calculates the valid range for NCn_LS with the value for the output - * frequency and N1_HS already set in settings. - * - * @param settings Holds the input and output frequencies and the setting - * for N1_HS. - * @return -1 when there are no valid settings for NCn_LS, 0 otherwise. - * @note Private function. - */ -int Si5324_CalcNclsLimits(si5324_settings_t *settings) { - // Calculate limits for NCn_LS - settings->nc1_ls_min = settings->n1_hs_min / settings->n1_hs; - if (settings->nc1_ls_min < SI5324_NC_LS_MIN) { - settings->nc1_ls_min = SI5324_NC_LS_MIN; - } - // Make sure NC_ls_min is one or even - if ((settings->nc1_ls_min > 1) && ((settings->nc1_ls_min & 0x1) == 1)) { - settings->nc1_ls_min++; - } - settings->nc1_ls_max = settings->n1_hs_max / settings->n1_hs; - if (settings->nc1_ls_max > SI5324_NC_LS_MAX) { - settings->nc1_ls_max = SI5324_NC_LS_MAX; - } - // Make sure NC_ls_max is even - if ((settings->nc1_ls_max & 0x1) == 1) { - settings->nc1_ls_max--; - } - // Check if actual N1 is within limits - if ((settings->nc1_ls_max * settings->n1_hs < settings->n1_hs_min) || - (settings->nc1_ls_min * settings->n1_hs > settings->n1_hs_max)) { - // No valid NC_ls possible: take next N1_hs - return -1; - } - return 0; -} - - -/*****************************************************************************/ -/** - * Find a valid setting for NCn_LS that can deliver the correct output - * frequency. Assumes that the valid range is relatively small so a full search - * can be done (should be true for video clock frequencies). - * - * @param settings Holds the input and output frequencies, the setting for - * N1_HS, and the limits for NCn_LS. - * @return 1 when the best possible result has been found. - * @note Private function. - */ -int Si5324_FindNcls(si5324_settings_t *settings) { - u64 fosc_1; - u32 result; - - fosc_1 = settings->fout * settings->n1_hs; - for (settings->nc1_ls = settings->nc1_ls_min; settings->nc1_ls <= settings->nc1_ls_max;) { - settings->fosc = fosc_1 * settings->nc1_ls; - if (SI5324_DEBUG) { - printk(KERN_INFO "Trying NCn_LS = %d: fosc = %dkHz.\n", - settings->nc1_ls, (u32)((settings->fosc >> 28) / 1000)); - } - result = Si5324_FindN2(settings); - if (result) { - // Best possible result found. Skip the rest of the possibilities. - break; - } - if (settings->nc1_ls == 1) { - settings->nc1_ls++; - } else { - settings->nc1_ls += 2; - } - } - return result; -} - -/*****************************************************************************/ -/** - * Calculate the frequency settings for the desired output frequency. - * - * @param ClkInFreq contains the frequency of the input clock. - * @param ClkOutFreq contains the desired output clock frequency. - * @param N1_hs will be set to the value for the N1_HS register. - * @param NCn_ls will be set to the value for the NCn_LS register. - * @param N2_hs will be set to the value for the N2_HS register. - * @param N2_ls will be set to the value for the N2_LS register. - * @param N3n will be set to the value for the N3n register. - * @param BwSel will be set to the value for the BW_SEL register. - * - * @return SI5324_SUCCESS for success, SI5324_ERR_FREQ when the requested - * frequency cannot be generated. - * @note Private function. - *****************************************************************************/ -int Si5324_CalcFreqSettings(u32 ClkInFreq, u32 ClkOutFreq, u32 *ClkActual, - u8 *N1_hs, u32 *NCn_ls, - u8 *N2_hs, u32 *N2_ls, - u32 *N3n, u8 *BwSel) { - /* TBD */ - si5324_settings_t settings; - int result; - - settings.fin = (u64)ClkInFreq << 28; // 32.28 fixed point - settings.fout= (u64)ClkOutFreq << 28; // 32.28 fixed point - settings.best_delta_fout = settings.fout; // High frequency error to start with - - // Calculate some limits for N1_HS * NCn_LS and for N3 base on the input - // and output frequencies. - settings.n1_hs_min = (int)(SI5324_FOSC_MIN / ClkOutFreq); - if (settings.n1_hs_min < SI5324_N1_HS_MIN * SI5324_NC_LS_MIN) { - settings.n1_hs_min = SI5324_N1_HS_MIN * SI5324_NC_LS_MIN; - } - settings.n1_hs_max = (int)(SI5324_FOSC_MAX / ClkOutFreq); - if (settings.n1_hs_max > SI5324_N1_HS_MAX * SI5324_NC_LS_MAX) { - settings.n1_hs_max = SI5324_N1_HS_MAX * SI5324_NC_LS_MAX; - } - settings.n31_min = ClkInFreq / SI5324_F3_MAX; - if (settings.n31_min < SI5324_N3_MIN) { - settings.n31_min = SI5324_N3_MIN; - } - settings.n31_max = ClkInFreq / SI5324_F3_MIN; - if (settings.n31_max > SI5324_N3_MAX) { - settings.n31_max = SI5324_N3_MAX; - } - // Find a valid oscillator frequency with the highest setting of N1_HS - // possible (reduces power) - for (settings.n1_hs = SI5324_N1_HS_MAX; settings.n1_hs >= SI5324_N1_HS_MIN; settings.n1_hs--) { - if (SI5324_DEBUG) { - printk(KERN_INFO "Trying N1_HS = %d.\n", settings.n1_hs); - } - result = Si5324_CalcNclsLimits(&settings); - if (result) { - if (SI5324_DEBUG) { - printk(KERN_INFO "No valid settings for NCn_LS.\n"); - } - continue; - } - result = Si5324_FindNcls(&settings); - if (result) { - // Best possible result found. Skip the rest of the possibilities. - break; - } - } - - if(SI5324_DEBUG) { - printk(KERN_INFO "Si5324: settings.best_delta_fout = %llu\n", (unsigned long long)settings.best_delta_fout); - printk(KERN_INFO "Si5324: settings.fout = %llu\n", (unsigned long long)settings.fout); - } - - if (settings.best_delta_fout == settings.fout) { - if (1 || SI5324_DEBUG) { - printk(KERN_INFO "Si5324: ERROR: No valid settings found."); - } - return SI5324_ERR_FREQ; - } - if (SI5324_DEBUG) { - printk(KERN_INFO "Si5324: Found solution: fout = %dHz.\n", - (u32)(settings.best_fout >> 28)); - } - - // Post processing: convert temporary values to actual register settings - *N1_hs = (u8)settings.best_n1_hs - 4; - *NCn_ls = settings.best_nc1_ls - 1; - *N2_hs = (u8)settings.best_n2_hs - 4; - *N2_ls = settings.best_n2_ls - 1; - *N3n = settings.best_n3 - 1; - /* How must the bandwidth selection be determined? Not all settings will - * be valid. - refclk 2, 0xA2, // BWSEL_REG=1010 (?) - free running 2, 0x42, // BWSEL_REG=0100 (?) - */ - *BwSel = 6; //4 - - if (ClkActual) *ClkActual = (settings.best_fout >> 28); - return SI5324_SUCCESS; - -} diff --git a/clk/si5324drv.h b/clk/si5324drv.h deleted file mode 100644 index dccc7df..0000000 --- a/clk/si5324drv.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2014 Xilinx, Inc. All rights reserved. - * - * Xilinx, Inc. - * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A - * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS - * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR - * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION - * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE - * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. - * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO - * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO - * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE - * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -/*****************************************************************************/ -/** -* -* @file si5324drv.h -* -* This file contains definitions for low-level driver functions for -* controlling the SiliconLabs Si5324 clock generator as mounted on the KC705 -* demo board. -* The user should refer to the hardware device specification for more details -* of the device operation. -* -*
-* MODIFICATION HISTORY:
-*
-* Ver   Who  Date        Changes
-* ----- --- ----------   -----------------------------------------------
-* 1.00  hf  2014/10/10   First release
-* 
-* -******************************************************************************/ - -#ifndef SI5324DRV_H_ -#define SI5324DRV_H_ - -#include - - -/****************************************************************************** - * User settable defines that depend on the specific board design. - * The defaults are for the Xilinx KC705 board. - *****************************************************************************/ - -/** - * The frequency of the crystal connected to the XA/XB pins of the Si5324 in Hz. - */ -#define SI5324_XTAL_FREQ 114285000 - - -/****************************************************************************** - * Defines independent on the specific board design. Should not be changed. - *****************************************************************************/ - -/** - * Debug output enable. Set to TRUE to enable debug prints, - * to FALSE to disable debug prints. - */ -#define SI5324_DEBUG FALSE - -/** - * The following constants are error codes generated by the functions in - * this driver. - */ -#define SI5324_SUCCESS 0 /**< Operation was successful */ -#define SI5324_ERR_IIC -1 /**< IIC error occurred */ -#define SI5324_ERR_FREQ -2 /**< Could not calculate frequency setting */ -#define SI5324_ERR_PARM -3 /**< Invalid parameter */ - -/** - * The following constants define the clock input select values. - */ -#define SI5324_CLKSRC_CLK1 1 /**< Use clock input 1 */ -#define SI5324_CLKSRC_CLK2 2 /**< Use clock input 2 */ -#define SI5324_CLKSRC_XTAL 3 /**< Use crystal (free running mode) */ - -/** - * The following constants define the limits of the Si5324 frequencies. - */ -#define SI5324_FOSC_MIN 4850000000 /**< Minimum oscillator frequency */ -#define SI5324_FOSC_MAX 5670000000 /**< Maximum oscillator frequency */ -#define SI5324_F3_MIN 10000 // 2000 /**< Minimum phase detector frequency */ -#define SI5324_F3_MAX 2000000 /**< Maximum phase detector frequency */ -#define SI5324_FIN_MIN 2000 /**< Minimum input frequency */ -#define SI5324_FIN_MAX 710000000 /**< Maximum input frequency */ -#define SI5324_FOUT_MIN 2000 /**< Minimum output frequency */ -#define SI5324_FOUT_MAX 945000000 /**< Maximum output frequency */ - -/** - * The following constants define the limits of the divider settings. - */ -#define SI5324_N1_HS_MIN 6 /**< Minimum N1_HS setting (4 and 5 are for higher output frequencies than we support */ -#define SI5324_N1_HS_MAX 11 /**< Maximum N1_HS setting */ -#define SI5324_NC_LS_MIN 1 /**< Minimum NCn_LS setting (1 and even values) */ -#define SI5324_NC_LS_MAX 0x100000 /**< Maximum NCn_LS setting (1 and even values) */ -#define SI5324_N2_HS_MIN 4 /**< Minimum NC2_HS setting */ -#define SI5324_N2_HS_MAX 11 /**< Maximum NC2_HS setting */ -#define SI5324_N2_LS_MIN 2 /**< Minimum NC2_LS setting (even values only) */ -#define SI5324_N2_LS_MAX 0x100000 /**< Maximum NC2_LS setting (even values only) */ -#define SI5324_N3_MIN 1 /**< Minimum N3n setting */ -#define SI5324_N3_MAX 0x080000 /**< Maximum N3n setting */ - - -typedef struct { - // Current Si5342 parameters - - /* high-speed output divider */ - u32 n1_hs_min; - u32 n1_hs_max; - u32 n1_hs; - - /* low-speed output divider for clkout1 */ - u32 nc1_ls_min; - u32 nc1_ls_max; - u32 nc1_ls; - - /* low-speed output divider for clkout2 */ - u32 nc2_ls_min; - u32 nc2_ls_max; - u32 nc2_ls; - - /* high-speed feedback divider (PLL multiplier) */ - u32 n2_hs; - /* low-speed feedback divider (PLL multiplier) */ - u32 n2_ls_min; - u32 n2_ls_max; - u32 n2_ls; - - /* input divider for clk1 */ - u32 n31_min; - u32 n31_max; - u32 n31; - - // Current frequencies (fixed point 36.28 notation) - u64 fin; - u64 fout; - u64 fosc; - // Best settings found - u64 best_delta_fout; - u64 best_fout; - u32 best_n1_hs; - u32 best_nc1_ls; - u32 best_n2_hs; - u32 best_n2_ls; - u32 best_n3; -} si5324_settings_t; - -int Si5324_CalcFreqSettings(u32 ClkInFreq, u32 ClkOutFreq, u32 *ClkActual, - u8 *N1_hs, u32 *NCn_ls, - u8 *N2_hs, u32 *N2_ls, - u32 *N3n, u8 *BwSel); - -#endif /* SI5324DRV_H_ */ diff --git a/hdmi/Makefile b/hdmi/Makefile index 6310f01..83f6f50 100644 --- a/hdmi/Makefile +++ b/hdmi/Makefile @@ -3,6 +3,7 @@ obj-m += xilinx-vphy.o xilinx-hdmi-rx.o xilinx-hdmi-tx.o # in same cases only used to check against presence, i.e. >0, actual number is not used ccflags-y := -DXPAR_XVPHY_NUM_INSTANCES=4 +ccflags-y += -DXPAR_XHDMIPHY1_NUM_INSTANCES=4 ccflags-y += -DXPAR_XV_HDMIRXSS_NUM_INSTANCES=4 ccflags-y += -DXPAR_XV_HDMITXSS_NUM_INSTANCES=4 ccflags-y += -DXPAR_XV_HDMIRX_NUM_INSTANCES=4 @@ -12,6 +13,10 @@ ccflags-y += -DXPAR_XVTC_NUM_INSTANCES=4 ccflags-y += -DXPAR_VPHY_0_TRANSCEIVER=5 ccflags-y += -DXPAR_VPHY_0_RX_PROTOCOL=1 ccflags-y += -DXPAR_VPHY_0_TX_PROTOCOL=1 +ccflags-y += -DXPAR_HDMIPHY1_0_TRANSCEIVER=7 +# Below two parameters are notused anywhere in the code +ccflags-y += -DXPAR_HDMIPHY1_0_RX_PROTOCOL=1 +ccflags-y += -DXPAR_HDMIPHY1_0_TX_PROTOCOL=1 ccflags-y += -DXPAR_XV_HDMIRX_0_DEVICE_ID=0 ccflags-y += -DXPAR_XV_HDMITX_0_DEVICE_ID=0 @@ -37,7 +42,7 @@ xilinx-hdmi-rx-objs := xilinx-hdmirx.o # the C API around the IP registers CFLAGS_xilinx-hdmirx.o += -I$(src)/xilinx-hdmi-rx/ -CFLAGS_xilinx-hdmirx.o += -I$(src)/include/ -Idrivers/media/platform/xilinx/ +CFLAGS_xilinx-hdmirx.o += -I$(src)/include/ xilinx-hdmi-rx-objs += xilinx-hdmi-rx/xv_hdmirx.o xilinx-hdmi-rx-objs += xilinx-hdmi-rx/xv_hdmirx_sinit.o xilinx-hdmi-rx-objs += xilinx-hdmi-rx/xv_hdmirx_intr.o @@ -45,6 +50,7 @@ xilinx-hdmi-rx-objs += xilinx-hdmi-rx/xv_hdmirxss.o xilinx-hdmi-rx-objs += xilinx-hdmi-rx/xv_hdmirxss_log.o xilinx-hdmi-rx-objs += xilinx-hdmi-rx/xv_hdmirxss_coreinit.o xilinx-hdmi-rx-objs += xilinx-hdmi-rx/xv_hdmirxss_hdcp.o +xilinx-hdmi-rx-objs += xlnx_hdmirx_audio.o # DRM (HDMI TX) xilinx-hdmi-tx-objs := xilinx_drm_hdmi.o @@ -63,7 +69,7 @@ xilinx-hdmi-tx-objs += xilinx-hdmi-tx/xv_hdmitxss_hdcp.o xilinx-hdmi-tx-objs += xilinx-hdmi-tx/xvtc.o xilinx-hdmi-tx-objs += xilinx-hdmi-tx/xvtc_intr.o xilinx-hdmi-tx-objs += xilinx-hdmi-tx/xvtc_sinit.o - +xilinx-hdmi-tx-objs += xlnx_hdmitx_audio.o # PHY (HDMI RX/TX) xilinx-vphy-objs := phy-vphy.o @@ -81,6 +87,15 @@ xilinx-vphy-objs += phy-xilinx-vphy/xvphy_hdmi_intr.o xilinx-vphy-objs += phy-xilinx-vphy/xvphy_intr.o xilinx-vphy-objs += phy-xilinx-vphy/xvphy_log.o xilinx-vphy-objs += phy-xilinx-vphy/xvphy_sinit.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1_i.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1_gtye5.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1_mmcme5.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1_hdmi.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1_hdmi_intr.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1_intr.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1_log.o +xilinx-vphy-objs += phy-xilinx-vphy/xhdmiphy1_sinit.o xilinx-vphy-objs += phy-xilinx-vphy/xvidc.o xilinx-vphy-objs += phy-xilinx-vphy/xvidc_timings_table.o diff --git a/hdmi/include/linux/phy/phy-vphy.h b/hdmi/include/linux/phy/phy-vphy.h index edb4e1d..8f19725 100644 --- a/hdmi/include/linux/phy/phy-vphy.h +++ b/hdmi/include/linux/phy/phy-vphy.h @@ -20,11 +20,12 @@ /* @TODO change directory name on production release */ #include "xvphy.h" +#include "xhdmiphy1.h" struct phy; /* VPHY is built (either as module or built-in) */ -extern XVphy *xvphy_get_xvphy(struct phy *phy); +extern void *xvphy_get_xvphy(struct phy *phy); extern void xvphy_mutex_lock(struct phy *phy); extern void xvphy_mutex_unlock(struct phy *phy); extern int xvphy_do_something(struct phy *phy); diff --git a/hdmi/phy-vphy.c b/hdmi/phy-vphy.c index 0b083a3..2fd42f6 100644 --- a/hdmi/phy-vphy.c +++ b/hdmi/phy-vphy.c @@ -43,6 +43,8 @@ /* baseline driver includes */ #include "phy-xilinx-vphy/xvphy.h" #include "phy-xilinx-vphy/xvphy_i.h" +#include "phy-xilinx-vphy/xhdmiphy1.h" +#include "phy-xilinx-vphy/xhdmiphy1_i.h" /* common RX/TX */ #include "phy-xilinx-vphy/xdebug.h" @@ -61,6 +63,8 @@ #include "phy-xilinx-vphy/xv_hdmic_vsif.h" #define XVPHY_DRU_REF_CLK_HZ 156250000 +/* TODO - [Versal] - This needs to be changed for versal */ +#define XHDMIPHY1_DRU_REF_CLK_HZ 200000000 #define hdmi_mutex_lock(x) mutex_lock(x) #define hdmi_mutex_unlock(x) mutex_unlock(x) @@ -100,29 +104,36 @@ struct xvphy_dev { /* virtual remapped I/O memory */ void __iomem *iomem; int irq; - /* protects the XVphy baseline against concurrent access */ + /* protects the XVphy/XHdmiphy1 baseline against concurrent access */ struct mutex xvphy_mutex; struct xvphy_lane *lanes[4]; /* bookkeeping for the baseline subsystem driver instance */ XVphy xvphy; + XHdmiphy1 xgtphy; /* AXI Lite clock drives the clock detector */ struct clk *axi_lite_clk; /* NI-DRU clock input */ - struct clk *clkp; + struct clk *dru_clk; + /* If Video Phy flag */ + u32 isvphy; }; /* given the (Linux) phy handle, return the xvphy */ -XVphy *xvphy_get_xvphy(struct phy *phy) +void *xvphy_get_xvphy(struct phy *phy) { struct xvphy_lane *vphy_lane = phy_get_drvdata(phy); struct xvphy_dev *vphy_dev = vphy_lane->data; - return &vphy_dev->xvphy; + + if (vphy_dev->isvphy) + return (void *)&vphy_dev->xvphy; + + return (void *)&vphy_dev->xgtphy; } EXPORT_SYMBOL_GPL(xvphy_get_xvphy); /* given the (Linux) phy handle, enter critical section of xvphy baseline code - * XVphy functions must be called with mutex acquired to prevent concurrent access - * by XVphy and upper-layer video protocol drivers */ + * XVphy/XHdmiphy1 functions must be called with mutex acquired to prevent concurrent access + * by XVphy/XHdmiphy1 and upper-layer video protocol drivers */ void xvphy_mutex_lock(struct phy *phy) { struct xvphy_lane *vphy_lane = phy_get_drvdata(phy); @@ -159,16 +170,60 @@ EXPORT_SYMBOL_GPL(XVphy_IsBonded); EXPORT_SYMBOL_GPL(XVphy_ClkDetFreqReset); EXPORT_SYMBOL_GPL(XVphy_ClkDetGetRefClkFreqHz); -static irqreturn_t xvphy_irq_handler(int irq, void *dev_id) -{ - struct xvphy_dev *vphydev; +/* XHdmiphy1 functions must be called with mutex acquired to prevent concurrent access + * by XHdmiphy1 and upper-layer video protocol drivers */ +EXPORT_SYMBOL_GPL(XHdmiphy1_GetPllType); +EXPORT_SYMBOL_GPL(XHdmiphy1_IBufDsEnable); +EXPORT_SYMBOL_GPL(XHdmiphy1_SetHdmiCallback); +EXPORT_SYMBOL_GPL(XHdmiphy1_HdmiCfgCalcMmcmParam); +EXPORT_SYMBOL_GPL(XHdmiphy1_MmcmStart); +EXPORT_SYMBOL_GPL(XHdmiphy1_HdmiDebugInfo); +EXPORT_SYMBOL_GPL(XHdmiphy1_RegisterDebug); +EXPORT_SYMBOL_GPL(XHdmiphy1_LogShow); +EXPORT_SYMBOL_GPL(XHdmiphy1_DruGetRefClkFreqHz); +EXPORT_SYMBOL_GPL(XHdmiphy1_GetLineRateHz); - vphydev = (struct xvphy_dev *)dev_id; - if (!vphydev) - return IRQ_NONE; +/* exclusively required by TX */ +EXPORT_SYMBOL_GPL(XHdmiphy1_Clkout1OBufTdsEnable); +EXPORT_SYMBOL_GPL(XHdmiphy1_SetHdmiTxParam); +//EXPORT_SYMBOL_GPL(XHdmiphy1_IsBonded); +EXPORT_SYMBOL_GPL(XHdmiphy1_ClkDetFreqReset); +EXPORT_SYMBOL_GPL(XHdmiphy1_ClkDetGetRefClkFreqHz); + +static void xvphy_intr_disable(struct xvphy_dev *vphydev) +{ + if (vphydev->isvphy) + XVphy_IntrDisable(&vphydev->xvphy, XVPHY_INTR_HANDLER_TYPE_TXRESET_DONE | + XVPHY_INTR_HANDLER_TYPE_RXRESET_DONE | + XVPHY_INTR_HANDLER_TYPE_CPLL_LOCK | + XVPHY_INTR_HANDLER_TYPE_QPLL0_LOCK | + XVPHY_INTR_HANDLER_TYPE_TXALIGN_DONE | + XVPHY_INTR_HANDLER_TYPE_QPLL1_LOCK | + XVPHY_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE | + XVPHY_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE | + XVPHY_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE | + XVPHY_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE | + XVPHY_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT | + XVPHY_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); + else + XHdmiphy1_IntrDisable(&vphydev->xgtphy, XHDMIPHY1_INTR_HANDLER_TYPE_TXRESET_DONE | + XHDMIPHY1_INTR_HANDLER_TYPE_RXRESET_DONE | + XHDMIPHY1_INTR_HANDLER_TYPE_LCPLL_LOCK | + XHDMIPHY1_INTR_HANDLER_TYPE_RPLL_LOCK | + XHDMIPHY1_INTR_HANDLER_TYPE_TX_GPO_RISING_EDGE | + XHDMIPHY1_INTR_HANDLER_TYPE_RX_GPO_RISING_EDGE | + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE | + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE | + XHDMIPHY1_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE | + XHDMIPHY1_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE | + XHDMIPHY1_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT | + XHDMIPHY1_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); +} - /* disable interrupts in the VPHY, they are re-enabled once serviced */ - XVphy_IntrDisable(&vphydev->xvphy, XVPHY_INTR_HANDLER_TYPE_TXRESET_DONE | +static void xvphy_intr_enable(struct xvphy_dev *vphydev) +{ + if (vphydev->isvphy) + XVphy_IntrEnable(&vphydev->xvphy, XVPHY_INTR_HANDLER_TYPE_TXRESET_DONE | XVPHY_INTR_HANDLER_TYPE_RXRESET_DONE | XVPHY_INTR_HANDLER_TYPE_CPLL_LOCK | XVPHY_INTR_HANDLER_TYPE_QPLL0_LOCK | @@ -176,8 +231,35 @@ static irqreturn_t xvphy_irq_handler(int irq, void *dev_id) XVPHY_INTR_HANDLER_TYPE_QPLL1_LOCK | XVPHY_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE | XVPHY_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE | + XVPHY_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE | + XVPHY_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE | XVPHY_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT | XVPHY_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); + else + XHdmiphy1_IntrEnable(&vphydev->xgtphy, XHDMIPHY1_INTR_HANDLER_TYPE_TXRESET_DONE | + XHDMIPHY1_INTR_HANDLER_TYPE_RXRESET_DONE | + XHDMIPHY1_INTR_HANDLER_TYPE_LCPLL_LOCK | + XHDMIPHY1_INTR_HANDLER_TYPE_RPLL_LOCK | + XHDMIPHY1_INTR_HANDLER_TYPE_TX_GPO_RISING_EDGE | + XHDMIPHY1_INTR_HANDLER_TYPE_RX_GPO_RISING_EDGE | + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE | + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE | + XHDMIPHY1_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE | + XHDMIPHY1_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE | + XHDMIPHY1_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT | + XHDMIPHY1_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); +} + +static irqreturn_t xvphy_irq_handler(int irq, void *dev_id) +{ + struct xvphy_dev *vphydev; + + vphydev = (struct xvphy_dev *)dev_id; + if (!vphydev) + return IRQ_NONE; + + /* Disable interrupts in the VPHY, they are re-enabled once serviced */ + xvphy_intr_disable(vphydev); return IRQ_WAKE_THREAD; } @@ -194,24 +276,23 @@ static irqreturn_t xvphy_irq_thread(int irq, void *dev_id) /* call baremetal interrupt handler with mutex locked */ hdmi_mutex_lock(&vphydev->xvphy_mutex); - IntrStatus = XVphy_ReadReg(vphydev->xvphy.Config.BaseAddr, XVPHY_INTR_STS_REG); - dev_dbg(vphydev->dev,"XVphy IntrStatus = 0x%08x\n", IntrStatus); + if (vphydev->isvphy) { + IntrStatus = XVphy_ReadReg(vphydev->xvphy.Config.BaseAddr, XVPHY_INTR_STS_REG); + dev_dbg(vphydev->dev,"XVphy IntrStatus = 0x%08x\n", IntrStatus); + } else { + IntrStatus = XHdmiphy1_ReadReg(vphydev->xgtphy.Config.BaseAddr, XHDMIPHY1_INTR_STS_REG); + dev_dbg(vphydev->dev,"XHdmiphy1 IntrStatus = 0x%08x\n", IntrStatus); + } /* handle pending interrupts */ - XVphy_InterruptHandler(&vphydev->xvphy); + if (vphydev->isvphy) + XVphy_InterruptHandler(&vphydev->xvphy); + else + XHdmiphy1_InterruptHandler(&vphydev->xgtphy); hdmi_mutex_unlock(&vphydev->xvphy_mutex); - /* enable interrupt requesting in the VPHY */ - XVphy_IntrEnable(&vphydev->xvphy, XVPHY_INTR_HANDLER_TYPE_TXRESET_DONE | - XVPHY_INTR_HANDLER_TYPE_RXRESET_DONE | - XVPHY_INTR_HANDLER_TYPE_CPLL_LOCK | - XVPHY_INTR_HANDLER_TYPE_QPLL0_LOCK | - XVPHY_INTR_HANDLER_TYPE_TXALIGN_DONE | - XVPHY_INTR_HANDLER_TYPE_QPLL1_LOCK | - XVPHY_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE | - XVPHY_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE | - XVPHY_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT | - XVPHY_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); + /* Enable interrupt requesting in the VPHY */ + xvphy_intr_enable(vphydev); return IRQ_HANDLED; } @@ -224,7 +305,10 @@ static irqreturn_t xvphy_irq_thread(int irq, void *dev_id) */ static int xvphy_phy_init(struct phy *phy) { - printk(KERN_INFO "xvphy_phy_init(%p).\n", phy); + struct xvphy_lane *vphy_lane = phy_get_drvdata(phy); + struct xvphy_dev *vphy_dev = vphy_lane->data; + + dev_dbg(vphy_dev->dev, "xvphy_phy_init(%p).\n", phy); return 0; } @@ -282,6 +366,7 @@ static struct phy *xvphy_xlate(struct device *dev, /* Local Global table for phy instance(s) configuration settings */ XVphy_Config XVphy_ConfigTable[XPAR_XVPHY_NUM_INSTANCES]; +XHdmiphy1_Config XHdmiphy1_ConfigTable[XPAR_XHDMIPHY1_NUM_INSTANCES]; static struct phy_ops xvphy_phyops = { .init = xvphy_phy_init, @@ -292,99 +377,210 @@ static int instance = 0; /* TX uses [1, 127], RX uses [128, 254] and VPHY uses [256, ...]. Note that 255 is used for not-present. */ #define VPHY_DEVICE_ID_BASE 256 -static int vphy_parse_of(struct xvphy_dev *vphydev, XVphy_Config *c) +static int vphy_parse_of(struct xvphy_dev *vphydev, void *c) { struct device *dev = vphydev->dev; struct device_node *node = dev->of_node; int rc; u32 val; bool has_err_irq; + XVphy_Config *vphycfg = (XVphy_Config *)c; + XHdmiphy1_Config *xgtphycfg = (XHdmiphy1_Config *)c; rc = of_property_read_u32(node, "xlnx,transceiver-type", &val); - if (rc < 0) - goto error_dt; - c->XcvrType = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,transceiver-type not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->XcvrType = val; + else + xgtphycfg->XcvrType = val; rc = of_property_read_u32(node, "xlnx,tx-buffer-bypass", &val); - if (rc < 0) - goto error_dt; - c->TxBufferBypass = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,tx-buffer-bypass not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->TxBufferBypass = val; + else + xgtphycfg->TxBufferBypass = val; rc = of_property_read_u32(node, "xlnx,input-pixels-per-clock", &val); - if (rc < 0) - goto error_dt; - c->Ppc = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,input-pixels-per-clock not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->Ppc = val; + else + xgtphycfg->Ppc = val; rc = of_property_read_u32(node, "xlnx,nidru", &val); - if (rc < 0) - goto error_dt; - c->DruIsPresent = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,nidru not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->DruIsPresent = val; + else + xgtphycfg->DruIsPresent = val; rc = of_property_read_u32(node, "xlnx,nidru-refclk-sel", &val); - if (rc < 0) - goto error_dt; - c->DruRefClkSel = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,nidru-refclk-sel not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->DruRefClkSel = val; + else + xgtphycfg->DruRefClkSel = val; rc = of_property_read_u32(node, "xlnx,rx-no-of-channels", &val); - if (rc < 0) - goto error_dt; - c->RxChannels = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,rx-no-of-channels not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->RxChannels = val; + else + xgtphycfg->RxChannels = val; rc = of_property_read_u32(node, "xlnx,tx-no-of-channels", &val); - if (rc < 0) - goto error_dt; - c->TxChannels = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,tx-no-of-channels not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->TxChannels = val; + else + xgtphycfg->TxChannels = val; rc = of_property_read_u32(node, "xlnx,rx-protocol", &val); - if (rc < 0) - goto error_dt; - c->RxProtocol = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,rx-protocol not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->RxProtocol = val; + else + xgtphycfg->RxProtocol = val; rc = of_property_read_u32(node, "xlnx,tx-protocol", &val); - if (rc < 0) - goto error_dt; - c->TxProtocol = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,tx-protocol not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->TxProtocol = val; + else + xgtphycfg->TxProtocol = val; rc = of_property_read_u32(node, "xlnx,rx-refclk-sel", &val); - if (rc < 0) - goto error_dt; - c->RxRefClkSel = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,rx-refclk-sel not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->RxRefClkSel = val; + else + xgtphycfg->RxRefClkSel = val; rc = of_property_read_u32(node, "xlnx,tx-refclk-sel", &val); - if (rc < 0) - goto error_dt; - c->TxRefClkSel = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,tx-refclk-sel not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->TxRefClkSel = val; + else + xgtphycfg->TxRefClkSel = val; rc = of_property_read_u32(node, "xlnx,rx-pll-selection", &val); - if (rc < 0) - goto error_dt; - c->RxSysPllClkSel = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,rx-pll-selection not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->RxSysPllClkSel = val; + else + xgtphycfg->RxSysPllClkSel = val; rc = of_property_read_u32(node, "xlnx,tx-pll-selection", &val); - if (rc < 0) - goto error_dt; - c->TxSysPllClkSel = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,tx-pll-selection not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->TxSysPllClkSel = val; + else + xgtphycfg->TxSysPllClkSel = val; rc = of_property_read_u32(node, "xlnx,hdmi-fast-switch", &val); - if (rc < 0) - goto error_dt; - c->HdmiFastSwitch = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,hdmi-fast-switch not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->HdmiFastSwitch = val; + else + xgtphycfg->HdmiFastSwitch = val; rc = of_property_read_u32(node, "xlnx,transceiver-width", &val); - if (rc < 0) - goto error_dt; - c->TransceiverWidth = val; + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,transceiver-width not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->TransceiverWidth = val; + else + xgtphycfg->TransceiverWidth = val; has_err_irq = false; has_err_irq = of_property_read_bool(node, "xlnx,err-irq-en"); - c->ErrIrq = has_err_irq; - return 0; + if (vphydev->isvphy) + vphycfg->ErrIrq = has_err_irq; + else + xgtphycfg->ErrIrq = has_err_irq; + + rc = of_property_read_u32(node, "xlnx,use-gt-ch4-hdmi", &val); + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,use-gt-ch4-hdmi not specified"); + return -EINVAL; + } + if (vphydev->isvphy) + vphycfg->UseGtAsTxTmdsClk = val; + else + xgtphycfg->UseGtAsTxTmdsClk = val; + + if (!vphydev->isvphy) { + rc = of_property_read_u32(node, "xlnx,rx-frl-refclk-sel", &val); + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,rx-frl-refclk-sel not specified"); + return -EINVAL; + } + xgtphycfg->RxFrlRefClkSel = val; -error_dt: - dev_err(vphydev->dev, "Error parsing device tree"); - return -EINVAL; + rc = of_property_read_u32(node, "xlnx,tx-frl-refclk-sel", &val); + if (rc < 0) { + dev_err(vphydev->dev, "Error parsing device tree: xlnx,tx-frl-refclk-sel not specified"); + return -EINVAL; + } + xgtphycfg->TxFrlRefClkSel = val; + } + + return 0; } +/* Match table for of_platform binding */ +static const struct of_device_id xvphy_of_match[] = { + { .compatible = "xlnx,hdmi-gt-controller-1.0" }, + { .compatible = "xlnx,vid-phy-controller-2.2" }, + { /* end of table */ }, +}; +MODULE_DEVICE_TABLE(of, xvphy_of_match); + /** * xvphy_probe - The device probe function for driver initialization. * @pdev: pointer to the platform device structure. @@ -407,7 +603,10 @@ static int xvphy_probe(struct platform_device *pdev) u32 Data; u16 DrpVal; - dev_info(&pdev->dev, "probed\n"); + void __iomem *iomem1; + const struct of_device_id *match; + + dev_info(&pdev->dev, "probe started\n"); vphydev = devm_kzalloc(&pdev->dev, sizeof(*vphydev), GFP_KERNEL); if (!vphydev) return -ENOMEM; @@ -419,10 +618,23 @@ static int xvphy_probe(struct platform_device *pdev) /* set a pointer to our driver data */ platform_set_drvdata(pdev, vphydev); + match = of_match_node(xvphy_of_match, np); + if (!match) + return -ENODEV; + + if (strncmp(match->compatible, "xlnx,vid-phy-controller", 23) == 0) + vphydev->isvphy = 1; + else + vphydev->isvphy = 0; + XVphy_ConfigTable[instance].DeviceId = VPHY_DEVICE_ID_BASE + instance; + XHdmiphy1_ConfigTable[instance].DeviceId = VPHY_DEVICE_ID_BASE + instance; dev_dbg(vphydev->dev,"DT parse start\n"); - ret = vphy_parse_of(vphydev, &XVphy_ConfigTable[instance]); + if (vphydev->isvphy) + ret = vphy_parse_of(vphydev, &XVphy_ConfigTable[instance]); + else + ret = vphy_parse_of(vphydev, &XHdmiphy1_ConfigTable[instance]); if (ret) return ret; dev_dbg(vphydev->dev,"DT parse done\n"); @@ -475,6 +687,7 @@ static int xvphy_probe(struct platform_device *pdev) /* set address in configuration data */ XVphy_ConfigTable[instance].BaseAddr = (uintptr_t)vphydev->iomem; + XHdmiphy1_ConfigTable[instance].BaseAddr = (uintptr_t)vphydev->iomem; vphydev->irq = platform_get_irq(pdev, 0); if (vphydev->irq <= 0) { @@ -483,7 +696,10 @@ static int xvphy_probe(struct platform_device *pdev) } /* the AXI lite clock is used for the clock rate detector */ - vphydev->axi_lite_clk = devm_clk_get(&pdev->dev, "axi-lite"); + if (vphydev->isvphy) + vphydev->axi_lite_clk = devm_clk_get(&pdev->dev, "vid_phy_axi4lite_aclk"); + else + vphydev->axi_lite_clk = devm_clk_get(&pdev->dev, "axi4lite_aclk"); if (IS_ERR(vphydev->axi_lite_clk)) { ret = PTR_ERR(vphydev->axi_lite_clk); vphydev->axi_lite_clk = NULL; @@ -505,34 +721,49 @@ static int xvphy_probe(struct platform_device *pdev) /* set axi-lite clk in configuration data */ XVphy_ConfigTable[instance].AxiLiteClkFreq = axi_lite_rate; XVphy_ConfigTable[instance].DrpClkFreq = axi_lite_rate; + XHdmiphy1_ConfigTable[instance].AxiLiteClkFreq = axi_lite_rate; + XHdmiphy1_ConfigTable[instance].DrpClkFreq = axi_lite_rate; /* dru-clk is used for the nidru block for low res support */ - vphydev->clkp = devm_clk_get(&pdev->dev, "dru-clk"); - if (IS_ERR(vphydev->clkp)) { - ret = PTR_ERR(vphydev->clkp); - vphydev->clkp = NULL; - if (ret == -EPROBE_DEFER) - dev_info(&pdev->dev, "dru-clk not ready -EPROBE_DEFER\n"); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get the nidru clk.\n"); - return ret; - } + if ((vphydev->isvphy && (XVphy_ConfigTable[instance].DruIsPresent == (TRUE))) || + (!vphydev->isvphy && (XHdmiphy1_ConfigTable[instance].DruIsPresent == (TRUE)))) { + vphydev->dru_clk = devm_clk_get(&pdev->dev, "dru-clk"); + if (IS_ERR(vphydev->dru_clk)) { + ret = PTR_ERR(vphydev->dru_clk); + vphydev->dru_clk = NULL; + if (ret == -EPROBE_DEFER) + dev_info(&pdev->dev, "dru-clk not ready -EPROBE_DEFER\n"); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "failed to get the nidru clk.\n"); + return ret; + } - ret = clk_prepare_enable(vphydev->clkp); - if (ret) { - dev_err(&pdev->dev, "failed to enable nidru clk\n"); - return ret; - } + ret = clk_prepare_enable(vphydev->dru_clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable nidru clk\n"); + return ret; + } - dru_clk_rate = clk_get_rate(vphydev->clkp); - dev_dbg(vphydev->dev,"default dru-clk rate = %lu\n", dru_clk_rate); - if (dru_clk_rate != XVPHY_DRU_REF_CLK_HZ) { - ret = clk_set_rate(vphydev->clkp, XVPHY_DRU_REF_CLK_HZ); - if (ret != 0) { - dev_err(&pdev->dev, "Cannot set rate : %d\n", ret); + dru_clk_rate = clk_get_rate(vphydev->dru_clk); + dev_dbg(vphydev->dev, "default dru-clk rate = %lu\n", dru_clk_rate); + if ((vphydev->isvphy && (dru_clk_rate != XVPHY_DRU_REF_CLK_HZ)) || + (!vphydev->isvphy && (dru_clk_rate != XHDMIPHY1_DRU_REF_CLK_HZ))) { + + if (vphydev->isvphy) + ret = clk_set_rate(vphydev->dru_clk, XVPHY_DRU_REF_CLK_HZ); + else + ret = clk_set_rate(vphydev->dru_clk, XHDMIPHY1_DRU_REF_CLK_HZ); + + if (ret != 0) { + dev_err(&pdev->dev, "Cannot set rate : %d\n", ret); + } + dru_clk_rate = clk_get_rate(vphydev->dru_clk); + dev_dbg(vphydev->dev, "ref dru-clk rate = %lu\n", dru_clk_rate); } - dru_clk_rate = clk_get_rate(vphydev->clkp); - dev_dbg(vphydev->dev,"ref dru-clk rate = %lu\n", dru_clk_rate); + } + else + { + dev_dbg(vphydev->dev, "DRU is not enabled from device tree\n"); } provider = devm_of_phy_provider_register(&pdev->dev, xvphy_xlate); @@ -541,17 +772,56 @@ static int xvphy_probe(struct platform_device *pdev) return PTR_ERR(provider); } + if (!vphydev->isvphy) { + /* For Versal */ + XHdmiphy1_Config *xgtphycfg = + (XHdmiphy1_Config *)(&XHdmiphy1_ConfigTable[instance]); + + iomem1 = ioremap(0xF70E000C, 4); + if (IS_ERR(iomem1)) + dev_err(vphydev->dev, "[Versal] - Error in iomem 5\n"); + XHdmiphy1_Out32((INTPTR)iomem1, 0xF9E8D7C6); + dev_dbg(vphydev->dev, "To: 0x%08x \r\n", XHdmiphy1_In32((INTPTR)iomem1)); + iounmap(iomem1); + + if (xgtphycfg->TxSysPllClkSel == 7 || xgtphycfg->RxSysPllClkSel == 8) { + iomem1 = ioremap(0xF70E3C4C, 4); + if (IS_ERR(iomem1)) + dev_err(vphydev->dev, "[Versal] - Error in iomem 6\n"); + dev_dbg(vphydev->dev, "RX:HS1 RPLL IPS From: 0x%08x ", XHdmiphy1_In32((INTPTR)iomem1)); + XHdmiphy1_Out32((INTPTR)iomem1, 0x03000810); + dev_dbg(vphydev->dev, "To: 0x%08x \r\n", XHdmiphy1_In32((INTPTR)iomem1)); + iounmap(iomem1); + } else { + iomem1 = ioremap(0xF70E3C48, 4); + if (IS_ERR(iomem1)) + dev_err(vphydev->dev, "[Versal] - Error in iomem 7\n"); + dev_dbg(vphydev->dev, "TX:HS1 LCPLL IPS From: 0x%08x ", XHdmiphy1_In32((INTPTR)iomem1)); + XHdmiphy1_Out32((INTPTR)iomem1, 0x03E00810); + dev_dbg(vphydev->dev, "To: 0x%08x \r\n", XHdmiphy1_In32((INTPTR)iomem1)); + iounmap(iomem1); + } + /* Delay 50ms for GT to complete initialization */ + usleep_range(50000, 50000); + } /* Initialize HDMI VPHY */ - Status = XVphy_Hdmi_CfgInitialize(&vphydev->xvphy, 0/*QuadID*/, - &XVphy_ConfigTable[instance]); + if (vphydev->isvphy) + Status = XVphy_Hdmi_CfgInitialize(&vphydev->xvphy, 0/*QuadID*/, + &XVphy_ConfigTable[instance]); + else + Status = XHdmiphy1_Hdmi_CfgInitialize(&vphydev->xgtphy, 0/*QuadID*/, + &XHdmiphy1_ConfigTable[instance]); if (Status != XST_SUCCESS) { dev_err(&pdev->dev, "HDMI VPHY initialization error\n"); return ENODEV; } - Data = XVphy_GetVersion(&vphydev->xvphy); - printk(KERN_INFO "VPhy version : %02d.%02d (%04x)\n", ((Data >> 24) & 0xFF), + if (vphydev->isvphy) + Data = XVphy_GetVersion(&vphydev->xvphy); + else + Data = XHdmiphy1_GetVersion(&vphydev->xgtphy); + dev_info(vphydev->dev, "VPhy version : %02d.%02d (%04x)\n", ((Data >> 24) & 0xFF), ((Data >> 16) & 0xFF), (Data & 0xFFFF)); @@ -563,36 +833,59 @@ static int xvphy_probe(struct platform_device *pdev) return ret; } - dev_dbg(vphydev->dev,"config.DruIsPresent = %d\n", XVphy_ConfigTable[instance].DruIsPresent); - if (vphydev->xvphy.Config.DruIsPresent == (TRUE)) { - dev_dbg(vphydev->dev,"DRU reference clock frequency %0d Hz\n\r", + if (vphydev->isvphy) { + dev_dbg(vphydev->dev,"config.DruIsPresent = %d\n", XVphy_ConfigTable[instance].DruIsPresent); + if (vphydev->xvphy.Config.DruIsPresent == (TRUE)) { + dev_dbg(vphydev->dev,"DRU reference clock frequency %0d Hz\n\r", XVphy_DruGetRefClkFreqHz(&vphydev->xvphy)); + } + } else { + dev_dbg(vphydev->dev,"config.DruIsPresent = %d\n", XHdmiphy1_ConfigTable[instance].DruIsPresent); + if (vphydev->xgtphy.Config.DruIsPresent == (TRUE)) { + dev_info(vphydev->dev,"DRU reference clock frequency %0d Hz\n", + XHdmiphy1_DruGetRefClkFreqHz(&vphydev->xgtphy)); + } } + dev_info(&pdev->dev, "probe successful\n"); /* probe has succeeded for this instance, increment instance index */ instance++; return 0; } -/* Match table for of_platform binding */ -static const struct of_device_id xvphy_of_match[] = { - { .compatible = "xlnx,vid-phy-controller-2.2" }, - { /* end of table */ }, +static int __maybe_unused xvphy_pm_suspend(struct device *dev) +{ + struct xvphy_dev *vphydev = dev_get_drvdata(dev); + dev_dbg(vphydev->dev, "Vphy suspend function called\n"); + xvphy_intr_disable(vphydev); + return 0; +} + +static int __maybe_unused xvphy_pm_resume(struct device *dev) +{ + struct xvphy_dev *vphydev = dev_get_drvdata(dev); + dev_dbg(vphydev->dev, "Vphy resume function called\n"); + xvphy_intr_enable(vphydev); + return 0; +} + +static const struct dev_pm_ops xvphy_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xvphy_pm_suspend, xvphy_pm_resume) }; -MODULE_DEVICE_TABLE(of, xvphy_of_match); static struct platform_driver xvphy_driver = { .probe = xvphy_probe, .driver = { .name = "xilinx-vphy", .of_match_table = xvphy_of_match, + .pm = &xvphy_pm_ops, }, }; module_platform_driver(xvphy_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Leon Woestenberg "); -MODULE_DESCRIPTION("Xilinx Vphy driver"); +MODULE_DESCRIPTION("Xilinx Vphy / HDMI GT Controller driver"); /* phy sub-directory is used as a place holder for all shared code for hdmi-rx and hdmi-tx driver. All shared API's need to be exported */ diff --git a/hdmi/phy-xilinx-vphy/sha2.c b/hdmi/phy-xilinx-vphy/sha2.c index 04aa7bc..81c651f 100644 --- a/hdmi/phy-xilinx-vphy/sha2.c +++ b/hdmi/phy-xilinx-vphy/sha2.c @@ -25,6 +25,7 @@ * Ver Who Date Changes * ----- ---- -------- ----------------------------------------------- * 1.00 MH 10/30/15 First Release +* 1.10 GM 10/14/19 Added "volatile" attribute to all "i" variables * * *****************************************************************************/ @@ -114,7 +115,8 @@ void XHdcp22Cmn_Sha256Hash(const u8 *Data, u32 DataSize, u8 *HashedData) ******************************************************************************/ static void Sha256Transform(Sha256Type *Ctx, u8 *Data) { - u32 a,b,c,d,e,f,g,h,i,j,t1,t2,m[64]; + volatile u32 i; + u32 a,b,c,d,e,f,g,h,j,t1,t2,m[64]; for (i=0,j=0; i < 16; ++i, j += 4) m[i] = (Data[j] << 24) | (Data[j+1] << 16) | (Data[j+2] << 8) | (Data[j+3]); @@ -195,7 +197,7 @@ static void Sha256Init(Sha256Type *Ctx) ******************************************************************************/ static void Sha256Update(Sha256Type *Ctx, const u8 *Data, u32 Len) { - u32 i; + volatile u32 i; for (i=0; i < Len; ++i) { Ctx->data[Ctx->datalen] = Data[i]; @@ -223,7 +225,7 @@ static void Sha256Update(Sha256Type *Ctx, const u8 *Data, u32 Len) ******************************************************************************/ static void Sha256Final(Sha256Type *Ctx, u8 *Hash) { - u32 i; + volatile u32 i; i = Ctx->datalen; diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x.c b/hdmi/phy-xilinx-vphy/xhdcp1x.c index 8e91157..030798a 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x.c -* @addtogroup hdcp1x_v4_0 * @{ * * This contains the implementation of the HDCP state machine module @@ -71,6 +70,14 @@ /************************** Constant Definitions *****************************/ +#if defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0) +#define INCLUDE_TX +#endif +#if defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0) +#define INCLUDE_RX +#endif #if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) #define INCLUDE_TX #endif @@ -137,9 +144,9 @@ int XHdcp1x_CfgInitialize(XHdcp1x *InstancePtr, const XHdcp1x_Config *CfgPtr, Xil_AssertNonvoid(CfgPtr != NULL); Xil_AssertNonvoid(EffectiveAddr != (UINTPTR)NULL); - /* clear instance */ - memset(InstancePtr, 0, sizeof(XHdcp1x)); - + /* Setup the InstancePtr. */ + (void)memset((void *)InstancePtr, 0, sizeof(XHdcp1x)); + /* Initialize InstancePtr. */ InstancePtr->Config = *CfgPtr; InstancePtr->Config.BaseAddress = EffectiveAddr; @@ -226,7 +233,7 @@ int XHdcp1x_CfgInitialize(XHdcp1x *InstancePtr, const XHdcp1x_Config *CfgPtr, /* Initialize RX */ XHdcp1x_RxInit(InstancePtr); } - + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; return (XST_SUCCESS); diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x.h b/hdmi/phy-xilinx-vphy/xhdcp1x.h index c9aa559..e699600 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x.h @@ -17,7 +17,6 @@ /** * * @file xhdcp1x.h -* @addtogroup hdcp1x_v4_0 * @{ * @details * @@ -705,6 +704,9 @@ * 4.1 yas 11/10/16 Added function XHdcp1x_SetHdmiMode. * 4.1 yas 08/03/17 Added flag IsAuthReqPending to the XHdcp1x_Tx data * structure to track any pending authentication requests. +* 4.2 yas 13/08/18 Addded hdcp14_PropagateTopoErrUpstream flag to track +* topology failures and ready the topology for the +* repeater application to read. * * ******************************************************************************/ @@ -933,6 +935,7 @@ typedef struct { u8 Depth; /**< Depth of the Repeater's downstream topology*/ u8 DeviceCount; /**< Number of downstream devices attached * to the Repeater*/ + u8 hdcp14_PropagateTopoErrUpstream; } XHdcp1x_RepeaterExchange; /** @@ -1069,9 +1072,9 @@ typedef struct { * second part of * authentication" callback * set flag*/ - XHdcp1x_Callback AuthenticatedCallback; /**< Unauthenticated callback*/ - void *AuthenticatedCallbackRef; /**< Unauthenticated reference */ - u32 IsAuthenticatedCallbackSet; /**< Unauthenticated config flag */ + XHdcp1x_Callback AuthenticatedCallback; /**< Authenticated callback*/ + void *AuthenticatedCallbackRef; /**< Authenticated reference */ + u32 IsAuthenticatedCallbackSet; /**< Authenticated config flag */ XHdcp1x_Callback UnauthenticatedCallback; /**< Unauthenticated * callback */ void *UnauthenticatedCallbackRef; /**< Unauthenticated diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_cipher.c b/hdmi/phy-xilinx-vphy/xhdcp1x_cipher.c index 47c365f..e74c20d 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_cipher.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_cipher.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_cipher.c -* @addtogroup hdcp1x_v4_0 * @{ * * This file contains the main implementation of the driver associated with @@ -313,7 +312,7 @@ int XHdcp1x_CipherDoRequest(XHdcp1x *InstancePtr, /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); - Xil_AssertNonvoid(Request >= (XHDCP1X_CIPHER_REQUEST_BLOCK)); + Xil_AssertNonvoid(Request < (XHDCP1X_CIPHER_REQUEST_MAX)); /* Check that it is not disabled */ if (!XHdcp1x_CipherIsEnabled(InstancePtr)) { diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_cipher.h b/hdmi/phy-xilinx-vphy/xhdcp1x_cipher.h index 040422b..de03590 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_cipher.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_cipher.h @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_cipher.h -* @addtogroup hdcp1x_v4_0 * @{ * * This is the main header file for Xilinx HDCP Cipher core. diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_cipher_intr.c b/hdmi/phy-xilinx-vphy/xhdcp1x_cipher_intr.c index 5356ff1..77e2ba0 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_cipher_intr.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_cipher_intr.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_cipher_intr.c -* @addtogroup hdcp1x_v4_0 * @{ * * This file contains interrupt related functions for Xilinx HDCP core. diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_debug.h b/hdmi/phy-xilinx-vphy/xhdcp1x_debug.h index a9ea10c..a58dcb2 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_debug.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_debug.h @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_debug.h -* @addtogroup hdcp1x_v4_0 * @{ * * This file provides the interface of the HDCP debug commands diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_hw.h b/hdmi/phy-xilinx-vphy/xhdcp1x_hw.h index adbe1cf..b19bf4b 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_hw.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_hw.h @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_hw.h -* @addtogroup hdcp1x_v4_0 * @{ * * This header file contains identifiers and register-level core functions (or diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_intr.c b/hdmi/phy-xilinx-vphy/xhdcp1x_intr.c index 738a03a..42f4569 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_intr.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_intr.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_cipher_intr.c -* @addtogroup hdcp1x_v4_0 * @{ * * This file contains interrupt related functions for Xilinx HDCP core. diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_platform.c b/hdmi/phy-xilinx-vphy/xhdcp1x_platform.c index a6eb26e..62b6037 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_platform.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_platform.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_platform.c -* @addtogroup hdcp1x_v4_0 * @{ * * This file provides the implementation for the hdcp platform integration diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_platform.h b/hdmi/phy-xilinx-vphy/xhdcp1x_platform.h index 05a9247..d4991bb 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_platform.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_platform.h @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_platform.h -* @addtogroup hdcp1x_v4_0 * @{ * * This file provides the interface for the hdcp platform integration module diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_port.c b/hdmi/phy-xilinx-vphy/xhdcp1x_port.c index 0260162..dbef966 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_port.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_port.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_port.c -* @addtogroup hdcp1x_v4_0 * @{ * * This contains the main implementation file for the Xilinx HDCP Port driver @@ -43,17 +42,26 @@ /************************** Constant Definitions *****************************/ - +#if defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0) +#define INCLUDE_HDMI_TX +#endif +#if defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0) +#define INCLUDE_HDMI_RX +#endif #if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) #define INCLUDE_HDMI_TX #endif #if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) #define INCLUDE_HDMI_RX #endif -#if defined(XPAR_XDP_NUM_INSTANCES) && (XPAR_XDP_NUM_INSTANCES > 0) -#define INCLUDE_DP_TX +#if defined(XPAR_XDPRXSS_NUM_INSTANCES) && (XPAR_XDPRXSS_NUM_INSTANCES > 0) #define INCLUDE_DP_RX #endif +#if defined(XPAR_XDPTXSS_NUM_INSTANCES) && (XPAR_XDPTXSS_NUM_INSTANCES > 0) +#define INCLUDE_DP_TX +#endif /**************************** Type Definitions *******************************/ diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_port.h b/hdmi/phy-xilinx-vphy/xhdcp1x_port.h index 58a03d4..ccf76c9 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_port.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_port.h @@ -16,7 +16,6 @@ /** * * @file xhdcp1x_port.h -* @addtogroup hdcp1x_v4_0 * @{ * * This header file contains the external declarations associated with the diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi.h b/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi.h index ce404ca..f2d09e9 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi.h @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_port_hdmi.h -* @addtogroup hdcp1x_v4_0 * @{ * * This file contains the definitions for the hdcp port registers/offsets for diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi_rx.c b/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi_rx.c index bb479e2..ea3ecfe 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi_rx.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi_rx.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_port_hdmi_rx.c -* @addtogroup hdcp1x_v4_0 * @{ * * This contains the implementation of the HDCP port driver for HDMI RX @@ -37,6 +36,8 @@ * 3.1 yas 07/28/16 Added function XHdcp1x_PortHdmiRxSetRepeater * 3.2 yas 10/27/16 Updated the XHdcp1x_PortHdmiRxDisable function to not * clear the AKSV, An and AInfo values in the DDC space. +* 4.2 yas 08/15/18 Updated XHdcp1x_PortHdmiRxDisable function to clear +* KSV_FIFO. * * ******************************************************************************/ @@ -44,7 +45,10 @@ /***************************** Include Files *********************************/ -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) //#include #include #include "xhdcp1x_port.h" @@ -175,7 +179,7 @@ static int XHdcp1x_PortHdmiRxDisable(XHdcp1x *InstancePtr) /* Clear HDCP register space for KSV FIFO (0x43) */ Value = 0; - XHdcp1x_PortHdmiRxWrite(InstancePtr, XHDCP1X_PORT_OFFSET_BCAPS, + XHdcp1x_PortHdmiRxWrite(InstancePtr, XHDCP1X_PORT_OFFSET_KSVFIFO, &Value, 1); return (Status); diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi_tx.c b/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi_tx.c index 58cd40b..ef5e7cd 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi_tx.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_port_hdmi_tx.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_port_hdmi_tx.c -* @addtogroup hdcp1x_v4_0 * @{ * * This contains the implementation of the HDCP port driver for HDMI TX @@ -39,7 +38,10 @@ /***************************** Include Files *********************************/ -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) //#include #include #include "xhdcp1x_port.h" diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_port_intr.c b/hdmi/phy-xilinx-vphy/xhdcp1x_port_intr.c index f650089..591127c 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_port_intr.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_port_intr.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_port_intr.c -* @addtogroup hdcp1x_v4_0 * @{ * * This contains the interrupt related functions of the Xilinx HDCP port driver diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c b/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c index 72821fe..5f95667 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_rx.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_rx.c -* @addtogroup hdcp1x_v4_0 * @{ * * This contains the main implementation file for the Xilinx HDCP receive state @@ -72,7 +71,10 @@ #include "xhdcp1x_cipher.h" #include "xhdcp1x_debug.h" #include "xhdcp1x_port.h" -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) #include "xhdcp1x_port_hdmi.h" #else #include "xhdcp1x_port_dp.h" @@ -890,10 +892,11 @@ int XHdcp1x_RxGetRepeaterInfo(XHdcp1x *InstancePtr, ******************************************************************************/ static void XHdcp1x_RxDebugLog(const XHdcp1x *InstancePtr, const char *LogMsg) { - char Label[20]; + char Label[16]; /* Format Label */ - snprintf(Label, 20, "hdcp-rx(%d) - ", InstancePtr->Config.DeviceId); + snprintf(Label, sizeof(Label), "hdcp-rx(%hu) - ", + InstancePtr->Config.DeviceId); /* Log it */ XHDCP1X_DEBUG_LOGMSG(Label); @@ -1244,7 +1247,10 @@ static void XHdcp1x_RxPollForComputations(XHdcp1x *InstancePtr, XHdcp1x_PortWrite(InstancePtr, XHDCP1X_PORT_OFFSET_RO, Buf, 2); -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) /* No reset required in the sofware for HDMI. KSV fifo * pointer reset is implemented in the hardware. */ @@ -1516,7 +1522,10 @@ void XHdcp1x_RxSetTopologyDeviceCnt(XHdcp1x *InstancePtr, u32 Value) ******************************************************************************/ void XHdcp1x_RxSetTopologyMaxCascadeExceeded(XHdcp1x *InstancePtr, u8 Value) { -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) u32 BStatus; @@ -1560,7 +1569,10 @@ void XHdcp1x_RxSetTopologyMaxDevsExceeded(XHdcp1x *InstancePtr, u8 Value) Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(Value == FALSE || Value == TRUE); -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) u16 DevCntErr = (Value & 0xFFFF); u32 BStatus; @@ -1603,7 +1615,10 @@ void XHdcp1x_RxSetHdmiMode(XHdcp1x *InstancePtr, u8 Value) /* Verify arguments */ Xil_AssertVoid(InstancePtr != NULL); -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) u32 BStatus; /* Update the value of HDMI_MODE bit in the BStatus Register */ @@ -1654,7 +1669,10 @@ static void XHdcp1x_RxAssembleKSVList(XHdcp1x *InstancePtr, *NextStatePtr = XHDCP1X_STATE_UNAUTHENTICATED; } else { -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) u32 BCaps; #else u32 BInfo; @@ -1667,7 +1685,10 @@ static void XHdcp1x_RxAssembleKSVList(XHdcp1x *InstancePtr, u32 ksvCount, ksvsToWrite; u16 RepeaterInfo = 0; -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) /* Ensure that the READY bit is clear */ /* Update the Ready bit in the BCaps Register */ @@ -1717,7 +1738,10 @@ static void XHdcp1x_RxAssembleKSVList(XHdcp1x *InstancePtr, tempKsv = InstancePtr->RepeaterValues.KsvList[ksvCount]; XHDCP1X_PORT_UINT_TO_BUF(Buf, tempKsv , (XHDCP1X_PORT_SIZE_BKSV * 8)); -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) /* Write the KSV to the HDCP_DAT register each time, * The KSV Fifo will auto increment @@ -1736,7 +1760,10 @@ static void XHdcp1x_RxAssembleKSVList(XHdcp1x *InstancePtr, ksvsToWrite -= 1; } -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) RepeaterInfo = (XHDCP1X_PORT_BIT_BSTATUS_HDMI_MODE) | (XHDCP1X_PORT_BSTATUS_BIT_DEPTH_NO_ERR) | (InstancePtr->RepeaterValues.Depth << @@ -1755,7 +1782,10 @@ static void XHdcp1x_RxAssembleKSVList(XHdcp1x *InstancePtr, XHdcp1x_RxCalculateSHA1Value(InstancePtr,RepeaterInfo); -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMIRX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMIRX1_NUM_INSTANCES > 0)) /* Update the value of V'H0 */ sha1value = 0; diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_rx.h b/hdmi/phy-xilinx-vphy/xhdcp1x_rx.h index 895166f..c2c011c 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_rx.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_rx.h @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_rx.h -* @addtogroup hdcp1x_v4_0 * @{ * * This file provides the interface of the HDCP RX state machine diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_selftest.c b/hdmi/phy-xilinx-vphy/xhdcp1x_selftest.c index a011403..cd45a42 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_selftest.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_selftest.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_selftest.c -* @addtogroup hdcp1x_v4_0 * @{ * * This file contains self test function for the hdcp interface diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_sinit.c b/hdmi/phy-xilinx-vphy/xhdcp1x_sinit.c index 19e98ca..5cd30a3 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_sinit.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_sinit.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_sinit.c -* @addtogroup hdcp1x_v4_0 * @{ * * This file contains static initialization method for Xilinx HDCP driver diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_tx.c b/hdmi/phy-xilinx-vphy/xhdcp1x_tx.c index 373343f..b7d1743 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_tx.c +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_tx.c @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_tx.c -* @addtogroup hdcp1x_v4_0 * @{ * * This contains the main implementation file for the Xilinx HDCP transmit @@ -57,6 +56,11 @@ * Increase timeout for topology propagation. * 4.1 yas 08/03/17 Updated the XHdcp1x_TxIsInProgress to track any * pending authentication requests. +* 4.2 yas 08/14/18 Updated the XHdcp1x_TxPollForWaitForReady function to +* ready topology in case of a topology error, and make +* it available in XHdcp1x_TxGetTopology(). +* Updating the XHdcp1x_TxReset() to clear the +* Authentication Request flag. * * *****************************************************************************/ @@ -73,7 +77,10 @@ #include "xhdcp1x_debug.h" #include "xhdcp1x_platform.h" #include "xhdcp1x_port.h" -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) #include "xhdcp1x_port_hdmi.h" #else #include "xhdcp1x_port_dp.h" @@ -366,8 +373,9 @@ int XHdcp1x_TxReset(XHdcp1x *InstancePtr) XHdcp1x_TxPostEvent(InstancePtr, XHDCP1X_EVENT_DISABLE); XHdcp1x_TxPostEvent(InstancePtr, XHDCP1X_EVENT_ENABLE); - /* Reset the Authentication In Progress Flag */ + /* Reset the Authentication In Progress Flag. */ InstancePtr->Tx.IsAuthReqPending = (FALSE); + return (Status); } @@ -800,7 +808,10 @@ void XHdcp1x_TxSetHdmiMode(XHdcp1x *InstancePtr, u8 Value) Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(Value == FALSE || Value == TRUE); -#if defined(XPAR_XV_HDMIRX_NUM_INSTANCES) && (XPAR_XV_HDMIRX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) InstancePtr->Tx.TxIsHdmi = Value; #else UNUSED(Value); @@ -987,7 +998,8 @@ static void XHdcp1x_TxDebugLog(const XHdcp1x *InstancePtr, const char *LogMsg) char Label[16]; /* Format Label */ - snprintf(Label, 16, "hdcp-tx(%d) - ", InstancePtr->Config.DeviceId); + snprintf(Label, sizeof(Label), "hdcp-tx(%hu) - ", + InstancePtr->Config.DeviceId); /* Log it */ XHDCP1X_DEBUG_LOGMSG(Label); @@ -1203,6 +1215,7 @@ static void XHdcp1x_TxEnableEncryptionState(XHdcp1x *InstancePtr) /* Enable it */ XHdcp1x_CipherEnableEncryption(InstancePtr, InstancePtr->Tx.EncryptionMap); + } } } @@ -1770,7 +1783,9 @@ static void XHdcp1x_TxPollForWaitForReady(XHdcp1x *InstancePtr, Status = XHdcp1x_PortGetRepeaterInfo(InstancePtr, &RepeaterInfo); if (Status == XST_SUCCESS) { /* Check that neither cascade or device numbers exceeded */ - if ((RepeaterInfo & 0x0880u) == 0) { + if ((!XHdcp1x_TxGetTopologyMaxCascadeExceeded(InstancePtr)) && + (!XHdcp1x_TxGetTopologyMaxDevsExceeded(InstancePtr))) { + /* Check for at least one attached device */ if ((RepeaterInfo & 0x007Fu) != 0) { /* Update InstancePtr */ @@ -1779,14 +1794,30 @@ static void XHdcp1x_TxPollForWaitForReady(XHdcp1x *InstancePtr, /* Update NextStatePtr */ *NextStatePtr = XHDCP1X_STATE_READKSVLIST; + /* No topology errors. */ + InstancePtr->RepeaterValues.hdcp14_PropagateTopoErrUpstream = FALSE; + /* Log */ XHdcp1x_TxDebugLog(InstancePtr, "devices attached: ksv list ready"); } /* Otherwise */ else { + /* + * Check if Repeater. If repeater, goto + * unauthenticated state and wait for the + * Repeater RX interface to trigger + * authentication after timing out of + * WaitForDownstream state. + * Otherwise, restart authentication on the TX. + */ + if (InstancePtr->IsRepeater) { + /* Update NextStatePtr */ + *NextStatePtr = XHDCP1X_STATE_UNAUTHENTICATED; + } else { /* Update NextStatePtr */ *NextStatePtr = XHDCP1X_STATE_DETERMINERXCAPABLE; + } /* Log */ XHdcp1x_TxDebugLog(InstancePtr, @@ -1795,10 +1826,53 @@ static void XHdcp1x_TxPollForWaitForReady(XHdcp1x *InstancePtr, } /* Check for cascade exceeded */ else { -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Disable the hdcp encryption for both HDMI and DP. * But currently only doing it for HDMI. */ XHdcp1x_TxDisableEncryptionState(InstancePtr); + + /* Propagate the failure upstream */ + InstancePtr->RepeaterValues.Depth = + ((RepeaterInfo & 0x0700u) >> + XHDCP1X_PORT_BSTATUS_DEPTH_SHIFT); + InstancePtr->RepeaterValues.DeviceCount = + (RepeaterInfo & + XHDCP1X_PORT_BSTATUS_DEV_CNT_MASK); + /* Set the KSV List to include the downstream + * device's BKSV. Do not Validate or assemble the KSV + * List from downstream.*/ + u8 Bksv[8]; + + XHdcp1x_PortRead(InstancePtr, XHDCP1X_PORT_OFFSET_BKSV, + Bksv, 5); + + u64 RemoteKsv = 0; + + /* Determine theRemoteKsv */ + XHDCP1X_PORT_BUF_TO_UINT(RemoteKsv, Bksv, + XHDCP1X_PORT_SIZE_BKSV * 8); + + /* Check for invalid */ + if (!XHdcp1x_TxIsKsvValid(RemoteKsv)) { + InstancePtr->RepeaterValues.KsvList[0] = + RemoteKsv; + } else { + InstancePtr->RepeaterValues.KsvList[0] = 0x0; + } + + /* Set V' to 0x0. */ + memset(InstancePtr->RepeaterValues.V, 0x0, + sizeof(u32)*5); + + InstancePtr->RepeaterValues.hdcp14_PropagateTopoErrUpstream = TRUE; + + if (InstancePtr->Tx.IsRepeaterExchangeCallbackSet) { + InstancePtr->Tx.RepeaterExchangeCallback( + InstancePtr->Tx.RepeaterExchangeRef); + } #endif /* Update NextStatePtr */ @@ -1839,7 +1913,10 @@ static int XHdcp1x_TxValidateKsvList(XHdcp1x *InstancePtr, u16 RepeaterInfo) u8 ksvListHolder[127*XHDCP1X_PORT_SIZE_BKSV]; -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) #else @@ -1864,7 +1941,10 @@ static int XHdcp1x_TxValidateKsvList(XHdcp1x *InstancePtr, u16 RepeaterInfo) /* Determine theNumToRead */ NumToRead = (((RepeaterInfo & 0x7Fu) * 5)); -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Read the ksv list */ /* Read the entire KSV fifo list in one go */ int ByteCount = 0; @@ -1973,7 +2053,10 @@ static int XHdcp1x_TxValidateKsvList(XHdcp1x *InstancePtr, u16 RepeaterInfo) /* Insert RepeaterInfo into the SHA-1 transform */ Buf[0] = (u8) (RepeaterInfo & 0xFFu); -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) Buf[1] = (u8) ( ((RepeaterInfo | (XHDCP1X_PORT_BIT_BSTATUS_HDMI_MODE)) >> XHDCP1X_PORT_BSTATUS_DEPTH_SHIFT) & 0xFFu); @@ -2012,7 +2095,10 @@ static int XHdcp1x_TxValidateKsvList(XHdcp1x *InstancePtr, u16 RepeaterInfo) /* Read the value from the far end */ if (XHdcp1x_PortRead(InstancePtr, Offset, Buf, 4) > 0) { -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Storing the V' prime values later */ #else memcpy(&InstancePtr->RepeaterValues.V[Offset - @@ -2050,7 +2136,10 @@ static int XHdcp1x_TxValidateKsvList(XHdcp1x *InstancePtr, u16 RepeaterInfo) if (InstancePtr->IsRepeater) { -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Do nothing */ #else /* Update this value in the RepeaterExchange @@ -2208,7 +2297,10 @@ u32 XHdcp1x_TxGetTopologyMaxCascadeExceeded(XHdcp1x *InstancePtr) u32 Buf; u32 Status; -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Read the BStatus Register */ XHdcp1x_PortRead(InstancePtr, XHDCP1X_PORT_OFFSET_BSTATUS, &Buf, XHDCP1X_PORT_SIZE_BSTATUS); @@ -2286,7 +2378,10 @@ u32 XHdcp1x_TxGetTopologyMaxDevsExceeded(XHdcp1x *InstancePtr) u32 Buf; u32 Status; -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Read the BStatus Register */ XHdcp1x_PortRead(InstancePtr, XHDCP1X_PORT_OFFSET_BSTATUS, &Buf, XHDCP1X_PORT_SIZE_BSTATUS); @@ -2325,7 +2420,9 @@ XHdcp1x_RepeaterExchange *XHdcp1x_TxGetTopology(XHdcp1x *InstancePtr) Xil_AssertNonvoid(InstancePtr != NULL); if (InstancePtr->IsRepeater) { - if (InstancePtr->Rx.CurrentState == XHDCP1X_STATE_AUTHENTICATED) { + if (InstancePtr->Tx.CurrentState == XHDCP1X_STATE_AUTHENTICATED) { + return &InstancePtr->RepeaterValues; + } else if (InstancePtr->RepeaterValues.hdcp14_PropagateTopoErrUpstream == TRUE) { return &InstancePtr->RepeaterValues; } } @@ -2354,13 +2451,19 @@ static int XHdcp1x_TxSetRepeaterInfo(XHdcp1x *InstancePtr) /* Check for repeater */ if (XHdcp1x_PortIsRepeater(InstancePtr)) { -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) u32 Buf; #else u16 RepeaterInfo; #endif -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Set the SHA1 Hash value */ XHdcp1x_PortRead(InstancePtr, XHDCP1X_PORT_OFFSET_VH0, @@ -2397,7 +2500,10 @@ static int XHdcp1x_TxSetRepeaterInfo(XHdcp1x *InstancePtr) /* Do nothing for DP */ #endif -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Copy the Depth read from the downstream HDCP device */ XHdcp1x_PortRead(InstancePtr, XHDCP1X_PORT_OFFSET_BSTATUS, @@ -2917,7 +3023,10 @@ static void XHdcp1x_TxRunWaitForReadyState(XHdcp1x *InstancePtr, /* For poll */ case XHDCP1X_EVENT_POLL: -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Don't read the Repeater info for HDMI from a * poll from application. We'll poll every 100ms. */ #else @@ -2939,7 +3048,10 @@ static void XHdcp1x_TxRunWaitForReadyState(XHdcp1x *InstancePtr, case XHDCP1X_EVENT_TIMEOUT: XHdcp1x_TxDebugLog(InstancePtr, "wait-for-ready timeout"); -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) InstancePtr->Tx.WaitForReadyPollCntFlag++; XHdcp1x_TxStopTimer(InstancePtr); XHdcp1x_TxPollForWaitForReady(InstancePtr, @@ -3128,11 +3240,14 @@ static void XHdcp1x_TxEnterState(XHdcp1x *InstancePtr, XHdcp1x_StateType State, switch (State) { /* For the disabled state */ case XHDCP1X_STATE_DISABLED: + /* Clear auth request pending flag */ + InstancePtr->Tx.IsAuthReqPending = FALSE; XHdcp1x_TxDisableState(InstancePtr); break; /* For determine rx capable */ case XHDCP1X_STATE_DETERMINERXCAPABLE: + InstancePtr->RepeaterValues.hdcp14_PropagateTopoErrUpstream = FALSE; InstancePtr->Tx.Flags |= XVPHY_FLAG_PHY_UP; XHdcp1x_TxSetCheckLinkState(InstancePtr, FALSE); XHdcp1x_TxDisableEncryptionState(InstancePtr); @@ -3159,7 +3274,10 @@ static void XHdcp1x_TxEnterState(XHdcp1x *InstancePtr, XHdcp1x_StateType State, /* For the validate rx state */ case XHDCP1X_STATE_TESTFORREPEATER: -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Enable encryption for HDMI (this will come immediately * after Ro' has been read and successfully compared). */ InstancePtr->Tx.EncryptionMap = 0x1; @@ -3175,7 +3293,10 @@ static void XHdcp1x_TxEnterState(XHdcp1x *InstancePtr, XHdcp1x_StateType State, case XHDCP1X_STATE_WAITFORREADY: InstancePtr->Tx.StateHelper = 0; -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) InstancePtr->Tx.WaitForReadyPollCntFlag = 0; /* Post the timeout */ XHdcp1x_TxPostEvent(InstancePtr, XHDCP1X_EVENT_TIMEOUT); @@ -3216,7 +3337,10 @@ static void XHdcp1x_TxEnterState(XHdcp1x *InstancePtr, XHdcp1x_StateType State, if (InstancePtr->IsRepeater == 1) { if(InstancePtr->Tx.DownstreamReady == 1) { InstancePtr->Tx.DownstreamReady = 0; -#if defined(XPAR_XV_HDMITX_NUM_INSTANCES) && (XPAR_XV_HDMITX_NUM_INSTANCES > 0) +#if (defined(XPAR_XV_HDMITX_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX_NUM_INSTANCES > 0)) || \ + (defined(XPAR_XV_HDMITX1_NUM_INSTANCES) && \ + (XPAR_XV_HDMITX1_NUM_INSTANCES > 0)) /* Do nothing for HDMI. */ #else /* In case of DisplayPort , read the Downstream Repeater diff --git a/hdmi/phy-xilinx-vphy/xhdcp1x_tx.h b/hdmi/phy-xilinx-vphy/xhdcp1x_tx.h index 09e65f8..a09b273 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp1x_tx.h +++ b/hdmi/phy-xilinx-vphy/xhdcp1x_tx.h @@ -17,7 +17,6 @@ /** * * @file xhdcp1x_tx.h -* @addtogroup hdcp1x_v4_0 * @{ * * This file provides the interface of the HDCP TX state machine diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_cipher.c b/hdmi/phy-xilinx-vphy/xhdcp22_cipher.c index 60d2074..751cc87 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_cipher.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_cipher.c @@ -17,7 +17,6 @@ /** * * @file xhdcp22_cipher.c -* @addtogroup hdcp22_cipher_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_cipher.h b/hdmi/phy-xilinx-vphy/xhdcp22_cipher.h index 86825e1..a4f7d89 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_cipher.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_cipher.h @@ -17,7 +17,6 @@ /** * * @file xhdcp22_cipher.h -* @addtogroup hdcp22_cipher_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_cipher_hw.h b/hdmi/phy-xilinx-vphy/xhdcp22_cipher_hw.h index ee84a84..1bcb442 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_cipher_hw.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_cipher_hw.h @@ -17,7 +17,6 @@ /** * * @file xhdcp22_cipher_hw.h -* @addtogroup hdcp22_cipher_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_cipher_sinit.c b/hdmi/phy-xilinx-vphy/xhdcp22_cipher_sinit.c index 4f9e96e..7c75008 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_cipher_sinit.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_cipher_sinit.c @@ -17,7 +17,6 @@ /** * * @file xhdcp22_cipher_sinit.c -* @addtogroup hdcp22_cipher_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_mmult.c b/hdmi/phy-xilinx-vphy/xhdcp22_mmult.c index a816b47..b576b7e 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_mmult.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_mmult.c @@ -17,7 +17,6 @@ /** * * @file xhdcp22_mmult.c -* @addtogroup hdcp22_mmult_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_mmult.h b/hdmi/phy-xilinx-vphy/xhdcp22_mmult.h index cba4338..60e855c 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_mmult.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_mmult.h @@ -17,7 +17,6 @@ /** * * @file xhdcp22_mmult.h -* @addtogroup hdcp22_mmult_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_mmult_hw.h b/hdmi/phy-xilinx-vphy/xhdcp22_mmult_hw.h index b8f2165..fd3c40f 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_mmult_hw.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_mmult_hw.h @@ -17,7 +17,6 @@ /** * * @file xhdcp22_mmult_hw.h -* @addtogroup hdcp22_mmult_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_mmult_sinit.c b/hdmi/phy-xilinx-vphy/xhdcp22_mmult_sinit.c index e6c1718..b43ede7 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_mmult_sinit.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_mmult_sinit.c @@ -17,7 +17,6 @@ /** * * @file xhdcp22_mmult_sinit.c -* @addtogroup hdcp22_mmult_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rng.c b/hdmi/phy-xilinx-vphy/xhdcp22_rng.c index 30d6a13..69e440f 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rng.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rng.c @@ -17,7 +17,6 @@ /** * * @file xhdcp22_rng.c -* @addtogroup hdcp22_rng_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rng.h b/hdmi/phy-xilinx-vphy/xhdcp22_rng.h index 0e79ccb..7b9bbea 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rng.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rng.h @@ -17,7 +17,6 @@ /** * * @file xhdcp22_rng.h -* @addtogroup hdcp22_rng_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rng_hw.h b/hdmi/phy-xilinx-vphy/xhdcp22_rng_hw.h index 944f685..ea5f9f7 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rng_hw.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rng_hw.h @@ -17,7 +17,6 @@ /** * * @file xhdcp22_rng_hw.h -* @addtogroup hdcp22_rng_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rng_sinit.c b/hdmi/phy-xilinx-vphy/xhdcp22_rng_sinit.c index 6d017c3..951ab77 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rng_sinit.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rng_sinit.c @@ -17,7 +17,6 @@ /** * * @file xhdcp22_rng_sinit.c -* @addtogroup hdcp22_rng_v1_1 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rx.c b/hdmi/phy-xilinx-vphy/xhdcp22_rx.c index 5e61095..250616a 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rx.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rx.c @@ -16,7 +16,6 @@ /*****************************************************************************/ /** * @file xhdcp22_rx.c -* @addtogroup hdcp22_rx_v2_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rx.h b/hdmi/phy-xilinx-vphy/xhdcp22_rx.h index 1c16bda..98cf121 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rx.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rx.h @@ -16,7 +16,6 @@ /*****************************************************************************/ /** * @file xhdcp22_rx.h -* @addtogroup hdcp22_rx_v2_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rx_crypt.c b/hdmi/phy-xilinx-vphy/xhdcp22_rx_crypt.c index d4dc806..e9f98f2 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rx_crypt.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rx_crypt.c @@ -16,7 +16,6 @@ /*****************************************************************************/ /** * @file xhdcp22_rx_crypt.c -* @addtogroup hdcp22_rx_v2_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rx_i.h b/hdmi/phy-xilinx-vphy/xhdcp22_rx_i.h index 10be673..08b0f52 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rx_i.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rx_i.h @@ -16,7 +16,6 @@ /*****************************************************************************/ /** * @file xhdcp22_rx_i.h -* @addtogroup hdcp22_rx_v2_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_rx_sinit.c b/hdmi/phy-xilinx-vphy/xhdcp22_rx_sinit.c index 66d4280..ad7ba5b 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_rx_sinit.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_rx_sinit.c @@ -16,7 +16,6 @@ /*****************************************************************************/ /** * @file xhdcp22_rx_sinit.c -* @addtogroup hdcp22_rx_v2_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_tx.c b/hdmi/phy-xilinx-vphy/xhdcp22_tx.c index c6a4c06..75722d0 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_tx.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_tx.c @@ -18,7 +18,6 @@ /** * * @file xhdcp22_tx.c -* @addtogroup hdcp22_tx_v2_0 * @{ * @details * @@ -60,6 +59,8 @@ * buffer. * 6. Check return status of DDC write/read when polling * RxStatus register. +* 2.31 YB 03/28/19 Moved the reading of the DDC status from +* XHdcp22Tx_TimerHandler to XHdcp22Tx_Poll. * * ******************************************************************************/ @@ -1014,6 +1015,11 @@ int XHdcp22Tx_Poll(XHdcp22_Tx *InstancePtr) /* Store the authentication status before executing the next state */ PrvAuthenticationStatus = InstancePtr->Info.AuthenticationStatus; + /* Set timer expired signaling flag */ + if (InstancePtr->Timer.TimerExpired == (TRUE) && InstancePtr->Info.IsEnabled) { + XHdcp22Tx_ReadRxStatus(InstancePtr); + } + /* continue executing the statemachine */ NewState = XHdcp22_Tx_StateTable[InstancePtr->Info.CurrentState](InstancePtr); Transition = transition_table[InstancePtr->Info.CurrentState][NewState]; @@ -3212,9 +3218,6 @@ static void XHdcp22Tx_TimerHandler(void *CallbackRef, u8 TmrCntNumber) /* Set timer expired signaling flag */ InstancePtr->Timer.TimerExpired = (TRUE); - - if (InstancePtr->Info.IsEnabled) - XHdcp22Tx_ReadRxStatus(InstancePtr); } diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_tx.h b/hdmi/phy-xilinx-vphy/xhdcp22_tx.h index f5f485c..f53461d 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_tx.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_tx.h @@ -17,7 +17,6 @@ /** * * @file xhdcp22_tx.h -* @addtogroup hdcp22_tx_v2_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_tx_crypt.c b/hdmi/phy-xilinx-vphy/xhdcp22_tx_crypt.c index 7857ac3..5efdbfe 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_tx_crypt.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_tx_crypt.c @@ -17,7 +17,6 @@ /** * * @file xhdcp22_tx_crypt.c -* @addtogroup hdcp22_tx_v2_4 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_tx_i.h b/hdmi/phy-xilinx-vphy/xhdcp22_tx_i.h index 1e18235..e0bde36 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_tx_i.h +++ b/hdmi/phy-xilinx-vphy/xhdcp22_tx_i.h @@ -17,7 +17,6 @@ /** * * @file xhdcp22_tx_i.h -* @addtogroup hdcp22_tx_v2_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdcp22_tx_sinit.c b/hdmi/phy-xilinx-vphy/xhdcp22_tx_sinit.c index 9400d74..48a8408 100644 --- a/hdmi/phy-xilinx-vphy/xhdcp22_tx_sinit.c +++ b/hdmi/phy-xilinx-vphy/xhdcp22_tx_sinit.c @@ -17,7 +17,6 @@ /** * * @file xhdcp22_tx_sinit.c -* @addtogroup hdcp22_tx_v2_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1.c b/hdmi/phy-xilinx-vphy/xhdmiphy1.c new file mode 100644 index 0000000..0b43796 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1.c @@ -0,0 +1,1381 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1.c + * + * Contains a minimal set of functions for the XHdmiphy1 driver that allow + * access to all of the Video PHY core's functionality. See xhdmiphy1.h for a + * detailed description of the driver. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include +#include "xstatus.h" +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" +#include "xhdmiphy1_hdmi.h" +#include +#include "xhdmiphy1_gt.h" + +/**************************** Function Prototypes *****************************/ +static u32 XHdmiphy1_DrpAccess(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + u16 Addr, u16 *Val); + +/**************************** Function Definitions ****************************/ + +/******************************************************************************/ +/** + * This function retrieves the configuration for this Video PHY instance and + * fills in the InstancePtr->Config structure. + * + * @param InstancePtr is a pointer to the XHdmiphy1 instance. + * @param ConfigPtr is a pointer to the configuration structure that will + * be used to copy the settings from. + * @param EffectiveAddr is the device base address in the virtual memory + * space. If the address translation is not used, then the physical + * address is passed. + * + * @return None. + * + * @note Unexpected errors may occur if the address mapping is changed + * after this function is invoked. + * +*******************************************************************************/ +void XHdmiphy1_CfgInitialize(XHdmiphy1 *InstancePtr, + XHdmiphy1_Config *ConfigPtr, + UINTPTR EffectiveAddr) +{ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + u8 Sel; +#endif + + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(ConfigPtr != NULL); + Xil_AssertVoid(EffectiveAddr != 0x0); + + (void)memset((void *)InstancePtr, 0, sizeof(XHdmiphy1)); + InstancePtr->IsReady = 0; + + InstancePtr->Config = *ConfigPtr; + InstancePtr->Config.BaseAddr = EffectiveAddr; + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE3) + InstancePtr->GtAdaptor = &Gthe3Config; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) + InstancePtr->GtAdaptor = &Gthe4Config; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) + InstancePtr->GtAdaptor = &Gtye4Config; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) + InstancePtr->GtAdaptor = &Gtye5Config; +#endif + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + const XHdmiphy1_SysClkDataSelType SysClkCfg[7][2] = { + {(XHdmiphy1_SysClkDataSelType)0, + XHDMIPHY1_SYSCLKSELDATA_TYPE_CPLL_OUTCLK}, + {(XHdmiphy1_SysClkDataSelType)1, + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK}, + {(XHdmiphy1_SysClkDataSelType)2, + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL1_OUTCLK}, + {(XHdmiphy1_SysClkDataSelType)3, + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL_OUTCLK}, + {(XHdmiphy1_SysClkDataSelType)4, + XHDMIPHY1_SYSCLKSELDATA_TYPE_PLL0_OUTCLK}, + {(XHdmiphy1_SysClkDataSelType)5, + XHDMIPHY1_SYSCLKSELDATA_TYPE_PLL1_OUTCLK}, + {(XHdmiphy1_SysClkDataSelType)6, + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK}, + }; + for (Sel = 0; Sel < 7; Sel++) { + if (InstancePtr->Config.TxSysPllClkSel == SysClkCfg[Sel][0]) { + InstancePtr->Config.TxSysPllClkSel = SysClkCfg[Sel][1]; + } + if (InstancePtr->Config.RxSysPllClkSel == SysClkCfg[Sel][0]) { + InstancePtr->Config.RxSysPllClkSel = SysClkCfg[Sel][1]; + } + } + + InstancePtr->Config.TxRefClkSel = (XHdmiphy1_PllRefClkSelType) + (InstancePtr->Config.TxRefClkSel + + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0); + InstancePtr->Config.RxRefClkSel = (XHdmiphy1_PllRefClkSelType) + (InstancePtr->Config.RxRefClkSel + + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0); + InstancePtr->Config.TxFrlRefClkSel = (XHdmiphy1_PllRefClkSelType) + (InstancePtr->Config.TxFrlRefClkSel + + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0); + InstancePtr->Config.RxFrlRefClkSel = (XHdmiphy1_PllRefClkSelType) + (InstancePtr->Config.RxFrlRefClkSel + + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0); + InstancePtr->Config.DruRefClkSel = (XHdmiphy1_PllRefClkSelType) + (InstancePtr->Config.DruRefClkSel + + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0); +#endif + + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; +} + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +/*****************************************************************************/ +/** +* This function will initialize the PLL selection for a given channel. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param QpllRefClkSel is the QPLL reference clock selection for the +* quad. +* @param CpllRefClkSel is the CPLL reference clock selection for the +* quad. +* @param TxPllSelect is the reference clock selection for the quad's +* TX PLL dividers. +* @param RxPllSelect is the reference clock selection for the quad's +* RX PLL dividers. +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_PllInitialize(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, + XHdmiphy1_PllRefClkSelType QpllRefClkSel, + XHdmiphy1_PllRefClkSelType CpllRefClkSel, + XHdmiphy1_PllType TxPllSelect, XHdmiphy1_PllType RxPllSelect) +{ + /* Suppress Warning Messages */ + ChId = ChId; + + /* Set configuration in software. */ + XHdmiphy1_CfgPllRefClkSel(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, QpllRefClkSel); + XHdmiphy1_CfgPllRefClkSel(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CHA, CpllRefClkSel); + XHdmiphy1_CfgSysClkDataSel(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, + Pll2SysClkData(TxPllSelect)); + XHdmiphy1_CfgSysClkDataSel(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, + Pll2SysClkData(RxPllSelect)); + XHdmiphy1_CfgSysClkOutSel(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, + Pll2SysClkOut(TxPllSelect)); + XHdmiphy1_CfgSysClkOutSel(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, + Pll2SysClkOut(RxPllSelect)); + + /* Write configuration to hardware at once. */ + XHdmiphy1_WriteCfgRefClkSelReg(InstancePtr, QuadId); + + return XST_SUCCESS; +} +#endif + +/******************************************************************************/ +/* +* This function installs a custom delay/sleep function to be used by the +* XHdmiphy1 driver. +* +* @param InstancePtr is a pointer to the XHdmiphy1 instance. +* @param CallbackFunc is the address to the callback function. +* @param CallbackRef is the user data item (microseconds to delay) that +* will be passed to the custom sleep/delay function when it is +* invoked. +* +* @return None. +* +* @note None. +* +*******************************************************************************/ +void XHdmiphy1_SetUserTimerHandler(XHdmiphy1 *InstancePtr, + XHdmiphy1_TimerHandler CallbackFunc, void *CallbackRef) +{ + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(CallbackFunc != NULL); + Xil_AssertVoid(CallbackRef != NULL); + + InstancePtr->UserTimerWaitUs = CallbackFunc; + InstancePtr->UserTimerPtr = CallbackRef; +} + +/******************************************************************************/ +/** +* This function is the delay/sleep function for the XHdmiphy1 driver. For the +* Zynq family, there exists native sleep functionality. For MicroBlaze however, +* there does not exist such functionality. In the MicroBlaze case, the default +* method for delaying is to use a predetermined amount of loop iterations. This +* method is prone to inaccuracy and dependent on system configuration; for +* greater accuracy, the user may supply their own delay/sleep handler, pointed +* to by InstancePtr->UserTimerWaitUs, which may have better accuracy if a +* hardware timer is used. +* +* @param InstancePtr is a pointer to the XHdmiphy1 instance. +* @param MicroSeconds is the number of microseconds to delay/sleep for. +* +* @return None. +* +* @note None. +* +*******************************************************************************/ +void XHdmiphy1_WaitUs(XHdmiphy1 *InstancePtr, u32 MicroSeconds) +{ + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + if (MicroSeconds == 0) { + return; + } + + if (InstancePtr->UserTimerWaitUs != NULL) { + /* Use the timer handler specified by the user for better + * accuracy. */ + InstancePtr->UserTimerWaitUs(InstancePtr, MicroSeconds); + } + else { + /* Wait the requested amount of time. */ + usleep_range(MicroSeconds, MicroSeconds + MicroSeconds/10); + } +} + +/*****************************************************************************/ +/** +* This function will obtian the IP version. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* +* @return The IP version of the Video PHY core. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_GetVersion(XHdmiphy1 *InstancePtr) +{ + return XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_VERSION_REG); +} + +/*****************************************************************************/ +/** +* Configure the channel's line rate. This is a software only configuration and +* this value is used in the PLL calculator. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param LineRate is the line rate to configure software. +* +* @return +* - XST_SUCCESS if the reference clock type is valid. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_CfgLineRate(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u64 LineRateHz) +{ + u8 Id; + u8 Id0; + u8 Id1; + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)].LineRateHz = + LineRateHz; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* Obtain the channel's PLL reference clock selection. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param ChId is the channel ID which to operate on. +* +* @return The PLL type being used by the channel. +* +* @note None. +* +******************************************************************************/ +XHdmiphy1_PllType XHdmiphy1_GetPllType(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, XHdmiphy1_ChannelId ChId) +{ + XHdmiphy1_PllType PllType; +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_SysClkDataSelType SysClkDataSel; + XHdmiphy1_SysClkOutSelType SysClkOutSel; + + SysClkDataSel = XHdmiphy1_GetSysClkDataSel(InstancePtr, QuadId, Dir, ChId); + SysClkOutSel = XHdmiphy1_GetSysClkOutSel(InstancePtr, QuadId, Dir, ChId); + + /* The sysclk data and output reference clocks should match. */ + + if ((SysClkDataSel == XHDMIPHY1_SYSCLKSELDATA_TYPE_CPLL_OUTCLK) && + (SysClkOutSel == XHDMIPHY1_SYSCLKSELOUT_TYPE_CPLL_REFCLK)) { + PllType = XHDMIPHY1_PLL_TYPE_CPLL; + } + else if ((SysClkDataSel == XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL_OUTCLK) && + (SysClkOutSel == XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL_REFCLK)) { + PllType = XHDMIPHY1_PLL_TYPE_QPLL; + } + else if ((SysClkDataSel == XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK) && + (SysClkOutSel == XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL0_REFCLK)) { + PllType = XHDMIPHY1_PLL_TYPE_QPLL0; + } + else if ((SysClkDataSel == XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL1_OUTCLK) && + (SysClkOutSel == XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL1_REFCLK)) { + PllType = XHDMIPHY1_PLL_TYPE_QPLL1; + } + else { + PllType = XHDMIPHY1_PLL_TYPE_UNKNOWN; + } +#else + /* Suppress Warning Messages */ + QuadId = QuadId; + ChId = ChId; + + if (Dir == XHDMIPHY1_DIR_TX) { + PllType = (XHdmiphy1_PllType) InstancePtr->Config.TxSysPllClkSel-2; + } + else if (Dir == XHDMIPHY1_DIR_RX) { + PllType = (XHdmiphy1_PllType) InstancePtr->Config.RxSysPllClkSel-2; + } + else { + PllType = XHDMIPHY1_PLL_TYPE_UNKNOWN; + } +#endif + + return PllType; +} + +/*****************************************************************************/ +/** +* This function will return the line rate in Hz for a given channel / quad. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to check. +* @param ChId is the channel ID for which to retrieve the line rate. +* +* @return The line rate in Hz. +* +* @note None. +* +******************************************************************************/ +u64 XHdmiphy1_GetLineRateHz(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid((ChId < XHDMIPHY1_CHANNEL_ID_CMNA)); + + XHdmiphy1_ChannelId Ch_Id = ChId; + + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + Ch_Id = XHDMIPHY1_CHANNEL_ID_CH1; + } else if (ChId == XHDMIPHY1_CHANNEL_ID_CMNA) { + Ch_Id = XHDMIPHY1_CHANNEL_ID_CMN0; + } + + return InstancePtr->Quads[QuadId].Plls[Ch_Id - + XHDMIPHY1_CHANNEL_ID_CH1].LineRateHz; +} + +/*****************************************************************************/ +/** +* This function will reset the GT's PLL logic. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID which to operate on. +* @param Dir is an indicator for TX or RX. +* @param Hold is an indicator whether to "hold" the reset if set to 1. +* If set to 0: reset, then enable. +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_ResetGtPll(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Hold) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_TX_INIT_REG; + } + else { + RegOffset = XHDMIPHY1_RX_INIT_REG; + } + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_TXRX_INIT_PLLGTRESET_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_TXRX_INIT_PLLGTRESET_MASK(ChId); + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + /* Assert reset. */ + RegVal |= MaskVal; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); + + if (!Hold) { + /* De-assert reset. */ + RegVal &= ~MaskVal; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function will reset the GT's TX/RX logic. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID which to operate on. +* @param Dir is an indicator for TX or RX. +* @param Hold is an indicator whether to "hold" the reset if set to 1. +* If set to 0: reset, then enable. +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_ResetGtTxRx(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Hold) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_TX_INIT_REG; + } + else { + RegOffset = XHDMIPHY1_RX_INIT_REG; + } + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_TXRX_INIT_GTRESET_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_TXRX_INIT_GTRESET_MASK(ChId); + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + /* Assert reset. */ + RegVal |= MaskVal; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); + + if (!Hold) { + /* De-assert reset. */ + RegVal &= ~MaskVal; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function will set/clear the TX/RX polarity bit. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID which to operate on. +* @param Dir is an indicator for TX or RX. +* @param Polarity 0-Not inverted 1-Inverted +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_SetPolarity(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Polarity) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_TX_CONTROL_REG; + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_TX_CONTROL_TXPOLARITY_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_TX_CONTROL_TXPOLARITY_MASK(ChId); + } + } + else { + RegOffset = XHDMIPHY1_RX_CONTROL_REG; + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_RX_CONTROL_RXPOLARITY_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_RX_CONTROL_RXPOLARITY_MASK(ChId); + } + } + + /* Read TX|RX Control Register */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + /* Clear Polarity Register bits */ + RegVal &= ~MaskVal; + + if (Polarity) { + RegVal |= MaskVal; + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function will set the TX/RXPRBSEL of the GT +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID which to operate on. +* @param Dir is an indicator for TX or RX. +* @param Pattern is the pattern XHdmiphy1_PrbsPattern +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_SetPrbsSel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + XHdmiphy1_PrbsPattern Pattern) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + u32 PrbsEnc = 0x0; + u8 Id, Id0, Id1; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_TX_CONTROL_REG; + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_TX_CONTROL_TXPRBSSEL_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_TX_CONTROL_TXPRBSSEL_MASK(ChId); + } + PrbsEnc = (u32) (((Pattern & 0x8) << 1) | (Pattern & 0x7)); + } + else { + RegOffset = XHDMIPHY1_RX_CONTROL_REG; + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_RX_CONTROL_RXPRBSSEL_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_RX_CONTROL_RXPRBSSEL_MASK(ChId); + } + PrbsEnc = (u32) (Pattern & 0xF); + } + + /* Read TX|RX Control Register */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + /* Mask out PRBS Register bits */ + RegVal &= ~MaskVal; + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + RegVal |= PrbsEnc << ((Dir == XHDMIPHY1_DIR_TX) ? + XHDMIPHY1_TX_CONTROL_TXPRBSSEL_SHIFT(Id) : + XHDMIPHY1_RX_CONTROL_RXPRBSSEL_SHIFT(Id)); + } + + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function will set the TX/RXPRBSEL of the GT +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID which to operate on. +* @param Dir is an indicator for TX or RX. +* @param ForceErr 0-No Error 1-Force Error +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_TxPrbsForceError(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 ForceErr) +{ + u32 RegVal; + u32 MaskVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_TX_CONTROL_TXPRBSFORCEERR_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_TX_CONTROL_TXPRBSFORCEERR_MASK(ChId); + } + + /* Read TX|RX Control Register */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_CONTROL_REG); + + /* Clear Polarity Register bits */ + RegVal &= ~MaskVal; + + if (ForceErr) { + RegVal |= MaskVal; + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_CONTROL_REG, RegVal); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function will set the TX voltage swing value for a given channel. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Vs is the voltage swing value to write. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_SetTxVoltageSwing(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 Vs) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if ((ChId == XHDMIPHY1_CHANNEL_ID_CH1) || + (ChId == XHDMIPHY1_CHANNEL_ID_CH2)) { + RegOffset = XHDMIPHY1_TX_DRIVER_CH12_REG; + } + else { + RegOffset = XHDMIPHY1_TX_DRIVER_CH34_REG; + } + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + MaskVal = XHDMIPHY1_TX_DRIVER_TXDIFFCTRL_MASK(ChId); + RegVal &= ~MaskVal; + RegVal |= ((Vs & 0xF) << XHDMIPHY1_TX_DRIVER_TXDIFFCTRL_SHIFT(ChId)); + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_DRIVER_EXT_REG); + MaskVal = XHDMIPHY1_TX_DRIVER_EXT_TXDIFFCTRL_MASK(ChId); + RegVal &= ~MaskVal; + RegVal |= ((Vs && 0x10) << + XHDMIPHY1_TX_DRIVER_EXT_TXDIFFCTRL_SHIFT(ChId)); + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_DRIVER_EXT_REG, RegVal); +} + +/*****************************************************************************/ +/** +* This function will set the TX pre-emphasis value for a given channel. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Pe is the pre-emphasis value to write. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_SetTxPreEmphasis(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 Pe) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if ((ChId == XHDMIPHY1_CHANNEL_ID_CH1) || + (ChId == XHDMIPHY1_CHANNEL_ID_CH2)) { + RegOffset = XHDMIPHY1_TX_DRIVER_CH12_REG; + } + else { + RegOffset = XHDMIPHY1_TX_DRIVER_CH34_REG; + } + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + MaskVal = XHDMIPHY1_TX_DRIVER_TXPRECURSOR_MASK(ChId); + RegVal &= ~MaskVal; + RegVal |= (Pe << XHDMIPHY1_TX_DRIVER_TXPRECURSOR_SHIFT(ChId)); + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); +} + +/*****************************************************************************/ +/** +* This function will set the TX post-curosr value for a given channel. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Pe is the pre-emphasis value to write. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_SetTxPostCursor(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 Pc) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if ((ChId == XHDMIPHY1_CHANNEL_ID_CH1) || + (ChId == XHDMIPHY1_CHANNEL_ID_CH2)) { + RegOffset = XHDMIPHY1_TX_DRIVER_CH12_REG; + } + else { + RegOffset = XHDMIPHY1_TX_DRIVER_CH34_REG; + } + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + MaskVal = XHDMIPHY1_TX_DRIVER_TXPOSTCURSOR_MASK(ChId); + RegVal &= ~MaskVal; + RegVal |= (Pc << XHDMIPHY1_TX_DRIVER_TXPOSTCURSOR_SHIFT(ChId)); + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); +} + +/*****************************************************************************/ +/** +* This function will enable or disable the LPM logic in the Video PHY core. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Enable will enable (if 1) or disable (if 0) the LPM logic. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_SetRxLpm(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Enable) +{ + u32 RegVal; + u32 MaskVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + Dir = Dir; + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_RX_EQ_CDR_REG); + + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_RX_CONTROL_RXLPMEN_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_RX_CONTROL_RXLPMEN_MASK(ChId); + } + + if (Enable) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_RX_EQ_CDR_REG, + RegVal); +} + +/*****************************************************************************/ +/** +* This function will initiate a write DRP transaction. It is a wrapper around +* XHdmiphy1_DrpAccess. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID on which to direct the DRP access. +* @param Addr is the DRP address to issue the DRP access to. +* @param Val is the value to write to the DRP address. +* +* @return +* - XST_SUCCESS if the DRP access was successful. +* - XST_FAILURE otherwise, if the busy bit did not go low, or if +* the ready bit did not go high. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_DrpWr(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u16 Addr, u16 Val) +{ + return XHdmiphy1_DrpAccess(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_TX, /* Write. */ + Addr, &Val); +} + +/*****************************************************************************/ +/** +* This function will initiate a read DRP transaction. It is a wrapper around +* XHdmiphy1_DrpAccess. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID on which to direct the DRP access. +* @param Addr is the DRP address to issue the DRP access to. +* @param RetVal is the DRP read_value returned implicitly. +* +* @return +* - XST_SUCCESS if the DRP access was successful. +* - XST_FAILURE otherwise, if the busy bit did not go low, or if +* the ready bit did not go high. +* +* @note None. +* +******************************************************************************/ +u16 XHdmiphy1_DrpRd(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u16 Addr, u16 *RetVal) +{ + u32 Status; + u16 Val; + + Status = XHdmiphy1_DrpAccess(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_RX, /* Read. */ + Addr, &Val); + + *RetVal = Val; + + return Status; +} + +/*****************************************************************************/ +/** +* This function will power down the mixed-mode clock manager (MMCM) core. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Hold is an indicator whether to "hold" the power down if set +* to 1. If set to 0: power down, then power back up. +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_MmcmPowerDown(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u8 Hold) +{ + u32 RegOffsetCtrl; + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffsetCtrl = XHDMIPHY1_MMCM_TXUSRCLK_CTRL_REG; + } + else { + RegOffsetCtrl = XHDMIPHY1_MMCM_RXUSRCLK_CTRL_REG; + } + + /* Power down. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl); + RegVal |= XHDMIPHY1_MMCM_USRCLK_CTRL_PWRDWN_MASK; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl, RegVal); + + if (!Hold) { + /* Power up. */ + RegVal &= ~XHDMIPHY1_MMCM_USRCLK_CTRL_PWRDWN_MASK; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl, + RegVal); + } +} + +/*****************************************************************************/ +/** +* This function will start the mixed-mode clock manager (MMCM) core. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_MmcmStart(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir) +{ + XHdmiphy1_Mmcm *MmcmPtr; + + if (Dir == XHDMIPHY1_DIR_RX) { + MmcmPtr= &InstancePtr->Quads[QuadId].RxMmcm; + } + else { + MmcmPtr= &InstancePtr->Quads[QuadId].TxMmcm; + } + + /* Check values if valid */ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + if (!((MmcmPtr->ClkOut0Div > 0) && (MmcmPtr->ClkOut0Div <= 128) && + (MmcmPtr->ClkOut1Div > 0) && (MmcmPtr->ClkOut1Div <= 128) && + (MmcmPtr->ClkOut2Div > 0) && (MmcmPtr->ClkOut2Div <= 128))) { +#else + if (!((MmcmPtr->ClkOut0Div > 0) && (MmcmPtr->ClkOut0Div <= 432) && + (MmcmPtr->ClkOut1Div > 0) && (MmcmPtr->ClkOut1Div <= 432) && + (MmcmPtr->ClkOut2Div > 0) && (MmcmPtr->ClkOut2Div <= 432))) { +#endif + return; + } + + /* Assert MMCM reset. */ + XHdmiphy1_MmcmReset(InstancePtr, QuadId, Dir, TRUE); + + /* Configure MMCM. */ + XHdmiphy1_MmcmWriteParameters(InstancePtr, QuadId, Dir); + + /* Release MMCM reset. */ + XHdmiphy1_MmcmReset(InstancePtr, QuadId, Dir, FALSE); + + /* Unmask the MMCM Lock */ + XHdmiphy1_MmcmLockedMaskEnable(InstancePtr, 0, Dir, FALSE); + + XHdmiphy1_LogWrite(InstancePtr, (Dir == XHDMIPHY1_DIR_TX) ? + XHDMIPHY1_LOG_EVT_TXPLL_RECONFIG : + XHDMIPHY1_LOG_EVT_RXPLL_RECONFIG, 1); +} + +/*****************************************************************************/ +/** +* This function enables the TX or RX IBUFDS peripheral. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param Dir is an indicator for TX or RX. +* @param Enable specifies TRUE/FALSE value to either enable or disable +* the IBUFDS, respectively. +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_IBufDsEnable(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u8 Enable) +{ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_PllRefClkSelType *TypePtr, *DruTypePtr, DruTypeDummy; + DruTypeDummy = XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTGREFCLK; + DruTypePtr = &DruTypeDummy; +#endif + u32 RegAddr = XHDMIPHY1_IBUFDS_GTXX_CTRL_REG; + u32 RegVal; + u32 MaskVal = 0; + + /* Suppress Warning Messages */ + QuadId = QuadId; + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + if (Dir == XHDMIPHY1_DIR_TX) { + TypePtr = &InstancePtr->Config.TxRefClkSel; + } + else { + TypePtr = &InstancePtr->Config.RxRefClkSel; + if (InstancePtr->Config.DruIsPresent) { + DruTypePtr = &InstancePtr->Config.DruRefClkSel; + } + } + + if ((*TypePtr == XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0) || + ((InstancePtr->Config.DruIsPresent) && + (*DruTypePtr == XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0))) { + MaskVal = XHDMIPHY1_IBUFDS_GTXX_CTRL_GTREFCLK0_CEB_MASK; + } + else if ((*TypePtr == XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK1) || + ((InstancePtr->Config.DruIsPresent) && + (*DruTypePtr == XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK1))) { + MaskVal = XHDMIPHY1_IBUFDS_GTXX_CTRL_GTREFCLK1_CEB_MASK; + } + else { +#endif + if (Dir == XHDMIPHY1_DIR_TX) { + RegAddr = XHDMIPHY1_MISC_TXUSRCLK_REG; + } + else { + RegAddr = XHDMIPHY1_MISC_RXUSRCLK_REG; + } + MaskVal = XHDMIPHY1_MISC_XXUSRCLK_REFCLK_CEB_MASK; +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + } +#endif + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegAddr); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + if (Enable) { + RegVal &= ~MaskVal; + } + else { + RegVal |= MaskVal; + } +#else + if (Enable) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } +#endif + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegAddr, RegVal); +} + +/*****************************************************************************/ +/** +* This function enables the TX or RX CLKOUT1 OBUFTDS peripheral. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param Dir is an indicator for TX or RX. +* @param Enable specifies TRUE/FALSE value to either enable or disable +* the OBUFTDS, respectively. +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_Clkout1OBufTdsEnable(XHdmiphy1 *InstancePtr, + XHdmiphy1_DirectionType Dir, u8 Enable) +{ + u32 RegVal; + u32 RegOffset; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_MISC_TXUSRCLK_REG; + } + else { + RegOffset = XHDMIPHY1_MISC_RXUSRCLK_REG; + } + + /* Read XXUSRCLK MISC register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + /* Write new value to XXUSRCLK MISC register. */ + if (Enable) { + RegVal |= XHDMIPHY1_MISC_XXUSRCLK_CKOUT1_OEN_MASK; + } + else { + RegVal &= ~XHDMIPHY1_MISC_XXUSRCLK_CKOUT1_OEN_MASK; + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); +} + +/*****************************************************************************/ +/** +* This function will initiate a DRP transaction (either read or write). +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID on which to direct the DRP access. +* @param Dir is an indicator for write (TX) or read (RX). +* @param Addr is the DRP address to issue the DRP access to. +* @param Val is a pointer to the data value. In write mode, this pointer +* will hold the value to write. In read mode, this pointer will +* be populated with the read value. +* +* @return +* - XST_SUCCESS if the DRP access was successful. +* - XST_FAILURE otherwise, if the busy bit did not go low, or if +* the ready bit did not go high. +* +* @note In read mode (Dir == XHDMIPHY1_DIR_RX), the data pointed to by Val +* will be populated with the u16 value that was read._ +* +******************************************************************************/ +static u32 XHdmiphy1_DrpAccess(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + u16 Addr, u16 *Val) +{ + u32 RegOffsetCtrl; + u32 RegOffsetSts; + u32 RegVal; + u8 Retry; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + /* Determine which DRP registers to use based on channel. */ + if (XHDMIPHY1_ISCMN(ChId)) { + RegOffsetCtrl = XHDMIPHY1_DRP_CONTROL_COMMON_REG; + RegOffsetSts = XHDMIPHY1_DRP_STATUS_COMMON_REG; + } + else if (XHDMIPHY1_ISTXMMCM(ChId)) { + RegOffsetCtrl = XHDMIPHY1_DRP_CONTROL_TXMMCM_REG; + RegOffsetSts = XHDMIPHY1_DRP_STATUS_TXMMCM_REG; + } + else if (XHDMIPHY1_ISRXMMCM(ChId)) { + RegOffsetCtrl = XHDMIPHY1_DRP_CONTROL_RXMMCM_REG; + RegOffsetSts = XHDMIPHY1_DRP_STATUS_RXMMCM_REG; + } + else { + RegOffsetCtrl = XHDMIPHY1_DRP_CONTROL_CH1_REG + + (4 * XHDMIPHY1_CH2IDX(ChId)); + RegOffsetSts = XHDMIPHY1_DRP_STATUS_CH1_REG + + (4 * (XHDMIPHY1_CH2IDX(ChId))); + } + + /* Wait until the DRP status indicates that it is not busy.*/ + Retry = 0; + do { + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + RegOffsetSts); + if (Retry > 150) { + return XST_FAILURE; + } + Retry++; + } while (RegVal & XHDMIPHY1_DRP_STATUS_DRPBUSY_MASK); + + /* Write the command to the channel's DRP. */ + RegVal = (Addr & XHDMIPHY1_DRP_CONTROL_DRPADDR_MASK); + RegVal |= XHDMIPHY1_DRP_CONTROL_DRPEN_MASK; + if (Dir == XHDMIPHY1_DIR_TX) { + /* Enable write. */ + RegVal |= XHDMIPHY1_DRP_CONTROL_DRPWE_MASK; + RegVal |= ((*Val << XHDMIPHY1_DRP_CONTROL_DRPDI_SHIFT) & + XHDMIPHY1_DRP_CONTROL_DRPDI_MASK); + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl, RegVal); + + /* Wait until the DRP status indicates ready.*/ + Retry = 0; + do { + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + RegOffsetSts); + if (Retry > 150) { + return XST_FAILURE; + } + Retry++; + } while (!(RegVal & XHDMIPHY1_DRP_STATUS_DRPRDY_MASK)); + + if (Dir == XHDMIPHY1_DIR_RX) { + /* Mask non-data out for read. */ + RegVal &= XHDMIPHY1_DRP_STATUS_DRPO_MASK; + /* Populate Val with read contents. */ + *Val = RegVal; + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function installs a callback function for the HDMIPHY error conditions +* +* @param InstancePtr is a pointer to the XHdmiphy1 instance. +* @param CallbackFunc is the address to the callback function. +* @param CallbackRef is the user data item that will be passed to the +* callback function when it is invoked. +* +* @return None. +* +* @note The XHdmiphy1_ErrorHandler API calls the registered function in +* ErrorCallback and passes two arguments: 1) CallbackRef +* 2) Error Type as defined by XHdmiphy1_ErrType. +* +* Sample Function Call: +* CallbackFunc(CallbackRef, XHdmiphy1_ErrType); +* +******************************************************************************/ +void XHdmiphy1_SetErrorCallback(XHdmiphy1 *InstancePtr, + void *CallbackFunc, void *CallbackRef) +{ + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(CallbackFunc != NULL); + Xil_AssertVoid(CallbackRef != NULL); + + InstancePtr->ErrorCallback = (XHdmiphy1_ErrorCallback)CallbackFunc; + InstancePtr->ErrorRef = CallbackRef; +} + +/*****************************************************************************/ +/** +* +* This function installs an asynchronous callback function for the LogWrite +* API: +* +* @param InstancePtr is a pointer to the XHdmiphy1 instance. +* @param CallbackFunc is the address of the callback function. +* @param CallbackRef is a user data item that will be passed to the +* callback function when it is invoked. +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_SetLogCallback(XHdmiphy1 *InstancePtr, + u64 *CallbackFunc, void *CallbackRef) +{ + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(CallbackFunc != NULL); + Xil_AssertVoid(CallbackRef != NULL); + + InstancePtr->LogWriteCallback = (XHdmiphy1_LogCallback)CallbackFunc; + InstancePtr->LogWriteRef = CallbackRef; +} + +/*****************************************************************************/ +/** +* This function prints out Video PHY register and GT Channel and Common +* DRP register contents. +* +* @param InstancePtr is a pointer to the Hdmiphy core instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_RegisterDebug(XHdmiphy1 *InstancePtr) +{ + u32 RegOffset; +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + u16 DrpAddr, MaxDrpAddr; + u16 DrpVal, ChId; + u8 MaxChannels; +#endif + + xil_printf("\r\nHDMIPHY Registers\r\n"); + xil_printf("-----------------\r\n"); + xil_printf("Offset | Value\r\n"); + xil_printf("-----------------\r\n"); + for (RegOffset = 0; RegOffset <= 0x334; ) { + xil_printf("0x%04x 0x%08x\r\n",RegOffset, + XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset)); + RegOffset += 4; + } + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE3) + MaxDrpAddr = 0x00B0; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) + MaxDrpAddr = 0x00B0; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) + MaxDrpAddr = 0x00B0; +#endif + + xil_printf("\r\nHDMIPHY GT COMMON DRP Registers\r\n"); + xil_printf("----------------------------\r\n"); + if (InstancePtr->HdmiIsQpllPresent == TRUE) { + xil_printf("Offset | Value\r\n"); + xil_printf("----------------------------\r\n"); + for (DrpAddr = 0x0000; DrpAddr <= MaxDrpAddr; DrpAddr++) { + XHdmiphy1_DrpRd(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CMN0, + DrpAddr, &DrpVal); + xil_printf("0x%04x 0x%04x\r\n",DrpAddr, DrpVal); + } + } else { + xil_printf("No QPLL in this HDMIPHY Instance\r\n"); + } + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE3) + MaxDrpAddr = 0x00CF; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) + MaxDrpAddr = 0x0125; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) + MaxDrpAddr = 0x0135; +#endif + /* Get Max number of channels in HDMIPHY */ + MaxChannels = (InstancePtr->Config.RxChannels > + InstancePtr->Config.TxChannels) ? + InstancePtr->Config.RxChannels : + InstancePtr->Config.TxChannels; + + for (ChId = 1; ChId <= MaxChannels; ChId++) { + xil_printf("\r\nHDMIPHY GT CHANNEL %d DRP Registers\r\n", ChId); + xil_printf("-------------------------------\r\n"); + xil_printf("Offset | Value\r\n"); + xil_printf("-------------------------------\r\n"); + for (DrpAddr = 0x0000; DrpAddr <= MaxDrpAddr; DrpAddr++) { + XHdmiphy1_DrpRd(InstancePtr, 0, ChId, DrpAddr, &DrpVal); + xil_printf("0x%04x 0x%04x\r\n",DrpAddr, DrpVal); + } + } +#endif +} diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1.h b/hdmi/phy-xilinx-vphy/xhdmiphy1.h new file mode 100644 index 0000000..e566a7a --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1.h @@ -0,0 +1,1028 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1.h + * @addtogroup xhdmiphy1_v1_0 + * @{ + * @details + * This is main header file of the Xilinx HDMI PHY Controller driver + * + * Video PHY Controller Overview + * + * The PHY is intended to simplify the use of serial transceivers and adds + * domain-specific configurability. The Video PHY Controller IP is not intended + * to be used as a stand alone IP and must be used with Xilinx Video MACs such + * as HDMI 2.1 Transmitter/Receiver Subsystems. The core enables simpler + * connectivity between MAC layers for TX and RX paths. However, it is still + * important to understand the behavior, usage, and any limitations of the + * transceivers. See the device specific transceiver user guide for details. + * + * Video PHY Controller Driver Features + * + * Video PHY Controller driver supports following features + * - Xilinx HDMI 2.1 MAC IP + * - GTHE3, GTHE4 and GTYE4 GT types + * - HDMI: + * - 4 pixel-wide video interface + * - 8/10/12 bits per component + * - RGB & YCbCr color space + * - Up to 10k resolution at both Input and Output interface + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +#ifndef XHDMIPHY1_H_ +/* Prevent circular inclusions by using protection macros. */ +#define XHDMIPHY1_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(XV_CONFIG_LOG_HDMIPHY1_DISABLE) && \ + !defined(XV_CONFIG_LOG_DISABLE_ALL) +#define XV_HDMIPHY1_LOG_ENABLE +#endif + +/******************************* Include Files ********************************/ + +#include "xil_assert.h" +#include "xhdmiphy1_hw.h" +#include "xvidc.h" + +/******************* Macros (Inline Functions) Definitions ********************/ + +#define XHDMIPHY1_GTHE3 4 +#define XHDMIPHY1_GTHE4 5 +#define XHDMIPHY1_GTYE4 6 +#define XHDMIPHY1_GTYE5 7 + +/****************************** Type Definitions ******************************/ + +/* This typedef enumerates the different GT types available. */ +typedef enum { + XHDMIPHY1_GT_TYPE_GTHE3 = 4, + XHDMIPHY1_GT_TYPE_GTHE4 = 5, + XHDMIPHY1_GT_TYPE_GTYE4 = 6, + XHDMIPHY1_GT_TYPE_GTYE5 = 7, +} XHdmiphy1_GtType; + +/** + * This typedef enumerates the various protocols handled by the Video PHY + * controller (HDMIPHY). + */ +typedef enum { + XHDMIPHY1_PROTOCOL_HDMI = 1, + XHDMIPHY1_PROTOCOL_HDMI21 = 2, + XHDMIPHY1_PROTOCOL_NONE = 3 +} XHdmiphy1_ProtocolType; + +/* This typedef enumerates is used to specify RX/TX direction information. */ +typedef enum { + XHDMIPHY1_DIR_RX = 0, + XHDMIPHY1_DIR_TX, + XHDMIPHY1_DIR_NONE +} XHdmiphy1_DirectionType; + +/** + * This typedef enumerates the list of available interrupt handler types. The + * values are used as parameters to the XHdmiphy1_SetIntrHandler function. + */ +typedef enum { + XHDMIPHY1_INTR_HANDLER_TYPE_TXRESET_DONE = + XHDMIPHY1_INTR_TXRESETDONE_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_RXRESET_DONE = + XHDMIPHY1_INTR_RXRESETDONE_MASK, +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHDMIPHY1_INTR_HANDLER_TYPE_CPLL_LOCK = + XHDMIPHY1_INTR_CPLL_LOCK_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL_LOCK = + XHDMIPHY1_INTR_QPLL_LOCK_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL0_LOCK = + XHDMIPHY1_INTR_QPLL_LOCK_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_TXALIGN_DONE = + XHDMIPHY1_INTR_TXALIGNDONE_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL1_LOCK = + XHDMIPHY1_INTR_QPLL1_LOCK_MASK, +#else + XHDMIPHY1_INTR_HANDLER_TYPE_LCPLL_LOCK = + XHDMIPHY1_INTR_LCPLL_LOCK_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_RPLL_LOCK = + XHDMIPHY1_INTR_RPLL_LOCK_MASK, +#endif + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE = + XHDMIPHY1_INTR_TXCLKDETFREQCHANGE_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE = + XHDMIPHY1_INTR_RXCLKDETFREQCHANGE_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE = + XHDMIPHY1_INTR_TXMMCMUSRCLK_LOCK_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE = + XHDMIPHY1_INTR_RXMMCMUSRCLK_LOCK_MASK, +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) + XHDMIPHY1_INTR_HANDLER_TYPE_TX_GPO_RISING_EDGE = + XHDMIPHY1_INTR_TXGPO_RE_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_GPO_RISING_EDGE = + XHDMIPHY1_INTR_RXGPO_RE_MASK, +#endif + XHDMIPHY1_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT = + XHDMIPHY1_INTR_TXTMRTIMEOUT_MASK, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT = + XHDMIPHY1_INTR_RXTMRTIMEOUT_MASK, +} XHdmiphy1_IntrHandlerType; + +/** + * This typedef enumerates the list of available hdmi handler types. The + * values are used as parameters to the XHdmiphy1_SetHdmiCallback function. + */ +typedef enum { + XHDMIPHY1_HDMI_HANDLER_TXINIT = 1, /**< TX init handler. */ + XHDMIPHY1_HDMI_HANDLER_TXREADY, /**< TX ready handler. */ + XHDMIPHY1_HDMI_HANDLER_RXINIT, /**< RX init handler. */ + XHDMIPHY1_HDMI_HANDLER_RXREADY /**< RX ready handler. */ +} XHdmiphy1_HdmiHandlerType; + +/** + * This typedef enumerates the different PLL types for a given GT channel. + */ +typedef enum { + XHDMIPHY1_PLL_TYPE_CPLL = 1, + XHDMIPHY1_PLL_TYPE_QPLL = 2, + XHDMIPHY1_PLL_TYPE_QPLL0 = 3, + XHDMIPHY1_PLL_TYPE_QPLL1 = 4, + XHDMIPHY1_PLL_TYPE_LCPLL = 5, + XHDMIPHY1_PLL_TYPE_RPLL = 6, + XHDMIPHY1_PLL_TYPE_UNKNOWN = 7, +} XHdmiphy1_PllType; + +/** + * This typedef enumerates the available channels. + */ +typedef enum { + XHDMIPHY1_CHANNEL_ID_CH1 = 1, + XHDMIPHY1_CHANNEL_ID_CH2 = 2, + XHDMIPHY1_CHANNEL_ID_CH3 = 3, + XHDMIPHY1_CHANNEL_ID_CH4 = 4, + XHDMIPHY1_CHANNEL_ID_CMN0 = 5, /* QPLL, QPLL0, LCPLL */ + XHDMIPHY1_CHANNEL_ID_CMN1 = 6, /* QPLL1, RPLL */ + XHDMIPHY1_CHANNEL_ID_CHA = 7, + XHDMIPHY1_CHANNEL_ID_CMNA = 8, + XHDMIPHY1_CHANNEL_ID_TXMMCM = 9, + XHDMIPHY1_CHANNEL_ID_RXMMCM = 10, + XHDMIPHY1_CHANNEL_ID_CMN = XHDMIPHY1_CHANNEL_ID_CMN0, +} XHdmiphy1_ChannelId; + +/** + * This typedef enumerates the available reference clocks for the PLL clock + * selection multiplexer. + */ +typedef enum { + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTREFCLK0, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK1 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTREFCLK1, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTNORTHREFCLK0 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTNORTHREFCLK0, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTNORTHREFCLK1 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTNORTHREFCLK1, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTSOUTHREFCLK0 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTSOUTHREFCLK0, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTSOUTHREFCLK1 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTSOUTHREFCLK1, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTEASTREFCLK0 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTEASTREFCLK0, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTEASTREFCLK1 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTEASTREFCLK1, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTWESTREFCLK0 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTWESTREFCLK0, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTWESTREFCLK1 = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTWESTREFCLK1, + XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTGREFCLK = + XHDMIPHY1_REF_CLK_SEL_XPLL_GTGREFCLK, +} XHdmiphy1_PllRefClkSelType; + +/** + * This typedef enumerates the available reference clocks used to drive the + * RX/TX datapaths. + */ +typedef enum { + XHDMIPHY1_SYSCLKSELDATA_TYPE_PLL0_OUTCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_PLL0, + XHDMIPHY1_SYSCLKSELDATA_TYPE_PLL1_OUTCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_PLL1, + XHDMIPHY1_SYSCLKSELDATA_TYPE_CPLL_OUTCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_CPLL, + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL_OUTCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_QPLL, + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_QPLL0, + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL1_OUTCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_QPLL1, +} XHdmiphy1_SysClkDataSelType; + +/** + * This typedef enumerates the available reference clocks used to drive the + * RX/TX output clocks. + */ +typedef enum { + XHDMIPHY1_SYSCLKSELOUT_TYPE_CPLL_REFCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CH, + XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL_REFCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CMN, + XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL0_REFCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CMN0, + XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL1_REFCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CMN1, + XHDMIPHY1_SYSCLKSELOUT_TYPE_PLL0_REFCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CH, + XHDMIPHY1_SYSCLKSELOUT_TYPE_PLL1_REFCLK = + XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CMN, +} XHdmiphy1_SysClkOutSelType; + +/** + * This typedef enumerates the available clocks that are used as multiplexer + * input selections for the RX/TX output clock. + */ +typedef enum { + XHDMIPHY1_OUTCLKSEL_TYPE_OUTCLKPCS = 1, + XHDMIPHY1_OUTCLKSEL_TYPE_OUTCLKPMA, + XHDMIPHY1_OUTCLKSEL_TYPE_PLLREFCLK_DIV1, + XHDMIPHY1_OUTCLKSEL_TYPE_PLLREFCLK_DIV2, + XHDMIPHY1_OUTCLKSEL_TYPE_PROGDIVCLK +} XHdmiphy1_OutClkSelType; + +/* This typedef enumerates the possible states a transceiver can be in. */ +typedef enum { + XHDMIPHY1_GT_STATE_IDLE, /**< Idle state. */ + XHDMIPHY1_GT_STATE_GPO_RE, /**< GPO RE state. */ + XHDMIPHY1_GT_STATE_LOCK, /**< Lock state. */ + XHDMIPHY1_GT_STATE_RESET, /**< Reset state. */ + XHDMIPHY1_GT_STATE_ALIGN, /**< Align state. */ + XHDMIPHY1_GT_STATE_READY, /**< Ready state. */ +} XHdmiphy1_GtState; + +#ifdef XV_HDMIPHY1_LOG_ENABLE +typedef enum { + XHDMIPHY1_LOG_EVT_NONE = 1, /**< Log event none. */ + XHDMIPHY1_LOG_EVT_QPLL_EN, /**< Log event QPLL enable. */ + XHDMIPHY1_LOG_EVT_QPLL_RST, /**< Log event QPLL reset. */ + XHDMIPHY1_LOG_EVT_QPLL_LOCK, /**< Log event QPLL lock. */ + XHDMIPHY1_LOG_EVT_QPLL_RECONFIG, /**< Log event QPLL reconfig. */ + XHDMIPHY1_LOG_EVT_QPLL0_EN, /**< Log event QPLL0 enable. */ + XHDMIPHY1_LOG_EVT_QPLL0_RST, /**< Log event QPLL0 reset. */ + XHDMIPHY1_LOG_EVT_QPLL0_LOCK, /**< Log event QPLL0 lock. */ + XHDMIPHY1_LOG_EVT_QPLL0_RECONFIG,/**< Log event QPLL0 reconfig. */ + XHDMIPHY1_LOG_EVT_QPLL1_EN, /**< Log event QPLL1 enable. */ + XHDMIPHY1_LOG_EVT_QPLL1_RST, /**< Log event QPLL1 reset. */ + XHDMIPHY1_LOG_EVT_QPLL1_LOCK, /**< Log event QPLL1 lock. */ + XHDMIPHY1_LOG_EVT_QPLL1_RECONFIG,/**< Log event QPLL1 reconfig. */ + XHDMIPHY1_LOG_EVT_PLL0_EN, /**< Log event PLL0 reset. */ + XHDMIPHY1_LOG_EVT_PLL0_RST, /**< Log event PLL0 reset. */ + XHDMIPHY1_LOG_EVT_PLL1_EN, /**< Log event PLL1 reset. */ + XHDMIPHY1_LOG_EVT_PLL1_RST, /**< Log event PLL1 reset. */ + XHDMIPHY1_LOG_EVT_CPLL_EN, /**< Log event CPLL reset. */ + XHDMIPHY1_LOG_EVT_CPLL_RST, /**< Log event CPLL reset. */ + XHDMIPHY1_LOG_EVT_CPLL_LOCK, /**< Log event CPLL lock. */ + XHDMIPHY1_LOG_EVT_CPLL_RECONFIG, /**< Log event CPLL reconfig. */ + XHDMIPHY1_LOG_EVT_LCPLL_LOCK, /**< Log event LCPLL lock. */ + XHDMIPHY1_LOG_EVT_RPLL_LOCK, /**< Log event RPLL lock. */ + XHDMIPHY1_LOG_EVT_TXPLL_EN, /**< Log event TXPLL enable. */ + XHDMIPHY1_LOG_EVT_TXPLL_RST, /**< Log event TXPLL reset. */ + XHDMIPHY1_LOG_EVT_RXPLL_EN, /**< Log event RXPLL enable. */ + XHDMIPHY1_LOG_EVT_RXPLL_RST, /**< Log event RXPLL reset. */ + XHDMIPHY1_LOG_EVT_GTRX_RST, /**< Log event GT RX reset. */ + XHDMIPHY1_LOG_EVT_GTTX_RST, /**< Log event GT TX reset. */ + XHDMIPHY1_LOG_EVT_VID_TX_RST, /**< Log event Vid TX reset. */ + XHDMIPHY1_LOG_EVT_VID_RX_RST, /**< Log event Vid RX reset. */ + XHDMIPHY1_LOG_EVT_TX_ALIGN, /**< Log event TX align. */ + XHDMIPHY1_LOG_EVT_TX_ALIGN_TMOUT,/**< Log event TX align Timeout. */ + XHDMIPHY1_LOG_EVT_TX_TMR, /**< Log event TX timer. */ + XHDMIPHY1_LOG_EVT_RX_TMR, /**< Log event RX timer. */ + XHDMIPHY1_LOG_EVT_GT_RECONFIG, /**< Log event GT reconfig. */ + XHDMIPHY1_LOG_EVT_GT_TX_RECONFIG,/**< Log event GT reconfig. */ + XHDMIPHY1_LOG_EVT_GT_RX_RECONFIG,/**< Log event GT reconfig. */ + XHDMIPHY1_LOG_EVT_INIT, /**< Log event init. */ + XHDMIPHY1_LOG_EVT_TXPLL_RECONFIG,/**< Log event TXPLL reconfig. */ + XHDMIPHY1_LOG_EVT_RXPLL_RECONFIG,/**< Log event RXPLL reconfig. */ + XHDMIPHY1_LOG_EVT_RXPLL_LOCK, /**< Log event RXPLL lock. */ + XHDMIPHY1_LOG_EVT_TXPLL_LOCK, /**< Log event TXPLL lock. */ + XHDMIPHY1_LOG_EVT_TX_RST_DONE, /**< Log event TX reset done. */ + XHDMIPHY1_LOG_EVT_RX_RST_DONE, /**< Log event RX reset done. */ + XHDMIPHY1_LOG_EVT_TX_FREQ, /**< Log event TX frequency. */ + XHDMIPHY1_LOG_EVT_RX_FREQ, /**< Log event RX frequency. */ + XHDMIPHY1_LOG_EVT_DRU_EN, /**< Log event DRU enable/disable. */ + XHDMIPHY1_LOG_EVT_TXGPO_RE, /**< Log event TX GPO Rising Edge. */ + XHDMIPHY1_LOG_EVT_RXGPO_RE, /**< Log event RX GPO Rising Edge. */ + XHDMIPHY1_LOG_EVT_FRL_RECONFIG, /**< Log event FRL TX Reconfig. */ + XHDMIPHY1_LOG_EVT_TMDS_RECONFIG, /**< Log event TMDS TX Reconfig. */ + XHDMIPHY1_LOG_EVT_1PPC_ERR, /**< Log event 1 PPC Error. */ + XHDMIPHY1_LOG_EVT_PPC_MSMTCH_ERR,/**< Log event PPC MismatchError. */ + XHDMIPHY1_LOG_EVT_VDCLK_HIGH_ERR,/**< Log evt VidClk > 148.5 MHz. */ + XHDMIPHY1_LOG_EVT_NO_DRU, /**< Log evt Vid not supported no DRU. */ + XHDMIPHY1_LOG_EVT_GT_QPLL_CFG_ERR,/**< Log event QPLL Config not found. */ + XHDMIPHY1_LOG_EVT_GT_CPLL_CFG_ERR,/**< Log evt LCPLL Config not found. */ + XHDMIPHY1_LOG_EVT_GT_LCPLL_CFG_ERR,/**< Log evt RPLL Config not found. */ + XHDMIPHY1_LOG_EVT_GT_RPLL_CFG_ERR,/**< Log event QPLL Config not found. */ + XHDMIPHY1_LOG_EVT_VD_NOT_SPRTD_ERR,/**< Log evt Vid fmt not supported. */ + XHDMIPHY1_LOG_EVT_MMCM_ERR, /**< Log event MMCM Config not found. */ + XHDMIPHY1_LOG_EVT_HDMI20_ERR, /**< Log event HDMI2.0 not supported. */ + XHDMIPHY1_LOG_EVT_NO_QPLL_ERR, /**< Log event QPLL not present. */ + XHDMIPHY1_LOG_EVT_DRU_CLK_ERR, /**< Log event DRU clk wrong freq. */ + XHDMIPHY1_LOG_EVT_USRCLK_ERR, /**< Log event usrclk > 297 MHz. */ + XHDMIPHY1_LOG_EVT_SPDGRDE_ERR, /**< Log event Speed Grade -1 error. */ + XHDMIPHY1_LOG_EVT_DUMMY, /**< Dummy Event should be last */ +} XHdmiphy1_LogEvent; +#endif + +/* This typedef enumerates the different MMCM Dividers */ +typedef enum { + XHDMIPHY1_MMCM_CLKFBOUT_MULT_F, /* M */ + XHDMIPHY1_MMCM_DIVCLK_DIVIDE, /* D */ + XHDMIPHY1_MMCM_CLKOUT_DIVIDE /* On */ +} XHdmiphy1_MmcmDivType; + +/* This typedef enumerates the different MMCM CLKINSEL */ +typedef enum { + XHDMIPHY1_MMCM_CLKINSEL_CLKIN1 = 1, + XHDMIPHY1_MMCM_CLKINSEL_CLKIN2 = 0, +} XHdmiphy1_MmcmClkinsel; + +/* This typedef enumerates the Linerate to TMDS Clock ratio + * for HDMI TX TMDS Clock pattern generator. */ +typedef enum { + XHDMIPHY1_Patgen_Ratio_10 = 0x1, /**< LR:Clock Ratio = 10 */ + XHDMIPHY1_Patgen_Ratio_20 = 0x2, /**< LR:Clock Ratio = 20 */ + XHDMIPHY1_Patgen_Ratio_30 = 0x3, /**< LR:Clock Ratio = 30 */ + XHDMIPHY1_Patgen_Ratio_40 = 0x4, /**< LR:Clock Ratio = 40 */ + XHDMIPHY1_Patgen_Ratio_50 = 0x5, /**< LR:Clock Ratio = 50 */ +} XHdmiphy1_HdmiTx_Patgen; + +/** + * This typedef enumerates the available PRBS patterns available + * from the + */ +typedef enum { + XHDMIPHY1_PRBSSEL_STD_MODE = 0x0, /**< Pattern gen/mon OFF */ + XHDMIPHY1_PRBSSEL_PRBS7 = 0x1, /**< PRBS-7 */ + XHDMIPHY1_PRBSSEL_PRBS9 = 0x2, /**< PRBS-9 */ + XHDMIPHY1_PRBSSEL_PRBS15 = 0x3, /**< PRBS-15 */ + XHDMIPHY1_PRBSSEL_PRBS23 = 0x4, /**< PRBS-23 */ + XHDMIPHY1_PRBSSEL_PRBS31 = 0x5, /**< PRBS-31 */ + XHDMIPHY1_PRBSSEL_PCIE = 0x8, /**< PCIE Compliance Pattern */ + XHDMIPHY1_PRBSSEL_SQUARE_2UI = 0x9, /**< Square wave with 2 UI */ + XHDMIPHY1_PRBSSEL_SQUARE_16UI = 0xA, /**< Square wave with 16 UI */ +} XHdmiphy1_PrbsPattern; + +/******************************************************************************/ +/** + * Callback type which represents the handler for interrupts. + * + * @param InstancePtr is a pointer to the XHdmiphy1 instance. + * + * @note None. + * +*******************************************************************************/ +typedef void (*XHdmiphy1_IntrHandler)(void *InstancePtr); + +/******************************************************************************/ +/** + * Callback type which represents a custom timer wait handler. This is only + * used for Microblaze since it doesn't have a native sleep function. To avoid + * dependency on a hardware timer, the default wait functionality is + * implemented using loop iterations; this isn't too accurate. If a custom + * timer handler is used, the user may implement their own wait implementation + * using a hardware timer (see example/) for better accuracy. + * + * @param InstancePtr is a pointer to the XHdmiphy1 instance. + * @param MicroSeconds is the number of microseconds to be passed to the + * timer function. + * + * @note None. + * +*******************************************************************************/ +typedef void (*XHdmiphy1_TimerHandler)(void *InstancePtr, u32 MicroSeconds); + +/******************************************************************************/ +/** + * Generic callback type. + * + * @param CallbackRef is a pointer to the callback reference. + * + * @note None. + * +*******************************************************************************/ +typedef void (*XHdmiphy1_Callback)(void *CallbackRef); + +/******************************************************************************/ +/** + * Generic callback type. + * + * @param CallbackRef is a pointer to the callback reference. + * + * @note u8 value. + * +*******************************************************************************/ +typedef u64 (*XHdmiphy1_LogCallback)(void *CallbackRef); + +/******************************************************************************/ +/** + * Error callback type. + * + * @param CallbackRef is a pointer to the callback reference. + * + * @note None. + * +*******************************************************************************/ +typedef void (*XHdmiphy1_ErrorCallback)(void *CallbackRef); +/** + * This typedef contains configuration information for CPLL/QPLL programming. + */ +typedef struct { + u8 MRefClkDiv; + /* Aliases for N (QPLL) and N1/N2 (CPLL). */ + union { + u8 NFbDivs[2]; + u8 NFbDiv; + struct { + u8 N1FbDiv; + u8 N2FbDiv; + }; + }; + u16 Cdr[5]; + u8 IsLowerBand; +} XHdmiphy1_PllParam; + +/** + * This typedef contains configuration information for PLL type and its + * reference clock. + */ +typedef struct { + /* Below members are common between CPLL/QPLL. */ + u64 LineRateHz; /**< The line rate for the + channel. */ + union { + XHdmiphy1_PllParam QpllParams; + XHdmiphy1_PllParam CpllParams; /**< Parameters for a CPLL. */ + XHdmiphy1_PllParam PllParams; + u16 LineRateCfg; + }; + union { + XHdmiphy1_PllRefClkSelType CpllRefClkSel; + /**< Multiplexer selection for + the reference clock of + the CPLL. */ + XHdmiphy1_PllRefClkSelType PllRefClkSel; + }; + /* Below members are CPLL specific. */ + union { + struct { + u8 RxOutDiv; /**< Output clock divider D for + the RX datapath. */ + u8 TxOutDiv; /**< Output clock divider D for + the TX datapath. */ + }; + u8 OutDiv[2]; + }; + union { + struct { + XHdmiphy1_GtState RxState; /**< Current state of RX GT. */ + XHdmiphy1_GtState TxState; /**< Current state of TX GT. */ + }; + XHdmiphy1_GtState GtState[2]; + }; + union { + struct { + XHdmiphy1_ProtocolType RxProtocol; + /**< The protocol which the RX + path is used for. */ + XHdmiphy1_ProtocolType TxProtocol; + /**< The protocol which the TX + path is used for. */ + }; + XHdmiphy1_ProtocolType Protocol[2]; + }; + union { + struct { + XHdmiphy1_SysClkDataSelType RxDataRefClkSel; + /**< Multiplexer selection for + the reference clock of + the RX datapath. */ + XHdmiphy1_SysClkDataSelType TxDataRefClkSel; + /**< Multiplexer selection for + the reference clock of + the TX datapath. */ + }; + XHdmiphy1_SysClkDataSelType DataRefClkSel[2]; + }; + union { + struct { + XHdmiphy1_SysClkOutSelType RxOutRefClkSel; + /**< Multiplexer selection for + the reference clock of + the RX output clock. */ + XHdmiphy1_SysClkOutSelType TxOutRefClkSel; + /**< Multiplexer selection for + the reference clock of + the TX output clock. */ + }; + XHdmiphy1_SysClkOutSelType OutRefClkSel[2]; + }; + union { + struct { + XHdmiphy1_OutClkSelType RxOutClkSel; + /**< Multiplexer selection for + which clock to use as + the RX output clock. */ + XHdmiphy1_OutClkSelType TxOutClkSel; + /**< Multiplexer selection for + which clock to use as + the TX output clock. */ + }; + XHdmiphy1_OutClkSelType OutClkSel[2]; + }; + union { + struct { + u8 RxDelayBypass; /**< Bypasses the delay + alignment block for the + RX output clock. */ + u8 TxDelayBypass; /**< Bypasses the delay + alignment block for the + TX output clock. */ + }; + u8 DelayBypass; + }; + u8 RxDataWidth; /**< In bits. */ + u8 RxIntDataWidth; /**< In bytes. */ + u8 TxDataWidth; /**< In bits. */ + u8 TxIntDataWidth; /**< In bytes. */ +} XHdmiphy1_Channel; + +/** + * This typedef contains configuration information for MMCM programming. + */ +typedef struct { + u16 DivClkDivide; + u16 ClkFbOutMult; + u16 ClkFbOutFrac; + u16 ClkOut0Div; + u16 ClkOut0Frac; + u16 ClkOut1Div; + u16 ClkOut2Div; +} XHdmiphy1_Mmcm; + +/** + * This typedef represents a GT quad. + */ +typedef struct { + union { + struct { + XHdmiphy1_Mmcm RxMmcm; /**< Mixed-mode clock manager + (MMCM) parameters for + RX. */ + XHdmiphy1_Mmcm TxMmcm; /**< MMCM parameters for TX. */ + }; + XHdmiphy1_Mmcm Mmcm[2]; /**< MMCM parameters. */ + }; + union { + struct { + XHdmiphy1_Channel Ch1; + XHdmiphy1_Channel Ch2; + XHdmiphy1_Channel Ch3; + XHdmiphy1_Channel Ch4; + union { + XHdmiphy1_Channel Cmn0; + XHdmiphy1_Channel Lcpll; + }; + union { + XHdmiphy1_Channel Cmn1; + XHdmiphy1_Channel Rpll; + }; + }; + XHdmiphy1_Channel Plls[6]; + }; + union { + struct { + u32 GtRefClk0Hz; + u32 GtRefClk1Hz; + u32 GtNorthRefClk0Hz; + u32 GtNorthRefClk1Hz; + u32 GtSouthRefClk0Hz; + u32 GtSouthRefClk1Hz; + u32 GtgRefClkHz; + }; + u32 RefClkHz[7]; + }; +} XHdmiphy1_Quad; + +#ifdef XV_HDMIPHY1_LOG_ENABLE +/** + * This typedef contains the logging mechanism for debug. + */ +typedef struct { + u16 DataBuffer[128]; /**< Log buffer with event data. */ + u64 TimeRecord[128]; /**< Log time for the event */ + u8 HeadIndex; /**< Index of the head entry of the + Event/DataBuffer. */ + u8 TailIndex; /**< Index of the tail entry of the + Event/DataBuffer. */ +} XHdmiphy1_Log; +#endif + +/** + * This typedef contains the HDMI 2.1 FRL configurations. + */ +typedef struct { + u8 IsEnabled; /**< Is HDMI operation is enabled? */ + u64 LineRate; /**< Linerate in bps. */ + u8 NChannels; /**< No of Channels. */ +} XHdmiphy1_Hdmi21Cfg; + +/** + * This typedef contains configuration information for the Video PHY core. + */ +typedef struct { + u16 DeviceId; /**< Device instance ID. */ + UINTPTR BaseAddr; /**< The base address of the core instance. */ + XHdmiphy1_GtType XcvrType; /**< HDMIPHY Transceiver Type */ + u8 TxChannels; /**< No. of active channels in TX */ + u8 RxChannels; /**< No. of active channels in RX */ + XHdmiphy1_ProtocolType TxProtocol; /**< Protocol which TX is used for. */ + XHdmiphy1_ProtocolType RxProtocol; /**< Protocol which RX is used for. */ + XHdmiphy1_PllRefClkSelType TxRefClkSel; /**< TX REFCLK selection. */ + XHdmiphy1_PllRefClkSelType RxRefClkSel; /**< RX REFCLK selection. */ + XHdmiphy1_PllRefClkSelType TxFrlRefClkSel; /**< TX FRL REFCLK selection. */ + XHdmiphy1_PllRefClkSelType RxFrlRefClkSel; /**< RX FRL REFCLK selection. */ + XHdmiphy1_SysClkDataSelType TxSysPllClkSel; /**< TX SYSCLK selection. */ + XHdmiphy1_SysClkDataSelType RxSysPllClkSel; /**< RX SYSCLK selectino. */ + u8 DruIsPresent; /**< A data recovery unit (DRU) exists + in the design .*/ + XHdmiphy1_PllRefClkSelType DruRefClkSel; /**< DRU REFCLK selection. */ + XVidC_PixelsPerClock Ppc; /**< Number of input pixels per + clock. */ + u8 TxBufferBypass; /**< TX Buffer Bypass is enabled in the + design. */ + u8 HdmiFastSwitch; /**< HDMI fast switching is enabled in the + design. */ + u8 TransceiverWidth; /**< Transceiver Width seeting in the design */ + u32 ErrIrq; /**< Error IRQ is enalbed in design */ + u32 AxiLiteClkFreq; /**< AXI Lite Clock Frequency in Hz */ + u32 DrpClkFreq; /**< DRP Clock Frequency in Hz */ + u8 UseGtAsTxTmdsClk; /**< Use 4th GT channel as TX TMDS clock */ +} XHdmiphy1_Config; + +/* Forward declaration. */ +struct XHdmiphy1_GtConfigS; + +/** + * The XHdmiphy1 driver instance data. The user is required to allocate a + * variable of this type for every XHdmiphy1 device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + u32 IsReady; /**< Device is initialized and ready. */ + XHdmiphy1_Config Config; /**< Configuration structure for + the Video PHY core. */ + const struct XHdmiphy1_GtConfigS *GtAdaptor; +#ifdef XV_HDMIPHY1_LOG_ENABLE + XHdmiphy1_Log Log; /**< A log of events. */ +#endif + XHdmiphy1_Quad Quads[2]; /**< The quads available to the + Video PHY core.*/ + u32 HdmiRxRefClkHz; /**< HDMI RX refclk. */ + u32 HdmiTxRefClkHz; /**< HDMI TX refclk. */ + u8 HdmiRxTmdsClockRatio; /**< HDMI TMDS clock ratio. */ + u8 HdmiTxSampleRate; /**< HDMI TX sample rate. */ + u8 HdmiRxDruIsEnabled; /**< The DRU is enabled. */ + u8 HdmiIsQpllPresent; /**< QPLL is present in HW */ + XHdmiphy1_Hdmi21Cfg TxHdmi21Cfg; /**< TX HDMI Config */ + XHdmiphy1_Hdmi21Cfg RxHdmi21Cfg; /**< TX HDMI Config */ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_IntrHandler IntrCpllLockHandler; /**< Callback function for CPLL + lock interrupts. */ + void *IntrCpllLockCallbackRef; /**< A pointer to the user data + passed to the CPLL lock + callback function. */ + XHdmiphy1_IntrHandler IntrQpllLockHandler; /**< Callback function for QPLL + lock interrupts. */ + void *IntrQpllLockCallbackRef; /**< A pointer to the user data + passed to the QPLL lock + callback function. */ + XHdmiphy1_IntrHandler IntrQpll1LockHandler; /**< Callback function for QPLL + lock interrupts. */ + void *IntrQpll1LockCallbackRef; /**< A pointer to the user data + passed to the QPLL lock + callback function. */ + XHdmiphy1_IntrHandler IntrTxAlignDoneHandler; /**< Callback function for TX + align done lock + interrupts. */ + void *IntrTxAlignDoneCallbackRef; /**< A pointer to the user data + passed to the TX align + done lock callback + function. */ +#else + XHdmiphy1_IntrHandler IntrLcpllLockHandler; /**< Callback function for + LCPLL lock interrupts. */ + void *IntrLcpllLockCallbackRef; /**< A pointer to the user data + passed to the LCPLL lock callback function. */ + XHdmiphy1_IntrHandler IntrRpllLockHandler; /**< Callback function for + RPLL lock interrupts. */ + void *IntrRpllLockCallbackRef; /**< A pointer to the user data + passed to the RPLL lock callback function. */ + XHdmiphy1_IntrHandler IntrTxGpoRisingEdgeHandler; /**< Callback function + for TX GPO [3:0] Rising Edge. */ + void *IntrTxGpoRisingEdgeCallbackRef; /**< A pointer to the user data + passed to the TX GPO [3:0] Rising Edge + callback function. */ + XHdmiphy1_IntrHandler IntrRxGpoRisingEdgeHandler; /**< Callback function + for RX GPO [7:4] Rising Edge. */ + void *IntrRxGpoRisingEdgeCallbackRef; /**< A pointer to the user data + passed to the RX GPO [7:4] Rising Edge + callback function. */ +#endif + XHdmiphy1_IntrHandler IntrTxResetDoneHandler; /**< Callback function for TX + reset done lock + interrupts. */ + void *IntrTxResetDoneCallbackRef; /**< A pointer to the user data + passed to the TX reset + done lock callback + function. */ + XHdmiphy1_IntrHandler IntrRxResetDoneHandler; /**< Callback function for RX + reset done lock + interrupts. */ + void *IntrRxResetDoneCallbackRef; /**< A pointer to the user data + passed to the RX reset + done lock callback + function. */ + XHdmiphy1_IntrHandler IntrTxClkDetFreqChangeHandler; /**< Callback function + for TX clock detector + frequency change + interrupts. */ + void *IntrTxClkDetFreqChangeCallbackRef; /**< A pointer to the user data + passed to the TX clock + detector frequency + change callback + function. */ + XHdmiphy1_IntrHandler IntrRxClkDetFreqChangeHandler; /**< Callback function + for RX clock detector + frequency change + interrupts. */ + void *IntrRxClkDetFreqChangeCallbackRef; /**< A pointer to the user data + passed to the RX clock + detector frequency + change callback + function. */ + XHdmiphy1_IntrHandler IntrTxMmcmLockHandler; /**< Callback function + for TX MMCM lock + interrupts. */ + void *IntrTxMmcmLockCallbackRef; /**< A pointer to the user data + passed to the TX MMCM lock + callback function. */ + XHdmiphy1_IntrHandler IntrRxMmcmLockHandler; /**< Callback function + for RX MMCM lock + interrupts. */ + void *IntrRxMmcmLockCallbackRef; /**< A pointer to the user data + passed to the RX MMCM lock + callback function. */ + XHdmiphy1_IntrHandler IntrTxTmrTimeoutHandler; /**< Callback function for + TX timer timeout interrupts. */ + void *IntrTxTmrTimeoutCallbackRef; /**< A pointer to the user data + passed to the TX timer + timeout callback + function. */ + XHdmiphy1_IntrHandler IntrRxTmrTimeoutHandler; /**< Callback function for + RX timer timeout interrupts. */ + void *IntrRxTmrTimeoutCallbackRef; /**< A pointer to the user data + passed to the RX timer timeout + callback function. */ + /* Error Condition callbacks. */ + XHdmiphy1_ErrorCallback ErrorCallback; /**< Callback for Error Condition.*/ + void *ErrorRef; /**< To be passed to the Error condition + callback. */ + XHdmiphy1_ErrorCallback PllLayoutErrorCallback; /**< Callback for Error + Condition. */ + void *PllLayoutErrorRef;/**< To be passed to the Error condition + callback. */ + /* HDMI callbacks. */ + XHdmiphy1_Callback HdmiTxInitCallback; /**< Callback for TX init. */ + void *HdmiTxInitRef; /**< To be passed to the TX init + callback. */ + XHdmiphy1_Callback HdmiTxReadyCallback; /**< Callback for TX ready. */ + void *HdmiTxReadyRef; /**< To be passed to the TX + ready callback. */ + XHdmiphy1_Callback HdmiRxInitCallback; /**< Callback for RX init. */ + void *HdmiRxInitRef; /**< To be passed to the RX + init callback. */ + XHdmiphy1_Callback HdmiRxReadyCallback; /**< Callback for RX ready. */ + void *HdmiRxReadyRef; /**< To be passed to the RX + ready callback. */ + XHdmiphy1_LogCallback LogWriteCallback; /**< Callback for log write */ + u32 *LogWriteRef; /**< To be passed to the log write callback */ + XHdmiphy1_TimerHandler UserTimerWaitUs; /**< Custom user function for + delay/sleep. */ + void *UserTimerPtr; /**< Pointer to a timer instance + used by the custom user + delay/sleep function. */ +} XHdmiphy1; + +/**************************** Function Prototypes *****************************/ + +/* xhdmiphy1.c: Setup and initialization functions. */ +void XHdmiphy1_CfgInitialize(XHdmiphy1 *InstancePtr, + XHdmiphy1_Config *ConfigPtr, + UINTPTR EffectiveAddr); +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +u32 XHdmiphy1_PllInitialize(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, + XHdmiphy1_PllRefClkSelType QpllRefClkSel, + XHdmiphy1_PllRefClkSelType CpllxRefClkSel, + XHdmiphy1_PllType TxPllSelect, XHdmiphy1_PllType RxPllSelect); +#endif +u32 XHdmiphy1_GetVersion(XHdmiphy1 *InstancePtr); +void XHdmiphy1_WaitUs(XHdmiphy1 *InstancePtr, u32 MicroSeconds); +void XHdmiphy1_SetUserTimerHandler(XHdmiphy1 *InstancePtr, + XHdmiphy1_TimerHandler CallbackFunc, void *CallbackRef); + +/* xhdmiphy1.c: Channel configuration functions - setters. */ +u32 XHdmiphy1_CfgLineRate(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u64 LineRateHz); + +/* xhdmiphy1.c: Channel configuration functions - getters. */ +XHdmiphy1_PllType XHdmiphy1_GetPllType(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, XHdmiphy1_ChannelId ChId); +u64 XHdmiphy1_GetLineRateHz(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); + +/* xhdmiphy1.c: Reset functions. */ +u32 XHdmiphy1_ResetGtPll(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Hold); +u32 XHdmiphy1_ResetGtTxRx(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Hold); + +/* xhdmiphy1.c: TX|RX Control functions. */ +u32 XHdmiphy1_SetPolarity(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Polarity); +u32 XHdmiphy1_SetPrbsSel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + XHdmiphy1_PrbsPattern Pattern); +u32 XHdmiphy1_TxPrbsForceError(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 ForceErr); +void XHdmiphy1_SetTxVoltageSwing(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 Vs); +void XHdmiphy1_SetTxPreEmphasis(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 Pe); +void XHdmiphy1_SetTxPostCursor(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 Pc); +void XHdmiphy1_SetRxLpm(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Enable); + +/* xhdmiphy1.c: GT/MMCM DRP access. */ +u32 XHdmiphy1_DrpWr(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u16 Addr, u16 Val); +u16 XHdmiphy1_DrpRd(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u16 Addr, u16 *RetVal); +void XHdmiphy1_MmcmPowerDown(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u8 Hold); +void XHdmiphy1_MmcmStart(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir); +void XHdmiphy1_IBufDsEnable(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u8 Enable); +void XHdmiphy1_Clkout1OBufTdsEnable(XHdmiphy1 *InstancePtr, + XHdmiphy1_DirectionType Dir, u8 Enable); + +/* xhdmiphy1.c: Error Condition. */ +void XHdmiphy1_SetErrorCallback(XHdmiphy1 *InstancePtr, + void *CallbackFunc, void *CallbackRef); + +/* xhdmiphy1_log.c: Logging functions. */ +void XHdmiphy1_SetLogCallback(XHdmiphy1 *InstancePtr, + u64 *CallbackFunc, void *CallbackRef); +int XHdmiphy1_LogShow(XHdmiphy1 *InstancePtr, char *buff, int buff_size); +void XHdmiphy1_LogReset(XHdmiphy1 *InstancePtr); +u16 XHdmiphy1_LogRead(XHdmiphy1 *InstancePtr); +#ifdef XV_HDMIPHY1_LOG_ENABLE +void XHdmiphy1_LogWrite(XHdmiphy1 *InstancePtr, XHdmiphy1_LogEvent Evt, + u8 Data); +#else +#define XHdmiphy1_LogWrite(...) +#endif + +/* xhdmiphy1_intr.c: Interrupt handling functions. */ +void XHdmiphy1_InterruptHandler(XHdmiphy1 *InstancePtr); + +/* xhdmiphy1_selftest.c: Self test function. */ +u32 XHdmiphy1_SelfTest(XHdmiphy1 *InstancePtr); + +/* xhdmiphy1_sinit.c: Configuration extraction function. */ +XHdmiphy1_Config *XHdmiphy1_LookupConfig(u16 DeviceId); + +/* xhdmiphy1_hdmi.c, xhdmiphy1_hdmi_intr.c: Protocol specific functions. */ +u32 XHdmiphy1_Hdmi_CfgInitialize(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_Config *CfgPtr); +u32 XHdmiphy1_SetHdmiTxParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, + XVidC_PixelsPerClock Ppc, XVidC_ColorDepth Bpc, + XVidC_ColorFormat ColorFormat); +u32 XHdmiphy1_SetHdmiRxParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); + +u32 XHdmiphy1_HdmiCfgCalcMmcmParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + XVidC_PixelsPerClock Ppc, XVidC_ColorDepth Bpc); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +void XHdmiphy1_HdmiUpdateClockSelection(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_SysClkDataSelType TxSysPllClkSel, + XHdmiphy1_SysClkDataSelType RxSysPllClkSel); +#endif +void XHdmiphy1_ClkDetFreqReset(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir); +u32 XHdmiphy1_ClkDetGetRefClkFreqHz(XHdmiphy1 *InstancePtr, + XHdmiphy1_DirectionType Dir); +u32 XHdmiphy1_DruGetRefClkFreqHz(XHdmiphy1 *InstancePtr); +int XHdmiphy1_HdmiDebugInfo(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, char *buff, int buff_size); +void XHdmiphy1_SetHdmiCallback(XHdmiphy1 *InstancePtr, + XHdmiphy1_HdmiHandlerType HandlerType, + void *CallbackFunc, void *CallbackRef); +u32 XHdmiphy1_Hdmi20Config(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir); +u32 XHdmiphy1_Hdmi21Config(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, + u64 LineRate, u8 NChannels); +void XHdmiphy1_RegisterDebug(XHdmiphy1 *InstancePtr); + +/******************* Macros (Inline Functions) Definitions ********************/ + +#define XHDMIPHY1_CH2IDX(Id) ((Id) - XHDMIPHY1_CHANNEL_ID_CH1) +#define XHDMIPHY1_ISCH(Id) (((Id) == XHDMIPHY1_CHANNEL_ID_CHA) || \ + ((XHDMIPHY1_CHANNEL_ID_CH1 <= (Id)) && ((Id) <= XHDMIPHY1_CHANNEL_ID_CH4))) +#define XHDMIPHY1_ISCMN(Id) (((Id) == XHDMIPHY1_CHANNEL_ID_CMNA) || \ + ((XHDMIPHY1_CHANNEL_ID_CMN0 <= (Id)) && ((Id) <= XHDMIPHY1_CHANNEL_ID_CMN1))) +#define XHDMIPHY1_ISTXMMCM(Id) ((Id) == XHDMIPHY1_CHANNEL_ID_TXMMCM) +#define XHDMIPHY1_ISRXMMCM(Id) ((Id) == XHDMIPHY1_CHANNEL_ID_RXMMCM) + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +#define XHdmiphy1_IsTxUsingQpll(InstancePtr, QuadId, ChId) \ + ((XHDMIPHY1_PLL_TYPE_QPLL == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, ChId)) || \ + (XHDMIPHY1_PLL_TYPE_QPLL0 == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, ChId)) || \ + (XHDMIPHY1_PLL_TYPE_QPLL1 == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, ChId))) +#define XHdmiphy1_IsRxUsingQpll(InstancePtr, QuadId, ChId) \ + ((XHDMIPHY1_PLL_TYPE_QPLL == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, ChId)) || \ + (XHDMIPHY1_PLL_TYPE_QPLL0 == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, ChId)) || \ + (XHDMIPHY1_PLL_TYPE_QPLL1 == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, ChId))) +#define XHdmiphy1_IsTxUsingCpll(InstancePtr, QuadId, ChId) \ + (XHDMIPHY1_PLL_TYPE_CPLL == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, ChId)) +#define XHdmiphy1_IsRxUsingCpll(InstancePtr, QuadId, ChId) \ + (XHDMIPHY1_PLL_TYPE_CPLL == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, ChId)) +#else +#define XHdmiphy1_IsTxUsingLcpll(InstancePtr, QuadId, ChId) \ + (XHDMIPHY1_PLL_TYPE_LCPLL == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, ChId)) +#define XHdmiphy1_IsRxUsingLcpll(InstancePtr, QuadId, ChId) \ + (XHDMIPHY1_PLL_TYPE_LCPLL == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, ChId)) +#define XHdmiphy1_IsTxUsingRpll(InstancePtr, QuadId, ChId) \ + (XHDMIPHY1_PLL_TYPE_RPLL == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, ChId)) +#define XHdmiphy1_IsRxUsingRpll(InstancePtr, QuadId, ChId) \ + (XHDMIPHY1_PLL_TYPE_RPLL == \ + XHdmiphy1_GetPllType(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, ChId)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* XHDMIPHY1_H_ */ +/** @} */ diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_gt.h b/hdmi/phy-xilinx-vphy/xhdmiphy1_gt.h new file mode 100644 index 0000000..8d68e3e --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_gt.h @@ -0,0 +1,127 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_gt.h + * + * The Xilinx HDMI PHY (HDMIPHY) driver. This driver supports the + * Xilinx HDMI PHY IP core. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * + * @addtogroup xhdmiphy1_v1_0 + * @{ +*******************************************************************************/ + +#ifndef XHDMIPHY1_GT_H_ +/* Prevent circular inclusions by using protection macros. */ +#define XHDMIPHY1_GT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************* Include Files ********************************/ + +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" +#include "xil_assert.h" + +/****************************** Type Definitions ******************************/ + +typedef struct { + const u8 *M; + const u8 *N1; + const u8 *N2; + const u8 *D; +} XHdmiphy1_GtPllDivs; + +typedef struct XHdmiphy1_GtConfigS { + u32 (*CfgSetCdr)(XHdmiphy1 *, u8, XHdmiphy1_ChannelId); + u32 (*CheckPllOpRange)(XHdmiphy1 *, u8, XHdmiphy1_ChannelId, u64); + u32 (*OutDivChReconfig)(XHdmiphy1 *, u8, XHdmiphy1_ChannelId, + XHdmiphy1_DirectionType); + u32 (*ClkChReconfig)(XHdmiphy1 *, u8, XHdmiphy1_ChannelId); + u32 (*ClkCmnReconfig)(XHdmiphy1 *, u8, XHdmiphy1_ChannelId); + u32 (*RxChReconfig)(XHdmiphy1 *, u8, XHdmiphy1_ChannelId); + u32 (*TxChReconfig)(XHdmiphy1 *, u8, XHdmiphy1_ChannelId); + + XHdmiphy1_GtPllDivs CpllDivs; + XHdmiphy1_GtPllDivs QpllDivs; +} XHdmiphy1_GtConfig; + +/******************* Macros (Inline Functions) Definitions ********************/ +#ifdef __cplusplus +u32 XHdmiphy1_CfgSetCdr(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +u32 XHdmiphy1_CheckPllOpRange(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u64 PllClkOutFreqHz); +u32 XHdmiphy1_OutDivChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +u32 XHdmiphy1_ClkChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +u32 XHdmiphy1_ClkCmnReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +u32 XHdmiphy1_RxChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +u32 XHdmiphy1_TxChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +#else +#define XHdmiphy1_CfgSetCdr(Ip, ...) \ + ((Ip)->GtAdaptor->CfgSetCdr(Ip, __VA_ARGS__)) +#define XHdmiphy1_CheckPllOpRange(Ip, ...) \ + ((Ip)->GtAdaptor->CheckPllOpRange(Ip, __VA_ARGS__)) +#define XHdmiphy1_OutDivChReconfig(Ip, ...) \ + ((Ip)->GtAdaptor->OutDivChReconfig(Ip, __VA_ARGS__)) +#define XHdmiphy1_ClkChReconfig(Ip, ...) \ + ((Ip)->GtAdaptor->ClkChReconfig(Ip, __VA_ARGS__)) +#define XHdmiphy1_ClkCmnReconfig(Ip, ...) \ + ((Ip)->GtAdaptor->ClkCmnReconfig(Ip, __VA_ARGS__)) +#define XHdmiphy1_RxChReconfig(Ip, ...) \ + ((Ip)->GtAdaptor->RxChReconfig(Ip, __VA_ARGS__)) +#define XHdmiphy1_TxChReconfig(Ip, ...) \ + ((Ip)->GtAdaptor->TxChReconfig(Ip, __VA_ARGS__)) +#endif + +/*************************** Variable Declarations ****************************/ + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE3) +extern const XHdmiphy1_GtConfig Gthe3Config; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) +extern const XHdmiphy1_GtConfig Gthe4Config; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) +extern const XHdmiphy1_GtConfig Gtye4Config; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) +extern const XHdmiphy1_GtConfig Gtye5Config; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* XHDMIPHY1_GT_H_ */ +/** @} */ \ No newline at end of file diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_gtye5.c b/hdmi/phy-xilinx-vphy/xhdmiphy1_gtye5.c new file mode 100644 index 0000000..1f154c2 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_gtye5.c @@ -0,0 +1,620 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ + +/******************************************************************************/ +/** + * + * @file xhdmiphy1_gtye4.c + * + * Contains a minimal set of functions for the XHdmiphy1 driver that allow + * access to all of the Video PHY core's functionality. See xhdmiphy1.h for a + * detailed description of the driver. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include "xhdmiphy1_gt.h" +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) +#include "xstatus.h" + +/**************************** Function Prototypes *****************************/ + +u32 XHdmiphy1_Gtye5RxChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +u32 XHdmiphy1_Gtye5TxChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); + +/************************** Constant Definitions ******************************/ +/* PLL operating ranges. */ +#define XHDMIPHY1_LCPLL_MIN 8000000000LL +#define XHDMIPHY1_LCPLL_MAX 16375000000LL +#define XHDMIPHY1_LCPLL_MIN_REFCLK 120000000LL +#define XHDMIPHY1_RPLL_MIN 4000000000LL +#define XHDMIPHY1_RPLL_MAX 8000000000LL +#define XHDMIPHY1_RPLL_MIN_REFCLK 120000000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_LRATE 3000000000U + + +const XHdmiphy1_GtConfig Gtye5Config = { +/* .CfgSetCdr = XHdmiphy1_Gtye4CfgSetCdr, + .CheckPllOpRange = XHdmiphy1_Gtye4CheckPllOpRange, + .OutDivChReconfig = XHdmiphy1_Gtye4OutDivChReconfig, + .ClkChReconfig = XHdmiphy1_Gtye4ClkChReconfig, + .ClkCmnReconfig = XHdmiphy1_Gtye4ClkCmnReconfig, */ + .RxChReconfig = XHdmiphy1_Gtye5RxChReconfig, + .TxChReconfig = XHdmiphy1_Gtye5TxChReconfig, + + .CpllDivs = { + .M = 0, + .N1 = 0, + .N2 = 0, + .D = 0, + }, + .QpllDivs = { + .M = 0, + .N1 = 0, + .N2 = 0, + .D = 0, + }, +}; + +/**************************** Function Definitions ****************************/ + +/*****************************************************************************/ +/** +* This function calculates the LCPLL parameters. +* +* @param InstancePtr is a pointer to the HDMI GT core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if calculated LCPLL parameters updated +* successfully. +* - XST_FAILURE if parameters not updated. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_HdmiLcpllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 Status = XST_SUCCESS; + u32 *RefClkPtr; + u8 TmdsClockRatio = 0; + u8 IsHdmi21 = 0; + u64 LineRate = 0; + + /* Suppress Warning Messages */ + ChId = ChId; + + + /* Pre-calculation. */ + if (Dir == XHDMIPHY1_DIR_RX) { + RefClkPtr = &InstancePtr->HdmiRxRefClkHz; + IsHdmi21 = InstancePtr->RxHdmi21Cfg.IsEnabled; + TmdsClockRatio = InstancePtr->HdmiRxTmdsClockRatio; + + /* Calculate Line Rate */ + if (IsHdmi21) { + LineRate = InstancePtr->RxHdmi21Cfg.LineRate; + } + else { + LineRate = (u64)(*RefClkPtr) * ((TmdsClockRatio ? 40 : 10)); + } + + /* Disable DRU */ + InstancePtr->HdmiRxDruIsEnabled = 0; + + /* Enable DRU based on incoming REFCLK */ + if ((!IsHdmi21) && (!TmdsClockRatio) && + (InstancePtr->HdmiRxRefClkHz < XHDMIPHY1_LCPLL_MIN_REFCLK)) { + if (InstancePtr->Config.DruIsPresent) { + /* Check DRU frequency */ + if (XHdmiphy1_DruGetRefClkFreqHz(InstancePtr) == XST_FAILURE) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_DRU_CLK_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + + InstancePtr->HdmiRxDruIsEnabled = 1; + LineRate = XHDMIPHY1_HDMI_GTYE5_DRU_LRATE; + } + else { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_NO_DRU, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + } + } + else { + RefClkPtr = &InstancePtr->HdmiTxRefClkHz; + IsHdmi21 = InstancePtr->TxHdmi21Cfg.IsEnabled; + InstancePtr->HdmiTxSampleRate = 1; + + if (!IsHdmi21) { + /* Determine if HDMI 2.0 Mode */ + if (*RefClkPtr >= 340000000) { + TmdsClockRatio = 1; + (*RefClkPtr) = (*RefClkPtr) / 4; + } + /* Check for x1 Over Sampling Mode*/ + else if (*RefClkPtr >= 124990000) { + InstancePtr->HdmiTxSampleRate = 1; + } + /* Check for x2 Over Sampling Mode*/ + else if (*RefClkPtr >= 99000000) { + InstancePtr->HdmiTxSampleRate = 2; + (*RefClkPtr) = (*RefClkPtr) * 2; + } + /* Check for x3 Over Sampling Mode*/ + else if (*RefClkPtr >= 59400000) { + InstancePtr->HdmiTxSampleRate = 3; + (*RefClkPtr) = (*RefClkPtr) * 3; + } + /* Check for x5 Over Sampling Mode*/ + else if (*RefClkPtr < 59400000) { + InstancePtr->HdmiTxSampleRate = 5; + (*RefClkPtr) = (*RefClkPtr) * 5; + } + } + + /* Calculate Line Rate */ + if (IsHdmi21) { + LineRate = InstancePtr->TxHdmi21Cfg.LineRate; + } + else { + LineRate = (u64)(*RefClkPtr) * ((TmdsClockRatio ? 40 : 10)); + } + + } + + /* Check for DRU mode */ + if ((Dir == XHDMIPHY1_DIR_RX) && + (InstancePtr->HdmiRxDruIsEnabled)) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 0; + } + /* Check for HDMI 1.4/2.0 GT LineRate Config */ + else if (!IsHdmi21) { + /* HDMI 1.4 */ + if (!TmdsClockRatio) { + if ((119990000 <= (*RefClkPtr)) && + ((*RefClkPtr) <= 204687500)) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 1; + } + else if ((204687500 <= (*RefClkPtr)) && + /* 297 MHz + 0.5% + 10 KHz error */ + ((*RefClkPtr) <= 298500000)) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 2; + } + else{ + Status = XST_FAILURE; + } + } + /* HDMI 2.0 */ + else { + if ((84570000 <= (*RefClkPtr)) && + ((*RefClkPtr) <= 102343750)) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 3; + } + else if ((102343750 <= (*RefClkPtr)) && + ((*RefClkPtr) <= 149500000)) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 4; + } + else{ + Status = XST_FAILURE; + } + } + } + /* Check for HDMI 2.1 GT LineRate Config */ + else if (IsHdmi21) { + if (LineRate == 3000000000) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 5; + } + else if (LineRate == 6000000000) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 6; + } + else if (LineRate == 8000000000) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 7; + } + else if (LineRate == 10000000000) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 8; + } + else if (LineRate == 12000000000) { + InstancePtr->Quads[0].Lcpll.LineRateCfg = 9; + } + else { + Status = XST_FAILURE; + } + } + + /* Update Line Rate Value */ + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + /* LCPLL is CMN0 */ + XHDMIPHY1_CHANNEL_ID_CMN0, LineRate); + + if (Status == XST_FAILURE) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_GT_LCPLL_CFG_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function calculates the RPLL parameters. +* +* @param InstancePtr is a pointer to the HDMI GT core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if calculated RPLL parameters updated +* successfully. +* - XST_FAILURE if parameters not updated. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_HdmiRpllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 Status = XST_SUCCESS; + u32 *RefClkPtr; + u8 TmdsClockRatio = 0; + u8 IsHdmi21 = 0; + u64 LineRate = 0; + + /* Suppress Warning Messages */ + ChId = ChId; + + + /* Pre-calculation. */ + if (Dir == XHDMIPHY1_DIR_RX) { + RefClkPtr = &InstancePtr->HdmiRxRefClkHz; + IsHdmi21 = InstancePtr->RxHdmi21Cfg.IsEnabled; + TmdsClockRatio = InstancePtr->HdmiRxTmdsClockRatio; + + /* Calculate Line Rate */ + if (IsHdmi21) { + LineRate = InstancePtr->RxHdmi21Cfg.LineRate; + } + else { + LineRate = (u64)(*RefClkPtr) * ((TmdsClockRatio ? 40 : 10)); + } + + /* Disable DRU */ + InstancePtr->HdmiRxDruIsEnabled = 0; + + /* Enable DRU based on incoming REFCLK */ + if ((!IsHdmi21) && (!TmdsClockRatio) && + (InstancePtr->HdmiRxRefClkHz < XHDMIPHY1_RPLL_MIN_REFCLK)) { + if (InstancePtr->Config.DruIsPresent) { + /* Check DRU frequency */ + if (XHdmiphy1_DruGetRefClkFreqHz(InstancePtr) == XST_FAILURE) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_DRU_CLK_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + + InstancePtr->HdmiRxDruIsEnabled = 1; + LineRate = XHDMIPHY1_HDMI_GTYE5_DRU_LRATE; + } + else { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_NO_DRU, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + } + } + else { + RefClkPtr = &InstancePtr->HdmiTxRefClkHz; + IsHdmi21 = InstancePtr->TxHdmi21Cfg.IsEnabled; + InstancePtr->HdmiTxSampleRate = 1; + + if (!IsHdmi21) { + /* Determine if HDMI 2.0 Mode */ + if (*RefClkPtr >= 340000000) { + TmdsClockRatio = 1; + (*RefClkPtr) = (*RefClkPtr) / 4; + } + /* Check for x1 Over Sampling Mode*/ + else if (*RefClkPtr >= 124990000) { + InstancePtr->HdmiTxSampleRate = 1; + } + /* Check for x2 Over Sampling Mode*/ + else if (*RefClkPtr >= 99000000) { + InstancePtr->HdmiTxSampleRate = 2; + (*RefClkPtr) = (*RefClkPtr) * 2; + } + /* Check for x3 Over Sampling Mode*/ + else if (*RefClkPtr >= 59400000) { + InstancePtr->HdmiTxSampleRate = 3; + (*RefClkPtr) = (*RefClkPtr) * 3; + } + /* Check for x5 Over Sampling Mode*/ + else if (*RefClkPtr < 59400000) { + InstancePtr->HdmiTxSampleRate = 5; + (*RefClkPtr) = (*RefClkPtr) * 5; + } + } + + /* Calculate Line Rate */ + if (IsHdmi21) { + LineRate = InstancePtr->TxHdmi21Cfg.LineRate; + } + else { + LineRate = (u64)(*RefClkPtr) * ((TmdsClockRatio ? 40 : 10)); + } + + } + + /* Check for DRU mode */ + if ((Dir == XHDMIPHY1_DIR_RX) && + (InstancePtr->HdmiRxDruIsEnabled)) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 0; + } + /* Check for HDMI 1.4/2.0 GT LineRate Config */ + else if (!IsHdmi21) { + /* HDMI 1.4 */ + if (!TmdsClockRatio) { + if ((119990000 <= (*RefClkPtr)) && + ((*RefClkPtr) <= 200000000)) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 1; + } + else if ((200000000 <= (*RefClkPtr)) && + /* 297 MHz + 0.5% + 10 KHz error */ + ((*RefClkPtr) <= 298500000)) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 2; + } + else{ + Status = XST_FAILURE; + } + } + /* HDMI 2.0 */ + else { + if ((84570000 <= (*RefClkPtr)) && + ((*RefClkPtr) <= 100000000)) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 3; + } + else if ((100000000 <= (*RefClkPtr)) && + ((*RefClkPtr) <= 149500000)) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 4; + } + else{ + Status = XST_FAILURE; + } + } + } + /* Check for HDMI 2.1 GT LineRate Config */ + else if (IsHdmi21) { + if (LineRate == 3000000000) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 5; + } + else if (LineRate == 6000000000) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 6; + } + else if (LineRate == 8000000000) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 7; + } + else if (LineRate == 10000000000) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 8; + } + else if (LineRate == 12000000000) { + InstancePtr->Quads[0].Rpll.LineRateCfg = 9; + } + else { + Status = XST_FAILURE; + } + } + + /* Update Line Rate Value */ + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + /* RPLL is CMN1 */ + XHDMIPHY1_CHANNEL_ID_CMN1, LineRate); + + if (Status == XST_FAILURE) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_GT_RPLL_CFG_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function calculates the TX PLL parameters. +* +* @param InstancePtr is a pointer to the HDMI GT core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - XST_SUCCESS if calculated QPLL parameters updated +* successfully. +* - XST_FAILURE if parameters not updated. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_HdmiTxPllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + u32 Status; + XHdmiphy1_PllType PllType; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + + if (PllType == XHDMIPHY1_PLL_TYPE_LCPLL) { + Status = XHdmiphy1_HdmiLcpllParam(InstancePtr, 0, ChId, + XHDMIPHY1_DIR_TX); + } + else { /* RPLL */ + Status = XHdmiphy1_HdmiRpllParam(InstancePtr, 0, ChId, + XHDMIPHY1_DIR_TX); + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function calculates the RX PLL parameters. +* +* @param InstancePtr is a pointer to the HDMI GT core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - XST_SUCCESS if calculated QPLL parameters updated +* successfully. +* - XST_FAILURE if parameters not updated. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_HdmiRxPllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + u32 Status; + XHdmiphy1_PllType PllType; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + + if (PllType == XHDMIPHY1_PLL_TYPE_LCPLL) { + Status = XHdmiphy1_HdmiLcpllParam(InstancePtr, 0, ChId, + XHDMIPHY1_DIR_RX); + } + else { /* RPLL */ + Status = XHdmiphy1_HdmiRpllParam(InstancePtr, 0, ChId, + XHDMIPHY1_DIR_RX); + } + + return Status; +} + + +/*****************************************************************************/ +/** +* This function will configure the channel's RX settings. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_Gtye5RxChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + u8 CfgValComp; + + /* Compare the current and next CFG values */ + CfgValComp = XHdmiphy1_CheckLineRateCfg(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_RX); + + if (!CfgValComp) { + /* If CFG values are different */ + XHdmiphy1_SetGtLineRateCfg(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_RX); + } + else { + /* Toggle RX Master Reset */ + XHdmiphy1_GtMstReset(InstancePtr, QuadId, ChId, XHDMIPHY1_DIR_RX, + TRUE); + XHdmiphy1_GtMstReset(InstancePtr, QuadId, ChId, XHDMIPHY1_DIR_RX, + FALSE); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function will configure the channel's TX settings. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_Gtye5TxChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + u8 CfgValComp; + + /* Compare the current and next CFG values */ + CfgValComp = XHdmiphy1_CheckLineRateCfg(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_TX); + + if (!CfgValComp) { + /* If CFG values are different */ + XHdmiphy1_SetGtLineRateCfg(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_TX); + } + else { + /* Toggle RX Master Reset */ + XHdmiphy1_GtMstReset(InstancePtr, QuadId, ChId, XHDMIPHY1_DIR_TX, + TRUE); + XHdmiphy1_GtMstReset(InstancePtr, QuadId, ChId, XHDMIPHY1_DIR_TX, + FALSE); + } + + return XST_SUCCESS; +} + +#endif diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi.c b/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi.c new file mode 100644 index 0000000..4d84440 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi.c @@ -0,0 +1,2865 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_hdmi.c + * + * This file contains video PHY functionality specific to the HDMI protocol. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include "xstatus.h" +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" +#include "xhdmiphy1_hdmi.h" + +/****************************** Type Definitions ******************************/ + +typedef struct { + u64 DruLineRate; + u16 PllScale; + u32 Qpll0RefClkMin; + u32 Qpll1RefClkMin; + u32 CpllRefClkMin; + u16 TxMmcmScale; + u64 TxMmcmFvcoMin; + u64 TxMmcmFvcoMax; + u16 RxMmcmScale; + u64 RxMmcmFvcoMin; + u64 RxMmcmFvcoMax; +} XHdmiphy1_GtHdmiChars; + +/**************************** Function Prototypes *****************************/ + +extern void XHdmiphy1_Ch2Ids(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 *Id0, u8 *Id1); +static const XHdmiphy1_GtHdmiChars *GetGtHdmiPtr(XHdmiphy1 *InstancePtr); +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +static void XHdmiphy1_HdmiSetSystemClockSelection(XHdmiphy1 *InstancePtr, + u8 QuadId); +#endif + +/**************************** Function Definitions ****************************/ + +/******************************************************************************/ +/** + * This function initializes the Video PHY for HDMI. + * + * @param InstancePtr is a pointer to the XHdmiphy1 instance. + * @param CfgPtr is a pointer to the configuration structure that will + * be used to copy the settings from. + * + * @return None. + * + * @note None. + * +*******************************************************************************/ +u32 XHdmiphy1_Hdmi_CfgInitialize(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_Config *CfgPtr) +{ + u8 Id, Id0, Id1; + + /* Verify arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CfgPtr != NULL); + + /* Init done. */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_INIT, 0); + + /* Setup the instance. */ + XHdmiphy1_CfgInitialize(InstancePtr, CfgPtr, CfgPtr->BaseAddr); + + /* Set default. */ + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_IDLE; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)].RxState = + XHDMIPHY1_GT_STATE_IDLE; + /* Initialize Transceiver Width values */ + if (InstancePtr->Config.TransceiverWidth == 2) { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + TxDataWidth = 20; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + TxIntDataWidth = 2; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxDataWidth = 20; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxIntDataWidth = 2; + } + else { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + TxDataWidth = 40; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + TxIntDataWidth = 4; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxDataWidth = 40; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxIntDataWidth = 4; + } + } + + /* Interrupt Disable. */ + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TXRESET_DONE); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RXRESET_DONE); +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_CPLL_LOCK); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL0_LOCK); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TXALIGN_DONE); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL1_LOCK); +#else + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_LCPLL_LOCK); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RPLL_LOCK); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_GPO_RISING_EDGE); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_GPO_RISING_EDGE); +#endif + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT); + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); + + /* Setup HDMI interrupt handler callback*/ + XHdmiphy1_HdmiIntrHandlerCallbackInit(InstancePtr); + + /* Configure clock detector. */ + XHdmiphy1_ClkDetEnable(InstancePtr, FALSE); + XHdmiphy1_ClkDetSetFreqTimeout(InstancePtr, + InstancePtr->Config.AxiLiteClkFreq); + XHdmiphy1_ClkDetSetFreqLockThreshold(InstancePtr, 40); + + /* Start capturing logs. */ + XHdmiphy1_LogReset(InstancePtr); + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_INIT, 0); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_HdmiSetSystemClockSelection(InstancePtr, QuadId); + + /* Indicate of QPLL is present in design */ + if ((XHdmiphy1_IsTxUsingQpll(InstancePtr, + QuadId, XHDMIPHY1_CHANNEL_ID_CH1) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX))) || + (XHdmiphy1_IsRxUsingQpll(InstancePtr, + QuadId, XHDMIPHY1_CHANNEL_ID_CH1) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)))) { + InstancePtr->HdmiIsQpllPresent = TRUE; + } else { + InstancePtr->HdmiIsQpllPresent = FALSE; + } + + if ((InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE3) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE4) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTYE4)) { + XHdmiphy1_SetBufgGtDiv(InstancePtr, XHDMIPHY1_DIR_TX, 1); + XHdmiphy1_SetBufgGtDiv(InstancePtr, XHDMIPHY1_DIR_RX, 1); + } + XHdmiphy1_PowerDownGtPll(InstancePtr, QuadId, XHDMIPHY1_CHANNEL_ID_CMNA, + TRUE); + XHdmiphy1_PowerDownGtPll(InstancePtr, QuadId, XHDMIPHY1_CHANNEL_ID_CHA, + TRUE); + XHdmiphy1_ResetGtPll(InstancePtr, QuadId, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, TRUE); + XHdmiphy1_ResetGtPll(InstancePtr, QuadId, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, TRUE); +#endif + XHdmiphy1_MmcmReset(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, TRUE); + XHdmiphy1_MmcmReset(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, TRUE); + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) { + XHdmiphy1_IBufDsEnable(InstancePtr, QuadId, XHDMIPHY1_DIR_TX, (FALSE)); + } + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)) { + XHdmiphy1_IBufDsEnable(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, (FALSE)); + } + + /* DRU Settings. */ + if (InstancePtr->Config.DruIsPresent) { + XHdmiphy1_IBufDsEnable(InstancePtr, QuadId, XHDMIPHY1_DIR_RX, TRUE); + XHdmiphy1_DruReset(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, TRUE); + XHdmiphy1_DruEnable(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, FALSE); + } + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + /* Set to DFE */ + XHdmiphy1_SetRxLpm(InstancePtr, QuadId, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, 0); +#endif + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + XHdmiphy1_SetTxVoltageSwing(InstancePtr, QuadId, +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + (XHdmiphy1_ChannelId)Id, 0xB); +#else + (XHdmiphy1_ChannelId)Id, 0x1F); +#endif + XHdmiphy1_SetTxPreEmphasis(InstancePtr, QuadId, + (XHdmiphy1_ChannelId)Id, 0x4); + XHdmiphy1_SetTxPostCursor(InstancePtr, QuadId, + (XHdmiphy1_ChannelId)Id, 0x4); + } + + /* Clear Interrupt Register */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_INTR_STS_REG, + 0xFFFFFFFF); + + /* Interrupt Enable. */ + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TXRESET_DONE); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RXRESET_DONE); +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_CPLL_LOCK); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL0_LOCK); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TXALIGN_DONE); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL1_LOCK); +#else + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_LCPLL_LOCK); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RPLL_LOCK); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_GPO_RISING_EDGE); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_GPO_RISING_EDGE); +#endif + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE); + XHdmiphy1_ClkDetEnable(InstancePtr, TRUE); + + /* Set the flag to indicate the driver is. */ + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + /* Init done. */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_INIT, 1); + + return XST_SUCCESS; +} + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +/*****************************************************************************/ +/** +* This function Sets the System Clock Selection +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void XHdmiphy1_HdmiSetSystemClockSelection(XHdmiphy1 *InstancePtr, + u8 QuadId) +{ + XHdmiphy1_PllType XHdmiphy1_QPllType; + + XHdmiphy1_QPllType = XHDMIPHY1_PLL_TYPE_QPLL0; + + /* Set system clock selections */ + if (InstancePtr->Config.TxSysPllClkSel == + InstancePtr->Config.RxSysPllClkSel) { + if (InstancePtr->Config.RxSysPllClkSel == + XHDMIPHY1_SYSCLKSELDATA_TYPE_CPLL_OUTCLK) { + XHdmiphy1_PllInitialize(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CHA, + InstancePtr->Config.RxRefClkSel, + InstancePtr->Config.RxRefClkSel, + XHDMIPHY1_PLL_TYPE_CPLL, + XHDMIPHY1_PLL_TYPE_CPLL); + } + else { + XHdmiphy1_PllInitialize(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMN0, + InstancePtr->Config.RxRefClkSel, + InstancePtr->Config.RxRefClkSel, + XHdmiphy1_QPllType, + XHdmiphy1_QPllType); + } + } + else if (InstancePtr->Config.TxSysPllClkSel == + XHDMIPHY1_SYSCLKSELDATA_TYPE_CPLL_OUTCLK) { + XHdmiphy1_PllInitialize(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CHA, + InstancePtr->Config.RxRefClkSel, + InstancePtr->Config.TxRefClkSel, + XHDMIPHY1_PLL_TYPE_CPLL, + XHdmiphy1_QPllType); + } + else { + XHdmiphy1_PllInitialize(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMN0, + InstancePtr->Config.TxRefClkSel, + InstancePtr->Config.RxRefClkSel, + XHdmiphy1_QPllType, + XHDMIPHY1_PLL_TYPE_CPLL); + } +} + +/*****************************************************************************/ +/** +* This function Updates the HDMIPHY clocking. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param TxSysPllClkSel is the SYSCLKDATA selection for TX. +* @param RxSysPllClkSel is the SYSCLKDATA selection for RX. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiUpdateClockSelection(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_SysClkDataSelType TxSysPllClkSel, + XHdmiphy1_SysClkDataSelType RxSysPllClkSel) +{ + u8 Id, Id0, Id1; + + /* Reset PLL */ + XHdmiphy1_ResetGtPll(InstancePtr, QuadId, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, TRUE); + XHdmiphy1_ResetGtPll(InstancePtr, QuadId, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, TRUE); + + /* Set default. */ + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_IDLE; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)].RxState = + XHDMIPHY1_GT_STATE_IDLE; + } + + /* Update Hdmiphy Clocking */ + InstancePtr->Config.TxSysPllClkSel = TxSysPllClkSel; + InstancePtr->Config.RxSysPllClkSel = RxSysPllClkSel; + XHdmiphy1_HdmiSetSystemClockSelection(InstancePtr, QuadId); +} + +/*****************************************************************************/ +/** +* This function resets the GT TX alignment module. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param ChId is the channel ID to operate on. +* @param Reset specifies TRUE/FALSE value to either assert or deassert +* reset on the TX alignment module, respectively. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_TxAlignReset(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 Reset) +{ + u32 RegVal; + u32 MaskVal = 0; + u8 Id, Id0, Id1; + + /* Read TX align register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_BUFFER_BYPASS_REG); + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + MaskVal |= XHDMIPHY1_TX_BUFFER_BYPASS_TXPHDLYRESET_MASK(Id); + } + + /* Write new value to BUFG_GT register. */ + if (Reset) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_BUFFER_BYPASS_REG, RegVal); +} + +/*****************************************************************************/ +/** +* This function resets the GT TX alignment module. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param ChId is the channel ID to operate on. +* @param Start specifies TRUE/FALSE value to either start or ttop the TX +* alignment module, respectively. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_TxAlignStart(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 Start) +{ + u32 RegVal; + u32 MaskVal = 0; + u8 Id, Id0, Id1; + + /* Read TX align register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_BUFFER_BYPASS_REG); + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + MaskVal |= XHDMIPHY1_TX_BUFFER_BYPASS_TXPHALIGN_MASK(Id); + } + + /* Write new value to BUFG_GT register. */ + if (Start) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } + + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_BUFFER_BYPASS_REG, RegVal); +} +#endif + +/*****************************************************************************/ +/** +* This function enables the HDMIPHY's detector peripheral. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param Enable specifies TRUE/FALSE value to either enable or disable +* the clock detector respectively. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_ClkDetEnable(XHdmiphy1 *InstancePtr, u8 Enable) +{ + u32 RegVal; + + /* Read clkdet ctrl register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_CLKDET_CTRL_REG); + + /* Write new value to clkdet ctrl register. */ + if (Enable) { + RegVal |= XHDMIPHY1_CLKDET_CTRL_RUN_MASK; + } + else { + RegVal &= ~XHDMIPHY1_CLKDET_CTRL_RUN_MASK; + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_CLKDET_CTRL_REG, + RegVal); +} + +/*****************************************************************************/ +/** +* This function clears the clock detector TX/RX timer. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_ClkDetTimerClear(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir) +{ + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + /* Read the clock detector control register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_CLKDET_CTRL_REG); + + if (Dir == XHDMIPHY1_DIR_TX) { + RegVal |= XHDMIPHY1_CLKDET_CTRL_TX_TMR_CLR_MASK; + } + else { + RegVal |= XHDMIPHY1_CLKDET_CTRL_RX_TMR_CLR_MASK; + } + + /* Write new value to clkdet ctrl register. */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_CLKDET_CTRL_REG, + RegVal); +} + +/*****************************************************************************/ +/** +* This function resets clock detector TX/RX frequency. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_ClkDetFreqReset(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir) +{ + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + /* Read clkdet ctrl register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_CLKDET_CTRL_REG); + + if (Dir == XHDMIPHY1_DIR_TX) { + RegVal |= XHDMIPHY1_CLKDET_CTRL_TX_FREQ_RST_MASK; + } + else { + RegVal |= XHDMIPHY1_CLKDET_CTRL_RX_FREQ_RST_MASK; + } + + /* Write new value to clkdet ctrl register. */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_CLKDET_CTRL_REG, + RegVal); +} + +/*****************************************************************************/ +/** +* This function sets the clock detector frequency lock counter threshold value. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param ThresholdVal is the threshold value to be set. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_ClkDetSetFreqLockThreshold(XHdmiphy1 *InstancePtr, + u16 ThresholdVal) +{ + u32 RegVal; + + /* Read clkdet ctrl register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_CLKDET_CTRL_REG); + RegVal &= ~XHDMIPHY1_CLKDET_CTRL_RX_FREQ_RST_MASK; + + /* Update with new threshold. */ + RegVal |= (ThresholdVal << XHDMIPHY1_CLKDET_CTRL_FREQ_LOCK_THRESH_SHIFT); + + /* Write new value to clkdet ctrl register. */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_CLKDET_CTRL_REG, + RegVal); +} + +/*****************************************************************************/ +/** +* This function checks clock detector RX/TX frequency zero indicator bit. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param Dir is an indicator for RX or TX. +* +* @return - TRUE if zero frequency. +* - FALSE otherwise, if non-zero frequency. +* +* @note None. +* +******************************************************************************/ +u8 XHdmiphy1_ClkDetCheckFreqZero(XHdmiphy1 *InstancePtr, + XHdmiphy1_DirectionType Dir) +{ + u32 MaskVal = 0; + u32 RegVal; + + if (Dir == XHDMIPHY1_DIR_TX) { + MaskVal = XHDMIPHY1_CLKDET_STAT_TX_FREQ_ZERO_MASK; + } + else { + MaskVal = XHDMIPHY1_CLKDET_STAT_RX_FREQ_ZERO_MASK; + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_DRU_STAT_REG); + RegVal &= MaskVal; + + if (RegVal) { + return (TRUE); + } + + return (FALSE); +} + +/*****************************************************************************/ +/** +* This function sets clock detector frequency lock counter threshold value. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param TimeoutVal is the timeout value and is normally the system clock +* frequency. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_ClkDetSetFreqTimeout(XHdmiphy1 *InstancePtr, u32 TimeoutVal) +{ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_CLKDET_FREQ_TMR_TO_REG, TimeoutVal); +} + +/*****************************************************************************/ +/** +* This function loads the timer to TX/RX in the clock detector. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for RX or TX. +* @param TimeoutVal is the timeout value to store in the clock detector. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_ClkDetTimerLoad(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u32 TimeoutVal) +{ + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_CLKDET_TMR_TX_REG; + } + else { + RegOffset = XHDMIPHY1_CLKDET_TMR_RX_REG; + } + + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, TimeoutVal); +} + +/*****************************************************************************/ +/** +* This function returns the frequency of the RX/TX reference clock as +* measured by the clock detector peripheral. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param Dir is an indicator for RX or TX. +* +* @return The measured frequency of the RX/TX reference clock. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_ClkDetGetRefClkFreqHz(XHdmiphy1 *InstancePtr, + XHdmiphy1_DirectionType Dir) +{ + u32 RegOffset; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_CLKDET_FREQ_TX_REG; + } + else { + RegOffset = XHDMIPHY1_CLKDET_FREQ_RX_REG; + } + + return XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); +} + +/*****************************************************************************/ +/** +* This function returns the frequency of the DRU reference clock as measured by +* the clock detector peripheral. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* +* @return The measured frequency of the DRU reference clock. +* +* @note The design must have a DRU for this function to return a valid +* value. +* +******************************************************************************/ +u32 XHdmiphy1_DruGetRefClkFreqHz(XHdmiphy1 *InstancePtr) +{ + u32 DruFreqHz = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_CLKDET_FREQ_DRU_REG); + + + + /* Verify argument. */ + Xil_AssertNonvoid(InstancePtr != NULL); + + if (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE3) { + if (DruFreqHz > XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK_MAX){ + return XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK; + } + else if (DruFreqHz > XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK2_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK2_MAX){ + return XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK2; + } + } + else if (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE4) { + if (DruFreqHz > XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK_MAX){ + return XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK; + } + else if (DruFreqHz > XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK2_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK2_MAX){ + return XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK2; + } + } + else if (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTYE4) { + if (DruFreqHz > XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK_MAX){ + return XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK; + } + else if (DruFreqHz > XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK2_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK2_MAX){ + return XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK2; + } + } + else { + if (DruFreqHz > XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK_MAX){ + return XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK; + } + if (DruFreqHz > XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK1_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK1_MAX){ + return XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK1; + } + if (DruFreqHz > XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK2_MIN && + DruFreqHz < XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK2_MAX){ + return XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK2; + } + } + + /* Return Failure */ + return XST_FAILURE; +} + +/*****************************************************************************/ +/** +* This function resets the DRU in the HDMIPHY. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param ChId is the channel ID to operate on. +* @param Reset specifies TRUE/FALSE value to either enable or disable +* the DRU respectively. +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_DruReset(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 Reset) +{ + u32 RegVal; + u32 MaskVal = 0; + u8 Id, Id0, Id1; + + /* Read DRU ctrl register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_DRU_CTRL_REG); + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + MaskVal |= XHDMIPHY1_DRU_CTRL_RST_MASK(Id); + } + + /* Write DRU ctrl register. */ + if (Reset) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_DRU_CTRL_REG, + RegVal); +} + +/*****************************************************************************/ +/** +* This function enabled/disables the DRU in the HDMIPHY. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param ChId is the channel ID to operate on. +* @param Enable specifies TRUE/FALSE value to either enable or disable +* the DRU, respectively. +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_DruEnable(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 Enable) +{ + u32 RegVal; + u32 MaskVal = 0; + u8 Id, Id0, Id1; + + /* Read DRU ctrl register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_DRU_CTRL_REG); + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + MaskVal |= XHDMIPHY1_DRU_CTRL_EN_MASK(Id); + } + + /* Write DRU ctrl register. */ + if (Enable) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_DRU_CTRL_REG, + RegVal); +} + +/*****************************************************************************/ +/** +* This function gets the DRU version +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* +* @return None. +* +******************************************************************************/ +u16 XHdmiphy1_DruGetVersion(XHdmiphy1 *InstancePtr) +{ + u32 RegVal; + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_DRU_STAT_REG); + RegVal &= XHDMIPHY1_DRU_STAT_VERSION_MASK; + RegVal >>= XHDMIPHY1_DRU_STAT_VERSION_SHIFT; + + return ((u16)RegVal); +} + +/*****************************************************************************/ +/** +* This function sets the DRU center frequency. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param ChId specifies the channel ID. +* @param CenterFreqHz is the frequency value to set. +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_DruSetCenterFreqHz(XHdmiphy1 *InstancePtr, + XHdmiphy1_ChannelId ChId, u64 CenterFreqHz) +{ + u32 CenterFreqL; + u32 CenterFreqH; + u32 RegOffset; + u8 Id, Id0, Id1; + + /* Split the 64-bit input into 2 32-bit values. */ + CenterFreqL = (u32)CenterFreqHz; + CenterFreqHz >>= 32; + CenterFreqHz &= XHDMIPHY1_DRU_CFREQ_H_MASK;; + CenterFreqH = (u32)CenterFreqHz; + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + RegOffset = XHDMIPHY1_DRU_CFREQ_L_REG(Id); + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, + CenterFreqL); + + RegOffset = XHDMIPHY1_DRU_CFREQ_H_REG(Id); + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, + CenterFreqH); + } +} + +/*****************************************************************************/ +/** +* This function calculates the center frequency value for the DRU. +* +* @param InstancePtr is a pointer to the XHdmiphy1 GT core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return The calculated DRU Center frequency value. +* +* @note According to XAPP1240: +* Center_f = fDIN * (2^32)/fdruclk +* The DRU clock is derived from the measured reference clock and +* the current QPLL settings. +* +******************************************************************************/ +u64 XHdmiphy1_DruCalcCenterFreqHz(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_Channel *ChPtr; + u64 DruRefClk; +#endif + u64 ClkDetRefClk; + u64 DataRate; + u64 FDin; + u64 FDruClk; + + ClkDetRefClk = XHdmiphy1_ClkDetGetRefClkFreqHz(InstancePtr, + XHDMIPHY1_DIR_RX); +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + DruRefClk = XHdmiphy1_DruGetRefClkFreqHz(InstancePtr); + + /* Take the master channel (channel 1). */ + ChPtr = &InstancePtr->Quads[QuadId].Ch1; + + if ((ChId == XHDMIPHY1_CHANNEL_ID_CMN0) || + (ChId == XHDMIPHY1_CHANNEL_ID_CMN1)) { + FDruClk = (DruRefClk * InstancePtr->Quads[QuadId].Plls[ + XHDMIPHY1_CH2IDX(ChId)].PllParams.NFbDiv) / + (InstancePtr->Quads[QuadId].Plls[ + XHDMIPHY1_CH2IDX(ChId)].PllParams.MRefClkDiv * + (ChPtr->RxOutDiv * 20)); + } + else { + FDruClk = (DruRefClk * ChPtr->PllParams.N1FbDiv * + ChPtr->PllParams.N2FbDiv * 2) / + (ChPtr->PllParams.MRefClkDiv * ChPtr->RxOutDiv * 20); + } +#else + /* Supress Warning */ + QuadId = QuadId; + ChId = ChId; + + FDruClk = (u64) (XHDMIPHY1_HDMI_GTYE5_DRU_LRATE / 20); +#endif + DataRate = 10 * ClkDetRefClk; + FDin = DataRate * ((u64)1 << 32); + + /* Check for divide by zero. */ + if (FDin && FDruClk) { + return (FDin / FDruClk); + } + return 0; +} + +/*****************************************************************************/ +/** +* This function sets the GT RX CDR and Equalization for DRU mode. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param Enable enables the DRU logic (when 1), or disables (when 0). +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_HdmiGtDruModeEnable(XHdmiphy1 *InstancePtr, u8 Enable) +{ + u32 RegVal; + u32 RegMask = 0; + u8 Id, Id0, Id1; + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_DRU_EN, Enable); + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_RX_EQ_CDR_REG); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + RegMask |= XHDMIPHY1_RX_STATUS_RXCDRHOLD_MASK(Id) | + XHDMIPHY1_RX_STATUS_RXOSOVRDEN_MASK(Id) | + XHDMIPHY1_RX_STATUS_RXLPMLFKLOVRDEN_MASK(Id) | + XHDMIPHY1_RX_STATUS_RXLPMHFOVRDEN_MASK(Id); + } + + if (Enable) { + RegVal |= RegMask; + } + else { + RegVal &= ~RegMask; + } + + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_RX_EQ_CDR_REG, + RegVal); +} + +/*****************************************************************************/ +/** +* This function calculates the HDMI MMCM parameters. +* +* @param InstancePtr is a pointer to the Hdmiphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for RX or TX. +* @param Ppc specifies the total number of pixels per clock. +* - 1 = XVIDC_PPC_1 +* - 2 = XVIDC_PPC_2 +* - 4 = XVIDC_PPC_4 +* @param Bpc specifies the color depth/bits per color component. +* - 6 = XVIDC_BPC_6 +* - 8 = XVIDC_BPC_8 +* - 10 = XVIDC_BPC_10 +* - 12 = XVIDC_BPC_12 +* - 16 = XVIDC_BPC_16 +* +* @return +* - XST_SUCCESS if calculated PLL parameters updated successfully. +* - XST_FAILURE if parameters not updated. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_HdmiCfgCalcMmcmParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + XVidC_PixelsPerClock Ppc, XVidC_ColorDepth Bpc) +{ + u32 RefClk; + u16 Div; + u16 Mult; + u16 MultDiv; + u8 Valid; + u64 LineRate = 0; + XHdmiphy1_Mmcm *MmcmPtr; + XHdmiphy1_PllType PllType; + + /* Suppress Warning Messages */ + ChId = ChId; + + /* Get line rate. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, Dir, + XHDMIPHY1_CHANNEL_ID_CH1); + + switch (PllType) { + case XHDMIPHY1_PLL_TYPE_QPLL: + case XHDMIPHY1_PLL_TYPE_QPLL0: + case XHDMIPHY1_PLL_TYPE_LCPLL: + LineRate = InstancePtr->Quads[QuadId].Cmn0.LineRateHz; + break; + case XHDMIPHY1_PLL_TYPE_QPLL1: + case XHDMIPHY1_PLL_TYPE_RPLL: + LineRate = InstancePtr->Quads[QuadId].Cmn1.LineRateHz; + break; + default: + LineRate = InstancePtr->Quads[QuadId].Ch1.LineRateHz; + break; + } + + if (((LineRate / 1000000) > 2970) && (Ppc == XVIDC_PPC_1)) { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_1PPC_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + + Div = 1; + + do { + if (Dir == XHDMIPHY1_DIR_RX) { + RefClk = InstancePtr->HdmiRxRefClkHz; + MmcmPtr= &InstancePtr->Quads[QuadId].RxMmcm; + + RefClk = RefClk / (GetGtHdmiPtr(InstancePtr))->RxMmcmScale; + Mult = (GetGtHdmiPtr(InstancePtr))->RxMmcmFvcoMax * Div / RefClk; + } + else { + RefClk = InstancePtr->HdmiTxRefClkHz; + MmcmPtr= &InstancePtr->Quads[QuadId].TxMmcm; + + RefClk = RefClk / (GetGtHdmiPtr(InstancePtr))->TxMmcmScale; + Mult = (GetGtHdmiPtr(InstancePtr))->TxMmcmFvcoMax * Div / RefClk; + } + + /* Return if RefClk is below valid range */ + if (RefClk < 20000000) { + return (XST_FAILURE); + } + + /* In case of 4 pixels per clock, the M must be a multiple of four. */ + if (Ppc == XVIDC_PPC_4) { + Mult = Mult / 4; + Mult = Mult * 4; + } + /* Else the M must be a multiple of two. */ + else if (Ppc == XVIDC_PPC_2) { + Mult = Mult / 2; + Mult = Mult * 2; + } + + + Valid = (FALSE); + do { + MultDiv = Mult / Div; + MmcmPtr->ClkFbOutMult = Mult; + MmcmPtr->DivClkDivide = Div; + + if (InstancePtr->Config.TransceiverWidth == 4) { + /* Link clock: TMDS clock ratio 1/40. */ + if ((LineRate / 1000000) >= 3400) { + if ((Dir == XHDMIPHY1_DIR_TX) && + (((LineRate / 1000000) / InstancePtr-> + HdmiTxSampleRate) < 3400)) { + MmcmPtr->ClkOut0Div = MultDiv * 4; + } + else { + MmcmPtr->ClkOut0Div = MultDiv; + } + } + /* Link clock: TMDS clock ratio 1/10. */ + else { + MmcmPtr->ClkOut0Div = MultDiv * 4; + } + } + else { /* 2 Byte Mode */ + /* Link clock: TMDS clock ratio 1/40. */ + if ((LineRate / 1000000) >= 3400) { + if ((Dir == XHDMIPHY1_DIR_TX) && + (((LineRate / 1000000) / InstancePtr-> + HdmiTxSampleRate) < 3400)) { + MmcmPtr->ClkOut0Div = MultDiv * 2; + } + else { + MmcmPtr->ClkOut0Div = MultDiv / 2; + } + } + /* Link clock: TMDS clock ratio 1/10. */ + else { + MmcmPtr->ClkOut0Div = MultDiv * 2; + } + } + + /* TMDS Clock */ + MmcmPtr->ClkOut1Div = MultDiv * ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1); + + /* Video clock. */ + MmcmPtr->ClkOut2Div = 0; + + switch (Bpc) { + case XVIDC_BPC_10: + /* Quad pixel. */ + if (Ppc == (XVIDC_PPC_4)) { + MmcmPtr->ClkOut2Div = (MultDiv * 5 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + /* Dual pixel. */ + else if (Ppc == (XVIDC_PPC_2)) { + /* The clock ratio is 2.5 */ + /* The PLL only supports integer values */ + /* The MultDiv must be dividable by two (2 * 2.5 = 5) + to get an integer number */ + if ((MultDiv % 2) == 0) { + MmcmPtr->ClkOut2Div = (MultDiv * 5 / 2 * + ((Dir == XHDMIPHY1_DIR_TX)? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + } + /* Single pixel. */ + else { + /* The clock ratio is 1.25 */ + /* The PLL only supports integer values */ + /* The MultDiv must be dividable by four (4 * 1.25 = 5) + to get an integer number */ + if ((MultDiv % 4) == 0) { + MmcmPtr->ClkOut2Div = (MultDiv * 5 / 4 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + } + break; + case XVIDC_BPC_12: + /* Quad pixel. */ + if (Ppc == (XVIDC_PPC_4)) { + MmcmPtr->ClkOut2Div = (MultDiv * 6 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + /* Dual pixel. */ + else if (Ppc == (XVIDC_PPC_2)) { + MmcmPtr->ClkOut2Div = (MultDiv * 3 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + /* Single pixel. */ + else { + /* The clock ratio is 1.5 */ + /* The PLL only supports integer values */ + /* The MultDiv must be dividable by two (2 * 1.5 = 3) + to get an integer number */ + if ((MultDiv % 2) == 0) { + MmcmPtr->ClkOut2Div = (MultDiv * 3 / 2 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + } + break; + case XVIDC_BPC_16 : + /* Quad pixel. */ + if (Ppc == (XVIDC_PPC_4)) { + MmcmPtr->ClkOut2Div = (MultDiv * 8 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + /* Dual pixel. */ + else if (Ppc == (XVIDC_PPC_2)) { + MmcmPtr->ClkOut2Div = (MultDiv * 4 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + /* Single pixel. */ + else { + MmcmPtr->ClkOut2Div = (MultDiv * 2 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + break; + case XVIDC_BPC_8: + default: + /* Quad pixel. */ + if (Ppc == (XVIDC_PPC_4)) { + MmcmPtr->ClkOut2Div = (MultDiv * 4 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + /* Dual pixel. */ + else if (Ppc == (XVIDC_PPC_2)) { + MmcmPtr->ClkOut2Div = (MultDiv * 2 * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + /* Single pixel. */ + else { + MmcmPtr->ClkOut2Div = (MultDiv * + ((Dir == XHDMIPHY1_DIR_TX) ? + (InstancePtr->HdmiTxSampleRate) : 1)); + } + break; + } + + /* Only do this when the ClkOut2Div has been set */ + if (MmcmPtr->ClkOut2Div) { + if (Dir == XHDMIPHY1_DIR_RX) { + /* Correct divider value if TMDS clock ratio is 1/40. */ + if (InstancePtr->HdmiRxTmdsClockRatio) { + if ((MmcmPtr->ClkOut2Div % 4) == 0) { + MmcmPtr->ClkOut2Div = MmcmPtr->ClkOut2Div / 4; + } + /* Not divisible by 4: repeat loop with a lower + * multiply value. */ + else { +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + MmcmPtr->ClkOut2Div = 255; +#else + MmcmPtr->ClkOut2Div = 65535; +#endif + } + } + } + /* TX. */ + else if ((((LineRate / 1000000) >= 3400) && + (InstancePtr->HdmiTxSampleRate == 1)) || + (((LineRate / 1000000) / InstancePtr-> + HdmiTxSampleRate) >= 3400)) { + if ((MmcmPtr->ClkOut2Div % 4) == 0) { + MmcmPtr->ClkOut2Div = MmcmPtr->ClkOut2Div / 4; + } + /* Not divisible by 4: repeat loop with a lower + * multiply value. */ + else { +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + MmcmPtr->ClkOut2Div = 255; +#else + MmcmPtr->ClkOut2Div = 65535; +#endif + } + } + } + + /* Check values. */ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + if ((MmcmPtr->ClkOut0Div > 0) && (MmcmPtr->ClkOut0Div <= 128) && + (MmcmPtr->ClkOut1Div > 0) && (MmcmPtr->ClkOut1Div <= 128) && + (MmcmPtr->ClkOut2Div > 0) && (MmcmPtr->ClkOut2Div <= 128)) { +#else + if ((MmcmPtr->ClkOut0Div > 0) && (MmcmPtr->ClkOut0Div <= 511) && + (MmcmPtr->ClkOut1Div > 0) && (MmcmPtr->ClkOut1Div <= 511) && + (MmcmPtr->ClkOut2Div > 0) && (MmcmPtr->ClkOut2Div <= 511)) { +#endif + Valid = (TRUE); + } + else { + /* 4 pixels per clock. */ + if (Ppc == (XVIDC_PPC_4)) { + /* Decrease Mult value. */ + Mult -= 4; + } + /* 2 pixels per clock. */ + else if (Ppc == (XVIDC_PPC_2)) { + /* Decrease M value. */ + Mult -= 2; + } + /* 1 pixel per clock */ + else { + /* Decrease M value */ + Mult -= 1; + } + } +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) + } while (!Valid && (Mult > 3) && (Mult < 432)); +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4 || \ + XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) + } while (!Valid && (Mult > 0) && (Mult < 129)); +#else + } while (!Valid && (Mult > 0) && (Mult < 65)); +#endif + + /* Increment divider */ + Div++; +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) + } while (!Valid && (Div > 0) && (Div < 124)); +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4 || \ + XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) + } while (!Valid && (Div > 0) && (Div < 107)); +#else + } while (!Valid && (Div > 0) && (Div < 20)); +#endif + + if (Valid) { + return (XST_SUCCESS); + } + else { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_MMCM_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } +} + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +/*****************************************************************************/ +/** +* This function calculates the QPLL parameters. +* +* @param InstancePtr is a pointer to the HDMI GT core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if calculated QPLL parameters updated +* successfully. +* - XST_FAILURE if parameters not updated. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_HdmiQpllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 Status; + u64 RefClk = 0; + u32 *RefClkPtr; + u64 TxLineRate = 0; + u8 Id, Id0, Id1; + + u8 SRArray[] = {1, 3, 5}; + u8 SRIndex; + u8 SRValue; + + /* Suppress Warning Messages */ + ChId = ChId; + + XHdmiphy1_SysClkDataSelType SysClkDataSel = + (XHdmiphy1_SysClkDataSelType) 0; + XHdmiphy1_SysClkOutSelType SysClkOutSel = + (XHdmiphy1_SysClkOutSelType) 0; + XHdmiphy1_ChannelId ActiveCmnId = + XHDMIPHY1_CHANNEL_ID_CMN0; + + u32 QpllRefClk; + u32 QpllClkMin = 0; + + /* Determine QPLL reference clock from the first (master) channel. */ + if (Dir == XHDMIPHY1_DIR_RX) { + QpllRefClk = InstancePtr->HdmiRxRefClkHz; + RefClkPtr = &InstancePtr->HdmiRxRefClkHz; + } + else { + QpllRefClk = InstancePtr->HdmiTxRefClkHz; + RefClkPtr = &InstancePtr->HdmiTxRefClkHz; + } + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE3) + /* Determine which QPLL to use. */ + if (((102343750 <= QpllRefClk) && (QpllRefClk <= 122500000)) || + ((204687500 <= QpllRefClk) && (QpllRefClk <= 245000000)) || + ((409375000 <= QpllRefClk) && (QpllRefClk <= 490000000))) { + SysClkDataSel = XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL1_OUTCLK; + SysClkOutSel = XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL1_REFCLK; + ActiveCmnId = XHDMIPHY1_CHANNEL_ID_CMN1; + QpllClkMin = (u32) XHDMIPHY1_HDMI_GTHE3_QPLL1_REFCLK_MIN; + } + else { + SysClkDataSel = XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK; + SysClkOutSel = XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL0_REFCLK; + ActiveCmnId = XHDMIPHY1_CHANNEL_ID_CMN0; + QpllClkMin = (u32) XHDMIPHY1_HDMI_GTHE3_QPLL0_REFCLK_MIN; + } +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) + /* Determine which QPLL to use. */ + if (((102343750 <= QpllRefClk) && (QpllRefClk <= 122500000)) || + ((204687500 <= QpllRefClk) && (QpllRefClk <= 245000000)) || + ((409375000 <= QpllRefClk) && (QpllRefClk <= 490000000))) { + SysClkDataSel = XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL1_OUTCLK; + SysClkOutSel = XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL1_REFCLK; + ActiveCmnId = XHDMIPHY1_CHANNEL_ID_CMN1; + QpllClkMin = (u32) XHDMIPHY1_HDMI_GTHE4_QPLL1_REFCLK_MIN; + } + else { + SysClkDataSel = XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK; + SysClkOutSel = XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL0_REFCLK; + ActiveCmnId = XHDMIPHY1_CHANNEL_ID_CMN0; + QpllClkMin = (u32) XHDMIPHY1_HDMI_GTHE4_QPLL0_REFCLK_MIN; + } +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) + /* Determine which QPLL to use. */ + if (((102343750 <= QpllRefClk) && (QpllRefClk <= 122500000)) || + ((204687500 <= QpllRefClk) && (QpllRefClk <= 245000000)) || + ((409375000 <= QpllRefClk) && (QpllRefClk <= 490000000))) { + SysClkDataSel = XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL1_OUTCLK; + SysClkOutSel = XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL1_REFCLK; + ActiveCmnId = XHDMIPHY1_CHANNEL_ID_CMN1; + QpllClkMin = (u32) XHDMIPHY1_HDMI_GTYE4_QPLL1_REFCLK_MIN; + } + else { + SysClkDataSel = XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK; + SysClkOutSel = XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL0_REFCLK; + ActiveCmnId = XHDMIPHY1_CHANNEL_ID_CMN0; + QpllClkMin = (u32) XHDMIPHY1_HDMI_GTYE4_QPLL0_REFCLK_MIN; + } +#endif + + /* Update QPLL clock selections. */ + XHdmiphy1_CfgSysClkDataSel(InstancePtr, QuadId, Dir, SysClkDataSel); + XHdmiphy1_CfgSysClkOutSel(InstancePtr, QuadId, Dir, SysClkOutSel); + + /* RX is using QPLL. */ + if (Dir == XHDMIPHY1_DIR_RX) { + /* Check if the reference clock is not below the minimum QPLL + * input frequency. */ + if (QpllRefClk >= QpllClkMin) { + RefClk = QpllRefClk; + + /* Scaled line rate. */ + if (InstancePtr->RxHdmi21Cfg.IsEnabled == 0) { + if (InstancePtr->HdmiRxTmdsClockRatio) { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, (RefClk * 40)); + } + else { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, (RefClk * 10)); + } + } else { /* InstancePtr->RxHdmi21Cfg.IsEnabled == 1 */ + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, + InstancePtr->RxHdmi21Cfg.LineRate); + } + + /* Clear DRU is enabled flag. */ + InstancePtr->HdmiRxDruIsEnabled = 0; + + /* Set RX data width. */ + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, + &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + if (InstancePtr->Config.TransceiverWidth == 2) { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxDataWidth = 20; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxIntDataWidth = 2; + } + else { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxDataWidth = 40; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxIntDataWidth = 4; + } + } + + } + /* The reference clock is below the minimum frequency thus + * select the DRU. */ + else if (InstancePtr->Config.DruIsPresent) { + RefClk = XHdmiphy1_DruGetRefClkFreqHz(InstancePtr); + /* Check DRU frequency */ + if (RefClk == XST_FAILURE) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_DRU_CLK_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + + + /* Round input frequency to 10 kHz. */ + RefClk = (RefClk+5000) / 10000; + RefClk = RefClk * 10000; + + /* Set the DRU to operate at a linerate of 2.5 Gbps. */ + XHdmiphy1_CfgLineRate(InstancePtr, + QuadId, XHDMIPHY1_CHANNEL_ID_CMNA, + (GetGtHdmiPtr(InstancePtr))->DruLineRate); + + /* Set DRU is enabled flag. */ + InstancePtr->HdmiRxDruIsEnabled = 1; + + /* Set RX data width to 40 and 4 bytes. */ + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, + &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[QuadId].Plls[ + XHDMIPHY1_CH2IDX(Id)].RxDataWidth = 20; + InstancePtr->Quads[QuadId].Plls[ + XHDMIPHY1_CH2IDX(Id)].RxIntDataWidth = 2; + } + } + else { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_NO_DRU, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + } + + /* TX is using QPLL. */ + else { + /* Set default TX sample rate. */ + InstancePtr->HdmiTxSampleRate = 1; + + if (InstancePtr->TxHdmi21Cfg.IsEnabled == 0) { + /* Update TX line rates. */ + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, (u64)((*RefClkPtr) * 10)); + TxLineRate = (*RefClkPtr) / 100000;; + + /* Check if the linerate is above the 340 Mcsc. */ + if ((TxLineRate) >= 3400) { + (*RefClkPtr) = (*RefClkPtr) / 4; + } + } else { /* InstancePtr->TxHdmi21Cfg.IsEnabled == 1 */ + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, + InstancePtr->TxHdmi21Cfg.LineRate); + } + } + + /* Calculate QPLL values. */ + for (SRIndex = 0; SRIndex < sizeof(SRArray); SRIndex++) { + /* Only use oversampling when then TX is using the QPLL. */ + if (Dir == XHDMIPHY1_DIR_TX) { + SRValue = SRArray[SRIndex]; + + if (InstancePtr->TxHdmi21Cfg.IsEnabled == 0) { + /* TX reference clock is below the minimum QPLL clock + * input frequency. */ + if ((*RefClkPtr) < QpllClkMin) { + RefClk = ((*RefClkPtr) * SRValue); + + /* Calculate scaled line rate. */ + if (TxLineRate >= 3400) { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, + (u64)(RefClk * 40)); + } + else { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, + (u64)(RefClk * 10)); + } + } + /* TX reference clock is in QPLL clock input range. + * In this case don't increase the reference clock, but + * increase the line rate. */ + else { + RefClk = (*RefClkPtr); + + /* Calculate scaled line rate. */ + if (TxLineRate >= 3400) { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, + (u64)(RefClk * 40 *SRValue)); + } + + else { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CMNA, + (u64)(RefClk * 10 *SRValue)); + } + } + } + else { /* InstancePtr->TxHdmi21Cfg.IsEnabled == 1 */ + RefClk = (*RefClkPtr); + } + } + /* For all other reference clocks force sample rate to one. */ + else { + SRValue = 1; + } + + Status = XHdmiphy1_ClkCalcParams(InstancePtr, QuadId, ActiveCmnId, + Dir, RefClk); + if (Status == (XST_SUCCESS)) { + /* Only execute when the TX is using the QPLL. */ + if (Dir == XHDMIPHY1_DIR_TX) { + /* Set TX sample rate. */ + InstancePtr->HdmiTxSampleRate = SRValue; + + /* Update reference clock only when the + * reference clock is below the minimum QPLL + * input frequency. */ + if ((*RefClkPtr) < QpllClkMin) { + (*RefClkPtr) = (*RefClkPtr) * SRValue; + } + else if (SRValue > 1) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_GT_QPLL_CFG_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + } + + /* Check Userclock Frequency */ + /* (300 MHz + 0.5%) + 10 KHz (Clkdet accuracy) */ + if (301500000 < + (XHdmiphy1_GetLineRateHz(InstancePtr, QuadId, + ActiveCmnId) / + (InstancePtr->Config.TransceiverWidth * 10))) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_USRCLK_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + + return (XST_SUCCESS); + } + } + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_GT_QPLL_CFG_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); +} + +/*****************************************************************************/ +/** +* This function calculates the CPLL parameters. +* +* @param InstancePtr is a pointer to the HDMI GT core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if calculated CPLL parameters updated +* successfully. +* - XST_FAILURE if parameters not updated. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_HdmiCpllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 Status; + u64 RefClk = 0; + u32 *RefClkPtr; + u32 TxLineRate = 0; + XHdmiphy1_ChannelId ChannelId = XHDMIPHY1_CHANNEL_ID_CHA; + u8 Id, Id0, Id1; + + u8 SRArray[] = {1, 3, 5}; + u8 SRIndex; + u8 SRValue; + + /* Suppress Warning Messages */ + ChId = ChId; + + /* TX is using CPLL. */ + if (Dir == XHDMIPHY1_DIR_TX) { + + /* Set default TX sample rate. */ + InstancePtr->HdmiTxSampleRate = 1; + + /* Set line rate. */ + RefClkPtr = &InstancePtr->HdmiTxRefClkHz; + if (InstancePtr->TxHdmi21Cfg.IsEnabled == 0) { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, ChannelId, + (u64)((*RefClkPtr) * 10)); + TxLineRate = (*RefClkPtr) / 100000; + + /* Check if the line rate is above the 340 Mcsc. */ + if (TxLineRate >= 3400) { + (*RefClkPtr) = (*RefClkPtr) / 4; + } + } else { /* InstancePtr->TxHdmi21Cfg.IsEnabled == 1 */ + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, ChannelId, + (u64)(InstancePtr->TxHdmi21Cfg.LineRate)); + TxLineRate = InstancePtr->TxHdmi21Cfg.LineRate / 100000; + } + } + /* RX is using CPLL. */ + else { + RefClkPtr = &InstancePtr->HdmiRxRefClkHz; + + /* Check if the reference clock is not below the minimum CPLL + * input frequency. */ + if ((*RefClkPtr) >= + (GetGtHdmiPtr(InstancePtr))->CpllRefClkMin) { + RefClk = (*RefClkPtr); + + /* Scaled linerate */ + if (InstancePtr->RxHdmi21Cfg.IsEnabled == 0) { + if (InstancePtr->HdmiRxTmdsClockRatio) { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + ChannelId, (RefClk * 40)); + } + else { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + ChannelId, (RefClk * 10)); + } + } else { /* InstancePtr->RxHdmi21Cfg.IsEnabled == 1 */ + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + ChannelId, InstancePtr->RxHdmi21Cfg.LineRate); + } + + /* Clear DRU is enabled flag. */ + InstancePtr->HdmiRxDruIsEnabled = 0; + + /* Set RX data width. */ + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, + &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + if (InstancePtr->Config.TransceiverWidth == 2) { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxDataWidth = 20; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxIntDataWidth = 2; + } + else { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxDataWidth = 40; + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxIntDataWidth = 4; + } + } + + } + /* The reference clock is below the minimum frequency thus + * select the DRU. */ + else { + if (InstancePtr->Config.DruIsPresent) { + /* Return config not found error when TMDS ratio is 1/40 */ + if (InstancePtr->HdmiRxTmdsClockRatio) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_GT_CPLL_CFG_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + + RefClk = XHdmiphy1_DruGetRefClkFreqHz(InstancePtr); + /* Check DRU frequency */ + if (RefClk == XST_FAILURE) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_DRU_CLK_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + + /* Round input frequency to 10 kHz. */ + RefClk = (RefClk+5000) / 10000; + RefClk = RefClk * 10000; + + /* Set the DRU to operate at a linerate of + * 2.5 Gbps. */ + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + ChannelId, + (GetGtHdmiPtr(InstancePtr))-> + DruLineRate); + + /* Set DRU is enabled flag. */ + InstancePtr->HdmiRxDruIsEnabled = 1; + + /* Set RX data width. */ + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, + &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[QuadId].Plls[ + XHDMIPHY1_CH2IDX(Id)]. + RxDataWidth = 20; + InstancePtr->Quads[QuadId].Plls[ + XHDMIPHY1_CH2IDX(Id)]. + RxIntDataWidth = 2; + } + + if (TxLineRate > (((GetGtHdmiPtr(InstancePtr)) + ->DruLineRate) / 1000000)) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_VD_NOT_SPRTD_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + } + else { + /* Return config not found error when TMDS ratio is 1/40 */ + if (InstancePtr->HdmiRxTmdsClockRatio) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_GT_CPLL_CFG_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + } + else { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_NO_DRU, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + } + return (XST_FAILURE); + } + } + } + + /* Try different sample rates. */ + for (SRIndex = 0; SRIndex < sizeof(SRArray); SRIndex++) { + /* Only use oversampling when then TX is using the CPLL. */ + if (Dir == XHDMIPHY1_DIR_TX) { + SRValue = SRArray[SRIndex]; + + if (InstancePtr->TxHdmi21Cfg.IsEnabled == 0) { + /* Multiply the reference clock with the sample rate + * value. */ + RefClk = ((*RefClkPtr) * SRValue); + + /* Calculate scaled line rate. */ + if (TxLineRate >= 3400) { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + ChannelId, (RefClk * 40)); + } + else { + XHdmiphy1_CfgLineRate(InstancePtr, QuadId, + ChannelId, (RefClk * 10)); + } + } + else { /* InstancePtr->TxHdmi21Cfg.IsEnabled == 1 */ + RefClk = (*RefClkPtr); + } + } + /* For all other reference clocks force sample rate to one. */ + else { + SRValue = 1; + } + + Status = XHdmiphy1_ClkCalcParams(InstancePtr, QuadId, + ChannelId, Dir, RefClk); + if (Status == (XST_SUCCESS)) { + /* Only execute when the TX is using the QPLL. */ + if (Dir == XHDMIPHY1_DIR_TX) { + InstancePtr->HdmiTxSampleRate = SRValue; + (*RefClkPtr) = (*RefClkPtr) * SRValue; + } + + /* Check Userclock Frequency */ + /* (300 MHz + 0.5%) + 10 KHz (Clkdet accuracy) */ + if (301500000 < (XHdmiphy1_GetLineRateHz(InstancePtr, QuadId, + XHDMIPHY1_CHANNEL_ID_CH1) / + (InstancePtr->Config.TransceiverWidth * 10))) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_USRCLK_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); + } + + return (XST_SUCCESS); + } + } + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_GT_CPLL_CFG_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + return (XST_FAILURE); +} +#endif + +/*****************************************************************************/ +/** +* This function update/set the HDMI TX parameter. +* +* @param InstancePtr is a pointer to the Hdmiphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Ppc is the pixels per clock to set. +* @param Bpc is the bits per color to set. +* @param ColorFormat is the color format to set. +* +* @return +* - XST_SUCCESS if TX parameters set/updated. +* - XST_FAILURE if low resolution video not supported. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_SetHdmiTxParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, + XVidC_PixelsPerClock Ppc, XVidC_ColorDepth Bpc, + XVidC_ColorFormat ColorFormat) +{ + u32 Status; + + /* Verify arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid((Ppc == (XVIDC_PPC_1)) || (Ppc == (XVIDC_PPC_2)) || + (Ppc == (XVIDC_PPC_4))); + Xil_AssertNonvoid((Bpc == (XVIDC_BPC_8)) || (Bpc == (XVIDC_BPC_10)) || + (Bpc == (XVIDC_BPC_12)) || (Bpc == (XVIDC_BPC_16))); + Xil_AssertNonvoid((ColorFormat == (XVIDC_CSF_RGB)) || + (ColorFormat == (XVIDC_CSF_YCRCB_444)) || + (ColorFormat == (XVIDC_CSF_YCRCB_422)) || + (ColorFormat == (XVIDC_CSF_YCRCB_420))); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + /* Only calculate the QPLL/CPLL parameters when the GT TX and RX are not + * coupled. */ + if (XHdmiphy1_IsTxUsingCpll(InstancePtr, QuadId, ChId)) { + Status = XHdmiphy1_HdmiCpllParam(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_TX); + } + else { + Status = XHdmiphy1_HdmiQpllParam(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_TX); + /* Update SysClk and PLL Clk registers immediately. */ + XHdmiphy1_WriteCfgRefClkSelReg(InstancePtr, QuadId); + } +#else + Status = XHdmiphy1_HdmiTxPllParam(InstancePtr, QuadId, ChId); +#endif + + if (Status == XST_FAILURE) { + return Status; + } + + /* Is HDMITXSS PPC match with HDMIPHY PPC? */ + if (Ppc == InstancePtr->Config.Ppc) { + Status = (XST_SUCCESS); + } + else { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_PPC_MSMTCH_ERR, 1); + XHdmiphy1_ErrorHandler(InstancePtr); + Status = (XST_FAILURE); + } + if (Status == (XST_SUCCESS)) { + /* HDMI 2.1 */ + if (InstancePtr->TxHdmi21Cfg.IsEnabled) { + InstancePtr->Quads[QuadId].TxMmcm.ClkFbOutMult = + XHDMIPHY1_FRL_VIDCLK_MMCM_FBOUTMULT; + InstancePtr->Quads[QuadId].TxMmcm.DivClkDivide = + XHDMIPHY1_FRL_VIDCLK_MMCM_DIVCLK; + InstancePtr->Quads[QuadId].TxMmcm.ClkOut0Div = + XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT0DIV; + InstancePtr->Quads[QuadId].TxMmcm.ClkOut1Div = + XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT1DIV; + InstancePtr->Quads[QuadId].TxMmcm.ClkOut2Div = + XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT2DIV; + return Status; + } + + /* Calculate TXPLL parameters. + * In HDMI the colordepth in YUV422 is always 12 bits, + * although on the link itself it is being transmitted as + * 8-bits. Therefore if the colorspace is YUV422, then force the + * colordepth to 8 bits. */ + if (ColorFormat == XVIDC_CSF_YCRCB_422) { + Status = XHdmiphy1_HdmiCfgCalcMmcmParam(InstancePtr, QuadId, + ChId, XHDMIPHY1_DIR_TX, Ppc, XVIDC_BPC_8); + } + /* Other colorspaces. */ + else { + Status = XHdmiphy1_HdmiCfgCalcMmcmParam(InstancePtr, QuadId, + ChId, XHDMIPHY1_DIR_TX, Ppc, Bpc); + } + } + else { + Status = (XST_FAILURE); + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function update/set the HDMI RX parameter. +* +* @param InstancePtr is a pointer to the Hdmiphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - XST_SUCCESS if RX parameters set/updated. +* - XST_FAILURE if low resolution video not supported. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_SetHdmiRxParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + XHdmiphy1_ChannelId ChanId = ChId; + XHdmiphy1_PllType PllType; + u32 Status; + u64 DruCenterFreq; + + /* Verify arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + if (XHdmiphy1_IsRxUsingCpll(InstancePtr, QuadId, ChId)) { + Status = XHdmiphy1_HdmiCpllParam(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_RX); + } + else { + Status = XHdmiphy1_HdmiQpllParam(InstancePtr, QuadId, ChId, + XHDMIPHY1_DIR_RX); + /* Update SysClk and PLL Clk registers immediately */ + XHdmiphy1_WriteCfgRefClkSelReg(InstancePtr, QuadId); + } +#else + Status = XHdmiphy1_HdmiRxPllParam(InstancePtr, QuadId, ChId); +#endif + + if (InstancePtr->HdmiRxDruIsEnabled) { + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + /* Update the ChId */ + ChanId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, + XHDMIPHY1_DIR_RX, PllType); + + DruCenterFreq = XHdmiphy1_DruCalcCenterFreqHz(InstancePtr, QuadId, + ChanId); + XHdmiphy1_DruSetCenterFreqHz(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, + DruCenterFreq); + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function enables or disables the Pattern Generator for the GT Channel 4 +* when it isused to generate the TX TMDS Clock. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Enable TRUE/FALSE +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_PatgenEnable(XHdmiphy1 *InstancePtr, u8 QuadId, u8 Enable) +{ + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_PATGEN_CTRL_REG); + + if (Enable) { + RegVal |= XHDMIPHY1_PATGEN_CTRL_ENABLE_MASK; + } + else { + RegVal &= ~XHDMIPHY1_PATGEN_CTRL_ENABLE_MASK; + } + + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_PATGEN_CTRL_REG, RegVal); +} + +/*****************************************************************************/ +/** +* This function sets the Pattern Generator for the GT Channel 4 when it is +* used to generate the TX TMDS Clock. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param TxLineRate in Mbps. +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_PatgenSetRatio(XHdmiphy1 *InstancePtr, u8 QuadId, + u64 TxLineRate) +{ + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + RegVal = (XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_PATGEN_CTRL_REG) + & ~XHDMIPHY1_PATGEN_CTRL_RATIO_MASK); + + if ((TxLineRate >= 3400) && (InstancePtr->HdmiTxSampleRate == 1)) { + RegVal |= XHDMIPHY1_Patgen_Ratio_40 & + XHDMIPHY1_PATGEN_CTRL_RATIO_MASK; + } + else { + RegVal |= InstancePtr->HdmiTxSampleRate & + XHDMIPHY1_PATGEN_CTRL_RATIO_MASK; + } + + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_PATGEN_CTRL_REG, RegVal); +} + +/*****************************************************************************/ +/** +* This function will configure the HDMIPHY to HDMI 2.0 mode +* +* @param InstancePtr is a pointer to the Hdmiphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if TX parameters set/updated. +* - XST_FAILURE if low resolution video not supported. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_Hdmi20Config(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir) +{ + XHdmiphy1_PllType PllType; + u32 Status = XST_SUCCESS; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_TMDS_RECONFIG, Dir); + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, Dir, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* Update HDMI Configurations */ + if (Dir == XHDMIPHY1_DIR_TX) { + InstancePtr->TxHdmi21Cfg.LineRate = 0; + InstancePtr->TxHdmi21Cfg.NChannels = 0; + InstancePtr->TxHdmi21Cfg.IsEnabled = FALSE; + } else { + InstancePtr->RxHdmi21Cfg.LineRate = 0; + InstancePtr->RxHdmi21Cfg.NChannels = 0; + InstancePtr->RxHdmi21Cfg.IsEnabled = FALSE; + } + + XHdmiphy1_MmcmSetClkinsel(InstancePtr, QuadId, Dir, + XHDMIPHY1_MMCM_CLKINSEL_CLKIN1); + + /* Disable Clock Detector Interrupts */ + if (Dir == XHDMIPHY1_DIR_TX) { + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE); + } else { + XHdmiphy1_IntrEnable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE); + } + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + /* Update reference clock election. */ + XHdmiphy1_CfgPllRefClkSel(InstancePtr, 0, + ((PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_CHANNEL_ID_CHA : XHDMIPHY1_CHANNEL_ID_CMNA), + ((Dir == XHDMIPHY1_DIR_TX) ? + InstancePtr->Config.TxRefClkSel : + InstancePtr->Config.RxRefClkSel)); + + /* Update RefClk selection. */ + XHdmiphy1_WriteCfgRefClkSelReg(InstancePtr, 0); +#else + /* Suppress Warning Messages */ + PllType = PllType; +#endif + + return Status; +} + +/*****************************************************************************/ +/** +* This function will configure the GT for HDMI 2.1 operation +* +* @param InstancePtr is a pointer to the Hdmiphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if TX parameters set/updated. +* - XST_FAILURE if low resolution video not supported. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_Hdmi21Config(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u64 LineRate, u8 NChannels) +{ + XHdmiphy1_PllType PllType; + u32 Status = XST_SUCCESS; + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) || \ + (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) + char SpeedGrade[5] = XPAR_HDMIPHY1_0_SPEEDGRADE_STR; + char CompVal[5] = "-1"; + char *SpeedGradePtr = &SpeedGrade[0]; + char *CompValPtr = &CompVal[0]; + + /* Look for -1 Parts. Max Line rate is 8Gbps */ + if (strncmp(SpeedGradePtr, CompValPtr, 2) == 0) { + if (LineRate > 8e9) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_SPDGRDE_ERR, Dir); + XHdmiphy1_ErrorHandler(InstancePtr); + return XST_FAILURE; + } + } +#endif + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_FRL_RECONFIG, Dir); + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, Dir, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* Disable Clock Detector Interrupts */ + if (Dir == XHDMIPHY1_DIR_TX) { + if (InstancePtr->Config.TxRefClkSel != + InstancePtr->Config.TxFrlRefClkSel) { + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE); + } + /* Enable 4th Channel output */ + XHdmiphy1_Clkout1OBufTdsEnable(InstancePtr, XHDMIPHY1_DIR_TX, (TRUE)); + } else { + if (InstancePtr->Config.RxRefClkSel != + InstancePtr->Config.RxFrlRefClkSel) { + XHdmiphy1_IntrDisable(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE); + } + } + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + /* Update reference clock election. */ + XHdmiphy1_CfgPllRefClkSel(InstancePtr, 0, + ((PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_CHANNEL_ID_CHA : XHDMIPHY1_CHANNEL_ID_CMNA), + ((Dir == XHDMIPHY1_DIR_TX) ? + InstancePtr->Config.TxFrlRefClkSel : + InstancePtr->Config.RxFrlRefClkSel)); + + /* Update RefClk selection. */ + XHdmiphy1_WriteCfgRefClkSelReg(InstancePtr, 0); +#endif + + /* Update HDMI Configurations */ + if (Dir == XHDMIPHY1_DIR_TX) { + InstancePtr->HdmiTxRefClkHz = XHDMIPHY1_HDMI21_FRL_REFCLK; + InstancePtr->TxHdmi21Cfg.LineRate = LineRate; + InstancePtr->TxHdmi21Cfg.NChannels = NChannels; + InstancePtr->TxHdmi21Cfg.IsEnabled = TRUE; + + Status = XHdmiphy1_SetHdmiTxParam(InstancePtr, 0, + ((PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_CHANNEL_ID_CHA : XHDMIPHY1_CHANNEL_ID_CMNA), + InstancePtr->Config.Ppc, + XVIDC_BPC_8, + XVIDC_CSF_RGB); + + /* Mask the MMCM Lock */ + XHdmiphy1_MmcmLockedMaskEnable(InstancePtr, 0, Dir, TRUE); + + if (InstancePtr->Config.TxRefClkSel == + InstancePtr->Config.TxFrlRefClkSel) { + XHdmiphy1_MmcmSetClkinsel(InstancePtr, QuadId, Dir, + XHDMIPHY1_MMCM_CLKINSEL_CLKIN1); + } else { + XHdmiphy1_MmcmSetClkinsel(InstancePtr, QuadId, Dir, + XHDMIPHY1_MMCM_CLKINSEL_CLKIN2); + } + if (InstancePtr->Config.TxRefClkSel != + InstancePtr->Config.TxFrlRefClkSel) { + XHdmiphy1_HdmiTxTimerTimeoutHandler(InstancePtr); + } + } else { + InstancePtr->HdmiRxRefClkHz = XHDMIPHY1_HDMI21_FRL_REFCLK; + InstancePtr->RxHdmi21Cfg.LineRate = LineRate; + InstancePtr->RxHdmi21Cfg.NChannels = NChannels; + InstancePtr->RxHdmi21Cfg.IsEnabled = TRUE; + + /* Set MMCM dividers for FRL mode */ + InstancePtr->Quads[QuadId].RxMmcm.ClkFbOutMult = + XHDMIPHY1_FRL_VIDCLK_MMCM_FBOUTMULT; + InstancePtr->Quads[QuadId].RxMmcm.DivClkDivide = + XHDMIPHY1_FRL_VIDCLK_MMCM_DIVCLK; + InstancePtr->Quads[QuadId].RxMmcm.ClkOut0Div = + XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT0DIV; + InstancePtr->Quads[QuadId].RxMmcm.ClkOut1Div = + XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT1DIV; + InstancePtr->Quads[QuadId].RxMmcm.ClkOut2Div = + XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT2DIV; + + /* Mask the MMCM Lock */ + XHdmiphy1_MmcmLockedMaskEnable(InstancePtr, 0, Dir, TRUE); + + if (InstancePtr->Config.RxRefClkSel != + InstancePtr->Config.RxFrlRefClkSel) { + /* Set MMCM CLKINSEL to CLK2 */ + XHdmiphy1_MmcmSetClkinsel(InstancePtr, QuadId, Dir, + XHDMIPHY1_MMCM_CLKINSEL_CLKIN2); + + /* Start RX MMCM. */ + XHdmiphy1_MmcmStart(InstancePtr, 0, XHDMIPHY1_DIR_RX); + + XHdmiphy1_HdmiRxTimerTimeoutHandler(InstancePtr); + } + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function prints Video PHY debug information related to HDMI. +* +* @param InstancePtr is a pointer to the Hdmiphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param buff Buffer to print to +* @param buff_size Maximum size of buff +* +* @return Number of characters printed in buff. +* +* @note None. +* +******************************************************************************/ + +int XHdmiphy1_HdmiDebugInfo(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, char *buff, int buff_size) +{ + int strSize = 0; + u32 RegValue; +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_Channel *ChPtr; + XHdmiphy1_ChannelId CmnId = XHDMIPHY1_CHANNEL_ID_CMN0; + u8 CpllDVal; + u8 QpllDVal; + u8 UsesQpll0 = 0; + + ChPtr = &InstancePtr->Quads[QuadId].Plls[0]; + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) { + if (XHdmiphy1_IsTxUsingCpll(InstancePtr, QuadId, ChId)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX: CPLL\n"); + } + else { + if ((ChPtr->TxDataRefClkSel == + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL_OUTCLK) || + (ChPtr->TxDataRefClkSel == + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK)) { + UsesQpll0 = (TRUE); + CmnId = XHDMIPHY1_CHANNEL_ID_CMN0; + } + else { + UsesQpll0 = (FALSE); + CmnId = XHDMIPHY1_CHANNEL_ID_CMN1; + } + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX: QPLL%d\n", (UsesQpll0 ? 0 : 1)); + } + } + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)) { + if (XHdmiphy1_IsRxUsingCpll(InstancePtr, QuadId, ChId)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX: CPLL\n"); + } + else { + if ((ChPtr->RxDataRefClkSel == + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL_OUTCLK) || + (ChPtr->RxDataRefClkSel == + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK)) { + UsesQpll0 = (TRUE); + CmnId = XHDMIPHY1_CHANNEL_ID_CMN0; + } + else { + UsesQpll0 = (FALSE); + CmnId = XHDMIPHY1_CHANNEL_ID_CMN1; + } + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX: QPLL%d\n", (UsesQpll0 ? 0 : 1)); + } + } + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX state: "); + switch (InstancePtr->Quads[QuadId]. + Plls[XHDMIPHY1_CH2IDX(ChId)].TxState) { + case (XHDMIPHY1_GT_STATE_IDLE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "idle\n"); + break; + case (XHDMIPHY1_GT_STATE_LOCK): + if (XHdmiphy1_IsTxUsingCpll(InstancePtr, QuadId, ChId)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL lock\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL%d lock\n", (UsesQpll0 ? 0 : 1)); + } + break; + case (XHDMIPHY1_GT_STATE_RESET): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT reset\n"); + break; + case (XHDMIPHY1_GT_STATE_ALIGN): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "align\n"); + break; + case (XHDMIPHY1_GT_STATE_READY): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "ready\n"); + break; + default: + strSize += scnprintf(buff+strSize, buff_size-strSize, + "unknown\n"); + break; + } + } + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX state: "); + switch (InstancePtr->Quads[QuadId]. + Plls[XHDMIPHY1_CH2IDX(ChId)].RxState) { + case (XHDMIPHY1_GT_STATE_IDLE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "idle\n"); + break; + case (XHDMIPHY1_GT_STATE_LOCK): + if (XHdmiphy1_IsRxUsingCpll(InstancePtr, QuadId, ChId)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL lock\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL%d lock\n", (UsesQpll0 ? 0 : 1)); + } + break; + case (XHDMIPHY1_GT_STATE_RESET): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT reset\n"); + break; + case (XHDMIPHY1_GT_STATE_READY): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "ready\n"); + break; + default: + strSize += scnprintf(buff+strSize, buff_size-strSize, + "unknown\n"); + break; + } + } + + if (XHdmiphy1_IsTxUsingCpll(InstancePtr, QuadId, ChId)) { + QpllDVal = ChPtr->RxOutDiv; + CpllDVal = ChPtr->TxOutDiv; + } + else { + CpllDVal = ChPtr->RxOutDiv; + QpllDVal = ChPtr->TxOutDiv; + } + + strSize += scnprintf(buff+strSize, buff_size-strSize, "\n"); + if ((XHdmiphy1_IsTxUsingQpll(InstancePtr, QuadId, ChId) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX))) || + (XHdmiphy1_IsRxUsingQpll(InstancePtr, QuadId, ChId) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)))) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL%d settings\n", (UsesQpll0 ? 0 : 1)); + strSize += scnprintf(buff+strSize, buff_size-strSize, + "-------------\n" \ + "M : %d - N : %d - D : %d\n\n", + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(CmnId)]. + PllParams.MRefClkDiv, + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(CmnId)]. + PllParams.NFbDiv, QpllDVal); + } + + if ((XHdmiphy1_IsTxUsingCpll(InstancePtr, QuadId, ChId) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX))) || + (XHdmiphy1_IsRxUsingCpll(InstancePtr, QuadId, ChId) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)))) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL settings\n" \ + "-------------\n" \ + "M : %d - N1 : %d - N2 : %d - D : %d\n\n", + ChPtr->PllParams.MRefClkDiv, + ChPtr->PllParams.N1FbDiv, ChPtr->PllParams.N2FbDiv, + CpllDVal); + } +#else + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) { + if (XHdmiphy1_IsTxUsingLcpll(InstancePtr, QuadId, ChId)) { + xil_printf("TX: LCPLL\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX: RPLL\n"); + } + } + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)) { + if (XHdmiphy1_IsRxUsingLcpll(InstancePtr, QuadId, ChId)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX: LCPLL\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX: RPLL\n"); + } + } + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX state: "); + switch (InstancePtr->Quads[QuadId]. + Plls[XHDMIPHY1_CH2IDX(ChId)].TxState) { + case (XHDMIPHY1_GT_STATE_IDLE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "idle\n"); + break; + case (XHDMIPHY1_GT_STATE_GPO_RE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GPO Assert\n"); + break; + case (XHDMIPHY1_GT_STATE_LOCK): + if (XHdmiphy1_IsTxUsingLcpll(InstancePtr, QuadId, ChId)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "LCPLL lock\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RPLL lock\n"); + } + break; + case (XHDMIPHY1_GT_STATE_RESET): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT reset\n"); + break; + case (XHDMIPHY1_GT_STATE_ALIGN): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "align\n"); + break; + case (XHDMIPHY1_GT_STATE_READY): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "ready\n"); + break; + default: + strSize += scnprintf(buff+strSize, buff_size-strSize, + "unknown\n"); + break; + } + } + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)) { + xil_printf("RX state: "); + switch (InstancePtr->Quads[QuadId]. + Plls[XHDMIPHY1_CH2IDX(ChId)].RxState) { + case (XHDMIPHY1_GT_STATE_IDLE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "idle\n"); + break; + case (XHDMIPHY1_GT_STATE_GPO_RE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GPO Assert\n"); + break; + case (XHDMIPHY1_GT_STATE_LOCK): + if (XHdmiphy1_IsRxUsingLcpll(InstancePtr, QuadId, ChId)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "LCPLL lock\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RPLL lock\n"); + } + break; + case (XHDMIPHY1_GT_STATE_RESET): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT reset\n"); + break; + case (XHDMIPHY1_GT_STATE_READY): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "ready\n"); + break; + default: + strSize += scnprintf(buff+strSize, buff_size-strSize, + "unknown\n"); + break; + } + } + + strSize += scnprintf(buff+strSize, buff_size-strSize, "\n"); + if ((XHdmiphy1_IsTxUsingLcpll(InstancePtr, QuadId, ChId) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX))) || + (XHdmiphy1_IsRxUsingLcpll(InstancePtr, QuadId, ChId) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)))) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "LCPLL settings\n" \ + "-------------\n" \ + "LR CFG : %d\n", + InstancePtr->Quads[QuadId].Lcpll.LineRateCfg); + strSize += scnprintf(buff+strSize, buff_size-strSize, "\n"); + } + + if ((XHdmiphy1_IsTxUsingRpll(InstancePtr, QuadId, ChId) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX))) || + (XHdmiphy1_IsRxUsingRpll(InstancePtr, QuadId, ChId) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)))) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RPLL settings\n" \ + "-------------\n" \ + "LR CFG : %d\n", + InstancePtr->Quads[QuadId].Rpll.LineRateCfg); + strSize += scnprintf(buff+strSize, buff_size-strSize, "\n"); + } +#endif + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX MMCM settings\n" + "-------------\n" + "Mult : %d - Div : %d - Clk0Div : %d - Clk1Div : %d - " + "Clk2Div : %d\n\n", + InstancePtr->Quads[QuadId].RxMmcm.ClkFbOutMult, + InstancePtr->Quads[QuadId].RxMmcm.DivClkDivide, + InstancePtr->Quads[QuadId].RxMmcm.ClkOut0Div, + InstancePtr->Quads[QuadId].RxMmcm.ClkOut1Div, + InstancePtr->Quads[QuadId].RxMmcm.ClkOut2Div); + } + + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX MMCM settings\n" \ + "-------------\n" \ + "Mult : %d - Div : %d - Clk0Div : %d - Clk1Div : %d - " + "Clk2Div : %d\n\n", + InstancePtr->Quads[QuadId].TxMmcm.ClkFbOutMult, + InstancePtr->Quads[QuadId].TxMmcm.DivClkDivide, + InstancePtr->Quads[QuadId].TxMmcm.ClkOut0Div, + InstancePtr->Quads[QuadId].TxMmcm.ClkOut1Div, + InstancePtr->Quads[QuadId].TxMmcm.ClkOut2Div); + } + + if ((InstancePtr->Config.DruIsPresent) && + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX))) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "DRU Settings\n" \ + "-------------\n"); + RegValue = XHdmiphy1_DruGetVersion(InstancePtr); + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Version : %d\n", RegValue); + + if (InstancePtr->HdmiRxDruIsEnabled) { + RegValue = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_DRU_GAIN_REG(ChId)); + + + strSize += scnprintf(buff+strSize, buff_size-strSize, + "G1 : %d\nG1_P : %d\n" + "G2 : %d\n", + ((RegValue & XHDMIPHY1_DRU_GAIN_G1_MASK)), + ((RegValue & XHDMIPHY1_DRU_GAIN_G1_P_MASK) >> + XHDMIPHY1_DRU_GAIN_G1_P_SHIFT), + ((RegValue & XHDMIPHY1_DRU_GAIN_G2_MASK) >> + XHDMIPHY1_DRU_GAIN_G2_SHIFT)); + + + RegValue = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_DRU_CFREQ_H_REG(ChId)); + + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Center_F : %x", RegValue); + + RegValue = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_DRU_CFREQ_L_REG(ChId)); + + strSize += scnprintf(buff+strSize, buff_size-strSize, + "%x\n", RegValue); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "DRU is disabled\n"); + } + + strSize += scnprintf(buff+strSize, buff_size-strSize," \n"); + } + return strSize; +} + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE3) +static const XHdmiphy1_GtHdmiChars Gthe3HdmiChars = { + .DruLineRate = XHDMIPHY1_HDMI_GTHE3_DRU_LRATE, + .PllScale = XHDMIPHY1_HDMI_GTHE3_PLL_SCALE, + .Qpll0RefClkMin = XHDMIPHY1_HDMI_GTHE3_QPLL0_REFCLK_MIN, + .Qpll1RefClkMin = XHDMIPHY1_HDMI_GTHE3_QPLL1_REFCLK_MIN, + .CpllRefClkMin = XHDMIPHY1_HDMI_GTHE3_CPLL_REFCLK_MIN, + .TxMmcmScale = XHDMIPHY1_HDMI_GTHE3_TX_MMCM_SCALE, + .TxMmcmFvcoMin = XHDMIPHY1_HDMI_GTHE3_TX_MMCM_FVCO_MIN, + .TxMmcmFvcoMax = XHDMIPHY1_HDMI_GTHE3_TX_MMCM_FVCO_MAX, + .RxMmcmScale = XHDMIPHY1_HDMI_GTHE3_RX_MMCM_SCALE, + .RxMmcmFvcoMin = XHDMIPHY1_HDMI_GTHE3_RX_MMCM_FVCO_MIN, + .RxMmcmFvcoMax = XHDMIPHY1_HDMI_GTHE3_RX_MMCM_FVCO_MAX, +}; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) +static const XHdmiphy1_GtHdmiChars Gthe4HdmiChars = { + .DruLineRate = XHDMIPHY1_HDMI_GTHE4_DRU_LRATE, + .PllScale = XHDMIPHY1_HDMI_GTHE4_PLL_SCALE, + .Qpll0RefClkMin = XHDMIPHY1_HDMI_GTHE4_QPLL0_REFCLK_MIN, + .Qpll1RefClkMin = XHDMIPHY1_HDMI_GTHE4_QPLL1_REFCLK_MIN, + .CpllRefClkMin = XHDMIPHY1_HDMI_GTHE4_CPLL_REFCLK_MIN, + .TxMmcmScale = XHDMIPHY1_HDMI_GTHE4_TX_MMCM_SCALE, + .TxMmcmFvcoMin = XHDMIPHY1_HDMI_GTHE4_TX_MMCM_FVCO_MIN, + .TxMmcmFvcoMax = XHDMIPHY1_HDMI_GTHE4_TX_MMCM_FVCO_MAX, + .RxMmcmScale = XHDMIPHY1_HDMI_GTHE4_RX_MMCM_SCALE, + .RxMmcmFvcoMin = XHDMIPHY1_HDMI_GTHE4_RX_MMCM_FVCO_MIN, + .RxMmcmFvcoMax = XHDMIPHY1_HDMI_GTHE4_RX_MMCM_FVCO_MAX, +}; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) +static const XHdmiphy1_GtHdmiChars Gtye4HdmiChars = { + .DruLineRate = XHDMIPHY1_HDMI_GTYE4_DRU_LRATE, + .PllScale = XHDMIPHY1_HDMI_GTYE4_PLL_SCALE, + .Qpll0RefClkMin = XHDMIPHY1_HDMI_GTYE4_QPLL0_REFCLK_MIN, + .Qpll1RefClkMin = XHDMIPHY1_HDMI_GTYE4_QPLL1_REFCLK_MIN, + .CpllRefClkMin = XHDMIPHY1_HDMI_GTYE4_CPLL_REFCLK_MIN, + .TxMmcmScale = XHDMIPHY1_HDMI_GTYE4_TX_MMCM_SCALE, + .TxMmcmFvcoMin = XHDMIPHY1_HDMI_GTYE4_TX_MMCM_FVCO_MIN, + .TxMmcmFvcoMax = XHDMIPHY1_HDMI_GTYE4_TX_MMCM_FVCO_MAX, + .RxMmcmScale = XHDMIPHY1_HDMI_GTYE4_RX_MMCM_SCALE, + .RxMmcmFvcoMin = XHDMIPHY1_HDMI_GTYE4_RX_MMCM_FVCO_MIN, + .RxMmcmFvcoMax = XHDMIPHY1_HDMI_GTYE4_RX_MMCM_FVCO_MAX, +}; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) +static const XHdmiphy1_GtHdmiChars Gtye5HdmiChars = { + .DruLineRate = XHDMIPHY1_HDMI_GTYE5_DRU_LRATE, + .PllScale = XHDMIPHY1_HDMI_GTYE5_PLL_SCALE, + .Qpll0RefClkMin = XHDMIPHY1_HDMI_GTYE5_LCPLL_REFCLK_MIN, + .Qpll1RefClkMin = XHDMIPHY1_HDMI_GTYE5_RPLL_REFCLK_MIN, + .CpllRefClkMin = 0, + .TxMmcmScale = XHDMIPHY1_HDMI_GTYE5_TX_MMCM_SCALE, + .TxMmcmFvcoMin = XHDMIPHY1_HDMI_GTYE5_TX_MMCM_FVCO_MIN, + .TxMmcmFvcoMax = XHDMIPHY1_HDMI_GTYE5_TX_MMCM_FVCO_MAX, + .RxMmcmScale = XHDMIPHY1_HDMI_GTYE5_RX_MMCM_SCALE, + .RxMmcmFvcoMin = XHDMIPHY1_HDMI_GTYE5_RX_MMCM_FVCO_MIN, + .RxMmcmFvcoMax = XHDMIPHY1_HDMI_GTYE5_RX_MMCM_FVCO_MAX, +}; +#endif + +/*****************************************************************************/ +/** +* This function returns a pointer to the HDMI parameters based on the GT type. +* +* @param InstancePtr is a pointer to the Hdmiphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - A pointer to the HDMI GT characteristics. +* - NULL if the GT type is unsupported. +* +* @note None. +* +******************************************************************************/ +static const XHdmiphy1_GtHdmiChars *GetGtHdmiPtr(XHdmiphy1 *InstancePtr) +{ + /* Suppress Warning Messages */ + InstancePtr = InstancePtr; + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE3) + return &Gthe3HdmiChars; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) + return &Gthe4HdmiChars; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE4) + return &Gtye4HdmiChars; +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) + return &Gtye5HdmiChars; +#endif + + return NULL; +} diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi.h b/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi.h new file mode 100644 index 0000000..3cfce89 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi.h @@ -0,0 +1,199 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_hdmi.h + * + * The Xilinx HDMI PHY (HDMIPHY) driver. This driver supports the + * Xilinx HDMI PHY IP core. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * + * @addtogroup xhdmiphy1_v1_0 + * @{ +*******************************************************************************/ + +#ifndef XHDMIPHY1_HDMI_H_ +/* Prevent circular inclusions by using protection macros. */ +#define XHDMIPHY1_HDMI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/************************** Constant Definitions ******************************/ + +#define XHDMIPHY1_HDMI_GTYE5_DRU_LRATE 2500000000U +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK 200000000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK_MIN 199990000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK_MAX 200010000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK1 125000000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK1_MIN 124990000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK1_MAX 125010000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK2 400000000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK2_MIN 399990000LL +#define XHDMIPHY1_HDMI_GTYE5_DRU_REFCLK2_MAX 400010000LL +#define XHDMIPHY1_HDMI_GTYE5_PLL_SCALE 1000 +#define XHDMIPHY1_HDMI_GTYE5_LCPLL_REFCLK_MIN 120000000LL +#define XHDMIPHY1_HDMI_GTYE5_RPLL_REFCLK_MIN 120000000LL +#define XHDMIPHY1_HDMI_GTYE5_TX_MMCM_SCALE 1 +#define XHDMIPHY1_HDMI_GTYE5_TX_MMCM_FVCO_MIN 2160000000U +#define XHDMIPHY1_HDMI_GTYE5_TX_MMCM_FVCO_MAX 4320000000U +#define XHDMIPHY1_HDMI_GTYE5_RX_MMCM_SCALE 1 +#define XHDMIPHY1_HDMI_GTYE5_RX_MMCM_FVCO_MIN 2160000000U +#define XHDMIPHY1_HDMI_GTYE5_RX_MMCM_FVCO_MAX 4320000000U + +#define XHDMIPHY1_HDMI_GTYE4_DRU_LRATE 2500000000U +#define XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK 156250000LL +#define XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK_MIN 156240000LL +#define XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK_MAX 156260000LL +#define XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK2 400000000LL +#define XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK2_MIN 399990000LL +#define XHDMIPHY1_HDMI_GTYE4_DRU_REFCLK2_MAX 400010000LL +#define XHDMIPHY1_HDMI_GTYE4_PLL_SCALE 1000 +#define XHDMIPHY1_HDMI_GTYE4_QPLL0_REFCLK_MIN 61250000LL +#define XHDMIPHY1_HDMI_GTYE4_QPLL1_REFCLK_MIN 50000000LL +#define XHDMIPHY1_HDMI_GTYE4_CPLL_REFCLK_MIN 50000000LL +#define XHDMIPHY1_HDMI_GTYE4_TX_MMCM_SCALE 1 +#define XHDMIPHY1_HDMI_GTYE4_TX_MMCM_FVCO_MIN 800000000U +#define XHDMIPHY1_HDMI_GTYE4_TX_MMCM_FVCO_MAX 1600000000U +#define XHDMIPHY1_HDMI_GTYE4_RX_MMCM_SCALE 1 +#define XHDMIPHY1_HDMI_GTYE4_RX_MMCM_FVCO_MIN 800000000U +#define XHDMIPHY1_HDMI_GTYE4_RX_MMCM_FVCO_MAX 1600000000U + +#define XHDMIPHY1_HDMI_GTHE4_DRU_LRATE 2500000000U +#define XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK 156250000LL +#define XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK_MIN 156240000LL +#define XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK_MAX 156260000LL +#define XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK2 400000000LL +#define XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK2_MIN 399980000LL +#define XHDMIPHY1_HDMI_GTHE4_DRU_REFCLK2_MAX 400020000LL +#define XHDMIPHY1_HDMI_GTHE4_PLL_SCALE 1000 +#define XHDMIPHY1_HDMI_GTHE4_QPLL0_REFCLK_MIN 61250000LL +#define XHDMIPHY1_HDMI_GTHE4_QPLL1_REFCLK_MIN 50000000LL +#define XHDMIPHY1_HDMI_GTHE4_CPLL_REFCLK_MIN 50000000LL +#define XHDMIPHY1_HDMI_GTHE4_TX_MMCM_SCALE 1 +#define XHDMIPHY1_HDMI_GTHE4_TX_MMCM_FVCO_MIN 800000000U +#define XHDMIPHY1_HDMI_GTHE4_TX_MMCM_FVCO_MAX 1600000000U +#define XHDMIPHY1_HDMI_GTHE4_RX_MMCM_SCALE 1 +#define XHDMIPHY1_HDMI_GTHE4_RX_MMCM_FVCO_MIN 800000000U +#define XHDMIPHY1_HDMI_GTHE4_RX_MMCM_FVCO_MAX 1600000000U + +#define XHDMIPHY1_HDMI_GTHE3_DRU_LRATE 2500000000U +#define XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK 156250000LL +#define XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK_MIN 156240000LL +#define XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK_MAX 156260000LL +#define XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK2 400000000LL +#define XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK2_MIN 399990000LL +#define XHDMIPHY1_HDMI_GTHE3_DRU_REFCLK2_MAX 400010000LL +#define XHDMIPHY1_HDMI_GTHE3_PLL_SCALE 1000 +#define XHDMIPHY1_HDMI_GTHE3_QPLL0_REFCLK_MIN 61250000LL +#define XHDMIPHY1_HDMI_GTHE3_QPLL1_REFCLK_MIN 50000000LL +#define XHDMIPHY1_HDMI_GTHE3_CPLL_REFCLK_MIN 50000000LL +#define XHDMIPHY1_HDMI_GTHE3_TX_MMCM_SCALE 1 +#define XHDMIPHY1_HDMI_GTHE3_TX_MMCM_FVCO_MIN 600000000U +#define XHDMIPHY1_HDMI_GTHE3_TX_MMCM_FVCO_MAX 1200000000U +#define XHDMIPHY1_HDMI_GTHE3_RX_MMCM_SCALE 1 +#define XHDMIPHY1_HDMI_GTHE3_RX_MMCM_FVCO_MIN 600000000U +#define XHDMIPHY1_HDMI_GTHE3_RX_MMCM_FVCO_MAX 1200000000U + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE3) +#define XHDMIPHY1_FRL_VIDCLK_MMCM_FBOUTMULT 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_DIVCLK 1 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT0DIV 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT1DIV 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT2DIV 4 +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTHE4) +#define XHDMIPHY1_FRL_VIDCLK_MMCM_FBOUTMULT 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_DIVCLK 1 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT0DIV 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT1DIV 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT2DIV 3 +#elif (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) +#define XHDMIPHY1_FRL_VIDCLK_MMCM_FBOUTMULT 6 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_DIVCLK 1 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT0DIV 6 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT1DIV 6 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT2DIV 6 +#else +#define XHDMIPHY1_FRL_VIDCLK_MMCM_FBOUTMULT 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_DIVCLK 1 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT0DIV 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT1DIV 3 +#define XHDMIPHY1_FRL_VIDCLK_MMCM_CLKOUT2DIV 3 +#endif + +#define XHDMIPHY1_HDMI21_FRL_REFCLK 400000000U + +/**************************** Function Prototypes *****************************/ + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +u32 XHdmiphy1_HdmiQpllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +u32 XHdmiphy1_HdmiCpllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +void XHdmiphy1_TxAlignReset(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 Reset); +void XHdmiphy1_TxAlignStart(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 Start); +#else +u32 XHdmiphy1_HdmiTxPllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +u32 XHdmiphy1_HdmiRxPllParam(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +#endif +void XHdmiphy1_ClkDetEnable(XHdmiphy1 *InstancePtr, u8 Enable); +void XHdmiphy1_ClkDetTimerClear(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir); +void XHdmiphy1_ClkDetSetFreqLockThreshold(XHdmiphy1 *InstancePtr, + u16 ThresholdVal); +u8 XHdmiphy1_ClkDetCheckFreqZero(XHdmiphy1 *InstancePtr, + XHdmiphy1_DirectionType Dir); +void XHdmiphy1_ClkDetSetFreqTimeout(XHdmiphy1 *InstancePtr, u32 TimeoutVal); +void XHdmiphy1_ClkDetTimerLoad(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u32 TimeoutVal); +void XHdmiphy1_DruReset(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 Reset); +void XHdmiphy1_DruEnable(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 Enable); +u16 XHdmiphy1_DruGetVersion(XHdmiphy1 *InstancePtr); +void XHdmiphy1_DruSetCenterFreqHz(XHdmiphy1 *InstancePtr, + XHdmiphy1_ChannelId ChId, u64 CenterFreqHz); +u64 XHdmiphy1_DruCalcCenterFreqHz(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +void XHdmiphy1_HdmiGtDruModeEnable(XHdmiphy1 *InstancePtr, u8 Enable); +void XHdmiphy1_PatgenSetRatio(XHdmiphy1 *InstancePtr, + u8 QuadId, u64 TxLineRate); +void XHdmiphy1_PatgenEnable(XHdmiphy1 *InstancePtr, u8 QuadId, u8 Enable); +void XHdmiphy1_HdmiIntrHandlerCallbackInit(XHdmiphy1 *InstancePtr); + +#ifdef __cplusplus +} +#endif + +#endif /* XHDMIPHY1_HDMI_H_ */ +/** @} */ diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi_intr.c b/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi_intr.c new file mode 100644 index 0000000..6d5cbd3 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_hdmi_intr.c @@ -0,0 +1,1314 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_hdmi_intr.c + * + * This file contains video PHY functionality specific to the HDMI protocol + * related to interrupts. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include "xstatus.h" +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" +#include "xhdmiphy1_hdmi.h" +#include "xhdmiphy1_gt.h" + +/************************** Function Prototypes ******************************/ + +extern void XHdmiphy1_Ch2Ids(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 *Id0, u8 *Id1); + +static void XHdmiphy1_HdmiGtHandler(XHdmiphy1 *InstancePtr); +static void XHdmiphy1_ClkDetHandler(XHdmiphy1 *InstancePtr); + +/**************************** Function Definitions ****************************/ + +/******************************************************************************/ +/** +* This function installs an HDMI callback function for the specified handler +* type +* +* @param InstancePtr is a pointer to the XHdmiphy1 instance. +* @param HandlerType is the interrupt handler type which specifies which +* interrupt event to attach the callback for. +* @param CallbackFunc is the address to the callback function. +* @param CallbackRef is the user data item that will be passed to the +* callback function when it is invoked. +* +* @return None. +* +* @note None. +* +*******************************************************************************/ +void XHdmiphy1_SetHdmiCallback(XHdmiphy1 *InstancePtr, + XHdmiphy1_HdmiHandlerType HandlerType, + void *CallbackFunc, void *CallbackRef) +{ + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid((HandlerType == XHDMIPHY1_HDMI_HANDLER_TXINIT) || + (HandlerType == XHDMIPHY1_HDMI_HANDLER_TXREADY) || + (HandlerType == XHDMIPHY1_HDMI_HANDLER_RXINIT) || + (HandlerType == XHDMIPHY1_HDMI_HANDLER_RXREADY)); + Xil_AssertVoid(CallbackFunc != NULL); + Xil_AssertVoid(CallbackRef != NULL); + + switch (HandlerType) { + case XHDMIPHY1_HDMI_HANDLER_TXINIT: + InstancePtr->HdmiTxInitCallback = (XHdmiphy1_Callback)CallbackFunc; + InstancePtr->HdmiTxInitRef = CallbackRef; + break; + + case XHDMIPHY1_HDMI_HANDLER_TXREADY: + InstancePtr->HdmiTxReadyCallback = (XHdmiphy1_Callback)CallbackFunc; + InstancePtr->HdmiTxReadyRef = CallbackRef; + break; + + case XHDMIPHY1_HDMI_HANDLER_RXINIT: + InstancePtr->HdmiRxInitCallback = (XHdmiphy1_Callback)CallbackFunc; + InstancePtr->HdmiRxInitRef = CallbackRef; + break; + + case XHDMIPHY1_HDMI_HANDLER_RXREADY: + InstancePtr->HdmiRxReadyCallback = (XHdmiphy1_Callback)CallbackFunc; + InstancePtr->HdmiRxReadyRef = CallbackRef; + break; + + default: + break; + } +} + +/*****************************************************************************/ +/** +* This function sets the appropriate HDMI interupt handlers. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiIntrHandlerCallbackInit(XHdmiphy1 *InstancePtr) +{ + /* GT Interrupts */ + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TXRESET_DONE, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RXRESET_DONE, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_CPLL_LOCK, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL_LOCK, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TXALIGN_DONE, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_QPLL1_LOCK, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); +#else + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_LCPLL_LOCK, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RPLL_LOCK, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_GPO_RISING_EDGE, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_GPO_RISING_EDGE, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); +#endif + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE, + (XHdmiphy1_IntrHandler)XHdmiphy1_HdmiGtHandler, InstancePtr); + + /* Clock Detector Interrupts */ + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE, + (XHdmiphy1_IntrHandler)XHdmiphy1_ClkDetHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE, + (XHdmiphy1_IntrHandler)XHdmiphy1_ClkDetHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT, + (XHdmiphy1_IntrHandler)XHdmiphy1_ClkDetHandler, InstancePtr); + + XHdmiphy1_SetIntrHandler(InstancePtr, + XHDMIPHY1_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT, + (XHdmiphy1_IntrHandler)XHdmiphy1_ClkDetHandler, InstancePtr); +} + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) +/*****************************************************************************/ +/** +* This function is the handler for events triggered by TX GPO Rising Edge. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiTxGpoRisingEdgeHandler(XHdmiphy1 *InstancePtr) +{ + u8 Id, Id0, Id1; + u8 CfgValComp; + + /* Compare the current and next CFG values */ + CfgValComp = XHdmiphy1_CheckLineRateCfg(InstancePtr, 0, + XHDMIPHY1_CHANNEL_ID_CH1, + XHDMIPHY1_DIR_TX); + + if (CfgValComp) { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_TXGPO_RE, 0); + } else { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_TXGPO_RE, 1); + } + + /* De-assert GPI port. */ + XHdmiphy1_SetGpi(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, FALSE); + + /* Wait for GPO TX = 0 */ + while (XHdmiphy1_GetGpo(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX)); + + /* Start TX MMCM. */ + XHdmiphy1_MmcmStart(InstancePtr, 0, XHDMIPHY1_DIR_TX); + + /* Configure TXRATE Port */ + XHdmiphy1_DirReconfig(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX); + + /* Deassert reset on GT Reset IP TX */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_COMMON_INIT_REG, + (XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_COMMON_INIT_REG) & ~0x1)); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_LOCK; + } +} + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by RX GPO Rising Edge. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiRxGpoRisingEdgeHandler(XHdmiphy1 *InstancePtr) +{ + u8 Id, Id0, Id1; + u8 CfgValComp; + + /* Compare the current and next CFG values */ + CfgValComp = XHdmiphy1_CheckLineRateCfg(InstancePtr, 0, + XHDMIPHY1_CHANNEL_ID_CH1, XHDMIPHY1_DIR_RX); + + if (CfgValComp) { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_RXGPO_RE, 0); + } else { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_RXGPO_RE, 1); + } + + /* De-assert GPI port. */ + XHdmiphy1_SetGpi(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, FALSE); + + /* Wait for GPO RX = 0 */ + while (XHdmiphy1_GetGpo(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX)); + + /* Configure RXRATE Port */ + XHdmiphy1_DirReconfig(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX); + + /* Deassert reset on GT Reset IP RX */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_COMMON_INIT_REG, + (XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_COMMON_INIT_REG) & ~0x2)); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].RxState = + XHDMIPHY1_GT_STATE_LOCK; + } +} + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by LCPLL lock done. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiLcpllLockHandler(XHdmiphy1 *InstancePtr) +{ + XHdmiphy1_PllType TxPllType; + u8 Id, Id0, Id1; + XHdmiphy1_ChannelId ChId; + + /* Determine PLL type. */ + TxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, + XHDMIPHY1_DIR_NONE, XHDMIPHY1_PLL_TYPE_LCPLL); + + if (XHdmiphy1_IsPllLocked(InstancePtr, 0, ChId) == XST_SUCCESS) { + /* Log, lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_LCPLL_LOCK, 1); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, + &Id1); + for (Id = Id0; Id <= Id1; Id++) { + if (TxPllType == XHDMIPHY1_PLL_TYPE_LCPLL) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)]. + TxState = XHDMIPHY1_GT_STATE_RESET; + } + else { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxState = XHDMIPHY1_GT_STATE_RESET; + } + } + } + else { + /* Log, Lost lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_LCPLL_LOCK, 0); + } + +} + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by RPLL lock done. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiRpllLockHandler(XHdmiphy1 *InstancePtr) +{ + XHdmiphy1_PllType TxPllType; + u8 Id, Id0, Id1; + XHdmiphy1_ChannelId ChId; + + /* Determine PLL type. */ + TxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, + XHDMIPHY1_DIR_NONE, XHDMIPHY1_PLL_TYPE_RPLL); + + if (XHdmiphy1_IsPllLocked(InstancePtr, 0, ChId) == XST_SUCCESS) { + /* Log, lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_RPLL_LOCK, 1); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, + &Id1); + for (Id = Id0; Id <= Id1; Id++) { + if (TxPllType == XHDMIPHY1_PLL_TYPE_RPLL) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)]. + TxState = XHDMIPHY1_GT_STATE_RESET; + } + else { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxState = XHDMIPHY1_GT_STATE_RESET; + } + } + } + else { + /* Log, Lost lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_RPLL_LOCK, 0); + } + +} +#else +/*****************************************************************************/ +/** +* This function is the handler for events triggered by QPLL lock done. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiQpllLockHandler(XHdmiphy1 *InstancePtr) +{ + XHdmiphy1_PllType TxPllType; + XHdmiphy1_PllType RxPllType; + u8 Id, Id0, Id1; + XHdmiphy1_ChannelId ChId; + + /* Determine PLL type. */ + TxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + RxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* RX is using QPLL. */ + if ((RxPllType == XHDMIPHY1_PLL_TYPE_QPLL) || + (RxPllType == XHDMIPHY1_PLL_TYPE_QPLL0) || + (RxPllType == XHDMIPHY1_PLL_TYPE_QPLL1)) { + + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, + XHDMIPHY1_DIR_RX, RxPllType); + + if (XHdmiphy1_IsPllLocked(InstancePtr, 0, ChId) == XST_SUCCESS) { + /* Log, lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_QPLL_LOCK, 1); + + /* GT RX reset. */ + XHdmiphy1_ResetGtTxRx(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, FALSE); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, + &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxState = XHDMIPHY1_GT_STATE_RESET; + } + } + else { + /* Log, Lost lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_QPLL_LOCK, 0); + } + } + /* TX is using QPLL. */ + else { + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, + XHDMIPHY1_DIR_TX, TxPllType); + + if (XHdmiphy1_IsPllLocked(InstancePtr, 0, ChId) == XST_SUCCESS) { + /* Log, lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_QPLL_LOCK, 1); + + /* GT TX reset. */ + XHdmiphy1_ResetGtTxRx(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, FALSE); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, + &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)]. + TxState = XHDMIPHY1_GT_STATE_RESET; + } + } + else { + /* Log, Lost lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_QPLL_LOCK, 0); + } + } +} + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by CPLL lock done. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiCpllLockHandler(XHdmiphy1 *InstancePtr) +{ + XHdmiphy1_PllType TxPllType; + XHdmiphy1_PllType RxPllType; + u8 Id, Id0, Id1; + XHdmiphy1_ChannelId ChId; + + /* Determine PLL type. */ + TxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + RxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + + /* RX is using CPLL. */ + if (RxPllType == XHDMIPHY1_PLL_TYPE_CPLL) { + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, + XHDMIPHY1_DIR_RX, RxPllType); + + if (XHdmiphy1_IsPllLocked(InstancePtr, 0, ChId) == XST_SUCCESS) { + /* Log, lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_CPLL_LOCK, 1); + /* GT RX reset. */ + XHdmiphy1_ResetGtTxRx(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, FALSE); + + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)]. + RxState = XHDMIPHY1_GT_STATE_RESET; + } + } + else { + /* Log, Lost lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_CPLL_LOCK, 0); + } + } + /* TX is using CPLL. */ + else { + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, + XHDMIPHY1_DIR_TX, TxPllType); + + if (XHdmiphy1_IsPllLocked(InstancePtr, 0, ChId) == XST_SUCCESS) { + /* Log, lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_CPLL_LOCK, 1); + + /* GT TX reset. */ + XHdmiphy1_ResetGtTxRx(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, FALSE); + + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)]. + TxState = XHDMIPHY1_GT_STATE_RESET; + } + } + else { + /* Log, Lost lock */ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_CPLL_LOCK, 0); + } + } +} + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by GT TX alignment done. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiGtTxAlignDoneLockHandler(XHdmiphy1 *InstancePtr) +{ + u8 Id, Id0, Id1; + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_TX_ALIGN, 1); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_READY; + } + + /* TX ready callback. */ + if (InstancePtr->HdmiTxReadyCallback) { + InstancePtr->HdmiTxReadyCallback(InstancePtr->HdmiTxReadyRef); + } +} +#endif + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by GT TX reset lock done. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiGtTxResetDoneLockHandler(XHdmiphy1 *InstancePtr) +{ + u8 Id, Id0, Id1; + XHdmiphy1_PllType PllType; + XHdmiphy1_ChannelId ChId; + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_TX_RST_DONE, 0); + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, XHDMIPHY1_DIR_TX, + PllType); + + /* Set TX TMDS Clock Pattern Generator */ + if ((InstancePtr->Config.UseGtAsTxTmdsClk == TRUE) && + ((InstancePtr->TxHdmi21Cfg.IsEnabled == 0) || + (InstancePtr->TxHdmi21Cfg.IsEnabled == 1 && + InstancePtr->TxHdmi21Cfg.NChannels == 3))) { + XHdmiphy1_PatgenSetRatio(InstancePtr, 0, + (u64)((XHdmiphy1_GetLineRateHz(InstancePtr, + 0, ChId)) / 1000000)); + XHdmiphy1_PatgenEnable(InstancePtr, 0, TRUE); + } else { + XHdmiphy1_PatgenEnable(InstancePtr, 0, FALSE); + } + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + if ((InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE3) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE4) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTYE4)) { + XHdmiphy1_TxAlignReset(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, TRUE); + XHdmiphy1_TxAlignReset(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, FALSE); + } + + /* GT alignment. */ + XHdmiphy1_TxAlignStart(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, TRUE); + XHdmiphy1_TxAlignStart(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, FALSE); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_ALIGN; + } +#else + /* Deassert TX LNKRDY MASK */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_TX_INIT_REG, + (XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_INIT_REG) & ~0x10101010)); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_READY; + } + + /* TX ready callback. */ + if (InstancePtr->HdmiTxReadyCallback) { + InstancePtr->HdmiTxReadyCallback(InstancePtr->HdmiTxReadyRef); + } +#endif +} + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by GT RX reset lock done. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiGtRxResetDoneLockHandler(XHdmiphy1 *InstancePtr) +{ + u8 Id, Id0, Id1; + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_RX_RST_DONE, 0); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].RxState = + XHDMIPHY1_GT_STATE_READY; + } + + /* Deassert RX LNKRDY MASK */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_RX_INIT_REG, + (XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_RX_INIT_REG) & ~0x10101010)); + + /* If DRU is use/d, release its reset. */ + if (InstancePtr->HdmiRxDruIsEnabled) { + XHdmiphy1_DruReset(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, FALSE); + } + + /* RX ready callback. */ + if (InstancePtr->HdmiRxReadyCallback) { + InstancePtr->HdmiRxReadyCallback(InstancePtr->HdmiRxReadyRef); + } +} + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by a change in TX frequency +* as detected by the HDMI clock detector logic. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiTxClkDetFreqChangeHandler(XHdmiphy1 *InstancePtr) +{ + XHdmiphy1_PllType PllType; + u8 Id, Id0, Id1; + + if (InstancePtr->TxHdmi21Cfg.IsEnabled) { + if (InstancePtr->Config.TxRefClkSel != + InstancePtr->Config.TxFrlRefClkSel) { + return; + } + } + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_TX_FREQ, 0); + + /* Set TX TMDS Clock Pattern Generator */ + if ((InstancePtr->Config.UseGtAsTxTmdsClk == TRUE) && + ((InstancePtr->TxHdmi21Cfg.IsEnabled == 0) || + (InstancePtr->TxHdmi21Cfg.IsEnabled == 1 && + InstancePtr->TxHdmi21Cfg.NChannels == 3))) { + XHdmiphy1_PatgenEnable(InstancePtr, 0, FALSE); + } + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* If the TX frequency has changed, the PLL is always disabled. */ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_PowerDownGtPll(InstancePtr, 0, + (PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_CHANNEL_ID_CHA : XHDMIPHY1_CHANNEL_ID_CMNA, TRUE); + + XHdmiphy1_ResetGtPll(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, TRUE); +#else + /* Suppress Warning Messages */ + PllType = PllType; + + /* Mask RESET DONE */ + /* Deassert TX LNKRDY MASK */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_TX_INIT_REG, + (XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_TX_INIT_REG) | 0x10101010)); +#endif + /* Mask the MMCM Lock */ + XHdmiphy1_MmcmLockedMaskEnable(InstancePtr, 0, XHDMIPHY1_DIR_TX, TRUE); + + /* Disable TX MMCM. */ + /* XHdmiphy1_MmcmPowerDown(InstancePtr, 0, XHDMIPHY1_DIR_TX, TRUE); */ + + /* Clear TX timer. */ + XHdmiphy1_ClkDetTimerClear(InstancePtr, 0, XHDMIPHY1_DIR_TX); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + /* Clear GT alignment. */ + XHdmiphy1_TxAlignStart(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, FALSE); +#endif + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_IDLE; + } + + /* If there is no reference clock, load TX timer in usec. */ + if (XHdmiphy1_ClkDetGetRefClkFreqHz(InstancePtr, XHDMIPHY1_DIR_TX)) { + XHdmiphy1_ClkDetTimerLoad(InstancePtr, 0, XHDMIPHY1_DIR_TX, + InstancePtr->Config.AxiLiteClkFreq/1000); + } + + /* Callback to re-initialize. */ + if (InstancePtr->HdmiTxInitCallback) { + InstancePtr->HdmiTxInitCallback(InstancePtr->HdmiTxInitRef); + } +} + +/*****************************************************************************/ +/** +* This function is the handler for events triggered by a change in RX frequency +* as detected by the HDMI clock detector logic. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiRxClkDetFreqChangeHandler(XHdmiphy1 *InstancePtr) +{ + XHdmiphy1_PllType PllType; + u32 RxRefClkHz; + u8 Id, Id0, Id1; + + if (InstancePtr->RxHdmi21Cfg.IsEnabled) { + if (InstancePtr->Config.RxRefClkSel != + InstancePtr->Config.RxFrlRefClkSel) { + return; + } + } + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_RX_FREQ, 0); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].RxState = + XHDMIPHY1_GT_STATE_IDLE; + } + + if (!InstancePtr->RxHdmi21Cfg.IsEnabled) { + /* Mask the MMCM Lock */ + XHdmiphy1_MmcmLockedMaskEnable(InstancePtr, 0, XHDMIPHY1_DIR_RX, TRUE); + } + + /* Determine PLL type and RX reference clock selection. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* Fetch New RX Reference Clock Frequency */ + RxRefClkHz = XHdmiphy1_ClkDetGetRefClkFreqHz(InstancePtr, + XHDMIPHY1_DIR_RX); + + /* Round input frequency to 10 kHz. */ + RxRefClkHz = (RxRefClkHz+5000) / 10000; + RxRefClkHz = RxRefClkHz * 10000; + + /* Store RX reference clock. */ + if (InstancePtr->RxHdmi21Cfg.IsEnabled) { + InstancePtr->HdmiRxRefClkHz = XHDMIPHY1_HDMI21_FRL_REFCLK; + } + else { + InstancePtr->HdmiRxRefClkHz = RxRefClkHz; + } + + /* If the RX frequency has changed, the PLL is always disabled. */ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_PowerDownGtPll(InstancePtr, 0, + (PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_CHANNEL_ID_CHA : XHDMIPHY1_CHANNEL_ID_CMNA, TRUE); + + XHdmiphy1_ResetGtPll(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, TRUE); +#else + /* Suppress Warning Messages */ + PllType = PllType; + + /* Mask RESET DONE */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_RX_INIT_REG, + (XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_RX_INIT_REG) | 0x10101010)); + +#endif + + /* If DRU is present, disable it and assert reset. */ + if (InstancePtr->Config.DruIsPresent) { + XHdmiphy1_DruReset(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, TRUE); + XHdmiphy1_DruEnable(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, FALSE); + } + + /* Clear RX timer. */ + XHdmiphy1_ClkDetTimerClear(InstancePtr, 0, XHDMIPHY1_DIR_RX); + + /* If there is reference clock, load RX timer in usec. + * The reference clock should be larger than 25Mhz. We are using a 20Mhz + * instead to keep some margin for errors. */ + if (RxRefClkHz > 20000000) { + XHdmiphy1_ClkDetTimerLoad(InstancePtr, 0, XHDMIPHY1_DIR_RX, + InstancePtr->Config.AxiLiteClkFreq/1000); + + /* Callback to re-initialize. */ + if (InstancePtr->HdmiRxInitCallback) { + InstancePtr->HdmiRxInitCallback(InstancePtr->HdmiRxInitRef); + } + } +} + +/*****************************************************************************/ +/** +* This function is the handler for TX timer timeout events. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiTxTimerTimeoutHandler(XHdmiphy1 *InstancePtr) +{ +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_ChannelId ChId; + XHdmiphy1_PllType PllType; +#else + u8 CfgValComp; +#endif + u8 Id, Id0, Id1; + + if (!InstancePtr->TxHdmi21Cfg.IsEnabled) { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_TX_TMR, 1); + } + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, XHDMIPHY1_DIR_TX, PllType); + + /* Start TX MMCM. */ + XHdmiphy1_MmcmStart(InstancePtr, 0, XHDMIPHY1_DIR_TX); + + /* Enable PLL. */ + XHdmiphy1_PowerDownGtPll(InstancePtr, 0, + (PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_CHANNEL_ID_CHA : XHDMIPHY1_CHANNEL_ID_CMNA, FALSE); + + if (PllType != XHDMIPHY1_PLL_TYPE_CPLL) { + /* Set QPLL Selection in PIO. */ + XHdmiphy1_WriteCfgRefClkSelReg(InstancePtr, 0); + } + + XHdmiphy1_ClkReconfig(InstancePtr, 0, ChId); + XHdmiphy1_OutDivReconfig(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX); + if ((InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE3) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE4) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTYE4)) { + XHdmiphy1_SetBufgGtDiv(InstancePtr, XHDMIPHY1_DIR_TX, + (PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + InstancePtr->Quads[0].Plls[0].TxOutDiv : + (InstancePtr->Quads[0].Plls[0].TxOutDiv != 16) ? + InstancePtr->Quads[0].Plls[0].TxOutDiv : + InstancePtr->Quads[0].Plls[0].TxOutDiv / 2); + } + + XHdmiphy1_DirReconfig(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX); + + /* Assert PLL reset. */ + XHdmiphy1_ResetGtPll(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, TRUE); + + /* De-assert PLL reset. */ + XHdmiphy1_ResetGtPll(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, FALSE); + + if ((InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE3) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE4) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTYE4)) { + /* Clear GT alignment. */ + XHdmiphy1_TxAlignStart(InstancePtr, ChId, FALSE); + } + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_LOCK; + } +#else + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].TxState = + XHDMIPHY1_GT_STATE_GPO_RE; + } + + /* Compare the current and next CFG values */ + CfgValComp = XHdmiphy1_CheckLineRateCfg(InstancePtr, 0, + XHDMIPHY1_CHANNEL_ID_CH1, XHDMIPHY1_DIR_TX); + + if (!CfgValComp) { + /* Assert GPI port. */ + XHdmiphy1_SetGpi(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_TX, TRUE); + } + else { + XHdmiphy1_HdmiTxGpoRisingEdgeHandler(InstancePtr); + } +#endif +} + +/*****************************************************************************/ +/** +* This function is the handler for RX timer timeout events. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiRxTimerTimeoutHandler(XHdmiphy1 *InstancePtr) +{ + XHdmiphy1_ChannelId ChId; + XHdmiphy1_PllType PllType; + u32 Status; + u8 Id, Id0, Id1; +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) + u8 CfgValComp; +#endif + + if (!InstancePtr->RxHdmi21Cfg.IsEnabled) { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_RX_TMR, 1); + } else { + if (InstancePtr->Config.RxRefClkSel == + InstancePtr->Config.RxFrlRefClkSel) { + /* Set MMCM CLKINSEL to CLK1 */ + XHdmiphy1_MmcmSetClkinsel(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_MMCM_CLKINSEL_CLKIN1); + + /* Start RX MMCM. */ + XHdmiphy1_MmcmStart(InstancePtr, 0, XHDMIPHY1_DIR_RX); + } + } + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, XHDMIPHY1_DIR_RX, PllType); + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + + + /* Set RX parameters. */ + Status = XHdmiphy1_SetHdmiRxParam(InstancePtr, 0, ChId); + if (Status != XST_SUCCESS) { + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].RxState = + XHDMIPHY1_GT_STATE_IDLE; + } + + return; + } + + /* Enable DRU to set the clock muxes. */ + XHdmiphy1_DruEnable(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, + InstancePtr->HdmiRxDruIsEnabled); + + /* Update GT DRU mode. */ + XHdmiphy1_HdmiGtDruModeEnable(InstancePtr, + InstancePtr->HdmiRxDruIsEnabled); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + /* Enable PLL. */ + XHdmiphy1_PowerDownGtPll(InstancePtr, 0, + (PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_CHANNEL_ID_CHA : XHDMIPHY1_CHANNEL_ID_CMNA, FALSE); + + /* Update reference clock election. */ + if (InstancePtr->RxHdmi21Cfg.IsEnabled == FALSE) { + XHdmiphy1_CfgPllRefClkSel(InstancePtr, 0, + ((PllType == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_CHANNEL_ID_CHA : XHDMIPHY1_CHANNEL_ID_CMNA), + ((InstancePtr->HdmiRxDruIsEnabled) ? + InstancePtr->Config.DruRefClkSel : + InstancePtr->Config.RxRefClkSel)); + } + + /* Update RefClk selection. */ + XHdmiphy1_WriteCfgRefClkSelReg(InstancePtr, 0); + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + /* Determine which channel(s) to operate on. */ + ChId = XHdmiphy1_GetRcfgChId(InstancePtr, 0, XHDMIPHY1_DIR_RX, PllType); + + XHdmiphy1_ClkReconfig(InstancePtr, 0, ChId); + XHdmiphy1_OutDivReconfig(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX); + + XHdmiphy1_DirReconfig(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX); + + /* Assert RX PLL reset. */ + XHdmiphy1_ResetGtPll(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, TRUE); + + /* De-assert RX PLL reset. */ + XHdmiphy1_ResetGtPll(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, FALSE); +#else + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[0].Plls[XHDMIPHY1_CH2IDX(Id)].RxState = + XHDMIPHY1_GT_STATE_GPO_RE; + } + + /* Compare the current and next CFG values */ + CfgValComp = XHdmiphy1_CheckLineRateCfg(InstancePtr, 0, + XHDMIPHY1_CHANNEL_ID_CH1, XHDMIPHY1_DIR_RX); + + if (!CfgValComp) { + /* Assert GPI port. */ + XHdmiphy1_SetGpi(InstancePtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + XHDMIPHY1_DIR_RX, TRUE); + } + else { + XHdmiphy1_HdmiRxGpoRisingEdgeHandler(InstancePtr); + } +#endif +} + +/*****************************************************************************/ +/** +* This function is the handler for TX MMCM Lock events. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiTxMmcmLockHandler(XHdmiphy1 *InstancePtr) +{ + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_TXPLL_LOCK, 1); + +} + +/*****************************************************************************/ +/** +* This function is the handler for RX MMCM Lock events. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiRxMmcmLockHandler(XHdmiphy1 *InstancePtr) +{ + + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_RXPLL_LOCK, 1); + +} + +/*****************************************************************************/ +/** +* This function is the interrupt handler for the GT events. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_HdmiGtHandler(XHdmiphy1 *InstancePtr) +{ + u32 Event; + u32 EventMask; + u32 EventAck; + XHdmiphy1_GtState *TxStatePtr; + XHdmiphy1_GtState *RxStatePtr; + XHdmiphy1_PllType TxPllType; + XHdmiphy1_PllType RxPllType; + + + EventMask = +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHDMIPHY1_INTR_QPLL0_LOCK_MASK | XHDMIPHY1_INTR_CPLL_LOCK_MASK | + XHDMIPHY1_INTR_QPLL1_LOCK_MASK | + XHDMIPHY1_INTR_TXALIGNDONE_MASK | +#else + XHDMIPHY1_INTR_LCPLL_LOCK_MASK | XHDMIPHY1_INTR_RPLL_LOCK_MASK | + XHDMIPHY1_INTR_TXGPO_RE_MASK | XHDMIPHY1_INTR_RXGPO_RE_MASK | +#endif + XHDMIPHY1_INTR_TXRESETDONE_MASK | XHDMIPHY1_INTR_RXRESETDONE_MASK | + XHDMIPHY1_INTR_TXMMCMUSRCLK_LOCK_MASK | + XHDMIPHY1_INTR_RXMMCMUSRCLK_LOCK_MASK; + + u8 QuadId = 0; + + /* Read Interrupt Status register */ + Event = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_INTR_STS_REG); + + EventAck = EventMask & Event; + + /* Read States for Quad=0 Ch1 */ + TxStatePtr = &InstancePtr->Quads[QuadId].Ch1.TxState; + RxStatePtr = &InstancePtr->Quads[QuadId].Ch1.RxState; + + /* Determine PLL type. */ + TxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_TX, + XHDMIPHY1_CHANNEL_ID_CH1); + RxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + + if (Event & XHDMIPHY1_INTR_TXMMCMUSRCLK_LOCK_MASK) { + XHdmiphy1_HdmiTxMmcmLockHandler(InstancePtr); + } + if (Event & XHDMIPHY1_INTR_RXMMCMUSRCLK_LOCK_MASK) { + XHdmiphy1_HdmiRxMmcmLockHandler(InstancePtr); + } +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + if ((Event & XHDMIPHY1_INTR_QPLL0_LOCK_MASK) || + (Event & XHDMIPHY1_INTR_QPLL1_LOCK_MASK)) { + XHdmiphy1_HdmiQpllLockHandler(InstancePtr); + } + if (Event & XHDMIPHY1_INTR_CPLL_LOCK_MASK) { + XHdmiphy1_HdmiCpllLockHandler(InstancePtr); + } + if ((Event & XHDMIPHY1_INTR_TXRESETDONE_MASK) + && (*TxStatePtr == XHDMIPHY1_GT_STATE_RESET)) { + XHdmiphy1_HdmiGtTxResetDoneLockHandler(InstancePtr); + } + if ((Event & XHDMIPHY1_INTR_TXALIGNDONE_MASK) + && (*TxStatePtr == XHDMIPHY1_GT_STATE_ALIGN)) { + XHdmiphy1_HdmiGtTxAlignDoneLockHandler(InstancePtr); + } + if ((Event & XHDMIPHY1_INTR_RXRESETDONE_MASK) + && (*RxStatePtr == XHDMIPHY1_GT_STATE_RESET)) { + XHdmiphy1_HdmiGtRxResetDoneLockHandler(InstancePtr); + } + + /* Suppress Warning Messages */ + TxPllType = TxPllType; + RxPllType = RxPllType; +#else + if (Event & XHDMIPHY1_INTR_TXGPO_RE_MASK) { + XHdmiphy1_HdmiTxGpoRisingEdgeHandler(InstancePtr); + } + if (Event & XHDMIPHY1_INTR_RXGPO_RE_MASK) { + XHdmiphy1_HdmiRxGpoRisingEdgeHandler(InstancePtr); + } + if ((Event & XHDMIPHY1_INTR_LCPLL_LOCK_MASK) && + (((*TxStatePtr != XHDMIPHY1_GT_STATE_IDLE) && + (TxPllType == XHDMIPHY1_PLL_TYPE_LCPLL)) || + ((*RxStatePtr != XHDMIPHY1_GT_STATE_IDLE) && + (RxPllType == XHDMIPHY1_PLL_TYPE_LCPLL)))) { + XHdmiphy1_HdmiLcpllLockHandler(InstancePtr); + } + if ((Event & XHDMIPHY1_INTR_RPLL_LOCK_MASK) && + (((*TxStatePtr != XHDMIPHY1_GT_STATE_IDLE) && + (TxPllType == XHDMIPHY1_PLL_TYPE_RPLL)) || + ((*RxStatePtr != XHDMIPHY1_GT_STATE_IDLE) && + (RxPllType == XHDMIPHY1_PLL_TYPE_RPLL)))) { + XHdmiphy1_HdmiRpllLockHandler(InstancePtr); + } + + /* [Versal] This is different from bare metal driver */ + if (Event & XHDMIPHY1_INTR_TXRESETDONE_MASK) + XHdmiphy1_HdmiGtTxResetDoneLockHandler(InstancePtr); + + if ((Event & XHDMIPHY1_INTR_RXRESETDONE_MASK) + && (*RxStatePtr == XHDMIPHY1_GT_STATE_RESET)) { + XHdmiphy1_HdmiGtRxResetDoneLockHandler(InstancePtr); + } + + /* Suppress Warning Messages */ + TxStatePtr = TxStatePtr; + RxStatePtr = RxStatePtr; +#endif + + /* Clear event flags by writing to Interrupt Status register */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_INTR_STS_REG, + EventAck); +} + +/*****************************************************************************/ +/** +* This function is the interrupt handler for the clock detector events. +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_ClkDetHandler(XHdmiphy1 *InstancePtr) +{ + u32 Event; + u32 EventMask; + u32 EventAck; + + EventMask = XHDMIPHY1_INTR_TXCLKDETFREQCHANGE_MASK | + XHDMIPHY1_INTR_RXCLKDETFREQCHANGE_MASK | + XHDMIPHY1_INTR_TXTMRTIMEOUT_MASK | + XHDMIPHY1_INTR_RXTMRTIMEOUT_MASK; + + /* Read Interrupt Status register */ + Event = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_INTR_STS_REG); + + EventAck = EventMask & Event; + + if (Event & XHDMIPHY1_INTR_TXCLKDETFREQCHANGE_MASK) { + XHdmiphy1_HdmiTxClkDetFreqChangeHandler(InstancePtr); + } + if (Event & XHDMIPHY1_INTR_RXCLKDETFREQCHANGE_MASK) { + XHdmiphy1_HdmiRxClkDetFreqChangeHandler(InstancePtr); + } + if (Event & XHDMIPHY1_INTR_TXTMRTIMEOUT_MASK) { + XHdmiphy1_HdmiTxTimerTimeoutHandler(InstancePtr); + } + if (Event & XHDMIPHY1_INTR_RXTMRTIMEOUT_MASK) { + XHdmiphy1_HdmiRxTimerTimeoutHandler(InstancePtr); + } + + /* Clear event flags by writing to Interrupt Status register */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_INTR_STS_REG, + EventAck); +} diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_hw.h b/hdmi/phy-xilinx-vphy/xhdmiphy1_hw.h new file mode 100644 index 0000000..43e7304 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_hw.h @@ -0,0 +1,705 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_hw.h + * + * This header file contains the identifiers and low-level driver functions (or + * macros) that can be used to access the device. High-level driver functions + * are defined in xhdmiphy1.h. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * + * @addtogroup xhdmiphy1_v1_0 + * @{ +*******************************************************************************/ + +#ifndef XHDMIPHY1_HW_H_ +/* Prevent circular inclusions by using protection macros. */ +#define XHDMIPHY1_HW_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files **********************************/ + +#include "xil_io.h" +#include "xil_types.h" + +/************************** Constant Definitions ******************************/ + +/******************************************************************************/ +/** + * Address mapping for the Video PHY core. + * +*******************************************************************************/ +/** @name HDMIPHY core registers: General registers. + * @{ + */ +#define XHDMIPHY1_VERSION_REG 0x000 +#define XHDMIPHY1_BANK_SELECT_REG 0x00C +#define XHDMIPHY1_REF_CLK_SEL_REG 0x010 +#define XHDMIPHY1_PLL_RESET_REG 0x014 +#define XHDMIPHY1_COMMON_INIT_REG 0x014 +#define XHDMIPHY1_PLL_LOCK_STATUS_REG 0x018 +#define XHDMIPHY1_TX_INIT_REG 0x01C +#define XHDMIPHY1_TX_INIT_STATUS_REG 0x020 +#define XHDMIPHY1_RX_INIT_REG 0x024 +#define XHDMIPHY1_RX_INIT_STATUS_REG 0x028 +#define XHDMIPHY1_IBUFDS_GTXX_CTRL_REG 0x02C +#define XHDMIPHY1_POWERDOWN_CONTROL_REG 0x030 +#define XHDMIPHY1_LOOPBACK_CONTROL_REG 0x038 +/* @} */ + +/** @name HDMIPHY core registers: Dynamic reconfiguration port (DRP) registers. + * @{ + */ +#define XHDMIPHY1_DRP_CONTROL_CH1_REG 0x040 +#define XHDMIPHY1_DRP_CONTROL_CH2_REG 0x044 +#define XHDMIPHY1_DRP_CONTROL_CH3_REG 0x048 +#define XHDMIPHY1_DRP_CONTROL_CH4_REG 0x04C +#define XHDMIPHY1_DRP_STATUS_CH1_REG 0x050 +#define XHDMIPHY1_DRP_STATUS_CH2_REG 0x054 +#define XHDMIPHY1_DRP_STATUS_CH3_REG 0x058 +#define XHDMIPHY1_DRP_STATUS_CH4_REG 0x05C +#define XHDMIPHY1_DRP_CONTROL_COMMON_REG 0x060 +#define XHDMIPHY1_DRP_STATUS_COMMON_REG 0x064 +#define XHDMIPHY1_DRP_CONTROL_TXMMCM_REG 0x124 +#define XHDMIPHY1_DRP_STATUS_TXMMCM_REG 0x128 +#define XHDMIPHY1_DRP_CONTROL_RXMMCM_REG 0x144 +#define XHDMIPHY1_DRP_STATUS_RXMMCM_REG 0x148 +/* @} */ + +/** @name HDMIPHY core registers: CPLL Calibration registers. + * @{ + */ +#define XHDMIPHY1_CPLL_CAL_PERIOD_REG 0x068 +#define XHDMIPHY1_CPLL_CAL_TOL_REG 0x06C +/* @} */ +/** @name HDMIPHY core registers: GT Debug INTF registers. + * @{ + */ +#define XHDMIPHY1_GT_DBG_GPI_REG 0x068 +#define XHDMIPHY1_GT_DBG_GPO_REG 0x06C +/* @} */ + +/** @name HDMIPHY core registers: Transmitter function registers. + * @{ + */ +#define XHDMIPHY1_TX_CONTROL_REG 0x070 +#define XHDMIPHY1_TX_BUFFER_BYPASS_REG 0x074 +#define XHDMIPHY1_TX_STATUS_REG 0x078 +#define XHDMIPHY1_TX_DRIVER_CH12_REG 0x07C +#define XHDMIPHY1_TX_DRIVER_CH34_REG 0x080 +#define XHDMIPHY1_TX_DRIVER_EXT_REG 0x084 +#define XHDMIPHY1_TX_RATE_CH12_REG 0x08C +#define XHDMIPHY1_TX_RATE_CH34_REG 0x090 +/* @} */ + +/** @name HDMIPHY core registers: Receiver function registers. + * @{ + */ +#define XHDMIPHY1_RX_RATE_CH12_REG 0x98 +#define XHDMIPHY1_RX_RATE_CH34_REG 0x9C +#define XHDMIPHY1_RX_CONTROL_REG 0x100 +#define XHDMIPHY1_RX_STATUS_REG 0x104 +#define XHDMIPHY1_RX_EQ_CDR_REG 0x108 +#define XHDMIPHY1_RX_TDLOCK_REG 0x10C +/* @} */ + +/** @name HDMIPHY core registers: Interrupt registers. + * @{ + */ +#define XHDMIPHY1_INTR_EN_REG 0x110 +#define XHDMIPHY1_INTR_DIS_REG 0x114 +#define XHDMIPHY1_INTR_MASK_REG 0x118 +#define XHDMIPHY1_INTR_STS_REG 0x11C +/* @} */ + +/** @name User clocking registers: MMCM and BUFGGT registers. + * @{ + */ +#define XHDMIPHY1_MMCM_TXUSRCLK_CTRL_REG 0x0120 +#define XHDMIPHY1_MMCM_TXUSRCLK_REG1 0x0124 +#define XHDMIPHY1_MMCM_TXUSRCLK_REG2 0x0128 +#define XHDMIPHY1_MMCM_TXUSRCLK_REG3 0x012C +#define XHDMIPHY1_MMCM_TXUSRCLK_REG4 0x0130 +#define XHDMIPHY1_BUFGGT_TXUSRCLK_REG 0x0134 +#define XHDMIPHY1_MISC_TXUSRCLK_REG 0x0138 + +#define XHDMIPHY1_MMCM_RXUSRCLK_CTRL_REG 0x0140 +#define XHDMIPHY1_MMCM_RXUSRCLK_REG1 0x0144 +#define XHDMIPHY1_MMCM_RXUSRCLK_REG2 0x0148 +#define XHDMIPHY1_MMCM_RXUSRCLK_REG3 0x014C +#define XHDMIPHY1_MMCM_RXUSRCLK_REG4 0x0150 +#define XHDMIPHY1_BUFGGT_RXUSRCLK_REG 0x0154 +#define XHDMIPHY1_MISC_RXUSRCLK_REG 0x0158 +/* @} */ + +/** @name Clock detector (HDMI) registers. + * @{ + */ +#define XHDMIPHY1_CLKDET_CTRL_REG 0x0200 +#define XHDMIPHY1_CLKDET_STAT_REG 0x0204 +#define XHDMIPHY1_CLKDET_FREQ_TMR_TO_REG 0x0208 +#define XHDMIPHY1_CLKDET_FREQ_TX_REG 0x020C +#define XHDMIPHY1_CLKDET_FREQ_RX_REG 0x0210 +#define XHDMIPHY1_CLKDET_TMR_TX_REG 0x0214 +#define XHDMIPHY1_CLKDET_TMR_RX_REG 0x0218 +#define XHDMIPHY1_CLKDET_FREQ_DRU_REG 0x021C +/* @} */ + +/** @name Data recovery unit registers (HDMI). + * @{ + */ +#define XHDMIPHY1_DRU_CTRL_REG 0x0300 +#define XHDMIPHY1_DRU_STAT_REG 0x0304 + +#define XHDMIPHY1_DRU_CFREQ_L_REG(Ch) (0x0308 + (12 * (Ch - 1))) +#define XHDMIPHY1_DRU_CFREQ_H_REG(Ch) (0x030C + (12 * (Ch - 1))) +#define XHDMIPHY1_DRU_GAIN_REG(Ch) (0x0310 + (12 * (Ch - 1))) +/* @} */ + +/** @name TMDS Clock Pattern Generator registers (HDMI). + * @{ + */ +#define XHDMIPHY1_PATGEN_CTRL_REG 0x0340 +/* @} */ + +/******************************************************************************/ + +/** @name HDMIPHY core masks, shifts, and register values. + * @{ + */ +/* 0x0F8: VERSION */ +#define XHDMIPHY1_VERSION_INTER_REV_MASK \ + 0x000000FF /**< Internal revision. */ +#define XHDMIPHY1_VERSION_CORE_PATCH_MASK \ + 0x00000F00 /**< Core patch details. */ +#define XHDMIPHY1_VERSION_CORE_PATCH_SHIFT 8 /**< Shift bits for core patch + details. */ +#define XHDMIPHY1_VERSION_CORE_VER_REV_MASK \ + 0x0000F000 /**< Core version revision. */ +#define XHDMIPHY1_VERSION_CORE_VER_REV_SHIFT 12 /**< Shift bits for core + version revision. */ +#define XHDMIPHY1_VERSION_CORE_VER_MNR_MASK \ + 0x00FF0000 /**< Core minor version. */ +#define XHDMIPHY1_VERSION_CORE_VER_MNR_SHIFT 16 /**< Shift bits for core minor + version. */ +#define XHDMIPHY1_VERSION_CORE_VER_MJR_MASK \ + 0xFF000000 /**< Core major version. */ +#define XHDMIPHY1_VERSION_CORE_VER_MJR_SHIFT 24 /**< Shift bits for core major + version. */ +/* 0x00C: BANK_SELECT_REG */ +#define XHDMIPHY1_BANK_SELECT_TX_MASK 0x00F +#define XHDMIPHY1_BANK_SELECT_RX_MASK 0xF00 +#define XHDMIPHY1_BANK_SELECT_RX_SHIFT 8 +/* 0x010: REF_CLK_SEL */ +#define XHDMIPHY1_REF_CLK_SEL_QPLL0_MASK 0x0000000F +#define XHDMIPHY1_REF_CLK_SEL_CPLL_MASK 0x000000F0 +#define XHDMIPHY1_REF_CLK_SEL_CPLL_SHIFT 4 +#define XHDMIPHY1_REF_CLK_SEL_QPLL1_MASK 0x00000F00 +#define XHDMIPHY1_REF_CLK_SEL_QPLL1_SHIFT 8 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTREFCLK0 1 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTREFCLK1 2 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTNORTHREFCLK0 3 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTNORTHREFCLK1 4 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTSOUTHREFCLK0 5 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTSOUTHREFCLK1 6 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTEASTREFCLK0 3 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTEASTREFCLK1 4 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTWESTREFCLK0 5 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTWESTREFCLK1 6 +#define XHDMIPHY1_REF_CLK_SEL_XPLL_GTGREFCLK 7 +#define XHDMIPHY1_REF_CLK_SEL_SYSCLKSEL_MASK 0x0F000000 +#define XHDMIPHY1_REF_CLK_SEL_SYSCLKSEL_SHIFT 24 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_PLL0 0 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_PLL1 1 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_CPLL 0 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_QPLL 1 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_QPLL0 3 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_DATA_QPLL1 2 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CH 0 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CMN 1 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CMN0 2 +#define XHDMIPHY1_REF_CLK_SEL_XXSYSCLKSEL_OUT_CMN1 3 +#define XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_OUT_MASK(G) \ + ((((G) == XHDMIPHY1_GT_TYPE_GTHE3) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTHE4) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTYE4)) ? 0x03000000 : 0x02000000) +#define XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_OUT_MASK(G) \ + ((((G) == XHDMIPHY1_GT_TYPE_GTHE3) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTHE4) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTYE4)) ? 0x0C000000 : 0x08000000) +#define XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_DATA_MASK(G) \ + ((((G) == XHDMIPHY1_GT_TYPE_GTHE3) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTHE4) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTYE4)) ? 0x30000000 : 0x01000000) +#define XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_DATA_MASK(G) \ + ((((G) == XHDMIPHY1_GT_TYPE_GTHE3) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTHE4) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTYE4)) ? 0xC0000000 : 0x04000000) +#define XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_OUT_SHIFT(G) \ + ((((G) == XHDMIPHY1_GT_TYPE_GTHE3) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTHE4) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTYE4)) ? 24 : 25) +#define XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_OUT_SHIFT(G) \ + ((((G) == XHDMIPHY1_GT_TYPE_GTHE3) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTHE4) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTYE4)) ? 26 : 27) +#define XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_DATA_SHIFT(G) \ + ((((G) == XHDMIPHY1_GT_TYPE_GTHE3) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTHE4) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTYE4)) ? 28 : 24) +#define XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_DATA_SHIFT(G) \ + ((((G) == XHDMIPHY1_GT_TYPE_GTHE3) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTHE4) || \ + ((G) == XHDMIPHY1_GT_TYPE_GTYE4)) ? 30 : 26) +/* 0x014: PLL_RESET */ +#define XHDMIPHY1_PLL_RESET_CPLL_MASK 0x1 +#define XHDMIPHY1_PLL_RESET_QPLL0_MASK 0x2 +#define XHDMIPHY1_PLL_RESET_QPLL1_MASK 0x4 +/* 0x014: COMMON INIT for Versal Only */ +#define XHDMIPHY1_GTWIZ_RESET_ALL_MASK 0x1 +#define XHDMIPHY1_PCIERST_ALL_CH_MASK 0x2 +/* 0x018: PLL_LOCK_STATUS */ +#define XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(Ch) \ + (0x01 << (Ch - 1)) +#define XHDMIPHY1_PLL_LOCK_STATUS_QPLL0_MASK 0x10 +#define XHDMIPHY1_PLL_LOCK_STATUS_QPLL1_MASK 0x20 +#define XHDMIPHY1_PLL_LOCK_STATUS_CPLL_ALL_MASK \ + (XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_PLL_LOCK_STATUS_CPLL_HDMI_MASK \ + (XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(XHDMIPHY1_CHANNEL_ID_CH3)) +#define XHDMIPHY1_PLL_LOCK_STATUS_RPLL_MASK 0xC0 +#define XHDMIPHY1_PLL_LOCK_STATUS_LCPLL_MASK 0x300 +/* 0x01C, 0x024: TX_INIT, RX_INIT */ +#define XHDMIPHY1_TXRX_INIT_GTRESET_MASK(Ch) \ + (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_INIT_PMARESET_MASK(Ch) \ + (0x02 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_INIT_PCSRESET_MASK(Ch) \ + (0x04 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_INIT_USERRDY_MASK(Ch) \ + (0x08 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_LNKRDY_SB_MASK(Ch) \ + (0x10 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_MSTRESET_MASK(Ch) \ + (0x20 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_INIT_USERRDY_MASK(Ch) \ + (0x40 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_INIT_PLLGTRESET_MASK(Ch) \ + (0x80 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_INIT_GTRESET_ALL_MASK \ + (XHDMIPHY1_TXRX_INIT_GTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TXRX_INIT_GTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TXRX_INIT_GTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TXRX_INIT_GTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_TXRX_LNKRDY_SB_ALL_MASK \ + (XHDMIPHY1_TXRX_LNKRDY_SB_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TXRX_LNKRDY_SB_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TXRX_LNKRDY_SB_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TXRX_LNKRDY_SB_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_TXRX_MSTRESET_ALL_MASK \ + (XHDMIPHY1_TXRX_MSTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TXRX_MSTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TXRX_MSTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TXRX_MSTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_TX_INIT_USERRDY_ALL_MASK \ + (XHDMIPHY1_TX_INIT_USERRDY_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TX_INIT_USERRDY_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TX_INIT_USERRDY_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TX_INIT_USERRDY_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_RX_INIT_USERRDY_ALL_MASK \ + (XHDMIPHY1_RX_INIT_USERRDY_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_RX_INIT_USERRDY_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_RX_INIT_USERRDY_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_RX_INIT_USERRDY_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_TXRX_INIT_PLLGTRESET_ALL_MASK \ + (XHDMIPHY1_TXRX_INIT_PLLGTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TXRX_INIT_PLLGTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TXRX_INIT_PLLGTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TXRX_INIT_PLLGTRESET_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +/* 0x020, 0x028: TX_STATUS, RX_STATUS */ +#define XHDMIPHY1_TXRX_INIT_STATUS_RESETDONE_MASK(Ch) \ + (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_INIT_STATUS_PMARESETDONE_MASK(Ch) \ + (0x02 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_INIT_STATUS_POWERGOOD_MASK(Ch) \ + (0x04 << (8 * (Ch - 1))) +#define XHDMIPHY1_TXRX_INIT_STATUS_RESETDONE_ALL_MASK \ + (XHDMIPHY1_TXRX_INIT_STATUS_RESETDONE_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TXRX_INIT_STATUS_RESETDONE_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TXRX_INIT_STATUS_RESETDONE_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TXRX_INIT_STATUS_RESETDONE_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_TXRX_INIT_STATUS_PMARESETDONE_ALL_MASK \ + (XHDMIPHY1_TXRX_INIT_STATUS_PMARESETDONE_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TXRX_INIT_STATUS_PMARESETDONE_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TXRX_INIT_STATUS_PMARESETDONE_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TXRX_INIT_STATUS_PMARESETDONE_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +/* 0x02C: IBUFDS_GTXX_CTRL */ +#define XHDMIPHY1_IBUFDS_GTXX_CTRL_GTREFCLK0_CEB_MASK 0x1 +#define XHDMIPHY1_IBUFDS_GTXX_CTRL_GTREFCLK1_CEB_MASK 0x2 +/* 0x030: POWERDOWN_CONTROL */ +#define XHDMIPHY1_POWERDOWN_CONTROL_CPLLPD_MASK(Ch) \ + (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_POWERDOWN_CONTROL_QPLL0PD_MASK(Ch) \ + (0x02 << (8 * (Ch - 1))) +#define XHDMIPHY1_POWERDOWN_CONTROL_QPLL1PD_MASK(Ch) \ + (0x04 << (8 * (Ch - 1))) +#define XHDMIPHY1_POWERDOWN_CONTROL_RXPD_MASK(Ch) \ + (0x18 << (8 * (Ch - 1))) +#define XHDMIPHY1_POWERDOWN_CONTROL_RXPD_SHIFT(Ch) \ + (3 + (8 * (Ch - 1))) +#define XHDMIPHY1_POWERDOWN_CONTROL_TXPD_MASK(Ch) \ + (0x60 << (8 * (Ch - 1))) +#define XHDMIPHY1_POWERDOWN_CONTROL_TXPD_SHIFT(Ch) \ + (5 + (8 * (Ch - 1))) +/* 0x038: LOOPBACK_CONTROL */ +#define XHDMIPHY1_LOOPBACK_CONTROL_CH_MASK(Ch) \ + (0x03 << (8 * (Ch - 1))) +#define XHDMIPHY1_LOOPBACK_CONTROL_CH_SHIFT(Ch) \ + (8 * (Ch - 1)) +/* 0x040, 0x044, 0x048, 0x04C, 0x060: DRP_CONTROL_CH[1-4], DRP_CONTROL_COMMON*/ +#define XHDMIPHY1_DRP_CONTROL_DRPADDR_MASK 0x00000FFF +#define XHDMIPHY1_DRP_CONTROL_DRPEN_MASK 0x00001000 +#define XHDMIPHY1_DRP_CONTROL_DRPWE_MASK 0x00002000 +#define XHDMIPHY1_DRP_CONTROL_DRPRESET_MASK 0x00004000 +#define XHDMIPHY1_DRP_CONTROL_DRPDI_MASK 0xFFFF0000 +#define XHDMIPHY1_DRP_CONTROL_DRPDI_SHIFT 16 +/* 0x050, 0x054, 0x058, 0x05C, 0x064: DRP_STATUS_CH[1-4], DRP_STATUS_COMMON */ +#define XHDMIPHY1_DRP_STATUS_DRPO_MASK 0x0FFFF +#define XHDMIPHY1_DRP_STATUS_DRPRDY_MASK 0x10000 +#define XHDMIPHY1_DRP_STATUS_DRPBUSY_MASK 0x20000 +/* 0x068: CPLL CAL PERIOD */ +#define XHDMIPHY1_CPLL_CAL_PERIOD_MASK 0x3FFFF +/* 0x06C: CPLL CAL TOLERANCE */ +#define XHDMIPHY1_CPLL_CAL_TOL_MASK 0x3FFFF +/* 0x068: GPI */ +#define XHDMIPHY1_TX_GPI_MASK(Ch) \ + (0x01 << (Ch - 1)) +#define XHDMIPHY1_RX_GPI_MASK(Ch) \ + (0x10 << (Ch - 1)) +/* 0x06C: GPO */ +#define XHDMIPHY1_TX_GPO_MASK(Ch) \ + (0x01 << (Ch - 1)) +#define XHDMIPHY1_TX_GPO_MASK_ALL(NCh) \ + ((NCh == 3) ? 0x7 : 0xF) +#define XHDMIPHY1_TX_GPO_SHIFT 0 +#define XHDMIPHY1_RX_GPO_MASK(Ch) \ + (0x10 << (Ch - 1)) +#define XHDMIPHY1_RX_GPO_MASK_ALL(NCh) \ + ((NCh == 3) ? 0x70 : 0xF0) +#define XHDMIPHY1_RX_GPO_SHIFT 4 +/* 0x070: TX_CONTROL */ +#define XHDMIPHY1_TX_CONTROL_TX8B10BEN_MASK(Ch) \ + (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_CONTROL_TX8B10BEN_ALL_MASK \ + (XHDMIPHY1_TX_CONTROL_TX8B10BEN_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TX_CONTROL_TX8B10BEN_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TX_CONTROL_TX8B10BEN_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TX_CONTROL_TX8B10BEN_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_TX_CONTROL_TXPOLARITY_MASK(Ch) \ + (0x02 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_CONTROL_TXPOLARITY_ALL_MASK \ + (XHDMIPHY1_TX_CONTROL_TXPOLARITY_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TX_CONTROL_TXPOLARITY_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TX_CONTROL_TXPOLARITY_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TX_CONTROL_TXPOLARITY_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_TX_CONTROL_TXPRBSSEL_MASK(Ch) \ + (0x5C << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_CONTROL_TXPRBSSEL_ALL_MASK \ + (XHDMIPHY1_TX_CONTROL_TXPRBSSEL_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TX_CONTROL_TXPRBSSEL_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TX_CONTROL_TXPRBSSEL_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TX_CONTROL_TXPRBSSEL_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_TX_CONTROL_TXPRBSSEL_SHIFT(Ch) \ + (2 + (8 * (Ch - 1))) +#define XHDMIPHY1_TX_CONTROL_TXPRBSFORCEERR_MASK(Ch) \ + (0x20 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_CONTROL_TXPRBSFORCEERR_ALL_MASK \ + (XHDMIPHY1_TX_CONTROL_TXPRBSFORCEERR_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_TX_CONTROL_TXPRBSFORCEERR_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_TX_CONTROL_TXPRBSFORCEERR_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_TX_CONTROL_TXPRBSFORCEERR_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +/* 0x074: TX_BUFFER_BYPASS */ +#define XHDMIPHY1_TX_BUFFER_BYPASS_TXPHDLYRESET_MASK(Ch) \ + (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_BUFFER_BYPASS_TXPHALIGN_MASK(Ch) \ + (0x02 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_BUFFER_BYPASS_TXPHALIGNEN_MASK(Ch) \ + (0x04 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_BUFFER_BYPASS_TXPHDLYPD_MASK(Ch) \ + (0x08 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_BUFFER_BYPASS_TXPHINIT_MASK(Ch) \ + (0x10 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_BUFFER_BYPASS_TXDLYRESET_MASK(Ch) \ + (0x20 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_BUFFER_BYPASS_TXDLYBYPASS_MASK(Ch) \ + (0x40 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_BUFFER_BYPASS_TXDLYEN_MASK(Ch) \ + (0x80 << (8 * (Ch - 1))) +/* 0x078: TX_STATUS */ +#define XHDMIPHY1_TX_STATUS_TXPHALIGNDONE_MASK(Ch) \ + (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_STATUS_TXPHINITDONE_MASK(Ch) \ + (0x02 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_STATUS_TXDLYRESETDONE_MASK(Ch) \ + (0x04 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_STATUS_TXBUFSTATUS_MASK(Ch) \ + (0x18 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_STATUS_TXBUFSTATUS_SHIFT(Ch) \ + (3 + (8 * (Ch - 1))) +/* 0x07C, 0x080: TX_DRIVER_CH12, TX_DRIVER_CH34 */ +#define XHDMIPHY1_TX_DRIVER_TXDIFFCTRL_MASK(Ch) \ + (0x000F << (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_DRIVER_TXDIFFCTRL_SHIFT(Ch) \ + (16 * ((Ch - 1) % 2)) +#define XHDMIPHY1_TX_DRIVER_TXELECIDLE_MASK(Ch) \ + (0x0010 << (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_DRIVER_TXELECIDLE_SHIFT(Ch) \ + (4 + (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_DRIVER_TXINHIBIT_MASK(Ch) \ + (0x0020 << (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_DRIVER_TXINHIBIT_SHIFT(Ch) \ + (5 + (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_DRIVER_TXPOSTCURSOR_MASK(Ch) \ + (0x07C0 << (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_DRIVER_TXPOSTCURSOR_SHIFT(Ch) \ + (6 + (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_DRIVER_TXPRECURSOR_MASK(Ch) \ + (0xF800 << (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_DRIVER_TXPRECURSOR_SHIFT(Ch) \ + (11 + (16 * ((Ch - 1) % 2))) +/* 0x084: TX_DRIVER_EXT */ +#define XHDMIPHY1_TX_DRIVER_EXT_TXDIFFCTRL_MASK(Ch) \ + (0x0001 << (8 * (Ch - 1))) +#define XHDMIPHY1_TX_DRIVER_EXT_TXDIFFCTRL_SHIFT(Ch) \ + (8 * (Ch - 1)) +/* 0x08C, 0x090: TX_RATE_CH12, TX_RATE_CH34 */ +#define XHDMIPHY1_TX_RATE_MASK(Ch) \ + (0x00FF << (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_TX_RATE_SHIFT(Ch) \ + (16 * ((Ch - 1) % 2)) +/* 0x098, 0x09C: RX_RATE_CH12, RX_RATE_CH34 */ +#define XHDMIPHY1_RX_RATE_MASK(Ch) \ + (0x00FF << (16 * ((Ch - 1) % 2))) +#define XHDMIPHY1_RX_RATE_SHIFT(Ch) \ + (16 * ((Ch - 1) % 2)) +/* 0x100: RX_CONTROL */ +#define XHDMIPHY1_RX_CONTROL_RX8B10BEN_MASK(Ch) \ + (0x02 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_CONTROL_RX8B10BEN_ALL_MASK \ + (XHDMIPHY1_RX_CONTROL_RX8B10BEN_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_RX_CONTROL_RX8B10BEN_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_RX_CONTROL_RX8B10BEN_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_RX_CONTROL_RX8B10BEN_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_RX_CONTROL_RXPOLARITY_MASK(Ch) \ + (0x04 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_CONTROL_RXPOLARITY_ALL_MASK \ + (XHDMIPHY1_RX_CONTROL_RXPOLARITY_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_RX_CONTROL_RXPOLARITY_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_RX_CONTROL_RXPOLARITY_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_RX_CONTROL_RXPOLARITY_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_RX_CONTROL_RXPRBSCNTRESET_MASK(Ch) \ + (0x08 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_CONTROL_RXPRBSSEL_MASK(Ch) \ + (0xF0 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_CONTROL_RXPRBSSEL_ALL_MASK \ + (XHDMIPHY1_RX_CONTROL_RXPRBSSEL_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_RX_CONTROL_RXPRBSSEL_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_RX_CONTROL_RXPRBSSEL_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_RX_CONTROL_RXPRBSSEL_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +#define XHDMIPHY1_RX_CONTROL_RXPRBSSEL_SHIFT(Ch) \ + (4 + (8 * (Ch - 1))) +/* 0x104: RX_STATUS */ +#define XHDMIPHY1_RX_STATUS_RXCDRLOCK_MASK(Ch) \ + (0x1 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_STATUS_RXBUFSTATUS_MASK(Ch) \ + (0xE << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_STATUS_RXBUFSTATUS_SHIFT(Ch) \ + (1 + (8 * (Ch - 1))) +/* 0x104: RX_EQ_CDR */ +#define XHDMIPHY1_RX_CONTROL_RXLPMEN_MASK(Ch) \ + (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_STATUS_RXCDRHOLD_MASK(Ch) \ + (0x02 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_STATUS_RXOSOVRDEN_MASK(Ch) \ + (0x04 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_STATUS_RXLPMLFKLOVRDEN_MASK(Ch) \ + (0x08 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_STATUS_RXLPMHFOVRDEN_MASK(Ch) \ + (0x10 << (8 * (Ch - 1))) +#define XHDMIPHY1_RX_CONTROL_RXLPMEN_ALL_MASK \ + (XHDMIPHY1_RX_CONTROL_RXLPMEN_MASK(XHDMIPHY1_CHANNEL_ID_CH1) | \ + XHDMIPHY1_RX_CONTROL_RXLPMEN_MASK(XHDMIPHY1_CHANNEL_ID_CH2) | \ + XHDMIPHY1_RX_CONTROL_RXLPMEN_MASK(XHDMIPHY1_CHANNEL_ID_CH3) | \ + XHDMIPHY1_RX_CONTROL_RXLPMEN_MASK(XHDMIPHY1_CHANNEL_ID_CH4)) +/* 0x110, 0x114, 0x118, 0x11C: INTR_EN, INTR_DIS, INTR_MASK, INTR_STS */ +#define XHDMIPHY1_INTR_TXRESETDONE_MASK 0x00000001 +#define XHDMIPHY1_INTR_RXRESETDONE_MASK 0x00000002 +#define XHDMIPHY1_INTR_CPLL_LOCK_MASK 0x00000004 +#define XHDMIPHY1_INTR_QPLL0_LOCK_MASK 0x00000008 +#define XHDMIPHY1_INTR_LCPLL_LOCK_MASK 0x00000008 +#define XHDMIPHY1_INTR_TXALIGNDONE_MASK 0x00000010 +#define XHDMIPHY1_INTR_QPLL1_LOCK_MASK 0x00000020 +#define XHDMIPHY1_INTR_RPLL_LOCK_MASK 0x00000020 +#define XHDMIPHY1_INTR_TXCLKDETFREQCHANGE_MASK 0x00000040 +#define XHDMIPHY1_INTR_RXCLKDETFREQCHANGE_MASK 0x00000080 +#define XHDMIPHY1_INTR_TXMMCMUSRCLK_LOCK_MASK 0x00000200 +#define XHDMIPHY1_INTR_RXMMCMUSRCLK_LOCK_MASK 0x00000400 +#define XHDMIPHY1_INTR_TXGPO_RE_MASK 0x00000800 +#define XHDMIPHY1_INTR_RXGPO_RE_MASK 0x00001000 +#define XHDMIPHY1_INTR_TXTMRTIMEOUT_MASK 0x40000000 +#define XHDMIPHY1_INTR_RXTMRTIMEOUT_MASK 0x80000000 +#define XHDMIPHY1_INTR_QPLL_LOCK_MASK XHDMIPHY1_INTR_QPLL0_LOCK_MASK +/* 0x120, 0x140: MMCM_TXUSRCLK_CTRL, MMCM_RXUSRCLK_CTRL */ +#define XHDMIPHY1_MMCM_USRCLK_CTRL_CFG_NEW_MASK 0x01 +#define XHDMIPHY1_MMCM_USRCLK_CTRL_RST_MASK 0x02 +#define XHDMIPHY1_MMCM_USRCLK_CTRL_CFG_SUCCESS_MASK 0x10 +#define XHDMIPHY1_MMCM_USRCLK_CTRL_LOCKED_MASK 0x200 +#define XHDMIPHY1_MMCM_USRCLK_CTRL_PWRDWN_MASK 0x400 +#define XHDMIPHY1_MMCM_USRCLK_CTRL_LOCKED_MASK_MASK 0x800 +#define XHDMIPHY1_MMCM_USRCLK_CTRL_CLKINSEL_MASK 0x1000 +/* 0x124, 0x144: MMCM_TXUSRCLK_REG1, MMCM_RXUSRCLK_REG1 */ +#define XHDMIPHY1_MMCM_USRCLK_REG1_DIVCLK_MASK \ + 0x00000FF +#define XHDMIPHY1_MMCM_USRCLK_REG1_CLKFBOUT_MULT_MASK \ + 0x000FF00 +#define XHDMIPHY1_MMCM_USRCLK_REG1_CLKFBOUT_MULT_SHIFT \ + 8 +#define XHDMIPHY1_MMCM_USRCLK_REG1_CLKFBOUT_FRAC_MASK \ + 0x3FF0000 +#define XHDMIPHY1_MMCM_USRCLK_REG1_CLKFBOUT_FRAC_SHIFT \ + 16 +/* 0x128, 0x148: MMCM_TXUSRCLK_REG2, MMCM_RXUSRCLK_REG2 */ +#define XHDMIPHY1_MMCM_USRCLK_REG2_DIVCLK_MASK \ + 0x00000FF +#define XHDMIPHY1_MMCM_USRCLK_REG2_CLKOUT0_FRAC_MASK \ + 0x3FF0000 +#define XHDMIPHY1_MMCM_USRCLK_REG2_CLKOUT0_FRAC_SHIFT \ + 16 +/* 0x12C, 0x130, 0x14C, 0x150: MMCM_TXUSRCLK_REG[3,4], MMCM_RXUSRCLK_REG[3,4]*/ +#define XHDMIPHY1_MMCM_USRCLK_REG34_DIVCLK_MASK \ + 0x00000FF +/* 0x134, 0x154: BUFGT_TXUSRCLK, BUFGT_RXUSRCLK */ +#define XHDMIPHY1_BUFGGT_XXUSRCLK_CLR_MASK 0x1 +#define XHDMIPHY1_BUFGGT_XXUSRCLK_DIV_MASK 0xE +#define XHDMIPHY1_BUFGGT_XXUSRCLK_DIV_SHIFT 1 +/* 0x138, 0x158: MISC_TXUSRCLK_REG, MISC_RXUSERCLK_REG */ +#define XHDMIPHY1_MISC_XXUSRCLK_CKOUT1_OEN_MASK 0x1 +#define XHDMIPHY1_MISC_XXUSRCLK_REFCLK_CEB_MASK 0x2 +/* 0x200: CLKDET_CTRL */ +#define XHDMIPHY1_CLKDET_CTRL_RUN_MASK 0x1 +#define XHDMIPHY1_CLKDET_CTRL_TX_TMR_CLR_MASK 0x2 +#define XHDMIPHY1_CLKDET_CTRL_RX_TMR_CLR_MASK 0x4 +#define XHDMIPHY1_CLKDET_CTRL_TX_FREQ_RST_MASK 0x8 +#define XHDMIPHY1_CLKDET_CTRL_RX_FREQ_RST_MASK 0x10 +#define XHDMIPHY1_CLKDET_CTRL_FREQ_LOCK_THRESH_MASK 0x1FE0 +#define XHDMIPHY1_CLKDET_CTRL_FREQ_LOCK_THRESH_SHIFT 5 +/* 0x204: CLKDET_STAT */ +#define XHDMIPHY1_CLKDET_STAT_TX_FREQ_ZERO_MASK 0x1 +#define XHDMIPHY1_CLKDET_STAT_RX_FREQ_ZERO_MASK 0x2 +#define XHDMIPHY1_CLKDET_STAT_TX_REFCLK_LOCK_MASK 0x3 +#define XHDMIPHY1_CLKDET_STAT_TX_REFCLK_LOCK_CAP_MASK 0x4 +/* 0x300: DRU_CTRL */ +#define XHDMIPHY1_DRU_CTRL_RST_MASK(Ch) (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_DRU_CTRL_EN_MASK(Ch) (0x02 << (8 * (Ch - 1))) +/* 0x304: DRU_STAT */ +#define XHDMIPHY1_DRU_STAT_ACTIVE_MASK(Ch) (0x01 << (8 * (Ch - 1))) +#define XHDMIPHY1_DRU_STAT_VERSION_MASK 0xFF000000 +#define XHDMIPHY1_DRU_STAT_VERSION_SHIFT 24 +/* 0x30C, 0x318, 0x324, 0x330: DRU_CFREQ_H_CH[1-4] */ +#define XHDMIPHY1_DRU_CFREQ_H_MASK 0x1F +/* 0x310, 0x31C, 0x328, 0x334: DRU_GAIN_CH[1-4] */ +#define XHDMIPHY1_DRU_GAIN_G1_MASK 0x00001F +#define XHDMIPHY1_DRU_GAIN_G1_SHIFT 0 +#define XHDMIPHY1_DRU_GAIN_G1_P_MASK 0x001F00 +#define XHDMIPHY1_DRU_GAIN_G1_P_SHIFT 8 +#define XHDMIPHY1_DRU_GAIN_G2_MASK 0x1F0000 +#define XHDMIPHY1_DRU_GAIN_G2_SHIFT 16 +/* 0x340 TMDS PATGEN */ +#define XHDMIPHY1_PATGEN_CTRL_ENABLE_MASK 0x80000000 +#define XHDMIPHY1_PATGEN_CTRL_ENABLE_SHIFT 31 +#define XHDMIPHY1_PATGEN_CTRL_RATIO_MASK 0x7 +#define XHDMIPHY1_PATGEN_CTRL_RATIO_SHIFT 0 +/* @} */ + +/******************* Macros (Inline Functions) Definitions ********************/ + +/** @name Register access macro definitions. + * @{ + */ +#define XHdmiphy1_In32 Xil_In32 +#define XHdmiphy1_Out32 Xil_Out32 +/* @} */ + +/******************************************************************************/ +/** + * This is a low-level function that reads from the specified register. + * + * @param BaseAddress is the base address of the device. + * @param RegOffset is the register offset to be read from. + * + * @return The 32-bit value of the specified register. + * + * @note C-style signature: + * u32 XHdmiphy1_ReadReg(u32 BaseAddress, u32 RegOffset) + * +*******************************************************************************/ +#define XHdmiphy1_ReadReg(BaseAddress, RegOffset) \ + XHdmiphy1_In32((BaseAddress) + (RegOffset)) + +/******************************************************************************/ +/** + * This is a low-level function that writes to the specified register. + * + * @param BaseAddress is the base address of the device. + * @param RegOffset is the register offset to write to. + * @param Data is the 32-bit data to write to the specified register. + * + * @return None. + * + * @note C-style signature: + * void XHdmiphy1_WriteReg(u32 BaseAddress, u32 RegOffset, u32 Data) + * +*******************************************************************************/ +#define XHdmiphy1_WriteReg(BaseAddress, RegOffset, Data) \ + XHdmiphy1_Out32((BaseAddress) + (RegOffset), (Data)) + +#ifdef __cplusplus +} +#endif + +#endif /* XHDMIPHY1_HW_H_ */ +/** @} */ diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_i.c b/hdmi/phy-xilinx-vphy/xhdmiphy1_i.c new file mode 100644 index 0000000..580a4c3 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_i.c @@ -0,0 +1,1875 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_i.c + * + * Contains generic APIs that are locally called or used within the + * HDMIPHY driver. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include +#include "xstatus.h" +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" +#include "xhdmiphy1_hdmi.h" +#include +#include "xhdmiphy1_gt.h" + +/**************************** Function Prototypes *****************************/ + + +/**************************** Function Definitions ****************************/ + +/*****************************************************************************/ +/** +* This function will set the channel IDs to correspond with the supplied +* channel ID based on the protocol. HDMI uses 3 channels; This ID +* translation is done to allow other functions to operate iteratively over +* multiple channels. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param ChId is the channel ID used to determine the indices. +* @param Id0 is a pointer to the start channel ID to set. +* @param Id1 is a pointer to the end channel ID to set. +* +* @return None. +* +* @note The contents of Id0 and Id1 will be set according to ChId. +* +******************************************************************************/ +void XHdmiphy1_Ch2Ids(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 *Id0, u8 *Id1) +{ + u8 Channels = 4; + + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + *Id0 = XHDMIPHY1_CHANNEL_ID_CH1; + if ((XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) || + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX))) { + if (InstancePtr->Config.UseGtAsTxTmdsClk == TRUE) { + *Id1 = XHDMIPHY1_CHANNEL_ID_CH4; + } + else { + *Id1 = XHDMIPHY1_CHANNEL_ID_CH3; + } + } + else { + Channels = ((InstancePtr->Config.TxChannels >= + InstancePtr->Config.RxChannels) ? + InstancePtr->Config.TxChannels : + InstancePtr->Config.RxChannels); + + if (Channels == 1) { + *Id1 = XHDMIPHY1_CHANNEL_ID_CH1; + } + else if (Channels == 2) { + *Id1 = XHDMIPHY1_CHANNEL_ID_CH2; + } + else if (Channels == 3) { + *Id1 = XHDMIPHY1_CHANNEL_ID_CH3; + } + else { + *Id1 = XHDMIPHY1_CHANNEL_ID_CH4; + } + } + } + else if (ChId == XHDMIPHY1_CHANNEL_ID_CMNA) { + *Id0 = XHDMIPHY1_CHANNEL_ID_CMN0; + if ((InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE3) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTHE4) || + (InstancePtr->Config.XcvrType == XHDMIPHY1_GT_TYPE_GTYE4)) { + *Id1 = XHDMIPHY1_CHANNEL_ID_CMN1; + } + else { + *Id1 = XHDMIPHY1_CHANNEL_ID_CMN0; + } + } + else { + *Id0 = *Id1 = ChId; + } +} + +/*****************************************************************************/ +/** +* This function will set the current RX/TX configuration over DRP. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID for which to write the settings for. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_DirReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 Status = XST_SUCCESS; + u8 Id, Id0, Id1; + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + if (Dir == XHDMIPHY1_DIR_TX) { + Status |= XHdmiphy1_TxChReconfig(InstancePtr, QuadId, + (XHdmiphy1_ChannelId)Id); + } + else { + Status |= XHdmiphy1_RxChReconfig(InstancePtr, QuadId, + (XHdmiphy1_ChannelId)Id); + } + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + break; + } + } + + XHdmiphy1_LogWrite(InstancePtr, (Dir == XHDMIPHY1_DIR_TX) ? + XHDMIPHY1_LOG_EVT_GT_TX_RECONFIG : XHDMIPHY1_LOG_EVT_GT_RX_RECONFIG, 1); + + return Status; +} + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +/*****************************************************************************/ +/** +* This function writes the current software configuration for the reference +* clock selections to hardware for the specified quad on all channels. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_WriteCfgRefClkSelReg(XHdmiphy1 *InstancePtr, u8 QuadId) +{ + u32 RegVal = 0; + XHdmiphy1_Channel *ChPtr; + XHdmiphy1_GtType GtType = InstancePtr->Config.XcvrType; + + /* Point to the first channel since settings apply to all channels. */ + ChPtr = &InstancePtr->Quads[QuadId].Ch1; + + /* PllRefClkSel. */ + /* - QPLL0. */ + RegVal &= ~XHDMIPHY1_REF_CLK_SEL_QPLL0_MASK; + RegVal = InstancePtr->Quads[QuadId].Cmn0.PllRefClkSel; + /* - CPLL. */ + RegVal &= ~XHDMIPHY1_REF_CLK_SEL_CPLL_MASK; + RegVal |= (ChPtr->CpllRefClkSel << XHDMIPHY1_REF_CLK_SEL_CPLL_SHIFT); + if ((GtType == XHDMIPHY1_GT_TYPE_GTHE3) || + (GtType == XHDMIPHY1_GT_TYPE_GTHE4) || + (GtType == XHDMIPHY1_GT_TYPE_GTYE4)) { + /* - QPLL1. */ + RegVal &= ~XHDMIPHY1_REF_CLK_SEL_QPLL1_MASK; + RegVal |= (InstancePtr->Quads[QuadId].Cmn1.PllRefClkSel << + XHDMIPHY1_REF_CLK_SEL_QPLL1_SHIFT); + } + + /* SysClkDataSel. PLLCLKSEL */ + RegVal &= ~XHDMIPHY1_REF_CLK_SEL_SYSCLKSEL_MASK; + /* - TXSYSCLKSEL[0]. TXPLLCLKSEL*/ + RegVal |= (ChPtr->TxDataRefClkSel << + XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_DATA_SHIFT(GtType)) & + XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_DATA_MASK(GtType); + /* - RXSYSCLKSEL[0]. RXPLLCLKSEL*/ + RegVal |= (ChPtr->RxDataRefClkSel << + XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_DATA_SHIFT(GtType)) & + XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_DATA_MASK(GtType); + + /* SysClkOutSel. */ + /* - TXSYSCLKSEL[1]. */ + RegVal |= (ChPtr->TxOutRefClkSel << + XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_OUT_SHIFT(GtType)) & + XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_OUT_MASK(GtType); + /* - RXSYSCLKSEL[1]. */ + RegVal |= (ChPtr->RxOutRefClkSel << + XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_OUT_SHIFT(GtType)) & + XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_OUT_MASK(GtType); + + /* Write to hardware. */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_REF_CLK_SEL_REG,RegVal); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* Configure the PLL reference clock selection for the specified channel(s). +* This is applied to both direction to the software configuration only. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param SysClkDataSel is the reference clock selection to configure. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_CfgPllRefClkSel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_PllRefClkSelType RefClkSel) +{ + u8 Id, Id0, Id1; + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)].PllRefClkSel = + RefClkSel; + } +} + +/*****************************************************************************/ +/** +* Configure the SYSCLKDATA reference clock selection for the direction. Same +* configuration applies to all channels in the quad. This is applied to the +* software configuration only. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param SysClkDataSel is the reference clock selection to configure. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_CfgSysClkDataSel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, + XHdmiphy1_SysClkDataSelType SysClkDataSel) +{ + XHdmiphy1_Channel *ChPtr; + u8 Id, Id0, Id1; + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + /* Select in software - same for all channels. */ + for (Id = Id0; Id <= Id1; Id++) { + ChPtr = &InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]; + ChPtr->DataRefClkSel[Dir] = SysClkDataSel; + } +} + +/*****************************************************************************/ +/** +* Configure the SYSCLKOUT reference clock selection for the direction. Same +* configuration applies to all channels in the quad. This is applied to the +* software configuration only. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param SysClkOutSel is the reference clock selection to configure. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_CfgSysClkOutSel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, + XHdmiphy1_SysClkOutSelType SysClkOutSel) +{ + XHdmiphy1_Channel *ChPtr; + u8 Id, Id0, Id1; + + XHdmiphy1_Ch2Ids(InstancePtr, XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + /* Select in software - same for all channels. */ + for (Id = Id0; Id <= Id1; Id++) { + ChPtr = &InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)]; + ChPtr->OutRefClkSel[Dir] = SysClkOutSel; + } +} +#endif + +/*****************************************************************************/ +/** +* Obtain the reconfiguration channel ID for given PLL type +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param PllType is the PLL type being used by the channel. +* +* @return The Channel ID to be used for reconfiguration +* +* @note None. +* +******************************************************************************/ +XHdmiphy1_ChannelId XHdmiphy1_GetRcfgChId(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, XHdmiphy1_PllType PllType) +{ + XHdmiphy1_ChannelId ChId; + + /* Suppress Warning Messages */ + InstancePtr = InstancePtr; + QuadId = QuadId; + Dir = Dir; + + /* Determine which channel(s) to operate on. */ + switch (PllType) { + case XHDMIPHY1_PLL_TYPE_QPLL: + case XHDMIPHY1_PLL_TYPE_QPLL0: + case XHDMIPHY1_PLL_TYPE_LCPLL: + ChId = XHDMIPHY1_CHANNEL_ID_CMN0; + break; + case XHDMIPHY1_PLL_TYPE_QPLL1: + case XHDMIPHY1_PLL_TYPE_RPLL: + ChId = XHDMIPHY1_CHANNEL_ID_CMN1; + break; + default: + ChId = XHDMIPHY1_CHANNEL_ID_CHA; + break; + } + + return ChId; +} + +/*****************************************************************************/ +/** +* This function will check the status of a PLL lock on the specified channel. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID which to operate on. +* +* @return +* - XST_SUCCESS if the specified PLL is locked. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_IsPllLocked(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + u32 RegVal; + u32 MaskVal; +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + XHdmiphy1_PllType TxPllType; + XHdmiphy1_PllType RxPllType; +#endif + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (ChId == XHDMIPHY1_CHANNEL_ID_CMN0) { +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_QPLL0_MASK; +#else + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_LCPLL_MASK; +#endif + } + else if (ChId == XHDMIPHY1_CHANNEL_ID_CMN1) { +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_QPLL1_MASK; +#else + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_RPLL_MASK; + } + else { + /* This will result to XST_FAILURE */ + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_CPLL_ALL_MASK; +#endif + } +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + else if (ChId == XHDMIPHY1_CHANNEL_ID_CMNA) { + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_QPLL0_MASK | + XHDMIPHY1_PLL_LOCK_STATUS_QPLL1_MASK; + } + else if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + TxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, + XHDMIPHY1_DIR_TX, XHDMIPHY1_CHANNEL_ID_CH1); + RxPllType = XHdmiphy1_GetPllType(InstancePtr, 0, + XHDMIPHY1_DIR_RX, XHDMIPHY1_CHANNEL_ID_CH1); + if (RxPllType == XHDMIPHY1_PLL_TYPE_CPLL && + XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)) { + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_CPLL_HDMI_MASK; + } + else if (TxPllType == XHDMIPHY1_PLL_TYPE_CPLL && + XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) { + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_CPLL_HDMI_MASK; + } + else { + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_CPLL_ALL_MASK; + } + } + else { + MaskVal = XHDMIPHY1_PLL_LOCK_STATUS_CPLL_MASK(ChId); + } +#endif + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_PLL_LOCK_STATUS_REG); + + if ((RegVal & MaskVal) == MaskVal) { + return XST_SUCCESS; + } + + return XST_FAILURE; +} + + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +/*****************************************************************************/ +/** +* Obtain the current reference clock frequency for the quad based on the +* reference clock type. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param RefClkType is the type to obtain the clock selection for. +* +* @return The current reference clock frequency for the quad for the +* specified type selection. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_GetQuadRefClkFreq(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_PllRefClkSelType RefClkType) +{ + u32 FreqHz; + + u8 RefClkIndex = RefClkType - XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTREFCLK0; + + FreqHz = (RefClkType > XHDMIPHY1_PLL_REFCLKSEL_TYPE_GTGREFCLK) ? 0 : + InstancePtr->Quads[QuadId].RefClkHz[RefClkIndex]; + + return FreqHz; +} + +/*****************************************************************************/ +/** +* Obtain the current [RT]XSYSCLKSEL[0] configuration. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param ChId is the channel ID which to operate on. +* +* @return The current [RT]XSYSCLKSEL[0] selection. +* +* @note None. +* +******************************************************************************/ +XHdmiphy1_SysClkDataSelType XHdmiphy1_GetSysClkDataSel(XHdmiphy1 *InstancePtr, + u8 QuadId, XHdmiphy1_DirectionType Dir, XHdmiphy1_ChannelId ChId) +{ + u32 Sel; + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + ChId = ChId; + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_REF_CLK_SEL_REG); + + if (Dir == XHDMIPHY1_DIR_TX) { + /* Synchronize software configuration to hardware. */ + Sel = RegVal & XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_DATA_MASK( + InstancePtr->Config.XcvrType); + Sel >>= XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_DATA_SHIFT( + InstancePtr->Config.XcvrType); + } + else { + /* Synchronize software configuration to hardware. */ + Sel = RegVal & XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_DATA_MASK( + InstancePtr->Config.XcvrType); + Sel >>= XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_DATA_SHIFT( + InstancePtr->Config.XcvrType); + } + + return (XHdmiphy1_SysClkDataSelType) Sel; +} + +/*****************************************************************************/ +/** +* Obtain the current [RT]XSYSCLKSEL[1] configuration. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param ChId is the channel ID which to operate on. +* +* @return The current [RT]XSYSCLKSEL[1] selection. +* +* @note None. +* +******************************************************************************/ +XHdmiphy1_SysClkOutSelType XHdmiphy1_GetSysClkOutSel(XHdmiphy1 *InstancePtr, + u8 QuadId, XHdmiphy1_DirectionType Dir, XHdmiphy1_ChannelId ChId) +{ + u32 Sel; + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + ChId = ChId; + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_REF_CLK_SEL_REG); + + if (Dir == XHDMIPHY1_DIR_TX) { + /* Synchronize software configuration to hardware. */ + Sel = RegVal & XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_OUT_MASK( + InstancePtr->Config.XcvrType); + Sel >>= XHDMIPHY1_REF_CLK_SEL_TXSYSCLKSEL_OUT_SHIFT( + InstancePtr->Config.XcvrType); + } + else { + /* Synchronize software configuration to hardware. */ + Sel = RegVal & XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_OUT_MASK( + InstancePtr->Config.XcvrType); + Sel >>= XHDMIPHY1_REF_CLK_SEL_RXSYSCLKSEL_OUT_SHIFT( + InstancePtr->Config.XcvrType); + } + + return (XHdmiphy1_SysClkOutSelType)Sel; +} + +/*****************************************************************************/ +/** +* This function will reset and enable the Video PHY's user core logic. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID which to operate on. +* @param Dir is an indicator for TX or RX. +* @param Hold is an indicator whether to "hold" the reset if set to 1. +* If set to 0: reset, then enable. +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_GtUserRdyEnable(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Hold) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_TX_INIT_REG; + + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_TX_INIT_USERRDY_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_TX_INIT_USERRDY_MASK(ChId); + } + } + else { + RegOffset = XHDMIPHY1_RX_INIT_REG; + if (ChId == XHDMIPHY1_CHANNEL_ID_CHA) { + MaskVal = XHDMIPHY1_RX_INIT_USERRDY_ALL_MASK; + } + else { + MaskVal = XHDMIPHY1_RX_INIT_USERRDY_MASK(ChId); + } + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + /* Assert reset. */ + RegVal |= MaskVal; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); + + if (!Hold) { + /* De-assert reset. */ + RegVal &= ~MaskVal; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + RegOffset, RegVal); + } + + return XST_SUCCESS; +} +#else +/*****************************************************************************/ +/** +* This function will set the TXRATE or RXRATE port to select the GT Wizard +* configuration +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for TX or RX. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_SetGtLineRateCfg(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 RegVal; + u32 MaskVal; + u32 ShiftVal; + u32 RegOffset; + u16 LRCfgVal; + XHdmiphy1_PllType PllType; + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, Dir, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* Extract Line Rate Config Value */ + if (PllType == XHDMIPHY1_PLL_TYPE_LCPLL) { + LRCfgVal = InstancePtr->Quads[QuadId].Lcpll.LineRateCfg; + } + else { /* RPLL */ + LRCfgVal = InstancePtr->Quads[QuadId].Rpll.LineRateCfg; + } + + if (Dir == XHDMIPHY1_DIR_TX) { + if ((ChId == XHDMIPHY1_CHANNEL_ID_CH1) || + (ChId == XHDMIPHY1_CHANNEL_ID_CH2)) { + RegOffset = XHDMIPHY1_TX_RATE_CH12_REG; + } + else { + RegOffset = XHDMIPHY1_TX_RATE_CH34_REG; + } + MaskVal = XHDMIPHY1_TX_RATE_MASK(ChId); + ShiftVal = XHDMIPHY1_TX_RATE_SHIFT(ChId); + } + else{ + if ((ChId == XHDMIPHY1_CHANNEL_ID_CH1) || + (ChId == XHDMIPHY1_CHANNEL_ID_CH2)) { + RegOffset = XHDMIPHY1_RX_RATE_CH12_REG; + } + else { + RegOffset = XHDMIPHY1_RX_RATE_CH34_REG; + } + MaskVal = XHDMIPHY1_RX_RATE_MASK(ChId); + ShiftVal = XHDMIPHY1_RX_RATE_SHIFT(ChId); + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + RegVal &= ~MaskVal; + RegVal |= (LRCfgVal << ShiftVal); + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); +} + +/*****************************************************************************/ +/** +* This function will get the TXRATE or RXRATE port to select the GT Wizard +* configuration +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for TX or RX. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +u16 XHdmiphy1_GetGtLineRateCfg(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 RegVal; + u32 MaskVal; + u32 ShiftVal; + u32 RegOffset; + u16 LRCfgVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + if ((ChId == XHDMIPHY1_CHANNEL_ID_CH1) || + (ChId == XHDMIPHY1_CHANNEL_ID_CH2)) { + RegOffset = XHDMIPHY1_TX_RATE_CH12_REG; + } + else { + RegOffset = XHDMIPHY1_TX_RATE_CH34_REG; + } + MaskVal = XHDMIPHY1_TX_RATE_MASK(ChId); + ShiftVal = XHDMIPHY1_TX_RATE_SHIFT(ChId); + } + else{ + if ((ChId == XHDMIPHY1_CHANNEL_ID_CH1) || + (ChId == XHDMIPHY1_CHANNEL_ID_CH2)) { + RegOffset = XHDMIPHY1_RX_RATE_CH12_REG; + } + else { + RegOffset = XHDMIPHY1_RX_RATE_CH34_REG; + } + MaskVal = XHDMIPHY1_RX_RATE_MASK(ChId); + ShiftVal = XHDMIPHY1_RX_RATE_SHIFT(ChId); + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + RegVal &= MaskVal; + LRCfgVal = (u16)(RegVal >> ShiftVal); + + return LRCfgVal; +} + +/*****************************************************************************/ +/** +* This function will set the GPI ports to the GT Wizard +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Set Set=TRUE; Clear=FALSE +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_SetGpi(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Set) +{ + u32 RegVal; + u32 MaskVal = 0; + u8 Id, Id0, Id1; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + /* Read GPI Register*/ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_GT_DBG_GPI_REG); + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + if (Dir == XHDMIPHY1_DIR_TX) { + MaskVal |= XHDMIPHY1_TX_GPI_MASK(Id); + } + else { + MaskVal |= XHDMIPHY1_RX_GPI_MASK(Id); + } + } + + /* Construct Register Value */ + if (Set) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } + + /* Write GPI Register*/ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_GT_DBG_GPI_REG, RegVal); +} + +/*****************************************************************************/ +/** +* This function will get the GPI ports value from the GT Wizard +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for TX or RX. +* +* @return Value. +* +* @note None. +* +******************************************************************************/ +u8 XHdmiphy1_GetGpo(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + ChId = ChId; + + /* Read GPI Register*/ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_GT_DBG_GPO_REG); + + if (Dir == XHDMIPHY1_DIR_TX) { + return ((RegVal & + XHDMIPHY1_TX_GPO_MASK_ALL(InstancePtr->Config.TxChannels)) + >> XHDMIPHY1_TX_GPO_SHIFT); + } + else { + return ((RegVal & + XHDMIPHY1_RX_GPO_MASK_ALL(InstancePtr->Config.RxChannels)) + >> XHDMIPHY1_RX_GPO_SHIFT); + } +} + +/*****************************************************************************/ +/** +* This function will set the (TX|RX) MSTRESET port of the GT +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Reset Set=TRUE; Clear=FALSE +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_GtMstReset(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Reset) +{ + u32 RegOffsetCtrl; + u32 RegVal; + u32 MaskVal = 0; + u8 Id, Id0, Id1; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + MaskVal |= XHDMIPHY1_TXRX_MSTRESET_MASK(Id); + } + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffsetCtrl = XHDMIPHY1_TX_INIT_REG; + } + else { + RegOffsetCtrl = XHDMIPHY1_RX_INIT_REG; + } + + /* Read TX|RX INIT Register*/ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + RegOffsetCtrl); + + /* Construct Register Value */ + if (Reset) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } + + /* Write TX|RX INIT Register*/ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + RegOffsetCtrl, RegVal); +} + +/*****************************************************************************/ +/** +* This function will will check the current CFG setting and compare +* it with the next CFG value +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Reset Set=TRUE; Clear=FALSE +* +* @return TRUE if Current and Next CFG are the same +* FALSE if Current and Next CFG are different +* +* @note None. +* +******************************************************************************/ +u8 XHdmiphy1_CheckLineRateCfg(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u16 CurrCfgVal, LRCfgVal; + XHdmiphy1_PllType PllType; + + /* Determine PLL type. */ + PllType = XHdmiphy1_GetPllType(InstancePtr, 0, Dir, + XHDMIPHY1_CHANNEL_ID_CH1); + + /* Extract Line Rate Config Value */ + if (PllType == XHDMIPHY1_PLL_TYPE_LCPLL) { + LRCfgVal = InstancePtr->Quads[QuadId].Lcpll.LineRateCfg; + } + else { /* RPLL */ + LRCfgVal = InstancePtr->Quads[QuadId].Rpll.LineRateCfg; + } + + /* Get current line rate configuration value */ + CurrCfgVal = XHdmiphy1_GetGtLineRateCfg(InstancePtr, QuadId, ChId, Dir); + + if (CurrCfgVal != LRCfgVal) { + return FALSE; + } + else { + return TRUE; + } +} +#endif + +/*****************************************************************************/ +/** +* This function will reset the mixed-mode clock manager (MMCM) core. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Hold is an indicator whether to "hold" the reset if set to 1. +* If set to 0: reset, then enable. +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_MmcmReset(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u8 Hold) +{ + u32 RegOffsetCtrl; + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffsetCtrl = XHDMIPHY1_MMCM_TXUSRCLK_CTRL_REG; + } + else { + RegOffsetCtrl = XHDMIPHY1_MMCM_RXUSRCLK_CTRL_REG; + } + + /* Assert reset. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl); + RegVal |= XHDMIPHY1_MMCM_USRCLK_CTRL_RST_MASK; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl, RegVal); + + if (!Hold) { + /* De-assert reset. */ + RegVal &= ~XHDMIPHY1_MMCM_USRCLK_CTRL_RST_MASK; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl, + RegVal); + } +} + +/*****************************************************************************/ +/** +* This function will reset the mixed-mode clock manager (MMCM) core. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Enable is an indicator whether to "Enable" the locked mask +* if set to 1. If set to 0: reset, then disable. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_MmcmLockedMaskEnable(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u8 Enable) +{ + u32 RegOffsetCtrl; + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffsetCtrl = XHDMIPHY1_MMCM_TXUSRCLK_CTRL_REG; + } + else { + RegOffsetCtrl = XHDMIPHY1_MMCM_RXUSRCLK_CTRL_REG; + } + + /* Assert reset. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl); + RegVal |= XHDMIPHY1_MMCM_USRCLK_CTRL_LOCKED_MASK_MASK; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl, RegVal); + + if (!Enable) { + /* De-assert reset. */ + RegVal &= ~XHDMIPHY1_MMCM_USRCLK_CTRL_LOCKED_MASK_MASK; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl, + RegVal); + } +} + +/*****************************************************************************/ +/** +* This function will get the lock status of the mixed-mode clock +* manager (MMCM) core. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. + +* +* @return TRUE if Locked else FALSE. +* +* @note None. +* +******************************************************************************/ +u8 XHdmiphy1_MmcmLocked(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir) +{ + u32 RegOffsetCtrl; + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffsetCtrl = XHDMIPHY1_MMCM_TXUSRCLK_CTRL_REG; + } + else { + RegOffsetCtrl = XHDMIPHY1_MMCM_RXUSRCLK_CTRL_REG; + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + RegOffsetCtrl) & XHDMIPHY1_MMCM_USRCLK_CTRL_LOCKED_MASK; + + return (RegVal ? TRUE : FALSE); + +} + +/*****************************************************************************/ +/** +* This function will set the CLKINSEL port of the MMCM +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Sel CLKINSEL value +* 0 - CLKIN1 +* 1 - CLKIN2 +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_MmcmSetClkinsel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, XHdmiphy1_MmcmClkinsel Sel) +{ + u32 RegOffsetCtrl; + u32 RegVal; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffsetCtrl = XHDMIPHY1_MMCM_TXUSRCLK_CTRL_REG; + } + else { + RegOffsetCtrl = XHDMIPHY1_MMCM_RXUSRCLK_CTRL_REG; + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffsetCtrl); + + if (Sel == XHDMIPHY1_MMCM_CLKINSEL_CLKIN2) { + RegVal &= ~XHDMIPHY1_MMCM_USRCLK_CTRL_CLKINSEL_MASK; + } + else { + RegVal |= XHDMIPHY1_MMCM_USRCLK_CTRL_CLKINSEL_MASK; + } + + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + RegOffsetCtrl, RegVal); + +} + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +/*****************************************************************************/ +/** +* This function obtains the divider value of the BUFG_GT peripheral. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param Dir is an indicator for TX or RX +* @param Div 3-bit divider value +* +* @return None. +* +******************************************************************************/ +void XHdmiphy1_SetBufgGtDiv(XHdmiphy1 *InstancePtr, + XHdmiphy1_DirectionType Dir, u8 Div) +{ + u32 RegVal; + u32 RegOffset; + u8 Divider = Div; + + if (Divider == 0) { + Divider = 1; + } + else { + Divider = Divider - 1; + } + + + if (Dir == XHDMIPHY1_DIR_TX) { + RegOffset = XHDMIPHY1_BUFGGT_TXUSRCLK_REG; + } + else { + RegOffset = XHDMIPHY1_BUFGGT_RXUSRCLK_REG; + } + + /* Read BUFG_GT register. */ + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + RegVal &= ~XHDMIPHY1_BUFGGT_XXUSRCLK_DIV_MASK; + + /* Shift divider value to correct position. */ + Divider <<= XHDMIPHY1_BUFGGT_XXUSRCLK_DIV_SHIFT; + Divider &= XHDMIPHY1_BUFGGT_XXUSRCLK_DIV_MASK; + RegVal |= Divider; + + /* Write new value to BUFG_GT ctrl register. */ + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); +} + +/*****************************************************************************/ +/** +* This function will power down the specified GT PLL. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to power down the PLL for. +* @param Dir is an indicator for TX or RX. +* @param Hold is an indicator whether to "hold" the power down if set +* to 1. If set to 0: power down, then power back up. +* +* @return +* - XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_PowerDownGtPll(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 Hold) +{ + u32 MaskVal = 0; + u32 RegVal; + u8 Id, Id0, Id1; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if (XHDMIPHY1_ISCH(ChId)) { + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + } + else { + /* When powering down a QPLL, power down for all channels. */ + XHdmiphy1_Ch2Ids(InstancePtr, + XHDMIPHY1_CHANNEL_ID_CHA, &Id0, &Id1); + } + for (Id = Id0; Id <= Id1; Id++) { + if (ChId == XHDMIPHY1_CHANNEL_ID_CMN0) { + MaskVal |= XHDMIPHY1_POWERDOWN_CONTROL_QPLL0PD_MASK(Id); + } + else if (ChId == XHDMIPHY1_CHANNEL_ID_CMN1) { + MaskVal |= XHDMIPHY1_POWERDOWN_CONTROL_QPLL1PD_MASK(Id); + } + else if (ChId == XHDMIPHY1_CHANNEL_ID_CMNA) { + MaskVal |= XHDMIPHY1_POWERDOWN_CONTROL_QPLL0PD_MASK(Id) | + XHDMIPHY1_POWERDOWN_CONTROL_QPLL1PD_MASK(Id); + } + else { + MaskVal |= XHDMIPHY1_POWERDOWN_CONTROL_CPLLPD_MASK(Id); + } + } + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_POWERDOWN_CONTROL_REG); + RegVal |= MaskVal; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_POWERDOWN_CONTROL_REG, RegVal); + + if (!Hold) { + RegVal &= ~MaskVal; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_POWERDOWN_CONTROL_REG, RegVal); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function will try to find the necessary PLL divisor values to produce +* the configured line rate given the specified PLL input frequency. This will +* be done for all channels specified by ChId. +* This function is a wrapper for XHdmiphy1_PllCalculator. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to calculate the PLL values for. +* @param ChId is the channel ID to calculate the PLL values for. +* @param Dir is an indicator for TX or RX. +* @param PllClkInFreqHz is the PLL input frequency on which to base the +* calculations on. A value of 0 indicates to use the currently +* configured quad PLL reference clock. A non-zero value indicates +* to ignore what is currently configured in SW, and use a custom +* frequency instead. +* +* @return +* - XST_SUCCESS if valid PLL values were found to satisfy the +* constraints. +* - XST_FAILURE otherwise. +* +* @note If successful, the channel's PllParams structure will be +* modified with the valid PLL parameters. +* +******************************************************************************/ +u32 XHdmiphy1_ClkCalcParams(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + u32 PllClkInFreqHz) +{ + u32 Status = XST_SUCCESS; + u8 Id, Id0, Id1; + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + Status = XHdmiphy1_PllCalculator(InstancePtr, QuadId, + (XHdmiphy1_ChannelId)Id, Dir, PllClkInFreqHz); + if (Status != XST_SUCCESS) { + return Status; + } + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function will set the current output divider configuration over DRP. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID for which to write the settings for. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_OutDivReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u32 Status; + u8 Id; + u8 Id0; + u8 Id1; + + if (!XHDMIPHY1_ISCH(ChId)) { + ChId = XHDMIPHY1_CHANNEL_ID_CHA; + } + + XHdmiphy1_LogWrite(InstancePtr, (Dir == XHDMIPHY1_DIR_TX) ? + XHDMIPHY1_LOG_EVT_GT_TX_RECONFIG : XHDMIPHY1_LOG_EVT_GT_RX_RECONFIG, 0); + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + Status = XHdmiphy1_OutDivChReconfig(InstancePtr, QuadId, + (XHdmiphy1_ChannelId)Id, Dir); + if (Status != XST_SUCCESS) { + break; + } + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function will set the current clocking settings for each channel to +* hardware based on the configuration stored in the driver's instance. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID for which to write the settings for. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_ClkReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + u32 Status = XST_SUCCESS; + u8 Id; + u8 Id0; + u8 Id1; + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + if (XHDMIPHY1_ISCH(Id)) { + Status |= XHdmiphy1_ClkChReconfig(InstancePtr, QuadId, + (XHdmiphy1_ChannelId)Id); + } + else if (XHDMIPHY1_ISCMN(ChId)) { + if (((XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) || + (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX))) && + (InstancePtr->HdmiIsQpllPresent == FALSE)) { + XHdmiphy1_LogWrite(InstancePtr, XHDMIPHY1_LOG_EVT_NO_QPLL_ERR, + 1); + XHdmiphy1_ErrorHandler(InstancePtr); + Status = XST_FAILURE; + return Status; + } + Status |= XHdmiphy1_ClkCmnReconfig(InstancePtr, QuadId, + (XHdmiphy1_ChannelId)Id); + } + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + return Status; + } + } + + if (XHDMIPHY1_ISCH(ChId)) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_CPLL_RECONFIG, 1); + } + else if (XHDMIPHY1_ISCMN(ChId)) { + XHdmiphy1_LogWrite(InstancePtr, + XHDMIPHY1_LOG_EVT_QPLL_RECONFIG, 1); + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function will translate from XHdmiphy1_PllType to +* XHdmiphy1_SysClkDataSelType. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* +* @return The reference clock type based on the PLL selection. +* +* @note None. +* +******************************************************************************/ +XHdmiphy1_SysClkDataSelType Pll2SysClkData(XHdmiphy1_PllType PllSelect) +{ + return (PllSelect == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_SYSCLKSELDATA_TYPE_CPLL_OUTCLK : + (PllSelect == XHDMIPHY1_PLL_TYPE_QPLL) ? + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL_OUTCLK : + (PllSelect == XHDMIPHY1_PLL_TYPE_QPLL0) ? + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL0_OUTCLK : + /*(PllSelect == XHDMIPHY1_PLL_TYPE_QPLL1) ?*/ + XHDMIPHY1_SYSCLKSELDATA_TYPE_QPLL1_OUTCLK; +} + +/*****************************************************************************/ +/** +* This function will translate from XHdmiphy1_PllType to +* XHdmiphy1_SysClkOutSelType. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* +* @return The reference clock type based on the PLL selection. +* +* @note None. +* +******************************************************************************/ +XHdmiphy1_SysClkOutSelType Pll2SysClkOut(XHdmiphy1_PllType PllSelect) +{ + return (PllSelect == XHDMIPHY1_PLL_TYPE_CPLL) ? + XHDMIPHY1_SYSCLKSELOUT_TYPE_CPLL_REFCLK : + (PllSelect == XHDMIPHY1_PLL_TYPE_QPLL) ? + XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL_REFCLK : + (PllSelect == XHDMIPHY1_PLL_TYPE_QPLL0) ? + XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL0_REFCLK : + /*(PllSelect == XHDMIPHY1_PLL_TYPE_QPLL1) ?*/ + XHDMIPHY1_SYSCLKSELOUT_TYPE_QPLL1_REFCLK; +} + +/*****************************************************************************/ +/** +* This function will try to find the necessary PLL divisor values to produce +* the configured line rate given the specified PLL input frequency. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to calculate the PLL values for. +* @param ChId is the channel ID to calculate the PLL values for. +* @param Dir is an indicator for TX or RX. +* @param PllClkInFreqHz is the PLL input frequency on which to base the +* calculations on. A value of 0 indicates to use the currently +* configured quad PLL reference clock. A non-zero value indicates +* to ignore what is currently configured in SW, and use a custom +* frequency instead. +* +* @return +* - XST_SUCCESS if valid PLL values were found to satisfy the +* constraints. +* - XST_FAILURE otherwise. +* +* @note If successful, the channel's PllParams structure will be +* modified with the valid PLL parameters. +* +******************************************************************************/ +u32 XHdmiphy1_PllCalculator(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + u32 PllClkInFreqHz) +{ + u32 Status; + u64 PllClkOutFreqHz; + u64 CalcLineRateFreqHz; + u8 Id, Id0, Id1; + u64 PllClkInFreqHzIn = PllClkInFreqHz; + XHdmiphy1_Channel *PllPtr = &InstancePtr->Quads[QuadId]. + Plls[XHDMIPHY1_CH2IDX(ChId)]; + + if (!PllClkInFreqHzIn) { + PllClkInFreqHzIn = XHdmiphy1_GetQuadRefClkFreq(InstancePtr, + QuadId, + PllPtr->PllRefClkSel); + } + + /* Select PLL value table offsets. */ + const XHdmiphy1_GtPllDivs *GtPllDivs; + if (XHDMIPHY1_ISCH(ChId)) { + GtPllDivs = &InstancePtr->GtAdaptor->CpllDivs; + } + else { + GtPllDivs = &InstancePtr->GtAdaptor->QpllDivs; + } + + const u8 *M, *N1, *N2, *D; + for (N2 = GtPllDivs->N2; *N2 != 0; N2++) { + for (N1 = GtPllDivs->N1; *N1 != 0; N1++) { + for (M = GtPllDivs->M; *M != 0; M++) { + PllClkOutFreqHz = (PllClkInFreqHzIn * *N1 * *N2) / *M; + + /* Test if the calculated PLL clock is in the VCO range. */ + Status = XHdmiphy1_CheckPllOpRange(InstancePtr, QuadId, ChId, + PllClkOutFreqHz); + if (Status != XST_SUCCESS) { + continue; + } + + if ((XHDMIPHY1_ISCH(ChId))) { + PllClkOutFreqHz *= 2; + } + + /* Apply TX/RX divisor. */ + for (D = GtPllDivs->D; *D != 0; D++) { + CalcLineRateFreqHz = PllClkOutFreqHz / *D; + if (CalcLineRateFreqHz == PllPtr->LineRateHz) { + goto calc_done; + } + } + } + } + } + /* Calculation failed, don't change divisor settings. */ + return XST_FAILURE; + +calc_done: + /* Found the multiplier and divisor values for requested line rate. */ + PllPtr->PllParams.MRefClkDiv = *M; + PllPtr->PllParams.NFbDiv = *N1; + PllPtr->PllParams.N2FbDiv = *N2; /* Won't be used for QPLL.*/ + PllPtr->PllParams.IsLowerBand = 1; /* Won't be used for CPLL. */ + + if (XHDMIPHY1_ISCMN(ChId)) { + /* Same divisor value for all channels if using a QPLL. */ + ChId = XHDMIPHY1_CHANNEL_ID_CHA; + } + + XHdmiphy1_Ch2Ids(InstancePtr, ChId, &Id0, &Id1); + for (Id = Id0; Id <= Id1; Id++) { + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(Id)].OutDiv[Dir] = + *D; + if (Dir == XHDMIPHY1_DIR_RX) { + XHdmiphy1_CfgSetCdr(InstancePtr,\ + QuadId, (XHdmiphy1_ChannelId)Id); + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function calculates the PLL VCO operating frequency. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* +* @return PLL VCO frequency in Hz +* +* @note None. +* +******************************************************************************/ +u64 XHdmiphy1_GetPllVcoFreqHz(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + u64 PllxVcoRateHz; + u64 PllRefClkHz; + XHdmiphy1_Channel *PllPtr = &InstancePtr->Quads[QuadId]. + Plls[XHDMIPHY1_CH2IDX(ChId)]; + + if (Dir == XHDMIPHY1_DIR_TX) { + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_TX)) { + PllRefClkHz = InstancePtr->HdmiTxRefClkHz; + } + else { + PllRefClkHz = XHdmiphy1_GetQuadRefClkFreq(InstancePtr, + QuadId, + PllPtr->PllRefClkSel); + } + } + else { + if (XHdmiphy1_IsHDMI(InstancePtr, XHDMIPHY1_DIR_RX)) { + if (InstancePtr->HdmiRxDruIsEnabled) { + PllRefClkHz = + XHdmiphy1_DruGetRefClkFreqHz(InstancePtr); + } + else { + PllRefClkHz = InstancePtr->HdmiRxRefClkHz; + } + } + else { + PllRefClkHz = XHdmiphy1_GetQuadRefClkFreq(InstancePtr, + QuadId, + PllPtr->PllRefClkSel); + } + } + + PllxVcoRateHz = (u64)(PllRefClkHz * + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(ChId)]. + PllParams.N1FbDiv * + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(ChId)]. + PllParams.N2FbDiv) / + InstancePtr->Quads[QuadId].Plls[XHDMIPHY1_CH2IDX(ChId)]. + PllParams.MRefClkDiv; + + return PllxVcoRateHz; +} + +/*****************************************************************************/ +/** +* This function returns the number of active reference clock sources +* based in the CFG +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* +* @return No of active REFCLK sources +* +* @note None. +* +******************************************************************************/ +u8 XHdmiphy1_GetRefClkSourcesCount(XHdmiphy1 *InstancePtr) +{ + u8 RefClkNum = 0; + u8 RefClkNumMax = 5; + XHdmiphy1_PllRefClkSelType RefClkSel[RefClkNumMax]; + XHdmiphy1_PllRefClkSelType RefClkSelTemp[RefClkNumMax]; + u8 i, j, Match; + + /* TxRefClkSel */ + RefClkSel[0] = (InstancePtr->Config.TxProtocol != + XHDMIPHY1_PROTOCOL_NONE) ? + InstancePtr->Config.TxRefClkSel : 99; + /* RxRefClkSel */ + RefClkSel[1] = (InstancePtr->Config.RxProtocol != + XHDMIPHY1_PROTOCOL_NONE) ? + InstancePtr->Config.RxRefClkSel : 99; + /* DruRefClkSel */ + RefClkSel[2] = (InstancePtr->Config.DruIsPresent) ? + InstancePtr->Config.DruRefClkSel : 99; + /* TxFrlRefClkSel */ + RefClkSel[3] = (InstancePtr->Config.TxProtocol == + XHDMIPHY1_PROTOCOL_HDMI21) ? + InstancePtr->Config.TxFrlRefClkSel : 99; + /* RxFrlRefClkSel */ + RefClkSel[4] = (InstancePtr->Config.RxProtocol == + XHDMIPHY1_PROTOCOL_HDMI21) ? + InstancePtr->Config.RxFrlRefClkSel : 99; + + /* Initialize Unique RefClk holder */ + for (i=0; iGtAdaptor->CfgSetCdr(InstancePtr, QuadId, ChId); +} + +/*****************************************************************************/ +/** +* This function is a transceiver adaptor to check if a given PLL output +* frequency is within the operating range of the PLL for the GT type. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param PllClkOutFreqHz is the frequency to check. +* +* @return +* - XST_SUCCESS if the frequency resides within the PLL's range. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_CheckPllOpRange(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, + u64 PllClkOutFreqHz) +{ + return InstancePtr->GtAdaptor->CheckPllOpRange(InstancePtr, + QuadId, ChId, + PllClkOutFreqHz); +} + +/*****************************************************************************/ +/** +* This function is a transceiver adaptor to set the output divider logic for +* a given channel. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for RX or TX. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_OutDivChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir) +{ + return InstancePtr->GtAdaptor->OutDivChReconfig(InstancePtr, QuadId, + ChId, Dir); +} + +/*****************************************************************************/ +/** +* This function is a transceiver adaptor to configure the channel +* clock settings. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_ClkChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + return InstancePtr->GtAdaptor->ClkChReconfig(InstancePtr, QuadId, ChId); +} + +/*****************************************************************************/ +/** +* This function is a transceiver adaptor to configure the common channel +* clock settings. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param CmnId is the common channel ID to operate on. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_ClkCmnReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + return InstancePtr->GtAdaptor->ClkCmnReconfig(InstancePtr, QuadId, ChId); +} + +/*****************************************************************************/ +/** +* This function is a transceiver adaptor to configure the channel's +* RX settings. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_RxChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + return InstancePtr->GtAdaptor->RxChReconfig(InstancePtr, QuadId, ChId); +} + +/*****************************************************************************/ +/** +* This function is a transceiver adaptor to configure the channel's +* TX settings. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* +* @return +* - XST_SUCCESS if the configuration was successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_TxChReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId) +{ + return InstancePtr->GtAdaptor->TxChReconfig(InstancePtr, QuadId, ChId); +} +#endif + +/*****************************************************************************/ +/** +* This function checks if Instance is HDMI 2.0 or HDMI 2.1 +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* @param Dir is an indicator for RX or TX. +* +* @return TRUE if HDMI 2.0 or 2.1 else FALSE. +* +* @note None. +* +******************************************************************************/ +u8 XHdmiphy1_IsHDMI(XHdmiphy1 *InstancePtr, XHdmiphy1_DirectionType Dir) +{ + if (Dir == XHDMIPHY1_DIR_TX) { + if ((InstancePtr->Config.TxProtocol == XHDMIPHY1_PROTOCOL_HDMI) || + (InstancePtr->Config.TxProtocol == XHDMIPHY1_PROTOCOL_HDMI21)) { + return TRUE; + } + } else { /* Dir == XHDMIPHY1_DIR_RX */ + if ((InstancePtr->Config.RxProtocol == XHDMIPHY1_PROTOCOL_HDMI) || + (InstancePtr->Config.RxProtocol == XHDMIPHY1_PROTOCOL_HDMI21)) { + return TRUE; + } + } + + return FALSE; +} + +/*****************************************************************************/ +/** +* This function is the error condition handler +* +* @param InstancePtr is a pointer to the HDMIPHY instance. +* @param ErrIrqType is the error type +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_ErrorHandler(XHdmiphy1 *InstancePtr) +{ + if (InstancePtr->ErrorCallback != NULL) { + InstancePtr->ErrorCallback(InstancePtr->ErrorRef); + } +} diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_i.h b/hdmi/phy-xilinx-vphy/xhdmiphy1_i.h new file mode 100644 index 0000000..103490a --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_i.h @@ -0,0 +1,171 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_i.h + * + * Contains generic APIs that are locally called or used within the + * HDMIPHY driver. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * + * @addtogroup xhdmiphy1_v1_0 + * @{ +*******************************************************************************/ + +#ifndef XHDMIPHY1_I_H_ +/* Prevent circular inclusions by using protection macros. */ +#define XHDMIPHY1_I_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************* Include Files ********************************/ + +#include "xil_assert.h" +#include "xhdmiphy1.h" +#include "xhdmiphy1_hw.h" +#include "xvidc.h" + +/****************************** Type Definitions ******************************/ + + +/**************************** Function Prototypes *****************************/ + + +void XHdmiphy1_Ch2Ids(XHdmiphy1 *InstancePtr, XHdmiphy1_ChannelId ChId, + u8 *Id0, u8 *Id1); +u32 XHdmiphy1_DirReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +XHdmiphy1_SysClkDataSelType Pll2SysClkData(XHdmiphy1_PllType PllSelect); +XHdmiphy1_SysClkOutSelType Pll2SysClkOut(XHdmiphy1_PllType PllSelect); +u32 XHdmiphy1_PllCalculator(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + u32 PllClkInFreqHz); + +/* xhdmiphy1.c: Channel configuration functions - setters. */ +u32 XHdmiphy1_WriteCfgRefClkSelReg(XHdmiphy1 *InstancePtr, u8 QuadId); +void XHdmiphy1_CfgPllRefClkSel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_PllRefClkSelType RefClkSel); +void XHdmiphy1_CfgSysClkDataSel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, XHdmiphy1_SysClkDataSelType SysClkDataSel); +void XHdmiphy1_CfgSysClkOutSel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, XHdmiphy1_SysClkOutSelType SysClkOutSel); + +u32 XHdmiphy1_ClkCalcParams(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + u32 PllClkInFreqHz); +u32 XHdmiphy1_OutDivReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +u32 XHdmiphy1_ClkReconfig(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +#endif + +/* xhdmiphy1.c: Channel configuration functions - getters. */ +XHdmiphy1_ChannelId XHdmiphy1_GetRcfgChId(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, XHdmiphy1_PllType PllType); +u32 XHdmiphy1_IsPllLocked(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId); +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +u32 XHdmiphy1_GetQuadRefClkFreq(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_PllRefClkSelType RefClkType); +XHdmiphy1_SysClkDataSelType XHdmiphy1_GetSysClkDataSel(XHdmiphy1 *InstancePtr, + u8 QuadId, XHdmiphy1_DirectionType Dir, XHdmiphy1_ChannelId ChId); +XHdmiphy1_SysClkOutSelType XHdmiphy1_GetSysClkOutSel(XHdmiphy1 *InstancePtr, + u8 QuadId, XHdmiphy1_DirectionType Dir, XHdmiphy1_ChannelId ChId); +u32 XHdmiphy1_GtUserRdyEnable(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Hold); +u32 XHdmiphy1_CfgCpllCalPeriodandTol(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, + u32 FreeRunClkFreq); +#else +void XHdmiphy1_SetGtLineRateCfg(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +u16 XHdmiphy1_GetGtLineRateCfg(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +void XHdmiphy1_SetGpi(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Set); +u8 XHdmiphy1_GetGpo(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +void XHdmiphy1_GtMstReset(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir, u8 Reset); +u8 XHdmiphy1_CheckLineRateCfg(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +#endif + +/* xhdmiphy1.c: GT/MMCM DRP access. */ +u32 XHdmiphy1_MmcmWriteParameters(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir); +void XHdmiphy1_MmcmReset(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u8 Hold); +void XHdmiphy1_MmcmLockedMaskEnable(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, u8 Enable); +u8 XHdmiphy1_MmcmLocked(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir); +void XHdmiphy1_MmcmSetClkinsel(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir, XHdmiphy1_MmcmClkinsel Sel); +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +void XHdmiphy1_SetBufgGtDiv(XHdmiphy1 *InstancePtr, + XHdmiphy1_DirectionType Dir, u8 Div); +/* xhdmiphy1.c Miscellaneous control. */ +u32 XHdmiphy1_PowerDownGtPll(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, u8 Hold); +#endif + +/* xhdmiphy1_intr.c: Interrupt handling functions. */ +void XHdmiphy1_SetIntrHandler(XHdmiphy1 *InstancePtr, + XHdmiphy1_IntrHandlerType HandlerType, + XHdmiphy1_IntrHandler CallbackFunc, void *CallbackRef); +void XHdmiphy1_IntrEnable(XHdmiphy1 *InstancePtr, + XHdmiphy1_IntrHandlerType Intr); +void XHdmiphy1_IntrDisable(XHdmiphy1 *InstancePtr, + XHdmiphy1_IntrHandlerType Intr); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) +u64 XHdmiphy1_GetPllVcoFreqHz(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_ChannelId ChId, XHdmiphy1_DirectionType Dir); +u8 XHdmiphy1_GetRefClkSourcesCount(XHdmiphy1 *InstancePtr); +#endif + +u8 XHdmiphy1_IsHDMI(XHdmiphy1 *InstancePtr, XHdmiphy1_DirectionType Dir); +void XHdmiphy1_HdmiTxTimerTimeoutHandler(XHdmiphy1 *InstancePtr); +void XHdmiphy1_HdmiRxTimerTimeoutHandler(XHdmiphy1 *InstancePtr); + +void XHdmiphy1_ErrorHandler(XHdmiphy1 *InstancePtr); + +/******************* Macros (Inline Functions) Definitions ********************/ + +#ifdef __cplusplus +} +#endif + +#endif /* XHDMIPHY1_I_H_ */ +/** @} */ diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_intr.c b/hdmi/phy-xilinx-vphy/xhdmiphy1_intr.c new file mode 100644 index 0000000..8e10289 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_intr.c @@ -0,0 +1,312 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_intr.c + * + * This file contains functions related to XHdmiphy1 interrupt handling. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" + +/**************************** Function Definitions ****************************/ + +/******************************************************************************/ +/** + * This function enables interrupts associated with the specified interrupt type + * + * @param InstancePtr is a pointer to the XHdmiphy1 instance. + * @param Intr is the interrupt type/mask to enable. + * + * @return None. + * + * @note None. +* +*******************************************************************************/ +void XHdmiphy1_IntrEnable(XHdmiphy1 *InstancePtr, + XHdmiphy1_IntrHandlerType Intr) +{ + u32 RegVal; + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_INTR_EN_REG); + RegVal |= Intr; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_INTR_EN_REG, + RegVal); +} + +/******************************************************************************/ +/** + * This function disabled interrupts associated with the specified interrupt + * type. + * + * @param InstancePtr is a pointer to the XHdmiphy1 instance. + * @param Intr is the interrupt type/mask to disable. + * + * @return None. + * + * @note None. + * +*******************************************************************************/ +void XHdmiphy1_IntrDisable(XHdmiphy1 *InstancePtr, + XHdmiphy1_IntrHandlerType Intr) +{ + u32 RegVal; + + RegVal = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_INTR_DIS_REG); + RegVal |= Intr; + XHdmiphy1_WriteReg(InstancePtr->Config.BaseAddr, XHDMIPHY1_INTR_DIS_REG, + RegVal); +} + +/******************************************************************************/ +/** + * This function installs a callback function for the specified handler type. + * + * @param InstancePtr is a pointer to the XHdmiphy1 instance. + * @param HandlerType is the interrupt handler type which specifies which + * interrupt event to attach the callback for. + * @param CallbackFunc is the address to the callback function. + * @param CallbackRef is the user data item that will be passed to the + * callback function when it is invoked. + * + * @return None. + * + * @note None. + * +*******************************************************************************/ +void XHdmiphy1_SetIntrHandler(XHdmiphy1 *InstancePtr, + XHdmiphy1_IntrHandlerType HandlerType, + XHdmiphy1_IntrHandler CallbackFunc, void *CallbackRef) +{ + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid((HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_TXRESET_DONE) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_RXRESET_DONE) || +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_CPLL_LOCK) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_QPLL_LOCK) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_TXALIGN_DONE) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_QPLL1_LOCK) || +#else + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_LCPLL_LOCK) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_RPLL_LOCK) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_TX_GPO_RISING_EDGE) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_RX_GPO_RISING_EDGE) || +#endif + (HandlerType == + XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE) || + (HandlerType == + XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT) || + (HandlerType == XHDMIPHY1_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT)); + Xil_AssertVoid(CallbackFunc != NULL); + Xil_AssertVoid(CallbackRef != NULL); + + switch (HandlerType) { + case XHDMIPHY1_INTR_HANDLER_TYPE_TXRESET_DONE: + InstancePtr->IntrTxResetDoneHandler = CallbackFunc; + InstancePtr->IntrTxResetDoneCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_RXRESET_DONE: + InstancePtr->IntrRxResetDoneHandler = CallbackFunc; + InstancePtr->IntrRxResetDoneCallbackRef = CallbackRef; + break; +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + case XHDMIPHY1_INTR_HANDLER_TYPE_CPLL_LOCK: + InstancePtr->IntrCpllLockHandler = CallbackFunc; + InstancePtr->IntrCpllLockCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_QPLL_LOCK: + InstancePtr->IntrQpllLockHandler = CallbackFunc; + InstancePtr->IntrQpllLockCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_TXALIGN_DONE: + InstancePtr->IntrTxAlignDoneHandler = CallbackFunc; + InstancePtr->IntrTxAlignDoneCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_QPLL1_LOCK: + InstancePtr->IntrQpll1LockHandler = CallbackFunc; + InstancePtr->IntrQpll1LockCallbackRef = CallbackRef; + break; +#else + case XHDMIPHY1_INTR_HANDLER_TYPE_TX_GPO_RISING_EDGE: + InstancePtr->IntrTxGpoRisingEdgeHandler = CallbackFunc; + InstancePtr->IntrTxGpoRisingEdgeCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_RX_GPO_RISING_EDGE: + InstancePtr->IntrRxGpoRisingEdgeHandler = CallbackFunc; + InstancePtr->IntrRxGpoRisingEdgeCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_LCPLL_LOCK: + InstancePtr->IntrLcpllLockHandler = CallbackFunc; + InstancePtr->IntrLcpllLockCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_RPLL_LOCK: + InstancePtr->IntrRpllLockHandler = CallbackFunc; + InstancePtr->IntrRpllLockCallbackRef = CallbackRef; + break; +#endif + case XHDMIPHY1_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE: + InstancePtr->IntrTxClkDetFreqChangeHandler = + CallbackFunc; + InstancePtr->IntrTxClkDetFreqChangeCallbackRef = + CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE: + InstancePtr->IntrRxClkDetFreqChangeHandler = + CallbackFunc; + InstancePtr->IntrRxClkDetFreqChangeCallbackRef = + CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE: + InstancePtr->IntrTxMmcmLockHandler = CallbackFunc; + InstancePtr->IntrTxMmcmLockCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE: + InstancePtr->IntrRxMmcmLockHandler = CallbackFunc; + InstancePtr->IntrRxMmcmLockCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT: + InstancePtr->IntrTxTmrTimeoutHandler = CallbackFunc; + InstancePtr->IntrTxTmrTimeoutCallbackRef = CallbackRef; + break; + case XHDMIPHY1_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT: + InstancePtr->IntrRxTmrTimeoutHandler = CallbackFunc; + InstancePtr->IntrRxTmrTimeoutCallbackRef = CallbackRef; + break; + default: + break; + } +} + +/******************************************************************************/ +/** + * This function is the interrupt handler for the XHdmiphy1 driver. It will + * detect what kind of interrupt has happened, and will invoke the appropriate + * callback function. + * + * @param InstancePtr is a pointer to the XHdmiphy1 instance. + * + * @return None. + * + * @note None. + * +*******************************************************************************/ +void XHdmiphy1_InterruptHandler(XHdmiphy1 *InstancePtr) +{ + u32 IntrStatus; + + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Determine what kind of interrupts have occurred. */ + IntrStatus = XHdmiphy1_ReadReg(InstancePtr->Config.BaseAddr, + XHDMIPHY1_INTR_STS_REG); + +#if (XPAR_HDMIPHY1_0_TRANSCEIVER != XHDMIPHY1_GTYE5) + if (IntrStatus & XHDMIPHY1_INTR_CPLL_LOCK_MASK) { + InstancePtr->IntrCpllLockHandler( + InstancePtr->IntrCpllLockCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_QPLL_LOCK_MASK) { + InstancePtr->IntrQpllLockHandler( + InstancePtr->IntrQpllLockCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_QPLL1_LOCK_MASK) { + InstancePtr->IntrQpll1LockHandler( + InstancePtr->IntrQpll1LockCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_TXRESETDONE_MASK) { + InstancePtr->IntrTxResetDoneHandler( + InstancePtr->IntrTxResetDoneCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_TXALIGNDONE_MASK) { + InstancePtr->IntrTxAlignDoneHandler( + InstancePtr->IntrTxAlignDoneCallbackRef); + } +#else + if (IntrStatus & XHDMIPHY1_INTR_TXGPO_RE_MASK) { + InstancePtr->IntrTxGpoRisingEdgeHandler( + InstancePtr->IntrTxGpoRisingEdgeCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_RXGPO_RE_MASK) { + InstancePtr->IntrRxGpoRisingEdgeHandler( + InstancePtr->IntrRxGpoRisingEdgeCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_LCPLL_LOCK_MASK) { + InstancePtr->IntrLcpllLockHandler( + InstancePtr->IntrLcpllLockCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_RPLL_LOCK_MASK) { + InstancePtr->IntrRpllLockHandler( + InstancePtr->IntrRpllLockCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_TXRESETDONE_MASK) { + InstancePtr->IntrTxResetDoneHandler( + InstancePtr->IntrTxResetDoneCallbackRef); + } +#endif + if (IntrStatus & XHDMIPHY1_INTR_RXRESETDONE_MASK) { + InstancePtr->IntrRxResetDoneHandler( + InstancePtr->IntrRxResetDoneCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_TXCLKDETFREQCHANGE_MASK) { + InstancePtr->IntrTxClkDetFreqChangeHandler( + InstancePtr->IntrTxClkDetFreqChangeCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_RXCLKDETFREQCHANGE_MASK) { + InstancePtr->IntrRxClkDetFreqChangeHandler( + InstancePtr->IntrRxClkDetFreqChangeCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_TXMMCMUSRCLK_LOCK_MASK) { + InstancePtr->IntrTxMmcmLockHandler( + InstancePtr->IntrTxMmcmLockCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_RXMMCMUSRCLK_LOCK_MASK) { + InstancePtr->IntrRxMmcmLockHandler( + InstancePtr->IntrRxMmcmLockCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_TXTMRTIMEOUT_MASK) { + InstancePtr->IntrTxTmrTimeoutHandler( + InstancePtr->IntrTxTmrTimeoutCallbackRef); + } + if (IntrStatus & XHDMIPHY1_INTR_RXTMRTIMEOUT_MASK) { + InstancePtr->IntrRxTmrTimeoutHandler( + InstancePtr->IntrRxTmrTimeoutCallbackRef); + } +} diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_log.c b/hdmi/phy-xilinx-vphy/xhdmiphy1_log.c new file mode 100644 index 0000000..1fa55bd --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_log.c @@ -0,0 +1,608 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1.c + * + * Contains a minimal set of functions for the XHdmiphy1 driver that allow + * access to all of the Video PHY core's functionality. See xhdmiphy1.h for a + * detailed description of the driver. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" + +/************************** Constant Definitions *****************************/ +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_WHITE "\x1b[37m" +#define ANSI_COLOR_RESET "\x1b[0m" + + +/**************************** Function Prototypes *****************************/ + +/**************************** Function Definitions ****************************/ + +/*****************************************************************************/ +/** +* This function will reset the driver's logginc mechanism. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_LogReset(XHdmiphy1 *InstancePtr) +{ +#ifdef XV_HDMIPHY1_LOG_ENABLE + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + + InstancePtr->Log.HeadIndex = 0; + InstancePtr->Log.TailIndex = 0; +#endif +} + +#ifdef XV_HDMIPHY1_LOG_ENABLE +/*****************************************************************************/ +/** +* This function will insert an event in the driver's logginc mechanism. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param Evt is the event type to log. +* @param Data is the associated data for the event. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XHdmiphy1_LogWrite(XHdmiphy1 *InstancePtr, XHdmiphy1_LogEvent Evt, + u8 Data) +{ + u64 TimeUnit = 0; + + if (InstancePtr->LogWriteCallback) { + TimeUnit = InstancePtr->LogWriteCallback(InstancePtr->LogWriteRef); + } + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Evt <= (XHDMIPHY1_LOG_EVT_DUMMY)); + Xil_AssertVoid(Data < 0xFF); + + /* Write data and event into log buffer */ + InstancePtr->Log.DataBuffer[InstancePtr->Log.HeadIndex] = + (Data << 8) | Evt; + InstancePtr->Log.TimeRecord[InstancePtr->Log.HeadIndex] = TimeUnit; + + /* Update head pointer if reached to end of the buffer */ + if (InstancePtr->Log.HeadIndex == + (u8)((sizeof(InstancePtr->Log.DataBuffer) / + sizeof(InstancePtr->Log.DataBuffer[0])) - 1)) { + /* Clear pointer */ + InstancePtr->Log.HeadIndex = 0; + } + else { + /* Increment pointer */ + InstancePtr->Log.HeadIndex++; + } + + /* Check tail pointer. When the two pointer are equal, then the buffer + * is full. In this case then increment the tail pointer as well to + * remove the oldest entry from the buffer. */ + if (InstancePtr->Log.TailIndex == InstancePtr->Log.HeadIndex) { + if (InstancePtr->Log.TailIndex == + (u8)((sizeof(InstancePtr->Log.DataBuffer) / + sizeof(InstancePtr->Log.DataBuffer[0])) - 1)) { + InstancePtr->Log.TailIndex = 0; + } + else { + InstancePtr->Log.TailIndex++; + } + } +} +#endif + +/*****************************************************************************/ +/** +* This function will read the last event from the log. +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* +* @return The log data. +* +* @note None. +* +******************************************************************************/ +u16 XHdmiphy1_LogRead(XHdmiphy1 *InstancePtr) +{ +#ifdef XV_HDMIPHY1_LOG_ENABLE + u16 Log; + + /* Verify argument. */ + Xil_AssertNonvoid(InstancePtr != NULL); + + /* Check if there is any data in the log */ + if (InstancePtr->Log.TailIndex == InstancePtr->Log.HeadIndex) { + Log = 0; + } + else { + Log = InstancePtr->Log.DataBuffer[InstancePtr->Log.TailIndex]; + + /* Increment tail pointer */ + if (InstancePtr->Log.TailIndex == + (u8)((sizeof(InstancePtr->Log.DataBuffer) / + sizeof(InstancePtr->Log.DataBuffer[0])) - 1)) { + InstancePtr->Log.TailIndex = 0; + } + else { + InstancePtr->Log.TailIndex++; + } + } + + return Log; +#endif +} + +/*****************************************************************************/ +/** +* This function will print the entire log to the passed buffer. +* +* @param InstancePtr is a pointer to the XVphy core instance. +* @param buff Buffer to print to +* @param buff_size size off buff passed +* +* @return number of bytes written to buff. +* +* @note None. +* +******************************************************************************/ +int XHdmiphy1_LogShow(XHdmiphy1 *InstancePtr, char *buff, int buff_size) +{ + int strSize = 0; +#ifdef XV_HDMIPHY1_LOG_ENABLE + u32 Log; + u8 Evt; + u8 Data; + u64 TimeUnit; + + /* Verify argument. */ + Xil_AssertVoid(InstancePtr != NULL); + + strSize = scnprintf(buff, buff_size, + "\r\n\n\nHDMIPHY log\r\n" \ + "------\r\n"); + + /* Read time record */ + TimeUnit = InstancePtr->Log.TimeRecord[InstancePtr->Log.TailIndex]; + + /* Read log data */ + Log = XHdmiphy1_LogRead(InstancePtr); + + while (Log != 0 && (buff_size - strSize) > 30 ) { + /* Event */ + Evt = Log & 0xff; + + /* Data */ + Data = (Log >> 8) & 0xFF; + + switch (Evt) { + case (XHDMIPHY1_LOG_EVT_NONE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT log end\r\n-------\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_QPLL_EN): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL enable (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_QPLL_RST): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL reset (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_CPLL_EN): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL enable (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_CPLL_RST): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL reset (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_TXPLL_EN): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX MMCM enable (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_TXPLL_RST): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX MMCM reset (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_RXPLL_EN): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX MMCM enable (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_RXPLL_RST): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX MMCM reset (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_GTRX_RST): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT RX reset (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_GTTX_RST): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT TX reset (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_VID_TX_RST): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Video TX reset (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_VID_RX_RST): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Video RX reset (%0d)\r\n", Data); + break; + case (XHDMIPHY1_LOG_EVT_TX_ALIGN): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX alignment done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX alignment start.\r\n."); + } + break; + case (XHDMIPHY1_LOG_EVT_TX_ALIGN_TMOUT): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX alignment watchdog timed out.\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_TX_TMR): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX timer event\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX timer load\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_RX_TMR): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX timer event\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX timer load\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_CPLL_RECONFIG): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL reconfig done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL reconfig start\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_GT_RECONFIG): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT reconfig done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT reconfig start\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_GT_TX_RECONFIG): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT TX reconfig done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT TX reconfig start\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_GT_RX_RECONFIG): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT RX reconfig done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT RX reconfig start\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_QPLL_RECONFIG): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL reconfig done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL reconfig start\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_INIT): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT init done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "GT init start\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_TXPLL_RECONFIG): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX MMCM reconfig done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX MMCM reconfig start\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_RXPLL_RECONFIG): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX MMCM reconfig done\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX MMCM reconfig start\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_QPLL_LOCK): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL lock\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "QPLL lost lock\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_CPLL_LOCK): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL lock\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "CPLL lost lock\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_LCPLL_LOCK): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "LCPLL lock\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "LCPLL lost lock\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_RPLL_LOCK): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RPLL lock\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RPLL lost lock\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_RXPLL_LOCK): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX MMCM lock\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX MMCM lost lock\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_TXPLL_LOCK): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX MMCM lock\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX MMCM lost lock\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_TX_RST_DONE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX reset done\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_RX_RST_DONE): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX reset done\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_TX_FREQ): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX frequency event\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_RX_FREQ): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX frequency event\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_DRU_EN): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX DRU enable\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX DRU disable\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_TXGPO_RE): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX GPO Rising Edge Detected\r\n"); + } else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX MSTRESET Toggled\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_RXGPO_RE): + if (Data == 1) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX GPO Rising Edge Detected\r\n"); + } else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX MSTRESET Toggled\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_FRL_RECONFIG): + if (Data == XHDMIPHY1_DIR_RX) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX FRL Reconfig\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX FRL Reconfig\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_TMDS_RECONFIG): + if (Data == XHDMIPHY1_DIR_RX) { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "RX TMDS Reconfig\r\n"); + } + else { + strSize += scnprintf(buff+strSize, buff_size-strSize, + "TX TMDS Reconfig\r\n"); + } + break; + case (XHDMIPHY1_LOG_EVT_1PPC_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! The HDMIPHY cannot support this video "); + strSize += scnprintf(buff+strSize, buff_size-strSize, + "format at PPC = 1\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_PPC_MSMTCH_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! HDMI TX SS PPC value, doesn't match with" + " HDMIPHY PPC value\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_VDCLK_HIGH_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! Video PHY cannot" + "support resolutions with video clock" + " > 148.5 MHz.\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_NO_DRU): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Warning: No DRU instance. "); + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Low resolution video isn't supported in this " + "design.\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_GT_QPLL_CFG_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! QPLL config not found!\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_GT_CPLL_CFG_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! CPLL config not found!\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_GT_LCPLL_CFG_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! LCPLL config not found!\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_GT_RPLL_CFG_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! RPLL config not found!\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_VD_NOT_SPRTD_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error: This video format " + "is not supported by this device\r\n"); + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Change to another format\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_MMCM_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! MMCM config not found!\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_HDMI20_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! The Video PHY doesn't " + "support HDMI 2.0 line rates\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_NO_QPLL_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! There's no QPLL instance in the design\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_DRU_CLK_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error: Wrong DRU REFCLK frequency detected\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_USRCLK_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! User Clock frequency is more than 300 MHz\r\n"); + break; + case (XHDMIPHY1_LOG_EVT_SPDGRDE_ERR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Error! %s: Line rates > 8.0 " + "Gbps are not supported by -1/-1LV devices" + ANSI_COLOR_RESET "\r\n", + (Data == XHDMIPHY1_DIR_RX) ? "RX" : "TX"); + break; + default: + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Unknown event %i\r\n", Evt); + break; + } + + if((buff_size - strSize) > 30) { + /* Read log data */ + Log = XHdmiphy1_LogRead(InstancePtr); + } else { + Log = 0; + } + } +#else + strSize += scnprintf(buff+strSize, buff_size-strSize, + "\r\nINFO:: HDMIPHY Log Feature is Disabled \r\n"); +#endif + return strSize; +} diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_mmcme5.c b/hdmi/phy-xilinx-vphy/xhdmiphy1_mmcme5.c new file mode 100644 index 0000000..f0f56d1 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_mmcme5.c @@ -0,0 +1,607 @@ +/******************************************************************************* + * + * + * Copyright (C) 2018 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ + +/******************************************************************************/ +/** + * + * @file xhdmiphy1_mmcme5.c + * + * Contains a minimal set of functions for the XHdmiphy1 driver that allow + * access to all of the Video PHY core's functionality. See xhdmiphy1.h for a + * detailed description of the driver. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include "xstatus.h" +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" +#if (XPAR_HDMIPHY1_0_TRANSCEIVER == XHDMIPHY1_GTYE5) + +/**************************** Function Prototypes *****************************/ +static u32 XHdmiphy1_Mmcme5DividerEncoding(XHdmiphy1_MmcmDivType DivType, + u16 Div); +static u32 XHdmiphy1_Mmcme5CpResEncoding(u16 Mult); +static u32 XHdmiphy1_Mmcme5LockReg1Reg2Encoding(u16 Mult); + +/************************** Constant Definitions ******************************/ + +/*****************************************************************************/ +/** +* This function returns the DRP encoding of ClkFbOutMult optimized for: +* Phase = 0; Dutycycle = 0.5; No Fractional division +* The calculations are based on XAPP888 +* +* @param Div is the divider to be encoded +* +* @return +* - Encoded Value for ClkReg1 [15: 0] +* - Encoded Value for ClkReg2 [31:16] +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_Mmcme5DividerEncoding(XHdmiphy1_MmcmDivType DivType, u16 Div) +{ + u32 DrpEnc; + u32 ClkReg1; + u32 ClkReg2; + u8 HiTime, LoTime; + u16 Divide = Div; + + if (DivType == XHDMIPHY1_MMCM_CLKOUT_DIVIDE) { + /* Div is an odd number */ + if (Div % 2) { + Divide = (Div / 2); + } + /* Div is an even number */ + else { + Divide = (Div / 2) + (Div % 2); + } + } + + HiTime = Divide / 2; + LoTime = HiTime; + + ClkReg2 = LoTime & 0xFF; + ClkReg2 |= (HiTime & 0xFF) << 8; + + if (DivType == XHDMIPHY1_MMCM_CLKFBOUT_MULT_F) { + ClkReg1 = (Divide % 2) ? 0x00001700 : 0x00001600; + } + else { + /* Div is an odd number */ + if (Div % 2) { + ClkReg1 = (Divide % 2) ? 0x0000BB00 : 0x0000BA00; + } + /* Div is an even number */ + else { + ClkReg1 = (Divide % 2) ? 0x00001B00 : 0x00001A00; + } + } + + DrpEnc = (ClkReg2 << 16) | ClkReg1; + + return DrpEnc; +} + +/*****************************************************************************/ +/** +* This function returns the DRP encoding of CP and Res optimized for: +* Phase = 0; Dutycycle = 0.5; BW = low; No Fractional division +* +* @param Mult is the divider to be encoded +* +* @return +* - [3:0] CP +* - [20:17] RES +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_Mmcme5CpResEncoding(u16 Mult) +{ + u32 DrpEnc; + u16 cp; + u16 res; + + switch (Mult) { + case 4: + cp = 5; res = 15; + break; + case 5: + cp = 6; res = 15; + break; + case 6: + cp = 7; res = 15; + break; + case 7: + cp = 13; res = 15; + break; + case 8: + cp = 14; res = 15; + break; + case 9: + cp = 15; res = 15; + break; + case 10: + cp = 14; res = 7; + break; + case 11: + cp = 15; res = 7; + break; + case 12 ... 13: + cp = 15; res = 11; + break; + case 14: + cp = 15; res = 13; + break; + case 15: + cp = 15; res = 3; + break; + case 16 ... 17: + cp = 14; res = 5; + break; + case 18 ... 19: + cp = 15; res = 5; + break; + case 20 ... 21: + cp = 15; res = 9; + break; + case 22 ... 23: + cp = 14; res = 14; + break; + case 24 ... 26: + cp = 15; res = 14; + break; + case 27 ... 28: + cp = 14; res = 1; + break; + case 29 ... 33: + cp = 15; res = 1; + break; + case 34 ... 37: + cp = 14; res = 6; + break; + case 38 ... 44: + cp = 15; res = 6; + break; + case 45 ... 57: + cp = 15; res = 10; + break; + case 58 ... 63: + cp = 13; res = 12; + break; + case 64 ... 70: + cp = 14; res = 12; + break; + case 71 ... 86: + cp = 15; res = 12; + break; + case 87 ... 93: + cp = 14; res = 2; + break; + case 94: + cp = 5; res = 15; + break; + case 95: + cp = 6; res = 15; + break; + case 96: + cp = 7; res = 15; + break; + case 97: + cp = 13; res = 15; + break; + case 98: + cp = 14; res = 15; + break; + case 99: + cp = 15; res = 15; + break; + case 100: + cp = 14; res = 7; + break; + case 101: + cp = 15; res = 7; + break; + case 102 ... 103: + cp = 15; res = 11; + break; + case 104: + cp = 15; res = 13; + break; + case 105: + cp = 15; res = 3; + break; + case 106 ... 107: + cp = 14; res = 5; + break; + case 108 ... 109: + cp = 15; res = 5; + break; + case 110 ... 111: + cp = 15; res = 9; + break; + case 112 ... 113: + cp = 14; res = 14; + break; + case 114 ... 116: + cp = 15; res = 14; + break; + case 117 ... 118: + cp = 14; res = 1; + break; + case 119 ... 123: + cp = 15; res = 1; + break; + case 124 ... 127: + cp = 14; res = 6; + break; + case 128 ... 134: + cp = 15; res = 6; + break; + case 135 ... 147: + cp = 15; res = 10; + break; + case 148 ... 153: + cp = 13; res = 12; + break; + case 154 ... 160: + cp = 14; res = 12; + break; + case 161 ... 176: + cp = 15; res = 12; + break; + case 177 ... 183: + cp = 14; res = 2; + break; + case 184 ... 200: + cp = 14; res = 4; + break; + case 201 ... 273: + cp = 15; res = 4; + break; + case 274 ... 300: + cp = 13; res = 8; + break; + case 301 ... 325: + cp = 14; res = 8; + break; + case 326 ... 432: + cp = 15; res = 8; + break; + default: + cp = 13; res = 8; + break; + } + + /* Construct the return value */ + DrpEnc = ((res & 0xf) << 17) | ((cp & 0xf) | 0x160); + + return DrpEnc; +} + +/*****************************************************************************/ +/** +* This function returns the DRP encoding of Lock Reg1 & Reg2 optimized for: +* Phase = 0; Dutycycle = 0.5; BW = low; No Fractional division +* +* @param Mult is the divider to be encoded +* +* @return +* - [15:0] Lock_1 Reg +* - [31:16] Lock_2 Reg +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_Mmcme5LockReg1Reg2Encoding(u16 Mult) +{ + u32 DrpEnc; + u16 Lock_1; + u16 Lock_2; + u16 lock_ref_dly; + u16 lock_fb_dly; + u16 lock_cnt; + u16 lock_sat_high = 9; + + switch (Mult) { + case 4: + lock_ref_dly = 4; + lock_fb_dly = 4; + lock_cnt = 1000; + break; + case 5: + lock_ref_dly = 6; + lock_fb_dly = 6; + lock_cnt = 1000; + break; + case 6 ... 7: + lock_ref_dly = 7; + lock_fb_dly = 7; + lock_cnt = 1000; + break; + case 8: + lock_ref_dly = 9; + lock_fb_dly = 9; + lock_cnt = 1000; + break; + case 9 ... 10: + lock_ref_dly = 10; + lock_fb_dly = 10; + lock_cnt = 1000; + break; + case 11: + lock_ref_dly = 11; + lock_fb_dly = 11; + lock_cnt = 1000; + break; + case 12: + lock_ref_dly = 13; + lock_fb_dly = 13; + lock_cnt = 1000; + break; + case 13 ... 14: + lock_ref_dly = 14; + lock_fb_dly = 14; + lock_cnt = 1000; + break; + case 15: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 900; + break; + case 16 ... 17: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 825; + break; + case 18: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 750; + break; + case 19 ... 20: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 700; + break; + case 21: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 650; + break; + case 22 ... 23: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 625; + break; + case 24: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 575; + break; + case 25: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 550; + break; + case 26 ... 28: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 525; + break; + case 29 ... 30: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 475; + break; + case 31: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 450; + break; + case 32 ... 33: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 425; + break; + case 34 ... 36: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 400; + break; + case 37: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 375; + break; + case 38 ... 40: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 350; + break; + case 41 ... 43: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 325; + break; + case 44 ... 47: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 300; + break; + case 48 ... 51: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 275; + break; + case 52 ... 205: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 950; + break; + case 206 ... 432: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 925; + break; + default: + lock_ref_dly = 16; + lock_fb_dly = 16; + lock_cnt = 250; + break; + } + + /* Construct Lock_1 Reg */ + Lock_1 = ((lock_fb_dly & 0x1F) << 10) | (lock_cnt & 0x3FF); + + /* Construct Lock_2 Reg */ + Lock_2 = ((lock_ref_dly & 0x1F) << 10) | (lock_sat_high & 0x3FF); + + /* Construct Return Value */ + DrpEnc = (Lock_2 << 16) | Lock_1; + + return DrpEnc; +} + +/*****************************************************************************/ +/** +* This function will write the mixed-mode clock manager (MMCM) values currently +* stored in the driver's instance structure to hardware . +* +* @param InstancePtr is a pointer to the XHdmiphy1 core instance. +* @param QuadId is the GT quad ID to operate on. +* @param Dir is an indicator for TX or RX. +* +* @return +* - XST_SUCCESS if the MMCM write was successful. +* - XST_FAILURE otherwise, if the configuration success bit did +* not go low. +* +* @note None. +* +******************************************************************************/ +u32 XHdmiphy1_MmcmWriteParameters(XHdmiphy1 *InstancePtr, u8 QuadId, + XHdmiphy1_DirectionType Dir) +{ + u8 ChId; + u32 DrpVal32; + u16 DrpRdVal; + XHdmiphy1_Mmcm *MmcmParams; + + ChId = (Dir == XHDMIPHY1_DIR_TX) ? + XHDMIPHY1_CHANNEL_ID_TXMMCM : + XHDMIPHY1_CHANNEL_ID_RXMMCM; + + MmcmParams = &InstancePtr->Quads[QuadId].Mmcm[Dir]; + + /* Check Parameters if has been Initialized */ + if (!MmcmParams->DivClkDivide && !MmcmParams->ClkFbOutMult && + !MmcmParams->ClkOut0Div && !MmcmParams->ClkOut1Div && + !MmcmParams->ClkOut2Div) { + return XST_FAILURE; + } + + /* Write CLKFBOUT_1 & CLKFBOUT_2 Values */ + DrpVal32 = XHdmiphy1_Mmcme5DividerEncoding(XHDMIPHY1_MMCM_CLKFBOUT_MULT_F, + MmcmParams->ClkFbOutMult); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x0C, + (u16)(DrpVal32 & 0xFFFF)); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x0D, + (u16)((DrpVal32 >> 16) & 0xFFFF)); + + /* Write DIVCLK_DIVIDE & DESKEW_2 Values */ + DrpVal32 = XHdmiphy1_Mmcme5DividerEncoding(XHDMIPHY1_MMCM_DIVCLK_DIVIDE, + MmcmParams->DivClkDivide) ; + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x21, + (u16)((DrpVal32 >> 16) & 0xFFFF)); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x20, + ((MmcmParams->DivClkDivide == 0) ? 0x0000 : + ((MmcmParams->DivClkDivide % 2) ? + 0x0400 : 0x0000))); + + /* Write CLKOUT0_1 & CLKOUT0_2 Values */ + DrpVal32 = XHdmiphy1_Mmcme5DividerEncoding(XHDMIPHY1_MMCM_CLKOUT_DIVIDE, + MmcmParams->ClkOut0Div); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x0E, + (u16)(DrpVal32 & 0xFFFF)); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x0F, + (u16)((DrpVal32 >> 16) & 0xFFFF)); + + /* Write CLKOUT1_1 & CLKOUT1_2 Values */ + DrpVal32 = XHdmiphy1_Mmcme5DividerEncoding(XHDMIPHY1_MMCM_CLKOUT_DIVIDE, + MmcmParams->ClkOut1Div); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x10, + (u16)(DrpVal32 & 0xFFFF)); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x11, + (u16)((DrpVal32 >> 16) & 0xFFFF)); + + /* Write CLKOUT2_1 & CLKOUT2_2 Values */ + DrpVal32 = XHdmiphy1_Mmcme5DividerEncoding(XHDMIPHY1_MMCM_CLKOUT_DIVIDE, + MmcmParams->ClkOut2Div); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x12, + (u16)(DrpVal32 & 0xFFFF)); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x13, + (u16)((DrpVal32 >> 16) & 0xFFFF)); + + /* Write CP & RES Values */ + DrpVal32 = XHdmiphy1_Mmcme5CpResEncoding(MmcmParams->ClkFbOutMult); + /* CP */ + DrpRdVal = XHdmiphy1_DrpRd(InstancePtr, QuadId, ChId, 0x1E, &DrpRdVal); + DrpRdVal &= ~(0xF); + + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x1E, + (u16)((DrpVal32 & 0xF) | DrpRdVal)); + + /* RES */ + DrpRdVal = XHdmiphy1_DrpRd(InstancePtr, QuadId, ChId, 0x2A, &DrpRdVal); + DrpRdVal &= ~(0x1E); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x2A, + (u16)(((DrpVal32 >> 15) & 0x1E) | DrpRdVal)); + + /* Write Lock Reg1 & Reg2 Values */ + DrpVal32 = XHdmiphy1_Mmcme5LockReg1Reg2Encoding(MmcmParams->ClkFbOutMult); + /* LOCK_1 */ + DrpRdVal = XHdmiphy1_DrpRd(InstancePtr, QuadId, ChId, 0x27, &DrpRdVal); + DrpRdVal &= ~(0x8000); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x27, + (u16)((DrpVal32 & 0x7FFF) | DrpRdVal)); + + /* LOCK_2 */ + DrpRdVal = XHdmiphy1_DrpRd(InstancePtr, QuadId, ChId, 0x28, &DrpRdVal); + DrpRdVal &= ~(0x8000); + XHdmiphy1_DrpWr(InstancePtr, QuadId, ChId, 0x28, + (u16)(((DrpVal32 >> 16) & 0x7FFF) | DrpRdVal)); + + return XST_SUCCESS; +} + +#endif diff --git a/hdmi/phy-xilinx-vphy/xhdmiphy1_sinit.c b/hdmi/phy-xilinx-vphy/xhdmiphy1_sinit.c new file mode 100644 index 0000000..a6c53b6 --- /dev/null +++ b/hdmi/phy-xilinx-vphy/xhdmiphy1_sinit.c @@ -0,0 +1,83 @@ +/******************************************************************************* + * + * + * Copyright (C) 2015, 2016, 2017 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + * +*******************************************************************************/ +/******************************************************************************/ +/** + * + * @file xhdmiphy1_sinit.c + * + * This file contains static initialization methods for the XHdmiphy1 driver. + * + * @note None. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ *            dd/mm/yy
+ * ----- ---- -------- -----------------------------------------------
+ * 1.0   gm   10/12/18 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include "xhdmiphy1.h" +#include "xhdmiphy1_i.h" + +/*************************** Variable Declarations ****************************/ + +#ifndef XPAR_XHDMIPHY1_NUM_INSTANCES +#define XPAR_XHDMIPHY1_NUM_INSTANCES 0 +#endif + +/** + * A table of configuration structures containing the configuration information + * for each Video PHY core in the system. + */ +extern XHdmiphy1_Config XHdmiphy1_ConfigTable[XPAR_XHDMIPHY1_NUM_INSTANCES]; + +/**************************** Function Definitions ****************************/ + +/******************************************************************************/ +/** + * This function looks for the device configuration based on the unique device + * ID. The table XHdmiphy1_ConfigTable[] contains the configuration information + * for each device in the system. + * + * @param DeviceId is the unique device ID of the device being looked up. + * + * @return A pointer to the configuration table entry corresponding to the + * given device ID, or NULL if no match is found. + * + * @note None. + * +*******************************************************************************/ +XHdmiphy1_Config *XHdmiphy1_LookupConfig(u16 DeviceId) +{ + XHdmiphy1_Config *CfgPtr = NULL; + u32 Index; + + for (Index = 0; Index < XPAR_XHDMIPHY1_NUM_INSTANCES; Index++) { + if (XHdmiphy1_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XHdmiphy1_ConfigTable[Index]; + break; + } + } + + return CfgPtr; +} diff --git a/hdmi/phy-xilinx-vphy/xil_types.h b/hdmi/phy-xilinx-vphy/xil_types.h index f1dc072..112fd87 100644 --- a/hdmi/phy-xilinx-vphy/xil_types.h +++ b/hdmi/phy-xilinx-vphy/xil_types.h @@ -18,7 +18,6 @@ * * @file xil_types.h * -* @addtogroup common_types Basic Data types for Xilinx® Software IP * * The xil_types.h file contains basic types for Xilinx software IP. These data types * are applicable for all processors supported by Xilinx. @@ -196,5 +195,4 @@ typedef void (*XExceptionHandler) (void *InstancePtr); #endif /* end of protection macro */ /** -* @} End of "addtogroup common_types". */ diff --git a/hdmi/phy-xilinx-vphy/xstatus.h b/hdmi/phy-xilinx-vphy/xstatus.h index 5f4835f..8815f06 100644 --- a/hdmi/phy-xilinx-vphy/xstatus.h +++ b/hdmi/phy-xilinx-vphy/xstatus.h @@ -18,7 +18,6 @@ * * @file xstatus.h * -* @addtogroup common_status_codes Xilinx® software status codes * * The xstatus.h file contains the Xilinx® software status codes.These codes are * used throughout the Xilinx device drivers. @@ -515,5 +514,4 @@ typedef s32 XStatus; #endif /* end of protection macro */ /** -* @} End of "addtogroup common_status_codes". */ diff --git a/hdmi/phy-xilinx-vphy/xtmrctr.c b/hdmi/phy-xilinx-vphy/xtmrctr.c index d7c743a..a114277 100644 --- a/hdmi/phy-xilinx-vphy/xtmrctr.c +++ b/hdmi/phy-xilinx-vphy/xtmrctr.c @@ -17,7 +17,6 @@ /** * * @file xtmrctr.c -* @addtogroup tmrctr_v4_0 * @{ * * Contains required functions for the XTmrCtr driver. diff --git a/hdmi/phy-xilinx-vphy/xtmrctr.h b/hdmi/phy-xilinx-vphy/xtmrctr.h index 5ea572b..c2023f3 100644 --- a/hdmi/phy-xilinx-vphy/xtmrctr.h +++ b/hdmi/phy-xilinx-vphy/xtmrctr.h @@ -17,7 +17,6 @@ /** * * @file xtmrctr.h -* @addtogroup tmrctr_v4_0 * @{ * @details * diff --git a/hdmi/phy-xilinx-vphy/xtmrctr_i.h b/hdmi/phy-xilinx-vphy/xtmrctr_i.h index b618131..7d9eaeb 100644 --- a/hdmi/phy-xilinx-vphy/xtmrctr_i.h +++ b/hdmi/phy-xilinx-vphy/xtmrctr_i.h @@ -17,7 +17,6 @@ /** * * @file xtmrctr_i.h -* @addtogroup tmrctr_v3_0 * @{ * * This file contains data which is shared between files internal to the diff --git a/hdmi/phy-xilinx-vphy/xtmrctr_intr.c b/hdmi/phy-xilinx-vphy/xtmrctr_intr.c index 7bcf237..c872020 100644 --- a/hdmi/phy-xilinx-vphy/xtmrctr_intr.c +++ b/hdmi/phy-xilinx-vphy/xtmrctr_intr.c @@ -17,7 +17,6 @@ /** * * @file xtmrctr_intr.c -* @addtogroup tmrctr_v4_0 * @{ * * Contains interrupt-related functions for the XTmrCtr component. diff --git a/hdmi/phy-xilinx-vphy/xtmrctr_l.c b/hdmi/phy-xilinx-vphy/xtmrctr_l.c index 08a039d..a51395f 100644 --- a/hdmi/phy-xilinx-vphy/xtmrctr_l.c +++ b/hdmi/phy-xilinx-vphy/xtmrctr_l.c @@ -17,7 +17,6 @@ /** * * @file xtmrctr_l.c -* @addtogroup tmrctr_v4_0 * @{ * * This file contains low-level driver functions that can be used to access the diff --git a/hdmi/phy-xilinx-vphy/xtmrctr_l.h b/hdmi/phy-xilinx-vphy/xtmrctr_l.h index ead95f8..3fa67b6 100644 --- a/hdmi/phy-xilinx-vphy/xtmrctr_l.h +++ b/hdmi/phy-xilinx-vphy/xtmrctr_l.h @@ -17,7 +17,6 @@ /** * * @file xtmrctr_l.h -* @addtogroup tmrctr_v4_0 * @{ * * This header file contains identifiers and low-level driver functions (or diff --git a/hdmi/phy-xilinx-vphy/xtmrctr_options.c b/hdmi/phy-xilinx-vphy/xtmrctr_options.c index e696edd..97d08cf 100644 --- a/hdmi/phy-xilinx-vphy/xtmrctr_options.c +++ b/hdmi/phy-xilinx-vphy/xtmrctr_options.c @@ -17,7 +17,6 @@ /** * * @file xtmrctr_options.c -* @addtogroup tmrctr_v4_0 * @{ * * Contains configuration options functions for the XTmrCtr component. diff --git a/hdmi/phy-xilinx-vphy/xtmrctr_sinit.c b/hdmi/phy-xilinx-vphy/xtmrctr_sinit.c index 48213d2..88cfa5c 100644 --- a/hdmi/phy-xilinx-vphy/xtmrctr_sinit.c +++ b/hdmi/phy-xilinx-vphy/xtmrctr_sinit.c @@ -17,7 +17,6 @@ /** * * @file xtmrctr_sinit.c -* @addtogroup tmrctr_v4_0 * @{ * * This file contains static initialization methods for the XTmrCtr driver. diff --git a/hdmi/phy-xilinx-vphy/xv_hdmic.c b/hdmi/phy-xilinx-vphy/xv_hdmic.c index 9d16af7..5c332b5 100644 --- a/hdmi/phy-xilinx-vphy/xv_hdmic.c +++ b/hdmi/phy-xilinx-vphy/xv_hdmic.c @@ -15,7 +15,6 @@ /** * * @file xhdmic.c - * @addtogroup hdmi_common_v1_0 * @{ * * Contains common utility functions that are typically used by hdmi-related @@ -29,6 +28,8 @@ * Ver Who Date Changes * ----- ---- -------- ----------------------------------------------- * 1.0 EB 21/12/17 Initial release. + * 1.1 EB 10/04/18 Fixed a bug in XV_HdmiC_ParseAudioInfoFrame + * 1.2 EB 18/06/19 Added FrlRateTable * * *******************************************************************************/ @@ -46,59 +47,527 @@ * 2) Video Identification Code. */ const XHdmiC_VicTable VicTable[VICTABLE_SIZE] = { - {XVIDC_VM_640x480_60_P, 1}, // Vic 1 - {XVIDC_VM_720x480_60_P, 2}, // Vic 2 - {XVIDC_VM_720x480_60_P, 3}, // Vic 3 - {XVIDC_VM_1280x720_60_P, 4}, // Vic 4 - {XVIDC_VM_1920x1080_60_I, 5}, // Vic 5 - {XVIDC_VM_1440x480_60_I, 6}, // Vic 6 - {XVIDC_VM_1440x480_60_I, 7}, // Vic 7 - - {XVIDC_VM_1920x1080_60_P, 16}, // Vic 16 - {XVIDC_VM_720x576_50_P, 17}, // Vic 17 - {XVIDC_VM_720x576_50_P, 18}, // Vic 18 - {XVIDC_VM_1280x720_50_P, 19}, // Vic 19 - {XVIDC_VM_1920x1080_50_I, 20}, // Vic 20 - {XVIDC_VM_1440x576_50_I, 21}, // Vic 21 - {XVIDC_VM_1440x576_50_I, 22}, // Vic 22 - - // 1680 x 720 - {XVIDC_VM_1680x720_50_P, 82}, // Vic 82 - {XVIDC_VM_1680x720_60_P, 83}, // Vic 83 - {XVIDC_VM_1680x720_100_P, 84}, // Vic 84 - {XVIDC_VM_1680x720_120_P, 85}, // Vic 85 - - // 1920 x 1080 - {XVIDC_VM_1920x1080_24_P, 32}, // Vic 32 - {XVIDC_VM_1920x1080_25_P, 33}, // Vic 33 - {XVIDC_VM_1920x1080_30_P, 34}, // Vic 34 - {XVIDC_VM_1920x1080_50_P, 31}, // Vic 31 - {XVIDC_VM_1920x1080_100_P, 64}, // Vic 64 - {XVIDC_VM_1920x1080_120_P, 63}, // Vic 63 - - // 2560 x 1080 - {XVIDC_VM_2560x1080_50_P, 89}, // Vic 89 - {XVIDC_VM_2560x1080_60_P, 90}, // Vic 89 - {XVIDC_VM_2560x1080_100_P, 91}, // Vic 91 - {XVIDC_VM_2560x1080_120_P, 92}, // Vic 92 - - // 3840 x 2160 - {XVIDC_VM_3840x2160_24_P, 93}, // Vic 93 - {XVIDC_VM_3840x2160_25_P, 94}, // Vic 94 - {XVIDC_VM_3840x2160_30_P, 95}, // Vic 95 - {XVIDC_VM_3840x2160_50_P, 96}, // Vic 96 - {XVIDC_VM_3840x2160_60_P, 97}, // Vic 97 - - // 4096 x 2160 - {XVIDC_VM_4096x2160_24_P, 98}, // Vic 98 - {XVIDC_VM_4096x2160_25_P, 99}, // Vic 99 - {XVIDC_VM_4096x2160_30_P, 100}, // Vic 100 - {XVIDC_VM_4096x2160_50_P, 101}, // Vic 101 - {XVIDC_VM_4096x2160_60_P, 102} // Vic 102 + {XVIDC_VM_640x480_60_P, 1}, /* Vic 1 */ + {XVIDC_VM_720x480_60_P, 2}, /* Vic 2 */ + {XVIDC_VM_720x480_60_P, 3}, /* Vic 3 */ + {XVIDC_VM_1280x720_60_P, 4}, /* Vic 4 */ + {XVIDC_VM_1920x1080_60_I, 5}, /* Vic 5 */ + {XVIDC_VM_1440x480_60_I, 6}, /* Vic 6 */ + {XVIDC_VM_1440x480_60_I, 7}, /* Vic 7 */ + + {XVIDC_VM_1440x240_60_P, 8}, /* Vic 8 */ + {XVIDC_VM_1440x240_60_P, 9}, /* Vic 9 */ + {XVIDC_VM_2880x480_60_I, 10}, /* Vic 10 */ + {XVIDC_VM_2880x480_60_I, 11}, /* Vic 11 */ + {XVIDC_VM_2880x240_60_P, 12}, /* Vic 12 */ + {XVIDC_VM_2880x240_60_P, 13}, /* Vic 13 */ + {XVIDC_VM_1440x480_60_P, 14}, /* Vic 14 */ + {XVIDC_VM_1440x480_60_P, 15}, /* Vic 15 */ + + {XVIDC_VM_1920x1080_60_P, 16}, /* Vic 16 */ + {XVIDC_VM_720x576_50_P, 17}, /* Vic 17 */ + {XVIDC_VM_720x576_50_P, 18}, /* Vic 18 */ + {XVIDC_VM_1280x720_50_P, 19}, /* Vic 19 */ + {XVIDC_VM_1920x1080_50_I, 20}, /* Vic 20 */ + {XVIDC_VM_1440x576_50_I, 21}, /* Vic 21 */ + {XVIDC_VM_1440x576_50_I, 22}, /* Vic 22 */ + + {XVIDC_VM_1440x288_50_P, 23}, /* Vic 23 */ + {XVIDC_VM_1440x288_50_P, 24}, /* Vic 24 */ + {XVIDC_VM_2880x576_50_I, 25}, /* Vic 25 */ + {XVIDC_VM_2880x576_50_I, 26}, /* Vic 26 */ + {XVIDC_VM_2880x288_50_P, 27}, /* Vic 27 */ + {XVIDC_VM_2880x288_50_P, 28}, /* Vic 28 */ + {XVIDC_VM_1440x576_50_P, 29}, /* Vic 29 */ + {XVIDC_VM_1440x576_50_P, 30}, /* Vic 30 */ + {XVIDC_VM_1920x1080_50_P, 31}, /* Vic 31 */ + {XVIDC_VM_1920x1080_24_P, 32}, /* Vic 32 */ + {XVIDC_VM_1920x1080_25_P, 33}, /* Vic 33 */ + {XVIDC_VM_1920x1080_30_P, 34}, /* Vic 34 */ + {XVIDC_VM_2880x480_60_P, 35}, /* Vic 35 */ + {XVIDC_VM_2880x480_60_P, 36}, /* Vic 36 */ + {XVIDC_VM_2880x576_50_P, 37}, /* Vic 37 */ + {XVIDC_VM_2880x576_50_P, 38}, /* Vic 38 */ + {XVIDC_VM_1920x1080_100_I, 40}, /* Vic 40 */ + {XVIDC_VM_1280x720_100_P, 41}, /* Vic 41 */ + {XVIDC_VM_720x576_100_P, 42}, /* Vic 42 */ + {XVIDC_VM_720x576_100_P, 43}, /* Vic 43 */ + {XVIDC_VM_1440x576_100_I, 44}, /* Vic 44 */ + {XVIDC_VM_1440x576_100_I, 45}, /* Vic 45 */ + {XVIDC_VM_1920x1080_120_I, 46}, /* Vic 46 */ + {XVIDC_VM_1280x720_120_P, 47}, /* Vic 47 */ + {XVIDC_VM_720x480_120_P, 48}, /* Vic 48 */ + {XVIDC_VM_720x480_120_P, 49}, /* Vic 49 */ + {XVIDC_VM_1440x480_120_I, 50}, /* Vic 50 */ + {XVIDC_VM_1440x480_120_I, 51}, /* Vic 51 */ + {XVIDC_VM_720x576_200_P, 52}, /* Vic 52 */ + {XVIDC_VM_720x576_200_P, 53}, /* Vic 53 */ + {XVIDC_VM_1440x576_200_I, 54}, /* Vic 54 */ + {XVIDC_VM_1440x576_200_I, 55}, /* Vic 55 */ + {XVIDC_VM_720x480_240_P, 56}, /* Vic 56 */ + {XVIDC_VM_720x480_240_P, 57}, /* Vic 57 */ + {XVIDC_VM_1440x480_240_I, 58}, /* Vic 58 */ + {XVIDC_VM_1440x480_240_I, 59}, /* Vic 59 */ + {XVIDC_VM_1280x720_24_P, 60}, /* Vic 60 */ + {XVIDC_VM_1280x720_25_P, 61}, /* Vic 61 */ + {XVIDC_VM_1280x720_30_P, 62}, /* Vic 62 */ + {XVIDC_VM_1920x1080_120_P, 63}, /* Vic 63 */ + {XVIDC_VM_1920x1080_100_P, 64}, /* Vic 64 */ + + /* 1280 x 720 */ + {XVIDC_VM_1280x720_24_P, 65}, /* Vic 65 */ + {XVIDC_VM_1280x720_25_P, 66}, /* Vic 66 */ + {XVIDC_VM_1280x720_30_P, 67}, /* Vic 67 */ + {XVIDC_VM_1280x720_50_P, 68}, /* Vic 68 */ + {XVIDC_VM_1280x720_60_P, 69}, /* Vic 69 */ + {XVIDC_VM_1280x720_100_P, 70}, /* Vic 70 */ + {XVIDC_VM_1280x720_120_P, 71}, /* Vic 71 */ + + /* 1680 x 720 */ + {XVIDC_VM_1680x720_24_P, 79}, /* Vic 82 */ + {XVIDC_VM_1680x720_25_P, 80}, /* Vic 82 */ + {XVIDC_VM_1680x720_30_P, 81}, /* Vic 82 */ + {XVIDC_VM_1680x720_50_P, 82}, /* Vic 82 */ + {XVIDC_VM_1680x720_60_P, 83}, /* Vic 83 */ + {XVIDC_VM_1680x720_100_P, 84}, /* Vic 84 */ + {XVIDC_VM_1680x720_120_P, 85}, /* Vic 85 */ + + /* 1920 x 1080 */ + {XVIDC_VM_1920x1080_24_P, 72}, /* Vic 32 */ + {XVIDC_VM_1920x1080_25_P, 73}, /* Vic 33 */ + {XVIDC_VM_1920x1080_30_P, 74}, /* Vic 34 */ + {XVIDC_VM_1920x1080_50_P, 75}, /* Vic 75 */ + {XVIDC_VM_1920x1080_60_P, 76}, /* Vic 76 */ + {XVIDC_VM_1920x1080_100_P, 77}, /* Vic 77 */ + {XVIDC_VM_1920x1080_120_P, 78}, /* Vic 78 */ + + /* 2560 x 1080 */ + {XVIDC_VM_2560x1080_24_P, 86}, /* Vic 86 */ + {XVIDC_VM_2560x1080_25_P, 87}, /* Vic 87 */ + {XVIDC_VM_2560x1080_30_P, 88}, /* Vic 88 */ + {XVIDC_VM_2560x1080_50_P, 89}, /* Vic 89 */ + {XVIDC_VM_2560x1080_60_P, 90}, /* Vic 90 */ + {XVIDC_VM_2560x1080_100_P, 91}, /* Vic 91 */ + {XVIDC_VM_2560x1080_120_P, 92}, /* Vic 92 */ + + /* 3840 x 2160 */ + {XVIDC_VM_3840x2160_24_P, 93}, /* Vic 93 */ + {XVIDC_VM_3840x2160_25_P, 94}, /* Vic 94 */ + {XVIDC_VM_3840x2160_30_P, 95}, /* Vic 95 */ + {XVIDC_VM_3840x2160_50_P, 96}, /* Vic 96 */ + {XVIDC_VM_3840x2160_60_P, 97}, /* Vic 97 */ + {XVIDC_VM_3840x2160_100_P, 117}, /* Vic 117 */ + {XVIDC_VM_3840x2160_120_P, 118}, /* Vic 118 */ + + /* 4096 x 2160 */ + {XVIDC_VM_4096x2160_24_P, 98}, /* Vic 98 */ + {XVIDC_VM_4096x2160_25_P, 99}, /* Vic 99 */ + {XVIDC_VM_4096x2160_30_P, 100}, /* Vic 100 */ + {XVIDC_VM_4096x2160_50_P, 101}, /* Vic 101 */ + {XVIDC_VM_4096x2160_60_P, 102}, /* Vic 102 */ + {XVIDC_VM_4096x2160_100_P, 218}, /* Vic 218 */ + {XVIDC_VM_4096x2160_120_P, 219}, /* Vic 219 */ + + /* 5120 x 2160 */ + {XVIDC_VM_5120x2160_24_P, 121}, /* Vic 121 */ + {XVIDC_VM_5120x2160_25_P, 122}, /* Vic 122 */ + {XVIDC_VM_5120x2160_30_P, 123}, /* Vic 123 */ + {XVIDC_VM_5120x2160_50_P, 125}, /* Vic 125 */ + {XVIDC_VM_5120x2160_60_P, 126}, /* Vic 126 */ + {XVIDC_VM_5120x2160_100_P, 127}, /* Vic 127 */ + {XVIDC_VM_5120x2160_120_P, 193}, /* Vic 193 */ + + /* 7680 x 4320 */ + {XVIDC_VM_7680x4320_24_P, 194}, /* Vic 194 */ + {XVIDC_VM_7680x4320_25_P, 195}, /* Vic 195 */ + {XVIDC_VM_7680x4320_30_P, 196}, /* Vic 196 */ + {XVIDC_VM_7680x4320_50_P, 198}, /* Vic 198 */ + {XVIDC_VM_7680x4320_60_P, 199}, /* Vic 199 */ + {XVIDC_VM_7680x4320_100_P, 200}, /* Vic 200 */ + {XVIDC_VM_7680x4320_120_P, 201}, /* Vic 201 */ + + /* 10240 x 4320 */ + {XVIDC_VM_10240x4320_24_P, 210}, /* Vic 210 */ + {XVIDC_VM_10240x4320_25_P, 211}, /* Vic 211 */ + {XVIDC_VM_10240x4320_30_P, 212}, /* Vic 212 */ + {XVIDC_VM_10240x4320_50_P, 214}, /* Vic 214 */ + {XVIDC_VM_10240x4320_60_P, 215}, /* Vic 215 */ + {XVIDC_VM_10240x4320_100_P, 216}, /* Vic 216 */ + {XVIDC_VM_10240x4320_120_P, 217}, /* Vic 217 */ }; -/*************************** Function Definitions *****************************/ +/** +* This table contains the attributes for various FRL Rate. +* Each entry is of the format: +* 1) Number of lanes +* 2) Line Rate. +*/ +const XHdmiC_FrlRate FrlRateTable[] = { + {3, 0}, /* XHDMIC_MAXFRLRATE_NOT_SUPPORTED */ + {3, 3}, /* XHDMIC_MAXFRLRATE_3X3GBITSPS */ + {3, 6}, /* XHDMIC_MAXFRLRATE_3X6GBITSPS */ + {4, 6}, /* XHDMIC_MAXFRLRATE_4X6GBITSPS */ + {4, 8}, /* XHDMIC_MAXFRLRATE_4X8GBITSPS */ + {4, 10}, /* XHDMIC_MAXFRLRATE_4X10GBITSPS */ + {4, 12}, /* XHDMIC_MAXFRLRATE_4X12GBITSPS */ +}; + +/** +* This table contains the CTS and N value of each TMDS character rate. +* Each entry is of the format: +* 1) Sample Frequency TMDS CLk, (32kHz, 44.1kHz, and 48kHz) +*/ +const XHdmiC_TMDS_N_Table TMDSChar_N_Table[] = +{ + /* TMDSClk 32k 44k1 48k 88k2 96k 176k4 192k */ + { 0, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 25200000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 27000000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 31500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 33750000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 37800000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 40500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 50400000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 54000000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 67500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 74250000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 81000000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + { 92812500, { 8192, 6272, 12288, 12544, 24576, 25088, 49152}}, + {108000000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + {111375000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + {148500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + {185625000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + {222750000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + {297000000, { 3072, 4704, 5120, 9408, 10240, 18816, 20480}}, + {371250000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + {445500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576}}, + {594000000, { 3072, 9408, 6144, 18816, 12288, 37632, 24576}} +}; + +/** +* This returns the the N Value based Audio Sampling Rate and TMDS +* Character Rate +*/ +u32 XHdmiC_TMDS_GetNVal(u32 TMDSCharRate, + XHdmiC_SamplingFrequency AudSampleFreq) +{ + XHdmiC_TMDS_N_Table const *item; + u32 i = 0; + + /* Proceed only with supported Audio Sampling Frequency */ + if (AudSampleFreq == XHDMIC_SAMPLING_FREQUENCY || + AudSampleFreq > XHDMIC_SAMPLING_FREQUENCY_192K) { + /* Since AudSampFreq not valid, return N Value = 0 */ + return 0; + } + + for(i = 0; i < sizeof(TMDSChar_N_Table)/sizeof(XHdmiC_TMDS_N_Table); i++) { + item = &TMDSChar_N_Table[i]; + /* 10kHz Tolerance */ + if(TMDSCharRate <= (item->TMDSCharRate + 10000) && + (TMDSCharRate >= (item->TMDSCharRate - 10000))) { + return item->ACR_NVal[AudSampleFreq-1]; + } + } + + /* If TMDS character rate could not be found return default values */ + item = &TMDSChar_N_Table[0]; + + return item->ACR_NVal[AudSampleFreq-1]; +} + +/** +* This returns the Audio Sampling Rate and TMDS +* Character Rate +*/ +XHdmiC_SamplingFrequency XHdmiC_TMDS_GetAudSampFreq(u32 TMDSCharRate, + u32 N) +{ + XHdmiC_TMDS_N_Table const *item; + u8 i = 0; + u8 j = 0; + + for(i = 0; i < sizeof(TMDSChar_N_Table)/sizeof(XHdmiC_TMDS_N_Table); i++) { + item = &TMDSChar_N_Table[i]; + if(TMDSCharRate <= (item->TMDSCharRate + 10000) && + (TMDSCharRate >= (item->TMDSCharRate - 10000))) { + for (j = 0; j < 7; j++) { + if(N == item->ACR_NVal[j]) { + return j; + break; + } + } + } + } + /* Return non-valid sample frequency */ + return XHDMIC_SAMPLING_FREQUENCY; +} + +/** +* Top level data structure for XHdmiC_FRL_CTS_N_Table_t +*/ +typedef struct { + /* 5 = FRL Rate 12,10,8,6,3 */ + XHdmiC_FRL_CTS_N_Val CTS_NVal[5]; +} XHdmiC_FRL_CTS_N_Table_t; + + +/** +* This table contains the CTS and N value of each FRL character rate. +* Each entry is of the format: +* 1) Sample Frequency (32kHz, 44.1kHz, and 48kHz) +*/ +const XHdmiC_FRL_CTS_N_Table_t FRL_CTS_N_Table[] = +{ + {/* 32kHz */ + { /* 3 Gbps */ + {171875, {4224, 8448, 16896, 33792, 67584, 135168}}, + /* 6 Gbps */ + {328125, {4032, 8064, 16128, 32256, 64512, 129024}}, + /* 8 Gbps */ + {437500, {4032, 8064, 16128, 32256, 64512, 129024}}, + /* 10 Gbps */ + {468750, {3456, 6912, 13824, 27648, 55296, 110592}}, + /* 12 Gbps */ + {500000, {3072, 6144, 12288, 24576, 49152, 98304 }}, + }, + }, + {/* 44.1kHz */ + { + {156250 ,{5292 ,10584 ,21168 ,42336 ,84672 ,169344}}, + {312500 ,{5292 ,10584 ,21168 ,42336 ,84672 ,169344}}, + {312500 ,{3969 ,7938 ,15876 ,31752 ,63504 ,127008}}, + {390625 ,{3969 ,7938 ,15876 ,31752 ,63504 ,127008}}, + {468750 ,{3969 ,7938 ,15876 ,31752 ,63504 ,127008}}, + }, + }, + {/* 48kHz */ + { + {156250 ,{5760 ,11520 ,23040 ,46080 ,92160 ,184320}}, + {328125 ,{6048 ,12096 ,24192 ,48384 ,96768 ,193536}}, + {437500 ,{6048 ,12096 ,24192 ,48384 ,96768 ,193536}}, + {468750 ,{5184 ,10368 ,20736 ,41472 ,82944 ,165888}}, + {515625 ,{4752 ,9504 ,19008 ,38016 ,76032 ,152064}}, + }, + }, +}; + +/** +* This returns the N value in FRL mode based on its Audio Sample Frequency +*/ +u32 XHdmiC_FRL_GetNVal(XHdmiC_FRLCharRate FRLCharRate, + XHdmiC_SamplingFrequencyVal AudSampleFreqVal) +{ + XHdmiC_FRL_CTS_N_Table_t const *item; + u8 SampleFreq; + u8 MultSampleFreq; + + /* Check for valid FRL Character Rate */ + if (FRLCharRate < R_166_667 && FRLCharRate > R_666_667 ) { + /* Since AudSampFreq not valid, return N Value = 0 */ + FRLCharRate = R_166_667; + } + + if (AudSampleFreqVal%XHDMIC_SAMPLING_FREQ_48K == 0) { + SampleFreq = 2; + MultSampleFreq = AudSampleFreqVal/XHDMIC_SAMPLING_FREQ_48K; + } else if (AudSampleFreqVal%XHDMIC_SAMPLING_FREQ_44_1K == 0) { + SampleFreq = 1; + MultSampleFreq = AudSampleFreqVal/XHDMIC_SAMPLING_FREQ_44_1K; + } else if (AudSampleFreqVal%XHDMIC_SAMPLING_FREQ_32K == 0) { + SampleFreq = 0; + MultSampleFreq = AudSampleFreqVal/XHDMIC_SAMPLING_FREQ_32K; + } else { + /* Not Valid Scenario */ + SampleFreq = 0; + MultSampleFreq = 0; + } + + /* MultSampleFreq is the divisible value from the 3 base + * Sample Frequency. + * However the N value array for FRL are based on the power of 2. + * {base_freq*(2^0),base_freq*(2^1),base_freq*(2^2),base_freq*(2^3),..} + */ + switch (MultSampleFreq) { + case 1: + case 2: + MultSampleFreq = MultSampleFreq - 1; + break; + + case 4: + MultSampleFreq = 2; + break; + + case 8: + MultSampleFreq = 3; + break; + + case 16: + MultSampleFreq = 4; + break; + + case 32: + MultSampleFreq = 5; + break; + + default: + MultSampleFreq = 0; + break; + } + + item = &FRL_CTS_N_Table[SampleFreq]; + return item->CTS_NVal[FRLCharRate].ACR_NVal[MultSampleFreq]; + +} + +/** +* This returns the Audio Sample Frequency for FRL +*/ +XHdmiC_SamplingFrequencyVal + XHdmiC_FRL_GetAudSampFreq(XHdmiC_FRLCharRate FRLCharRate, + u32 CTS, u32 N) +{ + XHdmiC_FRL_CTS_N_Table_t const *item; + u8 Index_0 = 0; + u8 Index_1 = 0; + XHdmiC_SamplingFrequencyVal SampleFreq = XHDMIC_SAMPLING_FREQ; + + item = &FRL_CTS_N_Table[SampleFreq]; + for (Index_0 = 0; Index_0 < 3; Index_0++) { + item = &FRL_CTS_N_Table[Index_0]; + /* Adding tolerance of 10k CTS */ + if ((CTS < (item->CTS_NVal[FRLCharRate].ACR_CTSVal + 10000)) && + (CTS > (item->CTS_NVal[FRLCharRate].ACR_CTSVal - 10000))) { + for (Index_1 = 0; Index_1 < 6; Index_1++) { + if (N == + item->CTS_NVal[FRLCharRate].ACR_NVal[Index_1]){ + if (Index_0 == 0) { + SampleFreq = + XHDMIC_SAMPLING_FREQ_32K << Index_1; + } else if (Index_0 == 1) { + SampleFreq = + XHDMIC_SAMPLING_FREQ_44_1K << Index_1; + } else { + SampleFreq = + XHDMIC_SAMPLING_FREQ_48K << Index_1; + } + break; + } + } + } + } + return SampleFreq; +} +/** +* This converts the Aud. Sampling Freq. Value to +* Audio Info-frame Sampling Freq. Format. +*/ +XHdmiC_SamplingFrequency + XHdmiC_GetAudIFSampFreq (XHdmiC_SamplingFrequencyVal AudSampFreqVal) +{ + XHdmiC_SamplingFrequency ExtACRSampFreq; + + switch (AudSampFreqVal) { + case XHDMIC_SAMPLING_FREQ_32K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQUENCY_32K; + break; + + case XHDMIC_SAMPLING_FREQ_44_1K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQUENCY_44_1K; + break; + + case XHDMIC_SAMPLING_FREQ_48K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQUENCY_48K; + break; + + case XHDMIC_SAMPLING_FREQ_88_2K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQUENCY_88_2K; + break; + + case XHDMIC_SAMPLING_FREQ_96K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQUENCY_96K; + break; + + case XHDMIC_SAMPLING_FREQ_176_4K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQUENCY_176_4K; + break; + + case XHDMIC_SAMPLING_FREQ_192K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQUENCY_192K; + break; + + default: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ; + break; + } + + return ExtACRSampFreq; +} + +/** +* This converts the Audio Info-frame Sampling Freq. Format. to +* Audio Sampling Freq. Value. +*/ +XHdmiC_SamplingFrequencyVal + XHdmiC_GetAudSampFreqVal(XHdmiC_SamplingFrequency AudSampFreqVal) +{ + XHdmiC_SamplingFrequencyVal ExtACRSampFreq; + + switch (AudSampFreqVal) { + case XHDMIC_SAMPLING_FREQUENCY_32K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ_32K; + break; + + case XHDMIC_SAMPLING_FREQUENCY_44_1K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ_44_1K; + break; + + case XHDMIC_SAMPLING_FREQUENCY_48K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ_48K; + break; + + case XHDMIC_SAMPLING_FREQUENCY_88_2K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ_88_2K; + break; + + case XHDMIC_SAMPLING_FREQUENCY_96K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ_96K; + break; + + case XHDMIC_SAMPLING_FREQUENCY_176_4K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ_176_4K; + break; + + case XHDMIC_SAMPLING_FREQUENCY_192K: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ_192K; + break; + + default: + ExtACRSampFreq = + XHDMIC_SAMPLING_FREQ_32K; + break; + } + + return ExtACRSampFreq; +} + +/*************************** Function Definitions *****************************/ /** * * This function retrieves the Auxiliary Video Information Info Frame. @@ -210,7 +679,8 @@ void XV_HdmiC_ParseAudioInfoFrame(XHdmiC_Aux *AuxPtr, XHdmiC_AudioInfoFrame *Aud AudIFPtr->ChannelCount = (AuxPtr->Data.Byte[1]) & 0x7; /* PB2 */ - AudIFPtr->SampleFrequency = AuxPtr->Data.Byte[2] & 0x1f; + AudIFPtr->SampleFrequency = (AuxPtr->Data.Byte[2] >> 2) & 0x7; + AudIFPtr->SampleSize = AuxPtr->Data.Byte[2] & 0x3; /* PB4 */ AudIFPtr->ChannelAllocation = AuxPtr->Data.Byte[4]; @@ -242,6 +712,8 @@ XHdmiC_Aux XV_HdmiC_AVIIF_GeneratePacket(XHdmiC_AVI_InfoFrame *infoFramePtr) u8 Crc; XHdmiC_Aux aux; + (void)memset((void *)&aux, 0, sizeof(XHdmiC_Aux)); + /* Header, Packet type*/ aux.Header.Byte[0] = AUX_AVI_INFOFRAME_TYPE; @@ -281,7 +753,7 @@ XHdmiC_Aux XV_HdmiC_AVIIF_GeneratePacket(XHdmiC_AVI_InfoFrame *infoFramePtr) /* PB6 */ aux.Data.Byte[6] = infoFramePtr->TopBar & 0xff; - + aux.Data.Byte[7] = 0; /* PB8 */ @@ -351,6 +823,8 @@ XHdmiC_Aux XV_HdmiC_AudioIF_GeneratePacket(XHdmiC_AudioInfoFrame *AudioInfoFrame u8 Crc; XHdmiC_Aux aux; + (void)memset((void *)&aux, 0, sizeof(XHdmiC_Aux)); + /* Header, Packet Type */ aux.Header.Byte[0] = AUX_AUDIO_INFOFRAME_TYPE; diff --git a/hdmi/phy-xilinx-vphy/xv_hdmic.h b/hdmi/phy-xilinx-vphy/xv_hdmic.h index 78ac4e0..f24025c 100644 --- a/hdmi/phy-xilinx-vphy/xv_hdmic.h +++ b/hdmi/phy-xilinx-vphy/xv_hdmic.h @@ -16,7 +16,6 @@ /** * * @file xhdmic.h - * @addtogroup hdmi_common_v1_0 * @{ * @details * @@ -35,7 +34,8 @@ * *******************************************************************************/ -#ifndef XV_HDMIC_H_ /* Prevent circular inclusions by using protection macros. */ +#ifndef XV_HDMIC_H_ /* Prevent circular inclusions by + using protection macros. */ #define XV_HDMIC_H_ #ifdef __cplusplus @@ -50,7 +50,7 @@ extern "C" { #include "xil_assert.h" /************************** Constant Definitions ******************************/ -#define VICTABLE_SIZE 38 +#define VICTABLE_SIZE 126 #define AUX_VSIF_TYPE 0x81 #define AUX_AVI_INFOFRAME_TYPE 0x82 #define AUX_GENERAL_CONTROL_PACKET_TYPE 0x3 @@ -208,6 +208,30 @@ typedef enum { XHDMIC_SAMPLING_FREQUENCY_192K } XHdmiC_SamplingFrequency; +typedef enum { + XHDMIC_SAMPLING_FREQ = 0, + XHDMIC_SAMPLING_FREQ_32K = 32000, + XHDMIC_SAMPLING_FREQ_64K = 32000, + XHDMIC_SAMPLING_FREQ_128K = 128000, + XHDMIC_SAMPLING_FREQ_256K = 128000, + XHDMIC_SAMPLING_FREQ_512K = 128000, + XHDMIC_SAMPLING_FREQ_1024K = 1024000, + + XHDMIC_SAMPLING_FREQ_44_1K = 44100, + XHDMIC_SAMPLING_FREQ_88_2K = 88200, + XHDMIC_SAMPLING_FREQ_176_4K = 176400, + XHDMIC_SAMPLING_FREQ_352_8K = 352800, + XHDMIC_SAMPLING_FREQ_705_6K = 705600, + XHDMIC_SAMPLING_FREQ_1411_2K = 1411200, + + XHDMIC_SAMPLING_FREQ_48K = 48000, + XHDMIC_SAMPLING_FREQ_96K = 96000, + XHDMIC_SAMPLING_FREQ_192K = 192000, + XHDMIC_SAMPLING_FREQ_384K = 384000, + XHDMIC_SAMPLING_FREQ_768K = 768000, + XHDMIC_SAMPLING_FREQ_1536K = 1536000, +} XHdmiC_SamplingFrequencyVal; + typedef enum { XHDMIC_SAMPLE_SIZE, XHDMIC_SAMPLE_SIZE_16, @@ -270,7 +294,59 @@ typedef enum { } XHdmiC_LevelShiftValue; /** - * This typedef contains the data structure for Auxiliary Video Information Info frame +* FRL Character Rate Enumeration +*/ +typedef enum { + R_166_667 = 0, /* 3 Gbps */ + R_333_333, /* 6 Gbps */ + R_444_444, /* 8 Gbps */ + R_555_556, /* 10 Gbps */ + R_666_667, /* 12 Gbps */ + XHDMIC_FRLCHARRATE_SIZE, +} XHdmiC_FRLCharRate; + +/** +* FRL Rate Enumeration +*/ +typedef enum { + XHDMIC_MAXFRLRATE_NOT_SUPPORTED, + XHDMIC_MAXFRLRATE_3X3GBITSPS, + XHDMIC_MAXFRLRATE_3X6GBITSPS, + XHDMIC_MAXFRLRATE_4X6GBITSPS, + XHDMIC_MAXFRLRATE_4X8GBITSPS, + XHDMIC_MAXFRLRATE_4X10GBITSPS, + XHDMIC_MAXFRLRATE_4X12GBITSPS, + XHDMIC_MAXFRLRATE_SIZE, + XHDMIC_MAXFRLRATE_TMDSONLY = XHDMIC_MAXFRLRATE_NOT_SUPPORTED +} XHdmiC_MaxFrlRate; + +/** +* FRL CTS/N Value Table +*/ +typedef struct { + u32 ACR_CTSVal; + u32 ACR_NVal[6]; /* multiply of 6 of the initial Sample Freq */ +} XHdmiC_FRL_CTS_N_Val; + +/** +* TMDS Char/N Value Table +*/ +typedef struct { + u32 TMDSCharRate; + u32 ACR_NVal[7]; +} XHdmiC_TMDS_N_Table; + +/** +* This typedef contains translations of FRL_Rate to Lanes and Line Rates. +*/ +typedef struct { + u8 Lanes; /**< No of Lanes */ + u8 LineRate; /**< Line Rate */ +} XHdmiC_FrlRate; + +/** + * This typedef contains the data structure for + * Auxiliary Video Information Info frame */ typedef struct XHDMIC_AVI_InfoFrame { unsigned char Version; @@ -324,17 +400,40 @@ typedef struct XHdmiC_Audio_InfoFrame { /*************************** Variable Declarations ****************************/ extern const XHdmiC_VicTable VicTable[VICTABLE_SIZE]; - +extern const XHdmiC_FrlRate FrlRateTable[]; /************************** Function Prototypes ******************************/ -void XV_HdmiC_ParseAVIInfoFrame(XHdmiC_Aux *AuxPtr, XHdmiC_AVI_InfoFrame *infoFramePtr); -void XV_HdmiC_ParseGCP(XHdmiC_Aux *AuxPtr, XHdmiC_GeneralControlPacket *GcpPtr); -void XV_HdmiC_ParseAudioInfoFrame(XHdmiC_Aux *AuxPtr, XHdmiC_AudioInfoFrame *AudIFPtr); +void XV_HdmiC_ParseAVIInfoFrame(XHdmiC_Aux *AuxPtr, + XHdmiC_AVI_InfoFrame *infoFramePtr); +void XV_HdmiC_ParseGCP(XHdmiC_Aux *AuxPtr, + XHdmiC_GeneralControlPacket *GcpPtr); +void XV_HdmiC_ParseAudioInfoFrame(XHdmiC_Aux *AuxPtr, + XHdmiC_AudioInfoFrame *AudIFPtr); XHdmiC_Aux XV_HdmiC_AVIIF_GeneratePacket(XHdmiC_AVI_InfoFrame *infoFramePtr); -XHdmiC_Aux XV_HdmiC_AudioIF_GeneratePacket(XHdmiC_AudioInfoFrame *AudioInfoFrame); -XHdmiC_Colorspace XV_HdmiC_XVidC_To_IfColorformat(XVidC_ColorFormat ColorFormat); +XHdmiC_Aux + XV_HdmiC_AudioIF_GeneratePacket(XHdmiC_AudioInfoFrame *AudioInfoFrame); +XHdmiC_Colorspace + XV_HdmiC_XVidC_To_IfColorformat(XVidC_ColorFormat ColorFormat); XVidC_AspectRatio XV_HdmiC_IFAspectRatio_To_XVidC(XHdmiC_PicAspectRatio AR); +u32 XHdmiC_FRL_GetNVal(XHdmiC_FRLCharRate FRLCharRate, + XHdmiC_SamplingFrequencyVal AudSampleFreqVal); +u32 XHdmiC_TMDS_GetNVal(u32 TMDSCharRate, + XHdmiC_SamplingFrequency AudSampleFreq); +XHdmiC_SamplingFrequencyVal + XHdmiC_FRL_GetAudSampFreq(XHdmiC_FRLCharRate FRLCharRate, + u32 CTS, u32 N); +XHdmiC_SamplingFrequency XHdmiC_TMDS_GetAudSampFreq(u32 TMDSCharRate, + u32 N); +XHdmiC_SamplingFrequency + XHdmiC_GetAudIFSampFreq (XHdmiC_SamplingFrequencyVal AudSampFreqVal); +XHdmiC_SamplingFrequencyVal + XHdmiC_GetAudSampFreqVal(XHdmiC_SamplingFrequency AudSampFreqVal); + +#ifdef __cplusplus +} +#endif + #endif /* XHDMIC_H_ */ /** @} */ diff --git a/hdmi/phy-xilinx-vphy/xv_hdmic_vsif.c b/hdmi/phy-xilinx-vphy/xv_hdmic_vsif.c index 8ed7e1a..eedc8f0 100644 --- a/hdmi/phy-xilinx-vphy/xv_hdmic_vsif.c +++ b/hdmi/phy-xilinx-vphy/xv_hdmic_vsif.c @@ -460,16 +460,13 @@ XHdmiC_Aux XV_HdmiC_VSIF_GeneratePacket(XHdmiC_VSIF *VSIFPtr) u8 ByteCount = 0; u8 Crc = 0; XHdmiC_Aux Aux; -// XHdmiC_Aux *AuxPtr; + + (void)memset((void *)&Aux, 0, sizeof(XHdmiC_Aux)); XHdmiC_3D_Struct_Field Format; XHdmiC_3D_Sampling_Method SampMethod; XHdmiC_3D_Sampling_Position SampPos; - /* Verify arguments */ -// Xil_AssertNonvoid(VSIFPtr != NULL); -// Xil_AssertNonvoid(AuxPtr != NULL); - /* Header, Packet type*/ Aux.Header.Byte[0] = AUX_VSIF_TYPE; diff --git a/hdmi/phy-xilinx-vphy/xvidc.c b/hdmi/phy-xilinx-vphy/xvidc.c index ad2e644..f6b0b43 100644 --- a/hdmi/phy-xilinx-vphy/xvidc.c +++ b/hdmi/phy-xilinx-vphy/xvidc.c @@ -17,7 +17,6 @@ /** * * @file xvidc.c - * @addtogroup video_common_v4_0 * @{ * * Contains common utility functions that are typically used by video-related @@ -147,7 +146,7 @@ void XVidC_UnregisterCustomTimingModes(void) * @note None. * *******************************************************************************/ -u32 XVidC_GetPixelClockHzByHVFr(u32 HTotal, u32 VTotal, u8 FrameRate) +u64 XVidC_GetPixelClockHzByHVFr(u32 HTotal, u32 VTotal, u8 FrameRate) { return (HTotal * VTotal * FrameRate); } @@ -163,9 +162,9 @@ u32 XVidC_GetPixelClockHzByHVFr(u32 HTotal, u32 VTotal, u8 FrameRate) * @note None. * *******************************************************************************/ -u32 XVidC_GetPixelClockHzByVmId(XVidC_VideoMode VmId) +u64 XVidC_GetPixelClockHzByVmId(XVidC_VideoMode VmId) { - u32 ClkHz; + u64 ClkHz; const XVidC_VideoTimingMode *VmPtr; VmPtr = XVidC_GetVideoModeData(VmId); @@ -574,6 +573,13 @@ XVidC_VideoMode XVidC_GetVideoModeIdExtensive(XVidC_VideoTiming *Timing, Timing->F1VSyncWidth)) { ResFound = (TRUE); break; + } else { + Mid = Mid + 1; + HActive = + XVidC_VideoTimingModes[Mid].Timing.HActive; + VActive = + XVidC_VideoTimingModes[Mid].Timing.VActive; + Rate = XVidC_VideoTimingModes[Mid].FrameRate; } } /* Check next entry */ @@ -739,6 +745,9 @@ const char *XVidC_GetFrameRateStr(XVidC_VideoMode VmId) case (XVIDC_FR_96HZ): return ("96Hz"); case (XVIDC_FR_100HZ): return ("100Hz"); case (XVIDC_FR_120HZ): return ("120Hz"); + case (XVIDC_FR_144HZ): return ("144Hz"); + case (XVIDC_FR_200HZ): return ("200Hz"); + case (XVIDC_FR_240HZ): return ("240Hz"); default: return ("Frame rate not supported"); @@ -826,6 +835,17 @@ const char *XVidC_GetColorFormatStr(XVidC_ColorFormat ColorFormatId) case XVIDC_CSF_MEM_BGR8: return ("BGR8"); case XVIDC_CSF_YCBCR_422: return ("YCBCR_422"); case XVIDC_CSF_YCBCR_420: return ("YCBCR_420"); + case XVIDC_CSF_YCBCR_444: return ("YCBCR_444"); + case XVIDC_CSF_MEM_RGBX12: return ("RGBX12"); + case XVIDC_CSF_MEM_RGB16: return ("RGB16"); + case XVIDC_CSF_MEM_YUVX12: return ("YUVX12"); + case XVIDC_CSF_MEM_YUV16: return ("YUV16"); + case XVIDC_CSF_MEM_Y_UV12: return ("Y_UV12"); + case XVIDC_CSF_MEM_Y_UV16: return ("Y_UV16"); + case XVIDC_CSF_MEM_Y_UV12_420: return ("Y_UV12_420"); + case XVIDC_CSF_MEM_Y_UV16_420: return ("Y_UV16_420"); + case XVIDC_CSF_MEM_Y12: return ("Y12"); + case XVIDC_CSF_MEM_Y16: return ("Y16"); default: return ("Color space format not supported"); } @@ -925,10 +945,12 @@ u32 XVidC_SetVideoStream(XVidC_VideoStream *VidStrmPtr, XVidC_VideoMode VmId, VidStrmPtr->Timing = *TimingPtr; VidStrmPtr->FrameRate = XVidC_GetFrameRate(VmId); VidStrmPtr->IsInterlaced = XVidC_IsInterlaced(VmId); - - } else { //Custom Timing - use as-is - VidStrmPtr->IsInterlaced = FALSE; + + } else { + /* In custom timing no need to set Timing, FrameRate and IsInterlaced + * as they are already set previously in wrapper code */ } + VidStrmPtr->VmId = VmId; VidStrmPtr->ColorFormatId = ColorFormat; VidStrmPtr->ColorDepth = Bpc; @@ -1071,19 +1093,20 @@ void XVidC_ReportStreamInfo(const XVidC_VideoStream *Stream) Stream->FrameRate); xil_printf("\tResolution: %dx%d [Custom Mode]\r\n", Stream->Timing.HActive, Stream->Timing.VActive); - xil_printf("\tPixel Clock: %d\r\n", - XVidC_GetPixelClockHzByHVFr( + xil_printf("\tPixel Clock: %d kHz\r\n", + (u32)(XVidC_GetPixelClockHzByHVFr( Stream->Timing.HTotal, Stream->Timing.F0PVTotal, - Stream->FrameRate)); + Stream->FrameRate)/1000)); } else { xil_printf("\tFrame Rate: %s\r\n", XVidC_GetFrameRateStr(Stream->VmId)); xil_printf("\tResolution: %s\r\n", XVidC_GetVideoModeStr(Stream->VmId)); - xil_printf("\tPixel Clock: %d\r\n", - XVidC_GetPixelClockHzByVmId(Stream->VmId)); + xil_printf("\tPixel Clock: %d kHz\r\n", + (u32)(XVidC_GetPixelClockHzByVmId(Stream->VmId) + /1000)); } } @@ -1103,7 +1126,7 @@ void XVidC_ReportStreamInfo(const XVidC_VideoStream *Stream) void XVidC_ReportTiming(const XVidC_VideoTiming *Timing, u8 IsInterlaced) { xil_printf("\r\n\tHSYNC Timing: hav=%04d, hfp=%02d, hsw=%02d(hsp=%d), " - "hbp=%03d, htot=%04d \n\r", Timing->HActive, + "hbp=%03d, htot=%04d \r\n", Timing->HActive, Timing->HFrontPorch, Timing->HSyncWidth, Timing->HSyncPolarity, Timing->HBackPorch, Timing->HTotal); @@ -1111,12 +1134,12 @@ void XVidC_ReportTiming(const XVidC_VideoTiming *Timing, u8 IsInterlaced) /* Interlaced */ if (IsInterlaced) { xil_printf("\tVSYNC Timing (Field 0): vav=%04d, vfp=%02d, " - "vsw=%02d(vsp=%d), vbp=%03d, vtot=%04d\n\r", + "vsw=%02d(vsp=%d), vbp=%03d, vtot=%04d\r\n", Timing->VActive, Timing->F0PVFrontPorch, Timing->F0PVSyncWidth, Timing->VSyncPolarity, Timing->F0PVBackPorch, Timing->F0PVTotal); xil_printf("\tVSYNC Timing (Field 1): vav=%04d, vfp=%02d, " - "vsw=%02d(vsp=%d), vbp=%03d, vtot=%04d\n\r", + "vsw=%02d(vsp=%d), vbp=%03d, vtot=%04d\r\n", Timing->VActive, Timing->F1VFrontPorch, Timing->F1VSyncWidth, Timing->VSyncPolarity, Timing->F1VBackPorch, Timing->F1VTotal); @@ -1124,7 +1147,7 @@ void XVidC_ReportTiming(const XVidC_VideoTiming *Timing, u8 IsInterlaced) /* Progressive */ else { xil_printf("\tVSYNC Timing: vav=%04d, vfp=%02d, " - "vsw=%02d(vsp=%d), vbp=%03d, vtot=%04d\n\r", + "vsw=%02d(vsp=%d), vbp=%03d, vtot=%04d\r\n", Timing->VActive, Timing->F0PVFrontPorch, Timing->F0PVSyncWidth, Timing->VSyncPolarity, Timing->F0PVBackPorch, Timing->F0PVTotal); @@ -1246,7 +1269,7 @@ int XVidC_ShowStreamInfo(const XVidC_VideoStream *Stream, char *buff, int buff_s "\tResolution: %dx%d [Custom Mode]\r\n", Stream->Timing.HActive, Stream->Timing.VActive); strSize += scnprintf(buff+strSize, buff_size-strSize, - "\tPixel Clock: %d\r\n", + "\tPixel Clock: %lld\r\n", XVidC_GetPixelClockHzByHVFr( Stream->Timing.HTotal, Stream->Timing.F0PVTotal, @@ -1260,7 +1283,7 @@ int XVidC_ShowStreamInfo(const XVidC_VideoStream *Stream, char *buff, int buff_s "\tResolution: %s\r\n", XVidC_GetVideoModeStr(Stream->VmId)); strSize += scnprintf(buff+strSize, buff_size-strSize, - "\tPixel Clock: %d\r\n", + "\tPixel Clock: %lld\r\n", XVidC_GetPixelClockHzByVmId(Stream->VmId)); } diff --git a/hdmi/phy-xilinx-vphy/xvidc.h b/hdmi/phy-xilinx-vphy/xvidc.h index a7a34cb..58d2bda 100644 --- a/hdmi/phy-xilinx-vphy/xvidc.h +++ b/hdmi/phy-xilinx-vphy/xvidc.h @@ -17,7 +17,6 @@ /** * * @file xvidc.h - * @addtogroup video_common_v4_0 * @{ * @details * @@ -59,6 +58,9 @@ * 4.3 eb 26/01/18 Added API XVidC_GetVideoModeIdExtensive * jsr 02/22/18 Added XVIDC_CSF_YCBCR_420 color space format * vyc 04/04/18 Added BGR8 memory format + * 4.5 jsr 07/03/18 Added XVIDC_VM_720x486_60_I video format + * 4.5 yas 03/08/19 Added support for frame rates 144HZ and 240HZ + * 4.6 mmo 02/14/19 Added 5k, 8k, 10k and Low Resolution with 200Hz, 240Hz * * *******************************************************************************/ @@ -88,9 +90,14 @@ extern "C" { typedef enum { /* Interlaced modes. */ XVIDC_VM_720x480_60_I = 0, + XVIDC_VM_720x486_60_I, XVIDC_VM_720x576_50_I, XVIDC_VM_1440x480_60_I, + XVIDC_VM_1440x480_120_I, + XVIDC_VM_1440x480_240_I, XVIDC_VM_1440x576_50_I, + XVIDC_VM_1440x576_100_I, + XVIDC_VM_1440x576_200_I, XVIDC_VM_1920x1080_48_I, XVIDC_VM_1920x1080_50_I, XVIDC_VM_1920x1080_60_I, @@ -103,6 +110,8 @@ typedef enum { XVIDC_VM_2048x1080_96_I, XVIDC_VM_2048x1080_100_I, XVIDC_VM_2048x1080_120_I, + XVIDC_VM_2880x480_60_I, + XVIDC_VM_2880x576_50_I, /* Progressive modes. */ @@ -113,7 +122,11 @@ typedef enum { XVIDC_VM_640x480_85_P, XVIDC_VM_720x400_85_P, XVIDC_VM_720x480_60_P, + XVIDC_VM_720x480_120_P, + XVIDC_VM_720x480_240_P, XVIDC_VM_720x576_50_P, + XVIDC_VM_720x576_100_P, + XVIDC_VM_720x576_200_P, XVIDC_VM_800x600_56_P, XVIDC_VM_800x600_60_P, XVIDC_VM_800x600_72_P, @@ -132,6 +145,8 @@ typedef enum { XVIDC_VM_1280x720_30_P, XVIDC_VM_1280x720_50_P, XVIDC_VM_1280x720_60_P, + XVIDC_VM_1280x720_100_P, + XVIDC_VM_1280x720_120_P, XVIDC_VM_1280x768_60_P, XVIDC_VM_1280x768_60_P_RB, XVIDC_VM_1280x768_75_P, @@ -159,6 +174,9 @@ typedef enum { XVIDC_VM_1400x1050_85_P, XVIDC_VM_1400x1050_120_P_RB, XVIDC_VM_1440x240_60_P, + XVIDC_VM_1440x288_50_P, + XVIDC_VM_1440x480_60_P, + XVIDC_VM_1440x576_50_P, XVIDC_VM_1440x900_60_P, XVIDC_VM_1440x900_60_P_RB, XVIDC_VM_1440x900_75_P, @@ -170,6 +188,9 @@ typedef enum { XVIDC_VM_1600x1200_75_P, XVIDC_VM_1600x1200_85_P, XVIDC_VM_1600x1200_120_P_RB, + XVIDC_VM_1680x720_24_P, + XVIDC_VM_1680x720_25_P, + XVIDC_VM_1680x720_30_P, XVIDC_VM_1680x720_50_P, XVIDC_VM_1680x720_60_P, XVIDC_VM_1680x720_100_P, @@ -211,6 +232,10 @@ typedef enum { XVIDC_VM_2048x1080_60_P, XVIDC_VM_2048x1080_100_P, XVIDC_VM_2048x1080_120_P, + XVIDC_VM_2560x1080_24_P, + XVIDC_VM_2560x1080_25_P, + XVIDC_VM_2560x1080_30_P, + XVIDC_VM_2560x1080_48_P, XVIDC_VM_2560x1080_50_P, XVIDC_VM_2560x1080_60_P, XVIDC_VM_2560x1080_100_P, @@ -220,6 +245,10 @@ typedef enum { XVIDC_VM_2560x1600_75_P, XVIDC_VM_2560x1600_85_P, XVIDC_VM_2560x1600_120_P_RB, + XVIDC_VM_2880x240_60_P, + XVIDC_VM_2880x288_50_P, + XVIDC_VM_2880x480_60_P, + XVIDC_VM_2880x576_50_P, XVIDC_VM_3840x2160_24_P, XVIDC_VM_3840x2160_25_P, XVIDC_VM_3840x2160_30_P, @@ -227,6 +256,8 @@ typedef enum { XVIDC_VM_3840x2160_50_P, XVIDC_VM_3840x2160_60_P, XVIDC_VM_3840x2160_60_P_RB, + XVIDC_VM_3840x2160_100_P, + XVIDC_VM_3840x2160_120_P, XVIDC_VM_4096x2160_24_P, XVIDC_VM_4096x2160_25_P, XVIDC_VM_4096x2160_30_P, @@ -234,6 +265,32 @@ typedef enum { XVIDC_VM_4096x2160_50_P, XVIDC_VM_4096x2160_60_P, XVIDC_VM_4096x2160_60_P_RB, + XVIDC_VM_4096x2160_100_P, + XVIDC_VM_4096x2160_120_P, + XVIDC_VM_5120x2160_24_P, + XVIDC_VM_5120x2160_25_P, + XVIDC_VM_5120x2160_30_P, + XVIDC_VM_5120x2160_48_P, + XVIDC_VM_5120x2160_50_P, + XVIDC_VM_5120x2160_60_P, + XVIDC_VM_5120x2160_100_P, + XVIDC_VM_5120x2160_120_P, + XVIDC_VM_7680x4320_24_P, + XVIDC_VM_7680x4320_25_P, + XVIDC_VM_7680x4320_30_P, + XVIDC_VM_7680x4320_48_P, + XVIDC_VM_7680x4320_50_P, + XVIDC_VM_7680x4320_60_P, + XVIDC_VM_7680x4320_120_P, + XVIDC_VM_7680x4320_100_P, + XVIDC_VM_10240x4320_24_P, + XVIDC_VM_10240x4320_25_P, + XVIDC_VM_10240x4320_30_P, + XVIDC_VM_10240x4320_48_P, + XVIDC_VM_10240x4320_50_P, + XVIDC_VM_10240x4320_60_P, + XVIDC_VM_10240x4320_100_P, + XVIDC_VM_10240x4320_120_P, XVIDC_VM_NUM_SUPPORTED, XVIDC_VM_USE_EDID_PREFERRED, @@ -249,6 +306,7 @@ typedef enum { /* Common naming. */ XVIDC_VM_480_60_I = XVIDC_VM_720x480_60_I, + XVIDC_VM_486_60_I = XVIDC_VM_720x486_60_I, XVIDC_VM_576_50_I = XVIDC_VM_720x576_50_I, XVIDC_VM_1080_50_I = XVIDC_VM_1920x1080_50_I, XVIDC_VM_1080_60_I = XVIDC_VM_1920x1080_60_I, @@ -307,7 +365,10 @@ typedef enum { XVIDC_FR_96HZ = 96, XVIDC_FR_100HZ = 100, XVIDC_FR_120HZ = 120, - XVIDC_FR_NUM_SUPPORTED = 18, + XVIDC_FR_144HZ = 144, + XVIDC_FR_200HZ = 200, + XVIDC_FR_240HZ = 240, + XVIDC_FR_NUM_SUPPORTED = 21, XVIDC_FR_UNKNOWN } XVidC_FrameRate; @@ -374,11 +435,22 @@ typedef enum { XVIDC_CSF_MEM_BGRX8, // [31:0] X:R:G:B 8:8:8:8 XVIDC_CSF_MEM_UYVY8, // [31:0] Y:V:Y:U 8:8:8:8 XVIDC_CSF_MEM_BGR8, // [23:0] R:G:B 8:8:8 + XVIDC_CSF_MEM_RGBX12, // [39:0] x:R:G:B 4:12:12:12 + XVIDC_CSF_MEM_YUVX12, // [39:0] x:V:U:Y 4:12:12:12 + XVIDC_CSF_MEM_Y_UV12, // [23:0] Y:Y 12:12, [23:0] V:U 12:12 + XVIDC_CSF_MEM_Y_UV12_420, // [23:0] Y:Y 12:12, [23:0] V:U 12:12 + XVIDC_CSF_MEM_Y12, // [39:0] x:Y2:Y1:Y0 4:12:12:12 + XVIDC_CSF_MEM_RGB16, // [47:0] R:G:B 16:16:16 + XVIDC_CSF_MEM_YUV16, // [47:0] V:U:Y 16:16:16 + XVIDC_CSF_MEM_Y_UV16, // [31:0] Y:Y 16:16, [31:0] V:U 16:16 + XVIDC_CSF_MEM_Y_UV16_420, // [31:0] Y:Y 16:16, [31:0] V:U 16:16 + XVIDC_CSF_MEM_Y16, // [47:0] Y2:Y1:Y0 16:16:16 XVIDC_CSF_MEM_END, // End of memory formats /* Streaming formats with components re-ordered */ XVIDC_CSF_YCBCR_422 = 64, XVIDC_CSF_YCBCR_420, + XVIDC_CSF_YCBCR_444, XVIDC_CSF_NUM_SUPPORTED, // includes the reserved slots XVIDC_CSF_UNKNOWN, @@ -548,8 +620,8 @@ typedef void (*XVidC_DelayHandler)(void *TimerPtr, u32 Delay); u32 XVidC_RegisterCustomTimingModes(const XVidC_VideoTimingMode *CustomTable, u16 NumElems); void XVidC_UnregisterCustomTimingModes(void); -u32 XVidC_GetPixelClockHzByHVFr(u32 HTotal, u32 VTotal, u8 FrameRate); -u32 XVidC_GetPixelClockHzByVmId(XVidC_VideoMode VmId); +u64 XVidC_GetPixelClockHzByHVFr(u32 HTotal, u32 VTotal, u8 FrameRate); +u64 XVidC_GetPixelClockHzByVmId(XVidC_VideoMode VmId); XVidC_VideoFormat XVidC_GetVideoFormat(XVidC_VideoMode VmId); u8 XVidC_IsInterlaced(XVidC_VideoMode VmId); const XVidC_VideoTimingMode* XVidC_GetVideoModeData(XVidC_VideoMode VmId); diff --git a/hdmi/phy-xilinx-vphy/xvidc_timings_table.c b/hdmi/phy-xilinx-vphy/xvidc_timings_table.c index 3764926..40de604 100644 --- a/hdmi/phy-xilinx-vphy/xvidc_timings_table.c +++ b/hdmi/phy-xilinx-vphy/xvidc_timings_table.c @@ -17,7 +17,6 @@ /** * * @file xvidc_timings_table.c - * @addtogroup video_common_v4_0 * @{ * * Contains video timings for various standard resolutions. @@ -38,6 +37,10 @@ * aad 07/10/17 Add XVIDC_VM_3840x2160_60_P_RB video format * aad 09/05/17 Fixed timings for 1366x768_60_P * aad 09/05/17 Added 1366x768_60_P_RB + * 4.4 eb 09/04/18 Fixed timings for 1280x720_24_P, 1280x720_25_P, + * 1280x720_30_P + * 4.5 jsr 07/03/18 Added timing for new video mode XVIDC_VM_720x486_60_I + * 4.5 mmo 02/14/19 Added 5k, 8k, 10k and Low Resolution with 200Hz, 240Hz * * *******************************************************************************/ @@ -81,15 +84,30 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = { XVIDC_VM_720x480_60_I, "720x480@60Hz (I)", XVIDC_FR_60HZ, {720, 19, 62, 57, 858, 0, 240, 4, 3, 15, 262, 5, 3, 15, 263, 0} }, + { XVIDC_VM_720x486_60_I, "720x486@60Hz (I)", XVIDC_FR_60HZ, + {720, 19, 62, 57, 858, 0, + 243, 1, 3, 15, 262, 2, 3, 15, 263, 0} }, { XVIDC_VM_720x576_50_I, "720x576@50Hz (I)", XVIDC_FR_50HZ, {720, 12, 63, 69, 864, 0, 288, 2, 3, 19, 312, 3, 3, 19, 313, 0} }, { XVIDC_VM_1440x480_60_I, "1440x480@60Hz (I)", XVIDC_FR_60HZ, {1440, 38, 124, 114, 1716, 0, 240, 4, 3, 15, 262, 5, 3, 15, 263, 0} }, + { XVIDC_VM_1440x480_120_I, "1440x480@120Hz (I)", XVIDC_FR_120HZ, + {1440, 38, 124, 114, 1716, 0, + 480, 4, 3, 15, 525, 0, 0, 0, 0, 0} }, + { XVIDC_VM_1440x480_240_I, "1440x480@240Hz (I)", XVIDC_FR_240HZ, + {1440, 38, 124, 114, 1716, 0, + 480, 4, 3, 15, 525, 0, 0, 0, 0, 0} }, { XVIDC_VM_1440x576_50_I, "1440x576@50Hz (I)", XVIDC_FR_50HZ, {1440, 24, 126, 138, 1728, 0, 288, 2, 3, 19, 312, 3, 3, 19, 313, 0} }, + { XVIDC_VM_1440x576_100_I, "1440x576@100Hz (I)", XVIDC_FR_100HZ, + {1440, 24, 126, 138, 1728, 0, + 576, 2, 3, 19, 625, 0, 0, 0, 0, 0} }, + { XVIDC_VM_1440x576_200_I, "1440x576@200Hz (I)", XVIDC_FR_200HZ, + {1440, 24, 126, 138, 1728, 0, + 576, 2, 3, 19, 625, 0, 0, 0, 0, 0} }, { XVIDC_VM_1920x1080_48_I, "1920x1080@48Hz (I)", XVIDC_FR_48HZ, {1920, 371, 88, 371, 2750, 1, 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, @@ -101,13 +119,13 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, { XVIDC_VM_1920x1080_96_I, "1920x1080@96Hz (I)", XVIDC_FR_96HZ, {1920, 371, 88, 371, 2750, 1, - 1080, 4, 10, 30, 1124, 6, 10, 30, 1126, 1} }, + 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, { XVIDC_VM_1920x1080_100_I, "1920x1080@100Hz (I)", XVIDC_FR_100HZ, {1920, 528, 44, 148, 2640, 1, - 1080, 4, 10, 30, 1124, 6, 10, 30, 1126, 1} }, + 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, { XVIDC_VM_1920x1080_120_I, "1920x1080@120Hz (I)", XVIDC_FR_120HZ, {1920, 88, 44, 148, 2200, 1, - 1080, 4, 10, 30, 1124, 6, 10, 30, 1126, 1} }, + 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, { XVIDC_VM_2048x1080_48_I, "2048x1080@48Hz (I)", XVIDC_FR_48HZ, {2048, 329, 44, 329, 2750, 1, 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, @@ -119,14 +137,19 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, { XVIDC_VM_2048x1080_96_I, "2048x1080@96Hz (I)", XVIDC_FR_96HZ, {2048, 329, 44, 329, 2750, 1, - 1080, 4, 10, 30, 1124, 6, 10, 30, 1126, 1} }, + 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, { XVIDC_VM_2048x1080_100_I, "2048x1080@100Hz (I)", XVIDC_FR_100HZ, {2048, 274, 44, 274, 2640, 1, - 1080, 4, 10, 30, 1124, 6, 10, 30, 1126, 1} }, + 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, { XVIDC_VM_2048x1080_120_I, "2048x1080@120Hz (I)", XVIDC_FR_120HZ, {2048, 66, 20, 66, 2200, 1, - 1080, 4, 10, 30, 1124, 6, 10, 30, 1126, 1} }, - + 540, 2, 5, 15, 562, 3, 5, 15, 563, 1} }, + { XVIDC_VM_2880x480_60_I, "2880x480@60Hz (I)", XVIDC_FR_60HZ, + {2880, 76, 248, 228, 3432, 0, + 240, 4, 3, 15, 262, 5, 3, 15, 263, 0} }, + {XVIDC_VM_2880x576_50_I, "2880x576@50Hz (I)", XVIDC_FR_50HZ, + {2880, 48, 252, 276, 3456, 0, + 576, 2, 3, 19, 312, 2, 3, 19, 313, 0} }, /* Progressive modes. */ { XVIDC_VM_640x350_85_P, "640x350@85Hz", XVIDC_FR_85HZ, @@ -150,9 +173,21 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = { XVIDC_VM_720x480_60_P, "720x480@60Hz", XVIDC_FR_60HZ, {720, 16, 62, 60, 858, 0, 480, 9, 6, 30, 525, 0, 0, 0, 0, 0} }, + { XVIDC_VM_720x480_120_P, "720x480@120Hz", XVIDC_FR_120HZ, + {720, 16, 62, 60, 858, 0, + 480, 9, 6, 30, 525, 0, 0, 0, 0, 0} }, + { XVIDC_VM_720x480_240_P, "720x480@240Hz", XVIDC_FR_240HZ, + {720, 16, 62, 60, 858, 0, + 480, 9, 6, 30, 525, 0, 0, 0, 0, 0} }, { XVIDC_VM_720x576_50_P, "720x576@50Hz", XVIDC_FR_50HZ, {720, 12, 64, 68, 864, 0, 576, 5, 5, 39, 625, 0, 0, 0, 0, 0} }, + { XVIDC_VM_720x576_100_P, "720x576@100Hz", XVIDC_FR_100HZ, + {720, 12, 64, 68, 864, 0, + 576, 5, 5, 39, 625, 0, 0, 0, 0, 0} }, + { XVIDC_VM_720x576_200_P, "720x576@200Hz", XVIDC_FR_200HZ, + {720, 12, 64, 68, 864, 0, + 576, 5, 5, 39, 625, 0, 0, 0, 0, 0} }, { XVIDC_VM_800x600_56_P, "800x600@56Hz", XVIDC_FR_56HZ, {800, 24, 72, 128, 1024, 1, 600, 1, 2, 22, 625, 0, 0, 0, 0, 1} }, @@ -193,13 +228,13 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = {1152, 64, 128, 256, 1600, 1, 864, 1, 3, 32, 900, 0, 0, 0, 0, 1} }, { XVIDC_VM_1280x720_24_P, "1280x720@24Hz", XVIDC_FR_24HZ, - {1280, 970, 905, 970, 4125, 1, + {1280, 1760, 40, 220, 3300, 1, 720, 5, 5, 20, 750, 0, 0, 0, 0, 1} }, { XVIDC_VM_1280x720_25_P, "1280x720@25Hz", XVIDC_FR_25HZ, - {1280, 970, 740, 970, 3960, 1, + {1280, 2420, 40, 220, 3960, 1, 720, 5, 5, 20, 750, 0, 0, 0, 0, 1} }, { XVIDC_VM_1280x720_30_P, "1280x720@30Hz", XVIDC_FR_30HZ, - {1280, 970, 80, 970, 3300, 1, + {1280, 1760, 40, 220, 3300, 1, 720, 5, 5, 20, 750, 0, 0, 0, 0, 1} }, { XVIDC_VM_1280x720_50_P, "1280x720@50Hz", XVIDC_FR_50HZ, {1280, 440, 40, 220, 1980, 1, @@ -207,6 +242,12 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = { XVIDC_VM_1280x720_60_P, "1280x720@60Hz", XVIDC_FR_60HZ, {1280, 110, 40, 220, 1650, 1, 720, 5, 5, 20, 750, 0, 0, 0, 0, 1} }, + { XVIDC_VM_1280x720_100_P, "1280x720@100Hz", XVIDC_FR_100HZ, + {1280, 440, 40, 220, 1980, 1, + 720, 5, 5, 20, 750, 0, 0, 0, 0, 1} }, + { XVIDC_VM_1280x720_120_P, "1280x720@120Hz", XVIDC_FR_120HZ, + {1280, 110, 40, 220, 1650, 1, + 720, 5, 5, 20, 750, 0, 0, 0, 0, 1} }, { XVIDC_VM_1280x768_60_P, "1280x768@60Hz", XVIDC_FR_60HZ, {1280, 64, 128, 192, 1664, 0, 768, 3, 7, 20, 798, 0, 0, 0, 0, 1} }, @@ -287,7 +328,16 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = 1050, 3, 4, 55, 1112, 0, 0, 0, 0, 0} }, { XVIDC_VM_1440x240_60_P, "1440x240@60Hz", XVIDC_FR_60HZ, {1440, 38, 124, 114, 1716, 0, - 240, 14, 3, 4, 262, 0, 0, 0, 0, 1} }, + 240, 4, 3, 15, 262, 0, 0, 0, 0, 1} }, + {XVIDC_VM_1440x288_50_P, "1440x288@50Hz", XVIDC_FR_50HZ, + {1440, 24, 126, 138, 1728, 0, + 288, 3, 3, 19, 313, 0, 0, 0, 0, 0} }, + { XVIDC_VM_1440x480_60_P, "1440x240@60Hz", XVIDC_FR_60HZ, + {1440, 32, 124, 120, 1716, 0, + 480, 9, 6, 30, 525, 0, 0, 0, 0, 0} }, + {XVIDC_VM_1440x576_50_P, "1440x576@50Hz", XVIDC_FR_50HZ, + {1440, 24, 128, 136, 1728, 0, + 576, 5, 5, 39, 625, 0, 0, 0, 0, 0} }, { XVIDC_VM_1440x900_60_P, "1440x900@60Hz", XVIDC_FR_60HZ, {1440, 80, 152, 232, 1904, 0, 900, 3, 6, 25, 934, 0, 0, 0, 0, 1} }, @@ -321,6 +371,15 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = { XVIDC_VM_1600x1200_120_P_RB, "1600x1200@120Hz (RB)", XVIDC_FR_120HZ, {1600, 48, 32, 80, 1760, 1, 1200, 3, 4, 64, 1271, 0, 0, 0, 0, 0} }, + {XVIDC_VM_1680x720_24_P, "1680x720@24Hz", XVIDC_FR_24HZ, + {1680, 1360, 40, 220, 3300, 1, + 720, 5, 5, 20, 750, 0, 0, 0, 0, 0} }, + {XVIDC_VM_1680x720_25_P, "1680x720@25Hz", XVIDC_FR_25HZ, + {1680, 1228, 40, 220, 3168, 1, + 720, 5, 5, 20, 750, 0, 0, 0, 0, 0} }, + {XVIDC_VM_1680x720_30_P, "1680x720@30Hz", XVIDC_FR_30HZ, + {1680, 700, 40, 220, 2640, 1, + 720, 5, 5, 20, 750, 0, 0, 0, 0, 0} }, { XVIDC_VM_1680x720_50_P, "1680x720@50Hz", XVIDC_FR_50HZ, {1680, 260, 40, 220, 2200, 1, 720, 5, 5, 20, 750, 0, 0, 0, 0, 1} }, @@ -444,6 +503,18 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = { XVIDC_VM_2048x1080_120_P, "2048x1080@120Hz", XVIDC_FR_120HZ, {2048, 88, 44, 148, 2200, 1, 1080, 4, 5, 36, 1125, 0, 0, 0, 0, 1} }, + { XVIDC_VM_2560x1080_24_P, "2560x1080@24Hz", XVIDC_FR_24HZ, + {2560, 998, 44, 148, 3750, 1, + 1080, 4, 5, 11, 1100, 0, 0, 0, 0, 1} }, + { XVIDC_VM_2560x1080_25_P, "2560x1080@25Hz", XVIDC_FR_25HZ, + {2560, 448, 44, 148, 3200, 1, + 1080, 4, 5, 36, 1125, 0, 0, 0, 0, 1} }, + { XVIDC_VM_2560x1080_30_P, "2560x1080@30Hz", XVIDC_FR_30HZ, + {2560, 768, 44, 148, 3520, 1, + 1080, 4, 5, 36, 1125, 0, 0, 0, 0, 1} }, + { XVIDC_VM_2560x1080_48_P, "2560x1080@48Hz", XVIDC_FR_48HZ, + {2560, 998, 44, 148, 3750, 1, + 1080, 4, 5, 11, 1100, 0, 0, 0, 0, 1} }, { XVIDC_VM_2560x1080_50_P, "2560x1080@50Hz", XVIDC_FR_50HZ, {2560, 548, 44, 148, 3300, 1, 1080, 4, 5, 36, 1125, 0, 0, 0, 0, 1} }, @@ -471,6 +542,18 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = { XVIDC_VM_2560x1600_120_P_RB, "2560x1600@120Hz (RB)", XVIDC_FR_120HZ, {2560, 48, 32, 80, 2720, 1, 1600, 3, 6, 85, 1694, 0, 0, 0, 0, 0} }, + { XVIDC_VM_2880x240_60_P, "2880x240@60Hz", XVIDC_FR_60HZ, + {2880, 76, 248, 228, 3432, 0, + 240, 14, 3, 4, 262, 0, 0, 0, 0, 1} }, + { XVIDC_VM_2880x288_50_P, "2880x288@50Hz", XVIDC_FR_50HZ, + {2880, 48, 252, 276, 3456, 0, + 288, 3, 3, 19, 313, 0, 0, 0, 0, 0} }, + {XVIDC_VM_2880x480_60_P, "2880x480@60Hz", XVIDC_FR_60HZ, + {2880, 64, 248, 240, 3432, 0, + 480, 9, 6, 30, 525, 0, 0, 0, 0, 0} }, + {XVIDC_VM_2880x576_50_P, "2880x576@50Hz", XVIDC_FR_50HZ, + {2880, 48, 256, 272, 3456, 0, + 576, 5, 5, 39, 625, 0, 0, 0, 0, 0} }, { XVIDC_VM_3840x2160_24_P, "3840x2160@24Hz", XVIDC_FR_24HZ, {3840, 1276, 88, 296, 5500, 1, 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, @@ -492,6 +575,12 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = { XVIDC_VM_3840x2160_60_P_RB, "3840x2160@60Hz (RB)", XVIDC_FR_60HZ, {3840, 48, 32, 80, 4000, 1, 2160, 3, 5, 54, 2222, 0, 0, 0, 0, 0} }, + { XVIDC_VM_3840x2160_100_P, "3840x2160@100Hz", XVIDC_FR_100HZ, + {3840, 1056, 88, 296, 5280, 1, + 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, + { XVIDC_VM_3840x2160_120_P, "3840x2160@120Hz", XVIDC_FR_120HZ, + {3840, 176, 88, 296, 4400, 1, + 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, { XVIDC_VM_4096x2160_24_P, "4096x2160@24Hz", XVIDC_FR_24HZ, {4096, 1020, 88, 296, 5500, 1, 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, @@ -513,6 +602,84 @@ const XVidC_VideoTimingMode XVidC_VideoTimingModes[XVIDC_VM_NUM_SUPPORTED] = { XVIDC_VM_4096x2160_60_P_RB, "4096x2160@60Hz (RB)", XVIDC_FR_60HZ, {4096, 8, 32, 40, 4176, 1, 2160, 48, 8, 6, 2222, 0, 0, 0, 0, 0} }, + { XVIDC_VM_4096x2160_100_P, "4096x2160@100Hz", XVIDC_FR_100HZ, + {4096, 800, 88, 296, 5280, 1, + 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, + { XVIDC_VM_4096x2160_120_P, "4096x2160@120Hz", XVIDC_FR_120HZ, + {4096, 88, 88, 128, 4400, 1, + 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, + { XVIDC_VM_5120x2160_24_P, "5120x2160@24Hz", XVIDC_FR_24HZ, + {5120, 1996, 88, 296, 7500, 1, + 2160, 8, 10, 22, 2200, 0, 0, 0, 0, 1} }, + { XVIDC_VM_5120x2160_25_P, "5120x2160@25Hz", XVIDC_FR_25HZ, + {5120, 1696, 88, 296, 7200, 1, + 2160, 8, 10, 22, 2200, 0, 0, 0, 0, 1} }, + { XVIDC_VM_5120x2160_30_P, "5120x2160@30Hz", XVIDC_FR_30HZ, + {5120, 664, 88, 128, 6000, 1, + 2160, 8, 10, 22, 2200, 0, 0, 0, 0, 1} }, + { XVIDC_VM_5120x2160_48_P, "5120x2160@48Hz", XVIDC_FR_48HZ, + {5120, 746, 88, 296, 6250, 1, + 2160, 8, 10, 297, 2475, 0, 0, 0, 0, 1} }, + { XVIDC_VM_5120x2160_50_P, "5120x2160@50Hz", XVIDC_FR_50HZ, + {5120, 1096, 88, 296, 6600, 1, + 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, + { XVIDC_VM_5120x2160_60_P, "5120x2160@60Hz", XVIDC_FR_60HZ, + {5120, 164, 88, 128, 5500, 1, + 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, + { XVIDC_VM_5120x2160_100_P, "5120x2160@100Hz", XVIDC_FR_100HZ, + {5120, 1096, 88, 296, 6600, 1, + 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, + { XVIDC_VM_5120x2160_120_P, "5120x2160@120Hz", XVIDC_FR_120HZ, + {5120, 164, 88, 128, 5500, 1, + 2160, 8, 10, 72, 2250, 0, 0, 0, 0, 1} }, + { XVIDC_VM_7680x4320_24_P, "7680x4320@24Hz", XVIDC_FR_24HZ, + {7680, 2552, 176, 592, 11000, 1, + 4320, 16, 20, 144, 4500, 0, 0, 0, 0, 1} }, + { XVIDC_VM_7680x4320_25_P, "7680x4320@25Hz", XVIDC_FR_25HZ, + {7680, 2352, 176, 592, 10800, 1, + 4320, 16, 20, 44, 4400, 0, 0, 0, 0, 1} }, + { XVIDC_VM_7680x4320_30_P, "7680x4320@30Hz", XVIDC_FR_30HZ, + {7680, 552, 176, 592, 9000, 1, + 4320, 16, 20, 44, 4400, 0, 0, 0, 0, 1} }, + { XVIDC_VM_7680x4320_48_P, "7680x4320@48Hz", XVIDC_FR_48HZ, + {7680, 2552, 176, 592, 11000, 1, + 4320, 16, 20, 144, 4500, 0, 0, 0, 0, 1} }, + { XVIDC_VM_7680x4320_50_P, "7680x4320@50Hz", XVIDC_FR_50HZ, + {7680, 2352, 176, 592, 10800, 1, + 4320, 16, 20, 44, 4400, 0, 0, 0, 0, 1} }, + { XVIDC_VM_7680x4320_60_P, "7680x4320@60Hz", XVIDC_FR_60HZ, + {7680, 552, 176, 592, 9000, 1, + 4320, 16, 20, 44, 4400, 0, 0, 0, 0, 1} }, + { XVIDC_VM_7680x4320_100_P, "7680x4320@100Hz" , XVIDC_FR_100HZ, + {7680, 2112, 176, 592, 10560, 1, + 4320, 16, 20, 144, 4500, 0, 0, 0, 0, 1} }, + { XVIDC_VM_7680x4320_120_P, "7680x4320@120Hz" , XVIDC_FR_120HZ, + {7680, 352, 176, 592, 8800, 1, + 4320, 16, 20, 144, 4500, 0, 0, 0, 0, 1} }, + { XVIDC_VM_10240x4320_24_P, "10240x4320@24Hz", XVIDC_FR_24HZ, + {10240, 1492, 176, 592, 12500, 1, + 4320, 16, 20, 594, 4950, 0, 0, 0, 0, 1} }, + { XVIDC_VM_10240x4320_25_P, "10240x4320@25Hz", XVIDC_FR_25HZ, + {10240, 2492, 176, 592, 13500, 1, + 4320, 16, 20, 44, 4400, 0, 0, 0, 0, 1} }, + { XVIDC_VM_10240x4320_30_P, "10240x4320@30Hz", XVIDC_FR_30HZ, + {10240, 288, 176, 296, 11000, 1, + 4320, 16, 20, 144, 4500, 0, 0, 0, 0, 1} }, + { XVIDC_VM_10240x4320_48_P, "10240x4320@48Hz", XVIDC_FR_48HZ, + {10240, 1492, 176, 592, 12500, 1, + 4320, 16, 20, 594, 4950, 0, 0, 0, 0, 1} }, + { XVIDC_VM_10240x4320_50_P, "10240x4320@50Hz", XVIDC_FR_50HZ, + {10240, 2492, 176, 592, 13500, 1, + 4320, 16, 20, 44, 4400, 0, 0, 0, 0, 1} }, + { XVIDC_VM_10240x4320_60_P, "10240x4320@60Hz", XVIDC_FR_60HZ, + {10240, 288, 176, 296, 11000, 1, + 4320, 16, 20, 144, 4500, 0, 0, 0, 0, 1} }, + { XVIDC_VM_10240x4320_100_P, "10240x4320@100Hz", XVIDC_FR_100HZ, + {10240, 2192, 176, 592, 13200, 1, + 4320, 16, 20, 144, 4500, 0, 0, 0, 0, 1} }, + { XVIDC_VM_10240x4320_120_P, "10240x4320@120Hz", XVIDC_FR_120HZ, + {10240, 288, 176, 296, 11000, 1, + 4320, 16, 20, 144, 4500, 0, 0, 0, 0, 1} }, }; /** @} */ diff --git a/hdmi/phy-xilinx-vphy/xvphy.c b/hdmi/phy-xilinx-vphy/xvphy.c index e70845f..540b6cb 100644 --- a/hdmi/phy-xilinx-vphy/xvphy.c +++ b/hdmi/phy-xilinx-vphy/xvphy.c @@ -61,6 +61,12 @@ * Moved XVphy_MmcmWriteParameters to xvphy_mmcme2/3/4.c * Added XVphy_SetPolarity, XVphy_SetPrbsSel and * XVphy_TxPrbsForceError APIs + * 1.8 gm 05/14/18 Removed XVphy_DrpWrite and XVphy_DrpRead APIs + * 23/07/18 Added APIs XVphy_SetTxVoltageSwing and + * XVphy_SetTxPreEmphasis from xvphy_i.c/h + * Added XVphy_SetTxPostCursor API + * 1.9 gm 14/05/18 Added XVphy_SetRxLpm from xvphy_i.c/.h + * * * *******************************************************************************/ @@ -945,71 +951,161 @@ u32 XVphy_TxPrbsForceError(XVphy *InstancePtr, u8 QuadId, /*****************************************************************************/ /** -* This function will initiate a write DRP transaction. It is a wrapper around -* XVphy_DrpAccess. +* This function will set the TX voltage swing value for a given channel. * * @param InstancePtr is a pointer to the XVphy core instance. * @param QuadId is the GT quad ID to operate on. -* @param ChId is the channel ID on which to direct the DRP access. -* @param Dir is an indicator for write (TX) or read (RX). -* @param Addr is the DRP address to issue the DRP access to. -* @param Val is the value to write to the DRP address. +* @param ChId is the channel ID to operate on. +* @param Vs is the voltage swing value to write. * -* @return -* - XST_SUCCESS if the DRP access was successful. -* - XST_FAILURE otherwise, if the busy bit did not go low, or if -* the ready bit did not go high. +* @return None. * * @note None. * -* @deprecated XVphy_DrpWrite will be deprecated in 2018.3 and replaced by -* XVphy_DrpWr to align with new naming of XVphy_DrpRd API. -* No functional change between XVphy_DrpWrite & XVphy_DrpWr. +******************************************************************************/ +void XVphy_SetTxVoltageSwing(XVphy *InstancePtr, u8 QuadId, + XVphy_ChannelId ChId, u8 Vs) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if ((ChId == XVPHY_CHANNEL_ID_CH1) || (ChId == XVPHY_CHANNEL_ID_CH2)) { + RegOffset = XVPHY_TX_DRIVER_CH12_REG; + } + else { + RegOffset = XVPHY_TX_DRIVER_CH34_REG; + } + RegVal = XVphy_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + MaskVal = XVPHY_TX_DRIVER_TXDIFFCTRL_MASK(ChId); + RegVal &= ~MaskVal; + RegVal |= (Vs << XVPHY_TX_DRIVER_TXDIFFCTRL_SHIFT(ChId)); + XVphy_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); +} + +/*****************************************************************************/ +/** +* This function will set the TX pre-emphasis value for a given channel. +* +* @param InstancePtr is a pointer to the XVphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Pe is the pre-emphasis value to write. +* +* @return None. +* +* @note None. * ******************************************************************************/ -u32 XVphy_DrpWrite(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, - u16 Addr, u16 Val) +void XVphy_SetTxPreEmphasis(XVphy *InstancePtr, u8 QuadId, + XVphy_ChannelId ChId, u8 Pe) { - return XVphy_DrpAccess(InstancePtr, QuadId, ChId, - XVPHY_DIR_TX, /* Write. */ - Addr, &Val); + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if ((ChId == XVPHY_CHANNEL_ID_CH1) || (ChId == XVPHY_CHANNEL_ID_CH2)) { + RegOffset = XVPHY_TX_DRIVER_CH12_REG; + } + else { + RegOffset = XVPHY_TX_DRIVER_CH34_REG; + } + RegVal = XVphy_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + MaskVal = XVPHY_TX_DRIVER_TXPRECURSOR_MASK(ChId); + RegVal &= ~MaskVal; + RegVal |= (Pe << XVPHY_TX_DRIVER_TXPRECURSOR_SHIFT(ChId)); + XVphy_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); } /*****************************************************************************/ /** -* This function will initiate a read DRP transaction. It is a wrapper around -* XVphy_DrpAccess. +* This function will set the TX post-curosr value for a given channel. * * @param InstancePtr is a pointer to the XVphy core instance. * @param QuadId is the GT quad ID to operate on. -* @param ChId is the channel ID on which to direct the DRP access. -* @param Dir is an indicator for write (TX) or read (RX). -* @param Addr is the DRP address to issue the DRP access to. +* @param ChId is the channel ID to operate on. +* @param Pe is the pre-emphasis value to write. * -* @return -* - XST_SUCCESS if the DRP access was successful. -* - XST_FAILURE otherwise, if the busy bit did not go low, or if -* the ready bit did not go high. +* @return None. * * @note None. * -* @deprecated XVphy_DrpRead will be deprecated in 2018.3 and replaced by -* XVphy_DrpRd to separate the return value of DRP register -* content and XST_SUCCESS/XST_FAILURE. -* A new argument (*RetVal) was added in XVphy_DrpRd to hold the -* DRP register content +******************************************************************************/ +void XVphy_SetTxPostCursor(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, + u8 Pc) +{ + u32 RegVal; + u32 MaskVal; + u32 RegOffset; + + /* Suppress Warning Messages */ + QuadId = QuadId; + + if ((ChId == XVPHY_CHANNEL_ID_CH1) || (ChId == XVPHY_CHANNEL_ID_CH2)) { + RegOffset = XVPHY_TX_DRIVER_CH12_REG; + } + else { + RegOffset = XVPHY_TX_DRIVER_CH34_REG; + } + RegVal = XVphy_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); + + MaskVal = XVPHY_TX_DRIVER_TXPOSTCURSOR_MASK(ChId); + RegVal &= ~MaskVal; + RegVal |= (Pc << XVPHY_TX_DRIVER_TXPOSTCURSOR_SHIFT(ChId)); + XVphy_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); +} + +/*****************************************************************************/ +/** +* This function will enable or disable the LPM logic in the Video PHY core. +* +* @param InstancePtr is a pointer to the XVphy core instance. +* @param QuadId is the GT quad ID to operate on. +* @param ChId is the channel ID to operate on. +* @param Dir is an indicator for TX or RX. +* @param Enable will enable (if 1) or disable (if 0) the LPM logic. +* +* @return None. +* +* @note None. * ******************************************************************************/ -u16 XVphy_DrpRead(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, u16 Addr) +void XVphy_SetRxLpm(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, + XVphy_DirectionType Dir, u8 Enable) { - u32 Status; - u16 Val; + u32 RegVal; + u32 MaskVal; - Status = XVphy_DrpAccess(InstancePtr, QuadId, ChId, - XVPHY_DIR_RX, /* Read. */ - Addr, &Val); + /* Suppress Warning Messages */ + QuadId = QuadId; + Dir = Dir; + + RegVal = XVphy_ReadReg(InstancePtr->Config.BaseAddr, + XVPHY_RX_EQ_CDR_REG); + + if (ChId == XVPHY_CHANNEL_ID_CHA) { + MaskVal = XVPHY_RX_CONTROL_RXLPMEN_ALL_MASK; + } + else { + MaskVal = XVPHY_RX_CONTROL_RXLPMEN_MASK(ChId); + } - return (Status == XST_SUCCESS) ? Val : 0xDEAD; + if (Enable) { + RegVal |= MaskVal; + } + else { + RegVal &= ~MaskVal; + } + XVphy_WriteReg(InstancePtr->Config.BaseAddr, XVPHY_RX_EQ_CDR_REG, + RegVal); } /*****************************************************************************/ @@ -1154,8 +1250,8 @@ void XVphy_MmcmStart(XVphy *InstancePtr, u8 QuadId, XVphy_DirectionType Dir) #endif #if defined (XPAR_XV_HDMITX_0_DEVICE_ID) || defined (XPAR_XV_HDMIRX_0_DEVICE_ID) #if defined (XPAR_XDP_0_DEVICE_ID) - } else if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI || - InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + } else if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX) || + XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { #endif XVphy_Mmcm *MmcmPtr; diff --git a/hdmi/phy-xilinx-vphy/xvphy.h b/hdmi/phy-xilinx-vphy/xvphy.h index 5f0fbc1..eedf6f2 100644 --- a/hdmi/phy-xilinx-vphy/xvphy.h +++ b/hdmi/phy-xilinx-vphy/xvphy.h @@ -17,7 +17,6 @@ /** * * @file xvphy.h - * @addtogroup xvphy * @{ * @details * This is main header file of the Xilinx Video PHY Controller driver @@ -80,6 +79,13 @@ * 1.7 gm 13/09/17 Added GTYE4 support * Added XVphy_SetPolarity, XVphy_SetPrbsSel and * XVphy_TxPrbsForceError APIs + * 1.8 gm 05/14/18 Updated CDR values for DP in xvphy_gtye4.c + * Removed XVphy_DrpWrite and XVphy_DrpRead APIs + * 23/07/18 Added APIs XVphy_SetTxVoltageSwing and + * XVphy_SetTxPreEmphasis from xvphy_i.c/h + * Added XVphy_SetTxPostCursor API + * 1.9 gm 14/05/18 Added XVphy_SetRxLpm from xvphy_i.c/.h + * Removed deprecated XVphy_HdmiInitialize API * * *******************************************************************************/ @@ -88,6 +94,10 @@ /* Prevent circular inclusions by using protection macros. */ #define XVPHY_H_ +#ifdef __cplusplus +extern "C" { +#endif + #if !defined(XV_CONFIG_LOG_VPHY_DISABLE) && !defined(XV_CONFIG_LOG_DISABLE_ALL) #define XV_VPHY_LOG_ENABLE #endif @@ -116,8 +126,8 @@ typedef enum { */ typedef enum { XVPHY_PROTOCOL_DP = 0, - XVPHY_PROTOCOL_HDMI, - XVPHY_PROTOCOL_NONE + XVPHY_PROTOCOL_HDMI = 1, + XVPHY_PROTOCOL_NONE = 3 } XVphy_ProtocolType; /* This typedef enumerates is used to specify RX/TX direction information. */ @@ -857,12 +867,16 @@ u32 XVphy_SetPrbsSel(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, XVphy_DirectionType Dir, XVphy_PrbsPattern Pattern); u32 XVphy_TxPrbsForceError(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, u8 ForceErr); +void XVphy_SetTxVoltageSwing(XVphy *InstancePtr, u8 QuadId, + XVphy_ChannelId ChId, u8 Vs); +void XVphy_SetTxPreEmphasis(XVphy *InstancePtr, u8 QuadId, + XVphy_ChannelId ChId, u8 Pe); +void XVphy_SetTxPostCursor(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, + u8 Pc); +void XVphy_SetRxLpm(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, + XVphy_DirectionType Dir, u8 Enable); /* xvphy.c: GT/MMCM DRP access. */ -u32 XVphy_DrpWrite(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, - u16 Addr, u16 Val) __attribute__ ((deprecated)); -u16 XVphy_DrpRead(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, - u16 Addr) __attribute__ ((deprecated)); u32 XVphy_DrpWr(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, u16 Addr, u16 Val); u16 XVphy_DrpRd(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, @@ -916,8 +930,6 @@ u32 XVphy_DpInitialize(XVphy *InstancePtr, XVphy_Config *CfgPtr, u8 QuadId, XVphy_PllRefClkSelType QpllRefClkSel, XVphy_PllType TxPllSelect, XVphy_PllType RxPllSelect, u8 LinkRate); -u32 XVphy_HdmiInitialize(XVphy *InstancePtr, u8 QuadId, XVphy_Config *CfgPtr, - u32 SystemFrequency) __attribute__ ((deprecated)); u32 XVphy_Hdmi_CfgInitialize(XVphy *InstancePtr, u8 QuadId, XVphy_Config *CfgPtr); u32 XVphy_SetHdmiTxParam(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, @@ -991,5 +1003,9 @@ void XVphy_RegisterDebug(XVphy *InstancePtr); #define XVPHY_GTHE4 5 #define XVPHY_GTYE4 6 +#ifdef __cplusplus +} +#endif + #endif /* XVPHY_H_ */ /** @} */ diff --git a/hdmi/phy-xilinx-vphy/xvphy_gt.h b/hdmi/phy-xilinx-vphy/xvphy_gt.h index d960163..f73888b 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_gt.h +++ b/hdmi/phy-xilinx-vphy/xvphy_gt.h @@ -38,7 +38,6 @@ * 1.7 gm 13/09/17 Added GTYE4 support * * - * @addtogroup xvphy * @{ *******************************************************************************/ @@ -46,6 +45,10 @@ /* Prevent circular inclusions by using protection macros. */ #define XVPHY_GT_H_ +#ifdef __cplusplus +extern "C" { +#endif + /******************************* Include Files ********************************/ #include "xvphy.h" @@ -119,5 +122,9 @@ extern const XVphy_GtConfig Gthe4Config; extern const XVphy_GtConfig Gtye4Config; #endif +#ifdef __cplusplus +} +#endif + #endif /* XVPHY_GT_H_ */ /** @} */ \ No newline at end of file diff --git a/hdmi/phy-xilinx-vphy/xvphy_gthe4.c b/hdmi/phy-xilinx-vphy/xvphy_gthe4.c index 473fa75..c9cc357 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_gthe4.c +++ b/hdmi/phy-xilinx-vphy/xvphy_gthe4.c @@ -29,11 +29,11 @@ * * Ver Who Date Changes * ----- ---- -------- ----------------------------------------------- - * 1.0 als 10/19/15 Initial release. - * 1.1 gm 03/18/16 Added XVphy_Gthe4RxPllRefClkDiv1Reconfig function + * 1.0 als 19/10/15 Initial release. + * 1.1 gm 18/03/16 Added XVphy_Gthe4RxPllRefClkDiv1Reconfig function * Added XVphy_Gthe4TxChReconfig function * Corrected RXCDRCFG2 values - * 1.2 gm 08/26/16 Suppressed warning messages due to unused arguments + * 1.2 gm 26/08/16 Suppressed warning messages due to unused arguments * 1.4 gm 29/11/16 Added preprocessor directives for sw footprint reduction * Changed TX reconfig hook from TxPllRefClkDiv1Reconfig to * TxChReconfig @@ -53,6 +53,8 @@ * 1.7 gm 13/09/17 Disabled intelligent clock sel in QPLL0/1 configuration * Updated DP CDR config for 8.1 Gbps * Updated XVPHY_QPLL0_MAX to 16375000000LL + * 1.8 gm 05/09/18 Enable IPS only when XVphy_GetRefClkSourcesCount + * returns more than 1. * * *******************************************************************************/ @@ -196,7 +198,8 @@ u32 XVphy_Gthe4CfgSetCdr(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId) ChPtr->PllParams.Cdr[1] = 0x0000; ChPtr->PllParams.Cdr[3] = 0x0000; ChPtr->PllParams.Cdr[4] = 0x0000; - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { /* RxOutDiv = 1 => Cdr[2] = 0x0269 * RxOutDiv = 2 => Cdr[2] = 0x0259 * RxOutDiv = 4 => Cdr[2] = 0x0249 @@ -443,7 +446,9 @@ u32 XVphy_Gthe4ClkCmnReconfig(XVphy *InstancePtr, u8 QuadId, /* Mask out QPLLx_REFCLK_DIV. */ DrpVal &= ~(0xF80); /* Disable Intelligent Reference Clock Selection */ - DrpVal |= (1 << 6); + if (XVphy_GetRefClkSourcesCount(InstancePtr) > 1) { + DrpVal |= (1 << 6); + } /* Set QPLLx_REFCLK_DIV. */ WriteVal = (XVphy_MToDrpEncoding(InstancePtr, QuadId, CmnId) & 0x1F); DrpVal |= (WriteVal << 7); @@ -451,8 +456,8 @@ u32 XVphy_Gthe4ClkCmnReconfig(XVphy *InstancePtr, u8 QuadId, Status |= XVphy_DrpWr(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CMN, (CmnId == XVPHY_CHANNEL_ID_CMN0) ? 0x18 : 0x98, DrpVal); - if ((InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) || - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI)) { + if ((XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) || + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX))) { QpllxVcoRateMHz = XVphy_GetPllVcoFreqHz(InstancePtr, QuadId, CmnId, XVphy_IsTxUsingQpll(InstancePtr, QuadId, CmnId) ? @@ -594,7 +599,7 @@ u32 XVphy_Gthe4RxChReconfig(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId) } } - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { /* RX_INT_DATAWIDTH */ Status |= XVphy_DrpRd(InstancePtr, QuadId, ChId, 0x66, &DrpVal); DrpVal &= ~(0x3); @@ -759,7 +764,7 @@ u32 XVphy_Gthe4TxChReconfig(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId) u32 Status = XST_SUCCESS; ReturnVal = XVphy_Gthe4TxPllRefClkDiv1Reconfig(InstancePtr, QuadId, ChId); - if (InstancePtr->Config.TxProtocol != XVPHY_PROTOCOL_HDMI) { + if (!XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { return ReturnVal; } @@ -784,7 +789,7 @@ u32 XVphy_Gthe4TxChReconfig(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId) break; } - if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { ChPtr = &InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(ChId)]; /* TX_INT_DATAWIDTH */ @@ -888,7 +893,7 @@ u32 XVphy_Gthe4TxPllRefClkDiv1Reconfig(XVphy *InstancePtr, u8 QuadId, XVphy_Channel *PllPtr = &InstancePtr->Quads[QuadId]. Plls[XVPHY_CH2IDX(ChId)]; - if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { TxRefClkHz = InstancePtr->HdmiTxRefClkHz; } else { @@ -930,7 +935,7 @@ u32 XVphy_Gthe4RxPllRefClkDiv1Reconfig(XVphy *InstancePtr, u8 QuadId, XVphy_Channel *PllPtr = &InstancePtr->Quads[QuadId]. Plls[XVPHY_CH2IDX(ChId)]; - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { RxRefClkHz = InstancePtr->HdmiRxRefClkHz; } else { diff --git a/hdmi/phy-xilinx-vphy/xvphy_hdmi.c b/hdmi/phy-xilinx-vphy/xvphy_hdmi.c index f663f47..8487d59 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_hdmi.c +++ b/hdmi/phy-xilinx-vphy/xvphy_hdmi.c @@ -70,6 +70,10 @@ * Added userclk freq checking in XVphy_HdmiCpllParam & * XVphy_HdmiQpllParam API * Removed XVphy_DruSetGain API + * 1.8 gm 05/14/18 Fixed a bug in XVphy_HdmiQpllParam where linerate is + * obtained from CH1 instead of QPLL0/1 + * 1.9 gm 14/05/18 Added TX and RX MMCM lock event logging + * Removed deprecated XVphy_HdmiInitialize API * * * @@ -108,213 +112,6 @@ static void XVphy_HdmiSetSystemClockSelection(XVphy *InstancePtr, u8 QuadId); /**************************** Function Definitions ****************************/ -/******************************************************************************/ -/** - * This function initializes the Video PHY for HDMI. - * - * @param InstancePtr is a pointer to the XVphy instance. - * @param CfgPtr is a pointer to the configuration structure that will - * be used to copy the settings from. - * @param SystemFrequency is the system frequency for the HDMI logic - * to be based on. - * - * @return None. - * - * @note None. - * - * @deprecated XVphy_HdmiInitialize will be deprecated in 2018.3 and replaced - * by XVphy_Hdmi_CfgInitialize. - * -*******************************************************************************/ -u32 XVphy_HdmiInitialize(XVphy *InstancePtr, u8 QuadId, XVphy_Config *CfgPtr, - u32 SystemFrequency) -{ - u8 Id, Id0, Id1; - - /* Verify arguments. */ - Xil_AssertNonvoid(InstancePtr != NULL); - Xil_AssertNonvoid(CfgPtr != NULL); - - /* Init done. */ - XVphy_LogWrite(InstancePtr, XVPHY_LOG_EVT_INIT, 0); - - /* Setup the instance. */ - XVphy_CfgInitialize(InstancePtr, CfgPtr, CfgPtr->BaseAddr); - - /* Set default. */ - XVphy_Ch2Ids(InstancePtr, XVPHY_CHANNEL_ID_CHA, &Id0, &Id1); - for (Id = Id0; Id <= Id1; Id++) { - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)].TxState = - XVPHY_GT_STATE_IDLE; - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)].RxState = - XVPHY_GT_STATE_IDLE; - //Initialize Transceiver Width values - if (InstancePtr->Config.TransceiverWidth == 2) { - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. - TxDataWidth = 20; - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. - TxIntDataWidth = 2; - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. - RxDataWidth = 20; - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. - RxIntDataWidth = 2; - } - else { - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. - TxDataWidth = 40; - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. - TxIntDataWidth = 4; - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. - RxDataWidth = 40; - InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. - RxIntDataWidth = 4; - } - } - - /* Interrupt Disable. */ - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TXRESET_DONE); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_RXRESET_DONE); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_CPLL_LOCK); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_QPLL0_LOCK); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TXALIGN_DONE); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_QPLL1_LOCK); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT); - XVphy_IntrDisable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); - - /* Setup HDMI interrupt handler callback*/ - XVphy_HdmiIntrHandlerCallbackInit(InstancePtr); - - /* Configure clock detector. */ - XVphy_ClkDetEnable(InstancePtr, FALSE); - XVphy_ClkDetSetFreqTimeout(InstancePtr, SystemFrequency); - XVphy_ClkDetSetFreqLockThreshold(InstancePtr, 40); - - /* Start capturing logs. */ - XVphy_LogReset(InstancePtr); - XVphy_LogWrite(InstancePtr, XVPHY_LOG_EVT_INIT, 0); - - XVphy_HdmiSetSystemClockSelection(InstancePtr, QuadId); - - /* Indicate of QPLL is present in design */ - if ((XVphy_IsTxUsingQpll(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CH1) && - (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI)) || - (XVphy_IsRxUsingQpll(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CH1) && - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI))) { - InstancePtr->HdmiIsQpllPresent = TRUE; - } else { - InstancePtr->HdmiIsQpllPresent = FALSE; - } - - if ((InstancePtr->Config.XcvrType == XVPHY_GT_TYPE_GTHE3) || - (InstancePtr->Config.XcvrType == XVPHY_GT_TYPE_GTHE4) || - (InstancePtr->Config.XcvrType == XVPHY_GT_TYPE_GTYE4)) { - XVphy_SetBufgGtDiv(InstancePtr, XVPHY_DIR_TX, 1); - XVphy_SetBufgGtDiv(InstancePtr, XVPHY_DIR_RX, 1); - } - XVphy_ResetGtPll(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CHA, - XVPHY_DIR_RX, TRUE); - XVphy_ResetGtPll(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CHA, - XVPHY_DIR_TX, TRUE); - if ((InstancePtr->Config.XcvrType == XVPHY_GT_TYPE_GTXE2) || - (InstancePtr->Config.XcvrType == XVPHY_GT_TYPE_GTPE2)) { - XVphy_ResetGtTxRx(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CHA, - XVPHY_DIR_RX, TRUE); - XVphy_ResetGtTxRx(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CHA, - XVPHY_DIR_TX, TRUE); - } - if (InstancePtr->Config.XcvrType != XVPHY_GT_TYPE_GTPE2) { - XVphy_PowerDownGtPll(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CMNA, - TRUE); - XVphy_PowerDownGtPll(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CHA, - TRUE); - } - XVphy_MmcmReset(InstancePtr, QuadId, XVPHY_DIR_TX, TRUE); - XVphy_MmcmReset(InstancePtr, QuadId, XVPHY_DIR_RX, TRUE); - if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { - XVphy_IBufDsEnable(InstancePtr, QuadId, XVPHY_DIR_TX, (FALSE)); - } - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { - XVphy_IBufDsEnable(InstancePtr, QuadId, XVPHY_DIR_RX, (FALSE)); - } - - /* DRU Settings. */ - if (InstancePtr->Config.DruIsPresent) { - XVphy_IBufDsEnable(InstancePtr, QuadId, XVPHY_DIR_RX, TRUE); - XVphy_DruReset(InstancePtr, XVPHY_CHANNEL_ID_CHA, TRUE); - XVphy_DruEnable(InstancePtr, XVPHY_CHANNEL_ID_CHA, FALSE); - } - - XVphy_SetRxLpm(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX, - 1); - - XVphy_Ch2Ids(InstancePtr, XVPHY_CHANNEL_ID_CHA, &Id0, &Id1); - for (Id = Id0; Id <= Id1; Id++) { -#if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTHE3 || \ - XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTHE4 || \ - XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTYE4) - XVphy_SetTxVoltageSwing(InstancePtr, QuadId, (XVphy_ChannelId)Id, 0xC); -#else - XVphy_SetTxVoltageSwing(InstancePtr, QuadId, (XVphy_ChannelId)Id, 0x1); -#endif - XVphy_SetTxPreEmphasis(InstancePtr, QuadId, (XVphy_ChannelId)Id, 0x1); - } - - /* Clear Interrupt Register */ - XVphy_WriteReg(InstancePtr->Config.BaseAddr, XVPHY_INTR_STS_REG, - 0xFFFFFFFF); - - /* Interrupt Enable. */ - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TXRESET_DONE); - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_RXRESET_DONE); - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_CPLL_LOCK); - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_QPLL0_LOCK); - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TXALIGN_DONE); - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_QPLL1_LOCK); - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE); - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE); -#if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTXE2) - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE); -#endif - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT); - XVphy_IntrEnable(InstancePtr, - XVPHY_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); - XVphy_ClkDetEnable(InstancePtr, TRUE); - - /* Set the flag to indicate the driver is. */ - InstancePtr->IsReady = XIL_COMPONENT_IS_READY; - - /* Init done. */ - XVphy_LogWrite(InstancePtr, XVPHY_LOG_EVT_INIT, 1); - - return XST_SUCCESS; -} - /******************************************************************************/ /** * This function initializes the Video PHY for HDMI. @@ -350,7 +147,7 @@ u32 XVphy_Hdmi_CfgInitialize(XVphy *InstancePtr, u8 QuadId, XVPHY_GT_STATE_IDLE; InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)].RxState = XVPHY_GT_STATE_IDLE; - //Initialize Transceiver Width values + /* Initialize Transceiver Width values */ if (InstancePtr->Config.TransceiverWidth == 2) { InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(Id)]. TxDataWidth = 20; @@ -416,9 +213,9 @@ u32 XVphy_Hdmi_CfgInitialize(XVphy *InstancePtr, u8 QuadId, /* Indicate of QPLL is present in design */ if ((XVphy_IsTxUsingQpll(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CH1) && - (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI)) || + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX))) || (XVphy_IsRxUsingQpll(InstancePtr, QuadId, XVPHY_CHANNEL_ID_CH1) && - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI))) { + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)))) { InstancePtr->HdmiIsQpllPresent = TRUE; } else { InstancePtr->HdmiIsQpllPresent = FALSE; @@ -449,10 +246,10 @@ u32 XVphy_Hdmi_CfgInitialize(XVphy *InstancePtr, u8 QuadId, } XVphy_MmcmReset(InstancePtr, QuadId, XVPHY_DIR_TX, TRUE); XVphy_MmcmReset(InstancePtr, QuadId, XVPHY_DIR_RX, TRUE); - if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { XVphy_IBufDsEnable(InstancePtr, QuadId, XVPHY_DIR_TX, (FALSE)); } - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { XVphy_IBufDsEnable(InstancePtr, QuadId, XVPHY_DIR_RX, (FALSE)); } @@ -499,14 +296,14 @@ u32 XVphy_Hdmi_CfgInitialize(XVphy *InstancePtr, u8 QuadId, XVPHY_INTR_HANDLER_TYPE_TX_CLKDET_FREQ_CHANGE); XVphy_IntrEnable(InstancePtr, XVPHY_INTR_HANDLER_TYPE_RX_CLKDET_FREQ_CHANGE); -#if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTXE2) XVphy_IntrEnable(InstancePtr, XVPHY_INTR_HANDLER_TYPE_TX_MMCM_LOCK_CHANGE); -#endif XVphy_IntrEnable(InstancePtr, XVPHY_INTR_HANDLER_TYPE_TX_TMR_TIMEOUT); XVphy_IntrEnable(InstancePtr, XVPHY_INTR_HANDLER_TYPE_RX_TMR_TIMEOUT); + XVphy_IntrEnable(InstancePtr, + XVPHY_INTR_HANDLER_TYPE_RX_MMCM_LOCK_CHANGE); XVphy_ClkDetEnable(InstancePtr, TRUE); /* Set the flag to indicate the driver is. */ @@ -1404,7 +1201,7 @@ u32 XVphy_HdmiCfgCalcMmcmParam(XVphy *InstancePtr, u8 QuadId, MmcmPtr->ClkOut0Div = MultDiv * 4; } } - else {//2 Byte Mode + else { /* 2 Byte Mode */ /* Link clock: TMDS clock ratio 1/40. */ if ((LineRate / 1000000) >= 3400) { if ((Dir == XVPHY_DIR_TX) && @@ -1918,7 +1715,7 @@ u32 XVphy_HdmiQpllParam(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, /* (297 MHz + 0.5%) + 10 KHz (Clkdet accuracy) */ if (298495000 < (XVphy_GetLineRateHz(InstancePtr, QuadId, - XVPHY_CHANNEL_ID_CH1) / + ActiveCmnId) / (InstancePtr->Config.TransceiverWidth * 10))) { XVphy_LogWrite(InstancePtr, XVPHY_LOG_EVT_USRCLK_ERR, 1); XVphy_CfgErrIntr(InstancePtr, XVPHY_ERR_USRCLK, 1); @@ -2461,7 +2258,7 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, } #endif - if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { if (InstancePtr->Config.XcvrType == XVPHY_GT_TYPE_GTPE2) { #if ((XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTHE3) || \ (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTHE4) || \ @@ -2507,7 +2304,7 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, } } - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { if (InstancePtr->Config.XcvrType == XVPHY_GT_TYPE_GTPE2) { strSize += scnprintf(buff+strSize, buff_size-strSize, "RX: PLL%d\n", (TxUsesPll0 ? 1 : 0)); @@ -2548,7 +2345,7 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, } } - if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { strSize += scnprintf(buff+strSize, buff_size-strSize, "TX state: "); switch (InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(ChId)].TxState) { @@ -2596,7 +2393,7 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, } } - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { strSize += scnprintf(buff+strSize, buff_size-strSize, "RX state: "); switch (InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(ChId)].RxState) { @@ -2652,9 +2449,9 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, strSize += scnprintf(buff+strSize, buff_size-strSize, "\n"); if (InstancePtr->Config.XcvrType != XVPHY_GT_TYPE_GTPE2) { if ((XVphy_IsTxUsingQpll(InstancePtr, QuadId, ChId) && - (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI)) || + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX))) || (XVphy_IsRxUsingQpll(InstancePtr, QuadId, ChId) && - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI))) { + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)))) { #if ((XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTHE3) || \ (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTHE4) || \ (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTYE4)) @@ -2674,9 +2471,9 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, } if ((XVphy_IsTxUsingCpll(InstancePtr, QuadId, ChId) && - (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI)) || + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX))) || (XVphy_IsRxUsingCpll(InstancePtr, QuadId, ChId) && - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI))) { + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)))) { strSize += scnprintf(buff+strSize, buff_size-strSize, "CPLL settings\n" \ "-------------\n" \ @@ -2689,10 +2486,10 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, else { if (((ChPtr->TxDataRefClkSel == XVPHY_SYSCLKSELDATA_TYPE_PLL0_OUTCLK) && - (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI)) || + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX))) || ((ChPtr->RxDataRefClkSel == XVPHY_SYSCLKSELDATA_TYPE_PLL0_OUTCLK) && - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI))) { + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)))) { CmnId = XVPHY_CHANNEL_ID_CMN0; strSize += scnprintf(buff+strSize, buff_size-strSize, "PLL0 settings\n" \ @@ -2710,10 +2507,10 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, if (((ChPtr->TxDataRefClkSel == XVPHY_SYSCLKSELDATA_TYPE_PLL1_OUTCLK) && - (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI)) || + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX))) || ((ChPtr->RxDataRefClkSel == XVPHY_SYSCLKSELDATA_TYPE_PLL1_OUTCLK) && - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI))) { + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)))) { CmnId = XVPHY_CHANNEL_ID_CMN1; strSize += scnprintf(buff+strSize, buff_size-strSize, "PLL1 settings\n" @@ -2729,7 +2526,7 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, } } - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { strSize += scnprintf(buff+strSize, buff_size-strSize, "RX MMCM settings\n" "-------------\n" @@ -2742,7 +2539,7 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, InstancePtr->Quads[QuadId].RxMmcm.ClkOut2Div); } - if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { strSize += scnprintf(buff+strSize, buff_size-strSize, "TX MMCM settings\n" \ "-------------\n" \ @@ -2756,7 +2553,7 @@ int XVphy_HdmiDebugInfo(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, } if ((InstancePtr->Config.DruIsPresent) && - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI)) { + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX))) { strSize += scnprintf(buff+strSize, buff_size-strSize, "DRU Settings\n" \ "-------------\n"); diff --git a/hdmi/phy-xilinx-vphy/xvphy_hdmi.h b/hdmi/phy-xilinx-vphy/xvphy_hdmi.h index 8bae360..e780a59 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_hdmi.h +++ b/hdmi/phy-xilinx-vphy/xvphy_hdmi.h @@ -39,7 +39,6 @@ * 1.7 gm 13/09/17 Removed XVphy_DruSetGain API * * - * @addtogroup xvphy_v1_7 * @{ *******************************************************************************/ #if defined (XPAR_XV_HDMITX_0_DEVICE_ID) || defined (XPAR_XV_HDMIRX_0_DEVICE_ID) @@ -48,13 +47,17 @@ /* Prevent circular inclusions by using protection macros. */ #define XVPHY_HDMI_H_ +#ifdef __cplusplus +extern "C" { +#endif + /************************** Constant Definitions ******************************/ -#define XVPHY_HDMI_GTYE4_DRU_LRATE 2500000000U -#define XVPHY_HDMI_GTYE4_DRU_REFCLK 156250000LL -#define XVPHY_HDMI_GTYE4_DRU_REFCLK_MIN 156240000LL -#define XVPHY_HDMI_GTYE4_DRU_REFCLK_MAX 156260000LL -#define XVPHY_HDMI_GTYE4_PLL_SCALE 1000 +#define XVPHY_HDMI_GTYE4_DRU_LRATE 2500000000U +#define XVPHY_HDMI_GTYE4_DRU_REFCLK 156250000LL +#define XVPHY_HDMI_GTYE4_DRU_REFCLK_MIN 156240000LL +#define XVPHY_HDMI_GTYE4_DRU_REFCLK_MAX 156260000LL +#define XVPHY_HDMI_GTYE4_PLL_SCALE 1000 #define XVPHY_HDMI_GTYE4_QPLL0_REFCLK_MIN 61250000LL #define XVPHY_HDMI_GTYE4_QPLL1_REFCLK_MIN 50000000LL #define XVPHY_HDMI_GTYE4_CPLL_REFCLK_MIN 50000000LL @@ -65,11 +68,11 @@ #define XVPHY_HDMI_GTYE4_RX_MMCM_FVCO_MIN 800000000U #define XVPHY_HDMI_GTYE4_RX_MMCM_FVCO_MAX 1600000000U -#define XVPHY_HDMI_GTHE4_DRU_LRATE 2500000000U -#define XVPHY_HDMI_GTHE4_DRU_REFCLK 156250000LL -#define XVPHY_HDMI_GTHE4_DRU_REFCLK_MIN 156240000LL -#define XVPHY_HDMI_GTHE4_DRU_REFCLK_MAX 156260000LL -#define XVPHY_HDMI_GTHE4_PLL_SCALE 1000 +#define XVPHY_HDMI_GTHE4_DRU_LRATE 2500000000U +#define XVPHY_HDMI_GTHE4_DRU_REFCLK 156250000LL +#define XVPHY_HDMI_GTHE4_DRU_REFCLK_MIN 156240000LL +#define XVPHY_HDMI_GTHE4_DRU_REFCLK_MAX 156260000LL +#define XVPHY_HDMI_GTHE4_PLL_SCALE 1000 #define XVPHY_HDMI_GTHE4_QPLL0_REFCLK_MIN 61250000LL #define XVPHY_HDMI_GTHE4_QPLL1_REFCLK_MIN 50000000LL #define XVPHY_HDMI_GTHE4_CPLL_REFCLK_MIN 50000000LL @@ -80,11 +83,11 @@ #define XVPHY_HDMI_GTHE4_RX_MMCM_FVCO_MIN 800000000U #define XVPHY_HDMI_GTHE4_RX_MMCM_FVCO_MAX 1600000000U -#define XVPHY_HDMI_GTHE3_DRU_LRATE 2500000000U -#define XVPHY_HDMI_GTHE3_DRU_REFCLK 156250000LL -#define XVPHY_HDMI_GTHE3_DRU_REFCLK_MIN 156240000LL -#define XVPHY_HDMI_GTHE3_DRU_REFCLK_MAX 156260000LL -#define XVPHY_HDMI_GTHE3_PLL_SCALE 1000 +#define XVPHY_HDMI_GTHE3_DRU_LRATE 2500000000U +#define XVPHY_HDMI_GTHE3_DRU_REFCLK 156250000LL +#define XVPHY_HDMI_GTHE3_DRU_REFCLK_MIN 156240000LL +#define XVPHY_HDMI_GTHE3_DRU_REFCLK_MAX 156260000LL +#define XVPHY_HDMI_GTHE3_PLL_SCALE 1000 #define XVPHY_HDMI_GTHE3_QPLL0_REFCLK_MIN 61250000LL #define XVPHY_HDMI_GTHE3_QPLL1_REFCLK_MIN 50000000LL #define XVPHY_HDMI_GTHE3_CPLL_REFCLK_MIN 50000000LL @@ -95,11 +98,11 @@ #define XVPHY_HDMI_GTHE3_RX_MMCM_FVCO_MIN 600000000U #define XVPHY_HDMI_GTHE3_RX_MMCM_FVCO_MAX 1200000000U -#define XVPHY_HDMI_GTHE2_DRU_LRATE 2500000000U -#define XVPHY_HDMI_GTHE2_DRU_REFCLK 125000000LL -#define XVPHY_HDMI_GTHE2_DRU_REFCLK_MIN 124990000LL -#define XVPHY_HDMI_GTHE2_DRU_REFCLK_MAX 125010000LL -#define XVPHY_HDMI_GTHE2_PLL_SCALE 1000 +#define XVPHY_HDMI_GTHE2_DRU_LRATE 2500000000U +#define XVPHY_HDMI_GTHE2_DRU_REFCLK 125000000LL +#define XVPHY_HDMI_GTHE2_DRU_REFCLK_MIN 124990000LL +#define XVPHY_HDMI_GTHE2_DRU_REFCLK_MAX 125010000LL +#define XVPHY_HDMI_GTHE2_PLL_SCALE 1000 #define XVPHY_HDMI_GTHE2_QPLL_REFCLK_MIN 61250000LL #define XVPHY_HDMI_GTHE2_CPLL_REFCLK_MIN 80000000LL #define XVPHY_HDMI_GTHE2_TX_MMCM_SCALE 1 @@ -109,13 +112,13 @@ #define XVPHY_HDMI_GTHE2_RX_MMCM_FVCO_MIN 600000000U #define XVPHY_HDMI_GTHE2_RX_MMCM_FVCO_MAX 1200000000U -#define XVPHY_HDMI_GTXE2_DRU_LRATE_QPLL 2000000000U -#define XVPHY_HDMI_GTXE2_DRU_LRATE_CPLL 2500000000U -#define XVPHY_HDMI_GTXE2_DRU_LRATE 2500000000U -#define XVPHY_HDMI_GTXE2_DRU_REFCLK 125000000LL -#define XVPHY_HDMI_GTXE2_DRU_REFCLK_MIN 124990000LL -#define XVPHY_HDMI_GTXE2_DRU_REFCLK_MAX 125010000LL -#define XVPHY_HDMI_GTXE2_PLL_SCALE 1000 +#define XVPHY_HDMI_GTXE2_DRU_LRATE_QPLL 2000000000U +#define XVPHY_HDMI_GTXE2_DRU_LRATE_CPLL 2500000000U +#define XVPHY_HDMI_GTXE2_DRU_LRATE 2500000000U +#define XVPHY_HDMI_GTXE2_DRU_REFCLK 125000000LL +#define XVPHY_HDMI_GTXE2_DRU_REFCLK_MIN 124990000LL +#define XVPHY_HDMI_GTXE2_DRU_REFCLK_MAX 125010000LL +#define XVPHY_HDMI_GTXE2_PLL_SCALE 1000 #define XVPHY_HDMI_GTXE2_QPLL_REFCLK_MIN 74125000LL #define XVPHY_HDMI_GTXE2_CPLL_REFCLK_MIN 80000000LL #define XVPHY_HDMI_GTXE2_TX_MMCM_SCALE 1 @@ -125,11 +128,11 @@ #define XVPHY_HDMI_GTXE2_RX_MMCM_FVCO_MIN 600000000U #define XVPHY_HDMI_GTXE2_RX_MMCM_FVCO_MAX 1200000000U -#define XVPHY_HDMI_GTPE2_DRU_LRATE 2500000000U -#define XVPHY_HDMI_GTPE2_DRU_REFCLK 100000000LL -#define XVPHY_HDMI_GTPE2_DRU_REFCLK_MIN 99990000LL -#define XVPHY_HDMI_GTPE2_DRU_REFCLK_MAX 100010000LL -#define XVPHY_HDMI_GTPE2_PLL_SCALE 1000 +#define XVPHY_HDMI_GTPE2_DRU_LRATE 2500000000U +#define XVPHY_HDMI_GTPE2_DRU_REFCLK 100000000LL +#define XVPHY_HDMI_GTPE2_DRU_REFCLK_MIN 99990000LL +#define XVPHY_HDMI_GTPE2_DRU_REFCLK_MAX 100010000LL +#define XVPHY_HDMI_GTPE2_PLL_SCALE 1000 #define XVPHY_HDMI_GTPE2_QPLL_REFCLK_MIN 80000000LL #define XVPHY_HDMI_GTPE2_CPLL_REFCLK_MIN 80000000LL #define XVPHY_HDMI_GTPE2_TX_MMCM_SCALE 1 @@ -166,6 +169,10 @@ void XVphy_HdmiGtDruModeEnable(XVphy *InstancePtr, u8 Enable); void XVphy_PatgenSetRatio(XVphy *InstancePtr, u8 QuadId, u64 TxLineRate); void XVphy_HdmiIntrHandlerCallbackInit(XVphy *InstancePtr); +#ifdef __cplusplus +} +#endif + #endif /* XVPHY_HDMI_H_ */ #endif -/** @} */ \ No newline at end of file +/** @} */ diff --git a/hdmi/phy-xilinx-vphy/xvphy_hdmi_intr.c b/hdmi/phy-xilinx-vphy/xvphy_hdmi_intr.c index 48af63b..a6ccb04 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_hdmi_intr.c +++ b/hdmi/phy-xilinx-vphy/xvphy_hdmi_intr.c @@ -48,6 +48,7 @@ * Improved TX initialization flow in bonded mode to * reset GT TX only when PLL and MMCM are locked * 1.7 gm 13/09/17 Added GTYE4 support + * 1.9 gm 14/05/18 Added TX and RX MMCM lock event logging * * *******************************************************************************/ @@ -698,7 +699,7 @@ void XVphy_HdmiTxClkDetFreqChangeHandler(XVphy *InstancePtr) XVphy_MmcmLockedMaskEnable(InstancePtr, 0, XVPHY_DIR_TX, TRUE); /* Disable TX MMCM. */ - //XVphy_MmcmPowerDown(InstancePtr, 0, XVPHY_DIR_TX, TRUE); + /* XVphy_MmcmPowerDown(InstancePtr, 0, XVPHY_DIR_TX, TRUE); */ /* Clear TX timer. */ XVphy_ClkDetTimerClear(InstancePtr, 0, XVPHY_DIR_TX); @@ -1079,7 +1080,6 @@ void XVphy_HdmiRxTimerTimeoutHandler(XVphy *InstancePtr) } } -#if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTXE2) /*****************************************************************************/ /** * This function is the handler for TX MMCM Lock events. @@ -1093,12 +1093,15 @@ void XVphy_HdmiRxTimerTimeoutHandler(XVphy *InstancePtr) ******************************************************************************/ void XVphy_HdmiTxMmcmLockHandler(XVphy *InstancePtr) { +#if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTXE2) XVphy_ChannelId ChId; XVphy_PllType TxPllType; u8 Id, Id0, Id1; +#endif XVphy_LogWrite(InstancePtr, XVPHY_LOG_EVT_TXPLL_LOCK, 1); +#if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTXE2) /* Determine PLL type. */ TxPllType = XVphy_GetPllType(InstancePtr, 0, XVPHY_DIR_TX, XVPHY_CHANNEL_ID_CH1); @@ -1123,8 +1126,26 @@ void XVphy_HdmiTxMmcmLockHandler(XVphy *InstancePtr) TxState = XVPHY_GT_STATE_RESET; } } -} #endif +} + +/*****************************************************************************/ +/** +* This function is the handler for RX MMCM Lock events. +* +* @param InstancePtr is a pointer to the VPHY instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XVphy_HdmiRxMmcmLockHandler(XVphy *InstancePtr) +{ + + XVphy_LogWrite(InstancePtr, XVPHY_LOG_EVT_RXPLL_LOCK, 1); + +} /*****************************************************************************/ /** @@ -1161,11 +1182,12 @@ void XVphy_HdmiGtHandler(XVphy *InstancePtr) TxStatePtr = &InstancePtr->Quads[QuadId].Ch1.TxState; RxStatePtr = &InstancePtr->Quads[QuadId].Ch1.RxState; -#if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTXE2) if (Event & XVPHY_INTR_TXMMCMUSRCLK_LOCK_MASK) { XVphy_HdmiTxMmcmLockHandler(InstancePtr); } -#endif + if (Event & XVPHY_INTR_RXMMCMUSRCLK_LOCK_MASK) { + XVphy_HdmiRxMmcmLockHandler(InstancePtr); + } if ((Event & XVPHY_INTR_QPLL0_LOCK_MASK) || (Event & XVPHY_INTR_QPLL1_LOCK_MASK)) { #if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTPE2) diff --git a/hdmi/phy-xilinx-vphy/xvphy_hw.h b/hdmi/phy-xilinx-vphy/xvphy_hw.h index 2169afa..b9f7d7d 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_hw.h +++ b/hdmi/phy-xilinx-vphy/xvphy_hw.h @@ -37,7 +37,6 @@ * 1.7 gm 13/09/17 Added GTYE4 support * * - * @addtogroup xvphy * @{ *******************************************************************************/ @@ -45,6 +44,10 @@ /* Prevent circular inclusions by using protection macros. */ #define XVPHY_HW_H_ +#ifdef __cplusplus +extern "C" { +#endif + /***************************** Include Files **********************************/ #include "xil_io.h" @@ -524,6 +527,7 @@ #define XVPHY_MMCM_USRCLK_CTRL_LOCKED_MASK 0x200 #define XVPHY_MMCM_USRCLK_CTRL_PWRDWN_MASK 0x400 #define XVPHY_MMCM_USRCLK_CTRL_LOCKED_MASK_MASK 0x800 +#define XVPHY_MMCM_USRCLK_CTRL_CLKINSEL_MASK 0x1000 /* 0x124, 0x144: MMCM_TXUSRCLK_REG1, MMCM_RXUSRCLK_REG1 */ #define XVPHY_MMCM_USRCLK_REG1_DIVCLK_MASK \ 0x00000FF @@ -628,5 +632,9 @@ #define XVphy_WriteReg(BaseAddress, RegOffset, Data) \ XVphy_Out32((BaseAddress) + (RegOffset), (Data)) +#ifdef __cplusplus +} +#endif + #endif /* XVPHY_HW_H_ */ -/** @} */ \ No newline at end of file +/** @} */ diff --git a/hdmi/phy-xilinx-vphy/xvphy_i.c b/hdmi/phy-xilinx-vphy/xvphy_i.c index d89a382..cc141df 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_i.c +++ b/hdmi/phy-xilinx-vphy/xvphy_i.c @@ -34,6 +34,10 @@ * 1.6 gm 06/08/17 Added XVphy_MmcmLocked, XVphy_ErrorHandler and * XVphy_PllLayoutErrorHandler APIs * 1.7 gm 13/09/17 Added GTYE4 support + * 1.8 gm 23/07/18 Moved APIs XVphy_SetTxVoltageSwing and + * XVphy_SetTxPreEmphasis to xvphy.c/h + * 05/09/18 Added XVphy_GetRefClkSourcesCount API + * 1.9 gm 11/04/18 Added XVphy_IsHDMI API * * *******************************************************************************/ @@ -53,127 +57,6 @@ /**************************** Function Definitions ****************************/ -/*****************************************************************************/ -/** -* This function will enable or disable the LPM logic in the Video PHY core. -* -* @param InstancePtr is a pointer to the XVphy core instance. -* @param QuadId is the GT quad ID to operate on. -* @param ChId is the channel ID to operate on. -* @param Dir is an indicator for TX or RX. -* @param Enable will enable (if 1) or disable (if 0) the LPM logic. -* -* @return None. -* -* @note None. -* -******************************************************************************/ -void XVphy_SetRxLpm(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, - XVphy_DirectionType Dir, u8 Enable) -{ - u32 RegVal; - u32 MaskVal; - - /* Suppress Warning Messages */ - QuadId = QuadId; - Dir = Dir; - - RegVal = XVphy_ReadReg(InstancePtr->Config.BaseAddr, - XVPHY_RX_EQ_CDR_REG); - - if (ChId == XVPHY_CHANNEL_ID_CHA) { - MaskVal = XVPHY_RX_CONTROL_RXLPMEN_ALL_MASK; - } - else { - MaskVal = XVPHY_RX_CONTROL_RXLPMEN_MASK(ChId); - } - - if (Enable) { - RegVal |= MaskVal; - } - else { - RegVal &= ~MaskVal; - } - XVphy_WriteReg(InstancePtr->Config.BaseAddr, XVPHY_RX_EQ_CDR_REG, - RegVal); -} - -/*****************************************************************************/ -/** -* This function will set the TX voltage swing value for a given channel. -* -* @param InstancePtr is a pointer to the XVphy core instance. -* @param QuadId is the GT quad ID to operate on. -* @param ChId is the channel ID to operate on. -* @param Vs is the voltage swing value to write. -* -* @return None. -* -* @note None. -* -******************************************************************************/ -void XVphy_SetTxVoltageSwing(XVphy *InstancePtr, u8 QuadId, - XVphy_ChannelId ChId, u8 Vs) -{ - u32 RegVal; - u32 MaskVal; - u32 RegOffset; - - /* Suppress Warning Messages */ - QuadId = QuadId; - - if ((ChId == XVPHY_CHANNEL_ID_CH1) || (ChId == XVPHY_CHANNEL_ID_CH2)) { - RegOffset = XVPHY_TX_DRIVER_CH12_REG; - } - else { - RegOffset = XVPHY_TX_DRIVER_CH34_REG; - } - RegVal = XVphy_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); - - MaskVal = XVPHY_TX_DRIVER_TXDIFFCTRL_MASK(ChId); - RegVal &= ~MaskVal; - RegVal |= (Vs << XVPHY_TX_DRIVER_TXDIFFCTRL_SHIFT(ChId)); - XVphy_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); -} - -/*****************************************************************************/ -/** -* This function will set the TX pre-emphasis value for a given channel. -* -* @param InstancePtr is a pointer to the XVphy core instance. -* @param QuadId is the GT quad ID to operate on. -* @param ChId is the channel ID to operate on. -* @param Pe is the pre-emphasis value to write. -* -* @return None. -* -* @note None. -* -******************************************************************************/ -void XVphy_SetTxPreEmphasis(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, - u8 Pe) -{ - u32 RegVal; - u32 MaskVal; - u32 RegOffset; - - /* Suppress Warning Messages */ - QuadId = QuadId; - - if ((ChId == XVPHY_CHANNEL_ID_CH1) || (ChId == XVPHY_CHANNEL_ID_CH2)) { - RegOffset = XVPHY_TX_DRIVER_CH12_REG; - } - else { - RegOffset = XVPHY_TX_DRIVER_CH34_REG; - } - RegVal = XVphy_ReadReg(InstancePtr->Config.BaseAddr, RegOffset); - - MaskVal = XVPHY_TX_DRIVER_TXPRECURSOR_MASK(ChId); - RegVal &= ~MaskVal; - RegVal |= (Pe << XVPHY_TX_DRIVER_TXPRECURSOR_SHIFT(ChId)); - XVphy_WriteReg(InstancePtr->Config.BaseAddr, RegOffset, RegVal); -} - /*****************************************************************************/ /** * This function writes the current software configuration for the reference @@ -531,11 +414,11 @@ u32 XVphy_IsPllLocked(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId) RxPllType = XVphy_GetPllType(InstancePtr, 0, XVPHY_DIR_RX, XVPHY_CHANNEL_ID_CH1); if (RxPllType == XVPHY_PLL_TYPE_CPLL && - InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { MaskVal = XVPHY_PLL_LOCK_STATUS_CPLL_HDMI_MASK; } else if (TxPllType == XVPHY_PLL_TYPE_CPLL && - InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { + XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { MaskVal = XVPHY_PLL_LOCK_STATUS_CPLL_HDMI_MASK; } else { @@ -1024,8 +907,8 @@ u32 XVphy_ClkReconfig(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId) (XVphy_ChannelId)Id); } else if (XVPHY_ISCMN(ChId)) { - if (((InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) || - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI)) && + if (((XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) || + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX))) && (InstancePtr->HdmiIsQpllPresent == FALSE)) { XVphy_LogWrite(InstancePtr, XVPHY_LOG_EVT_NO_QPLL_ERR, 1); XVphy_CfgErrIntr(InstancePtr, XVPHY_ERR_NO_QPLL, 1); @@ -1082,8 +965,8 @@ void XVphy_Ch2Ids(XVphy *InstancePtr, XVphy_ChannelId ChId, if (ChId == XVPHY_CHANNEL_ID_CHA) { *Id0 = XVPHY_CHANNEL_ID_CH1; - if ((InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) || - (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI)) { + if ((XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) || + (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX))) { if (InstancePtr->Config.UseGtAsTxTmdsClk == TRUE) { *Id1 = XVPHY_CHANNEL_ID_CH4; } @@ -1305,7 +1188,7 @@ u64 XVphy_GetPllVcoFreqHz(XVphy *InstancePtr, u8 QuadId, Plls[XVPHY_CH2IDX(ChId)]; if (Dir == XVPHY_DIR_TX) { - if (InstancePtr->Config.TxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_TX)) { PllRefClkHz = InstancePtr->HdmiTxRefClkHz; } else { @@ -1314,7 +1197,7 @@ u64 XVphy_GetPllVcoFreqHz(XVphy *InstancePtr, u8 QuadId, } } else { - if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + if (XVphy_IsHDMI(InstancePtr, XVPHY_DIR_RX)) { #if defined (XPAR_XV_HDMITX_0_DEVICE_ID) || defined (XPAR_XV_HDMIRX_0_DEVICE_ID) if (InstancePtr->HdmiRxDruIsEnabled) { PllRefClkHz = XVphy_DruGetRefClkFreqHz(InstancePtr); @@ -1332,7 +1215,7 @@ u64 XVphy_GetPllVcoFreqHz(XVphy *InstancePtr, u8 QuadId, } } - PllxVcoRateHz = (PllRefClkHz * + PllxVcoRateHz = (u64)(PllRefClkHz * InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(ChId)]. PllParams.N1FbDiv * InstancePtr->Quads[QuadId].Plls[XVPHY_CH2IDX(ChId)]. @@ -1343,6 +1226,67 @@ u64 XVphy_GetPllVcoFreqHz(XVphy *InstancePtr, u8 QuadId, return PllxVcoRateHz; } +/*****************************************************************************/ +/** +* This function returns the number of active reference clock sources +* based in the CFG +* +* @param InstancePtr is a pointer to the XVphy core instance. +* +* @return No of active REFCLK sources +* +* @note None. +* +******************************************************************************/ +u8 XVphy_GetRefClkSourcesCount(XVphy *InstancePtr) +{ + u8 RefClkNum = 0; + u8 RefClkNumMax = 3; + XVphy_PllRefClkSelType RefClkSel[RefClkNumMax]; + XVphy_PllRefClkSelType RefClkSelTemp[RefClkNumMax]; + u8 i, j, Match; + + /* TxRefClkSel */ + RefClkSel[0] = (InstancePtr->Config.TxProtocol != XVPHY_PROTOCOL_NONE) ? + InstancePtr->Config.TxRefClkSel : 99; + /* RxRefClkSel */ + RefClkSel[1] = (InstancePtr->Config.RxProtocol != XVPHY_PROTOCOL_NONE) ? + InstancePtr->Config.RxRefClkSel : 99; + /* DruRefClkSel */ + RefClkSel[2] = (InstancePtr->Config.DruIsPresent) ? + InstancePtr->Config.DruRefClkSel : 99; + + /* Initialize Unique RefClk holder */ + for (i=0; iConfig.TxProtocol == XVPHY_PROTOCOL_HDMI) { + return TRUE; + } + } else { /* Dir == XVPHY_DIR_RX */ + if (InstancePtr->Config.RxProtocol == XVPHY_PROTOCOL_HDMI) { + return TRUE; + } + } + + return FALSE; +} + /*****************************************************************************/ /** * This function is the error condition handler diff --git a/hdmi/phy-xilinx-vphy/xvphy_i.h b/hdmi/phy-xilinx-vphy/xvphy_i.h index 0103f48..b061803 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_i.h +++ b/hdmi/phy-xilinx-vphy/xvphy_i.h @@ -36,9 +36,13 @@ * 1.6 gm 06/08/17 Added XVphy_MmcmLocked, XVphy_ErrorHandler and * XVphy_PllLayoutErrorHandler APIs * 1.7 gm 13/09/17 Removed XVphy_MmcmWriteParameters API + * 1.8 gm 23/07/18 Moved APIs XVphy_SetTxVoltageSwing and + * XVphy_SetTxPreEmphasis to xvphy.c/h + * 05/09/18 Added XVphy_GetRefClkSourcesCount API + * 1.9 gm 11/04/18 Added XVphy_IsHDMI API + * Moved XVphy_SetRxLpm to xvphy.c/.h * * - * @addtogroup xvphy * @{ *******************************************************************************/ @@ -46,6 +50,10 @@ /* Prevent circular inclusions by using protection macros. */ #define XVPHY_I_H_ +#ifdef __cplusplus +extern "C" { +#endif + /******************************* Include Files ********************************/ #include "xil_assert.h" @@ -67,14 +75,6 @@ u32 XVphy_PllCalculator(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, XVphy_DirectionType Dir, u32 PllClkInFreqHz); -/* xvphy.c: Voltage swing and preemphasis. */ -void XVphy_SetRxLpm(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, - XVphy_DirectionType Dir, u8 Enable); -void XVphy_SetTxVoltageSwing(XVphy *InstancePtr, u8 QuadId, - XVphy_ChannelId ChId, u8 Vs); -void XVphy_SetTxPreEmphasis(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, - u8 Pe); - /* xvphy.c: Channel configuration functions - setters. */ u32 XVphy_WriteCfgRefClkSelReg(XVphy *InstancePtr, u8 QuadId); void XVphy_CfgPllRefClkSel(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, @@ -130,6 +130,11 @@ void XVphy_CfgErrIntr(XVphy *InstancePtr, XVphy_ErrType ErrIrq, u8 Set); u64 XVphy_GetPllVcoFreqHz(XVphy *InstancePtr, u8 QuadId, XVphy_ChannelId ChId, XVphy_DirectionType Dir); +u8 XVphy_GetRefClkSourcesCount(XVphy *InstancePtr); + +u8 XVphy_IsHDMI(XVphy *InstancePtr, XVphy_DirectionType Dir); +void XVphy_HdmiTxTimerTimeoutHandler(XVphy *InstancePtr); +void XVphy_HdmiRxTimerTimeoutHandler(XVphy *InstancePtr); void XVphy_ErrorHandler(XVphy *InstancePtr); #if (XPAR_VPHY_0_TRANSCEIVER == XVPHY_GTXE2) @@ -138,5 +143,9 @@ void XVphy_PllLayoutErrorHandler(XVphy *InstancePtr); /******************* Macros (Inline Functions) Definitions ********************/ +#ifdef __cplusplus +} +#endif + #endif /* XVPHY_I_H_ */ /** @} */ \ No newline at end of file diff --git a/hdmi/phy-xilinx-vphy/xvphy_intr.c b/hdmi/phy-xilinx-vphy/xvphy_intr.c index da7820a..dee1fb9 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_intr.c +++ b/hdmi/phy-xilinx-vphy/xvphy_intr.c @@ -43,7 +43,7 @@ /******************************************************************************/ /** - * This function enables interrupts associated with the specified interrupt type. + * This function enables interrupts associated with the specified interrupt type * * @param InstancePtr is a pointer to the XVphy instance. * @param Intr is the interrupt type/mask to enable. diff --git a/hdmi/phy-xilinx-vphy/xvphy_log.c b/hdmi/phy-xilinx-vphy/xvphy_log.c index c414d1d..1754d71 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_log.c +++ b/hdmi/phy-xilinx-vphy/xvphy_log.c @@ -40,7 +40,6 @@ * Changed xil_printf new lines to \r\n * Added XVPHY_LOG_EVT_DRU_CLK_ERR log event * 1.7 gm 13/09/17 Added XVPHY_LOG_EVT_USRCLK_ERR event - * eb 23/01/18 Minor cleanup * * *******************************************************************************/ @@ -50,6 +49,17 @@ #include "xvphy.h" #include "xvphy_i.h" +/************************** Constant Definitions *****************************/ +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_WHITE "\x1b[37m" +#define ANSI_COLOR_RESET "\x1b[0m" + + /**************************** Function Prototypes *****************************/ /**************************** Function Definitions ****************************/ @@ -103,7 +113,7 @@ void XVphy_LogWrite(XVphy *InstancePtr, XVphy_LogEvent Evt, u8 Data) /* Update head pointer if reached to end of the buffer */ if (InstancePtr->Log.HeadIndex == - (u8)((sizeof(InstancePtr->Log.DataBuffer) / sizeof(InstancePtr->Log.DataBuffer[0])) - 1)) { + (u8)((sizeof(InstancePtr->Log.DataBuffer) / 2) - 1)) { /* Clear pointer */ InstancePtr->Log.HeadIndex = 0; } @@ -117,7 +127,7 @@ void XVphy_LogWrite(XVphy *InstancePtr, XVphy_LogEvent Evt, u8 Data) * remove the oldest entry from the buffer. */ if (InstancePtr->Log.TailIndex == InstancePtr->Log.HeadIndex) { if (InstancePtr->Log.TailIndex == - (u8)((sizeof(InstancePtr->Log.DataBuffer) / sizeof(InstancePtr->Log.DataBuffer[0])) - 1)) { + (u8)((sizeof(InstancePtr->Log.DataBuffer) / 2) - 1)) { InstancePtr->Log.TailIndex = 0; } else { @@ -155,7 +165,7 @@ u16 XVphy_LogRead(XVphy *InstancePtr) /* Increment tail pointer */ if (InstancePtr->Log.TailIndex == - (u8)((sizeof(InstancePtr->Log.DataBuffer) / sizeof(InstancePtr->Log.DataBuffer[0])) - 1)) { + (u8)((sizeof(InstancePtr->Log.DataBuffer) / 2) - 1)) { InstancePtr->Log.TailIndex = 0; } else { diff --git a/hdmi/phy-xilinx-vphy/xvphy_mmcme4.c b/hdmi/phy-xilinx-vphy/xvphy_mmcme4.c index 10497b8..6064e80 100644 --- a/hdmi/phy-xilinx-vphy/xvphy_mmcme4.c +++ b/hdmi/phy-xilinx-vphy/xvphy_mmcme4.c @@ -468,10 +468,10 @@ u32 XVphy_MmcmWriteParameters(XVphy *InstancePtr, u8 QuadId, } - //Write Power Register Value + /* Write Power Register Value */ XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x27, 0xFFFF); - //Write CLKFBOUT Reg1 & Reg2 Values + /* Write CLKFBOUT Reg1 & Reg2 Values */ DrpVal32 = XVphy_Mmcme4DividerEncoding(MMCM_CLKFBOUT_MULT_F, MmcmParams->ClkFbOutMult); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x14, @@ -479,13 +479,13 @@ u32 XVphy_MmcmWriteParameters(XVphy *InstancePtr, u8 QuadId, XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x15, (u16)((DrpVal32 >> 16) & 0xFFFF)); - //Write DIVCLK_DIVIDE Value + /* Write DIVCLK_DIVIDE Value */ DrpVal32 = XVphy_Mmcme4DividerEncoding(MMCM_DIVCLK_DIVIDE, MmcmParams->DivClkDivide) ; XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x16, (u16)(DrpVal32 & 0xFFFF)); - //Write CLKOUT0 Reg1 & Reg2 Values + /* Write CLKOUT0 Reg1 & Reg2 Values */ DrpVal32 = XVphy_Mmcme4DividerEncoding(MMCM_CLKOUT_DIVIDE, MmcmParams->ClkOut0Div); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x08, @@ -493,7 +493,7 @@ u32 XVphy_MmcmWriteParameters(XVphy *InstancePtr, u8 QuadId, XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x09, (u16)((DrpVal32 >> 16) & 0xFFFF)); - //Write CLKOUT1 Reg1 & Reg2 Values + /* Write CLKOUT1 Reg1 & Reg2 Values */ DrpVal32 = XVphy_Mmcme4DividerEncoding(MMCM_CLKOUT_DIVIDE, MmcmParams->ClkOut1Div); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x0A, @@ -501,7 +501,7 @@ u32 XVphy_MmcmWriteParameters(XVphy *InstancePtr, u8 QuadId, XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x0B, (u16)((DrpVal32 >> 16) & 0xFFFF)); - //Write CLKOUT2 Reg1 & Reg2 Values + /* Write CLKOUT2 Reg1 & Reg2 Values */ DrpVal32 = XVphy_Mmcme4DividerEncoding(MMCM_CLKOUT_DIVIDE, MmcmParams->ClkOut2Div); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x0C, @@ -509,23 +509,23 @@ u32 XVphy_MmcmWriteParameters(XVphy *InstancePtr, u8 QuadId, XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x0D, (u16)((DrpVal32 >> 16) & 0xFFFF)); - //Write Lock Reg1 Value + /* Write Lock Reg1 Value */ DrpVal = XVphy_Mmcme4LockReg1Encoding(MmcmParams->ClkFbOutMult); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x18, DrpVal); - //Write Lock Reg2 Value + /* Write Lock Reg2 Value */ DrpVal = XVphy_Mmcme4LockReg2Encoding(MmcmParams->ClkFbOutMult); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x19, DrpVal); - //Write Lock Reg3 Value + /* Write Lock Reg3 Value */ DrpVal = XVphy_Mmcme4LockReg3Encoding(MmcmParams->ClkFbOutMult); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x1A, DrpVal); - //Write Filter Reg1 Value + /* Write Filter Reg1 Value */ DrpVal = XVphy_Mmcme4FilterReg1Encoding(MmcmParams->ClkFbOutMult); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x4E, DrpVal); - //Write Filter Reg2 Value + /* Write Filter Reg2 Value */ DrpVal = XVphy_Mmcme4FilterReg2Encoding(MmcmParams->ClkFbOutMult); XVphy_DrpWr(InstancePtr, QuadId, ChId, 0x4F, DrpVal); diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirx.c b/hdmi/xilinx-hdmi-rx/xv_hdmirx.c index bc9c2ad..4665e7c 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirx.c +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirx.c @@ -46,6 +46,17 @@ * EB 18/01/18 Moved VicTable to Hdmi Common library * EB 26/01/18 Updated XV_HdmiRx_GetVideoTiming to use * XVidC_GetVideoModeIdExtensive +* 2.20 EB 16/08/18 Replaced TIME_10MS, TIME_16MS, TIME_200MS with +* XV_HdmiRx_GetTime10Ms, XV_HdmiRx_GetTime16Ms +* XV_HdmiRx_GetTime200Ms +* Added TMDS Clock Ratio callback support +* 2.30 EB 05/03/19 Updated the description of the API +* XV_HdmiRx_GetLinkStatus +* 2.40 EB 30/07/19 Updated XV_HdmiRx_GetVideoTiming to fix an issue where +* FrameRate for YUV420 may be incorrect +* Updated XV_HdmiRx_GetVideoTiming to fix an issue where +* video timing values may be incorrect +* 06/08/19 Added Vic and Video Timing mismatch callback support * * ******************************************************************************/ @@ -97,7 +108,6 @@ static void StubCallback(void *CallbackRef); int XV_HdmiRx_CfgInitialize(XV_HdmiRx *InstancePtr, XV_HdmiRx_Config *CfgPtr, UINTPTR EffectiveAddr) { u32 RegValue; - u32 Time_16ms; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); @@ -116,7 +126,6 @@ int XV_HdmiRx_CfgInitialize(XV_HdmiRx *InstancePtr, XV_HdmiRx_Config *CfgPtr, UI return (XST_FAILURE); } - Time_16ms = (InstancePtr->Config.AxiLiteClkFreq * 10)/625; /* Callbacks These are placeholders pointing to the StubCallback @@ -159,6 +168,13 @@ int XV_HdmiRx_CfgInitialize(XV_HdmiRx *InstancePtr, XV_HdmiRx_Config *CfgPtr, UI InstancePtr->ModeCallback = (XV_HdmiRx_Callback)((void *)StubCallback); InstancePtr->IsModeCallbackSet = (FALSE); + InstancePtr->TmdsClkRatioCallback = + (XV_HdmiRx_Callback)((void *)StubCallback); + InstancePtr->IsTmdsClkRatioCallbackSet = (FALSE); + + InstancePtr->VicErrorCallback = (XV_HdmiRx_Callback)((void *)StubCallback); + InstancePtr->IsVicErrorCallbackSet = (FALSE); + /* Clear HDMI variables */ XV_HdmiRx_Clear(InstancePtr); @@ -223,8 +239,8 @@ int XV_HdmiRx_CfgInitialize(XV_HdmiRx *InstancePtr, XV_HdmiRx_Config *CfgPtr, UI Video Timing detector peripheral */ - // Set timebase - XV_HdmiRx_VtdSetTimebase(InstancePtr, Time_16ms); // 16 ms + // Set timebase - 16 ms + XV_HdmiRx_VtdSetTimebase(InstancePtr, XV_HdmiRx_GetTime16Ms(InstancePtr)); // The VTD run flag is set in the armed state @@ -399,6 +415,7 @@ int XV_HdmiRx_SetStream(XV_HdmiRx *InstancePtr, XVidC_PixelsPerClock Ppc, u32 Cl ******************************************************************************/ void XV_HdmiRx_INT_VRST(XV_HdmiRx *InstancePtr, u8 Reset) { + /* Verify argument. */ Xil_AssertVoid(InstancePtr != NULL); @@ -648,9 +665,6 @@ int XV_HdmiRx_SetHpd(XV_HdmiRx *InstancePtr, u8 SetClr) * - 0 = Link error counter for channel 0. * - 1 = Link error counter for channel 1. * - 2 = Link error counter for channel 2. -* - 3 = Link phase. -* - 4 = Link delay. -* - 5 = Link line length * * @return Link status of the HDMI RX core link. * @@ -1446,304 +1460,302 @@ int XV_HdmiRx_GetVideoTiming(XV_HdmiRx *InstancePtr) u8 YUV420_Correction; u8 IsInterlaced; - // Lookup the videomode based on the vic - InstancePtr->Stream.Video.VmId = XV_HdmiRx_LookupVmId(InstancePtr->Stream.Vic); + InstancePtr->Stream.Video.VmId = XVIDC_VM_NOT_SUPPORTED; - // Was the vic found? - // Yes, then get the timing parameters from the video library - if (InstancePtr->Stream.Video.VmId != (XVIDC_VM_NOT_SUPPORTED)) { + // If the colorspace is YUV420, then the horizontal parameters must be doubled + if (InstancePtr->Stream.Video.ColorFormatId == XVIDC_CSF_YCRCB_420) { + YUV420_Correction = 2; + } else { + YUV420_Correction = 1; + } - // Copy the current VideoStream - VidStreamCopy = InstancePtr->Stream.Video; + // First we read the video parameters from the VTD and store them in a local variable + /* Read Total Pixels */ + HTotal = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_TOT_PIX_OFFSET)) * YUV420_Correction; - if (XVidC_IsStream3D(&InstancePtr->Stream.Video)){ - XVidC_Set3DVideoStream(&InstancePtr->Stream.Video, - VidStreamCopy.VmId, - VidStreamCopy.ColorFormatId, - VidStreamCopy.ColorDepth, - VidStreamCopy.PixPerClk, - &VidStreamCopy.Info_3D); - } - else { - XVidC_SetVideoStream(&InstancePtr->Stream.Video, - VidStreamCopy.VmId, - VidStreamCopy.ColorFormatId, - VidStreamCopy.ColorDepth, - VidStreamCopy.PixPerClk); - } + /* Read Active Pixels */ + HActive = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_ACT_PIX_OFFSET)) * YUV420_Correction; - return (XST_SUCCESS); - } + /* Read Hsync Width */ + HSyncWidth = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_HSW_OFFSET)) * YUV420_Correction; + + /* Read HFront Porch */ + HFrontPorch = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_HFP_OFFSET)) * YUV420_Correction; + + /* Read HBack Porch */ + HBackPorch = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_HBP_OFFSET)) * YUV420_Correction; + + /* Total lines field 1 */ + F0PVTotal = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_TOT_LIN_OFFSET)) & (0xFFFF); + + /* Total lines field 2 */ + F1VTotal = ((XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_TOT_LIN_OFFSET))) >> 16); + + /* Active lines field 1 */ + VActive = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_ACT_LIN_OFFSET)) & (0xFFFF); + + /* Read VSync Width field 1*/ + F0PVSyncWidth = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VSW_OFFSET)) & (0xFFFF); + + /* Read VSync Width field 2*/ + F1VSyncWidth = ((XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VSW_OFFSET))) >> 16); + + /* Read VFront Porch field 1*/ + F0PVFrontPorch = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VFP_OFFSET)) & (0xFFFF); + + /* Read VFront Porch field 2*/ + F1VFrontPorch = ((XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VFP_OFFSET))) >> 16); - // No, then read the timing parameters from the video timing detector + /* Read VBack Porch field 1 */ + F0PVBackPorch = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VBP_OFFSET)) & (0xFFFF); + + /* Read VBack Porch field 2 */ + F1VBackPorch = ((XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VBP_OFFSET))) >> 16); + + /* Read Status register */ + Data = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_STA_OFFSET)); + + /* Check video format */ + if ((Data) & (XV_HDMIRX_VTD_STA_FMT_MASK)) { + /* Interlaced */ + IsInterlaced = 1; + } else { - // If the colorspace is YUV420, then the horizontal parameters must be doubled - if (InstancePtr->Stream.Video.ColorFormatId == XVIDC_CSF_YCRCB_420) { - YUV420_Correction = 2; - } else { - YUV420_Correction = 1; - } - // First we read the video parameters from the VTD and store them in a local variable - /* Read Total Pixels */ - HTotal = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_TOT_PIX_OFFSET)) * YUV420_Correction; + /* Progressive */ + IsInterlaced = 0; + } - /* Read Active Pixels */ - HActive = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_ACT_PIX_OFFSET)) * YUV420_Correction; + // Next, we compare these values with the previous stored values + // By default the match is true + Match = TRUE; - /* Read Hsync Width */ - HSyncWidth = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_HSW_OFFSET)) * YUV420_Correction; + if (!HActive | !HFrontPorch | !HSyncWidth | !HBackPorch | !HTotal | !VActive | + !F0PVFrontPorch | !F0PVSyncWidth | !F0PVBackPorch | !F0PVTotal) { + Match = FALSE; + } - /* Read HFront Porch */ - HFrontPorch = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_HFP_OFFSET)) * YUV420_Correction; + if (IsInterlaced == 1) { + if (F1VTotal != (VActive + F1VFrontPorch + + F1VSyncWidth + F1VBackPorch)) { + Match = FALSE; + } + } else { + if (F1VFrontPorch | F1VSyncWidth | F1VBackPorch) { + Match = FALSE; + } + } - /* Read HBack Porch */ - HBackPorch = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_HBP_OFFSET)) * YUV420_Correction; + // Htotal + if (HTotal != InstancePtr->Stream.Video.Timing.HTotal) { + Match = FALSE; + } - /* Total lines field 1 */ - F0PVTotal = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_TOT_LIN_OFFSET)) & (0xFFFF); + // HActive + if (HActive != InstancePtr->Stream.Video.Timing.HActive) { + Match = FALSE; + } - /* Total lines field 2 */ - F1VTotal = ((XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_TOT_LIN_OFFSET))) >> 16); + // HSyncWidth + if (HSyncWidth != InstancePtr->Stream.Video.Timing.HSyncWidth) { + Match = FALSE; + } - /* Active lines field 1 */ - VActive = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_ACT_LIN_OFFSET)) & (0xFFFF); + // HFrontPorch + if (HFrontPorch != InstancePtr->Stream.Video.Timing.HFrontPorch) { + Match = FALSE; + } - /* Read VSync Width field 1*/ - F0PVSyncWidth = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VSW_OFFSET)) & (0xFFFF); + // HBackPorch + if (HBackPorch != InstancePtr->Stream.Video.Timing.HBackPorch) { + Match = FALSE; + } - /* Read VSync Width field 2*/ - F1VSyncWidth = ((XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VSW_OFFSET))) >> 16); + // F0PVTotal + if (F0PVTotal != InstancePtr->Stream.Video.Timing.F0PVTotal) { + Match = FALSE; + } - /* Read VFront Porch field 1*/ - F0PVFrontPorch = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VFP_OFFSET)) & (0xFFFF); + // F1VTotal + if (F1VTotal != InstancePtr->Stream.Video.Timing.F1VTotal) { + Match = FALSE; + } - /* Read VFront Porch field 2*/ - F1VFrontPorch = ((XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VFP_OFFSET))) >> 16); + // VActive + if (VActive != InstancePtr->Stream.Video.Timing.VActive) { + Match = FALSE; + } - /* Read VBack Porch field 1 */ - F0PVBackPorch = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VBP_OFFSET)) & (0xFFFF); + // F0PVSyncWidth + if (F0PVSyncWidth != InstancePtr->Stream.Video.Timing.F0PVSyncWidth) { + Match = FALSE; + } - /* Read VBack Porch field 2 */ - F1VBackPorch = ((XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_VBP_OFFSET))) >> 16); + // F1VSyncWidth + if (F1VSyncWidth != InstancePtr->Stream.Video.Timing.F1VSyncWidth) { + Match = FALSE; + } - /* Read Status register */ - Data = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_STA_OFFSET)); + // F0PVFrontPorch + if (F0PVFrontPorch != InstancePtr->Stream.Video.Timing.F0PVFrontPorch) { + Match = FALSE; + } - /* Check video format */ - if ((Data) & (XV_HDMIRX_VTD_STA_FMT_MASK)) { - /* Interlaced */ - IsInterlaced = 1; - } - else { - /* Progressive */ - IsInterlaced = 0; - } + // F1VFrontPorch + if (F1VFrontPorch != InstancePtr->Stream.Video.Timing.F1VFrontPorch) { + Match = FALSE; + } - // Next, we compare these values with the previous stored values - // By default the match is true - Match = TRUE; + // F0PVBackPorch + if (F0PVBackPorch != InstancePtr->Stream.Video.Timing.F0PVBackPorch) { + Match = FALSE; + } - if (!HActive | !HFrontPorch | !HSyncWidth | !HBackPorch | !HTotal | !VActive | - !F0PVFrontPorch | !F0PVSyncWidth | !F0PVBackPorch | !F0PVTotal) { - Match = FALSE; - } + // F1VBackPorch + if (F1VBackPorch != InstancePtr->Stream.Video.Timing.F1VBackPorch) { + Match = FALSE; + } - if ((IsInterlaced == 1) & (!F1VFrontPorch | !F1VSyncWidth | !F1VBackPorch | !F1VTotal)) { - Match = FALSE; - } + if (HTotal != (HActive + HFrontPorch + HSyncWidth +HBackPorch)) { + Match = FALSE; + } - // Htotal - if (HTotal != InstancePtr->Stream.Video.Timing.HTotal) { - Match = FALSE; - } + if (F0PVTotal != (VActive + F0PVFrontPorch + F0PVSyncWidth +F0PVBackPorch)) { + Match = FALSE; + } - // HActive - if (HActive != InstancePtr->Stream.Video.Timing.HActive) { - Match = FALSE; - } + if ((IsInterlaced == 1) && (F1VTotal != (VActive + F1VFrontPorch + F1VSyncWidth +F1VBackPorch))) { + Match = FALSE; + } - // HSyncWidth - if (HSyncWidth != InstancePtr->Stream.Video.Timing.HSyncWidth) { - Match = FALSE; - } + // Then we store the timing parameters regardless if there was a match + /* Read Total Pixels */ + InstancePtr->Stream.Video.Timing.HTotal = HTotal; - // HFrontPorch - if (HFrontPorch != InstancePtr->Stream.Video.Timing.HFrontPorch) { - Match = FALSE; - } + /* Read Active Pixels */ + InstancePtr->Stream.Video.Timing.HActive = HActive; - // HBackPorch - if (HBackPorch != InstancePtr->Stream.Video.Timing.HBackPorch) { - Match = FALSE; - } + /* Read Hsync Width */ + InstancePtr->Stream.Video.Timing.HSyncWidth = HSyncWidth; - // F0PVTotal - if (F0PVTotal != InstancePtr->Stream.Video.Timing.F0PVTotal) { - Match = FALSE; - } + /* Read HFront Porch */ + InstancePtr->Stream.Video.Timing.HFrontPorch = HFrontPorch; - // F1VTotal - if (F1VTotal != InstancePtr->Stream.Video.Timing.F1VTotal) { - Match = FALSE; - } + /* Read HBack Porch */ + InstancePtr->Stream.Video.Timing.HBackPorch = HBackPorch; - // VActive - if (VActive != InstancePtr->Stream.Video.Timing.VActive) { - Match = FALSE; - } + /* Total lines field 1 */ + InstancePtr->Stream.Video.Timing.F0PVTotal = F0PVTotal; - // F0PVSyncWidth - if (F0PVSyncWidth != InstancePtr->Stream.Video.Timing.F0PVSyncWidth) { - Match = FALSE; - } + /* Total lines field 2 */ + InstancePtr->Stream.Video.Timing.F1VTotal = F1VTotal; - // F1VSyncWidth - if (F1VSyncWidth != InstancePtr->Stream.Video.Timing.F1VSyncWidth) { - Match = FALSE; - } + /* Active lines field 1 */ + InstancePtr->Stream.Video.Timing.VActive = VActive; - // F0PVFrontPorch - if (F0PVFrontPorch != InstancePtr->Stream.Video.Timing.F0PVFrontPorch) { - Match = FALSE; - } + /* Read VSync Width field 1*/ + InstancePtr->Stream.Video.Timing.F0PVSyncWidth = F0PVSyncWidth; - // F1VFrontPorch - if (F1VFrontPorch != InstancePtr->Stream.Video.Timing.F1VFrontPorch) { - Match = FALSE; - } + /* Read VSync Width field 2*/ + InstancePtr->Stream.Video.Timing.F1VSyncWidth = F1VSyncWidth; - // F0PVBackPorch - if (F0PVBackPorch != InstancePtr->Stream.Video.Timing.F0PVBackPorch) { - Match = FALSE; - } + /* Read VFront Porch field 1*/ + InstancePtr->Stream.Video.Timing.F0PVFrontPorch = F0PVFrontPorch; + + /* Read VFront Porch field 2*/ + InstancePtr->Stream.Video.Timing.F1VFrontPorch = F1VFrontPorch; + + /* Read VBack Porch field 1 */ + InstancePtr->Stream.Video.Timing.F0PVBackPorch = F0PVBackPorch; + + /* Read VBack Porch field 2 */ + InstancePtr->Stream.Video.Timing.F1VBackPorch = F1VBackPorch; - // F1VBackPorch - if (F1VBackPorch != InstancePtr->Stream.Video.Timing.F1VBackPorch) { - Match = FALSE; + // Do we have a match? + // Yes, then continue processing + if (Match) { + + /* Read Status register */ + Data = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_STA_OFFSET)); + + /* Check video format */ + if ((Data) & (XV_HDMIRX_VTD_STA_FMT_MASK)) { + /* Interlaced */ + InstancePtr->Stream.Video.IsInterlaced = 1; + } + else { + /* Progressive */ + InstancePtr->Stream.Video.IsInterlaced = 0; } - if (HTotal != (HActive + HFrontPorch + HSyncWidth +HBackPorch)) { - Match = FALSE; + /* Check Vsync polarity */ + if ((Data) & (XV_HDMIRX_VTD_STA_VS_POL_MASK)) { + /* Positive */ + InstancePtr->Stream.Video.Timing.VSyncPolarity = 1; + } + else { + /* Negative */ + InstancePtr->Stream.Video.Timing.VSyncPolarity = 0; } - if (F0PVTotal != (VActive + F0PVFrontPorch + F0PVSyncWidth +F0PVBackPorch)) { - Match = FALSE; + /* Check Hsync polarity */ + if ((Data) & (XV_HDMIRX_VTD_STA_HS_POL_MASK)) { + /* Positive */ + InstancePtr->Stream.Video.Timing.HSyncPolarity = 1; + } + else { + /* Negative */ + InstancePtr->Stream.Video.Timing.HSyncPolarity = 0; } - if ((IsInterlaced == 1) && (F1VTotal != (VActive + F1VFrontPorch + F1VSyncWidth +F1VBackPorch))) { - Match = FALSE; + /* Calculate and set the frame rate field assuming the stream is + * of YUV420 */ + InstancePtr->Stream.Video.FrameRate = + (XVidC_FrameRate) (XV_HdmiRx_Divide((InstancePtr->Stream.PixelClk << 1), + (InstancePtr->Stream.Video.Timing.F0PVTotal * + InstancePtr->Stream.Video.Timing.HTotal))); + + /* If the colorspace is not YUV420, then the frame rate must be + * halved */ + if (InstancePtr->Stream.Video.ColorFormatId != XVIDC_CSF_YCRCB_420) { + InstancePtr->Stream.Video.FrameRate >>= 1; } - // Then we store the timing parameters regardless if there was a match - /* Read Total Pixels */ - InstancePtr->Stream.Video.Timing.HTotal = HTotal; - - /* Read Active Pixels */ - InstancePtr->Stream.Video.Timing.HActive = HActive; - - /* Read Hsync Width */ - InstancePtr->Stream.Video.Timing.HSyncWidth = HSyncWidth; - - /* Read HFront Porch */ - InstancePtr->Stream.Video.Timing.HFrontPorch = HFrontPorch; - - /* Read HBack Porch */ - InstancePtr->Stream.Video.Timing.HBackPorch = HBackPorch; - - /* Total lines field 1 */ - InstancePtr->Stream.Video.Timing.F0PVTotal = F0PVTotal; - - /* Total lines field 2 */ - InstancePtr->Stream.Video.Timing.F1VTotal = F1VTotal; - - /* Active lines field 1 */ - InstancePtr->Stream.Video.Timing.VActive = VActive; - - /* Read VSync Width field 1*/ - InstancePtr->Stream.Video.Timing.F0PVSyncWidth = F0PVSyncWidth; - - /* Read VSync Width field 2*/ - InstancePtr->Stream.Video.Timing.F1VSyncWidth = F1VSyncWidth; - - /* Read VFront Porch field 1*/ - InstancePtr->Stream.Video.Timing.F0PVFrontPorch = F0PVFrontPorch; - - /* Read VFront Porch field 2*/ - InstancePtr->Stream.Video.Timing.F1VFrontPorch = F1VFrontPorch; - - /* Read VBack Porch field 1 */ - InstancePtr->Stream.Video.Timing.F0PVBackPorch = F0PVBackPorch; - - /* Read VBack Porch field 2 */ - InstancePtr->Stream.Video.Timing.F1VBackPorch = F1VBackPorch; - - // Do we have a match? - // Yes, then continue processing - if (Match) { - - /* Read Status register */ - Data = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_STA_OFFSET)); - - /* Check video format */ - if ((Data) & (XV_HDMIRX_VTD_STA_FMT_MASK)) { - /* Interlaced */ - InstancePtr->Stream.Video.IsInterlaced = 1; - } - else { - /* Progressive */ - InstancePtr->Stream.Video.IsInterlaced = 0; - } - - /* Check Vsync polarity */ - if ((Data) & (XV_HDMIRX_VTD_STA_VS_POL_MASK)) { - /* Positive */ - InstancePtr->Stream.Video.Timing.VSyncPolarity = 1; - } - else { - /* Negative */ - InstancePtr->Stream.Video.Timing.VSyncPolarity = 0; - } - - /* Check Hsync polarity */ - if ((Data) & (XV_HDMIRX_VTD_STA_HS_POL_MASK)) { - /* Positive */ - InstancePtr->Stream.Video.Timing.HSyncPolarity = 1; - } - else { - /* Negative */ - InstancePtr->Stream.Video.Timing.HSyncPolarity = 0; - } - - // Calculate and set the frame rate field - InstancePtr->Stream.Video.FrameRate = - (XVidC_FrameRate) (XV_HdmiRx_Divide(InstancePtr->Stream.PixelClk, - (InstancePtr->Stream.Video.Timing.F0PVTotal * InstancePtr->Stream.Video.Timing.HTotal))); - - // If the colorspace is YUV420, then the frame rate must be doubled - if (InstancePtr->Stream.Video.ColorFormatId == XVIDC_CSF_YCRCB_420) { - InstancePtr->Stream.Video.FrameRate = (XVidC_FrameRate) (InstancePtr->Stream.Video.FrameRate * 2); - } - - // Lookup the video mode id - InstancePtr->Stream.Video.VmId = - XVidC_GetVideoModeIdExtensive(&InstancePtr->Stream.Video.Timing, - InstancePtr->Stream.Video.FrameRate, - InstancePtr->Stream.Video.IsInterlaced, - (TRUE)); - - //If video mode not found in the table tag it as custom - if (InstancePtr->Stream.Video.VmId == XVIDC_VM_NOT_SUPPORTED) { - InstancePtr->Stream.Video.VmId = XVIDC_VM_CUSTOM; - } - - // Return success - return (XST_SUCCESS); + // Lookup the video mode id + InstancePtr->Stream.Video.VmId = + XVidC_GetVideoModeIdExtensive(&InstancePtr->Stream.Video.Timing, + InstancePtr->Stream.Video.FrameRate, + InstancePtr->Stream.Video.IsInterlaced, + (TRUE)); + + //If video mode not found in the table tag it as custom + if (InstancePtr->Stream.Video.VmId == XVIDC_VM_NOT_SUPPORTED) { + InstancePtr->Stream.Video.VmId = XVIDC_VM_CUSTOM; } - // No match - else { - return (XST_FAILURE); + VidStreamCopy = InstancePtr->Stream.Video; + + if (XVidC_IsStream3D(&InstancePtr->Stream.Video)){ + XVidC_Set3DVideoStream(&InstancePtr->Stream.Video, + VidStreamCopy.VmId, + VidStreamCopy.ColorFormatId, + VidStreamCopy.ColorDepth, + VidStreamCopy.PixPerClk, + &VidStreamCopy.Info_3D); + } else { + XVidC_SetVideoStream(&InstancePtr->Stream.Video, + VidStreamCopy.VmId, + VidStreamCopy.ColorFormatId, + VidStreamCopy.ColorDepth, + VidStreamCopy.PixPerClk); } + + // Return success + return (XST_SUCCESS); + } + + // No match + else { + return (XST_FAILURE); } } diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirx.h b/hdmi/xilinx-hdmi-rx/xv_hdmirx.h index dda2a4f..981ff10 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirx.h +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirx.h @@ -129,6 +129,13 @@ * MMO 08/02/18 Added XV_HdmiRx_SyncStatus enumaration, and as * an element in XV_HdmiRx_Stream for Sync Loss * handling +* 2.20 EB 16/08/18 Replaced TIME_10MS, TIME_16MS, TIME_200MS with +* XV_HdmiRx_GetTime10Ms, XV_HdmiRx_GetTime16Ms +* XV_HdmiRx_GetTime200Ms +* Added TMDS Clock Ratio callback support +* YB 15/08/18 Added new callbacks for HDCP 1.4 & 2.2 protocol events. +* Enumerated new entries for HDCP 1.4 & 2.2 protocol +* events in XV_HdmiRx_HandlerType enum. * * ******************************************************************************/ @@ -160,7 +167,8 @@ extern "C" { */ typedef enum { XV_HDMIRX_HANDLER_CONNECT = 1, /**< A connect event interrupt type */ - XV_HDMIRX_HANDLER_BRDG_OVERFLOW, /**< Interrupt type for bridge overflow */ + XV_HDMIRX_HANDLER_BRDG_OVERFLOW, /**< Interrupt type for bridge + overflow */ XV_HDMIRX_HANDLER_AUX, /**< Interrupt type for AUX peripheral */ XV_HDMIRX_HANDLER_AUD, /**< Interrupt type for AUD peripheral */ XV_HDMIRX_HANDLER_LNKSTA, /**< Interrupt type for LNKSTA peripheral */ @@ -169,9 +177,13 @@ typedef enum { XV_HDMIRX_HANDLER_STREAM_INIT, /**< Interrupt type for stream init */ XV_HDMIRX_HANDLER_STREAM_UP, /**< Interrupt type for stream up */ XV_HDMIRX_HANDLER_HDCP, /**< Interrupt type for hdcp */ + XV_HDMIRX_HANDLER_DDC_HDCP_14_PROT, /**< Interrupt type for HDCP14PROT event */ + XV_HDMIRX_HANDLER_DDC_HDCP_22_PROT, /**< Interrupt type for HDCP22PROT event */ XV_HDMIRX_HANDLER_LINK_ERROR, /**< Interrupt type for link error */ XV_HDMIRX_HANDLER_SYNC_LOSS, /**< Interrupt type for sync loss */ - XV_HDMIRX_HANDLER_MODE /**< Interrupt type for mode */ + XV_HDMIRX_HANDLER_MODE, /**< Interrupt type for mode */ + XV_HDMIRX_HANDLER_TMDS_CLK_RATIO, /**< Interrupt type for TMDS clock ratio */ + XV_HDMIRX_HANDLER_VIC_ERROR /**< Interrupt type for VIC error */ } XV_HdmiRx_HandlerType; /*@}*/ @@ -216,6 +228,7 @@ typedef struct { u16 DeviceId; /**< DeviceId is the unique ID of the HDMI RX core */ UINTPTR BaseAddress; /**< BaseAddress is the physical base address * of the core's registers */ + u32 AxiLiteClkFreq; } XV_HdmiRx_Config; @@ -306,6 +319,15 @@ typedef struct { XV_HdmiRx_HdcpCallback HdcpCallback; /**< Callback for hdcp callback */ void *HdcpRef; /**< To be passed to the hdcp callback */ u32 IsHdcpCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ + + XV_HdmiRx_Callback Hdcp14ProtEvtCallback; /**< Callback for hdcp 1.4 protocol event written on the ddc. */ + void *Hdcp14ProtEvtRef; /**< To be passed to the hdcp 1.4 protocol event callback */ + u32 IsHdcp14ProtEvtCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ + + XV_HdmiRx_Callback Hdcp22ProtEvtCallback; /**< Callback for hdcp 2.2 protocol event written on the ddc. */ + void *Hdcp22ProtEvtRef; /**< To be passed to the hdcp 2.2 protocol event callback */ + u32 IsHdcp22ProtEvtCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ + XV_HdmiRx_Callback LinkErrorCallback; /**< Callback for link error callback */ void *LinkErrorRef; /**< To be passed to the link error callback */ u32 IsLinkErrorCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ @@ -322,6 +344,14 @@ typedef struct { void *ModeRef; /**< To be passed to the link error callback */ u32 IsModeCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ + XV_HdmiRx_Callback TmdsClkRatioCallback; /**< Callback for TMDS clock ratio change */ + void *TmdsClkRatioRef; /**< To be passed to the TMDS callback */ + u32 IsTmdsClkRatioCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ + + XV_HdmiRx_Callback VicErrorCallback; /**< Callback for Vic error detection */ + void *VicErrorRef; /**< To be passed to the vic error callback */ + u32 IsVicErrorCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ + /* HDMI RX stream */ XV_HdmiRx_Stream Stream; /**< HDMI RX stream information */ @@ -336,6 +366,51 @@ typedef struct { /***************** Macros (Inline Functions) Definitions *********************/ +/*****************************************************************************/ +/** +* +* This macro returns the clock cycles required to count up to 10MS with respect +* to AXI Lite Frequency +* +* @param InstancePtr is a pointer to the XV_HdmiRX core instance. +* +* @return None. +* +* +******************************************************************************/ +#define XV_HdmiRx_GetTime10Ms(InstancePtr) \ + (InstancePtr)->Config.AxiLiteClkFreq/100 + +/*****************************************************************************/ +/** +* +* This macro returns the clock cycles required to count up to 16MS with +* respect to AXI Lite Frequency +* +* @param InstancePtr is a pointer to the XV_HdmiRX core instance. +* +* @return None. +* +* +******************************************************************************/ +#define XV_HdmiRx_GetTime16Ms(InstancePtr) \ + ((InstancePtr)->Config.AxiLiteClkFreq*10)/625 + +/*****************************************************************************/ +/** +* +* This macro returns the clock cycles required to count up to 200MS with +* respect to AXI Lite Frequency +* +* @param InstancePtr is a pointer to the XV_HdmiRX core instance. +* +* @return None. +* +* +******************************************************************************/ +#define XV_HdmiRx_GetTime200Ms(InstancePtr) \ + (InstancePtr)->Config.AxiLiteClkFreq/5 + /*****************************************************************************/ /** * @@ -438,7 +513,7 @@ typedef struct { * * This macro controls the HDMI RX Scrambler. * -* @param InstancePtr is a pointer to the XHdmi_Tx core instance. +* @param InstancePtr is a pointer to the XHdmi_Rx core instance. * @param SetClr specifies TRUE/FALSE value to either enable or disable the * scrambler. * @@ -1209,6 +1284,7 @@ int XV_HdmiRx_GetTmdsClockRatio(XV_HdmiRx *InstancePtr); u8 XV_HdmiRx_GetAviVic(XV_HdmiRx *InstancePtr); XVidC_ColorFormat XV_HdmiRx_GetAviColorSpace(XV_HdmiRx *InstancePtr); XVidC_ColorDepth XV_HdmiRx_GetGcpColorDepth(XV_HdmiRx *InstancePtr); +XVidC_VideoMode XV_HdmiRx_LookupVmId(u8 Vic); int XV_HdmiRx_GetVideoProperties(XV_HdmiRx *InstancePtr); int XV_HdmiRx_GetVideoTiming(XV_HdmiRx *InstancePtr); u32 XV_HdmiRx_Divide(u32 Dividend, u32 Divisor); @@ -1221,8 +1297,13 @@ int XV_HdmiRx_SelfTest(XV_HdmiRx *InstancePtr); /* Interrupt related function in xv_hdmirx_intr.c */ void XV_HdmiRx_IntrHandler(void *InstancePtr); -int XV_HdmiRx_SetCallback(XV_HdmiRx *InstancePtr, u32 HandlerType, void *CallbackFunc, void *CallbackRef); +int XV_HdmiRx_SetCallback(XV_HdmiRx *InstancePtr, + XV_HdmiRx_HandlerType HandlerType, + void *CallbackFunc, + void *CallbackRef); + +/* [Linux] No need to add vendor specific API */ /************************** Variable Declarations ****************************/ /************************** Variable Declarations ****************************/ diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirx_intr.c b/hdmi/xilinx-hdmi-rx/xv_hdmirx_intr.c index 45e563a..c855ac9 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirx_intr.c +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirx_intr.c @@ -46,6 +46,14 @@ * 16/11/17 Update Reset sequence with dedicated reset for * each clock domain * MMO 08/02/18 Adding proper handling for Sync Loss/Sync Recover +* 2.10 YH 13/04/18 Fixed a bug in PioIntrHandler +* 2.20 EB 16/08/18 Replaced TIME_10MS, TIME_16MS, TIME_200MS with +* XV_HdmiRx_GetTime10Ms, XV_HdmiRx_GetTime16Ms +* XV_HdmiRx_GetTime200Ms +* Added TMDS Clock Ratio callback support +* YB 15/08/18 Added new cases for HDCP 1.4 & 2.2 protocol events in +* XV_HdmiRx_SetCallback function. +* Updated the HdmiRx_DdcIntrHandler() function. * * ******************************************************************************/ @@ -204,7 +212,10 @@ void XV_HdmiRx_IntrHandler(void *InstancePtr) * installed replaces it with the new handler. * ******************************************************************************/ -int XV_HdmiRx_SetCallback(XV_HdmiRx *InstancePtr, u32 HandlerType, void *CallbackFunc, void *CallbackRef) +int XV_HdmiRx_SetCallback(XV_HdmiRx *InstancePtr, + XV_HdmiRx_HandlerType HandlerType, + void *CallbackFunc, + void *CallbackRef) { u32 Status; @@ -285,12 +296,28 @@ int XV_HdmiRx_SetCallback(XV_HdmiRx *InstancePtr, u32 HandlerType, void *Callbac Status = (XST_SUCCESS); break; - case (XV_HDMIRX_HANDLER_LINK_ERROR): - InstancePtr->LinkErrorCallback = (XV_HdmiRx_Callback)CallbackFunc; - InstancePtr->LinkErrorRef = CallbackRef; - InstancePtr->IsLinkErrorCallbackSet = (TRUE); - Status = (XST_SUCCESS); - break; + // HDCP 1.4 Event + case (XV_HDMIRX_HANDLER_DDC_HDCP_14_PROT): + InstancePtr->Hdcp14ProtEvtCallback = (XV_HdmiRx_Callback)CallbackFunc; + InstancePtr->Hdcp14ProtEvtRef = CallbackRef; + InstancePtr->IsHdcp14ProtEvtCallbackSet = (TRUE); + Status = (XST_SUCCESS); + break; + + // HDCP 2.2 Event + case (XV_HDMIRX_HANDLER_DDC_HDCP_22_PROT): + InstancePtr->Hdcp22ProtEvtCallback = (XV_HdmiRx_Callback)CallbackFunc; + InstancePtr->Hdcp22ProtEvtRef = CallbackRef; + InstancePtr->IsHdcp22ProtEvtCallbackSet = (TRUE); + Status = (XST_SUCCESS); + break; + + case (XV_HDMIRX_HANDLER_LINK_ERROR): + InstancePtr->LinkErrorCallback = (XV_HdmiRx_Callback)CallbackFunc; + InstancePtr->LinkErrorRef = CallbackRef; + InstancePtr->IsLinkErrorCallbackSet = (TRUE); + Status = (XST_SUCCESS); + break; // Bridge FIFO Overflow case (XV_HDMIRX_HANDLER_BRDG_OVERFLOW): @@ -316,6 +343,24 @@ int XV_HdmiRx_SetCallback(XV_HdmiRx *InstancePtr, u32 HandlerType, void *Callbac Status = (XST_SUCCESS); break; + // TMDS clock ratio + case (XV_HDMIRX_HANDLER_TMDS_CLK_RATIO): + InstancePtr->TmdsClkRatioCallback = + (XV_HdmiRx_Callback)CallbackFunc; + InstancePtr->TmdsClkRatioRef = CallbackRef; + InstancePtr->IsTmdsClkRatioCallbackSet = (TRUE); + Status = (XST_SUCCESS); + break; + + // Vic Error + case (XV_HDMIRX_HANDLER_VIC_ERROR): + InstancePtr->VicErrorCallback = + (XV_HdmiRx_Callback)CallbackFunc; + InstancePtr->VicErrorRef = CallbackRef; + InstancePtr->IsVicErrorCallbackSet = (TRUE); + Status = (XST_SUCCESS); + break; + default: Status = (XST_INVALID_PARAM); break; @@ -340,15 +385,19 @@ int XV_HdmiRx_SetCallback(XV_HdmiRx *InstancePtr, u32 HandlerType, void *Callbac void HdmiRx_VtdIntrHandler(XV_HdmiRx *InstancePtr) { u32 Status; + XVidC_VideoMode DecodedVmId = 0; /* Read Video timing detector Status register */ - Status = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_STA_OFFSET)); + Status = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, + (XV_HDMIRX_VTD_STA_OFFSET)); /* Check for time base event */ if ((Status) & (XV_HDMIRX_VTD_STA_TIMEBASE_EVT_MASK)) { // Clear event flag - XV_HdmiRx_WriteReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_STA_OFFSET), (XV_HDMIRX_VTD_STA_TIMEBASE_EVT_MASK)); + XV_HdmiRx_WriteReg(InstancePtr->Config.BaseAddress, + (XV_HDMIRX_VTD_STA_OFFSET), + (XV_HDMIRX_VTD_STA_TIMEBASE_EVT_MASK)); // Check if we are in lock state if (InstancePtr->Stream.State == XV_HDMIRX_STATE_STREAM_LOCK) { @@ -357,12 +406,26 @@ void HdmiRx_VtdIntrHandler(XV_HdmiRx *InstancePtr) Status = XV_HdmiRx_GetVideoTiming(InstancePtr); if (Status == XST_SUCCESS) { + if (InstancePtr->Stream.Vic != 0) { + DecodedVmId = XV_HdmiRx_LookupVmId(InstancePtr->Stream.Vic); + + if (DecodedVmId != InstancePtr->Stream.Video.VmId && + !(DecodedVmId == XVIDC_VM_NOT_SUPPORTED && + InstancePtr->Stream.Video.VmId == + XVIDC_VM_CUSTOM)) { + /* Call VIC error callback */ + if (InstancePtr->VicErrorCallback) { + InstancePtr->VicErrorCallback( + InstancePtr->VicErrorRef); + } + } + } // Enable AXI Stream output XV_HdmiRx_AxisEnable(InstancePtr, (TRUE)); // Set stream status to up - InstancePtr->Stream.State = XV_HDMIRX_STATE_STREAM_UP; // The stream is up + InstancePtr->Stream.State = XV_HDMIRX_STATE_STREAM_UP; // Set stream sync status to est InstancePtr->Stream.SyncStatus = XV_HDMIRX_SYNCSTAT_SYNC_EST; @@ -393,8 +456,8 @@ void HdmiRx_VtdIntrHandler(XV_HdmiRx *InstancePtr) InstancePtr->Stream.State = XV_HDMIRX_STATE_STREAM_LOCK; } else if (InstancePtr->Stream.SyncStatus == XV_HDMIRX_SYNCSTAT_SYNC_LOSS) { - // Sync Est/Recover Flag - InstancePtr->Stream.SyncStatus = XV_HDMIRX_SYNCSTAT_SYNC_EST; + // Sync Est/Recover Flag + InstancePtr->Stream.SyncStatus = XV_HDMIRX_SYNCSTAT_SYNC_EST; // Call sync lost callback if (InstancePtr->IsSyncLossCallbackSet) { @@ -412,8 +475,8 @@ void HdmiRx_VtdIntrHandler(XV_HdmiRx *InstancePtr) XV_HdmiRx_WriteReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_VTD_STA_OFFSET), (XV_HDMIRX_VTD_STA_SYNC_LOSS_EVT_MASK)); if (InstancePtr->Stream.State == XV_HDMIRX_STATE_STREAM_UP) { - // Enable the Stream Up + Sync Loss Flag - InstancePtr->Stream.SyncStatus = XV_HDMIRX_SYNCSTAT_SYNC_LOSS; + // Enable the Stream Up + Sync Loss Flag + InstancePtr->Stream.SyncStatus = XV_HDMIRX_SYNCSTAT_SYNC_LOSS; // Call sync lost callback if (InstancePtr->IsSyncLossCallbackSet) { @@ -497,8 +560,8 @@ void HdmiRx_DdcIntrHandler(XV_HdmiRx *InstancePtr) XV_HdmiRx_WriteReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_DDC_STA_OFFSET), (XV_HDMIRX_DDC_STA_HDCP_1_PROT_EVT_MASK)); /* Callback */ - if (InstancePtr->IsHdcpCallbackSet) { - InstancePtr->HdcpCallback(InstancePtr->HdcpRef, XV_HDMIRX_DDC_STA_HDCP_1_PROT_EVT_MASK); + if (InstancePtr->IsHdcp14ProtEvtCallbackSet) { + InstancePtr->Hdcp14ProtEvtCallback(InstancePtr->Hdcp14ProtEvtRef); } } @@ -509,8 +572,8 @@ void HdmiRx_DdcIntrHandler(XV_HdmiRx *InstancePtr) XV_HdmiRx_WriteReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_DDC_STA_OFFSET), (XV_HDMIRX_DDC_STA_HDCP_2_PROT_EVT_MASK)); /* Callback */ - if (InstancePtr->IsHdcpCallbackSet) { - InstancePtr->HdcpCallback(InstancePtr->HdcpRef, XV_HDMIRX_DDC_STA_HDCP_2_PROT_EVT_MASK); + if (InstancePtr->IsHdcp22ProtEvtCallbackSet) { + InstancePtr->Hdcp22ProtEvtCallback(InstancePtr->Hdcp22ProtEvtRef); } } @@ -532,8 +595,6 @@ void HdmiRx_PioIntrHandler(XV_HdmiRx *InstancePtr) { u32 Event; u32 Data; - u32 Time_10ms = InstancePtr->Config.AxiLiteClkFreq/100; - u32 Time_200ms = InstancePtr->Config.AxiLiteClkFreq/5; /* Read PIO IN Event register.*/ Event = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_PIO_IN_EVT_OFFSET)); @@ -575,7 +636,8 @@ void HdmiRx_PioIntrHandler(XV_HdmiRx *InstancePtr) InstancePtr->Stream.State = XV_HDMIRX_STATE_STREAM_IDLE; // The stream idle // Load timer - XV_HdmiRx_TmrStart(InstancePtr, Time_10ms); // 10 ms + XV_HdmiRx_TmrStart(InstancePtr, + XV_HdmiRx_GetTime10Ms(InstancePtr)); // 10 ms } // Video ready event has occurred @@ -602,8 +664,9 @@ void HdmiRx_PioIntrHandler(XV_HdmiRx *InstancePtr) // Set stream status to arm InstancePtr->Stream.State = XV_HDMIRX_STATE_STREAM_ARM; // The stream is armed - // Load timer - XV_HdmiRx_TmrStart(InstancePtr, Time_200ms); // 200 ms (one UHD frame is 40 ms, 5 frames) + // Load timer - 200 ms (one UHD frame is 40 ms, 5 frames) + XV_HdmiRx_TmrStart(InstancePtr, + XV_HdmiRx_GetTime200Ms(InstancePtr)); } } @@ -680,11 +743,12 @@ void HdmiRx_PioIntrHandler(XV_HdmiRx *InstancePtr) /* Clear variables */ XV_HdmiRx_Clear(InstancePtr); - // Set stream status to idle + // Set stream status to idle InstancePtr->Stream.State = XV_HDMIRX_STATE_STREAM_IDLE; // Load timer - XV_HdmiRx_TmrStart(InstancePtr, Time_10ms); // 10 ms + XV_HdmiRx_TmrStart(InstancePtr, + XV_HdmiRx_GetTime10Ms(InstancePtr)); // 10 ms } // Call mode callback @@ -693,6 +757,21 @@ void HdmiRx_PioIntrHandler(XV_HdmiRx *InstancePtr) } } + // TMDS clock ratio + if ((Event) & (XV_HDMIRX_PIO_IN_SCDC_TMDS_CLOCK_RATIO_MASK)) { + // Call TMDS Ratio callback + if (InstancePtr->IsTmdsClkRatioCallbackSet) { + InstancePtr->TmdsClkRatioCallback(InstancePtr->TmdsClkRatioRef); + } + } + + /* Bridge Overflow event has occurred */ + if ((Event) & (XV_HDMIRX_PIO_IN_BRDG_OVERFLOW_MASK)) { + // Check if user callback has been registered + if (InstancePtr->IsBrdgOverflowCallbackSet) { + InstancePtr->BrdgOverflowCallback(InstancePtr->BrdgOverflowRef); + } + } } @@ -711,7 +790,6 @@ void HdmiRx_PioIntrHandler(XV_HdmiRx *InstancePtr) void HdmiRx_TmrIntrHandler(XV_HdmiRx *InstancePtr) { u32 Status; - u32 Time_200ms = InstancePtr->Config.AxiLiteClkFreq/5; /* Read Status register */ Status = XV_HdmiRx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_TMR_STA_OFFSET)); @@ -743,8 +821,9 @@ void HdmiRx_TmrIntrHandler(XV_HdmiRx *InstancePtr) // Clear GetVideoPropertiesTries InstancePtr->Stream.GetVideoPropertiesTries = 0; - // Load timer - XV_HdmiRx_TmrStart(InstancePtr, Time_200ms); // 200 ms (one UHD frame is 40 ms, 5 frames) + // Load timer - 200 ms (one UHD frame is 40 ms, 5 frames) + XV_HdmiRx_TmrStart(InstancePtr, + XV_HdmiRx_GetTime200Ms(InstancePtr)); } // Init state @@ -789,8 +868,9 @@ void HdmiRx_TmrIntrHandler(XV_HdmiRx *InstancePtr) } else { - // Load timer - XV_HdmiRx_TmrStart(InstancePtr, Time_200ms); // 200 ms (one UHD frame is 40 ms, 5 frames) + // Load timer - 200 ms (one UHD frame is 40 ms, 5 frames) + XV_HdmiRx_TmrStart(InstancePtr, + XV_HdmiRx_GetTime200Ms(InstancePtr)); } } @@ -831,12 +911,12 @@ void HdmiRx_AuxIntrHandler(XV_HdmiRx *InstancePtr) /* Check for GCP colordepth event */ if ((Status) & (XV_HDMIRX_AUX_STA_GCP_CD_EVT_MASK)) { - /* Clear event flag */ - XV_HdmiRx_WriteReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_AUX_STA_OFFSET), (XV_HDMIRX_AUX_STA_GCP_CD_EVT_MASK)); + /* Clear event flag */ + XV_HdmiRx_WriteReg(InstancePtr->Config.BaseAddress, (XV_HDMIRX_AUX_STA_OFFSET), (XV_HDMIRX_AUX_STA_GCP_CD_EVT_MASK)); - if ((Status) & (XV_HDMIRX_AUX_STA_GCP_MASK)) { - InstancePtr->Stream.Video.ColorDepth = XV_HdmiRx_GetGcpColorDepth(InstancePtr); - } + if ((Status) & (XV_HDMIRX_AUX_STA_GCP_MASK)) { + InstancePtr->Stream.Video.ColorDepth = XV_HdmiRx_GetGcpColorDepth(InstancePtr); + } } /* Check for new packet */ diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirxss.c b/hdmi/xilinx-hdmi-rx/xv_hdmirxss.c index c1b215f..fb95f0f 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirxss.c +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirxss.c @@ -97,6 +97,13 @@ * XV_HdmiRxSs_GetVSIF * Updated XV_HdmiRxSs_ConfigBridgeMode so Pixel * Pepetition is based on received AVI InfoFrame +* 5.10 MMO 06/04/18 Updated XV_HdmiRxSs_ToggleHpd and XV_HdmiRxSs_Stop +* for cleaner HPD flow during transition from HDMI2.0 +* to HDMI1.4 +* YH 13/04/18 Fixed a bug in XV_HdmiRxSs_BrdgOverflowCallback +* 5.20 EB 03/08/18 Added function XV_HdmiRxSs_AudioMute +* Added TMDS Clock Ratio callback support +* 5.40 EB 06/08/19 Added Vic and Video Timing mismatch callback support ******************************************************************************/ /***************************** Include Files *********************************/ @@ -143,6 +150,8 @@ static void XV_HdmiRxSs_StreamInitCallback(void *CallbackRef); static void XV_HdmiRxSs_StreamUpCallback(void *CallbackRef); static void XV_HdmiRxSs_SyncLossCallback(void *CallbackRef); static void XV_HdmiRxSs_ModeCallback(void *CallbackRef); +static void XV_HdmiRxSs_TmdsClkRatioCallback(void *CallbackRef); +static void XV_HdmiRxSs_VicErrorCallback(void *CallbackRef); static void XV_HdmiRxSs_ReportCoreInfo(XV_HdmiRxSs *InstancePtr); static void XV_HdmiRxSs_ReportTiming(XV_HdmiRxSs *InstancePtr); @@ -155,28 +164,6 @@ static void XV_HdmiRxSs_ConfigBridgeMode(XV_HdmiRxSs *InstancePtr); /***************** Macros (Inline Functions) Definitions *********************/ /*****************************************************************************/ -/** -* This macros selects the bridge YUV420 mode -* -* @param InstancePtr is a pointer to the HDMI RX Subsystem -* -*****************************************************************************/ -#define XV_HdmiRxSs_BridgeYuv420(InstancePtr,Enable) \ -{ \ - XV_HdmiRx_Bridge_yuv420(InstancePtr->HdmiRxPtr, Enable); \ -} \ - -/*****************************************************************************/ -/** -* This macros selects the bridge pixel repeat mode -* -* @param InstancePtr is a pointer to the HDMI TX Subsystem -* -*****************************************************************************/ -#define XV_HdmiRxSs_BridgePixelDrop(InstancePtr,Enable) \ -{ \ - XV_HdmiRx_Bridge_pixel(InstancePtr->HdmiRxPtr, Enable); \ -} /************************** Function Definition ******************************/ @@ -191,7 +178,8 @@ void XV_HdmiRxSs_ReportInfo(XV_HdmiRxSs *InstancePtr) xil_printf("HDMI RX Mode - "); if (InstancePtr->HdmiRxPtr->Stream.IsHdmi == (TRUE)) { xil_printf("HDMI\r\n"); - } else { + } + else { xil_printf("DVI\r\n"); } xil_printf("------------\r\n"); @@ -402,6 +390,16 @@ static int XV_HdmiRxSs_RegisterSubsysCallbacks(XV_HdmiRxSs *InstancePtr) XV_HDMIRX_HANDLER_MODE, (void *)XV_HdmiRxSs_ModeCallback, (void *)InstancePtr); + + XV_HdmiRx_SetCallback(HdmiRxSsPtr->HdmiRxPtr, + XV_HDMIRX_HANDLER_TMDS_CLK_RATIO, + (void *)XV_HdmiRxSs_TmdsClkRatioCallback, + (void *)InstancePtr); + + XV_HdmiRx_SetCallback(HdmiRxSsPtr->HdmiRxPtr, + XV_HDMIRX_HANDLER_VIC_ERROR, + (void *)XV_HdmiRxSs_VicErrorCallback, + (void *)InstancePtr); } return(XST_SUCCESS); @@ -617,7 +615,7 @@ void XV_HdmiRxSs_Start(XV_HdmiRxSs *InstancePtr) #ifdef XV_HDMIRXSS_LOG_ENABLE XV_HdmiRxSs_LogWrite(InstancePtr, XV_HDMIRXSS_LOG_EVT_START, 0); #endif - /* Set RX hot plug detect */ + /* Drive HDMI RX HPD High */ XV_HdmiRx_SetHpd(InstancePtr->HdmiRxPtr, TRUE); /* Disable Audio Peripheral */ @@ -638,6 +636,16 @@ void XV_HdmiRxSs_Start(XV_HdmiRxSs *InstancePtr) void XV_HdmiRxSs_Stop(XV_HdmiRxSs *InstancePtr) { Xil_AssertVoid(InstancePtr != NULL); + + /* Clear SCDC variables */ + XV_HdmiRx_DdcScdcClear(InstancePtr->HdmiRxPtr); + + /* Disable the scrambler */ + XV_HdmiRx_SetScrambler(InstancePtr->HdmiRxPtr, (FALSE)); + + /* Drive HDMI RX HPD Low */ + XV_HdmiRx_SetHpd(InstancePtr->HdmiRxPtr, (FALSE)); + #ifdef XV_HDMIRXSS_LOG_ENABLE XV_HdmiRxSs_LogWrite(InstancePtr, XV_HDMIRXSS_LOG_EVT_STOP, 0); #endif @@ -762,8 +770,8 @@ static void XV_HdmiRxSs_BrdgOverflowCallback(void *CallbackRef) XV_HdmiRxSs *HdmiRxSsPtr = (XV_HdmiRxSs *)CallbackRef; // Check if user callback has been registered - if (HdmiRxSsPtr->ConnectCallback) { - HdmiRxSsPtr->ConnectCallback(HdmiRxSsPtr->ConnectRef); + if (HdmiRxSsPtr->BrdgOverflowCallback) { + HdmiRxSsPtr->BrdgOverflowCallback(HdmiRxSsPtr->BrdgOverflowRef); } } @@ -862,7 +870,7 @@ static void XV_HdmiRxSs_AuxCallback(void *CallbackRef) // Parse Aux to retrieve Avi InfoFrame XV_HdmiC_ParseAVIInfoFrame(AuxPtr, AviInfoFramePtr); HdmiRxSsPtr->HdmiRxPtr->Stream.Video.ColorFormatId = - XV_HdmiRx_GetAviColorSpace(HdmiRxSsPtr->HdmiRxPtr); + XV_HdmiRx_GetAviColorSpace(HdmiRxSsPtr->HdmiRxPtr); HdmiRxSsPtr->HdmiRxPtr->Stream.Vic = XV_HdmiRx_GetAviVic(HdmiRxSsPtr->HdmiRxPtr); HdmiRxSsPtr->HdmiRxPtr->Stream.Video.AspectRatio = @@ -903,7 +911,7 @@ static void XV_HdmiRxSs_SyncLossCallback(void *CallbackRef) XV_HdmiRxSs *HdmiRxSsPtr = (XV_HdmiRxSs *)CallbackRef; if (HdmiRxSsPtr->HdmiRxPtr->Stream.SyncStatus == - XV_HDMIRX_SYNCSTAT_SYNC_LOSS) { + XV_HDMIRX_SYNCSTAT_SYNC_LOSS) { // Push sync loss event to HDCP event queue #ifdef XV_HDMIRXSS_LOG_ENABLE XV_HdmiRxSs_LogWrite(HdmiRxSsPtr, XV_HDMIRXSS_LOG_EVT_SYNCLOSS, 0); @@ -915,7 +923,7 @@ static void XV_HdmiRxSs_SyncLossCallback(void *CallbackRef) } // Sync is recovered/establish else if (HdmiRxSsPtr->HdmiRxPtr->Stream.SyncStatus == - XV_HDMIRX_SYNCSTAT_SYNC_EST) { + XV_HDMIRX_SYNCSTAT_SYNC_EST) { // Push sync loss event to HDCP event queue #ifdef XV_HDMIRXSS_LOG_ENABLE XV_HdmiRxSs_LogWrite(HdmiRxSsPtr, XV_HDMIRXSS_LOG_EVT_SYNCEST, 0); @@ -965,6 +973,56 @@ static void XV_HdmiRxSs_ModeCallback(void *CallbackRef) } } +/*****************************************************************************/ +/** +* +* This function is called when the TMDS CLK ratio changes. +* +* @param None. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void XV_HdmiRxSs_TmdsClkRatioCallback(void *CallbackRef) +{ + XV_HdmiRxSs *HdmiRxSsPtr = (XV_HdmiRxSs *)CallbackRef; + + // Check if user callback has been registered + if (HdmiRxSsPtr->TmdsClkRatioCallback) { + HdmiRxSsPtr->TmdsClkRatioCallback(HdmiRxSsPtr->TmdsClkRatioRef); + } + +} + +/*****************************************************************************/ +/** +* +* This function is called when the Vic does not match with the detected video +* timing. +* +* @param None. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void XV_HdmiRxSs_VicErrorCallback(void *CallbackRef) +{ + XV_HdmiRxSs *HdmiRxSsPtr = (XV_HdmiRxSs *)CallbackRef; + +#ifdef XV_HDMIRXSS_LOG_ENABLE + XV_HdmiRxSs_LogWrite(HdmiRxSsPtr, XV_HDMIRXSS_LOG_EVT_VICERROR, 0); +#endif + + // Check if user callback has been registered + if (HdmiRxSsPtr->VicErrorCallback) { + HdmiRxSsPtr->VicErrorCallback(HdmiRxSsPtr->VicErrorRef); + } +} + /*****************************************************************************/ /** * @@ -1239,8 +1297,10 @@ static void XV_HdmiRxSs_StreamUpCallback(void *CallbackRef) * installed replaces it with the new handler. * ******************************************************************************/ -int XV_HdmiRxSs_SetCallback(XV_HdmiRxSs *InstancePtr, u32 HandlerType, - void *CallbackFunc, void *CallbackRef) +int XV_HdmiRxSs_SetCallback(XV_HdmiRxSs *InstancePtr, + XV_HdmiRxSs_HandlerType HandlerType, + void *CallbackFunc, + void *CallbackRef) { u32 Status; @@ -1311,6 +1371,21 @@ int XV_HdmiRxSs_SetCallback(XV_HdmiRxSs *InstancePtr, u32 HandlerType, Status = (XST_SUCCESS); break; + // TMDS_CLK_RATIO + case (XV_HDMIRXSS_HANDLER_TMDS_CLK_RATIO): + InstancePtr->TmdsClkRatioCallback = + (XV_HdmiRxSs_Callback)CallbackFunc; + InstancePtr->TmdsClkRatioRef = CallbackRef; + Status = (XST_SUCCESS); + break; + + // VIC_ERROR + case (XV_HDMIRXSS_HANDLER_VIC_ERROR): + InstancePtr->VicErrorCallback = (XV_HdmiRxSs_Callback)CallbackFunc; + InstancePtr->VicErrorRef = CallbackRef; + Status = (XST_SUCCESS); + break; + // HDCP case (XV_HDMIRXSS_HANDLER_HDCP): InstancePtr->HdcpCallback = (XV_HdmiRxSs_Callback)CallbackFunc; @@ -1542,7 +1617,7 @@ void XV_HdmiRxSs_LoadEdid(XV_HdmiRxSs *InstancePtr, u8 *EdidDataPtr, ******************************************************************************/ void XV_HdmiRxSs_SetHpd(XV_HdmiRxSs *InstancePtr, u8 Value) { - /* Drive HPD low */ + /* Drive HDMI RX HPD based on the input value */ XV_HdmiRx_SetHpd(InstancePtr->HdmiRxPtr, Value); } @@ -1558,13 +1633,19 @@ void XV_HdmiRxSs_SetHpd(XV_HdmiRxSs *InstancePtr, u8 Value) ******************************************************************************/ void XV_HdmiRxSs_ToggleHpd(XV_HdmiRxSs *InstancePtr) { - /* Drive HPD low */ + /* Clear SCDC variables */ + XV_HdmiRx_DdcScdcClear(InstancePtr->HdmiRxPtr); + + /* Disable the scrambler */ + XV_HdmiRx_SetScrambler(InstancePtr->HdmiRxPtr, (FALSE)); + + /* Drive HDMI RX HPD Low */ XV_HdmiRx_SetHpd(InstancePtr->HdmiRxPtr, (FALSE)); /* Wait 500 ms */ XV_HdmiRxSs_WaitUs(InstancePtr, 500000); - /* Drive HPD high */ + /* Drive HDMI RX HPD High */ XV_HdmiRx_SetHpd(InstancePtr->HdmiRxPtr, (TRUE)); } @@ -2042,11 +2123,11 @@ static void XV_HdmiRxSs_ConfigBridgeMode(XV_HdmiRxSs *InstancePtr) { // Pixel Repetition factor of 3 and above are not supported by the bridge if (AviInfoFramePtr->PixelRepetition > XHDMIC_PIXEL_REPETITION_FACTOR_2) { #ifdef XV_HDMIRXSS_LOG_ENABLE - XV_HdmiRxSs_LogWrite(InstancePtr, XV_HDMIRXSS_LOG_EVT_PIX_REPEAT_ERR, - AviInfoFramePtr->PixelRepetition); + XV_HdmiRxSs_LogWrite(InstancePtr, XV_HDMIRXSS_LOG_EVT_PIX_REPEAT_ERR, + AviInfoFramePtr->PixelRepetition); #endif - return; + return; } if (HdmiRxSsVidStreamPtr->ColorFormatId == XVIDC_CSF_YCRCB_420) { @@ -2082,10 +2163,11 @@ static void XV_HdmiRxSs_ConfigBridgeMode(XV_HdmiRxSs *InstancePtr) { * * @return None. * -* @note None. +* @note Linux - No need to put definition inside. * ******************************************************************************/ void XV_HdmiRxSs_SetDefaultPpc(XV_HdmiRxSs *InstancePtr, u8 Id) { + } /*****************************************************************************/ @@ -2199,3 +2281,24 @@ int XV_HdmiRxSs_ShowInfo(XV_HdmiRxSs *InstancePtr, char *buff, int buff_size) return strSize; } + +/* +* This function set HDMI RX audio parameters +* +* @param Enable 0: Unmute the audio 1: Mute the audio. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XV_HdmiRxSs_AudioMute(XV_HdmiRxSs *InstancePtr, u8 Enable) +{ + //Audio Mute Mode + if (Enable){ + XV_HdmiRx_AudioDisable(InstancePtr->HdmiRxPtr); + } + else{ + XV_HdmiRx_AudioEnable(InstancePtr->HdmiRxPtr); + } +} diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirxss.h b/hdmi/xilinx-hdmi-rx/xv_hdmirxss.h index b90c9ed..d7d69bb 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirxss.h +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirxss.h @@ -75,6 +75,13 @@ * Added functions XV_HdmiRxSs_GetAviInfoframe, * XV_HdmiRxSs_GetGCP, XV_HdmiRxSs_GetAudioInfoframe, * XV_HdmiRxSs_GetVSIF +* 5.2 YB 08/14/18 Added dedicated callbacks for HDCP 1.4 and HDCP 2.2 +* protocol events. +* EB 03/08/18 Added function XV_HdmiRxSs_AudioMute +* Added TMDS Clock Ratio callback support +* YB 17/08/18 Marked XV_HDMIRXSS_HDCP_1_PROT_EVT and +* XV_HDMIRXSS_HDCP_2_PROT_EVT as deprecated. +* 5.40 EB 06/08/19 Added Vic and Video Timing mismatch callback support * * ******************************************************************************/ @@ -97,6 +104,10 @@ extern "C" { #if defined(XPAR_XHDCP_NUM_INSTANCES) || defined(XPAR_XHDCP22_RX_NUM_INSTANCES) #define USE_HDCP_RX +#define USE_HDCP_14_PROT_EVT_ENUM +#pragma message ("'XV_HDMIRXSS_HDCP_1_PROT_EVT' event is deprecated") +#define USE_HDCP_22_PROT_EVT_ENUM +#pragma message ("'XV_HDMIRXSS_HDCP_2_PROT_EVT' event is deprecated") #define XV_HDMIRXSS_HDCP_KEYSEL 0x00u #define XV_HDMIRXSS_HDCP_MAX_QUEUE_SIZE 16 #endif @@ -109,11 +120,42 @@ extern "C" { #ifdef XPAR_XHDCP22_RX_NUM_INSTANCES #include "xhdcp22_rx.h" #endif + +/***************** Macros (Inline Functions) Definitions *********************/ +/*****************************************************************************/ +/** +* This macros selects the bridge YUV420 mode +* +* @param InstancePtr is a pointer to the HDMI RX Subsystem +* +*****************************************************************************/ +#define XV_HdmiRxSs_BridgeYuv420(InstancePtr,Enable) \ +{ \ + XV_HdmiRx_Bridge_yuv420(InstancePtr->HdmiRxPtr, Enable); \ +} \ + +/*****************************************************************************/ +/** +* This macros selects the bridge pixel repeat mode +* +* @param InstancePtr is a pointer to the HDMI RX Subsystem +* +*****************************************************************************/ +#define XV_HdmiRxSs_BridgePixelDrop(InstancePtr,Enable) \ +{ \ + XV_HdmiRx_Bridge_pixel(InstancePtr->HdmiRxPtr, Enable); \ +} + + /****************************** Type Definitions ******************************/ /** @name Handler Types * @{ */ +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_RESET "\x1b[0m" + #ifdef XV_HDMIRXSS_LOG_ENABLE typedef enum { XV_HDMIRXSS_LOG_EVT_NONE = 1, /**< Log event none. */ @@ -141,6 +183,7 @@ typedef enum { XV_HDMIRXSS_LOG_EVT_SYNCLOSS, /**< Log event Sync Loss detected. */ XV_HDMIRXSS_LOG_EVT_PIX_REPEAT_ERR, /**< Log event Unsupported Pixel Repetition. */ XV_HDMIRXSS_LOG_EVT_SYNCEST, /**< Log event Sync Loss detected. */ + XV_HDMIRXSS_LOG_EVT_VICERROR, /**< Log event vic error detected. */ XV_HDMIRXSS_LOG_EVT_DUMMY /**< Dummy Event should be last */ } XV_HdmiRxSs_LogEvent; @@ -180,8 +223,12 @@ typedef enum XV_HDMIRXSS_HDCP_STREAMDOWN_EVT, XV_HDMIRXSS_HDCP_CONNECT_EVT, XV_HDMIRXSS_HDCP_DISCONNECT_EVT, +#ifdef USE_HDCP_14_PROT_EVT_ENUM XV_HDMIRXSS_HDCP_1_PROT_EVT, +#endif +#ifdef USE_HDCP_22_PROT_EVT_ENUM XV_HDMIRXSS_HDCP_2_PROT_EVT, +#endif XV_HDMIRXSS_HDCP_DVI_MODE_EVT, XV_HDMIRXSS_HDCP_HDMI_MODE_EVT, XV_HDMIRXSS_HDCP_SYNC_LOSS_EVT, @@ -259,14 +306,19 @@ typedef enum { unauthenticated event*/ XV_HDMIRXSS_HANDLER_HDCP_AUTHENTICATION_REQUEST, /**< Handler for HDCP authentication request - event */ + event */ XV_HDMIRXSS_HANDLER_HDCP_STREAM_MANAGE_REQUEST, /**< Handler for HDCP stream manage request event */ XV_HDMIRXSS_HANDLER_HDCP_TOPOLOGY_UPDATE, /**< Handler for HDCP topology update event*/ - XV_HDMIRXSS_HANDLER_HDCP_ENCRYPTION_UPDATE /**< Handler for HDCP + XV_HDMIRXSS_HANDLER_HDCP_ENCRYPTION_UPDATE, /**< Handler for HDCP encryption status - update event */ + update event */ + XV_HDMIRXSS_HANDLER_TMDS_CLK_RATIO, /**< Handler type for + TMDS clock ratio + change */ + XV_HDMIRXSS_HANDLER_VIC_ERROR /**< Handler type for + VIC error change */ } XV_HdmiRxSs_HandlerType; /*@}*/ @@ -325,6 +377,8 @@ typedef struct XV_HdmiRxSs_Config Config; /**< Hardware configuration */ u32 IsReady; /**< Device and the driver instance are initialized */ + u8 AppMajVer; /**< Major Version of application used by the driver */ + u8 AppMinVer; /**< Minor Version of application used by the driver */ #ifdef XV_HDMIRXSS_LOG_ENABLE XV_HdmiRxSs_Log Log; /**< A log of events. */ @@ -373,6 +427,15 @@ typedef struct XV_HdmiRxSs_Callback HdcpCallback; /**< Callback for HDCP 1.4 event */ void *HdcpRef; /**< To be passed to the hdcp callback */ + XV_HdmiRxSs_Callback TmdsClkRatioCallback; /**< Callback for scdc TMDS clock + ratio change callback */ + void *TmdsClkRatioRef;/**< To be passed to the scdc tmds clock ratio change + callback */ + + XV_HdmiRxSs_Callback VicErrorCallback; /**< Callback for VIC error + detection */ + void *VicErrorRef; /**< To be passed to the VIC error callback */ + // Scratch pad u8 IsStreamConnected; /**< HDMI RX Stream Connected */ u8 IsStreamUp; /**< HDMI RX Stream Up */ @@ -434,9 +497,9 @@ void XV_HdmiRxSs_RXCore_LRST(XV_HdmiRxSs *InstancePtr, u8 Reset); void XV_HdmiRxSs_VRST(XV_HdmiRxSs *InstancePtr, u8 Reset); void XV_HdmiRxSs_SYSRST(XV_HdmiRxSs *InstancePtr, u8 Reset); int XV_HdmiRxSs_SetCallback(XV_HdmiRxSs *InstancePtr, - u32 HandlerType, - void *CallbackFunc, - void *CallbackRef); + XV_HdmiRxSs_HandlerType HandlerType, + void *CallbackFunc, + void *CallbackRef); void XV_HdmiRxSs_SetEdidParam(XV_HdmiRxSs *InstancePtr, u8 *EdidDataPtr, u16 Length); void XV_HdmiRxSs_LoadDefaultEdid(XV_HdmiRxSs *InstancePtr); @@ -465,6 +528,7 @@ int XV_HdmiRxSs_IsStreamConnected(XV_HdmiRxSs *InstancePtr); void XV_HdmiRxSs_SetDefaultPpc(XV_HdmiRxSs *InstancePtr, u8 Id); void XV_HdmiRxSs_SetPpc(XV_HdmiRxSs *InstancePtr, u8 Id, u8 Ppc); +void XV_HdmiRxSs_AudioMute(XV_HdmiRxSs *InstancePtr, u8 Enable); #ifdef XV_HDMIRXSS_LOG_ENABLE void XV_HdmiRxSs_LogReset(XV_HdmiRxSs *InstancePtr); diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirxss_coreinit.c b/hdmi/xilinx-hdmi-rx/xv_hdmirxss_coreinit.c index d643ef5..f032972 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirxss_coreinit.c +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirxss_coreinit.c @@ -17,7 +17,6 @@ /** * * @file xv_hdmirxss_coreinit.c -* @addtogroup v_hdmirxss * @{ * @details @@ -57,6 +56,8 @@ * Add compiler option(XV_HDMIRXSS_LOG_ENABLE) to enable Log * 3.2 MH 04/07/17 Fixed issue to prevent HDCP protocol switching when only * one protocol is in the design. +* 5.2 YB 13/08/18 Added XV_HdmiRxSs_DdcHdcp14ProtocolEvtCallback() and +* XV_HdmiRxSs_DdcHdcp22ProtocolEvtCallback() functions. * * ******************************************************************************/ @@ -72,6 +73,8 @@ static void XV_HdmiRxSs_DdcSetRegAddrHandler(void *RefPtr, u32 Data); static void XV_HdmiRxSs_DdcSetRegDataHandler(void *RefPtr, u32 Data); static u32 XV_HdmiRxSs_DdcGetRegDataHandler(void *RefPtr); static void XV_HdmiRxSs_DdcHdcpCallback(void *RefPtr, int Type); +static void XV_HdmiRxSs_DdcHdcp14ProtocolEvtCallback(void *RefPtr); +static void XV_HdmiRxSs_DdcHdcp22ProtocolEvtCallback(void *RefPtr); #endif #ifdef XPAR_XHDCP22_RX_NUM_INSTANCES static u32 XV_HdmiRxSs_DdcGetWriteMessageBufferWordsHandler(void *RefPtr); @@ -268,6 +271,12 @@ int XV_HdmiRxSs_SubcoreInitHdcp14(XV_HdmiRxSs *HdmiRxSsPtr) (void *)XV_HdmiRxSs_DdcHdcpCallback, (void *)HdmiRxSsPtr); + /* Set-up the HDMI RX HDCP 1.4 Protocol Event Callback Handler */ + XV_HdmiRx_SetCallback(HdmiRxSsPtr->HdmiRxPtr, + XV_HDMIRX_HANDLER_DDC_HDCP_14_PROT, + (void *)XV_HdmiRxSs_DdcHdcp14ProtocolEvtCallback, + (void *)HdmiRxSsPtr); + /* Enable HDMI-RX DDC interrupts */ XV_HdmiRx_DdcIntrEnable(HdmiRxSsPtr->HdmiRxPtr); @@ -380,6 +389,12 @@ int XV_HdmiRxSs_SubcoreInitHdcp22(XV_HdmiRxSs *HdmiRxSsPtr) (void *)XV_HdmiRxSs_DdcHdcpCallback, (void *)HdmiRxSsPtr); + /* Set-up the HDMI RX HDCP 2.2 Protocol Event Callback Handler */ + XV_HdmiRx_SetCallback(HdmiRxSsPtr->HdmiRxPtr, + XV_HDMIRX_HANDLER_DDC_HDCP_22_PROT, + (void *)XV_HdmiRxSs_DdcHdcp22ProtocolEvtCallback, + (void *)HdmiRxSsPtr); + /* Set-up the HDMI RX Link error Callback Handler */ XV_HdmiRx_SetCallback(HdmiRxSsPtr->HdmiRxPtr, XV_HDMIRX_HANDLER_LINK_ERROR, @@ -637,7 +652,9 @@ static void XV_HdmiRxSs_DdcHdcpCallback(void *RefPtr, int Type) case XV_HDMIRX_DDC_STA_HDCP_1_PROT_EVT_MASK: #if defined(XPAR_XHDCP_NUM_INSTANCES) && defined(XPAR_XHDCP22_RX_NUM_INSTANCES) if (HdmiRxSsPtr->Hdcp14Ptr && HdmiRxSsPtr->Hdcp22Ptr) { +#ifdef USE_HDCP_14_PROT_EVT_ENUM XV_HdmiRxSs_HdcpPushEvent(HdmiRxSsPtr, XV_HDMIRXSS_HDCP_1_PROT_EVT); +#endif } #endif break; @@ -646,7 +663,9 @@ static void XV_HdmiRxSs_DdcHdcpCallback(void *RefPtr, int Type) case XV_HDMIRX_DDC_STA_HDCP_2_PROT_EVT_MASK: #if defined(XPAR_XHDCP_NUM_INSTANCES) && defined(XPAR_XHDCP22_RX_NUM_INSTANCES) if (HdmiRxSsPtr->Hdcp14Ptr && HdmiRxSsPtr->Hdcp22Ptr) { +#ifdef USE_HDCP_22_PROT_EVT_ENUM XV_HdmiRxSs_HdcpPushEvent(HdmiRxSsPtr, XV_HDMIRXSS_HDCP_2_PROT_EVT); +#endif } #endif break; @@ -655,6 +674,33 @@ static void XV_HdmiRxSs_DdcHdcpCallback(void *RefPtr, int Type) break; } } + +/*****************************************************************************/ +/** +* This function is called when the HDMI-RX DDC HDCP 1.4 Protocol Event +* interrupt has occurred. +* +* @param RefPtr is a callback reference to the HDCP22 RX instance. +* +* @return None. +* +* @note None. +******************************************************************************/ +static void XV_HdmiRxSs_DdcHdcp14ProtocolEvtCallback(void *RefPtr) +{ + XV_HdmiRxSs *HdmiRxSsPtr; + HdmiRxSsPtr = (XV_HdmiRxSs*) RefPtr; + + /* Enable HDCP 1.4 */ +#if defined(XPAR_XHDCP_NUM_INSTANCES) && defined(XPAR_XHDCP22_RX_NUM_INSTANCES) + if (HdmiRxSsPtr->Hdcp14Ptr && HdmiRxSsPtr->Hdcp22Ptr) { + if (XV_HdmiRxSs_HdcpSetProtocol(HdmiRxSsPtr, XV_HDMIRXSS_HDCP_14) != + XST_SUCCESS) { + XV_HdmiRxSs_HdcpSetProtocol(HdmiRxSsPtr, XV_HDMIRXSS_HDCP_22); + } + } +#endif +} #endif #ifdef XPAR_XHDCP22_RX_NUM_INSTANCES @@ -680,6 +726,33 @@ static void XV_HdmiRxSs_LinkErrorCallback(void *RefPtr) } } } + +/*****************************************************************************/ +/** +* This function is called when the HDMI-RX DDC HDCP 2.2 Protocol Event +* interrupt has occurred. +* +* @param RefPtr is a callback reference to the HDCP22 RX instance. +* +* @return None. +* +* @note None. +******************************************************************************/ +static void XV_HdmiRxSs_DdcHdcp22ProtocolEvtCallback(void *RefPtr) +{ + XV_HdmiRxSs *HdmiRxSsPtr; + HdmiRxSsPtr = (XV_HdmiRxSs*) RefPtr; + + /* Enable HDCP 2.2 */ +#if defined(XPAR_XHDCP_NUM_INSTANCES) && defined(XPAR_XHDCP22_RX_NUM_INSTANCES) + if (HdmiRxSsPtr->Hdcp14Ptr && HdmiRxSsPtr->Hdcp22Ptr) { + if (XV_HdmiRxSs_HdcpSetProtocol(HdmiRxSsPtr, XV_HDMIRXSS_HDCP_22) != + XST_SUCCESS) { + XV_HdmiRxSs_HdcpSetProtocol(HdmiRxSsPtr, XV_HDMIRXSS_HDCP_14); + } + } +#endif +} #endif /** @} */ diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirxss_coreinit.h b/hdmi/xilinx-hdmi-rx/xv_hdmirxss_coreinit.h index 5ea6fe5..5ffe218 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirxss_coreinit.h +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirxss_coreinit.h @@ -17,7 +17,6 @@ /** * * @file xv_hdmirxss_coreinit.h -* @addtogroup v_hdmirxss * @{ * @details * diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirxss_hdcp.c b/hdmi/xilinx-hdmi-rx/xv_hdmirxss_hdcp.c index 75e1dc9..1038197 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirxss_hdcp.c +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirxss_hdcp.c @@ -507,6 +507,7 @@ static int XV_HdmiRxSs_HdcpProcessEvents(XV_HdmiRxSs *InstancePtr) #endif break; +#ifdef USE_HDCP_14_PROT_EVT_ENUM // HDCP 1.4 protocol event // Enable HDCP 1.4 case XV_HDMIRXSS_HDCP_1_PROT_EVT : @@ -518,7 +519,9 @@ static int XV_HdmiRxSs_HdcpProcessEvents(XV_HdmiRxSs *InstancePtr) } #endif break; +#endif +#ifdef USE_HDCP_22_PROT_EVT_ENUM // HDCP 2.2 protocol event // Enable HDCP 2.2 case XV_HDMIRXSS_HDCP_2_PROT_EVT : @@ -530,6 +533,7 @@ static int XV_HdmiRxSs_HdcpProcessEvents(XV_HdmiRxSs *InstancePtr) } #endif break; +#endif // DVI mode event case XV_HDMIRXSS_HDCP_DVI_MODE_EVT: @@ -560,11 +564,11 @@ static int XV_HdmiRxSs_HdcpProcessEvents(XV_HdmiRxSs *InstancePtr) // Sync est/recover event case XV_HDMIRXSS_HDCP_SYNC_EST_EVT: -#ifdef XPAR_XHDCP_NUM_INSTANCES + #ifdef XPAR_XHDCP_NUM_INSTANCES if (InstancePtr->Hdcp14Ptr) { XHdcp1x_SetHdmiMode(InstancePtr->Hdcp14Ptr, TRUE); } -#endif + #endif break; default : diff --git a/hdmi/xilinx-hdmi-rx/xv_hdmirxss_log.c b/hdmi/xilinx-hdmi-rx/xv_hdmirxss_log.c index 32c7778..17eb98f 100644 --- a/hdmi/xilinx-hdmi-rx/xv_hdmirxss_log.c +++ b/hdmi/xilinx-hdmi-rx/xv_hdmirxss_log.c @@ -27,12 +27,13 @@ * Ver Who Date Changes * ----- ---- -------- ----------------------------------------------- * 1.0 YH 17/08/16 Initial release. - * 1.01 MMO 03/01/17 Add compiler option(XV_HDMIRXSS_LOG_ENABLE) to enable Log - * + * 1.01 MMO 03/01/17 Add compiler option(XV_HDMIRXSS_LOG_ENABLE) to enable + * Log * 1.4 YH 07/07/17 Add new log type XV_HDMIRXSS_LOG_EVT_SETSTREAM_ERR * 5.0 EB 16/01/18 Added new log XV_HDMIRXSS_LOG_EVT_PIX_REPEAT_ERR * 23/01/18 Minor cleanup * MMO 05/02/18 Added new log XV_HDMIRXSS_LOG_EVT_SYNCEST + * 5.4 EB 06/08/19 Added new log XV_HDMIRXSS_LOG_EVT_VICERROR * * *******************************************************************************/ @@ -89,31 +90,31 @@ void XV_HdmiRxSs_LogWrite(XV_HdmiRxSs *InstancePtr, XV_HdmiRxSs_LogEvent Evt, u8 InstancePtr->Log.DataBuffer[InstancePtr->Log.HeadIndex] = (Data << 8) | Evt; - /* Update head pointer if reached to end of the buffer */ - if (InstancePtr->Log.HeadIndex == + /* Update head pointer if reached to end of the buffer */ + if (InstancePtr->Log.HeadIndex == (u8)((sizeof(InstancePtr->Log.DataBuffer) / sizeof(InstancePtr->Log.DataBuffer[0])) - 1)) { - /* Clear pointer */ - InstancePtr->Log.HeadIndex = 0; - } - else { - /* Increment pointer */ - InstancePtr->Log.HeadIndex++; - } + /* Clear pointer */ + InstancePtr->Log.HeadIndex = 0; + } + else { + /* Increment pointer */ + InstancePtr->Log.HeadIndex++; + } - /* Check tail pointer. When the two pointer are equal, then the buffer - * is full. In this case then increment the tail pointer as well to - * remove the oldest entry from the buffer. */ - if (InstancePtr->Log.TailIndex == InstancePtr->Log.HeadIndex) { - if (InstancePtr->Log.TailIndex == + /* Check tail pointer. When the two pointer are equal, then the buffer + * is full. In this case then increment the tail pointer as well to + * remove the oldest entry from the buffer. */ + if (InstancePtr->Log.TailIndex == InstancePtr->Log.HeadIndex) { + if (InstancePtr->Log.TailIndex == (u8)((sizeof(InstancePtr->Log.DataBuffer) / sizeof(InstancePtr->Log.DataBuffer[0])) - 1)) { - InstancePtr->Log.TailIndex = 0; - } - else { - InstancePtr->Log.TailIndex++; - } - } + InstancePtr->Log.TailIndex = 0; + } + else { + InstancePtr->Log.TailIndex++; + } + } } /*****************************************************************************/ @@ -305,6 +306,10 @@ int XV_HdmiRxSs_LogShow(XV_HdmiRxSs *InstancePtr, char *buff, int buff_size) strSize += scnprintf(buff+strSize, buff_size-strSize, "RX Sync Loss recovered\r\n"); break; + case (XV_HDMIRXSS_LOG_EVT_VICERROR): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "Vic and video timing mismatch\r\n"); + break; default: strSize += scnprintf(buff+strSize, buff_size-strSize, "Unknown event: %i\r\n", Evt); diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitx.c b/hdmi/xilinx-hdmi-tx/xv_hdmitx.c index 6358dc1..90d7514 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitx.c +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitx.c @@ -53,6 +53,15 @@ * EB 23/01/18 Updated XV_HdmiTx_SetAudioChannels to fix an issue * where setting audio channel value will unmute the * audio regardless of the current status +* 2.02 MMO 11/08/18 Added Bridge Overflow and Bridge Underflow (PIO IN) +* EB 14/08/18 Updated XV_HdmiTx_CfgInitialize to initialize +* HPD pulse periods +* 2.03 EB 28/03/19 Disable PIO Interrupt for XV_HdmiTx_DdcWrite and +* XV_HdmiTx_DdcRead APIs to prevent another DDC +* transactions from happening in the middle of a DDC +* transaction +* EB 16/07/19 Replaced sampling rate of 4 with 2 at the API +* XV_HdmiTx_SetSampleRate * * ******************************************************************************/ @@ -174,6 +183,8 @@ int XV_HdmiTx_CfgInitialize(XV_HdmiTx *InstancePtr, XV_HdmiTx_Config *CfgPtr, /* PIO: Set event rising edge masks */ XV_HdmiTx_WriteReg(InstancePtr->Config.BaseAddress, (XV_HDMITX_PIO_IN_EVT_RE_OFFSET), + (XV_HDMITX_PIO_IN_BRDG_UNDERFLOW_MASK) | + (XV_HDMITX_PIO_IN_BRDG_OVERFLOW_MASK) | (XV_HDMITX_PIO_IN_HPD_TOGGLE_MASK) | (XV_HDMITX_PIO_IN_HPD_MASK) | (XV_HDMITX_PIO_IN_VS_MASK) | @@ -188,6 +199,27 @@ int XV_HdmiTx_CfgInitialize(XV_HdmiTx *InstancePtr, XV_HdmiTx_Config *CfgPtr, (XV_HDMITX_PIO_IN_LNK_RDY_MASK) ); + /* Set the Timegrid for HPD Pulse for Connect and Toggle Event */ + XV_HdmiTx_WriteReg(InstancePtr->Config.BaseAddress, + XV_HDMITX_HPD_TIMEGRID_OFFSET, + XV_HdmiTx_GetTime1Ms(InstancePtr)); + + /* Toggle HPD Pulse (50ms - 99ms)*/ + RegValue = ((99 << XV_HDMITX_SHIFT_16) | /* 99 ms on Bit 31:16 */ + (50)); /* 50 ms on Bit 15:0 */ + + XV_HdmiTx_WriteReg(InstancePtr->Config.BaseAddress, + XV_HDMITX_TOGGLE_CONF_OFFSET, + RegValue); + + /* HPD/Connect Trigger (100ms + 0ms)*/ + RegValue = ((10 << XV_HDMITX_SHIFT_16) | /* 10 ms on Bit 31:16 */ + (100)); /* 100 ms on Bit 15:0 */ + + XV_HdmiTx_WriteReg(InstancePtr->Config.BaseAddress, + XV_HDMITX_CONNECT_CONF_OFFSET, + RegValue); + /* Enable the PIO peripheral interrupt */ XV_HdmiTx_PioIntrEnable(InstancePtr); @@ -229,8 +261,8 @@ void XV_HdmiTx_SetAxiClkFreq(XV_HdmiTx *InstancePtr, u32 ClkFreq) { InstancePtr->CpuClkFreq = ClkFreq; - /* Initialize DDC */ - XV_HdmiTx_DdcInit(InstancePtr, InstancePtr->CpuClkFreq); + /* Initialize DDC */ + XV_HdmiTx_DdcInit(InstancePtr, InstancePtr->CpuClkFreq); } /*****************************************************************************/ @@ -379,6 +411,7 @@ u32 XV_HdmiTx_GetTmdsClk (XV_HdmiTx *InstancePtr, u32 TmdsClock; /* Calculate reference clock. First calculate the pixel clock */ + /* TODO - Not same as BM code */ if (VideoMode != XVIDC_VM_CUSTOM) { TmdsClock = XVidC_GetPixelClockHzByVmId(VideoMode); } else { @@ -560,7 +593,7 @@ int XV_HdmiTx_ClockRatio(XV_HdmiTx *InstancePtr) { Status = XV_HdmiTx_DdcWrite(InstancePtr, 0x54, 2, (u8*)&DdcBuf, (TRUE)); } - return XST_SUCCESS; + return XST_SUCCESS; } return XST_FAILURE; } @@ -796,6 +829,7 @@ XVidC_3DInfo *Info3D) ******************************************************************************/ void XV_HdmiTx_INT_VRST(XV_HdmiTx *InstancePtr, u8 Reset) { + /* Verify argument. */ Xil_AssertVoid(InstancePtr != NULL); @@ -1050,6 +1084,7 @@ void XV_HdmiTx_SetPixelRate(XV_HdmiTx *InstancePtr) * * @param InstancePtr is a pointer to the XV_HdmiTx core instance. * @param SampleRate specifies the value that needs to be set. +* - 2 samples per clock * - 3 samples per clock. * - 5 samples per clock. * @@ -1076,12 +1111,12 @@ void XV_HdmiTx_SetSampleRate(XV_HdmiTx *InstancePtr, u8 SampleRate) // Check for sample rate switch (SampleRate) { - case 3: - RegValue = 1; + case 2: + RegValue = 2; break; - case 4: - RegValue = 2; + case 3: + RegValue = 1; break; case 5: @@ -1342,6 +1377,7 @@ static u32 XV_HdmiTx_DdcWriteCommand(XV_HdmiTx *InstancePtr, u32 Cmd) Status &= XV_HDMITX_DDC_STA_CMD_FULL; // Check if the command fifo isn't full + /* TODO - Not same as BM code */ if (!Status) { XV_HdmiTx_WriteReg(InstancePtr->Config.BaseAddress, (XV_HDMITX_DDC_CMD_OFFSET), (Cmd)); @@ -1400,6 +1436,7 @@ static u8 XV_HdmiTx_DdcReadData(XV_HdmiTx *InstancePtr) Status &= XV_HDMITX_DDC_STA_DAT_EMPTY; // Check if the data fifo has data + /* TODO - Not same as BM code */ if (!Status) { Data = XV_HdmiTx_ReadReg(InstancePtr->Config.BaseAddress, (XV_HDMITX_DDC_DAT_OFFSET)); @@ -1459,6 +1496,16 @@ int XV_HdmiTx_DdcWrite(XV_HdmiTx *InstancePtr, u8 Slave, Xil_AssertNonvoid(Buffer != NULL); Xil_AssertNonvoid((Stop == (TRUE)) || (Stop == (FALSE))); + /* [DIFF FROM BM] Not taking this BM logic as we disable PIO interrupts in the handler and + * enabling it when interrupt is processed. + */ +#if 0 + /* Disable PIO Interrupt to prevent another DDC transactions from happening + * in the middle of an ongoing DDC transaction + */ + XV_HdmiTx_PioIntrDisable(InstancePtr); +#endif + // Status default, assume failure Status = XST_FAILURE; @@ -1521,7 +1568,7 @@ int XV_HdmiTx_DdcWrite(XV_HdmiTx *InstancePtr, u8 Slave, // Write Data for (Index = 0; Index < Length; Index++) { Status = XV_HdmiTx_DdcWriteCommand(InstancePtr, *Buffer++); - if (Status == XST_FAILURE) return(Status); + if (Status == XST_FAILURE) return(Status); } // Wait for done flag @@ -1552,6 +1599,14 @@ int XV_HdmiTx_DdcWrite(XV_HdmiTx *InstancePtr, u8 Slave, // Disable DDC peripheral XV_HdmiTx_DdcDisable(InstancePtr); + /* [DIFF FROM BM] Not taking this BM logic as we disable PIO interrupts in the handler and + * enabling it when interrupt is processed. + */ +#if 0 + // Enable the interrupts which were disabled earlier + XV_HdmiTx_PioIntrEnable(InstancePtr); +#endif + return Status; } @@ -1589,6 +1644,16 @@ int XV_HdmiTx_DdcRead(XV_HdmiTx *InstancePtr, u8 Slave, u16 Length, Xil_AssertNonvoid(Buffer != NULL); Xil_AssertNonvoid((Stop == (TRUE)) || (Stop == (FALSE))); + /* [DIFF FROM BM] Not taking this BM logic as we disable PIO interrupts in the handler and + * enabling it when interrupt is processed. + */ +#if 0 + /* Disable PIO Interrupt to prevent another DDC transactions from happening + * in the middle of an ongoing DDC transaction + */ + XV_HdmiTx_PioIntrDisable(InstancePtr); +#endif + // Status default, assume failure Status = XST_FAILURE; @@ -1675,6 +1740,14 @@ int XV_HdmiTx_DdcRead(XV_HdmiTx *InstancePtr, u8 Slave, u16 Length, // Disable DDC peripheral XV_HdmiTx_DdcDisable(InstancePtr); + /* [DIFF FROM BM] Not taking this BM logic as we disable PIO interrupts in the handler and + * enabling it when interrupt is processed. + */ +#if 0 + // Enable the interrupts which were disabled earlier + XV_HdmiTx_PioIntrEnable(InstancePtr); +#endif + return Status; } @@ -1828,7 +1901,7 @@ int XV_HdmiTx_SetAudioChannels(XV_HdmiTx *InstancePtr, u8 Value) u8 AudioStatus; AudioStatus = XV_HdmiTx_ReadReg((InstancePtr)->Config.BaseAddress, - XV_HDMITX_AUD_CTRL_OFFSET) & XV_HDMITX_AUD_CTRL_RUN_MASK; + XV_HDMITX_AUD_CTRL_OFFSET) & XV_HDMITX_AUD_CTRL_RUN_MASK; // Stop peripheral XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitx.h b/hdmi/xilinx-hdmi-tx/xv_hdmitx.h index 8f233df..53ccb20 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitx.h +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitx.h @@ -135,6 +135,9 @@ * XV_HdmiTx_VSIF_3DSampPosToString APIs * Moved VicTable, XV_HdmiTx_Aux to Hdmi Common library * EB 24/01/18 Added OverrideHdmi14Scrambler to XV_HdmiTx_Stream +* 2.2 EB 03/08/18 Marked XV_HdmiTx_AudioMute and XV_HdmiTx_AudioUnmute +* as deprecated +* MMO 11/08/18 Added Bridge Overflow and Bridge Underflow (PIO IN) * * ******************************************************************************/ @@ -168,12 +171,14 @@ extern "C" { * interrupt requests from peripheral. */ typedef enum { - XV_HDMITX_HANDLER_CONNECT = 1, // Handler for connect - XV_HDMITX_HANDLER_TOGGLE, // Handler for toggle + XV_HDMITX_HANDLER_CONNECT = 1, // Handler for connect + XV_HDMITX_HANDLER_TOGGLE, // Handler for toggle XV_HDMITX_HANDLER_BRDGUNLOCK, // Handler for bridge unlocked - XV_HDMITX_HANDLER_VS, // Handler for vsync - XV_HDMITX_HANDLER_STREAM_DOWN, // Handler for stream down - XV_HDMITX_HANDLER_STREAM_UP // Handler for stream up + XV_HDMITX_HANDLER_BRDGOVERFLOW, // Handler for bridge overflow + XV_HDMITX_HANDLER_BRDGUNDERFLOW,// Handler for bridge underflow + XV_HDMITX_HANDLER_VS, // Handler for vsync + XV_HDMITX_HANDLER_STREAM_DOWN, // Handler for stream down + XV_HDMITX_HANDLER_STREAM_UP // Handler for stream up } XV_HdmiTx_HandlerType; /*@}*/ @@ -224,7 +229,8 @@ typedef struct { u8 IsHdmi20; /**< HDMI 2.0 flag */ u8 IsScrambled; /**< Scrambler flag 1 - scrambled data , 0 - non scrambled data */ - u8 OverrideScrambler; /**< Override scramble flag */ + u8 OverrideScrambler; /**< Override scramble + flag */ u32 TMDSClock; /**< TMDS clock */ u8 TMDSClockRatio; /**< TMDS clock ration 0 - 1/10, 1 - 1/40 */ @@ -279,13 +285,28 @@ typedef struct { u32 IsVsCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ - XV_HdmiTx_Callback BrdgUnlockedCallback; /**< Callback for Bridge UnLocked - event interrupt */ + XV_HdmiTx_Callback BrdgUnlockedCallback; /**< Callback for Bridge + *UnLocked event interrupt */ void *BrdgUnlockedRef; /**< To be passed to the Bridge Unlocked interrupt callback */ u32 IsBrdgUnlockedCallbackSet; /**< Set flag. This flag is set to true when the callback has been registered */ + XV_HdmiTx_Callback BrdgOverflowCallback; /**< Callback for Bridge + * Overflow event interrupt */ + void *BrdgOverflowRef; /**< To be passed to the Bridge + Overflow interrupt callback */ + u32 IsBrdgOverflowCallbackSet; /**< Set flag. This flag is set to + true when the callback has been registered */ + + XV_HdmiTx_Callback BrdgUnderflowCallback; /**< Callback for Bridge + * Underflow event + * interrupt */ + void *BrdgUnderflowRef; /**< To be passed to the Bridge + Underflow interrupt callback */ + u32 IsBrdgUnderflowCallbackSet; /**< Set flag. This flag is set to + true when the callback has been registered */ + XV_HdmiTx_Callback StreamDownCallback; /**< Callback for stream down callback */ void *StreamDownRef; /**< To be passed to the stream @@ -304,13 +325,28 @@ typedef struct { XHdmiC_Aux Aux; /**< AUX peripheral information */ /* HDMI TX stream */ - XV_HdmiTx_Stream Stream; /**< HDMI TX stream information */ - u32 CpuClkFreq; /* CPU Clock frequency */ + XV_HdmiTx_Stream Stream; /**< HDMI TX stream information */ + u32 CpuClkFreq; /* CPU Clock frequency */ } XV_HdmiTx; /***************** Macros (Inline Functions) Definitions *********************/ +/*****************************************************************************/ +/** +* +* This macro returns the clock cycles required to count up to 1MS with respect +* to AXI Lite Frequency +* +* @param InstancePtr is a pointer to the XV_HdmiTX core instance. +* +* @return None. +* +* +******************************************************************************/ +#define XV_HdmiTx_GetTime1Ms(InstancePtr) \ + (InstancePtr)->Config.AxiLiteClkFreq/1000 + /*****************************************************************************/ /** * @@ -435,12 +471,12 @@ typedef struct { if (SetClr) { \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ (XV_HDMITX_PIO_OUT_SET_OFFSET), \ - (XV_HDMITX_PIO_OUT_BRIDGE_PIXEL_MASK)); \ + (XV_HDMITX_PIO_OUT_BRIDGE_PIXEL_MASK)); \ } \ else { \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ (XV_HDMITX_PIO_OUT_CLR_OFFSET), \ - (XV_HDMITX_PIO_OUT_BRIDGE_PIXEL_MASK)); \ + (XV_HDMITX_PIO_OUT_BRIDGE_PIXEL_MASK)); \ } \ } @@ -734,12 +770,16 @@ typedef struct { * @return None. * * @note C-style signature: -* void XV_HdmiTx_AudioEnable(XV_HdmiTx *InstancePtr) +* void XV_HdmiTx_AudioUnmute(XV_HdmiTx *InstancePtr) +* +* @deprecated XV_HdmiTx_AudioUnmute will be deprecated in 2019.3 and replaced +* by XV_HdmiTx_AudioEnable. * ******************************************************************************/ #define XV_HdmiTx_AudioUnmute(InstancePtr) \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ - (XV_HDMITX_AUD_CTRL_SET_OFFSET), (XV_HDMITX_AUD_CTRL_RUN_MASK)) + (XV_HDMITX_AUD_CTRL_SET_OFFSET), (XV_HDMITX_AUD_CTRL_RUN_MASK)) \ + _Pragma ("GCC warning \"'XV_HdmiTx_AudioUnmute' macro is deprecated\"") /*****************************************************************************/ /** @@ -751,12 +791,16 @@ typedef struct { * @return None. * * @note C-style signature: -* void XV_HdmiTx_AudioDisable(XV_HdmiTx *InstancePtr) +* void XV_HdmiTx_AudioMute(XV_HdmiTx *InstancePtr) +* +* @deprecated XV_HdmiTx_AudioMute will be deprecated in 2019.3 and replaced +* by XV_HdmiTx_AudioDisable. * ******************************************************************************/ #define XV_HdmiTx_AudioMute(InstancePtr) \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ - (XV_HDMITX_AUD_CTRL_CLR_OFFSET), (XV_HDMITX_AUD_CTRL_RUN_MASK)) + (XV_HDMITX_AUD_CTRL_CLR_OFFSET), (XV_HDMITX_AUD_CTRL_RUN_MASK)) \ + _Pragma ("GCC warning \"'XV_HdmiTx_AudioMute' macro is deprecated\"") /*****************************************************************************/ /** @@ -821,7 +865,7 @@ typedef struct { * @return Sample rate * * @note C-style signature: -* u8 XV_HdmiTx_GetMode(XV_HdmiTx *InstancePtr) +* u8 XV_HdmiTx_GetSampleRate(XV_HdmiTx *InstancePtr) * ******************************************************************************/ #define XV_HdmiTx_GetSampleRate(InstancePtr) \ @@ -915,12 +959,12 @@ typedef struct { if (SetClr) { \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ (XV_HDMITX_MASK_CTRL_SET_OFFSET), \ - (XV_HDMITX_MASK_CTRL_NOISE_MASK)); \ + (XV_HDMITX_MASK_CTRL_NOISE_MASK)); \ } \ else { \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ (XV_HDMITX_MASK_CTRL_CLR_OFFSET), \ - (XV_HDMITX_MASK_CTRL_NOISE_MASK)); \ + (XV_HDMITX_MASK_CTRL_NOISE_MASK)); \ } \ } @@ -942,7 +986,7 @@ typedef struct { { \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ (XV_HDMITX_MASK_RED_OFFSET), \ - (Value)); \ + (Value)); \ } /*****************************************************************************/ @@ -963,7 +1007,7 @@ typedef struct { { \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ (XV_HDMITX_MASK_GREEN_OFFSET), \ - (Value)); \ + (Value)); \ } /*****************************************************************************/ @@ -984,7 +1028,7 @@ typedef struct { { \ XV_HdmiTx_WriteReg((InstancePtr)->Config.BaseAddress, \ (XV_HDMITX_MASK_BLUE_OFFSET), \ - (Value)); \ + (Value)); \ } /*****************************************************************************/ @@ -1066,9 +1110,13 @@ int XV_HdmiTx_SelfTest(XV_HdmiTx *InstancePtr); /* Interrupt related functions in xv_hdmitx_intr.c */ void XV_HdmiTx_IntrHandler(void *InstancePtr); -int XV_HdmiTx_SetCallback(XV_HdmiTx *InstancePtr, u32 HandlerType, - void *CallbackFunc, void *CallbackRef); +int XV_HdmiTx_SetCallback(XV_HdmiTx *InstancePtr, + XV_HdmiTx_HandlerType HandlerType, + void *CallbackFunc, + void *CallbackRef); + +/* [Linux] Not supporting vendor specific APIs */ /************************** Variable Declarations ****************************/ /************************** Variable Declarations ****************************/ diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitx_hw.h b/hdmi/xilinx-hdmi-tx/xv_hdmitx_hw.h index 45a164e..a0b191f 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitx_hw.h +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitx_hw.h @@ -36,13 +36,17 @@ * 1.02 YH 14/11/16 Added BRIDGE_YUV420 and BRIDGE_PIXEL mask to PIO Out * 1.03 MG 06/03/17 Added XV_HDMITX_AUX_STA_PKT_RDY_MASK * 1.04 MMO 03/05/17 Updated the comments for XV_HdmiTx_ReadReg and -* XV_HdmiTx_WriteReg +* XV_HdmiTx_WriteReg * 1.1 MG 03/05/17 Introduced video mask peripheral * 1.2 YH 22/08/17 Added XV_HDMITX_AUD_CTRL_AUDFMT_MASK (Audio Format) * 1.3 YH 06/10/17 Added XV_HDMITX_AUD_CTRL_AUDFMT_SHIFT (Audio Format) * 1.4 YH 16/01/18 Added PIO_OUT for dedicated reset for each clock domain * Added PIO_IN to bridge unlock interrupt * Added PIO_OUT to set GCP_AVMUTE +* 1.5 MMO 11/08/18 Added PIO_IN to bridge overflow and underflow interrupt +* EB 14/08/18 Added XV_HDMITX_HPD_TIMEGRID_OFFSET, +* XV_HDMITX_TOGGLE_CONF_OFFSET and +* XV_HDMITX_CONNECT_CONF_OFFSET * * ******************************************************************************/ @@ -94,9 +98,17 @@ extern "C" { #define XV_HDMITX_PIO_IN_EVT_OFFSET ((XV_HDMITX_PIO_BASE)+(10*4))/**< PIO * In Event Register * offset */ #define XV_HDMITX_PIO_IN_EVT_RE_OFFSET ((XV_HDMITX_PIO_BASE)+(11*4))/**< PIO - * In Event Rising Edge * Register offset */ + * In Event Rising Edge + * Register offset */ #define XV_HDMITX_PIO_IN_EVT_FE_OFFSET ((XV_HDMITX_PIO_BASE)+(12*4))/**< PIO - * In Event Falling Edge * Register offset */ + * In Event Falling Edge + * Register offset */ +#define XV_HDMITX_HPD_TIMEGRID_OFFSET ((XV_HDMITX_PIO_BASE)+(13*4))/**< PIO + * HPD Config. * offset */ +#define XV_HDMITX_TOGGLE_CONF_OFFSET ((XV_HDMITX_PIO_BASE)+(14*4))/**< PIO + * HPD Config. * Register offset */ +#define XV_HDMITX_CONNECT_CONF_OFFSET ((XV_HDMITX_PIO_BASE)+(15*4))/**< PIO + * HPD Config. * Register offset */ // PIO peripheral Control register masks #define XV_HDMITX_PIO_CTRL_RUN_MASK (1<<0) /**< PIO Control Run mask */ @@ -129,7 +141,7 @@ extern "C" { #define XV_HDMITX_PIO_OUT_COLOR_SPACE_SHIFT 10 /**< PIO Out Color Space * shift */ #define XV_HDMITX_PIO_OUT_GCP_CLEARAVMUTE_MASK (1<<28) /**< PIO Out - * GCP_CLEARAVMUTE mask */ + * GCP_CLEARAVMUTE mask */ #define XV_HDMITX_PIO_OUT_BRIDGE_YUV420_MASK (1<<29) /**< PIO Out Bridge_YUV420 * mask */ #define XV_HDMITX_PIO_OUT_BRIDGE_PIXEL_MASK (1<<30) /**< PIO Out Bridge_Pixel @@ -155,11 +167,16 @@ extern "C" { #define XV_HDMITX_PIO_IN_VS_MASK (1<<3) /**< PIO In Vsync mask */ #define XV_HDMITX_PIO_IN_PPP_MASK 0x07 /**< PIO In Pixel packing * phase mask */ -#define XV_HDMITX_PIO_IN_HPD_TOGGLE_MASK (1<<8) /**< PIO In HPD toggle mask */ +#define XV_HDMITX_PIO_IN_HPD_TOGGLE_MASK (1<<8) /**< PIO In HPD toggle + * mask */ #define XV_HDMITX_PIO_IN_PPP_SHIFT 5 /**< PIO In Pixel packing * phase shift */ #define XV_HDMITX_PIO_IN_BRDG_LOCKED_MASK (1<<9) /**< PIO In Bridge Locked * mask */ +#define XV_HDMITX_PIO_IN_BRDG_OVERFLOW_MASK (1<<10) /**< PIO In Bridge Overflow + * mask */ +#define XV_HDMITX_PIO_IN_BRDG_UNDERFLOW_MASK (1<<11) /**< PIO In Bridge + * Underflow mask */ /**< DDC (Display Data Channel) peripheral register offsets */ /**< The DDC is the second peripheral on the local bus */ diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitx_intr.c b/hdmi/xilinx-hdmi-tx/xv_hdmitx_intr.c index 5918410..d5a7cbf 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitx_intr.c +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitx_intr.c @@ -29,6 +29,7 @@ * 1.00 10/07/15 Initial release. * 1.1 YH 18/08/16 squash unused variable compiler warning * 1.2 YH 16/01/18 Added bridge unlock interrupt +* 1.3 MMO 11/08/18 Added bridge overflow and underflow interrupt * * ******************************************************************************/ @@ -47,7 +48,7 @@ /************************** Function Prototypes ******************************/ - +/* [Linux] Cannot make static as it is being called from TX driver wrapper code */ void HdmiTx_PioIntrHandler(XV_HdmiTx *InstancePtr); void HdmiTx_DdcIntrHandler(XV_HdmiTx *InstancePtr); @@ -139,9 +140,9 @@ void XV_HdmiTx_IntrHandler(void *InstancePtr) * ******************************************************************************/ int XV_HdmiTx_SetCallback(XV_HdmiTx *InstancePtr, - u32 HandlerType, - void *CallbackFunc, - void *CallbackRef) + XV_HdmiTx_HandlerType HandlerType, + void *CallbackFunc, + void *CallbackRef) { u32 Status; @@ -174,6 +175,20 @@ int XV_HdmiTx_SetCallback(XV_HdmiTx *InstancePtr, Status = (XST_SUCCESS); break; + case (XV_HDMITX_HANDLER_BRDGOVERFLOW): + InstancePtr->BrdgOverflowCallback = (XV_HdmiTx_Callback)CallbackFunc; + InstancePtr->BrdgOverflowRef = CallbackRef; + InstancePtr->IsBrdgOverflowCallbackSet = (TRUE); + Status = (XST_SUCCESS); + break; + + case (XV_HDMITX_HANDLER_BRDGUNDERFLOW): + InstancePtr->BrdgUnderflowCallback = (XV_HdmiTx_Callback)CallbackFunc; + InstancePtr->BrdgUnderflowRef = CallbackRef; + InstancePtr->IsBrdgUnderflowCallbackSet = (TRUE); + Status = (XST_SUCCESS); + break; + case (XV_HDMITX_HANDLER_VS): InstancePtr->VsCallback = (XV_HdmiTx_Callback)CallbackFunc; InstancePtr->VsRef = CallbackRef; @@ -272,6 +287,24 @@ void HdmiTx_PioIntrHandler(XV_HdmiTx *InstancePtr) } } + /* Bridge Overflow event has occurred */ + if ((Event) & (XV_HDMITX_PIO_IN_BRDG_OVERFLOW_MASK)) { + + // Check if user callback has been registered + if (InstancePtr->IsBrdgOverflowCallbackSet) { + InstancePtr->BrdgOverflowCallback(InstancePtr->BrdgOverflowRef); + } + } + + /* Bridge Underflow event has occurred */ + if ((Event) & (XV_HDMITX_PIO_IN_BRDG_UNDERFLOW_MASK)) { + + // Check if user callback has been registered + if (InstancePtr->IsBrdgUnderflowCallbackSet) { + InstancePtr->BrdgUnderflowCallback(InstancePtr->BrdgUnderflowRef); + } + } + /* Vsync event has occurred */ if ((Event) & (XV_HDMITX_PIO_IN_VS_MASK)) { diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitxss.c b/hdmi/xilinx-hdmi-tx/xv_hdmitxss.c index 602b085..2d57fc6 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitxss.c +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitxss.c @@ -128,8 +128,17 @@ * XV_HdmiTxSs_SetVideoStreamHdmi14ScramblingOverrideFlag * 25/01/18 Added function XV_HdmiTxSs_SetScrambler * 01/02/18 Updated function XV_HdmiTxSs_VtcSetup and changed the -* input parameters to it to enable logging of -* unsupported video timing by VTC +* input parameters to it to enable logging of +* unsupported video timing by VTC +* SM 28/02/18 Added definition of XV_HdmiTxSS_SetAppVersion() API +* 5.20 EB 03/08/18 Updated XV_HdmiTxSS_MaskSetRed, XV_HdmiTxSS_MaskSetGreen, +* XV_HdmiTxSS_MaskSetBlue API +* Replaced XV_HdmiTx_AudioMute API call with +* XV_HdmiTx_AudioDisable +* Replaced XV_HdmiTx_AudioUnmute API call with +* XV_HdmiTx_AudioEnable +* Replaced XV_HdmiTx_AudioUnmute API call with +* MMO 11/08/18 Added Bridge Overflow and Bridge Underflow Interrupt * * ******************************************************************************/ @@ -196,9 +205,13 @@ static u32 XV_HdmiTxSS_SetTMDS(XV_HdmiTxSs *InstancePtr, static void XV_HdmiTxSs_ConnectCallback(void *CallbackRef); static void XV_HdmiTxSs_ToggleCallback(void *CallbackRef); static void XV_HdmiTxSs_BrdgUnlockedCallback(void *CallbackRef); +static void XV_HdmiTxSs_BrdgOverflowCallback(void *CallbackRef); +static void XV_HdmiTxSs_BrdgUnderflowCallback(void *CallbackRef); static void XV_HdmiTxSs_VsCallback(void *CallbackRef); static void XV_HdmiTxSs_StreamUpCallback(void *CallbackRef); static void XV_HdmiTxSs_StreamDownCallback(void *CallbackRef); +static u32 XV_HdmiTxSS_GetVidMaskColorValue(XV_HdmiTxSs *InstancePtr, + u16 Value); static void XV_HdmiTxSs_ReportCoreInfo(XV_HdmiTxSs *InstancePtr); static void XV_HdmiTxSs_ReportTiming(XV_HdmiTxSs *InstancePtr); @@ -354,6 +367,16 @@ static int XV_HdmiTxSs_RegisterSubsysCallbacks(XV_HdmiTxSs *InstancePtr) (void *)XV_HdmiTxSs_BrdgUnlockedCallback, (void *)InstancePtr); + XV_HdmiTx_SetCallback(HdmiTxSsPtr->HdmiTxPtr, + XV_HDMITX_HANDLER_BRDGOVERFLOW, + (void *)XV_HdmiTxSs_BrdgOverflowCallback, + (void *)InstancePtr); + + XV_HdmiTx_SetCallback(HdmiTxSsPtr->HdmiTxPtr, + XV_HDMITX_HANDLER_BRDGUNDERFLOW, + (void *)XV_HdmiTxSs_BrdgUnderflowCallback, + (void *)InstancePtr); + XV_HdmiTx_SetCallback(HdmiTxSsPtr->HdmiTxPtr, XV_HDMITX_HANDLER_VS, (void *)XV_HdmiTxSs_VsCallback, @@ -849,9 +872,9 @@ static int XV_HdmiTxSs_VtcSetup(XV_HdmiTxSs *HdmiTxSsPtr) /* 4 pixels per clock */ if (HdmiTxSsPtr->HdmiTxPtr->Stream.Video.PixPerClk == XVIDC_PPC_4) { - /* If the parameters below are not divisible by the current PPC setting, - * log an error as VTC does not support such video timing - */ + /* If the parameters below are not divisible by the current PPC setting, + * log an error as VTC does not support such video timing + */ if (VideoTiming.HActiveVideo & 0x3 || VideoTiming.HFrontPorch & 0x3 || VideoTiming.HBackPorch & 0x3 || VideoTiming.HSyncWidth & 0x3) { #ifdef XV_HDMITXSS_LOG_ENABLE @@ -867,9 +890,9 @@ static int XV_HdmiTxSs_VtcSetup(XV_HdmiTxSs *HdmiTxSsPtr) /* 2 pixels per clock */ else if (HdmiTxSsPtr->HdmiTxPtr->Stream.Video.PixPerClk == XVIDC_PPC_2) { - /* If the parameters below are not divisible by the current PPC setting, - * log an error as VTC does not support such video timing - */ + /* If the parameters below are not divisible by the current PPC setting, + * log an error as VTC does not support such video timing + */ if (VideoTiming.HActiveVideo & 0x1 || VideoTiming.HFrontPorch & 0x1 || VideoTiming.HBackPorch & 0x1 || VideoTiming.HSyncWidth & 0x1) { #ifdef XV_HDMITXSS_LOG_ENABLE @@ -893,9 +916,9 @@ static int XV_HdmiTxSs_VtcSetup(XV_HdmiTxSs *HdmiTxSsPtr) /* For YUV420 the line width is double there for double the blanking */ if (HdmiTxSsPtr->HdmiTxPtr->Stream.Video.ColorFormatId == XVIDC_CSF_YCRCB_420) { - /* If the parameters below are not divisible by the current PPC setting, - * log an error as VTC does not support such video timing - */ + /* If the parameters below are not divisible by the current PPC setting, + * log an error as VTC does not support such video timing + */ if (VideoTiming.HActiveVideo & 0x1 || VideoTiming.HFrontPorch & 0x1 || VideoTiming.HBackPorch & 0x1 || VideoTiming.HSyncWidth & 0x1) { #ifdef XV_HDMITXSS_LOG_ENABLE @@ -1024,6 +1047,7 @@ static u32 XV_HdmiTxSS_SetTMDS(XV_HdmiTxSs *InstancePtr, XVidC_VideoMode VideoMode, XVidC_ColorFormat ColorFormat, XVidC_ColorDepth Bpc) { + u32 TmdsClk; TmdsClk = XV_HdmiTx_GetTmdsClk(InstancePtr->HdmiTxPtr, @@ -1151,12 +1175,61 @@ static void XV_HdmiTxSs_BrdgUnlockedCallback(void *CallbackRef) { XV_HdmiTxSs *HdmiTxSsPtr = (XV_HdmiTxSs *)CallbackRef; +#ifdef XV_HDMITXSS_LOG_ENABLE + XV_HdmiTxSs_LogWrite(HdmiTxSsPtr, XV_HDMITXSS_LOG_EVT_BRDG_UNLOCKED, 0); +#endif + /* Check if user callback has been registered */ if (HdmiTxSsPtr->BrdgUnlockedCallback) { HdmiTxSsPtr->BrdgUnlockedCallback(HdmiTxSsPtr->BrdgUnlockedRef); } } +/*****************************************************************************/ +/** +* +* This function is called when a bridge Overflow has occurred. +* +* @param None. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void XV_HdmiTxSs_BrdgOverflowCallback(void *CallbackRef) +{ + XV_HdmiTxSs *HdmiTxSsPtr = (XV_HdmiTxSs *)CallbackRef; + + /* Check if user callback has been registered */ + if (HdmiTxSsPtr->BrdgOverflowCallback) { + HdmiTxSsPtr->BrdgOverflowCallback(HdmiTxSsPtr->BrdgOverflowRef); + } +} + + +/*****************************************************************************/ +/** +* +* This function is called when a bridge Underflow has occurred. +* +* @param None. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void XV_HdmiTxSs_BrdgUnderflowCallback(void *CallbackRef) +{ + XV_HdmiTxSs *HdmiTxSsPtr = (XV_HdmiTxSs *)CallbackRef; + + /* Check if user callback has been registered */ + if (HdmiTxSsPtr->BrdgUnderflowCallback) { + HdmiTxSsPtr->BrdgUnderflowCallback(HdmiTxSsPtr->BrdgUnderflowRef); + } +} + /*****************************************************************************/ /** * @@ -1175,7 +1248,7 @@ static void XV_HdmiTxSs_VsCallback(void *CallbackRef) // Check if user callback has been registered if (HdmiTxSsPtr->VsCallback) { - HdmiTxSsPtr->VsCallback(HdmiTxSsPtr->VsRef); + HdmiTxSsPtr->VsCallback(HdmiTxSsPtr->VsRef); } } @@ -1229,7 +1302,7 @@ static void XV_HdmiTxSs_StreamUpCallback(void *CallbackRef) if (HdmiTxSsPtr->AudioEnabled) { /* HDMI TX unmute audio */ HdmiTxSsPtr->AudioMute = (FALSE); - XV_HdmiTx_AudioUnmute(HdmiTxSsPtr->HdmiTxPtr); + XV_HdmiTx_AudioEnable(HdmiTxSsPtr->HdmiTxPtr); } /* Configure video bridge mode according to HW setting and video format */ @@ -1254,7 +1327,6 @@ static void XV_HdmiTxSs_StreamUpCallback(void *CallbackRef) static void XV_HdmiTxSs_StreamDownCallback(void *CallbackRef) { XV_HdmiTxSs *HdmiTxSsPtr = (XV_HdmiTxSs *)CallbackRef; - /* Assert HDMI TXCore link reset */ XV_HdmiTxSs_TXCore_LRST(HdmiTxSsPtr, TRUE); XV_HdmiTxSs_TXCore_VRST(HdmiTxSsPtr, TRUE); @@ -1295,6 +1367,8 @@ static void XV_HdmiTxSs_StreamDownCallback(void *CallbackRef) * (XV_HDMITXSS_HANDLER_VS) VsCallback * (XV_HDMITXSS_HANDLER_STREAM_DOWN) StreamDownCallback * (XV_HDMITXSS_HANDLER_STREAM_UP) StreamUpCallback +* (XV_HDMITXSS_HANDLER_BRDGOVERFLOW) BrdgOverflowCallback +* (XV_HDMITXSS_HANDLER_BRDGUNDERFLOW) BrdgUnderflowCallback * (XV_HDMITXSS_HANDLER_HDCP_AUTHENTICATED) * (XV_HDMITXSS_HANDLER_HDCP_DOWNSTREAM_TOPOLOGY_AVAILABLE) * (XV_HDMITXSS_HANDLER_HDCP_UNAUTHENTICATED) @@ -1315,9 +1389,9 @@ static void XV_HdmiTxSs_StreamDownCallback(void *CallbackRef) * ******************************************************************************/ int XV_HdmiTxSs_SetCallback(XV_HdmiTxSs *InstancePtr, - u32 HandlerType, - void *CallbackFunc, - void *CallbackRef) + XV_HdmiTxSs_HandlerType HandlerType, + void *CallbackFunc, + void *CallbackRef) { u32 Status; @@ -1345,11 +1419,28 @@ int XV_HdmiTxSs_SetCallback(XV_HdmiTxSs *InstancePtr, // Bridge Unlocked case (XV_HDMITXSS_HANDLER_BRDGUNLOCK): - InstancePtr->BrdgUnlockedCallback = (XV_HdmiTxSs_Callback)CallbackFunc; + InstancePtr->BrdgUnlockedCallback = + (XV_HdmiTxSs_Callback)CallbackFunc; InstancePtr->BrdgUnlockedRef = CallbackRef; Status = (XST_SUCCESS); break; + // Bridge Overflow + case (XV_HDMITXSS_HANDLER_BRDGOVERFLOW): + InstancePtr->BrdgOverflowCallback = + (XV_HdmiTxSs_Callback)CallbackFunc; + InstancePtr->BrdgOverflowRef = CallbackRef; + Status = (XST_SUCCESS); + break; + + // Bridge Underflow + case (XV_HDMITXSS_HANDLER_BRDGUNDERFLOW): + InstancePtr->BrdgUnderflowCallback = + (XV_HdmiTxSs_Callback)CallbackFunc; + InstancePtr->BrdgUnderflowRef = CallbackRef; + Status = (XST_SUCCESS); + break; + // Vsync case (XV_HDMITXSS_HANDLER_VS): InstancePtr->VsCallback = (XV_HdmiTxSs_Callback)CallbackFunc; @@ -1595,7 +1686,7 @@ void XV_HdmiTxSs_StreamStart(XV_HdmiTxSs *InstancePtr) XV_HdmiTxSs_LogWrite(InstancePtr, XV_HDMITXSS_LOG_EVT_STREAMSTART, 0); #endif if ((InstancePtr->HdmiTxPtr->Stream.IsHdmi20 == (FALSE)) - && (TmdsClk > 340000000)) { + && (TmdsClk > 340000000)) { xdbg_printf(XDBG_DEBUG_GENERAL, "\r\nWarning: Sink does not support HDMI 2.0\r\n"); xdbg_printf(XDBG_DEBUG_GENERAL, @@ -1783,7 +1874,7 @@ void XV_HdmiTxSs_SetAudioChannels(XV_HdmiTxSs *InstancePtr, u8 AudioChannels) * * This function set HDMI TX audio parameters * -* @param None. +* @param Enable 0: Unmute the audio 1: Mute the audio. * * @return None. * @@ -1794,13 +1885,13 @@ void XV_HdmiTxSs_AudioMute(XV_HdmiTxSs *InstancePtr, u8 Enable) { //Audio Mute Mode if (Enable){ - XV_HdmiTx_AudioMute(InstancePtr->HdmiTxPtr); + XV_HdmiTx_AudioDisable(InstancePtr->HdmiTxPtr); #ifdef XV_HDMITXSS_LOG_ENABLE XV_HdmiTxSs_LogWrite(InstancePtr, XV_HDMITXSS_LOG_EVT_AUDIOMUTE, 0); #endif } else{ - XV_HdmiTx_AudioUnmute(InstancePtr->HdmiTxPtr); + XV_HdmiTx_AudioEnable(InstancePtr->HdmiTxPtr); #ifdef XV_HDMITXSS_LOG_ENABLE XV_HdmiTxSs_LogWrite(InstancePtr, XV_HDMITXSS_LOG_EVT_AUDIOUNMUTE, 0); #endif @@ -1942,7 +2033,7 @@ u32 XV_HdmiTxSs_SetStream(XV_HdmiTxSs *InstancePtr, #endif if(TmdsClock == 0) { xdbg_printf(XDBG_DEBUG_GENERAL, - "\nWarning: Sink does not support HDMI 2.0\r\n"); + "\r\nWarning: Sink does not support HDMI 2.0\r\n"); xdbg_printf(XDBG_DEBUG_GENERAL, " Connect to HDMI 2.0 Sink or \r\n"); xdbg_printf(XDBG_DEBUG_GENERAL, @@ -2042,11 +2133,11 @@ void XV_HdmiTxSs_SetVideoStreamType(XV_HdmiTxSs *InstancePtr, u8 StreamType) { //InstancePtr->HdmiTxPtr->Stream.IsHdmi = StreamType; if (StreamType) { - XV_HdmiTxSS_SetHdmiMode(InstancePtr); - XV_HdmiTxSs_AudioMute(InstancePtr, FALSE); + XV_HdmiTxSS_SetHdmiMode(InstancePtr); + XV_HdmiTxSs_AudioMute(InstancePtr, FALSE); } else { - XV_HdmiTxSs_AudioMute(InstancePtr, TRUE); - XV_HdmiTxSS_SetDviMode(InstancePtr); + XV_HdmiTxSs_AudioMute(InstancePtr, TRUE); + XV_HdmiTxSS_SetDviMode(InstancePtr); } } @@ -2164,16 +2255,17 @@ int XV_HdmiTxSs_DetectHdmi20(XV_HdmiTxSs *InstancePtr) ******************************************************************************/ void XV_HdmiTxSs_RefClockChangeInit(XV_HdmiTxSs *InstancePtr) { - /* Assert VID_IN bridge resets */ - XV_HdmiTxSs_SYSRST(InstancePtr, TRUE); - XV_HdmiTxSs_VRST(InstancePtr, TRUE); - /* Assert HDMI TXCore resets */ - XV_HdmiTxSs_TXCore_LRST(InstancePtr, TRUE); - XV_HdmiTxSs_TXCore_VRST(InstancePtr, TRUE); + /* Assert VID_IN bridge resets */ + XV_HdmiTxSs_SYSRST(InstancePtr, TRUE); + XV_HdmiTxSs_VRST(InstancePtr, TRUE); + + /* Assert HDMI TXCore resets */ + XV_HdmiTxSs_TXCore_LRST(InstancePtr, TRUE); + XV_HdmiTxSs_TXCore_VRST(InstancePtr, TRUE); - /* Clear variables */ - XV_HdmiTx_Clear(InstancePtr->HdmiTxPtr); + /* Clear variables */ + XV_HdmiTx_Clear(InstancePtr->HdmiTxPtr); } /*****************************************************************************/ @@ -2409,10 +2501,10 @@ static void XV_HdmiTxSs_ConfigBridgeMode(XV_HdmiTxSs *InstancePtr) { // Pixel Repetition factor of 3 and above are not supported by the bridge if (AviInfoFramePtr->PixelRepetition > XHDMIC_PIXEL_REPETITION_FACTOR_2) { #ifdef XV_HDMITXSS_LOG_ENABLE - XV_HdmiTxSs_LogWrite(InstancePtr, XV_HDMITXSS_LOG_EVT_PIX_REPEAT_ERR, - AviInfoFramePtr->PixelRepetition); + XV_HdmiTxSs_LogWrite(InstancePtr, XV_HDMITXSS_LOG_EVT_PIX_REPEAT_ERR, + AviInfoFramePtr->PixelRepetition); #endif - return; + return; } if (HdmiTxSsVidStreamPtr->ColorFormatId == XVIDC_CSF_YCRCB_420) { @@ -2451,10 +2543,11 @@ static void XV_HdmiTxSs_ConfigBridgeMode(XV_HdmiTxSs *InstancePtr) { * * @return None. * -* @note None. +* @note Linux - No need to put definition inside. * ******************************************************************************/ void XV_HdmiTxSs_SetDefaultPpc(XV_HdmiTxSs *InstancePtr, u8 Id) { + } /*****************************************************************************/ @@ -2525,6 +2618,19 @@ void XV_HdmiTxSS_MaskNoise(XV_HdmiTxSs *InstancePtr, u8 Enable) XV_HdmiTx_MaskNoise(InstancePtr->HdmiTxPtr, Enable); } +static u32 XV_HdmiTxSS_GetVidMaskColorValue(XV_HdmiTxSs *InstancePtr, + u16 Value) +{ + u32 Data; + s8 Temp; + + Temp = InstancePtr->Config.MaxBitsPerPixel - + InstancePtr->HdmiTxPtr->Stream.Video.ColorDepth; + Data = Value << ((Temp > 0) ? Temp : 0); + + return Data; +} + /*****************************************************************************/ /** * This function will set the red component in the video mask. @@ -2541,30 +2647,7 @@ void XV_HdmiTxSS_MaskSetRed(XV_HdmiTxSs *InstancePtr, u16 Value) { u32 Data; - switch (InstancePtr->HdmiTxPtr->Stream.Video.ColorDepth) { - - // 10 bpc - case XVIDC_BPC_10: - // Color depth - Data = (Value << 6); - break; - - // 12 bpc - case XVIDC_BPC_12: - // Color depth - Data = (Value << 4); - break; - - // 16 bpc - case XVIDC_BPC_16: - // Color depth - Data = Value; - break; - - default : - Data = (Value << 8); - break; - } + Data = XV_HdmiTxSS_GetVidMaskColorValue(InstancePtr, Value); XV_HdmiTx_MaskSetRed(InstancePtr->HdmiTxPtr, (Data)); } @@ -2586,30 +2669,7 @@ void XV_HdmiTxSS_MaskSetGreen(XV_HdmiTxSs *InstancePtr, u16 Value) { u32 Data; - switch (InstancePtr->HdmiTxPtr->Stream.Video.ColorDepth) { - - // 10 bpc - case XVIDC_BPC_10: - // Color depth - Data = (Value << 6); - break; - - // 12 bpc - case XVIDC_BPC_12: - // Color depth - Data = (Value << 4); - break; - - // 16 bpc - case XVIDC_BPC_16: - // Color depth - Data = Value; - break; - - default : - Data = (Value << 8); - break; - } + Data = XV_HdmiTxSS_GetVidMaskColorValue(InstancePtr, Value); XV_HdmiTx_MaskSetGreen(InstancePtr->HdmiTxPtr, (Data)); } @@ -2630,30 +2690,7 @@ void XV_HdmiTxSS_MaskSetBlue(XV_HdmiTxSs *InstancePtr, u16 Value) { u32 Data; - switch (InstancePtr->HdmiTxPtr->Stream.Video.ColorDepth) { - - // 10 bpc - case XVIDC_BPC_10: - // Color depth - Data = (Value << 6); - break; - - // 12 bpc - case XVIDC_BPC_12: - // Color depth - Data = (Value << 4); - break; - - // 16 bpc - case XVIDC_BPC_16: - // Color depth - Data = Value; - break; - - default : - Data = (Value << 8); - break; - } + Data = XV_HdmiTxSS_GetVidMaskColorValue(InstancePtr, Value); XV_HdmiTx_MaskSetBlue(InstancePtr->HdmiTxPtr, (Data)); } diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitxss.h b/hdmi/xilinx-hdmi-tx/xv_hdmitxss.h index 57d4e27..fb6d41c 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitxss.h +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitxss.h @@ -86,6 +86,9 @@ * 25/01/18 Added function XV_HdmiTxSs_SetScrambler * mmo 08/02/18 Added LowResolutionSupp & YUV420Supp in the * XV_HdmiTxSs_Config +* SM 28/02/18 Added XV_HdmiTxSS_SetAppVersion API and AppMajVer and +* AppMinVer version number in XV_HdmiTxSs structure +* MMO 11/08/18 Added Bridge Overflow and Bridge Underflow Interrupt * * ******************************************************************************/ @@ -129,6 +132,10 @@ extern "C" { /****************************** Type Definitions ******************************/ +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_RESET "\x1b[0m" + /** * This typedef contains the different background colors available */ @@ -175,6 +182,7 @@ typedef enum { Repetition. */ XV_HDMITXSS_LOG_EVT_VTC_RES_ERR, /**< Log event Resolution Unsupported by VTC. */ + XV_HDMITXSS_LOG_EVT_BRDG_UNLOCKED, /**< VID-OUT bridge unlocked. */ XV_HDMITXSS_LOG_EVT_DUMMY /**< Dummy Event should be last */ } XV_HdmiTxSs_LogEvent; @@ -182,11 +190,11 @@ typedef enum { * This typedef contains the logging mechanism for debug. */ typedef struct { - u16 DataBuffer[256]; /**< Log buffer with event data. */ - u8 HeadIndex; /**< Index of the head entry of the - Event/DataBuffer. */ - u8 TailIndex; /**< Index of the tail entry of the - Event/DataBuffer. */ + u16 DataBuffer[256]; /**< Log buffer with event data. */ + u8 HeadIndex; /**< Index of the head entry of the + Event/DataBuffer. */ + u8 TailIndex; /**< Index of the tail entry of the + Event/DataBuffer. */ } XV_HdmiTxSs_Log; #endif @@ -267,6 +275,12 @@ typedef enum { XV_HDMITXSS_HANDLER_BRDGUNLOCK, /**< Handler for bridge unlocked event */ + XV_HDMITXSS_HANDLER_BRDGOVERFLOW, /**< Handler for + bridge overflow + event */ + XV_HDMITXSS_HANDLER_BRDGUNDERFLOW, /**< Handler for + bridge underflow + event */ XV_HDMITXSS_HANDLER_VS, /**< Handler for vsync event */ XV_HDMITXSS_HANDLER_STREAM_DOWN, /**< Handler for @@ -370,11 +384,21 @@ typedef struct void *ToggleRef; /**< To be passed to the toggle callback */ - XV_HdmiTxSs_Callback BrdgUnlockedCallback; /**< Callback for Bridge UnLocked - event interrupt */ + XV_HdmiTxSs_Callback BrdgUnlockedCallback; /**< Callback for Bridge + * UnLocked event interrupt */ void *BrdgUnlockedRef; /**< To be passed to the Bridge Unlocked interrupt callback */ + XV_HdmiTxSs_Callback BrdgOverflowCallback; /**< Callback for Bridge + * Overflow event interrupt */ + void *BrdgOverflowRef; /**< To be passed to the Bridge + Overflow interrupt callback */ + + XV_HdmiTxSs_Callback BrdgUnderflowCallback; /**< Callback for Bridge + * Underflow event interrupt */ + void *BrdgUnderflowRef; /**< To be passed to the Bridge + Underflow interrupt callback */ + XV_HdmiTxSs_Callback VsCallback; /**< Callback for Vsync event */ void *VsRef; /**< To be passed to the Vsync callback */ @@ -445,9 +469,9 @@ void XV_HdmiTxSs_SetGcpClearAvmuteBit(XV_HdmiTxSs *InstancePtr); void XV_HdmiTxSs_ClearGcpClearAvmuteBit(XV_HdmiTxSs *InstancePtr); int XV_HdmiTxSs_SetCallback(XV_HdmiTxSs *InstancePtr, - u32 HandlerType, - void *CallbackFuncPtr, - void *CallbackRef); + XV_HdmiTxSs_HandlerType HandlerType, + void *CallbackFuncPtr, + void *CallbackRef); int XV_HdmiTxSs_ReadEdid(XV_HdmiTxSs *InstancePtr, u8 *BufferPtr); int XV_HdmiTxSs_ReadEdidSegment(XV_HdmiTxSs *InstancePtr, u8 *Buffer, u8 segment); void XV_HdmiTxSs_SetScrambler(XV_HdmiTxSs *InstancePtr, u8 Enable); diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitxss_coreinit.c b/hdmi/xilinx-hdmi-tx/xv_hdmitxss_coreinit.c index 57f1e3a..9dbc434 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitxss_coreinit.c +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitxss_coreinit.c @@ -17,7 +17,6 @@ /** * * @file xv_hdmitxss_coreinit.c -* @addtogroup v_hdmitxss * @{ * @details diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitxss_coreinit.h b/hdmi/xilinx-hdmi-tx/xv_hdmitxss_coreinit.h index 60c4560..bfd948c 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitxss_coreinit.h +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitxss_coreinit.h @@ -17,7 +17,6 @@ /** * * @file xv_hdmitxss_coreinit.h -* @addtogroup v_hdmitxss * @{ * @details * diff --git a/hdmi/xilinx-hdmi-tx/xv_hdmitxss_log.c b/hdmi/xilinx-hdmi-tx/xv_hdmitxss_log.c index 0faf534..80b46ef 100644 --- a/hdmi/xilinx-hdmi-tx/xv_hdmitxss_log.c +++ b/hdmi/xilinx-hdmi-tx/xv_hdmitxss_log.c @@ -282,6 +282,10 @@ int XV_HdmiTxSs_LogShow(XV_HdmiTxSs *InstancePtr, char *buff, int buff_size) strSize += scnprintf(buff+strSize, buff_size-strSize, "Unsupported Video by VTC\r\n"); break; + case (XV_HDMITXSS_LOG_EVT_BRDG_UNLOCKED): + strSize += scnprintf(buff+strSize, buff_size-strSize, + "VID Bridge Unlocked\r\n"); + break; default: strSize += scnprintf(buff+strSize, buff_size-strSize, "Unknown event: %i\r\n", Data); diff --git a/hdmi/xilinx-hdmi-tx/xvtc.c b/hdmi/xilinx-hdmi-tx/xvtc.c index 8347792..9dd4de7 100644 --- a/hdmi/xilinx-hdmi-tx/xvtc.c +++ b/hdmi/xilinx-hdmi-tx/xvtc.c @@ -17,7 +17,6 @@ /** * * @file xvtc.c -* @addtogroup vtc_v7_2 * @{ * * This is main code of Xilinx MVI Video Timing Controller (VTC) device driver. @@ -155,6 +154,16 @@ * sk 08/16/16 Used UINTPTR instead of u32 for Baseaddress as part of * adding 64 bit support. CR# 867425. * Changed the prototype of XVtc_CfgInitialize API. +* 8.0 jsr 07/03/18 Added a new register XVTC_GASIZE_F1_OFFSET for interlaced +* modes FIELD1 vactive size. This value is same as FILED0 +* vactive size for all interlaced modes except for SDI NTSC +* mode +* jsr 10/01/18 Removed the hard coded programming of vactive size values +* based on resolutions. Moved the hard coded values for SDI +* NTSC resolution to SDI TXSS driver instead of in VTC +* driver. +* jsr 10/03/18 Corrected the VGA resoultion timing paramters w.r.t the +* timing values given in the VTC GUI for 640x480p * * ******************************************************************************/ @@ -183,7 +192,7 @@ * callback functions. If application is not registered any of the callback * function, these functions will be called for doing nothing. */ -static void StubCallBack(void *CallBackRef); +static void StubCallBack(void *CallBackRef, u32 Mask); static void StubErrCallBack(void *CallBackRef, u32 ErrorMask); /************************** Variable Definitions *****************************/ @@ -1335,6 +1344,18 @@ void XVtc_SetGenerator(XVtc *InstancePtr, XVtc_Signal *SignalCfgPtr) XVTC_ASIZE_VERT_MASK; XVtc_WriteReg(InstancePtr->Config.BaseAddress, XVTC_GASIZE_OFFSET, RegValue); + /* For some resolutions, the FIELD1 vactive size is different + * from FIELD0, e.g. XVIDC_VM_720x486_60_I (SDI NTSC), + * As there is no vactive FIELD1 entry in the video common + * library, program it separately. For resolutions where + * vactive values are different, it should be taken care in + * corrosponding driver. Otherwise program same values in + * FIELD0 and FIELD1 registers */ + RegValue = ((r_vactive) << XVTC_ASIZE_VERT_SHIFT) & + XVTC_ASIZE_VERT_MASK; + + XVtc_WriteReg(InstancePtr->Config.BaseAddress, + XVTC_GASIZE_F1_OFFSET, RegValue); /* Update the Generator Horizontal 1 Register */ RegValue = (SCPtr->HSyncStart + r_hactive) & @@ -1414,6 +1435,18 @@ void XVtc_SetGenerator(XVtc *InstancePtr, XVtc_Signal *SignalCfgPtr) XVTC_ASIZE_VERT_MASK; XVtc_WriteReg(InstancePtr->Config.BaseAddress, XVTC_GASIZE_OFFSET, RegValue); + /* For some resolutions, the FIELD1 vactive size is different + * from FIELD0, e.g. XVIDC_VM_720x486_60_I (SDI NTSC), + * As there is no vactive FIELD1 entry in the video common + * library, program it separately. For resolutions where + * vactive values are different, it should be taken care in + * corrosponding driver. Otherwise program same values in + * FIELD0 and FIELD1 registers */ + RegValue = ((r_vactive) << XVTC_ASIZE_VERT_SHIFT) & + XVTC_ASIZE_VERT_MASK; + + XVtc_WriteReg(InstancePtr->Config.BaseAddress, + XVTC_GASIZE_F1_OFFSET, RegValue); /* Update the Generator Horizontal 1 Register */ RegValue = (SCPtr->HSyncStart) & XVTC_SB_START_MASK; @@ -1895,17 +1928,17 @@ void XVtc_ConvVideoMode2Timing(XVtc *InstancePtr, u16 Mode, case XVTC_VMODE_VGA: // 640x480 (VGA) { // Horizontal Timing - TimingPtr->HActiveVideo = 656; - TimingPtr->HFrontPorch = 8; + TimingPtr->HActiveVideo = 640; + TimingPtr->HFrontPorch = 16; TimingPtr->HSyncWidth = 96; - TimingPtr->HBackPorch = 40; + TimingPtr->HBackPorch = 48; TimingPtr->HSyncPolarity = 0; // Vertical Timing - TimingPtr->VActiveVideo = 496; - TimingPtr->V0FrontPorch = 2; + TimingPtr->VActiveVideo = 480; + TimingPtr->V0FrontPorch = 10; TimingPtr->V0SyncWidth = 2; - TimingPtr->V0BackPorch = 25; + TimingPtr->V0BackPorch = 33; TimingPtr->VSyncPolarity = 0; break; @@ -2323,8 +2356,8 @@ u16 XVtc_ConvTiming2VideoMode(XVtc *InstancePtr, XVtc_Timing *TimingPtr) return XVTC_VMODE_576P; } } - else if((TimingPtr->HActiveVideo == 656) && - (TimingPtr->VActiveVideo == 496)) { + else if((TimingPtr->HActiveVideo == 640) && + (TimingPtr->VActiveVideo == 480)) { return XVTC_VMODE_VGA; } else if((TimingPtr->HActiveVideo == 800) && @@ -2580,9 +2613,10 @@ u16 XVtc_GetDetectorVideoMode(XVtc *InstancePtr) * @note None. * ******************************************************************************/ -static void StubCallBack(void *CallBackRef) +static void StubCallBack(void *CallBackRef, u32 Mask) { (void)CallBackRef; + (void)Mask; Xil_AssertVoidAlways(); } diff --git a/hdmi/xilinx-hdmi-tx/xvtc.h b/hdmi/xilinx-hdmi-tx/xvtc.h index 08e12f0..15f2e3e 100644 --- a/hdmi/xilinx-hdmi-tx/xvtc.h +++ b/hdmi/xilinx-hdmi-tx/xvtc.h @@ -17,7 +17,6 @@ /** * * @file xvtc.h -* @addtogroup vtc_v7_2 * @{ * @details * @@ -281,6 +280,8 @@ * 7.2 sk 08/16/16 Used UINTPTR instead of u32 for Baseaddress as part of * adding 64 bit support. CR# 867425. * Changed the prototype of XVtc_CfgInitialize API. +* ms 03/17/17 Added readme.txt file in examples folder for doxygen +* generation. * * ******************************************************************************/ diff --git a/hdmi/xilinx-hdmi-tx/xvtc_hw.h b/hdmi/xilinx-hdmi-tx/xvtc_hw.h index 7ce32fc..4c25ce3 100644 --- a/hdmi/xilinx-hdmi-tx/xvtc_hw.h +++ b/hdmi/xilinx-hdmi-tx/xvtc_hw.h @@ -17,7 +17,6 @@ /** * * @file xvtc_hw.h -* @addtogroup vtc_v7_2 * @{ * * This header file contains identifiers and register-level core functions (or @@ -134,6 +133,7 @@ * Added backward compatibility macros. * 7.1 vns 10/14/15 Added XVTC_CTL_INTERLACE_MASK macro and * modified XVTC_CTL_ALLSS_MASK +* 8.0 jsr 07/03/18 Added new register XVTC_GASIZE_F1_OFFSET * * ******************************************************************************/ @@ -212,6 +212,8 @@ extern "C" { * Sync Offset */ #define XVTC_GVSHOFF_F1_OFFSET 0x090 /**< Generator Field 1 Vsync horizontal * Offset */ +#define XVTC_GASIZE_F1_OFFSET 0x094 /**< Generator Field 1 Active Size + * Offset */ #define XVTC_FS00_OFFSET 0x100 /**< Frame Sync 00 Config * Register Offset */ @@ -374,6 +376,8 @@ extern "C" { XVTC_IXR_LOCKALL_MASK) /**< Mask for all * interrupts Mask */ +#define XVTC_IXR_SPURIOUS_INTR_MASK ~(XVTC_IXR_ALLINTR_MASK) + /** @name Error Register Bit Definitions * @{ */ diff --git a/hdmi/xilinx-hdmi-tx/xvtc_intr.c b/hdmi/xilinx-hdmi-tx/xvtc_intr.c index db50117..b425513 100644 --- a/hdmi/xilinx-hdmi-tx/xvtc_intr.c +++ b/hdmi/xilinx-hdmi-tx/xvtc_intr.c @@ -17,7 +17,6 @@ /** * * @file xvtc_intr.c -* @addtogroup vtc_v7_2 * @{ * * This file contains interrupt related functions of Xilinx VTC core. @@ -103,6 +102,7 @@ * "XTEST_FAILED" -> "XST_FAILURE" * "XTEST_PASSED" -> "XST_SUCCESS" * 6.1 adk 08/23/14 Alligned doxygen tags. +* 8.1 pg 04/03/20 Fixed interrupt handler issue * * ******************************************************************************/ @@ -167,7 +167,7 @@ void XVtc_IntrHandler(void *InstancePtr) XVtc_IntrClear(XVtcPtr, PendingIntr); /* Spurious interrupt has happened */ - if (0 == (PendingIntr | XVTC_IXR_ALLINTR_MASK)) { + if (PendingIntr & XVTC_IXR_SPURIOUS_INTR_MASK) { ErrorStatus = 0; XVtcPtr->ErrCallBack(XVtcPtr->ErrRef, ErrorStatus); return; diff --git a/hdmi/xilinx-hdmi-tx/xvtc_sinit.c b/hdmi/xilinx-hdmi-tx/xvtc_sinit.c index 241b53e..39c3cc3 100644 --- a/hdmi/xilinx-hdmi-tx/xvtc_sinit.c +++ b/hdmi/xilinx-hdmi-tx/xvtc_sinit.c @@ -17,7 +17,6 @@ /** * * @file xvtc_sinit.c -* @addtogroup vtc_v7_2 * @{ * * This file contains static initialization methods for Xilinx VTC core. diff --git a/hdmi/xilinx-hdmirx.c b/hdmi/xilinx-hdmirx.c index dc69825..f4e98ae 100644 --- a/hdmi/xilinx-hdmirx.c +++ b/hdmi/xilinx-hdmirx.c @@ -31,7 +31,6 @@ #include #include "linux/phy/phy-vphy.h" -#include "xilinx-vip.h" /* baseline driver includes */ #include "xilinx-hdmi-rx/xv_hdmirxss.h" @@ -39,6 +38,7 @@ /* for the HMAC, using password to decrypt HDCP keys */ #include "phy-xilinx-vphy/xhdcp22_common.h" #include "phy-xilinx-vphy/aes256.h" +#include "xlnx_hdmirx_audio.h" #define hdmi_mutex_lock(x) mutex_lock(x) #define hdmi_mutex_unlock(x) mutex_unlock(x) @@ -122,12 +122,22 @@ struct xhdmi_device { u32 IntrStatus[7]; /* pointer to xvphy */ XVphy *xvphy; + /* pointer to HDMI GT controller phy */ + XHdmiphy1 *xgtphy; + /* flag to determine which phy */ + u32 isvphy; /* HDCP keys */ u8 hdcp_password[32]; u8 Hdcp22Lc128[16]; u8 Hdcp22PrivateKey[902]; u8 Hdcp14KeyA[328]; u8 Hdcp14KeyB[328]; + /* flag to indicate audio is enabled in device tree */ + bool audio_enabled; + /* flag to indicate audio is initialized */ + bool audio_init; + /* audio data to be shared with audio module */ + struct xlnx_hdmirx_audio_data *rx_audio_data; }; // Xilinx EDID @@ -140,14 +150,15 @@ static const u8 xilinx_edid[] = { 0x58, 0x2C, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x18, 0x4B, 0x0F, 0x8C, 0x3C, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x58, 0x49, 0x4C, 0x49, 0x4E, 0x58, 0x20, 0x48, 0x44, 0x4D, 0x49, 0x0A, 0x20, 0x01, 0x85, - 0x02, 0x03, 0x37, 0xF0, 0x57, 0x61, 0x10, 0x1F, 0x04, 0x13, 0x05, 0x14, 0x20, 0x21, 0x22, 0x5D, + + 0x02, 0x03, 0x3B, 0xF1, 0x57, 0x61, 0x10, 0x1F, 0x04, 0x13, 0x05, 0x14, 0x20, 0x21, 0x22, 0x5D, 0x5E, 0x5F, 0x60, 0x65, 0x66, 0x62, 0x63, 0x64, 0x07, 0x16, 0x03, 0x12, 0x23, 0x09, 0x07, 0x07, - 0x67, 0x03, 0x0C, 0x00, 0x10, 0x00, 0x78, 0x78, 0x67, 0xD8, 0x5D, 0xC4, 0x01, 0x78, 0xC0, 0x07, - 0xE3, 0x0F, 0x01, 0xE0, 0xE2, 0x00, 0xCF, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, - 0x2C, 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, 0x08, 0xE8, 0x00, 0x30, 0xF2, 0x70, 0x5A, - 0x80, 0xB0, 0x58, 0x8A, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, 0x04, 0x74, 0x00, 0x30, 0xF2, - 0x70, 0x5A, 0x80, 0xB0, 0x58, 0x8A, 0x00, 0x20, 0x52, 0x31, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC + 0x6B, 0x03, 0x0C, 0x00, 0x10, 0x00, 0x78, 0x3C, 0x20, 0x00, 0x20, 0x03, 0x67, 0xD8, 0x5D, 0xC4, + 0x01, 0x78, 0x80, 0x07, 0xE3, 0x0F, 0x01, 0xE0, 0xE2, 0x00, 0xCF, 0x02, 0x3A, 0x80, 0x18, 0x71, + 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, 0x08, 0xE8, 0x00, + 0x30, 0xF2, 0x70, 0x5A, 0x80, 0xB0, 0x58, 0x8A, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, 0x04, + 0x74, 0x00, 0x30, 0xF2, 0x70, 0x5A, 0x80, 0xB0, 0x58, 0x8A, 0x00, 0x20, 0x52, 0x31, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC }; static inline struct xhdmi_device *to_xhdmi(struct v4l2_subdev *subdev) @@ -349,6 +360,42 @@ static int xhdmi_enum_frame_size(struct v4l2_subdev *subdev, return 0; } +/** + * xhdmi_enum_mbus_code - Enumerate the media format code + * @subdev: V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @code: returning media bus code + * + * Enumerate the media bus code of the subdevice. Return the corresponding + * pad format code. This function only works for subdevices with fixed format + * on all pads. Subdevices with multiple format should have their own + * function to enumerate mbus codes. + * + * Return: 0 if the media bus code is found, or -EINVAL if the format index + * is not valid. + */ +int xhdmi_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct v4l2_mbus_framefmt *format; + + /* Enumerating frame sizes based on the active configuration isn't + * supported yet. + */ + if (code->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + if (code->index) + return -EINVAL; + + format = v4l2_subdev_get_try_format(subdev, cfg, code->pad); + + code->code = format->code; + + return 0; +} + static int xhdmi_dv_timings_cap(struct v4l2_subdev *subdev, struct v4l2_dv_timings_cap *cap) { @@ -426,7 +473,7 @@ static struct v4l2_subdev_video_ops xhdmi_video_ops = { * it must implement format related functionality using v4l2_subdev_pad_ops instead of * v4l2_subdev_video_ops. */ static struct v4l2_subdev_pad_ops xhdmi_pad_ops = { - .enum_mbus_code = xvip_enum_mbus_code, + .enum_mbus_code = xhdmi_enum_mbus_code, .enum_frame_size = xhdmi_enum_frame_size, .get_fmt = xhdmi_get_format, .set_fmt = xhdmi_set_format, @@ -458,16 +505,6 @@ static const struct media_entity_operations xhdmi_media_ops = { * Power Management */ -static int __maybe_unused xhdmi_pm_suspend(struct device *dev) -{ - return 0; -} - -static int __maybe_unused xhdmi_pm_resume(struct device *dev) -{ - return 0; -} - void HdmiRx_PioIntrHandler(XV_HdmiRx *InstancePtr); void HdmiRx_TmrIntrHandler(XV_HdmiRx *InstancePtr); void HdmiRx_VtdIntrHandler(XV_HdmiRx *InstancePtr); @@ -497,6 +534,30 @@ static void XV_HdmiRxSs_IntrDisable(XV_HdmiRxSs *HdmiRxSsPtr) XV_HdmiRx_LinkIntrDisable(HdmiRxSsPtr->HdmiRxPtr); } +static int __maybe_unused hdmirx_pm_suspend(struct device *dev) +{ + unsigned long flags; + struct xhdmi_device *xhdmi = dev_get_drvdata(dev); + XV_HdmiRxSs *HdmiRxSsPtr = (XV_HdmiRxSs *)&xhdmi->xv_hdmirxss; + dev_dbg(xhdmi->dev,"HDMI RX suspend function called\n"); + spin_lock_irqsave(&xhdmi->irq_lock, flags); + XV_HdmiRxSs_IntrDisable(HdmiRxSsPtr); + spin_unlock_irqrestore(&xhdmi->irq_lock, flags); + return 0; +} + +static int __maybe_unused hdmirx_pm_resume(struct device *dev) +{ + unsigned long flags; + struct xhdmi_device *xhdmi = dev_get_drvdata(dev); + XV_HdmiRxSs *HdmiRxSsPtr = (XV_HdmiRxSs *)&xhdmi->xv_hdmirxss; + dev_dbg(xhdmi->dev,"HDMI RX resume function called\n"); + spin_lock_irqsave(&xhdmi->irq_lock, flags); + XV_HdmiRxSs_IntrEnable(HdmiRxSsPtr); + spin_unlock_irqrestore(&xhdmi->irq_lock, flags); + return 0; +} + static irqreturn_t hdmirx_irq_handler(int irq, void *dev_id) { struct xhdmi_device *xhdmi; @@ -638,7 +699,11 @@ static void RxConnectCallback(void *CallbackRef) struct xhdmi_device *xhdmi = (struct xhdmi_device *)CallbackRef; XV_HdmiRxSs *HdmiRxSsPtr = &xhdmi->xv_hdmirxss; XVphy *VphyPtr = xhdmi->xvphy; - if (!xhdmi || !HdmiRxSsPtr || !VphyPtr) return; + XHdmiphy1 *XGtPhyPtr = xhdmi->xgtphy; + + if (!xhdmi || !HdmiRxSsPtr || (xhdmi->isvphy && !VphyPtr) || + (!xhdmi->isvphy && !XGtPhyPtr)) + return; xhdmi->cable_is_connected = !!HdmiRxSsPtr->IsStreamConnected; dev_dbg(xhdmi->dev,"RxConnectCallback(): cable is %sconnected.\n", @@ -647,11 +712,20 @@ static void RxConnectCallback(void *CallbackRef) xvphy_mutex_lock(xhdmi->phy[0]); /* RX cable is connected? */ if (HdmiRxSsPtr->IsStreamConnected) { - XVphy_IBufDsEnable(VphyPtr, 0, XVPHY_DIR_RX, (TRUE)); + if (xhdmi->isvphy) + XVphy_IBufDsEnable(VphyPtr, 0, XVPHY_DIR_RX, (TRUE)); + else + XHdmiphy1_IBufDsEnable(XGtPhyPtr, 0, XHDMIPHY1_DIR_RX, (TRUE)); } else { - /* clear GT RX TMDS clock ratio */ - VphyPtr->HdmiRxTmdsClockRatio = 0; - XVphy_IBufDsEnable(VphyPtr, 0, XVPHY_DIR_RX, (FALSE)); + if (xhdmi->isvphy) { + /* clear GT RX TMDS clock ratio */ + VphyPtr->HdmiRxTmdsClockRatio = 0; + XVphy_IBufDsEnable(VphyPtr, 0, XVPHY_DIR_RX, (FALSE)); + } else { + /* clear GT RX TMDS clock ratio */ + XGtPhyPtr->HdmiRxTmdsClockRatio = 0; + XHdmiphy1_IBufDsEnable(XGtPhyPtr, 0, XHDMIPHY1_DIR_RX, (FALSE)); + } } xvphy_mutex_unlock(xhdmi->phy[0]); } @@ -673,9 +747,14 @@ static void RxStreamInitCallback(void *CallbackRef) struct xhdmi_device *xhdmi = (struct xhdmi_device *)CallbackRef; XV_HdmiRxSs *HdmiRxSsPtr = &xhdmi->xv_hdmirxss; XVphy *VphyPtr = xhdmi->xvphy; + XHdmiphy1 *XGtPhyPtr = xhdmi->xgtphy; XVidC_VideoStream *HdmiRxSsVidStreamPtr; u32 Status; - if (!xhdmi || !HdmiRxSsPtr || !VphyPtr) return; + + if (!xhdmi || !HdmiRxSsPtr || (xhdmi->isvphy && !VphyPtr) || + (!xhdmi->isvphy && !XGtPhyPtr)) + return; + dev_dbg(xhdmi->dev,"RxStreamInitCallback\r\n"); // Calculate RX MMCM parameters // In the application the YUV422 colordepth is 12 bits @@ -687,16 +766,30 @@ static void RxStreamInitCallback(void *CallbackRef) xvphy_mutex_lock(xhdmi->phy[0]); if (HdmiRxSsVidStreamPtr->ColorFormatId == XVIDC_CSF_YCRCB_422) { - Status = XVphy_HdmiCfgCalcMmcmParam(VphyPtr, 0, XVPHY_CHANNEL_ID_CH1, - XVPHY_DIR_RX, - HdmiRxSsVidStreamPtr->PixPerClk, - XVIDC_BPC_8); + if (xhdmi->isvphy) { + Status = XVphy_HdmiCfgCalcMmcmParam(VphyPtr, 0, XVPHY_CHANNEL_ID_CH1, + XVPHY_DIR_RX, + HdmiRxSsVidStreamPtr->PixPerClk, + XVIDC_BPC_8); + } else { + Status = XHdmiphy1_HdmiCfgCalcMmcmParam(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CH1, + XHDMIPHY1_DIR_RX, + HdmiRxSsVidStreamPtr->PixPerClk, + XVIDC_BPC_8); + } // Other colorspaces } else { - Status = XVphy_HdmiCfgCalcMmcmParam(VphyPtr, 0, XVPHY_CHANNEL_ID_CH1, - XVPHY_DIR_RX, - HdmiRxSsVidStreamPtr->PixPerClk, - HdmiRxSsVidStreamPtr->ColorDepth); + if (xhdmi->isvphy) { + Status = XVphy_HdmiCfgCalcMmcmParam(VphyPtr, 0, XVPHY_CHANNEL_ID_CH1, + XVPHY_DIR_RX, + HdmiRxSsVidStreamPtr->PixPerClk, + HdmiRxSsVidStreamPtr->ColorDepth); + } else { + Status = XHdmiphy1_HdmiCfgCalcMmcmParam(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CH1, + XHDMIPHY1_DIR_RX, + HdmiRxSsVidStreamPtr->PixPerClk, + HdmiRxSsVidStreamPtr->ColorDepth); + } } if (Status == XST_FAILURE) { @@ -705,7 +798,10 @@ static void RxStreamInitCallback(void *CallbackRef) } // Enable and configure RX MMCM - XVphy_MmcmStart(VphyPtr, 0, XVPHY_DIR_RX); + if (xhdmi->isvphy) + XVphy_MmcmStart(VphyPtr, 0, XVPHY_DIR_RX); + else + XHdmiphy1_MmcmStart(XGtPhyPtr, 0, XHDMIPHY1_DIR_RX); //wait 10ms for PLL to stabilize usleep_range(10000, 11000); xvphy_mutex_unlock(xhdmi->phy[0]); @@ -728,7 +824,23 @@ static void RxStreamUpCallback(void *CallbackRef) xhdmi->detected_format.width = Stream->Timing.HActive; xhdmi->detected_format.height = Stream->Timing.VActive; - xhdmi->detected_format.field = Stream->IsInterlaced? V4L2_FIELD_INTERLACED: V4L2_FIELD_NONE; + /* Check for the NTSC and PAL resolutions. RX will detect the resolution as 1440x240 (NTSC resolution) + * for field 0 and field 1. + * Upon detecting this RX should drop the extra pixel and send only 720x240 per field to Frame buffer write IP. + * Therefore in the end of this function, we will have to call API to configure bridge for pixel drop. + */ + if((((Stream->Timing.HActive == 1440) && (Stream->Timing.VActive == 240) && (Stream->FrameRate == 60)) || + ((Stream->Timing.HActive == 1440) && (Stream->Timing.VActive == 288) && (Stream->FrameRate == 50))) + && (!!Stream->IsInterlaced)) + { + xhdmi->detected_format.width /= 2; + dev_dbg(xhdmi->dev, "NTSC/PAL detected_format.width after divide by 2 = %d\n", xhdmi->detected_format.width); + } + + /* There is no point in setting feild V4L2_FIELD_INTERLACED as it is not getting used */ + //xhdmi->detected_format.field = Stream->IsInterlaced? V4L2_FIELD_INTERLACED: V4L2_FIELD_NONE; + xhdmi->detected_format.field = V4L2_FIELD_NONE; + /* https://linuxtv.org/downloads/v4l-dvb-apis/ch02s05.html#v4l2-colorspace */ if (Stream->ColorFormatId == XVIDC_CSF_RGB) { dev_dbg(xhdmi->dev,"xhdmi->detected_format.colorspace = V4L2_COLORSPACE_SRGB\n"); @@ -742,18 +854,61 @@ static void RxStreamUpCallback(void *CallbackRef) /* see UG934 page 8 */ /* the V4L2 media bus fmt codes match the AXI S format, and match those from TPG */ if (Stream->ColorFormatId == XVIDC_CSF_RGB) { - /* red blue green */ - xhdmi->detected_format.code = MEDIA_BUS_FMT_RBG888_1X24; - dev_dbg(xhdmi->dev,"XVIDC_CSF_RGB -> MEDIA_BUS_FMT_RBG888_1X24\n"); + if (HdmiRxSsPtr->Config.MaxBitsPerPixel == 10) { + if(Stream->ColorDepth == XVIDC_BPC_8) { + xhdmi->detected_format.code = MEDIA_BUS_FMT_RBG888_1X24; + dev_dbg(xhdmi->dev,"XVIDC_CSF_RGB -> MEDIA_BUS_FMT_RBG888_1X24\n"); + } else { + xhdmi->detected_format.code = MEDIA_BUS_FMT_RBG101010_1X30; + dev_dbg(xhdmi->dev,"XVIDC_CSF_RGB -> MEDIA_BUS_FMT_RBG101010_1X30\n"); + } + /* Default will always be 8 */ + } else { + xhdmi->detected_format.code = MEDIA_BUS_FMT_RBG888_1X24; + dev_dbg(xhdmi->dev,"XVIDC_CSF_RGB -> MEDIA_BUS_FMT_RBG888_1X24\n"); + } + + /* YUV444 */ } else if (Stream->ColorFormatId == XVIDC_CSF_YCRCB_444) { - xhdmi->detected_format.code = MEDIA_BUS_FMT_VUY8_1X24; - dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_444 -> MEDIA_BUS_FMT_VUY8_1X24\n"); + if (HdmiRxSsPtr->Config.MaxBitsPerPixel == 10) { + if(Stream->ColorDepth == XVIDC_BPC_8) { + xhdmi->detected_format.code = MEDIA_BUS_FMT_VUY8_1X24; + dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_444 -> MEDIA_BUS_FMT_VUY8_1X24\n"); + } else { + xhdmi->detected_format.code = MEDIA_BUS_FMT_VUY10_1X30; + dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_444 -> MEDIA_BUS_FMT_VUY10_1X30\n"); + } + /* Default will always be 8 */ + } else { + xhdmi->detected_format.code = MEDIA_BUS_FMT_VUY8_1X24; + dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_444 -> MEDIA_BUS_FMT_VUY8_1X24\n"); + } + + /* Since 422 is always detected as 12 BPC, set the 8bit media bus format */ } else if (Stream->ColorFormatId == XVIDC_CSF_YCRCB_422) { - xhdmi->detected_format.code = MEDIA_BUS_FMT_UYVY8_1X16; - dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_422 -> MEDIA_BUS_FMT_UYVY8_1X16\n"); + if (HdmiRxSsPtr->Config.MaxBitsPerPixel == 10) { + xhdmi->detected_format.code = MEDIA_BUS_FMT_UYVY10_1X20; + dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_422 -> MEDIA_BUS_FMT_UYVY10_1X20\n"); + /* Default will always be 8 */ + } else { + xhdmi->detected_format.code = MEDIA_BUS_FMT_UYVY8_1X16; + dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_422 -> MEDIA_BUS_FMT_UYVY8_1X16\n"); + } + + /* YUV420 */ } else if (Stream->ColorFormatId == XVIDC_CSF_YCRCB_420) { - xhdmi->detected_format.code = MEDIA_BUS_FMT_VYYUYY8_1X24; - dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_420 -> MEDIA_BUS_FMT_VYYUYY8_1X24\n"); + if (HdmiRxSsPtr->Config.MaxBitsPerPixel == 10) { + if(Stream->ColorDepth == XVIDC_BPC_8) { + xhdmi->detected_format.code = MEDIA_BUS_FMT_VYYUYY8_1X24; + dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_420 -> MEDIA_BUS_FMT_VYYUYY8_1X24\n"); + } else { + xhdmi->detected_format.code = MEDIA_BUS_FMT_VYYUYY10_4X20; + dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_420 -> MEDIA_BUS_FMT_VYYUYY10_1X24\n"); + } + } else { + xhdmi->detected_format.code = MEDIA_BUS_FMT_VYYUYY8_1X24; + dev_dbg(xhdmi->dev,"XVIDC_CSF_YCRCB_420 -> MEDIA_BUS_FMT_VYYUYY8_1X24\n"); + } } xhdmi->detected_format.xfer_func = V4L2_XFER_FUNC_DEFAULT; @@ -786,6 +941,23 @@ static void RxStreamUpCallback(void *CallbackRef) } xhdmi->detected_timings.bt.pixelclock *= Stream->Timing.HTotal; + /* Check for the NTSC and PAL resolutions. RX will detect the resolution as 1440x240 (NTSC resolution) + * for field 0 and field 1. + * Upon detecting this RX should drop the extra pixel and send only 720x240 per field to Frame buffer write IP. + * Therefore in the end of this function, we will have to call API to configure bridge for pixel drop. + */ + if((((Stream->Timing.HActive == 1440) && (Stream->Timing.VActive == 240) && (Stream->FrameRate == 60)) || + ((Stream->Timing.HActive == 1440) && (Stream->Timing.VActive == 288) && (Stream->FrameRate == 50))) + && (!!Stream->IsInterlaced)) + { + xhdmi->detected_timings.bt.width /= 2; + dev_dbg(xhdmi->dev, "NTSC/PAL detected_timings.bt.width after divide by 2 = %d\n", xhdmi->detected_format.width); + + dev_dbg(xhdmi->dev,"Programming RX bridge for dropping pixels\n"); + XV_HdmiRxSs_BridgeYuv420(HdmiRxSsPtr, FALSE); + XV_HdmiRxSs_BridgePixelDrop(HdmiRxSsPtr, TRUE); + } + dev_dbg(xhdmi->dev,"HdmiRxSsPtr->HdmiRxPtr->Stream.PixelClk = %d\n", HdmiRxSsPtr->HdmiRxPtr->Stream.PixelClk); /* Read HFront Porch */ xhdmi->detected_timings.bt.hfrontporch = Stream->Timing.HFrontPorch; @@ -814,6 +986,11 @@ static void RxStreamUpCallback(void *CallbackRef) /* notify source format change event */ v4l2_subdev_notify_event(&xhdmi->subdev, &xhdmi_ev_fmt); + /* TODO: As subsystem API XV_HdmiRxSs_AudioEnable is not available, + * core API is used currently. + */ + if (xhdmi->audio_init) + XV_HdmiRx_AudioEnable(HdmiRxSsPtr->HdmiRxPtr); #ifdef DEBUG v4l2_print_dv_timings("xilinx-hdmi-rx", "", & xhdmi->detected_timings, 1); #endif @@ -824,22 +1001,26 @@ static void RxBrdgOverflowCallback(void *CallbackRef) struct xhdmi_device *xhdmi = (struct xhdmi_device *)CallbackRef; XV_HdmiRxSs *HdmiRxSsPtr = &xhdmi->xv_hdmirxss; - dev_dbg(xhdmi->dev,"RxBrdgOverflowCallback()\n"); + //dev_dbg(xhdmi->dev,"RxBrdgOverflowCallback()\n"); } static void RxAudCallback(void *CallbackRef) { struct xhdmi_device *xhdmi = (struct xhdmi_device *)CallbackRef; XV_HdmiRxSs *HdmiRxSsPtr = &xhdmi->xv_hdmirxss; - XV_HdmiRx_AudioFormatType format; - u8 NumChannels; + struct xlnx_hdmirx_audio_data *adata = xhdmi->rx_audio_data; dev_dbg(xhdmi->dev,"%s()\n", __func__); - format = XV_HdmiRxSs_GetAudioFormat(HdmiRxSsPtr); - NumChannels = XV_HdmiRxSs_GetAudioChannels(HdmiRxSsPtr); + adata->format = XV_HdmiRxSs_GetAudioFormat(HdmiRxSsPtr); + adata->num_channels = XV_HdmiRxSs_GetAudioChannels(HdmiRxSsPtr); //ToDo: Insert registered ALSA driver call-back - dev_dbg(xhdmi->dev, "Channels = %d\n", NumChannels); - dev_dbg(xhdmi->dev, "Format = %d\n", format); + if (xhdmi->audio_init && adata->num_channels >= 2) { + adata->audio_detected = true; + wake_up_interruptible(&adata->audio_update_q); + } + + dev_dbg(xhdmi->dev, "Channels = %d\n", adata->num_channels); + dev_dbg(xhdmi->dev, "Format = %d\n", adata->format); } static void RxAuxCallback(void *CallbackRef) @@ -851,7 +1032,7 @@ static void RxAuxCallback(void *CallbackRef) AuxPtr = XV_HdmiRxSs_GetAuxiliary(HdmiRxSsPtr); - dev_dbg(xhdmi->dev,"%s()\n", __func__); + //dev_dbg(xhdmi->dev,"%s()\n", __func__); /* read out the aux packet to a local buffer * currently only 1 Aux packet (last recvd) is stored */ @@ -868,8 +1049,12 @@ static void VphyHdmiRxInitCallback(void *CallbackRef) struct xhdmi_device *xhdmi = (struct xhdmi_device *)CallbackRef; XV_HdmiRxSs *HdmiRxSsPtr = &xhdmi->xv_hdmirxss; XVphy *VphyPtr = xhdmi->xvphy; + XHdmiphy1 *XGtPhyPtr = xhdmi->xgtphy; + + if ((!xhdmi) || (xhdmi->isvphy && !VphyPtr) || + (!xhdmi->isvphy && !XGtPhyPtr)) + return; - if (!xhdmi || !VphyPtr) return; dev_dbg(xhdmi->dev,"VphyHdmiRxInitCallback()\n"); /* a pair of mutexes must be locked in fixed order to prevent deadlock, @@ -880,7 +1065,11 @@ static void VphyHdmiRxInitCallback(void *CallbackRef) XV_HdmiRxSs_RefClockChangeInit(HdmiRxSsPtr); /* @NOTE maybe implement xvphy_set_hdmirx_tmds_clockratio(); */ - VphyPtr->HdmiRxTmdsClockRatio = HdmiRxSsPtr->TMDSClockRatio; + if (xhdmi->isvphy) + VphyPtr->HdmiRxTmdsClockRatio = HdmiRxSsPtr->TMDSClockRatio; + else + XGtPhyPtr->HdmiRxTmdsClockRatio = HdmiRxSsPtr->TMDSClockRatio; + /* unlock RX SS but keep XVPHY locked */ hdmi_mutex_unlock(&xhdmi->xhdmi_mutex); } @@ -892,8 +1081,13 @@ static void VphyHdmiRxReadyCallback(void *CallbackRef) struct xhdmi_device *xhdmi = (struct xhdmi_device *)CallbackRef; XVphy *VphyPtr = xhdmi->xvphy; XVphy_PllType RxPllType; + XHdmiphy1 *XGtPhyPtr = xhdmi->xgtphy; + XHdmiphy1_PllType GtRxPllType; + + if ((!xhdmi) || (xhdmi->isvphy && !VphyPtr) || + (!xhdmi->isvphy && !XGtPhyPtr)) + return; - if (!xhdmi || !VphyPtr) return; dev_dbg(xhdmi->dev,"VphyHdmiRxReadyCallback()\n"); /* a pair of mutexes must be locked in fixed order to prevent deadlock, @@ -902,15 +1096,27 @@ static void VphyHdmiRxReadyCallback(void *CallbackRef) hdmi_mutex_lock(&xhdmi->xhdmi_mutex); xvphy_mutex_lock(xhdmi->phy[0]); - RxPllType = XVphy_GetPllType(VphyPtr, 0, XVPHY_DIR_RX, - XVPHY_CHANNEL_ID_CH1); - if (!(RxPllType == XVPHY_PLL_TYPE_CPLL)) { - XV_HdmiRxSs_SetStream(&xhdmi->xv_hdmirxss, VphyPtr->HdmiRxRefClkHz, - (XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CMN0)/1000000)); - } - else { - XV_HdmiRxSs_SetStream(&xhdmi->xv_hdmirxss, VphyPtr->HdmiRxRefClkHz, - (XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CH1)/1000000)); + if (xhdmi->isvphy) { + RxPllType = XVphy_GetPllType(VphyPtr, 0, XVPHY_DIR_RX, + XVPHY_CHANNEL_ID_CH1); + if (!(RxPllType == XVPHY_PLL_TYPE_CPLL)) { + XV_HdmiRxSs_SetStream(&xhdmi->xv_hdmirxss, VphyPtr->HdmiRxRefClkHz, + (XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CMN0)/1000000)); + } + else { + XV_HdmiRxSs_SetStream(&xhdmi->xv_hdmirxss, VphyPtr->HdmiRxRefClkHz, + (XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CH1)/1000000)); + } + } else { + GtRxPllType = XHdmiphy1_GetPllType(XGtPhyPtr, 0, XHDMIPHY1_DIR_RX, + XHDMIPHY1_CHANNEL_ID_CH1); + if (!(GtRxPllType == XHDMIPHY1_PLL_TYPE_CPLL)) { + XV_HdmiRxSs_SetStream(&xhdmi->xv_hdmirxss, XGtPhyPtr->HdmiRxRefClkHz, + (XHdmiphy1_GetLineRateHz(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CMN0)/1000000)); + } else { + XV_HdmiRxSs_SetStream(&xhdmi->xv_hdmirxss, XGtPhyPtr->HdmiRxRefClkHz, + (XHdmiphy1_GetLineRateHz(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CH1)/1000000)); + } } hdmi_mutex_unlock(&xhdmi->xhdmi_mutex); } @@ -1196,12 +1402,16 @@ static ssize_t vphy_log_show(struct device *sysfs_dev, struct device_attribute * { ssize_t count; XV_HdmiRxSs *HdmiRxSsPtr; - XVphy *VphyPtr; struct xhdmi_device *xhdmi = (struct xhdmi_device *)dev_get_drvdata(sysfs_dev); + XVphy *VphyPtr = xhdmi->xvphy; + XHdmiphy1 *XGtPhyPtr = xhdmi->xgtphy; HdmiRxSsPtr = (XV_HdmiRxSs *)&xhdmi->xv_hdmirxss; - VphyPtr = xhdmi->xvphy; - count = XVphy_LogShow(VphyPtr, buf, PAGE_SIZE); + if (xhdmi->isvphy) + count = XVphy_LogShow(VphyPtr, buf, PAGE_SIZE); + else + count = XHdmiphy1_LogShow(XGtPhyPtr, buf, PAGE_SIZE); + return count; } @@ -1211,15 +1421,26 @@ static ssize_t vphy_info_show(struct device *sysfs_dev, struct device_attribute ssize_t count; XV_HdmiRxSs *HdmiRxSsPtr; XVphy *VphyPtr; + XHdmiphy1 *XGtPhyPtr; struct xhdmi_device *xhdmi = (struct xhdmi_device *)dev_get_drvdata(sysfs_dev); HdmiRxSsPtr = (XV_HdmiRxSs *)&xhdmi->xv_hdmirxss; - VphyPtr = xhdmi->xvphy; - count = XVphy_HdmiDebugInfo(VphyPtr, 0, XVPHY_CHANNEL_ID_CHA, buf, PAGE_SIZE); - count += scnprintf(&buf[count], (PAGE_SIZE-count), "Rx Ref Clk: %0d Hz\n", - XVphy_ClkDetGetRefClkFreqHz(xhdmi->xvphy, XVPHY_DIR_RX)); - count += scnprintf(&buf[count], (PAGE_SIZE-count), "DRU Ref Clk: %0d Hz\n", - XVphy_DruGetRefClkFreqHz(xhdmi->xvphy)); + + if (xhdmi->isvphy) { + VphyPtr = xhdmi->xvphy; + count = XVphy_HdmiDebugInfo(VphyPtr, 0, XVPHY_CHANNEL_ID_CHA, buf, PAGE_SIZE); + count += scnprintf(&buf[count], (PAGE_SIZE-count), "Rx Ref Clk: %0d Hz\n", + XVphy_ClkDetGetRefClkFreqHz(xhdmi->xvphy, XVPHY_DIR_RX)); + count += scnprintf(&buf[count], (PAGE_SIZE-count), "DRU Ref Clk: %0d Hz\n", + XVphy_DruGetRefClkFreqHz(xhdmi->xvphy)); + } else { + XGtPhyPtr = xhdmi->xgtphy; + count = XHdmiphy1_HdmiDebugInfo(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, buf, PAGE_SIZE); + count += scnprintf(&buf[count], (PAGE_SIZE-count), "Rx Ref Clk: %0d Hz\n", + XHdmiphy1_ClkDetGetRefClkFreqHz(xhdmi->xgtphy, XHDMIPHY1_DIR_RX)); + count += scnprintf(&buf[count], (PAGE_SIZE-count), "DRU Ref Clk: %0d Hz\n", + XHdmiphy1_DruGetRefClkFreqHz(xhdmi->xgtphy)); + } return count; } @@ -1570,6 +1791,11 @@ static int xhdmi_parse_of(struct xhdmi_device *xhdmi, XV_HdmiRxSs_Config *config goto error_dt; config->Ppc = val; + rc = of_property_read_u32(node, "xlnx,max-bits-per-component", &val); + if (rc < 0) + goto error_dt; + config->MaxBitsPerPixel = val; + rc = of_property_read_u32(node, "xlnx,edid-ram-size", &val); if (rc == 0) { if (val % 128) @@ -1586,6 +1812,8 @@ static int xhdmi_parse_of(struct xhdmi_device *xhdmi, XV_HdmiRxSs_Config *config isHdcp14_en = of_property_read_bool(node, "xlnx,include-hdcp-1-4"); isHdcp22_en = of_property_read_bool(node, "xlnx,include-hdcp-2-2"); + xhdmi->audio_enabled = + of_property_read_bool(node, "xlnx,audio-enabled"); if (isHdcp14_en) { /* HDCP14 Core */ @@ -1638,6 +1866,7 @@ static int xhdmi_parse_of(struct xhdmi_device *xhdmi, XV_HdmiRxSs_Config *config XHdcp22_Rng_ConfigTable[XPAR_XHDCP22_RNG_NUM_INSTANCES/2 + instance].BaseAddress = RX_HDCP22_RNG_OFFSET; } + return 0; error_dt: @@ -1659,13 +1888,21 @@ static int xhdmi_probe(struct platform_device *pdev) unsigned long axi_clk_rate; XV_HdmiRxSs *HdmiRxSsPtr; + struct xlnx_hdmirx_audio_data *adata; u32 Status; - dev_info(&pdev->dev, "probed\n"); + dev_info(&pdev->dev, "probe started\n"); /* allocate zeroed HDMI RX device structure */ xhdmi = devm_kzalloc(&pdev->dev, sizeof(*xhdmi), GFP_KERNEL); if (!xhdmi) return -ENOMEM; + xhdmi->rx_audio_data = + devm_kzalloc(&pdev->dev, sizeof(struct xlnx_hdmirx_audio_data), + GFP_KERNEL); + if (!xhdmi->rx_audio_data) + return -ENOMEM; + + adata = xhdmi->rx_audio_data; /* store pointer of the real device inside platform device */ xhdmi->dev = &pdev->dev; @@ -1694,6 +1931,13 @@ static int xhdmi_probe(struct platform_device *pdev) /* acquire vphy lanes */ for (index = 0; index < 3; index++) { + static const struct of_device_id xlnx_hdmi_phy_id_table[] = { + { .compatible = "xlnx,hdmi-gt-controller-1.0", }, + { .compatible = "xlnx,vid-phy-controller-2.2", }, + { /* end of table */ }, + }; + const struct of_device_id *match; + char phy_name[16]; snprintf(phy_name, sizeof(phy_name), "hdmi-phy%d", index); xhdmi->phy[index] = devm_phy_get(xhdmi->dev, phy_name); @@ -1701,7 +1945,7 @@ static int xhdmi_probe(struct platform_device *pdev) ret = PTR_ERR(xhdmi->phy[index]); xhdmi->phy[index] = NULL; if (ret == -EPROBE_DEFER) { - dev_info(xhdmi->dev, "xvphy not ready -EPROBE_DEFER\n"); + dev_info(xhdmi->dev, "xvphy/xgtphy not ready -EPROBE_DEFER\n"); return ret; } if (ret != -EPROBE_DEFER) @@ -1710,6 +1954,12 @@ static int xhdmi_probe(struct platform_device *pdev) goto error_phy; } + match = of_match_node(xlnx_hdmi_phy_id_table, xhdmi->phy[index]->dev.parent->of_node); + if (strncmp(match->compatible, "xlnx,vid-phy-controller", 23) == 0) + xhdmi->isvphy = 1; + else + xhdmi->isvphy = 0; + ret = phy_init(xhdmi->phy[index]); if (ret) { dev_err(xhdmi->dev, @@ -1738,7 +1988,7 @@ static int xhdmi_probe(struct platform_device *pdev) } /* video streaming bus clock */ - xhdmi->clk = devm_clk_get(xhdmi->dev, "video"); + xhdmi->clk = devm_clk_get(xhdmi->dev, "s_axis_video_aclk"); if (IS_ERR(xhdmi->clk)) { ret = PTR_ERR(xhdmi->clk); if (ret == -EPROBE_DEFER) @@ -1751,7 +2001,7 @@ static int xhdmi_probe(struct platform_device *pdev) clk_prepare_enable(xhdmi->clk); /* AXI lite register bus clock */ - xhdmi->axi_lite_clk = devm_clk_get(xhdmi->dev, "axi-lite"); + xhdmi->axi_lite_clk = devm_clk_get(xhdmi->dev, "s_axi_cpu_aclk"); if (IS_ERR(xhdmi->axi_lite_clk)) { ret = PTR_ERR(xhdmi->clk); if (ret == -EPROBE_DEFER) @@ -1794,16 +2044,16 @@ static int xhdmi_probe(struct platform_device *pdev) } if (xhdmi->config.Hdcp14.IsPresent) { - xhdmi->hdcp1x_irq = platform_get_irq_byname(pdev, "hdcp1x"); + xhdmi->hdcp1x_irq = platform_get_irq_byname(pdev, "hdcp14_irq"); dev_dbg(xhdmi->dev,"xhdmi->hdcp1x_irq = %d\n", xhdmi->hdcp1x_irq); - xhdmi->hdcp1x_timer_irq = platform_get_irq_byname(pdev, "hdcp1x-timer"); + xhdmi->hdcp1x_timer_irq = platform_get_irq_byname(pdev, "hdcp14_timer_irq"); dev_dbg(xhdmi->dev,"xhdmi->hdcp1x_timer_irq = %d\n", xhdmi->hdcp1x_timer_irq); } if (xhdmi->config.Hdcp22.IsPresent) { - xhdmi->hdcp22_irq = platform_get_irq_byname(pdev, "hdcp22"); + xhdmi->hdcp22_irq = platform_get_irq_byname(pdev, "hdcp22_irq"); dev_dbg(xhdmi->dev,"xhdmi->hdcp22_irq = %d\n", xhdmi->hdcp22_irq); - xhdmi->hdcp22_timer_irq = platform_get_irq_byname(pdev, "hdcp22-timer"); + xhdmi->hdcp22_timer_irq = platform_get_irq_byname(pdev, "hdcp22_timer_irq"); dev_dbg(xhdmi->dev,"xhdmi->hdcp22_timer_irq = %d\n", xhdmi->hdcp22_timer_irq); } @@ -1935,16 +2185,26 @@ static int xhdmi_probe(struct platform_device *pdev) XV_HdmiRxSs_SetCallback(HdmiRxSsPtr, XV_HDMIRXSS_HANDLER_AUX, RxAuxCallback, (void *)xhdmi); - /* get a reference to the XVphy data structure */ - xhdmi->xvphy = xvphy_get_xvphy(xhdmi->phy[0]); + /* get a reference to the XVphy/ XHdmiphy1 data structure */ + if (xhdmi->isvphy) + xhdmi->xvphy = xvphy_get_xvphy(xhdmi->phy[0]); + else + xhdmi->xgtphy = xvphy_get_xvphy(xhdmi->phy[0]); xvphy_mutex_lock(xhdmi->phy[0]); /* the callback is not specific to a single lane, but we need to * provide one of the phy's as reference */ - XVphy_SetHdmiCallback(xhdmi->xvphy, XVPHY_HDMI_HANDLER_RXINIT, - VphyHdmiRxInitCallback, (void *)xhdmi); - XVphy_SetHdmiCallback(xhdmi->xvphy, XVPHY_HDMI_HANDLER_RXREADY, - VphyHdmiRxReadyCallback, (void *)xhdmi); + if (xhdmi->isvphy) { + XVphy_SetHdmiCallback(xhdmi->xvphy, XVPHY_HDMI_HANDLER_RXINIT, + VphyHdmiRxInitCallback, (void *)xhdmi); + XVphy_SetHdmiCallback(xhdmi->xvphy, XVPHY_HDMI_HANDLER_RXREADY, + VphyHdmiRxReadyCallback, (void *)xhdmi); + } else { + XHdmiphy1_SetHdmiCallback(xhdmi->xgtphy, XHDMIPHY1_HDMI_HANDLER_RXINIT, + VphyHdmiRxInitCallback, (void *)xhdmi); + XHdmiphy1_SetHdmiCallback(xhdmi->xgtphy, XHDMIPHY1_HDMI_HANDLER_RXREADY, + VphyHdmiRxReadyCallback, (void *)xhdmi); + } xvphy_mutex_unlock(xhdmi->phy[0]); @@ -2002,12 +2262,23 @@ static int xhdmi_probe(struct platform_device *pdev) spin_lock_irqsave(&xhdmi->irq_lock, flags); XV_HdmiRxSs_IntrEnable(HdmiRxSsPtr); spin_unlock_irqrestore(&xhdmi->irq_lock, flags); - + /* probe has succeeded for this instance, increment instance index */ instance++; - dev_info(xhdmi->dev, "probe successful\n"); + if (xhdmi->audio_enabled) { + ret = hdmirx_register_aud_dev(xhdmi->dev); + if (ret < 0) { + xhdmi->audio_init = false; + dev_err(xhdmi->dev, "hdmi rx audio init failed\n"); + } else { + xhdmi->audio_init = true; + init_waitqueue_head(&adata->audio_update_q); + dev_info(xhdmi->dev, "hdmi rx audio initialized\n"); + } + } /* return success */ + dev_info(xhdmi->dev, "probe successful\n"); return 0; error: @@ -2048,11 +2319,15 @@ static int xhdmi_remove(struct platform_device *pdev) v4l2_ctrl_handler_free(&xhdmi->ctrl_handler); media_entity_cleanup(&subdev->entity); clk_disable_unprepare(xhdmi->clk); + if (xhdmi->audio_init) + hdmirx_unregister_aud_dev(&pdev->dev); dev_dbg(xhdmi->dev,"removed.\n"); return 0; } -static SIMPLE_DEV_PM_OPS(xhdmi_pm_ops, xhdmi_pm_suspend, xhdmi_pm_resume); +static const struct dev_pm_ops xhdmirx_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(hdmirx_pm_suspend, hdmirx_pm_resume) +}; static const struct of_device_id xhdmi_of_id_table[] = { { .compatible = "xlnx,v-hdmi-rx-ss-3.1" }, @@ -2063,13 +2338,57 @@ MODULE_DEVICE_TABLE(of, xhdmi_of_id_table); static struct platform_driver xhdmi_driver = { .driver = { .name = "xilinx-hdmi-rx", - .pm = &xhdmi_pm_ops, + .pm = &xhdmirx_pm_ops, .of_match_table = xhdmi_of_id_table, }, .probe = xhdmi_probe, .remove = xhdmi_remove, }; +struct xlnx_hdmirx_audio_data *hdmirx_get_audio_data(struct device *dev) +{ + struct xhdmi_device *xhdmi = dev_get_drvdata(dev); + + if (!xhdmi) + return NULL; + else + return xhdmi->rx_audio_data; +} + +u32 hdmirx_audio_startup(struct device *dev) +{ + int err; + struct xlnx_hdmirx_audio_data *adata; + unsigned long jiffies = msecs_to_jiffies(XHDMI_AUDIO_DETECT_TIMEOUT); + struct xhdmi_device *xhdmi = dev_get_drvdata(dev); + XV_HdmiRxSs *HdmiRxSsPtr = &xhdmi->xv_hdmirxss; + adata = xhdmi->rx_audio_data; + + hdmi_mutex_lock(&xhdmi->xhdmi_mutex); + XV_HdmiRx_AudioEnable(HdmiRxSsPtr->HdmiRxPtr); + hdmi_mutex_unlock(&xhdmi->xhdmi_mutex); + + err = wait_event_interruptible_timeout(adata->audio_update_q, + adata->audio_detected, + jiffies); + if (!err) { + dev_err(dev, "No audio detected in input stream\n"); + return 0; + } + + return adata->num_channels; +} + +void hdmirx_audio_shutdown(struct device *dev) +{ + struct xhdmi_device *xhdmi = dev_get_drvdata(dev); + XV_HdmiRxSs *HdmiRxSsPtr = &xhdmi->xv_hdmirxss; + + hdmi_mutex_lock(&xhdmi->xhdmi_mutex); + XV_HdmiRx_AudioDisable(HdmiRxSsPtr->HdmiRxPtr); + hdmi_mutex_unlock(&xhdmi->xhdmi_mutex); +} + module_platform_driver(xhdmi_driver); MODULE_DESCRIPTION("Xilinx HDMI RXSS V4L2 driver"); diff --git a/hdmi/xilinx_drm_hdmi.c b/hdmi/xilinx_drm_hdmi.c index 305440f..86b5c4b 100644 --- a/hdmi/xilinx_drm_hdmi.c +++ b/hdmi/xilinx_drm_hdmi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -50,10 +51,14 @@ #include "phy-xilinx-vphy/xhdcp22_common.h" #include "phy-xilinx-vphy/aes256.h" +#include "xlnx_hdmitx_audio.h" + #define HDMI_MAX_LANES 4 #define XVPHY_TXREFCLK_RDY_LOW 0 #define XVPHY_TXREFCLK_RDY_HIGH 1 +#define XHDMIPHY1_TXREFCLK_RDY_LOW 0 +#define XHDMIPHY1_TXREFCLK_RDY_HIGH 1 #define hdmi_mutex_lock(x) mutex_lock(x) #define hdmi_mutex_unlock(x) mutex_unlock(x) @@ -107,6 +112,12 @@ * @xv_hdmitxss: IP low level driver structure * @IntrStatus: Flag to indicate irq status * @xvphy: pointer to xilinx video phy + * @xgtphy: pointer to Xilinx HDMI GT Controller phy + * @isvphy: Flag to determine which Phy + * @audio_enabled: flag to indicate audio is enabled in device tree + * @audio_init: flag to indicate audio is initialized + * @tx_audio_data: audio data to be shared with audio module + * @audio_pdev: audio platform device */ struct xlnx_drm_hdmi { struct drm_encoder encoder; @@ -157,6 +168,7 @@ struct xlnx_drm_hdmi { int dpms; XVidC_ColorFormat xvidc_colorfmt; + XVidC_ColorDepth xvidc_colordepth; /* configuration for the baseline subsystem driver instance */ XV_HdmiTxSs_Config config; /* bookkeeping for the baseline subsystem driver instance */ @@ -165,12 +177,20 @@ struct xlnx_drm_hdmi { u32 IntrStatus; /* pointer to xvphy */ XVphy *xvphy; + /* pointer to xgtphy */ + XHdmiphy1 *xgtphy; + /* flag to determine which Phy */ + u32 isvphy; /* HDCP keys */ u8 hdcp_password[32]; u8 Hdcp22Lc128[16]; u8 Hdcp22PrivateKey[902]; u8 Hdcp14KeyA[328]; u8 Hdcp14KeyB[328]; + bool audio_enabled; + bool audio_init; + struct xlnx_hdmitx_audio_data *tx_audio_data; + struct platform_device *audio_pdev; }; static const u8 Hdcp22Srm[] = { @@ -224,6 +244,30 @@ static void XV_HdmiTxSs_IntrDisable(XV_HdmiTxSs *HdmiTxSsPtr) XV_HdmiTx_PioIntrDisable(HdmiTxSsPtr->HdmiTxPtr); } +static int __maybe_unused hdmitx_pm_suspend(struct device *dev) +{ + unsigned long flags; + struct xlnx_drm_hdmi *xhdmi = dev_get_drvdata(dev); + XV_HdmiTxSs *HdmiTxSsPtr = (XV_HdmiTxSs *)&xhdmi->xv_hdmitxss; + dev_dbg(xhdmi->dev,"HDMI TX suspend function called\n"); + spin_lock_irqsave(&xhdmi->irq_lock, flags); + XV_HdmiTxSs_IntrDisable(HdmiTxSsPtr); + spin_unlock_irqrestore(&xhdmi->irq_lock, flags); + return 0; +} + +static int __maybe_unused hdmitx_pm_resume(struct device *dev) +{ + unsigned long flags; + struct xlnx_drm_hdmi *xhdmi = dev_get_drvdata(dev); + XV_HdmiTxSs *HdmiTxSsPtr = (XV_HdmiTxSs *)&xhdmi->xv_hdmitxss; + dev_dbg(xhdmi->dev,"HDMI TX resume function called\n"); + spin_lock_irqsave(&xhdmi->irq_lock, flags); + XV_HdmiTxSs_IntrEnable(HdmiTxSsPtr); + spin_unlock_irqrestore(&xhdmi->irq_lock, flags); + return 0; +} + /* XV_HdmiTx_IntrHandler */ static irqreturn_t hdmitx_irq_handler(int irq, void *dev_id) { @@ -467,8 +511,6 @@ static void SendInfoframe(XV_HdmiTxSs *HdmiTxSsPtr) /* GCP does not need to be sent out because GCP packets on the TX side is handled by the HDMI TX core fully. */ - AuxFifo = XV_HdmiC_AudioIF_GeneratePacket(AudioInfoFramePtr); - XV_HdmiTxSs_SendGenericAuxInfoframe(HdmiTxSsPtr, &AuxFifo); SendVSInfoframe(HdmiTxSsPtr); } @@ -489,18 +531,23 @@ static void TxConnectCallback(void *CallbackRef) struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)CallbackRef; XV_HdmiTxSs *HdmiTxSsPtr = &xhdmi->xv_hdmitxss; XVphy *VphyPtr = xhdmi->xvphy; + XHdmiphy1 *XGtPhyPtr = xhdmi->xgtphy; dev_dbg(xhdmi->dev,"%s()\n", __func__); xvphy_mutex_lock(xhdmi->phy[0]); if (HdmiTxSsPtr->IsStreamConnected) { int xst_hdmi20; xhdmi->cable_connected = 1; + xhdmi->connector.status = connector_status_connected; /* Check HDMI sink version */ xst_hdmi20 = XV_HdmiTxSs_DetectHdmi20(HdmiTxSsPtr); dev_dbg(xhdmi->dev,"TxConnectCallback(): TX connected to HDMI %s Sink Device\n", (xst_hdmi20 == XST_SUCCESS)? "2.0": "1.4"); xhdmi->is_hdmi_20_sink = (xst_hdmi20 == XST_SUCCESS); - XVphy_IBufDsEnable(VphyPtr, 0, XVPHY_DIR_TX, (TRUE)); + if (xhdmi->isvphy) + XVphy_IBufDsEnable(VphyPtr, 0, XVPHY_DIR_TX, (TRUE)); + else + XHdmiphy1_IBufDsEnable(XGtPhyPtr, 0, XHDMIPHY1_DIR_TX, (TRUE)); XV_HdmiTxSs_StreamStart(HdmiTxSsPtr); /* stream never goes down on disconnect. Force hdcp event */ if (xhdmi->hdmi_stream_up && @@ -513,12 +560,31 @@ static void TxConnectCallback(void *CallbackRef) else { dev_dbg(xhdmi->dev,"TxConnectCallback(): TX disconnected\n"); xhdmi->cable_connected = 0; + xhdmi->connector.status = connector_status_disconnected; xhdmi->have_edid = 0; xhdmi->is_hdmi_20_sink = 0; /* do not disable ibufds - stream will not go down*/ -// XVphy_IBufDsEnable(VphyPtr, 0, XVPHY_DIR_TX, (FALSE)); + if (xhdmi->isvphy) + XVphy_IBufDsEnable(VphyPtr, 0, XVPHY_DIR_TX, (FALSE)); + else + XHdmiphy1_IBufDsEnable(XGtPhyPtr, 0, XHDMIPHY1_DIR_TX, (FALSE)); } xvphy_mutex_unlock(xhdmi->phy[0]); + + if(xhdmi->connector.dev) { + /* Not using drm_kms_helper_hotplug_event because apart from notifying + * user space about hotplug, it also calls output_poll_changed of drm device + * that is used to inform the fbdev helper of output changes. It is of no use + * here. Sometimes there were hang issue while running the application + * on using drm_kms_helper_hotplug_event API. */ + drm_sysfs_hotplug_event(xhdmi->connector.dev); + //drm_kms_helper_hotplug_event(xhdmi->drm_dev); + dev_dbg(xhdmi->dev,"Hotplug event sent to user space, Connect = %d", xhdmi->connector.status); + } else { + printk(KERN_WARNING "Not sending HOTPLUG event because " + "drm device is NULL as drm_connector_init is not called yet.\n"); + } + dev_dbg(xhdmi->dev,"TxConnectCallback() done\n"); } @@ -526,14 +592,18 @@ static void TxStreamUpCallback(void *CallbackRef) { struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)CallbackRef; XVphy *VphyPtr; + XHdmiphy1 *XGtPhyPtr; XV_HdmiTxSs *HdmiTxSsPtr; XVphy_PllType TxPllType; - u64 TxLineRate; + XHdmiphy1_PllType GtTxPllType; + u64 TxLineRate = 0; XHdmiC_AVI_InfoFrame *AVIInfoFramePtr; XVidC_VideoStream *HdmiTxSsVidStreamPtr; HdmiTxSsPtr = &xhdmi->xv_hdmitxss; + VphyPtr = xhdmi->xvphy; + XGtPhyPtr = xhdmi->xgtphy; dev_dbg(xhdmi->dev,"TxStreamUpCallback(): TX stream is up\n"); xhdmi->hdmi_stream_up = 1; @@ -544,23 +614,41 @@ static void TxStreamUpCallback(void *CallbackRef) (HdmiTxSsVidStreamPtr->VmId == XVIDC_VM_1440x576_50_I) ) { AVIInfoFramePtr->PixelRepetition = XHDMIC_PIXEL_REPETITION_FACTOR_2; + dev_dbg(xhdmi->dev,"Pixel repetition set to 2\n"); } else { AVIInfoFramePtr->PixelRepetition = XHDMIC_PIXEL_REPETITION_FACTOR_1; + dev_dbg(xhdmi->dev,"Pixel repetition set to 1\n"); } xvphy_mutex_lock(xhdmi->phy[0]); - TxPllType = XVphy_GetPllType(VphyPtr, 0, XVPHY_DIR_TX, XVPHY_CHANNEL_ID_CH1); - if ((TxPllType == XVPHY_PLL_TYPE_CPLL)) { - TxLineRate = XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CH1); - } - else if((TxPllType == XVPHY_PLL_TYPE_QPLL) || + if (xhdmi->isvphy) { + TxPllType = XVphy_GetPllType(VphyPtr, 0, XVPHY_DIR_TX, XVPHY_CHANNEL_ID_CH1); + if ((TxPllType == XVPHY_PLL_TYPE_CPLL)) { + TxLineRate = XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CH1); + } + else if((TxPllType == XVPHY_PLL_TYPE_QPLL) || (TxPllType == XVPHY_PLL_TYPE_QPLL0) || (TxPllType == XVPHY_PLL_TYPE_PLL0)) { - TxLineRate = XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CMN0); - } - else { - TxLineRate = XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CMN1); + TxLineRate = XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CMN0); + } + else { + TxLineRate = XVphy_GetLineRateHz(VphyPtr, 0, XVPHY_CHANNEL_ID_CMN1); + } + } else { + GtTxPllType = XHdmiphy1_GetPllType(XGtPhyPtr, 0, XHDMIPHY1_DIR_TX, XHDMIPHY1_CHANNEL_ID_CH1); + /* Versal - Implementation different here */ + if (GtTxPllType == XHDMIPHY1_PLL_TYPE_LCPLL) { + TxLineRate = + XHdmiphy1_GetLineRateHz(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CMN0); + dev_dbg(xhdmi->dev, "GtPhy TxLineRate LCPLL %lld Kbps\r\n",(TxLineRate/1000)); + } else if (GtTxPllType == XHDMIPHY1_PLL_TYPE_RPLL) { + TxLineRate = + XHdmiphy1_GetLineRateHz(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CMN1); + dev_dbg(xhdmi->dev, "GtPhy TxLineRate RPLL %lld Kbps\r\n",(TxLineRate/1000)); + } else { + dev_err(xhdmi->dev, "GtPhy Error! Invalid GtTxPllType in TxStreamUpCallback.\r\n"); + } } /* configure an external retimer through a (virtual) CCF clock @@ -570,10 +658,16 @@ static void TxStreamUpCallback(void *CallbackRef) (void)clk_set_rate(xhdmi->retimer_clk, (signed long long)TxLineRate); } /* Copy Sampling Rate */ - XV_HdmiTxSs_SetSamplingRate(HdmiTxSsPtr, VphyPtr->HdmiTxSampleRate); + if (xhdmi->isvphy) + XV_HdmiTxSs_SetSamplingRate(HdmiTxSsPtr, VphyPtr->HdmiTxSampleRate); + else + XV_HdmiTxSs_SetSamplingRate(HdmiTxSsPtr, XGtPhyPtr->HdmiTxSampleRate); /* Enable TX TMDS clock*/ - XVphy_Clkout1OBufTdsEnable(VphyPtr, XVPHY_DIR_TX, (TRUE)); + if (xhdmi->isvphy) + XVphy_Clkout1OBufTdsEnable(VphyPtr, XVPHY_DIR_TX, (TRUE)); + else + XHdmiphy1_Clkout1OBufTdsEnable(XGtPhyPtr, XHDMIPHY1_DIR_TX, (TRUE)); xvphy_mutex_unlock(xhdmi->phy[0]); @@ -583,6 +677,12 @@ static void TxStreamUpCallback(void *CallbackRef) if (xhdmi->hdcp_authenticate) { XHdcp_Authenticate(HdmiTxSsPtr); } + + /* Enable Audio */ + if (xhdmi->audio_enabled) { + XV_HdmiTxSs_AudioMute(HdmiTxSsPtr, 0); + } + dev_dbg(xhdmi->dev,"TxStreamUpCallback(): done\n"); } @@ -601,11 +701,51 @@ static void TxStreamDownCallback(void *CallbackRef) static void TxVsCallback(void *CallbackRef) { + XHdmiC_Aux aud_aux_fifo; struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)CallbackRef; XV_HdmiTxSs *HdmiTxSsPtr = &xhdmi->xv_hdmitxss; /* Send NULL Aux packet */ SendInfoframe(HdmiTxSsPtr); + + if (xhdmi->audio_init) { + aud_aux_fifo.Header.Byte[0] = xhdmi->tx_audio_data->buffer[0]; + aud_aux_fifo.Header.Byte[1] = xhdmi->tx_audio_data->buffer[1]; + aud_aux_fifo.Header.Byte[2] = xhdmi->tx_audio_data->buffer[2]; + aud_aux_fifo.Header.Byte[3] = 0; + + aud_aux_fifo.Data.Byte[0] = xhdmi->tx_audio_data->buffer[3]; + aud_aux_fifo.Data.Byte[1] = xhdmi->tx_audio_data->buffer[4]; + aud_aux_fifo.Data.Byte[2] = xhdmi->tx_audio_data->buffer[5]; + aud_aux_fifo.Data.Byte[3] = xhdmi->tx_audio_data->buffer[6]; + aud_aux_fifo.Data.Byte[4] = xhdmi->tx_audio_data->buffer[7]; + aud_aux_fifo.Data.Byte[5] = xhdmi->tx_audio_data->buffer[8]; + + XV_HdmiTxSs_SendGenericAuxInfoframe(HdmiTxSsPtr, + &aud_aux_fifo); + } +} + +void TxBrdgUnlockedCallback(void *CallbackRef) +{ + /* When video out bridge lost lock, reset TPG */ + /* ResetTpg(); */ + /* Config and Run the TPG */ + /* XV_ConfigTpg(&Tpg); */ + struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)CallbackRef; + dev_dbg(xhdmi->dev,"TX Bridge Unlocked Callback\r\n"); +} + +void TxBrdgOverflowCallback(void *CallbackRef) +{ + struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)CallbackRef; + dev_dbg(xhdmi->dev,"TX Video Bridge Overflow\r\n"); +} + +void TxBrdgUnderflowCallback(void *CallbackRef) +{ + struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)CallbackRef; + dev_dbg(xhdmi->dev,"TX Video Bridge Underflow\r\n"); } void TxHdcpAuthenticatedCallback(void *CallbackRef) @@ -648,10 +788,15 @@ static void VphyHdmiTxInitCallback(void *CallbackRef) { struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)CallbackRef; XVphy *VphyPtr; + XHdmiphy1 *XGtPhyPtr; XV_HdmiTxSs *HdmiTxSsPtr; HdmiTxSsPtr = &xhdmi->xv_hdmitxss; - VphyPtr = xhdmi->xvphy; + + if (xhdmi->isvphy) + VphyPtr = xhdmi->xvphy; + else + XGtPhyPtr = xhdmi->xgtphy; dev_dbg(xhdmi->dev,"VphyHdmiTxInitCallback(): XV_HdmiTxSs_RefClockChangeInit()\n"); @@ -737,6 +882,33 @@ static int xlnx_drm_hdmi_connector_mode_valid(struct drm_connector *connector, enum drm_mode_status status = MODE_OK; dev_dbg(xhdmi->dev, "%s\n", __func__); + + /* This is done to make the functionality similar as BM code in which the + * timing table has vdisplay value of 540 for 1080i usecase. + * By this change, doing modetest -M xlnx, will give vdisplay 540 instead of + * 1080 */ + if(mode->flags & DRM_MODE_FLAG_INTERLACE) { + mode->vdisplay = mode->vdisplay / 2; + dev_dbg(xhdmi->dev, "For DRM_MODE_FLAG_INTERLACE, divide mode->vdisplay %d\n", mode->vdisplay); + } + + if((mode->flags & DRM_MODE_FLAG_DBLCLK) && (mode->flags & DRM_MODE_FLAG_INTERLACE)) { + mode->clock *= 2; + /* This logic is needed because the value of vrefresh is coming as zero for 480i@60 and 576i@50 + * because of which after multiplying the pixel clock by 2, the mode getting selected is 480i@120 + * 576i@100 from drm_edid.c file as this becomes the matching mode. + * Seems like bug in the kernel code for handling of DRM_MODE_FLAG_DBLCLK flag. + */ + if(mode->vrefresh == 0) + { + if(mode->vdisplay == 240) + mode->vrefresh = 60; + else if (mode->vdisplay == 288) + mode->vrefresh = 50; + } + dev_dbg(xhdmi->dev, "For DRM_MODE_FLAG_DBLCLK, multiply pixel_clk by 2, New pixel clock %d, refresh rate = %d\n", mode->clock, mode->vrefresh); + } + drm_mode_debug_printmodeline(mode); hdmi_mutex_lock(&xhdmi->hdmi_mutex); /* HDMI 2.0 sink connected? */ @@ -794,6 +966,7 @@ static int xlnx_drm_hdmi_connector_get_modes(struct drm_connector *connector) struct edid *edid = NULL; struct drm_display_info *info = &connector->display_info; int ret; + bool is_hdmi_sink; dev_dbg(xhdmi->dev, "%s\n", __func__); hdmi_mutex_lock(&xhdmi->hdmi_mutex); @@ -810,11 +983,22 @@ static int xlnx_drm_hdmi_connector_get_modes(struct drm_connector *connector) if (!edid) { xhdmi->have_edid = 0; dev_err(xhdmi->dev, "xlnx_drm_hdmi_get_modes() could not obtain edid, assume <= 1024x768 works.\n"); + drm_connector_update_edid_property(connector, NULL); return 0; } xhdmi->have_edid = 1; - drm_mode_connector_update_edid_property(connector, edid); + /* If the sink is non HDMI, set the stream type to DVI else HDMI */ + is_hdmi_sink = drm_detect_hdmi_monitor(edid); + if(is_hdmi_sink) { + XV_HdmiTxSs_SetVideoStreamType(&xhdmi->xv_hdmitxss, 1); + dev_dbg(xhdmi->dev, "EDID shows HDMI sink is connected, setting stream type to HDMI\n"); + } else { + XV_HdmiTxSs_SetVideoStreamType(&xhdmi->xv_hdmitxss, 0); + dev_dbg(xhdmi->dev, "EDID shows non HDMI sink is connected, setting stream type to DVI\n"); + } + + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); dev_dbg(xhdmi->dev, "xlnx_drm_hdmi_get_modes() done\n"); @@ -874,7 +1058,7 @@ static void xlnx_drm_hdmi_encoder_disable(struct drm_encoder *encoder) xlnx_drm_hdmi_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); } -static u32 hdmitx_find_media_bus(u32 drm_fourcc) +static u32 hdmitx_find_media_bus(struct xlnx_drm_hdmi *xhdmi, u32 drm_fourcc) { switch(drm_fourcc) { @@ -882,28 +1066,41 @@ static u32 hdmitx_find_media_bus(u32 drm_fourcc) case DRM_FORMAT_XRGB8888: case DRM_FORMAT_BGR888: case DRM_FORMAT_RGB888: + xhdmi->xvidc_colordepth = XVIDC_BPC_8; + return XVIDC_CSF_RGB; case DRM_FORMAT_XBGR2101010: + xhdmi->xvidc_colordepth = XVIDC_BPC_10; return XVIDC_CSF_RGB; case DRM_FORMAT_VUY888: case DRM_FORMAT_XVUY8888: case DRM_FORMAT_Y8: + xhdmi->xvidc_colordepth = XVIDC_BPC_8; + return XVIDC_CSF_YCRCB_444; case DRM_FORMAT_XVUY2101010: case DRM_FORMAT_Y10: + xhdmi->xvidc_colordepth = XVIDC_BPC_10; return XVIDC_CSF_YCRCB_444; case DRM_FORMAT_YUYV: //packed, 8b case DRM_FORMAT_UYVY: //packed, 8b case DRM_FORMAT_NV16: //semi-planar, 8b + xhdmi->xvidc_colordepth = XVIDC_BPC_8; + return XVIDC_CSF_YCRCB_422; case DRM_FORMAT_XV20: //semi-planar, 10b + xhdmi->xvidc_colordepth = XVIDC_BPC_10; return XVIDC_CSF_YCRCB_422; case DRM_FORMAT_NV12: //semi-planar, 8b + xhdmi->xvidc_colordepth = XVIDC_BPC_8; + return XVIDC_CSF_YCRCB_420; case DRM_FORMAT_XV15: //semi-planar, 10b + xhdmi->xvidc_colordepth = XVIDC_BPC_10; return XVIDC_CSF_YCRCB_420; default: - printk("Error: Unknown drm_fourcc format code: %d\n", drm_fourcc); + printk("Warning: Unknown drm_fourcc format code: %d\n", drm_fourcc); + xhdmi->xvidc_colordepth = XVIDC_BPC_UNKNOWN; return XVIDC_CSF_RGB; } } @@ -928,6 +1125,7 @@ static void xlnx_drm_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, XVidC_VideoTiming vt; XVphy *VphyPtr; + XHdmiphy1 *XGtPhyPtr; XV_HdmiTxSs *HdmiTxSsPtr; XVidC_VideoStream *HdmiTxSsVidStreamPtr; XHdmiC_AVI_InfoFrame *AviInfoFramePtr; @@ -936,20 +1134,23 @@ static void xlnx_drm_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, u32 PrevPhyTxRefClock = 0; u32 Result; u32 drm_fourcc; - XVidC_VideoMode VmId; XVidC_ColorDepth ColorDepth; int ret; dev_dbg(xhdmi->dev,"%s\n", __func__); HdmiTxSsPtr = &xhdmi->xv_hdmitxss; + VphyPtr = xhdmi->xvphy; + XGtPhyPtr = xhdmi->xgtphy; hdmi_mutex_lock(&xhdmi->hdmi_mutex); xvphy_mutex_lock(xhdmi->phy[0]); drm_mode_debug_printmodeline(mode); drm_fourcc = encoder->crtc->primary->state->fb->format->format; - xhdmi->xvidc_colorfmt = hdmitx_find_media_bus(drm_fourcc); + xhdmi->xvidc_colorfmt = hdmitx_find_media_bus(xhdmi, drm_fourcc); + dev_dbg(xhdmi->dev,"xvidc_colorfmt = %d\n", xhdmi->xvidc_colorfmt); + dev_dbg(xhdmi->dev,"xvidc_colordepth = %d\n", xhdmi->xvidc_colordepth); dev_dbg(xhdmi->dev,"mode->clock = %d\n", mode->clock * 1000); dev_dbg(xhdmi->dev,"mode->crtc_clock = %d\n", mode->crtc_clock * 1000); @@ -966,6 +1167,8 @@ static void xlnx_drm_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, dev_dbg(xhdmi->dev,"mode->htotal = %d\n", mode->htotal); dev_dbg(xhdmi->dev,"mode->vtotal = %d\n", mode->vtotal); dev_dbg(xhdmi->dev,"mode->vrefresh = %d\n", mode->vrefresh); + dev_dbg(xhdmi->dev,"mode->flags = %d interlace = %d\n", mode->flags, + !!(mode->flags & DRM_MODE_FLAG_INTERLACE)); /* see slide 20 of http://events.linuxfoundation.org/sites/events/files/slides/brezillon-drm-kms.pdf */ vt.HActive = mode->hdisplay; @@ -975,17 +1178,47 @@ static void xlnx_drm_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, vt.HTotal = mode->htotal; vt.HSyncPolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC); + /* Enable this code for debugging of NTSC and PAL resolution */ + if((((mode->hdisplay == 720) && (mode->vdisplay == 240) && (mode->vrefresh == 60)) || + ((mode->hdisplay == 720) && (mode->vdisplay == 288) && (mode->vrefresh == 50))) + && (mode->flags & DRM_MODE_FLAG_INTERLACE) && (mode->flags & DRM_MODE_FLAG_DBLCLK)) + { + dev_dbg(xhdmi->dev,"NTSC/PAL\n"); + vt.HActive *= 2; + vt.HFrontPorch *= 2; + vt.HSyncWidth *= 2; + vt.HBackPorch *= 2; + vt.HTotal *= 2; + } + vt.VActive = mode->vdisplay; /* Progressive timing data is stored in field 0 */ vt.F0PVFrontPorch = mode->vsync_start - mode->vdisplay; vt.F0PVSyncWidth = mode->vsync_end - mode->vsync_start; vt.F0PVBackPorch = mode->vtotal - mode->vsync_end; vt.F0PVTotal = mode->vtotal; - /* Interlaced output is not support - set field 1 to 0 */ - vt.F1VFrontPorch = 0; - vt.F1VSyncWidth = 0; - vt.F1VBackPorch = 0; - vt.F1VTotal = 0; + + if(mode->flags & DRM_MODE_FLAG_INTERLACE) { + dev_dbg(xhdmi->dev,"Programming fields for interlace"); + + vt.VActive = mode->vdisplay; + + vt.F0PVFrontPorch = (mode->vsync_start - (mode->vdisplay * 2)) / 2; + vt.F0PVSyncWidth = (mode->vsync_end - mode->vsync_start) / 2; + vt.F0PVBackPorch = (mode->vtotal - mode->vsync_end) / 2; + vt.F0PVTotal = mode->vdisplay + vt.F0PVFrontPorch + vt.F0PVSyncWidth + + vt.F0PVBackPorch; + + if((mode->vtotal - mode->vsync_end) % 2) + vt.F1VFrontPorch = 1 + (mode->vsync_start - (mode->vdisplay * 2)) / 2; + else + vt.F1VFrontPorch = (mode->vsync_start - (mode->vdisplay * 2)) / 2; + vt.F1VSyncWidth = (mode->vsync_end - mode->vsync_start) / 2; + vt.F1VBackPorch = (mode->vtotal - mode->vsync_end) / 2; + vt.F1VTotal = mode->vdisplay + vt.F1VFrontPorch + vt.F1VSyncWidth + + vt.F1VBackPorch; + } + vt.VSyncPolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC); HdmiTxSsVidStreamPtr = XV_HdmiTxSs_GetVideoStream(HdmiTxSsPtr); @@ -997,36 +1230,52 @@ static void xlnx_drm_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, // Reset Vendor Specific InfoFrame (void)memset((void *)VSIFPtr, 0, sizeof(XHdmiC_VSIF)); - /* Get current Tx Ref clock from PHY */ - PrevPhyTxRefClock = VphyPtr->HdmiTxRefClkHz; + if (xhdmi->isvphy) { + /* Get current Tx Ref clock from PHY */ + PrevPhyTxRefClock = VphyPtr->HdmiTxRefClkHz; - /* Disable TX TDMS clock */ - XVphy_Clkout1OBufTdsEnable(VphyPtr, XVPHY_DIR_TX, (FALSE)); + /* Disable TX TDMS clock */ + XVphy_Clkout1OBufTdsEnable(VphyPtr, XVPHY_DIR_TX, (FALSE)); + } else { + /* Get current Tx Ref clock from PHY */ + PrevPhyTxRefClock = XGtPhyPtr->HdmiTxRefClkHz; + + /* Disable TX TDMS clock */ + XHdmiphy1_Clkout1OBufTdsEnable(XGtPhyPtr, XHDMIPHY1_DIR_TX, (FALSE)); + } - VmId = XVidC_GetVideoModeIdExtensive(&vt, mode->vrefresh, FALSE, FALSE); + /* The isExtensive is made true to get the correct video timing by matching + * all the parameters */ + HdmiTxSsVidStreamPtr->VmId = XVidC_GetVideoModeIdExtensive(&vt, + mode->vrefresh, !!(mode->flags & DRM_MODE_FLAG_INTERLACE), TRUE); - dev_dbg(xhdmi->dev,"VmId = %d\n", VmId); - if (VmId == XVIDC_VM_NOT_SUPPORTED) { //no match found in timing table + dev_dbg(xhdmi->dev,"VmId = %d Interlaced = %d\n", HdmiTxSsVidStreamPtr->VmId, !!(mode->flags & DRM_MODE_FLAG_INTERLACE)); + if (HdmiTxSsVidStreamPtr->VmId == XVIDC_VM_NOT_SUPPORTED) { //no match found in timing table dev_dbg(xhdmi->dev,"Tx Video Mode not supported. Using DRM Timing\n"); - VmId = XVIDC_VM_CUSTOM; + HdmiTxSsVidStreamPtr->VmId = XVIDC_VM_CUSTOM; HdmiTxSsVidStreamPtr->FrameRate = mode->vrefresh; HdmiTxSsVidStreamPtr->Timing = vt; //overwrite with drm detected timing + HdmiTxSsVidStreamPtr->IsInterlaced = (!!(mode->flags & DRM_MODE_FLAG_INTERLACE)); #ifdef DEBUG - XVidC_ReportTiming(&HdmiTxSsVidStreamPtr->Timing, FALSE); + XVidC_ReportTiming(&HdmiTxSsVidStreamPtr->Timing, !!(mode->flags & DRM_MODE_FLAG_INTERLACE)); #endif } - ColorDepth = HdmiTxSsPtr->Config.MaxBitsPerPixel; + /* The value of xvidc_colordepth is set by calling hdmitx_find_media_bus() + * API earlier in this function. Check whether the value is valid or not */ + if (XVIDC_BPC_UNKNOWN == xhdmi->xvidc_colordepth) + xhdmi->xvidc_colordepth = HdmiTxSsPtr->Config.MaxBitsPerPixel; + /* check if resolution is supported at requested bit depth */ switch (xhdmi->xvidc_colorfmt) { case XVIDC_CSF_RGB: case XVIDC_CSF_YCRCB_444: - if ((ColorDepth > XVIDC_BPC_8) && + if ((xhdmi->xvidc_colordepth > XVIDC_BPC_8) && (mode->hdisplay >= 3840) && (mode->vdisplay >= 2160) && (mode->vrefresh >= XVIDC_FR_50HZ)) { dev_dbg(xhdmi->dev,"INFO> UHD only supports 24-bits color depth\n"); - ColorDepth = XVIDC_BPC_8; + xhdmi->xvidc_colordepth = XVIDC_BPC_8; } break; @@ -1034,28 +1283,50 @@ static void xlnx_drm_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, break; } - TmdsClock = XV_HdmiTxSs_SetStream(HdmiTxSsPtr, VmId, xhdmi->xvidc_colorfmt, - ColorDepth, NULL); + TmdsClock = XV_HdmiTxSs_SetStream(HdmiTxSsPtr, HdmiTxSsVidStreamPtr->VmId, xhdmi->xvidc_colorfmt, + xhdmi->xvidc_colordepth, NULL); //Update AVI InfoFrame AviInfoFramePtr->Version = 2; AviInfoFramePtr->ColorSpace = XV_HdmiC_XVidC_To_IfColorformat(xhdmi->xvidc_colorfmt); AviInfoFramePtr->VIC = HdmiTxSsPtr->HdmiTxPtr->Stream.Vic; + if ( (HdmiTxSsVidStreamPtr->VmId == XVIDC_VM_1440x480_60_I) || + (HdmiTxSsVidStreamPtr->VmId == XVIDC_VM_1440x576_50_I) ) { + AviInfoFramePtr->PixelRepetition = XHDMIC_PIXEL_REPETITION_FACTOR_2; + } else { + AviInfoFramePtr->PixelRepetition = XHDMIC_PIXEL_REPETITION_FACTOR_1; + } + // Set TX reference clock - VphyPtr->HdmiTxRefClkHz = TmdsClock; + if (xhdmi->isvphy) + VphyPtr->HdmiTxRefClkHz = TmdsClock; + else + XGtPhyPtr->HdmiTxRefClkHz = TmdsClock; + dev_dbg(xhdmi->dev,"(TmdsClock = %u, from XV_HdmiTxSs_SetStream())\n", TmdsClock); - dev_dbg(xhdmi->dev,"XVphy_SetHdmiTxParam(PixPerClk = %d, ColorDepth = %d, ColorFormatId=%d)\n", + if (xhdmi->isvphy) { + dev_dbg(xhdmi->dev,"XVphy_SetHdmiTxParam(PixPerClk = %d, ColorDepth = %d, ColorFormatId=%d)\n", (int)HdmiTxSsVidStreamPtr->PixPerClk, (int)HdmiTxSsVidStreamPtr->ColorDepth, (int)HdmiTxSsVidStreamPtr->ColorFormatId); - // Set GT TX parameters, this might change VphyPtr->HdmiTxRefClkHz - Result = XVphy_SetHdmiTxParam(VphyPtr, 0, XVPHY_CHANNEL_ID_CHA, + // Set GT TX parameters, this might change VphyPtr->HdmiTxRefClkHz + Result = XVphy_SetHdmiTxParam(VphyPtr, 0, XVPHY_CHANNEL_ID_CHA, HdmiTxSsVidStreamPtr->PixPerClk, HdmiTxSsVidStreamPtr->ColorDepth, HdmiTxSsVidStreamPtr->ColorFormatId); + } else { + dev_dbg(xhdmi->dev,"XHdmiphy1_SetHdmiTxParam(PixPerClk = %d, ColorDepth = %d, ColorFormatId=%d)\n", + (int)HdmiTxSsVidStreamPtr->PixPerClk, (int)HdmiTxSsVidStreamPtr->ColorDepth, + (int)HdmiTxSsVidStreamPtr->ColorFormatId); + // Set GT TX parameters, this might change XGtPhyPtr->HdmiTxRefClkHz + Result = XHdmiphy1_SetHdmiTxParam(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, + HdmiTxSsVidStreamPtr->PixPerClk, + HdmiTxSsVidStreamPtr->ColorDepth, + HdmiTxSsVidStreamPtr->ColorFormatId); + } if (Result == (XST_FAILURE)) { dev_dbg(xhdmi->dev,"Unable to set requested TX video resolution.\n\r"); xvphy_mutex_unlock(xhdmi->phy[0]); @@ -1063,7 +1334,11 @@ static void xlnx_drm_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, return; } - adjusted_mode->clock = VphyPtr->HdmiTxRefClkHz / 1000; + if (xhdmi->isvphy) + adjusted_mode->clock = VphyPtr->HdmiTxRefClkHz / 1000; + else + adjusted_mode->clock = XGtPhyPtr->HdmiTxRefClkHz / 1000; + dev_dbg(xhdmi->dev,"adjusted_mode->clock = %u Hz\n", adjusted_mode->clock); /* request required tmds clock rate */ @@ -1076,12 +1351,32 @@ static void xlnx_drm_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, * signal must be toggled (asserted and de-asserted) to reset phy's * internal frequency detection state machine */ - dev_dbg(xhdmi->dev,"PrevPhyTxRefClock: %d, NewRefClock: %d\n", PrevPhyTxRefClock, VphyPtr->HdmiTxRefClkHz); - if (PrevPhyTxRefClock == VphyPtr->HdmiTxRefClkHz) { - /* Switching between resolutions with same frequency */ - dev_dbg(xhdmi->dev,"***** Reset Phy Tx Frequency *******\n"); - XVphy_ClkDetFreqReset(VphyPtr, 0, XVPHY_DIR_TX); + if (xhdmi->isvphy) { + dev_dbg(xhdmi->dev,"PrevPhyTxRefClock: %d, NewRefClock: %d\n", PrevPhyTxRefClock, VphyPtr->HdmiTxRefClkHz); + if (PrevPhyTxRefClock == VphyPtr->HdmiTxRefClkHz) { + /* Switching between resolutions with same frequency */ + dev_dbg(xhdmi->dev,"***** Reset Phy Tx Frequency *******\n"); + XVphy_ClkDetFreqReset(VphyPtr, 0, XVPHY_DIR_TX); + } + } else { + dev_dbg(xhdmi->dev,"PrevPhyTxRefClock: %d, NewRefClock: %d\n", PrevPhyTxRefClock, XGtPhyPtr->HdmiTxRefClkHz); + if (PrevPhyTxRefClock == XGtPhyPtr->HdmiTxRefClkHz) { + /* Switching between resolutions with same frequency */ + dev_dbg(xhdmi->dev,"***** Reset Phy Tx Frequency *******\n"); + XHdmiphy1_ClkDetFreqReset(XGtPhyPtr, 0, XHDMIPHY1_DIR_TX); + } + } + + xhdmi->tx_audio_data->tmds_clk = clk_get_rate(xhdmi->tmds_clk); + /* if the mode is HDMI 2.0, use a multiplier value of 4 */ + if (HdmiTxSsPtr->HdmiTxPtr->Stream.TMDSClockRatio) { + xhdmi->tx_audio_data->tmds_clk = + xhdmi->tx_audio_data->tmds_clk * 4; + xhdmi->tx_audio_data->tmds_clk_ratio = true; + } else { + xhdmi->tx_audio_data->tmds_clk_ratio = false; } + xvphy_mutex_unlock(xhdmi->phy[0]); hdmi_mutex_unlock(&xhdmi->hdmi_mutex); } @@ -1363,10 +1658,16 @@ static ssize_t vphy_log_show(struct device *sysfs_dev, struct device_attribute * { ssize_t count; XVphy *VphyPtr; + XHdmiphy1 *XGtPhyPtr; struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)dev_get_drvdata(sysfs_dev); - VphyPtr = xhdmi->xvphy; - count = XVphy_LogShow(VphyPtr, buf, PAGE_SIZE); + if (xhdmi->isvphy) { + VphyPtr = xhdmi->xvphy; + count = XVphy_LogShow(VphyPtr, buf, PAGE_SIZE); + } else { + XGtPhyPtr = xhdmi->xgtphy; + count = XHdmiphy1_LogShow(XGtPhyPtr, buf, PAGE_SIZE); + } return count; } @@ -1375,12 +1676,20 @@ static ssize_t vphy_info_show(struct device *sysfs_dev, struct device_attribute { ssize_t count; XVphy *VphyPtr; + XHdmiphy1 *XGtPhyPtr; struct xlnx_drm_hdmi *xhdmi = (struct xlnx_drm_hdmi *)dev_get_drvdata(sysfs_dev); - VphyPtr = xhdmi->xvphy; - count = XVphy_HdmiDebugInfo(VphyPtr, 0, XVPHY_CHANNEL_ID_CHA, buf, PAGE_SIZE); - count += scnprintf(&buf[count], (PAGE_SIZE-count), "Tx Ref Clk: %0d Hz\n", + if (xhdmi->isvphy) { + VphyPtr = xhdmi->xvphy; + count = XVphy_HdmiDebugInfo(VphyPtr, 0, XVPHY_CHANNEL_ID_CHA, buf, PAGE_SIZE); + count += scnprintf(&buf[count], (PAGE_SIZE-count), "Tx Ref Clk: %0d Hz\n", XVphy_ClkDetGetRefClkFreqHz(xhdmi->xvphy, XVPHY_DIR_TX)); + } else { + XGtPhyPtr = xhdmi->xgtphy; + count = XHdmiphy1_HdmiDebugInfo(XGtPhyPtr, 0, XHDMIPHY1_CHANNEL_ID_CHA, buf, PAGE_SIZE); + count += scnprintf(&buf[count], (PAGE_SIZE-count), "Tx Ref Clk: %0d Hz\n", + XHdmiphy1_ClkDetGetRefClkFreqHz(xhdmi->xgtphy, XHDMIPHY1_DIR_TX)); + } return count; } @@ -1807,11 +2116,9 @@ static int xlnx_drm_hdmi_create_connector(struct drm_encoder *encoder) struct drm_connector *connector = &xhdmi->connector; int ret; - connector->polled = DRM_CONNECTOR_POLL_HPD | - DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT; + connector->polled = DRM_CONNECTOR_POLL_HPD; + connector->interlace_allowed = true; - connector->interlace_allowed = false; ret = drm_connector_init(encoder->dev, connector, &xlnx_drm_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -1826,10 +2133,10 @@ static int xlnx_drm_hdmi_create_connector(struct drm_encoder *encoder) dev_err(xhdmi->dev, "Failed to register the connector (ret=%d)\n", ret); return ret; } - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) { dev_err(xhdmi->dev, - "Failed to attch encoder to connector (ret=%d)\n", ret); + "Failed to attach encoder to connector (ret=%d)\n", ret); return ret; } @@ -1844,6 +2151,11 @@ static int xlnx_drm_hdmi_bind(struct device *dev, struct device *master, struct drm_device *drm_dev = data; int ret; + /* NOTE - "xlnx-drm" is the platform driver + * "xlnx" is drm driver (Xilinx DRM KMS Driver) + * In above case - drm_dev->driver->name = xlnx + */ + /* * TODO: The possible CRTCs are 1 now as per current implementation of * HDMI tx driver. DRM framework can support more than one CRTCs and @@ -1912,16 +2224,34 @@ static void xlnx_drm_hdmi_initialize(struct xlnx_drm_hdmi *xhdmi) TxStreamDownCallback, (void *)xhdmi); XV_HdmiTxSs_SetCallback(HdmiTxSsPtr, XV_HDMITXSS_HANDLER_VS, TxVsCallback, (void *)xhdmi); + XV_HdmiTxSs_SetCallback(HdmiTxSsPtr, XV_HDMITXSS_HANDLER_BRDGUNLOCK, + TxBrdgUnlockedCallback, (void *)xhdmi); + XV_HdmiTxSs_SetCallback(HdmiTxSsPtr, XV_HDMITXSS_HANDLER_BRDGOVERFLOW, + TxBrdgOverflowCallback, (void *)xhdmi); + XV_HdmiTxSs_SetCallback(HdmiTxSsPtr, XV_HDMITXSS_HANDLER_BRDGUNDERFLOW, + TxBrdgUnderflowCallback, (void *)xhdmi); /* get a reference to the XVphy data structure */ - xhdmi->xvphy = xvphy_get_xvphy(xhdmi->phy[0]); + if (xhdmi->isvphy) + xhdmi->xvphy = xvphy_get_xvphy(xhdmi->phy[0]); + else + xhdmi->xgtphy = xvphy_get_xvphy(xhdmi->phy[0]); + xvphy_mutex_lock(xhdmi->phy[0]); /* the callback is not specific to a single lane, but we need to * provide one of the phys as reference */ - XVphy_SetHdmiCallback(xhdmi->xvphy, XVPHY_HDMI_HANDLER_TXINIT, - VphyHdmiTxInitCallback, (void *)xhdmi); - XVphy_SetHdmiCallback(xhdmi->xvphy, XVPHY_HDMI_HANDLER_TXREADY, - VphyHdmiTxReadyCallback, (void *)xhdmi); + + if (xhdmi->isvphy) { + XVphy_SetHdmiCallback(xhdmi->xvphy, XVPHY_HDMI_HANDLER_TXINIT, + VphyHdmiTxInitCallback, (void *)xhdmi); + XVphy_SetHdmiCallback(xhdmi->xvphy, XVPHY_HDMI_HANDLER_TXREADY, + VphyHdmiTxReadyCallback, (void *)xhdmi); + } else { + XHdmiphy1_SetHdmiCallback(xhdmi->xgtphy, XHDMIPHY1_HDMI_HANDLER_TXINIT, + VphyHdmiTxInitCallback, (void *)xhdmi); + XHdmiphy1_SetHdmiCallback(xhdmi->xgtphy, XHDMIPHY1_HDMI_HANDLER_TXREADY, + VphyHdmiTxReadyCallback, (void *)xhdmi); + } xvphy_mutex_unlock(xhdmi->phy[0]); /* Request the interrupt */ @@ -1999,6 +2329,8 @@ static int xlnx_drm_hdmi_parse_of(struct xlnx_drm_hdmi *xhdmi, XV_HdmiTxSs_Confi isHdcp14_en = of_property_read_bool(node, "xlnx,include-hdcp-1-4"); isHdcp22_en = of_property_read_bool(node, "xlnx,include-hdcp-2-2"); + xhdmi->audio_enabled = + of_property_read_bool(node, "xlnx,audio-enabled"); if (isHdcp14_en) { /* HDCP14 Core */ @@ -2062,6 +2394,16 @@ static int xlnx_drm_hdmi_parse_of(struct xlnx_drm_hdmi *xhdmi, XV_HdmiTxSs_Confi } // set default color format to RGB xhdmi->xvidc_colorfmt = XVIDC_CSF_RGB; + + if (xhdmi->audio_enabled) { + xhdmi->tx_audio_data->acr_base = hdmitx_parse_aud_dt(dev); + if (!xhdmi->tx_audio_data->acr_base) { + xhdmi->audio_init = false; + dev_err(dev, "tx audio: acr base parse failed\n"); + } + } else { + dev_info(dev, "hdmi tx audio disabled in DT\n"); + } return 0; error_dt: @@ -2077,11 +2419,18 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) struct resource *res; unsigned long axi_clk_rate; - dev_info(&pdev->dev, "probed\n"); + dev_info(&pdev->dev, "probe started\n"); /* allocate zeroed HDMI TX device structure */ xhdmi = devm_kzalloc(&pdev->dev, sizeof(*xhdmi), GFP_KERNEL); if (!xhdmi) return -ENOMEM; + + xhdmi->tx_audio_data = + devm_kzalloc(&pdev->dev, sizeof(struct xlnx_hdmitx_audio_data), + GFP_KERNEL); + if (!xhdmi->tx_audio_data) + return -ENOMEM; + /* store pointer of the real device inside platform device */ xhdmi->dev = &pdev->dev; @@ -2107,6 +2456,13 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) /* acquire vphy lanes */ for (index = 0; index < 3; index++) { + static const struct of_device_id xlnx_hdmi_phy_id_table[] = { + { .compatible = "xlnx,hdmi-gt-controller-1.0", }, + { .compatible = "xlnx,vid-phy-controller-2.2", }, + { /* end of table */ }, + }; + const struct of_device_id *match; + char phy_name[16]; snprintf(phy_name, sizeof(phy_name), "hdmi-phy%d", index); xhdmi->phy[index] = devm_phy_get(xhdmi->dev, phy_name); @@ -2114,7 +2470,7 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) ret = PTR_ERR(xhdmi->phy[index]); xhdmi->phy[index] = NULL; if (ret == -EPROBE_DEFER) { - dev_info(xhdmi->dev, "xvphy not ready -EPROBE_DEFER\n"); + dev_info(xhdmi->dev, "xvphy/xgtphy not ready -EPROBE_DEFER\n"); return ret; } if (ret != -EPROBE_DEFER) @@ -2123,6 +2479,12 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) goto error_phy; } + match = of_match_node(xlnx_hdmi_phy_id_table, xhdmi->phy[index]->dev.parent->of_node); + if (strncmp(match->compatible, "xlnx,vid-phy-controller", 23) == 0) + xhdmi->isvphy = 1; + else + xhdmi->isvphy = 0; + ret = phy_init(xhdmi->phy[index]); if (ret) { dev_err(xhdmi->dev, @@ -2144,7 +2506,7 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) /* 4 clock sources to be acquired and enabled */ /* acquire video streaming bus clock */ - xhdmi->clk = devm_clk_get(xhdmi->dev, "video"); + xhdmi->clk = devm_clk_get(xhdmi->dev, "s_axis_video_aclk"); if (IS_ERR(xhdmi->clk)) { ret = PTR_ERR(xhdmi->clk); if (ret == -EPROBE_DEFER) @@ -2157,7 +2519,7 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) clk_prepare_enable(xhdmi->clk); /* acquire axi-lite register bus clock */ - xhdmi->axi_lite_clk = devm_clk_get(xhdmi->dev, "axi-lite"); + xhdmi->axi_lite_clk = devm_clk_get(xhdmi->dev, "s_axi_cpu_aclk"); if (IS_ERR(xhdmi->axi_lite_clk)) { ret = PTR_ERR(xhdmi->clk); if (ret == -EPROBE_DEFER) @@ -2196,6 +2558,7 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) return ret; } + xhdmi->tx_audio_data->tmds_clk = clk_get_rate(xhdmi->tmds_clk); /* support to drive an external retimer IC on the TX path, depending on TX clock line rate */ xhdmi->retimer_clk = devm_clk_get(&pdev->dev, "retimer-clk"); if (IS_ERR(xhdmi->retimer_clk)) { @@ -2241,16 +2604,16 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) } if (xhdmi->config.Hdcp14.IsPresent) { - xhdmi->hdcp1x_irq = platform_get_irq_byname(pdev, "hdcp1x"); + xhdmi->hdcp1x_irq = platform_get_irq_byname(pdev, "hdcp14_irq"); dev_dbg(xhdmi->dev,"xhdmi->hdcp1x_irq = %d\n", xhdmi->hdcp1x_irq); - xhdmi->hdcp1x_timer_irq = platform_get_irq_byname(pdev, "hdcp1x-timer"); + xhdmi->hdcp1x_timer_irq = platform_get_irq_byname(pdev, "hdcp14_timer_irq"); dev_dbg(xhdmi->dev,"xhdmi->hdcp1x_timer_irq = %d\n", xhdmi->hdcp1x_timer_irq); } if (xhdmi->config.Hdcp22.IsPresent) { - xhdmi->hdcp22_irq = platform_get_irq_byname(pdev, "hdcp22"); + xhdmi->hdcp22_irq = platform_get_irq_byname(pdev, "hdcp22_irq"); dev_dbg(xhdmi->dev,"xhdmi->hdcp22_irq = %d\n", xhdmi->hdcp22_irq); - xhdmi->hdcp22_timer_irq = platform_get_irq_byname(pdev, "hdcp22-timer"); + xhdmi->hdcp22_timer_irq = platform_get_irq_byname(pdev, "hdcp22_timer_irq"); dev_dbg(xhdmi->dev,"xhdmi->hdcp22_timer_irq = %d\n", xhdmi->hdcp22_timer_irq); } @@ -2273,6 +2636,16 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) /* probe has succeeded for this instance, increment instance index */ instance++; + if (xhdmi->audio_enabled && xhdmi->tx_audio_data->acr_base) { + xhdmi->audio_pdev = hdmitx_register_aud_dev(xhdmi->dev); + if (IS_ERR(xhdmi->audio_pdev)) { + xhdmi->audio_init = false; + dev_err(xhdmi->dev, "hdmi tx audio init failed\n"); + } else { + xhdmi->audio_init = true; + dev_info(xhdmi->dev, "hdmi tx audio initialized\n"); + } + } dev_info(xhdmi->dev, "probe successful\n"); return component_add(xhdmi->dev, &xlnx_drm_hdmi_component_ops); @@ -2292,12 +2665,59 @@ static int xlnx_drm_hdmi_probe(struct platform_device *pdev) static int xlnx_drm_hdmi_remove(struct platform_device *pdev) { struct platform_driver *pdrv; + struct xlnx_drm_hdmi *xhdmi = platform_get_drvdata(pdev); + if (xhdmi->audio_init) + platform_device_unregister(xhdmi->audio_pdev); sysfs_remove_group(&pdev->dev.kobj, &attr_group); component_del(&pdev->dev, &xlnx_drm_hdmi_component_ops); return 0; } +struct xlnx_hdmitx_audio_data *hdmitx_get_audio_data(struct device *dev) +{ + struct xlnx_drm_hdmi *xhdmi = dev_get_drvdata(dev); + + if (!xhdmi) + return NULL; + else + return xhdmi->tx_audio_data; +} + +void hdmitx_audio_startup(struct device *dev) +{ + XV_HdmiTxSs *HdmiTxSsPtr; + struct xlnx_drm_hdmi *xhdmi = dev_get_drvdata(dev); + XV_HdmiTxSs *xv_hdmitxss = (XV_HdmiTxSs *)&xhdmi->xv_hdmitxss; + + hdmi_mutex_lock(&xhdmi->hdmi_mutex); + XV_HdmiTxSs_AudioMute(xv_hdmitxss, 0); + hdmi_mutex_unlock(&xhdmi->hdmi_mutex); +} + +void hdmitx_audio_shutdown(struct device *dev) +{ + XV_HdmiTxSs *HdmiTxSsPtr; + struct xlnx_drm_hdmi *xhdmi = dev_get_drvdata(dev); + XV_HdmiTxSs *xv_hdmitxss = (XV_HdmiTxSs *)&xhdmi->xv_hdmitxss; + + hdmi_mutex_lock(&xhdmi->hdmi_mutex); + XV_HdmiTxSs_AudioMute(xv_hdmitxss, 1); + hdmi_mutex_unlock(&xhdmi->hdmi_mutex); +} + +void hdmitx_audio_mute(struct device *dev, bool enable) +{ + if (enable) + hdmitx_audio_shutdown(dev); + else + hdmitx_audio_startup(dev); +} + +static const struct dev_pm_ops xhdmitx_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(hdmitx_pm_suspend, hdmitx_pm_resume) +}; + static const struct of_device_id xlnx_drm_hdmi_of_match[] = { { .compatible = "xlnx,v-hdmi-tx-ss-3.1", }, { /* end of table */ }, @@ -2310,6 +2730,7 @@ static struct platform_driver xlnx_drm_hdmi_driver = { .driver = { .owner = THIS_MODULE, .name = "xlnx-drm-hdmi", + .pm = &xhdmitx_pm_ops, .of_match_table = xlnx_drm_hdmi_of_match, }, }; diff --git a/hdmi/xlnx_hdmirx_audio.c b/hdmi/xlnx_hdmirx_audio.c new file mode 100644 index 0000000..9c144be --- /dev/null +++ b/hdmi/xlnx_hdmirx_audio.c @@ -0,0 +1,112 @@ +/* + * Xilinx ALSA SoC HDMI audio capture support + * + * Copyright (C) 2017-2018 Xilinx, Inc. + * + * Author: Maruthi Srinivas Bayyavarapu + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include + +#include "xlnx_hdmirx_audio.h" + +#define XV_AES_ENABLE 0x8 + + +/* xlnx_rx_pcm_startup - initialze audio during audio usecase + * + * This function is called by ALSA framework before audio + * capture begins. + * + * Return: 0 on success + */ +static int xlnx_rx_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + u32 channels = hdmirx_audio_startup(dai->dev); + + if (!channels) + return -EINVAL; + + dev_info(dai->dev, + "Detected audio with channel count = %d, starting capture\n", + channels); + return 0; +} + +/* xlnx_rx_pcm_shutdown - Deinitialze audio when audio usecase is stopped + * + * This function is called by ALSA framework before audio capture usecase + * ends. + */ +static void xlnx_rx_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + hdmirx_audio_shutdown(dai->dev); +} + +static const struct snd_soc_dai_ops xlnx_rx_dai_ops = { + .startup = xlnx_rx_pcm_startup, + .shutdown = xlnx_rx_pcm_shutdown, +}; + +static struct snd_soc_dai_driver xlnx_rx_audio_dai = { + .name = "xlnx_hdmi_rx", + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &xlnx_rx_dai_ops, +}; + +static int xlnx_rx_codec_probe(struct snd_soc_component *component) +{ + return 0; +} + +void xlnx_rx_codec_remove(struct snd_soc_component *component) +{ +} + +static const struct snd_soc_component_driver xlnx_rx_codec_driver = { + .probe = xlnx_rx_codec_probe, + .remove = xlnx_rx_codec_remove, +}; + +/* hdmirx_register_aud_dev - register audio device + * + * This functions registers codec DAI device as part of + * ALSA SoC framework. + */ +int hdmirx_register_aud_dev(struct device *dev) +{ + return snd_soc_register_component(dev, &xlnx_rx_codec_driver, + &xlnx_rx_audio_dai, 1); +} + +/* hdmirx_register_aud_dev - register audio device + * + * This functions unregisters codec DAI device + */ +void hdmirx_unregister_aud_dev(struct device *dev) +{ + snd_soc_unregister_component(dev); +} + diff --git a/hdmi/xlnx_hdmirx_audio.h b/hdmi/xlnx_hdmirx_audio.h new file mode 100644 index 0000000..46a2710 --- /dev/null +++ b/hdmi/xlnx_hdmirx_audio.h @@ -0,0 +1,36 @@ +/* + * Xilinx ALSA SoC HDMI audio capture support + * + * Copyright (C) 2017-2018 Xilinx, Inc. + * + * Author: Maruthi Srinivas Bayyavarapu + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __XILINX_HDMI_RX_AUD_H__ +#define __XILINX_HDMI_RX_AUD_H__ + +#define XHDMI_AUDIO_DETECT_TIMEOUT 50 + +struct xlnx_hdmirx_audio_data *hdmirx_get_audio_data(struct device *dev); +int hdmirx_register_aud_dev(struct device *dev); +void hdmirx_unregister_aud_dev(struct device *dev); +u32 hdmirx_audio_startup(struct device *dev); +void hdmirx_audio_shutdown(struct device *dev); + +struct xlnx_hdmirx_audio_data { + void __iomem *aes_base; + bool audio_detected; + wait_queue_head_t audio_update_q; + int format; + u8 num_channels; +}; +#endif /* __XILINX_HDMI_RX_AUD_H__ */ diff --git a/hdmi/xlnx_hdmitx_audio.c b/hdmi/xlnx_hdmitx_audio.c new file mode 100644 index 0000000..03d0a8e --- /dev/null +++ b/hdmi/xlnx_hdmitx_audio.c @@ -0,0 +1,265 @@ +/* + * Xilinx ALSA SoC HDMI audio playback support + * + * Copyright (C) 2017-2018 Xilinx, Inc. + * + * Author: Maruthi Srinivas Bayyavarapu + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include + +#include "xlnx_hdmitx_audio.h" + +#define XV_ACR_ENABLE 0x4 +#define XV_ACR_N 0xc +#define ACR_CTRL_TMDSCLKRATIO BIT(3) + +struct acr_n_table { + u32 tmds_rate; + u32 acr_nval[7]; +}; + +/* N values for Audio Clock Regeneration */ +const struct acr_n_table acr_n_table[] = { + /* TMDSClk 32k 44k1 48k 88k2 96k 176k4 192k */ + { 0, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 25200000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 27000000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 31500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 33750000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 37800000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 40500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 50400000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 54000000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 67500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 74250000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 81000000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + { 92812500, { 8192, 6272, 12288, 12544, 24576, 25088, 49152} }, + {108000000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + {111375000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + {148500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + {185625000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + {222750000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + {297000000, { 3072, 4704, 5120, 9408, 10240, 18816, 20480} }, + {371250000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + {445500000, { 4096, 6272, 6144, 12544, 12288, 25088, 24576} }, + {594000000, { 3072, 9408, 6144, 18816, 12288, 37632, 24576} } +}; + +static u16 srate_to_index(u32 srate) +{ + u16 index; + + switch (srate) { + case 32000: + index = 0; + break; + case 44100: + index = 1; + break; + case 48000: + index = 2; + break; + case 88200: + index = 3; + break; + case 96000: + index = 4; + break; + case 176400: + index = 5; + break; + case 192000: + index = 6; + break; + default: + index = 0; + break; + } + + return index; +} + +/* xhdmi_acr_get_n - calculate N value from lookup table + * @tmds_rate: TMDS clock + * @srate: sampling rate + * + * This function retrieves N value from the lookup table using + * TMDS clock and sampling rate + * + * Return: N value + */ +static const unsigned int xhdmi_acr_get_n(unsigned int tmds_rate, int srate) +{ + struct acr_n_table const *item; + u16 i, idx; + + for (i = 0; i < sizeof(acr_n_table)/sizeof(struct acr_n_table); i++) { + item = &acr_n_table[i]; + if (item->tmds_rate == tmds_rate) { + idx = srate_to_index(srate); + return item->acr_nval[idx]; + } + } + + /* if not found return default */ + item = &acr_n_table[0]; + idx = srate_to_index(srate); + return item->acr_nval[idx]; +} + +/* hdmitx_parse_aud_dt - parse ACR node from DT + * @dev: device + * + * Parse the DT entry related to ACR IP. + */ +void __iomem *hdmitx_parse_aud_dt(struct device *dev) +{ + u32 val; + int rc; + struct device_node *node, *acr_node; + void __iomem *acr_base; + struct resource acr_res; + + node = dev->of_node; + acr_node = of_parse_phandle(node, "xlnx,xlnx-hdmi-acr-ctrl", 0); + if (!acr_node) { + dev_err(dev, "failed to get acr_node!\n"); + acr_base = NULL; + } else { + rc = of_address_to_resource(acr_node, 0, &acr_res); + if (rc) { + dev_err(dev, "acr resource failed: %d\n", rc); + acr_base = NULL; + } else { + acr_base = devm_ioremap_resource(dev, &acr_res); + if (IS_ERR(acr_base)) { + dev_err(dev, "acr ioremap failed\n"); + acr_base = NULL; + } + } + of_node_put(acr_node); + } + return acr_base; +} + +/* audio_codec_startup - initialze audio during audio usecase + * + * This function is called by ALSA framework before audio + * playback begins. This callback initializes audio + * + * Return: 0 on success + */ +static int audio_codec_startup(struct device *dev, void *data) +{ + hdmitx_audio_startup(dev); + + return 0; +} + +/* audio_codec_hw_params - sets the playback stream properties + * @dev: device + * @data: optional data set during registration + * @fmt: Protocol between ASoC cpu-dai and HDMI-encoder + * @hparams: stream parameters + * + * This function is called by ALSA framework after startup callback + * packs the audio infoframe from stream paremters and programs ACR + * block + * + * Return: 0 on success + */ +static int audio_codec_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparams) +{ + u32 n, i, val; + struct hdmi_audio_infoframe *frame = &hparams->cea; + struct xlnx_hdmitx_audio_data *adata = hdmitx_get_audio_data(dev); + + if (!adata) + return -EINVAL; + + hdmi_audio_infoframe_pack(&hparams->cea, adata->buffer, + HDMI_INFOFRAME_SIZE(AUDIO)); + + n = xhdmi_acr_get_n(adata->tmds_clk, hparams->sample_rate); + + /* Disable ACR */ + writel(2, adata->acr_base + XV_ACR_ENABLE); + /* program 'N' */ + writel(n, adata->acr_base + XV_ACR_N); + + val = 3; + if (adata->tmds_clk_ratio) + val |= ACR_CTRL_TMDSCLKRATIO; + + /* Enable ACR */ + writel(val, adata->acr_base + XV_ACR_ENABLE); + + return 0; +} + +/* audio_codec_shutdown - Deinitialze audio when audio usecase is stopped + * + * This function is called by ALSA framework before audio playback usecase + * ends. + */ +static void audio_codec_shutdown(struct device *dev, void *data) +{ + hdmitx_audio_shutdown(dev); +} + +/* audio_codec_digital_mute - mute or unmute audio + * + * This function is called by ALSA framework before audio usecase + * starts and before audio usecase ends + */ + +static int audio_codec_digital_mute(struct device *dev, void *data, bool enable) +{ + hdmitx_audio_mute(dev, enable); + + return 0; +} + +static const struct hdmi_codec_ops audio_ops = { + .audio_startup = audio_codec_startup, + .hw_params = audio_codec_hw_params, + .audio_shutdown = audio_codec_shutdown, + .digital_mute = audio_codec_digital_mute, +}; + +/* hdmitx_register_aud_dev - register audio device + * @dev: device + * + * This functions registers a new platform device and a corresponding + * module is loaded which registers a audio codec device and + * calls the registered callbacks + * + * Return: platform device + */ +struct platform_device *hdmitx_register_aud_dev(struct device *dev) +{ + struct platform_device *audio_pdev; + struct hdmi_codec_pdata codec_pdata = { + .ops = &audio_ops, + .i2s = 1, + .max_i2s_channels = 2, + }; + + audio_pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, + 0, &codec_pdata, sizeof(codec_pdata)); + + return audio_pdev; +} diff --git a/hdmi/xlnx_hdmitx_audio.h b/hdmi/xlnx_hdmitx_audio.h new file mode 100644 index 0000000..444e055 --- /dev/null +++ b/hdmi/xlnx_hdmitx_audio.h @@ -0,0 +1,36 @@ +/* + * Xilinx ALSA SoC HDMI audio playback support + * + * Copyright (C) 2017-2018 Xilinx, Inc. + * + * Author: Maruthi Srinivas Bayyavarapu + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __XILINX_HDMI_TX_AUD_H__ +#define __XILINX_HDMI_TX_AUD_H__ + +struct xlnx_hdmitx_audio_data { + u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)]; + unsigned int tmds_clk; + void __iomem *acr_base; + bool tmds_clk_ratio; +}; + +struct xlnx_hdmitx_audio_data *hdmitx_get_audio_data(struct device *dev); +void __iomem *hdmitx_parse_aud_dt(struct device *dev); +struct platform_device *hdmitx_register_aud_dev(struct device *dev); + +void hdmitx_audio_startup(struct device *dev); +void hdmitx_audio_shutdown(struct device *dev); +void hdmitx_audio_mute(struct device *dev, bool enable); + +#endif /* __XILINX_HDMI_TX_AUD_H__ */