ZC706 - AD9375 - JESD204

good afternoon, I'm using the HDL 2019_1 image, on the adrv 9375 debug board, an external 100MHz oscillator is connected instead of a 122.88 Mhz crystal oscillator, using the default JESD settings without changes. When booting Linux, I get the following error messages:

mmcblk0: mmc0:aaaa SC16G 14.8 GiB
mmcblk0: p1 p2 p3
axi_adxcvr 44a60000.axi-adxcvr-rx: AXI-ADXCVR-RX (17.01.a) using GTX2 at 0x44A60000 mapped to 0xf092a000. Number of lanes: 2.
axi_adxcvr 44a50000.axi-adxcvr-rx-os: AXI-ADXCVR-RX (17.01.a) using GTX2 at 0x44A50000 mapped to 0xf092c000. Number of lanes: 2.
axi_adxcvr 44a80000.axi-adxcvr-tx: AXI-ADXCVR-TX (17.01.a) using GTX2 at 0x44A80000 mapped to 0xf092e000. Number of lanes: 4.
axi_sysid 45000000.axi-sysid-0: [adrv9371x] on [zc706] git <2e4ac278eb09c13471e381459b0da790ebad8373> clean [2019-12-05 04:23:03] UTC
fpga_manager fpga0: Xilinx Zynq FPGA Manager registered
NET: Registered protocol family 17
Registering SWP/SWPB emulation handler
input: Genius USB Optical Mouse as /devices/soc0/amba/e0002000.usb/ci_hdrc.0/usb1/1-1/1-1:1.0/0003:0458:003A.0001/input/input0
hid-generic 0003:0458:003A.0001: input,hidraw0: USB HID v1.11 Mouse [Genius USB Optical Mouse] on usb-ci_hdrc.0-1/input0
Console: switching to colour frame buffer device 240x67
axi-hdmi 70e00000.axi_hdmi: fb0: frame buffer device
[drm] Initialized axi_hdmi_drm 1.0.0 20120930 for 70e00000.axi_hdmi on minor 0
ad9371 spi0.1: ad9371_probe : enter
ad9371 spi0.1: deframerStatus (0x61)
WARNING: 136: Mismatch detected in MYKONOS_jesd204bIlasCheck()
ad9371 spi0.1: ILAS mismatch: c7f8
ad9371 spi0.1: ILAS lanes per converter did not match
ad9371 spi0.1: ILAS scrambling did not match
ad9371 spi0.1: ILAS octets per frame did not match
ad9371 spi0.1: ILAS frames per multiframe did not match
ad9371 spi0.1: ILAS number of converters did not match
ad9371 spi0.1: ILAS sample resolution did not match
ad9371 spi0.1: ILAS control bits per sample did not match
ad9371 spi0.1: ILAS bits per sample did not match
ad9371 spi0.1: ILAS checksum did not match
ad9371 spi0.1: ad9371_probe : AD9375 Rev 4, Firmware 5.2.2 API version: 1.5.2.3566 successfully initialized

/***********************************************************************************************************************************/

root@analog:~# cat /sys/bus/platform/devices/44a90000.axi-jesd204-tx/status
Link is enabled
Measured Link Clock: 50.000 MHz
Reported Link Clock: 50.000 MHz
Lane rate: 2000.000 MHz
Lane rate / 40: 50.000 MHz
LMFC rate: 3.125 MHz
SYNC~: deasserted
Link status: ILAS
SYSREF captured: Yes
SYSREF alignment error: No

-------------------------------------------------------------------------------

root@analog:~# cat /sys/bus/platform/devices/44aa0000.axi-jesd204-rx/status
Link is enabled
Measured Link Clock: 100.000 MHz
Reported Link Clock: 100.000 MHz
Lane rate: 4000.000 MHz
Lane rate / 40: 100.000 MHz
LMFC rate: 3.125 MHz
Link status: DATA
SYSREF captured: Yes
SYSREF alignment error: No

------------------------------------------------------------------------------------------

root@analog:~# cat /sys/bus/platform/devices/44ab0000.axi-jesd204-rx/status
Link is enabled
Measured Link Clock: 50.000 MHz
Reported Link Clock: 50.000 MHz
Lane rate: 2000.000 MHz
Lane rate / 40: 50.000 MHz
LMFC rate: 3.125 MHz
Link status: DATA
SYSREF captured: Yes
SYSREF alignment error: No

/************************************************************************************************************************************/

how can i fix them? As I understand it is due to a change in the frequency of the reference generator?


3872.8176_system_dts.txt
/dts-v1/;

/ {
	#address-cells = <0x1>;
	#size-cells = <0x1>;
	compatible = "xlnx,zynq-7000";
	interrupt-parent = <0x1>;
	model = "Xilinx Zynq ZC706";

	cpus {
		#address-cells = <0x1>;
		#size-cells = <0x0>;

		cpu@0 {
			compatible = "arm,cortex-a9";
			device_type = "cpu";
			reg = <0x0>;
			clocks = <0x2 0x3>;
			clock-latency = <0x3e8>;
			cpu0-supply = <0x3>;
			operating-points = <0xa2c2b 0xf4240 0x51616 0xf4240>;
		};

		cpu@1 {
			compatible = "arm,cortex-a9";
			device_type = "cpu";
			reg = <0x1>;
			clocks = <0x2 0x3>;
		};
	};

	fpga-full {
		compatible = "fpga-region";
		fpga-mgr = <0x4>;
		#address-cells = <0x1>;
		#size-cells = <0x1>;
		ranges;
	};

	pmu@f8891000 {
		compatible = "arm,cortex-a9-pmu";
		interrupts = <0x0 0x5 0x4 0x0 0x6 0x4>;
		interrupt-parent = <0x1>;
		reg = <0xf8891000 0x1000 0xf8893000 0x1000>;
	};

	fixedregulator {
		compatible = "regulator-fixed";
		regulator-name = "VCCPINT";
		regulator-min-microvolt = <0xf4240>;
		regulator-max-microvolt = <0xf4240>;
		regulator-boot-on;
		regulator-always-on;
		linux,phandle = <0x3>;
		phandle = <0x3>;
	};

	amba {
		u-boot,dm-pre-reloc;
		compatible = "simple-bus";
		#address-cells = <0x1>;
		#size-cells = <0x1>;
		interrupt-parent = <0x1>;
		ranges;

		adc@f8007100 {
			compatible = "xlnx,zynq-xadc-1.00.a";
			reg = <0xf8007100 0x20>;
			interrupts = <0x0 0x7 0x4>;
			interrupt-parent = <0x1>;
			clocks = <0x2 0xc>;
		};

		can@e0008000 {
			compatible = "xlnx,zynq-can-1.0";
			status = "disabled";
			clocks = <0x2 0x13 0x2 0x24>;
			clock-names = "can_clk", "pclk";
			reg = <0xe0008000 0x1000>;
			interrupts = <0x0 0x1c 0x4>;
			interrupt-parent = <0x1>;
			tx-fifo-depth = <0x40>;
			rx-fifo-depth = <0x40>;
		};

		can@e0009000 {
			compatible = "xlnx,zynq-can-1.0";
			status = "disabled";
			clocks = <0x2 0x14 0x2 0x25>;
			clock-names = "can_clk", "pclk";
			reg = <0xe0009000 0x1000>;
			interrupts = <0x0 0x33 0x4>;
			interrupt-parent = <0x1>;
			tx-fifo-depth = <0x40>;
			rx-fifo-depth = <0x40>;
		};

		gpio@e000a000 {
			compatible = "xlnx,zynq-gpio-1.0";
			#gpio-cells = <0x2>;
			clocks = <0x2 0x2a>;
			gpio-controller;
			interrupt-controller;
			#interrupt-cells = <0x2>;
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x14 0x4>;
			reg = <0xe000a000 0x1000>;
			linux,phandle = <0x5>;
			phandle = <0x5>;
		};

		i2c@e0004000 {
			compatible = "cdns,i2c-r1p10";
			status = "disabled";
			clocks = <0x2 0x26>;
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x19 0x4>;
			reg = <0xe0004000 0x1000>;
			#address-cells = <0x1>;
			#size-cells = <0x0>;
		};

		i2c@e0005000 {
			compatible = "cdns,i2c-r1p10";
			status = "disabled";
			clocks = <0x2 0x27>;
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x30 0x4>;
			reg = <0xe0005000 0x1000>;
			#address-cells = <0x1>;
			#size-cells = <0x0>;
		};

		interrupt-controller@f8f01000 {
			compatible = "arm,cortex-a9-gic";
			#interrupt-cells = <0x3>;
			interrupt-controller;
			reg = <0xf8f01000 0x1000 0xf8f00100 0x100>;
			linux,phandle = <0x1>;
			phandle = <0x1>;
		};

		cache-controller@f8f02000 {
			compatible = "arm,pl310-cache";
			reg = <0xf8f02000 0x1000>;
			interrupts = <0x0 0x2 0x4>;
			arm,data-latency = <0x3 0x2 0x2>;
			arm,tag-latency = <0x2 0x2 0x2>;
			cache-unified;
			cache-level = <0x2>;
		};

		memory-controller@f8006000 {
			compatible = "xlnx,zynq-ddrc-a05";
			reg = <0xf8006000 0x1000>;
		};

		ocmc@f800c000 {
			compatible = "xlnx,zynq-ocmc-1.0";
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x3 0x4>;
			reg = <0xf800c000 0x1000>;
		};

		serial@e0000000 {
			compatible = "xlnx,xuartps", "cdns,uart-r1p8";
			status = "disabled";
			clocks = <0x2 0x17 0x2 0x28>;
			clock-names = "uart_clk", "pclk";
			reg = <0xe0000000 0x1000>;
			interrupts = <0x0 0x1b 0x4>;
		};

		serial@e0001000 {
			compatible = "xlnx,xuartps", "cdns,uart-r1p8";
			status = "okay";
			clocks = <0x2 0x18 0x2 0x29>;
			clock-names = "uart_clk", "pclk";
			reg = <0xe0001000 0x1000>;
			interrupts = <0x0 0x32 0x4>;
		};

		spi@e0006000 {
			compatible = "xlnx,zynq-spi-r1p6";
			reg = <0xe0006000 0x1000>;
			status = "okay";
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x1a 0x4>;
			clocks = <0x2 0x19 0x2 0x22>;
			clock-names = "ref_clk", "pclk";
			#address-cells = <0x1>;
			#size-cells = <0x0>;

			ad9528-1@0 {
				compatible = "adi,ad9528";
				reg = <0x0>;
				#address-cells = <0x1>;
				#size-cells = <0x0>;
				spi-max-frequency = <0x989680>;
				clock-output-names = "ad9528-1_out0", "ad9528-1_out1", "ad9528-1_out2", "ad9528-1_out3", "ad9528-1_out4", "ad9528-1_out5", "ad9528-1_out6", "ad9528-1_out7", "ad9528-1_out8", "ad9528-1_out9", "ad9528-1_out10", "ad9528-1_out11", "ad9528-1_out12", "ad9528-1_out13";
				#clock-cells = <0x1>;
				adi,vcxo-freq = <100000000>;
				adi,pll1-bypass-enable;
				adi,osc-in-diff-enable;

				adi,pll2-vco-div-m1 = <4>;
				adi,pll2-n2-div = <30>;
				adi,pll2-r1-div = <3>;
				adi,pll2-charge-pump-current-nA = <0xc4888>;

				adi,status-mon-pin0-function-select = <0x1>;
				adi,status-mon-pin1-function-select = <0x7>;
				reset-gpios = <0x5 0x71 0x0>;
				linux,phandle = <0x9>;
				phandle = <0x9>;

				channel@13 {
					reg = <0xd>;
					adi,extended-name = "DEV_CLK";
					adi,driver-mode = <0x0>;
					adi,divider-phase = <0x0>;
					adi,channel-divider = <0xA>;
					adi,signal-source = <0x0>;
				};

				channel@1 {
					reg = <0x1>;
					adi,extended-name = "FMC_CLK";
					adi,driver-mode = <0x0>;
					adi,divider-phase = <0x0>;
					adi,channel-divider = <0xA>;
					adi,signal-source = <0x0>;
				};

				channel@12 {
					reg = <0xc>;
					adi,extended-name = "DEV_SYSREF";
					adi,driver-mode = <0x0>;
					adi,divider-phase = <0x0>;
					adi,channel-divider = <0xA>;
					adi,signal-source = <0x2>;
				};

				channel@3 {
					reg = <0x3>;
					adi,extended-name = "FMC_SYSREF";
					adi,driver-mode = <0x0>;
					adi,divider-phase = <0x0>;
					adi,channel-divider = <0xA>;
					adi,signal-source = <0x2>;
				};
			};

			ad9371-phy@1 {
				compatible = "adi,ad9375";
				reg = <0x1>;
				spi-max-frequency = <0x17d7840>;
				clocks = <0x6 0x7 0x8 0x9 0xd 0x9 0x1 0x9 0xc 0x9 0x3>;
				clock-names = "jesd_rx_clk", "jesd_tx_clk", "jesd_rx_os_clk", "dev_clk", "fmc_clk", "sysref_dev_clk", "sysref_fmc_clk";
				clock-output-names = "rx_sampl_clk", "rx_os_sampl_clk", "tx_sampl_clk";
				#clock-cells = <0x1>;
				
				adi,clocks-clk-pll-vco-freq_khz = <12000000>;
				adi,clocks-device-clock_khz = <100000>;
				adi,clocks-clk-pll-hs-div = <4>;
				adi,clocks-clk-pll-vco-div = <3>;
				#adi,jesd204-obs-framer-over-sample = <>;

				adi,rx-profile-adc-div = <1>;
				adi,rx-profile-en-high-rej-dec5 = <1>;
				adi,rx-profile-iq-rate_khz = <100000>;
				adi,rx-profile-rf-bandwidth_hz = <80000000>;
				adi,rx-profile-rhb1-decimation = <1>;
				adi,rx-profile-rx-bbf-3db-corner_khz = <80000>;
				adi,rx-profile-rx-dec5-decimation = <5>;
				adi,rx-profile-rx-fir-decimation = <2>;
				adi,rx-profile-rx-fir-gain_db = <(-6)>;
				adi,rx-profile-rx-fir-num-fir-coefs = <48>;
				adi,rx-profile-rx-fir-coefs = /bits/ 16 <(-4) (-17) (23) (41) (-53) (-95) (117) (184) (-221) (-331) (389) (553) (-644) (-888) (1026) (1387) (-1608) (-2158) (2580) (3485) (-4786) (-7622) (9629) (32372) (32372) (9629) (-7622) (-4786) (3485) (2580) (-2158) (-1608) (1387) (1026) (-888) (-644) (553) (389) (-331) (-221) (184) (117) (-95) (-53) (41) (23) (-17) (-4)>;
				adi,rx-profile-custom-adc-profile =/bits/ 16 <660 473 201 98 1280 477 1587 269 1062 82 645 28 48 32 19 190>;

				adi,obs-profile-adc-div = <1>;
				adi,obs-profile-en-high-rej-dec5 = <1>;
				adi,obs-profile-iq-rate_khz = <100000>;
				adi,obs-profile-rf-bandwidth_hz = <80000000>;
				adi,obs-profile-rhb1-decimation = <1>;
				adi,obs-profile-rx-bbf-3db-corner_khz = <40000>;
				adi,obs-profile-rx-dec5-decimation = <5>;
				adi,obs-profile-rx-fir-decimation = <2>;
				adi,obs-profile-rx-fir-gain_db = <0>;
				adi,obs-profile-rx-fir-num-fir-coefs = <48>;
				adi,obs-profile-rx-fir-coefs = /bits/ 16 <(0) (-14) (12) (31) (-28) (-72) (67) (138) (-130) (-245) (235) (406) (-396) (-646) (640) (1003) (-1013) (-1559) (1636) (2557) (-2975) (-5752) (4332) (18454) (18454) (4332) (-5752) (-2975) (2557) (1636) (-1559) (-1013) (1003) (640) (-646) (-396) (406) (235) (-245) (-130) (138) (67) (-72) (-28) (31) (12) (-14) (0)>;
				adi,obs-profile-custom-adc-profile = /bits/ 16 <660 473 201 98 1280 477 1587 269 1062 82 645 28 48 32 19 190>;
				adi,obs-settings-custom-loopback-adc-profile = /bits/ 16 <737 439 201 98 1280 112 1505 53 1081 17 667 40 48 33 19 194>;
			

				adi,tx-profile-dac-div = <1>;/*2.5 = 1*/
				adi,tx-profile-iq-rate_khz = <100000>;
				adi,tx-profile-primary-sig-bandwidth_hz = <20000000>;
				adi,tx-profile-rf-bandwidth_hz = <80000000>;
				adi,tx-profile-thb1-interpolation = <1>;
				adi,tx-profile-thb2-interpolation = <2>;
				adi,tx-profile-tx-bbf-3db-corner_khz = <40000>;
				adi,tx-profile-tx-dac-3db-corner_khz = <92000>;
				adi,tx-profile-tx-fir-interpolation = <1>;
				adi,tx-profile-tx-input-hb-interpolation = <1>;
				adi,tx-profile-tx-fir-gain_db = <6>;
				adi,tx-profile-tx-fir-num-fir-coefs = <16>;
				adi,tx-profile-tx-fir-coefs = /bits/ 16 <(-37) (-192) (197) (-190) (-7) (816) (-2646) (20216) (-2646) (816) (-7) (-190) (197) (-192) (-37) (0)>;
				

				adi,sniffer-profile-adc-div = <1>;
				adi,sniffer-profile-en-high-rej-dec5 = <1>;
				adi,sniffer-profile-iq-rate_khz = <50000>;
				adi,sniffer-profile-rf-bandwidth_hz = <20000000>;
				adi,sniffer-profile-rhb1-decimation = <2>;
				adi,sniffer-profile-rx-bbf-3db-corner_khz = <20000>;
				adi,sniffer-profile-rx-dec5-decimation = <5>;
				adi,sniffer-profile-rx-fir-decimation = <2>;
				adi,sniffer-profile-custom-adc-profile = <0xfff30041 0x1d001d 0xffd6ffaa 0xff91ffd6 0x4b00c7 0xd9005f 0xff6bfe91 0xfe69ff54 0xfd027f 0x2be0134 0xfe63fbda 0xfb62fde5 0x29106e9 0x7ee03e4 0xfbc9f383 0xf073f6e1 0x78f1ead 0x34f942a3 0x42a334f9 0x1ead078f 0xf6e1f073 0xf383fbc9 0x3e407ee 0x6e90291 0xfde5fb62 0xfbdafe63 0x13402be 0x27f00fd 0xff54fe69 0xfe91ff6b 0x5f00d9 0xc7004b 0xffd6ff91 0xffaaffd6 0x1d001d 0x41fff3>;
				

				reset-gpios = <0x5 0x6a 0x0>;
				test-gpios = <0x5 0x6b 0x0>;
				sysref_req-gpios = <0x5 0x70 0x0>;
				rx2_enable-gpios = <0x5 0x6c 0x0>;
				rx1_enable-gpios = <0x5 0x6d 0x0>;
				tx2_enable-gpios = <0x5 0x6e 0x0>;
				tx1_enable-gpios = <0x5 0x6f 0x0>;
		
				linux,phandle = <0x13>;
				phandle = <0x13>;
			};
		};

		spi@e0007000 {
			compatible = "xlnx,zynq-spi-r1p6";
			reg = <0xe0007000 0x1000>;
			status = "disabled";
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x31 0x4>;
			clocks = <0x2 0x1a 0x2 0x23>;
			clock-names = "ref_clk", "pclk";
			#address-cells = <0x1>;
			#size-cells = <0x0>;
		};

		spi@e000d000 {
			clock-names = "ref_clk", "pclk";
			clocks = <0x2 0xa 0x2 0x2b>;
			compatible = "xlnx,zynq-qspi-1.0";
			status = "okay";
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x13 0x4>;
			reg = <0xe000d000 0x1000>;
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			is-dual = <0x1>;
			num-cs = <0x1>;

			ps7-qspi@0 {
				#address-cells = <0x1>;
				#size-cells = <0x1>;
				spi-tx-bus-width = <0x1>;
				spi-rx-bus-width = <0x4>;
				compatible = "n25q128a11";
				reg = <0x0>;
				spi-max-frequency = <0x2faf080>;

				partition@0 {
					label = "boot";
					reg = <0x0 0x500000>;
				};

				partition@500000 {
					label = "bootenv";
					reg = <0x500000 0x20000>;
				};

				partition@520000 {
					label = "config";
					reg = <0x520000 0x20000>;
				};

				partition@540000 {
					label = "image";
					reg = <0x540000 0xa80000>;
				};

				partition@fc0000 {
					label = "spare";
					reg = <0xfc0000 0x0>;
				};
			};
		};

		memory-controller@e000e000 {
			#address-cells = <0x1>;
			#size-cells = <0x1>;
			status = "disabled";
			clock-names = "memclk", "aclk";
			clocks = <0x2 0xb 0x2 0x2c>;
			compatible = "arm,pl353-smc-r2p1";
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x12 0x4>;
			ranges;
			reg = <0xe000e000 0x1000>;

			flash@e1000000 {
				status = "disabled";
				compatible = "arm,pl353-nand-r2p1";
				reg = <0xe1000000 0x1000000>;
				#address-cells = <0x1>;
				#size-cells = <0x1>;
			};

			flash@e2000000 {
				status = "disabled";
				compatible = "cfi-flash";
				reg = <0xe2000000 0x2000000>;
				#address-cells = <0x1>;
				#size-cells = <0x1>;
			};
		};

		ethernet@e000b000 {
			compatible = "cdns,zynq-gem", "cdns,gem";
			reg = <0xe000b000 0x1000>;
			status = "okay";
			interrupts = <0x0 0x16 0x4>;
			clocks = <0x2 0x1e 0x2 0x1e 0x2 0xd>;
			clock-names = "pclk", "hclk", "tx_clk";
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			phy-handle = <0xa>;
			phy-mode = "rgmii-id";

			phy@7 {
				device_type = "ethernet-phy";
				reg = <0x7>;
				linux,phandle = <0xa>;
				phandle = <0xa>;
			};
		};

		ethernet@e000c000 {
			compatible = "cdns,zynq-gem", "cdns,gem";
			reg = <0xe000c000 0x1000>;
			status = "disabled";
			interrupts = <0x0 0x2d 0x4>;
			clocks = <0x2 0x1f 0x2 0x1f 0x2 0xe>;
			clock-names = "pclk", "hclk", "tx_clk";
			#address-cells = <0x1>;
			#size-cells = <0x0>;
		};

		mmc@e0100000 {
			compatible = "arasan,sdhci-8.9a";
			status = "okay";
			clock-names = "clk_xin", "clk_ahb";
			clocks = <0x2 0x15 0x2 0x20>;
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x18 0x4>;
			reg = <0xe0100000 0x1000>;
		};

		mmc@e0101000 {
			compatible = "arasan,sdhci-8.9a";
			status = "disabled";
			clock-names = "clk_xin", "clk_ahb";
			clocks = <0x2 0x16 0x2 0x21>;
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x2f 0x4>;
			reg = <0xe0101000 0x1000>;
		};

		slcr@f8000000 {
			u-boot,dm-pre-reloc;
			#address-cells = <0x1>;
			#size-cells = <0x1>;
			compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";
			reg = <0xf8000000 0x1000>;
			ranges;
			linux,phandle = <0xb>;
			phandle = <0xb>;

			clkc@100 {
				u-boot,dm-pre-reloc;
				#clock-cells = <0x1>;
				compatible = "xlnx,ps7-clkc";
				fclk-enable = <0xf>;
				clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", "lqspi", "smc", "pcap", "gem0", "gem1", "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", "swdt", "dbg_trc", "dbg_apb";
				reg = <0x100 0x100>;
				ps-clk-frequency = <0x1fca055>;
				linux,phandle = <0x2>;
				phandle = <0x2>;
			};

			rstc@200 {
				compatible = "xlnx,zynq-reset";
				reg = <0x200 0x48>;
				#reset-cells = <0x1>;
				syscon = <0xb>;
			};

			pinctrl@700 {
				compatible = "xlnx,pinctrl-zynq";
				reg = <0x700 0x200>;
				syscon = <0xb>;
			};
		};

		dmac@f8003000 {
			compatible = "arm,pl330", "arm,primecell";
			reg = <0xf8003000 0x1000>;
			interrupt-parent = <0x1>;
			interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6", "dma7";
			interrupts = <0x0 0xd 0x4 0x0 0xe 0x4 0x0 0xf 0x4 0x0 0x10 0x4 0x0 0x11 0x4 0x0 0x28 0x4 0x0 0x29 0x4 0x0 0x2a 0x4 0x0 0x2b 0x4>;
			#dma-cells = <0x1>;
			#dma-channels = <0x8>;
			#dma-requests = <0x4>;
			clocks = <0x2 0x1b>;
			clock-names = "apb_pclk";
			linux,phandle = <0x10>;
			phandle = <0x10>;
		};

		devcfg@f8007000 {
			compatible = "xlnx,zynq-devcfg-1.0";
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x8 0x4>;
			reg = <0xf8007000 0x100>;
			clocks = <0x2 0xc 0x2 0xf 0x2 0x10 0x2 0x11 0x2 0x12>;
			clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
			syscon = <0xb>;
			linux,phandle = <0x4>;
			phandle = <0x4>;
		};

		efuse@f800d000 {
			compatible = "xlnx,zynq-efuse";
			reg = <0xf800d000 0x20>;
		};

		timer@f8f00200 {
			compatible = "arm,cortex-a9-global-timer";
			reg = <0xf8f00200 0x20>;
			interrupts = <0x1 0xb 0x301>;
			interrupt-parent = <0x1>;
			clocks = <0x2 0x4>;
		};

		timer@f8001000 {
			interrupt-parent = <0x1>;
			interrupts = <0x0 0xa 0x4 0x0 0xb 0x4 0x0 0xc 0x4>;
			compatible = "cdns,ttc";
			clocks = <0x2 0x6>;
			reg = <0xf8001000 0x1000>;
		};

		timer@f8002000 {
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x25 0x4 0x0 0x26 0x4 0x0 0x27 0x4>;
			compatible = "cdns,ttc";
			clocks = <0x2 0x6>;
			reg = <0xf8002000 0x1000>;
		};

		timer@f8f00600 {
			interrupt-parent = <0x1>;
			interrupts = <0x1 0xd 0x301>;
			compatible = "arm,cortex-a9-twd-timer";
			reg = <0xf8f00600 0x20>;
			clocks = <0x2 0x4>;
		};

		usb@e0002000 {
			compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
			status = "okay";
			clocks = <0x2 0x1c>;
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x15 0x4>;
			reg = <0xe0002000 0x1000>;
			phy_type = "ulpi";
			dr_mode = "host";
			xlnx,phy-reset-gpio = <0x5 0x7 0x0>;
		};

		usb@e0003000 {
			compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
			status = "disabled";
			clocks = <0x2 0x1d>;
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x2c 0x4>;
			reg = <0xe0003000 0x1000>;
			phy_type = "ulpi";
		};

		watchdog@f8005000 {
			clocks = <0x2 0x2d>;
			compatible = "cdns,wdt-r1p2";
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x9 0x1>;
			reg = <0xf8005000 0x1000>;
			timeout-sec = <0xa>;
		};
	};

	aliases {
		ethernet0 = "/amba/ethernet@e000b000";
		serial0 = "/amba/serial@e0001000";
	};

	memory {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	chosen {
		bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait";
		linux,stdout-path = "/amba@0/uart@E0001000";
	};

	leds {
		compatible = "gpio-leds";

		ds8 {
			label = "ds12:green";
			gpios = <0x5 0x3d 0x0>;
		};

		ds9 {
			label = "ds15:green";
			gpios = <0x5 0x3e 0x0>;
		};

		ds10 {
			label = "ds16:green";
			gpios = <0x5 0x3f 0x0>;
		};

		ds35 {
			label = "ds17:green";
			gpios = <0x5 0x40 0x0>;
		};
	};

	gpio_keys {
		compatible = "gpio-keys";
		#address-cells = <0x1>;
		#size-cells = <0x0>;
		autorepeat;

		sw7 {
			label = "Left";
			linux,code = <0x69>;
			gpios = <0x5 0x3a 0x0>;
		};

		sw8 {
			label = "Right";
			linux,code = <0x6a>;
			gpios = <0x5 0x3c 0x0>;
		};

		sw9 {
			label = "Select";
			linux,code = <0x1c>;
			gpios = <0x5 0x3b 0x0>;
		};
	};

	fpga-axi@0 {
		compatible = "simple-bus";
		#address-cells = <0x1>;
		#size-cells = <0x1>;
		ranges;

		i2c@41600000 {
			compatible = "xlnx,axi-iic-1.02.a", "xlnx,xps-iic-2.00.a";
			reg = <0x41600000 0x10000>;
			interrupt-parent = <0x1>;
			interrupts = <0x0 0x3a 0x4>;
			clocks = <0x2 0xf>;
			clock-names = "pclk";
			#address-cells = <0x1>;
			#size-cells = <0x0>;

			i2cswitch@74 {
				compatible = "nxp,pca9548";
				#address-cells = <0x1>;
				#size-cells = <0x0>;
				reg = <0x74>;

				i2c@0 {
					#address-cells = <0x1>;
					#size-cells = <0x0>;
					reg = <0x0>;

					osc@5d {
						compatible = "si570";
						temperature-stability = <0x32>;
						reg = <0x5d>;
						factory-fout = <0x9502f90>;
						initial-fout = <0x8d9ee20>;
					};
				};

				i2c@1 {
					#address-cells = <0x1>;
					#size-cells = <0x0>;
					reg = <0x1>;

					adv7511 {
						compatible = "adi,adv7511";
						reg = <0x39 0x3f>;
						reg-names = "primary", "edid";
						adi,input-depth = <0x8>;
						adi,input-colorspace = "rgb";
						adi,input-clock = "1x";
						adi,clock-delay = <0x0>;
						#sound-dai-cells = <0x0>;
						linux,phandle = <0x1d>;
						phandle = <0x1d>;

						ports {
							#address-cells = <0x1>;
							#size-cells = <0x0>;

							port@0 {
								reg = <0x0>;

								endpoint {
									remote-endpoint = <0xc>;
									linux,phandle = <0xf>;
									phandle = <0xf>;
								};
							};

							port@1 {
								reg = <0x1>;
							};
						};
					};
				};

				i2c@2 {
					#address-cells = <0x1>;
					#size-cells = <0x0>;
					reg = <0x2>;

					eeprom@54 {
						compatible = "at,24c08";
						reg = <0x54>;
					};
				};

				i2c@3 {
					#address-cells = <0x1>;
					#size-cells = <0x0>;
					reg = <0x3>;

					gpio@21 {
						compatible = "ti,tca6416";
						reg = <0x21>;
						gpio-controller;
						#gpio-cells = <0x2>;
					};
				};

				i2c@4 {
					#address-cells = <0x1>;
					#size-cells = <0x0>;
					reg = <0x4>;

					rtc@54 {
						compatible = "nxp,pcf8563";
						reg = <0x51>;
					};
				};

				i2c@5 {
					#address-cells = <0x1>;
					#size-cells = <0x0>;
					reg = <0x5>;

					eeprom@50 {
						compatible = "at24,24c02";
						reg = <0x50>;
					};

					eeprom@54 {
						compatible = "at24,24c02";
						reg = <0x54>;
					};

					ad7291@2f {
						compatible = "adi,ad7291";
						reg = <0x2f>;
					};
				};
			};
		};

		dma@43000000 {
			compatible = "adi,axi-dmac-1.00.a";
			reg = <0x43000000 0x10000>;
			#dma-cells = <0x1>;
			interrupts = <0x0 0x3b 0x0>;
			clocks = <0x2 0x10>;
			linux,phandle = <0xd>;
			phandle = <0xd>;

			adi,channels {
				#size-cells = <0x0>;
				#address-cells = <0x1>;

				dma-channel@0 {
					reg = <0x0>;
					adi,source-bus-width = <0x40>;
					adi,source-bus-type = <0x0>;
					adi,destination-bus-width = <0x40>;
					adi,destination-bus-type = <0x1>;
				};
			};
		};

		axi-clkgen@79000000 {
			compatible = "adi,axi-clkgen-2.00.a";
			reg = <0x79000000 0x10000>;
			#clock-cells = <0x0>;
			clocks = <0x2 0x10>;
			linux,phandle = <0xe>;
			phandle = <0xe>;
		};

		axi_hdmi@70e00000 {
			compatible = "adi,axi-hdmi-tx-1.00.a";
			reg = <0x70e00000 0x10000>;
			dmas = <0xd 0x0>;
			dma-names = "video";
			clocks = <0xe>;
			adi,is-rgb;

			port {

				endpoint {
					remote-endpoint = <0xf>;
					linux,phandle = <0xc>;
					phandle = <0xc>;
				};
			};
		};

		axi-spdif-tx@75c00000 {
			compatible = "adi,axi-spdif-tx-1.00.a";
			reg = <0x75c00000 0x1000>;
			dmas = <0x10 0x0>;
			dma-names = "tx";
			clocks = <0x2 0xf 0x11>;
			clock-names = "axi", "ref";
			#sound-dai-cells = <0x0>;
			linux,phandle = <0x1c>;
			phandle = <0x1c>;
		};

		axi-sysid-0@45000000 {
			compatible = "adi,axi-sysid-1.00.a";
			reg = <0x45000000 0x10000>;
		};

		rx-dmac@7c400000 {
			compatible = "adi,axi-dmac-1.00.a";
			reg = <0x7c400000 0x10000>;
			#dma-cells = <0x1>;
			interrupts = <0x0 0x39 0x0>;
			clocks = <0x2 0x10>;
			linux,phandle = <0x12>;
			phandle = <0x12>;

			adi,channels {
				#size-cells = <0x0>;
				#address-cells = <0x1>;

				dma-channel@0 {
					reg = <0x0>;
					adi,source-bus-width = <0x40>;
					adi,source-bus-type = <0x2>;
					adi,destination-bus-width = <0x40>;
					adi,destination-bus-type = <0x0>;
				};
			};
		};

		rx-obs-dmac@7c440000 {
			compatible = "adi,axi-dmac-1.00.a";
			reg = <0x7c440000 0x10000>;
			#dma-cells = <0x1>;
			interrupts = <0x0 0x37 0x0>;
			clocks = <0x2 0x10>;
			linux,phandle = <0x14>;
			phandle = <0x14>;

			adi,channels {
				#size-cells = <0x0>;
				#address-cells = <0x1>;

				dma-channel@0 {
					reg = <0x0>;
					adi,source-bus-width = <0x40>;
					adi,source-bus-type = <0x2>;
					adi,destination-bus-width = <0x40>;
					adi,destination-bus-type = <0x0>;
				};
			};
		};

		tx-dmac@7c420000 {
			compatible = "adi,axi-dmac-1.00.a";
			reg = <0x7c420000 0x10000>;
			#dma-cells = <0x1>;
			interrupts = <0x0 0x38 0x0>;
			clocks = <0x2 0x10>;
			linux,phandle = <0x15>;
			phandle = <0x15>;

			adi,channels {
				#size-cells = <0x0>;
				#address-cells = <0x1>;

				dma-channel@0 {
					reg = <0x0>;
					adi,source-bus-width = <0x40>;
					adi,source-bus-type = <0x0>;
					adi,destination-bus-width = <0x80>;
					adi,destination-bus-type = <0x1>;
				};
			};
		};

		axi-ad9371-rx-hpc@44a00000 {
			compatible = "adi,axi-ad9371-rx-1.0";
			reg = <0x44a00000 0x8000>;
			dmas = <0x12 0x0>;
			dma-names = "rx";
			spibus-connected = <0x13>;
			adi,axi-decimation-core-available;
			decimation-gpios = <0x5 0x73 0x0>;
		};

		axi-ad9371-rx-obs-hpc@44a08000 {
			compatible = "adi,axi-ad9371-obs-1.0";
			reg = <0x44a08000 0x1000>;
			dmas = <0x14 0x0>;
			dma-names = "rx";
			clocks = <0x13 0x1>;
			clock-names = "sampl_clk";
		};

		axi-ad9371-tx-hpc@44a04000 {
			compatible = "adi,axi-ad9371-tx-1.0";
			reg = <0x44a04000 0x4000>;
			dmas = <0x15 0x0>;
			dma-names = "tx";
			clocks = <0x13 0x2>;
			clock-names = "sampl_clk";
			spibus-connected = <0x13>;
			adi,axi-pl-fifo-enable;
			adi,axi-interpolation-core-available;
			interpolation-gpios = <0x5 0x74 0x0>;
			plddrbypass-gpios = <0x5 0x72 0x0>;
		};

		axi-jesd204-rx@44aa0000 {
			compatible = "adi,axi-jesd204-rx-1.0";
			reg = <0x44aa0000 0x1000>;
			interrupts = <0x0 0x36 0x0>;
			clocks = <0x2 0x10 0x16 0x17 0x0>;
			clock-names = "s_axi_aclk", "device_clk", "lane_clk";
			#clock-cells = <0x0>;
			clock-output-names = "jesd_rx_lane_clk";

			adi,octets-per-frame = <0x4>;
			adi,frames-per-multiframe = <0x20>;
			
					linux,phandle = <0x6>;
			phandle = <0x6>;
		};

		axi-jesd204-tx@44a90000 {
			compatible = "adi,axi-jesd204-tx-1.0";
			reg = <0x44a90000 0x1000>;
			interrupts = <0x0 0x35 0x0>;
			clocks = <0x2 0x10 0x18 0x19 0x0>;
			clock-names = "s_axi_aclk", "device_clk", "lane_clk";
			#clock-cells = <0x0>;
			clock-output-names = "jesd_tx_lane_clk";
			
			adi,octets-per-frame = <0x2>;
			adi,frames-per-multiframe = <0x20>;
			adi,converter-resolution = <0xe>;
			adi,bits-per-sample = <0x10>;
			adi,converters-per-device = <0x4>;
			adi,control-bits-per-sample = <0x2>;
			
					
			linux,phandle = <0x7>;
			phandle = <0x7>;
		};

		axi-jesd204-rx@44ab0000 {
			compatible = "adi,axi-jesd204-rx-1.0";
			reg = <0x44ab0000 0x1000>;
			interrupts = <0x0 0x34 0x0>;
			clocks = <0x2 0x10 0x1a 0x1b 0x0>;
			clock-names = "s_axi_aclk", "device_clk", "lane_clk";
			#clock-cells = <0x0>;
			clock-output-names = "jesd_rx_os_lane_clk";
			
			adi,octets-per-frame = <0x2>;
			adi,frames-per-multiframe = <0x20>;

			linux,phandle = <0x8>;
			phandle = <0x8>;
		};

		axi-clkgen@43c00000 {
			compatible = "adi,axi-clkgen-2.00.a";
			reg = <0x43c00000 0x10000>;
			#clock-cells = <0x0>;
			clocks = <0x9 0x1>;
			clock-output-names = "axi_tx_clkgen";
			linux,phandle = <0x18>;
			phandle = <0x18>;
		};

		axi-clkgen@43c10000 {
			compatible = "adi,axi-clkgen-2.00.a";
			reg = <0x43c10000 0x10000>;
			#clock-cells = <0x0>;
			clocks = <0x9 0x1>;
			clock-output-names = "axi_rx_clkgen";
			linux,phandle = <0x16>;
			phandle = <0x16>;
		};

		axi-clkgen@43c20000 {
			compatible = "adi,axi-clkgen-2.00.a";
			reg = <0x43c20000 0x10000>;
			#clock-cells = <0x0>;
			clocks = <0x9 0x1>;
			clock-output-names = "axi_rx_os_clkgen";
			linux,phandle = <0x1a>;
			phandle = <0x1a>;
		};

		axi-adxcvr-rx@44a60000 {
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			compatible = "adi,axi-adxcvr-1.0";
			reg = <0x44a60000 0x1000>;
			clocks = <0x9 0x1 0x16 0x0>;
			clock-names = "conv", "div40";
			#clock-cells = <0x1>;
			clock-output-names = "rx_gt_clk", "rx_out_clk";
			adi,sys-clk-select = <0x0>;
			adi,out-clk-select = <0x3>;
			adi,use-lpm-enable;
			adi,use-cpll-enable;
			linux,phandle = <0x17>;
			phandle = <0x17>;
		};

		axi-adxcvr-rx-os@44a50000 {
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			compatible = "adi,axi-adxcvr-1.0";
			reg = <0x44a50000 0x1000>;
			clocks = <0x9 0x1 0x1a>;
			clock-names = "conv", "div40";
			#clock-cells = <0x1>;
			clock-output-names = "rx_os_gt_clk", "rx_os_out_clk";
			adi,sys-clk-select = <0x0>;
			adi,out-clk-select = <0x3>;
			adi,use-lpm-enable;
			adi,use-cpll-enable;
			linux,phandle = <0x1b>;
			phandle = <0x1b>;
		};

		axi-adxcvr-tx@44a80000 {
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			compatible = "adi,axi-adxcvr-1.0";
			reg = <0x44a80000 0x1000>;
			clocks = <0x9 0x1 0x18>;
			clock-names = "conv", "div40";
			#clock-cells = <0x1>;
			clock-output-names = "tx_gt_clk", "tx_out_clk";
			adi,sys-clk-select = <0x3>;
			adi,out-clk-select = <0x3>;
			linux,phandle = <0x19>;
			phandle = <0x19>;
		};
	};

	audio_clock {
		compatible = "fixed-clock";
		#clock-cells = <0x0>;
		clock-frequency = <0xbb8000>;
		linux,phandle = <0x11>;
		phandle = <0x11>;
	};

	adv7511_hdmi_snd {
		compatible = "simple-audio-card";
		simple-audio-card,name = "HDMI monitor";
		simple-audio-card,widgets = "Speaker", "Speaker";
		simple-audio-card,routing = "Speaker", "TX";

		simple-audio-card,dai-link@0 {
			format = "spdif";

			cpu {
				sound-dai = <0x1c>;
				frame-master;
				bitclock-master;
			};

			codec {
				sound-dai = <0x1d>;
			};
		};
	};
};

Parents
No Data
Reply
  • xilinx_transceiver_c.txt
    /*
     * Xilinx High-speed tranceiver dynamic reconfiguration
     *
     * Copyright 2016-2017 Analog Devices Inc.
     *
     * Licensed under the GPL-2.
     *
     */
    
    #include <linux/device.h>
    #include <linux/fpga/adi-axi-common.h>
    #include <linux/kernel.h>
    #include <linux/module.h>
    
    #include "xilinx_transceiver.h"
    
    #define OUT_DIV_ADDR			0x88
    #define OUT_DIV_TX_OFFSET		0x4
    #define OUT_DIV_RX_OFFSET		0x0
    
    #define RXCDR_CFG0_ADDR			0xa8
    #define RXCDR_CFG0_MASK			0xffff
    
    #define RXCDR_CFG1_ADDR			0xa9
    #define RXCDR_CFG1_MASK			0xffff
    
    #define RXCDR_CFG2_ADDR			0xaa
    #define RXCDR_CFG2_MASK			0xffff
    
    #define RXCDR_CFG3_ADDR			0xab
    #define RXCDR_CFG3_MASK			0xffff
    
    #define RXCDR_CFG4_ADDR			0xac
    #define RXCDR_CFG4_MASK			0x00ff
    
    #define RX_DFE_LPM_CFG_ADDR		0x29
    #define RX_DFE_LPM_CFG_MASK		0xffff
    
    #define QPLL_CFG0_ADDR			0x32
    #define QPLL_CFG0_LOWBAND_MASK		0x0040
    
    #define QPLL_CFG1_ADDR			0x33
    #define QPLL_REFCLK_DIV_M_MASK		0xf800
    #define QPLL_REFCLK_DIV_M_OFFSET	11
    #define QPLL_REFCLK_DIV_M(x)		((x) << 11)
    
    #define QPLL_FBDIV_N_ADDR		0x36
    #define QPLL_FBDIV_N_MASK		0x03ff
    
    #define QPLL_FBDIV_RATIO_ADDR		0x37
    #define QPLL_FBDIV_RATIO_MASK		0x0040
    
    #define CPLL_CFG0_ADDR			0x5c
    #define CPLL_CFG0_MASK			0xff00
    
    #define CPLL_CFG1_ADDR			0x5d
    #define CPLL_CFG1_MASK			0xffff
    
    #define CPLL_REFCLK_DIV_M_ADDR		0x5e
    #define CPLL_REFCLK_DIV_M_MASK		0x1f00
    #define CPLL_FB_DIV_45_N1_MASK		0x0080
    #define CPLL_FBDIV_N2_MASK		0x007f
    
    #define RX_CLK25_DIV			0x11
    #define RX_CLK25_DIV_OFFSET		6
    #define RX_CLK25_DIV_MASK		0x07c0
    
    #define TX_CLK25_DIV			0x6a
    #define TX_CLK25_DIV_MASK		0x1f
    
    #define GTH34_SYSCLK_CPLL		0
    #define GTH34_SYSCLK_QPLL1		2
    #define GTH34_SYSCLK_QPLL0		3
    
    #define GTH34_QPLL0_FBDIV_DIV		0x14
    #define GTH34_QPLL0_REFCLK_DIV		0x18
    #define GTH34_QPLL1_FBDIV		0x94
    #define GTH34_QPLL1_REFCLK_DIV		0x98
    
    #define GTH34_QPLL_FBDIV(xcvr, x)	\
    	(0x14 + xilinx_xcvr_qpll_sel((xcvr), (x)) * 0x80)
    #define GTH34_QPLL_REFCLK_DIV(xcvr, x)	\
    	(0x18 + xilinx_xcvr_qpll_sel((xcvr), (x)) * 0x80)
    
    static int xilinx_xcvr_drp_read(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned int reg)
    {
    	int ret;
    
    	ret = xcvr->drp_ops->read(xcvr, drp_port, reg);
    
    	if (ret >= 0)
    		dev_dbg(xcvr->dev, "%s: drp_port: %d, reg 0x%X val 0x%X\n",
    			__func__, drp_port, reg, ret);
    	else
    		dev_err(xcvr->dev, "%s: Failed to read reg %d-0x%X: %d\n",
    			__func__, drp_port, reg, ret);
    
    	return ret;
    }
    
    static int xilinx_xcvr_drp_write(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned int reg, unsigned int val)
    {
    	int read_val;
    	int ret;
    
    	dev_dbg(xcvr->dev, "%s: drp_port: %d, reg 0x%X, val 0x%X\n",
    		__func__, drp_port, reg, val);
    
    	ret = xcvr->drp_ops->write(xcvr, drp_port, reg, val);
    	if (ret < 0) {
    		dev_err(xcvr->dev, "%s: Failed to write reg %d-0x%X: %d\n",
    			__func__, drp_port, reg, ret);
    		return ret;
    	}
    
    	read_val = xilinx_xcvr_drp_read(xcvr, drp_port, reg);
    	if (read_val != val)
    		dev_err(xcvr->dev,
    			"%s: read-write mismatch: reg 0x%X, val 0x%4X, expected val 0x%4X\n",
    			__func__, reg, val, read_val);
    
    	return 0;
    }
    
    int xilinx_xcvr_drp_update(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned int reg, unsigned int mask,
    	unsigned int val)
    {
    	int ret;
    
    	ret = xilinx_xcvr_drp_read(xcvr, drp_port, reg);
    	if (ret < 0)
    		return ret;
    
    	val |= ret & ~mask;
    
    	return xilinx_xcvr_drp_write(xcvr, drp_port, reg, val);
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_drp_update);
    
    static int xilinx_xcvr_gth3_configure_cdr(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned int out_div)
    {
    	/*
    	 * TODO: UltraScale FPGAs Transceivers Wizard should be used for
    	 *	 generating these settings
    	 */
    
    	return 0;
    }
    
    static int xilinx_xcvr_gtx2_configure_cdr(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned lane_rate, unsigned int out_div,
    	bool lpm_enable)
    {
    	unsigned int cfg0, cfg1, cfg2, cfg3, cfg4;
    
    	cfg0 = 0x0020;
    	cfg2 = 0x23FF;
    
    	switch (xcvr->refclk_ppm) {
    	case PM_200:
    		cfg3 = 0x0000;
    		break;
    	case PM_700:
    	case PM_1250:
    		cfg3 = 0x8000;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	if (lane_rate > 6600000 && out_div == 1)
    		cfg4 = 0x0B;
    	else
    		cfg4 = 0x03;
    
    	if (xcvr->encoding == ENC_8B10B) {
    
    		switch (out_div) {
    		case 1:
    			cfg1 = 0x1040;
    			break;
    		case 2:
    			cfg1 = 0x1020;
    			break;
    		case 4:
    			cfg1 = 0x1010;
    			break;
    		case 8:
    			cfg1 = 0x1008;
    			break;
    		default:
    			return -EINVAL;
    		}
    
    	} else {
    
    		switch (out_div) {
    		case 1:
    			if (lpm_enable) {
    				if (lane_rate  > 6600000) {
    					if (xcvr->refclk_ppm == PM_1250)
    						cfg1 = 0x1020;
    					else
    						cfg1 = 0x1040;
    				} else {
    					cfg1 = 0x1020;
    				}
    			} else { /* DFE */
    				if (lane_rate  > 6600000) {
    					if (xcvr->refclk_ppm == PM_1250)
    						cfg1 = 0x1020;
    					else
    						cfg1 = 0x1040;
    				} else {
    					if (xcvr->refclk_ppm == PM_1250)
    						cfg1 = 0x1020;
    					else
    						cfg1 = 0x2040;
    				}
    			}
    			break;
    		case 2:
    			cfg1 = 0x4020;
    			break;
    		case 4:
    			cfg1 = 0x4010;
    			break;
    		case 8:
    			cfg1 = 0x4008;
    			break;
    		default:
    			return -EINVAL;
    		}
    	}
    
    	xilinx_xcvr_drp_write(xcvr, drp_port, RXCDR_CFG0_ADDR, cfg0);
    	xilinx_xcvr_drp_write(xcvr, drp_port, RXCDR_CFG1_ADDR, cfg1);
    	xilinx_xcvr_drp_write(xcvr, drp_port, RXCDR_CFG2_ADDR, cfg2);
    	xilinx_xcvr_drp_write(xcvr, drp_port, RXCDR_CFG3_ADDR, cfg3);
    	xilinx_xcvr_drp_update(xcvr, drp_port, RXCDR_CFG4_ADDR, RXCDR_CFG4_MASK, cfg4);
    
    	return 0;
    }
    
    int xilinx_xcvr_configure_cdr(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned lane_rate, unsigned int out_div,
    	bool lpm_enable)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		return xilinx_xcvr_gtx2_configure_cdr(xcvr, drp_port, lane_rate,
    			out_div, lpm_enable);
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		return xilinx_xcvr_gth3_configure_cdr(xcvr, drp_port, out_div);
    	default:
    		return -EINVAL;
    	}
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_configure_cdr);
    
    int xilinx_xcvr_configure_lpm_dfe_mode(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, bool lpm)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		/*
    		 * TODO: UltraScale FPGAs Transceivers Wizard should be used for
    		 *	 generating these settings
    		 */
    		break;
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		if (lpm)
    			xilinx_xcvr_drp_write(xcvr, drp_port, 0x029, 0x0104);
    		else
    			xilinx_xcvr_drp_write(xcvr, drp_port, 0x029, 0x0954);
    		break;
    	}
    
    	return 0;
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_configure_lpm_dfe_mode);
    
    static unsigned int xilinx_xcvr_qpll_sel(struct xilinx_xcvr *xcvr,
    					 unsigned int sys_clk_sel)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		if (sys_clk_sel == GTH34_SYSCLK_QPLL1)
    			return 1;
    		/* fall-through */
    	default:
    		return 0;
    	}
    }
    
    static void xilinx_xcvr_setup_cpll_vco_range(struct xilinx_xcvr *xcvr,
    					     unsigned int *vco_max)
    {
    	if  ((xcvr->type == XILINX_XCVR_TYPE_US_GTH3) |
    	     (xcvr->type == XILINX_XCVR_TYPE_US_GTH4) |
    	     (xcvr->type == XILINX_XCVR_TYPE_US_GTY4)) {
    		if (xcvr->voltage < 850)
    			*vco_max = 4250000;
    		else if ((xcvr->speed_grade / 10) == 1)
    			*vco_max = 4250000;
    	}
    }
    
    static void xilinx_xcvr_setup_qpll_vco_range(struct xilinx_xcvr *xcvr,
    					     unsigned int *vco0_min,
    					     unsigned int *vco0_max,
    					     unsigned int *vco1_min,
    					     unsigned int *vco1_max)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		if ((xcvr->dev_package == ADI_AXI_FPGA_DEV_FB) |
    		    (xcvr->dev_package == ADI_AXI_FPGA_DEV_SB))
    			*vco0_max = 6600000;
    		if ((xcvr->speed_grade / 10) == 2)
    			*vco1_max = 10312500;
    		break;
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		*vco1_min = 8000000;
    		*vco1_max = 13000000;
    		if (((xcvr->voltage < 900) | (xcvr->voltage > 720)) &
    		    ((xcvr->speed_grade / 10) == 1)) {
    			*vco0_max = 12500000;
    			*vco1_max = *vco0_max;
    		}
    		if (xcvr->voltage == 720) {
    			if ((xcvr->speed_grade / 10) == 2)
    				*vco0_max = 12500000;
    			else if ((xcvr->speed_grade / 10) == 1)
    				*vco0_max = 10312500;
    			*vco1_max = *vco0_max;
    		}
    	}
    }
    
    static int xilinx_xcvr_get_cpll_vco_ranges(struct xilinx_xcvr *xcvr,
    					   unsigned int *vco_min,
    					   unsigned int *vco_max)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		*vco_min = 1600000;
    		*vco_max = 3300000;
    		break;
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		*vco_min = 2000000;
    		*vco_max = 6250000;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	if (ADI_AXI_PCORE_VER_MAJOR(xcvr->version) > 0x10)
    		xilinx_xcvr_setup_cpll_vco_range(xcvr, vco_max);
    
    	if (xcvr->vco0_min)
    		*vco_min = xcvr->vco0_min;
    
    	if (xcvr->vco0_max)
    		*vco_max = xcvr->vco0_max;
    
    	return 0;
    }
    
    int xilinx_xcvr_calc_cpll_config(struct xilinx_xcvr *xcvr,
    	unsigned int refclk_hz, unsigned int lane_rate_khz,
    	struct xilinx_xcvr_cpll_config *conf,
    	unsigned int *out_div)
    {
    	unsigned int n1, n2, d, m;
    	unsigned int refclk_khz = DIV_ROUND_CLOSEST(refclk_hz, 1000);
    	unsigned int vco_freq;
    	unsigned int vco_min;
    	unsigned int vco_max;
    	int ret;
    
    	ret = xilinx_xcvr_get_cpll_vco_ranges(xcvr, &vco_min, &vco_max);
    	if (ret)
    		return ret;
    
    	for (m = 1; m <= 2; m++) {
    		for (d = 1; d <= 8; d <<= 1) {
    			for (n1 = 5; n1 >= 4; n1--) {
    				for (n2 = 5; n2 >= 1; n2--) {
    					vco_freq = refclk_khz * n1 * n2 / m;
    
    					if (vco_freq > vco_max || vco_freq < vco_min)
    						continue;
    
    					if (refclk_khz / m / d == lane_rate_khz / (2 * n1 * n2)) {
    						if (conf) {
    							conf->refclk_div = m;
    							conf->fb_div_N1 = n1;
    							conf->fb_div_N2 = n2;
    						}
    
    						if (out_div)
    							*out_div = d;
    
    						return 0;
    					}
    				}
    			}
    		}
    	}
    
    	dev_dbg(xcvr->dev,
    		 "CPLL: failed to find setting for lane rate %u kHz with reference clock %u kHz\n",
    		lane_rate_khz, refclk_khz);
    
    	return -EINVAL;
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_calc_cpll_config);
    
    static int xilinx_xcvr_get_qpll_vco_ranges(struct xilinx_xcvr *xcvr,
    	unsigned int sys_clk_sel,
    	unsigned int *vco0_min, unsigned int *vco0_max,
    	unsigned int *vco1_min, unsigned int *vco1_max)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		*vco0_min = 5930000;
    		*vco0_max = 8000000;
    		*vco1_min = 9600000;
    		*vco1_max = 12500000;
    		break;
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		if (xilinx_xcvr_qpll_sel(xcvr, sys_clk_sel)) {
    			*vco0_min = 8000000;
    			*vco0_max = 13000000;
    		} else {
    			*vco0_min = 9600000;
    			*vco0_max = 16375000;
    		}
    		*vco1_min = *vco0_min;
    		*vco1_max = *vco0_max;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	if (ADI_AXI_PCORE_VER_MAJOR(xcvr->version) > 0x10)
    		xilinx_xcvr_setup_qpll_vco_range(xcvr,
    						 vco0_min, vco0_max,
    						 vco1_min, vco1_max);
    
    	if (xcvr->vco0_min)
    		*vco0_min = xcvr->vco0_min;
    
    	if (xcvr->vco0_max)
    		*vco0_max = xcvr->vco0_max;
    
    	if (xcvr->vco1_min)
    		*vco1_min = xcvr->vco1_min;
    
    	if (xcvr->vco1_max)
    		*vco1_max = xcvr->vco1_max;
    
    	return 0;
    }
    
    int xilinx_xcvr_calc_qpll_config(struct xilinx_xcvr *xcvr,
    	unsigned int sys_clk_sel, unsigned int refclk_hz,
    	unsigned int lane_rate_khz,
    	struct xilinx_xcvr_qpll_config *conf,
    	unsigned int *out_div)
    {
    	unsigned int refclk_khz = DIV_ROUND_CLOSEST(refclk_hz, 1000);
    	unsigned int n, d, m;
    	unsigned int vco_freq;
    	unsigned int band;
    	unsigned int vco0_min;
    	unsigned int vco0_max;
    	unsigned int vco1_min;
    	unsigned int vco1_max;
    	const u8 *N;
    	int ret;
    
    	static const u8 N_gtx2[] = {16, 20, 32, 40, 64, 66, 80, 100, 0};
    	static const u8 N_gth34[] = {16, 20, 32, 40, 64, 66, 75, 80, 100,
    			112, 120, 125, 150, 160, 0};
    
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		N = N_gtx2;
    		break;
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		N = N_gth34;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	ret = xilinx_xcvr_get_qpll_vco_ranges(xcvr, sys_clk_sel,
    					      &vco0_min, &vco0_max,
    					      &vco1_min, &vco1_max);
    	if (ret)
    		return ret;
    
    	for (m = 1; m <= 4; m++) {
    		for (d = 1; d <= 16; d <<= 1) {
    			for (n = 0; N[n] != 0; n++) {
    				vco_freq = refclk_khz * N[n] / m;
    
    				/*
    				 * high band = 9.8G to 12.5GHz VCO
    				 * low band = 5.93G to 8.0GHz VCO
    				 */
    				if (vco_freq >= vco1_min && vco_freq <= vco1_max)
    					band = 1;
    				else if (vco_freq >= vco0_min && vco_freq <= vco0_max)
    					band = 0;
    				else
    					continue;
    
    				if (refclk_khz / m / d == lane_rate_khz / N[n]) {
    
    					if (conf) {
    						conf->refclk_div = m;
    						conf->fb_div = N[n];
    						conf->band = band;
    					}
    
    					if (out_div)
    						*out_div = d;
    
    					return 0;
    				}
    			}
    		}
    	}
    
    	dev_dbg(xcvr->dev,
    		 "QPLL: failed to find setting for lane rate %u kHz with reference clock %u kHz\n",
    		 lane_rate_khz, refclk_khz);
    
    	return -EINVAL;
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_calc_qpll_config);
    
    int xilinx_xcvr_gth34_cpll_read_config(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, struct xilinx_xcvr_cpll_config *conf)
    {
    	int val;
    
    	val = xilinx_xcvr_drp_read(xcvr, drp_port, 0x28);
    	if (val < 0)
    		return val;
    
    	if (val & CPLL_FB_DIV_45_N1_MASK)
    		conf->fb_div_N1 = 5;
    	else
    		conf->fb_div_N1 = 4;
    
    	switch ((val >> 8) & 0xff) {
    	case 3:
    		conf->fb_div_N2 = 5;
    		break;
    	case 2:
    		conf->fb_div_N2 = 4;
    		break;
    	case 1:
    		conf->fb_div_N2 = 3;
    		break;
    	case 0:
    		conf->fb_div_N2 = 2;
    		break;
    	default:
    		conf->fb_div_N2 = 1;
    		break;
    	}
    
    	val = xilinx_xcvr_drp_read(xcvr, drp_port, 0x2a);
    	if (val < 0)
    		return val;
    
    	if (val & 0xf800)
    		conf->refclk_div = 1;
    	else
    		conf->refclk_div = 2;
    
    	dev_dbg(xcvr->dev, "cpll: fb_div_N1=%d\ncpll: fb_div_N2=%d\ncpll: refclk_div=%d\n",
    		conf->fb_div_N1, conf->fb_div_N2, conf->refclk_div);
    
    	return 0;
    }
    
    int xilinx_xcvr_gtx2_cpll_read_config(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, struct xilinx_xcvr_cpll_config *conf)
    {
    	int val;
    
    	val = xilinx_xcvr_drp_read(xcvr, drp_port, CPLL_REFCLK_DIV_M_ADDR);
    	if (val < 0)
    		return val;
    
    	if (val & CPLL_FB_DIV_45_N1_MASK)
    		conf->fb_div_N1 = 5;
    	else
    		conf->fb_div_N1 = 4;
    
    	switch (val & CPLL_FBDIV_N2_MASK) {
    	case 3:
    		conf->fb_div_N2 = 5;
    		break;
    	case 2:
    		conf->fb_div_N2 = 4;
    		break;
    	case 1:
    		conf->fb_div_N2 = 3;
    		break;
    	case 0:
    		conf->fb_div_N2 = 2;
    		break;
    	default:
    		conf->fb_div_N2 = 1;
    		break;
    	}
    
    	if (val & CPLL_REFCLK_DIV_M_MASK)
    		conf->refclk_div = 1;
    	else
    		conf->refclk_div = 2;
    
    	return 0;
    }
    
    int xilinx_xcvr_cpll_read_config(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, struct xilinx_xcvr_cpll_config *conf)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		return xilinx_xcvr_gtx2_cpll_read_config(xcvr, drp_port, conf);
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		return xilinx_xcvr_gth34_cpll_read_config(xcvr, drp_port, conf);
    	default:
    		return -EINVAL;
    	}
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_cpll_read_config);
    
    static int xilinx_xcvr_gth34_cpll_write_config(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, const struct xilinx_xcvr_cpll_config *conf)
    {
    	unsigned int val;
    	int ret;
    
    	switch (conf->fb_div_N2) {
    	case 1:
    		val = 0x10;
    		break;
    	case 2:
    		val = 0x00;
    		break;
    	case 3:
    		val = 0x01;
    		break;
    	case 4:
    		val = 0x2;
    		break;
    	case 5:
    		val = 0x3;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	val <<= 8;
    
    	switch (conf->fb_div_N1) {
    	case 4:
    		break;
    	case 5:
    		val |= CPLL_FB_DIV_45_N1_MASK;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	ret = xilinx_xcvr_drp_update(xcvr, drp_port, 0x28,
    		0xff80, val);
    	if (ret)
    		return ret;
    
    	switch (conf->refclk_div) {
    	case 1:
    		val = 16;
    		break;
    	case 2:
    		val = 0;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	val <<= 11;
    
    	return xilinx_xcvr_drp_update(xcvr, drp_port, 0x2a,
    		0xf800, val);
    }
    
    static int xilinx_xcvr_gtx2_cpll_write_config(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, const struct xilinx_xcvr_cpll_config *conf)
    {
    	unsigned int val = 0;
    
    	switch (conf->fb_div_N1) {
    	case 4:
    		break;
    	case 5:
    		val |= CPLL_FB_DIV_45_N1_MASK;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	switch (conf->fb_div_N2) {
    	case 1:
    		val |= 0x10;
    		/* fall-through */
    	case 2:
    		val |= 0x00;
    		break;
    	case 3:
    		val |= 0x01;
    		break;
    	case 4:
    		val |= 0x2;
    		break;
    	case 5:
    		val |= 0x3;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	switch (conf->refclk_div) {
    	case 1:
    		val |= CPLL_REFCLK_DIV_M_MASK;
    		break;
    	case 2:
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	return xilinx_xcvr_drp_update(xcvr, drp_port, CPLL_REFCLK_DIV_M_ADDR,
    		CPLL_REFCLK_DIV_M_MASK | CPLL_FB_DIV_45_N1_MASK | CPLL_FBDIV_N2_MASK,
    		val);
    }
    
    int xilinx_xcvr_cpll_write_config(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, const struct xilinx_xcvr_cpll_config *conf)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		return xilinx_xcvr_gtx2_cpll_write_config(xcvr, drp_port, conf);
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		return xilinx_xcvr_gth34_cpll_write_config(xcvr, drp_port, conf);
    	default:
    		return -EINVAL;
    	}
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_cpll_write_config);
    
    int xilinx_xcvr_cpll_calc_lane_rate(struct xilinx_xcvr *xcvr,
    	unsigned int refclk_hz, const struct xilinx_xcvr_cpll_config *conf,
    	unsigned int out_div)
    {
    	if (conf->refclk_div == 0 || out_div == 0)
    		return 0;
    
    	return DIV_ROUND_CLOSEST_ULL((unsigned long long)refclk_hz *
    			conf->fb_div_N1 * conf->fb_div_N2 * 2,
    			conf->refclk_div * out_div * 1000);
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_cpll_calc_lane_rate);
    
    static int xilinx_xcvr_gth34_qpll_read_config(struct xilinx_xcvr *xcvr,
    	unsigned int sys_clk_sel, unsigned int drp_port,
    	struct xilinx_xcvr_qpll_config *conf)
    {
    	int val;
    
    	val = xilinx_xcvr_drp_read(xcvr, drp_port,
    			GTH34_QPLL_REFCLK_DIV(xcvr, sys_clk_sel));
    	if (val < 0)
    		return val;
    
    	switch ((val >> 7) & 0x1f) {
    	case 16:
    		conf->refclk_div = 1;
    		break;
    	case 0:
    		conf->refclk_div = 2;
    		break;
    	case 1:
    		conf->refclk_div = 3;
    		break;
    	case 2:
    		conf->refclk_div = 4;
    		break;
    	default:
    		conf->refclk_div = 5;
    		break;
    	}
    
    	val = xilinx_xcvr_drp_read(xcvr, drp_port,
    			GTH34_QPLL_FBDIV(xcvr, sys_clk_sel));
    	if (val < 0)
    		return val;
    
    	conf->fb_div = (val & 0xff) + 2;
    
    	conf->band = 0;
    
    	dev_dbg(xcvr->dev, "qpll: fb_div=%d, qpll: refclk_div=%d\n",
    		conf->fb_div, conf->refclk_div);
    
    	return 0;
    }
    
    
    static int xilinx_xcvr_gtx2_qpll_read_config(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, struct xilinx_xcvr_qpll_config *conf)
    {
    	int val;
    
    	val = xilinx_xcvr_drp_read(xcvr, drp_port, QPLL_CFG1_ADDR);
    	if (val < 0)
    		return val;
    
    	switch ((val & QPLL_REFCLK_DIV_M_MASK) >> QPLL_REFCLK_DIV_M_OFFSET) {
    	case 16:
    		conf->refclk_div = 1;
    		break;
    	case 0:
    		conf->refclk_div = 2;
    		break;
    	case 1:
    		conf->refclk_div = 3;
    		break;
    	case 2:
    		conf->refclk_div = 4;
    		break;
    	}
    
    	val = xilinx_xcvr_drp_read(xcvr, drp_port, QPLL_FBDIV_N_ADDR);
    	if (val < 0)
    		return val;
    
    	switch (val & QPLL_FBDIV_N_MASK) {
    	case 32:
    		conf->fb_div = 16;
    		break;
    	case 48:
    		conf->fb_div = 20;
    		break;
    	case 96:
    		conf->fb_div = 32;
    		break;
    	case 128:
    		conf->fb_div = 40;
    		break;
    	case 224:
    		conf->fb_div = 64;
    		break;
    	case 320:
    		conf->fb_div = 66;
    		break;
    	case 288:
    		conf->fb_div = 80;
    		break;
    	case 368:
    		conf->fb_div = 100;
    		break;
    	}
    
    	val = xilinx_xcvr_drp_read(xcvr, drp_port, QPLL_CFG0_ADDR);
    	if (val < 0)
    		return 0;
    
    	if (val & QPLL_CFG0_LOWBAND_MASK)
    		conf->band = 0;
    	else
    		conf->band = 1;
    
    	return 0;
    }
    
    int xilinx_xcvr_qpll_read_config(struct xilinx_xcvr *xcvr,
    	unsigned int sys_clk_sel, unsigned int drp_port,
    	struct xilinx_xcvr_qpll_config *conf)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		return xilinx_xcvr_gtx2_qpll_read_config(xcvr, drp_port, conf);
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		return xilinx_xcvr_gth34_qpll_read_config(xcvr, sys_clk_sel,
    				drp_port, conf);
    	default:
    		return -EINVAL;
    	}
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_qpll_read_config);
    
    static int xilinx_xcvr_gth34_qpll_write_config(struct xilinx_xcvr *xcvr,
    	unsigned int sys_clk_sel, unsigned int drp_port,
    	const struct xilinx_xcvr_qpll_config *conf)
    {
    	unsigned int refclk, fbdiv;
    	int ret;
    
    	fbdiv = conf->fb_div - 2;
    
    	switch (conf->refclk_div) {
    	case 1:
    		refclk = 16;
    		break;
    	case 2:
    		refclk = 0;
    		break;
    	case 3:
    		refclk = 1;
    		break;
    	case 4:
    		refclk = 2;
    		break;
    	default:
    		dev_dbg(xcvr->dev, "Invalid refclk divider: %d\n",
    			conf->refclk_div);
    		return -EINVAL;
    	}
    
    	ret = xilinx_xcvr_drp_update(xcvr, drp_port,
    			GTH34_QPLL_FBDIV(xcvr, sys_clk_sel), 0xff, fbdiv);
    	if (ret < 0)
    		return ret;
    
    	return xilinx_xcvr_drp_update(xcvr, drp_port,
    			GTH34_QPLL_REFCLK_DIV(xcvr, sys_clk_sel),
    			0xf80, refclk << 7);
    }
    
    static int xilinx_xcvr_gtx2_qpll_write_config(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, const struct xilinx_xcvr_qpll_config *conf)
    {
    	unsigned int cfg0, cfg1, fbdiv, fbdiv_ratio;
    	int ret;
    
    	switch (conf->refclk_div) {
    	case 1:
    		cfg1 = QPLL_REFCLK_DIV_M(16);
    		break;
    	case 2:
    		cfg1 = QPLL_REFCLK_DIV_M(0);
    		break;
    	case 3:
    		cfg1 = QPLL_REFCLK_DIV_M(1);
    		break;
    	case 4:
    		cfg1 = QPLL_REFCLK_DIV_M(2);
    		break;
    	default:
    		dev_dbg(xcvr->dev, "Invalid refclk divider: %d\n",
    			conf->refclk_div);
    		return -EINVAL;
    	}
    
    	fbdiv_ratio = QPLL_FBDIV_RATIO_MASK;
    
    	switch (conf->fb_div) {
    	case 16:
    		fbdiv = 32;
    		break;
    	case 20:
    		fbdiv = 48;
    		break;
    	case 32:
    		fbdiv = 96;
    		break;
    	case 40:
    		fbdiv = 128;
    		break;
    	case 64:
    		fbdiv = 224;
    		break;
    	case 66:
    		fbdiv = 320;
    		fbdiv_ratio = 0;
    		break;
    	case 80:
    		fbdiv = 288;
    		break;
    	case 100:
    		fbdiv = 368;
    		break;
    	default:
    		dev_dbg(xcvr->dev, "Invalid feedback divider: %d\n",
    			conf->fb_div);
    		return -EINVAL;
    	}
    
    	if (conf->band)
    		cfg0 = 0;
    	else
    		cfg0 = QPLL_CFG0_LOWBAND_MASK;
    
    	ret = xilinx_xcvr_drp_update(xcvr, drp_port, QPLL_CFG0_ADDR,
    		QPLL_CFG0_LOWBAND_MASK, cfg0);
    	if (ret < 0)
    		return ret;
    
    	ret = xilinx_xcvr_drp_update(xcvr, drp_port, QPLL_CFG1_ADDR,
    		QPLL_REFCLK_DIV_M_MASK, cfg1);
    	if (ret < 0)
    		return ret;
    
    	ret = xilinx_xcvr_drp_update(xcvr, drp_port, QPLL_FBDIV_N_ADDR,
    		QPLL_FBDIV_N_MASK, fbdiv);
    	if (ret < 0)
    		return ret;
    
    	ret = xilinx_xcvr_drp_update(xcvr, drp_port, QPLL_FBDIV_RATIO_ADDR,
    		QPLL_FBDIV_RATIO_MASK, fbdiv_ratio);
    	if (ret < 0)
    		return ret;
    
    	return 0;
    }
    
    int xilinx_xcvr_qpll_write_config(struct xilinx_xcvr *xcvr,
    	unsigned int sys_clk_sel, unsigned int drp_port,
    	const struct xilinx_xcvr_qpll_config *conf)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		return xilinx_xcvr_gtx2_qpll_write_config(xcvr, drp_port, conf);
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		return xilinx_xcvr_gth34_qpll_write_config(xcvr, sys_clk_sel,
    				drp_port, conf);
    	default:
    		return -EINVAL;
    	}
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_qpll_write_config);
    
    int xilinx_xcvr_qpll_calc_lane_rate(struct xilinx_xcvr *xcvr,
    	unsigned int sys_clk_sel, unsigned int refclk_hz,
    	const struct xilinx_xcvr_qpll_config *conf,
    	unsigned int out_div)
    {
    	if (conf->refclk_div == 0 || out_div == 0)
    		return 0;
    
    	/* FIXME: do we need to use sys_clk_sel here ? */
    
    	return DIV_ROUND_CLOSEST_ULL((unsigned long long)refclk_hz * conf->fb_div,
    			conf->refclk_div * out_div * 1000);
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_qpll_calc_lane_rate);
    
    static int xilinx_xcvr_gth34_read_out_div(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned int *rx_out_div, unsigned int *tx_out_div)
    {
    	int ret;
    
    	if (rx_out_div) {
    		ret = xilinx_xcvr_drp_read(xcvr, drp_port, 0x63);
    		if (ret < 0)
    			return ret;
    
    		*rx_out_div = 1 << (ret & 7);
    	}
    
    	if (tx_out_div) {
    		ret = xilinx_xcvr_drp_read(xcvr, drp_port, 0x7c);
    		if (ret < 0)
    			return ret;
    
    		*tx_out_div = 1 << ((ret >> 8) & 7);
    	}
    
    	return 0;
    }
    
    static int xilinx_xcvr_gtx2_read_out_div(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned int *rx_out_div, unsigned int *tx_out_div)
    {
    	int ret;
    
    	ret = xilinx_xcvr_drp_read(xcvr, drp_port, OUT_DIV_ADDR);
    	if (ret < 0)
    		return ret;
    
    	if (rx_out_div)
    		*rx_out_div = 1 << ((ret >> OUT_DIV_RX_OFFSET) & 7);
    	if (tx_out_div)
    		*tx_out_div = 1 << ((ret >> OUT_DIV_TX_OFFSET) & 7);
    
    	return 0;
    }
    
    int xilinx_xcvr_read_out_div(struct xilinx_xcvr *xcvr, unsigned int drp_port,
    	unsigned int *rx_out_div, unsigned int *tx_out_div)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		return xilinx_xcvr_gtx2_read_out_div(xcvr, drp_port,
    			rx_out_div, tx_out_div);
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		return xilinx_xcvr_gth34_read_out_div(xcvr, drp_port,
    			rx_out_div, tx_out_div);
    	default:
    		return -EINVAL;
    	}
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_read_out_div);
    
    static unsigned int xilinx_xcvr_out_div_to_val(unsigned int out_div)
    {
    	switch (out_div) {
    	case 1:
    		return 0;
    	case 2:
    		return 1;
    	case 4:
    		return 2;
    	case 8:
    		return 3;
    	default:
    		return 4;
    	}
    }
    
    static int xilinx_xcvr_gth34_write_out_div(struct xilinx_xcvr *xcvr, unsigned int drp_port,
    	int rx_out_div, int tx_out_div)
    {
    	int ret;
    
    	if (rx_out_div >= 0) {
    		ret = xilinx_xcvr_drp_update(xcvr, drp_port, 0x63, 0x7,
    			xilinx_xcvr_out_div_to_val(rx_out_div));
    		if (ret)
    			return ret;
    	}
    	if (tx_out_div >= 0) {
    		ret = xilinx_xcvr_drp_update(xcvr, drp_port, 0x7c, 0x700,
    			xilinx_xcvr_out_div_to_val(tx_out_div) << 8);
    		if (ret)
    			return ret;
    	}
    
    	return 0;
    }
    
    static int xilinx_xcvr_gtx2_write_out_div(struct xilinx_xcvr *xcvr, unsigned int drp_port,
    	int rx_out_div, int tx_out_div)
    {
    	unsigned int val = 0;
    	unsigned int mask = 0;
    
    	if (tx_out_div >= 0) {
    		val |= xilinx_xcvr_out_div_to_val(tx_out_div) << OUT_DIV_TX_OFFSET;
    		mask |= 0x7 << OUT_DIV_TX_OFFSET;
    	}
    	if (rx_out_div >= 0) {
    		val |= xilinx_xcvr_out_div_to_val(rx_out_div) << OUT_DIV_RX_OFFSET;
    		mask |= 0x7 << OUT_DIV_RX_OFFSET;
    	}
    
    	return xilinx_xcvr_drp_update(xcvr, drp_port, OUT_DIV_ADDR, mask, val);
    }
    
    int xilinx_xcvr_write_out_div(struct xilinx_xcvr *xcvr, unsigned int drp_port,
    	int rx_out_div, int tx_out_div)
    {
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		return xilinx_xcvr_gtx2_write_out_div(xcvr, drp_port,
    			rx_out_div, tx_out_div);
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		return xilinx_xcvr_gth34_write_out_div(xcvr, drp_port,
    			rx_out_div, tx_out_div);
    	default:
    		return -EINVAL;
    	}
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_write_out_div);
    
    int xilinx_xcvr_write_rx_clk25_div(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned int div)
    {
    	unsigned int reg, mask;
    
    	if (div == 0 || div > 32)
    		return -EINVAL;
    
    	div--;
    
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		div <<= RX_CLK25_DIV_OFFSET;
    		mask = RX_CLK25_DIV_MASK;
    		reg = RX_CLK25_DIV;
    		break;
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		div <<= 3;
    		mask = 0xf8;
    		reg = 0x6d;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	return xilinx_xcvr_drp_update(xcvr, drp_port, reg, mask, div);
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_write_rx_clk25_div);
    
    int xilinx_xcvr_write_tx_clk25_div(struct xilinx_xcvr *xcvr,
    	unsigned int drp_port, unsigned int div)
    {
    	unsigned int reg, mask;
    
    	if (div == 0 || div > 32)
    		return -EINVAL;
    
    	div--;
    
    	switch (xcvr->type) {
    	case XILINX_XCVR_TYPE_S7_GTX2:
    		mask = TX_CLK25_DIV_MASK;
    		reg = TX_CLK25_DIV;
    		break;
    	case XILINX_XCVR_TYPE_US_GTH3:
    	case XILINX_XCVR_TYPE_US_GTH4:
    	case XILINX_XCVR_TYPE_US_GTY4:
    		div <<= 11;
    		mask = 0xf800;
    		reg = 0x7a;
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	return xilinx_xcvr_drp_update(xcvr, drp_port, reg, mask, div);
    }
    EXPORT_SYMBOL_GPL(xilinx_xcvr_write_tx_clk25_div);
    
    MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
    MODULE_DESCRIPTION("Xilinx high-speed transceiver dynamic reconfiguration");
    MODULE_LICENSE("GPL v2");
    

Children