Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile =================================================================== @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:8 @ # architecture-specific flags and dependencies. # +GCOV_PROFILE := n + LDFLAGS_bootp :=-p --no-undefined -X \ --defsym initrd_phys=$(INITRD_PHYS) \ --defsym params_phys=$(PARAMS_PHYS) -T Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/compressed/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/boot/compressed/Makefile 2014-07-20 22:05:50.288065763 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/compressed/Makefile 2014-07-20 22:06:33.848347087 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:40 @ OBJS += hyp-stub.o endif +GCOV_PROFILE := n + # # Architecture dependencies # Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/boot/dts/Makefile 2014-07-20 22:05:50.284065829 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/Makefile 2014-07-20 22:06:33.863346840 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:267 @ wm8750-apc8750.dtb \ wm8850-w70v2.dtb dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \ + zynq-zc702-base-trd.dtb \ + zynq-zc702-drm-v4l2.dtb \ + zynq-afx-nand.dtb \ + zynq-afx-nor.dtb \ + zynq-cc108.dtb \ + zynq-zc770-xm010.dtb \ + zynq-zc770-xm011.dtb \ + zynq-zc770-xm012.dtb \ + zynq-zc770-xm013.dtb \ zynq-zc706.dtb \ zynq-zed.dtb Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-afx-nand.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-afx-nand.dts 2014-07-20 22:06:33.874346658 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f + * + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + serial0 = &ps7_uart_1; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x8000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0x3cffff>; + gpio-mask-low = <0xff008002>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_smcc_0: ps7-smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 11>, <&clkc 44>; + compatible = "xlnx,ps7-smcc-1.00.a", "xlnx,ps7-smc"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 18 4>; + ranges ; + reg = <0xe000e000 0x1000>; + xlnx,addr25 = <0x0>; + xlnx,nor-chip-sel0 = <0x0>; + xlnx,nor-chip-sel1 = <0x0>; + xlnx,sram-chip-sel0 = <0x0>; + xlnx,sram-chip-sel1 = <0x0>; + ps7_nand_0: ps7-nand@e1000000 { + compatible = "xlnx,ps7-nand-1.00.a"; + reg = <0xe1000000 0x1000000>; + xlnx,nand-cycle-t0 = <0x4>; + xlnx,nand-cycle-t1 = <0x4>; + xlnx,nand-cycle-t2 = <0x1>; + xlnx,nand-cycle-t3 = <0x2>; + xlnx,nand-cycle-t4 = <0x2>; + xlnx,nand-cycle-t5 = <0x2>; + xlnx,nand-cycle-t6 = <0x4>; + xlnx,nand-width = <0x10>; + #address-cells = <0x1>; + #size-cells = <0x1>; + + partition@nand-fsbl-uboot { + label = "nand-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@nand-linux { + label = "nand-linux"; + reg = <0x100000 0x500000>; + }; + partition@nand-device-tree { + label = "nand-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@nand-rootfs { + label = "nand-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@nand-bitstream { + label = "nand-bitstream"; + reg = <0xC00000 0x400000>; + + }; + } ; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_ttc_1: ps7-ttc@f8002000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 37 4>, <0 38 4>, <0 39 4>; + reg = <0xf8002000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-afx-nor.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-afx-nor.dts 2014-07-20 22:06:33.882346526 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f + * + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + serial0 = &ps7_uart_1; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x8000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_smcc_0: ps7-smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 11>, <&clkc 44>; + compatible = "xlnx,ps7-smcc-1.00.a", "xlnx,ps7-smc"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 18 4>; + ranges ; + reg = <0xe000e000 0x1000>; + xlnx,addr25 = <0x1>; + xlnx,nor-chip-sel0 = <0x1>; + xlnx,nor-chip-sel1 = <0x0>; + xlnx,sram-chip-sel0 = <0x0>; + xlnx,sram-chip-sel1 = <0x0>; + ps7_nor_0: ps7-nor@e2000000 { + bank-width = <1>; + compatible = "xlnx,ps7-nor-1.00.a", "cfi-flash"; + reg = <0xe2000000 0x1000>; + xlnx,sram-cycle-t0 = <0xb>; + xlnx,sram-cycle-t1 = <0xb>; + xlnx,sram-cycle-t2 = <0x5>; + xlnx,sram-cycle-t3 = <0x4>; + xlnx,sram-cycle-t4 = <0x3>; + xlnx,sram-cycle-t5 = <0x3>; + xlnx,sram-cycle-t6 = <0x2>; + #address-cells = <1>; + #size-cells = <1>; + + partition@nor-fsbl-uboot { + label = "nor-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@nor-linux { + label = "nor-linux"; + reg = <0x100000 0x500000>; + }; + partition@nor-device-tree { + label = "nor-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@nor-rootfs { + label = "nor-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@nor-bitstream { + label = "nor-bitstream"; + reg = <0xC00000 0x400000>; + }; + + } ; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_ttc_1: ps7-ttc@f8002000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 37 4>, <0 38 4>, <0 39 4>; + reg = <0xf8002000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-cc108.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-cc108.dts 2014-07-20 22:06:33.891346378 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.7 EDK_P.20131013 + * + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + ethernet0 = &ps7_ethernet_0; + serial0 = &ps7_uart_1; + spi0 = &ps7_qspi_0; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x20000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_ethernet_0: ps7-ethernet@e000b000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; + enet-reset = <&ps7_gpio_0 0 0>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; + local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + reg = <0xe000b000 0x1000>; + xlnx,eth-mode = <0x1>; + xlnx,has-mdio = <0x1>; + xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@1 { + compatible = "marvell,88e1510"; + device_type = "ethernet-phy"; + reg = <1>; + } ; + } ; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0x0>; + gpio-mask-low = <0x0>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_qspi_0: ps7-qspi@e000d000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; + is-dual = <0>; + num-chip-select = <1>; + reg = <0xe000d000 0x1000>; + xlnx,fb-clk = <0x0>; + xlnx,qspi-mode = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { /* 16 MB */ + compatible = "n25q128"; + reg = <0x0>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "qspi-fsbl-uboot-bs"; + reg = <0x0 0x400000>; /* 4MB */ + }; + partition@0x400000 { + label = "qspi-linux"; + reg = <0x400000 0x400000>; /* 4MB */ + }; + partition@0x800000 { + label = "qspi-rootfs"; + reg = <0x800000 0x400000>; /* 4MB */ + }; + partition@0xc00000 { + label = "qspi-devicetree"; + reg = <0xc00000 0x100000>; /* 1MB */ + }; + partition@0xd00000 { + label = "qspi-scratch"; + reg = <0xd00000 0x200000>; /* 2MB */ + }; + partition@0xf00000 { + label = "qspi-uboot-env"; + reg = <0xf00000 0x100000>; /* 1MB */ + }; + }; + } ; + ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-linear-1.00.a"; + reg = <0xfc000000 0x1000000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_sd_1: ps7-sdio@e0101000 { + broken-cd ; + wp-inverted ; + clock-frequency = <50000000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 22>, <&clkc 33>; + compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci-8.9a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 47 4>; + reg = <0xe0101000 0x1000>; + xlnx,has-cd = <0x0>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x0>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_ttc_1: ps7-ttc@f8002000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 37 4>, <0 38 4>, <0 39 4>; + reg = <0xf8002000 0x1000>; + } ; + ps7_uart_0: serial@e0000000 { + status = "disabled"; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 23>, <&clkc 40>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 27 4>; + port-number = <0>; + reg = <0xe0000000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_usb_0: ps7-usb@e0002000 { + clocks = <&clkc 28>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "peripheral"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 21 4>; + phy_type = "ulpi"; + reg = <0xe0002000 0x1000>; + usb-reset = <&ps7_gpio_0 9 0>; + } ; + ps7_usb_1: ps7-usb@e0003000 { + clocks = <&clkc 29>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "host"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 44 4>; + phy_type = "ulpi"; + reg = <0xe0003000 0x1000>; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc702-base-trd.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc702-base-trd.dts 2014-07-20 22:06:33.901346213 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/dts-v1/; + +/ { + model = "Xilinx Zynq ZC702"; + compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000"; + #address-cells = <0x1>; + #size-cells = <0x1>; + interrupt-parent = <0x1>; + aliases { + spi1 = &qspi0; + }; + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; + }; + chosen { + bootargs = "console=tty0 console=ttyPS0,115200 root=/dev/ram rw ip=192.168.1.10:::255.255.255.0:ZC702:eth0 earlyprintk mem=768M"; + linux,stdout-path = "/amba@0/uart@E0001000"; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <0 5 4>, <0 6 4>; + interrupt-parent = <&gic>; + }; + + amba@0 { + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + + gic: intc@f8f01000 { + interrupt-controller; + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + reg = <0xf8f01000 0x1000>, + <0xf8f00100 0x0100>; + }; + + pl310@f8f02000 { + compatible = "arm,pl310-cache"; + cache-unified; + cache-level = <2>; + reg = <0xf8f02000 0x1000>; + interrupts = <0 2 4>; + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + }; + + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + + ps7_ocm_0: ps7-ocm@0xfffc0000 { + compatible = "xlnx,ps7-ocm"; + reg = <0xfffc0000 0x40000>; /* 256k */ + }; + + uart@e0001000 { + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + clocks = <&clkc 24>, <&clkc 41>; + clock-names = "ref_clk", "aper_clk"; + reg = <0xe0001000 0x1000>; + interrupts = <0 50 4>; + interrupt-parent = <&gic>; + }; + + slcr: slcr@f8000000 { + compatible = "xlnx,zynq-slcr"; + reg = <0xF8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + + clkc: clkc { + #clock-cells = <1>; + compatible = "xlnx,ps7-clkc"; + ps-clk-frequency = <33333333>; + 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"; + }; + } ; + }; + + timer@0xf8001000 { + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + clocks = <&clkc 6>; + reg = <0xf8001000 0x1000>; + interrupts = <0 10 4>,<0 11 4>,<0 12 4>; + interrupt-parent = <&gic>; + }; + + timer@f8f00600 { + compatible = "arm,cortex-a9-twd-timer"; + clocks = <&clkc 4>; + reg = <0xf8f00600 0x20>; + interrupts = <1 13 0x301>; + interrupt-parent = <&gic>; + }; + + swdt@f8005000 { + device_type = "watchdog"; + compatible = "xlnx,ps7-wdt-1.00.a"; + clocks = <&clkc 45>; + reg = <0xf8005000 0x100>; + interrupts = <0 9 4>; + interrupt-parent = <&gic>; + reset = <0>; + timeout = <10>; + }; + + scuwdt@f8f00620 { + device_type = "watchdog"; + compatible = "arm,mpcore_wdt"; + clocks = <&clkc 4>; + reg = <0xf8f00620 0x20>; + clock-frequency = <333333333>; + reset = <1>; + }; + + eth@e000b000 { + compatible = "xlnx,ps7-ethernet-1.00.a"; + clocks = <&clkc 13>, <&clkc 30>; + clock-names = "ref_clk", "aper_clk"; + reg = <0xe000b000 0x1000>; + interrupts = <0 22 4>; + interrupt-parent = <&gic>; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + xlnx,ptp-enet-clock = <111111111>; + xlnx,slcr-div0-1000Mbps = <8>; + xlnx,slcr-div0-100Mbps = <8>; + xlnx,slcr-div0-10Mbps = <8>; + xlnx,slcr-div1-1000Mbps = <1>; + xlnx,slcr-div1-100Mbps = <5>; + xlnx,slcr-div1-10Mbps = <50>; + #address-cells = <0x1>; + #size-cells = <0x0>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@7 { + compatible = "marvell,88e1116r"; + device_type = "ethernet-phy"; + reg = <7>; + }; + }; + }; + + i2c0: i2c@e0004000 { + compatible = "xlnx,ps7-i2c-1.00.a"; + clocks = <&clkc 38>; + reg = <0xE0004000 0x1000>; + interrupts = <0 25 4>; + interrupt-parent = <&gic>; + bus-id = <0>; + input-clk = <111111111>; + i2c-clk = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + i2cswitch@74 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x74>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + osc@5d { + compatible = "si570"; + reg = <0x5d>; + factory-fout = <156250000>; + initial-fout = <148500000>; + }; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + hdmio@39 { + compatible = "adv7511"; + reg = <0x39>; + interrupts = <0 54 4>; + interrupt-parent = <&gic>; + dma-request = <&logicvc0>; + edid-addr = <0x50>; + video-input { + input-id = <1>; + input-style = <3>; + input-color-depth = <8>; + bit-justification = <1>; + hsync-polarity = <0>; + vsync-polarity = <0>; + clock-delay = <3>; + }; + video-output { + hdmi-mode = <0>; + output-format = <0>; + output-color-space = <0>; + up-conversion = <0>; + csc-enable = <1>; + csc-scaling-factor = <2>; + csc-coefficients { + a1 = <0x0B37>; + a2 = <0x0800>; + a3 = <0x0000>; + a4 = <0x1A86>; + b1 = <0x1A49>; + b2 = <0x0800>; + b3 = <0x1D3F>; + b4 = <0x0422>; + c1 = <0x0000>; + c2 = <0x0800>; + c3 = <0x0E2D>; + c4 = <0x1914>; + }; + }; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@54 { + compatible = "at,24c08"; + reg = <0x54>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + gpio@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + rtc@54 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; + + i2c@5{ + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + eeprom@50 { + compatible = "at,24c02"; + reg = <0x50>; + }; + }; + + i2c@6{ + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + eeprom@50 { + compatible = "at,24c02"; + reg = <0x50>; + }; + }; + + i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + hwmon@52 { + compatible = "pmbus,ucd9248"; + reg = <52>; + }; + hwmon@53 { + compatible = "pmbus,ucd9248"; + reg = <53>; + }; + hwmon@54 { + compatible = "pmbus,ucd9248"; + reg = <54>; + }; + }; + }; + }; + + i2c1: i2c@e0005000 { + compatible = "xlnx,ps7-i2c-1.00.a"; + clocks = <&clkc 39>; + reg = <0xE0005000 0x1000>; + interrupts = <0 48 4>; + interrupt-parent = <&gic>; + bus-id = <1>; + input-clk = <111111111>; + i2c-clk = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + i2cswitch@70 { + compatible = "nxp,pca9546"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + i2c_adv7611: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + ioexp: gpio@20 { + compatible = "nxp,pca9534"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + }; + }; + + sdhci@e0100000 { + compatible = "xlnx,ps7-sdhci-1.00.a"; + clocks = <&clkc 21>, <&clkc 32>; + clock-names = "ref_clk", "aper_clk"; + reg = <0xe0100000 0x1000>; + xlnx,has-cd = <0x1>; + interrupts = <0 24 4>; + interrupt-parent = <&gic>; + clock-frequency = <33333000>; + }; + + usb@e0002000 { + compatible = "xlnx,ps7-usb-1.00.a"; + clocks = <&clkc 28>; + reg = <0xe0002000 0x1000>; + interrupts = <0 21 4>; + interrupt-parent = <&gic>; + dr_mode = "host"; + phy_type = "ulpi"; + }; + + gpio@e000a000 { + compatible = "xlnx,ps7-gpio-1.00.a"; + clocks = <&clkc 42>; + reg = <0xe000a000 0x1000>; + interrupts = <0 20 4>; + interrupt-parent = <&gic>; + }; + + qspi0: spi@e000d000 { + compatible = "xlnx,ps7-qspi-1.00.a"; + clocks = <&clkc 10>, <&clkc 43>; + clock-names = "ref_clk", "aper_clk"; + reg = <0xE000D000 0x1000>; + interrupts = <0 19 4>; + interrupt-parent = <&gic>; + speed-hz = <200000000>; + num-chip-select = <1>; + #address-cells = <1>; + #size-cells = <0>; + is-dual = <0>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x100000 0x500000>; + }; + partition@qspi-device-tree { + label = "qspi-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@qspi-rootfs { + label = "qspi-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; + reg = <0xC00000 0x400000>; + }; + }; + }; + + devcfg@f8007000 { + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + reg = <0xf8007000 0x100>; + interrupts = <0 8 4>; + interrupt-parent = <&gic>; + }; + + xadc@f8007100 { + compatible = "xlnx,ps7-xadc-1.00.a"; + clocks = <&clkc 12>; + reg = <0xf8007100 0x20>; + interrupts = <0 7 4>; + interrupt-parent = <&gic>; + }; + + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + arm,primecell-periphid = <0x41330>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + clocks = <&clkc 27>; + interrupt-parent = <&gic>; + interrupts = <0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4>; + reg = <0xf8003000 0x1000>; + }; + + axi_sobel_0: axi-sobel@0x400D0000 { + compatible = "generic-uio"; + reg = <0x400D0000 0x10000>; + interrupts = <0 55 4>; + interrupt-parent = <&gic>; + }; + + yuv2rgb_0: v-ycrcb2rgb@0x40050000 { + compatible = "generic-uio"; + reg = <0x40050000 0x10000>; + }; + + tpg_0: v-tpg@40080000 { + compatible = "generic-uio"; + reg = <0x40080000 0x10000>; + }; + + cresample_0: v-cresample@40040000 { + compatible = "generic-uio"; + reg = <0x40040000 0x10000>; + }; + + vtc_0: v-tc@40070000 { + compatible = "generic-uio"; + reg = <0x40070000 0x10000>; + }; + + perf_mon_hp0_hp2: axi-perf-mon@400f0000 { + compatible = "generic-uio"; + reg = <0x400f0000 0x10000>; + }; + + axi_vdma_0: axivdma@0x40090000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,axi-vdma"; + ranges = <0x40090000 0x40090000 0x10000>; + reg = <0x40090000 0x10000>; + xlnx,flush-fsync = <0x1>; + xlnx,include-sg = <0x0>; + xlnx,num-fstores = <0x3>; + xlnx,family = "zynq-770"; + dma-channel@0x40090000 { + compatible = "xlnx,axi-vdma-s2mm-channel"; + interrupt-parent = <&gic>; + interrupts = <0 58 4>; + xlnx,datawidth = <0x08>; + xlnx,genlock-mode = <0x1>; + xlnx,include-dre = <0x1>; + xlnx,device-id = <0x0>; + }; + }; + + axi_vdma_1: axivdma@0x400B0000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,axi-vdma"; + ranges = <0x400B0000 0x400B0000 0x10000>; + reg = <0x400B0000 0x10000>; + xlnx,flush-fsync = <0x1>; + xlnx,include-sg = <0x0>; + xlnx,num-fstores = <0x3>; + xlnx,family = "zynq-770"; + dma-s2mmchannel@0x400B0000 { + compatible = "xlnx,axi-vdma-s2mm-channel"; + interrupt-parent = <&gic>; + interrupts = <0 57 4>; + xlnx,datawidth = <0x08>; + xlnx,genlock-mode = <0x1>; + xlnx,include-dre = <0x1>; + xlnx,device-id = <0x1>; + }; + dma-mm2schannel@0x400B0000 { + compatible = "xlnx,axi-vdma-mm2s-channel"; + interrupt-parent = <&gic>; + interrupts = <0 56 4>; + xlnx,datawidth = <0x08>; + xlnx,genlock-mode = <0x1>; + xlnx,include-dre = <0x1>; + xlnx,device-id = <0x1>; + }; + }; + + logicvc0: logicvc@40030000 { + compatible = "xylon,logicvc-3.00.a"; + reg = <0x40030000 0x6000>; + interrupt-parent = <&gic>; + interrupts = <0 59 4>; + + xlnx,display-interface = <0>; + xlnx,display-color-space = <1>; + xlnx,ip-license-type = <0>; + xlnx,ip-major-revision = <3>; + xlnx,ip-minor-revision = <0>; + xlnx,ip-patch-level = <0>; + xlnx,num-of-layers = <3>; + xlnx,layer-0-type = <0>; + xlnx,layer-0-alpha-mode = <0>; + xlnx,layer-0-data-width = <16>; + xlnx,layer-0-offset = <0>; + xlnx,layer-1-type = <0>; + xlnx,layer-1-alpha-mode = <0>; + xlnx,layer-1-data-width = <24>; + xlnx,layer-1-offset = <1620>; + xlnx,layer-2-type = <0>; + xlnx,layer-2-alpha-mode = <0>; + xlnx,layer-2-data-width = <24>; + xlnx,layer-2-offset = <6480>; + xlnx,layer-3-type = <0>; + xlnx,layer-3-alpha-mode = <0>; + xlnx,layer-3-data-width = <24>; + xlnx,layer-3-offset = <9720>; + xlnx,layer-4-type = <0>; + xlnx,layer-4-alpha-mode = <0>; + xlnx,layer-4-data-width = <24>; + xlnx,layer-4-offset = <12960>; + xlnx,buffer-0-offset = <1080>; + xlnx,buffer-1-offset = <1080>; + xlnx,buffer-2-offset = <1080>; + xlnx,buffer-3-offset = <1080>; + xlnx,buffer-4-offset = <1080>; + xlnx,little-endian = <1>; + xlnx,readable-regs = <1>; + xlnx,row-stride = <2048>; + xlnx,use-background = <1>; + xlnx,use-size-position = <1>; + xlnx,vmem-baseaddr = <0x30000000>; + xlnx,vmem-highaddr = <0x3FFFFFFF>; + + //0-EXT; 1-ZynqPS; 2-logiCLK; 3-SI570 + pixel-clock-source = <3>; + pixel-data-invert = <0>; + pixel-clock-active-high = <1>; + pixel-component-format = "ARGB"; + pixel-component-layer = <0>,<1>,<2>; + active-layer = <0>; + videomode = "1920x1080"; + edid { + preffered-videomode = <1>; + display-data = <0>; + }; + }; + + xylon-video-params { + 800x480_TM050RBH01 { + name = "800x480_TM050RBH01"; + refresh = <60>; + xres = <800>; + yres = <480>; + pixclock-khz = <30000>; + left-margin = <40>; + right-margin = <40>; + upper-margin = <29>; + lower-margin = <13>; + hsync-len = <48>; + vsync-len = <3>; + sync = <0>; + vmode = <0>; + }; + 1280x720 { + name = "1280x720"; + refresh = <60>; + xres = <1280>; + yres = <720>; + pixclock-khz = <74250>; + left-margin = <220>; + right-margin = <110>; + upper-margin = <20>; + lower-margin = <5>; + hsync-len = <40>; + vsync-len = <5>; + sync = <0>; + vmode = <0>; + }; + 1680x1050 { + name = "1680x1050"; + refresh = <60>; + xres = <1680>; + yres = <1050>; + pixclock-khz = <119000>; + left-margin = <80>; + right-margin = <48>; + upper-margin = <21>; + lower-margin = <3>; + hsync-len = <32>; + vsync-len = <6>; + sync = <0>; + vmode = <0>; + }; + 1920x1080 { + name = "1920x1080"; + refresh = <60>; + xres = <1920>; + yres = <1080>; + pixclock-khz = <148500>; + left-margin = <148>; + right-margin = <88>; + upper-margin = <36>; + lower-margin = <4>; + hsync-len = <44>; + vsync-len = <5>; + sync = <0>; + vmode = <0>; + }; + }; + }; +}; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc702-drm-v4l2.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc702-drm-v4l2.dts 2014-07-20 22:06:33.915345982 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f + * + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + ethernet0 = &ps7_ethernet_0; + i2c0 = &ps7_i2c_0; + serial0 = &ps7_uart_1; + spi0 = &ps7_qspi_0; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x40000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_can_0: ps7-can@e0008000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 19>, <&clkc 36>; + compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 28 4>; + reg = <0xe0008000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + arm,primecell-periphid = <0x41330>; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_ethernet_0: ps7-ethernet@e000b000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; + local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + reg = <0xe000b000 0x1000>; + xlnx,enet-reset = "MIO 11"; + xlnx,eth-mode = <0x1>; + xlnx,has-mdio = <0x1>; + xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@7 { + compatible = "marvell,88e1116r"; + device_type = "ethernet-phy"; + reg = <7>; + } ; + } ; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0x0>; + gpio-mask-low = <0x5600>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_i2c_0: ps7-i2c@e0004000 { + bus-id = <0>; + clocks = <&clkc 38>; + compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 25 4>; + reg = <0xe0004000 0x1000>; + xlnx,has-interrupt = <0x0>; + xlnx,i2c-reset = "MIO 13"; + #address-cells = <1>; + #size-cells = <0>; + i2cswitch@74 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x74>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + si570: si570@5d { + compatible = "si570"; + reg = <0x5d>; + factory-fout = <156250000>; + initial-fout = <148500000>; + }; + }; + + i2c_adv7511: i2c@1 { + #size-cells = <0>; + #address-cells = <1>; + reg = <1>; + + adv7511: adv7511@39 { + compatible = "adi,adv7511"; + reg = <0x39>; + adi,input-style = <0x02>; + adi,input-id = <0x01>; + adi,input-color-depth = <0x3>; + adi,sync-pulse = <0x03>; + adi,bit-justification = <0x01>; + adi,up-conversion = <0x00>; + adi,timing-generation-sequence = <0x00>; + adi,vsync-polarity = <0x02>; + adi,hsync-polarity = <0x02>; + adi,tdms-clock-inversion; + adi,clock-delay = <0x00>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@54 { + compatible = "at,24c08"; + reg = <0x54>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + gpio@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + rtc@54 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; + + i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + hwmon@52 { + compatible = "pmbus,ucd9248"; + reg = <52>; + }; + hwmon@53 { + compatible = "pmbus,ucd9248"; + reg = <53>; + }; + hwmon@54 { + compatible = "pmbus,ucd9248"; + reg = <54>; + }; + }; + }; + + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_qspi_0: ps7-qspi@e000d000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; + is-dual = <0>; + num-chip-select = <1>; + reg = <0xe000d000 0x1000>; + xlnx,fb-clk = <0x1>; + xlnx,qspi-mode = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x100000 0x500000>; + }; + partition@qspi-device-tree { + label = "qspi-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@qspi-rootfs { + label = "qspi-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; + reg = <0xC00000 0x400000>; + }; + }; + + } ; + ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-linear-1.00.a"; + reg = <0xfc000000 0x1000000>; + } ; + ps7_ram_0: ps7-ram@0 { + compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xfffc0000 0x40000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_sd_0: ps7-sdio@e0100000 { + clock-frequency = <50000000>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 21>, <&clkc 32>; + compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 24 4>; + reg = <0xe0100000 0x1000>; + xlnx,has-cd = <0x1>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x1>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_usb_0: ps7-usb@e0002000 { + clocks = <&clkc 28>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "host"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 21 4>; + phy_type = "ulpi"; + reg = <0xe0002000 0x1000>; + xlnx,usb-reset = "MIO 7"; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + + axi_vdma_0: axivdma@40000000 { + compatible = "xlnx,axi-vdma"; + reg = <0x40000000 0x10000>; + + xlnx,flush-fsync = <1>; + xlnx,num-fstores = <1>; + xlnx,family = "zynq-770"; + + #dma-cells = <1>; + dma-mm2schannel@40000000 { + compatible = "xlnx,axi-vdma-mm2s-channel"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 58 0x4>; + xlnx,datawidth = <0x40>; + xlnx,device-id = <0>; + }; + }; + + axi_vdma_1: axivdma@40060000 { + compatible = "xlnx,axi-vdma"; + reg = <0x40060000 0x10000>; + + xlnx,flush-fsync = <1>; + xlnx,num-fstores = <1>; + xlnx,family = "zynq-770"; + + #dma-cells = <1>; + dma-mm2schannel@40060000 { + compatible = "xlnx,axi-vdma-mm2s-channel"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 57 0x4>; + xlnx,datawidth = <0x40>; + xlnx,device-id = <0>; + }; + dma-s2mmchannel@40060000 { + compatible = "xlnx,axi-vdma-s2mm-channel"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 56 4>; + xlnx,datawidth = <0x40>; + xlnx,include-dre; + xlnx,device-id = <1>; + }; + }; + + axi_vdma_2: axivdma@400a0000 { + compatible = "xlnx,axi-vdma"; + reg = <0x400a0000 0x10000>; + + xlnx,flush-fsync = <1>; + xlnx,num-fstores = <1>; + xlnx,family = "zynq-770"; + + #dma-cells = <1>; + dma-mm2schannel@400a0000 { + compatible = "xlnx,axi-vdma-mm2s-channel"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 35 0x4>; + xlnx,datawidth = <0x40>; + xlnx,device-id = <0>; + }; + }; + + vtc_0: v-tc@40010000 { + compatible = "xlnx,v-tc-6.0"; + reg = <0x40010000 0x10000>; + interrupts = <0 54 4>; + interrupt-parent = <&ps7_scugic_0>; + }; + + cresample_0: v-cresample@40020000 { + compatible = "xlnx,v-cresample-4.0"; + reg = <0x40020000 0x10000>; + xlnx,input-format = "yuv444"; + xlnx,output-format = "yuv422"; + }; + + rgb2ycrcb_0: v-rgb2ycrcb@40030000 { + compatible = "xlnx,v-rgb2ycrcb-7.0"; + reg = <0x40030000 0x10000>; + }; + + osd_0: v-osd@40040000 { + compatible = "xlnx,v-osd-6.0"; + reg = <0x40040000 0x10000>; + xlnx,num-layers = <3>; + xlnx,screen-width = <1920>; + }; + + xilinx_drm { + compatible = "xlnx,drm"; + osd = <&osd_0>; + vtc = <&vtc_0>; + encoder-slave = <&adv7511>; + clocks = <&si570>; + planes { + plane0 { + dmas = <&axi_vdma_0 0>; + dma-names = "vdma"; + rgb2yuv = <&rgb2ycrcb_0>; + cresample = <&cresample_0>; + }; + plane1 { + dmas = <&axi_vdma_1 0>; + dma-names = "vdma"; + }; + plane2 { + dmas = <&axi_vdma_2 0>; + dma-names = "vdma"; + }; + }; + }; + + axi_tpg_0: axi_tpg@40050000 { + compatible = "xlnx,axi-tpg"; + reg = <0x40050000 0x10000>; + + xlnx,axi-video-format = "yuv422"; + xlnx,axi-video-width = <8>; + + port { + tpg0_out: endpoint { + remote-endpoint = <&vcap0_in>; + }; + }; + }; + + axi_video_cap { + compatible = "xlnx,axi-video"; + dmas = <&axi_vdma_1 1>; + dma-names = "vdma-s2mm"; + + vdma-s2mm { + port { + vcap0_in: endpoint { + remote-endpoint = <&tpg0_out>; + }; + }; + }; + }; + + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc702.dts =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/boot/dts/zynq-zc702.dts 2014-07-20 22:05:50.283065845 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc702.dts 2014-07-20 22:06:33.926345800 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ /* - * Copyright (C) 2011 Xilinx - * Copyright (C) 2012 National Instruments Corp. + * Device Tree Generator version: 1.1 * - * 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. + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f * - * 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. */ -/dts-v1/; -/include/ "zynq-7000.dtsi" +/dts-v1/; / { - model = "Zynq ZC702 Development Board"; - compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000"; - - memory { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + ethernet0 = &ps7_ethernet_0; + i2c0 = &ps7_i2c_0; + serial0 = &ps7_uart_1; + spi0 = &ps7_qspi_0; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { device_type = "memory"; reg = <0x0 0x40000000>; - }; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_can_0: ps7-can@e0008000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 19>, <&clkc 36>; + compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 28 4>; + reg = <0xe0008000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_ethernet_0: ps7-ethernet@e000b000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; + enet-reset = <&ps7_gpio_0 11 0>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; + local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + reg = <0xe000b000 0x1000>; + xlnx,eth-mode = <0x1>; + xlnx,has-mdio = <0x1>; + xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@7 { + compatible = "marvell,88e1116r"; + device_type = "ethernet-phy"; + reg = <7>; + } ; + } ; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0x0>; + gpio-mask-low = <0x5600>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_i2c_0: ps7-i2c@e0004000 { + bus-id = <0>; + clocks = <&clkc 38>; + compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; + i2c-reset = <&ps7_gpio_0 13 0>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 25 4>; + reg = <0xe0004000 0x1000>; + xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + i2cswitch@74 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x74>; - chosen { - bootargs = "console=ttyPS0,115200 earlyprintk"; - }; + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + si570: clock-generator@5d { + #clock-cells = <0>; + compatible = "silabs,si570"; + temperature-stability = <50>; + reg = <0x5d>; + factory-fout = <156250000>; + clock-frequency = <148500000>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@54 { + compatible = "at,24c08"; + reg = <0x54>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + gpio@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + rtc@54 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; + + i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + hwmon@52 { + compatible = "pmbus,ucd9248"; + reg = <52>; + }; + hwmon@53 { + compatible = "pmbus,ucd9248"; + reg = <53>; + }; + hwmon@54 { + compatible = "pmbus,ucd9248"; + reg = <54>; + }; + }; + }; -}; + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_qspi_0: ps7-qspi@e000d000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; + is-dual = <0>; + num-chip-select = <1>; + reg = <0xe000d000 0x1000>; + xlnx,fb-clk = <0x1>; + xlnx,qspi-mode = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x100000 0x500000>; + }; + partition@qspi-device-tree { + label = "qspi-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@qspi-rootfs { + label = "qspi-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; + reg = <0xC00000 0x400000>; + }; + }; -&uart1 { - status = "okay"; -}; + } ; + ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-linear-1.00.a"; + reg = <0xfc000000 0x1000000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_sd_0: ps7-sdio@e0100000 { + clock-frequency = <50000000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 21>, <&clkc 32>; + compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci-8.9a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 24 4>; + reg = <0xe0100000 0x1000>; + xlnx,has-cd = <0x1>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x1>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_usb_0: ps7-usb@e0002000 { + clocks = <&clkc 28>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "host"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 21 4>; + phy_type = "ulpi"; + reg = <0xe0002000 0x1000>; + usb-reset = <&ps7_gpio_0 7 0>; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc706.dts =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/boot/dts/zynq-zc706.dts 2014-07-20 22:05:50.285065813 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc706.dts 2014-07-20 22:06:33.939345586 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ /* - * Copyright (C) 2011 Xilinx - * Copyright (C) 2012 National Instruments Corp. - * Copyright (C) 2013 Xilinx + * Device Tree Generator version: 1.1 * - * 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. + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f * - * 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. */ -/dts-v1/; -/include/ "zynq-7000.dtsi" +/dts-v1/; / { - model = "Zynq ZC706 Development Board"; - compatible = "xlnx,zynq-zc706", "xlnx,zynq-7000"; - - memory { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + ethernet0 = &ps7_ethernet_0; + i2c0 = &ps7_i2c_0; + serial0 = &ps7_uart_1; + spi0 = &ps7_qspi_0; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { device_type = "memory"; - reg = <0 0x40000000>; - }; + reg = <0x0 0x40000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_ethernet_0: ps7-ethernet@e000b000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; + enet-reset = <&ps7_gpio_0 47 0>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; + local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + reg = <0xe000b000 0x1000>; + xlnx,eth-mode = <0x1>; + xlnx,has-mdio = <0x1>; + xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@7 { + compatible = "marvell,88e1116r"; + device_type = "ethernet-phy"; + reg = <7>; + } ; + } ; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0x0>; + gpio-mask-low = <0x0>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_i2c_0: ps7-i2c@e0004000 { + bus-id = <0>; + clocks = <&clkc 38>; + compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; + i2c-reset = <&ps7_gpio_0 46 0>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 25 4>; + reg = <0xe0004000 0x1000>; + xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + i2cswitch@74 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x74>; - chosen { - bootargs = "console=ttyPS0,115200 earlyprintk"; - }; + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + si570: clock-generator@5d { + #clock-cells = <0>; + compatible = "silabs,si570"; + temperature-stability = <50>; + reg = <0x5d>; + factory-fout = <156250000>; + clock-frequency = <148500000>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@54 { + compatible = "at,24c08"; + reg = <0x54>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + gpio@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; + + + i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + ucd90120@65 { + compatible = "pmbus,ucd90120"; + reg = <0x65>; + }; + }; + }; -}; + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_qspi_0: ps7-qspi@e000d000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; + is-dual = <1>; + num-chip-select = <1>; + reg = <0xe000d000 0x1000>; + xlnx,fb-clk = <0x1>; + xlnx,qspi-mode = <0x2>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x100000 0x500000>; + }; + partition@qspi-device-tree { + label = "qspi-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@qspi-rootfs { + label = "qspi-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; + reg = <0xC00000 0x400000>; + }; + }; -&uart1 { - status = "okay"; -}; + } ; + ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-linear-1.00.a"; + reg = <0xfc000000 0x2000000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_sd_0: ps7-sdio@e0100000 { + clock-frequency = <50000000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 21>, <&clkc 32>; + compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci-8.9a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 24 4>; + reg = <0xe0100000 0x1000>; + xlnx,has-cd = <0x1>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x1>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_ttc_1: ps7-ttc@f8002000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 37 4>, <0 38 4>, <0 39 4>; + reg = <0xf8002000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_usb_0: ps7-usb@e0002000 { + clocks = <&clkc 28>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "host"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 21 4>; + phy_type = "ulpi"; + reg = <0xe0002000 0x1000>; + usb-reset = <&ps7_gpio_0 7 0>; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc770-xm010.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc770-xm010.dts 2014-07-20 22:06:33.950345405 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f + * + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + ethernet0 = &ps7_ethernet_0; + i2c0 = &ps7_i2c_0; + serial0 = &ps7_uart_1; + spi0 = &ps7_spi_1; + spi1 = &ps7_qspi_0; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x40000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_can_0: ps7-can@e0008000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 19>, <&clkc 36>; + compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 28 4>; + reg = <0xe0008000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_ethernet_0: ps7-ethernet@e000b000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; + local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + reg = <0xe000b000 0x1000>; + xlnx,eth-mode = <0x1>; + xlnx,has-mdio = <0x1>; + xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@7 { + compatible = "marvell,88e1116r"; + device_type = "ethernet-phy"; + reg = <7>; + } ; + } ; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0x0>; + gpio-mask-low = <0x200>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_i2c_0: ps7-i2c@e0004000 { + bus-id = <0>; + clocks = <&clkc 38>; + compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 25 4>; + reg = <0xe0004000 0x1000>; + xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + m24c02_eeprom@52 { + compatible = "at,24c02"; + reg = <0x52>; + }; + + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_qspi_0: ps7-qspi@e000d000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; + is-dual = <0>; + num-chip-select = <1>; + reg = <0xe000d000 0x1000>; + xlnx,fb-clk = <0x1>; + xlnx,qspi-mode = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x100000 0x500000>; + }; + partition@qspi-device-tree { + label = "qspi-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@qspi-rootfs { + label = "qspi-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; + reg = <0xC00000 0x400000>; + }; + }; + + } ; + ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-linear-1.00.a"; + reg = <0xfc000000 0x1000000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_sd_0: ps7-sdio@e0100000 { + clock-frequency = <50000000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 21>, <&clkc 32>; + compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci-8.9a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 24 4>; + reg = <0xe0100000 0x1000>; + xlnx,has-cd = <0x1>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x1>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_spi_1: ps7-spi@e0007000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 26>, <&clkc 35>; + compatible = "xlnx,ps7-spi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 49 4>; + num-chip-select = <4>; + reg = <0xe0007000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { + compatible = "sst25wf080"; + reg = <1>; + spi-max-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@test { + label = "spi-flash"; + reg = <0x0 0x100000>; + }; + }; + + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_usb_0: ps7-usb@e0002000 { + clocks = <&clkc 28>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "host"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 21 4>; + phy_type = "ulpi"; + reg = <0xe0002000 0x1000>; + usb-reset = <&ps7_gpio_0 7 0>; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc770-xm011.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc770-xm011.dts 2014-07-20 22:06:33.961345223 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f + * + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + i2c0 = &ps7_i2c_1; + serial0 = &ps7_uart_1; + spi0 = &ps7_spi_0; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x40000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_can_0: ps7-can@e0008000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 19>, <&clkc 36>; + compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 28 4>; + reg = <0xe0008000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0xfc>; + gpio-mask-low = <0xff8002>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_i2c_1: ps7-i2c@e0005000 { + bus-id = <0>; + clocks = <&clkc 39>; + compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 48 4>; + reg = <0xe0005000 0x1000>; + xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + m24c02_eeprom@52 { + compatible = "at,24c02"; + reg = <0x52>; + }; + + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_smcc_0: ps7-smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 11>, <&clkc 44>; + compatible = "xlnx,ps7-smcc-1.00.a", "xlnx,ps7-smc"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 18 4>; + ranges ; + reg = <0xe000e000 0x1000>; + xlnx,addr25 = <0x0>; + xlnx,nor-chip-sel0 = <0x0>; + xlnx,nor-chip-sel1 = <0x0>; + xlnx,sram-chip-sel0 = <0x0>; + xlnx,sram-chip-sel1 = <0x0>; + ps7_nand_0: ps7-nand@e1000000 { + compatible = "xlnx,ps7-nand-1.00.a"; + reg = <0xe1000000 0x1000000>; + xlnx,nand-cycle-t0 = <0x4>; + xlnx,nand-cycle-t1 = <0x4>; + xlnx,nand-cycle-t2 = <0x1>; + xlnx,nand-cycle-t3 = <0x2>; + xlnx,nand-cycle-t4 = <0x2>; + xlnx,nand-cycle-t5 = <0x2>; + xlnx,nand-cycle-t6 = <0x4>; + xlnx,nand-width = <0x8>; + #address-cells = <1>; + #size-cells = <1>; + + partition@nand-fsbl-uboot { + label = "nand-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@nand-linux { + label = "nand-linux"; + reg = <0x100000 0x500000>; + }; + partition@nand-device-tree { + label = "nand-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@nand-rootfs { + label = "nand-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@nand-bitstream { + label = "nand-bitstream"; + reg = <0xC00000 0x400000>; + + }; + + } ; + } ; + ps7_spi_0: ps7-spi@e0006000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 25>, <&clkc 34>; + compatible = "xlnx,ps7-spi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 26 4>; + num-chip-select = <4>; + reg = <0xe0006000 0x1000>; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_usb_1: ps7-usb@e0003000 { + clocks = <&clkc 29>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "host"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 44 4>; + phy_type = "ulpi"; + reg = <0xe0003000 0x1000>; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc770-xm012.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc770-xm012.dts 2014-07-20 22:06:33.969345091 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f + * + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + i2c0 = &ps7_i2c_0; + i2c1 = &ps7_i2c_1; + serial0 = &ps7_uart_1; + spi0 = &ps7_spi_1; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x40000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_can_1: ps7-can@e0009000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 20>, <&clkc 37>; + compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 51 4>; + reg = <0xe0009000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0x0>; + gpio-mask-low = <0x4004>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_i2c_0: ps7-i2c@e0004000 { + bus-id = <0>; + clocks = <&clkc 38>; + compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 25 4>; + reg = <0xe0004000 0x1000>; + xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + m24c02_eeprom@52 { + compatible = "at,24c02"; + reg = <0x52>; + }; + + } ; + ps7_i2c_1: ps7-i2c@e0005000 { + bus-id = <1>; + clocks = <&clkc 39>; + compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 48 4>; + reg = <0xe0005000 0x1000>; + xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + m24c02_eeprom@52 { + compatible = "at,24c02"; + reg = <0x52>; + }; + + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_smcc_0: ps7-smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 11>, <&clkc 44>; + compatible = "xlnx,ps7-smcc-1.00.a", "xlnx,ps7-smc"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 18 4>; + ranges ; + reg = <0xe000e000 0x1000>; + xlnx,addr25 = <0x1>; + xlnx,nor-chip-sel0 = <0x1>; + xlnx,nor-chip-sel1 = <0x0>; + xlnx,sram-chip-sel0 = <0x0>; + xlnx,sram-chip-sel1 = <0x0>; + ps7_nor_0: ps7-nor@e2000000 { + bank-width = <1>; + compatible = "xlnx,ps7-nor-1.00.a", "cfi-flash"; + reg = <0xe2000000 0x1000>; + xlnx,sram-cycle-t0 = <0xb>; + xlnx,sram-cycle-t1 = <0xb>; + xlnx,sram-cycle-t2 = <0x4>; + xlnx,sram-cycle-t3 = <0x4>; + xlnx,sram-cycle-t4 = <0x3>; + xlnx,sram-cycle-t5 = <0x3>; + xlnx,sram-cycle-t6 = <0x2>; + #address-cells = <1>; + #size-cells = <1>; + + partition@nor-fsbl-uboot { + label = "nor-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@nor-linux { + label = "nor-linux"; + reg = <0x100000 0x500000>; + }; + partition@nor-device-tree { + label = "nor-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@nor-rootfs { + label = "nor-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@nor-bitstream { + label = "nor-bitstream"; + reg = <0xC00000 0x400000>; + }; + } ; + } ; + ps7_spi_1: ps7-spi@e0007000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 26>, <&clkc 35>; + compatible = "xlnx,ps7-spi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 49 4>; + num-chip-select = <4>; + reg = <0xe0007000 0x1000>; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_ttc_1: ps7-ttc@f8002000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 37 4>, <0 38 4>, <0 39 4>; + reg = <0xf8002000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc770-xm013.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zc770-xm013.dts 2014-07-20 22:06:33.978344943 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f + * + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + ethernet0 = &ps7_ethernet_1; + i2c0 = &ps7_i2c_1; + serial0 = &ps7_uart_0; + spi0 = &ps7_spi_0; + spi1 = &ps7_qspi_0; + } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0000000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x40000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_can_1: ps7-can@e0009000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 20>, <&clkc 37>; + compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 51 4>; + reg = <0xe0009000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_ethernet_1: ps7-ethernet@e000c000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 14>, <&clkc 31>; + compatible = "xlnx,ps7-ethernet-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 45 4>; + local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + reg = <0xe000c000 0x1000>; + xlnx,eth-mode = <0x1>; + xlnx,has-mdio = <0x1>; + xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@7 { + compatible = "vitesse,vsc8211"; + device_type = "ethernet-phy"; + reg = <7>; + } ; + } ; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0xdc000>; + gpio-mask-low = <0xfc00080>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_i2c_1: ps7-i2c@e0005000 { + bus-id = <0>; + clocks = <&clkc 39>; + compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 48 4>; + reg = <0xe0005000 0x1000>; + xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + si570: clock-generator@55 { + #clock-cells = <0>; + compatible = "silabs,si570"; + temperature-stability = <50>; + reg = <0x55>; + factory-fout = <156250000>; + clock-frequency = <148500000>; + }; + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_qspi_0: ps7-qspi@e000d000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; + is-dual = <1>; + num-chip-select = <1>; + reg = <0xe000d000 0x1000>; + xlnx,fb-clk = <0x1>; + xlnx,qspi-mode = <0x2>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x100000 0x500000>; + }; + partition@qspi-device-tree { + label = "qspi-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@qspi-rootfs { + label = "qspi-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; + reg = <0xC00000 0x400000>; + }; + }; + + } ; + ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-linear-1.00.a"; + reg = <0xfc000000 0x2000000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_spi_0: ps7-spi@e0006000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 25>, <&clkc 34>; + compatible = "xlnx,ps7-spi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 26 4>; + num-chip-select = <4>; + reg = <0xe0006000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + eeprom: at25@0 { + at25,byte-len = <8192>; + at25,addr-mode = <2>; + at25,page-size = <32>; + + compatible = "atmel,at25"; + reg = <2>; + spi-max-frequency = <1000000>; + }; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_uart_0: serial@e0000000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 23>, <&clkc 40>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 27 4>; + port-number = <0>; + reg = <0xe0000000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_wdt_0: ps7-wdt@f8005000 { + clocks = <&clkc 45>; + compatible = "xlnx,ps7-wdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset = <0>; + timeout = <10>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zed.dts =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/boot/dts/zynq-zed.dts 2014-07-20 22:05:50.287065779 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/boot/dts/zynq-zed.dts 2014-07-20 22:06:33.988344778 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ /* - * Copyright (C) 2011 Xilinx - * Copyright (C) 2012 National Instruments Corp. - * Copyright (C) 2013 Xilinx + * Device Tree Generator version: 1.1 * - * 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. + * (C) Copyright 2007-2013 Xilinx, Inc. + * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK <monstr@monstr.eu> + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 14.5 EDK_P.58f * - * 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. */ -/dts-v1/; -/include/ "zynq-7000.dtsi" +/dts-v1/; / { - model = "Zynq Zed Development Board"; + #address-cells = <1>; + #size-cells = <1>; compatible = "xlnx,zynq-7000"; - - memory { - device_type = "memory"; - reg = <0 0x20000000>; - }; - + model = "Xilinx Zynq"; + aliases { + ethernet0 = &ps7_ethernet_0; + serial0 = &ps7_uart_1; + spi0 = &ps7_qspi_0; + } ; chosen { - bootargs = "console=ttyPS0,115200 earlyprintk"; - }; - -}; + bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rootwait rw earlyprintk"; + linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { + bus-handle = <&ps7_axi_interconnect_0>; + compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + interrupt-handle = <&ps7_scugic_0>; + reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; + reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; + reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; + reg = <0x0 0x20000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; + reg = <0xf800b000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { + clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; + clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 8 4>; + reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + clock-names = "apb_pclk"; + clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; + interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", + "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; + reg = <0xf8003000 0x1000>; + } ; + ps7_ethernet_0: ps7-ethernet@e000b000 { + #address-cells = <1>; + #size-cells = <0>; + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; + local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + reg = <0xe000b000 0x1000>; + xlnx,eth-mode = <0x1>; + xlnx,has-mdio = <0x1>; + xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@0 { + compatible = "marvell,88e1510"; + device_type = "ethernet-phy"; + reg = <0>; + } ; + } ; + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; + clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0xc0000>; + gpio-mask-low = <0xfe81>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; + reg = <0xe0200000 0x1000>; + } ; + ps7_ocmc_0: ps7-ocmc@f800c000 { + compatible = "xlnx,ps7-ocmc-1.00.a", "xlnx,zynq-ocm-1.0"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; + reg = <0xf800c000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { + arm,data-latency = <3 2 2>; + arm,tag-latency = <2 2 2>; + cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 2 4>; + reg = <0xf8f02000 0x1000>; + } ; + ps7_qspi_0: ps7-qspi@e000d000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; + is-dual = <0>; + num-chip-select = <1>; + reg = <0xe000d000 0x1000>; + xlnx,fb-clk = <0x1>; + xlnx,qspi-mode = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x100000 0x500000>; + }; + partition@qspi-device-tree { + label = "qspi-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@qspi-rootfs { + label = "qspi-rootfs"; + reg = <0x620000 0x5E0000>; + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; + reg = <0xC00000 0x400000>; + }; + }; -&uart1 { - status = "okay"; -}; + } ; + ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-linear-1.00.a"; + reg = <0xfc000000 0x1000000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; + num_cpus = <2>; + num_interrupts = <96>; + reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 13 0x301>; + reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { + clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <1 14 0x301>; + reg = <0xf8f00620 0xe0>; + } ; + ps7_sd_0: ps7-sdio@e0100000 { + clock-frequency = <50000000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 21>, <&clkc 32>; + compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci-8.9a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 24 4>; + reg = <0xe0100000 0x1000>; + xlnx,has-cd = <0x1>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x1>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; + reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + clkc: clkc { + #clock-cells = <1>; + 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"; + compatible = "xlnx,ps7-clkc"; + fclk-enable = <0xf>; + ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { + clocks = <&clkc 6>; + compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; + interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 10 4>, <0 11 4>, <0 12 4>; + reg = <0xf8001000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { + clock-names = "ref_clk", "aper_clk"; + clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 50 4>; + port-number = <0>; + reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; + } ; + ps7_usb_0: ps7-usb@e0002000 { + clocks = <&clkc 28>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "host"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 21 4>; + phy_type = "ulpi"; + reg = <0xe0002000 0x1000>; + } ; + ps7_xadc: ps7-xadc@f8007100 { + clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; + reg = <0xf8007100 0x20>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/arm/configs/xilinx_zynq_apf_defconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/configs/xilinx_zynq_apf_defconfig 2014-07-20 22:06:34.025344167 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.12.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="arm-xilinx-linux-gnueabi-" +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="-xilinx-trd" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +# CONFIG_AUDIT is not set + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_GENERIC_SCHED_CLOCK=y +# CONFIG_CGROUPS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_PCI_QUIRKS=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +# CONFIG_FREEZER is not set + +# +# System Type +# +CONFIG_MMU=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set + +# +# Multiple platform selection +# + +# +# CPU Core family selection +# +# CONFIG_ARCH_MULTI_V6 is not set +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_MULTI_V6_V7=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_BCM is not set +CONFIG_GPIO_PCA953X=y +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U8500 is not set +CONFIG_ARCH_VEXPRESS=y + +# +# Versatile Express platform type +# +CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y +# CONFIG_ARCH_VEXPRESS_CA9X4 is not set +CONFIG_PLAT_VERSATILE_CLCD=y +CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_WM8850 is not set +CONFIG_ARCH_ZYNQ=y + +# +# Xilinx Specific Options +# +CONFIG_XILINX_L1_PREFETCH=y +CONFIG_XILINX_L2_PREFETCH=y +CONFIG_XILINX_AXIPCIE=y +CONFIG_PLAT_VERSATILE=y +CONFIG_ARM_TIMER_SP804=y + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +CONFIG_PL310_ERRATA_588369=y +# CONFIG_ARM_ERRATA_643719 is not set +CONFIG_ARM_ERRATA_720789=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_ERRATA_775420=y +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_773022 is not set +CONFIG_ICST=y + +# +# Bus support +# +CONFIG_ARM_AMBA=y +CONFIG_PCI=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set + +# +# PCI host controller drivers +# +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HAVE_ARM_SCU=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_ARM_TWD=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_ARCH_NR_GPIO=1024 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ_FIXED=0 +CONFIG_HZ_100=y +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +# CONFIG_ZBUD is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_XEN is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_ARM_ZYNQ_CPUFREQ=y + +# +# CPU Idle +# +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +# CONFIG_KERNEL_MODE_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +# CONFIG_SUSPEND is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=m +# CONFIG_IP_MROUTE is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NET_MPLS_GSO is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +# CONFIG_DMA_SHARED_BUFFER is not set +CONFIG_DMA_CMA=y + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=256 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 + +# +# Bus devices +# +# CONFIG_ARM_CCI is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +CONFIG_MTD_M25P80=y +# CONFIG_M25PXX_USE_FAST_READ is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_ZYNQ=y +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_MTD=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_VIRTIO_BLK is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_ARM_CHARLCD is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +CONFIG_SI570=y +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_HAVE_PATA_PLATFORM=y +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_VIRTIO_NET is not set +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMD is not set +CONFIG_NET_VENDOR_ARC=y +# CONFIG_ARC_EMAC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_MACB is not set +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +CONFIG_TIGON3=y +# CONFIG_BNX2X is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EXAR is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +CONFIG_E1000E=y +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +CONFIG_NET_VENDOR_I825XX=y +# CONFIG_IP1000 is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +CONFIG_R8169=y +# CONFIG_SH_ETH is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_SFC is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +CONFIG_XILINX_EMACLITE=y +CONFIG_XILINX_AXI_EMAC=y +CONFIG_XILINX_PS_EMAC=y +# CONFIG_XILINX_PS_EMAC_HWTSTAMP is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +CONFIG_MARVELL_PHY=y +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +CONFIG_VITESSE_PHY=y +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y +# CONFIG_MDIO_GPIO is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_HOSTAP is not set +# CONFIG_WL_TI is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_OLPC_APSP is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_PCH_UART is not set +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +CONFIG_XILINX_DEVCFG=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_VERSATILE is not set +CONFIG_I2C_ZYNQ=y +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_ZYNQ_QSPI=y +# CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED is not set +CONFIG_SPI_ZYNQ=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_HSI is not set + +# +# PPS support +# +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +CONFIG_GPIO_XILINX=y +CONFIG_GPIO_ZYNQ=y +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X_IRQ is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# LPC GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_SMB347 is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_RESTART is not set +CONFIG_POWER_RESET_VEXPRESS=y +# CONFIG_POWER_AVS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_SENSORS_XADCPS=y +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +CONFIG_ZYNQ_WATCHDOG=y +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_MEN_A21_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_VEXPRESS_CONFIG=y +# CONFIG_REGULATOR is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_VIDEO_XILINX is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Supported MMC/SDIO adapters +# +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +CONFIG_VIDEO_ADV7604=y +# CONFIG_VIDEO_ADV7842 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_CX25840 is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +CONFIG_VIDEO_ADV7511=y +# CONFIG_VIDEO_AD9389B is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_THS8200 is not set + +# +# Camera sensor devices +# +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_OV9650 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set +# CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_M5MOLS is not set +# CONFIG_VIDEO_S5K6AA is not set +# CONFIG_VIDEO_S5K4ECGX is not set +# CONFIG_VIDEO_SMIAPP is not set +# CONFIG_VIDEO_S5C73M3 is not set + +# +# Flash devices +# +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_AS3645A is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set + +# +# Miscelaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set + +# +# Sensors used on soc_camera driver +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_XILINX is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +CONFIG_FB_XYLON=y +# CONFIG_FB_XYLON_PLATFORM is not set +CONFIG_FB_XYLON_OF=y +CONFIG_FB_XYLON_PIXCLK=y +# CONFIG_FB_XYLON_PIXCLK_ZYNQ_PS is not set +# CONFIG_FB_XYLON_PIXCLK_LOGICLK is not set +CONFIG_FB_XYLON_PIXCLK_SI570=y +CONFIG_FB_XYLON_MISC=y +CONFIG_FB_XYLON_MISC_ADV7511=y +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_SOUND is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_HUION is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO_TPKBD is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +CONFIG_HID_MICROSOFT=y +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_XUSBPS_DR_OF=y +CONFIG_USB_EHCI_XUSBPS=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_RCAR_PHY is not set +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +# CONFIG_USB_ZYNQ_PHY is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +CONFIG_USB_GADGET_XUSBPS=y +CONFIG_XUSBPS_ERRATA_DT654401=y +CONFIG_USB_XUSBPS=y +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_AMD5536UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=m +CONFIG_USB_F_SS_LB=m +# CONFIG_USB_CONFIGFS is not set +CONFIG_USB_ZERO=m +# CONFIG_USB_ZERO_HNPTEST is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_UWB is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_ARMMMCI is not set +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=y +CONFIG_EDAC_ZYNQ=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +CONFIG_RTC_DRV_PCF8563=y +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_MOXART is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_XILINX_DMA_ENGINES=y +CONFIG_XILINX_AXIDMA=y +# CONFIG_XILINX_DMATEST is not set +CONFIG_XILINX_AXIVDMA=y +# CONFIG_XILINX_VDMATEST is not set +CONFIG_XILINX_AXICDMA=y +# CONFIG_XILINX_CDMATEST is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_DW_DMAC_CORE is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_TIMB_DMA is not set +CONFIG_PL330_DMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_NET_DMA is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_MF624 is not set +# CONFIG_UIO_XILINX_APM is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=m + +# +# Virtio drivers +# +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_ET131X is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_ECHO is not set +# CONFIG_COMEDI is not set +# CONFIG_R8187SE is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_R8188EU is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_DX_SEP is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_CRYSTALHD is not set +# CONFIG_FB_XGI is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +# CONFIG_LTE_GDM724X is not set +CONFIG_NET_VENDOR_SILICOM=y +# CONFIG_SBYPASS is not set +# CONFIG_BPCTL is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_XILLYBUS is not set +# CONFIG_DGNC is not set +# CONFIG_DGAP is not set +CONFIG_XILINX_VIDEO_IP=y +CONFIG_XILINX_VDMA_WRAPPER=y +CONFIG_XILINX_APF=y +CONFIG_XILINX_DMA_APF=y +# CONFIG_PMODS is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +CONFIG_COMMON_CLK_DEBUG=y +CONFIG_COMMON_CLK_VERSATILE=y +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_AXI_CLKGEN is not set + +# +# Hardware Spinlock drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CADENCE_TTC_TIMER=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y + +# +# Remoteproc drivers +# +CONFIG_REMOTEPROC=m +# CONFIG_STE_MODEM_RPROC is not set +CONFIG_ZYNQ_REMOTEPROC=m +CONFIG_MB_REMOTEPROC=m + +# +# Rpmsg drivers +# +CONFIG_RPMSG=m +# CONFIG_RPMSG_SERVER_SAMPLE is not set +# CONFIG_RPMSG_OMX is not set +# CONFIG_RPMSG_FREERTOS_STAT is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +CONFIG_MEMORY=y +CONFIG_ZYNQ_SMC=y +# CONFIG_IIO is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_FMC is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_KERNEL=y + +# +# Memory Debugging +# +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_CPU_STALL_VERBOSE is not set +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set + +# +# Runtime Testing +# +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ZYNQ_UART0 is not set +CONFIG_DEBUG_ZYNQ_UART1=y +# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set +# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set +# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +CONFIG_DEBUG_LL_INCLUDE="debug/zynq.S" +# CONFIG_DEBUG_UART_PL01X is not set +# CONFIG_DEBUG_UART_8250 is not set +CONFIG_DEBUG_UNCOMPRESS=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_EARLY_PRINTK=y +# CONFIG_OC_ETM is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=m +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_FONT_SUPPORT=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_VIRTUALIZATION=y Index: linux-3.12.24-rt38-xilinx/arch/arm/configs/xilinx_zynq_base_trd_defconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/configs/xilinx_zynq_base_trd_defconfig 2014-07-20 22:06:34.056343656 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.12.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="-xilinx-trd" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +# CONFIG_AUDIT is not set + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_GENERIC_SCHED_CLOCK=y +# CONFIG_CGROUPS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_PCI_QUIRKS=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +# CONFIG_FREEZER is not set + +# +# System Type +# +CONFIG_MMU=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set + +# +# Multiple platform selection +# + +# +# CPU Core family selection +# +# CONFIG_ARCH_MULTI_V6 is not set +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_MULTI_V6_V7=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_BCM is not set +CONFIG_GPIO_PCA953X=y +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U8500 is not set +CONFIG_ARCH_VEXPRESS=y + +# +# Versatile Express platform type +# +CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y +# CONFIG_ARCH_VEXPRESS_CA9X4 is not set +CONFIG_PLAT_VERSATILE_CLCD=y +CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_WM8850 is not set +CONFIG_ARCH_ZYNQ=y + +# +# Xilinx Specific Options +# +CONFIG_XILINX_L1_PREFETCH=y +CONFIG_XILINX_L2_PREFETCH=y +CONFIG_XILINX_AXIPCIE=y +CONFIG_PLAT_VERSATILE=y +CONFIG_ARM_TIMER_SP804=y + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +CONFIG_PL310_ERRATA_588369=y +# CONFIG_ARM_ERRATA_643719 is not set +CONFIG_ARM_ERRATA_720789=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_ERRATA_775420=y +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_773022 is not set +CONFIG_ICST=y + +# +# Bus support +# +CONFIG_ARM_AMBA=y +CONFIG_PCI=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set + +# +# PCI host controller drivers +# +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HAVE_ARM_SCU=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_ARM_TWD=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_ARCH_NR_GPIO=1024 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ_FIXED=0 +CONFIG_HZ_100=y +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +# CONFIG_ZBUD is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_XEN is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_ARM_ZYNQ_CPUFREQ=y + +# +# CPU Idle +# +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +# CONFIG_KERNEL_MODE_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +# CONFIG_SUSPEND is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=m +# CONFIG_IP_MROUTE is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NET_MPLS_GSO is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_CMA is not set + +# +# Bus devices +# +# CONFIG_ARM_CCI is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +CONFIG_MTD_M25P80=y +# CONFIG_M25PXX_USE_FAST_READ is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_ZYNQ=y +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_MTD=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_VIRTIO_BLK is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_ARM_CHARLCD is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +CONFIG_SI570=y +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_HAVE_PATA_PLATFORM=y +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_VIRTIO_NET is not set +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMD is not set +CONFIG_NET_VENDOR_ARC=y +# CONFIG_ARC_EMAC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_MACB is not set +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +CONFIG_TIGON3=y +# CONFIG_BNX2X is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EXAR is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +CONFIG_E1000E=y +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +CONFIG_NET_VENDOR_I825XX=y +# CONFIG_IP1000 is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +CONFIG_R8169=y +# CONFIG_SH_ETH is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_SFC is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +CONFIG_XILINX_EMACLITE=y +CONFIG_XILINX_AXI_EMAC=y +CONFIG_XILINX_PS_EMAC=y +# CONFIG_XILINX_PS_EMAC_HWTSTAMP is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +CONFIG_MARVELL_PHY=y +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +CONFIG_VITESSE_PHY=y +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y +# CONFIG_MDIO_GPIO is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_HOSTAP is not set +# CONFIG_WL_TI is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_OLPC_APSP is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_PCH_UART is not set +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +CONFIG_XILINX_DEVCFG=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_VERSATILE is not set +CONFIG_I2C_ZYNQ=y +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_ZYNQ_QSPI=y +# CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED is not set +CONFIG_SPI_ZYNQ=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_HSI is not set + +# +# PPS support +# +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +CONFIG_GPIO_XILINX=y +CONFIG_GPIO_ZYNQ=y +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X_IRQ is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# LPC GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_SMB347 is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_RESTART is not set +CONFIG_POWER_RESET_VEXPRESS=y +# CONFIG_POWER_AVS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_SENSORS_XADCPS=y +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +CONFIG_ZYNQ_WATCHDOG=y +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_MEN_A21_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_VEXPRESS_CONFIG=y +# CONFIG_REGULATOR is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_VIDEO_XILINX is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Supported MMC/SDIO adapters +# +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +CONFIG_VIDEO_ADV7604=y +# CONFIG_VIDEO_ADV7842 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_CX25840 is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +CONFIG_VIDEO_ADV7511=y +# CONFIG_VIDEO_AD9389B is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_THS8200 is not set + +# +# Camera sensor devices +# +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_OV9650 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set +# CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_M5MOLS is not set +# CONFIG_VIDEO_S5K6AA is not set +# CONFIG_VIDEO_S5K4ECGX is not set +# CONFIG_VIDEO_SMIAPP is not set +# CONFIG_VIDEO_S5C73M3 is not set + +# +# Flash devices +# +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_AS3645A is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set + +# +# Miscelaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set + +# +# Sensors used on soc_camera driver +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_XILINX is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +CONFIG_FB_XYLON=y +# CONFIG_FB_XYLON_PLATFORM is not set +CONFIG_FB_XYLON_OF=y +CONFIG_FB_XYLON_PIXCLK=y +# CONFIG_FB_XYLON_PIXCLK_ZYNQ_PS is not set +# CONFIG_FB_XYLON_PIXCLK_LOGICLK is not set +CONFIG_FB_XYLON_PIXCLK_SI570=y +CONFIG_FB_XYLON_MISC=y +CONFIG_FB_XYLON_MISC_ADV7511=y +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_SOUND is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_HUION is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO_TPKBD is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +CONFIG_HID_MICROSOFT=y +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_XUSBPS_DR_OF=y +CONFIG_USB_EHCI_XUSBPS=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_RCAR_PHY is not set +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +# CONFIG_USB_ZYNQ_PHY is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +CONFIG_USB_GADGET_XUSBPS=y +CONFIG_XUSBPS_ERRATA_DT654401=y +CONFIG_USB_XUSBPS=y +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_AMD5536UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=m +CONFIG_USB_F_SS_LB=m +# CONFIG_USB_CONFIGFS is not set +CONFIG_USB_ZERO=m +# CONFIG_USB_ZERO_HNPTEST is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_UWB is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_ARMMMCI is not set +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=y +CONFIG_EDAC_ZYNQ=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +CONFIG_RTC_DRV_PCF8563=y +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_MOXART is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_XILINX_DMA_ENGINES=y +CONFIG_XILINX_AXIDMA=y +# CONFIG_XILINX_DMATEST is not set +CONFIG_XILINX_AXIVDMA=y +# CONFIG_XILINX_VDMATEST is not set +CONFIG_XILINX_AXICDMA=y +# CONFIG_XILINX_CDMATEST is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_DW_DMAC_CORE is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_TIMB_DMA is not set +CONFIG_PL330_DMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_NET_DMA is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_MF624 is not set +# CONFIG_UIO_XILINX_APM is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=m + +# +# Virtio drivers +# +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_ET131X is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_ECHO is not set +# CONFIG_COMEDI is not set +# CONFIG_R8187SE is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_R8188EU is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_DX_SEP is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_CRYSTALHD is not set +# CONFIG_FB_XGI is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +# CONFIG_LTE_GDM724X is not set +CONFIG_NET_VENDOR_SILICOM=y +# CONFIG_SBYPASS is not set +# CONFIG_BPCTL is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_XILLYBUS is not set +# CONFIG_DGNC is not set +# CONFIG_DGAP is not set +CONFIG_XILINX_VIDEO_IP=y +CONFIG_XILINX_VDMA_WRAPPER=y +# CONFIG_XILINX_APF is not set +# CONFIG_PMODS is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +CONFIG_COMMON_CLK_DEBUG=y +CONFIG_COMMON_CLK_VERSATILE=y +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_AXI_CLKGEN is not set + +# +# Hardware Spinlock drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CADENCE_TTC_TIMER=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y + +# +# Remoteproc drivers +# +CONFIG_REMOTEPROC=m +# CONFIG_STE_MODEM_RPROC is not set +CONFIG_ZYNQ_REMOTEPROC=m +CONFIG_MB_REMOTEPROC=m + +# +# Rpmsg drivers +# +CONFIG_RPMSG=m +# CONFIG_RPMSG_SERVER_SAMPLE is not set +# CONFIG_RPMSG_OMX is not set +# CONFIG_RPMSG_FREERTOS_STAT is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +CONFIG_MEMORY=y +CONFIG_ZYNQ_SMC=y +# CONFIG_IIO is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_FMC is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_KERNEL=y + +# +# Memory Debugging +# +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_CPU_STALL_VERBOSE is not set +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set + +# +# Runtime Testing +# +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ZYNQ_UART0 is not set +CONFIG_DEBUG_ZYNQ_UART1=y +# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set +# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set +# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +CONFIG_DEBUG_LL_INCLUDE="debug/zynq.S" +# CONFIG_DEBUG_UART_PL01X is not set +# CONFIG_DEBUG_UART_8250 is not set +CONFIG_DEBUG_UNCOMPRESS=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_EARLY_PRINTK=y +# CONFIG_OC_ETM is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=m +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_FONT_SUPPORT=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_VIRTUALIZATION=y Index: linux-3.12.24-rt38-xilinx/arch/arm/configs/xilinx_zynq_defconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/configs/xilinx_zynq_defconfig 2014-07-20 22:06:34.086343161 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.12.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="-xilinx" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +# CONFIG_AUDIT is not set + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_GENERIC_SCHED_CLOCK=y +# CONFIG_CGROUPS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_PCI_QUIRKS=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set + +# +# Multiple platform selection +# + +# +# CPU Core family selection +# +# CONFIG_ARCH_MULTI_V6 is not set +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_MULTI_V6_V7=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U8500 is not set +CONFIG_ARCH_VEXPRESS=y + +# +# Versatile Express platform type +# +CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y +# CONFIG_ARCH_VEXPRESS_CA9X4 is not set +CONFIG_PLAT_VERSATILE_CLCD=y +CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_WM8850 is not set +CONFIG_ARCH_ZYNQ=y + +# +# Xilinx Specific Options +# +CONFIG_XILINX_L1_PREFETCH=y +CONFIG_XILINX_L2_PREFETCH=y +CONFIG_XILINX_AXIPCIE=y +CONFIG_PLAT_VERSATILE=y +CONFIG_ARM_TIMER_SP804=y + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +CONFIG_PL310_ERRATA_588369=y +# CONFIG_ARM_ERRATA_643719 is not set +CONFIG_ARM_ERRATA_720789=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_ERRATA_775420=y +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_773022 is not set +CONFIG_ICST=y + +# +# Bus support +# +CONFIG_ARM_AMBA=y +CONFIG_PCI=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set + +# +# PCI host controller drivers +# +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HAVE_ARM_SCU=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_ARM_TWD=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_ARCH_NR_GPIO=1024 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ_FIXED=0 +CONFIG_HZ_100=y +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +# CONFIG_ZBUD is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_XEN is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_ARM_ZYNQ_CPUFREQ=y + +# +# CPU Idle +# +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +# CONFIG_KERNEL_MODE_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_CPU_PM=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=m +# CONFIG_IP_MROUTE is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NET_MPLS_GSO is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_CMA is not set + +# +# Bus devices +# +# CONFIG_ARM_CCI is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +CONFIG_MTD_M25P80=y +# CONFIG_M25PXX_USE_FAST_READ is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_ZYNQ=y +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_MTD=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_VIRTIO_BLK is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_ARM_CHARLCD is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_SI570 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_SRAM=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_HAVE_PATA_PLATFORM=y +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_VIRTIO_NET is not set +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMD is not set +CONFIG_NET_VENDOR_ARC=y +# CONFIG_ARC_EMAC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +CONFIG_MACB=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +CONFIG_TIGON3=y +# CONFIG_BNX2X is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EXAR is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +CONFIG_E1000E=y +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +CONFIG_NET_VENDOR_I825XX=y +# CONFIG_IP1000 is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +CONFIG_R8169=y +# CONFIG_SH_ETH is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_SFC is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +CONFIG_XILINX_EMACLITE=y +CONFIG_XILINX_AXI_EMAC=y +CONFIG_XILINX_PS_EMAC=y +# CONFIG_XILINX_PS_EMAC_HWTSTAMP is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +CONFIG_MARVELL_PHY=y +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +CONFIG_VITESSE_PHY=y +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y +# CONFIG_MDIO_GPIO is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_HOSTAP is not set +# CONFIG_WL_TI is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_OLPC_APSP is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_PCH_UART is not set +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +CONFIG_XILINX_DEVCFG=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_VERSATILE is not set +CONFIG_I2C_ZYNQ=y +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +CONFIG_SPI_XILINX=y +CONFIG_SPI_ZYNQ_QSPI=y +# CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED is not set +CONFIG_SPI_ZYNQ=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_HSI is not set + +# +# PPS support +# +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +CONFIG_GPIO_XILINX=y +CONFIG_GPIO_ZYNQ=y +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# LPC GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_SMB347 is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_RESTART is not set +CONFIG_POWER_RESET_VEXPRESS=y +# CONFIG_POWER_AVS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_SENSORS_XADCPS=y +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +CONFIG_ZYNQ_WATCHDOG=y +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +CONFIG_XILINX_WATCHDOG=y +# CONFIG_MEN_A21_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_VEXPRESS_CONFIG=y +# CONFIG_REGULATOR is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set + +# +# Supported MMC/SDIO adapters +# +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_XILINX is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +CONFIG_FB_XYLON=y +# CONFIG_FB_XYLON_PLATFORM is not set +CONFIG_FB_XYLON_OF=y +# CONFIG_FB_XYLON_PIXCLK is not set +# CONFIG_FB_XYLON_MISC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_SOUND is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_HUION is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO_TPKBD is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +CONFIG_HID_MICROSOFT=y +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_XUSBPS_DR_OF=y +CONFIG_USB_EHCI_XUSBPS=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_RCAR_PHY is not set +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +# CONFIG_USB_ZYNQ_PHY is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +CONFIG_USB_GADGET_XUSBPS=y +CONFIG_XUSBPS_ERRATA_DT654401=y +CONFIG_USB_XUSBPS=y +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_R8A66597 is not set +CONFIG_USB_GADGET_XILINX=y +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_AMD5536UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=m +CONFIG_USB_F_SS_LB=m +# CONFIG_USB_CONFIGFS is not set +CONFIG_USB_ZERO=m +# CONFIG_USB_ZERO_HNPTEST is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_UWB is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_ARMMMCI is not set +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=y +CONFIG_EDAC_ZYNQ=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +CONFIG_RTC_DRV_PCF8563=y +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_MOXART is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_XILINX_DMA_ENGINES=y +CONFIG_XILINX_AXIDMA=y +# CONFIG_XILINX_DMATEST is not set +CONFIG_XILINX_AXIVDMA=y +# CONFIG_XILINX_VDMATEST is not set +CONFIG_XILINX_AXICDMA=y +# CONFIG_XILINX_CDMATEST is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_DW_DMAC_CORE is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_TIMB_DMA is not set +CONFIG_PL330_DMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_NET_DMA is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_MF624 is not set +CONFIG_UIO_XILINX_APM=y +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=m + +# +# Virtio drivers +# +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +CONFIG_COMMON_CLK_DEBUG=y +CONFIG_COMMON_CLK_VERSATILE=y +# CONFIG_COMMON_CLK_SI5351 is not set +CONFIG_COMMON_CLK_SI570=y +# CONFIG_COMMON_CLK_AXI_CLKGEN is not set + +# +# Hardware Spinlock drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CADENCE_TTC_TIMER=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y + +# +# Remoteproc drivers +# +CONFIG_REMOTEPROC=m +# CONFIG_STE_MODEM_RPROC is not set +CONFIG_ZYNQ_REMOTEPROC=m +CONFIG_MB_REMOTEPROC=m + +# +# Rpmsg drivers +# +CONFIG_RPMSG=m +# CONFIG_RPMSG_SERVER_SAMPLE is not set +# CONFIG_RPMSG_OMX is not set +# CONFIG_RPMSG_FREERTOS_STAT is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +CONFIG_MEMORY=y +CONFIG_ZYNQ_SMC=y +# CONFIG_IIO is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_FMC is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_KERNEL=y + +# +# Memory Debugging +# +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_CPU_STALL_VERBOSE is not set +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set + +# +# Runtime Testing +# +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ZYNQ_UART0 is not set +CONFIG_DEBUG_ZYNQ_UART1=y +# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set +# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set +# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +CONFIG_DEBUG_LL_INCLUDE="debug/zynq.S" +# CONFIG_DEBUG_UART_PL01X is not set +# CONFIG_DEBUG_UART_8250 is not set +CONFIG_DEBUG_UNCOMPRESS=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_EARLY_PRINTK=y +# CONFIG_OC_ETM is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=m +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_FONT_SUPPORT=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_VIRTUALIZATION=y Index: linux-3.12.24-rt38-xilinx/arch/arm/configs/xilinx_zynq_drm_defconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/configs/xilinx_zynq_drm_defconfig 2014-07-20 22:06:34.116342666 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.12.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="-xilinx-drm" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +# CONFIG_AUDIT is not set + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_GENERIC_SCHED_CLOCK=y +# CONFIG_CGROUPS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_PCI_QUIRKS=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set + +# +# Multiple platform selection +# + +# +# CPU Core family selection +# +# CONFIG_ARCH_MULTI_V6 is not set +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_MULTI_V6_V7=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U8500 is not set +CONFIG_ARCH_VEXPRESS=y + +# +# Versatile Express platform type +# +CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y +# CONFIG_ARCH_VEXPRESS_CA9X4 is not set +CONFIG_PLAT_VERSATILE_CLCD=y +CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_WM8850 is not set +CONFIG_ARCH_ZYNQ=y + +# +# Xilinx Specific Options +# +CONFIG_XILINX_L1_PREFETCH=y +CONFIG_XILINX_L2_PREFETCH=y +CONFIG_XILINX_AXIPCIE=y +CONFIG_PLAT_VERSATILE=y +CONFIG_ARM_TIMER_SP804=y + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +CONFIG_PL310_ERRATA_588369=y +# CONFIG_ARM_ERRATA_643719 is not set +CONFIG_ARM_ERRATA_720789=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_ERRATA_775420=y +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_773022 is not set +CONFIG_ICST=y + +# +# Bus support +# +CONFIG_ARM_AMBA=y +CONFIG_PCI=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set + +# +# PCI host controller drivers +# +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HAVE_ARM_SCU=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_ARM_TWD=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_ARCH_NR_GPIO=1024 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ_FIXED=0 +CONFIG_HZ_100=y +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +# CONFIG_ZBUD is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_XEN is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_ARM_ZYNQ_CPUFREQ=y + +# +# CPU Idle +# +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +# CONFIG_KERNEL_MODE_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_CPU_PM=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=m +# CONFIG_IP_MROUTE is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NET_MPLS_GSO is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_CMA=y + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=128 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 + +# +# Bus devices +# +# CONFIG_ARM_CCI is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +CONFIG_MTD_M25P80=y +# CONFIG_M25PXX_USE_FAST_READ is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_ZYNQ=y +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_MTD=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_VIRTIO_BLK is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_ARM_CHARLCD is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_SI570 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_SRAM=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_HAVE_PATA_PLATFORM=y +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_VIRTIO_NET is not set +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMD is not set +CONFIG_NET_VENDOR_ARC=y +# CONFIG_ARC_EMAC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +CONFIG_MACB=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +CONFIG_TIGON3=y +# CONFIG_BNX2X is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EXAR is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +CONFIG_E1000E=y +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +CONFIG_NET_VENDOR_I825XX=y +# CONFIG_IP1000 is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +CONFIG_R8169=y +# CONFIG_SH_ETH is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_SFC is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +CONFIG_XILINX_EMACLITE=y +CONFIG_XILINX_AXI_EMAC=y +CONFIG_XILINX_PS_EMAC=y +# CONFIG_XILINX_PS_EMAC_HWTSTAMP is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +CONFIG_MARVELL_PHY=y +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +CONFIG_VITESSE_PHY=y +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y +# CONFIG_MDIO_GPIO is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_HOSTAP is not set +# CONFIG_WL_TI is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_OLPC_APSP is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_PCH_UART is not set +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +CONFIG_XILINX_DEVCFG=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_VERSATILE is not set +CONFIG_I2C_ZYNQ=y +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +CONFIG_SPI_XILINX=y +CONFIG_SPI_ZYNQ_QSPI=y +# CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED is not set +CONFIG_SPI_ZYNQ=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_HSI is not set + +# +# PPS support +# +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +CONFIG_GPIO_XILINX=y +CONFIG_GPIO_ZYNQ=y +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# LPC GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_SMB347 is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_RESTART is not set +CONFIG_POWER_RESET_VEXPRESS=y +# CONFIG_POWER_AVS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_SENSORS_XADCPS=y +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +CONFIG_ZYNQ_WATCHDOG=y +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +CONFIG_XILINX_WATCHDOG=y +# CONFIG_MEN_A21_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_VEXPRESS_CONFIG=y +# CONFIG_REGULATOR is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +CONFIG_VIDEO_XILINX=y +CONFIG_VIDEO_XILINX_REMAPPER=y +CONFIG_VIDEO_XILINX_TPG=y +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Supported MMC/SDIO adapters +# +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_DRM=y +CONFIG_DRM_KMS_HELPER=y +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +CONFIG_DRM_GEM_CMA_HELPER=y +CONFIG_DRM_KMS_CMA_HELPER=y + +# +# I2C encoder or helper chips +# +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +CONFIG_DRM_ENCODER_ADV7511=y +# CONFIG_DRM_TDFX is not set +# CONFIG_DRM_R128 is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_VIA is not set +# CONFIG_DRM_SAVAGE is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_RCAR_DU is not set +# CONFIG_DRM_SHMOBILE is not set +# CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_QXL is not set +CONFIG_DRM_XILINX=y +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_HDMI=y +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_XILINX is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +CONFIG_FB_XYLON=y +# CONFIG_FB_XYLON_PLATFORM is not set +CONFIG_FB_XYLON_OF=y +# CONFIG_FB_XYLON_PIXCLK is not set +# CONFIG_FB_XYLON_MISC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_PCI=y +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_OXYGEN is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_YMFPCI is not set +CONFIG_SND_ARM=y +# CONFIG_SND_ARMAACI is not set +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_HIFACE is not set +CONFIG_SND_SOC=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_HUION is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO_TPKBD is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +CONFIG_HID_MICROSOFT=y +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_XUSBPS_DR_OF=y +CONFIG_USB_EHCI_XUSBPS=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_RCAR_PHY is not set +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +# CONFIG_USB_ZYNQ_PHY is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +CONFIG_USB_GADGET_XUSBPS=y +CONFIG_XUSBPS_ERRATA_DT654401=y +CONFIG_USB_XUSBPS=y +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_R8A66597 is not set +CONFIG_USB_GADGET_XILINX=y +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_AMD5536UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=m +CONFIG_USB_F_SS_LB=m +# CONFIG_USB_CONFIGFS is not set +CONFIG_USB_ZERO=m +# CONFIG_USB_ZERO_HNPTEST is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_UWB is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_ARMMMCI is not set +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=y +CONFIG_EDAC_ZYNQ=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +CONFIG_RTC_DRV_PCF8563=y +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_MOXART is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_XILINX_DMA_ENGINES=y +CONFIG_XILINX_AXIDMA=y +# CONFIG_XILINX_DMATEST is not set +CONFIG_XILINX_AXIVDMA=y +# CONFIG_XILINX_VDMATEST is not set +CONFIG_XILINX_AXICDMA=y +# CONFIG_XILINX_CDMATEST is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_DW_DMAC_CORE is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_TIMB_DMA is not set +CONFIG_PL330_DMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_NET_DMA is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_MF624 is not set +CONFIG_UIO_XILINX_APM=y +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=m + +# +# Virtio drivers +# +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +CONFIG_COMMON_CLK_DEBUG=y +CONFIG_COMMON_CLK_VERSATILE=y +# CONFIG_COMMON_CLK_SI5351 is not set +CONFIG_COMMON_CLK_SI570=y +# CONFIG_COMMON_CLK_AXI_CLKGEN is not set + +# +# Hardware Spinlock drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CADENCE_TTC_TIMER=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y + +# +# Remoteproc drivers +# +CONFIG_REMOTEPROC=m +# CONFIG_STE_MODEM_RPROC is not set +CONFIG_ZYNQ_REMOTEPROC=m +CONFIG_MB_REMOTEPROC=m + +# +# Rpmsg drivers +# +CONFIG_RPMSG=m +# CONFIG_RPMSG_SERVER_SAMPLE is not set +# CONFIG_RPMSG_OMX is not set +# CONFIG_RPMSG_FREERTOS_STAT is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +CONFIG_MEMORY=y +CONFIG_ZYNQ_SMC=y +# CONFIG_IIO is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_FMC is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_KERNEL=y + +# +# Memory Debugging +# +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_CPU_STALL_VERBOSE is not set +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set + +# +# Runtime Testing +# +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ZYNQ_UART0 is not set +CONFIG_DEBUG_ZYNQ_UART1=y +# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set +# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set +# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +CONFIG_DEBUG_LL_INCLUDE="debug/zynq.S" +# CONFIG_DEBUG_UART_PL01X is not set +# CONFIG_DEBUG_UART_8250 is not set +CONFIG_DEBUG_UNCOMPRESS=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_EARLY_PRINTK=y +# CONFIG_OC_ETM is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=m +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_FONT_SUPPORT=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_VIRTUALIZATION=y Index: linux-3.12.24-rt38-xilinx/arch/arm/include/asm/elf.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/include/asm/elf.h 2014-07-20 22:05:50.291065713 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/include/asm/elf.h 2014-07-20 22:06:34.131342419 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:53 @ #define R_ARM_ABS32 2 #define R_ARM_CALL 28 #define R_ARM_JUMP24 29 +#define R_ARM_TARGET1 38 #define R_ARM_V4BX 40 #define R_ARM_PREL31 42 #define R_ARM_MOVW_ABS_NC 43 Index: linux-3.12.24-rt38-xilinx/arch/arm/include/asm/hardirq.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/include/asm/hardirq.h 2014-07-20 22:05:50.292065697 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/include/asm/hardirq.h 2014-07-20 22:06:34.141342254 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:8 @ #include <linux/threads.h> #include <asm/irq.h> -#define NR_IPI 6 +#define NR_IPI 16 typedef struct { unsigned int __softirq_pending; Index: linux-3.12.24-rt38-xilinx/arch/arm/include/asm/setup.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/include/asm/setup.h 2014-07-20 22:05:50.290065730 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/include/asm/setup.h 2014-07-20 22:06:34.155342023 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:52 @ #define bank_phys_end(bank) ((bank)->start + (bank)->size) #define bank_phys_size(bank) (bank)->size -extern int arm_add_memory(phys_addr_t start, phys_addr_t size); +extern int arm_add_memory(u64 start, u64 size); extern void early_print(const char *str, ...); extern void dump_machine_table(void); Index: linux-3.12.24-rt38-xilinx/arch/arm/include/asm/smp.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/include/asm/smp.h 2014-07-20 22:05:50.293065680 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/include/asm/smp.h 2014-07-20 22:06:34.167341825 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:120 @ */ extern void smp_set_ops(struct smp_operations *); +extern int set_ipi_handler(int ipinr, void *handler, char *desc); +extern void clear_ipi_handler(int ipinr); + #endif /* ifndef __ASM_ARM_SMP_H */ Index: linux-3.12.24-rt38-xilinx/arch/arm/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/Kconfig 2014-07-20 22:05:50.276065961 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/Kconfig 2014-07-20 22:06:34.186341512 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:7 @ select ARCH_BINFMT_ELF_RANDOMIZE_PIE select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST - select ARCH_HAVE_CUSTOM_GPIO_H + select ARCH_HAVE_CUSTOM_GPIO_H if (!ARCH_ZYNQ) select ARCH_WANT_IPC_PARSE_VERSION select BUILDTIME_EXTABLE_SORT if MMU select CLONE_BACKWARDS @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1604 @ # selected platforms. config ARCH_NR_GPIO int - default 1024 if ARCH_SHMOBILE || ARCH_TEGRA + default 1024 if ARCH_SHMOBILE || ARCH_TEGRA || ARCH_ZYNQ default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || SOC_DRA7XX default 392 if ARCH_U8500 default 352 if ARCH_VT8500 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2100 @ config KEXEC bool "Kexec system call (EXPERIMENTAL)" - depends on (!SMP || PM_SLEEP_SMP) + depends on PM_SLEEP_SMP help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot Index: linux-3.12.24-rt38-xilinx/arch/arm/kernel/machine_kexec.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/kernel/machine_kexec.c 2014-07-20 22:05:50.281065878 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/kernel/machine_kexec.c 2014-07-20 22:06:34.201341264 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:5 @ * machine_kexec.c - handle transition of Linux booting another kernel */ +#include <linux/cpu.h> #include <linux/mm.h> #include <linux/kexec.h> #include <linux/delay.h> @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:120 @ unsigned long msecs; local_irq_disable(); + disable_nonboot_cpus(); atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); smp_call_function(machine_crash_nonpanic_core, NULL, false); Index: linux-3.12.24-rt38-xilinx/arch/arm/kernel/module.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/kernel/module.c 2014-07-20 22:05:50.280065895 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/kernel/module.c 2014-07-20 22:06:34.212341083 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:92 @ break; case R_ARM_ABS32: + case R_ARM_TARGET1: *(u32 *)loc += sym->st_value; break; Index: linux-3.12.24-rt38-xilinx/arch/arm/kernel/process.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/kernel/process.c 2014-07-20 22:05:50.278065928 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/kernel/process.c 2014-07-20 22:06:34.223340901 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:191 @ void machine_shutdown(void) { disable_nonboot_cpus(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif } /* Index: linux-3.12.24-rt38-xilinx/arch/arm/kernel/setup.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/kernel/setup.c 2014-07-20 22:05:50.279065912 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/kernel/setup.c 2014-07-20 22:06:34.237340670 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:622 @ /* can't use cpu_relax() here as it may require MMU setup */; } -int __init arm_add_memory(phys_addr_t start, phys_addr_t size) +int __init arm_add_memory(u64 start, u64 size) { struct membank *bank = &meminfo.bank[meminfo.nr_banks]; u64 aligned_start; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:694 @ static int __init early_mem(char *p) { static int usermem __initdata = 0; - phys_addr_t size; - phys_addr_t start; + u64 size; + u64 start; char *endp; /* Index: linux-3.12.24-rt38-xilinx/arch/arm/kernel/smp.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/kernel/smp.c 2014-07-20 22:05:50.282065862 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/kernel/smp.c 2014-07-20 22:06:34.250340456 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:451 @ smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); } -static const char *ipi_types[NR_IPI] = { -#define S(x,s) [x] = s - S(IPI_WAKEUP, "CPU wakeup interrupts"), - S(IPI_TIMER, "Timer broadcast interrupts"), - S(IPI_RESCHEDULE, "Rescheduling interrupts"), - S(IPI_CALL_FUNC, "Function call interrupts"), - S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), - S(IPI_CPU_STOP, "CPU stop interrupts"), +struct ipi { + const char *desc; + void (*handler)(void); +}; + +static void ipi_cpu_stop(void); + +static struct ipi ipi_types[NR_IPI] = { +#define S(x, s, f) [x].desc = s, [x].handler = f + S(IPI_WAKEUP, "CPU wakeup interrupts", NULL), +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST + S(IPI_TIMER, "Timer broadcast interrupts", tick_receive_broadcast), +#endif + S(IPI_RESCHEDULE, "Rescheduling interrupts", scheduler_ipi), + S(IPI_CALL_FUNC, "Function call interrupts", + generic_smp_call_function_interrupt), + S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts", + generic_smp_call_function_single_interrupt), + S(IPI_CPU_STOP, "CPU stop interrupts", ipi_cpu_stop), }; void show_ipi_list(struct seq_file *p, int prec) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:477 @ unsigned int cpu, i; for (i = 0; i < NR_IPI; i++) { - seq_printf(p, "%*s%u: ", prec - 1, "IPI", i); - - for_each_online_cpu(cpu) - seq_printf(p, "%10u ", - __get_irq_stat(cpu, ipi_irqs[i])); - - seq_printf(p, " %s\n", ipi_types[i]); + if (ipi_types[i].handler) { + seq_printf(p, "%*s%u: ", prec - 1, "IPI", i); + for_each_present_cpu(cpu) + seq_printf(p, "%10u ", + __get_irq_stat(cpu, ipi_irqs[i])); + seq_printf(p, " %s\n", ipi_types[i].desc); + } } } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:510 @ /* * ipi_cpu_stop - handle IPI from smp_send_stop() */ -static void ipi_cpu_stop(unsigned int cpu) +static void ipi_cpu_stop(void) { + unsigned int cpu = smp_processor_id(); + if (system_state == SYSTEM_BOOTING || system_state == SYSTEM_RUNNING) { raw_spin_lock(&stop_lock); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:544 @ unsigned int cpu = smp_processor_id(); struct pt_regs *old_regs = set_irq_regs(regs); - if (ipinr < NR_IPI) + if (ipi_types[ipinr].handler) { __inc_irq_stat(cpu, ipi_irqs[ipinr]); - - switch (ipinr) { - case IPI_WAKEUP: - break; - -#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST - case IPI_TIMER: irq_enter(); - tick_receive_broadcast(); + (*ipi_types[ipinr].handler)(); irq_exit(); - break; -#endif + } else + pr_debug("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); - case IPI_RESCHEDULE: - scheduler_ipi(); - break; + set_irq_regs(old_regs); +} - case IPI_CALL_FUNC: - irq_enter(); - generic_smp_call_function_interrupt(); - irq_exit(); - break; +/* + * set_ipi_handler: + * Interface provided for a kernel module to specify an IPI handler function. + */ +int set_ipi_handler(int ipinr, void *handler, char *desc) +{ + unsigned int cpu = smp_processor_id(); - case IPI_CALL_FUNC_SINGLE: - irq_enter(); - generic_smp_call_function_single_interrupt(); - irq_exit(); - break; + if (ipi_types[ipinr].handler) { + pr_crit("CPU%u: IPI handler 0x%x already registered to %pf\n", + cpu, ipinr, ipi_types[ipinr].handler); + return -1; + } - case IPI_CPU_STOP: - irq_enter(); - ipi_cpu_stop(cpu); - irq_exit(); - break; + ipi_types[ipinr].handler = handler; + ipi_types[ipinr].desc = desc; - default: - printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", - cpu, ipinr); - break; - } - set_irq_regs(old_regs); + return 0; +} +EXPORT_SYMBOL(set_ipi_handler); + +/* + * clear_ipi_handler: + * Interface provided for a kernel module to clear an IPI handler function. + */ +void clear_ipi_handler(int ipinr) +{ + ipi_types[ipinr].handler = NULL; + ipi_types[ipinr].desc = NULL; } +EXPORT_SYMBOL(clear_ipi_handler); void smp_send_reschedule(int cpu) { Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/common.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mach-zynq/common.c 2014-07-20 22:05:50.272066027 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/common.c 2014-07-20 22:06:34.265340209 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:19 @ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/cpu.h> #include <linux/cpumask.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/clk/zynq.h> +#include <linux/opp.h> #include <linux/clocksource.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of.h> +#include <linux/memblock.h> +#include <linux/irqchip.h> +#include <linux/irqchip/arm-gic.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:47 @ void __iomem *zynq_scu_base; -static struct of_device_id zynq_of_bus_ids[] __initdata = { - { .compatible = "simple-bus", }, - {} +/** + * zynq_memory_init() - Initialize special memory + * + * We need to stop things allocating the low memory as DMA can't work in + * the 1st 512K of memory. Using reserve vs remove is not totally clear yet. + */ +static void __init zynq_memory_init(void) +{ + /* + * Reserve the 0-0x4000 addresses (before page tables and kernel) + * which can't be used for DMA + */ + if (!__pa(PAGE_OFFSET)) + memblock_reserve(0, 0x4000); +} + +#ifdef CONFIG_CPU_FREQ +#define CPUFREQ_MIN_FREQ_HZ 200000000 +static unsigned int freq_divs[] __initdata = { + 2, 3 }; +static long __init xilinx_calc_opp_freq(struct clk *clk, long rate) +{ + long rate_nearest = clk_round_rate_nearest(clk, rate); + long rate_round = clk_round_rate(clk, rate_nearest / 1000 * 1000); + + if (rate_round != rate_nearest) + rate_nearest += 1000; + + return rate_nearest; +} + /** - * zynq_init_machine - System specific initialization, intended to be - * called from board specific initialization. + * zynq_opp_init() - Register OPPs + * + * Registering frequency/voltage operating points for voltage and frequency + * scaling. Currently we only support frequency scaling. */ -static void __init zynq_init_machine(void) +static int __init zynq_opp_init(void) +{ + long freq; + unsigned int i; + struct device *dev = get_cpu_device(0); + int ret = 0; + struct clk *cpuclk = clk_get(NULL, "cpufreq_clk"); + + if (!dev) { + pr_warn("%s: no cpu device. DVFS not available.", __func__); + return -ENODEV; + } + + if (IS_ERR(cpuclk)) { + pr_warn("%s: CPU clock not found. DVFS not available.", + __func__); + return PTR_ERR(cpuclk); + } + + /* frequency/voltage operating points. For now use f only */ + freq = clk_get_rate(cpuclk); + ret |= opp_add(dev, xilinx_calc_opp_freq(cpuclk, freq), 0); + for (i = 0; i < ARRAY_SIZE(freq_divs); i++) { + long tmp = xilinx_calc_opp_freq(cpuclk, freq / freq_divs[i]); + if (tmp >= CPUFREQ_MIN_FREQ_HZ) + ret |= opp_add(dev, tmp, 0); + } + freq = xilinx_calc_opp_freq(cpuclk, CPUFREQ_MIN_FREQ_HZ); + if (freq >= CPUFREQ_MIN_FREQ_HZ && IS_ERR(opp_find_freq_exact(dev, freq, + 1))) + ret |= opp_add(dev, freq, 0); + + if (ret) + pr_warn("%s: Error adding OPPs.", __func__); + + return ret; +} +device_initcall(zynq_opp_init); +#endif + +#ifdef CONFIG_CACHE_L2X0 +static int __init zynq_l2c_init(void) +{ + /* 64KB way size, 8-way associativity, parity disabled, + * prefetching option */ +#ifndef CONFIG_XILINX_L2_PREFETCH + return l2x0_of_init(0x02060000, 0xF0F0FFFF); +#else + return l2x0_of_init(0x72060000, 0xF0F0FFFF); +#endif +} +early_initcall(zynq_l2c_init); +#endif + + +#ifdef CONFIG_XILINX_L1_PREFETCH +static void __init zynq_data_prefetch_enable(void *info) { /* - * 64KB way size, 8-way associativity, parity disabled + * Enable prefetching in aux control register. L2 prefetch must + * only be enabled if the slave supports it (PL310 does) */ - l2x0_of_init(0x02060000, 0xF0F0FFFF); + asm volatile ("mrc p15, 0, r1, c1, c0, 1\n" + "orr r1, r1, #6\n" + "mcr p15, 0, r1, c1, c0, 1\n" + : : : "r1"); +} +#endif + +static void __init zynq_init_late(void) +{ + zynq_pm_late_init(); - of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL); +#ifdef CONFIG_XILINX_L1_PREFETCH + on_each_cpu(zynq_data_prefetch_enable, NULL, 0); +#endif +} + +/** + * zynq_init_machine - System specific initialization, intended to be + * called from board specific initialization. + */ +static void __init zynq_init_machine(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static void __init zynq_timer_init(void) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:206 @ zynq_scu_map_io(); } +static void __init zynq_irq_init(void) +{ + gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; + irqchip_init(); +} + static void zynq_system_reset(enum reboot_mode mode, const char *cmd) { zynq_slcr_system_reset(); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:225 @ DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") .smp = smp_ops(zynq_smp_ops), .map_io = zynq_map_io, + .init_irq = zynq_irq_init, .init_machine = zynq_init_machine, + .init_late = zynq_init_late, .init_time = zynq_timer_init, .dt_compat = zynq_dt_match, + .reserve = zynq_memory_init, .restart = zynq_system_reset, MACHINE_END Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/common.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mach-zynq/common.h 2014-07-20 22:05:50.267066110 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/common.h 2014-07-20 22:06:34.274340060 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:24 @ extern void zynq_slcr_system_reset(void); extern void zynq_slcr_cpu_stop(int cpu); extern void zynq_slcr_cpu_start(int cpu); +extern u32 zynq_slcr_get_ocm_config(void); #ifdef CONFIG_SMP +extern void zynq_secondary_startup(void); extern void secondary_startup(void); extern char zynq_secondary_trampoline; extern char zynq_secondary_trampoline_jump; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:36 @ extern struct smp_operations zynq_smp_ops __initdata; #endif +extern void zynq_slcr_write(u32 val, u32 offset); +extern u32 zynq_slcr_read(u32 offset); + +extern void zynq_slcr_init_preload_fpga(void); +extern void zynq_slcr_init_postload_fpga(void); + extern void __iomem *zynq_slcr_base; extern void __iomem *zynq_scu_base; /* Hotplug */ extern void zynq_platform_cpu_die(unsigned int cpu); +#ifdef CONFIG_SUSPEND +int zynq_pm_late_init(void); +#else +static inline int zynq_pm_late_init(void) +{ + return 0; +} +#endif + +extern unsigned int zynq_sys_suspend_sz; +int zynq_sys_suspend(void __iomem *ddrc_base, void __iomem *slcr_base); + #endif Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/headsmp.S =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mach-zynq/headsmp.S 2014-07-20 22:05:50.275065977 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/headsmp.S 2014-07-20 22:06:34.284339895 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:21 @ .word /* cpu 1 */ .globl zynq_secondary_trampoline_end zynq_secondary_trampoline_end: - ENDPROC(zynq_secondary_trampoline) + +ENTRY(zynq_secondary_startup) + bl v7_invalidate_l1 + b secondary_startup +ENDPROC(zynq_secondary_startup) Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mach-zynq/Kconfig 2014-07-20 22:05:50.273066011 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/Kconfig 2014-07-20 22:06:34.295339714 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:5 @ bool "Xilinx Zynq ARM Cortex A9 Platform" if ARCH_MULTI_V7 select ARM_AMBA select ARM_GIC - select COMMON_CLK - select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select ICST select MIGHT_HAVE_CACHE_L2X0 - select USE_OF select HAVE_SMP - select SPARSE_IRQ + select CACHE_L2X0 + select ARCH_REQUIRE_GPIOLIB + select ARCH_HAS_CPUFREQ + select ARCH_HAS_OPP + select MIGHT_HAVE_PCI select CADENCE_TTC_TIMER + select GENERIC_ALLOCATOR help Support for Xilinx Zynq ARM Cortex A9 Platform + +if ARCH_ZYNQ + +menu "Xilinx Specific Options" + +config XILINX_L1_PREFETCH + bool "L1 Cache Prefetch" + default y + help + This option turns on L1 cache prefetching to get the best performance + in many cases. This may not always be the best performance depending on + the usage. There are some cases where this may cause issues when booting. + +config XILINX_L2_PREFETCH + bool "L2 Cache Prefetch" + default y + help + This option turns on L2 cache prefetching to get the best performance + in many cases. This may not always be the best performance depending on + the usage. + +config XILINX_AXIPCIE + bool "Xilinx AXI PCIe host bridge support" + select PCI + select ARCH_SUPPORTS_MSI + help + Say 'Y' here if you want kernel to support the Xilinx AXI PCIe + Host Bridge. This supports Message Signal Interrupts (MSI), if you + want to use this feature select CONFIG_PCI_MSI from 'Bus Support ->'. + +endmenu + +endif Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mach-zynq/Makefile 2014-07-20 22:05:50.270066060 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/Makefile 2014-07-20 22:06:34.304339565 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:6 @ # # Common support -obj-y := common.o slcr.o +obj-y := common.o slcr.o zynq_ocm.o + +obj-$(CONFIG_PCI_MSI) += xaxipcie-msi.o CFLAGS_REMOVE_hotplug.o =-march=armv6k CFLAGS_hotplug.o =-Wa,-march=armv7-a -mcpu=cortex-a9 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_SMP) += headsmp.o platsmp.o +obj-$(CONFIG_SUSPEND) += pm.o suspend.o +obj-$(CONFIG_XILINX_AXIPCIE) += xaxipcie.o Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/Makefile.boot =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mach-zynq/Makefile.boot 2014-07-20 22:05:50.269066076 +0200 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ - zreladdr-y += 0x00008000 -params_phys-y := 0x00000100 -initrd_phys-y := 0x00800000 Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/platsmp.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mach-zynq/platsmp.c 2014-07-20 22:05:50.268066093 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/platsmp.c 2014-07-20 22:06:34.333339087 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:42 @ u32 trampoline_code_size = &zynq_secondary_trampoline_end - &zynq_secondary_trampoline; - if (cpu > ncores) { + if (cpu >= ncores) { pr_warn("CPU No. is not available in the system\n"); return -1; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:98 @ static int zynq_boot_secondary(unsigned int cpu, struct task_struct *idle) { - return zynq_cpun_start(virt_to_phys(secondary_startup), cpu); + return zynq_cpun_start(virt_to_phys(zynq_secondary_startup), cpu); } /* @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:117 @ static void __init zynq_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); - scu_enable(zynq_scu_base); } +#ifdef CONFIG_HOTPLUG_CPU +static int zynq_cpu_kill(unsigned cpu) +{ + zynq_slcr_cpu_stop(cpu); + return 1; +} +#endif + struct smp_operations zynq_smp_ops __initdata = { .smp_init_cpus = zynq_smp_init_cpus, .smp_prepare_cpus = zynq_smp_prepare_cpus, .smp_boot_secondary = zynq_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU .cpu_die = zynq_platform_cpu_die, + .cpu_kill = zynq_cpu_kill, #endif }; Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/pm.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/pm.c 2014-07-20 22:06:34.343338922 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Suspend support for Zynq + * + * Copyright (C) 2012 Xilinx + * + * Soren Brinkmann <soren.brinkmann@xilinx.com> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/clk/zynq.h> +#include <linux/err.h> +#include <linux/genalloc.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/slab.h> +#include <linux/suspend.h> +#include <asm/cacheflush.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/mach/map.h> +#include <asm/suspend.h> +#include "common.h" + +#define DDRC_CTRL_REG1_OFFS 0x60 +#define DDRC_DRAM_PARAM_REG3_OFFS 0x20 +#define SCU_CTRL 0 + +#define DDRC_CLOCKSTOP_MASK BIT(23) +#define DDRC_SELFREFRESH_MASK BIT(12) +#define SCU_STBY_EN_MASK BIT(5) + +static void __iomem *ddrc_base; +static void __iomem *ocm_base; + +static int zynq_pm_prepare_late(void) +{ + return zynq_clk_suspend_early(); +} + +static void zynq_pm_wake(void) +{ + zynq_clk_resume_late(); +} + +static int zynq_pm_suspend(unsigned long arg) +{ + u32 reg; + int (*zynq_suspend_ptr)(void __iomem *, void __iomem *); + int do_ddrpll_bypass = 1; + + /* Enable DDR self-refresh and clock stop */ + if (ddrc_base) { + reg = readl(ddrc_base + DDRC_CTRL_REG1_OFFS); + reg |= DDRC_SELFREFRESH_MASK; + writel(reg, ddrc_base + DDRC_CTRL_REG1_OFFS); + + reg = readl(ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS); + reg |= DDRC_CLOCKSTOP_MASK; + writel(reg, ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS); + } else { + do_ddrpll_bypass = 0; + } + + /* SCU standby mode */ + if (zynq_scu_base) { + reg = readl(zynq_scu_base + SCU_CTRL); + reg |= SCU_STBY_EN_MASK; + writel(reg, zynq_scu_base + SCU_CTRL); + } + + /* Topswitch clock stop disable */ + zynq_clk_topswitch_disable(); + + /* A9 clock gating */ + asm volatile ("mrc p15, 0, r12, c15, c0, 0\n" + "orr r12, r12, #1\n" + "mcr p15, 0, r12, c15, c0, 0\n" + : /* no outputs */ + : /* no inputs */ + : "r12"); + + if (ocm_base) { + /* + * Copy code to suspend system into OCM. The suspend code + * needs to run from OCM as DRAM may no longer be available + * when the PLL is stopped. + */ + memcpy((__force void *)ocm_base, &zynq_sys_suspend, + zynq_sys_suspend_sz); + flush_icache_range((unsigned long)ocm_base, + (unsigned long)(ocm_base) + zynq_sys_suspend_sz); + zynq_suspend_ptr = (__force void *)ocm_base; + } else { + do_ddrpll_bypass = 0; + } + + /* Transfer to suspend code in OCM */ + if (do_ddrpll_bypass) { + /* + * Going this way will turn off DDR related clocks and the DDR + * PLL. I.e. We might brake sub systems relying on any of this + * clocks. And even worse: If there are any other masters in the + * system (e.g. in the PL) accessing DDR they are screwed. + */ + flush_cache_all(); + if (zynq_suspend_ptr(ddrc_base, zynq_slcr_base)) + pr_warn("DDR self refresh failed.\n"); + } else { + WARN_ONCE(1, "DRAM self-refresh not available\n"); + cpu_do_idle(); + } + + /* Topswitch clock stop enable */ + zynq_clk_topswitch_enable(); + + /* SCU standby mode */ + if (zynq_scu_base) { + reg = readl(zynq_scu_base + SCU_CTRL); + reg &= ~SCU_STBY_EN_MASK; + writel(reg, zynq_scu_base + SCU_CTRL); + } + + /* A9 clock gating */ + asm volatile ("mrc p15, 0, r12, c15, c0, 0\n" + "bic r12, r12, #1\n" + "mcr p15, 0, r12, c15, c0, 0\n" + : /* no outputs */ + : /* no inputs */ + : "r12"); + + /* Disable DDR self-refresh and clock stop */ + if (ddrc_base) { + reg = readl(ddrc_base + DDRC_CTRL_REG1_OFFS); + reg &= ~DDRC_SELFREFRESH_MASK; + writel(reg, ddrc_base + DDRC_CTRL_REG1_OFFS); + + reg = readl(ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS); + reg &= ~DDRC_CLOCKSTOP_MASK; + writel(reg, ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS); + } + + return 0; +} + +static int zynq_pm_enter(suspend_state_t suspend_state) +{ + switch (suspend_state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + outer_disable(); + cpu_suspend(0, zynq_pm_suspend); + outer_resume(); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct platform_suspend_ops zynq_pm_ops = { + .prepare_late = zynq_pm_prepare_late, + .enter = zynq_pm_enter, + .wake = zynq_pm_wake, + .valid = suspend_valid_only_mem, +}; + +/** + * zynq_pm_ioremap() - Create IO mappings + * @comp DT compatible string + * Returns a pointer to the mapped memory or NULL. + * + * Remap the memory region for a compatible DT node. + */ +static void __iomem *zynq_pm_ioremap(const char *comp) +{ + struct device_node *np; + void __iomem *base = NULL; + + np = of_find_compatible_node(NULL, NULL, comp); + if (np) { + base = of_iomap(np, 0); + of_node_put(np); + } else { + pr_warn("%s: no compatible node found for '%s'\n", __func__, + comp); + } + + return base; +} + +/** + * zynq_pm_remap_ocm() - Remap OCM + * Returns a pointer to the mapped memory or NULL. + * + * Remap the OCM. + */ +static void __iomem *zynq_pm_remap_ocm(void) +{ + struct device_node *np; + const char *comp = "xlnx,zynq-ocm-1.0"; + void __iomem *base = NULL; + + np = of_find_compatible_node(NULL, NULL, comp); + if (np) { + struct device *dev; + unsigned long pool_addr; + unsigned long pool_addr_virt; + struct gen_pool *pool; + + of_node_put(np); + + dev = &(of_find_device_by_node(np)->dev); + + /* Get OCM pool from device tree or platform data */ + pool = dev_get_gen_pool(dev); + if (!pool) { + pr_warn("%s: OCM pool is not available\n", __func__); + return NULL; + } + + pool_addr_virt = gen_pool_alloc(pool, zynq_sys_suspend_sz); + if (!pool_addr_virt) { + pr_warn("%s: Can't get OCM poll\n", __func__); + return NULL; + } + pool_addr = gen_pool_virt_to_phys(pool, pool_addr_virt); + if (!pool_addr) { + pr_warn("%s: Can't get physical address of OCM pool\n", + __func__); + return NULL; + } + base = __arm_ioremap(pool_addr, zynq_sys_suspend_sz, MT_MEMORY); + if (!base) { + pr_warn("%s: IOremap OCM pool failed\n", __func__); + return NULL; + } + pr_debug("%s: Remap OCM %s from %lx to %lx\n", __func__, comp, + pool_addr_virt, (unsigned long)base); + } else { + pr_warn("%s: no compatible node found for '%s'\n", __func__, + comp); + } + + return base; +} + +int __init zynq_pm_late_init(void) +{ + ddrc_base = zynq_pm_ioremap("xlnx,ps7-ddrc"); + if (!ddrc_base) + pr_warn("%s: Unable to map DDRC IO memory.\n", __func__); + + /* + * FIXME: should be done by an ocm driver which then provides allocators + */ + ocm_base = zynq_pm_remap_ocm(); + if (!ocm_base) + pr_warn("%s: Unable to map OCM.\n", __func__); + + suspend_set_ops(&zynq_pm_ops); + + return 0; +} Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/slcr.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mach-zynq/slcr.c 2014-07-20 22:05:50.274065994 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/slcr.c 2014-07-20 22:06:34.351338790 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:18 @ */ #include <linux/io.h> +#include <linux/module.h> #include <linux/of_address.h> #include <linux/clk/zynq.h> #include "common.h" /* register offsets */ #define SLCR_UNLOCK_OFFSET 0x8 /* SCLR unlock register */ + #define SLCR_PS_RST_CTRL_OFFSET 0x200 /* PS Software Reset Control */ +#define SLCR_FPGA_RST_CTRL_OFFSET 0x240 /* FPGA Software Reset Control */ #define SLCR_A9_CPU_RST_CTRL_OFFSET 0x244 /* CPU Software Reset Control */ #define SLCR_REBOOT_STATUS_OFFSET 0x258 /* PS Reboot Status */ +#define SLCR_LVL_SHFTR_EN_OFFSET 0x900 /* Level Shifters Enable */ +#define SLCR_OCM_CFG_OFFSET 0x910 /* OCM Address Mapping */ #define SLCR_UNLOCK_MAGIC 0xDF0D #define SLCR_A9_CPU_CLKSTOP 0x10 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:64 @ } /** + * zynq_slcr_write - Write to a register in SLCR block + * + * @val: Value to write to the register + * @offset: Register offset in SLCR block + */ +void zynq_slcr_write(u32 val, u32 offset) +{ + writel(val, zynq_slcr_base + offset); +} +EXPORT_SYMBOL(zynq_slcr_write); + +/** + * zynq_slcr_read - Read a register in SLCR block + * + * @offset: Register offset in SLCR block + * + * return: Value read from the SLCR register + */ +u32 zynq_slcr_read(u32 offset) +{ + return readl(zynq_slcr_base + offset); +} +EXPORT_SYMBOL(zynq_slcr_read); + +/** + * zynq_slcr_get_ocm_config - Get SLCR OCM config + * + * return: OCM config bits + */ +u32 zynq_slcr_get_ocm_config(void) +{ + return zynq_slcr_read(SLCR_OCM_CFG_OFFSET); +} + +/** + * zynq_slcr_init_preload_fpga - Disable communication from the PL to PS. + */ +void zynq_slcr_init_preload_fpga(void) +{ + + /* Assert FPGA top level output resets */ + zynq_slcr_write(0xF, SLCR_FPGA_RST_CTRL_OFFSET); + + /* Disable level shifters */ + zynq_slcr_write(0, SLCR_LVL_SHFTR_EN_OFFSET); + + /* Enable output level shifters */ + zynq_slcr_write(0xA, SLCR_LVL_SHFTR_EN_OFFSET); +} +EXPORT_SYMBOL(zynq_slcr_init_preload_fpga); + +/** + * zynq_slcr_init_postload_fpga - Re-enable communication from the PL to PS. + */ +void zynq_slcr_init_postload_fpga(void) +{ + + /* Enable level shifters */ + zynq_slcr_write(0xf, SLCR_LVL_SHFTR_EN_OFFSET); + + /* Deassert AXI interface resets */ + zynq_slcr_write(0, SLCR_FPGA_RST_CTRL_OFFSET); +} +EXPORT_SYMBOL(zynq_slcr_init_postload_fpga); + +/** * zynq_slcr_cpu_start - Start cpu * @cpu: cpu number */ void zynq_slcr_cpu_start(int cpu) { u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + reg &= ~(SLCR_A9_CPU_RST << cpu); writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu); Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/suspend.S =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/suspend.S 2014-07-20 22:06:34.360338641 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Suspend support for Zynq + * + * Copyright (C) 2012 Xilinx + * + * Soren Brinkmann <soren.brinkmann@xilinx.com> + * + * 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 <linux/linkage.h> + +#define DDRPLL_CTRL_OFFS 0x104 +#define PLLSTATUS_OFFS 0x10c +#define DDR_CLK_CTRL_OFFS 0x124 +#define DCI_CLK_CTRL_OFFS 0x128 +#define DDR_CMD_STA_OFFS 0x618 +#define MODE_STS_OFFS 0x54 + +#define PLL_RESET_MASK 1 +#define PLL_PWRDWN_MASK (1 << 1) +#define PLL_BYPASS_MASK (1 << 4) +#define DCICLK_ENABLE_MASK 1 +#define DDRCLK_ENABLE_MASK 3 +#define DDR_LOCK_MASK (1 << 1) +#define DDR_STATUS_MASK 7 + +#define DDR_OPMODE_SR 3 +#define MAXTRIES 100 + + .text + +/** + * zynq_sys_suspend - Enter suspend + * @ddrc_base: Base address of the DDRC + * @slcr_base: Base address of the SLCR + * Returns -1 if DRAM subsystem is not gated off, 0 otherwise. + * + * This function is moved into OCM and finishes the suspend operation. I.e. DDR + * related clocks are gated off and the DDR PLL is bypassed. + */ +ENTRY(zynq_sys_suspend) + dsb + /* Check DDRC is in self-refresh mode */ + ldr r2, [r0, #MODE_STS_OFFS] + and r2, #DDR_STATUS_MASK + cmp r2, #DDR_OPMODE_SR + movweq r3, #0xff00 + bne suspend + + mov r3, #0 + /* Wait for command queue empty */ +1: cmp r3, #MAXTRIES + movweq r3, #0xff00 + beq suspend + ldr r2, [r1, #DDR_CMD_STA_OFFS] + cmp r2, #0 + addne r3, #1 + bne 1b + + dsb + + /* Stop DDR clocks */ + ldr r2, [r1, #DDR_CLK_CTRL_OFFS] + bic r2, #DDRCLK_ENABLE_MASK + str r2, [r1, #DDR_CLK_CTRL_OFFS] + + dmb + + ldr r2, [r1, #DCI_CLK_CTRL_OFFS] + bic r2, #DCICLK_ENABLE_MASK + str r2, [r1, #DCI_CLK_CTRL_OFFS] + + dmb + + /* Bypass and powerdown DDR PLL */ + ldr r2, [r1, #DDRPLL_CTRL_OFFS] + orr r2, #PLL_BYPASS_MASK + str r2, [r1, #DDRPLL_CTRL_OFFS] + orr r2, #(PLL_PWRDWN_MASK | PLL_RESET_MASK) + str r2, [r1, #DDRPLL_CTRL_OFFS] + +suspend: + wfi + dsb + cmp r3, #0xff00 + moveq r0, #-1 + beq exit + + /* Power up DDR PLL */ + ldr r2, [r1, #DDRPLL_CTRL_OFFS] + bic r2, #(PLL_PWRDWN_MASK | PLL_RESET_MASK) + str r2, [r1, #DDRPLL_CTRL_OFFS] + /* wait for lock */ +1: ldr r2, [r1, #PLLSTATUS_OFFS] + and r2, #DDR_LOCK_MASK + cmp r2, #0 + beq 1b + + dsb + + /* Disable PLL bypass */ + ldr r2, [r1, #DDRPLL_CTRL_OFFS] + bic r2, #PLL_BYPASS_MASK + str r2, [r1, #DDRPLL_CTRL_OFFS] + + dmb + + /* Start DDR clocks */ + ldr r2, [r1, #DCI_CLK_CTRL_OFFS] + orr r2, #DCICLK_ENABLE_MASK + str r2, [r1, #DCI_CLK_CTRL_OFFS] + + dmb + + ldr r2, [r1, #DDR_CLK_CTRL_OFFS] + orr r2, #DDRCLK_ENABLE_MASK + str r2, [r1, #DDR_CLK_CTRL_OFFS] + + dsb + + mov r0, #0 +exit: bx lr + +ENTRY(zynq_sys_suspend_sz) + .word . - zynq_sys_suspend + + ENDPROC(zynq_sys_suspend) Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/xaxipcie.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/xaxipcie.c 2014-07-20 22:06:34.374338411 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx AXI PCIe IP hardware initialation, setup and + * configuration spaces access file. + * + * Copyright (c) 2012 Xilinx, Inc. + * + * This program has adopted some work from PCI/PCIE support for AMCC + * PowerPC boards written by Benjamin Herrenschmidt. + * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/of_address.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/sizes.h> +#include <linux/irqdomain.h> +#include <linux/pci.h> +#include <asm/mach/pci.h> + +/* Register definitions */ +#define PCIE_CFG_CMD 0x00000004 +#define PCIE_CFG_CLS 0x00000008 +#define PCIE_CFG_HDR 0x0000000C +#define PCIE_CFG_AD1 0x00000010 +#define PCIE_CFG_AD2 0x00000014 +#define PCIE_CFG_BUS 0x00000018 +#define PCIE_CFG_IO 0x0000001C +#define PCIE_CFG_MEM 0x00000020 +#define PCIE_CFG_PREF_MEM 0x00000024 +#define PCIE_CFG_PREF_BASE_UPPER 0x00000028 +#define PCIE_CFG_PREF_LIMIT_UPPER 0x0000002c +#define PCIE_CFG_IO_UPPER 0x00000030 + +#define XAXIPCIE_REG_VSECC 0x00000128 +#define XAXIPCIE_REG_VSECH 0x0000012c +#define XAXIPCIE_REG_BIR 0x00000130 +#define XAXIPCIE_REG_BSCR 0x00000134 +#define XAXIPCIE_REG_IDR 0x00000138 +#define XAXIPCIE_REG_IMR 0x0000013c +#define XAXIPCIE_REG_BLR 0x00000140 +#define XAXIPCIE_REG_PSCR 0x00000144 +#define XAXIPCIE_REG_RPSC 0x00000148 +#define XAXIPCIE_REG_MSIBASE1 0x0000014c +#define XAXIPCIE_REG_MSIBASE2 0x00000150 +#define XAXIPCIE_REG_RPEFR 0x00000154 +#define XAXIPCIE_REG_RPIFR1 0x00000158 +#define XAXIPCIE_REG_RPIFR2 0x0000015c +#define XAXIPCIE_REG_VSECC2 0x00000200 +#define XAXIPCIE_REG_VSECH2 0x00000204 + +/* Interrupt register defines */ +#define XAXIPCIE_INTR_LINK_DOWN (1 << 0) +#define XAXIPCIE_INTR_ECRC_ERR (1 << 1) +#define XAXIPCIE_INTR_STR_ERR (1 << 2) +#define XAXIPCIE_INTR_HOT_RESET (1 << 3) +#define XAXIPCIE_INTR_CFG_COMPL (7 << 5) +#define XAXIPCIE_INTR_CFG_TIMEOUT (1 << 8) +#define XAXIPCIE_INTR_CORRECTABLE (1 << 9) +#define XAXIPCIE_INTR_NONFATAL (1 << 10) +#define XAXIPCIE_INTR_FATAL (1 << 11) +#define XAXIPCIE_INTR_INTX (1 << 16) +#define XAXIPCIE_INTR_MSI (1 << 17) +#define XAXIPCIE_INTR_SLV_UNSUPP (1 << 20) +#define XAXIPCIE_INTR_SLV_UNEXP (1 << 21) +#define XAXIPCIE_INTR_SLV_COMPL (1 << 22) +#define XAXIPCIE_INTR_SLV_ERRP (1 << 23) +#define XAXIPCIE_INTR_SLV_CMPABT (1 << 24) +#define XAXIPCIE_INTR_SLV_ILLBUR (1 << 25) +#define XAXIPCIE_INTR_MST_DECERR (1 << 26) +#define XAXIPCIE_INTR_MST_SLVERR (1 << 27) +#define XAXIPCIE_INTR_MST_ERRP (1 << 28) + +#define BUS_LOC_SHIFT 20 +#define DEV_LOC_SHIFT 12 +#define PRIMARY_BUS 1 +#define PORT_REG_SIZE 0x1000 +#define PORT_HEADER_SIZE 0x128 + +#define XAXIPCIE_LOCAL_CNFG_BASE 0x00000000 +#define XAXIPCIE_REG_BASE 0x00000128 +#define XAXIPCIE_REG_PSCR_LNKUP 0x00000800 +#define XAXIPCIE_REG_IMR_MASKALL 0x1FF30FED +#define XAXIPCIE_REG_IDR_MASKALL 0xFFFFFFFF +#define XAXIPCIE_REG_RPSC_BEN 0x00000001 +#define BUS_MASTER_ENABLE 0x00000004 + +#define XAXIPCIE_ACCESS8 1 +#define XAXIPCIE_ACCESS16 2 + +#define XAXIPCIE_MEM_SPACE 2 +#define XAXIPCIE_MEM_SPACE64 3 + +/* Config structure for PCIe */ +struct xaxi_pcie_of_config { + u32 num_instances; + u32 device_id; + u32 device_type; + u32 ecam_base; + u32 ecam_high; + u32 baseaddr; + u32 highaddr; + u32 bars_num; + u32 irq_num; + u32 reg_base; + u32 reg_len; + u32 pcie2axibar_0; + u32 pcie2axibar_1; + const __be32 *ranges; + int range_len; + u32 address_cells; +}; + +/* PCIe Root Port Structure */ +struct xaxi_pcie_port { + struct device_node *node; + u32 reg_base; + u32 reg_len; + u32 ecam_base; + u32 ecam_high; + u32 baseaddr; + u32 highaddr; + u32 header_addr; + u8 index; + u8 type; + u8 link_up; + u8 bars_num; + u32 irq_num; + const __be32 *ranges; + int range_len; + u32 pna; + u8 __iomem *base_addr_remap; + u8 __iomem *header_remap; + u8 __iomem *ecam_remap; + u32 pcie2axibar_0; + u32 pcie2axibar_1; + u32 root_bus_nr; + u32 first_busno; + u32 last_busno; + resource_size_t isa_mem_phys; + resource_size_t isa_mem_size; + resource_size_t pci_mem_offset; + struct resource io_resource; + struct resource mem_resources[3]; + char mem_space_name[16]; +}; + +static struct xaxi_pcie_port *xaxi_pcie_ports; +static int xaxi_pcie_port_cnt; +static int last_bus_on_record; + +/* ISA Memory physical address */ +static resource_size_t isa_mem_base; + +#ifdef CONFIG_PCI_MSI +static int xaxipcie_msi_irq_base; + +int xaxipcie_alloc_msi_irqdescs(struct device_node *node, + unsigned long msg_addr); +#endif + +/* Macros */ +#define is_link_up(base_address) \ + ((readl(base_address + XAXIPCIE_REG_PSCR) & \ + XAXIPCIE_REG_PSCR_LNKUP) ? 1 : 0) + +#define bridge_enable(base_address) \ + writel((readl(base_address + XAXIPCIE_REG_RPSC) | \ + XAXIPCIE_REG_RPSC_BEN), \ + (base_address + XAXIPCIE_REG_RPSC)) + +/** + * xaxi_pcie_verify_config + * @port: A pointer to a pcie port that needs to be handled + * @bus: Bus structure of current bus + * @devfun: device/function + * + * @return: Error / no error + * + * @note: Make sure we can handle this configuration call on our + * device. + */ +static int xaxi_pcie_verify_config(struct xaxi_pcie_port *port, + struct pci_bus *bus, + unsigned int devfn) +{ + static int message; + + /* Endpoint can not generate upstream(remote) config cycles */ + if ((!port->type) && bus->number != port->first_busno) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Check we are within the mapped range */ + if (bus->number > port->last_busno) { + if (!message) { + pr_warn("Warning! Probing bus %u out of range !\n", + bus->number); + message++; + } + return PCIBIOS_DEVICE_NOT_FOUND; + } + + /* The other side of the RC has only one device as well */ + if (bus->number == (port->first_busno + 1) && + PCI_SLOT(devfn) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Check if we have a link */ + if (!port->link_up) + port->link_up = is_link_up(port->base_addr_remap); + + if ((bus->number != port->first_busno) && !port->link_up) + return PCIBIOS_DEVICE_NOT_FOUND; + + return 0; +} + +/** + * xaxi_pcie_get_config_base + * @port: A pointer to a pcie port that needs to be handled + * @bus: Bus structure of current bus + * @devfun: Device/function + * @where: Offset from base + * + * @return: Base address of the configuration space needed to be + * accessed. + * + * @note: Get the base address of the configuration space for this + * pcie device. + */ +static void __iomem *xaxi_pcie_get_config_base( + struct xaxi_pcie_port *port, + struct pci_bus *bus, + unsigned int devfn, int where) +{ + int relbus; + + relbus = ((bus->number << BUS_LOC_SHIFT) | (devfn << DEV_LOC_SHIFT)); + + return port->header_remap + relbus + where; +} + +/** + * xaxi_pcie_read_config - Read config reg. + * @port: A pointer to a pcie port that needs to be handled + * @bus: Bus structure of current bus + * @devfun: Device/function + * @where: Offset from base + * @size: Byte/word/dword + * @val: A pointer to value read + * + * @return: Error / no error + * + * + * @note: Read byte/word/dword from pcie device config reg. + */ +static int xaxi_pcie_read_config(struct pci_bus *bus, + unsigned int devfn, + int where, + int size, + u32 *val) +{ + struct pci_sys_data *sys = bus->sysdata; + struct xaxi_pcie_port *port = sys->private_data; + void __iomem *addr; + + if (xaxi_pcie_verify_config(port, bus, devfn) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr = xaxi_pcie_get_config_base(port, bus, devfn, where); + + if ((bus->number == 0) && devfn > 0) { + *val = 0xFFFFFFFF; + return PCIBIOS_SUCCESSFUL; + } + + switch (size) { + case XAXIPCIE_ACCESS8: + *val = readb(addr); + break; + case XAXIPCIE_ACCESS16: + *val = readw(addr); + break; + default: + *val = readl(addr); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +/** + * xaxi_pcie_write_config - Write config reg. + * @port: A pointer to a pcie port that needs to be handled + * @bus: Bus structure of current bus + * @devfun: Device/function + * @where: Offset from base + * @size: Byte/word/dword + * @val: Value to be written to device + * + * @return: Error / no error + * + * + * @note: Write byte/word/dword to pcie device config reg. + */ +static int xaxi_pcie_write_config(struct pci_bus *bus, + unsigned int devfn, + int where, + int size, + u32 val) +{ + struct pci_sys_data *sys = bus->sysdata; + struct xaxi_pcie_port *port = sys->private_data; + void __iomem *addr; + + if (xaxi_pcie_verify_config(port, bus, devfn) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr = xaxi_pcie_get_config_base(port, bus, devfn, where); + + if ((bus->number == 0) && devfn > 0) + return PCIBIOS_SUCCESSFUL; + + switch (size) { + case XAXIPCIE_ACCESS8: + writeb(val, addr); + break; + case XAXIPCIE_ACCESS16: + writew(val, addr); + break; + default: + writel(val, addr); + break; + } + + wmb(); + + return PCIBIOS_SUCCESSFUL; +} + +/** + * xaxi_pcie_set_bridge_resource - Setup base & limit registers of config space. + * @port: Pointer to a root port + * + * @return: None + * + * @note: None + */ +static void xaxi_pcie_set_bridge_resource(struct xaxi_pcie_port *port) +{ + const __be32 *ranges = port->ranges; + int rlen = port->range_len; + int np = port->pna + 5; + u32 pci_space; + unsigned long long pci_addr, size; + u32 val = 0; + + while ((rlen -= np * 4) >= 0) { + pci_space = be32_to_cpup(ranges); + pci_addr = of_read_number(ranges + 1, 2); + size = of_read_number(ranges + port->pna + 3, 2); + + pr_info("%s:pci_space: 0x%08x pci_addr:0x%016llx size: 0x%016llx\n", + __func__, pci_space, pci_addr, size); + + ranges += np; + + switch ((pci_space >> 24) & 0x3) { + case XAXIPCIE_MEM_SPACE: /* PCI Memory space */ + pr_info("%s:Setting resource in Memory Space\n", + __func__); + writel(port->pcie2axibar_0, + port->header_remap + + PCIE_CFG_AD1); + writel(port->pcie2axibar_1, + port->header_remap + + PCIE_CFG_AD2); + break; + case XAXIPCIE_MEM_SPACE64: /* PCI 64 bits Memory space */ + pr_info("%s:Setting resource in Prefetchable Memory Space\n", + __func__); + + val = ((pci_addr >> 16) & 0xfff0) | + ((pci_addr + size - 1) & 0xfff00000); + + writel(val, port->header_remap + + PCIE_CFG_PREF_MEM); + + val = ((pci_addr >> 32) & 0xffffffff); + writel(val, port->header_remap + + PCIE_CFG_PREF_BASE_UPPER); + + val = (((pci_addr + size - 1) >> 32) & 0xffffffff); + writel(val, port->header_remap + + PCIE_CFG_PREF_LIMIT_UPPER); + break; + } + } +} + +static int xaxi_pcie_hookup_resources(struct xaxi_pcie_port *port, + struct pci_sys_data *sys) +{ + struct resource *res; + int i; + + /* Hookup Memory resources */ + for (i = 0; i < 3; ++i) { + res = &port->mem_resources[i]; + snprintf(port->mem_space_name, sizeof(port->mem_space_name), + "PCIe %d MEM", port->index); + port->mem_space_name[sizeof(port->mem_space_name) - 1] = 0; + res->name = port->mem_space_name; + + if (!res->flags) { + if (i > 0) + continue; + /* Workaround for lack of MEM resource only on 32-bit */ + res->start = port->pci_mem_offset; + res->end = (resource_size_t)-1LL; + res->flags = IORESOURCE_MEM; + } + if (request_resource(&iomem_resource, res)) + panic("Request PCIe%d Memory resource failed\n", + port->index); + pci_add_resource_offset(&sys->resources, + res, port->pci_mem_offset); + + pr_info("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", + i, (unsigned long long)res->start, + (unsigned long long)res->end, + (unsigned long)res->flags); + } + + return 0; +} + +static void xaxi_pcie_process_bridge_OF_ranges(struct xaxi_pcie_port *port, + int primary) +{ + /* The address cells of PCIe node */ + int pna = port->pna; + int np = pna + 5; + int memno = 0, isa_hole = -1; + u32 pci_space; + unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size; + unsigned long long isa_mb = 0; + struct resource *res; + const __be32 *ranges = port->ranges; + int rlen = port->range_len; + struct device_node *node = port->node; + + pr_info("PCI host bridge %s %s ranges:\n", + node->full_name, primary ? "(primary)" : ""); + + /* Parse it */ + pr_debug("Parsing ranges property...\n"); + while ((rlen -= np * 4) >= 0) { + /* Read next ranges element */ + pci_space = be32_to_cpup(ranges); + pci_addr = of_read_number(ranges + 1, 2); + cpu_addr = of_translate_address(node, ranges + 3); + size = of_read_number(ranges + pna + 3, 2); + + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx\n", + pci_space, pci_addr); + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n", cpu_addr, size); + + ranges += np; + + /* If we failed translation or got a zero-sized region + * (some FW try to feed us with non sensical zero sized regions + * such as power3 which look like some kind of attempt + * at exposing the VGA memory hole) + */ + if (cpu_addr == OF_BAD_ADDR || size == 0) + continue; + + /* Now consume following elements while they are contiguous */ + for (; rlen >= np * sizeof(u32); + ranges += np, rlen -= np * 4) { + if (be32_to_cpup(ranges) != pci_space) + break; + pci_next = of_read_number(ranges + 1, 2); + cpu_next = of_translate_address(node, ranges + 3); + if (pci_next != pci_addr + size || + cpu_next != cpu_addr + size) + break; + size += of_read_number(ranges + pna + 3, 2); + } + + /* Act based on address space type */ + res = NULL; + switch ((pci_space >> 24) & 0x3) { + case XAXIPCIE_MEM_SPACE: /* PCI Memory space */ + case XAXIPCIE_MEM_SPACE64: /* PCI 64 bits Memory space */ + pr_info("MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n", + cpu_addr, cpu_addr + size - 1, pci_addr, + (pci_space & 0x40000000) ? "Prefetch" : ""); + + /* We support only 3 memory ranges */ + if (memno >= 3) { + pr_info("\\--> Skipped (too many) !\n"); + continue; + } + /* Handles ISA memory hole space here */ + if (pci_addr == 0) { + isa_mb = cpu_addr; + isa_hole = memno; + if (primary || isa_mem_base == 0) + isa_mem_base = cpu_addr; + port->isa_mem_phys = cpu_addr; + port->isa_mem_size = size; + } + + /* We get the PCI/Mem offset from the first range or + * the, current one if the offset came from an ISA + * hole. If they don't match, bugger. + */ + if (memno == 0 || + (isa_hole >= 0 && pci_addr != 0 && + port->pci_mem_offset == isa_mb)) + port->pci_mem_offset = cpu_addr - pci_addr; + else if (pci_addr != 0 && + port->pci_mem_offset != cpu_addr - pci_addr) { + pr_info("\\--> Skipped (offset mismatch) !\n"); + continue; + } + + /* Build resource */ + res = &port->mem_resources[memno++]; + res->flags = IORESOURCE_MEM; + if (pci_space & 0x40000000) + res->flags |= IORESOURCE_PREFETCH; + res->start = cpu_addr; + break; + } + if (res != NULL) { + res->name = node->full_name; + res->end = res->start + size - 1; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + } + + /* If there's an ISA hole and the pci_mem_offset is -not- matching + * the ISA hole offset, then we need to remove the ISA hole from + * the resource list for that brige + */ + if (isa_hole >= 0 && port->pci_mem_offset != isa_mb) { + unsigned int next = isa_hole + 1; + pr_info("Removing ISA hole at 0x%016llx\n", isa_mb); + if (next < memno) + memmove(&port->mem_resources[isa_hole], + &port->mem_resources[next], + sizeof(struct resource) * (memno - next)); + port->mem_resources[--memno].flags = 0; + } +} + +static struct pci_ops xaxi_pcie_ops = { + .read = xaxi_pcie_read_config, + .write = xaxi_pcie_write_config, +}; + +static int xaxi_pcie_setup(int nr, struct pci_sys_data *sys) +{ + u32 val; + struct xaxi_pcie_port *port = &xaxi_pcie_ports[nr]; + + sys->private_data = port; + + /* Get bus range */ + port->first_busno = last_bus_on_record; + + val = readl(port->base_addr_remap + XAXIPCIE_REG_PSCR); + val = readl(port->header_remap + XAXIPCIE_REG_BIR); + val = (val >> 16) & 0x7; + port->last_busno = (((port->reg_base - port->reg_len - 1) >> 20) + & 0xFF) & val; + + /* Write primary, secondary and subordinate bus numbers */ + val = port->first_busno; + val |= ((port->first_busno + 1) << 8); + val |= (port->last_busno << 16); + + writel(val, (port->header_remap + PCIE_CFG_BUS)); + last_bus_on_record = port->last_busno + 1; + + xaxi_pcie_set_bridge_resource(port); + + /* Parse outbound mapping resources */ + xaxi_pcie_process_bridge_OF_ranges(port, PRIMARY_BUS); + xaxi_pcie_hookup_resources(port, sys); + + return 1; +} + +static struct pci_bus __init *xaxi_pcie_scan_bus(int nr, + struct pci_sys_data *sys) +{ + struct xaxi_pcie_port *port; + + if (nr >= xaxi_pcie_port_cnt) + return NULL; + + port = &xaxi_pcie_ports[nr]; + port->root_bus_nr = sys->busnr; + + return pci_scan_root_bus(NULL, sys->busnr, &xaxi_pcie_ops, sys, + &sys->resources); +} + +static int xaxi_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + struct pci_sys_data *sys = dev->sysdata; + struct xaxi_pcie_port *port = sys->private_data; + + return port->irq_num; +} + +/* Interrupt handler */ +static irqreturn_t xaxi_pcie_intr_handler(int irq, void *data) +{ + struct xaxi_pcie_port *port = (struct xaxi_pcie_port *)data; + u32 val = 0, mask = 0; + u32 status; + u32 msi_addr = 0; + u32 msi_data = 0; + + /* Read interrupt decode and mask registers */ + val = readl(port->header_remap + XAXIPCIE_REG_IDR); + mask = readl(port->header_remap + XAXIPCIE_REG_IMR); + + status = val & mask; + if (!status) + return IRQ_NONE; + + if (status & XAXIPCIE_INTR_LINK_DOWN) + pr_err("Link Down\n"); + + if (status & XAXIPCIE_INTR_ECRC_ERR) + pr_warn("ECRC failed\n"); + + if (status & XAXIPCIE_INTR_STR_ERR) + pr_warn("Streaming error\n"); + + if (status & XAXIPCIE_INTR_HOT_RESET) + pr_info("Hot reset\n"); + + if (status & XAXIPCIE_INTR_CFG_TIMEOUT) + pr_warn("ECAM access timeout\n"); + + if (status & XAXIPCIE_INTR_CORRECTABLE) { + pr_warn("Correctable error message\n"); + val = readl(port->header_remap + + XAXIPCIE_REG_RPEFR); + if (val & (1 << 18)) { + writel(0xFFFFFFFF, + port->base_addr_remap + + XAXIPCIE_REG_RPEFR); + pr_debug("Requester ID %d\n", (val & 0xffff)); + } + } + + if (status & XAXIPCIE_INTR_NONFATAL) { + pr_warn("Non fatal error message\n"); + val = readl((port->header_remap) + + XAXIPCIE_REG_RPEFR); + if (val & (1 << 18)) { + writel(0xFFFFFFFF, + port->base_addr_remap + + XAXIPCIE_REG_RPEFR); + pr_debug("Requester ID %d\n", (val & 0xffff)); + } + } + + if (status & XAXIPCIE_INTR_FATAL) { + pr_warn("Fatal error message\n"); + val = readl(port->header_remap + + XAXIPCIE_REG_RPEFR); + if (val & (1 << 18)) { + writel(0xFFFFFFFF, + port->base_addr_remap + + XAXIPCIE_REG_RPEFR); + pr_debug("Requester ID %d\n", (val & 0xffff)); + } + } + + if (status & XAXIPCIE_INTR_INTX) { + /* INTx interrupt received */ + val = readl(port->header_remap + XAXIPCIE_REG_RPIFR1); + + /* Check whether interrupt valid */ + if (!(val & (1 << 31))) { + pr_warn("RP Intr FIFO1 read error\n"); + return IRQ_HANDLED; + } + + /* Check MSI or INTX */ + if (!(val & (1 << 30))) { + if (val & (1 << 29)) + pr_debug("INTx assert\n"); + else + pr_debug("INTx deassert\n"); + } + + /* Clear interrupt FIFO register 1 */ + writel(0xFFFFFFFF, + port->base_addr_remap + XAXIPCIE_REG_RPIFR1); + } + + if (status & XAXIPCIE_INTR_MSI) { + /* MSI Interrupt */ + val = readl(port->header_remap + XAXIPCIE_REG_RPIFR1); + + if (!(val & (1 << 31))) { + pr_warn("RP Intr FIFO1 read error\n"); + return IRQ_HANDLED; + } + + if (val & (1 << 30)) { + msi_addr = (val >> 16) & 0x7FF; + msi_data = readl(port->header_remap + + XAXIPCIE_REG_RPIFR2) & 0xFFFF; + pr_debug("%s: msi_addr %08x msi_data %08x\n", + __func__, msi_addr, msi_data); + } + + /* Clear interrupt FIFO register 1 */ + writel(0xFFFFFFFF, + port->base_addr_remap + XAXIPCIE_REG_RPIFR1); +#ifdef CONFIG_PCI_MSI + /* Handle MSI Interrupt */ + if (msi_data >= xaxipcie_msi_irq_base) + generic_handle_irq(msi_data); +#endif + } + + if (status & XAXIPCIE_INTR_SLV_UNSUPP) + pr_warn("Slave unsupported request\n"); + + if (status & XAXIPCIE_INTR_SLV_UNEXP) + pr_warn("Slave unexpected completion\n"); + + if (status & XAXIPCIE_INTR_SLV_COMPL) + pr_warn("Slave completion timeout\n"); + + if (status & XAXIPCIE_INTR_SLV_ERRP) + pr_warn("Slave Error Poison\n"); + + if (status & XAXIPCIE_INTR_SLV_CMPABT) + pr_warn("Slave Completer Abort\n"); + + if (status & XAXIPCIE_INTR_SLV_ILLBUR) + pr_warn("Slave Illegal Burst\n"); + + if (status & XAXIPCIE_INTR_MST_DECERR) + pr_warn("Master decode error\n"); + + if (status & XAXIPCIE_INTR_MST_SLVERR) + pr_warn("Master slave error\n"); + + if (status & XAXIPCIE_INTR_MST_ERRP) + pr_warn("Master error poison\n"); + + /* Clear the Interrupt Decode register */ + writel(status, port->base_addr_remap + XAXIPCIE_REG_IDR); + + return IRQ_HANDLED; +} + +/** + * xaxi_pcie_init_port - Initialize hardware + * @port: A pointer to a pcie port that needs to be initialized + * + * @return: Error / no error + * + * @note: None + */ +static int xaxi_pcie_init_port(struct xaxi_pcie_port *port) +{ + void __iomem *base_addr_remap = NULL; + int err = 0; +#ifdef CONFIG_PCI_MSI + unsigned long xaxipcie_msg_addr; +#endif + + base_addr_remap = ioremap(port->reg_base, port->reg_len); + if (!base_addr_remap) + return -ENOMEM; + + port->base_addr_remap = base_addr_remap; + + /* make sure it is root port before touching header */ + if (port->type) { + port->header_remap = base_addr_remap; + writel(BUS_MASTER_ENABLE, + port->base_addr_remap + PCIE_CFG_CMD); + } + +#ifdef CONFIG_PCI_MSI + xaxipcie_msg_addr = port->reg_base & ~0xFFF; /* 4KB aligned */ + writel(0x0, port->base_addr_remap + + XAXIPCIE_REG_MSIBASE1); + + writel(xaxipcie_msg_addr, port->base_addr_remap + + XAXIPCIE_REG_MSIBASE2); + + xaxipcie_msi_irq_base = xaxipcie_alloc_msi_irqdescs(port->node, + xaxipcie_msg_addr); + if (xaxipcie_msi_irq_base < 0) { + pr_err("%s: Couldn't allocate MSI IRQ numbers\n", + __func__); + return -ENODEV; + } +#endif + + port->link_up = is_link_up(port->base_addr_remap); + if (!port->link_up) + pr_info("%s: LINK IS DOWN\n", __func__); + else + pr_info("%s: LINK IS UP\n", __func__); + + /* Disable all interrupts*/ + writel(~XAXIPCIE_REG_IDR_MASKALL, + port->base_addr_remap + XAXIPCIE_REG_IMR); + + /* Clear pending interrupts*/ + writel(readl(port->base_addr_remap + XAXIPCIE_REG_IDR) & + XAXIPCIE_REG_IMR_MASKALL, + port->base_addr_remap + XAXIPCIE_REG_IDR); + + /* Enable all interrupts*/ + writel(XAXIPCIE_REG_IMR_MASKALL, + port->base_addr_remap + XAXIPCIE_REG_IMR); + + /* + * Bridge enable must be done after enumeration, + * but there is no callback defined + */ + bridge_enable(port->base_addr_remap); + + /* Register Interrupt Handler */ + err = request_irq(port->irq_num, xaxi_pcie_intr_handler, + IRQF_SHARED, "zynqpcie", port); + if (err) { + pr_err("%s: Could not allocate interrupt\n", __func__); + return err; + } + + return 0; +} + +static struct xaxi_pcie_port * +xaxi_pcie_instantiate_port_info(struct xaxi_pcie_of_config *config, + struct device_node *node) +{ + struct xaxi_pcie_port *port; + int port_num; + + port_num = config->device_id; + port = &xaxi_pcie_ports[port_num]; + port->node = of_node_get(node); + port->index = port_num; + port->type = config->device_type; + port->reg_base = config->reg_base; + port->reg_len = config->reg_len; + port->bars_num = config->bars_num; + port->irq_num = config->irq_num; + port->header_addr = port->reg_base + XAXIPCIE_LOCAL_CNFG_BASE; + port->pcie2axibar_0 = config->pcie2axibar_0; + port->pcie2axibar_1 = config->pcie2axibar_1; + port->ranges = config->ranges; + port->range_len = config->range_len; + port->pna = config->address_cells; + + return port; +} + +/** + * xaxi_get_pcie_of_config - Read info from device tree + * @node: A pointer to device node to read from + * @info: A pointer to xilinx_pcie_node struct to write device tree + * info into to. + * + * @return: Error / no error + * + * @note: Read related info from device tree + */ +static int xaxi_pcie_get_of_config(struct device_node *node, + struct xaxi_pcie_of_config *info) +{ + const __be32 *value; + int rlen; + + info->num_instances = 1; + + value = of_get_property(node, "xlnx,device-num", &rlen); + + info->device_id = 0; + + value = of_get_property(node, "xlnx,include-rc", &rlen); + if (value) + info->device_type = be32_to_cpup(value); + else + return -ENODEV; + + value = of_get_property(node, "reg", &rlen); + if (value) { + info->reg_base = + be32_to_cpup(value); + info->reg_len = + be32_to_cpup(value + 1); + } else + return -ENODEV; + + value = of_get_property(node, "xlnx,pciebar-num", &rlen); + if (value) + info->bars_num = be32_to_cpup(value); + else + return -ENODEV; + + info->irq_num = irq_of_parse_and_map(node, 0); + + /* Get address translation parameters */ + value = of_get_property(node, "xlnx,pciebar2axibar-0", &rlen); + if (value) { + info->pcie2axibar_0 = + be32_to_cpup(value); + } else + return -ENODEV; + + value = of_get_property(node, "xlnx,pciebar2axibar-1", &rlen); + if (value) { + info->pcie2axibar_1 = + be32_to_cpup(value); + } else + return -ENODEV; + + /* The address cells of PCIe node */ + info->address_cells = of_n_addr_cells(node); + + /* Get ranges property */ + value = of_get_property(node, "ranges", &rlen); + if (value) { + info->ranges = value; + info->range_len = rlen; + } else + return -ENODEV; + + return 0; +} + +static int __init xaxi_pcie_of_probe(struct device_node *node) +{ + int err = 0; + struct xaxi_pcie_of_config config; + struct xaxi_pcie_port *port; + + err = xaxi_pcie_get_of_config(node, &config); + if (err) { + pr_err("%s: Invalid Configuration\n", __func__); + return err; + } + + if (!xaxi_pcie_port_cnt) { + xaxi_pcie_port_cnt = config.num_instances; + + if (xaxi_pcie_port_cnt) { + xaxi_pcie_ports = (struct xaxi_pcie_port *) + kzalloc(xaxi_pcie_port_cnt * + sizeof(struct xaxi_pcie_port), GFP_KERNEL); + + if (!xaxi_pcie_ports) { + pr_err("%s: Memory allocation failed\n", + __func__); + return -ENOMEM; + } + } else /* not suppose to be here + * when we don't have pcie ports */ + return -ENODEV; + } + + port = xaxi_pcie_instantiate_port_info(&config, node); + err = xaxi_pcie_init_port(port); + if (err) { + pr_err("%s: Port Initalization failed\n", __func__); + return err; + } + + return err; +} + +static struct of_device_id xaxi_pcie_match[] = { + { .compatible = "xlnx,axi-pcie-1.05.a" ,}, + {} +}; + +static struct hw_pci xaxi_pcie_hw __initdata = { + .nr_controllers = 1, + .setup = xaxi_pcie_setup, + .scan = xaxi_pcie_scan_bus, + .map_irq = xaxi_pcie_map_irq, +}; + +static int __init xaxi_pcie_init(void) +{ + int err; + int init = 0; + struct device_node *node; + + for_each_matching_node(node, xaxi_pcie_match) { + err = xaxi_pcie_of_probe(node); + if (err) { + pr_err("%s: Root Port Probe failed\n", __func__); + + return err; + } + pr_info("AXI PCIe Root Port Probe Successful\n"); + init++; + } + + if (init) + pci_common_init(&xaxi_pcie_hw); + + return 0; +} + +subsys_initcall(xaxi_pcie_init); Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/xaxipcie-msi.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/xaxipcie-msi.c 2014-07-20 22:06:34.382338279 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PCIe IP hardware MSI initialisation + * + * Copyright (c) 2012 Xilinx, Inc. + * + * This program has adopted some work from PCI/PCIE support for AMCC + * PowerPC boards written by Benjamin Herrenschmidt. + * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/msi.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/module.h> + +#define XILINX_NUM_MSI_IRQS 128 + +static DECLARE_BITMAP(msi_irq_in_use, XILINX_NUM_MSI_IRQS); + +static unsigned long xaxipcie_msg_addr; +static struct irq_domain *xaxipcie_irq_domain; +static int xaxipcie_msi_irq_base; + +/* Dynamic irq allocate and deallocation */ + +/** + * create_irq- Dynamic irq allocate + * void + * + * @return: Interrupt number allocated/ error + * + * @note: None + */ +int create_irq(void) +{ + int irq, pos; +again: + pos = find_first_zero_bit(msi_irq_in_use, XILINX_NUM_MSI_IRQS); + + irq = irq_find_mapping(xaxipcie_irq_domain, pos); + + /* test_and_set_bit operates on 32-bits at a time */ + if (test_and_set_bit(pos, msi_irq_in_use)) + goto again; + + dynamic_irq_init(irq); + set_irq_flags(irq, IRQF_VALID); + + return irq; +} + +/** + * destroy_irq- Dynamic irq de-allocate + * @irq: Interrupt number to de-allocate + * + * @return: None + * + * @note: None + */ +void destroy_irq(unsigned int irq) +{ + int pos = irq - xaxipcie_msi_irq_base; + + dynamic_irq_cleanup(irq); + + clear_bit(pos, msi_irq_in_use); +} + +/** + * arch_teardown_msi_irq-Teardown the Interrupt + * @irq: Interrupt number to teardown + * + * @return: None + * + * @note: This function is called when pci_disable_msi is called + */ +void arch_teardown_msi_irq(unsigned int irq) +{ + destroy_irq(irq); +} + +/** + * xilinx_msi_nop-No operation handler + * @irq: Interrupt number + * + * @return: None + * + * @note: None + */ +static void xilinx_msi_nop(struct irq_data *d) +{ + return; +} + +static struct irq_chip xilinx_msi_chip = { + .name = "PCIe-MSI", + .irq_ack = xilinx_msi_nop, + .irq_enable = unmask_msi_irq, + .irq_disable = mask_msi_irq, + .irq_mask = mask_msi_irq, + .irq_unmask = unmask_msi_irq, +}; + +/** + * arch_setup_msi_irq-Setup MSI interrupt + * @pdev: Pointer to current pci device structure + * @desc: Pointer to MSI description structure + * + * @return: Error/ no-error + * + * @note: This function is called when pci_enable_msi is called + */ +int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) +{ + int irq = create_irq(); + struct msi_msg msg; + + if (irq < 0) + return irq; + + irq_set_msi_desc(irq, desc); + + msg.address_hi = 0x00000000; + msg.address_lo = xaxipcie_msg_addr; + msg.data = irq; + + pr_debug("irq %d addr_hi %08x low %08x data %08x\n", + irq, msg.address_hi, msg.address_lo, msg.data); + + write_msi_msg(irq, &msg); + + irq_set_chip_and_handler(irq, &xilinx_msi_chip, handle_simple_irq); + + return 0; +} + + +/** + * xaxipcie_alloc_msi_irqdescs - allocate msi irq descs + * @node: Pointer to device node structure + * @msg_addr: PCIe MSI message address + * + * @return: Allocated MSI IRQ Base/ error + * + * @note: This function is called when xaxipcie_init_port() is called + */ +int xaxipcie_alloc_msi_irqdescs(struct device_node *node, + unsigned long msg_addr) +{ + /* Store the PCIe MSI message address */ + xaxipcie_msg_addr = msg_addr; + + /* Allocate MSI IRQ descriptors */ + xaxipcie_msi_irq_base = irq_alloc_descs(-1, 0, + XILINX_NUM_MSI_IRQS, 0); + + if (xaxipcie_msi_irq_base < 0) + return -ENODEV; + + /* Register IRQ domain */ + xaxipcie_irq_domain = irq_domain_add_legacy(node, + XILINX_NUM_MSI_IRQS, + xaxipcie_msi_irq_base, + 0, &irq_domain_simple_ops, NULL); + + if (!xaxipcie_irq_domain) + return -ENOMEM; + + return xaxipcie_msi_irq_base; +} +EXPORT_SYMBOL(xaxipcie_alloc_msi_irqdescs); Index: linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/zynq_ocm.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/arm/mach-zynq/zynq_ocm.c 2014-07-20 22:06:34.390338147 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Copyright (C) 2013 Xilinx + * + * Based on "Generic on-chip SRAM allocation driver" + * + * Copyright (C) 2012 Philipp Zabel, Pengutronix + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/genalloc.h> + +#include "common.h" + +#define ZYNQ_OCM_HIGHADDR 0xfffc0000 +#define ZYNQ_OCM_LOWADDR 0x0 +#define ZYNQ_OCM_BLOCK_SIZE 0x10000 +#define ZYNQ_OCM_BLOCKS 4 +#define ZYNQ_OCM_GRANULARITY 32 + +#define ZYNQ_OCM_PARITY_CTRL 0x0 +#define ZYNQ_OCM_PARITY_ENABLE 0x1e + +#define ZYNQ_OCM_PARITY_ERRADDRESS 0x4 + +#define ZYNQ_OCM_IRQ_STS 0x8 +#define ZYNQ_OCM_IRQ_STS_ERR_MASK 0x7 + +struct zynq_ocm_dev { + void __iomem *base; + int irq; + struct gen_pool *pool; + struct resource res[ZYNQ_OCM_BLOCKS]; +}; + +/** + * zynq_ocm_irq_handler - Interrupt service routine of the OCM controller + * @irq: IRQ number + * @data: Pointer to the zynq_ocm_dev structure + * + * returns: IRQ_HANDLED always + */ +static irqreturn_t zynq_ocm_irq_handler(int irq, void *data) +{ + u32 sts; + u32 err_addr; + struct zynq_ocm_dev *zynq_ocm = data; + + /* check status */ + sts = readl(zynq_ocm->base + ZYNQ_OCM_IRQ_STS); + if (sts & ZYNQ_OCM_IRQ_STS_ERR_MASK) { + /* check error address */ + err_addr = readl(zynq_ocm->base + ZYNQ_OCM_PARITY_ERRADDRESS); + pr_err("%s: OCM err intr generated at 0x%04x (stat: 0x%08x).", + __func__, err_addr, sts & ZYNQ_OCM_IRQ_STS_ERR_MASK); + } + pr_warn("%s: Interrupt generated by OCM, but no error is found.", + __func__); + + return IRQ_HANDLED; +} + +/** + * zynq_ocm_probe - Probe method for the OCM driver + * @pdev: Pointer to the platform_device structure + * + * This function initializes the driver data structures and the hardware. + * + * returns: 0 on success and error value on failure + */ +static int zynq_ocm_probe(struct platform_device *pdev) +{ + int ret; + struct zynq_ocm_dev *zynq_ocm; + u32 i, ocm_config, curr; + struct resource *res; + + ocm_config = zynq_slcr_get_ocm_config(); + + zynq_ocm = devm_kzalloc(&pdev->dev, sizeof(*zynq_ocm), GFP_KERNEL); + if (!zynq_ocm) + return -ENOMEM; + + zynq_ocm->pool = devm_gen_pool_create(&pdev->dev, + ilog2(ZYNQ_OCM_GRANULARITY), -1); + if (!zynq_ocm->pool) + return -ENOMEM; + + curr = 0; /* For storing current struct resource for OCM */ + for (i = 0; i < ZYNQ_OCM_BLOCKS; i++) { + u32 base, start, end; + + /* Setup base address for 64kB OCM block */ + if (ocm_config & BIT(i)) + base = ZYNQ_OCM_HIGHADDR; + else + base = ZYNQ_OCM_LOWADDR; + + /* Calculate start and end block addresses */ + start = i * ZYNQ_OCM_BLOCK_SIZE + base; + end = start + (ZYNQ_OCM_BLOCK_SIZE - 1); + + /* Concatenate OCM blocks together to get bigger pool */ + if (i > 0 && start == (zynq_ocm->res[curr - 1].end + 1)) { + zynq_ocm->res[curr - 1].end = end; + } else { +#ifdef CONFIG_SMP + /* + * OCM block if placed at 0x0 has special meaning + * for SMP because jump trampoline is added there. + * Ensure that this address won't be allocated. + */ + if (!base) { + u32 trampoline_code_size = + &zynq_secondary_trampoline_end - + &zynq_secondary_trampoline; + dev_dbg(&pdev->dev, + "Allocate reset vector table %dB\n", + trampoline_code_size); + /* postpone start offset */ + start += trampoline_code_size; + } +#endif + /* First resource is always initialized */ + zynq_ocm->res[curr].start = start; + zynq_ocm->res[curr].end = end; + zynq_ocm->res[curr].flags = IORESOURCE_MEM; + curr++; /* Increment curr value */ + } + dev_dbg(&pdev->dev, "OCM block %d, start %x, end %x\n", + i, start, end); + } + + /* + * Separate pool allocation from OCM block detection to ensure + * the biggest possible pool. + */ + for (i = 0; i < ZYNQ_OCM_BLOCKS; i++) { + unsigned long size; + void __iomem *virt_base; + + /* Skip all zero size resources */ + if (zynq_ocm->res[i].end == 0) + break; + dev_dbg(&pdev->dev, "OCM resources %d, start %x, end %x\n", + i, zynq_ocm->res[i].start, zynq_ocm->res[i].end); + size = resource_size(&zynq_ocm->res[i]); + virt_base = devm_ioremap_resource(&pdev->dev, + &zynq_ocm->res[i]); + if (IS_ERR(virt_base)) + return PTR_ERR(virt_base); + + ret = gen_pool_add_virt(zynq_ocm->pool, + (unsigned long)virt_base, + zynq_ocm->res[i].start, size, -1); + if (ret < 0) { + dev_err(&pdev->dev, "Gen pool failed\n"); + return ret; + } + dev_info(&pdev->dev, "ZYNQ OCM pool: %ld KiB @ 0x%p\n", + size / 1024, virt_base); + } + + /* Get OCM config space */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + zynq_ocm->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(zynq_ocm->base)) + return PTR_ERR(zynq_ocm->base); + + /* Allocate OCM parity IRQ */ + zynq_ocm->irq = platform_get_irq(pdev, 0); + if (zynq_ocm->irq < 0) { + dev_err(&pdev->dev, "irq resource not found\n"); + return zynq_ocm->irq; + } + ret = devm_request_irq(&pdev->dev, zynq_ocm->irq, zynq_ocm_irq_handler, + 0, pdev->name, zynq_ocm); + if (ret != 0) { + dev_err(&pdev->dev, "request_irq failed\n"); + return ret; + } + + /* Enable parity errors */ + writel(ZYNQ_OCM_PARITY_ENABLE, zynq_ocm->base + ZYNQ_OCM_PARITY_CTRL); + + platform_set_drvdata(pdev, zynq_ocm); + + return 0; +} + +/** + * zynq_ocm_remove - Remove method for the OCM driver + * @pdev: Pointer to the platform_device structure + * + * This function is called if a device is physically removed from the system or + * if the driver module is being unloaded. It frees all resources allocated to + * the device. + * + * returns: 0 on success and error value on failure + */ +static int zynq_ocm_remove(struct platform_device *pdev) +{ + struct zynq_ocm_dev *zynq_ocm = platform_get_drvdata(pdev); + + if (gen_pool_avail(zynq_ocm->pool) < gen_pool_size(zynq_ocm->pool)) + dev_dbg(&pdev->dev, "removed while SRAM allocated\n"); + + return 0; +} + +static struct of_device_id zynq_ocm_dt_ids[] = { + { .compatible = "xlnx,zynq-ocm-1.0" }, + { /* end of table */ } +}; + +static struct platform_driver zynq_ocm_driver = { + .driver = { + .name = "zynq_ocm", + .of_match_table = zynq_ocm_dt_ids, + }, + .probe = zynq_ocm_probe, + .remove = zynq_ocm_remove, +}; + +static int __init zynq_ocm_init(void) +{ + return platform_driver_register(&zynq_ocm_driver); +} + +arch_initcall(zynq_ocm_init); Index: linux-3.12.24-rt38-xilinx/arch/arm/mm/mmu.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/arm/mm/mmu.c 2014-07-20 22:05:50.277065944 +0200 +++ linux-3.12.24-rt38-xilinx/arch/arm/mm/mmu.c 2014-07-20 22:06:34.408337850 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:574 @ mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB; break; } - printk("Memory policy: ECC %sabled, Data cache %s\n", - ecc_mask ? "en" : "dis", cp->policy); + pr_info("Memory policy: %sData cache %s\n", + ecc_mask ? "ECC enabled, " : "", cp->policy); for (i = 0; i < ARRAY_SIZE(mem_types); i++) { struct mem_type *t = &mem_types[i]; Index: linux-3.12.24-rt38-xilinx/arch/microblaze/boot/dts/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/boot/dts/Makefile 2014-07-20 22:05:50.320065235 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/boot/dts/Makefile 2014-07-20 22:06:34.427337536 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ # -# arch/microblaze/boot/Makefile -# obj-y += linked_dtb.o Index: linux-3.12.24-rt38-xilinx/arch/microblaze/include/asm/io.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/include/asm/io.h 2014-07-20 22:05:50.323065185 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/include/asm/io.h 2014-07-20 22:06:34.445337239 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:345 @ #define iowrite32_rep(p, src, count) \ outsl((unsigned long) (p), (src), (count)) +#define readb_relaxed readb +#define readw_relaxed readw +#define readl_relaxed readl + +#define writeb_relaxed writeb +#define writew_relaxed writew +#define writel_relaxed writel + #endif /* _ASM_MICROBLAZE_IO_H */ Index: linux-3.12.24-rt38-xilinx/arch/microblaze/include/asm/irq.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/include/asm/irq.h 2014-07-20 22:05:50.322065202 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/include/asm/irq.h 2014-07-20 22:06:34.455337075 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:12 @ #ifndef _ASM_MICROBLAZE_IRQ_H #define _ASM_MICROBLAZE_IRQ_H -#define NR_IRQS (32 + 1) +/* + * Linux IRQ# is currently offset by one to map to the hardware + * irq number. So hardware IRQ0 maps to Linux irq 1. + */ +#define NO_IRQ_OFFSET 1 +#define IRQ_OFFSET NO_IRQ_OFFSET +/* AXI PCIe MSI support */ +#if defined(CONFIG_XILINX_AXIPCIE) && defined(CONFIG_PCI_MSI) +#define IRQ_XILINX_MSI_0 128 +#define XILINX_NUM_MSI_IRQS 32 +#define NR_IRQS (32 + IRQ_XILINX_MSI_0 + IRQ_OFFSET) +#else +#define NR_IRQS (32 + IRQ_OFFSET) +#endif + #include <asm-generic/irq.h> struct pt_regs; Index: linux-3.12.24-rt38-xilinx/arch/microblaze/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/Kconfig 2014-07-20 22:05:50.312065367 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/Kconfig 2014-07-20 22:06:34.466336893 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:32 @ select MODULES_USE_ELF_RELA select CLONE_BACKWARDS3 select CLKSRC_OF + select BUILDTIME_EXTABLE_SORT config SWAP def_bool n @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:86 @ bool "MMU support" default n -config NO_MMU - bool - depends on !MMU - default y - comment "Boot options" config CMDLINE_BOOL @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:249 @ endchoice -config KERNEL_PAD - hex "Kernel PAD for unpacking" if ADVANCED_OPTIONS - default "0x80000" if MMU - endmenu source "mm/Kconfig" @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:274 @ bool "Xilinx PCI host bridge support" depends on PCI +config XILINX_AXIPCIE + bool "Xilinx AXI PCIe host bridge support" + depends on PCI + select ARCH_SUPPORTS_MSI + source "drivers/pci/Kconfig" endmenu Index: linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/cpu/cpuinfo.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/kernel/cpu/cpuinfo.c 2014-07-20 22:05:50.316065301 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/cpu/cpuinfo.c 2014-07-20 22:06:34.483336613 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:42 @ {"8.30.a", 0x17}, {"8.40.a", 0x18}, {"8.40.b", 0x19}, + {"8.50.a", 0x1a}, {"9.0", 0x1b}, {"9.1", 0x1d}, {NULL, 0}, Index: linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/head.S =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/kernel/head.S 2014-07-20 22:05:50.319065251 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/head.S 2014-07-20 22:06:34.494336431 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:67 @ #endif mts rmsr, r0 +/* Disable stack protection from bootloader */ + mts rslr, r0 + addi r8, r0, 0xFFFFFFF + mts rshr, r8 /* * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc' * if the msrclr instruction is not enabled. We use this to detect @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:183 @ /* start to do TLB calculation */ addik r12, r0, _end rsub r12, r3, r12 - addik r12, r12, CONFIG_KERNEL_PAD /* that's the pad */ + addik r12, r12, CONFIG_LOWMEM_SIZE >> PTE_SHIFT /* that's the pad */ or r9, r0, r0 /* TLB0 = 0 */ or r10, r0, r0 /* TLB1 = 0 */ Index: linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/hw_exception_handler.S =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/kernel/hw_exception_handler.S 2014-07-20 22:05:50.318065268 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/hw_exception_handler.S 2014-07-20 22:06:34.634334122 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:150 @ or r3, r0, NUM_TO_REG (regnum); /* Shift right instruction depending on available configuration */ - #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0 - #define BSRLI(rD, rA, imm) \ - bsrli rD, rA, imm - #else - #define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA) + #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL == 0 /* Only the used shift constants defined here - add more if needed */ #define BSRLI2(rD, rA) \ srl rD, rA; /* << 1 */ \ srl rD, rD; /* << 2 */ + #define BSRLI4(rD, rA) \ + BSRLI2(rD, rA); \ + BSRLI2(rD, rD) #define BSRLI10(rD, rA) \ srl rD, rA; /* << 1 */ \ srl rD, rD; /* << 2 */ \ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:172 @ #define BSRLI20(rD, rA) \ BSRLI10(rD, rA); \ BSRLI10(rD, rD) + + .macro bsrli, rD, rA, IMM + .if (\IMM) == 2 + BSRLI2(\rD, \rA) + .elseif (\IMM) == 10 + BSRLI10(\rD, \rA) + .elseif (\IMM) == 12 + BSRLI2(\rD, \rA) + BSRLI10(\rD, \rD) + .elseif (\IMM) == 14 + BSRLI4(\rD, \rA) + BSRLI10(\rD, \rD) + .elseif (\IMM) == 20 + BSRLI20(\rD, \rA) + .elseif (\IMM) == 24 + BSRLI4(\rD, \rA) + BSRLI20(\rD, \rD) + .elseif (\IMM) == 28 + BSRLI4(\rD, \rA) + BSRLI4(\rD, \rD) + BSRLI20(\rD, \rD) + .else + .error "BSRLI shift macros \IMM" + .endif + .endm #endif + #endif /* CONFIG_MMU */ .extern other_exception_handler /* Defined in exception.c */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:221 @ * - W S REG EXC * * - * STACK FRAME STRUCTURE (for NO_MMU) - * --------------------------------- + * STACK FRAME STRUCTURE (for CONFIG_MMU=n) + * ---------------------------------------- * * +-------------+ + 0 * | MSR | @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:632 @ ex4: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:641 @ beqi r5, ex2 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:733 @ ex6: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:742 @ beqi r5, ex7 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:804 @ ex9: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:813 @ beqi r5, ex10 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:950 @ .ent _unaligned_data_exception _unaligned_data_exception: andi r8, r3, 0x3E0; /* Mask and extract the register operand */ - BSRLI(r8,r8,2); /* r8 >> 2 = register operand * 8 */ + bsrli r8, r8, 2; /* r8 >> 2 = register operand * 8 */ andi r6, r3, 0x400; /* Extract ESR[S] */ bneid r6, ex_sw_vm; andi r6, r3, 0x800; /* Extract ESR[W] - delay slot */ Index: linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/setup.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/kernel/setup.c 2014-07-20 22:05:50.314065334 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/setup.c 2014-07-20 22:06:34.645333941 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:177 @ #else if (!msr) { pr_info("!!!Your kernel not setup MSR instruction but "); - pr_cont"CPU have it %x\n", msr); + pr_cont("CPU have it %x\n", msr); } #endif Index: linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/syscall_table.S =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/kernel/syscall_table.S 2014-07-20 22:05:50.317065284 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/syscall_table.S 2014-07-20 22:06:34.656333759 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:195 @ .long sys_ni_syscall /* reserved for streams2 */ .long sys_vfork /* 190 */ .long sys_getrlimit - .long sys_mmap_pgoff /* mmap2 */ + .long sys_mmap2 .long sys_truncate64 .long sys_ftruncate64 .long sys_stat64 /* 195 */ Index: linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/sys_microblaze.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/kernel/sys_microblaze.c 2014-07-20 22:05:50.313065351 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/sys_microblaze.c 2014-07-20 22:06:34.665333611 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:36 @ #include <linux/slab.h> #include <asm/syscalls.h> -asmlinkage long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t pgoff) +SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, unsigned long, fd, + off_t, pgoff) { if (pgoff & ~PAGE_MASK) return -EINVAL; return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); } + +SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, unsigned long, fd, + unsigned long, pgoff) +{ + if (pgoff & (~PAGE_MASK >> 12)) + return -EINVAL; + + return sys_mmap_pgoff(addr, len, prot, flags, fd, + pgoff >> (PAGE_SHIFT - 12)); +} Index: linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/timer.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/kernel/timer.c 2014-07-20 22:05:50.315065317 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/kernel/timer.c 2014-07-20 22:06:34.676333429 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:151 @ static struct irqaction timer_irqaction = { .handler = timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .name = "timer", .dev_id = &clockevent_xilinx_timer, }; Index: linux-3.12.24-rt38-xilinx/arch/microblaze/pci/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/pci/Makefile 2014-07-20 22:05:50.310065400 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/pci/Makefile 2014-07-20 22:06:34.689333215 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:7 @ obj-$(CONFIG_PCI) += pci-common.o indirect_pci.o iomap.o obj-$(CONFIG_PCI_XILINX) += xilinx_pci.o +obj-$(CONFIG_XILINX_AXIPCIE) += xilinx_axipcie.o +obj-$(CONFIG_PCI_MSI) += msi.o Index: linux-3.12.24-rt38-xilinx/arch/microblaze/pci/msi.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/pci/msi.c 2014-07-20 22:06:34.697333083 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PCIe IP hardware MSI initialisation + * + * Copyright (c) 2010-2011 Xilinx, Inc. + * + * This program has adopted some work from PCI/PCIE support for AMCC + * PowerPC boards written by Benjamin Herrenschmidt. + * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/pci.h> +#include <linux/msi.h> +#include <asm/irq.h> +#include "xilinx_axipcie.h" + +static DECLARE_BITMAP(msi_irq_in_use, XILINX_NUM_MSI_IRQS); + +/* + * Dynamic irq allocate and deallocation + */ + +/** +* create_irq- Dynamic irq allocate +* void +* +* @return: Interrupt number allocated/ error +* +* @note: None +*/ +int create_irq(void) +{ + int irq, pos; +again: + pos = find_first_zero_bit(msi_irq_in_use, XILINX_NUM_MSI_IRQS); + + irq = IRQ_XILINX_MSI_0 + pos; + if (irq > NR_IRQS) + return -ENOSPC; + + /* test_and_set_bit operates on 32-bits at a time */ + if (test_and_set_bit(pos, msi_irq_in_use)) + goto again; + + dynamic_irq_init(irq); + + return irq; +} + +/** +* destroy_irq- Dynamic irq de-allocate +* @irq: Interrupt number to de-allocate +* +* @return: None +* +* @note: None +*/ +void destroy_irq(unsigned int irq) +{ + int pos = irq - IRQ_XILINX_MSI_0; + + dynamic_irq_cleanup(irq); + + clear_bit(pos, msi_irq_in_use); +} + +/** +* arch_teardown_msi_irq-Teardown the Interrupt +* @irq: Interrupt number to teardown +* +* @return: None +* +* @note: This function is called when pci_disable_msi is called +*/ +void arch_teardown_msi_irq(unsigned int irq) +{ + destroy_irq(irq); +} + +/** +* xilinx_msi_nop-No operation handler +* @irq: Interrupt number +* +* @return: None +* +* @note: None +*/ +static void xilinx_msi_nop(struct irq_data *d) +{ + return; +} + +static struct irq_chip xilinx_msi_chip = { + .name = "PCI-MSI", + .irq_ack = xilinx_msi_nop, + .irq_enable = unmask_msi_irq, + .irq_disable = mask_msi_irq, + .irq_mask = mask_msi_irq, + .irq_unmask = unmask_msi_irq, +}; + +/** +* arch_setup_msi_irq-Setup MSI interrupt +* @pdev: Pointer to current pci device structure +* @desc: Pointer to MSI description structure +* +* @return: Error/ no-error +* +* @note: This function is called when pci_enable_msi is called +*/ + +int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) +{ + int irq = create_irq(); + struct msi_msg msg; + + if (irq < 0) + return irq; + + irq_set_msi_desc(irq, desc); + + msg.address_hi = 0x00000000; + msg.address_lo = msg_addr; + msg.data = irq; + + DBG("irq %d addr_hi %08x low %08x data %08x\n", + irq, msg.address_hi, msg.address_lo, msg.data); + + write_msi_msg(irq, &msg); + + irq_set_chip_and_handler(irq, &xilinx_msi_chip, handle_simple_irq); + + return 0; +} Index: linux-3.12.24-rt38-xilinx/arch/microblaze/pci/pci-common.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/microblaze/pci/pci-common.c 2014-07-20 22:05:50.311065383 +0200 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/pci/pci-common.c 2014-07-20 22:06:34.712332835 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:190 @ return device_create_file(&pdev->dev, &dev_attr_devspec); } -void pcibios_set_master(struct pci_dev *dev) +void __weak pcibios_set_master(struct pci_dev *dev) { /* No special bus mastering setup handling */ } Index: linux-3.12.24-rt38-xilinx/arch/microblaze/pci/xilinx_axipcie.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/pci/xilinx_axipcie.c 2014-07-20 22:06:34.726332604 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx AXI PCIe IP hardware initialation, setup and + * configuration spaces access file. + * + * Copyright (c) 2010-2011 Xilinx, Inc. + * + * This program has adopted some work from PCI/PCIE support for AMCC + * PowerPC boards written by Benjamin Herrenschmidt. + * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/of_address.h> +#include <linux/of.h> +#include <linux/bootmem.h> +#include <linux/delay.h> +#include <linux/compiler.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <asm/pci-bridge.h> +#include <linux/interrupt.h> +#include "xilinx_axipcie.h" + +static struct xilinx_axipcie_port *xilinx_axipcie_ports; +static unsigned int xilinx_axipcie_port_count; + +static const struct of_device_id xilinx_axipcie_match[] = { + { .compatible = "xlnx,axi-pcie-1.05.a" ,}, + {} +}; + +static int last_bus_on_record; + +#ifdef CONFIG_PCI_MSI +unsigned long msg_addr; +#endif + +/* Macros */ +#define is_link_up(base_address) \ + ((in_le32(((u8 *)base_address) + AXIPCIE_REG_PSCR) & \ + AXIPCIE_REG_PSCR_LNKUP) ? 1 : 0) + +#define bridge_enable(base_address) \ + out_le32((((u8 *)base_address) + AXIPCIE_REG_RPSC), \ + (in_le32(((u8 *)base_address) + AXIPCIE_REG_RPSC) | \ + AXIPCIE_REG_RPSC_BEN)) + +/** + * xilinx_get_axipcie_ip_config_info - Read info from device tree + * @dev: A pointer to device node to read from + * @ip_config_info: A pointer to xilinx_pcie_node struct to write device tree + * info into to. + * + * @return: Error / no error + * + * @note: Read related info from device tree + */ +int xilinx_get_axipcie_ip_config_info(struct device_node *dev, + struct xilinx_axipcie_node *ip_config_info) +{ + u32 *ip_setup_parameter; + u32 rlen; + + ip_config_info->number_of_instances = 1; + + ip_setup_parameter = (u32 *) of_get_property(dev, + "xlnx,device-num", &rlen); + ip_config_info->device_id = 0; + + ip_setup_parameter = (u32 *) of_get_property(dev, + "xlnx,include-rc", &rlen); + + if (ip_setup_parameter) + ip_config_info->device_type = be32_to_cpup(ip_setup_parameter); + else + return -ENODEV; + + ip_setup_parameter = (u32 *) of_get_property(dev, + "reg", &rlen); + + if (ip_setup_parameter) { + ip_config_info->reg_base = + be32_to_cpup(ip_setup_parameter); + ip_config_info->reg_len = + be32_to_cpup(ip_setup_parameter + 1); + } else + return -ENODEV; + + ip_setup_parameter = (u32 *) of_get_property(dev, + "xlnx,pciebar-num", &rlen); + + if (ip_setup_parameter) + ip_config_info->bars_num = be32_to_cpup(ip_setup_parameter); + else + return -ENODEV; + + ip_config_info->irq_num = irq_of_parse_and_map(dev, 0); + + /* Get address translation parameters */ + ip_setup_parameter = (u32 *) of_get_property(dev, + "xlnx,pciebar2axibar-0", &rlen); + + if (ip_setup_parameter) + ip_config_info->pcie2axibar_0 = + be32_to_cpup(ip_setup_parameter); + else + return -ENODEV; + + ip_setup_parameter = (u32 *) of_get_property(dev, + "xlnx,pciebar2axibar-1", &rlen); + + if (ip_setup_parameter) + ip_config_info->pcie2axibar_1 = + be32_to_cpup(ip_setup_parameter); + else + ip_config_info->pcie2axibar_1 = 0x0; + + return 0; +} + +/** + * fixup_xilinx_axipcie_bridge + * @dev: A pointer to device pcie device struct + * + * @return: None + * + * @note: A fix up routine to be called by kernel during enumeration + */ +static void fixup_xilinx_axipcie_bridge(struct pci_dev *dev) +{ + struct pci_controller *hose; + int i; + + if (dev->devfn != 0 || dev->bus->self != NULL) + return; + + hose = pci_bus_to_host(dev->bus); + if (hose == NULL) + return; + + if (!of_match_node(xilinx_axipcie_match, hose->dn)) + return; + + /* Hide the PCI host BARs from the kernel as their content doesn't + * fit well in the resource management + */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + dev->resource[i].start = dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_xilinx_axipcie_bridge); + +/** + * xilinx_init_axipcie_port - Initialize hardware + * @port: A pointer to a pcie port that needs to be initialized + * + * @return: Error / no error + * + * @note: None + */ +static int xilinx_init_axipcie_port(struct xilinx_axipcie_port *port) +{ + void __iomem *base_addr_remap = NULL; + + /* base_addr_remap = ioremap(port->reg_base, PORT_REG_SIZE); */ + base_addr_remap = ioremap(port->reg_base, port->reg_len); + if (!base_addr_remap) + return -ENOMEM; + + port->base_addr_remap = base_addr_remap; + + /* make sure it is root port before touching header */ + if (port->type) { + + port->header_remap = base_addr_remap; + out_le32((((u8 *)port->base_addr_remap) + PCIE_CFG_CMD), + BUS_MASTER_ENABLE); + } + +#ifdef CONFIG_PCI_MSI + msg_addr = port->reg_base & ~0xFFF; /* 4KB aligned */ + out_le32((((u8 *)port->base_addr_remap) + AXIPCIE_REG_MSIBASE1), + 0x00000000); + out_le32((((u8 *)port->base_addr_remap) + AXIPCIE_REG_MSIBASE2), + msg_addr); +#endif + + port->link = is_link_up(port->base_addr_remap); + if (!port->link) + pr_info("LINK IS DOWN\n"); + else + pr_info("LINK IS UP\n"); + + /* Disable all interrupts*/ + out_le32((((u8 *)port->base_addr_remap) + AXIPCIE_REG_IMR), + ~AXIPCIE_REG_IDR_MASKALL); + /* Clear pending interrupts*/ + out_le32((((u8 *)port->base_addr_remap) + AXIPCIE_REG_IDR), + in_le32(((u8 *)port->base_addr_remap) + AXIPCIE_REG_IDR) & + AXIPCIE_REG_IMR_MASKALL); + /* Enable all interrupts*/ + out_le32((((u8 *)port->base_addr_remap) + AXIPCIE_REG_IMR), + AXIPCIE_REG_IMR_MASKALL); + + /* Bridge enable must be done after enumeration, + but there is no callback defined */ + bridge_enable(port->base_addr_remap); + + return 0; +} + +/** + * xilinx_axipcie_verify_config + * @port: A pointer to a pcie port that needs to be handled + * @bus: Bus structure of current bus + * @devfun: device/function + * + * @return: Error / no error + * + * @note: Make sure we can handle this configuration call on our + * device. + */ +static int xilinx_axipcie_verify_config(struct xilinx_axipcie_port *port, + struct pci_bus *bus, + unsigned int devfn) +{ + static int message; + + /* Endpoint can not generate upstream(remote) config cycles */ + if ((!port->type) && bus->number != port->hose->first_busno) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Check we are within the mapped range */ + if (bus->number > port->hose->last_busno) { + if (!message) { + printk(KERN_WARNING "Warning! Probing bus %u" + " out of range !\n", bus->number); + message++; + } + return PCIBIOS_DEVICE_NOT_FOUND; + } + + /* The other side of the RC has only one device as well */ + if (bus->number == (port->hose->first_busno + 1) && + PCI_SLOT(devfn) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Check if we have a link */ + if (!port->link) + port->link = is_link_up(port->base_addr_remap); + + if ((bus->number != port->hose->first_busno) && !port->link) + return PCIBIOS_DEVICE_NOT_FOUND; + + return 0; +} + +/** + * xilinx_axipcie_get_config_base + * @port: A pointer to a pcie port that needs to be handled + * @bus: Bus structure of current bus + * @devfun: Device/function + * + * @return: Base address of the configuration space needed to be + * accessed. + * + * @note: Get the base address of the configuration space for this + * pcie device. + */ +static void __iomem *xilinx_axipcie_get_config_base( + struct xilinx_axipcie_port *port, + struct pci_bus *bus, + unsigned int devfn) +{ + int relbus; + + relbus = ((bus->number << BUS_LOC_SHIFT) | (devfn << DEV_LOC_SHIFT)); + + if (relbus == 0) + return (void __iomem *)port->header_remap; + + return (void __iomem *)port->hose->cfg_data + relbus; +} + +/** + * xilinx_axipcie_read_config - Read config reg. + * @port: A pointer to a pcie port that needs to be handled + * @bus: Bus structure of current bus + * @devfun: Device/function + * @offset: Offset from base + * @len: Byte/word/dword + * @val: A pointer to value read + * + * @return: Error / no error + * + * + * @note: Read byte/word/dword from pcie device config reg. + */ +static int xilinx_axipcie_read_config(struct pci_bus *bus, + unsigned int devfn, + int offset, + int len, + u32 *val) +{ + struct pci_controller *hose = (struct pci_controller *) bus->sysdata; + struct xilinx_axipcie_port *port = + &xilinx_axipcie_ports[hose->indirect_type]; + void __iomem *addr; + + if (xilinx_axipcie_verify_config(port, bus, devfn) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr = xilinx_axipcie_get_config_base(port, bus, devfn); + + if ((bus->number == 0) && devfn > 0) { + *val = 0xFFFFFFFF; + return PCIBIOS_SUCCESSFUL; + } + + switch (len) { + case 1: + *val = in_8((u8 *)(addr + offset)); + break; + case 2: + *val = in_le16((u16 *)(addr + offset)); + break; + default: + *val = in_le32((u32 *)(addr + offset)); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +/** + * xilinx_axipcie_write_config - Write config reg. + * @port: A pointer to a pcie port that needs to be handled + * @bus: Bus structure of current bus + * @devfun: Device/function + * @offset: Offset from base + * @len: Byte/word/dword + * @val: Value to be written to device + * + * @return: Error / no error + * + * + * @note: Write byte/word/dword to pcie device config reg. + */ +static int xilinx_axipcie_write_config(struct pci_bus *bus, + unsigned int devfn, + int offset, + int len, + u32 val) +{ + struct pci_controller *hose = (struct pci_controller *) bus->sysdata; + struct xilinx_axipcie_port *port = + &xilinx_axipcie_ports[hose->indirect_type]; + void __iomem *addr; + + if (xilinx_axipcie_verify_config(port, bus, devfn) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr = xilinx_axipcie_get_config_base(port, bus, devfn); + + if ((bus->number == 0) && devfn > 0) + return PCIBIOS_SUCCESSFUL; + + switch (len) { + case 1: + out_8((u8 *)(addr + offset), val); + break; + case 2: + out_le16((u16 *)(addr + offset), val); + break; + default: + out_le32((u32 *)(addr + offset), val); + break; + } + + wmb(); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops xlnx_pcie_pci_ops = { + .read = xilinx_axipcie_read_config, + .write = xilinx_axipcie_write_config, +}; + +/** + * xilinx_set_bridge_resource - Setup base & limit registers of config space. + * @port: Pointer to a root port + * + * @return: None + * + * @note: None + */ +void xilinx_set_bridge_resource(struct xilinx_axipcie_port *port) +{ + const u32 *ranges; + int rlen; + /* The address cells of PCIe parent node */ + int pna = of_n_addr_cells(port->node); + int np = pna + 5; + u32 pci_space; + unsigned long long pci_addr, size; + struct device_node *dev; + u32 val = 0; + + dev = port->node; + + /* Get ranges property */ + ranges = of_get_property(dev, "ranges", &rlen); + if (ranges == NULL) { + printk(KERN_DEBUG "%s:Didnot get any ranges property\n", + __func__); + return; + } + + while ((rlen -= np * 4) >= 0) { + pci_space = be32_to_cpup(ranges); + pci_addr = of_read_number(ranges + 1, 2); + size = of_read_number(ranges + pna + 3, 2); + + printk(KERN_INFO "%s:pci_space: 0x%08x pci_addr:0x%016llx size:" + "0x%016llx\n", __func__, pci_space, pci_addr, size); + + ranges += np; + + switch ((pci_space >> 24) & 0x3) { + case 1: /* PCI IO space */ + printk(KERN_INFO "%s:Setting resource in IO Space\n", + __func__); + + val = ((pci_addr >> 8) & 0x000000F0) | + ((pci_addr + size - 1) & 0x0000F000); + + out_le32((((u8 *)port->header_remap) + PCIE_CFG_IO), + val); + + val = ((pci_addr >> 16) & 0x0000FFFF) | + ((pci_addr + size - 1) & 0xFFFF0000); + + out_le32((((u8 *)port->header_remap) + + PCIE_CFG_IO_UPPER), val); + + break; + case 2: /* PCI Memory space */ + printk(KERN_INFO "%s:Setting resource in Memory Space\n", + __func__); + val = ((pci_addr >> 16) & 0xfff0) | + ((pci_addr + size - 1) & 0xfff00000); + + /* out_le32((((u8 *)port->header_remap) + PCIE_CFG_MEM), + val); */ + + break; + case 3: /* PCI 64 bits Memory space */ + printk(KERN_INFO "%s:Setting resource in Prefetchable" + " Memory Space\n", __func__); + + val = ((pci_addr >> 16) & 0xfff0) | + ((pci_addr + size - 1) & 0xfff00000); + + out_le32((((u8 *)port->header_remap) + + PCIE_CFG_PREF_MEM), val); + + val = ((pci_addr >> 32) & 0xffffffff); + out_le32((((u8 *)port->header_remap) + + PCIE_CFG_PREF_BASE_UPPER), val); + + val = (((pci_addr + size - 1) >> 32) & 0xffffffff); + out_le32((((u8 *)port->header_remap) + + PCIE_CFG_PREF_LIMIT_UPPER), val); + + break; + } + } + + /* EP initiated memory access */ + out_le32((((u8 *)port->header_remap) + PCIE_CFG_AD1), + port->pcie2axibar_0); + out_le32((((u8 *)port->header_remap) + PCIE_CFG_AD2), + port->pcie2axibar_1); +} + +/** + * xilinx_setup_axipcie_root_port - Setup root port + * @port: Pointer to a root port + * + * @return: Error / no error + * + * @note: This is a root port so set it up accordingly + */ +static int __init xilinx_setup_axipcie_root_port( + struct xilinx_axipcie_port *port) +{ + struct pci_controller *hose = NULL; + u32 val = 0; + + /* Allocate the host controller data structure */ + hose = pcibios_alloc_controller(port->node); + if (!hose) { + iounmap(port->base_addr_remap); + iounmap(port->header_remap); + return -ENOMEM; + } + + hose->indirect_type = port->index; + + /* Get bus range */ + hose->first_busno = last_bus_on_record; + + val = in_le32(((u8 *)port->header_remap) + AXIPCIE_REG_BIR); + val = (val >> 16) & 0x7; + hose->last_busno = (((port->reg_base - port->reg_len - 1) >> 20) + & 0xFF) & val; + + /* Write primary, secondary and subordinate bus numbers */ + val = hose->first_busno; + val |= ((hose->first_busno + 1) << 8); + val |= (hose->last_busno << 16); + + out_le32((((u8 *)port->header_remap) + PCIE_CFG_BUS), val); + last_bus_on_record = hose->last_busno + 1; + + port->ecam_remap = port->header_remap; + + /* Setup config space */ + hose->cfg_addr = port->header_remap; + hose->cfg_data = port->ecam_remap; + hose->ops = &xlnx_pcie_pci_ops; + port->hose = hose; + + xilinx_set_bridge_resource(port); + /* Parse outbound mapping resources */ + pci_process_bridge_OF_ranges(hose, port->node, PRIMARY_BUS); + + return 0; +} + +/** + * Interrupt handler + */ +static irqreturn_t xilinx_axipcie_intr_handler(int irq, void *data) +{ + struct xilinx_axipcie_port *port = (struct xilinx_axipcie_port *)data; + u32 val = 0, mask = 0; + u32 status; + u32 msi_addr = 0; + u32 msi_data = 0; + + /* Read interrupt decode and mask registers */ + val = in_le32(((u8 *)port->header_remap) + AXIPCIE_REG_IDR); + mask = in_le32(((u8 *)port->header_remap) + AXIPCIE_REG_IMR); + + status = val & mask; + if (!status) + return IRQ_NONE; + + if (status & AXIPCIE_INTR_LINK_DOWN) + printk(KERN_ERR "Link Down\n"); + + if (status & AXIPCIE_INTR_ECRC_ERR) + printk(KERN_WARNING "ECRC failed\n"); + + if (status & AXIPCIE_INTR_STR_ERR) + printk(KERN_WARNING "Streaming error\n"); + + if (status & AXIPCIE_INTR_HOT_RESET) + printk(KERN_INFO "Hot reset\n"); + + if (status & AXIPCIE_INTR_CFG_TIMEOUT) + printk(KERN_WARNING "ECAM access timeout\n"); + + if (status & AXIPCIE_INTR_CORRECTABLE) { + printk(KERN_WARNING "Correctable error message\n"); + val = in_le32(((u8 *)port->header_remap) + + AXIPCIE_REG_RPEFR); + if (val & (1 << 18)) { + out_le32((((u8 *)port->base_addr_remap) + + AXIPCIE_REG_RPEFR), 0xFFFFFFFF); + DBG("Requester ID %d\n", (val & 0xffff)); + } + } + + if (status & AXIPCIE_INTR_NONFATAL) { + printk(KERN_WARNING "Non fatal error message\n"); + val = in_le32(((u8 *)port->header_remap) + + AXIPCIE_REG_RPEFR); + if (val & (1 << 18)) { + out_le32((((u8 *)port->base_addr_remap) + + AXIPCIE_REG_RPEFR), 0xFFFFFFFF); + DBG("Requester ID %d\n", (val & 0xffff)); + } + } + + if (status & AXIPCIE_INTR_FATAL) { + printk(KERN_WARNING "Fatal error message\n"); + val = in_le32(((u8 *)port->header_remap) + + AXIPCIE_REG_RPEFR); + if (val & (1 << 18)) { + out_le32((((u8 *)port->base_addr_remap) + + AXIPCIE_REG_RPEFR), 0xFFFFFFFF); + DBG("Requester ID %d\n", (val & 0xffff)); + } + } + + if (status & AXIPCIE_INTR_INTX) { + /* INTx interrupt received */ + val = in_le32(((u8 *)port->header_remap) + AXIPCIE_REG_RPIFR1); + + /* Check whether interrupt valid */ + if (!(val & (1 << 31))) { + printk(KERN_WARNING "RP Intr FIFO1 read error\n"); + return IRQ_HANDLED; + } + + /* Check MSI or INTX */ + if (!(val & (1 << 30))) { + if (val & (1 << 29)) + DBG("INTx assert\n"); + else + DBG("INTx deassert\n"); + } + + /* Clear interrupt FIFO register 1 */ + out_le32((((u8 *)port->base_addr_remap) + AXIPCIE_REG_RPIFR1), + 0xFFFFFFFF); + } + + if (status & AXIPCIE_INTR_MSI) { + /* MSI Interrupt */ + val = in_le32(((u8 *)port->header_remap) + AXIPCIE_REG_RPIFR1); + + if (!(val & (1 << 31))) { + printk(KERN_WARNING "RP Intr FIFO1 read error\n"); + return IRQ_HANDLED; + } + + if (val & (1 << 30)) { + msi_addr = (val >> 16) & 0x7FF; + msi_data = in_le32(((u8 *)port->header_remap) + + AXIPCIE_REG_RPIFR2) & 0xFFFF; + DBG("%s: msi_addr %08x msi_data %08x\n", + __func__, msi_addr, msi_data); + } + + /* Clear interrupt FIFO register 1 */ + out_le32((((u8 *)port->base_addr_remap) + AXIPCIE_REG_RPIFR1), + 0xFFFFFFFF); +#ifdef CONFIG_PCI_MSI + /* Handle MSI Interrupt */ + if (msi_data >= IRQ_XILINX_MSI_0) + generic_handle_irq(msi_data); +#endif + } + + if (status & AXIPCIE_INTR_SLV_UNSUPP) + printk(KERN_WARNING "Slave unsupported request\n"); + + if (status & AXIPCIE_INTR_SLV_UNEXP) + printk(KERN_WARNING "Slave unexpected completion\n"); + + if (status & AXIPCIE_INTR_SLV_COMPL) + printk(KERN_WARNING "Slave completion timeout\n"); + + if (status & AXIPCIE_INTR_SLV_ERRP) + printk(KERN_WARNING "Slave Error Poison\n"); + + if (status & AXIPCIE_INTR_SLV_CMPABT) + printk(KERN_WARNING "Slave Completer Abort\n"); + + if (status & AXIPCIE_INTR_SLV_ILLBUR) + printk(KERN_WARNING "Slave Illegal Burst\n"); + + if (status & AXIPCIE_INTR_MST_DECERR) + printk(KERN_WARNING "Master decode error\n"); + + if (status & AXIPCIE_INTR_MST_SLVERR) + printk(KERN_WARNING "Master slave error\n"); + + if (status & AXIPCIE_INTR_MST_ERRP) + printk(KERN_WARNING "Master error poison\n"); + + /* Clear the Interrupt Decode register */ + out_le32((((u8 *)port->base_addr_remap) + AXIPCIE_REG_IDR), status); + + return IRQ_HANDLED; +} + +/** + * xilinx_probe_axipcie_node + * @np: Pointer to device node to be probed + * + * @return: Error / no error + * + * @note: Find out how this pcie node is configured + */ +static int __init xilinx_probe_axipcie_node(struct device_node *np) +{ + struct xilinx_axipcie_port *port; + struct xilinx_axipcie_node ip_setup_info; + int portno; + int error; + int ret; + + printk(KERN_INFO "Probing Xilinx PCI Express root complex device\n"); + + error = xilinx_get_axipcie_ip_config_info(np , &ip_setup_info); + + if (error) { + printk(KERN_INFO "Error while getting pcie config info\n"); + return error; + } + + if (!xilinx_axipcie_port_count) { + xilinx_axipcie_port_count = ip_setup_info.number_of_instances; + + if (xilinx_axipcie_port_count) { + + xilinx_axipcie_ports = + kzalloc(xilinx_axipcie_port_count * + sizeof(struct xilinx_axipcie_port), GFP_KERNEL); + + if (!xilinx_axipcie_ports) { + printk(KERN_INFO "Memory allocation failed\n"); + return -ENOMEM; + } + } else /* not suppose to be here + * when we don't have pcie ports */ + return -ENODEV; + } + + /* Initialize this port vital info. struct */ + portno = ip_setup_info.device_id; + + port = &xilinx_axipcie_ports[portno]; + port->node = of_node_get(np); + port->index = portno; + port->type = ip_setup_info.device_type; + port->reg_base = ip_setup_info.reg_base; + port->reg_len = ip_setup_info.reg_len; + port->bars_num = ip_setup_info.bars_num; + port->irq_num = ip_setup_info.irq_num; + port->header_addr = port->reg_base + AXIPCIE_LOCAL_CNFG_BASE; + port->pcie2axibar_0 = ip_setup_info.pcie2axibar_0; + port->pcie2axibar_1 = ip_setup_info.pcie2axibar_1; + + irq_set_chip_data(port->irq_num, port); + + /* initialize hardware */ + error = xilinx_init_axipcie_port(port); + if (error) { + printk(KERN_INFO "Error while initialize pcie port\n"); + return error; + } + + /* Register interrupt handler */ + ret = request_irq(port->irq_num, xilinx_axipcie_intr_handler, + IRQF_SHARED, "xaxipcie", port); + if (ret) { + printk(KERN_ERR "%s: Could not allocate interrupt\n", __func__); + return ret; + } + + /* Setup hose data structure */ + if (port->type) { + error = xilinx_setup_axipcie_root_port(port); + if (error) { + printk(KERN_INFO "Error while initialize " + "pcie root port\n"); + return error; + } + } + + return 0; +} + +/** + * pcibios_set_master - Architecture specific function + * @dev: A pointer to device pcie device struct + * + * @return: Error / no error + * @note: Enables Bridge Enable bit during the rescan process + */ +void pcibios_set_master(struct pci_dev *dev) +{ + struct pci_controller *hose = + (struct pci_controller *) dev->bus->sysdata; + struct xilinx_axipcie_port *port = + &xilinx_axipcie_ports[hose->indirect_type]; + + if (port->link) + bridge_enable(port->base_addr_remap); +} + +/** + * xilinx_find_axipcie_nodes - Entry function + * void + * + * @return: Error / no error + * @note: Find pcie nodes in device tree + */ +static int __init xilinx_find_axipcie_nodes(void) +{ + struct device_node *np; + const struct of_device_id *matches = xilinx_axipcie_match; + int error = 0; + + printk(KERN_INFO "Initialising Xilinx PCI Express root" + " complex device\n"); + for_each_matching_node(np, matches) { + error = xilinx_probe_axipcie_node(np); + if (error) + return error; + } + return 0; +} + +arch_initcall(xilinx_find_axipcie_nodes); Index: linux-3.12.24-rt38-xilinx/arch/microblaze/pci/xilinx_axipcie.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/microblaze/pci/xilinx_axipcie.h 2014-07-20 22:06:34.734332472 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Header file for Xilinx AXI PCIe IP driver. + * + * Copyright (c) 2010-2011 Xilinx, Inc. + * + * This program has adopted some work from PCI/PCIE support for AMCC + * PowerPC boards written by Benjamin Herrenschmidt. + * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef XILINX_AXIPCIE_H_ +#define XILINX_AXIPCIE_H_ + +/* Register definitions */ +#define PCIE_CFG_CMD 0x00000004 +#define PCIE_CFG_CLS 0x00000008 +#define PCIE_CFG_HDR 0x0000000C +#define PCIE_CFG_AD1 0x00000010 +#define PCIE_CFG_AD2 0x00000014 +#define PCIE_CFG_BUS 0x00000018 +#define PCIE_CFG_IO 0x0000001C +#define PCIE_CFG_MEM 0x00000020 +#define PCIE_CFG_PREF_MEM 0x00000024 +#define PCIE_CFG_PREF_BASE_UPPER 0x00000028 +#define PCIE_CFG_PREF_LIMIT_UPPER 0x0000002c +#define PCIE_CFG_IO_UPPER 0x00000030 + +#define AXIPCIE_REG_VSECC 0x00000128 +#define AXIPCIE_REG_VSECH 0x0000012c +#define AXIPCIE_REG_BIR 0x00000130 +#define AXIPCIE_REG_BSCR 0x00000134 +#define AXIPCIE_REG_IDR 0x00000138 +#define AXIPCIE_REG_IMR 0x0000013c +#define AXIPCIE_REG_BLR 0x00000140 +#define AXIPCIE_REG_PSCR 0x00000144 +#define AXIPCIE_REG_RPSC 0x00000148 +#define AXIPCIE_REG_MSIBASE1 0x0000014c +#define AXIPCIE_REG_MSIBASE2 0x00000150 +#define AXIPCIE_REG_RPEFR 0x00000154 +#define AXIPCIE_REG_RPIFR1 0x00000158 +#define AXIPCIE_REG_RPIFR2 0x0000015c +#define AXIPCIE_REG_VSECC2 0x00000200 +#define AXIPCIE_REG_VSECH2 0x00000204 + +/* Interrupt register defines */ +#define AXIPCIE_INTR_LINK_DOWN (1 << 0) +#define AXIPCIE_INTR_ECRC_ERR (1 << 1) +#define AXIPCIE_INTR_STR_ERR (1 << 2) +#define AXIPCIE_INTR_HOT_RESET (1 << 3) +#define AXIPCIE_INTR_CFG_COMPL (7 << 5) +#define AXIPCIE_INTR_CFG_TIMEOUT (1 << 8) +#define AXIPCIE_INTR_CORRECTABLE (1 << 9) +#define AXIPCIE_INTR_NONFATAL (1 << 10) +#define AXIPCIE_INTR_FATAL (1 << 11) +#define AXIPCIE_INTR_INTX (1 << 16) +#define AXIPCIE_INTR_MSI (1 << 17) +#define AXIPCIE_INTR_SLV_UNSUPP (1 << 20) +#define AXIPCIE_INTR_SLV_UNEXP (1 << 21) +#define AXIPCIE_INTR_SLV_COMPL (1 << 22) +#define AXIPCIE_INTR_SLV_ERRP (1 << 23) +#define AXIPCIE_INTR_SLV_CMPABT (1 << 24) +#define AXIPCIE_INTR_SLV_ILLBUR (1 << 25) +#define AXIPCIE_INTR_MST_DECERR (1 << 26) +#define AXIPCIE_INTR_MST_SLVERR (1 << 27) +#define AXIPCIE_INTR_MST_ERRP (1 << 28) + +#define BUS_LOC_SHIFT 20 +#define DEV_LOC_SHIFT 12 +#define PRIMARY_BUS 1 +#define PORT_REG_SIZE 0x1000 +#define PORT_HEADER_SIZE 0x128 + +#define AXIPCIE_LOCAL_CNFG_BASE 0x00000000 +#define AXIPCIE_REG_BASE 0x00000128 +#define AXIPCIE_REG_PSCR_LNKUP 0x00000800 +#define AXIPCIE_REG_IMR_MASKALL 0x1FF30FED +#define AXIPCIE_REG_IDR_MASKALL 0xFFFFFFFF +#define AXIPCIE_REG_RPSC_BEN 0x00000001 +#define BUS_MASTER_ENABLE 0x00000004 + +/* debug */ +//#define XILINX_AXIPCIE_DEBUG +#ifdef XILINX_AXIPCIE_DEBUG +#define DBG(x...) ((void)printk(x)) +#else +#define DBG(x...) \ + do { \ + } while(0) +#endif + +/* Xilinx CR# 657412 */ +/* Byte swapping */ +#define xpcie_out_be32(a, v) __raw_writel(__cpu_to_be32(v), (a)) +#define xpcie_out_be16(a, v) __raw_writew(__cpu_to_be16(v), (a)) + +#define xpcie_in_be32(a) __be32_to_cpu(__raw_readl(a)) +#define xpcie_in_be16(a) __be16_to_cpu(__raw_readw(a)) + +#ifdef CONFIG_PCI_MSI +extern unsigned long msg_addr; +#endif + +struct xilinx_axipcie_node { + u32 number_of_instances; + u32 device_id; + u32 device_type; + u32 ecam_base; + u32 ecam_high; + u32 baseaddr; + u32 highaddr; + u32 bars_num; + u32 irq_num; + u32 reg_base; + u32 reg_len; + u32 pcie2axibar_0; + u32 pcie2axibar_1; +}; + +struct xilinx_axipcie_port { + struct pci_controller *hose; + struct device_node *node; + u32 reg_base; + u32 reg_len; + u32 ecam_base; + u32 ecam_high; + u32 baseaddr; + u32 highaddr; + u32 header_addr; + u8 index; + u8 type; + u8 link; + u8 bars_num; + u32 irq_num; + unsigned int __iomem *base_addr_remap; + unsigned int __iomem *header_remap; + unsigned int __iomem *ecam_remap; + u32 pcie2axibar_0; + u32 pcie2axibar_1; +}; + +#endif /* XILINX_AXIPCIE_H_ */ Index: linux-3.12.24-rt38-xilinx/arch/powerpc/boot/dts/virtex405-ml405.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/boot/dts/virtex405-ml405.dts 2014-07-20 22:06:34.749332225 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * This file supports the Xilinx ML405 board with the 405 processor. + * A reference design for the FPGA is provided at http://git.xilinx.com. + * + * (C) Copyright 2008 Xilinx, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,virtex"; + model = "testing"; + DDR_SDRAM: memory@0 { + device_type = "memory"; + reg = < 0 0x8000000 >; + } ; + chosen { + bootargs = "console=ttyS0 ip=on root=/dev/ram"; + linux,stdout-path = "/plb@0/serial@83e00000"; + } ; + cpus { + #address-cells = <1>; + #cpus = <1>; + + #size-cells = <0>; + ppc405_0: cpu@0 { + clock-frequency = <0x11e1a300>; + compatible = "PowerPC,405", "ibm,ppc405"; + d-cache-line-size = <0x20>; + d-cache-size = <0x4000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x4000>; + model = "PowerPC,405"; + reg = <0>; + timebase-frequency = <0x11e1a300>; + xlnx,apu-control = <0xde00>; + xlnx,apu-udi-1 = <0xa18983>; + xlnx,apu-udi-2 = <0xa38983>; + xlnx,apu-udi-3 = <0xa589c3>; + xlnx,apu-udi-4 = <0xa789c3>; + xlnx,apu-udi-5 = <0xa98c03>; + xlnx,apu-udi-6 = <0xab8c03>; + xlnx,apu-udi-7 = <0xad8c43>; + xlnx,apu-udi-8 = <0xaf8c43>; + xlnx,deterministic-mult = <0>; + xlnx,disable-operand-forwarding = <1>; + xlnx,fastest-plb-clock = "DPLB0"; + xlnx,generate-plb-timespecs = <1>; + xlnx,mmu-enable = <1>; + xlnx,pvr-high = <0>; + xlnx,pvr-low = <0>; + } ; + } ; + plb: plb@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,plb-v46-1.02.a", "simple-bus"; + ranges ; + IIC_EEPROM: i2c@81600000 { + compatible = "xlnx,xps-iic-2.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 4 2 >; + reg = < 0x81600000 0x10000 >; + xlnx,clk-freq = <0x5f5e100>; + xlnx,family = "virtex4"; + xlnx,gpo-width = <1>; + xlnx,iic-freq = <0x186a0>; + xlnx,scl-inertial-delay = <0>; + xlnx,sda-inertial-delay = <0>; + xlnx,ten-bit-adr = <0>; + } ; + LEDs_4Bit: gpio@81400000 { + compatible = "xlnx,xps-gpio-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 5 2 >; + reg = < 0x81400000 0x10000 >; + xlnx,all-inputs = <0>; + xlnx,all-inputs-2 = <0>; + xlnx,dout-default = <0>; + xlnx,dout-default-2 = <0>; + xlnx,family = "virtex4"; + xlnx,gpio-width = <4>; + xlnx,interrupt-present = <1>; + xlnx,is-bidir = <1>; + xlnx,is-bidir-2 = <1>; + xlnx,is-dual = <0>; + xlnx,tri-default = <0xffffffff>; + xlnx,tri-default-2 = <0xffffffff>; + } ; + RS232_Uart: serial@83e00000 { + compatible = "ns16550"; + device_type = "serial"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 6 2 >; + reg = < 0x83e00000 0x10000 >; + reg-offset = <0x1003>; + reg-shift = <2>; + clock-frequency = <0x05f5e100>; + xlnx,family = "virtex4"; + xlnx,has-external-rclk = <0>; + xlnx,has-external-xin = <0>; + xlnx,is-a-16550 = <1>; + } ; + SysACE_CompactFlash: sysace@83600000 { + compatible = "xlnx,xps-sysace-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 3 2 >; + reg = < 0x83600000 0x10000 >; + xlnx,family = "virtex4"; + xlnx,mem-width = <0x10>; + } ; + TriMode_MAC_GMII: xps-ll-temac@81c00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,compound"; + ethernet@81c00000 { + compatible = "xlnx,xps-ll-temac-1.01.a"; + device_type = "network"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 2 2 >; + llink-connected = <&PIM2>; + local-mac-address = [ 02 00 00 00 00 01 ]; + reg = < 0x81c00000 0x40 >; + xlnx,bus2core-clk-ratio = <1>; + xlnx,phy-type = <1>; + xlnx,phyaddr = <1>; + xlnx,rxcsum = <0>; + xlnx,rxfifo = <0x1000>; + xlnx,temac-type = <1>; + xlnx,txcsum = <0>; + xlnx,txfifo = <0x1000>; + } ; + } ; + mpmc@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,mpmc-4.00.a"; + PIM2: sdma@84600100 { + compatible = "xlnx,ll-dma-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 1 2 0 2 >; + reg = < 0x84600100 0x80 >; + } ; + } ; + xps_bram_if_cntlr_1: xps-bram-if-cntlr@ffffe000 { + compatible = "xlnx,xps-bram-if-cntlr-1.00.a"; + reg = < 0xffffe000 0x2000 >; + xlnx,family = "virtex4"; + } ; + xps_intc_0: interrupt-controller@81800000 { + #interrupt-cells = <2>; + compatible = "xlnx,xps-intc-1.00.a"; + interrupt-controller ; + reg = < 0x81800000 0x10000 >; + xlnx,num-intr-inputs = <7>; + } ; + } ; + ppc405_0_dplb1: plb@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,plb-v46-1.02.a", "simple-bus"; + ranges ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/powerpc/boot/dts/virtex440-avnet-v5fx30t.dts =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/boot/dts/virtex440-avnet-v5fx30t.dts 2014-07-20 22:06:34.758332077 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Device Tree Generator version: 1.1 + * + * This file supports the Avnet V5FX30T board with the 440 processor. + * A reference design for the FPGA is provided at the avnet web site. + * + * (C) Copyright 2009 Xilinx, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,virtex440", "xlnx,virtex"; + dcr-parent = <&ppc440_0>; + model = "testing"; + DDR2_SDRAM_16Mx32: memory@0 { + device_type = "memory"; + reg = < 0x0 0x4000000 >; + } ; + chosen { + bootargs = "console=ttyS0 root=/dev/ram"; + linux,stdout-path = "/plb@0/serial@83e00000"; + } ; + cpus { + #address-cells = <1>; + #cpus = <0x1>; + #size-cells = <0>; + ppc440_0: cpu@0 { + #address-cells = <1>; + #size-cells = <1>; + clock-frequency = <400000000>; + compatible = "PowerPC,440", "ibm,ppc440"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + dcr-access-method = "native"; + dcr-controller ; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; + model = "PowerPC,440"; + reg = <0>; + timebase-frequency = <400000000>; + xlnx,apu-control = <0x2000>; + xlnx,apu-udi-0 = <0x0>; + xlnx,apu-udi-1 = <0x0>; + xlnx,apu-udi-10 = <0x0>; + xlnx,apu-udi-11 = <0x0>; + xlnx,apu-udi-12 = <0x0>; + xlnx,apu-udi-13 = <0x0>; + xlnx,apu-udi-14 = <0x0>; + xlnx,apu-udi-15 = <0x0>; + xlnx,apu-udi-2 = <0x0>; + xlnx,apu-udi-3 = <0x0>; + xlnx,apu-udi-4 = <0x0>; + xlnx,apu-udi-5 = <0x0>; + xlnx,apu-udi-6 = <0x0>; + xlnx,apu-udi-7 = <0x0>; + xlnx,apu-udi-8 = <0x0>; + xlnx,apu-udi-9 = <0x0>; + xlnx,dcr-autolock-enable = <0x1>; + xlnx,dcu-rd-ld-cache-plb-prio = <0x0>; + xlnx,dcu-rd-noncache-plb-prio = <0x0>; + xlnx,dcu-rd-touch-plb-prio = <0x0>; + xlnx,dcu-rd-urgent-plb-prio = <0x0>; + xlnx,dcu-wr-flush-plb-prio = <0x0>; + xlnx,dcu-wr-store-plb-prio = <0x0>; + xlnx,dcu-wr-urgent-plb-prio = <0x0>; + xlnx,dma0-control = <0x0>; + xlnx,dma0-plb-prio = <0x0>; + xlnx,dma0-rxchannelctrl = <0x1010000>; + xlnx,dma0-rxirqtimer = <0x3ff>; + xlnx,dma0-txchannelctrl = <0x1010000>; + xlnx,dma0-txirqtimer = <0x3ff>; + xlnx,dma1-control = <0x0>; + xlnx,dma1-plb-prio = <0x0>; + xlnx,dma1-rxchannelctrl = <0x1010000>; + xlnx,dma1-rxirqtimer = <0x3ff>; + xlnx,dma1-txchannelctrl = <0x1010000>; + xlnx,dma1-txirqtimer = <0x3ff>; + xlnx,dma2-control = <0x0>; + xlnx,dma2-plb-prio = <0x0>; + xlnx,dma2-rxchannelctrl = <0x1010000>; + xlnx,dma2-rxirqtimer = <0x3ff>; + xlnx,dma2-txchannelctrl = <0x1010000>; + xlnx,dma2-txirqtimer = <0x3ff>; + xlnx,dma3-control = <0x0>; + xlnx,dma3-plb-prio = <0x0>; + xlnx,dma3-rxchannelctrl = <0x1010000>; + xlnx,dma3-rxirqtimer = <0x3ff>; + xlnx,dma3-txchannelctrl = <0x1010000>; + xlnx,dma3-txirqtimer = <0x3ff>; + xlnx,endian-reset = <0x0>; + xlnx,generate-plb-timespecs = <0x1>; + xlnx,icu-rd-fetch-plb-prio = <0x0>; + xlnx,icu-rd-spec-plb-prio = <0x0>; + xlnx,icu-rd-touch-plb-prio = <0x0>; + xlnx,interconnect-imask = <0xffffffff>; + xlnx,mplb-allow-lock-xfer = <0x1>; + xlnx,mplb-arb-mode = <0x0>; + xlnx,mplb-awidth = <0x20>; + xlnx,mplb-counter = <0x500>; + xlnx,mplb-dwidth = <0x80>; + xlnx,mplb-max-burst = <0x8>; + xlnx,mplb-native-dwidth = <0x80>; + xlnx,mplb-p2p = <0x0>; + xlnx,mplb-prio-dcur = <0x2>; + xlnx,mplb-prio-dcuw = <0x3>; + xlnx,mplb-prio-icu = <0x4>; + xlnx,mplb-prio-splb0 = <0x1>; + xlnx,mplb-prio-splb1 = <0x0>; + xlnx,mplb-read-pipe-enable = <0x1>; + xlnx,mplb-sync-tattribute = <0x0>; + xlnx,mplb-wdog-enable = <0x1>; + xlnx,mplb-write-pipe-enable = <0x1>; + xlnx,mplb-write-post-enable = <0x1>; + xlnx,num-dma = <0x1>; + xlnx,pir = <0xf>; + xlnx,ppc440mc-addr-base = <0x0>; + xlnx,ppc440mc-addr-high = <0x3ffffff>; + xlnx,ppc440mc-arb-mode = <0x0>; + xlnx,ppc440mc-bank-conflict-mask = <0x300000>; + xlnx,ppc440mc-control = <0xf850008f>; + xlnx,ppc440mc-max-burst = <0x8>; + xlnx,ppc440mc-prio-dcur = <0x2>; + xlnx,ppc440mc-prio-dcuw = <0x3>; + xlnx,ppc440mc-prio-icu = <0x4>; + xlnx,ppc440mc-prio-splb0 = <0x1>; + xlnx,ppc440mc-prio-splb1 = <0x0>; + xlnx,ppc440mc-row-conflict-mask = <0xfff80>; + xlnx,ppcdm-asyncmode = <0x0>; + xlnx,ppcds-asyncmode = <0x0>; + xlnx,user-reset = <0x0>; + DMA0: sdma@80 { + compatible = "xlnx,ll-dma-1.00.a"; + dcr-reg = < 0x80 0x11 >; + interrupt-parent = <&xps_intc_0>; + interrupts = < 7 2 8 2 >; + } ; + } ; + } ; + plb_v46_0: plb@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,plb-v46-1.03.a", "simple-bus"; + ranges ; + DIP_Switches_8Bit: gpio@81420000 { + compatible = "xlnx,xps-gpio-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 5 2 >; + reg = < 0x81420000 0x10000 >; + xlnx,all-inputs = <0x1>; + xlnx,all-inputs-2 = <0x0>; + xlnx,dout-default = <0x0>; + xlnx,dout-default-2 = <0x0>; + xlnx,family = "virtex5"; + xlnx,gpio-width = <0x8>; + xlnx,interrupt-present = <0x1>; + xlnx,is-bidir = <0x0>; + xlnx,is-bidir-2 = <0x1>; + xlnx,is-dual = <0x0>; + xlnx,tri-default = <0xffffffff>; + xlnx,tri-default-2 = <0xffffffff>; + } ; + FLASH_8Mx16: flash@86000000 { + bank-width = <2>; + compatible = "xlnx,xps-mch-emc-2.00.a", "cfi-flash"; + reg = < 0x86000000 0x2000000 >; + xlnx,family = "virtex5"; + xlnx,include-datawidth-matching-0 = <0x1>; + xlnx,include-datawidth-matching-1 = <0x0>; + xlnx,include-datawidth-matching-2 = <0x0>; + xlnx,include-datawidth-matching-3 = <0x0>; + xlnx,include-negedge-ioregs = <0x0>; + xlnx,include-plb-ipif = <0x1>; + xlnx,include-wrbuf = <0x1>; + xlnx,max-mem-width = <0x10>; + xlnx,mch-native-dwidth = <0x20>; + xlnx,mch-plb-clk-period-ps = <0x2710>; + xlnx,mch-splb-awidth = <0x20>; + xlnx,mch0-accessbuf-depth = <0x10>; + xlnx,mch0-protocol = <0x0>; + xlnx,mch0-rddatabuf-depth = <0x10>; + xlnx,mch1-accessbuf-depth = <0x10>; + xlnx,mch1-protocol = <0x0>; + xlnx,mch1-rddatabuf-depth = <0x10>; + xlnx,mch2-accessbuf-depth = <0x10>; + xlnx,mch2-protocol = <0x0>; + xlnx,mch2-rddatabuf-depth = <0x10>; + xlnx,mch3-accessbuf-depth = <0x10>; + xlnx,mch3-protocol = <0x0>; + xlnx,mch3-rddatabuf-depth = <0x10>; + xlnx,mem0-width = <0x10>; + xlnx,mem1-width = <0x20>; + xlnx,mem2-width = <0x20>; + xlnx,mem3-width = <0x20>; + xlnx,num-banks-mem = <0x1>; + xlnx,num-channels = <0x2>; + xlnx,priority-mode = <0x0>; + xlnx,synch-mem-0 = <0x0>; + xlnx,synch-mem-1 = <0x0>; + xlnx,synch-mem-2 = <0x0>; + xlnx,synch-mem-3 = <0x0>; + xlnx,synch-pipedelay-0 = <0x2>; + xlnx,synch-pipedelay-1 = <0x2>; + xlnx,synch-pipedelay-2 = <0x2>; + xlnx,synch-pipedelay-3 = <0x2>; + xlnx,tavdv-ps-mem-0 = <0x1d4c0>; + xlnx,tavdv-ps-mem-1 = <0x3a98>; + xlnx,tavdv-ps-mem-2 = <0x3a98>; + xlnx,tavdv-ps-mem-3 = <0x3a98>; + xlnx,tcedv-ps-mem-0 = <0x1d4c0>; + xlnx,tcedv-ps-mem-1 = <0x3a98>; + xlnx,tcedv-ps-mem-2 = <0x3a98>; + xlnx,tcedv-ps-mem-3 = <0x3a98>; + xlnx,thzce-ps-mem-0 = <0x88b8>; + xlnx,thzce-ps-mem-1 = <0x1b58>; + xlnx,thzce-ps-mem-2 = <0x1b58>; + xlnx,thzce-ps-mem-3 = <0x1b58>; + xlnx,thzoe-ps-mem-0 = <0x1b58>; + xlnx,thzoe-ps-mem-1 = <0x1b58>; + xlnx,thzoe-ps-mem-2 = <0x1b58>; + xlnx,thzoe-ps-mem-3 = <0x1b58>; + xlnx,tlzwe-ps-mem-0 = <0x88b8>; + xlnx,tlzwe-ps-mem-1 = <0x0>; + xlnx,tlzwe-ps-mem-2 = <0x0>; + xlnx,tlzwe-ps-mem-3 = <0x0>; + xlnx,twc-ps-mem-0 = <0x1d4c0>; + xlnx,twc-ps-mem-1 = <0x3a98>; + xlnx,twc-ps-mem-2 = <0x3a98>; + xlnx,twc-ps-mem-3 = <0x3a98>; + xlnx,twp-ps-mem-0 = <0x1d4c0>; + xlnx,twp-ps-mem-1 = <0x2ee0>; + xlnx,twp-ps-mem-2 = <0x2ee0>; + xlnx,twp-ps-mem-3 = <0x2ee0>; + xlnx,xcl0-linesize = <0x4>; + xlnx,xcl0-writexfer = <0x1>; + xlnx,xcl1-linesize = <0x4>; + xlnx,xcl1-writexfer = <0x1>; + xlnx,xcl2-linesize = <0x4>; + xlnx,xcl2-writexfer = <0x1>; + xlnx,xcl3-linesize = <0x4>; + xlnx,xcl3-writexfer = <0x1>; + } ; + Hard_Ethernet_MAC: xps-ll-temac@81c00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,compound"; + ethernet@81c00000 { + compatible = "xlnx,xps-ll-temac-1.01.b"; + device_type = "network"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 3 2 >; + llink-connected = <&DMA0>; + local-mac-address = [ 02 00 00 00 00 00 ]; + reg = < 0x81c00000 0x40 >; + xlnx,bus2core-clk-ratio = <0x1>; + xlnx,phy-type = <0x1>; + xlnx,phyaddr = <0x1>; + xlnx,rxcsum = <0x1>; + xlnx,rxfifo = <0x1000>; + xlnx,temac-type = <0x0>; + xlnx,txcsum = <0x1>; + xlnx,txfifo = <0x1000>; + } ; + } ; + LEDs_8Bit: gpio@81400000 { + compatible = "xlnx,xps-gpio-1.00.a"; + reg = < 0x81400000 0x10000 >; + xlnx,all-inputs = <0x0>; + xlnx,all-inputs-2 = <0x0>; + xlnx,dout-default = <0x0>; + xlnx,dout-default-2 = <0x0>; + xlnx,family = "virtex5"; + xlnx,gpio-width = <0x8>; + xlnx,interrupt-present = <0x0>; + xlnx,is-bidir = <0x0>; + xlnx,is-bidir-2 = <0x1>; + xlnx,is-dual = <0x0>; + xlnx,tri-default = <0xffffffff>; + xlnx,tri-default-2 = <0xffffffff>; + } ; + Push_Buttons_3Bit: gpio@81440000 { + compatible = "xlnx,xps-gpio-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 4 2 >; + reg = < 0x81440000 0x10000 >; + xlnx,all-inputs = <0x1>; + xlnx,all-inputs-2 = <0x0>; + xlnx,dout-default = <0x0>; + xlnx,dout-default-2 = <0x0>; + xlnx,family = "virtex5"; + xlnx,gpio-width = <0x3>; + xlnx,interrupt-present = <0x1>; + xlnx,is-bidir = <0x0>; + xlnx,is-bidir-2 = <0x1>; + xlnx,is-dual = <0x0>; + xlnx,tri-default = <0xffffffff>; + xlnx,tri-default-2 = <0xffffffff>; + } ; + RS232: serial@83e00000 { + clock-frequency = <100000000>; + compatible = "xlnx,xps-uart16550-2.00.b", "ns16550"; + current-speed = <9600>; + device_type = "serial"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 6 2 >; + reg = < 0x83e00000 0x10000 >; + reg-offset = <0x1003>; + reg-shift = <2>; + xlnx,family = "virtex5"; + xlnx,has-external-rclk = <0x0>; + xlnx,has-external-xin = <0x0>; + xlnx,is-a-16550 = <0x1>; + } ; + xps_bram_if_cntlr_1: xps-bram-if-cntlr@ffff0000 { + compatible = "xlnx,xps-bram-if-cntlr-1.00.a"; + reg = < 0xffff0000 0x10000 >; + xlnx,family = "virtex5"; + } ; + xps_intc_0: interrupt-controller@81800000 { + #interrupt-cells = <0x2>; + compatible = "xlnx,xps-intc-1.00.a"; + interrupt-controller ; + reg = < 0x81800000 0x10000 >; + xlnx,num-intr-inputs = <0x9>; + } ; + xps_timebase_wdt_1: xps-timebase-wdt@83a00000 { + compatible = "xlnx,xps-timebase-wdt-1.00.b"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 1 0 0 2 >; + reg = < 0x83a00000 0x10000 >; + xlnx,family = "virtex5"; + xlnx,wdt-enable-once = <0x0>; + xlnx,wdt-interval = <0x1e>; + } ; + xps_timer_1: timer@83c00000 { + compatible = "xlnx,xps-timer-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 2 2 >; + reg = < 0x83c00000 0x10000 >; + xlnx,count-width = <0x20>; + xlnx,family = "virtex5"; + xlnx,gen0-assert = <0x1>; + xlnx,gen1-assert = <0x1>; + xlnx,one-timer-only = <0x1>; + xlnx,trig0-assert = <0x1>; + xlnx,trig1-assert = <0x1>; + } ; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/arch/powerpc/boot/.gitignore =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/boot/.gitignore 2014-07-20 22:05:50.307065450 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/boot/.gitignore 2014-07-20 22:06:34.766331945 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:31 @ zImage.miboot zImage.pmac zImage.pseries +zImage.virtex zconf.h zlib.h zutil.h Index: linux-3.12.24-rt38-xilinx/arch/powerpc/boot/kernel_fdt.its =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/boot/kernel_fdt.its 2014-07-20 22:06:34.773331829 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Simple U-boot uImage source file containing a single kernel and FDT blob + */ +/ { + description = "PetaLinux PPC uImage with single Linux kernel and FDT blob"; + #address-cells = <1>; + + images { + kernel@1 { + description = "PetaLinux kernel"; + data = /incbin/("./vmlinux.bin.gz"); + type = "kernel"; + arch = "ppc"; + os = "linux"; + compression = "gzip"; + load = <00000000>; + entry = <00000000>; + hash@1 { + algo = "crc32"; + }; + hash@2 { + algo = "sha1"; + }; + }; + fdt@1 { + description = "Flattened Device Tree blob"; + data = /incbin/("./target.dtb"); + type = "flat_dt"; + arch = "ppc"; + compression = "none"; +/* + hash@1 { + algo = "crc32"; + }; + hash@2 { + algo = "sha1"; + }; +*/ + }; + }; + + configurations { + default = "conf@1"; + conf@1 { + description = "Boot Linux kernel with FDT blob"; + kernel = "kernel@1"; + fdt = "fdt@1"; + }; + }; +}; Index: linux-3.12.24-rt38-xilinx/arch/powerpc/boot/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/boot/Makefile 2014-07-20 22:05:50.306065466 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/boot/Makefile 2014-07-20 22:06:34.783331664 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:340 @ $(obj)/uImage.%: vmlinux $(obj)/%.dtb $(wrapperbits) $(call if_changed,wrap,uboot-$*,,$(obj)/$*.dtb) + $(call if_changed,wrap,uboot-fit,,$(obj)/$*.dtb) $(obj)/cuImage.initrd.%: vmlinux $(obj)/%.dtb $(wrapperbits) $(call if_changed,wrap,cuboot-$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz) Index: linux-3.12.24-rt38-xilinx/arch/powerpc/boot/simpleboot.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/boot/simpleboot.c 2014-07-20 22:05:50.305065482 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/boot/simpleboot.c 2014-07-20 22:06:34.794331483 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:34 @ const u32 *na, *ns, *reg, *timebase; u64 memsize64; int node, size, i; + void *the_dtb = _dtb_start; + + /* See if we were passed a DTB in the regs. If so, use that instead */ + if (fdt_check_header((void *)r3) == 0) + the_dtb = (void *)r3; /* Make sure FDT blob is sane */ - if (fdt_check_header(_dtb_start) != 0) + if (fdt_check_header(the_dtb) != 0) fatal("Invalid device tree blob\n"); /* Find the #address-cells and #size-cells properties */ - node = fdt_path_offset(_dtb_start, "/"); + node = fdt_path_offset(the_dtb, "/"); if (node < 0) fatal("Cannot find root node\n"); - na = fdt_getprop(_dtb_start, node, "#address-cells", &size); + na = fdt_getprop(the_dtb, node, "#address-cells", &size); if (!na || (size != 4)) fatal("Cannot find #address-cells property"); - ns = fdt_getprop(_dtb_start, node, "#size-cells", &size); + ns = fdt_getprop(the_dtb, node, "#size-cells", &size); if (!ns || (size != 4)) fatal("Cannot find #size-cells property"); /* Find the memory range */ - node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", + node = fdt_node_offset_by_prop_value(the_dtb, -1, "device_type", "memory", sizeof("memory")); if (node < 0) fatal("Cannot find memory node\n"); - reg = fdt_getprop(_dtb_start, node, "reg", &size); + reg = fdt_getprop(the_dtb, node, "reg", &size); if (size < (*na+*ns) * sizeof(u32)) fatal("cannot get memory range\n"); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:77 @ memsize64 = 0xffffffff; /* finally, setup the timebase */ - node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", + node = fdt_node_offset_by_prop_value(the_dtb, -1, "device_type", "cpu", sizeof("cpu")); if (!node) fatal("Cannot find cpu node\n"); - timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); + timebase = fdt_getprop(the_dtb, node, "timebase-frequency", &size); if (timebase && (size == 4)) timebase_period_ns = 1000000000 / *timebase; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:89 @ simple_alloc_init(_end, memsize64 - (unsigned long)_end, 32, 64); /* prepare the device tree and find the console */ - fdt_init(_dtb_start); + fdt_init(the_dtb); if (platform_specific_init) platform_specific_init(); Index: linux-3.12.24-rt38-xilinx/arch/powerpc/boot/wrapper =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/boot/wrapper 2014-07-20 22:05:50.308065433 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/boot/wrapper 2014-07-20 22:06:34.805331301 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:146 @ tmp=$tmpdir/zImage.$$.o ksection=.kernel:vmlinux.strip isection=.kernel:initrd -link_address='0x400000' make_space=y +# default auto-calculate link_address to make room for the kernel +# round up kernel image size to nearest megabyte +link_address=`${CROSS}size -x ${kernel} | grep ${kernel} | awk '{printf("0x%08x", and($4 + 0x0fffff, 0xfffe0000))}'` + case "$platform" in pseries) platformo="$object/of.o $object/epapr.o" @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:170 @ link_address='0x500000' pie= ;; -miboot|uboot*) +miboot|uboot|uboot-fit) # miboot and U-boot want just the bare bits, not an ELF binary ext=bin objflags="-O binary" @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:345 @ fi exit 0 ;; +uboot-fit) + pwd + rm -f "$ofile" + #[ "$vmz" != vmlinux.bin.gz ] && mv "$vmz" "vmlinux.bin.gz" + mv "$dtb" "target.dtb" + cp arch/powerpc/boot/kernel_fdt.its . + mkimage -f kernel_fdt.its "$ofile" + #rm kernet_fdt.its + exit 0 + ;; esac addsec() { Index: linux-3.12.24-rt38-xilinx/arch/powerpc/configs/40x/virtex4_defconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/configs/40x/virtex4_defconfig 2014-07-20 22:06:34.831330872 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Automatically generated make config: don't edit +# Linux/powerpc 2.6.37-rc4 Kernel Configuration +# Tue Dec 14 10:53:11 2010 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_PPC_BOOK3S_32 is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +CONFIG_40x=y +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_4xx=y +CONFIG_PPC_MMU_NOHASH=y +CONFIG_PPC_MMU_NOHASH_32=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_32BIT=y +CONFIG_WORD_SIZE=32 +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_MMU=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set +# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set +CONFIG_IRQ_PER_CPU=y +CONFIG_NR_IRQS=512 +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_PPC_DCR_NATIVE=y +CONFIG_PPC_DCR_MMIO=y +CONFIG_PPC_DCR=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_PPC_ADV_DEBUG_REGS=y +CONFIG_PPC_ADV_DEBUG_IACS=2 +CONFIG_PPC_ADV_DEBUG_DACS=2 +CONFIG_PPC_ADV_DEBUG_DVCS=0 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y +CONFIG_HAVE_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +# CONFIG_HAVE_GENERIC_HARDIRQS is not set +# CONFIG_SPARSE_IRQ is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +# CONFIG_TINY_RCU is not set +# CONFIG_TINY_PREEMPT_RCU is not set +CONFIG_PREEMPT_RCU=y +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_NET_NS=y +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_PCI_QUIRKS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_DMA_API_DEBUG=y + +# +# GCOV-based kernel profiling +# +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_FREEZER is not set +# CONFIG_PPC4xx_PCI_EXPRESS is not set + +# +# Platform support +# +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +# CONFIG_ISS4xx is not set +# CONFIG_PPC4xx_GPIO is not set +CONFIG_XILINX_VIRTEX=y +# CONFIG_ACADIA is not set +# CONFIG_EP405 is not set +# CONFIG_HCU4 is not set +# CONFIG_HOTFOOT is not set +# CONFIG_KILAUEA is not set +# CONFIG_MAKALU is not set +# CONFIG_WALNUT is not set +CONFIG_XILINX_VIRTEX_GENERIC_BOARD=y +# CONFIG_PPC40x_SIMPLE is not set +CONFIG_XILINX_VIRTEX_II_PRO=y +CONFIG_XILINX_VIRTEX_4_FX=y +CONFIG_IBM405_ERR77=y +CONFIG_IBM405_ERR51=y +CONFIG_KVM_GUEST=y +# CONFIG_IPIC is not set +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_MPIC_U3_HT_IRQS is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_FSL_ULI1575 is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_XILINX_PCI is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_MATH_EMULATION=y +# CONFIG_IOMMU_HELPER is not set +# CONFIG_SWIOTLB is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_WALK_MEMORY=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_MAX_ACTIVE_REGIONS=32 +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_NEED_PER_CPU_KM=y +CONFIG_PPC_4K_PAGES=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +CONFIG_EXTRA_TARGETS="simpleImage.virtex405-ml405 simpleImage.initrd.virtex405-ml405" +# CONFIG_PM is not set +CONFIG_SECCOMP=y +# CONFIG_COMPRESSED_DEVICE_TREE is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_4xx_SOC=y +CONFIG_PPC_PCI_CHOICE=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HAS_RAPIDIO is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_PAGE_OFFSET=0xc0000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_PHYSICAL_START=0x00000000 +CONFIG_TASK_SIZE=0xc0000000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_TPROXY is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +# CONFIG_NETFILTER_XT_MARK is not set + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_TTL is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_LOG is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_ARPTABLES is not set + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# + +# +# Some wireless drivers require a rate control algorithm +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_GPIO=y +CONFIG_OF_I2C=y +CONFIG_OF_SPI=y +CONFIG_OF_MDIO=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_XILINX_SYSACE=y +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_RBD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_BMP085 is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +CONFIG_XILINX_DRIVERS=y +CONFIG_NEED_XILINX_LLDMA=y +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_ARCNET is not set +CONFIG_MII=y +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_DNET is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_IBM_NEW_EMAC is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_NET_PCI is not set +# CONFIG_B44 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_XILINX_EMAC is not set +# CONFIG_ATL2 is not set +CONFIG_XILINX_EMACLITE=y +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_IP1000 is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +# CONFIG_XILINX_TEMAC is not set +# CONFIG_ATL1E is not set +CONFIG_XILINX_LLTEMAC=y +# CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_RGMII is not set +CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_GMII=y +# CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_MII is not set +# CONFIG_XILINX_LLTEMAC_NATIONAL_DP83865_GMII is not set +# CONFIG_ATL1C is not set +# CONFIG_JME is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_PCH_GBE is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set +CONFIG_WLAN=y +# CONFIG_AIRO is not set +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_HOSTAP is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set + +# +# CAIF transport drivers +# +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_XILINXPS2 is not set +# CONFIG_SERIO_XILINX_XPS_PS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +# CONFIG_SERIAL_MFD_HSU is not set +CONFIG_SERIAL_UARTLITE=y +CONFIG_SERIAL_UARTLITE_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=m +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +CONFIG_XILINX_HWICAP=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_SMBUS is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set +CONFIG_XILINX_IIC=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_INTEL_MID is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +CONFIG_I2C_DEBUG_CORE=y +CONFIG_I2C_DEBUG_ALGO=y +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +CONFIG_SPI_XILINX=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_BASIC_MMIO is not set +# CONFIG_GPIO_IT8761E is not set +CONFIG_GPIO_XILINX=y +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_VX855 is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_LANGWELL is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_MFD_SUPPORT=y +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC35892 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set +# CONFIG_STUB_POULSBO is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_CT65550 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_IBM_GXT4500 is not set +CONFIG_FB_XILINX=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_UWB is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_XILINX_EDK=y +# CONFIG_XILINX_LLDMA_USE_DCR is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_ROMFS_BACKED_BY_BLOCK=y +CONFIG_ROMFS_ON_BLOCK=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y +CONFIG_NFSD=y +CONFIG_NFSD_DEPRECATED=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m +# CONFIG_DLM is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +CONFIG_BKL=y +# CONFIG_SPARSE_RCU_POINTER is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_RCU_CPU_STALL_DETECTOR=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_DETECTOR_RUNNABLE=y +CONFIG_RCU_CPU_STALL_VERBOSE=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_PPC_DISABLE_WERROR is not set +CONFIG_PPC_WERROR=y +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=m +CONFIG_CRYPTO_ALGAPI2=m +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=m +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=m +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_PPC4XX is not set +# CONFIG_PPC_CLOCK is not set +# CONFIG_VIRTUALIZATION is not set Index: linux-3.12.24-rt38-xilinx/arch/powerpc/configs/44x/avnet_v5fx30t_defconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/configs/44x/avnet_v5fx30t_defconfig 2014-07-20 22:06:34.852330526 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.29-rc5 +# Thu Mar 12 19:42:21 2009 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +CONFIG_44x=y +# CONFIG_E200 is not set +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +CONFIG_PPC_MMU_NOHASH=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_WORD_SIZE=32 +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_MMU=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_HARDIRQS=y +# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set +CONFIG_IRQ_PER_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set +CONFIG_PPC_DCR_NATIVE=y +CONFIG_PPC_DCR_MMIO=y +CONFIG_PPC_DCR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_PCI_QUIRKS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_FREEZER is not set +# CONFIG_PPC4xx_PCI_EXPRESS is not set + +# +# Platform support +# +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +# CONFIG_BAMBOO is not set +# CONFIG_EBONY is not set +# CONFIG_SAM440EP is not set +# CONFIG_SEQUOIA is not set +# CONFIG_TAISHAN is not set +# CONFIG_KATMAI is not set +# CONFIG_RAINIER is not set +# CONFIG_WARP is not set +# CONFIG_ARCHES is not set +# CONFIG_CANYONLANDS is not set +# CONFIG_GLACIER is not set +# CONFIG_YOSEMITE is not set +CONFIG_XILINX_VIRTEX440_GENERIC_BOARD=y +# CONFIG_PPC44x_SIMPLE is not set +# CONFIG_PPC4xx_GPIO is not set +CONFIG_XILINX_VIRTEX_5_FXT=y +# CONFIG_IPIC is not set +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_FSL_ULI1575 is not set +CONFIG_XILINX_VIRTEX=y +# CONFIG_SIMPLE_GPIO is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_MATH_EMULATION=y +# CONFIG_IOMMU_HELPER is not set +CONFIG_PPC_NEED_DMA_SYNC_OPS=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_WALK_MEMORY=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_64K_PAGES is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +CONFIG_EXTRA_TARGETS="simpleImage.virtex440-avnet-v5fx30t simpleImage.initrd.virtex440-avnet-v5fx30t" +CONFIG_SECCOMP=y +# CONFIG_COMPRESSED_DEVICE_TREE is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_4xx_SOC=y +CONFIG_PPC_PCI_CHOICE=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_STUB is not set +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HAS_RAPIDIO is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_PAGE_OFFSET=0xc0000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_PHYSICAL_START=0x00000000 +CONFIG_TASK_SIZE=0xc0000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_NET=y + +# +# Networking options +# +CONFIG_COMPAT_NET_DEV_OPS=y +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NF_CONNTRACK is not set +CONFIG_NETFILTER_XTABLES=m +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_TTL is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_LOG is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_ARPTABLES is not set + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_PHONET is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_OLD_REGULATORY=y +# CONFIG_WIRELESS_EXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_PARTITIONS is not set +# CONFIG_MTD_TESTS is not set + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +# CONFIG_MTD_BLKDEVS is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_OF is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_QINFO_PROBE is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_XILINX_SYSACE is not set +# CONFIG_XILINX_SYSACE_OLD is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_93CX6 is not set +CONFIG_XILINX_DRIVERS=y +CONFIG_NEED_XILINX_LLDMA=y +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# Enable only one of the two stacks, unless you know what you are doing +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_IBM_NEW_EMAC is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_NET_PCI is not set +# CONFIG_B44 is not set +# CONFIG_XILINX_EMAC is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_ATL2 is not set +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_IP1000 is not set +# CONFIG_IGB is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +# CONFIG_XILINX_TEMAC is not set +# CONFIG_ATL1E is not set +CONFIG_XILINX_LLTEMAC=y +# CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_RGMII is not set +# CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_GMII is not set +# CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_MII is not set +CONFIG_XILINX_LLTEMAC_NATIONAL_DP83865_GMII=y +# CONFIG_JME is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_IWLWIFI_LEDS is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_XILINXPS2 is not set +# CONFIG_SERIO_XILINX_XPS_PS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_HVC_UDBG is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=m +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +CONFIG_XILINX_HWICAP=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Graphics adapter I2C/DDC channel drivers +# +# CONFIG_I2C_VOODOO3 is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_SPI is not set +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_REGULATOR is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_CT65550 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_IBM_GXT4500 is not set +CONFIG_FB_XILINX=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_UWB is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +CONFIG_XILINX_EDK=y +CONFIG_XILINX_LLDMA_USE_DCR=y +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=m + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_REGISTER_V4 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=y +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m +# CONFIG_DLM is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_HAVE_LMB=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y + +# +# Tracers +# +# CONFIG_DYNAMIC_PRINTK_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_IRQSTACKS is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_PPC_CLOCK is not set +# CONFIG_VIRTUALIZATION is not set Index: linux-3.12.24-rt38-xilinx/arch/powerpc/configs/44x/virtex5_defconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/configs/44x/virtex5_defconfig 2014-07-20 22:05:50.294065664 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/configs/44x/virtex5_defconfig 2014-07-20 22:06:34.873330180 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Automatically generated make config: don't edit +# Linux/powerpc 2.6.37-rc4 Kernel Configuration +# Wed Dec 15 13:45:41 2010 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_PPC_BOOK3S_32 is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set CONFIG_44x=y +# CONFIG_E200 is not set +# CONFIG_PPC_FPU is not set +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +CONFIG_PPC_MMU_NOHASH=y +CONFIG_PPC_MMU_NOHASH_32=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_32BIT=y +CONFIG_WORD_SIZE=32 +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_MMU=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set +# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set +CONFIG_IRQ_PER_CPU=y +CONFIG_NR_IRQS=512 +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_PPC_DCR_NATIVE=y +CONFIG_PPC_DCR_MMIO=y +CONFIG_PPC_DCR=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_PPC_ADV_DEBUG_REGS=y +CONFIG_PPC_ADV_DEBUG_IACS=4 +CONFIG_PPC_ADV_DEBUG_DACS=2 +CONFIG_PPC_ADV_DEBUG_DVCS=2 +CONFIG_PPC_ADV_DEBUG_DAC_RANGE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y +CONFIG_HAVE_IRQ_WORK=y + +# +# General setup +# CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +# CONFIG_HAVE_GENERIC_HARDIRQS is not set +# CONFIG_SPARSE_IRQ is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +# CONFIG_TINY_RCU is not set +# CONFIG_TINY_PREEMPT_RCU is not set +CONFIG_PREEMPT_RCU=y +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_TREE_RCU_TRACE is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_PCI_QUIRKS=y +CONFIG_COMPAT_BRK=y CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_DMA_API_DEBUG=y + +# +# GCOV-based kernel profiling +# +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +CONFIG_LBDAF=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_FREEZER is not set +# CONFIG_PPC4xx_PCI_EXPRESS is not set + +# +# Platform support +# +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +# CONFIG_PPC_47x is not set +# CONFIG_BAMBOO is not set +# CONFIG_BLUESTONE is not set # CONFIG_EBONY is not set +# CONFIG_SAM440EP is not set +# CONFIG_SEQUOIA is not set +# CONFIG_TAISHAN is not set +# CONFIG_KATMAI is not set +# CONFIG_RAINIER is not set +# CONFIG_WARP is not set +# CONFIG_ARCHES is not set +# CONFIG_CANYONLANDS is not set +# CONFIG_GLACIER is not set +# CONFIG_REDWOOD is not set +# CONFIG_EIGER is not set +# CONFIG_YOSEMITE is not set +# CONFIG_ISS4xx is not set +# CONFIG_ICON is not set CONFIG_XILINX_VIRTEX440_GENERIC_BOARD=y +# CONFIG_XILINX_ML510 is not set +# CONFIG_PPC44x_SIMPLE is not set +# CONFIG_PPC4xx_GPIO is not set +CONFIG_XILINX_VIRTEX=y +CONFIG_XILINX_VIRTEX_5_FXT=y +CONFIG_KVM_GUEST=y +# CONFIG_IPIC is not set +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_MPIC_U3_HT_IRQS is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_FSL_ULI1575 is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_XILINX_PCI is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set CONFIG_MATH_EMULATION=y +# CONFIG_IOMMU_HELPER is not set +# CONFIG_SWIOTLB is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_WALK_MEMORY=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_MAX_ACTIVE_REGIONS=32 +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_NEED_PER_CPU_KM=y +CONFIG_STDBINUTILS=y +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_64K_PAGES is not set +CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" +CONFIG_EXTRA_TARGETS="" +CONFIG_SECCOMP=y +# CONFIG_COMPRESSED_DEVICE_TREE is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_4xx_SOC=y +CONFIG_PPC_PCI_CHOICE=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HAS_RAPIDIO is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_PAGE_OFFSET=0xc0000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_PHYSICAL_START=0x00000000 +CONFIG_TASK_SIZE=0xc0000000 +CONFIG_CONSISTENT_SIZE=0x00200000 CONFIG_NET=y + +# +# Networking options +# CONFIG_PACKET=y CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y # CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_TPROXY is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +# CONFIG_NETFILTER_XT_MARK is not set + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_IP_NF_QUEUE is not set CONFIG_IP_NF_IPTABLES=m +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_TTL is not set CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_LOG is not set +# CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_ARPTABLES is not set + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# + +# +# Some wireless drivers require a rate control algorithm +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# CONFIG_PROC_DEVICETREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_GPIO=y +CONFIG_OF_I2C=y +CONFIG_OF_SPI=y +CONFIG_OF_MDIO=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set CONFIG_XILINX_SYSACE=y +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_RBD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_BMP085 is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +CONFIG_EEPROM_AT25=y +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +CONFIG_XILINX_DRIVERS=y +CONFIG_NEED_XILINX_LLDMA=y +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_ARCNET is not set CONFIG_MII=y +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_DNET is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_IBM_NEW_EMAC is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_NET_PCI is not set +# CONFIG_B44 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_XILINX_EMAC is not set +# CONFIG_ATL2 is not set +CONFIG_XILINX_EMACLITE=y +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_IP1000 is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +# CONFIG_XILINX_TEMAC is not set +# CONFIG_ATL1E is not set +CONFIG_XILINX_LLTEMAC=y +# CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_RGMII is not set +CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_GMII=y +# CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_MII is not set +# CONFIG_XILINX_LLTEMAC_NATIONAL_DP83865_GMII is not set +# CONFIG_ATL1C is not set +# CONFIG_JME is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_PCH_GBE is not set # CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set +CONFIG_WLAN=y +# CONFIG_AIRO is not set +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_HOSTAP is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set + +# +# CAIF transport drivers +# +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y # CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_XILINXPS2 is not set CONFIG_SERIO_XILINX_XPS_PS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set + +# +# Serial drivers +# CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +# CONFIG_SERIAL_MFD_HSU is not set CONFIG_SERIAL_UARTLITE=y CONFIG_SERIAL_UARTLITE_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=m +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set CONFIG_XILINX_HWICAP=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_SMBUS is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set +CONFIG_XILINX_IIC=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_INTEL_MID is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +CONFIG_SPI_XILINX=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_BASIC_MMIO is not set +# CONFIG_GPIO_IT8761E is not set CONFIG_GPIO_XILINX=y +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_VX855 is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_LANGWELL is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_MFD_SUPPORT=y +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC35892 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set +# CONFIG_STUB_POULSBO is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_CT65550 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_IBM_GXT4500 is not set CONFIG_FB_XILINX=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set CONFIG_FONTS=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_SOUND is not set # CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set +# CONFIG_UWB is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_XILINX_EDK=y +CONFIG_XILINX_LLDMA_USE_DCR=y +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_AUTOFS_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set CONFIG_ROMFS_FS=y +CONFIG_ROMFS_BACKED_BY_BLOCK=y +CONFIG_ROMFS_ON_BLOCK=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set CONFIG_NLS_ASCII=m CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set CONFIG_NLS_UTF8=m +# CONFIG_DLM is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y + +# +# Kernel hacking +# CONFIG_PRINTK_TIME=y +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_KMEMLEAK is not set +CONFIG_DEBUG_PREEMPT=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +CONFIG_BKL=y +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_RCU_TORTURE_TEST is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_PPC_DISABLE_WERROR is not set +CONFIG_PPC_WERROR=y +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_XMON is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_PPC4XX is not set +# CONFIG_PPC_CLOCK is not set +# CONFIG_VIRTUALIZATION is not set Index: linux-3.12.24-rt38-xilinx/arch/powerpc/kernel/entry_32.S =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/kernel/entry_32.S 2014-07-20 22:05:50.304065499 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/kernel/entry_32.S 2014-07-20 22:06:34.892329866 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:702 @ andc r11,r11,r0 MTMSRD(r11) isync +#if defined(CONFIG_XILINX_VIRTEX_5_FXT) && defined(CONFIG_PPC_FPU) + mfspr r5,SPRN_CCR0 + andis. r5,r5, ~(1<<6)@l + andi. r5,r5, ~(1<<5)@l + mtspr SPRN_CCR0,r5 + isync +#endif 1: stw r11,_MSR(r1) mfcr r10 stw r10,_CCR(r1) Index: linux-3.12.24-rt38-xilinx/arch/powerpc/kernel/fpu.S =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/kernel/fpu.S 2014-07-20 22:05:50.303065516 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/kernel/fpu.S 2014-07-20 22:06:34.903329685 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:127 @ * enable the FPU for the current task and return to the task. */ _GLOBAL(load_up_fpu) +#if defined(CONFIG_XILINX_VIRTEX_5_FXT) && defined(CONFIG_PPC_FPU) + li r3,0 + lis r5,excep_state@h + ori r5,r5,excep_state@l + stw r3,0(r5) + + mfspr r5,SPRN_CCR0 + /* set CCR0[9] to disable the load miss queue inside the ppc440 */ + oris r5,r5, (1<<6) + /* set CCR0[26] to ... */ + ori r5,r5, (1<<5) + mtspr SPRN_CCR0,r5 + isync +#endif + mfmsr r5 ori r5,r5,MSR_FP #ifdef CONFIG_VSX @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:209 @ * Enables the FPU for use in the kernel on return. */ _GLOBAL(giveup_fpu) +#if defined(CONFIG_XILINX_VIRTEX_5_FXT) && defined(CONFIG_PPC_FPU) + mfspr r5,SPRN_CCR0 + /* set CCR0[9] to disable the load miss queue inside the ppc440 */ + oris r5,r5, (1<<6) + /* set CCR0[26] to ... */ + ori r5,r5, (1<<5) + mtspr SPRN_CCR0,r5 + isync +#endif + mfmsr r5 ori r5,r5,MSR_FP #ifdef CONFIG_VSX Index: linux-3.12.24-rt38-xilinx/arch/powerpc/kernel/head_44x.S =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/kernel/head_44x.S 2014-07-20 22:05:50.302065532 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/kernel/head_44x.S 2014-07-20 22:06:34.918329437 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:99 @ bl init_cpu_state /* + * The following code is needed to make GDB work with soft breakpoints. + * This patch was provided by Brian Hill. + */ + lis r2,DBCR0_IDM@h + mtspr SPRN_DBCR0,r2 + isync + + /* clear any residual debug events */ + li r2,-1 + mtspr SPRN_DBSR,r2 + + /* * This is where the main kernel code starts. */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:947 @ tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ + /* Force context change */ +#ifdef CONFIG_XILINX_VIRTEX_5_FXT + /* We can not use the content of the MSR register when we are using XMD + * to connect to a ml5xx board as XMD changes the contents of the MSR + * register. We load the default value instead. + * + * EDK 10.1 fixes this issue so this should be removed once the automated + * testing is updated to 10.1 tools. + */ + lis r0,MSR_KERNEL@h + ori r0,r0,MSR_KERNEL@l +#else mfmsr r0 +#endif mtspr SPRN_SRR1, r0 lis r0,3f@h ori r0,r0,3f@l Index: linux-3.12.24-rt38-xilinx/arch/powerpc/kernel/traps.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/kernel/traps.c 2014-07-20 22:05:50.301065548 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/kernel/traps.c 2014-07-20 22:06:34.936329140 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:83 @ EXPORT_SYMBOL(__debugger_fault_handler); #endif +#if defined(CONFIG_XILINX_VIRTEX_5_FXT) && defined(CONFIG_PPC_FPU) +u8 excep_state = 0; +#endif + /* Transactional Memory trap debug */ #ifdef TM_DEBUG_SW #define TM_DEBUG(x...) printk(KERN_INFO x) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1181 @ if (!emulate_math(regs)) goto bail; +#if defined(CONFIG_XILINX_VIRTEX_5_FXT) && defined(CONFIG_PPC_FPU) + if (reason & REASON_ILLEGAL) { + if (excep_state < 1) { + excep_state++; + return; + } + /* should never get here */ + BUG(); + } +#endif + /* Try to emulate it if we should. */ if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { switch (emulate_instruction(regs)) { Index: linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/40x/40x.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/40x/40x.h 2014-07-20 22:06:34.950328910 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:3 @ +#ifndef __POWERPC_PLATFORMS_40X_40X_H +#define __POWERPC_PLATFORMS_40X_40X_H + +extern void ppc40x_reset_system(char *cmd); + +#endif /* __POWERPC_PLATFORMS_44X_44X_H */ Index: linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/40x/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/platforms/40x/Makefile 2014-07-20 22:05:50.300065565 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/40x/Makefile 2014-07-20 22:06:34.958328778 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ obj-$(CONFIG_WALNUT) += walnut.o -obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o +obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o misc_40x.o obj-$(CONFIG_EP405) += ep405.o obj-$(CONFIG_PPC40x_SIMPLE) += ppc40x_simple.o Index: linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/40x/misc_40x.S =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/40x/misc_40x.S 2014-07-20 22:06:34.966328646 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * This file contains miscellaneous low-level functions for PPC 44x. + * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation. + * + * 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. + * + */ + +#include <asm/reg.h> +#include <asm/ppc_asm.h> + + .text + +/* + * void ppc40x_reset_system(char *cmd) + * + * At present, this routine just applies a system reset. + */ +_GLOBAL(ppc40x_reset_system) + mfspr r13,SPRN_DBCR0 + oris r13,r13,DBCR0_RST_SYSTEM@h + mtspr SPRN_DBCR0,r13 + blr Index: linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/40x/virtex.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/platforms/40x/virtex.c 2014-07-20 22:05:50.299065581 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/40x/virtex.c 2014-07-20 22:06:34.974328514 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:21 @ #include <asm/ppc4xx.h> static struct of_device_id xilinx_of_bus_ids[] __initdata = { + { .compatible = "simple-bus", }, { .compatible = "xlnx,plb-v46-1.00.a", }, + { .compatible = "xlnx,plb-v46-1.02.a", }, { .compatible = "xlnx,plb-v34-1.01.a", }, { .compatible = "xlnx,plb-v34-1.02.a", }, { .compatible = "xlnx,opb-v20-1.10.c", }, Index: linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/44x/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/platforms/44x/Kconfig 2014-07-20 22:05:50.296065631 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/44x/Kconfig 2014-07-20 22:06:34.989328266 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:254 @ help Enable gpiolib support for ppc440 based boards +config XILINX_PPC_FPU + depends on XILINX_VIRTEX_5_FXT + bool "Enable Xilinx Soft FPU" + select PPC_FPU + default n + help + This option enables the Xilinx Soft FPU attached to the APU + interface of the PPC440 (requires DP_FULL FPU pcore). + config PPC4xx_OCM bool "PPC4xx On Chip Memory (OCM) support" depends on 4xx Index: linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/platforms/Kconfig 2014-07-20 22:05:50.297065614 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/platforms/Kconfig 2014-07-20 22:06:35.000328085 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:335 @ config CPM bool +config XILINX_VIRTEX + bool + select PPC_DCR_MMIO + select PPC_DCR_NATIVE + help + Support for Xilinx Virtex platforms. + config OF_RTC bool help Index: linux-3.12.24-rt38-xilinx/arch/powerpc/sysdev/xilinx_pci.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/arch/powerpc/sysdev/xilinx_pci.c 2014-07-20 22:05:50.295065648 +0200 +++ linux-3.12.24-rt38-xilinx/arch/powerpc/sysdev/xilinx_pci.c 2014-07-20 22:06:35.014327854 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:118 @ /* Set the max latency timer to 255 */ early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff); - /* Set the max bus number to 255 */ + /* Set the max bus number to 255, and bus/subbus no's to 0 */ pci_reg = of_iomap(pci_node, 0); - out_8(pci_reg + XPLB_PCI_BUS, 0xff); + out_be32(pci_reg + XPLB_PCI_BUS, 0x000000ff); iounmap(pci_reg); /* Nothing past the root bridge is working right now. By default Index: linux-3.12.24-rt38-xilinx/config =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/config 2014-07-20 22:06:35.046327326 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.12.14 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="-xilinx" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +# CONFIG_AUDIT is not set + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_CPU_IDLERUNTIME=y +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=1 +CONFIG_RCU_BOOST_DELAY=500 +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_IKPATCHSET is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_GENERIC_SCHED_CLOCK=y +# CONFIG_CGROUPS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_PCI_QUIRKS=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_FREEZER is not set + +# +# System Type +# +CONFIG_MMU=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set + +# +# Multiple platform selection +# + +# +# CPU Core family selection +# +# CONFIG_ARCH_MULTI_V6 is not set +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_MULTI_V6_V7=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U8500 is not set +CONFIG_ARCH_VEXPRESS=y + +# +# Versatile Express platform type +# +CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y +# CONFIG_ARCH_VEXPRESS_CA9X4 is not set +CONFIG_PLAT_VERSATILE_CLCD=y +CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_WM8850 is not set +CONFIG_ARCH_ZYNQ=y + +# +# Xilinx Specific Options +# +CONFIG_XILINX_L1_PREFETCH=y +CONFIG_XILINX_L2_PREFETCH=y +CONFIG_XILINX_AXIPCIE=y +CONFIG_PLAT_VERSATILE=y +CONFIG_ARM_TIMER_SP804=y + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +CONFIG_PL310_ERRATA_588369=y +# CONFIG_ARM_ERRATA_643719 is not set +CONFIG_ARM_ERRATA_720789=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_ERRATA_775420=y +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_773022 is not set +CONFIG_ICST=y + +# +# Bus support +# +CONFIG_ARM_AMBA=y +CONFIG_PCI=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set + +# +# PCI host controller drivers +# +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HAVE_ARM_SCU=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_ARM_TWD=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_ARCH_NR_GPIO=1024 +CONFIG_PREEMPT=y +CONFIG_PREEMPT_RT_BASE=y +CONFIG_HAVE_PREEMPT_LAZY=y +CONFIG_PREEMPT_LAZY=y +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT__LL is not set +# CONFIG_PREEMPT_RTB is not set +CONFIG_PREEMPT_RT_FULL=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ_FIXED=0 +CONFIG_HZ_100=y +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +# CONFIG_ZBUD is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_XEN is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/mmcblk0p2 rw earlyprintk" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_ARM_ZYNQ_CPUFREQ=y + +# +# CPU Idle +# +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +# CONFIG_KERNEL_MODE_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +# CONFIG_SUSPEND is not set +# CONFIG_PM_RUNTIME is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=y +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_IP_MROUTE is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NET_MPLS_GSO is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_CMA is not set + +# +# Bus devices +# +# CONFIG_ARM_CCI is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +CONFIG_MTD_M25P80=y +# CONFIG_M25PXX_USE_FAST_READ is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_ZYNQ=y +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_MTD=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_VIRTIO_BLK is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +CONFIG_HWLAT_DETECTOR=y +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_ARM_CHARLCD is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_SI570 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_SRAM=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_HAVE_PATA_PLATFORM=y +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_VIRTIO_NET is not set +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMD is not set +CONFIG_NET_VENDOR_ARC=y +# CONFIG_ARC_EMAC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +CONFIG_MACB=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +CONFIG_TIGON3=y +# CONFIG_BNX2X is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EXAR is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +CONFIG_E1000E=y +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +CONFIG_NET_VENDOR_I825XX=y +# CONFIG_IP1000 is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +CONFIG_R8169=y +# CONFIG_SH_ETH is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_SFC is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +CONFIG_XILINX_EMACLITE=y +CONFIG_XILINX_AXI_EMAC=y +CONFIG_XILINX_PS_EMAC=y +# CONFIG_XILINX_PS_EMAC_HWTSTAMP is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +CONFIG_MARVELL_PHY=y +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +CONFIG_VITESSE_PHY=y +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y +# CONFIG_MDIO_GPIO is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_HOSTAP is not set +# CONFIG_WL_TI is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_OLPC_APSP is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_PCH_UART is not set +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +CONFIG_XILINX_DEVCFG=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_VERSATILE is not set +CONFIG_I2C_ZYNQ=y +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +CONFIG_SPI_XILINX=y +CONFIG_SPI_ZYNQ_QSPI=y +# CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED is not set +CONFIG_SPI_ZYNQ=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_HSI is not set + +# +# PPS support +# +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +CONFIG_GPIO_XILINX=y +CONFIG_GPIO_ZYNQ=y +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# LPC GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_SMB347 is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_RESTART is not set +CONFIG_POWER_RESET_VEXPRESS=y +# CONFIG_POWER_AVS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_SENSORS_XADCPS=y +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +CONFIG_ZYNQ_WATCHDOG=y +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +CONFIG_XILINX_WATCHDOG=y +# CONFIG_MEN_A21_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_VEXPRESS_CONFIG=y +# CONFIG_REGULATOR is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set + +# +# Supported MMC/SDIO adapters +# +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_XILINX is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +CONFIG_FB_XYLON=y +# CONFIG_FB_XYLON_PLATFORM is not set +CONFIG_FB_XYLON_OF=y +# CONFIG_FB_XYLON_PIXCLK is not set +# CONFIG_FB_XYLON_MISC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_SOUND is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_HUION is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO_TPKBD is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +CONFIG_HID_MICROSOFT=y +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_XUSBPS_DR_OF=y +CONFIG_USB_EHCI_XUSBPS=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_RCAR_PHY is not set +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +CONFIG_USB_GADGET_XUSBPS=y +CONFIG_XUSBPS_ERRATA_DT654401=y +CONFIG_USB_XUSBPS=y +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_R8A66597 is not set +CONFIG_USB_GADGET_XILINX=y +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_AMD5536UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_U_ETHER=y +CONFIG_USB_U_RNDIS=y +CONFIG_USB_F_ECM=y +CONFIG_USB_F_SUBSET=y +CONFIG_USB_F_RNDIS=y +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_ZERO is not set +CONFIG_USB_ETH=y +CONFIG_USB_ETH_RNDIS=y +# CONFIG_USB_ETH_EEM is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_UWB is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_ARMMMCI is not set +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=y +CONFIG_EDAC_ZYNQ=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +CONFIG_RTC_DRV_PCF8563=y +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_MOXART is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_XILINX_DMA_ENGINES=y +CONFIG_XILINX_AXIDMA=y +# CONFIG_XILINX_DMATEST is not set +CONFIG_XILINX_AXIVDMA=y +# CONFIG_XILINX_VDMATEST is not set +CONFIG_XILINX_AXICDMA=y +# CONFIG_XILINX_CDMATEST is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_DW_DMAC_CORE is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_TIMB_DMA is not set +CONFIG_PL330_DMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_MF624 is not set +CONFIG_UIO_XILINX_APM=y +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=y + +# +# Virtio drivers +# +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +CONFIG_COMMON_CLK_DEBUG=y +CONFIG_COMMON_CLK_VERSATILE=y +# CONFIG_COMMON_CLK_SI5351 is not set +CONFIG_COMMON_CLK_SI570=y +# CONFIG_COMMON_CLK_AXI_CLKGEN is not set + +# +# Hardware Spinlock drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CADENCE_TTC_TIMER=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y + +# +# Remoteproc drivers +# +CONFIG_REMOTEPROC=y +# CONFIG_STE_MODEM_RPROC is not set +CONFIG_ZYNQ_REMOTEPROC=y +CONFIG_MB_REMOTEPROC=y + +# +# Rpmsg drivers +# +CONFIG_RPMSG=y +# CONFIG_RPMSG_SERVER_SAMPLE is not set +# CONFIG_RPMSG_OMX is not set +# CONFIG_RPMSG_FREERTOS_STAT is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +CONFIG_MEMORY=y +CONFIG_ZYNQ_SMC=y +# CONFIG_IIO is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_FMC is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_KERNEL=y + +# +# Memory Debugging +# +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_HIGHMEM is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_PREEMPT=y + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_TRACE_IRQFLAGS=y +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_RING_BUFFER_ALLOW_SWAP=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_INTERRUPT_OFF_HIST=y +CONFIG_PREEMPT_TRACER=y +CONFIG_PREEMPT_OFF_HIST=y +CONFIG_SCHED_TRACER=y +CONFIG_WAKEUP_LATENCY_HIST=y +CONFIG_MISSED_TIMER_OFFSETS_HIST=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_PROBE_EVENTS is not set +CONFIG_DYNAMIC_FTRACE=y +# CONFIG_FUNCTION_PROFILER is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set + +# +# Runtime Testing +# +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_OLD_MCOUNT=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ZYNQ_UART0 is not set +CONFIG_DEBUG_ZYNQ_UART1=y +# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set +# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set +# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +CONFIG_DEBUG_LL_INCLUDE="debug/zynq.S" +# CONFIG_DEBUG_UART_PL01X is not set +# CONFIG_DEBUG_UART_8250 is not set +CONFIG_DEBUG_UNCOMPRESS=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_EARLY_PRINTK=y +# CONFIG_OC_ETM is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_FONT_SUPPORT=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_VIRTUALIZATION=y Index: linux-3.12.24-rt38-xilinx/debian/changelog =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/debian/changelog 2014-07-20 22:06:35.055327178 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2 @ +linux-image-zedboard-3.12.14-rt23 (3.12.14-rt23-2) unstable; urgency=low + + * Custom built Linux kernel. + + -- Anonymous <root@slartibartfast.linutronix> Wed, 04 Jun 2014 08:42:05 +0200 Index: linux-3.12.24-rt38-xilinx/debian/control =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/debian/control 2014-07-20 22:06:35.060327095 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Source: linux-image-zedboard-3.12.14-rt23 +Section: kernel +Priority: optional +Maintainer: Anonymous <root@slartibartfast.linutronix> +Standards-Version: 3.8.4 +Homepage: http://www.kernel.org/ + +Package: linux-image-zedboard-3.12.14-rt23 +Provides: linux-image, linux-image-2.6, linux-modules-3.12.14-rt23 +Suggests: linux-firmware-image-zedboard-3.12.14-rt23 +Architecture: any +Description: Linux kernel, version 3.12.14-rt23 + This package contains the Linux kernel, modules and corresponding other + files, version: 3.12.14-rt23. + +Package: linux-headers-zedboard-3.12.14-rt23 +Provides: linux-headers, linux-headers-2.6 +Architecture: any +Description: Linux kernel headers for 3.12.14-rt23 on amd64 + This package provides kernel header files for 3.12.14-rt23 on amd64 + . + This is useful for people who need to build external modules + +Package: linux-libc-dev +Section: devel +Provides: linux-kernel-headers +Architecture: any +Description: Linux support headers for userspace development + This package provides userspaces headers from the Linux kernel. These headers + are used by the installed headers for GNU glibc and other system libraries. Index: linux-3.12.24-rt38-xilinx/debian/copyright =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/debian/copyright 2014-07-20 22:06:35.066326996 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +This is a packacked upstream version of the Linux kernel. + +The sources may be found at most Linux ftp sites, including: +ftp://ftp.kernel.org/pub/linux/kernel + +Copyright: 1991 - 2009 Linus Torvalds and others. + +The git repository for mainline kernel development is at: +git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 dated June, 1991. + +On Debian GNU/Linux systems, the complete text of the GNU General Public +License version 2 can be found in `/usr/share/common-licenses/GPL-2'. Index: linux-3.12.24-rt38-xilinx/debian/source/format =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/debian/source/format 2014-07-20 22:06:35.075326848 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ +3.0 (git) Index: linux-3.12.24-rt38-xilinx/debian/source/options =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/debian/source/options 2014-07-20 22:06:35.080326765 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ +git-ref=HEAD +git-depth=3 Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/arm/zynq/xlnx,zynq-ocm.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/arm/zynq/xlnx,zynq-ocm.txt 2014-07-20 22:06:35.096326501 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Device tree bindings for Zynq's OCM + +The OCM is divided to 4 64kB segments which can be separately configured +to low or high location. Location is controlled via SLCR. + +Required properties: + compatible: Compatibility string. Must be "xlnx,zynq-ocm-1.0". + reg: Specify the base and size of the OCM registers in the memory map. + E.g.: reg = <0xf800c000 0x1000>; + +Example: +ps7_ram_0: ps7-ram@f800c000 { + compatible = "xlnx,zynq-ocm-1.0"; + reg = <0xf800c000 0x1000>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 3 4>; +} ; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/arm/zynq/xlnx,zynq-smc.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/arm/zynq/xlnx,zynq-smc.txt 2014-07-20 22:06:35.102326402 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Device tree bindings for Zynq's SMC (PL353) + +The SMC supports NAND, NOR and SRAM memory. The SMC driver handles generic +tasks, while children drivers handle memory type specifics. + +Required properties: + compatible: Compatibility string. Must be "xlnx,ps7-smc". + reg: Specify the base and size of the SMC registers in the memory map. + E.g.: reg = <0xe000e000 0x1000>; + #address-cells: Address cells, must be 1. + #size-cells: Size cells. Must be 1. + ranges + +Child nodes: + For NAND the "xlnx,ps7-nand" and for NOR the "cfi-flash" drivers are supported + as child nodes. + +Example: + ps7_smc_0: ps7-smc@e000e000 { + compatible = "xlnx,ps7-smc"; + reg = <0xe000e000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + ps7_nand_0: ps7-nand@e1000000 { + compatible = "xlnx,ps7-nand-1.00.a"; + (...) + }; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/clock/silabs,si570.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/clock/silabs,si570.txt 2014-07-20 22:06:35.113326221 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Binding for Silicon Labs 570, 571, 598 and 599 programmable +I2C clock generators. + +Reference +This binding uses the common clock binding[1]. Details about the devices can be +found in the data sheets[2][3]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Si570/571 Data Sheet + http://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf +[3] Si598/599 Data Sheet + http://www.silabs.com/Support%20Documents/TechnicalDocs/si598-99.pdf + +Required properties: + - compatible: Shall be one of "silabs,si570", "silabs,si571", + "silabs,si598", "silabs,si599" + - reg: I2C device address. + - #clock-cells: From common clock bindings: Shall be 0. + - factory-fout: Factory set default frequency. This frequency is part specific. + The correct frequency for the part used has to be provided in + order to generate the correct output frequencies. For more + details, please refer to the data sheet. + - temperature-stability: Temperature stability of the device in PPM. Should be + one of: 7, 20, 50 or 100. + +Optional properties: + - clock-output-names: From common clock bindings. Recommended to be "si570". + - clock-frequency: Output frequency to generate. This defines the output + frequency set during boot. It can be reprogrammed during + runtime through the common clock framework. + +Example: + si570: clock-generator@5d { + #clock-cells = <0>; + compatible = "silabs,si570"; + temperature-stability = <50>; + reg = <0x5d>; + factory-fout = <156250000>; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/clock/zynq-7000.txt =================================================================== --- linux-3.12.24-rt38-xilinx.orig/Documentation/devicetree/bindings/clock/zynq-7000.txt 2014-07-20 22:05:50.329065087 +0200 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/clock/zynq-7000.txt 2014-07-20 22:06:35.121326089 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:25 @ Optional properties: - clocks : as described in the clock bindings - clock-names : as described in the clock bindings + - fclk-enable : Bit mask to enable FCLKs in cases no proper CCF compatible + driver is available. Bit [0..3] correspond to FCLK0..FCLK3. The + corresponding FCLK will only be enabled if it is actually + running at boot time. Clock inputs: The following strings are optional parameters to the 'clock-names' property in Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/dma/xilinx/axi-cdma.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/dma/xilinx/axi-cdma.txt 2014-07-20 22:06:35.135325858 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Xilinx AXI CDMA engine, it does transfers between memory and memory + +Required properties: +- compatible: Should be "xlnx,axi-cdma" +- reg: Should contain CDMA registers location and length. +- interrupts: Should contain channel CDMA interrupts. + +Example: +++++++++ + +axi_cdma_0: axicdma@40030000 { + compatible = "xlnx,axi-cdma"; + reg = < 0x40030000 0x10000 >; + dma-channel@40030000 { + interrupts = < 0 59 4 >; + } ; +} ; + Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/dma/xilinx/axi-dma.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/dma/xilinx/axi-dma.txt 2014-07-20 22:06:35.141325759 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Xilinx AXI DMA engine, it does transfers between memory and device. It can be +configured to have one channel or two channels. If configured as two +channels, one is to transmit to device and another is to receive from +device. + +Required properties: +- compatible: Should be "xlnx,axi-dma" +- reg: Should contain DMA registers location and length. +- interrupts: Should contain per channel DMA interrupts. +- compatible (child node): It should be either "xlnx,axi-dma-mm2s-channel" or + "xlnx,axi-dma-s2mm-channel". It depends on the hardware design and it + can also have both channels. + +Example: +++++++++ + +axi_dma_0: axidma@40400000 { + compatible = "xlnx,axi-dma"; + reg = < 0x40400000 0x10000 >; + dma-channel@40400000 { + compatible = "xlnx,axi-dma-mm2s-channel"; + interrupts = < 0 59 4 >; + } ; + dma-channel@40030030 { + compatible = "xlnx,axi-dma-s2mm-channel"; + interrupts = < 0 58 4 >; + } ; +} ; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/dma/xilinx/axi-vdma.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/dma/xilinx/axi-vdma.txt 2014-07-20 22:06:35.147325660 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Xilinx AXI VDMA engine, it does transfers between memory and video devices. +It can be configured to have one channel or two channels. If configured +as two channels, one is to transmit to the video device and another is +to receive from the video device. + +Required properties: +- compatible: Should be "xlnx,axi-vdma" +- #dma-cells: Should be <1>, see "dmas" property below +- reg: Should contain VDMA registers location and length. +- interrupts: Should contain per channel VDMA interrupts. +- compatible (child node): It should be either "xlnx,axi-vdma-mm2s-channel" or + "xlnx,axi-vdma-s2mm-channel". It depends on the hardware design and it + can also have both channels. +- xlnx,device-id: Should contain device number in each channel. It should be + {0,1,2...so on} to the number of VDMA devices configured in hardware. +- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w. +- xlnx,data-width: Should contain the stream data width, takes {32,64...so on}. +- xlnx,flush-fsync: (Optional) Tells whether which channel to Flush on Fsync. + It takes following values: + {1}, flush both channels + {2}, flush mm2s channel + {3}, flush s2mm channel +- xlnx,include-sg: (Optional) Tells whether configured for Scatter-mode in + the hardware. +- xlnx,include-dre: (Optional) Tells whether hardware is configured for Data + Realignment Engine. +- xlnx,genlock-mode: (Optional) Tells whether Genlock synchornisation is + enabled/disabled in hardware. + +Example: +++++++++ + +axi_vdma_0: axivdma@40030000 { + compatible = "xlnx,axi-vdma"; + #dma_cells = <1>; + reg = < 0x40030000 0x10000 >; + xlnx,flush-fsync = <0x1>; + dma-channel@40030000 { + compatible = "xlnx,axi-vdma-mm2s-channel"; + interrupts = < 0 54 4 >; + xlnx,num-fstores = <0x8>; + xlnx,device-id = <0x0>; + xlnx,datawidth = <0x40>; + } ; + dma-channel@40030030 { + compatible = "xlnx,axi-vdma-s2mm-channel"; + interrupts = < 0 53 4 >; + xlnx,num-fstores = <0x8>; + xlnx,device-id = <0x0>; + xlnx,datawidth = <0x40>; + } ; +} ; + + +* Xilinx Video DMA client + +Required properties: +- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs, + where Channel ID is '0' for write/tx and '1' for read/rx + channel. +- dma-names: a list of DMA channel names, one per "dmas" entry + +VDMA Test Client Example: ++++++++++++++++++++++++++ + +vdmatest_0: vdmatest@0 { + compatible ="xlnx,axi-vdma-test"; + dmas = <&axi_vdma_0 0 + &axi_vdma_0 1>; + dma-names = "vdma0", "vdma1"; +} ; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/dma/xilinx/vdmatest.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/dma/xilinx/vdmatest.txt 2014-07-20 22:06:35.153325561 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +* Xilinx Video DMA Test client + +Required properties: +- compatible: Should be "xlnx,axi-vdma-test" +- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs, + where Channel ID is '0' for write/tx and '1' for read/rx + channel. +- dma-names: a list of DMA channel names, one per "dmas" entry +- xlnx,num-fstores: Should be the number of framebuffers as configured in + VDMA device node. + +Example: +++++++++ + +vdmatest_0: vdmatest@0 { + compatible ="xlnx,axi-vdma-test"; + dmas = <&axi_vdma_0 0 + &axi_vdma_0 1>; + dma-names = "vdma0", "vdma1"; + xlnx,num-fstores = <0x8>; +} ; + + +Xilinx Video DMA Device Node Example +++++++++++++++++++++++++++++++++++++ +axi_vdma_0: axivdma@44A40000 { + compatible = "xlnx,axi-vdma"; + ... + dma-channel@44A40000 { + ... + xlnx,num-fstores = <0x8>; + ... + } ; + dma-channel@44A40030 { + ... + xlnx,num-fstores = <0x8>; + ... + } ; +} ; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/cresample.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/cresample.txt 2014-07-20 22:06:35.165325363 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Device-Tree bindings for Xilinx Chroma Resampler(CRESAMPLE) + +Xilinx CRESAMPLE provides the chroma resampling of YUV formats. + +Required properties: + - compatible: value should be "xlnx,v-cresample-3.01.a" + - reg: base address and size of the CRESAMPLE IP + - xlnx,input-format, xlnx,output-format: the input/output video formats of + CRESAMPLE. The value should be one of following format strings. + + yuv422 + yuv444 + yuv420 + +Example: + + v_cresample_0: v-cresample@40020000 { + compatible = "xlnx,v-cresample-3.01.a"; + reg = <0x40020000 0x10000>; + xlnx,input-format = "yuv444"; + xlnx,output-format = "yuv422"; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/osd.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/osd.txt 2014-07-20 22:06:35.171325264 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Device-Tree bindings for Xilinx Video On Screen Display(OSD) + +Xilinx OSD provides the multiplane support. Some properties can be configured +in IP synthesis. + +Required properties: + - compatible: value should be "xlnx,v-osd-5.01.a" + - reg: base address and size of the OSD IP + - xlnx,num-layers: the number of layers(up to 8) supported by OSD + - xlnx,screen-width: the maximum size(up to 4096) of screen pixel width by OSD + +Example: + + v_osd_0: v-osd@40040000 { + compatible = "xlnx,v-osd-5.01.a"; + reg = <0x40040000 0x10000>; + xlnx,num-layers = <2>; + xlnx,screen-width = <1920>; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/rgb2ycrcb.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/rgb2ycrcb.txt 2014-07-20 22:06:35.177325165 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Device-Tree bindings for Xilinx RGB to YCrCb convertor(RGB2YCRCB) + +Xilinx RGB2YCRCB converts the pixel format from RGB to YCrCb + +Required properties: + - compatible: value should be "xlnx,v-rgb2ycrcb-6.01.a" + - reg: base address and size of the RGB2YCRCB IP + +Example: + + v_rgb2ycrcb_0: v-rgb2ycrcb@40030000 { + compatible = "xlnx,v-rgb2ycrcb-6.01.a"; + reg = <0x40030000 0x10000>; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/vtc.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/vtc.txt 2014-07-20 22:06:35.183325066 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Device-Tree bindings for Xilinx Video Timing Controller(VTC) + +Xilinx VTC provides the timings for Video IPs. + +Required properties: + - compatible: value should be "xlnx,v-tc-5.01.a" + - reg: base address and size of the VTC IP + - interrupts: the interrupt number + - interrupts-parent: the phandle for interrupt controller + +Example: + + v_tc_0: v-tc@40010000 { + compatible = "xlnx,v-tc-5.01.a"; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 54 4>; + reg = <0x40010000 0x10000>; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/xilinx_drm.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/drm/xilinx/xilinx_drm.txt 2014-07-20 22:06:35.190324951 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Device-Tree bindings for Xilinx DRM + +Xilinx DRM supports the display pipelines with Xilinx soft IPs on FPGA and +IPs on Xilinx boards. + +The example hardware pipeline is depicted below +(*IPs in parentheses() are optional. IPs in brackets[] don't require drivers). +vdma-[remap]-(rgb2yuv)-(cresample)-(osd)-(rgb2yuv)-(cresample)-[axi2vid]-adv7511 +(vdma-[remap]-(rgb2yuv)-(cresample)-|) | + si570 -> vtc + +Required properties: + - compatible: value should be "xlnx,drm". + - osd: the phandle for on screen display IP if used in the hardware design + - rgb2yuv: the phandle for rgb2ycrcb IP if used in the hardware design + - cresample: the phandle for chroma resampler IP if used in the hardware design + - vtc: the phandle for video timing controller IP + - encoder-slave: the phandle for the encoder slave. + - clocks: the phandle for the pixel clock + - planes: the subnode for resources for each plane + +Required plane properties: + - dmas: the phandle list of DMA specifiers + - dma-names: the indentifier strings for DMAs + - rgb2yuv: the phandle for rgb2ycrcb IP if used for plane + - cresample: the phandle for chroma resampler IP if used for plane + +The pipeline can be configured as following examples or more. + - Example 1: +vdma - [remap] - rgb2yuv - cresample - [axi2vid] - adv7511 + | + si570 - vtc + xilinx_drm { + compatible = "xlnx,drm"; + vtc = <&v_tc_0>; + encoder-slave = <&adv7511>; + clocks = <&si570>; + planes { + plane0 { + dma = <&axi_vdma_0>; + dma-names = "vdma"; + rgb2yuv = <&v_rgb2ycrcb_0>; + cresample = <&v_cresample_0>; + }; + }; + }; + + - Example 2: +vdma - [remap] --------- osd - cresample - [axi2vid] - adv7511 +vdma - [remap] - rgb2yuv -| | + si570 - vtc + + xilinx_drm { + compatible = "xlnx,drm"; + osd = <&v_osd_0>; + cresample = <&v_cresample_0>; + vtc = <&v_tc_0>; + encoder-slave = <&adv7511>; + clocks = <&si570>; + planes { + plane0 { + dma = <&axi_vdma_0>; + dma-names = "vdma"; + }; + plane1 { + dma = <&axi_vdma_1>; + dma-names = "vdma"; + rgb2yuv = <&v_rgb2ycrcb_0>; + }; + }; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/edac/zynq_edac.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/edac/zynq_edac.txt 2014-07-20 22:06:35.200324786 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Zynq EDAC driver, it does reports the DDR ECC single bit errors that are +corrected and double bit ecc errors that are detected by the DDR ECC controller. +ECC support for DDR is available in half-bus width(16 bit) configuration only. + +Required properties: +- compatible: Should be "xlnx,ps7-ddrc" or "xlnx,ps7-ddrc-1.00.a" +- reg: Should contain DDR controller registers location and length. + +Example: +++++++++ + +ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; +}; + +Zynq EDAC driver detects the DDR ECC enable state by reading the appropriate +control register. Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt =================================================================== --- linux-3.12.24-rt38-xilinx.orig/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt 2014-07-20 22:05:50.330065070 +0200 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt 2014-07-20 22:06:35.234324225 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:12 @ - compatible : Should be "xlnx,xps-gpio-1.00.a" - reg : Address and length of the register set for the device - #gpio-cells : Should be two. The first cell is the pin number and the - second cell is used to specify optional parameters (currently unused). + second cell is used to specify channel offset: + 0 - first channel + 8 - second channel - gpio-controller : Marks the device node as a GPIO controller. Optional properties: Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/media/xilinx/video.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/media/xilinx/video.txt 2014-07-20 22:06:35.248323994 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +DT bindings for Xilinx video IP cores +------------------------------------- + +Xilinx video IP cores process video streams by acting as video sinks and/or +sources. They are connected by links through their input and output ports, +creating a video pipeline. + +Each video IP core is represented by an AMBA bus child node in the device +tree using bindings documented in this directory. Connections between the IP +cores are represented as defined in ../video-interfaces.txt. + +Common properties +----------------- + +The following properties are common to all Xilinx video IP cores. + +- xlnx,axi-video-format: This property represents a video format transmitted + on an AXI bus between video IP cores. How the format relates to the IP core + is decribed in the IP core bindings documentation. The following formats are + supported. + + rbg + xrgb + yuv422 + +- xlnx,axi-video-width: This property qualifies the video format with the + sample width expressed as a number of bits per pixel component. All components + must use the same width. + +The following table lists the supported formats and widths combinations, along +with the corresponding media bus pixel code. + +----------------+-------+------------------------------------------------------- +Format | Width | Media bus code +----------------+-------+------------------------------------------------------- +rbg | 8 | V4L2_MBUS_FMT_RBG888_1X24 +xrgb | 8 | V4L2_MBUS_FMT_RGB888_1X32_PADHI +yuv422 | 8 | V4L2_MBUS_FMT_UYVY8_1X16 +----------------+-------+------------------------------------------------------- Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/media/xilinx/xlnx,axi-remapper.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/media/xilinx/xlnx,axi-remapper.txt 2014-07-20 22:06:35.254323895 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Xilinx Video Remapper +--------------------- + +The IP core remaps input pixel components to produce an output pixel with +less, more or the same number of components as the input pixel. + +Required properties: + +- compatible: Must be "xlnx,axi-remapper". + +- xlnx,axi-video-width: Video pixel component width, as defined in video.txt. + +- #xlnx,axi-s-components: Number of components per pixel at the input port + (between 1 and 4 inclusive). + +- #xlnx,axi-m-components: Number of components per pixel at the output port + (between 1 and 4 inclusive). + +- xlnx,axi-component-maps: Remapping configuration represented as an array of + integers. The array contains one entry per output component, in the low to + high order. Each entry corresponds to the zero-based position of the + corresponding input component, or the value 4 to drive a constant value on + the output component. For example, to remap RGB to BGR use <2 1 0>, and to + remap RBG to xRGB use <1 0 2 4>. + +- ports: Video ports, using the DT bindings defined in ../video-interfaces.txt. + The remapper as an input port (0) and and output port (1). + +Example: RBG to xRGB remapper + + axi_remapper_0: axi_remapper { + compatible = "xlnx,axi-remapper"; + + xlnx,axi-video-width = <8>; + + #xlnx,axi-s-components = <3>; + #xlnx,axi-m-components = <4>; + xlnx,axi-component-maps = <1 0 2 4>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + remap0_in: endpoint { + remote-endpoint = <&tpg0_out>; + }; + }; + port@1 { + reg = <1>; + remap0_out: endpoint { + remote-endpoint = <&sobel0_in>; + }; + }; + }; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/media/xilinx/xlnx,axi-tpg.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/media/xilinx/xlnx,axi-tpg.txt 2014-07-20 22:06:35.260323796 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Xilinx Video Test Pattern Generator (TPG) +----------------------------------------- + +Required properties: + +- compatible: Must be "xlnx,axi-tpg". + +- reg: Physical base address and length of the registers set for the device. + +- xlnx,axi-video-format, xlnx,axi-video-width: Video format and width, as + defined in video.txt. + +- port: Video port, using the DT bindings defined in ../video-interfaces.txt. + The TPG has a single output port numbered 0. + +Example: + + axi_tpg_0: axi_tpg@40050000 { + compatible = "xlnx,axi-tpg"; + reg = <0x40050000 0x10000>; + + xlnx,axi-video-format = "yuv422"; + xlnx,axi-video-width = <8>; + + port { + tpg0_out: endpoint { + remote-endpoint = <&remap0_in>; + }; + }; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/misc/xilinx-axitrafgen.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/misc/xilinx-axitrafgen.txt 2014-07-20 22:06:35.270323631 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +* Xilinx AXI Traffic generator IP + +Required properties: +- compatible: "xlnx,axi-traffic-gen" +- interrupts: Should contain AXI Traffic Generator interrupts. +- interrupt-parent: Must be core interrupt controller. +- reg: Should contain AXI Traffic Generator registers location and length. +- interrupt-names: Should contain both the intr names of device - error + and completion. +- xlnx,device-id: Device instance Id. + +Example: +++++++++ +axi_traffic_gen_1: axi-traffic-gen@76000000 { + compatible = "xlnx,axi-traffic-gen-1.0", "xlnx,axi-traffic-gen"; + interrupts = <0 2 2 2>; + interrupt-parent = <&axi_intc_1>; + interrupt-names = "err-out", "irq-out"; + reg = <0x76000000 0x800000>; + xlnx,device-id = <0x0>; +} ; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt 2014-07-20 22:06:35.281323450 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Device Tree Bindings for the Arasan SDHCI Controller + + The bindings follow the mmc[1], clock[2] and interrupt[3] bindings. Only + deviations are documented here. + + [1] Documentation/devicetree/bindings/mmc/mmc.txt + [2] Documentation/devicetree/bindings/clock/clock-bindings.txt + [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Required Properties: + - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' + - reg: From mmc bindings: Register location and length. + - clocks: From clock bindings: Handles to clock inputs. + - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb" + - interrupts: Interrupt specifier + - interrupt-parent: Phandle for the interrupt controller that services + interrupts for this device. + +Example: + sdhci@e0100000 { + compatible = "arasan,sdhci-8.9a"; + reg = <0xe0100000 0x1000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 21>, <&clkc 32>; + interrupt-parent = <&gic>; + interrupts = <0 24 4>; + } ; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/net/can/xilinx_can.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/net/can/xilinx_can.txt 2014-07-20 22:06:35.300323136 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Xilinx Axi CAN/Zynq CANPS controller Device Tree Bindings +--------------------------------------------------------- + +Required properties: +- compatible : Should be "xlnx,ps7-can" for Zynq CAN controllers and + "xlnx,axi-can-1.00.a" for Axi CAN controllers. +- reg : Physical base address and size of the Axi CAN/Zynq + CANPS registers map. +- interrupts : Property with a value describing the interrupt + number. +- interrupt-parent : Must be core interrupt controller +- clock-names : List of input clock names - "ref_clk", "aper_clk" + (See clock bindings for details). +- clocks : Clock phandles (see clock bindings for details). + + +Example: + +For Zynq CANPS Dts file: + ps7_can_0: ps7-can@e0008000 { + compatible = "xlnx,ps7-can"; + clocks = <&clkc 19>, <&clkc 36>; + clock-names = "ref_clk", "aper_clk"; + reg = <0xe0008000 0x1000>; + interrupts = <0 28 4>; + interrupt-parent = <&gic>; + }; +For Axi CAN Dts file: + axi_can_0: axi-can@40000000 { + compatible = "xlnx,axi-can-1.00.a"; + clocks = <&clkc 0>; + clock-names = "ref_clk" ; + reg = <0x40000000 0x10000>; + interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 59 1>; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/pci/xilinx-axipcie.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/pci/xilinx-axipcie.txt 2014-07-20 22:06:35.311322955 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +* Xilinx AXI PCIe Root Port Bridge + +Required properties: + compatible: Should be "xlnx,axi-pcie-1.05.a" + reg: Should contain AXI PCIe registers location and length. + interrupts: Should contain AXI PCIe interrupts. + ranges: These are the parameters for each PCIe bar implemented within the IP + The ranges property is <<child address> <parent address> <size>>. + The parent address #address-cells is taken from the parent node. + xlnx, include-rc: Root Port (=1) or End Point(=0) + xlnx,axibar2pciebar-0: Translates address from AXI to PCIe + xlnx,pciebar2axibar-0: Translates address from PCIe to AXI + +Example: +++++++++ + + ps7_axi_interconnect_0: axi@0 { + #address-cells = <1>; + #size-cells = <1>; + pci_express: axi-pcie@50000000 { + #address-cells = <3>; + #size-cells = <2>; + compatible = "xlnx,axi-pcie-1.05.a"; + interrupts = < 0 52 4 >; + ranges = < 0x02000000 0 0x60000000 0x60000000 0 0x10000000 >; + reg = < 0x50000000 0x10000000 >; + xlnx,include-rc = <0x1>; + xlnx,axibar2pciebar-0 = <0x60000000>; + xlnx,pciebar2axibar-0 = <0x0>; + }; + }; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/remoteproc/mb_remoteproc.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/remoteproc/mb_remoteproc.txt 2014-07-20 22:06:35.321322790 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Xilinx ARM-Microblaze remoteproc driver + +This driver requires specific Zynq hardware design where Microblaze is added +to the programmable logic. +Microblaze is connected with PS block via axi bus connected to PS HP port +to ensure access to PS DDR. +Communication channels are done via soft GPIO IP connected to PS block +and to Microblaze. There are also 2 gpio control signals reset and debug +which are used for reseting Microblaze. + +Required properties: +- compatible : Should be "xlnx,mb_remoteproc" +- reg : Address and length of the ddr address space +- bram: Phandle to bram controller which can access Microblaze BRAM +- bram-firmware : Microblaze BRAM bootloader name +- firmware : Default firmware name which can be override by + "firmware" module parameter +- reset : Gpio phandle which reset Microblaze remoteproc +- debug : Gpio phandle which setup Microblaze to debug state +- ipino : Gpio phandle for Microblaze to ARM communication +- vring0 : Gpio phandle for ARM to Microblaze communication vring 0 +- vring1 : Gpio phandle for ARM to Microblaze communication vring 1 + +Microblaze SoC can be also connected to the PS block via a axi bus. +That's why there is the option to allocate interrupts for Microblaze use only. +The driver will allocate interrupts to itself and Microblaze sw has to ensure +that interrupts are properly enabled and handled by Microblaze interrupt +controller. + +Optional properties: + - interrupts : Interrupt mapping for remoteproc + - interrupt-parent : Phandle for the interrupt controller + +Example: +test_mb: mb_remoteproc-test@800000 { + compatible = "xlnx,mb_remoteproc"; + reg = < 0x8000000 0x8000000 >; + bram = <&axi_bram_ctrl_0>; + bram-firmware = "mb.bin"; + firmware = "image.elf"; + reset = <&zynq_gpio_reset 1 0>; + debug = <&zynq_gpio_reset 0 0>; + ipino = <&zynq_gpio_vring 0 0>; + vring0 = <&zynq_gpio_vring 1 0>; + vring1 = <&zynq_gpio_vring 2 0>; +} ; Index: linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/xilinx.txt =================================================================== --- linux-3.12.24-rt38-xilinx.orig/Documentation/devicetree/bindings/xilinx.txt 2014-07-20 22:05:50.332065037 +0200 +++ linux-3.12.24-rt38-xilinx/Documentation/devicetree/bindings/xilinx.txt 2014-07-20 22:06:35.330322642 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:256 @ Optional properties: - 8-bit (empty) : Set this property for SystemACE in 8 bit mode + - port-number = <port_number> : Set port number for particular device iii) Xilinx EMAC and Xilinx TEMAC Index: linux-3.12.24-rt38-xilinx/Documentation/pmods/00-INDEX =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/pmods/00-INDEX 2014-07-20 22:06:35.341322460 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +Documentation for pmods, a set of peripheral modules provided by Digilent Inc., +which can be plugged to various development boards to add additional functionalities. +These drivers are maintained by Digilent Inc. + +00-INDEX + - this file +pmodoled.txt + - PmodOLED: 128 by 32 pixel 0.9" Organic LED Graphic Display Index: linux-3.12.24-rt38-xilinx/Documentation/pmods/pmodoled.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/Documentation/pmods/pmodoled.txt 2014-07-20 22:06:35.347322361 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +PmodOLED +======== + +Copyright 2012, Digilent Inc. + + +Description +----------- + +The PmodOLED features an SPI-controlled monochrome OLED display, +perfect for embedded applications requiring small, complex visual output. + +The PmodOLED uses a standard 12-pin connector to display output on +a 128x32 pixel organic LED (OLED) panel. The graphic display panel uses +the Solomon Systech SSD1306 display controller. + +An SPI interface is used to configure the display, +as well as to send the bitmap data to the device. + +The PmodOLED displays the last image drawn on the screen until it is +powered down or a new image is drawn to the display. Refreshing and +updating is handled internally. + +The Reference Manual for PmodOLED display is available online at +Digilent Inc. Website (www.digilentinc.com) + +For more information on the OLED display interface, see the +UG-2832HSWEG04 datasheet available online or from Univisio. + +The OLED display uses a compatible command set from the SSD1306 device. +For more information, see the SSD1306 datasheet available at +www.solomon-systech.com. + + +Interface +--------- + +Signal Description + +CS SPI Chip Select (Slave Select) +SDIN SPI Data In (MOSI) +SCLK SPI Clock +D/C Data/Command Control +RES Power Reset +VBATC VBAT Battery Voltage Control +VDDC VDD Logic Voltage Control + + +Devicetree +---------- + +Required Properties: +- compatible : Should be "dlgnt,pmodoled-gpio" +- vbat-gpio : Should specify the GPIO for VBATC, see "gpios property" in + Documentation/devicetree/gpio.txt. +- vdd-gpio : Should specify the GPIO for VDDC, see "gpios property" in + Documentation/devicetree/gpio.txt. +- res-gpio : Should specify the GPIO for RES, see "gpios property" in + Documentation/devicetree/gpio.txt. +- dc-gpio : Should specify the GPIO for D/C, see "gpios property" in + Documentation/devicetree/gpio.txt. +- spi-bus-num : Should specify the bus number for PmodOLED SPI controller. + This value cannot be shared by any other SPI controller present in the + device tree. +- spi-sclk-gpio : Should specify the GPIO for SCLK, see "gpios property" in + Documentation/devicetree/gpio.txt. +- spi-sdin-gpio : Should specify the GPIO for SDIN, see "gpios property" in + Documentation/devicetree/gpio.txt. + +Optional Properties: +- spi-cs-gpio : Should specify the GPIO for CS, see "gpios property" in + Documentation/devicetree/gpio.txt. If unspecified, CS is assumed to be + tied to ground. + +Examples: + +zed_oled { + compatible = "dglnt,pmodoled-gpio"; + /* GPIO Pins */ + vbat-gpio = <&gpiops 55 0>; + vdd-gpio = <&gpiops 56 0>; + res-gpio = <&gpiops 57 0>; + dc-gpio = <&gpiops 58 0>; + /* SPI-GPIOs */ + spi-bus-num = <2>; + spi-sclk-gpio = <&gpiops 59 0>; + spi-sdin-gpio = <&gpiops 60 0>; +}; + +pmodoled_A { + compatible = "dglnt,pmodoled-gpio"; + vbat-gpio = <&gpiops 88 0>; + vdd-gpio = <&gpiops 89 0>; + res-gpio = <&gpiops 87 0>; + dc-gpio = <&gpiops 86 0>; + spi-bus-num = <3>; + spi-sclk-gpio = <&gpiops 85 0>; + spi-sdin-gpio = <&gpiops 83 0>; + spi-cs-gpio = <&gpiops 82 0>; +}; + + +Configuration +------------- + +The PmodOLED is located in the kernel configuration menu at +Device Drivers -> Pmods -> PmodOLED. The driver can be built into the kernel +by selecting (*) for it, or loadable module by selecting (M) for it. + + +Device Nodes +------------ + +A char device node will be created for each PmodOLED device automatically. +The name of the node is default to the one declared in the device tree. + + +Read/Writes +----------- + +The driver provides a 512 Byte display buffer for the display of PmodOLED. +The Whole screen is divided into four lines, each of them is 128 bits wide +and 8 bits high, as shown in the figure below. + + +--------------------------...----------------------------+ + + Line 4 + + +--------------------------...----------------------------+ + + Line 3 + + +--------------------------...----------------------------+ + + Line 2 + + +--------------------------...----------------------------+ MSB (bit 7) + + Line 1 + + +--------------------------...----------------------------+ LSB (bit 0) +byte 127 byte 0 + +Users can perform read and write functions to the device node to access the data +inside the display buffer. Index: linux-3.12.24-rt38-xilinx/drivers/char/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/char/Kconfig 2014-07-20 22:05:50.188067413 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/char/Kconfig 2014-07-20 22:06:35.363322097 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:381 @ If unsure, say N. +config XILINX_DEVCFG + tristate "Xilinx Device Configuration" + depends on ARCH_ZYNQ + help + This option enables support for the Xilinx device configuration driver. + If unsure, say N + config R3964 tristate "Siemens R3964 line discipline" depends on TTY Index: linux-3.12.24-rt38-xilinx/drivers/char/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/char/Makefile 2014-07-20 22:05:50.186067446 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/char/Makefile 2014-07-20 22:06:35.373321932 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:34 @ obj-$(CONFIG_EFI_RTC) += efirtc.o obj-$(CONFIG_DS1302) += ds1302.o obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/ +obj-$(CONFIG_XILINX_DEVCFG) += xilinx_devcfg.o ifeq ($(CONFIG_GENERIC_NVRAM),y) obj-$(CONFIG_NVRAM) += generic_nvram.o else Index: linux-3.12.24-rt38-xilinx/drivers/char/xilinx_devcfg.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/char/xilinx_devcfg.c 2014-07-20 22:06:35.396321553 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Zynq Device Config driver + * + * Copyright (c) 2011 - 2013 Xilinx Inc. + * + * 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. + * + * 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., 675 Mass Ave, Cambridge, MA + * 02139, USA. + */ + +#include <linux/cdev.h> +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/sysctl.h> +#include <linux/types.h> +#include <linux/uaccess.h> + +extern void zynq_slcr_init_preload_fpga(void); +extern void zynq_slcr_init_postload_fpga(void); + +#define DRIVER_NAME "xdevcfg" +#define XDEVCFG_DEVICES 1 + +/* An array, which is set to true when the device is registered. */ +static DEFINE_MUTEX(xdevcfg_mutex); + +/* Constant Definitions */ +#define XDCFG_CTRL_OFFSET 0x00 /* Control Register */ +#define XDCFG_LOCK_OFFSET 0x04 /* Lock Register */ +#define XDCFG_INT_STS_OFFSET 0x0C /* Interrupt Status Register */ +#define XDCFG_INT_MASK_OFFSET 0x10 /* Interrupt Mask Register */ +#define XDCFG_STATUS_OFFSET 0x14 /* Status Register */ +#define XDCFG_DMA_SRC_ADDR_OFFSET 0x18 /* DMA Source Address Register */ +#define XDCFG_DMA_DEST_ADDR_OFFSET 0x1C /* DMA Destination Address Reg */ +#define XDCFG_DMA_SRC_LEN_OFFSET 0x20 /* DMA Source Transfer Length */ +#define XDCFG_DMA_DEST_LEN_OFFSET 0x24 /* DMA Destination Transfer */ +#define XDCFG_UNLOCK_OFFSET 0x34 /* Unlock Register */ +#define XDCFG_MCTRL_OFFSET 0x80 /* Misc. Control Register */ + +/* Control Register Bit definitions */ +#define XDCFG_CTRL_PCFG_PROG_B_MASK 0x40000000 /* Program signal to + * Reset FPGA */ +#define XDCFG_CTRL_PCAP_PR_MASK 0x08000000 /* Enable PCAP for PR */ +#define XDCFG_CTRL_PCAP_MODE_MASK 0x04000000 /* Enable PCAP */ +#define XDCFG_CTRL_PCFG_AES_EN_MASK 0x00000E00 /* AES Enable Mask */ +#define XDCFG_CTRL_SEU_EN_MASK 0x00000100 /* SEU Enable Mask */ +#define XDCFG_CTRL_SPNIDEN_MASK 0x00000040 /* Secure Non Invasive + * Debug Enable */ +#define XDCFG_CTRL_SPIDEN_MASK 0x00000020 /* Secure Invasive + * Debug Enable */ +#define XDCFG_CTRL_NIDEN_MASK 0x00000010 /* Non-Invasive Debug + * Enable */ +#define XDCFG_CTRL_DBGEN_MASK 0x00000008 /* Invasive Debug + * Enable */ +#define XDCFG_CTRL_DAP_EN_MASK 0x00000007 /* DAP Enable Mask */ + +/* Lock register bit definitions */ + +#define XDCFG_LOCK_AES_EN_MASK 0x00000008 /* Lock AES_EN update */ +#define XDCFG_LOCK_SEU_MASK 0x00000004 /* Lock SEU_En update */ +#define XDCFG_LOCK_DBG_MASK 0x00000001 /* This bit locks + * security config + * including: DAP_En, + * DBGEN,NIDEN, SPNIEN */ + +/* Miscellaneous Control Register bit definitions */ +#define XDCFG_MCTRL_PCAP_LPBK_MASK 0x00000010 /* Internal PCAP loopback */ + +/* Status register bit definitions */ +#define XDCFG_STATUS_PCFG_INIT_MASK 0x00000010 /* FPGA init status */ + +/* Interrupt Status/Mask Register Bit definitions */ +#define XDCFG_IXR_DMA_DONE_MASK 0x00002000 /* DMA Command Done */ +#define XDCFG_IXR_PCFG_DONE_MASK 0x00000004 /* FPGA programmed */ +#define XDCFG_IXR_ERROR_FLAGS_MASK 0x00F0F860 +#define XDCFG_IXR_ALL_MASK 0xF8F7F87F +/* Miscellaneous constant values */ +#define XDCFG_DMA_INVALID_ADDRESS 0xFFFFFFFF /* Invalid DMA address */ + +static const char * const fclk_name[] = { + "fclk0", + "fclk1", + "fclk2", + "fclk3" +}; +#define NUMFCLKS ARRAY_SIZE(fclk_name) + +/** + * struct xdevcfg_drvdata - Device Configuration driver structure + * + * @dev: Pointer to the device structure + * @cdev: Instance of the cdev structure + * @devt: Pointer to the dev_t structure + * @class: Pointer to device class + * @fclk_class: Pointer to fclk device class + * @dma_done: The dma_done status bit for the DMA command completion + * @error_status: The error status captured during the DMA transfer + * @irq: Interrupt number + * @clk: Peripheral clock for devcfg + * @fclk: Array holding references to the FPGA clocks + * @fclk_exported: Flag inidcating whether an FPGA clock is exported + * @is_open: The status bit to indicate whether the device is opened + * @sem: Instance for the mutex + * @lock: Instance of spinlock + * @base_address: The virtual device base address of the device registers + * @is_partial_bitstream: Status bit to indicate partial/full bitstream + */ +struct xdevcfg_drvdata { + struct device *dev; + struct cdev cdev; + dev_t devt; + struct class *class; + struct class *fclk_class; + int irq; + struct clk *clk; + struct clk *fclk[NUMFCLKS]; + u8 fclk_exported[NUMFCLKS]; + volatile bool dma_done; + volatile int error_status; + bool is_open; + struct mutex sem; + spinlock_t lock; + void __iomem *base_address; + int ep107; + bool is_partial_bitstream; + bool endian_swap; + char residue_buf[3]; + int residue_len; +}; + +/** + * struct fclk_data - FPGA clock data + * @clk: Pointer to clock + * @enable: Flag indicating enable status of the clock + * @rate_rnd: Rate to be rounded for round rate operation + */ +struct fclk_data { + struct clk *clk; + int enabled; + unsigned long rate_rnd; +}; + +/* Register read/write access routines */ +#define xdevcfg_writereg(offset, val) __raw_writel(val, offset) +#define xdevcfg_readreg(offset) __raw_readl(offset) + +/** + * xdevcfg_reset_pl() - Reset the programmable logic. + * @base_address: The base address of the device. + * + * Must be called with PCAP clock enabled + */ +static void xdevcfg_reset_pl(void __iomem *base_address) +{ + /* + * Create a rising edge on PCFG_INIT. PCFG_INIT follows PCFG_PROG_B, + * so we need to * poll it after setting PCFG_PROG_B to make sure that + * the rising edge happens. + */ + xdevcfg_writereg(base_address + XDCFG_CTRL_OFFSET, + (xdevcfg_readreg(base_address + XDCFG_CTRL_OFFSET) | + XDCFG_CTRL_PCFG_PROG_B_MASK)); + while (!(xdevcfg_readreg(base_address + XDCFG_STATUS_OFFSET) & + XDCFG_STATUS_PCFG_INIT_MASK)) + ; + + xdevcfg_writereg(base_address + XDCFG_CTRL_OFFSET, + (xdevcfg_readreg(base_address + XDCFG_CTRL_OFFSET) & + ~XDCFG_CTRL_PCFG_PROG_B_MASK)); + while (xdevcfg_readreg(base_address + XDCFG_STATUS_OFFSET) & + XDCFG_STATUS_PCFG_INIT_MASK) + ; + + xdevcfg_writereg(base_address + XDCFG_CTRL_OFFSET, + (xdevcfg_readreg(base_address + XDCFG_CTRL_OFFSET) | + XDCFG_CTRL_PCFG_PROG_B_MASK)); + while (!(xdevcfg_readreg(base_address + XDCFG_STATUS_OFFSET) & + XDCFG_STATUS_PCFG_INIT_MASK)) + ; +} + +/** + * xdevcfg_irq() - The main interrupt handler. + * @irq: The interrupt number. + * @data: Pointer to the driver data structure. + * returns: IRQ_HANDLED after the interrupt is handled. + **/ +static irqreturn_t xdevcfg_irq(int irq, void *data) +{ + u32 intr_status; + struct xdevcfg_drvdata *drvdata = data; + + spin_lock(&drvdata->lock); + + intr_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_INT_STS_OFFSET); + + /* Clear the interrupts */ + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET, + intr_status); + + if ((intr_status & XDCFG_IXR_DMA_DONE_MASK) == XDCFG_IXR_DMA_DONE_MASK) + drvdata->dma_done = 1; + + if ((intr_status & XDCFG_IXR_ERROR_FLAGS_MASK) == + XDCFG_IXR_ERROR_FLAGS_MASK) + drvdata->error_status = 1; + + spin_unlock(&drvdata->lock); + + return IRQ_HANDLED; +} + +/** + * xdevcfg_write() - The is the driver write function. + * + * @file: Pointer to the file structure. + * @buf: Pointer to the bitstream location. + * @count: The number of bytes to be written. + * @ppos: Pointer to the offset value + * returns: Success or error status. + **/ +static ssize_t +xdevcfg_write(struct file *file, const char __user *buf, size_t count, + loff_t *ppos) +{ + char *kbuf; + int status; + unsigned long timeout; + u32 intr_reg; + dma_addr_t dma_addr; + u32 transfer_length = 0; + struct xdevcfg_drvdata *drvdata = file->private_data; + size_t user_count = count; + int i; + + status = clk_enable(drvdata->clk); + if (status) + return status; + + status = mutex_lock_interruptible(&drvdata->sem); + + if (status) + goto err_clk; + + kbuf = dma_alloc_coherent(drvdata->dev, count + drvdata->residue_len, + &dma_addr, GFP_KERNEL); + if (!kbuf) { + status = -ENOMEM; + goto err_unlock; + } + + /* Collect stragglers from last time (0 to 3 bytes) */ + memcpy(kbuf, drvdata->residue_buf, drvdata->residue_len); + + /* Fetch user data, appending to stragglers */ + if (copy_from_user(kbuf + drvdata->residue_len, buf, count)) { + status = -EFAULT; + goto error; + } + + /* Include stragglers in total bytes to be handled */ + count += drvdata->residue_len; + + /* First block contains a header */ + if (*ppos == 0 && count > 4) { + /* Look for sync word */ + for (i = 0; i < count - 4; i++) { + if (memcmp(kbuf + i, "\x66\x55\x99\xAA", 4) == 0) { + pr_debug("Found normal sync word\n"); + drvdata->endian_swap = 0; + break; + } + if (memcmp(kbuf + i, "\xAA\x99\x55\x66", 4) == 0) { + pr_debug("Found swapped sync word\n"); + drvdata->endian_swap = 1; + break; + } + } + /* Remove the header, aligning the data on word boundary */ + if (i != count - 4) { + count -= i; + memmove(kbuf, kbuf + i, count); + } + } + + /* Save stragglers for next time */ + drvdata->residue_len = count % 4; + count -= drvdata->residue_len; + memcpy(drvdata->residue_buf, kbuf + count, drvdata->residue_len); + + /* Fixup endianess of the data */ + if (drvdata->endian_swap) { + for (i = 0; i < count; i += 4) { + u32 *p = (u32 *)&kbuf[i]; + *p = swab32(*p); + } + } + + /* Enable DMA and error interrupts */ + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET, + XDCFG_IXR_ALL_MASK); + + + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_MASK_OFFSET, + (u32) (~(XDCFG_IXR_DMA_DONE_MASK | + XDCFG_IXR_ERROR_FLAGS_MASK))); + + drvdata->dma_done = 0; + drvdata->error_status = 0; + + /* Initiate DMA write command */ + if (count < 0x1000) + xdevcfg_writereg(drvdata->base_address + + XDCFG_DMA_SRC_ADDR_OFFSET, (u32)(dma_addr + 1)); + else + xdevcfg_writereg(drvdata->base_address + + XDCFG_DMA_SRC_ADDR_OFFSET, (u32) dma_addr); + + xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_DEST_ADDR_OFFSET, + (u32)XDCFG_DMA_INVALID_ADDRESS); + /* Convert number of bytes to number of words. */ + if (count % 4) + transfer_length = (count / 4 + 1); + else + transfer_length = count / 4; + xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_SRC_LEN_OFFSET, + transfer_length); + xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_DEST_LEN_OFFSET, 0); + + timeout = jiffies + msecs_to_jiffies(1000); + + while (!drvdata->dma_done) { + if (time_after(jiffies, timeout)) { + status = -ETIMEDOUT; + goto error; + } + } + + if (drvdata->error_status) + status = drvdata->error_status; + + /* Disable the DMA and error interrupts */ + intr_reg = xdevcfg_readreg(drvdata->base_address + + XDCFG_INT_MASK_OFFSET); + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_MASK_OFFSET, + intr_reg | (XDCFG_IXR_DMA_DONE_MASK | + XDCFG_IXR_ERROR_FLAGS_MASK)); + + /* If we didn't write correctly, then bail out. */ + if (status) { + status = -EFAULT; + goto error; + } + + *ppos += user_count; + status = user_count; + +error: + dma_free_coherent(drvdata->dev, count, kbuf, dma_addr); +err_unlock: + mutex_unlock(&drvdata->sem); +err_clk: + clk_disable(drvdata->clk); + return status; +} + + +/** + * xdevcfg_read() - The is the driver read function. + * @file: Pointer to the file structure. + * @buf: Pointer to the bitstream location. + * @count: The number of bytes read. + * @ppos: Pointer to the offsetvalue + * returns: Success or error status. + */ +static ssize_t +xdevcfg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + u32 *kbuf; + int status; + unsigned long timeout; + dma_addr_t dma_addr; + struct xdevcfg_drvdata *drvdata = file->private_data; + u32 intr_reg; + + status = clk_enable(drvdata->clk); + if (status) + return status; + + status = mutex_lock_interruptible(&drvdata->sem); + if (status) + goto err_clk; + + /* Get new data from the ICAP, and return was requested. */ + kbuf = dma_alloc_coherent(drvdata->dev, count, &dma_addr, GFP_KERNEL); + if (!kbuf) { + status = -ENOMEM; + goto err_unlock; + } + + drvdata->dma_done = 0; + drvdata->error_status = 0; + + /* Enable DMA and error interrupts */ + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET, + XDCFG_IXR_ALL_MASK); + + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_MASK_OFFSET, + (u32) (~(XDCFG_IXR_DMA_DONE_MASK | + XDCFG_IXR_ERROR_FLAGS_MASK))); + /* Initiate DMA read command */ + xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_SRC_ADDR_OFFSET, + (u32)XDCFG_DMA_INVALID_ADDRESS); + xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_DEST_ADDR_OFFSET, + (u32)dma_addr); + xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_SRC_LEN_OFFSET, 0); + xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_DEST_LEN_OFFSET, + count / 4); + + timeout = jiffies + msecs_to_jiffies(1000); + + while (!drvdata->dma_done) { + if (time_after(jiffies, timeout)) { + status = -ETIMEDOUT; + goto error; + } + } + + if (drvdata->error_status) + status = drvdata->error_status; + + /* Disable and clear DMA and error interrupts */ + intr_reg = xdevcfg_readreg(drvdata->base_address + + XDCFG_INT_MASK_OFFSET); + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_MASK_OFFSET, + intr_reg | (XDCFG_IXR_DMA_DONE_MASK | + XDCFG_IXR_ERROR_FLAGS_MASK)); + + + /* If we didn't read correctly, then bail out. */ + if (status) { + status = -EFAULT; + goto error; + } + + /* If we fail to return the data to the user, then bail out. */ + if (copy_to_user(buf, kbuf, count)) { + status = -EFAULT; + goto error; + } + + status = count; +error: + dma_free_coherent(drvdata->dev, count, kbuf, dma_addr); +err_unlock: + mutex_unlock(&drvdata->sem); +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_open() - The is the driver open function. + * @inode: Pointer to the inode structure of this device. + * @file: Pointer to the file structure. + * returns: Success or error status. + */ +static int xdevcfg_open(struct inode *inode, struct file *file) +{ + struct xdevcfg_drvdata *drvdata; + int status; + + drvdata = container_of(inode->i_cdev, struct xdevcfg_drvdata, cdev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + status = mutex_lock_interruptible(&drvdata->sem); + if (status) + goto err_clk; + + if (drvdata->is_open) { + status = -EBUSY; + goto error; + } + + file->private_data = drvdata; + drvdata->is_open = 1; + drvdata->endian_swap = 0; + drvdata->residue_len= 0; + + /* + * If is_partial_bitstream is set, then PROG_B is not asserted + * (xdevcfg_reset_pl function) and also zynq_slcr_init_preload_fpga and + * zynq_slcr_init_postload_fpga functions are not invoked. + */ + if (!drvdata->is_partial_bitstream) + zynq_slcr_init_preload_fpga(); + + /* + * Only do the reset of the PL for Zynq as it causes problems on the + * EP107 and the issue is not understood, but not worth investigating + * as the emulation platform is very different than silicon and not a + * complete implementation. Also, do not reset if it is a partial + * bitstream. + */ + if ((!drvdata->ep107) && (!drvdata->is_partial_bitstream)) + xdevcfg_reset_pl(drvdata->base_address); + + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET, + XDCFG_IXR_PCFG_DONE_MASK); + +error: + mutex_unlock(&drvdata->sem); +err_clk: + clk_disable(drvdata->clk); + return status; +} + +/** + * xdevcfg_release() - The is the driver release function. + * @inode: Pointer to the inode structure of this device. + * @file: Pointer to the file structure. + * returns: Success. + */ +static int xdevcfg_release(struct inode *inode, struct file *file) +{ + struct xdevcfg_drvdata *drvdata = file->private_data; + + if (!drvdata->is_partial_bitstream) + zynq_slcr_init_postload_fpga(); + + if (drvdata->residue_len) + printk("Did not transfer last %d bytes\n", + drvdata->residue_len); + + drvdata->is_open = 0; + + return 0; +} + +static const struct file_operations xdevcfg_fops = { + .owner = THIS_MODULE, + .write = xdevcfg_write, + .read = xdevcfg_read, + .open = xdevcfg_open, + .release = xdevcfg_release, +}; + +/* + * The following functions are the routines provided to the user to + * set/get the status bit value in the control/lock registers. + */ + +/** + * xdevcfg_set_dap_en() - This function sets the DAP bits in the + * control register with the given value. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: negative error if the string could not be converted + * or the size of the buffer. + */ +static ssize_t xdevcfg_set_dap_en(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 ctrl_reg_status; + unsigned long flags; + unsigned long mask_bit; + int status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + ctrl_reg_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET); + spin_lock_irqsave(&drvdata->lock, flags); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_unlock; + + if (mask_bit > 7) { + status = -EINVAL; + goto err_unlock; + } + + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status | + (((u32)mask_bit) & XDCFG_CTRL_DAP_EN_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_unlock: + spin_unlock_irqrestore(&drvdata->lock, flags); + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_dap_en_status() - The function returns the DAP_EN bits status in + * the control register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: Size of the buffer. + */ +static ssize_t xdevcfg_show_dap_en_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 dap_en_status; + int status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + dap_en_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET) & XDCFG_CTRL_DAP_EN_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", dap_en_status); + + return status; +} + +static DEVICE_ATTR(enable_dap, 0644, xdevcfg_show_dap_en_status, + xdevcfg_set_dap_en); + +/** + * xdevcfg_set_dbgen() - This function sets the DBGEN bit in the + * control register with the given value. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + */ +static ssize_t xdevcfg_set_dbgen(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 ctrl_reg_status; + unsigned long flags; + unsigned long mask_bit; + int status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + ctrl_reg_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status | XDCFG_CTRL_DBGEN_MASK)); + else + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status & (~XDCFG_CTRL_DBGEN_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_dbgen_status() - The function returns the DBGEN bit status in + * the control register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: Size of the buffer. + */ +static ssize_t xdevcfg_show_dbgen_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 dbgen_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + dbgen_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET) & XDCFG_CTRL_DBGEN_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (dbgen_status >> 3)); + + return status; +} + +static DEVICE_ATTR(enable_dbg_in, 0644, xdevcfg_show_dbgen_status, + xdevcfg_set_dbgen); + +/** + * xdevcfg_set_niden() - This function sets the NIDEN bit in the + * control register with the given value. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + */ +static ssize_t xdevcfg_set_niden(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 ctrl_reg_status; + unsigned long flags; + unsigned long mask_bit; + int status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + ctrl_reg_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status | XDCFG_CTRL_NIDEN_MASK)); + else + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status & (~XDCFG_CTRL_NIDEN_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_niden_status() - The function returns the NIDEN bit status in + * the control register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: Size of the buffer. + */ +static ssize_t xdevcfg_show_niden_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 niden_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + niden_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET) & XDCFG_CTRL_NIDEN_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (niden_status >> 4)); + + return status; +} + +static DEVICE_ATTR(enable_dbg_nonin, 0644, xdevcfg_show_niden_status, + xdevcfg_set_niden); + +/** + * xdevcfg_set_spiden() - This function sets the SPIDEN bit in the + * control register with the given value. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + */ +static ssize_t xdevcfg_set_spiden(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 ctrl_reg_status; + unsigned long flags; + unsigned long mask_bit; + int status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + ctrl_reg_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status | XDCFG_CTRL_SPIDEN_MASK)); + else + + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status & (~XDCFG_CTRL_SPIDEN_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_spiden_status() - The function returns the SPIDEN bit status in + * the control register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: Size of the buffer. + */ +static ssize_t xdevcfg_show_spiden_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 spiden_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + spiden_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET) & XDCFG_CTRL_SPIDEN_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (spiden_status >> 5)); + + return status; +} + +static DEVICE_ATTR(enable_sec_dbg_in, 0644, xdevcfg_show_spiden_status, + xdevcfg_set_spiden); + +/** + * xdevcfg_set_spniden() - This function sets the SPNIDEN bit in the + * control register with the given value. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or the size of buffer + */ +static ssize_t xdevcfg_set_spniden(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 ctrl_reg_status; + unsigned long flags; + unsigned long mask_bit; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + ctrl_reg_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET); + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status | XDCFG_CTRL_SPNIDEN_MASK)); + else + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status & (~XDCFG_CTRL_SPNIDEN_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_spniden_status() - The function returns the SPNIDEN bit status + * in the control register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: Size of the buffer. + */ +static ssize_t xdevcfg_show_spniden_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 spniden_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + spniden_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET) & XDCFG_CTRL_SPNIDEN_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (spniden_status >> 6)); + + return status; +} + +static DEVICE_ATTR(enable_sec_dbg_nonin, 0644, xdevcfg_show_spniden_status, + xdevcfg_set_spniden); + +/** + * xdevcfg_set_seu() - This function sets the SEU_EN bit in the + * control register with the given value + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + */ +static ssize_t xdevcfg_set_seu(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 ctrl_reg_status; + unsigned long flags; + unsigned long mask_bit; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + ctrl_reg_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status | XDCFG_CTRL_SEU_EN_MASK)); + else + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status & (~XDCFG_CTRL_SEU_EN_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_seu_status() - The function returns the SEU_EN bit status + * in the control register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: size of the buffer. + */ +static ssize_t xdevcfg_show_seu_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 seu_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + seu_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET) & XDCFG_CTRL_SEU_EN_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (seu_status > 8)); + + return status; +} + +static DEVICE_ATTR(enable_seu, 0644, xdevcfg_show_seu_status, xdevcfg_set_seu); + +/** + * xdevcfg_set_aes() - This function sets the AES_EN bits in the + * control register with either all 1s or all 0s. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + * + * The user must send only one bit in the buffer to notify whether he wants to + * either set or reset these bits. + */ +static ssize_t xdevcfg_set_aes(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 ctrl_reg_status; + unsigned long flags; + unsigned long mask_bit; + int status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + ctrl_reg_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status < 0) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status | + XDCFG_CTRL_PCFG_AES_EN_MASK)); + else + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (ctrl_reg_status & + (~XDCFG_CTRL_PCFG_AES_EN_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_aes_status() - The function returns the AES_EN bit status + * in the control register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: size of the buffer. + */ +static ssize_t xdevcfg_show_aes_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 aes_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + aes_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_CTRL_OFFSET) & XDCFG_CTRL_PCFG_AES_EN_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (aes_status >> 9)); + + return status; +} + +static DEVICE_ATTR(enable_aes, 0644, xdevcfg_show_aes_status, xdevcfg_set_aes); + +/** + * xdevcfg_set_aes_en_lock() - This function sets the LOCK_AES_EN bit in the + * lock register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + */ +static ssize_t xdevcfg_set_aes_en_lock(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 aes_en_lock_status; + unsigned long flags; + unsigned long mask_bit; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + aes_en_lock_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_LOCK_OFFSET); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET, + (aes_en_lock_status | XDCFG_LOCK_AES_EN_MASK)); + else + xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET, + (aes_en_lock_status & + (~XDCFG_LOCK_AES_EN_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_aes_en_lock_status() - The function returns the LOCK_AES_EN bit + * status in the lock register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: size of the buffer. + */ +static ssize_t xdevcfg_show_aes_en_lock_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 aes_en_lock_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + aes_en_lock_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_LOCK_OFFSET) & XDCFG_LOCK_AES_EN_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (aes_en_lock_status >> 3)); + + return status; +} + +static DEVICE_ATTR(aes_en_lock, 0644, xdevcfg_show_aes_en_lock_status, + xdevcfg_set_aes_en_lock); + +/** + * xdevcfg_set_seu_lock() - This function sets the LOCK_SEU bit in the + * lock register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + */ +static ssize_t xdevcfg_set_seu_lock(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 seu_lock_status; + unsigned long flags; + unsigned long mask_bit; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + seu_lock_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_LOCK_OFFSET); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET, + (seu_lock_status | XDCFG_LOCK_SEU_MASK)); + else + xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET, + (seu_lock_status & (~XDCFG_LOCK_SEU_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_seu_lock_status() - The function returns the LOCK_SEU bit + * status in the lock register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: size of the buffer. + */ +static ssize_t xdevcfg_show_seu_lock_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 seu_lock_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + seu_lock_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_LOCK_OFFSET) & XDCFG_LOCK_SEU_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (seu_lock_status >> 2)); + + return status; +} + +static DEVICE_ATTR(seu_lock, 0644, xdevcfg_show_seu_lock_status, + xdevcfg_set_seu_lock); + +/** + * xdevcfg_set_dbg_lock() - This function sets the LOCK_DBG bit in the + * lock register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + */ +static ssize_t xdevcfg_set_dbg_lock(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u32 lock_reg_status; + unsigned long flags; + unsigned long mask_bit; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + lock_reg_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_LOCK_OFFSET); + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + goto err_clk; + + if (mask_bit > 1) { + status = -EINVAL; + goto err_clk; + } + + spin_lock_irqsave(&drvdata->lock, flags); + + if (mask_bit) + xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET, + (lock_reg_status | XDCFG_LOCK_DBG_MASK)); + else + xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET, + (lock_reg_status & (~XDCFG_LOCK_DBG_MASK))); + + spin_unlock_irqrestore(&drvdata->lock, flags); + + clk_disable(drvdata->clk); + + return size; + +err_clk: + clk_disable(drvdata->clk); + + return status; +} + +/** + * xdevcfg_show_dbg_lock_status() - The function returns the LOCK_DBG bit + * status in the lock register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: size of the buffer. + */ +static ssize_t xdevcfg_show_dbg_lock_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 dbg_lock_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + dbg_lock_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_LOCK_OFFSET) & XDCFG_LOCK_DBG_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", dbg_lock_status); + + return status; +} + +static DEVICE_ATTR(dbg_lock, 0644, xdevcfg_show_dbg_lock_status, + xdevcfg_set_dbg_lock); + +/** + * xdevcfg_show_prog_done_status() - The function returns the PROG_DONE bit + * status in the interrupt status register. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: size of the buffer. + */ +static ssize_t xdevcfg_show_prog_done_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 prog_done_status; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = clk_enable(drvdata->clk); + if (status) + return status; + + prog_done_status = xdevcfg_readreg(drvdata->base_address + + XDCFG_INT_STS_OFFSET) & XDCFG_IXR_PCFG_DONE_MASK; + + clk_disable(drvdata->clk); + + status = sprintf(buf, "%d\n", (prog_done_status >> 2)); + + return status; +} + +static DEVICE_ATTR(prog_done, 0644, xdevcfg_show_prog_done_status, + NULL); + +/** + * xdevcfg_set_is_partial_bitstream() - This function sets the + * is_partial_bitstream variable. If is_partial_bitstream is set, + * then PROG_B is not asserted (xdevcfg_reset_pl) and also + * zynq_slcr_init_preload_fpga and zynq_slcr_init_postload_fpga functions + * are not invoked. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * @size: The number of bytes used from the buffer + * returns: -EINVAL if invalid parameter is sent or size + */ +static ssize_t xdevcfg_set_is_partial_bitstream(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned long mask_bit; + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = strict_strtoul(buf, 10, &mask_bit); + + if (status) + return status; + + if (mask_bit > 1) + return -EINVAL; + + if (mask_bit) + drvdata->is_partial_bitstream = 1; + else + drvdata->is_partial_bitstream = 0; + + return size; +} + +/** + * xdevcfg_show_is_partial_bitstream_status() - The function returns the + * value of is_partial_bitstream variable. + * @dev: Pointer to the device structure. + * @attr: Pointer to the device attribute structure. + * @buf: Pointer to the buffer location for the configuration + * data. + * returns: size of the buffer. + */ +static ssize_t xdevcfg_show_is_partial_bitstream_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t status; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + status = sprintf(buf, "%d\n", drvdata->is_partial_bitstream); + + return status; +} + +static DEVICE_ATTR(is_partial_bitstream, 0644, + xdevcfg_show_is_partial_bitstream_status, + xdevcfg_set_is_partial_bitstream); + +static const struct attribute *xdevcfg_attrs[] = { + &dev_attr_prog_done.attr, /* PCFG_DONE bit in Intr Status register */ + &dev_attr_dbg_lock.attr, /* Debug lock bit in Lock register */ + &dev_attr_seu_lock.attr, /* SEU lock bit in Lock register */ + &dev_attr_aes_en_lock.attr, /* AES EN lock bit in Lock register */ + &dev_attr_enable_aes.attr, /* AES EN bit in Control register */ + &dev_attr_enable_seu.attr, /* SEU EN bit in Control register */ + &dev_attr_enable_sec_dbg_nonin.attr, /*SPNIDEN bit in Control register*/ + &dev_attr_enable_sec_dbg_in.attr, /*SPIDEN bit in Control register */ + &dev_attr_enable_dbg_nonin.attr, /* NIDEN bit in Control register */ + &dev_attr_enable_dbg_in.attr, /* DBGEN bit in Control register */ + &dev_attr_enable_dap.attr, /* DAP_EN bits in Control register */ + &dev_attr_is_partial_bitstream.attr, /* Flag for partial bitstream */ + NULL, +}; + + +static const struct attribute_group xdevcfg_attr_group = { + .attrs = (struct attribute **) xdevcfg_attrs, +}; + +static ssize_t fclk_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fclk_data *pdata = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", pdata->enabled); +} + +static ssize_t fclk_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long enable; + int ret; + struct fclk_data *pdata = dev_get_drvdata(dev); + + ret = kstrtoul(buf, 0, &enable); + if (ret) + return -EINVAL; + + enable = !!enable; + if (enable == pdata->enabled) + return count; + + if (enable) + ret = clk_enable(pdata->clk); + else + clk_disable(pdata->clk); + + if (ret) + return ret; + + pdata->enabled = enable; + return count; +} + +static DEVICE_ATTR(enable, 0644, fclk_enable_show, fclk_enable_store); + +static ssize_t fclk_set_rate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fclk_data *pdata = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%lu\n", clk_get_rate(pdata->clk)); +} + +static ssize_t fclk_set_rate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + unsigned long rate; + struct fclk_data *pdata = dev_get_drvdata(dev); + + ret = kstrtoul(buf, 0, &rate); + if (ret) + return -EINVAL; + + rate = clk_round_rate(pdata->clk, rate); + ret = clk_set_rate(pdata->clk, rate); + + return ret ? ret : count; +} + +static DEVICE_ATTR(set_rate, 0644, fclk_set_rate_show, fclk_set_rate_store); + +static ssize_t fclk_round_rate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fclk_data *pdata = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%lu => %lu\n", pdata->rate_rnd, + clk_round_rate(pdata->clk, pdata->rate_rnd)); +} + +static ssize_t fclk_round_rate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + unsigned long rate; + struct fclk_data *pdata = dev_get_drvdata(dev); + + ret = kstrtoul(buf, 0, &rate); + if (ret) + return -EINVAL; + + pdata->rate_rnd = rate; + + return count; +} + +static DEVICE_ATTR(round_rate, 0644, fclk_round_rate_show, + fclk_round_rate_store); + +static const struct attribute *fclk_ctrl_attrs[] = { + &dev_attr_enable.attr, + &dev_attr_set_rate.attr, + &dev_attr_round_rate.attr, + NULL, +}; + +static const struct attribute_group fclk_ctrl_attr_grp = { + .attrs = (struct attribute **)fclk_ctrl_attrs, +}; + +static ssize_t xdevcfg_fclk_export_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int i, ret; + struct device *subdev; + struct fclk_data *fdata; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + for (i = 0; i < NUMFCLKS; i++) { + if (!strncmp(buf, fclk_name[i], strlen(fclk_name[i]))) + break; + } + + if (i < NUMFCLKS && !drvdata->fclk_exported[i]) { + drvdata->fclk_exported[i] = 1; + subdev = device_create(drvdata->fclk_class, dev, MKDEV(0, 0), + NULL, fclk_name[i]); + if (IS_ERR(subdev)) + return PTR_ERR(subdev); + ret = clk_prepare(drvdata->fclk[i]); + if (ret) + return ret; + fdata = kzalloc(sizeof(*fdata), GFP_KERNEL); + if (!fdata) { + ret = -ENOMEM; + goto err_unprepare; + } + fdata->clk = drvdata->fclk[i]; + dev_set_drvdata(subdev, fdata); + ret = sysfs_create_group(&subdev->kobj, &fclk_ctrl_attr_grp); + if (ret) + goto err_free; + } else { + return -EINVAL; + } + + return size; + +err_free: + kfree(fdata); +err_unprepare: + clk_unprepare(drvdata->fclk[i]); + + return ret; +} + +static ssize_t xdevcfg_fclk_export_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i; + ssize_t count = 0; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + for (i = 0; i < NUMFCLKS; i++) { + if (!drvdata->fclk_exported[i]) + count += scnprintf(buf + count, PAGE_SIZE - count, + "%s\n", fclk_name[i]); + } + return count; +} + +static DEVICE_ATTR(fclk_export, 0644, xdevcfg_fclk_export_show, + xdevcfg_fclk_export_store); + +static int match_fclk(struct device *dev, const void *data) +{ + struct fclk_data *fdata = dev_get_drvdata(dev); + + return fdata->clk == data; +} + +static ssize_t xdevcfg_fclk_unexport_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int i; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + for (i = 0; i < NUMFCLKS; i++) { + if (!strncmp(buf, fclk_name[i], strlen(fclk_name[i]))) + break; + } + + if (i < NUMFCLKS && drvdata->fclk_exported[i]) { + struct fclk_data *fdata; + struct device *subdev; + + drvdata->fclk_exported[i] = 0; + subdev = class_find_device(drvdata->fclk_class, NULL, + drvdata->fclk[i], match_fclk); + fdata = dev_get_drvdata(subdev); + if (fdata->enabled) + clk_disable(fdata->clk); + clk_unprepare(fdata->clk); + kfree(fdata); + device_unregister(subdev); + put_device(subdev); + } else { + return -EINVAL; + } + + return size; +} + +static ssize_t xdevcfg_fclk_unexport_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i; + ssize_t count = 0; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + for (i = 0; i < NUMFCLKS; i++) { + if (drvdata->fclk_exported[i]) + count += scnprintf(buf + count, PAGE_SIZE - count, + "%s\n", fclk_name[i]); + } + return count; +} + +static DEVICE_ATTR(fclk_unexport, 0644, xdevcfg_fclk_unexport_show, + xdevcfg_fclk_unexport_store); + +static const struct attribute *fclk_exp_attrs[] = { + &dev_attr_fclk_export.attr, + &dev_attr_fclk_unexport.attr, + NULL, +}; + +static const struct attribute_group fclk_exp_attr_grp = { + .attrs = (struct attribute **)fclk_exp_attrs, +}; + +static void xdevcfg_fclk_init(struct device *dev) +{ + int i; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + for (i = 0; i < NUMFCLKS; i++) { + drvdata->fclk[i] = clk_get(dev, fclk_name[i]); + if (IS_ERR(drvdata->fclk[i])) { + dev_warn(dev, "fclk not found\n"); + return; + } + } + + drvdata->fclk_class = class_create(THIS_MODULE, "fclk"); + if (IS_ERR(drvdata->fclk_class)) { + dev_warn(dev, "failed to create fclk class\n"); + return; + } + sysfs_create_group(&dev->kobj, &fclk_exp_attr_grp); + + return; +} + +static void xdevcfg_fclk_remove(struct device *dev) +{ + int i; + struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev); + + for (i = 0; i < NUMFCLKS; i++) { + if (drvdata->fclk_exported[i]) { + struct fclk_data *fdata; + struct device *subdev; + + drvdata->fclk_exported[i] = 0; + subdev = class_find_device(drvdata->fclk_class, NULL, + drvdata->fclk[i], match_fclk); + fdata = dev_get_drvdata(subdev); + if (fdata->enabled) + clk_disable(fdata->clk); + clk_unprepare(fdata->clk); + kfree(fdata); + device_unregister(subdev); + put_device(subdev); + + } + } + + class_destroy(drvdata->fclk_class); + sysfs_remove_group(&dev->kobj, &fclk_exp_attr_grp); + + return; +} + +/** + * xdevcfg_drv_probe - Probe call for the device. + * + * @pdev: handle to the platform device structure. + * Returns 0 on success, negative error otherwise. + * + * It does all the memory allocation and registration for the device. + */ +static int xdevcfg_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + struct xdevcfg_drvdata *drvdata; + dev_t devt; + int retval; + u32 ctrlreg; + struct device_node *np; + const void *prop; + int size; + struct device *dev; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + drvdata->base_address = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(drvdata->base_address)) + return PTR_ERR(drvdata->base_address); + + drvdata->irq = platform_get_irq(pdev, 0); + retval = devm_request_irq(&pdev->dev, drvdata->irq, &xdevcfg_irq, + 0, dev_name(&pdev->dev), drvdata); + if (retval) { + dev_err(&pdev->dev, "No IRQ available"); + return retval; + } + + platform_set_drvdata(pdev, drvdata); + spin_lock_init(&drvdata->lock); + mutex_init(&drvdata->sem); + drvdata->is_open = 0; + drvdata->is_partial_bitstream = 0; + drvdata->dma_done = 0; + drvdata->error_status = 0; + dev_info(&pdev->dev, "ioremap %pa to %p\n", + &res->start, drvdata->base_address); + + drvdata->clk = devm_clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(drvdata->clk)) { + dev_err(&pdev->dev, "input clock not found\n"); + return PTR_ERR(drvdata->clk); + } + + retval = clk_prepare_enable(drvdata->clk); + if (retval) { + dev_err(&pdev->dev, "unable to enable clock\n"); + return retval; + } + + /* + * Figure out from the device tree if this is running on the EP107 + * emulation platform as it doesn't match the silicon exactly and the + * driver needs to work accordingly. + */ + np = of_get_next_parent(pdev->dev.of_node); + np = of_get_next_parent(np); + prop = of_get_property(np, "compatible", &size); + + if (prop != NULL) { + if ((strcmp((const char *)prop, "xlnx,zynq-ep107")) == 0) + drvdata->ep107 = 1; + else + drvdata->ep107 = 0; + } + + /* Unlock the device */ + xdevcfg_writereg(drvdata->base_address + XDCFG_UNLOCK_OFFSET, + 0x757BDF0D); + + /* + * Set the configuration register with the following options + * - Reset FPGA + * - Enable PCAP interface for Partial reconfiguration + * - Enable the PCAP interface + * - Set the throughput rate for maximum speed + * - Se the CPU in user mode + */ + ctrlreg = xdevcfg_readreg(drvdata->base_address + XDCFG_CTRL_OFFSET); + xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, + (XDCFG_CTRL_PCFG_PROG_B_MASK | + XDCFG_CTRL_PCAP_PR_MASK | + XDCFG_CTRL_PCAP_MODE_MASK | + ctrlreg)); + + /* Ensure internal PCAP loopback is disabled */ + ctrlreg = xdevcfg_readreg(drvdata->base_address + XDCFG_MCTRL_OFFSET); + xdevcfg_writereg(drvdata->base_address + XDCFG_MCTRL_OFFSET, + (~XDCFG_MCTRL_PCAP_LPBK_MASK & + ctrlreg)); + + + retval = alloc_chrdev_region(&devt, 0, XDEVCFG_DEVICES, DRIVER_NAME); + if (retval < 0) + goto failed5; + + drvdata->devt = devt; + + cdev_init(&drvdata->cdev, &xdevcfg_fops); + drvdata->cdev.owner = THIS_MODULE; + retval = cdev_add(&drvdata->cdev, devt, 1); + if (retval) { + dev_err(&pdev->dev, "cdev_add() failed\n"); + goto failed6; + } + + drvdata->class = class_create(THIS_MODULE, DRIVER_NAME); + if (IS_ERR(drvdata->class)) { + dev_err(&pdev->dev, "failed to create class\n"); + goto failed6; + } + + dev = device_create(drvdata->class, &pdev->dev, devt, drvdata, + DRIVER_NAME); + if (IS_ERR(dev)) { + dev_err(&pdev->dev, "unable to create device\n"); + goto failed7; + } + + /* create sysfs files for the device */ + retval = sysfs_create_group(&(pdev->dev.kobj), &xdevcfg_attr_group); + if (retval) { + dev_err(&pdev->dev, "Failed to create sysfs attr group\n"); + cdev_del(&drvdata->cdev); + goto failed8; + } + + xdevcfg_fclk_init(&pdev->dev); + + clk_disable(drvdata->clk); + + return 0; /* Success */ + +failed8: + device_destroy(drvdata->class, drvdata->devt); +failed7: + class_destroy(drvdata->class); +failed6: + /* Unregister char driver */ + unregister_chrdev_region(devt, XDEVCFG_DEVICES); +failed5: + clk_disable_unprepare(drvdata->clk); + + return retval; +} + +/** + * xdevcfg_drv_remove - Remove call for the device. + * + * @pdev: handle to the platform device structure. + * Returns 0 or error status. + * + * Unregister the device after releasing the resources. + */ +static int xdevcfg_drv_remove(struct platform_device *pdev) +{ + struct xdevcfg_drvdata *drvdata; + + drvdata = platform_get_drvdata(pdev); + + if (!drvdata) + return -ENODEV; + + unregister_chrdev_region(drvdata->devt, XDEVCFG_DEVICES); + + sysfs_remove_group(&pdev->dev.kobj, &xdevcfg_attr_group); + + xdevcfg_fclk_remove(&pdev->dev); + device_destroy(drvdata->class, drvdata->devt); + class_destroy(drvdata->class); + cdev_del(&drvdata->cdev); + clk_unprepare(drvdata->clk); + + return 0; /* Success */ +} + +static struct of_device_id xdevcfg_of_match[] = { + { .compatible = "xlnx,ps7-dev-cfg-1.00.a", }, + { /* end of table */} +}; +MODULE_DEVICE_TABLE(of, xdevcfg_of_match); + +/* Driver Structure */ +static struct platform_driver xdevcfg_platform_driver = { + .probe = xdevcfg_drv_probe, + .remove = xdevcfg_drv_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .of_match_table = xdevcfg_of_match, + }, +}; + +module_platform_driver(xdevcfg_platform_driver); + +MODULE_AUTHOR("Xilinx, Inc"); +MODULE_DESCRIPTION("Xilinx Device Config Driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/char/xilinx_hwicap/xilinx_hwicap.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/char/xilinx_hwicap/xilinx_hwicap.c 2014-07-20 22:05:50.187067430 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/char/xilinx_hwicap/xilinx_hwicap.c 2014-07-20 22:06:35.412321289 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:734 @ iounmap(drvdata->base_address); release_mem_region(drvdata->mem_start, drvdata->mem_size); kfree(drvdata); - dev_set_drvdata(dev, NULL); mutex_lock(&icap_sem); probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0; Index: linux-3.12.24-rt38-xilinx/drivers/clk/clk.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/clk/clk.c 2014-07-20 22:05:50.220066885 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/clk/clk.c 2014-07-20 22:06:35.433320943 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:967 @ * @rate: the rate which is to be rounded * * Takes in a rate as input and rounds it to a rate that the clk can actually - * use which is then returned. If clk doesn't support round_rate operation - * then the parent rate is returned. + * use and does not exceed the requested frequency, which is then returned. + * If clk doesn't support round_rate operation then the parent rate + * is returned. */ long clk_round_rate(struct clk *clk, unsigned long rate) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:984 @ EXPORT_SYMBOL_GPL(clk_round_rate); /** + * clk_round_rate_nearest - round the given rate for a clk + * @clk: the clk for which we are rounding a rate + * @rate: the rate which is to be rounded + * + * Takes in a rate as input and rounds it to the closest rate that the clk + * can actually use which is then returned. If clk doesn't support + * round_rate operation then the parent rate is returned. + */ +long clk_round_rate_nearest(struct clk *clk, unsigned long rate) +{ + long lower_limit = clk_round_rate(clk, rate); + long upper_limit = clk_round_rate(clk, rate + (rate - lower_limit)); + + if (rate - lower_limit < upper_limit - rate) + return lower_limit; + else + return upper_limit; +} +EXPORT_SYMBOL_GPL(clk_round_rate_nearest); + +/** * __clk_notify - call clk notifier chain * @clk: struct clk * that is changing rate * @msg: clk notifier type (see include/linux/clk.h) Index: linux-3.12.24-rt38-xilinx/drivers/clk/clk-si570.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/clk/clk-si570.c 2014-07-20 22:06:35.446320728 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Driver for Silicon Labs Si570/Si571 Programmable XO/VCXO + * + * Copyright (C) 2010, 2011 Ericsson AB. + * Copyright (C) 2011 Guenter Roeck. + * Copyright (C) 2011 - 2013 Xilinx Inc. + * + * Author: Guenter Roeck <guenter.roeck@ericsson.com> + * Sören Brinkmann <soren.brinkmann@xilinx.com> + * + * 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. + */ + +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +/* Si570 registers */ +#define SI570_REG_HS_N1 7 +#define SI570_REG_N1_RFREQ0 8 +#define SI570_REG_RFREQ1 9 +#define SI570_REG_RFREQ2 10 +#define SI570_REG_RFREQ3 11 +#define SI570_REG_RFREQ4 12 +#define SI570_REG_CONTROL 135 +#define SI570_REG_FREEZE_DCO 137 +#define SI570_DIV_OFFSET_7PPM 6 + +#define HS_DIV_SHIFT 5 +#define HS_DIV_MASK 0xe0 +#define HS_DIV_OFFSET 4 +#define N1_6_2_MASK 0x1f +#define N1_1_0_MASK 0xc0 +#define RFREQ_37_32_MASK 0x3f + +#define SI570_MIN_FREQ 10000000L +#define SI570_MAX_FREQ 1417500000L +#define SI598_MAX_FREQ 525000000L + +#define FDCO_MIN 4850000000LL +#define FDCO_MAX 5670000000LL + +#define SI570_CNTRL_RECALL (1 << 0) +#define SI570_CNTRL_FREEZE_M (1 << 5) +#define SI570_CNTRL_NEWFREQ (1 << 6) + +#define SI570_FREEZE_DCO (1 << 4) + +/** + * struct clk_si570: + * @hw: Clock hw struct + * @regmap: Device's regmap + * @div_offset: Rgister offset for dividers + * @max_freq: Maximum frequency for this device + * @fxtal: Factory xtal frequency + * @n1: Clock divider N1 + * @hs_div: Clock divider HSDIV + * @rfreq: Clock multiplier RFREQ + * @frequency: Current output frequency + * @i2c_client: I2C client pointer + */ +struct clk_si570 { + struct clk_hw hw; + struct regmap *regmap; + unsigned int div_offset; + u64 max_freq; + u64 fxtal; + unsigned int n1; + unsigned int hs_div; + u64 rfreq; + u64 frequency; + struct i2c_client *i2c_client; +}; +#define to_clk_si570(_hw) container_of(_hw, struct clk_si570, hw) + +enum clk_si570_variant { + si57x, + si59x +}; + +/** + * si570_get_divs() - Read clock dividers from HW + * @data: Pointer to struct clk_si570 + * @rfreq: Fractional multiplier (output) + * @n1: Divider N1 (output) + * @hs_div: Divider HSDIV (output) + * Returns 0 on success, negative errno otherwise. + * + * Retrieve clock dividers and multipliers from the HW. + */ +static int si570_get_divs(struct clk_si570 *data, u64 *rfreq, + unsigned int *n1, unsigned int *hs_div) +{ + int err; + u8 reg[6]; + u64 tmp; + + err = regmap_bulk_read(data->regmap, SI570_REG_HS_N1 + data->div_offset, + reg, ARRAY_SIZE(reg)); + if (err) + return err; + + *hs_div = ((reg[0] & HS_DIV_MASK) >> HS_DIV_SHIFT) + HS_DIV_OFFSET; + *n1 = ((reg[0] & N1_6_2_MASK) << 2) + ((reg[1] & N1_1_0_MASK) >> 6) + 1; + /* Handle invalid cases */ + if (*n1 > 1) + *n1 &= ~1; + + tmp = reg[1] & RFREQ_37_32_MASK; + tmp = (tmp << 8) + reg[2]; + tmp = (tmp << 8) + reg[3]; + tmp = (tmp << 8) + reg[4]; + tmp = (tmp << 8) + reg[5]; + *rfreq = tmp; + + return 0; +} + +/** + * si570_get_defaults() - Get default values + * @data: Driver data structure + * @fout: Factory frequency output + * Returns 0 on success, negative errno otherwise. + */ +static int si570_get_defaults(struct clk_si570 *data, u64 fout) +{ + int err; + u64 fdco; + + regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_RECALL); + + err = si570_get_divs(data, &data->rfreq, &data->n1, &data->hs_div); + if (err) + return err; + + /* + * Accept optional precision loss to avoid arithmetic overflows. + * Acceptable per Silicon Labs Application Note AN334. + */ + fdco = fout * data->n1 * data->hs_div; + if (fdco >= (1LL << 36)) + data->fxtal = div64_u64(fdco << 24, data->rfreq >> 4); + else + data->fxtal = div64_u64(fdco << 28, data->rfreq); + + data->frequency = fout; + + return 0; +} + +/** + * si570_update_rfreq() - Update clock multiplier + * @data: Driver data structure + * Passes on regmap_bulk_write() return value. + */ +static int si570_update_rfreq(struct clk_si570 *data) +{ + u8 reg[5]; + + reg[0] = ((data->n1 - 1) << 6) | + ((data->rfreq >> 32) & RFREQ_37_32_MASK); + reg[1] = (data->rfreq >> 24) & 0xff; + reg[2] = (data->rfreq >> 16) & 0xff; + reg[3] = (data->rfreq >> 8) & 0xff; + reg[4] = data->rfreq & 0xff; + + return regmap_bulk_write(data->regmap, SI570_REG_N1_RFREQ0 + + data->div_offset, reg, ARRAY_SIZE(reg)); +} + +/** + * si570_calc_divs() - Caluclate clock dividers + * @frequency: Target frequency + * @data: Driver data structure + * @out_rfreq: RFREG fractional multiplier (output) + * @out_n1: Clock divider N1 (output) + * @out_hs_div: Clock divider HSDIV (output) + * Returns 0 on success, negative errno otherwise. + * + * Calculate the clock dividers (@out_hs_div, @out_n1) and clock multiplier + * (@out_rfreq) for a given target @frequency. + */ +static int si570_calc_divs(unsigned long frequency, struct clk_si570 *data, + u64 *out_rfreq, unsigned int *out_n1, unsigned int *out_hs_div) +{ + int i; + unsigned int n1, hs_div; + u64 fdco, best_fdco = ULLONG_MAX; + static const uint8_t si570_hs_div_values[] = { 11, 9, 7, 6, 5, 4 }; + + for (i = 0; i < ARRAY_SIZE(si570_hs_div_values); i++) { + hs_div = si570_hs_div_values[i]; + /* Calculate lowest possible value for n1 */ + n1 = div_u64(div_u64(FDCO_MIN, hs_div), frequency); + if (!n1 || (n1 & 1)) + n1++; + while (n1 <= 128) { + fdco = (u64)frequency * (u64)hs_div * (u64)n1; + if (fdco > FDCO_MAX) + break; + if (fdco >= FDCO_MIN && fdco < best_fdco) { + *out_n1 = n1; + *out_hs_div = hs_div; + *out_rfreq = div64_u64(fdco << 28, data->fxtal); + best_fdco = fdco; + } + n1 += (n1 == 1 ? 1 : 2); + } + } + + if (best_fdco == ULLONG_MAX) + return -EINVAL; + + return 0; +} + +static unsigned long si570_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + int err; + u64 rfreq, rate; + unsigned int n1, hs_div; + struct clk_si570 *data = to_clk_si570(hw); + + err = si570_get_divs(data, &rfreq, &n1, &hs_div); + if (err) { + dev_err(&data->i2c_client->dev, "unable to recalc rate\n"); + return data->frequency; + } + + rfreq = div_u64(rfreq, hs_div * n1); + rate = (data->fxtal * rfreq) >> 28; + + return rate; +} + +static long si570_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + int err; + u64 rfreq; + unsigned int n1, hs_div; + struct clk_si570 *data = to_clk_si570(hw); + + if (!rate) + return 0; + + if (div64_u64(abs(rate - data->frequency) * 10000LL, + data->frequency) < 35) { + rfreq = div64_u64((data->rfreq * rate) + + div64_u64(data->frequency, 2), data->frequency); + n1 = data->n1; + hs_div = data->hs_div; + + } else { + err = si570_calc_divs(rate, data, &rfreq, &n1, &hs_div); + if (err) { + dev_err(&data->i2c_client->dev, + "unable to round rate\n"); + return 0; + } + } + + return rate; +} + +/** + * si570_set_frequency() - Adjust output frequency + * @data: Driver data structure + * @frequency: Target frequency + * Returns 0 on success. + * + * Update output frequency for big frequency changes (> 3,500 ppm). + */ +static int si570_set_frequency(struct clk_si570 *data, unsigned long frequency) +{ + int err; + + err = si570_calc_divs(frequency, data, &data->rfreq, &data->n1, + &data->hs_div); + if (err) + return err; + + /* + * The DCO reg should be accessed with a read-modify-write operation + * per AN334 + */ + regmap_write(data->regmap, SI570_REG_FREEZE_DCO, SI570_FREEZE_DCO); + regmap_write(data->regmap, SI570_REG_HS_N1 + data->div_offset, + ((data->hs_div - HS_DIV_OFFSET) << HS_DIV_SHIFT) | + (((data->n1 - 1) >> 2) & N1_6_2_MASK)); + si570_update_rfreq(data); + regmap_write(data->regmap, SI570_REG_FREEZE_DCO, 0); + regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_NEWFREQ); + + /* Applying a new frequency can take up to 10ms */ + usleep_range(10000, 12000); + + return 0; +} + +/** + * si570_set_frequency_small() - Adjust output frequency + * @data: Driver data structure + * @frequency: Target frequency + * Returns 0 on success. + * + * Update output frequency for small frequency changes (< 3,500 ppm). + */ +static int si570_set_frequency_small(struct clk_si570 *data, + unsigned long frequency) +{ + /* + * This is a re-implementation of DIV_ROUND_CLOSEST + * using the div64_u64 function lieu of letting the compiler + * insert EABI calls + */ + data->rfreq = div64_u64((data->rfreq * frequency) + + div_u64(data->frequency, 2), data->frequency); + regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_FREEZE_M); + si570_update_rfreq(data); + regmap_write(data->regmap, SI570_REG_CONTROL, 0); + + /* Applying a new frequency (small change) can take up to 100us */ + usleep_range(100, 200); + + return 0; +} + +static int si570_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_si570 *data = to_clk_si570(hw); + struct i2c_client *client = data->i2c_client; + int err; + + if (rate < SI570_MIN_FREQ || rate > data->max_freq) { + dev_err(&client->dev, + "requested frequency %lu Hz is out of range\n", rate); + return -EINVAL; + } + + if (div64_u64(abs(rate - data->frequency) * 10000LL, + data->frequency) < 35) + err = si570_set_frequency_small(data, rate); + else + err = si570_set_frequency(data, rate); + + if (err) + return err; + + data->frequency = rate; + + return 0; +} + +static const struct clk_ops si570_clk_ops = { + .recalc_rate = si570_recalc_rate, + .round_rate = si570_round_rate, + .set_rate = si570_set_rate, +}; + +static bool si570_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SI570_REG_CONTROL: + return true; + default: + return false; + } +} + +static bool si570_regmap_is_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SI570_REG_HS_N1 ... (SI570_REG_RFREQ4 + SI570_DIV_OFFSET_7PPM): + case SI570_REG_CONTROL: + case SI570_REG_FREEZE_DCO: + return true; + default: + return false; + } +} + +static struct regmap_config si570_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = 137, + .writeable_reg = si570_regmap_is_writeable, + .volatile_reg = si570_regmap_is_volatile, +}; + +static int si570_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct clk_si570 *data; + struct clk_init_data init; + struct clk *clk; + u32 initial_fout, factory_fout, stability; + int err; + enum clk_si570_variant variant = id->driver_data; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + init.ops = &si570_clk_ops; + init.flags = CLK_IS_ROOT; + init.num_parents = 0; + data->hw.init = &init; + data->i2c_client = client; + + if (variant == si57x) { + err = of_property_read_u32(client->dev.of_node, + "temperature-stability", &stability); + if (err) { + dev_err(&client->dev, + "'temperature-stability' property missing\n"); + return err; + } + /* adjust register offsets for 7ppm devices */ + if (stability == 7) + data->div_offset = SI570_DIV_OFFSET_7PPM; + + data->max_freq = SI570_MAX_FREQ; + } else { + data->max_freq = SI598_MAX_FREQ; + } + + if (of_property_read_string(client->dev.of_node, "clock-output-names", + &init.name)) + init.name = client->dev.of_node->name; + + err = of_property_read_u32(client->dev.of_node, "factory-fout", + &factory_fout); + if (err) { + dev_err(&client->dev, "'factory-fout' property missing\n"); + return err; + } + + data->regmap = devm_regmap_init_i2c(client, &si570_regmap_config); + if (IS_ERR(data->regmap)) { + dev_err(&client->dev, "failed to allocate register map\n"); + return PTR_ERR(data->regmap); + } + + i2c_set_clientdata(client, data); + err = si570_get_defaults(data, factory_fout); + if (err) + return err; + + clk = devm_clk_register(&client->dev, &data->hw); + if (IS_ERR(clk)) { + dev_err(&client->dev, "clock registration failed\n"); + return PTR_ERR(clk); + } + err = of_clk_add_provider(client->dev.of_node, of_clk_src_simple_get, + clk); + if (err) { + dev_err(&client->dev, "unable to add clk provider\n"); + return err; + } + + /* Read the requested initial output frequency from device tree */ + if (!of_property_read_u32(client->dev.of_node, "clock-frequency", + &initial_fout)) { + err = clk_set_rate(clk, initial_fout); + if (err) { + of_clk_del_provider(client->dev.of_node); + return err; + } + } + + /* Display a message indicating that we've successfully registered */ + dev_info(&client->dev, "registered, current frequency %llu Hz\n", + data->frequency); + + return 0; +} + +static int si570_remove(struct i2c_client *client) +{ + of_clk_del_provider(client->dev.of_node); + return 0; +} + +static const struct i2c_device_id si570_id[] = { + { "si570", si57x }, + { "si571", si57x }, + { "si598", si59x }, + { "si599", si59x }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si570_id); + +static const struct of_device_id clk_si570_of_match[] = { + { .compatible = "silabs,si570" }, + { .compatible = "silabs,si571" }, + { .compatible = "silabs,si598" }, + { .compatible = "silabs,si599" }, + { }, +}; +MODULE_DEVICE_TABLE(of, clk_si570_of_match); + +static struct i2c_driver si570_driver = { + .driver = { + .name = "si570", + .of_match_table = of_match_ptr(clk_si570_of_match), + }, + .probe = si570_probe, + .remove = si570_remove, + .id_table = si570_id, +}; +module_i2c_driver(si570_driver); + +MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); +MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com"); +MODULE_DESCRIPTION("Si570 driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/clk/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/clk/Kconfig 2014-07-20 22:05:50.224066819 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/clk/Kconfig 2014-07-20 22:06:35.462320464 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:67 @ This driver supports Silicon Labs 5351A/B/C programmable clock generators. +config COMMON_CLK_SI570 + tristate "Clock driver for SiLabs 570 and compatible devices" + depends on I2C + depends on OF + select REGMAP_I2C + help + ---help--- + This driver supports Silicon Labs 570/571/598/599 programmable + clock generators. + config COMMON_CLK_S2MPS11 tristate "Clock driver for S2MPS11 MFD" depends on MFD_SEC_CORE Index: linux-3.12.24-rt38-xilinx/drivers/clk/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/clk/Makefile 2014-07-20 22:05:50.222066852 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/clk/Makefile 2014-07-20 22:06:35.504319771 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:43 @ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o +obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o Index: linux-3.12.24-rt38-xilinx/drivers/clk/zynq/clkc.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/clk/zynq/clkc.c 2014-07-20 22:05:50.221066869 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/clk/zynq/clkc.c 2014-07-20 22:06:35.521319491 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:23 @ #include <linux/clk/zynq.h> #include <linux/clk-provider.h> +#include <linux/clkdev.h> #include <linux/of.h> #include <linux/slab.h> #include <linux/string.h> @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:50 @ #define SLCR_CAN_MIOCLK_CTRL (zynq_slcr_base_priv + 0x160) #define SLCR_DBG_CLK_CTRL (zynq_slcr_base_priv + 0x164) #define SLCR_PCAP_CLK_CTRL (zynq_slcr_base_priv + 0x168) +#define SLCR_TOPSW_CLK_CTRL (zynq_slcr_base_priv + 0x16c) #define SLCR_FPGA0_CLK_CTRL (zynq_slcr_base_priv + 0x170) #define SLCR_621_TRUE (zynq_slcr_base_priv + 0x1c4) #define SLCR_SWDT_CLK_SEL (zynq_slcr_base_priv + 0x304) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:105 @ static const char *gem1_emio_input_names[] __initdata = {"gem1_emio_clk"}; static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"}; +#ifdef CONFIG_SUSPEND +unsigned int zynq_clk_suspended; +static struct clk *armpll_save_parent; +static struct clk *iopll_save_parent; + +#define TOPSW_CLK_CTRL_DIS_MASK BIT(0) + +int zynq_clk_suspend_early(void) +{ + int ret; + + zynq_clk_suspended = 1; + + iopll_save_parent = clk_get_parent(clks[iopll]); + armpll_save_parent = clk_get_parent(clks[armpll]); + + ret = clk_set_parent(clks[iopll], ps_clk); + if (ret) + pr_info("%s: reparent iopll failed %d\n", __func__, ret); + + ret = clk_set_parent(clks[armpll], ps_clk); + if (ret) + pr_info("%s: reparent armpll failed %d\n", __func__, ret); + + return 0; +} + +void zynq_clk_resume_late(void) +{ + clk_set_parent(clks[armpll], armpll_save_parent); + clk_set_parent(clks[iopll], iopll_save_parent); + + zynq_clk_suspended = 0; +} + +void zynq_clk_topswitch_enable(void) +{ + u32 reg; + + reg = readl(SLCR_TOPSW_CLK_CTRL); + reg &= ~TOPSW_CLK_CTRL_DIS_MASK; + writel(reg, SLCR_TOPSW_CLK_CTRL); +} + +void zynq_clk_topswitch_disable(void) +{ + u32 reg; + + reg = readl(SLCR_TOPSW_CLK_CTRL); + reg |= TOPSW_CLK_CTRL_DIS_MASK; + writel(reg, SLCR_TOPSW_CLK_CTRL); +} +#endif + static void __init zynq_clk_register_fclk(enum zynq_clk fclk, const char *clk_name, void __iomem *fclk_ctrl_reg, - const char **parents) + const char **parents, int enable) { struct clk *clk; + u32 enable_reg; char *mux_name; char *div0_name; char *div1_name; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:201 @ clks[fclk] = clk_register_gate(NULL, clk_name, div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg, 0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock); + enable_reg = readl(fclk_gate_reg) & 1; + if (enable && !enable_reg) { + if (clk_prepare_enable(clks[fclk])) + pr_warn("%s: FCLK%u enable failed\n", __func__, + fclk - fclk0); + } kfree(mux_name); kfree(div0_name); kfree(div1_name); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:265 @ int ret; struct clk *clk; char *clk_name; + unsigned int fclk_enable; const char *clk_output_name[clk_max]; const char *cpu_parents[4]; const char *periph_parents[4]; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:300 @ ps_clk = clk_register_fixed_rate(NULL, "ps_clk", NULL, CLK_IS_ROOT, tmp); + ret = of_property_read_u32(np, "fclk-enable", &fclk_enable); + if (ret) + fclk_enable = 0xf; + /* PLLs */ clk = clk_register_zynq_pll("armpll_int", "ps_clk", SLCR_ARMPLL_CTRL, SLCR_PLL_STATUS, 0, &armpll_lock); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:335 @ clks[cpu_6or4x] = clk_register_gate(NULL, clk_output_name[cpu_6or4x], "cpu_div", CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, 24, 0, &armclk_lock); + clk_register_clkdev(clks[cpu_6or4x], "cpufreq_clk", NULL); clk = clk_register_fixed_factor(NULL, "cpu_3or2x_div", "cpu_div", 0, 1, 2); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:398 @ clk_prepare_enable(clks[dci]); /* Peripheral clocks */ - for (i = fclk0; i <= fclk3; i++) + for (i = fclk0; i <= fclk3; i++) { + int enable = !!(fclk_enable & BIT(i - fclk0)); zynq_clk_register_fclk(i, clk_output_name[i], SLCR_FPGA0_CLK_CTRL + 0x10 * (i - fclk0), - periph_parents); + periph_parents, enable); + } zynq_clk_register_periph_clk(lqspi, 0, clk_output_name[lqspi], NULL, SLCR_LQSPI_CLK_CTRL, periph_parents, 0); Index: linux-3.12.24-rt38-xilinx/drivers/clocksource/cadence_ttc_timer.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/clocksource/cadence_ttc_timer.c 2014-07-20 22:05:50.170067710 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/clocksource/cadence_ttc_timer.c 2014-07-20 22:06:35.537319227 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:70 @ * struct ttc_timer - This definition defines local timer structure * * @base_addr: Base address of timer + * @freq: Timer input clock frequency * @clk: Associated clock source * @clk_rate_change_nb Notifier block for clock rate changes */ struct ttc_timer { void __iomem *base_addr; + unsigned long freq; struct clk *clk; struct notifier_block clk_rate_change_nb; }; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:202 @ switch (mode) { case CLOCK_EVT_MODE_PERIODIC: ttc_set_interval(timer, - DIV_ROUND_CLOSEST(clk_get_rate(ttce->ttc.clk), + DIV_ROUND_CLOSEST(ttce->ttc.freq, PRESCALE * HZ)); break; case CLOCK_EVT_MODE_ONESHOT: @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:224 @ } } -static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct clk_notifier_data *ndata = data; - struct ttc_timer *ttc = to_ttc_timer(nb); - struct ttc_timer_clocksource *ttccs = container_of(ttc, - struct ttc_timer_clocksource, ttc); - - switch (event) { - case POST_RATE_CHANGE: - /* - * Do whatever is necessary to maintain a proper time base - * - * I cannot find a way to adjust the currently used clocksource - * to the new frequency. __clocksource_updatefreq_hz() sounds - * good, but does not work. Not sure what's that missing. - * - * This approach works, but triggers two clocksource switches. - * The first after unregister to clocksource jiffies. And - * another one after the register to the newly registered timer. - * - * Alternatively we could 'waste' another HW timer to ping pong - * between clock sources. That would also use one register and - * one unregister call, but only trigger one clocksource switch - * for the cost of another HW timer used by the OS. - */ - clocksource_unregister(&ttccs->cs); - clocksource_register_hz(&ttccs->cs, - ndata->new_rate / PRESCALE); - /* fall through */ - case PRE_RATE_CHANGE: - case ABORT_RATE_CHANGE: - default: - return NOTIFY_DONE; - } -} - static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) { struct ttc_timer_clocksource *ttccs; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:241 @ return; } - ttccs->ttc.clk_rate_change_nb.notifier_call = - ttc_rate_change_clocksource_cb; - ttccs->ttc.clk_rate_change_nb.next = NULL; - if (clk_notifier_register(ttccs->ttc.clk, - &ttccs->ttc.clk_rate_change_nb)) - pr_warn("Unable to register clock notifier.\n"); - + ttccs->ttc.freq = clk_get_rate(ttccs->ttc.clk); ttccs->ttc.base_addr = base; ttccs->cs.name = "ttc_clocksource"; ttccs->cs.rating = 200; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:260 @ __raw_writel(CNT_CNTRL_RESET, ttccs->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); - err = clocksource_register_hz(&ttccs->cs, - clk_get_rate(ttccs->ttc.clk) / PRESCALE); + err = clocksource_register_hz(&ttccs->cs, ttccs->ttc.freq / PRESCALE); if (WARN_ON(err)) { kfree(ttccs); return; } ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET; - setup_sched_clock(ttc_sched_clock_read, 16, - clk_get_rate(ttccs->ttc.clk) / PRESCALE); + setup_sched_clock(ttc_sched_clock_read, 16, ttccs->ttc.freq / PRESCALE); } static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:294 @ ndata->new_rate / PRESCALE); local_irq_restore(flags); + /* update cached frequency */ + ttc->freq = ndata->new_rate; + + if (ttcce->ce.mode == CLOCK_EVT_MODE_PERIODIC) + ttc_set_interval(ttc, DIV_ROUND_CLOSEST(ttc->freq, + PRESCALE * HZ)); + /* fall through */ } case PRE_RATE_CHANGE: @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:334 @ if (clk_notifier_register(ttcce->ttc.clk, &ttcce->ttc.clk_rate_change_nb)) pr_warn("Unable to register clock notifier.\n"); + ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk); ttcce->ttc.base_addr = base; ttcce->ce.name = "ttc_clockevent"; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:364 @ } clockevents_config_and_register(&ttcce->ce, - clk_get_rate(ttcce->ttc.clk) / PRESCALE, 1, 0xfffe); + ttcce->ttc.freq / PRESCALE, 1, 0xfffe); } /** @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:426 @ } CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); +CLOCKSOURCE_OF_DECLARE(ttc1, "xlnx,ps7-ttc-1.00.a", ttc_timer_init); Index: linux-3.12.24-rt38-xilinx/drivers/cpufreq/Kconfig.arm =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/cpufreq/Kconfig.arm 2014-07-20 22:05:50.175067628 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/cpufreq/Kconfig.arm 2014-07-20 22:06:35.550319013 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:238 @ default y help This adds the CPUFreq driver support for TEGRA SOCs. + +config ARM_ZYNQ_CPUFREQ + bool "Xilinx Zynq" + depends on ARCH_ZYNQ + default n + select CPU_FREQ_TABLE + select PM_OPP + help + This adds the CPUFreq driver for Xilinx Zynq SoCs. + Index: linux-3.12.24-rt38-xilinx/drivers/cpufreq/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/cpufreq/Makefile 2014-07-20 22:05:50.174067644 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/cpufreq/Makefile 2014-07-20 22:06:35.560318848 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:80 @ obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o +obj-$(CONFIG_ARM_ZYNQ_CPUFREQ) += zynq-cpufreq.o ################################################################################## # PowerPC platform drivers Index: linux-3.12.24-rt38-xilinx/drivers/cpufreq/zynq-cpufreq.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/cpufreq/zynq-cpufreq.c 2014-07-20 22:06:35.575318600 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * CPU frequency scaling for Zynq + * + * Based on drivers/cpufreq/omap-cpufreq.c, + * Copyright (C) 2005 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 <linux/kernel.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/clk/zynq.h> +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/module.h> +#include <linux/opp.h> +#include <linux/platform_device.h> +#include <asm/smp_plat.h> +#include <asm/cpu.h> + +static atomic_t freq_table_users = ATOMIC_INIT(0); +static struct cpufreq_frequency_table *freq_table; +static struct device *mpu_dev; +static struct clk *cpuclk; + +static int zynq_verify_speed(struct cpufreq_policy *policy) +{ + if (!freq_table) + return -EINVAL; + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static unsigned int zynq_getspeed(unsigned int cpu) +{ + unsigned long rate; + + if (cpu >= num_present_cpus()) + return 0; + + rate = clk_get_rate(cpuclk) / 1000; + return rate; +} + +static int zynq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int i; + int ret = 0; + struct cpufreq_freqs freqs; + +#ifdef CONFIG_SUSPEND + if (zynq_clk_suspended) + return -EPERM; +#endif + + if (!freq_table) { + dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, + policy->cpu); + return -EINVAL; + } + + ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, + relation, &i); + if (ret) { + dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n", + __func__, policy->cpu, target_freq, ret); + return ret; + } + freqs.new = freq_table[i].frequency; + if (!freqs.new) { + dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__, + policy->cpu, target_freq); + return -EINVAL; + } + + freqs.old = zynq_getspeed(policy->cpu); + freqs.cpu = policy->cpu; + + if (freqs.old == freqs.new && policy->cur == freqs.new) + return ret; + + /* notifiers */ + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + + dev_dbg(mpu_dev, "cpufreq-zynq: %u MHz --> %u MHz\n", + freqs.old / 1000, freqs.new / 1000); + + ret = clk_set_rate(cpuclk, freqs.new * 1000); + + freqs.new = zynq_getspeed(policy->cpu); + + /* notifiers */ + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + + return ret; +} + +static inline void freq_table_free(void) +{ + if (atomic_dec_and_test(&freq_table_users)) + opp_free_cpufreq_table(mpu_dev, &freq_table); +} + +static int __cpuinit zynq_cpu_init(struct cpufreq_policy *policy) +{ + int result = 0; + + cpuclk = devm_clk_get(mpu_dev, "cpufreq_clk"); + if (IS_ERR(cpuclk)) { + dev_err(mpu_dev, "cpufreq_clk clock not found."); + return PTR_ERR(cpuclk); + } + + if (policy->cpu >= num_possible_cpus()) + return -EINVAL; + + policy->cur = policy->min = policy->max = zynq_getspeed(policy->cpu); + + if (!freq_table) + result = opp_init_cpufreq_table(mpu_dev, &freq_table); + + if (result) { + dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n", + __func__, policy->cpu, result); + return result; + } + + atomic_inc(&freq_table_users); + + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (result) { + freq_table_free(); + return result; + } + + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + policy->cur = zynq_getspeed(policy->cpu); + + /* + * On Zynq configuartion, both processors share the voltage + * and clock. So both CPUs needs to be scaled together and hence + * needs software co-ordination. Use cpufreq affected_cpus + * interface to handle this scenario. Additional is_smp() check + * is to keep SMP_ON_UP build working. + */ + if (is_smp()) { + policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; + cpumask_setall(policy->cpus); + } + + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 300 * 1000; + + return 0; +} + +static int zynq_cpu_exit(struct cpufreq_policy *policy) +{ + freq_table_free(); + return 0; +} + +static struct freq_attr *zynq_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver zynq_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .verify = zynq_verify_speed, + .target = zynq_target, + .get = zynq_getspeed, + .init = zynq_cpu_init, + .exit = zynq_cpu_exit, + .name = "Zynq cpufreq", + .attr = zynq_cpufreq_attr, +}; + +static int __init zynq_cpufreq_init(void) +{ + struct device *dev = get_cpu_device(0); + + if (!dev) { + pr_warn("%s: Error: device not found.", __func__); + return -EINVAL; + } + mpu_dev = dev; + return cpufreq_register_driver(&zynq_cpufreq_driver); +} + +static void __exit zynq_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&zynq_cpufreq_driver); +} + +MODULE_DESCRIPTION("cpufreq driver for Zynq"); +MODULE_LICENSE("GPL"); +module_init(zynq_cpufreq_init); +module_exit(zynq_cpufreq_exit); Index: linux-3.12.24-rt38-xilinx/drivers/dma/dmatest.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/dma/dmatest.c 2014-07-20 22:05:50.149068057 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/dma/dmatest.c 2014-07-20 22:06:35.597318237 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:629 @ break; } + align = 3; len = dmatest_random() % params->buf_size + 1; len = (len >> align) << align; if (!len) Index: linux-3.12.24-rt38-xilinx/drivers/dma/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/dma/Kconfig 2014-07-20 22:05:50.163067826 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/dma/Kconfig 2014-07-20 22:06:35.609318040 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:36 @ comment "DMA Devices" +source "drivers/dma/xilinx/Kconfig" + config INTEL_MID_DMAC tristate "Intel MID DMA support for Peripheral DMA controllers" depends on PCI && X86 Index: linux-3.12.24-rt38-xilinx/drivers/dma/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/dma/Makefile 2014-07-20 22:05:50.162067842 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/dma/Makefile 2014-07-20 22:06:35.619317875 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:44 @ obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o obj-$(CONFIG_TI_CPPI41) += cppi41.o obj-$(CONFIG_K3_DMA) += k3dma.o +obj-$(CONFIG_XILINX_DMA_ENGINES) += xilinx/ Index: linux-3.12.24-rt38-xilinx/drivers/dma/pl330.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/dma/pl330.c 2014-07-20 22:05:50.161067858 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/dma/pl330.c 2014-07-20 22:06:35.639317545 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2925 @ amba_set_drvdata(adev, pdmac); - irq = adev->irq[0]; - ret = request_irq(irq, pl330_irq_handler, 0, - dev_name(&adev->dev), pi); - if (ret) - return ret; + for (i = 0; i <= AMBA_NR_IRQS; i++) { + irq = adev->irq[i]; + if (irq) { + ret = devm_request_irq(&adev->dev, irq, + pl330_irq_handler, 0, + dev_name(&adev->dev), pi); + if (ret) + return ret; + } else { + break; + } + } pi->pcfg.periph_id = adev->periphid; ret = pl330_add(pi); if (ret) - goto probe_err1; + return ret; INIT_LIST_HEAD(&pdmac->desc_pool); spin_lock_init(&pdmac->pool_lock); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:3054 @ } probe_err2: pl330_del(pi); -probe_err1: - free_irq(irq, pi); return ret; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:3063 @ struct dma_pl330_dmac *pdmac = amba_get_drvdata(adev); struct dma_pl330_chan *pch, *_p; struct pl330_info *pi; - int irq; if (!pdmac) return 0; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:3089 @ pl330_del(pi); - irq = adev->irq[0]; - free_irq(irq, pi); - return 0; } Index: linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/axidmatest.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/axidmatest.c 2014-07-20 22:06:35.657317248 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * XILINX AXI DMA Engine test module + * + * Copyright (C) 2010 Xilinx, Inc. All rights reserved. + * + * Based on Atmel DMA Test Client + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/init.h> +#include <linux/kthread.h> +#include <linux/module.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/wait.h> +#include <linux/amba/xilinx_dma.h> + +static unsigned int test_buf_size = 64; +module_param(test_buf_size, uint, S_IRUGO); +MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer"); + +static unsigned int iterations; +module_param(iterations, uint, S_IRUGO); +MODULE_PARM_DESC(iterations, + "Iterations before stopping test (default: infinite)"); + +/* + * Initialization patterns. All bytes in the source buffer has bit 7 + * set, all bytes in the destination buffer has bit 7 cleared. + * + * Bit 6 is set for all bytes which are to be copied by the DMA + * engine. Bit 5 is set for all bytes which are to be overwritten by + * the DMA engine. + * + * The remaining bits are the inverse of a counter which increments by + * one for each byte address. + */ +#define PATTERN_SRC 0x80 +#define PATTERN_DST 0x00 +#define PATTERN_COPY 0x40 +#define PATTERN_OVERWRITE 0x20 +#define PATTERN_COUNT_MASK 0x1f + +struct dmatest_slave_thread { + struct list_head node; + struct task_struct *task; + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + u8 **srcs; + u8 **dsts; + enum dma_transaction_type type; +}; + +struct dmatest_chan { + struct list_head node; + struct dma_chan *chan; + struct list_head threads; +}; + +/* + * These are protected by dma_list_mutex since they're only used by + * the DMA filter function callback + */ +static LIST_HEAD(dmatest_channels); +static unsigned int nr_channels; + +static unsigned long dmatest_random(void) +{ + unsigned long buf; + + get_random_bytes(&buf, sizeof(buf)); + return buf; +} + +static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len) +{ + unsigned int i; + u8 *buf; + + for (; (buf = *bufs); bufs++) { + for (i = 0; i < start; i++) + buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); + for ( ; i < start + len; i++) + buf[i] = PATTERN_SRC | PATTERN_COPY + | (~i & PATTERN_COUNT_MASK); + for ( ; i < test_buf_size; i++) + buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); + buf++; + } +} + +static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len) +{ + unsigned int i; + u8 *buf; + + for (; (buf = *bufs); bufs++) { + for (i = 0; i < start; i++) + buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); + for ( ; i < start + len; i++) + buf[i] = PATTERN_DST | PATTERN_OVERWRITE + | (~i & PATTERN_COUNT_MASK); + for ( ; i < test_buf_size; i++) + buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); + } +} + +static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index, + unsigned int counter, bool is_srcbuf) +{ + u8 diff = actual ^ pattern; + u8 expected = pattern | (~counter & PATTERN_COUNT_MASK); + const char *thread_name = current->comm; + + if (is_srcbuf) + pr_warn( + "%s: srcbuf[0x%x] overwritten! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if ((pattern & PATTERN_COPY) + && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) + pr_warn( + "%s: dstbuf[0x%x] not copied! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if (diff & PATTERN_SRC) + pr_warn( + "%s: dstbuf[0x%x] was copied! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else + pr_warn( + "%s: dstbuf[0x%x] mismatch! Expected %02x, got %02x\n", + thread_name, index, expected, actual); +} + +static unsigned int dmatest_verify(u8 **bufs, unsigned int start, + unsigned int end, unsigned int counter, u8 pattern, + bool is_srcbuf) +{ + unsigned int i; + unsigned int error_count = 0; + u8 actual; + u8 expected; + u8 *buf; + unsigned int counter_orig = counter; + + for (; (buf = *bufs); bufs++) { + counter = counter_orig; + for (i = start; i < end; i++) { + actual = buf[i]; + expected = pattern | (~counter & PATTERN_COUNT_MASK); + if (actual != expected) { + if (error_count < 32) + dmatest_mismatch(actual, pattern, i, + counter, is_srcbuf); + error_count++; + } + counter++; + } + } + + if (error_count > 32) + pr_warn("%s: %u errors suppressed\n", + current->comm, error_count - 32); + + return error_count; +} + +static void dmatest_slave_tx_callback(void *completion) +{ + complete(completion); +} + +static void dmatest_slave_rx_callback(void *completion) +{ + complete(completion); +} + +/* Function for slave transfers + * Each thread requires 2 channels, one for transmit, and one for receive + */ +static int dmatest_slave_func(void *data) +{ + struct dmatest_slave_thread *thread = data; + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + const char *thread_name; + unsigned int src_off, dst_off, len; + unsigned int error_count; + unsigned int failed_tests = 0; + unsigned int total_tests = 0; + dma_cookie_t tx_cookie; + dma_cookie_t rx_cookie; + enum dma_status status; + enum dma_ctrl_flags flags; + int ret; + int src_cnt; + int dst_cnt; + int bd_cnt = 11; + int i; + struct xilinx_dma_config config; + thread_name = current->comm; + + ret = -ENOMEM; + + /* JZ: limit testing scope here */ + iterations = 5; + test_buf_size = 700; + + smp_rmb(); + tx_chan = thread->tx_chan; + rx_chan = thread->rx_chan; + src_cnt = dst_cnt = bd_cnt; + + thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL); + if (!thread->srcs) + goto err_srcs; + for (i = 0; i < src_cnt; i++) { + thread->srcs[i] = kmalloc(test_buf_size, GFP_KERNEL); + if (!thread->srcs[i]) + goto err_srcbuf; + } + thread->srcs[i] = NULL; + + thread->dsts = kcalloc(dst_cnt+1, sizeof(u8 *), GFP_KERNEL); + if (!thread->dsts) + goto err_dsts; + for (i = 0; i < dst_cnt; i++) { + thread->dsts[i] = kmalloc(test_buf_size, GFP_KERNEL); + if (!thread->dsts[i]) + goto err_dstbuf; + } + thread->dsts[i] = NULL; + + set_user_nice(current, 10); + + flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT; + + while (!kthread_should_stop() + && !(iterations && total_tests >= iterations)) { + struct dma_device *tx_dev = tx_chan->device; + struct dma_device *rx_dev = rx_chan->device; + struct dma_async_tx_descriptor *txd = NULL; + struct dma_async_tx_descriptor *rxd = NULL; + dma_addr_t dma_srcs[src_cnt]; + dma_addr_t dma_dsts[dst_cnt]; + struct completion rx_cmp; + struct completion tx_cmp; + unsigned long rx_tmo = + msecs_to_jiffies(300000); /* RX takes longer */ + unsigned long tx_tmo = msecs_to_jiffies(30000); + u8 align = 0; + struct scatterlist tx_sg[bd_cnt]; + struct scatterlist rx_sg[bd_cnt]; + + total_tests++; + + /* honor larger alignment restrictions */ + align = tx_dev->copy_align; + if (rx_dev->copy_align > align) + align = rx_dev->copy_align; + + if (1 << align > test_buf_size) { + pr_err("%u-byte buffer too small for %d-byte alignment\n", + test_buf_size, 1 << align); + break; + } + + len = dmatest_random() % test_buf_size + 1; + len = (len >> align) << align; + if (!len) + len = 1 << align; + src_off = dmatest_random() % (test_buf_size - len + 1); + dst_off = dmatest_random() % (test_buf_size - len + 1); + + src_off = (src_off >> align) << align; + dst_off = (dst_off >> align) << align; + + dmatest_init_srcs(thread->srcs, src_off, len); + dmatest_init_dsts(thread->dsts, dst_off, len); + + for (i = 0; i < src_cnt; i++) { + u8 *buf = thread->srcs[i] + src_off; + + dma_srcs[i] = dma_map_single(tx_dev->dev, buf, len, + DMA_MEM_TO_DEV); + } + + for (i = 0; i < dst_cnt; i++) { + dma_dsts[i] = dma_map_single(rx_dev->dev, + thread->dsts[i], + test_buf_size, + DMA_MEM_TO_DEV); + + dma_unmap_single(rx_dev->dev, dma_dsts[i], + test_buf_size, + DMA_MEM_TO_DEV); + + dma_dsts[i] = dma_map_single(rx_dev->dev, + thread->dsts[i], + test_buf_size, + DMA_DEV_TO_MEM); + } + + sg_init_table(tx_sg, bd_cnt); + sg_init_table(rx_sg, bd_cnt); + + for (i = 0; i < bd_cnt; i++) { + sg_dma_address(&tx_sg[i]) = dma_srcs[i]; + sg_dma_address(&rx_sg[i]) = dma_dsts[i] + dst_off; + + sg_dma_len(&tx_sg[i]) = len; + sg_dma_len(&rx_sg[i]) = len; + + } + + /* Only one interrupt */ + config.coalesc = 1; + config.delay = 0; + rx_dev->device_control(rx_chan, DMA_SLAVE_CONFIG, + (unsigned long)&config); + + config.coalesc = 1; + config.delay = 0; + tx_dev->device_control(tx_chan, DMA_SLAVE_CONFIG, + (unsigned long)&config); + + rxd = rx_dev->device_prep_slave_sg(rx_chan, rx_sg, bd_cnt, + DMA_DEV_TO_MEM, flags, NULL); + + txd = tx_dev->device_prep_slave_sg(tx_chan, tx_sg, bd_cnt, + DMA_MEM_TO_DEV, flags, NULL); + + if (!rxd || !txd) { + for (i = 0; i < src_cnt; i++) + dma_unmap_single(tx_dev->dev, dma_srcs[i], len, + DMA_MEM_TO_DEV); + for (i = 0; i < dst_cnt; i++) + dma_unmap_single(rx_dev->dev, dma_dsts[i], + test_buf_size, + DMA_DEV_TO_MEM); + pr_warn( + "%s: #%u: prep error with src_off=0x%x ", + thread_name, total_tests - 1, src_off); + pr_warn("dst_off=0x%x len=0x%x\n", + dst_off, len); + msleep(100); + failed_tests++; + continue; + } + + init_completion(&rx_cmp); + rxd->callback = dmatest_slave_rx_callback; + rxd->callback_param = &rx_cmp; + rx_cookie = rxd->tx_submit(rxd); + + init_completion(&tx_cmp); + txd->callback = dmatest_slave_tx_callback; + txd->callback_param = &tx_cmp; + tx_cookie = txd->tx_submit(txd); + + if (dma_submit_error(rx_cookie) || + dma_submit_error(tx_cookie)) { + pr_warn( + "%s: #%u: submit error %d/%d with src_off=0x%x ", + thread_name, total_tests - 1, + rx_cookie, tx_cookie, src_off); + pr_warn("dst_off=0x%x len=0x%x\n", + dst_off, len); + msleep(100); + failed_tests++; + continue; + } + dma_async_issue_pending(tx_chan); + dma_async_issue_pending(rx_chan); + + tx_tmo = wait_for_completion_timeout(&tx_cmp, tx_tmo); + + status = dma_async_is_tx_complete(tx_chan, tx_cookie, + NULL, NULL); + + if (tx_tmo == 0) { + pr_warn("%s: #%u: tx test timed out\n", + thread_name, total_tests - 1); + failed_tests++; + continue; + } else if (status != DMA_SUCCESS) { + pr_warn( + "%s: #%u: tx got completion callback, ", + thread_name, total_tests - 1); + pr_warn("but status is \'%s\'\n", + status == DMA_ERROR ? "error" : + "in progress"); + failed_tests++; + continue; + } + + rx_tmo = wait_for_completion_timeout(&rx_cmp, rx_tmo); + status = dma_async_is_tx_complete(rx_chan, rx_cookie, + NULL, NULL); + + if (rx_tmo == 0) { + pr_warn("%s: #%u: rx test timed out\n", + thread_name, total_tests - 1); + failed_tests++; + continue; + } else if (status != DMA_SUCCESS) { + pr_warn( + "%s: #%u: rx got completion callback, ", + thread_name, total_tests - 1); + pr_warn("but status is \'%s\'\n", + status == DMA_ERROR ? "error" : + "in progress"); + failed_tests++; + continue; + } + + /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */ + for (i = 0; i < dst_cnt; i++) + dma_unmap_single(rx_dev->dev, dma_dsts[i], + test_buf_size, DMA_DEV_TO_MEM); + + error_count = 0; + + pr_debug("%s: verifying source buffer...\n", thread_name); + error_count += dmatest_verify(thread->srcs, 0, src_off, + 0, PATTERN_SRC, true); + error_count += dmatest_verify(thread->srcs, src_off, + src_off + len, src_off, + PATTERN_SRC | PATTERN_COPY, true); + error_count += dmatest_verify(thread->srcs, src_off + len, + test_buf_size, src_off + len, + PATTERN_SRC, true); + + pr_debug("%s: verifying dest buffer...\n", + thread->task->comm); + error_count += dmatest_verify(thread->dsts, 0, dst_off, + 0, PATTERN_DST, false); + error_count += dmatest_verify(thread->dsts, dst_off, + dst_off + len, src_off, + PATTERN_SRC | PATTERN_COPY, false); + error_count += dmatest_verify(thread->dsts, dst_off + len, + test_buf_size, dst_off + len, + PATTERN_DST, false); + + if (error_count) { + pr_warn("%s: #%u: %u errors with ", + thread_name, total_tests - 1, error_count); + pr_warn("src_off=0x%x dst_off=0x%x len=0x%x\n", + src_off, dst_off, len); + failed_tests++; + } else { + pr_debug("%s: #%u: No errors with ", + thread_name, total_tests - 1); + pr_debug("src_off=0x%x dst_off=0x%x len=0x%x\n", + src_off, dst_off, len); + } + } + + ret = 0; + for (i = 0; thread->dsts[i]; i++) + kfree(thread->dsts[i]); +err_dstbuf: + kfree(thread->dsts); +err_dsts: + for (i = 0; thread->srcs[i]; i++) + kfree(thread->srcs[i]); +err_srcbuf: + kfree(thread->srcs); +err_srcs: + pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", + thread_name, total_tests, failed_tests, ret); + + if (iterations > 0) + while (!kthread_should_stop()) { + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit); + interruptible_sleep_on(&wait_dmatest_exit); + } + + return ret; +} + +static void dmatest_cleanup_channel(struct dmatest_chan *dtc) +{ + struct dmatest_slave_thread *thread; + struct dmatest_slave_thread *_thread; + int ret; + + list_for_each_entry_safe(thread, _thread, &dtc->threads, node) { + ret = kthread_stop(thread->task); + pr_debug("dmatest: thread %s exited with status %d\n", + thread->task->comm, ret); + list_del(&thread->node); + kfree(thread); + } + kfree(dtc); +} + +static int dmatest_add_slave_threads(struct dmatest_chan *tx_dtc, + struct dmatest_chan *rx_dtc) +{ + struct dmatest_slave_thread *thread; + struct dma_chan *tx_chan = tx_dtc->chan; + struct dma_chan *rx_chan = rx_dtc->chan; + + thread = kzalloc(sizeof(struct dmatest_slave_thread), GFP_KERNEL); + if (!thread) { + pr_warn("dmatest: No memory for slave thread %s-%s\n", + dma_chan_name(tx_chan), dma_chan_name(rx_chan)); + + } + + thread->tx_chan = tx_chan; + thread->rx_chan = rx_chan; + thread->type = (enum dma_transaction_type)DMA_SLAVE; + smp_wmb(); + thread->task = kthread_run(dmatest_slave_func, thread, "%s-%s", + dma_chan_name(tx_chan), dma_chan_name(rx_chan)); + if (IS_ERR(thread->task)) { + pr_warn("dmatest: Failed to run thread %s-%s\n", + dma_chan_name(tx_chan), dma_chan_name(rx_chan)); + kfree(thread); + } + + /* srcbuf and dstbuf are allocated by the thread itself */ + + list_add_tail(&thread->node, &tx_dtc->threads); + + /* Added one thread with 2 channels */ + return 1; +} + +static int dmatest_add_slave_channels(struct dma_chan *tx_chan, + struct dma_chan *rx_chan) +{ + struct dmatest_chan *tx_dtc; + struct dmatest_chan *rx_dtc; + unsigned int thread_count = 0; + + tx_dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL); + if (!tx_dtc) { + pr_warn("dmatest: No memory for tx %s\n", + dma_chan_name(tx_chan)); + return -ENOMEM; + } + + rx_dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL); + if (!rx_dtc) { + pr_warn("dmatest: No memory for rx %s\n", + dma_chan_name(rx_chan)); + return -ENOMEM; + } + + tx_dtc->chan = tx_chan; + rx_dtc->chan = rx_chan; + INIT_LIST_HEAD(&tx_dtc->threads); + INIT_LIST_HEAD(&rx_dtc->threads); + + dmatest_add_slave_threads(tx_dtc, rx_dtc); + thread_count += 1; + + pr_info("dmatest: Started %u threads using %s %s\n", + thread_count, dma_chan_name(tx_chan), dma_chan_name(rx_chan)); + + list_add_tail(&tx_dtc->node, &dmatest_channels); + list_add_tail(&rx_dtc->node, &dmatest_channels); + nr_channels += 2; + + return 0; +} + +static bool xdma_filter(struct dma_chan *chan, void *param) +{ + pr_debug("dmatest: Private is %x\n", *((int *)chan->private)); + + if (*((int *)chan->private) == *(int *)param) + return true; + + return false; +} + +static int __init dmatest_init(void) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + int err = 0; + + /* JZ for slave transfer channels */ + enum dma_data_direction direction; + struct dma_chan *rx_chan; + u32 match, device_id = 0; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE | DMA_PRIVATE, mask); + + for (;;) { + direction = DMA_MEM_TO_DEV; + match = (direction & 0xFF) | XILINX_DMA_IP_DMA | + (device_id << XILINX_DMA_DEVICE_ID_SHIFT); + pr_debug("dmatest: match is %x\n", match); + + chan = dma_request_channel(mask, xdma_filter, (void *)&match); + + if (chan) + pr_debug("dmatest: Found tx device\n"); + else + pr_debug("dmatest: No more tx channels available\n"); + + direction = DMA_DEV_TO_MEM; + match = (direction & 0xFF) | XILINX_DMA_IP_DMA | + (device_id << XILINX_DMA_DEVICE_ID_SHIFT); + rx_chan = dma_request_channel(mask, xdma_filter, &match); + + if (rx_chan) + pr_debug("dmatest: Found rx device\n"); + else + pr_debug("dmatest: No more rx channels available\n"); + + if (chan && rx_chan) { + err = dmatest_add_slave_channels(chan, rx_chan); + if (err) { + dma_release_channel(chan); + dma_release_channel(rx_chan); + } + } else + break; + + device_id++; + } + + return err; +} +/* when compiled-in wait for drivers to load first */ +late_initcall(dmatest_init); + +static void __exit dmatest_exit(void) +{ + struct dmatest_chan *dtc, *_dtc; + struct dma_chan *chan; + + list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) { + list_del(&dtc->node); + chan = dtc->chan; + dmatest_cleanup_channel(dtc); + pr_debug("dmatest: dropped channel %s\n", + dma_chan_name(chan)); + dma_release_channel(chan); + } +} +module_exit(dmatest_exit); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx AXI DMA Test Client"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/cdmatest.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/cdmatest.c 2014-07-20 22:06:35.736315945 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * XILINX CDMA Engine test module + * + * Copyright (C) 2012 Xilinx, Inc. All rights reserved. + * + * Based on Atmel DMA Test Client + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/init.h> +#include <linux/kthread.h> +#include <linux/module.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/wait.h> +#include <linux/amba/xilinx_dma.h> + +static unsigned int test_buf_size = 64; +module_param(test_buf_size, uint, S_IRUGO); +MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer"); + +static char test_channel[20]; +module_param_string(channel, test_channel, sizeof(test_channel), S_IRUGO); +MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)"); + +static char test_device[20]; +module_param_string(device, test_device, sizeof(test_device), S_IRUGO); +MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)"); + +static unsigned int threads_per_chan = 1; +module_param(threads_per_chan, uint, S_IRUGO); +MODULE_PARM_DESC(threads_per_chan, + "Number of threads to start per channel (default: 1)"); + +static unsigned int max_channels; +module_param(max_channels, uint, S_IRUGO); +MODULE_PARM_DESC(max_channels, + "Maximum number of channels to use (default: all)"); + +static unsigned int iterations; +module_param(iterations, uint, S_IRUGO); +MODULE_PARM_DESC(iterations, + "Iterations before stopping test (default: infinite)"); + +static unsigned int xor_sources = 3; +module_param(xor_sources, uint, S_IRUGO); +MODULE_PARM_DESC(xor_sources, + "Number of xor source buffers (default: 3)"); + +static unsigned int pq_sources = 3; +module_param(pq_sources, uint, S_IRUGO); +MODULE_PARM_DESC(pq_sources, + "Number of p+q source buffers (default: 3)"); + +/* + * Initialization patterns. All bytes in the source buffer has bit 7 + * set, all bytes in the destination buffer has bit 7 cleared. + * + * Bit 6 is set for all bytes which are to be copied by the DMA + * engine. Bit 5 is set for all bytes which are to be overwritten by + * the DMA engine. + * + * The remaining bits are the inverse of a counter which increments by + * one for each byte address. + */ +#define PATTERN_SRC 0x80 +#define PATTERN_DST 0x00 +#define PATTERN_COPY 0x40 +#define PATTERN_OVERWRITE 0x20 +#define PATTERN_COUNT_MASK 0x1f + +struct cdmatest_thread { + struct list_head node; + struct task_struct *task; + struct dma_chan *chan; + u8 **srcs; + u8 **dsts; + enum dma_transaction_type type; +}; + +struct cdmatest_chan { + struct list_head node; + struct dma_chan *chan; + struct list_head threads; +}; + +/* + * These are protected by dma_list_mutex since they're only used by + * the DMA filter function callback + */ +static LIST_HEAD(cdmatest_channels); +static unsigned int nr_channels; + +static bool cdmatest_match_channel(struct dma_chan *chan) +{ + if (test_channel[0] == '\0') + return true; + return strcmp(dma_chan_name(chan), test_channel) == 0; +} + +static bool cdmatest_match_device(struct dma_device *device) +{ + if (test_device[0] == '\0') + return true; + return strcmp(dev_name(device->dev), test_device) == 0; +} + +static unsigned long cdmatest_random(void) +{ + unsigned long buf; + + get_random_bytes(&buf, sizeof(buf)); + return buf; +} + +static void cdmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len) +{ + unsigned int i; + u8 *buf; + + for (; (buf = *bufs); bufs++) { + for (i = 0; i < start; i++) + buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); + for ( ; i < start + len; i++) + buf[i] = PATTERN_SRC | PATTERN_COPY + | (~i & PATTERN_COUNT_MASK); + for ( ; i < test_buf_size; i++) + buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); + buf++; + } +} + +static void cdmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len) +{ + unsigned int i; + u8 *buf; + + for (; (buf = *bufs); bufs++) { + for (i = 0; i < start; i++) + buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); + for ( ; i < start + len; i++) + buf[i] = PATTERN_DST | PATTERN_OVERWRITE + | (~i & PATTERN_COUNT_MASK); + for ( ; i < test_buf_size; i++) + buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); + } +} + +static void cdmatest_mismatch(u8 actual, u8 pattern, unsigned int index, + unsigned int counter, bool is_srcbuf) +{ + u8 diff = actual ^ pattern; + u8 expected = pattern | (~counter & PATTERN_COUNT_MASK); + const char *thread_name = current->comm; + + if (is_srcbuf) + pr_warn( + "%s: srcbuf[0x%x] overwritten! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if ((pattern & PATTERN_COPY) + && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) + pr_warn( + "%s: dstbuf[0x%x] not copied! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if (diff & PATTERN_SRC) + pr_warn( + "%s: dstbuf[0x%x] was copied! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else + pr_warn( + "%s: dstbuf[0x%x] mismatch! Expected %02x, got %02x\n", + thread_name, index, expected, actual); +} + +static unsigned int cdmatest_verify(u8 **bufs, unsigned int start, + unsigned int end, unsigned int counter, u8 pattern, + bool is_srcbuf) +{ + unsigned int i; + unsigned int error_count = 0; + u8 actual; + u8 expected; + u8 *buf; + unsigned int counter_orig = counter; + + for (; (buf = *bufs); bufs++) { + counter = counter_orig; + for (i = start; i < end; i++) { + actual = buf[i]; + expected = pattern | (~counter & PATTERN_COUNT_MASK); + if (actual != expected) { + if (error_count < 32) + cdmatest_mismatch(actual, pattern, i, + counter, is_srcbuf); + error_count++; + } + counter++; + } + } + + if (error_count > 32) + pr_warn("%s: %u errors suppressed\n", + current->comm, error_count - 32); + + return error_count; +} + +static void cdmatest_callback(void *completion) +{ + complete(completion); +} + +/* + * This function repeatedly tests DMA transfers of various lengths and + * offsets for a given operation type until it is told to exit by + * kthread_stop(). There may be multiple threads running this function + * in parallel for a single channel, and there may be multiple channels + * being tested in parallel. + * + * Before each test, the source and destination buffer is initialized + * with a known pattern. This pattern is different depending on + * whether it's in an area which is supposed to be copied or + * overwritten, and different in the source and destination buffers. + * So if the DMA engine doesn't copy exactly what we tell it to copy, + * we'll notice. + */ +static int cdmatest_func(void *data) +{ + struct cdmatest_thread *thread = data; + struct dma_chan *chan; + const char *thread_name; + unsigned int src_off, dst_off, len; + unsigned int error_count; + unsigned int failed_tests = 0; + unsigned int total_tests = 0; + dma_cookie_t cookie; + enum dma_status status; + enum dma_ctrl_flags flags; + u8 pq_coefs[pq_sources + 1]; + int ret; + int src_cnt; + int dst_cnt; + int i; + + thread_name = current->comm; + + ret = -ENOMEM; + + /* JZ: limit testing scope here */ + iterations = 5; + + smp_rmb(); + chan = thread->chan; + if (thread->type == DMA_MEMCPY) + src_cnt = dst_cnt = 1; + else if (thread->type == DMA_XOR) { + src_cnt = xor_sources | 1; + /* force odd to ensure dst = src */ + dst_cnt = 1; + } else if (thread->type == DMA_PQ) { + src_cnt = pq_sources | 1; + /* force odd to ensure dst = src */ + dst_cnt = 2; + for (i = 0; i < src_cnt; i++) + pq_coefs[i] = 1; + } else + goto err_srcs; + + thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL); + if (!thread->srcs) + goto err_srcs; + for (i = 0; i < src_cnt; i++) { + thread->srcs[i] = kmalloc(test_buf_size, GFP_KERNEL); + if (!thread->srcs[i]) + goto err_srcbuf; + } + thread->srcs[i] = NULL; + + thread->dsts = kcalloc(dst_cnt+1, sizeof(u8 *), GFP_KERNEL); + if (!thread->dsts) + goto err_dsts; + for (i = 0; i < dst_cnt; i++) { + thread->dsts[i] = kmalloc(test_buf_size, GFP_KERNEL); + if (!thread->dsts[i]) + goto err_dstbuf; + } + thread->dsts[i] = NULL; + + set_user_nice(current, 10); + + flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT; + + while (!kthread_should_stop() + && !(iterations && total_tests >= iterations)) { + struct dma_device *dev = chan->device; + struct dma_async_tx_descriptor *tx = NULL; + dma_addr_t dma_srcs[src_cnt]; + dma_addr_t dma_dsts[dst_cnt]; + struct completion cmp; + unsigned long tmo = msecs_to_jiffies(3000); + u8 align = 0; + + total_tests++; + + /* honor alignment restrictions */ + if (thread->type == DMA_MEMCPY) + align = dev->copy_align; + else if (thread->type == DMA_XOR) + align = dev->xor_align; + else if (thread->type == DMA_PQ) + align = dev->pq_align; + + if (1 << align > test_buf_size) { + pr_err("%u-byte buffer too small for %d-byte alignment\n", + test_buf_size, 1 << align); + break; + } + + len = cdmatest_random() % test_buf_size + 1; + len = (len >> align) << align; + if (!len) + len = 1 << align; + src_off = cdmatest_random() % (test_buf_size - len + 1); + dst_off = cdmatest_random() % (test_buf_size - len + 1); + + src_off = (src_off >> align) << align; + dst_off = (dst_off >> align) << align; + + cdmatest_init_srcs(thread->srcs, src_off, len); + cdmatest_init_dsts(thread->dsts, dst_off, len); + + for (i = 0; i < src_cnt; i++) { + u8 *buf = thread->srcs[i] + src_off; + + dma_srcs[i] = dma_map_single(dev->dev, buf, len, + DMA_MEM_TO_DEV); + } + /* map with DMA_MEM_TO_MEM to force writeback/invalidate */ + for (i = 0; i < dst_cnt; i++) { + dma_dsts[i] = dma_map_single(dev->dev, thread->dsts[i], + test_buf_size, + DMA_MEM_TO_MEM); + } + + if (thread->type == DMA_MEMCPY) { + tx = dev->device_prep_dma_memcpy(chan, + dma_dsts[0] + dst_off, + dma_srcs[0], len, + flags); + + } else if (thread->type == DMA_XOR) + tx = dev->device_prep_dma_xor(chan, + dma_dsts[0] + dst_off, + dma_srcs, src_cnt, + len, flags); + else if (thread->type == DMA_PQ) { + dma_addr_t dma_pq[dst_cnt]; + + for (i = 0; i < dst_cnt; i++) + dma_pq[i] = dma_dsts[i] + dst_off; + tx = dev->device_prep_dma_pq(chan, dma_pq, dma_srcs, + src_cnt, pq_coefs, + len, flags); + } + + if (!tx) { + for (i = 0; i < src_cnt; i++) + dma_unmap_single(dev->dev, dma_srcs[i], len, + DMA_MEM_TO_DEV); + for (i = 0; i < dst_cnt; i++) + dma_unmap_single(dev->dev, dma_dsts[i], + test_buf_size, + DMA_MEM_TO_MEM); + pr_warn( + "%s: #%u: prep error with src_off=0x%x ", + thread_name, total_tests - 1, src_off); + pr_warn("dst_off=0x%x len=0x%x\n", + dst_off, len); + msleep(100); + failed_tests++; + continue; + } + + init_completion(&cmp); + tx->callback = cdmatest_callback; + tx->callback_param = &cmp; + cookie = tx->tx_submit(tx); + + if (dma_submit_error(cookie)) { + pr_warn( + "%s: #%u: submit error %d with src_off=0x%x ", + thread_name, total_tests - 1, + cookie, src_off); + pr_warn("dst_off=0x%x len=0x%x\n", + dst_off, len); + msleep(100); + failed_tests++; + continue; + } + dma_async_issue_pending(chan); + + tmo = wait_for_completion_timeout(&cmp, tmo); + status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); + + if (tmo == 0) { + pr_warn("%s: #%u: test timed out\n", + thread_name, total_tests - 1); + failed_tests++; + continue; + } else if (status != DMA_SUCCESS) { + pr_warn( + "%s: #%u: got completion callback, ", + thread_name, total_tests - 1); + pr_warn("but status is \'%s\'\n", + status == DMA_ERROR ? "error" : + "in progress"); + failed_tests++; + continue; + } + + /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */ + for (i = 0; i < dst_cnt; i++) + dma_unmap_single(dev->dev, dma_dsts[i], test_buf_size, + DMA_MEM_TO_MEM); + + error_count = 0; + + pr_debug("%s: verifying source buffer...\n", thread_name); + error_count += cdmatest_verify(thread->srcs, 0, src_off, + 0, PATTERN_SRC, true); + error_count += cdmatest_verify(thread->srcs, src_off, + src_off + len, src_off, + PATTERN_SRC | PATTERN_COPY, true); + error_count += cdmatest_verify(thread->srcs, src_off + len, + test_buf_size, src_off + len, + PATTERN_SRC, true); + + pr_debug("%s: verifying dest buffer...\n", + thread->task->comm); + error_count += cdmatest_verify(thread->dsts, 0, dst_off, + 0, PATTERN_DST, false); + error_count += cdmatest_verify(thread->dsts, dst_off, + dst_off + len, src_off, + PATTERN_SRC | PATTERN_COPY, false); + error_count += cdmatest_verify(thread->dsts, dst_off + len, + test_buf_size, dst_off + len, + PATTERN_DST, false); + + if (error_count) { + pr_warn("%s: #%u: %u errors with ", + thread_name, total_tests - 1, error_count); + pr_warn("src_off=0x%x dst_off=0x%x len=0x%x\n", + src_off, dst_off, len); + failed_tests++; + } else { + pr_debug("%s: #%u: No errors with ", + thread_name, total_tests - 1); + pr_debug("src_off=0x%x dst_off=0x%x len=0x%x\n", + src_off, dst_off, len); + } + } + + ret = 0; + for (i = 0; thread->dsts[i]; i++) + kfree(thread->dsts[i]); +err_dstbuf: + kfree(thread->dsts); +err_dsts: + for (i = 0; thread->srcs[i]; i++) + kfree(thread->srcs[i]); +err_srcbuf: + kfree(thread->srcs); +err_srcs: + pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", + thread_name, total_tests, failed_tests, ret); + + if (iterations > 0) + while (!kthread_should_stop()) { + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_cdmatest_exit); + interruptible_sleep_on(&wait_cdmatest_exit); + } + + return ret; +} + +static void cdmatest_cleanup_channel(struct cdmatest_chan *dtc) +{ + struct cdmatest_thread *thread; + struct cdmatest_thread *_thread; + int ret; + + list_for_each_entry_safe(thread, _thread, &dtc->threads, node) { + ret = kthread_stop(thread->task); + pr_debug("cdmatest: thread %s exited with status %d\n", + thread->task->comm, ret); + list_del(&thread->node); + kfree(thread); + } + kfree(dtc); +} + +static int cdmatest_add_threads(struct cdmatest_chan *dtc, + enum dma_transaction_type type) +{ + struct cdmatest_thread *thread; + struct dma_chan *chan = dtc->chan; + char *op; + unsigned int i; + + if (type == DMA_MEMCPY) + op = "copy"; + else if (type == DMA_XOR) + op = "xor"; + else if (type == DMA_PQ) + op = "pq"; + else + return -EINVAL; + + for (i = 0; i < threads_per_chan; i++) { + thread = kzalloc(sizeof(struct cdmatest_thread), GFP_KERNEL); + if (!thread) { + pr_warn("cdmatest: No memory for %s-%s%u\n", + dma_chan_name(chan), op, i); + + break; + } + thread->chan = dtc->chan; + thread->type = type; + smp_wmb(); + thread->task = kthread_run(cdmatest_func, thread, "%s-%s%u", + dma_chan_name(chan), op, i); + if (IS_ERR(thread->task)) { + pr_warn("cdmatest: Failed to run thread %s-%s%u\n", + dma_chan_name(chan), op, i); + kfree(thread); + break; + } + + /* srcbuf and dstbuf are allocated by the thread itself */ + + list_add_tail(&thread->node, &dtc->threads); + } + + return i; +} + +static int cdmatest_add_channel(struct dma_chan *chan) +{ + struct cdmatest_chan *dtc; + struct dma_device *dma_dev = chan->device; + unsigned int thread_count = 0; + int cnt; + + dtc = kmalloc(sizeof(struct cdmatest_chan), GFP_KERNEL); + if (!dtc) { + pr_warn("cdmatest: No memory for %s\n", dma_chan_name(chan)); + return -ENOMEM; + } + + dtc->chan = chan; + INIT_LIST_HEAD(&dtc->threads); + + if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) { + cnt = cdmatest_add_threads(dtc, DMA_MEMCPY); + thread_count += cnt > 0 ? cnt : 0; + } + if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { + cnt = cdmatest_add_threads(dtc, DMA_XOR); + thread_count += cnt > 0 ? cnt : 0; + } + if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { + cnt = cdmatest_add_threads(dtc, DMA_PQ); + thread_count += cnt > 0 ? cnt : 0; + } + + pr_info("cdmatest: Started %u threads using %s\n", + thread_count, dma_chan_name(chan)); + + list_add_tail(&dtc->node, &cdmatest_channels); + nr_channels++; + + return 0; +} + +static bool filter(struct dma_chan *chan, void *param) +{ + if (!cdmatest_match_channel(chan) || + !cdmatest_match_device(chan->device)) + return false; + + return true; +} + +static int __init cdmatest_init(void) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + int err = 0; + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + for (;;) { + chan = dma_request_channel(mask, filter, NULL); + + if (chan) { + err = cdmatest_add_channel(chan); + if (err) { + dma_release_channel(chan); + break; /* add_channel failed, punt */ + } + } else + break; /* no more channels available */ + if (max_channels && nr_channels >= max_channels) + break; /* we have all we need */ + } + + return err; +} +/* when compiled-in wait for drivers to load first */ +late_initcall(cdmatest_init); + +static void __exit cdmatest_exit(void) +{ + struct cdmatest_chan *dtc, *_dtc; + struct dma_chan *chan; + + list_for_each_entry_safe(dtc, _dtc, &cdmatest_channels, node) { + list_del(&dtc->node); + chan = dtc->chan; + cdmatest_cleanup_channel(dtc); + pr_debug("cdmatest: dropped channel %s\n", + dma_chan_name(chan)); + dma_release_channel(chan); + } +} +module_exit(cdmatest_exit); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx AXI CDMA Test Client"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/Kconfig 2014-07-20 22:06:35.748315747 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# XILINX DMA Engines configuration +# + +menuconfig XILINX_DMA_ENGINES + bool "Xilinx DMA Engines" + help + Enable support for the Xilinx DMA controllers. It supports three DMA + engines: Axi Central DMA (memory to memory transfer), Axi DMA (memory and + device transfer), and Axi VDMA (memory and video device transfer). + +if XILINX_DMA_ENGINES + +config XILINX_AXIDMA + tristate "Xilinx AXI DMA Engine" + select DMA_ENGINE + help + Enable support for Xilinx Axi DMA (memory and device transfer). + +config XILINX_DMATEST + tristate "DMA Test client for AXI DMA" + depends on XILINX_AXIDMA + help + Simple DMA test client. Say N unless you're debugging a + DMA Device driver. + +config XILINX_AXIVDMA + tristate "Xilinx AXI VDMA Engine" + select DMA_ENGINE + help + Enable support for Xilinx Axi VDMA (memory and video device transfer). + +config XILINX_VDMATEST + tristate "DMA Test client for VDMA" + depends on XILINX_AXIVDMA + help + Simple DMA test client. Say N unless you're debugging a + DMA Device driver. + +config XILINX_AXICDMA + tristate "Xilinx AXI CDMA Engine" + select DMA_ENGINE + help + Enable support for Xilinx Axi Central DMA (memory to memory transfer). + +config XILINX_CDMATEST + tristate "DMA Test client for CDMA" + depends on XILINX_AXICDMA + help + Simple DMA test client. Say N unless you're debugging a + DMA Device driver. + +endif # XILINX_DMA_ENGINES Index: linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/Makefile 2014-07-20 22:06:35.753315664 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:3 @ +obj-$(CONFIG_XILINX_AXIDMA) += xilinx_axidma.o +obj-$(CONFIG_XILINX_DMATEST) += axidmatest.o +obj-$(CONFIG_XILINX_AXIVDMA) += xilinx_axivdma.o +obj-$(CONFIG_XILINX_VDMATEST) += vdmatest.o +obj-$(CONFIG_XILINX_AXICDMA) += xilinx_axicdma.o +obj-$(CONFIG_XILINX_CDMATEST) += cdmatest.o Index: linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/vdmatest.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/vdmatest.c 2014-07-20 22:06:35.767315433 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * XILINX VDMA Engine test client driver + * + * Copyright (C) 2010-2013 Xilinx, Inc. All rights reserved. + * + * Based on Atmel DMA Test Client + * + * Description: + * This is a simple Xilinx VDMA test client for AXI VDMA driver. + * This test assumes both the channels of VDMA are enabled in the + * hardware design and configured in back-to-back connection. Test + * starts by pumping the data onto one channel (MM2S) and then + * compares the data that is received on the other channel (S2MM). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/amba/xilinx_dma.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/kthread.h> +#include <linux/module.h> +#include <linux/of_dma.h> +#include <linux/platform_device.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/wait.h> + +static unsigned int test_buf_size = 64; +module_param(test_buf_size, uint, S_IRUGO); +MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer"); + +static unsigned int iterations; +module_param(iterations, uint, S_IRUGO); +MODULE_PARM_DESC(iterations, + "Iterations before stopping test (default: infinite)"); + +/* + * Initialization patterns. All bytes in the source buffer has bit 7 + * set, all bytes in the destination buffer has bit 7 cleared. + * + * Bit 6 is set for all bytes which are to be copied by the DMA + * engine. Bit 5 is set for all bytes which are to be overwritten by + * the DMA engine. + * + * The remaining bits are the inverse of a counter which increments by + * one for each byte address. + */ +#define PATTERN_SRC 0x80 +#define PATTERN_DST 0x00 +#define PATTERN_COPY 0x40 +#define PATTERN_OVERWRITE 0x20 +#define PATTERN_COUNT_MASK 0x1f + +/* Maximum number of frame buffers */ +#define MAX_NUM_FRAMES 32 + +/** + * struct vdmatest_slave_thread - VDMA test thread + * @node: Thread node + * @task: Task structure pointer + * @tx_chan: Tx channel pointer + * @rx_chan: Rx Channel pointer + * @srcs: Source buffer + * @dsts: Destination buffer + * @type: DMA transaction type + */ +struct xilinx_vdmatest_slave_thread { + struct list_head node; + struct task_struct *task; + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + u8 **srcs; + u8 **dsts; + enum dma_transaction_type type; +}; + +/** + * struct vdmatest_chan - VDMA Test channel + * @node: Channel node + * @chan: DMA channel pointer + * @threads: List of VDMA test threads + */ +struct xilinx_vdmatest_chan { + struct list_head node; + struct dma_chan *chan; + struct list_head threads; +}; + +/* Global variables */ +static LIST_HEAD(xilinx_vdmatest_channels); +static unsigned int nr_channels; +static unsigned int frm_cnt; +static dma_addr_t dma_srcs[MAX_NUM_FRAMES]; +static dma_addr_t dma_dsts[MAX_NUM_FRAMES]; +static struct scatterlist tx_sg[MAX_NUM_FRAMES]; +static struct scatterlist rx_sg[MAX_NUM_FRAMES]; + +static void xilinx_vdmatest_init_srcs(u8 **bufs, unsigned int start, + unsigned int len) +{ + unsigned int i; + u8 *buf; + + for (; (buf = *bufs); bufs++) { + for (i = 0; i < start; i++) + buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); + for (; i < start + len; i++) + buf[i] = PATTERN_SRC | PATTERN_COPY + | (~i & PATTERN_COUNT_MASK); + for (; i < test_buf_size; i++) + buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); + buf++; + } +} + +static void xilinx_vdmatest_init_dsts(u8 **bufs, unsigned int start, + unsigned int len) +{ + unsigned int i; + u8 *buf; + + for (; (buf = *bufs); bufs++) { + for (i = 0; i < start; i++) + buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); + for (; i < start + len; i++) + buf[i] = PATTERN_DST | PATTERN_OVERWRITE + | (~i & PATTERN_COUNT_MASK); + for (; i < test_buf_size; i++) + buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); + } +} + +static void xilinx_vdmatest_mismatch(u8 actual, u8 pattern, unsigned int index, + unsigned int counter, bool is_srcbuf) +{ + u8 diff = actual ^ pattern; + u8 expected = pattern | (~counter & PATTERN_COUNT_MASK); + const char *thread_name = current->comm; + + if (is_srcbuf) + pr_warn( + "%s: srcbuf[0x%x] overwritten! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if ((pattern & PATTERN_COPY) + && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) + pr_warn( + "%s: dstbuf[0x%x] not copied! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if (diff & PATTERN_SRC) + pr_warn( + "%s: dstbuf[0x%x] was copied! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else + pr_warn( + "%s: dstbuf[0x%x] mismatch! Expected %02x, got %02x\n", + thread_name, index, expected, actual); +} + +static unsigned int xilinx_vdmatest_verify(u8 **bufs, unsigned int start, + unsigned int end, unsigned int counter, u8 pattern, + bool is_srcbuf) +{ + unsigned int i, error_count = 0; + u8 actual, expected, *buf; + unsigned int counter_orig = counter; + + for (; (buf = *bufs); bufs++) { + counter = counter_orig; + for (i = start; i < end; i++) { + actual = buf[i]; + expected = pattern | (~counter & PATTERN_COUNT_MASK); + if (actual != expected) { + if (error_count < 32) + xilinx_vdmatest_mismatch(actual, + pattern, i, + counter, is_srcbuf); + error_count++; + } + counter++; + } + } + + if (error_count > 32) + pr_warn("%s: %u errors suppressed\n", + current->comm, error_count - 32); + + return error_count; +} + +static void xilinx_vdmatest_slave_tx_callback(void *completion) +{ + pr_debug("Got tx callback\n"); + complete(completion); +} + +static void xilinx_vdmatest_slave_rx_callback(void *completion) +{ + pr_debug("Got rx callback\n"); + complete(completion); +} + +/* + * Function for slave transfers + * Each thread requires 2 channels, one for transmit, and one for receive + */ +static int xilinx_vdmatest_slave_func(void *data) +{ + struct xilinx_vdmatest_slave_thread *thread = data; + struct dma_chan *tx_chan, *rx_chan; + const char *thread_name; + unsigned int len, error_count; + unsigned int failed_tests = 0, total_tests = 0; + dma_cookie_t tx_cookie, rx_cookie; + enum dma_status status; + enum dma_ctrl_flags flags; + int ret = -ENOMEM, i; + int hsize = 64, vsize = 32; + struct xilinx_vdma_config config; + + thread_name = current->comm; + + /* Limit testing scope here */ + iterations = 1; + test_buf_size = hsize * vsize; + + /* This barrier ensures 'thread' is initialized and + * we get valid DMA channels + */ + smp_rmb(); + tx_chan = thread->tx_chan; + rx_chan = thread->rx_chan; + + thread->srcs = kcalloc(frm_cnt+1, sizeof(u8 *), GFP_KERNEL); + if (!thread->srcs) + goto err_srcs; + for (i = 0; i < frm_cnt; i++) { + thread->srcs[i] = kmalloc(test_buf_size, GFP_KERNEL); + if (!thread->srcs[i]) + goto err_srcbuf; + } + + thread->dsts = kcalloc(frm_cnt+1, sizeof(u8 *), GFP_KERNEL); + if (!thread->dsts) + goto err_dsts; + for (i = 0; i < frm_cnt; i++) { + thread->dsts[i] = kmalloc(test_buf_size, GFP_KERNEL); + if (!thread->dsts[i]) + goto err_dstbuf; + } + + set_user_nice(current, 10); + + flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT; + + while (!kthread_should_stop() + && !(iterations && total_tests >= iterations)) { + struct dma_device *tx_dev = tx_chan->device; + struct dma_device *rx_dev = rx_chan->device; + struct dma_async_tx_descriptor *txd = NULL; + struct dma_async_tx_descriptor *rxd = NULL; + struct completion rx_cmp, tx_cmp; + unsigned long rx_tmo = + msecs_to_jiffies(30000); /* RX takes longer */ + unsigned long tx_tmo = msecs_to_jiffies(30000); + u8 align = 0; + + total_tests++; + + /* honor larger alignment restrictions */ + align = tx_dev->copy_align; + if (rx_dev->copy_align > align) + align = rx_dev->copy_align; + + if (1 << align > test_buf_size) { + pr_err("%u-byte buffer too small for %d-byte alignment\n", + test_buf_size, 1 << align); + break; + } + + len = test_buf_size; + xilinx_vdmatest_init_srcs(thread->srcs, 0, len); + xilinx_vdmatest_init_dsts(thread->dsts, 0, len); + + sg_init_table(tx_sg, frm_cnt); + sg_init_table(rx_sg, frm_cnt); + + for (i = 0; i < frm_cnt; i++) { + u8 *buf = thread->srcs[i]; + + dma_srcs[i] = dma_map_single(tx_dev->dev, buf, len, + DMA_MEM_TO_DEV); + pr_debug("src buf %x dma %x\n", (unsigned int)buf, + (unsigned int)dma_srcs[i]); + sg_dma_address(&tx_sg[i]) = dma_srcs[i]; + sg_dma_len(&tx_sg[i]) = len; + } + + for (i = 0; i < frm_cnt; i++) { + dma_dsts[i] = dma_map_single(rx_dev->dev, + thread->dsts[i], + test_buf_size, + DMA_DEV_TO_MEM); + pr_debug("dst %x dma %x\n", + (unsigned int)thread->dsts[i], + (unsigned int)dma_dsts[i]); + sg_dma_address(&rx_sg[i]) = dma_dsts[i]; + sg_dma_len(&rx_sg[i]) = len; + } + + /* Zero out configuration */ + memset(&config, 0, sizeof(struct xilinx_vdma_config)); + + /* Set up hardware configuration information */ + config.vsize = vsize; + config.hsize = hsize; + config.stride = hsize; + config.frm_cnt_en = 1; + config.coalesc = frm_cnt * 10; + config.park = 1; + tx_dev->device_control(tx_chan, DMA_SLAVE_CONFIG, + (unsigned long)&config); + + config.park = 0; + rx_dev->device_control(rx_chan, DMA_SLAVE_CONFIG, + (unsigned long)&config); + + rxd = rx_dev->device_prep_slave_sg(rx_chan, rx_sg, frm_cnt, + DMA_DEV_TO_MEM, flags, NULL); + + txd = tx_dev->device_prep_slave_sg(tx_chan, tx_sg, frm_cnt, + DMA_MEM_TO_DEV, flags, NULL); + + if (!rxd || !txd) { + for (i = 0; i < frm_cnt; i++) + dma_unmap_single(tx_dev->dev, dma_srcs[i], len, + DMA_MEM_TO_DEV); + for (i = 0; i < frm_cnt; i++) + dma_unmap_single(rx_dev->dev, dma_dsts[i], + test_buf_size, + DMA_DEV_TO_MEM); + pr_warn("%s: #%u: prep error with len=0x%x ", + thread_name, total_tests - 1, len); + msleep(100); + failed_tests++; + continue; + } + + init_completion(&rx_cmp); + rxd->callback = xilinx_vdmatest_slave_rx_callback; + rxd->callback_param = &rx_cmp; + rx_cookie = rxd->tx_submit(rxd); + + init_completion(&tx_cmp); + txd->callback = xilinx_vdmatest_slave_tx_callback; + txd->callback_param = &tx_cmp; + tx_cookie = txd->tx_submit(txd); + + if (dma_submit_error(rx_cookie) || + dma_submit_error(tx_cookie)) { + pr_warn("%s: #%u: submit error %d/%d with len=0x%x ", + thread_name, total_tests - 1, + rx_cookie, tx_cookie, len); + msleep(100); + failed_tests++; + continue; + } + dma_async_issue_pending(tx_chan); + dma_async_issue_pending(rx_chan); + + tx_tmo = wait_for_completion_timeout(&tx_cmp, tx_tmo); + + status = dma_async_is_tx_complete(tx_chan, tx_cookie, + NULL, NULL); + + if (tx_tmo == 0) { + pr_warn("%s: #%u: tx test timed out\n", + thread_name, total_tests - 1); + failed_tests++; + continue; + } else if (status != DMA_SUCCESS) { + pr_warn( + "%s: #%u: tx got completion callback, ", + thread_name, total_tests - 1); + pr_warn("but status is \'%s\'\n", + status == DMA_ERROR ? "error" : + "in progress"); + failed_tests++; + continue; + } + + rx_tmo = wait_for_completion_timeout(&rx_cmp, rx_tmo); + status = dma_async_is_tx_complete(rx_chan, rx_cookie, + NULL, NULL); + + if (rx_tmo == 0) { + pr_warn("%s: #%u: rx test timed out\n", + thread_name, total_tests - 1); + failed_tests++; + continue; + } else if (status != DMA_SUCCESS) { + pr_warn( + "%s: #%u: rx got completion callback, ", + thread_name, total_tests - 1); + pr_warn("but status is \'%s\'\n", + status == DMA_ERROR ? "error" : + "in progress"); + failed_tests++; + continue; + } + + /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */ + for (i = 0; i < frm_cnt; i++) + dma_unmap_single(rx_dev->dev, dma_dsts[i], + test_buf_size, DMA_DEV_TO_MEM); + + error_count = 0; + + pr_debug("%s: verifying source buffer...\n", thread_name); + error_count += xilinx_vdmatest_verify(thread->srcs, 0, 0, + 0, PATTERN_SRC, true); + error_count += xilinx_vdmatest_verify(thread->srcs, 0, + len, 0, PATTERN_SRC | PATTERN_COPY, true); + error_count += xilinx_vdmatest_verify(thread->srcs, len, + test_buf_size, len, PATTERN_SRC, true); + + pr_debug("%s: verifying dest buffer...\n", + thread->task->comm); + error_count += xilinx_vdmatest_verify(thread->dsts, 0, 0, + 0, PATTERN_DST, false); + error_count += xilinx_vdmatest_verify(thread->dsts, 0, + len, 0, PATTERN_SRC | PATTERN_COPY, false); + error_count += xilinx_vdmatest_verify(thread->dsts, len, + test_buf_size, len, PATTERN_DST, false); + + if (error_count) { + pr_warn("%s: #%u: %u errors with len=0x%x\n", + thread_name, total_tests - 1, error_count, len); + failed_tests++; + } else { + pr_debug("%s: #%u: No errors with len=0x%x\n", + thread_name, total_tests - 1, len); + } + } + + ret = 0; + for (i = 0; thread->dsts[i]; i++) + kfree(thread->dsts[i]); +err_dstbuf: + kfree(thread->dsts); +err_dsts: + for (i = 0; thread->srcs[i]; i++) + kfree(thread->srcs[i]); +err_srcbuf: + kfree(thread->srcs); +err_srcs: + pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", + thread_name, total_tests, failed_tests, ret); + + if (iterations > 0) + while (!kthread_should_stop()) { + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_vdmatest_exit); + interruptible_sleep_on(&wait_vdmatest_exit); + } + + return ret; +} + +static void xilinx_vdmatest_cleanup_channel(struct xilinx_vdmatest_chan *dtc) +{ + struct xilinx_vdmatest_slave_thread *thread, *_thread; + int ret; + + list_for_each_entry_safe(thread, _thread, + &dtc->threads, node) { + ret = kthread_stop(thread->task); + pr_info("xilinx_vdmatest: thread %s exited with status %d\n", + thread->task->comm, ret); + list_del(&thread->node); + kfree(thread); + } + kfree(dtc); +} + +static int +xilinx_vdmatest_add_slave_threads(struct xilinx_vdmatest_chan *tx_dtc, + struct xilinx_vdmatest_chan *rx_dtc) +{ + struct xilinx_vdmatest_slave_thread *thread; + struct dma_chan *tx_chan = tx_dtc->chan; + struct dma_chan *rx_chan = rx_dtc->chan; + + thread = kzalloc(sizeof(struct xilinx_vdmatest_slave_thread), + GFP_KERNEL); + if (!thread) + pr_warn("xilinx_vdmatest: No memory for slave thread %s-%s\n", + dma_chan_name(tx_chan), dma_chan_name(rx_chan)); + + thread->tx_chan = tx_chan; + thread->rx_chan = rx_chan; + thread->type = (enum dma_transaction_type)DMA_SLAVE; + + /* This barrier ensures the DMA channels in the 'thread' + * are initialized + */ + smp_wmb(); + thread->task = kthread_run(xilinx_vdmatest_slave_func, thread, "%s-%s", + dma_chan_name(tx_chan), dma_chan_name(rx_chan)); + if (IS_ERR(thread->task)) { + pr_warn("xilinx_vdmatest: Failed to run thread %s-%s\n", + dma_chan_name(tx_chan), dma_chan_name(rx_chan)); + kfree(thread); + } + + list_add_tail(&thread->node, &tx_dtc->threads); + + /* Added one thread with 2 channels */ + return 1; +} + +static int xilinx_vdmatest_add_slave_channels(struct dma_chan *tx_chan, + struct dma_chan *rx_chan) +{ + struct xilinx_vdmatest_chan *tx_dtc, *rx_dtc; + unsigned int thread_count = 0; + + tx_dtc = kmalloc(sizeof(struct xilinx_vdmatest_chan), GFP_KERNEL); + if (!tx_dtc) + return -ENOMEM; + + rx_dtc = kmalloc(sizeof(struct xilinx_vdmatest_chan), GFP_KERNEL); + if (!rx_dtc) + return -ENOMEM; + + tx_dtc->chan = tx_chan; + rx_dtc->chan = rx_chan; + INIT_LIST_HEAD(&tx_dtc->threads); + INIT_LIST_HEAD(&rx_dtc->threads); + + xilinx_vdmatest_add_slave_threads(tx_dtc, rx_dtc); + thread_count += 1; + + pr_info("xilinx_vdmatest: Started %u threads using %s %s\n", + thread_count, dma_chan_name(tx_chan), dma_chan_name(rx_chan)); + + list_add_tail(&tx_dtc->node, &xilinx_vdmatest_channels); + list_add_tail(&rx_dtc->node, &xilinx_vdmatest_channels); + nr_channels += 2; + + return 0; +} + +static int xilinx_vdmatest_probe(struct platform_device *pdev) +{ + struct dma_chan *chan, *rx_chan; + int err; + + err = of_property_read_u32(pdev->dev.of_node, + "xlnx,num-fstores", &frm_cnt); + if (err < 0) { + pr_err("xilinx_vdmatest: missing xlnx,num-fstores property\n"); + return err; + } + + chan = dma_request_slave_channel(&pdev->dev, "vdma0"); + if (IS_ERR(chan)) { + pr_err("xilinx_vdmatest: No Tx channel\n"); + return PTR_ERR(chan); + } + + rx_chan = dma_request_slave_channel(&pdev->dev, "vdma1"); + if (IS_ERR(rx_chan)) { + err = PTR_ERR(rx_chan); + pr_err("xilinx_vdmatest: No Rx channel\n"); + goto free_tx; + } + + err = xilinx_vdmatest_add_slave_channels(chan, rx_chan); + if (err) { + pr_err("xilinx_vdmatest: Unable to add channels\n"); + goto free_rx; + } + return 0; + +free_rx: + dma_release_channel(rx_chan); +free_tx: + dma_release_channel(chan); + + return err; +} + +static int xilinx_vdmatest_remove(struct platform_device *pdev) +{ + struct xilinx_vdmatest_chan *dtc, *_dtc; + struct dma_chan *chan; + + list_for_each_entry_safe(dtc, _dtc, &xilinx_vdmatest_channels, node) { + list_del(&dtc->node); + chan = dtc->chan; + xilinx_vdmatest_cleanup_channel(dtc); + pr_info("xilinx_vdmatest: dropped channel %s\n", + dma_chan_name(chan)); + dma_release_channel(chan); + } + return 0; +} + +static const struct of_device_id xilinx_vdmatest_of_ids[] = { + { .compatible = "xlnx,axi-vdma-test",}, + {} +}; + +static struct platform_driver xilinx_vdmatest_driver = { + .driver = { + .name = "xilinx_vdmatest", + .owner = THIS_MODULE, + .of_match_table = xilinx_vdmatest_of_ids, + }, + .probe = xilinx_vdmatest_probe, + .remove = xilinx_vdmatest_remove, +}; + +module_platform_driver(xilinx_vdmatest_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx AXI VDMA Test Client"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/xilinx_axicdma.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/xilinx_axicdma.c 2014-07-20 22:06:35.781315202 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Central DMA Engine support + * + * Copyright (C) 2010 - 2013 Xilinx, Inc. All rights reserved. + * + * Based on the Freescale DMA driver. + * + * Description: + * . Axi CDMA engine, it does transfers between memory and memory + * + * This 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. + */ + +#include <linux/amba/xilinx_dma.h> +#include <linux/dmapool.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* Hw specific definitions */ +#define XILINX_CDMA_MAX_TRANS_LEN 0x7FFFFF /* Max transfer length */ + +/* Register Offsets */ +#define XILINX_CDMA_CONTROL_OFFSET 0x00 /* Control Reg */ +#define XILINX_CDMA_STATUS_OFFSET 0x04 /* Status Reg */ +#define XILINX_CDMA_CDESC_OFFSET 0x08 /* Current descriptor Reg */ +#define XILINX_CDMA_TDESC_OFFSET 0x10 /* Tail descriptor Reg */ +#define XILINX_CDMA_SRCADDR_OFFSET 0x18 /* Source Address Reg */ +#define XILINX_CDMA_DSTADDR_OFFSET 0x20 /* Dest Address Reg */ +#define XILINX_CDMA_BTT_OFFSET 0x28 /* Bytes to transfer Reg */ + +/* General register bits definitions */ +#define XILINX_CDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */ + +#define XILINX_CDMA_SR_IDLE_MASK 0x00000002 /* DMA channel idle */ + +#define XILINX_CDMA_XR_IRQ_IOC_MASK 0x00001000 /* Completion interrupt */ +#define XILINX_CDMA_XR_IRQ_DELAY_MASK 0x00002000 /* Delay interrupt */ +#define XILINX_CDMA_XR_IRQ_ERROR_MASK 0x00004000 /* Error interrupt */ +#define XILINX_CDMA_XR_IRQ_ALL_MASK 0x00007000 /* All interrupts */ + +#define XILINX_CDMA_XR_DELAY_MASK 0xFF000000 /* Delay timeout counter */ +#define XILINX_CDMA_XR_COALESCE_MASK 0x00FF0000 /* Coalesce counter */ + +#define XILINX_CDMA_DELAY_SHIFT 24 /* Delay counter shift */ +#define XILINX_CDMA_COALESCE_SHIFT 16 /* Coaelsce counter shift */ + +#define XILINX_CDMA_DELAY_MAX 0xFF /* Maximum delay counter value */ +/* Maximum coalescing counter value */ +#define XILINX_CDMA_COALESCE_MAX 0xFF + +#define XILINX_CDMA_CR_SGMODE_MASK 0x00000008 /* Scatter gather mode */ + +/* BD definitions for Axi Cdma */ +#define XILINX_CDMA_BD_STS_ALL_MASK 0xF0000000 + +/* Feature encodings */ +#define XILINX_CDMA_FTR_DATA_WIDTH_MASK 0x000000FF /* Data width mask, 1024 */ +#define XILINX_CDMA_FTR_HAS_SG 0x00000100 /* Has SG */ +#define XILINX_CDMA_FTR_HAS_SG_SHIFT 8 /* Has SG shift */ + +/* Delay loop counter to prevent hardware failure */ +#define XILINX_CDMA_RESET_LOOP 1000000 +#define XILINX_CDMA_HALT_LOOP 1000000 + +/* Hardware descriptor */ +struct xilinx_cdma_desc_hw { + u32 next_desc; /* 0x00 */ + u32 pad1; /* 0x04 */ + u32 src_addr; /* 0x08 */ + u32 pad2; /* 0x0C */ + u32 dest_addr; /* 0x10 */ + u32 pad3; /* 0x14 */ + u32 control; /* 0x18 */ + u32 status; /* 0x1C */ +} __aligned(64); + +/* Software descriptor */ +struct xilinx_cdma_desc_sw { + struct xilinx_cdma_desc_hw hw; + struct list_head node; + struct list_head tx_list; + struct dma_async_tx_descriptor async_tx; +} __aligned(64); + +/* Per DMA specific operations should be embedded in the channel structure */ +struct xilinx_cdma_chan { + void __iomem *regs; /* Control status registers */ + dma_cookie_t completed_cookie; /* Maximum cookie completed */ + dma_cookie_t cookie; /* The current cookie */ + spinlock_t lock; /* Descriptor operation lock */ + bool sg_waiting; /* SG transfer waiting */ + struct list_head active_list; /* Active descriptors */ + struct list_head pending_list; /* Descriptors waiting */ + struct dma_chan common; /* DMA common channel */ + struct dma_pool *desc_pool; /* Descriptors pool */ + struct device *dev; /* The dma device */ + int irq; /* Channel IRQ */ + int id; /* Channel ID */ + enum dma_transfer_direction direction; /* Transfer direction */ + int max_len; /* Max data len per transfer */ + bool is_lite; /* Whether is light build */ + bool has_sg; /* Support scatter transfers */ + bool has_dre; /* For unaligned transfers */ + int err; /* Channel has errors */ + struct tasklet_struct tasklet; /* Cleanup work after irq */ + u32 feature; /* IP feature */ + u32 private; /* Match info for + channel request */ + void (*start_transfer)(struct xilinx_cdma_chan *chan); + struct xilinx_cdma_config config; /* Device configuration info */ +}; + +struct xilinx_cdma_device { + void __iomem *regs; + struct device *dev; + struct dma_device common; + struct xilinx_cdma_chan *chan; + u32 feature; +}; + +#define to_xilinx_chan(chan) \ + container_of(chan, struct xilinx_cdma_chan, common) + +/* IO accessors */ +static inline void +cdma_write(struct xilinx_cdma_chan *chan, u32 reg, u32 val) +{ + writel(val, chan->regs + reg); +} + +static inline u32 cdma_read(struct xilinx_cdma_chan *chan, u32 reg) +{ + return readl(chan->regs + reg); +} + +/* Required functions */ + +static int xilinx_cdma_alloc_chan_resources(struct dma_chan *dchan) +{ + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan); + + /* Has this channel already been allocated? */ + if (chan->desc_pool) + return 1; + + /* + * We need the descriptor to be aligned to 64bytes + * for meeting Xilinx DMA specification requirement. + */ + chan->desc_pool = + dma_pool_create("xilinx_cdma_desc_pool", + chan->dev, + sizeof(struct xilinx_cdma_desc_sw), + __alignof__(struct xilinx_cdma_desc_sw), 0); + if (!chan->desc_pool) { + dev_err(chan->dev, + "unable to allocate channel %d descriptor pool\n", + chan->id); + return -ENOMEM; + } + + chan->completed_cookie = 1; + chan->cookie = 1; + + /* there is at least one descriptor free to be allocated */ + return 1; +} + +static void xilinx_cdma_free_desc_list(struct xilinx_cdma_chan *chan, + struct list_head *list) +{ + struct xilinx_cdma_desc_sw *desc, *_desc; + + list_for_each_entry_safe(desc, _desc, list, node) { + list_del(&desc->node); + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); + } +} + +static void xilinx_cdma_free_desc_list_reverse(struct xilinx_cdma_chan *chan, + struct list_head *list) +{ + struct xilinx_cdma_desc_sw *desc, *_desc; + + list_for_each_entry_safe_reverse(desc, _desc, list, node) { + list_del(&desc->node); + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); + } +} + +static void xilinx_cdma_free_chan_resources(struct dma_chan *dchan) +{ + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan); + unsigned long flags; + + dev_dbg(chan->dev, "Free all channel resources.\n"); + spin_lock_irqsave(&chan->lock, flags); + xilinx_cdma_free_desc_list(chan, &chan->active_list); + xilinx_cdma_free_desc_list(chan, &chan->pending_list); + spin_unlock_irqrestore(&chan->lock, flags); + + dma_pool_destroy(chan->desc_pool); + chan->desc_pool = NULL; +} + +static enum dma_status xilinx_cdma_desc_status(struct xilinx_cdma_chan *chan, + struct xilinx_cdma_desc_sw *desc) +{ + return dma_async_is_complete(desc->async_tx.cookie, + chan->completed_cookie, + chan->cookie); +} + +static void xilinx_cdma_chan_desc_cleanup(struct xilinx_cdma_chan *chan) +{ + struct xilinx_cdma_desc_sw *desc, *_desc; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + + list_for_each_entry_safe(desc, _desc, &chan->active_list, node) { + dma_async_tx_callback callback; + void *callback_param; + + if (xilinx_cdma_desc_status(chan, desc) == DMA_IN_PROGRESS) + break; + + /* Remove from the list of running transactions */ + list_del(&desc->node); + + /* Run the link descriptor callback function */ + callback = desc->async_tx.callback; + callback_param = desc->async_tx.callback_param; + if (callback) { + spin_unlock_irqrestore(&chan->lock, flags); + callback(callback_param); + spin_lock_irqsave(&chan->lock, flags); + } + + /* Run any dependencies, then free the descriptor */ + dma_run_dependencies(&desc->async_tx); + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); + } + + spin_unlock_irqrestore(&chan->lock, flags); +} + +static enum dma_status xilinx_tx_status(struct dma_chan *dchan, + dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan); + dma_cookie_t last_used; + dma_cookie_t last_complete; + + xilinx_cdma_chan_desc_cleanup(chan); + + last_used = dchan->cookie; + last_complete = chan->completed_cookie; + + dma_set_tx_state(txstate, last_complete, last_used, 0); + + return dma_async_is_complete(cookie, last_complete, last_used); +} + +static int cdma_is_idle(struct xilinx_cdma_chan *chan) +{ + return cdma_read(chan, XILINX_CDMA_STATUS_OFFSET) & + XILINX_CDMA_SR_IDLE_MASK; +} + +/* Only needed for Axi CDMA v2_00_a or earlier core */ +static void cdma_sg_toggle(struct xilinx_cdma_chan *chan) +{ + cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, + cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) & + ~XILINX_CDMA_CR_SGMODE_MASK); + + cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, + cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) | + XILINX_CDMA_CR_SGMODE_MASK); +} + +static void xilinx_cdma_start_transfer(struct xilinx_cdma_chan *chan) +{ + unsigned long flags; + struct xilinx_cdma_desc_sw *desch, *desct; + struct xilinx_cdma_desc_hw *hw; + + if (chan->err) + return; + + spin_lock_irqsave(&chan->lock, flags); + + if (list_empty(&chan->pending_list)) + goto out_unlock; + + /* If hardware is busy, cannot submit */ + if (!cdma_is_idle(chan)) { + dev_dbg(chan->dev, "DMA controller still busy %x\n", + cdma_read(chan, XILINX_CDMA_STATUS_OFFSET)); + goto out_unlock; + } + + /* Enable interrupts */ + cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, + cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) | + XILINX_CDMA_XR_IRQ_ALL_MASK); + + desch = list_first_entry(&chan->pending_list, + struct xilinx_cdma_desc_sw, node); + + if (chan->has_sg) { + + /* If hybrid mode, append pending list to active list */ + desct = container_of(chan->pending_list.prev, + struct xilinx_cdma_desc_sw, node); + + list_splice_tail_init(&chan->pending_list, &chan->active_list); + + /* + * If hardware is idle, then all descriptors on the active list + * are done, start new transfers + */ + cdma_sg_toggle(chan); + + cdma_write(chan, XILINX_CDMA_CDESC_OFFSET, + desch->async_tx.phys); + + /* Update tail ptr register and start the transfer */ + cdma_write(chan, XILINX_CDMA_TDESC_OFFSET, + desch->async_tx.phys); + goto out_unlock; + } + + /* In simple mode */ + list_del(&desch->node); + list_add_tail(&desch->node, &chan->active_list); + + hw = &desch->hw; + + cdma_write(chan, XILINX_CDMA_SRCADDR_OFFSET, hw->src_addr); + cdma_write(chan, XILINX_CDMA_DSTADDR_OFFSET, hw->dest_addr); + + /* Start the transfer */ + cdma_write(chan, XILINX_CDMA_BTT_OFFSET, + hw->control & XILINX_CDMA_MAX_TRANS_LEN); + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); +} + +/* + * If sg mode, link the pending list to running list; if simple mode, get the + * head of the pending list and submit it to hw + */ +static void xilinx_cdma_issue_pending(struct dma_chan *dchan) +{ + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan); + + xilinx_cdma_start_transfer(chan); +} + +/** + * xilinx_cdma_update_completed_cookie - Update the completed cookie. + * @chan : xilinx DMA channel + * + * CONTEXT: hardirq + */ +static void xilinx_cdma_update_completed_cookie(struct xilinx_cdma_chan *chan) +{ + struct xilinx_cdma_desc_sw *desc = NULL; + struct xilinx_cdma_desc_hw *hw = NULL; + unsigned long flags; + dma_cookie_t cookie = -EBUSY; + int done = 0; + + spin_lock_irqsave(&chan->lock, flags); + + if (list_empty(&chan->active_list)) { + dev_dbg(chan->dev, "no running descriptors\n"); + goto out_unlock; + } + + /* Get the last completed descriptor, update the cookie to that */ + list_for_each_entry(desc, &chan->active_list, node) { + if (chan->has_sg) { + hw = &desc->hw; + + /* If a BD has no status bits set, hw has it */ + if (!(hw->status & XILINX_CDMA_BD_STS_ALL_MASK)) { + break; + } else { + done = 1; + cookie = desc->async_tx.cookie; + } + } else { + /* In non-SG mode, all active entries are done */ + done = 1; + cookie = desc->async_tx.cookie; + } + } + + if (done) + chan->completed_cookie = cookie; + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); +} + +/* Reset hardware */ +static int cdma_reset(struct xilinx_cdma_chan *chan) +{ + int loop = XILINX_CDMA_RESET_LOOP; + u32 tmp; + + cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, + cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) | + XILINX_CDMA_CR_RESET_MASK); + + tmp = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) & + XILINX_CDMA_CR_RESET_MASK; + + /* Wait for the hardware to finish reset */ + while (loop && tmp) { + tmp = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) & + XILINX_CDMA_CR_RESET_MASK; + loop -= 1; + } + + if (!loop) { + dev_err(chan->dev, "reset timeout, cr %x, sr %x\n", + cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET), + cdma_read(chan, XILINX_CDMA_STATUS_OFFSET)); + return -EBUSY; + } + + /* For Axi CDMA, always do sg transfers if sg mode is built in */ + if (chan->has_sg) + cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, + tmp | XILINX_CDMA_CR_SGMODE_MASK); + + return 0; +} + + +static irqreturn_t cdma_intr_handler(int irq, void *data) +{ + struct xilinx_cdma_chan *chan = data; + int update_cookie = 0; + int to_transfer = 0; + u32 stat, reg; + + reg = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET); + + /* Disable intr */ + cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, + reg & ~XILINX_CDMA_XR_IRQ_ALL_MASK); + + stat = cdma_read(chan, XILINX_CDMA_STATUS_OFFSET); + if (!(stat & XILINX_CDMA_XR_IRQ_ALL_MASK)) + return IRQ_NONE; + + /* Ack the interrupts */ + cdma_write(chan, XILINX_CDMA_STATUS_OFFSET, + XILINX_CDMA_XR_IRQ_ALL_MASK); + + /* Check for only the interrupts which are enabled */ + stat &= (reg & XILINX_CDMA_XR_IRQ_ALL_MASK); + + if (stat & XILINX_CDMA_XR_IRQ_ERROR_MASK) { + dev_err(chan->dev, + "Channel %x has errors %x, cdr %x tdr %x\n", + (u32)chan, + (u32)cdma_read(chan, XILINX_CDMA_STATUS_OFFSET), + (u32)cdma_read(chan, XILINX_CDMA_CDESC_OFFSET), + (u32)cdma_read(chan, XILINX_CDMA_TDESC_OFFSET)); + chan->err = 1; + } + + /* + * Device takes too long to do the transfer when user requires + * responsiveness + */ + if (stat & XILINX_CDMA_XR_IRQ_DELAY_MASK) + dev_dbg(chan->dev, "Inter-packet latency too long\n"); + + if (stat & XILINX_CDMA_XR_IRQ_IOC_MASK) { + update_cookie = 1; + to_transfer = 1; + } + + if (update_cookie) + xilinx_cdma_update_completed_cookie(chan); + + if (to_transfer) + chan->start_transfer(chan); + + tasklet_schedule(&chan->tasklet); + return IRQ_HANDLED; +} + +static void cdma_do_tasklet(unsigned long data) +{ + struct xilinx_cdma_chan *chan = (struct xilinx_cdma_chan *)data; + + xilinx_cdma_chan_desc_cleanup(chan); +} + +/* Append the descriptor list to the pending list */ +static void append_desc_queue(struct xilinx_cdma_chan *chan, + struct xilinx_cdma_desc_sw *desc) +{ + struct xilinx_cdma_desc_sw *tail = + container_of(chan->pending_list.prev, + struct xilinx_cdma_desc_sw, node); + struct xilinx_cdma_desc_hw *hw; + + if (list_empty(&chan->pending_list)) + goto out_splice; + + /* + * Add the hardware descriptor to the chain of hardware descriptors + * that already exists in memory. + */ + hw = &(tail->hw); + hw->next_desc = (u32)desc->async_tx.phys; + + /* + * Add the software descriptor and all children to the list + * of pending transactions + */ +out_splice: + list_splice_tail_init(&desc->tx_list, &chan->pending_list); +} + +/* + * Assign cookie to each descriptor, and append the descriptors to the pending + * list + */ +static dma_cookie_t xilinx_cdma_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct xilinx_cdma_chan *chan = to_xilinx_chan(tx->chan); + struct xilinx_cdma_desc_sw *desc = + container_of(tx, struct xilinx_cdma_desc_sw, async_tx); + struct xilinx_cdma_desc_sw *child; + unsigned long flags; + dma_cookie_t cookie = -EBUSY; + + if (chan->err) { + /* + * If reset fails, need to hard reset the system. + * Channel is no longer functional + */ + if (!cdma_reset(chan)) + chan->err = 0; + else + return cookie; + } + + spin_lock_irqsave(&chan->lock, flags); + + /* + * assign cookies to all of the software descriptors + * that make up this transaction + */ + cookie = chan->cookie; + list_for_each_entry(child, &desc->tx_list, node) { + cookie++; + if (cookie < 0) + cookie = DMA_MIN_COOKIE; + + child->async_tx.cookie = cookie; + } + + chan->cookie = cookie; + + /* put this transaction onto the tail of the pending queue */ + append_desc_queue(chan, desc); + + spin_unlock_irqrestore(&chan->lock, flags); + + return cookie; +} + +static struct xilinx_cdma_desc_sw *xilinx_cdma_alloc_descriptor( + struct xilinx_cdma_chan *chan) +{ + struct xilinx_cdma_desc_sw *desc; + dma_addr_t pdesc; + + desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc); + if (!desc) { + dev_dbg(chan->dev, "out of memory for desc\n"); + return NULL; + } + + memset(desc, 0, sizeof(*desc)); + INIT_LIST_HEAD(&desc->tx_list); + dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); + desc->async_tx.tx_submit = xilinx_cdma_tx_submit; + desc->async_tx.phys = pdesc; + + return desc; +} + +/** + * xilinx_cdma_prep_memcpy - prepare descriptors for a memcpy transaction + * @dchan: DMA channel + * @dma_dst: destination address + * @dma_src: source address + * @len: transfer length + * @flags: transfer ack flags + */ +static struct dma_async_tx_descriptor *xilinx_cdma_prep_memcpy( + struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src, + size_t len, unsigned long flags) +{ + struct xilinx_cdma_chan *chan; + struct xilinx_cdma_desc_sw *first = NULL, *prev = NULL, *new; + struct xilinx_cdma_desc_hw *hw, *prev_hw; + size_t copy; + dma_addr_t src = dma_src; + dma_addr_t dst = dma_dst; + + if (!dchan) + return NULL; + + if (!len) + return NULL; + + chan = to_xilinx_chan(dchan); + + if (chan->err) { + + /* + * If reset fails, need to hard reset the system. + * Channel is no longer functional + */ + if (!cdma_reset(chan)) + chan->err = 0; + else + return NULL; + } + + /* + * If build does not have Data Realignment Engine (DRE), + * src has to be aligned + */ + if (!chan->has_dre) { + if ((dma_src & + (chan->feature & XILINX_CDMA_FTR_DATA_WIDTH_MASK)) || + (dma_dst & + (chan->feature & XILINX_CDMA_FTR_DATA_WIDTH_MASK))) { + + dev_err(chan->dev, + "Src/Dest address not aligned when no DRE\n"); + + return NULL; + } + } + + do { + /* Allocate descriptor from DMA pool */ + new = xilinx_cdma_alloc_descriptor(chan); + if (!new) { + dev_err(chan->dev, + "No free memory for link descriptor\n"); + goto fail; + } + + copy = min_t(size_t, len, chan->max_len); + + /* if lite build, transfer cannot cross page boundary */ + if (chan->is_lite) + copy = min(copy, (size_t)(PAGE_MASK - + (src & PAGE_MASK))); + + if (!copy) { + dev_err(chan->dev, + "Got zero transfer length for %x\n", + (unsigned int)src); + goto fail; + } + + hw = &(new->hw); + hw->control = + (hw->control & ~XILINX_CDMA_MAX_TRANS_LEN) | copy; + hw->src_addr = src; + hw->dest_addr = dst; + + if (!first) + first = new; + else { + prev_hw = &(prev->hw); + prev_hw->next_desc = new->async_tx.phys; + } + + new->async_tx.cookie = 0; + async_tx_ack(&new->async_tx); + + prev = new; + len -= copy; + src += copy; + dst += copy; + + /* Insert the descriptor to the list */ + list_add_tail(&new->node, &first->tx_list); + } while (len); + + /* Link the last BD with the first BD */ + hw->next_desc = first->async_tx.phys; + + new->async_tx.flags = flags; /* client is in control of this ack */ + new->async_tx.cookie = -EBUSY; + + return &first->async_tx; + +fail: + if (!first) + return NULL; + + xilinx_cdma_free_desc_list_reverse(chan, &first->tx_list); + return NULL; +} + +/* Run-time device configuration for Axi CDMA */ +static int xilinx_cdma_device_control(struct dma_chan *dchan, + enum dma_ctrl_cmd cmd, unsigned long arg) +{ + struct xilinx_cdma_chan *chan; + unsigned long flags; + + if (!dchan) + return -EINVAL; + + chan = to_xilinx_chan(dchan); + + if (cmd == DMA_TERMINATE_ALL) { + spin_lock_irqsave(&chan->lock, flags); + + /* Remove and free all of the descriptors in the lists */ + xilinx_cdma_free_desc_list(chan, &chan->pending_list); + xilinx_cdma_free_desc_list(chan, &chan->active_list); + + spin_unlock_irqrestore(&chan->lock, flags); + return 0; + } else if (cmd == DMA_SLAVE_CONFIG) { + /* + * Configure interrupt coalescing and delay counter + * Use value XILINX_CDMA_NO_CHANGE to signal no change + */ + struct xilinx_cdma_config *cfg = + (struct xilinx_cdma_config *)arg; + u32 reg = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET); + + if (cfg->coalesc <= XILINX_CDMA_COALESCE_MAX) { + reg &= ~XILINX_CDMA_XR_COALESCE_MASK; + reg |= cfg->coalesc << XILINX_CDMA_COALESCE_SHIFT; + + chan->config.coalesc = cfg->coalesc; + } + + if (cfg->delay <= XILINX_CDMA_DELAY_MAX) { + reg &= ~XILINX_CDMA_XR_DELAY_MASK; + reg |= cfg->delay << XILINX_CDMA_DELAY_SHIFT; + chan->config.delay = cfg->delay; + } + + cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, reg); + + return 0; + } + + return -ENXIO; +} + +static void xilinx_cdma_free_channels(struct xilinx_cdma_device *xdev) +{ + + list_del(&xdev->chan->common.device_node); + tasklet_kill(&xdev->chan->tasklet); + irq_dispose_mapping(xdev->chan->irq); +} + +/* + * Probing channels + * + * . Get channel features from the device tree entry + * . Initialize special channel handling routines + */ +static int xilinx_cdma_chan_probe(struct xilinx_cdma_device *xdev, + struct device_node *node, u32 feature) +{ + struct xilinx_cdma_chan *chan; + int err; + u32 device_id, value, width = 0; + + /* alloc channel */ + chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + chan->feature = feature; + chan->max_len = XILINX_CDMA_MAX_TRANS_LEN; + + chan->has_dre = of_property_read_bool(node, "xlnx,include-dre"); + + err = of_property_read_u32(node, "xlnx,datawidth", &value); + if (err) { + dev_err(xdev->dev, "unable to read datawidth property"); + return err; + } else { + width = value >> 3; /* convert bits to bytes */ + + /* If data width is greater than 8 bytes, DRE is not in hw */ + if (width > 8) + chan->has_dre = 0; + + chan->feature |= width - 1; + } + + err = of_property_read_u32(node, "xlnx,device-id", &device_id); + if (err) { + dev_err(xdev->dev, "unable to read device id property"); + return err; + } + + chan->direction = DMA_MEM_TO_MEM; + chan->start_transfer = xilinx_cdma_start_transfer; + + chan->has_sg = (xdev->feature & XILINX_CDMA_FTR_HAS_SG) >> + XILINX_CDMA_FTR_HAS_SG_SHIFT; + + chan->is_lite = of_property_read_bool(node, "xlnx,lite-mode"); + if (chan->is_lite) { + err = of_property_read_u32(node, "xlnx,max-burst-len", &value); + if (err) { + dev_err(xdev->dev, "unable to read max burstlen property"); + return err; + } + if (value) { + if (!width) { + dev_err(xdev->dev, + "Lite mode w/o data width property\n"); + return -EPERM; + } + chan->max_len = width * value; + } + } + + chan->regs = xdev->regs; + + /* + * Used by dmatest channel matching in slave transfers + * Can change it to be a structure to have more matching information + */ + chan->private = (chan->direction & 0xFF) | XILINX_DMA_IP_CDMA | + (device_id << XILINX_DMA_DEVICE_ID_SHIFT); + chan->common.private = (void *)&(chan->private); + + if (!chan->has_dre) + xdev->common.copy_align = fls(width - 1); + + chan->dev = xdev->dev; + xdev->chan = chan; + + /* Initialize the channel */ + err = cdma_reset(chan); + if (err) { + dev_err(xdev->dev, "Reset channel failed\n"); + return err; + } + + spin_lock_init(&chan->lock); + INIT_LIST_HEAD(&chan->pending_list); + INIT_LIST_HEAD(&chan->active_list); + + chan->common.device = &xdev->common; + + /* Find the IRQ line, if it exists in the device tree */ + chan->irq = irq_of_parse_and_map(node, 0); + err = devm_request_irq(xdev->dev, chan->irq, cdma_intr_handler, + IRQF_SHARED, + "xilinx-cdma-controller", chan); + if (err) { + dev_err(xdev->dev, "unable to request IRQ\n"); + return err; + } + + tasklet_init(&chan->tasklet, cdma_do_tasklet, (unsigned long)chan); + + /* Add the channel to DMA device channel list */ + list_add_tail(&chan->common.device_node, &xdev->common.channels); + + return 0; +} + +static int xilinx_cdma_probe(struct platform_device *pdev) +{ + struct xilinx_cdma_device *xdev; + struct device_node *child, *node; + struct resource *res; + int ret; + u32 value; + + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); + if (!xdev) + return -ENOMEM; + + xdev->dev = &(pdev->dev); + INIT_LIST_HEAD(&xdev->common.channels); + + node = pdev->dev.of_node; + + /* iomap registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xdev->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xdev->regs)) + return PTR_ERR(xdev->regs); + + /* Check if SG is enabled */ + value = of_property_read_bool(node, "xlnx,include-sg"); + if (value) + xdev->feature |= XILINX_CDMA_FTR_HAS_SG; + + /* Axi CDMA only does memcpy */ + dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask); + xdev->common.device_prep_dma_memcpy = xilinx_cdma_prep_memcpy; + + xdev->common.device_control = xilinx_cdma_device_control; + xdev->common.device_issue_pending = xilinx_cdma_issue_pending; + xdev->common.device_alloc_chan_resources = + xilinx_cdma_alloc_chan_resources; + xdev->common.device_free_chan_resources = + xilinx_cdma_free_chan_resources; + xdev->common.device_tx_status = xilinx_tx_status; + xdev->common.dev = &pdev->dev; + + platform_set_drvdata(pdev, xdev); + + for_each_child_of_node(node, child) { + ret = xilinx_cdma_chan_probe(xdev, child, xdev->feature); + if (ret) { + dev_err(&pdev->dev, "Probing channels failed\n"); + goto free_chan_resources; + } + } + + ret = dma_async_device_register(&xdev->common); + if (ret) { + dev_err(&pdev->dev, "CDMA device registration failed\n"); + goto free_chan_resources; + } + + dev_info(&pdev->dev, "Probing xilinx axi cdma engine...Successful\n"); + + return 0; + +free_chan_resources: + xilinx_cdma_free_channels(xdev); + + return ret; +} + +static int xilinx_cdma_remove(struct platform_device *pdev) +{ + struct xilinx_cdma_device *xdev; + + xdev = platform_get_drvdata(pdev); + dma_async_device_unregister(&xdev->common); + + xilinx_cdma_free_channels(xdev); + + return 0; +} + +static const struct of_device_id xilinx_cdma_of_match[] = { + { .compatible = "xlnx,axi-cdma", }, + {} +}; +MODULE_DEVICE_TABLE(of, xilinx_cdma_of_match); + +static struct platform_driver xilinx_cdma_driver = { + .driver = { + .name = "xilinx-cdma", + .owner = THIS_MODULE, + .of_match_table = xilinx_cdma_of_match, + }, + .probe = xilinx_cdma_probe, + .remove = xilinx_cdma_remove, +}; + +module_platform_driver(xilinx_cdma_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx CDMA driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/xilinx_axidma.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/xilinx_axidma.c 2014-07-20 22:06:35.799314906 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx AXI DMA Engine support + * + * Copyright (C) 2012 - 2013 Xilinx, Inc. All rights reserved. + * + * Based on the Freescale DMA driver. + * + * Description: + * . Axi DMA engine, it does transfers between memory and device. It can be + * configured to have one channel or two channels. If configured as two + * channels, one is to transmit to a device and another is to receive from + * a device. + * + * This 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. + */ + +#include <linux/amba/xilinx_dma.h> +#include <linux/dmapool.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* Hw specific definitions */ +#define XILINX_DMA_MAX_CHANS_PER_DEVICE 0x2 /* Max no of channels */ +#define XILINX_DMA_MAX_TRANS_LEN 0x7FFFFF /* Max transfer length */ + +/* Register Offsets */ +#define XILINX_DMA_CONTROL_OFFSET 0x00 /* Control Reg */ +#define XILINX_DMA_STATUS_OFFSET 0x04 /* Status Reg */ +#define XILINX_DMA_CDESC_OFFSET 0x08 /* Current descriptor Reg */ +#define XILINX_DMA_TDESC_OFFSET 0x10 /* Tail descriptor Reg */ +#define XILINX_DMA_SRCADDR_OFFSET 0x18 /* Source Address Reg */ +#define XILINX_DMA_DSTADDR_OFFSET 0x20 /* Dest Address Reg */ +#define XILINX_DMA_BTT_OFFSET 0x28 /* Bytes to transfer Reg */ + +/* General register bits definitions */ +#define XILINX_DMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */ +#define XILINX_DMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA engine */ + +#define XILINX_DMA_SR_HALTED_MASK 0x00000001 /* DMA channel halted */ +#define XILINX_DMA_SR_IDLE_MASK 0x00000002 /* DMA channel idle */ + +#define XILINX_DMA_XR_IRQ_IOC_MASK 0x00001000 /* Completion interrupt */ +#define XILINX_DMA_XR_IRQ_DELAY_MASK 0x00002000 /* Delay interrupt */ +#define XILINX_DMA_XR_IRQ_ERROR_MASK 0x00004000 /* Error interrupt */ +#define XILINX_DMA_XR_IRQ_ALL_MASK 0x00007000 /* All interrupts */ + +#define XILINX_DMA_XR_DELAY_MASK 0xFF000000 /* Delay timeout counter */ +#define XILINX_DMA_XR_COALESCE_MASK 0x00FF0000 /* Coalesce counter */ + +#define XILINX_DMA_DELAY_SHIFT 24 /* Delay timeout counter shift */ +#define XILINX_DMA_COALESCE_SHIFT 16 /* Coalesce counter shift */ + +#define XILINX_DMA_DELAY_MAX 0xFF /* Maximum delay counter value */ +#define XILINX_DMA_COALESCE_MAX 0xFF /* Max coalescing counter value */ + +#define XILINX_DMA_RX_CHANNEL_OFFSET 0x30 /* S2MM Channel Offset */ + +/* BD definitions for AXI Dma */ +#define XILINX_DMA_BD_STS_ALL_MASK 0xF0000000 +#define XILINX_DMA_BD_SOP 0x08000000 /* Start of packet bit */ +#define XILINX_DMA_BD_EOP 0x04000000 /* End of packet bit */ + +/* Feature encodings */ +#define XILINX_DMA_FTR_HAS_SG 0x00000100 /* Has SG */ +#define XILINX_DMA_FTR_HAS_SG_SHIFT 8 /* Has SG shift */ +/* Optional feature for dma */ +#define XILINX_DMA_FTR_STSCNTRL_STRM 0x00010000 + + +/* Delay loop counter to prevent hardware failure */ +#define XILINX_DMA_RESET_LOOP 1000000 +#define XILINX_DMA_HALT_LOOP 1000000 + +#if defined(CONFIG_XILINX_DMATEST) || defined(CONFIG_XILINX_DMATEST_MODULE) +# define TEST_DMA_WITH_LOOPBACK +#endif + +/* Hardware descriptor */ +struct xilinx_dma_desc_hw { + u32 next_desc; /* 0x00 */ + u32 pad1; /* 0x04 */ + u32 buf_addr; /* 0x08 */ + u32 pad2; /* 0x0C */ + u32 pad3; /* 0x10 */ + u32 pad4; /* 0x14 */ + u32 control; /* 0x18 */ + u32 status; /* 0x1C */ + u32 app_0; /* 0x20 */ + u32 app_1; /* 0x24 */ + u32 app_2; /* 0x28 */ + u32 app_3; /* 0x2C */ + u32 app_4; /* 0x30 */ +} __aligned(64); + +/* Software descriptor */ +struct xilinx_dma_desc_sw { + struct xilinx_dma_desc_hw hw; + struct list_head node; + struct list_head tx_list; + struct dma_async_tx_descriptor async_tx; +} __aligned(64); + +/* Per DMA specific operations should be embedded in the channel structure */ +struct xilinx_dma_chan { + void __iomem *regs; /* Control status registers */ + dma_cookie_t completed_cookie; /* The maximum cookie completed */ + dma_cookie_t cookie; /* The current cookie */ + spinlock_t lock; /* Descriptor operation lock */ + bool sg_waiting; /* Scatter gather transfer waiting */ + struct list_head active_list; /* Active descriptors */ + struct list_head pending_list; /* Descriptors waiting */ + struct dma_chan common; /* DMA common channel */ + struct dma_pool *desc_pool; /* Descriptors pool */ + struct device *dev; /* The dma device */ + int irq; /* Channel IRQ */ + int id; /* Channel ID */ + enum dma_transfer_direction direction; + /* Transfer direction */ + int max_len; /* Maximum data len per transfer */ + bool has_sg; /* Support scatter transfers */ + bool has_dre; /* Support unaligned transfers */ + int err; /* Channel has errors */ + struct tasklet_struct tasklet; /* Cleanup work after irq */ + u32 feature; /* IP feature */ + u32 private; /* Match info for channel request */ + void (*start_transfer)(struct xilinx_dma_chan *chan); + struct xilinx_dma_config config; + /* Device configuration info */ +}; + +/* DMA Device Structure */ +struct xilinx_dma_device { + void __iomem *regs; + struct device *dev; + struct dma_device common; + struct xilinx_dma_chan *chan[XILINX_DMA_MAX_CHANS_PER_DEVICE]; + u32 feature; +}; + +#define to_xilinx_chan(chan) \ + container_of(chan, struct xilinx_dma_chan, common) + +/* IO accessors */ +static inline void dma_write(struct xilinx_dma_chan *chan, u32 reg, u32 val) +{ + writel(val, chan->regs + reg); +} + +static inline u32 dma_read(struct xilinx_dma_chan *chan, u32 reg) +{ + return readl(chan->regs + reg); +} + +static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) +{ + struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); + + /* Has this channel already been allocated? */ + if (chan->desc_pool) + return 1; + + /* + * We need the descriptor to be aligned to 64bytes + * for meeting Xilinx DMA specification requirement. + */ + chan->desc_pool = + dma_pool_create("xilinx_dma_desc_pool", chan->dev, + sizeof(struct xilinx_dma_desc_sw), + __alignof__(struct xilinx_dma_desc_sw), 0); + if (!chan->desc_pool) { + dev_err(chan->dev, + "unable to allocate channel %d descriptor pool\n", + chan->id); + return -ENOMEM; + } + + chan->completed_cookie = 1; + chan->cookie = 1; + + /* There is at least one descriptor free to be allocated */ + return 1; +} + +static void xilinx_dma_free_desc_list(struct xilinx_dma_chan *chan, + struct list_head *list) +{ + struct xilinx_dma_desc_sw *desc, *_desc; + + list_for_each_entry_safe(desc, _desc, list, node) { + list_del(&desc->node); + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); + } +} + +static void xilinx_dma_free_desc_list_reverse(struct xilinx_dma_chan *chan, + struct list_head *list) +{ + struct xilinx_dma_desc_sw *desc, *_desc; + + list_for_each_entry_safe_reverse(desc, _desc, list, node) { + list_del(&desc->node); + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); + } +} + +static void xilinx_dma_free_chan_resources(struct dma_chan *dchan) +{ + struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); + unsigned long flags; + + dev_dbg(chan->dev, "Free all channel resources.\n"); + spin_lock_irqsave(&chan->lock, flags); + xilinx_dma_free_desc_list(chan, &chan->active_list); + xilinx_dma_free_desc_list(chan, &chan->pending_list); + spin_unlock_irqrestore(&chan->lock, flags); + + dma_pool_destroy(chan->desc_pool); + chan->desc_pool = NULL; +} + +static enum dma_status xilinx_dma_desc_status(struct xilinx_dma_chan *chan, + struct xilinx_dma_desc_sw *desc) +{ + return dma_async_is_complete(desc->async_tx.cookie, + chan->completed_cookie, + chan->cookie); +} + +static void xilinx_chan_desc_cleanup(struct xilinx_dma_chan *chan) +{ + struct xilinx_dma_desc_sw *desc, *_desc; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + + list_for_each_entry_safe(desc, _desc, &chan->active_list, node) { + dma_async_tx_callback callback; + void *callback_param; + + if (xilinx_dma_desc_status(chan, desc) == DMA_IN_PROGRESS) + break; + + /* Remove from the list of running transactions */ + list_del(&desc->node); + + /* Run the link descriptor callback function */ + callback = desc->async_tx.callback; + callback_param = desc->async_tx.callback_param; + if (callback) { + spin_unlock_irqrestore(&chan->lock, flags); + callback(callback_param); + spin_lock_irqsave(&chan->lock, flags); + } + + /* Run any dependencies, then free the descriptor */ + dma_run_dependencies(&desc->async_tx); + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); + } + + spin_unlock_irqrestore(&chan->lock, flags); +} + +static enum dma_status xilinx_tx_status(struct dma_chan *dchan, + dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); + dma_cookie_t last_used; + dma_cookie_t last_complete; + + xilinx_chan_desc_cleanup(chan); + + last_used = dchan->cookie; + last_complete = chan->completed_cookie; + + dma_set_tx_state(txstate, last_complete, last_used, 0); + + return dma_async_is_complete(cookie, last_complete, last_used); +} + +static int dma_is_running(struct xilinx_dma_chan *chan) +{ + return !(dma_read(chan, XILINX_DMA_STATUS_OFFSET) & + XILINX_DMA_SR_HALTED_MASK) && + (dma_read(chan, XILINX_DMA_CONTROL_OFFSET) & + XILINX_DMA_CR_RUNSTOP_MASK); +} + +static int dma_is_idle(struct xilinx_dma_chan *chan) +{ + return dma_read(chan, XILINX_DMA_STATUS_OFFSET) & + XILINX_DMA_SR_IDLE_MASK; +} + +/* Stop the hardware, the ongoing transfer will be finished */ +static void dma_halt(struct xilinx_dma_chan *chan) +{ + int loop = XILINX_DMA_HALT_LOOP; + + dma_write(chan, XILINX_DMA_CONTROL_OFFSET, + dma_read(chan, XILINX_DMA_CONTROL_OFFSET) & + ~XILINX_DMA_CR_RUNSTOP_MASK); + + /* Wait for the hardware to halt */ + while (loop) { + if (!(dma_read(chan, XILINX_DMA_CONTROL_OFFSET) & + XILINX_DMA_CR_RUNSTOP_MASK)) + break; + + loop -= 1; + } + + if (!loop) { + pr_debug("Cannot stop channel %x: %x\n", + (unsigned int)chan, + (unsigned int)dma_read(chan, + XILINX_DMA_CONTROL_OFFSET)); + chan->err = 1; + } +} + +/* Start the hardware. Transfers are not started yet */ +static void dma_start(struct xilinx_dma_chan *chan) +{ + int loop = XILINX_DMA_HALT_LOOP; + + dma_write(chan, XILINX_DMA_CONTROL_OFFSET, + dma_read(chan, XILINX_DMA_CONTROL_OFFSET) | + XILINX_DMA_CR_RUNSTOP_MASK); + + /* Wait for the hardware to start */ + while (loop) { + if (dma_read(chan, XILINX_DMA_CONTROL_OFFSET) & + XILINX_DMA_CR_RUNSTOP_MASK) + break; + + loop -= 1; + } + + if (!loop) { + pr_debug("Cannot start channel %x: %x\n", + (unsigned int)chan, + (unsigned int)dma_read(chan, + XILINX_DMA_CONTROL_OFFSET)); + + chan->err = 1; + } +} + +static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) +{ + unsigned long flags; + struct xilinx_dma_desc_sw *desch, *desct; + struct xilinx_dma_desc_hw *hw; + + if (chan->err) + return; + + spin_lock_irqsave(&chan->lock, flags); + + if (list_empty(&chan->pending_list)) + goto out_unlock; + + /* If hardware is busy, cannot submit */ + if (dma_is_running(chan) && !dma_is_idle(chan)) { + dev_dbg(chan->dev, "DMA controller still busy\n"); + goto out_unlock; + } + + /* + * If hardware is idle, then all descriptors on active list are + * done, start new transfers + */ + dma_halt(chan); + + if (chan->err) + goto out_unlock; + + if (chan->has_sg) { + desch = list_first_entry(&chan->pending_list, + struct xilinx_dma_desc_sw, node); + + desct = container_of(chan->pending_list.prev, + struct xilinx_dma_desc_sw, node); + + dma_write(chan, XILINX_DMA_CDESC_OFFSET, desch->async_tx.phys); + + dma_start(chan); + + if (chan->err) + goto out_unlock; + list_splice_tail_init(&chan->pending_list, &chan->active_list); + + /* Enable interrupts */ + dma_write(chan, XILINX_DMA_CONTROL_OFFSET, + dma_read(chan, XILINX_DMA_CONTROL_OFFSET) | + XILINX_DMA_XR_IRQ_ALL_MASK); + + /* Update tail ptr register and start the transfer */ + dma_write(chan, XILINX_DMA_TDESC_OFFSET, desct->async_tx.phys); + goto out_unlock; + } + + /* In simple mode */ + dma_halt(chan); + + if (chan->err) + goto out_unlock; + + pr_info("xilinx_dma_start_transfer::simple DMA mode\n"); + + desch = list_first_entry(&chan->pending_list, + struct xilinx_dma_desc_sw, node); + + list_del(&desch->node); + list_add_tail(&desch->node, &chan->active_list); + + dma_start(chan); + + if (chan->err) + goto out_unlock; + + hw = &desch->hw; + + /* Enable interrupts */ + dma_write(chan, XILINX_DMA_CONTROL_OFFSET, + dma_read(chan, XILINX_DMA_CONTROL_OFFSET) | + XILINX_DMA_XR_IRQ_ALL_MASK); + + dma_write(chan, XILINX_DMA_SRCADDR_OFFSET, hw->buf_addr); + + /* Start the transfer */ + dma_write(chan, XILINX_DMA_BTT_OFFSET, + hw->control & XILINX_DMA_MAX_TRANS_LEN); + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); +} + +static void xilinx_dma_issue_pending(struct dma_chan *dchan) +{ + struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); + + xilinx_dma_start_transfer(chan); +} + +/** + * xilinx_dma_update_completed_cookie - Update the completed cookie. + * @chan : xilinx DMA channel + * + * CONTEXT: hardirq + */ +static void xilinx_dma_update_completed_cookie(struct xilinx_dma_chan *chan) +{ + struct xilinx_dma_desc_sw *desc = NULL; + struct xilinx_dma_desc_hw *hw = NULL; + unsigned long flags; + dma_cookie_t cookie = -EBUSY; + int done = 0; + + spin_lock_irqsave(&chan->lock, flags); + + if (list_empty(&chan->active_list)) { + dev_dbg(chan->dev, "no running descriptors\n"); + goto out_unlock; + } + + /* Get the last completed descriptor, update the cookie to that */ + list_for_each_entry(desc, &chan->active_list, node) { + if (chan->has_sg) { + hw = &desc->hw; + + /* If a BD has no status bits set, hw has it */ + if (!(hw->status & XILINX_DMA_BD_STS_ALL_MASK)) { + break; + } else { + done = 1; + cookie = desc->async_tx.cookie; + } + } else { + /* In non-SG mode, all active entries are done */ + done = 1; + cookie = desc->async_tx.cookie; + } + } + + if (done) + chan->completed_cookie = cookie; + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); +} + +/* Reset hardware */ +static int dma_reset(struct xilinx_dma_chan *chan) +{ + int loop = XILINX_DMA_RESET_LOOP; + u32 tmp; + + dma_write(chan, XILINX_DMA_CONTROL_OFFSET, + dma_read(chan, XILINX_DMA_CONTROL_OFFSET) | + XILINX_DMA_CR_RESET_MASK); + + tmp = dma_read(chan, XILINX_DMA_CONTROL_OFFSET) & + XILINX_DMA_CR_RESET_MASK; + + /* Wait for the hardware to finish reset */ + while (loop && tmp) { + tmp = dma_read(chan, XILINX_DMA_CONTROL_OFFSET) & + XILINX_DMA_CR_RESET_MASK; + loop -= 1; + } + + if (!loop) { + dev_err(chan->dev, "reset timeout, cr %x, sr %x\n", + dma_read(chan, XILINX_DMA_CONTROL_OFFSET), + dma_read(chan, XILINX_DMA_STATUS_OFFSET)); + return -EBUSY; + } + + return 0; +} + +static irqreturn_t dma_intr_handler(int irq, void *data) +{ + struct xilinx_dma_chan *chan = data; + int update_cookie = 0; + int to_transfer = 0; + u32 stat, reg; + + reg = dma_read(chan, XILINX_DMA_CONTROL_OFFSET); + + /* Disable intr */ + dma_write(chan, XILINX_DMA_CONTROL_OFFSET, + reg & ~XILINX_DMA_XR_IRQ_ALL_MASK); + + stat = dma_read(chan, XILINX_DMA_STATUS_OFFSET); + if (!(stat & XILINX_DMA_XR_IRQ_ALL_MASK)) + return IRQ_NONE; + + /* Ack the interrupts */ + dma_write(chan, XILINX_DMA_STATUS_OFFSET, + XILINX_DMA_XR_IRQ_ALL_MASK); + + /* Check for only the interrupts which are enabled */ + stat &= (reg & XILINX_DMA_XR_IRQ_ALL_MASK); + + if (stat & XILINX_DMA_XR_IRQ_ERROR_MASK) { + dev_err(chan->dev, + "Channel %x has errors %x, cdr %x tdr %x\n", + (unsigned int)chan, + (unsigned int)dma_read(chan, XILINX_DMA_STATUS_OFFSET), + (unsigned int)dma_read(chan, XILINX_DMA_CDESC_OFFSET), + (unsigned int)dma_read(chan, XILINX_DMA_TDESC_OFFSET)); + chan->err = 1; + } + + /* + * Device takes too long to do the transfer when user requires + * responsiveness + */ + if (stat & XILINX_DMA_XR_IRQ_DELAY_MASK) + dev_dbg(chan->dev, "Inter-packet latency too long\n"); + + if (stat & XILINX_DMA_XR_IRQ_IOC_MASK) { + update_cookie = 1; + to_transfer = 1; + } + + if (update_cookie) + xilinx_dma_update_completed_cookie(chan); + + if (to_transfer) + chan->start_transfer(chan); + + tasklet_schedule(&chan->tasklet); + return IRQ_HANDLED; +} + +static void dma_do_tasklet(unsigned long data) +{ + struct xilinx_dma_chan *chan = (struct xilinx_dma_chan *)data; + + xilinx_chan_desc_cleanup(chan); +} + +/* Append the descriptor list to the pending list */ +static void append_desc_queue(struct xilinx_dma_chan *chan, + struct xilinx_dma_desc_sw *desc) +{ + struct xilinx_dma_desc_sw *tail = + container_of(chan->pending_list.prev, + struct xilinx_dma_desc_sw, node); + struct xilinx_dma_desc_hw *hw; + + if (list_empty(&chan->pending_list)) + goto out_splice; + + /* + * Add the hardware descriptor to the chain of hardware descriptors + * that already exists in memory. + */ + hw = &(tail->hw); + hw->next_desc = (u32)desc->async_tx.phys; + + /* + * Add the software descriptor and all children to the list + * of pending transactions + */ +out_splice: + list_splice_tail_init(&desc->tx_list, &chan->pending_list); +} + +/* + * Assign cookie to each descriptor, and append the descriptors to the pending + * list + */ +static dma_cookie_t xilinx_dma_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct xilinx_dma_chan *chan = to_xilinx_chan(tx->chan); + struct xilinx_dma_desc_sw *desc; + struct xilinx_dma_desc_sw *child; + unsigned long flags; + dma_cookie_t cookie = -EBUSY; + + desc = container_of(tx, struct xilinx_dma_desc_sw, async_tx); + + if (chan->err) { + /* + * If reset fails, need to hard reset the system. + * Channel is no longer functional + */ + if (!dma_reset(chan)) + chan->err = 0; + else + return cookie; + } + + spin_lock_irqsave(&chan->lock, flags); + + /* + * Assign cookies to all of the software descriptors + * that make up this transaction + */ + cookie = chan->cookie; + list_for_each_entry(child, &desc->tx_list, node) { + cookie++; + if (cookie < 0) + cookie = DMA_MIN_COOKIE; + + child->async_tx.cookie = cookie; + } + + chan->cookie = cookie; + + /* Put this transaction onto the tail of the pending queue */ + append_desc_queue(chan, desc); + + spin_unlock_irqrestore(&chan->lock, flags); + + return cookie; +} + +static struct +xilinx_dma_desc_sw *xilinx_dma_alloc_descriptor(struct xilinx_dma_chan *chan) +{ + struct xilinx_dma_desc_sw *desc; + dma_addr_t pdesc; + + desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc); + if (!desc) { + dev_dbg(chan->dev, "out of memory for desc\n"); + return NULL; + } + + memset(desc, 0, sizeof(*desc)); + INIT_LIST_HEAD(&desc->tx_list); + dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); + desc->async_tx.tx_submit = xilinx_dma_tx_submit; + desc->async_tx.phys = pdesc; + + return desc; +} + +/** + * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction + * @chan: DMA channel + * @sgl: scatterlist to transfer to/from + * @sg_len: number of entries in @scatterlist + * @direction: DMA direction + * @flags: transfer ack flags + */ +static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg( + struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len, + enum dma_transfer_direction direction, unsigned long flags, + void *context) +{ + struct xilinx_dma_chan *chan; + struct xilinx_dma_desc_sw *first = NULL, *prev = NULL, *new = NULL; + struct xilinx_dma_desc_hw *hw = NULL, *prev_hw = NULL; + + size_t copy; + + int i; + struct scatterlist *sg; + size_t sg_used; + dma_addr_t dma_src; + +#ifdef TEST_DMA_WITH_LOOPBACK + int total_len; +#endif + if (!dchan) + return NULL; + + chan = to_xilinx_chan(dchan); + + if (chan->direction != direction) + return NULL; + +#ifdef TEST_DMA_WITH_LOOPBACK + total_len = 0; + + for_each_sg(sgl, sg, sg_len, i) { + total_len += sg_dma_len(sg); + } +#endif + /* Build transactions using information in the scatter gather list */ + for_each_sg(sgl, sg, sg_len, i) { + sg_used = 0; + + /* Loop until the entire scatterlist entry is used */ + while (sg_used < sg_dma_len(sg)) { + + /* Allocate the link descriptor from DMA pool */ + new = xilinx_dma_alloc_descriptor(chan); + if (!new) { + dev_err(chan->dev, + "No free memory for link descriptor\n"); + goto fail; + } + + /* + * Calculate the maximum number of bytes to transfer, + * making sure it is less than the hw limit + */ + copy = min((size_t)(sg_dma_len(sg) - sg_used), + (size_t)chan->max_len); + hw = &(new->hw); + + dma_src = sg_dma_address(sg) + sg_used; + + hw->buf_addr = dma_src; + + /* Fill in the descriptor */ + hw->control = copy; + + /* + * If this is not the first descriptor, chain the + * current descriptor after the previous descriptor + * + * For the first DMA_MEM_TO_DEV transfer, set SOP + */ + if (!first) { + first = new; + if (direction == DMA_MEM_TO_DEV) { + hw->control |= XILINX_DMA_BD_SOP; +#ifdef TEST_DMA_WITH_LOOPBACK + hw->app_4 = total_len; +#endif + } + } else { + prev_hw = &(prev->hw); + prev_hw->next_desc = new->async_tx.phys; + } + + new->async_tx.cookie = 0; + async_tx_ack(&new->async_tx); + + prev = new; + sg_used += copy; + + /* Insert the link descriptor into the LD ring */ + list_add_tail(&new->node, &first->tx_list); + } + } + + /* Link the last BD with the first BD */ + hw->next_desc = first->async_tx.phys; + + if (direction == DMA_MEM_TO_DEV) + hw->control |= XILINX_DMA_BD_EOP; + + /* All scatter gather list entries has length == 0 */ + if (!first || !new) + return NULL; + + new->async_tx.flags = flags; + new->async_tx.cookie = -EBUSY; + + /* Set EOP to the last link descriptor of new list */ + hw->control |= XILINX_DMA_BD_EOP; + + return &first->async_tx; + +fail: + /* + * If first was not set, then we failed to allocate the very first + * descriptor, and we're done + */ + if (!first) + return NULL; + + /* + * First is set, so all of the descriptors we allocated have been added + * to first->tx_list, INCLUDING "first" itself. Therefore we + * must traverse the list backwards freeing each descriptor in turn + */ + xilinx_dma_free_desc_list_reverse(chan, &first->tx_list); + + return NULL; +} + +/* Run-time device configuration for Axi DMA */ +static int xilinx_dma_device_control(struct dma_chan *dchan, + enum dma_ctrl_cmd cmd, unsigned long arg) +{ + struct xilinx_dma_chan *chan; + unsigned long flags; + + if (!dchan) + return -EINVAL; + + chan = to_xilinx_chan(dchan); + + if (cmd == DMA_TERMINATE_ALL) { + /* Halt the DMA engine */ + dma_halt(chan); + + spin_lock_irqsave(&chan->lock, flags); + + /* Remove and free all of the descriptors in the lists */ + xilinx_dma_free_desc_list(chan, &chan->pending_list); + xilinx_dma_free_desc_list(chan, &chan->active_list); + + spin_unlock_irqrestore(&chan->lock, flags); + return 0; + } else if (cmd == DMA_SLAVE_CONFIG) { + /* + * Configure interrupt coalescing and delay counter + * Use value XILINX_DMA_NO_CHANGE to signal no change + */ + struct xilinx_dma_config *cfg = (struct xilinx_dma_config *)arg; + u32 reg = dma_read(chan, XILINX_DMA_CONTROL_OFFSET); + + if (cfg->coalesc <= XILINX_DMA_COALESCE_MAX) { + reg &= ~XILINX_DMA_XR_COALESCE_MASK; + reg |= cfg->coalesc << XILINX_DMA_COALESCE_SHIFT; + + chan->config.coalesc = cfg->coalesc; + } + + if (cfg->delay <= XILINX_DMA_DELAY_MAX) { + reg &= ~XILINX_DMA_XR_DELAY_MASK; + reg |= cfg->delay << XILINX_DMA_DELAY_SHIFT; + chan->config.delay = cfg->delay; + } + + dma_write(chan, XILINX_DMA_CONTROL_OFFSET, reg); + + return 0; + } else + return -ENXIO; +} + +static void xilinx_dma_free_channels(struct xilinx_dma_device *xdev) +{ + int i; + + for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++) { + list_del(&xdev->chan[i]->common.device_node); + tasklet_kill(&xdev->chan[i]->tasklet); + irq_dispose_mapping(xdev->chan[i]->irq); + } +} + +/* + * Probing channels + * + * . Get channel features from the device tree entry + * . Initialize special channel handling routines + */ +static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, + struct device_node *node, u32 feature) +{ + struct xilinx_dma_chan *chan; + int err; + u32 device_id, value, width = 0; + + /* alloc channel */ + chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + chan->feature = feature; + chan->max_len = XILINX_DMA_MAX_TRANS_LEN; + + chan->has_dre = of_property_read_bool(node, "xlnx,include-dre"); + + err = of_property_read_u32(node, "xlnx,datawidth", &value); + if (err) { + dev_err(xdev->dev, "unable to read datawidth property"); + return err; + } else { + width = value >> 3; /* convert bits to bytes */ + + /* If data width is greater than 8 bytes, DRE is not in hw */ + if (width > 8) + chan->has_dre = 0; + + chan->feature |= width - 1; + } + + err = of_property_read_u32(node, "xlnx,device-id", &device_id); + if (err) { + dev_err(xdev->dev, "unable to read device id property"); + return err; + } + + chan->has_sg = (xdev->feature & XILINX_DMA_FTR_HAS_SG) >> + XILINX_DMA_FTR_HAS_SG_SHIFT; + + chan->start_transfer = xilinx_dma_start_transfer; + + if (of_device_is_compatible(node, "xlnx,axi-dma-mm2s-channel")) + chan->direction = DMA_MEM_TO_DEV; + + if (of_device_is_compatible(node, "xlnx,axi-dma-s2mm-channel")) + chan->direction = DMA_DEV_TO_MEM; + + chan->regs = xdev->regs; + + if (chan->direction == DMA_DEV_TO_MEM) { + chan->regs = (xdev->regs + XILINX_DMA_RX_CHANNEL_OFFSET); + chan->id = 1; + } + + /* + * Used by dmatest channel matching in slave transfers + * Can change it to be a structure to have more matching information + */ + chan->private = (chan->direction & 0xFF) | XILINX_DMA_IP_DMA | + (device_id << XILINX_DMA_DEVICE_ID_SHIFT); + chan->common.private = (void *)&(chan->private); + + if (!chan->has_dre) + xdev->common.copy_align = fls(width - 1); + + chan->dev = xdev->dev; + xdev->chan[chan->id] = chan; + + /* Initialize the channel */ + err = dma_reset(chan); + if (err) { + dev_err(xdev->dev, "Reset channel failed\n"); + return err; + } + + spin_lock_init(&chan->lock); + INIT_LIST_HEAD(&chan->pending_list); + INIT_LIST_HEAD(&chan->active_list); + + chan->common.device = &xdev->common; + + /* find the IRQ line, if it exists in the device tree */ + chan->irq = irq_of_parse_and_map(node, 0); + err = devm_request_irq(xdev->dev, chan->irq, dma_intr_handler, + IRQF_SHARED, + "xilinx-dma-controller", chan); + if (err) { + dev_err(xdev->dev, "unable to request IRQ\n"); + return err; + } + + tasklet_init(&chan->tasklet, dma_do_tasklet, (unsigned long)chan); + + /* Add the channel to DMA device channel list */ + list_add_tail(&chan->common.device_node, &xdev->common.channels); + + return 0; +} + +static int xilinx_dma_probe(struct platform_device *pdev) +{ + struct xilinx_dma_device *xdev; + struct device_node *child, *node; + struct resource *res; + int ret; + u32 value; + + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); + if (!xdev) + return -ENOMEM; + + xdev->dev = &(pdev->dev); + INIT_LIST_HEAD(&xdev->common.channels); + + node = pdev->dev.of_node; + + /* iomap registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xdev->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xdev->regs)) + return PTR_ERR(xdev->regs); + + /* Check if SG is enabled */ + value = of_property_read_bool(node, "xlnx,include-sg"); + if (value) + xdev->feature |= XILINX_DMA_FTR_HAS_SG; + + /* Check if status control streams are enabled */ + value = of_property_read_bool(node, + "xlnx,sg-include-stscntrl-strm"); + if (value) + xdev->feature |= XILINX_DMA_FTR_STSCNTRL_STRM; + + /* Axi DMA only do slave transfers */ + dma_cap_set(DMA_SLAVE, xdev->common.cap_mask); + dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask); + xdev->common.device_prep_slave_sg = xilinx_dma_prep_slave_sg; + xdev->common.device_control = xilinx_dma_device_control; + xdev->common.device_issue_pending = xilinx_dma_issue_pending; + xdev->common.device_alloc_chan_resources = + xilinx_dma_alloc_chan_resources; + xdev->common.device_free_chan_resources = + xilinx_dma_free_chan_resources; + xdev->common.device_tx_status = xilinx_tx_status; + xdev->common.dev = &pdev->dev; + + platform_set_drvdata(pdev, xdev); + + for_each_child_of_node(node, child) { + ret = xilinx_dma_chan_probe(xdev, child, xdev->feature); + if (ret) { + dev_err(&pdev->dev, "Probing channels failed\n"); + goto free_chan_resources; + } + } + + ret = dma_async_device_register(&xdev->common); + if (ret) { + dev_err(&pdev->dev, "DMA device registration failed\n"); + goto free_chan_resources; + } + + dev_info(&pdev->dev, "Probing xilinx axi dma engine...Successful\n"); + + return 0; + +free_chan_resources: + xilinx_dma_free_channels(xdev); + + return ret; +} + +static int xilinx_dma_remove(struct platform_device *pdev) +{ + struct xilinx_dma_device *xdev; + + xdev = platform_get_drvdata(pdev); + dma_async_device_unregister(&xdev->common); + + xilinx_dma_free_channels(xdev); + + return 0; +} + +static const struct of_device_id xilinx_dma_of_match[] = { + { .compatible = "xlnx,axi-dma", }, + {} +}; +MODULE_DEVICE_TABLE(of, xilinx_dma_of_match); + +static struct platform_driver xilinx_dma_driver = { + .driver = { + .name = "xilinx-dma", + .owner = THIS_MODULE, + .of_match_table = xilinx_dma_of_match, + }, + .probe = xilinx_dma_probe, + .remove = xilinx_dma_remove, +}; + +module_platform_driver(xilinx_dma_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx DMA driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/xilinx_axivdma.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/dma/xilinx/xilinx_axivdma.c 2014-07-20 22:06:35.817314609 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * DMA driver for Xilinx Video DMA Engine + * + * Copyright (C) 2010-2013 Xilinx, Inc. All rights reserved. + * + * Based on the Freescale DMA driver. + * + * Description: + * The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP + * core that provides high-bandwidth direct memory access between memory + * and AXI4-Stream type video target peripherals. The core provides efficient + * two dimensional DMA operations with independent asynchronous read (S2MM) + * and write (MM2S) channel operation. It can be configured to have either + * one channel or two channels. If configured as two channels, one is to + * transmit to the video device (MM2S) and another is to receive from the + * video device (S2MM). Initialization, status, interrupt and management + * registers are accessed through an AXI4-Lite slave interface. + * + * 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. + */ + +#include <linux/amba/xilinx_dma.h> +#include <linux/bitops.h> +#include <linux/dmapool.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_dma.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> +#include <linux/slab.h> + +/* Register/Descriptor Offsets */ +#define XILINX_VDMA_MM2S_CTRL_OFFSET 0x0000 +#define XILINX_VDMA_S2MM_CTRL_OFFSET 0x0030 +#define XILINX_VDMA_MM2S_DESC_OFFSET 0x0050 +#define XILINX_VDMA_S2MM_DESC_OFFSET 0x00a0 + +/* Control Registers */ +#define XILINX_VDMA_REG_DMACR 0x0000 +#define XILINX_VDMA_DMACR_DELAY_MAX 0xff +#define XILINX_VDMA_DMACR_DELAY_SHIFT 24 +#define XILINX_VDMA_DMACR_FRAME_COUNT_MAX 0xff +#define XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT 16 +#define XILINX_VDMA_DMACR_ERR_IRQ (1 << 14) +#define XILINX_VDMA_DMACR_DLY_CNT_IRQ (1 << 13) +#define XILINX_VDMA_DMACR_FRM_CNT_IRQ (1 << 12) +#define XILINX_VDMA_DMACR_MASTER_SHIFT 8 +#define XILINX_VDMA_DMACR_FSYNCSRC_SHIFT 5 +#define XILINX_VDMA_DMACR_FRAMECNT_EN (1 << 4) +#define XILINX_VDMA_DMACR_GENLOCK_EN (1 << 3) +#define XILINX_VDMA_DMACR_RESET (1 << 2) +#define XILINX_VDMA_DMACR_CIRC_EN (1 << 1) +#define XILINX_VDMA_DMACR_RUNSTOP (1 << 0) +#define XILINX_VDMA_DMACR_DELAY_MASK \ + (XILINX_VDMA_DMACR_DELAY_MAX << \ + XILINX_VDMA_DMACR_DELAY_SHIFT) +#define XILINX_VDMA_DMACR_FRAME_COUNT_MASK \ + (XILINX_VDMA_DMACR_FRAME_COUNT_MAX << \ + XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT) +#define XILINX_VDMA_DMACR_MASTER_MASK \ + (0xf << XILINX_VDMA_DMACR_MASTER_SHIFT) +#define XILINX_VDMA_DMACR_FSYNCSRC_MASK \ + (3 << XILINX_VDMA_DMACR_FSYNCSRC_SHIFT) + +#define XILINX_VDMA_REG_DMASR 0x0004 +#define XILINX_VDMA_DMASR_DELAY_SHIFT 24 +#define XILINX_VDMA_DMASR_FRAME_COUNT_SHIFT 16 +#define XILINX_VDMA_DMASR_EOL_LATE_ERR (1 << 15) +#define XILINX_VDMA_DMASR_ERR_IRQ (1 << 14) +#define XILINX_VDMA_DMASR_DLY_CNT_IRQ (1 << 13) +#define XILINX_VDMA_DMASR_FRM_CNT_IRQ (1 << 12) +#define XILINX_VDMA_DMASR_SOF_LATE_ERR (1 << 11) +#define XILINX_VDMA_DMASR_SG_DEC_ERR (1 << 10) +#define XILINX_VDMA_DMASR_SG_SLV_ERR (1 << 9) +#define XILINX_VDMA_DMASR_EOF_EARLY_ERR (1 << 8) +#define XILINX_VDMA_DMASR_SOF_EARLY_ERR (1 << 7) +#define XILINX_VDMA_DMASR_DMA_DEC_ERR (1 << 6) +#define XILINX_VDMA_DMASR_DMA_SLAVE_ERR (1 << 5) +#define XILINX_VDMA_DMASR_DMA_INT_ERR (1 << 4) +#define XILINX_VDMA_DMASR_IDLE (1 << 1) +#define XILINX_VDMA_DMASR_HALTED (1 << 0) +#define XILINX_VDMA_DMASR_DELAY_MASK \ + (0xff << XILINX_VDMA_DMASR_DELAY_SHIFT) +#define XILINX_VDMA_DMASR_FRAME_COUNT_MASK \ + (0xff << XILINX_VDMA_DMASR_FRAME_COUNT_SHIFT) + +#define XILINX_VDMA_REG_CURDESC 0x0008 +#define XILINX_VDMA_REG_TAILDESC 0x0010 +#define XILINX_VDMA_REG_REG_INDEX 0x0014 +#define XILINX_VDMA_REG_FRMSTORE 0x0018 +#define XILINX_VDMA_REG_THRESHOLD 0x001c +#define XILINX_VDMA_REG_FRMPTR_STS 0x0024 +#define XILINX_VDMA_REG_PARK_PTR 0x0028 +#define XILINX_VDMA_PARK_PTR_WR_REF_SHIFT 8 +#define XILINX_VDMA_PARK_PTR_RD_REF_SHIFT 0 +#define XILINX_VDMA_REG_VDMA_VERSION 0x002c + +/* Register Direct Mode Registers */ +#define XILINX_VDMA_REG_VSIZE 0x0000 +#define XILINX_VDMA_REG_HSIZE 0x0004 + +#define XILINX_VDMA_REG_FRMDLY_STRIDE 0x0008 +#define XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT 24 +#define XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT 0 +#define XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_MASK \ + (0x1f << \ + XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT) +#define XILINX_VDMA_FRMDLY_STRIDE_STRIDE_MASK \ + (0xffff << \ + XILINX_VDMA_FRMDLY_STRIDE_STRIDE_MASK) + +#define XILINX_VDMA_REG_START_ADDRESS(n) (0x000c + 4 * (n)) + +/* Hw specific definitions */ +#define XILINX_VDMA_MAX_CHANS_PER_DEVICE 0x2 + +#define XILINX_VDMA_DMAXR_ALL_IRQ_MASK (XILINX_VDMA_DMASR_FRM_CNT_IRQ | \ + XILINX_VDMA_DMASR_DLY_CNT_IRQ | \ + XILINX_VDMA_DMASR_ERR_IRQ) + +#define XILINX_VDMA_DMASR_ALL_ERR_MASK (XILINX_VDMA_DMASR_EOL_LATE_ERR | \ + XILINX_VDMA_DMASR_SOF_LATE_ERR | \ + XILINX_VDMA_DMASR_SG_DEC_ERR | \ + XILINX_VDMA_DMASR_SG_SLV_ERR | \ + XILINX_VDMA_DMASR_EOF_EARLY_ERR | \ + XILINX_VDMA_DMASR_SOF_EARLY_ERR | \ + XILINX_VDMA_DMASR_DMA_DEC_ERR | \ + XILINX_VDMA_DMASR_DMA_SLAVE_ERR | \ + XILINX_VDMA_DMASR_DMA_INT_ERR) + +/* + * Recoverable errors are DMA Internal error, SOF Early, EOF Early and SOF Late. + * They are only recoverable when C_FLUSH_ON_FSYNC is enabled in the h/w system. + */ +#define XILINX_VDMA_DMASR_ERR_RECOVER_MASK \ + (XILINX_VDMA_DMASR_SOF_LATE_ERR | \ + XILINX_VDMA_DMASR_EOF_EARLY_ERR | \ + XILINX_VDMA_DMASR_SOF_EARLY_ERR | \ + XILINX_VDMA_DMASR_DMA_INT_ERR) + +/* Axi VDMA Flush on Fsync bits */ +#define XILINX_VDMA_FLUSH_S2MM 3 +#define XILINX_VDMA_FLUSH_MM2S 2 +#define XILINX_VDMA_FLUSH_BOTH 1 + +/* Delay loop counter to prevent hardware failure */ +#define XILINX_VDMA_LOOP_COUNT 1000000 + +/** + * struct xilinx_vdma_desc_hw - Hardware Descriptor + * @next_desc: Next Descriptor Pointer @0x00 + * @pad1: Reserved @0x04 + * @buf_addr: Buffer address @0x08 + * @pad2: Reserved @0x0C + * @vsize: Vertical Size @0x10 + * @hsize: Horizontal Size @0x14 + * @stride: Number of bytes between the first + * pixels of each horizontal line @0x18 + */ +struct xilinx_vdma_desc_hw { + u32 next_desc; + u32 pad1; + u32 buf_addr; + u32 pad2; + u32 vsize; + u32 hsize; + u32 stride; +} __aligned(64); + +/** + * struct xilinx_vdma_tx_segment - Descriptor segment + * @hw: Hardware descriptor + * @node: Node in the descriptor segments list + * @cookie: Segment cookie + * @phys: Physical address of segment + */ +struct xilinx_vdma_tx_segment { + struct xilinx_vdma_desc_hw hw; + struct list_head node; + dma_cookie_t cookie; + dma_addr_t phys; +} __aligned(64); + +/** + * struct xilinx_vdma_tx_descriptor - Per Transaction structure + * @async_tx: Async transaction descriptor + * @segments: TX segments list + * @node: Node in the channel descriptors list + */ +struct xilinx_vdma_tx_descriptor { + struct dma_async_tx_descriptor async_tx; + struct list_head segments; + struct list_head node; +}; + +#define to_vdma_tx_descriptor(tx) \ + container_of(tx, struct xilinx_vdma_tx_descriptor, async_tx) + +/** + * struct xilinx_vdma_chan - Driver specific VDMA channel structure + * @xdev: Driver specific device structure + * @ctrl_offset: Control registers offset + * @desc_offset: TX descriptor registers offset + * @completed_cookie: Maximum cookie completed + * @cookie: The current cookie + * @lock: Descriptor operation lock + * @pending_list: Descriptors waiting + * @active_desc: Active descriptor + * @done_list: Complete descriptors + * @common: DMA common channel + * @desc_pool: Descriptors pool + * @dev: The dma device + * @irq: Channel IRQ + * @id: Channel ID + * @direction: Transfer direction + * @num_frms: Number of frames + * @has_sg: Support scatter transfers + * @genlock: Support genlock mode + * @err: Channel has errors + * @tasklet: Cleanup work after irq + * @private: Match info for channel request + * @config: Device configuration info + * @flush_on_fsync: Flush on Frame sync + */ +struct xilinx_vdma_chan { + struct xilinx_vdma_device *xdev; + u32 ctrl_offset; + u32 desc_offset; + dma_cookie_t completed_cookie; + dma_cookie_t cookie; + spinlock_t lock; + struct list_head pending_list; + struct xilinx_vdma_tx_descriptor *active_desc; + struct list_head done_list; + struct dma_chan common; + struct dma_pool *desc_pool; + struct device *dev; + int irq; + int id; + enum dma_transfer_direction direction; + int num_frms; + bool has_sg; + bool genlock; + bool err; + struct tasklet_struct tasklet; + u32 private; + struct xilinx_vdma_config config; + bool flush_on_fsync; +}; + +/** + * struct xilinx_vdma_device - VDMA device structure + * @regs: I/O mapped base address + * @dev: Device Structure + * @common: DMA device structure + * @chan: Driver specific VDMA channel + * @has_sg: Specifies whether Scatter-Gather is present or not + * @flush_on_fsync: Flush on frame sync + */ +struct xilinx_vdma_device { + void __iomem *regs; + struct device *dev; + struct dma_device common; + struct xilinx_vdma_chan *chan[XILINX_VDMA_MAX_CHANS_PER_DEVICE]; + bool has_sg; + u32 flush_on_fsync; +}; + +#define to_xilinx_chan(chan) \ + container_of(chan, struct xilinx_vdma_chan, common) + +/* IO accessors */ +static inline u32 vdma_read(struct xilinx_vdma_chan *chan, u32 reg) +{ + return ioread32(chan->xdev->regs + reg); +} + +static inline void vdma_write(struct xilinx_vdma_chan *chan, u32 reg, u32 value) +{ + iowrite32(value, chan->xdev->regs + reg); +} + +static inline void vdma_desc_write(struct xilinx_vdma_chan *chan, u32 reg, + u32 value) +{ + vdma_write(chan, chan->desc_offset + reg, value); +} + +static inline u32 vdma_ctrl_read(struct xilinx_vdma_chan *chan, u32 reg) +{ + return vdma_read(chan, chan->ctrl_offset + reg); +} + +static inline void vdma_ctrl_write(struct xilinx_vdma_chan *chan, u32 reg, + u32 value) +{ + vdma_write(chan, chan->ctrl_offset + reg, value); +} + +static inline void vdma_ctrl_clr(struct xilinx_vdma_chan *chan, u32 reg, + u32 clr) +{ + vdma_ctrl_write(chan, reg, vdma_ctrl_read(chan, reg) & ~clr); +} + +static inline void vdma_ctrl_set(struct xilinx_vdma_chan *chan, u32 reg, + u32 set) +{ + vdma_ctrl_write(chan, reg, vdma_ctrl_read(chan, reg) | set); +} + +/* ----------------------------------------------------------------------------- + * Descriptors and segments alloc and free + */ + +/** + * xilinx_vdma_alloc_tx_segment - Allocate transaction segment + * @chan: Driver specific VDMA channel + * + * Return the allocated segment on success and NULL on failure. + */ +static struct xilinx_vdma_tx_segment * +xilinx_vdma_alloc_tx_segment(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_tx_segment *segment; + dma_addr_t phys; + + segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys); + if (!segment) + return NULL; + + memset(segment, 0, sizeof(*segment)); + segment->phys = phys; + + return segment; +} + +/** + * xilinx_vdma_free_tx_segment - Free transaction segment + * @chan: Driver specific VDMA channel + * @segment: VDMA transaction segment + */ +static void xilinx_vdma_free_tx_segment(struct xilinx_vdma_chan *chan, + struct xilinx_vdma_tx_segment *segment) +{ + dma_pool_free(chan->desc_pool, segment, segment->phys); +} + +/** + * xilinx_vdma_tx_descriptor - Allocate transaction descriptor + * @chan: Driver specific VDMA channel + * + * Return the allocated descriptor on success and NULL on failure. + */ +static struct xilinx_vdma_tx_descriptor * +xilinx_vdma_alloc_tx_descriptor(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_tx_descriptor *desc; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + INIT_LIST_HEAD(&desc->segments); + + return desc; +} + +/** + * xilinx_vdma_free_tx_descriptor - Free transaction descriptor + * @chan: Driver specific VDMA channel + * @desc: VDMA transaction descriptor + */ +static void +xilinx_vdma_free_tx_descriptor(struct xilinx_vdma_chan *chan, + struct xilinx_vdma_tx_descriptor *desc) +{ + struct xilinx_vdma_tx_segment *segment, *next; + + if (!desc) + return; + + list_for_each_entry_safe(segment, next, &desc->segments, node) { + list_del(&segment->node); + xilinx_vdma_free_tx_segment(chan, segment); + } + + kfree(desc); +} + +/* Required functions */ + +/** + * xilinx_vdma_free_descriptors - Free descriptors list + * @chan: Driver specific VDMA channel + * @list: List to parse and delete the descriptor + */ +static void xilinx_vdma_free_desc_list(struct xilinx_vdma_chan *chan, + struct list_head *list) +{ + struct xilinx_vdma_tx_descriptor *desc, *next; + + list_for_each_entry_safe(desc, next, list, node) { + list_del(&desc->node); + xilinx_vdma_free_tx_descriptor(chan, desc); + } +} + +/** + * xilinx_vdma_free_descriptors - Free channel descriptors + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_free_descriptors(struct xilinx_vdma_chan *chan) +{ + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + + xilinx_vdma_free_desc_list(chan, &chan->pending_list); + xilinx_vdma_free_desc_list(chan, &chan->done_list); + + xilinx_vdma_free_tx_descriptor(chan, chan->active_desc); + chan->active_desc = NULL; + + spin_unlock_irqrestore(&chan->lock, flags); +} + +/** + * xilinx_vdma_free_chan_resources - Free channel resources + * @dchan: DMA channel + */ +static void xilinx_vdma_free_chan_resources(struct dma_chan *dchan) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + + dev_dbg(chan->dev, "Free all channel resources.\n"); + + tasklet_kill(&chan->tasklet); + xilinx_vdma_free_descriptors(chan); + dma_pool_destroy(chan->desc_pool); + chan->desc_pool = NULL; +} + +/** + * xilinx_vdma_chan_desc_cleanup - Clean channel descriptors + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_chan_desc_cleanup(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_tx_descriptor *desc, *next; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + + list_for_each_entry_safe(desc, next, &chan->done_list, node) { + dma_async_tx_callback callback; + void *callback_param; + + /* Remove from the list of running transactions */ + list_del(&desc->node); + + /* Run the link descriptor callback function */ + callback = desc->async_tx.callback; + callback_param = desc->async_tx.callback_param; + if (callback) { + spin_unlock_irqrestore(&chan->lock, flags); + callback(callback_param); + spin_lock_irqsave(&chan->lock, flags); + } + + /* Run any dependencies, then free the descriptor */ + dma_run_dependencies(&desc->async_tx); + xilinx_vdma_free_tx_descriptor(chan, desc); + } + + spin_unlock_irqrestore(&chan->lock, flags); +} + +/** + * xilinx_vdma_do_tasklet - Schedule completion tasklet + * @data: Pointer to the Xilinx VDMA channel structure + */ +static void xilinx_vdma_do_tasklet(unsigned long data) +{ + struct xilinx_vdma_chan *chan = (struct xilinx_vdma_chan *)data; + + xilinx_vdma_chan_desc_cleanup(chan); +} + +/** + * xilinx_vdma_alloc_chan_resources - Allocate channel resources + * @dchan: DMA channel + * + * Returns '1' on success and failure value on error + */ +static int xilinx_vdma_alloc_chan_resources(struct dma_chan *dchan) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + + /* Has this channel already been allocated? */ + if (chan->desc_pool) + return 1; + + /* + * We need the descriptor to be aligned to 64bytes + * for meeting Xilinx VDMA specification requirement. + */ + chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool", + chan->dev, + sizeof(struct xilinx_vdma_tx_segment), + __alignof__(struct xilinx_vdma_tx_segment), 0); + if (!chan->desc_pool) { + dev_err(chan->dev, + "unable to allocate channel %d descriptor pool\n", + chan->id); + return -ENOMEM; + } + + tasklet_init(&chan->tasklet, xilinx_vdma_do_tasklet, + (unsigned long)chan); + + chan->completed_cookie = DMA_MIN_COOKIE; + chan->cookie = DMA_MIN_COOKIE; + + /* There is at least one descriptor free to be allocated */ + return 1; +} + +/** + * xilinx_vdma_tx_status - Get VDMA transaction status + * @dchan: DMA channel + * @cookie: Transaction identifier + * @txstate: Transaction state + * + * Returns DMA transaction status + */ +static enum dma_status xilinx_vdma_tx_status(struct dma_chan *dchan, + dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + dma_cookie_t last_used; + dma_cookie_t last_complete; + + xilinx_vdma_chan_desc_cleanup(chan); + + last_used = dchan->cookie; + last_complete = chan->completed_cookie; + + dma_set_tx_state(txstate, last_complete, last_used, 0); + + return dma_async_is_complete(cookie, last_complete, last_used); +} + +/** + * xilinx_vdma_is_running - Check if VDMA channel is running + * @chan: Driver specific VDMA channel + * + * Returns '1' if running, '0' if not. + */ +static int xilinx_vdma_is_running(struct xilinx_vdma_chan *chan) +{ + return !(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) & + XILINX_VDMA_DMASR_HALTED) && + (vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) & + XILINX_VDMA_DMACR_RUNSTOP); +} + +/** + * xilinx_vdma_is_idle - Check if VDMA channel is idle + * @chan: Driver specific VDMA channel + * + * Returns '1' if idle, '0' if not. + */ +static int xilinx_vdma_is_idle(struct xilinx_vdma_chan *chan) +{ + return vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) & + XILINX_VDMA_DMASR_IDLE; +} + +/** + * xilinx_vdma_halt - Halt VDMA channel + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_halt(struct xilinx_vdma_chan *chan) +{ + int loop = XILINX_VDMA_LOOP_COUNT + 1; + + vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP); + + /* Wait for the hardware to halt */ + while (loop--) + if (vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) & + XILINX_VDMA_DMASR_HALTED) + break; + + if (!loop) { + dev_err(chan->dev, "Cannot stop channel %p: %x\n", + chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR)); + chan->err = true; + } + + return; +} + +/** + * xilinx_vdma_start - Start VDMA channel + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_start(struct xilinx_vdma_chan *chan) +{ + int loop = XILINX_VDMA_LOOP_COUNT + 1; + + vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP); + + /* Wait for the hardware to start */ + while (loop) + if (!(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) & + XILINX_VDMA_DMASR_HALTED)) + break; + + if (!loop) { + dev_err(chan->dev, "Cannot start channel %p: %x\n", + chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR)); + + chan->err = true; + } + + return; +} + +/** + * xilinx_vdma_start_transfer - Starts VDMA transfer + * @chan: Driver specific channel struct pointer + */ +static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_config *config = &chan->config; + struct xilinx_vdma_tx_descriptor *desc; + unsigned long flags; + u32 reg; + struct xilinx_vdma_tx_segment *head, *tail = NULL; + + if (chan->err) + return; + + spin_lock_irqsave(&chan->lock, flags); + + /* There's already an active descriptor, bail out. */ + if (chan->active_desc) + goto out_unlock; + + if (list_empty(&chan->pending_list)) + goto out_unlock; + + desc = list_first_entry(&chan->pending_list, + struct xilinx_vdma_tx_descriptor, node); + + /* If it is SG mode and hardware is busy, cannot submit */ + if (chan->has_sg && xilinx_vdma_is_running(chan) && + !xilinx_vdma_is_idle(chan)) { + dev_dbg(chan->dev, "DMA controller still busy\n"); + goto out_unlock; + } + + if (chan->err) + goto out_unlock; + + /* + * If hardware is idle, then all descriptors on the running lists are + * done, start new transfers + */ + if (chan->has_sg) { + head = list_first_entry(&desc->segments, + struct xilinx_vdma_tx_segment, node); + tail = list_entry(desc->segments.prev, + struct xilinx_vdma_tx_segment, node); + + vdma_ctrl_write(chan, XILINX_VDMA_REG_CURDESC, head->phys); + } + + /* Configure the hardware using info in the config structure */ + reg = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR); + + if (config->frm_cnt_en) + reg |= XILINX_VDMA_DMACR_FRAMECNT_EN; + else + reg &= ~XILINX_VDMA_DMACR_FRAMECNT_EN; + + /* + * With SG, start with circular mode, so that BDs can be fetched. + * In direct register mode, if not parking, enable circular mode + */ + if (chan->has_sg || !config->park) + reg |= XILINX_VDMA_DMACR_CIRC_EN; + + if (config->park) + reg &= ~XILINX_VDMA_DMACR_CIRC_EN; + + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, reg); + + if (config->park && (config->park_frm >= 0) && + (config->park_frm < chan->num_frms)) { + if (chan->direction == DMA_MEM_TO_DEV) + vdma_write(chan, XILINX_VDMA_REG_PARK_PTR, + config->park_frm << + XILINX_VDMA_PARK_PTR_RD_REF_SHIFT); + else + vdma_write(chan, XILINX_VDMA_REG_PARK_PTR, + config->park_frm << + XILINX_VDMA_PARK_PTR_WR_REF_SHIFT); + } + + /* Start the hardware */ + xilinx_vdma_start(chan); + + if (chan->err) + goto out_unlock; + + /* Start the transfer */ + if (chan->has_sg) { + vdma_ctrl_write(chan, XILINX_VDMA_REG_TAILDESC, tail->phys); + } else { + struct xilinx_vdma_tx_segment *segment; + int i = 0; + + list_for_each_entry(segment, &desc->segments, node) + vdma_desc_write(chan, + XILINX_VDMA_REG_START_ADDRESS(i++), + segment->hw.buf_addr); + + vdma_desc_write(chan, XILINX_VDMA_REG_HSIZE, config->hsize); + vdma_desc_write(chan, XILINX_VDMA_REG_FRMDLY_STRIDE, + (config->frm_dly << + XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT) | + (config->stride << + XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT)); + vdma_desc_write(chan, XILINX_VDMA_REG_VSIZE, config->vsize); + } + + list_del(&desc->node); + chan->active_desc = desc; + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); +} + +/** + * xilinx_vdma_issue_pending - Issue pending transactions + * @dchan: DMA channel + */ +static void xilinx_vdma_issue_pending(struct dma_chan *dchan) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + + xilinx_vdma_start_transfer(chan); +} + +/** + * xilinx_vdma_complete_descriptor - Mark the active descriptor as complete + * @chan : xilinx DMA channel + * + * CONTEXT: hardirq + */ +static void xilinx_vdma_complete_descriptor(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_tx_descriptor *desc; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + + desc = chan->active_desc; + if (!desc) { + dev_dbg(chan->dev, "no running descriptors\n"); + goto out_unlock; + } + + list_add_tail(&desc->node, &chan->done_list); + + /* Update the completed cookie and reset the active descriptor. */ + chan->completed_cookie = desc->async_tx.cookie; + chan->active_desc = NULL; + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); +} + +/** + * xilinx_vdma_reset - Reset VDMA channel + * @chan: Driver specific VDMA channel + * + * Returns '0' on success and failure value on error + */ +static int xilinx_vdma_reset(struct xilinx_vdma_chan *chan) +{ + int loop = XILINX_VDMA_LOOP_COUNT + 1; + u32 tmp; + + vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RESET); + + tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) & + XILINX_VDMA_DMACR_RESET; + + /* Wait for the hardware to finish reset */ + while (loop-- && tmp) + tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) & + XILINX_VDMA_DMACR_RESET; + + if (!loop) { + dev_err(chan->dev, "reset timeout, cr %x, sr %x\n", + vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR), + vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR)); + return -ETIMEDOUT; + } + + chan->err = false; + + return 0; +} + +/** + * xilinx_vdma_chan_reset - Reset VDMA channel and enable interrupts + * @chan: Driver specific VDMA channel + * + * Returns '0' on success and failure value on error + */ +static int xilinx_vdma_chan_reset(struct xilinx_vdma_chan *chan) +{ + int err; + + /* Reset VDMA */ + err = xilinx_vdma_reset(chan); + if (err) + return err; + + /* Enable interrupts */ + vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, + XILINX_VDMA_DMAXR_ALL_IRQ_MASK); + + return 0; +} + +/** + * xilinx_vdma_irq_handler - VDMA Interrupt handler + * @irq: IRQ number + * @data: Pointer to the Xilinx VDMA channel structure + * + * Returns IRQ_HANDLED/IRQ_NONE + */ +static irqreturn_t xilinx_vdma_irq_handler(int irq, void *data) +{ + struct xilinx_vdma_chan *chan = data; + u32 status; + + /* Read the status and ack the interrupts. */ + status = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR); + if (!(status & XILINX_VDMA_DMAXR_ALL_IRQ_MASK)) + return IRQ_NONE; + + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR, + status & XILINX_VDMA_DMAXR_ALL_IRQ_MASK); + + if (status & XILINX_VDMA_DMASR_ERR_IRQ) { + /* + * An error occurred. If C_FLUSH_ON_FSYNC is enabled and the + * error is recoverable, ignore it. Otherwise flag the error. + * + * Only recoverable errors can be cleared in the DMASR register, + * make sure not to write to other error bits to 1. + */ + u32 errors = status & XILINX_VDMA_DMASR_ALL_ERR_MASK; + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR, + errors & XILINX_VDMA_DMASR_ERR_RECOVER_MASK); + + if (!chan->flush_on_fsync || + (errors & ~XILINX_VDMA_DMASR_ERR_RECOVER_MASK)) { + dev_err(chan->dev, + "Channel %p has errors %x, cdr %x tdr %x\n", + chan, errors, + vdma_ctrl_read(chan, XILINX_VDMA_REG_CURDESC), + vdma_ctrl_read(chan, XILINX_VDMA_REG_TAILDESC)); + chan->err = 1; + } + } + + if (status & XILINX_VDMA_DMASR_DLY_CNT_IRQ) { + /* + * Device takes too long to do the transfer when user requires + * responsiveness. + */ + dev_dbg(chan->dev, "Inter-packet latency too long\n"); + } + + if (status & XILINX_VDMA_DMASR_FRM_CNT_IRQ) { + xilinx_vdma_complete_descriptor(chan); + xilinx_vdma_start_transfer(chan); + } + + tasklet_schedule(&chan->tasklet); + return IRQ_HANDLED; +} + +/** + * xilinx_vdma_tx_submit - Submit DMA transaction + * @tx: Async transaction descriptor + * + * Returns cookie value on success and failure value on error + */ +static dma_cookie_t xilinx_vdma_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct xilinx_vdma_tx_descriptor *desc = to_vdma_tx_descriptor(tx); + struct xilinx_vdma_chan *chan = to_xilinx_chan(tx->chan); + struct xilinx_vdma_tx_segment *segment; + dma_cookie_t cookie; + unsigned long flags; + int err; + + if (chan->err) { + /* + * If reset fails, need to hard reset the system. + * Channel is no longer functional + */ + err = xilinx_vdma_chan_reset(chan); + if (err < 0) + return err; + } + + spin_lock_irqsave(&chan->lock, flags); + + /* Assign cookies to all of the segments that make up this transaction. + * Use the cookie of the last segment as the transaction cookie. + */ + cookie = chan->cookie; + + list_for_each_entry(segment, &desc->segments, node) { + if (cookie < DMA_MAX_COOKIE) + cookie++; + else + cookie = DMA_MIN_COOKIE; + + segment->cookie = cookie; + } + + tx->cookie = cookie; + chan->cookie = cookie; + + /* Append the transaction to the pending transactions queue. */ + list_add_tail(&desc->node, &chan->pending_list); + + spin_unlock_irqrestore(&chan->lock, flags); + + return cookie; +} + +/** + * xilinx_vdma_prep_slave_sg - prepare a descriptor for a DMA_SLAVE transaction + * @dchan: DMA channel + * @sgl: scatterlist to transfer to/from + * @sg_len: number of entries in @sgl + * @dir: DMA direction + * @flags: transfer ack flags + * @context: unused + */ +static struct dma_async_tx_descriptor * +xilinx_vdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction dir, + unsigned long flags, void *context) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + struct xilinx_vdma_tx_descriptor *desc; + struct xilinx_vdma_tx_segment *segment; + struct xilinx_vdma_tx_segment *prev = NULL; + struct scatterlist *sg; + int i; + + if (chan->direction != dir || sg_len == 0) + return NULL; + + /* Enforce one sg entry for one frame. */ + if (sg_len != chan->num_frms) { + dev_err(chan->dev, + "number of entries %d not the same as num stores %d\n", + sg_len, chan->num_frms); + return NULL; + } + + /* Allocate a transaction descriptor. */ + desc = xilinx_vdma_alloc_tx_descriptor(chan); + if (!desc) + return NULL; + + dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); + desc->async_tx.tx_submit = xilinx_vdma_tx_submit; + desc->async_tx.cookie = 0; + async_tx_ack(&desc->async_tx); + + /* Build the list of transaction segments. */ + for_each_sg(sgl, sg, sg_len, i) { + struct xilinx_vdma_desc_hw *hw; + + /* Allocate the link descriptor from DMA pool */ + segment = xilinx_vdma_alloc_tx_segment(chan); + if (!segment) + goto error; + + /* Fill in the hardware descriptor */ + hw = &segment->hw; + hw->buf_addr = sg_dma_address(sg); + hw->vsize = chan->config.vsize; + hw->hsize = chan->config.hsize; + hw->stride = (chan->config.frm_dly << + XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT) | + (chan->config.stride << + XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT); + if (prev) + prev->hw.next_desc = segment->phys; + + /* Insert the segment into the descriptor segments list. */ + list_add_tail(&segment->node, &desc->segments); + + prev = segment; + } + + /* Link the last hardware descriptor with the first. */ + segment = list_first_entry(&desc->segments, + struct xilinx_vdma_tx_segment, node); + prev->hw.next_desc = segment->phys; + + return &desc->async_tx; + +error: + xilinx_vdma_free_tx_descriptor(chan, desc); + return NULL; +} + +/** + * xilinx_vdma_terminate_all - Halt the channel and free descriptors + * @chan: Driver specific VDMA Channel pointer + */ +static void xilinx_vdma_terminate_all(struct xilinx_vdma_chan *chan) +{ + /* Halt the DMA engine */ + xilinx_vdma_halt(chan); + + /* Remove and free all of the descriptors in the lists */ + xilinx_vdma_free_descriptors(chan); +} + +/** + * xilinx_vdma_slave_config - Configure VDMA channel + * Run-time configuration for Axi VDMA, supports: + * . halt the channel + * . configure interrupt coalescing and inter-packet delay threshold + * . start/stop parking + * . enable genlock + * . set transfer information using config struct + * + * @chan: Driver specific VDMA Channel pointer + * @cfg: Channel configuration pointer + * + * Returns '0' on success and failure value on error + */ +static int xilinx_vdma_slave_config(struct xilinx_vdma_chan *chan, + struct xilinx_vdma_config *cfg) +{ + u32 dmacr; + + if (cfg->reset) + return xilinx_vdma_chan_reset(chan); + + dmacr = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR); + + /* If vsize is -1, it is park-related operations */ + if (cfg->vsize == -1) { + if (cfg->park) + dmacr &= ~XILINX_VDMA_DMACR_CIRC_EN; + else + dmacr |= XILINX_VDMA_DMACR_CIRC_EN; + + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, dmacr); + return 0; + } + + /* If hsize is -1, it is interrupt threshold settings */ + if (cfg->hsize == -1) { + if (cfg->coalesc <= XILINX_VDMA_DMACR_FRAME_COUNT_MAX) { + dmacr &= ~XILINX_VDMA_DMACR_FRAME_COUNT_MASK; + dmacr |= cfg->coalesc << + XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT; + chan->config.coalesc = cfg->coalesc; + } + + if (cfg->delay <= XILINX_VDMA_DMACR_DELAY_MAX) { + dmacr &= ~XILINX_VDMA_DMACR_DELAY_MASK; + dmacr |= cfg->delay << XILINX_VDMA_DMACR_DELAY_SHIFT; + chan->config.delay = cfg->delay; + } + + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, dmacr); + return 0; + } + + /* Transfer information */ + chan->config.vsize = cfg->vsize; + chan->config.hsize = cfg->hsize; + chan->config.stride = cfg->stride; + chan->config.frm_dly = cfg->frm_dly; + chan->config.park = cfg->park; + + /* genlock settings */ + chan->config.gen_lock = cfg->gen_lock; + chan->config.master = cfg->master; + + if (cfg->gen_lock && chan->genlock) { + dmacr |= XILINX_VDMA_DMACR_GENLOCK_EN; + dmacr |= cfg->master << XILINX_VDMA_DMACR_MASTER_SHIFT; + } + + chan->config.frm_cnt_en = cfg->frm_cnt_en; + if (cfg->park) + chan->config.park_frm = cfg->park_frm; + else + chan->config.park_frm = -1; + + chan->config.coalesc = cfg->coalesc; + chan->config.delay = cfg->delay; + if (cfg->coalesc <= XILINX_VDMA_DMACR_FRAME_COUNT_MAX) { + dmacr |= cfg->coalesc << XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT; + chan->config.coalesc = cfg->coalesc; + } + + if (cfg->delay <= XILINX_VDMA_DMACR_DELAY_MAX) { + dmacr |= cfg->delay << XILINX_VDMA_DMACR_DELAY_SHIFT; + chan->config.delay = cfg->delay; + } + + /* FSync Source selection */ + dmacr &= ~XILINX_VDMA_DMACR_FSYNCSRC_MASK; + dmacr |= cfg->ext_fsync << XILINX_VDMA_DMACR_FSYNCSRC_SHIFT; + + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, dmacr); + return 0; +} + +/** + * xilinx_vdma_device_control - Configure DMA channel of the device + * @dchan: DMA Channel pointer + * @cmd: DMA control command + * @arg: Channel configuration + * + * Returns '0' on success and failure value on error + */ +static int xilinx_vdma_device_control(struct dma_chan *dchan, + enum dma_ctrl_cmd cmd, unsigned long arg) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + + switch (cmd) { + case DMA_TERMINATE_ALL: + xilinx_vdma_terminate_all(chan); + return 0; + case DMA_SLAVE_CONFIG: + return xilinx_vdma_slave_config(chan, + (struct xilinx_vdma_config *)arg); + default: + return -ENXIO; + } +} + +/* ----------------------------------------------------------------------------- + * Probe and remove + */ + +/** + * xilinx_vdma_chan_remove - Per Channel remove function + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_chan_remove(struct xilinx_vdma_chan *chan) +{ + /* Disable all interrupts */ + vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR, + XILINX_VDMA_DMAXR_ALL_IRQ_MASK); + + list_del(&chan->common.device_node); +} + +/** + * xilinx_vdma_chan_probe - Per Channel Probing + * It get channel features from the device tree entry and + * initialize special channel handling routines + * + * @xdev: Driver specific device structure + * @node: Device node + * + * Returns '0' on success and failure value on error + */ +static int xilinx_vdma_chan_probe(struct xilinx_vdma_device *xdev, + struct device_node *node) +{ + struct xilinx_vdma_chan *chan; + bool has_dre = false; + u32 device_id; + u32 value; + int err; + + /* Allocate and initialize the channel structure */ + chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + chan->dev = xdev->dev; + chan->xdev = xdev; + chan->has_sg = xdev->has_sg; + + spin_lock_init(&chan->lock); + INIT_LIST_HEAD(&chan->pending_list); + INIT_LIST_HEAD(&chan->done_list); + + /* Retrieve the channel properties from the device tree */ + has_dre = of_property_read_bool(node, "xlnx,include-dre"); + + chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode"); + + err = of_property_read_u32(node, "xlnx,datawidth", &value); + if (!err) { + u32 width = value >> 3; /* Convert bits to bytes */ + + /* If data width is greater than 8 bytes, DRE is not in hw */ + if (width > 8) + has_dre = false; + + if (!has_dre) + xdev->common.copy_align = fls(width - 1); + } + + err = of_property_read_u32(node, "xlnx,device-id", &device_id); + if (err < 0) { + dev_err(xdev->dev, "missing xlnx,device-id property\n"); + return err; + } + + if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel")) { + chan->direction = DMA_MEM_TO_DEV; + chan->id = 0; + + chan->ctrl_offset = XILINX_VDMA_MM2S_CTRL_OFFSET; + chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET; + + if (xdev->flush_on_fsync == XILINX_VDMA_FLUSH_BOTH || + xdev->flush_on_fsync == XILINX_VDMA_FLUSH_MM2S) + chan->flush_on_fsync = true; + } else if (of_device_is_compatible(node, + "xlnx,axi-vdma-s2mm-channel")) { + chan->direction = DMA_DEV_TO_MEM; + chan->id = 1; + + chan->ctrl_offset = XILINX_VDMA_S2MM_CTRL_OFFSET; + chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET; + + if (xdev->flush_on_fsync == XILINX_VDMA_FLUSH_BOTH || + xdev->flush_on_fsync == XILINX_VDMA_FLUSH_S2MM) + chan->flush_on_fsync = true; + } else { + dev_err(xdev->dev, "Invalid channel compatible node\n"); + return -EINVAL; + } + + /* + * Used by DMA clients who doesnt have a device node and can request + * the channel by passing this as a filter to 'dma_request_channel()'. + */ + chan->private = (chan->direction & 0xff) | + XILINX_DMA_IP_VDMA | + (device_id << XILINX_DMA_DEVICE_ID_SHIFT); + + /* Request the interrupt */ + chan->irq = irq_of_parse_and_map(node, 0); + err = devm_request_irq(xdev->dev, chan->irq, xilinx_vdma_irq_handler, + IRQF_SHARED, "xilinx-vdma-controller", chan); + if (err) { + dev_err(xdev->dev, "unable to request IRQ\n"); + return err; + } + + /* Initialize the DMA channel and add it to the DMA engine channels + * list. + */ + chan->common.device = &xdev->common; + chan->common.private = (void *)&(chan->private); + + list_add_tail(&chan->common.device_node, &xdev->common.channels); + xdev->chan[chan->id] = chan; + + /* Reset the channel */ + err = xilinx_vdma_chan_reset(chan); + if (err < 0) { + dev_err(xdev->dev, "Reset channel failed\n"); + return err; + } + + return 0; +} + +/** + * struct of_dma_filter_xilinx_args - Channel filter args + * @dev: DMA device structure + * @chan_id: Channel id + */ +struct of_dma_filter_xilinx_args { + struct dma_device *dev; + u32 chan_id; +}; + +/** + * xilinx_vdma_dt_filter - VDMA channel filter function + * @chan: DMA channel pointer + * @param: Filter match value + * + * Returns true/false based on the result + */ +static bool xilinx_vdma_dt_filter(struct dma_chan *chan, void *param) +{ + struct of_dma_filter_xilinx_args *args = param; + + return chan->device == args->dev && chan->chan_id == args->chan_id; +} + +/** + * of_dma_xilinx_xlate - Translation function + * @dma_spec: Pointer to DMA specifier as found in the device tree + * @ofdma: Pointer to DMA controller data + * + * Returns DMA channel pointer on success and NULL on error + */ +static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct of_dma_filter_xilinx_args args; + dma_cap_mask_t cap; + + args.dev = ofdma->of_dma_data; + if (!args.dev) + return NULL; + + if (dma_spec->args_count != 1) + return NULL; + + dma_cap_zero(cap); + dma_cap_set(DMA_SLAVE, cap); + + args.chan_id = dma_spec->args[0]; + + return dma_request_channel(cap, xilinx_vdma_dt_filter, &args); +} + +/** + * xilinx_vdma_probe - Driver probe function + * @pdev: Pointer to the platform_device structure + * + * Returns '0' on success and failure value on error + */ +static int xilinx_vdma_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct xilinx_vdma_device *xdev; + struct device_node *child; + struct resource *io; + int num_frames, i, err; + + dev_info(&pdev->dev, "Probing xilinx axi vdma engine\n"); + + /* Allocate and initialize the DMA engine structure */ + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); + if (!xdev) + return -ENOMEM; + + xdev->dev = &pdev->dev; + + /* Request and map I/O memory */ + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xdev->regs = devm_ioremap_resource(&pdev->dev, io); + if (IS_ERR(xdev->regs)) + return PTR_ERR(xdev->regs); + + /* Retrieve the DMA engine properties from the device tree */ + xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg"); + + err = of_property_read_u32(node, "xlnx,num-fstores", &num_frames); + if (err < 0) { + dev_err(xdev->dev, "missing xlnx,num-fstores property\n"); + return err; + } + + of_property_read_u32(node, "xlnx,flush-fsync", &xdev->flush_on_fsync); + + /* Initialize the DMA engine */ + xdev->common.dev = &pdev->dev; + + INIT_LIST_HEAD(&xdev->common.channels); + dma_cap_set(DMA_SLAVE, xdev->common.cap_mask); + dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask); + + xdev->common.device_alloc_chan_resources = + xilinx_vdma_alloc_chan_resources; + xdev->common.device_free_chan_resources = + xilinx_vdma_free_chan_resources; + xdev->common.device_prep_slave_sg = xilinx_vdma_prep_slave_sg; + xdev->common.device_control = xilinx_vdma_device_control; + xdev->common.device_tx_status = xilinx_vdma_tx_status; + xdev->common.device_issue_pending = xilinx_vdma_issue_pending; + + platform_set_drvdata(pdev, xdev); + + /* Initialize the channels */ + for_each_child_of_node(node, child) { + err = xilinx_vdma_chan_probe(xdev, child); + if (err < 0) + goto error; + } + + for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++) { + if (xdev->chan[i]) + xdev->chan[i]->num_frms = num_frames; + } + + /* Register the DMA engine with the core */ + dma_async_device_register(&xdev->common); + + err = of_dma_controller_register(node, of_dma_xilinx_xlate, + &xdev->common); + if (err < 0) + dev_err(&pdev->dev, "Unable to register DMA to DT\n"); + + return 0; + +error: + for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++) { + if (xdev->chan[i]) + xilinx_vdma_chan_remove(xdev->chan[i]); + } + + return err; +} + +/** + * xilinx_vdma_remove - Driver remove function + * @pdev: Pointer to the platform_device structure + * + * Always returns '0' + */ +static int xilinx_vdma_remove(struct platform_device *pdev) +{ + struct xilinx_vdma_device *xdev; + int i; + + of_dma_controller_free(pdev->dev.of_node); + + xdev = platform_get_drvdata(pdev); + dma_async_device_unregister(&xdev->common); + + for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++) { + if (xdev->chan[i]) + xilinx_vdma_chan_remove(xdev->chan[i]); + } + + return 0; +} + +static const struct of_device_id xilinx_vdma_of_ids[] = { + { .compatible = "xlnx,axi-vdma",}, + {} +}; + +static struct platform_driver xilinx_vdma_driver = { + .driver = { + .name = "xilinx-vdma", + .owner = THIS_MODULE, + .of_match_table = xilinx_vdma_of_ids, + }, + .probe = xilinx_vdma_probe, + .remove = xilinx_vdma_remove, +}; + +module_platform_driver(xilinx_vdma_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx VDMA driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/edac/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/edac/Kconfig 2014-07-20 22:05:50.172067677 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/edac/Kconfig 2014-07-20 22:06:35.830314394 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:329 @ Support for error detection and correction on the Tilera memory controller. +config EDAC_ZYNQ + tristate "ZYNQ DDR Memory Controller" + depends on EDAC_MM_EDAC && ARCH_ZYNQ + help + This enables support for EDAC on the ECC memory used + with the ZYNQ DDR memory controller. + config EDAC_HIGHBANK_MC tristate "Highbank Memory Controller" depends on EDAC_MM_EDAC && ARCH_HIGHBANK Index: linux-3.12.24-rt38-xilinx/drivers/edac/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/edac/Makefile 2014-07-20 22:05:50.171067694 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/edac/Makefile 2014-07-20 22:06:35.840314229 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:67 @ obj-$(CONFIG_EDAC_OCTEON_L2C) += octeon_edac-l2c.o obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o +obj-$(CONFIG_EDAC_ZYNQ) += zynq_edac.o Index: linux-3.12.24-rt38-xilinx/drivers/edac/zynq_edac.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/edac/zynq_edac.c 2014-07-20 22:06:35.853314015 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Zynq DDR ECC Driver + * This driver is based on ppc4xx_edac.c drivers + * + * Copyright (C) 2012 - 2013 Xilinx, Inc. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/edac.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "edac_core.h" + +/* Number of cs_rows needed per memory controller */ +#define ZYNQ_EDAC_NR_CSROWS 1 + +/* Number of channels per memory controller */ +#define ZYNQ_EDAC_NR_CHANS 1 + +/* Granularity of reported error in bytes */ +#define ZYNQ_EDAC_ERROR_GRAIN 1 + +#define ZYNQ_EDAC_MESSAGE_SIZE 256 + +/* Zynq DDR memory controller registers that are relevant to ECC */ +#define ZYNQ_DDRC_CONTROL_REG_OFFSET 0x0 /* Control regsieter */ +#define ZYNQ_DDRC_T_ZQ_REG_OFFSET 0xA4 /* ZQ register */ + +/* ECC control register */ +#define ZYNQ_DDRC_ECC_CONTROL_REG_OFFSET 0xC4 +/* ECC log register */ +#define ZYNQ_DDRC_ECC_CE_LOG_REG_OFFSET 0xC8 +/* ECC address register */ +#define ZYNQ_DDRC_ECC_CE_ADDR_REG_OFFSET 0xCC +/* ECC data[31:0] register */ +#define ZYNQ_DDRC_ECC_CE_DATA_31_0_REG_OFFSET 0xD0 + +/* Uncorrectable error info regsisters */ +#define ZYNQ_DDRC_ECC_UE_LOG_REG_OFFSET 0xDC /* ECC control register */ +#define ZYNQ_DDRC_ECC_UE_ADDR_REG_OFFSET 0xE0 /* ECC log register */ +#define ZYNQ_DDRC_ECC_UE_DATA_31_0_REG_OFFSET 0xE4 /* ECC address register */ + +#define ZYNQ_DDRC_ECC_STAT_REG_OFFSET 0xF0 /* ECC statistics register */ +#define ZYNQ_DDRC_ECC_SCRUB_REG_OFFSET 0xF4 /* ECC scrub register */ + +/* Control regsiter bitfield definitions */ +#define ZYNQ_DDRC_CTRLREG_BUSWIDTH_MASK 0xC +#define ZYNQ_DDRC_CTRLREG_BUSWIDTH_SHIFT 2 + +#define ZYNQ_DDRCTL_WDTH_16 1 +#define ZYNQ_DDRCTL_WDTH_32 0 + +/* ZQ register bitfield definitions */ +#define ZYNQ_DDRC_T_ZQ_REG_DDRMODE_MASK 0x2 + +/* ECC control register bitfield definitions */ +#define ZYNQ_DDRC_ECCCTRL_CLR_CE_ERR 0x2 +#define ZYNQ_DDRC_ECCCTRL_CLR_UE_ERR 0x1 + +/* ECC correctable/uncorrectable error log register definitions */ +#define ZYNQ_DDRC_ECC_CE_LOGREG_VALID 0x1 +#define ZYNQ_DDRC_ECC_CE_LOGREG_BITPOS_MASK 0xFE +#define ZYNQ_DDRC_ECC_CE_LOGREG_BITPOS_SHIFT 1 + +/* ECC correctable/uncorrectable error address register definitions */ +#define ZYNQ_DDRC_ECC_ADDRREG_COL_MASK 0xFFF +#define ZYNQ_DDRC_ECC_ADDRREG_ROW_MASK 0xFFFF000 +#define ZYNQ_DDRC_ECC_ADDRREG_ROW_SHIFT 12 +#define ZYNQ_DDRC_ECC_ADDRREG_BANK_MASK 0x70000000 +#define ZYNQ_DDRC_ECC_ADDRREG_BANK_SHIFT 28 + +/* ECC statistic regsiter definitions */ +#define ZYNQ_DDRC_ECC_STATREG_UECOUNT_MASK 0xFF +#define ZYNQ_DDRC_ECC_STATREG_CECOUNT_MASK 0xFF00 +#define ZYNQ_DDRC_ECC_STATREG_CECOUNT_SHIFT 8 + +/* ECC scrub regsiter definitions */ +#define ZYNQ_DDRC_ECC_SCRUBREG_ECC_MODE_MASK 0x7 +#define ZYNQ_DDRC_ECC_SCRUBREG_ECCMODE_SECDED 0x4 + +/** + * struct ecc_error_info - ECC error log information + * @row: Row number + * @col: Column number + * @bank: Bank number + * @bitpos: Bit position + * @data: Data causing the error + */ +struct ecc_error_info { + u32 row; + u32 col; + u32 bank; + u32 bitpos; + u32 data; +}; + +/** + * struct zynq_ecc_status - ECC status information to report + * @ce_count: Correctable error count + * @ue_count: Uncorrectable error count + * @ceinfo: Correctable error log information + * @ueinfo: Uncorrectable error log information + */ +struct zynq_ecc_status { + u32 ce_count; + u32 ue_count; + struct ecc_error_info ceinfo; + struct ecc_error_info ueinfo; +}; + +/** + * struct zynq_edac_priv - Zynq DDR memory controller private instance data + * @baseaddr: Base address of the DDR controller + * @ce_count: Correctable Error count + * @ue_count: Uncorrectable Error count + */ +struct zynq_edac_priv { + void __iomem *baseaddr; + u32 ce_count; + u32 ue_count; +}; + +/** + * zynq_edac_geterror_info - Get the current ecc error info + * @base: Pointer to the base address of the ddr memory controller + * @perrstatus: Pointer to the zynq ecc status structure + * + * This routine determines there is any ecc error or not + * + * Returns zero if there is no error otherwise returns 1 + */ +static int zynq_edac_geterror_info(void __iomem *base, + struct zynq_ecc_status *perrstatus) +{ + u32 regval; + u32 clearval = 0; + + regval = readl(base + ZYNQ_DDRC_ECC_STAT_REG_OFFSET) & + (ZYNQ_DDRC_ECC_STATREG_UECOUNT_MASK | + ZYNQ_DDRC_ECC_STATREG_CECOUNT_MASK); + + if (regval == 0) + return 0; + + memset(perrstatus, 0, sizeof(struct zynq_ecc_status)); + + perrstatus->ce_count = (regval & ZYNQ_DDRC_ECC_STATREG_CECOUNT_MASK) >> + ZYNQ_DDRC_ECC_STATREG_CECOUNT_SHIFT; + perrstatus->ue_count = (regval & ZYNQ_DDRC_ECC_STATREG_UECOUNT_MASK); + + if (perrstatus->ce_count) { + regval = readl(base + ZYNQ_DDRC_ECC_CE_LOG_REG_OFFSET); + if (regval & ZYNQ_DDRC_ECC_CE_LOGREG_VALID) { + perrstatus->ceinfo.bitpos = (regval & + ZYNQ_DDRC_ECC_CE_LOGREG_BITPOS_MASK) >> + ZYNQ_DDRC_ECC_CE_LOGREG_BITPOS_SHIFT; + regval = readl(base + + ZYNQ_DDRC_ECC_CE_ADDR_REG_OFFSET); + perrstatus->ceinfo.row = (regval & + ZYNQ_DDRC_ECC_ADDRREG_ROW_MASK) >> + ZYNQ_DDRC_ECC_ADDRREG_ROW_SHIFT; + perrstatus->ceinfo.col = (regval & + ZYNQ_DDRC_ECC_ADDRREG_COL_MASK); + perrstatus->ceinfo.bank = (regval & + ZYNQ_DDRC_ECC_ADDRREG_BANK_MASK) >> + ZYNQ_DDRC_ECC_ADDRREG_BANK_SHIFT; + perrstatus->ceinfo.data = readl(base + + ZYNQ_DDRC_ECC_CE_DATA_31_0_REG_OFFSET); + edac_dbg(3, "ce bitposition: %d data: %d\n", + perrstatus->ceinfo.bitpos, + perrstatus->ceinfo.data); + } + clearval = ZYNQ_DDRC_ECCCTRL_CLR_CE_ERR; + } + + if (perrstatus->ue_count) { + regval = readl(base + ZYNQ_DDRC_ECC_UE_LOG_REG_OFFSET); + if (regval & ZYNQ_DDRC_ECC_CE_LOGREG_VALID) { + regval = readl(base + + ZYNQ_DDRC_ECC_UE_ADDR_REG_OFFSET); + perrstatus->ueinfo.row = (regval & + ZYNQ_DDRC_ECC_ADDRREG_ROW_MASK) >> + ZYNQ_DDRC_ECC_ADDRREG_ROW_SHIFT; + perrstatus->ueinfo.col = (regval & + ZYNQ_DDRC_ECC_ADDRREG_COL_MASK); + perrstatus->ueinfo.bank = (regval & + ZYNQ_DDRC_ECC_ADDRREG_BANK_MASK) >> + ZYNQ_DDRC_ECC_ADDRREG_BANK_SHIFT; + perrstatus->ueinfo.data = readl(base + + ZYNQ_DDRC_ECC_UE_DATA_31_0_REG_OFFSET); + } + clearval |= ZYNQ_DDRC_ECCCTRL_CLR_UE_ERR; + } + + writel(clearval, base + ZYNQ_DDRC_ECC_CONTROL_REG_OFFSET); + writel(0x0, base + ZYNQ_DDRC_ECC_CONTROL_REG_OFFSET); + + return 1; +} + +/** + * zynq_edac_generate_message - Generate interpreted ECC status message + * @mci: Pointer to the edac memory controller instance + * @perrstatus: Pointer to the zynq ecc status structure + * @buffer: Pointer to the buffer in which to generate the + * message + * @size: The size, in bytes, of space available in buffer + * + * This routine generates to the provided buffer the portion of the + * driver-unique report message associated with the ECC register of + * the specified ECC status. + */ +static void zynq_edac_generate_message(const struct mem_ctl_info *mci, + struct zynq_ecc_status *perrstatus, char *buffer, + size_t size) +{ + struct ecc_error_info *pinfo = NULL; + + if (perrstatus->ce_count > 0) + pinfo = &perrstatus->ceinfo; + else + pinfo = &perrstatus->ueinfo; + + snprintf(buffer, ZYNQ_EDAC_MESSAGE_SIZE, + "DDR ECC error type :%s Row %d Bank %d Col %d ", + (perrstatus->ce_count > 0) ? "CE" : "UE", pinfo->row, + pinfo->bank, pinfo->col); +} + +/** + * zynq_edac_handle_error - Handle controller error types CE and UE + * @mci: Pointer to the edac memory controller instance + * @perrstatus: Pointer to the zynq ecc status structure + * + * This routine handles an xilinx,ps7-ddrc controller ECC correctable error. + */ +static void zynq_edac_handle_error(struct mem_ctl_info *mci, + struct zynq_ecc_status *perrstatus) +{ + char message[ZYNQ_EDAC_MESSAGE_SIZE]; + + zynq_edac_generate_message(mci, perrstatus, &message[0], + ZYNQ_EDAC_MESSAGE_SIZE); + + if (perrstatus->ce_count) + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, + perrstatus->ce_count, 0, 0, 0, 0, 0, -1, + &message[0], ""); + else + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, + perrstatus->ue_count, 0, 0, 0, 0, 0, -1, + &message[0], ""); +} + +/** + * zynq_edac_check - Check controller for ECC errors + * @mci: Pointer to the edac memory controller instance + * + * This routine is used to check and post ECC errors and is called by + * the EDAC polling thread + */ +static void zynq_edac_check(struct mem_ctl_info *mci) +{ + struct zynq_edac_priv *priv = mci->pvt_info; + struct zynq_ecc_status errstatus; + int status; + + status = zynq_edac_geterror_info(priv->baseaddr, &errstatus); + if (status) { + priv->ce_count += errstatus.ce_count; + priv->ue_count += errstatus.ue_count; + + if (errstatus.ce_count) { + zynq_edac_handle_error(mci, &errstatus); + errstatus.ce_count = 0; + } + if (errstatus.ue_count) { + zynq_edac_handle_error(mci, &errstatus); + errstatus.ue_count = 0; + } + edac_dbg(3, "total error count ce %d ue %d\n", + priv->ce_count, priv->ue_count); + } +} + +/** + * zynq_edac_get_dtype - Return the controller memory width + * @base: Pointer to the ddr memory contoller base address + * + * This routine returns the EDAC device type width appropriate for the + * current controller configuration. + * + * Returns a device type width enumeration. + */ +static enum dev_type zynq_edac_get_dtype(void __iomem *base) +{ + enum dev_type dt; + u32 width; + + width = readl(base + ZYNQ_DDRC_CONTROL_REG_OFFSET); + width = (width & ZYNQ_DDRC_CTRLREG_BUSWIDTH_MASK) >> + ZYNQ_DDRC_CTRLREG_BUSWIDTH_SHIFT; + + switch (width) { + case ZYNQ_DDRCTL_WDTH_16: + dt = DEV_X2; + break; + case ZYNQ_DDRCTL_WDTH_32: + dt = DEV_X4; + break; + default: + dt = DEV_UNKNOWN; + } + + return dt; +} + +/** + * zynq_edac_get_eccstate - Return the controller ecc enable/disable status + * @base: Pointer to the ddr memory contoller base address + * + * This routine returns the ECC enable/diable status for the xlnx,ps7-ddrc + * controller + * + * Returns a ecc status boolean i.e true/false - enabled/disabled. + */ +static bool zynq_edac_get_eccstate(void __iomem *base) +{ + enum dev_type dt; + u32 ecctype; + bool state = false; + + dt = zynq_edac_get_dtype(base); + + ecctype = (readl(base + ZYNQ_DDRC_ECC_SCRUB_REG_OFFSET) & + ZYNQ_DDRC_ECC_SCRUBREG_ECC_MODE_MASK); + + if ((ecctype == ZYNQ_DDRC_ECC_SCRUBREG_ECCMODE_SECDED) + && (dt == DEV_X2)) { + state = true; + writel(0x0, base + ZYNQ_DDRC_ECC_CONTROL_REG_OFFSET); + } else { + state = false; + } + + return state; +} + +/** + * zynq_edac_get_memsize - Return the size of the attched mmeory device + * + * This routine returns the size of the system memory by reading the sysinfo + * information + * + * Returns the memory size in bytes + */ +static u32 zynq_edac_get_memsize(void) +{ + struct sysinfo inf; + + /* Reading the system memory size from the global meminfo structure */ + si_meminfo(&inf); + + return inf.totalram * inf.mem_unit; +} + +/** + * zynq_edac_get_mtype - Returns controller memory type + * @base: pointer to the zynq ecc status structure + * + * This routine returns the EDAC memory type appropriate for the + * current controller configuration. + * + * Returns a memory type enumeration. + */ +static enum mem_type zynq_edac_get_mtype(void __iomem *base) +{ + enum mem_type mt; + u32 memtype; + + memtype = readl(base + ZYNQ_DDRC_T_ZQ_REG_OFFSET); + + if (memtype & ZYNQ_DDRC_T_ZQ_REG_DDRMODE_MASK) + mt = MEM_DDR3; + else + mt = MEM_DDR2; + + return mt; +} + +/** + * zynq_edac_init_csrows - Initialize the cs row data + * @mci: Pointer to the edac memory controller instance + * + * This routine initializes the chip select rows associated + * with the EDAC memory controller instance + * + * Returns 0 if OK; otherwise, -EINVAL if the memory bank size + * configuration cannot be determined. + */ +static int zynq_edac_init_csrows(struct mem_ctl_info *mci) +{ + struct csrow_info *csi; + struct dimm_info *dimm; + struct zynq_edac_priv *priv = mci->pvt_info; + u32 size; + int row, j; + + for (row = 0; row < mci->nr_csrows; row++) { + csi = mci->csrows[row]; + size = zynq_edac_get_memsize(); + + for (j = 0; j < csi->nr_channels; j++) { + dimm = csi->channels[j]->dimm; + dimm->edac_mode = EDAC_FLAG_SECDED; + dimm->mtype = zynq_edac_get_mtype(priv->baseaddr); + dimm->nr_pages = + (size >> PAGE_SHIFT) / csi->nr_channels; + dimm->grain = ZYNQ_EDAC_ERROR_GRAIN; + dimm->dtype = zynq_edac_get_dtype(priv->baseaddr); + } + + } + + return 0; +} + +/** + * zynq_edac_mc_init - Initialize driver instance + * @mci: Pointer to the edac memory controller instance + * @pdev: Pointer to the platform_device struct + * + * This routine performs initialization of the EDAC memory controller + * instance and related driver-private data associated with the + * xlnx,ps7-ddrc memory controller the instance is bound to. + * + * Returns 0 if OK; otherwise, < 0 on error. + */ +static int zynq_edac_mc_init(struct mem_ctl_info *mci, + struct platform_device *pdev) +{ + int status; + struct zynq_edac_priv *priv; + + /* Initial driver pointers and private data */ + mci->pdev = &pdev->dev; + priv = mci->pvt_info; + platform_set_drvdata(pdev, mci); + + /* Initialize controller capabilities and configuration */ + mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->scrub_cap = SCRUB_HW_SRC; + /* Check the scrub setting from the controller */ + mci->scrub_mode = SCRUB_NONE; + + mci->edac_cap = EDAC_FLAG_SECDED; + /* Initialize strings */ + mci->ctl_name = "zynq_ddr_controller"; + mci->dev_name = dev_name(&pdev->dev); + mci->mod_name = "zynq_edac"; + mci->mod_ver = "1"; + + /* Initialize callbacks */ + edac_op_state = EDAC_OPSTATE_POLL; + mci->edac_check = zynq_edac_check; + mci->ctl_page_to_phys = NULL; + + /* + * Initialize the MC control structure 'csrows' table + * with the mapping and control information. + */ + status = zynq_edac_init_csrows(mci); + if (status) + pr_err("Failed to initialize rows!\n"); + + return status; +} + +/** + * zynq_edac_mc_probe - Check controller and bind driver + * @pdev: Pointer to the platform_device struct + * + * This routine probes a specific xilinx,ps7-ddrc controller + * instance for binding with the driver. + * + * Returns 0 if the controller instance was successfully bound to the + * driver; otherwise, < 0 on error. + */ +static int zynq_edac_mc_probe(struct platform_device *pdev) +{ + struct mem_ctl_info *mci; + struct edac_mc_layer layers[2]; + struct zynq_edac_priv *priv; + int rc; + struct resource *res; + void __iomem *baseaddr; + + /* Get the data from the platform device */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + baseaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(baseaddr)) + return PTR_ERR(baseaddr); + + /* Check for the ecc enable status */ + if (zynq_edac_get_eccstate(baseaddr) == false) { + dev_err(&pdev->dev, "ecc not enabled\n"); + return -ENXIO; + } + + /* + * At this point, we know ECC is enabled, allocate an EDAC + * controller instance and perform the appropriate + * initialization. + */ + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = ZYNQ_EDAC_NR_CSROWS; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = ZYNQ_EDAC_NR_CHANS; + layers[1].is_virt_csrow = false; + + mci = edac_mc_alloc(pdev->id, ARRAY_SIZE(layers), layers, + sizeof(struct zynq_edac_priv)); + if (mci == NULL) { + pr_err("Failed memory allocation for mci instance!\n"); + return -ENOMEM; + } + + priv = mci->pvt_info; + priv->baseaddr = baseaddr; + rc = zynq_edac_mc_init(mci, pdev); + if (rc) { + pr_err("Failed to initialize instance!\n"); + goto free_edac_mc; + } + + /* + * We have a valid, initialized EDAC instance bound to the + * controller. Attempt to register it with the EDAC subsystem + */ + rc = edac_mc_add_mc(mci); + if (rc) { + dev_err(&pdev->dev, "failed to register with EDAC core\n"); + goto del_edac_mc; + } + + return rc; + +del_edac_mc: + edac_mc_del_mc(&pdev->dev); +free_edac_mc: + edac_mc_free(mci); + + return rc; +} + +/** + * zynq_edac_mc_remove - Unbind driver from controller + * @pdev: Pointer to the platform_device struct + * + * This routine unbinds the EDAC memory controller instance associated + * with the specified xilinx,ps7-ddrc controller described by the + * OpenFirmware device tree node passed as a parameter. + * + * Unconditionally returns 0. + */ +static int zynq_edac_mc_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + + return 0; +} + +/* Device tree node type and compatible tuples this driver can match on */ +static struct of_device_id zynq_edac_match[] = { + { .compatible = "xlnx,ps7-ddrc-1.00.a", }, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, zynq_edac_match); + +static struct platform_driver zynq_edac_mc_driver = { + .driver = { + .name = "zynq-edac", + .owner = THIS_MODULE, + .of_match_table = zynq_edac_match, + }, + .probe = zynq_edac_mc_probe, + .remove = zynq_edac_mc_remove, +}; + +module_platform_driver(zynq_edac_mc_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Zynq DDR ECC driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/gpio/gpio-xilinx.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/gpio/gpio-xilinx.c 2014-07-20 22:05:50.185067463 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/gpio/gpio-xilinx.c 2014-07-20 22:06:35.868313767 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:20 @ #include <linux/errno.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> +#include <linux/interrupt.h> #include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> #include <linux/gpio.h> #include <linux/slab.h> /* Register Offset Definitions */ -#define XGPIO_DATA_OFFSET (0x0) /* Data register */ -#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */ +#define XGPIO_DATA_OFFSET 0x0 /* Data register */ +#define XGPIO_TRI_OFFSET 0x4 /* I/O direction register */ +#define XGPIO_GIER_OFFSET 0x11c /* Global Interrupt Enable */ +#define XGPIO_GIER_IE BIT(31) + +#define XGPIO_IPISR_OFFSET 0x120 /* IP Interrupt Status */ +#define XGPIO_IPIER_OFFSET 0x128 /* IP Interrupt Enable */ #define XGPIO_CHANNEL_OFFSET 0x8 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:53 @ /** * struct xgpio_instance - Stores information about GPIO device - * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks - * gpio_state: GPIO state shadow register - * gpio_dir: GPIO direction shadow register - * offset: GPIO channel offset - * gpio_lock: Lock used for synchronization + * @mmchip: OF GPIO chip for memory mapped banks + * @gpio_state: GPIO state shadow register + * @gpio_dir: GPIO direction shadow register + * @offset: GPIO channel offset + * @irq_base: GPIO channel irq base address + * @irq_enable: GPIO irq enable/disable bitfield + * @gpio_lock: Lock used for synchronization + * @irq_domain: irq_domain of the controller */ struct xgpio_instance { struct of_mm_gpio_chip mmchip; u32 gpio_state; u32 gpio_dir; u32 offset; + int irq_base; + u32 irq_enable; spinlock_t gpio_lock; + struct irq_domain *irq_domain; }; /** @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:78 @ * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * - * This function reads the specified signal of the GPIO device. It returns 0 if - * the signal clear, 1 if signal is set or negative value on error. + * This function reads the specified signal of the GPIO device. + * + * Return: + * 0 if direction of GPIO signals is set as input otherwise it + * returns negative error value. */ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:132 @ * @gpio: GPIO signal number. * * This function sets the direction of specified GPIO signal as input. - * It returns 0 if direction of GPIO signals is set as input otherwise it - * returns negative error value. + * + * Return: + * 0 - if direction of GPIO signals is set as input + * otherwise it returns negative error value. */ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:162 @ * @gpio: GPIO signal number. * @val: Value to be written to specified signal. * - * This function sets the direction of specified GPIO signal as output. If all - * GPIO signals of GPIO chip is configured as input then it returns + * This function sets the direction of specified GPIO signal as output. + * + * Return: + * If all GPIO signals of GPIO chip is configured as input then it returns * error otherwise it returns 0. */ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:197 @ /** * xgpio_save_regs - Set initial values of GPIO pins - * @mm_gc: pointer to memory mapped GPIO chip structure + * @mm_gc: Pointer to memory mapped GPIO chip structure */ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:211 @ } /** + * xgpio_xlate - Set initial values of GPIO pins + * @gc: Pointer to gpio_chip device structure. + * @gpiospec: gpio specifier as found in the device tree + * @flags: A flags pointer based on binding + * + * Return: + * irq number otherwise -EINVAL + */ +static int xgpio_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, + mmchip); + + if (gpiospec->args[1] == chip->offset) + return gpiospec->args[0]; + + return -EINVAL; +} + +/** + * xgpio_irq_mask - Write the specified signal of the GPIO device. + * @irq_data: per irq and chip data passed down to chip functions + */ +static void xgpio_irq_mask(struct irq_data *irq_data) +{ + unsigned long flags; + struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); + struct of_mm_gpio_chip *mm_gc = &chip->mmchip; + u32 offset = irq_data->irq - chip->irq_base; + u32 temp; + + pr_debug("%s: Disable %d irq, irq_enable_mask 0x%x\n", + __func__, offset, chip->irq_enable); + + spin_lock_irqsave(&chip->gpio_lock, flags); + + chip->irq_enable &= ~BIT(offset); + + if (!chip->irq_enable) { + /* Enable per channel interrupt */ + temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET); + temp &= chip->offset / XGPIO_CHANNEL_OFFSET + 1; + xgpio_writereg(mm_gc->regs + XGPIO_IPIER_OFFSET, temp); + + /* Disable global interrupt if channel interrupts are unused */ + temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET); + if (!temp) + xgpio_writereg(mm_gc->regs + XGPIO_GIER_OFFSET, + ~XGPIO_GIER_IE); + + } + spin_unlock_irqrestore(&chip->gpio_lock, flags); +} + +/** + * xgpio_irq_unmask - Write the specified signal of the GPIO device. + * @irq_data: per irq and chip data passed down to chip functions + */ +static void xgpio_irq_unmask(struct irq_data *irq_data) +{ + unsigned long flags; + struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); + struct of_mm_gpio_chip *mm_gc = &chip->mmchip; + u32 offset = irq_data->irq - chip->irq_base; + u32 temp; + + pr_debug("%s: Enable %d irq, irq_enable_mask 0x%x\n", + __func__, offset, chip->irq_enable); + + /* Setup pin as input */ + xgpio_dir_in(&mm_gc->gc, offset); + + spin_lock_irqsave(&chip->gpio_lock, flags); + + chip->irq_enable |= BIT(offset); + + if (chip->irq_enable) { + + /* Enable per channel interrupt */ + temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET); + temp |= chip->offset / XGPIO_CHANNEL_OFFSET + 1; + xgpio_writereg(mm_gc->regs + XGPIO_IPIER_OFFSET, temp); + + /* Enable global interrupts */ + xgpio_writereg(mm_gc->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE); + } + + spin_unlock_irqrestore(&chip->gpio_lock, flags); +} + +/** + * xgpio_set_irq_type - Write the specified signal of the GPIO device. + * @irq_data: Per irq and chip data passed down to chip functions + * @type: Interrupt type that is to be set for the gpio pin + * + * Return: + * 0 if interrupt type is supported otherwise otherwise -EINVAL + */ +static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type) +{ + /* Only rising edge case is supported now */ + if (type == IRQ_TYPE_EDGE_RISING) + return 0; + + return -EINVAL; +} + +/* irq chip descriptor */ +static struct irq_chip xgpio_irqchip = { + .name = "xgpio", + .irq_mask = xgpio_irq_mask, + .irq_unmask = xgpio_irq_unmask, + .irq_set_type = xgpio_set_irq_type, +}; + +/** + * xgpio_to_irq - Find out gpio to Linux irq mapping + * @gc: Pointer to gpio_chip device structure. + * @offset: Gpio pin offset + * + * Return: + * irq number otherwise -EINVAL + */ +static int xgpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, + mmchip); + + return irq_find_mapping(chip->irq_domain, offset); +} + +/** + * xgpio_irqhandler - Gpio interrupt service routine + * @irq: gpio irq number + * @desc: Pointer to interrupt description + */ +static void xgpio_irqhandler(unsigned int irq, struct irq_desc *desc) +{ + struct xgpio_instance *chip = (struct xgpio_instance *) + irq_get_handler_data(irq); + struct of_mm_gpio_chip *mm_gc = &chip->mmchip; + struct irq_chip *irqchip = irq_desc_get_chip(desc); + int offset; + unsigned long val; + + chained_irq_enter(irqchip, desc); + + val = xgpio_readreg(mm_gc->regs + chip->offset); + /* Only rising edge is supported */ + val &= chip->irq_enable; + + for_each_set_bit(offset, &val, chip->mmchip.gc.ngpio) { + generic_handle_irq(chip->irq_base + offset); + } + + xgpio_writereg(mm_gc->regs + XGPIO_IPISR_OFFSET, + chip->offset / XGPIO_CHANNEL_OFFSET + 1); + + chained_irq_exit(irqchip, desc); +} + +static struct lock_class_key gpio_lock_class; + +/** + * xgpio_irq_setup - Allocate irq for gpio and setup appropriate functions + * @np: Device node of the GPIO chip + * @chip: Pointer to private gpio channel structure + * + * Return: + * 0 if success, otherwise -1 + */ +static int xgpio_irq_setup(struct device_node *np, struct xgpio_instance *chip) +{ + u32 pin_num; + struct resource res; + + int ret = of_irq_to_resource(np, 0, &res); + if (!ret) { + pr_info("GPIO IRQ not connected\n"); + return 0; + } + + chip->mmchip.gc.of_xlate = xgpio_xlate; + chip->mmchip.gc.of_gpio_n_cells = 2; + chip->mmchip.gc.to_irq = xgpio_to_irq; + + chip->irq_base = irq_alloc_descs(-1, 0, chip->mmchip.gc.ngpio, 0); + if (chip->irq_base < 0) { + pr_err("Couldn't allocate IRQ numbers\n"); + return -1; + } + chip->irq_domain = irq_domain_add_legacy(np, chip->mmchip.gc.ngpio, + chip->irq_base, 0, + &irq_domain_simple_ops, NULL); + + /* + * set the irq chip, handler and irq chip data for callbacks for + * each pin + */ + for (pin_num = 0; pin_num < chip->mmchip.gc.ngpio; pin_num++) { + u32 gpio_irq = irq_find_mapping(chip->irq_domain, pin_num); + irq_set_lockdep_class(gpio_irq, &gpio_lock_class); + pr_debug("IRQ Base: %d, Pin %d = IRQ %d\n", + chip->irq_base, pin_num, gpio_irq); + irq_set_chip_and_handler(gpio_irq, &xgpio_irqchip, + handle_simple_irq); + irq_set_chip_data(gpio_irq, (void *)chip); +#ifdef CONFIG_ARCH_ZYNQ + set_irq_flags(gpio_irq, IRQF_VALID); +#endif + } + irq_set_handler_data(res.start, (void *)chip); + irq_set_chained_handler(res.start, xgpio_irqhandler); + + return 0; +} + +/** * xgpio_of_probe - Probe method for the GPIO device. * @np: pointer to device tree node * * This function probes the GPIO device in the device tree. It initializes the - * driver data structure. It returns 0, if the driver is bound to the GPIO - * device, or a negative value if there is an error. + * driver data structure. + * + * Return: + * It returns 0, if the driver is bound to the GPIO device, or + * a negative value if there is an error. */ -static int xgpio_of_probe(struct device_node *np) +static int xgpio_of_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct xgpio_instance *chip; int status = 0; const u32 *tree_info; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:481 @ /* Call the OF gpio helper to setup and register the GPIO device */ status = of_mm_gpiochip_add(np, &chip->mmchip); if (status) { - kfree(chip); pr_err("%s: error in probe function with status %d\n", np->full_name, status); return status; } + status = xgpio_irq_setup(np, chip); + if (status) { + pr_err("%s: GPIO IRQ initialization failed %d\n", + np->full_name, status); + return status; + } + pr_info("XGpio: %s: registered, base is %d\n", np->full_name, chip->mmchip.gc.base); tree_info = of_get_property(np, "xlnx,is-dual", NULL); if (tree_info && be32_to_cpup(tree_info)) { - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:531 @ chip->mmchip.save_regs = xgpio_save_regs; + status = xgpio_irq_setup(np, chip); + if (status) { + pr_err("%s: GPIO IRQ initialization failed %d\n", + np->full_name, status); + return status; + } + /* Call the OF gpio helper to setup and register the GPIO dev */ status = of_mm_gpiochip_add(np, &chip->mmchip); if (status) { - kfree(chip); pr_err("%s: error in probe function with status %d\n", - np->full_name, status); + np->full_name, status); return status; } pr_info("XGpio: %s: dual channel registered, base is %d\n", @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:556 @ { .compatible = "xlnx,xps-gpio-1.00.a", }, { /* end of list */ }, }; +MODULE_DEVICE_TABLE(of, xgpio_of_match); + +static struct platform_driver xilinx_gpio_driver = { + .probe = xgpio_of_probe, + .driver = { + .owner = THIS_MODULE, + .name = "xilinx-gpio", + .of_match_table = xgpio_of_match, + }, +}; static int __init xgpio_init(void) { - struct device_node *np; - - for_each_matching_node(np, xgpio_of_match) - xgpio_of_probe(np); - - return 0; + return platform_driver_register(&xilinx_gpio_driver); } /* Make sure we get initialized before anyone else tries to use us */ Index: linux-3.12.24-rt38-xilinx/drivers/gpio/gpio-zynq.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpio/gpio-zynq.c 2014-07-20 22:06:35.883313520 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PS GPIO device driver + * + * 2009-2011 (c) Xilinx, Inc. + * + * 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. + * + * 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., 675 Mass + * Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/export.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/pm_wakeup.h> +#include <linux/slab.h> +#include <asm/mach/irq.h> +#include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> + +#define DRIVER_NAME "zynq_gpio" +#define ZYNQ_GPIO_NR_GPIOS 118 + +static struct irq_domain *irq_domain; + +/* Register offsets for the GPIO device */ + +#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK)) /* LSW Mask & + Data -WO */ +#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK)) /* MSW Mask & + Data -WO */ +#define ZYNQ_GPIO_DATA_OFFSET(BANK) (0x040 + (4 * BANK)) /* Data Register + -RW */ +#define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK)) /* Direction + mode reg-RW */ +#define ZYNQ_GPIO_OUTEN_OFFSET(BANK) (0x208 + (0x40 * BANK)) /* Output + enable reg-RW + */ +#define ZYNQ_GPIO_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK)) /* Interrupt + mask reg-RO */ +#define ZYNQ_GPIO_INTEN_OFFSET(BANK) (0x210 + (0x40 * BANK)) /* Interrupt + enable reg-WO + */ +#define ZYNQ_GPIO_INTDIS_OFFSET(BANK) (0x214 + (0x40 * BANK)) /* Interrupt + disable reg-WO + */ +#define ZYNQ_GPIO_INTSTS_OFFSET(BANK) (0x218 + (0x40 * BANK)) /* Interrupt + status reg-RO + */ +#define ZYNQ_GPIO_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK)) /* Interrupt + type reg-RW + */ +#define ZYNQ_GPIO_INTPOL_OFFSET(BANK) (0x220 + (0x40 * BANK)) /* Interrupt + polarity reg + -RW */ +#define ZYNQ_GPIO_INTANY_OFFSET(BANK) (0x224 + (0x40 * BANK)) /* Interrupt on + any, reg-RW */ + +/* Read/Write access to the GPIO PS registers */ +#define zynq_gpio_readreg(offset) __raw_readl(offset) +#define zynq_gpio_writereg(val, offset) __raw_writel(val, offset) + +static unsigned int zynq_gpio_pin_table[] = { + 31, /* 0 - 31 */ + 53, /* 32 - 53 */ + 85, /* 54 - 85 */ + 117 /* 86 - 117 */ +}; + +/** + * struct zynq_gpio - gpio device private data structure + * @chip: instance of the gpio_chip + * @base_addr: base address of the GPIO device + * @gpio_lock: lock used for synchronization + */ +struct zynq_gpio { + struct gpio_chip chip; + void __iomem *base_addr; + unsigned int irq; + unsigned int irq_base; + struct clk *clk; + spinlock_t gpio_lock; +}; + +/** + * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank + * for a given pin in the GPIO device + * @pin_num: gpio pin number within the device + * @bank_num: an output parameter used to return the bank number of the gpio + * pin + * @bank_pin_num: an output parameter used to return pin number within a bank + * for the given gpio pin + * + * Returns the bank number. + */ +static inline void zynq_gpio_get_bank_pin(unsigned int pin_num, + unsigned int *bank_num, + unsigned int *bank_pin_num) +{ + for (*bank_num = 0; *bank_num < 4; (*bank_num)++) + if (pin_num <= zynq_gpio_pin_table[*bank_num]) + break; + + if (*bank_num == 0) + *bank_pin_num = pin_num; + else + *bank_pin_num = pin_num % (zynq_gpio_pin_table[*bank_num - 1] + + 1); +} + +/** + * zynq_gpio_get_value - Get the state of the specified pin of GPIO device + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * This function reads the state of the specified pin of the GPIO device. + * It returns 0 if the pin is low, 1 if pin is high. + */ +static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin) +{ + unsigned int bank_num, bank_pin_num; + struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + + return (zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_DATA_OFFSET(bank_num)) >> + bank_pin_num) & 1; +} + +/** + * zynq_gpio_set_value - Modify the state of the pin with specified value + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * @state: value used to modify the state of the specified pin + * + * This function calculates the register offset (i.e to lower 16 bits or + * upper 16 bits) based on the given pin number and sets the state of a + * gpio pin to the specified value. The state is either 0 or non-zero. + */ +static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin, + int state) +{ + unsigned long flags; + unsigned int reg_offset; + unsigned int bank_num, bank_pin_num; + struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + + if (bank_pin_num >= 16) { + bank_pin_num -= 16; /* only 16 data bits in bit maskable reg */ + reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num); + } else { + reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num); + } + + /* + * get the 32 bit value to be written to the mask/data register where + * the upper 16 bits is the mask and lower 16 bits is the data + */ + if (state) + state = 1; + state = ~(1 << (bank_pin_num + 16)) & ((state << bank_pin_num) | + 0xFFFF0000); + + spin_lock_irqsave(&gpio->gpio_lock, flags); + zynq_gpio_writereg(state, gpio->base_addr + reg_offset); + spin_unlock_irqrestore(&gpio->gpio_lock, flags); +} + +/** + * zynq_gpio_dir_in - Set the direction of the specified GPIO pin as input + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * This function uses the read-modify-write sequence to set the direction of + * the gpio pin as input. Returns 0 always. + */ +static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) +{ + unsigned int reg, bank_num, bank_pin_num; + struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + /* clear the bit in direction mode reg to set the pin as input */ + reg = zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + reg &= ~(1 << bank_pin_num); + zynq_gpio_writereg(reg, gpio->base_addr + + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + + return 0; +} + +/** + * zynq_gpio_dir_out - Set the direction of the specified GPIO pin as output + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * @state: value to be written to specified pin + * + * This function sets the direction of specified GPIO pin as output, configures + * the Output Enable register for the pin and uses zynq_gpio_set to set + * the state of the pin to the value specified. Returns 0 always. + */ +static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, + int state) +{ + struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + unsigned int reg, bank_num, bank_pin_num; + + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + + /* set the GPIO pin as output */ + reg = zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + reg |= 1 << bank_pin_num; + zynq_gpio_writereg(reg, gpio->base_addr + + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + + /* configure the output enable reg for the pin */ + reg = zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); + reg |= 1 << bank_pin_num; + zynq_gpio_writereg(reg, gpio->base_addr + + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); + + /* set the state of the pin */ + zynq_gpio_set_value(chip, pin, state); + return 0; +} + +static int zynq_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return irq_find_mapping(irq_domain, offset); +} + +/** + * zynq_gpio_irq_ack - Acknowledge the interrupt of a gpio pin + * @irq_data: irq data containing irq number of gpio pin for the interrupt + * to ack + * + * This function calculates gpio pin number from irq number and sets the bit + * in the Interrupt Status Register of the corresponding bank, to ACK the irq. + */ +static void zynq_gpio_irq_ack(struct irq_data *irq_data) +{ + struct zynq_gpio *gpio = (struct zynq_gpio *) + irq_data_get_irq_chip_data(irq_data); + unsigned int device_pin_num, bank_num, bank_pin_num; + + device_pin_num = irq_data->hwirq; + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + zynq_gpio_writereg(1 << bank_pin_num, gpio->base_addr + + (ZYNQ_GPIO_INTSTS_OFFSET(bank_num))); +} + +/** + * zynq_gpio_irq_mask - Disable the interrupts for a gpio pin + * @irq: irq number of gpio pin for which interrupt is to be disabled + * + * This function calculates gpio pin number from irq number and sets the + * bit in the Interrupt Disable register of the corresponding bank to disable + * interrupts for that pin. + */ +static void zynq_gpio_irq_mask(struct irq_data *irq_data) +{ + struct zynq_gpio *gpio = (struct zynq_gpio *) + irq_data_get_irq_chip_data(irq_data); + unsigned int device_pin_num, bank_num, bank_pin_num; + + device_pin_num = irq_data->hwirq; + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + zynq_gpio_writereg(1 << bank_pin_num, + gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); +} + +/** + * zynq_gpio_irq_unmask - Enable the interrupts for a gpio pin + * @irq_data: irq data containing irq number of gpio pin for the interrupt + * to enable + * + * This function calculates the gpio pin number from irq number and sets the + * bit in the Interrupt Enable register of the corresponding bank to enable + * interrupts for that pin. + */ +static void zynq_gpio_irq_unmask(struct irq_data *irq_data) +{ + struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + unsigned int device_pin_num, bank_num, bank_pin_num; + + device_pin_num = irq_data->hwirq; + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + zynq_gpio_writereg(1 << bank_pin_num, + gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num)); +} + +/** + * zynq_gpio_set_irq_type - Set the irq type for a gpio pin + * @irq_data: irq data containing irq number of gpio pin + * @type: interrupt type that is to be set for the gpio pin + * + * This function gets the gpio pin number and its bank from the gpio pin number + * and configures the INT_TYPE, INT_POLARITY and INT_ANY registers. Returns 0, + * negative error otherwise. + * TYPE-EDGE_RISING, INT_TYPE - 1, INT_POLARITY - 1, INT_ANY - 0; + * TYPE-EDGE_FALLING, INT_TYPE - 1, INT_POLARITY - 0, INT_ANY - 0; + * TYPE-EDGE_BOTH, INT_TYPE - 1, INT_POLARITY - NA, INT_ANY - 1; + * TYPE-LEVEL_HIGH, INT_TYPE - 0, INT_POLARITY - 1, INT_ANY - NA; + * TYPE-LEVEL_LOW, INT_TYPE - 0, INT_POLARITY - 0, INT_ANY - NA + */ +static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) +{ + struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + unsigned int device_pin_num, bank_num, bank_pin_num; + unsigned int int_type, int_pol, int_any; + + device_pin_num = irq_data->hwirq; + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + + int_type = zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); + int_pol = zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); + int_any = zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + + /* + * based on the type requested, configure the INT_TYPE, INT_POLARITY + * and INT_ANY registers + */ + switch (type) { + case IRQ_TYPE_EDGE_RISING: + int_type |= (1 << bank_pin_num); + int_pol |= (1 << bank_pin_num); + int_any &= ~(1 << bank_pin_num); + break; + case IRQ_TYPE_EDGE_FALLING: + int_type |= (1 << bank_pin_num); + int_pol &= ~(1 << bank_pin_num); + int_any &= ~(1 << bank_pin_num); + break; + case IRQ_TYPE_EDGE_BOTH: + int_type |= (1 << bank_pin_num); + int_any |= (1 << bank_pin_num); + break; + case IRQ_TYPE_LEVEL_HIGH: + int_type &= ~(1 << bank_pin_num); + int_pol |= (1 << bank_pin_num); + break; + case IRQ_TYPE_LEVEL_LOW: + int_type &= ~(1 << bank_pin_num); + int_pol &= ~(1 << bank_pin_num); + break; + default: + return -EINVAL; + } + + zynq_gpio_writereg(int_type, + gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); + zynq_gpio_writereg(int_pol, + gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); + zynq_gpio_writereg(int_any, + gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + return 0; +} + +static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on) +{ + if (on) + zynq_gpio_irq_unmask(data); + else + zynq_gpio_irq_mask(data); + + return 0; +} + +/* irq chip descriptor */ +static struct irq_chip zynq_gpio_irqchip = { + .name = DRIVER_NAME, + .irq_ack = zynq_gpio_irq_ack, + .irq_mask = zynq_gpio_irq_mask, + .irq_unmask = zynq_gpio_irq_unmask, + .irq_set_type = zynq_gpio_set_irq_type, + .irq_set_wake = zynq_gpio_set_wake, +}; + +/** + * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device + * @irq: irq number of the gpio bank where interrupt has occurred + * @desc: irq descriptor instance of the 'irq' + * + * This function reads the Interrupt Status Register of each bank to get the + * gpio pin number which has triggered an interrupt. It then acks the triggered + * interrupt and calls the pin specific handler set by the higher layer + * application for that pin. + * Note: A bug is reported if no handler is set for the gpio pin. + */ +static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) +{ + struct zynq_gpio *gpio = (struct zynq_gpio *)irq_get_handler_data(irq); + int gpio_irq = gpio->irq_base; + unsigned int int_sts, int_enb, bank_num; + struct irq_desc *gpio_irq_desc; + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + + for (bank_num = 0; bank_num < 4; bank_num++) { + int_sts = zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); + int_enb = zynq_gpio_readreg(gpio->base_addr + + ZYNQ_GPIO_INTMASK_OFFSET(bank_num)); + int_sts &= ~int_enb; + + for (; int_sts != 0; int_sts >>= 1, gpio_irq++) { + if ((int_sts & 1) == 0) + continue; + gpio_irq_desc = irq_to_desc(gpio_irq); + BUG_ON(!gpio_irq_desc); + chip = irq_desc_get_chip(gpio_irq_desc); + BUG_ON(!chip); + chip->irq_ack(&gpio_irq_desc->irq_data); + + /* call the pin specific handler */ + generic_handle_irq(gpio_irq); + } + /* shift to first virtual irq of next bank */ + gpio_irq = gpio->irq_base + zynq_gpio_pin_table[bank_num] + 1; + } + + chip = irq_desc_get_chip(desc); + chained_irq_exit(chip, desc); +} + +#ifdef CONFIG_PM_SLEEP +static int zynq_gpio_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + if (!device_may_wakeup(dev)) { + if (!pm_runtime_suspended(dev)) + clk_disable(gpio->clk); + return 0; + } + + return 0; +} + +static int zynq_gpio_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + if (!device_may_wakeup(dev)) { + if (!pm_runtime_suspended(dev)) + return clk_enable(gpio->clk); + } + + return 0; +} +#endif + +#ifdef CONFIG_PM_RUNTIME +static int zynq_gpio_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + clk_disable(gpio->clk); + + return 0; +} + +static int zynq_gpio_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + return clk_enable(gpio->clk); +} + +static int zynq_gpio_idle(struct device *dev) +{ + return pm_schedule_suspend(dev, 1); +} + +static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + int ret; + + ret = pm_runtime_get_sync(chip->dev); + + /* + * If the device is already active pm_runtime_get() will return 1 on + * success, but gpio_request still needs to return 0. + */ + return ret < 0 ? ret : 0; +} + +static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pm_runtime_put_sync(chip->dev); +} + +static void zynq_gpio_pm_runtime_init(struct platform_device *pdev) +{ + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + clk_disable(gpio->clk); + pm_runtime_enable(&pdev->dev); +} + +#else /* ! CONFIG_PM_RUNTIME */ +#define zynq_gpio_request NULL +#define zynq_gpio_free NULL +static void zynq_gpio_pm_runtime_init(struct platform_device *pdev) {} +#endif /* ! CONFIG_PM_RUNTIME */ + +#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP) +static const struct dev_pm_ops zynq_gpio_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume) + SET_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, zynq_gpio_runtime_resume, + zynq_gpio_idle) +}; +#define ZYNQ_GPIO_PM (&zynq_gpio_dev_pm_ops) + +#else /*! CONFIG_PM_RUNTIME || ! CONFIG_PM_SLEEP */ +#define ZYNQ_GPIO_PM NULL +#endif /*! CONFIG_PM_RUNTIME */ + +/** + * zynq_gpio_probe - Initialization method for a zynq_gpio device + * @pdev: platform device instance + * + * This function allocates memory resources for the gpio device and registers + * all the banks of the device. It will also set up interrupts for the gpio + * pins. + * Note: Interrupts are disabled for all the banks during initialization. + * Returns 0 on success, negative error otherwise. + */ +static int zynq_gpio_probe(struct platform_device *pdev) +{ + int ret; + unsigned int irq_num; + struct zynq_gpio *gpio; + struct gpio_chip *chip; + struct resource *res; + int pin_num, bank_num, gpio_irq; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + spin_lock_init(&gpio->gpio_lock); + + platform_set_drvdata(pdev, gpio); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio->base_addr)) + return PTR_ERR(gpio->base_addr); + + irq_num = platform_get_irq(pdev, 0); + gpio->irq = irq_num; + + /* configure the gpio chip */ + chip = &gpio->chip; + chip->label = "zynq_gpio"; + chip->owner = THIS_MODULE; + chip->dev = &pdev->dev; + chip->get = zynq_gpio_get_value; + chip->set = zynq_gpio_set_value; + chip->request = zynq_gpio_request; + chip->free = zynq_gpio_free; + chip->direction_input = zynq_gpio_dir_in; + chip->direction_output = zynq_gpio_dir_out; + chip->to_irq = zynq_gpio_to_irq; + chip->dbg_show = NULL; + chip->base = 0; /* default pin base */ + chip->ngpio = ZYNQ_GPIO_NR_GPIOS; + chip->can_sleep = 0; + + gpio->irq_base = irq_alloc_descs(-1, 0, chip->ngpio, 0); + if (gpio->irq_base < 0) { + dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } + + irq_domain = irq_domain_add_legacy(pdev->dev.of_node, + chip->ngpio, gpio->irq_base, 0, + &irq_domain_simple_ops, NULL); + + /* report a bug if gpio chip registration fails */ + ret = gpiochip_add(chip); + if (ret < 0) + return ret; + + dev_info(&pdev->dev, "gpio at 0x%08lx mapped to 0x%08lx\n", + (unsigned long)res->start, (unsigned long)gpio->base_addr); + + /* Enable GPIO clock */ + gpio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gpio->clk)) { + dev_err(&pdev->dev, "input clock not found.\n"); + gpiochip_remove(chip); + return PTR_ERR(gpio->clk); + } + ret = clk_prepare_enable(gpio->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock.\n"); + gpiochip_remove(chip); + return ret; + } + + /* disable interrupts for all banks */ + for (bank_num = 0; bank_num < 4; bank_num++) { + zynq_gpio_writereg(0xffffffff, gpio->base_addr + + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); + } + + /* + * set the irq chip, handler and irq chip data for callbacks for + * each pin + */ + for (pin_num = 0; pin_num < min_t(int, ZYNQ_GPIO_NR_GPIOS, + (int)chip->ngpio); pin_num++) { + gpio_irq = irq_find_mapping(irq_domain, pin_num); + irq_set_chip_and_handler(gpio_irq, &zynq_gpio_irqchip, + handle_simple_irq); + irq_set_chip_data(gpio_irq, (void *)gpio); + set_irq_flags(gpio_irq, IRQF_VALID); + } + + irq_set_handler_data(irq_num, (void *)gpio); + irq_set_chained_handler(irq_num, zynq_gpio_irqhandler); + + zynq_gpio_pm_runtime_init(pdev); + + device_set_wakeup_capable(&pdev->dev, 1); + + return 0; + + + return ret; +} + +static int zynq_gpio_remove(struct platform_device *pdev) +{ + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + clk_disable_unprepare(gpio->clk); + device_set_wakeup_capable(&pdev->dev, 0); + return 0; +} + +static struct of_device_id zynq_gpio_of_match[] = { + { .compatible = "xlnx,ps7-gpio-1.00.a", }, + { /* end of table */} +}; +MODULE_DEVICE_TABLE(of, zynq_gpio_of_match); + +static struct platform_driver zynq_gpio_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = ZYNQ_GPIO_PM, + .of_match_table = zynq_gpio_of_match, + }, + .probe = zynq_gpio_probe, + .remove = zynq_gpio_remove, +}; + +/** + * zynq_gpio_init - Initial driver registration call + */ +static int __init zynq_gpio_init(void) +{ + return platform_driver_register(&zynq_gpio_driver); +} + +postcore_initcall(zynq_gpio_init); Index: linux-3.12.24-rt38-xilinx/drivers/gpio/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/gpio/Kconfig 2014-07-20 22:05:50.183067495 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/gpio/Kconfig 2014-07-20 22:06:35.893313355 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:281 @ config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ + select GENERIC_IRQ_CHIP help - Say yes here to support the Xilinx FPGA GPIO device + Say yes here to support the Xilinx AXI/XPS GPIO device + +config GPIO_ZYNQ + tristate "Xilinx ZYNQ GPIO support" + depends on ARCH_ZYNQ + select GENERIC_IRQ_CHIP + help + Say yes here to support Xilinx ZYNQ GPIO controller. config GPIO_VR41XX tristate "NEC VR4100 series General-purpose I/O Uint support" Index: linux-3.12.24-rt38-xilinx/drivers/gpio/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/gpio/Makefile 2014-07-20 22:05:50.182067512 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/gpio/Makefile 2014-07-20 22:06:35.974312019 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:95 @ obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o +obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/drm_edid.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/gpu/drm/drm_edid.c 2014-07-20 22:05:50.197067264 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/drm_edid.c 2014-07-20 22:06:36.004311524 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1100 @ * Try to fetch EDID information by calling i2c driver function. */ static int -drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, +drm_do_probe_ddc_edid(void *data, unsigned char *buf, int block, int len) { + struct i2c_adapter *adapter = data; unsigned char start = block * EDID_LENGTH; unsigned char segment = block >> 1; unsigned char xfers = segment ? 3 : 2; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1159 @ return true; } -static u8 * -drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) +struct edid *drm_do_get_edid(struct drm_connector *connector, + int (*get_edid_block)(void *, unsigned char *buf, int, int), void *data) { int i, j = 0, valid_extensions = 0; u8 *block, *new; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1171 @ /* base block fetch */ for (i = 0; i < 4; i++) { - if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) + if (get_edid_block(data, block, 0, EDID_LENGTH)) goto out; if (drm_edid_block_valid(block, 0, print_bad_edid)) break; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1185 @ /* if there's no extensions, we're done */ if (block[0x7e] == 0) - return block; + return (struct edid *)block; new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); if (!new) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1194 @ for (j = 1; j <= block[0x7e]; j++) { for (i = 0; i < 4; i++) { - if (drm_do_probe_ddc_edid(adapter, + if (get_edid_block(data, block + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1222 @ block = new; } - return block; + return (struct edid *)block; carp: if (print_bad_edid) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1235 @ kfree(block); return NULL; } +EXPORT_SYMBOL_GPL(drm_do_get_edid); /** * Probe DDC presence. @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1268 @ struct edid *edid = NULL; if (drm_probe_ddc(adapter)) - edid = (struct edid *)drm_do_get_edid(connector, adapter); + edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, + adapter); return edid; } Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/i2c/adv7511_audio.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/i2c/adv7511_audio.c 2014-07-20 22:06:36.020311260 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Analog Devices ADV7511 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include <drm/i2c/adv7511.h> + +static const struct snd_soc_dapm_widget adv7511_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("TMDS"), + SND_SOC_DAPM_AIF_IN("AIFIN", "Playback", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route adv7511_routes[] = { + { "TMDS", NULL, "AIFIN" }, +}; + +static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs, + unsigned int *cts, unsigned int *n) +{ + switch (fs) { + case 32000: + *n = 4096; + break; + case 44100: + *n = 6272; + break; + case 48000: + *n = 6144; + break; + } + + *cts = ((f_tmds * *n) / (128 * fs)) * 1000; +} + +static int adv7511_update_cts_n(struct adv7511 *adv7511) +{ + unsigned int cts = 0; + unsigned int n = 0; + + adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n); + + regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf); + regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff); + regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff); + + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0, + (cts >> 16) & 0xf); + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1, + (cts >> 8) & 0xff); + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2, + cts & 0xff); + + return 0; +} + +static int adv7511_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct adv7511 *adv7511 = snd_soc_codec_get_drvdata(codec); + unsigned int rate; + unsigned int len; + + switch (params_rate(params)) { + case 32000: + rate = ADV7511_SAMPLE_FREQ_32000; + break; + case 44100: + rate = ADV7511_SAMPLE_FREQ_44100; + break; + case 48000: + rate = ADV7511_SAMPLE_FREQ_48000; + break; + case 88200: + rate = ADV7511_SAMPLE_FREQ_88200; + break; + case 96000: + rate = ADV7511_SAMPLE_FREQ_96000; + break; + case 176400: + rate = ADV7511_SAMPLE_FREQ_176400; + break; + case 192000: + rate = ADV7511_SAMPLE_FREQ_192000; + break; + default: + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + len = ADV7511_I2S_SAMPLE_LEN_16; + break; + case SNDRV_PCM_FORMAT_S18_3LE: + len = ADV7511_I2S_SAMPLE_LEN_18; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + len = ADV7511_I2S_SAMPLE_LEN_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + len = ADV7511_I2S_SAMPLE_LEN_24; + break; + default: + return -EINVAL; + } + + adv7511->f_audio = params_rate(params); + + adv7511_update_cts_n(adv7511); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3, + ADV7511_AUDIO_CFG3_LEN_MASK, len); + regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, + ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4); + + return 0; +} + +static int adv7511_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct adv7511 *adv7511 = snd_soc_codec_get_drvdata(codec); + unsigned int audio_source, i2s_format = 0; + unsigned int invert_clock; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + audio_source = ADV7511_AUDIO_SOURCE_I2S; + i2s_format = ADV7511_I2S_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + audio_source = ADV7511_AUDIO_SOURCE_I2S; + i2s_format = ADV7511_I2S_FORMAT_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + audio_source = ADV7511_AUDIO_SOURCE_I2S; + i2s_format = ADV7511_I2S_FORMAT_LEFT_J; + break; + case SND_SOC_DAIFMT_SPDIF: + audio_source = ADV7511_AUDIO_SOURCE_SPDIF; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + invert_clock = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + invert_clock = 1; + break; + default: + return -EINVAL; + } + + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70, + audio_source << 4); + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6), + invert_clock << 6); + regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03, + i2s_format); + + adv7511->audio_source = audio_source; + + return 0; +} + +static int adv7511_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct adv7511 *adv7511 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_ON: + switch (adv7511->audio_source) { + case ADV7511_AUDIO_SOURCE_I2S: + break; + case ADV7511_AUDIO_SOURCE_SPDIF: + regmap_update_bits(adv7511->regmap, + ADV7511_REG_AUDIO_CONFIG, BIT(7), + BIT(7)); + break; + } + break; + case SND_SOC_BIAS_PREPARE: + if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { + adv7511_packet_enable(adv7511, + ADV7511_PACKET_ENABLE_AUDIO_SAMPLE); + adv7511_packet_enable(adv7511, + ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); + adv7511_packet_enable(adv7511, + ADV7511_PACKET_ENABLE_N_CTS); + } else { + adv7511_packet_disable(adv7511, + ADV7511_PACKET_ENABLE_AUDIO_SAMPLE); + adv7511_packet_disable(adv7511, + ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); + adv7511_packet_disable(adv7511, + ADV7511_PACKET_ENABLE_N_CTS); + } + break; + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, + BIT(7), 0); + break; + case SND_SOC_BIAS_OFF: + break; + } + codec->dapm.bias_level = level; + return 0; +} + +#define ADV7511_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) + +#define ADV7511_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops adv7511_dai_ops = { + .hw_params = adv7511_hw_params, + /*.set_sysclk = adv7511_set_dai_sysclk,*/ + .set_fmt = adv7511_set_dai_fmt, +}; + +static struct snd_soc_dai_driver adv7511_dai = { + .name = "adv7511", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = ADV7511_RATES, + .formats = ADV7511_FORMATS, + }, + .ops = &adv7511_dai_ops, +}; + +static int adv7511_suspend(struct snd_soc_codec *codec) +{ + return adv7511_set_bias_level(codec, SND_SOC_BIAS_OFF); +} + +static int adv7511_resume(struct snd_soc_codec *codec) +{ + return adv7511_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +} + +static int adv7511_probe(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + return adv7511_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +} + +static int adv7511_remove(struct snd_soc_codec *codec) +{ + adv7511_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static struct snd_soc_codec_driver adv7511_codec_driver = { + .probe = adv7511_probe, + .remove = adv7511_remove, + .suspend = adv7511_suspend, + .resume = adv7511_resume, + .set_bias_level = adv7511_set_bias_level, + + .dapm_widgets = adv7511_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adv7511_dapm_widgets), + .dapm_routes = adv7511_routes, + .num_dapm_routes = ARRAY_SIZE(adv7511_routes), +}; + +int adv7511_audio_init(struct device *dev) +{ + return snd_soc_register_codec(dev, &adv7511_codec_driver, + &adv7511_dai, 1); +} + +void adv7511_audio_exit(struct device *dev) +{ + snd_soc_unregister_codec(dev); +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/i2c/adv7511_core.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/i2c/adv7511_core.c 2014-07-20 22:06:36.034311029 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Analog Devices ADV7511 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_encoder_slave.h> + +#include <drm/i2c/adv7511.h> + +static const uint8_t adv7511_register_defaults[] = { + 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */ + 0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13, + 0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ + 0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84, + 0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */ + 0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */ + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, + 0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */ + 0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */ + 0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */ + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */ + 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04, + 0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, + 0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */ + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +/* ADI recommanded values for proper operation. */ +static const struct reg_default adv7511_fixed_registers[] = { + { 0x98, 0x03 }, + { 0x9a, 0xe0 }, + { 0x9c, 0x30 }, + { 0x9d, 0x61 }, + { 0xa2, 0xa4 }, + { 0xa3, 0xa4 }, + { 0xe0, 0xd0 }, + { 0xf9, 0x00 }, + { 0x55, 0x02 }, +}; + +static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder) +{ + return to_encoder_slave(encoder)->slave_priv; +} + +static void adv7511_set_colormap(struct adv7511 *adv7511, bool enable, + const uint16_t *coeff, + unsigned int scaling_factor) +{ + unsigned int i; + + regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1), + ADV7511_CSC_UPDATE_MODE, ADV7511_CSC_UPDATE_MODE); + + if (enable) { + for (i = 0; i < 12; ++i) { + regmap_update_bits(adv7511->regmap, + ADV7511_REG_CSC_UPPER(i), + 0x1f, coeff[i] >> 8); + regmap_write(adv7511->regmap, + ADV7511_REG_CSC_LOWER(i), + coeff[i] & 0xff); + } + } + + if (enable) + regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0), + 0xe0, 0x80 | (scaling_factor << 5)); + else + regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0), + 0x80, 0x00); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1), + ADV7511_CSC_UPDATE_MODE, 0); +} + +#define ADV7511_HDMI_CFG_MODE_MASK 0x2 +#define ADV7511_HDMI_CFG_MODE_DVI 0x0 +#define ADV7511_HDMI_CFG_MODE_HDMI 0x2 + +#define ADV7511_PACKET_MEM_SPD 0 +#define ADV7511_PACKET_MEM_MPEG 1 +#define ADV7511_PACKET_MEM_ACP 2 +#define ADV7511_PACKET_MEM_ISRC1 3 +#define ADV7511_PACKET_MEM_ISRC2 4 +#define ADV7511_PACKET_MEM_GM 5 +#define ADV7511_PACKET_MEM_SPARE1 6 +#define ADV7511_PACKET_MEM_SPARE2 7 + +#define ADV7511_PACKET_MEM_DATA_REG(x) ((x) * 0x20) +#define ADV7511_PACKET_MEM_UPDATE_REG(x) ((x) * 0x20 + 0x1f) +#define ADV7511_PACKET_MEM_UPDATE_ENABLE BIT(7) + +static void adv7511_set_config(struct drm_encoder *encoder, void *c) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + struct adv7511_video_config *config = c; + bool output_format_422, output_format_ycbcr; + unsigned int mode; + uint8_t infoframe[17]; + + if (config->hdmi_mode) { + mode = ADV7511_HDMI_CFG_MODE_HDMI; + + switch (config->avi_infoframe.colorspace) { + case HDMI_COLORSPACE_YUV444: + output_format_422 = false; + output_format_ycbcr = true; + break; + case HDMI_COLORSPACE_YUV422: + output_format_422 = true; + output_format_ycbcr = true; + break; + default: + output_format_422 = false; + output_format_ycbcr = false; + break; + } + } else { + mode = ADV7511_HDMI_CFG_MODE_DVI; + output_format_422 = false; + output_format_ycbcr = false; + } + + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); + + adv7511_set_colormap(adv7511, config->csc_enable, + config->csc_coefficents, + config->csc_scaling_factor); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x81, + (output_format_422 << 7) | output_format_ycbcr); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG, + ADV7511_HDMI_CFG_MODE_MASK, mode); + + hdmi_avi_infoframe_pack(&config->avi_infoframe, infoframe, + sizeof(infoframe)); + + /* The AVI infoframe id is not configurable */ + regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION, + infoframe + 1, sizeof(infoframe) - 1); + + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); +} + +static void adv7511_set_link_config(struct adv7511 *adv7511, + const struct adv7511_link_config *config) +{ + enum adv7511_input_sync_pulse sync_pulse; + + switch (config->id) { + case ADV7511_INPUT_ID_12_15_16BIT_RGB444_YCbCr444: + sync_pulse = ADV7511_INPUT_SYNC_PULSE_NONE; + break; + default: + sync_pulse = config->sync_pulse; + break; + } + + switch (config->id) { + case ADV7511_INPUT_ID_16_20_24BIT_YCbCr422_EMBEDDED_SYNC: + case ADV7511_INPUT_ID_8_10_12BIT_YCbCr422_EMBEDDED_SYNC: + adv7511->embedded_sync = true; + break; + default: + adv7511->embedded_sync = false; + break; + } + + regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, 0xf, + config->id); + regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x7e, + (config->input_color_depth << 4) | + (config->input_style << 2)); + regmap_write(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG2, + (config->reverse_bitorder << 6) | + (config->bit_justification << 3)); + regmap_write(adv7511->regmap, ADV7511_REG_TIMING_GEN_SEQ, + (sync_pulse << 2) | (config->timing_gen_seq << 1)); + regmap_write(adv7511->regmap, 0xba, (config->clock_delay << 5)); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_TMDS_CLOCK_INV, 0x08, + config->tmds_clock_inversion << 3); + + adv7511->hsync_polarity = config->hsync_polarity; + adv7511->vsync_polarity = config->vsync_polarity; +} + +int adv7511_packet_enable(struct adv7511 *adv7511, unsigned int packet) +{ + if (packet & 0xff) + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0, + packet, 0xff); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, + packet, 0xff); + } + + return 0; +} + +int adv7511_packet_disable(struct adv7511 *adv7511, unsigned int packet) +{ + if (packet & 0xff) + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0, + packet, 0x00); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, + packet, 0x00); + } + + return 0; +} + +static bool adv7511_register_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADV7511_REG_SPDIF_FREQ: + case ADV7511_REG_CTS_AUTOMATIC1: + case ADV7511_REG_CTS_AUTOMATIC2: + case ADV7511_REG_VIC_DETECTED: + case ADV7511_REG_VIC_SEND: + case ADV7511_REG_AUX_VIC_DETECTED: + case ADV7511_REG_STATUS: + case ADV7511_REG_GC(1): + case ADV7511_REG_INT(0): + case ADV7511_REG_INT(1): + case ADV7511_REG_PLL_STATUS: + case ADV7511_REG_AN(0): + case ADV7511_REG_AN(1): + case ADV7511_REG_AN(2): + case ADV7511_REG_AN(3): + case ADV7511_REG_AN(4): + case ADV7511_REG_AN(5): + case ADV7511_REG_AN(6): + case ADV7511_REG_AN(7): + case ADV7511_REG_HDCP_STATUS: + case ADV7511_REG_BCAPS: + case ADV7511_REG_BKSV(0): + case ADV7511_REG_BKSV(1): + case ADV7511_REG_BKSV(2): + case ADV7511_REG_BKSV(3): + case ADV7511_REG_BKSV(4): + case ADV7511_REG_DDC_STATUS: + case ADV7511_REG_BSTATUS(0): + case ADV7511_REG_BSTATUS(1): + case ADV7511_REG_CHIP_ID_HIGH: + case ADV7511_REG_CHIP_ID_LOW: + return true; + } + + return false; +} + +static bool adv7511_hpd(struct adv7511 *adv7511) +{ + unsigned int irq0; + int ret; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); + if (ret < 0) + return false; + + if (irq0 & ADV7511_INT0_HDP) { + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_HDP); + return true; + } + + return false; +} + +static irqreturn_t adv7511_irq_handler(int irq, void *devid) +{ + struct adv7511 *adv7511 = devid; + + if (adv7511_hpd(adv7511)) + drm_helper_hpd_irq_event(adv7511->encoder->dev); + + wake_up_all(&adv7511->wq); + + return IRQ_HANDLED; +} + +static unsigned int adv7511_is_interrupt_pending(struct adv7511 *adv7511, + unsigned int irq) +{ + unsigned int irq0, irq1; + unsigned int pending; + int ret; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); + if (ret < 0) + return 0; + ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1); + if (ret < 0) + return 0; + + pending = (irq1 << 8) | irq0; + + return pending & irq; +} + +static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq, + int timeout) +{ + unsigned int pending = 0; + int ret; + + if (adv7511->i2c_main->irq) { + ret = wait_event_interruptible_timeout(adv7511->wq, + adv7511_is_interrupt_pending(adv7511, irq), + msecs_to_jiffies(timeout)); + if (ret <= 0) + return 0; + pending = adv7511_is_interrupt_pending(adv7511, irq); + } else { + if (timeout < 25) + timeout = 25; + do { + pending = adv7511_is_interrupt_pending(adv7511, irq); + if (pending) + break; + msleep(25); + timeout -= 25; + } while (timeout >= 25); + } + + return pending; +} + +static int adv7511_get_edid_block(void *data, unsigned char *buf, int block, + int len) +{ + struct drm_encoder *encoder = data; + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + struct i2c_msg xfer[2]; + uint8_t offset; + int i; + int ret; + + if (len > 128) + return -EINVAL; + + if (adv7511->current_edid_segment != block / 2) { + unsigned int status; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS, + &status); + if (ret < 0) + return ret; + + if (status != 2) { + regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT, + block); + ret = adv7511_wait_for_interrupt(adv7511, + ADV7511_INT0_EDID_READY | + ADV7511_INT1_DDC_ERROR, 200); + + if (!(ret & ADV7511_INT0_EDID_READY)) + return -EIO; + } + + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); + + /* Break this apart, hopefully more I2C controllers will + * support 64 byte transfers than 256 byte transfers + */ + + xfer[0].addr = adv7511->i2c_edid->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = &offset; + xfer[1].addr = adv7511->i2c_edid->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 64; + xfer[1].buf = adv7511->edid_buf; + + offset = 0; + + for (i = 0; i < 4; ++i) { + ret = i2c_transfer(adv7511->i2c_edid->adapter, xfer, + ARRAY_SIZE(xfer)); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + + xfer[1].buf += 64; + offset += 64; + } + + adv7511->current_edid_segment = block / 2; + } + + if (block % 2 == 0) + memcpy(buf, adv7511->edid_buf, len); + else + memcpy(buf, adv7511->edid_buf + 128, len); + + return 0; +} + +static int adv7511_get_modes(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + struct edid *edid; + unsigned int count; + + /* Reading the EDID only works if the device is powered */ + if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) { + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, 0); + adv7511->current_edid_segment = -1; + } + + edid = drm_do_get_edid(connector, adv7511_get_edid_block, encoder); + + if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, + ADV7511_POWER_POWER_DOWN); + + adv7511->edid = edid; + if (!edid) + return 0; + + drm_mode_connector_update_edid_property(connector, edid); + count = drm_add_edid_modes(connector, edid); + + kfree(adv7511->edid); + + return count; +} + +struct edid *adv7511_get_edid(struct drm_encoder *encoder) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + + if (!adv7511->edid) + return NULL; + + return kmemdup(adv7511->edid, sizeof(*adv7511->edid) + + adv7511->edid->extensions * 128, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(adv7511_get_edid); + +static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + + switch (mode) { + case DRM_MODE_DPMS_ON: + adv7511->current_edid_segment = -1; + + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, 0); + /* + * Per spec it is allowed to pulse the HDP signal to indicate + * that the EDID information has changed. Some monitors do this + * when they wakeup from standby or are enabled. When the HDP + * goes low the adv7511 is reset and the outputs are disabled + * which might cause the monitor to go to standby again. To + * avoid this we ignore the HDP pin for the first few seconds + * after enabeling the output. + */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HDP_SRC_MASK, + ADV7511_REG_POWER2_HDP_SRC_NONE); + /* Most of the registers are reset during power down or + * when HPD is low + */ + regcache_sync(adv7511->regmap); + break; + default: + /* TODO: setup additional power down modes */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, + ADV7511_POWER_POWER_DOWN); + regcache_mark_dirty(adv7511->regmap); + break; + } + + adv7511->dpms_mode = mode; +} + +static enum drm_connector_status +adv7511_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + enum drm_connector_status status; + unsigned int val; + bool hpd; + int ret; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val); + if (ret < 0) + return connector_status_disconnected; + + if (val & ADV7511_STATUS_HPD) + status = connector_status_connected; + else + status = connector_status_disconnected; + + hpd = adv7511_hpd(adv7511); + + /* The chip resets itself when the cable is disconnected, so in case + * there is a pending HPD interrupt and the cable is connected there was + * at least on transition from disconnected to connected and the chip + * has to be reinitialized. */ + if (status == connector_status_connected && hpd && + adv7511->dpms_mode == DRM_MODE_DPMS_ON) { + regcache_mark_dirty(adv7511->regmap); + adv7511_encoder_dpms(encoder, adv7511->dpms_mode); + adv7511_get_modes(encoder, connector); + status = connector_status_disconnected; + } else { + /* Renable HDP sensing */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HDP_SRC_MASK, + ADV7511_REG_POWER2_HDP_SRC_BOTH); + } + + adv7511->status = status; + return status; +} + +static void adv7511_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + unsigned int low_refresh_rate; + unsigned int hsync_polarity = 0; + unsigned int vsync_polarity = 0; + + if (adv7511->embedded_sync) { + unsigned int hsync_offset, hsync_len; + unsigned int vsync_offset, vsync_len; + + hsync_offset = adj_mode->crtc_hsync_start - + adj_mode->crtc_hdisplay; + vsync_offset = adj_mode->crtc_vsync_start - + adj_mode->crtc_vdisplay; + hsync_len = adj_mode->crtc_hsync_end - + adj_mode->crtc_hsync_start; + vsync_len = adj_mode->crtc_vsync_end - + adj_mode->crtc_vsync_start; + + /* The hardware vsync generator has a off-by-one bug */ + vsync_offset += 1; + + regmap_write(adv7511->regmap, ADV7511_REG_HSYNC_PLACEMENT_MSB, + ((hsync_offset >> 10) & 0x7) << 5); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(0), + (hsync_offset >> 2) & 0xff); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(1), + ((hsync_offset & 0x3) << 6) | + ((hsync_len >> 4) & 0x3f)); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(2), + ((hsync_len & 0xf) << 4) | + ((vsync_offset >> 6) & 0xf)); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(3), + ((vsync_offset & 0x3f) << 2) | + ((vsync_len >> 8) & 0x3)); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(4), + vsync_len & 0xff); + + hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC); + vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC); + } else { + enum adv7511_sync_polarity mode_hsync_polarity; + enum adv7511_sync_polarity mode_vsync_polarity; + + /** + * If the input signal is always low or always high we want to + * invert or let it passthrough depending on the polarity of the + * current mode. + **/ + if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC) + mode_hsync_polarity = ADV7511_SYNC_POLARITY_LOW; + else + mode_hsync_polarity = ADV7511_SYNC_POLARITY_HIGH; + + if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC) + mode_vsync_polarity = ADV7511_SYNC_POLARITY_LOW; + else + mode_vsync_polarity = ADV7511_SYNC_POLARITY_HIGH; + + if (adv7511->hsync_polarity != mode_hsync_polarity && + adv7511->hsync_polarity != + ADV7511_SYNC_POLARITY_PASSTHROUGH) + hsync_polarity = 1; + + if (adv7511->vsync_polarity != mode_vsync_polarity && + adv7511->vsync_polarity != + ADV7511_SYNC_POLARITY_PASSTHROUGH) + vsync_polarity = 1; + } + + if (mode->vrefresh <= 24000) + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ; + else if (mode->vrefresh <= 25000) + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ; + else if (mode->vrefresh <= 30000) + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ; + else + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE; + + regmap_update_bits(adv7511->regmap, 0xfb, + 0x6, low_refresh_rate << 1); + regmap_update_bits(adv7511->regmap, 0x17, + 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); + + adv7511->f_tmds = mode->clock; +} + +static struct drm_encoder_slave_funcs adv7511_encoder_funcs = { + .set_config = adv7511_set_config, + .dpms = adv7511_encoder_dpms, + /* .destroy = adv7511_encoder_destroy,*/ + .mode_set = adv7511_encoder_mode_set, + .detect = adv7511_encoder_detect, + .get_modes = adv7511_get_modes, +}; + +static const struct regmap_config adv7511_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, + .reg_defaults_raw = adv7511_register_defaults, + .num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults), + + .volatile_reg = adv7511_register_volatile, +}; + +/* + adi,input-id - + 0x00: + 0x01: + 0x02: + 0x03: + 0x04: + 0x05: + adi,sync-pulse - Selects the sync pulse + 0x00: Use the DE signal as sync pulse + 0x01: Use the HSYNC signal as sync pulse + 0x02: Use the VSYNC signal as sync pulse + 0x03: No external sync pulse + adi,bit-justification - + 0x00: Evently + 0x01: Right + 0x02: Left + adi,up-conversion - + 0x00: zero-order up conversion + 0x01: first-order up conversion + adi,timing-generation-sequence - + 0x00: Sync adjustment first, then DE generation + 0x01: DE generation first then sync adjustment + adi,vsync-polarity - Polarity of the vsync signal + 0x00: Passthrough + 0x01: Active low + 0x02: Active high + adi,hsync-polarity - Polarity of the hsync signal + 0x00: Passthrough + 0x01: Active low + 0x02: Active high + adi,reverse-bitorder - If set the bitorder is reveresed + adi,tmds-clock-inversion - If set use tdms clock inversion + adi,clock-delay - Clock delay for the video data clock + 0x00: -1200 ps + 0x01: -800 ps + 0x02: -400 ps + 0x03: no dealy + 0x04: 400 ps + 0x05: 800 ps + 0x06: 1200 ps + 0x07: 1600 ps + adi,input-style - Specifies the input style used + 0x02: Use input style 1 + 0x01: Use input style 2 + 0x03: Use Input style 3 + adi,input-color-depth - Selects the input format color depth + 0x03: 8-bit per channel + 0x01: 10-bit per channel + 0x02: 12-bit per channel +*/ + +static int adv7511_parse_dt(struct device_node *np, + struct adv7511_link_config *config) +{ + int ret; + + ret = of_property_read_u32(np, "adi,input-id", &config->id); + if (ret < 0) + return ret; + + config->sync_pulse = ADV7511_INPUT_SYNC_PULSE_NONE; + of_property_read_u32(np, "adi,sync-pulse", &config->sync_pulse); + + ret = of_property_read_u32(np, "adi,bit-justification", + &config->bit_justification); + if (ret < 0) + return ret; + + config->up_conversion = ADV7511_UP_CONVERSION_ZERO_ORDER; + of_property_read_u32(np, "adi,up-conversion", &config->up_conversion); + + ret = of_property_read_u32(np, "adi,timing-generation-sequence", + &config->timing_gen_seq); + if (ret < 0) + return ret; + + ret = of_property_read_u32(np, "adi,vsync-polarity", + &config->vsync_polarity); + if (ret < 0) + return ret; + + ret = of_property_read_u32(np, "adi,hsync-polarity", + &config->hsync_polarity); + if (ret < 0) + return ret; + + config->reverse_bitorder = of_property_read_bool(np, + "adi,reverse-bitorder"); + config->tmds_clock_inversion = of_property_read_bool(np, + "adi,tmds-clock-inversion"); + + ret = of_property_read_u32(np, "adi,clock-delay", + &config->clock_delay); + if (ret) + return ret; + + ret = of_property_read_u32(np, "adi,input-style", + &config->input_style); + if (ret) + return ret; + + ret = of_property_read_u32(np, "adi,input-color-depth", + &config->input_color_depth); + if (ret) + return ret; + + config->gpio_pd = of_get_gpio(np, 0); + if (config->gpio_pd == -EPROBE_DEFER) + return -EPROBE_DEFER; + + return 0; +} + +static const int edid_i2c_addr = 0x7e; +static const int packet_i2c_addr = 0x70; +static const int cec_i2c_addr = 0x78; + +static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct adv7511_link_config link_config; + struct adv7511 *adv7511; + struct device *dev = &i2c->dev; + unsigned int val; + int ret; + + if (dev->of_node) { + ret = adv7511_parse_dt(dev->of_node, &link_config); + if (ret) + return ret; + } else { + if (!dev->platform_data) + return -EINVAL; + link_config = *(struct adv7511_link_config *)dev->platform_data; + } + + adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL); + if (!adv7511) + return -ENOMEM; + + adv7511->gpio_pd = link_config.gpio_pd; + + if (gpio_is_valid(adv7511->gpio_pd)) { + ret = devm_gpio_request_one(dev, adv7511->gpio_pd, + GPIOF_OUT_INIT_HIGH, "PD"); + if (ret) + return ret; + mdelay(5); + gpio_set_value_cansleep(adv7511->gpio_pd, 0); + } + + adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config); + if (IS_ERR(adv7511->regmap)) + return PTR_ERR(adv7511->regmap); + + ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val); + if (ret) + return ret; + dev_dbg(dev, "Rev. %d\n", val); + + ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers, + ARRAY_SIZE(adv7511_fixed_registers)); + if (ret) + return ret; + + regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr); + regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR, + packet_i2c_addr); + regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr); + adv7511_packet_disable(adv7511, 0xffff); + + adv7511->i2c_main = i2c; + adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1); + adv7511->i2c_packet = i2c_new_dummy(i2c->adapter, packet_i2c_addr >> 1); + if (!adv7511->i2c_edid) + return -ENOMEM; + + if (i2c->irq) { + ret = request_threaded_irq(i2c->irq, NULL, adv7511_irq_handler, + IRQF_ONESHOT, dev_name(dev), + adv7511); + if (ret) + goto err_i2c_unregister_device; + + init_waitqueue_head(&adv7511->wq); + } + + /* CEC is unused for now */ + regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, + ADV7511_CEC_CTRL_POWER_DOWN); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); + + adv7511->current_edid_segment = -1; + + i2c_set_clientdata(i2c, adv7511); + adv7511_audio_init(dev); + + adv7511_set_link_config(adv7511, &link_config); + + return 0; + +err_i2c_unregister_device: + i2c_unregister_device(adv7511->i2c_edid); + + return ret; +} + +static int adv7511_remove(struct i2c_client *i2c) +{ + struct adv7511 *adv7511 = i2c_get_clientdata(i2c); + + i2c_unregister_device(adv7511->i2c_edid); + + if (i2c->irq) + free_irq(i2c->irq, adv7511); + kfree(adv7511->edid); + + return 0; +} + +static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev, + struct drm_encoder_slave *encoder) +{ + + struct adv7511 *adv7511 = i2c_get_clientdata(i2c); + + encoder->slave_priv = adv7511; + encoder->slave_funcs = &adv7511_encoder_funcs; + + adv7511->encoder = &encoder->base; + + return 0; +} + +static const struct i2c_device_id adv7511_ids[] = { + { "adv7511", 0 }, + {} +}; + +static struct drm_i2c_encoder_driver adv7511_driver = { + .i2c_driver = { + .driver = { + .name = "adv7511", + }, + .id_table = adv7511_ids, + .probe = adv7511_probe, + .remove = adv7511_remove, + }, + + .encoder_init = adv7511_encoder_init, +}; + +static int adv7511_init(void) +{ + return drm_i2c_encoder_register(THIS_MODULE, &adv7511_driver); +} +module_init(adv7511_init); + +static void adv7511_exit(void) +{ + drm_i2c_encoder_unregister(&adv7511_driver); +} +module_exit(adv7511_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/i2c/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/gpu/drm/i2c/Kconfig 2014-07-20 22:05:50.199067232 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/i2c/Kconfig 2014-07-20 22:06:36.042310897 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:28 @ help Support for NXP Semiconductors TDA998X HDMI encoders. +config DRM_ENCODER_ADV7511 + tristate "ADV7511 encoder" + depends on SOUND + depends on SND + depends on SND_SOC + select REGMAP_I2C + select HDMI + endmenu Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/i2c/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/gpu/drm/i2c/Makefile 2014-07-20 22:05:50.198067248 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/i2c/Makefile 2014-07-20 22:06:36.052310732 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:11 @ tda998x-y := tda998x_drv.o obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o + +adv7511-y := adv7511_core.o adv7511_audio.o +obj-$(CONFIG_DRM_ENCODER_ADV7511) += adv7511.o Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/gpu/drm/Kconfig 2014-07-20 22:05:50.196067281 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/Kconfig 2014-07-20 22:06:36.062310567 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:239 @ source "drivers/gpu/drm/qxl/Kconfig" source "drivers/gpu/drm/msm/Kconfig" + +source "drivers/gpu/drm/xilinx/Kconfig" Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/gpu/drm/Makefile 2014-07-20 22:05:50.195067298 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/Makefile 2014-07-20 22:06:36.071310419 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:58 @ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ obj-$(CONFIG_DRM_MSM) += msm/ +obj-$(CONFIG_DRM_XILINX) += xilinx/ obj-y += i2c/ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/Kconfig 2014-07-20 22:06:36.084310204 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +config DRM_XILINX + tristate "Xilinx DRM" + depends on DRM && ARCH_ZYNQ && HAVE_CLK + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER + select DRM_ENCODER_ADV7511 + select XILINX_AXIVDMA + help + DRM display driver for Xilinx IP based pipelines. Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/Makefile 2014-07-20 22:06:36.089310122 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Makefile for the drm device driver. This driver provides support for the +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. + +xilinx_drm-y := xilinx_drm_drv.o xilinx_drm_crtc.o xilinx_drm_plane.o \ + xilinx_drm_encoder.o xilinx_drm_connector.o +xilinx_drm-y += xilinx_cresample.o xilinx_rgb2yuv.o xilinx_osd.o xilinx_vtc.o + +obj-$(CONFIG_DRM_XILINX) += xilinx_drm.o Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_cresample.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_cresample.c 2014-07-20 22:06:36.096310006 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Chroma Resampler support for Xilinx DRM KMS + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <linux/device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> + +#include "xilinx_drm_drv.h" + +/* registers */ +/* general control registers */ +#define CRESAMPLE_CONTROL 0x0000 + +/* horizontal and vertical active frame size */ +#define CRESAMPLE_ACTIVE_SIZE 0x0020 + +/* control register bit definition */ +#define CRESAMPLE_CTL_EN (1 << 0) /* enable */ +#define CRESAMPLE_CTL_RU (1 << 1) /* reg update */ +#define CRESAMPLE_CTL_RESET (1 << 31) /* instant reset */ + +struct xilinx_cresample { + void __iomem *base; + const char *input_format_name; + const char *output_format_name; +}; + +/* enable cresample */ +void xilinx_cresample_enable(struct xilinx_cresample *cresample) +{ + u32 reg; + + reg = xilinx_drm_readl(cresample->base, CRESAMPLE_CONTROL); + xilinx_drm_writel(cresample->base, CRESAMPLE_CONTROL, + reg | CRESAMPLE_CTL_EN); +} + +/* disable cresample */ +void xilinx_cresample_disable(struct xilinx_cresample *cresample) +{ + u32 reg; + + reg = xilinx_drm_readl(cresample->base, CRESAMPLE_CONTROL); + xilinx_drm_writel(cresample->base, CRESAMPLE_CONTROL, + reg & ~CRESAMPLE_CTL_EN); +} + +/* configure cresample */ +void xilinx_cresample_configure(struct xilinx_cresample *cresample, + int hactive, int vactive) +{ + /* configure hsize and vsize */ + xilinx_drm_writel(cresample->base, CRESAMPLE_ACTIVE_SIZE, + (vactive << 16) | hactive); +} + +/* reset cresample */ +void xilinx_cresample_reset(struct xilinx_cresample *cresample) +{ + u32 reg; + + xilinx_drm_writel(cresample->base, CRESAMPLE_CONTROL, + CRESAMPLE_CTL_RESET); + + /* enable register update */ + reg = xilinx_drm_readl(cresample->base, CRESAMPLE_CONTROL); + xilinx_drm_writel(cresample->base, CRESAMPLE_CONTROL, + reg | CRESAMPLE_CTL_RU); +} + +/* get an input format */ +const char * +xilinx_cresample_get_input_format_name(struct xilinx_cresample *cresample) +{ + return cresample->input_format_name; +} + +/* get an output format */ +const char * +xilinx_cresample_get_output_format_name(struct xilinx_cresample *cresample) +{ + return cresample->output_format_name; +} + +struct xilinx_cresample *xilinx_cresample_probe(struct device *dev, + struct device_node *node) +{ + struct xilinx_cresample *cresample; + struct resource res; + int ret; + + cresample = devm_kzalloc(dev, sizeof(*cresample), GFP_KERNEL); + if (!cresample) + return ERR_PTR(-ENOMEM); + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + dev_err(dev, "failed to of_address_to_resource\n"); + return ERR_PTR(ret); + } + + cresample->base = devm_ioremap_resource(dev, &res); + if (IS_ERR(cresample->base)) + return ERR_CAST(cresample->base); + + ret = of_property_read_string(node, "xlnx,input-format", + &cresample->input_format_name); + if (ret) { + dev_warn(dev, "failed to get an input format prop\n"); + return ERR_PTR(ret); + } + + ret = of_property_read_string(node, "xlnx,output-format", + &cresample->output_format_name); + if (ret) { + dev_warn(dev, "failed to get an output format prop\n"); + return ERR_PTR(ret); + } + + xilinx_cresample_reset(cresample); + + return cresample; +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_cresample.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_cresample.h 2014-07-20 22:06:36.102309908 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Chroma Resampler Header for Xilinx DRM KMS + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_CRESAMPLE_H_ +#define _XILINX_CRESAMPLE_H_ + +struct xilinx_cresample; + +void xilinx_cresample_configure(struct xilinx_cresample *cresample, + int hactive, int vactive); +void xilinx_cresample_reset(struct xilinx_cresample *cresample); +void xilinx_cresample_enable(struct xilinx_cresample *cresample); +void xilinx_cresample_disable(struct xilinx_cresample *cresample); + +const char * +xilinx_cresample_get_input_format_name(struct xilinx_cresample *cresample); +const char * +xilinx_cresample_get_output_format_name(struct xilinx_cresample *cresample); + +struct device; +struct device_node; + +struct xilinx_cresample *xilinx_cresample_probe(struct device *dev, + struct device_node *node); + +#endif /* _XILINX_CRESAMPLE_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_connector.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_connector.c 2014-07-20 22:06:36.179308638 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM connector driver for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_encoder_slave.h> +#include <drm/i2c/adv7511.h> + +#include <linux/device.h> + +#include "xilinx_drm_drv.h" + +struct xilinx_drm_connector { + struct drm_connector base; + struct drm_encoder *encoder; +}; + +#define to_xilinx_connector(x) \ + container_of(x, struct xilinx_drm_connector, base) + +/* get mode list */ +static int xilinx_drm_connector_get_modes(struct drm_connector *base_connector) +{ + struct xilinx_drm_connector *connector = + to_xilinx_connector(base_connector); + struct drm_encoder *encoder = connector->encoder; + struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder); + struct drm_encoder_slave_funcs *encoder_sfuncs = + encoder_slave->slave_funcs; + int count = 0; + + if (encoder_sfuncs->get_modes) + count = encoder_sfuncs->get_modes(encoder, base_connector); + + return count; +} + +/* check if mode is valid */ +static int xilinx_drm_connector_mode_valid(struct drm_connector *base_connector, + struct drm_display_mode *mode) +{ + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + return MODE_NO_INTERLACE; + + return MODE_OK; +} + +/* find best encoder: return stored encoder */ +static struct drm_encoder * +xilinx_drm_connector_best_encoder(struct drm_connector *base_connector) +{ + struct xilinx_drm_connector *connector = + to_xilinx_connector(base_connector); + + return connector->encoder; +} + +static struct drm_connector_helper_funcs xilinx_drm_connector_helper_funcs = { + .get_modes = xilinx_drm_connector_get_modes, + .mode_valid = xilinx_drm_connector_mode_valid, + .best_encoder = xilinx_drm_connector_best_encoder, +}; + +static enum drm_connector_status +xilinx_drm_connector_detect(struct drm_connector *base_connector, bool force) +{ + struct xilinx_drm_connector *connector = + to_xilinx_connector(base_connector); + enum drm_connector_status status = connector_status_unknown; + struct drm_encoder *encoder = connector->encoder; + struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder); + struct drm_encoder_slave_funcs *encoder_sfuncs = + encoder_slave->slave_funcs; + + if (encoder_sfuncs->detect) + status = encoder_sfuncs->detect(encoder, base_connector); + + /* some connector ignores the first hpd, so try again if forced */ + if (force && (status != connector_status_connected)) + status = encoder_sfuncs->detect(encoder, base_connector); + + DRM_DEBUG_KMS("status: %d\n", status); + + return status; +} + +/* destroy connector */ +void xilinx_drm_connector_destroy(struct drm_connector *base_connector) +{ + drm_sysfs_connector_remove(base_connector); + drm_connector_cleanup(base_connector); +} + +static struct drm_connector_funcs xilinx_drm_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = xilinx_drm_connector_detect, + .destroy = xilinx_drm_connector_destroy, +}; + +/* create connector */ +struct drm_connector * +xilinx_drm_connector_create(struct drm_device *drm, + struct drm_encoder *base_encoder) +{ + struct xilinx_drm_connector *connector; + int ret; + + connector = devm_kzalloc(drm->dev, sizeof(*connector), GFP_KERNEL); + if (!connector) + return ERR_PTR(-ENOMEM); + + connector->base.polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + + ret = drm_connector_init(drm, &connector->base, + &xilinx_drm_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + if (ret) { + DRM_ERROR("failed to initialize connector\n"); + return ERR_PTR(ret); + } + + drm_connector_helper_add(&connector->base, + &xilinx_drm_connector_helper_funcs); + + /* add sysfs entry for connector */ + ret = drm_sysfs_connector_add(&connector->base); + if (ret) { + DRM_ERROR("failed to add to sysfs\n"); + goto err_sysfs; + } + + /* connect connector and encoder */ + connector->base.encoder = base_encoder; + ret = drm_mode_connector_attach_encoder(&connector->base, base_encoder); + if (ret) { + DRM_ERROR("failed to attach connector to encoder\n"); + goto err_attach; + } + connector->encoder = base_encoder; + + return &connector->base; + +err_attach: + drm_sysfs_connector_remove(&connector->base); +err_sysfs: + drm_connector_cleanup(&connector->base); + return ERR_PTR(ret); +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_connector.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_connector.h 2014-07-20 22:06:36.185308539 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM connector header for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_DRM_CONNECTOR_H_ +#define _XILINX_DRM_CONNECTOR_H_ + +struct drm_device; +struct drm_connector; + +struct drm_connector * +xilinx_drm_connector_create(struct drm_device *drm, + struct drm_encoder *base_encoder); +void xilinx_drm_connector_destroy(struct drm_connector *base_connector); + +#endif /* _XILINX_DRM_CONNECTOR_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c 2014-07-20 22:06:36.195308374 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM crtc driver for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> + +#include <video/videomode.h> + +#include "xilinx_drm_drv.h" +#include "xilinx_drm_plane.h" + +#include "xilinx_cresample.h" +#include "xilinx_rgb2yuv.h" +#include "xilinx_vtc.h" + +struct xilinx_drm_crtc { + struct drm_crtc base; + struct drm_plane *priv_plane; + struct xilinx_cresample *cresample; + struct xilinx_rgb2yuv *rgb2yuv; + struct clk *pixel_clock; + struct xilinx_vtc *vtc; + struct xilinx_drm_plane_manager *plane_manager; + int dpms; + struct drm_pending_vblank_event *event; +}; + +#define to_xilinx_crtc(x) container_of(x, struct xilinx_drm_crtc, base) + +/* set crtc dpms */ +static void xilinx_drm_crtc_dpms(struct drm_crtc *base_crtc, int dpms) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + + DRM_DEBUG_KMS("dpms: %d -> %d\n", crtc->dpms, dpms); + + if (crtc->dpms == dpms) + return; + + crtc->dpms = dpms; + + switch (dpms) { + case DRM_MODE_DPMS_ON: + xilinx_drm_plane_dpms(crtc->priv_plane, dpms); + if (crtc->rgb2yuv) + xilinx_rgb2yuv_enable(crtc->rgb2yuv); + if (crtc->cresample) + xilinx_cresample_enable(crtc->cresample); + xilinx_vtc_enable(crtc->vtc); + break; + default: + xilinx_vtc_disable(crtc->vtc); + xilinx_vtc_reset(crtc->vtc); + if (crtc->cresample) { + xilinx_cresample_disable(crtc->cresample); + xilinx_cresample_reset(crtc->cresample); + } + if (crtc->rgb2yuv) { + xilinx_rgb2yuv_disable(crtc->rgb2yuv); + xilinx_rgb2yuv_reset(crtc->rgb2yuv); + } + xilinx_drm_plane_dpms(crtc->priv_plane, dpms); + break; + } +} + +/* prepare crtc */ +static void xilinx_drm_crtc_prepare(struct drm_crtc *base_crtc) +{ + xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF); +} + +/* apply mode to crtc pipe */ +static void xilinx_drm_crtc_commit(struct drm_crtc *base_crtc) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + + xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_ON); + xilinx_drm_plane_commit(crtc->priv_plane); +} + +/* fix mode */ +static bool xilinx_drm_crtc_mode_fixup(struct drm_crtc *base_crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* no op */ + return true; +} + +/* set new mode in crtc pipe */ +static int xilinx_drm_crtc_mode_set(struct drm_crtc *base_crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + struct videomode vm; + long diff; + int ret; + + /* set pixel clock */ + ret = clk_set_rate(crtc->pixel_clock, adjusted_mode->clock * 1000); + if (ret) { + DRM_ERROR("failed to set a pixel clock\n"); + return ret; + } + + diff = clk_get_rate(crtc->pixel_clock) - adjusted_mode->clock * 1000; + if (abs(diff) > (adjusted_mode->clock * 1000) / 20) + DRM_INFO("actual pixel clock rate(%d) is off by %ld\n", + adjusted_mode->clock, diff); + + /* set video timing */ + vm.hactive = adjusted_mode->hdisplay; + vm.hfront_porch = adjusted_mode->hsync_start - adjusted_mode->hdisplay; + vm.hback_porch = adjusted_mode->htotal - adjusted_mode->hsync_end; + vm.hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start; + + vm.vactive = adjusted_mode->vdisplay; + vm.vfront_porch = adjusted_mode->vsync_start - adjusted_mode->vdisplay; + vm.vback_porch = adjusted_mode->vtotal - adjusted_mode->vsync_end; + vm.vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start; + + xilinx_vtc_config_sig(crtc->vtc, &vm); + + /* configure cresample and rgb2yuv */ + if (crtc->cresample) + xilinx_cresample_configure(crtc->cresample, + adjusted_mode->hdisplay, + adjusted_mode->vdisplay); + if (crtc->rgb2yuv) + xilinx_rgb2yuv_configure(crtc->rgb2yuv, + adjusted_mode->hdisplay, + adjusted_mode->vdisplay); + + /* configure a plane: vdma and osd layer */ + ret = xilinx_drm_plane_mode_set(crtc->priv_plane, base_crtc, + base_crtc->fb, 0, 0, + adjusted_mode->hdisplay, + adjusted_mode->vdisplay, + x, y, + adjusted_mode->hdisplay, + adjusted_mode->vdisplay); + if (ret) { + DRM_ERROR("failed to mode set a plane\n"); + return ret; + } + + return 0; +} + +static int _xilinx_drm_crtc_mode_set_base(struct drm_crtc *base_crtc, + struct drm_framebuffer *fb, + int x, int y) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + int ret; + + /* configure a plane */ + ret = xilinx_drm_plane_mode_set(crtc->priv_plane, base_crtc, + fb, 0, 0, + base_crtc->hwmode.hdisplay, + base_crtc->hwmode.vdisplay, + x, y, + base_crtc->hwmode.hdisplay, + base_crtc->hwmode.vdisplay); + if (ret) { + DRM_ERROR("failed to mode set a plane\n"); + return ret; + } + + /* apply the new fb addr */ + xilinx_drm_crtc_commit(base_crtc); + + return 0; +} + +/* update address and information from fb */ +static int xilinx_drm_crtc_mode_set_base(struct drm_crtc *base_crtc, + int x, int y, + struct drm_framebuffer *old_fb) +{ + /* configure a plane */ + return _xilinx_drm_crtc_mode_set_base(base_crtc, base_crtc->fb, x, y); +} + +/* load rgb LUT for crtc */ +static void xilinx_drm_crtc_load_lut(struct drm_crtc *base_crtc) +{ + /* no op */ +} + +static struct drm_crtc_helper_funcs xilinx_drm_crtc_helper_funcs = { + .dpms = xilinx_drm_crtc_dpms, + .prepare = xilinx_drm_crtc_prepare, + .commit = xilinx_drm_crtc_commit, + .mode_fixup = xilinx_drm_crtc_mode_fixup, + .mode_set = xilinx_drm_crtc_mode_set, + .mode_set_base = xilinx_drm_crtc_mode_set_base, + .load_lut = xilinx_drm_crtc_load_lut, +}; + +/* destroy crtc */ +void xilinx_drm_crtc_destroy(struct drm_crtc *base_crtc) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + + /* make sure crtc is off */ + xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF); + + drm_crtc_cleanup(base_crtc); + + clk_disable_unprepare(crtc->pixel_clock); + + xilinx_drm_plane_destroy_planes(crtc->plane_manager); + xilinx_drm_plane_destroy_private(crtc->plane_manager, crtc->priv_plane); + xilinx_drm_plane_remove_manager(crtc->plane_manager); +} + +/* cancel page flip functions */ +void xilinx_drm_crtc_cancel_page_flip(struct drm_crtc *base_crtc, + struct drm_file *file) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + struct drm_device *drm = base_crtc->dev; + struct drm_pending_vblank_event *event; + unsigned long flags; + + spin_lock_irqsave(&drm->event_lock, flags); + event = crtc->event; + if (event && (event->base.file_priv == file)) { + crtc->event = NULL; + event->base.destroy(&event->base); + drm_vblank_put(drm, 0); + } + spin_unlock_irqrestore(&drm->event_lock, flags); +} + +/* finish page flip functions */ +static void xilinx_drm_crtc_finish_page_flip(struct drm_crtc *base_crtc) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + struct drm_device *drm = base_crtc->dev; + struct drm_pending_vblank_event *event; + unsigned long flags; + + spin_lock_irqsave(&drm->event_lock, flags); + event = crtc->event; + crtc->event = NULL; + if (event) { + drm_send_vblank_event(drm, 0, event); + drm_vblank_put(drm, 0); + } + spin_unlock_irqrestore(&drm->event_lock, flags); +} + +/* page flip functions */ +static int xilinx_drm_crtc_page_flip(struct drm_crtc *base_crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + struct drm_device *drm = base_crtc->dev; + unsigned long flags; + int ret; + + spin_lock_irqsave(&drm->event_lock, flags); + if (crtc->event != NULL) { + spin_unlock_irqrestore(&drm->event_lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&drm->event_lock, flags); + + /* configure a plane */ + ret = _xilinx_drm_crtc_mode_set_base(base_crtc, fb, + base_crtc->x, base_crtc->y); + if (ret) { + DRM_ERROR("failed to mode set a plane\n"); + return ret; + } + + base_crtc->fb = fb; + + if (event) { + event->pipe = 0; + drm_vblank_get(drm, 0); + spin_lock_irqsave(&drm->event_lock, flags); + crtc->event = event; + spin_unlock_irqrestore(&drm->event_lock, flags); + } + + return 0; +} + +/* vblank interrupt handler */ +static void xilinx_drm_crtc_vblank_handler(void *data) +{ + struct drm_crtc *base_crtc = data; + struct drm_device *drm; + + if (!base_crtc) + return; + + drm = base_crtc->dev; + + drm_handle_vblank(drm, 0); + xilinx_drm_crtc_finish_page_flip(base_crtc); +} + +/* enable vblank interrupt */ +void xilinx_drm_crtc_enable_vblank(struct drm_crtc *base_crtc) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + + xilinx_vtc_enable_vblank_intr(crtc->vtc, xilinx_drm_crtc_vblank_handler, + base_crtc); +} + +/* disable vblank interrupt */ +void xilinx_drm_crtc_disable_vblank(struct drm_crtc *base_crtc) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + + xilinx_vtc_disable_vblank_intr(crtc->vtc); +} + +/* check max width */ +unsigned int xilinx_drm_crtc_get_max_width(struct drm_crtc *base_crtc) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + + return xilinx_drm_plane_get_max_width(crtc->priv_plane); +} + +/* check format */ +bool xilinx_drm_crtc_check_format(struct drm_crtc *base_crtc, uint32_t fourcc) +{ + struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); + + return xilinx_drm_plane_check_format(crtc->plane_manager); +} + +static struct drm_crtc_funcs xilinx_drm_crtc_funcs = { + .destroy = xilinx_drm_crtc_destroy, + .set_config = drm_crtc_helper_set_config, + .page_flip = xilinx_drm_crtc_page_flip, +}; + +/* create crtc */ +struct drm_crtc *xilinx_drm_crtc_create(struct drm_device *drm) +{ + struct xilinx_drm_crtc *crtc; + struct device_node *sub_node; + int possible_crtcs = 1; + int ret; + + crtc = devm_kzalloc(drm->dev, sizeof(*crtc), GFP_KERNEL); + if (!crtc) + return ERR_PTR(-ENOMEM); + + /* probe chroma resampler and enable */ + sub_node = of_parse_phandle(drm->dev->of_node, "cresample", 0); + if (sub_node) { + crtc->cresample = xilinx_cresample_probe(drm->dev, sub_node); + of_node_put(sub_node); + if (IS_ERR(crtc->cresample)) { + DRM_ERROR("failed to probe a cresample\n"); + return ERR_CAST(crtc->cresample); + } + } + + /* probe color space converter and enable */ + sub_node = of_parse_phandle(drm->dev->of_node, "rgb2yuv", 0); + if (sub_node) { + crtc->rgb2yuv = xilinx_rgb2yuv_probe(drm->dev, sub_node); + of_node_put(sub_node); + if (IS_ERR(crtc->rgb2yuv)) { + DRM_ERROR("failed to probe a rgb2yuv\n"); + return ERR_CAST(crtc->rgb2yuv); + } + } + + /* probe a plane manager */ + crtc->plane_manager = xilinx_drm_plane_probe_manager(drm); + if (IS_ERR(crtc->plane_manager)) { + DRM_ERROR("failed to probe a plane manager\n"); + return ERR_CAST(crtc->plane_manager); + } + + /* create a private plane. there's only one crtc now */ + crtc->priv_plane = xilinx_drm_plane_create_private(crtc->plane_manager, + possible_crtcs); + if (IS_ERR(crtc->priv_plane)) { + DRM_ERROR("failed to create a private plane for crtc\n"); + ret = PTR_ERR(crtc->priv_plane); + goto err_plane; + } + + /* create extra planes */ + xilinx_drm_plane_create_planes(crtc->plane_manager, possible_crtcs); + + crtc->pixel_clock = devm_clk_get(drm->dev, 0); + if (IS_ERR(crtc->pixel_clock)) { + DRM_DEBUG_KMS("failed to get pixel clock\n"); + ret = -EPROBE_DEFER; + goto err_out; + } + + ret = clk_prepare_enable(crtc->pixel_clock); + if (ret) { + DRM_DEBUG_KMS("failed to prepare/enable clock\n"); + goto err_out; + } + + sub_node = of_parse_phandle(drm->dev->of_node, "vtc", 0); + if (!sub_node) { + DRM_ERROR("failed to get a video timing controller node\n"); + ret = -ENODEV; + goto err_out; + } + + crtc->vtc = xilinx_vtc_probe(drm->dev, sub_node); + of_node_put(sub_node); + if (IS_ERR(crtc->vtc)) { + DRM_ERROR("failed to probe video timing controller\n"); + ret = PTR_ERR(crtc->vtc); + goto err_out; + } + + crtc->dpms = DRM_MODE_DPMS_OFF; + + /* initialize drm crtc */ + ret = drm_crtc_init(drm, &crtc->base, &xilinx_drm_crtc_funcs); + if (ret) { + DRM_ERROR("failed to initialize crtc\n"); + goto err_out; + } + drm_crtc_helper_add(&crtc->base, &xilinx_drm_crtc_helper_funcs); + + return &crtc->base; + +err_out: + xilinx_drm_plane_destroy_planes(crtc->plane_manager); + xilinx_drm_plane_destroy_private(crtc->plane_manager, crtc->priv_plane); +err_plane: + xilinx_drm_plane_remove_manager(crtc->plane_manager); + return ERR_PTR(ret); +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_crtc.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_crtc.h 2014-07-20 22:06:36.201308275 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM crtc header for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_DRM_CRTC_H_ +#define _XILINX_DRM_CRTC_H_ + +struct drm_device; +struct drm_crtc; + +void xilinx_drm_crtc_enable_vblank(struct drm_crtc *base_crtc); +void xilinx_drm_crtc_disable_vblank(struct drm_crtc *base_crtc); +void xilinx_drm_crtc_cancel_page_flip(struct drm_crtc *base_crtc, + struct drm_file *file); + +unsigned int xilinx_drm_crtc_get_max_width(struct drm_crtc *base_crtc); +bool xilinx_drm_crtc_check_format(struct drm_crtc *base_crtc, uint32_t fourcc); + +struct drm_crtc *xilinx_drm_crtc_create(struct drm_device *drm); +void xilinx_drm_crtc_destroy(struct drm_crtc *base_crtc); + +#endif /* _XILINX_DRM_CRTC_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_drv.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_drv.c 2014-07-20 22:06:36.210308126 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM KMS support for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "xilinx_drm_connector.h" +#include "xilinx_drm_crtc.h" +#include "xilinx_drm_drv.h" +#include "xilinx_drm_encoder.h" + +#define DRIVER_NAME "xilinx_drm" +#define DRIVER_DESC "Xilinx DRM KMS support for Xilinx" +#define DRIVER_DATE "20130509" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +/* + * TODO: The possible pipeline configurations are numerous with Xilinx soft IPs. + * It's not too bad for now, but the more proper way(Common Display Framework, + * or some internal abstraction) should be considered, when it reaches a point + * that such thing is required. + */ + +struct xilinx_drm_private { + struct drm_device *drm; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + struct drm_fbdev_cma *fbdev; + struct platform_device *pdev; +}; + +/** + * struct xilinx_video_format_desc - Xilinx Video IP video format description + * @name: Xilinx video format name + * @xilinx_format: xilinx format code + * @drm_format: drm format code + */ +struct xilinx_video_format_desc { + const char *name; + unsigned int xilinx_format; + uint32_t drm_format; +}; + +static const struct xilinx_video_format_desc xilinx_video_formats[] = { + { "yuv422", XILINX_VIDEO_FORMAT_YUV422, DRM_FORMAT_YUV422 }, + { "yuv444", XILINX_VIDEO_FORMAT_YUV444, DRM_FORMAT_YUV444 }, + { "xrgb888", XILINX_VIDEO_FORMAT_RGB, DRM_FORMAT_XRGB8888 }, + { "yuv420", XILINX_VIDEO_FORMAT_YUV420, DRM_FORMAT_YUV420 }, +}; + +/* create a fb */ +static struct drm_framebuffer * +xilinx_drm_fb_create(struct drm_device *drm, struct drm_file *file_priv, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct xilinx_drm_private *private = drm->dev_private; + bool res; + + res = xilinx_drm_crtc_check_format(private->crtc, + mode_cmd->pixel_format); + if (!res) { + DRM_ERROR("unsupported pixel format %08x\n", + mode_cmd->pixel_format); + return ERR_PTR(-EINVAL); + } + + return drm_fb_cma_create(drm, file_priv, mode_cmd); +} + +/* poll changed handler */ +static void xilinx_drm_output_poll_changed(struct drm_device *drm) +{ + struct xilinx_drm_private *private = drm->dev_private; + + drm_fbdev_cma_hotplug_event(private->fbdev); +} + +static const struct drm_mode_config_funcs xilinx_drm_mode_config_funcs = { + .fb_create = xilinx_drm_fb_create, + .output_poll_changed = xilinx_drm_output_poll_changed, +}; + +/* enable vblank */ +static int xilinx_drm_enable_vblank(struct drm_device *drm, int crtc) +{ + struct xilinx_drm_private *private = drm->dev_private; + + xilinx_drm_crtc_enable_vblank(private->crtc); + + return 0; +} + +/* disable vblank */ +static void xilinx_drm_disable_vblank(struct drm_device *drm, int crtc) +{ + struct xilinx_drm_private *private = drm->dev_private; + + xilinx_drm_crtc_disable_vblank(private->crtc); +} + +/* initialize mode config */ +static void xilinx_drm_mode_config_init(struct drm_device *drm) +{ + struct xilinx_drm_private *private = drm->dev_private; + + drm->mode_config.min_width = 0; + drm->mode_config.min_height = 0; + + drm->mode_config.max_width = + xilinx_drm_crtc_get_max_width(private->crtc); + drm->mode_config.max_height = 4096; + + drm->mode_config.funcs = &xilinx_drm_mode_config_funcs; +} + +/* convert xilinx format to drm format by code */ +int xilinx_drm_format_by_code(unsigned int xilinx_format, uint32_t *drm_format) +{ + const struct xilinx_video_format_desc *format; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) { + format = &xilinx_video_formats[i]; + if (format->xilinx_format == xilinx_format) { + *drm_format = format->drm_format; + return 0; + } + } + + DRM_ERROR("Unknown Xilinx video format: %d\n", xilinx_format); + + return -EINVAL; +} + +/* convert xilinx format to drm format by name */ +int xilinx_drm_format_by_name(const char *name, uint32_t *drm_format) +{ + const struct xilinx_video_format_desc *format; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) { + format = &xilinx_video_formats[i]; + if (strcmp(format->name, name) == 0) { + *drm_format = format->drm_format; + return 0; + } + } + + DRM_ERROR("Unknown Xilinx video format: %s\n", name); + + return -EINVAL; +} + +/* load xilinx drm */ +static int xilinx_drm_load(struct drm_device *drm, unsigned long flags) +{ + struct xilinx_drm_private *private; + struct platform_device *pdev = drm->platformdev; + int ret; + + private = devm_kzalloc(drm->dev, sizeof(*private), GFP_KERNEL); + if (!private) + return -ENOMEM; + + drm_mode_config_init(drm); + + /* create a xilinx crtc */ + private->crtc = xilinx_drm_crtc_create(drm); + if (IS_ERR(private->crtc)) { + DRM_DEBUG_DRIVER("failed to create xilinx crtc\n"); + ret = PTR_ERR(private->crtc); + goto err_crtc; + } + + /* create a xilinx encoder */ + private->encoder = xilinx_drm_encoder_create(drm); + if (IS_ERR(private->encoder)) { + DRM_DEBUG_DRIVER("failed to create xilinx encoder\n"); + ret = PTR_ERR(private->encoder); + goto err_encoder; + } + + /* create a xilinx connector */ + private->connector = xilinx_drm_connector_create(drm, private->encoder); + if (IS_ERR(private->connector)) { + DRM_DEBUG_DRIVER("failed to create xilinx connector\n"); + ret = PTR_ERR(private->connector); + goto err_connector; + } + + ret = drm_vblank_init(drm, 1); + if (ret) { + dev_err(&pdev->dev, "failed to initialize vblank\n"); + goto err_vblank; + } + + /* enable irq to enable vblank feature */ + drm->irq_enabled = 1; + + /* allow disable vblank */ + drm->vblank_disable_allowed = 1; + + /* initialize xilinx cma framebuffer */ + private->fbdev = drm_fbdev_cma_init(drm, 32, 1, 1); + if (IS_ERR(private->fbdev)) { + DRM_ERROR("failed to initialize drm cma fbdev\n"); + ret = PTR_ERR(private->fbdev); + goto err_fbdev; + } + + drm->dev_private = private; + private->drm = drm; + + drm_kms_helper_poll_init(drm); + + /* set up mode config for xilinx */ + xilinx_drm_mode_config_init(drm); + + drm_helper_disable_unused_functions(drm); + + platform_set_drvdata(pdev, private); + + return 0; + +err_fbdev: + drm_vblank_cleanup(drm); +err_vblank: + xilinx_drm_connector_destroy(private->connector); +err_connector: + xilinx_drm_encoder_destroy(private->encoder); +err_encoder: + xilinx_drm_crtc_destroy(private->crtc); +err_crtc: + drm_mode_config_cleanup(drm); + if (ret == -EPROBE_DEFER) + DRM_INFO("load() is defered & will be called again\n"); + return ret; +} + +/* unload xilinx drm */ +static int xilinx_drm_unload(struct drm_device *drm) +{ + struct xilinx_drm_private *private = drm->dev_private; + + drm_vblank_cleanup(drm); + + drm_kms_helper_poll_fini(drm); + + drm_fbdev_cma_fini(private->fbdev); + + drm_mode_config_cleanup(drm); + + return 0; +} + +/* preclose */ +static void xilinx_drm_preclose(struct drm_device *drm, struct drm_file *file) +{ + struct xilinx_drm_private *private = drm->dev_private; + + /* cancel pending page flip request */ + xilinx_drm_crtc_cancel_page_flip(private->crtc, file); +} + +/* restore the default mode when xilinx drm is released */ +static void xilinx_drm_lastclose(struct drm_device *drm) +{ + struct xilinx_drm_private *private = drm->dev_private; + + drm_fbdev_cma_restore_mode(private->fbdev); +} + +static const struct file_operations xilinx_drm_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .mmap = drm_gem_cma_mmap, + .poll = drm_poll, + .read = drm_read, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .llseek = noop_llseek, +}; + +static struct drm_driver xilinx_drm_driver = { + .driver_features = DRIVER_MODESET | DRIVER_GEM | + DRIVER_PRIME, + .load = xilinx_drm_load, + .unload = xilinx_drm_unload, + .preclose = xilinx_drm_preclose, + .lastclose = xilinx_drm_lastclose, + + .get_vblank_counter = drm_vblank_count, + .enable_vblank = xilinx_drm_enable_vblank, + .disable_vblank = xilinx_drm_disable_vblank, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + .gem_free_object = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_dumb_destroy, + + .fops = &xilinx_drm_fops, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, +}; + +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) +/* suspend xilinx drm */ +static int xilinx_drm_pm_suspend(struct device *dev) +{ + struct xilinx_drm_private *private = dev_get_drvdata(dev); + + drm_kms_helper_poll_disable(private->drm); + drm_helper_connector_dpms(private->connector, DRM_MODE_DPMS_SUSPEND); + + return 0; +} + +/* resume xilinx drm */ +static int xilinx_drm_pm_resume(struct device *dev) +{ + struct xilinx_drm_private *private = dev_get_drvdata(dev); + + drm_helper_connector_dpms(private->connector, DRM_MODE_DPMS_ON); + drm_kms_helper_poll_enable(private->drm); + + return 0; +} +#endif + +static const struct dev_pm_ops xilinx_drm_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xilinx_drm_pm_suspend, xilinx_drm_pm_resume) + SET_RUNTIME_PM_OPS(xilinx_drm_pm_suspend, xilinx_drm_pm_resume, NULL) +}; + +/* init xilinx drm platform */ +static int xilinx_drm_platform_probe(struct platform_device *pdev) +{ + return drm_platform_init(&xilinx_drm_driver, pdev); +} + +/* exit xilinx drm platform */ +static int xilinx_drm_platform_remove(struct platform_device *pdev) +{ + drm_platform_exit(&xilinx_drm_driver, pdev); + + return 0; +} + +static const struct of_device_id xilinx_drm_of_match[] = { + { .compatible = "xlnx,drm", }, + { /* end of table */ }, +}; +MODULE_DEVICE_TABLE(of, xilinx_drm_of_match); + +static struct platform_driver xilinx_drm_private_driver = { + .probe = xilinx_drm_platform_probe, + .remove = xilinx_drm_platform_remove, + .driver = { + .owner = THIS_MODULE, + .name = "xilinx-drm", + .pm = &xilinx_drm_pm_ops, + .of_match_table = xilinx_drm_of_match, + }, +}; + +module_platform_driver(xilinx_drm_private_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx DRM KMS Driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_drv.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_drv.h 2014-07-20 22:06:36.216308027 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM KMS Header for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_DRM_H_ +#define _XILINX_DRM_H_ + +enum xilinx_video_format { + XILINX_VIDEO_FORMAT_YUV422 = 0, + XILINX_VIDEO_FORMAT_YUV444 = 1, + XILINX_VIDEO_FORMAT_RGB = 2, + XILINX_VIDEO_FORMAT_YUV420 = 3, +}; + +/* convert the xilinx format to the drm format */ +int xilinx_drm_format_by_code(unsigned int xilinx_format, uint32_t *drm_format); +int xilinx_drm_format_by_name(const char *name, uint32_t *drm_format); + +/* io write operations */ +static inline void xilinx_drm_writel(void __iomem *base, int offset, u32 val) +{ + writel(val, base + offset); +} + +/* io read operations */ +static inline u32 xilinx_drm_readl(void __iomem *base, int offset) +{ + return readl(base + offset); +} + +#endif /* _XILINX_DRM_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_encoder.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_encoder.c 2014-07-20 22:06:36.224307895 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM encoder driver for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_encoder_slave.h> +#include <drm/i2c/adv7511.h> + +#include <linux/hdmi.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "xilinx_drm_drv.h" + +struct xilinx_drm_encoder { + struct drm_encoder_slave slave; + struct i2c_client *i2c_slave; + bool rgb; + int dpms; +}; + +#define to_xilinx_encoder(x) \ + container_of(x, struct xilinx_drm_encoder, slave) + +/* coefficients for adv7511 color space conversion */ +static const uint16_t adv7511_csc_ycbcr_to_rgb[] = { + 0x0734, 0x04ad, 0x0000, 0x1c1b, + 0x1ddc, 0x04ad, 0x1f24, 0x0135, + 0x0000, 0x04ad, 0x087c, 0x1b77, +}; + +/* set encoder dpms */ +static void xilinx_drm_encoder_dpms(struct drm_encoder *base_encoder, int dpms) +{ + struct xilinx_drm_encoder *encoder; + struct drm_encoder_slave *encoder_slave; + struct drm_encoder_slave_funcs *encoder_sfuncs; + + encoder_slave = to_encoder_slave(base_encoder); + encoder_sfuncs = encoder_slave->slave_funcs; + encoder = to_xilinx_encoder(encoder_slave); + + DRM_DEBUG_KMS("dpms: %d -> %d\n", encoder->dpms, dpms); + + if (encoder->dpms == dpms) + return; + + encoder->dpms = dpms; + if (encoder_sfuncs->dpms) + encoder_sfuncs->dpms(base_encoder, dpms); +} + +/* adjust a mode if needed */ +static bool +xilinx_drm_encoder_mode_fixup(struct drm_encoder *base_encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_encoder_slave *encoder_slave; + struct drm_encoder_slave_funcs *encoder_sfuncs = NULL; + bool ret = true; + + encoder_slave = to_encoder_slave(base_encoder); + encoder_sfuncs = encoder_slave->slave_funcs; + if (encoder_sfuncs->mode_fixup) + ret = encoder_sfuncs->mode_fixup(base_encoder, mode, + adjusted_mode); + + return ret; +} + +/* set mode to xilinx encoder */ +static void xilinx_drm_encoder_mode_set(struct drm_encoder *base_encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct xilinx_drm_encoder *encoder; + struct drm_device *dev = base_encoder->dev; + struct drm_encoder_slave *encoder_slave; + struct drm_encoder_slave_funcs *encoder_sfuncs; + struct drm_connector *iter; + struct drm_connector *connector = NULL; + struct adv7511_video_config config; + struct edid *edid; + + DRM_DEBUG_KMS("h: %d, v: %d\n", + adjusted_mode->hdisplay, adjusted_mode->vdisplay); + DRM_DEBUG_KMS("refresh: %d, pclock: %d khz\n", + adjusted_mode->vrefresh, adjusted_mode->clock); + + encoder_slave = to_encoder_slave(base_encoder); + encoder = to_xilinx_encoder(encoder_slave); + + /* search for a connector for this encoder. + * assume there's only one connector for this encoder + */ + list_for_each_entry(iter, &dev->mode_config.connector_list, head) { + if (iter->encoder == base_encoder) { + connector = iter; + break; + } + } + if (!connector) { + DRM_ERROR("failed to find a connector\n"); + return; + } + + edid = adv7511_get_edid(base_encoder); + if (edid) { + config.hdmi_mode = drm_detect_hdmi_monitor(edid); + kfree(edid); + } else + config.hdmi_mode = false; + + hdmi_avi_infoframe_init(&config.avi_infoframe); + + config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN; + + if (encoder->rgb) { + config.csc_enable = false; + config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; + } else { + config.csc_scaling_factor = ADV7511_CSC_SCALING_4; + config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; + + if ((connector->display_info.color_formats & + DRM_COLOR_FORMAT_YCRCB422) && + config.hdmi_mode) { + config.csc_enable = false; + config.avi_infoframe.colorspace = + HDMI_COLORSPACE_YUV422; + } else { + config.csc_enable = true; + config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; + } + } + + encoder_sfuncs = encoder_slave->slave_funcs; + if (encoder_sfuncs->set_config) + encoder_sfuncs->set_config(base_encoder, &config); + + if (encoder_sfuncs->mode_set) + encoder_sfuncs->mode_set(base_encoder, mode, adjusted_mode); +} + +/* apply mode to encoder pipe */ +static void xilinx_drm_encoder_commit(struct drm_encoder *base_encoder) +{ + /* start encoder with new mode */ + xilinx_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_ON); +} + +/* prepare encoder */ +static void xilinx_drm_encoder_prepare(struct drm_encoder *base_encoder) +{ + xilinx_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_OFF); +} + +/* get crtc */ +static struct drm_crtc * +xilinx_drm_encoder_get_crtc(struct drm_encoder *base_encoder) +{ + return base_encoder->crtc; +} + +static struct drm_encoder_helper_funcs xilinx_drm_encoder_helper_funcs = { + .dpms = xilinx_drm_encoder_dpms, + .mode_fixup = xilinx_drm_encoder_mode_fixup, + .mode_set = xilinx_drm_encoder_mode_set, + .prepare = xilinx_drm_encoder_prepare, + .commit = xilinx_drm_encoder_commit, + .get_crtc = xilinx_drm_encoder_get_crtc, +}; + +/* destroy encoder */ +void xilinx_drm_encoder_destroy(struct drm_encoder *base_encoder) +{ + struct xilinx_drm_encoder *encoder; + struct drm_encoder_slave *encoder_slave; + + encoder_slave = to_encoder_slave(base_encoder); + encoder = to_xilinx_encoder(encoder_slave); + + /* make sure encoder is off */ + xilinx_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_OFF); + + drm_encoder_cleanup(base_encoder); + put_device(&encoder->i2c_slave->dev); +} + +static struct drm_encoder_funcs xilinx_drm_encoder_funcs = { + .destroy = xilinx_drm_encoder_destroy, +}; + +/* create encoder */ +struct drm_encoder *xilinx_drm_encoder_create(struct drm_device *drm) +{ + struct xilinx_drm_encoder *encoder; + struct device_node *sub_node; + struct drm_i2c_encoder_driver *i2c_driver; + int ret; + + encoder = devm_kzalloc(drm->dev, sizeof(*encoder), GFP_KERNEL); + if (!encoder) + return ERR_PTR(-ENOMEM); + + encoder->dpms = DRM_MODE_DPMS_OFF; + + /* get slave encoder */ + sub_node = of_parse_phandle(drm->dev->of_node, "encoder-slave", 0); + if (!sub_node) { + DRM_ERROR("failed to get an encoder slave node\n"); + return ERR_PTR(-ENODEV); + } + + encoder->i2c_slave = of_find_i2c_device_by_node(sub_node); + of_node_put(sub_node); + if (!encoder->i2c_slave) { + DRM_DEBUG_KMS("failed to get an encoder slv\n"); + return ERR_PTR(-EPROBE_DEFER); + } + + /* initialize slave encoder */ + i2c_driver = to_drm_i2c_encoder_driver(encoder->i2c_slave->driver); + if (!i2c_driver) { + DRM_ERROR("failed to initialize encoder slave\n"); + ret = -EPROBE_DEFER; + goto err_out; + } + + ret = i2c_driver->encoder_init(encoder->i2c_slave, drm, + &encoder->slave); + if (ret) { + DRM_ERROR("failed to initialize encoder slave\n"); + goto err_out; + } + + if (!encoder->slave.slave_funcs) { + DRM_ERROR("there's no encoder slave function\n"); + ret = -ENODEV; + goto err_out; + } + + encoder->rgb = of_property_read_bool(drm->dev->of_node, "adi,is-rgb"); + + /* initialize encoder */ + encoder->slave.base.possible_crtcs = 1; + ret = drm_encoder_init(drm, &encoder->slave.base, + &xilinx_drm_encoder_funcs, + DRM_MODE_ENCODER_TMDS); + if (ret) { + DRM_ERROR("failed to initialize drm encoder\n"); + goto err_out; + } + + drm_encoder_helper_add(&encoder->slave.base, + &xilinx_drm_encoder_helper_funcs); + + return &encoder->slave.base; + +err_out: + put_device(&encoder->i2c_slave->dev); + return ERR_PTR(ret); +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_encoder.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_encoder.h 2014-07-20 22:06:36.230307796 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM encoder header for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_DRM_ENCODER_H_ +#define _XILINX_DRM_ENCODER_H_ + +struct drm_device; +struct drm_encoder; + +struct drm_encoder *xilinx_drm_encoder_create(struct drm_device *drm); +void xilinx_drm_encoder_destroy(struct drm_encoder *base_encoder); + +#endif /* _XILINX_DRM_ENCODER_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_plane.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_plane.c 2014-07-20 22:06:36.241307615 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM plane driver for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> + +#include <linux/amba/xilinx_dma.h> +#include <linux/device.h> +#include <linux/dmaengine.h> +#include <linux/of_dma.h> +#include <linux/platform_device.h> + +#include "xilinx_drm_drv.h" + +#include "xilinx_cresample.h" +#include "xilinx_osd.h" +#include "xilinx_rgb2yuv.h" + +/** + * struct xilinx_drm_plane_vdma: Xilinx drm plane VDMA object + * + * @chan: dma channel + * @dma_config: vdma config + */ +struct xilinx_drm_plane_vdma { + struct dma_chan *chan; + struct xilinx_vdma_config dma_config; +}; + +/** + * struct xilinx_drm_plane: Xilinx drm plane object + * + * @base: base drm plane object + * @id: plane id + * @dpms: current dpms level + * @priv: flag for private plane + * @x: x position + * @y: y position + * @paddr: physical address of current plane buffer + * @bpp: bytes per pixel + * @format: pixel format + * @vdma: vdma object + * @rgb2yuv: rgb2yuv instance + * @cresample: cresample instance + * @osd_layer: osd layer + * @manager: plane manager + */ +struct xilinx_drm_plane { + struct drm_plane base; + int id; + int dpms; + bool priv; + uint32_t x; + uint32_t y; + dma_addr_t paddr; + int bpp; + uint32_t format; + struct xilinx_drm_plane_vdma vdma; + struct xilinx_rgb2yuv *rgb2yuv; + struct xilinx_cresample *cresample; + struct xilinx_osd_layer *osd_layer; + struct xilinx_drm_plane_manager *manager; +}; + +#define MAX_PLANES 8 + +/** + * struct xilinx_drm_plane_manager: Xilinx drm plane manager object + * + * @drm: drm device + * @node: plane device node + * @osd: osd instance + * @num_planes: number of available planes + * @format: video format + * @max_width: maximum width + * @planes: xilinx drm planes + */ +struct xilinx_drm_plane_manager { + struct drm_device *drm; + struct device_node *node; + struct xilinx_osd *osd; + int num_planes; + uint32_t format; + int max_width; + struct xilinx_drm_plane *planes[MAX_PLANES]; +}; + +#define to_xilinx_plane(x) container_of(x, struct xilinx_drm_plane, base) + +/* set plane dpms */ +void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms) +{ + struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane); + struct xilinx_drm_plane_manager *manager = plane->manager; + struct xilinx_vdma_config dma_config; + + DRM_DEBUG_KMS("plane->id: %d\n", plane->id); + DRM_DEBUG_KMS("dpms: %d -> %d\n", plane->dpms, dpms); + + if (plane->dpms == dpms) + return; + + plane->dpms = dpms; + switch (dpms) { + case DRM_MODE_DPMS_ON: + /* start vdma engine */ + dma_async_issue_pending(plane->vdma.chan); + + if (plane->rgb2yuv) + xilinx_rgb2yuv_enable(plane->rgb2yuv); + + if (plane->cresample) + xilinx_cresample_enable(plane->cresample); + + /* enable osd */ + if (manager->osd) { + xilinx_osd_disable_rue(manager->osd); + + /* set zorder(= id for now) */ + xilinx_osd_layer_set_priority(plane->osd_layer, + plane->id); + /* FIXME: use global alpha for now */ + xilinx_osd_layer_set_alpha(plane->osd_layer, 1, 0xff); + xilinx_osd_layer_enable(plane->osd_layer); + if (plane->priv) { + /* set background color as black */ + xilinx_osd_set_color(manager->osd, 0x0, 0x0, + 0x0); + xilinx_osd_enable(manager->osd); + } + + xilinx_osd_enable_rue(manager->osd); + } + + break; + default: + /* disable/reset osd */ + if (manager->osd) { + xilinx_osd_disable_rue(manager->osd); + + xilinx_osd_layer_set_dimension(plane->osd_layer, + 0, 0, 0, 0); + xilinx_osd_layer_disable(plane->osd_layer); + if (plane->priv) + xilinx_osd_reset(manager->osd); + + xilinx_osd_enable_rue(manager->osd); + } + + if (plane->cresample) { + xilinx_cresample_disable(plane->cresample); + xilinx_cresample_reset(plane->cresample); + } + + if (plane->rgb2yuv) { + xilinx_rgb2yuv_disable(plane->rgb2yuv); + xilinx_rgb2yuv_reset(plane->rgb2yuv); + } + + /* reset vdma */ + dma_config.reset = 1; + dmaengine_device_control(plane->vdma.chan, DMA_SLAVE_CONFIG, + (unsigned long)&dma_config); + + /* stop vdma engine and release descriptors */ + dmaengine_terminate_all(plane->vdma.chan); + break; + } +} + +/* apply mode to plane pipe */ +void xilinx_drm_plane_commit(struct drm_plane *base_plane) +{ + struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane); + struct dma_async_tx_descriptor *desc; + uint32_t height = plane->vdma.dma_config.hsize; + int pitch = plane->vdma.dma_config.stride; + size_t offset; + + DRM_DEBUG_KMS("plane->id: %d\n", plane->id); + + offset = plane->x * plane->bpp + plane->y * pitch; + desc = dmaengine_prep_slave_single(plane->vdma.chan, + plane->paddr + offset, + height * pitch, DMA_MEM_TO_DEV, 0); + if (!desc) { + DRM_ERROR("failed to prepare DMA descriptor\n"); + return; + } + + /* submit vdma desc */ + dmaengine_submit(desc); + + /* start vdma with new mode */ + dma_async_issue_pending(plane->vdma.chan); +} + +/* mode set a plane */ +int xilinx_drm_plane_mode_set(struct drm_plane *base_plane, + struct drm_crtc *crtc, struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane); + struct drm_gem_cma_object *obj; + + DRM_DEBUG_KMS("plane->id: %d\n", plane->id); + + if (fb->pixel_format != plane->format) { + DRM_ERROR("unsupported pixel format %08x\n", fb->pixel_format); + return -EINVAL; + } + + /* configure cresample */ + if (plane->cresample) + xilinx_cresample_configure(plane->cresample, crtc_w, crtc_h); + + /* configure rgb2yuv */ + if (plane->rgb2yuv) + xilinx_rgb2yuv_configure(plane->rgb2yuv, crtc_w, crtc_h); + + obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!obj) { + DRM_ERROR("failed to get a gem obj for fb\n"); + return -EINVAL; + } + + plane->x = src_x; + plane->y = src_y; + plane->bpp = fb->bits_per_pixel / 8; + plane->paddr = obj->paddr; + + DRM_DEBUG_KMS("h: %d(%d), v: %d(%d), paddr: %p\n", + src_w, crtc_x, src_h, crtc_y, (void *)obj->paddr); + DRM_DEBUG_KMS("bpp: %d\n", plane->bpp); + + /* configure vdma desc */ + plane->vdma.dma_config.hsize = src_w * plane->bpp; + plane->vdma.dma_config.vsize = src_h; + plane->vdma.dma_config.stride = fb->pitches[0]; + plane->vdma.dma_config.park = 1; + plane->vdma.dma_config.park_frm = 0; + + dmaengine_device_control(plane->vdma.chan, DMA_SLAVE_CONFIG, + (unsigned long)&plane->vdma.dma_config); + + /* set OSD dimensions */ + if (plane->manager->osd) { + xilinx_osd_disable_rue(plane->manager->osd); + + /* if a plane is private, it's for crtc */ + if (plane->priv) + xilinx_osd_set_dimension(plane->manager->osd, + crtc_w, crtc_h); + + xilinx_osd_layer_set_dimension(plane->osd_layer, crtc_x, crtc_y, + src_w, src_h); + + xilinx_osd_enable_rue(plane->manager->osd); + } + + return 0; +} + +/* update a plane. just call mode_set() with bit-shifted values */ +static int xilinx_drm_plane_update(struct drm_plane *base_plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + int ret; + + ret = xilinx_drm_plane_mode_set(base_plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x >> 16, src_y >> 16, + src_w >> 16, src_h >> 16); + if (ret) { + DRM_ERROR("failed to mode-set a plane\n"); + return ret; + } + + /* make sure a plane is on */ + xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_ON); + /* apply the new fb addr */ + xilinx_drm_plane_commit(base_plane); + + return 0; +} + +/* disable a plane */ +static int xilinx_drm_plane_disable(struct drm_plane *base_plane) +{ + xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF); + + return 0; +} + +/* destroy a plane */ +static void xilinx_drm_plane_destroy(struct drm_plane *base_plane) +{ + struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane); + + xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF); + + plane->manager->planes[plane->id] = NULL; + + drm_plane_cleanup(base_plane); + + dma_release_channel(plane->vdma.chan); + + if (plane->manager->osd) { + xilinx_osd_layer_disable(plane->osd_layer); + xilinx_osd_layer_put(plane->osd_layer); + } +} + +/* set property of a plane */ +static int xilinx_drm_plane_set_property(struct drm_plane *base_plane, + struct drm_property *property, + uint64_t val) +{ + /* TODO: set zorder, etc */ + return -EINVAL; +} + +static struct drm_plane_funcs xilinx_drm_plane_funcs = { + .update_plane = xilinx_drm_plane_update, + .disable_plane = xilinx_drm_plane_disable, + .destroy = xilinx_drm_plane_destroy, + .set_property = xilinx_drm_plane_set_property, +}; + +/* get a plane max width */ +int xilinx_drm_plane_get_max_width(struct drm_plane *base_plane) +{ + struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane); + + return plane->manager->max_width; +} + +/* check if format is supported */ +bool xilinx_drm_plane_check_format(struct xilinx_drm_plane_manager *manager, + uint32_t format) +{ + int i; + + for (i = 0; i < MAX_PLANES; i++) + if (manager->planes[i] && + (manager->planes[i]->format == format)) + return true; + + return false; +} + +/* create a plane */ +static struct xilinx_drm_plane * +xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager, + unsigned int possible_crtcs, bool priv) +{ + struct xilinx_drm_plane *plane; + struct device *dev = manager->drm->dev; + char plane_name[16]; + struct device_node *plane_node; + struct device_node *sub_node; + uint32_t fmt_in = -1; + uint32_t fmt_out = -1; + const char *fmt; + int i; + int ret; + + for (i = 0; i < manager->num_planes; i++) + if (!manager->planes[i]) + break; + + if (i >= manager->num_planes) { + DRM_ERROR("failed to allocate plane\n"); + return ERR_PTR(-ENODEV); + } + + snprintf(plane_name, sizeof(plane_name), "plane%d", i); + plane_node = of_get_child_by_name(manager->node, plane_name); + if (!plane_node) { + DRM_ERROR("failed to find a plane node\n"); + return ERR_PTR(-ENODEV); + } + + plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); + if (!plane) { + ret = -ENOMEM; + goto err_out; + } + + plane->priv = priv; + plane->id = i; + plane->dpms = DRM_MODE_DPMS_OFF; + plane->format = -1; + DRM_DEBUG_KMS("plane->id: %d\n", plane->id); + + plane->vdma.chan = of_dma_request_slave_channel(plane_node, "vdma"); + if (!plane->vdma.chan) { + DRM_ERROR("failed to request dma channel\n"); + ret = -ENODEV; + goto err_out; + } + + /* probe color space converter */ + sub_node = of_parse_phandle(plane_node, "rgb2yuv", i); + if (sub_node) { + plane->rgb2yuv = xilinx_rgb2yuv_probe(dev, sub_node); + of_node_put(sub_node); + if (IS_ERR(plane->rgb2yuv)) { + DRM_ERROR("failed to probe a rgb2yuv\n"); + ret = PTR_ERR(plane->rgb2yuv); + goto err_dma; + } + + /* rgb2yuv input format */ + plane->format = DRM_FORMAT_XRGB8888; + + /* rgb2yuv output format */ + fmt_out = DRM_FORMAT_YUV444; + } + + /* probe chroma resampler */ + sub_node = of_parse_phandle(plane_node, "cresample", i); + if (sub_node) { + plane->cresample = xilinx_cresample_probe(dev, sub_node); + of_node_put(sub_node); + if (IS_ERR(plane->cresample)) { + DRM_ERROR("failed to probe a cresample\n"); + ret = PTR_ERR(plane->cresample); + goto err_dma; + } + + /* cresample input format */ + fmt = xilinx_cresample_get_input_format_name(plane->cresample); + ret = xilinx_drm_format_by_name(fmt, &fmt_in); + if (ret) + goto err_dma; + + /* format sanity check */ + if ((fmt_out != -1) && (fmt_out != fmt_in)) { + DRM_ERROR("input/output format mismatch\n"); + ret = -EINVAL; + goto err_dma; + } + + if (plane->format == -1) + plane->format = fmt_in; + + /* cresample output format */ + fmt = xilinx_cresample_get_output_format_name(plane->cresample); + ret = xilinx_drm_format_by_name(fmt, &fmt_out); + if (ret) + goto err_dma; + } + + /* create an OSD layer when OSD is available */ + if (manager->osd) { + /* format sanity check */ + if ((fmt_out != -1) && (fmt_out != manager->format)) { + DRM_ERROR("input/output format mismatch\n"); + ret = -EINVAL; + goto err_dma; + } + + /* create an osd layer */ + plane->osd_layer = xilinx_osd_layer_get(manager->osd); + if (IS_ERR(plane->osd_layer)) { + DRM_ERROR("failed to create a osd layer\n"); + ret = PTR_ERR(plane->osd_layer); + plane->osd_layer = NULL; + goto err_dma; + } + + if (plane->format == -1) + plane->format = manager->format; + } + + /* If there's no IP other than VDMA, choose XRGB8888 */ + if (plane->format == -1) + plane->format = DRM_FORMAT_XRGB8888; + + /* initialize drm plane */ + ret = drm_plane_init(manager->drm, &plane->base, possible_crtcs, + &xilinx_drm_plane_funcs, &plane->format, 1, priv); + if (ret) { + DRM_ERROR("failed to initialize plane\n"); + goto err_init; + } + plane->manager = manager; + manager->planes[i] = plane; + + of_node_put(plane_node); + + return plane; + +err_init: + if (manager->osd) { + xilinx_osd_layer_disable(plane->osd_layer); + xilinx_osd_layer_put(plane->osd_layer); + } +err_dma: + dma_release_channel(plane->vdma.chan); +err_out: + of_node_put(plane_node); + return ERR_PTR(ret); +} + +/* create a private plane */ +struct drm_plane * +xilinx_drm_plane_create_private(struct xilinx_drm_plane_manager *manager, + unsigned int possible_crtcs) +{ + struct xilinx_drm_plane *plane; + + plane = xilinx_drm_plane_create(manager, possible_crtcs, true); + if (IS_ERR(plane)) { + DRM_ERROR("failed to allocate a private plane\n"); + return ERR_CAST(plane); + } + + return &plane->base; +} + +void xilinx_drm_plane_destroy_private(struct xilinx_drm_plane_manager *manager, + struct drm_plane *base_plane) +{ + xilinx_drm_plane_destroy(base_plane); +} + +/* destroy planes */ +void xilinx_drm_plane_destroy_planes(struct xilinx_drm_plane_manager *manager) +{ + struct xilinx_drm_plane *plane; + int i; + + for (i = 0; i < manager->num_planes; i++) { + plane = manager->planes[i]; + if (plane && !plane->priv) { + xilinx_drm_plane_destroy(&plane->base); + manager->planes[i] = NULL; + } + } +} + +/* create extra planes */ +int xilinx_drm_plane_create_planes(struct xilinx_drm_plane_manager *manager, + unsigned int possible_crtcs) +{ + int i; + int err_ret; + + /* find if there any available plane, and create if available */ + for (i = 0; i < manager->num_planes; i++) { + if (manager->planes[i]) + continue; + manager->planes[i] = xilinx_drm_plane_create(manager, + possible_crtcs, + false); + if (IS_ERR(manager->planes[i])) { + DRM_ERROR("failed to allocate a plane\n"); + err_ret = PTR_ERR(manager->planes[i]); + manager->planes[i] = NULL; + goto err_out; + } + } + + return 0; + +err_out: + xilinx_drm_plane_destroy_planes(manager); + return err_ret; +} + +/* initialize a plane manager: num_planes, format, max_width */ +static int +xilinx_drm_plane_init_manager(struct xilinx_drm_plane_manager *manager) +{ + unsigned int format; + int ret = 0; + + if (manager->osd) { + manager->num_planes = xilinx_osd_get_num_layers(manager->osd); + manager->max_width = xilinx_osd_get_max_width(manager->osd); + + format = xilinx_osd_get_format(manager->osd); + ret = xilinx_drm_format_by_code(format, &manager->format); + } else { + /* without osd, only one plane is supported */ + manager->num_planes = 1; + /* XRGB based on the current pipeline design without osd */ + manager->format = DRM_FORMAT_XRGB8888; + manager->max_width = 4096; + } + + return ret; +} + +struct xilinx_drm_plane_manager * +xilinx_drm_plane_probe_manager(struct drm_device *drm) +{ + struct xilinx_drm_plane_manager *manager; + struct device *dev = drm->dev; + struct device_node *sub_node; + int ret; + + manager = devm_kzalloc(dev, sizeof(*manager), GFP_KERNEL); + if (!manager) + return ERR_PTR(-ENOMEM); + + /* this node is used to create a plane */ + manager->node = of_get_child_by_name(dev->of_node, "planes"); + if (!manager->node) { + DRM_ERROR("failed to get a planes node\n"); + return ERR_PTR(-EINVAL); + } + + manager->drm = drm; + + /* probe an OSD. proceed even if there's no OSD */ + sub_node = of_parse_phandle(dev->of_node, "osd", 0); + if (sub_node) { + manager->osd = xilinx_osd_probe(dev, sub_node); + of_node_put(sub_node); + if (IS_ERR(manager->osd)) { + of_node_put(manager->node); + DRM_ERROR("failed to probe an osd\n"); + return ERR_CAST(manager->osd); + } + } + + ret = xilinx_drm_plane_init_manager(manager); + if (ret) { + DRM_ERROR("failed to init a plane manager\n"); + return ERR_PTR(ret); + } + + return manager; +} + +void xilinx_drm_plane_remove_manager(struct xilinx_drm_plane_manager *manager) +{ + int i; + + for (i = 0; i < manager->num_planes; i++) { + if (manager->planes[i] && !manager->planes[i]->priv) { + xilinx_drm_plane_dpms(&manager->planes[i]->base, + DRM_MODE_DPMS_OFF); + xilinx_drm_plane_destroy(&manager->planes[i]->base); + manager->planes[i] = NULL; + } + } + + of_node_put(manager->node); +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_plane.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_drm_plane.h 2014-07-20 22:06:36.248307499 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DRM plane header for Xilinx + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_DRM_PLANE_H_ +#define _XILINX_DRM_PLANE_H_ + +struct drm_crtc; +struct drm_plane; + +/* plane operations */ +void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms); +void xilinx_drm_plane_commit(struct drm_plane *base_plane); +int xilinx_drm_plane_mode_set(struct drm_plane *base_plane, + struct drm_crtc *crtc, struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h); +int xilinx_drm_plane_get_max_width(struct drm_plane *base_plane); + +/* plane manager operations */ +struct xilinx_drm_plane_manager; + +struct drm_plane * +xilinx_drm_plane_create_private(struct xilinx_drm_plane_manager *manager, + unsigned int possible_crtcs); +void xilinx_drm_plane_destroy_private(struct xilinx_drm_plane_manager *manager, + struct drm_plane *base_plane); +int xilinx_drm_plane_create_planes(struct xilinx_drm_plane_manager *manager, + unsigned int possible_crtcs); +void xilinx_drm_plane_destroy_planes(struct xilinx_drm_plane_manager *manager); + +bool xilinx_drm_plane_check_format(struct xilinx_drm_plane_manager *manager); + +struct xilinx_drm_plane_manager * +xilinx_drm_plane_probe_manager(struct drm_device *drm); +void xilinx_drm_plane_remove_manager(struct xilinx_drm_plane_manager *manager); + +#endif /* _XILINX_DRM_PLANE_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_osd.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_osd.c 2014-07-20 22:06:36.256307367 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx OSD support + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <drm/drmP.h> + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> + +#include "xilinx_drm_drv.h" + +/* registers */ +#define OSD_CTL 0x000 /* control */ +#define OSD_SS 0x020 /* screen size */ +#define OSD_ENC 0x028 /* encoding register */ +#define OSD_BC0 0x100 /* background color channel 0 */ +#define OSD_BC1 0x104 /* background color channel 1 */ +#define OSD_BC2 0x108 /* background color channel 2 */ + +#define OSD_L0C 0x110 /* layer 0 control */ + +/* register offset of layers */ +#define OSD_LAYER_SIZE 0x10 +#define OSD_LXC 0x00 /* layer control */ +#define OSD_LXP 0x04 /* layer position */ +#define OSD_LXS 0x08 /* layer size */ + +/*osd control register bit definition */ +#define OSD_CTL_RUE (1 << 1) /* osd reg update enable */ +#define OSD_CTL_EN (1 << 0) /* osd enable */ + +/* osd screen size register bit definition */ +#define OSD_SS_YSIZE_MASK 0x0fff0000 /* vertical height of OSD output */ +#define OSD_SS_YSIZE_SHIFT 16 /* bit shift of OSD_SS_YSIZE_MASK */ +#define OSD_SS_XSIZE_MASK 0x00000fff /* horizontal width of OSD output */ + +/* osd vidoe format mask */ +#define OSD_VIDEO_FORMAT_MASK 0x0000000f /* video format */ + +/* osd background color channel 0 */ +#define OSD_BC0_YG_MASK 0x000000ff /* Y (luma) or Green */ + +/* osd background color channel 1 */ +#define OSD_BC1_UCBB_MASK 0x000000ff /* U (Cb) or Blue */ + +/* osd background color channel 2 */ +#define OSD_BC2_VCRR_MASK 0x000000ff /* V(Cr) or Red */ + +/* maximum number of the layers */ +#define OSD_MAX_NUM_OF_LAYERS 8 + +/* osd layer control (layer 0 through (OSD_MAX_NUM_OF_LAYERS - 1)) */ +#define OSD_LXC_ALPHA_MASK 0x0fff0000 /* global alpha value */ +#define OSD_LXC_ALPHA_SHIFT 16 /* bit shift of alpha value */ +#define OSD_LXC_PRIORITY_MASK 0x00000700 /* layer priority */ +#define OSD_LXC_PRIORITY_SHIFT 8 /* bit shift of priority */ +#define OSD_LXC_GALPHAEN (1 << 1) /* global alpha enable */ +#define OSD_LXC_EN (1 << 0) /* layer enable */ + +/* osd layer position (layer 0 through (OSD_MAX_NUM_OF_LAYERS - 1)) */ +#define OSD_LXP_YSTART_MASK 0x0fff0000 /* vert start line */ +#define OSD_LXP_YSTART_SHIFT 16 /* vert start line bit shift */ +#define OSD_LXP_XSTART_MASK 0x00000fff /* horizontal start pixel */ + +/* osd layer size (layer 0 through (OSD_MAX_NUM_OF_LAYERS - 1)) */ +#define OSD_LXS_YSIZE_MASK 0x0fff0000 /* vert size */ +#define OSD_LXS_YSIZE_SHIFT 16 /* vertical size bit shift */ +#define OSD_LXS_XSIZE_MASK 0x00000fff /* horizontal size of layer */ + +/* osd software reset */ +#define OSD_RST_RESET (1 << 31) + +/** + * struct xilinx_osd_layer: Xilinx OSD layer object + * + * @base: base address + * @id: id + * @avail: available flag + * @osd: osd + */ +struct xilinx_osd_layer { + void __iomem *base; + int id; + bool avail; + struct xilinx_osd *osd; +}; + +/** + * struct xilinx_osd: Xilinx OSD object + * + * @base: base address + * @layers: layers + * @num_layers: number of layers + * @max_width: maximum width + * @format: video format + */ +struct xilinx_osd { + void __iomem *base; + struct xilinx_osd_layer *layers[OSD_MAX_NUM_OF_LAYERS]; + unsigned int num_layers; + unsigned int max_width; + unsigned int format; +}; + +/* osd layer operation */ +/* set layer alpha */ +void xilinx_osd_layer_set_alpha(struct xilinx_osd_layer *layer, u32 enable, + u32 alpha) +{ + u32 value; + + DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id); + DRM_DEBUG_DRIVER("alpha: 0x%08x\n", alpha); + + value = xilinx_drm_readl(layer->base, OSD_LXC); + value = enable ? (value | OSD_LXC_GALPHAEN) : + (value & ~OSD_LXC_GALPHAEN); + value &= ~OSD_LXC_ALPHA_MASK; + value |= (alpha << OSD_LXC_ALPHA_SHIFT) & OSD_LXC_ALPHA_MASK; + xilinx_drm_writel(layer->base, OSD_LXC, value); +} + +/* set layer priority */ +void xilinx_osd_layer_set_priority(struct xilinx_osd_layer *layer, u32 prio) +{ + u32 value; + + DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id); + DRM_DEBUG_DRIVER("prio: %d\n", prio); + + value = xilinx_drm_readl(layer->base, OSD_LXC); + value &= ~OSD_LXC_PRIORITY_MASK; + value |= (prio << OSD_LXC_PRIORITY_SHIFT) & OSD_LXC_PRIORITY_MASK; + xilinx_drm_writel(layer->base, OSD_LXC, value); +} + +/* set layer dimension */ +void xilinx_osd_layer_set_dimension(struct xilinx_osd_layer *layer, + u16 xstart, u16 ystart, + u16 xsize, u16 ysize) +{ + u32 value; + + DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id); + DRM_DEBUG_DRIVER("w: %d(%d), h: %d(%d)\n", + xsize, xstart, ysize, ystart); + + value = xstart & OSD_LXP_XSTART_MASK; + value |= (ystart << OSD_LXP_YSTART_SHIFT) & OSD_LXP_YSTART_MASK; + + xilinx_drm_writel(layer->base, OSD_LXP, value); + + value = xsize & OSD_LXS_XSIZE_MASK; + value |= (ysize << OSD_LXS_YSIZE_SHIFT) & OSD_LXS_YSIZE_MASK; + + xilinx_drm_writel(layer->base, OSD_LXS, value); +} + +/* enable layer */ +void xilinx_osd_layer_enable(struct xilinx_osd_layer *layer) +{ + u32 value; + + DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id); + + value = xilinx_drm_readl(layer->base, OSD_LXC); + value |= OSD_LXC_EN; + xilinx_drm_writel(layer->base, OSD_LXC, value); +} + +/* disable layer */ +void xilinx_osd_layer_disable(struct xilinx_osd_layer *layer) +{ + u32 value; + + DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id); + + value = xilinx_drm_readl(layer->base, OSD_LXC); + value &= ~OSD_LXC_EN; + xilinx_drm_writel(layer->base, OSD_LXC, value); +} + +/* get an available layer */ +struct xilinx_osd_layer *xilinx_osd_layer_get(struct xilinx_osd *osd) +{ + struct xilinx_osd_layer *layer = NULL; + int i; + + for (i = 0; i < osd->num_layers; i++) { + if (osd->layers[i]->avail) { + layer = osd->layers[i]; + layer->avail = false; + break; + } + } + + if (!layer) + return ERR_PTR(-ENODEV); + + DRM_DEBUG_DRIVER("layer id: %d\n", i); + + return layer; +} + +/* put a layer */ +void xilinx_osd_layer_put(struct xilinx_osd_layer *layer) +{ + layer->avail = true; +} + +/* osd operations */ +/* set osd color */ +void xilinx_osd_set_color(struct xilinx_osd *osd, u8 r, u8 g, u8 b) +{ + u32 value; + + value = g; + xilinx_drm_writel(osd->base, OSD_BC0, value); + value = b; + xilinx_drm_writel(osd->base, OSD_BC1, value); + value = r; + xilinx_drm_writel(osd->base, OSD_BC2, value); +} + +/* set osd dimension */ +void xilinx_osd_set_dimension(struct xilinx_osd *osd, u32 width, u32 height) +{ + u32 value; + + DRM_DEBUG_DRIVER("w: %d, h: %d\n", width, height); + + value = width | ((height << OSD_SS_YSIZE_SHIFT) & OSD_SS_YSIZE_MASK); + xilinx_drm_writel(osd->base, OSD_SS, value); +} + +/* get osd number of layers */ +unsigned int xilinx_osd_get_num_layers(struct xilinx_osd *osd) +{ + return osd->num_layers; +} + +/* get osd max width */ +unsigned int xilinx_osd_get_max_width(struct xilinx_osd *osd) +{ + return osd->max_width; +} + +/* get osd color format */ +unsigned int xilinx_osd_get_format(struct xilinx_osd *osd) +{ + return osd->format; +} + +/* reset osd */ +void xilinx_osd_reset(struct xilinx_osd *osd) +{ + xilinx_drm_writel(osd->base, OSD_CTL, OSD_RST_RESET); +} + +/* enable osd */ +void xilinx_osd_enable(struct xilinx_osd *osd) +{ + xilinx_drm_writel(osd->base, OSD_CTL, + xilinx_drm_readl(osd->base, OSD_CTL) | OSD_CTL_EN); +} + +/* disable osd */ +void xilinx_osd_disable(struct xilinx_osd *osd) +{ + xilinx_drm_writel(osd->base, OSD_CTL, + xilinx_drm_readl(osd->base, OSD_CTL) & ~OSD_CTL_EN); +} + +/* register-update-enable osd */ +void xilinx_osd_enable_rue(struct xilinx_osd *osd) +{ + xilinx_drm_writel(osd->base, OSD_CTL, + xilinx_drm_readl(osd->base, OSD_CTL) | OSD_CTL_RUE); +} + +/* register-update-enable osd */ +void xilinx_osd_disable_rue(struct xilinx_osd *osd) +{ + xilinx_drm_writel(osd->base, OSD_CTL, + xilinx_drm_readl(osd->base, OSD_CTL) & ~OSD_CTL_RUE); +} + +struct xilinx_osd *xilinx_osd_probe(struct device *dev, + struct device_node *node) +{ + struct xilinx_osd *osd; + struct xilinx_osd_layer *layer; + struct resource res; + int i; + int ret; + + osd = devm_kzalloc(dev, sizeof(*osd), GFP_KERNEL); + if (!osd) + return ERR_PTR(-ENOMEM); + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + dev_err(dev, "failed to of_address_to_resource\n"); + return ERR_PTR(ret); + } + + osd->base = devm_ioremap_resource(dev, &res); + if (IS_ERR(osd->base)) + return ERR_CAST(osd->base); + + ret = of_property_read_u32(node, "xlnx,num-layers", &osd->num_layers); + if (ret) { + dev_warn(dev, "failed to get num of layers prop\n"); + return ERR_PTR(ret); + } + + ret = of_property_read_u32(node, "xlnx,screen-width", &osd->max_width); + if (ret) { + dev_warn(dev, "failed to get screen width prop\n"); + return ERR_PTR(ret); + } + + /* read the video format set by a user */ + osd->format = xilinx_drm_readl(osd->base, OSD_ENC) & + OSD_VIDEO_FORMAT_MASK; + + for (i = 0; i < osd->num_layers; i++) { + layer = devm_kzalloc(dev, sizeof(*layer), GFP_KERNEL); + if (!layer) + return ERR_PTR(-ENOMEM); + + layer->base = osd->base + OSD_L0C + OSD_LAYER_SIZE * i; + layer->id = i; + layer->osd = osd; + layer->avail = true; + osd->layers[i] = layer; + } + + return osd; +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_osd.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_osd.h 2014-07-20 22:06:36.263307252 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx OSD Header for Xilinx DRM KMS + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_OSD_H_ +#define _XILINX_OSD_H_ + +struct xilinx_osd; +struct xilinx_osd_layer; + +/* osd layer configuration */ +void xilinx_osd_layer_set_alpha(struct xilinx_osd_layer *layer, u32 enable, + u32 alpha); +void xilinx_osd_layer_set_priority(struct xilinx_osd_layer *layer, u32 prio); +void xilinx_osd_layer_set_dimension(struct xilinx_osd_layer *layer, + u16 xstart, u16 ystart, + u16 xsize, u16 ysize); + +/* osd layer operation */ +void xilinx_osd_layer_enable(struct xilinx_osd_layer *layer); +void xilinx_osd_layer_disable(struct xilinx_osd_layer *layer); +struct xilinx_osd_layer *xilinx_osd_layer_get(struct xilinx_osd *osd); +void xilinx_osd_layer_put(struct xilinx_osd_layer *layer); + +/* osd configuration */ +void xilinx_osd_set_color(struct xilinx_osd *osd, u8 r, u8 g, u8 b); +void xilinx_osd_set_dimension(struct xilinx_osd *osd, u32 width, u32 height); + +unsigned int xilinx_osd_get_num_layers(struct xilinx_osd *osd); +unsigned int xilinx_osd_get_max_width(struct xilinx_osd *osd); +unsigned int xilinx_osd_get_format(struct xilinx_osd *osd); + +/* osd operation */ +void xilinx_osd_reset(struct xilinx_osd *osd); +void xilinx_osd_enable(struct xilinx_osd *osd); +void xilinx_osd_disable(struct xilinx_osd *osd); +void xilinx_osd_enable_rue(struct xilinx_osd *osd); +void xilinx_osd_disable_rue(struct xilinx_osd *osd); + +struct device; +struct device_node; + +struct xilinx_osd *xilinx_osd_probe(struct device *dev, + struct device_node *node); + +#endif /* _XILINX_OSD_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_rgb2yuv.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_rgb2yuv.c 2014-07-20 22:06:36.269307153 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx rgb to yuv converter support for Xilinx DRM KMS + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <linux/device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> + +#include "xilinx_drm_drv.h" + +/* registers */ +/* control register */ +#define RGB_CONTROL 0x000 +/* active size v,h */ +#define RGB_ACTIVE_SIZE 0x020 + +/* control register bit definition */ +#define RGB_CTL_EN (1 << 0) /* enable */ +#define RGB_CTL_RUE (1 << 1) /* register update enable */ +#define RGB_RST_RESET (1 << 31) /* instant reset */ + +struct xilinx_rgb2yuv { + void __iomem *base; +}; + +/* enable rgb2yuv */ +void xilinx_rgb2yuv_enable(struct xilinx_rgb2yuv *rgb2yuv) +{ + u32 reg; + + reg = xilinx_drm_readl(rgb2yuv->base, RGB_CONTROL); + xilinx_drm_writel(rgb2yuv->base, RGB_CONTROL, reg | RGB_CTL_EN); +} + +/* disable rgb2yuv */ +void xilinx_rgb2yuv_disable(struct xilinx_rgb2yuv *rgb2yuv) +{ + u32 reg; + + reg = xilinx_drm_readl(rgb2yuv->base, RGB_CONTROL); + xilinx_drm_writel(rgb2yuv->base, RGB_CONTROL, reg & ~RGB_CTL_EN); +} + +/* configure rgb2yuv */ +void xilinx_rgb2yuv_configure(struct xilinx_rgb2yuv *rgb2yuv, + int hactive, int vactive) +{ + xilinx_drm_writel(rgb2yuv->base, RGB_ACTIVE_SIZE, + (vactive << 16) | hactive); +} + +/* reset rgb2yuv */ +void xilinx_rgb2yuv_reset(struct xilinx_rgb2yuv *rgb2yuv) +{ + u32 reg; + + xilinx_drm_writel(rgb2yuv->base, RGB_CONTROL, RGB_RST_RESET); + + /* enable register update */ + reg = xilinx_drm_readl(rgb2yuv->base, RGB_CONTROL); + xilinx_drm_writel(rgb2yuv->base, RGB_CONTROL, reg | RGB_CTL_RUE); +} + +/* probe rgb2yuv */ +struct xilinx_rgb2yuv *xilinx_rgb2yuv_probe(struct device *dev, + struct device_node *node) +{ + struct xilinx_rgb2yuv *rgb2yuv; + struct resource res; + int ret; + + rgb2yuv = devm_kzalloc(dev, sizeof(*rgb2yuv), GFP_KERNEL); + if (!rgb2yuv) + return ERR_PTR(-ENOMEM); + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + dev_err(dev, "failed to of_address_to_resource\n"); + return ERR_PTR(ret); + } + + rgb2yuv->base = devm_ioremap_resource(dev, &res); + if (IS_ERR(rgb2yuv->base)) + return ERR_CAST(rgb2yuv->base); + + xilinx_rgb2yuv_reset(rgb2yuv); + + return rgb2yuv; +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_rgb2yuv.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_rgb2yuv.h 2014-07-20 22:06:36.275307054 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Color Space Converter Header for Xilinx DRM KMS + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_RGB2YUV_H_ +#define _XILINX_RGB2YUV_H_ + +struct xilinx_rgb2yuv; + +void xilinx_rgb2yuv_configure(struct xilinx_rgb2yuv *rgb2yuv, + int hactive, int vactive); +void xilinx_rgb2yuv_reset(struct xilinx_rgb2yuv *rgb2yuv); +void xilinx_rgb2yuv_enable(struct xilinx_rgb2yuv *rgb2yuv); +void xilinx_rgb2yuv_disable(struct xilinx_rgb2yuv *rgb2yuv); + +struct device; +struct device_node; + +struct xilinx_rgb2yuv *xilinx_rgb2yuv_probe(struct device *dev, + struct device_node *node); + +#endif /* _XILINX_RGB2YUV_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_vtc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_vtc.c 2014-07-20 22:06:36.355305734 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Video Timing Controller support for Xilinx DRM KMS + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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 <drm/drmP.h> + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> + +#include <video/videomode.h> + +#include "xilinx_drm_drv.h" +#include "xilinx_vtc.h" + +/* register offsets */ +#define VTC_CTL 0x000 /* control */ +#define VTC_STATS 0x004 /* status */ +#define VTC_ERROR 0x008 /* error */ + +#define VTC_GASIZE 0x060 /* generator active size */ +#define VTC_GPOL 0x06c /* generator polarity */ +#define VTC_GHSIZE 0x070 /* generator frame horizontal size */ +#define VTC_GVSIZE 0x074 /* generator frame vertical size */ +#define VTC_GHSYNC 0x078 /* generator horizontal sync */ +#define VTC_GVBHOFF 0x07c /* generator vblank horizontal offset */ +#define VTC_GVSYNC 0x080 /* generator vertical sync */ +#define VTC_GVSHOFF 0x084 /* generator vsync horizontal offset */ + +#define VTC_RESET 0x000 /* reset register */ +#define VTC_ISR 0x004 /* interrupt status register */ +#define VTC_IER 0x00c /* interrupt enable register */ + +/* control register bit */ +#define VTC_CTL_FIP (1 << 6) /* field id output polarity */ +#define VTC_CTL_ACP (1 << 5) /* active chroma output polarity */ +#define VTC_CTL_AVP (1 << 4) /* active video output polarity */ +#define VTC_CTL_HSP (1 << 3) /* hori sync output polarity */ +#define VTC_CTL_VSP (1 << 2) /* vert sync output polarity */ +#define VTC_CTL_HBP (1 << 1) /* hori blank output polarity */ +#define VTC_CTL_VBP (1 << 0) /* vert blank output polarity */ + +#define VTC_CTL_FIPSS (1 << 26) /* field id output polarity source */ +#define VTC_CTL_ACPSS (1 << 25) /* active chroma out polarity source */ +#define VTC_CTL_AVPSS (1 << 24) /* active video out polarity source */ +#define VTC_CTL_HSPSS (1 << 23) /* hori sync out polarity source */ +#define VTC_CTL_VSPSS (1 << 22) /* vert sync out polarity source */ +#define VTC_CTL_HBPSS (1 << 21) /* hori blank out polarity source */ +#define VTC_CTL_VBPSS (1 << 20) /* vert blank out polarity source */ + +#define VTC_CTL_VCSS (1 << 18) /* chroma source select */ +#define VTC_CTL_VASS (1 << 17) /* vertical offset source select */ +#define VTC_CTL_VBSS (1 << 16) /* vertical sync end source select */ +#define VTC_CTL_VSSS (1 << 15) /* vertical sync start source select */ +#define VTC_CTL_VFSS (1 << 14) /* vertical active size source select */ +#define VTC_CTL_VTSS (1 << 13) /* vertical frame size source select */ + +#define VTC_CTL_HBSS (1 << 11) /* horiz sync end source select */ +#define VTC_CTL_HSSS (1 << 10) /* horiz sync start source select */ +#define VTC_CTL_HFSS (1 << 9) /* horiz active size source select */ +#define VTC_CTL_HTSS (1 << 8) /* horiz frame size source select */ + +#define VTC_CTL_GE (1 << 2) /* vtc generator enable */ +#define VTC_CTL_RU (1 << 1) /* vtc register update */ + +/* vtc generator horizontal 1 */ +#define VTC_GH1_BPSTART_MASK 0x1fff0000 /* horiz back porch start */ +#define VTC_GH1_BPSTART_SHIFT 16 +#define VTC_GH1_SYNCSTART_MASK 0x00001fff + +/* vtc generator vertical 1 (filed 0) */ +#define VTC_GV1_BPSTART_MASK 0x1fff0000 /* vertical back porch start */ +#define VTC_GV1_BPSTART_SHIFT 16 +#define VTC_GV1_SYNCSTART_MASK 0x00001fff + +/* vtc generator/detector vblank/vsync horizontal offset registers */ +#define VTC_XVXHOX_HEND_MASK 0x1fff0000 /* horizontal offset end */ +#define VTC_XVXHOX_HEND_SHIFT 16 /* horizontal offset end + shift */ +#define VTC_XVXHOX_HSTART_MASK 0x00001fff /* horizontal offset start */ + +/* reset register bit definition */ +#define VTC_RESET_RESET (1 << 31) /* Software Reset */ + +/* interrupt status/enable register bit definition */ +#define VTC_IXR_FSYNC15 (1 << 31) /* frame sync interrupt 15 */ +#define VTC_IXR_FSYNC14 (1 << 30) /* frame sync interrupt 14 */ +#define VTC_IXR_FSYNC13 (1 << 29) /* frame sync interrupt 13 */ +#define VTC_IXR_FSYNC12 (1 << 28) /* frame sync interrupt 12 */ +#define VTC_IXR_FSYNC11 (1 << 27) /* frame sync interrupt 11 */ +#define VTC_IXR_FSYNC10 (1 << 26) /* frame sync interrupt 10 */ +#define VTC_IXR_FSYNC09 (1 << 25) /* frame sync interrupt 09 */ +#define VTC_IXR_FSYNC08 (1 << 24) /* frame sync interrupt 08 */ +#define VTC_IXR_FSYNC07 (1 << 23) /* frame sync interrupt 07 */ +#define VTC_IXR_FSYNC06 (1 << 22) /* frame sync interrupt 06 */ +#define VTC_IXR_FSYNC05 (1 << 21) /* frame sync interrupt 05 */ +#define VTC_IXR_FSYNC04 (1 << 20) /* frame sync interrupt 04 */ +#define VTC_IXR_FSYNC03 (1 << 19) /* frame sync interrupt 03 */ +#define VTC_IXR_FSYNC02 (1 << 18) /* frame sync interrupt 02 */ +#define VTC_IXR_FSYNC01 (1 << 17) /* frame sync interrupt 01 */ +#define VTC_IXR_FSYNC00 (1 << 16) /* frame sync interrupt 00 */ +#define VTC_IXR_FSYNCALL_MASK (VTC_IXR_FSYNC00 | \ + VTC_IXR_FSYNC01 | \ + VTC_IXR_FSYNC02 | \ + VTC_IXR_FSYNC03 | \ + VTC_IXR_FSYNC04 | \ + VTC_IXR_FSYNC05 | \ + VTC_IXR_FSYNC06 | \ + VTC_IXR_FSYNC07 | \ + VTC_IXR_FSYNC08 | \ + VTC_IXR_FSYNC09 | \ + VTC_IXR_FSYNC10 | \ + VTC_IXR_FSYNC11 | \ + VTC_IXR_FSYNC12 | \ + VTC_IXR_FSYNC13 | \ + VTC_IXR_FSYNC14 | \ + VTC_IXR_FSYNC15) + +#define VTC_IXR_G_AV (1 << 13) /* generator actv video intr */ +#define VTC_IXR_G_VBLANK (1 << 12) /* generator vblank interrupt */ +#define VTC_IXR_G_ALL_MASK (VTC_IXR_G_AV | \ + VTC_IXR_G_VBLANK) /* all generator intr */ + +#define VTC_IXR_D_AV (1 << 11) /* detector active video intr */ +#define VTC_IXR_D_VBLANK (1 << 10) /* detector vblank interrupt */ +#define VTC_IXR_D_ALL_MASK (VTC_IXR_D_AV | \ + VTC_IXR_D_VBLANK) /* all detector intr */ + +#define VTC_IXR_LOL (1 << 9) /* lock loss */ +#define VTC_IXR_LO (1 << 8) /* lock */ +#define VTC_IXR_LOCKALL_MASK (VTC_IXR_LOL | \ + VTC_IXR_LO) /* all signal lock intr */ + +#define VTC_IXR_ACL (1 << 21) /* active chroma signal lock */ +#define VTC_IXR_AVL (1 << 20) /* active video signal lock */ +#define VTC_IXR_HSL (1 << 19) /* horizontal sync signal + lock */ +#define VTC_IXR_VSL (1 << 18) /* vertical sync signal lock */ +#define VTC_IXR_HBL (1 << 17) /* horizontal blank signal + lock */ +#define VTC_IXR_VBL (1 << 16) /* vertical blank signal lock */ + +/* mask for all interrupts */ +#define VTC_IXR_ALLINTR_MASK (VTC_IXR_FSYNCALL_MASK | \ + VTC_IXR_G_ALL_MASK | \ + VTC_IXR_D_ALL_MASK | \ + VTC_IXR_LOCKALL_MASK) +/** + * struct xilinx_vtc: Xilinx VTC object + * + * @base: base addr + * @irq: irq + * @vblank_fn: vblank handler func + * @vblank_data: vblank handler private data + */ +struct xilinx_vtc { + void __iomem *base; + int irq; + void (*vblank_fn)(void *); + void *vblank_data; +}; + +/** + * struct xilinx_vtc_polarity: vtc polarity config + * + * @active_chroma: active chroma polarity + * @active_video: active video polarity + * @field_id: field ID polarity + * @vblank: vblank polarity + * @vsync: vsync polarity + * @hblank: hblank polarity + * @hsync: hsync polarity + */ +struct xilinx_vtc_polarity { + u8 active_chroma; + u8 active_video; + u8 field_id; + u8 vblank; + u8 vsync; + u8 hblank; + u8 hsync; +}; + +/** + * struct xilinx_vtc_hori_offset: vtc horizontal offset config + * + * @vblank_hori_start: vblank horizontal start + * @vblank_hori_end: vblank horizontal end + * @vsync_hori_start: vsync horizontal start + * @vsync_hori_end: vsync horizontal end + */ +struct xilinx_vtc_hori_offset { + u16 vblank_hori_start; + u16 vblank_hori_end; + u16 vsync_hori_start; + u16 vsync_hori_end; +}; + +/** + * struct xilinx_vtc_src_config: vtc source config + * + * @field_id_pol: filed id polarity source + * @active_chroma_pol: active chroma polarity source + * @active_video_pol: active video polarity source + * @hsync_pol: hsync polarity source + * @vsync_pol: vsync polarity source + * @hblank_pol: hblnak polarity source + * @vblank_pol: vblank polarity source + * @vchroma: vchroma polarity start source + * @vactive: vactive size source + * @vbackporch: vbackporch start source + * @vsync: vsync start source + * @vfrontporch: vfrontporch start source + * @vtotal: vtotal size source + * @hactive: hactive start source + * @hbackporch: hbackporch start source + * @hsync: hsync start source + * @hfrontporch: hfrontporch start source + * @htotal: htotal size source + */ +struct xilinx_vtc_src_config { + u8 field_id_pol; + u8 active_chroma_pol; + u8 active_video_pol; + u8 hsync_pol; + u8 vsync_pol; + u8 hblank_pol; + u8 vblank_pol; + + u8 vchroma; + u8 vactive; + u8 vbackporch; + u8 vsync; + u8 vfrontporch; + u8 vtotal; + + u8 hactive; + u8 hbackporch; + u8 hsync; + u8 hfrontporch; + u8 htotal; +}; + +/* configure polarity of signals */ +static void xilinx_vtc_config_polarity(struct xilinx_vtc *vtc, + struct xilinx_vtc_polarity *polarity) +{ + u32 reg; + + reg = xilinx_drm_readl(vtc->base, VTC_GPOL); + + if (polarity->active_chroma) + reg |= VTC_CTL_ACP; + if (polarity->active_video) + reg |= VTC_CTL_AVP; + if (polarity->field_id) + reg |= VTC_CTL_FIP; + if (polarity->vblank) + reg |= VTC_CTL_VBP; + if (polarity->vsync) + reg |= VTC_CTL_VSP; + if (polarity->hblank) + reg |= VTC_CTL_HBP; + if (polarity->hsync) + reg |= VTC_CTL_HSP; + + xilinx_drm_writel(vtc->base, VTC_GPOL, reg); +} + +/* configure horizontal offset */ +static void +xilinx_vtc_config_hori_offset(struct xilinx_vtc *vtc, + struct xilinx_vtc_hori_offset *hori_offset) +{ + u32 reg; + + reg = hori_offset->vblank_hori_start & VTC_XVXHOX_HSTART_MASK; + reg |= (hori_offset->vblank_hori_end << VTC_XVXHOX_HEND_SHIFT) & + VTC_XVXHOX_HEND_MASK; + xilinx_drm_writel(vtc->base, VTC_GVBHOFF, reg); + + reg = hori_offset->vsync_hori_start & VTC_XVXHOX_HSTART_MASK; + reg |= (hori_offset->vsync_hori_end << VTC_XVXHOX_HEND_SHIFT) & + VTC_XVXHOX_HEND_MASK; + xilinx_drm_writel(vtc->base, VTC_GVSHOFF, reg); +} + +/* configure source */ +static void xilinx_vtc_config_src(struct xilinx_vtc *vtc, + struct xilinx_vtc_src_config *src_config) +{ + u32 reg; + + reg = xilinx_drm_readl(vtc->base, VTC_CTL); + + if (src_config->field_id_pol) + reg |= VTC_CTL_FIPSS; + if (src_config->active_chroma_pol) + reg |= VTC_CTL_ACPSS; + if (src_config->active_video_pol) + reg |= VTC_CTL_AVPSS; + if (src_config->hsync_pol) + reg |= VTC_CTL_HSPSS; + if (src_config->vsync_pol) + reg |= VTC_CTL_VSPSS; + if (src_config->hblank_pol) + reg |= VTC_CTL_HBPSS; + if (src_config->vblank_pol) + reg |= VTC_CTL_VBPSS; + + if (src_config->vchroma) + reg |= VTC_CTL_VCSS; + if (src_config->vactive) + reg |= VTC_CTL_VASS; + if (src_config->vbackporch) + reg |= VTC_CTL_VBSS; + if (src_config->vsync) + reg |= VTC_CTL_VSSS; + if (src_config->vfrontporch) + reg |= VTC_CTL_VFSS; + if (src_config->vtotal) + reg |= VTC_CTL_VTSS; + + if (src_config->hbackporch) + reg |= VTC_CTL_HBSS; + if (src_config->hsync) + reg |= VTC_CTL_HSSS; + if (src_config->hfrontporch) + reg |= VTC_CTL_HFSS; + if (src_config->htotal) + reg |= VTC_CTL_HTSS; + + xilinx_drm_writel(vtc->base, VTC_CTL, reg); +} + +/* enable vtc */ +void xilinx_vtc_enable(struct xilinx_vtc *vtc) +{ + u32 reg; + + /* enable a generator only for now */ + reg = xilinx_drm_readl(vtc->base, VTC_CTL); + xilinx_drm_writel(vtc->base, VTC_CTL, reg | VTC_CTL_GE); +} + +/* disable vtc */ +void xilinx_vtc_disable(struct xilinx_vtc *vtc) +{ + u32 reg; + + /* disable a generator only for now */ + reg = xilinx_drm_readl(vtc->base, VTC_CTL); + xilinx_drm_writel(vtc->base, VTC_CTL, reg & ~VTC_CTL_GE); +} + +/* configure vtc signals */ +void xilinx_vtc_config_sig(struct xilinx_vtc *vtc, + struct videomode *vm) +{ + u32 reg; + u32 htotal, hactive, hsync_start, hbackporch_start; + u32 vtotal, vactive, vsync_start, vbackporch_start; + struct xilinx_vtc_hori_offset hori_offset; + struct xilinx_vtc_polarity polarity; + struct xilinx_vtc_src_config src; + + reg = xilinx_drm_readl(vtc->base, VTC_CTL); + xilinx_drm_writel(vtc->base, VTC_CTL, reg & ~VTC_CTL_RU); + + htotal = vm->hactive + vm->hfront_porch + vm->hsync_len + + vm->hback_porch; + vtotal = vm->vactive + vm->vfront_porch + vm->vsync_len + + vm->vback_porch; + + hactive = vm->hactive; + vactive = vm->vactive; + + hsync_start = vm->hactive + vm->hfront_porch; + vsync_start = vm->vactive + vm->vfront_porch; + + hbackporch_start = hsync_start + vm->hsync_len; + vbackporch_start = vsync_start + vm->vsync_len; + + reg = htotal & 0x1fff; + xilinx_drm_writel(vtc->base, VTC_GHSIZE, reg); + + reg = vtotal & 0x1fff; + xilinx_drm_writel(vtc->base, VTC_GVSIZE, reg); + + DRM_DEBUG_DRIVER("ht: %d, vt: %d\n", htotal, vtotal); + + reg = hactive & 0x1fff; + reg |= (vactive & 0x1fff) << 16; + xilinx_drm_writel(vtc->base, VTC_GASIZE, reg); + + DRM_DEBUG_DRIVER("ha: %d, va: %d\n", hactive, vactive); + + reg = hsync_start & VTC_GH1_SYNCSTART_MASK; + reg |= (hbackporch_start << VTC_GH1_BPSTART_SHIFT) & + VTC_GH1_BPSTART_MASK; + xilinx_drm_writel(vtc->base, VTC_GHSYNC, reg); + + DRM_DEBUG_DRIVER("hs: %d, hb: %d\n", hsync_start, hbackporch_start); + + reg = vsync_start & VTC_GV1_SYNCSTART_MASK; + reg |= (vbackporch_start << VTC_GV1_BPSTART_SHIFT) & + VTC_GV1_BPSTART_MASK; + xilinx_drm_writel(vtc->base, VTC_GVSYNC, reg); + + DRM_DEBUG_DRIVER("vs: %d, vb: %d\n", vsync_start, vbackporch_start); + + hori_offset.vblank_hori_start = hactive; + hori_offset.vblank_hori_end = hactive; + hori_offset.vsync_hori_start = hactive; + hori_offset.vsync_hori_end = hactive; + + xilinx_vtc_config_hori_offset(vtc, &hori_offset); + + /* set up polarity */ + memset(&polarity, 0x0, sizeof(polarity)); + polarity.hsync = 1; + polarity.vsync = 1; + polarity.hblank = 1; + polarity.vblank = 1; + polarity.active_video = 1; + polarity.active_chroma = 1; + polarity.field_id = 1; + xilinx_vtc_config_polarity(vtc, &polarity); + + /* set up src config */ + memset(&src, 0x0, sizeof(src)); + src.vchroma = 1; + src.vactive = 1; + src.vbackporch = 1; + src.vsync = 1; + src.vfrontporch = 1; + src.vtotal = 1; + src.hactive = 1; + src.hbackporch = 1; + src.hsync = 1; + src.hfrontporch = 1; + src.htotal = 1; + xilinx_vtc_config_src(vtc, &src); + + reg = xilinx_drm_readl(vtc->base, VTC_CTL); + xilinx_drm_writel(vtc->base, VTC_CTL, reg | VTC_CTL_RU); +} + +/* reset vtc */ +void xilinx_vtc_reset(struct xilinx_vtc *vtc) +{ + u32 reg; + + xilinx_drm_writel(vtc->base, VTC_RESET, VTC_RESET_RESET); + + /* enable register update */ + reg = xilinx_drm_readl(vtc->base, VTC_CTL); + xilinx_drm_writel(vtc->base, VTC_CTL, reg | VTC_CTL_RU); +} + +/* enable interrupt */ +static inline void xilinx_vtc_intr_enable(struct xilinx_vtc *vtc, u32 intr) +{ + xilinx_drm_writel(vtc->base, VTC_IER, (intr & VTC_IXR_ALLINTR_MASK) | + xilinx_drm_readl(vtc->base, VTC_IER)); +} + +/* disable interrupt */ +static inline void xilinx_vtc_intr_disable(struct xilinx_vtc *vtc, u32 intr) +{ + xilinx_drm_writel(vtc->base, VTC_IER, ~(intr & VTC_IXR_ALLINTR_MASK) & + xilinx_drm_readl(vtc->base, VTC_IER)); +} + +/* get interrupt */ +static inline u32 xilinx_vtc_intr_get(struct xilinx_vtc *vtc) +{ + return xilinx_drm_readl(vtc->base, VTC_IER) & + xilinx_drm_readl(vtc->base, VTC_ISR) & VTC_IXR_ALLINTR_MASK; +} + +/* clear interrupt */ +static inline void xilinx_vtc_intr_clear(struct xilinx_vtc *vtc, u32 intr) +{ + xilinx_drm_writel(vtc->base, VTC_ISR, intr & VTC_IXR_ALLINTR_MASK); +} + +/* interrupt handler */ +static irqreturn_t xilinx_vtc_intr_handler(int irq, void *data) +{ + struct xilinx_vtc *vtc = data; + + u32 intr = xilinx_vtc_intr_get(vtc); + + if ((intr & VTC_IXR_G_VBLANK) && (vtc->vblank_fn)) + vtc->vblank_fn(vtc->vblank_data); + + xilinx_vtc_intr_clear(vtc, intr); + + return IRQ_HANDLED; +} + +/* enable vblank interrupt */ +void xilinx_vtc_enable_vblank_intr(struct xilinx_vtc *vtc, + void (*vblank_fn)(void *), + void *vblank_priv) +{ + vtc->vblank_fn = vblank_fn; + vtc->vblank_data = vblank_priv; + xilinx_vtc_intr_enable(vtc, VTC_IXR_G_VBLANK); +} + +/* disable vblank interrupt */ +void xilinx_vtc_disable_vblank_intr(struct xilinx_vtc *vtc) +{ + xilinx_vtc_intr_disable(vtc, VTC_IXR_G_VBLANK); + vtc->vblank_data = NULL; + vtc->vblank_fn = NULL; +} + +/* probe vtc */ +struct xilinx_vtc *xilinx_vtc_probe(struct device *dev, + struct device_node *node) +{ + struct xilinx_vtc *vtc; + struct resource res; + int ret; + + vtc = devm_kzalloc(dev, sizeof(*vtc), GFP_KERNEL); + if (!vtc) + return ERR_PTR(-ENOMEM); + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + dev_err(dev, "failed to of_address_to_resource\n"); + return ERR_PTR(ret); + } + + vtc->base = devm_ioremap_resource(dev, &res); + if (IS_ERR(vtc->base)) + return ERR_CAST(vtc->base); + + xilinx_vtc_intr_disable(vtc, VTC_IXR_ALLINTR_MASK); + vtc->irq = irq_of_parse_and_map(node, 0); + if (vtc->irq > 0) { + ret = devm_request_irq(dev, vtc->irq, xilinx_vtc_intr_handler, + IRQF_SHARED, "xilinx_vtc", vtc); + if (ret) { + dev_warn(dev, "failed to requet_irq() for vtc\n"); + return ERR_PTR(ret); + } + } + + xilinx_vtc_reset(vtc); + + return vtc; +} Index: linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_vtc.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/gpu/drm/xilinx/xilinx_vtc.h 2014-07-20 22:06:36.362305619 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Video Timing Controller Header for Xilinx DRM KMS + * + * Copyright (C) 2013 Xilinx, Inc. + * + * Author: Hyun Woo Kwon <hyunk@xilinx.com> + * + * 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_VTC_H_ +#define _XILINX_VTC_H_ + +struct xilinx_vtc; + +struct videomode; + +void xilinx_vtc_config_sig(struct xilinx_vtc *vtc, + struct videomode *vm); +void xilinx_vtc_enable_vblank_intr(struct xilinx_vtc *vtc, + void (*fn)(void *), void *data); +void xilinx_vtc_disable_vblank_intr(struct xilinx_vtc *vtc); +void xilinx_vtc_reset(struct xilinx_vtc *vtc); +void xilinx_vtc_enable(struct xilinx_vtc *vtc); +void xilinx_vtc_disable(struct xilinx_vtc *vtc); + +struct device; +struct device_node; + +struct xilinx_vtc *xilinx_vtc_probe(struct device *dev, + struct device_node *node); + +#endif /* _XILINX_VTC_H_ */ Index: linux-3.12.24-rt38-xilinx/drivers/hwmon/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/hwmon/Kconfig 2014-07-20 22:05:50.204067149 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/hwmon/Kconfig 2014-07-20 22:06:36.379305338 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1556 @ help Support for the A/D converter on MC13783 and MC13892 PMIC. +config SENSORS_XADCPS + tristate "Xilinx Zynq XADC" + depends on ARCH_ZYNQ + depends on SYSFS + help + Support for the A/D converter on Xilinx Zynq. + if ACPI comment "ACPI drivers" Index: linux-3.12.24-rt38-xilinx/drivers/hwmon/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/hwmon/Makefile 2014-07-20 22:05:50.203067166 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/hwmon/Makefile 2014-07-20 22:06:36.390305157 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:145 @ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o +obj-$(CONFIG_SENSORS_XADCPS) += xilinx-xadcps.o obj-$(CONFIG_PMBUS) += pmbus/ Index: linux-3.12.24-rt38-xilinx/drivers/hwmon/xilinx-xadcps.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/hwmon/xilinx-xadcps.c 2014-07-20 22:06:36.403304943 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * drivers/hwmon/xilinx-xadcps.c - Xilinx Zynq XADC support + * + * Copyright (c) 2012 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation. + * + * 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 + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/sysfs.h> +#include <linux/kobject.h> +#include <linux/io.h> +#include <linux/spinlock.h> + +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> + +/* XADC interface register offsets */ +#define XADC_CONFIG 0x00 +#define XADC_INTSTS 0x04 +#define XADC_INTMSK 0x08 +#define XADC_STATUS 0x0C +#define XADC_CFIFO 0x10 +#define XADC_DFIFO 0x14 +#define XADC_CTL 0x18 + +/* XADC interface register fields */ +#define XADC_CONFIG_ENABLE (1 << 31) +#define XADC_CONFIG_CFIFOTH_MSK 0xF +#define XADC_CONFIG_CFIFOTH_SHIFT 20 +#define XADC_CONFIG_DFIFOTH_MSK 0xF +#define XADC_CONFIG_DFIFOTH_SHIFT 16 +#define XADC_CONFIG_WEDGE (1 << 13) +#define XADC_CONFIG_REDGE (1 << 12) +#define XADC_CONFIG_TCKRATE_MSK 0x3 +#define XADC_CONFIG_TCKRATE_SHIFT 8 +#define XADC_CONFIG_IGAP_MSK 0x1F +#define XADC_CONFIG_IGAP_SHIFT 0 + +#define TCKRATE_DIV16 3 + +#define XADC_INT_CFIFO_LTH (1 << 9) +#define XADC_INT_DFIFO_GTH (1 << 8) + +#define XADC_STATUS_CFIFO_LVL_MSK 0xF +#define XADC_STATUS_CFIFO_LVL_SHIFT 16 +#define XADC_STATUS_DFIFO_EMPTY (1 << 8) + +#define XADC_FIFO_CMD_MSK 0xF +#define XADC_FIFO_CMD_SHIFT 26 +#define XADC_FIFO_ADDR_MSK 0x3FF +#define XADC_FIFO_ADDR_SHIFT 16 +#define XADC_FIFO_DATA_MSK 0xFFFF +#define XADC_FIFO_DATA_SHIFT 0 + +/* XADC commands */ +#define XADC_CMD_NOP 0 +#define XADC_CMD_READ 1 +#define XADC_CMD_WRITE 2 + +/* XADC register offsets */ +#define REG_TEMP 0x00 +#define REG_VCCINT 0x01 +#define REG_VCCAUX 0x02 +#define REG_VPVN 0x03 +#define REG_VCCBRAM 0x06 + +#define REG_MAX_TEMP 0x20 +#define REG_MAX_VCCINT 0x21 +#define REG_MAX_VCCAUX 0x22 +#define REG_MAX_VCCBRAM 0x23 +#define REG_MIN_TEMP 0x24 +#define REG_MIN_VCCINT 0x25 +#define REG_MIN_VCCAUX 0x26 +#define REG_MIN_VCCBRAM 0x27 + +#define REG_FLAG 0x3F +#define REG_CFG1 0x41 + +#define REG_SEQ_SEL0 0x48 +#define REG_SEQ_SEL1 0x49 +#define REG_SEQ_AVG0 0x4A +#define REG_SEQ_AVG1 0x4B +#define REG_SEQ_BIP0 0x4C +#define REG_SEQ_BIP1 0x4D +#define REG_SEQ_ACQ0 0x4E +#define REG_SEQ_ACQ1 0x4F + +/* XADC register fields */ +#define REG_CFG1_CAL_ADCOG (1 << 5) /* ADC offset & gain */ +#define REG_CFG1_CAL_SSOG (1 << 7) /* supply sensor offset &gain */ + +#define REG_CFG1_SEQ_MSK 0xF +#define REG_CFG1_SEQ_SHIFT 12 + +#define MODE_DEF 0 /* Internal sensors, no alarms */ +#define MODE_IND 8 /* Independent:ADC A -int, ADC B -ext */ + +#define REG_FLAG_DIS (1 << 8) +#define REG_FLAG_REF (1 << 9) + +/* Sequencer registers 0 */ +#define REG_SEQ_V (1 << 11) + +#define READ(dev, reg) readl((dev->iobase + XADC_##reg)) +#define WRITE(dev, reg, value) writel(value, dev->iobase+XADC_##reg) + +#define GETFIELD(reg, field, value) \ + (((value) >> (reg##_##field##_SHIFT)) & reg##_##field##_MSK) + +#define SETFIELD(reg, field, value) \ + (((value) & reg##_##field##_MSK) << reg##_##field##_SHIFT) + +#define CLRFIELD(reg, field, value) \ + ((value) & ~(reg##_##field##_MSK << reg##_##field##_SHIFT)) + +#define READOP(reg) \ + (SETFIELD(XADC_FIFO, CMD, XADC_CMD_READ) |\ + SETFIELD(XADC_FIFO, ADDR, reg)) + +#define WRITEOP(reg, val) \ + (SETFIELD(XADC_FIFO, CMD, XADC_CMD_WRITE) |\ + SETFIELD(XADC_FIFO, ADDR, reg) | SETFIELD(XADC_FIFO, DATA, val)) + +#define NOOP (SETFIELD(XADC_FIFO, CMD, XADC_CMD_NOP)) + +struct xadc_op { + u32 cmd; + u32 res; +}; + +struct xadc_batch { + int count; + int writeptr; + int readptr; + struct list_head q; + struct completion comp; + struct xadc_op *ops; +}; + + +struct xadc_t { + struct device *dev; + struct device *hwmon; + void __iomem *iobase; + int irq; + struct clk *clk; + spinlock_t slock; + struct list_head runq; + struct xadc_batch *curr; + u32 chanmode[17]; /* Channel 0-15 VAUX, 16 is V */ + #define CHAN_ON 1 + #define CHAN_BIPOLAR 2 +}; + + +static void run_batch(struct xadc_t *xadc) +{ + u32 config, rdt; + + if (list_empty(&xadc->runq)) { + xadc->curr = NULL; + return; + } + xadc->curr = list_first_entry(&xadc->runq, struct xadc_batch, q); + list_del(&xadc->curr->q); + + config = READ(xadc, CONFIG); + config = CLRFIELD(XADC_CONFIG, CFIFOTH, config); + config = CLRFIELD(XADC_CONFIG, DFIFOTH, config); + + rdt = xadc->curr->count-xadc->curr->readptr; + if (rdt > 15) /* Trigger at half FIFO or count */ + rdt = 8; + else + rdt--; + + config |= SETFIELD(XADC_CONFIG, CFIFOTH, 0) | /* Just trigger */ + SETFIELD(XADC_CONFIG, DFIFOTH, rdt); + + WRITE(xadc, CONFIG, config); + + /* unmask CFIFO,DFIFO interrupts */ + WRITE(xadc, INTMSK, READ(xadc, INTMSK) & + ~(XADC_INT_CFIFO_LTH | XADC_INT_DFIFO_GTH)); +} + +static void add_batch(struct xadc_t *xadc, struct xadc_batch *b) +{ + unsigned long flags; + + BUG_ON(b->count < 1); + b->writeptr = 0; + b->readptr = 0; + init_completion(&b->comp); + list_add_tail(&b->q, &xadc->runq); + spin_lock_irqsave(&xadc->slock, flags); + if (!xadc->curr) + run_batch(xadc); + spin_unlock_irqrestore(&xadc->slock, flags); +} + +static inline u16 read_register(struct xadc_t *xadc, unsigned int reg) +{ + u16 ret; + struct xadc_op *ops; + struct xadc_batch *b = kzalloc(sizeof(*b), GFP_KERNEL); + + if (!b) + return 0; + ops = kzalloc(sizeof(*ops) * 2, GFP_KERNEL); + if (!ops) { + kfree(b); + return 0; + } + + b->count = 2; + b->ops = ops; + ops[0].cmd = READOP(reg); + ops[1].cmd = NOOP; + add_batch(xadc, b); + wait_for_completion_interruptible(&b->comp); + ret = GETFIELD(XADC_FIFO, DATA, b->ops[1].res); + kfree(ops); + kfree(b); + return ret; +} + +static inline void write_register(struct xadc_t *xadc, unsigned int reg, + u16 val) +{ + struct xadc_op *ops; + struct xadc_batch *b = kzalloc(sizeof(*b), GFP_KERNEL); + + if (!b) + return; + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + if (!ops) { + kfree(b); + return; + } + + b->count = 1; + b->ops = ops; + ops[0].cmd = WRITEOP(reg, val); + add_batch(xadc, b); + wait_for_completion_interruptible(&b->comp); + kfree(ops); + kfree(b); +} + +static inline int reg2temp(u16 reg) +{ + int val; + + val = (reg >> 4) & 0xFFF; /* Use only 12 bits */ + val = ((val * 503975) / 4096) - 273150; /* (X*503.975/4096) -273.15 */ + val = DIV_ROUND_CLOSEST(val, 1000); + return val; +} + +static inline unsigned reg2vcc(u16 reg) +{ + unsigned val; + + val = (reg >> 4) & 0xFFF; /* Use only 12 bits */ + val = ((val * 3000) / 4096); /* (X*3/4096) */ + /* Return voltage in mV */ + return val; +} + +static inline unsigned reg2v(u16 reg) +{ + unsigned val; + + val = (reg >> 4) & 0xFFF; /*Use only 12 bits */ + val = (val * 1000 / 4096); /* (X/4096) */ + /* Return voltage in mV */ + return val; +} + +static inline int reg2bv(u16 reg) +{ + int val; + + val = (reg >> 4) & 0xFFF; /* Use only 12 bits */ + if (val & 0x800) + val = val - 0x1000; + val = (val * 1000 / 4096); /* (X/4096) */ + /* Return voltage in mV */ + return val; +} + +static ssize_t xadc_read_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xadc_t *xadc = platform_get_drvdata(pdev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + unsigned int reg = attr->index; + u16 regval; + + clk_enable(xadc->clk); + + regval = read_register(xadc, reg); + + clk_disable(xadc->clk); + + return sprintf(buf, "%d\n", reg2temp(regval)); +} + +static ssize_t xadc_read_vcc(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xadc_t *xadc = platform_get_drvdata(pdev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + unsigned int reg = attr->index; + u16 regval; + + clk_enable(xadc->clk); + + regval = read_register(xadc, reg); + + clk_disable(xadc->clk); + + return sprintf(buf, "%u\n", reg2vcc(regval)); +} + +static ssize_t xadc_read_v(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xadc_t *xadc = platform_get_drvdata(pdev); + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + unsigned int reg = attr->index; + unsigned int chan = attr->nr; + u16 regval; + + if (!(xadc->chanmode[chan] & CHAN_ON)) + return sprintf(buf, "%d\n", 0); + + clk_enable(xadc->clk); + + regval = read_register(xadc, reg); + + clk_disable(xadc->clk); + + if ((xadc->chanmode[chan] & CHAN_BIPOLAR)) + return sprintf(buf, "%d\n", reg2bv(regval)); + + return sprintf(buf, "%u\n", reg2v(regval)); +} + +#ifdef DEBUG +static ssize_t xadc_read_registers(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xadc_t *xadc = platform_get_drvdata(pdev); + unsigned int i, count = 0; + + clk_enable(xadc->clk); + + for (i = 0; i < 0x60; i++) + count += sprintf(buf+count, "%02X %04x\n", i, + read_register(xadc, i)); + + clk_disable(xadc->clk); + + return count; +} +#endif + +static ssize_t xadc_read_flags(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xadc_t *xadc = platform_get_drvdata(pdev); + u16 val; + + clk_enable(xadc->clk); + + val = read_register(xadc, REG_FLAG); + + clk_disable(xadc->clk); + + return sprintf(buf, "enabled:\t%s\nreference:\t%s\n", + val & REG_FLAG_DIS ? "no" : "yes", + val & REG_FLAG_REF ? "internal" : "external"); +} + +static ssize_t xadc_read_vmode(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xadc_t *xadc = platform_get_drvdata(pdev); + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + unsigned int channel = attr->nr; + + return sprintf(buf, "%s\n", (xadc->chanmode[channel] & CHAN_ON) ? + ((xadc->chanmode[channel] & CHAN_BIPOLAR) ? + "bipolar" : "unipolar") : "off"); +} + +static ssize_t xadc_write_vmode(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xadc_t *xadc = platform_get_drvdata(pdev); + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + unsigned int channel = attr->nr; + unsigned int reg = attr->index; + u32 mode; + u16 val; + + if (!strncmp("off", buf, 3)) + mode = 0; + else if (!strncmp("unipolar", buf, 8)) + mode = CHAN_ON; + else if (!strncmp("bipolar", buf, 7)) + mode = CHAN_ON | CHAN_BIPOLAR; + else + return -EIO; + + if (mode == xadc->chanmode[channel]) + return count; + + xadc->chanmode[channel] = mode; + + clk_enable(xadc->clk); + + if (mode & CHAN_BIPOLAR) { + val = read_register(xadc, reg + REG_SEQ_BIP0); + if (0 == reg) /* only dedicated channel there */ + val |= REG_SEQ_V; + else + val |= 1 << channel; + write_register(xadc, reg + REG_SEQ_BIP0, val); + } else { + val = read_register(xadc, reg + REG_SEQ_BIP0); + if (0 == reg) /* only dedicated channel there */ + val &= ~REG_SEQ_V; + else + val &= ~(1 << channel); + write_register(xadc, reg + REG_SEQ_BIP0, val); + } + + if (mode & CHAN_ON) { + val = read_register(xadc, reg + REG_SEQ_SEL0); + if (0 == reg) /* only dedicated channel there */ + val |= REG_SEQ_V; + else + val |= 1 << channel; + write_register(xadc, reg + REG_SEQ_SEL0, val); + } else { + val = read_register(xadc, reg + REG_SEQ_SEL0); + if (0 == reg) /* only dedicated channel there */ + val &= ~REG_SEQ_V; + else + val &= ~(1 << channel); + write_register(xadc, reg + REG_SEQ_SEL0, val); + } + + clk_disable(xadc->clk); + + return count; +} + +static ssize_t show_name(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%s\n", "xadcps"); +} + +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static SENSOR_DEVICE_ATTR(status, S_IRUGO, xadc_read_flags, NULL, 0); +static SENSOR_DEVICE_ATTR(temp, S_IRUGO, xadc_read_temp, NULL, REG_TEMP); +static SENSOR_DEVICE_ATTR(temp_min, S_IRUGO, xadc_read_temp, NULL, + REG_MIN_TEMP); +static SENSOR_DEVICE_ATTR(temp_max, S_IRUGO, xadc_read_temp, NULL, + REG_MAX_TEMP); +static SENSOR_DEVICE_ATTR(vccint, S_IRUGO, xadc_read_vcc, NULL, REG_VCCINT); +static SENSOR_DEVICE_ATTR(vccint_min, S_IRUGO, xadc_read_vcc, NULL, + REG_MIN_VCCINT); +static SENSOR_DEVICE_ATTR(vccint_max, S_IRUGO, xadc_read_vcc, NULL, + REG_MAX_VCCINT); +static SENSOR_DEVICE_ATTR(vccaux, S_IRUGO, xadc_read_vcc, NULL, REG_VCCAUX); +static SENSOR_DEVICE_ATTR(vccaux_min, S_IRUGO, xadc_read_vcc, NULL, + REG_MIN_VCCAUX); +static SENSOR_DEVICE_ATTR(vccaux_max, S_IRUGO, xadc_read_vcc, NULL, + REG_MAX_VCCAUX); +static SENSOR_DEVICE_ATTR(vccbram, S_IRUGO, xadc_read_vcc, NULL, REG_VCCBRAM); +static SENSOR_DEVICE_ATTR(vccbram_min, S_IRUGO, xadc_read_vcc, NULL, + REG_MIN_VCCBRAM); +static SENSOR_DEVICE_ATTR(vccbram_max, S_IRUGO, xadc_read_vcc, NULL, + REG_MAX_VCCBRAM); +/* + * channel number, register + * for VPVN = 16, REG_VPVN + * for VAUXi = i, REG_VAUX0 + i + */ +static SENSOR_DEVICE_ATTR_2(v, S_IRUGO, xadc_read_v, NULL, 16, REG_VPVN); +/* channel number, offset from REG_SEQ_xxx_0 + * for VPVN = 16, 0 + * for VAUXi = i, 1 + */ +static SENSOR_DEVICE_ATTR_2(v_mode, S_IWUSR|S_IRUGO, xadc_read_vmode, + xadc_write_vmode, 16, 0); +#ifdef DEBUG +static SENSOR_DEVICE_ATTR(registers, S_IRUGO, xadc_read_registers, NULL, 0); +#endif + +static struct attribute *xadc_attr[] = { + &dev_attr_name.attr, +#ifdef DEBUG + &sensor_dev_attr_registers.dev_attr.attr, +#endif + &sensor_dev_attr_status.dev_attr.attr, + &sensor_dev_attr_temp.dev_attr.attr, + &sensor_dev_attr_temp_min.dev_attr.attr, + &sensor_dev_attr_temp_max.dev_attr.attr, + &sensor_dev_attr_vccint.dev_attr.attr, + &sensor_dev_attr_vccint_min.dev_attr.attr, + &sensor_dev_attr_vccint_max.dev_attr.attr, + &sensor_dev_attr_vccaux.dev_attr.attr, + &sensor_dev_attr_vccaux_min.dev_attr.attr, + &sensor_dev_attr_vccaux_max.dev_attr.attr, + &sensor_dev_attr_vccbram.dev_attr.attr, + &sensor_dev_attr_vccbram_min.dev_attr.attr, + &sensor_dev_attr_vccbram_max.dev_attr.attr, + &sensor_dev_attr_v.dev_attr.attr, + &sensor_dev_attr_v_mode.dev_attr.attr, + NULL +}; + + + +static const struct attribute_group xadc_group = { + .attrs = xadc_attr, +}; + +static irqreturn_t xadc_irq(int irq, void *data) +{ + struct xadc_t *xadc = data; + u32 intsts, intmsk; + + + intsts = READ(xadc, INTSTS); + intmsk = READ(xadc, INTMSK); + dev_dbg(xadc->dev, "intsts %08x intmsk %08x\n", intsts, intmsk); + + if (intsts & ~intmsk & XADC_INT_DFIFO_GTH) { + + while (!(READ(xadc, STATUS) & XADC_STATUS_DFIFO_EMPTY)) + xadc->curr->ops[xadc->curr->readptr++].res = + READ(xadc, DFIFO); + if ((xadc->curr->readptr) == xadc->curr->count) { + intmsk |= XADC_INT_DFIFO_GTH; + WRITE(xadc, INTMSK, intmsk); + complete(&xadc->curr->comp); + run_batch(xadc); + } else { + u32 config; + int rdt; + + config = READ(xadc, CONFIG); + config = CLRFIELD(XADC_CONFIG, DFIFOTH, config); + rdt = xadc->curr->count-xadc->curr->readptr; + if (rdt > 15) + rdt = 8; + else + rdt--; + config |= SETFIELD(XADC_CONFIG, DFIFOTH, rdt); + WRITE(xadc, CONFIG, config); + } + WRITE(xadc, INTSTS, XADC_INT_DFIFO_GTH); + } + + if (intsts & ~intmsk & XADC_INT_CFIFO_LTH) { + int i, towrite; + u32 status = READ(xadc, STATUS); + + /*Don't write more than FIFO capacity*/ + towrite = xadc->curr->count - xadc->curr->writeptr; + towrite = (15 - GETFIELD(XADC_STATUS, CFIFO_LVL, status)); + towrite = min(towrite, + xadc->curr->count - xadc->curr->writeptr); + + for (i = 0; i < towrite; i++) + WRITE(xadc, CFIFO, + xadc->curr->ops[xadc->curr->writeptr++].cmd); + + if (xadc->curr->writeptr == xadc->curr->count) { + intmsk |= XADC_INT_CFIFO_LTH; + WRITE(xadc, INTMSK, intmsk); + } else { + u32 config; + int cmdt; + config = READ(xadc, CONFIG); + config = CLRFIELD(XADC_CONFIG, CFIFOTH, config); + cmdt = xadc->curr->count-xadc->curr->writeptr; + if (cmdt > 8) /* Half-full */ + cmdt = 8; + else /* Will write all next time */ + cmdt--; + config |= SETFIELD(XADC_CONFIG, CFIFOTH, cmdt); + WRITE(xadc, CONFIG, config); + } + WRITE(xadc, INTSTS, XADC_INT_CFIFO_LTH); + } + + return IRQ_HANDLED; +} + +static struct xadc_op xadc_ops[] = { + {.cmd = WRITEOP(REG_CFG1, REG_CFG1_CAL_SSOG | + REG_CFG1_CAL_ADCOG | + SETFIELD(REG_CFG1, SEQ, MODE_DEF)),}, + {.cmd = READOP(REG_FLAG),}, /* read flags */ + {.cmd = WRITEOP(REG_SEQ_SEL0, 0)}, + {.cmd = WRITEOP(REG_SEQ_AVG0, 0)}, + {.cmd = WRITEOP(REG_SEQ_BIP0, 0)}, + {.cmd = WRITEOP(REG_SEQ_ACQ0, 0)}, + {.cmd = WRITEOP(REG_SEQ_SEL1, 0)}, + {.cmd = WRITEOP(REG_SEQ_AVG1, 0)}, + {.cmd = WRITEOP(REG_SEQ_BIP1, 0)}, + {.cmd = WRITEOP(REG_SEQ_ACQ1, 0)}, + {.cmd = WRITEOP(REG_CFG1, REG_CFG1_CAL_SSOG | REG_CFG1_CAL_ADCOG | + SETFIELD(REG_CFG1, SEQ, MODE_IND)),}, +}; +static struct xadc_batch setup = { + .count = ARRAY_SIZE(xadc_ops), + .ops = xadc_ops, +}; + +static int xadc_probe(struct platform_device *pdev) +{ + struct xadc_t *xadc; + struct resource *res; + u16 val; + int ret; + + xadc = devm_kzalloc(&pdev->dev, sizeof(*xadc), GFP_KERNEL); + if (!xadc) + return -ENOMEM; + + xadc->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xadc->iobase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xadc->iobase)) + return PTR_ERR(xadc->iobase); + + xadc->irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, xadc->irq, &xadc_irq, IRQF_SHARED, + dev_name(&pdev->dev), xadc); + if (ret) { + dev_err(xadc->dev, "Failed to request irq: %d\n", xadc->irq); + return ret; + } + + xadc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(xadc->clk)) { + dev_err(&pdev->dev, "input clock not found\n"); + return PTR_ERR(xadc->clk); + } + + ret = clk_prepare_enable(xadc->clk); + if (ret) { + dev_err(&pdev->dev, "unable to enable clock\n"); + return ret; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &xadc_group); + if (ret) + goto err_clk_disable; + + platform_set_drvdata(pdev, xadc); + + xadc->hwmon = hwmon_device_register(&pdev->dev); + if (IS_ERR(xadc->hwmon)) { + ret = PTR_ERR(xadc->hwmon); + dev_err(xadc->dev, "Failed to register hwmon device\n"); + goto err_group; + } + + WRITE(xadc, CONFIG, 0); + WRITE(xadc, CTL, 0); /* ~RESET */ + + WRITE(xadc, CONFIG, XADC_CONFIG_WEDGE | /* Default values */ + XADC_CONFIG_REDGE | + SETFIELD(XADC_CONFIG, TCKRATE, TCKRATE_DIV16) | + SETFIELD(XADC_CONFIG, IGAP, 20)); + + WRITE(xadc, CONFIG, READ(xadc, CONFIG) | XADC_CONFIG_ENABLE); + + WRITE(xadc, INTSTS, ~0); /* clear all interrupts */ + WRITE(xadc, INTMSK, ~0); /* mask all interrupts */ + + INIT_LIST_HEAD(&xadc->runq); + spin_lock_init(&xadc->slock); + + add_batch(xadc, &setup); + wait_for_completion_interruptible(&setup.comp); + + val = setup.ops[2].res; + dev_info(xadc->dev, "enabled:\t%s\treference:\t%s\n", + val & REG_FLAG_DIS ? "no" : "yes", + val & REG_FLAG_REF ? "internal" : "external"); + + clk_disable(xadc->clk); + + return 0; + +err_group: + sysfs_remove_group(&pdev->dev.kobj, &xadc_group); +err_clk_disable: + clk_disable_unprepare(xadc->clk); + + return ret; +} + +static int xadc_remove(struct platform_device *pdev) +{ + struct xadc_t *xadc = platform_get_drvdata(pdev); + + hwmon_device_unregister(xadc->hwmon); + + sysfs_remove_group(&pdev->dev.kobj, &xadc_group); + + clk_unprepare(xadc->clk); + + return 0; +} + +static struct of_device_id xadcps_of_match[] = { + { .compatible = "xlnx,ps7-xadc-1.00.a", }, + { /* end of table */} +}; +MODULE_DEVICE_TABLE(of, xadcps_of_match); + +static struct platform_driver xadc_driver = { + .probe = xadc_probe, + .remove = xadc_remove, + .driver = { + .name = "xadcps", + .owner = THIS_MODULE, + .of_match_table = xadcps_of_match, + }, +}; + +module_platform_driver(xadc_driver); + +MODULE_AUTHOR("Vlad Lungu <vlad.lungu@windriver.com>"); +MODULE_DESCRIPTION("Xilinx Zynq XADC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:xadcps"); Index: linux-3.12.24-rt38-xilinx/drivers/i2c/busses/i2c-xiic.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/i2c/busses/i2c-xiic.c 2014-07-20 22:05:50.248066423 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/i2c/busses/i2c-xiic.c 2014-07-20 22:06:36.420304662 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:35 @ #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> +#include <linux/err.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/i2c.h> @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:72 @ struct i2c_adapter adap; struct i2c_msg *tx_msg; spinlock_t lock; - unsigned int tx_pos; + unsigned int tx_pos; unsigned int nmsgs; enum xilinx_i2c_state state; struct i2c_msg *rx_msg; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:275 @ bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1; - dev_dbg(i2c->adap.dev.parent, "%s entry, bytes in fifo: %d, msg: %d" - ", SR: 0x%x, CR: 0x%x\n", - __func__, bytes_in_fifo, xiic_rx_space(i2c), - xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), - xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + dev_dbg(i2c->adap.dev.parent, "%s entry, bytes in fifo: %d, msg: %d", + __func__, bytes_in_fifo, xiic_rx_space(i2c)); if (bytes_in_fifo > xiic_rx_space(i2c)) bytes_in_fifo = xiic_rx_space(i2c); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:340 @ ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); pend = isr & ier; - dev_dbg(i2c->adap.dev.parent, "%s entry, IER: 0x%x, ISR: 0x%x, " - "pend: 0x%x, SR: 0x%x, msg: %p, nmsgs: %d\n", - __func__, ier, isr, pend, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), + dev_dbg(i2c->adap.dev.parent, "%s: IER: 0x%x, ISR: 0x%x, pend: 0x%x\n", + __func__, ier, isr, pend); + dev_dbg(i2c->adap.dev.parent, "%s: SR: 0x%x, msg: %p, nmsgs: %d\n", + __func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), i2c->tx_msg, i2c->nmsgs); /* Do not processes a devices interrupts if the device has no @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:543 @ xiic_irq_clr(i2c, XIIC_INTR_TX_ERROR_MASK); - dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d, " - "ISR: 0x%x, CR: 0x%x\n", - __func__, msg, msg->len, xiic_getreg32(i2c, XIIC_IISR_OFFSET), + dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d", + __func__, msg, msg->len); + dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", + __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); if (!(msg->flags & I2C_M_NOSTART)) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:697 @ int ret, irq; u8 i; + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - goto resource_missing; + i2c->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->base)) { + dev_err(&pdev->dev, "Could not allocate iomem\n"); + return PTR_ERR(i2c->base); + } irq = platform_get_irq(pdev, 0); if (irq < 0) - goto resource_missing; - - pdata = (struct xiic_i2c_platform_data *)dev_get_platdata(&pdev->dev); - - i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); - if (!i2c) - return -ENOMEM; + return irq; - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "Memory region busy\n"); - ret = -EBUSY; - goto request_mem_failed; + ret = devm_request_irq(&pdev->dev, irq, xiic_isr, 0, pdev->name, i2c); + if (ret < 0) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + return ret; } - i2c->base = ioremap(res->start, resource_size(res)); - if (!i2c->base) { - dev_err(&pdev->dev, "Unable to map registers\n"); - ret = -EIO; - goto map_failed; - } + pdata = (struct xiic_i2c_platform_data *)dev_get_platdata(&pdev->dev); /* hook up driver to tree */ platform_set_drvdata(pdev, i2c); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:731 @ spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - ret = request_irq(irq, xiic_isr, 0, pdev->name, i2c); - if (ret) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto request_irq_failed; - } /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); if (ret) { dev_err(&pdev->dev, "Failed to add adapter\n"); - goto add_adapter_failed; + return ret; } if (pdata) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:746 @ } return 0; - -add_adapter_failed: - free_irq(irq, i2c); -request_irq_failed: - xiic_deinit(i2c); - iounmap(i2c->base); -map_failed: - release_mem_region(res->start, resource_size(res)); -request_mem_failed: - kfree(i2c); - - return ret; -resource_missing: - dev_err(&pdev->dev, "IRQ or Memory resource is missing\n"); - return -ENOENT; } static int xiic_i2c_remove(struct platform_device *pdev) { struct xiic_i2c *i2c = platform_get_drvdata(pdev); - struct resource *res; /* remove adapter & data */ i2c_del_adapter(&i2c->adap); xiic_deinit(i2c); - free_irq(platform_get_irq(pdev, 0), i2c); - - iounmap(i2c->base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - - kfree(i2c); - return 0; } Index: linux-3.12.24-rt38-xilinx/drivers/i2c/busses/i2c-zynq.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/i2c/busses/i2c-zynq.c 2014-07-20 22:06:36.436304398 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx I2C bus driver for the Zynq I2C Interfaces. + * + * 2009-2011 (c) Xilinx, Inc. + * + * 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. + * + * 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., 675 Mass Ave, Cambridge, MA + * 02139, USA. + * + * + * Workaround in Receive Mode + * If there is only one message to be processed, then based on length of + * the message we set the HOLD bit. + * If the length is less than the FIFO depth, then we will directly + * receive a COMP interrupt and the transaction is done. + * If the length is more than the FIFO depth, then we enable the HOLD bit. + * if the requested data is greater than the max transfer size(252 bytes) + * update the transfer size register with max transfer size else update + * with the requested size. + * We will receive the DATA interrupt, if the transfer size register value + * is zero then repeat the above step for the remaining bytes (if any) and + * process the data in the fifo. + * + * The bus hold flag logic provides support for repeated start. + * + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/export.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* + * Register Map + * Register offsets for the I2C device. + */ +#define XI2CPS_CR_OFFSET 0x00 /* Control Register, RW */ +#define XI2CPS_SR_OFFSET 0x04 /* Status Register, RO */ +#define XI2CPS_ADDR_OFFSET 0x08 /* I2C Address Register, RW */ +#define XI2CPS_DATA_OFFSET 0x0C /* I2C Data Register, RW */ +#define XI2CPS_ISR_OFFSET 0x10 /* Interrupt Status Register, RW */ +#define XI2CPS_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */ +#define XI2CPS_SLV_PAUSE_OFFSET 0x18 /* Slave monitor pause Register, RW */ +#define XI2CPS_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */ +#define XI2CPS_IMR_OFFSET 0x20 /* Interrupt Mask Register, RO */ +#define XI2CPS_IER_OFFSET 0x24 /* Interrupt Enable Register, WO */ +#define XI2CPS_IDR_OFFSET 0x28 /* Interrupt Disable Register, WO */ + +/* + * Control Register Bit mask definitions + * This register contains various control bits that affect the operation of the + * I2C controller. + */ +#define XI2CPS_CR_HOLD_BUS_MASK 0x00000010 /* Hold Bus bit */ +#define XI2CPS_CR_RW_MASK 0x00000001 /* Read or Write Master transfer + * 0= Transmitter, 1= Receiver */ +#define XI2CPS_CR_CLR_FIFO_MASK 0x00000040 /* 1 = Auto init FIFO to zeroes */ + +/* + * I2C Address Register Bit mask definitions + * Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0] + * bits. A write access to this register always initiates a transfer if the I2C + * is in master mode. + */ +#define XI2CPS_ADDR_MASK 0x000003FF /* I2C Address Mask */ + +/* + * I2C Interrupt Registers Bit mask definitions + * All the four interrupt registers (Status/Mask/Enable/Disable) have the same + * bit definitions. + */ +#define XI2CPS_IXR_ALL_INTR_MASK 0x000002FF /* All ISR Mask */ + +#define XI2CPS_FIFO_DEPTH 16 /* FIFO Depth */ +#define XI2CPS_TIMEOUT (50 * HZ) /* Timeout for bus busy check */ +#define XI2CPS_ENABLED_INTR 0x2EF /* Enabled Interrupts */ + +#define XI2CPS_DATA_INTR_DEPTH (XI2CPS_FIFO_DEPTH - 2)/* FIFO depth at which + * the DATA interrupt + * occurs + */ +#define XI2CPS_MAX_TRANSFER_SIZE 255 /* Max transfer size */ +#define XI2CPS_TRANSFER_SIZE (XI2CPS_MAX_TRANSFER_SIZE - 3) /* Transfer size + in multiples of data interrupt depth */ + +#define DRIVER_NAME "xi2cps" + +#define xi2cps_readreg(offset) __raw_readl(id->membase + offset) +#define xi2cps_writereg(val, offset) __raw_writel(val, id->membase + offset) + +/** + * struct xi2cps - I2C device private data structure + * @membase: Base address of the I2C device + * @adap: I2C adapter instance + * @p_msg: Message pointer + * @err_status: Error status in Interrupt Status Register + * @xfer_done: Transfer complete status + * @p_send_buf: Pointer to transmit buffer + * @p_recv_buf: Pointer to receive buffer + * @suspended: Flag holding the device's PM status + * @send_count: Number of bytes still expected to send + * @recv_count: Number of bytes still expected to receive + * @irq: IRQ number + * @cur_timeout: The current timeout value used by the device + * @input_clk: Input clock to I2C controller + * @i2c_clk: Current I2C frequency + * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit + * @clk: Pointer to struct clk + * @clk_rate_change_nb: Notifier block for clock rate changes + */ +struct xi2cps { + void __iomem *membase; + struct i2c_adapter adap; + struct i2c_msg *p_msg; + int err_status; + struct completion xfer_done; + unsigned char *p_send_buf; + unsigned char *p_recv_buf; + u8 suspended; + int send_count; + int recv_count; + int irq; + int cur_timeout; + unsigned int input_clk; + unsigned int i2c_clk; + unsigned int bus_hold_flag; + struct clk *clk; + struct notifier_block clk_rate_change_nb; +}; + +#define to_xi2cps(_nb) container_of(_nb, struct xi2cps, clk_rate_change_nb) +#define MAX_F_ERR 10000 + +/** + * xi2cps_isr - Interrupt handler for the I2C device + * @irq: irq number for the I2C device + * @ptr: void pointer to xi2cps structure + * + * Returns IRQ_HANDLED always + * + * This function handles the data interrupt, transfer complete interrupt and + * the error interrupts of the I2C device. + */ +static irqreturn_t xi2cps_isr(int irq, void *ptr) +{ + unsigned int isr_status, avail_bytes; + unsigned int bytes_to_recv, bytes_to_send; + unsigned int ctrl_reg = 0; + struct xi2cps *id = ptr; + + isr_status = xi2cps_readreg(XI2CPS_ISR_OFFSET); + + /* Handling Nack interrupt */ + if (isr_status & 0x00000004) + complete(&id->xfer_done); + + /* Handling Arbitration lost interrupt */ + if (isr_status & 0x00000200) + complete(&id->xfer_done); + + /* Handling Data interrupt */ + if (isr_status & 0x00000002) { + if (id->recv_count >= XI2CPS_DATA_INTR_DEPTH) { + /* Always read data interrupt threshold bytes */ + bytes_to_recv = XI2CPS_DATA_INTR_DEPTH; + id->recv_count = id->recv_count - + XI2CPS_DATA_INTR_DEPTH; + avail_bytes = xi2cps_readreg(XI2CPS_XFER_SIZE_OFFSET); + /* + * if the tranfer size register value is zero, then + * check for the remaining bytes and update the + * transfer size register. + */ + if (avail_bytes == 0) { + if (id->recv_count > XI2CPS_TRANSFER_SIZE) + xi2cps_writereg(XI2CPS_TRANSFER_SIZE, + XI2CPS_XFER_SIZE_OFFSET); + else + xi2cps_writereg(id->recv_count, + XI2CPS_XFER_SIZE_OFFSET); + } + /* Process the data received */ + while (bytes_to_recv) { + *(id->p_recv_buf)++ = + xi2cps_readreg(XI2CPS_DATA_OFFSET); + bytes_to_recv = bytes_to_recv - 1; + } + + if ((id->bus_hold_flag == 0) && + (id->recv_count <= XI2CPS_FIFO_DEPTH)) { + /* Clear the hold bus bit */ + xi2cps_writereg( + (xi2cps_readreg(XI2CPS_CR_OFFSET) & + (~XI2CPS_CR_HOLD_BUS_MASK)), + XI2CPS_CR_OFFSET); + } + } + } + + /* Handling Transfer Complete interrupt */ + if (isr_status & 0x00000001) { + if ((id->p_recv_buf) == NULL) { + /* + * If the device is sending data If there is further + * data to be sent. Calculate the available space + * in FIFO and fill the FIFO with that many bytes. + */ + if (id->send_count > 0) { + avail_bytes = XI2CPS_FIFO_DEPTH - + xi2cps_readreg(XI2CPS_XFER_SIZE_OFFSET); + if (id->send_count > avail_bytes) + bytes_to_send = avail_bytes; + else + bytes_to_send = id->send_count; + + while (bytes_to_send--) { + xi2cps_writereg( + (*(id->p_send_buf)++), + XI2CPS_DATA_OFFSET); + id->send_count--; + } + } else { + /* + * Signal the completion of transaction and + * clear the hold bus bit if there are no + * further messages to be processed. + */ + complete(&id->xfer_done); + } + if (id->send_count == 0) { + if (id->bus_hold_flag == 0) { + /* Clear the hold bus bit */ + ctrl_reg = + xi2cps_readreg(XI2CPS_CR_OFFSET); + if ((ctrl_reg & XI2CPS_CR_HOLD_BUS_MASK) + == XI2CPS_CR_HOLD_BUS_MASK) + xi2cps_writereg( + (ctrl_reg & + (~XI2CPS_CR_HOLD_BUS_MASK)), + XI2CPS_CR_OFFSET); + } + } + } else { + if (id->bus_hold_flag == 0) { + /* Clear the hold bus bit */ + ctrl_reg = + xi2cps_readreg(XI2CPS_CR_OFFSET); + if ((ctrl_reg & XI2CPS_CR_HOLD_BUS_MASK) + == XI2CPS_CR_HOLD_BUS_MASK) + xi2cps_writereg( + (ctrl_reg & + (~XI2CPS_CR_HOLD_BUS_MASK)), + XI2CPS_CR_OFFSET); + } + /* + * If the device is receiving data, then signal + * the completion of transaction and read the data + * present in the FIFO. Signal the completion of + * transaction. + */ + while (xi2cps_readreg(XI2CPS_SR_OFFSET) + & 0x00000020) { + *(id->p_recv_buf)++ = + xi2cps_readreg(XI2CPS_DATA_OFFSET); + id->recv_count--; + } + complete(&id->xfer_done); + } + } + + /* Update the status for errors */ + id->err_status = isr_status & 0x000002EC; + xi2cps_writereg(isr_status, XI2CPS_ISR_OFFSET); + return IRQ_HANDLED; +} + +/** + * xi2cps_mrecv - Prepare and start a master receive operation + * @id: pointer to the i2c device structure + * + */ +static void xi2cps_mrecv(struct xi2cps *id) +{ + unsigned int ctrl_reg; + unsigned int isr_status; + + id->p_recv_buf = id->p_msg->buf; + id->recv_count = id->p_msg->len; + + /* + * Set the controller in master receive mode and clear the FIFO. + * Set the slave address in address register. + * Check for the message size against FIFO depth and set the + * HOLD bus bit if it is more than FIFO depth. + * Clear the interrupts in interrupt status register. + */ + ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET); + ctrl_reg |= (XI2CPS_CR_RW_MASK | XI2CPS_CR_CLR_FIFO_MASK); + + if ((id->p_msg->flags & I2C_M_RECV_LEN) == I2C_M_RECV_LEN) + id->recv_count = I2C_SMBUS_BLOCK_MAX + 1; + + if (id->recv_count > XI2CPS_FIFO_DEPTH) + ctrl_reg |= XI2CPS_CR_HOLD_BUS_MASK; + + xi2cps_writereg(ctrl_reg, XI2CPS_CR_OFFSET); + + isr_status = xi2cps_readreg(XI2CPS_ISR_OFFSET); + xi2cps_writereg(isr_status, XI2CPS_ISR_OFFSET); + + xi2cps_writereg((id->p_msg->addr & XI2CPS_ADDR_MASK), + XI2CPS_ADDR_OFFSET); + /* + * The no. of bytes to receive is checked against the limit of + * max transfer size. Set transfer size register with no of bytes + * receive if it is less than transfer size and transfer size if + * it is more. Enable the interrupts. + */ + if (id->recv_count > XI2CPS_TRANSFER_SIZE) + xi2cps_writereg(XI2CPS_TRANSFER_SIZE, XI2CPS_XFER_SIZE_OFFSET); + else + xi2cps_writereg(id->recv_count, XI2CPS_XFER_SIZE_OFFSET); + /* + * Clear the bus hold flag if bytes to receive is less than FIFO size. + */ + if (id->bus_hold_flag == 0 && + ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && + (id->recv_count <= XI2CPS_FIFO_DEPTH)) { + /* Clear the hold bus bit */ + ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET); + if ((ctrl_reg & XI2CPS_CR_HOLD_BUS_MASK) == + XI2CPS_CR_HOLD_BUS_MASK) + xi2cps_writereg( + (ctrl_reg & (~XI2CPS_CR_HOLD_BUS_MASK)), + XI2CPS_CR_OFFSET); + } + xi2cps_writereg(XI2CPS_ENABLED_INTR, XI2CPS_IER_OFFSET); +} + +/** + * xi2cps_msend - Prepare and start a master send operation + * @id: pointer to the i2c device + */ +static void xi2cps_msend(struct xi2cps *id) +{ + unsigned int avail_bytes; + unsigned int bytes_to_send; + unsigned int ctrl_reg; + unsigned int isr_status; + + id->p_recv_buf = NULL; + id->p_send_buf = id->p_msg->buf; + id->send_count = id->p_msg->len; + + /* + * Set the controller in Master transmit mode and clear the FIFO. + * Set the slave address in address register. + * Check for the message size against FIFO depth and set the + * HOLD bus bit if it is more than FIFO depth. + * Clear the interrupts in interrupt status register. + */ + ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET); + ctrl_reg &= ~XI2CPS_CR_RW_MASK; + ctrl_reg |= XI2CPS_CR_CLR_FIFO_MASK; + + if ((id->send_count) > XI2CPS_FIFO_DEPTH) + ctrl_reg |= XI2CPS_CR_HOLD_BUS_MASK; + xi2cps_writereg(ctrl_reg, XI2CPS_CR_OFFSET); + + isr_status = xi2cps_readreg(XI2CPS_ISR_OFFSET); + xi2cps_writereg(isr_status, XI2CPS_ISR_OFFSET); + + /* + * Calculate the space available in FIFO. Check the message length + * against the space available, and fill the FIFO accordingly. + * Enable the interrupts. + */ + avail_bytes = XI2CPS_FIFO_DEPTH - + xi2cps_readreg(XI2CPS_XFER_SIZE_OFFSET); + + if (id->send_count > avail_bytes) + bytes_to_send = avail_bytes; + else + bytes_to_send = id->send_count; + + while (bytes_to_send--) { + xi2cps_writereg((*(id->p_send_buf)++), XI2CPS_DATA_OFFSET); + id->send_count--; + } + + xi2cps_writereg((id->p_msg->addr & XI2CPS_ADDR_MASK), + XI2CPS_ADDR_OFFSET); + + /* + * Clear the bus hold flag if there is no more data + * and if it is the last message. + */ + if (id->bus_hold_flag == 0 && id->send_count == 0) { + /* Clear the hold bus bit */ + ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET); + if ((ctrl_reg & XI2CPS_CR_HOLD_BUS_MASK) == + XI2CPS_CR_HOLD_BUS_MASK) + xi2cps_writereg( + (ctrl_reg & (~XI2CPS_CR_HOLD_BUS_MASK)), + XI2CPS_CR_OFFSET); + } + xi2cps_writereg(XI2CPS_ENABLED_INTR, XI2CPS_IER_OFFSET); +} + +/** + * xi2cps_master_reset - Reset the interface + * @adap: pointer to the i2c adapter driver instance + * + * Returns none + * + * This function cleanup the fifos, clear the hold bit and status + * and disable the interrupts. + */ +static void xi2cps_master_reset(struct i2c_adapter *adap) +{ + struct xi2cps *id = adap->algo_data; + u32 regval; + + /* Disable the interrupts */ + xi2cps_writereg(XI2CPS_IXR_ALL_INTR_MASK, XI2CPS_IDR_OFFSET); + /* Clear the hold bit and fifos */ + regval = xi2cps_readreg(XI2CPS_CR_OFFSET); + regval &= ~XI2CPS_CR_HOLD_BUS_MASK; + regval |= XI2CPS_CR_CLR_FIFO_MASK; + xi2cps_writereg(regval, XI2CPS_CR_OFFSET); + /* Update the transfercount register to zero */ + xi2cps_writereg(0x0, XI2CPS_XFER_SIZE_OFFSET); + /* Clear the interupt status register */ + regval = xi2cps_readreg(XI2CPS_ISR_OFFSET); + xi2cps_writereg(regval, XI2CPS_ISR_OFFSET); + /* Clear the status register */ + regval = xi2cps_readreg(XI2CPS_SR_OFFSET); + xi2cps_writereg(regval, XI2CPS_SR_OFFSET); +} + +/** + * xi2cps_master_xfer - The main i2c transfer function + * @adap: pointer to the i2c adapter driver instance + * @msgs: pointer to the i2c message structure + * @num: the number of messages to transfer + * + * Returns number of msgs processed on success, negative error otherwise + * + * This function waits for the bus idle condition and updates the timeout if + * modified by user. Then initiates the send/recv activity based on the + * transfer message received. + */ +static int xi2cps_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct xi2cps *id = adap->algo_data; + unsigned int count, retries; + unsigned long timeout; + int ret; + + /* Waiting for bus-ready. If bus not ready, it returns after timeout */ + timeout = jiffies + XI2CPS_TIMEOUT; + while ((xi2cps_readreg(XI2CPS_SR_OFFSET)) & 0x00000100) { + if (time_after(jiffies, timeout)) { + dev_warn(id->adap.dev.parent, + "timedout waiting for bus ready\n"); + xi2cps_master_reset(adap); + return -ETIMEDOUT; + } + schedule_timeout(1); + } + + /* The bus is free. Set the new timeout value if updated */ + if (id->adap.timeout != id->cur_timeout) { + xi2cps_writereg((id->adap.timeout & 0xFF), + XI2CPS_TIME_OUT_OFFSET); + id->cur_timeout = id->adap.timeout; + } + + /* + * Set the flag to one when multiple messages are to be + * processed with a repeated start. + */ + if (num > 1) { + id->bus_hold_flag = 1; + xi2cps_writereg((xi2cps_readreg(XI2CPS_CR_OFFSET) | + XI2CPS_CR_HOLD_BUS_MASK), XI2CPS_CR_OFFSET); + } else { + id->bus_hold_flag = 0; + } + + /* Process the msg one by one */ + for (count = 0; count < num; count++, msgs++) { + + if (count == (num - 1)) + id->bus_hold_flag = 0; + retries = adap->retries; +retry: + id->err_status = 0; + id->p_msg = msgs; + init_completion(&id->xfer_done); + + /* Check for the TEN Bit mode on each msg */ + if (msgs->flags & I2C_M_TEN) { + xi2cps_writereg((xi2cps_readreg(XI2CPS_CR_OFFSET) & + (~0x00000004)), XI2CPS_CR_OFFSET); + } else { + if ((xi2cps_readreg(XI2CPS_CR_OFFSET) & 0x00000004) + == 0) + xi2cps_writereg( + (xi2cps_readreg(XI2CPS_CR_OFFSET) | + (0x00000004)), XI2CPS_CR_OFFSET); + } + + /* Check for the R/W flag on each msg */ + if (msgs->flags & I2C_M_RD) + xi2cps_mrecv(id); + else + xi2cps_msend(id); + + /* Wait for the signal of completion */ + ret = wait_for_completion_interruptible_timeout( + &id->xfer_done, HZ); + if (ret == 0) { + dev_err(id->adap.dev.parent, + "timeout waiting on completion\n"); + xi2cps_master_reset(adap); + return -ETIMEDOUT; + } + xi2cps_writereg(XI2CPS_IXR_ALL_INTR_MASK, XI2CPS_IDR_OFFSET); + + /* If it is bus arbitration error, try again */ + if (id->err_status & 0x00000200) { + dev_dbg(id->adap.dev.parent, + "Lost ownership on bus, trying again\n"); + if (retries--) { + mdelay(2); + goto retry; + } + dev_err(id->adap.dev.parent, + "Retries completed, exit\n"); + num = -EREMOTEIO; + break; + } + /* Report the other error interrupts to application as EIO */ + if (id->err_status & 0x000000E4) { + xi2cps_master_reset(adap); + num = -EIO; + break; + } + } + + id->p_msg = NULL; + id->err_status = 0; + + return num; +} + +/** + * xi2cps_func - Returns the supported features of the I2C driver + * @adap: pointer to the i2c adapter structure + * + * Returns 32 bit value, each bit corresponding to a feature + */ +static u32 xi2cps_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | + (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm xi2cps_algo = { + .master_xfer = xi2cps_master_xfer, + .functionality = xi2cps_func, +}; + +/** + * xi2cps_calc_divs() - Calculate clock dividers + * @f: I2C clock frequency + * @input_clk: Input clock frequency + * @a: First divider (return value) + * @b: Second divider (return value) + * @err: Frequency error + * Return 0 on success, negative errno otherwise. + * + * f is used as input and output variable. As input it is used as target I2C + * frequency. On function exit f holds the actually resulting I2C frequency. + */ +static int xi2cps_calc_divs(unsigned int *f, unsigned int input_clk, + unsigned int *a, unsigned int *b, unsigned int *err) +{ + unsigned int fscl = *f; + unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0; + unsigned int last_error, current_error; + unsigned int best_fscl = *f, actual_fscl, temp; + + /* calculate (divisor_a+1) x (divisor_b+1) */ + temp = input_clk / (22 * fscl); + + /* + * If the calculated value is negative or 0, the fscl input is out of + * range. Return error. + */ + if (!temp) + return -EINVAL; + + last_error = -1; + for (div_b = 0; div_b < 64; div_b++) { + div_a = input_clk / (22 * fscl * (div_b + 1)); + + if (div_a != 0) + div_a = div_a - 1; + + if (div_a > 3) + continue; + + actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1)); + + current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) : + (fscl - actual_fscl)); + + if (last_error > current_error) { + calc_div_a = div_a; + calc_div_b = div_b; + best_fscl = actual_fscl; + last_error = current_error; + } + } + + *err = last_error; + *a = calc_div_a; + *b = calc_div_b; + *f = best_fscl; + + return 0; +} + +/** + * xi2cps_setclk - This function sets the serial clock rate for the I2C device + * @fscl: The clock frequency in Hz + * @id: Pointer to the I2C device structure + * + * Returns zero on success, negative error otherwise + * + * The device must be idle rather than busy transferring data before setting + * these device options. + * The data rate is set by values in the control register. + * The formula for determining the correct register values is + * Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1)) + * See the hardware data sheet for a full explanation of setting the serial + * clock rate. The clock can not be faster than the input clock divide by 22. + * The two most common clock rates are 100KHz and 400KHz. + */ +static int xi2cps_setclk(unsigned int fscl, struct xi2cps *id) +{ + unsigned int div_a, div_b; + unsigned int ctrl_reg; + unsigned int err; + int ret = 0; + + ret = xi2cps_calc_divs(&fscl, id->input_clk, &div_a, &div_b, &err); + if (ret) + return ret; + + ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET); + ctrl_reg &= ~(0x0000C000 | 0x00003F00); + ctrl_reg |= ((div_a << 14) | (div_b << 8)); + xi2cps_writereg(ctrl_reg, XI2CPS_CR_OFFSET); + + return 0; +} + +/** + * xi2cps_clk_notifier_cb - Clock rate change callback + * @nb: Pointer to notifier block + * @event: Notification reason + * @data: Pointer to notification data object + * Returns NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK + * otherwise. + * + * This function is called when the xi2cps input clock frequency changes. In the + * pre-rate change notification here it is determined if the rate change may be + * allowed or not. + * In th post-change case necessary adjustments are conducted. + */ +static int xi2cps_clk_notifier_cb(struct notifier_block *nb, unsigned long + event, void *data) +{ + struct clk_notifier_data *ndata = data; + struct xi2cps *id = to_xi2cps(nb); + + if (id->suspended) + return NOTIFY_OK; + + switch (event) { + case PRE_RATE_CHANGE: + { + /* + * if a rate change is announced we need to check whether we can + * maintain the current frequency by changing the clock + * dividers. Probably we could also define an acceptable + * frequency range. + */ + unsigned int input_clk = (unsigned int)ndata->new_rate; + unsigned int fscl = id->i2c_clk; + unsigned int div_a, div_b; + unsigned int err = 0; + int ret; + + ret = xi2cps_calc_divs(&fscl, input_clk, &div_a, &div_b, &err); + if (ret) + return NOTIFY_STOP; + if (err > MAX_F_ERR) + return NOTIFY_STOP; + + return NOTIFY_OK; + } + case POST_RATE_CHANGE: + id->input_clk = ndata->new_rate; + /* We probably need to stop the HW before this and restart + * afterwards */ + xi2cps_setclk(id->i2c_clk, id); + return NOTIFY_OK; + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +#ifdef CONFIG_PM_SLEEP +/** + * xi2cps_suspend - Suspend method for the driver + * @_dev: Address of the platform_device structure + * Returns 0 on success and error value on error + * + * Put the driver into low power mode. + */ +static int xi2cps_suspend(struct device *_dev) +{ + struct platform_device *pdev = container_of(_dev, + struct platform_device, dev); + struct xi2cps *xi2c = platform_get_drvdata(pdev); + + clk_disable(xi2c->clk); + xi2c->suspended = 1; + + return 0; +} + +/** + * xi2cps_resume - Resume from suspend + * @_dev: Address of the platform_device structure + * Returns 0 on success and error value on error + * + * Resume operation after suspend. + */ +static int xi2cps_resume(struct device *_dev) +{ + struct platform_device *pdev = container_of(_dev, + struct platform_device, dev); + struct xi2cps *xi2c = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(xi2c->clk); + if (ret) { + dev_err(_dev, "Cannot enable clock.\n"); + return ret; + } + + xi2c->suspended = 0; + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(xi2cps_dev_pm_ops, xi2cps_suspend, xi2cps_resume); + +/************************/ +/* Platform bus binding */ +/************************/ + +/** + * xi2cps_probe - Platform registration call + * @pdev: Handle to the platform device structure + * + * Returns zero on success, negative error otherwise + * + * This function does all the memory allocation and registration for the i2c + * device. User can modify the address mode to 10 bit address mode using the + * ioctl call with option I2C_TENBIT. + */ +static int xi2cps_probe(struct platform_device *pdev) +{ + struct resource *r_mem = NULL; + struct xi2cps *id; + int ret = 0; + const unsigned int *prop; + /* + * Allocate memory for xi2cps structure. + * Initialize the structure to zero and set the platform data. + * Obtain the resource base address from platform data and remap it. + * Get the irq resource from platform data.Initialize the adapter + * structure members and also xi2cps structure. + */ + id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL); + if (!id) + return -ENOMEM; + + platform_set_drvdata(pdev, id); + + r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + id->membase = devm_ioremap_resource(&pdev->dev, r_mem); + if (IS_ERR(id->membase)) + return PTR_ERR(id->membase); + + id->irq = platform_get_irq(pdev, 0); + + prop = of_get_property(pdev->dev.of_node, "bus-id", NULL); + if (prop) { + id->adap.nr = be32_to_cpup(prop); + } else { + dev_err(&pdev->dev, "couldn't determine bus-id\n"); + return -ENXIO; + } + id->adap.dev.of_node = pdev->dev.of_node; + id->adap.algo = (struct i2c_algorithm *) &xi2cps_algo; + id->adap.timeout = 0x1F; /* Default timeout value */ + id->adap.retries = 3; /* Default retry value. */ + id->adap.algo_data = id; + id->adap.dev.parent = &pdev->dev; + snprintf(id->adap.name, sizeof(id->adap.name), + "XILINX I2C at %08lx", (unsigned long)r_mem->start); + + id->cur_timeout = id->adap.timeout; + id->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(id->clk)) { + dev_err(&pdev->dev, "input clock not found.\n"); + return PTR_ERR(id->clk); + } + ret = clk_prepare_enable(id->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock.\n"); + return ret; + } + id->clk_rate_change_nb.notifier_call = xi2cps_clk_notifier_cb; + id->clk_rate_change_nb.next = NULL; + if (clk_notifier_register(id->clk, &id->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); + id->input_clk = (unsigned int)clk_get_rate(id->clk); + + ret = of_property_read_u32(pdev->dev.of_node, "i2c-clk", &id->i2c_clk); + if (ret) { + ret = -ENXIO; + dev_err(&pdev->dev, "couldn't determine i2c-clk\n"); + goto err_clk_dis; + } + + /* + * Set Master Mode,Normal addressing mode (7 bit address), + * Enable Transmission of Ack in Control Register. + * Set the timeout and I2C clock and request the IRQ(ISR mapped). + * Call to the i2c_add_numbered_adapter registers the adapter. + */ + xi2cps_writereg(0x0000000E, XI2CPS_CR_OFFSET); + xi2cps_writereg(id->adap.timeout, XI2CPS_TIME_OUT_OFFSET); + + ret = xi2cps_setclk(id->i2c_clk, id); + if (ret < 0) { + dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n", id->i2c_clk); + ret = -EINVAL; + goto err_clk_dis; + } + + ret = devm_request_irq(&pdev->dev, id->irq, xi2cps_isr, 0, + DRIVER_NAME, id); + if (ret) { + dev_err(&pdev->dev, "cannot get irq %d\n", id->irq); + goto err_clk_dis; + } + + ret = i2c_add_numbered_adapter(&id->adap); + if (ret < 0) { + dev_err(&pdev->dev, "reg adap failed: %d\n", ret); + goto err_clk_dis; + } + + dev_info(&pdev->dev, "%d kHz mmio %08lx irq %d\n", + id->i2c_clk/1000, (unsigned long)r_mem->start, id->irq); + + return 0; + +err_clk_dis: + clk_disable_unprepare(id->clk); + return ret; +} + +/** + * xi2cps_remove - Unregister the device after releasing the resources + * @pdev: Handle to the platform device structure + * + * Returns zero always + * + * This function frees all the resources allocated to the device. + */ +static int xi2cps_remove(struct platform_device *pdev) +{ + struct xi2cps *id = platform_get_drvdata(pdev); + + i2c_del_adapter(&id->adap); + clk_notifier_unregister(id->clk, &id->clk_rate_change_nb); + clk_disable_unprepare(id->clk); + + return 0; +} + +static const struct of_device_id xi2cps_of_match[] = { + { .compatible = "xlnx,ps7-i2c-1.00.a", }, + { /* end of table */} +}; +MODULE_DEVICE_TABLE(of, xi2cps_of_match); + +static struct platform_driver xi2cps_drv = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = xi2cps_of_match, + .pm = &xi2cps_dev_pm_ops, + }, + .probe = xi2cps_probe, + .remove = xi2cps_remove, +}; + +module_platform_driver(xi2cps_drv); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx Zynq I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); Index: linux-3.12.24-rt38-xilinx/drivers/i2c/busses/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/i2c/busses/Kconfig 2014-07-20 22:05:50.247066439 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/i2c/busses/Kconfig 2014-07-20 22:06:36.448304200 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:732 @ This driver can also be built as a module. If so, the module will be called i2c-versatile. +config I2C_ZYNQ + tristate "XILINX ZYNQ I2C Controller" + depends on ARCH_ZYNQ + help + Say yes here to select Xilnx ZYNQ I2C Host Controller + config I2C_WMT tristate "Wondermedia WM8xxx SoC I2C bus support" depends on ARCH_VT8500 Index: linux-3.12.24-rt38-xilinx/drivers/i2c/busses/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/i2c/busses/Makefile 2014-07-20 22:05:50.246066456 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/i2c/busses/Makefile 2014-07-20 22:06:36.458304035 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:79 @ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o +obj-$(CONFIG_I2C_ZYNQ) += i2c-zynq.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o Index: linux-3.12.24-rt38-xilinx/drivers/irqchip/irq-gic.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/irqchip/irq-gic.c 2014-07-20 22:05:50.208067083 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/irqchip/irq-gic.c 2014-07-20 22:06:36.474303771 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:25 @ * As such, the enable set/clear, pending set/clear and active bit * registers are banked per-cpu for these sources. */ +#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/err.h> @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:271 @ return IRQ_SET_MASK_OK; } + +void gic_set_cpu(unsigned int cpu, unsigned int irq) +{ + struct irq_data *d = irq_get_irq_data(irq); + struct cpumask mask; + + cpumask_clear(&mask); + cpumask_set_cpu(cpu, &mask); + gic_set_affinity(d, &mask, true); +} +EXPORT_SYMBOL(gic_set_cpu); #endif #ifdef CONFIG_PM @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:686 @ /* this always happens on GIC0 */ writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); } +EXPORT_SYMBOL(gic_raise_softirq); #endif static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, Index: linux-3.12.24-rt38-xilinx/drivers/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/Kconfig 2014-07-20 22:05:50.181067529 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/Kconfig 2014-07-20 22:06:36.488303541 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:115 @ source "drivers/auxdisplay/Kconfig" +source "drivers/xilinx_common/Kconfig" + source "drivers/uio/Kconfig" source "drivers/vfio/Kconfig" Index: linux-3.12.24-rt38-xilinx/drivers/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/Makefile 2014-07-20 22:05:50.173067660 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/Makefile 2014-07-20 22:06:36.498303376 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:154 @ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_IPACK_BUS) += ipack/ obj-$(CONFIG_NTB) += ntb/ + obj-$(CONFIG_FMC) += fmc/ + +obj-y += xilinx_common/ Index: linux-3.12.24-rt38-xilinx/drivers/media/i2c/adv7511.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/media/i2c/adv7511.c 2014-07-20 22:05:50.219066901 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/media/i2c/adv7511.c 2014-07-20 22:06:36.517303062 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1048 @ adv7511_s_audio_stream(sd, false); } +struct v4l2_subdev *adv7511_subdev(struct v4l2_subdev *sd) +{ + static struct v4l2_subdev *subdev; + + if (sd) + subdev = sd; + + return subdev; +} +EXPORT_SYMBOL(adv7511_subdev); + static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adv7511_state *state; Index: linux-3.12.24-rt38-xilinx/drivers/media/i2c/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/media/i2c/Makefile 2014-07-20 22:05:50.218066918 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/media/i2c/Makefile 2014-07-20 22:06:36.528302881 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:28 @ obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o +obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/media/platform/Kconfig 2014-07-20 22:05:50.217066935 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/Kconfig 2014-07-20 22:06:36.542302650 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:127 @ source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" +source "drivers/media/platform/xilinx/Kconfig" endif # V4L_PLATFORM_DRIVERS Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/media/platform/Makefile 2014-07-20 22:05:50.216066951 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/Makefile 2014-07-20 22:06:36.551302502 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:55 @ obj-$(CONFIG_ARCH_OMAP) += omap/ +obj-$(CONFIG_VIDEO_XILINX) += xilinx/ + ccflags-y += -I$(srctree)/drivers/media/i2c Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/Kconfig 2014-07-20 22:06:36.564302287 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +config VIDEO_XILINX + tristate "Xilinx Video IP (EXPERIMENTAL)" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF + select VIDEOBUF2_DMA_CONTIG + ---help--- + Driver for Xilinx Video IP Pipelines + +if VIDEO_XILINX + +config VIDEO_XILINX_REMAPPER + tristate "Xilinx Video Remapper" + depends on VIDEO_XILINX + ---help--- + Driver for the Xilinx Video Remapper + +config VIDEO_XILINX_TPG + tristate "Xilinx Video Test Pattern Generator" + depends on VIDEO_XILINX + ---help--- + Driver for the Xilinx Video Test Pattern Generator + +endif #VIDEO_XILINX Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/Makefile 2014-07-20 22:06:36.569302204 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2 @ +xilinx-axi-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o + +obj-$(CONFIG_VIDEO_XILINX) += xilinx-axi-video.o +obj-$(CONFIG_VIDEO_XILINX_REMAPPER) += xilinx-remapper.o +obj-$(CONFIG_VIDEO_XILINX_TPG) += xilinx-tpg.o Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-dma.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-dma.c 2014-07-20 22:06:36.580302023 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Video DMA + * + * Copyright (C) 2013 Ideas on Board SPRL + * + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/amba/xilinx_dma.h> +#include <linux/dmaengine.h> +#include <linux/lcm.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/slab.h> + +#include <media/v4l2-dev.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "xilinx-dma.h" +#include "xilinx-vip.h" +#include "xilinx-vipp.h" + +#define XVIP_DMA_DEF_FORMAT V4L2_PIX_FMT_YUYV +#define XVIP_DMA_DEF_WIDTH 1920 +#define XVIP_DMA_DEF_HEIGHT 1080 + +/* Minimum and maximum widths are expressed in bytes */ +#define XVIP_DMA_MIN_WIDTH 1U +#define XVIP_DMA_MAX_WIDTH 65535U +#define XVIP_DMA_MIN_HEIGHT 1U +#define XVIP_DMA_MAX_HEIGHT 8191U + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static struct v4l2_subdev * +xvip_dma_remote_subdev(struct media_pad *local, u32 *pad) +{ + struct media_pad *remote; + + remote = media_entity_remote_pad(local); + if (remote == NULL || + media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + return NULL; + + if (pad) + *pad = remote->index; + + return media_entity_to_v4l2_subdev(remote->entity); +} + +static int xvip_dma_verify_format(struct xvip_dma *dma) +{ + struct v4l2_subdev_format fmt; + struct v4l2_subdev *subdev; + int ret; + + subdev = xvip_dma_remote_subdev(&dma->pad, &fmt.pad); + if (subdev == NULL) + return -EINVAL; + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret < 0) + return ret == -ENOIOCTLCMD ? -EINVAL : ret; + + if (dma->fmtinfo->code != fmt.format.code || + dma->format.height != fmt.format.height || + dma->format.width != fmt.format.width) + return -EINVAL; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * videobuf2 queue operations + */ + +/** + * struct xvip_dma_buffer - Video DMA buffer + * @buf: vb2 buffer base object + * @dma: DMA channel that uses the buffer + * @addr: DMA bus address for the buffer memory + * @length: total length of the buffer in bytes + * @bytesused: number of bytes used in the buffer + */ +struct xvip_dma_buffer { + struct vb2_buffer buf; + + struct xvip_dma *dma; + + dma_addr_t addr; + unsigned int length; + unsigned int bytesused; +}; + +#define to_xvip_dma_buffer(vb) container_of(vb, struct xvip_dma_buffer, buf) + +static void xvip_dma_complete(void *param) +{ + struct xvip_dma_buffer *buf = param; + struct xvip_dma *dma = buf->dma; + + buf->buf.v4l2_buf.sequence = dma->sequence++; + v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp); + vb2_set_plane_payload(&buf->buf, 0, buf->length); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); +} + +static int +xvip_dma_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + + *nplanes = 1; + + sizes[0] = dma->format.sizeimage; + alloc_ctxs[0] = dma->alloc_ctx; + + return 0; +} + +static int xvip_dma_buffer_prepare(struct vb2_buffer *vb) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue); + struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb); + + buf->dma = dma; + buf->addr = vb2_dma_contig_plane_dma_addr(vb, 0); + buf->length = vb2_plane_size(vb, 0); + buf->bytesused = 0; + + return 0; +} + +static void xvip_dma_buffer_queue(struct vb2_buffer *vb) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue); + struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb); + struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction dir; + u32 flags; + + if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK + | DMA_COMPL_SKIP_DEST_UNMAP; + dir = DMA_DEV_TO_MEM; + } else { + flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK + | DMA_COMPL_SKIP_SRC_UNMAP; + dir = DMA_MEM_TO_DEV; + } + + desc = dmaengine_prep_slave_single(dma->dma, buf->addr, buf->length, + dir, flags); + desc->callback = xvip_dma_complete; + desc->callback_param = buf; + + dmaengine_submit(desc); + + if (vb2_is_streaming(&dma->queue)) + dma_async_issue_pending(dma->dma); +} + +static void xvip_dma_wait_prepare(struct vb2_queue *vq) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + + mutex_unlock(&dma->lock); +} + +static void xvip_dma_wait_finish(struct vb2_queue *vq) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + + mutex_lock(&dma->lock); +} + +static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + int ret; + + dma->sequence = 0; + + /* Mark the pipeline as streaming. */ + ret = media_entity_pipeline_start(&dma->video.entity, + &dma->xvipp->pipe); + if (ret < 0) + return ret; + + /* Verify that the configured format matches the output of the + * connected subdev. + */ + ret = xvip_dma_verify_format(dma); + if (ret < 0) { + media_entity_pipeline_stop(&dma->video.entity); + return ret; + } + + /* Start the DMA engine. This must be done before starting the blocks + * in the pipeline to avoid DMA synchronization issues. + */ + dma_async_issue_pending(dma->dma); + + /* Start the pipeline. */ + xvip_pipeline_set_stream(dma->xvipp, true); + + return 0; +} + +static int xvip_dma_stop_streaming(struct vb2_queue *vq) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + struct xilinx_vdma_config config; + + /* Stop the pipeline. */ + xvip_pipeline_set_stream(dma->xvipp, false); + + /* Stop and reset the DMA engine. */ + dmaengine_device_control(dma->dma, DMA_TERMINATE_ALL, 0); + + config.reset = 1; + + dmaengine_device_control(dma->dma, DMA_SLAVE_CONFIG, + (unsigned long)&config); + + /* Mark the pipeline as being stopped. */ + media_entity_pipeline_stop(&dma->video.entity); + + return 0; +} + +static struct vb2_ops xvip_dma_queue_qops = { + .queue_setup = xvip_dma_queue_setup, + .buf_prepare = xvip_dma_buffer_prepare, + .buf_queue = xvip_dma_buffer_queue, + .wait_prepare = xvip_dma_wait_prepare, + .wait_finish = xvip_dma_wait_finish, + .start_streaming = xvip_dma_start_streaming, + .stop_streaming = xvip_dma_stop_streaming, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 ioctls + */ + +static int +xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + else + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + + strlcpy(cap->driver, "xilinx-vipp", sizeof(cap->driver)); + strlcpy(cap->card, dma->video.name, sizeof(cap->card)); + strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); + + return 0; +} + +static int +xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + mutex_lock(&dma->lock); + format->fmt.pix = dma->format; + mutex_unlock(&dma->lock); + + return 0; +} + +static void +__xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix, + const struct xvip_video_format **fmtinfo) +{ + const struct xvip_video_format *info; + unsigned int min_width; + unsigned int max_width; + unsigned int min_bpl; + unsigned int max_bpl; + unsigned int width; + unsigned int align; + unsigned int bpl; + + /* Retrieve format information and select the default format if the + * requested format isn't supported. + */ + info = xvip_get_format_by_fourcc(pix->pixelformat); + if (info == NULL) + info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT); + + pix->pixelformat = info->fourcc; + pix->colorspace = V4L2_COLORSPACE_SRGB; + pix->field = V4L2_FIELD_NONE; + + /* The transfer alignment requirements are expressed in bytes. Compute + * the minimum and maximum values, clamp the requested width and convert + * it back to pixels. + */ + align = lcm(dma->align, info->bpp); + min_width = roundup(XVIP_DMA_MIN_WIDTH, align); + max_width = rounddown(XVIP_DMA_MAX_WIDTH, align); + width = rounddown(pix->width * info->bpp, align); + + pix->width = clamp(width, min_width, max_width) / info->bpp; + pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT, + XVIP_DMA_MAX_HEIGHT); + + /* Clamp the requested bytes per line value. If the maximum bytes per + * line value is zero, the module doesn't support user configurable line + * sizes. Override the requested value with the minimum in that case. + */ + min_bpl = pix->width * info->bpp; + max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align); + bpl = rounddown(pix->bytesperline, dma->align); + + pix->bytesperline = clamp(bpl, min_bpl, max_bpl); + pix->sizeimage = pix->bytesperline * pix->height; + + if (fmtinfo) + *fmtinfo = info; +} + +static int +xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + __xvip_dma_try_format(dma, &format->fmt.pix, NULL); + return 0; +} + +static int +xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + const struct xvip_video_format *info; + struct xilinx_vdma_config config; + int ret; + + __xvip_dma_try_format(dma, &format->fmt.pix, &info); + + mutex_lock(&dma->lock); + + if (vb2_is_streaming(&dma->queue)) { + ret = -EBUSY; + goto done; + } + + dma->format = format->fmt.pix; + dma->fmtinfo = info; + + /* Configure the DMA engine. */ + memset(&config, 0, sizeof(config)); + + config.park = 1; + config.park_frm = 0; + config.vsize = dma->format.height; + config.hsize = dma->format.width * info->bpp; + config.stride = dma->format.bytesperline; + config.ext_fsync = 2; + config.frm_cnt_en = 1; + config.coalesc = 1; + + dmaengine_device_control(dma->dma, DMA_SLAVE_CONFIG, + (unsigned long)&config); + + ret = 0; + +done: + mutex_unlock(&dma->lock); + return ret; +} + +static int +xvip_dma_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + + if (dma->queue.owner && dma->queue.owner != vfh) { + ret = -EBUSY; + goto done; + } + + ret = vb2_reqbufs(&dma->queue, rb); + if (ret < 0) + goto done; + + dma->queue.owner = vfh; + +done: + mutex_unlock(&dma->lock); + return ret ? ret : rb->count; +} + +static int +xvip_dma_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + ret = vb2_querybuf(&dma->queue, buf); + mutex_unlock(&dma->lock); + + return ret; +} + +static int +xvip_dma_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + + if (dma->queue.owner && dma->queue.owner != vfh) { + ret = -EBUSY; + goto done; + } + + ret = vb2_qbuf(&dma->queue, buf); + +done: + mutex_unlock(&dma->lock); + return ret; +} + +static int +xvip_dma_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + + if (dma->queue.owner && dma->queue.owner != vfh) { + ret = -EBUSY; + goto done; + } + + ret = vb2_dqbuf(&dma->queue, buf, file->f_flags & O_NONBLOCK); + +done: + mutex_unlock(&dma->lock); + return ret; +} + +static int +xvip_dma_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *eb) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + + if (dma->queue.owner && dma->queue.owner != vfh) { + ret = -EBUSY; + goto done; + } + + ret = vb2_expbuf(&dma->queue, eb); + +done: + mutex_unlock(&dma->lock); + return ret; +} + +static int +xvip_dma_streamon(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + + if (dma->queue.owner && dma->queue.owner != vfh) { + ret = -EBUSY; + goto done; + } + + ret = vb2_streamon(&dma->queue, type); + +done: + mutex_unlock(&dma->lock); + return ret; +} + +static int +xvip_dma_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + + if (dma->queue.owner && dma->queue.owner != vfh) { + ret = -EBUSY; + goto done; + } + + ret = vb2_streamoff(&dma->queue, type); + +done: + mutex_unlock(&dma->lock); + return ret; +} + +static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = { + .vidioc_querycap = xvip_dma_querycap, + .vidioc_g_fmt_vid_cap = xvip_dma_get_format, + .vidioc_g_fmt_vid_out = xvip_dma_get_format, + .vidioc_s_fmt_vid_cap = xvip_dma_set_format, + .vidioc_s_fmt_vid_out = xvip_dma_set_format, + .vidioc_try_fmt_vid_cap = xvip_dma_try_format, + .vidioc_try_fmt_vid_out = xvip_dma_try_format, + .vidioc_reqbufs = xvip_dma_reqbufs, + .vidioc_querybuf = xvip_dma_querybuf, + .vidioc_qbuf = xvip_dma_qbuf, + .vidioc_dqbuf = xvip_dma_dqbuf, + .vidioc_expbuf = xvip_dma_expbuf, + .vidioc_streamon = xvip_dma_streamon, + .vidioc_streamoff = xvip_dma_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 file operations + */ + +static int xvip_dma_open(struct file *file) +{ + struct xvip_dma *dma = video_drvdata(file); + struct v4l2_fh *vfh; + + vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); + if (vfh == NULL) + return -ENOMEM; + + v4l2_fh_init(vfh, &dma->video); + v4l2_fh_add(vfh); + + file->private_data = vfh; + + return 0; +} + +static int xvip_dma_release(struct file *file) +{ + struct xvip_dma *dma = video_drvdata(file); + struct v4l2_fh *vfh = file->private_data; + + mutex_lock(&dma->lock); + if (dma->queue.owner == vfh) { + vb2_queue_release(&dma->queue); + dma->queue.owner = NULL; + } + mutex_unlock(&dma->lock); + + v4l2_fh_release(file); + + file->private_data = NULL; + + return 0; +} + +static unsigned int xvip_dma_poll(struct file *file, poll_table *wait) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + ret = vb2_poll(&dma->queue, file, wait); + mutex_unlock(&dma->lock); + + return ret; +} + +static int xvip_dma_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + int ret; + + mutex_lock(&dma->lock); + ret = vb2_mmap(&dma->queue, vma); + mutex_unlock(&dma->lock); + + return ret; +} + +static struct v4l2_file_operations xvip_dma_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = xvip_dma_open, + .release = xvip_dma_release, + .poll = xvip_dma_poll, + .mmap = xvip_dma_mmap, +}; + +/* ----------------------------------------------------------------------------- + * Xilinx Video DMA Core + */ + +int xvip_dma_init(struct xvip_pipeline *xvipp, struct xvip_dma *dma, + enum v4l2_buf_type type) +{ + char name[10]; + int ret; + + dma->xvipp = xvipp; + mutex_init(&dma->lock); + + dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT); + dma->format.pixelformat = dma->fmtinfo->fourcc; + dma->format.colorspace = V4L2_COLORSPACE_SRGB; + dma->format.field = V4L2_FIELD_NONE; + dma->format.width = XVIP_DMA_DEF_WIDTH; + dma->format.height = XVIP_DMA_DEF_HEIGHT; + dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp; + dma->format.sizeimage = dma->format.bytesperline * dma->format.height; + + /* Initialize the media entity... */ + dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0); + if (ret < 0) + return ret; + + /* ... and the video node... */ + dma->video.v4l2_dev = &xvipp->v4l2_dev; + dma->video.fops = &xvip_dma_fops; + snprintf(dma->video.name, sizeof(dma->video.name), "%s %s", + xvipp->dev->of_node->full_name, + type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input"); + dma->video.vfl_type = VFL_TYPE_GRABBER; + dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? VFL_DIR_RX : VFL_DIR_TX; + dma->video.release = video_device_release_empty; + dma->video.ioctl_ops = &xvip_dma_ioctl_ops; + + video_set_drvdata(&dma->video, dma); + + /* ... and the buffers queue... */ + dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xvipp->dev); + if (IS_ERR(dma->alloc_ctx)) + goto error; + + dma->queue.type = type; + dma->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + dma->queue.drv_priv = dma; + dma->queue.buf_struct_size = sizeof(struct xvip_dma_buffer); + dma->queue.ops = &xvip_dma_queue_qops; + dma->queue.mem_ops = &vb2_dma_contig_memops; + dma->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&dma->queue); + if (ret < 0) { + dev_err(dma->xvipp->dev, "failed to initialize VB2 queue\n"); + goto error; + } + + /* ... and the DMA channel. */ + sprintf(name, "vdma-%s", + type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "s2mm" : "mm2s"); + dma->dma = dma_request_slave_channel(dma->xvipp->dev, name); + if (dma->dma == NULL) { + dev_err(dma->xvipp->dev, "no VDMA channel found\n"); + ret = -ENODEV; + goto error; + } + + dma->align = 1 << dma->dma->device->copy_align; + + ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + dev_err(dma->xvipp->dev, "failed to register video device\n"); + goto error; + } + + return 0; + +error: + vb2_dma_contig_cleanup_ctx(dma->alloc_ctx); + xvip_dma_cleanup(dma); + return ret; +} + +void xvip_dma_cleanup(struct xvip_dma *dma) +{ + if (video_is_registered(&dma->video)) + video_unregister_device(&dma->video); + + if (dma->dma) + dma_release_channel(dma->dma); + + vb2_dma_contig_cleanup_ctx(dma->alloc_ctx); + media_entity_cleanup(&dma->video.entity); +} Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-dma.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-dma.h 2014-07-20 22:06:36.587301907 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Video DMA + * + * Copyright (C) 2013 Ideas on Board SPRL + * + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIP_DMA_H__ +#define __XILINX_VIP_DMA_H__ + +#include <linux/mutex.h> +#include <linux/videodev2.h> + +#include <media/media-entity.h> +#include <media/v4l2-dev.h> +#include <media/videobuf2-core.h> + +struct dma_chan; +struct xvip_pipeline; +struct xvip_video_format; + +/** + * struct xvip_dma - Video pipeline DMA channel + * @video: V4L2 video device associated with the DMA channel + * @pad: media pad for the video device entity + * @xvipp: video pipeline that uses the DMA channel + * @lock: protects the @format, @fmtinfo and @queue fields + * @format: active V4L2 pixel format + * @fmtinfo: format information corresponding to the active @format + * @queue: vb2 buffers queue + * @alloc_ctx: allocation context for the vb2 @queue + * @sequence: V4L2 buffers sequence number + * @dma: DMA engine channel + * @align: transfer alignment required by the DMA channel (in bytes) + */ +struct xvip_dma { + struct video_device video; + struct media_pad pad; + + struct xvip_pipeline *xvipp; + + struct mutex lock; + struct v4l2_pix_format format; + const struct xvip_video_format *fmtinfo; + + struct vb2_queue queue; + void *alloc_ctx; + unsigned int sequence; + + struct dma_chan *dma; + unsigned int align; +}; + +#define to_xvip_dma(vdev) container_of(vdev, struct xvip_dma, video) + +int xvip_dma_init(struct xvip_pipeline *xvipp, struct xvip_dma *dma, + enum v4l2_buf_type type); +void xvip_dma_cleanup(struct xvip_dma *dma); + +#endif /* __XILINX_VIP_DMA_H__ */ Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-remapper.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-remapper.c 2014-07-20 22:06:36.597301743 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Video Remapper + * + * Copyright (C) 2013 Ideas on Board SPRL + * + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-subdev.h> + +#include "xilinx-vip.h" + +#define XREMAP_MIN_WIDTH 1 +#define XREMAP_DEF_WIDTH 1920 +#define XREMAP_MAX_WIDTH 65535 +#define XREMAP_MIN_HEIGHT 1 +#define XREMAP_DEF_HEIGHT 1080 +#define XREMAP_MAX_HEIGHT 65535 + +#define XREMAP_PAD_SINK 0 +#define XREMAP_PAD_SOURCE 1 + +/** + * struct xremap_mapping_output - Output format description + * @code: media bus pixel core after remapping + * @num_components: number of pixel components after remapping + * @component_maps: configuration array corresponding to this output + */ +struct xremap_mapping_output { + u32 code; + unsigned int num_components; + unsigned int component_maps[4]; +}; + +/** + * struct xremap_mapping - Input-output remapping description + * @code: media bus pixel code before remapping + * @width: video bus width in bits + * @num_components: number of pixel components before remapping + * @outputs: array of possible output formats + */ +struct xremap_mapping { + u32 code; + unsigned int width; + unsigned int num_components; + const struct xremap_mapping_output *outputs; +}; + +/** + * struct xremap_device - Xilinx Test Pattern Generator device structure + * @xvip: Xilinx Video IP device + * @pads: media pads + * @formats: V4L2 media bus formats at the sink and source pads + * @config: device configuration parsed from its DT node + * @config.width: video bus width in bits + * @config.num_s_components: number of pixel components at the input + * @config.num_m_components: number of pixel components at the output + * @config.component_maps: component remapping configuration + * @default_mapping: Default mapping compatible with the configuration + * @default_output: Default output format for the default mapping + */ +struct xremap_device { + struct xvip_device xvip; + struct media_pad pads[2]; + struct v4l2_mbus_framefmt formats[2]; + + struct { + unsigned int width; + unsigned int num_s_components; + unsigned int num_m_components; + unsigned int component_maps[4]; + } config; + + const struct xremap_mapping *default_mapping; + const struct xremap_mapping_output *default_output; +}; + +static inline struct xremap_device *to_remap(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct xremap_device, xvip.subdev); +} + +/* ----------------------------------------------------------------------------- + * Mappings + */ + +static const struct xremap_mapping xremap_mappings[] = { + { + .code = V4L2_MBUS_FMT_RBG888_1X24, + .width = 8, + .num_components = 3, + .outputs = (const struct xremap_mapping_output[]) { + { V4L2_MBUS_FMT_RGB888_1X32_PADHI, 4, { 1, 0, 2, 4 } }, + { }, + }, + }, +}; + +static const struct xremap_mapping_output * +xremap_match_mapping(struct xremap_device *xremap, + const struct xremap_mapping *mapping) +{ + const struct xremap_mapping_output *output; + + if (mapping->width != xremap->config.width || + mapping->num_components != xremap->config.num_s_components) + return NULL; + + for (output = mapping->outputs; output->code; ++output) { + unsigned int i; + + if (output->num_components != xremap->config.num_m_components) + continue; + + for (i = 0; i < output->num_components; ++i) { + if (output->component_maps[i] != + xremap->config.component_maps[i]) + break; + } + + if (i == output->num_components) + return output; + } + + return NULL; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +static int xremap_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct xremap_device *xremap = to_remap(subdev); + struct v4l2_mbus_framefmt *format; + + if (code->pad == XREMAP_PAD_SINK) { + const struct xremap_mapping *mapping = NULL; + unsigned int index = code->index + 1; + unsigned int i; + + /* Iterate through the mappings and skip the ones that don't + * match the remapper configuration until we reach the requested + * index. + */ + for (i = 0; i < ARRAY_SIZE(xremap_mappings) && index; ++i) { + mapping = &xremap_mappings[i]; + + if (xremap_match_mapping(xremap, mapping)) + index--; + } + + /* If the index was larger than the number of supported mappings + * return -EINVAL. + */ + if (index > 0) + return -EINVAL; + + code->code = mapping->code; + } else { + if (code->index) + return -EINVAL; + + format = v4l2_subdev_get_try_format(fh, code->pad); + code->code = format->code; + } + + return 0; +} + +static int xremap_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(fh, fse->pad); + + if (fse->index || fse->code != format->code) + return -EINVAL; + + if (fse->pad == XREMAP_PAD_SINK) { + /* The remapper doesn't restrict the size on the sink pad. */ + fse->min_width = XREMAP_MIN_WIDTH; + fse->max_width = XREMAP_MAX_WIDTH; + fse->min_height = XREMAP_MIN_HEIGHT; + fse->max_height = XREMAP_MAX_HEIGHT; + } else { + /* The size on the source pad are fixed and always identical to + * the size on the sink pad. + */ + fse->min_width = format->width; + fse->max_width = format->width; + fse->min_height = format->height; + fse->max_height = format->height; + } + + return 0; +} + +static struct v4l2_mbus_framefmt * +xremap_get_pad_format(struct xremap_device *xremap, struct v4l2_subdev_fh *fh, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &xremap->formats[pad]; + default: + return NULL; + } +} + +static int xremap_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct xremap_device *xremap = to_remap(subdev); + + fmt->format = *xremap_get_pad_format(xremap, fh, fmt->pad, fmt->which); + + return 0; +} + +static int xremap_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct xremap_device *xremap = to_remap(subdev); + const struct xremap_mapping_output *output; + const struct xremap_mapping *mapping; + struct v4l2_mbus_framefmt *format; + unsigned int i; + + format = xremap_get_pad_format(xremap, fh, fmt->pad, fmt->which); + + if (fmt->pad == XREMAP_PAD_SOURCE) { + fmt->format = *format; + return 0; + } + + /* Find the mapping. If the requested format has no mapping, use the + * default. + */ + for (i = 0; i < ARRAY_SIZE(xremap_mappings); ++i) { + mapping = &xremap_mappings[i]; + if (mapping->code != fmt->format.code) + continue; + + output = xremap_match_mapping(xremap, mapping); + if (output) + break; + } + + if (!output) { + mapping = xremap->default_mapping; + output = xremap->default_output; + } + + format->code = mapping->code; + format->width = clamp_t(unsigned int, fmt->format.width, + XREMAP_MIN_WIDTH, XREMAP_MAX_WIDTH); + format->height = clamp_t(unsigned int, fmt->format.height, + XREMAP_MIN_HEIGHT, XREMAP_MAX_HEIGHT); + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + fmt->format = *format; + + /* Propagate the format to the source pad. */ + format = xremap_get_pad_format(xremap, fh, XREMAP_PAD_SOURCE, + fmt->which); + *format = fmt->format; + format->code = output->code; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +/* + * xremap_init_formats - Initialize formats on all pads + * @subdev: remapper V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. If fh is not NULL, try + * formats are initialized on the file handle. Otherwise active formats are + * initialized on the device. + */ +static void xremap_init_formats(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh) +{ + struct xremap_device *xremap = to_remap(subdev); + struct v4l2_subdev_format format; + + memset(&format, 0, sizeof(format)); + + format.pad = XREMAP_PAD_SINK; + format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.format.code = xremap->default_mapping->code; + format.format.width = XREMAP_DEF_WIDTH; + format.format.height = XREMAP_DEF_HEIGHT; + + xremap_set_format(subdev, fh, &format); +} + +static int xremap_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + xremap_init_formats(subdev, fh); + + return 0; +} + +static int xremap_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + return 0; +} + +static struct v4l2_subdev_core_ops xremap_core_ops = { +}; + +static struct v4l2_subdev_video_ops xremap_video_ops = { +}; + +static struct v4l2_subdev_pad_ops xremap_pad_ops = { + .enum_mbus_code = xremap_enum_mbus_code, + .enum_frame_size = xremap_enum_frame_size, + .get_fmt = xremap_get_format, + .set_fmt = xremap_set_format, +}; + +static struct v4l2_subdev_ops xremap_ops = { + .core = &xremap_core_ops, + .video = &xremap_video_ops, + .pad = &xremap_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops xremap_internal_ops = { + .open = xremap_open, + .close = xremap_close, +}; + +/* ----------------------------------------------------------------------------- + * Media Operations + */ + +static const struct media_entity_operations xremap_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static int xremap_parse_of(struct xremap_device *xremap) +{ + struct device_node *node = xremap->xvip.dev->of_node; + unsigned int i; + int ret; + + /* Parse the DT properties. */ + ret = of_property_read_u32(node, "xlnx,axi-video-width", + &xremap->config.width); + if (ret < 0) { + dev_dbg(xremap->xvip.dev, "unable to parse %s property\n", + "xlnx,axi-video-width"); + return -EINVAL; + } + + ret = of_property_read_u32(node, "#xlnx,axi-s-components", + &xremap->config.num_s_components); + if (ret < 0) { + dev_dbg(xremap->xvip.dev, "unable to parse %s property\n", + "#xlnx,axi-s-components"); + return -EINVAL; + } + + ret = of_property_read_u32(node, "#xlnx,axi-m-components", + &xremap->config.num_m_components); + if (ret < 0) { + dev_dbg(xremap->xvip.dev, "unable to parse %s property\n", + "#xlnx,axi-m-components"); + return -EINVAL; + } + + ret = of_property_read_u32_array(node, "xlnx,axi-component-maps", + xremap->config.component_maps, + xremap->config.num_m_components); + if (ret < 0) { + dev_dbg(xremap->xvip.dev, "unable to parse %s property\n", + "xlnx,axi-component-maps"); + return -EINVAL; + } + + /* Validate the parsed values. */ + if (xremap->config.num_s_components > 4 || + xremap->config.num_m_components > 4) { + dev_dbg(xremap->xvip.dev, + "invalid number of components (s %u m %u)\n", + xremap->config.num_s_components, + xremap->config.num_m_components); + return -EINVAL; + } + + for (i = 0; i < xremap->config.num_m_components; ++i) { + if (xremap->config.component_maps[i] > 4) { + dev_dbg(xremap->xvip.dev, "invalid map %u @%u\n", + xremap->config.component_maps[i], i); + return -EINVAL; + } + } + + /* Find the first mapping that matches the remapper configuration and + * store it as the default mapping. + */ + for (i = 0; i < ARRAY_SIZE(xremap_mappings); ++i) { + const struct xremap_mapping_output *output; + const struct xremap_mapping *mapping; + + mapping = &xremap_mappings[i]; + output = xremap_match_mapping(xremap, mapping); + + if (output) { + xremap->default_mapping = mapping; + xremap->default_output = output; + return 0; + } + } + + dev_err(xremap->xvip.dev, + "No format compatible with device configuration\n"); + + return -EINVAL; +} + +static int xremap_probe(struct platform_device *pdev) +{ + struct xremap_device *xremap; + struct v4l2_subdev *subdev; + int ret; + + xremap = devm_kzalloc(&pdev->dev, sizeof(*xremap), GFP_KERNEL); + if (!xremap) + return -ENOMEM; + + xremap->xvip.dev = &pdev->dev; + + ret = xremap_parse_of(xremap); + if (ret < 0) + return ret; + + /* Initialize V4L2 subdevice and media entity */ + subdev = &xremap->xvip.subdev; + v4l2_subdev_init(subdev, &xremap_ops); + subdev->dev = &pdev->dev; + subdev->internal_ops = &xremap_internal_ops; + strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name)); + v4l2_set_subdevdata(subdev, xremap); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + xremap_init_formats(subdev, NULL); + + xremap->pads[XREMAP_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + xremap->pads[XREMAP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + subdev->entity.ops = &xremap_media_ops; + ret = media_entity_init(&subdev->entity, 2, xremap->pads, 0); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, xremap); + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register subdev\n"); + goto error; + } + + dev_info(&pdev->dev, "device registered\n"); + + return 0; + +error: + media_entity_cleanup(&subdev->entity); + return ret; +} + +static int xremap_remove(struct platform_device *pdev) +{ + struct xremap_device *xremap = platform_get_drvdata(pdev); + struct v4l2_subdev *subdev = &xremap->xvip.subdev; + + v4l2_async_unregister_subdev(subdev); + media_entity_cleanup(&subdev->entity); + + return 0; +} + +static const struct of_device_id xremap_of_id_table[] = { + { .compatible = "xlnx,axi-remapper" }, + { } +}; +MODULE_DEVICE_TABLE(of, xremap_of_id_table); + +static struct platform_driver xremap_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "xilinx-axi-remapper", + .of_match_table = of_match_ptr(xremap_of_id_table), + }, + .probe = xremap_probe, + .remove = xremap_remove, +}; + +module_platform_driver(xremap_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("Xilinx Video Remapper Driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-tpg.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-tpg.c 2014-07-20 22:06:36.607301578 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Test Pattern Generator + * + * Copyright (C) 2013 Ideas on Board SPRL + * + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-subdev.h> + +#include "xilinx-vip.h" + +#define XTPG_MIN_WIDTH 32 +#define XTPG_DEF_WIDTH 1920 +#define XTPG_MAX_WIDTH 7680 +#define XTPG_MIN_HEIGHT 32 +#define XTPG_DEF_HEIGHT 1080 +#define XTPG_MAX_HEIGHT 7680 + +#define XTPG_CTRL_STATUS_SLAVE_ERROR (1 << 16) +#define XTPG_CTRL_IRQ_SLAVE_ERROR (1 << 16) + +#define XTPG_PATTERN_CONTROL 0x0100 +#define XTPG_MOTION_SPEED 0x0104 +#define XTPG_CROSS_HAIRS 0x0108 +#define XTPG_ZPLATE_HOR_CONTROL 0x010c +#define XTPG_ZPLATE_VER_CONTROL 0x0110 +#define XTPG_BOX_SIZE 0x0114 +#define XTPG_BOX_COLOR 0x0118 +#define XTPG_STUCK_PIXEL_THRESH 0x011c +#define XTPG_NOISE_GAIN 0x0120 + +/** + * struct xtpg_device - Xilinx Test Pattern Generator device structure + * @pad: media pad + * @xvip: Xilinx Video IP device + * @format: active V4L2 media bus format at the source pad + * @vip_format: format information corresponding to the active format + */ +struct xtpg_device { + struct xvip_device xvip; + struct media_pad pad; + + struct v4l2_mbus_framefmt format; + const struct xvip_video_format *vip_format; +}; + +static inline struct xtpg_device *to_tpg(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct xtpg_device, xvip.subdev); +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Video Operations + */ + +static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + const u32 width = xtpg->format.width; + const u32 height = xtpg->format.height; + + if (!enable) { + /* Stopping the TPG without resetting it confuses the VDMA and + * results in VDMA errors the next time the stream is started. + * Reset the TPG when stopping the stream for now. + */ + xvip_write(&xtpg->xvip, XVIP_CTRL_CONTROL, + XVIP_CTRL_CONTROL_SW_RESET); + xvip_write(&xtpg->xvip, XVIP_CTRL_CONTROL, 0); + return 0; + } + + xvip_write(&xtpg->xvip, XVIP_TIMING_ACTIVE_SIZE, + (height << XVIP_TIMING_ACTIVE_VSIZE_SHIFT) | + (width << XVIP_TIMING_ACTIVE_HSIZE_SHIFT)); + + xvip_write(&xtpg->xvip, XTPG_PATTERN_CONTROL, 0x00001029); + xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, 1); + xvip_write(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, (74 * 1920) / width); + xvip_write(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, (3 * 1080) / height); + xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, (112 * height) / 1080); + xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, 0x76543200); + + xvip_write(&xtpg->xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_ENABLE | + XVIP_CTRL_CONTROL_REG_UPDATE); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +static int xtpg_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + + if (code->index) + return -EINVAL; + + code->code = xtpg->vip_format->code; + + return 0; +} + +static int xtpg_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + + if (fse->index || fse->code != xtpg->vip_format->code) + return -EINVAL; + + fse->min_width = XTPG_MIN_WIDTH; + fse->max_width = XTPG_MAX_WIDTH; + fse->min_height = XTPG_MIN_HEIGHT; + fse->max_height = XTPG_MAX_HEIGHT; + + return 0; +} + +static struct v4l2_mbus_framefmt * +__xtpg_get_pad_format(struct xtpg_device *xtpg, + struct v4l2_subdev_fh *fh, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &xtpg->format; + default: + return NULL; + } +} + +static int xtpg_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + + fmt->format = + *__xtpg_get_pad_format(xtpg, fh, fmt->pad, fmt->which); + + return 0; +} + +static int xtpg_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + struct v4l2_mbus_framefmt *__format; + + __format = __xtpg_get_pad_format(xtpg, fh, format->pad, + format->which); + __format->width = clamp_t(unsigned int, format->format.width, + XTPG_MIN_WIDTH, XTPG_MAX_WIDTH); + __format->height = clamp_t(unsigned int, format->format.height, + XTPG_MIN_HEIGHT, XTPG_MAX_HEIGHT); + + format->format = *__format; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(fh, 0); + + format->code = xtpg->vip_format->code; + format->width = XTPG_DEF_WIDTH; + format->height = XTPG_DEF_HEIGHT; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + +static int xtpg_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + return 0; +} + +static struct v4l2_subdev_core_ops xtpg_core_ops = { +}; + +static struct v4l2_subdev_video_ops xtpg_video_ops = { + .s_stream = xtpg_s_stream, +}; + +static struct v4l2_subdev_pad_ops xtpg_pad_ops = { + .enum_mbus_code = xtpg_enum_mbus_code, + .enum_frame_size = xtpg_enum_frame_size, + .get_fmt = xtpg_get_format, + .set_fmt = xtpg_set_format, +}; + +static struct v4l2_subdev_ops xtpg_ops = { + .core = &xtpg_core_ops, + .video = &xtpg_video_ops, + .pad = &xtpg_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops xtpg_internal_ops = { + .open = xtpg_open, + .close = xtpg_close, +}; + +/* ----------------------------------------------------------------------------- + * Media Operations + */ + +static const struct media_entity_operations xtpg_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static int xtpg_parse_of(struct xtpg_device *xtpg) +{ + struct device_node *node = xtpg->xvip.dev->of_node; + + xtpg->vip_format = xvip_of_get_format(node); + if (xtpg->vip_format == NULL) { + dev_err(xtpg->xvip.dev, "invalid format in DT"); + return -EINVAL; + } + + return 0; +} + +static int xtpg_probe(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev; + struct xtpg_device *xtpg; + struct resource *res; + u32 version; + int ret; + + xtpg = devm_kzalloc(&pdev->dev, sizeof(*xtpg), GFP_KERNEL); + if (!xtpg) + return -ENOMEM; + + xtpg->xvip.dev = &pdev->dev; + + ret = xtpg_parse_of(xtpg); + if (ret < 0) + return ret; + + xtpg->format.code = xtpg->vip_format->code; + xtpg->format.width = XTPG_DEF_WIDTH; + xtpg->format.height = XTPG_DEF_HEIGHT; + xtpg->format.field = V4L2_FIELD_NONE; + xtpg->format.colorspace = V4L2_COLORSPACE_SRGB; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xtpg->xvip.iomem = devm_ioremap_resource(&pdev->dev, res); + if (xtpg->xvip.iomem == NULL) + return -ENODEV; + + /* Initialize V4L2 subdevice and media entity */ + subdev = &xtpg->xvip.subdev; + v4l2_subdev_init(subdev, &xtpg_ops); + subdev->dev = &pdev->dev; + subdev->internal_ops = &xtpg_internal_ops; + strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name)); + v4l2_set_subdevdata(subdev, xtpg); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + xtpg->pad.flags = MEDIA_PAD_FL_SOURCE; + subdev->entity.ops = &xtpg_media_ops; + ret = media_entity_init(&subdev->entity, 1, &xtpg->pad, 0); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, xtpg); + + version = xvip_read(&xtpg->xvip, XVIP_CTRL_VERSION); + + dev_info(&pdev->dev, "device found, version %u.%02x%x\n", + ((version & XVIP_CTRL_VERSION_MAJOR_MASK) >> + XVIP_CTRL_VERSION_MAJOR_SHIFT), + ((version & XVIP_CTRL_VERSION_MINOR_MASK) >> + XVIP_CTRL_VERSION_MINOR_SHIFT), + ((version & XVIP_CTRL_VERSION_REVISION_MASK) >> + XVIP_CTRL_VERSION_REVISION_SHIFT)); + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register subdev\n"); + goto error; + } + + return 0; + +error: + media_entity_cleanup(&subdev->entity); + return ret; +} + +static int xtpg_remove(struct platform_device *pdev) +{ + struct xtpg_device *xtpg = platform_get_drvdata(pdev); + struct v4l2_subdev *subdev = &xtpg->xvip.subdev; + + v4l2_async_unregister_subdev(subdev); + media_entity_cleanup(&subdev->entity); + + return 0; +} + +static const struct of_device_id xtpg_of_id_table[] = { + { .compatible = "xlnx,axi-tpg" }, + { } +}; +MODULE_DEVICE_TABLE(of, xtpg_of_id_table); + +static struct platform_driver xtpg_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "xilinx-axi-tpg", + .of_match_table = of_match_ptr(xtpg_of_id_table), + }, + .probe = xtpg_probe, + .remove = xtpg_remove, +}; + +module_platform_driver(xtpg_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("Xilinx Test Pattern Generator Driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-vip.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-vip.c 2014-07-20 22:06:36.614301462 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Video IP Core + * + * Copyright (C) 2013 Ideas on Board SPRL + * + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/of.h> + +#include "xilinx-vip.h" + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static const struct xvip_video_format xvip_video_formats[] = { + { "rbg", 8, 3, V4L2_MBUS_FMT_RBG888_1X24, 0 }, + { "xrgb", 8, 4, V4L2_MBUS_FMT_RGB888_1X32_PADHI, V4L2_PIX_FMT_BGR32 }, + { "yuv422", 8, 2, V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_YUYV }, +}; + +/** + * xvip_get_format_by_code - Retrieve format information for a media bus code + * @code: the format media bus code + * + * Return: a pointer to the format information structure corresponding to the + * given V4L2 media bus format @code, or %NULL if no corresponding format can be + * found. + */ +const struct xvip_video_format *xvip_get_format_by_code(unsigned int code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (format->code == code) + return format; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(xvip_get_format_by_code); + +/** + * xvip_get_format_by_fourcc - Retrieve format information for a 4CC + * @fourcc: the format 4CC + * + * Return: a pointer to the format information structure corresponding to the + * given V4L2 format @fourcc, or %NULL if no corresponding format can be found. + */ +const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (format->fourcc == fourcc) + return format; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc); + +/** + * xvip_of_get_format - Parse a device tree node and return format information + * @node: the device tree node + * + * Read the xlnx,axi-video-format and xlnx,axi-video-width properties from the + * device tree @node passed as an argument and return the corresponding format + * information. + * + * Return: a pointer to the format information structure corresponding to the + * format name and width, or %NULL if no corresponding format can be found. + */ +const struct xvip_video_format *xvip_of_get_format(struct device_node *node) +{ + const char *name; + unsigned int i; + u32 width; + int ret; + + ret = of_property_read_string(node, "xlnx,axi-video-format", &name); + if (ret < 0) + return NULL; + + ret = of_property_read_u32(node, "xlnx,axi-video-width", &width); + if (ret < 0) + return NULL; + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (strcmp(format->name, name) == 0 && format->width == width) + return format; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(xvip_of_get_format); Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-vip.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-vip.h 2014-07-20 22:06:36.620301363 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Video IP Core + * + * Copyright (C) 2013 Ideas on Board SPRL + * + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIP_H__ +#define __XILINX_VIP_H__ + +#include <linux/io.h> +#include <media/v4l2-subdev.h> + +/* Xilinx Video IP Control Registers */ +#define XVIP_CTRL_CONTROL 0x0000 +#define XVIP_CTRL_CONTROL_SW_ENABLE (1 << 0) +#define XVIP_CTRL_CONTROL_REG_UPDATE (1 << 1) +#define XVIP_CTRL_CONTROL_BYPASS (1 << 4) +#define XVIP_CTRL_CONTROL_TEST_PATTERN (1 << 5) +#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET (1 << 30) +#define XVIP_CTRL_CONTROL_SW_RESET (1 << 31) +#define XVIP_CTRL_STATUS 0x0004 +#define XVIP_CTRL_STATUS_PROC_STARTED (1 << 0) +#define XVIP_CTRL_STATUS_EOF (1 << 1) +#define XVIP_CTRL_ERROR 0x0008 +#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY (1 << 0) +#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE (1 << 1) +#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY (1 << 2) +#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE (1 << 3) +#define XVIP_CTRL_IRQ_ENABLE 0x000c +#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED (1 << 0) +#define XVIP_CTRL_IRQ_EOF (1 << 1) +#define XVIP_CTRL_VERSION 0x0010 +#define XVIP_CTRL_VERSION_MAJOR_MASK (0xff << 24) +#define XVIP_CTRL_VERSION_MAJOR_SHIFT 24 +#define XVIP_CTRL_VERSION_MINOR_MASK (0xff << 16) +#define XVIP_CTRL_VERSION_MINOR_SHIFT 16 +#define XVIP_CTRL_VERSION_REVISION_MASK (0xf << 12) +#define XVIP_CTRL_VERSION_REVISION_SHIFT 12 +#define XVIP_CTRL_VERSION_PATCH_MASK (0xf << 8) +#define XVIP_CTRL_VERSION_PATCH_SHIFT 8 +#define XVIP_CTRL_VERSION_INTERNAL_MASK (0xff << 0) +#define XVIP_CTRL_VERSION_INTERNAL_SHIFT 0 + +/* Xilinx Video IP Timing Registers */ +#define XVIP_TIMING_ACTIVE_SIZE 0x0020 +#define XVIP_TIMING_ACTIVE_VSIZE_MASK (0x7ff << 16) +#define XVIP_TIMING_ACTIVE_VSIZE_SHIFT 16 +#define XVIP_TIMING_ACTIVE_HSIZE_MASK (0x7ff << 0) +#define XVIP_TIMING_ACTIVE_HSIZE_SHIFT 0 +#define XVIP_TIMING_OUTPUT_ENCODING 0x0028 +#define XVIP_TIMING_OUTPUT_NBITS_8 (0 << 4) +#define XVIP_TIMING_OUTPUT_NBITS_10 (1 << 4) +#define XVIP_TIMING_OUTPUT_NBITS_12 (2 << 4) +#define XVIP_TIMING_OUTPUT_NBITS_16 (3 << 4) +#define XVIP_TIMING_OUTPUT_NBITS_MASK (3 << 4) +#define XVIP_TIMING_OUTPUT_NBITS_SHIFT 4 +#define XVIP_TIMING_VIDEO_FORMAT_YUV422 (0 << 0) +#define XVIP_TIMING_VIDEO_FORMAT_YUV444 (1 << 0) +#define XVIP_TIMING_VIDEO_FORMAT_RGB (2 << 0) +#define XVIP_TIMING_VIDEO_FORMAT_YUV420 (3 << 0) +#define XVIP_TIMING_VIDEO_FORMAT_MASK (3 << 0) +#define XVIP_TIMING_VIDEO_FORMAT_SHIFT 0 + +/** + * struct xvip_device - Xilinx Video IP device structure + * @subdev: V4L2 subdevice + * @dev: (OF) device + * @iomem: device I/O register space remapped to kernel virtual memory + */ +struct xvip_device { + struct v4l2_subdev subdev; + struct device *dev; + void __iomem *iomem; +}; + +/** + * struct xvip_video_format - Xilinx Video IP video format description + * @name: AXI4 format name + * @width: AXI4 format width in bits per component + * @bpp: bytes per pixel (when stored in memory) + * @code: media bus format code + * @fourcc: V4L2 pixel format FCC identifier + */ +struct xvip_video_format { + const char *name; + unsigned int width; + unsigned int bpp; + unsigned int code; + u32 fourcc; +}; + +const struct xvip_video_format *xvip_get_format_by_code(unsigned int code); +const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc); +const struct xvip_video_format *xvip_of_get_format(struct device_node *node); + +static inline u32 xvip_read(struct xvip_device *xvip, u32 addr) +{ + return ioread32(xvip->iomem + addr); +} + +static inline void xvip_write(struct xvip_device *xvip, u32 addr, u32 value) +{ + iowrite32(value, xvip->iomem + addr); +} + +#endif /* __XILINX_VIP_H__ */ Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-vipp.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-vipp.c 2014-07-20 22:06:36.630301198 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Video IP Pipeline + * + * Copyright (C) 2013 Ideas on Board SPRL + * + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> +#include <media/v4l2-of.h> + +#include "xilinx-dma.h" +#include "xilinx-vipp.h" + +#define XVIPP_DMA_S2MM 0 +#define XVIPP_DMA_MM2S 1 + +/** + * struct xvip_pipeline_entity - Entity in a video pipeline + * @list: list entry in a pipeline entities list + * @node: the entity's DT node + * @entity: media entity, from the corresponding V4L2 subdev or video device + * @asd: subdev asynchronous registration information + * @subdev: V4L2 subdev (valid for all entities by DMA channels) + */ +struct xvip_pipeline_entity { + struct list_head list; + struct device_node *node; + struct media_entity *entity; + + struct v4l2_async_subdev asd; + struct v4l2_subdev *subdev; +}; + +/* ----------------------------------------------------------------------------- + * Pipeline Stream Management + */ + +/** + * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline + * @xvipp: Xilinx Video Pipeline + * @start: Start (when true) or stop (when false) the pipeline + * + * Walk the entities chain starting at the pipeline output video node and start + * or stop all of them. + * + * Return: 0 if successful, or the return value of the failed video::s_stream + * operation otherwise. + */ +static int xvip_pipeline_start_stop(struct xvip_pipeline *xvipp, bool start) +{ + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int ret; + + entity = &xvipp->dma[XVIPP_DMA_S2MM].video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, start); + if (start && ret < 0 && ret != -ENOIOCTLCMD) + return ret; + } + + return 0; +} + +/** + * xvip_pipeline_set_stream - Enable/disable streaming on a pipeline + * @xvipp: Xilinx Video Pipeline + * @on: Turn the stream on when true or off when false + * + * The pipeline is shared between all DMA engines connect at its input and + * output. While the stream state of DMA engines can be controlled + * independently, pipelines have a shared stream state that enable or disable + * all entities in the pipeline. For this reason the pipeline uses a streaming + * counter that tracks the number of DMA engines that have requested the stream + * to be enabled. + * + * When called with the @on argument set to true, this function will increment + * the pipeline streaming count. If the streaming count reaches the number of + * DMA engines in the pipeline it will enable all entities that belong to the + * pipeline. + * + * Similarly, when called with the @on argument set to false, this function will + * decrement the pipeline streaming count and disable all entities in the + * pipeline when the streaming count reaches zero. + * + * Return: 0 if successful, or the return value of the failed video::s_stream + * operation otherwise. Stopping the pipeline never fails. The pipeline state is + * not updated when the operation fails. + */ +int xvip_pipeline_set_stream(struct xvip_pipeline *xvipp, bool on) +{ + int ret = 0; + + mutex_lock(&xvipp->lock); + + if (on) { + if (xvipp->stream_count == xvipp->num_dmas - 1) { + ret = xvip_pipeline_start_stop(xvipp, true); + if (ret < 0) + goto done; + } + xvipp->stream_count++; + } else { + if (--xvipp->stream_count == 0) + xvip_pipeline_start_stop(xvipp, false); + } + +done: + mutex_unlock(&xvipp->lock); + return ret; +} + +/* ----------------------------------------------------------------------------- + * Pipeline Management + */ + +static struct xvip_pipeline_entity * +xvipp_pipeline_find_entity(struct xvip_pipeline *xvipp, + const struct device_node *node) +{ + struct xvip_pipeline_entity *entity; + + list_for_each_entry(entity, &xvipp->entities, list) { + if (entity->node == node) + return entity; + } + + return NULL; +} + +static int xvipp_pipeline_build_one(struct xvip_pipeline *xvipp, + struct xvip_pipeline_entity *entity) +{ + u32 link_flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; + struct media_entity *local = entity->entity; + struct media_entity *remote; + struct media_pad *local_pad; + struct media_pad *remote_pad; + struct xvip_pipeline_entity *ent; + struct v4l2_of_link link; + struct device_node *ep = NULL; + struct device_node *next; + int ret = 0; + + dev_dbg(xvipp->dev, "creating links for entity %s\n", local->name); + + while (1) { + /* Get the next endpoint and parse its link. */ + next = v4l2_of_get_next_endpoint(entity->node, ep); + if (next == NULL) + break; + + of_node_put(ep); + ep = next; + + dev_dbg(xvipp->dev, "processing endpoint %s\n", ep->full_name); + + ret = v4l2_of_parse_link(ep, &link); + if (ret < 0) { + dev_err(xvipp->dev, "failed to parse link for %s\n", + ep->full_name); + continue; + } + + /* Skip sink ports, they will be processed from the other end of + * the link. + */ + if (link.local_port >= local->num_pads) { + dev_err(xvipp->dev, "invalid port number %u on %s\n", + link.local_port, link.local_node->full_name); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + local_pad = &local->pads[link.local_port]; + + if (local_pad->flags & MEDIA_PAD_FL_SINK) { + dev_dbg(xvipp->dev, "skipping sink port %s:%u\n", + link.local_node->full_name, link.local_port); + v4l2_of_put_link(&link); + continue; + } + + /* Find the remote entity. */ + ent = xvipp_pipeline_find_entity(xvipp, link.remote_node); + if (ent == NULL) { + dev_err(xvipp->dev, "no entity found for %s\n", + link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -ENODEV; + break; + } + + remote = ent->entity; + + if (link.remote_port >= remote->num_pads) { + dev_err(xvipp->dev, "invalid port number %u on %s\n", + link.remote_port, link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + remote_pad = &remote->pads[link.remote_port]; + + v4l2_of_put_link(&link); + + /* Create the media link. */ + dev_dbg(xvipp->dev, "creating %s:%u -> %s:%u link\n", + local->name, local_pad->index, + remote->name, remote_pad->index); + + ret = media_entity_create_link(local, local_pad->index, + remote, remote_pad->index, + link_flags); + if (ret < 0) { + dev_err(xvipp->dev, + "failed to create %s:%u -> %s:%u link\n", + local->name, local_pad->index, + remote->name, remote_pad->index); + break; + } + } + + of_node_put(ep); + return ret; +} + +static int xvipp_pipeline_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct xvip_pipeline *xvipp = + container_of(notifier, struct xvip_pipeline, notifier); + struct xvip_pipeline_entity *entity; + int ret; + + dev_dbg(xvipp->dev, "notify complete, all subdevs registered\n"); + + /* Create links for every entity. */ + list_for_each_entry(entity, &xvipp->entities, list) { + ret = xvipp_pipeline_build_one(xvipp, entity); + if (ret < 0) + return ret; + } + + ret = v4l2_device_register_subdev_nodes(&xvipp->v4l2_dev); + if (ret < 0) + dev_err(xvipp->dev, "failed to register subdev nodes\n"); + + return ret; +} + +static int xvipp_pipeline_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct xvip_pipeline *xvipp = + container_of(notifier, struct xvip_pipeline, notifier); + struct xvip_pipeline_entity *entity; + + /* Locate the entity corresponding to the bound subdev and store the + * subdev pointer. + */ + list_for_each_entry(entity, &xvipp->entities, list) { + if (entity->node != subdev->dev->of_node) + continue; + + if (entity->subdev) { + dev_err(xvipp->dev, "duplicate subdev for node %s\n", + entity->node->full_name); + return -EINVAL; + } + + dev_dbg(xvipp->dev, "subdev %s bound\n", subdev->name); + entity->entity = &subdev->entity; + entity->subdev = subdev; + return 0; + } + + dev_err(xvipp->dev, "no entity for subdev %s\n", subdev->name); + return -EINVAL; +} + +static int xvipp_pipeline_parse_one(struct xvip_pipeline *xvipp, + struct device_node *node) +{ + struct xvip_pipeline_entity *entity; + struct device_node *remote; + struct device_node *ep = NULL; + struct device_node *next; + int ret = 0; + + dev_dbg(xvipp->dev, "parsing node %s\n", node->full_name); + + while (1) { + next = v4l2_of_get_next_endpoint(node, ep); + if (next == NULL) + break; + + of_node_put(ep); + ep = next; + + dev_dbg(xvipp->dev, "handling endpoint %s\n", ep->full_name); + + remote = v4l2_of_get_remote_port_parent(ep); + if (remote == NULL) { + ret = -EINVAL; + break; + } + + /* Skip entities that we have already processed. */ + if (xvipp_pipeline_find_entity(xvipp, remote)) { + of_node_put(remote); + continue; + } + + entity = devm_kzalloc(xvipp->dev, sizeof(*entity), GFP_KERNEL); + if (entity == NULL) { + of_node_put(remote); + ret = -ENOMEM; + break; + } + + entity->node = remote; + entity->asd.match_type = V4L2_ASYNC_MATCH_OF; + entity->asd.match.of.node = remote; + list_add_tail(&entity->list, &xvipp->entities); + xvipp->num_subdevs++; + } + + of_node_put(ep); + return ret; +} + +static int xvipp_pipeline_parse(struct xvip_pipeline *xvipp) +{ + struct xvip_pipeline_entity *entity; + int ret; + + /* Walk the links to parse the full pipeline. */ + list_for_each_entry(entity, &xvipp->entities, list) { + ret = xvipp_pipeline_parse_one(xvipp, entity->node); + if (ret < 0) + break; + } + + return ret; +} + +static int +xvipp_pipeline_dma_init_one(struct xvip_pipeline *xvipp, struct xvip_dma *dma, + struct device_node *node, enum v4l2_buf_type type) +{ + struct xvip_pipeline_entity *entity; + int ret; + + ret = xvip_dma_init(xvipp, dma, type); + if (ret < 0) { + dev_err(xvipp->dev, "%s initialization failed\n", + node->full_name); + return ret; + } + + entity = devm_kzalloc(xvipp->dev, sizeof(*entity), GFP_KERNEL); + if (entity == NULL) + return -ENOMEM; + + entity->node = of_node_get(node); + entity->entity = &dma->video.entity; + + list_add_tail(&entity->list, &xvipp->entities); + xvipp->num_dmas++; + + return 0; +} + +static int xvipp_pipeline_dma_init(struct xvip_pipeline *xvipp) +{ + struct device_node *vdma; + int ret; + + /* The s2mm vdma channel at the pipeline output is mandatory. */ + vdma = of_get_child_by_name(xvipp->dev->of_node, "vdma-s2mm"); + if (vdma == NULL) { + dev_err(xvipp->dev, "vdma-s2mm node not present\n"); + return -EINVAL; + } + + ret = xvipp_pipeline_dma_init_one(xvipp, &xvipp->dma[XVIPP_DMA_S2MM], + vdma, V4L2_BUF_TYPE_VIDEO_CAPTURE); + of_node_put(vdma); + + if (ret < 0) + return ret; + + /* The mm2s vdma channel at the pipeline input is optional. */ + vdma = of_get_child_by_name(xvipp->dev->of_node, "vdma-mm2s"); + if (vdma == NULL) + return 0; + + ret = xvipp_pipeline_dma_init_one(xvipp, &xvipp->dma[XVIPP_DMA_MM2S], + vdma, V4L2_BUF_TYPE_VIDEO_OUTPUT); + of_node_put(vdma); + + return ret; +} + +static void xvipp_pipeline_cleanup(struct xvip_pipeline *xvipp) +{ + struct xvip_pipeline_entity *entity; + struct xvip_pipeline_entity *prev; + + v4l2_async_notifier_unregister(&xvipp->notifier); + + list_for_each_entry_safe(entity, prev, &xvipp->entities, list) { + of_node_put(entity->node); + list_del(&entity->list); + } + + xvip_dma_cleanup(&xvipp->dma[XVIPP_DMA_S2MM]); + xvip_dma_cleanup(&xvipp->dma[XVIPP_DMA_MM2S]); +} + +static int xvipp_pipeline_init(struct xvip_pipeline *xvipp) +{ + struct xvip_pipeline_entity *entity; + struct v4l2_async_subdev **subdevs = NULL; + unsigned int num_subdevs; + unsigned int i; + int ret; + + /* Init the DMA channels. */ + ret = xvipp_pipeline_dma_init(xvipp); + if (ret < 0) { + dev_err(xvipp->dev, "DMA initialization failed\n"); + goto done; + } + + /* Parse the pipeline to extract a list of subdevice DT nodes. */ + ret = xvipp_pipeline_parse(xvipp); + if (ret < 0) { + dev_err(xvipp->dev, "pipeline parsing failed\n"); + goto done; + } + + if (!xvipp->num_subdevs) { + dev_err(xvipp->dev, "no subdev found in pipeline\n"); + goto done; + } + + /* Register the subdevices notifier. */ + num_subdevs = xvipp->num_subdevs; + subdevs = devm_kzalloc(xvipp->dev, sizeof(*subdevs) * num_subdevs, + GFP_KERNEL); + if (subdevs == NULL) { + ret = -ENOMEM; + goto done; + } + + i = 0; + list_for_each_entry(entity, &xvipp->entities, list) { + /* Skip entities that correspond to video nodes. */ + if (entity->entity == NULL) + subdevs[i++] = &entity->asd; + } + + xvipp->notifier.subdevs = subdevs; + xvipp->notifier.num_subdevs = num_subdevs; + xvipp->notifier.bound = xvipp_pipeline_notify_bound; + xvipp->notifier.complete = xvipp_pipeline_notify_complete; + + ret = v4l2_async_notifier_register(&xvipp->v4l2_dev, &xvipp->notifier); + if (ret < 0) { + dev_err(xvipp->dev, "notifier registration failed\n"); + goto done; + } + + ret = 0; + +done: + if (ret < 0) + xvipp_pipeline_cleanup(xvipp); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Media Controller and V4L2 + */ + +static void xvipp_v4l2_cleanup(struct xvip_pipeline *xvipp) +{ + v4l2_device_unregister(&xvipp->v4l2_dev); + media_device_unregister(&xvipp->media_dev); +} + +static int xvipp_v4l2_init(struct xvip_pipeline *xvipp) +{ + int ret; + + xvipp->media_dev.dev = xvipp->dev; + strlcpy(xvipp->media_dev.model, "Xilinx Video Pipeline", + sizeof(xvipp->media_dev.model)); + xvipp->media_dev.hw_revision = 0; + + ret = media_device_register(&xvipp->media_dev); + if (ret < 0) { + dev_err(xvipp->dev, "media device registration failed (%d)\n", + ret); + return ret; + } + + xvipp->v4l2_dev.mdev = &xvipp->media_dev; + ret = v4l2_device_register(xvipp->dev, &xvipp->v4l2_dev); + if (ret < 0) { + dev_err(xvipp->dev, "V4L2 device registration failed (%d)\n", + ret); + media_device_unregister(&xvipp->media_dev); + return ret; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static int xvipp_probe(struct platform_device *pdev) +{ + struct xvip_pipeline *xvipp; + int ret; + + xvipp = devm_kzalloc(&pdev->dev, sizeof(*xvipp), GFP_KERNEL); + if (!xvipp) + return -ENOMEM; + + xvipp->dev = &pdev->dev; + INIT_LIST_HEAD(&xvipp->entities); + mutex_init(&xvipp->lock); + + ret = xvipp_v4l2_init(xvipp); + if (ret < 0) + return ret; + + ret = xvipp_pipeline_init(xvipp); + if (ret < 0) + goto error; + + platform_set_drvdata(pdev, xvipp); + + dev_info(xvipp->dev, "device registered\n"); + + return 0; + +error: + xvipp_v4l2_cleanup(xvipp); + return ret; +} + +static int xvipp_remove(struct platform_device *pdev) +{ + struct xvip_pipeline *xvipp = platform_get_drvdata(pdev); + + xvipp_pipeline_cleanup(xvipp); + xvipp_v4l2_cleanup(xvipp); + mutex_destroy(&xvipp->lock); + + return 0; +} + +static const struct of_device_id xvipp_of_id_table[] = { + { .compatible = "xlnx,axi-video" }, + { } +}; +MODULE_DEVICE_TABLE(of, xvipp_of_id_table); + +static struct platform_driver xvipp_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "xilinx-axi-video", + .of_match_table = of_match_ptr(xvipp_of_id_table), + }, + .probe = xvipp_probe, + .remove = xvipp_remove, +}; + +module_platform_driver(xvipp_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("Xilinx Video IP Pipeline Driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-vipp.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/media/platform/xilinx/xilinx-vipp.h 2014-07-20 22:06:36.637301083 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Video IP Pipeline + * + * Copyright (C) 2013 Ideas on Board SPRL + * + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIPP_H__ +#define __XILINX_VIPP_H__ + +#include <linux/list.h> +#include <linux/mutex.h> +#include <media/media-device.h> +#include <media/v4l2-async.h> +#include <media/v4l2-device.h> + +#include "xilinx-dma.h" + +/** + * struct xvip_pipeline - Xilinx Video IP device structure + * @v4l2_dev: V4L2 device + * @media_dev: media device + * @pipe: media pipeline + * @dev: (OF) device + * @notifier: V4L2 asynchronous subdevs notifier + * @entities: entities in the pipeline as a list of xvip_pipeline_entity + * @num_subdevs: number of subdevs in the pipeline + * @dma: DMA channels at the pipeline output and input + * @num_dmas: number of DMA engines in the pipeline + * @lock: protects the pipeline @stream_count + * @stream_count: number of DMA engines currently streaming + */ +struct xvip_pipeline { + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct media_pipeline pipe; + struct device *dev; + + struct v4l2_async_notifier notifier; + struct list_head entities; + unsigned int num_subdevs; + + struct xvip_dma dma[2]; + unsigned int num_dmas; + + struct mutex lock; + unsigned int stream_count; +}; + +int xvip_pipeline_set_stream(struct xvip_pipeline *xvipp, bool on); + +#endif /* __XILINX_VIPP_H__ */ Index: linux-3.12.24-rt38-xilinx/drivers/media/v4l2-core/v4l2-of.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/media/v4l2-core/v4l2-of.c 2014-07-20 22:05:50.215066968 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/media/v4l2-core/v4l2-of.c 2014-07-20 22:06:36.650300869 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:124 @ * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. * The caller should hold a reference to @node. + * + * Return: 0. */ -void v4l2_of_parse_endpoint(const struct device_node *node, - struct v4l2_of_endpoint *endpoint) +int v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) { struct device_node *port_node = of_get_parent(node); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:151 @ v4l2_of_parse_parallel_bus(node, endpoint); of_node_put(port_node); + + return 0; } EXPORT_SYMBOL(v4l2_of_parse_endpoint); /** + * v4l2_of_parse_link() - parse a link between two endpoints + * @node: pointer to the endpoint at the local end of the link + * @link: pointer to the V4L2 OF link data structure + * + * Fill the link structure with the local and remote nodes and port numbers. + * The local_node and remote_node fields are set to point to the local and + * remote port parent nodes respectively (the port parent node being the parent + * node of the port node if that node isn't a 'ports' node, or the grand-parent + * node of the port node otherwise). + * + * A reference is taken to both the local and remote nodes, the caller must use + * v4l2_of_put_link() to drop the references when done with the link. + * + * Return: 0 on success, or -ENOLINK if the remote endpoint can't be found. + */ +int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link) +{ + struct device_node *np; + + memset(link, 0, sizeof(*link)); + + np = of_get_parent(node); + of_property_read_u32(np, "reg", &link->local_port); + np = of_get_next_parent(np); + if (of_node_cmp(np->name, "ports") == 0) + np = of_get_next_parent(np); + link->local_node = np; + + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) { + of_node_put(link->local_node); + return -ENOLINK; + } + + np = of_get_parent(np); + of_property_read_u32(np, "reg", &link->remote_port); + np = of_get_next_parent(np); + if (of_node_cmp(np->name, "ports") == 0) + np = of_get_next_parent(np); + link->remote_node = np; + + return 0; +} +EXPORT_SYMBOL(v4l2_of_parse_link); + +/** + * v4l2_of_put_link() - drop references to nodes in a link + * @link: pointer to the V4L2 OF link data structure + * + * Drop references to the local and remote nodes in the link. This function must + * be called on every link parsed with v4l2_of_parse_link(). + */ +void v4l2_of_put_link(struct v4l2_of_link *link) +{ + of_node_put(link->local_node); + of_node_put(link->remote_node); +} +EXPORT_SYMBOL(v4l2_of_put_link); + +/** * v4l2_of_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node * @prev: previous endpoint node, or NULL to get first @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:330 @ np = of_parse_phandle(node, "remote-endpoint", 0); if (!np) return NULL; - return of_get_parent(np); + return of_get_next_parent(np); } EXPORT_SYMBOL(v4l2_of_get_remote_port); Index: linux-3.12.24-rt38-xilinx/drivers/memory/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/memory/Kconfig 2014-07-20 22:05:50.190067380 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/memory/Kconfig 2014-07-20 22:06:36.663300654 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:53 @ analysis, especially for IOMMU/SMMU(System Memory Management Unit) module. +config ZYNQ_SMC + bool "Zynq Static Memory Controller(SMC) driver" + default y + depends on ARCH_ZYNQ + help + This driver is for the Static Memory Controller(SMC) module available + in Zynq SoCs. endif Index: linux-3.12.24-rt38-xilinx/drivers/memory/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/memory/Makefile 2014-07-20 22:05:50.189067397 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/memory/Makefile 2014-07-20 22:06:36.672300505 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:12 @ obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o +obj-$(CONFIG_ZYNQ_SMC) += zynq-smc.o Index: linux-3.12.24-rt38-xilinx/drivers/memory/zynq-smc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/memory/zynq-smc.c 2014-07-20 22:06:36.684300308 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Zynq SMC Driver + * + * Copyright (C) 2012 - 2013 Xilinx, Inc. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Currently only a single SMC instance is supported. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/memory/zynq-smc.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* Register definitions */ +#define XSMCPS_MEMC_STATUS_OFFS 0 /* Controller status reg, RO */ +#define XSMCPS_CFG_CLR_OFFS 0xC /* Clear config reg, WO */ +#define XSMCPS_DIRECT_CMD_OFFS 0x10 /* Direct command reg, WO */ +#define XSMCPS_SET_CYCLES_OFFS 0x14 /* Set cycles register, WO */ +#define XSMCPS_SET_OPMODE_OFFS 0x18 /* Set opmode register, WO */ +#define XSMCPS_ECC_STATUS_OFFS 0x400 /* ECC status register */ +#define XSMCPS_ECC_MEMCFG_OFFS 0x404 /* ECC mem config reg */ +#define XSMCPS_ECC_MEMCMD1_OFFS 0x408 /* ECC mem cmd1 reg */ +#define XSMCPS_ECC_MEMCMD2_OFFS 0x40C /* ECC mem cmd2 reg */ +#define XSMCPS_ECC_VALUE0_OFFS 0x418 /* ECC value 0 reg */ + +#define XSMCPS_CFG_CLR_INT_1 0x10 +#define XSMCPS_ECC_STATUS_BUSY (1 << 6) +#define XSMCPS_DC_UPT_NAND_REGS ((4 << 23) | /* CS: NAND chip */ \ + (2 << 21)) /* UpdateRegs operation */ + +#define XNANDPS_ECC_CMD1 ((0x80) | /* Write command */ \ + (0 << 8) | /* Read command */ \ + (0x30 << 16) | /* Read End command */ \ + (1 << 24)) /* Read End command calid */ + +#define XNANDPS_ECC_CMD2 ((0x85) | /* Write col change cmd */ \ + (5 << 8) | /* Read col change cmd */ \ + (0xE0 << 16) | /* Read col change end cmd */ \ + (1 << 24)) /* Read col change end cmd valid */ +/** + * struct xsmcps_data + * @devclk: Pointer to the peripheral clock + * @aperclk: Pointer to the APER clock + * @clk_rate_change_nb: Notifier block for clock frequency change callback + */ +struct xsmcps_data { + struct clk *devclk; + struct clk *aperclk; + struct notifier_block clk_rate_change_nb; +}; + +/* SMC virtual register base */ +static void __iomem *xsmcps_base; +static DEFINE_SPINLOCK(xsmcps_lock); + +/** + * xsmcps_set_buswidth - Set memory buswidth + * @bw: Memory buswidth (8 | 16) + * Returns 0 on success or negative errno. + * + * Must be called with xsmcps_lock held. + */ +static int xsmcps_set_buswidth(unsigned int bw) +{ + u32 reg; + + if (bw != 8 && bw != 16) + return -EINVAL; + + reg = readl(xsmcps_base + XSMCPS_SET_OPMODE_OFFS); + reg &= ~3; + if (bw == 16) + reg |= 1; + writel(reg, xsmcps_base + XSMCPS_SET_OPMODE_OFFS); + + return 0; +} + +/** + * xsmcps_set_cycles - Set memory timing parameters + * @t0: t_rc read cycle time + * @t1: t_wc write cycle time + * @t2: t_rea/t_ceoe output enable assertion delay + * @t3: t_wp write enable deassertion delay + * @t4: t_clr/t_pc page cycle time + * @t5: t_ar/t_ta ID read time/turnaround time + * @t6: t_rr busy to RE timing + * + * Sets NAND chip specific timing parameters. + * + * Must be called with xsmcps_lock held. + */ +static void xsmcps_set_cycles(u32 t0, u32 t1, u32 t2, u32 t3, u32 + t4, u32 t5, u32 t6) +{ + t0 &= 0xf; + t1 = (t1 & 0xf) << 4; + t2 = (t2 & 7) << 8; + t3 = (t3 & 7) << 11; + t4 = (t4 & 7) << 14; + t5 = (t5 & 7) << 17; + t6 = (t6 & 0xf) << 20; + + t0 |= t1 | t2 | t3 | t4 | t5 | t6; + + writel(t0, xsmcps_base + XSMCPS_SET_CYCLES_OFFS); +} + +/** + * xsmcps_ecc_is_busy_noirq - Read ecc busy flag + * Returns the ecc_status bit from the ecc_status register. 1 = busy, 0 = idle + * + * Must be called with xsmcps_lock held. + */ +static int xsmcps_ecc_is_busy_noirq(void) +{ + return !!(readl(xsmcps_base + XSMCPS_ECC_STATUS_OFFS) & + XSMCPS_ECC_STATUS_BUSY); +} + +/** + * xsmcps_ecc_is_busy - Read ecc busy flag + * Returns the ecc_status bit from the ecc_status register. 1 = busy, 0 = idle + */ +int xsmcps_ecc_is_busy(void) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&xsmcps_lock, flags); + + ret = xsmcps_ecc_is_busy_noirq(); + + spin_unlock_irqrestore(&xsmcps_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(xsmcps_ecc_is_busy); + +/** + * xsmcps_get_ecc_val - Read ecc_valueN registers + * @ecc_reg: Index of the ecc_value reg (0..3) + * Returns the content of the requested ecc_value register. + * + * There are four valid ecc_value registers. The argument is truncated to stay + * within this valid boundary. + */ +u32 xsmcps_get_ecc_val(int ecc_reg) +{ + u32 addr, reg; + unsigned long flags; + + ecc_reg &= 3; + addr = XSMCPS_ECC_VALUE0_OFFS + (ecc_reg << 2); + + spin_lock_irqsave(&xsmcps_lock, flags); + + reg = readl(xsmcps_base + addr); + + spin_unlock_irqrestore(&xsmcps_lock, flags); + + return reg; +} +EXPORT_SYMBOL_GPL(xsmcps_get_ecc_val); + +/** + * xsmcps_get_nand_int_status_raw - Get NAND interrupt status bit + * Returns the raw_int_status1 bit from the memc_status register + */ +int xsmcps_get_nand_int_status_raw(void) +{ + u32 reg; + unsigned long flags; + + spin_lock_irqsave(&xsmcps_lock, flags); + + reg = readl(xsmcps_base + XSMCPS_MEMC_STATUS_OFFS); + + spin_unlock_irqrestore(&xsmcps_lock, flags); + + reg >>= 6; + reg &= 1; + + return reg; +} +EXPORT_SYMBOL_GPL(xsmcps_get_nand_int_status_raw); + +/** + * xsmcps_clr_nand_int - Clear NAND interrupt + */ +void xsmcps_clr_nand_int(void) +{ + unsigned long flags; + + spin_lock_irqsave(&xsmcps_lock, flags); + + writel(XSMCPS_CFG_CLR_INT_1, xsmcps_base + XSMCPS_CFG_CLR_OFFS); + + spin_unlock_irqrestore(&xsmcps_lock, flags); +} +EXPORT_SYMBOL_GPL(xsmcps_clr_nand_int); + +/** + * xsmcps_set_ecc_mode - Set SMC ECC mode + * @mode: ECC mode (BYPASS, APB, MEM) + * Returns 0 on success or negative errno. + */ +int xsmcps_set_ecc_mode(enum xsmcps_ecc_mode mode) +{ + u32 reg; + unsigned long flags; + int ret = 0; + + switch (mode) { + case XSMCPS_ECCMODE_BYPASS: + case XSMCPS_ECCMODE_APB: + case XSMCPS_ECCMODE_MEM: + spin_lock_irqsave(&xsmcps_lock, flags); + + reg = readl(xsmcps_base + XSMCPS_ECC_MEMCFG_OFFS); + reg &= ~0xc; + reg |= mode << 2; + writel(reg, xsmcps_base + XSMCPS_ECC_MEMCFG_OFFS); + + spin_unlock_irqrestore(&xsmcps_lock, flags); + break; + default: + ret = -EINVAL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(xsmcps_set_ecc_mode); + +/** + * xsmcps_set_ecc_pg_size - Set SMC ECC page size + * @pg_sz: ECC page size + * Returns 0 on success or negative errno. + */ +int xsmcps_set_ecc_pg_size(unsigned int pg_sz) +{ + u32 reg, sz; + unsigned long flags; + + switch (pg_sz) { + case 0: + sz = 0; + break; + case 512: + sz = 1; + break; + case 1024: + sz = 2; + break; + case 2048: + sz = 3; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&xsmcps_lock, flags); + + reg = readl(xsmcps_base + XSMCPS_ECC_MEMCFG_OFFS); + reg &= ~3; + reg |= sz; + writel(reg, xsmcps_base + XSMCPS_ECC_MEMCFG_OFFS); + + spin_unlock_irqrestore(&xsmcps_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(xsmcps_set_ecc_pg_size); + +static int xsmcps_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + switch (event) { + case PRE_RATE_CHANGE: + /* + * if a rate change is announced we need to check whether we can + * run under the changed conditions + */ + /* fall through */ + case POST_RATE_CHANGE: + return NOTIFY_OK; + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +#ifdef CONFIG_PM_SLEEP +static int xsmcps_suspend(struct device *dev) +{ + struct xsmcps_data *xsmcps = dev_get_drvdata(dev); + + clk_disable(xsmcps->devclk); + clk_disable(xsmcps->aperclk); + + return 0; +} + +static int xsmcps_resume(struct device *dev) +{ + int ret; + struct xsmcps_data *xsmcps = dev_get_drvdata(dev); + + ret = clk_enable(xsmcps->aperclk); + if (ret) { + dev_err(dev, "Cannot enable APER clock.\n"); + return ret; + } + + ret = clk_enable(xsmcps->devclk); + if (ret) { + dev_err(dev, "Cannot enable device clock.\n"); + clk_disable(xsmcps->aperclk); + return ret; + } + return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(xsmcps_dev_pm_ops, xsmcps_suspend, xsmcps_resume); + +/** + * xsmcps_init_nand_interface - Initialize the NAND interface + * @pdev: Pointer to the platform_device struct + * @nand_node: Pointer to the xnandps device_node struct + */ +static void xsmcps_init_nand_interface(struct platform_device *pdev, + struct device_node *nand_node) +{ + u32 t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr; + unsigned int bw; + int err; + unsigned long flags; + + err = of_property_read_u32(nand_node, "xlnx,nand-width", &bw); + if (err) { + dev_warn(&pdev->dev, + "xlnx,nand-width not in device tree, using 8"); + bw = 8; + } + /* nand-cycle-<X> property is refer to the NAND flash timing + * mapping between dts and the NAND flash AC timing + * X : AC timing name + * t0 : t_rc + * t1 : t_wc + * t2 : t_rea + * t3 : t_wp + * t4 : t_clr + * t5 : t_ar + * t6 : t_rr + */ + err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t0", &t_rc); + if (err) { + dev_warn(&pdev->dev, "xlnx,nand-cycle-t0 not in device tree"); + goto default_nand_timing; + } + err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t1", &t_wc); + if (err) { + dev_warn(&pdev->dev, "xlnx,nand-cycle-t1 not in device tree"); + goto default_nand_timing; + } + err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t2", &t_rea); + if (err) { + dev_warn(&pdev->dev, "xlnx,nand-cycle-t2 not in device tree"); + goto default_nand_timing; + } + err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t3", &t_wp); + if (err) { + dev_warn(&pdev->dev, "xlnx,nand-cycle-t3 not in device tree"); + goto default_nand_timing; + } + err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t4", &t_clr); + if (err) { + dev_warn(&pdev->dev, "xlnx,nand-cycle-t4 not in device tree"); + goto default_nand_timing; + } + err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t5", &t_ar); + if (err) { + dev_warn(&pdev->dev, "xlnx,nand-cycle-t5 not in device tree"); + goto default_nand_timing; + } + err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t6", &t_rr); + if (err) { + dev_warn(&pdev->dev, "xlnx,nand-cycle-t6 not in device tree"); + goto default_nand_timing; + } + +default_nand_timing: + if (err) { + /* set default NAND flash timing property */ + dev_warn(&pdev->dev, "Using default timing for"); + dev_warn(&pdev->dev, "2Gb Numonyx MT29F2G08ABAEAWP NAND flash"); + dev_warn(&pdev->dev, "t_wp, t_clr, t_ar are set to 4"); + dev_warn(&pdev->dev, "t_rc, t_wc, t_rr are set to 2"); + dev_warn(&pdev->dev, "t_rea is set to 1"); + t_rc = t_wc = t_rr = 4; + t_rea = 1; + t_wp = t_clr = t_ar = 2; + } + + spin_lock_irqsave(&xsmcps_lock, flags); + + if (xsmcps_set_buswidth(bw)) { + dev_warn(&pdev->dev, "xlnx,nand-width not valid, using 8"); + xsmcps_set_buswidth(8); + } + + /* + * Default assume 50MHz clock (20ns cycle time) and 3V operation + * The SET_CYCLES_REG register value depends on the flash device. + * Look in to the device datasheet and change its value, This value + * is for 2Gb Numonyx flash. + */ + xsmcps_set_cycles(t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr); + writel(XSMCPS_CFG_CLR_INT_1, xsmcps_base + XSMCPS_CFG_CLR_OFFS); + writel(XSMCPS_DC_UPT_NAND_REGS, xsmcps_base + XSMCPS_DIRECT_CMD_OFFS); + /* Wait till the ECC operation is complete */ + while (xsmcps_ecc_is_busy_noirq()) + cpu_relax(); + /* Set the command1 and command2 register */ + writel(XNANDPS_ECC_CMD1, xsmcps_base + XSMCPS_ECC_MEMCMD1_OFFS); + writel(XNANDPS_ECC_CMD2, xsmcps_base + XSMCPS_ECC_MEMCMD2_OFFS); + + spin_unlock_irqrestore(&xsmcps_lock, flags); +} + +static const struct of_device_id matches_nor[] = { + { .compatible = "cfi-flash" }, + {} +}; + +static const struct of_device_id matches_nand[] = { + { .compatible = "xlnx,ps7-nand-1.00.a" }, + {} +}; + +static int xsmcps_probe(struct platform_device *pdev) +{ + struct xsmcps_data *xsmcps; + struct device_node *child; + struct resource *res; + unsigned long flags; + int err; + struct device_node *of_node = pdev->dev.of_node; + const struct of_device_id *matches = NULL; + + xsmcps = devm_kzalloc(&pdev->dev, sizeof(*xsmcps), GFP_KERNEL); + if (!xsmcps) + return -ENOMEM; + + /* Get the NAND controller virtual address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xsmcps_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xsmcps_base)) + return PTR_ERR(xsmcps_base); + + xsmcps->aperclk = devm_clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(xsmcps->aperclk)) { + dev_err(&pdev->dev, "aper_clk clock not found.\n"); + return PTR_ERR(xsmcps->aperclk); + } + + xsmcps->devclk = devm_clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(xsmcps->devclk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + return PTR_ERR(xsmcps->devclk); + } + + err = clk_prepare_enable(xsmcps->aperclk); + if (err) { + dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + return err; + } + + err = clk_prepare_enable(xsmcps->devclk); + if (err) { + dev_err(&pdev->dev, "Unable to enable device clock.\n"); + goto out_clk_dis_aper; + } + + platform_set_drvdata(pdev, xsmcps); + + xsmcps->clk_rate_change_nb.notifier_call = xsmcps_clk_notifier_cb; + if (clk_notifier_register(xsmcps->devclk, &xsmcps->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); + + + /* clear interrupts */ + spin_lock_irqsave(&xsmcps_lock, flags); + + writel(0x52, xsmcps_base + XSMCPS_CFG_CLR_OFFS); + + spin_unlock_irqrestore(&xsmcps_lock, flags); + + /* Find compatible children. Only a single child is supported */ + for_each_available_child_of_node(of_node, child) { + if (of_match_node(matches_nand, child)) { + xsmcps_init_nand_interface(pdev, child); + if (!matches) { + matches = matches_nand; + } else { + dev_err(&pdev->dev, + "incompatible configuration\n"); + goto out_clk_disable; + } + } + + if (of_match_node(matches_nor, child)) { + static int counts; + if (!matches) { + matches = matches_nor; + } else { + if (matches != matches_nor || counts > 1) { + dev_err(&pdev->dev, + "incompatible configuration\n"); + goto out_clk_disable; + } + } + counts++; + } + } + + if (matches) + of_platform_populate(of_node, matches, NULL, &pdev->dev); + + return 0; + +out_clk_disable: + clk_disable_unprepare(xsmcps->devclk); +out_clk_dis_aper: + clk_disable_unprepare(xsmcps->aperclk); + + return err; +} + +static int xsmcps_remove(struct platform_device *pdev) +{ + struct xsmcps_data *xsmcps = platform_get_drvdata(pdev); + + clk_notifier_unregister(xsmcps->devclk, &xsmcps->clk_rate_change_nb); + clk_disable_unprepare(xsmcps->devclk); + clk_disable_unprepare(xsmcps->aperclk); + + return 0; +} + +/* Match table for device tree binding */ +static const struct of_device_id xsmcps_of_match[] = { + { .compatible = "xlnx,ps7-smc" }, + { }, +}; +MODULE_DEVICE_TABLE(of, xsmcps_of_match); + +static struct platform_driver xsmcps_driver = { + .probe = xsmcps_probe, + .remove = xsmcps_remove, + .driver = { + .name = "xsmcps", + .owner = THIS_MODULE, + .pm = &xsmcps_dev_pm_ops, + .of_match_table = xsmcps_of_match, + }, +}; + +module_platform_driver(xsmcps_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx PS SMC Driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/misc/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/misc/Kconfig 2014-07-20 22:05:50.242066522 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/misc/Kconfig 2014-07-20 22:06:36.701300027 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:549 @ stereo and mono audio, video, microphone and UART data to use a common connector port. +config SI570 + tristate "Silicon Labs Si570 Clock Generator" + depends on I2C && SYSFS + help + If you say yes here you get support for the Silicon Labs Si570 + digital clock generator. + + To compile this driver as a module, choose M here: the module + will be called si570 + config LATTICE_ECP3_CONFIG tristate "Lattice ECP3 FPGA bitstream configuration via SPI" depends on SPI && SYSFS @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:579 @ the genalloc API. It is supposed to be used for small on-chip SRAM areas found on many SoCs. +config XILINX_TRAFGEN + tristate "Xilinx Traffic Generator" + depends on MICROBLAZE + help + This option enables support for the Xilinx Traffic Generator driver. + It is designed to generate AXI4 traffic which can be used to stress + different modules/interconnect connected in the system. Different + configurable options which are provided through sysfs entries allow + allow the user to generate a wide variety of traffic based on their + their requirements. + + If unsure, say N + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" Index: linux-3.12.24-rt38-xilinx/drivers/misc/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/misc/Makefile 2014-07-20 22:05:50.241066538 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/misc/Makefile 2014-07-20 22:06:36.711299862 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:53 @ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_INTEL_MEI) += mei/ +obj-$(CONFIG_SI570) += si570.o obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o obj-$(CONFIG_HWLAT_DETECTOR) += hwlat_detector.o +obj-$(CONFIG_XILINX_TRAFGEN) += xilinx_trafgen.o Index: linux-3.12.24-rt38-xilinx/drivers/misc/si570.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/misc/si570.c 2014-07-20 22:06:36.723299664 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Driver for Silicon Labs Si570/Si571 Programmable XO/VCXO + * + * Copyright (C) 2010, 2011 Ericsson AB. + * Copyright (C) 2011 Guenter Roeck. + * + * Author: Guenter Roeck <guenter.roeck@ericsson.com> + * + * 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. + */ + +#include <linux/module.h> +#include <linux/jiffies.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/log2.h> +#include <linux/slab.h> +#include <linux/i2c/si570.h> + +/* Si570 registers */ +#define SI570_REG_HS_N1 7 +#define SI570_REG_N1_RFREQ0 8 +#define SI570_REG_RFREQ1 9 +#define SI570_REG_RFREQ2 10 +#define SI570_REG_RFREQ3 11 +#define SI570_REG_RFREQ4 12 +#define SI570_REG_CONTROL 135 +#define SI570_REG_FREEZE_DCO 137 + +#define HS_DIV_SHIFT 5 +#define HS_DIV_MASK 0xe0 +#define HS_DIV_OFFSET 4 +#define N1_6_2_MASK 0x1f +#define N1_1_0_MASK 0xc0 +#define RFREQ_37_32_MASK 0x3f + +#define SI570_FOUT_FACTORY_DFLT 156250000LL +#define SI598_FOUT_FACTORY_DFLT 10000000LL + +#define SI570_MIN_FREQ 10000000L +#define SI570_MAX_FREQ 1417500000L +#define SI598_MAX_FREQ 525000000L + +#define FDCO_MIN 4850000000LL +#define FDCO_MAX 5670000000LL +#define FDCO_CENTER ((FDCO_MIN + FDCO_MAX) / 2) + +#define SI570_CNTRL_RECALL (1 << 0) +#define SI570_CNTRL_FREEZE_ADC (1 << 4) +#define SI570_CNTRL_FREEZE_M (1 << 5) +#define SI570_CNTRL_NEWFREQ (1 << 6) +#define SI570_CNTRL_RESET (1 << 7) + +#define SI570_FREEZE_DCO (1 << 4) +#define SI570_UNFREEZE_DCO 0xEF + +struct si570_data { + struct attribute_group attrs; + struct mutex lock; + u64 max_freq; + u64 fout; /* Factory default frequency */ + u64 fxtal; /* Factory xtal frequency */ + unsigned int n1; + unsigned int hs_div; + u64 rfreq; + u64 frequency; +}; + + +static struct i2c_client *si570_client; + + +static int si570_get_defaults(struct i2c_client *client) +{ + struct si570_data *data = i2c_get_clientdata(client); + int reg1, reg2, reg3, reg4, reg5, reg6; + u64 fdco; + + i2c_smbus_write_byte_data(client, SI570_REG_CONTROL, + SI570_CNTRL_RECALL); + + reg1 = i2c_smbus_read_byte_data(client, SI570_REG_HS_N1); + if (reg1 < 0) + return reg1; + reg2 = i2c_smbus_read_byte_data(client, SI570_REG_N1_RFREQ0); + if (reg2 < 0) + return reg2; + reg3 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ1); + if (reg3 < 0) + return reg3; + reg4 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ2); + if (reg4 < 0) + return reg4; + reg5 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ3); + if (reg5 < 0) + return reg5; + reg6 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ4); + if (reg6 < 0) + return reg6; + + data->hs_div = ((reg1 & HS_DIV_MASK) >> HS_DIV_SHIFT) + HS_DIV_OFFSET; + data->n1 = ((reg1 & N1_6_2_MASK) << 2) + ((reg2 & N1_1_0_MASK) >> 6) + + 1; + /* Handle invalid cases */ + if (data->n1 > 1) + data->n1 &= ~1; + + data->rfreq = reg2 & RFREQ_37_32_MASK; + data->rfreq = (data->rfreq << 8) + reg3; + data->rfreq = (data->rfreq << 8) + reg4; + data->rfreq = (data->rfreq << 8) + reg5; + data->rfreq = (data->rfreq << 8) + reg6; + + /* + * Accept optional precision loss to avoid arithmetic overflows. + * Acceptable per Silicon Labs Application Note AN334. + */ + fdco = data->fout * data->n1 * data->hs_div; + if (fdco >= (1LL << 36)) + data->fxtal = div64_u64((fdco << 24), (data->rfreq >> 4)); + else + data->fxtal = div64_u64((fdco << 28), data->rfreq); + + data->frequency = data->fout; + + return 0; +} + +/* + * Update rfreq registers + * This function must be called with update mutex lock held. + */ +static void si570_update_rfreq(struct i2c_client *client, + struct si570_data *data) +{ + int status; + status = i2c_smbus_write_byte_data(client, SI570_REG_N1_RFREQ0, + ((data->n1 - 1) << 6) + | ((data->rfreq >> 32) & RFREQ_37_32_MASK)); + if (status < 0) + dev_err(&client->dev, + "unable to write 0x%llX to REG_N1_RFREQ0: %d\n", + (((data->n1 - 1) << 6) | ((data->rfreq >> 32) & + RFREQ_37_32_MASK)) & 0xff, status); + status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ1, + (data->rfreq >> 24) & 0xff); + if (status < 0) + dev_err(&client->dev, + "unable to write 0x%llX to REG_RFREQ1: %d\n", + (data->rfreq >> 24) & 0xff, status); + status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ2, + (data->rfreq >> 16) & 0xff); + if (status < 0) + dev_err(&client->dev, + "unable to write 0x%llX to REG_RFREQ2: %d\n", + (data->rfreq >> 16) & 0xff, status); + status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ3, + (data->rfreq >> 8) & 0xff); + if (status < 0) + dev_err(&client->dev, + "unable to write 0x%llX to REG_RFREQ3: %d\n", + (data->rfreq >> 8) & 0xff, status); + status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ4, + data->rfreq & 0xff); + if (status < 0) + dev_err(&client->dev, + "unable to write 0x%llX to REG_RFREQ4: %d\n", + data->rfreq & 0xff, status); +} + +/* + * Update si570 frequency for small frequency changes (< 3,500 ppm) + * This function must be called with update mutex lock held. + */ +static int si570_set_frequency_small(struct i2c_client *client, + struct si570_data *data, + unsigned long frequency) +{ + data->frequency = frequency; + /* This is a re-implementation of DIV_ROUND_CLOSEST + * using the div64_u64 function lieu of letting the compiler + * insert EABI calls + */ + data->rfreq = div64_u64((data->rfreq * frequency) + + div64_u64(data->frequency, 2), data->frequency); + i2c_smbus_write_byte_data(client, SI570_REG_CONTROL, + SI570_CNTRL_FREEZE_M); + si570_update_rfreq(client, data); + i2c_smbus_write_byte_data(client, SI570_REG_CONTROL, 0); + + return 0; +} + +static const uint8_t si570_hs_div_values[] = { 11, 9, 7, 6, 5, 4 }; + +/* + * Set si570 frequency. + * This function must be called with update mutex lock held. + */ +static int si570_set_frequency(struct i2c_client *client, + struct si570_data *data, + unsigned long frequency) +{ + int i, n1, hs_div; + u64 fdco, best_fdco = ULLONG_MAX; + + for (i = 0; i < ARRAY_SIZE(si570_hs_div_values); i++) { + hs_div = si570_hs_div_values[i]; + /* Calculate lowest possible value for n1 */ + n1 = div64_u64(div64_u64(FDCO_MIN, (u64)hs_div), + (u64)frequency); + if (!n1 || (n1 & 1)) + n1++; + while (n1 <= 128) { + fdco = (u64)frequency * (u64)hs_div * (u64)n1; + if (fdco > FDCO_MAX) + break; + if (fdco >= FDCO_MIN && fdco < best_fdco) { + data->n1 = n1; + data->hs_div = hs_div; + data->frequency = frequency; + data->rfreq = div64_u64((fdco << 28), + data->fxtal); + best_fdco = fdco; + } + n1 += (n1 == 1 ? 1 : 2); + } + } + if (best_fdco == ULLONG_MAX) { + dev_err(&client->dev, "error - best FDCO is out of range\n"); + return -EINVAL; + } + + /* The DCO reg should be accessed with a read-modify-write operation + * per AN334 + */ + i2c_smbus_write_byte_data(client, SI570_REG_FREEZE_DCO, + SI570_FREEZE_DCO); + i2c_smbus_write_byte_data(client, SI570_REG_HS_N1, + ((data->hs_div - HS_DIV_OFFSET) << + HS_DIV_SHIFT) + | (((data->n1 - 1) >> 2) & N1_6_2_MASK)); + si570_update_rfreq(client, data); + i2c_smbus_write_byte_data(client, SI570_REG_FREEZE_DCO, + 0); + i2c_smbus_write_byte_data(client, SI570_REG_CONTROL, + SI570_CNTRL_NEWFREQ); + return 0; +} + +/* + * Reset chip. + * This function must be called with update mutex lock held. + */ +static int si570_reset(struct i2c_client *client, struct si570_data *data) +{ + i2c_smbus_write_byte_data(client, SI570_REG_CONTROL, + SI570_CNTRL_RESET); + usleep_range(1000, 5000); + return si570_set_frequency(client, data, data->frequency); +} + +static ssize_t show_frequency_attr(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct si570_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%llu\n", data->frequency); +} + +int get_frequency_si570(struct device *dev, unsigned long *freq) +{ + int err; + char buf[10+1]; + + if ((!dev) || (to_i2c_client(dev) != si570_client)) + return -EINVAL; + + show_frequency_attr(dev, NULL, buf); + + err = strict_strtoul(buf, 10, freq); + if (err) + return err; + + return 0; +} +EXPORT_SYMBOL(get_frequency_si570); + +static ssize_t set_frequency_attr(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct si570_data *data = i2c_get_clientdata(client); + unsigned long val; + int err; + + err = strict_strtoul(buf, 10, &val); + if (err) + return err; + + if (val < SI570_MIN_FREQ || val > data->max_freq) { + dev_err(&client->dev, + "requested frequency %lu Hz is out of range\n", val); + return -EINVAL; + } + + mutex_lock(&data->lock); + + if (div64_u64(abs(val - data->frequency) * 10000LL, + data->frequency) < 35) + err = si570_set_frequency_small(client, data, val); + else + err = si570_set_frequency(client, data, val); + mutex_unlock(&data->lock); + if (err) { + dev_warn(&client->dev, + "unable to set output frequency %lu Hz: %d\n", + val, err); + return err; + } + + dev_info(&client->dev, + "set new output frequency %lu Hz\n", val); + + return count; +} + +int set_frequency_si570(struct device *dev, unsigned long freq) +{ + char buf[10+1]; + + if ((!dev) || (to_i2c_client(dev) != si570_client)) + return -EINVAL; + + sprintf(buf, "%lu", freq); + + return set_frequency_attr(dev, NULL, buf, 0); +} +EXPORT_SYMBOL(set_frequency_si570); + +static ssize_t show_reset_attr(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "%d\n", 0); +} + +static ssize_t set_reset_attr(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct si570_data *data = i2c_get_clientdata(client); + unsigned long val; + int err; + + err = strict_strtoul(buf, 10, &val); + if (err) + return err; + if (val == 0) + goto done; + + mutex_lock(&data->lock); + err = si570_reset(client, data); + mutex_unlock(&data->lock); + if (err) + return err; +done: + return count; +} + +int reset_si570(struct device *dev, int id) +{ + char buf[4]; + + if ((!dev) || (to_i2c_client(dev) != si570_client)) + return -EINVAL; + + sprintf(buf, "%lu", (unsigned long)id); + return set_reset_attr(dev, NULL, buf, 0); +} +EXPORT_SYMBOL(reset_si570); + +struct i2c_client *get_i2c_client_si570(void) +{ + return si570_client; +} +EXPORT_SYMBOL(get_i2c_client_si570); + +static DEVICE_ATTR(frequency, S_IWUSR | S_IRUGO, show_frequency_attr, set_frequency_attr); +static DEVICE_ATTR(reset, S_IWUSR | S_IRUGO, show_reset_attr, set_reset_attr); + +static struct attribute *si570_attr[] = { + &dev_attr_frequency.attr, + &dev_attr_reset.attr, + NULL +}; + +static const struct i2c_device_id si570_id[] = { + { "si570", 0 }, + { "si571", 0 }, + { "si598", 1 }, + { "si599", 1 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si570_id); + +static int si570_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct si570_platform_data *pdata = client->dev.platform_data; + struct si570_data *data; + int err; + unsigned long initial_fout; + u32 tmp = SI570_FOUT_FACTORY_DFLT; + + data = kzalloc(sizeof(struct si570_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + if (id->driver_data) { + data->fout = SI598_FOUT_FACTORY_DFLT; + data->max_freq = SI598_MAX_FREQ; + } else { + data->fout = SI570_FOUT_FACTORY_DFLT; + data->max_freq = SI570_MAX_FREQ; + } + + if (pdata && pdata->factory_fout) + data->fout = pdata->factory_fout; + + if (client->dev.of_node && + (of_property_read_u32(client->dev.of_node, "factory-fout", + &tmp) < 0)) + dev_warn(&client->dev, + "DTS does not contain factory-fout, using default\n"); + else + data->fout = tmp; + + i2c_set_clientdata(client, data); + err = si570_get_defaults(client); + if (err < 0) + goto exit_free; + + mutex_init(&data->lock); + + /* Register sysfs hooks */ + data->attrs.attrs = si570_attr; + err = sysfs_create_group(&client->dev.kobj, &data->attrs); + if (err) + goto exit_free; + + /* Display a message indicating that we've successfully registered */ + dev_info(&client->dev, + "registered %s with default frequency %llu Hz\n", + id->name, data->fout); + + /* Read the requested initial fout from either platform data or the + * device tree + */ + initial_fout = 0; + if (pdata && pdata->initial_fout) { + initial_fout = pdata->initial_fout; + } + if (client->dev.of_node) { + of_property_read_u32(client->dev.of_node, "initial-fout", + (u32 *)&initial_fout); + if (pdata && pdata->initial_fout && + (pdata->initial_fout != initial_fout)) { + dev_warn(&client->dev, + "OF initial fout %lu overrides platform data fout %lu\n", + initial_fout, + pdata->initial_fout); + } + } + + if (initial_fout != 0) { + if (initial_fout < SI570_MIN_FREQ || + initial_fout > data->max_freq) { + dev_err(&client->dev, + "requested initial frequency %lu is out of range, using default\n", + initial_fout); + return 0; + } + + mutex_lock(&data->lock); + + if (div64_u64(abs(initial_fout - data->frequency) * + 10000LL, data->frequency) < 35) + err = si570_set_frequency_small(client, data, + initial_fout); + else + err = si570_set_frequency(client, data, + initial_fout); + mutex_unlock(&data->lock); + if (err) { + dev_warn(&client->dev, + "unable to set initial output frequency %lu: %d\n", + initial_fout, err); + return err; + } + + dev_info(&client->dev, + "set initial output frequency %lu Hz\n", + initial_fout); + } + + si570_client = client; + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int si570_remove(struct i2c_client *client) +{ + struct si570_data *data = i2c_get_clientdata(client); + + sysfs_remove_group(&client->dev.kobj, &data->attrs); + kfree(data); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id i2c_si570_of_match[] = { + { .compatible = "si570" }, + { }, +}; +MODULE_DEVICE_TABLE(of, i2c_si570_of_match); +#endif + +static struct i2c_driver si570_driver = { + .driver = { + .name = "si570", + .of_match_table = of_match_ptr(i2c_si570_of_match), + }, + .probe = si570_probe, + .remove = si570_remove, + .id_table = si570_id, +}; + +static int __init si570_init(void) +{ + return i2c_add_driver(&si570_driver); +} + +static void __exit si570_exit(void) +{ + i2c_del_driver(&si570_driver); +} + +MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); +MODULE_DESCRIPTION("Si570 driver"); +MODULE_LICENSE("GPL"); + +module_init(si570_init); +module_exit(si570_exit); Index: linux-3.12.24-rt38-xilinx/drivers/misc/xilinx_trafgen.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/misc/xilinx_trafgen.c 2014-07-20 22:06:36.741299367 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx AXI Traffic Generator + * + * Copyright (C) 2013 Xilinx, Inc. All rights reserved. + * + * Description: + * This driver is developed for AXI Traffic Generator IP, which is + * designed to generate AXI4 traffic which can be used to stress + * different modules/interconnect connected in the system. Different + * configurable options which are provided through sysfs entries + * allow the user to generate a wide variety of traffic based on + * their requirements. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* Hw specific definitions */ + +/* Internal RAM Offsets */ +#define XTG_PARAM_RAM_OFFSET 0x1000 /* Parameter RAM offset */ +#define XTG_COMMAND_RAM_OFFSET 0x8000 /* Command RAM offset */ +#define XTG_MASTER_RAM_INIT_OFFSET 0x10000 /* Master RAM initial offset(v1.0) */ +#define XTG_MASTER_RAM_OFFSET 0xc000 /* Master RAM offset */ + +/* Register Offsets */ +#define XTG_MCNTL_OFFSET 0x00 /* Master control */ +#define XTG_SCNTL_OFFSET 0x04 /* Slave control */ +#define XTG_ERR_STS_OFFSET 0x08 /* Error status */ +#define XTG_ERR_EN_OFFSET 0x0C /* Error enable */ +#define XTG_MSTERR_INTR_OFFSET 0x10 /* Master error interrupt enable */ +#define XTG_CFG_STS_OFFSET 0x14 /* Config status */ +#define XTG_STREAM_CNTL_OFFSET 0x30 /* Streaming Control */ +#define XTG_STREAM_TL_OFFSET 0x38 /* Streaming Transfer Length */ +#define XTG_STATIC_CNTL_OFFSET 0x60 /* Static Control */ +#define XTG_STATIC_LEN_OFFSET 0x64 /* Static Length */ + +/* Register Bitmasks/shifts */ + +/* Master logic enable */ +#define XTG_MCNTL_MSTEN_MASK 0x00100000 +/* Slave error interrupt enable */ +#define XTG_SCNTL_ERREN_MASK 0x00008000 +/* Master complete interrupt enable */ +#define XTG_ERR_EN_MSTIRQEN_MASK 0x80000000 +/* Master error interrupt enable */ +#define XTG_MSTERR_INTR_MINTREN_MASK 0x00008000 +/* Master complete done status */ +#define XTG_ERR_STS_MSTDONE_MASK 0x80000000 +/* Error mask for error status/enable registers */ +#define XTG_ERR_ALL_ERRS_MASK 0x001F0003 +/* Core Revision shift */ +#define XTG_MCNTL_REV_SHIFT 24 + +/* Axi Traffic Generator Command RAM Entry field mask/shifts */ + +/* Command RAM entry masks */ +#define XTG_LEN_MASK 0xFF /* Driven to a*_len line */ +#define XTG_LOCK_MASK 0x1 /* Driven to a*_lock line */ +#define XTG_BURST_MASK 0x3 /* Driven to a*_burst line */ +#define XTG_SIZE_MASK 0x7 /* Driven to a*_size line */ +#define XTG_ID_MASK 0x1F /* Driven to a*_id line */ +#define XTG_PROT_MASK 0x7 /* Driven to a*_prot line */ +#define XTG_LAST_ADDR_MASK 0x7 /* Last address */ +#define XTG_VALID_CMD_MASK 0x1 /* Valid Command */ +#define XTG_MSTRAM_INDEX_MASK 0x1FFF /* Master RAM Index */ +#define XTG_OTHER_DEPEND_MASK 0x1FF /* Other depend Command no */ +#define XTG_MY_DEPEND_MASK 0x1FF /* My depend command no */ +#define XTG_QOS_MASK 0xF /* Driven to a*_qos line */ +#define XTG_USER_MASK 0xFF /* Driven to a*_user line */ +#define XTG_CACHE_MASK 0xF /* Driven to a*_cache line */ +#define XTG_EXPECTED_RESP_MASK 0x7 /* Expected response */ + +/* Command RAM entry shift values */ +#define XTG_LEN_SHIFT 0 /* Driven to a*_len line */ +#define XTG_LOCK_SHIFT 8 /* Driven to a*_lock line */ +#define XTG_BURST_SHIFT 10 /* Driven to a*_burst line */ +#define XTG_SIZE_SHIFT 12 /* Driven to a*_size line */ +#define XTG_ID_SHIFT 15 /* Driven to a*_id line */ +#define XTG_PROT_SHIFT 21 /* Driven to a*_prot line */ +#define XTG_LAST_ADDR_SHIFT 28 /* Last address */ +#define XTG_VALID_CMD_SHIFT 31 /* Valid Command */ +#define XTG_MSTRAM_INDEX_SHIFT 0 /* Master RAM Index */ +#define XTG_OTHER_DEPEND_SHIFT 13 /* Other depend cmd num */ +#define XTG_MY_DEPEND_SHIFT 22 /* My depend cmd num */ +#define XTG_QOS_SHIFT 16 /* Driven to a*_qos line */ +#define XTG_USER_SHIFT 5 /* Driven to a*_user line */ +#define XTG_CACHE_SHIFT 4 /* Driven to a*_cache line */ +#define XTG_EXPECTED_RESP_SHIFT 0 /* Expected response */ + +/* Axi Traffic Generator Parameter RAM Entry field mask/shifts */ + +/* Parameter RAM Entry field shift values */ +#define XTG_PARAM_ADDRMODE_SHIFT 24 /* Address mode */ +#define XTG_PARAM_INTERVALMODE_SHIFT 26 /* Interval mode */ +#define XTG_PARAM_IDMODE_SHIFT 28 /* Id mode */ +#define XTG_PARAM_OP_SHIFT 29 /* Opcode */ + +/* PARAM RAM Opcode shift values */ +#define XTG_PARAM_COUNT_SHIFT 0 /* Repeat/Delay count */ +#define XTG_PARAM_DELAYRANGE_SHIFT 0 /* Delay range */ +#define XTG_PARAM_DELAY_SHIFT 8 /* FIXED RPT delay count */ +#define XTG_PARAM_ADDRRANGE_SHIFT 20 /* Address range */ + +/* Parameter RAM Entry field mask values */ +#define XTG_PARAM_ADDRMODE_MASK 0x3 /* Address mode */ +#define XTG_PARAM_INTERVALMODE_MASK 0x3 /* Interval mode */ +#define XTG_PARAM_IDMODE_MASK 0x1 /* Id mode */ +#define XTG_PARAM_OP_MASK 0x7 /* Opcode */ + +/* PARAM RAM Opcode mask values */ +#define XTG_PARAM_COUNT_MASK 0xFFFFFF/* Repeat/Delay count */ +#define XTG_PARAM_DELAYRANGE_MASK 0xFF /* Delay range */ +#define XTG_PARAM_DELAY_MASK 0xFFF /* FIXED RPT delay count */ +#define XTG_PARAM_ADDRRANGE_MASK 0xF /* Address range */ + +/* PARAM RAM Opcode values */ +#define XTG_PARAM_OP_NOP 0x0 /* NOP mode */ +#define XTG_PARAM_OP_RPT 0x1 /* Repeat mode */ +#define XTG_PARAM_OP_DELAY 0x2 /* Delay mode */ +#define XTG_PARAM_OP_FIXEDRPT 0x3 /* Fixed repeat delay */ + +/* Axi Traffic Generator Static Mode masks */ +#define XTG_STATIC_CNTL_TD_MASK 0x00000002 /* Transfer Done Mask */ +#define XTG_STATIC_CNTL_STEN_MASK 0x00000001 /* Static Enable Mask */ +#define XTG_STATIC_CNTL_RESET_MASK 0x00000000 /* Static Reset Mask */ + +/* Axi Traffic Generator Stream Mode mask/shifts */ +#define XTG_STREAM_CNTL_STEN_MASK 0x00000001 /* Stream Enable Mask */ +#define XTG_STREAM_TL_TCNT_MASK 0xFFFF0000 /* Transfer Count Mask */ +#define XTG_STREAM_TL_TLEN_MASK 0x0000FFFF /* Transfer Length Mask */ +#define XTG_STREAM_TL_TCNT_SHIFT 16 /* Transfer Count Shift */ + +/* Driver Specific Definitions */ + +#define MAX_NUM_ENTRIES 256 /* Number of command entries per region */ + +#define VALID_SIG 0xa5a5a5a5 /* Valid unique identifier */ + +/* Internal RAM Sizes */ +#define XTG_PRM_RAM_BLOCK_SIZE 0x400 /* PRAM Block size (1KB) */ +#define XTG_CMD_RAM_BLOCK_SIZE 0x1000 /* CRAM Block size (4KB) */ +#define XTG_PARAM_RAM_SIZE 0x800 /* Parameter RAM (2KB) */ +#define XTG_COMMAND_RAM_SIZE 0x2000 /* Command RAM (8KB) */ +#define XTG_MASTER_RAM_SIZE 0x2000 /* Master RAM (8KB) */ + +/* RAM Access Flags */ +#define XTG_READ_RAM 0x0 /* Read RAM flag */ +#define XTG_WRITE_RAM 0x1 /* Write RAM flag */ +#define XTG_WRITE_RAM_ZERO 0x2 /* Write Zero flag */ + +/* Bytes per entry */ +#define XTG_CRAM_BYTES_PER_ENTRY 16 /* CRAM bytes per entry */ +#define XTG_PRAM_BYTES_PER_ENTRY 4 /* PRAM bytes per entry */ + +/* Interrupt Definitions */ +#define XTG_MASTER_CMP_INTR 0x1 /* Master complete intr flag */ +#define XTG_MASTER_ERR_INTR 0x2 /* Master error intr flag */ +#define XTG_SLAVE_ERR_INTR 0x4 /* Slave error intr flag */ + +/* + * Version value of the trafgen core. + * For the initial IP release the version(v1.0) value is 0x47 + * From the v2.0 IP and onwards the value starts from 0x20. + * For eg: + * v2.1 -> 0x21 + * v2.2 -> 0x22 ... so on. + * + */ +#define XTG_INIT_VERSION 0x47 /* Trafgen initial version(v1.0) */ + +/* Macro */ +#define to_xtg_dev_info(n) ((struct xtg_dev_info *)dev_get_drvdata(n)) + +/** + * struct xtg_cram - Command RAM structure + * @addr: Address Driven to a*_addr line + * @valid_cmd: Valid Command + * @last_addr: Last address + * @prot: Driven to a*_prot line + * @id: Driven to a*_id line + * @size: Driven to a*_size line + * @burst: Driven to a*_burst line + * @lock: Driven to a*_lock line + * @length: Driven to a*_len line + * @my_dpnd: My Depend command number + * @other_dpnd: Other depend command number + * @mram_idx: Master RAM index + * @qos: Driven to a*_qos line + * @user: Driven to a*_user line + * @cache: Driven to a*_cache line + * @expected_resp: Expected response + * @index: Command Index + * @is_write_block: Write/Read block + * @is_valid_req: Unique signature + * + * FIXME: This structure is shared with the user application and + * hence need to be synchronized. We know these kind of structures + * should not be defined in the driver and this need to be fixed + * if found a proper placeholder (in uapi/). + */ +struct xtg_cram { + u32 addr; + u32 valid_cmd; + u32 last_addr; + u32 prot; + u32 id; + u32 size; + u32 burst; + u32 lock; + u32 length; + u32 my_dpnd; + u32 other_dpnd; + u32 mram_idx; + u32 qos; + u32 user; + u32 cache; + u32 expected_resp; + u16 index; + bool is_write_block; + u32 is_valid_req; +}; + +/** + * struct xtg_pram - Parameter RAM structure + * @op_cntl0: Control field 0 + * @op_cntl1: Control field 1 + * @op_cntl2: Control field 2 + * @addr_mode: Address mode + * @interval_mode: Interval mode + * @id_mode: Id mode + * @opcode: Opcode + * @index: Command Index + * @is_write_block: Write/Read block + * @is_valid_req: Unique signature + * + * FIXME: This structure is shared with the user application and + * hence need to be synchronized. We know these kind of structures + * should not be defined in the driver and this need to be fixed + * if found a proper placeholder (in uapi/). + */ +struct xtg_pram { + u32 op_cntl0; + u32 op_cntl1; + u32 op_cntl2; + u32 addr_mode; + u32 interval_mode; + u32 id_mode; + u32 opcode; + u16 index; + bool is_write_block; + u32 is_valid_req; +}; + +/** + * struct xtg_dev_info - Global Driver structure + * @regs: Iomapped base address + * @dev: Device structure + * @phys_base_addr: Physical base address + * @last_rd_valid_idx: Last Read Valid Command Index + * @last_wr_valid_idx: Last Write Valid Command Index + * @id: Device instance id + * @xtg_mram_offset: MasterRam offset + */ +struct xtg_dev_info { + void __iomem *regs; + struct device *dev; + u32 phys_base_addr; + s16 last_rd_valid_idx; + s16 last_wr_valid_idx; + u32 id; + u32 xtg_mram_offset; +}; + +/** + * enum xtg_sysfs_ioctl - Ioctl opcodes + * @XTG_GET_MASTER_CMP_STS: get master complete status + * @XTG_GET_SLV_CTRL_REG: get slave control reg status + * @XTG_GET_ERR_STS: get error status + * @XTG_GET_CFG_STS: get config status + * @XTG_GET_LAST_VALID_INDEX: get last valid index + * @XTG_GET_DEVICE_ID: get device id + * @XTG_GET_RESOURCE: get resource + * @XTG_GET_STATIC_ENABLE: get staic mode traffic genration state + * @XTG_GET_STATIC_BURSTLEN: get static mode burst length + * @XTG_GET_STATIC_TRANSFERDONE: get static transfer done + * @XTG_GET_STREAM_ENABLE : get strean mode traffic genration state + * @XTG_GET_STREAM_TRANSFERLEN: get streaming mode transfer length + * @XTG_GET_STREAM_TRANSFERCNT: get streaming mode transfer count + * @XTG_START_MASTER_LOGIC: start master logic + * @XTG_SET_SLV_CTRL_REG: set slave control + * @XTG_CLEAR_ERRORS: clear errors + * @XTG_ENABLE_ERRORS: enable errors + * @XTG_ENABLE_INTRS: enable interrupts + * @XTG_CLEAR_MRAM: clear master ram + * @XTG_CLEAR_CRAM: clear command ram + * @XTG_CLEAR_PRAM: clear parameter ram + * @XTG_SET_STATIC_ENABLE: enable static mode traffic genration + * @XTG_SET_STATIC_DISABLE: disable static mode traffic genration + * @XTG_SET_STATIC_BURSTLEN: set static mode burst length + * @XTG_SET_STATIC_TRANSFERDONE: set static transfer done + * @XTG_SET_STREAM_ENABLE: enable streaming mode traffic genration + * @XTG_SET_STREAM_DISABLE: disable streaming mode traffic genration + * @XTG_SET_STREAM_TRANSFERLEN: set streaming mode transfer length + * @XTG_SET_STREAM_TRANSFERCNT: set streaming mode transfer count + */ +enum xtg_sysfs_ioctl_opcode { + XTG_GET_MASTER_CMP_STS, + XTG_GET_SLV_CTRL_REG, + XTG_GET_ERR_STS, + XTG_GET_CFG_STS, + XTG_GET_LAST_VALID_INDEX, + XTG_GET_DEVICE_ID, + XTG_GET_RESOURCE, + XTG_GET_STATIC_ENABLE, + XTG_GET_STATIC_BURSTLEN, + XTG_GET_STATIC_TRANSFERDONE, + XTG_GET_STREAM_ENABLE, + XTG_GET_STREAM_TRANSFERLEN, + XTG_GET_STREAM_TRANSFERCNT, + XTG_START_MASTER_LOGIC, + XTG_SET_SLV_CTRL_REG, + XTG_CLEAR_ERRORS, + XTG_ENABLE_ERRORS, + XTG_ENABLE_INTRS, + XTG_CLEAR_MRAM, + XTG_CLEAR_CRAM, + XTG_CLEAR_PRAM, + XTG_SET_STATIC_ENABLE, + XTG_SET_STATIC_DISABLE, + XTG_SET_STATIC_BURSTLEN, + XTG_SET_STATIC_TRANSFERDONE, + XTG_SET_STREAM_ENABLE, + XTG_SET_STREAM_DISABLE, + XTG_SET_STREAM_TRANSFERLEN, + XTG_SET_STREAM_TRANSFERCNT +}; + +/** + * xtg_access_rams - Write/Read Master/Command/Parameter RAM + * @tg: Pointer to xtg_dev_info structure + * @where: Offset from base + * @count: Number of bytes to write/read + * @flags: Read/Write/Write Zero + * @data: Data pointer + */ +static void xtg_access_rams(struct xtg_dev_info *tg, int where, + int count, int flags, u32 *data) +{ + u32 index; + + for (index = 0; count > 0; index++, count -= 4) { + if (flags) { + if (flags & XTG_WRITE_RAM_ZERO) + writel(0x0, tg->regs + where + index * 4); + else + writel(data[index], + tg->regs + where + index * 4); + } else { + data[index] = readl(tg->regs + where + index * 4); + } + } +} + +/** + * xtg_prepare_cmd_words - Prepares all four Command RAM words + * @tg: Pointer to xtg_dev_info structure + * @cmdp: Pointer to xtg_cram structure + * @cmd_words: Pointer to Command Words that needs to be prepared + */ +static void xtg_prepare_cmd_words(struct xtg_dev_info *tg, + const struct xtg_cram *cmdp, u32 *cmd_words) +{ + /* Command Word 0 */ + cmd_words[0] = cmdp->addr; + + /* Command Word 1 */ + cmd_words[1] = 0; + cmd_words[1] |= (cmdp->length & XTG_LEN_MASK) << XTG_LEN_SHIFT; + cmd_words[1] |= (cmdp->lock & XTG_LOCK_MASK) << XTG_LOCK_SHIFT; + cmd_words[1] |= (cmdp->burst & XTG_BURST_MASK) << XTG_BURST_SHIFT; + cmd_words[1] |= (cmdp->size & XTG_SIZE_MASK) << XTG_SIZE_SHIFT; + cmd_words[1] |= (cmdp->id & XTG_ID_MASK) << XTG_ID_SHIFT; + cmd_words[1] |= (cmdp->prot & XTG_PROT_MASK) << XTG_PROT_SHIFT; + cmd_words[1] |= (cmdp->last_addr & XTG_LAST_ADDR_MASK) << + XTG_LAST_ADDR_SHIFT; + cmd_words[1] |= (cmdp->valid_cmd & XTG_VALID_CMD_MASK) << + XTG_VALID_CMD_SHIFT; + + /* Command Word 2 */ + cmd_words[2] = 0; + cmd_words[2] |= (cmdp->mram_idx & XTG_MSTRAM_INDEX_MASK) << + XTG_MSTRAM_INDEX_SHIFT; + cmd_words[2] |= (cmdp->other_dpnd & XTG_OTHER_DEPEND_MASK) << + XTG_OTHER_DEPEND_SHIFT; + cmd_words[2] |= (cmdp->my_dpnd & XTG_MY_DEPEND_MASK) << + XTG_MY_DEPEND_SHIFT; + + /* Command Word 3 */ + cmd_words[3] = 0; + cmd_words[3] |= (cmdp->qos & XTG_QOS_MASK) << XTG_QOS_SHIFT; + cmd_words[3] |= (cmdp->user & XTG_USER_MASK) << XTG_USER_SHIFT; + cmd_words[3] |= (cmdp->cache & XTG_CACHE_MASK) << XTG_CACHE_SHIFT; + cmd_words[3] |= (cmdp->expected_resp & XTG_EXPECTED_RESP_MASK) << + XTG_EXPECTED_RESP_SHIFT; +} + +/** + * xtg_prepare_param_words - Prepares Parameter RAM word + * @tg: Pointer to xtg_dev_info structure + * @cmdp: Pointer to xtg_pram structure + * @param_word: Pointer to Param Word that needs to be prepared + */ +static void xtg_prepare_param_word(struct xtg_dev_info *tg, + const struct xtg_pram *cmdp, u32 *param_word) +{ + *param_word = 0; + *param_word |= (cmdp->opcode & XTG_PARAM_OP_MASK) << XTG_PARAM_OP_SHIFT; + *param_word |= (cmdp->addr_mode & XTG_PARAM_ADDRMODE_MASK) << + XTG_PARAM_ADDRMODE_SHIFT; + *param_word |= (cmdp->id_mode & XTG_PARAM_IDMODE_MASK) << + XTG_PARAM_IDMODE_SHIFT; + *param_word |= (cmdp->interval_mode & XTG_PARAM_INTERVALMODE_MASK) << + XTG_PARAM_INTERVALMODE_SHIFT; + + switch (cmdp->opcode) { + case XTG_PARAM_OP_RPT: + case XTG_PARAM_OP_DELAY: + *param_word |= (cmdp->op_cntl0 & XTG_PARAM_COUNT_MASK) << + XTG_PARAM_COUNT_SHIFT; + break; + + case XTG_PARAM_OP_FIXEDRPT: + *param_word |= (cmdp->op_cntl0 & XTG_PARAM_ADDRRANGE_MASK) << + XTG_PARAM_ADDRRANGE_SHIFT; + *param_word |= (cmdp->op_cntl1 & XTG_PARAM_DELAY_MASK) << + XTG_PARAM_DELAY_SHIFT; + *param_word |= (cmdp->op_cntl2 & XTG_PARAM_DELAYRANGE_MASK) << + XTG_PARAM_DELAYRANGE_SHIFT; + break; + + case XTG_PARAM_OP_NOP: + *param_word = 0; + break; + } +} + +/** + * xtg_sysfs_ioctl - Implements sysfs operations + * @dev: Device structure + * @buf: Value to write + * @opcode: Ioctl opcode + */ +static ssize_t xtg_sysfs_ioctl(struct device *dev, const char *buf, + enum xtg_sysfs_ioctl_opcode opcode) +{ + struct xtg_dev_info *tg = to_xtg_dev_info(dev); + unsigned long wrval; + ssize_t status, rdval = 0; + + if (opcode > XTG_GET_STREAM_TRANSFERCNT) { + status = kstrtoul(buf, 16, &wrval); + if (status < 0) + return status; + } + + switch (opcode) { + case XTG_GET_MASTER_CMP_STS: + rdval = (readl(tg->regs + XTG_MCNTL_OFFSET) & + XTG_MCNTL_MSTEN_MASK) ? 1 : 0; + break; + + case XTG_GET_SLV_CTRL_REG: + rdval = readl(tg->regs + XTG_SCNTL_OFFSET); + break; + + case XTG_GET_ERR_STS: + rdval = readl(tg->regs + XTG_ERR_STS_OFFSET) & + XTG_ERR_ALL_ERRS_MASK; + break; + + case XTG_GET_CFG_STS: + rdval = readl(tg->regs + XTG_CFG_STS_OFFSET); + break; + + case XTG_GET_LAST_VALID_INDEX: + rdval = (tg->last_wr_valid_idx << 16) | + tg->last_rd_valid_idx; + break; + + case XTG_GET_DEVICE_ID: + rdval = tg->id; + break; + + case XTG_GET_RESOURCE: + rdval = (unsigned long)tg->regs; + break; + + case XTG_GET_STATIC_ENABLE: + rdval = readl(tg->regs + XTG_STATIC_CNTL_OFFSET); + break; + + case XTG_GET_STATIC_BURSTLEN: + rdval = readl(tg->regs + XTG_STATIC_LEN_OFFSET); + break; + + case XTG_GET_STATIC_TRANSFERDONE: + rdval = (readl(tg->regs + XTG_STATIC_CNTL_OFFSET) & + XTG_STATIC_CNTL_TD_MASK); + break; + + case XTG_GET_STREAM_ENABLE: + rdval = readl(tg->regs + XTG_STREAM_CNTL_OFFSET); + break; + + case XTG_GET_STREAM_TRANSFERLEN: + rdval = (readl(tg->regs + XTG_STREAM_TL_OFFSET) & + XTG_STREAM_TL_TLEN_MASK); + break; + + case XTG_GET_STREAM_TRANSFERCNT: + rdval = ((readl(tg->regs + XTG_STREAM_TL_OFFSET) & + XTG_STREAM_TL_TCNT_MASK) >> + XTG_STREAM_TL_TCNT_SHIFT); + break; + + case XTG_START_MASTER_LOGIC: + if (wrval) + writel(readl(tg->regs + XTG_MCNTL_OFFSET) | + XTG_MCNTL_MSTEN_MASK, + tg->regs + XTG_MCNTL_OFFSET); + break; + + case XTG_SET_SLV_CTRL_REG: + writel(wrval, tg->regs + XTG_SCNTL_OFFSET); + break; + + case XTG_ENABLE_ERRORS: + wrval &= XTG_ERR_ALL_ERRS_MASK; + writel(readl(tg->regs + XTG_ERR_EN_OFFSET) | wrval, + tg->regs + XTG_ERR_EN_OFFSET); + break; + + case XTG_CLEAR_ERRORS: + wrval &= XTG_ERR_ALL_ERRS_MASK; + writel(readl(tg->regs + XTG_ERR_STS_OFFSET) | wrval, + tg->regs + XTG_ERR_STS_OFFSET); + break; + + case XTG_ENABLE_INTRS: + if (wrval & XTG_MASTER_CMP_INTR) { + pr_info("Enabling Master Complete Interrupt\n"); + writel(readl(tg->regs + XTG_ERR_EN_OFFSET) | + XTG_ERR_EN_MSTIRQEN_MASK, + tg->regs + XTG_ERR_EN_OFFSET); + } + if (wrval & XTG_MASTER_ERR_INTR) { + pr_info("Enabling Interrupt on Master Errors\n"); + writel(readl(tg->regs + XTG_MSTERR_INTR_OFFSET) | + XTG_MSTERR_INTR_MINTREN_MASK, + tg->regs + XTG_MSTERR_INTR_OFFSET); + } + if (wrval & XTG_SLAVE_ERR_INTR) { + pr_info("Enabling Interrupt on Slave Errors\n"); + writel(readl(tg->regs + XTG_SCNTL_OFFSET) | + XTG_SCNTL_ERREN_MASK, + tg->regs + XTG_SCNTL_OFFSET); + } + break; + + case XTG_CLEAR_MRAM: + if (wrval) + xtg_access_rams(tg, tg->xtg_mram_offset, + XTG_MASTER_RAM_SIZE, XTG_WRITE_RAM | + XTG_WRITE_RAM_ZERO, NULL); + break; + + case XTG_CLEAR_CRAM: + if (wrval) + xtg_access_rams(tg, XTG_COMMAND_RAM_OFFSET, + XTG_COMMAND_RAM_SIZE, XTG_WRITE_RAM | + XTG_WRITE_RAM_ZERO, NULL); + break; + + case XTG_CLEAR_PRAM: + if (wrval) + xtg_access_rams(tg, XTG_PARAM_RAM_OFFSET, + XTG_PARAM_RAM_SIZE, XTG_WRITE_RAM | + XTG_WRITE_RAM_ZERO, NULL); + break; + + case XTG_SET_STATIC_ENABLE: + if (wrval) { + wrval &= XTG_STATIC_CNTL_STEN_MASK; + writel(readl(tg->regs + XTG_STATIC_CNTL_OFFSET) | wrval, + tg->regs + XTG_STATIC_CNTL_OFFSET); + } else { + writel(readl(tg->regs + XTG_STATIC_CNTL_OFFSET) & + ~XTG_STATIC_CNTL_STEN_MASK, + tg->regs + XTG_STATIC_CNTL_OFFSET); + } + break; + + case XTG_SET_STATIC_BURSTLEN: + writel(wrval, tg->regs + XTG_STATIC_LEN_OFFSET); + break; + + case XTG_SET_STATIC_TRANSFERDONE: + wrval |= XTG_STATIC_CNTL_TD_MASK; + writel(readl(tg->regs + XTG_STATIC_CNTL_OFFSET) | wrval, + tg->regs + XTG_STATIC_CNTL_OFFSET); + break; + + case XTG_SET_STREAM_ENABLE: + if (wrval) { + wrval &= XTG_STREAM_CNTL_STEN_MASK; + writel(readl(tg->regs + XTG_STREAM_CNTL_OFFSET) | wrval, + tg->regs + XTG_STREAM_CNTL_OFFSET); + } else { + writel(readl(tg->regs + XTG_STREAM_CNTL_OFFSET) & + ~XTG_STREAM_CNTL_STEN_MASK, + tg->regs + XTG_STREAM_CNTL_OFFSET); + } + break; + + case XTG_SET_STREAM_TRANSFERLEN: + wrval &= XTG_STREAM_TL_TLEN_MASK; + writel(readl(tg->regs + XTG_STREAM_TL_OFFSET) | wrval, + tg->regs + XTG_STREAM_TL_OFFSET); + break; + + case XTG_SET_STREAM_TRANSFERCNT: + wrval = ((wrval << XTG_STREAM_TL_TCNT_SHIFT) & + XTG_STREAM_TL_TCNT_MASK); + writel(readl(tg->regs + XTG_STREAM_TL_OFFSET) | wrval, + tg->regs + XTG_STREAM_TL_OFFSET); + break; + + default: + break; + } + + return rdval; +} + +/* Sysfs functions */ + +static ssize_t xtg_show_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_DEVICE_ID); + + return sprintf(buf, "%d\n", rdval); +} +static DEVICE_ATTR(id, S_IRUGO, xtg_show_id, NULL); + +static ssize_t xtg_show_resource(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_RESOURCE); + + return sprintf(buf, "0x%08x\n", rdval); +} +static DEVICE_ATTR(resource, S_IRUGO, xtg_show_resource, NULL); + +static ssize_t xtg_show_master_cmp_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_MASTER_CMP_STS); + + return sprintf(buf, "%d\n", rdval); +} + +static ssize_t xtg_start_master_logic(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_START_MASTER_LOGIC); + + return size; +} +static DEVICE_ATTR(start_master, 0644, xtg_show_master_cmp_status, + xtg_start_master_logic); + +static ssize_t xtg_show_slv_ctrl_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_SLV_CTRL_REG); + + return sprintf(buf, "0x%08x\n", rdval); +} + +static ssize_t xtg_config_slv_ctrl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_SET_SLV_CTRL_REG); + + return size; +} +static DEVICE_ATTR(config_slave, 0644, xtg_show_slv_ctrl_status, + xtg_config_slv_ctrl); + +static ssize_t xtg_show_errs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_ERR_STS); + + return sprintf(buf, "0x%08x\n", rdval); +} + +static ssize_t xtg_clear_errs(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_CLEAR_ERRORS); + + return size; +} +static DEVICE_ATTR(err_sts, 0644, xtg_show_errs, xtg_clear_errs); + +static ssize_t xtg_enable_errs(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_ENABLE_ERRORS); + + return size; +} +static DEVICE_ATTR(err_en, 0644, NULL, xtg_enable_errs); + +static ssize_t xtg_enable_interrupts(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_ENABLE_INTRS); + + return size; +} +static DEVICE_ATTR(intr_en, 0644, NULL, xtg_enable_interrupts); + +static ssize_t xtg_show_last_valid_index(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_LAST_VALID_INDEX); + + return sprintf(buf, "0x%08x\n", rdval); +} +static DEVICE_ATTR(last_valid_index, S_IRUGO, xtg_show_last_valid_index, NULL); + +static ssize_t xtg_show_config_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_CFG_STS); + + return sprintf(buf, "0x%08x\n", rdval); +} +static DEVICE_ATTR(config_sts, S_IRUGO, xtg_show_config_status, NULL); + +static ssize_t xtg_clear_mram(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_CLEAR_MRAM); + + return size; +} +static DEVICE_ATTR(mram_clear, 0644, NULL, xtg_clear_mram); + +static ssize_t xtg_clear_cram(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_CLEAR_CRAM); + + return size; +} +static DEVICE_ATTR(cram_clear, 0644, NULL, xtg_clear_cram); + +static ssize_t xtg_clear_pram(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_CLEAR_CRAM); + + return size; +} +static DEVICE_ATTR(pram_clear, 0644, NULL, xtg_clear_pram); + +static ssize_t xtg_show_static_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_STATIC_ENABLE); + + return sprintf(buf, "0x%08x\n", rdval); +} + +static ssize_t xtg_static_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_SET_STATIC_ENABLE); + + return size; +} +static DEVICE_ATTR(static_en, 0644, xtg_show_static_enable, xtg_static_enable); + +static ssize_t xtg_get_static_burstlen(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_STATIC_BURSTLEN); + + return sprintf(buf, "%d\n", rdval); +} + +static ssize_t xtg_static_burstlen(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_SET_STATIC_BURSTLEN); + + return size; +} +static DEVICE_ATTR(static_burstlen, 0644, xtg_get_static_burstlen, + xtg_static_burstlen); + +static ssize_t xtg_get_static_transferdone(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_STATIC_TRANSFERDONE); + + return sprintf(buf, "%d\n", rdval); +} + +static ssize_t xtg_static_transferdone(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_SET_STATIC_TRANSFERDONE); + + return size; +} +static DEVICE_ATTR(static_transferdone, 0644, xtg_get_static_transferdone, + xtg_static_transferdone); + +static ssize_t xtg_reset_static_transferdone(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_STATIC_TRANSFERDONE); + if (rdval == XTG_STATIC_CNTL_RESET_MASK) + rdval = 1; + else + rdval = 0; + return sprintf(buf, "%d\n", rdval); +} +static DEVICE_ATTR(reset_static_transferdone, 0644, + xtg_reset_static_transferdone, NULL); + +static ssize_t xtg_show_stream_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_STREAM_ENABLE); + + return sprintf(buf, "0x%08x\n", rdval); +} + +static ssize_t xtg_stream_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_SET_STREAM_ENABLE); + + return size; +} +static DEVICE_ATTR(stream_en, 0644, xtg_show_stream_enable, xtg_stream_enable); + +static ssize_t xtg_get_stream_transferlen(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_STREAM_TRANSFERLEN); + + return sprintf(buf, "%d\n", rdval); +} + +static ssize_t xtg_set_stream_transferlen(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_SET_STREAM_TRANSFERLEN); + + return size; +} +static DEVICE_ATTR(stream_transferlen, 0644, xtg_get_stream_transferlen, + xtg_set_stream_transferlen); + +static ssize_t xtg_get_stream_transfercnt(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t rdval = xtg_sysfs_ioctl(dev, buf, XTG_GET_STREAM_TRANSFERCNT); + + return sprintf(buf, "%d\n", rdval); +} + +static ssize_t xtg_set_stream_transfercnt(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + xtg_sysfs_ioctl(dev, buf, XTG_SET_STREAM_TRANSFERCNT); + + return size; +} +static DEVICE_ATTR(stream_transfercnt, 0644, xtg_get_stream_transfercnt, + xtg_set_stream_transfercnt); + +static ssize_t xtg_pram_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + pr_info("No read access to Parameter RAM\n"); + + return 0; +} + +static ssize_t xtg_pram_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct xtg_dev_info *tg = + to_xtg_dev_info(container_of(kobj, struct device, kobj)); + u32 *data = (u32 *)buf; + + if (off >= XTG_PARAM_RAM_SIZE) { + pr_err("Requested Write len exceeds 2K PRAM size\n"); + return -ENOMEM; + } + + if (count >= XTG_PARAM_RAM_SIZE) + count = XTG_PARAM_RAM_SIZE; + + /* Program each command */ + if (count == sizeof(struct xtg_pram)) { + struct xtg_pram *cmdp = (struct xtg_pram *)buf; + u32 param_word; + + if (!cmdp) + return -EINVAL; + + if (cmdp->is_valid_req == VALID_SIG) { + /* Prepare parameter word */ + xtg_prepare_param_word(tg, cmdp, ¶m_word); + + count = XTG_PRAM_BYTES_PER_ENTRY; + data = ¶m_word; + + /* Maximum command entries are 256 */ + if (cmdp->index > MAX_NUM_ENTRIES) + return -EINVAL; + + /* Calculate the block index */ + if (cmdp->is_write_block) + off = XTG_PRM_RAM_BLOCK_SIZE + + cmdp->index * count; + else + off = cmdp->index * count; + } + } + + off += XTG_PARAM_RAM_OFFSET; + xtg_access_rams(tg, off, count, XTG_WRITE_RAM, data); + + return count; +} + +static ssize_t xtg_pram_mmap(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + struct xtg_dev_info *tg = + to_xtg_dev_info(container_of(kobj, struct device, kobj)); + int ret; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_IO; + + ret = remap_pfn_range(vma, vma->vm_start, (tg->phys_base_addr + + XTG_PARAM_RAM_OFFSET) >> PAGE_SHIFT, + XTG_PARAM_RAM_SIZE, vma->vm_page_prot); + return ret; +} + +static struct bin_attribute xtg_pram_attr = { + .attr = { + .name = "parameter_ram", + .mode = S_IRUGO | S_IWUSR, + }, + .size = XTG_PARAM_RAM_SIZE, + .read = xtg_pram_read, + .write = xtg_pram_write, + .mmap = xtg_pram_mmap, +}; + +static ssize_t xtg_cram_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct xtg_dev_info *tg = + to_xtg_dev_info(container_of(kobj, struct device, kobj)); + + off += XTG_COMMAND_RAM_OFFSET; + xtg_access_rams(tg, off, count, XTG_READ_RAM, (u32 *)buf); + + return count; +} + +static ssize_t xtg_cram_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct xtg_dev_info *tg = + to_xtg_dev_info(container_of(kobj, struct device, kobj)); + u32 *data = (u32 *)buf; + + if (off >= XTG_COMMAND_RAM_SIZE) { + pr_err("Requested Write len exceeds 8K CRAM size\n"); + return -ENOMEM; + } + + /* Program each command */ + if (count == sizeof(struct xtg_cram)) { + struct xtg_cram *cmdp = (struct xtg_cram *)buf; + u32 cmd_words[4]; + + if (!cmdp) + return -EINVAL; + + if (cmdp->is_valid_req == VALID_SIG) { + /* Prepare command words */ + xtg_prepare_cmd_words(tg, cmdp, cmd_words); + count = XTG_CRAM_BYTES_PER_ENTRY; + data = cmd_words; + + /* Maximum command entries are 256 */ + if (cmdp->index > MAX_NUM_ENTRIES) + return -EINVAL; + + /* Calculate the block index */ + if (cmdp->is_write_block) + off = XTG_CMD_RAM_BLOCK_SIZE + + cmdp->index * count; + else + off = cmdp->index * count; + + /* Store the valid command index */ + if (cmdp->valid_cmd) { + if (cmdp->is_write_block) + tg->last_wr_valid_idx = + cmdp->index; + else + tg->last_rd_valid_idx = + cmdp->index; + } + } + } + + off += XTG_COMMAND_RAM_OFFSET; + xtg_access_rams(tg, off, count, XTG_WRITE_RAM, data); + + return count; +} + +static ssize_t xtg_cram_mmap(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + struct xtg_dev_info *tg = + to_xtg_dev_info(container_of(kobj, struct device, kobj)); + int ret; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_IO; + + ret = remap_pfn_range(vma, vma->vm_start, (tg->phys_base_addr + + XTG_COMMAND_RAM_OFFSET) >> PAGE_SHIFT, + XTG_COMMAND_RAM_SIZE, vma->vm_page_prot); + return ret; +} + +static struct bin_attribute xtg_cram_attr = { + .attr = { + .name = "command_ram", + .mode = S_IRUGO | S_IWUSR, + }, + .size = XTG_COMMAND_RAM_SIZE, + .read = xtg_cram_read, + .write = xtg_cram_write, + .mmap = xtg_cram_mmap, +}; + +static ssize_t xtg_mram_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct xtg_dev_info *tg = + to_xtg_dev_info(container_of(kobj, struct device, kobj)); + + off += tg->xtg_mram_offset; + xtg_access_rams(tg, off, count, XTG_READ_RAM, (u32 *)buf); + + return count; +} + +static ssize_t xtg_mram_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct xtg_dev_info *tg = + to_xtg_dev_info(container_of(kobj, struct device, kobj)); + + if (off >= XTG_MASTER_RAM_SIZE) { + pr_err("Requested Write len exceeds 8K MRAM size\n"); + return -ENOMEM; + } + + off += tg->xtg_mram_offset; + xtg_access_rams(tg, off, count, XTG_WRITE_RAM, (u32 *)buf); + + return count; +} + +static ssize_t xtg_mram_mmap(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + struct xtg_dev_info *tg = + to_xtg_dev_info(container_of(kobj, struct device, kobj)); + int ret; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_IO; + + ret = remap_pfn_range(vma, vma->vm_start, (tg->phys_base_addr + + tg->xtg_mram_offset) >> PAGE_SHIFT, + XTG_MASTER_RAM_SIZE, + vma->vm_page_prot); + return ret; +} + +static struct bin_attribute xtg_mram_attr = { + .attr = { + .name = "master_ram", + .mode = S_IRUGO | S_IWUSR, + }, + .size = XTG_MASTER_RAM_SIZE, + .read = xtg_mram_read, + .write = xtg_mram_write, + .mmap = xtg_mram_mmap, +}; + +static const struct attribute *xtg_attrs[] = { + &dev_attr_id.attr, + &dev_attr_resource.attr, + &dev_attr_start_master.attr, + &dev_attr_config_slave.attr, + &dev_attr_err_en.attr, + &dev_attr_err_sts.attr, + &dev_attr_intr_en.attr, + &dev_attr_last_valid_index.attr, + &dev_attr_config_sts.attr, + &dev_attr_mram_clear.attr, + &dev_attr_cram_clear.attr, + &dev_attr_pram_clear.attr, + &dev_attr_static_en.attr, + &dev_attr_static_burstlen.attr, + &dev_attr_static_transferdone.attr, + &dev_attr_stream_transfercnt.attr, + &dev_attr_stream_transferlen.attr, + &dev_attr_stream_en.attr, + &dev_attr_reset_static_transferdone.attr, + NULL, +}; + +/** + * xtg_remove_sysfs_dev_files - Remove sysfs entries for device + * @tg: Pointer to xtg_dev_info structure + */ +static void xtg_remove_sysfs_dev_files(struct xtg_dev_info *tg) +{ + struct device *dev = tg->dev; + + sysfs_remove_files(&dev->kobj, xtg_attrs); + sysfs_remove_bin_file(&dev->kobj, &xtg_mram_attr); + sysfs_remove_bin_file(&dev->kobj, &xtg_cram_attr); + sysfs_remove_bin_file(&dev->kobj, &xtg_pram_attr); +} + +/** + * xtg_create_sysfs_dev_files - Create sysfs entries for device + * @tg: Pointer to xtg_dev_info structure + * + * Returns '0' on success and failure value on error + */ +static int xtg_create_sysfs_dev_files(struct xtg_dev_info *tg) +{ + struct device *dev = tg->dev; + int err; + + err = sysfs_create_files(&dev->kobj, xtg_attrs); + if (err < 0) + goto out; + + err = sysfs_create_bin_file(&dev->kobj, &xtg_mram_attr); + if (err < 0) + goto out; + + err = sysfs_create_bin_file(&dev->kobj, &xtg_cram_attr); + if (err < 0) + goto out; + + err = sysfs_create_bin_file(&dev->kobj, &xtg_pram_attr); + if (err < 0) + goto out; + + return 0; + +out: + xtg_remove_sysfs_dev_files(tg); + + return err; +} + +/** + * xtg_cmp_intr_handler - Master Complete Interrupt handler + * @irq: IRQ number + * @data: Pointer to the xtg_dev_info structure + * + * Returns IRQ_HANDLED always + */ +static irqreturn_t xtg_cmp_intr_handler(int irq, void *data) +{ + struct xtg_dev_info *tg = (struct xtg_dev_info *)data; + + writel(readl(tg->regs + XTG_ERR_STS_OFFSET) | + XTG_ERR_STS_MSTDONE_MASK, + tg->regs + XTG_ERR_STS_OFFSET); + + return IRQ_HANDLED; +} + +/** + * xtg_err_intr_handler - Master/Slave Error Interrupt handler + * @irq: IRQ number + * @data: Pointer to the xtg_dev_info structure + * + * Returns IRQ_HANDLED always + */ +static irqreturn_t xtg_err_intr_handler(int irq, void *data) +{ + struct xtg_dev_info *tg = (struct xtg_dev_info *)data; + u32 value; + + value = readl(tg->regs + XTG_ERR_STS_OFFSET) & + XTG_ERR_ALL_ERRS_MASK; + + if (value) { + dev_err(tg->dev, "Found errors 0x%08x\n", value); + writel(readl(tg->regs + XTG_ERR_STS_OFFSET) | value, + tg->regs + XTG_ERR_STS_OFFSET); + } + + return IRQ_HANDLED; +} + +/** + * xtg_probe - Driver probe function + * @pdev: Pointer to the platform_device structure + * + * Returns '0' on success and failure value on error + */ +static int xtg_probe(struct platform_device *pdev) +{ + struct xtg_dev_info *tg; + struct device_node *node; + struct resource *res; + int err, irq, var; + + tg = devm_kzalloc(&pdev->dev, sizeof(*tg), GFP_KERNEL); + if (!tg) + return -ENOMEM; + + tg->dev = &(pdev->dev); + + node = pdev->dev.of_node; + + /* Map the registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tg->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tg->regs)) + return PTR_ERR(tg->regs); + + + /* Save physical base address */ + tg->phys_base_addr = res->start; + + /* Get the device instance id */ + err = of_property_read_u32(node, "xlnx,device-id", &tg->id); + if (err < 0) { + dev_err(&pdev->dev, "unable to read property"); + return err; + } + + /* Map the error interrupt, if it exists in the device tree. */ + irq = platform_get_irq_byname(pdev, "err-out"); + if (irq < 0) { + dev_dbg(&pdev->dev, "unable to get err irq"); + } else { + err = devm_request_irq(&pdev->dev, irq, xtg_err_intr_handler, + 0, dev_name(&pdev->dev), tg); + if (err < 0) { + dev_err(&pdev->dev, "unable to request irq %d", irq); + return err; + } + } + + /* Map the completion interrupt, if it exists in the device tree. */ + irq = platform_get_irq_byname(pdev, "irq-out"); + if (irq < 0) { + dev_dbg(&pdev->dev, "unable to get cmp irq"); + } else { + err = devm_request_irq(&pdev->dev, irq, xtg_cmp_intr_handler, + 0, dev_name(&pdev->dev), tg); + if (err < 0) { + dev_err(&pdev->dev, "unable to request irq %d", irq); + return err; + } + } + + /* + * Create sysfs file entries for the device + * + * NOTE: We can create sysfs entries by adding attribute groups + * and then populate into device_driver structure. We see issue + * here, as this process doesn't allow to add sysfs entries with + * BIN attributes (SYSFS_KOBJ_BIN_ATTR). Also, this would create + * sysfs entries under driver/ which will be a bit confusing for + * users as bin files and normal files will be populated at diff + * erent places. So to avoid this, we created this function to + * add sysfs entries at a common place. + * + * this issue being addressed in mainline by + * 'sysfs: add support for binary attributes in groups'. + * It removes this overhead of creating/removing sysfs file entries. + */ + err = xtg_create_sysfs_dev_files(tg); + if (err < 0) { + dev_err(tg->dev, "unable to create sysfs entries\n"); + return err; + } + + /* + * Initialize the write and read valid index values. + * Possible range of values for these variables is <0 255>. + */ + tg->last_wr_valid_idx = -1; + tg->last_rd_valid_idx = -1; + + dev_set_drvdata(&pdev->dev, tg); + + /* Update the Proper MasterRam offset */ + tg->xtg_mram_offset = XTG_MASTER_RAM_OFFSET; + var = readl(tg->regs + XTG_MCNTL_OFFSET) >> XTG_MCNTL_REV_SHIFT; + if (var == XTG_INIT_VERSION) + tg->xtg_mram_offset = XTG_MASTER_RAM_INIT_OFFSET; + + dev_info(&pdev->dev, "Probing xilinx traffic generator success\n"); + + return 0; +} + +/** + * xtg_remove - Driver remove function + * @pdev: Pointer to the platform_device structure + * + * Always returns '0' + */ +static int xtg_remove(struct platform_device *pdev) +{ + struct xtg_dev_info *tg; + + tg = dev_get_drvdata(&pdev->dev); + + xtg_remove_sysfs_dev_files(tg); + + return 0; +} + +static struct of_device_id xtg_of_match[] = { + { .compatible = "xlnx,axi-traffic-gen", }, + { /* end of table */ } +}; +MODULE_DEVICE_TABLE(of, xtg_of_match); + +static struct platform_driver xtg_driver = { + .driver = { + .name = "xilinx-trafgen", + .owner = THIS_MODULE, + .of_match_table = xtg_of_match, + }, + .probe = xtg_probe, + .remove = xtg_remove, +}; + +module_platform_driver(xtg_driver); + +MODULE_AUTHOR("Xilinx Inc."); +MODULE_DESCRIPTION("Xilinx Traffic Generator driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/mmc/host/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/mmc/host/Kconfig 2014-07-20 22:05:50.240066555 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/mmc/host/Kconfig 2014-07-20 22:06:36.759299071 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:133 @ If unsure, say N. +config MMC_SDHCI_OF_ARASAN + tristate "SDHCI OF support for the Arasan SDHCI controllers" + depends on MMC_SDHCI_PLTFM + depends on OF + help + This selects the Arasan Secure Digital Host Controller Interface + (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_CNS3XXX tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" depends on ARCH_CNS3XXX Index: linux-3.12.24-rt38-xilinx/drivers/mmc/host/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/mmc/host/Makefile 2014-07-20 22:05:50.238066588 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/mmc/host/Makefile 2014-07-20 22:06:36.769298906 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:60 @ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o +obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o Index: linux-3.12.24-rt38-xilinx/drivers/mmc/host/sdhci-of-arasan.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/mmc/host/sdhci-of-arasan.c 2014-07-20 22:06:36.779298741 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Arasan Secure Digital Host Controller Interface. + * Copyright (C) 2011 - 2012 Michal Simek <monstr@monstr.eu> + * Copyright (c) 2012 Wind River Systems, Inc. + * Copyright (C) 2013 Pengutronix e.K. + * Copyright (C) 2013 Xilinx Inc. + * + * Based on sdhci-of-esdhc.c + * + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * Copyright (c) 2009 MontaVista Software, Inc. + * + * Authors: Xiaobo Xie <X.Xie@freescale.com> + * Anton Vorontsov <avorontsov@ru.mvista.com> + * + * 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. + */ + +#include <linux/module.h> +#include "sdhci-pltfm.h" + +#define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c + +#define CLK_CTRL_TIMEOUT_SHIFT 16 +#define CLK_CTRL_TIMEOUT_MASK (0xf << CLK_CTRL_TIMEOUT_SHIFT) +#define CLK_CTRL_TIMEOUT_MIN_EXP 13 + +/** + * struct sdhci_arasan_data + * @clk_ahb: Pointer to the AHB clock + */ +struct sdhci_arasan_data { + struct clk *clk_ahb; +}; + +static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) +{ + u32 div; + unsigned long freq; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + div = readl(host->ioaddr + SDHCI_ARASAN_CLK_CTRL_OFFSET); + div = (div & CLK_CTRL_TIMEOUT_MASK) >> CLK_CTRL_TIMEOUT_SHIFT; + + freq = clk_get_rate(pltfm_host->clk); + freq /= 1 << (CLK_CTRL_TIMEOUT_MIN_EXP + div); + + return freq; +} + +static struct sdhci_ops sdhci_arasan_ops = { + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_timeout_clock = sdhci_arasan_get_timeout_clock, +}; + +static struct sdhci_pltfm_data sdhci_arasan_pdata = { + .ops = &sdhci_arasan_ops, +}; + +#ifdef CONFIG_PM_SLEEP +/** + * sdhci_arasan_suspend - Suspend method for the driver + * @dev: Address of the device structure + * Returns 0 on success and error value on error + * + * Put the device in a low power state. + */ +static int sdhci_arasan_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; + int ret; + + ret = sdhci_suspend_host(host); + if (ret) + return ret; + + clk_disable(pltfm_host->clk); + clk_disable(sdhci_arasan->clk_ahb); + + return 0; +} + +/** + * sdhci_arasan_resume - Resume method for the driver + * @dev: Address of the device structure + * Returns 0 on success and error value on error + * + * Resume operation after suspend + */ +static int sdhci_arasan_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; + int ret; + + ret = clk_enable(sdhci_arasan->clk_ahb); + if (ret) { + dev_err(dev, "Cannot enable AHB clock.\n"); + return ret; + } + + ret = clk_enable(pltfm_host->clk); + if (ret) { + dev_err(dev, "Cannot enable SD clock.\n"); + clk_disable(sdhci_arasan->clk_ahb); + return ret; + } + + return sdhci_resume_host(host); +} +#endif /* ! CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, + sdhci_arasan_resume); + +static int sdhci_arasan_probe(struct platform_device *pdev) +{ + int ret; + struct clk *clk_xin; + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_arasan_data *sdhci_arasan; + + sdhci_arasan = devm_kzalloc(&pdev->dev, sizeof(*sdhci_arasan), + GFP_KERNEL); + if (!sdhci_arasan) + return -ENOMEM; + + sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); + if (IS_ERR(sdhci_arasan->clk_ahb)) { + dev_err(&pdev->dev, "clk_ahb clock not found.\n"); + return PTR_ERR(sdhci_arasan->clk_ahb); + } + + clk_xin = devm_clk_get(&pdev->dev, "clk_xin"); + if (IS_ERR(clk_xin)) { + dev_err(&pdev->dev, "clk_xin clock not found.\n"); + return PTR_ERR(clk_xin); + } + + ret = clk_prepare_enable(sdhci_arasan->clk_ahb); + if (ret) { + dev_err(&pdev->dev, "Unable to enable AHB clock.\n"); + return ret; + } + + ret = clk_prepare_enable(clk_xin); + if (ret) { + dev_err(&pdev->dev, "Unable to enable SD clock.\n"); + goto clk_dis_ahb; + } + + host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0); + if (IS_ERR(host)) { + ret = PTR_ERR(host); + dev_err(&pdev->dev, "platform init failed (%u)\n", ret); + goto clk_disable_all; + } + + sdhci_get_of_property(pdev); + pltfm_host = sdhci_priv(host); + pltfm_host->priv = sdhci_arasan; + pltfm_host->clk = clk_xin; + + ret = sdhci_add_host(host); + if (ret) { + dev_err(&pdev->dev, "platform register failed (%u)\n", ret); + goto err_pltfm_free; + } + + return 0; + +err_pltfm_free: + sdhci_pltfm_free(pdev); +clk_disable_all: + clk_disable_unprepare(clk_xin); +clk_dis_ahb: + clk_disable_unprepare(sdhci_arasan->clk_ahb); + + return ret; +} + +static int sdhci_arasan_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; + + clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(sdhci_arasan->clk_ahb); + + return sdhci_pltfm_unregister(pdev); +} + +static const struct of_device_id sdhci_arasan_of_match[] = { + { .compatible = "arasan,sdhci-8.9a" }, + { .compatible = "xlnx,ps7-sdhci-1.00.a" }, + { .compatible = "generic-sdhci" }, + { } +}; +MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); + +static struct platform_driver sdhci_arasan_driver = { + .driver = { + .name = "sdhci-arasan", + .owner = THIS_MODULE, + .of_match_table = sdhci_arasan_of_match, + .pm = &sdhci_arasan_dev_pm_ops, + }, + .probe = sdhci_arasan_probe, + .remove = sdhci_arasan_remove, +}; + +module_platform_driver(sdhci_arasan_driver); + +MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller"); +MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/mtd/chips/cfi_probe.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/mtd/chips/cfi_probe.c 2014-07-20 22:05:50.180067545 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/mtd/chips/cfi_probe.c 2014-07-20 22:06:36.794298493 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:161 @ __u32 base = 0; int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor); int i; + int extendedId1 = 0; + int extendedId2 = 0; + int extendedId3 = 0; int addr_unlock1 = 0x555, addr_unlock2 = 0x2AA; xip_enable(base, map, cfi); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:190 @ for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) ((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor); + /* Note we put the device back into Read Mode BEFORE going into Auto + * Select Mode, as some devices support nesting of modes, others + * don't. This way should always work. + * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and + * so should be treated as nops or illegal (and so put the device + * back into Read Mode, which is a nop in this case). + */ + cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); + cfi->mfr = cfi_read_query16(map, base); + cfi->id = cfi_read_query16(map, base + ofs_factor); + + /* Get device ID cycle 1,2,3 for Numonyx/ST devices */ + if ((cfi->mfr == CFI_MFR_INTEL || cfi->mfr == CFI_MFR_ST) + && ((cfi->id & 0xff) == 0x7e) + && (le16_to_cpu(cfi->cfiq->P_ID) == 0x0002)) { + extendedId1 = cfi_read_query16(map, base + 0x1 * ofs_factor); + extendedId2 = cfi_read_query16(map, base + 0xe * ofs_factor); + extendedId3 = cfi_read_query16(map, base + 0xf * ofs_factor); + } + + /* Get AMD/Spansion extended JEDEC ID */ + if (cfi->mfr == CFI_MFR_AMD && (cfi->id & 0xff) == 0x7e) + cfi->id = cfi_read_query(map, base + 0xe * ofs_factor) << 8 | + cfi_read_query(map, base + 0xf * ofs_factor); + + /* Put it back into Read Mode */ + cfi_qry_mode_off(base, map, cfi); + xip_allowed(base, map); + /* Do any necessary byteswapping */ cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:231 @ cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc); cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize); + /* If the device is a M29EW used in 8-bit mode, adjust buffer size */ + if ((cfi->cfiq->MaxBufWriteSize > 0x8) && (cfi->mfr == CFI_MFR_INTEL || + cfi->mfr == CFI_MFR_ST) && (extendedId1 == 0x7E) && + (extendedId2 == 0x22 || extendedId2 == 0x23 || extendedId2 == 0x28) && + (extendedId3 == 0x01)) { + cfi->cfiq->MaxBufWriteSize = 0x8; + pr_warning("Adjusted buffer size on Numonyx flash M29EW family"); + pr_warning("in 8 bit mode\n"); + } + #ifdef DEBUG_CFI /* Dump the information therein */ print_cfi_ident(cfi->cfiq); Index: linux-3.12.24-rt38-xilinx/drivers/mtd/devices/m25p80.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/mtd/devices/m25p80.c 2014-07-20 22:05:50.179067562 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/mtd/devices/m25p80.c 2014-07-20 22:06:36.819298081 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:44 @ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ 0x6b /* Quad read command */ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ +#define OPCODE_QPP 0x32 /* Quad page program */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ #define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ #define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_RDID 0x9f /* Read JEDEC ID */ +#define OPCODE_RDFSR 0x70 /* Read Flag Status Register */ +#define OPCODE_WREAR 0xc5 /* Write Extended Address Register */ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:73 @ /* Used for Spansion flashes only. */ #define OPCODE_BRWR 0x17 /* Bank register write */ +#define OPCODE_BRRD 0x16 /* Bank register read */ /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:84 @ #define SR_BP2 0x10 /* Block protect 2 */ #define SR_SRWD 0x80 /* SR write protect */ +/* Flag Status Register bits. */ +#define FSR_RDY 0x80 /* Ready/Busy program erase + controller */ /* Define max times to check status register before we give up. */ -#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ +#define MAX_READY_WAIT_JIFFIES (480 * HZ) /* N25Q specs 480s max chip erase */ #define MAX_CMD_SIZE 6 #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:106 @ u8 program_opcode; u8 *command; bool fast_read; + u16 curbank; + u32 jedec_id; + bool check_fsr; + bool shift; + bool isparallel; + bool isstacked; + u8 dummycount; }; static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:127 @ */ /* - * Read the status register, returning its value in the location - * Return the status register value. + * Read register, returning its value in the location * Returns negative if error occurred. */ -static int read_sr(struct m25p *flash) +static inline int read_spi_reg(struct m25p *flash, u8 code, const char *name) { ssize_t retval; - u8 code = OPCODE_RDSR; u8 val; retval = spi_write_then_read(flash->spi, &code, 1, &val, 1); if (retval < 0) { - dev_err(&flash->spi->dev, "error %d reading SR\n", - (int) retval); + dev_err(&flash->spi->dev, "error %d reading %s\n", + (int) retval, name); return retval; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:147 @ } /* + * Read flag status register, returning its value in the location + * Return flag status register value. + * Returns negative if error occurred. + */ +static int read_fsr(struct m25p *flash) +{ + return read_spi_reg(flash, OPCODE_RDFSR, "FSR"); +} + +/* + * Read the status register, returning its value in the location + * Return the status register value. + * Returns negative if error occurred. + */ +static int read_sr(struct m25p *flash) +{ + return read_spi_reg(flash, OPCODE_RDSR, "SR"); +} + +/* * Write status register 1 byte * Returns negative if error occurred. */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:206 @ { int status; bool need_wren = false; + int ret; + u8 val; switch (JEDEC_MFR(jedec_id)) { case CFI_MFR_ST: /* Micron, actually */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:228 @ default: /* Spansion style */ flash->command[0] = OPCODE_BRWR; - flash->command[1] = enable << 7; - return spi_write(flash->spi, flash->command, 2); + flash->command[1] = enable << 7 ; + ret = spi_write(flash->spi, flash->command, 2); + + /* verify the 4 byte mode is enabled */ + flash->command[0] = OPCODE_BRRD; + spi_write_then_read(flash->spi, flash->command, 1, &val, 1); + if (val != enable << 7) { + dev_warn(&flash->spi->dev, + "fallback to 3-byte address mode\n"); + dev_warn(&flash->spi->dev, + "maximum accessible size is 16MB\n"); + flash->addr_width = 3; + } + return ret; } } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:252 @ static int wait_till_ready(struct m25p *flash) { unsigned long deadline; - int sr; + int sr, fsr; deadline = jiffies + MAX_READY_WAIT_JIFFIES; do { if ((sr = read_sr(flash)) < 0) break; - else if (!(sr & SR_WIP)) + else if (!(sr & SR_WIP)) { + if (flash->check_fsr) { + fsr = read_fsr(flash); + if (!(fsr & FSR_RDY)) + return 1; + } return 0; + } cond_resched(); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:276 @ } /* + * Update Extended Address/bank selection Register. + * Call with flash->lock locked. + */ +static int write_ear(struct m25p *flash, u32 addr) +{ + u8 ear; + int ret; + + /* Wait until finished previous write command. */ + if (wait_till_ready(flash)) + return 1; + + if (flash->mtd.size <= (0x1000000) << flash->shift) + return 0; + + addr = addr % (u32) flash->mtd.size; + ear = addr >> 24; + + if ((!flash->isstacked) && (ear == flash->curbank)) + return 0; + + if (flash->isstacked && (flash->mtd.size <= 0x2000000)) + return 0; + + if (JEDEC_MFR(flash->jedec_id) == 0x01) + flash->command[0] = OPCODE_BRWR; + if (JEDEC_MFR(flash->jedec_id) == 0x20) { + write_enable(flash); + flash->command[0] = OPCODE_WREAR; + } + flash->command[1] = ear; + + ret = spi_write(flash->spi, flash->command, 2); + if (ret) + return ret; + + flash->curbank = ear; + + return 0; +} + +/* * Erase the whole flash memory * * Returns 0 if successful, non-zero otherwise. @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:331 @ if (wait_till_ready(flash)) return 1; + if (flash->isstacked) + flash->spi->master->flags &= ~SPI_MASTER_U_PAGE; + /* Send write enable, then erase commands. */ write_enable(flash); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:342 @ spi_write(flash->spi, flash->command, 1); + if (flash->isstacked) { + /* Wait until finished previous write command. */ + if (wait_till_ready(flash)) + return 1; + + flash->spi->master->flags |= SPI_MASTER_U_PAGE; + + /* Send write enable, then erase commands. */ + write_enable(flash); + + /* Set up command buffer. */ + flash->command[0] = OPCODE_CHIP_ERASE; + + spi_write(flash->spi, flash->command, 1); + } + return 0; } static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd) { + int i; + /* opcode is in cmd[0] */ - cmd[1] = addr >> (flash->addr_width * 8 - 8); - cmd[2] = addr >> (flash->addr_width * 8 - 16); - cmd[3] = addr >> (flash->addr_width * 8 - 24); - cmd[4] = addr >> (flash->addr_width * 8 - 32); + for (i = 1; i <= flash->addr_width; i++) + cmd[i] = addr >> (flash->addr_width * 8 - i * 8); } static int m25p_cmdsz(struct m25p *flash) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:390 @ if (wait_till_ready(flash)) return 1; + /* update Extended Address Register */ + if (write_ear(flash, offset)) + return 1; + /* Send write enable, then erase commands. */ write_enable(flash); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:419 @ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); - u32 addr,len; + u32 addr, len, offset; uint32_t rem; pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev), @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:451 @ /* "sector"-at-a-time erase */ } else { while (len) { - if (erase_sector(flash, addr)) { + offset = addr; + if (flash->isparallel == 1) + offset /= 2; + if (flash->isstacked == 1) { + if (offset >= (flash->mtd.size / 2)) { + offset = offset - (flash->mtd.size / 2); + flash->spi->master->flags |= + SPI_MASTER_U_PAGE; + } else + flash->spi->master->flags &= + ~SPI_MASTER_U_PAGE; + } + if (erase_sector(flash, offset)) { instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:505 @ * Should add 1 byte DUMMY_BYTE. */ t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0); + t[0].len = m25p_cmdsz(flash) + flash->dummycount; spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; t[1].len = len; spi_message_add_tail(&t[1], &m); - mutex_lock(&flash->lock); - /* Wait till previous write/erase is done. */ - if (wait_till_ready(flash)) { + if (wait_till_ready(flash)) /* REVISIT status return?? */ - mutex_unlock(&flash->lock); return 1; - } /* FIXME switch to OPCODE_FAST_READ. It's required for higher * clocks; and at this writing, every chip this driver handles @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:530 @ spi_sync(flash->spi, &m); *retlen = m.actual_length - m25p_cmdsz(flash) - - (flash->fast_read ? 1 : 0); + flash->dummycount; - mutex_unlock(&flash->lock); + return 0; +} + +static int m25p80_read_ext(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct m25p *flash = mtd_to_m25p(mtd); + u32 addr = from; + u32 offset = from; + u32 read_len = 0; + u32 actual_len = 0; + u32 read_count = 0; + u32 rem_bank_len = 0; + u8 bank = 0; + +#define OFFSET_16_MB 0x1000000 + mutex_lock(&flash->lock); + + while (len) { + bank = addr / (OFFSET_16_MB << flash->shift); + rem_bank_len = ((OFFSET_16_MB << flash->shift) * (bank + 1)) - + addr; + offset = addr; + if (flash->isparallel == 1) + offset /= 2; + if (flash->isstacked == 1) { + if (offset >= (flash->mtd.size / 2)) { + offset = offset - (flash->mtd.size / 2); + flash->spi->master->flags |= SPI_MASTER_U_PAGE; + } else { + flash->spi->master->flags &= ~SPI_MASTER_U_PAGE; + } + } + write_ear(flash, offset); + if (len < rem_bank_len) + read_len = len; + else + read_len = rem_bank_len; + + m25p80_read(mtd, offset, read_len, &actual_len, buf); + + addr += actual_len; + len -= actual_len; + buf += actual_len; + read_count += actual_len; + } + + *retlen = read_count; + + mutex_unlock(&flash->lock); return 0; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:612 @ t[1].tx_buf = buf; spi_message_add_tail(&t[1], &m); - mutex_lock(&flash->lock); - /* Wait until finished previous write command. */ - if (wait_till_ready(flash)) { - mutex_unlock(&flash->lock); + if (wait_till_ready(flash)) return 1; - } write_enable(flash); /* Set up the opcode in the write buffer. */ flash->command[0] = flash->program_opcode; - m25p_addr2cmd(flash, to, flash->command); + m25p_addr2cmd(flash, (to >> flash->shift), flash->command); page_offset = to & (flash->page_size - 1); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:649 @ page_size = flash->page_size; /* write the next page to flash */ - m25p_addr2cmd(flash, to + i, flash->command); + m25p_addr2cmd(flash, ((to + i) >> flash->shift), + flash->command); t[1].tx_buf = buf + i; t[1].len = page_size; - wait_till_ready(flash); + if (wait_till_ready(flash)) + return 1; write_enable(flash); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:666 @ } } - mutex_unlock(&flash->lock); + return 0; +} +static int m25p80_write_ext(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct m25p *flash = mtd_to_m25p(mtd); + u32 addr = to; + u32 offset = to; + u32 write_len = 0; + u32 actual_len = 0; + u32 write_count = 0; + u32 rem_bank_len = 0; + u8 bank = 0; + +#define OFFSET_16_MB 0x1000000 + + mutex_lock(&flash->lock); + while (len) { + bank = addr / (OFFSET_16_MB << flash->shift); + rem_bank_len = ((OFFSET_16_MB << flash->shift) * (bank + 1)) - + addr; + offset = addr; + + if (flash->isstacked == 1) { + if (offset >= (flash->mtd.size / 2)) { + offset = offset - (flash->mtd.size / 2); + flash->spi->master->flags |= SPI_MASTER_U_PAGE; + } else { + flash->spi->master->flags &= ~SPI_MASTER_U_PAGE; + } + } + write_ear(flash, (offset >> flash->shift)); + if (len < rem_bank_len) + write_len = len; + else + write_len = rem_bank_len; + + m25p80_write(mtd, offset, write_len, &actual_len, buf); + + addr += actual_len; + len -= actual_len; + buf += actual_len; + write_count += actual_len; + } + + *retlen = write_count; + + mutex_unlock(&flash->lock); return 0; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:930 @ #define SST_WRITE 0x04 /* use SST byte programming */ #define M25P_NO_FR 0x08 /* Can't do fastread */ #define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */ +#define SECT_32K 0x20 /* OPCODE_BE_32K */ +#define E_FSR 0x40 /* Flag SR exists for flash */ }; #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1012 @ { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, + /* Numonyx flash n25q128 - FIXME check the name */ + { "n25q128", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, + { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, E_FSR) }, + { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, E_FSR) }, + { "n25q256a13", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | E_FSR) }, + { "n25q256a11", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | E_FSR) }, + { "n25q512a13", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | E_FSR) }, + { "n25q512a11", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | E_FSR) }, + { "n25q00aa13", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | E_FSR) }, /* PMC */ { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1046 @ { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, - { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + /* s25fl064k supports 4KiB, 32KiB and 64KiB sectors erase size. */ + /* To support JFFS2, the minimum erase size is 8KiB(>4KiB). */ + /* And thus, the sector size of s25fl064k is set to 32KiB for */ + /* JFFS2 support. */ + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_32K) }, /* SST -- large erase sizes are "overlays", "sectors" are 4K */ { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1062 @ { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, /* ST Microelectronics -- newer production may have feature updates */ { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1109 @ { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + /* Winbond -- w25q "blocks" are 64K, "sectors" are 32KiB */ + /* w25q64 supports 4KiB, 32KiB and 64KiB sectors erase size. */ + /* To support JFFS2, the minimum erase size is 8KiB(>4KiB). */ + /* And thus, the sector size of w25q64 is set to 32KiB for */ + /* JFFS2 support. */ + { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_32K) }, { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1269 @ flash->mtd.writesize = 1; flash->mtd.flags = MTD_CAP_NORFLASH; flash->mtd.size = info->sector_size * info->n_sectors; + + { +#ifdef CONFIG_OF + const char *comp_str; + u32 is_dual; + np = of_get_next_parent(spi->dev.of_node); + of_property_read_string(np, "compatible", &comp_str); + if (!strcmp(comp_str, "xlnx,ps7-qspi-1.00.a")) { + if (of_property_read_u32(np, "is-dual", &is_dual) < 0) { + /* Default to single if prop not defined */ + flash->shift = 0; + flash->isstacked = 0; + flash->isparallel = 0; + } else { + if (is_dual == 1) { + /* dual parallel */ + flash->shift = 1; + info->sector_size <<= flash->shift; + info->page_size <<= flash->shift; + flash->mtd.size <<= flash->shift; + flash->isparallel = 1; + flash->isstacked = 0; + } else { +#ifdef CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED + /* dual stacked */ + flash->shift = 0; + flash->mtd.size <<= 1; + flash->isstacked = 1; + flash->isparallel = 0; +#else + /* single */ + flash->shift = 0; + flash->isstacked = 0; + flash->isparallel = 0; +#endif + } + } + } +#else + /* Default to single */ + flash->shift = 0; + flash->isstacked = 0; + flash->isparallel = 0; +#endif + } + flash->mtd._erase = m25p80_erase; - flash->mtd._read = m25p80_read; + flash->mtd._read = m25p80_read_ext; /* flash protection support for STmicro chips */ if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1328 @ if (info->flags & SST_WRITE) flash->mtd._write = sst_write; else - flash->mtd._write = m25p80_write; + flash->mtd._write = m25p80_write_ext; /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { flash->erase_opcode = OPCODE_BE_4K; - flash->mtd.erasesize = 4096; + flash->mtd.erasesize = 4096 << flash->shift; + } else if (info->flags & SECT_32K) { + flash->erase_opcode = OPCODE_BE_32K; + flash->mtd.erasesize = 32768 << flash->shift; } else if (info->flags & SECT_4K_PMC) { flash->erase_opcode = OPCODE_BE_4K_PMC; flash->mtd.erasesize = 4096; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1345 @ flash->mtd.erasesize = info->sector_size; } + flash->read_opcode = OPCODE_NORM_READ; + flash->program_opcode = OPCODE_PP; + flash->dummycount = 0; + if (info->flags & M25P_NO_ERASE) flash->mtd.flags |= MTD_NO_ERASE; + if (info->flags & E_FSR) + flash->check_fsr = 1; + + flash->jedec_id = info->jedec_id; ppdata.of_node = spi->dev.of_node; flash->mtd.dev.parent = &spi->dev; flash->page_size = info->page_size; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1372 @ flash->fast_read = false; /* Default commands */ - if (flash->fast_read) + if (flash->fast_read) { flash->read_opcode = OPCODE_FAST_READ; - else - flash->read_opcode = OPCODE_NORM_READ; + flash->dummycount = 1; + } flash->program_opcode = OPCODE_PP; + if (spi->master->flags & SPI_MASTER_QUAD_MODE) { + flash->read_opcode = OPCODE_QUAD_READ; + flash->program_opcode = OPCODE_QPP; + flash->dummycount = 1; + } + if (info->addr_width) flash->addr_width = info->addr_width; else if (flash->mtd.size > 0x1000000) { /* enable 4-byte addressing if the device exceeds 16MiB */ - flash->addr_width = 4; - if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { - /* Dedicated 4-byte command set */ - flash->read_opcode = flash->fast_read ? - OPCODE_FAST_READ_4B : - OPCODE_NORM_READ_4B; - flash->program_opcode = OPCODE_PP_4B; - /* No small sector erase for 4-byte command set */ - flash->erase_opcode = OPCODE_SE_4B; - flash->mtd.erasesize = info->sector_size; - } else - set_4byte(flash, info->jedec_id, 1); +#ifdef CONFIG_OF + const char *comp_str; + np = of_get_next_parent(spi->dev.of_node); + of_property_read_string(np, "compatible", &comp_str); + if (!strcmp(comp_str, "xlnx,ps7-qspi-1.00.a")) { + flash->addr_width = 3; + set_4byte(flash, info->jedec_id, 0); + } else { +#endif + flash->addr_width = 4; + if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { + /* Dedicated 4-byte command set */ + flash->read_opcode = flash->fast_read ? + OPCODE_FAST_READ_4B : + OPCODE_NORM_READ_4B; + flash->program_opcode = OPCODE_PP_4B; + /* No small sector erase for 4-byte + * command set + */ + flash->erase_opcode = OPCODE_SE_4B; + flash->mtd.erasesize = info->sector_size; + } else + set_4byte(flash, info->jedec_id, 1); +#ifdef CONFIG_OF + } +#endif } else { flash->addr_width = 3; } Index: linux-3.12.24-rt38-xilinx/drivers/mtd/nand/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/mtd/nand/Kconfig 2014-07-20 22:05:50.177067595 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/mtd/nand/Kconfig 2014-07-20 22:06:36.835297817 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:520 @ This enables the driver for the NAND Flash on evaluation board based on w90p910 / NUC9xx. +config MTD_NAND_ZYNQ + tristate "Xilinx Zynq NAND flash driver" + depends on MTD_NAND && ARCH_ZYNQ + select ZYNQ_SMC + help + This enables access to the NAND flash device on Xilinx Zynq. + config MTD_NAND_JZ4740 tristate "Support for JZ4740 SoC NAND controller" depends on MACH_JZ4740 Index: linux-3.12.24-rt38-xilinx/drivers/mtd/nand/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/mtd/nand/Makefile 2014-07-20 22:05:50.176067611 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/mtd/nand/Makefile 2014-07-20 22:06:36.845297652 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:52 @ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ +obj-$(CONFIG_MTD_NAND_ZYNQ) += zynq_nand.o nand-objs := nand_base.o nand_bbt.o Index: linux-3.12.24-rt38-xilinx/drivers/mtd/nand/nand_base.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/mtd/nand/nand_base.c 2014-07-20 22:05:50.178067578 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/mtd/nand/nand_base.c 2014-07-20 22:06:36.877297124 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:814 @ int status, state = chip->state; unsigned long timeo = (state == FL_ERASING ? 400 : 20); +#if defined(ARCH_ZYNQ) && (CONFIG_HZ == 20) + /* Xilinx Zynq NAND work around for HZ=20 */ + timeo += 1; +#endif + led_trigger_event(nand_led_trigger, LED_FULL); /* @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2943 @ int i; int val; +#ifdef CONFIG_MTD_NAND_XILINX_PS + uint8_t *buf; + unsigned int options; + int j; +#endif + /* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */ if (chip->options & NAND_BUSWIDTH_16) { pr_err("Trying ONFI probe in 16 bits mode, aborting !\n"); return 0; } + /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2963 @ chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { +#ifdef CONFIG_MTD_NAND_XILINX_PS + buf = (uint8_t *)p; + for(j = 0;j < 256;j++) + buf[j] = chip->read_byte(mtd); +#else chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); +#endif if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { pr_info("ONFI param page %d valid\n", i); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:3044 @ pr_info("Failed to detect the extended param page.\n"); } +#ifdef CONFIG_MTD_NAND_XILINX_PS + /* Read the chip options before clearing the bits */ + options = chip->options; +#endif + pr_info("ONFI flash detected\n"); +#ifdef CONFIG_MTD_NAND_XILINX_PS + /* set the bus width option */ + if (options & NAND_BUSWIDTH_16) + chip->options |= NAND_BUSWIDTH_16; +#endif return 1; } Index: linux-3.12.24-rt38-xilinx/drivers/mtd/nand/zynq_nand.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/mtd/nand/zynq_nand.c 2014-07-20 22:06:36.897296794 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Zynq NAND Flash Controller Driver + * + * Copyright (C) 2009 - 2013 Xilinx, Inc. + * + * This driver is based on plat_nand.c and mxc_nand.c drivers + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/memory/zynq-smc.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define XNANDPS_DRIVER_NAME "xilinx_nandps" + +/* NAND flash driver defines */ +#define XNANDPS_CMD_PHASE 1 /* End command valid in command phase */ +#define XNANDPS_DATA_PHASE 2 /* End command valid in data phase */ +#define XNANDPS_ECC_SIZE 512 /* Size of data for ECC operation */ + +/* Flash memory controller operating parameters */ + +#define XNANDPS_ECC_CONFIG ((1 << 4) | /* ECC read at end of page */ \ + (0 << 5)) /* No Jumping */ + +/* AXI Address definitions */ +#define START_CMD_SHIFT 3 +#define END_CMD_SHIFT 11 +#define END_CMD_VALID_SHIFT 20 +#define ADDR_CYCLES_SHIFT 21 +#define CLEAR_CS_SHIFT 21 +#define ECC_LAST_SHIFT 10 +#define COMMAND_PHASE (0 << 19) +#define DATA_PHASE (1 << 19) + +#define XNANDPS_ECC_LAST (1 << ECC_LAST_SHIFT) /* Set ECC_Last */ +#define XNANDPS_CLEAR_CS (1 << CLEAR_CS_SHIFT) /* Clear chip select */ + +#define ONDIE_ECC_FEATURE_ADDR 0x90 + +/* Macros for the NAND controller register read/write */ +#define xnandps_write32(addr, val) __raw_writel((val), (addr)) + + +/** + * struct xnandps_command_format - Defines NAND flash command format + * @start_cmd: First cycle command (Start command) + * @end_cmd: Second cycle command (Last command) + * @addr_cycles: Number of address cycles required to send the address + * @end_cmd_valid: The second cycle command is valid for cmd or data phase + */ +struct xnandps_command_format { + int start_cmd; + int end_cmd; + u8 addr_cycles; + u8 end_cmd_valid; +}; + +/** + * struct xnandps_info - Defines the NAND flash driver instance + * @chip: NAND chip information structure + * @mtd: MTD information structure + * @parts: Pointer to the mtd_partition structure + * @nand_base: Virtual address of the NAND flash device + * @end_cmd_pending: End command is pending + * @end_cmd: End command + */ +struct xnandps_info { + struct nand_chip chip; + struct mtd_info mtd; + struct mtd_partition *parts; + void __iomem *nand_base; + unsigned long end_cmd_pending; + unsigned long end_cmd; +}; + +/* + * The NAND flash operations command format + */ +static const struct xnandps_command_format xnandps_commands[] = { + {NAND_CMD_READ0, NAND_CMD_READSTART, 5, XNANDPS_CMD_PHASE}, + {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, XNANDPS_CMD_PHASE}, + {NAND_CMD_READID, NAND_CMD_NONE, 1, NAND_CMD_NONE}, + {NAND_CMD_STATUS, NAND_CMD_NONE, 0, NAND_CMD_NONE}, + {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5, XNANDPS_DATA_PHASE}, + {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, NAND_CMD_NONE}, + {NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, XNANDPS_CMD_PHASE}, + {NAND_CMD_RESET, NAND_CMD_NONE, 0, NAND_CMD_NONE}, + {NAND_CMD_PARAM, NAND_CMD_NONE, 1, NAND_CMD_NONE}, + {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE}, + {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE}, + {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0}, + /* Add all the flash commands supported by the flash device and Linux */ + /* The cache program command is not supported by driver because driver + * cant differentiate between page program and cached page program from + * start command, these commands can be differentiated through end + * command, which doesn't fit in to the driver design. The cache program + * command is not supported by NAND subsystem also, look at 1612 line + * number (in nand_write_page function) of nand_base.c file. + * {NAND_CMD_SEQIN, NAND_CMD_CACHEDPROG, 5, XNANDPS_YES}, */ +}; + +/* Define default oob placement schemes for large and small page devices */ +static struct nand_ecclayout nand_oob_16 = { + .eccbytes = 3, + .eccpos = {0, 1, 2}, + .oobfree = { + {.offset = 8, + . length = 8} } +}; + +static struct nand_ecclayout nand_oob_64 = { + .eccbytes = 12, + .eccpos = { + 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63}, + .oobfree = { + {.offset = 2, + .length = 50} } +}; + +static struct nand_ecclayout ondie_nand_oob_64 = { + .eccbytes = 32, + + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 24, 25, 26, 27, 28, 29, 30, 31, + 40, 41, 42, 43, 44, 45, 46, 47, + 56, 57, 58, 59, 60, 61, 62, 63 + }, + + .oobfree = { + { .offset = 4, .length = 4 }, + { .offset = 20, .length = 4 }, + { .offset = 36, .length = 4 }, + { .offset = 52, .length = 4 } + } +}; + +/* Generic flash bbt decriptors */ +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +/** + * xnandps_calculate_hwecc - Calculate Hardware ECC + * @mtd: Pointer to the mtd_info structure + * @data: Pointer to the page data + * @ecc_code: Pointer to the ECC buffer where ECC data needs to be stored + * + * This function retrieves the Hardware ECC data from the controller and returns + * ECC data back to the MTD subsystem. + * + * returns: 0 on success or error value on failure + */ +static int +xnandps_calculate_hwecc(struct mtd_info *mtd, const u8 *data, u8 *ecc_code) +{ + u32 ecc_value = 0; + u8 ecc_reg, ecc_byte; + u32 ecc_status; + + /* Wait till the ECC operation is complete */ + while (xsmcps_ecc_is_busy()) + cpu_relax(); + + for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) { + /* Read ECC value for each block */ + ecc_value = xsmcps_get_ecc_val(ecc_reg); + ecc_status = (ecc_value >> 24) & 0xFF; + /* ECC value valid */ + if (ecc_status & 0x40) { + for (ecc_byte = 0; ecc_byte < 3; ecc_byte++) { + /* Copy ECC bytes to MTD buffer */ + *ecc_code = ecc_value & 0xFF; + ecc_value = ecc_value >> 8; + ecc_code++; + } + } else { + /* TODO */ + /* dev_dbg(&pdev->dev, "pl350: ecc status failed\n"); */ + } + } + return 0; +} + +/** + * onehot - onehot function + * @value: Value to check for onehot + * + * This function checks whether a value is onehot or not. + * onehot is if and only if onebit is set. + */ +static int onehot(unsigned short value) +{ + return (value & (value - 1)) == 0; +} + +/** + * xnandps_correct_data - ECC correction function + * @mtd: Pointer to the mtd_info structure + * @buf: Pointer to the page data + * @read_ecc: Pointer to the ECC value read from spare data area + * @calc_ecc: Pointer to the calculated ECC value + * + * This function corrects the ECC single bit errors & detects 2-bit errors. + * + * returns: 0 if no ECC errors found + * 1 if single bit error found and corrected. + * -1 if multiple ECC errors found. + */ +static int xnandps_correct_data(struct mtd_info *mtd, unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) +{ + unsigned char bit_addr; + unsigned int byte_addr; + unsigned short ecc_odd, ecc_even; + unsigned short read_ecc_lower, read_ecc_upper; + unsigned short calc_ecc_lower, calc_ecc_upper; + + read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) & 0xfff; + read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) & 0xfff; + + calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) & 0xfff; + calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) & 0xfff; + + ecc_odd = read_ecc_lower ^ calc_ecc_lower; + ecc_even = read_ecc_upper ^ calc_ecc_upper; + + if ((ecc_odd == 0) && (ecc_even == 0)) + return 0; /* no error */ + + if (ecc_odd == (~ecc_even & 0xfff)) { + /* bits [11:3] of error code is byte offset */ + byte_addr = (ecc_odd >> 3) & 0x1ff; + /* bits [2:0] of error code is bit offset */ + bit_addr = ecc_odd & 0x7; + /* Toggling error bit */ + buf[byte_addr] ^= (1 << bit_addr); + return 1; + } + + if (onehot(ecc_odd | ecc_even) == 1) + return 1; /* one error in parity */ + + return -1; /* Uncorrectable error */ +} + +/** + * xnandps_read_oob - [REPLACABLE] the most common OOB data read function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @page: Page number to read + */ +static int xnandps_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + unsigned long data_width = 4; + unsigned long data_phase_addr = 0; + uint8_t *p; + + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + + p = chip->oob_poi; + chip->read_buf(mtd, p, (mtd->oobsize - data_width)); + p += (mtd->oobsize - data_width); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= XNANDPS_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + chip->read_buf(mtd, p, data_width); + + return 0; +} + +/** + * xnandps_write_oob - [REPLACABLE] the most common OOB data write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @page: Page number to write + */ +static int xnandps_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + int status = 0; + const uint8_t *buf = chip->oob_poi; + unsigned long data_width = 4; + unsigned long data_phase_addr = 0; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + + chip->write_buf(mtd, buf, (mtd->oobsize - data_width)); + buf += (mtd->oobsize - data_width); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= XNANDPS_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + chip->write_buf(mtd, buf, data_width); + + /* Send command to program the OOB data */ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/** + * xnandps_read_page_raw - [Intern] read raw page data without ecc + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * @page: Page number to read + */ +static int xnandps_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + unsigned long data_width = 4; + unsigned long data_phase_addr = 0; + uint8_t *p; + + chip->read_buf(mtd, buf, mtd->writesize); + + p = chip->oob_poi; + chip->read_buf(mtd, p, (mtd->oobsize - data_width)); + p += (mtd->oobsize - data_width); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= XNANDPS_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + + chip->read_buf(mtd, p, data_width); + return 0; +} + +/** + * xnandps_write_page_raw - [Intern] raw page write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + */ +static int xnandps_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + unsigned long data_width = 4; + unsigned long data_phase_addr = 0; + uint8_t *p; + + chip->write_buf(mtd, buf, mtd->writesize); + + p = chip->oob_poi; + chip->write_buf(mtd, p, (mtd->oobsize - data_width)); + p += (mtd->oobsize - data_width); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= XNANDPS_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + + chip->write_buf(mtd, p, data_width); + + return 0; +} + +/** + * nand_write_page_hwecc - Hardware ECC based page write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * + * This functions writes data and hardware generated ECC values in to the page. + */ +static int xnandps_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required) +{ + int i, eccsize = chip->ecc.size; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + const uint8_t *p = buf; + uint32_t *eccpos = chip->ecc.layout->eccpos; + unsigned long data_phase_addr = 0; + unsigned long data_width = 4; + uint8_t *oob_ptr; + + for ( ; (eccsteps - 1); eccsteps--) { + chip->write_buf(mtd, p, eccsize); + p += eccsize; + } + chip->write_buf(mtd, p, (eccsize - data_width)); + p += (eccsize - data_width); + + /* Set ECC Last bit to 1 */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= XNANDPS_ECC_LAST; + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + chip->write_buf(mtd, p, data_width); + + /* Wait for ECC to be calculated and read the error values */ + p = buf; + chip->ecc.calculate(mtd, p, &ecc_calc[0]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]); + + /* Clear ECC last bit */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr &= ~XNANDPS_ECC_LAST; + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + + /* Write the spare area with ECC bytes */ + oob_ptr = chip->oob_poi; + chip->write_buf(mtd, oob_ptr, (mtd->oobsize - data_width)); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= XNANDPS_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + oob_ptr += (mtd->oobsize - data_width); + chip->write_buf(mtd, oob_ptr, data_width); + + return 0; +} + +/** + * xnandps_write_page_swecc - [REPLACABLE] software ecc based page write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + */ +static int xnandps_write_page_swecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + const uint8_t *p = buf; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + /* Software ecc calculation */ + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + + chip->ecc.write_page_raw(mtd, chip, buf, 1); + + return 0; +} + +/** + * xnandps_read_page_hwecc - Hardware ECC based page read function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the buffer to store read data + * @oob_required: Caller requires OOB data read to chip->oob_poi + * @page: Page number to read + * + * This functions reads data and checks the data integrity by comparing hardware + * generated ECC values and read ECC values from spare area. + * + * returns: 0 always and updates ECC operation status in to MTD structure + */ +static int xnandps_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int i, stat, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + unsigned long data_phase_addr = 0; + unsigned long data_width = 4; + uint8_t *oob_ptr; + + for ( ; (eccsteps - 1); eccsteps--) { + chip->read_buf(mtd, p, eccsize); + p += eccsize; + } + chip->read_buf(mtd, p, (eccsize - data_width)); + p += (eccsize - data_width); + + /* Set ECC Last bit to 1 */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= XNANDPS_ECC_LAST; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + chip->read_buf(mtd, p, data_width); + + /* Read the calculated ECC value */ + p = buf; + chip->ecc.calculate(mtd, p, &ecc_calc[0]); + + /* Clear ECC last bit */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr &= ~XNANDPS_ECC_LAST; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + + /* Read the stored ECC value */ + oob_ptr = chip->oob_poi; + chip->read_buf(mtd, oob_ptr, (mtd->oobsize - data_width)); + + /* de-assert chip select */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= XNANDPS_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + + oob_ptr += (mtd->oobsize - data_width); + chip->read_buf(mtd, oob_ptr, data_width); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = ~(chip->oob_poi[eccpos[i]]); + + eccsteps = chip->ecc.steps; + p = buf; + + /* Check ECC error for all blocks and correct if it is correctable */ + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/** + * xnandps_read_page_swecc - [REPLACABLE] software ecc based page read function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the buffer to store read data + * @oob_required: Caller requires OOB data read to chip->oob_poi + * @page: Page number to read + */ +static int xnandps_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + chip->ecc.read_page_raw(mtd, chip, buf, page, 1); + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + p = buf; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/** + * xnandps_select_chip - Select the flash device + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * + * This function is empty as the NAND controller handles chip select line + * internally based on the chip address passed in command and data phase. + */ +static void xnandps_select_chip(struct mtd_info *mtd, int chip) +{ + return; +} + +/** + * xnandps_cmd_function - Send command to NAND device + * @mtd: Pointer to the mtd_info structure + * @command: The command to be sent to the flash device + * @column: The column address for this command, -1 if none + * @page_addr: The page address for this command, -1 if none + */ +static void xnandps_cmd_function(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd->priv; + const struct xnandps_command_format *curr_cmd = NULL; + struct xnandps_info *xnand = + container_of(mtd, struct xnandps_info, mtd); + void __iomem *cmd_addr; + unsigned long cmd_data = 0; + unsigned long cmd_phase_addr = 0; + unsigned long data_phase_addr = 0; + unsigned long end_cmd = 0; + unsigned long end_cmd_valid = 0; + unsigned long i; + + if (xnand->end_cmd_pending) { + /* Check for end command if this command request is same as the + * pending command then return */ + if (xnand->end_cmd == command) { + xnand->end_cmd = 0; + xnand->end_cmd_pending = 0; + return; + } + } + + /* Emulate NAND_CMD_READOOB for large page device */ + if ((mtd->writesize > XNANDPS_ECC_SIZE) && + (command == NAND_CMD_READOOB)) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Get the command format */ + for (i = 0; (xnandps_commands[i].start_cmd != NAND_CMD_NONE || + xnandps_commands[i].end_cmd != NAND_CMD_NONE); i++) + if (command == xnandps_commands[i].start_cmd) + curr_cmd = &xnandps_commands[i]; + + if (curr_cmd == NULL) + return; + + /* Clear interrupt */ + xsmcps_clr_nand_int(); + + /* Get the command phase address */ + if (curr_cmd->end_cmd_valid == XNANDPS_CMD_PHASE) + end_cmd_valid = 1; + + if (curr_cmd->end_cmd == NAND_CMD_NONE) + end_cmd = 0x0; + else + end_cmd = curr_cmd->end_cmd; + + cmd_phase_addr = (unsigned long __force)xnand->nand_base | + (curr_cmd->addr_cycles << ADDR_CYCLES_SHIFT) | + (end_cmd_valid << END_CMD_VALID_SHIFT) | + (COMMAND_PHASE) | + (end_cmd << END_CMD_SHIFT) | + (curr_cmd->start_cmd << START_CMD_SHIFT); + + cmd_addr = (void __iomem * __force)cmd_phase_addr; + + /* Get the data phase address */ + end_cmd_valid = 0; + + data_phase_addr = (unsigned long __force)xnand->nand_base | + (0x0 << CLEAR_CS_SHIFT) | + (end_cmd_valid << END_CMD_VALID_SHIFT) | + (DATA_PHASE) | + (end_cmd << END_CMD_SHIFT) | + (0x0 << ECC_LAST_SHIFT); + + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + chip->IO_ADDR_W = chip->IO_ADDR_R; + + /* Command phase AXI write */ + /* Read & Write */ + if (column != -1 && page_addr != -1) { + /* Adjust columns for 16 bit bus width */ + if (chip->options & NAND_BUSWIDTH_16) + column >>= 1; + cmd_data = column; + if (mtd->writesize > XNANDPS_ECC_SIZE) { + cmd_data |= page_addr << 16; + /* Another address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) { + xnandps_write32(cmd_addr, cmd_data); + cmd_data = (page_addr >> 16); + } + } else { + cmd_data |= page_addr << 8; + } + } else if (page_addr != -1) { + /* Erase */ + cmd_data = page_addr; + } else if (column != -1) { + /* Change read/write column, read id etc */ + /* Adjust columns for 16 bit bus width */ + if ((chip->options & NAND_BUSWIDTH_16) && + ((command == NAND_CMD_READ0) || + (command == NAND_CMD_SEQIN) || + (command == NAND_CMD_RNDOUT) || + (command == NAND_CMD_RNDIN))) + column >>= 1; + cmd_data = column; + } + + xnandps_write32(cmd_addr, cmd_data); + + if (curr_cmd->end_cmd_valid) { + xnand->end_cmd = curr_cmd->end_cmd; + xnand->end_cmd_pending = 1; + } + + ndelay(100); + + if ((command == NAND_CMD_READ0) || + (command == NAND_CMD_RESET) || + (command == NAND_CMD_PARAM) || + (command == NAND_CMD_GET_FEATURES)) { + + while (!chip->dev_ready(mtd)) + ; + return; + } +} + +/** + * xnandps_read_buf - read chip data into buffer + * @mtd: Pointer to the mtd info structure + * @buf: Pointer to the buffer to store read data + * @len: Number of bytes to read + */ +static void xnandps_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + unsigned long *ptr = (unsigned long *)buf; + + len >>= 2; + for (i = 0; i < len; i++) + ptr[i] = readl(chip->IO_ADDR_R); +} + +/** + * xnandps_write_buf - write buffer to chip + * @mtd: Pointer to the mtd info structure + * @buf: Pointer to the buffer to store read data + * @len: Number of bytes to write + */ +static void xnandps_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + unsigned long *ptr = (unsigned long *)buf; + + len >>= 2; + + for (i = 0; i < len; i++) + writel(ptr[i], chip->IO_ADDR_W); +} + +/** + * xnandps_device_ready - Check device ready/busy line + * @mtd: Pointer to the mtd_info structure + * + * returns: 0 on busy or 1 on ready state + */ +static int xnandps_device_ready(struct mtd_info *mtd) +{ + if (xsmcps_get_nand_int_status_raw()) { + xsmcps_clr_nand_int(); + return 1; + } + return 0; +} + +/** + * xnandps_probe - Probe method for the NAND driver + * @pdev: Pointer to the platform_device structure + * + * This function initializes the driver data structures and the hardware. + * + * returns: 0 on success or error value on failure + */ +static int xnandps_probe(struct platform_device *pdev) +{ + struct xnandps_info *xnand; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + struct resource *res; + u8 maf_id, dev_id, i; + u8 get_feature; + u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; + int ondie_ecc_enabled = 0; + struct mtd_part_parser_data ppdata; + const unsigned int *prop; + u32 options = 0; + + xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL); + if (!xnand) + return -ENOMEM; + + /* Map physical address of NAND flash */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xnand->nand_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xnand->nand_base)) + return PTR_ERR(xnand->nand_base); + + /* Get x8 or x16 mode from device tree */ + prop = of_get_property(pdev->dev.of_node, "xlnx,nand-width", NULL); + if (prop) { + if (be32_to_cpup(prop) == 16) { + options |= NAND_BUSWIDTH_16; + } else if (be32_to_cpup(prop) == 8) { + options &= ~NAND_BUSWIDTH_16; + } else { + dev_info(&pdev->dev, "xlnx,nand-width not valid, using 8"); + options &= ~NAND_BUSWIDTH_16; + } + } else { + dev_info(&pdev->dev, "xlnx,nand-width not in device tree, using 8"); + options &= ~NAND_BUSWIDTH_16; + } + + /* Link the private data with the MTD structure */ + mtd = &xnand->mtd; + nand_chip = &xnand->chip; + + nand_chip->priv = xnand; + mtd->priv = nand_chip; + mtd->owner = THIS_MODULE; + mtd->name = "xilinx_nand"; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = xnand->nand_base; + nand_chip->IO_ADDR_W = xnand->nand_base; + + /* Set the driver entry points for MTD */ + nand_chip->cmdfunc = xnandps_cmd_function; + nand_chip->dev_ready = xnandps_device_ready; + nand_chip->select_chip = xnandps_select_chip; + + /* If we don't set this delay driver sets 20us by default */ + nand_chip->chip_delay = 30; + + /* Buffer read/write routines */ + nand_chip->read_buf = xnandps_read_buf; + nand_chip->write_buf = xnandps_write_buf; + + /* Set the device option and flash width */ + nand_chip->options = options; + nand_chip->bbt_options = NAND_BBT_USE_FLASH; + + platform_set_drvdata(pdev, xnand); + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1, NULL)) { + dev_err(&pdev->dev, "nand_scan_ident for NAND failed\n"); + return -ENXIO; + } + + /* Check if On-Die ECC flash */ + nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + maf_id = nand_chip->read_byte(mtd); + dev_id = nand_chip->read_byte(mtd); + + if ((maf_id == 0x2c) && + ((dev_id == 0xf1) || (dev_id == 0xa1) || + (dev_id == 0xb1) || + (dev_id == 0xaa) || (dev_id == 0xba) || + (dev_id == 0xda) || (dev_id == 0xca) || + (dev_id == 0xac) || (dev_id == 0xbc) || + (dev_id == 0xdc) || (dev_id == 0xcc) || + (dev_id == 0xa3) || (dev_id == 0xb3) || + (dev_id == 0xd3) || (dev_id == 0xc3))) { + + nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + get_feature = nand_chip->read_byte(mtd); + + if (get_feature & 0x08) { + ondie_ecc_enabled = 1; + } else { + nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + for (i = 0; i < 4; i++) + writeb(set_feature[i], nand_chip->IO_ADDR_W); + + ndelay(1000); + + nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + get_feature = nand_chip->read_byte(mtd); + + if (get_feature & 0x08) + ondie_ecc_enabled = 1; + } + } + + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.read_oob = xnandps_read_oob; + nand_chip->ecc.read_page_raw = xnandps_read_page_raw; + nand_chip->ecc.strength = 1; + nand_chip->ecc.write_oob = xnandps_write_oob; + nand_chip->ecc.write_page_raw = xnandps_write_page_raw; + if (ondie_ecc_enabled) { + /* bypass the controller ECC block */ + xsmcps_set_ecc_mode(XSMCPS_ECCMODE_BYPASS); + + /* The software ECC routines won't work with the + SMC controller */ + nand_chip->ecc.bytes = 0; + nand_chip->ecc.layout = &ondie_nand_oob_64; + nand_chip->ecc.read_page = xnandps_read_page_raw; + nand_chip->ecc.write_page = xnandps_write_page_raw; + nand_chip->ecc.size = mtd->writesize; + /* On-Die ECC spare bytes offset 8 is used for ECC codes */ + /* Use the BBT pattern descriptors */ + nand_chip->bbt_td = &bbt_main_descr; + nand_chip->bbt_md = &bbt_mirror_descr; + } else { + /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ + nand_chip->ecc.bytes = 3; + nand_chip->ecc.calculate = xnandps_calculate_hwecc; + nand_chip->ecc.correct = xnandps_correct_data; + nand_chip->ecc.hwctl = NULL; + nand_chip->ecc.read_page = xnandps_read_page_hwecc; + nand_chip->ecc.size = XNANDPS_ECC_SIZE; + nand_chip->ecc.write_page = xnandps_write_page_hwecc; + + xsmcps_set_ecc_pg_size(mtd->writesize); + switch (mtd->writesize) { + case 512: + case 1024: + case 2048: + xsmcps_set_ecc_mode(XSMCPS_ECCMODE_APB); + break; + default: + /* The software ECC routines won't work with the + SMC controller */ + nand_chip->ecc.calculate = nand_calculate_ecc; + nand_chip->ecc.correct = nand_correct_data; + nand_chip->ecc.read_page = xnandps_read_page_swecc; + /* nand_chip->ecc.read_subpage = nand_read_subpage; */ + nand_chip->ecc.write_page = xnandps_write_page_swecc; + nand_chip->ecc.size = 256; + break; + } + + if (mtd->oobsize == 16) + nand_chip->ecc.layout = &nand_oob_16; + else if (mtd->oobsize == 64) + nand_chip->ecc.layout = &nand_oob_64; + } + + /* second phase scan */ + if (nand_scan_tail(mtd)) { + dev_err(&pdev->dev, "nand_scan_tail for NAND failed\n"); + return -ENXIO; + } + + ppdata.of_node = pdev->dev.of_node; + + mtd_device_parse_register(&xnand->mtd, NULL, &ppdata, NULL, 0); + + return 0; +} + +/** + * xnandps_remove - Remove method for the NAND driver + * @pdev: Pointer to the platform_device structure + * + * This function is called if the driver module is being unloaded. It frees all + * resources allocated to the device. + * + * returns: 0 on success or error value on failure + */ +static int xnandps_remove(struct platform_device *pdev) +{ + struct xnandps_info *xnand = platform_get_drvdata(pdev); + + /* Release resources, unregister device */ + nand_release(&xnand->mtd); + /* kfree(NULL) is safe */ + kfree(xnand->parts); + + return 0; +} + +/* Match table for device tree binding */ +static const struct of_device_id xnandps_of_match[] = { + { .compatible = "xlnx,ps7-nand-1.00.a" }, + {}, +}; +MODULE_DEVICE_TABLE(of, xnandps_of_match); + +/* + * xnandps_driver - This structure defines the NAND subsystem platform driver + */ +static struct platform_driver xnandps_driver = { + .probe = xnandps_probe, + .remove = xnandps_remove, + .driver = { + .name = XNANDPS_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = xnandps_of_match, + }, +}; + +module_platform_driver(xnandps_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_ALIAS("platform:" XNANDPS_DRIVER_NAME); +MODULE_DESCRIPTION("Xilinx PS NAND Flash Driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/net/can/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/can/Kconfig 2014-07-20 22:05:50.250066390 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/can/Kconfig 2014-07-20 22:06:36.912296547 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:128 @ endian syntheses of the cores would need some modifications on the hardware level to work. +config CAN_XILINXCAN + tristate "Xilinx CAN" + depends on CAN && (ARCH_ZYNQ || MICROBLAZE) + default n + ---help--- + Xilinx CAN driver. This driver supports both soft AXI CAN IP and + Zynq CANPS IP. + source "drivers/net/can/mscan/Kconfig" source "drivers/net/can/sja1000/Kconfig" Index: linux-3.12.24-rt38-xilinx/drivers/net/can/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/can/Makefile 2014-07-20 22:05:50.249066407 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/can/Makefile 2014-07-20 22:06:36.921296398 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:28 @ obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o obj-$(CONFIG_PCH_CAN) += pch_can.o obj-$(CONFIG_CAN_GRCAN) += grcan.o +obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG Index: linux-3.12.24-rt38-xilinx/drivers/net/can/xilinx_can.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/net/can/xilinx_can.c 2014-07-20 22:06:36.940296085 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx CAN device driver + * + * Copyright (C) 2012 - 2013 Xilinx, Inc. + * Copyright (C) 2009 PetaLogix. All rights reserved. + * + * Description: + * This driver is developed for Axi CAN IP and for Zynq CANPS Controller. + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/skbuff.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> +#include <linux/can/led.h> + +#define DRIVER_NAME "XILINX_CAN" + +/* CAN registers set */ +#define XCAN_SRR_OFFSET 0x00 /* Software reset */ +#define XCAN_MSR_OFFSET 0x04 /* Mode select */ +#define XCAN_BRPR_OFFSET 0x08 /* Baud rate prescaler */ +#define XCAN_BTR_OFFSET 0x0C /* Bit timing */ +#define XCAN_ECR_OFFSET 0x10 /* Error counter */ +#define XCAN_ESR_OFFSET 0x14 /* Error status */ +#define XCAN_SR_OFFSET 0x18 /* Status */ +#define XCAN_ISR_OFFSET 0x1C /* Interrupt status */ +#define XCAN_IER_OFFSET 0x20 /* Interrupt enable */ +#define XCAN_ICR_OFFSET 0x24 /* Interrupt clear */ +#define XCAN_TXFIFO_ID_OFFSET 0x30 /* TX FIFO ID */ +#define XCAN_TXFIFO_DLC_OFFSET 0x34 /* TX FIFO DLC */ +#define XCAN_TXFIFO_DW1_OFFSET 0x38 /* TX FIFO Data Word 1 */ +#define XCAN_TXFIFO_DW2_OFFSET 0x3C /* TX FIFO Data Word 2 */ +#define XCAN_RXFIFO_ID_OFFSET 0x50 /* RX FIFO ID */ +#define XCAN_RXFIFO_DLC_OFFSET 0x54 /* RX FIFO DLC */ +#define XCAN_RXFIFO_DW1_OFFSET 0x58 /* RX FIFO Data Word 1 */ +#define XCAN_RXFIFO_DW2_OFFSET 0x5C /* RX FIFO Data Word 2 */ + +/* CAN register bit masks - XCAN_<REG>_<BIT>_MASK */ +#define XCAN_SRR_CEN_MASK 0x00000002 /* CAN enable */ +#define XCAN_MSR_LBACK_MASK 0x00000002 /* Loop back mode select */ +#define XCAN_MSR_SLEEP_MASK 0x00000001 /* Sleep mode select */ +#define XCAN_BRPR_BRP_MASK 0x000000FF /* Baud rate prescaler */ +#define XCAN_BTR_SJW_MASK 0x00000180 /* Synchronous jump width */ +#define XCAN_BTR_TS2_MASK 0x00000070 /* Time segment 2 */ +#define XCAN_BTR_TS1_MASK 0x0000000F /* Time segment 1 */ +#define XCAN_ECR_REC_MASK 0x0000FF00 /* Receive error counter */ +#define XCAN_ECR_TEC_MASK 0x000000FF /* Transmit error counter */ +#define XCAN_ESR_ACKER_MASK 0x00000010 /* ACK error */ +#define XCAN_ESR_BERR_MASK 0x00000008 /* Bit error */ +#define XCAN_ESR_STER_MASK 0x00000004 /* Stuff error */ +#define XCAN_ESR_FMER_MASK 0x00000002 /* Form error */ +#define XCAN_ESR_CRCER_MASK 0x00000001 /* CRC error */ +#define XCAN_SR_TXFLL_MASK 0x00000400 /* TX FIFO is full */ +#define XCAN_SR_ESTAT_MASK 0x00000180 /* Error status */ +#define XCAN_SR_ERRWRN_MASK 0x00000040 /* Error warning */ +#define XCAN_SR_NORMAL_MASK 0x00000008 /* Normal mode */ +#define XCAN_SR_LBACK_MASK 0x00000002 /* Loop back mode */ +#define XCAN_SR_CONFIG_MASK 0x00000001 /* Configuration mode */ +#define XCAN_IXR_TXFEMP_MASK 0x00004000 /* TX FIFO Empty */ +#define XCAN_IXR_WKUP_MASK 0x00000800 /* Wake up interrupt */ +#define XCAN_IXR_SLP_MASK 0x00000400 /* Sleep interrupt */ +#define XCAN_IXR_BSOFF_MASK 0x00000200 /* Bus off interrupt */ +#define XCAN_IXR_ERROR_MASK 0x00000100 /* Error interrupt */ +#define XCAN_IXR_RXNEMP_MASK 0x00000080 /* RX FIFO NotEmpty intr */ +#define XCAN_IXR_RXOFLW_MASK 0x00000040 /* RX FIFO Overflow intr */ +#define XCAN_IXR_RXOK_MASK 0x00000010 /* Message received intr */ +#define XCAN_IXR_TXOK_MASK 0x00000002 /* TX successful intr */ +#define XCAN_IXR_ARBLST_MASK 0x00000001 /* Arbitration lost intr */ +#define XCAN_IDR_ID1_MASK 0xFFE00000 /* Standard msg identifier */ +#define XCAN_IDR_SRR_MASK 0x00100000 /* Substitute remote TXreq */ +#define XCAN_IDR_IDE_MASK 0x00080000 /* Identifier extension */ +#define XCAN_IDR_ID2_MASK 0x0007FFFE /* Extended message ident */ +#define XCAN_IDR_RTR_MASK 0x00000001 /* Remote TX request */ +#define XCAN_DLCR_DLC_MASK 0xF0000000 /* Data length code */ + +/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */ +#define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ +#define XCAN_BTR_TS2_SHIFT 4 /* Time segment 2 */ +#define XCAN_IDR_ID1_SHIFT 21 /* Standard Messg Identifier */ +#define XCAN_IDR_ID2_SHIFT 1 /* Extended Message Identifier */ +#define XCAN_DLCR_DLC_SHIFT 28 /* Data length code */ + +/* CAN frame length constants */ +#define XCAN_ECHO_SKB_MAX 64 +#define XCAN_FRAME_MAX_DATA_LEN 8 +#define XCAN_TIMEOUT (50 * HZ) + +/** + * struct xcan_priv - This definition define CAN driver instance + * @can: CAN private data structure. + * @open_time: For holding timeout values + * @waiting_ech_skb_index: Pointer for skb + * @ech_skb_next: This tell the next packet in the queue + * @waiting_ech_skb_num: Gives the number of packets waiting + * @xcan_echo_skb_max: Maximum number packets the driver CAN send + * @ech_skb_lock: For spinlock purpose + * @read_reg: For reading data from CAN registers + * @write_reg: For writing data to CAN registers + * @dev: Network device data structure + * @reg_base: Ioremapped address to registers + * @irq_flags: For request_irq() + * @aperclk: Pointer to struct clk + * @devclk: Pointer to struct clk + */ +struct xcan_priv { + struct can_priv can; + int open_time; + int waiting_ech_skb_index; + int ech_skb_next; + int waiting_ech_skb_num; + int xcan_echo_skb_max; + spinlock_t ech_skb_lock; + u32 (*read_reg)(const struct xcan_priv *priv, int reg); + void (*write_reg)(const struct xcan_priv *priv, int reg, u32 val); + struct net_device *dev; + void __iomem *reg_base; + unsigned long irq_flags; + struct clk *aperclk; + struct clk *devclk; +}; + +/* CAN Bittiming constants as per Xilinx CAN specs */ +static struct can_bittiming_const xcan_bittiming_const = { + .name = DRIVER_NAME, + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 256, + .brp_inc = 1, +}; + +/** + * xcan_write_reg - Write a value to the device register + * @priv: Driver private data structure + * @reg: Register offset + * @val: Value to write at the Register offset + * + * Write data to the paricular CAN register + */ +static void xcan_write_reg(const struct xcan_priv *priv, int reg, u32 val) +{ + writel(val, priv->reg_base + reg); +} + +/** + * xcan_read_reg - Read a value from the device register + * @priv: Driver private data structure + * @reg: Register offset + * + * Read data from the particular CAN register + * Return: value read from the CAN register + */ +static u32 xcan_read_reg(const struct xcan_priv *priv, int reg) +{ + return readl(priv->reg_base + reg); +} + +/** + * set_reset_mode - Resets the CAN device mode + * @ndev: Pointer to net_device structure + * + * This is the driver reset mode routine.The driver + * enters into configuration mode. + * + * Return: 0 on success and failure value on error + */ +static int set_reset_mode(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + unsigned long timeout; + + priv->can.state = CAN_STATE_STOPPED; + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_OFFSET); + + timeout = jiffies + XCAN_TIMEOUT; + while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & XCAN_SR_CONFIG_MASK)) { + if (time_after(jiffies, timeout)) { + netdev_warn(ndev, "timedout waiting for config mode\n"); + return -ETIMEDOUT; + } + schedule_timeout(1); + } + + return 0; +} + +/** + * xcan_set_bittiming - CAN set bit timing routine + * @ndev: Pointer to net_device structure + * + * This is the driver setbittiming routine. + * Return: 0 on success and failure value on error + */ +static int xcan_set_bittiming(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct can_bittiming *bt = &priv->can.bittiming; + u32 btr0, btr1; + u32 is_config_mode; + + /* Check whether Xilinx CAN is in configuration mode. + * It cannot set bit timing if Xilinx CAN is not in configuration mode. + */ + is_config_mode = priv->read_reg(priv, XCAN_SR_OFFSET) & + XCAN_SR_CONFIG_MASK; + if (!is_config_mode) { + netdev_alert(ndev, + "Cannot set bittiming can is not in config mode\n"); + return -EPERM; + } + + netdev_dbg(ndev, "brp=%d,prop=%d,phase_seg1:%d,phase_reg2=%d,sjw=%d\n", + bt->brp, bt->prop_seg, bt->phase_seg1, bt->phase_seg2, + bt->sjw); + + /* Setting Baud Rate prescalar value in BRPR Register */ + btr0 = (bt->brp - 1) & XCAN_BRPR_BRP_MASK; + + /* Setting Time Segment 1 in BTR Register */ + btr1 = (bt->prop_seg + bt->phase_seg1 - 1) & XCAN_BTR_TS1_MASK; + + /* Setting Time Segment 2 in BTR Register */ + btr1 |= ((bt->phase_seg2 - 1) << XCAN_BTR_TS2_SHIFT) & + XCAN_BTR_TS2_MASK; + + /* Setting Synchronous jump width in BTR Register */ + btr1 |= ((bt->sjw - 1) << XCAN_BTR_SJW_SHIFT) & XCAN_BTR_SJW_MASK; + + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + netdev_info(ndev, "Doesn't support Triple Sampling\n"); + netdev_dbg(ndev, "Setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); + + priv->write_reg(priv, XCAN_BRPR_OFFSET, btr0); + priv->write_reg(priv, XCAN_BTR_OFFSET, btr1); + + netdev_dbg(ndev, "BRPR=0x%08x, BTR=0x%08x\n", + priv->read_reg(priv, XCAN_BRPR_OFFSET), + priv->read_reg(priv, XCAN_BTR_OFFSET)); + + return 0; +} + +/** + * set_normal_mode - CAN device mode setting routine + * @ndev: Pointer to net_device structure + * + * This routine sets the CAN device mode. + * Return: 0 on success + */ +static int set_normal_mode(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + + /* Enable interrupts */ + priv->write_reg(priv, XCAN_IER_OFFSET, XCAN_IXR_TXOK_MASK | + XCAN_IXR_BSOFF_MASK | XCAN_IXR_WKUP_MASK | + XCAN_IXR_SLP_MASK | XCAN_IXR_RXNEMP_MASK | + XCAN_IXR_ERROR_MASK | XCAN_IXR_ARBLST_MASK); + + /* Check whether it is loopback mode or normal mode */ + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) + /* Put device into loopback mode */ + priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_LBACK_MASK); + else + /* The device is in normal mode */ + priv->write_reg(priv, XCAN_MSR_OFFSET, 0); + + if (priv->can.state == CAN_STATE_STOPPED) { + /* Enable Xilinx CAN */ + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { + while ((priv->read_reg(priv, XCAN_SR_OFFSET) & + XCAN_SR_LBACK_MASK) == 0) + ; + } else { + while ((priv->read_reg(priv, XCAN_SR_OFFSET) + & XCAN_SR_NORMAL_MASK) == 0) + ; + } + netdev_dbg(ndev, "status:#x%08x\n", + priv->read_reg(priv, XCAN_SR_OFFSET)); + } + + return 0; +} + +/** + * xcan_start - This the drivers start routine + * @ndev: Pointer to net_device structure + * + * This is the drivers start routine. + * Based on the State of the CAN device it puts + * the CAN device into a proper mode. + * + * Return: 0 on success, negative errno otherwise + */ +static int xcan_start(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + + /* Check if it is in reset mode */ + if (priv->can.state != CAN_STATE_STOPPED) + set_reset_mode(ndev); + + /* Leave reset mode */ + return set_normal_mode(ndev); +} + +/** + * xcan_do_set_mode - This sets the mode of the driver + * @ndev: Pointer to net_device structure + * @mode: Tells the mode of the driver + * + * This check the drivers state and calls the + * the corresponding modes to set. + * + * Return: 0 on success and failure value on error + */ +static int xcan_do_set_mode(struct net_device *ndev, enum can_mode mode) +{ + struct xcan_priv *priv = netdev_priv(ndev); + int ret; + + netdev_dbg(ndev, "Setting the mode of the driver%s\n", __func__); + + if (!priv->open_time) + return -EINVAL; + + switch (mode) { + case CAN_MODE_START: + ret = xcan_start(ndev); + if (ret < 0) + netdev_err(ndev, "xcan_start failed!\n"); + + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +/** + * xcan_start_xmit - Starts the transmission + * @skb: sk_buff pointer that contains data to be Txed + * @ndev: Pointer to net_device structure + * + * This function is invoked from upper layers to initiate transmission. This + * function uses the next available free txbuff and populates their fields to + * start the transmission. + * + * Return: 0 on success and failure value on error + */ +static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf = (struct can_frame *)skb->data; + u32 id, dlc, tmp_dw1, tmp_dw2 = 0, data1, data2 = 0; + unsigned long flags; + + /* Check if the TX buffer is full */ + if (priv->read_reg(priv, XCAN_SR_OFFSET) & XCAN_SR_TXFLL_MASK) { + netif_stop_queue(ndev); + netdev_err(ndev, "TX register is still full!\n"); + return NETDEV_TX_BUSY; + } else if (priv->waiting_ech_skb_num == priv->xcan_echo_skb_max) { + netdev_err(ndev, "waiting:0x%08x, max:0x%08x\n", + priv->waiting_ech_skb_num, priv->xcan_echo_skb_max); + /* Theoretically, if TX interrupts get lost, we might end here + * without ever recovering.Check if TX FIFO is empty recover + * in this case + */ + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK); + netdev_err(ndev, "Trying to recover...\n"); + if (priv->read_reg(priv, XCAN_ISR_OFFSET) & + XCAN_IXR_TXFEMP_MASK) { + spin_lock_irqsave(&priv->ech_skb_lock, flags); + while (priv->waiting_ech_skb_num > 0) { + spin_unlock_irqrestore(&priv->ech_skb_lock, + flags); + can_get_echo_skb(ndev, + priv->waiting_ech_skb_index); + priv->waiting_ech_skb_index = + (priv->waiting_ech_skb_index + 1) % + priv->xcan_echo_skb_max; + spin_lock_irqsave(&priv->ech_skb_lock, flags); + priv->waiting_ech_skb_num--; + } + spin_unlock_irqrestore(&priv->ech_skb_lock, flags); + netdev_err(ndev, "...recovered!\n"); + } else { + netdev_err(ndev, "...could not recover (yet)!\n"); + } + return NETDEV_TX_BUSY; + } + + /* Watch carefully on the bit sequence */ + if ((cf->can_id & CAN_EFF_FLAG) == 0) { + /* Standard CAN ID format */ + id = ((cf->can_id & CAN_SFF_MASK) << XCAN_IDR_ID1_SHIFT) & + XCAN_IDR_ID1_MASK; + + if ((cf->can_id & CAN_RTR_FLAG) != 0) + /* Extended frames remote TX request */ + id |= XCAN_IDR_SRR_MASK; + } else { + /* Extended CAN ID formact */ + id = ((cf->can_id & CAN_EFF_MASK) << XCAN_IDR_ID2_SHIFT) & + XCAN_IDR_ID2_MASK; + id |= (((cf->can_id & CAN_EFF_MASK) >> + (CAN_EFF_ID_BITS-CAN_SFF_ID_BITS)) << + XCAN_IDR_ID1_SHIFT) & XCAN_IDR_ID1_MASK; + + /* The substibute remote TX request bit should be "1" + * for extended frames as in the Xilinx CAN datasheet + */ + id |= XCAN_IDR_IDE_MASK | XCAN_IDR_SRR_MASK; + + if (cf->can_id & CAN_RTR_FLAG) + /* Extended frames remote TX request */ + id |= XCAN_IDR_RTR_MASK; + } + + dlc = (cf->can_dlc & 0xf) << XCAN_DLCR_DLC_SHIFT; + + tmp_dw1 = le32_to_cpup((u32 *)(cf->data)); + data1 = htonl(tmp_dw1); + if (dlc > 4) { + tmp_dw2 = le32_to_cpup((u32 *)(cf->data + 4)); + data2 = htonl(tmp_dw2); + } + + netdev_dbg(ndev, "can:id=0x%08x,dlc=0x%08x,d1=0x%08x,d2=0x%08x\n", + cf->can_id, cf->can_dlc, tmp_dw1, tmp_dw2); + netdev_dbg(ndev, "tx:id=0x%08x,dlc=0x%08x,d1=0x%08x,d2=0x%08x\n", + id, dlc, data1, data2); + + /* Write the Frame to Xilinx CAN TX FIFO */ + priv->write_reg(priv, XCAN_TXFIFO_ID_OFFSET, id); + priv->write_reg(priv, XCAN_TXFIFO_DLC_OFFSET, dlc); + priv->write_reg(priv, XCAN_TXFIFO_DW1_OFFSET, data1); + priv->write_reg(priv, XCAN_TXFIFO_DW2_OFFSET, data2); + stats->tx_bytes += (dlc & 0xf); + ndev->trans_start = jiffies; + + can_put_echo_skb(skb, ndev, priv->ech_skb_next); + + priv->ech_skb_next = (priv->ech_skb_next + 1) % priv->xcan_echo_skb_max; + + spin_lock_irqsave(&priv->ech_skb_lock, flags); + priv->waiting_ech_skb_num++; + spin_unlock_irqrestore(&priv->ech_skb_lock, flags); + + return NETDEV_TX_OK; +} + +/** + * xcan_rx - Is called from CAN isr to complete the received + * frame processing + * @ndev: Pointer to net_device structure + * + * This function is invoked from the CAN isr to process the Rx frames. It + * does minimal processing and invokes "netif_rx" to complete further + * processing. + */ +static void xcan_rx(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u32 id_xcan, dlc, tmp_dw1, tmp_dw2, data1, data2 = 0; + + skb = alloc_can_skb(ndev, &cf); + if (!skb) + return; + + /* Read a frame from Xilinx zynq CANPS */ + id_xcan = priv->read_reg(priv, XCAN_RXFIFO_ID_OFFSET); + dlc = priv->read_reg(priv, XCAN_RXFIFO_DLC_OFFSET) & XCAN_DLCR_DLC_MASK; + tmp_dw1 = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET); + tmp_dw2 = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET); + netdev_dbg(ndev, "rx:id=0x%08x,dlc=0x%08x,d1=0x%08x,d2=0x%08x\n", + id_xcan, dlc, tmp_dw1, tmp_dw2); + + /* Change Xilinx CAN data length format to socketCAN data format */ + cf->can_dlc = get_can_dlc((dlc & XCAN_DLCR_DLC_MASK) >> + XCAN_DLCR_DLC_SHIFT); + + /* Change Xilinx CAN ID format to socketCAN ID format */ + if (id_xcan & XCAN_IDR_IDE_MASK) { + /* The received frame is an Extended format frame */ + cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3; + cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >> + XCAN_IDR_ID2_SHIFT; + cf->can_id |= CAN_EFF_FLAG; + if (id_xcan & XCAN_IDR_RTR_MASK) + cf->can_id |= CAN_RTR_FLAG; + } else { + /* The received frame is a standard format frame */ + cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> + XCAN_IDR_ID1_SHIFT; + if (id_xcan & XCAN_IDR_RTR_MASK) + cf->can_id |= CAN_RTR_FLAG; + } + + /* Change Xilinx CAN data format to socketCAN data format */ + data1 = cpu_to_le32((u32 *)tmp_dw1); + *(u32 *)(cf->data) = ntohl(data1); + if (cf->can_dlc > 4) { + data2 = cpu_to_le32((u32 *)tmp_dw2); + *(u32 *)(cf->data+4) = ntohl(data2); + } else { + *(u32 *)(cf->data+4) = 0; + } + stats->rx_bytes += cf->can_dlc; + + can_led_event(ndev, CAN_LED_EVENT_RX); + + netif_rx(skb); + + stats->rx_packets++; +} + +/** + * xcan_err_interrupt - error frame Isr + * @ndev: net_device pointer + * @isr: Interrupts status register value + * + * This is the CAN error interrupt and it will + * check the the type of error and forward the error + * frame to upper layers. + */ +static void xcan_err_interrupt(struct net_device *ndev, u32 isr) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u32 err_status, status; + u8 i; + + skb = alloc_can_err_skb(ndev, &cf); + if (!skb) + return; + + err_status = priv->read_reg(priv, XCAN_ESR_OFFSET); + status = priv->read_reg(priv, XCAN_SR_OFFSET); + + cf->can_id = CAN_ERR_FLAG; + memset(cf->data, 0, sizeof(cf->data)); + + if (isr & XCAN_IXR_BSOFF_MASK) { + cf->can_id |= CAN_ERR_BUSOFF; + priv->can.state = CAN_STATE_BUS_OFF; + can_bus_off(ndev); + } else if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) { + cf->can_id |= CAN_ERR_CRTL; + priv->can.state = CAN_STATE_ERROR_PASSIVE; + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE | + CAN_ERR_CRTL_TX_PASSIVE; + } else if (status & XCAN_SR_ERRWRN_MASK) { + cf->can_id |= CAN_ERR_CRTL; + priv->can.state = CAN_STATE_ERROR_WARNING; + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING | + CAN_ERR_CRTL_TX_WARNING; + } + + /* Check for Arbitration lost interrupt */ + if (isr & XCAN_IXR_ARBLST_MASK) { + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] = CAN_ERR_LOSTARB_UNSPEC; + } + + /* Check for RX FIFO Overflow interrupt */ + if (isr & XCAN_IXR_RXOFLW_MASK) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; + } + + /* Check for error interrupt */ + if (isr & XCAN_IXR_ERROR_MASK) + cf->can_id |= CAN_ERR_PROT; + + /* Check for Ack error interrupt */ + if (err_status & XCAN_ESR_ACKER_MASK) + cf->can_id |= CAN_ERR_ACK; + + /* Check for Bit error interrupt */ + if (err_status & XCAN_ESR_BERR_MASK) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_BIT; + } + + /* Check for Stuff error interrupt */ + if (err_status & XCAN_ESR_STER_MASK) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_STUFF; + } + + /* Check for Form error interrupt */ + if (err_status & XCAN_ESR_FMER_MASK) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_FORM; + } + + /* Check for CRC error interrupt */ + if (err_status & XCAN_ESR_CRCER_MASK) { + cf->can_id |= CAN_ERR_PROT; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ | + CAN_ERR_PROT_LOC_CRC_DEL; + } + + for (i = 0; i < XCAN_FRAME_MAX_DATA_LEN; ) + if (cf->data[i++] != 0) + cf->can_dlc = i; + netif_rx(skb); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + + priv->write_reg(priv, XCAN_ESR_OFFSET, err_status); + netdev_dbg(ndev, "%s: error status register:0x%x\n", + __func__, priv->read_reg(priv, XCAN_ESR_OFFSET)); +} + +/** + * xcan_state_interrupt - It will check the state of the CAN device + * @ndev: net_device pointer + * @isr: interrupt status register value + * + * This will checks the state of the CAN device + * and puts the device into appropriate state. + */ +static void xcan_state_interrupt(struct net_device *ndev, u32 isr) +{ + struct xcan_priv *priv = netdev_priv(ndev); + + /* Check for Sleep interrupt if set put CAN device in sleep state */ + if (isr & XCAN_IXR_SLP_MASK) + priv->can.state = CAN_STATE_SLEEPING; + + /* Check for Wake up interrupt if set put CAN device in Active state */ + if (isr & XCAN_IXR_WKUP_MASK) + priv->can.state = CAN_STATE_ERROR_ACTIVE; +} + +/** + * xcan_rx_interrupt - Rx Isr + * @ndev: net_device pointer + * + * This is the CAN Rx Isr. It invokes "xcan_rx" to complete the + * received frame processing. + */ +static void xcan_rx_interrupt(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + u32 isr; + + /* FIXME - Need to implement NAPI */ + do { + xcan_rx(ndev); + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK); + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + netdev_dbg(ndev, "received one packet\n"); + } while (isr & XCAN_IXR_RXNEMP_MASK); +} + +/** + * xcan_tx_interrupt - Tx Done Isr + * @ndev: net_device pointer + */ +static void xcan_tx_interrupt(struct net_device *ndev) +{ + unsigned long flags; + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + + stats->tx_packets++; + netdev_dbg(ndev, "%s: waiting total:%d,current:%d\n", __func__, + priv->waiting_ech_skb_num, priv->waiting_ech_skb_index); + + spin_lock_irqsave(&priv->ech_skb_lock, flags); + + if (priv->waiting_ech_skb_num != 0) { + spin_unlock_irqrestore(&priv->ech_skb_lock, flags); + can_get_echo_skb(ndev, priv->waiting_ech_skb_index); + priv->waiting_ech_skb_index = + (priv->waiting_ech_skb_index + 1) % + priv->xcan_echo_skb_max; + spin_lock_irqsave(&priv->ech_skb_lock, flags); + priv->waiting_ech_skb_num--; + } + spin_unlock_irqrestore(&priv->ech_skb_lock, flags); + + netdev_dbg(ndev, "%s: waiting total:%d,current:%d\n", __func__, + priv->waiting_ech_skb_num, priv->waiting_ech_skb_index); + + netif_wake_queue(ndev); + + can_led_event(ndev, CAN_LED_EVENT_TX); +} + +/** + * xcan_interrupt - CAN Isr + * @irq: irq number + * @dev_id: device id poniter + * + * This is the xilinx CAN Isr. It checks for the type of interrupt + * and invokes the corresponding ISR. + * + * Return: + * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise + */ +static irqreturn_t xcan_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct xcan_priv *priv = netdev_priv(ndev); + u32 isr; + + if (priv->can.state == CAN_STATE_STOPPED) + return IRQ_NONE; + + /* Get the interrupt status from Xilinx CAN */ + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + priv->write_reg(priv, XCAN_ICR_OFFSET, isr); + netdev_dbg(ndev, "%s: isr:#x%08x, err:#x%08x\n", __func__, + isr, priv->read_reg(priv, XCAN_ESR_OFFSET)); + + /* Check for the type of interrupt and Processing it */ + if (isr & (XCAN_IXR_SLP_MASK | XCAN_IXR_WKUP_MASK)) + xcan_state_interrupt(ndev, isr); + + /* Check for the type of error interrupt and Processing it */ + if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | + XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) + xcan_err_interrupt(ndev, isr); + + /* Check for Rx interrupt and Processing it */ + if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) + xcan_rx_interrupt(ndev); + + /* Check for Tx interrupt and Processing it */ + if (isr & XCAN_IXR_TXOK_MASK) + xcan_tx_interrupt(ndev); + + return IRQ_HANDLED; +} + +/** + * xcan_open - Driver open routine + * @ndev: Pointer to net_device structure + * + * This is the driver open routine. + * Return: 0 on success and failure value on error + */ +static int xcan_open(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + int err; + + /* Set chip into reset mode */ + err = set_reset_mode(ndev); + if (err < 0) + netdev_err(ndev, "mode resetting failed failed!\n"); + + /* Common open */ + err = open_candev(ndev); + if (err) + return err; + + err = xcan_start(ndev); + if (err < 0) + netdev_err(ndev, "xcan_start failed!\n"); + + priv->open_time = jiffies; + + can_led_event(ndev, CAN_LED_EVENT_OPEN); + netif_start_queue(ndev); + + return 0; +} + +/** + * xcan_close - Driver stop routine + * @ndev: Pointer to net_device structure + * + * Return: 0 on success + */ +static int xcan_close(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + if (set_reset_mode(ndev) < 0) + netdev_err(ndev, "mode resetting failed failed!\n"); + + close_candev(ndev); + + priv->open_time = 0; + + can_led_event(ndev, CAN_LED_EVENT_STOP); + + return 0; +} + +/** + * xcan_get_berr_counter - error counter routine + * @ndev: Pointer to net_device structure + * @bec: Pointer to can_berr_counter structure + * + * This is the driver error counter routine. + * Return: 0 on success + */ +static int xcan_get_berr_counter(const struct net_device *ndev, + struct can_berr_counter *bec) +{ + struct xcan_priv *priv = netdev_priv(ndev); + + bec->txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_REC_MASK; + bec->rxerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK; + netdev_dbg(ndev, "Bus Tx err count=0x%08x,Bus Rx err count=0x%08x\n", + bec->txerr, bec->rxerr); + return 0; +} + +static const struct net_device_ops xcan_netdev_ops = { + .ndo_open = xcan_open, + .ndo_stop = xcan_close, + .ndo_start_xmit = xcan_start_xmit, +}; + +#ifdef CONFIG_PM_SLEEP +/** + * xcan_suspend - Suspend method for the driver + * @_dev: Address of the platform_device structure + * + * Put the driver into low power mode. + * Return: 0 on success + */ +static int xcan_suspend(struct device *_dev) +{ + struct platform_device *pdev = container_of(_dev, + struct platform_device, dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct xcan_priv *priv = netdev_priv(ndev); + + if (netif_running(ndev)) { + netif_stop_queue(ndev); + netif_device_detach(ndev); + } + + priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_SLEEP_MASK); + priv->can.state = CAN_STATE_SLEEPING; + + clk_disable(priv->aperclk); + clk_disable(priv->devclk); + + return 0; +} + +/** + * xcan_resume - Resume from suspend + * @dev: Address of the platformdevice structure + * + * Resume operation after suspend. + * Return: 0 on success + */ +static int xcan_resume(struct device *dev) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct xcan_priv *priv = netdev_priv(ndev); + int ret; + + ret = clk_enable(priv->aperclk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + ret = clk_enable(priv->devclk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + + priv->write_reg(priv, XCAN_MSR_OFFSET, 0); + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + if (netif_running(ndev)) { + netif_device_attach(ndev); + netif_start_queue(ndev); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(xcan_dev_pm_ops, xcan_suspend, xcan_resume); + +/** + * xcan_probe - Platform registration call + * @pdev: Handle to the platform device structure + * + * This function does all the memory allocation and registration for the CAN + * device. + * + * Return: 0 on success and failure value on error + */ +static int xcan_probe(struct platform_device *pdev) +{ + struct resource *res; /* IO mem resources */ + struct net_device *ndev; + struct xcan_priv *priv; + struct device *dev = &pdev->dev; + int ret, irq; + + /* Create a CAN device instance */ + ndev = alloc_candev(sizeof(struct xcan_priv), XCAN_ECHO_SKB_MAX); + if (!ndev) + return -ENOMEM; + + priv = netdev_priv(ndev); + priv->dev = ndev; + priv->can.bittiming_const = &xcan_bittiming_const; + priv->can.do_set_bittiming = xcan_set_bittiming; + priv->can.do_set_mode = xcan_do_set_mode; + priv->can.do_get_berr_counter = xcan_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK; + priv->waiting_ech_skb_index = 0; + priv->ech_skb_next = 0; + priv->waiting_ech_skb_num = 0; + priv->xcan_echo_skb_max = XCAN_ECHO_SKB_MAX; + + /* Get IRQ for the device */ + ndev->irq = platform_get_irq(pdev, 0); + irq = devm_request_irq(&pdev->dev, ndev->irq, &xcan_interrupt, + priv->irq_flags, dev_name(&pdev->dev), + (void *)ndev); + if (irq < 0) { + ret = irq; + dev_err(&pdev->dev, "Irq allocation for CAN failed\n"); + goto err_free; + } + + spin_lock_init(&priv->ech_skb_lock); + ndev->flags |= IFF_ECHO; /* We support local echo */ + + platform_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + ndev->netdev_ops = &xcan_netdev_ops; + + /* Get the virtual base address for the device */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->reg_base)) { + ret = PTR_ERR(priv->reg_base); + goto err_free; + } + ndev->mem_start = res->start; + ndev->mem_end = res->end; + + priv->write_reg = xcan_write_reg; + priv->read_reg = xcan_read_reg; + + /* Getting the CAN devclk info */ + priv->devclk = devm_clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(priv->devclk)) { + dev_err(&pdev->dev, "Device clock not found.\n"); + ret = PTR_ERR(priv->devclk); + goto err_free; + } + + /* Check for type of CAN device */ + if (of_device_is_compatible(pdev->dev.of_node, "xlnx,ps7-can")) { + priv->aperclk = devm_clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(priv->aperclk)) { + dev_err(&pdev->dev, "aper clock not found\n"); + ret = PTR_ERR(priv->aperclk); + goto err_free; + } + } else { + priv->aperclk = priv->devclk; + } + + ret = clk_prepare_enable(priv->devclk); + if (ret) { + dev_err(&pdev->dev, "unable to enable device clock\n"); + goto err_free; + } + + ret = clk_prepare_enable(priv->aperclk); + if (ret) { + dev_err(&pdev->dev, "unable to enable aper clock\n"); + goto err_unprepar_disabledev; + } + + priv->can.clock.freq = clk_get_rate(priv->devclk); + + ret = register_candev(ndev); + if (ret) { + dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret); + goto err_unprepar_disableaper; + } + + dev_info(&pdev->dev, + "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n", + priv->reg_base, ndev->irq, priv->can.clock.freq, + priv->xcan_echo_skb_max); + + return 0; + +err_unprepar_disableaper: + clk_disable_unprepare(priv->aperclk); +err_unprepar_disabledev: + clk_disable_unprepare(priv->devclk); +err_free: + free_candev(ndev); + + return ret; +} + +/** + * xcan_remove - Unregister the device after releasing the resources + * @pdev: Handle to the platform device structure + * + * This function frees all the resources allocated to the device. + * Return: 0 on success + */ +static int xcan_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct xcan_priv *priv = netdev_priv(ndev); + + if (set_reset_mode(ndev) < 0) + netdev_err(ndev, "mode resetting failed!\n"); + + unregister_candev(ndev); + clk_disable_unprepare(priv->aperclk); + clk_disable_unprepare(priv->devclk); + + free_candev(ndev); + + return 0; +} + +/* Match table for OF platform binding */ +static struct of_device_id xcan_of_match[] = { + { .compatible = "xlnx,ps7-can", }, + { .compatible = "xlnx,axi-can-1.00.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, xcan_of_match); + +static struct platform_driver xcan_driver = { + .probe = xcan_probe, + .remove = xcan_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .pm = &xcan_dev_pm_ops, + .of_match_table = xcan_of_match, + }, +}; + +module_platform_driver(xcan_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Xilinx Inc"); +MODULE_DESCRIPTION("Xilinx CAN interface"); Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/cadence/macb.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/cadence/macb.c 2014-07-20 22:05:50.252066357 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/cadence/macb.c 2014-07-20 22:06:36.965295673 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:20 @ #include <linux/circ_buf.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/netdevice.h> @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:207 @ return 0; } +/** + * macb_set_tx_clk() - Set a clock to a new frequency + * @clk Pointer to the clock to change + * @rate New frequency in Hz + * @dev Pointer to the struct net_device + */ +static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) +{ + long ferr, rate, rate_rounded; + + switch (speed) { + case SPEED_10: + rate = 2500000; + break; + case SPEED_100: + rate = 25000000; + break; + case SPEED_1000: + rate = 125000000; + break; + default: + return; + } + + rate_rounded = clk_round_rate(clk, rate); + if (rate_rounded < 0) + return; + + /* RGMII allows 50 ppm frequency error. Test and warn if this limit + * is not satisfied. + */ + ferr = abs(rate_rounded - rate); + ferr = DIV_ROUND_UP(ferr, rate / 100000); + if (ferr > 5) + netdev_warn(dev, "unable to generate target frequency: %ld Hz\n", + rate); + + if (clk_set_rate(clk, rate_rounded)) + netdev_err(dev, "adjusting tx_clk failed.\n"); +} + static void macb_handle_link_change(struct net_device *dev) { struct macb *bp = netdev_priv(dev); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:295 @ spin_unlock_irqrestore(&bp->lock, flags); + if (!IS_ERR(bp->tx_clk)) + macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); + if (status_change) { if (phydev->link) { netif_carrier_on(dev); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1838 @ spin_lock_init(&bp->lock); INIT_WORK(&bp->tx_error_task, macb_tx_error_task); - bp->pclk = clk_get(&pdev->dev, "pclk"); + bp->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(bp->pclk)) { - dev_err(&pdev->dev, "failed to get macb_clk\n"); + err = PTR_ERR(bp->pclk); + dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err); goto err_out_free_dev; } - clk_prepare_enable(bp->pclk); - bp->hclk = clk_get(&pdev->dev, "hclk"); + bp->hclk = devm_clk_get(&pdev->dev, "hclk"); if (IS_ERR(bp->hclk)) { - dev_err(&pdev->dev, "failed to get hclk\n"); - goto err_out_put_pclk; + err = PTR_ERR(bp->hclk); + dev_err(&pdev->dev, "failed to get hclk (%u)\n", err); + goto err_out_free_dev; + } + + bp->tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); + + err = clk_prepare_enable(bp->pclk); + if (err) { + dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); + goto err_out_free_dev; + } + + err = clk_prepare_enable(bp->hclk); + if (err) { + dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err); + goto err_out_disable_pclk; + } + + if (!IS_ERR(bp->tx_clk)) { + err = clk_prepare_enable(bp->tx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", + err); + goto err_out_disable_hclk; + } } - clk_prepare_enable(bp->hclk); - bp->regs = ioremap(regs->start, resource_size(regs)); + bp->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); if (!bp->regs) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); err = -ENOMEM; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1883 @ } dev->irq = platform_get_irq(pdev, 0); - err = request_irq(dev->irq, macb_interrupt, 0, dev->name, dev); + err = devm_request_irq(&pdev->dev, dev->irq, macb_interrupt, 0, + dev->name, dev); if (err) { dev_err(&pdev->dev, "Unable to request IRQ %d (error %d)\n", dev->irq, err); - goto err_out_iounmap; + goto err_out_disable_clocks; } dev->netdev_ops = &macb_netdev_ops; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1951 @ err = register_netdev(dev); if (err) { dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); - goto err_out_free_irq; + goto err_out_disable_clocks; } err = macb_mii_init(bp); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1974 @ err_out_unregister_netdev: unregister_netdev(dev); -err_out_free_irq: - free_irq(dev->irq, dev); -err_out_iounmap: - iounmap(bp->regs); err_out_disable_clocks: + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); +err_out_disable_hclk: clk_disable_unprepare(bp->hclk); - clk_put(bp->hclk); +err_out_disable_pclk: clk_disable_unprepare(bp->pclk); -err_out_put_pclk: - clk_put(bp->pclk); err_out_free_dev: free_netdev(dev); err_out: @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2002 @ kfree(bp->mii_bus->irq); mdiobus_free(bp->mii_bus); unregister_netdev(dev); - free_irq(dev->irq, dev); - iounmap(bp->regs); + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); clk_disable_unprepare(bp->hclk); - clk_put(bp->hclk); clk_disable_unprepare(bp->pclk); - clk_put(bp->pclk); free_netdev(dev); } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2013 @ } #ifdef CONFIG_PM -static int macb_suspend(struct platform_device *pdev, pm_message_t state) +static int macb_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); struct macb *bp = netdev_priv(netdev); netif_carrier_off(netdev); netif_device_detach(netdev); + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); return 0; } -static int macb_resume(struct platform_device *pdev) +static int macb_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); struct macb *bp = netdev_priv(netdev); clk_prepare_enable(bp->pclk); clk_prepare_enable(bp->hclk); + if (!IS_ERR(bp->tx_clk)) + clk_prepare_enable(bp->tx_clk); netif_device_attach(netdev); return 0; } -#else -#define macb_suspend NULL -#define macb_resume NULL #endif +static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); + static struct platform_driver macb_driver = { .remove = __exit_p(macb_remove), - .suspend = macb_suspend, - .resume = macb_resume, .driver = { .name = "macb", .owner = THIS_MODULE, .of_match_table = of_match_ptr(macb_dt_ids), + .pm = &macb_pm_ops, }, }; Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/cadence/macb.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/cadence/macb.h 2014-07-20 22:05:50.251066373 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/cadence/macb.h 2014-07-20 22:06:36.979295442 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:575 @ struct platform_device *pdev; struct clk *pclk; struct clk *hclk; + struct clk *tx_clk; struct net_device *dev; struct napi_struct napi; struct work_struct tx_error_task; Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/xilinx/Kconfig 2014-07-20 22:05:50.257066275 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/Kconfig 2014-07-20 22:06:37.007294980 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:30 @ config XILINX_AXI_EMAC tristate "Xilinx 10/100/1000 AXI Ethernet support" - depends on MICROBLAZE + depends on (MICROBLAZE || ARCH_ZYNQ) select PHYLIB ---help--- This driver supports the 10/100/1000 Ethernet from Xilinx for the AXI bus interface used in Xilinx Virtex FPGAs. -config XILINX_LL_TEMAC - tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" - depends on (PPC || MICROBLAZE) +#config XILINX_LL_TEMAC +# tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" +# depends on (PPC || MICROBLAZE) +# select PHYLIB +# ---help--- +# This driver supports the Xilinx 10/100/1000 LocalLink TEMAC +# core used in Xilinx Spartan and Virtex FPGAs + +config XILINX_LLTEMAC + tristate "Xilinx LLTEMAC 10/100/1000 Ethernet MAC driver" + depends on XILINX_DRIVERS + select XILINX_EDK + select NEED_XILINX_LLDMA + help + This driver supports the 10/100/1000 LLTEMAC. + +choice + prompt "Xilinx LLTEMAC PHY Support" + depends on XILINX_LLTEMAC + default XILINX_LLTEMAC_MARVELL_88E1111_GMII + +config XILINX_LLTEMAC_MARVELL_88E1111_RGMII + bool "MARVELL 88E1111 using RGMII" + help + This phy is used by many Xilinx boards. This option includes + code for enabling RGMII over copper. + +config XILINX_LLTEMAC_MARVELL_88E1111_GMII + bool "MARVELL 88E1111 using GMII" + help + This phy is used by many Xilinx boards. This option includes + code for enabling GMII over copper, and for setting the correct + speed based on whatever the phy is able to autonegotiate. This is + usually the best option to use on ML40x and ML50x boards. + +config XILINX_LLTEMAC_MARVELL_88E1111_MII + bool "MARVELL 88E1111 using MII or other PHY" + help + If your physical interface is not covered by the other + selections, then choose this option. This option includes generic + speed autonegotation code. + +config XILINX_LLTEMAC_XILINX_1000BASEX + bool "Xilinx 1000BASE-X PHY" + help + This PHY supports physical attachment via GT/GTP/GTX transceivers. + +endchoice + +config XILINX_PS_EMAC + tristate "Xilinx PS tri-speed EMAC support" + depends on ARCH_ZYNQ select PHYLIB ---help--- - This driver supports the Xilinx 10/100/1000 LocalLink TEMAC - core used in Xilinx Spartan and Virtex FPGAs + This driver supports tri-speed EMAC. + +config XILINX_PS_EMAC_HWTSTAMP + bool "Generate hardware packet timestamps" + depends on XILINX_PS_EMAC + default n + ---help--- + Generate hardare packet timestamps. This is to facilitate IEE 1588. + endif # NET_VENDOR_XILINX Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/ll_temac_main.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/xilinx/ll_temac_main.c 2014-07-20 22:05:50.253066340 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/ll_temac_main.c 2014-07-20 22:06:37.021294749 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:687 @ skb_frag_t *frag; num_frag = skb_shinfo(skb)->nr_frags; - frag = &skb_shinfo(skb)->frags[0]; start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; if (temac_check_tx_bd_space(lp, num_frag)) { - if (!netif_queue_stopped(ndev)) { + if (!netif_queue_stopped(ndev)) netif_stop_queue(ndev); - return NETDEV_TX_BUSY; - } return NETDEV_TX_BUSY; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:708 @ cur_p->app0 |= STS_CTRL_APP0_SOP; cur_p->len = skb_headlen(skb); - cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, - DMA_TO_DEVICE); + cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); cur_p->app4 = (unsigned long)skb; for (ii = 0; ii < num_frag; ii++) { + frag = &skb_shinfo(skb)->frags[ii]; lp->tx_bd_tail++; if (lp->tx_bd_tail >= TX_BD_NUM) lp->tx_bd_tail = 0; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:724 @ skb_frag_size(frag), DMA_TO_DEVICE); cur_p->len = skb_frag_size(frag); cur_p->app0 = 0; - frag++; } cur_p->app0 |= STS_CTRL_APP0_EOP; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1051 @ /* Setup checksum offload, but default to off if not specified */ lp->temac_features = 0; p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL); + dev_info(&op->dev, "TX_CSUM %d\n", be32_to_cpup(p)); if (p && be32_to_cpu(*p)) { lp->temac_features |= TEMAC_FEATURE_TX_CSUM; /* Can checksum TCP/UDP over IPv4. */ ndev->features |= NETIF_F_IP_CSUM; } p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL); + dev_info(&op->dev, "RX_CSUM %d\n", be32_to_cpup(p)); if (p && be32_to_cpu(*p)) lp->temac_features |= TEMAC_FEATURE_RX_CSUM; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1106 @ } temac_init_mac_address(ndev, (void *)addr); - rc = temac_mdio_setup(lp, op->dev.of_node); - if (rc) - dev_warn(&op->dev, "error registering MDIO bus\n"); - lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0); - if (lp->phy_node) + if (lp->phy_node) { dev_dbg(lp->dev, "using PHY node %s (%p)\n", np->full_name, np); + rc = temac_mdio_setup(lp, op->dev.of_node); + if (rc) + dev_warn(&op->dev, "error registering MDIO bus\n"); + } + /* Add the device attributes */ rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group); if (rc) { Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/ll_temac_mdio.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/xilinx/ll_temac_mdio.c 2014-07-20 22:05:50.259066241 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/ll_temac_mdio.c 2014-07-20 22:06:37.031294584 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:66 @ int clk_div; int rc, size; struct resource res; + struct device_node *np1 = of_get_parent(lp->phy_node); /* Calculate a reasonable divisor for the clock rate */ clk_div = 0x3f; /* worst-case default setting */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:89 @ if (!bus) return -ENOMEM; - of_address_to_resource(np, 0, &res); + of_address_to_resource(np1, 0, &res); snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", (unsigned long long)res.start); bus->priv = lp; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:101 @ lp->mii_bus = bus; - rc = of_mdiobus_register(bus, np); + rc = of_mdiobus_register(bus, np1); if (rc) goto err_register; Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/xilinx/Makefile 2014-07-20 22:05:50.255066308 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/Makefile 2014-07-20 22:06:37.041294419 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:8 @ ll_temac-objs := ll_temac_main.o ll_temac_mdio.o obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o +obj-$(CONFIG_XILINX_PS_EMAC) += xilinx_emacps.o xilinx_emac-objs := xilinx_axienet_main.o xilinx_axienet_mdio.o obj-$(CONFIG_XILINX_AXI_EMAC) += xilinx_emac.o + +obj-$(CONFIG_XILINX_LLTEMAC) += xilinx_lltemac/ Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_axienet.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/xilinx/xilinx_axienet.h 2014-07-20 22:05:50.261066208 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_axienet.h 2014-07-20 22:06:37.054294205 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:12 @ #define XILINX_AXIENET_H #include <linux/netdevice.h> +#include <linux/of_irq.h> #include <linux/spinlock.h> #include <linux/interrupt.h> +#include <linux/if_vlan.h> /* Packet size info */ #define XAE_HDR_SIZE 14 /* Size of Ethernet header */ -#define XAE_HDR_VLAN_SIZE 18 /* Size of an Ethernet hdr + VLAN */ #define XAE_TRL_SIZE 4 /* Size of Ethernet trailer (FCS) */ #define XAE_MTU 1500 /* Max MTU of an Ethernet frame */ #define XAE_JUMBO_MTU 9000 /* Max MTU of a jumbo Eth. frame */ #define XAE_MAX_FRAME_SIZE (XAE_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE) -#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + XAE_HDR_VLAN_SIZE + XAE_TRL_SIZE) +#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + VLAN_ETH_HLEN + XAE_TRL_SIZE) #define XAE_MAX_JUMBO_FRAME_SIZE (XAE_JUMBO_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE) /* Configuration options */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:341 @ #define DELAY_OF_ONE_MILLISEC 1000 +/* Read/Write access to the registers */ +#ifndef out_be32 +#ifdef CONFIG_ARCH_ZYNQ +#define in_be32(offset) __raw_readl(offset) +#define out_be32(offset, val) __raw_writel(val, offset) +#endif +#endif + /** * struct axidma_bd - Axi Dma buffer descriptor layout * @next: MM2S/S2MM Next Descriptor Pointer @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:460 @ u32 rx_bd_ci; u32 max_frm_size; - u32 jumbo_support; + u32 rxmem; int csum_offload_on_tx_path; int csum_offload_on_rx_path; Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_axienet_main.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/xilinx/xilinx_axienet_main.c 2014-07-20 22:05:50.260066225 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_axienet_main.c 2014-07-20 22:06:37.076293842 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:266 @ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); /* Populate the tail pointer and bring the Rx Axi DMA engine out of - * halted state. This will make the Rx side ready for reception.*/ + * halted state. This will make the Rx side ready for reception. + */ axienet_dma_out32(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p); cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:277 @ /* Write to the RS (Run-stop) bit in the Tx channel control register. * Tx channel is now ready to run. But only after we write to the - * tail pointer register that the Tx channel will start transmitting */ + * tail pointer register that the Tx channel will start transmitting. + */ axienet_dma_out32(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p); cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:359 @ netdev_mc_count(ndev) > XAE_MULTICAST_CAM_TABLE_NUM) { /* We must make the kernel realize we had to move into * promiscuous mode. If it was a promiscuous mode request - * the flag is already set. If not we set it. */ + * the flag is already set. If not we set it. + */ ndev->flags |= IFF_PROMISC; reg = axienet_ior(lp, XAE_FMI_OFFSET); reg |= XAE_FMI_PM_MASK; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:444 @ /* Reset Axi DMA. This would reset Axi Ethernet core as well. The reset * process of Axi DMA takes a while to complete as all pending * commands/transfers will be flushed or completed during this - * reset process. */ + * reset process. + */ axienet_dma_out32(lp, offset, XAXIDMA_CR_RESET_MASK); timeout = DELAY_OF_ONE_MILLISEC; while (axienet_dma_in32(lp, offset) & XAXIDMA_CR_RESET_MASK) { udelay(1); if (--timeout == 0) { - dev_err(dev, "axienet_device_reset DMA " - "reset timeout!\n"); + dev_err(dev, + "axienet_device_reset DMA reset timeout!\n"); break; } } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:478 @ __axienet_device_reset(lp, &ndev->dev, XAXIDMA_RX_CR_OFFSET); lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE; + lp->options |= XAE_OPTION_VLAN; lp->options &= (~XAE_OPTION_JUMBO); if ((ndev->mtu > XAE_MTU) && - (ndev->mtu <= XAE_JUMBO_MTU) && - (lp->jumbo_support)) { - lp->max_frm_size = ndev->mtu + XAE_HDR_VLAN_SIZE + - XAE_TRL_SIZE; - lp->options |= XAE_OPTION_JUMBO; + (ndev->mtu <= XAE_JUMBO_MTU)) { + lp->max_frm_size = ndev->mtu + VLAN_ETH_HLEN + + XAE_TRL_SIZE; + + if (lp->max_frm_size <= lp->rxmem) + lp->options |= XAE_OPTION_JUMBO; } if (axienet_dma_bd_init(ndev)) { - dev_err(&ndev->dev, "axienet_device_reset descriptor " + dev_err(&ndev->dev, + "axienet_device_reset descriptor " "allocation failed\n"); } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:507 @ axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK); /* Sync default options with HW but leave receiver and - * transmitter disabled.*/ + * transmitter disabled. + */ axienet_setoptions(ndev, lp->options & ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); axienet_set_mac_address(ndev, NULL); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:560 @ emmc_reg |= XAE_EMMC_LINKSPD_10; break; default: - dev_err(&ndev->dev, "Speed other than 10, 100 " + dev_err(&ndev->dev, + "Speed other than 10, 100 " "or 1Gbps is not supported\n"); break; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:570 @ lp->last_link = link_state; phy_print_status(phy); } else { - dev_err(&ndev->dev, "Error setting Axi Ethernet " - "mac speed\n"); + dev_err(&ndev->dev, + "Error setting Axi Ethernet mac speed\n"); } } } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:613 @ size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; packets++; - lp->tx_bd_ci = ++lp->tx_bd_ci % TX_BD_NUM; + ++lp->tx_bd_ci; + lp->tx_bd_ci %= TX_BD_NUM; cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; status = cur_p->status; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:700 @ skb_headlen(skb), DMA_TO_DEVICE); for (ii = 0; ii < num_frag; ii++) { - lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM; + ++lp->tx_bd_tail; + lp->tx_bd_tail %= TX_BD_NUM; cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; frag = &skb_shinfo(skb)->frags[ii]; cur_p->phys = dma_map_single(ndev->dev.parent, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:715 @ cur_p->app4 = (unsigned long)skb; tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; + wmb(); + /* Start the transfer */ axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p); - lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM; + ++lp->tx_bd_tail; + lp->tx_bd_tail %= TX_BD_NUM; return NETDEV_TX_OK; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:740 @ u32 csumstatus; u32 size = 0; u32 packets = 0; - dma_addr_t tail_p; + dma_addr_t tail_p = 0; struct axienet_local *lp = netdev_priv(ndev); struct sk_buff *skb, *new_skb; struct axidma_bd *cur_p; - tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; + rmb(); cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) { + tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; skb = (struct sk_buff *) (cur_p->sw_id_offset); length = cur_p->app4 & 0x0000FFFF; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:793 @ cur_p->status = 0; cur_p->sw_id_offset = (u32) new_skb; - lp->rx_bd_ci = ++lp->rx_bd_ci % RX_BD_NUM; + ++lp->rx_bd_ci; + lp->rx_bd_ci %= RX_BD_NUM; cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; } ndev->stats.rx_packets += packets; ndev->stats.rx_bytes += size; - axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p); + if (tail_p) + axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p); } /** @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:824 @ status = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET); if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) { + axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status); axienet_start_xmit_done(lp->ndev); goto out; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:848 @ axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr); tasklet_schedule(&lp->dma_err_tasklet); + axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status); } out: - axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status); return IRQ_HANDLED; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:873 @ status = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET); if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) { + axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status); axienet_recv(lp->ndev); goto out; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:897 @ axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr); tasklet_schedule(&lp->dma_err_tasklet); + axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status); } out: - axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status); return IRQ_HANDLED; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:932 @ /* Disable the MDIO interface till Axi Ethernet Reset is completed. * When we do an Axi Ethernet reset, it resets the complete core * including the MDIO. If MDIO is not disabled when the reset - * process is started, MDIO will be broken afterwards. */ + * process is started, MDIO will be broken afterwards. + */ axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK))); axienet_device_reset(ndev); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:944 @ return ret; if (lp->phy_node) { - lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, + if (lp->phy_type == XAE_PHY_TYPE_GMII) { + lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, axienet_adjust_link, 0, PHY_INTERFACE_MODE_GMII); - if (!lp->phy_dev) { - dev_err(lp->dev, "of_phy_connect() failed\n"); - return -ENODEV; + } else if (lp->phy_type == XAE_PHY_TYPE_RGMII_2_0) { + lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, + axienet_adjust_link, 0, + PHY_INTERFACE_MODE_RGMII_ID); } - phy_start(lp->phy_dev); + + if (!lp->phy_dev) + dev_err(lp->dev, "of_phy_connect() failed\n"); + else + phy_start(lp->phy_dev); } /* Enable tasklets for Axi DMA error handling */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1042 @ if (netif_running(ndev)) return -EBUSY; - if (lp->jumbo_support) { - if ((new_mtu > XAE_JUMBO_MTU) || (new_mtu < 64)) - return -EINVAL; - ndev->mtu = new_mtu; - } else { - if ((new_mtu > XAE_MTU) || (new_mtu < 64)) - return -EINVAL; - ndev->mtu = new_mtu; - } + + if ((new_mtu + VLAN_ETH_HLEN + + XAE_TRL_SIZE) > lp->rxmem) + return -EINVAL; + + if ((new_mtu > XAE_JUMBO_MTU) || (new_mtu < 64)) + return -EINVAL; + + ndev->mtu = new_mtu; return 0; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1075 @ } #endif +/* Ioctl MII Interface */ +static int axienet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct axienet_local *priv = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + if (!priv->phy_dev) + return -EOPNOTSUPP; + + return phy_mii_ioctl(priv->phy_dev, rq, cmd); +} + static const struct net_device_ops axienet_netdev_ops = { .ndo_open = axienet_open, .ndo_stop = axienet_stop, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1097 @ .ndo_set_mac_address = netdev_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = axienet_set_multicast_list, + .ndo_do_ioctl = axienet_ioctl, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = axienet_poll_controller, #endif @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1253 @ * axienet_ethtools_set_pauseparam - Set device pause parameter(flow control) * settings. * @ndev: Pointer to net_device structure - * @epauseparam:Pointer to ethtool_pauseparam structure + * @epauseparm:Pointer to ethtool_pauseparam structure * * This implements ethtool command for enabling flow control on Rx and Tx * paths. Issue "ethtool -A ethX tx on|off" under linux prompt to execute this @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1267 @ struct axienet_local *lp = netdev_priv(ndev); if (netif_running(ndev)) { - printk(KERN_ERR "%s: Please stop netif before applying " - "configruation\n", ndev->name); + dev_err(&ndev->dev, + "%s: Please stop netif before applying configuration\n", + ndev->name); return -EFAULT; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1325 @ struct axienet_local *lp = netdev_priv(ndev); if (netif_running(ndev)) { - printk(KERN_ERR "%s: Please stop netif before applying " - "configruation\n", ndev->name); + dev_err(&ndev->dev, + "%s: Please stop netif before applying configuration\n", + ndev->name); return -EFAULT; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1396 @ /* Disable the MDIO interface till Axi Ethernet Reset is completed. * When we do an Axi Ethernet reset, it resets the complete core * including the MDIO. So if MDIO is not disabled when the reset - * process is started, MDIO will be broken afterwards. */ + * process is started, MDIO will be broken afterwards. + */ axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg & ~XAE_MDIO_MC_MDIOEN_MASK)); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1468 @ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); /* Populate the tail pointer and bring the Rx Axi DMA engine out of - * halted state. This will make the Rx side ready for reception.*/ + * halted state. This will make the Rx side ready for reception. + */ axienet_dma_out32(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p); cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1479 @ /* Write to the RS (Run-stop) bit in the Tx channel control register. * Tx channel is now ready to run. But only after we write to the - * tail pointer register that the Tx channel will start transmitting */ + * tail pointer register that the Tx channel will start transmitting + */ axienet_dma_out32(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p); cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1496 @ axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK); /* Sync default options with HW but leave receiver and - * transmitter disabled.*/ + * transmitter disabled. + */ axienet_setoptions(ndev, lp->options & ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); axienet_set_mac_address(ndev, NULL); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1506 @ } /** - * axienet_of_probe - Axi Ethernet probe function. - * @op: Pointer to platform device structure. - * @match: Pointer to device id structure + * axienet_probe - Axi Ethernet probe function. + * @pdev: Pointer to platform device structure. * * returns: 0, on success * Non-zero error value on failure. @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1517 @ * device. Parses through device tree and populates fields of * axienet_local. It registers the Ethernet device. */ -static int axienet_of_probe(struct platform_device *op) +static int axienet_probe(struct platform_device *pdev) { - __be32 *p; - int size, ret = 0; + int ret; struct device_node *np; struct axienet_local *lp; struct net_device *ndev; - const void *addr; + u8 mac_addr[6]; + struct resource *ethres, dmares; + u32 value; ndev = alloc_etherdev(sizeof(*lp)); if (!ndev) return -ENOMEM; ether_setup(ndev); - platform_set_drvdata(op, ndev); + platform_set_drvdata(pdev, ndev); - SET_NETDEV_DEV(ndev, &op->dev); + SET_NETDEV_DEV(ndev, &pdev->dev); ndev->flags &= ~IFF_MULTICAST; /* clear multicast */ ndev->features = NETIF_F_SG; ndev->netdev_ops = &axienet_netdev_ops; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1542 @ lp = netdev_priv(ndev); lp->ndev = ndev; - lp->dev = &op->dev; + lp->dev = &pdev->dev; lp->options = XAE_OPTION_DEFAULTS; /* Map device registers */ - lp->regs = of_iomap(op->dev.of_node, 0); + ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lp->regs = devm_ioremap_resource(&pdev->dev, ethres); if (!lp->regs) { - dev_err(&op->dev, "could not map Axi Ethernet regs.\n"); - goto nodev; + dev_err(&pdev->dev, "could not map Axi Ethernet regs.\n"); + ret = -ENOMEM; + goto free_netdev; } + /* Setup checksum offload, but default to off if not specified */ lp->features = 0; - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,txcsum", NULL); - if (p) { - switch (be32_to_cpup(p)) { + ret = of_property_read_u32(pdev->dev.of_node, "xlnx,txcsum", &value); + if (!ret) { + dev_info(&pdev->dev, "TX_CSUM %d\n", value); + + switch (value) { case 1: lp->csum_offload_on_tx_path = XAE_FEATURE_PARTIAL_TX_CSUM; lp->features |= XAE_FEATURE_PARTIAL_TX_CSUM; /* Can checksum TCP/UDP over IPv4. */ - ndev->features |= NETIF_F_IP_CSUM; + ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; break; case 2: lp->csum_offload_on_tx_path = XAE_FEATURE_FULL_TX_CSUM; lp->features |= XAE_FEATURE_FULL_TX_CSUM; /* Can checksum TCP/UDP over IPv4. */ - ndev->features |= NETIF_F_IP_CSUM; + ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; break; default: lp->csum_offload_on_tx_path = XAE_NO_CSUM_OFFLOAD; } } - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL); - if (p) { - switch (be32_to_cpup(p)) { + ret = of_property_read_u32(pdev->dev.of_node, "xlnx,rxcsum", &value); + if (!ret) { + dev_info(&pdev->dev, "RX_CSUM %d\n", value); + + switch (value) { case 1: lp->csum_offload_on_rx_path = XAE_FEATURE_PARTIAL_RX_CSUM; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1599 @ } } /* For supporting jumbo frames, the Axi Ethernet hardware must have - * a larger Rx/Tx Memory. Typically, the size must be more than or - * equal to 16384 bytes, so that we can enable jumbo option and start - * supporting jumbo frames. Here we check for memory allocated for - * Rx/Tx in the hardware from the device-tree and accordingly set - * flags. */ - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,rxmem", NULL); - if (p) { - if ((be32_to_cpup(p)) >= 0x4000) - lp->jumbo_support = 1; - } - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,temac-type", - NULL); - if (p) - lp->temac_type = be32_to_cpup(p); - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,phy-type", NULL); - if (p) - lp->phy_type = be32_to_cpup(p); + * a larger Rx/Tx Memory. Typically, the size must be large so that + * we can enable jumbo option and start supporting jumbo frames. + * Here we check for memory allocated for Rx/Tx in the hardware from + * the device-tree and accordingly set flags. + */ + of_property_read_u32(pdev->dev.of_node, "xlnx,rxmem", &lp->rxmem); + of_property_read_u32(pdev->dev.of_node, "xlnx,temac-type", + &lp->temac_type); + of_property_read_u32(pdev->dev.of_node, "xlnx,phy-type", &lp->phy_type); /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ - np = of_parse_phandle(op->dev.of_node, "axistream-connected", 0); - if (!np) { - dev_err(&op->dev, "could not find DMA node\n"); - goto err_iounmap; - } - lp->dma_regs = of_iomap(np, 0); - if (lp->dma_regs) { - dev_dbg(&op->dev, "MEM base: %p\n", lp->dma_regs); - } else { - dev_err(&op->dev, "unable to map DMA registers\n"); - of_node_put(np); + np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0); + if (IS_ERR(np)) { + dev_err(&pdev->dev, "could not find DMA node\n"); + ret = PTR_ERR(np); + goto free_netdev; + } + ret = of_address_to_resource(np, 0, &dmares); + if (ret) { + dev_err(&pdev->dev, "unable to get DMA resource\n"); + goto free_netdev; + } + lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares); + if (!lp->dma_regs) { + dev_err(&pdev->dev, "could not map DMA regs\n"); + ret = -ENOMEM; + goto free_netdev; } lp->rx_irq = irq_of_parse_and_map(np, 1); lp->tx_irq = irq_of_parse_and_map(np, 0); of_node_put(np); if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) { - dev_err(&op->dev, "could not determine irqs\n"); + dev_err(&pdev->dev, "could not determine irqs\n"); ret = -ENOMEM; - goto err_iounmap_2; + goto free_netdev; } /* Retrieve the MAC address */ - addr = of_get_property(op->dev.of_node, "local-mac-address", &size); - if ((!addr) || (size != 6)) { - dev_err(&op->dev, "could not find MAC address\n"); - ret = -ENODEV; - goto err_iounmap_2; + ret = of_property_read_u8_array(pdev->dev.of_node, + "local-mac-address", mac_addr, 6); + if (ret) { + dev_err(&pdev->dev, "could not find MAC address\n"); + goto free_netdev; } - axienet_set_mac_address(ndev, (void *) addr); + axienet_set_mac_address(ndev, (void *) mac_addr); lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD; lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD; - lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0); - ret = axienet_mdio_setup(lp, op->dev.of_node); - if (ret) - dev_warn(&op->dev, "error registering MDIO bus\n"); + lp->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); + if (lp->phy_node) { + ret = axienet_mdio_setup(lp, pdev->dev.of_node); + if (ret) + dev_warn(&pdev->dev, "error registering MDIO bus\n"); + } ret = register_netdev(lp->ndev); if (ret) { dev_err(lp->dev, "register_netdev() error (%i)\n", ret); - goto err_iounmap_2; + goto free_netdev; } return 0; -err_iounmap_2: - if (lp->dma_regs) - iounmap(lp->dma_regs); -err_iounmap: - iounmap(lp->regs); -nodev: +free_netdev: free_netdev(ndev); - ndev = NULL; + return ret; } -static int axienet_of_remove(struct platform_device *op) +static int axienet_remove(struct platform_device *pdev) { - struct net_device *ndev = platform_get_drvdata(op); + struct net_device *ndev = platform_get_drvdata(pdev); struct axienet_local *lp = netdev_priv(ndev); axienet_mdio_teardown(lp); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1681 @ of_node_put(lp->phy_node); lp->phy_node = NULL; - iounmap(lp->regs); - if (lp->dma_regs) - iounmap(lp->dma_regs); free_netdev(ndev); return 0; } -static struct platform_driver axienet_of_driver = { - .probe = axienet_of_probe, - .remove = axienet_of_remove, +static struct platform_driver axienet_driver = { + .probe = axienet_probe, + .remove = axienet_remove, .driver = { .owner = THIS_MODULE, .name = "xilinx_axienet", @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1696 @ }, }; -module_platform_driver(axienet_of_driver); +module_platform_driver(axienet_driver); MODULE_DESCRIPTION("Xilinx Axi Ethernet driver"); MODULE_AUTHOR("Xilinx"); Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c 2014-07-20 22:05:50.258066258 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c 2014-07-20 22:06:37.088293644 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:131 @ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np) { int ret; - u32 clk_div, host_clock; - u32 *property_p; + u32 clk_div; struct mii_bus *bus; struct resource res; struct device_node *np1; + /* the ethernet controller device node */ + struct device_node *npp = NULL; /* clk_div can be calculated by deriving it from the equation: * fMDIO = fHOST / ((1 + clk_div) * 2) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:162 @ * fHOST can be read from the flattened device tree as property * "clock-frequency" from the CPU */ - - np1 = of_find_node_by_name(NULL, "cpu"); - if (!np1) { - printk(KERN_WARNING "%s(): Could not find CPU device node.", - __func__); - printk(KERN_WARNING "Setting MDIO clock divisor to " - "default %d\n", DEFAULT_CLOCK_DIVISOR); - clk_div = DEFAULT_CLOCK_DIVISOR; - goto issue; + np1 = of_get_parent(lp->phy_node); + if (np1) { + npp = of_get_parent(np1); + of_node_put(np1); } - property_p = (u32 *) of_get_property(np1, "clock-frequency", NULL); - if (!property_p) { - printk(KERN_WARNING "%s(): Could not find CPU property: " - "clock-frequency.", __func__); - printk(KERN_WARNING "Setting MDIO clock divisor to " - "default %d\n", DEFAULT_CLOCK_DIVISOR); + if (!npp) { + dev_warn(lp->dev, + "Could not find ethernet controller device node."); + dev_warn(lp->dev, "Setting MDIO clock divisor to default %d\n", + DEFAULT_CLOCK_DIVISOR); clk_div = DEFAULT_CLOCK_DIVISOR; - of_node_put(np1); - goto issue; + } else { + u32 *property_p; + + property_p = (uint32_t *)of_get_property(npp, + "clock-frequency", NULL); + if (!property_p) { + dev_warn(lp->dev, + "Could not find clock ethernet " + "controller property."); + dev_warn(lp->dev, + "Setting MDIO clock divisor to default %d\n", + DEFAULT_CLOCK_DIVISOR); + clk_div = DEFAULT_CLOCK_DIVISOR; + } else { + u32 host_clock = be32_to_cpup(property_p); + + clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1; + + /* If there is any remainder from the division of + * fHOST / (MAX_MDIO_FREQ * 2), then we need to add 1 + * to the clock divisor or we will surely be + * above 2.5 MHz + */ + if (host_clock % (MAX_MDIO_FREQ * 2)) + clk_div++; + dev_dbg(lp->dev, + "Setting MDIO clock divisor to %u " + "based on %u Hz host clock.\n", + clk_div, host_clock); + } + of_node_put(npp); } - host_clock = be32_to_cpup(property_p); - clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1; - /* If there is any remainder from the division of - * fHOST / (MAX_MDIO_FREQ * 2), then we need to add - * 1 to the clock divisor or we will surely be above 2.5 MHz */ - if (host_clock % (MAX_MDIO_FREQ * 2)) - clk_div++; - - printk(KERN_DEBUG "%s(): Setting MDIO clock divisor to %u based " - "on %u Hz host clock.\n", __func__, clk_div, host_clock); - - of_node_put(np1); -issue: - axienet_iow(lp, XAE_MDIO_MC_OFFSET, - (((u32) clk_div) | XAE_MDIO_MC_MDIOEN_MASK)); + axienet_iow(lp, XAE_MDIO_MC_OFFSET, (((u32)clk_div) | + XAE_MDIO_MC_MDIOEN_MASK)); ret = axienet_mdio_wait_until_ready(lp); if (ret < 0) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:217 @ if (!bus) return -ENOMEM; - np1 = of_get_parent(lp->phy_node); - of_address_to_resource(np1, 0, &res); + of_address_to_resource(npp, 0, &res); snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", (unsigned long long) res.start); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:246 @ void axienet_mdio_teardown(struct axienet_local *lp) { mdiobus_unregister(lp->mii_bus); - kfree(lp->mii_bus->irq); mdiobus_free(lp->mii_bus); lp->mii_bus = NULL; } Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_emaclite.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/net/ethernet/xilinx/xilinx_emaclite.c 2014-07-20 22:05:50.256066291 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_emaclite.c 2014-07-20 22:06:37.105293363 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:25 @ #include <linux/slab.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of_mdio.h> #include <linux/of_net.h> @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:35 @ #define DRIVER_NAME "xilinx_emaclite" /* Register offsets for the EmacLite Core */ -#define XEL_TXBUFF_OFFSET 0x0 /* Transmit Buffer */ +#define XEL_TXBUFF_OFFSET 0x0 /* Transmit Buffer */ #define XEL_MDIOADDR_OFFSET 0x07E4 /* MDIO Address Register */ #define XEL_MDIOWR_OFFSET 0x07E8 /* MDIO Write Data Register */ #define XEL_MDIORD_OFFSET 0x07EC /* MDIO Read Data Register */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:67 @ #define XEL_MDIOCTRL_MDIOEN_MASK 0x00000008 /* MDIO Enable */ /* Global Interrupt Enable Register (GIER) Bit Masks */ -#define XEL_GIER_GIE_MASK 0x80000000 /* Global Enable */ +#define XEL_GIER_GIE_MASK 0x80000000 /* Global Enable */ /* Transmit Status Register (TSR) Bit Masks */ -#define XEL_TSR_XMIT_BUSY_MASK 0x00000001 /* Tx complete */ -#define XEL_TSR_PROGRAM_MASK 0x00000002 /* Program the MAC address */ -#define XEL_TSR_XMIT_IE_MASK 0x00000008 /* Tx interrupt enable bit */ -#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000 /* Buffer is active, SW bit +#define XEL_TSR_XMIT_BUSY_MASK 0x00000001 /* Tx complete */ +#define XEL_TSR_PROGRAM_MASK 0x00000002 /* Program the MAC address */ +#define XEL_TSR_XMIT_IE_MASK 0x00000008 /* Tx interrupt enable bit */ +#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000 /* Buffer is active, SW bit * only. This is not documented * in the HW spec */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:81 @ #define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK) /* Receive Status Register (RSR) */ -#define XEL_RSR_RECV_DONE_MASK 0x00000001 /* Rx complete */ -#define XEL_RSR_RECV_IE_MASK 0x00000008 /* Rx interrupt enable bit */ +#define XEL_RSR_RECV_DONE_MASK 0x00000001 /* Rx complete */ +#define XEL_RSR_RECV_IE_MASK 0x00000008 /* Rx interrupt enable bit */ /* Transmit Packet Length Register (TPLR) */ -#define XEL_TPLR_LENGTH_MASK 0x0000FFFF /* Tx packet length */ +#define XEL_TPLR_LENGTH_MASK 0x0000FFFF /* Tx packet length */ /* Receive Packet Length Register (RPLR) */ -#define XEL_RPLR_LENGTH_MASK 0x0000FFFF /* Rx packet length */ +#define XEL_RPLR_LENGTH_MASK 0x0000FFFF /* Rx packet length */ -#define XEL_HEADER_OFFSET 12 /* Offset to length field */ -#define XEL_HEADER_SHIFT 16 /* Shift value for length */ +#define XEL_HEADER_OFFSET 12 /* Offset to length field */ +#define XEL_HEADER_SHIFT 16 /* Shift value for length */ /* General Ethernet Definitions */ -#define XEL_ARP_PACKET_SIZE 28 /* Max ARP packet size */ -#define XEL_HEADER_IP_LENGTH_OFFSET 16 /* IP Length Offset */ +#define XEL_ARP_PACKET_SIZE 28 /* Max ARP packet size */ +#define XEL_HEADER_IP_LENGTH_OFFSET 16 /* IP Length Offset */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:167 @ __raw_writel(reg_data | XEL_TSR_XMIT_IE_MASK, drvdata->base_addr + XEL_TSR_OFFSET); - /* Enable the Tx interrupts for the second Buffer if - * configured in HW */ - if (drvdata->tx_ping_pong != 0) { - reg_data = __raw_readl(drvdata->base_addr + - XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); - __raw_writel(reg_data | XEL_TSR_XMIT_IE_MASK, - drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_TSR_OFFSET); - } - /* Enable the Rx interrupts for the first buffer */ __raw_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr + XEL_RSR_OFFSET); - /* Enable the Rx interrupts for the second Buffer if - * configured in HW */ - if (drvdata->rx_ping_pong != 0) { - __raw_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr + - XEL_BUFFER_OFFSET + XEL_RSR_OFFSET); - } - /* Enable the Global Interrupt Enable */ __raw_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET); } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:193 @ __raw_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK), drvdata->base_addr + XEL_TSR_OFFSET); - /* Disable the Tx interrupts for the second Buffer - * if configured in HW */ - if (drvdata->tx_ping_pong != 0) { - reg_data = __raw_readl(drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_TSR_OFFSET); - __raw_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK), - drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_TSR_OFFSET); - } - /* Disable the Rx interrupts for the first buffer */ reg_data = __raw_readl(drvdata->base_addr + XEL_RSR_OFFSET); __raw_writel(reg_data & (~XEL_RSR_RECV_IE_MASK), drvdata->base_addr + XEL_RSR_OFFSET); - - /* Disable the Rx interrupts for the second buffer - * if configured in HW */ - if (drvdata->rx_ping_pong != 0) { - - reg_data = __raw_readl(drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_RSR_OFFSET); - __raw_writel(reg_data & (~XEL_RSR_RECV_IE_MASK), - drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_RSR_OFFSET); - } } /** @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:224 @ *to_u16_ptr++ = *from_u16_ptr++; *to_u16_ptr++ = *from_u16_ptr++; + /* This barrier resolves occasional issues seen around + * cases where the data is not properly flushed out + * from the processor store buffers to the destination + * memory locations. + */ + wmb(); + /* Output a word */ *to_u32_ptr++ = align_buffer; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:246 @ for (; length > 0; length--) *to_u8_ptr++ = *from_u8_ptr++; + /* This barrier resolves occasional issues seen around + * cases where the data is not properly flushed out + * from the processor store buffers to the destination + * memory locations. + */ + wmb(); *to_u32_ptr = align_buffer; } } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1054 @ * This function un maps the IO region of the Emaclite device and frees the net * device. */ -static void xemaclite_remove_ndev(struct net_device *ndev, - struct platform_device *pdev) +static void xemaclite_remove_ndev(struct net_device *ndev) { if (ndev) { - struct net_local *lp = netdev_priv(ndev); - - if (lp->base_addr) - devm_iounmap(&pdev->dev, lp->base_addr); free_netdev(ndev); } } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1188 @ return 0; error: - xemaclite_remove_ndev(ndev, ofdev); + xemaclite_remove_ndev(ndev); return rc; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1222 @ of_node_put(lp->phy_node); lp->phy_node = NULL; - xemaclite_remove_ndev(ndev, of_dev); + xemaclite_remove_ndev(ndev); return 0; } Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_emacps.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_emacps.c 2014-07-20 22:06:37.141292770 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Ethernet: Linux driver for Ethernet. + * + * Author: Xilinx, Inc. + * + * 2010 (c) Xilinx, Inc. This file is licensed uner the terms of the GNU + * General Public License version 2. This program is licensed "as is" + * without any warranty of any kind, whether express or implied. + * + * This is a driver for xilinx processor sub-system (ps) ethernet device. + * This driver is mainly used in Linux 2.6.30 and above and it does _not_ + * support Linux 2.4 kernel due to certain new features (e.g. NAPI) is + * introduced in this driver. + * + * TODO: + * 1. JUMBO frame is not enabled per EPs spec. Please update it if this + * support is added in and set MAX_MTU to 9000. + * 2. PTP slave mode: Findout and implement the proper equation and algorithm + * for adjusting the hw timer frequency inorder to sync with the master + * clock offset. Also formula for deriving the max adjustable frequency + * value in ppb. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/platform_device.h> +#include <linux/phy.h> +#include <linux/mii.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/ethtool.h> +#include <linux/vmalloc.h> +#include <linux/version.h> +#include <linux/of.h> +#include <linux/interrupt.h> +#include <linux/clocksource.h> +#include <linux/net_tstamp.h> +#include <linux/pm_runtime.h> +#include <linux/clk.h> +#include <linux/of_net.h> +#include <linux/of_address.h> +#include <linux/of_mdio.h> +#include <linux/timer.h> +#include <linux/ptp_clock_kernel.h> + +/************************** Constant Definitions *****************************/ + +/* Must be shorter than length of ethtool_drvinfo.driver field to fit */ +#define DRIVER_NAME "xemacps" +#define DRIVER_DESCRIPTION "Xilinx Tri-Mode Ethernet MAC driver" +#define DRIVER_VERSION "1.00a" + +/* Transmission timeout is 3 seconds. */ +#define TX_TIMEOUT (3*HZ) + +/* for RX skb IP header word-aligned */ +#define RX_IP_ALIGN_OFFSET 2 + +/* DMA buffer descriptors must be aligned on a 4-byte boundary. */ +#define ALIGNMENT_BD 8 + +/* Maximum value for hash bits. 2**6 */ +#define XEMACPS_MAX_HASH_BITS 64 + +/* MDC clock division + * currently supporting 8, 16, 32, 48, 64, 96, 128, 224. + */ +enum { MDC_DIV_8 = 0, MDC_DIV_16, MDC_DIV_32, MDC_DIV_48, +MDC_DIV_64, MDC_DIV_96, MDC_DIV_128, MDC_DIV_224 }; + +/* Specify the receive buffer size in bytes, 64, 128, 192, 10240 */ +#define XEMACPS_RX_BUF_SIZE 1536 + +/* Number of receive buffer bytes as a unit, this is HW setup */ +#define XEMACPS_RX_BUF_UNIT 64 + +/* Default SEND and RECV buffer descriptors (BD) numbers. + * BD Space needed is (XEMACPS_SEND_BD_CNT+XEMACPS_RECV_BD_CNT)*8 + */ +#undef DEBUG +#define DEBUG + +#define XEMACPS_SEND_BD_CNT 256 +#define XEMACPS_RECV_BD_CNT 256 + +#define XEMACPS_NAPI_WEIGHT 64 + +/* Register offset definitions. Unless otherwise noted, register access is + * 32 bit. Names are self explained here. + */ +#define XEMACPS_NWCTRL_OFFSET 0x00000000 /* Network Control reg */ +#define XEMACPS_NWCFG_OFFSET 0x00000004 /* Network Config reg */ +#define XEMACPS_NWSR_OFFSET 0x00000008 /* Network Status reg */ +#define XEMACPS_USERIO_OFFSET 0x0000000C /* User IO reg */ +#define XEMACPS_DMACR_OFFSET 0x00000010 /* DMA Control reg */ +#define XEMACPS_TXSR_OFFSET 0x00000014 /* TX Status reg */ +#define XEMACPS_RXQBASE_OFFSET 0x00000018 /* RX Q Base address reg */ +#define XEMACPS_TXQBASE_OFFSET 0x0000001C /* TX Q Base address reg */ +#define XEMACPS_RXSR_OFFSET 0x00000020 /* RX Status reg */ +#define XEMACPS_ISR_OFFSET 0x00000024 /* Interrupt Status reg */ +#define XEMACPS_IER_OFFSET 0x00000028 /* Interrupt Enable reg */ +#define XEMACPS_IDR_OFFSET 0x0000002C /* Interrupt Disable reg */ +#define XEMACPS_IMR_OFFSET 0x00000030 /* Interrupt Mask reg */ +#define XEMACPS_PHYMNTNC_OFFSET 0x00000034 /* Phy Maintaince reg */ +#define XEMACPS_RXPAUSE_OFFSET 0x00000038 /* RX Pause Time reg */ +#define XEMACPS_TXPAUSE_OFFSET 0x0000003C /* TX Pause Time reg */ +#define XEMACPS_HASHL_OFFSET 0x00000080 /* Hash Low address reg */ +#define XEMACPS_HASHH_OFFSET 0x00000084 /* Hash High address reg */ +#define XEMACPS_LADDR1L_OFFSET 0x00000088 /* Specific1 addr low */ +#define XEMACPS_LADDR1H_OFFSET 0x0000008C /* Specific1 addr high */ +#define XEMACPS_LADDR2L_OFFSET 0x00000090 /* Specific2 addr low */ +#define XEMACPS_LADDR2H_OFFSET 0x00000094 /* Specific2 addr high */ +#define XEMACPS_LADDR3L_OFFSET 0x00000098 /* Specific3 addr low */ +#define XEMACPS_LADDR3H_OFFSET 0x0000009C /* Specific3 addr high */ +#define XEMACPS_LADDR4L_OFFSET 0x000000A0 /* Specific4 addr low */ +#define XEMACPS_LADDR4H_OFFSET 0x000000A4 /* Specific4 addr high */ +#define XEMACPS_MATCH1_OFFSET 0x000000A8 /* Type ID1 Match reg */ +#define XEMACPS_MATCH2_OFFSET 0x000000AC /* Type ID2 Match reg */ +#define XEMACPS_MATCH3_OFFSET 0x000000B0 /* Type ID3 Match reg */ +#define XEMACPS_MATCH4_OFFSET 0x000000B4 /* Type ID4 Match reg */ +#define XEMACPS_WOL_OFFSET 0x000000B8 /* Wake on LAN reg */ +#define XEMACPS_STRETCH_OFFSET 0x000000BC /* IPG Stretch reg */ +#define XEMACPS_SVLAN_OFFSET 0x000000C0 /* Stacked VLAN reg */ +#define XEMACPS_MODID_OFFSET 0x000000FC /* Module ID reg */ +#define XEMACPS_OCTTXL_OFFSET 0x00000100 /* Octects transmitted Low + reg */ +#define XEMACPS_OCTTXH_OFFSET 0x00000104 /* Octects transmitted High + reg */ +#define XEMACPS_TXCNT_OFFSET 0x00000108 /* Error-free Frmaes + transmitted counter */ +#define XEMACPS_TXBCCNT_OFFSET 0x0000010C /* Error-free Broadcast + Frames counter*/ +#define XEMACPS_TXMCCNT_OFFSET 0x00000110 /* Error-free Multicast + Frame counter */ +#define XEMACPS_TXPAUSECNT_OFFSET 0x00000114 /* Pause Frames Transmitted + Counter */ +#define XEMACPS_TX64CNT_OFFSET 0x00000118 /* Error-free 64 byte Frames + Transmitted counter */ +#define XEMACPS_TX65CNT_OFFSET 0x0000011C /* Error-free 65-127 byte + Frames Transmitted counter */ +#define XEMACPS_TX128CNT_OFFSET 0x00000120 /* Error-free 128-255 byte + Frames Transmitted counter */ +#define XEMACPS_TX256CNT_OFFSET 0x00000124 /* Error-free 256-511 byte + Frames transmitted counter */ +#define XEMACPS_TX512CNT_OFFSET 0x00000128 /* Error-free 512-1023 byte + Frames transmitted counter */ +#define XEMACPS_TX1024CNT_OFFSET 0x0000012C /* Error-free 1024-1518 byte + Frames transmitted counter */ +#define XEMACPS_TX1519CNT_OFFSET 0x00000130 /* Error-free larger than + 1519 byte Frames transmitted + Counter */ +#define XEMACPS_TXURUNCNT_OFFSET 0x00000134 /* TX under run error + Counter */ +#define XEMACPS_SNGLCOLLCNT_OFFSET 0x00000138 /* Single Collision Frame + Counter */ +#define XEMACPS_MULTICOLLCNT_OFFSET 0x0000013C /* Multiple Collision Frame + Counter */ +#define XEMACPS_EXCESSCOLLCNT_OFFSET 0x00000140 /* Excessive Collision Frame + Counter */ +#define XEMACPS_LATECOLLCNT_OFFSET 0x00000144 /* Late Collision Frame + Counter */ +#define XEMACPS_TXDEFERCNT_OFFSET 0x00000148 /* Deferred Transmission + Frame Counter */ +#define XEMACPS_CSENSECNT_OFFSET 0x0000014C /* Carrier Sense Error + Counter */ +#define XEMACPS_OCTRXL_OFFSET 0x00000150 /* Octects Received register + Low */ +#define XEMACPS_OCTRXH_OFFSET 0x00000154 /* Octects Received register + High */ +#define XEMACPS_RXCNT_OFFSET 0x00000158 /* Error-free Frames + Received Counter */ +#define XEMACPS_RXBROADCNT_OFFSET 0x0000015C /* Error-free Broadcast + Frames Received Counter */ +#define XEMACPS_RXMULTICNT_OFFSET 0x00000160 /* Error-free Multicast + Frames Received Counter */ +#define XEMACPS_RXPAUSECNT_OFFSET 0x00000164 /* Pause Frames + Received Counter */ +#define XEMACPS_RX64CNT_OFFSET 0x00000168 /* Error-free 64 byte Frames + Received Counter */ +#define XEMACPS_RX65CNT_OFFSET 0x0000016C /* Error-free 65-127 byte + Frames Received Counter */ +#define XEMACPS_RX128CNT_OFFSET 0x00000170 /* Error-free 128-255 byte + Frames Received Counter */ +#define XEMACPS_RX256CNT_OFFSET 0x00000174 /* Error-free 256-512 byte + Frames Received Counter */ +#define XEMACPS_RX512CNT_OFFSET 0x00000178 /* Error-free 512-1023 byte + Frames Received Counter */ +#define XEMACPS_RX1024CNT_OFFSET 0x0000017C /* Error-free 1024-1518 byte + Frames Received Counter */ +#define XEMACPS_RX1519CNT_OFFSET 0x00000180 /* Error-free 1519-max byte + Frames Received Counter */ +#define XEMACPS_RXUNDRCNT_OFFSET 0x00000184 /* Undersize Frames Received + Counter */ +#define XEMACPS_RXOVRCNT_OFFSET 0x00000188 /* Oversize Frames Received + Counter */ +#define XEMACPS_RXJABCNT_OFFSET 0x0000018C /* Jabbers Received + Counter */ +#define XEMACPS_RXFCSCNT_OFFSET 0x00000190 /* Frame Check Sequence + Error Counter */ +#define XEMACPS_RXLENGTHCNT_OFFSET 0x00000194 /* Length Field Error + Counter */ +#define XEMACPS_RXSYMBCNT_OFFSET 0x00000198 /* Symbol Error Counter */ +#define XEMACPS_RXALIGNCNT_OFFSET 0x0000019C /* Alignment Error + Counter */ +#define XEMACPS_RXRESERRCNT_OFFSET 0x000001A0 /* Receive Resource Error + Counter */ +#define XEMACPS_RXORCNT_OFFSET 0x000001A4 /* Receive Overrun */ +#define XEMACPS_RXIPCCNT_OFFSET 0x000001A8 /* IP header Checksum Error + Counter */ +#define XEMACPS_RXTCPCCNT_OFFSET 0x000001AC /* TCP Checksum Error + Counter */ +#define XEMACPS_RXUDPCCNT_OFFSET 0x000001B0 /* UDP Checksum Error + Counter */ + +#define XEMACPS_1588S_OFFSET 0x000001D0 /* 1588 Timer Seconds */ +#define XEMACPS_1588NS_OFFSET 0x000001D4 /* 1588 Timer Nanoseconds */ +#define XEMACPS_1588ADJ_OFFSET 0x000001D8 /* 1588 Timer Adjust */ +#define XEMACPS_1588INC_OFFSET 0x000001DC /* 1588 Timer Increment */ +#define XEMACPS_PTPETXS_OFFSET 0x000001E0 /* PTP Event Frame + Transmitted Seconds */ +#define XEMACPS_PTPETXNS_OFFSET 0x000001E4 /* PTP Event Frame + Transmitted Nanoseconds */ +#define XEMACPS_PTPERXS_OFFSET 0x000001E8 /* PTP Event Frame Received + Seconds */ +#define XEMACPS_PTPERXNS_OFFSET 0x000001EC /* PTP Event Frame Received + Nanoseconds */ +#define XEMACPS_PTPPTXS_OFFSET 0x000001F0 /* PTP Peer Frame + Transmitted Seconds */ +#define XEMACPS_PTPPTXNS_OFFSET 0x000001F4 /* PTP Peer Frame + Transmitted Nanoseconds */ +#define XEMACPS_PTPPRXS_OFFSET 0x000001F8 /* PTP Peer Frame Received + Seconds */ +#define XEMACPS_PTPPRXNS_OFFSET 0x000001FC /* PTP Peer Frame Received + Nanoseconds */ + +/* network control register bit definitions */ +#define XEMACPS_NWCTRL_FLUSH_DPRAM_MASK 0x00040000 +#define XEMACPS_NWCTRL_RXTSTAMP_MASK 0x00008000 /* RX Timestamp in CRC */ +#define XEMACPS_NWCTRL_ZEROPAUSETX_MASK 0x00001000 /* Transmit zero quantum + pause frame */ +#define XEMACPS_NWCTRL_PAUSETX_MASK 0x00000800 /* Transmit pause frame */ +#define XEMACPS_NWCTRL_HALTTX_MASK 0x00000400 /* Halt transmission + after current frame */ +#define XEMACPS_NWCTRL_STARTTX_MASK 0x00000200 /* Start tx (tx_go) */ + +#define XEMACPS_NWCTRL_STATWEN_MASK 0x00000080 /* Enable writing to + stat counters */ +#define XEMACPS_NWCTRL_STATINC_MASK 0x00000040 /* Increment statistic + registers */ +#define XEMACPS_NWCTRL_STATCLR_MASK 0x00000020 /* Clear statistic + registers */ +#define XEMACPS_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */ +#define XEMACPS_NWCTRL_TXEN_MASK 0x00000008 /* Enable transmit */ +#define XEMACPS_NWCTRL_RXEN_MASK 0x00000004 /* Enable receive */ +#define XEMACPS_NWCTRL_LOOPEN_MASK 0x00000002 /* local loopback */ + +/* name network configuration register bit definitions */ +#define XEMACPS_NWCFG_BADPREAMBEN_MASK 0x20000000 /* disable rejection of + non-standard preamble */ +#define XEMACPS_NWCFG_IPDSTRETCH_MASK 0x10000000 /* enable transmit IPG */ +#define XEMACPS_NWCFG_FCSIGNORE_MASK 0x04000000 /* disable rejection of + FCS error */ +#define XEMACPS_NWCFG_HDRXEN_MASK 0x02000000 /* RX half duplex */ +#define XEMACPS_NWCFG_RXCHKSUMEN_MASK 0x01000000 /* enable RX checksum + offload */ +#define XEMACPS_NWCFG_PAUSECOPYDI_MASK 0x00800000 /* Do not copy pause + Frames to memory */ +#define XEMACPS_NWCFG_MDC_SHIFT_MASK 18 /* shift bits for MDC */ +#define XEMACPS_NWCFG_MDCCLKDIV_MASK 0x001C0000 /* MDC Mask PCLK divisor */ +#define XEMACPS_NWCFG_FCSREM_MASK 0x00020000 /* Discard FCS from + received frames */ +#define XEMACPS_NWCFG_LENGTHERRDSCRD_MASK 0x00010000 +/* RX length error discard */ +#define XEMACPS_NWCFG_RXOFFS_MASK 0x0000C000 /* RX buffer offset */ +#define XEMACPS_NWCFG_PAUSEEN_MASK 0x00002000 /* Enable pause TX */ +#define XEMACPS_NWCFG_RETRYTESTEN_MASK 0x00001000 /* Retry test */ +#define XEMACPS_NWCFG_1000_MASK 0x00000400 /* Gigbit mode */ +#define XEMACPS_NWCFG_EXTADDRMATCHEN_MASK 0x00000200 +/* External address match enable */ +#define XEMACPS_NWCFG_UCASTHASHEN_MASK 0x00000080 /* Receive unicast hash + frames */ +#define XEMACPS_NWCFG_MCASTHASHEN_MASK 0x00000040 /* Receive multicast hash + frames */ +#define XEMACPS_NWCFG_BCASTDI_MASK 0x00000020 /* Do not receive + broadcast frames */ +#define XEMACPS_NWCFG_COPYALLEN_MASK 0x00000010 /* Copy all frames */ + +#define XEMACPS_NWCFG_NVLANDISC_MASK 0x00000004 /* Receive only VLAN + frames */ +#define XEMACPS_NWCFG_FDEN_MASK 0x00000002 /* Full duplex */ +#define XEMACPS_NWCFG_100_MASK 0x00000001 /* 10 or 100 Mbs */ + +/* network status register bit definitaions */ +#define XEMACPS_NWSR_MDIOIDLE_MASK 0x00000004 /* PHY management idle */ +#define XEMACPS_NWSR_MDIO_MASK 0x00000002 /* Status of mdio_in */ + +/* MAC address register word 1 mask */ +#define XEMACPS_LADDR_MACH_MASK 0x0000FFFF /* Address bits[47:32] + bit[31:0] are in BOTTOM */ + +/* DMA control register bit definitions */ +#define XEMACPS_DMACR_RXBUF_MASK 0x00FF0000 /* Mask bit for RX buffer + size */ +#define XEMACPS_DMACR_RXBUF_SHIFT 16 /* Shift bit for RX buffer + size */ +#define XEMACPS_DMACR_TCPCKSUM_MASK 0x00000800 /* enable/disable TX + checksum offload */ +#define XEMACPS_DMACR_TXSIZE_MASK 0x00000400 /* TX buffer memory size */ +#define XEMACPS_DMACR_RXSIZE_MASK 0x00000300 /* RX buffer memory size */ +#define XEMACPS_DMACR_ENDIAN_MASK 0x00000080 /* Endian configuration */ +#define XEMACPS_DMACR_BLENGTH_MASK 0x0000001F /* Buffer burst length */ +#define XEMACPS_DMACR_BLENGTH_INCR16 0x00000010 /* Buffer burst length */ +#define XEMACPS_DMACR_BLENGTH_INCR8 0x00000008 /* Buffer burst length */ +#define XEMACPS_DMACR_BLENGTH_INCR4 0x00000004 /* Buffer burst length */ +#define XEMACPS_DMACR_BLENGTH_SINGLE 0x00000002 /* Buffer burst length */ + +/* transmit status register bit definitions */ +#define XEMACPS_TXSR_HRESPNOK_MASK 0x00000100 /* Transmit hresp not OK */ +#define XEMACPS_TXSR_COL1000_MASK 0x00000080 /* Collision Gbs mode */ +#define XEMACPS_TXSR_URUN_MASK 0x00000040 /* Transmit underrun */ +#define XEMACPS_TXSR_TXCOMPL_MASK 0x00000020 /* Transmit completed OK */ +#define XEMACPS_TXSR_BUFEXH_MASK 0x00000010 /* Transmit buffs exhausted + mid frame */ +#define XEMACPS_TXSR_TXGO_MASK 0x00000008 /* Status of go flag */ +#define XEMACPS_TXSR_RXOVR_MASK 0x00000004 /* Retry limit exceeded */ +#define XEMACPS_TXSR_COL100_MASK 0x00000002 /* Collision 10/100 mode */ +#define XEMACPS_TXSR_USEDREAD_MASK 0x00000001 /* TX buffer used bit set */ + +#define XEMACPS_TXSR_ERROR_MASK (XEMACPS_TXSR_HRESPNOK_MASK | \ + XEMACPS_TXSR_COL1000_MASK | \ + XEMACPS_TXSR_URUN_MASK | \ + XEMACPS_TXSR_BUFEXH_MASK | \ + XEMACPS_TXSR_RXOVR_MASK | \ + XEMACPS_TXSR_COL100_MASK | \ + XEMACPS_TXSR_USEDREAD_MASK) + +/* receive status register bit definitions */ +#define XEMACPS_RXSR_HRESPNOK_MASK 0x00000008 /* Receive hresp not OK */ +#define XEMACPS_RXSR_RXOVR_MASK 0x00000004 /* Receive overrun */ +#define XEMACPS_RXSR_FRAMERX_MASK 0x00000002 /* Frame received OK */ +#define XEMACPS_RXSR_BUFFNA_MASK 0x00000001 /* RX buffer used bit set */ + +#define XEMACPS_RXSR_ERROR_MASK (XEMACPS_RXSR_HRESPNOK_MASK | \ + XEMACPS_RXSR_RXOVR_MASK | \ + XEMACPS_RXSR_BUFFNA_MASK) + +/* interrupts bit definitions + * Bits definitions are same in XEMACPS_ISR_OFFSET, + * XEMACPS_IER_OFFSET, XEMACPS_IDR_OFFSET, and XEMACPS_IMR_OFFSET + */ +#define XEMACPS_IXR_PTPPSTX_MASK 0x02000000 /* PTP Psync transmitted */ +#define XEMACPS_IXR_PTPPDRTX_MASK 0x01000000 /* PTP Pdelay_req + transmitted */ +#define XEMACPS_IXR_PTPSTX_MASK 0x00800000 /* PTP Sync transmitted */ +#define XEMACPS_IXR_PTPDRTX_MASK 0x00400000 /* PTP Delay_req + transmitted */ +#define XEMACPS_IXR_PTPPSRX_MASK 0x00200000 /* PTP Psync received */ +#define XEMACPS_IXR_PTPPDRRX_MASK 0x00100000 /* PTP Pdelay_req + received */ +#define XEMACPS_IXR_PTPSRX_MASK 0x00080000 /* PTP Sync received */ +#define XEMACPS_IXR_PTPDRRX_MASK 0x00040000 /* PTP Delay_req received */ +#define XEMACPS_IXR_PAUSETX_MASK 0x00004000 /* Pause frame + transmitted */ +#define XEMACPS_IXR_PAUSEZERO_MASK 0x00002000 /* Pause time has reached + zero */ +#define XEMACPS_IXR_PAUSENZERO_MASK 0x00001000 /* Pause frame received */ +#define XEMACPS_IXR_HRESPNOK_MASK 0x00000800 /* hresp not ok */ +#define XEMACPS_IXR_RXOVR_MASK 0x00000400 /* Receive overrun + occurred */ +#define XEMACPS_IXR_TXCOMPL_MASK 0x00000080 /* Frame transmitted ok */ +#define XEMACPS_IXR_TXEXH_MASK 0x00000040 /* Transmit err occurred or + no buffers*/ +#define XEMACPS_IXR_RETRY_MASK 0x00000020 /* Retry limit exceeded */ +#define XEMACPS_IXR_URUN_MASK 0x00000010 /* Transmit underrun */ +#define XEMACPS_IXR_TXUSED_MASK 0x00000008 /* Tx buffer used bit read */ +#define XEMACPS_IXR_RXUSED_MASK 0x00000004 /* Rx buffer used bit read */ +#define XEMACPS_IXR_FRAMERX_MASK 0x00000002 /* Frame received ok */ +#define XEMACPS_IXR_MGMNT_MASK 0x00000001 /* PHY management complete */ +#define XEMACPS_IXR_ALL_MASK 0x03FC7FFE /* Everything except MDIO */ + +#define XEMACPS_IXR_TX_ERR_MASK (XEMACPS_IXR_TXEXH_MASK | \ + XEMACPS_IXR_RETRY_MASK | \ + XEMACPS_IXR_URUN_MASK | \ + XEMACPS_IXR_TXUSED_MASK) + +#define XEMACPS_IXR_RX_ERR_MASK (XEMACPS_IXR_HRESPNOK_MASK | \ + XEMACPS_IXR_RXUSED_MASK | \ + XEMACPS_IXR_RXOVR_MASK) +/* PHY Maintenance bit definitions */ +#define XEMACPS_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */ +#define XEMACPS_PHYMNTNC_OP_R_MASK 0x20000000 /* read operation */ +#define XEMACPS_PHYMNTNC_OP_W_MASK 0x10000000 /* write operation */ +#define XEMACPS_PHYMNTNC_ADDR_MASK 0x0F800000 /* Address bits */ +#define XEMACPS_PHYMNTNC_REG_MASK 0x007C0000 /* register bits */ +#define XEMACPS_PHYMNTNC_DATA_MASK 0x0000FFFF /* data bits */ +#define XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK 23 /* Shift bits for PHYAD */ +#define XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK 18 /* Shift bits for PHREG */ + +/* Wake on LAN bit definition */ +#define XEMACPS_WOL_MCAST_MASK 0x00080000 +#define XEMACPS_WOL_SPEREG1_MASK 0x00040000 +#define XEMACPS_WOL_ARP_MASK 0x00020000 +#define XEMACPS_WOL_MAGIC_MASK 0x00010000 +#define XEMACPS_WOL_ARP_ADDR_MASK 0x0000FFFF + +/* Buffer descriptor status words offset */ +#define XEMACPS_BD_ADDR_OFFSET 0x00000000 /**< word 0/addr of BDs */ +#define XEMACPS_BD_STAT_OFFSET 0x00000004 /**< word 1/status of BDs */ + +/* Transmit buffer descriptor status words bit positions. + * Transmit buffer descriptor consists of two 32-bit registers, + * the first - word0 contains a 32-bit address pointing to the location of + * the transmit data. + * The following register - word1, consists of various information to + * control transmit process. After transmit, this is updated with status + * information, whether the frame was transmitted OK or why it had failed. + */ +#define XEMACPS_TXBUF_USED_MASK 0x80000000 /* Used bit. */ +#define XEMACPS_TXBUF_WRAP_MASK 0x40000000 /* Wrap bit, last + descriptor */ +#define XEMACPS_TXBUF_RETRY_MASK 0x20000000 /* Retry limit exceeded */ +#define XEMACPS_TXBUF_EXH_MASK 0x08000000 /* Buffers exhausted */ +#define XEMACPS_TXBUF_LAC_MASK 0x04000000 /* Late collision. */ +#define XEMACPS_TXBUF_NOCRC_MASK 0x00010000 /* No CRC */ +#define XEMACPS_TXBUF_LAST_MASK 0x00008000 /* Last buffer */ +#define XEMACPS_TXBUF_LEN_MASK 0x00003FFF /* Mask for length field */ + +#define XEMACPS_TXBUF_ERR_MASK 0x3C000000 /* Mask for length field */ + +/* Receive buffer descriptor status words bit positions. + * Receive buffer descriptor consists of two 32-bit registers, + * the first - word0 contains a 32-bit word aligned address pointing to the + * address of the buffer. The lower two bits make up the wrap bit indicating + * the last descriptor and the ownership bit to indicate it has been used. + * The following register - word1, contains status information regarding why + * the frame was received (the filter match condition) as well as other + * useful info. + */ +#define XEMACPS_RXBUF_BCAST_MASK 0x80000000 /* Broadcast frame */ +#define XEMACPS_RXBUF_MULTIHASH_MASK 0x40000000 /* Multicast hashed frame */ +#define XEMACPS_RXBUF_UNIHASH_MASK 0x20000000 /* Unicast hashed frame */ +#define XEMACPS_RXBUF_EXH_MASK 0x08000000 /* buffer exhausted */ +#define XEMACPS_RXBUF_AMATCH_MASK 0x06000000 /* Specific address + matched */ +#define XEMACPS_RXBUF_IDFOUND_MASK 0x01000000 /* Type ID matched */ +#define XEMACPS_RXBUF_IDMATCH_MASK 0x00C00000 /* ID matched mask */ +#define XEMACPS_RXBUF_VLAN_MASK 0x00200000 /* VLAN tagged */ +#define XEMACPS_RXBUF_PRI_MASK 0x00100000 /* Priority tagged */ +#define XEMACPS_RXBUF_VPRI_MASK 0x000E0000 /* Vlan priority */ +#define XEMACPS_RXBUF_CFI_MASK 0x00010000 /* CFI frame */ +#define XEMACPS_RXBUF_EOF_MASK 0x00008000 /* End of frame. */ +#define XEMACPS_RXBUF_SOF_MASK 0x00004000 /* Start of frame. */ +#define XEMACPS_RXBUF_LEN_MASK 0x00003FFF /* Mask for length field */ + +#define XEMACPS_RXBUF_WRAP_MASK 0x00000002 /* Wrap bit, last BD */ +#define XEMACPS_RXBUF_NEW_MASK 0x00000001 /* Used bit.. */ +#define XEMACPS_RXBUF_ADD_MASK 0xFFFFFFFC /* Mask for address */ + +#define XEAMCPS_GEN_PURPOSE_TIMER_LOAD 100 /* timeout value is msecs */ + +#define XEMACPS_GMII2RGMII_FULLDPLX BMCR_FULLDPLX +#define XEMACPS_GMII2RGMII_SPEED1000 BMCR_SPEED1000 +#define XEMACPS_GMII2RGMII_SPEED100 BMCR_SPEED100 +#define XEMACPS_GMII2RGMII_REG_NUM 0x10 + +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP +#define NS_PER_SEC 1000000000ULL /* Nanoseconds per + second */ +/* Sum of Ethernet, IP and UDP header length */ +#define XEMACPS_TX_PTPHDR_OFFSET 42 +#define XEMACPS_RX_PTPHDR_OFFSET 28 /* Sum of IP and UDP header length */ +#define XEMACPS_IP_PROTO_OFFSET 9 /* Protocol field offset */ +#define XEMACPS_UDP_PORT_OFFSET 22 /* UDP dst port offset */ +#define XEMACPS_PTP_EVENT_PORT_NUM 0x13F /* Transport port for ptp */ +#endif + +#define xemacps_read(base, reg) \ + __raw_readl(((void __iomem *)(base)) + (reg)) +#define xemacps_write(base, reg, val) \ + __raw_writel((val), ((void __iomem *)(base)) + (reg)) + +struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; + size_t len; +}; + +/* DMA buffer descriptor structure. Each BD is two words */ +struct xemacps_bd { + u32 addr; + u32 ctrl; +}; + + +/* Our private device data. */ +struct net_local { + void __iomem *baseaddr; + struct clk *devclk; + struct clk *aperclk; + struct notifier_block clk_rate_change_nb; + + struct device_node *phy_node; + struct device_node *gmii2rgmii_phy_node; + struct ring_info *tx_skb; + struct ring_info *rx_skb; + + struct xemacps_bd *rx_bd; + struct xemacps_bd *tx_bd; + + dma_addr_t rx_bd_dma; /* physical address */ + dma_addr_t tx_bd_dma; /* physical address */ + + u32 tx_bd_ci; + u32 tx_bd_tail; + u32 rx_bd_ci; + + u32 tx_bd_freecnt; + + spinlock_t tx_lock; + spinlock_t rx_lock; + spinlock_t nwctrlreg_lock; + + struct platform_device *pdev; + struct net_device *ndev; /* this device */ + struct tasklet_struct tx_bdreclaim_tasklet; + struct workqueue_struct *txtimeout_handler_wq; + struct work_struct txtimeout_reinit; + + struct napi_struct napi; /* napi information for device */ + struct net_device_stats stats; /* Statistics for this device */ + + struct timer_list gen_purpose_timer; /* Used for stats update */ + + struct mii_bus *mii_bus; + struct phy_device *phy_dev; + struct phy_device *gmii2rgmii_phy_dev; + phy_interface_t phy_interface; + unsigned int link; + unsigned int speed; + unsigned int duplex; + /* RX ip/tcp/udp checksum */ + unsigned ip_summed; + unsigned int enetnum; + unsigned int lastrxfrmscntr; +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + struct hwtstamp_config hwtstamp_config; + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_caps; + spinlock_t tmreg_lock; + int phc_index; + unsigned int tmr_add; +#endif +}; +#define to_net_local(_nb) container_of(_nb, struct net_local,\ + clk_rate_change_nb) + +static struct net_device_ops netdev_ops; + +/** + * xemacps_mdio_read - Read current value of phy register indicated by + * phyreg. + * @bus: mdio bus + * @mii_id: mii id + * @phyreg: phy register to be read + * + * @return: value read from specified phy register. + * + * note: This is for 802.3 clause 22 phys access. For 802.3 clause 45 phys + * access, set bit 30 to be 1. e.g. change XEMACPS_PHYMNTNC_OP_MASK to + * 0x00020000. + */ +static int xemacps_mdio_read(struct mii_bus *bus, int mii_id, int phyreg) +{ + struct net_local *lp = bus->priv; + u32 regval; + int value; + volatile u32 ipisr; + + regval = XEMACPS_PHYMNTNC_OP_MASK; + regval |= XEMACPS_PHYMNTNC_OP_R_MASK; + regval |= (mii_id << XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK); + regval |= (phyreg << XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK); + + xemacps_write(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET, regval); + + /* wait for end of transfer */ + do { + cpu_relax(); + ipisr = xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET); + } while ((ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0); + + value = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET) & + XEMACPS_PHYMNTNC_DATA_MASK; + + return value; +} + +/** + * xemacps_mdio_write - Write passed in value to phy register indicated + * by phyreg. + * @bus: mdio bus + * @mii_id: mii id + * @phyreg: phy register to be configured. + * @value: value to be written to phy register. + * return 0. This API requires to be int type or compile warning generated + * + * note: This is for 802.3 clause 22 phys access. For 802.3 clause 45 phys + * access, set bit 30 to be 1. e.g. change XEMACPS_PHYMNTNC_OP_MASK to + * 0x00020000. + */ +static int xemacps_mdio_write(struct mii_bus *bus, int mii_id, int phyreg, + u16 value) +{ + struct net_local *lp = bus->priv; + u32 regval; + volatile u32 ipisr; + + regval = XEMACPS_PHYMNTNC_OP_MASK; + regval |= XEMACPS_PHYMNTNC_OP_W_MASK; + regval |= (mii_id << XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK); + regval |= (phyreg << XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK); + regval |= value; + + xemacps_write(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET, regval); + + /* wait for end of transfer */ + do { + cpu_relax(); + ipisr = xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET); + } while ((ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0); + + return 0; +} + + +/** + * xemacps_mdio_reset - mdio reset. It seems to be required per open + * source documentation phy.txt. But there is no reset in this device. + * Provide function API for now. + * @bus: mdio bus + **/ +static int xemacps_mdio_reset(struct mii_bus *bus) +{ + return 0; +} + +/** + * xemacps_set_freq() - Set a clock to a new frequency + * @clk Pointer to the clock to change + * @rate New frequency in Hz + * @dev Pointer to the struct device + */ +static void xemacps_set_freq(struct clk *clk, long rate, struct device *dev) +{ + rate = clk_round_rate(clk, rate); + if (rate < 0) + return; + + dev_info(dev, "Set clk to %ld Hz\n", rate); + if (clk_set_rate(clk, rate)) + dev_err(dev, "Setting new clock rate failed.\n"); +} + +/** + * xemacps_adjust_link - handles link status changes, such as speed, + * duplex, up/down, ... + * @ndev: network device + */ +static void xemacps_adjust_link(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = lp->phy_dev; + struct phy_device *gmii2rgmii_phydev = lp->gmii2rgmii_phy_dev; + int status_change = 0; + u32 regval; + u16 gmii2rgmii_reg = 0; + + if (phydev->link) { + if ((lp->speed != phydev->speed) || + (lp->duplex != phydev->duplex)) { + regval = xemacps_read(lp->baseaddr, + XEMACPS_NWCFG_OFFSET); + regval &= ~(XEMACPS_NWCFG_FDEN_MASK | + XEMACPS_NWCFG_1000_MASK | + XEMACPS_NWCFG_100_MASK); + + if (phydev->duplex) { + regval |= XEMACPS_NWCFG_FDEN_MASK; + gmii2rgmii_reg |= XEMACPS_GMII2RGMII_FULLDPLX; + } + + if (phydev->speed == SPEED_1000) { + regval |= XEMACPS_NWCFG_1000_MASK; + gmii2rgmii_reg |= XEMACPS_GMII2RGMII_SPEED1000; + xemacps_set_freq(lp->devclk, 125000000, + &lp->pdev->dev); + } else if (phydev->speed == SPEED_100) { + regval |= XEMACPS_NWCFG_100_MASK; + gmii2rgmii_reg |= XEMACPS_GMII2RGMII_SPEED100; + xemacps_set_freq(lp->devclk, 25000000, + &lp->pdev->dev); + } else if (phydev->speed == SPEED_10) { + xemacps_set_freq(lp->devclk, 2500000, + &lp->pdev->dev); + } else { + dev_err(&lp->pdev->dev, + "%s: unknown PHY speed %d\n", + __func__, phydev->speed); + return; + } + + xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, + regval); + + if (gmii2rgmii_phydev != NULL) { + xemacps_mdio_write(lp->mii_bus, + gmii2rgmii_phydev->addr, + XEMACPS_GMII2RGMII_REG_NUM, + gmii2rgmii_reg); + } + + lp->speed = phydev->speed; + lp->duplex = phydev->duplex; + status_change = 1; + } + } + + if (phydev->link != lp->link) { + lp->link = phydev->link; + status_change = 1; + } + + if (status_change) { + if (phydev->link) + dev_info(&lp->pdev->dev, "link up (%d/%s)\n", + phydev->speed, + DUPLEX_FULL == phydev->duplex ? + "FULL" : "HALF"); + else + dev_info(&lp->pdev->dev, "link down\n"); + } +} + +static int xemacps_clk_notifier_cb(struct notifier_block *nb, unsigned long + event, void *data) +{ +/* + struct clk_notifier_data *ndata = data; + struct net_local *nl = to_net_local(nb); +*/ + + switch (event) { + case PRE_RATE_CHANGE: + /* if a rate change is announced we need to check whether we can + * maintain the current frequency by changing the clock + * dividers. + * I don't see how this can be done using the current fmwk!? + * For now we always allow the rate change. Otherwise we would + * even prevent ourself to change the rate. + */ + return NOTIFY_OK; + case POST_RATE_CHANGE: + /* not sure this will work. actually i'm sure it does not. this + * callback is not allowed to call back into COMMON_CLK, what + * adjust_link() does...*/ + /*xemacps_adjust_link(nl->ndev); would likely lock up kernel */ + return NOTIFY_OK; + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +/** + * xemacps_mii_probe - probe mii bus, find the right bus_id to register + * phy callback function. + * @ndev: network interface device structure + * return 0 on success, negative value if error + **/ +static int xemacps_mii_probe(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = NULL; + + if (lp->phy_node) { + phydev = of_phy_connect(lp->ndev, + lp->phy_node, + &xemacps_adjust_link, + 0, + lp->phy_interface); + } + if (!phydev) { + dev_err(&lp->pdev->dev, "%s: no PHY found\n", ndev->name); + return -1; + } + + dev_dbg(&lp->pdev->dev, + "GEM: phydev %p, phydev->phy_id 0x%x, phydev->addr 0x%x\n", + phydev, phydev->phy_id, phydev->addr); + + phydev->supported &= (PHY_GBIT_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + phydev->advertising = phydev->supported; + + lp->link = 0; + lp->speed = 0; + lp->duplex = -1; + lp->phy_dev = phydev; + + phy_start(lp->phy_dev); + + dev_dbg(&lp->pdev->dev, "phy_addr 0x%x, phy_id 0x%08x\n", + lp->phy_dev->addr, lp->phy_dev->phy_id); + + dev_dbg(&lp->pdev->dev, "attach [%s] phy driver\n", + lp->phy_dev->drv->name); + + if (lp->gmii2rgmii_phy_node) { + phydev = of_phy_connect(lp->ndev, + lp->gmii2rgmii_phy_node, + NULL, + 0, 0); + if (!phydev) { + dev_err(&lp->pdev->dev, "%s: no gmii to rgmii converter found\n", + ndev->name); + return -1; + } + lp->gmii2rgmii_phy_dev = phydev; + } else + lp->gmii2rgmii_phy_dev = NULL; + + return 0; +} + +/** + * xemacps_mii_init - Initialize and register mii bus to network device + * @lp: local device instance pointer + * return 0 on success, negative value if error + **/ +static int xemacps_mii_init(struct net_local *lp) +{ + int rc = -ENXIO, i; + struct resource res; + struct device_node *np = of_get_parent(lp->phy_node); + struct device_node *npp; + + lp->mii_bus = mdiobus_alloc(); + if (lp->mii_bus == NULL) { + rc = -ENOMEM; + goto err_out; + } + + lp->mii_bus->name = "XEMACPS mii bus"; + lp->mii_bus->read = &xemacps_mdio_read; + lp->mii_bus->write = &xemacps_mdio_write; + lp->mii_bus->reset = &xemacps_mdio_reset; + lp->mii_bus->priv = lp; + lp->mii_bus->parent = &lp->ndev->dev; + + lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (!lp->mii_bus->irq) { + rc = -ENOMEM; + goto err_out_free_mdiobus; + } + + for (i = 0; i < PHY_MAX_ADDR; i++) + lp->mii_bus->irq[i] = PHY_POLL; + npp = of_get_parent(np); + of_address_to_resource(npp, 0, &res); + snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%.8llx", + (unsigned long long)res.start); + if (of_mdiobus_register(lp->mii_bus, np)) + goto err_out_free_mdio_irq; + + return 0; + +err_out_free_mdio_irq: + kfree(lp->mii_bus->irq); +err_out_free_mdiobus: + mdiobus_free(lp->mii_bus); +err_out: + return rc; +} + +/** + * xemacps_update_hdaddr - Update device's MAC address when configured + * MAC address is not valid, reconfigure with a good one. + * @lp: local device instance pointer + **/ +static void xemacps_update_hwaddr(struct net_local *lp) +{ + u32 regvall; + u16 regvalh; + u8 addr[6]; + + regvall = xemacps_read(lp->baseaddr, XEMACPS_LADDR1L_OFFSET); + regvalh = xemacps_read(lp->baseaddr, XEMACPS_LADDR1H_OFFSET); + addr[0] = regvall & 0xFF; + addr[1] = (regvall >> 8) & 0xFF; + addr[2] = (regvall >> 16) & 0xFF; + addr[3] = (regvall >> 24) & 0xFF; + addr[4] = regvalh & 0xFF; + addr[5] = (regvalh >> 8) & 0xFF; + + if (is_valid_ether_addr(addr)) { + memcpy(lp->ndev->dev_addr, addr, sizeof(addr)); + } else { + dev_info(&lp->pdev->dev, "invalid address, use assigned\n"); + random_ether_addr(lp->ndev->dev_addr); + dev_info(&lp->pdev->dev, + "MAC updated %02x:%02x:%02x:%02x:%02x:%02x\n", + lp->ndev->dev_addr[0], lp->ndev->dev_addr[1], + lp->ndev->dev_addr[2], lp->ndev->dev_addr[3], + lp->ndev->dev_addr[4], lp->ndev->dev_addr[5]); + } +} + +/** + * xemacps_set_hwaddr - Set device's MAC address from ndev->dev_addr + * @lp: local device instance pointer + **/ +static void xemacps_set_hwaddr(struct net_local *lp) +{ + u32 regvall = 0; + u16 regvalh = 0; +#ifdef __LITTLE_ENDIAN + regvall = cpu_to_le32(*((u32 *)lp->ndev->dev_addr)); + regvalh = cpu_to_le16(*((u16 *)(lp->ndev->dev_addr + 4))); +#endif +#ifdef __BIG_ENDIAN + regvall = cpu_to_be32(*((u32 *)lp->ndev->dev_addr)); + regvalh = cpu_to_be16(*((u16 *)(lp->ndev->dev_addr + 4))); +#endif + /* LADDRXH has to be wriiten latter than LADDRXL to enable + * this address even if these 16 bits are zeros. */ + xemacps_write(lp->baseaddr, XEMACPS_LADDR1L_OFFSET, regvall); + xemacps_write(lp->baseaddr, XEMACPS_LADDR1H_OFFSET, regvalh); +#ifdef DEBUG + regvall = xemacps_read(lp->baseaddr, XEMACPS_LADDR1L_OFFSET); + regvalh = xemacps_read(lp->baseaddr, XEMACPS_LADDR1H_OFFSET); + dev_dbg(&lp->pdev->dev, + "MAC 0x%08x, 0x%08x, %02x:%02x:%02x:%02x:%02x:%02x\n", + regvall, regvalh, + (regvall & 0xff), ((regvall >> 8) & 0xff), + ((regvall >> 16) & 0xff), (regvall >> 24), + (regvalh & 0xff), (regvalh >> 8)); +#endif +} + +/* + * xemacps_reset_hw - Helper function to reset the underlying hardware. + * This is called when we get into such deep trouble that we don't know + * how to handle otherwise. + * @lp: local device instance pointer + */ +static void xemacps_reset_hw(struct net_local *lp) +{ + u32 regisr; + /* make sure we have the buffer for ourselves */ + wmb(); + + /* Have a clean start */ + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, 0); + + /* Clear statistic counters */ + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, + XEMACPS_NWCTRL_STATCLR_MASK); + + /* Clear TX and RX status */ + xemacps_write(lp->baseaddr, XEMACPS_TXSR_OFFSET, ~0UL); + xemacps_write(lp->baseaddr, XEMACPS_RXSR_OFFSET, ~0UL); + + /* Disable all interrupts */ + xemacps_write(lp->baseaddr, XEMACPS_IDR_OFFSET, ~0UL); + synchronize_irq(lp->ndev->irq); + regisr = xemacps_read(lp->baseaddr, XEMACPS_ISR_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_ISR_OFFSET, regisr); +} + +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + +/** + * xemacps_ptp_read - Read timestamp information from the timer counters + * @lp: Local device instance pointer + * @ts: Timespec structure to hold the current time value + * return: None + */ +static inline void xemacps_ptp_read(struct net_local *lp, + struct timespec *ts) +{ + ts->tv_sec = xemacps_read(lp->baseaddr, XEMACPS_1588S_OFFSET); + ts->tv_nsec = xemacps_read(lp->baseaddr, XEMACPS_1588NS_OFFSET); + + if (ts->tv_sec < xemacps_read(lp->baseaddr, XEMACPS_1588S_OFFSET)) + ts->tv_nsec = xemacps_read(lp->baseaddr, XEMACPS_1588NS_OFFSET); +} + +/** + * xemacps_ptp_write - Update the currenrt time value to the timer counters + * @lp: Local device instance pointer + * @ts: Timespec structure to hold the time value + * return: None + */ +static inline void xemacps_ptp_write(struct net_local *lp, + const struct timespec *ts) +{ + xemacps_write(lp->baseaddr, XEMACPS_1588S_OFFSET, ts->tv_sec); + xemacps_write(lp->baseaddr, XEMACPS_1588NS_OFFSET, ts->tv_nsec); +} + +/** + * xemacps_rx_hwtstamp - Read rx timestamp from hw and update it to the skbuff + * @lp: Local device instance pointer + * @skb: Pointer to the socket buffer + * @msg_type: PTP message type + * return: None + */ +static void xemacps_rx_hwtstamp(struct net_local *lp, + struct sk_buff *skb, unsigned msg_type) +{ + u32 sec, nsec; + + if (msg_type) { + /* PTP Peer Event Frame packets */ + sec = xemacps_read(lp->baseaddr, XEMACPS_PTPPRXS_OFFSET); + nsec = xemacps_read(lp->baseaddr, XEMACPS_PTPPRXNS_OFFSET); + } else { + /* PTP Event Frame packets */ + sec = xemacps_read(lp->baseaddr, XEMACPS_PTPERXS_OFFSET); + nsec = xemacps_read(lp->baseaddr, XEMACPS_PTPERXNS_OFFSET); + } + skb_hwtstamps(skb)->hwtstamp = ktime_set(sec, nsec); +} + +/** + * xemacps_tx_hwtstamp - Read tx timestamp from hw and update it to the skbuff + * @lp: Local device instance pointer + * @skb: Pointer to the socket buffer + * @msg_type: PTP message type + * return: None + */ +static void xemacps_tx_hwtstamp(struct net_local *lp, + struct sk_buff *skb, unsigned msg_type) +{ + u32 sec, nsec; + + if (msg_type) { + /* PTP Peer Event Frame packets */ + sec = xemacps_read(lp->baseaddr, XEMACPS_PTPPTXS_OFFSET); + nsec = xemacps_read(lp->baseaddr, XEMACPS_PTPPTXNS_OFFSET); + } else { + /* PTP Event Frame packets */ + sec = xemacps_read(lp->baseaddr, XEMACPS_PTPETXS_OFFSET); + nsec = xemacps_read(lp->baseaddr, XEMACPS_PTPETXNS_OFFSET); + } + skb_hwtstamps(skb)->hwtstamp = ktime_set(sec, nsec); + skb_tstamp_tx(skb, skb_hwtstamps(skb)); +} + +/** + * xemacps_ptp_enable - Select the mode of operation + * @ptp: PTP clock structure + * @rq: Requested feature to change + * @on: Whether to enable or disable the feature + * return: Always returns EOPNOTSUPP + */ +static int xemacps_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + return -EOPNOTSUPP; +} + +/** + * xemacps_ptp_gettime - Get the current time from the timer counter registers + * @ptp: PTP clock structure + * @ts: Timespec structure to hold the current time value + * return: Always returns zero + */ +static int xemacps_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ + unsigned long flags; + struct net_local *lp = container_of(ptp, struct net_local, ptp_caps); + + spin_lock_irqsave(&lp->tmreg_lock, flags); + xemacps_ptp_read(lp, ts); + spin_unlock_irqrestore(&lp->tmreg_lock, flags); + + return 0; +} + +/** + * xemacps_ptp_settime - Apply the time info to the timer counter registers + * @ptp: PTP clock structure + * @ts: Timespec structure to hold the current time value + * return: Always returns zero + */ +static int xemacps_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec *ts) +{ + unsigned long flags; + struct net_local *lp = container_of(ptp, struct net_local, ptp_caps); + + spin_lock_irqsave(&lp->tmreg_lock, flags); + xemacps_ptp_write(lp, ts); + spin_unlock_irqrestore(&lp->tmreg_lock, flags); + + return 0; +} + +/** + * xemacps_ptp_adjfreq - Adjust the clock freequency + * @ptp: PTP clock info structure + * @ppb: Frequency in parts per billion + * return: Always returns zero + */ +static int xemacps_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + struct net_local *lp = container_of(ptp, struct net_local, ptp_caps); + u64 adj; + u32 diff, addend; + int neg_adj = 0; + + /* FIXME: the following logic is not working and need to + * fine tune the algorithm and parameters + */ + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + + addend = lp->tmr_add; + adj = addend; + adj *= ppb; + diff = div_u64(adj, 1000000000ULL); + + addend = neg_adj ? addend - diff : addend + diff; + xemacps_write(lp->baseaddr, XEMACPS_1588INC_OFFSET, addend); + + return 0; +} + +/** + * xemacps_ptp_adjtime - Adjust the timer counter value with delta + * @ptp: PTP clock info structure + * @delta: Delta value in nano seconds + * return: Always returns zero + */ +static int xemacps_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + unsigned long flags; + struct net_local *lp = container_of(ptp, struct net_local, ptp_caps); + struct timespec now, then = ns_to_timespec(delta); + + spin_lock_irqsave(&lp->tmreg_lock, flags); + xemacps_ptp_read(lp, &now); + now = timespec_add(now, then); + xemacps_ptp_write(lp, (const struct timespec *)&now); + spin_unlock_irqrestore(&lp->tmreg_lock, flags); + return 0; +} + +/** + * xemacps_ptp_init - Initialize the clock and register with ptp sub system + * @lp: Local device instance pointer + * return: None + */ +static void xemacps_ptp_init(struct net_local *lp) +{ + struct timespec now; + unsigned long rate; + u32 delta; + + lp->ptp_caps.owner = THIS_MODULE; + snprintf(lp->ptp_caps.name, 16, "zynq ptp"); + lp->ptp_caps.n_alarm = 0; + lp->ptp_caps.n_ext_ts = 0; + lp->ptp_caps.n_per_out = 0; + lp->ptp_caps.pps = 0; + lp->ptp_caps.adjfreq = xemacps_ptp_adjfreq; + lp->ptp_caps.adjtime = xemacps_ptp_adjtime; + lp->ptp_caps.gettime = xemacps_ptp_gettime; + lp->ptp_caps.settime = xemacps_ptp_settime; + lp->ptp_caps.enable = xemacps_ptp_enable; + + rate = clk_get_rate(lp->aperclk); + + spin_lock_init(&lp->tmreg_lock); + getnstimeofday(&now); + xemacps_ptp_write(lp, (const struct timespec *)&now); + lp->tmr_add = (NS_PER_SEC/rate); + xemacps_write(lp->baseaddr, XEMACPS_1588INC_OFFSET, + lp->tmr_add); + + /* Having eight bits for the number of increments field, + * the max adjustable frequency is inputfreq/(2 pow 8) + * formula for converting the freq hz to ppm is + * Delta(Hz) = (inputfreq(Hz) * ppm)/(10 pow 6) + */ + + delta = rate / 256; + rate = rate / 1000000; + lp->ptp_caps.max_adj = (delta / rate) * 1000; + + lp->ptp_clock = ptp_clock_register(&lp->ptp_caps, &lp->pdev->dev); + if (IS_ERR(lp->ptp_clock)) + pr_err("ptp_clock_register failed\n"); + + lp->phc_index = ptp_clock_index(lp->ptp_clock); +} + +/** + * xemacps_ptp_close - Disable the ptp interface + * @lp: Local device instance pointer + * return: None + */ +static void xemacps_ptp_close(struct net_local *lp) +{ + /* Clear the time counters */ + xemacps_write(lp->baseaddr, XEMACPS_1588NS_OFFSET, 0x0); + xemacps_write(lp->baseaddr, XEMACPS_1588S_OFFSET, 0x0); + xemacps_write(lp->baseaddr, XEMACPS_1588ADJ_OFFSET, 0x0); + xemacps_write(lp->baseaddr, XEMACPS_1588INC_OFFSET, 0x0); + + ptp_clock_unregister(lp->ptp_clock); + + /* Initialize hwstamp config */ + lp->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + lp->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF; +} +#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */ + +/** + * xemacps_rx - process received packets when napi called + * @lp: local device instance pointer + * @budget: NAPI budget + * return: number of BDs processed + **/ +static int xemacps_rx(struct net_local *lp, int budget) +{ + struct xemacps_bd *cur_p; + u32 len; + struct sk_buff *skb; + struct sk_buff *new_skb; + u32 new_skb_baddr; + unsigned int numbdfree = 0; + u32 size = 0; + u32 packets = 0; + u32 regval; + + cur_p = &lp->rx_bd[lp->rx_bd_ci]; + regval = cur_p->addr; + rmb(); + while (numbdfree < budget) { + if (!(regval & XEMACPS_RXBUF_NEW_MASK)) + break; + + new_skb = netdev_alloc_skb(lp->ndev, XEMACPS_RX_BUF_SIZE); + if (new_skb == NULL) { + dev_err(&lp->ndev->dev, "no memory for new sk_buff\n"); + break; + } + /* Get dma handle of skb->data */ + new_skb_baddr = (u32) dma_map_single(lp->ndev->dev.parent, + new_skb->data, + XEMACPS_RX_BUF_SIZE, + DMA_FROM_DEVICE); + + /* the packet length */ + len = cur_p->ctrl & XEMACPS_RXBUF_LEN_MASK; + rmb(); + skb = lp->rx_skb[lp->rx_bd_ci].skb; + dma_unmap_single(lp->ndev->dev.parent, + lp->rx_skb[lp->rx_bd_ci].mapping, + lp->rx_skb[lp->rx_bd_ci].len, + DMA_FROM_DEVICE); + + /* setup received skb and send it upstream */ + skb_put(skb, len); /* Tell the skb how much data we got. */ + skb->protocol = eth_type_trans(skb, lp->ndev); + + skb->ip_summed = lp->ip_summed; + +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + if ((lp->hwtstamp_config.rx_filter == HWTSTAMP_FILTER_ALL) && + (ntohs(skb->protocol) == ETH_P_IP)) { + u8 transport_poto, msg_type; + u16 dst_port; + /* While the GEM can timestamp PTP packets, it does + * not mark the RX descriptor to identify them. This + * is entirely the wrong place to be parsing UDP + * headers, but some minimal effort must be made. + * NOTE: the below parsing of ip_proto and dest_port + * depend on the use of Ethernet_II encapsulation, + * IPv4 without any options. + */ + skb_copy_from_linear_data_offset(skb, + XEMACPS_IP_PROTO_OFFSET, &transport_poto, 1); + if (transport_poto == IPPROTO_UDP) { + skb_copy_from_linear_data_offset(skb, + XEMACPS_UDP_PORT_OFFSET, &dst_port, 2); + if (ntohs(dst_port) == + XEMACPS_PTP_EVENT_PORT_NUM) { + skb_copy_from_linear_data_offset(skb, + XEMACPS_RX_PTPHDR_OFFSET, + &msg_type, 1); + xemacps_rx_hwtstamp(lp, skb, + msg_type & 0x2); + } + } + } +#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */ + size += len; + packets++; + netif_receive_skb(skb); + + cur_p->addr = (cur_p->addr & ~XEMACPS_RXBUF_ADD_MASK) + | (new_skb_baddr); + lp->rx_skb[lp->rx_bd_ci].skb = new_skb; + lp->rx_skb[lp->rx_bd_ci].mapping = new_skb_baddr; + lp->rx_skb[lp->rx_bd_ci].len = XEMACPS_RX_BUF_SIZE; + + cur_p->ctrl = 0; + cur_p->addr &= (~XEMACPS_RXBUF_NEW_MASK); + wmb(); + + lp->rx_bd_ci++; + lp->rx_bd_ci = lp->rx_bd_ci % XEMACPS_RECV_BD_CNT; + cur_p = &lp->rx_bd[lp->rx_bd_ci]; + regval = cur_p->addr; + rmb(); + numbdfree++; + } + wmb(); + lp->stats.rx_packets += packets; + lp->stats.rx_bytes += size; + return numbdfree; +} + +/** + * xemacps_rx_poll - NAPI poll routine + * napi: pointer to napi struct + * budget: + **/ +static int xemacps_rx_poll(struct napi_struct *napi, int budget) +{ + struct net_local *lp = container_of(napi, struct net_local, napi); + int work_done = 0; + u32 regval; + + spin_lock(&lp->rx_lock); + while (1) { + regval = xemacps_read(lp->baseaddr, XEMACPS_RXSR_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_RXSR_OFFSET, regval); + if (regval & XEMACPS_RXSR_HRESPNOK_MASK) + dev_err(&lp->pdev->dev, "RX error 0x%x\n", regval); + + work_done += xemacps_rx(lp, budget - work_done); + if (work_done >= budget) + break; + + napi_complete(napi); + /* We disabled RX interrupts in interrupt service + * routine, now it is time to enable it back. + */ + xemacps_write(lp->baseaddr, + XEMACPS_IER_OFFSET, XEMACPS_IXR_FRAMERX_MASK); + + /* If a packet has come in between the last check of the BD + * list and unmasking the interrupts, we may have missed the + * interrupt, so reschedule here. + */ + if ((lp->rx_bd[lp->rx_bd_ci].addr & XEMACPS_RXBUF_NEW_MASK) + && napi_reschedule(napi)) { + xemacps_write(lp->baseaddr, + XEMACPS_IDR_OFFSET, XEMACPS_IXR_FRAMERX_MASK); + continue; + } + break; + } + spin_unlock(&lp->rx_lock); + return work_done; +} + +/** + * xemacps_tx_poll - tx bd reclaim tasklet handler + * @data: pointer to network interface device structure + **/ +static void xemacps_tx_poll(unsigned long data) +{ + struct net_device *ndev = (struct net_device *)data; + struct net_local *lp = netdev_priv(ndev); + u32 regval; + struct xemacps_bd *cur_p; + u32 numbdsinhw; + struct ring_info *rp; + struct sk_buff *skb; + unsigned long flags; + u32 txbdcount = 0; + bool isfrag = false; + + numbdsinhw = XEMACPS_SEND_BD_CNT - lp->tx_bd_freecnt; + if (!numbdsinhw) + return; + + regval = xemacps_read(lp->baseaddr, XEMACPS_TXSR_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_TXSR_OFFSET, regval); + dev_dbg(&lp->pdev->dev, "TX status 0x%x\n", regval); + if (regval & (XEMACPS_TXSR_HRESPNOK_MASK | XEMACPS_TXSR_BUFEXH_MASK)) + dev_err(&lp->pdev->dev, "TX error 0x%x\n", regval); + + cur_p = &lp->tx_bd[lp->tx_bd_ci]; + + while (numbdsinhw) { + + if ((cur_p->ctrl & XEMACPS_TXBUF_USED_MASK) != + XEMACPS_TXBUF_USED_MASK) { + if (isfrag == false) + break; + } + rp = &lp->tx_skb[lp->tx_bd_ci]; + skb = rp->skb; + lp->stats.tx_bytes += cur_p->ctrl & XEMACPS_TXBUF_LEN_MASK; + +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { + u8 msg_type; + skb_copy_from_linear_data_offset(skb, + XEMACPS_TX_PTPHDR_OFFSET, &msg_type, 1); + xemacps_tx_hwtstamp(lp, skb, msg_type & 0x2); + } +#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */ + + dma_unmap_single(&lp->pdev->dev, rp->mapping, rp->len, + DMA_TO_DEVICE); + rp->skb = NULL; + dev_kfree_skb(skb); + /* log tx completed packets, errors logs + * are in other error counters. + */ + if (cur_p->ctrl & XEMACPS_TXBUF_LAST_MASK) { + lp->stats.tx_packets++; + isfrag = false; + } else { + isfrag = true; + } + + /* Set used bit, preserve wrap bit; clear everything else. */ + cur_p->ctrl |= XEMACPS_TXBUF_USED_MASK; + cur_p->ctrl &= (XEMACPS_TXBUF_USED_MASK | + XEMACPS_TXBUF_WRAP_MASK); + lp->tx_bd_ci++; + lp->tx_bd_ci = lp->tx_bd_ci % XEMACPS_SEND_BD_CNT; + cur_p = &lp->tx_bd[lp->tx_bd_ci]; + numbdsinhw--; + txbdcount++; + } + + spin_lock(&lp->tx_lock); + lp->tx_bd_freecnt += txbdcount; + spin_unlock(&lp->tx_lock); + + if (numbdsinhw) { + spin_lock_irqsave(&lp->nwctrlreg_lock, flags); + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET); + regval |= XEMACPS_NWCTRL_STARTTX_MASK; + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regval); + spin_unlock_irqrestore(&lp->nwctrlreg_lock, flags); + } + + netif_wake_queue(ndev); +} + +/** + * xemacps_interrupt - interrupt main service routine + * @irq: interrupt number + * @dev_id: pointer to a network device structure + * return IRQ_HANDLED or IRQ_NONE + **/ +static irqreturn_t xemacps_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev = dev_id; + struct net_local *lp = netdev_priv(ndev); + u32 regisr; + u32 regctrl; + + regisr = xemacps_read(lp->baseaddr, XEMACPS_ISR_OFFSET); + if (unlikely(!regisr)) + return IRQ_NONE; + + xemacps_write(lp->baseaddr, XEMACPS_ISR_OFFSET, regisr); + + while (regisr) { + if (regisr & (XEMACPS_IXR_TXCOMPL_MASK | + XEMACPS_IXR_TX_ERR_MASK)) { + tasklet_schedule(&lp->tx_bdreclaim_tasklet); + } + + if (regisr & XEMACPS_IXR_RXUSED_MASK) { + spin_lock(&lp->nwctrlreg_lock); + regctrl = xemacps_read(lp->baseaddr, + XEMACPS_NWCTRL_OFFSET); + regctrl |= XEMACPS_NWCTRL_FLUSH_DPRAM_MASK; + xemacps_write(lp->baseaddr, + XEMACPS_NWCTRL_OFFSET, regctrl); + spin_unlock(&lp->nwctrlreg_lock); + } + + if (regisr & XEMACPS_IXR_FRAMERX_MASK) { + xemacps_write(lp->baseaddr, + XEMACPS_IDR_OFFSET, XEMACPS_IXR_FRAMERX_MASK); + napi_schedule(&lp->napi); + } + regisr = xemacps_read(lp->baseaddr, XEMACPS_ISR_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_ISR_OFFSET, regisr); + } + + return IRQ_HANDLED; +} + +/* + * Free all packets presently in the descriptor rings. + */ +static void xemacps_clean_rings(struct net_local *lp) +{ + int i; + + for (i = 0; i < XEMACPS_RECV_BD_CNT; i++) { + if (lp->rx_skb && lp->rx_skb[i].skb) { + dma_unmap_single(lp->ndev->dev.parent, + lp->rx_skb[i].mapping, + lp->rx_skb[i].len, + DMA_FROM_DEVICE); + + dev_kfree_skb(lp->rx_skb[i].skb); + lp->rx_skb[i].skb = NULL; + lp->rx_skb[i].mapping = 0; + } + } + + for (i = 0; i < XEMACPS_SEND_BD_CNT; i++) { + if (lp->tx_skb && lp->tx_skb[i].skb) { + dma_unmap_single(lp->ndev->dev.parent, + lp->tx_skb[i].mapping, + lp->tx_skb[i].len, + DMA_TO_DEVICE); + + dev_kfree_skb(lp->tx_skb[i].skb); + lp->tx_skb[i].skb = NULL; + lp->tx_skb[i].mapping = 0; + } + } +} + +/** + * xemacps_descriptor_free - Free allocated TX and RX BDs + * @lp: local device instance pointer + **/ +static void xemacps_descriptor_free(struct net_local *lp) +{ + int size; + + xemacps_clean_rings(lp); + + /* kfree(NULL) is safe, no need to check here */ + kfree(lp->tx_skb); + lp->tx_skb = NULL; + kfree(lp->rx_skb); + lp->rx_skb = NULL; + + size = XEMACPS_RECV_BD_CNT * sizeof(struct xemacps_bd); + if (lp->rx_bd) { + dma_free_coherent(&lp->pdev->dev, size, + lp->rx_bd, lp->rx_bd_dma); + lp->rx_bd = NULL; + } + + size = XEMACPS_SEND_BD_CNT * sizeof(struct xemacps_bd); + if (lp->tx_bd) { + dma_free_coherent(&lp->pdev->dev, size, + lp->tx_bd, lp->tx_bd_dma); + lp->tx_bd = NULL; + } +} + +/** + * xemacps_descriptor_init - Allocate both TX and RX BDs + * @lp: local device instance pointer + * return 0 on success, negative value if error + **/ +static int xemacps_descriptor_init(struct net_local *lp) +{ + int size; + struct sk_buff *new_skb; + u32 new_skb_baddr; + u32 i; + struct xemacps_bd *cur_p; + u32 regval; + + lp->tx_skb = NULL; + lp->rx_skb = NULL; + lp->rx_bd = NULL; + lp->tx_bd = NULL; + + /* Reset the indexes which are used for accessing the BDs */ + lp->tx_bd_ci = 0; + lp->tx_bd_tail = 0; + lp->rx_bd_ci = 0; + + size = XEMACPS_SEND_BD_CNT * sizeof(struct ring_info); + lp->tx_skb = kzalloc(size, GFP_KERNEL); + if (!lp->tx_skb) + goto err_out; + size = XEMACPS_RECV_BD_CNT * sizeof(struct ring_info); + lp->rx_skb = kzalloc(size, GFP_KERNEL); + if (!lp->rx_skb) + goto err_out; + + /* + * Set up RX buffer descriptors. + */ + + size = XEMACPS_RECV_BD_CNT * sizeof(struct xemacps_bd); + lp->rx_bd = dma_alloc_coherent(&lp->pdev->dev, size, + &lp->rx_bd_dma, GFP_KERNEL); + if (!lp->rx_bd) + goto err_out; + dev_dbg(&lp->pdev->dev, "RX ring %d bytes at 0x%x mapped %p\n", + size, lp->rx_bd_dma, lp->rx_bd); + + for (i = 0; i < XEMACPS_RECV_BD_CNT; i++) { + cur_p = &lp->rx_bd[i]; + + new_skb = netdev_alloc_skb(lp->ndev, XEMACPS_RX_BUF_SIZE); + if (new_skb == NULL) { + dev_err(&lp->ndev->dev, "alloc_skb error %d\n", i); + goto err_out; + } + + /* Get dma handle of skb->data */ + new_skb_baddr = (u32) dma_map_single(lp->ndev->dev.parent, + new_skb->data, + XEMACPS_RX_BUF_SIZE, + DMA_FROM_DEVICE); + + /* set wrap bit for last BD */ + regval = (new_skb_baddr & XEMACPS_RXBUF_ADD_MASK); + if (i == XEMACPS_RECV_BD_CNT - 1) + regval |= XEMACPS_RXBUF_WRAP_MASK; + cur_p->addr = regval; + cur_p->ctrl = 0; + wmb(); + + lp->rx_skb[i].skb = new_skb; + lp->rx_skb[i].mapping = new_skb_baddr; + lp->rx_skb[i].len = XEMACPS_RX_BUF_SIZE; + } + + /* + * Set up TX buffer descriptors. + */ + + size = XEMACPS_SEND_BD_CNT * sizeof(struct xemacps_bd); + lp->tx_bd = dma_alloc_coherent(&lp->pdev->dev, size, + &lp->tx_bd_dma, GFP_KERNEL); + if (!lp->tx_bd) + goto err_out; + dev_dbg(&lp->pdev->dev, "TX ring %d bytes at 0x%x mapped %p\n", + size, lp->tx_bd_dma, lp->tx_bd); + + for (i = 0; i < XEMACPS_SEND_BD_CNT; i++) { + cur_p = &lp->tx_bd[i]; + /* set wrap bit for last BD */ + cur_p->addr = 0; + regval = XEMACPS_TXBUF_USED_MASK; + if (i == XEMACPS_SEND_BD_CNT - 1) + regval |= XEMACPS_TXBUF_WRAP_MASK; + cur_p->ctrl = regval; + } + wmb(); + + lp->tx_bd_freecnt = XEMACPS_SEND_BD_CNT; + + dev_dbg(&lp->pdev->dev, + "lp->tx_bd %p lp->tx_bd_dma %p lp->tx_skb %p\n", + lp->tx_bd, (void *)lp->tx_bd_dma, lp->tx_skb); + dev_dbg(&lp->pdev->dev, + "lp->rx_bd %p lp->rx_bd_dma %p lp->rx_skb %p\n", + lp->rx_bd, (void *)lp->rx_bd_dma, lp->rx_skb); + + return 0; + +err_out: + xemacps_descriptor_free(lp); + return -ENOMEM; +} + +/** + * xemacps_init_hw - Initialize hardware to known good state + * @lp: local device instance pointer + **/ +static void xemacps_init_hw(struct net_local *lp) +{ + u32 regval; + + xemacps_reset_hw(lp); + xemacps_set_hwaddr(lp); + + /* network configuration */ + regval = 0; + regval |= XEMACPS_NWCFG_FDEN_MASK; + regval |= XEMACPS_NWCFG_RXCHKSUMEN_MASK; + regval |= XEMACPS_NWCFG_PAUSECOPYDI_MASK; + regval |= XEMACPS_NWCFG_FCSREM_MASK; + regval |= XEMACPS_NWCFG_PAUSEEN_MASK; + regval |= XEMACPS_NWCFG_100_MASK; + regval |= XEMACPS_NWCFG_HDRXEN_MASK; + + regval |= (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK); + if (lp->ndev->flags & IFF_PROMISC) /* copy all */ + regval |= XEMACPS_NWCFG_COPYALLEN_MASK; + if (!(lp->ndev->flags & IFF_BROADCAST)) /* No broadcast */ + regval |= XEMACPS_NWCFG_BCASTDI_MASK; + xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval); + + /* Init TX and RX DMA Q address */ + xemacps_write(lp->baseaddr, XEMACPS_RXQBASE_OFFSET, lp->rx_bd_dma); + xemacps_write(lp->baseaddr, XEMACPS_TXQBASE_OFFSET, lp->tx_bd_dma); + + /* DMACR configurations */ + regval = (((XEMACPS_RX_BUF_SIZE / XEMACPS_RX_BUF_UNIT) + + ((XEMACPS_RX_BUF_SIZE % XEMACPS_RX_BUF_UNIT) ? 1 : 0)) << + XEMACPS_DMACR_RXBUF_SHIFT); + regval |= XEMACPS_DMACR_RXSIZE_MASK; + regval |= XEMACPS_DMACR_TXSIZE_MASK; + regval |= XEMACPS_DMACR_TCPCKSUM_MASK; +#ifdef __LITTLE_ENDIAN + regval &= ~XEMACPS_DMACR_ENDIAN_MASK; +#endif +#ifdef __BIG_ENDIAN + regval |= XEMACPS_DMACR_ENDIAN_MASK; +#endif + regval |= XEMACPS_DMACR_BLENGTH_INCR16; + xemacps_write(lp->baseaddr, XEMACPS_DMACR_OFFSET, regval); + + /* Enable TX, RX and MDIO port */ + regval = 0; + regval |= XEMACPS_NWCTRL_MDEN_MASK; + regval |= XEMACPS_NWCTRL_TXEN_MASK; + regval |= XEMACPS_NWCTRL_RXEN_MASK; + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regval); + +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + /* Initialize the ptp clock */ + xemacps_ptp_init(lp); +#endif + + /* Enable interrupts */ + regval = XEMACPS_IXR_ALL_MASK; + xemacps_write(lp->baseaddr, XEMACPS_IER_OFFSET, regval); +} + +/** + * xemacps_resetrx_for_no_rxdata - Resets the Rx if there is no data + * for a while (presently 100 msecs) + * @data: Used for net_local instance pointer + **/ +static void xemacps_resetrx_for_no_rxdata(unsigned long data) +{ + struct net_local *lp = (struct net_local *)data; + unsigned long regctrl; + unsigned long tempcntr; + unsigned long flags; + + tempcntr = xemacps_read(lp->baseaddr, XEMACPS_RXCNT_OFFSET); + if ((!tempcntr) && (!(lp->lastrxfrmscntr))) { + spin_lock_irqsave(&lp->nwctrlreg_lock, flags); + regctrl = xemacps_read(lp->baseaddr, + XEMACPS_NWCTRL_OFFSET); + regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK); + xemacps_write(lp->baseaddr, + XEMACPS_NWCTRL_OFFSET, regctrl); + regctrl = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET); + regctrl |= (XEMACPS_NWCTRL_RXEN_MASK); + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regctrl); + spin_unlock_irqrestore(&lp->nwctrlreg_lock, flags); + } + lp->lastrxfrmscntr = tempcntr; +} + +/** + * xemacps_update_stats - Update the statistic structure entries from + * the corresponding emacps hardware statistic registers + * @data: Used for net_local instance pointer + **/ +static void xemacps_update_stats(unsigned long data) +{ + struct net_local *lp = (struct net_local *)data; + struct net_device_stats *nstat = &lp->stats; + u32 cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_RXUNDRCNT_OFFSET); + nstat->rx_errors += cnt; + nstat->rx_length_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_RXOVRCNT_OFFSET); + nstat->rx_errors += cnt; + nstat->rx_length_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_RXJABCNT_OFFSET); + nstat->rx_errors += cnt; + nstat->rx_length_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_RXFCSCNT_OFFSET); + nstat->rx_errors += cnt; + nstat->rx_crc_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_RXLENGTHCNT_OFFSET); + nstat->rx_errors += cnt; + nstat->rx_length_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_RXALIGNCNT_OFFSET); + nstat->rx_errors += cnt; + nstat->rx_frame_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_RXRESERRCNT_OFFSET); + nstat->rx_errors += cnt; + nstat->rx_missed_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_RXORCNT_OFFSET); + nstat->rx_errors += cnt; + nstat->rx_fifo_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_TXURUNCNT_OFFSET); + nstat->tx_errors += cnt; + nstat->tx_fifo_errors += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_SNGLCOLLCNT_OFFSET); + nstat->collisions += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_MULTICOLLCNT_OFFSET); + nstat->collisions += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_EXCESSCOLLCNT_OFFSET); + nstat->tx_errors += cnt; + nstat->tx_aborted_errors += cnt; + nstat->collisions += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_LATECOLLCNT_OFFSET); + nstat->tx_errors += cnt; + nstat->collisions += cnt; + + cnt = xemacps_read(lp->baseaddr, XEMACPS_CSENSECNT_OFFSET); + nstat->tx_errors += cnt; + nstat->tx_carrier_errors += cnt; +} + +/** + * xemacps_gen_purpose_timerhandler - Timer handler that is called at regular + * intervals upon expiry of the gen_purpose_timer defined in net_local struct. + * @data: Used for net_local instance pointer + * + * This timer handler is used to update the statistics by calling the API + * xemacps_update_stats. The statistics register can typically overflow pretty + * quickly under heavy load conditions. This timer is used to periodically + * read the stats registers and update the corresponding stats structure + * entries. The stats registers when read reset to 0. + **/ +static void xemacps_gen_purpose_timerhandler(unsigned long data) +{ + struct net_local *lp = (struct net_local *)data; + + xemacps_update_stats(data); + xemacps_resetrx_for_no_rxdata(data); + mod_timer(&(lp->gen_purpose_timer), + jiffies + msecs_to_jiffies(XEAMCPS_GEN_PURPOSE_TIMER_LOAD)); +} + +/** + * xemacps_open - Called when a network device is made active + * @ndev: network interface device structure + * return 0 on success, negative value if error + * + * The open entry point is called when a network interface is made active + * by the system (IFF_UP). At this point all resources needed for transmit + * and receive operations are allocated, the interrupt handler is + * registered with OS, the watchdog timer is started, and the stack is + * notified that the interface is ready. + * + * note: if error(s), allocated resources before error require to be + * released or system issues (such as memory) leak might happen. + **/ +static int xemacps_open(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + int rc; + + dev_dbg(&lp->pdev->dev, "open\n"); + if (!is_valid_ether_addr(ndev->dev_addr)) + return -EADDRNOTAVAIL; + + rc = xemacps_descriptor_init(lp); + if (rc) { + dev_err(&lp->pdev->dev, + "Unable to allocate DMA memory, rc %d\n", rc); + return rc; + } + + rc = pm_runtime_get_sync(&lp->pdev->dev); + if (rc < 0) { + dev_err(&lp->pdev->dev, + "pm_runtime_get_sync() failed, rc %d\n", rc); + goto err_free_rings; + } + + napi_enable(&lp->napi); + xemacps_init_hw(lp); + rc = xemacps_mii_probe(ndev); + if (rc != 0) { + dev_err(&lp->pdev->dev, + "%s mii_probe fail.\n", lp->mii_bus->name); + if (rc == (-2)) { + mdiobus_unregister(lp->mii_bus); + kfree(lp->mii_bus->irq); + mdiobus_free(lp->mii_bus); + } + rc = -ENXIO; + goto err_pm_put; + } + + setup_timer(&(lp->gen_purpose_timer), xemacps_gen_purpose_timerhandler, + (unsigned long)lp); + mod_timer(&(lp->gen_purpose_timer), + jiffies + msecs_to_jiffies(XEAMCPS_GEN_PURPOSE_TIMER_LOAD)); + + netif_carrier_on(ndev); + netif_start_queue(ndev); + tasklet_enable(&lp->tx_bdreclaim_tasklet); + + return 0; + +err_pm_put: + napi_disable(&lp->napi); + xemacps_reset_hw(lp); + pm_runtime_put(&lp->pdev->dev); +err_free_rings: + xemacps_descriptor_free(lp); + + return rc; +} + +/** + * xemacps_close - disable a network interface + * @ndev: network interface device structure + * return 0 + * + * The close entry point is called when a network interface is de-activated + * by OS. The hardware is still under the driver control, but needs to be + * disabled. A global MAC reset is issued to stop the hardware, and all + * transmit and receive resources are freed. + **/ +static int xemacps_close(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + + del_timer_sync(&(lp->gen_purpose_timer)); + netif_stop_queue(ndev); + napi_disable(&lp->napi); + tasklet_disable(&lp->tx_bdreclaim_tasklet); + netif_carrier_off(ndev); + if (lp->phy_dev) + phy_disconnect(lp->phy_dev); + if (lp->gmii2rgmii_phy_node) + phy_disconnect(lp->gmii2rgmii_phy_dev); + xemacps_reset_hw(lp); +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + xemacps_ptp_close(lp); +#endif + mdelay(500); + xemacps_descriptor_free(lp); + + pm_runtime_put(&lp->pdev->dev); + + return 0; +} + +/** + * xemacps_reinit_for_txtimeout - work queue scheduled for the tx timeout + * handling. + * @ndev: queue work structure + **/ +static void xemacps_reinit_for_txtimeout(struct work_struct *data) +{ + struct net_local *lp = container_of(data, struct net_local, + txtimeout_reinit); + int rc; + + netif_stop_queue(lp->ndev); + napi_disable(&lp->napi); + tasklet_disable(&lp->tx_bdreclaim_tasklet); + spin_lock_bh(&lp->tx_lock); + xemacps_reset_hw(lp); + spin_unlock_bh(&lp->tx_lock); + + if (lp->phy_dev) + phy_stop(lp->phy_dev); + + xemacps_descriptor_free(lp); + rc = xemacps_descriptor_init(lp); + if (rc) { + dev_err(&lp->pdev->dev, + "Unable to allocate DMA memory, rc %d\n", rc); + return; + } + + xemacps_init_hw(lp); + + lp->link = 0; + lp->speed = 0; + lp->duplex = -1; + + if (lp->phy_dev) + phy_start(lp->phy_dev); + + napi_enable(&lp->napi); + tasklet_enable(&lp->tx_bdreclaim_tasklet); + lp->ndev->trans_start = jiffies; + netif_wake_queue(lp->ndev); +} + +/** + * xemacps_tx_timeout - callback used when the transmitter has not made + * any progress for dev->watchdog ticks. + * @ndev: network interface device structure + **/ +static void xemacps_tx_timeout(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + + dev_err(&lp->pdev->dev, "transmit timeout %lu ms, reseting...\n", + TX_TIMEOUT * 1000UL / HZ); + queue_work(lp->txtimeout_handler_wq, &lp->txtimeout_reinit); +} + +/** + * xemacps_set_mac_address - set network interface mac address + * @ndev: network interface device structure + * @addr: pointer to MAC address + * return 0 on success, negative value if error + **/ +static int xemacps_set_mac_address(struct net_device *ndev, void *addr) +{ + struct net_local *lp = netdev_priv(ndev); + struct sockaddr *hwaddr = (struct sockaddr *)addr; + + if (netif_running(ndev)) + return -EBUSY; + + if (!is_valid_ether_addr(hwaddr->sa_data)) + return -EADDRNOTAVAIL; + + dev_dbg(&lp->pdev->dev, "hwaddr 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + hwaddr->sa_data[0], hwaddr->sa_data[1], hwaddr->sa_data[2], + hwaddr->sa_data[3], hwaddr->sa_data[4], hwaddr->sa_data[5]); + + memcpy(ndev->dev_addr, hwaddr->sa_data, ndev->addr_len); + + xemacps_set_hwaddr(lp); + return 0; +} + +/** + * xemacps_clear_csum - Clear the csum field for transport protocols + * @skb: socket buffer + * @ndev: network interface device structure + * return 0 on success, other value if error + **/ +static int xemacps_clear_csum(struct sk_buff *skb, struct net_device *ndev) +{ + /* Only run for packets requiring a checksum. */ + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + + if (unlikely(skb_cow_head(skb, 0))) + return -1; + + *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) = 0; + + return 0; +} + +/** + * xemacps_start_xmit - transmit a packet (called by kernel) + * @skb: socket buffer + * @ndev: network interface device structure + * return 0 on success, other value if error + **/ +static int xemacps_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + dma_addr_t mapping; + unsigned int nr_frags, len; + int i; + u32 regval; + void *virt_addr; + skb_frag_t *frag; + struct xemacps_bd *cur_p; + unsigned long flags; + u32 bd_tail; + + nr_frags = skb_shinfo(skb)->nr_frags + 1; + if (nr_frags > lp->tx_bd_freecnt) { + netif_stop_queue(ndev); /* stop send queue */ + return NETDEV_TX_BUSY; + } + + if (xemacps_clear_csum(skb, ndev)) { + kfree(skb); + return NETDEV_TX_OK; + } + + bd_tail = lp->tx_bd_tail; + cur_p = &lp->tx_bd[bd_tail]; + frag = &skb_shinfo(skb)->frags[0]; + + for (i = 0; i < nr_frags; i++) { + if (i == 0) { + len = skb_headlen(skb); + mapping = dma_map_single(&lp->pdev->dev, skb->data, + len, DMA_TO_DEVICE); + } else { + len = skb_frag_size(frag); + virt_addr = skb_frag_address(frag); + mapping = dma_map_single(&lp->pdev->dev, virt_addr, + len, DMA_TO_DEVICE); + frag++; + skb_get(skb); + } + + lp->tx_skb[lp->tx_bd_tail].skb = skb; + lp->tx_skb[lp->tx_bd_tail].mapping = mapping; + lp->tx_skb[lp->tx_bd_tail].len = len; + cur_p->addr = mapping; + + /* preserve critical status bits */ + regval = cur_p->ctrl; + regval &= (XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK); + /* update length field */ + regval |= ((regval & ~XEMACPS_TXBUF_LEN_MASK) | len); + /* commit second to last buffer to hardware */ + if (i != 0) + regval &= ~XEMACPS_TXBUF_USED_MASK; + /* last fragment of this packet? */ + if (i == (nr_frags - 1)) + regval |= XEMACPS_TXBUF_LAST_MASK; + cur_p->ctrl = regval; + + lp->tx_bd_tail++; + lp->tx_bd_tail = lp->tx_bd_tail % XEMACPS_SEND_BD_CNT; + cur_p = &(lp->tx_bd[lp->tx_bd_tail]); + } + + /* commit first buffer to hardware -- do this after + * committing the other buffers to avoid an underrun */ + cur_p = &lp->tx_bd[bd_tail]; + regval = cur_p->ctrl; + regval &= ~XEMACPS_TXBUF_USED_MASK; + cur_p->ctrl = regval; + + spin_lock_bh(&lp->tx_lock); + lp->tx_bd_freecnt -= nr_frags; + spin_unlock_bh(&lp->tx_lock); + + spin_lock_irqsave(&lp->nwctrlreg_lock, flags); + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, + (regval | XEMACPS_NWCTRL_STARTTX_MASK)); + spin_unlock_irqrestore(&lp->nwctrlreg_lock, flags); + + ndev->trans_start = jiffies; + return 0; +} + +/* + * Get the MAC Address bit from the specified position + */ +static unsigned get_bit(u8 *mac, unsigned bit) +{ + unsigned byte; + + byte = mac[bit / 8]; + byte >>= (bit & 0x7); + byte &= 1; + + return byte; +} + +/* + * Calculate a GEM MAC Address hash index + */ +static unsigned calc_mac_hash(u8 *mac) +{ + int index_bit, mac_bit; + unsigned hash_index; + + hash_index = 0; + mac_bit = 5; + for (index_bit = 5; index_bit >= 0; index_bit--) { + hash_index |= (get_bit(mac, mac_bit) ^ + get_bit(mac, mac_bit + 6) ^ + get_bit(mac, mac_bit + 12) ^ + get_bit(mac, mac_bit + 18) ^ + get_bit(mac, mac_bit + 24) ^ + get_bit(mac, mac_bit + 30) ^ + get_bit(mac, mac_bit + 36) ^ + get_bit(mac, mac_bit + 42)) + << index_bit; + mac_bit--; + } + + return hash_index; +} + +/** + * xemacps_set_hashtable - Add multicast addresses to the internal + * multicast-hash table. Called from xemac_set_rx_mode(). + * @ndev: network interface device structure + * + * The hash address register is 64 bits long and takes up two + * locations in the memory map. The least significant bits are stored + * in EMAC_HSL and the most significant bits in EMAC_HSH. + * + * The unicast hash enable and the multicast hash enable bits in the + * network configuration register enable the reception of hash matched + * frames. The destination address is reduced to a 6 bit index into + * the 64 bit hash register using the following hash function. The + * hash function is an exclusive or of every sixth bit of the + * destination address. + * + * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] + * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] + * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] + * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] + * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] + * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] + * + * da[0] represents the least significant bit of the first byte + * received, that is, the multicast/unicast indicator, and da[47] + * represents the most significant bit of the last byte received. If + * the hash index, hi[n], points to a bit that is set in the hash + * register then the frame will be matched according to whether the + * frame is multicast or unicast. A multicast match will be signalled + * if the multicast hash enable bit is set, da[0] is 1 and the hash + * index points to a bit set in the hash register. A unicast match + * will be signalled if the unicast hash enable bit is set, da[0] is 0 + * and the hash index points to a bit set in the hash register. To + * receive all multicast frames, the hash register should be set with + * all ones and the multicast hash enable bit should be set in the + * network configuration register. + **/ +static void xemacps_set_hashtable(struct net_device *ndev) +{ + struct netdev_hw_addr *curr; + u32 regvalh, regvall, hash_index; + u8 *mc_addr; + struct net_local *lp; + + lp = netdev_priv(ndev); + + regvalh = regvall = 0; + + netdev_for_each_mc_addr(curr, ndev) { + if (!curr) /* end of list */ + break; + mc_addr = curr->addr; + hash_index = calc_mac_hash(mc_addr); + + if (hash_index >= XEMACPS_MAX_HASH_BITS) { + dev_err(&lp->pdev->dev, + "hash calculation out of range %d\n", + hash_index); + break; + } + if (hash_index < 32) + regvall |= (1 << hash_index); + else + regvalh |= (1 << (hash_index - 32)); + } + + xemacps_write(lp->baseaddr, XEMACPS_HASHL_OFFSET, regvall); + xemacps_write(lp->baseaddr, XEMACPS_HASHH_OFFSET, regvalh); +} + +/** + * xemacps_set_rx_mode - enable/disable promiscuous and multicast modes + * @ndev: network interface device structure + **/ +static void xemacps_set_rx_mode(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + u32 regval; + + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET); + + /* promisc mode */ + if (ndev->flags & IFF_PROMISC) + regval |= XEMACPS_NWCFG_COPYALLEN_MASK; + if (!(ndev->flags & IFF_PROMISC)) + regval &= ~XEMACPS_NWCFG_COPYALLEN_MASK; + + /* All multicast mode */ + if (ndev->flags & IFF_ALLMULTI) { + regval |= XEMACPS_NWCFG_MCASTHASHEN_MASK; + xemacps_write(lp->baseaddr, XEMACPS_HASHL_OFFSET, ~0UL); + xemacps_write(lp->baseaddr, XEMACPS_HASHH_OFFSET, ~0UL); + /* Specific multicast mode */ + } else if ((ndev->flags & IFF_MULTICAST) + && (netdev_mc_count(ndev) > 0)) { + regval |= XEMACPS_NWCFG_MCASTHASHEN_MASK; + xemacps_set_hashtable(ndev); + /* Disable multicast mode */ + } else { + xemacps_write(lp->baseaddr, XEMACPS_HASHL_OFFSET, 0x0); + xemacps_write(lp->baseaddr, XEMACPS_HASHH_OFFSET, 0x0); + regval &= ~XEMACPS_NWCFG_MCASTHASHEN_MASK; + } + + /* broadcast mode */ + if (ndev->flags & IFF_BROADCAST) + regval &= ~XEMACPS_NWCFG_BCASTDI_MASK; + /* No broadcast */ + if (!(ndev->flags & IFF_BROADCAST)) + regval |= XEMACPS_NWCFG_BCASTDI_MASK; + + xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval); +} + +#define MIN_MTU 60 +#define MAX_MTU 1500 +/** + * xemacps_change_mtu - Change maximum transfer unit + * @ndev: network interface device structure + * @new_mtu: new vlaue for maximum frame size + * return: 0 on success, negative value if error. + **/ +static int xemacps_change_mtu(struct net_device *ndev, int new_mtu) +{ + if ((new_mtu < MIN_MTU) || + ((new_mtu + ndev->hard_header_len) > MAX_MTU)) + return -EINVAL; + + ndev->mtu = new_mtu; /* change mtu in net_device structure */ + return 0; +} + +/** + * xemacps_get_settings - get device specific settings. + * Usage: Issue "ethtool ethX" under linux prompt. + * @ndev: network device + * @ecmd: ethtool command structure + * return: 0 on success, negative value if error. + **/ +static int +xemacps_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = lp->phy_dev; + + if (!phydev) + return -ENODEV; + + return phy_ethtool_gset(phydev, ecmd); +} + +/** + * xemacps_set_settings - set device specific settings. + * Usage: Issue "ethtool -s ethX speed 1000" under linux prompt + * to change speed + * @ndev: network device + * @ecmd: ethtool command structure + * return: 0 on success, negative value if error. + **/ +static int +xemacps_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = lp->phy_dev; + + if (!phydev) + return -ENODEV; + + return phy_ethtool_sset(phydev, ecmd); +} + +/** + * xemacps_get_drvinfo - report driver information + * Usage: Issue "ethtool -i ethX" under linux prompt + * @ndev: network device + * @ed: device driver information structure + **/ +static void +xemacps_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *ed) +{ + struct net_local *lp = netdev_priv(ndev); + + memset(ed, 0, sizeof(struct ethtool_drvinfo)); + strcpy(ed->driver, lp->pdev->dev.driver->name); + strcpy(ed->version, DRIVER_VERSION); +} + +/** + * xemacps_get_ringparam - get device dma ring information. + * Usage: Issue "ethtool -g ethX" under linux prompt + * @ndev: network device + * @erp: ethtool ring parameter structure + **/ +static void +xemacps_get_ringparam(struct net_device *ndev, struct ethtool_ringparam *erp) +{ + memset(erp, 0, sizeof(struct ethtool_ringparam)); + + erp->rx_max_pending = XEMACPS_RECV_BD_CNT; + erp->tx_max_pending = XEMACPS_SEND_BD_CNT; + erp->rx_pending = 0; + erp->tx_pending = 0; +} + +/** + * xemacps_get_wol - get device wake on lan status + * Usage: Issue "ethtool ethX" under linux prompt + * @ndev: network device + * @ewol: wol status + **/ +static void +xemacps_get_wol(struct net_device *ndev, struct ethtool_wolinfo *ewol) +{ + struct net_local *lp = netdev_priv(ndev); + u32 regval; + + ewol->supported = WAKE_MAGIC | WAKE_ARP | WAKE_UCAST | WAKE_MCAST; + + regval = xemacps_read(lp->baseaddr, XEMACPS_WOL_OFFSET); + if (regval | XEMACPS_WOL_MCAST_MASK) + ewol->wolopts |= WAKE_MCAST; + if (regval | XEMACPS_WOL_ARP_MASK) + ewol->wolopts |= WAKE_ARP; + if (regval | XEMACPS_WOL_SPEREG1_MASK) + ewol->wolopts |= WAKE_UCAST; + if (regval | XEMACPS_WOL_MAGIC_MASK) + ewol->wolopts |= WAKE_MAGIC; + +} + +/** + * xemacps_set_wol - set device wake on lan configuration + * Usage: Issue "ethtool -s ethX wol u|m|b|g" under linux prompt to enable + * specified type of packet. + * Usage: Issue "ethtool -s ethX wol d" under linux prompt to disable + * this feature. + * @ndev: network device + * @ewol: wol status + * return 0 on success, negative value if not supported + **/ +static int +xemacps_set_wol(struct net_device *ndev, struct ethtool_wolinfo *ewol) +{ + struct net_local *lp = netdev_priv(ndev); + u32 regval; + + if (ewol->wolopts & ~(WAKE_MAGIC | WAKE_ARP | WAKE_UCAST | WAKE_MCAST)) + return -EOPNOTSUPP; + + regval = xemacps_read(lp->baseaddr, XEMACPS_WOL_OFFSET); + regval &= ~(XEMACPS_WOL_MCAST_MASK | XEMACPS_WOL_ARP_MASK | + XEMACPS_WOL_SPEREG1_MASK | XEMACPS_WOL_MAGIC_MASK); + + if (ewol->wolopts & WAKE_MAGIC) + regval |= XEMACPS_WOL_MAGIC_MASK; + if (ewol->wolopts & WAKE_ARP) + regval |= XEMACPS_WOL_ARP_MASK; + if (ewol->wolopts & WAKE_UCAST) + regval |= XEMACPS_WOL_SPEREG1_MASK; + if (ewol->wolopts & WAKE_MCAST) + regval |= XEMACPS_WOL_MCAST_MASK; + + xemacps_write(lp->baseaddr, XEMACPS_WOL_OFFSET, regval); + + return 0; +} + +/** + * xemacps_get_pauseparam - get device pause status + * Usage: Issue "ethtool -a ethX" under linux prompt + * @ndev: network device + * @epauseparam: pause parameter + * + * note: hardware supports only tx flow control + **/ +static void +xemacps_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *epauseparm) +{ + struct net_local *lp = netdev_priv(ndev); + u32 regval; + + epauseparm->autoneg = 0; + epauseparm->rx_pause = 0; + + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET); + epauseparm->tx_pause = regval & XEMACPS_NWCFG_PAUSEEN_MASK; +} + +/** + * xemacps_set_pauseparam - set device pause parameter(flow control) + * Usage: Issue "ethtool -A ethX tx on|off" under linux prompt + * @ndev: network device + * @epauseparam: pause parameter + * return 0 on success, negative value if not supported + * + * note: hardware supports only tx flow control + **/ +static int +xemacps_set_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *epauseparm) +{ + struct net_local *lp = netdev_priv(ndev); + u32 regval; + + if (netif_running(ndev)) { + dev_err(&lp->pdev->dev, + "Please stop netif before apply configruation\n"); + return -EFAULT; + } + + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET); + + if (epauseparm->tx_pause) + regval |= XEMACPS_NWCFG_PAUSEEN_MASK; + if (!(epauseparm->tx_pause)) + regval &= ~XEMACPS_NWCFG_PAUSEEN_MASK; + + xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval); + return 0; +} + +/** + * xemacps_get_stats - get device statistic raw data in 64bit mode + * @ndev: network device + **/ +static struct net_device_stats +*xemacps_get_stats(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + struct net_device_stats *nstat = &lp->stats; + + xemacps_update_stats((unsigned long)lp); + return nstat; +} + +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP +/** + * xemacps_get_ts_info - Get the interface timestamp capabilities + * @dev: Network device + * @info: Holds the interface timestamp capability info + * retur: Always return zero + */ +static int xemacps_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + struct net_local *lp = netdev_priv(dev); + + info->so_timestamping = + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->phc_index = lp->phc_index; + info->tx_types = (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON); + info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_ALL); + return 0; +} +#endif + +static struct ethtool_ops xemacps_ethtool_ops = { + .get_settings = xemacps_get_settings, + .set_settings = xemacps_set_settings, + .get_drvinfo = xemacps_get_drvinfo, + .get_link = ethtool_op_get_link, /* ethtool default */ + .get_ringparam = xemacps_get_ringparam, + .get_wol = xemacps_get_wol, + .set_wol = xemacps_set_wol, + .get_pauseparam = xemacps_get_pauseparam, + .set_pauseparam = xemacps_set_pauseparam, +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + .get_ts_info = xemacps_get_ts_info, +#endif +}; + +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP +static int xemacps_hwtstamp_ioctl(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + struct hwtstamp_config config; + struct net_local *lp; + u32 regval; + + lp = netdev_priv(netdev); + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + /* reserved for future extensions */ + if (config.flags) + return -EINVAL; + + if ((config.tx_type != HWTSTAMP_TX_OFF) && + (config.tx_type != HWTSTAMP_TX_ON)) + return -ERANGE; + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + config.rx_filter = HWTSTAMP_FILTER_ALL; + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, + (regval | XEMACPS_NWCTRL_RXTSTAMP_MASK)); + break; + default: + return -ERANGE; + } + + config.tx_type = HWTSTAMP_TX_ON; + lp->hwtstamp_config = config; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} +#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */ + +/** + * xemacps_ioctl - ioctl entry point + * @ndev: network device + * @rq: interface request ioctl + * @cmd: command code + * + * Called when user issues an ioctl request to the network device. + **/ +static int xemacps_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = lp->phy_dev; + + if (!netif_running(ndev)) + return -EINVAL; + + if (!phydev) + return -ENODEV; + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return phy_mii_ioctl(phydev, rq, cmd); +#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + case SIOCSHWTSTAMP: + return xemacps_hwtstamp_ioctl(ndev, rq, cmd); +#endif + default: + dev_info(&lp->pdev->dev, "ioctl %d not implemented.\n", cmd); + return -EOPNOTSUPP; + } + +} + +/** + * xemacps_probe - Platform driver probe + * @pdev: Pointer to platform device structure + * + * Return 0 on success, negative value if error + */ +static int xemacps_probe(struct platform_device *pdev) +{ + struct resource *r_mem = NULL; + struct resource *r_irq = NULL; + struct net_device *ndev; + struct net_local *lp; + u32 regval = 0; + int rc = -ENXIO; + + r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!r_mem || !r_irq) { + dev_err(&pdev->dev, "no IO resource defined.\n"); + return -ENXIO; + } + + ndev = alloc_etherdev(sizeof(*lp)); + if (!ndev) { + dev_err(&pdev->dev, "etherdev allocation failed.\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + lp = netdev_priv(ndev); + lp->pdev = pdev; + lp->ndev = ndev; + + spin_lock_init(&lp->tx_lock); + spin_lock_init(&lp->rx_lock); + spin_lock_init(&lp->nwctrlreg_lock); + + lp->baseaddr = devm_ioremap_resource(&pdev->dev, r_mem); + if (IS_ERR(lp->baseaddr)) { + rc = PTR_ERR(lp->baseaddr); + goto err_out_free_netdev; + } + + dev_dbg(&lp->pdev->dev, "BASEADDRESS hw: %p virt: %p\n", + (void *)r_mem->start, lp->baseaddr); + + ndev->irq = platform_get_irq(pdev, 0); + + ndev->netdev_ops = &netdev_ops; + ndev->watchdog_timeo = TX_TIMEOUT; + ndev->ethtool_ops = &xemacps_ethtool_ops; + ndev->base_addr = r_mem->start; + ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG; + netif_napi_add(ndev, &lp->napi, xemacps_rx_poll, XEMACPS_NAPI_WEIGHT); + + lp->ip_summed = CHECKSUM_UNNECESSARY; + + rc = register_netdev(ndev); + if (rc) { + dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); + goto err_out_free_netdev; + } + + if (ndev->irq == 54) + lp->enetnum = 0; + else + lp->enetnum = 1; + + lp->aperclk = devm_clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(lp->aperclk)) { + dev_err(&pdev->dev, "aper_clk clock not found.\n"); + rc = PTR_ERR(lp->aperclk); + goto err_out_unregister_netdev; + } + lp->devclk = devm_clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(lp->devclk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + rc = PTR_ERR(lp->devclk); + goto err_out_unregister_netdev; + } + + rc = clk_prepare_enable(lp->aperclk); + if (rc) { + dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + goto err_out_unregister_netdev; + } + rc = clk_prepare_enable(lp->devclk); + if (rc) { + dev_err(&pdev->dev, "Unable to enable device clock.\n"); + goto err_out_clk_dis_aper; + } + + lp->clk_rate_change_nb.notifier_call = xemacps_clk_notifier_cb; + lp->clk_rate_change_nb.next = NULL; + if (clk_notifier_register(lp->devclk, &lp->clk_rate_change_nb)) + dev_warn(&pdev->dev, + "Unable to register clock notifier.\n"); + + lp->phy_node = of_parse_phandle(lp->pdev->dev.of_node, + "phy-handle", 0); + lp->gmii2rgmii_phy_node = of_parse_phandle(lp->pdev->dev.of_node, + "gmii2rgmii-phy-handle", 0); + rc = of_get_phy_mode(lp->pdev->dev.of_node); + if (rc < 0) { + dev_err(&lp->pdev->dev, "error in getting phy i/f\n"); + goto err_out_unregister_clk_notifier; + } + + lp->phy_interface = rc; + + /* Set MDIO clock divider */ + regval = (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK); + xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval); + + + regval = XEMACPS_NWCTRL_MDEN_MASK; + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regval); + + rc = xemacps_mii_init(lp); + if (rc) { + dev_err(&lp->pdev->dev, "error in xemacps_mii_init\n"); + goto err_out_unregister_clk_notifier; + } + + xemacps_update_hwaddr(lp); + tasklet_init(&lp->tx_bdreclaim_tasklet, xemacps_tx_poll, + (unsigned long) ndev); + tasklet_disable(&lp->tx_bdreclaim_tasklet); + + lp->txtimeout_handler_wq = create_singlethread_workqueue(DRIVER_NAME); + INIT_WORK(&lp->txtimeout_reinit, xemacps_reinit_for_txtimeout); + + platform_set_drvdata(pdev, ndev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + dev_info(&lp->pdev->dev, "pdev->id %d, baseaddr 0x%08lx, irq %d\n", + pdev->id, ndev->base_addr, ndev->irq); + + rc = devm_request_irq(&pdev->dev, ndev->irq, &xemacps_interrupt, 0, + ndev->name, ndev); + if (rc) { + dev_err(&lp->pdev->dev, "Unable to request IRQ %p, error %d\n", + r_irq, rc); + goto err_out_unregister_clk_notifier; + } + + return 0; + +err_out_unregister_clk_notifier: + clk_notifier_unregister(lp->devclk, &lp->clk_rate_change_nb); + clk_disable_unprepare(lp->devclk); +err_out_clk_dis_aper: + clk_disable_unprepare(lp->aperclk); +err_out_unregister_netdev: + unregister_netdev(ndev); +err_out_free_netdev: + free_netdev(ndev); + + return rc; +} + +/** + * xemacps_remove - called when platform driver is unregistered + * @pdev: Pointer to the platform device structure + * + * return: 0 on success + */ +static int xemacps_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct net_local *lp; + + if (ndev) { + lp = netdev_priv(ndev); + + mdiobus_unregister(lp->mii_bus); + kfree(lp->mii_bus->irq); + mdiobus_free(lp->mii_bus); + unregister_netdev(ndev); + + clk_notifier_unregister(lp->devclk, &lp->clk_rate_change_nb); + if (!pm_runtime_suspended(&pdev->dev)) { + clk_disable_unprepare(lp->devclk); + clk_disable_unprepare(lp->aperclk); + } else { + clk_unprepare(lp->devclk); + clk_unprepare(lp->aperclk); + } + + free_netdev(ndev); + } + + return 0; +} + +#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP +/** + * xemacps_suspend - Suspend event + * @device: Pointer to device structure + * + * Return 0 + */ +static int xemacps_suspend(struct device *device) +{ + struct platform_device *pdev = container_of(device, + struct platform_device, dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct net_local *lp = netdev_priv(ndev); + + netif_device_detach(ndev); + if (!pm_runtime_suspended(device)) { + clk_disable(lp->devclk); + clk_disable(lp->aperclk); + } + return 0; +} + +/** + * xemacps_resume - Resume after previous suspend + * @pdev: Pointer to platform device structure + * + * Returns 0 on success, errno otherwise. + */ +static int xemacps_resume(struct device *device) +{ + struct platform_device *pdev = container_of(device, + struct platform_device, dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct net_local *lp = netdev_priv(ndev); + + if (!pm_runtime_suspended(device)) { + int ret; + + ret = clk_enable(lp->aperclk); + if (ret) + return ret; + + ret = clk_enable(lp->devclk); + if (ret) { + clk_disable(lp->aperclk); + return ret; + } + } + netif_device_attach(ndev); + return 0; +} +#endif /* ! CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_RUNTIME +static int xemacps_runtime_idle(struct device *dev) +{ + return pm_schedule_suspend(dev, 1); +} + +static int xemacps_runtime_resume(struct device *device) +{ + int ret; + struct platform_device *pdev = container_of(device, + struct platform_device, dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct net_local *lp = netdev_priv(ndev); + + ret = clk_enable(lp->aperclk); + if (ret) + return ret; + + ret = clk_enable(lp->devclk); + if (ret) { + clk_disable(lp->aperclk); + return ret; + } + + return 0; +} + +static int xemacps_runtime_suspend(struct device *device) +{ + struct platform_device *pdev = container_of(device, + struct platform_device, dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct net_local *lp = netdev_priv(ndev); + + clk_disable(lp->devclk); + clk_disable(lp->aperclk); + return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +static const struct dev_pm_ops xemacps_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xemacps_suspend, xemacps_resume) + SET_RUNTIME_PM_OPS(xemacps_runtime_suspend, xemacps_runtime_resume, + xemacps_runtime_idle) +}; +#define XEMACPS_PM (&xemacps_dev_pm_ops) +#else /* ! CONFIG_PM */ +#define XEMACPS_PM NULL +#endif /* ! CONFIG_PM */ + +static struct net_device_ops netdev_ops = { + .ndo_open = xemacps_open, + .ndo_stop = xemacps_close, + .ndo_start_xmit = xemacps_start_xmit, + .ndo_set_rx_mode = xemacps_set_rx_mode, + .ndo_set_mac_address = xemacps_set_mac_address, + .ndo_do_ioctl = xemacps_ioctl, + .ndo_change_mtu = xemacps_change_mtu, + .ndo_tx_timeout = xemacps_tx_timeout, + .ndo_get_stats = xemacps_get_stats, +}; + +static struct of_device_id xemacps_of_match[] = { + { .compatible = "xlnx,ps7-ethernet-1.00.a", }, + { /* end of table */} +}; +MODULE_DEVICE_TABLE(of, xemacps_of_match); + +static struct platform_driver xemacps_driver = { + .probe = xemacps_probe, + .remove = xemacps_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = xemacps_of_match, + .pm = XEMACPS_PM, + }, +}; + +module_platform_driver(xemacps_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx Ethernet driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/Makefile 2014-07-20 22:06:37.153292572 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# Makefile for the Xilinx Tri-mode ethernet driver +# + +EXTRA_CFLAGS += -Idrivers/xilinx_common + +# The Linux adapter for the Xilinx driver code. +xilinx_temac-objs := xlltemac_main.o xlltemac.o xlltemac_control.o + +obj-$(CONFIG_XILINX_LLTEMAC) := xilinx_temac.o Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac.c 2014-07-20 22:06:37.174292225 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xlltemac.c + * + * The XLlTemac driver. Functions in this file are the minimum required functions + * for this driver. See xlltemac.h for a detailed description of the driver. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a jvb 11/10/06 First release + * </pre> + ******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include <linux/dma-mapping.h> +#include <linux/string.h> +#include <linux/delay.h> + +#include "xlltemac.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +static void InitHw(XLlTemac *InstancePtr); /* HW reset */ + +/************************** Variable Definitions *****************************/ + +xdbg_stmnt(int indent_on = 0; + + ) + xdbg_stmnt(u32 _xlltemac_rir_value; + + ) + +/*****************************************************************************/ +/** + * + * XLlTemac_CfgInitialize initializes a TEMAC channel along with the + * <i>InstancePtr</i> that references it. Each TEMAC channel is treated as a + * separate device from the point of view of this driver. + * + * The PHY is setup independently from the TEMAC. Use the MII or whatever other + * interface may be present for setup. + * + * @param InstancePtr references the memory instance to be associated with + * the TEMAC channel upon initialization. + * @param CfgPtr references the structure holding the hardware configuration + * for the TEMAC channel to initialize. + * @param EffectiveAddress is the processor address used to access the + * base address of the TEMAC channel. In systems with an MMU and virtual + * memory, <i>EffectiveAddress</i> is the virtual address mapped to the + * physical in <code>ConfigPtr->Config.BaseAddress</code>. In systems + * without an active MMU, <i>EffectiveAddress</i> should be set to the + * same value as <code>ConfigPtr->Config.BaseAddress</code>. + * + * @return XLlTemac_CfgInitialize returns XST_SUCCESS. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + * + ******************************************************************************/ + int XLlTemac_CfgInitialize(XLlTemac *InstancePtr, + XLlTemac_Config *CfgPtr, u32 EffectiveAddress) +{ + /* Verify arguments */ + XASSERT_NONVOID(InstancePtr != NULL); + + /* Clear instance memory and make copy of configuration */ + memset(InstancePtr, 0, sizeof(XLlTemac)); + memcpy(&InstancePtr->Config, CfgPtr, sizeof(XLlTemac_Config)); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_CfgInitialize\n"); + /* Set device base address */ + InstancePtr->Config.BaseAddress = EffectiveAddress; + + /* Reset the hardware and set default options */ + InstancePtr->IsReady = XCOMPONENT_IS_READY; + + XLlTemac_Reset(InstancePtr, XTE_NORESET_HARD); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "Temac_CfgInitialize: returning SUCCESS\n"); + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** + * XLlTemac_Start starts the TEMAC channel as follows: + * - Enable transmitter if XTE_TRANSMIT_ENABLE_OPTION is set + * - Enable receiver if XTE_RECEIVER_ENABLE_OPTION is set + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return N/A + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +void XLlTemac_Start(XLlTemac *InstancePtr) +{ + u32 Reg; + + /* Assert bad arguments and conditions */ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + /* If already started, then there is nothing to do */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_Start\n"); + /* Enable transmitter if not already enabled */ + if (InstancePtr->Options & XTE_TRANSMITTER_ENABLE_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, "enabling transmitter\n"); + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TC_OFFSET); + if (!(Reg & XTE_TC_TX_MASK)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "transmitter not enabled, enabling now\n"); + XLlTemac_WriteIndirectReg(InstancePtr->Config. + BaseAddress, XTE_TC_OFFSET, + Reg | XTE_TC_TX_MASK); + } + xdbg_printf(XDBG_DEBUG_GENERAL, "transmitter enabled\n"); + } + + /* Enable receiver */ + if (InstancePtr->Options & XTE_RECEIVER_ENABLE_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, "enabling receiver\n"); + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + if (!(Reg & XTE_RCW1_RX_MASK)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "receiver not enabled, enabling now\n"); + + XLlTemac_WriteIndirectReg(InstancePtr->Config. + BaseAddress, XTE_RCW1_OFFSET, + Reg | XTE_RCW1_RX_MASK); + } + xdbg_printf(XDBG_DEBUG_GENERAL, "receiver enabled\n"); + } + + /* Mark as started */ + InstancePtr->IsStarted = XCOMPONENT_IS_STARTED; + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_Start: done\n"); +} + +/*****************************************************************************/ +/** + * XLlTemac_Stop gracefully stops the TEMAC channel as follows: + * - Disable all interrupts from this device + * - Disable the receiver + * + * XLlTemac_Stop does not modify any of the current device options. + * + * Since the transmitter is not disabled, frames currently in internal buffers + * or in process by a DMA engine are allowed to be transmitted. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return N/A + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +void XLlTemac_Stop(XLlTemac *InstancePtr) +{ + u32 Reg; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + /* If already stopped, then there is nothing to do */ + if (InstancePtr->IsStarted == 0) { + return; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_Stop\n"); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_Stop: disabling interrupts\n"); + /* Disable interrupts */ + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, XTE_IE_OFFSET, 0); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_Stop: disabling receiver\n"); + /* Disable the receiver */ + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + Reg &= ~XTE_RCW1_RX_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET, Reg); + + /* Stopping the receiver in mid-packet causes a dropped packet indication + * from HW. Clear it. + */ + /* get the interrupt pending register */ + Reg = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, XTE_IP_OFFSET); + if (Reg & XTE_INT_RXRJECT_MASK) { + /* set the interrupt status register to clear the interrupt */ + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, + XTE_IS_OFFSET, XTE_INT_RXRJECT_MASK); + } + + /* Mark as stopped */ + InstancePtr->IsStarted = 0; + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_Stop: done\n"); +} + + +/*****************************************************************************/ +/** + * XLlTemac_Reset performs a reset of the TEMAC channel, specified by + * <i>InstancePtr</i>, or both channels if <i>HardCoreAction</i> is set to + * XTE_RESET_HARD. + * + * XLlTemac_Reset also resets the TEMAC channel's options to their default values. + * + * The calling software is responsible for re-configuring the TEMAC channel + * (if necessary) and restarting the MAC after the reset. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param HardCoreAction describes how XLlTemac_Reset should treat the hard core + * block of the TEMAC.<br><br> + * + * If XTE_RESET_HARD is set to XTE_RESET_HARD, then XLlTemac_Reset asserts + * the reset signal to the hard core block which will reset both channels + * of the TEMAC. This, of course, will bork any activity that may be + * occuring on the other channel. So, be careful here.<br><br> + * + * Otherwise, XLlTemac_Reset resets just the transmitter and receiver of + * this TEMAC channel. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +void XLlTemac_Reset(XLlTemac *InstancePtr, int HardCoreAction) +{ + u32 Reg; + u32 TimeoutCount = 2; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_Reset\n"); + /* Stop the device and reset HW */ + XLlTemac_Stop(InstancePtr); + InstancePtr->Options = XTE_DEFAULT_OPTIONS; + + /* Reset the receiver */ + xdbg_printf(XDBG_DEBUG_GENERAL, "resetting the receiver\n"); + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + Reg |= XTE_RCW1_RST_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET, Reg); + + /* Reset the transmitter */ + xdbg_printf(XDBG_DEBUG_GENERAL, "resetting the transmitter\n"); + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TC_OFFSET); + Reg |= XTE_TC_RST_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TC_OFFSET, Reg); + + xdbg_printf(XDBG_DEBUG_GENERAL, "waiting until reset is done\n"); + /* Poll until the reset is done */ + while (Reg & (XTE_RCW1_RST_MASK | XTE_TC_RST_MASK)) { + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + Reg |= XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TC_OFFSET); + } + + /* Reset hard core if required */ + /* Resetting hard core will cause both channels to reset :-( */ + if (HardCoreAction == XTE_RESET_HARD) { + xdbg_printf(XDBG_DEBUG_GENERAL, "hard reset\n"); + Reg = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET); + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET, Reg | XTE_RAF_HTRST_MASK); + while (TimeoutCount && + (!(XLlTemac_ReadReg + (InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & XTE_RDY_HARD_ACS_RDY_MASK))) { + udelay(XTE_RESET_HARD_DELAY_US); + TimeoutCount--; + } + } + + /* Setup HW */ + InitHw(InstancePtr); +} + + +/****************************************************************************** + * InitHw (internal use only) performs a one-time setup of a TEMAC channel. The + * setup performed here only need to occur once after any reset. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +static void InitHw(XLlTemac *InstancePtr) +{ + u32 Reg; + + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac InitHw\n"); + /* Disable the receiver */ + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac InitHw\n"); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac InitHw: disabling receiver\n"); + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + Reg &= ~XTE_RCW1_RX_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET, Reg); + + /* + * Stopping the receiver in mid-packet causes a dropped packet + * indication from HW. Clear it. + */ + /* get the interrupt pending register */ + Reg = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, XTE_IP_OFFSET); + if (Reg & XTE_INT_RXRJECT_MASK) { + /* + * set the interrupt status register to clear the pending + * interrupt + */ + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, + XTE_IS_OFFSET, XTE_INT_RXRJECT_MASK); + } + + /* Sync default options with HW but leave receiver and transmitter + * disabled. They get enabled with XLlTemac_Start() if + * XTE_TRANSMITTER_ENABLE_OPTION and XTE_RECEIVER_ENABLE_OPTION are set + */ + XLlTemac_SetOptions(InstancePtr, InstancePtr->Options & + ~(XTE_TRANSMITTER_ENABLE_OPTION | + XTE_RECEIVER_ENABLE_OPTION)); + + XLlTemac_ClearOptions(InstancePtr, ~InstancePtr->Options); + + /* Set default MDIO divisor */ + XLlTemac_PhySetMdioDivisor(InstancePtr, XTE_MDIO_DIV_DFT); + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac InitHw: done\n"); +} + +/*****************************************************************************/ +/** + * XLlTemac_SetMacAddress sets the MAC address for the TEMAC channel, specified + * by <i>InstancePtr</i> to the MAC address specified by <i>AddressPtr</i>. + * The TEMAC channel must be stopped before calling this function. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param AddressPtr is a reference to the 6-byte MAC address to set. + * + * @return On successful completion, XLlTemac_SetMacAddress returns XST_SUCCESS. + * Otherwise, if the TEMAC channel has not stopped, + * XLlTemac_SetMacAddress returns XST_DEVICE_IS_STARTED. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_SetMacAddress(XLlTemac *InstancePtr, void *AddressPtr) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_NONVOID(AddressPtr != NULL); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_SetMacAddress: setting mac address to: 0x%08x%8x%8x%8x%8x%8x\n", + Aptr[0], Aptr[1], Aptr[2], Aptr[3], Aptr[4], Aptr[5]); + /* + * Set the MAC bits [31:0] in UAW0 + * Having Aptr be unsigned type prevents the following operations from sign extending + */ + MacAddr = Aptr[0]; + MacAddr |= Aptr[1] << 8; + MacAddr |= Aptr[2] << 16; + MacAddr |= Aptr[3] << 24; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_UAW0_OFFSET, MacAddr); + + /* There are reserved bits in UAW1 so don't affect them */ + MacAddr = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_UAW1_OFFSET); + MacAddr &= ~XTE_UAW1_UNICASTADDR_MASK; + + /* Set MAC bits [47:32] in UAW1 */ + MacAddr |= Aptr[4]; + MacAddr |= Aptr[5] << 8; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_UAW1_OFFSET, MacAddr); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * XLlTemac_GetMacAddress gets the MAC address for the TEMAC channel, specified + * by <i>InstancePtr</i> into the memory buffer specified by <i>AddressPtr</i>. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param AddressPtr references the memory buffer to store the retrieved MAC + * address. This memory buffer must be at least 6 bytes in length. + * + * @return N/A + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +void XLlTemac_GetMacAddress(XLlTemac *InstancePtr, void *AddressPtr) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + /* Read MAC bits [31:0] in UAW0 */ + MacAddr = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_UAW0_OFFSET); + Aptr[0] = (u8) MacAddr; + Aptr[1] = (u8) (MacAddr >> 8); + Aptr[2] = (u8) (MacAddr >> 16); + Aptr[3] = (u8) (MacAddr >> 24); + + /* Read MAC bits [47:32] in UAW1 */ + MacAddr = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_UAW1_OFFSET); + Aptr[4] = (u8) MacAddr; + Aptr[5] = (u8) (MacAddr >> 8); +} + +/*****************************************************************************/ +/** + * XLlTemac_SetOptions enables the options, <i>Options</i> for the TEMAC channel, + * specified by <i>InstancePtr</i>. The TEMAC channel should be stopped with + * XLlTemac_Stop() before changing options. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param Options is a bitmask of OR'd XTE_*_OPTION values for options to + * set. Options not specified are not affected. + * + * @return On successful completion, XLlTemac_SetOptions returns XST_SUCCESS. + * Otherwise, if the device has not been stopped, XLlTemac_SetOptions + * returns XST_DEVICE_IS_STARTED. + * + * @note + * See xlltemac.h for a description of the available options. + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_SetOptions(XLlTemac *InstancePtr, u32 Options) +{ + u32 Reg; /* Generic register contents */ + u32 RegRcw1; /* Reflects original contents of RCW1 */ + u32 RegTc; /* Reflects original contents of TC */ + u32 RegNewRcw1; /* Reflects new contents of RCW1 */ + u32 RegNewTc; /* Reflects new contents of TC */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_SetOptions\n"); + /* Many of these options will change the RCW1 or TC registers. + * To reduce the amount of IO to the device, group these options here + * and change them all at once. + */ + + /* Grab current register contents */ + RegRcw1 = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + RegTc = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TC_OFFSET); + RegNewRcw1 = RegRcw1; + RegNewTc = RegTc; + + xdbg_printf(XDBG_DEBUG_GENERAL, + "current control regs: RCW1: 0x%0x; TC: 0x%0x\n", RegRcw1, + RegTc); + xdbg_printf(XDBG_DEBUG_GENERAL, + "Options: 0x%0x; default options: 0x%0x\n", Options, + XTE_DEFAULT_OPTIONS); + + /* Turn on jumbo packet support for both Rx and Tx */ + if (Options & XTE_JUMBO_OPTION) { + RegNewTc |= XTE_TC_JUM_MASK; + RegNewRcw1 |= XTE_RCW1_JUM_MASK; + } + + /* Turn on VLAN packet support for both Rx and Tx */ + if (Options & XTE_VLAN_OPTION) { + RegNewTc |= XTE_TC_VLAN_MASK; + RegNewRcw1 |= XTE_RCW1_VLAN_MASK; + } + + /* Turn on FCS stripping on receive packets */ + if (Options & XTE_FCS_STRIP_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: enabling fcs stripping\n"); + RegNewRcw1 &= ~XTE_RCW1_FCS_MASK; + } + + /* Turn on FCS insertion on transmit packets */ + if (Options & XTE_FCS_INSERT_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: enabling fcs insertion\n"); + RegNewTc &= ~XTE_TC_FCS_MASK; + } + + /* Turn on length/type field checking on receive packets */ + if (Options & XTE_LENTYPE_ERR_OPTION) { + RegNewRcw1 &= ~XTE_RCW1_LT_DIS_MASK; + } + + /* Enable transmitter */ + if (Options & XTE_TRANSMITTER_ENABLE_OPTION) { + RegNewTc |= XTE_TC_TX_MASK; + } + + /* Enable receiver */ + if (Options & XTE_RECEIVER_ENABLE_OPTION) { + RegNewRcw1 |= XTE_RCW1_RX_MASK; + } + + /* Change the TC or RCW1 registers if they need to be modified */ + if (RegTc != RegNewTc) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: writting tc: 0x%0x\n", RegNewTc); + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TC_OFFSET, RegNewTc); + } + + if (RegRcw1 != RegNewRcw1) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: writting rcw1: 0x%0x\n", RegNewRcw1); + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET, RegNewRcw1); + } + + /* Rest of options twiddle bits of other registers. Handle them one at + * a time + */ + + /* Turn on flow control */ + if (Options & XTE_FLOW_CONTROL_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: endabling flow control\n"); + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_FCC_OFFSET); + Reg |= XTE_FCC_FCRX_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_FCC_OFFSET, Reg); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (fcc): 0x%0x\n", + XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET)); + + /* Turn on promiscuous frame filtering (all frames are received ) */ + if (Options & XTE_PROMISC_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: endabling promiscuous mode\n"); + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_AFM_OFFSET); + Reg |= XTE_AFM_PM_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_AFM_OFFSET, Reg); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (afm): 0x%0x\n", + XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET)); + + /* Allow broadcast address filtering */ + if (Options & XTE_BROADCAST_OPTION) { + Reg = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET); + Reg &= ~XTE_RAF_BCSTREJ_MASK; + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET, Reg); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (raf): 0x%0x\n", + XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET)); + + /* Allow multicast address filtering */ + if (Options & XTE_MULTICAST_OPTION) { + Reg = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET); + Reg &= ~XTE_RAF_MCSTREJ_MASK; + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET, Reg); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (raf2): 0x%0x\n", + XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET)); + + /* The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. Reflecting the + * option in InstancePtr->Options is good enough for now. + */ + + /* Set options word to its new value */ + InstancePtr->Options |= Options; + + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (end): 0x%0x\n", + XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET)); + xdbg_printf(XDBG_DEBUG_GENERAL, "setOptions: returning SUCCESS\n"); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * XLlTemac_ClearOptions clears the options, <i>Options</i> for the TEMAC channel, + * specified by <i>InstancePtr</i>. The TEMAC channel should be stopped with + * XLlTemac_Stop() before changing options. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param Options is a bitmask of OR'd XTE_*_OPTION values for options to + * clear. Options not specified are not affected. + * + * @return On successful completion, XLlTemac_ClearOptions returns XST_SUCCESS. + * Otherwise, if the device has not been stopped, XLlTemac_ClearOptions + * returns XST_DEVICE_IS_STARTED. + * + * @note + * See xlltemac.h for a description of the available options. + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_ClearOptions(XLlTemac *InstancePtr, u32 Options) +{ + u32 Reg; /* Generic */ + u32 RegRcw1; /* Reflects original contents of RCW1 */ + u32 RegTc; /* Reflects original contents of TC */ + u32 RegNewRcw1; /* Reflects new contents of RCW1 */ + u32 RegNewTc; /* Reflects new contents of TC */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "Xtemac_ClearOptions: 0x%08x\n", + Options); + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Many of these options will change the RCW1 or TC registers. + * Group these options here and change them all at once. What we are + * trying to accomplish is to reduce the amount of IO to the device + */ + + /* Grab current register contents */ + RegRcw1 = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + RegTc = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TC_OFFSET); + RegNewRcw1 = RegRcw1; + RegNewTc = RegTc; + + /* Turn off jumbo packet support for both Rx and Tx */ + if (Options & XTE_JUMBO_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: disabling jumbo\n"); + RegNewTc &= ~XTE_TC_JUM_MASK; + RegNewRcw1 &= ~XTE_RCW1_JUM_MASK; + } + + /* Turn off VLAN packet support for both Rx and Tx */ + if (Options & XTE_VLAN_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: disabling vlan\n"); + RegNewTc &= ~XTE_TC_VLAN_MASK; + RegNewRcw1 &= ~XTE_RCW1_VLAN_MASK; + } + + /* Turn off FCS stripping on receive packets */ + if (Options & XTE_FCS_STRIP_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: disabling fcs strip\n"); + RegNewRcw1 |= XTE_RCW1_FCS_MASK; + } + + /* Turn off FCS insertion on transmit packets */ + if (Options & XTE_FCS_INSERT_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: disabling fcs insert\n"); + RegNewTc |= XTE_TC_FCS_MASK; + } + + /* Turn off length/type field checking on receive packets */ + if (Options & XTE_LENTYPE_ERR_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: disabling lentype err\n"); + RegNewRcw1 |= XTE_RCW1_LT_DIS_MASK; + } + + /* Disable transmitter */ + if (Options & XTE_TRANSMITTER_ENABLE_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: disabling transmitter\n"); + RegNewTc &= ~XTE_TC_TX_MASK; + } + + /* Disable receiver */ + if (Options & XTE_RECEIVER_ENABLE_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: disabling receiver\n"); + RegNewRcw1 &= ~XTE_RCW1_RX_MASK; + } + + /* Change the TC and RCW1 registers if they need to be + * modified + */ + if (RegTc != RegNewTc) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: setting TC: 0x%0x\n", + RegNewTc); + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TC_OFFSET, RegNewTc); + } + + if (RegRcw1 != RegNewRcw1) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: setting RCW1: 0x%0x\n", + RegNewRcw1); + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET, RegNewRcw1); + } + + /* Rest of options twiddle bits of other registers. Handle them one at + * a time + */ + + /* Turn off flow control */ + if (Options & XTE_FLOW_CONTROL_OPTION) { + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_FCC_OFFSET); + Reg &= ~XTE_FCC_FCRX_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_FCC_OFFSET, Reg); + } + + /* Turn off promiscuous frame filtering */ + if (Options & XTE_PROMISC_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: disabling promiscuous mode\n"); + Reg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_AFM_OFFSET); + Reg &= ~XTE_AFM_PM_MASK; + xdbg_printf(XDBG_DEBUG_GENERAL, + "Xtemac_ClearOptions: setting AFM: 0x%0x\n", Reg); + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_AFM_OFFSET, Reg); + } + + /* Disable broadcast address filtering */ + if (Options & XTE_BROADCAST_OPTION) { + Reg = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET); + Reg |= XTE_RAF_BCSTREJ_MASK; + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET, Reg); + } + + /* Disable multicast address filtering */ + if (Options & XTE_MULTICAST_OPTION) { + Reg = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET); + Reg |= XTE_RAF_MCSTREJ_MASK; + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, + XTE_RAF_OFFSET, Reg); + } + + /* The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. Reflecting the + * option in InstancePtr->Options is good enough for now. + */ + + /* Set options word to its new value */ + InstancePtr->Options &= ~Options; + + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * XLlTemac_GetOptions returns the current option settings. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XLlTemac_GetOptions returns a bitmask of XTE_*_OPTION constants, + * each bit specifying an option that is currently active. + * + * @note + * See xlltemac.h for a description of the available options. + * + ******************************************************************************/ +u32 XLlTemac_GetOptions(XLlTemac *InstancePtr) +{ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + return (InstancePtr->Options); +} + +/*****************************************************************************/ +/** + * XLlTemac_GetOperatingSpeed gets the current operating link speed. This may be + * the value set by XLlTemac_SetOperatingSpeed() or a hardware default. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XLlTemac_GetOperatingSpeed returns the link speed in units of megabits + * per second. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +u16 XLlTemac_GetOperatingSpeed(XLlTemac *InstancePtr) +{ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_GetOperatingSpeed\n"); + switch (XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_EMMC_OFFSET) & + XTE_EMMC_LINKSPEED_MASK) { + case XTE_EMMC_LINKSPD_1000: + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_GetOperatingSpeed: returning 1000\n"); + return (1000); + + case XTE_EMMC_LINKSPD_100: + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_GetOperatingSpeed: returning 100\n"); + return (100); + + case XTE_EMMC_LINKSPD_10: + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_GetOperatingSpeed: returning 10\n"); + return (10); + + default: + return (0); + } +} + + +/*****************************************************************************/ +/** + * XLlTemac_SetOperatingSpeed sets the current operating link speed. For any + * traffic to be passed, this speed must match the current MII/GMII/SGMII/RGMII + * link speed. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param Speed is the speed to set in units of Mbps. Valid values are 10, 100, + * or 1000. XLlTemac_SetOperatingSpeed ignores invalid values. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +void XLlTemac_SetOperatingSpeed(XLlTemac *InstancePtr, u16 Speed) +{ + u32 EmmcReg; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_VOID((Speed == 10) || (Speed == 100) || (Speed == 1000)); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_SetOperatingSpeed\n"); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_SetOperatingSpeed: setting speed to: %d (0x%0x)\n", + Speed, Speed); + /* Get the current contents of the EMAC config register and zero out + * speed bits + */ + EmmcReg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_EMMC_OFFSET) & + ~XTE_EMMC_LINKSPEED_MASK; + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_SetOperatingSpeed: current speed: 0x%0x\n", + EmmcReg); + switch (Speed) { + case 10: + break; + + case 100: + EmmcReg |= XTE_EMMC_LINKSPD_100; + break; + + case 1000: + EmmcReg |= XTE_EMMC_LINKSPD_1000; + break; + + default: + return; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_SetOperatingSpeed: new speed: 0x%0x\n", EmmcReg); + /* Set register and return */ + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_EMMC_OFFSET, EmmcReg); + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_SetOperatingSpeed: done\n"); +} + +/*****************************************************************************/ +/** + * XLlTemac_PhySetMdioDivisor sets the MDIO clock divisor in the TEMAC channel, + * specified by <i>InstancePtr</i> to the value, <i>Divisor</i>. This function + * must be called once after each reset prior to accessing MII PHY registers. + * + * From the Virtex-4 Embedded Tri-Mode Ethernet MAC User's Guide, the + * following equation governs the MDIO clock to the PHY: + * + * <pre> + * f[HOSTCLK] + * f[MDC] = ----------------- + * (1 + Divisor) * 2 + * </pre> + * + * where f[HOSTCLK] is the bus clock frequency in MHz, and f[MDC] is the + * MDIO clock frequency in MHz to the PHY. Typically, f[MDC] should not + * exceed 2.5 MHz. Some PHYs can tolerate faster speeds which means faster + * access. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param Divisor is the divisor value to set within the range of 0 to + * XTE_MC_CLK_DVD_MAX. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +void XLlTemac_PhySetMdioDivisor(XLlTemac *InstancePtr, u8 Divisor) +{ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY) + XASSERT_VOID(Divisor <= XTE_MC_CLOCK_DIVIDE_MAX); + + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_PhySetMdioDivisor\n"); + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_MC_OFFSET, + (u32) Divisor | XTE_MC_MDIOEN_MASK); +} + +/*****************************************************************************/ +/* + * XLlTemac_PhyRead reads the specified PHY register, <i>RegiseterNum</i> on the + * PHY specified by <i>PhyAddress</i> into <i>PhyDataPtr</i>. This Ethernet + * driver does not require the device to be stopped before reading from the PHY. + * It is the responsibility of the calling code to stop the device if it is + * deemed necessary. + * + * Note that the TEMAC hardware provides the ability to talk to a PHY that + * adheres to the Media Independent Interface (MII) as defined in the IEEE 802.3 + * standard. + * + * <b>It is important that calling code set up the MDIO clock with + * XLlTemac_PhySetMdioDivisor() prior to accessing the PHY with this function.</b> + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param PhyAddress is the address of the PHY to be written (multiple + * PHYs supported). + * @param RegisterNum is the register number, 0-31, of the specific PHY register + * to write. + * @param PhyDataPtr is a reference to the location where the 16-bit result + * value is stored. + * + * @return N/A + * + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr.<br><br> + * + * There is the possibility that this function will not return if the hardware + * is broken (i.e., it never sets the status bit indicating that the write is + * done). If this is of concern, the calling code should provide a mechanism + * suitable for recovery. + * + ******************************************************************************/ +void XLlTemac_PhyRead(XLlTemac *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr) +{ + u32 MiiReg; + u32 Rdy; + u32 Ie; + u32 Tis; + + XASSERT_VOID(InstancePtr != NULL); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_PhyRead: BaseAddress: 0x%08x\n", + InstancePtr->Config.BaseAddress); + /* + * XLlTemac_PhyRead saves the state of the IE register so that it can + * clear the HardAcsCmplt bit and later restore the state of the IE + * register. Since XLlTemac_PhyRead will poll for the status already, the + * HardAcsCmplt bit is cleared in the IE register so that the + * application code above doesn't also receive the interrupt. + */ + Ie = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, XTE_IE_OFFSET); + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, XTE_IE_OFFSET, + Ie & ~XTE_INT_HARDACSCMPLT_MASK); + + /* + * This is a double indirect mechanism. We indirectly write the + * PHYAD and REGAD so we can read the PHY register back out in + * the LSW register. + * + * In this case, the method of reading the data is a little unusual. + * Normally to write to a TEMAC register, one would set the WEN bit + * in the CTL register so that the values of the LSW will be written. + * + * In this case, the WEN bit is not set, and the PHYAD and REGAD + * values in the LSW will still get sent to the PHY before actually + * reading the result in the LSW. + * + * What needs to be done, is the following: + * 1) Write lsw reg with the phyad, and the regad + * 2) write the ctl reg with the miimai value (BUT WEN bit set to 0!!!) + * 3) poll the ready bit + * 4) get the value out of lsw + */ + MiiReg = RegisterNum & XTE_MIIM_REGAD_MASK; + MiiReg |= ((PhyAddress << XTE_MIIM_PHYAD_SHIFT) & XTE_MIIM_PHYAD_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_PhyRead: Mii Reg: 0x%0x; Value written: 0x%0x\n", + RegisterNum, MiiReg); + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, XTE_LSW_OFFSET, + MiiReg); + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, XTE_CTL_OFFSET, + XTE_MIIMAI_OFFSET); + + /* + * Wait here polling, until the value is ready to be read. + */ + do { + Rdy = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET); + } while (!(Rdy & XTE_RSE_MIIM_RR_MASK)); + + /* Read data */ + *PhyDataPtr = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_LSW_OFFSET); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_PhyRead: Value retrieved: 0x%0x\n", *PhyDataPtr); + + /* + * Clear MII status bits. The TIS register in the hard TEMAC doesn't + * use the 'write a 1 to clear' method, so we need to read the TIS + * register, clear the MIIM RST bit, and then write it back out. + */ + Tis = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TIS_OFFSET); + Tis &= ~XTE_RSE_MIIM_RR_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TIS_OFFSET, Tis); + + /* + * restore the state of the IE reg + */ + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, XTE_IE_OFFSET, Ie); +} + + +/*****************************************************************************/ +/* + * XLlTemac_PhyWrite writes <i>PhyData</i> to the specified PHY register, + * <i>RegiseterNum</i> on the PHY specified by <i>PhyAddress</i>. This Ethernet + * driver does not require the device to be stopped before writing to the PHY. + * It is the responsibility of the calling code to stop the device if it is + * deemed necessary. + * + * Note that the TEMAC hardware provides the ability to talk to a PHY that + * adheres to the Media Independent Interface (MII) as defined in the IEEE 802.3 + * standard. + * + * <b>It is important that calling code set up the MDIO clock with + * XLlTemac_PhySetMdioDivisor() prior to accessing the PHY with this function.</b> + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param PhyAddress is the address of the PHY to be written (multiple + * PHYs supported). + * @param RegisterNum is the register number, 0-31, of the specific PHY register + * to write. + * @param PhyData is the 16-bit value that will be written to the register. + * + * @return N/A + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr.<br><br> + * + * There is the possibility that this function will not return if the hardware + * is broken (i.e., it never sets the status bit indicating that the write is + * done). If this is of concern, the calling code should provide a mechanism + * suitable for recovery. + * + ******************************************************************************/ +void XLlTemac_PhyWrite(XLlTemac *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData) +{ + u32 MiiReg; + u32 Rdy; + u32 Ie; + u32 Tis; + + XASSERT_VOID(InstancePtr != NULL); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_PhyWrite\n"); + /* + * XLlTemac_PhyWrite saves the state of the IE register so that it can + * clear the HardAcsCmplt bit and later restore the state of the IE + * register. Since XLlTemac_PhyWrite will poll for the status already, the + * HardAcsCmplt bit is cleared in the IE register so that the + * application code above doesn't also receive the interrupt. + */ + Ie = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, XTE_IE_OFFSET); + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, XTE_IE_OFFSET, + Ie & ~XTE_INT_HARDACSCMPLT_MASK); + + /* + * This is a double indirect mechanism. We indirectly write the + * PhyData to the MIIMWD register, and then indirectly write PHYAD and + * REGAD so the value in MIIMWD will get written to the PHY. + */ + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_MIIMWD_OFFSET, PhyData); + + MiiReg = RegisterNum & XTE_MIIM_REGAD_MASK; + MiiReg |= ((PhyAddress << XTE_MIIM_PHYAD_SHIFT) & XTE_MIIM_PHYAD_MASK); + + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_MIIMAI_OFFSET, MiiReg); + + /* + * Wait here polling, until the value is ready to be read. + */ + do { + Rdy = XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET); + } while (!(Rdy & XTE_RSE_MIIM_WR_MASK)); + + /* + * Clear MII status bits. The TIS register in the hard TEMAC doesn't + * use the 'write a 1 to clear' method, so we need to read the TIS + * register, clear the MIIM WST bit, and then write it back out. + */ + Tis = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TIS_OFFSET); + Tis &= XTE_RSE_MIIM_WR_MASK; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_TIS_OFFSET, Tis); + + /* + * restore the state of the IE reg + */ + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, XTE_IE_OFFSET, Ie); +} Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac_control.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac_control.c 2014-07-20 22:06:37.188291994 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xlltemac_control.c + * + * Functions in this file implement general purpose command and control related + * functionality. See xlltemac.h for a detailed description of the driver. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a jvb 11/10/06 First release + * </pre> + *****************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xlltemac.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** + * in the TEMAC channel's multicast filter list. + * + * XLlTemac_MulticastAdd adds the Ethernet address, <i>AddressPtr</i> to the + * TEMAC channel's multicast filter list, at list index <i>Entry</i>. The + * address referenced by <i>AddressPtr</i> may be of any unicast, multicast, or + * broadcast address form. The harware for the TEMAC channel can hold up to + * XTE_MULTI_MAT_ENTRIES addresses in this filter list.<br><br> + * + * The device must be stopped to use this function.<br><br> + * + * Once an Ethernet address is programmed, the TEMAC channel will begin + * receiving data sent from that address. The TEMAC hardware does not have a + * control bit to disable multicast filtering. The only way to prevent the + * TEMAC channel from receiving messages from an Ethernet address in the + * Multicast Address Table (MAT) is to clear it with XLlTemac_MulticastClear(). + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param AddressPtr is a pointer to the 6-byte Ethernet address to set. The + * previous address at the location <i>Entry</i> (if any) is overwritten + * with the value at <i>AddressPtr</i>. + * @param Entry is the hardware storage location to program this address and + * must be between 0..XTE_MULTI_MAT_ENTRIES-1. + * + * @return On successful completion, XLlTemac_MulticastAdd returns XST_SUCCESS. + * Otherwise, if the TEMAC channel is not stopped, XLlTemac_MulticastAdd + * returns XST_DEVICE_IS_STARTED. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_MulticastAdd(XLlTemac *InstancePtr, void *AddressPtr, int Entry) +{ + u32 Maw0Reg; + u32 Maw1Reg; + u8 *Aptr = (u8 *) AddressPtr; + u32 Rdy; + int MaxWait = 100; + u32 BaseAddress = InstancePtr->Config.BaseAddress; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_NONVOID(AddressPtr != NULL); + XASSERT_NONVOID(Entry < XTE_MULTI_MAT_ENTRIES); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_MulticastAdd\n"); + + /* The device must be stopped before clearing the multicast hash table */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_MulticastAdd: returning DEVICE_IS_STARTED\n"); + + return (XST_DEVICE_IS_STARTED); + } + + /* Set MAC bits [31:0] */ + Maw0Reg = Aptr[0]; + Maw0Reg |= Aptr[1] << 8; + Maw0Reg |= Aptr[2] << 16; + Maw0Reg |= Aptr[3] << 24; + + /* Set MAC bits [47:32] */ + Maw1Reg = Aptr[4]; + Maw1Reg |= Aptr[5] << 8; + + /* Add in MAT address */ + Maw1Reg |= (Entry << XTE_MAW1_MATADDR_SHIFT_MASK); + + /* Program HW */ + xdbg_printf(XDBG_DEBUG_GENERAL, "Setting MAT entry: %d\n", Entry); + XLlTemac_WriteReg(BaseAddress, XTE_LSW_OFFSET, Maw0Reg); + XLlTemac_WriteReg(BaseAddress, XTE_CTL_OFFSET, + XTE_MAW0_OFFSET | XTE_CTL_WEN_MASK); + Rdy = XLlTemac_ReadReg(BaseAddress, XTE_RDY_OFFSET); + while (MaxWait && (!(Rdy & XTE_RDY_HARD_ACS_RDY_MASK))) { + Rdy = XLlTemac_ReadReg(BaseAddress, XTE_RDY_OFFSET); + xdbg_stmnt( + if (MaxWait == 100) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "RDY reg not initially ready\n"); + } + ); + MaxWait--; + xdbg_stmnt( + if (MaxWait == 0) { + xdbg_printf (XDBG_DEBUG_GENERAL, + "RDY reg never showed ready\n"); + } + ) + } + XLlTemac_WriteReg(BaseAddress, XTE_LSW_OFFSET, + Maw1Reg); + XLlTemac_WriteReg(BaseAddress, XTE_CTL_OFFSET, + XTE_MAW1_OFFSET | XTE_CTL_WEN_MASK); + Rdy = XLlTemac_ReadReg(BaseAddress, XTE_RDY_OFFSET); + while (MaxWait && (!(Rdy & XTE_RDY_HARD_ACS_RDY_MASK))) { + Rdy = XLlTemac_ReadReg(BaseAddress, XTE_RDY_OFFSET); + xdbg_stmnt( + if (MaxWait == 100) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "RDY reg not initially ready\n"); + } + ); + MaxWait--; + xdbg_stmnt( + if (MaxWait == 0) { + xdbg_printf (XDBG_DEBUG_GENERAL, + "RDY reg never showed ready\n"); + } + ) + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_MulticastAdd: returning SUCCESS\n"); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * XLlTemac_MulticastGet gets the Ethernet address stored at index <i>Entry</i> + * in the TEMAC channel's multicast filter list.<br><br> + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param AddressPtr references the memory buffer to store the retrieved + * Ethernet address. This memory buffer must be at least 6 bytes in + * length. + * @param Entry is the hardware storage location from which to retrieve the + * address and must be between 0..XTE_MULTI_MAT_ENTRIES-1. + * + * @return N/A + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +void XLlTemac_MulticastGet(XLlTemac *InstancePtr, void *AddressPtr, int Entry) +{ + u32 Maw0Reg; + u32 Maw1Reg; + u8 *Aptr = (u8 *) AddressPtr; + u32 Rdy; + int MaxWait = 100; + u32 BaseAddress = InstancePtr->Config.BaseAddress; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_VOID(Entry < XTE_MULTI_MAT_ENTRIES); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(BaseAddress, XTE_RDY_OFFSET) & + XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_MulticastGet\n"); + + /* + * Tell HW to provide address stored in given entry. + * In this case, the Access is a little weird, becuase we need to + * write the LSW register first, then initiate a write operation, + * even though it's a read operation. + */ + xdbg_printf(XDBG_DEBUG_GENERAL, "Getting MAT entry: %d\n", Entry); + XLlTemac_WriteReg(BaseAddress, XTE_LSW_OFFSET, + Entry << XTE_MAW1_MATADDR_SHIFT_MASK | XTE_MAW1_RNW_MASK); + XLlTemac_WriteReg(BaseAddress, XTE_CTL_OFFSET, + XTE_MAW1_OFFSET | XTE_CTL_WEN_MASK); + Rdy = XLlTemac_ReadReg(BaseAddress, XTE_RDY_OFFSET); + while (MaxWait && (!(Rdy & XTE_RDY_HARD_ACS_RDY_MASK))) { + Rdy = XLlTemac_ReadReg(BaseAddress, XTE_RDY_OFFSET); + xdbg_stmnt( + if (MaxWait == 100) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "RDY reg not initially ready\n"); + } + ); + MaxWait--; + xdbg_stmnt( + if (MaxWait == 0) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "RDY reg never showed ready\n"); + } + ) + + } + Maw0Reg = XLlTemac_ReadReg(BaseAddress, XTE_LSW_OFFSET); + Maw1Reg = XLlTemac_ReadReg(BaseAddress, XTE_MSW_OFFSET); + + /* Copy the address to the user buffer */ + Aptr[0] = (u8) Maw0Reg; + Aptr[1] = (u8) (Maw0Reg >> 8); + Aptr[2] = (u8) (Maw0Reg >> 16); + Aptr[3] = (u8) (Maw0Reg >> 24); + Aptr[4] = (u8) Maw1Reg; + Aptr[5] = (u8) (Maw1Reg >> 8); + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_MulticastGet: done\n"); +} + +/*****************************************************************************/ +/** + * XLlTemac_MulticastClear clears the Ethernet address stored at index <i>Entry</i> + * in the TEMAC channel's multicast filter list.<br><br> + * + * The device must be stopped to use this function.<br><br> + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param Entry is the HW storage location used when this address was added. + * It must be between 0..XTE_MULTI_MAT_ENTRIES-1. + * @param Entry is the hardware storage location to clear and must be between + * 0..XTE_MULTI_MAT_ENTRIES-1. + * + * @return On successful completion, XLlTemac_MulticastClear returns XST_SUCCESS. + * Otherwise, if the TEMAC channel is not stopped, XLlTemac_MulticastClear + * returns XST_DEVICE_IS_STARTED. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_MulticastClear(XLlTemac *InstancePtr, int Entry) +{ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_NONVOID(Entry < XTE_MULTI_MAT_ENTRIES); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_MulticastClear\n"); + + /* The device must be stopped before clearing the multicast hash table */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_MulticastClear: returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Clear the entry by writing 0:0:0:0:0:0 to it */ + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_MAW0_OFFSET, 0); + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_MAW1_OFFSET, Entry << XTE_MAW1_MATADDR_SHIFT_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_MulticastClear: returning SUCCESS\n"); + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * XLlTemac_SetMacPauseAddress sets the MAC address used for pause frames to + * <i>AddressPtr</i>. <i>AddressPtr</i> will be the address the TEMAC channel + * will recognize as being for pause frames. Pause frames transmitted with + * XLlTemac_SendPausePacket() will also use this address. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param AddressPtr is a pointer to the 6-byte Ethernet address to set. + * + * @return On successful completion, XLlTemac_SetMacPauseAddress returns + * XST_SUCCESS. Otherwise, if the TEMAC channel is not stopped, + * XLlTemac_SetMacPauseAddress returns XST_DEVICE_IS_STARTED. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_SetMacPauseAddress(XLlTemac *InstancePtr, void *AddressPtr) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_SetMacPauseAddress\n"); + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_SetMacPauseAddress: returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Set the MAC bits [31:0] in ERXC0 */ + MacAddr = Aptr[0]; + MacAddr |= Aptr[1] << 8; + MacAddr |= Aptr[2] << 16; + MacAddr |= Aptr[3] << 24; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW0_OFFSET, MacAddr); + + /* ERCW1 contains other info that must be preserved */ + MacAddr = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + MacAddr &= ~XTE_RCW1_PAUSEADDR_MASK; + + /* Set MAC bits [47:32] */ + MacAddr |= Aptr[4]; + MacAddr |= Aptr[5] << 8; + XLlTemac_WriteIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET, MacAddr); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_SetMacPauseAddress: returning SUCCESS\n"); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * XLlTemac_GetMacPauseAddress gets the MAC address used for pause frames for the + * TEMAC channel specified by <i>InstancePtr</i>. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param AddressPtr references the memory buffer to store the retrieved MAC + * address. This memory buffer must be at least 6 bytes in length. + * + * @return N/A + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +void XLlTemac_GetMacPauseAddress(XLlTemac *InstancePtr, void *AddressPtr) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_VOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_SetMacPauseAddress\n"); + + /* Read MAC bits [31:0] in ERXC0 */ + MacAddr = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW0_OFFSET); + Aptr[0] = (u8) MacAddr; + Aptr[1] = (u8) (MacAddr >> 8); + Aptr[2] = (u8) (MacAddr >> 16); + Aptr[3] = (u8) (MacAddr >> 24); + + /* Read MAC bits [47:32] in RCW1 */ + MacAddr = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_RCW1_OFFSET); + Aptr[4] = (u8) MacAddr; + Aptr[5] = (u8) (MacAddr >> 8); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_SetMacPauseAddress: done\n"); +} + +/*****************************************************************************/ +/** + * XLlTemac_SendPausePacket sends a pause packet with the value of + * <i>PauseValue</i>. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param PauseValue is the pause value in units of 512 bit times. + * + * @return On successful completion, XLlTemac_SendPausePacket returns + * XST_SUCCESS. Otherwise, if the TEMAC channel is not started, + * XLlTemac_SendPausePacket returns XST_DEVICE_IS_STOPPED. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_SendPausePacket(XLlTemac *InstancePtr, u16 PauseValue) +{ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_SetMacPauseAddress\n"); + + /* Make sure device is ready for this operation */ + if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_SendPausePacket: returning DEVICE_IS_STOPPED\n"); + return (XST_DEVICE_IS_STOPPED); + } + + /* Send flow control frame */ + XLlTemac_WriteReg(InstancePtr->Config.BaseAddress, XTE_TPF_OFFSET, + (u32) PauseValue & XTE_TPF_TPFV_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_SendPausePacket: returning SUCCESS\n"); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * XLlTemac_GetSgmiiStatus get the state of the link when using the SGMII media + * interface. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param SpeedPtr references the location to store the result, which is the + * autonegotiated link speed in units of Mbits/sec, either 0, 10, 100, + * or 1000. + * + * @return On successful completion, XLlTemac_GetSgmiiStatus returns XST_SUCCESS. + * Otherwise, if TEMAC channel is not using an SGMII interface, + * XLlTemac_GetSgmiiStatus returns XST_NO_FEATURE. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_GetSgmiiStatus(XLlTemac *InstancePtr, u16 *SpeedPtr) +{ + int PhyType; + u32 EgmicReg; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_GetSgmiiStatus\n"); + /* Make sure PHY is SGMII */ + PhyType = XLlTemac_GetPhysicalInterface(InstancePtr); + if (PhyType != XTE_PHY_TYPE_SGMII) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_GetSgmiiStatus: returning NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* Get the current contents of RGMII/SGMII config register */ + EgmicReg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_PHYC_OFFSET); + + /* Extract speed */ + switch (EgmicReg & XTE_PHYC_SGMIILINKSPEED_MASK) { + case XTE_PHYC_SGLINKSPD_10: + *SpeedPtr = 10; + break; + + case XTE_PHYC_SGLINKSPD_100: + *SpeedPtr = 100; + break; + + case XTE_PHYC_SGLINKSPD_1000: + *SpeedPtr = 1000; + break; + + default: + *SpeedPtr = 0; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_GetSgmiiStatus: returning SUCCESS\n"); + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * XLlTemac_GetRgmiiStatus get the state of the link when using the RGMII media + * interface. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param SpeedPtr references the location to store the result, which is the + * autonegotiaged link speed in units of Mbits/sec, either 0, 10, 100, + * or 1000. + * @param IsFullDuplexPtr references the value to set to indicate full duplex + * operation. XLlTemac_GetRgmiiStatus sets <i>IsFullDuplexPtr</i> to TRUE + * when the RGMII link is operating in full duplex mode. Otherwise, + * XLlTemac_GetRgmiiStatus sets <i>IsFullDuplexPtr</i> to FALSE. + * @param IsLinkUpPtr references the value to set to indicate the link status. + * XLlTemac_GetRgmiiStatus sets <i>IsLinkUpPtr</i> to TRUE when the RGMII + * link up. Otherwise, XLlTemac_GetRgmiiStatus sets <i>IsLinkUpPtr</i> to + * FALSE. + * + * @return On successful completion, XLlTemac_GetRgmiiStatus returns XST_SUCCESS. + * Otherwise, if TEMAC channel is not using an RGMII interface, + * XLlTemac_GetRgmiiStatus returns XST_NO_FEATURE. + * + * @note + * + * This routine accesses the hard TEMAC registers through a shared interface + * between both channels of the TEMAC. Becuase of this, the application/OS code + * must provide mutual exclusive access to this routine with any of the other + * routines in this TEMAC driverr. + * + ******************************************************************************/ +int XLlTemac_GetRgmiiStatus(XLlTemac *InstancePtr, u16 *SpeedPtr, + int *IsFullDuplexPtr, int *IsLinkUpPtr) +{ + int PhyType; + u32 EgmicReg; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + /* + * If the mutual exclusion is enforced properly in the calling code, we + * should never get into the following case. + */ + XASSERT_NONVOID(XLlTemac_ReadReg(InstancePtr->Config.BaseAddress, + XTE_RDY_OFFSET) & XTE_RDY_HARD_ACS_RDY_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XLlTemac_GetRgmiiStatus\n"); + /* Make sure PHY is RGMII */ + PhyType = XLlTemac_GetPhysicalInterface(InstancePtr); + if ((PhyType != XTE_PHY_TYPE_RGMII_1_3) && + (PhyType != XTE_PHY_TYPE_RGMII_2_0)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_GetRgmiiStatus: returning NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* Get the current contents of RGMII/SGMII config register */ + EgmicReg = XLlTemac_ReadIndirectReg(InstancePtr->Config.BaseAddress, + XTE_PHYC_OFFSET); + + /* Extract speed */ + switch (EgmicReg & XTE_PHYC_RGMIILINKSPEED_MASK) { + case XTE_PHYC_RGLINKSPD_10: + *SpeedPtr = 10; + break; + + case XTE_PHYC_RGLINKSPD_100: + *SpeedPtr = 100; + break; + + case XTE_PHYC_RGLINKSPD_1000: + *SpeedPtr = 1000; + break; + + default: + *SpeedPtr = 0; + } + + /* Extract duplex and link status */ + if (EgmicReg & XTE_PHYC_RGMIIHD_MASK) { + *IsFullDuplexPtr = FALSE; + } + else { + *IsFullDuplexPtr = TRUE; + } + + if (EgmicReg & XTE_PHYC_RGMIILINK_MASK) { + *IsLinkUpPtr = TRUE; + } + else { + *IsLinkUpPtr = FALSE; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XLlTemac_GetRgmiiStatus: returning SUCCESS\n"); + return (XST_SUCCESS); +} + Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac.h 2014-07-20 22:06:37.203291747 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xlltemac.h + * + * The Xilinx Tri-Mode Ethernet driver component. This driver supports the + * Virtex-5(TM) and Virtex-4(TM) 10/100/1000 MAC (TEMAC). + * + * For a full description of TEMAC features, please see the hardware spec. This driver + * supports the following features: + * - Memory mapped access to host interface registers + * - Virtual memory support + * - Unicast, broadcast, and multicast receive address filtering + * - Full duplex operation (half duplex not supported) + * - Automatic source address insertion or overwrite (programmable) + * - Automatic PAD & FCS insertion and stripping (programmable) + * - Flow control + * - VLAN frame support + * - Pause frame support + * - Jumbo frame support + * - Checksum offload + * + * <h2>Driver Description</h2> + * + * The device driver enables higher layer software (e.g., an application) to + * configure a TEMAC channel. It is intended that this driver be used in + * cooperation with another driver (FIFO or DMA) for data communication. This + * device driver can support multiple devices even when those devices have + * significantly different configurations. + * + * <h2>Initialization & Configuration</h2> + * + * The XLlTemac_Config structure can be used by the driver to configure itself. + * This configuration structure is typically created by the tool-chain based on + * hardware build properties, although, other methods are allowed and currently + * used in some systems. + * + * To support multiple runtime loading and initialization strategies employed + * by various operating systems, the driver instance can be initialized using + * the XLlTemac_CfgInitialze() routine. + * + * <h2>Interrupts and Asynchronous Callbacks</h2> + * + * The driver has no dependencies on the interrupt controller. It provides + * no interrupt handlers. The application/OS software should set up its own + * interrupt handlers if required. + * + * <h2>Device Reset</h2> + * + * When a TEMAC channel is connected up to a FIFO or DMA core in hardware, + * errors may be reported on one of those cores (FIFO or DMA) such that it can + * be determined that the TEMAC channel needs to be reset. If a reset is + * performed, the calling code should also reconfigure and reapply the proper + * settings in the TEMAC channel. + * + * When a TEMAC channel reset is required, XLlTemac_Reset() should be utilized. + * + * <h2>Virtual Memory</h2> + * + * This driver may be used in systems with virtual memory support by passing + * the appropriate value for the <i>EffectiveAddress</i> parameter to the + * XLlTemac_CfgInitialize() routine. + * + * <h2>Transfering Data</h2> + * + * The TEMAC core by itself is not cabable of transmitting or receiving data in + * any meaninful way. Instead one or both TEMAC channels need to be connected + * to a FIFO or DMA core in hardware. + * + * This TEMAC driver is modeled in a similar fashion where the application code + * or O/S adapter driver needs to make use of a separte FIFO or DMA driver in + * connection with this driver to establish meaningful communication over + * ethernet. + * + * <h2>Checksum Offloading</h2> + * + * If configured, the device can compute a 16-bit checksum from frame data. In + * most circumstances this can lead to a substantial gain in throughput. + * + * The checksum offload settings for each frame sent or recieved are + * transmitted through the LocalLink interface in hardware. What this means is + * that the checksum offload feature is indirectly controlled in the TEMAC + * channel through the driver for the FIFO or DMA core connected to the TEMAC + * channel. + * + * Refer to the documentation for the FIFO or DMA driver used for data + * communication on how to set the values for the relevant LocalLink header + * words. + * + * Since this hardware implementation is general purpose in nature system software must + * perform pre and post frame processing to obtain the desired results for the + * types of packets being transferred. Most of the time this will be TCP/IP + * traffic. + * + * TCP/IP and UDP/IP frames contain separate checksums for the IP header and + * UDP/TCP header+data. With this hardware implementation, the IP header checksum + * cannot be offloaded. Many stacks that support offloading will compute the IP + * header if required and use hardware to compute the UDP/TCP header+data checksum. + * There are other complications concerning the IP pseudo header that must be + * taken into consideration. Readers should consult a TCP/IP design reference + * for more details. + * + * There are certain device options that will affect the checksum calculation + * performed by hardware for Tx: + * + * - FCS insertion disabled (XTE_FCS_INSERT_OPTION): software is required to + * calculate and insert the FCS value at the end of the frame, but the + * checksum must be known ahead of time prior to calculating the FCS. + * Therefore checksum offloading cannot be used in this situation. + * + * And for Rx: + * + * - FCS/PAD stripping disabled (XTE_FCS_STRIP_OPTION): The 4 byte FCS at the + * end of frame will be included in the hardware calculated checksum. software must + * subtract out this data. + * + * - FCS/PAD stripping disabled (XTE_FCS_STRIP_OPTION): For frames smaller + * than 64 bytes, padding will be included in the hardware calculated checksum. + * software must subtract out this data. It may be better to allow the TCP/IP + * stack verify checksums for this type of packet. + * + * - VLAN enabled (XTE_VLAN_OPTION): The 4 extra bytes in the Ethernet header + * affect the hardware calculated checksum. software must subtract out the 1st two + * 16-bit words starting at the 15th byte. + * + * <h3>Transmit Checksum Offloading</h3> + * + * For transmit, the software can specify where in the frame the checksum + * calculation is to start, where the result should be inserted, and a seed + * value. The checksum is calculated from the start point through the end of + * frame. + * + * The checsum offloading settings are sent in the transmit LocalLink header + * words. The relevant LocalLink header words are described in brief below. + * Refer to the XPS_LL_TEMAC v1.00a hardware specification for more details. + * + * <h4>LocalLink header word 3:</h4> + * <pre> + * Bits 31 (MSB): Transmit Checksum Enable: 1 - enabled, 0 - disabled + * Bits 0-30 (LSB): Reserved + * </pre> + * + * <h4>LocalLink header word 4:</h4> + * <pre> + * Bits 16-31 (MSB): Transmit Checksum Insertion Point: Frame offset where the + * computed checksum value is stored, which should be in the + * TCP or UDP header + * Bits 0-15 (LSB): Transmit Checksum Calculation Starting Point: Offset + * in the frame where checksum calculation should begin + * </pre> + * + * <h4>LocalLink header word 5:</h4> + * <pre> + * Bits 16-31 (MSB): Transmit Checksum Calculation Initial Value: Checksum + * seed value + * Bits 0-15 (LSB): Reserved + * </pre> + * + * <h3>Receive Checksum Offloading</h3> + * + * For Receive, the 15th byte to end of frame is checksummed. This range of + * bytes is the entire Ethernet payload (for non-VLAN frames). + * + * The checsum offloading information is sent in the receive LocalLink header + * words. The relevant LocalLink header words are described in brief below. + * Refer to the XPS_LL_TEMAC v1.00a hardware specification for more details. + * + * <h4>LocalLink header word 6:</h4> + * <pre> + * Bits 16-31 (MSB): Receive Raw Checksum: Computed checksum value + * Bits 0-15 (LSB): Reserved + * </pre> + * + * <h2>PHY Communication</h2> + * + * Prior to PHY access, the MDIO clock must be setup. This driver will set a + * safe default that should work with PLB bus speeds of up to 150 MHz and keep + * the MDIO clock below 2.5 MHz. If the user wishes faster access to the PHY + * then the clock divisor can be set to a different value (see + * XLlTemac_PhySetMdioDivisor()). + * + * MII register access is performed through the functions XLlTemac_PhyRead() and + * XLlTemac_PhyWrite(). + * + * <h2>Link Sync</h2> + * + * When the device is used in a multispeed environment, the link speed must be + * explicitly set using XLlTemac_SetOperatingSpeed() and must match the speed the + * PHY has negotiated. If the speeds are mismatched, then the MAC will not pass + * traffic. + * + * The application/OS software may use the AutoNegotiation interrupt to be + * notified when the PHY has completed auto-negotiation. + * + * <h2>Asserts</h2> + * + * Asserts are used within all Xilinx drivers to enforce constraints on argument + * values. Asserts can be turned off on a system-wide basis by defining, at + * compile time, the NDEBUG identifier. By default, asserts are turned on and it + * is recommended that users leave asserts on during development. For deployment + * use -DNDEBUG compiler switch to remove assert code. + * + * <h2>Driver Errata</h2> + * + * - A dropped receive frame indication may be reported by the driver after + * calling XLlTemac_Stop() followed by XLlTemac_Start(). This can occur if a + * frame is arriving when stop is called. + * - On Rx with checksum offloading enabled and FCS/PAD stripping disabled, + * FCS and PAD data will be included in the checksum result. + * - On Tx with checksum offloading enabled and auto FCS insertion disabled, + * the user calculated FCS will be included in the checksum result. + * + * @note + * + * Xilinx drivers are typically composed of two components, one is the driver + * and the other is the adapter. The driver is independent of OS and processor + * and is intended to be highly portable. The adapter is OS-specific and + * facilitates communication between the driver and an OS. + * <br><br> + * This driver is intended to be RTOS and processor independent. Any needs for + * dynamic memory management, threads or thread mutual exclusion, or cache + * control must be satisfied by the layer above this driver. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a jvb 11/10/06 First release + * 1.00a rpm 06/08/07 Added interrupt IDs to config structure for convenience + * </pre> + * + *****************************************************************************/ + +#ifndef XTEMAC_H /* prevent circular inclusions */ +#define XTEMAC_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xenv.h" +#include "xbasic_types.h" +#include "xstatus.h" +#include "xlltemac_hw.h" + +/************************** Constant Definitions *****************************/ + +/* + * Device information + */ +#define XTE_DEVICE_NAME "xlltemac" +#define XTE_DEVICE_DESC "Xilinx Tri-speed 10/100/1000 MAC" + +/* LocalLink TYPE Enumerations */ +#define XPAR_LL_FIFO 1 +#define XPAR_LL_DMA 2 + +/** @name Configuration options + * + * The following are device configuration options. See the + * <i>XLlTemac_SetOptions</i>, <i>XLlTemac_ClearOptions</i> and + * <i>XLlTemac_GetOptions</i> routines for information on how to use options. + * + * The default state of the options are also noted below. + * + * @{ + */ + +#define XTE_PROMISC_OPTION 0x00000001 +/**< XTE_PROMISC_OPTION specifies the TEMAC channel to accept all incoming + * packets. + * This driver sets this option to disabled (cleared) by default. */ + +#define XTE_JUMBO_OPTION 0x00000002 +/**< XTE_JUMBO_OPTION specifies the TEMAC channel to accept jumbo frames + * for transmit and receive. + * This driver sets this option to disabled (cleared) by default. */ + +#define XTE_VLAN_OPTION 0x00000004 +/**< XTE_VLAN_OPTION specifies the TEMAC channel to enable VLAN support for + * transmit and receive. + * This driver sets this option to disabled (cleared) by default. */ + +#define XTE_FLOW_CONTROL_OPTION 0x00000008 +/**< XTE_FLOW_CONTROL_OPTION specifies the TEMAC channel to recognize + * received flow control frames. + * This driver sets this option to enabled (set) by default. */ + +#define XTE_FCS_STRIP_OPTION 0x00000010 +/**< XTE_FCS_STRIP_OPTION specifies the TEMAC channel to strip FCS and PAD + * from received frames. Note that PAD from VLAN frames is not stripped. + * This driver sets this option to enabled (set) by default. */ + +#define XTE_FCS_INSERT_OPTION 0x00000020 +/**< XTE_FCS_INSERT_OPTION specifies the TEMAC channel to generate the FCS + * field and add PAD automatically for outgoing frames. + * This driver sets this option to enabled (set) by default. */ + +#define XTE_LENTYPE_ERR_OPTION 0x00000040 +/**< XTE_LENTYPE_ERR_OPTION specifies the TEMAC channel to enable + * Length/Type error checking (mismatched type/length field) for received + * frames. + * This driver sets this option to enabled (set) by default. */ + +#define XTE_TRANSMITTER_ENABLE_OPTION 0x00000080 +/**< XTE_TRANSMITTER_ENABLE_OPTION specifies the TEMAC channel transmitter + * to be enabled. + * This driver sets this option to enabled (set) by default. */ + +#define XTE_RECEIVER_ENABLE_OPTION 0x00000100 +/**< XTE_RECEIVER_ENABLE_OPTION specifies the TEMAC channel receiver to be + * enabled. + * This driver sets this option to enabled (set) by default. */ + +#define XTE_BROADCAST_OPTION 0x00000200 +/**< XTE_BROADCAST_OPTION specifies the TEMAC channel to receive frames + * sent to the broadcast Ethernet address. + * This driver sets this option to enabled (set) by default. */ + +#define XTE_MULTICAST_OPTION 0x00000400 +/**< XTE_MULTICAST_OPTION specifies the TEMAC channel to receive frames + * sent to Ethernet addresses that are programmed into the Multicast Address + * Table (MAT). + * This driver sets this option to disabled (cleared) by default. */ + +#define XTE_DEFAULT_OPTIONS \ + (XTE_FLOW_CONTROL_OPTION | \ + XTE_BROADCAST_OPTION | \ + XTE_FCS_INSERT_OPTION | \ + XTE_FCS_STRIP_OPTION | \ + XTE_LENTYPE_ERR_OPTION | \ + XTE_TRANSMITTER_ENABLE_OPTION | \ + XTE_RECEIVER_ENABLE_OPTION) +/**< XTE_DEFAULT_OPTIONS specify the options set in XLlTemac_Reset() and + * XLlTemac_CfgInitialize() */ + +/*@}*/ + +/** @name Reset parameters + * + * These are used by function XLlTemac_Reset(). + * @{ + */ +#define XTE_RESET_HARD 1 +#define XTE_NORESET_HARD 0 +/*@}*/ + +#define XTE_MULTI_MAT_ENTRIES 4 /* Number of storable addresses in + the Multicast Address Table */ + +#define XTE_MDIO_DIV_DFT 29 /* Default MDIO clock divisor */ + +/* The next few constants help upper layers determine the size of memory + * pools used for Ethernet buffers and descriptor lists. + */ +#define XTE_MAC_ADDR_SIZE 6 /* MAC addresses are 6 bytes */ +#define XTE_MTU 1500 /* max MTU size of an Ethernet frame */ +#define XTE_JUMBO_MTU 8982 /* max MTU size of a jumbo Ethernet frame */ +#define XTE_HDR_SIZE 14 /* size of an Ethernet header */ +#define XTE_HDR_VLAN_SIZE 18 /* size of an Ethernet header with VLAN */ +#define XTE_TRL_SIZE 4 /* size of an Ethernet trailer (FCS) */ +#define XTE_MAX_FRAME_SIZE (XTE_MTU + XTE_HDR_SIZE + XTE_TRL_SIZE) +#define XTE_MAX_VLAN_FRAME_SIZE (XTE_MTU + XTE_HDR_VLAN_SIZE + XTE_TRL_SIZE) +#define XTE_MAX_JUMBO_FRAME_SIZE (XTE_JUMBO_MTU + XTE_HDR_SIZE + XTE_TRL_SIZE) + +/* Constant values returned by XLlTemac_mGetPhysicalInterface(). Note that these + * values match design parameters from the PLB_TEMAC spec + */ +#define XTE_PHY_TYPE_MII 0 +#define XTE_PHY_TYPE_GMII 1 +#define XTE_PHY_TYPE_RGMII_1_3 2 +#define XTE_PHY_TYPE_RGMII_2_0 3 +#define XTE_PHY_TYPE_SGMII 4 +#define XTE_PHY_TYPE_1000BASE_X 5 + +/**************************** Type Definitions *******************************/ + + +/** + * This typedef contains configuration information for a TEMAC channel. + * Each channel is treated as a separate device from the point of view of this + * driver. + */ +typedef struct { + /** u16 DeviceId; < DeviceId is the unique ID of the device */ + u32 BaseAddress;/**< BaseAddress is the physical base address of the + * channel's registers + */ + u8 TxCsum; /**< TxCsum indicates that the channel has checksum + * offload on the Tx channel or not. + */ + u8 RxCsum; /**< RxCsum indicates that the channel has checksum + * offload on the Rx channel or not. + */ + u8 PhyType; /**< PhyType indicates which type of PHY interface is + * used (MII, GMII, RGMII, ect. + */ + u8 TemacIntr; /**< TEMAC interrupt ID */ + + int LLDevType; /**< LLDevType is the type of device attached to the + * temac's local link interface. + */ + u32 LLDevBaseAddress; /**< LLDevBaseAddress is the base address of then + * device attached to the temac's local link + * interface. + */ + u8 LLFifoIntr; /**< LL FIFO interrupt ID (unused if DMA) */ + u8 LLDmaRxIntr; /**< LL DMA RX interrupt ID (unused if FIFO) */ + u8 LLDmaTxIntr; /**< LL DMA TX interrupt ID (unused if FIFO) */ + +} XLlTemac_Config; + + +/** + * struct XLlTemac is the type for TEMAC driver instance data. The calling code + * is required to use a unique instance of this structure for every TEMAC + * channel used in the system. Each channel is treated as a separate device + * from the point of view of this driver. A reference to a structure of this + * type is then passed to the driver API functions. + */ +typedef struct XLlTemac { + XLlTemac_Config Config; /* hardware configuration */ + u32 IsStarted; /* Device is currently started */ + u32 IsReady; /* Device is initialized and ready */ + u32 Options; /* Current options word */ + u32 Flags; /* Internal driver flags */ +} XLlTemac; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** + * + * XLlTemac_IsStarted reports if the device is in the started or stopped state. To + * be in the started state, the calling code must have made a successful call to + * <i>XLlTemac_Start</i>. To be in the stopped state, <i>XLlTemac_Stop</i> or + * <i>XLlTemac_CfgInitialize</i> function must have been called. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XLlTemac_IsStarted returns TRUE if the device has been started. + * Otherwise, XLlTemac_IsStarted returns FALSE. + * + * @note + * + * Signature: u32 XLlTemac_IsStarted(XLlTemac *InstancePtr) + * + ******************************************************************************/ +#define XLlTemac_IsStarted(InstancePtr) \ + (((InstancePtr)->IsStarted == XCOMPONENT_IS_STARTED) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XLlTemac_IsDma reports if the device is currently connected to DMA. +* +* @param InstancePtr references the TEMAC channel on which to operate. +* +* @return XLlTemac_IsDma returns TRUE if the device is connected DMA. Otherwise, +* XLlTemac_IsDma returns FALSE. +* +* @note +* +* Signature: u32 XLlTemac_IsDma(XLlTemac *InstancePtr) +* +******************************************************************************/ +#define XLlTemac_IsDma(InstancePtr) \ + (((InstancePtr)->Config.LLDevType == XPAR_LL_DMA) ? TRUE: FALSE) + +/*****************************************************************************/ +/** +* +* XLlTemac_IsFifo reports if the device is currently connected to a fifo core. +* +* @param InstancePtr references the TEMAC channel on which to operate. +* +* @return XLlTemac_IsFifo returns TRUE if the device is connected to a fifo core. +* Otherwise, XLlTemac_IsFifo returns FALSE. +* +* @note +* +* Signature: u32 XLlTemac_IsFifo(XLlTemac *InstancePtr) +* +******************************************************************************/ +#define XLlTemac_IsFifo(InstancePtr) \ + (((InstancePtr)->Config.LLDevType == XPAR_LL_FIFO) ? TRUE: FALSE) + +/*****************************************************************************/ +/** +* +* XLlTemac_LlDevBaseAddress reports the base address of the core connected to +* the TEMAC's local link interface. +* +* @param InstancePtr references the TEMAC channel on which to operate. +* +* @return XLlTemac_IsFifo returns the base address of the core connected to +* the TEMAC's local link interface. +* +* @note +* +* Signature: u32 XLlTemac_LlDevBaseAddress(XLlTemac *InstancePtr) +* +******************************************************************************/ +#define XLlTemac_LlDevBaseAddress(InstancePtr) \ + ((InstancePtr)->Config.LLDevBaseAddress) + +/*****************************************************************************/ +/** + * + * XLlTemac_IsRecvFrameDropped determines if the device thinks it has dropped a + * receive frame. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XLlTemac_IsRecvFrameDropped returns TRUE if the device interrupt + * status register reports that a frame has been dropped. Otherwise, + * XLlTemac_IsRecvFrameDropped returns FALSE. + * + * @note + * + * Signature: u32 XLlTemac_IsRecvFrameDropped(XLlTemac *InstancePtr) + * + ******************************************************************************/ +#define XLlTemac_IsRecvFrameDropped(InstancePtr) \ + ((XLlTemac_ReadReg((InstancePtr)->Config.BaseAddress, XTE_IS_OFFSET) \ + & XTE_INT_RXRJECT_MASK) ? TRUE : FALSE) + +/*****************************************************************************/ +/** + * + * XLlTemac_IsRxCsum determines if the device is configured with checksum + * offloading on the receive channel. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XLlTemac_IsRxCsum returns TRUE if the device is configured with + * checksum offloading on the receive channel. Otherwise, + * XLlTemac_IsRxCsum returns FALSE. + * + * @note + * + * Signature: u32 XLlTemac_IsRxCsum(XLlTemac *InstancePtr) + * + ******************************************************************************/ +#define XLlTemac_IsRxCsum(InstancePtr) (((InstancePtr)->Config.RxCsum) ? \ + TRUE : FALSE) + +/*****************************************************************************/ +/** + * + * XLlTemac_IsTxCsum determines if the device is configured with checksum + * offloading on the transmit channel. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XLlTemac_IsTxCsum returns TRUE if the device is configured with + * checksum offloading on the transmit channel. Otherwise, + * XLlTemac_IsTxCsum returns FALSE. + * + * @note + * + * Signature: u32 XLlTemac_IsTxCsum(XLlTemac *InstancePtr) + * + ******************************************************************************/ +#define XLlTemac_IsTxCsum(InstancePtr) (((InstancePtr)->Config.TxCsum) ? \ + TRUE : FALSE) + +/*****************************************************************************/ +/** + * + * XLlTemac_GetPhysicalInterface returns the type of PHY interface being used by + * the given instance, specified by <i>InstancePtr</i>. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XLlTemac_GetPhysicalInterface returns one of XTE_PHY_TYPE_<x> where + * <x> is MII, GMII, RGMII_1_3, RGMII_2_0, SGMII, or 1000BASE_X (defined in + * xlltemac.h). + * + * @note + * + * Signature: int XLlTemac_GetPhysicalInterface(XLlTemac *InstancePtr) + * + ******************************************************************************/ +#define XLlTemac_GetPhysicalInterface(InstancePtr) \ + ((InstancePtr)->Config.PhyType) + +/****************************************************************************/ +/** +* +* XLlTemac_Status returns a bit mask of the interrupt status register (ISR). +* XLlTemac_Status can be used to query the status without having to have +* interrupts enabled. +* +* @param InstancePtr references the TEMAC channel on which to operate. +* +* @return XLlTemac_IntStatus returns a bit mask of the status conditions. +* The mask will be a set of bitwise or'd values from the +* <code>XTE_INT_*_MASK</code> preprocessor symbols. +* +* @note +* C-style signature: +* u32 XLlTemac_IntStatus(XLlTemac *InstancePtr) +* +*****************************************************************************/ +#define XLlTemac_Status(InstancePtr) \ + XLlTemac_ReadReg((InstancePtr)->Config.BaseAddress, XTE_IS_OFFSET) + +/****************************************************************************/ +/** +* +* XLlTemac_IntEnable enables the interrupts specified in <i>Mask</i>. The +* corresponding interrupt for each bit set to 1 in <i>Mask</i>, will be +* enabled. +* +* @param InstancePtr references the TEMAC channel on which to operate. +* +* @param Mask contains a bit mask of the interrupts to enable. The mask +* can be formed using a set of bitwise or'd values from the +* <code>XTE_INT_*_MASK</code> preprocessor symbols. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlTemac_IntEnable(XLlTemac *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XLlTemac_IntEnable(InstancePtr, Mask) \ + XLlTemac_WriteReg((InstancePtr)->Config.BaseAddress, XTE_IE_OFFSET, \ + XLlTemac_ReadReg((InstancePtr)->Config.BaseAddress, \ + XTE_IE_OFFSET) | ((Mask) & XTE_INT_ALL_MASK)); \ + +/****************************************************************************/ +/** +* +* XLlTemac_IntDisable disables the interrupts specified in <i>Mask</i>. The +* corresponding interrupt for each bit set to 1 in <i>Mask</i>, will be +* disabled. In other words, XLlTemac_IntDisable uses the "set a bit to clear it" +* scheme. +* +* @param InstancePtr references the TEMAC channel on which to operate. +* +* @param Mask contains a bit mask of the interrupts to disable. The mask +* can be formed using a set of bitwise or'd values from the +* <code>XTE_INT_*_MASK</code> preprocessor symbols. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlTemac_IntDisable(XLlTemac *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XLlTemac_IntDisable(InstancePtr, Mask) \ + XLlTemac_WriteReg((InstancePtr)->Config.BaseAddress, XTE_IE_OFFSET, \ + XLlTemac_ReadReg((InstancePtr)->Config.BaseAddress, \ + XTE_IE_OFFSET) & ~((Mask) & XTE_INT_ALL_MASK)); \ + +/****************************************************************************/ +/** +* +* XLlTemac_IntPending returns a bit mask of the pending interrupts. Each bit +* set to 1 in the return value represents a pending interrupt. +* +* @param InstancePtr references the TEMAC channel on which to operate. +* +* @return XLlTemac_IntPending returns a bit mask of the interrupts that are +* pending. The mask will be a set of bitwise or'd values from the +* <code>XTE_INT_*_MASK</code> preprocessor symbols. +* +* @note +* C-style signature: +* u32 XLlTemac_IntPending(XLlTemac *InstancePtr) +* +*****************************************************************************/ +#define XLlTemac_IntPending(InstancePtr) \ + XLlTemac_ReadReg((InstancePtr)->Config.BaseAddress, XTE_IP_OFFSET) + +/****************************************************************************/ +/** +* +* XLlTemac_IntClear clears pending interrupts specified in <i>Mask</i>. +* The corresponding pending interrupt for each bit set to 1 in <i>Mask</i>, +* will be cleared. In other words, XLlTemac_IntClear uses the "set a bit to +* clear it" scheme. +* +* @param InstancePtr references the TEMAC channel on which to operate. +* +* @param Mask contains a bit mask of the pending interrupts to clear. The +* mask can be formed using a set of bitwise or'd values from the +* <code>XTE_INT_*_MASK</code> preprocessor symbols. +* +* @note +* C-style signature: +* void XLlTemac_IntClear(XLlTemac *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XLlTemac_IntClear(InstancePtr, Mask) \ + XLlTemac_WriteReg((InstancePtr)->Config.BaseAddress, XTE_IS_OFFSET, \ + ((Mask) & XTE_INT_ALL_MASK)) + +/************************** Function Prototypes ******************************/ + +/* + * Initialization functions in xlltemac.c + */ +int XLlTemac_CfgInitialize(XLlTemac *InstancePtr, XLlTemac_Config *CfgPtr, + u32 VirtualAddress); +void XLlTemac_Start(XLlTemac *InstancePtr); +void XLlTemac_Stop(XLlTemac *InstancePtr); +void XLlTemac_Reset(XLlTemac *InstancePtr, int HardCoreAction); + +/* + * Initialization functions in xlltemac_sinit.c + */ +XLlTemac_Config *XLlTemac_LookupConfig(u16 DeviceId); + +/* + * MAC configuration/control functions in xlltemac_control.c + */ +int XLlTemac_SetOptions(XLlTemac *InstancePtr, u32 Options); +int XLlTemac_ClearOptions(XLlTemac *InstancePtr, u32 Options); +u32 XLlTemac_GetOptions(XLlTemac *InstancePtr); + +int XLlTemac_SetMacAddress(XLlTemac *InstancePtr, void *AddressPtr); +void XLlTemac_GetMacAddress(XLlTemac *InstancePtr, void *AddressPtr); + +int XLlTemac_SetMacPauseAddress(XLlTemac *InstancePtr, void *AddressPtr); +void XLlTemac_GetMacPauseAddress(XLlTemac *InstancePtr, void *AddressPtr); +int XLlTemac_SendPausePacket(XLlTemac *InstancePtr, u16 PauseValue); + +int XLlTemac_GetSgmiiStatus(XLlTemac *InstancePtr, u16 *SpeedPtr); +int XLlTemac_GetRgmiiStatus(XLlTemac *InstancePtr, u16 *SpeedPtr, + int *IsFullDuplexPtr, int *IsLinkUpPtr); +u16 XLlTemac_GetOperatingSpeed(XLlTemac *InstancePtr); +void XLlTemac_SetOperatingSpeed(XLlTemac *InstancePtr, u16 Speed); + +void XLlTemac_PhySetMdioDivisor(XLlTemac *InstancePtr, u8 Divisor); +void XLlTemac_PhyRead(XLlTemac *InstancePtr, u32 PhyAddress, u32 RegisterNum, + u16 *PhyDataPtr); +void XLlTemac_PhyWrite(XLlTemac *InstancePtr, u32 PhyAddress, u32 RegisterNum, + u16 PhyData); +int XLlTemac_MulticastAdd(XLlTemac *InstancePtr, void *AddressPtr, int Entry); +void XLlTemac_MulticastGet(XLlTemac *InstancePtr, void *AddressPtr, int Entry); +int XLlTemac_MulticastClear(XLlTemac *InstancePtr, int Entry); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac_hw.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac_hw.h 2014-07-20 22:06:37.216291532 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* iId: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ + +/*****************************************************************************/ +/** + * + * @file xlltemac_hw.h + * + * This header file contains identifiers and low-level driver functions (or + * macros) that can be used to access the Tri-Mode MAC Ethernet (TEMAC) device. + * High-level driver functions are defined in xlltemac.h. + * + * @note + * + * Some registers are not accessible when a HW instance is configured for SGDMA. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a jvb 11/10/06 First release + * </pre> + * + ******************************************************************************/ + +#ifndef XTEMAC_HW_H /* prevent circular inclusions */ +#define XTEMAC_HW_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xio.h" +#include "xdebug.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************** Constant Definitions *****************************/ + +#define XTE_RESET_HARD_DELAY_US 4 /**< Us to delay for hard core reset */ + +/* Register offset definitions. Unless otherwise noted, register access is + * 32 bit. + */ + +/** @name Direct registers + * @{ + */ +#define XTE_RAF_OFFSET 0x00000000 /**< Reset and address filter */ +#define XTE_TPF_OFFSET 0x00000004 /**< Transmit pause frame */ +#define XTE_IFGP_OFFSET 0x00000008 /**< Transmit inter-frame gap adjustment */ +#define XTE_IS_OFFSET 0x0000000C /**< Interrupt status */ +#define XTE_IP_OFFSET 0x00000010 /**< Interrupt pending */ +#define XTE_IE_OFFSET 0x00000014 /**< Interrupt enable */ + +#define XTE_MSW_OFFSET 0x00000020 /**< Most significant word data */ +#define XTE_LSW_OFFSET 0x00000024 /**< Least significant word data */ +#define XTE_CTL_OFFSET 0x00000028 /**< Control */ +#define XTE_RDY_OFFSET 0x0000002C /**< Ready status */ +/*@}*/ + + +/** @name HARD_TEMAC Core Registers + * These are registers defined within the device's hard core located in the + * processor block. They are accessed indirectly through the registers, MSW, + * LSW, and CTL. + * + * Access to these registers should go through macros XLlTemac_ReadIndirectReg() + * and XLlTemac_WriteIndirectReg() to guarantee proper access. + * @{ + */ +#define XTE_RCW0_OFFSET 0x00000200 /**< Rx configuration word 0 */ +#define XTE_RCW1_OFFSET 0x00000240 /**< Rx configuration word 1 */ +#define XTE_TC_OFFSET 0x00000280 /**< Tx configuration */ +#define XTE_FCC_OFFSET 0x000002C0 /**< Flow control configuration */ +#define XTE_EMMC_OFFSET 0x00000300 /**< EMAC mode configuration */ +#define XTE_PHYC_OFFSET 0x00000320 /**< RGMII/SGMII configuration */ +#define XTE_MC_OFFSET 0x00000340 /**< Management configuration */ +#define XTE_UAW0_OFFSET 0x00000380 /**< Unicast address word 0 */ +#define XTE_UAW1_OFFSET 0x00000384 /**< Unicast address word 1 */ +#define XTE_MAW0_OFFSET 0x00000388 /**< Multicast address word 0 */ +#define XTE_MAW1_OFFSET 0x0000038C /**< Multicast address word 1 */ +#define XTE_AFM_OFFSET 0x00000390 /**< Address Filter (promiscuous) mode */ +#define XTE_TIS_OFFSET 0x000003A0 /**< Interrupt status */ +#define XTE_TIE_OFFSET 0x000003A4 /**< Interrupt enable */ +#define XTE_MIIMWD_OFFSET 0x000003B0 /**< MII management write data */ +#define XTE_MIIMAI_OFFSET 0x000003B4 /**< MII management access initiate */ +/*@}*/ + + +/* Register masks. The following constants define bit locations of various + * control bits in the registers. Constants are not defined for those registers + * that have a single bit field representing all 32 bits. For further + * information on the meaning of the various bit masks, refer to the HW spec. + */ + +/** @name Reset and Address Filter bits + * These bits are associated with the XTE_RAF_OFFSET register. + * @{ + */ +#define XTE_RAF_HTRST_MASK 0x00000001 /**< Hard TEMAC Reset */ +#define XTE_RAF_MCSTREJ_MASK 0x00000002 /**< Reject receive multicast destination address */ +#define XTE_RAF_BCSTREJ_MASK 0x00000004 /**< Reject receive broadcast destination address */ +/*@}*/ + +/** @name Transmit Pause Frame Register (TPF) + * @{ + */ +#define XTE_TPF_TPFV_MASK 0x0000FFFF /**< Tx pause frame value */ +/*@}*/ + +/** @name Transmit Inter-Frame Gap Adjustement Register (TFGP) + * @{ + */ +#define XTE_TFGP_IFGP_MASK 0x0000007F /**< Transmit inter-frame gap adjustment value */ +/*@}*/ + +/** @name Interrupt bits + * These bits are associated with the XTE_IS_OFFSET, XTE_IP_OFFSET, and + * XTE_IE_OFFSET registers. + * @{ + */ +#define XTE_INT_HARDACSCMPLT_MASK 0x00000001 /**< Hard register access complete */ +#define XTE_INT_AUTONEG_MASK 0x00000002 /**< Auto negotiation complete */ +#define XTE_INT_RC_MASK 0x00000004 /**< Receive complete */ +#define XTE_INT_RXRJECT_MASK 0x00000008 /**< Receive frame rejected */ +#define XTE_INT_RXFIFOOVR_MASK 0x00000010 /**< Receive fifo overrun */ +#define XTE_INT_TC_MASK 0x00000020 /**< Transmit complete */ +#define XTE_INT_ALL_MASK 0x0000003f /**< All the ints */ +/*@}*/ + + +#define XTE_INT_RECV_ERROR_MASK \ + (XTE_INT_RXRJECT_MASK | XTE_INT_RXFIFOOVR_MASK) /**< INT bits that indicate receive errors */ +/*@}*/ + + +/** @name Control Register (CTL) + * @{ + */ +#define XTE_CTL_WEN_MASK 0x00008000 /**< Write Enable */ +/*@}*/ + + +/** @name Ready Status, TEMAC Interrupt Status, TEMAC Interrupt Enable Registers + * (RDY, TIS, TIE) + * @{ + */ +#define XTE_RSE_FABR_RR_MASK 0x00000001 /**< Fabric read ready */ +#define XTE_RSE_MIIM_RR_MASK 0x00000002 /**< MII management read ready */ +#define XTE_RSE_MIIM_WR_MASK 0x00000004 /**< MII management write ready */ +#define XTE_RSE_AF_RR_MASK 0x00000008 /**< Address filter read ready*/ +#define XTE_RSE_AF_WR_MASK 0x00000010 /**< Address filter write ready*/ +#define XTE_RSE_CFG_RR_MASK 0x00000020 /**< Configuration register read ready*/ +#define XTE_RSE_CFG_WR_MASK 0x00000040 /**< Configuration register write ready*/ +#define XTE_RDY_HARD_ACS_RDY_MASK 0x00010000 /**< Hard register access ready */ +#define XTE_RDY_ALL (XTE_RSE_FABR_RR_MASK | \ + XTE_RSE_MIIM_RR_MASK | \ + XTE_RSE_MIIM_WR_MASK | \ + XTE_RSE_AF_RR_MASK | \ + XTE_RSE_AF_WR_MASK | \ + XTE_RSE_CFG_RR_MASK | \ + XTE_RSE_CFG_WR_MASK | \ + XTE_RDY_HARD_ACS_RDY_MASK) +/*@}*/ + + +/** @name Receive Configuration Word 1 (RCW1) + * @{ + */ +#define XTE_RCW1_RST_MASK 0x80000000 /**< Reset */ +#define XTE_RCW1_JUM_MASK 0x40000000 /**< Jumbo frame enable */ +#define XTE_RCW1_FCS_MASK 0x20000000 /**< In-Band FCS enable (FCS not stripped) */ +#define XTE_RCW1_RX_MASK 0x10000000 /**< Receiver enable */ +#define XTE_RCW1_VLAN_MASK 0x08000000 /**< VLAN frame enable */ +#define XTE_RCW1_HD_MASK 0x04000000 /**< Half duplex mode */ +#define XTE_RCW1_LT_DIS_MASK 0x02000000 /**< Length/type field valid check disable */ +#define XTE_RCW1_PAUSEADDR_MASK 0x0000FFFF /**< Pause frame source address + bits [47:32]. Bits [31:0] + are stored in register + RCW0 */ +/*@}*/ + + +/** @name Transmitter Configuration (TC) + * @{ + */ +#define XTE_TC_RST_MASK 0x80000000 /**< reset */ +#define XTE_TC_JUM_MASK 0x40000000 /**< Jumbo frame enable */ +#define XTE_TC_FCS_MASK 0x20000000 /**< In-Band FCS enable (FCS not generated) */ +#define XTE_TC_TX_MASK 0x10000000 /**< Transmitter enable */ +#define XTE_TC_VLAN_MASK 0x08000000 /**< VLAN frame enable */ +#define XTE_TC_HD_MASK 0x04000000 /**< Half duplex mode */ +#define XTE_TC_IFG_MASK 0x02000000 /**< Inter-frame gap adjustment enable */ +/*@}*/ + + +/** @name Flow Control Configuration (FCC) + * @{ + */ +#define XTE_FCC_FCRX_MASK 0x20000000 /**< Rx flow control enable */ +#define XTE_FCC_FCTX_MASK 0x40000000 /**< Tx flow control enable */ +/*@}*/ + + +/** @name EMAC Configuration (EMMC) + * @{ + */ +#define XTE_EMMC_LINKSPEED_MASK 0xC0000000 /**< Link speed */ +#define XTE_EMMC_RGMII_MASK 0x20000000 /**< RGMII mode enable */ +#define XTE_EMMC_SGMII_MASK 0x10000000 /**< SGMII mode enable */ +#define XTE_EMMC_GPCS_MASK 0x08000000 /**< 1000BaseX mode enable */ +#define XTE_EMMC_HOST_MASK 0x04000000 /**< Host interface enable */ +#define XTE_EMMC_TX16BIT 0x02000000 /**< 16 bit Tx client enable */ +#define XTE_EMMC_RX16BIT 0x01000000 /**< 16 bit Rx client enable */ + +#define XTE_EMMC_LINKSPD_10 0x00000000 /**< XTE_EMCFG_LINKSPD_MASK for + 10 Mbit */ +#define XTE_EMMC_LINKSPD_100 0x40000000 /**< XTE_EMCFG_LINKSPD_MASK for + 100 Mbit */ +#define XTE_EMMC_LINKSPD_1000 0x80000000 /**< XTE_EMCFG_LINKSPD_MASK for + 1000 Mbit */ +/*@}*/ + + +/** @name EMAC RGMII/SGMII Configuration (PHYC) + * @{ + */ +#define XTE_PHYC_SGMIILINKSPEED_MASK 0xC0000000 /**< SGMII link speed */ +#define XTE_PHYC_RGMIILINKSPEED_MASK 0x0000000C /**< RGMII link speed */ +#define XTE_PHYC_RGMIIHD_MASK 0x00000002 /**< RGMII Half-duplex mode */ +#define XTE_PHYC_RGMIILINK_MASK 0x00000001 /**< RGMII link status */ + +#define XTE_PHYC_RGLINKSPD_10 0x00000000 /**< XTE_GMIC_RGLINKSPD_MASK + for 10 Mbit */ +#define XTE_PHYC_RGLINKSPD_100 0x00000004 /**< XTE_GMIC_RGLINKSPD_MASK + for 100 Mbit */ +#define XTE_PHYC_RGLINKSPD_1000 0x00000008 /**< XTE_GMIC_RGLINKSPD_MASK + for 1000 Mbit */ +#define XTE_PHYC_SGLINKSPD_10 0x00000000 /**< XTE_SGMIC_RGLINKSPD_MASK + for 10 Mbit */ +#define XTE_PHYC_SGLINKSPD_100 0x40000000 /**< XTE_SGMIC_RGLINKSPD_MASK + for 100 Mbit */ +#define XTE_PHYC_SGLINKSPD_1000 0x80000000 /**< XTE_SGMIC_RGLINKSPD_MASK + for 1000 Mbit */ +/*@}*/ + + +/** @name EMAC Management Configuration (MC) + * @{ + */ +#define XTE_MC_MDIOEN_MASK 0x00000040 /**< MII management enable */ +#define XTE_MC_CLOCK_DIVIDE_MAX 0x3F /**< Maximum MDIO divisor */ +/*@}*/ + + +/** @name EMAC Unicast Address Register Word 1 (UAW1) + * @{ + */ +#define XTE_UAW1_UNICASTADDR_MASK 0x0000FFFF /**< Station address bits [47:32] + Station address bits [31:0] + are stored in register + UAW0 */ +/*@}*/ + + +/** @name EMAC Multicast Address Register Word 1 (MAW1) + * @{ + */ +#define XTE_MAW1_RNW_MASK 0x00800000 /**< Multicast address table register read enable */ +#define XTE_MAW1_ADDR_MASK 0x00030000 /**< Multicast address table register address */ +#define XTE_MAW1_MULTICADDR_MASK 0x0000FFFF /**< Multicast address bits [47:32] + Multicast address bits [31:0] + are stored in register + MAW0 */ +#define XTE_MAW1_MATADDR_SHIFT_MASK 16 /**< Number of bits to shift right + to align with + XTE_MAW1_CAMADDR_MASK */ +/*@}*/ + + +/** @name EMAC Address Filter Mode (AFM) + * @{ + */ +#define XTE_AFM_PM_MASK 0x80000000 /**< Promiscuous mode enable */ +/*@}*/ + + +/** @name Media Independent Interface Management (MIIM) + * @{ + */ +#define XTE_MIIM_REGAD_MASK 0x1F /**< MII Phy register address (REGAD) */ +#define XTE_MIIM_PHYAD_MASK 0x03E0 /**< MII Phy address (PHYAD) */ +#define XTE_MIIM_PHYAD_SHIFT 5 /**< MII Shift bits for PHYAD */ +/*@}*/ + + +/** @name Checksum offload buffer descriptor extensions + * @{ + */ +/** Byte offset where checksum should begin (16 bit word) */ +#define XTE_BD_TX_CSBEGIN_OFFSET XDMAV3_BD_USR0_OFFSET + +/** Offset where checksum should be inserted (16 bit word) */ +#define XTE_BD_TX_CSINSERT_OFFSET (XDMAV3_BD_USR0_OFFSET + 2) + +/** Checksum offload control for transmit (16 bit word) */ +#define XTE_BD_TX_CSCNTRL_OFFSET XDMAV3_BD_USR1_OFFSET + +/** Seed value for checksum calculation (16 bit word) */ +#define XTE_BD_TX_CSINIT_OFFSET (XDMAV3_BD_USR1_OFFSET + 2) + +/** Receive frame checksum calculation (16 bit word) */ +#define XTE_BD_RX_CSRAW_OFFSET (XDMAV3_BD_USR5_OFFSET + 2) + +/*@}*/ + +/** @name TX_CSCNTRL bit mask + * @{ + */ +#define XTE_BD_TX_CSCNTRL_CALC_MASK 0x0001 /**< Enable/disable Tx + checksum */ +/*@}*/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +xdbg_stmnt(extern int indent_on); + +#define XLlTemac_indent(RegOffset) \ + ((indent_on && ((RegOffset) >= XTE_RAF_OFFSET) && ((RegOffset) <= XTE_RDY_OFFSET)) ? "\t" : "") + +#define XLlTemac_reg_name(RegOffset) \ + (((RegOffset) == XTE_RAF_OFFSET) ? "XTE_RAF_OFFSET": \ + ((RegOffset) == XTE_TPF_OFFSET) ? "XTE_TPF_OFFSET": \ + ((RegOffset) == XTE_IFGP_OFFSET) ? "XTE_IFGP_OFFSET": \ + ((RegOffset) == XTE_IS_OFFSET) ? "XTE_IS_OFFSET": \ + ((RegOffset) == XTE_IP_OFFSET) ? "XTE_IP_OFFSET": \ + ((RegOffset) == XTE_IE_OFFSET) ? "XTE_IE_OFFSET": \ + ((RegOffset) == XTE_MSW_OFFSET) ? "XTE_MSW_OFFSET": \ + ((RegOffset) == XTE_LSW_OFFSET) ? "XTE_LSW_OFFSET": \ + ((RegOffset) == XTE_CTL_OFFSET) ? "XTE_CTL_OFFSET": \ + ((RegOffset) == XTE_RDY_OFFSET) ? "XTE_RDY_OFFSET": \ + ((RegOffset) == XTE_RCW0_OFFSET) ? "XTE_RCW0_OFFSET": \ + ((RegOffset) == XTE_RCW1_OFFSET) ? "XTE_RCW1_OFFSET": \ + ((RegOffset) == XTE_TC_OFFSET) ? "XTE_TC_OFFSET": \ + ((RegOffset) == XTE_FCC_OFFSET) ? "XTE_FCC_OFFSET": \ + ((RegOffset) == XTE_EMMC_OFFSET) ? "XTE_EMMC_OFFSET": \ + ((RegOffset) == XTE_PHYC_OFFSET) ? "XTE_PHYC_OFFSET": \ + ((RegOffset) == XTE_MC_OFFSET) ? "XTE_MC_OFFSET": \ + ((RegOffset) == XTE_UAW0_OFFSET) ? "XTE_UAW0_OFFSET": \ + ((RegOffset) == XTE_UAW1_OFFSET) ? "XTE_UAW1_OFFSET": \ + ((RegOffset) == XTE_MAW0_OFFSET) ? "XTE_MAW0_OFFSET": \ + ((RegOffset) == XTE_MAW1_OFFSET) ? "XTE_MAW1_OFFSET": \ + ((RegOffset) == XTE_AFM_OFFSET) ? "XTE_AFM_OFFSET": \ + ((RegOffset) == XTE_TIS_OFFSET) ? "XTE_TIS_OFFSET": \ + ((RegOffset) == XTE_TIE_OFFSET) ? "XTE_TIE_OFFSET": \ + ((RegOffset) == XTE_MIIMWD_OFFSET) ? "XTE_MIIMWD_OFFSET": \ + ((RegOffset) == XTE_MIIMAI_OFFSET) ? "XTE_MIIMAI_OFFSET": \ + "unknown") + +#define XLlTemac_print_reg_o(BaseAddress, RegOffset, Value) \ + xdbg_printf(XDBG_DEBUG_TEMAC_REG, "%s0x%0x -> %s(0x%0x)\n", \ + XLlTemac_indent(RegOffset), (Value), \ + XLlTemac_reg_name(RegOffset), (RegOffset)) \ + +#define XLlTemac_print_reg_i(BaseAddress, RegOffset, Value) \ + xdbg_printf(XDBG_DEBUG_TEMAC_REG, "%s%s(0x%0x) -> 0x%0x\n", \ + XLlTemac_indent(RegOffset), XLlTemac_reg_name(RegOffset), \ + (RegOffset), (Value)) \ + +/****************************************************************************/ +/** + * + * XLlTemac_ReadReg returns the value read from the register specified by + * <i>RegOffset</i>. + * + * @param BaseAddress is the base address of the TEMAC channel. + * @param RegOffset is the offset of the register to be read. + * + * @return XLlTemac_ReadReg returns the 32-bit value of the register. + * + * @note + * C-style signature: + * u32 XLlTemac_mReadReg(u32 BaseAddress, u32 RegOffset) + * + *****************************************************************************/ +#ifdef DEBUG +#define XLlTemac_ReadReg(BaseAddress, RegOffset) \ +({ \ + u32 value; \ + if ((RegOffset) > 0x2c) { \ + printf ("readreg: Woah! wrong reg addr: 0x%0x\n", (RegOffset)); \ + } \ + value = XIo_In32(((BaseAddress) + (RegOffset))); \ + XLlTemac_print_reg_i((BaseAddress), (RegOffset), value); \ + value; \ +}) +#else +#define XLlTemac_ReadReg(BaseAddress, RegOffset) \ + (XIo_In32(((BaseAddress) + (RegOffset)))) +#endif + +/****************************************************************************/ +/** + * + * XLlTemac_WriteReg, writes <i>Data</i> to the register specified by + * <i>RegOffset</i>. + * + * @param BaseAddress is the base address of the TEMAC channel. + * @param RegOffset is the offset of the register to be written. + * @param Data is the 32-bit value to write to the register. + * + * @return N/A + * + * @note + * C-style signature: + * void XLlTemac_mWriteReg(u32 BaseAddress, u32 RegOffset, u32 Data) + * + *****************************************************************************/ +#ifdef DEBUG +#define XLlTemac_WriteReg(BaseAddress, RegOffset, Data) \ +({ \ + if ((RegOffset) > 0x2c) { \ + printf ("writereg: Woah! wrong reg addr: 0x%0x\n", (RegOffset)); \ + } \ + XLlTemac_print_reg_o((BaseAddress), (RegOffset), (Data)); \ + XIo_Out32(((BaseAddress) + (RegOffset)), (Data)); \ +}) +#else +#define XLlTemac_WriteReg(BaseAddress, RegOffset, Data) \ + XIo_Out32(((BaseAddress) + (RegOffset)), (Data)) +#endif + +/****************************************************************************/ +/** + * + * XLlTemac_ReadIndirectReg returns the value read from the hard TEMAC register + * specified by <i>RegOffset</i>. + * + * @param BaseAddress is the base address of the TEMAC channel. + * @param RegOffset is the offset of the hard TEMAC register to be read. + * + * @return XLlTemac_ReadIndirectReg returns the 32-bit value of the register. + * + * @note + * C-style signature: + * u32 XLlTemac_mReadIndirectReg(u32 BaseAddress, u32 RegOffset) + * + *****************************************************************************/ +#ifdef DEBUG +extern u32 _xlltemac_rir_value; + +#define XLlTemac_ReadIndirectReg(BaseAddress, RegOffset) \ +( \ + indent_on = 1, \ + (((RegOffset) < 0x200) ? \ + xdbg_printf(XDBG_DEBUG_ERROR, \ + "readindirect: Woah! wrong reg addr: 0x%0x\n", \ + (RegOffset)) : 0), \ + (((RegOffset) > 0x3b4) ? \ + xdbg_printf(XDBG_DEBUG_ERROR, \ + "readindirect: Woah! wrong reg addr: 0x%0x\n", \ + (RegOffset)) : 0), \ + XLlTemac_WriteReg((BaseAddress), XTE_CTL_OFFSET, (RegOffset)), \ + _xlltemac_rir_value = XLlTemac_ReadReg((BaseAddress), XTE_LSW_OFFSET), \ + XLlTemac_print_reg_i((BaseAddress), (RegOffset), _xlltemac_rir_value), \ + indent_on = 0, \ + _xlltemac_rir_value \ +) +#else +#define XLlTemac_ReadIndirectReg(BaseAddress, RegOffset) \ +( \ + XLlTemac_WriteReg((BaseAddress), XTE_CTL_OFFSET, (RegOffset)), \ + XLlTemac_ReadReg((BaseAddress), XTE_LSW_OFFSET) \ +) +#endif + +/****************************************************************************/ +/** + * + * XLlTemac_WriteIndirectReg, writes <i>Data</i> to the hard TEMAC register + * specified by <i>RegOffset</i>. + * + * @param BaseAddress is the base address of the TEMAC channel. + * @param RegOffset is the offset of the hard TEMAC register to be written. + * @param Data is the 32-bit value to write to the register. + * + * @return N/A + * + * @note + * C-style signature: + * void XLlTemac_WriteIndirectReg(u32 BaseAddress, u32 RegOffset, u32 Data) + * + *****************************************************************************/ +#ifdef DEBUG +#define XLlTemac_WriteIndirectReg(BaseAddress, RegOffset, Data) \ +( \ + indent_on = 1, \ + (((RegOffset) < 0x200) ? \ + xdbg_printf(XDBG_DEBUG_ERROR, \ + "readindirect: Woah! wrong reg addr: 0x%0x\n", \ + (RegOffset)) : 0), \ + (((RegOffset) > 0x3b4) ? \ + xdbg_printf(XDBG_DEBUG_ERROR, \ + "readindirect: Woah! wrong reg addr: 0x%0x\n", \ + (RegOffset)) : 0), \ + XLlTemac_print_reg_o((BaseAddress), (RegOffset), (Data)), \ + XLlTemac_WriteReg((BaseAddress), XTE_LSW_OFFSET, (Data)), \ + XLlTemac_WriteReg((BaseAddress), XTE_CTL_OFFSET, \ + ((RegOffset) | XTE_CTL_WEN_MASK)), \ + ((XLlTemac_ReadReg((BaseAddress), XTE_RDY_OFFSET) & \ + XTE_RDY_HARD_ACS_RDY_MASK) ? \ + ((XLlTemac_ReadIndirectReg((BaseAddress), (RegOffset)) != (Data)) ? \ + xdbg_printf(XDBG_DEBUG_ERROR, \ + "data written is not read back: Reg: 0x%0x\n", \ + (RegOffset)) \ + : 0) \ + : xdbg_printf(XDBG_DEBUG_ERROR, "(temac_wi) RDY reg not initially ready\n")), \ + indent_on = 0 \ +) +#else +#define XLlTemac_WriteIndirectReg(BaseAddress, RegOffset, Data) \ + XLlTemac_WriteReg((BaseAddress), XTE_LSW_OFFSET, (Data)), \ + XLlTemac_WriteReg((BaseAddress), XTE_CTL_OFFSET, \ + ((RegOffset) | XTE_CTL_WEN_MASK)) +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac_main.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/net/ethernet/xilinx/xilinx_lltemac/xlltemac_main.c 2014-07-20 22:06:37.256290873 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Ethernet: Linux driver for the XPS_LLTEMAC core. + * + * Author: Xilinx, Inc. + * + * 2006-2007 (c) Xilinx, Inc. This file is licensed uner the terms of the GNU + * General Public License version 2.1. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a jvb 05/08/05 First release + * </pre> + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/mm.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/mii.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <asm/io.h> +#include <linux/ethtool.h> +#include <linux/vmalloc.h> + +#ifdef CONFIG_OF +// For open firmware. +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/of_net.h> +#endif + +#include "xbasic_types.h" +#include "xlltemac.h" +#include "xllfifo.h" +#include "xlldma.h" +#include "xlldma_bdring.h" + +#define LOCAL_FEATURE_RX_CSUM 0x01 + +/* + * Default SEND and RECV buffer descriptors (BD) numbers. + * BD Space needed is (XTE_SEND_BD_CNT+XTE_RECV_BD_CNT)*Sizeof(XLlDma_Bd). + * Each XLlDma_Bd instance currently takes 40 bytes. + */ +#define XTE_SEND_BD_CNT 256 +#define XTE_RECV_BD_CNT 256 + +/* Must be shorter than length of ethtool_drvinfo.driver field to fit */ +#define DRIVER_NAME "xilinx_lltemac" +#define DRIVER_DESCRIPTION "Xilinx Tri-Mode Ethernet MAC driver" +#define DRIVER_VERSION "1.00a" + +#define TX_TIMEOUT (3*HZ) /* Transmission timeout is 3 seconds. */ + +/* + * This version of the Xilinx TEMAC uses external DMA or FIFO cores. + * Currently neither the DMA or FIFO cores used require any memory alignment + * restrictions. + */ +/* + * ALIGNMENT_RECV = the alignement required to receive + * ALIGNMENT_SEND = the alignement required to send + * ALIGNMENT_SEND_PERF = tx alignment for better performance + * + * ALIGNMENT_SEND is used to see if we *need* to copy the data to re-align. + * ALIGNMENT_SEND_PERF is used if we've decided we need to copy anyway, we just + * copy to this alignment for better performance. + */ + +#define ALIGNMENT_RECV 34 +#define ALIGNMENT_SEND 8 +#define ALIGNMENT_SEND_PERF 32 + +#define XTE_SEND 1 +#define XTE_RECV 2 + +/* SGDMA buffer descriptors must be aligned on a 8-byte boundary. */ +#define ALIGNMENT_BD XLLDMA_BD_MINIMUM_ALIGNMENT + +/* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */ +#define BUFFER_ALIGNSEND(adr) ((ALIGNMENT_SEND - ((u32) adr)) % ALIGNMENT_SEND) +#define BUFFER_ALIGNSEND_PERF(adr) ((ALIGNMENT_SEND_PERF - ((u32) adr)) % 32) +#define BUFFER_ALIGNRECV(adr) ((ALIGNMENT_RECV - ((u32) adr)) % 32) + +/* Default TX/RX Threshold and waitbound values for SGDMA mode */ +#define DFT_TX_THRESHOLD 24 +#define DFT_TX_WAITBOUND 254 +#define DFT_RX_THRESHOLD 4 +#define DFT_RX_WAITBOUND 254 + +#define XTE_AUTOSTRIPPING 1 + +/* Put Buffer Descriptors in BRAM? + * NOTE: + * Putting BDs in BRAM only works if there is only ONE instance of the TEMAC + * in hardware. The code does not handle multiple instances, e.g. it does + * not manage the memory in BRAM. + */ +#define BD_IN_BRAM 0 +#define BRAM_BASEADDR 0xffff8000 + + +/* + * Checksum offload macros + */ +#define BdCsumEnable(BdPtr) \ + XLlDma_mBdWrite((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET, \ + (XLlDma_mBdRead((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET)) | 1 ) + +/* Used for debugging */ +#define BdCsumEnabled(BdPtr) \ + ((XLlDma_mBdRead((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET)) & 1) + +#define BdCsumDisable(BdPtr) \ + XLlDma_mBdWrite((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET, \ + (XLlDma_mBdRead((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET)) & 0xFFFFFFFE ) + +#define BdCsumSetup(BdPtr, Start, Insert) \ + XLlDma_mBdWrite((BdPtr), XLLDMA_BD_USR1_OFFSET, ((Start) << 16) | (Insert)) + +/* Used for debugging */ +#define BdCsumInsert(BdPtr) \ + (XLlDma_mBdRead((BdPtr), XLLDMA_BD_USR1_OFFSET) & 0xffff) + +#define BdCsumSeed(BdPtr, Seed) \ + XLlDma_mBdWrite((BdPtr), XLLDMA_BD_USR2_OFFSET, 0) + +#define BdCsumGet(BdPtr) \ + (XLlDma_mBdRead((BdPtr), XLLDMA_BD_USR3_OFFSET) & 0xffff) + +#define BdGetRxLen(BdPtr) \ + (XLlDma_mBdRead((BdPtr), XLLDMA_BD_USR4_OFFSET) & 0x3fff) + +/* LLTEMAC platform data */ +struct xlltemac_platform_data { + u8 tx_csum; + u8 rx_csum; + u8 phy_type; + u8 dcr_host; + u8 ll_dev_type; + u32 ll_dev_baseaddress; + u32 ll_dev_dma_rx_irq; + u32 ll_dev_dma_tx_irq; + u32 ll_dev_fifo_irq; + + u8 mac_addr[6]; +}; + +/* + * Our private per device data. When a net_device is allocated we will + * ask for enough extra space for this. + */ +struct net_local { + struct list_head rcv; + struct list_head xmit; + + struct net_device *ndev; /* this device */ + struct net_device *next_dev; /* The next device in dev_list */ + struct net_device_stats stats; /* Statistics for this device */ + struct timer_list phy_timer; /* PHY monitoring timer */ + + u32 index; /* Which interface is this */ +#if 0 + XInterruptHandler Isr; /* Pointer to the XLlTemac ISR routine */ +#endif + u8 gmii_addr; /* The GMII address of the PHY */ + u32 virt_dma_addr; /* Virtual address to mapped dma */ + + /* The underlying OS independent code needs space as well. A + * pointer to the following XLlTemac structure will be passed to + * any XLlTemac_ function that requires it. However, we treat the + * data as an opaque object in this file (meaning that we never + * reference any of the fields inside of the structure). */ + XLlFifo Fifo; + XLlDma Dma; + XLlTemac Emac; + + unsigned int fifo_irq; /* fifo irq */ + unsigned int dma_irq_s; /* send irq */ + unsigned int dma_irq_r; /* recv irq */ + unsigned int frame_size; /* actual frame size = mtu + padding */ + + int cur_speed; + + /* Buffer Descriptor space for both TX and RX BD ring */ + void *desc_space; /* virtual address of BD space */ + dma_addr_t desc_space_handle; /* physical address of BD space */ + int desc_space_size; /* size of BD space */ + + /* buffer for one skb in case no room is available for transmission */ + struct sk_buff *deferred_skb; + + /* send buffers for non tx-dre hw */ + void **tx_orig_buffers; /* Buffer addresses as returned by + dma_alloc_coherent() */ + void **tx_buffers; /* Buffers addresses aligned for DMA */ + dma_addr_t *tx_phys_buffers; /* Buffer addresses in physical memory */ + size_t tx_buffers_cur; /* Index of current buffer used */ + + /* stats */ + int max_frags_in_a_packet; + unsigned long realignments; + unsigned long tx_hw_csums; + unsigned long rx_hw_csums; + unsigned long local_features; +#if ! XTE_AUTOSTRIPPING + unsigned long stripping; +#endif +}; + +static u32 dma_rx_int_mask = XLLDMA_CR_IRQ_ALL_EN_MASK; +static u32 dma_tx_int_mask = XLLDMA_CR_IRQ_ALL_EN_MASK; + +/* for exclusion of all program flows (processes, ISRs and BHs) */ +static spinlock_t XTE_spinlock; /* = SPIN_LOCK_UNLOCKED; */ +static spinlock_t XTE_tx_spinlock; /* = SPIN_LOCK_UNLOCKED; */ +static spinlock_t XTE_rx_spinlock; /* = SPIN_LOCK_UNLOCKED; */ + +/* + * ethtool has a status reporting feature where we can report any sort of + * status information we'd like. This is the list of strings used for that + * status reporting. ETH_GSTRING_LEN is defined in ethtool.h + */ +static char xenet_ethtool_gstrings_stats[][ETH_GSTRING_LEN] = { + "txpkts", "txdropped", "txerr", "txfifoerr", + "rxpkts", "rxdropped", "rxerr", "rxfifoerr", + "rxrejerr", "max_frags", "tx_hw_csums", "rx_hw_csums", +}; + +#define XENET_STATS_LEN sizeof(xenet_ethtool_gstrings_stats) / ETH_GSTRING_LEN + +/* Helper function to determine if a given XLlTemac error warrants a reset. */ +extern inline int status_requires_reset(int s) +{ + return (s == XST_FIFO_ERROR || + s == XST_PFIFO_DEADLOCK || + s == XST_DMA_ERROR || s == XST_IPIF_ERROR); +} + +/* Queues with locks */ +static LIST_HEAD(receivedQueue); +static spinlock_t receivedQueueSpin; // = SPIN_LOCK_UNLOCKED; + +static LIST_HEAD(sentQueue); +static spinlock_t sentQueueSpin; // = SPIN_LOCK_UNLOCKED; + + +/* from mii.h + * + * Items in mii.h but not in gmii.h + */ +#define ADVERTISE_100FULL 0x0100 +#define ADVERTISE_100HALF 0x0080 +#define ADVERTISE_10FULL 0x0040 +#define ADVERTISE_10HALF 0x0020 +#define ADVERTISE_CSMA 0x0001 + +#define EX_ADVERTISE_1000FULL 0x0200 +#define EX_ADVERTISE_1000HALF 0x0100 + +/* + * items not in mii.h nor gmii.h but should be + */ +#define MII_EXADVERTISE 0x09 + +/* + * Wrap certain temac routines with a lock, so access to the shared hard temac + * interface is accessed mutually exclusive for dual channel temac support. + */ + +static inline void _XLlTemac_Start(XLlTemac *InstancePtr) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_Start(InstancePtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + +static inline void _XLlTemac_Stop(XLlTemac *InstancePtr) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_Stop(InstancePtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + +static inline void _XLlTemac_Reset(XLlTemac *InstancePtr, int HardCoreAction) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_Reset(InstancePtr, HardCoreAction); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + +static inline int _XLlTemac_SetMacAddress(XLlTemac *InstancePtr, + void *AddressPtr) +{ + int status; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + status = XLlTemac_SetMacAddress(InstancePtr, AddressPtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + return status; +} + +static inline void _XLlTemac_GetMacAddress(XLlTemac *InstancePtr, + void *AddressPtr) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_GetMacAddress(InstancePtr, AddressPtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + +static inline int _XLlTemac_SetOptions(XLlTemac *InstancePtr, u32 Options) +{ + int status; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + status = XLlTemac_SetOptions(InstancePtr, Options); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + return status; +} + +static inline int _XLlTemac_ClearOptions(XLlTemac *InstancePtr, u32 Options) +{ + int status; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + status = XLlTemac_ClearOptions(InstancePtr, Options); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + return status; +} + +static inline u16 _XLlTemac_GetOperatingSpeed(XLlTemac *InstancePtr) +{ + u16 speed; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + speed = XLlTemac_GetOperatingSpeed(InstancePtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + return speed; +} + +static inline void _XLlTemac_SetOperatingSpeed(XLlTemac *InstancePtr, u16 Speed) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_SetOperatingSpeed(InstancePtr, Speed); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + /* We need a delay after we set the speed. Otherwise the PHY will not be ready. */ + udelay(10000); +} + +static inline void _XLlTemac_PhySetMdioDivisor(XLlTemac *InstancePtr, u8 Divisor) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_PhySetMdioDivisor(InstancePtr, Divisor); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + +static inline void _XLlTemac_PhyRead(XLlTemac *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_PhyRead(InstancePtr, PhyAddress, RegisterNum, PhyDataPtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + +static inline void _XLlTemac_PhyWrite(XLlTemac *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_PhyWrite(InstancePtr, PhyAddress, RegisterNum, PhyData); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + + +static inline int _XLlTemac_MulticastClear(XLlTemac *InstancePtr, int Entry) +{ + int status; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + status = XLlTemac_MulticastClear(InstancePtr, Entry); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + return status; +} + +static inline int _XLlTemac_SetMacPauseAddress(XLlTemac *InstancePtr, void *AddressPtr) +{ + int status; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + status = XLlTemac_SetMacPauseAddress(InstancePtr, AddressPtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + return status; +} + +static inline void _XLlTemac_GetMacPauseAddress(XLlTemac *InstancePtr, void *AddressPtr) +{ + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_GetMacPauseAddress(InstancePtr, AddressPtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + +static inline int _XLlTemac_GetSgmiiStatus(XLlTemac *InstancePtr, u16 *SpeedPtr) +{ + int status; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + status = XLlTemac_GetSgmiiStatus(InstancePtr, SpeedPtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + return status; +} + +static inline int _XLlTemac_GetRgmiiStatus(XLlTemac *InstancePtr, + u16 *SpeedPtr, + int *IsFullDuplexPtr, + int *IsLinkUpPtr) +{ + int status; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + status = XLlTemac_GetRgmiiStatus(InstancePtr, SpeedPtr, IsFullDuplexPtr, IsLinkUpPtr); + spin_unlock_irqrestore(&XTE_spinlock, flags); + + return status; +} + + +#ifdef CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_RGMII +#define MARVELL_88E1111_EXTENDED_PHY_CTL_REG_OFFSET 20 +#define MARVELL_88E1111_EXTENDED_PHY_STATUS_REG_OFFSET 27 +#endif + +#ifdef CONFIG_XILINX_LLTEMAC_NATIONAL_DP83865_GMII +# define NATIONAL_DP83865_CONTROL_INIT 0x9200 +# define NATIONAL_DP83865_CONTROL 0 +# define NATIONAL_DP83865_STATUS 1 +# define NATIONAL_DP83865_STATUS_LINK 0x04 +# define NATIONAL_DP83865_STATUS_AUTONEGEND 0x20 +# define NATIONAL_DP83865_STATUS_AUTONEG 0x11 +# define NATIONAL_DP83865_LINKSPEED_1000M 0x10 +# define NATIONAL_DP83865_LINKSPEED_100M 0x8 +# define NATIONAL_DP83865_LINKSPEED_MASK 0x18 +# define NATIONAL_DP83865_RETRIES 5 +#endif + +#define DEBUG_ERROR KERN_ERR +#define DEBUG_LOG(level, ...) printk(level __VA_ARGS__) + +/* + * Perform any necessary special phy setup. In the gmii case, nothing needs to + * be done. + */ +static void phy_setup(struct net_local *lp) +{ +#ifdef CONFIG_XILINX_LLTEMAC_NATIONAL_DP83865_GMII + u16 RegValue; + + printk(KERN_INFO "NATIONAL DP83865 PHY\n"); + RegValue = NATIONAL_DP83865_CONTROL_INIT; + /*Do not reset phy*/ + _XLlTemac_PhyWrite(&lp->Emac, lp->gmii_addr, + NATIONAL_DP83865_CONTROL, RegValue); + + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, + NATIONAL_DP83865_STATUS, &RegValue); + + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, + NATIONAL_DP83865_STATUS, &RegValue); +#endif +#ifdef CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_RGMII + u16 Register; + + /* + * Set up MAC interface + * + * Write 0x0cc3 to reg 20 in PHY + * 5432 1098 7654 3210 + * ---- ---- ---- ---- + * 0cc3=0000 1100 1100 0011 + * downshift counter (bits 11-9): 110 = 7 times + * downshift enable (bit 8): 0 = enable + * RGMII timing control (bit 7): 1 = add delay to rx clk ro rxd + * outputs + * Default Mac interface speed (bits 6-4): 100 = 10mbps 2.5 mhz + * (between phy and temac - gets renegotiated) + * reserved (bit 3) + * DTE detect (bit 2): 0 disabled + * RGMII transmit timing control (bit 1): 1 = add delay + * to tx clk ro txd outputs + * Transmitter Disable (bit 0): 1 = enabled + */ + _XLlTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MARVELL_88E1111_EXTENDED_PHY_CTL_REG_OFFSET, 0x0cc3); + + /* + * Set RGMII to copper with correct hysterisis and correct mode + * Disable fiber/copper auto sel, choose copper + * RGMII /Modified MII to copper mode + * + * Write 0x848b to reg 27 + * 5432 1098 7654 3210 + * ---- ---- ---- ---- + * 848b=1000 0100 1000 1011 + * Fiber/Copper Auto Selection (bit 15): 1 = disable auto selection + * Interrupt Polarity (bit 10): 1 = int active low + * DTE detect status drop hysteresis (bts 8-5): 0100 = report 20s after DTE power status drop + * HWCFG mode (bits 3-0): 1011 = RGMII/Modified MII to Copper + */ + _XLlTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MARVELL_88E1111_EXTENDED_PHY_STATUS_REG_OFFSET, 0x848b); + + /* + * Reset the PHY + */ + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMCR, &Register); + Register |= BMCR_RESET; + _XLlTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MII_BMCR, Register); + +#endif /* CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_RGMII */ + +#ifdef CONFIG_XILINX_LLTEMAC_XILINX_1000BASEX + u16 Register; + + /* + * Setup the PHY control register + */ + Register = BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_ANENABLE; + _XLlTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MII_BMCR, Register); + +#endif /* CONFIG_XILINX_LLTEMAC_XILINX_1000BASEX */ +} + + +typedef enum DUPLEX { UNKNOWN_DUPLEX, HALF_DUPLEX, FULL_DUPLEX } DUPLEX; + +static int renegotiate_speed(struct net_device *dev, int speed, DUPLEX duplex) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + int retries = 2; + int wait_count; + u16 phy_reg0 = BMCR_ANENABLE | BMCR_ANRESTART; + u16 phy_reg1; + u16 phy_reg4; + u16 phy_reg9 = 0; + + + /* + * It appears that the 10baset full and half duplex settings + * are overloaded for gigabit ethernet + */ + if ((duplex == FULL_DUPLEX) && (speed == 10)) { + phy_reg4 = ADVERTISE_10FULL | ADVERTISE_CSMA; + } + else if ((duplex == FULL_DUPLEX) && (speed == 100)) { + phy_reg4 = ADVERTISE_100FULL | ADVERTISE_CSMA; + } + else if ((duplex == FULL_DUPLEX) && (speed == 1000)) { + phy_reg4 = ADVERTISE_CSMA; + phy_reg9 = EX_ADVERTISE_1000FULL; + } + else if (speed == 10) { + phy_reg4 = ADVERTISE_10HALF | ADVERTISE_CSMA; + } + else if (speed == 100) { + phy_reg4 = ADVERTISE_100HALF | ADVERTISE_CSMA; + } + else if (speed == 1000) { + phy_reg4 = ADVERTISE_CSMA; + phy_reg9 = EX_ADVERTISE_1000HALF; + } + else { + printk(KERN_ERR + "%s: XLlTemac: unsupported speed requested: %d\n", + dev->name, speed); + return -1; + } + + /* + * link status in register 1: + * first read / second read: + * 0 0 link is down + * 0 1 link is up (but it was down earlier) + * 1 0 link is down (but it was just up) + * 1 1 link is up + * + */ + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, &phy_reg1); + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, &phy_reg1); + _XLlTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MII_ADVERTISE, phy_reg4); + _XLlTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MII_EXADVERTISE, phy_reg9); + +#ifndef CONFIG_XILINX_LLTEMAC_NATIONAL_DP83865_GMII + while (retries--) { + /* initiate an autonegotiation of the speed */ + _XLlTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MII_BMCR, phy_reg0); + + wait_count = 10; /* so we don't loop forever */ + while (wait_count--) { + /* wait a bit for the negotiation to complete */ + mdelay(500); + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, + &phy_reg1); + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, + &phy_reg1); + + if ((phy_reg1 & BMSR_LSTATUS) && + (phy_reg1 & BMSR_ANEGCOMPLETE)) + break; + + } + + if (phy_reg1 & BMSR_LSTATUS) { + printk(KERN_INFO + "%s: XLlTemac: We renegotiated the speed to: %d\n", + dev->name, speed); + return 0; + } + else { + printk(KERN_ERR + "%s: XLlTemac: Not able to set the speed to %d (status: 0x%0x)\n", + dev->name, speed, phy_reg1); + return -1; + } + } + + printk(KERN_ERR + "%s: XLlTemac: Not able to set the speed to %d\n", dev->name, + speed); + return -1; +#else + printk(KERN_INFO + "%s: XLlTemac: We renegotiated the speed to: %d\n", + dev->name, speed); + return 0; +#endif +} + +/* + * This function sets up MAC's speed according to link speed of PHY + */ +static void set_mac_speed(struct net_local *lp) +{ + u16 phylinkspeed; + struct net_device *dev = lp->ndev; + +#ifdef CONFIG_XILINX_LLTEMAC_NATIONAL_DP83865_GMII + u16 RegValue; + int i; + + for (i = 0; i < NATIONAL_DP83865_RETRIES*10; i++) { + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, + NATIONAL_DP83865_STATUS, &RegValue); + if (RegValue & (NATIONAL_DP83865_STATUS_AUTONEGEND + |NATIONAL_DP83865_STATUS_LINK)) + break; + udelay(1 * 100000); + } + + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, + NATIONAL_DP83865_STATUS_AUTONEG, &RegValue); + /* Get current link speed */ + phylinkspeed = (RegValue & NATIONAL_DP83865_LINKSPEED_MASK); + + /* Update TEMAC speed accordingly */ + switch (phylinkspeed) { + case (NATIONAL_DP83865_LINKSPEED_1000M): + _XLlTemac_SetOperatingSpeed(&lp->Emac, 1000); + printk(KERN_INFO "XLlTemac: speed set to 1000Mb/s\n"); + break; + case (NATIONAL_DP83865_LINKSPEED_100M): + _XLlTemac_SetOperatingSpeed(&lp->Emac, 100); + printk(KERN_INFO "XLlTemac: speed set to 100Mb/s\n"); + break; + default: + _XLlTemac_SetOperatingSpeed(&lp->Emac, 10); + printk(KERN_INFO "XLlTemac: speed set to 10Mb/s\n"); + break; + } + + return; + +#elif CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_GMII + /* + * This function is specific to MARVELL 88E1111 PHY chip on + * many Xilinx boards and assumes GMII interface is being used + * by the TEMAC. + */ + +#define MARVELL_88E1111_PHY_SPECIFIC_STATUS_REG_OFFSET 17 +#define MARVELL_88E1111_LINKSPEED_MARK 0xC000 +#define MARVELL_88E1111_LINKSPEED_SHIFT 14 +#define MARVELL_88E1111_LINKSPEED_1000M 0x0002 +#define MARVELL_88E1111_LINKSPEED_100M 0x0001 +#define MARVELL_88E1111_LINKSPEED_10M 0x0000 + u16 RegValue; + + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, + MARVELL_88E1111_PHY_SPECIFIC_STATUS_REG_OFFSET, + &RegValue); + /* Get current link speed */ + phylinkspeed = (RegValue & MARVELL_88E1111_LINKSPEED_MARK) + >> MARVELL_88E1111_LINKSPEED_SHIFT; + + /* Update TEMAC speed accordingly */ + switch (phylinkspeed) { + case (MARVELL_88E1111_LINKSPEED_1000M): + _XLlTemac_SetOperatingSpeed(&lp->Emac, 1000); + printk(KERN_INFO "%s: XLlTemac: speed set to 1000Mb/s\n", + dev->name); + lp->cur_speed = 1000; + break; + case (MARVELL_88E1111_LINKSPEED_100M): + _XLlTemac_SetOperatingSpeed(&lp->Emac, 100); + printk(KERN_INFO "%s: XLlTemac: speed set to 100Mb/s\n", + dev->name); + lp->cur_speed = 100; + break; + case (MARVELL_88E1111_LINKSPEED_10M): + _XLlTemac_SetOperatingSpeed(&lp->Emac, 10); + printk(KERN_INFO "%s: XLlTemac: speed set to 10Mb/s\n", + dev->name); + lp->cur_speed = 10; + break; + default: + _XLlTemac_SetOperatingSpeed(&lp->Emac, 1000); + printk(KERN_INFO "%s: XLlTemac: speed defaults to 1000Mb/s\n", + dev->name); + lp->cur_speed = 1000; + break; + } + +#elif defined CONFIG_XILINX_LLTEMAC_XILINX_1000BASEX + /* + * This function is specific to Xilinx 1000Base-X PHY, + * which only supports 1000Mbps, Full duplex links + */ + + _XLlTemac_SetOperatingSpeed(&lp->Emac, 1000); + printk(KERN_INFO "%s: XLlTemac: speed set to 1000Mb/s\n", dev->name); + lp->cur_speed = 1000; + +#else /* generic PHY, there have been issues with 10Mbit with this code */ + int ret; + int retry_count = 1; + + if (XLlTemac_GetPhysicalInterface(&lp->Emac) == XTE_PHY_TYPE_MII) { + phylinkspeed = 100; + } + else { + phylinkspeed = 1000; + } + + /* + * Try to renegotiate the speed until something sticks + */ + while (phylinkspeed > 1) { + ret = renegotiate_speed(dev, phylinkspeed, FULL_DUPLEX); + /* + * ret == 1 - try it again + * ret == 0 - it worked + * ret < 0 - there was some failure negotiating the speed + */ + if (ret == 0) { + /* it worked, get out of the loop */ + break; + } + + /* it didn't work this time, but it may work if we try again */ + if ((ret == 1) && (retry_count)) { + retry_count--; + printk("trying again...\n"); + continue; + } + /* reset the retry_count, becuase we're about to try a lower speed */ + retry_count = 1; + phylinkspeed /= 10; + } + if (phylinkspeed == 1) { + printk(KERN_INFO "%s: XLlTemac: could not negotiate speed\n", + dev->name); + lp->cur_speed = 0; + + return; + } + + _XLlTemac_SetOperatingSpeed(&lp->Emac, phylinkspeed); + printk(KERN_INFO "%s: XLlTemac: speed set to %dMb/s\n", dev->name, + phylinkspeed); + lp->cur_speed = phylinkspeed; +#endif +} + +/* + * Helper function to reset the underlying hardware. This is called + * when we get into such deep trouble that we don't know how to handle + * otherwise. + */ +static void reset(struct net_device *dev, u32 line_num) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + u32 TxThreshold, TxWaitBound, RxThreshold, RxWaitBound; + u32 Options; + static u32 reset_cnt = 0; + int status; + + printk(KERN_INFO "%s: XLlTemac: resets (#%u) from adapter code line %d\n", + dev->name, ++reset_cnt, line_num); + + /* Shouldn't really be necessary, but shouldn't hurt. */ + netif_stop_queue(dev); + + /* Stop device */ + _XLlTemac_Stop(&lp->Emac); + + /* + * XLlTemac_Reset puts the device back to the default state. We need + * to save all the settings we don't already know, reset, restore + * the settings, and then restart the TEMAC. + */ + Options = XLlTemac_GetOptions(&lp->Emac); + + /* + * Capture the dma coalesce settings (if needed) and reset the + * connected core, dma or fifo + */ + if (XLlTemac_IsDma(&lp->Emac)) { + XLlDma_BdRingGetCoalesce(&XLlDma_mGetRxRing(&lp->Dma), + &RxThreshold, &RxWaitBound); + XLlDma_BdRingGetCoalesce(&XLlDma_mGetTxRing(&lp->Dma), + &TxThreshold, &TxWaitBound); + + XLlDma_Reset(&lp->Dma); + } else { + XLlFifo_Reset(&lp->Fifo); + } + + /* now we can reset the device */ + _XLlTemac_Reset(&lp->Emac, XTE_NORESET_HARD); + + /* Reset on TEMAC also resets PHY. Give it some time to finish negotiation + * before we move on */ + mdelay(2000); + + /* + * The following four functions will return an error if the + * EMAC is already started. We just stopped it by calling + * _XLlTemac_Reset() so we can safely ignore the return values. + */ + (int) _XLlTemac_SetMacAddress(&lp->Emac, dev->dev_addr); + (int) _XLlTemac_SetOptions(&lp->Emac, Options); + (int) _XLlTemac_ClearOptions(&lp->Emac, ~Options); + Options = XLlTemac_GetOptions(&lp->Emac); + printk(KERN_INFO "%s: XLlTemac: Options: 0x%x\n", dev->name, Options); + + phy_setup(lp); + set_mac_speed(lp); + + if (XLlTemac_IsDma(&lp->Emac)) { /* SG DMA mode */ + status = XLlDma_BdRingSetCoalesce(&lp->Dma.RxBdRing, + RxThreshold, RxWaitBound); + status |= XLlDma_BdRingSetCoalesce(&lp->Dma.TxBdRing, + TxThreshold, TxWaitBound); + if (status != XST_SUCCESS) { + /* Print the error, but keep on going as it's not a fatal error. */ + printk(KERN_ERR "%s: XLlTemac: error setting coalesce values (probably out of range). status: %d\n", + dev->name, status); + } + XLlDma_mBdRingIntEnable(&lp->Dma.RxBdRing, dma_rx_int_mask); + XLlDma_mBdRingIntEnable(&lp->Dma.TxBdRing, dma_tx_int_mask); + } else { /* FIFO interrupt mode */ + XLlFifo_IntEnable(&lp->Fifo, XLLF_INT_TC_MASK | + XLLF_INT_RC_MASK | XLLF_INT_RXERROR_MASK | + XLLF_INT_TXERROR_MASK); + } + XLlTemac_IntDisable(&lp->Emac, XTE_INT_ALL_MASK); + + if (lp->deferred_skb) { + dev_kfree_skb_any(lp->deferred_skb); + lp->deferred_skb = NULL; + lp->stats.tx_errors++; + } + + /* + * XLlTemac_Start returns an error when: if configured for + * scatter-gather DMA and a descriptor list has not yet been created + * for the send or receive channel, or if no receive buffer descriptors + * have been initialized. Those are not happening. so ignore the returned + * result checking. + */ + _XLlTemac_Start(&lp->Emac); + + /* We're all ready to go. Start the queue in case it was stopped. */ + netif_wake_queue(dev); +} + +/* + * The PHY registers read here should be standard registers in all PHY chips + */ +static int get_phy_status(struct net_device *dev, DUPLEX * duplex, int *linkup) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + u16 reg; + + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMCR, ®); + *duplex = FULL_DUPLEX; + +#ifdef CONFIG_XILINX_LLTEMAC_NATIONAL_DP83865_GMII + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, + NATIONAL_DP83865_STATUS, ®); + *linkup=(reg & NATIONAL_DP83865_STATUS_LINK) != 0; + +#else + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, ®); + *linkup = (reg & BMSR_LSTATUS) != 0; +#endif + + return 0; +} + +/* + * This routine is used for two purposes. The first is to keep the + * EMAC's duplex setting in sync with the PHY's. The second is to keep + * the system apprised of the state of the link. Note that this driver + * does not configure the PHY. Either the PHY should be configured for + * auto-negotiation or it should be handled by something like mii-tool. */ +static void poll_gmii(unsigned long data) +{ + struct net_device *dev; + struct net_local *lp; + DUPLEX phy_duplex; + int phy_carrier; + int netif_carrier; + + dev = (struct net_device *) data; + lp = (struct net_local *) netdev_priv(dev); + + /* First, find out what's going on with the PHY. */ + if (get_phy_status(dev, &phy_duplex, &phy_carrier)) { + printk(KERN_ERR "%s: XLlTemac: terminating link monitoring.\n", + dev->name); + return; + } + netif_carrier = netif_carrier_ok(dev) != 0; + if (phy_carrier != netif_carrier) { + if (phy_carrier) { + set_mac_speed(lp); + printk(KERN_INFO + "%s: XLlTemac: PHY Link carrier restored.\n", + dev->name); + netif_carrier_on(dev); + } + else { + printk(KERN_INFO "%s: XLlTemac: PHY Link carrier lost.\n", + dev->name); + netif_carrier_off(dev); + } + } + + /* Set up the timer so we'll get called again in 2 seconds. */ + lp->phy_timer.expires = jiffies + 2 * HZ; + add_timer(&lp->phy_timer); +} + +static irqreturn_t xenet_temac_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + /* + * All we care about here is the RxRject interrupts. Explanation below: + * + * Interrupt Usage Description + * --------- ----------------- + * TxCmplt: Fifo or DMA will have completion interrupts. We'll use + * those and not the TEMAC ones. + * RxFifoOvr: if the RX fifo is overflowing, the last thing we need + * is more interrupts to handle. + * RxRJect: We're keeping stats on rejected packets (we could + * choose not to). + * RxCmplt: Fifo or DMA will have completion interrupts. We'll use + * those and not the TEMAC ones. + * AutoNeg: This driver doesn't make use of the autonegotation + * completion interrupt. + * HardAcsCmplt: This driver just polls the RDY register for this + * information instead of using an interrupt handler. + * CfgWst, CfgRst, + * AfWst, AfRst, + * MiimWst, MiimRst, + * FabrRst: All of these registers indicate when access (read or + * write) to one or other of the Hard Temac Core + * registers is complete. Instead of relying on an + * interrupt context switch to be notified that the + * access is complete, this driver instead polls for the + * status, which, in most cases, should be faster. + */ + XLlTemac_IntClear(&lp->Emac, XTE_INT_ALL_MASK); + + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + + + return IRQ_HANDLED; +} + +static void FifoSendHandler(struct net_device *dev); +static void FifoRecvHandler(unsigned long p /*struct net_device *dev*/); + +static DECLARE_TASKLET(FifoRecvBH, FifoRecvHandler, 0); + +static irqreturn_t xenet_fifo_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct net_local *lp = (struct net_local *) netdev_priv(dev); + u32 irq_status; + + unsigned long flags; + + /* + * Need to: + * 1) Read the FIFO IS register + * 2) clear all bits in the FIFO IS register + * 3) loop on each bit in the IS register, and handle each interrupt event + * + */ + irq_status = XLlFifo_IntPending(&lp->Fifo); + XLlFifo_IntClear(&lp->Fifo, irq_status); + while (irq_status) { + if (irq_status & XLLF_INT_RC_MASK) { + /* handle the receive completion */ + struct list_head *cur_lp; + spin_lock_irqsave(&receivedQueueSpin, flags); + list_for_each(cur_lp, &receivedQueue) { + if (cur_lp == &(lp->rcv)) { + break; + } + } + if (cur_lp != &(lp->rcv)) { + list_add_tail(&lp->rcv, &receivedQueue); + XLlFifo_IntDisable(&lp->Fifo, XLLF_INT_ALL_MASK); + tasklet_schedule(&FifoRecvBH); + } + spin_unlock_irqrestore(&receivedQueueSpin, flags); + irq_status &= ~XLLF_INT_RC_MASK; + } else if (irq_status & XLLF_INT_TC_MASK) { + /* handle the transmit completion */ + FifoSendHandler(dev); + irq_status &= ~XLLF_INT_TC_MASK; + } else if (irq_status & XLLF_INT_TXERROR_MASK) { + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + XLlFifo_Reset(&lp->Fifo); + irq_status &= ~XLLF_INT_TXERROR_MASK; + } else if (irq_status & XLLF_INT_RXERROR_MASK) { + lp->stats.rx_errors++; + XLlFifo_Reset(&lp->Fifo); + irq_status &= ~XLLF_INT_RXERROR_MASK; + } else { + /* debug + * if (irq_status == 0) printk("Temac: spurious fifo int\n"); + */ + } + } + + return IRQ_HANDLED; +} + +/* The callback function for completed frames sent in SGDMA mode. */ +static void DmaSendHandlerBH(unsigned long p); +static void DmaRecvHandlerBH(unsigned long p); + +static DECLARE_TASKLET(DmaSendBH, DmaSendHandlerBH, 0); +static DECLARE_TASKLET(DmaRecvBH, DmaRecvHandlerBH, 0); + +static irqreturn_t xenet_dma_rx_interrupt(int irq, void *dev_id) +{ + u32 irq_status; + struct net_device *dev = dev_id; + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct list_head *cur_lp; + + unsigned long flags; + + /* Read pending interrupts */ + irq_status = XLlDma_mBdRingGetIrq(&lp->Dma.RxBdRing); + + XLlDma_mBdRingAckIrq(&lp->Dma.RxBdRing, irq_status); + + if ((irq_status & XLLDMA_IRQ_ALL_ERR_MASK)) { + XLlDma_Reset(&lp->Dma); + return IRQ_HANDLED; + } + if ((irq_status & (XLLDMA_IRQ_DELAY_MASK | XLLDMA_IRQ_COALESCE_MASK))) { + spin_lock_irqsave(&receivedQueueSpin, flags); + list_for_each(cur_lp, &receivedQueue) { + if (cur_lp == &(lp->rcv)) { + break; + } + } + if (cur_lp != &(lp->rcv)) { + list_add_tail(&lp->rcv, &receivedQueue); + XLlDma_mBdRingIntDisable(&lp->Dma.RxBdRing, + XLLDMA_CR_IRQ_ALL_EN_MASK); + tasklet_schedule(&DmaRecvBH); + } + spin_unlock_irqrestore(&receivedQueueSpin, flags); + } + return IRQ_HANDLED; +} + +static irqreturn_t xenet_dma_tx_interrupt(int irq, void *dev_id) +{ + u32 irq_status; + struct net_device *dev = dev_id; + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct list_head *cur_lp; + + unsigned long flags; + + /* Read pending interrupts */ + irq_status = XLlDma_mBdRingGetIrq(&(lp->Dma.TxBdRing)); + + XLlDma_mBdRingAckIrq(&(lp->Dma.TxBdRing), irq_status); + + if ((irq_status & XLLDMA_IRQ_ALL_ERR_MASK)) { + XLlDma_Reset(&lp->Dma); + return IRQ_HANDLED; + } + + if ((irq_status & (XLLDMA_IRQ_DELAY_MASK | XLLDMA_IRQ_COALESCE_MASK))) { + spin_lock_irqsave(&sentQueueSpin, flags); + list_for_each(cur_lp, &sentQueue) { + if (cur_lp == &(lp->xmit)) { + break; + } + } + if (cur_lp != &(lp->xmit)) { + list_add_tail(&lp->xmit, &sentQueue); + XLlDma_mBdRingIntDisable(&lp->Dma.TxBdRing, + XLLDMA_CR_IRQ_ALL_EN_MASK); + tasklet_schedule(&DmaSendBH); + } + spin_unlock_irqrestore(&sentQueueSpin, flags); + } + return IRQ_HANDLED; +} + +/* + * Q: + * Why doesn't this linux driver use an interrupt handler for the TEMAC itself? + * + * A: + * Let's take a look at all the possible events that could be signaled by the + * TEMAC core. + * + * possible events: + * Transmit Complete (TxCmplt) [not handled by this driver] + * The TEMAC TxCmplt interrupt status is ignored by software in favor of + * paying attention to the transmit complete status in the connected DMA + * or FIFO core. + * Receive Fifo Overflow (RxFifoOver) [not handled by this driver] + * We have discovered that the overhead of an interrupt context switch + * to attempt to handle this sort of event actually worsens the + * condition, and cuases further dropped packets further increasing the + * time spent in this interrupt handler. + * Receive Frame Rejected (RxRject) [not handled by this driver] + * We could possibly handle this interrupt and gather statistics + * information based on these events that occur. However it is not that + * critical. + * Receive Complete (RxCmplt) [not handled by this driver] + * The TEMAC RxCmplt interrupt status is ignored by software in favor of + * paying attention to the receive complete status in the connected DMA + * or FIFO core. + * Autonegotiaion Complete (AutoNeg) [not handled by this driver] + * Autonegotiation on the TEMAC is a bit complicated, and is handled in + * a way that does not require the use of this interrupt event. + * Hard Temac Core Access Complete (HardAcsCmplt) [not handled by this driver] + * This event really just indicates if there are any events in the TIS + * register. As can be seen below, none of the events from the TIS + * register are handled, so there is no need to handle this event + * either. + * Configuration Write Complete (CfgWst) [not handled by this driver] + * Configuration Read Complete (CfgRst) [not handled by this driver] + * Address Filter Write Complete (AfWst) [not handled by this driver] + * Address Filter Read Complete (AfRst) [not handled by this driver] + * MII Management Write Complete (MiimWst) [not handled by this driver] + * MII Management Read Complete (MiimRst) [not handled by this driver] + * Fabric Read Complete (FabrRst) [not handled by this driver] + * All of the above registers indicate when access (read or write) to + * one or other of the Hard Temac Core registers is complete. Instead of + * relying on an interrupt context switch to be notified that the access + * is complete, this driver instead polls for the status, which, in most + * cases, should be faster. + */ + +static int xenet_open(struct net_device *dev) +{ + struct net_local *lp; + u32 Options; + int irqval = 0; + + /* + * Just to be safe, stop TX queue and the device first. If the device is + * already stopped, an error will be returned. In this case, we don't + * really care. + */ + netif_stop_queue(dev); + lp = (struct net_local *) netdev_priv(dev); + _XLlTemac_Stop(&lp->Emac); + + INIT_LIST_HEAD(&(lp->rcv)); + INIT_LIST_HEAD(&(lp->xmit)); + + /* Set the MAC address each time opened. */ + if (_XLlTemac_SetMacAddress(&lp->Emac, dev->dev_addr) != XST_SUCCESS) { + printk(KERN_ERR "%s: XLlTemac: could not set MAC address.\n", + dev->name); + return -EIO; + } + + /* + * If the device is not configured for polled mode, connect to the + * interrupt controller and enable interrupts. Currently, there + * isn't any code to set polled mode, so this check is probably + * superfluous. + */ + Options = XLlTemac_GetOptions(&lp->Emac); + Options |= XTE_FLOW_CONTROL_OPTION; + /* Enabling jumbo packets shouldn't be a problem if MTU is smaller */ + Options |= XTE_JUMBO_OPTION; + Options |= XTE_TRANSMITTER_ENABLE_OPTION; + Options |= XTE_RECEIVER_ENABLE_OPTION; +#if XTE_AUTOSTRIPPING + Options |= XTE_FCS_STRIP_OPTION; +#endif + + (int) _XLlTemac_SetOptions(&lp->Emac, Options); + (int) _XLlTemac_ClearOptions(&lp->Emac, ~Options); + Options = XLlTemac_GetOptions(&lp->Emac); + printk(KERN_INFO "%s: XLlTemac: Options: 0x%x\n", dev->name, Options); + + /* Just use interrupt driven methods - no polled mode */ + + irqval = request_irq(dev->irq, &xenet_temac_interrupt, 0, dev->name, dev); + if (irqval) { + printk(KERN_ERR + "%s: XLlTemac: could not allocate interrupt %d.\n", + dev->name, dev->irq); + return irqval; + } + if (XLlTemac_IsDma(&lp->Emac)) { + printk(KERN_INFO + "%s: XLlTemac: allocating interrupt %d for dma mode tx.\n", + dev->name, lp->dma_irq_s); + irqval = request_irq(lp->dma_irq_s, + &xenet_dma_tx_interrupt, 0, "xilinx_dma_tx_int", dev); + if (irqval) { + printk(KERN_ERR + "%s: XLlTemac: could not allocate interrupt %d.\n", + dev->name, lp->dma_irq_s); + return irqval; + } + printk(KERN_INFO + "%s: XLlTemac: allocating interrupt %d for dma mode rx.\n", + dev->name, lp->dma_irq_r); + irqval = request_irq(lp->dma_irq_r, + &xenet_dma_rx_interrupt, 0, "xilinx_dma_rx_int", dev); + if (irqval) { + printk(KERN_ERR + "%s: XLlTemac: could not allocate interrupt %d.\n", + dev->name, lp->dma_irq_r); + return irqval; + } + } else { + printk(KERN_INFO + "%s: XLlTemac: allocating interrupt %d for fifo mode.\n", + dev->name, lp->fifo_irq); + /* With the way interrupts are issued on the fifo core, this needs to be + * fast interrupt handler. + */ + irqval = request_irq(lp->fifo_irq, + &xenet_fifo_interrupt, 0, "xilinx_fifo_int", dev); + if (irqval) { + printk(KERN_ERR + "%s: XLlTemac: could not allocate interrupt %d.\n", + dev->name, lp->fifo_irq); + return irqval; + } + } + + /* give the system enough time to establish a link */ + mdelay(2000); + + phy_setup(lp); + set_mac_speed(lp); + + /* Enable interrupts - no polled mode */ + if (XLlTemac_IsFifo(&lp->Emac)) { /* fifo direct interrupt driver mode */ + XLlFifo_IntEnable(&lp->Fifo, XLLF_INT_TC_MASK | + XLLF_INT_RC_MASK | XLLF_INT_RXERROR_MASK | + XLLF_INT_TXERROR_MASK); + } else { /* SG DMA mode */ + XLlDma_mBdRingIntEnable(&lp->Dma.RxBdRing, dma_rx_int_mask); + XLlDma_mBdRingIntEnable(&lp->Dma.TxBdRing, dma_tx_int_mask); + } + /* + * Make sure all temac interrupts are disabled. These + * interrupts are not data flow releated. + */ + XLlTemac_IntDisable(&lp->Emac, XTE_INT_ALL_MASK); + + /* Start TEMAC device */ + _XLlTemac_Start(&lp->Emac); + if (XLlTemac_IsDma(&lp->Emac)) { + u32 threshold_s, timer_s, threshold_r, timer_r; + + XLlDma_BdRingGetCoalesce(&lp->Dma.TxBdRing, &threshold_s, &timer_s); + XLlDma_BdRingGetCoalesce(&lp->Dma.RxBdRing, &threshold_r, &timer_r); + printk(KERN_INFO + "%s: XLlTemac: Send Threshold = %d, Receive Threshold = %d\n", + dev->name, threshold_s, threshold_r); + printk(KERN_INFO + "%s: XLlTemac: Send Wait bound = %d, Receive Wait bound = %d\n", + dev->name, timer_s, timer_r); + if (XLlDma_BdRingStart(&lp->Dma.TxBdRing) == XST_FAILURE) { + printk(KERN_ERR "%s: XLlTemac: could not start dma tx channel\n", dev->name); + return -EIO; + } + if (XLlDma_BdRingStart(&lp->Dma.RxBdRing) == XST_FAILURE) { + printk(KERN_ERR "%s: XLlTemac: could not start dma rx channel\n", dev->name); + return -EIO; + } + } + + /* We're ready to go. */ + netif_start_queue(dev); + + /* Set up the PHY monitoring timer. */ + lp->phy_timer.expires = jiffies + 2 * HZ; + lp->phy_timer.data = (unsigned long) dev; + lp->phy_timer.function = &poll_gmii; + init_timer(&lp->phy_timer); + add_timer(&lp->phy_timer); + return 0; +} + +static int xenet_close(struct net_device *dev) +{ + struct net_local *lp; + unsigned long flags; + + lp = (struct net_local *) netdev_priv(dev); + + /* Shut down the PHY monitoring timer. */ + del_timer_sync(&lp->phy_timer); + + /* Stop Send queue */ + netif_stop_queue(dev); + + /* Now we could stop the device */ + _XLlTemac_Stop(&lp->Emac); + + /* + * Free the interrupt - not polled mode. + */ + free_irq(dev->irq, dev); + if (XLlTemac_IsDma(&lp->Emac)) { + free_irq(lp->dma_irq_s, dev); + free_irq(lp->dma_irq_r, dev); + } else { + free_irq(lp->fifo_irq, dev); + } + + spin_lock_irqsave(&receivedQueueSpin, flags); + list_del(&(lp->rcv)); + spin_unlock_irqrestore(&receivedQueueSpin, flags); + + spin_lock_irqsave(&sentQueueSpin, flags); + list_del(&(lp->xmit)); + spin_unlock_irqrestore(&sentQueueSpin, flags); + + return 0; +} + +static struct net_device_stats *xenet_get_stats(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + return &lp->stats; +} + +static int descriptor_init(struct net_device *dev); +static void free_descriptor_skb(struct net_device *dev); + +static void xenet_set_multicast_list(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + int i; + u32 Options; + unsigned long flags; + + spin_lock_irqsave(&XTE_spinlock, flags); + XLlTemac_Stop(&lp->Emac); + + Options = XLlTemac_GetOptions(&lp->Emac); + Options &= ~XTE_PROMISC_OPTION; + Options &= ~XTE_MULTICAST_OPTION; + for (i = 0; i < 4; i++) + XLlTemac_MulticastClear(&lp->Emac, i); + + if ((dev->flags & IFF_PROMISC) || + (dev->flags & IFF_ALLMULTI) || + (netdev_mc_count(dev) > 4)) { + Options |= XTE_PROMISC_OPTION; + goto done; + } + + if (dev->flags & IFF_MULTICAST) { + struct netdev_hw_addr *ha; + i = 0; + netdev_for_each_mc_addr(ha, dev) { + XLlTemac_MulticastAdd(&lp->Emac, ha->addr, i++); + } + Options |= XTE_MULTICAST_OPTION; + } + +done: + XLlTemac_SetOptions(&lp->Emac, Options); + + XLlTemac_Start(&lp->Emac); + spin_unlock_irqrestore(&XTE_spinlock, flags); +} + +static int xenet_change_mtu(struct net_device *dev, int new_mtu) +{ + int result; + int device_enable = 0; +#ifdef CONFIG_XILINX_GIGE_VLAN + int head_size = XTE_HDR_VLAN_SIZE; +#else + int head_size = XTE_HDR_SIZE; +#endif + struct net_local *lp = (struct net_local *) netdev_priv(dev); + int max_frame = new_mtu + head_size + XTE_TRL_SIZE; + int min_frame = 1 + head_size + XTE_TRL_SIZE; + +#ifdef CONFIG_PPC + if (netif_running(dev)) { + printk("STOP device first!!!\n"); + return -1; + } +#endif + if (max_frame < min_frame) + return -EINVAL; + + if (max_frame > XTE_MAX_JUMBO_FRAME_SIZE) { + printk(KERN_INFO "Wrong MTU packet size. Use %d size\n", + XTE_JUMBO_MTU); + new_mtu = XTE_JUMBO_MTU; + } + + dev->mtu = new_mtu; /* change mtu in net_device structure */ + + /* stop driver */ + if (netif_running(dev)) { + device_enable = 1; + xenet_close(dev); + } + /* free all created descriptors for previous size */ + free_descriptor_skb(dev); + /* setup new frame size */ + lp->frame_size = dev->mtu + XTE_HDR_SIZE + XTE_TRL_SIZE; + XLlDma_Initialize(&lp->Dma, lp->virt_dma_addr); /* initialize dma */ + + result = descriptor_init(dev); /* create new skb with new size */ + if (result) { + printk(KERN_ERR "Descriptor initialization failed.\n"); + return -EINVAL; + } + + if (device_enable) + xenet_open(dev); /* open the device */ + return 0; +} + +static int xenet_FifoSend(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp; + unsigned long flags, fifo_free_bytes; + int total_frags = skb_shinfo(skb)->nr_frags + 1; + unsigned int total_len; + skb_frag_t *frag; + int i; + void *virt_addr; + + total_len = skb_headlen(skb); + + frag = &skb_shinfo(skb)->frags[0]; + for (i = 1; i < total_frags; i++, frag++) { + total_len += frag->size; + } + + /* The following lock is used to protect TxVacancy, Write + * and TxSetLen sequence which could happen from FifoSendHandler + * or other processor in SMP case. + */ + spin_lock_irqsave(&XTE_tx_spinlock, flags); + lp = (struct net_local *) netdev_priv(dev); + + fifo_free_bytes = XLlFifo_TxVacancy(&lp->Fifo) * 4; + if (fifo_free_bytes < total_len) { + netif_stop_queue(dev); /* stop send queue */ + lp->deferred_skb = skb; /* buffer the sk_buffer and will send + it in interrupt context */ + spin_unlock_irqrestore(&XTE_tx_spinlock, flags); + return 0; + } + + /* Write frame data to FIFO */ + XLlFifo_Write(&lp->Fifo, (void *) skb->data, skb_headlen(skb)); + + frag = &skb_shinfo(skb)->frags[0]; + for (i = 1; i < total_frags; i++, frag++) { + virt_addr = skb_frag_address(frag); + XLlFifo_Write(&lp->Fifo, virt_addr, frag->size); + } + + /* Initiate transmit */ + XLlFifo_TxSetLen(&lp->Fifo, total_len); + lp->stats.tx_bytes += total_len; + spin_unlock_irqrestore(&XTE_tx_spinlock, flags); + + dev_kfree_skb(skb); /* free skb */ + dev->trans_start = jiffies; + return 0; +} + +/* Callback function for completed frames sent in FIFO interrupt driven mode */ +static void FifoSendHandler(struct net_device *dev) +{ + struct net_local *lp; + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&XTE_tx_spinlock, flags); + lp = (struct net_local *) netdev_priv(dev); + lp->stats.tx_packets++; + + /*Send out the deferred skb and wake up send queue if a deferred skb exists */ + if (lp->deferred_skb) { + int total_frags; + unsigned int total_len; + unsigned long fifo_free_bytes; + skb_frag_t *frag; + int i; + void *virt_addr; + + skb = lp->deferred_skb; + total_frags = skb_shinfo(skb)->nr_frags + 1; + total_len = skb_headlen(skb); + + frag = &skb_shinfo(skb)->frags[0]; + for (i = 1; i < total_frags; i++, frag++) { + total_len += frag->size; + } + + fifo_free_bytes = XLlFifo_TxVacancy(&lp->Fifo) * 4; + if (fifo_free_bytes < total_len) { + /* If still no room for the deferred packet, return */ + spin_unlock_irqrestore(&XTE_tx_spinlock, flags); + return; + } + + /* Write frame data to FIFO */ + XLlFifo_Write(&lp->Fifo, (void *) skb->data, skb_headlen(skb)); + + frag = &skb_shinfo(skb)->frags[0]; + for (i = 1; i < total_frags; i++, frag++) { + virt_addr = skb_frag_address(frag); + XLlFifo_Write(&lp->Fifo, virt_addr, frag->size); + } + + /* Initiate transmit */ + XLlFifo_TxSetLen(&lp->Fifo, total_len); + + dev_kfree_skb(skb); /* free skb */ + lp->deferred_skb = NULL; + lp->stats.tx_packets++; + lp->stats.tx_bytes += total_len; + dev->trans_start = jiffies; + netif_wake_queue(dev); /* wake up send queue */ + } + spin_unlock_irqrestore(&XTE_tx_spinlock, flags); +} + +#if 0 +/* + * These are used for debugging purposes, left here in case they are useful + * for further debugging + */ +static unsigned int _xenet_tx_csum(struct sk_buff *skb) +{ + unsigned int csum = 0; + long csstart = skb_transport_header(skb) - skb->data; + + if (csstart != skb->len) { + csum = skb_checksum(skb, csstart, skb->len - csstart, 0); + } + + return csum; +} + +static inline unsigned int _xenet_rx_csum(struct sk_buff *skb) +{ + return skb_checksum(skb, 0, skb->len, 0); +} +#endif + +/* + * xenet_DmaSend_internal is an internal use, send routine. + * Any locks that need to be acquired, should be acquired + * prior to calling this routine. + */ +static int xenet_DmaSend_internal(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp; + XLlDma_Bd *bd_ptr; + int result; + int total_frags; + int i; + void *virt_addr; + size_t len; + dma_addr_t phy_addr; + XLlDma_Bd *first_bd_ptr; + XLlDma_Bd *last_bd_ptr; + skb_frag_t *frag; + + lp = (struct net_local *) netdev_priv(dev); + + /* get skb_shinfo(skb)->nr_frags + 1 buffer descriptors */ + total_frags = skb_shinfo(skb)->nr_frags + 1; + + /* stats */ + if (lp->max_frags_in_a_packet < total_frags) { + lp->max_frags_in_a_packet = total_frags; + } + + if (total_frags < XTE_SEND_BD_CNT) { + result = XLlDma_BdRingAlloc(&lp->Dma.TxBdRing, total_frags, + &bd_ptr); + + if (result != XST_SUCCESS) { + netif_stop_queue(dev); /* stop send queue */ + lp->deferred_skb = skb; /* buffer the sk_buffer and will send + it in interrupt context */ + return result; + } + } else { + dev_kfree_skb(skb); + lp->stats.tx_dropped++; + printk(KERN_ERR + "%s: XLlTemac: could not send TX socket buffers (too many fragments).\n", + dev->name); + return XST_FAILURE; + } + + len = skb_headlen(skb); + + /* get the physical address of the header */ + phy_addr = (u32) dma_map_single(dev->dev.parent, skb->data, len, + DMA_TO_DEVICE); + + /* get the header fragment, it's in the skb differently */ + XLlDma_mBdSetBufAddr(bd_ptr, phy_addr); + XLlDma_mBdSetLength(bd_ptr, len); + XLlDma_mBdSetId(bd_ptr, skb); + + /* + * if tx checksum offloading is enabled, when the ethernet stack + * wants us to perform the checksum in hardware, + * skb->ip_summed is CHECKSUM_PARTIAL. Otherwise skb->ip_summed is + * CHECKSUM_NONE, meaning the checksum is already done, or + * CHECKSUM_UNNECESSARY, meaning checksumming is turned off (e.g. + * loopback interface) + * + * skb->csum is an overloaded value. On send, skb->csum is the offset + * into the buffer (skb_transport_header(skb)) to place the csum value. + * On receive this feild gets set to the actual csum value, before it's + * passed up the stack. + * + * When we get here, the ethernet stack above will have already + * computed the pseudoheader csum value and have placed it in the + * TCP/UDP header. + * + * The IP header csum has also already been computed and inserted. + * + * Since the IP header with it's own csum should compute to a null + * csum, it should be ok to include it in the hw csum. If it is decided + * to change this scheme, skb should be examined before dma_map_single() + * is called, which flushes the page from the cpu's cache. + * + * skb->data points to the beginning of the whole packet + * skb_transport_header(skb) points to the beginning of the ip header + * + */ + if (skb->ip_summed == CHECKSUM_PARTIAL) { + + unsigned int csum_start_off = skb_transport_offset(skb); + unsigned int csum_index_off = csum_start_off + skb->csum_offset; + +#if 0 + { + unsigned int csum = _xenet_tx_csum(skb); + + *((unsigned short *) (raw + skb->csum)) = + csum_fold(csum); + BdCsumDisable(bd_ptr); + } +#else + BdCsumEnable(bd_ptr); + BdCsumSetup(bd_ptr, csum_start_off, csum_index_off); + +#endif + lp->tx_hw_csums++; + } + else { + /* + * This routine will do no harm even if hardware checksum capability is + * off. + */ + BdCsumDisable(bd_ptr); + } + + first_bd_ptr = bd_ptr; + last_bd_ptr = bd_ptr; + + frag = &skb_shinfo(skb)->frags[0]; + + for (i = 1; i < total_frags; i++, frag++) { + bd_ptr = XLlDma_mBdRingNext(&lp->Dma.TxBdRing, bd_ptr); + last_bd_ptr = bd_ptr; + + virt_addr = skb_frag_address(frag); + phy_addr = + (u32) dma_map_single(dev->dev.parent, virt_addr, + frag->size, DMA_TO_DEVICE); + + XLlDma_mBdSetBufAddr(bd_ptr, phy_addr); + XLlDma_mBdSetLength(bd_ptr, frag->size); + XLlDma_mBdSetId(bd_ptr, NULL); + BdCsumDisable(bd_ptr); + XLlDma_mBdSetStsCtrl(bd_ptr, 0); + } + + if (first_bd_ptr == last_bd_ptr) { + XLlDma_mBdSetStsCtrl(last_bd_ptr, + XLLDMA_BD_STSCTRL_SOP_MASK | + XLLDMA_BD_STSCTRL_EOP_MASK); + } else { + XLlDma_mBdSetStsCtrl(first_bd_ptr, XLLDMA_BD_STSCTRL_SOP_MASK); + XLlDma_mBdSetStsCtrl(last_bd_ptr, XLLDMA_BD_STSCTRL_EOP_MASK); + } + + + /* Enqueue to HW */ + result = XLlDma_BdRingToHw(&lp->Dma.TxBdRing, total_frags, + first_bd_ptr); + if (result != XST_SUCCESS) { + netif_stop_queue(dev); /* stop send queue */ + dev_kfree_skb(skb); + XLlDma_mBdSetId(first_bd_ptr, NULL); + lp->stats.tx_dropped++; + printk(KERN_ERR + "%s: XLlTemac: could not send commit TX buffer descriptor (%d).\n", + dev->name, result); + reset(dev, __LINE__); + + return XST_FAILURE; + } + + dev->trans_start = jiffies; + + return XST_SUCCESS; +} + +/* The send function for frames sent in DMA mode */ +static int xenet_DmaSend(struct sk_buff *skb, struct net_device *dev) +{ + /* The following spin_lock protects + * SgAlloc, SgCommit sequence, which also exists in DmaSendHandlerBH Bottom + * Half, or triggered by other processor in SMP case. + */ + spin_lock_bh(&XTE_tx_spinlock); + + xenet_DmaSend_internal(skb, dev); + + spin_unlock_bh(&XTE_tx_spinlock); + + return 0; +} + + +static void DmaSendHandlerBH(unsigned long p) +{ + struct net_device *dev; + struct net_local *lp; + XLlDma_Bd *BdPtr, *BdCurPtr; + unsigned long len; + unsigned long flags; + struct sk_buff *skb; + dma_addr_t skb_dma_addr; + int result = XST_SUCCESS; + unsigned int bd_processed, bd_processed_save; + + while (1) { + spin_lock_irqsave(&sentQueueSpin, flags); + if (list_empty(&sentQueue)) { + spin_unlock_irqrestore(&sentQueueSpin, flags); + break; + } + + lp = list_entry(sentQueue.next, struct net_local, xmit); + + list_del_init(&(lp->xmit)); + spin_unlock_irqrestore(&sentQueueSpin, flags); + + spin_lock_irqsave(&XTE_tx_spinlock, flags); + dev = lp->ndev; + bd_processed_save = 0; + while ((bd_processed = + XLlDma_BdRingFromHw(&lp->Dma.TxBdRing, XTE_SEND_BD_CNT, + &BdPtr)) > 0) { + + bd_processed_save = bd_processed; + BdCurPtr = BdPtr; + do { + len = XLlDma_mBdGetLength(BdCurPtr); + skb_dma_addr = (dma_addr_t) XLlDma_mBdGetBufAddr(BdCurPtr); + dma_unmap_single(dev->dev.parent, skb_dma_addr, + len, DMA_TO_DEVICE); + + /* get ptr to skb */ + skb = (struct sk_buff *) + XLlDma_mBdGetId(BdCurPtr); + if (skb) + dev_kfree_skb(skb); + + /* reset BD id */ + XLlDma_mBdSetId(BdCurPtr, NULL); + + lp->stats.tx_bytes += len; + if (XLlDma_mBdGetStsCtrl(BdCurPtr) & XLLDMA_BD_STSCTRL_EOP_MASK) { + lp->stats.tx_packets++; + } + + BdCurPtr = XLlDma_mBdRingNext(&lp->Dma.TxBdRing, BdCurPtr); + bd_processed--; + } while (bd_processed > 0); + + result = XLlDma_BdRingFree(&lp->Dma.TxBdRing, + bd_processed_save, BdPtr); + if (result != XST_SUCCESS) { + printk(KERN_ERR + "%s: XLlDma: BdRingFree() error %d.\n", + dev->name, result); + reset(dev, __LINE__); + spin_unlock_irqrestore(&XTE_tx_spinlock, flags); + return; + } + } + XLlDma_mBdRingIntEnable(&lp->Dma.TxBdRing, dma_tx_int_mask); + + /* Send out the deferred skb if it exists */ + if ((lp->deferred_skb) && bd_processed_save) { + skb = lp->deferred_skb; + lp->deferred_skb = NULL; + + result = xenet_DmaSend_internal(skb, dev); + } + + if (result == XST_SUCCESS) { + netif_wake_queue(dev); /* wake up send queue */ + } + spin_unlock_irqrestore(&XTE_tx_spinlock, flags); + } +} + +static void xenet_tx_timeout(struct net_device *dev) +{ + struct net_local *lp; + unsigned long flags; + + /* + * Make sure that no interrupts come in that could cause reentrancy + * problems in reset. + */ + spin_lock_irqsave(&XTE_tx_spinlock, flags); + + lp = (struct net_local *) netdev_priv(dev); + printk(KERN_ERR + "%s: XLlTemac: exceeded transmit timeout of %lu ms. Resetting emac.\n", + dev->name, TX_TIMEOUT * 1000UL / HZ); + lp->stats.tx_errors++; + + reset(dev, __LINE__); + + spin_unlock_irqrestore(&XTE_tx_spinlock, flags); +} + +/* The callback function for frames received when in FIFO mode. */ +static void FifoRecvHandler(unsigned long p) +{ + struct net_local *lp; + struct sk_buff *skb; + u32 len; + + struct net_device *dev; + unsigned long flags; + spin_lock_irqsave(&receivedQueueSpin, flags); + if (list_empty(&receivedQueue)) { + spin_unlock_irqrestore(&receivedQueueSpin, flags); + return; + } + lp = list_entry(receivedQueue.next, struct net_local, rcv); + + list_del_init(&(lp->rcv)); + spin_unlock_irqrestore(&receivedQueueSpin, flags); + dev = lp->ndev; + + while (XLlFifo_RxOccupancy(&lp->Fifo) != 0) { + + len = XLlFifo_RxGetLen(&lp->Fifo); + + /* + * TODO: Hm this is odd, if we can't allocate the skb, we throw away the next packet. Why? + */ + if (!(skb = /*dev_ */ alloc_skb(len + ALIGNMENT_RECV, GFP_ATOMIC))) { +#define XTE_RX_SINK_BUFFER_SIZE 1024 + static u32 rx_buffer_sink[XTE_RX_SINK_BUFFER_SIZE / sizeof(u32)]; + + /* Couldn't get memory. */ + lp->stats.rx_dropped++; + printk(KERN_ERR + "%s: XLlTemac: could not allocate receive buffer.\n", + dev->name); + + /* consume data in Xilinx TEMAC RX data fifo so it is sync with RX length fifo */ + for (; len > XTE_RX_SINK_BUFFER_SIZE; + len -= XTE_RX_SINK_BUFFER_SIZE) { + XLlFifo_Read(&lp->Fifo, rx_buffer_sink, + XTE_RX_SINK_BUFFER_SIZE); + } + XLlFifo_Read(&lp->Fifo, rx_buffer_sink, len); + break; + } + + /* Read the packet data */ + XLlFifo_Read(&lp->Fifo, skb->data, len); + lp->stats.rx_packets++; + lp->stats.rx_bytes += len; + + skb_put(skb, len); /* Tell the skb how much data we got. */ + skb->dev = dev; /* Fill out required meta-data. */ + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); /* Send the packet upstream. */ + } + XLlFifo_IntEnable(&lp->Fifo, XLLF_INT_TC_MASK | XLLF_INT_RC_MASK | + XLLF_INT_RXERROR_MASK | XLLF_INT_TXERROR_MASK); + +} + + +/* + * _xenet_DmaSetupRecvBuffers allocates as many socket buffers (sk_buff's) as it + * can up to the number of free RX buffer descriptors. Then it sets up the RX + * buffer descriptors to DMA into the socket_buffers. + * + * The net_device, dev, indcates on which device to operate for buffer + * descriptor allocation. + */ +static void _xenet_DmaSetupRecvBuffers(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + int free_bd_count = XLlDma_mBdRingGetFreeCnt(&lp->Dma.RxBdRing); + int num_sk_buffs; + struct sk_buff_head sk_buff_list; + struct sk_buff *new_skb; + u32 new_skb_baddr; + XLlDma_Bd *BdPtr, *BdCurPtr; + u32 align; + int result; + +#if 0 + int align_max = ALIGNMENT_RECV; +#else + int align_max = 0; +#endif + + + skb_queue_head_init(&sk_buff_list); + for (num_sk_buffs = 0; num_sk_buffs < free_bd_count; num_sk_buffs++) { + new_skb = alloc_skb(lp->frame_size + align_max, GFP_ATOMIC); + if (new_skb == NULL) { + break; + } + /* + * I think the XTE_spinlock, and Recv DMA int disabled will protect this + * list as well, so we can use the __ version just fine + */ + __skb_queue_tail(&sk_buff_list, new_skb); + } + if (!num_sk_buffs) { + printk(KERN_ERR "%s: XLlTemac: alloc_skb unsuccessful\n", + dev->name); + return; + } + + /* now we got a bunch o' sk_buffs */ + result = XLlDma_BdRingAlloc(&lp->Dma.RxBdRing, num_sk_buffs, &BdPtr); + if (result != XST_SUCCESS) { + /* we really shouldn't get this */ + skb_queue_purge(&sk_buff_list); + printk(KERN_ERR "%s: XLlDma: BdRingAlloc unsuccessful (%d)\n", + dev->name, result); + reset(dev, __LINE__); + return; + } + + BdCurPtr = BdPtr; + + new_skb = skb_dequeue(&sk_buff_list); + while (new_skb) { + /* make sure we're long-word aligned */ + align = BUFFER_ALIGNRECV(new_skb->data); + if (align) { + skb_reserve(new_skb, align); + } + + /* Get dma handle of skb->data */ + new_skb_baddr = (u32) dma_map_single(dev->dev.parent, + new_skb->data, lp->frame_size, + DMA_FROM_DEVICE); + XLlDma_mBdSetBufAddr(BdCurPtr, new_skb_baddr); + XLlDma_mBdSetLength(BdCurPtr, lp->frame_size); + XLlDma_mBdSetId(BdCurPtr, new_skb); + XLlDma_mBdSetStsCtrl(BdCurPtr, + XLLDMA_BD_STSCTRL_SOP_MASK | + XLLDMA_BD_STSCTRL_EOP_MASK); + + BdCurPtr = XLlDma_mBdRingNext(&lp->Dma.RxBdRing, BdCurPtr); + + new_skb = skb_dequeue(&sk_buff_list); + } + + /* enqueue RxBD with the attached skb buffers such that it is + * ready for frame reception */ + result = XLlDma_BdRingToHw(&lp->Dma.RxBdRing, num_sk_buffs, BdPtr); + if (result != XST_SUCCESS) { + printk(KERN_ERR + "%s: XLlDma: (DmaSetupRecvBuffers) BdRingToHw unsuccessful (%d)\n", + dev->name, result); + skb_queue_purge(&sk_buff_list); + BdCurPtr = BdPtr; + while (num_sk_buffs > 0) { + XLlDma_mBdSetId(BdCurPtr, NULL); + BdCurPtr = XLlDma_mBdRingNext(&lp->Dma.RxBdRing, + BdCurPtr); + num_sk_buffs--; + } + reset(dev, __LINE__); + return; + } +} + +static void DmaRecvHandlerBH(unsigned long p) +{ + struct net_device *dev; + struct net_local *lp; + struct sk_buff *skb; + u32 len, skb_baddr; + int result; + unsigned long flags; + XLlDma_Bd *BdPtr, *BdCurPtr; + unsigned int bd_processed, bd_processed_saved; + + while (1) { + spin_lock_irqsave(&receivedQueueSpin, flags); + if (list_empty(&receivedQueue)) { + spin_unlock_irqrestore(&receivedQueueSpin, flags); + break; + } + lp = list_entry(receivedQueue.next, struct net_local, rcv); + + list_del_init(&(lp->rcv)); + spin_unlock_irqrestore(&receivedQueueSpin, flags); + dev = lp->ndev; + + spin_lock_irqsave(&XTE_rx_spinlock, flags); + if ((bd_processed = + XLlDma_BdRingFromHw(&lp->Dma.RxBdRing, XTE_RECV_BD_CNT, &BdPtr)) > 0) { + + bd_processed_saved = bd_processed; + BdCurPtr = BdPtr; + do { + /* + * Regular length field not updated on rx, + * USR4 updated instead. + */ + len = BdGetRxLen(BdCurPtr); + + /* get ptr to skb */ + skb = (struct sk_buff *) + XLlDma_mBdGetId(BdCurPtr); + + /* get and free up dma handle used by skb->data */ + skb_baddr = (dma_addr_t) XLlDma_mBdGetBufAddr(BdCurPtr); + dma_unmap_single(dev->dev.parent, skb_baddr, + lp->frame_size, + DMA_FROM_DEVICE); + + /* reset ID */ + XLlDma_mBdSetId(BdCurPtr, NULL); + + /* setup received skb and send it upstream */ + skb_put(skb, len); /* Tell the skb how much data we got. */ + skb->dev = dev; + + /* this routine adjusts skb->data to skip the header */ + skb->protocol = eth_type_trans(skb, dev); + + /* default the ip_summed value */ + skb->ip_summed = CHECKSUM_NONE; + + /* if we're doing rx csum offload, set it up */ + if (((lp->local_features & LOCAL_FEATURE_RX_CSUM) != 0) && + (skb->protocol == __constant_htons(ETH_P_IP)) && + (skb->len > 64)) { + unsigned int csum; + + /* + * This hardware only supports proper checksum calculations + * on TCP/UDP packets. + * + * skb->csum is an overloaded value. On send, skb->csum is + * the offset into the buffer (skb_transport_header(skb)) + * to place the csum value. On receive this feild gets set + * to the actual csum value, before it's passed up the stack. + * + * If we set skb->ip_summed to CHECKSUM_COMPLETE, the ethernet + * stack above will compute the pseudoheader csum value and + * add it to the partial checksum already computed (to be + * placed in skb->csum) and verify it. + * + * Setting skb->ip_summed to CHECKSUM_NONE means that the + * cheksum didn't verify and the stack will (re)check it. + * + * Setting skb->ip_summed to CHECKSUM_UNNECESSARY means + * that the cheksum was verified/assumed to be good and the + * stack does not need to (re)check it. + * + * The ethernet stack above will (re)compute the checksum + * under the following conditions: + * 1) skb->ip_summed was set to CHECKSUM_NONE + * 2) skb->len does not match the length of the ethernet + * packet determined by parsing the packet. In this case + * the ethernet stack will assume any prior checksum + * value was miscomputed and throw it away. + * 3) skb->ip_summed was set to CHECKSUM_COMPLETE, skb->csum was + * set, but the result does not check out ok by the + * ethernet stack. + * + * If the TEMAC hardware stripping feature is off, each + * packet will contain an FCS feild which will have been + * computed by the hardware checksum operation. This 4 byte + * FCS value needs to be subtracted back out of the checksum + * value computed by hardware as it's not included in a + * normal ethernet packet checksum. + * + * The minimum transfer packet size over the wire is 64 + * bytes. If the packet is sent as exactly 64 bytes, then + * it probably contains some random padding bytes. It's + * somewhat difficult to determine the actual length of the + * real packet data, so we just let the stack recheck the + * checksum for us. + * + * After the call to eth_type_trans(), the following holds + * true: + * skb->data points to the beginning of the ip header + */ + csum = BdCsumGet(BdCurPtr); + +#if ! XTE_AUTOSTRIPPING + if (!lp->stripping) { + /* take off the FCS */ + u16 *data; + + /* FCS is 4 bytes */ + skb_put(skb, -4); + + data = (u16 *) (&skb-> + data[skb->len]); + + /* subtract out the FCS from the csum value */ + csum = csum_sub(csum, *data /* & 0xffff */); + data++; + csum = csum_sub(csum, *data /* & 0xffff */); + } +#endif + skb->csum = csum; + skb->ip_summed = CHECKSUM_COMPLETE; + + lp->rx_hw_csums++; + } + + lp->stats.rx_packets++; + lp->stats.rx_bytes += len; + netif_rx(skb); /* Send the packet upstream. */ + + BdCurPtr = + XLlDma_mBdRingNext(&lp->Dma.RxBdRing, + BdCurPtr); + bd_processed--; + } while (bd_processed > 0); + + /* give the descriptor back to the driver */ + result = XLlDma_BdRingFree(&lp->Dma.RxBdRing, + bd_processed_saved, BdPtr); + if (result != XST_SUCCESS) { + printk(KERN_ERR + "%s: XLlDma: BdRingFree unsuccessful (%d)\n", + dev->name, result); + reset(dev, __LINE__); + spin_unlock_irqrestore(&XTE_rx_spinlock, flags); + return; + } + + _xenet_DmaSetupRecvBuffers(dev); + } + XLlDma_mBdRingIntEnable(&lp->Dma.RxBdRing, dma_rx_int_mask); + spin_unlock_irqrestore(&XTE_rx_spinlock, flags); + } +} + +static int descriptor_init(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + int recvsize, sendsize; + int dftsize; + u32 *recvpoolptr, *sendpoolptr; + void *recvpoolphy, *sendpoolphy; + int result; + +/* + * Buffer Descriptr + * word byte description + * 0 0h next ptr + * 1 4h buffer addr + * 2 8h buffer len + * 3 ch sts/ctrl | app data (0) [tx csum enable (bit 31 LSB)] + * 4 10h app data (1) [tx csum begin (bits 0-15 MSB) | csum insert (bits 16-31 LSB)] + * 5 14h app data (2) [tx csum seed (bits 16-31 LSB)] + * 6 18h app data (3) [rx raw csum (bits 16-31 LSB)] + * 7 1ch app data (4) [rx recv length (bits 18-31 LSB)] + */ +#if 0 + int XferType = XDMAV3_DMACR_TYPE_BFBURST_MASK; + int XferWidth = XDMAV3_DMACR_DSIZE_64_MASK; +#endif + + /* calc size of descriptor space pool; alloc from non-cached memory */ + dftsize = XLlDma_mBdRingMemCalc(ALIGNMENT_BD, + XTE_RECV_BD_CNT + XTE_SEND_BD_CNT); + printk(KERN_INFO "XLlTemac: buffer descriptor size: %d (0x%0x)\n", + dftsize, dftsize); + +#if BD_IN_BRAM == 0 + /* + * Allow buffer descriptors to be cached. + * Old method w/cache on buffer descriptors disabled: + * lp->desc_space = dma_alloc_coherent(NULL, dftsize, + * &lp->desc_space_handle, GFP_KERNEL); + * (note if going back to dma_alloc_coherent() the CACHE macros in + * xenv_linux.h need to be disabled. + */ + + printk(KERN_INFO "XLlTemac: Allocating DMA descriptors with kmalloc"); + lp->desc_space = kmalloc(dftsize, GFP_KERNEL); + lp->desc_space_handle = (dma_addr_t) page_to_phys(virt_to_page(lp->desc_space)); +#else + printk(KERN_INFO "XLlTemac: Allocating DMA descriptors in Block Ram"); + lp->desc_space_handle = BRAM_BASEADDR; + lp->desc_space = ioremap(lp->desc_space_handle, dftsize); +#endif + if (lp->desc_space == NULL) + return -1; + + lp->desc_space_size = dftsize; + + printk(KERN_INFO + "XLlTemac: (buffer_descriptor_init) phy: 0x%x, virt: 0x%x, size: 0x%x\n", + lp->desc_space_handle, (unsigned int) lp->desc_space, + lp->desc_space_size); + + /* calc size of send and recv descriptor space */ + recvsize = XLlDma_mBdRingMemCalc(ALIGNMENT_BD, XTE_RECV_BD_CNT); + sendsize = XLlDma_mBdRingMemCalc(ALIGNMENT_BD, XTE_SEND_BD_CNT); + + recvpoolptr = lp->desc_space; + sendpoolptr = (void *) ((u32) lp->desc_space + recvsize); + + recvpoolphy = (void *) lp->desc_space_handle; + sendpoolphy = (void *) ((u32) lp->desc_space_handle + recvsize); + + result = XLlDma_BdRingCreate(&lp->Dma.RxBdRing, (u32) recvpoolphy, + (u32) recvpoolptr, ALIGNMENT_BD, + XTE_RECV_BD_CNT); + if (result != XST_SUCCESS) { + printk(KERN_ERR "XLlTemac: DMA Ring Create (RECV). Error: %d\n", result); + return -EIO; + } + + result = XLlDma_BdRingCreate(&lp->Dma.TxBdRing, (u32) sendpoolphy, + (u32) sendpoolptr, ALIGNMENT_BD, + XTE_SEND_BD_CNT); + if (result != XST_SUCCESS) { + printk(KERN_ERR "XLlTemac: DMA Ring Create (SEND). Error: %d\n", result); + return -EIO; + } + + _xenet_DmaSetupRecvBuffers(dev); + return 0; +} + +static void free_descriptor_skb(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + XLlDma_Bd *BdPtr; + struct sk_buff *skb; + dma_addr_t skb_dma_addr; + u32 len, i; + + /* Unmap and free skb's allocated and mapped in descriptor_init() */ + + /* Get the virtual address of the 1st BD in the DMA RX BD ring */ + BdPtr = (XLlDma_Bd *) lp->Dma.RxBdRing.FirstBdAddr; + + for (i = 0; i < XTE_RECV_BD_CNT; i++) { + skb = (struct sk_buff *) XLlDma_mBdGetId(BdPtr); + if (skb) { + skb_dma_addr = (dma_addr_t) XLlDma_mBdGetBufAddr(BdPtr); + dma_unmap_single(dev->dev.parent, skb_dma_addr, + lp->frame_size, DMA_FROM_DEVICE); + dev_kfree_skb(skb); + } + /* find the next BD in the DMA RX BD ring */ + BdPtr = XLlDma_mBdRingNext(&lp->Dma.RxBdRing, BdPtr); + } + + /* Unmap and free TX skb's that have not had a chance to be freed + * in DmaSendHandlerBH(). This could happen when TX Threshold is larger + * than 1 and TX waitbound is 0 + */ + + /* Get the virtual address of the 1st BD in the DMA TX BD ring */ + BdPtr = (XLlDma_Bd *) lp->Dma.TxBdRing.FirstBdAddr; + + for (i = 0; i < XTE_SEND_BD_CNT; i++) { + skb = (struct sk_buff *) XLlDma_mBdGetId(BdPtr); + if (skb) { + skb_dma_addr = (dma_addr_t) XLlDma_mBdGetBufAddr(BdPtr); + len = XLlDma_mBdGetLength(BdPtr); + dma_unmap_single(dev->dev.parent, skb_dma_addr, len, + DMA_TO_DEVICE); + dev_kfree_skb(skb); + } + /* find the next BD in the DMA TX BD ring */ + BdPtr = XLlDma_mBdRingNext(&lp->Dma.TxBdRing, BdPtr); + } + +#if BD_IN_BRAM == 0 + kfree(lp->desc_space); +/* this is old approach which was removed */ +/* dma_free_coherent(NULL, + lp->desc_space_size, + lp->desc_space, lp->desc_space_handle); */ +#else + iounmap(lp->desc_space); +#endif +} + +static int +xenet_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + u32 mac_options; + u32 threshold, timer; + u16 gmii_cmd, gmii_status, gmii_advControl; + + memset(ecmd, 0, sizeof(struct ethtool_cmd)); + + mac_options = XLlTemac_GetOptions(&(lp->Emac)); + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMCR, &gmii_cmd); + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, &gmii_status); + + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_ADVERTISE, &gmii_advControl); + + ecmd->duplex = DUPLEX_FULL; + + ecmd->supported |= SUPPORTED_MII; + + ecmd->port = PORT_MII; + + ecmd->speed = lp->cur_speed; + + if (gmii_status & BMSR_ANEGCAPABLE) { + ecmd->supported |= SUPPORTED_Autoneg; + } + if (gmii_status & BMSR_ANEGCOMPLETE) { + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->advertising |= ADVERTISED_Autoneg; + } + else { + ecmd->autoneg = AUTONEG_DISABLE; + } + ecmd->phy_address = lp->Emac.Config.BaseAddress; + ecmd->transceiver = XCVR_INTERNAL; + if (XLlTemac_IsDma(&lp->Emac)) { + /* get TX threshold */ + + XLlDma_BdRingGetCoalesce(&lp->Dma.TxBdRing, &threshold, &timer); + ecmd->maxtxpkt = threshold; + + /* get RX threshold */ + XLlDma_BdRingGetCoalesce(&lp->Dma.RxBdRing, &threshold, &timer); + ecmd->maxrxpkt = threshold; + } + + ecmd->supported |= SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg; + + return 0; +} + +static int +xenet_ethtool_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + if ((ecmd->duplex != DUPLEX_FULL) || + (ecmd->transceiver != XCVR_INTERNAL) || + (ecmd->phy_address && + (ecmd->phy_address != lp->Emac.Config.BaseAddress))) { + return -EOPNOTSUPP; + } + + if ((ecmd->speed != 1000) && (ecmd->speed != 100) && + (ecmd->speed != 10)) { + printk(KERN_ERR + "%s: XLlTemac: xenet_ethtool_set_settings speed not supported: %d\n", + dev->name, ecmd->speed); + return -EOPNOTSUPP; + } + + if (ecmd->speed != lp->cur_speed) { + renegotiate_speed(dev, ecmd->speed, FULL_DUPLEX); + _XLlTemac_SetOperatingSpeed(&lp->Emac, ecmd->speed); + lp->cur_speed = ecmd->speed; + } + return 0; +} + +static int +xenet_ethtool_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + u32 threshold, waitbound; + + memset(ec, 0, sizeof(struct ethtool_coalesce)); + + if (!(XLlTemac_IsDma(&lp->Emac))) { + return -EIO; + } + + XLlDma_BdRingGetCoalesce(&lp->Dma.RxBdRing, &threshold, &waitbound); + ec->rx_max_coalesced_frames = threshold; + ec->rx_coalesce_usecs = waitbound; + + XLlDma_BdRingGetCoalesce(&lp->Dma.TxBdRing, &threshold, &waitbound); + ec->tx_max_coalesced_frames = threshold; + ec->tx_coalesce_usecs = waitbound; + + return 0; +} + +#if 0 +static void disp_bd_ring(XLlDma_BdRing *bd_ring) +{ + int num_bds = bd_ring->AllCnt; + u32 *cur_bd_ptr = (u32 *) bd_ring->FirstBdAddr; + int idx; + + printk("ChanBase: %p\n", (void *) bd_ring->ChanBase); + printk("FirstBdPhysAddr: %p\n", (void *) bd_ring->FirstBdPhysAddr); + printk("FirstBdAddr: %p\n", (void *) bd_ring->FirstBdAddr); + printk("LastBdAddr: %p\n", (void *) bd_ring->LastBdAddr); + printk("Length: %d (0x%0x)\n", bd_ring->Length, bd_ring->Length); + printk("RunState: %d (0x%0x)\n", bd_ring->RunState, bd_ring->RunState); + printk("Separation: %d (0x%0x)\n", bd_ring->Separation, + bd_ring->Separation); + printk("BD Count: %d\n", bd_ring->AllCnt); + + printk("\n"); + + printk("FreeHead: %p\n", (void *) bd_ring->FreeHead); + printk("PreHead: %p\n", (void *) bd_ring->PreHead); + printk("HwHead: %p\n", (void *) bd_ring->HwHead); + printk("HwTail: %p\n", (void *) bd_ring->HwTail); + printk("PostHead: %p\n", (void *) bd_ring->PostHead); + printk("BdaRestart: %p\n", (void *) bd_ring->BdaRestart); + + printk("Ring Contents:\n"); +/* + * Buffer Descriptr + * word byte description + * 0 0h next ptr + * 1 4h buffer addr + * 2 8h buffer len + * 3 ch sts/ctrl | app data (0) [tx csum enable (bit 31 LSB)] + * 4 10h app data (1) [tx csum begin (bits 0-15 MSB) | csum insert (bits 16-31 LSB)] + * 5 14h app data (2) [tx csum seed (bits 16-31 LSB)] + * 6 18h app data (3) [rx raw csum (bits 16-31 LSB)] + * 7 1ch app data (4) [rx recv length (bits 18-31 LSB)] + * 8 20h sw app data (0) [id] + */ + printk("Idx NextBD BuffAddr Length CTL/CSE CSUM B/I CSUMSeed Raw CSUM RecvLen ID\n"); + printk("--- -------- -------- -------- -------- -------- -------- -------- -------- --------\n"); + + for (idx = 0; idx < num_bds; idx++) { + printk("%3d %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", + idx, + cur_bd_ptr[XLLDMA_BD_NDESC_OFFSET / sizeof(*cur_bd_ptr)], + cur_bd_ptr[XLLDMA_BD_BUFA_OFFSET / sizeof(*cur_bd_ptr)], + cur_bd_ptr[XLLDMA_BD_BUFL_OFFSET / sizeof(*cur_bd_ptr)], + cur_bd_ptr[XLLDMA_BD_STSCTRL_USR0_OFFSET / + sizeof(*cur_bd_ptr)], + cur_bd_ptr[XLLDMA_BD_USR1_OFFSET / sizeof(*cur_bd_ptr)], + cur_bd_ptr[XLLDMA_BD_USR2_OFFSET / sizeof(*cur_bd_ptr)], + cur_bd_ptr[XLLDMA_BD_USR3_OFFSET / sizeof(*cur_bd_ptr)], + cur_bd_ptr[XLLDMA_BD_USR4_OFFSET / sizeof(*cur_bd_ptr)], + cur_bd_ptr[XLLDMA_BD_ID_OFFSET / sizeof(*cur_bd_ptr)]); + + cur_bd_ptr += bd_ring->Separation / sizeof(int); + } + printk("--------------------------------------- Done ---------------------------------------\n"); +} +#endif + +static int +xenet_ethtool_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) +{ + int ret; + struct net_local *lp; + + lp = (struct net_local *) netdev_priv(dev); + + if (!(XLlTemac_IsDma(&lp->Emac))) { + return -EIO; + } + + if (ec->rx_coalesce_usecs == 0) { + ec->rx_coalesce_usecs = 1; + dma_rx_int_mask = XLLDMA_CR_IRQ_ALL_EN_MASK & ~XLLDMA_CR_IRQ_DELAY_EN_MASK; + } + if ((ret = XLlDma_BdRingSetCoalesce(&lp->Dma.RxBdRing, + (u16) (ec->rx_max_coalesced_frames), + (u16) (ec->rx_coalesce_usecs))) != XST_SUCCESS) { + printk(KERN_ERR "%s: XLlDma: BdRingSetCoalesce error %d\n", + dev->name, ret); + return -EIO; + } + XLlDma_mBdRingIntEnable(&lp->Dma.RxBdRing, dma_rx_int_mask); + + if (ec->tx_coalesce_usecs == 0) { + ec->tx_coalesce_usecs = 1; + dma_tx_int_mask = XLLDMA_CR_IRQ_ALL_EN_MASK & ~XLLDMA_CR_IRQ_DELAY_EN_MASK; + } + if ((ret = XLlDma_BdRingSetCoalesce(&lp->Dma.TxBdRing, + (u16) (ec->tx_max_coalesced_frames), + (u16) (ec->tx_coalesce_usecs))) != XST_SUCCESS) { + printk(KERN_ERR "%s: XLlDma: BdRingSetCoalesce error %d\n", + dev->name, ret); + return -EIO; + } + XLlDma_mBdRingIntEnable(&lp->Dma.TxBdRing, dma_tx_int_mask); + + return 0; +} + +static void +xenet_ethtool_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *erp) +{ + memset(erp, 0, sizeof(struct ethtool_ringparam)); + + erp->rx_max_pending = XTE_RECV_BD_CNT; + erp->tx_max_pending = XTE_SEND_BD_CNT; + erp->rx_pending = XTE_RECV_BD_CNT; + erp->tx_pending = XTE_SEND_BD_CNT; +} + +static void +xenet_ethtool_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epp) +{ + u32 Options; + u16 gmii_status; + struct net_local *lp = netdev_priv(dev); + + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, &gmii_status); + + /* I suspect that the expected value is that autonegotiation is + * enabled, not completed. + * As seen in xenet_do_ethtool_ioctl() */ + if (gmii_status & BMSR_ANEGCOMPLETE) { + epp->autoneg = AUTONEG_ENABLE; + } + else { + epp->autoneg = AUTONEG_DISABLE; + } + + Options = XLlTemac_GetOptions(&lp->Emac); + if (Options & XTE_FLOW_CONTROL_OPTION) { + epp->rx_pause = 1; + epp->tx_pause = 1; + } + else { + epp->rx_pause = 0; + epp->tx_pause = 0; + } +} + +#if 0 +static u32 +xenet_ethtool_get_rx_csum(struct net_device *dev) +{ + struct net_local *lp = netdev_priv(dev); + u32 retval; + + retval = (lp->local_features & LOCAL_FEATURE_RX_CSUM) != 0; + + return retval; +} + +static int +xenet_ethtool_set_rx_csum(struct net_device *dev, u32 onoff) +{ + struct net_local *lp = netdev_priv(dev); + + if (onoff) { + if (XLlTemac_IsRxCsum(&lp->Emac) == TRUE) { + lp->local_features |= + LOCAL_FEATURE_RX_CSUM; + } + } + else { + lp->local_features &= ~LOCAL_FEATURE_RX_CSUM; + } + + return 0; +} + +static u32 +xenet_ethtool_get_tx_csum(struct net_device *dev) +{ + u32 retval; + + retval = (dev->features & NETIF_F_IP_CSUM) != 0; + return retval; +} + +static int +xenet_ethtool_set_tx_csum(struct net_device *dev, u32 onoff) +{ + struct net_local *lp = netdev_priv(dev); + + if (onoff) { + if (XLlTemac_IsTxCsum(&lp->Emac) == TRUE) { + dev->features |= NETIF_F_IP_CSUM; + } + } + else { + dev->features &= ~NETIF_F_IP_CSUM; + } + + return 0; +} + +static u32 +xenet_ethtool_get_sg(struct net_device *dev) +{ + u32 retval; + + retval = (dev->features & NETIF_F_SG) != 0; + + return retval; +} + +static int +xenet_ethtool_set_sg(struct net_device *dev, u32 onoff) +{ + struct net_local *lp = netdev_priv(dev); + + if (onoff) { + if (XLlTemac_IsDma(&lp->Emac)) { + dev->features |= + NETIF_F_SG | NETIF_F_FRAGLIST; + } + } + else { + dev->features &= + ~(NETIF_F_SG | NETIF_F_FRAGLIST); + } + + return 0; +} +#endif +static void +xenet_ethtool_get_strings(struct net_device *dev, u32 stringset, u8 *strings) +{ + *strings = 0; + + switch (stringset) { + case ETH_SS_STATS: + memcpy(strings, + &xenet_ethtool_gstrings_stats, + sizeof(xenet_ethtool_gstrings_stats)); + + break; + + default: + break; + } +} + +static void +xenet_ethtool_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct net_local *lp = netdev_priv(dev); + + data[0] = lp->stats.tx_packets; + data[1] = lp->stats.tx_dropped; + data[2] = lp->stats.tx_errors; + data[3] = lp->stats.tx_fifo_errors; + data[4] = lp->stats.rx_packets; + data[5] = lp->stats.rx_dropped; + data[6] = lp->stats.rx_errors; + data[7] = lp->stats.rx_fifo_errors; + data[8] = lp->stats.rx_crc_errors; + data[9] = lp->max_frags_in_a_packet; + data[10] = lp->tx_hw_csums; + data[11] = lp->rx_hw_csums; +} + +static int +xenet_ethtool_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return XENET_STATS_LEN; + default: + return -EOPNOTSUPP; + } + + return 0; +} + + +#define EMAC_REGS_N 32 +struct mac_regsDump { + struct ethtool_regs hd; + u16 data[EMAC_REGS_N]; +}; + +static int +xenet_ethtool_get_regs_len(struct net_device *dev) +{ + return (sizeof(u16) * EMAC_REGS_N); +} + +static void +xenet_ethtool_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *ret) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct mac_regsDump *dump = (struct mac_regsDump *) regs; + int i; + + dump->hd.version = 0; + dump->hd.len = sizeof(dump->data); + memset(dump->data, 0, sizeof(dump->data)); + + for (i = 0; i < EMAC_REGS_N; i++) { + _XLlTemac_PhyRead(&lp->Emac, lp->gmii_addr, i, &(dump->data[i])); + } + + *(int *) ret = 0; +} + +static void +xenet_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *ed) +{ + memset(ed, 0, sizeof(struct ethtool_drvinfo)); + strncpy(ed->driver, DRIVER_NAME, sizeof(ed->driver) - 1); + strncpy(ed->version, DRIVER_VERSION, sizeof(ed->version) - 1); + /* Also tell how much memory is needed for dumping register values */ + ed->regdump_len = sizeof(u16) * EMAC_REGS_N; + ed->n_stats = XENET_STATS_LEN; +} + +/* + * xenet_do_ethtool_ioctl: + * DEPRECATED + */ +static int xenet_do_ethtool_ioctl(struct net_device *dev, struct ifreq *rq) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct ethtool_cmd ecmd; + struct ethtool_coalesce eco; + struct ethtool_drvinfo edrv; + struct ethtool_ringparam erp; + struct ethtool_pauseparam epp; + struct mac_regsDump regs; + int ret = -EOPNOTSUPP; + u32 Options; + + if (copy_from_user(&ecmd, rq->ifr_data, sizeof(ecmd))) + return -EFAULT; + switch (ecmd.cmd) { + case ETHTOOL_GSET: /* Get setting. No command option needed w/ ethtool */ + ret = xenet_ethtool_get_settings(dev, &ecmd); + if (ret < 0) + return -EIO; + if (copy_to_user(rq->ifr_data, &ecmd, sizeof(ecmd))) + return -EFAULT; + ret = 0; + break; + case ETHTOOL_SSET: /* Change setting. Use "-s" command option w/ ethtool */ + ret = xenet_ethtool_set_settings(dev, &ecmd); + break; + case ETHTOOL_GPAUSEPARAM: /* Get pause parameter information. Use "-a" w/ ethtool */ + ret = xenet_ethtool_get_settings(dev, &ecmd); + if (ret < 0) + return ret; + epp.cmd = ecmd.cmd; + epp.autoneg = ecmd.autoneg; + Options = XLlTemac_GetOptions(&lp->Emac); + if (Options & XTE_FCS_INSERT_OPTION) { + epp.rx_pause = 1; + epp.tx_pause = 1; + } + else { + epp.rx_pause = 0; + epp.tx_pause = 0; + } + if (copy_to_user + (rq->ifr_data, &epp, sizeof(struct ethtool_pauseparam))) + return -EFAULT; + ret = 0; + break; + case ETHTOOL_SPAUSEPARAM: /* Set pause parameter. Use "-A" w/ ethtool */ + return -EOPNOTSUPP; /* TODO: To support in next version */ + case ETHTOOL_GRXCSUM:{ /* Get rx csum offload info. Use "-k" w/ ethtool */ + struct ethtool_value edata = { ETHTOOL_GRXCSUM }; + + edata.data = + (lp->local_features & LOCAL_FEATURE_RX_CSUM) != + 0; + if (copy_to_user(rq->ifr_data, &edata, sizeof(edata))) + return -EFAULT; + ret = 0; + break; + } + case ETHTOOL_SRXCSUM:{ /* Set rx csum offload info. Use "-K" w/ ethtool */ + struct ethtool_value edata; + + if (copy_from_user(&edata, rq->ifr_data, sizeof(edata))) + return -EFAULT; + + if (edata.data) { + if (XLlTemac_IsRxCsum(&lp->Emac) == TRUE) { + lp->local_features |= + LOCAL_FEATURE_RX_CSUM; + } + } + else { + lp->local_features &= ~LOCAL_FEATURE_RX_CSUM; + } + + ret = 0; + break; + } + case ETHTOOL_GTXCSUM:{ /* Get tx csum offload info. Use "-k" w/ ethtool */ + struct ethtool_value edata = { ETHTOOL_GTXCSUM }; + + edata.data = (dev->features & NETIF_F_IP_CSUM) != 0; + if (copy_to_user(rq->ifr_data, &edata, sizeof(edata))) + return -EFAULT; + ret = 0; + break; + } + case ETHTOOL_STXCSUM:{ /* Set tx csum offload info. Use "-K" w/ ethtool */ + struct ethtool_value edata; + + if (copy_from_user(&edata, rq->ifr_data, sizeof(edata))) + return -EFAULT; + + if (edata.data) { + if (XLlTemac_IsTxCsum(&lp->Emac) == TRUE) { + dev->features |= NETIF_F_IP_CSUM; + } + } + else { + dev->features &= ~NETIF_F_IP_CSUM; + } + + ret = 0; + break; + } + case ETHTOOL_GSG:{ /* Get ScatterGather info. Use "-k" w/ ethtool */ + struct ethtool_value edata = { ETHTOOL_GSG }; + + edata.data = (dev->features & NETIF_F_SG) != 0; + if (copy_to_user(rq->ifr_data, &edata, sizeof(edata))) + return -EFAULT; + ret = 0; + break; + } + case ETHTOOL_SSG:{ /* Set ScatterGather info. Use "-K" w/ ethtool */ + struct ethtool_value edata; + + if (copy_from_user(&edata, rq->ifr_data, sizeof(edata))) + return -EFAULT; + + if (edata.data) { + if (XLlTemac_IsDma(&lp->Emac)) { + dev->features |= + NETIF_F_SG | NETIF_F_FRAGLIST; + } + } + else { + dev->features &= + ~(NETIF_F_SG | NETIF_F_FRAGLIST); + } + + ret = 0; + break; + } + case ETHTOOL_GCOALESCE: /* Get coalescing info. Use "-c" w/ ethtool */ + if (!(XLlTemac_IsDma(&lp->Emac))) + break; + eco.cmd = ecmd.cmd; + ret = xenet_ethtool_get_coalesce(dev, &eco); + if (ret < 0) { + return -EIO; + } + if (copy_to_user + (rq->ifr_data, &eco, sizeof(struct ethtool_coalesce))) { + return -EFAULT; + } + ret = 0; + break; + case ETHTOOL_SCOALESCE: /* Set coalescing info. Use "-C" w/ ethtool */ + if (!(XLlTemac_IsDma(&lp->Emac))) + break; + if (copy_from_user + (&eco, rq->ifr_data, sizeof(struct ethtool_coalesce))) + return -EFAULT; + ret = xenet_ethtool_set_coalesce(dev, &eco); + break; + case ETHTOOL_GDRVINFO: /* Get driver information. Use "-i" w/ ethtool */ + edrv.cmd = edrv.cmd; + xenet_ethtool_get_drvinfo(dev, &edrv); + edrv.n_stats = XENET_STATS_LEN; + if (copy_to_user + (rq->ifr_data, &edrv, sizeof(struct ethtool_drvinfo))) { + return -EFAULT; + } + ret = 0; + break; + case ETHTOOL_GREGS: /* Get register values. Use "-d" with ethtool */ + regs.hd.cmd = edrv.cmd; + xenet_ethtool_get_regs(dev, &(regs.hd), &ret); + if (ret < 0) { + return ret; + } + if (copy_to_user + (rq->ifr_data, ®s, sizeof(struct mac_regsDump))) { + return -EFAULT; + } + ret = 0; + break; + case ETHTOOL_GRINGPARAM: /* Get RX/TX ring parameters. Use "-g" w/ ethtool */ + erp.cmd = edrv.cmd; + xenet_ethtool_get_ringparam(dev, &(erp)); + if (copy_to_user + (rq->ifr_data, &erp, sizeof(struct ethtool_ringparam))) { + return -EFAULT; + } + ret = 0; + break; + case ETHTOOL_NWAY_RST: /* Restart auto negotiation if enabled. Use "-r" w/ ethtool */ + return -EOPNOTSUPP; /* TODO: To support in next version */ + case ETHTOOL_GSTRINGS:{ + struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS }; + void __user *addr = rq->ifr_data; + char *strings = NULL; + + if (copy_from_user(&gstrings, addr, sizeof(gstrings))) { + return -EFAULT; + } + switch (gstrings.string_set) { + case ETH_SS_STATS: + gstrings.len = XENET_STATS_LEN; + strings = *xenet_ethtool_gstrings_stats; + break; + default: + return -EOPNOTSUPP; + } + if (copy_to_user(addr, &gstrings, sizeof(gstrings))) { + return -EFAULT; + } + addr += offsetof(struct ethtool_gstrings, data); + if (copy_to_user + (addr, strings, gstrings.len * ETH_GSTRING_LEN)) { + return -EFAULT; + } + ret = 0; + break; + } + case ETHTOOL_GSTATS:{ + struct { + struct ethtool_stats cmd; + uint64_t data[XENET_STATS_LEN]; + } stats = { { + ETHTOOL_GSTATS, XENET_STATS_LEN}}; + + stats.data[0] = lp->stats.tx_packets; + stats.data[1] = lp->stats.tx_dropped; + stats.data[2] = lp->stats.tx_errors; + stats.data[3] = lp->stats.tx_fifo_errors; + stats.data[4] = lp->stats.rx_packets; + stats.data[5] = lp->stats.rx_dropped; + stats.data[6] = lp->stats.rx_errors; + stats.data[7] = lp->stats.rx_fifo_errors; + stats.data[8] = lp->stats.rx_crc_errors; + stats.data[9] = lp->max_frags_in_a_packet; + stats.data[10] = lp->tx_hw_csums; + stats.data[11] = lp->rx_hw_csums; + + if (copy_to_user(rq->ifr_data, &stats, sizeof(stats))) { + return -EFAULT; + } + ret = 0; + break; + } + default: + return -EOPNOTSUPP; /* All other operations not supported */ + } + return ret; +} + +static int xenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + /* gmii_ioctl_data has 4 u16 fields: phy_id, reg_num, val_in & val_out */ + struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data; + struct { + __u16 threshold; + __u32 direction; + } thr_arg; + struct { + __u16 waitbound; + __u32 direction; + } wbnd_arg; + + int ret; + u32 threshold, timer; + XLlDma_BdRing *RingPtr; + u32 *dma_int_mask_ptr; + + switch (cmd) { + case SIOCETHTOOL: + /* DEPRECATED */ + return xenet_do_ethtool_ioctl(dev, rq); + case SIOCGMIIPHY: /* Get address of GMII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = lp->gmii_addr; + /* Fall Through */ + + case SIOCGMIIREG: /* Read GMII PHY register. */ + case SIOCDEVPRIVATE + 1: /* for binary compat, remove in 2.5 */ + if (data->phy_id > 31 || data->reg_num > 31) + return -ENXIO; + + /* Stop the PHY timer to prevent reentrancy. */ + del_timer_sync(&lp->phy_timer); + + _XLlTemac_PhyRead(&lp->Emac, data->phy_id, data->reg_num, + &data->val_out); + + /* Start the PHY timer up again. */ + lp->phy_timer.expires = jiffies + 2 * HZ; + add_timer(&lp->phy_timer); + return 0; + + case SIOCSMIIREG: /* Write GMII PHY register. */ + case SIOCDEVPRIVATE + 2: /* for binary compat, remove in 2.5 */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (data->phy_id > 31 || data->reg_num > 31) + return -ENXIO; + + /* Stop the PHY timer to prevent reentrancy. */ + del_timer_sync(&lp->phy_timer); + + _XLlTemac_PhyWrite(&lp->Emac, data->phy_id, data->reg_num, + data->val_in); + + /* Start the PHY timer up again. */ + lp->phy_timer.expires = jiffies + 2 * HZ; + add_timer(&lp->phy_timer); + return 0; + + case SIOCDEVPRIVATE + 3: /* set THRESHOLD */ + if (XLlTemac_IsFifo(&lp->Emac)) + return -EFAULT; + + if (copy_from_user(&thr_arg, rq->ifr_data, sizeof(thr_arg))) + return -EFAULT; + + if (thr_arg.direction == XTE_SEND) { + RingPtr = &lp->Dma.TxBdRing; + } else { + RingPtr = &lp->Dma.RxBdRing; + } + XLlDma_BdRingGetCoalesce(RingPtr, &threshold, &timer); + if (thr_arg.direction == XTE_SEND) { + RingPtr = &lp->Dma.TxBdRing; + } else { + RingPtr = &lp->Dma.RxBdRing; + } + if ((ret = XLlDma_BdRingSetCoalesce(RingPtr, thr_arg.threshold, + timer)) != XST_SUCCESS) { + return -EIO; + } + return 0; + + case SIOCDEVPRIVATE + 4: /* set WAITBOUND */ + if (!(XLlTemac_IsDma(&lp->Emac))) + return -EFAULT; + + if (copy_from_user(&wbnd_arg, rq->ifr_data, sizeof(wbnd_arg))) + return -EFAULT; + + if (wbnd_arg.direction == XTE_SEND) { + RingPtr = &lp->Dma.TxBdRing; + } else { + RingPtr = &lp->Dma.RxBdRing; + } + XLlDma_BdRingGetCoalesce(RingPtr, &threshold, &timer); + if (wbnd_arg.direction == XTE_SEND) { + RingPtr = &lp->Dma.TxBdRing; + dma_int_mask_ptr = &dma_tx_int_mask; + } else { + RingPtr = &lp->Dma.RxBdRing; + dma_int_mask_ptr = &dma_rx_int_mask; + } + if (wbnd_arg.waitbound == 0) { + wbnd_arg.waitbound = 1; + *dma_int_mask_ptr = XLLDMA_CR_IRQ_ALL_EN_MASK & ~XLLDMA_CR_IRQ_DELAY_EN_MASK; + } + if ((ret = XLlDma_BdRingSetCoalesce(RingPtr, threshold, + wbnd_arg.waitbound)) != XST_SUCCESS) { + return -EIO; + } + XLlDma_mBdRingIntEnable(RingPtr, *dma_int_mask_ptr); + + return 0; + + case SIOCDEVPRIVATE + 5: /* get THRESHOLD */ + if (!(XLlTemac_IsDma(&lp->Emac))) + return -EFAULT; + + if (copy_from_user(&thr_arg, rq->ifr_data, sizeof(thr_arg))) + return -EFAULT; + + if (thr_arg.direction == XTE_SEND) { + RingPtr = &lp->Dma.TxBdRing; + } else { + RingPtr = &lp->Dma.RxBdRing; + } + XLlDma_BdRingGetCoalesce(RingPtr, + (u32 *) &(thr_arg.threshold), &timer); + if (copy_to_user(rq->ifr_data, &thr_arg, sizeof(thr_arg))) { + return -EFAULT; + } + return 0; + + case SIOCDEVPRIVATE + 6: /* get WAITBOUND */ + if (!(XLlTemac_IsDma(&lp->Emac))) + return -EFAULT; + + if (copy_from_user(&wbnd_arg, rq->ifr_data, sizeof(wbnd_arg))) { + return -EFAULT; + } + if (thr_arg.direction == XTE_SEND) { + RingPtr = &lp->Dma.TxBdRing; + } else { + RingPtr = &lp->Dma.RxBdRing; + } + XLlDma_BdRingGetCoalesce(RingPtr, &threshold, + (u32 *) &(wbnd_arg.waitbound)); + if (copy_to_user(rq->ifr_data, &wbnd_arg, sizeof(wbnd_arg))) { + return -EFAULT; + } + return 0; + + default: + return -EOPNOTSUPP; + } +} + + +/****************************************************************************** + * + * NEW FUNCTIONS FROM LINUX 2.6 + * + ******************************************************************************/ + +static void xtenet_remove_ndev(struct net_device *ndev) +{ + if (ndev) { + struct net_local *lp = netdev_priv(ndev); + + if (XLlTemac_IsDma(&lp->Emac) && (lp->desc_space)) + free_descriptor_skb(ndev); + + iounmap((__force void __iomem *) (lp->Emac.Config.BaseAddress)); + free_netdev(ndev); + } +} + +static int xtenet_remove(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + + unregister_netdev(ndev); + xtenet_remove_ndev(ndev); + + return 0; /* success */ +} + +/* Detect the PHY address by scanning addresses 0 to 31 and + * looking at the MII status register (register 1) and assuming + * the PHY supports 10Mbps full/half duplex. Feel free to change + * this code to match your PHY, or hardcode the address if needed. + */ +/* Use MII register 1 (MII status register) to detect PHY */ +#define PHY_DETECT_REG 1 + +#ifdef CONFIG_XILINX_LLTEMAC_XILINX_1000BASEX +/* Mask used to verify certain PHY features (or register contents) + * in the register above: + * 0x0100: Extended register support + * 0x0180: Unidirectional support + * 0x0040: MF Preamble suppression support + * 0x0008: Auto-negotiation support + */ +#define PHY_DETECT_MASK 0x01C8 +#else +/* Mask used to verify certain PHY features (or register contents) + * in the register above: + * 0x1000: 10Mbps full duplex support + * 0x0800: 10Mbps half duplex support + * 0x0008: Auto-negotiation support + */ +#define PHY_DETECT_MASK 0x1808 +#endif + +static int detect_phy(struct net_local *lp, char *dev_name) +{ + u16 phy_reg; + u32 phy_addr; + + for (phy_addr = 31; phy_addr > 0; phy_addr--) { + _XLlTemac_PhyRead(&lp->Emac, phy_addr, PHY_DETECT_REG, &phy_reg); + + if ((phy_reg != 0xFFFF) && + ((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + printk(KERN_INFO "XTemac: PHY detected at address %d.\n", phy_addr); + return phy_addr; + } + } + + printk(KERN_WARNING "XTemac: No PHY detected. Assuming a PHY at address 0\n"); + return 0; /* default to zero */ +} + +static struct net_device_ops xilinx_netdev_ops; + +/* From include/linux/ethtool.h */ +static struct ethtool_ops ethtool_ops = { + .get_settings = xenet_ethtool_get_settings, + .set_settings = xenet_ethtool_set_settings, + .get_drvinfo = xenet_ethtool_get_drvinfo, + .get_regs_len = xenet_ethtool_get_regs_len, + .get_regs = xenet_ethtool_get_regs, + .get_coalesce = xenet_ethtool_get_coalesce, + .set_coalesce = xenet_ethtool_set_coalesce, + .get_ringparam = xenet_ethtool_get_ringparam, + .get_pauseparam = xenet_ethtool_get_pauseparam, +/* .get_rx_csum = xenet_ethtool_get_rx_csum, + .set_rx_csum = xenet_ethtool_set_rx_csum, + .get_tx_csum = xenet_ethtool_get_tx_csum, + .set_tx_csum = xenet_ethtool_set_tx_csum, + .get_sg = xenet_ethtool_get_sg, + .set_sg = xenet_ethtool_set_sg, */ + .get_strings = xenet_ethtool_get_strings, + .get_ethtool_stats = xenet_ethtool_get_ethtool_stats, + .get_sset_count = xenet_ethtool_get_sset_count, +}; + +/** Shared device initialization code */ +static int xtenet_setup( + struct device *dev, + struct resource *r_mem, + struct resource *r_irq, + struct xlltemac_platform_data *pdata) { + int xs; + u32 virt_baddr; /* virtual base address of TEMAC */ + + XLlTemac_Config Temac_Config; + + struct net_device *ndev = NULL; + struct net_local *lp = NULL; + + int rc = 0; + + /* Create an ethernet device instance */ + ndev = alloc_etherdev(sizeof(struct net_local)); + if (!ndev) { + dev_err(dev, "Could not allocate net device.\n"); + rc = -ENOMEM; + goto error; + } + dev_set_drvdata(dev, ndev); + + SET_NETDEV_DEV(ndev, dev); + ndev->irq = r_irq->start; + + /* Initialize the private data used by XEmac_LookupConfig(). + * The private data are zeroed out by alloc_etherdev() already. + */ + lp = netdev_priv(ndev); + lp->ndev = ndev; + lp->dma_irq_r = pdata->ll_dev_dma_rx_irq; + lp->dma_irq_s = pdata->ll_dev_dma_tx_irq; + lp->fifo_irq = pdata->ll_dev_fifo_irq; + + /* Setup the Config structure for the XLlTemac_CfgInitialize() call. */ + Temac_Config.BaseAddress = r_mem->start; +#if 0 + Config.RxPktFifoDepth = pdata->rx_pkt_fifo_depth; + Config.TxPktFifoDepth = pdata->tx_pkt_fifo_depth; + Config.MacFifoDepth = pdata->mac_fifo_depth; + Config.IpIfDmaConfig = pdata->dma_mode; +#endif + Temac_Config.TxCsum = pdata->tx_csum; + Temac_Config.RxCsum = pdata->rx_csum; + Temac_Config.LLDevType = pdata->ll_dev_type; + Temac_Config.LLDevBaseAddress = pdata->ll_dev_baseaddress; + Temac_Config.PhyType = pdata->phy_type; + + /* Get the virtual base address for the device */ + virt_baddr = (__force u32) ioremap(r_mem->start, + r_mem->end - r_mem->start + 1); + if (0 == virt_baddr) { + dev_err(dev, "XLlTemac: Could not allocate iomem.\n"); + rc = -EIO; + goto error; + } + + if (XLlTemac_CfgInitialize(&lp->Emac, &Temac_Config, virt_baddr) != + XST_SUCCESS) { + dev_err(dev, "XLlTemac: Could not initialize device.\n"); + + rc = -ENODEV; + goto error; + } + + /* Set the MAC address from platform data */ + memcpy(ndev->dev_addr, pdata->mac_addr, 6); + + if (_XLlTemac_SetMacAddress(&lp->Emac, ndev->dev_addr) != XST_SUCCESS) { + /* should not fail right after an initialize */ + dev_err(dev, "XLlTemac: could not set MAC address.\n"); + rc = -EIO; + goto error; + } + + dev_info(dev, + "MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n", + pdata->mac_addr[0], pdata->mac_addr[1], + pdata->mac_addr[2], pdata->mac_addr[3], + pdata->mac_addr[4], pdata->mac_addr[5]); + + if (ndev->mtu > XTE_JUMBO_MTU) + ndev->mtu = XTE_JUMBO_MTU; + + lp->frame_size = ndev->mtu + XTE_HDR_SIZE + XTE_TRL_SIZE; + + if (XLlTemac_IsDma(&lp->Emac)) { + int result; + + dev_err(dev, "XLlTemac: using DMA mode.\n"); + + if (pdata->dcr_host) { + printk("XLlTemac: DCR address: 0x%0x\n", pdata->ll_dev_baseaddress); + XLlDma_Initialize(&lp->Dma, pdata->ll_dev_baseaddress); + lp->virt_dma_addr = pdata->ll_dev_baseaddress; + } else { + virt_baddr = (__force u32) ioremap(pdata->ll_dev_baseaddress, 4096); + lp->virt_dma_addr = virt_baddr; + if (0 == virt_baddr) { + dev_err(dev, + "XLlTemac: Could not allocate iomem for local link connected device.\n"); + rc = -EIO; + goto error; + } + printk("XLlTemac: Dma base address: phy: 0x%x, virt: 0x%x\n", pdata->ll_dev_baseaddress, virt_baddr); + XLlDma_Initialize(&lp->Dma, virt_baddr); + } + + xilinx_netdev_ops.ndo_start_xmit = xenet_DmaSend; + + result = descriptor_init(ndev); + if (result) { + rc = -EIO; + goto error; + } + + /* set the packet threshold and wait bound for both TX/RX directions */ + if (DFT_TX_WAITBOUND == 0) { + dma_tx_int_mask = XLLDMA_CR_IRQ_ALL_EN_MASK & ~XLLDMA_CR_IRQ_DELAY_EN_MASK; + xs = XLlDma_BdRingSetCoalesce(&lp->Dma.TxBdRing, DFT_TX_THRESHOLD, 1); + } else { + xs = XLlDma_BdRingSetCoalesce(&lp->Dma.TxBdRing, DFT_TX_THRESHOLD, DFT_TX_WAITBOUND); + } + if (xs != XST_SUCCESS) { + dev_err(dev, + "XLlTemac: could not set SEND pkt threshold/waitbound, ERROR %d", + xs); + } + XLlDma_mBdRingIntEnable(&lp->Dma.TxBdRing, dma_tx_int_mask); + + if (DFT_RX_WAITBOUND == 0) { + dma_rx_int_mask = XLLDMA_CR_IRQ_ALL_EN_MASK & ~XLLDMA_CR_IRQ_DELAY_EN_MASK; + xs = XLlDma_BdRingSetCoalesce(&lp->Dma.RxBdRing, DFT_RX_THRESHOLD, 1); + } else { + xs = XLlDma_BdRingSetCoalesce(&lp->Dma.RxBdRing, DFT_RX_THRESHOLD, DFT_RX_WAITBOUND); + } + if (xs != XST_SUCCESS) { + dev_err(dev, + "XLlTemac: Could not set RECV pkt threshold/waitbound ERROR %d", + xs); + } + XLlDma_mBdRingIntEnable(&lp->Dma.RxBdRing, dma_rx_int_mask); + } + else { + dev_err(dev, + "XLlTemac: using FIFO direct interrupt driven mode.\n"); + + virt_baddr = (__force u32) ioremap(pdata->ll_dev_baseaddress, + 4096); + if (0 == virt_baddr) { + dev_err(dev, + "XLlTemac: Could not allocate iomem for local link connected device.\n"); + rc = -EIO; + goto error; + } + printk("XLlTemac: Fifo base address: 0x%0x\n", virt_baddr); + XLlFifo_Initialize(&lp->Fifo, virt_baddr); + + xilinx_netdev_ops.ndo_start_xmit = xenet_FifoSend; + } + + /** Scan to find the PHY */ + lp->gmii_addr = detect_phy(lp, ndev->name); + + + /* initialize the netdev structure */ + + ndev->netdev_ops = &xilinx_netdev_ops; + + if (XLlTemac_IsDma(&lp->Emac)) { + ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST; + + if (XLlTemac_IsTxCsum(&lp->Emac) == TRUE) { + /* + * This hardware only supports proper checksum calculations + * on TCP/UDP packets. + */ + ndev->features |= NETIF_F_IP_CSUM; + } + if (XLlTemac_IsRxCsum(&lp->Emac) == TRUE) { + lp->local_features |= LOCAL_FEATURE_RX_CSUM; + } + } + + ndev->watchdog_timeo = TX_TIMEOUT; + + /* init the stats */ + lp->max_frags_in_a_packet = 0; + lp->tx_hw_csums = 0; + lp->rx_hw_csums = 0; + +#if ! XTE_AUTOSTRIPPING + lp->stripping = + (XLlTemac_GetOptions(&(lp->Emac)) & XTE_FCS_STRIP_OPTION) != 0; +#endif + + /* Set ethtool IOCTL handler vectors. + * xenet_do_ethtool_ioctl() is deprecated. + */ + SET_ETHTOOL_OPS(ndev, ðtool_ops); + + rc = register_netdev(ndev); + if (rc) { + dev_err(dev, + "%s: Cannot register net device, aborting.\n", + ndev->name); + goto error; /* rc is already set here... */ + } + + dev_info(dev, + "%s: Xilinx TEMAC at 0x%08X mapped to 0x%08X, irq=%d\n", + ndev->name, + (unsigned int)r_mem->start, + lp->Emac.Config.BaseAddress, + ndev->irq); + + return 0; + +error: + if (ndev) { + xtenet_remove_ndev(ndev); + } + return rc; +} + +#if 0 +static int xtenet_probe(struct device *dev) +{ + struct resource *r_irq = NULL; /* Interrupt resources */ + struct resource *r_mem = NULL; /* IO mem resources */ + struct xlltemac_platform_data *pdata; + struct platform_device *pdev = to_platform_device(dev); + + /* param check */ + if (!pdev) { + dev_err(dev, "Probe called with NULL param.\n"); + return -ENODEV; + } + + pdata = (struct xlltemac_platform_data *) pdev->dev.platform_data; + if (!pdata) { + dev_err(dev, "Couldn't find platform data.\n"); + + return -ENODEV; + } + + /* Get iospace and an irq for the device */ + r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r_irq || !r_mem) { + dev_err(dev, "IO resource(s) not found.\n"); + return -ENODEV; + } + + return xtenet_setup(dev, r_mem, r_irq, pdata); +} +#endif + + +#ifdef CONFIG_OF +static u32 get_u32(struct platform_device *op, const char *s) { + u32 *p = (u32 *)of_get_property(op->dev.of_node, s, NULL); + if(p) { + return *p; + } else { + dev_warn(&op->dev, "Parameter %s not found, defaulting to false.\n", s); + return FALSE; + } +} + +static struct net_device_ops xilinx_netdev_ops = { + .ndo_open = xenet_open, + .ndo_stop = xenet_close, + .ndo_start_xmit = NULL, + .ndo_do_ioctl = xenet_ioctl, + .ndo_change_mtu = xenet_change_mtu, + .ndo_tx_timeout = xenet_tx_timeout, + .ndo_get_stats = xenet_get_stats, + .ndo_set_mac_address = eth_mac_addr, + .ndo_set_rx_mode = xenet_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, +}; + +static struct of_device_id xtenet_fifo_of_match[] = { + { .compatible = "xlnx,xps-ll-fifo-1.00.a", }, + { .compatible = "xlnx,xps-ll-fifo-1.00.b", }, + { .compatible = "xlnx,xps-ll-fifo-1.01.a", }, + { /* end of list */ }, +}; + +static struct of_device_id xtenet_sdma_of_match[] = { + { .compatible = "xlnx,ll-dma-1.00.a", }, + { /* end of list */ }, +}; + +static int xtenet_of_probe(struct platform_device *op) +{ + struct resource r_irq_struct; + struct resource r_mem_struct; + struct resource r_connected_mem_struct; + struct resource r_connected_irq_struct; + struct xlltemac_platform_data pdata_struct; + + struct resource *r_irq = &r_irq_struct; /* Interrupt resources */ + struct resource *r_mem = &r_mem_struct; /* IO mem resources */ + struct xlltemac_platform_data *pdata = &pdata_struct; + const void *mac_address; + int rc = 0; + const phandle *llink_connected_handle; + struct device_node *llink_connected_node; + u32 *dcrreg_property; + + /* + * Make sure the locks are initialized + */ + spin_lock_init(&XTE_spinlock); + spin_lock_init(&XTE_tx_spinlock); + spin_lock_init(&XTE_rx_spinlock); + + INIT_LIST_HEAD(&sentQueue); + INIT_LIST_HEAD(&receivedQueue); + + spin_lock_init(&sentQueueSpin); + spin_lock_init(&receivedQueueSpin); + + printk(KERN_INFO "Device Tree Probing \'%s\'\n", + op->dev.of_node->name); + + /* Get iospace for the device */ + rc = of_address_to_resource(op->dev.of_node, 0, r_mem); + if(rc) { + dev_warn(&op->dev, "invalid address\n"); + return rc; + } + + /* Get IRQ for the device */ + rc = of_irq_to_resource(op->dev.of_node, 0, r_irq); + if(!rc) { + dev_warn(&op->dev, "no IRQ found.\n"); + return rc; + } + + pdata_struct.tx_csum = get_u32(op, "xlnx,txcsum"); + pdata_struct.rx_csum = get_u32(op, "xlnx,rxcsum"); + pdata_struct.phy_type = get_u32(op, "xlnx,phy-type"); + llink_connected_handle = + of_get_property(op->dev.of_node, "llink-connected", NULL); + if(!llink_connected_handle) { + dev_warn(&op->dev, "no Locallink connection found.\n"); + return rc; + } + + llink_connected_node = + of_find_node_by_phandle(*llink_connected_handle); + rc = of_address_to_resource( + llink_connected_node, + 0, + &r_connected_mem_struct); + + /** Get the right information from whatever the locallink is + connected to. */ + if(of_match_node(xtenet_fifo_of_match, llink_connected_node)) { + /** Connected to a fifo. */ + + if(rc) { + dev_warn(&op->dev, "invalid address\n"); + return rc; + } + + pdata_struct.ll_dev_baseaddress = r_connected_mem_struct.start; + pdata_struct.ll_dev_type = XPAR_LL_FIFO; + pdata_struct.ll_dev_dma_rx_irq = 0; + pdata_struct.ll_dev_dma_tx_irq = 0; + + rc = of_irq_to_resource( + llink_connected_node, + 0, + &r_connected_irq_struct); + if(!rc) { + dev_warn(&op->dev, "no IRQ found.\n"); + return rc; + } + pdata_struct.ll_dev_fifo_irq = r_connected_irq_struct.start; + pdata_struct.dcr_host = 0x0; + } else if(of_match_node(xtenet_sdma_of_match, llink_connected_node)) { + /** Connected to a dma port, default to 405 type dma */ + pdata->dcr_host = 0; + if(rc) { + /* no address was found, might be 440, check for dcr reg */ + + dcrreg_property = (u32 *)of_get_property(llink_connected_node, "dcr-reg", NULL); + if(dcrreg_property) { + r_connected_mem_struct.start = *dcrreg_property; + pdata->dcr_host = 0xFF; + } else { + dev_warn(&op->dev, "invalid address\n"); + return rc; + } + } + + pdata_struct.ll_dev_baseaddress = r_connected_mem_struct.start; + pdata_struct.ll_dev_type = XPAR_LL_DMA; + + rc = of_irq_to_resource( + llink_connected_node, + 0, + &r_connected_irq_struct); + if(!rc) { + dev_warn(&op->dev, "First IRQ not found.\n"); + return rc; + } + pdata_struct.ll_dev_dma_rx_irq = r_connected_irq_struct.start; + rc = of_irq_to_resource( + llink_connected_node, + 1, + &r_connected_irq_struct); + if(!rc) { + dev_warn(&op->dev, "Second IRQ not found.\n"); + return rc; + } + pdata_struct.ll_dev_dma_tx_irq = r_connected_irq_struct.start; + + pdata_struct.ll_dev_fifo_irq = 0; + } else { + dev_warn(&op->dev, "Locallink connection not matched.\n"); + return rc; + } + + of_node_put(llink_connected_node); + mac_address = of_get_mac_address(op->dev.of_node); + if(mac_address) { + memcpy(pdata_struct.mac_addr, mac_address, 6); + } else { + dev_warn(&op->dev, "No MAC address found.\n"); + } + + return xtenet_setup(&op->dev, r_mem, r_irq, pdata); +} + +static int xtenet_of_remove(struct platform_device *op) +{ + return xtenet_remove(&op->dev); +} + +static struct of_device_id xtenet_of_match[] = { + { .compatible = "xlnx,xps-ll-temac-1.00.a", }, + { .compatible = "xlnx,xps-ll-temac-1.00.b", }, + { .compatible = "xlnx,xps-ll-temac-1.01.a", }, + { .compatible = "xlnx,xps-ll-temac-1.01.b", }, + { /* end of list */ }, +}; + +MODULE_DEVICE_TABLE(of, xtenet_of_match); +#endif + +static struct platform_driver xtenet_of_driver = { + .probe = xtenet_of_probe, + .remove = xtenet_of_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(xtenet_of_match), + }, +}; + +module_platform_driver(xtenet_of_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/remoteproc/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/remoteproc/Kconfig 2014-07-20 22:05:50.264066159 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/remoteproc/Kconfig 2014-07-20 22:06:37.270290642 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:67 @ It's safe to say n here if you're not interested in multimedia offloading. +config ZYNQ_REMOTEPROC + tristate "Support ZYNQ remoteproc" + depends on ARCH_ZYNQ && SMP && !DEBUG_SG + select REMOTEPROC + select RPMSG + select HOTPLUG_CPU + default m + help + Say y here to support Xilinx ZynQ remote processors (the second + ARM CORTEX-A9 cpu) via the remote processor framework. + +config MB_REMOTEPROC + tristate "Support Microblaze remoteproc" + depends on ARCH_ZYNQ && !DEBUG_SG + select GPIO_XILINX + select REMOTEPROC + select RPMSG + default m + help + Say y here to support Xilinx Microblaze remote processors + on the Xilinx Zynq. + endmenu Index: linux-3.12.24-rt38-xilinx/drivers/remoteproc/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/remoteproc/Makefile 2014-07-20 22:05:50.263066176 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/remoteproc/Makefile 2014-07-20 22:06:37.279290493 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:13 @ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o +obj-$(CONFIG_ZYNQ_REMOTEPROC) += zynq_remoteproc.o +obj-$(CONFIG_MB_REMOTEPROC) += mb_remoteproc.o Index: linux-3.12.24-rt38-xilinx/drivers/remoteproc/mb_remoteproc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/remoteproc/mb_remoteproc.c 2014-07-20 22:06:37.290290312 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Microblaze Remote Processor driver + * + * Copyright (C) 2012 - 2013 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2013 Xilinx, Inc. + * Copyright (C) 2012 PetaLogix + * + * Based on origin OMAP Remote Processor driver + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/remoteproc.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> +#include <linux/smp.h> +#include <linux/irqchip/arm-gic.h> +#include <asm/outercache.h> +#include <asm/cacheflush.h> +#include <linux/slab.h> +#include <linux/cpu.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/delay.h> + +#include "remoteproc_internal.h" + +/* Module parameter */ +static char *firmware; + +/* Private data */ +struct mb_rproc_pdata { + struct rproc *rproc; + u32 mem_start; + u32 mem_end; + int reset_gpio; + int mb_debug_gpio; + int ipi; + int vring0; + int vring1; + void __iomem *vbase; + const unsigned char *bootloader; +}; + +/* Store rproc for IPI handler */ +static struct platform_device *remoteprocdev; +static struct work_struct workqueue; + +static void handle_event(struct work_struct *work) +{ + struct mb_rproc_pdata *local = platform_get_drvdata(remoteprocdev); + + flush_cache_all(); + outer_flush_range(local->mem_start, local->mem_end); + + if (rproc_vq_interrupt(local->rproc, 0) == IRQ_NONE) + dev_info(&remoteprocdev->dev, "no message found in vqid 0\n"); +} + +static irqreturn_t ipi_kick(int irq, void *dev_id) +{ + dev_dbg(&remoteprocdev->dev, "KICK Linux because of pending message\n"); + schedule_work(&workqueue); + dev_dbg(&remoteprocdev->dev, "KICK Linux handled\n"); + + return IRQ_HANDLED; +} + +static int mb_rproc_start(struct rproc *rproc) +{ + struct device *dev = rproc->dev.parent; + struct platform_device *pdev = to_platform_device(dev); + struct mb_rproc_pdata *local = platform_get_drvdata(pdev); + const struct firmware *fw; + int ret; + + dev_info(dev, "%s\n", __func__); + INIT_WORK(&workqueue, handle_event); + + flush_cache_all(); + outer_flush_range(local->mem_start, local->mem_end); + + remoteprocdev = pdev; + + ret = request_firmware(&fw, local->bootloader, &pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "request_firmware failed\n"); + return ret; + } + /* Copy bootloader to memory */ + memcpy(local->vbase, fw->data, fw->size); + release_firmware(fw); + + /* Just for sure synchronize memories */ + dsb(); + + /* Release Microblaze from reset */ + gpio_set_value(local->reset_gpio, 0); + + return 0; +} + +/* kick a firmware */ +static void mb_rproc_kick(struct rproc *rproc, int vqid) +{ + struct device *dev = rproc->dev.parent; + struct platform_device *pdev = to_platform_device(dev); + struct mb_rproc_pdata *local = platform_get_drvdata(pdev); + + dev_dbg(dev, "KICK Firmware to start send messages vqid %d\n", vqid); + + flush_cache_all(); + outer_flush_all(); + + /* Send swirq to firmware */ + gpio_set_value(local->vring0, 0); + gpio_set_value(local->vring1, 0); + dsb(); + + if (!vqid) { + udelay(500); + gpio_set_value(local->vring0, 1); + dsb(); + } else { + udelay(100); + gpio_set_value(local->vring1, 1); + dsb(); + } +} + +/* power off the remote processor */ +static int mb_rproc_stop(struct rproc *rproc) +{ + struct device *dev = rproc->dev.parent; + struct platform_device *pdev = to_platform_device(dev); + struct mb_rproc_pdata *local = platform_get_drvdata(pdev); + + /* Setup MB to the state where all memory transactions are done */ + gpio_set_value(local->mb_debug_gpio, 1); + dsb(); /* Be sure that this write has been done */ + /* + * This should be enough to ensure one CLK as + * it is written in MB ref guide + */ + gpio_set_value(local->mb_debug_gpio, 0); + + udelay(1000); /* Wait some time to finish all mem transactions */ + + /* Add Microblaze to reset state */ + gpio_set_value(local->reset_gpio, 1); + + /* No reason to wait that operations where done */ + return 0; +} + +static struct rproc_ops mb_rproc_ops = { + .start = mb_rproc_start, + .stop = mb_rproc_stop, + .kick = mb_rproc_kick, +}; + +/* Just to detect bug if interrupt forwarding is broken */ +static irqreturn_t mb_remoteproc_interrupt(int irq, void *dev_id) +{ + struct device *dev = dev_id; + + dev_err(dev, "GIC IRQ %d is not forwarded correctly\n", irq); + + return IRQ_HANDLED; +} + +static int mb_remoteproc_probe(struct platform_device *pdev) +{ + const unsigned char *prop; + struct platform_device *bram_pdev; + struct device_node *bram_dev; + struct resource *res; /* IO mem resources */ + int ret = 0; + int count = 0; + struct mb_rproc_pdata *local; + + local = devm_kzalloc(&pdev->dev, sizeof(*local), GFP_KERNEL); + if (!local) + return -ENOMEM; + + platform_set_drvdata(pdev, local); + + /* Declare memory for firmware */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid address\n"); + return -ENODEV; + } + + local->mem_start = res->start; + local->mem_end = res->end; + + /* Alloc phys addr from 0 to max_addr for firmware */ + ret = dma_declare_coherent_memory(&pdev->dev, local->mem_start, + local->mem_start, local->mem_end - local->mem_start + 1, + DMA_MEMORY_IO); + if (!ret) { + dev_err(&pdev->dev, "dma_declare_coherent_memory failed\n"); + return ret; + } + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret); + return ret; + } + + /* Alloc IRQ based on DTS to be sure that no other driver will use it */ + while (1) { + int irq; + /* Allocating shared IRQs will ensure that any module will + * use these IRQs */ + irq = platform_get_irq(pdev, count++); + if (irq == -ENXIO) + break; + ret = devm_request_irq(&pdev->dev, irq, mb_remoteproc_interrupt, + 0, dev_name(&pdev->dev), &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "IRQ %d already allocated\n", irq); + return ret; + } + + dev_info(&pdev->dev, "%d: Alloc irq: %d\n", count, irq); + } + + /* Find out reset gpio and keep microblaze in reset */ + local->reset_gpio = of_get_named_gpio(pdev->dev.of_node, "reset", 0); + if (local->reset_gpio < 0) { + dev_err(&pdev->dev, "reset-gpio property not found\n"); + return local->reset_gpio; + } + ret = devm_gpio_request_one(&pdev->dev, local->reset_gpio, + GPIOF_OUT_INIT_HIGH, "mb_reset"); + if (ret) { + dev_err(&pdev->dev, "Please specify gpio reset addr\n"); + return ret; + } + + /* Find out reset gpio and keep microblaze in reset */ + local->mb_debug_gpio = of_get_named_gpio(pdev->dev.of_node, "debug", 0); + if (local->mb_debug_gpio < 0) { + dev_err(&pdev->dev, "mb-debug-gpio property not found\n"); + return local->mb_debug_gpio; + } + ret = devm_gpio_request_one(&pdev->dev, local->mb_debug_gpio, + GPIOF_OUT_INIT_LOW, "mb_debug"); + if (ret) { + dev_err(&pdev->dev, "Please specify gpio debug pin\n"); + return ret; + } + + /* IPI number for getting irq from firmware */ + local->ipi = of_get_named_gpio(pdev->dev.of_node, "ipino", 0); + if (local->ipi < 0) { + dev_err(&pdev->dev, "ipi-gpio property not found\n"); + return local->ipi; + } + ret = devm_gpio_request_one(&pdev->dev, local->ipi, GPIOF_IN, "mb_ipi"); + if (ret) { + dev_err(&pdev->dev, "Please specify gpio reset addr\n"); + return ret; + } + ret = devm_request_irq(&pdev->dev, gpio_to_irq(local->ipi), + ipi_kick, IRQF_SHARED|IRQF_TRIGGER_RISING, + dev_name(&pdev->dev), local); + if (ret) { + dev_err(&pdev->dev, "IRQ %d already allocated\n", local->ipi); + return ret; + } + + /* Find out vring0 pin */ + local->vring0 = of_get_named_gpio(pdev->dev.of_node, "vring0", 0); + if (local->vring0 < 0) { + dev_err(&pdev->dev, "reset-gpio property not found\n"); + return local->vring0; + } + ret = devm_gpio_request_one(&pdev->dev, local->vring0, + GPIOF_DIR_OUT, "mb_vring0"); + if (ret) { + dev_err(&pdev->dev, "Please specify gpio reset addr\n"); + return ret; + } + + /* Find out vring1 pin */ + local->vring1 = of_get_named_gpio(pdev->dev.of_node, "vring1", 0); + if (local->vring1 < 0) { + dev_err(&pdev->dev, "reset-gpio property not found\n"); + return local->vring1; + } + ret = devm_gpio_request_one(&pdev->dev, local->vring1, + GPIOF_DIR_OUT, "mb_vring1"); + if (ret) { + dev_err(&pdev->dev, "Please specify gpio reset addr\n"); + return ret; + } + + /* Allocate bram device */ + bram_dev = of_parse_phandle(pdev->dev.of_node, "bram", 0); + if (!bram_dev) { + dev_err(&pdev->dev, "Please specify bram connection\n"); + return -ENODEV; + } + bram_pdev = of_find_device_by_node(bram_dev); + if (!bram_pdev) { + dev_err(&pdev->dev, "BRAM device hasn't found\n"); + return -ENODEV; + } + res = platform_get_resource(bram_pdev, IORESOURCE_MEM, 0); + local->vbase = devm_ioremap_resource(&pdev->dev, res); + if (!local->vbase) + return -ENODEV; + + /* Load simple bootloader to bram */ + local->bootloader = of_get_property(pdev->dev.of_node, + "bram-firmware", NULL); + if (!local->bootloader) { + dev_err(&pdev->dev, "Please specify BRAM firmware\n"); + return -ENODEV; + } + + dev_info(&pdev->dev, "Using microblaze BRAM bootloader: %s\n", + local->bootloader); + + /* Module param firmware first */ + if (firmware) + prop = firmware; + else + prop = of_get_property(pdev->dev.of_node, "firmware", NULL); + + if (prop) { + dev_info(&pdev->dev, "Using firmware: %s\n", prop); + local->rproc = rproc_alloc(&pdev->dev, dev_name(&pdev->dev), + &mb_rproc_ops, prop, sizeof(struct rproc)); + if (!local->rproc) { + dev_err(&pdev->dev, "rproc allocation failed\n"); + return -ENOMEM; + } + + ret = rproc_add(local->rproc); + if (ret) { + dev_err(&pdev->dev, "rproc registration failed\n"); + rproc_put(local->rproc); + return ret; + } + return 0; + } + + return -ENODEV; +} + +static int mb_remoteproc_remove(struct platform_device *pdev) +{ + struct mb_rproc_pdata *local = platform_get_drvdata(pdev); + + dev_info(&pdev->dev, "%s\n", __func__); + + dma_release_declared_memory(&pdev->dev); + + rproc_del(local->rproc); + rproc_put(local->rproc); + + return 0; +} + +/* Match table for OF platform binding */ +static struct of_device_id mb_remoteproc_match[] = { + { .compatible = "xlnx,mb_remoteproc", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, mb_remoteproc_match); + +static struct platform_driver mb_remoteproc_driver = { + .probe = mb_remoteproc_probe, + .remove = mb_remoteproc_remove, + .driver = { + .name = "mb_remoteproc", + .owner = THIS_MODULE, + .of_match_table = mb_remoteproc_match, + }, +}; +module_platform_driver(mb_remoteproc_driver); + +module_param(firmware, charp, 0); +MODULE_PARM_DESC(firmware, "Override the firmware image name. Default value in DTS."); + +MODULE_AUTHOR("Michal Simek <monstr@monstr.eu"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Microblaze remote processor control driver"); Index: linux-3.12.24-rt38-xilinx/drivers/remoteproc/remoteproc_core.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/remoteproc/remoteproc_core.c 2014-07-20 22:05:50.262066192 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/remoteproc/remoteproc_core.c 2014-07-20 22:06:37.304290081 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:692 @ * enum fw_resource_type. */ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { - [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, + [RSC_CARVEOUT] = NULL, /* Register carveouts separately */ [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */ + [RSC_MMU] = NULL, /* For firmware purpose */ +}; + +static rproc_handle_resource_t rproc_carveout_handlers[RSC_LAST] = { + [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, }; static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:930 @ /* count the number of notify-ids */ rproc->max_notifyid = -1; + + /* look for carveout areas and register them first */ + ret = rproc_handle_resources(rproc, tablesz, rproc_carveout_handlers); + if (ret) + goto out; + ret = rproc_handle_resources(rproc, tablesz, rproc_count_vrings_handler); if (ret) goto out; Index: linux-3.12.24-rt38-xilinx/drivers/remoteproc/remoteproc_elf_loader.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/remoteproc/remoteproc_elf_loader.c 2014-07-20 22:05:50.265066142 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/remoteproc/remoteproc_elf_loader.c 2014-07-20 22:06:37.317289867 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:323 @ { struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data; struct elf32_shdr *shdr; + const u8 *elf_data = fw->data; + struct elf32_phdr *phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); shdr = find_table(&rproc->dev, ehdr, fw->size); if (!shdr) return NULL; - return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size); + return rproc_da_to_va(rproc, shdr->sh_addr - phdr->p_vaddr + phdr->p_paddr, shdr->sh_size); } const struct rproc_fw_ops rproc_elf_fw_ops = { Index: linux-3.12.24-rt38-xilinx/drivers/remoteproc/zynq_remoteproc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/remoteproc/zynq_remoteproc.c 2014-07-20 22:06:37.328289685 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Zynq Remote Processor driver + * + * Copyright (C) 2012 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2012 PetaLogix + * + * Based on origin OMAP Remote Processor driver + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/remoteproc.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> +#include <linux/smp.h> +#include <linux/irqchip/arm-gic.h> +#include <asm/outercache.h> +#include <asm/cacheflush.h> +#include <linux/slab.h> +#include <linux/cpu.h> + +#include "remoteproc_internal.h" + +extern int __cpuinit zynq_cpun_start(u32 address, int cpu); + +/* Module parameter */ +static char *firmware; + +/* Structure for storing IRQs */ +struct irq_list { + int irq; + struct list_head list; +}; + +/* Private data */ +struct zynq_rproc_pdata { + struct irq_list mylist; + struct rproc *rproc; + u32 ipino; + u32 vring0; + u32 vring1; + u32 mem_start; + u32 mem_end; +}; + +/* Store rproc for IPI handler */ +static struct platform_device *remoteprocdev; +static struct work_struct workqueue; + +static void handle_event(struct work_struct *work) +{ + struct zynq_rproc_pdata *local = platform_get_drvdata(remoteprocdev); + + flush_cache_all(); + outer_flush_range(local->mem_start, local->mem_end); + + if (rproc_vq_interrupt(local->rproc, 0) == IRQ_NONE) + dev_dbg(&remoteprocdev->dev, "no message found in vqid 0\n"); +} + +static void ipi_kick(void) +{ + dev_dbg(&remoteprocdev->dev, "KICK Linux because of pending message\n"); + schedule_work(&workqueue); +} + +static int zynq_rproc_start(struct rproc *rproc) +{ + struct device *dev = rproc->dev.parent; + struct platform_device *pdev = to_platform_device(dev); + struct zynq_rproc_pdata *local = platform_get_drvdata(pdev); + int ret; + + dev_dbg(dev, "%s\n", __func__); + INIT_WORK(&workqueue, handle_event); + + flush_cache_all(); + outer_flush_range(local->mem_start, local->mem_end); + + remoteprocdev = pdev; + ret = zynq_cpun_start(0, 1); + + return ret; +} + +/* kick a firmware */ +static void zynq_rproc_kick(struct rproc *rproc, int vqid) +{ + struct device *dev = rproc->dev.parent; + struct platform_device *pdev = to_platform_device(dev); + struct zynq_rproc_pdata *local = platform_get_drvdata(pdev); + + dev_dbg(dev, "KICK Firmware to start send messages vqid %d\n", vqid); + + /* Send swirq to firmware */ + if (!vqid) + gic_raise_softirq(cpumask_of(1), local->vring0); + else + gic_raise_softirq(cpumask_of(1), local->vring1); +} + +/* power off the remote processor */ +static int zynq_rproc_stop(struct rproc *rproc) +{ + dev_dbg(rproc->dev.parent, "%s\n", __func__); + + /* FIXME missing reset option */ + return 0; +} + +static struct rproc_ops zynq_rproc_ops = { + .start = zynq_rproc_start, + .stop = zynq_rproc_stop, + .kick = zynq_rproc_kick, +}; + +/* Just to detect bug if interrupt forwarding is broken */ +static irqreturn_t zynq_remoteproc_interrupt(int irq, void *dev_id) +{ + struct device *dev = dev_id; + + dev_err(dev, "GIC IRQ %d is not forwarded correctly\n", irq); + + /* + * MS: Calling this function doesn't need to be BUG + * especially for cases where firmware doesn't disable + * interrupts. In next probing can be som interrupts pending. + * The next scenario is for cases when you want to monitor + * non frequent interrupt through Linux kernel. Interrupt happen + * and it is forwarded to Linux which update own statistic + * in (/proc/interrupt) and forward it to firmware. + * + * gic_set_cpu(1, irq); - setup cpu1 as destination cpu + * gic_raise_softirq(cpumask_of(1), irq); - forward irq to firmware + */ + + gic_set_cpu(1, irq); + return IRQ_HANDLED; +} + +static void clear_irq(struct platform_device *pdev) +{ + struct list_head *pos, *q; + struct irq_list *tmp; + struct zynq_rproc_pdata *local = platform_get_drvdata(pdev); + + dev_info(&pdev->dev, "Deleting the irq_list\n"); + list_for_each_safe(pos, q, &local->mylist.list) { + tmp = list_entry(pos, struct irq_list, list); + free_irq(tmp->irq, &pdev->dev); + gic_set_cpu(0, tmp->irq); + list_del(pos); + kfree(tmp); + } +} + +static int zynq_remoteproc_probe(struct platform_device *pdev) +{ + const unsigned char *prop; + struct resource *res; /* IO mem resources */ + int ret = 0; + struct irq_list *tmp; + int count = 0; + struct zynq_rproc_pdata *local; + + ret = cpu_down(1); + /* EBUSY means CPU is already released */ + if (ret && (ret != -EBUSY)) { + dev_err(&pdev->dev, "Can't release cpu1\n"); + return -ENOMEM; + } + + local = devm_kzalloc(&pdev->dev, sizeof(struct zynq_rproc_pdata), + GFP_KERNEL); + if (!local) + return -ENOMEM; + + platform_set_drvdata(pdev, local); + + /* Declare memory for firmware */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid address\n"); + return -ENODEV; + } + + local->mem_start = res->start; + local->mem_end = res->end; + + /* Alloc phys addr from 0 to max_addr for firmware */ + ret = dma_declare_coherent_memory(&pdev->dev, local->mem_start, + local->mem_start, local->mem_end - local->mem_start + 1, + DMA_MEMORY_IO); + if (!ret) { + dev_err(&pdev->dev, "dma_declare_coherent_memory failed\n"); + goto dma_fault; + } + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret); + goto dma_fault; + } + + /* Init list for IRQs - it can be long list */ + INIT_LIST_HEAD(&local->mylist.list); + + /* Alloc IRQ based on DTS to be sure that no other driver will use it */ + while (1) { + int irq; + + irq = platform_get_irq(pdev, count++); + if (irq == -ENXIO) + break; + + tmp = kzalloc(sizeof(struct irq_list), GFP_KERNEL); + if (!tmp) { + dev_err(&pdev->dev, "Unable to alloc irq list\n"); + ret = -ENOMEM; + goto irq_fault; + } + + tmp->irq = irq; + + dev_dbg(&pdev->dev, "%d: Alloc irq: %d\n", count, tmp->irq); + + /* Allocating shared IRQs will ensure that any module will + * use these IRQs */ + ret = request_irq(tmp->irq, zynq_remoteproc_interrupt, 0, + dev_name(&pdev->dev), &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "IRQ %d already allocated\n", + tmp->irq); + goto irq_fault; + } + + /* + * MS: Here is place for detecting problem with firmware + * which doesn't work correctly with interrupts + * + * MS: Comment if you want to count IRQs on Linux + */ + gic_set_cpu(1, tmp->irq); + list_add(&(tmp->list), &(local->mylist.list)); + } + + /* Allocate free IPI number */ + ret = of_property_read_u32(pdev->dev.of_node, "ipino", &local->ipino); + if (ret < 0) { + dev_err(&pdev->dev, "unable to read property"); + goto irq_fault; + } + + ret = set_ipi_handler(local->ipino, ipi_kick, "Firmware kick"); + if (ret) { + dev_err(&pdev->dev, "IPI handler already registered\n"); + goto irq_fault; + } + + /* Read vring0 ipi number */ + ret = of_property_read_u32(pdev->dev.of_node, "vring0", &local->vring0); + if (ret < 0) { + dev_err(&pdev->dev, "unable to read property"); + goto ipi_fault; + } + + /* Read vring1 ipi number */ + ret = of_property_read_u32(pdev->dev.of_node, "vring1", &local->vring1); + if (ret < 0) { + dev_err(&pdev->dev, "unable to read property"); + goto ipi_fault; + } + + /* Module param firmware first */ + if (firmware) + prop = firmware; + else + prop = of_get_property(pdev->dev.of_node, "firmware", NULL); + + if (prop) { + dev_dbg(&pdev->dev, "Using firmware: %s\n", prop); + local->rproc = rproc_alloc(&pdev->dev, dev_name(&pdev->dev), + &zynq_rproc_ops, prop, sizeof(struct rproc)); + if (!local->rproc) { + dev_err(&pdev->dev, "rproc allocation failed\n"); + goto ipi_fault; + } + + ret = rproc_add(local->rproc); + if (ret) { + dev_err(&pdev->dev, "rproc registration failed\n"); + goto rproc_fault; + } + + return ret; + } else + ret = -ENODEV; + +rproc_fault: + rproc_put(local->rproc); +ipi_fault: + clear_ipi_handler(local->ipino); + +irq_fault: + clear_irq(pdev); + +dma_fault: + /* Cpu can't be power on - for example in nosmp mode */ + ret |= cpu_up(1); + if (ret) + dev_err(&pdev->dev, "Can't power on cpu1 %d\n", ret); + + return ret; +} + +static int zynq_remoteproc_remove(struct platform_device *pdev) +{ + struct zynq_rproc_pdata *local = platform_get_drvdata(pdev); + u32 ret; + + dev_info(&pdev->dev, "%s\n", __func__); + + dma_release_declared_memory(&pdev->dev); + + clear_ipi_handler(local->ipino); + clear_irq(pdev); + + rproc_del(local->rproc); + rproc_put(local->rproc); + + /* Cpu can't be power on - for example in nosmp mode */ + ret = cpu_up(1); + if (ret) + dev_err(&pdev->dev, "Can't power on cpu1 %d\n", ret); + + return 0; +} + +/* Match table for OF platform binding */ +static struct of_device_id zynq_remoteproc_match[] = { + { .compatible = "xlnx,zynq_remoteproc", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, zynq_remoteproc_match); + +static struct platform_driver zynq_remoteproc_driver = { + .probe = zynq_remoteproc_probe, + .remove = zynq_remoteproc_remove, + .driver = { + .name = "zynq_remoteproc", + .owner = THIS_MODULE, + .of_match_table = zynq_remoteproc_match, + }, +}; +module_platform_driver(zynq_remoteproc_driver); + +module_param(firmware, charp, 0); +MODULE_PARM_DESC(firmware, "Override the firmware image name. Default value in DTS."); + +MODULE_AUTHOR("Michal Simek <monstr@monstr.eu"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Zynq remote processor control driver"); Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/host/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/host/Kconfig 2014-07-20 22:06:37.339289504 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +config OMAP_RPMSG + tristate "OMAP virtio-based remote processor messaging support" + depends on ARCH_OMAP4 && OMAP_REMOTE_PROC + select CONFIG_OMAP_MBOX_FWK + select RPMSG + help + Say Y if you want to enable OMAP's virtio-based remote-processor + messaging, currently only available on OMAP4. This is required + for offloading cpu-intensive and/or latency-sensitive tasks to + the remote on-chip M3s or C64x+ dsp, usually used by multimedia + frameworks. Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/host/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/host/Makefile 2014-07-20 22:06:37.345289405 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ +obj-$(CONFIG_OMAP_RPMSG) += omap_rpmsg.o Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/host/omap_rpmsg.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/host/omap_rpmsg.c 2014-07-20 22:06:37.355289240 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Remote processor messaging transport (OMAP platform-specific bits) + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + * + * 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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/init.h> +#include <linux/virtio.h> +#include <linux/virtio_config.h> +#include <linux/virtio_ids.h> +#include <linux/virtio_ring.h> +#include <linux/rpmsg.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/notifier.h> +#include <linux/remoteproc.h> + +#include <plat/mailbox.h> +#include <plat/dsp.h> + +#include "omap_rpmsg.h" + +/** + * struct omap_rpmsg_vproc - omap's virtio remote processor state + * @vdev: virtio device + * @vring: phys address of two vrings; first one used for rx, 2nd one for tx + * @buf_paddr: physical address of the IPC buffer region + * @buf_size: size of IPC buffer region + * @buf_mapped: kernel (ioremap'ed) address of IPC buffer region + * @mbox_name: name of omap mailbox device to use with this vproc + * @rproc_name: name of remote proc device to use with this vproc + * @mbox: omap mailbox handle + * @rproc: remoteproc handle + * @nb: notifier block that will be invoked on inbound mailbox messages + * @vq: virtio's virtqueues + * @base_vq_id: index of first virtqueue that belongs to this vproc + * @num_of_vqs: number of virtqueues this vproc owns + * @static_chnls: table of static channels for this vproc + */ +struct omap_rpmsg_vproc { + struct virtio_device vdev; + unsigned int vring[2]; /* mpu owns first vring, ipu owns the 2nd */ + unsigned int buf_paddr; + unsigned int buf_size; /* size must be page-aligned */ + void *buf_mapped; + char *mbox_name; + char *rproc_name; + struct omap_mbox *mbox; + struct rproc *rproc; + struct notifier_block nb; + struct virtqueue *vq[2]; + int base_vq_id; + int num_of_vqs; + struct rpmsg_channel_info *static_chnls; +}; + +#define to_omap_vproc(vd) container_of(vd, struct omap_rpmsg_vproc, vdev) + +/** + * struct omap_rpmsg_vq_info - virtqueue state + * @num: number of buffers supported by the vring + * @vq_id: a unique index of this virtqueue + * @addr: address where the vring is mapped onto + * @vproc: the virtual remote processor state + * + * Such a struct will be maintained for every virtqueue we're + * using to communicate with the remote processor + */ +struct omap_rpmsg_vq_info { + __u16 num; + __u16 vq_id; + void *addr; + struct omap_rpmsg_vproc *vproc; +}; + +/* + * For now, allocate 256 buffers of 512 bytes for each side. each buffer + * will then have 16B for the msg header and 496B for the payload. + * This will require a total space of 256KB for the buffers themselves, and + * 3 pages for every vring (the size of the vring depends on the number of + * buffers it supports). + */ +#define RPMSG_NUM_BUFS (512) +#define RPMSG_BUF_SIZE (512) +#define RPMSG_BUFS_SPACE (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE) + +/* + * The alignment between the consumer and producer parts of the vring. + * Note: this is part of the "wire" protocol. If you change this, you need + * to update your BIOS image as well + */ +#define RPMSG_VRING_ALIGN (4096) + +/* With 256 buffers, our vring will occupy 3 pages */ +#define RPMSG_RING_SIZE ((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \ + RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE) + +/* The total IPC space needed to communicate with a remote processor */ +#define RPMSG_IPC_MEM (RPMSG_BUFS_SPACE + 2 * RPMSG_RING_SIZE) + +/* + * Provide rpmsg core with platform-specific configuration. + * Since user data is at stake here, bugs can't be tolerated. hence + * the BUG_ON approach on invalid lengths. + * + * For more info on these configuration requests, see enum + * rpmsg_platform_requests. + */ +static void omap_rpmsg_get(struct virtio_device *vdev, unsigned int request, + void *buf, unsigned len) +{ + struct omap_rpmsg_vproc *vproc = to_omap_vproc(vdev); + int tmp; + + switch (request) { + case VPROC_BUF_ADDR: + BUG_ON(len != sizeof(vproc->buf_mapped)); + memcpy(buf, &vproc->buf_mapped, len); + break; + case VPROC_BUF_PADDR: + BUG_ON(len != sizeof(vproc->buf_paddr)); + memcpy(buf, &vproc->buf_paddr, len); + break; + case VPROC_BUF_NUM: + BUG_ON(len != sizeof(tmp)); + tmp = RPMSG_NUM_BUFS; + memcpy(buf, &tmp, len); + break; + case VPROC_BUF_SZ: + BUG_ON(len != sizeof(tmp)); + tmp = RPMSG_BUF_SIZE; + memcpy(buf, &tmp, len); + break; + case VPROC_STATIC_CHANNELS: + BUG_ON(len != sizeof(vproc->static_chnls)); + memcpy(buf, &vproc->static_chnls, len); + break; + default: + dev_err(&vdev->dev, "invalid request: %d\n", request); + } +} + +/* kick the remote processor, and let it know which virtqueue to poke at */ +static void omap_rpmsg_notify(struct virtqueue *vq) +{ + struct omap_rpmsg_vq_info *rpvq = vq->priv; + int ret; + + pr_debug("sending mailbox msg: %d\n", rpvq->vq_id); + /* send the index of the triggered virtqueue in the mailbox payload */ + ret = omap_mbox_msg_send(rpvq->vproc->mbox, rpvq->vq_id); + if (ret) + pr_err("ugh, omap_mbox_msg_send() failed: %d\n", ret); +} + +/** + * omap_rpmsg_mbox_callback() - inbound mailbox message handler + * @this: notifier block + * @index: unused + * @data: mailbox payload + * + * This handler is invoked by omap's mailbox driver whenever a mailbox + * message is received. Usually, the mailbox payload simply contains + * the index of the virtqueue that is kicked by the remote processor, + * and we let virtio handle it. + * + * In addition to virtqueue indices, we also have some out-of-band values + * that indicates different events. Those values are deliberately very + * big so they don't coincide with virtqueue indices. Moreover, + * they are rarely used, if used at all, and their necessity should + * be revisited. + */ +static int omap_rpmsg_mbox_callback(struct notifier_block *this, + unsigned long index, void *data) +{ + mbox_msg_t msg = (mbox_msg_t) data; + struct omap_rpmsg_vproc *vproc; + + vproc = container_of(this, struct omap_rpmsg_vproc, nb); + + pr_debug("mbox msg: 0x%x\n", msg); + + switch (msg) { + case RP_MBOX_CRASH: + pr_err("%s has just crashed !\n", vproc->rproc_name); + /* todo: smarter error handling here */ + break; + case RP_MBOX_ECHO_REPLY: + pr_info("received echo reply from %s !\n", vproc->rproc_name); + break; + case RP_MBOX_PENDING_MSG: + /* + * a new inbound message is waiting in our rx vring (1st vring). + * Let's pretend the message explicitly contained the rx vring + * index number and handle it generically. + */ + msg = vproc->base_vq_id; + /* intentional fall-through */ + default: + /* ignore vq indices which are clearly not for us */ + if (msg < vproc->base_vq_id) + break; + + msg -= vproc->base_vq_id; + + /* + * Currently both PENDING_MSG and explicit-virtqueue-index + * messaging are supported. + * Whatever approach is taken, at this point 'msg' contains + * the index of the vring which was just triggered. + */ + if (msg < vproc->num_of_vqs) + vring_interrupt(msg, vproc->vq[msg]); + } + + return NOTIFY_DONE; +} + +/* prepare a virtqueue */ +static struct virtqueue *rp_find_vq(struct virtio_device *vdev, + unsigned index, + void (*callback)(struct virtqueue *vq), + const char *name) +{ + struct omap_rpmsg_vproc *vproc = to_omap_vproc(vdev); + struct omap_rpmsg_vq_info *rpvq; + struct virtqueue *vq; + int err; + + rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL); + if (!rpvq) + return ERR_PTR(-ENOMEM); + + /* ioremap'ing normal memory, so we cast away sparse's complaints */ + rpvq->addr = (__force void *) ioremap_nocache(vproc->vring[index], + RPMSG_RING_SIZE); + if (!rpvq->addr) { + err = -ENOMEM; + goto free_rpvq; + } + + memset(rpvq->addr, 0, RPMSG_RING_SIZE); + + pr_debug("vring%d: phys 0x%x, virt 0x%x\n", index, vproc->vring[index], + (unsigned int) rpvq->addr); + + vq = vring_new_virtqueue(RPMSG_NUM_BUFS / 2, RPMSG_VRING_ALIGN, vdev, + rpvq->addr, omap_rpmsg_notify, callback, name); + if (!vq) { + pr_err("vring_new_virtqueue failed\n"); + err = -ENOMEM; + goto unmap_vring; + } + + vproc->vq[index] = vq; + vq->priv = rpvq; + /* unique id for this virtqueue */ + rpvq->vq_id = vproc->base_vq_id + index; + rpvq->vproc = vproc; + + return vq; + +unmap_vring: + /* iounmap normal memory, so make sparse happy */ + iounmap((__force void __iomem *) rpvq->addr); +free_rpvq: + kfree(rpvq); + return ERR_PTR(err); +} + +static void omap_rpmsg_del_vqs(struct virtio_device *vdev) +{ + struct virtqueue *vq, *n; + struct omap_rpmsg_vproc *vproc = to_omap_vproc(vdev); + + if (vproc->rproc) + rproc_put(vproc->rproc); + + if (vproc->mbox) + omap_mbox_put(vproc->mbox, &vproc->nb); + + if (vproc->buf_mapped) + /* iounmap normal memory, so make sparse happy */ + iounmap((__force void __iomem *)vproc->buf_mapped); + + list_for_each_entry_safe(vq, n, &vdev->vqs, list) { + struct omap_rpmsg_vq_info *rpvq = vq->priv; + vring_del_virtqueue(vq); + /* iounmap normal memory, so make sparse happy */ + iounmap((__force void __iomem *) rpvq->addr); + kfree(rpvq); + } +} + +static int omap_rpmsg_find_vqs(struct virtio_device *vdev, unsigned nvqs, + struct virtqueue *vqs[], + vq_callback_t *callbacks[], + const char *names[]) +{ + struct omap_rpmsg_vproc *vproc = to_omap_vproc(vdev); + int i, err; + + /* we maintain two virtqueues per remote processor (for RX and TX) */ + if (nvqs != 2) + return -EINVAL; + + for (i = 0; i < nvqs; ++i) { + vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]); + if (IS_ERR(vqs[i])) { + err = PTR_ERR(vqs[i]); + goto error; + } + } + + vproc->num_of_vqs = nvqs; + + /* ioremap'ing normal memory, so we cast away sparse's complaints */ + vproc->buf_mapped = (__force void *) ioremap_nocache(vproc->buf_paddr, + vproc->buf_size); + if (!vproc->buf_mapped) { + pr_err("ioremap failed\n"); + err = -ENOMEM; + goto error; + } + + /* for now, use mailbox's notifiers. later that can be optimized */ + vproc->nb.notifier_call = omap_rpmsg_mbox_callback; + vproc->mbox = omap_mbox_get(vproc->mbox_name, &vproc->nb); + if (IS_ERR(vproc->mbox)) { + pr_err("failed to get mailbox %s\n", vproc->mbox_name); + err = -EINVAL; + goto error; + } + + pr_debug("buf: phys 0x%x, virt 0x%x\n", vproc->buf_paddr, + (unsigned int) vproc->buf_mapped); + + /* tell the M3 we're ready (so M3 will know we're sane) */ + err = omap_mbox_msg_send(vproc->mbox, RP_MBOX_READY); + if (err) { + pr_err("ugh, omap_mbox_msg_send() failed: %d\n", err); + goto error; + } + + /* send it the physical address of the vrings + IPC buffer */ + err = omap_mbox_msg_send(vproc->mbox, (mbox_msg_t) vproc->buf_paddr); + if (err) { + pr_err("ugh, omap_mbox_msg_send() failed: %d\n", err); + goto error; + } + + /* ping the remote processor. this is only for sanity-sake; + * there is no functional effect whatsoever */ + err = omap_mbox_msg_send(vproc->mbox, RP_MBOX_ECHO_REQUEST); + if (err) { + pr_err("ugh, omap_mbox_msg_send() failed: %d\n", err); + goto error; + } + + /* now load the firmware, and boot the M3 */ + vproc->rproc = rproc_get(vproc->rproc_name); + if (!vproc->rproc) { + pr_err("failed to get rproc %s\n", vproc->rproc_name); + err = -EINVAL; + goto error; + } + + return 0; + +error: + omap_rpmsg_del_vqs(vdev); + return err; +} + +/* + * should be nice to add firmware support for these handlers. + * for now provide them so virtio doesn't crash + */ +static u8 omap_rpmsg_get_status(struct virtio_device *vdev) +{ + return 0; +} + +static void omap_rpmsg_set_status(struct virtio_device *vdev, u8 status) +{ + dev_dbg(&vdev->dev, "new status: %d\n", status); +} + +static void omap_rpmsg_reset(struct virtio_device *vdev) +{ + dev_dbg(&vdev->dev, "reset !\n"); +} + +static u32 omap_rpmsg_get_features(struct virtio_device *vdev) +{ + /* for now, use hardcoded bitmap. later this should be provided + * by the firmware itself */ + return 1 << VIRTIO_RPMSG_F_NS; +} + +static void omap_rpmsg_finalize_features(struct virtio_device *vdev) +{ + /* Give virtio_ring a chance to accept features */ + vring_transport_features(vdev); +} + +static void omap_rpmsg_vproc_release(struct device *dev) +{ + /* this handler is provided so driver core doesn't yell at us */ +} + +static struct virtio_config_ops omap_rpmsg_config_ops = { + .get_features = omap_rpmsg_get_features, + .finalize_features = omap_rpmsg_finalize_features, + .get = omap_rpmsg_get, + .find_vqs = omap_rpmsg_find_vqs, + .del_vqs = omap_rpmsg_del_vqs, + .reset = omap_rpmsg_reset, + .set_status = omap_rpmsg_set_status, + .get_status = omap_rpmsg_get_status, +}; + +/* + * Populating the static channels table. + * + * This is not always required, and the example below just demonstrates + * how to populate it with a static server channel. + * + * This example should be moved to Documentation/rpmsh.h before merging. + * + * For more info, see 'struct rpmsg_channel_info'. + */ +static struct rpmsg_channel_info omap_ipuc0_static_chnls[] = { + RMSG_SERVER_CHNL("rpmsg-server-sample", 137), + { }, +}; + +static struct rpmsg_channel_info omap_ipuc1_static_chnls[] = { + { }, +}; + +static struct omap_rpmsg_vproc omap_rpmsg_vprocs[] = { + /* ipu_c0's rpmsg backend */ + { + .vdev.id.device = VIRTIO_ID_RPMSG, + .vdev.config = &omap_rpmsg_config_ops, + .mbox_name = "mailbox-1", + .rproc_name = "ipu", + /* core 0 is using indices 0 + 1 for its vqs */ + .base_vq_id = 0, + .static_chnls = omap_ipuc0_static_chnls, + }, + /* ipu_c1's rpmsg backend */ + { + .vdev.id.device = VIRTIO_ID_RPMSG, + .vdev.config = &omap_rpmsg_config_ops, + .mbox_name = "mailbox-1", + .rproc_name = "ipu", + /* core 1 is using indices 2 + 3 for its vqs */ + .base_vq_id = 2, + .static_chnls = omap_ipuc1_static_chnls, + }, +}; + +static int __init omap_rpmsg_ini(void) +{ + int i, ret = 0; + /* + * This whole area generally needs some rework. + * E.g, consider using dma_alloc_coherent for the IPC buffers and + * vrings, use CMA, etc... + */ + phys_addr_t paddr = omap_dsp_get_mempool_base(); + phys_addr_t psize = omap_dsp_get_mempool_size(); + + /* + * allocate carverout memory for the buffers and vring, and + * then register the vproc virtio device + */ + for (i = 0; i < ARRAY_SIZE(omap_rpmsg_vprocs); i++) { + struct omap_rpmsg_vproc *vproc = &omap_rpmsg_vprocs[i]; + + if (psize < RPMSG_IPC_MEM) { + pr_err("out of carveout memory: %d (%d)\n", psize, i); + return -ENOMEM; + } + + vproc->buf_paddr = paddr; + vproc->buf_size = RPMSG_BUFS_SPACE; + vproc->vring[0] = paddr + RPMSG_BUFS_SPACE; + vproc->vring[1] = paddr + RPMSG_BUFS_SPACE + RPMSG_RING_SIZE; + + paddr += RPMSG_IPC_MEM; + psize -= RPMSG_IPC_MEM; + + pr_debug("vproc%d: buf 0x%x, vring0 0x%x, vring1 0x%x\n", i, + vproc->buf_paddr, vproc->vring[0], vproc->vring[1]); + + vproc->vdev.dev.release = omap_rpmsg_vproc_release; + + ret = register_virtio_device(&vproc->vdev); + if (ret) { + pr_err("failed to register vproc: %d\n", ret); + break; + } + } + + return ret; +} +module_init(omap_rpmsg_ini); + +static void __exit omap_rpmsg_fini(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(omap_rpmsg_vprocs); i++) { + struct omap_rpmsg_vproc *vproc = &omap_rpmsg_vprocs[i]; + + unregister_virtio_device(&vproc->vdev); + } +} +module_exit(omap_rpmsg_fini); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("OMAP Remote processor messaging virtio device"); Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/host/omap_rpmsg.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/host/omap_rpmsg.h 2014-07-20 22:06:37.366289058 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Remote processor messaging + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Texas Instruments nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _OMAP_RPMSG_H +#define _OMAP_RPMSG_H + +/* + * enum - Predefined Mailbox Messages + * + * @RP_MBOX_READY: informs the M3's that we're up and running. this is + * part of the init sequence sent that the M3 expects to see immediately + * after it is booted. + * + * @RP_MBOX_PENDING_MSG: informs the receiver that there is an inbound + * message waiting in its own receive-side vring. please note that currently + * this message is optional: alternatively, one can explicitly send the index + * of the triggered virtqueue itself. the preferred approach will be decided + * as we progress and experiment with those two different approaches. + * + * @RP_MBOX_CRASH: this message is sent if BIOS crashes + * + * @RP_MBOX_ECHO_REQUEST: a mailbox-level "ping" message. + * + * @RP_MBOX_ECHO_REPLY: a mailbox-level reply to a "ping" + * + * @RP_MBOX_ABORT_REQUEST: a "please crash" request, used for testing the + * recovery mechanism (to some extent). + */ +enum omap_rp_mbox_messages { + RP_MBOX_READY = 0xFFFFFF00, + RP_MBOX_PENDING_MSG = 0xFFFFFF01, + RP_MBOX_CRASH = 0xFFFFFF02, + RP_MBOX_ECHO_REQUEST = 0xFFFFFF03, + RP_MBOX_ECHO_REPLY = 0xFFFFFF04, + RP_MBOX_ABORT_REQUEST = 0xFFFFFF05, +}; + +#endif /* _OMAP_RPMSG_H */ Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/rpmsg/Kconfig 2014-07-20 22:05:50.206067116 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/Kconfig 2014-07-20 22:06:37.373288943 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:9 @ select VIRTIO select VIRTUALIZATION +config RPMSG_SERVER_SAMPLE + tristate "An rpmsg server sample" + depends on RPMSG + ---help--- + This is just a sample server driver for the rpmsg bus. + Say either Y or M. You know you want to. + +config RPMSG_OMX + tristate "rpmsg OMX driver" + depends on RPMSG + ---help--- + An rpmsg driver that exposes OMX API to user space, in order to + allow multimedia applications to offload OMX processing to + remote processors. + + If unsure, say N. + +config RPMSG_FREERTOS_STAT + tristate "An FreeRTOS statistic" + depends on RPMSG + ---help--- + This is just a sample to get statistic from FreeRTOS. + Say either Y or M. You know you want to. + +source "drivers/rpmsg/host/Kconfig" + endmenu Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/rpmsg/Makefile 2014-07-20 22:05:50.205067133 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/Makefile 2014-07-20 22:06:37.382288794 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2 @ obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o +obj-$(CONFIG_RPMSG_SERVER_SAMPLE) += rpmsg_server_sample.o +obj-$(CONFIG_RPMSG_FREERTOS_STAT) += rpmsg_freertos_statistic.o +obj-$(CONFIG_RPMSG_OMX) += rpmsg_omx.o +obj-$(CONFIG_RPMSG) += host/ Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/rpmsg_freertos_statistic.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/rpmsg_freertos_statistic.c 2014-07-20 22:06:37.392288629 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Remote processor messaging transport - sample server driver + * + * Copyright (C) 2012 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2012 PetaLogix + * + * Based on original OMX driver made by: + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/rpmsg.h> +#include <linux/slab.h> +#include <linux/cdev.h> +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/scatterlist.h> +#include <linux/idr.h> +#include <linux/poll.h> +#include <linux/jiffies.h> +#include <linux/mutex.h> +#include <linux/wait.h> +#include <linux/skbuff.h> + +struct rpmsg_service { + struct cdev cdev; + struct rpmsg_channel *rpdev; + struct device *dev; + int major; + int minor; +}; + +struct rpmsg_instance { + struct rpmsg_endpoint *ept; + struct rpmsg_service *service; + struct sk_buff_head queue; + struct mutex lock; + wait_queue_head_t readq; +}; + +static void rpmsg_cb(struct rpmsg_channel *rpdev, void *data, int len, + void *priv, u32 src) +{ + static int rx_count; + struct sk_buff *skb; + char *skbdata; + /* priv is setup only for new endpoints */ + struct rpmsg_instance *instance = priv; + + dev_dbg(&rpdev->dev, "incoming msg %d (src: 0x%x) len %d\n", + ++rx_count, src, len); + + print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 32, 1, + data, len, true); + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) { + dev_err(&rpdev->dev, "alloc_skb err: %u\n", len); + return; + } + + skbdata = skb_put(skb, len); + memcpy(skbdata, data, len); + mutex_lock(&instance->lock); + skb_queue_tail(&instance->queue, skb); + mutex_unlock(&instance->lock); + /* wake up any blocking processes, waiting for new data */ + wake_up_interruptible(&instance->readq); +} + +static ssize_t rpmsg_read(struct file *filp, char __user *buf, + size_t len, loff_t *offp) +{ + struct rpmsg_instance *instance = filp->private_data; + struct sk_buff *skb; + int use; + + if (mutex_lock_interruptible(&instance->lock)) + return -ERESTARTSYS; + + /* nothing to read ? */ + if (skb_queue_empty(&instance->queue)) { + mutex_unlock(&instance->lock); + /* non-blocking requested ? return now */ + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + /* otherwise block, and wait for data */ + if (wait_event_interruptible(instance->readq, + !skb_queue_empty(&instance->queue))) + return -ERESTARTSYS; + if (mutex_lock_interruptible(&instance->lock)) + return -ERESTARTSYS; + } + + skb = skb_dequeue(&instance->queue); + if (!skb) { + printk("err is rmpsg_omx racy ?\n"); + return -EFAULT; + } + + mutex_unlock(&instance->lock); + + use = min(len, skb->len); + if (copy_to_user(buf, skb->data, use)) + use = -EFAULT; + + kfree_skb(skb); + return use; +} + +/* MAX number of bytes in one packet - depend on resource table */ +#define CHANNEL_SIZE 512 + +static ssize_t rpmsg_write(struct file *filp, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct rpmsg_instance *instance = filp->private_data; + struct rpmsg_service *service = instance->service; + int err; + char kbuf[CHANNEL_SIZE]; + + len = len < CHANNEL_SIZE ? len : CHANNEL_SIZE; + if (copy_from_user(kbuf, ubuf, len)) + return -EMSGSIZE; + + err = rpmsg_send_offchannel(service->rpdev, instance->ept->addr, + service->rpdev->dst, kbuf, len); + if (err) { + dev_err(service->dev, "rpmsg_send failed: %d\n", err); + return err; + } + + return len; +} + +static int rpmsg_open(struct inode *inode, struct file *filp) +{ + struct rpmsg_instance *instance; + struct rpmsg_service *service; + + service = container_of(inode->i_cdev, struct rpmsg_service, cdev); + + instance = kzalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) + return -ENOMEM; + + instance->service = service; + + mutex_init(&instance->lock); + skb_queue_head_init(&instance->queue); + init_waitqueue_head(&instance->readq); + + filp->private_data = instance; + + /* assign a new, unique, local address and associate omx with it */ + instance->ept = rpmsg_create_ept(service->rpdev, rpmsg_cb, instance, + RPMSG_ADDR_ANY); + if (!instance->ept) { + dev_err(service->dev, "create ept failed\n"); + kfree(instance); + return -ENOMEM; + } + + dev_dbg(service->dev, "New endpoint at %d\n", instance->ept->addr); + return 0; +} + +typedef enum { + CLEAR = 0, + START, + STOP, + CLONE, + GET, + QUIT, + STATE_MASK = 0xF, +} message_state; + +static int rpmsg_release(struct inode *inode, struct file *filp) +{ + int err, temp; + struct rpmsg_instance *instance = filp->private_data; + struct rpmsg_service *service = instance->service; + + /* Place for sending any STOP message or announce driver + * that connection from user-space is lost */ + temp = QUIT; + err = rpmsg_send_offchannel(service->rpdev, instance->ept->addr, + service->rpdev->dst, &temp, sizeof(temp)); + if (err) { + dev_err(service->dev, "rpmsg_send failed: %d\n", err); + /* No return here because driver wants to quit */ + } + + /* Discard all SKBs */ + while (!skb_queue_empty(&instance->queue)) { + struct sk_buff *skb; + skb = skb_dequeue(&instance->queue); + kfree_skb(skb); + } + + rpmsg_destroy_ept(instance->ept); /* Also endpoint */ + kfree(instance); + return 0; +} + + +static const struct file_operations rpmsg_fops = { + .open = rpmsg_open, + .release = rpmsg_release, + .read = rpmsg_read, + .write = rpmsg_write, + .owner = THIS_MODULE, +}; + +static struct class *rpmsg_class; +static dev_t rpmsg_dev; +static u32 minor; + +static int rpmsg_sample_probe(struct rpmsg_channel *rpdev) +{ + int ret; + struct rpmsg_service *service; + + service = kzalloc(sizeof(*service), GFP_KERNEL); + if (!service) { + dev_err(&rpdev->dev, "kzalloc failed\n"); + return -ENOMEM; + } + + service->rpdev = rpdev; + service->major = MAJOR(rpmsg_dev); + service->minor = minor++; + + cdev_init(&service->cdev, &rpmsg_fops); + service->cdev.owner = THIS_MODULE; + ret = cdev_add(&service->cdev, + MKDEV(service->major, service->minor), 1); + if (ret) { + dev_err(&rpdev->dev, "cdev_add failed: %d\n", ret); + goto free; + } + + service->dev = device_create(rpmsg_class, &rpdev->dev, + MKDEV(service->major, service->minor), NULL, + "rpmsg%d", service->minor); + if (IS_ERR(service->dev)) { + dev_err(&rpdev->dev, "device_create failed: %d\n", ret); + goto clean_cdev; + } + dev_set_drvdata(&rpdev->dev, service); + + dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n", + rpdev->src, rpdev->dst); + return 0; + +clean_cdev: + cdev_del(&service->cdev); +free: + kfree(service); + return ret; +} + +static void rpmsg_sample_remove(struct rpmsg_channel *rpdev) +{ + struct rpmsg_service *service = dev_get_drvdata(&rpdev->dev); + int major = MAJOR(rpmsg_dev); + + device_destroy(rpmsg_class, MKDEV(major, service->minor)); + cdev_del(&service->cdev); + kfree(service); +} + +static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, + int len, void *priv, u32 src) +{ + dev_info(&rpdev->dev, "ORIGIN callback function without priv\n"); +} + +static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = { + { .name = "rpmsg-timer-statistic" }, + { }, +}; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table); + +static struct rpmsg_driver rpmsg_sample_server = { + .drv.name = KBUILD_MODNAME, + .drv.owner = THIS_MODULE, + .id_table = rpmsg_driver_sample_id_table, + .probe = rpmsg_sample_probe, + .callback = rpmsg_sample_cb, + .remove = rpmsg_sample_remove, +}; + +#define MAX_DEVICES 8 + +static int __init init(void) +{ + int ret; + + /* Allocate 0-8 char devices */ + ret = alloc_chrdev_region(&rpmsg_dev, 0, MAX_DEVICES, + KBUILD_MODNAME); + if (ret) { + pr_err("alloc_chrdev_region failed: %d\n", ret); + goto out; + } + + /* Create class for this device */ + rpmsg_class = class_create(THIS_MODULE, KBUILD_MODNAME); + if (IS_ERR(rpmsg_class)) { + ret = PTR_ERR(rpmsg_class); + pr_err("class_create failed: %d\n", ret); + goto unreg_region; + } + + return register_rpmsg_driver(&rpmsg_sample_server); + +unreg_region: + unregister_chrdev_region(rpmsg_dev, MAX_DEVICES); +out: + return ret; +} + +static void __exit fini(void) +{ + unregister_rpmsg_driver(&rpmsg_sample_server); + class_destroy(rpmsg_class); + unregister_chrdev_region(rpmsg_dev, MAX_DEVICES); +} +module_init(init); +module_exit(fini); + +MODULE_DESCRIPTION("Virtio remote processor messaging sample driver"); +MODULE_AUTHOR("Michal Simek <monstr@monstr.eu"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/rpmsg_omx.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/rpmsg_omx.c 2014-07-20 22:06:37.401288481 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * OMX offloading remote processor driver + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + * + * 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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/idr.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/cdev.h> +#include <linux/jiffies.h> +#include <linux/mutex.h> +#include <linux/wait.h> +#include <linux/skbuff.h> +#include <linux/sched.h> +#include <linux/rpmsg.h> +#include <linux/rpmsg_omx.h> + +/* maximum OMX devices this driver can handle */ +#define MAX_OMX_DEVICES 8 + +struct rpmsg_omx_service { + struct cdev cdev; + struct device *dev; + struct rpmsg_channel *rpdev; + int minor; +}; + +struct rpmsg_omx_instance { + struct rpmsg_omx_service *omxserv; + struct sk_buff_head queue; + struct mutex lock; + wait_queue_head_t readq; + struct completion reply_arrived; + struct rpmsg_endpoint *ept; + u32 dst; + int state; +}; + +static struct class *rpmsg_omx_class; +static dev_t rpmsg_omx_dev; + +/* store all remote omx connection services (usually one per remoteproc) */ +static DEFINE_IDR(rpmsg_omx_services); +static DEFINE_SPINLOCK(rpmsg_omx_services_lock); + +static void rpmsg_omx_cb(struct rpmsg_channel *rpdev, void *data, int len, + void *priv, u32 src) +{ + struct omx_msg_hdr *hdr = data; + struct rpmsg_omx_instance *omx = priv; + struct omx_conn_rsp *rsp; + struct sk_buff *skb; + char *skbdata; + + if (len < sizeof(*hdr) || hdr->len < len - sizeof(*hdr)) { + dev_warn(&rpdev->dev, "%s: truncated message\n", __func__); + return; + } + + dev_dbg(&rpdev->dev, "%s: incoming msg src 0x%x type %d len %d\n", + __func__, src, hdr->type, hdr->len); + print_hex_dump(KERN_DEBUG, "rpmsg_omx RX: ", DUMP_PREFIX_NONE, 16, 1, + data, len, true); + + switch (hdr->type) { + case OMX_CONN_RSP: + if (hdr->len < sizeof(*rsp)) { + dev_warn(&rpdev->dev, "incoming empty response msg\n"); + break; + } + rsp = (struct omx_conn_rsp *) hdr->data; + dev_info(&rpdev->dev, "conn rsp: status %d addr %d\n", + rsp->status, rsp->addr); + omx->dst = rsp->addr; + if (rsp->status) + omx->state = OMX_FAIL; + else + omx->state = OMX_CONNECTED; + complete(&omx->reply_arrived); + break; + case OMX_RAW_MSG: + skb = alloc_skb(hdr->len, GFP_KERNEL); + if (!skb) { + dev_err(&rpdev->dev, "alloc_skb err: %u\n", hdr->len); + break; + } + skbdata = skb_put(skb, hdr->len); + memcpy(skbdata, hdr->data, hdr->len); + + mutex_lock(&omx->lock); + skb_queue_tail(&omx->queue, skb); + mutex_unlock(&omx->lock); + /* wake up any blocking processes, waiting for new data */ + wake_up_interruptible(&omx->readq); + break; + default: + dev_warn(&rpdev->dev, "unexpected msg type: %d\n", hdr->type); + break; + } +} + +static int rpmsg_omx_connect(struct rpmsg_omx_instance *omx, char *omxname) +{ + struct omx_msg_hdr *hdr; + struct omx_conn_req *payload; + struct rpmsg_omx_service *omxserv = omx->omxserv; + char connect_msg[sizeof(*hdr) + sizeof(*payload)] = { 0 }; + int ret; + + if (omx->state == OMX_CONNECTED) { + dev_dbg(omxserv->dev, "endpoint already connected\n"); + return -EISCONN; + } + + hdr = (struct omx_msg_hdr *)connect_msg; + hdr->type = OMX_CONN_REQ; + hdr->flags = 0; + hdr->len = strlen(omxname) + 1; + payload = (struct omx_conn_req *)hdr->data; + strcpy(payload->name, omxname); + + init_completion(&omx->reply_arrived); + + /* send a conn req to the remote OMX connection service. use + * the new local address that was just allocated by ->open */ + ret = rpmsg_send_offchannel(omxserv->rpdev, omx->ept->addr, + omxserv->rpdev->dst, connect_msg, sizeof(connect_msg)); + if (ret) { + dev_err(omxserv->dev, "rpmsg_send failed: %d\n", ret); + return ret; + } + + /* wait until a connection reply arrives or 5 seconds elapse */ + ret = wait_for_completion_interruptible_timeout(&omx->reply_arrived, + msecs_to_jiffies(5000)); + if (omx->state == OMX_CONNECTED) + return 0; + + if (omx->state == OMX_FAIL) + return -ENXIO; + + if (ret) { + dev_err(omxserv->dev, "premature wakeup: %d\n", ret); + return -EIO; + } + + return -ETIMEDOUT; +} + +static +long rpmsg_omx_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct rpmsg_omx_instance *omx = filp->private_data; + struct rpmsg_omx_service *omxserv = omx->omxserv; + char buf[48]; + int ret = 0; + + dev_dbg(omxserv->dev, "%s: cmd %d, arg 0x%lx\n", __func__, cmd, arg); + + if (_IOC_TYPE(cmd) != OMX_IOC_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > OMX_IOC_MAXNR) + return -ENOTTY; + + switch (cmd) { + case OMX_IOCCONNECT: + ret = copy_from_user(buf, (char __user *) arg, sizeof(buf)); + if (ret) { + dev_err(omxserv->dev, "copy_from_user fail: %d\n", ret); + ret = -EFAULT; + break; + } + /* make sure user input is null terminated */ + buf[sizeof(buf) - 1] = '\0'; + ret = rpmsg_omx_connect(omx, buf); + break; + default: + dev_warn(omxserv->dev, "unhandled ioctl cmd: %d\n", cmd); + break; + } + + return ret; +} + +static int rpmsg_omx_open(struct inode *inode, struct file *filp) +{ + struct rpmsg_omx_service *omxserv; + struct rpmsg_omx_instance *omx; + + omxserv = container_of(inode->i_cdev, struct rpmsg_omx_service, cdev); + + omx = kzalloc(sizeof(*omx), GFP_KERNEL); + if (!omx) + return -ENOMEM; + + mutex_init(&omx->lock); + skb_queue_head_init(&omx->queue); + init_waitqueue_head(&omx->readq); + omx->omxserv = omxserv; + omx->state = OMX_UNCONNECTED; + + /* assign a new, unique, local address and associate omx with it */ + omx->ept = rpmsg_create_ept(omxserv->rpdev, rpmsg_omx_cb, omx, + RPMSG_ADDR_ANY); + if (!omx->ept) { + dev_err(omxserv->dev, "create ept failed\n"); + kfree(omx); + return -ENOMEM; + } + + /* associate filp with the new omx instance */ + filp->private_data = omx; + + dev_info(omxserv->dev, "local addr assigned: 0x%x\n", omx->ept->addr); + + return 0; +} + +static int rpmsg_omx_release(struct inode *inode, struct file *filp) +{ + struct rpmsg_omx_instance *omx = filp->private_data; + struct rpmsg_omx_service *omxserv = omx->omxserv; + char kbuf[512]; + struct omx_msg_hdr *hdr = (struct omx_msg_hdr *) kbuf; + struct omx_disc_req *disc_req = (struct omx_disc_req *)hdr->data; + int use, ret; + + /* todo: release resources here */ + + /* send a disconnect msg with the OMX instance addr */ + hdr->type = OMX_DISCONNECT; + hdr->flags = 0; + hdr->len = sizeof(struct omx_disc_req); + disc_req->addr = omx->dst; + use = sizeof(*hdr) + hdr->len; + + dev_info(omxserv->dev, "Disconnecting from OMX service at %d\n", + omx->dst); + + /* send the msg to the remote OMX connection service */ + ret = rpmsg_send_offchannel(omxserv->rpdev, omx->ept->addr, + omxserv->rpdev->dst, kbuf, use); + if (ret) { + dev_err(omxserv->dev, "rpmsg_send failed: %d\n", ret); + return ret; + } + + rpmsg_destroy_ept(omx->ept); + kfree(omx); + + return 0; +} + +static ssize_t rpmsg_omx_read(struct file *filp, char __user *buf, + size_t len, loff_t *offp) +{ + struct rpmsg_omx_instance *omx = filp->private_data; + struct sk_buff *skb; + int use; + + if (omx->state != OMX_CONNECTED) + return -ENOTCONN; + + if (mutex_lock_interruptible(&omx->lock)) + return -ERESTARTSYS; + + /* nothing to read ? */ + if (skb_queue_empty(&omx->queue)) { + mutex_unlock(&omx->lock); + /* non-blocking requested ? return now */ + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + /* otherwise block, and wait for data */ + if (wait_event_interruptible(omx->readq, + !skb_queue_empty(&omx->queue))) + return -ERESTARTSYS; + if (mutex_lock_interruptible(&omx->lock)) + return -ERESTARTSYS; + } + + skb = skb_dequeue(&omx->queue); + if (!skb) { + dev_err(omx->omxserv->dev, "err is rmpsg_omx racy ?\n"); + return -EFAULT; + } + + mutex_unlock(&omx->lock); + + use = min(len, skb->len); + + if (copy_to_user(buf, skb->data, use)) + use = -EFAULT; + + kfree_skb(skb); + return use; +} + +static ssize_t rpmsg_omx_write(struct file *filp, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct rpmsg_omx_instance *omx = filp->private_data; + struct rpmsg_omx_service *omxserv = omx->omxserv; + char kbuf[512]; + struct omx_msg_hdr *hdr = (struct omx_msg_hdr *) kbuf; + int use, ret; + + if (omx->state != OMX_CONNECTED) + return -ENOTCONN; + + /* + * for now, limit msg size to 512 bytes (incl. header). + * (note: rpmsg's limit is even tighter. this whole thing needs fixing) + */ + use = min(sizeof(kbuf) - sizeof(*hdr), len); + + /* + * copy the data. Later, number of copies can be optimized if found to + * be significant in real use cases + */ + if (copy_from_user(hdr->data, ubuf, use)) + return -EMSGSIZE; + + hdr->type = OMX_RAW_MSG; + hdr->flags = 0; + hdr->len = use; + + use += sizeof(*hdr); + + ret = rpmsg_send_offchannel(omxserv->rpdev, omx->ept->addr, + omx->dst, kbuf, use); + if (ret) { + dev_err(omxserv->dev, "rpmsg_send failed: %d\n", ret); + return ret; + } + + return use; +} + +static +unsigned int rpmsg_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct rpmsg_omx_instance *omx = filp->private_data; + unsigned int mask = 0; + + if (mutex_lock_interruptible(&omx->lock)) + return -ERESTARTSYS; + + poll_wait(filp, &omx->readq, wait); + + if (!skb_queue_empty(&omx->queue)) + mask |= POLLIN | POLLRDNORM; + + /* implement missing rpmsg virtio functionality here */ + if (true) + mask |= POLLOUT | POLLWRNORM; + + mutex_unlock(&omx->lock); + + return mask; +} + +static const struct file_operations rpmsg_omx_fops = { + .open = rpmsg_omx_open, + .release = rpmsg_omx_release, + .unlocked_ioctl = rpmsg_omx_ioctl, + .read = rpmsg_omx_read, + .write = rpmsg_omx_write, + .poll = rpmsg_poll, + .owner = THIS_MODULE, +}; + +static int rpmsg_omx_probe(struct rpmsg_channel *rpdev) +{ + int ret, major, minor; + struct rpmsg_omx_service *omxserv; + + if (!idr_pre_get(&rpmsg_omx_services, GFP_KERNEL)) { + dev_err(&rpdev->dev, "idr_pre_get failes\n"); + return -ENOMEM; + } + + omxserv = kzalloc(sizeof(*omxserv), GFP_KERNEL); + if (!omxserv) { + dev_err(&rpdev->dev, "kzalloc failed\n"); + return -ENOMEM; + } + + /* dynamically assign a new minor number */ + spin_lock(&rpmsg_omx_services_lock); + ret = idr_get_new(&rpmsg_omx_services, omxserv, &minor); + spin_unlock(&rpmsg_omx_services_lock); + + if (ret) { + dev_err(&rpdev->dev, "failed to idr_get_new: %d\n", ret); + goto free_omx; + } + + major = MAJOR(rpmsg_omx_dev); + + omxserv->rpdev = rpdev; + omxserv->minor = minor; + + cdev_init(&omxserv->cdev, &rpmsg_omx_fops); + omxserv->cdev.owner = THIS_MODULE; + ret = cdev_add(&omxserv->cdev, MKDEV(major, minor), 1); + if (ret) { + dev_err(&rpdev->dev, "cdev_add failed: %d\n", ret); + goto rem_idr; + } + + omxserv->dev = device_create(rpmsg_omx_class, &rpdev->dev, + MKDEV(major, minor), NULL, + "rpmsg-omx%d", minor); + if (IS_ERR(omxserv->dev)) { + ret = PTR_ERR(omxserv->dev); + dev_err(&rpdev->dev, "device_create failed: %d\n", ret); + goto clean_cdev; + } + + dev_set_drvdata(&rpdev->dev, omxserv); + + dev_info(omxserv->dev, "new OMX connection srv channel: %u -> %u!\n", + rpdev->src, rpdev->dst); + return 0; + +clean_cdev: + cdev_del(&omxserv->cdev); +rem_idr: + spin_lock(&rpmsg_omx_services_lock); + idr_remove(&rpmsg_omx_services, minor); + spin_unlock(&rpmsg_omx_services_lock); +free_omx: + kfree(omxserv); + return ret; +} + +static void rpmsg_omx_remove(struct rpmsg_channel *rpdev) +{ + struct rpmsg_omx_service *omxserv = dev_get_drvdata(&rpdev->dev); + int major = MAJOR(rpmsg_omx_dev); + + dev_info(omxserv->dev, "rpmsg omx driver is removed\n"); + + device_destroy(rpmsg_omx_class, MKDEV(major, omxserv->minor)); + cdev_del(&omxserv->cdev); + spin_lock(&rpmsg_omx_services_lock); + idr_remove(&rpmsg_omx_services, omxserv->minor); + spin_unlock(&rpmsg_omx_services_lock); + kfree(omxserv); +} + +static void rpmsg_omx_driver_cb(struct rpmsg_channel *rpdev, void *data, + int len, void *priv, u32 src) +{ + dev_warn(&rpdev->dev, "uhm, unexpected message\n"); + + print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1, + data, len, true); +} + +static struct rpmsg_device_id rpmsg_omx_id_table[] = { + { .name = "rpmsg-omx" }, + { }, +}; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_omx_id_table); + +static struct rpmsg_driver rpmsg_omx_driver = { + .drv.name = KBUILD_MODNAME, + .drv.owner = THIS_MODULE, + .id_table = rpmsg_omx_id_table, + .probe = rpmsg_omx_probe, + .callback = rpmsg_omx_driver_cb, + .remove = rpmsg_omx_remove, +}; + +static int __init init(void) +{ + int ret; + + ret = alloc_chrdev_region(&rpmsg_omx_dev, 0, MAX_OMX_DEVICES, + KBUILD_MODNAME); + if (ret) { + pr_err("alloc_chrdev_region failed: %d\n", ret); + goto out; + } + + rpmsg_omx_class = class_create(THIS_MODULE, KBUILD_MODNAME); + if (IS_ERR(rpmsg_omx_class)) { + ret = PTR_ERR(rpmsg_omx_class); + pr_err("class_create failed: %d\n", ret); + goto unreg_region; + } + + return register_rpmsg_driver(&rpmsg_omx_driver); + +unreg_region: + unregister_chrdev_region(rpmsg_omx_dev, MAX_OMX_DEVICES); +out: + return ret; +} +module_init(init); + +static void __exit fini(void) +{ + unregister_rpmsg_driver(&rpmsg_omx_driver); + class_destroy(rpmsg_omx_class); + unregister_chrdev_region(rpmsg_omx_dev, MAX_OMX_DEVICES); +} +module_exit(fini); + +MODULE_DESCRIPTION("OMX offloading rpmsg driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/rpmsg_server_sample.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/rpmsg_server_sample.c 2014-07-20 22:06:37.408288365 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Remote processor messaging transport - sample server driver + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + * + * 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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/rpmsg.h> +#include <linux/io.h> + +#define MSG ("hello world!") +#define MSG_LIMIT 100 + +#define MSG_LAT ("12345678901234567890123456789012345678901234567890"\ + "12345678901234567890123456789012345678901234567890"\ + "12345678901234567890123456789012345678901234567890"\ + "12345678901234567890123456789012345678901234567890"\ + "12345678901234567890123456789012345678901234567890"\ + "12345678901234567890123456789012345678901234567890"\ + "12345678901234567890123456789012345678901234567890"\ + "12345678901234567890123456789012345678901234567890"\ + "12345678901234567890123456789012345678901234567890"\ + "123456789012345678901234567890123456789012345") +#define MSG_LAT_LIMIT 100000 + +u64 start; /* variable for storing jiffies */ + +/* TTC runs on 133 MHz - (1 / 133000000 = 8 ns) */ +#define TTC_HZ 8 + +/* ttc ioremap pointer */ +u8 *ttc_base; + +/* Enable/disable latency measuring */ +static int latency; + +static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len, + void *priv, u32 src) +{ + int err; + static int rx_count; + + if (latency) { + static u32 min = 0x10000000; + static u32 max; + static u32 average; + + u32 value = __raw_readl(ttc_base + 0x1c); /* Read value */ + __raw_writel(0x11, ttc_base + 0x10); /* Stop TTC */ + + if (value < min) + min = value; + if (value > max) + max = value; + + average += value; + /* count messages */ + ++rx_count; + + if (rx_count >= MSG_LAT_LIMIT) { + u64 end = get_jiffies_64(); + u32 time = end - start; + u32 timeps = ((1000000 / MSG_LAT_LIMIT) * time) / HZ; + + printk(KERN_INFO "actual value %d ns, min %d ns, max %d" + " ns, average %d ns\n", value * TTC_HZ, + min * TTC_HZ, max * TTC_HZ, + (average/rx_count) * TTC_HZ); + printk(KERN_INFO "Start/end jiffies %llx/%llx, " + "messages %d. Time: %d s, " + "Messages per second %d\n", end, start, + rx_count, time/HZ, + 1000000 / timeps); + + dev_info(&rpdev->dev, "goodbye!\n"); + return; + } + + __raw_writel(0x10, ttc_base + 0x10); /* Start TTC */ + /* reply */ + err = rpmsg_sendto(rpdev, MSG_LAT, strlen(MSG_LAT), src); + } else { + dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n", + ++rx_count, src); + print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1, + data, len, true); + + /* samples should not live forever */ + if (rx_count >= MSG_LIMIT) { + dev_info(&rpdev->dev, "goodbye!\n"); + return; + } + + err = rpmsg_sendto(rpdev, MSG, strlen(MSG), src); /* reply */ + } + + if (err) + pr_err("rpmsg_send failed: %d\n", err); +} + +static int rpmsg_sample_probe(struct rpmsg_channel *rpdev) +{ + int err; + + if (latency) { + dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!, len %d\n", + rpdev->src, rpdev->dst, strlen(MSG_LAT)); + + ttc_base = ioremap(0xf8002000, PAGE_SIZE); /* TTC base addr */ + if (!ttc_base) { + pr_err("TTC Ioremap failed\n"); + return -1; + } + start = get_jiffies_64(); + __raw_writel(0x10, ttc_base + 0x10); /* Start TTC */ + + err = rpmsg_sendto(rpdev, MSG_LAT, strlen(MSG_LAT), 50); + } else { + dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!, len %d\n", + rpdev->src, rpdev->dst, strlen(MSG)); + + err = rpmsg_sendto(rpdev, MSG, strlen(MSG), 50); + } + + if (err) { + pr_err("rpmsg_send failed: %d\n", err); + return err; + } + + return 0; +} + +static void rpmsg_sample_remove(struct rpmsg_channel *rpdev) +{ + dev_info(&rpdev->dev, "rpmsg sample driver is removed\n"); +} + +static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = { + { .name = "rpmsg-server-sample" }, + { }, +}; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table); + +static struct rpmsg_driver rpmsg_sample_server = { + .drv.name = KBUILD_MODNAME, + .drv.owner = THIS_MODULE, + .id_table = rpmsg_driver_sample_id_table, + .probe = rpmsg_sample_probe, + .callback = rpmsg_sample_cb, + .remove = rpmsg_sample_remove, +}; + +static int __init init(void) +{ + return register_rpmsg_driver(&rpmsg_sample_server); +} + +static void __exit fini(void) +{ + unregister_rpmsg_driver(&rpmsg_sample_server); +} +module_init(init); +module_exit(fini); + +module_param(latency, int, 0); +MODULE_PARM_DESC(latency, "Enable latency measuring code."); + +MODULE_DESCRIPTION("Virtio remote processor messaging sample driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/rpmsg/virtio_rpmsg_bus.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/rpmsg/virtio_rpmsg_bus.c 2014-07-20 22:05:50.207067099 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/rpmsg/virtio_rpmsg_bus.c 2014-07-20 22:06:37.424288102 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:54 @ * @sendq: wait queue of sending contexts waiting for a tx buffers * @sleepers: number of senders that are waiting for a tx buffer * @ns_ept: the bus's name service endpoint + * @id: unique system-wide index id for this vproc * * This structure stores the rpmsg state of a given virtio remote processor * device (there might be several virtio proc devices for each physical @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:72 @ wait_queue_head_t sendq; atomic_t sleepers; struct rpmsg_endpoint *ns_ept; + int id; }; +int get_virtproc_id(struct virtproc_info *vrp) +{ + return vrp->id; +} +EXPORT_SYMBOL(get_virtproc_id); + /** * struct rpmsg_channel_info - internal channel info representation * @name: name of service @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:145 @ rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); /* + * The virtio devices we are probed with represent remote processors + * on the system. We call them _virtual_ processors, because every physical + * remote processor might actually have several virtio devices. + * + * The idr below is used to assign each vproc a unique, system-wide, index id. + */ +static struct idr vprocs; +static DEFINE_MUTEX(vprocs_mutex); + +/* * Unique (and free running) index for rpmsg devices. * * Yeah, we're not recycling those numbers (yet?). will be easy @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:514 @ * this function will be used to create both static and dynamic * channels. */ -static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp, +static struct rpmsg_channel *__rpmsg_create_channel(struct virtproc_info *vrp, struct rpmsg_channel_info *chinfo) { struct rpmsg_channel *rpdev; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:570 @ * find an existing channel using its name + address properties, * and destroy it */ -static int rpmsg_destroy_channel(struct virtproc_info *vrp, +static int __rpmsg_destroy_channel(struct virtproc_info *vrp, struct rpmsg_channel_info *chinfo) { struct virtio_device *vdev = vrp->vdev; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:908 @ wake_up_interruptible(&vrp->sendq); } +struct rpmsg_channel *rpmsg_create_channel(int vrp_id, const char *name, + int src, int dst) +{ + struct rpmsg_channel_info chinfo; + struct virtproc_info *vrp; + + strncpy(chinfo.name, name, sizeof(chinfo.name)); + chinfo.src = src; + chinfo.dst = dst; + + /* TODO we probably want radix tree and fw-induced id numbers ? */ + vrp = idr_find(&vprocs, vrp_id); + if (!vrp) + return NULL; + + return __rpmsg_create_channel(vrp, &chinfo); +} +EXPORT_SYMBOL(rpmsg_create_channel); + /* invoked when a name service announcement arrives */ static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len, void *priv, u32 src) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:970 @ chinfo.dst = msg->addr; if (msg->flags & RPMSG_NS_DESTROY) { - ret = rpmsg_destroy_channel(vrp, &chinfo); + ret = __rpmsg_destroy_channel(vrp, &chinfo); if (ret) - dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret); + dev_err(dev, "__rpmsg_destroy_channel err: %d\n", ret); } else { - newch = rpmsg_create_channel(vrp, &chinfo); + newch = __rpmsg_create_channel(vrp, &chinfo); if (!newch) - dev_err(dev, "rpmsg_create_channel failed\n"); + dev_err(dev, "__rpmsg_create_channel failed\n"); } } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:987 @ struct virtqueue *vqs[2]; struct virtproc_info *vrp; void *bufs_va; - int err = 0, i; + int err = 0, i, vproc_id; vrp = kzalloc(sizeof(*vrp), GFP_KERNEL); if (!vrp) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1000 @ mutex_init(&vrp->tx_lock); init_waitqueue_head(&vrp->sendq); + if (!idr_pre_get(&vprocs, GFP_KERNEL)) + goto free_vrp; + + mutex_lock(&vprocs_mutex); + + err = idr_get_new(&vprocs, vrp, &vproc_id); + + mutex_unlock(&vprocs_mutex); + + if (err) { + dev_err(&vdev->dev, "idr_get_new failed: %d\n", err); + goto free_vrp; + } + + vrp->id = vproc_id; + /* We expect two virtqueues, rx and tx (and in this order) */ err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names); if (err) - goto free_vrp; + goto rem_idr; vrp->rvq = vqs[0]; vrp->svq = vqs[1]; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1083 @ bufs_va, vrp->bufs_dma); vqs_del: vdev->config->del_vqs(vrp->vdev); +rem_idr: + mutex_lock(&vprocs_mutex); + idr_remove(&vprocs, vproc_id); + mutex_unlock(&vprocs_mutex); free_vrp: kfree(vrp); return err; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1117 @ vdev->config->del_vqs(vrp->vdev); + /* FIXME del_vqs is calling rproc_shutdown which switch loaded resource + * table back to cached table but without any synchronization. + * That's why vdev->config->reset(vdev) above is called on loaded table + * and this one is called on cached resource table which ensure + * that WARN_ON_ONCE(dev->config->get_status(dev)); in + * virtio_dev_remove() won't show bug because cached table wasn't + * synchronized with loaded one. + */ + vdev->config->reset(vdev); + dma_free_coherent(vdev->dev.parent->parent, RPMSG_TOTAL_BUF_SPACE, vrp->rbufs, vrp->bufs_dma); + mutex_lock(&vprocs_mutex); + idr_remove(&vprocs, vrp->id); + mutex_unlock(&vprocs_mutex); + kfree(vrp); } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1160 @ { int ret; + idr_init(&vprocs); + ret = bus_register(&rpmsg_bus); if (ret) { pr_err("failed to register rpmsg bus: %d\n", ret); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1182 @ { unregister_virtio_driver(&virtio_ipc_driver); bus_unregister(&rpmsg_bus); + + idr_remove_all(&vprocs); + idr_destroy(&vprocs); } module_exit(rpmsg_fini); Index: linux-3.12.24-rt38-xilinx/drivers/spi/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/spi/Kconfig 2014-07-20 22:05:50.169067727 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/spi/Kconfig 2014-07-20 22:06:37.450287673 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:508 @ See the "OPB Serial Peripheral Interface (SPI) (v1.00e)" Product Specification document (DS464) for hardware details. - Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" +config SPI_ZYNQ_QSPI + tristate "Xilinx PS QSPI controller" + depends on ARCH_ZYNQ + depends on SPI_MASTER + help + This selects the Xilinx ZYNQ Quad SPI controller master driver. + +config SPI_ZYNQ_QSPI_DUAL_STACKED + bool "Xilinx PS QSPI Dual stacked configuration" + depends on SPI_ZYNQ_QSPI + help + This selects the Xilinx ZYNQ Quad SPI controller in dual stacked mode. + Enable this option if your hw design is using dual stacked + configuration. + +config SPI_ZYNQ + tristate "Xilinx ZYNQ SPI controller" + depends on ARCH_ZYNQ + depends on SPI_MASTER + help + This selects the Xilinx ZYNQ SPI controller master driver. + config SPI_NUC900 tristate "Nuvoton NUC900 series SPI" depends on ARCH_W90X900 Index: linux-3.12.24-rt38-xilinx/drivers/spi/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/spi/Makefile 2014-07-20 22:05:50.168067743 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/spi/Makefile 2014-07-20 22:06:37.463287458 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:81 @ obj-$(CONFIG_SPI_TXX9) += spi-txx9.o obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o +obj-$(CONFIG_SPI_ZYNQ) += spi-zynq.o +obj-$(CONFIG_SPI_ZYNQ_QSPI) += spi-zynq-qspi.o Index: linux-3.12.24-rt38-xilinx/drivers/spi/spi-xilinx.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/spi/spi-xilinx.c 2014-07-20 22:05:50.166067776 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/spi/spi-xilinx.c 2014-07-20 22:06:37.474287277 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:371 @ if (!master) return -ENODEV; + /* clear the dma_mask, to try to disable use of dma */ + master->dev.dma_mask = 0; + /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA; Index: linux-3.12.24-rt38-xilinx/drivers/spi/spi-zynq.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/spi/spi-zynq.c 2014-07-20 22:06:37.490287013 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * + * Xilinx PS SPI controller driver (master mode only) + * + * (c) 2008-2011 Xilinx, Inc. + * + * based on Blackfin On-Chip SPI Driver (spi_bfin5xx.c) + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> + +/* + * Name of this driver + */ +#define XSPIPS_NAME "xspips" + +/* + * Register offset definitions + */ +#define XSPIPS_CR_OFFSET 0x00 /* Configuration Register, RW */ +#define XSPIPS_ISR_OFFSET 0x04 /* Interrupt Status Register, RO */ +#define XSPIPS_IER_OFFSET 0x08 /* Interrupt Enable Register, WO */ +#define XSPIPS_IDR_OFFSET 0x0c /* Interrupt Disable Register, WO */ +#define XSPIPS_IMR_OFFSET 0x10 /* Interrupt Enabled Mask Register, RO */ +#define XSPIPS_ER_OFFSET 0x14 /* Enable/Disable Register, RW */ +#define XSPIPS_DR_OFFSET 0x18 /* Delay Register, RW */ +#define XSPIPS_TXD_OFFSET 0x1C /* Data Transmit Register, WO */ +#define XSPIPS_RXD_OFFSET 0x20 /* Data Receive Register, RO */ +#define XSPIPS_SICR_OFFSET 0x24 /* Slave Idle Count Register, RW */ +#define XSPIPS_THLD_OFFSET 0x28 /* Transmit FIFO Watermark Register,RW */ + +/* + * SPI Configuration Register bit Masks + * + * This register contains various control bits that affect the operation + * of the SPI controller + */ +#define XSPIPS_CR_MANSTRT_MASK 0x00010000 /* Manual TX Start */ +#define XSPIPS_CR_CPHA_MASK 0x00000004 /* Clock Phase Control */ +#define XSPIPS_CR_CPOL_MASK 0x00000002 /* Clock Polarity Control */ +#define XSPIPS_CR_SSCTRL_MASK 0x00003C00 /* Slave Select Mask */ + +/* + * SPI Interrupt Registers bit Masks + * + * All the four interrupt registers (Status/Mask/Enable/Disable) have the same + * bit definitions. + */ +#define XSPIPS_IXR_TXOW_MASK 0x00000004 /* SPI TX FIFO Overwater */ +#define XSPIPS_IXR_MODF_MASK 0x00000002 /* SPI Mode Fault */ +#define XSPIPS_IXR_RXNEMTY_MASK 0x00000010 /* SPI RX FIFO Not Empty */ +#define XSPIPS_IXR_ALL_MASK (XSPIPS_IXR_TXOW_MASK | XSPIPS_IXR_MODF_MASK) + +/* + * SPI Enable Register bit Masks + * + * This register is used to enable or disable the SPI controller + */ +#define XSPIPS_ER_ENABLE_MASK 0x00000001 /* SPI Enable Bit Mask */ + +/* + * Definitions for the status of queue + */ +#define XSPIPS_QUEUE_STOPPED 0 +#define XSPIPS_QUEUE_RUNNING 1 + +/* + * Macros for the SPI controller read/write + */ +#define xspips_read(addr) __raw_readl(addr) +#define xspips_write(addr, val) __raw_writel((val), (addr)) + + +/** + * struct xspips - This definition defines spi driver instance + * @workqueue: Queue of all the transfers + * @work: Information about current transfer + * @queue: Head of the queue + * @queue_state: Queue status + * @regs: Virtual address of the SPI controller registers + * @devclk: Pointer to the peripheral clock + * @aperclk: Pointer to the APER clock + * @clk_rate_change_nb: Notifier block for clock frequency change callback + * @irq: IRQ number + * @speed_hz: Current SPI bus clock speed in Hz + * @trans_queue_lock: Lock used for accessing transfer queue + * @ctrl_reg_lock: Lock used for accessing configuration register + * @txbuf: Pointer to the TX buffer + * @rxbuf: Pointer to the RX buffer + * @remaining_bytes: Number of bytes left to transfer + * @dev_busy: Device busy flag + * @done: Transfer complete status + */ +struct xspips { + struct workqueue_struct *workqueue; + struct work_struct work; + struct list_head queue; + int queue_state; + void __iomem *regs; + struct clk *devclk; + struct clk *aperclk; + struct notifier_block clk_rate_change_nb; + int irq; + u32 speed_hz; + spinlock_t trans_queue_lock; + spinlock_t ctrl_reg_lock; + const u8 *txbuf; + u8 *rxbuf; + int remaining_bytes; + u8 dev_busy; + struct completion done; +}; + + +/** + * xspips_init_hw - Initialize the hardware and configure the SPI controller + * @regs_base: Base address of SPI controller + * + * On reset the SPI controller is configured to be in master mode, baud rate + * divisor is set to 2, threshold value for TX FIFO not full interrupt is set + * to 1 and size of the word to be transferred as 8 bit. + * This function initializes the SPI controller to disable and clear all the + * interrupts, enable manual slave select and manual start, deselect all the + * chip select lines, and enable the SPI controller. + */ +static void xspips_init_hw(void __iomem *regs_base) +{ + xspips_write(regs_base + XSPIPS_ER_OFFSET, ~XSPIPS_ER_ENABLE_MASK); + xspips_write(regs_base + XSPIPS_IDR_OFFSET, 0x7F); + + /* Clear the RX FIFO */ + while (xspips_read(regs_base + XSPIPS_ISR_OFFSET) & + XSPIPS_IXR_RXNEMTY_MASK) + xspips_read(regs_base + XSPIPS_RXD_OFFSET); + + xspips_write(regs_base + XSPIPS_ISR_OFFSET, 0x7F); + xspips_write(regs_base + XSPIPS_CR_OFFSET, 0x0000FC01); + xspips_write(regs_base + XSPIPS_ER_OFFSET, XSPIPS_ER_ENABLE_MASK); +} + +/** + * xspips_chipselect - Select or deselect the chip select line + * @spi: Pointer to the spi_device structure + * @is_on: Select(1) or deselect (0) the chip select line + */ +static void xspips_chipselect(struct spi_device *spi, int is_on) +{ + struct xspips *xspi = spi_master_get_devdata(spi->master); + u32 ctrl_reg; + unsigned long flags; + + spin_lock_irqsave(&xspi->ctrl_reg_lock, flags); + + ctrl_reg = xspips_read(xspi->regs + XSPIPS_CR_OFFSET); + + if (is_on) { + /* Select the slave */ + ctrl_reg &= ~XSPIPS_CR_SSCTRL_MASK; + ctrl_reg |= (((~(0x0001 << spi->chip_select)) << 10) & + XSPIPS_CR_SSCTRL_MASK); + } else { + /* Deselect the slave */ + ctrl_reg |= XSPIPS_CR_SSCTRL_MASK; + } + + xspips_write(xspi->regs + XSPIPS_CR_OFFSET, ctrl_reg); + + spin_unlock_irqrestore(&xspi->ctrl_reg_lock, flags); +} + +/** + * xspips_setup_transfer - Configure SPI controller for specified transfer + * @spi: Pointer to the spi_device structure + * @transfer: Pointer to the spi_transfer structure which provides information + * about next transfer setup parameters + * + * Sets the operational mode of SPI controller for the next SPI transfer and + * sets the requested clock frequency. + * + * returns: 0 on success and error value on error + * + * Note: If the requested frequency is not an exact match with what can be + * obtained using the prescalar value the driver sets the clock frequency which + * is lower than the requested frequency (maximum lower) for the transfer. If + * the requested frequency is higher or lower than that is supported by the SPI + * controller the driver will set the highest or lowest frequency supported by + * controller. + */ +static int xspips_setup_transfer(struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct xspips *xspi = spi_master_get_devdata(spi->master); + u8 bits_per_word; + u32 ctrl_reg; + u32 req_hz; + u32 baud_rate_val; + unsigned long flags, frequency; + + bits_per_word = (transfer) ? + transfer->bits_per_word : spi->bits_per_word; + req_hz = (transfer) ? transfer->speed_hz : spi->max_speed_hz; + + if (bits_per_word != 8) { + dev_err(&spi->dev, "%s, unsupported bits per word %x\n", + __func__, spi->bits_per_word); + return -EINVAL; + } + + frequency = clk_get_rate(xspi->devclk); + + spin_lock_irqsave(&xspi->ctrl_reg_lock, flags); + + xspips_write(xspi->regs + XSPIPS_ER_OFFSET, ~XSPIPS_ER_ENABLE_MASK); + ctrl_reg = xspips_read(xspi->regs + XSPIPS_CR_OFFSET); + + /* Set the SPI clock phase and clock polarity */ + ctrl_reg &= (~XSPIPS_CR_CPHA_MASK) & (~XSPIPS_CR_CPOL_MASK); + if (spi->mode & SPI_CPHA) + ctrl_reg |= XSPIPS_CR_CPHA_MASK; + if (spi->mode & SPI_CPOL) + ctrl_reg |= XSPIPS_CR_CPOL_MASK; + + /* Set the clock frequency */ + if (xspi->speed_hz != req_hz) { + baud_rate_val = 1; /* first valid value is 1 */ + while ((baud_rate_val < 8) && (frequency / + (2 << baud_rate_val)) > req_hz) + baud_rate_val++; + + ctrl_reg &= 0xFFFFFFC7; + ctrl_reg |= (baud_rate_val << 3); + + xspi->speed_hz = (frequency / (2 << baud_rate_val)); + } + + xspips_write(xspi->regs + XSPIPS_CR_OFFSET, ctrl_reg); + xspips_write(xspi->regs + XSPIPS_ER_OFFSET, XSPIPS_ER_ENABLE_MASK); + + spin_unlock_irqrestore(&xspi->ctrl_reg_lock, flags); + + dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u clock speed\n", + __func__, spi->mode, spi->bits_per_word, + xspi->speed_hz); + + return 0; +} + +/** + * xspips_setup - Configure the SPI controller + * @spi: Pointer to the spi_device structure + * + * Sets the operational mode of SPI controller for the next SPI transfer, sets + * the baud rate and divisor value to setup the requested spi clock. + * + * returns: 0 on success and error value on error + */ +static int xspips_setup(struct spi_device *spi) +{ + if (!spi->max_speed_hz) + return -EINVAL; + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + return xspips_setup_transfer(spi, NULL); +} + +/** + * xspips_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible + * @xspi: Pointer to the xspips structure + */ +static void xspips_fill_tx_fifo(struct xspips *xspi) +{ + while ((xspips_read(xspi->regs + XSPIPS_ISR_OFFSET) & 0x00000008) == 0 + && (xspi->remaining_bytes > 0)) { + if (xspi->txbuf) + xspips_write(xspi->regs + XSPIPS_TXD_OFFSET, + *xspi->txbuf++); + else + xspips_write(xspi->regs + XSPIPS_TXD_OFFSET, 0); + + xspi->remaining_bytes--; + } +} + +/** + * xspips_irq - Interrupt service routine of the SPI controller + * @irq: IRQ number + * @dev_id: Pointer to the xspi structure + * + * This function handles TX empty and Mode Fault interrupts only. + * On TX empty interrupt this function reads the received data from RX FIFO and + * fills the TX FIFO if there is any data remaining to be transferred. + * On Mode Fault interrupt this function indicates that transfer is completed, + * the SPI subsystem will identify the error as the remaining bytes to be + * transferred is non-zero. + * + * returns: IRQ_HANDLED always + */ +static irqreturn_t xspips_irq(int irq, void *dev_id) +{ + struct xspips *xspi = dev_id; + u32 intr_status; + + intr_status = xspips_read(xspi->regs + XSPIPS_ISR_OFFSET); + xspips_write(xspi->regs + XSPIPS_ISR_OFFSET, intr_status); + xspips_write(xspi->regs + XSPIPS_IDR_OFFSET, XSPIPS_IXR_ALL_MASK); + + if (intr_status & XSPIPS_IXR_MODF_MASK) { + /* Indicate that transfer is completed, the SPI subsystem will + * identify the error as the remaining bytes to be + * transferred is non-zero */ + complete(&xspi->done); + } else if (intr_status & XSPIPS_IXR_TXOW_MASK) { + u32 ctrl_reg; + + /* Read out the data from the RX FIFO */ + while (xspips_read(xspi->regs + XSPIPS_ISR_OFFSET) & + XSPIPS_IXR_RXNEMTY_MASK) { + u8 data; + + data = xspips_read(xspi->regs + XSPIPS_RXD_OFFSET); + if (xspi->rxbuf) + *xspi->rxbuf++ = data; + + /* Data memory barrier is placed here to ensure that + * data read operation is completed before the status + * read is initiated. Without dmb, there are chances + * that data and status reads will appear at the SPI + * peripheral back-to-back which results in an + * incorrect status read. + */ + dmb(); + } + + if (xspi->remaining_bytes) { + /* There is more data to send */ + xspips_fill_tx_fifo(xspi); + + xspips_write(xspi->regs + XSPIPS_IER_OFFSET, + XSPIPS_IXR_ALL_MASK); + + spin_lock(&xspi->ctrl_reg_lock); + + ctrl_reg = xspips_read(xspi->regs + XSPIPS_CR_OFFSET); + ctrl_reg |= XSPIPS_CR_MANSTRT_MASK; + xspips_write(xspi->regs + XSPIPS_CR_OFFSET, ctrl_reg); + + spin_unlock(&xspi->ctrl_reg_lock); + } else { + /* Transfer is completed */ + complete(&xspi->done); + } + } + + return IRQ_HANDLED; +} + +/** + * xspips_start_transfer - Initiates the SPI transfer + * @spi: Pointer to the spi_device structure + * @transfer: Pointer to the spi_transfer structure which provide information + * about next transfer parameters + * + * This function fills the TX FIFO, starts the SPI transfer, and waits for the + * transfer to be completed. + * + * returns: Number of bytes transferred in the last transfer + */ +static int xspips_start_transfer(struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct xspips *xspi = spi_master_get_devdata(spi->master); + u32 ctrl_reg; + unsigned long flags; + + xspi->txbuf = transfer->tx_buf; + xspi->rxbuf = transfer->rx_buf; + xspi->remaining_bytes = transfer->len; + INIT_COMPLETION(xspi->done); + + xspips_fill_tx_fifo(xspi); + + xspips_write(xspi->regs + XSPIPS_IER_OFFSET, XSPIPS_IXR_ALL_MASK); + + spin_lock_irqsave(&xspi->ctrl_reg_lock, flags); + + /* Start the transfer by enabling manual start bit */ + ctrl_reg = xspips_read(xspi->regs + XSPIPS_CR_OFFSET); + ctrl_reg |= XSPIPS_CR_MANSTRT_MASK; + xspips_write(xspi->regs + XSPIPS_CR_OFFSET, ctrl_reg); + + spin_unlock_irqrestore(&xspi->ctrl_reg_lock, flags); + + wait_for_completion(&xspi->done); + + return (transfer->len) - (xspi->remaining_bytes); +} + +/** + * xspips_work_queue - Get the transfer request from queue to perform transfers + * @work: Pointer to the work_struct structure + */ +static void xspips_work_queue(struct work_struct *work) +{ + struct xspips *xspi = container_of(work, struct xspips, work); + unsigned long flags; + + spin_lock_irqsave(&xspi->trans_queue_lock, flags); + xspi->dev_busy = 1; + + if (list_empty(&xspi->queue) || + xspi->queue_state == XSPIPS_QUEUE_STOPPED) { + xspi->dev_busy = 0; + spin_unlock_irqrestore(&xspi->trans_queue_lock, flags); + return; + } + + while (!list_empty(&xspi->queue)) { + struct spi_message *msg; + struct spi_device *spi; + struct spi_transfer *transfer = NULL; + unsigned cs_change = 1; + int status = 0; + + msg = container_of(xspi->queue.next, struct spi_message, queue); + list_del_init(&msg->queue); + spin_unlock_irqrestore(&xspi->trans_queue_lock, flags); + spi = msg->spi; + + list_for_each_entry(transfer, &msg->transfers, transfer_list) { + if ((transfer->bits_per_word || transfer->speed_hz) && + cs_change) { + status = xspips_setup_transfer(spi, transfer); + if (status < 0) + break; + } + + if (cs_change) + xspips_chipselect(spi, 1); + + cs_change = transfer->cs_change; + + if (!transfer->tx_buf && !transfer->rx_buf && + transfer->len) { + status = -EINVAL; + break; + } + + if (transfer->len) + status = xspips_start_transfer(spi, transfer); + + if (status != transfer->len) { + if (status > 0) + status = -EMSGSIZE; + break; + } + msg->actual_length += status; + status = 0; + + if (transfer->delay_usecs) + udelay(transfer->delay_usecs); + + if (!cs_change) + continue; + if (transfer->transfer_list.next == &msg->transfers) + break; + + xspips_chipselect(spi, 0); + } + + msg->status = status; + msg->complete(msg->context); + + if (!(status == 0 && cs_change)) + xspips_chipselect(spi, 0); + + spin_lock_irqsave(&xspi->trans_queue_lock, flags); + } + xspi->dev_busy = 0; + spin_unlock_irqrestore(&xspi->trans_queue_lock, flags); +} + +/** + * xspips_transfer - Add a new transfer request at the tail of work queue + * @spi: Pointer to the spi_device structure + * @message: Pointer to the spi_transfer structure which provide information + * about next transfer parameters + * + * returns: 0 on success and error value on error + */ +static int xspips_transfer(struct spi_device *spi, struct spi_message *message) +{ + struct xspips *xspi = spi_master_get_devdata(spi->master); + struct spi_transfer *transfer; + unsigned long flags; + + if (xspi->queue_state == XSPIPS_QUEUE_STOPPED) + return -ESHUTDOWN; + + message->actual_length = 0; + message->status = -EINPROGRESS; + + /* Check each transfer's parameters */ + list_for_each_entry(transfer, &message->transfers, transfer_list) { + u8 bits_per_word = + transfer->bits_per_word ? : spi->bits_per_word; + + bits_per_word = bits_per_word ? : 8; + if (!transfer->tx_buf && !transfer->rx_buf && transfer->len) + return -EINVAL; + if (bits_per_word != 8) + return -EINVAL; + } + + spin_lock_irqsave(&xspi->trans_queue_lock, flags); + list_add_tail(&message->queue, &xspi->queue); + if (!xspi->dev_busy) + queue_work(xspi->workqueue, &xspi->work); + spin_unlock_irqrestore(&xspi->trans_queue_lock, flags); + + return 0; +} + +/** + * xspips_start_queue - Starts the queue of the SPI driver + * @xspi: Pointer to the xspips structure + * + * returns: 0 on success and error value on error + */ +static inline int xspips_start_queue(struct xspips *xspi) +{ + unsigned long flags; + + spin_lock_irqsave(&xspi->trans_queue_lock, flags); + + if (xspi->queue_state == XSPIPS_QUEUE_RUNNING || xspi->dev_busy) { + spin_unlock_irqrestore(&xspi->trans_queue_lock, flags); + return -EBUSY; + } + + xspi->queue_state = XSPIPS_QUEUE_RUNNING; + spin_unlock_irqrestore(&xspi->trans_queue_lock, flags); + + return 0; +} + +/** + * xspips_stop_queue - Stops the queue of the SPI driver + * @xspi: Pointer to the xspips structure + * + * This function waits till queue is empty and then stops the queue. + * Maximum time out is set to 5 seconds. + * + * returns: 0 on success and error value on error + */ +static inline int xspips_stop_queue(struct xspips *xspi) +{ + unsigned long flags; + unsigned limit = 500; + int ret = 0; + + if (xspi->queue_state != XSPIPS_QUEUE_RUNNING) + return ret; + + spin_lock_irqsave(&xspi->trans_queue_lock, flags); + + while ((!list_empty(&xspi->queue) || xspi->dev_busy) && limit--) { + spin_unlock_irqrestore(&xspi->trans_queue_lock, flags); + msleep(10); + spin_lock_irqsave(&xspi->trans_queue_lock, flags); + } + + if (!list_empty(&xspi->queue) || xspi->dev_busy) + ret = -EBUSY; + + if (ret == 0) + xspi->queue_state = XSPIPS_QUEUE_STOPPED; + + spin_unlock_irqrestore(&xspi->trans_queue_lock, flags); + + return ret; +} + +/** + * xspips_destroy_queue - Destroys the queue of the SPI driver + * @xspi: Pointer to the xspips structure + * + * returns: 0 on success and error value on error + */ +static inline int xspips_destroy_queue(struct xspips *xspi) +{ + int ret; + + ret = xspips_stop_queue(xspi); + if (ret != 0) + return ret; + + destroy_workqueue(xspi->workqueue); + + return 0; +} + +static int xspips_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + switch (event) { + case PRE_RATE_CHANGE: + /* if a rate change is announced we need to check whether we can + * maintain the current frequency by changing the clock + * dividers. And we may have to suspend operation and return + * after the rate change or its abort + */ + return NOTIFY_OK; + case POST_RATE_CHANGE: + return NOTIFY_OK; + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +/** + * xspips_probe - Probe method for the SPI driver + * @pdev: Pointer to the platform_device structure + * + * This function initializes the driver data structures and the hardware. + * + * returns: 0 on success and error value on error + */ +static int xspips_probe(struct platform_device *pdev) +{ + int ret = 0; + struct spi_master *master; + struct xspips *xspi; + struct resource *res; + + master = spi_alloc_master(&pdev->dev, sizeof(*xspi)); + if (master == NULL) + return -ENOMEM; + + xspi = spi_master_get_devdata(master); + master->dev.of_node = pdev->dev.of_node; + platform_set_drvdata(pdev, master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xspi->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xspi->regs)) { + ret = PTR_ERR(xspi->regs); + goto remove_master; + } + + xspi->irq = platform_get_irq(pdev, 0); + if (xspi->irq < 0) { + ret = -ENXIO; + dev_err(&pdev->dev, "irq number is negative\n"); + goto remove_master; + } + + ret = devm_request_irq(&pdev->dev, xspi->irq, xspips_irq, + 0, pdev->name, xspi); + if (ret != 0) { + ret = -ENXIO; + dev_err(&pdev->dev, "request_irq failed\n"); + goto remove_master; + } + + xspi->aperclk = devm_clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(xspi->aperclk)) { + dev_err(&pdev->dev, "aper_clk clock not found.\n"); + ret = PTR_ERR(xspi->aperclk); + goto remove_master; + } + + xspi->devclk = devm_clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(xspi->devclk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xspi->devclk); + goto remove_master; + } + + ret = clk_prepare_enable(xspi->aperclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + goto remove_master; + } + + ret = clk_prepare_enable(xspi->devclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable device clock.\n"); + goto clk_dis_aper; + } + + xspi->clk_rate_change_nb.notifier_call = xspips_clk_notifier_cb; + xspi->clk_rate_change_nb.next = NULL; + if (clk_notifier_register(xspi->devclk, &xspi->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); + + /* SPI controller initializations */ + xspips_init_hw(xspi->regs); + + init_completion(&xspi->done); + + ret = of_property_read_u32(pdev->dev.of_node, "num-chip-select", + (u32 *)&master->num_chipselect); + if (ret < 0) { + dev_err(&pdev->dev, "couldn't determine num-chip-select\n"); + goto clk_notif_unreg; + } + master->setup = xspips_setup; + master->transfer = xspips_transfer; + master->mode_bits = SPI_CPOL | SPI_CPHA; + + xspi->speed_hz = clk_get_rate(xspi->devclk) / 2; + + xspi->dev_busy = 0; + + INIT_LIST_HEAD(&xspi->queue); + spin_lock_init(&xspi->trans_queue_lock); + spin_lock_init(&xspi->ctrl_reg_lock); + + xspi->queue_state = XSPIPS_QUEUE_STOPPED; + xspi->dev_busy = 0; + + INIT_WORK(&xspi->work, xspips_work_queue); + xspi->workqueue = + create_singlethread_workqueue(dev_name(&pdev->dev)); + if (!xspi->workqueue) { + ret = -ENOMEM; + dev_err(&pdev->dev, "problem initializing queue\n"); + goto clk_notif_unreg; + } + + ret = xspips_start_queue(xspi); + if (ret != 0) { + dev_err(&pdev->dev, "problem starting queue\n"); + goto remove_queue; + } + + ret = spi_register_master(master); + if (ret) { + dev_err(&pdev->dev, "spi_register_master failed\n"); + goto remove_queue; + } + + dev_info(&pdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n", res->start, + (u32 __force)xspi->regs, xspi->irq); + + return ret; + +remove_queue: + (void)xspips_destroy_queue(xspi); +clk_notif_unreg: + clk_notifier_unregister(xspi->devclk, &xspi->clk_rate_change_nb); + clk_disable_unprepare(xspi->devclk); +clk_dis_aper: + clk_disable_unprepare(xspi->aperclk); +remove_master: + spi_master_put(master); + return ret; +} + +/** + * xspips_remove - Remove method for the SPI driver + * @pdev: Pointer to the platform_device structure + * + * This function is called if a device is physically removed from the system or + * if the driver module is being unloaded. It frees all resources allocated to + * the device. + * + * returns: 0 on success and error value on error + */ +static int xspips_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct xspips *xspi = spi_master_get_devdata(master); + int ret = 0; + + ret = xspips_destroy_queue(xspi); + if (ret != 0) + return ret; + + xspips_write(xspi->regs + XSPIPS_ER_OFFSET, ~XSPIPS_ER_ENABLE_MASK); + + clk_notifier_unregister(xspi->devclk, &xspi->clk_rate_change_nb); + clk_disable_unprepare(xspi->devclk); + clk_disable_unprepare(xspi->aperclk); + + spi_unregister_master(master); + spi_master_put(master); + + dev_dbg(&pdev->dev, "remove succeeded\n"); + return 0; + +} + +#ifdef CONFIG_PM_SLEEP +/** + * xspips_suspend - Suspend method for the SPI driver + * @dev: Address of the platform_device structure + * + * This function stops the SPI driver queue and disables the SPI controller + * + * returns: 0 on success and error value on error + */ +static int xspips_suspend(struct device *dev) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct xspips *xspi = spi_master_get_devdata(master); + int ret = 0; + + ret = xspips_stop_queue(xspi); + if (ret != 0) + return ret; + + xspips_write(xspi->regs + XSPIPS_ER_OFFSET, ~XSPIPS_ER_ENABLE_MASK); + + clk_disable(xspi->devclk); + clk_disable(xspi->aperclk); + + dev_dbg(&pdev->dev, "suspend succeeded\n"); + return 0; +} + +/** + * xspips_resume - Resume method for the SPI driver + * @dev: Address of the platform_device structure + * + * This function starts the SPI driver queue and initializes the SPI controller + * + * returns: 0 on success and error value on error + */ +static int xspips_resume(struct device *dev) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct xspips *xspi = spi_master_get_devdata(master); + int ret = 0; + + ret = clk_enable(xspi->aperclk); + if (ret) { + dev_err(dev, "Cannot enable APER clock.\n"); + return ret; + } + + ret = clk_enable(xspi->devclk); + if (ret) { + dev_err(dev, "Cannot enable device clock.\n"); + clk_disable(xspi->aperclk); + return ret; + } + + xspips_init_hw(xspi->regs); + + ret = xspips_start_queue(xspi); + if (ret != 0) { + dev_err(&pdev->dev, "problem starting queue (%d)\n", ret); + return ret; + } + + dev_dbg(&pdev->dev, "resume succeeded\n"); + return 0; +} +#endif /* ! CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(xspips_dev_pm_ops, xspips_suspend, xspips_resume); + +/* Work with hotplug and coldplug */ +MODULE_ALIAS("platform:" XSPIPS_NAME); + +static struct of_device_id xspips_of_match[] = { + { .compatible = "xlnx,ps7-spi-1.00.a", }, + { /* end of table */} +}; +MODULE_DEVICE_TABLE(of, xspips_of_match); + +/* + * xspips_driver - This structure defines the SPI subsystem platform driver + */ +static struct platform_driver xspips_driver = { + .probe = xspips_probe, + .remove = xspips_remove, + .driver = { + .name = XSPIPS_NAME, + .owner = THIS_MODULE, + .of_match_table = xspips_of_match, + .pm = &xspips_dev_pm_ops, + }, +}; + +module_platform_driver(xspips_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx PS SPI driver"); +MODULE_LICENSE("GPL"); + Index: linux-3.12.24-rt38-xilinx/drivers/spi/spi-zynq-qspi.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/spi/spi-zynq-qspi.c 2014-07-20 22:06:37.506286749 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * + * Xilinx PS Quad-SPI (QSPI) controller driver (master mode only) + * + * (c) 2009-2011 Xilinx, Inc. + * + * based on Xilinx PS SPI Driver (xspips.c) + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> + +/* + * Name of this driver + */ +#define DRIVER_NAME "xqspips" + +/* + * Register offset definitions + */ +#define XQSPIPS_CONFIG_OFFSET 0x00 /* Configuration Register, RW */ +#define XQSPIPS_STATUS_OFFSET 0x04 /* Interrupt Status Register, RO */ +#define XQSPIPS_IEN_OFFSET 0x08 /* Interrupt Enable Register, WO */ +#define XQSPIPS_IDIS_OFFSET 0x0C /* Interrupt Disable Reg, WO */ +#define XQSPIPS_IMASK_OFFSET 0x10 /* Interrupt Enabled Mask Reg,RO */ +#define XQSPIPS_ENABLE_OFFSET 0x14 /* Enable/Disable Register, RW */ +#define XQSPIPS_DELAY_OFFSET 0x18 /* Delay Register, RW */ +#define XQSPIPS_TXD_00_00_OFFSET 0x1C /* Transmit 4-byte inst, WO */ +#define XQSPIPS_TXD_00_01_OFFSET 0x80 /* Transmit 1-byte inst, WO */ +#define XQSPIPS_TXD_00_10_OFFSET 0x84 /* Transmit 2-byte inst, WO */ +#define XQSPIPS_TXD_00_11_OFFSET 0x88 /* Transmit 3-byte inst, WO */ +#define XQSPIPS_RXD_OFFSET 0x20 /* Data Receive Register, RO */ +#define XQSPIPS_SIC_OFFSET 0x24 /* Slave Idle Count Register, RW */ +#define XQSPIPS_TX_THRESH_OFFSET 0x28 /* TX FIFO Watermark Reg, RW */ +#define XQSPIPS_RX_THRESH_OFFSET 0x2C /* RX FIFO Watermark Reg, RW */ +#define XQSPIPS_GPIO_OFFSET 0x30 /* GPIO Register, RW */ +#define XQSPIPS_LINEAR_CFG_OFFSET 0xA0 /* Linear Adapter Config Ref, RW */ +#define XQSPIPS_MOD_ID_OFFSET 0xFC /* Module ID Register, RO */ + +/* + * QSPI Configuration Register bit Masks + * + * This register contains various control bits that effect the operation + * of the QSPI controller + */ +#define XQSPIPS_CONFIG_IFMODE_MASK 0x80000000 /* Flash Memory Interface */ +#define XQSPIPS_CONFIG_MANSRT_MASK 0x00010000 /* Manual TX Start */ +#define XQSPIPS_CONFIG_MANSRTEN_MASK 0x00008000 /* Enable Manual TX Mode */ +#define XQSPIPS_CONFIG_SSFORCE_MASK 0x00004000 /* Manual Chip Select */ +#define XQSPIPS_CONFIG_BDRATE_MASK 0x00000038 /* Baud Rate Divisor Mask */ +#define XQSPIPS_CONFIG_CPHA_MASK 0x00000004 /* Clock Phase Control */ +#define XQSPIPS_CONFIG_CPOL_MASK 0x00000002 /* Clock Polarity Control */ +#define XQSPIPS_CONFIG_SSCTRL_MASK 0x00003C00 /* Slave Select Mask */ +#define XQSPIPS_CONFIG_MSTREN_MASK 0x00000001 /* Master Mode */ + +/* + * QSPI Interrupt Registers bit Masks + * + * All the four interrupt registers (Status/Mask/Enable/Disable) have the same + * bit definitions. + */ +#define XQSPIPS_IXR_TXNFULL_MASK 0x00000004 /* QSPI TX FIFO Overflow */ +#define XQSPIPS_IXR_TXFULL_MASK 0x00000008 /* QSPI TX FIFO is full */ +#define XQSPIPS_IXR_RXNEMTY_MASK 0x00000010 /* QSPI RX FIFO Not Empty */ +#define XQSPIPS_IXR_ALL_MASK (XQSPIPS_IXR_TXNFULL_MASK | \ + XQSPIPS_IXR_RXNEMTY_MASK) + +/* + * QSPI Enable Register bit Masks + * + * This register is used to enable or disable the QSPI controller + */ +#define XQSPIPS_ENABLE_ENABLE_MASK 0x00000001 /* QSPI Enable Bit Mask */ + +/* + * QSPI Linear Configuration Register + * + * It is named Linear Configuration but it controls other modes when not in + * linear mode also. + */ +#define XQSPIPS_LCFG_TWO_MEM_MASK 0x40000000 /* LQSPI Two memories Mask */ +#define XQSPIPS_LCFG_SEP_BUS_MASK 0x20000000 /* LQSPI Separate bus Mask */ +#define XQSPIPS_LCFG_U_PAGE_MASK 0x10000000 /* LQSPI Upper Page Mask */ + +#define XQSPIPS_LCFG_DUMMY_SHIFT 8 + +#define XQSPIPS_FAST_READ_QOUT_CODE 0x6B /* read instruction code */ +#define XQSPIPS_FIFO_DEPTH 63 /* FIFO depth in words */ +#define XQSPIPS_RX_THRESHOLD 32 /* Rx FIFO threshold level */ + +/* + * The modebits configurable by the driver to make the SPI support different + * data formats + */ +#define MODEBITS (SPI_CPOL | SPI_CPHA) + +/* + * Definitions for the status of queue + */ +#define XQSPIPS_QUEUE_STOPPED 0 +#define XQSPIPS_QUEUE_RUNNING 1 + +/* + * Definitions of the flash commands + */ +/* Flash opcodes in ascending order */ +#define XQSPIPS_FLASH_OPCODE_WRSR 0x01 /* Write status register */ +#define XQSPIPS_FLASH_OPCODE_PP 0x02 /* Page program */ +#define XQSPIPS_FLASH_OPCODE_NORM_READ 0x03 /* Normal read data bytes */ +#define XQSPIPS_FLASH_OPCODE_WRDS 0x04 /* Write disable */ +#define XQSPIPS_FLASH_OPCODE_RDSR1 0x05 /* Read status register 1 */ +#define XQSPIPS_FLASH_OPCODE_WREN 0x06 /* Write enable */ +#define XQSPIPS_FLASH_OPCODE_BRRD 0x16 /* Bank Register Read */ +#define XQSPIPS_FLASH_OPCODE_BRWR 0x17 /* Bank Register Write */ +#define XQSPIPS_FLASH_OPCODE_EXTADRD 0xC8 /* Micron - Bank Reg Read */ +#define XQSPIPS_FLASH_OPCODE_EXTADWR 0xC5 /* Micron - Bank Reg Write */ +#define XQSPIPS_FLASH_OPCODE_FAST_READ 0x0B /* Fast read data bytes */ +#define XQSPIPS_FLASH_OPCODE_BE_4K 0x20 /* Erase 4KiB block */ +#define XQSPIPS_FLASH_OPCODE_RDSR2 0x35 /* Read status register 2 */ +#define XQSPIPS_FLASH_OPCODE_RDFSR 0x70 /* Read flag status register */ +#define XQSPIPS_FLASH_OPCODE_DUAL_READ 0x3B /* Dual read data bytes */ +#define XQSPIPS_FLASH_OPCODE_BE_32K 0x52 /* Erase 32KiB block */ +#define XQSPIPS_FLASH_OPCODE_QUAD_READ 0x6B /* Quad read data bytes */ +#define XQSPIPS_FLASH_OPCODE_ERASE_SUS 0x75 /* Erase suspend */ +#define XQSPIPS_FLASH_OPCODE_ERASE_RES 0x7A /* Erase resume */ +#define XQSPIPS_FLASH_OPCODE_RDID 0x9F /* Read JEDEC ID */ +#define XQSPIPS_FLASH_OPCODE_BE 0xC7 /* Erase whole flash block */ +#define XQSPIPS_FLASH_OPCODE_SE 0xD8 /* Sector erase (usually 64KB)*/ +#define XQSPIPS_FLASH_OPCODE_QPP 0x32 /* Quad page program */ + +/* + * Macros for the QSPI controller read/write + */ +#define xqspips_read(addr) readl_relaxed(addr) +#define xqspips_write(addr, val) writel_relaxed((val), (addr)) + +/** + * struct xqspips - Defines qspi driver instance + * @workqueue: Queue of all the transfers + * @work: Information about current transfer + * @queue: Head of the queue + * @queue_state: Queue status + * @regs: Virtual address of the QSPI controller registers + * @devclk: Pointer to the peripheral clock + * @aperclk: Pointer to the APER clock + * @clk_rate_change_nb: Notifier block for clock frequency change callback + * @irq: IRQ number + * @speed_hz: Current QSPI bus clock speed in Hz + * @trans_queue_lock: Lock used for accessing transfer queue + * @config_reg_lock: Lock used for accessing configuration register + * @txbuf: Pointer to the TX buffer + * @rxbuf: Pointer to the RX buffer + * @bytes_to_transfer: Number of bytes left to transfer + * @bytes_to_receive: Number of bytes left to receive + * @dev_busy: Device busy flag + * @done: Transfer complete status + * @is_inst: Flag to indicate the first message in a Transfer request + * @is_dual: Flag to indicate whether dual flash memories are used + */ +struct xqspips { + struct workqueue_struct *workqueue; + struct work_struct work; + struct list_head queue; + u8 queue_state; + void __iomem *regs; + struct clk *devclk; + struct clk *aperclk; + struct notifier_block clk_rate_change_nb; + int irq; + u32 speed_hz; + spinlock_t trans_queue_lock; + spinlock_t config_reg_lock; + const void *txbuf; + void *rxbuf; + int bytes_to_transfer; + int bytes_to_receive; + u8 dev_busy; + struct completion done; + bool is_inst; + u32 is_dual; +}; + +/** + * struct xqspips_inst_format - Defines qspi flash instruction format + * @opcode: Operational code of instruction + * @inst_size: Size of the instruction including address bytes + * @offset: Register address where instruction has to be written + */ +struct xqspips_inst_format { + u8 opcode; + u8 inst_size; + u8 offset; +}; + +/* + * List of all the QSPI instructions and its format + */ +static struct xqspips_inst_format flash_inst[] = { + { XQSPIPS_FLASH_OPCODE_WREN, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_WRDS, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_RDSR1, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_RDSR2, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_WRSR, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_RDFSR, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_PP, 4, XQSPIPS_TXD_00_00_OFFSET }, + { XQSPIPS_FLASH_OPCODE_SE, 4, XQSPIPS_TXD_00_00_OFFSET }, + { XQSPIPS_FLASH_OPCODE_BE_32K, 4, XQSPIPS_TXD_00_00_OFFSET }, + { XQSPIPS_FLASH_OPCODE_BE_4K, 4, XQSPIPS_TXD_00_00_OFFSET }, + { XQSPIPS_FLASH_OPCODE_BE, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_ERASE_SUS, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_ERASE_RES, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_RDID, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_NORM_READ, 4, XQSPIPS_TXD_00_00_OFFSET }, + { XQSPIPS_FLASH_OPCODE_FAST_READ, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_DUAL_READ, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_QUAD_READ, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_BRRD, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_BRWR, 2, XQSPIPS_TXD_00_10_OFFSET }, + { XQSPIPS_FLASH_OPCODE_EXTADRD, 1, XQSPIPS_TXD_00_01_OFFSET }, + { XQSPIPS_FLASH_OPCODE_EXTADWR, 2, XQSPIPS_TXD_00_10_OFFSET }, + { XQSPIPS_FLASH_OPCODE_QPP, 4, XQSPIPS_TXD_00_00_OFFSET }, + /* Add all the instructions supported by the flash device */ +}; + +/** + * xqspips_init_hw - Initialize the hardware + * @regs_base: Base address of QSPI controller + * @is_dual: Indicates whether dual memories are used + * + * The default settings of the QSPI controller's configurable parameters on + * reset are + * - Master mode + * - Baud rate divisor is set to 2 + * - Threshold value for TX FIFO not full interrupt is set to 1 + * - Flash memory interface mode enabled + * - Size of the word to be transferred as 8 bit + * This function performs the following actions + * - Disable and clear all the interrupts + * - Enable manual slave select + * - Enable manual start + * - Deselect all the chip select lines + * - Set the size of the word to be transferred as 32 bit + * - Set the little endian mode of TX FIFO and + * - Enable the QSPI controller + */ +static void xqspips_init_hw(void __iomem *regs_base, int is_dual) +{ + u32 config_reg; + + xqspips_write(regs_base + XQSPIPS_ENABLE_OFFSET, + ~XQSPIPS_ENABLE_ENABLE_MASK); + xqspips_write(regs_base + XQSPIPS_IDIS_OFFSET, 0x7F); + + /* Disable linear mode as the boot loader may have used it */ + xqspips_write(regs_base + XQSPIPS_LINEAR_CFG_OFFSET, 0); + + /* Clear the RX FIFO */ + while (xqspips_read(regs_base + XQSPIPS_STATUS_OFFSET) & + XQSPIPS_IXR_RXNEMTY_MASK) + xqspips_read(regs_base + XQSPIPS_RXD_OFFSET); + + xqspips_write(regs_base + XQSPIPS_STATUS_OFFSET , 0x7F); + config_reg = xqspips_read(regs_base + XQSPIPS_CONFIG_OFFSET); + config_reg &= ~(XQSPIPS_CONFIG_MSTREN_MASK | + XQSPIPS_CONFIG_CPOL_MASK | + XQSPIPS_CONFIG_CPHA_MASK | + XQSPIPS_CONFIG_BDRATE_MASK | + XQSPIPS_CONFIG_SSFORCE_MASK | + XQSPIPS_CONFIG_MANSRTEN_MASK | + XQSPIPS_CONFIG_MANSRT_MASK); + config_reg |= (XQSPIPS_CONFIG_MSTREN_MASK | + XQSPIPS_CONFIG_SSFORCE_MASK | + XQSPIPS_CONFIG_IFMODE_MASK); + xqspips_write(regs_base + XQSPIPS_CONFIG_OFFSET, config_reg); + + xqspips_write(regs_base + XQSPIPS_RX_THRESH_OFFSET, + XQSPIPS_RX_THRESHOLD); + if (is_dual == 1) + /* Enable two memories on seperate buses */ + xqspips_write(regs_base + XQSPIPS_LINEAR_CFG_OFFSET, + (XQSPIPS_LCFG_TWO_MEM_MASK | + XQSPIPS_LCFG_SEP_BUS_MASK | + (1 << XQSPIPS_LCFG_DUMMY_SHIFT) | + XQSPIPS_FAST_READ_QOUT_CODE)); +#ifdef CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED + /* Enable two memories on shared bus */ + xqspips_write(regs_base + XQSPIPS_LINEAR_CFG_OFFSET, + (XQSPIPS_LCFG_TWO_MEM_MASK | + (1 << XQSPIPS_LCFG_DUMMY_SHIFT) | + XQSPIPS_FAST_READ_QOUT_CODE)); +#endif + xqspips_write(regs_base + XQSPIPS_ENABLE_OFFSET, + XQSPIPS_ENABLE_ENABLE_MASK); +} + +/** + * xqspips_copy_read_data - Copy data to RX buffer + * @xqspi: Pointer to the xqspips structure + * @data: The 32 bit variable where data is stored + * @size: Number of bytes to be copied from data to RX buffer + */ +static void xqspips_copy_read_data(struct xqspips *xqspi, u32 data, u8 size) +{ + if (xqspi->rxbuf) { + data >>= (4 - size) * 8; + data = le32_to_cpu(data); + memcpy((u8 *)xqspi->rxbuf, &data, size); + xqspi->rxbuf += size; + } + xqspi->bytes_to_receive -= size; + if (xqspi->bytes_to_receive < 0) + xqspi->bytes_to_receive = 0; +} + +/** + * xqspips_copy_write_data - Copy data from TX buffer + * @xqspi: Pointer to the xqspips structure + * @data: Pointer to the 32 bit variable where data is to be copied + * @size: Number of bytes to be copied from TX buffer to data + */ +static void xqspips_copy_write_data(struct xqspips *xqspi, u32 *data, u8 size) +{ + + if (xqspi->txbuf) { + switch (size) { + case 1: + *data = *((u8 *)xqspi->txbuf); + xqspi->txbuf += 1; + *data |= 0xFFFFFF00; + break; + case 2: + *data = *((u16 *)xqspi->txbuf); + xqspi->txbuf += 2; + *data |= 0xFFFF0000; + break; + case 3: + *data = *((u16 *)xqspi->txbuf); + xqspi->txbuf += 2; + *data |= (*((u8 *)xqspi->txbuf) << 16); + xqspi->txbuf += 1; + *data |= 0xFF000000; + break; + case 4: + *data = *((u32 *)xqspi->txbuf); + xqspi->txbuf += 4; + break; + default: + /* This will never execute */ + break; + } + } else { + *data = 0; + } + + xqspi->bytes_to_transfer -= size; + if (xqspi->bytes_to_transfer < 0) + xqspi->bytes_to_transfer = 0; +} + +/** + * xqspips_chipselect - Select or deselect the chip select line + * @qspi: Pointer to the spi_device structure + * @is_on: Select(1) or deselect (0) the chip select line + */ +static void xqspips_chipselect(struct spi_device *qspi, int is_on) +{ + struct xqspips *xqspi = spi_master_get_devdata(qspi->master); + u32 config_reg; + unsigned long flags; + + spin_lock_irqsave(&xqspi->config_reg_lock, flags); + + config_reg = xqspips_read(xqspi->regs + XQSPIPS_CONFIG_OFFSET); + + if (is_on) { + /* Select the slave */ + config_reg &= ~XQSPIPS_CONFIG_SSCTRL_MASK; + config_reg |= (((~(0x0001 << qspi->chip_select)) << 10) & + XQSPIPS_CONFIG_SSCTRL_MASK); + } else { + /* Deselect the slave */ + config_reg |= XQSPIPS_CONFIG_SSCTRL_MASK; + } + + xqspips_write(xqspi->regs + XQSPIPS_CONFIG_OFFSET, config_reg); + + spin_unlock_irqrestore(&xqspi->config_reg_lock, flags); +} + +/** + * xqspips_setup_transfer - Configure QSPI controller for specified transfer + * @qspi: Pointer to the spi_device structure + * @transfer: Pointer to the spi_transfer structure which provides information + * about next transfer setup parameters + * + * Sets the operational mode of QSPI controller for the next QSPI transfer and + * sets the requested clock frequency. + * + * returns: 0 on success and -EINVAL on invalid input parameter + * + * Note: If the requested frequency is not an exact match with what can be + * obtained using the prescalar value, the driver sets the clock frequency which + * is lower than the requested frequency (maximum lower) for the transfer. If + * the requested frequency is higher or lower than that is supported by the QSPI + * controller the driver will set the highest or lowest frequency supported by + * controller. + */ +static int xqspips_setup_transfer(struct spi_device *qspi, + struct spi_transfer *transfer) +{ + struct xqspips *xqspi = spi_master_get_devdata(qspi->master); + u32 config_reg; + u32 req_hz; + u32 baud_rate_val = 0; + unsigned long flags; + int update_baud = 0; + + req_hz = (transfer) ? transfer->speed_hz : qspi->max_speed_hz; + + if (qspi->mode & ~MODEBITS) { + dev_err(&qspi->dev, "%s, unsupported mode bits %x\n", + __func__, qspi->mode & ~MODEBITS); + return -EINVAL; + } + + if (transfer && (transfer->speed_hz == 0)) + req_hz = qspi->max_speed_hz; + + /* Set the clock frequency */ + if (xqspi->speed_hz != req_hz) { + while ((baud_rate_val < 8) && + (clk_get_rate(xqspi->devclk) / (2 << baud_rate_val)) > + req_hz) + baud_rate_val++; + xqspi->speed_hz = req_hz; + update_baud = 1; + } + + spin_lock_irqsave(&xqspi->config_reg_lock, flags); + + config_reg = xqspips_read(xqspi->regs + XQSPIPS_CONFIG_OFFSET); + + /* Set the QSPI clock phase and clock polarity */ + config_reg &= (~XQSPIPS_CONFIG_CPHA_MASK) & + (~XQSPIPS_CONFIG_CPOL_MASK); + if (qspi->mode & SPI_CPHA) + config_reg |= XQSPIPS_CONFIG_CPHA_MASK; + if (qspi->mode & SPI_CPOL) + config_reg |= XQSPIPS_CONFIG_CPOL_MASK; + + if (update_baud) { + config_reg &= 0xFFFFFFC7; + config_reg |= (baud_rate_val << 3); + } + + xqspips_write(xqspi->regs + XQSPIPS_CONFIG_OFFSET, config_reg); + + spin_unlock_irqrestore(&xqspi->config_reg_lock, flags); + + dev_dbg(&qspi->dev, "%s, mode %d, %u bits/w, %u clock speed\n", + __func__, qspi->mode & MODEBITS, qspi->bits_per_word, + xqspi->speed_hz); + + return 0; +} + +/** + * xqspips_setup - Configure the QSPI controller + * @qspi: Pointer to the spi_device structure + * + * Sets the operational mode of QSPI controller for the next QSPI transfer, baud + * rate and divisor value to setup the requested qspi clock. + * + * returns: 0 on success and error value on failure + */ +static int xqspips_setup(struct spi_device *qspi) +{ + + if (qspi->mode & SPI_LSB_FIRST) + return -EINVAL; + + if (!qspi->max_speed_hz) + return -EINVAL; + + if (!qspi->bits_per_word) + qspi->bits_per_word = 32; + + return xqspips_setup_transfer(qspi, NULL); +} + +/** + * xqspips_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible + * @xqspi: Pointer to the xqspips structure + * @size: Size of the fifo to be filled + */ +static void xqspips_fill_tx_fifo(struct xqspips *xqspi, u32 size) +{ + u32 fifocount; + + for (fifocount = 0; (fifocount < size) && + (xqspi->bytes_to_transfer >= 4); fifocount++) { + if (xqspi->txbuf) { + xqspips_write(xqspi->regs + XQSPIPS_TXD_00_00_OFFSET, + *((u32 *)xqspi->txbuf)); + xqspi->txbuf += 4; + } else { + xqspips_write(xqspi->regs + XQSPIPS_TXD_00_00_OFFSET, + 0x00); + } + xqspi->bytes_to_transfer -= 4; + if (xqspi->bytes_to_transfer < 0) + xqspi->bytes_to_transfer = 0; + } +} + +/** + * xqspips_irq - Interrupt service routine of the QSPI controller + * @irq: IRQ number + * @dev_id: Pointer to the xqspi structure + * + * This function handles TX empty only. + * On TX empty interrupt this function reads the received data from RX FIFO and + * fills the TX FIFO if there is any data remaining to be transferred. + * + * returns: IRQ_HANDLED always + */ +static irqreturn_t xqspips_irq(int irq, void *dev_id) +{ + struct xqspips *xqspi = dev_id; + u32 intr_status; + u8 offset[3] = {XQSPIPS_TXD_00_01_OFFSET, XQSPIPS_TXD_00_10_OFFSET, + XQSPIPS_TXD_00_11_OFFSET}; + u32 rxcount; + u32 rxindex = 0; + + intr_status = xqspips_read(xqspi->regs + XQSPIPS_STATUS_OFFSET); + xqspips_write(xqspi->regs + XQSPIPS_STATUS_OFFSET , intr_status); + xqspips_write(xqspi->regs + XQSPIPS_IDIS_OFFSET, + XQSPIPS_IXR_ALL_MASK); + + if ((intr_status & XQSPIPS_IXR_TXNFULL_MASK) || + (intr_status & XQSPIPS_IXR_RXNEMTY_MASK)) { + /* This bit is set when Tx FIFO has < THRESHOLD entries. We have + the THRESHOLD value set to 1, so this bit indicates Tx FIFO + is empty */ + u32 data; + + rxcount = xqspi->bytes_to_receive - xqspi->bytes_to_transfer; + rxcount = (rxcount % 4) ? ((rxcount/4) + 1) : (rxcount/4); + + /* Read out the data from the RX FIFO */ + while ((rxindex < rxcount) && + (rxindex < XQSPIPS_RX_THRESHOLD)) { + + if (xqspi->bytes_to_receive < 4 && !xqspi->is_dual) { + data = xqspips_read(xqspi->regs + + XQSPIPS_RXD_OFFSET); + xqspips_copy_read_data(xqspi, data, + xqspi->bytes_to_receive); + } else { + if (xqspi->rxbuf) { + (*(u32 *)xqspi->rxbuf) = + xqspips_read(xqspi->regs + + XQSPIPS_RXD_OFFSET); + xqspi->rxbuf += 4; + } else { + data = xqspips_read(xqspi->regs + + XQSPIPS_RXD_OFFSET); + } + xqspi->bytes_to_receive -= 4; + if (xqspi->bytes_to_receive < 0) + xqspi->bytes_to_receive = 0; + } + rxindex++; + } + + if (xqspi->bytes_to_transfer) { + if (xqspi->bytes_to_transfer >= 4) { + /* There is more data to send */ + xqspips_fill_tx_fifo(xqspi, + XQSPIPS_RX_THRESHOLD); + } else { + int tmp; + tmp = xqspi->bytes_to_transfer; + xqspips_copy_write_data(xqspi, &data, + xqspi->bytes_to_transfer); + if (xqspi->is_dual) + xqspips_write(xqspi->regs + + XQSPIPS_TXD_00_00_OFFSET, data); + else + xqspips_write(xqspi->regs + + offset[tmp - 1], data); + } + xqspips_write(xqspi->regs + XQSPIPS_IEN_OFFSET, + XQSPIPS_IXR_ALL_MASK); + } else { + /* If transfer and receive is completed then only send + * complete signal */ + if (xqspi->bytes_to_receive) { + /* There is still some data to be received. + Enable Rx not empty interrupt */ + xqspips_write(xqspi->regs + XQSPIPS_IEN_OFFSET, + XQSPIPS_IXR_ALL_MASK); + } else { + xqspips_write(xqspi->regs + XQSPIPS_IDIS_OFFSET, + XQSPIPS_IXR_ALL_MASK); + complete(&xqspi->done); + } + } + } + + return IRQ_HANDLED; +} + +/** + * xqspips_start_transfer - Initiates the QSPI transfer + * @qspi: Pointer to the spi_device structure + * @transfer: Pointer to the spi_transfer structure which provide information + * about next transfer parameters + * + * This function fills the TX FIFO, starts the QSPI transfer, and waits for the + * transfer to be completed. + * + * returns: Number of bytes transferred in the last transfer + */ +static int xqspips_start_transfer(struct spi_device *qspi, + struct spi_transfer *transfer) +{ + struct xqspips *xqspi = spi_master_get_devdata(qspi->master); + u32 data = 0; + u8 instruction = 0; + u8 index; + struct xqspips_inst_format *curr_inst; + + xqspi->txbuf = transfer->tx_buf; + xqspi->rxbuf = transfer->rx_buf; + xqspi->bytes_to_transfer = transfer->len; + xqspi->bytes_to_receive = transfer->len; + + if (xqspi->txbuf) + instruction = *(u8 *)xqspi->txbuf; + + INIT_COMPLETION(xqspi->done); + if (instruction && xqspi->is_inst) { + for (index = 0 ; index < ARRAY_SIZE(flash_inst); index++) + if (instruction == flash_inst[index].opcode) + break; + + /* Instruction might have already been transmitted. This is a + * 'data only' transfer */ + if (index == ARRAY_SIZE(flash_inst)) + goto xfer_data; + + curr_inst = &flash_inst[index]; + + /* Get the instruction */ + data = 0; + xqspips_copy_write_data(xqspi, &data, + curr_inst->inst_size); + + /* Write the instruction to LSB of the FIFO. The core is + * designed such that it is not necessary to check whether the + * write FIFO is full before writing. However, write would be + * delayed if the user tries to write when write FIFO is full + */ + xqspips_write(xqspi->regs + curr_inst->offset, data); + goto xfer_start; + } + +xfer_data: + /* In case of Fast, Dual and Quad reads, transmit the instruction first. + * Address and dummy byte will be transmitted in interrupt handler, + * after instruction is transmitted */ + if (((xqspi->is_inst == 0) && (xqspi->bytes_to_transfer >= 4)) || + ((xqspi->bytes_to_transfer >= 4) && + (instruction != XQSPIPS_FLASH_OPCODE_FAST_READ) && + (instruction != XQSPIPS_FLASH_OPCODE_DUAL_READ) && + (instruction != XQSPIPS_FLASH_OPCODE_QUAD_READ))) + xqspips_fill_tx_fifo(xqspi, XQSPIPS_FIFO_DEPTH); + +xfer_start: + xqspips_write(xqspi->regs + XQSPIPS_IEN_OFFSET, + XQSPIPS_IXR_ALL_MASK); + + wait_for_completion(&xqspi->done); + + return (transfer->len) - (xqspi->bytes_to_transfer); +} + +/** + * xqspips_work_queue - Get the request from queue to perform transfers + * @work: Pointer to the work_struct structure + */ +static void xqspips_work_queue(struct work_struct *work) +{ + struct xqspips *xqspi = container_of(work, struct xqspips, work); + unsigned long flags; +#ifdef CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED + u32 lqspi_cfg_reg; +#endif + + spin_lock_irqsave(&xqspi->trans_queue_lock, flags); + xqspi->dev_busy = 1; + + /* Check if list is empty or queue is stoped */ + if (list_empty(&xqspi->queue) || + xqspi->queue_state == XQSPIPS_QUEUE_STOPPED) { + xqspi->dev_busy = 0; + spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags); + return; + } + + /* Keep requesting transfer till list is empty */ + while (!list_empty(&xqspi->queue)) { + struct spi_message *msg; + struct spi_device *qspi; + struct spi_transfer *transfer = NULL; + unsigned cs_change = 1; + int status = 0; + + msg = container_of(xqspi->queue.next, struct spi_message, + queue); + list_del_init(&msg->queue); + spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags); + qspi = msg->spi; + +#ifdef CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED + lqspi_cfg_reg = xqspips_read(xqspi->regs + + XQSPIPS_LINEAR_CFG_OFFSET); + if (qspi->master->flags & SPI_MASTER_U_PAGE) + lqspi_cfg_reg |= XQSPIPS_LCFG_U_PAGE_MASK; + else + lqspi_cfg_reg &= ~XQSPIPS_LCFG_U_PAGE_MASK; + xqspips_write(xqspi->regs + XQSPIPS_LINEAR_CFG_OFFSET, + lqspi_cfg_reg); +#endif + + list_for_each_entry(transfer, &msg->transfers, transfer_list) { + if (transfer->bits_per_word || transfer->speed_hz) { + status = xqspips_setup_transfer(qspi, transfer); + if (status < 0) + break; + } + + /* Select the chip if required */ + if (cs_change) { + xqspips_chipselect(qspi, 1); + xqspi->is_inst = 1; + } + + cs_change = transfer->cs_change; + + if (!transfer->tx_buf && !transfer->rx_buf && + transfer->len) { + status = -EINVAL; + break; + } + + /* Request the transfer */ + if (transfer->len) { + status = xqspips_start_transfer(qspi, transfer); + xqspi->is_inst = 0; + } + + if (status != transfer->len) { + if (status > 0) + status = -EMSGSIZE; + break; + } + msg->actual_length += status; + status = 0; + + if (transfer->delay_usecs) + udelay(transfer->delay_usecs); + + if (cs_change) + /* Deselect the chip */ + xqspips_chipselect(qspi, 0); + + if (transfer->transfer_list.next == &msg->transfers) + break; + } + + msg->status = status; + msg->complete(msg->context); + + xqspips_setup_transfer(qspi, NULL); + + if (!(status == 0 && cs_change)) + xqspips_chipselect(qspi, 0); + + spin_lock_irqsave(&xqspi->trans_queue_lock, flags); + } + xqspi->dev_busy = 0; + spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags); +} + +/** + * xqspips_transfer - Add a new transfer request at the tail of work queue + * @qspi: Pointer to the spi_device structure + * @message: Pointer to the spi_transfer structure which provides information + * about next transfer parameters + * + * returns: 0 on success, -EINVAL on invalid input parameter and + * -ESHUTDOWN if queue is stopped by module unload function + */ +static int xqspips_transfer(struct spi_device *qspi, + struct spi_message *message) +{ + struct xqspips *xqspi = spi_master_get_devdata(qspi->master); + struct spi_transfer *transfer; + unsigned long flags; + + if (xqspi->queue_state == XQSPIPS_QUEUE_STOPPED) + return -ESHUTDOWN; + + message->actual_length = 0; + message->status = -EINPROGRESS; + + /* Check each transfer's parameters */ + list_for_each_entry(transfer, &message->transfers, transfer_list) { + if (!transfer->tx_buf && !transfer->rx_buf && transfer->len) + return -EINVAL; + /* QSPI controller supports only 32 bit transfers whereas higher + * layer drivers request 8 bit transfers. Re-visit at a later + * time */ + /* if (bits_per_word != 32) + return -EINVAL; */ + } + + spin_lock_irqsave(&xqspi->trans_queue_lock, flags); + list_add_tail(&message->queue, &xqspi->queue); + if (!xqspi->dev_busy) + queue_work(xqspi->workqueue, &xqspi->work); + spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags); + + return 0; +} + +/** + * xqspips_start_queue - Starts the queue of the QSPI driver + * @xqspi: Pointer to the xqspips structure + * + * returns: 0 on success and -EBUSY if queue is already running or device is + * busy + */ +static inline int xqspips_start_queue(struct xqspips *xqspi) +{ + unsigned long flags; + + spin_lock_irqsave(&xqspi->trans_queue_lock, flags); + + if (xqspi->queue_state == XQSPIPS_QUEUE_RUNNING || xqspi->dev_busy) { + spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags); + return -EBUSY; + } + + xqspi->queue_state = XQSPIPS_QUEUE_RUNNING; + spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags); + + return 0; +} + +/** + * xqspips_stop_queue - Stops the queue of the QSPI driver + * @xqspi: Pointer to the xqspips structure + * + * This function waits till queue is empty and then stops the queue. + * Maximum time out is set to 5 seconds. + * + * returns: 0 on success and -EBUSY if queue is not empty or device is busy + */ +static inline int xqspips_stop_queue(struct xqspips *xqspi) +{ + unsigned long flags; + unsigned limit = 500; + int ret = 0; + + if (xqspi->queue_state != XQSPIPS_QUEUE_RUNNING) + return ret; + + spin_lock_irqsave(&xqspi->trans_queue_lock, flags); + + while ((!list_empty(&xqspi->queue) || xqspi->dev_busy) && limit--) { + spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags); + msleep(10); + spin_lock_irqsave(&xqspi->trans_queue_lock, flags); + } + + if (!list_empty(&xqspi->queue) || xqspi->dev_busy) + ret = -EBUSY; + + if (ret == 0) + xqspi->queue_state = XQSPIPS_QUEUE_STOPPED; + + spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags); + + return ret; +} + +/** + * xqspips_destroy_queue - Destroys the queue of the QSPI driver + * @xqspi: Pointer to the xqspips structure + * + * returns: 0 on success and error value on failure + */ +static inline int xqspips_destroy_queue(struct xqspips *xqspi) +{ + int ret; + + ret = xqspips_stop_queue(xqspi); + if (ret != 0) + return ret; + + destroy_workqueue(xqspi->workqueue); + + return 0; +} + +static int xqspips_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + switch (event) { + case PRE_RATE_CHANGE: + /* if a rate change is announced we need to check whether we can + * maintain the current frequency by changing the clock + * dividers. And we may have to suspend operation and return + * after the rate change or its abort + */ + return NOTIFY_OK; + case POST_RATE_CHANGE: + return NOTIFY_OK; + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +#ifdef CONFIG_PM_SLEEP +/** + * xqspips_suspend - Suspend method for the QSPI driver + * @_dev: Address of the platform_device structure + * + * This function stops the QSPI driver queue and disables the QSPI controller + * + * returns: 0 on success and error value on error + */ +static int xqspips_suspend(struct device *_dev) +{ + struct platform_device *pdev = container_of(_dev, + struct platform_device, dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct xqspips *xqspi = spi_master_get_devdata(master); + int ret = 0; + + ret = xqspips_stop_queue(xqspi); + if (ret != 0) + return ret; + + xqspips_write(xqspi->regs + XQSPIPS_ENABLE_OFFSET, + ~XQSPIPS_ENABLE_ENABLE_MASK); + + clk_disable(xqspi->devclk); + clk_disable(xqspi->aperclk); + + dev_dbg(&pdev->dev, "suspend succeeded\n"); + return 0; +} + +/** + * xqspips_resume - Resume method for the QSPI driver + * @dev: Address of the platform_device structure + * + * The function starts the QSPI driver queue and initializes the QSPI controller + * + * returns: 0 on success and error value on error + */ +static int xqspips_resume(struct device *dev) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct xqspips *xqspi = spi_master_get_devdata(master); + int ret = 0; + + ret = clk_enable(xqspi->aperclk); + if (ret) { + dev_err(dev, "Cannot enable APER clock.\n"); + return ret; + } + + ret = clk_enable(xqspi->devclk); + if (ret) { + dev_err(dev, "Cannot enable device clock.\n"); + clk_disable(xqspi->aperclk); + return ret; + } + + xqspips_init_hw(xqspi->regs, xqspi->is_dual); + + ret = xqspips_start_queue(xqspi); + if (ret != 0) { + dev_err(&pdev->dev, "problem starting queue (%d)\n", ret); + return ret; + } + + dev_dbg(&pdev->dev, "resume succeeded\n"); + return 0; +} +#endif /* ! CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(xqspips_dev_pm_ops, xqspips_suspend, xqspips_resume); + +/** + * xqspips_probe - Probe method for the QSPI driver + * @pdev: Pointer to the platform_device structure + * + * This function initializes the driver data structures and the hardware. + * + * returns: 0 on success and error value on failure + */ +static int xqspips_probe(struct platform_device *pdev) +{ + int ret = 0; + struct spi_master *master; + struct xqspips *xqspi; + struct resource *res; + + master = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); + if (master == NULL) + return -ENOMEM; + + xqspi = spi_master_get_devdata(master); + master->dev.of_node = pdev->dev.of_node; + platform_set_drvdata(pdev, master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xqspi->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xqspi->regs)) { + ret = PTR_ERR(xqspi->regs); + goto remove_master; + } + + xqspi->irq = platform_get_irq(pdev, 0); + if (xqspi->irq < 0) { + ret = -ENXIO; + dev_err(&pdev->dev, "irq resource not found\n"); + goto remove_master; + } + ret = devm_request_irq(&pdev->dev, xqspi->irq, xqspips_irq, + 0, pdev->name, xqspi); + if (ret != 0) { + ret = -ENXIO; + dev_err(&pdev->dev, "request_irq failed\n"); + goto remove_master; + } + + if (of_property_read_u32(pdev->dev.of_node, "is-dual", &xqspi->is_dual)) + dev_warn(&pdev->dev, "couldn't determine configuration info " + "about dual memories. defaulting to single memory\n"); + + xqspi->aperclk = devm_clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(xqspi->aperclk)) { + dev_err(&pdev->dev, "aper_clk clock not found.\n"); + ret = PTR_ERR(xqspi->aperclk); + goto remove_master; + } + + xqspi->devclk = devm_clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(xqspi->devclk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xqspi->devclk); + goto remove_master; + } + + ret = clk_prepare_enable(xqspi->aperclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + goto remove_master; + } + + ret = clk_prepare_enable(xqspi->devclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable device clock.\n"); + goto clk_dis_aper; + } + + xqspi->clk_rate_change_nb.notifier_call = xqspips_clk_notifier_cb; + xqspi->clk_rate_change_nb.next = NULL; + if (clk_notifier_register(xqspi->devclk, &xqspi->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); + + + /* QSPI controller initializations */ + xqspips_init_hw(xqspi->regs, xqspi->is_dual); + + init_completion(&xqspi->done); + + ret = of_property_read_u32(pdev->dev.of_node, "num-chip-select", + (u32 *)&master->num_chipselect); + if (ret < 0) { + dev_err(&pdev->dev, "couldn't determine num-chip-select\n"); + goto clk_unreg_notif; + } + + master->setup = xqspips_setup; + master->transfer = xqspips_transfer; + master->flags = SPI_MASTER_QUAD_MODE; + + xqspi->speed_hz = clk_get_rate(xqspi->devclk) / 2; + + xqspi->dev_busy = 0; + + INIT_LIST_HEAD(&xqspi->queue); + spin_lock_init(&xqspi->trans_queue_lock); + spin_lock_init(&xqspi->config_reg_lock); + + xqspi->queue_state = XQSPIPS_QUEUE_STOPPED; + xqspi->dev_busy = 0; + + INIT_WORK(&xqspi->work, xqspips_work_queue); + xqspi->workqueue = + create_singlethread_workqueue(dev_name(&pdev->dev)); + if (!xqspi->workqueue) { + ret = -ENOMEM; + dev_err(&pdev->dev, "problem initializing queue\n"); + goto clk_unreg_notif; + } + + ret = xqspips_start_queue(xqspi); + if (ret != 0) { + dev_err(&pdev->dev, "problem starting queue\n"); + goto remove_queue; + } + + ret = spi_register_master(master); + if (ret) { + dev_err(&pdev->dev, "spi_register_master failed\n"); + goto remove_queue; + } + + dev_info(&pdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n", res->start, + (u32 __force)xqspi->regs, xqspi->irq); + + return ret; + +remove_queue: + (void)xqspips_destroy_queue(xqspi); +clk_unreg_notif: + clk_notifier_unregister(xqspi->devclk, &xqspi->clk_rate_change_nb); + clk_disable_unprepare(xqspi->devclk); +clk_dis_aper: + clk_disable_unprepare(xqspi->aperclk); +remove_master: + spi_master_put(master); + return ret; +} + +/** + * xqspips_remove - Remove method for the QSPI driver + * @pdev: Pointer to the platform_device structure + * + * This function is called if a device is physically removed from the system or + * if the driver module is being unloaded. It frees all resources allocated to + * the device. + * + * returns: 0 on success and error value on failure + */ +static int xqspips_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct xqspips *xqspi = spi_master_get_devdata(master); + int ret = 0; + + ret = xqspips_destroy_queue(xqspi); + if (ret != 0) + return ret; + + xqspips_write(xqspi->regs + XQSPIPS_ENABLE_OFFSET, + ~XQSPIPS_ENABLE_ENABLE_MASK); + + clk_notifier_unregister(xqspi->devclk, &xqspi->clk_rate_change_nb); + clk_disable_unprepare(xqspi->devclk); + clk_disable_unprepare(xqspi->aperclk); + + spi_unregister_master(master); + spi_master_put(master); + + + dev_dbg(&pdev->dev, "remove succeeded\n"); + return 0; +} + +/* Work with hotplug and coldplug */ +MODULE_ALIAS("platform:" DRIVER_NAME); + +static struct of_device_id xqspips_of_match[] = { + { .compatible = "xlnx,ps7-qspi-1.00.a", }, + { /* end of table */} +}; +MODULE_DEVICE_TABLE(of, xqspips_of_match); + +/* + * xqspips_driver - This structure defines the QSPI platform driver + */ +static struct platform_driver xqspips_driver = { + .probe = xqspips_probe, + .remove = xqspips_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = xqspips_of_match, + .pm = &xqspips_dev_pm_ops, + }, +}; + +module_platform_driver(xqspips_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx PS QSPI driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/Kconfig 2014-07-20 22:06:37.518286551 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# APF driver configuration +# + +menuconfig XILINX_APF + tristate "Xilinx APF Accelerator driver" + depends on ARCH_ZYNQ + default n + help + Select if you want to include APF accelerator driver + +config XILINX_DMA_APF + bool "Xilinx APF DMA engines support" + depends on XILINX_APF + select DMA_ENGINE + help + Enable support for the Xilinx APF DMA controllers. Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/Makefile 2014-07-20 22:06:37.523286469 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# gpio support: dedicated expander chips, etc + +ccflags-$(CONFIG_DEBUG_XILINX_APF) += -DDEBUG +ccflags-$(CONFIG_XILINX_APF) += -Idrivers/dma + +obj-$(CONFIG_XILINX_APF) += xlnk.o +obj-$(CONFIG_XILINX_APF) += xlnk-eng.o +obj-$(CONFIG_XILINX_DMA_APF) += xilinx-dma-apf.o + Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/xilinx-dma-apf.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/xilinx-dma-apf.c 2014-07-20 22:06:37.537286238 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx AXI DMA Engine support + * + * Copyright (C) 2010 Xilinx, Inc. All rights reserved. + * + * Description: + * This driver supports Xilinx AXI DMA engine: + * . Axi DMA engine, it does transfers between memory and device. It can be + * configured to have one channel or two channels. If configured as two + * channels, one is for transmit to device and another is for receive from + * device. + * + * This 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. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/dmapool.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/dma-attrs.h> +#include <linux/pagemap.h> +#include <linux/device.h> +#include <linux/types.h> +#include <linux/pm.h> +#include <linux/fs.h> +#include <linux/gfp.h> +#include <linux/string.h> +#include <linux/uaccess.h> +#include <asm/cacheflush.h> +#include <linux/sched.h> + +#include "xilinx-dma-apf.h" + +#include "xlnk-event-tracer-type.h" +#include "xlnk.h" + +static DEFINE_MUTEX(dma_list_mutex); +static LIST_HEAD(dma_device_list); +/* IO accessors */ +#define DMA_OUT(addr, val) (iowrite32(val, addr)) +#define DMA_IN(addr) (ioread32(addr)) + +static int unpin_user_pages(struct scatterlist *sglist, unsigned int cnt); +/* Driver functions */ +static void xdma_clean_bd(struct xdma_desc_hw *bd) +{ + bd->src_addr = 0x0; + bd->control = 0x0; + bd->status = 0x0; + bd->app[0] = 0x0; + bd->app[1] = 0x0; + bd->app[2] = 0x0; + bd->app[3] = 0x0; + bd->app[4] = 0x0; + bd->dmahead = 0x0; + bd->sw_flag = 0x0; +} + +static int dma_is_running(struct xdma_chan *chan) +{ + return !(DMA_IN(&chan->regs->sr) & XDMA_SR_HALTED_MASK) && + (DMA_IN(&chan->regs->cr) & XDMA_CR_RUNSTOP_MASK); +} + +static int dma_is_idle(struct xdma_chan *chan) +{ + return DMA_IN(&chan->regs->sr) & XDMA_SR_IDLE_MASK; +} + +static void dma_halt(struct xdma_chan *chan) +{ + DMA_OUT(&chan->regs->cr, + (DMA_IN(&chan->regs->cr) & ~XDMA_CR_RUNSTOP_MASK)); +} + +static void dma_start(struct xdma_chan *chan) +{ + DMA_OUT(&chan->regs->cr, + (DMA_IN(&chan->regs->cr) | XDMA_CR_RUNSTOP_MASK)); +} + +static int dma_init(struct xdma_chan *chan) +{ + int loop = XDMA_RESET_LOOP; + + DMA_OUT(&chan->regs->cr, + (DMA_IN(&chan->regs->cr) | XDMA_CR_RESET_MASK)); + + /* Wait for the hardware to finish reset + */ + while (loop) { + if (!(DMA_IN(&chan->regs->cr) & XDMA_CR_RESET_MASK)) + break; + + loop -= 1; + } + + if (!loop) + return 1; + + return 0; +} + +static int xdma_alloc_chan_descriptors(struct xdma_chan *chan) +{ + int i; + u8 *ptr; + + /* + * We need the descriptor to be aligned to 64bytes + * for meeting Xilinx DMA specification requirement. + */ + ptr = (u8 *)dma_alloc_coherent(chan->dev, + (sizeof(struct xdma_desc_hw) * XDMA_MAX_BD_CNT), + &chan->bd_phys_addr, + GFP_KERNEL); + + if (!ptr) { + dev_err(chan->dev, + "unable to allocate channel %d descriptor pool\n", + chan->id); + return -ENOMEM; + } + + memset(ptr, 0, (sizeof(struct xdma_desc_hw) * XDMA_MAX_BD_CNT)); + chan->bd_cur = 0; + chan->bd_tail = 0; + chan->bd_used = 0; + chan->bd_chain_size = sizeof(struct xdma_desc_hw) * XDMA_MAX_BD_CNT; + + /* + * Pre allocate all the channels. + */ + for (i = 0; i < XDMA_MAX_BD_CNT; i++) { + chan->bds[i] = (struct xdma_desc_hw *) + (ptr + (sizeof(struct xdma_desc_hw) * i)); + chan->bds[i]->next_desc = chan->bd_phys_addr + + (sizeof(struct xdma_desc_hw) * + ((i + 1) % XDMA_MAX_BD_CNT)); + } + + /* there is at least one descriptor free to be allocated */ + return 0; +} + +static void xdma_free_chan_resources(struct xdma_chan *chan) +{ + dev_dbg(chan->dev, "Free all channel resources.\n"); + dma_free_coherent(chan->dev, (sizeof(struct xdma_desc_hw) * + XDMA_MAX_BD_CNT), chan->bds[0], chan->bd_phys_addr); +} + +static void xilinx_chan_desc_reinit(struct xdma_chan *chan) +{ + struct xdma_desc_hw *desc; + unsigned int start, end; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + start = 0; + end = XDMA_MAX_BD_CNT; + + while (start < end) { + desc = chan->bds[start]; + xdma_clean_bd(desc); + start++; + } + /* Re-initialize bd_cur and bd_tail values */ + chan->bd_cur = 0; + chan->bd_tail = 0; + chan->bd_used = 0; + spin_unlock_irqrestore(&chan->lock, flags); +} + +static void xilinx_chan_desc_cleanup(struct xdma_chan *chan) +{ + struct xdma_head *dmahead; + struct xdma_desc_hw *desc; + struct completion *cmp; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); +#define XDMA_BD_STS_RXEOF_MASK 0x04000000 + desc = chan->bds[chan->bd_cur]; + while ((desc->status & XDMA_BD_STS_ALL_MASK)) { + if ((desc->status & XDMA_BD_STS_RXEOF_MASK) && + !(desc->dmahead)) { + pr_info("ERROR: premature EOF on DMA\n"); + dma_init(chan); /* reset the dma HW */ + while (!(desc->dmahead)) { + xdma_clean_bd(desc); + chan->bd_used--; + chan->bd_cur++; + if (chan->bd_cur >= XDMA_MAX_BD_CNT) + chan->bd_cur = 0; + desc = chan->bds[chan->bd_cur]; + } + } + if (desc->dmahead) { + + if ((desc->sw_flag & XDMA_BD_SF_POLL_MODE_MASK)) + if (!(desc->sw_flag & XDMA_BD_SF_SW_DONE_MASK)) + break; + + dmahead = (struct xdma_head *)desc->dmahead; + cmp = (struct completion *)&dmahead->cmp; + if (dmahead->nappwords_o) + memcpy(dmahead->appwords_o, desc->app, + dmahead->nappwords_o * sizeof(u32)); + + if (chan->poll_mode) + cmp->done = 1; + else + complete(cmp); + } + xdma_clean_bd(desc); + chan->bd_used--; + chan->bd_cur++; + if (chan->bd_cur >= XDMA_MAX_BD_CNT) + chan->bd_cur = 0; + desc = chan->bds[chan->bd_cur]; + } + spin_unlock_irqrestore(&chan->lock, flags); +} + +static void xdma_err_tasklet(unsigned long data) +{ + struct xdma_chan *chan = (struct xdma_chan *)data; + + if (chan->err) { + /* If reset failed, need to hard reset + * Channel is no longer functional + */ + if (!dma_init(chan)) + chan->err = 0; + else + dev_err(chan->dev, + "DMA channel reset failed, please reset system\n"); + } + + rmb(); + xilinx_chan_desc_cleanup(chan); + + xilinx_chan_desc_reinit(chan); +} + +static void xdma_tasklet(unsigned long data) +{ + struct xdma_chan *chan = (struct xdma_chan *)data; + + rmb(); + xilinx_chan_desc_cleanup(chan); +} + +static void dump_cur_bd(struct xdma_chan *chan) +{ + u32 index; + + index = (((u32)DMA_IN(&chan->regs->cdr)) - chan->bd_phys_addr) / + sizeof(struct xdma_desc_hw); + + dev_err(chan->dev, "cur bd @ %08x\n", (u32)DMA_IN(&chan->regs->cdr)); + dev_err(chan->dev, " buf = 0x%08x\n", chan->bds[index]->src_addr); + dev_err(chan->dev, " ctrl = 0x%08x\n", chan->bds[index]->control); + dev_err(chan->dev, " sts = 0x%08x\n", chan->bds[index]->status); + dev_err(chan->dev, " next = 0x%08x\n", chan->bds[index]->next_desc); +} + +static irqreturn_t xdma_rx_intr_handler(int irq, void *data) +{ + struct xdma_chan *chan = data; + u32 stat; + + stat = DMA_IN(&chan->regs->sr); + + if (!(stat & XDMA_XR_IRQ_ALL_MASK)) { + return IRQ_NONE; + } + + /* Ack the interrupts */ + DMA_OUT(&chan->regs->sr, (stat & XDMA_XR_IRQ_ALL_MASK)); + + if (stat & XDMA_XR_IRQ_ERROR_MASK) { + dev_err(chan->dev, "Channel %s has errors %x, cdr %x tdr %x\n", + chan->name, (unsigned int)stat, + (unsigned int)DMA_IN(&chan->regs->cdr), + (unsigned int)DMA_IN(&chan->regs->tdr)); + + dump_cur_bd(chan); + + chan->err = 1; + tasklet_schedule(&chan->dma_err_tasklet); + } + + if (!(chan->poll_mode) && ((stat & XDMA_XR_IRQ_DELAY_MASK) || + (stat & XDMA_XR_IRQ_IOC_MASK))) + tasklet_schedule(&chan->tasklet); + + return IRQ_HANDLED; +} + +static irqreturn_t xdma_tx_intr_handler(int irq, void *data) +{ + struct xdma_chan *chan = data; + u32 stat; + + stat = DMA_IN(&chan->regs->sr); + + if (!(stat & XDMA_XR_IRQ_ALL_MASK)) { + return IRQ_NONE; + } + + /* Ack the interrupts */ + DMA_OUT(&chan->regs->sr, (stat & XDMA_XR_IRQ_ALL_MASK)); + + if (stat & XDMA_XR_IRQ_ERROR_MASK) { + dev_err(chan->dev, "Channel %s has errors %x, cdr %x tdr %x\n", + chan->name, (unsigned int)stat, + (unsigned int)DMA_IN(&chan->regs->cdr), + (unsigned int)DMA_IN(&chan->regs->tdr)); + + dump_cur_bd(chan); + + chan->err = 1; + tasklet_schedule(&chan->dma_err_tasklet); + } + + if (!(chan->poll_mode) && ((stat & XDMA_XR_IRQ_DELAY_MASK) || + (stat & XDMA_XR_IRQ_IOC_MASK))) + tasklet_schedule(&chan->tasklet); + + return IRQ_HANDLED; +} + +static void xdma_chan_remove(struct xdma_chan *chan) +{ + dma_halt(chan); + xdma_free_chan_resources(chan); + free_irq(chan->irq, chan); + kfree(chan); +} + +static void xdma_start_transfer(struct xdma_chan *chan, + int start_index, + int end_index) +{ + dma_addr_t cur_phys; + dma_addr_t tail_phys; + u32 regval; + + if (chan->err) + return; + + cur_phys = chan->bd_phys_addr + (start_index * + sizeof(struct xdma_desc_hw)); + tail_phys = chan->bd_phys_addr + (end_index * + sizeof(struct xdma_desc_hw)); + /* If hardware is busy, move the tail & return */ + if (dma_is_running(chan) || dma_is_idle(chan)) { + /* Update tail ptr register and start the transfer */ + DMA_OUT(&chan->regs->tdr, tail_phys); + xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_KICKOFF); + return; + } + + DMA_OUT(&chan->regs->cdr, cur_phys); + + dma_start(chan); + + /* Enable interrupts */ + regval = DMA_IN(&chan->regs->cr); + regval |= (chan->poll_mode ? XDMA_XR_IRQ_ERROR_MASK + : XDMA_XR_IRQ_ALL_MASK); + DMA_OUT(&chan->regs->cr, regval); + + /* Update tail ptr register and start the transfer */ + DMA_OUT(&chan->regs->tdr, tail_phys); + xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_KICKOFF); +} + +static int xdma_setup_hw_desc(struct xdma_chan *chan, + struct xdma_head *dmahead, + struct scatterlist *sgl, + unsigned int sg_len, + enum dma_data_direction direction, + unsigned int nappwords_i, + u32 *appwords_i) +{ + struct xdma_desc_hw *bd = NULL; + size_t copy; + struct scatterlist *sg; + size_t sg_used; + dma_addr_t dma_src; + int i, start_index = -1, end_index1 = 0, end_index2 = -1; + int status; + unsigned long flags; + unsigned int bd_used_saved; + + if (!chan) + return -ENODEV; + + /* if we almost run out of bd, try to recycle some */ + if ((chan->poll_mode) && (chan->bd_used >= XDMA_BD_CLEANUP_THRESHOLD)) + xilinx_chan_desc_cleanup(chan); + + spin_lock_irqsave(&chan->lock, flags); + + bd_used_saved = chan->bd_used; + /* + * Build transactions using information in the scatter gather list + */ + for_each_sg(sgl, sg, sg_len, i) { + sg_used = 0; + + /* Loop until the entire scatterlist entry is used */ + while (sg_used < sg_dma_len(sg)) { + /* Allocate the link descriptor from DMA pool */ + bd = chan->bds[chan->bd_tail]; + if ((bd->control) & (XDMA_BD_STS_ACTUAL_LEN_MASK)) { + end_index2 = chan->bd_tail; + status = -ENOMEM; + /* If first was not set, then we failed to + * allocate the very first descriptor, + * and we're done */ + if (start_index == -1) + goto out_unlock; + else + goto out_clean; + } + /* + * Calculate the maximum number of bytes to transfer, + * making sure it is less than the DMA controller limit + */ + copy = min((size_t)(sg_dma_len(sg) - sg_used), + (size_t)chan->max_len); + /* + * Only the src address for DMA + */ + dma_src = sg_dma_address(sg) + sg_used; + bd->src_addr = dma_src; + + /* Fill in the descriptor */ + bd->control = copy; + + /* + * If this is not the first descriptor, chain the + * current descriptor after the previous descriptor + * + * For the first DMA_TO_DEVICE transfer, set SOP + */ + if (start_index == -1) { + start_index = chan->bd_tail; + + if (nappwords_i) + memcpy(bd->app, appwords_i, + nappwords_i * sizeof(u32)); + + if (direction == DMA_TO_DEVICE) + bd->control |= XDMA_BD_SOP; + } + + sg_used += copy; + end_index2 = chan->bd_tail; + chan->bd_tail++; + chan->bd_used++; + if (chan->bd_tail >= XDMA_MAX_BD_CNT) { + end_index1 = XDMA_MAX_BD_CNT; + chan->bd_tail = 0; + } + } + } + + if (start_index == -1) { + status = -EINVAL; + goto out_unlock; + } + + bd->dmahead = (u32) dmahead; + bd->sw_flag = chan->poll_mode ? XDMA_BD_SF_POLL_MODE_MASK : 0; + dmahead->last_bd_index = end_index2; + + if (direction == DMA_TO_DEVICE) + bd->control |= XDMA_BD_EOP; + + wmb(); + + xdma_start_transfer(chan, start_index, end_index2); + + spin_unlock_irqrestore(&chan->lock, flags); + + return 0; + +out_clean: + if (!end_index1) { + for (i = start_index; i < end_index2; i++) + xdma_clean_bd(chan->bds[i]); + } else { + /* clean till the end of bd list first, and then 2nd end */ + for (i = start_index; i < end_index1; i++) + xdma_clean_bd(chan->bds[i]); + + end_index1 = 0; + for (i = end_index1; i < end_index2; i++) + xdma_clean_bd(chan->bds[i]); + } + /* Move the bd_tail back */ + chan->bd_tail = start_index; + chan->bd_used = bd_used_saved; + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); + + return status; +} + +#define XDMA_SGL_MAX_LEN XDMA_MAX_BD_CNT +static struct scatterlist sglist_array[XDMA_SGL_MAX_LEN]; + +/* + * create minimal length scatter gather list for physically contiguous buffer + * that starts at phy_buf and has length phy_buf_len bytes + */ +static unsigned int phy_buf_to_sgl(void *phy_buf, unsigned int phy_buf_len, + struct scatterlist **sgl) +{ + unsigned int sgl_cnt = 0; + struct scatterlist *sgl_head; + unsigned int dma_len; + + if (!phy_buf || !phy_buf_len) { + pr_err("phy_buf is NULL or phy_buf_len = 0\n"); + return sgl_cnt; + } + + *sgl = sglist_array; + sgl_head = *sgl; + + while (phy_buf_len > 0) { + + sgl_cnt++; + if (sgl_cnt > XDMA_SGL_MAX_LEN) + return 0; + + dma_len = (phy_buf_len > XDMA_MAX_TRANS_LEN) ? + XDMA_MAX_TRANS_LEN : phy_buf_len; + + sg_dma_address(sgl_head) = (dma_addr_t)phy_buf; + sg_dma_len(sgl_head) = dma_len; + sgl_head = sg_next(sgl_head); + + phy_buf += dma_len; + phy_buf_len -= dma_len; + + } + return sgl_cnt; +} + +/* merge sg list, sgl, with length sgl_len, to sgl_merged, to save dma bds */ +static unsigned int sgl_merge(struct scatterlist *sgl, unsigned int sgl_len, + struct scatterlist **sgl_merged) +{ + struct scatterlist *sghead, *sgend, *sgnext, *sg_merged_head; + unsigned int sg_visited_cnt = 0, sg_merged_num = 0; + unsigned int dma_len = 0; + + *sgl_merged = sglist_array; + sg_merged_head = *sgl_merged; + sghead = sgl; + + while (sghead && (sg_visited_cnt < sgl_len)) { + + dma_len = sg_dma_len(sghead); + sgend = sghead; + sg_visited_cnt++; + sgnext = sg_next(sgend); + + while (sgnext && (sg_visited_cnt < sgl_len)) { + + if ((sg_dma_address(sgend) + sg_dma_len(sgend)) != + sg_dma_address(sgnext)) + break; + + if (dma_len + sg_dma_len(sgnext) >= XDMA_MAX_TRANS_LEN) + break; + + sgend = sgnext; + dma_len += sg_dma_len(sgend); + sg_visited_cnt++; + sgnext = sg_next(sgnext); + + } + + sg_merged_num++; + if (sg_merged_num > XDMA_SGL_MAX_LEN) + return 0; + + memcpy(sg_merged_head, sghead, sizeof(struct scatterlist)); + + sg_dma_len(sg_merged_head) = dma_len; + + sg_merged_head = sg_next(sg_merged_head); + sghead = sg_next(sgend); + } + + return sg_merged_num; +} + +static struct page *mapped_pages[XDMA_MAX_BD_CNT]; +static int pin_user_pages(unsigned long uaddr, + unsigned int ulen, + int write, + struct scatterlist **scatterpp, + unsigned int *cntp, + unsigned int user_flags) +{ + int status; + struct mm_struct *mm = current->mm; + struct task_struct *curr_task = current; + unsigned int first_page; + unsigned int last_page; + unsigned int num_pages; + struct scatterlist *sglist; + + unsigned int pgidx; + unsigned int pglen; + unsigned int pgoff; + unsigned int sublen; + + first_page = uaddr / PAGE_SIZE; + last_page = (uaddr + ulen - 1) / PAGE_SIZE; + num_pages = last_page - first_page + 1; + xlnk_record_event(XLNK_ET_KERNEL_BEFORE_GET_USER_PAGES); + down_read(&mm->mmap_sem); + status = get_user_pages(curr_task, mm, uaddr, num_pages, write, 1, + mapped_pages, NULL); + up_read(&mm->mmap_sem); + xlnk_record_event(XLNK_ET_KERNEL_AFTER_GET_USER_PAGES); + + if (status == num_pages) { + sglist = kcalloc(num_pages, + sizeof(struct scatterlist), + GFP_KERNEL); + if (sglist == NULL) { + pr_err("%s: kcalloc failed to create sg list\n", + __func__); + return -ENOMEM; + } + sg_init_table(sglist, num_pages); + sublen = 0; + for (pgidx = 0; pgidx < status; pgidx++) { + if (pgidx == 0 && num_pages != 1) { + pgoff = uaddr & (~PAGE_MASK); + pglen = PAGE_SIZE - pgoff; + } else if (pgidx == 0 && num_pages == 1) { + pgoff = uaddr & (~PAGE_MASK); + pglen = ulen; + } else if (pgidx == num_pages - 1) { + pgoff = 0; + pglen = ulen - sublen; + } else { + pgoff = 0; + pglen = PAGE_SIZE; + } + + sublen += pglen; + + sg_set_page(&sglist[pgidx], + mapped_pages[pgidx], + pglen, pgoff); + + sg_dma_len(&sglist[pgidx]) = pglen; + } + + *scatterpp = sglist; + *cntp = num_pages; + + return 0; + } else { + + for (pgidx = 0; pgidx < status; pgidx++) { + page_cache_release(mapped_pages[pgidx]); + } + return -ENOMEM; + } +} + +static int unpin_user_pages(struct scatterlist *sglist, unsigned int cnt) +{ + struct page *pg; + unsigned int i; + + if (!sglist) + return 0; + + for (i = 0; i < cnt; i++) { + pg = sg_page(sglist + i); + if (pg) { + page_cache_release(pg); + } + } + + kfree(sglist); + return 0; +} + +struct xdma_chan *xdma_request_channel(char *name) +{ + int i; + struct xdma_device *device, *tmp; + + mutex_lock(&dma_list_mutex); + list_for_each_entry_safe(device, tmp, &dma_device_list, node) { + for (i = 0; i < device->channel_count; i++) { + if (device->chan[i]->client_count) + continue; + if (!strcmp(device->chan[i]->name, name)) { + device->chan[i]->client_count++; + mutex_unlock(&dma_list_mutex); + return device->chan[i]; + } + } + } + mutex_unlock(&dma_list_mutex); + return NULL; +} +EXPORT_SYMBOL(xdma_request_channel); + +void xdma_release_channel(struct xdma_chan *chan) +{ + mutex_lock(&dma_list_mutex); + if (!chan->client_count) { + mutex_unlock(&dma_list_mutex); + return; + } + chan->client_count--; + dma_halt(chan); + xilinx_chan_desc_reinit(chan); + mutex_unlock(&dma_list_mutex); +} +EXPORT_SYMBOL(xdma_release_channel); + +void xdma_release_all_channels(void) +{ + int i; + struct xdma_device *device, *tmp; + + list_for_each_entry_safe(device, tmp, &dma_device_list, node) { + for (i = 0; i < device->channel_count; i++) { + if (device->chan[i]->client_count) { + dma_halt(device->chan[i]); + xilinx_chan_desc_reinit(device->chan[i]); + device->chan[i]->client_count = 0; + pr_info("%s: chan %s freed\n", + __func__, + device->chan[i]->name); + } + } + } +} +EXPORT_SYMBOL(xdma_release_all_channels); + +int xdma_submit(struct xdma_chan *chan, + void *userbuf, + unsigned int size, + unsigned int nappwords_i, + u32 *appwords_i, + unsigned int nappwords_o, + unsigned int user_flags, + struct xdma_head **dmaheadpp) +{ + struct xdma_head *dmahead; + struct scatterlist *sglist, *sglist_dma; + unsigned int sgcnt, sgcnt_dma; + enum dma_data_direction dmadir; + int status; + void *kaddr; + DEFINE_DMA_ATTRS(attrs); + + + xlnk_record_event(XLNK_ET_KERNEL_ENTER_DMA_SUBMIT); + dmahead = kmalloc(sizeof(struct xdma_head), GFP_KERNEL); + if (!dmahead) + return -ENOMEM; + + memset(dmahead, 0, sizeof(struct xdma_head)); + + dmahead->chan = chan; + dmahead->userbuf = userbuf; + dmahead->size = size; + dmahead->dmadir = chan->direction; + dmahead->userflag = user_flags; + dmadir = chan->direction; + if (user_flags & CF_FLAG_PHYSICALLY_CONTIGUOUS) { + /* + * convert physically contiguous buffer into + * minimal length sg list + */ + sgcnt = phy_buf_to_sgl(userbuf, size, &sglist); + if (!sgcnt) + return -ENOMEM; + + sglist_dma = sglist; + sgcnt_dma = sgcnt; + if (user_flags & CF_FLAG_CACHE_FLUSH_INVALIDATE) { + kaddr = phys_to_virt((phys_addr_t)userbuf); + dmac_map_area(kaddr, size, DMA_TO_DEVICE); + outer_clean_range((phys_addr_t)userbuf, + (u32)userbuf + size); + } + } else { + /* pin user pages is monitored separately */ + xlnk_record_event(XLNK_ET_KERNEL_BEFORE_PIN_USER_PAGE); + status = pin_user_pages((unsigned long)userbuf, size, + dmadir != DMA_TO_DEVICE, + &sglist, &sgcnt, user_flags); + if (status < 0) { + pr_err("pin_user_pages failed\n"); + return status; + } + xlnk_record_event(XLNK_ET_KERNEL_AFTER_PIN_USER_PAGE); + xlnk_record_event(XLNK_ET_KERNEL_BEFORE_DMA_MAP_SG); + if (!(user_flags & CF_FLAG_CACHE_FLUSH_INVALIDATE)) + dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); + + status = get_dma_ops(chan->dev)->map_sg(chan->dev, sglist, + sgcnt, dmadir, &attrs); + if (!status) { + pr_err("dma_map_sg failed\n"); + unpin_user_pages(sglist, sgcnt); + return -ENOMEM; + } + xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_MAP_SG); + + /* merge sg list to save dma bds */ + sgcnt_dma = sgl_merge(sglist, sgcnt, &sglist_dma); + if (!sgcnt_dma) { + get_dma_ops(chan->dev)->unmap_sg(chan->dev, sglist, + sgcnt, dmadir, &attrs); + unpin_user_pages(sglist, sgcnt); + return -ENOMEM; + } + } + dmahead->sglist = sglist; + dmahead->sgcnt = sgcnt; + + /* skipping config */ + init_completion(&dmahead->cmp); + + if (nappwords_i > XDMA_MAX_APPWORDS) + nappwords_i = XDMA_MAX_APPWORDS; + + if (nappwords_o > XDMA_MAX_APPWORDS) + nappwords_o = XDMA_MAX_APPWORDS; + + dmahead->nappwords_o = nappwords_o; + + xlnk_record_event(XLNK_ET_KERNEL_BEFORE_DMA_SETUP_BD); + status = xdma_setup_hw_desc(chan, dmahead, sglist_dma, sgcnt_dma, + dmadir, nappwords_i, appwords_i); + xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_SETUP_BD); + if (status) { + pr_err("setup hw desc failed\n"); + if (!(user_flags & CF_FLAG_PHYSICALLY_CONTIGUOUS)) { + get_dma_ops(chan->dev)->unmap_sg(chan->dev, sglist, + sgcnt, dmadir, &attrs); + unpin_user_pages(sglist, sgcnt); + } + + return -ENOMEM; + } + + *dmaheadpp = dmahead; + + xlnk_record_event(XLNK_ET_KERNEL_LEAVE_DMA_SUBMIT); + return 0; +} +EXPORT_SYMBOL(xdma_submit); + +int xdma_wait(struct xdma_head *dmahead, unsigned int user_flags) +{ + struct xdma_chan *chan = dmahead->chan; + void *kaddr, *paddr; + int size; + DEFINE_DMA_ATTRS(attrs); + xlnk_record_event(XLNK_ET_KERNEL_ENTER_DMA_WAIT); + + if (chan->poll_mode) { + xilinx_chan_desc_cleanup(chan); + } else + wait_for_completion(&dmahead->cmp); + + if (!(user_flags & CF_FLAG_PHYSICALLY_CONTIGUOUS)) { + xlnk_record_event(XLNK_ET_KERNEL_BEFORE_DMA_UNMAP_SG); + if (!(user_flags & CF_FLAG_CACHE_FLUSH_INVALIDATE)) + dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); + + get_dma_ops(chan->dev)->unmap_sg(chan->dev, dmahead->sglist, + dmahead->sgcnt, + dmahead->dmadir, &attrs); + xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_UNMAP_SG); + + unpin_user_pages(dmahead->sglist, dmahead->sgcnt); + } else { + if (user_flags & CF_FLAG_CACHE_FLUSH_INVALIDATE) { + paddr = dmahead->userbuf; + size = dmahead->size; + kaddr = phys_to_virt((phys_addr_t)paddr); + outer_inv_range((phys_addr_t)paddr, (u32)paddr + size); + dmac_unmap_area(kaddr, size, DMA_FROM_DEVICE); + } + } + xlnk_record_event(XLNK_ET_KERNEL_LEAVE_DMA_WAIT); + return 0; +} +EXPORT_SYMBOL(xdma_wait); + +int xdma_getconfig(struct xdma_chan *chan, + unsigned char *irq_thresh, + unsigned char *irq_delay) +{ + *irq_thresh = (DMA_IN(&chan->regs->cr) >> XDMA_COALESCE_SHIFT) & 0xff; + *irq_delay = (DMA_IN(&chan->regs->cr) >> XDMA_DELAY_SHIFT) & 0xff; + return 0; +} +EXPORT_SYMBOL(xdma_getconfig); + +int xdma_setconfig(struct xdma_chan *chan, + unsigned char irq_thresh, + unsigned char irq_delay) +{ + unsigned long val; + + if (dma_is_running(chan)) + return -EBUSY; + + val = DMA_IN(&chan->regs->cr); + val &= ~((0xff << XDMA_COALESCE_SHIFT) | + (0xff << XDMA_DELAY_SHIFT)); + val |= ((irq_thresh << XDMA_COALESCE_SHIFT) | + (irq_delay << XDMA_DELAY_SHIFT)); + + DMA_OUT(&chan->regs->cr, val); + return 0; +} +EXPORT_SYMBOL(xdma_setconfig); + +/* Brute-force probing for xilinx DMA + */ +static int xdma_probe(struct platform_device *pdev) +{ + struct xdma_device *xdev; + struct resource *res; + int err, i, j; + struct xdma_chan *chan; + struct dma_device_config *dma_config; + int dma_chan_dir; + int dma_chan_reg_offset; + + pr_info("%s: probe dma %x, nres %d, id %d\n", __func__, + (unsigned int)&pdev->dev, + pdev->num_resources, pdev->id); + + xdev = devm_kzalloc(&pdev->dev, sizeof(struct xdma_device), GFP_KERNEL); + if (!xdev) { + dev_err(&pdev->dev, "Not enough memory for device\n"); + return -ENOMEM; + } + xdev->dev = &(pdev->dev); + + dma_config = (struct dma_device_config *)xdev->dev->platform_data; + if (dma_config->channel_count < 1 || dma_config->channel_count > 2) + return -EFAULT; + + /* Get the memory resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xdev->regs = devm_ioremap_resource(&pdev->dev, res); + if (!xdev->regs) { + dev_err(&pdev->dev, "unable to iomap registers\n"); + return -EFAULT; + } + + dev_info(&pdev->dev, "AXIDMA device %d physical base address=%pa\n", + pdev->id, &res->start); + dev_info(&pdev->dev, "AXIDMA device %d remapped to %pa\n", + pdev->id, &xdev->regs); + + /* Allocate the channels */ + + dev_info(&pdev->dev, "has %d channel(s)\n", dma_config->channel_count); + for (i = 0; i < dma_config->channel_count; i++) { + chan = devm_kzalloc(&pdev->dev, sizeof(*chan), GFP_KERNEL); + if (!chan) { + dev_err(&pdev->dev, "no free memory for DMA channel\n"); + return -ENOMEM; + } + + dma_chan_dir = strcmp(dma_config->channel_config[i].type, + "axi-dma-mm2s-channel") ? + DMA_FROM_DEVICE : DMA_TO_DEVICE; + dma_chan_reg_offset = dma_chan_dir == DMA_TO_DEVICE ? 0 : 0x30; + + /* Initialize channel parameters */ + chan->id = i; + chan->regs = xdev->regs + dma_chan_reg_offset; + /* chan->regs = xdev->regs; */ + chan->dev = xdev->dev; + chan->max_len = XDMA_MAX_TRANS_LEN; + chan->direction = dma_chan_dir; + sprintf(chan->name, "%schan%d", dev_name(&pdev->dev), chan->id); + pr_info(" chan%d name: %s\n", chan->id, chan->name); + pr_info(" chan%d direction: %s\n", chan->id, + dma_chan_dir == DMA_FROM_DEVICE ? + "FROM_DEVICE" : "TO_DEVICE"); + + spin_lock_init(&chan->lock); + tasklet_init(&chan->tasklet, xdma_tasklet, (unsigned long)chan); + tasklet_init(&chan->dma_err_tasklet, xdma_err_tasklet, + (unsigned long)chan); + + xdev->chan[chan->id] = chan; + + /* The IRQ resource */ + chan->irq = dma_config->channel_config[i].irq; + if (chan->irq <= 0) { + pr_err("get_resource for IRQ for dev %d failed\n", + pdev->id); + return -ENODEV; + } + + err = devm_request_irq(&pdev->dev, + chan->irq, + dma_chan_dir == DMA_TO_DEVICE ? + xdma_tx_intr_handler : xdma_rx_intr_handler, + IRQF_SHARED, + pdev->name, + chan); + if (err) { + dev_err(&pdev->dev, "unable to request IRQ\n"); + return err; + } + pr_info(" chan%d irq: %d\n", chan->id, chan->irq); + + chan->poll_mode = dma_config->channel_config[i].poll_mode; + pr_info(" chan%d poll mode: %s\n", chan->id, + chan->poll_mode ? "on" : "off"); + + /* Allocate channel BD's */ + err = xdma_alloc_chan_descriptors(xdev->chan[chan->id]); + if (err) { + dev_err(&pdev->dev, "unable to allocate BD's\n"); + return -ENOMEM; + } + pr_info(" chan%d bd ring @ 0x%08x (size: 0x%08x bytes)\n", + chan->id, chan->bd_phys_addr, + chan->bd_chain_size); + + err = dma_init(xdev->chan[chan->id]); + if (err) { + dev_err(&pdev->dev, "DMA init failed\n"); + /* FIXME Check this - unregister all chan resources */ + for (j = 0; j <= i; j++) + xdma_free_chan_resources(xdev->chan[j]); + return -EIO; + } + } + xdev->channel_count = dma_config->channel_count; + + /* Add the DMA device to the global list */ + mutex_lock(&dma_list_mutex); + list_add_tail(&xdev->node, &dma_device_list); + mutex_unlock(&dma_list_mutex); + + platform_set_drvdata(pdev, xdev); + + return 0; +} + +static int xdma_remove(struct platform_device *pdev) +{ + int i; + struct xdma_device *xdev = platform_get_drvdata(pdev); + + /* Remove the DMA device from the global list */ + mutex_lock(&dma_list_mutex); + list_del(&xdev->node); + mutex_unlock(&dma_list_mutex); + + for (i = 0; i < XDMA_MAX_CHANS_PER_DEVICE; i++) { + if (xdev->chan[i]) + xdma_chan_remove(xdev->chan[i]); + } + + return 0; +} + +static struct platform_driver xdma_driver = { + .probe = xdma_probe, + .remove = xdma_remove, + .driver = { + .owner = THIS_MODULE, + .name = "xilinx-axidma", + }, +}; + +module_platform_driver(xdma_driver); + +MODULE_DESCRIPTION("Xilinx DMA driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/xilinx-dma-apf.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/xilinx-dma-apf.h 2014-07-20 22:06:37.545286106 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx AXI DMA Engine support + * + * Copyright (C) 2010 Xilinx, Inc. All rights reserved. + * + * This 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 __XILINX_DMA_APF_H +#define __XILINX_DMA_APF_H + +/* ioctls */ +#include <linux/ioctl.h> + +/* tasklet */ +#include <linux/interrupt.h> + +/* dma stuff */ +#include <linux/dma-mapping.h> + +#define XDMA_IOC_MAGIC 'X' +#define XDMA_IOCRESET _IO(XDMA_IOC_MAGIC, 0) +#define XDMA_IOCREQUEST _IOWR(XDMA_IOC_MAGIC, 1, unsigned long) +#define XDMA_IOCRELEASE _IOWR(XDMA_IOC_MAGIC, 2, unsigned long) +#define XDMA_IOCSUBMIT _IOWR(XDMA_IOC_MAGIC, 3, unsigned long) +#define XDMA_IOCWAIT _IOWR(XDMA_IOC_MAGIC, 4, unsigned long) +#define XDMA_IOCGETCONFIG _IOWR(XDMA_IOC_MAGIC, 5, unsigned long) +#define XDMA_IOCSETCONFIG _IOWR(XDMA_IOC_MAGIC, 6, unsigned long) +#define XDMA_IOC_MAXNR 6 + +/* Specific hardware configuration-related constants + */ +#define XDMA_RESET_LOOP 1000000 +#define XDMA_HALT_LOOP 1000000 +#define XDMA_NO_CHANGE 0xFFFF; + +/* General register bits definitions + */ +#define XDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */ +#define XDMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA engine */ + +#define XDMA_SR_HALTED_MASK 0x00000001 /* DMA channel halted */ +#define XDMA_SR_IDLE_MASK 0x00000002 /* DMA channel idle */ + +#define XDMA_SR_ERR_INTERNAL_MASK 0x00000010/* Datamover internal err */ +#define XDMA_SR_ERR_SLAVE_MASK 0x00000020 /* Datamover slave err */ +#define XDMA_SR_ERR_DECODE_MASK 0x00000040 /* Datamover decode err */ +#define XDMA_SR_ERR_SG_INT_MASK 0x00000100 /* SG internal err */ +#define XDMA_SR_ERR_SG_SLV_MASK 0x00000200 /* SG slave err */ +#define XDMA_SR_ERR_SG_DEC_MASK 0x00000400 /* SG decode err */ +#define XDMA_SR_ERR_ALL_MASK 0x00000770 /* All errors */ + +#define XDMA_XR_IRQ_IOC_MASK 0x00001000 /* Completion interrupt */ +#define XDMA_XR_IRQ_DELAY_MASK 0x00002000 /* Delay interrupt */ +#define XDMA_XR_IRQ_ERROR_MASK 0x00004000 /* Error interrupt */ +#define XDMA_XR_IRQ_ALL_MASK 0x00007000 /* All interrupts */ + +#define XDMA_XR_DELAY_MASK 0xFF000000 /* Delay timeout counter */ +#define XDMA_XR_COALESCE_MASK 0x00FF0000 /* Coalesce counter */ + +#define XDMA_DELAY_SHIFT 24 +#define XDMA_COALESCE_SHIFT 16 + +#define XDMA_DELAY_MAX 0xFF /**< Maximum delay counter value */ +#define XDMA_COALESCE_MAX 0xFF /**< Maximum coalescing counter value */ + +/* BD definitions for Axi DMA + */ +#define XDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF +#define XDMA_BD_STS_COMPL_MASK 0x80000000 +#define XDMA_BD_STS_ERR_MASK 0x70000000 +#define XDMA_BD_STS_ALL_MASK 0xF0000000 + +/* DMA BD special bits definitions + */ +#define XDMA_BD_SOP 0x08000000 /* Start of packet bit */ +#define XDMA_BD_EOP 0x04000000 /* End of packet bit */ + +/* BD Software Flag definitions for Axi DMA + */ +#define XDMA_BD_SF_POLL_MODE_MASK 0x00000002 +#define XDMA_BD_SF_SW_DONE_MASK 0x00000001 + +/* driver defines */ +#define XDMA_MAX_BD_CNT 2048 +#define XDMA_MAX_CHANS_PER_DEVICE 2 +#define XDMA_MAX_TRANS_LEN 0x7FF000 +#define XDMA_MAX_APPWORDS 5 +#define XDMA_BD_CLEANUP_THRESHOLD ((XDMA_MAX_BD_CNT * 8) / 10) + +/* Platform data definition until ARM supports device tree */ +struct dma_channel_config { + char *type; + unsigned int include_dre; + unsigned int datawidth; + unsigned int max_burst_len; + unsigned int irq; + unsigned int poll_mode; + unsigned int lite_mode; +}; +struct dma_device_config { + char *type; + unsigned int include_sg; + unsigned int sg_include_stscntrl_strm; /* dma only */ + unsigned int channel_count; + struct dma_channel_config *channel_config; +}; + +struct xdma_desc_hw { + u32 next_desc; /* 0x00 */ + u32 pad1; /* 0x04 */ + u32 src_addr; /* 0x08 */ + u32 pad2; /* 0x0c */ + u32 addr_vsize; /* 0x10 */ + u32 hsize; /* 0x14 */ + u32 control; /* 0x18 */ + u32 status; /* 0x1c */ + u32 app[5]; /* 0x20 */ + u32 dmahead; + u32 sw_flag; /* 0x38 */ + u32 Reserved0; +} __aligned(64); + +/* shared by all Xilinx DMA engines */ +struct xdma_regs { + u32 cr; /* 0x00 Control Register */ + u32 sr; /* 0x04 Status Register */ + u32 cdr; /* 0x08 Current Descriptor Register */ + u32 pad1; + u32 tdr; /* 0x10 Tail Descriptor Register */ + u32 pad2; + u32 src; /* 0x18 Source Address Register (cdma) */ + u32 pad3; + u32 dst; /* 0x20 Destination Address Register (cdma) */ + u32 pad4; + u32 btt_ref; /* 0x28 Bytes To Transfer (cdma) or + park_ref (vdma) */ + u32 version; /* 0x2c version (vdma) */ +}; + +/* Per DMA specific operations should be embedded in the channel structure */ +struct xdma_chan { + char name[64]; + struct xdma_regs __iomem *regs; + struct device *dev; /* The dma device */ + struct xdma_desc_hw *bds[XDMA_MAX_BD_CNT]; + dma_addr_t bd_phys_addr; + u32 bd_chain_size; + int bd_cur; + int bd_tail; + unsigned int bd_used; /* # of BDs passed to hw chan */ + enum dma_data_direction direction; /* Transfer direction */ + int id; /* Channel ID */ + int irq; /* Channel IRQ */ + int poll_mode; /* Poll mode turned on? */ + spinlock_t lock; /* Descriptor operation lock */ + struct tasklet_struct tasklet; /* Cleanup work after irq */ + struct tasklet_struct dma_err_tasklet; /* Cleanup work after irq */ + int max_len; /* Maximum len per transfer */ + int err; /* Channel has errors */ + int client_count; +}; + +struct xdma_device { + void __iomem *regs; + struct device *dev; + struct list_head node; + struct xdma_chan *chan[XDMA_MAX_CHANS_PER_DEVICE]; + u8 channel_count; +}; + +struct xdma_head { + void *userbuf; + unsigned int size; + unsigned int dmaflag; + enum dma_data_direction dmadir; + void *sglist; + unsigned int sgcnt; + struct completion cmp; + struct xdma_chan *chan; + unsigned int nappwords_o; + u32 appwords_o[XDMA_MAX_APPWORDS]; + unsigned int userflag; + u32 last_bd_index; +}; + +struct xdma_chan *xdma_request_channel(char *name); +void xdma_release_channel(struct xdma_chan *chan); +void xdma_release_all_channels(void); +int xdma_submit(struct xdma_chan *chan, + void *userbuf, + unsigned int size, + unsigned int nappwords_i, + u32 *appwords_i, + unsigned int nappwords_o, + unsigned int user_flags, + struct xdma_head **dmaheadpp); +int xdma_wait(struct xdma_head *dmahead, unsigned int user_flags); +int xdma_getconfig(struct xdma_chan *chan, + unsigned char *irq_thresh, + unsigned char *irq_delay); +int xdma_setconfig(struct xdma_chan *chan, + unsigned char irq_thresh, + unsigned char irq_delay); + +#endif Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk.c 2014-07-20 22:06:37.559285875 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * xlnk.c + * + * Xilinx Accelerator driver support. + * + * Copyright (C) 2010 Xilinx Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* ----------------------------------- Host OS */ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/gfp.h> +#include <linux/mm.h> +#include <asm/cacheflush.h> +#include <linux/io.h> + +#include <linux/string.h> + +#include <linux/uaccess.h> + +#include <linux/dmaengine.h> +#include <linux/completion.h> +#include <linux/wait.h> + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/cdev.h> + +#include <linux/sched.h> +#include <linux/pagemap.h> +#include <linux/errno.h> /* error codes */ +#include <linux/dma-mapping.h> /* dma */ + + +#include "xlnk-ioctl.h" +#include "xlnk-event-tracer-type.h" +#include "xlnk.h" + +#ifdef CONFIG_XILINX_DMA_APF +#include "xilinx-dma-apf.h" +#endif + +#ifdef CONFIG_XILINX_MCDMA +#include "xdma-if.h" +#include "xdma.h" + +static void xdma_if_device_release(struct device *op) +{ +} + +#endif + +#define DRIVER_NAME "xlnk" +#define DRIVER_VERSION "0.2" + +static struct platform_device *xlnk_pdev; +static struct device *xlnk_dev; + +static struct cdev xlnk_cdev; + +static struct class *xlnk_class; + +static s32 driver_major; + +static char *driver_name = DRIVER_NAME; + +static void *xlnk_dev_buf; +static ssize_t xlnk_dev_size; +static int xlnk_dev_vmas; + +#define XLNK_BUF_POOL_SIZE 256 +static void **xlnk_bufpool; +static unsigned int xlnk_bufpool_size = XLNK_BUF_POOL_SIZE; +static dma_addr_t xlnk_phyaddr[XLNK_BUF_POOL_SIZE]; +static size_t xlnk_buflen[XLNK_BUF_POOL_SIZE]; +static unsigned int xlnk_bufcacheable[XLNK_BUF_POOL_SIZE]; + + +static int xlnk_open(struct inode *ip, struct file *filp); /* Open */ +static int xlnk_release(struct inode *ip, struct file *filp); /* Release */ +static long xlnk_ioctl(struct file *filp, unsigned int code, + unsigned long args); +static ssize_t xlnk_read(struct file *filp, char __user *buf, + size_t count, loff_t *offp); +static ssize_t xlnk_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offp); +static int xlnk_mmap(struct file *filp, struct vm_area_struct *vma); +static void xlnk_vma_open(struct vm_area_struct *vma); +static void xlnk_vma_close(struct vm_area_struct *vma); + +static int xlnk_init_bufpool(void); + +static void xlnk_start_benchmark_counter(void); +static int xlnk_dump_events(unsigned long buf); +static int xlnk_get_event_size(unsigned long buf); + +static int xlnk_shutdown(unsigned long buf); +static int xlnk_recover_resource(unsigned long buf); + +static const struct file_operations xlnk_fops = { + .open = xlnk_open, + .release = xlnk_release, + .read = xlnk_read, + .write = xlnk_write, + .unlocked_ioctl = xlnk_ioctl, + .mmap = xlnk_mmap, +}; + +#define MAX_XLNK_DMAS 16 + +struct xlnk_device_pack { + char name[64]; + struct platform_device pdev; + struct resource res[8]; + +#ifdef CONFIG_XILINX_DMA_APF + struct dma_channel_config dma_chan_cfg[4]; /* for xidane dma only */ + struct dma_device_config dma_dev_cfg; /* for xidane dma only */ +#endif + +#ifdef CONFIG_XILINX_MCDMA + struct xdma_device_info mcdma_dev_cfg; /* for mcdma only */ +#endif + +}; + +static struct xlnk_device_pack *xlnk_devpacks[16]; +static void xlnk_devpacks_init(void) +{ + unsigned int i; + + for (i = 0; i < 16; i++) + xlnk_devpacks[0] = NULL; + +} + +static void xlnk_devpacks_delete(struct xlnk_device_pack *devpack) +{ + unsigned int i; + + for (i = 0; i < 16; i++) { + if (xlnk_devpacks[i] == devpack) + xlnk_devpacks[i] = NULL; + } +} + +static void xlnk_devpacks_add(struct xlnk_device_pack *devpack) +{ + unsigned int i; + + for (i = 0; i < 16; i++) { + if (xlnk_devpacks[i] == NULL) { + xlnk_devpacks[i] = devpack; + break; + } + } +} + +static struct xlnk_device_pack *xlnk_devpacks_find(unsigned long base) +{ + unsigned int i; + + for (i = 0; i < 16; i++) { + if (xlnk_devpacks[i] + && xlnk_devpacks[i]->res[0].start == base) + return xlnk_devpacks[i]; + } + return NULL; +} + +static void xlnk_devpacks_free(unsigned long base) +{ + struct xlnk_device_pack *devpack; + + devpack = xlnk_devpacks_find(base); + if (devpack) { + platform_device_unregister(&devpack->pdev); + kfree(devpack); + xlnk_devpacks_delete(devpack); + } +} + +static void xlnk_devpacks_free_all(void) +{ + struct xlnk_device_pack *devpack; + unsigned int i; + + for (i = 0; i < 16; i++) { + devpack = xlnk_devpacks[i]; + if (devpack) { + platform_device_unregister(&devpack->pdev); + kfree(devpack); + xlnk_devpacks_delete(devpack); + } + } +} + +static int xlnk_probe(struct platform_device *pdev) +{ + int err; + dev_t dev = 0; + + /* use 2.6 device model */ + err = alloc_chrdev_region(&dev, 0, 1, driver_name); + if (err) { + pr_err("%s: Can't get major %d\n", __func__, driver_major); + goto err1; + } + + cdev_init(&xlnk_cdev, &xlnk_fops); + + xlnk_cdev.owner = THIS_MODULE; + + err = cdev_add(&xlnk_cdev, dev, 1); + + if (err) { + pr_err("%s: Failed to add XLNK device\n", __func__); + goto err3; + } + + /* udev support */ + xlnk_class = class_create(THIS_MODULE, "xlnk"); + if (IS_ERR(xlnk_class)) { + pr_err("%s: Error creating xlnk class\n", __func__); + goto err3; + } + + driver_major = MAJOR(dev); + + pr_info("xlnk major %d\n", driver_major); + + device_create(xlnk_class, NULL, MKDEV(driver_major, 0), + NULL, "xlnk"); + + xlnk_init_bufpool(); + + pr_info("%s driver loaded\n", DRIVER_NAME); + + xlnk_pdev = pdev; + xlnk_dev = &pdev->dev; + + if (xlnk_pdev) + pr_info("xlnk_pdev is not null\n"); + else + pr_info("xlnk_pdev is null\n"); + + xlnk_devpacks_init(); + +#ifdef CONFIG_ARCH_ZYNQ + xlnk_start_benchmark_counter(); +#endif + + return 0; + +err3: + cdev_del(&xlnk_cdev); + unregister_chrdev_region(dev, 1); +err1: + return err; +} + +static int xlnk_buf_findnull(void) +{ + int i; + + for (i = 1; i < xlnk_bufpool_size; i++) { + if (!xlnk_bufpool[i]) + return i; + } + + return 0; +} + +/** + * allocate and return an id + * id must be a positve number + */ +static int xlnk_allocbuf(unsigned int len, unsigned int cacheable) +{ + int id; + + id = xlnk_buf_findnull(); + + if (id <= 0) + return -ENOMEM; + + xlnk_bufpool[id] = dma_alloc_coherent(xlnk_dev, len, + &xlnk_phyaddr[id], + GFP_KERNEL | GFP_DMA); + xlnk_buflen[id] = len; + xlnk_bufcacheable[id] = cacheable; + + if (!xlnk_bufpool[id]) { + pr_err("%s: dma_alloc_coherent of %d byte buffer failed\n", + __func__, len); + return -ENOMEM; + } + + return id; +} + +static int xlnk_init_bufpool(void) +{ + unsigned int i; + + xlnk_dev_buf = kmalloc(8192, GFP_KERNEL | __GFP_DMA); + *((char *)xlnk_dev_buf) = '\0'; + + if (!xlnk_dev_buf) { + pr_err("%s: malloc failed\n", __func__); + return -ENOMEM; + } + + xlnk_bufpool = kmalloc(sizeof(void *) * xlnk_bufpool_size, + GFP_KERNEL); + + xlnk_bufpool[0] = xlnk_dev_buf; + for (i = 1; i < xlnk_bufpool_size; i++) + xlnk_bufpool[i] = NULL; + + return 0; +} + +#define XLNK_SUSPEND NULL +#define XLNK_RESUME NULL + +static int xlnk_remove(struct platform_device *pdev) +{ + dev_t devno; + + kfree(xlnk_dev_buf); + xlnk_dev_buf = NULL; + + kfree(xlnk_bufpool); + xlnk_bufpool = NULL; + + devno = MKDEV(driver_major, 0); + cdev_del(&xlnk_cdev); + unregister_chrdev_region(devno, 1); + if (xlnk_class) { + /* remove the device from sysfs */ + device_destroy(xlnk_class, MKDEV(driver_major, 0)); + class_destroy(xlnk_class); + } + + xlnk_devpacks_free_all(); + + return 0; +} + + +static struct platform_driver xlnk_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = xlnk_probe, + .remove = xlnk_remove, + .suspend = XLNK_SUSPEND, + .resume = XLNK_RESUME, +}; + +static u64 dma_mask = 0xFFFFFFFFUL; + +static struct platform_device xlnk_device = { + .name = "xlnk", + .id = 0, + .dev = { + .platform_data = NULL, + .dma_mask = &dma_mask, + .coherent_dma_mask = 0xFFFFFFFF, + }, + .resource = NULL, + .num_resources = 0, +}; + +/* + * This function is called when an application opens handle to the + * bridge driver. + */ +static int xlnk_open(struct inode *ip, struct file *filp) +{ + int status = 0; + + if ((filp->f_flags & O_ACCMODE) == O_WRONLY) + xlnk_dev_size = 0; + + return status; +} + +static ssize_t xlnk_read(struct file *filp, char __user *buf, + size_t count, loff_t *offp) +{ + ssize_t retval = 0; + + /* todo: need semi for critical section */ + + if (*offp >= xlnk_dev_size) + goto out; + + if (*offp + count > xlnk_dev_size) + count = xlnk_dev_size - *offp; + + if (copy_to_user(buf, xlnk_dev_buf + *offp, count)) { + retval = -EFAULT; + goto out; + } + *offp += count; + retval = count; + + out: + return retval; +} + +static ssize_t xlnk_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offp) +{ + ssize_t retval = 0; + + /* todo: need to setup semi for critical section */ + + if (copy_from_user(xlnk_dev_buf + *offp, buf, count)) { + retval = -EFAULT; + goto out; + } + *offp += count; + retval = count; + + if (xlnk_dev_size < *offp) + xlnk_dev_size = *offp; + + out: + return retval; +} + +/* + * This function is called when an application closes handle to the bridge + * driver. + */ +static int xlnk_release(struct inode *ip, struct file *filp) +{ + int status = 0; + return status; +} + + +static int xlnk_devregister(char *name, unsigned int id, + unsigned long base, unsigned int size, + unsigned int *irqs, + u32 *handle) +{ + unsigned int nres; + unsigned int nirq; + unsigned int *irqptr; + struct xlnk_device_pack *devpack; + unsigned int i; + int status; + + devpack = xlnk_devpacks_find(base); + if (devpack) { + *handle = (u32)devpack; + return 0; + } + nirq = 0; + irqptr = irqs; + + while (*irqptr) { + nirq++; + irqptr++; + } + + if (nirq > 7) + return -ENOMEM; + + nres = nirq + 1; + + devpack = kzalloc(sizeof(struct xlnk_device_pack), + GFP_KERNEL); + strcpy(devpack->name, name); + devpack->pdev.name = devpack->name; + + devpack->pdev.id = id; + + devpack->pdev.dev.dma_mask = &dma_mask; + devpack->pdev.dev.coherent_dma_mask = 0xFFFFFFFF; + + devpack->res[0].start = base; + devpack->res[0].end = base + size - 1; + devpack->res[0].flags = IORESOURCE_MEM; + + for (i = 0; i < nirq; i++) { + devpack->res[i+1].start = irqs[i]; + devpack->res[i+1].end = irqs[i]; + devpack->res[i+1].flags = IORESOURCE_IRQ; + } + + devpack->pdev.resource = devpack->res; + devpack->pdev.num_resources = nres; + + status = platform_device_register(&devpack->pdev); + if (status) { + kfree(devpack); + *handle = 0; + } else { + xlnk_devpacks_add(devpack); + *handle = (u32)devpack; + } + return status; +} + +static int xlnk_dmaregister(char *name, unsigned int id, + unsigned long base, unsigned int size, + unsigned int chan_num, + unsigned int chan0_dir, + unsigned int chan0_irq, + unsigned int chan0_poll_mode, + unsigned int chan0_include_dre, + unsigned int chan0_data_width, + unsigned int chan1_dir, + unsigned int chan1_irq, + unsigned int chan1_poll_mode, + unsigned int chan1_include_dre, + unsigned int chan1_data_width, + u32 *handle) +{ + int status = -1; + +#ifdef CONFIG_XILINX_DMA_APF + + struct xlnk_device_pack *devpack; + + if (strcmp(name, "xilinx-axidma")) + return -EINVAL; + + if (chan_num < 1 || chan_num > 2) + return -EINVAL; + + devpack = xlnk_devpacks_find(base); + if (devpack) { + *handle = (u32)devpack; + return 0; + } + + devpack = kzalloc(sizeof(struct xlnk_device_pack), + GFP_KERNEL); + if (!devpack) + return -ENOMEM; + + strcpy(devpack->name, name); + devpack->pdev.name = devpack->name; + + devpack->pdev.id = id; + + devpack->dma_chan_cfg[0].include_dre = chan0_include_dre; + devpack->dma_chan_cfg[0].datawidth = chan0_data_width; + devpack->dma_chan_cfg[0].irq = chan0_irq; + devpack->dma_chan_cfg[0].poll_mode = chan0_poll_mode; + devpack->dma_chan_cfg[0].type = chan0_dir ? + "axi-dma-s2mm-channel" : + "axi-dma-mm2s-channel"; + + if (chan_num > 1) { + devpack->dma_chan_cfg[1].include_dre = chan1_include_dre; + devpack->dma_chan_cfg[1].datawidth = chan1_data_width; + devpack->dma_chan_cfg[1].irq = chan1_irq; + devpack->dma_chan_cfg[1].poll_mode = chan1_poll_mode; + devpack->dma_chan_cfg[1].type = chan1_dir ? + "axi-dma-s2mm-channel" : + "axi-dma-mm2s-channel"; + } + + devpack->dma_dev_cfg.type = "axi-dma"; + devpack->dma_dev_cfg.include_sg = 1; + devpack->dma_dev_cfg.sg_include_stscntrl_strm = 1; + devpack->dma_dev_cfg.channel_count = chan_num; + devpack->dma_dev_cfg.channel_config = &devpack->dma_chan_cfg[0]; + + devpack->pdev.dev.platform_data = &devpack->dma_dev_cfg; + + devpack->pdev.dev.dma_mask = &dma_mask; + devpack->pdev.dev.coherent_dma_mask = 0xFFFFFFFF; + + devpack->res[0].start = base; + devpack->res[0].end = base + size - 1; + devpack->res[0].flags = IORESOURCE_MEM; + + devpack->pdev.resource = devpack->res; + devpack->pdev.num_resources = 1; + + status = platform_device_register(&devpack->pdev); + if (status) { + kfree(devpack); + *handle = 0; + } else { + xlnk_devpacks_add(devpack); + *handle = (u32)devpack; + } + +#endif + return status; +} + +static int xlnk_mcdmaregister(char *name, unsigned int id, + unsigned long base, unsigned int size, + unsigned int mm2s_chan_num, + unsigned int mm2s_chan_irq, + unsigned int s2mm_chan_num, + unsigned int s2mm_chan_irq, + u32 *handle) +{ + int status = -1; + +#ifdef CONFIG_XILINX_MCDMA + struct xlnk_device_pack *devpack; + + if (strcmp(name, "xdma")) + return -EINVAL; + + + devpack = xlnk_devpacks_find(base); + if (devpack) { + *handle = (u32)devpack; + return 0; + } + + devpack = kzalloc(sizeof(struct xlnk_device_pack), + GFP_KERNEL); + if (!devpack) + return -ENOMEM; + + strcpy(devpack->name, name); + devpack->pdev.name = devpack->name; + devpack->pdev.id = id; + + devpack->mcdma_dev_cfg.tx_chans = mm2s_chan_num; + devpack->mcdma_dev_cfg.rx_chans = s2mm_chan_num; + devpack->mcdma_dev_cfg.legacy_mode = XDMA_MCHAN_MODE; + devpack->mcdma_dev_cfg.device_id = id; + + devpack->pdev.dev.platform_data = &devpack->mcdma_dev_cfg; + devpack->pdev.dev.dma_mask = &dma_mask; + devpack->pdev.dev.coherent_dma_mask = 0xFFFFFFFF; + devpack->pdev.dev.release = xdma_if_device_release, + + devpack->res[0].start = base; + devpack->res[0].end = base + size - 1; + devpack->res[0].flags = IORESOURCE_MEM; + + devpack->res[1].start = mm2s_chan_irq; + devpack->res[1].end = s2mm_chan_irq; + devpack->res[1].flags = IORESOURCE_IRQ; + + devpack->pdev.resource = devpack->res; + devpack->pdev.num_resources = 2; + + status = platform_device_register(&devpack->pdev); + if (status) { + kfree(devpack); + *handle = 0; + } else { + xlnk_devpacks_add(devpack); + *handle = (u32)devpack; + } + +#endif + + return status; +} + +static int xlnk_allocbuf_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + + union xlnk_args temp_args; + int status; + int id; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + id = xlnk_allocbuf(temp_args.allocbuf.len, + temp_args.allocbuf.cacheable); + + if (id <= 0) + return -ENOMEM; + + put_user(id, temp_args.allocbuf.idptr); + put_user((u32)(xlnk_phyaddr[id]), temp_args.allocbuf.phyaddrptr); + + return 0; +} + +static int xlnk_freebuf(int id) +{ + + if (id <= 0 || id >= xlnk_bufpool_size) + return -ENOMEM; + + if (!xlnk_bufpool[id]) + return -ENOMEM; + + dma_free_coherent(xlnk_dev, xlnk_buflen[id], xlnk_bufpool[id], + xlnk_phyaddr[id]); + + xlnk_bufpool[id] = NULL; + xlnk_phyaddr[id] = (dma_addr_t)NULL; + xlnk_buflen[id] = 0; + + return 0; +} + +static void xlnk_free_all_buf(void) +{ + int i; + + for (i = 1; i < xlnk_bufpool_size; i++) + xlnk_freebuf(i); +} + +static int xlnk_freebuf_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + + union xlnk_args temp_args; + int status; + int id; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + id = temp_args.freebuf.id; + return xlnk_freebuf(id); +} + +static int xlnk_dmarequest_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + +#ifdef CONFIG_XILINX_DMA_APF + + union xlnk_args temp_args; + int status; + struct xdma_chan *chan; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + if (!temp_args.dmarequest.name[0]) + return 0; + + chan = xdma_request_channel(temp_args.dmarequest.name); + + if (!chan) { + return -ENOMEM; + } + + temp_args.dmarequest.dmachan = (u32)chan; + temp_args.dmarequest.bd_space_phys_addr = chan->bd_phys_addr; + temp_args.dmarequest.bd_space_size = chan->bd_chain_size; + + copy_to_user((void __user *)args, &temp_args, sizeof(union xlnk_args)); + + return 0; + +#else + + return -1; + +#endif + +} + +static int xlnk_dmasubmit_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + +#ifdef CONFIG_XILINX_DMA_APF + union xlnk_args temp_args; + struct xdma_head *dmahead; + int status = -1; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + if (!temp_args.dmasubmit.dmachan) + return -ENODEV; + + status = xdma_submit((struct xdma_chan *)temp_args.dmasubmit.dmachan, + temp_args.dmasubmit.buf, + temp_args.dmasubmit.len, + temp_args.dmasubmit.nappwords_i, + temp_args.dmasubmit.appwords_i, + temp_args.dmasubmit.nappwords_o, + temp_args.dmasubmit.flag, + &dmahead); + + if (!status) { + temp_args.dmasubmit.dmahandle = (u32)dmahead; + temp_args.dmasubmit.last_bd_index = + (u32)dmahead->last_bd_index; + copy_to_user((void __user *)args, &temp_args, + sizeof(union xlnk_args)); + return 0; + } +#endif + return -ENOMEM; +} + + +static int xlnk_dmawait_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + int status = -1; + +#ifdef CONFIG_XILINX_DMA_APF + union xlnk_args temp_args; + struct xdma_head *dmahead; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + dmahead = (struct xdma_head *)temp_args.dmawait.dmahandle; + status = xdma_wait(dmahead, dmahead->userflag); + + if (temp_args.dmawait.nappwords) { + memcpy(temp_args.dmawait.appwords, dmahead->appwords_o, + dmahead->nappwords_o * sizeof(u32)); + + copy_to_user((void __user *)args, &temp_args, + sizeof(union xlnk_args)); + } + kfree(dmahead); + +#endif + + return status; +} + +static int xlnk_dmarelease_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + int status = -1; + +#ifdef CONFIG_XILINX_DMA_APF + + union xlnk_args temp_args; + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + xdma_release_channel((struct xdma_chan *)temp_args.dmarelease.dmachan); +#endif + + return status; +} + + +static int xlnk_devregister_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + union xlnk_args temp_args; + int status; + u32 handle; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + status = xlnk_devregister(temp_args.devregister.name, + temp_args.devregister.id, + temp_args.devregister.base, + temp_args.devregister.size, + temp_args.devregister.irqs, + &handle); + + return status; +} + +static int xlnk_dmaregister_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + union xlnk_args temp_args; + int status; + u32 handle; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + status = xlnk_dmaregister(temp_args.dmaregister.name, + temp_args.dmaregister.id, + temp_args.dmaregister.base, + temp_args.dmaregister.size, + temp_args.dmaregister.chan_num, + temp_args.dmaregister.chan0_dir, + temp_args.dmaregister.chan0_irq, + temp_args.dmaregister.chan0_poll_mode, + temp_args.dmaregister.chan0_include_dre, + temp_args.dmaregister.chan0_data_width, + temp_args.dmaregister.chan1_dir, + temp_args.dmaregister.chan1_irq, + temp_args.dmaregister.chan1_poll_mode, + temp_args.dmaregister.chan1_include_dre, + temp_args.dmaregister.chan1_data_width, + &handle); + + return status; +} + +static int xlnk_mcdmaregister_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + union xlnk_args temp_args; + int status; + u32 handle; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + status = xlnk_mcdmaregister(temp_args.mcdmaregister.name, + temp_args.mcdmaregister.id, + temp_args.mcdmaregister.base, + temp_args.mcdmaregister.size, + temp_args.mcdmaregister.mm2s_chan_num, + temp_args.mcdmaregister.mm2s_chan_irq, + temp_args.mcdmaregister.s2mm_chan_num, + temp_args.mcdmaregister.s2mm_chan_irq, + &handle); + + return status; +} + +static int xlnk_devunregister_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + union xlnk_args temp_args; + int status; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) + return -ENOMEM; + + xlnk_devpacks_free(temp_args.devunregister.base); + + return 0; +} + +static int xlnk_cachecontrol_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + union xlnk_args temp_args; + int status, size; + void *paddr, *kaddr; + + status = copy_from_user(&temp_args, (void __user *)args, + sizeof(union xlnk_args)); + + if (status) { + pr_err("Error in copy_from_user. status = %d\n", status); + return -ENOMEM; + } + + if (!(temp_args.cachecontrol.action == 0 || + temp_args.cachecontrol.action == 1)) { + pr_err("Illegal action specified to cachecontrol_ioctl: %d\n", + temp_args.cachecontrol.action); + return -EINVAL; + } + + size = temp_args.cachecontrol.size; + paddr = temp_args.cachecontrol.phys_addr; + kaddr = phys_to_virt((unsigned int)paddr); + + if (temp_args.cachecontrol.action == 0) { + /* flush cache */ + dmac_map_area(kaddr, size, DMA_TO_DEVICE); + outer_clean_range((unsigned int)paddr, + (unsigned int)(paddr + size)); + } else { + /* invalidate cache */ + outer_inv_range((unsigned int)paddr, + (unsigned int)(paddr + size)); + dmac_unmap_area(kaddr, size, DMA_FROM_DEVICE); + } + + return 0; +} + +/* This function provides IO interface to the bridge driver. */ +static long xlnk_ioctl(struct file *filp, unsigned int code, + unsigned long args) +{ + int status = 0; + + xlnk_record_event(XLNK_ET_KERNEL_ENTER_IOCTL); + + if (_IOC_TYPE(code) != XLNK_IOC_MAGIC) + return -ENOTTY; + if (_IOC_NR(code) > XLNK_IOC_MAXNR) + return -ENOTTY; + + /* some sanity check */ + switch (code) { + case XLNK_IOCALLOCBUF: + status = xlnk_allocbuf_ioctl(filp, code, args); + break; + case XLNK_IOCFREEBUF: + status = xlnk_freebuf_ioctl(filp, code, args); + break; + case XLNK_IOCDMAREQUEST: + status = xlnk_dmarequest_ioctl(filp, code, args); + break; + case XLNK_IOCDMASUBMIT: + status = xlnk_dmasubmit_ioctl(filp, code, args); + break; + case XLNK_IOCDMAWAIT: + status = xlnk_dmawait_ioctl(filp, code, args); + break; + case XLNK_IOCDMARELEASE: + status = xlnk_dmarelease_ioctl(filp, code, args); + break; + case XLNK_IOCDEVREGISTER: + status = xlnk_devregister_ioctl(filp, code, args); + break; + case XLNK_IOCDMAREGISTER: + status = xlnk_dmaregister_ioctl(filp, code, args); + break; + case XLNK_IOCMCDMAREGISTER: + status = xlnk_mcdmaregister_ioctl(filp, code, args); + break; + case XLNK_IOCDEVUNREGISTER: + status = xlnk_devunregister_ioctl(filp, code, args); + break; + case XLNK_IOCGETEVENTSIZE: + status = xlnk_get_event_size(args); + break; + case XLNK_IOCCACHECTRL: + status = xlnk_cachecontrol_ioctl(filp, code, args); + break; + case XLNK_IOCDUMPEVENTS: + status = xlnk_dump_events(args); + break; + case XLNK_IOCSHUTDOWN: + status = xlnk_shutdown(args); + break; + case XLNK_IOCRECRES: /* recover resource */ + status = xlnk_recover_resource(args); + break; + } + + xlnk_record_event(XLNK_ET_KERNEL_LEAVE_IOCTL); + return status; +} + +static struct vm_operations_struct xlnk_vm_ops = { + .open = xlnk_vma_open, + .close = xlnk_vma_close, +}; + +/* This function maps kernel space memory to user space memory. */ +static int xlnk_mmap(struct file *filp, struct vm_area_struct *vma) +{ + + int bufid; + int status; + + bufid = vma->vm_pgoff >> (24 - PAGE_SHIFT); + + if (bufid == 0) + status = remap_pfn_range(vma, vma->vm_start, + virt_to_phys(xlnk_dev_buf) >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); + else { + if (xlnk_bufcacheable[bufid] == 0) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + status = remap_pfn_range(vma, vma->vm_start, + xlnk_phyaddr[bufid] >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); + } + if (status) + return -EAGAIN; + + xlnk_vma_open(vma); + vma->vm_ops = &xlnk_vm_ops; + vma->vm_private_data = xlnk_bufpool[bufid]; + + return 0; +} + +static void xlnk_vma_open(struct vm_area_struct *vma) +{ + xlnk_dev_vmas++; +} + +static void xlnk_vma_close(struct vm_area_struct *vma) +{ + xlnk_dev_vmas--; +} + + +#ifdef CONFIG_ARCH_ZYNQ + +/* + * Xidane XLNK benchmark counter support + */ +static u32 __iomem *bc_virt; + + +/* Zynq global counter */ +static const unsigned long bc_phyaddr = 0xF8F00200; +static const unsigned long bc_to_cpu_shift = 1; +static const unsigned long bc_csr_size = 16; +static const unsigned long bc_ctr_offset = 2; +static const unsigned long bc_ctr_start = 1; +static const unsigned long bc_data_offset; + + +static void xlnk_start_benchmark_counter(void) +{ + bc_virt = ioremap(bc_phyaddr, bc_csr_size); + if (bc_virt) { + iowrite32(bc_ctr_start, bc_virt + bc_ctr_offset); + pr_info("xlnk: benchmark counter started\n"); + /* iounmap(bc_virt); */ + } +} + +#define XLNK_EVENT_TRACER_ENTRY_NUM 60000 +static struct event_tracer { + u32 event_id; + u32 event_time; +} xlnk_et[XLNK_EVENT_TRACER_ENTRY_NUM]; + +static unsigned long xlnk_et_index; +static unsigned long xlnk_et_numbers_to_dump; + +void xlnk_record_event(u32 event_id) +{ + if (xlnk_et_index >= XLNK_EVENT_TRACER_ENTRY_NUM) + return; + + xlnk_et[xlnk_et_index].event_id = event_id; + xlnk_et[xlnk_et_index].event_time = ioread32(bc_virt + + bc_data_offset) << + bc_to_cpu_shift; + xlnk_et_index++; +} +EXPORT_SYMBOL(xlnk_record_event); + +static int xlnk_get_event_size(unsigned long args) +{ + unsigned long __user *datap = (unsigned long __user *)args; + + /* take a snapshot of current index and only copy this + * size to user space thru xlnk_dump_events(), as the snapshot + * value determine the dynamically created user space event + * trace buffer size but the xlnk_et_index could keep going up + * with any xlnk_record_event() calls after this function + */ + xlnk_et_numbers_to_dump = xlnk_et_index; + put_user(xlnk_et_numbers_to_dump, datap); + return 0; +} + +static int xlnk_dump_events(unsigned long buf) +{ + /* only dump the number of event traces reported thru + * xlnk_get_event_size() and ignore the rest to avoid + * buffer overflow issue + */ + copy_to_user((void __user *)buf, xlnk_et, + xlnk_et_numbers_to_dump * sizeof(struct event_tracer)); + + /* clear up event pool so it's ready to use again */ + xlnk_et_index = 0; + xlnk_et_numbers_to_dump = 0; + + return 0; +} +#endif + + +static int xlnk_shutdown(unsigned long buf) +{ + return 0; +} + +static int xlnk_recover_resource(unsigned long buf) +{ + xlnk_free_all_buf(); +#ifdef CONFIG_XILINX_DMA_APF + xdma_release_all_channels(); +#endif + return 0; +} + +static int __init xlnk_init(void) +{ + pr_info("%s driver initializing\n", DRIVER_NAME); + + xlnk_dev_buf = NULL; + xlnk_dev_size = 0; + xlnk_dev_vmas = 0; + xlnk_bufpool = NULL; + + platform_device_register(&xlnk_device); + + return platform_driver_register(&xlnk_driver); +} + +static void __exit xlnk_exit(void) +{ + platform_driver_unregister(&xlnk_driver); +} + +/* APF driver initialization and de-initialization functions */ +module_init(xlnk_init); +module_exit(xlnk_exit); + +MODULE_DESCRIPTION("Xilinx APF driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk-eng.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk-eng.c 2014-07-20 22:06:37.567285743 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx XLNK Engine Driver + * + * Copyright (C) 2010 Xilinx, Inc. All rights reserved. + * + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/spinlock_types.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/string.h> +#include <linux/uio_driver.h> + + +#include "xlnk-eng.h" + +static DEFINE_MUTEX(xlnk_eng_list_mutex); +static LIST_HEAD(xlnk_eng_list); + +int xlnk_eng_register_device(struct xlnk_eng_device *xlnk_dev) +{ + mutex_lock(&xlnk_eng_list_mutex); + /* todo: need to add more error checking */ + + list_add_tail(&xlnk_dev->global_node, &xlnk_eng_list); + + mutex_unlock(&xlnk_eng_list_mutex); + + return 0; +} +EXPORT_SYMBOL(xlnk_eng_register_device); + + +void xlnk_eng_unregister_device(struct xlnk_eng_device *xlnk_dev) +{ + mutex_lock(&xlnk_eng_list_mutex); + /* todo: need to add more error checking */ + + list_del(&xlnk_dev->global_node); + + mutex_unlock(&xlnk_eng_list_mutex); +} +EXPORT_SYMBOL(xlnk_eng_unregister_device); + +struct xlnk_eng_device *xlnk_eng_request_by_name(char *name) +{ + struct xlnk_eng_device *device, *_d; + int found = 0; + + mutex_lock(&xlnk_eng_list_mutex); + + list_for_each_entry_safe(device, _d, &xlnk_eng_list, global_node) { + if (!strcmp(dev_name(device->dev), name)) { + found = 1; + break; + } + } + if (found) + device = device->alloc(device); + else + device = NULL; + + mutex_unlock(&xlnk_eng_list_mutex); + + return device; +} +EXPORT_SYMBOL(xlnk_eng_request_by_name); + +void xlnk_eng_release(struct xlnk_eng_device *xlnk_dev) +{ + if (!xlnk_dev) + return; + + xlnk_dev->free(xlnk_dev); +} +EXPORT_SYMBOL(xlnk_eng_release); + +#define DRIVER_NAME "xilinx-xlnk-eng" + +struct xilinx_xlnk_eng_device { + struct xlnk_eng_device common; + void __iomem *base; + spinlock_t lock; + int cnt; +}; + + +#define to_xilinx_xlnk(dev) container_of(dev, \ + struct xilinx_xlnk_eng_device, common) + +static struct xlnk_eng_device *xilinx_xlnk_alloc( + struct xlnk_eng_device *xlnkdev) +{ + struct xilinx_xlnk_eng_device *xdev; + struct xlnk_eng_device *retdev; + + xdev = to_xilinx_xlnk(xlnkdev); + + if (xdev->cnt == 0) { + xdev->cnt++; + retdev = xlnkdev; + } else + retdev = NULL; + + return retdev; +} + +static void xilinx_xlnk_free(struct xlnk_eng_device *xlnkdev) +{ + struct xilinx_xlnk_eng_device *xdev; + + xdev = to_xilinx_xlnk(xlnkdev); + + xdev->cnt = 0; +} + +static int xlnk_eng_probe(struct platform_device *pdev) +{ + struct resource *res; + struct xilinx_xlnk_eng_device *xdev; + struct uio_info *info; + char *devname; + + pr_info("xlnk_eng_probe ...\n"); + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); + if (!xdev) { + dev_err(&pdev->dev, "Not enough memory for device\n"); + return -ENOMEM; + } + + /* more error handling */ + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(&pdev->dev, "Not enough memory for device\n"); + return -ENOMEM; + } + + devname = devm_kzalloc(&pdev->dev, 64, GFP_KERNEL); + if (!devname) { + dev_err(&pdev->dev, "Not enough memory for device\n"); + return -ENOMEM; + } + sprintf(devname, "%s.%d", DRIVER_NAME, pdev->id); + pr_info("uio name %s\n", devname); + /* iomap registers */ + + /* Get the data from the platform device */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xdev->base = devm_ioremap_resource(&pdev->dev, res); + + /* %pa types should be used here */ + dev_info(&pdev->dev, "physical base : 0x%lx\n", + (unsigned long)res->start); + dev_info(&pdev->dev, "register range : 0x%lx\n", + (unsigned long)resource_size(res)); + dev_info(&pdev->dev, "base remapped to: 0x%lx\n", + (unsigned long)xdev->base); + if (!xdev->base) { + dev_err(&pdev->dev, "unable to iomap registers\n"); + return -ENOMEM; + } + + info->mem[0].addr = res->start; + info->mem[0].size = resource_size(res); + info->mem[0].memtype = UIO_MEM_PHYS; + info->mem[0].internal_addr = xdev->base; + + /* info->name = DRIVER_NAME; */ + info->name = devname; + info->version = "0.0.1"; + + info->irq = -1; + + xdev->common.dev = &pdev->dev; + + xdev->common.alloc = xilinx_xlnk_alloc; + xdev->common.free = xilinx_xlnk_free; + + dev_set_drvdata(&pdev->dev, xdev); + + spin_lock_init(&xdev->lock); + + xdev->cnt = 0; + + xlnk_eng_register_device(&xdev->common); + + if (uio_register_device(&pdev->dev, info)) { + dev_err(&pdev->dev, "uio_register_device failed\n"); + return -ENODEV; + } + dev_info(&pdev->dev, "xilinx-xlnk-eng uio registered\n"); + + return 0; +} + +static int xlnk_eng_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver xlnk_eng_driver = { + .probe = xlnk_eng_probe, + .remove = xlnk_eng_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, +}; + +module_platform_driver(xlnk_eng_driver); + +MODULE_DESCRIPTION("Xilinx xlnk engine generic driver"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk-eng.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk-eng.h 2014-07-20 22:06:37.643284489 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx XLNK Engine Driver + * + * Copyright (C) 2010 Xilinx, Inc. All rights reserved. + * + * + */ + +#ifndef XLNK_ENG_H +#define XLNK_ENG_H + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/spinlock_types.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/string.h> + +struct xlnk_eng_device { + struct list_head global_node; + struct xlnk_eng_device * (*alloc)(struct xlnk_eng_device *xdev); + void (*free)(struct xlnk_eng_device *xdev); + struct device *dev; +}; +extern int xlnk_eng_register_device(struct xlnk_eng_device *xlnk_dev); +extern void xlnk_eng_unregister_device(struct xlnk_eng_device *xlnk_dev); +extern struct xlnk_eng_device *xlnk_eng_request_by_name(char *name); +extern void xlnk_eng_release(struct xlnk_eng_device *xlnk_dev); + +#endif + Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk-event-tracer-type.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk-event-tracer-type.h 2014-07-20 22:06:37.649284390 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +#ifndef XLNK_EVENT_TRACER_TYPE_H +#define XLNK_EVENT_TRACER_TYPE_H + +#define XLNK_ET_USERSPACE_BEFORE_ACC_TRANSFER_CALL 50 +#define XLNK_ET_USERSPACE_BEFORE_PORT_WAIT4COMPLETION 51 + +#define XLNK_ET_USERSPACE_BEFORE_DMA_SUBMIT 100 +#define XLNK_ET_USERSPACE_AFTER_DMA_SUBMIT 101 +#define XLNK_ET_USERSPACE_BEFORE_DMA_WAIT4COMPLETION 102 +#define XLNK_ET_USERSPACE_AFTER_DMA_WAIT4COMPLETION 103 + +#define XLNK_ET_KERNEL_ENTER_IOCTL 5000 +#define XLNK_ET_KERNEL_LEAVE_IOCTL 5001 +#define XLNK_ET_KERNEL_ENTER_DMA_SUBMIT 5002 +#define XLNK_ET_KERNEL_LEAVE_DMA_SUBMIT 5003 +#define XLNK_ET_KERNEL_BEFORE_PIN_USER_PAGE 5004 +#define XLNK_ET_KERNEL_BEFORE_GET_USER_PAGES 5005 +#define XLNK_ET_KERNEL_AFTER_GET_USER_PAGES 5006 +#define XLNK_ET_KERNEL_AFTER_PIN_USER_PAGE 5007 +#define XLNK_ET_KERNEL_BEFORE_DMA_MAP_SG 5008 +#define XLNK_ET_KERNEL_AFTER_DMA_MAP_SG 5009 +#define XLNK_ET_KERNEL_BEFORE_DMA_SETUP_BD 5010 +#define XLNK_ET_KERNEL_AFTER_DMA_KICKOFF 5011 +#define XLNK_ET_KERNEL_AFTER_DMA_SETUP_BD 5012 +#define XLNK_ET_KERNEL_ENTER_DMA_WAIT 5013 +#define XLNK_ET_KERNEL_BEFORE_DMA_UNMAP_SG 5014 +#define XLNK_ET_KERNEL_AFTER_DMA_UNMAP_SG 5015 +#define XLNK_ET_KERNEL_LEAVE_DMA_WAIT 5016 + + +#define XLNK_ET_KERNEL_DMA_MM2S_INTR 5100 +#define XLNK_ET_KERNEL_DMA_MM2S_HALF_BOTTOM_START 5101 +#define XLNK_ET_KERNEL_DMA_MM2S_HALF_BOTTOM_END 5102 +#define XLNK_ET_KERNEL_DMA_S2MM_INTR 5110 +#define XLNK_ET_KERNEL_DMA_S2MM_HALF_BOTTOM_START 5111 +#define XLNK_ET_KERNEL_DMA_S2MM_HALF_BOTTOM_END 5112 + +#endif + Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk.h 2014-07-20 22:06:37.656284275 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +#ifndef _XLNK_OS_H +#define _XLNK_OS_H + +#include <linux/stddef.h> + +#define XLNK_FLAG_COHERENT 0x00000001 +#define XLNK_FLAG_KERNEL_BUFFER 0x00000002 +#define XLNK_FLAG_DMAPOLLING 0x00000004 +#define XLNK_FLAG_PHYSICAL_ADDR 0x00000100 +#define XLNK_FLAG_VIRTUAL_ADDR 0x00000200 + +#define CF_FLAG_CACHE_FLUSH_INVALIDATE 0x00000001 +#define CF_FLAG_PHYSICALLY_CONTIGUOUS 0x00000002 +#define CF_FLAG_DMAPOLLING 0x00000004 + +extern void xlnk_record_event(u32 event_id); + + +enum xlnk_dma_direction { + XLNK_DMA_BI = 0, + XLNK_DMA_TO_DEVICE = 1, + XLNK_DMA_FROM_DEVICE = 2, + XLNK_DMA_NONE = 3, +}; + +union xlnk_args { + struct { + unsigned int len; + unsigned int __user *idptr; + unsigned int __user *phyaddrptr; + unsigned int cacheable; + } allocbuf; + struct { + unsigned int id; + void *buf; + } freebuf; + struct { + char name[64]; /* max length of 64 */ + u32 dmachan; /* return value */ + unsigned int bd_space_phys_addr;/*for bd chain used by dmachan*/ + unsigned int bd_space_size; /* bd chain size in bytes */ + } dmarequest; +#define XLNK_MAX_APPWORDS 5 + struct { + u32 dmachan; + void *buf; /* buffer base address */ + void *buf2; /* used to point src_buf in cdma case */ + unsigned int buf_offset; /* used on kernel allocated buffers */ + unsigned int len; + unsigned int bufflag; /* zero all the time so far */ + u32 sglist; /* ignored */ + unsigned int sgcnt; /* ignored */ + enum xlnk_dma_direction dmadir; + unsigned int nappwords_i; /* n appwords passed to BD */ + unsigned int appwords_i[XLNK_MAX_APPWORDS]; + unsigned int nappwords_o; /* n appwords passed from BD */ + /* appwords array we only accept 5 max */ + unsigned int flag; + u32 dmahandle; /* return value */ + unsigned int last_bd_index; /*index of last bd used by request*/ + } dmasubmit; + struct { + u32 dmahandle; + unsigned int nappwords; /* n appwords read from BD */ + unsigned int appwords[XLNK_MAX_APPWORDS]; + /* appwords array we only accept 5 max */ + } dmawait; + struct { + u32 dmachan; + } dmarelease; + struct { + unsigned long base; + unsigned int size; + unsigned int irqs[8]; + char name[32]; + unsigned int id; + } devregister; + struct { + unsigned int base; + } devunregister; + struct { + char name[32]; + unsigned int id; + unsigned long base; + unsigned int size; + unsigned int chan_num; + unsigned int chan0_dir; + unsigned int chan0_irq; + unsigned int chan0_poll_mode; + unsigned int chan0_include_dre; + unsigned int chan0_data_width; + unsigned int chan1_dir; + unsigned int chan1_irq; + unsigned int chan1_poll_mode; + unsigned int chan1_include_dre; + unsigned int chan1_data_width; + } dmaregister; + struct { + char name[32]; + unsigned int id; + unsigned long base; + unsigned int size; + unsigned int mm2s_chan_num; + unsigned int mm2s_chan_irq; + unsigned int s2mm_chan_num; + unsigned int s2mm_chan_irq; + } mcdmaregister; + struct { + void *phys_addr; + int size; + int action; + } cachecontrol; +}; + + +#endif Index: linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk-ioctl.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/apf/xlnk-ioctl.h 2014-07-20 22:06:37.662284176 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +#ifndef _XLNK_IOCTL_H +#define _XLNK_IOCTL_H + +#include <linux/ioctl.h> + +#define XLNK_IOC_MAGIC 'X' + +#define XLNK_IOCRESET _IO(XLNK_IOC_MAGIC, 0) + +#define XLNK_IOCALLOCBUF _IOWR(XLNK_IOC_MAGIC, 2, unsigned long) +#define XLNK_IOCFREEBUF _IOWR(XLNK_IOC_MAGIC, 3, unsigned long) + + + +#define XLNK_IOCDMAREQUEST _IOWR(XLNK_IOC_MAGIC, 7, unsigned long) +#define XLNK_IOCDMASUBMIT _IOWR(XLNK_IOC_MAGIC, 8, unsigned long) +#define XLNK_IOCDMAWAIT _IOWR(XLNK_IOC_MAGIC, 9, unsigned long) +#define XLNK_IOCDMARELEASE _IOWR(XLNK_IOC_MAGIC, 10, unsigned long) + + + + + +#define XLNK_IOCDEVREGISTER _IOWR(XLNK_IOC_MAGIC, 16, unsigned long) +#define XLNK_IOCDMAREGISTER _IOWR(XLNK_IOC_MAGIC, 17, unsigned long) +#define XLNK_IOCDEVUNREGISTER _IOWR(XLNK_IOC_MAGIC, 18, unsigned long) +#define XLNK_IOCCDMAREQUEST _IOWR(XLNK_IOC_MAGIC, 19, unsigned long) +#define XLNK_IOCCDMASUBMIT _IOWR(XLNK_IOC_MAGIC, 20, unsigned long) +#define XLNK_IOCGETEVENTSIZE _IOWR(XLNK_IOC_MAGIC, 21, unsigned long) +#define XLNK_IOCDUMPEVENTS _IOWR(XLNK_IOC_MAGIC, 22, unsigned long) +#define XLNK_IOCMCDMAREGISTER _IOWR(XLNK_IOC_MAGIC, 23, unsigned long) +#define XLNK_IOCCACHECTRL _IOWR(XLNK_IOC_MAGIC, 24, unsigned long) + +#define XLNK_IOCSHUTDOWN _IOWR(XLNK_IOC_MAGIC, 100, unsigned long) +#define XLNK_IOCRECRES _IOWR(XLNK_IOC_MAGIC, 101, unsigned long) + +#define XLNK_IOC_MAXNR 101 + +#endif Index: linux-3.12.24-rt38-xilinx/drivers/staging/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/staging/Kconfig 2014-07-20 22:05:50.165067793 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/staging/Kconfig 2014-07-20 22:06:37.669284060 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:151 @ source "drivers/staging/dgap/Kconfig" +source "drivers/staging/video/axivdma/Kconfig" + +source "drivers/staging/apf/Kconfig" + +source "drivers/staging/pmods/Kconfig" + endif # STAGING Index: linux-3.12.24-rt38-xilinx/drivers/staging/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/staging/Makefile 2014-07-20 22:05:50.164067809 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/staging/Makefile 2014-07-20 22:06:37.678283912 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:69 @ obj-$(CONFIG_XILLYBUS) += xillybus/ obj-$(CONFIG_DGNC) += dgnc/ obj-$(CONFIG_DGAP) += dgap/ +obj-$(CONFIG_XILINX_VIDEO_IP) += video/axivdma/ +obj-$(CONFIG_XILINX_APF) += apf/ +obj-$(CONFIG_PMODS) += pmods/ Index: linux-3.12.24-rt38-xilinx/drivers/staging/pmods/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/pmods/Kconfig 2014-07-20 22:06:37.690283714 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +menuconfig PMODS + bool "Pmod Support" + depends on HAS_IOMEM && OF + help + Digilent PMOD Support + +if PMODS + +config PMODS_DEBUG + bool "Enable Debug Message" + +config PMODOLED + tristate "PmodOLED1" + select SPI_BITBANG + select SPI_GPIO + help + The Digilent PmodOLED1, as well as ZED on-board OLED. Uses SPI over GPIO. + Configuration SPI_BITBANG and SPI_GPIO will be selected automatically. + +endif # PMODS Index: linux-3.12.24-rt38-xilinx/drivers/staging/pmods/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/pmods/Makefile 2014-07-20 22:06:37.696283615 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ + +ccflags-$(CONFIG_PMODS_DEBUG) += -DDEBUG + +obj-$(CONFIG_PMODOLED) += pmodoled-gpio.o Index: linux-3.12.24-rt38-xilinx/drivers/staging/pmods/pmodoled-gpio.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/pmods/pmodoled-gpio.c 2014-07-20 22:06:37.708283417 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * pmodolde-gpio.c - PmodOLED-GPIO driver + * + * Copyright (c) 2012 Digilent. All right reserved. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_gpio.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_gpio.h> +#include <linux/cdev.h> +#include <linux/mutex.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/types.h> +#include <asm/uaccess.h> + +#define DRIVER_NAME "pmodoled-gpio" +#define SPI_DRIVER_NAME "pmodoled-gpio-spi" +#define MAX_PMODOLED_GPIO_DEV_NUM 16 +#define DISPLAY_BUF_SZ 512 /* 32 x 128 bit monochrome == 512 bytes */ +#define MAX_LINE_LEN 16 /* 128 bits wide and current char width is 8 bit */ +#define MAX_ROW 4 +#define OLED_MAX_PG_CNT 4 /* number of display pages in OLED controller */ +#define OLED_CONTROLLER_PG_SZ 128 +#define OLED_CONTROLLER_CMD 0 +#define OLED_CONTROLLER_DATA 1 + +/* commands for the OLED display controller */ +#define OLED_SET_PG_ADDR 0x22 +#define OLED_DISPLAY_OFF 0xAE +#define OLED_DISPLAY_ON 0xAF +#define OLED_CONTRAST_CTRL 0x81 +#define OLED_SET_PRECHARGE_PERIOD 0xD9 +#define OLED_SET_SEGMENT_REMAP 0xA1 +#define OLED_SET_COM_DIR 0xC8 +#define OLED_SET_COM_PINS 0xDA + +static dev_t gpio_pmodoled_dev_id; +static unsigned int device_num; +static unsigned int cur_minor; +static unsigned int spi_drv_registered; +/* struct mutex minor_mutex; */ +static struct class *gpio_pmodoled_class; + +struct gpio_pmodoled_device { + const char *name; + /* R/W Mutex Lock */ + struct mutex mutex; + /* Display Buffers */ + uint8_t disp_on; + uint8_t *disp_buf; + /* Pin Assignment */ + unsigned long iVBAT; + unsigned long iVDD; + unsigned long iRES; + unsigned long iDC; + unsigned long iSCLK; + unsigned long iSDIN; + unsigned long iCS; + /* SPI Info */ + uint32_t spi_id; + /* platform device structures */ + struct platform_device *pdev; + /* Char Device */ + struct cdev cdev; + struct spi_device *spi; + dev_t dev_id; +}; + +/** + * screen_buf_to_display - + * @screen_buf - + * @dev - + * + */ +static int screen_buf_to_display(uint8_t *screen_buf, struct gpio_pmodoled_device *dev) +{ + uint32_t pg; + int status; + uint8_t lower_start_column = 0x00; + uint8_t upper_start_column = 0x10; + uint8_t wr_buf[10]; + + for (pg = 0; pg < OLED_MAX_PG_CNT; pg++) { + wr_buf[0] = OLED_SET_PG_ADDR; + wr_buf[1] = pg; + wr_buf[2] = lower_start_column; + wr_buf[3] = upper_start_column; + gpio_set_value(dev->iDC, OLED_CONTROLLER_CMD); + status = spi_write(dev->spi, wr_buf, 4); + if (status) { + dev_err(&dev->spi->dev, "screen_buf_to_display: Error writing to SPI\n"); + break; + } + + gpio_set_value(dev->iDC, OLED_CONTROLLER_DATA); + status = spi_write(dev->spi, (uint8_t *) (screen_buf + + (pg*OLED_CONTROLLER_PG_SZ)), OLED_CONTROLLER_PG_SZ); + if (status) { + dev_err(&dev->spi->dev, "screen_buf_to_display: Error writing to SPI\n"); + break; + } + } + return status; +} + +/** + * A basic open function. It exists mainly to save the id of + * the OLED and some other basic information. + */ +static int gpio_pmodoled_open(struct inode *inode, struct file *fp) +{ + struct gpio_pmodoled_device *dev; + + dev = container_of(inode->i_cdev, struct gpio_pmodoled_device, cdev); + fp->private_data = dev; + + return 0; +} + +static int gpio_pmodoled_close(struct inode *inode, struct file *fp) +{ + return 0; +} + +/** + * Driver write function + * + * This function uses a generic SPI write to send values to the Pmod device + * It takes a raw data array from the app in the buffer, copied it into + * device dispay buffer, and finally sends the buffer to the OLED using SPI + */ +static ssize_t gpio_pmodoled_write(struct file *fp, const char __user *buffer, size_t length, loff_t *offset) +{ + ssize_t retval = 0; + struct gpio_pmodoled_device *dev; + unsigned int minor_id; + int cnt; + int status; + + dev = fp->private_data; + minor_id = MINOR(dev->dev_id); + + if (mutex_lock_interruptible(&dev->mutex)) { + retval = -ERESTARTSYS; + goto write_lock_err; + } + + if (buffer == NULL) { + dev_err(&dev->spi->dev, "oled_write: ERROR: invalid buffer address: 0x%08lx\n", + (__force unsigned long) buffer); + retval = -EINVAL; + goto quit_write; + } + + if (length > DISPLAY_BUF_SZ) + cnt = DISPLAY_BUF_SZ; + else + cnt = length; + + if (copy_from_user(dev->disp_buf, buffer, cnt)) { + dev_err(&dev->spi->dev, "oled_write: copy_from_user failed\n"); + retval = -EFAULT; + goto quit_write; + } else + retval = cnt; + + status = screen_buf_to_display(dev->disp_buf, dev); + if (status) { + dev_err(&dev->spi->dev, "oled_write: Error sending string to display\n"); + retval = -EFAULT; + goto quit_write; + } + +quit_write: + mutex_unlock(&dev->mutex); +write_lock_err: + return retval; +} + +/** + * Driver Read Function + * + * This function does not actually read the Pmod as it is a write-only device. Instead + * It returns data in the buffer generated for the display that was used when the OLED + * was last programmed. + */ +static ssize_t gpio_pmodoled_read(struct file *fp, char __user *buffer, size_t length, loff_t *offset) +{ + ssize_t retval = 0; + struct gpio_pmodoled_device *dev; + unsigned int minor_id; + int cnt; + + dev = fp->private_data; + minor_id = MINOR(dev->dev_id); + + if (mutex_lock_interruptible(&dev->mutex)) { + retval = -ERESTARTSYS; + goto read_lock_err; + } + + if (buffer == NULL) { + dev_err(&dev->spi->dev, "OLED_read: ERROR: invalid buffer " + "address: 0x%08lx\n", (__force unsigned long)buffer); + retval = -EINVAL; + goto quit_read; + } + + if (length > DISPLAY_BUF_SZ) + cnt = DISPLAY_BUF_SZ; + else + cnt = length; + retval = copy_to_user((void __user *)buffer, dev->disp_buf, cnt); + if (!retval) + retval = cnt; /* copy success, return amount in buffer */ + +quit_read: + mutex_unlock(&dev->mutex); +read_lock_err: + return retval; +} + +static struct file_operations gpio_pmodoled_cdev_fops = { + .owner = THIS_MODULE, + .write = gpio_pmodoled_write, + .read = gpio_pmodoled_read, + .open = gpio_pmodoled_open, + .release = gpio_pmodoled_close, +}; + +static int add_gpio_pmodoled_device_to_bus(struct gpio_pmodoled_device *dev) +{ + struct spi_master *spi_master; + struct spi_device *spi_device; + int status = 0; + + spi_master = spi_busnum_to_master(dev->spi_id); + if (!spi_master) { + dev_err(&dev->pdev->dev, "spi_busnum_to_master(%d) returned NULL\n", dev->spi_id); + return -ENOSYS; + } + + spi_device = spi_alloc_device(spi_master); + if (!spi_device) { + put_device(&spi_master->dev); + dev_err(&dev->pdev->dev, "spi_alloc_device() failed\n"); + return -ENOMEM; + } + + spi_device->chip_select = 0; + spi_device->max_speed_hz = 4000000; + spi_device->mode = SPI_MODE_0; + spi_device->bits_per_word = 8; + spi_device->controller_data = (void *) dev->iCS; + spi_device->dev.platform_data = dev; + strlcpy(spi_device->modalias, SPI_DRIVER_NAME, sizeof(SPI_DRIVER_NAME)); + + status = spi_add_device(spi_device); + if (status < 0) { + spi_dev_put(spi_device); + dev_err(&dev->pdev->dev, "spi_add_device() failed %d\n", status); + return status; + } + dev->spi = spi_device; + + put_device(&spi_master->dev); + + return status; +} + +/** + * gpio_pmodoled_setup_cdev - Setup Char Device for ZED on-board OLED device. + * @dev: pointer to device tree node + * @dev_id: pointer to device major and minor number + * @spi: pointer to spi_device structure + * + * This function initializes char device for OLED device, and add it into + * kernel device structure. It returns 0, if the cdev is successfully + * initialized, or a negative value if there is an error. + */ +static int gpio_pmodoled_setup_cdev(struct gpio_pmodoled_device *dev, dev_t *dev_id, struct spi_device *spi) +{ + int status = 0; + struct device *device; + + cdev_init(&dev->cdev, &gpio_pmodoled_cdev_fops); + dev->cdev.owner = THIS_MODULE; + dev->cdev.ops = &gpio_pmodoled_cdev_fops; + dev->spi = spi; + + *dev_id = MKDEV(MAJOR(gpio_pmodoled_dev_id), cur_minor++); + status = cdev_add(&dev->cdev, *dev_id, 1); + if (status < 0) + return status; + + /* Add Device node in system */ + device = device_create(gpio_pmodoled_class, NULL, + *dev_id, NULL, + "%s", dev->name); + if (IS_ERR(device)) { + status = PTR_ERR(device); + dev_err(&spi->dev, "failed to create device node %s, err %d\n", + dev->name, status); + cdev_del(&dev->cdev); + } + + return status; +} + +/** + * gpio_pmodoled_init_gpio - Initialize GPIO for ZED Onboard OLED + * @dev - gpio_pmodoled_device + * + * Initializes OLED GPIO Control Pins. + * It returns 0, if the gpio pins are successfully + * initialized, or a negative value if there is an error. + */ +static int gpio_pmodoled_init_gpio(struct gpio_pmodoled_device *dev) +{ + struct gpio gpio_pmodoled_ctrl[] = { + {dev->iVBAT, GPIOF_OUT_INIT_HIGH, "OLED VBat"}, + {dev->iVDD, GPIOF_OUT_INIT_HIGH, "OLED VDD"}, + {dev->iRES, GPIOF_OUT_INIT_HIGH, "OLED_RESET"}, + {dev->iDC, GPIOF_OUT_INIT_HIGH, "OLED_D/C"}, + }; + int status; + int i; + + for (i = 0; i < ARRAY_SIZE(gpio_pmodoled_ctrl); i++) { + status = gpio_is_valid(gpio_pmodoled_ctrl[i].gpio); + if (!status) { + dev_err(&dev->spi->dev, "!! gpio_is_valid for GPIO %d, %s FAILED!, status: %d\n", + gpio_pmodoled_ctrl[i].gpio, gpio_pmodoled_ctrl[i].label, status); + goto gpio_invalid; + } + } + + status = gpio_request_array(gpio_pmodoled_ctrl, ARRAY_SIZE(gpio_pmodoled_ctrl)); + if (status) { + dev_err(&dev->spi->dev, "!! gpio_request_array FAILED!\n"); + dev_err(&dev->spi->dev, " status is: %d\n", status); + gpio_free_array(gpio_pmodoled_ctrl, 4); + goto gpio_invalid; + } + +gpio_invalid: + return status; +} + +/** + * gpio_pmodoled_disp_init - + * @dev: + * + */ +static void gpio_pmodoled_disp_init(struct gpio_pmodoled_device *dev) +{ + int status; + uint8_t wr_buf[20]; + + /* We are going to be sending commands + * so clear the data/cmd bit */ + gpio_set_value(dev->iDC, OLED_CONTROLLER_CMD); + + /* Start by turning VDD on and wait for the power to come up */ + gpio_set_value(dev->iVDD, 0); + msleep(1); + + /* Display off Command */ + wr_buf[0] = OLED_DISPLAY_OFF; + status = spi_write(dev->spi, wr_buf, 1); + + /* Bring Reset Low and then High */ + gpio_set_value(dev->iRES, 1); + msleep(1); + gpio_set_value(dev->iRES, 0); + msleep(1); + gpio_set_value(dev->iRES, 1); + + /* Send the set charge pump and set precharge period commands */ + wr_buf[0] = 0x8D; + wr_buf[1] = 0x14; + wr_buf[2] = OLED_SET_PRECHARGE_PERIOD; + wr_buf[3] = 0xF1; + + status = spi_write(dev->spi, wr_buf, 4); + + /* Turn on VCC and wait 100ms */ + gpio_set_value(dev->iVBAT, 0); + msleep(100); + + /* Set Display COntrast */ + wr_buf[0] = OLED_CONTRAST_CTRL; + wr_buf[1] = 0x0F; + + /* Invert the display */ + wr_buf[2] = OLED_SET_SEGMENT_REMAP; /* Remap Columns */ + wr_buf[3] = OLED_SET_COM_DIR; /* Remap Rows */ + + /* Select sequential COM configuration */ + wr_buf[4] = OLED_SET_COM_PINS; + wr_buf[5] = 0x00; + wr_buf[6] = 0xC0; + wr_buf[7] = 0x20; + wr_buf[8] = 0x00; + + /* Turn on Display */ + wr_buf[9] = OLED_DISPLAY_ON; + + status = spi_write(dev->spi, wr_buf, 10); +} + + +/** + * SPI hardware probe. Sets correct SPI mode, attempts + * to obtain memory needed by the driver, and performs + * a simple initialization of the device. + */ +static int gpio_pmodoled_spi_probe(struct spi_device *spi) +{ + int status = 0; + struct gpio_pmodoled_device *gpio_pmodoled_dev; + + /* We rely on full duplex transfers, mostly to reduce + * per transfer overheads (by making few transfers). + */ + if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) { + status = -EINVAL; + dev_err(&spi->dev, "SPI settings incorrect: %d\n", status); + goto spi_err; + } + + /* We must use SPI_MODE_0 */ + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + + status = spi_setup(spi); + if (status < 0) { + dev_err(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n", + spi->mode, spi->max_speed_hz / 1000, + status); + goto spi_err; + } + + /* Get gpio_pmodoled_device structure */ + gpio_pmodoled_dev = (struct gpio_pmodoled_device *) spi->dev.platform_data; + if (gpio_pmodoled_dev == NULL) { + dev_err(&spi->dev, "Cannot get gpio_pmodoled_device.\n"); + status = -EINVAL; + goto spi_platform_data_err; + } + + printk(KERN_INFO SPI_DRIVER_NAME " [%s] SPI Probing\n", gpio_pmodoled_dev->name); + +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_probe: setup char device\n", gpio_pmodoled_dev->name); +#endif + + /* Setup char driver */ + status = gpio_pmodoled_setup_cdev(gpio_pmodoled_dev, &(gpio_pmodoled_dev->dev_id), spi); + if (status) { + dev_err(&spi->dev, "spi_probe: Error adding %s device: %d\n", SPI_DRIVER_NAME, status); + goto cdev_add_err; + } + + /* Initialize Mutex */ + mutex_init(&gpio_pmodoled_dev->mutex); + + /** + * It is important to the OLED's longevity that the lines that + * control it's power are carefully controlled. This is a good + * time to ensure that the device is ot turned on until it is + * instructed to do so. + */ +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_probe: initialize device\n", gpio_pmodoled_dev->name); +#endif + + status = gpio_pmodoled_init_gpio(gpio_pmodoled_dev); + if (status) { + dev_err(&spi->dev, "spi_probe: Error initializing GPIO\n"); + goto oled_init_error; + } + + gpio_pmodoled_disp_init(gpio_pmodoled_dev); + + memset(gpio_pmodoled_dev->disp_buf, 0x00, DISPLAY_BUF_SZ); + + status = screen_buf_to_display(gpio_pmodoled_dev->disp_buf, gpio_pmodoled_dev); + if (status) { + dev_err(&spi->dev, "spi_probe: Error sending initial Display String\n"); + goto oled_init_error; + } + return status; + +oled_init_error: + if (&gpio_pmodoled_dev->cdev) + cdev_del(&gpio_pmodoled_dev->cdev); +cdev_add_err: +spi_platform_data_err: +spi_err: + return status; +} + +static int gpio_pmodoled_spi_remove(struct spi_device *spi) +{ + int status; + struct gpio_pmodoled_device *dev; + uint8_t wr_buf[10]; + + dev = (struct gpio_pmodoled_device *) spi->dev.platform_data; + + if (dev == NULL) { + dev_err(&spi->dev, "spi_remove: Error fetch gpio_pmodoled_device struct\n"); + return -EINVAL; + } + +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Clearing Display\n", dev->name); +#endif + + /* Clear Display */ + memset(dev->disp_buf, 0, DISPLAY_BUF_SZ); + status = screen_buf_to_display(dev->disp_buf, dev); + + /* Turn off display */ + wr_buf[0] = OLED_DISPLAY_OFF; + status = spi_write(spi, wr_buf, 1); + if (status) + dev_err(&spi->dev, "oled_spi_remove: Error writing to SPI device\n"); + + /* Turn off VCC (VBAT) */ + gpio_set_value(dev->iVBAT, 1); + msleep(100); + /* TUrn off VDD Power */ + gpio_set_value(dev->iVDD, 1); +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Free GPIOs\n", dev->name); +#endif + +{ + struct gpio gpio_pmodoled_ctrl[] = { + {dev->iVBAT, GPIOF_OUT_INIT_HIGH, "OLED VBat"}, + {dev->iVDD, GPIOF_OUT_INIT_HIGH, "OLED VDD"}, + {dev->iRES, GPIOF_OUT_INIT_HIGH, "OLED_RESET"}, + {dev->iDC, GPIOF_OUT_INIT_HIGH, "OLED_D/C"}, + }; + + gpio_free_array(gpio_pmodoled_ctrl, 4); +} + + if (&dev->cdev) { +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Destroy Char Device\n", dev->name); +#endif + device_destroy(gpio_pmodoled_class, dev->dev_id); + cdev_del(&dev->cdev); + } + + cur_minor--; + + printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Device Removed\n", dev->name); + + return status; +} + +static struct spi_driver gpio_pmodoled_spi_driver = { + .driver = { + .name = SPI_DRIVER_NAME, + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = gpio_pmodoled_spi_probe, + .remove = gpio_pmodoled_spi_remove, +}; + +static const struct of_device_id gpio_pmodoled_of_match[] = { + { .compatible = "dglnt,pmodoled-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, gpio_pmodoled_of_match); + +/** + * gpio_pmodoled_of_probe - Probe method for PmodOLED device (over GPIO). + * @pdev: pointer to platform devices + * + * This function probes the OLED device in the device tree. It initializes the + * OLED driver data structure. It returns 0, if the driver is bound to the OLED + * device, or a negative value if there is an error. + */ +static int gpio_pmodoled_of_probe(struct platform_device *pdev) +{ + struct gpio_pmodoled_device *gpio_pmodoled_dev; + struct platform_device *gpio_pmodoled_pdev; + struct spi_gpio_platform_data *gpio_pmodoled_pdata; + + struct device_node *np = pdev->dev.of_node; + + const u32 *tree_info; + int status = 0; + + /* Alloc Space for platform device structure */ + gpio_pmodoled_dev = (struct gpio_pmodoled_device *) kzalloc(sizeof(*gpio_pmodoled_dev), GFP_KERNEL); + if (!gpio_pmodoled_dev) { + status = -ENOMEM; + goto dev_alloc_err; + } + + /* Alloc Graphic Buffer for device */ + gpio_pmodoled_dev->disp_buf = (uint8_t *) kmalloc(DISPLAY_BUF_SZ, GFP_KERNEL); + if (!gpio_pmodoled_dev->disp_buf) { + status = -ENOMEM; + dev_err(&pdev->dev, "Device Display data buffer allocation failed: %d\n", status); + goto disp_buf_alloc_err; + } + + /* Get the GPIO Pins */ + gpio_pmodoled_dev->iVBAT = of_get_named_gpio(np, "vbat-gpio", 0); + gpio_pmodoled_dev->iVDD = of_get_named_gpio(np, "vdd-gpio", 0); + gpio_pmodoled_dev->iRES = of_get_named_gpio(np, "res-gpio", 0); + gpio_pmodoled_dev->iDC = of_get_named_gpio(np, "dc-gpio", 0); + gpio_pmodoled_dev->iSCLK = of_get_named_gpio(np, "spi-sclk-gpio", 0); + gpio_pmodoled_dev->iSDIN = of_get_named_gpio(np, "spi-sdin-gpio", 0); + status = of_get_named_gpio(np, "spi-cs-gpio", 0); + gpio_pmodoled_dev->iCS = (status < 0) ? SPI_GPIO_NO_CHIPSELECT : status; +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " %s: iVBAT: 0x%lx\n", np->name, gpio_pmodoled_dev->iVBAT); + printk(KERN_INFO DRIVER_NAME " %s: iVDD : 0x%lx\n", np->name, gpio_pmodoled_dev->iVDD); + printk(KERN_INFO DRIVER_NAME " %s: iRES : 0x%lx\n", np->name, gpio_pmodoled_dev->iRES); + printk(KERN_INFO DRIVER_NAME " %s: iDC : 0x%lx\n", np->name, gpio_pmodoled_dev->iDC); + printk(KERN_INFO DRIVER_NAME " %s: iSCLK: 0x%lx\n", np->name, gpio_pmodoled_dev->iSCLK); + printk(KERN_INFO DRIVER_NAME " %s: iSDIN: 0x%lx\n", np->name, gpio_pmodoled_dev->iSDIN); + printk(KERN_INFO DRIVER_NAME " %s: iCS : 0x%lx\n", np->name, gpio_pmodoled_dev->iCS); +#endif + + /* Get SPI Related Params */ + tree_info = of_get_property(np, "spi-bus-num", NULL); + if (tree_info) { + gpio_pmodoled_dev->spi_id = be32_to_cpup((tree_info)); +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " %s: BUS_ID\t%x\n", np->name, gpio_pmodoled_dev->spi_id); +#endif + } + + /* Alloc Space for platform data structure */ + gpio_pmodoled_pdata = (struct spi_gpio_platform_data *) kzalloc(sizeof(*gpio_pmodoled_pdata), GFP_KERNEL); + if (!gpio_pmodoled_pdata) { + status = -ENOMEM; + goto pdata_alloc_err; + } + + /* Fill up Platform Data Structure */ + gpio_pmodoled_pdata->sck = gpio_pmodoled_dev->iSCLK; + gpio_pmodoled_pdata->miso = SPI_GPIO_NO_MISO; + gpio_pmodoled_pdata->mosi = gpio_pmodoled_dev->iSDIN; + gpio_pmodoled_pdata->num_chipselect = 1; + + /* Alloc Space for platform data structure */ + gpio_pmodoled_pdev = (struct platform_device *) kzalloc(sizeof(*gpio_pmodoled_pdev), GFP_KERNEL); + if (!gpio_pmodoled_pdev) { + status = -ENOMEM; + goto pdev_alloc_err; + } + + /* Fill up Platform Device Structure */ + gpio_pmodoled_pdev->name = "spi_gpio"; + gpio_pmodoled_pdev->id = gpio_pmodoled_dev->spi_id; + gpio_pmodoled_pdev->dev.platform_data = gpio_pmodoled_pdata; + gpio_pmodoled_dev->pdev = gpio_pmodoled_pdev; + + /* Register spi_gpio master */ + status = platform_device_register(gpio_pmodoled_dev->pdev); + if (status < 0) { + dev_err(&pdev->dev, "platform_device_register failed: %d\n", status); + goto pdev_reg_err; + } + +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " %s: spi_gpio platform device registered.\n", np->name); +#endif + gpio_pmodoled_dev->name = np->name; + + /* Fill up Board Info for SPI device */ + status = add_gpio_pmodoled_device_to_bus(gpio_pmodoled_dev); + if (status < 0) { + dev_err(&pdev->dev, "add_gpio_pmodoled_device_to_bus failed: %d\n", status); + goto spi_add_err; + } + +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " %s: spi device registered.\n", np->name); +#endif + + /* Point device node data to gpio_pmodoled_device structure */ + if (np->data == NULL) + np->data = gpio_pmodoled_dev; + + if (gpio_pmodoled_dev_id == 0) { + /* Alloc Major & Minor number for char device */ + status = alloc_chrdev_region(&gpio_pmodoled_dev_id, 0, MAX_PMODOLED_GPIO_DEV_NUM, DRIVER_NAME); + if (status) { + dev_err(&pdev->dev, "Character device region not allocated correctly: %d\n", status); + goto err_alloc_chrdev_region; + } +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " : Char Device Region Registered, with Major: %d.\n", + MAJOR(gpio_pmodoled_dev_id)); +#endif + } + + if (gpio_pmodoled_class == NULL) { + /* Create Pmodoled-gpio Device Class */ + gpio_pmodoled_class = class_create(THIS_MODULE, DRIVER_NAME); + if (IS_ERR(gpio_pmodoled_class)) { + status = PTR_ERR(gpio_pmodoled_class); + goto err_create_class; + } +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " : pmodoled_gpio device class registered.\n"); +#endif + } + + if (spi_drv_registered == 0) { + /* Register SPI Driver for Pmodoled Device */ + status = spi_register_driver(&gpio_pmodoled_spi_driver); + if (status < 0) { + dev_err(&pdev->dev, "gpio_pmodoled_spi_driver register failed: %d\n", status); + goto err_spi_register; + } + spi_drv_registered = 1; + } + + device_num++; + + return status; + +err_spi_register: + class_destroy(gpio_pmodoled_class); + gpio_pmodoled_class = NULL; +err_create_class: + unregister_chrdev_region(gpio_pmodoled_dev_id, MAX_PMODOLED_GPIO_DEV_NUM); + gpio_pmodoled_dev_id = 0; +err_alloc_chrdev_region: + spi_unregister_device(gpio_pmodoled_dev->spi); +spi_add_err: + platform_device_unregister(gpio_pmodoled_dev->pdev); +pdev_reg_err: + kfree(gpio_pmodoled_pdev); +pdev_alloc_err: + kfree(gpio_pmodoled_pdata); +pdata_alloc_err: + kfree(gpio_pmodoled_dev->disp_buf); +disp_buf_alloc_err: + kfree(gpio_pmodoled_dev); +dev_alloc_err: + return status; +} + +/** + * gpio_pmodoled_of_remove - Remove method for ZED on-board OLED device. + * @np: pointer to device tree node + * + * This function removes the OLED device in the device tree. It frees the + * OLED driver data structure. It returns 0, if the driver is successfully + * removed, or a negative value if there is an error. + */ +static int gpio_pmodoled_of_remove(struct platform_device *pdev) +{ + struct gpio_pmodoled_device *gpio_pmodoled_dev; + struct device_node *np = pdev->dev.of_node; + + if (np->data == NULL) { + dev_err(&pdev->dev, "pmodoled %s: ERROR: No gpio_pmodoled_device structure found!\n", np->name); + return -ENOSYS; + } + gpio_pmodoled_dev = (struct gpio_pmodoled_device *) (np->data); + +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " %s : Free display buffer.\n", np->name); +#endif + + if (gpio_pmodoled_dev->disp_buf != NULL) + kfree(gpio_pmodoled_dev->disp_buf); + +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " %s : Unregister gpio_spi Platform Devices.\n", np->name); +#endif + + if (gpio_pmodoled_dev->pdev != NULL) + platform_device_unregister(gpio_pmodoled_dev->pdev); + + np->data = NULL; + device_num--; + + /* Unregister SPI Driver, Destroy pmodoled-gpio class, Release device id Region after + * all pmodoled-gpio devices have been removed. + */ + if (device_num == 0) { +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " : Unregister SPI Driver.\n"); +#endif + spi_unregister_driver(&gpio_pmodoled_spi_driver); + spi_drv_registered = 0; + +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " : Destroy pmodoled_gpio Class.\n"); +#endif + + if (gpio_pmodoled_class) + class_destroy(gpio_pmodoled_class); + + gpio_pmodoled_class = NULL; + +#ifdef CONFIG_PMODS_DEBUG + printk(KERN_INFO DRIVER_NAME " : Release Char Device Region.\n"); +#endif + + unregister_chrdev_region(gpio_pmodoled_dev_id, MAX_PMODOLED_GPIO_DEV_NUM); + gpio_pmodoled_dev_id = 0; + } + + return 0; +} + +static struct platform_driver gpio_pmodoled_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = gpio_pmodoled_of_match, + }, + .probe = gpio_pmodoled_of_probe, + .remove = gpio_pmodoled_of_remove, +}; + +module_platform_driver(gpio_pmodoled_driver); + +MODULE_AUTHOR("Digilent, Inc."); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(DRIVER_NAME": PmodOLED display driver"); +MODULE_ALIAS(DRIVER_NAME); Index: linux-3.12.24-rt38-xilinx/drivers/staging/video/axivdma/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/video/axivdma/Kconfig 2014-07-20 22:06:37.720283219 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +menuconfig XILINX_VIDEO_IP + tristate "Xilinx Video IP components" + ---help--- + This adds support to include Xilinx Video IP components. + Xilinx video IP need few additional drivers which are not currently in Xilinx + main-stream kernel are added in this section. + Example includes : AXI VDMA client driver. + +config XILINX_VDMA_WRAPPER + tristate "Video DMA Wrapper" + depends on XILINX_VIDEO_IP && XILINX_DMA_ENGINES + ---help--- + Enables Video DMA IP component.Uses Slave-DMA API of the DMA engine. + Provides user space application an interface to configure/control + Xilinx VDMA IP. + VDMA wrapper can be extened to supports other features exported by VDMA engine. Index: linux-3.12.24-rt38-xilinx/drivers/staging/video/axivdma/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/video/axivdma/Makefile 2014-07-20 22:06:37.726283120 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ +obj-$(CONFIG_XILINX_VDMA_WRAPPER) += xvdma.o Index: linux-3.12.24-rt38-xilinx/drivers/staging/video/axivdma/xvdma.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/video/axivdma/xvdma.c 2014-07-20 22:06:37.734282988 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * xvdma.c + * + * Xilinx Video DMA Driver + * + * Author: Xilinx Inc. + * + * 2002-2006 (c)Xilinx Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/amba/xilinx_dma.h> +#include <linux/cdev.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/fcntl.h> +#include <linux/fs.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/slab.h> +#include <linux/sysctl.h> +#include <linux/uaccess.h> +#include "xvdma.h" + + +struct xvdma_dev *xvdma_dev_info[MAX_DEVICES + 1]; +static u64 dma_mask = 0xFFFFFFFFUL; +struct chan_buf chan_buf[MAX_FRAMES]; +u32 num_devices; +struct completion cmp; + +void xvdma_get_dev_info(u32 device_id, struct xvdma_dev *dev) +{ + int i; + + for (i = 0; i < MAX_DEVICES; i++) { + if (xvdma_dev_info[i]->device_id == device_id) + break; + } + memcpy(dev, xvdma_dev_info[i], sizeof(struct xvdma_dev)); +} + +/* + * This function is called when an application opens handle to the + * bridge driver. + */ +static int xvdma_open(struct inode *ip, struct file *filp) +{ + return 0; +} + +static int xvdma_release(struct inode *ip, struct file *filp) +{ + return 0; +} + + +static long xvdma_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct xvdma_dev xvdma_dev; + struct xvdma_chan_cfg chan_cfg; + struct xvdma_buf_info buf_info; + struct xvdma_transfer tx_info; + u32 devices, chan; + + switch (cmd) { + case XVDMA_GET_NUM_DEVICES: + { + if (copy_from_user((void *)&devices, + (const void __user *)arg, + sizeof(u32))) + return -EFAULT; + + devices = num_devices; + if (copy_to_user((u32 *)arg, + &devices, sizeof(u32))) + return -EFAULT; + break; + } + case XVDMA_GET_DEV_INFO: + { + if (copy_from_user((void *)&xvdma_dev, + (const void __user *)arg, + sizeof(struct xvdma_dev))) + return -EFAULT; + + xvdma_get_dev_info(xvdma_dev.device_id, &xvdma_dev); + + if (copy_to_user((struct xvdma_dev *)arg, + &xvdma_dev, sizeof(struct xvdma_dev))) + return -EFAULT; + break; + } + case XVDMA_DEVICE_CONTROL: + { + if (copy_from_user((void *)&chan_cfg, + (const void __user *)arg, + sizeof(struct xvdma_chan_cfg))) + return -EFAULT; + + xvdma_device_control(&chan_cfg); + break; + } + case XVDMA_PREP_BUF: + { + if (copy_from_user((void *)&buf_info, + (const void __user *)arg, + sizeof(struct xvdma_buf_info))) + return -EFAULT; + xvdma_prep_slave_sg(&buf_info); + break; + } + case XVDMA_START_TRANSFER: + { + if (copy_from_user((void *)&tx_info, + (const void __user *)arg, + sizeof(struct xvdma_transfer))) + return -EFAULT; + + xvdma_start_transfer(&tx_info); + break; + } + case XVDMA_STOP_TRANSFER: + { + if (copy_from_user((void *)&chan, + (const void __user *)arg, + sizeof(u32))) + return -EFAULT; + + xvdma_stop_transfer((struct dma_chan *)chan); + break; + } + default: + break; + } + return 0; +} + +static bool xvdma_filter(struct dma_chan *chan, void *param) +{ + if (*((int *)chan->private) == *(int *)param) + return true; + + + return false; +} + +void vdma_sync_callback(void *completion) +{ + complete(completion); +} + +void xvdma_stop_transfer(struct dma_chan *chan) +{ + struct dma_device *chan_dev; + + if (chan) { + chan_dev = chan->device; + chan_dev->device_control(chan, DMA_TERMINATE_ALL, + (unsigned long)NULL); + } +} + +void xvdma_start_transfer(struct xvdma_transfer *tx_info) +{ + unsigned long tmo = msecs_to_jiffies(3000); + + init_completion(&cmp); + if (tx_info->chan) + dma_async_issue_pending((struct dma_chan *)tx_info->chan); + + if (tx_info->wait) { + tmo = wait_for_completion_timeout(&cmp, tmo); + if (0 == tmo) + pr_err("Timeout has occured...\n"); + } +} + +void xvdma_prep_slave_sg(struct xvdma_buf_info *buf_info) +{ + struct dma_chan *chan; + struct dma_device *chan_dev; + struct dma_async_tx_descriptor *chan_desc; + struct scatterlist chansg[MAX_FRAMES]; + dma_addr_t dma_srcs[MAX_FRAMES]; + u8 **buf = NULL; + int buf_size; + u32 flags = 0; + int i; + u32 device_id; + u32 frm_cnt = buf_info->frm_cnt; + + buf_size = buf_info->buf_size; + chan = (struct dma_chan *) buf_info->chan; + device_id = buf_info->device_id; + + if (chan) { + flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP + | DMA_PREP_INTERRUPT; + + if (buf_info->fixed_buffer) { + chan_dev = chan->device; + sg_init_table(chansg, frm_cnt); + for (i = 0; i < frm_cnt; i++) { + if (!buf_info->shared_buffer) { + dma_srcs[i] = + buf_info->addr_base + i * buf_size; + chan_buf[device_id].dma_addr[i] = + dma_srcs[i]; + } + sg_dma_address(&chansg[i]) = + chan_buf[device_id].dma_addr[i]; + sg_dma_len(&chansg[i]) = buf_size; + } + } else { + if (!buf_info->shared_buffer) { + buf = kcalloc(frm_cnt + 1, sizeof(u8 *), + GFP_KERNEL); + if (!buf) + pr_err("Buf failed\n"); + + for (i = 0; i < frm_cnt; i++) { + buf[i] = kmalloc(buf_size, GFP_KERNEL); + if (!buf[i]) + pr_err("Buf[%d] failed\n", i); + } + buf[i] = NULL; + } + + chan_dev = chan->device; + sg_init_table(chansg, frm_cnt); + for (i = 0; i < frm_cnt; i++) { + if (!buf_info->shared_buffer) { + dma_srcs[i] = dma_map_single( + chan_dev->dev, buf[i], buf_size, + buf_info->mem_type); + chan_buf[device_id].dma_addr[i] = + dma_srcs[i]; + } + sg_dma_address(&chansg[i]) = + chan_buf[device_id].dma_addr[i]; + sg_dma_len(&chansg[i]) = buf_size; + } + } + chan_desc = chan_dev->device_prep_slave_sg(chan, chansg, + frm_cnt, buf_info->direction, flags, NULL); + if (buf_info->callback) { + chan_desc->callback = vdma_sync_callback; + chan_desc->callback_param = &cmp; + } + chan_desc->tx_submit(chan_desc); + } +} + +void xvdma_device_control(struct xvdma_chan_cfg *chan_cfg) +{ + struct dma_chan *chan; + struct dma_device *chan_dev; + + chan = (struct dma_chan *) chan_cfg->chan; + + if (chan) { + chan_dev = chan->device; + chan_dev->device_control(chan, DMA_SLAVE_CONFIG, + (unsigned long)&chan_cfg->config); + } +} + +void xvdma_add_dev_info(struct dma_chan *tx_chan, + struct dma_chan *rx_chan) +{ + static u32 i; + + xvdma_dev_info[i] = (struct xvdma_dev *) + kzalloc(sizeof(struct xvdma_dev), GFP_KERNEL); + + xvdma_dev_info[i]->tx_chan = (u32) tx_chan; + xvdma_dev_info[i]->rx_chan = (u32) rx_chan; + xvdma_dev_info[i]->device_id = i; + num_devices++; + i++; +} + +void xvdma_scan_channels(void) +{ + dma_cap_mask_t mask; + u32 match_tx, match_rx; + struct dma_chan *tx_chan, *rx_chan; + u32 device_id = 0; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE | DMA_PRIVATE, mask); + + for (;;) { + match_tx = (DMA_TO_DEVICE & 0xFF) | XILINX_DMA_IP_VDMA | + (device_id << XVDMA_DEVICE_ID_SHIFT); + tx_chan = dma_request_channel(mask, xvdma_filter, + (void *)&match_tx); + match_rx = (DMA_FROM_DEVICE & 0xFF) | XILINX_DMA_IP_VDMA | + (device_id << XVDMA_DEVICE_ID_SHIFT); + rx_chan = dma_request_channel(mask, xvdma_filter, + (void *)&match_rx); + + if (!tx_chan && !rx_chan) + break; + else + xvdma_add_dev_info(tx_chan, rx_chan); + + device_id++; + } +} + +void xvdma_release_channels(void) +{ + int i; + + for (i = 0; i < MAX_DEVICES; i++) { + if (xvdma_dev_info[i]->tx_chan) + dma_release_channel((struct dma_chan *) + xvdma_dev_info[i]->tx_chan); + if (xvdma_dev_info[i]->rx_chan) + dma_release_channel((struct dma_chan *) + xvdma_dev_info[i]->rx_chan); + } +} + +static const struct file_operations xvdma_fops = { + .owner = THIS_MODULE, + .open = xvdma_open, + .unlocked_ioctl = xvdma_ioctl, + .release = xvdma_release, +}; + +static int xvdma_probe(struct platform_device *pdev) +{ + dev_t devt; + struct xvdma_drvdata *drvdata = NULL; + struct device *dev = &pdev->dev; + int retval; + + devt = MKDEV(XVDMA_MAJOR, XVDMA_MINOR); + + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct xvdma_drvdata), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + dev_set_drvdata(dev, (void *)drvdata); + + drvdata->dev = dev; + drvdata->devt = devt; + + cdev_init(&drvdata->cdev, &xvdma_fops); + drvdata->cdev.owner = THIS_MODULE; + retval = cdev_add(&drvdata->cdev, devt, 1); + if (retval) { + dev_err(dev, "cdev_add() failed\n"); + return retval; + } + + xvdma_scan_channels(); + dev_info(dev, "Xilinx VDMA probe successful\n"); + dev_info(dev, "Devices Scanned %d\n", num_devices); + return 0; +} + +static int xvdma_remove(struct platform_device *op) +{ + struct xvdma_drvdata *drvdata; + struct device *dev = &op->dev; + + drvdata = (struct xvdma_drvdata *)dev_get_drvdata(dev); + if (!drvdata) + return 0; + + xvdma_release_channels(); + cdev_del(&drvdata->cdev); + return 0; +} + +static struct platform_driver xvdma_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = xvdma_probe, + .remove = xvdma_remove, + .suspend = XVDMA_SUSPEND, + .resume = XVDMA_RESUME, +}; + +static struct platform_device xvdma_device = { + .name = "xvdma", + .id = 0, + .dev = { + .platform_data = NULL, + .dma_mask = &dma_mask, + .coherent_dma_mask = 0xFFFFFFFF, + }, + .resource = NULL, + .num_resources = 0, +}; + +static int __init xvdma_init(void) +{ + platform_device_register(&xvdma_device); + + return platform_driver_register(&xvdma_driver); +} + +static void __exit xvdma_exit(void) +{ + platform_driver_unregister(&xvdma_driver); +} + +late_initcall(xvdma_init); +module_exit(xvdma_exit); + +MODULE_AUTHOR("Xilinx Inc."); +MODULE_DESCRIPTION("Xilinx AXI VDMA client driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/staging/video/axivdma/xvdma.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/staging/video/axivdma/xvdma.h 2014-07-20 22:06:37.741282873 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* +xvdma.h +Wrapper client driver for xilinx VDMA Engine. + +*/ +#ifndef __XVDMA_H +#define __XVDMA_H + +#include <linux/amba/xilinx_dma.h> + +#define DRIVER_NAME "xvdma" +#define XVDMA_SUSPEND NULL +#define XVDMA_RESUME NULL + +#define XVDMA_MAJOR 10 +#define XVDMA_MINOR 224 + +#define MAX_DEVICES 4 +#define MAX_FRAMES 5 +#define DMA_CHAN_RESET 10 + +#define XVDMA_IOCTL_BASE 'W' +#define XVDMA_GET_NUM_DEVICES _IO(XVDMA_IOCTL_BASE, 0) +#define XVDMA_GET_DEV_INFO _IO(XVDMA_IOCTL_BASE, 1) +#define XVDMA_DEVICE_CONTROL _IO(XVDMA_IOCTL_BASE, 2) +#define XVDMA_PREP_BUF _IO(XVDMA_IOCTL_BASE, 3) +#define XVDMA_START_TRANSFER _IO(XVDMA_IOCTL_BASE, 4) +#define XVDMA_STOP_TRANSFER _IO(XVDMA_IOCTL_BASE, 5) + +#define XVDMA_DEVICE_ID_SHIFT 28 + +struct xvdma_drvdata { + struct device *dev; + struct cdev cdev; /* Char device structure */ + dev_t devt; +}; + +struct xvdma_dev { + + u32 tx_chan; + u32 rx_chan; + u32 device_id; +}; + +struct xvdma_chan_cfg { + struct xilinx_vdma_config config; + u32 chan; +}; + +struct xvdma_buf_info { + u32 chan; + u32 device_id; + u32 direction; + u32 shared_buffer; + u32 mem_type; + u32 fixed_buffer; + u32 buf_size; + u32 addr_base; + u32 frm_cnt; + u32 callback; +}; + +struct xvdma_transfer { + u32 chan; + u32 wait; +}; + +struct chan_buf { + u32 device_id; + dma_addr_t dma_addr[MAX_FRAMES]; +}; + +void xvdma_device_control(struct xvdma_chan_cfg *); +void xvdma_prep_slave_sg(struct xvdma_buf_info *); +void xvdma_start_transfer(struct xvdma_transfer *); +void xvdma_stop_transfer(struct dma_chan *); + +#endif Index: linux-3.12.24-rt38-xilinx/drivers/tty/serial/8250/8250_core.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/tty/serial/8250/8250_core.c 2014-07-20 22:05:50.214066984 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/tty/serial/8250/8250_core.c 2014-07-20 22:06:37.769282411 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:3194 @ if (uart_match_port(&serial8250_ports[i].port, port)) return &serial8250_ports[i]; + /* Look at setup port->line port first. If is available, use it */ + if (port->line >= 0 && port->line < nr_uarts) + if (serial8250_ports[port->line].port.type == PORT_UNKNOWN && + serial8250_ports[port->line].port.iobase == 0) { + return &serial8250_ports[port->line]; + } + /* * We didn't find a matching entry, so look for the first * free entry. We look for one which hasn't been previously Index: linux-3.12.24-rt38-xilinx/drivers/tty/serial/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/tty/serial/Kconfig 2014-07-20 22:05:50.211067034 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/tty/serial/Kconfig 2014-07-20 22:06:37.845281157 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1391 @ config SERIAL_XILINX_PS_UART tristate "Xilinx PS UART support" - depends on OF + depends on ARCH_ZYNQ select SERIAL_CORE help This driver supports the Xilinx PS UART port. Index: linux-3.12.24-rt38-xilinx/drivers/tty/serial/of_serial.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/tty/serial/of_serial.c 2014-07-20 22:05:50.209067067 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/tty/serial/of_serial.c 2014-07-20 22:06:37.856280976 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:154 @ struct uart_port port; int port_type; int ret; + int ids; match = of_match_device(of_platform_serial_table, &ofdev->dev); if (!match) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:172 @ if (ret) goto out; + ids = of_alias_get_id(ofdev->dev.of_node, "serial"); + if (ids < 0) { + dev_warn(&ofdev->dev, "FAILED to find out alias id\n"); + } else { + if (ids < CONFIG_SERIAL_8250_RUNTIME_UARTS) + port.line = ids; + else { + dev_warn(&ofdev->dev, + "FAILED to register serial driver with id %d\n", + ids); + goto out; + } + } + switch (port_type) { #ifdef CONFIG_SERIAL_8250 case PORT_8250 ... PORT_MAX_8250: Index: linux-3.12.24-rt38-xilinx/drivers/tty/serial/uartlite.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/tty/serial/uartlite.c 2014-07-20 22:05:50.212067017 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/tty/serial/uartlite.c 2014-07-20 22:06:37.868280778 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:425 @ u8 val; /* Spin waiting for TX fifo to have space available */ - for (i = 0; i < 100000; i++) { + for (i = 0; i < 10000000; i++) { val = uart_in32(ULITE_STATUS, port); if ((val & ULITE_STATUS_TXFULL) == 0) break; Index: linux-3.12.24-rt38-xilinx/drivers/tty/serial/xilinx_uartps.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/tty/serial/xilinx_uartps.c 2014-07-20 22:05:50.213067000 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/tty/serial/xilinx_uartps.c 2014-07-20 22:06:37.890280415 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ /* * Xilinx PS UART driver * - * 2011 (c) Xilinx Inc. + * 2011 - 2013 (C) Xilinx Inc. * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:14 @ * */ +#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) +#if defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif +#endif + #include <linux/platform_device.h> #include <linux/serial.h> +#include <linux/console.h> #include <linux/serial_core.h> -#include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/console.h> -#include <linux/clk.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/moduleparam.h> #include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/clk.h> #define XUARTPS_TTY_NAME "ttyPS" #define XUARTPS_NAME "xuartps" #define XUARTPS_MAJOR 0 /* use dynamic node allocation */ #define XUARTPS_MINOR 0 /* works best with devtmpfs */ -#define XUARTPS_NR_PORTS 2 -#define XUARTPS_FIFO_SIZE 16 /* FIFO size */ + +#define XUARTPS_NR_PORTS 10 +#define XUARTPS_FIFO_SIZE 64 /* FIFO size */ + #define XUARTPS_REGISTER_SPACE 0xFFF #define xuartps_readl(offset) ioread32(port->membase + offset) #define xuartps_writel(val, offset) iowrite32(val, port->membase + offset) +/* Rx Trigger level */ +static int rx_trigger_level = 56; +module_param (rx_trigger_level, uint, S_IRUGO); +MODULE_PARM_DESC (rx_trigger_level, "Rx trigger level, 1-63 bytes"); + +/* Rx Timeout */ +static int rx_timeout = 10; +module_param (rx_timeout, uint, S_IRUGO); +MODULE_PARM_DESC (rx_timeout, "Rx timeout, 1-255"); + + /********************************Register Map********************************/ /** UART * @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:152 @ #define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ #define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */ +/* Goes in read_status_mask for break detection as the HW doesn't do it*/ +#define XUARTPS_IXR_BRK 0x80000000 + /** Channel Status Register * * The channel status register (CSR) is provided to enable the control logic @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:166 @ #define XUARTPS_SR_TXFULL 0x00000010 /* TX FIFO full */ #define XUARTPS_SR_RXTRIG 0x00000001 /* Rx Trigger */ -/** - * struct xuartps - device data - * @refclk Reference clock - * @aperclk APB clock - */ struct xuartps { - struct clk *refclk; + struct uart_port *port; + unsigned int baud; + struct clk *devclk; struct clk *aperclk; + struct notifier_block clk_rate_change_nb; }; +#define to_xuartps(_nb) container_of(_nb, struct xuartps, clk_rate_change_nb); + /** * xuartps_isr - Interrupt handler @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:198 @ */ isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET); + /* There is no hardware break detection, so we interpret framing + * error with all-zeros data as a break sequence. Most of the time, + * there's another non-zero byte at the end of the sequence. + * + */ + + if (isrstatus & XUARTPS_IXR_FRAMING) { + while(!(xuartps_readl(XUARTPS_SR_OFFSET) & \ + XUARTPS_SR_RXEMPTY)) { + if(!xuartps_readl(XUARTPS_FIFO_OFFSET)) { + port->read_status_mask |= XUARTPS_IXR_BRK; + isrstatus &=~ XUARTPS_IXR_FRAMING; + } + } + xuartps_writel(XUARTPS_IXR_FRAMING, + XUARTPS_ISR_OFFSET); + } + /* drop byte with parity error if IGNPAR specified */ if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY) - isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT); + isrstatus &= ~XUARTPS_IXR_TOUT; isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:229 @ while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { data = xuartps_readl(XUARTPS_FIFO_OFFSET); + + /*Non-NULL byte after BREAK is garbage (99%)*/ + if(data && (port->read_status_mask & + XUARTPS_IXR_BRK)) { + port->read_status_mask&=~XUARTPS_IXR_BRK; + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + + + /*uart_handle_sysrq_char() doesn't work if + *spinlocked, for some reason + */ + if (port->sysrq) { + spin_unlock(&port->lock); + if(uart_handle_sysrq_char(port, \ + (unsigned char)data)) { + spin_lock(&port->lock); + continue; + } + spin_lock(&port->lock); + } + port->icount.rx++; if (isrstatus & XUARTPS_IXR_PARITY) { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:316 @ } /** - * xuartps_set_baud_rate - Calculate and set the baud rate - * @port: Handle to the uart port structure - * @baud: Baud rate to set - * + * xuartps_calc_baud_divs - Calculate baud rate divisors + * @clk: UART module input clock + * @baud: Desired baud rate + * @rbdiv: BDIV value (return value) + * @rcd: CD value (return value) + * @div8: Value for clk_sel bit in mod (return value) * Returns baud rate, requested baud when possible, or actual baud when there - * was too much error - **/ -static unsigned int xuartps_set_baud_rate(struct uart_port *port, - unsigned int baud) + * was too much error, zero if no valid divisors are found. + * + * Formula to obtain baud rate is + * baud_tx/rx rate = clk/CD * (BDIV + 1) + * input_clk = (Uart User Defined Clock or Apb Clock) + * depends on UCLKEN in MR Reg + * clk = input_clk or input_clk/8; + * depends on CLKS in MR reg + * CD and BDIV depends on values in + * baud rate generate register + * baud rate clock divisor register + */ +static unsigned int xuartps_calc_baud_divs(unsigned int clk, unsigned int baud, + u32 *rbdiv, u32 *rcd, int *div8) { - unsigned int sel_clk; - unsigned int calc_baud = 0; - unsigned int brgr_val, brdiv_val; + u32 cd, bdiv; + unsigned int calc_baud; + unsigned int bestbaud = 0; unsigned int bauderror; + unsigned int besterror = ~0; - /* Formula to obtain baud rate is - * baud_tx/rx rate = sel_clk/CD * (BDIV + 1) - * input_clk = (Uart User Defined Clock or Apb Clock) - * depends on UCLKEN in MR Reg - * sel_clk = input_clk or input_clk/8; - * depends on CLKS in MR reg - * CD and BDIV depends on values in - * baud rate generate register - * baud rate clock divisor register - */ - sel_clk = port->uartclk; - if (xuartps_readl(XUARTPS_MR_OFFSET) & XUARTPS_MR_CLKSEL) - sel_clk = sel_clk / 8; - - /* Find the best values for baud generation */ - for (brdiv_val = 4; brdiv_val < 255; brdiv_val++) { + if (baud < clk / (256 * 65535)) { + *div8 = 1; + clk /= 8; + } else { + *div8 = 0; + } - brgr_val = sel_clk / (baud * (brdiv_val + 1)); - if (brgr_val < 2 || brgr_val > 65535) + for (bdiv = 4; bdiv <= 255; bdiv++) { + cd = DIV_ROUND_CLOSEST(clk, baud * (bdiv + 1)); + if (cd < 1 || cd > 65535) continue; - calc_baud = sel_clk / (brgr_val * (brdiv_val + 1)); + calc_baud = clk / (cd * (bdiv + 1)); if (baud > calc_baud) bauderror = baud - calc_baud; else bauderror = calc_baud - baud; - /* use the values when percent error is acceptable */ - if (((bauderror * 100) / baud) < 3) { - calc_baud = baud; - break; + if (besterror > bauderror) { + *rbdiv = bdiv; + *rcd = cd; + bestbaud = calc_baud; + besterror = bauderror; } } + /* use the values when percent error is acceptable */ + if (((besterror * 100) / baud) < 3) + bestbaud = baud; - /* Set the values for the new baud rate */ - xuartps_writel(brgr_val, XUARTPS_BAUDGEN_OFFSET); - xuartps_writel(brdiv_val, XUARTPS_BAUDDIV_OFFSET); + return bestbaud; +} + +/** + * xuartps_set_baud_rate - Calculate and set the baud rate + * @port: Handle to the uart port structure + * @baud: Baud rate to set + * Returns baud rate, requested baud when possible, or actual baud when there + * was too much error, zero if no valid divisors are found. + */ +static unsigned int xuartps_set_baud_rate(struct uart_port *port, + unsigned int baud) +{ + unsigned int calc_baud; + u32 cd, bdiv; + u32 mreg; + int div8; + struct xuartps *xuartps = port->private_data; + + calc_baud = xuartps_calc_baud_divs(port->uartclk, baud, &bdiv, &cd, + &div8); + + /* Write new divisors to hardware */ + mreg = xuartps_readl(XUARTPS_MR_OFFSET); + if (div8) + mreg |= XUARTPS_MR_CLKSEL; + else + mreg &= ~XUARTPS_MR_CLKSEL; + xuartps_writel(mreg, XUARTPS_MR_OFFSET); + xuartps_writel(cd, XUARTPS_BAUDGEN_OFFSET); + xuartps_writel(bdiv, XUARTPS_BAUDDIV_OFFSET); + xuartps->baud = baud; return calc_baud; } +/* + * no clue yet how to implement this. i think we need access to the port + * structure in this function to do the required changes. but i don't know how + * to get it in here. + * + * Think I got it. port must have a notifier_block* member from where we then + * can get to the outer port structure with a container_of() call. + * + * Not sure when to stop UART. probably it's enough to stop, reconfigure, start + * in POST_RATE_CHANGE + */ +static int xuartps_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + u32 ctrl_reg; + struct uart_port *port; + int locked = 0; + struct clk_notifier_data *ndata = data; + unsigned long flags = 0; + struct xuartps *xuartps = to_xuartps(nb); + + port = xuartps->port; + if (port->suspended) + return NOTIFY_OK; + + switch (event) { + case PRE_RATE_CHANGE: + { + u32 bdiv; + u32 cd; + int div8; + + /* Find out if current baud-rate can be achieved with new clock + * frequency. */ + if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud, + &bdiv, &cd, &div8)) + return NOTIFY_BAD; + + spin_lock_irqsave(&xuartps->port->lock, flags); + + /* Disable the TX and RX to set baud rate */ + xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | + (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), + XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&xuartps->port->lock, flags); + + return NOTIFY_OK; + } + case POST_RATE_CHANGE: + /* Set clk dividers to generate correct baud with new clock + * frequency. */ + + spin_lock_irqsave(&xuartps->port->lock, flags); + + locked = 1; + port->uartclk = ndata->new_rate; + + xuartps->baud = xuartps_set_baud_rate(xuartps->port, + xuartps->baud); + /* fall through */ + case ABORT_RATE_CHANGE: + if (!locked) + spin_lock_irqsave(&xuartps->port->lock, flags); + + /* Set TX/RX Reset */ + xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), + XUARTPS_CR_OFFSET); + + while (xuartps_readl(XUARTPS_CR_OFFSET) & + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) + cpu_relax(); + + /* + * Clear the RX disable and TX disable bits and then set the TX + * enable bit and RX enable bit to enable the transmitter and + * receiver. + */ + xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); + xuartps_writel( + (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | + (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), + XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&xuartps->port->lock, flags); + + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } +} + /*----------------------Uart Operations---------------------------*/ /** @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:546 @ port->state->xmit.tail = (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); } - + xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_ISR_OFFSET); /* Enable the TX Empty interrupt */ xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_IER_OFFSET); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:594 @ { unsigned int status; - status = xuartps_readl(XUARTPS_ISR_OFFSET) & XUARTPS_IXR_TXEMPTY; + status = xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_IXR_TXEMPTY; return status ? TIOCSER_TEMT : 0; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:640 @ unsigned int baud; unsigned long flags; unsigned int ctrl_reg, mode_reg; + unsigned int minbaud, maxbaud; spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ while ((xuartps_readl(XUARTPS_SR_OFFSET) & - XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { + XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) xuartps_readl(XUARTPS_FIFO_OFFSET); - } /* Disable the TX and RX to set baud rate */ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:655 @ XUARTPS_CR_OFFSET); /* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk */ - baud = uart_get_baud_rate(port, termios, old, 0, 10000000); + /* min and max baud should be calculated here based on port->uartclk. + * this way we get a valid baud and can safely call set_baud() */ + minbaud = port->uartclk / (256 * 65535 * 8); + maxbaud = port->uartclk / 5; /* not sure about bdiv < 4 */ + baud = uart_get_baud_rate(port, termios, old, minbaud, maxbaud); baud = xuartps_set_baud_rate(port, baud); if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:684 @ | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), XUARTPS_CR_OFFSET); - xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); + xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG | XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:735 @ cval |= XUARTPS_MR_PARITY_MARK; else cval |= XUARTPS_MR_PARITY_SPACE; - } else if (termios->c_cflag & PARODD) + } else { + if (termios->c_cflag & PARODD) cval |= XUARTPS_MR_PARITY_ODD; else cval |= XUARTPS_MR_PARITY_EVEN; - } else + } + } else { cval |= XUARTPS_MR_PARITY_NONE; - xuartps_writel(cval , XUARTPS_MR_OFFSET); + } + cval |= mode_reg & 1; + xuartps_writel(cval, XUARTPS_MR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:759 @ static int xuartps_startup(struct uart_port *port) { unsigned int retval = 0, status = 0; + unsigned long flags; retval = request_irq(port->irq, xuartps_isr, 0, XUARTPS_NAME, (void *)port); if (retval) return retval; + spin_lock_irqsave(&port->lock, flags); + /* Disable the TX and RX */ xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS, XUARTPS_CR_OFFSET); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:794 @ | XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT, XUARTPS_MR_OFFSET); - /* Set the RX FIFO Trigger level to 14 assuming FIFO size as 16 */ - xuartps_writel(14, XUARTPS_RXWM_OFFSET); + /* Set the RX FIFO Trigger level to use most of the FIFO, but it + * can be tuned with a module parameter + */ + xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET); - /* Receive Timeout register is enabled with value of 10 */ - xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); + /* Receive Timeout register is enabled but it + * can be tuned with a module parameter + */ + xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); /* Clear out any pending interrupts before enabling them */ xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:812 @ XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN | XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); + return retval; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:825 @ static void xuartps_shutdown(struct uart_port *port) { int status; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); /* Disable interrupts */ status = xuartps_readl(XUARTPS_IMR_OFFSET); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:836 @ /* Disable the TX and RX */ xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS, XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&port->lock, flags); free_irq(port->irq, port); } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:949 @ /* N/A */ } +#if defined(CONFIG_CONSOLE_POLL) +static int xuartps_poll_get_char(struct uart_port *port) +{ + u32 imr; + int c; + + /*Disable all interrupts*/ + imr = xuartps_readl(XUARTPS_IMR_OFFSET); + xuartps_writel(imr, XUARTPS_IDR_OFFSET); + + /*Check if FIFO is empty*/ + if + (xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) + c = NO_POLL_CHAR; + else + /*Read a character*/ + c = (unsigned char) xuartps_readl(XUARTPS_FIFO_OFFSET); + + /*Enable interrupts*/ + xuartps_writel(imr, XUARTPS_IER_OFFSET); + + return c; +} + +static void xuartps_poll_put_char(struct uart_port *port, unsigned char c) +{ + u32 imr; + + /*Disable all interrupts*/ + imr = xuartps_readl(XUARTPS_IMR_OFFSET); + xuartps_writel(imr, XUARTPS_IDR_OFFSET); + + /*Wait until FIFO is empty*/ + while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)) + cpu_relax(); + + /*Write a character*/ + xuartps_writel(c, XUARTPS_FIFO_OFFSET); + + /*Wait until FIFO is empty*/ + while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)) + cpu_relax(); + + /*Enable interrupts*/ + xuartps_writel(imr, XUARTPS_IER_OFFSET); + + return; +} +#endif + /** The UART operations structure */ static struct uart_ops xuartps_ops = { @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1031 @ .config_port = xuartps_config_port, /* Configure when driver * adds a xuartps port */ +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = xuartps_poll_get_char, + .poll_put_char = xuartps_poll_put_char, +#endif }; static struct uart_port xuartps_port[2]; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1045 @ * * Returns a pointer to a uart_port or NULL for failure **/ -static struct uart_port *xuartps_get_port(void) +static struct uart_port *xuartps_get_port(int id) { struct uart_port *port; - int id; - /* Find the next unused port */ - for (id = 0; id < XUARTPS_NR_PORTS; id++) - if (xuartps_port[id].mapbase == 0) - break; + /* try the given port id if failed use default method */ + if (xuartps_port[id].mapbase != 0) { + /* Find the next unused port */ + for (id = 0; id < XUARTPS_NR_PORTS; id++) + if (xuartps_port[id].mapbase == 0) + break; + } if (id >= XUARTPS_NR_PORTS) return NULL; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1115 @ { struct uart_port *port = &xuartps_port[co->index]; unsigned long flags; - unsigned int imr; + unsigned int imr, ctrl; int locked = 1; if (oops_in_progress) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1127 @ imr = xuartps_readl(XUARTPS_IMR_OFFSET); xuartps_writel(imr, XUARTPS_IDR_OFFSET); + /* + * Make sure that the tx part is enabled. Set the TX enable bit and + * clear the TX disable bit to enable the transmitter. + */ + ctrl = xuartps_readl(XUARTPS_CR_OFFSET); + xuartps_writel((ctrl & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN, + XUARTPS_CR_OFFSET); + uart_console_write(port, s, count, xuartps_console_putchar); xuartps_console_wait_tx(port); + xuartps_writel(ctrl, XUARTPS_CR_OFFSET); + /* restore interrupt state, it seems like there may be a h/w bug * in that the interrupt enable register should not need to be * written based on the data sheet @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1232 @ **/ static int xuartps_probe(struct platform_device *pdev) { - int rc; struct uart_port *port; struct resource *res, *res2; - struct xuartps *xuartps_data; + unsigned int clk = 0; + int ret; + int id = 0; - xuartps_data = kzalloc(sizeof(*xuartps_data), GFP_KERNEL); - if (!xuartps_data) - return -ENOMEM; + struct xuartps *xuartps; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; - xuartps_data->aperclk = clk_get(&pdev->dev, "aper_clk"); - if (IS_ERR(xuartps_data->aperclk)) { + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res2) + return -ENODEV; + + /* Look for a serialN alias */ + id = of_alias_get_id(pdev->dev.of_node, "serial"); + if (id < 0) { + dev_warn(&pdev->dev, "failed to get alias id, errno %d\n", id); + id = 0; + } + + port = xuartps_get_port(id); + xuartps = devm_kzalloc(&pdev->dev, sizeof(*xuartps), GFP_KERNEL); + + xuartps->aperclk = devm_clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(xuartps->aperclk)) { dev_err(&pdev->dev, "aper_clk clock not found.\n"); - rc = PTR_ERR(xuartps_data->aperclk); - goto err_out_free; + return PTR_ERR(xuartps->aperclk); } - xuartps_data->refclk = clk_get(&pdev->dev, "ref_clk"); - if (IS_ERR(xuartps_data->refclk)) { + xuartps->devclk = devm_clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(xuartps->devclk)) { dev_err(&pdev->dev, "ref_clk clock not found.\n"); - rc = PTR_ERR(xuartps_data->refclk); - goto err_out_clk_put_aper; + return PTR_ERR(xuartps->devclk); } - rc = clk_prepare_enable(xuartps_data->aperclk); - if (rc) { + ret = clk_prepare_enable(xuartps->aperclk); + if (ret) { dev_err(&pdev->dev, "Unable to enable APER clock.\n"); - goto err_out_clk_put; + return ret; } - rc = clk_prepare_enable(xuartps_data->refclk); - if (rc) { + ret = clk_prepare_enable(xuartps->devclk); + if (ret) { dev_err(&pdev->dev, "Unable to enable device clock.\n"); goto err_out_clk_dis_aper; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - rc = -ENODEV; - goto err_out_clk_disable; - } - - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) { - rc = -ENODEV; - goto err_out_clk_disable; - } + clk = (unsigned int)clk_get_rate(xuartps->devclk); + xuartps->clk_rate_change_nb.notifier_call = xuartps_clk_notifier_cb; + xuartps->clk_rate_change_nb.next = NULL; + if (clk_notifier_register(xuartps->devclk, + &xuartps->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); /* Initialize the port structure */ - port = xuartps_get_port(); - if (!port) { dev_err(&pdev->dev, "Cannot get uart_port structure\n"); - rc = -ENODEV; - goto err_out_clk_disable; + ret = -ENODEV; + goto err_out_clk_dis; } else { /* Register the port. * This function also registers this device with the tty layer @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1300 @ port->mapbase = res->start; port->irq = res2->start; port->dev = &pdev->dev; - port->uartclk = clk_get_rate(xuartps_data->refclk); - port->private_data = xuartps_data; + port->uartclk = clk; + port->private_data = xuartps; + xuartps->port = port; platform_set_drvdata(pdev, port); - rc = uart_add_one_port(&xuartps_uart_driver, port); - if (rc) { + ret = uart_add_one_port(&xuartps_uart_driver, port); + if (ret) { dev_err(&pdev->dev, - "uart_add_one_port() failed; err=%i\n", rc); - goto err_out_clk_disable; + "uart_add_one_port() failed; err=%i\n", ret); + port->private_data = NULL; + xuartps->port = NULL; + goto err_out_clk_dis; } return 0; } - -err_out_clk_disable: - clk_disable_unprepare(xuartps_data->refclk); +err_out_clk_dis: + clk_notifier_unregister(xuartps->devclk, &xuartps->clk_rate_change_nb); + clk_disable_unprepare(xuartps->devclk); err_out_clk_dis_aper: - clk_disable_unprepare(xuartps_data->aperclk); -err_out_clk_put: - clk_put(xuartps_data->refclk); -err_out_clk_put_aper: - clk_put(xuartps_data->aperclk); -err_out_free: - kfree(xuartps_data); + clk_disable_unprepare(xuartps->aperclk); - return rc; + return ret; } /** @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1332 @ static int xuartps_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct xuartps *xuartps_data = port->private_data; - int rc; + int rc = 0; + struct xuartps *xuartps; /* Remove the xuartps port from the serial core */ - rc = uart_remove_one_port(&xuartps_uart_driver, port); - port->mapbase = 0; - clk_disable_unprepare(xuartps_data->refclk); - clk_disable_unprepare(xuartps_data->aperclk); - clk_put(xuartps_data->refclk); - clk_put(xuartps_data->aperclk); - kfree(xuartps_data); + if (port) { + xuartps = port->private_data; + clk_notifier_unregister(xuartps->devclk, + &xuartps->clk_rate_change_nb); + xuartps->port = NULL; + port->private_data = NULL; + rc = uart_remove_one_port(&xuartps_uart_driver, port); + port->mapbase = 0; + clk_disable_unprepare(xuartps->devclk); + clk_disable_unprepare(xuartps->aperclk); + } return rc; } +#ifdef CONFIG_PM_SLEEP +/** + * xuartps_suspend - suspend event + * @device: Pointer to the device structure + * + * Returns 0 + */ +static int xuartps_suspend(struct device *device) +{ + struct uart_port *port = dev_get_drvdata(device); + struct tty_struct *tty; + struct device *tty_dev; + int may_wake = 0; + + /* Get the tty which could be NULL so don't assume it's valid */ + tty = tty_port_tty_get(&port->state->port); + if (tty) { + tty_dev = tty->dev; + may_wake = device_may_wakeup(tty_dev); + tty_kref_put(tty); + } + + /* + * Call the API provided in serial_core.c file which handles + * the suspend. + */ + uart_suspend_port(&xuartps_uart_driver, port); + if (console_suspend_enabled && !may_wake) { + struct xuartps *xuartps = port->private_data; + + clk_disable(xuartps->devclk); + clk_disable(xuartps->aperclk); + } else { + unsigned long flags = 0; + + spin_lock_irqsave(&port->lock, flags); + /* Empty the receive FIFO 1st before making changes */ + while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY)) + xuartps_readl(XUARTPS_FIFO_OFFSET); + dmb(); + /* set RX trigger level to 1 */ + xuartps_writel(1, XUARTPS_RXWM_OFFSET); + /* disable RX timeout interrups */ + xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IDR_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); + } + + return 0; +} + +/** + * xuartps_resume - Resume after a previous suspend + * @device: Pointer to the device structure + * + * Returns 0 + */ +static int xuartps_resume(struct device *device) +{ + struct uart_port *port = dev_get_drvdata(device); + unsigned long flags = 0; + u32 ctrl_reg; + struct tty_struct *tty; + struct device *tty_dev; + int may_wake = 0; + + /* Get the tty which could be NULL so don't assume it's valid */ + tty = tty_port_tty_get(&port->state->port); + if (tty) { + tty_dev = tty->dev; + may_wake = device_may_wakeup(tty_dev); + tty_kref_put(tty); + } + + if (console_suspend_enabled && !may_wake) { + struct xuartps *xuartps = port->private_data; + + clk_enable(xuartps->aperclk); + clk_enable(xuartps->devclk); + + spin_lock_irqsave(&port->lock, flags); + + /* Set TX/RX Reset */ + xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), + XUARTPS_CR_OFFSET); + while (xuartps_readl(XUARTPS_CR_OFFSET) & + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) + cpu_relax(); + + /* restore rx timeout value */ + xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + /* Enable Tx/Rx */ + ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); + xuartps_writel( + (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | + (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), + XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&port->lock, flags); + } else { + spin_lock_irqsave(&port->lock, flags); + /* restore original rx trigger level */ + xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET); + /* enable RX timeout interrupt */ + xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); + } + + return uart_resume_port(&xuartps_uart_driver, port); +} +#endif + +static SIMPLE_DEV_PM_OPS(xuartps_dev_pm_ops, xuartps_suspend, xuartps_resume); + /* Match table for of_platform binding */ static struct of_device_id xuartps_of_match[] = { + { .compatible = "xlnx,ps7-uart-1.00.a", }, { .compatible = "xlnx,xuartps", }, {} }; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1479 @ .owner = THIS_MODULE, .name = XUARTPS_NAME, /* Driver name */ .of_match_table = xuartps_of_match, + .pm = &xuartps_dev_pm_ops, }, }; Index: linux-3.12.24-rt38-xilinx/drivers/uio/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/uio/Kconfig 2014-07-20 22:05:50.194067314 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/uio/Kconfig 2014-07-20 22:06:37.904280184 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:138 @ If you compile this as a module, it will be called uio_mf624. +config UIO_XILINX_APM + tristate "Xilinx AXI Performance Monitor driver" + depends on MICROBLAZE || ARCH_ZYNQ + help + This driver is developed for AXI Performance Monitor IP, designed to + monitor AXI4 traffic for performance analysis of AXI bus in the + system. Driver maps HW registers and parameters to userspace. + + To compile this driver as a module, choose M here; the module + will be called uio_xilinx_apm. + endif Index: linux-3.12.24-rt38-xilinx/drivers/uio/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/uio/Makefile 2014-07-20 22:05:50.192067347 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/uio/Makefile 2014-07-20 22:06:37.913280036 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:11 @ obj-$(CONFIG_UIO_NETX) += uio_netx.o obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o obj-$(CONFIG_UIO_MF624) += uio_mf624.o +obj-$(CONFIG_UIO_XILINX_APM) += uio_xilinx_apm.o Index: linux-3.12.24-rt38-xilinx/drivers/uio/uio_pdrv_genirq.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/uio/uio_pdrv_genirq.c 2014-07-20 22:05:50.191067363 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/uio/uio_pdrv_genirq.c 2014-07-20 22:06:37.923279871 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:270 @ #ifdef CONFIG_OF static struct of_device_id uio_of_genirq_match[] = { + { .compatible = "generic-uio", }, { /* This is filled with module_parm */ }, { /* Sentinel */ }, }; Index: linux-3.12.24-rt38-xilinx/drivers/uio/uio_xilinx_apm.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/uio/uio_xilinx_apm.c 2014-07-20 22:06:37.933279706 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx AXI Performance Monitor + * + * Copyright (C) 2013 Xilinx, Inc. All rights reserved. + * + * Description: + * This driver is developed for AXI Performance Monitor IP, + * designed to monitor AXI4 traffic for performance analysis + * of AXI bus in the system. Driver maps HW registers and parameters + * to userspace. Userspace need not clear the interrupt of IP since + * driver clears the interrupt. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/uio_driver.h> + +#define XAPM_IS_OFFSET 0x0038 /* Interrupt Status Register */ +#define DRV_NAME "xilinxapm_uio" +#define DRV_VERSION "1.0" +#define UIO_DUMMY_MEMSIZE 4096 +#define XAPM_MODE_ADVANCED 1 +#define XAPM_MODE_PROFILE 2 +#define XAPM_MODE_TRACE 3 + +/** + * struct xapm_param - HW parameters structure + * @mode: Mode in which APM is working + * @maxslots: Maximum number of Slots in APM + * @eventcnt: Event counting enabled in APM + * @eventlog: Event logging enabled in APM + * @sampledcnt: Sampled metric counters enabled in APM + * @numcounters: Number of counters in APM + * @metricwidth: Metric Counter width (32/64) + * @sampledwidth: Sampled metric counter width + * @globalcntwidth: Global Clock counter width + * @scalefactor: Scaling factor + * @isr: Interrupts info shared to userspace + */ +struct xapm_param { + u32 mode; + u32 maxslots; + u32 eventcnt; + u32 eventlog; + u32 sampledcnt; + u32 numcounters; + u32 metricwidth; + u32 sampledwidth; + u32 globalcntwidth; + u32 scalefactor; + u32 isr; +}; + +/** + * struct xapm_dev - Global driver structure + * @info: uio_info structure + * @param: xapm_param structure + * @regs: IOmapped base address + */ +struct xapm_dev { + struct uio_info info; + struct xapm_param param; + void __iomem *regs; +}; + +/** + * xapm_handler - Interrupt handler for APM + * @irq: IRQ number + * @info: Pointer to uio_info structure + */ +static irqreturn_t xapm_handler(int irq, struct uio_info *info) +{ + struct xapm_dev *xapm = (struct xapm_dev *)info->priv; + void *ptr; + + ptr = (unsigned long *)xapm->info.mem[1].addr; + /* Clear the interrupt and copy the ISR value to userspace */ + xapm->param.isr = readl(xapm->regs + XAPM_IS_OFFSET); + writel(xapm->param.isr, xapm->regs + XAPM_IS_OFFSET); + memcpy(ptr, &xapm->param, sizeof(struct xapm_param)); + + return IRQ_HANDLED; +} + +/** + * xapm_getprop - Retrieves dts properties to param structure + * @pdev: Pointer to platform device + * @param: Pointer to param structure + */ +static int xapm_getprop(struct platform_device *pdev, struct xapm_param *param) +{ + u32 mode = 0; + int ret; + struct device_node *node; + + node = pdev->dev.of_node; + + /* Retrieve required dts properties and fill param structure */ + ret = of_property_read_u32(node, "xlnx,enable-profile", &mode); + if (ret < 0) + dev_info(&pdev->dev, "no property xlnx,enable-profile\n"); + else if (mode) + param->mode = XAPM_MODE_PROFILE; + + ret = of_property_read_u32(node, "xlnx,enable-trace", &mode); + if (ret < 0) + dev_info(&pdev->dev, "no property xlnx,enable-trace\n"); + else if (mode) + param->mode = XAPM_MODE_TRACE; + + ret = of_property_read_u32(node, "xlnx,num-monitor-slots", + ¶m->maxslots); + if (ret < 0) { + dev_err(&pdev->dev, "no property xlnx,num-monitor-slots"); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,enable-event-count", + ¶m->eventcnt); + if (ret < 0) { + dev_err(&pdev->dev, "no property xlnx,enable-event-count"); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,enable-event-log", + ¶m->eventlog); + if (ret < 0) { + dev_err(&pdev->dev, "no property xlnx,enable-event-log"); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,have-sampled-metric-cnt", + ¶m->sampledcnt); + if (ret < 0) { + dev_err(&pdev->dev, "no property xlnx,have-sampled-metric-cnt"); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,num-of-counters", + ¶m->numcounters); + if (ret < 0) { + dev_err(&pdev->dev, "no property xlnx,num-of-counters"); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,metric-count-width", + ¶m->metricwidth); + if (ret < 0) { + dev_err(&pdev->dev, "no property xlnx,metric-count-width"); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,metrics-sample-count-width", + ¶m->sampledwidth); + if (ret < 0) { + dev_err(&pdev->dev, "no property metrics-sample-count-width"); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,global-count-width", + ¶m->globalcntwidth); + if (ret < 0) { + dev_err(&pdev->dev, "no property xlnx,global-count-width"); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,metric-count-scale", + ¶m->scalefactor); + if (ret < 0) { + dev_err(&pdev->dev, "no property xlnx,metric-count-scale"); + return ret; + } + + return 0; +} + +/** + * xapm_probe - Driver probe function + * @pdev: Pointer to the platform_device structure + * + * Returns '0' on success and failure value on error + */ + +static int xapm_probe(struct platform_device *pdev) +{ + struct xapm_dev *xapm; + struct resource *res; + int irq; + int ret; + void *ptr; + + xapm = devm_kzalloc(&pdev->dev, (sizeof(struct xapm_dev)), GFP_KERNEL); + if (!xapm) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xapm->regs = devm_ioremap_resource(&pdev->dev, res); + if (!xapm->regs) { + dev_err(&pdev->dev, "unable to iomap registers\n"); + return -ENOMEM; + } + + /* Initialize mode as Advanced so that if no mode in dts, default + * is Advanced + */ + xapm->param.mode = XAPM_MODE_ADVANCED; + ret = xapm_getprop(pdev, &xapm->param); + if (ret < 0) + return ret; + + xapm->info.mem[0].name = "xilinx_apm"; + xapm->info.mem[0].addr = res->start; + xapm->info.mem[0].size = resource_size(res); + xapm->info.mem[0].memtype = UIO_MEM_PHYS; + + xapm->info.mem[1].addr = (unsigned long)kzalloc(UIO_DUMMY_MEMSIZE, + GFP_KERNEL); + ptr = (unsigned long *)xapm->info.mem[1].addr; + xapm->info.mem[1].size = UIO_DUMMY_MEMSIZE; + xapm->info.mem[1].memtype = UIO_MEM_LOGICAL; + + xapm->info.name = "axi-pmon"; + xapm->info.version = DRV_VERSION; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "unable to get irq\n"); + return irq; + } + + xapm->info.irq = irq; + xapm->info.handler = xapm_handler; + xapm->info.priv = xapm; + + memcpy(ptr, &xapm->param, sizeof(struct xapm_param)); + + ret = uio_register_device(&pdev->dev, &xapm->info); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register to UIO\n"); + return ret; + } + + platform_set_drvdata(pdev, xapm); + + dev_info(&pdev->dev, "Probed Xilinx APM\n"); + + return 0; +} + +/** + * xapm_remove - Driver remove function + * @pdev: Pointer to the platform_device structure + * + * Always returns '0' + */ +static int xapm_remove(struct platform_device *pdev) +{ + struct xapm_dev *xapm = platform_get_drvdata(pdev); + + uio_unregister_device(&xapm->info); + + return 0; +} + +static struct of_device_id xapm_of_match[] = { + { .compatible = "xlnx,axi-perf-monitor", }, + { /* end of table*/ } +}; + +MODULE_DEVICE_TABLE(of, xapm_of_match); + +static struct platform_driver xapm_driver = { + .driver = { + .name = "xilinx-axipmon", + .owner = THIS_MODULE, + .of_match_table = xapm_of_match, + }, + .probe = xapm_probe, + .remove = xapm_remove, +}; + +module_platform_driver(xapm_driver); + +MODULE_AUTHOR("Xilinx Inc."); +MODULE_DESCRIPTION("Xilinx AXI Performance Monitor driver"); +MODULE_LICENSE("GPL v2"); Index: linux-3.12.24-rt38-xilinx/drivers/usb/c67x00/c67x00-drv.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/c67x00/c67x00-drv.c 2014-07-20 22:05:50.227066770 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/c67x00/c67x00-drv.c 2014-07-20 22:06:37.947279475 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:44 @ #include <linux/module.h> #include <linux/usb.h> #include <linux/usb/c67x00.h> +#include <linux/of_platform.h> #include "c67x00.h" #include "c67x00-hcd.h" @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:124 @ { struct c67x00_device *c67x00; struct c67x00_platform_data *pdata; - struct resource *res, *res2; - int ret, i; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; - - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) - return -ENODEV; + struct resource *res; + int ret, i, irq; - c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL); + c67x00 = devm_kzalloc(&pdev->dev, sizeof(*c67x00), GFP_KERNEL); if (!c67x00) return -ENOMEM; - if (!request_mem_region(res->start, resource_size(res), - pdev->name)) { - dev_err(&pdev->dev, "Memory region busy\n"); - ret = -EBUSY; - goto request_mem_failed; - } - c67x00->hpi.base = ioremap(res->start, resource_size(res)); - if (!c67x00->hpi.base) { - dev_err(&pdev->dev, "Unable to map HPI registers\n"); - ret = -EIO; - goto map_failed; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + c67x00->hpi.base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(c67x00->hpi.base)) + return PTR_ERR(c67x00->hpi.base); + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + if (!pdev->dev.of_node) + return -ENODEV; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = of_property_read_u32(pdev->dev.of_node, "hpi-regstep", + &pdata->hpi_regstep); + if (!ret) + return ret; + + ret = of_property_read_u32(pdev->dev.of_node, "sie-config", + &pdata->sie_config); + if (!ret) + return ret; } spin_lock_init(&c67x00->hpi.lock); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:163 @ c67x00_ll_init(c67x00); c67x00_ll_hpi_reg_init(c67x00); - ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "irq resource not found\n"); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, c67x00_irq, 0, pdev->name, + c67x00); if (ret) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto request_irq_failed; + return ret; } ret = c67x00_ll_reset(c67x00); if (ret) { dev_err(&pdev->dev, "Device reset failed\n"); - goto reset_failed; + return ret; } for (i = 0; i < C67X00_SIES; i++) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:188 @ platform_set_drvdata(pdev, c67x00); return 0; - - reset_failed: - free_irq(res2->start, c67x00); - request_irq_failed: - iounmap(c67x00->hpi.base); - map_failed: - release_mem_region(res->start, resource_size(res)); - request_mem_failed: - kfree(c67x00); - - return ret; } static int c67x00_drv_remove(struct platform_device *pdev) { struct c67x00_device *c67x00 = platform_get_drvdata(pdev); - struct resource *res; int i; for (i = 0; i < C67X00_SIES; i++) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:200 @ c67x00_ll_release(c67x00); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res) - free_irq(res->start, c67x00); - - iounmap(c67x00->hpi.base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - - kfree(c67x00); - return 0; } +#ifdef CONFIG_OF +/* Match table for OF platform binding - from xilinx_emaclite */ +static struct of_device_id c67x00_of_match[] = { + { .compatible = "cypress,c67x00", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, c67x00_of_match); +#endif + static struct platform_driver c67x00_driver = { .probe = c67x00_drv_probe, .remove = c67x00_drv_remove, .driver = { .owner = THIS_MODULE, .name = "c67x00", + .of_match_table = of_match_ptr(c67x00_of_match), }, }; Index: linux-3.12.24-rt38-xilinx/drivers/usb/c67x00/c67x00-hcd.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/c67x00/c67x00-hcd.h 2014-07-20 22:05:50.226066786 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/c67x00/c67x00-hcd.h 2014-07-20 22:06:37.957279310 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:55 @ */ #define TOTAL_FRAME_BW 12000 -#define DEFAULT_EOT 2250 +#define DEFAULT_EOT 9600 /* This value fits MicroBlaze system. + it may requires a bigger value for + some USB device. */ #define MAX_FRAME_BW_STD (TOTAL_FRAME_BW - DEFAULT_EOT) #define MAX_FRAME_BW_ISO 2400 Index: linux-3.12.24-rt38-xilinx/drivers/usb/c67x00/c67x00-sched.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/c67x00/c67x00-sched.c 2014-07-20 22:05:50.228066753 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/c67x00/c67x00-sched.c 2014-07-20 22:06:38.040277941 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1036 @ !td_acked(td)) goto cont; + /* + * at this point, there are no errors, but it's still possible + * that the td wasn't executed by the c67x00. Confirm it was + * executed or force a retry + */ + if ((td->retry_cnt & TD_RETRYCNTMASK_ACT_FLG) && + td->status == 0) + goto cont; + /* Sequence ok and acked, don't need to fix toggle */ ack_ok = 1; Index: linux-3.12.24-rt38-xilinx/drivers/usb/core/hub.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/core/hub.c 2014-07-20 22:05:50.225066802 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/core/hub.c 2014-07-20 22:06:38.083277232 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:860 @ "%s failed (err = %d)\n", __func__, ret); } else { *status = le16_to_cpu(hub->status->hub.wHubStatus); - *change = le16_to_cpu(hub->status->hub.wHubChange); + *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; } mutex_unlock(&hub->status_mutex); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1696 @ * where the controller driver doesn't have bus_suspend and * bus_resume methods. */ +#ifdef CONFIG_USB_ZYNQ_PHY + usb_disable_autosuspend(hdev); +#else if (hdev->parent) { /* normal device */ usb_enable_autosuspend(hdev); } else { /* root hub */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1707 @ if (drv->bus_suspend && drv->bus_resume) usb_enable_autosuspend(hdev); } +#endif if (hdev->level == MAX_TOPO_LEVEL) { dev_err(&intf->dev, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:3856 @ * Between connect detection and reset signaling there must be a delay * of 100ms at least for debounce and power-settling. The corresponding * timer shall restart whenever the downstream port detects a disconnect. - * + * * Apparently there are some bluetooth and irda-dongles and a number of * low-speed devices for which this debounce period may last over a second. * Not covered by the spec - but easy to deal with. @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4082 @ udev->tt = &hub->tt; udev->ttport = port1; } - + /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? * Because device hardware and firmware is sometimes buggy in * this area, and this is how Linux has done it for ages. @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4246 @ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); usb_ep0_reinit(udev); } - + retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); if (retval < (signed)sizeof(udev->descriptor)) { if (retval != -ENODEV) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4532 @ goto loop_disable; } } - + /* check for devices running slower than they could */ if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200 && udev->speed == USB_SPEED_FULL @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4592 @ dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1); } - + done: hub_port_disable(hub, port1, 1); if (hcd->driver->relinquish_port && !hub->hdev->parent) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4757 @ * EM interference sometimes causes badly * shielded USB devices to be shutdown by * the hub, this hack enables them again. - * Works at least with mouse driver. + * Works at least with mouse driver. */ if (!(portstatus & USB_PORT_STAT_ENABLE) && !connect_change @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:5155 @ if (ret < 0) goto re_enumerate; - + /* Device might have changed firmware (DFU or similar) */ if (descriptors_changed(udev, &descriptor, bos)) { dev_info(&udev->dev, "device firmware changed\n"); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:5234 @ usb_release_bos_descriptor(udev); udev->bos = bos; return 0; - + re_enumerate: /* LPM state doesn't matter when we're about to destroy the device. */ hub_port_logical_disconnect(parent_hub, port1); Index: linux-3.12.24-rt38-xilinx/drivers/usb/gadget/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/gadget/Kconfig 2014-07-20 22:05:50.237066604 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/gadget/Kconfig 2014-07-20 22:06:38.106276852 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:188 @ dynamically linked module called "fsl_usb2_udc" and force all gadget drivers to also be dynamically linked. +config USB_GADGET_XUSBPS + tristate "Xilinx PS Highspeed USB DR Peripheral Controller" + depends on ARCH_ZYNQ + select USB_GADGET_DUALSPEED + select USB_XUSBPS_DR_OF if OF + help + Xilinx PS USB controller core supports device mode. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "xilinx_usbps_udc" and + force all gadget drivers to also be dynamically linked. + +config XUSBPS_ERRATA_DT654401 + bool "USB Errata: Adding a dTD to a Primed Endpoint May Not Get Recognized" + depends on USB_GADGET_XUSBPS + ---help--- + There is an issue with the add dTD tripwire semaphore (ATDTW bit + in USBCMD register) that can cause the controller to ignore a dTD + that is added to a primed endpoint. When this happens, the software + can read the tripwire bit and the status bit at '1' even though + the endpoint is unprimed. + + This issue is only applicable for the Zynq silicon revisions < 3.0. + For silicon versions 3.0 and higher, disable this option. + +config USB_XUSBPS + tristate + depends on USB_GADGET_XUSBPS + default USB_GADGET + select USB_GADGET_SELECTED + config USB_FUSB300 tristate "Faraday FUSB300 USB Peripheral Controller" depends on !PHYS_ADDR_T_64BIT && HAS_DMA @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:288 @ dynamically linked module called "r8a66597_udc" and force all gadget drivers to also be dynamically linked. +config USB_GADGET_XILINX + boolean "Xilinx USB Driver" + depends on (XILINX_VIRTEX || MICROBLAZE || ARCH_ZYNQ) + select USB_GADGET_DUALSPEED + help + Sample USB gadget driver + config USB_RENESAS_USBHS_UDC tristate 'Renesas USBHS controller' depends on USB_RENESAS_USBHS @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:780 @ help This driver implements Ethernet style communication, in one of several ways: - + - The "Communication Device Class" (CDC) Ethernet Control Model. That protocol is often avoided with pure Ethernet adapters, in favor of simpler vendor-specific hardware, but is widely @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:822 @ If you say "y" here, the Ethernet gadget driver will try to provide a second device configuration, supporting RNDIS to talk to such Microsoft USB hosts. - + To make MS-Windows work with this, use Documentation/usb/linux.inf as the "driver info file". For versions of MS-Windows older than XP, you'll need to download drivers from Microsoft's website; a URL Index: linux-3.12.24-rt38-xilinx/drivers/usb/gadget/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/gadget/Makefile 2014-07-20 22:05:50.236066621 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/gadget/Makefile 2014-07-20 22:06:38.117276671 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:30 @ obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o +obj-$(CONFIG_USB_GADGET_XILINX) += xilinx_udc.o obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o obj-$(CONFIG_USB_MV_UDC) += mv_udc.o mv_udc-y := mv_udc_core.o +obj-$(CONFIG_USB_XUSBPS) += xilinx_usbps_udc.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o Index: linux-3.12.24-rt38-xilinx/drivers/usb/gadget/xilinx_udc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/usb/gadget/xilinx_udc.c 2014-07-20 22:06:38.146276193 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx USB peripheral controller driver + * + * Copyright (C) 2010 - 2013 Xilinx, Inc. + * + * Copyright (C) 2004 by Thomas Rathbone + * Copyright (C) 2005 by HP Labs + * Copyright (C) 2005 by David Brownell + * + * Some parts of this driver code is based on the driver for at91-series + * USB peripheral controller (at91_udc.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. + * + * 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., 675 Mass Ave, Cambridge, MA + * 02139, USA. + */ + +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/prefetch.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/io.h> +#include <linux/seq_file.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> +#include <linux/dma-mapping.h> +#include "gadget_chips.h" + +/* Register offsets for the USB device.*/ +#define XUSB_EP0_CONFIG_OFFSET 0x0000 /* EP0 Config Reg Offset */ +#define XUSB_SETUP_PKT_ADDR_OFFSET 0x0080 /* Setup Packet Address */ +#define XUSB_ADDRESS_OFFSET 0x0100 /* Address Register */ +#define XUSB_CONTROL_OFFSET 0x0104 /* Control Register */ +#define XUSB_STATUS_OFFSET 0x0108 /* Status Register */ +#define XUSB_FRAMENUM_OFFSET 0x010C /* Frame Number Register */ +#define XUSB_IER_OFFSET 0x0110 /* Interrupt Enable Register */ +#define XUSB_BUFFREADY_OFFSET 0x0114 /* Buffer Ready Register */ +#define XUSB_TESTMODE_OFFSET 0x0118 /* Test Mode Register */ +#define XUSB_DMA_RESET_OFFSET 0x0200 /* DMA Soft Reset Register */ +#define XUSB_DMA_CONTROL_OFFSET 0x0204 /* DMA Control Register */ +#define XUSB_DMA_DSAR_ADDR_OFFSET 0x0208 /* DMA source Address Reg */ +#define XUSB_DMA_DDAR_ADDR_OFFSET 0x020C /* DMA destination Addr Reg */ +#define XUSB_DMA_LENGTH_OFFSET 0x0210 /* DMA Length Register */ +#define XUSB_DMA_STATUS_OFFSET 0x0214 /* DMA Status Register */ + +/* Endpoint Configuration Space offsets */ +#define XUSB_EP_CFGSTATUS_OFFSET 0x00 /* Endpoint Config Status */ +#define XUSB_EP_BUF0COUNT_OFFSET 0x08 /* Buffer 0 Count */ +#define XUSB_EP_BUF1COUNT_OFFSET 0x0C /* Buffer 1 Count */ + +#define XUSB_CONTROL_USB_READY_MASK 0x80000000 /* USB ready Mask */ + +/* Interrupt register related masks.*/ +#define XUSB_STATUS_GLOBAL_INTR_MASK 0x80000000 /* Global Intr Enable */ +#define XUSB_STATUS_RESET_MASK 0x00800000 /* USB Reset Mask */ +#define XUSB_STATUS_SUSPEND_MASK 0x00400000 /* USB Suspend Mask */ +#define XUSB_STATUS_DISCONNECT_MASK 0x00200000 /* USB Disconnect Mask */ +#define XUSB_STATUS_FIFO_BUFF_RDY_MASK 0x00100000 /* FIFO Buff Ready Mask */ +#define XUSB_STATUS_FIFO_BUFF_FREE_MASK 0x00080000 /* FIFO Buff Free Mask */ +#define XUSB_STATUS_SETUP_PACKET_MASK 0x00040000 /* Setup packet received */ +#define XUSB_STATUS_EP1_BUFF2_COMP_MASK 0x00000200 /* EP 1 Buff 2 Processed */ +#define XUSB_STATUS_EP1_BUFF1_COMP_MASK 0x00000002 /* EP 1 Buff 1 Processed */ +#define XUSB_STATUS_EP0_BUFF2_COMP_MASK 0x00000100 /* EP 0 Buff 2 Processed */ +#define XUSB_STATUS_EP0_BUFF1_COMP_MASK 0x00000001 /* EP 0 Buff 1 Processed */ +#define XUSB_STATUS_HIGH_SPEED_MASK 0x00010000 /* USB Speed Mask */ +/* Suspend,Reset and Disconnect Mask */ +#define XUSB_STATUS_INTR_EVENT_MASK 0x00E00000 +/* Buffers completion Mask */ +#define XUSB_STATUS_INTR_BUFF_COMP_ALL_MASK 0x0000FEFF +/* Mask for buffer 0 and buffer 1 completion for all Endpoints */ +#define XUSB_STATUS_INTR_BUFF_COMP_SHIFT_MASK 0x00000101 +#define XUSB_STATUS_EP_BUFF2_SHIFT 8 /* EP buffer offset */ + +/* Endpoint Configuration Status Register */ +#define XUSB_EP_CFG_VALID_MASK 0x80000000 /* Endpoint Valid bit */ +#define XUSB_EP_CFG_STALL_MASK 0x40000000 /* Endpoint Stall bit */ +#define XUSB_EP_CFG_DATA_TOGGLE_MASK 0x08000000 /* Endpoint Data toggle */ + +/* USB device specific global configuration constants.*/ +#define XUSB_MAX_ENDPOINTS 8 /* Maximum End Points */ +#define XUSB_EP_NUMBER_ZERO 0 /* End point Zero */ + +/* Test Modes (Set Feature).*/ +#define TEST_J 1 /* Chirp J Test */ +#define TEST_K 2 /* Chirp K Test */ +#define TEST_SE0_NAK 3 /* Chirp SE0 Test */ +#define TEST_PKT 4 /* Packet Test */ + +#define CONFIGURATION_ONE 0x01 /* USB device configuration*/ +#define STANDARD_OUT_DEVICE 0x00 /* Out device */ +#define STANDARD_OUT_ENDPOINT 0x02 /* Standard Out end point */ + +#define XUSB_DMA_READ_FROM_DPRAM 0x80000000/**< DPRAM is the source + address for DMA transfer + */ +#define XUSB_DMA_DMASR_BUSY 0x80000000 /**< DMA busy*/ +#define XUSB_DMA_DMASR_ERROR 0x40000000 /**< DMA Error */ + +/* + * When this bit is set, the DMA buffer ready bit is set by hardware upon + * DMA transfer completion. + */ +#define XUSB_DMA_BRR_CTRL 0x40000000 /**< DMA bufready ctrl bit */ + +/* Phase States */ +#define SETUP_PHASE 0x0000 /* Setup Phase */ +#define DATA_PHASE 0x0001 /* Data Phase */ +#define STATUS_PHASE 0x0002 /* Status Phase */ + +#define EP_TRANSMIT 0 /* EP is IN endpoint */ +#define DRIVER_VERSION "10 October 2010" /* Driver version date */ + +#define EP0_MAX_PACKET 64 /* Endpoint 0 maximum packet length */ + +/** + * struct xusb_request - Xilinx USB device request structure + * @usb_req: Linux usb request structure + * @queue: usb device request queue + */ +struct xusb_request { + struct usb_request usb_req; + struct list_head queue; +}; + +/** + * struct xusb_ep - USB end point structure. + * @ep_usb: usb endpoint instance + * @queue: endpoint message queue + * @udc: xilinx usb peripheral driver instance pointer + * @epnumber: endpoint number + * @is_in: endpoint direction (IN or OUT) + * @stopped: endpoint active status + * @is_iso: endpoint type(isochronous or non isochronous) + * @maxpacket: maximum packet size the endpoint can store + * @rambase: the endpoint buffer address + * @buffer0count: the size of the packet recieved in the first buffer + * @buffer0ready: the busy state of first buffer + * @buffer1count: the size of the packet received in the second buffer + * @buffer1ready: the busy state of second buffer + * @eptype: endpoint transfer type (BULK, INTERRUPT) + * @curbufnum: current buffer of endpoint that will be processed next + * @endpointoffset: the endpoint register offset value + * @desc: pointer to the usb endpoint descriptor + * @data: pointer to the xusb_request structure + */ +struct xusb_ep { + struct usb_ep ep_usb; + struct list_head queue; + struct xusb_udc *udc; + u16 epnumber; + u8 is_in; + u8 stopped; + u8 is_iso; + u16 maxpacket; + u32 rambase; + u16 buffer0count; + u8 buffer0ready; + u16 buffer1count; + u8 buffer1ready; + u8 eptype; + u8 curbufnum; + u32 endpointoffset; + const struct usb_endpoint_descriptor *desc; + struct xusb_request *data; +}; + +/** + * struct xusb_udc - USB peripheral driver structure + * @gadget: USB gadget driver instance + * @lock: instance of spinlock + * @ep: an array of endpoint structures + * @base_address: the usb device base address + * @driver pointer: to the usb gadget driver instance + * @dma_enabled: flag indicating whether the dma is included in the system + * @status: status flag indicating the device cofiguration + * @read_fn: function pointer to read device registers + * @write_fn: function pointer to write to device registers + */ +struct xusb_udc { + struct usb_gadget gadget; + spinlock_t lock; + struct xusb_ep ep[8]; + void __iomem *base_address; + struct usb_gadget_driver *driver; + bool dma_enabled; + u8 status; + unsigned int (*read_fn) (void __iomem *); + void (*write_fn) (u32, void __iomem *); +}; + +/* Global xusb_udc variable*/ +static struct xusb_udc controller; + +/** + * struct cmdbuf - Standard USB Command Buffer Structure defined + * @setup: usb_ctrlrequest structure for control requests + * @contreadptr: pointer to endpoint0 read data + * @contwriteptr: pointer to endpoint0 write data + * @contreadcount: read data bytes count + * @contwritecount: write data bytes count + * @setupseqtx: tx status + * @setupseqrx: rx status + * @contreaddatabuffer: read data buffer for endpoint0 + */ +struct cmdbuf { + struct usb_ctrlrequest setup; + u8 *contreadptr; + u8 *contwriteptr; + u32 contreadcount; + u32 contwritecount; + u32 setupseqtx; + u32 setupseqrx; + u8 contreaddatabuffer[64]; +}; + +static struct cmdbuf ch9_cmdbuf; + +/* + * Initial Fixed locations provided for endpoint memory address + * in the USB core. The user needs to modify this as per his application. + */ +static u32 rambase[8] = { 0x22, 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, + 0x1600 }; + +static const char driver_name[] = "xilinx_udc"; +static const char ep0name[] = "ep0"; + +/* Control endpoint configuration.*/ +static struct usb_endpoint_descriptor config_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(0x40), +}; + +/** + * to_udc - Returns the udc instance pointer + * @g: pointer to the usb gadget driver instance + * + * Returns: xusb_udc pointer + */ +static inline struct xusb_udc *to_udc(struct usb_gadget *g) +{ + + return container_of(g, struct xusb_udc, gadget); +} + +/** + * xusb_write32 - little endian write to device registers + * @val: data to be written + * @addr: addr of device register + */ +static void xusb_write32(u32 val, void __iomem *addr) +{ + iowrite32(val, addr); +} + +/** + * xusb_read32 - little endian read from device registers + * @addr: addr of device register + */ +static unsigned int xusb_read32(void __iomem *addr) +{ + return ioread32(addr); +} + +/** + * xusb_write32_be - big endian write to device registers + * @val: data to be written + * @addr: addr of device register + */ +static void xusb_write32_be(u32 val, void __iomem *addr) +{ + iowrite32be(val, addr); +} + +/** + * xusb_read32_be - big endian read from device registers + * @addr: addr of device register + */ +static unsigned int xusb_read32_be(void __iomem *addr) +{ + return ioread32be(addr); +} + +/** + * setup_ctrl_wr_status_stage - Sets up the usb device status stages. + * @udc: pointer to the usb device controller structure. + */ +static void setup_ctrl_wr_status_stage(struct xusb_udc *udc) +{ + u32 epcfgreg; + + epcfgreg = (udc->read_fn(udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset)| + XUSB_EP_CFG_DATA_TOGGLE_MASK); + udc->write_fn(epcfgreg, (udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset)); + udc->write_fn(0, (udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset + + XUSB_EP_BUF0COUNT_OFFSET)); + udc->write_fn(1, (udc->base_address + XUSB_BUFFREADY_OFFSET)); +} + +/** + * ep_configure - Configures the given endpoint. + * @ep: pointer to the usb device endpoint structure. + * @udc: pointer to the usb peripheral controller structure. + * + * This function configures a specific endpoint with the given configuration + * data. + */ +static void ep_configure(struct xusb_ep *ep, struct xusb_udc *udc) +{ + u32 epcfgreg = 0; + + /* + * Configure the end point direction, type, Max Packet Size and the + * EP buffer location. + */ + epcfgreg = ((ep->is_in << 29) | (ep->eptype << 28) | + (ep->ep_usb.maxpacket << 15) | (ep->rambase)); + udc->write_fn(epcfgreg, (udc->base_address + ep->endpointoffset)); + + /* Set the Buffer count and the Buffer ready bits.*/ + udc->write_fn(ep->buffer0count, + (udc->base_address + ep->endpointoffset + + XUSB_EP_BUF0COUNT_OFFSET)); + udc->write_fn(ep->buffer1count, + (udc->base_address + ep->endpointoffset + + XUSB_EP_BUF1COUNT_OFFSET)); + if (ep->buffer0ready == 1) + udc->write_fn(1 << ep->epnumber, + (udc->base_address + XUSB_BUFFREADY_OFFSET)); + if (ep->buffer1ready == 1) + udc->write_fn(1 << (ep->epnumber + XUSB_STATUS_EP_BUFF2_SHIFT), + (udc->base_address + XUSB_BUFFREADY_OFFSET)); +} + +/** + * ep_sendrecv - Transmits or receives data to or from an endpoint. + * @ep: pointer to the usb endpoint configuration structure. + * @bufferptr: pointer to buffer containing the data to be sent. + * @bufferlen: The number of data bytes to be sent. + * @direction: The direction of data transfer (transmit or receive). + * + * Returns: 0 on success and 1 on failure + * + * This function copies the transmit/receive data to/from the end point buffer + * and enables the buffer for transmission/reception. + */ +static int ep_sendrecv(struct xusb_ep *ep, u8 *bufferptr, u32 bufferlen, + u8 direction) +{ + u32 *eprambase; + u32 bytestosend; + u8 *temprambase; + unsigned long timeout; + u32 srcaddr = 0; + u32 dstaddr = 0; + int rc = 0; + struct xusb_udc *udc = &controller; + + bytestosend = bufferlen; + + /* Put the transmit buffer into the correct ping-pong buffer.*/ + if ((!(ep->curbufnum)) && (!(ep->buffer0ready))) { + /* Get the Buffer address and copy the transmit data.*/ + eprambase = (u32 __force *)(ep->udc->base_address + + ep->rambase); + + if (ep->udc->dma_enabled) { + if (direction == EP_TRANSMIT) { + srcaddr = dma_map_single( + ep->udc->gadget.dev.parent, + bufferptr, bufferlen, DMA_TO_DEVICE); + dstaddr = virt_to_phys(eprambase); + udc->write_fn(bufferlen, + (ep->udc->base_address + + ep->endpointoffset + + XUSB_EP_BUF0COUNT_OFFSET)); + udc->write_fn(XUSB_DMA_BRR_CTRL | + (1 << (ep->epnumber)), + (ep->udc->base_address + + XUSB_DMA_CONTROL_OFFSET)); + } else { + srcaddr = virt_to_phys(eprambase); + dstaddr = dma_map_single( + ep->udc->gadget.dev.parent, + bufferptr, bufferlen, DMA_FROM_DEVICE); + udc->write_fn(XUSB_DMA_BRR_CTRL | + XUSB_DMA_READ_FROM_DPRAM | + (1 << (ep->epnumber)), + (ep->udc->base_address + + XUSB_DMA_CONTROL_OFFSET)); + } + /* + * Set the addresses in the DMA source and destination + * registers and then set the length into the DMA length + * register. + */ + udc->write_fn(srcaddr, (ep->udc->base_address + + XUSB_DMA_DSAR_ADDR_OFFSET)); + udc->write_fn(dstaddr, (ep->udc->base_address + + XUSB_DMA_DDAR_ADDR_OFFSET)); + udc->write_fn(bufferlen, (ep->udc->base_address + + XUSB_DMA_LENGTH_OFFSET)); + } else { + + while (bytestosend > 3) { + if (direction == EP_TRANSMIT) + *eprambase++ = *(u32 *) bufferptr; + else + *(u32 *) bufferptr = *eprambase++; + bufferptr += 4; + bytestosend -= 4; + } + temprambase = (u8 *) eprambase; + while (bytestosend--) { + if (direction == EP_TRANSMIT) + *temprambase++ = *bufferptr++; + else + *bufferptr++ = *temprambase++; + } + /* + * Set the Buffer count register with transmit length + * and enable the buffer for transmission. + */ + if (direction == EP_TRANSMIT) + udc->write_fn(bufferlen, + (ep->udc->base_address + + ep->endpointoffset + + XUSB_EP_BUF0COUNT_OFFSET)); + udc->write_fn(1 << ep->epnumber, + (ep->udc->base_address + + XUSB_BUFFREADY_OFFSET)); + } + ep->buffer0ready = 1; + ep->curbufnum = 1; + + } else + if ((ep->curbufnum == 1) && (!(ep->buffer1ready))) { + + /* Get the Buffer address and copy the transmit data.*/ + eprambase = (u32 __force *)(ep->udc->base_address + + ep->rambase + ep->ep_usb.maxpacket); + if (ep->udc->dma_enabled) { + if (direction == EP_TRANSMIT) { + srcaddr = dma_map_single( + ep->udc->gadget.dev.parent, + bufferptr, bufferlen, + DMA_TO_DEVICE); + dstaddr = virt_to_phys(eprambase); + udc->write_fn(bufferlen, + (ep->udc->base_address + + ep->endpointoffset + + XUSB_EP_BUF1COUNT_OFFSET)); + udc->write_fn(XUSB_DMA_BRR_CTRL | + (1 << (ep->epnumber + + XUSB_STATUS_EP_BUFF2_SHIFT)), + (ep->udc->base_address + + XUSB_DMA_CONTROL_OFFSET)); + } else { + srcaddr = virt_to_phys(eprambase); + dstaddr = dma_map_single( + ep->udc->gadget.dev.parent, + bufferptr, bufferlen, + DMA_FROM_DEVICE); + udc->write_fn(XUSB_DMA_BRR_CTRL | + XUSB_DMA_READ_FROM_DPRAM | + (1 << (ep->epnumber + + XUSB_STATUS_EP_BUFF2_SHIFT)), + (ep->udc->base_address + + XUSB_DMA_CONTROL_OFFSET)); + } + /* + * Set the addresses in the DMA source and + * destination registers and then set the length + * into the DMA length register. + */ + udc->write_fn(srcaddr, + (ep->udc->base_address + + XUSB_DMA_DSAR_ADDR_OFFSET)); + udc->write_fn(dstaddr, + (ep->udc->base_address + + XUSB_DMA_DDAR_ADDR_OFFSET)); + udc->write_fn(bufferlen, + (ep->udc->base_address + + XUSB_DMA_LENGTH_OFFSET)); + } else { + while (bytestosend > 3) { + if (direction == EP_TRANSMIT) + *eprambase++ = + *(u32 *) bufferptr; + else + *(u32 *) bufferptr = + *eprambase++; + bufferptr += 4; + bytestosend -= 4; + } + temprambase = (u8 *) eprambase; + while (bytestosend--) { + if (direction == EP_TRANSMIT) + *temprambase++ = *bufferptr++; + else + *bufferptr++ = *temprambase++; + } + /* + * Set the Buffer count register with transmit + * length and enable the buffer for + * transmission. + */ + if (direction == EP_TRANSMIT) + udc->write_fn(bufferlen, + (ep->udc->base_address + + ep->endpointoffset + + XUSB_EP_BUF1COUNT_OFFSET)); + udc->write_fn(1 << (ep->epnumber + + XUSB_STATUS_EP_BUFF2_SHIFT), + (ep->udc->base_address + + XUSB_BUFFREADY_OFFSET)); + } + ep->buffer1ready = 1; + ep->curbufnum = 0; + } else + /* + * None of the ping-pong buffer is free. Return a + * failure. + */ + return 1; + + if (ep->udc->dma_enabled) { + /* + * Wait till DMA transaction is complete and + * check whether the DMA transaction was + * successful. + */ + while ((udc->read_fn(ep->udc->base_address + + XUSB_DMA_STATUS_OFFSET) & XUSB_DMA_DMASR_BUSY) == + XUSB_DMA_DMASR_BUSY) { + timeout = jiffies + 10000; + + if (time_after(jiffies, timeout)) { + rc = -ETIMEDOUT; + goto clean; + } + + } + if ((udc->read_fn(ep->udc->base_address + + XUSB_DMA_STATUS_OFFSET) & XUSB_DMA_DMASR_ERROR) == + XUSB_DMA_DMASR_ERROR) + dev_dbg(&ep->udc->gadget.dev, "DMA Error\n"); +clean: + if (direction == EP_TRANSMIT) { + + dma_unmap_single(ep->udc->gadget.dev.parent, + srcaddr, bufferlen, DMA_TO_DEVICE); + } else { + + dma_unmap_single(ep->udc->gadget.dev.parent, + dstaddr, bufferlen, DMA_FROM_DEVICE); + } + + } + return rc; +} + +/** + * done - Exeutes the endpoint data transfer completion tasks. + * @ep: pointer to the usb device endpoint structure. + * @req: pointer to the usb request structure. + * @status: Status of the data transfer. + * + * Deletes the message from the queue and updates data transfer completion + * status. + */ +static void done(struct xusb_ep *ep, struct xusb_request *req, int status) +{ + u8 stopped = ep->stopped; + + list_del_init(&req->queue); + + if (req->usb_req.status == -EINPROGRESS) + req->usb_req.status = status; + else + status = req->usb_req.status; + + if (status && status != -ESHUTDOWN) + dev_dbg(&ep->udc->gadget.dev, "%s done %p, status %d\n", + ep->ep_usb.name, req, status); + ep->stopped = 1; + + spin_unlock(&ep->udc->lock); + if (req->usb_req.complete) + req->usb_req.complete(&ep->ep_usb, &req->usb_req); + spin_lock(&ep->udc->lock); + + ep->stopped = stopped; +} + +/** + * read_fifo - Reads the data from the given endpoint buffer. + * @ep: pointer to the usb device endpoint structure. + * @req: pointer to the usb request structure. + * + * Returns: 0 for success and error value on failure + * + * Pulls OUT packet data from the endpoint buffer. + */ +static int read_fifo(struct xusb_ep *ep, struct xusb_request *req) +{ + u8 *buf; + u32 is_short, count, bufferspace; + u8 bufoffset; + u8 two_pkts = 0; + struct xusb_udc *udc = &controller; + + if ((ep->buffer0ready == 1) && (ep->buffer1ready == 1)) { + dev_dbg(&ep->udc->gadget.dev, "%s: Packet NOT ready!\n", + __func__); + return -EINVAL; + } +top: + if (ep->curbufnum) + bufoffset = 0xC; + else + bufoffset = 0x08; + count = udc->read_fn(ep->udc->base_address + + ep->endpointoffset + bufoffset); + if (!ep->buffer0ready && !ep->buffer1ready) + two_pkts = 1; + + dev_dbg(&ep->udc->gadget.dev, + "curbufnum is %d and buf0rdy is %d, buf1rdy is %d\n", + ep->curbufnum, ep->buffer0ready, ep->buffer1ready); + + buf = req->usb_req.buf + req->usb_req.actual; + prefetchw(buf); + bufferspace = req->usb_req.length - req->usb_req.actual; + + req->usb_req.actual += min(count, bufferspace); + is_short = (count < ep->ep_usb.maxpacket); + + if (count) { + if (unlikely(!bufferspace)) { + /* This happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->usb_req.status != -EOVERFLOW) + dev_dbg(&ep->udc->gadget.dev, + "%s overflow %d\n", + ep->ep_usb.name, count); + req->usb_req.status = -EOVERFLOW; + } else { + if (!ep_sendrecv(ep, buf, count, 1)) { + dev_dbg(&ep->udc->gadget.dev, + "read %s, %d bytes%s req %p %d/%d\n", + ep->ep_usb.name, count, + is_short ? "/S" : "", req, + req->usb_req.actual, + req->usb_req.length); + bufferspace -= count; + /* Completion */ + if ((req->usb_req.actual == + req->usb_req.length) || is_short) { + done(ep, req, 0); + return 1; + } + + if (two_pkts) { + two_pkts = 0; + goto top; + } + + } else { + dev_dbg(&ep->udc->gadget.dev, + "rcv fail..curbufnum is %d and buf0rdy is" + "%d, buf1rdy is %d\n", ep->curbufnum, + ep->buffer0ready, ep->buffer1ready); + req->usb_req.actual -= min(count, bufferspace); + return -EINVAL; + } + } + } else + return -EINVAL; + + return 0; +} + +/** + * write_fifo - Writes data into the given endpoint buffer. + * @ep: pointer to the usb device endpoint structure. + * @req: pointer to the usb request structure. + * + * Returns: 0 for success and error value on failure + * + * Loads endpoint buffer for an IN packet. + */ +static int write_fifo(struct xusb_ep *ep, struct xusb_request *req) +{ + u8 *buf; + u32 max; + u32 length; + int is_last, is_short = 0; + + max = le16_to_cpu(ep->desc->wMaxPacketSize); + + if (req) { + buf = req->usb_req.buf + req->usb_req.actual; + prefetch(buf); + length = req->usb_req.length - req->usb_req.actual; + } else { + buf = NULL; + length = 0; + } + + length = min(length, max); + if (ep_sendrecv(ep, buf, length, EP_TRANSMIT) == 1) { + buf = req->usb_req.buf - req->usb_req.actual; + dev_dbg(&ep->udc->gadget.dev, "Send failure\n"); + return 0; + } else { + req->usb_req.actual += length; + + if (unlikely(length != max)) + is_last = is_short = 1; + else { + if (likely(req->usb_req.length != + req->usb_req.actual) || req->usb_req.zero) + is_last = 0; + else + is_last = 1; + } + dev_dbg(&ep->udc->gadget.dev, + "%s: wrote %s %d bytes%s%s %d left %p\n", __func__, + ep->ep_usb.name, length, + is_last ? "/L" : "", is_short ? "/S" : "", + req->usb_req.length - req->usb_req.actual, req); + + if (is_last) { + done(ep, req, 0); + return 1; + } + } + return 0; +} + +/** + * nuke - Cleans up the data transfer message list. + * @ep: pointer to the usb device endpoint structure. + * @status: Status of the data transfer. + */ +static void nuke(struct xusb_ep *ep, int status) +{ + struct xusb_request *req; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct xusb_request, queue); + + done(ep, req, status); + } +} + +/***************************** Endpoint related functions*********************/ +/** + * xusb_ep_set_halt - Stalls/unstalls the given endpoint. + * @_ep: pointer to the usb device endpoint structure. + * @value: value to indicate stall/unstall. + * + * Returns: 0 for success and error value on failure + */ +static int xusb_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct xusb_ep *ep = container_of(_ep, struct xusb_ep, ep_usb); + unsigned long flags; + u32 epcfgreg; + struct xusb_udc *udc = &controller; + + if (!_ep || (!ep->desc && ep->epnumber)) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + + if (ep->is_in && (!list_empty(&ep->queue)) && value) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EAGAIN; + } + if ((ep->buffer0ready == 1) || (ep->buffer1ready == 1)) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EAGAIN; + } + + if (value) { + /* Stall the device.*/ + epcfgreg = udc->read_fn(ep->udc->base_address + + ep->endpointoffset); + epcfgreg |= XUSB_EP_CFG_STALL_MASK; + + udc->write_fn(epcfgreg, + (ep->udc->base_address + ep->endpointoffset)); + ep->stopped = 1; + } else { + + ep->stopped = 0; + /* Unstall the device.*/ + epcfgreg = udc->read_fn(ep->udc->base_address + + ep->endpointoffset); + epcfgreg &= ~XUSB_EP_CFG_STALL_MASK; + udc->write_fn(epcfgreg, + (ep->udc->base_address + ep->endpointoffset)); + if (ep->epnumber) { + /* Reset the toggle bit.*/ + epcfgreg = udc->read_fn(ep->udc->base_address + + ep->endpointoffset); + epcfgreg &= ~XUSB_EP_CFG_DATA_TOGGLE_MASK; + udc->write_fn(epcfgreg, (ep->udc->base_address + + ep->endpointoffset)); + } + } + + spin_unlock_irqrestore(&ep->udc->lock, flags); + return 0; +} + +/** + * xusb_ep_enable - Enables the given endpoint. + * @_ep: pointer to the usb device endpoint structure. + * @desc: pointer to usb endpoint descriptor. + * + * Returns: 0 for success and error value on failure + */ +static int xusb_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct xusb_ep *ep = container_of(_ep, struct xusb_ep, ep_usb); + struct xusb_udc *dev = ep->udc; + u32 tmp; + u8 eptype = 0; + unsigned long flags; + u32 epcfg; + struct xusb_udc *udc = &controller; + + /* + * The check for _ep->name == ep0name is not done as this enable i used + * for enabling ep0 also. In other gadget drivers, this ep name is not + * used. + */ + if (!_ep || !desc || ep->desc || + desc->bDescriptorType != USB_DT_ENDPOINT) { + dev_dbg(&ep->udc->gadget.dev, "first check fails\n"); + return -EINVAL; + } + + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + dev_dbg(&ep->udc->gadget.dev, "bogus device state\n"); + return -ESHUTDOWN; + } + + + ep->is_in = ((desc->bEndpointAddress & USB_DIR_IN) != 0); + /* + * The address of the endpoint is encoded as follows: + * Bit 3...0: The endpoint number + * Bit 6...4: Reserved, reset to zero + * Bit 7: Direction, ignored for + * control endpoints + * 0 = OUT endpoint + * 1 = IN endpoint + */ + ep->epnumber = (desc->bEndpointAddress & 0x0f); + ep->stopped = 0; + ep->desc = desc; + ep->ep_usb.desc = desc; + tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + spin_lock_irqsave(&ep->udc->lock, flags); + ep->ep_usb.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + + switch (tmp) { + case USB_ENDPOINT_XFER_CONTROL: + dev_dbg(&ep->udc->gadget.dev, "only one control endpoint\n"); + /* NON- ISO */ + eptype = 0; + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EINVAL; + case USB_ENDPOINT_XFER_INT: + /* NON- ISO */ + eptype = 0; + if (ep->ep_usb.maxpacket > 64) + goto bogus_max; + break; + case USB_ENDPOINT_XFER_BULK: + /* NON- ISO */ + eptype = 0; + switch (ep->ep_usb.maxpacket) { + case 8: + case 16: + case 32: + case 64: + case 512: + goto ok; + } +bogus_max: + dev_dbg(&ep->udc->gadget.dev, "bogus maxpacket %d\n", + ep->ep_usb.maxpacket); + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EINVAL; + case USB_ENDPOINT_XFER_ISOC: + /* ISO */ + eptype = 1; + ep->is_iso = 1; + break; + } + +ok: ep->eptype = eptype; + ep->buffer0ready = 0; + ep->buffer1ready = 0; + ep->curbufnum = 0; + ep->rambase = rambase[ep->epnumber]; + ep_configure(ep, ep->udc); + + dev_dbg(&ep->udc->gadget.dev, "Enable Endpoint %d max pkt is %d\n", + ep->epnumber, ep->ep_usb.maxpacket); + + /* Enable the End point.*/ + epcfg = udc->read_fn(ep->udc->base_address + ep->endpointoffset); + epcfg |= XUSB_EP_CFG_VALID_MASK; + udc->write_fn(epcfg, + (ep->udc->base_address + ep->endpointoffset)); + if (ep->epnumber) + ep->rambase <<= 2; + + if (ep->epnumber) + udc->write_fn((udc->read_fn(ep->udc->base_address + + XUSB_IER_OFFSET) | + (XUSB_STATUS_INTR_BUFF_COMP_SHIFT_MASK << + ep->epnumber)), + (ep->udc->base_address + XUSB_IER_OFFSET)); + if ((ep->epnumber) && (!ep->is_in)) { + + /* Set the buffer ready bits.*/ + udc->write_fn(1 << ep->epnumber, (ep->udc->base_address + + XUSB_BUFFREADY_OFFSET)); + ep->buffer0ready = 1; + udc->write_fn((1 << (ep->epnumber + + XUSB_STATUS_EP_BUFF2_SHIFT)), + (ep->udc->base_address + + XUSB_BUFFREADY_OFFSET)); + ep->buffer1ready = 1; + } + + spin_unlock_irqrestore(&ep->udc->lock, flags); + + return 0; +} + +/** + * xusb_ep_disable - Disables the given endpoint. + * @_ep: pointer to the usb device endpoint structure. + * + * Returns: 0 for success and error value on failure + */ +static int xusb_ep_disable(struct usb_ep *_ep) +{ + struct xusb_ep *ep = container_of(_ep, struct xusb_ep, ep_usb); + unsigned long flags; + u32 epcfg; + struct xusb_udc *udc = &controller; + + if (ep == &ep->udc->ep[XUSB_EP_NUMBER_ZERO]) { + dev_dbg(&ep->udc->gadget.dev, "Ep0 disable called\n"); + return -EINVAL; + } + spin_lock_irqsave(&ep->udc->lock, flags); + + nuke(ep, -ESHUTDOWN); + + /* Restore the endpoint's pristine config */ + ep->desc = NULL; + ep->ep_usb.desc = NULL; + + ep->stopped = 1; + + /* + * The address of the endpoint is encoded as follows: + * Bit 3...0: The endpoint number + * Bit 6...4: Reserved, reset to zero + * Bit 7: Direction, ignored for + * control endpoints + * 0 = OUT endpoint + * 1 = IN endpoint + */ + dev_dbg(&ep->udc->gadget.dev, "USB Ep %d disable\n ", ep->epnumber); + + /* Disable the endpoint.*/ + epcfg = udc->read_fn(ep->udc->base_address + ep->endpointoffset); + epcfg &= ~XUSB_EP_CFG_VALID_MASK; + udc->write_fn(epcfg, (ep->udc->base_address + ep->endpointoffset)); + spin_unlock_irqrestore(&ep->udc->lock, flags); + return 0; +} + +/** + * xusb_ep_alloc_request - Initializes the request queue. + * @_ep: pointer to the usb device endpoint structure. + * @gfp_flags: Flags related to the request call. + * + * Returns: pointer to request structure on success and a NULL on failure. + */ +static struct usb_request *xusb_ep_alloc_request(struct usb_ep *_ep, + gfp_t gfp_flags) +{ + struct xusb_request *req; + + req = kmalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + memset(req, 0, sizeof(*req)); + INIT_LIST_HEAD(&req->queue); + return &req->usb_req; +} + +/** + * xusb_ep_free_request - Releases the request from queue. + * @_ep: pointer to the usb device endpoint structure. + * @_req: pointer to the usb request structure. + */ +static void xusb_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct xusb_ep *ep = container_of(_ep, struct xusb_ep, ep_usb); + struct xusb_request *req; + + req = container_of(_req, struct xusb_request, usb_req); + + if (!list_empty(&req->queue)) + dev_warn(&ep->udc->gadget.dev, "Error: No memory to free"); + + kfree(req); +} + +/** + * xusb_ep_queue - Adds the request to the queue. + * @_ep: pointer to the usb device endpoint structure. + * @_req: pointer to the usb request structure. + * @gfp_flags: Flags related to the request call. + * + * Returns: 0 for success and error value on failure + */ +static int xusb_ep_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct xusb_request *req; + struct xusb_ep *ep; + struct xusb_udc *dev; + unsigned long flags; + u32 length, count; + u8 *corebuf; + struct xusb_udc *udc = &controller; + + req = container_of(_req, struct xusb_request, usb_req); + ep = container_of(_ep, struct xusb_ep, ep_usb); + + if (!_req || !_req->complete || !_req->buf || + !list_empty(&req->queue)) { + dev_dbg(&ep->udc->gadget.dev, "invalid request\n"); + return -EINVAL; + } + + if (!_ep || (!ep->desc && ep->ep_usb.name != ep0name)) { + dev_dbg(&ep->udc->gadget.dev, "invalid ep\n"); + return -EINVAL; + } + + dev = ep->udc; + if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + dev_dbg(&ep->udc->gadget.dev, "%s, bogus device state %p\n", + __func__, dev->driver); + return -ESHUTDOWN; + } + + spin_lock_irqsave(&dev->lock, flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + + /* Try to kickstart any empty and idle queue */ + if (list_empty(&ep->queue)) { + if (!ep->epnumber) { + ep->data = req; + if (ch9_cmdbuf.setup.bRequestType & USB_DIR_IN) { + ch9_cmdbuf.contwriteptr = req->usb_req.buf + + req->usb_req.actual; + prefetch(ch9_cmdbuf.contwriteptr); + length = req->usb_req.length - + req->usb_req.actual; + corebuf = (void __force *) ((ep->rambase << 2) + + ep->udc->base_address); + ch9_cmdbuf.contwritecount = length; + length = count = min_t(u32, length, + EP0_MAX_PACKET); + while (length--) + *corebuf++ = *ch9_cmdbuf.contwriteptr++; + udc->write_fn(count, (ep->udc->base_address + + XUSB_EP_BUF0COUNT_OFFSET)); + udc->write_fn(1, (ep->udc->base_address + + XUSB_BUFFREADY_OFFSET)); + ch9_cmdbuf.contwritecount -= count; + } else { + if (ch9_cmdbuf.setup.wLength) { + ch9_cmdbuf.contreadptr = + req->usb_req.buf + + req->usb_req.actual; + udc->write_fn(req->usb_req.length , + (ep->udc->base_address + + XUSB_EP_BUF0COUNT_OFFSET)); + udc->write_fn(1, (ep->udc->base_address + + XUSB_BUFFREADY_OFFSET)); + } else { + setup_ctrl_wr_status_stage(udc); + req = NULL; + } + } + } else { + + if (ep->is_in) { + dev_dbg(&ep->udc->gadget.dev, + "write_fifo called from queue\n"); + if (write_fifo(ep, req) == 1) + req = NULL; + } else { + dev_dbg(&ep->udc->gadget.dev, + "read_fifo called from queue\n"); + if (read_fifo(ep, req) == 1) + req = NULL; + } + } + } + + if (req != NULL) + list_add_tail(&req->queue, &ep->queue); + spin_unlock_irqrestore(&dev->lock, flags); + return 0; +} + +/** + * xusb_ep_dequeue - Removes the request from the queue. + * @_ep: pointer to the usb device endpoint structure. + * @_req: pointer to the usb request structure. + * + * Returns: 0 for success and error value on failure + */ +static int xusb_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct xusb_ep *ep; + struct xusb_request *req; + unsigned long flags; + + ep = container_of(_ep, struct xusb_ep, ep_usb); + + if (!_ep || ep->ep_usb.name == ep0name) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + /* Make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->usb_req == _req) + break; + } + if (&req->usb_req != _req) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EINVAL; + } + + done(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&ep->udc->lock, flags); + + return 0; +} + +static struct usb_ep_ops xusb_ep_ops = { + .enable = xusb_ep_enable, + .disable = xusb_ep_disable, + + .alloc_request = xusb_ep_alloc_request, + .free_request = xusb_ep_free_request, + + .queue = xusb_ep_queue, + .dequeue = xusb_ep_dequeue, + .set_halt = xusb_ep_set_halt, +}; + +/** + * xusb_get_frame - Reads the current usb frame number. + * @gadget: pointer to the usb gadget structure. + * + * Returns: current frame number for success and error value on failure. + */ +static int xusb_get_frame(struct usb_gadget *gadget) +{ + + struct xusb_udc *udc = to_udc(gadget); + unsigned long flags; + int retval; + + if (!gadget) + return -ENODEV; + + local_irq_save(flags); + retval = udc->read_fn(udc->base_address + XUSB_FRAMENUM_OFFSET); + local_irq_restore(flags); + return retval; +} + +/** + * set_testmode - Sets the usb device into the given test mode. + * @udc: pointer to the usb controller structure. + * @testmode: Test mode to which the device is to be set. + * @bufptr: pointer to the buffer containing the test packet. + * + * Returns: This function never returns if the command is successful + * and -ENOTSUPP on failure. + * + * This function is needed for USB certification tests. + */ +static int set_testmode(struct xusb_udc *udc, u8 testmode, u8 *bufptr) +{ + u32 *src, *dst; + u32 count; + u32 crtlreg; + + /* Stop the SIE.*/ + crtlreg = udc->read_fn(udc->base_address + XUSB_CONTROL_OFFSET); + crtlreg &= ~XUSB_CONTROL_USB_READY_MASK; + udc->write_fn(crtlreg, (udc->base_address + XUSB_CONTROL_OFFSET)); + if (testmode == TEST_PKT) { + + if (bufptr == NULL) + /* Null pointer is passed.*/ + return -EINVAL; + + + src = (u32 *) bufptr; + dst = (u32 __force *) (udc->base_address); + count = 14; + + /* Copy Leurker PKT to DPRAM at 0.*/ + while (count--) + *dst++ = *src++; + } + + /* Set the test mode.*/ + udc->write_fn(testmode, (udc->base_address + XUSB_TESTMODE_OFFSET)); + /* Re-start the SIE.*/ + udc->write_fn(XUSB_CONTROL_USB_READY_MASK, + (udc->base_address + XUSB_CONTROL_OFFSET)); + + while (1) + ; /* Only way out is through hardware reset! */ + + return 0; +} + +/** + * xusb_ioctl - The i/o control function to call the testmode function. + * @gadget: pointer to the usb gadget structure. + * @code: Test mode to which the device is to be set. + * @param: Parameter to be sent for the test. + * + * Returns: 0 for success and error value on failure + */ +static int xusb_ioctl(struct usb_gadget *gadget, unsigned code, + unsigned long param) +{ + struct xusb_udc *udc = to_udc(gadget); + u8 *BufPtr; + + BufPtr = (u8 *) param; + + if ((code == TEST_J) || (code == TEST_K) || + (code == TEST_SE0_NAK) || (code == TEST_PKT)) + + return set_testmode(udc, code, BufPtr); + else + return -EINVAL; + + return 0; +} + +static int xudc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int xudc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static void xusb_release(struct device *dev); + +static const struct usb_gadget_ops xusb_udc_ops = { + .get_frame = xusb_get_frame, + .ioctl = xusb_ioctl, + .udc_start = xudc_start, + .udc_stop = xudc_stop, +}; + +/*-------------------------------------------------------------------------*/ +static struct xusb_udc controller = { + .gadget = { + .ops = &xusb_udc_ops, + .ep0 = &controller.ep[XUSB_EP_NUMBER_ZERO].ep_usb, + .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, + .is_otg = 0, + .is_a_peripheral = 0, + .b_hnp_enable = 0, + .a_hnp_support = 0, + .a_alt_hnp_support = 0, + .name = driver_name, + .dev = { + .init_name = "xilinx_udc", + .release = xusb_release, + }, + }, + .ep[0] = { + .ep_usb = { + .name = ep0name, + .ops = &xusb_ep_ops, + .maxpacket = 0x40, + }, + .udc = &controller, + .epnumber = 0, + .buffer0count = 0, + .buffer0ready = 0, + .buffer1count = 0, + .buffer1ready = 0, + .curbufnum = 0, + .eptype = 0, + .endpointoffset = 0, + }, + .ep[1] = { + .ep_usb = { + .name = "ep1", + .ops = &xusb_ep_ops, + }, + .udc = &controller, + .epnumber = 1, + .buffer0count = 0, + .buffer0ready = 0, + .buffer1count = 0, + .buffer1ready = 0, + .curbufnum = 0, + .eptype = 0, + .endpointoffset = 0, + }, + .ep[2] = { + .ep_usb = { + .name = "ep2", + .ops = &xusb_ep_ops, + }, + .udc = &controller, + .epnumber = 2, + .buffer0count = 0, + .buffer0ready = 0, + .buffer1count = 0, + .buffer1ready = 0, + .curbufnum = 0, + .eptype = 0, + .endpointoffset = 0, + }, + .ep[3] = { + .ep_usb = { + .name = "ep3", + .ops = &xusb_ep_ops, + }, + .udc = &controller, + .epnumber = 3, + .buffer0count = 0, + .buffer0ready = 0, + .buffer1count = 0, + .buffer1ready = 0, + .curbufnum = 0, + .eptype = 0, + .endpointoffset = 0, + }, + .ep[4] = { + .ep_usb = { + .name = "ep4", + .ops = &xusb_ep_ops, + }, + .udc = &controller, + .epnumber = 4, + .buffer0count = 0, + .buffer0ready = 0, + .buffer1count = 0, + .buffer1ready = 0, + .curbufnum = 0, + .eptype = 0, + .endpointoffset = 0, + }, + .ep[5] = { + .ep_usb = { + .name = "ep5", + .ops = &xusb_ep_ops, + }, + .udc = &controller, + .epnumber = 5, + .buffer0count = 0, + .buffer0ready = 0, + .buffer1count = 0, + .buffer1ready = 0, + .curbufnum = 0, + .eptype = 0, + .endpointoffset = 0, + }, + .ep[6] = { + .ep_usb = { + .name = "ep6", + .ops = &xusb_ep_ops, + }, + .udc = &controller, + .epnumber = 6, + .buffer0count = 0, + .buffer0ready = 0, + .buffer1count = 0, + .buffer1ready = 0, + .eptype = 0, + .curbufnum = 0, + .endpointoffset = 0, + }, + .ep[7] = { + .ep_usb = { + .name = "ep7", + .ops = &xusb_ep_ops, + }, + .udc = &controller, + .epnumber = 7, + .buffer0count = 0, + .buffer0ready = 0, + .buffer1count = 0, + .buffer1ready = 0, + .curbufnum = 0, + .eptype = 0, + .endpointoffset = 0, + }, + .status = 0, + .write_fn = xusb_write32_be, + .read_fn = xusb_read32_be, +}; + +/** + * xudc_reinit - Restores inital software state. + * @udc: pointer to the usb device controller structure. + */ +static void xudc_reinit(struct xusb_udc *udc) +{ + u32 ep_number; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); + + for (ep_number = 0; ep_number < XUSB_MAX_ENDPOINTS; ep_number++) { + struct xusb_ep *ep = &udc->ep[ep_number]; + + if (ep_number) { + list_add_tail(&ep->ep_usb.ep_list, + &udc->gadget.ep_list); + ep->ep_usb.maxpacket = (unsigned short)~0; + } + ep->desc = NULL; + ep->stopped = 0; + /* + * The configuration register address offset between + * each endpoint is 0x10. + */ + ep->endpointoffset = XUSB_EP0_CONFIG_OFFSET + + (ep_number * 0x10); + ep->is_in = 0; + ep->is_iso = 0; + ep->maxpacket = 0; + ep_configure(ep, udc); + udc->status = 0; + + /* Initialize one queue per endpoint */ + INIT_LIST_HEAD(&ep->queue); + } +} + +/** + * stop_activity - Stops any further activity on the device. + * @udc: pointer to the usb device controller structure. + */ +static void stop_activity(struct xusb_udc *udc) +{ + struct usb_gadget_driver *driver = udc->driver; + int i; + + if (udc->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + udc->gadget.speed = USB_SPEED_HIGH; + + for (i = 0; i < XUSB_MAX_ENDPOINTS; i++) { + struct xusb_ep *ep = &udc->ep[i]; + + ep->stopped = 1; + nuke(ep, -ESHUTDOWN); + } + if (driver) { + spin_unlock(&udc->lock); + driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + + xudc_reinit(udc); +} + +/** + * startup_intrhandler - The usb device controller interrupt handler. + * @callbackref: pointer to the reference value being passed. + * @intrstatus: The mask value containing the interrupt sources. + * + * This handler handles the RESET, SUSPEND and DISCONNECT interrupts. + */ +static void startup_intrhandler(void *callbackref, u32 intrstatus) +{ + struct xusb_udc *udc; + u32 intrreg; + + udc = (struct xusb_udc *) callbackref; + + if (intrstatus & XUSB_STATUS_RESET_MASK) { + dev_dbg(&udc->gadget.dev, "Reset\n"); + if (intrstatus & XUSB_STATUS_HIGH_SPEED_MASK) + udc->gadget.speed = USB_SPEED_HIGH; + else + udc->gadget.speed = USB_SPEED_FULL; + + if (udc->status == 1) { + udc->status = 0; + /* Set device address to 0.*/ + udc->write_fn(0, (udc->base_address + + XUSB_ADDRESS_OFFSET)); + } + /* Disable the Reset interrupt.*/ + intrreg = udc->read_fn(udc->base_address + + XUSB_IER_OFFSET); + + intrreg &= ~XUSB_STATUS_RESET_MASK; + udc->write_fn(intrreg, (udc->base_address + XUSB_IER_OFFSET)); + /* Enable thesuspend and disconnect.*/ + intrreg = + udc->read_fn(udc->base_address + XUSB_IER_OFFSET); + intrreg |= + (XUSB_STATUS_SUSPEND_MASK | + XUSB_STATUS_DISCONNECT_MASK); + udc->write_fn(intrreg, (udc->base_address + XUSB_IER_OFFSET)); + } + + if (intrstatus & XUSB_STATUS_DISCONNECT_MASK) { + + /* Disable the Disconnect interrupt.*/ + intrreg = + udc->read_fn(udc->base_address + XUSB_IER_OFFSET); + intrreg &= ~XUSB_STATUS_DISCONNECT_MASK; + udc->write_fn(intrreg, (udc->base_address + XUSB_IER_OFFSET)); + dev_dbg(&udc->gadget.dev, "Disconnect\n"); + if (udc->status == 1) { + udc->status = 0; + /* Set device address to 0.*/ + udc->write_fn(0, (udc->base_address + + XUSB_ADDRESS_OFFSET)); + /* Enable the USB device.*/ + udc->write_fn(XUSB_CONTROL_USB_READY_MASK, + (udc->base_address + XUSB_CONTROL_OFFSET)); + } + + /* Enable the suspend and reset interrupts.*/ + intrreg = (udc->read_fn(udc->base_address + XUSB_IER_OFFSET) | + (XUSB_STATUS_SUSPEND_MASK | + XUSB_STATUS_RESET_MASK)); + udc->write_fn(intrreg, (udc->base_address + XUSB_IER_OFFSET)); + stop_activity(udc); + } + + if (intrstatus & XUSB_STATUS_SUSPEND_MASK) { + dev_dbg(&udc->gadget.dev, "Suspend\n"); + /* Disable the Suspend interrupt.*/ + intrreg = (udc->read_fn(udc->base_address + XUSB_IER_OFFSET) & + ~XUSB_STATUS_SUSPEND_MASK); + udc->write_fn(intrreg, (udc->base_address + XUSB_IER_OFFSET)); + /* Enable the Disconnect and reset interrupts. */ + intrreg = (udc->read_fn(udc->base_address + XUSB_IER_OFFSET)| + (XUSB_STATUS_DISCONNECT_MASK | + XUSB_STATUS_RESET_MASK)); + udc->write_fn(intrreg, (udc->base_address + XUSB_IER_OFFSET)); + } +} + +/** + * setclearfeature - Executes the set feature and clear feature commands. + * @udc: pointer to the usb device controller structure. + * @flag: Value deciding the set or clear action. + * + * Processes the SET_FEATURE and CLEAR_FEATURE commands. + */ +static void set_clear_feature(struct xusb_udc *udc, int flag) +{ + u8 endpoint; + u8 outinbit; + u32 epcfgreg; + + switch (ch9_cmdbuf.setup.bRequestType) { + case STANDARD_OUT_DEVICE: + switch (ch9_cmdbuf.setup.wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + /* User needs to add code here.*/ + break; + + case USB_DEVICE_TEST_MODE: + /* + * The Test Mode will be executed + * after the status phase. + */ + break; + + default: + epcfgreg = udc->read_fn(udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset); + epcfgreg |= XUSB_EP_CFG_STALL_MASK; + udc->write_fn(epcfgreg, (udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset)); + break; + } + break; + + case STANDARD_OUT_ENDPOINT: + if (!ch9_cmdbuf.setup.wValue) { + endpoint = ch9_cmdbuf.setup.wIndex & 0xf; + outinbit = ch9_cmdbuf.setup.wIndex & 0x80; + outinbit = outinbit >> 7; + + /* Make sure direction matches.*/ + if (outinbit != udc->ep[endpoint].is_in) { + epcfgreg = udc->read_fn(udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset); + epcfgreg |= XUSB_EP_CFG_STALL_MASK; + + udc->write_fn(epcfgreg, (udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset)); + return; + } + + if (!endpoint) { + /* Clear the stall.*/ + epcfgreg = udc->read_fn(udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset); + + epcfgreg &= ~XUSB_EP_CFG_STALL_MASK; + + udc->write_fn(epcfgreg, (udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset)); + break; + } else { + if (flag == 1) { + epcfgreg = + udc->read_fn(udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO]. + endpointoffset); + epcfgreg |= XUSB_EP_CFG_STALL_MASK; + + udc->write_fn(epcfgreg, + (udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO]. + endpointoffset)); + } else { + /* Unstall the endpoint.*/ + epcfgreg = + udc->read_fn(udc->base_address + + udc->ep[endpoint].endpointoffset); + epcfgreg &= + ~(XUSB_EP_CFG_STALL_MASK | + XUSB_EP_CFG_DATA_TOGGLE_MASK); + udc->write_fn(epcfgreg, + (udc->base_address + + udc->ep[endpoint]. + endpointoffset)); + } + } + } + break; + + default: + epcfgreg = udc->read_fn(udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset); + epcfgreg |= XUSB_EP_CFG_STALL_MASK; + udc->write_fn(epcfgreg, (udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset)); + return; + } + + /* Cause and valid status phase to be issued.*/ + setup_ctrl_wr_status_stage(udc); + + return; +} + +/** + * execute_command - Processes the USB specification chapter 9 commands. + * @udc: pointer to the usb device controller structure. + * + * Returns: 0 for success and the same reuqest command if it is not handled. + */ +static int execute_command(struct xusb_udc *udc) +{ + + if ((ch9_cmdbuf.setup.bRequestType & USB_TYPE_MASK) == + USB_TYPE_STANDARD) { + /* Process the chapter 9 command.*/ + switch (ch9_cmdbuf.setup.bRequest) { + + case USB_REQ_CLEAR_FEATURE: + set_clear_feature(udc, 0); + break; + + case USB_REQ_SET_FEATURE: + set_clear_feature(udc, 1); + break; + + case USB_REQ_SET_ADDRESS: + setup_ctrl_wr_status_stage(udc); + break; + + case USB_REQ_SET_CONFIGURATION: + udc->status = 1; + return ch9_cmdbuf.setup.bRequest; + + default: + /* + * Return the same request to application for + * handling. + */ + return ch9_cmdbuf.setup.bRequest; + } + + } else + if ((ch9_cmdbuf.setup.bRequestType & USB_TYPE_MASK) == + USB_TYPE_CLASS) + return ch9_cmdbuf.setup.bRequest; + return 0; +} + +/** + * process_setup_pkt - Processes the setup packet. + * @udc: pointer to the usb device controller structure. + * @ctrl: pointer to the usb control endpoint structure. + * + * Returns: 0 for success and request to be handled by application if + * is not handled by the driver. + */ +static int process_setup_pkt(struct xusb_udc *udc, struct usb_ctrlrequest *ctrl) +{ + u32 *ep0rambase; + + /* Load up the chapter 9 command buffer.*/ + ep0rambase = (u32 __force *) (udc->base_address + + XUSB_SETUP_PKT_ADDR_OFFSET); + memcpy((void *)&ch9_cmdbuf.setup, (void *)ep0rambase, 8); + + ctrl->bRequestType = ch9_cmdbuf.setup.bRequestType; + ctrl->bRequest = ch9_cmdbuf.setup.bRequest; + ctrl->wValue = ch9_cmdbuf.setup.wValue; + ctrl->wIndex = ch9_cmdbuf.setup.wIndex; + ctrl->wLength = ch9_cmdbuf.setup.wLength; + + ch9_cmdbuf.setup.wValue = cpu_to_le16(ch9_cmdbuf.setup.wValue); + ch9_cmdbuf.setup.wIndex = cpu_to_le16(ch9_cmdbuf.setup.wIndex); + ch9_cmdbuf.setup.wLength = cpu_to_le16(ch9_cmdbuf.setup.wLength); + + /* Restore ReadPtr to data buffer.*/ + ch9_cmdbuf.contreadptr = &ch9_cmdbuf.contreaddatabuffer[0]; + ch9_cmdbuf.contreadcount = 0; + + if (ch9_cmdbuf.setup.bRequestType & USB_DIR_IN) { + /* Execute the get command.*/ + ch9_cmdbuf.setupseqrx = STATUS_PHASE; + ch9_cmdbuf.setupseqtx = DATA_PHASE; + return execute_command(udc); + } else { + /* Execute the put command.*/ + ch9_cmdbuf.setupseqrx = DATA_PHASE; + ch9_cmdbuf.setupseqtx = STATUS_PHASE; + return execute_command(udc); + } + /* Control should never come here.*/ + return 0; +} + +/** + * ep0_out_token - Processes the endpoint 0 OUT token. + * @udc: pointer to the usb device controller structure. + */ +static void ep0_out_token(struct xusb_udc *udc) +{ + struct xusb_ep *ep; + u8 count; + u8 *ep0rambase; + u16 index; + + ep = &udc->ep[0]; + switch (ch9_cmdbuf.setupseqrx) { + case STATUS_PHASE: + /* + * This resets both state machines for the next + * Setup packet. + */ + ch9_cmdbuf.setupseqrx = SETUP_PHASE; + ch9_cmdbuf.setupseqtx = SETUP_PHASE; + ep->data->usb_req.actual = ep->data->usb_req.length; + done(ep, ep->data, 0); + break; + + case DATA_PHASE: + count = udc->read_fn(udc->base_address + + XUSB_EP_BUF0COUNT_OFFSET); + /* Copy the data to be received from the DPRAM. */ + ep0rambase = + (u8 __force *) (udc->base_address + + (udc->ep[XUSB_EP_NUMBER_ZERO].rambase << 2)); + + for (index = 0; index < count; index++) + *ch9_cmdbuf.contreadptr++ = *ep0rambase++; + + ch9_cmdbuf.contreadcount += count; + if (ch9_cmdbuf.setup.wLength == ch9_cmdbuf.contreadcount) { + setup_ctrl_wr_status_stage(udc); + } else { + /* Set the Tx packet size and the Tx enable bit.*/ + udc->write_fn(0, (udc->base_address + + XUSB_EP_BUF0COUNT_OFFSET)); + udc->write_fn(1, (udc->base_address + + XUSB_BUFFREADY_OFFSET)); + } + break; + + default: + break; + } +} + +/** + * ep0_in_token - Processes the endpoint 0 IN token. + * @udc: pointer to the usb device controller structure. + */ +static void ep0_in_token(struct xusb_udc *udc) +{ + struct xusb_ep *ep; + u32 epcfgreg; + u16 count; + u16 length; + u8 *ep0rambase; + + ep = &udc->ep[0]; + switch (ch9_cmdbuf.setupseqtx) { + case STATUS_PHASE: + if (ch9_cmdbuf.setup.bRequest == USB_REQ_SET_ADDRESS) { + /* Set the address of the device.*/ + udc->write_fn(ch9_cmdbuf.setup.wValue, + (udc->base_address + + XUSB_ADDRESS_OFFSET)); + break; + } else + if (ch9_cmdbuf.setup.bRequest == USB_REQ_SET_FEATURE) { + if (ch9_cmdbuf.setup.bRequestType == + STANDARD_OUT_DEVICE) { + if (ch9_cmdbuf.setup.wValue == + USB_DEVICE_TEST_MODE) + udc->write_fn(TEST_J, + (udc->base_address + + XUSB_TESTMODE_OFFSET)); + } + } + ep->data->usb_req.actual = ch9_cmdbuf.setup.wLength; + done(ep, ep->data, 0); + break; + + case DATA_PHASE: + if (!ch9_cmdbuf.contwritecount) { + /* + * We're done with data transfer, next + * will be zero length OUT with data toggle of + * 1. Setup data_toggle. + */ + epcfgreg = udc->read_fn(udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset); + epcfgreg |= XUSB_EP_CFG_DATA_TOGGLE_MASK; + udc->write_fn(epcfgreg, + (udc->base_address + + udc->ep[XUSB_EP_NUMBER_ZERO].endpointoffset)); + count = 0; + + ch9_cmdbuf.setupseqtx = STATUS_PHASE; + + } else { + length = count = min_t(u32, ch9_cmdbuf.contwritecount, + EP0_MAX_PACKET); + /* Copy the data to be transmitted into the DPRAM. */ + ep0rambase = (u8 __force *) (udc->base_address + + (udc->ep[XUSB_EP_NUMBER_ZERO].rambase << 2)); + while (length--) + *ep0rambase++ = *ch9_cmdbuf.contwriteptr++; + + ch9_cmdbuf.contwritecount -= count; + } + udc->write_fn(count, (udc->base_address + + XUSB_EP_BUF0COUNT_OFFSET)); + udc->write_fn(1, (udc->base_address + XUSB_BUFFREADY_OFFSET)); + break; + + default: + break; + } +} + +/** + * control_ep_intrhandler - Endpoint 0 interrupt handler. + * @callbackref: pointer to the call back reference passed by the + * main interrupt handler. + * @intrstatus: It's the mask value for the interrupt sources on endpoint 0. + * + * Processes the commands received during enumeration phase. + */ +static void control_ep_intrhandler(void *callbackref, u32 intrstatus) +{ + struct xusb_udc *udc; + struct usb_ctrlrequest ctrl; + int status; + int epnum; + u32 intrreg; + + udc = (struct xusb_udc *) callbackref; + + /* Process the end point zero buffer interrupt.*/ + if (intrstatus & XUSB_STATUS_EP0_BUFF1_COMP_MASK) { + if (intrstatus & XUSB_STATUS_SETUP_PACKET_MASK) { + /* + * Enable the Disconnect, suspend and reset + * interrupts. + */ + intrreg = udc->read_fn(udc->base_address + + XUSB_IER_OFFSET); + intrreg |= (XUSB_STATUS_DISCONNECT_MASK | + XUSB_STATUS_SUSPEND_MASK | + XUSB_STATUS_RESET_MASK); + udc->write_fn(intrreg, + (udc->base_address + XUSB_IER_OFFSET)); + status = process_setup_pkt(udc, &ctrl); + if (status || ((ch9_cmdbuf.setup.bRequestType & + USB_TYPE_MASK) == USB_TYPE_CLASS)) { + /* + * Request is to be handled by the gadget + * driver. + */ + spin_unlock(&udc->lock); + udc->driver->setup(&udc->gadget, &ctrl); + spin_lock(&udc->lock); + } else { + if (ctrl.bRequest == USB_REQ_CLEAR_FEATURE) { + epnum = ctrl.wIndex & 0xf; + udc->ep[epnum].stopped = 0; + } + if (ctrl.bRequest == USB_REQ_SET_FEATURE) { + epnum = ctrl.wIndex & 0xf; + udc->ep[epnum].stopped = 1; + } + } + } else + if (intrstatus & XUSB_STATUS_FIFO_BUFF_RDY_MASK) + ep0_out_token(udc); + else if (intrstatus & + XUSB_STATUS_FIFO_BUFF_FREE_MASK) + ep0_in_token(udc); + } +} + +/** + * noncontrol_ep_intrhandler - Non control endpoint interrupt handler. + * @callbackref: pointer to the call back reference passed by the + * main interrupt handler. + * @epnum: End point number for which the interrupt is to be processed + * @intrstatus: It's the mask value for the interrupt sources on endpoint 0. + */ +static void noncontrol_ep_intrhandler(void *callbackref, u8 epnum, + u32 intrstatus) +{ + + struct xusb_request *req; + struct xusb_udc *udc; + struct xusb_ep *ep; + + udc = (struct xusb_udc *) callbackref; + ep = &udc->ep[epnum]; + + /* Process the End point interrupts.*/ + if (intrstatus & (XUSB_STATUS_EP0_BUFF1_COMP_MASK << epnum)) + ep->buffer0ready = 0; + if (intrstatus & (XUSB_STATUS_EP0_BUFF2_COMP_MASK << epnum)) + ep->buffer1ready = 0; + + if (list_empty(&ep->queue)) + req = NULL; + else + req = list_entry(ep->queue.next, struct xusb_request, queue); + if (!req) + return; + if (ep->is_in) + (void)write_fifo(ep, req); + else + (void)read_fifo(ep, req); +} + +/** + * xusb_udc_irq - The main interrupt handler. + * @irq: The interrupt number. + * @_udc: pointer to the usb device controller structure. + * + * Returns: IRQ_HANDLED after the interrupt is handled. + */ +static irqreturn_t xusb_udc_irq(int irq, void *_udc) +{ + struct xusb_udc *udc = _udc; + u32 intrstatus; + u8 index; + u32 bufintr; + + spin_lock(&(udc->lock)); + + /* Read the Interrupt Status Register.*/ + intrstatus = udc->read_fn(udc->base_address + XUSB_STATUS_OFFSET); + /* Call the handler for the event interrupt.*/ + if (intrstatus & XUSB_STATUS_INTR_EVENT_MASK) { + /* + * Check if there is any action to be done for : + * - USB Reset received {XUSB_STATUS_RESET_MASK} + * - USB Suspend received {XUSB_STATUS_SUSPEND_MASK} + * - USB Disconnect received {XUSB_STATUS_DISCONNECT_MASK} + */ + startup_intrhandler(udc, intrstatus); + } + + /* Check the buffer completion interrupts */ + if (intrstatus & XUSB_STATUS_INTR_BUFF_COMP_ALL_MASK) { + if (intrstatus & XUSB_STATUS_EP0_BUFF1_COMP_MASK) + control_ep_intrhandler(udc, intrstatus); + + for (index = 1; index < 8; index++) { + bufintr = ((intrstatus & + (XUSB_STATUS_EP1_BUFF1_COMP_MASK << + (index - 1))) || + (intrstatus & + (XUSB_STATUS_EP1_BUFF2_COMP_MASK << + (index - 1)))); + + if (bufintr) + noncontrol_ep_intrhandler(udc, index, + intrstatus); + } + } + spin_unlock(&(udc->lock)); + + return IRQ_HANDLED; +} + +/** + * xudc_start - Starts the device. + * @gadget: pointer to the usb gadget structure + * @driver: pointer to gadget driver structure + * + * Returns: zero always + */ +static int xudc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct xusb_udc *udc = &controller; + const struct usb_endpoint_descriptor *d = &config_bulk_out_desc; + + driver->driver.bus = NULL; + /* hook up the driver */ + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + udc->gadget.speed = driver->max_speed; + + /* Enable the USB device.*/ + xusb_ep_enable(&udc->ep[XUSB_EP_NUMBER_ZERO].ep_usb, d); + udc->write_fn(0, (udc->base_address + XUSB_ADDRESS_OFFSET)); + udc->write_fn(XUSB_CONTROL_USB_READY_MASK, + (udc->base_address + XUSB_CONTROL_OFFSET)); + + return 0; +} + +/** + * xudc_stop - stops the device. + * @gadget: pointer to the usb gadget structure + * @driver: pointer to usb gadget driver structure + * + * Returns: zero always + */ +static int xudc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct xusb_udc *udc = &controller; + unsigned long flags; + u32 crtlreg; + + /* Disable USB device.*/ + crtlreg = udc->read_fn(udc->base_address + XUSB_CONTROL_OFFSET); + crtlreg &= ~XUSB_CONTROL_USB_READY_MASK; + udc->write_fn(crtlreg, (udc->base_address + XUSB_CONTROL_OFFSET)); + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + stop_activity(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + + return 0; +} + +/** + * xusb_release - Releases device structure + * @dev: pointer to device structure + */ +static void xusb_release(struct device *dev) +{ +} + +/** + * xudc_probe - The device probe function for driver initialization. + * @pdev: pointer to the platform device structure. + * + * Returns: 0 for success and error value on failure + */ +static int xudc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res; + struct xusb_udc *udc = &controller; + int err; + int irq; + int ret; + + dev_dbg(&pdev->dev, "%s(%p)\n", __func__, pdev); + + /* Map the registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + udc->base_address = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!udc->base_address) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "unable to get irq\n"); + return irq; + } + err = devm_request_irq(&pdev->dev, irq, xusb_udc_irq, + 0, dev_name(&pdev->dev), udc); + if (err < 0) { + dev_err(&pdev->dev, "unable to request irq %d", irq); + return err; + } + + udc->dma_enabled = of_property_read_bool(np, "xlnx,include-dma"); + + udc->gadget.dev.parent = &pdev->dev; + + spin_lock_init(&udc->lock); + + /* Check for IP endianness */ + udc->write_fn(TEST_J, (udc->base_address + XUSB_TESTMODE_OFFSET)); + if ((udc->read_fn(udc->base_address + XUSB_TESTMODE_OFFSET)) + != TEST_J) { + controller.write_fn = xusb_write32; + controller.read_fn = xusb_read32; + } + udc->write_fn(0, (udc->base_address + XUSB_TESTMODE_OFFSET)); + + xudc_reinit(udc); + + /* Set device address to 0.*/ + udc->write_fn(0, (udc->base_address + XUSB_ADDRESS_OFFSET)); + + ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + if (ret) + dev_dbg(&pdev->dev, "usb_add_gadget_udc returned %d\n", ret); + + /* Enable the interrupts.*/ + udc->write_fn((XUSB_STATUS_GLOBAL_INTR_MASK | + XUSB_STATUS_RESET_MASK | + XUSB_STATUS_DISCONNECT_MASK | + XUSB_STATUS_SUSPEND_MASK | + XUSB_STATUS_FIFO_BUFF_RDY_MASK | + XUSB_STATUS_FIFO_BUFF_FREE_MASK | + XUSB_STATUS_EP0_BUFF1_COMP_MASK), + (udc->base_address + XUSB_IER_OFFSET)); + + platform_set_drvdata(pdev, udc); + + dev_info(&pdev->dev, "%s version %s\n", driver_name, DRIVER_VERSION); + dev_info(&pdev->dev, "%s #%d at 0x%08X mapped to 0x%08X\n", + driver_name, 0, (u32)res->start, + (u32 __force)udc->base_address); + + return 0; +} + +/** + * xudc_remove - Releases the resources allocated during the initialization. + * @pdev: pointer to the platform device structure. + * + * Returns: 0 for success and error value on failure + */ +static int xudc_remove(struct platform_device *pdev) +{ + struct xusb_udc *udc = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "remove\n"); + usb_del_gadget_udc(&udc->gadget); + if (udc->driver) + return -EBUSY; + + device_unregister(&udc->gadget.dev); + + return 0; +} + +/* Match table for of_platform binding */ +static const struct of_device_id usb_of_match[] = { + { .compatible = "xlnx,xps-usb2-device-4.00.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, usb_of_match); + +static struct platform_driver xudc_driver = { + .driver = { + .name = driver_name, + .owner = THIS_MODULE, + .of_match_table = usb_of_match, + }, + .probe = xudc_probe, + .remove = xudc_remove, +}; + +module_platform_driver(xudc_driver); + +MODULE_DESCRIPTION("Xilinx udc driver"); +MODULE_AUTHOR("Xilinx, Inc"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/usb/gadget/xilinx_usbps_udc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/usb/gadget/xilinx_usbps_udc.c 2014-07-20 22:06:38.181275615 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PS USB Device Controller Driver. + * + * Copyright (C) 2011 Xilinx, Inc. + * + * This file is based on fsl_udc_core.c file with few minor modifications + * to support Xilinx PS USB controller. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published bydrive + * the Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#undef VERBOSE + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/mm.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/xilinx_devices.h> +#include <linux/dmapool.h> +#include <linux/delay.h> + +#include <linux/io.h> +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/unaligned.h> +#include <asm/dma.h> + +#include <linux/usb/xilinx_usbps_otg.h> + +#define DRIVER_DESC "Xilinx PS USB Device Controller driver" +#define DRIVER_AUTHOR "Xilinx, Inc." +#define DRIVER_VERSION "Apr 01, 2011" + + +/* USB registers */ +#define USB_MAX_CTRL_PAYLOAD 64 + + /* USB DR device mode registers (Little Endian) */ +struct usb_dr_device { + /* Capability register */ + u8 res1[256]; + u16 caplength; /* Capability Register Length */ + u16 hciversion; /* Host Controller Interface Version */ + u32 hcsparams; /* Host Controller Structual Parameters */ + u32 hccparams; /* Host Controller Capability Parameters */ + u8 res2[20]; + u32 dciversion; /* Device Controller Interface Version */ + u32 dccparams; /* Device Controller Capability Parameters */ + u8 res3[24]; + /* Operation register */ + u32 usbcmd; /* USB Command Register */ + u32 usbsts; /* USB Status Register */ + u32 usbintr; /* USB Interrupt Enable Register */ + u32 frindex; /* Frame Index Register */ + u8 res4[4]; + u32 deviceaddr; /* Device Address */ + u32 endpointlistaddr; /* Endpoint List Address Register */ + u8 res5[4]; + u32 burstsize; /* Master Interface Data Burst Size Register */ + u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */ + u8 res6[24]; + u32 configflag; /* Configure Flag Register */ + u32 portsc1; /* Port 1 Status and Control Register */ + u8 res7[28]; + u32 otgsc; /* On-The-Go Status and Control */ + u32 usbmode; /* USB Mode Register */ + u32 endptsetupstat; /* Endpoint Setup Status Register */ + u32 endpointprime; /* Endpoint Initialization Register */ + u32 endptflush; /* Endpoint Flush Register */ + u32 endptstatus; /* Endpoint Status Register */ + u32 endptcomplete; /* Endpoint Complete Register */ + u32 endptctrl[6]; /* Endpoint Control Registers */ +}; + +/* ep0 transfer state */ +#define WAIT_FOR_SETUP 0 +#define DATA_STATE_XMIT 1 +#define WAIT_FOR_OUT_STATUS 3 +#define DATA_STATE_RECV 4 + +/* Device Controller Capability Parameter register */ +#define DCCPARAMS_DC 0x00000080 +#define DCCPARAMS_DEN_MASK 0x0000001f + +/* Frame Index Register Bit Masks */ +#define USB_FRINDEX_MASKS 0x3fff +/* USB CMD Register Bit Masks */ +#define USB_CMD_RUN_STOP 0x00000001 +#define USB_CMD_CTRL_RESET 0x00000002 +#define USB_CMD_ASYNC_SCHEDULE_EN 0x00000020 +#define USB_CMD_SUTW 0x00002000 +#define USB_CMD_ATDTW 0x00004000 + +/* USB STS Register Bit Masks */ +#define USB_STS_INT 0x00000001 +#define USB_STS_ERR 0x00000002 +#define USB_STS_PORT_CHANGE 0x00000004 +#define USB_STS_SYS_ERR 0x00000010 +#define USB_STS_RESET 0x00000040 +#define USB_STS_SOF 0x00000080 +#define USB_STS_SUSPEND 0x00000100 + +/* USB INTR Register Bit Masks */ +#define USB_INTR_INT_EN 0x00000001 +#define USB_INTR_ERR_INT_EN 0x00000002 +#define USB_INTR_PTC_DETECT_EN 0x00000004 +#define USB_INTR_SYS_ERR_EN 0x00000010 +#define USB_INTR_RESET_EN 0x00000040 +#define USB_INTR_SOF_EN 0x00000080 +#define USB_INTR_DEVICE_SUSPEND 0x00000100 + +/* Device Address bit masks */ +#define USB_DEVICE_ADDRESS_MASK 0xFE000000 +#define USB_DEVICE_ADDRESS_BIT_POS 25 + +/* endpoint list address bit masks */ +#define USB_EP_LIST_ADDRESS_MASK 0xfffff800 + +/* PORTSCX Register Bit Masks */ +#define PORTSCX_CURRENT_CONNECT_STATUS 0x00000001 +#define PORTSCX_PORT_ENABLE 0x00000004 +#define PORTSCX_PORT_EN_DIS_CHANGE 0x00000008 +#define PORTSCX_OVER_CURRENT_CHG 0x00000020 +#define PORTSCX_PORT_FORCE_RESUME 0x00000040 +#define PORTSCX_PORT_SUSPEND 0x00000080 +#define PORTSCX_PORT_RESET 0x00000100 +#define PORTSCX_PHY_LOW_POWER_SPD 0x00800000 +#define PORTSCX_PORT_SPEED_MASK 0x0C000000 +#define PORTSCX_PORT_WIDTH 0x10000000 +#define PORTSCX_PHY_TYPE_SEL 0xC0000000 + +/* bit 27-26 are port speed */ +#define PORTSCX_PORT_SPEED_FULL 0x00000000 +#define PORTSCX_PORT_SPEED_LOW 0x04000000 +#define PORTSCX_PORT_SPEED_HIGH 0x08000000 +#define PORTSCX_PORT_SPEED_UNDEF 0x0C000000 + +/* bit 28 is parallel transceiver width for UTMI interface */ +#define PORTSCX_PTW_16BIT 0x10000000 + +/* bit 31-30 are port transceiver select */ +#define PORTSCX_PTS_UTMI 0x00000000 +#define PORTSCX_PTS_ULPI 0x80000000 +#define PORTSCX_PTS_FSLS 0xC0000000 + +/* otgsc Register Bit Masks */ +#define OTGSC_CTRL_OTG_TERM 0x00000008 + +/* USB MODE Register Bit Masks */ +#define USB_MODE_CTRL_MODE_IDLE 0x00000000 +#define USB_MODE_CTRL_MODE_DEVICE 0x00000002 +#define USB_MODE_CTRL_MODE_HOST 0x00000003 +#define USB_MODE_SETUP_LOCK_OFF 0x00000008 + +/* Endpoint Setup Status bit masks */ +#define EP_SETUP_STATUS_MASK 0x0000003F +#define EP_SETUP_STATUS_EP0 0x00000001 + +/* ENDPOINTCTRLx Register Bit Masks */ +#define EPCTRL_TX_ENABLE 0x00800000 +#define EPCTRL_TX_DATA_TOGGLE_RST 0x00400000 /* Not EP0 */ +#define EPCTRL_TX_EP_STALL 0x00010000 +#define EPCTRL_RX_ENABLE 0x00000080 +#define EPCTRL_RX_DATA_TOGGLE_RST 0x00000040 /* Not EP0 */ +#define EPCTRL_RX_EP_STALL 0x00000001 + +/* bit 19-18 and 3-2 are endpoint type */ +#define EPCTRL_TX_EP_TYPE_SHIFT 18 +#define EPCTRL_RX_EP_TYPE_SHIFT 2 + + +/* Endpoint Queue Head data struct + * Rem: all the variables of qh are LittleEndian Mode + * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr + */ +struct ep_queue_head { + u32 max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len + and IOS(15) */ + u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */ + u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */ + u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15), + MultO(11-10), STS (7-0) */ + u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */ + u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */ + u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */ + u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */ + u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */ + u32 res1; + u8 setup_buffer[8]; /* Setup data 8 bytes */ + u32 res2[4]; +}; + +/* Endpoint Queue Head Bit Masks */ +#define EP_QUEUE_HEAD_MULT_POS 30 +#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000 +#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16 +#define EP_QUEUE_HEAD_IOS 0x00008000 +#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040 +#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080 +#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0 +#define EP_MAX_LENGTH_TRANSFER 0x4000 + +/* Endpoint Transfer Descriptor data struct */ +/* Rem: all the variables of td are LittleEndian Mode */ +struct ep_td_struct { + u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set + indicate invalid */ + u32 size_ioc_sts; /* Total bytes (30-16), IOC (15), + MultO(11-10), STS (7-0) */ + u32 buff_ptr0; /* Buffer pointer Page 0 */ + u32 buff_ptr1; /* Buffer pointer Page 1 */ + u32 buff_ptr2; /* Buffer pointer Page 2 */ + u32 buff_ptr3; /* Buffer pointer Page 3 */ + u32 buff_ptr4; /* Buffer pointer Page 4 */ + u32 res; + /* 32 bytes */ + dma_addr_t td_dma; /* dma address for this td */ + /* virtual address of next td specified in next_td_ptr */ + struct ep_td_struct *next_td_virt; +}; + +/* Endpoint Transfer Descriptor bit Masks */ +#define DTD_NEXT_TERMINATE 0x00000001 +#define DTD_IOC 0x00008000 +#define DTD_STATUS_ACTIVE 0x00000080 +#define DTD_STATUS_HALTED 0x00000040 +#define DTD_STATUS_DATA_BUFF_ERR 0x00000020 +#define DTD_STATUS_TRANSACTION_ERR 0x00000008 +#define DTD_RESERVED_FIELDS 0x80007300 +#define DTD_ADDR_MASK 0xFFFFFFE0 +#define DTD_PACKET_SIZE 0x7FFF0000 +#define DTD_LENGTH_BIT_POS 16 +#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \ + DTD_STATUS_DATA_BUFF_ERR | \ + DTD_STATUS_TRANSACTION_ERR) +/* Alignment requirements; must be a power of two */ +#define DTD_ALIGNMENT 0x20 +#define QH_ALIGNMENT 2048 + +/* Controller dma boundary */ +#define UDC_DMA_BOUNDARY 0x1000 + +/*-------------------------------------------------------------------------*/ + +/* ### driver private data + */ +struct xusbps_req { + struct usb_request req; + struct list_head queue; + /* ep_queue() func will add + a request->queue into a udc_ep->queue 'd tail */ + struct xusbps_ep *ep; + unsigned mapped:1; + + struct ep_td_struct *head, *tail; /* For dTD List + cpu endian Virtual addr */ + unsigned int dtd_count; +}; + +#define REQ_UNCOMPLETE 1 + +struct xusbps_ep { + struct usb_ep ep; + struct list_head queue; + struct xusbps_udc *udc; + struct ep_queue_head *qh; + struct usb_gadget *gadget; + + char name[14]; + unsigned stopped:1; + unsigned int wedge; +}; + +#define EP_DIR_IN 1 +#define EP_DIR_OUT 0 + +struct xusbps_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct completion *done; /* to make sure release() is done */ + struct xusbps_ep *eps; + unsigned int max_ep; + unsigned int irq; + + /* xusbps otg transceiver */ + struct xusbps_otg *xotg; + + struct usb_ctrlrequest local_setup_buff; + spinlock_t lock; + struct usb_phy *transceiver; + unsigned softconnect:1; + unsigned vbus_active:1; + unsigned stopped:1; + unsigned remote_wakeup:1; + + struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ + struct xusbps_req *status_req; /* ep0 status request */ + struct dma_pool *td_pool; /* dma pool for DTD */ + enum xusbps_usb2_phy_modes phy_mode; + + size_t ep_qh_size; /* size after alignment adjustment*/ + dma_addr_t ep_qh_dma; /* dma address of QH */ + + u32 max_pipes; /* Device max pipes */ + u32 resume_state; /* USB state to resume */ + u32 usb_state; /* USB current state */ + u32 ep0_state; /* Endpoint zero state */ + u32 ep0_dir; /* Endpoint zero direction: can be + USB_DIR_IN or USB_DIR_OUT */ + u8 device_address; /* Device USB address */ +}; + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +#define DBG(fmt, args...) pr_debug("[%s] " fmt "\n", \ + __func__, ## args) +#else +#define DBG(fmt, args...) do {} while (0) +#endif + + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(stuff...) do {} while (0) +#endif + +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARNING(stuff...) pr_warn("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) + +/*-------------------------------------------------------------------------*/ + +/* ### Add board specific defines here */ + +/* pipe direction macro from device view */ +#define USB_RECV 0 /* OUT EP */ +#define USB_SEND 1 /* IN EP */ + +/* internal used help routines. */ +#define ep_index(EP) ((EP)->ep.desc->bEndpointAddress&0xF) +#define ep_maxpacket(EP) ((EP)->ep.maxpacket) +#define ep_is_in(EP) ((ep_index(EP) == 0) ? (EP->udc->ep0_dir == \ + USB_DIR_IN) : ((EP)->ep.desc->bEndpointAddress \ + & USB_DIR_IN) == USB_DIR_IN) +#define get_ep_by_pipe(udc, pipe) ((pipe == 1) ? &udc->eps[0] : \ + &udc->eps[pipe]) +#define get_pipe_by_windex(windex) ((windex & USB_ENDPOINT_NUMBER_MASK) \ + * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) + + +static int xusbps_udc_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + + switch (event) { + case PRE_RATE_CHANGE: + /* if a rate change is announced we need to check whether we can + * maintain the current frequency by changing the clock + * dividers. + */ + /* fall through */ + case POST_RATE_CHANGE: + return NOTIFY_OK; + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +static int xusbps_udc_clk_init(struct platform_device *pdev) +{ + struct xusbps_usb2_platform_data *pdata = pdev->dev.platform_data; + int rc; + + rc = clk_prepare_enable(pdata->clk); + if (rc) { + dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + goto err_out_clk_put; + } + + pdata->clk_rate_change_nb.notifier_call = xusbps_udc_clk_notifier_cb; + pdata->clk_rate_change_nb.next = NULL; + if (clk_notifier_register(pdata->clk, &pdata->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); + + return 0; + +err_out_clk_put: + clk_put(pdata->clk); + + return rc; +} + +static void xusbps_udc_clk_release(struct platform_device *pdev) +{ + struct xusbps_usb2_platform_data *pdata = pdev->dev.platform_data; + + clk_disable_unprepare(pdata->clk); +} + + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +static const char driver_name[] = "xusbps-udc"; +static const char driver_desc[] = DRIVER_DESC; + +static struct usb_dr_device __iomem *dr_regs; + +/* it is initialized in probe() */ +static struct xusbps_udc *udc_controller; + +static const struct usb_endpoint_descriptor +xusbps_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, +}; + +static void xusbps_ep_fifo_flush(struct usb_ep *_ep); + +static inline u32 xusbps_readl(const unsigned __iomem *addr) +{ + return readl(addr); +} + +static inline void xusbps_writel(u32 val32, unsigned __iomem *addr) +{ + writel(val32, addr); +} + +/******************************************************************** + * Internal Used Function +********************************************************************/ +/*----------------------------------------------------------------- + * done() - retire a request; caller blocked irqs + * @status : request status to be set, only works when + * request is still in progress. + *--------------------------------------------------------------*/ +static void done(struct xusbps_ep *ep, struct xusbps_req *req, int status) +{ + struct xusbps_udc *udc = NULL; + unsigned char stopped = ep->stopped; + struct ep_td_struct *curr_td, *next_td; + int j; + + udc = (struct xusbps_udc *)ep->udc; + /* Removed the req from xusbps_ep->queue */ + list_del_init(&req->queue); + + /* req.status should be set as -EINPROGRESS in ep_queue() */ + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + /* Free dtd for the request */ + next_td = req->head; + for (j = 0; j < req->dtd_count; j++) { + curr_td = next_td; + if (j != req->dtd_count - 1) + next_td = curr_td->next_td_virt; + dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); + } + + if (req->mapped) { + dma_unmap_single(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + ep_is_in(ep) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } else + dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + ep_is_in(ep) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + + if (status && (status != -ESHUTDOWN)) + VDBG("complete %s req %p stat %d len %u/%u", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + ep->stopped = 1; + + spin_unlock(&ep->udc->lock); + /* complete() is from gadget layer, + * eg fsg->bulk_in_complete() */ + if (req->req.complete) + req->req.complete(&ep->ep, &req->req); + + spin_lock(&ep->udc->lock); + ep->stopped = stopped; +} + +/*----------------------------------------------------------------- + * nuke(): delete all requests related to this ep + * called with spinlock held + *--------------------------------------------------------------*/ +static void nuke(struct xusbps_ep *ep, int status) +{ + ep->stopped = 1; + + /* Flush fifo */ + xusbps_ep_fifo_flush(&ep->ep); + + /* Whether this eq has request linked */ + while (!list_empty(&ep->queue)) { + struct xusbps_req *req = NULL; + + req = list_entry(ep->queue.next, struct xusbps_req, queue); + done(ep, req, status); + } +} + +/*------------------------------------------------------------------ + Internal Hardware related function + ------------------------------------------------------------------*/ + +static int dr_controller_setup(struct xusbps_udc *udc) +{ + unsigned int tmp, portctrl; + unsigned long timeout; +#define XUSBPS_UDC_RESET_TIMEOUT 1000 + + /* Config PHY interface */ + portctrl = xusbps_readl(&dr_regs->portsc1); + portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); + switch (udc->phy_mode) { + case XUSBPS_USB2_PHY_ULPI: + portctrl |= PORTSCX_PTS_ULPI; + break; + case XUSBPS_USB2_PHY_UTMI_WIDE: + portctrl |= PORTSCX_PTW_16BIT; + /* fall through */ + case XUSBPS_USB2_PHY_UTMI: + portctrl |= PORTSCX_PTS_UTMI; + break; + case XUSBPS_USB2_PHY_SERIAL: + portctrl |= PORTSCX_PTS_FSLS; + break; + default: + return -EINVAL; + } + xusbps_writel(portctrl, &dr_regs->portsc1); + + /* Stop and reset the usb controller */ + tmp = xusbps_readl(&dr_regs->usbcmd); + tmp &= ~USB_CMD_RUN_STOP; + xusbps_writel(tmp, &dr_regs->usbcmd); + + tmp = xusbps_readl(&dr_regs->usbcmd); + tmp |= USB_CMD_CTRL_RESET; + xusbps_writel(tmp, &dr_regs->usbcmd); + + /* Wait for reset to complete */ + timeout = jiffies + XUSBPS_UDC_RESET_TIMEOUT; + while (xusbps_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) { + if (time_after(jiffies, timeout)) { + ERR("udc reset timeout!\n"); + return -ETIMEDOUT; + } + cpu_relax(); + } + + /* Set the controller as device mode */ + tmp = xusbps_readl(&dr_regs->usbmode); + tmp |= USB_MODE_CTRL_MODE_DEVICE; + /* Disable Setup Lockout */ + tmp |= USB_MODE_SETUP_LOCK_OFF; + xusbps_writel(tmp, &dr_regs->usbmode); + + /* Set OTG Terminate bit */ + tmp = xusbps_readl(&dr_regs->otgsc); + tmp |= OTGSC_CTRL_OTG_TERM; + xusbps_writel(tmp, &dr_regs->otgsc); + + /* Clear the setup status */ + xusbps_writel(0, &dr_regs->usbsts); + + tmp = udc->ep_qh_dma; + tmp &= USB_EP_LIST_ADDRESS_MASK; + xusbps_writel(tmp, &dr_regs->endpointlistaddr); + + VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x", + udc->ep_qh, (int)tmp, + xusbps_readl(&dr_regs->endpointlistaddr)); + + return 0; +} + +/* Enable DR irq and set controller to run state */ +static void dr_controller_run(struct xusbps_udc *udc) +{ + u32 temp; + +#ifdef CONFIG_USB_ZYNQ_PHY + if (gadget_is_otg(&udc->gadget)) { + /* Enable DR irq reg except suspend interrupt */ + temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN + | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN + | USB_INTR_SYS_ERR_EN; + } else { + /* Enable DR irq reg */ + temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN + | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN + | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; + } +#else + /* Enable DR irq reg */ + temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN + | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN + | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; +#endif + + xusbps_writel(temp, &dr_regs->usbintr); + + /* + * Enable disconnect notification using B session end interrupt. + * This is a SW workaround for USB disconnect detection as mentioned + * in AR# 47538 + */ + if (!gadget_is_otg(&udc->gadget)) { + temp = xusbps_readl(&dr_regs->otgsc); + temp |= OTGSC_BSEIE; + xusbps_writel(temp, &dr_regs->otgsc); + } + + /* Clear stopped bit */ + udc->stopped = 0; + + /* Set the controller as device mode */ + temp = xusbps_readl(&dr_regs->usbmode); + temp |= USB_MODE_CTRL_MODE_DEVICE; + temp |= USB_MODE_SETUP_LOCK_OFF; + xusbps_writel(temp, &dr_regs->usbmode); + + /* Set OTG Terminate bit */ + temp = xusbps_readl(&dr_regs->otgsc); + temp |= OTGSC_CTRL_OTG_TERM; + xusbps_writel(temp, &dr_regs->otgsc); + + /* Set controller to Run */ + temp = xusbps_readl(&dr_regs->usbcmd); + temp |= USB_CMD_RUN_STOP; + xusbps_writel(temp, &dr_regs->usbcmd); +} + +static void dr_controller_stop(struct xusbps_udc *udc) +{ + unsigned int tmp; + + /* disable all INTR */ + xusbps_writel(0, &dr_regs->usbintr); + + /* Set stopped bit for isr */ + udc->stopped = 1; + + /* disable IO output */ +/* usb_sys_regs->control = 0; */ + + /* set controller to Stop */ + tmp = xusbps_readl(&dr_regs->usbcmd); + tmp &= ~USB_CMD_RUN_STOP; + xusbps_writel(tmp, &dr_regs->usbcmd); +} + +static void dr_ep_setup(unsigned char ep_num, unsigned char dir, + unsigned char ep_type) +{ + unsigned int tmp_epctrl = 0; + + tmp_epctrl = xusbps_readl(&dr_regs->endptctrl[ep_num]); + if (dir) { + if (ep_num) + tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; + tmp_epctrl |= EPCTRL_TX_ENABLE; + tmp_epctrl |= ((unsigned int)(ep_type) + << EPCTRL_TX_EP_TYPE_SHIFT); + } else { + if (ep_num) + tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; + tmp_epctrl |= EPCTRL_RX_ENABLE; + tmp_epctrl |= ((unsigned int)(ep_type) + << EPCTRL_RX_EP_TYPE_SHIFT); + } + + xusbps_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]); +} + +static void +dr_ep_change_stall(unsigned char ep_num, unsigned char dir, int value) +{ + u32 tmp_epctrl = 0; + + tmp_epctrl = xusbps_readl(&dr_regs->endptctrl[ep_num]); + + if (value) { + /* set the stall bit */ + if (dir) + tmp_epctrl |= EPCTRL_TX_EP_STALL; + else + tmp_epctrl |= EPCTRL_RX_EP_STALL; + } else { + /* clear the stall bit and reset data toggle */ + if (dir) { + tmp_epctrl &= ~EPCTRL_TX_EP_STALL; + tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; + } else { + tmp_epctrl &= ~EPCTRL_RX_EP_STALL; + tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; + } + } + xusbps_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]); +} + +/* Get stall status of a specific ep + Return: 0: not stalled; 1:stalled */ +static int dr_ep_get_stall(unsigned char ep_num, unsigned char dir) +{ + u32 epctrl; + + epctrl = xusbps_readl(&dr_regs->endptctrl[ep_num]); + if (dir) + return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0; + else + return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0; +} + +/******************************************************************** + Internal Structure Build up functions +********************************************************************/ + +/*------------------------------------------------------------------ +* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH + * @zlt: Zero Length Termination Select (1: disable; 0: enable) + * @mult: Mult field + ------------------------------------------------------------------*/ +static void struct_ep_qh_setup(struct xusbps_udc *udc, unsigned char ep_num, + unsigned char dir, unsigned char ep_type, + unsigned int max_pkt_len, + unsigned int zlt, unsigned char mult) +{ + struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir]; + unsigned int tmp = 0; + + /* set the Endpoint Capabilites in QH */ + switch (ep_type) { + case USB_ENDPOINT_XFER_CONTROL: + /* Interrupt On Setup (IOS). for control ep */ + tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) + | EP_QUEUE_HEAD_IOS; + break; + case USB_ENDPOINT_XFER_ISOC: + tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) + | (mult << EP_QUEUE_HEAD_MULT_POS); + break; + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS; + break; + default: + VDBG("error ep type is %d", ep_type); + return; + } + if (zlt) + tmp |= EP_QUEUE_HEAD_ZLT_SEL; + + p_QH->max_pkt_length = cpu_to_le32(tmp); + p_QH->next_dtd_ptr = 1; + p_QH->size_ioc_int_sts = 0; +} + +/* Setup qh structure and ep register for ep0. */ +static void ep0_setup(struct xusbps_udc *udc) +{ + /* the intialization of an ep includes: fields in QH, Regs, + * xusbps_ep struct */ + struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, + USB_MAX_CTRL_PAYLOAD, 1, 0); + struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, + USB_MAX_CTRL_PAYLOAD, 1, 0); + dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL); + dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL); + + return; + +} + +/*********************************************************************** + Endpoint Management Functions +***********************************************************************/ + +/*------------------------------------------------------------------------- + * when configurations are set, or when interface settings change + * for example the do_set_interface() in gadget layer, + * the driver will enable or disable the relevant endpoints + * ep0 doesn't use this routine. It is always enabled. +-------------------------------------------------------------------------*/ +static int xusbps_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct xusbps_udc *udc = NULL; + struct xusbps_ep *ep = NULL; + unsigned short max = 0; + unsigned char mult = 0, zlt; + int retval = -EINVAL; + unsigned long flags = 0; + + ep = container_of(_ep, struct xusbps_ep, ep); + + /* catch various bogus parameters */ + if (!_ep || !desc + || (desc->bDescriptorType != USB_DT_ENDPOINT)) + return -EINVAL; + + udc = ep->udc; + + if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) + return -ESHUTDOWN; + + max = usb_endpoint_maxp(desc); + + /* Disable automatic zlp generation. Driver is reponsible to indicate + * explicitly through req->req.zero. This is needed to enable multi-td + * request. */ + zlt = 1; + + /* Assume the max packet size from gadget is always correct */ + switch (desc->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_CONTROL: + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + /* mult = 0. Execute N Transactions as demonstrated by + * the USB variable length packet protocol where N is + * computed using the Maximum Packet Length (dQH) and + * the Total Bytes field (dTD) */ + mult = 0; + break; + case USB_ENDPOINT_XFER_ISOC: + /* Calculate transactions needed for high bandwidth iso */ + mult = (unsigned char)(1 + ((max >> 11) & 0x03)); + max = max & 0x7ff; /* bit 0~10 */ + /* 3 transactions at most */ + if (mult > 3) + goto en_done; + break; + default: + goto en_done; + } + + spin_lock_irqsave(&udc->lock, flags); + ep->ep.maxpacket = max; + ep->ep.desc = desc; + ep->stopped = 0; + ep->wedge = 0; + + /* Controller related setup */ + /* Init EPx Queue Head (Ep Capabilites field in QH + * according to max, zlt, mult) */ + struct_ep_qh_setup(udc, (unsigned char) ep_index(ep), + (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN) + ? USB_SEND : USB_RECV), + (unsigned char) (desc->bmAttributes + & USB_ENDPOINT_XFERTYPE_MASK), + max, zlt, mult); + + /* Init endpoint ctrl register */ + dr_ep_setup((unsigned char) ep_index(ep), + (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN) + ? USB_SEND : USB_RECV), + (unsigned char) (desc->bmAttributes + & USB_ENDPOINT_XFERTYPE_MASK)); + + spin_unlock_irqrestore(&udc->lock, flags); + retval = 0; + + VDBG("enabled %s (ep%d%s) maxpacket %d", ep->ep.name, + ep->ep.desc->bEndpointAddress & 0x0f, + (desc->bEndpointAddress & USB_DIR_IN) + ? "in" : "out", max); +en_done: + return retval; +} + +/*--------------------------------------------------------------------- + * @ep : the ep being unconfigured. May not be ep0 + * Any pending and uncomplete req will complete with status (-ESHUTDOWN) +*---------------------------------------------------------------------*/ +static int xusbps_ep_disable(struct usb_ep *_ep) +{ + struct xusbps_udc *udc = NULL; + struct xusbps_ep *ep = NULL; + unsigned long flags = 0; + u32 epctrl; + int ep_num; + + ep = container_of(_ep, struct xusbps_ep, ep); + if (!_ep || !ep->ep.desc) { + VDBG("%s not enabled", _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + /* disable ep on controller */ + ep_num = ep_index(ep); + epctrl = xusbps_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl &= ~EPCTRL_TX_ENABLE; + else + epctrl &= ~EPCTRL_RX_ENABLE; + xusbps_writel(epctrl, &dr_regs->endptctrl[ep_num]); + + udc = (struct xusbps_udc *)ep->udc; + spin_lock_irqsave(&udc->lock, flags); + + /* nuke all pending requests (does flush) */ + nuke(ep, -ESHUTDOWN); + + ep->ep.desc = NULL; + ep->stopped = 1; + spin_unlock_irqrestore(&udc->lock, flags); + + VDBG("disabled %s OK", _ep->name); + return 0; +} + +/*--------------------------------------------------------------------- + * allocate a request object used by this endpoint + * the main operation is to insert the req->queue to the eq->queue + * Returns the request, or null if one could not be allocated +*---------------------------------------------------------------------*/ +static struct usb_request * +xusbps_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct xusbps_req *req = NULL; + + req = kzalloc(sizeof *req, gfp_flags); + if (!req) + return NULL; + + req->req.dma = DMA_ADDR_INVALID; + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void xusbps_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct xusbps_req *req = NULL; + + req = container_of(_req, struct xusbps_req, req); + + if (_req) + kfree(req); +} + +/*-------------------------------------------------------------------------*/ +static void xusbps_queue_td(struct xusbps_ep *ep, struct xusbps_req *req) +{ + int i = ep_index(ep) * 2 + ep_is_in(ep); + u32 temp, bitmask, tmp_stat; + struct ep_queue_head *dQH = &ep->udc->ep_qh[i]; + + /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr); + VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */ + + bitmask = ep_is_in(ep) + ? (1 << (ep_index(ep) + 16)) + : (1 << (ep_index(ep))); + + /* check if the pipe is empty */ + if (!(list_empty(&ep->queue))) { + /* Add td to the end */ + struct xusbps_req *lastreq; + lastreq = list_entry(ep->queue.prev, struct xusbps_req, queue); + lastreq->tail->next_td_ptr = + cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK); + wmb(); + /* Read prime bit, if 1 goto done */ + if (xusbps_readl(&dr_regs->endpointprime) & bitmask) + goto out; + + do { + /* Set ATDTW bit in USBCMD */ + temp = xusbps_readl(&dr_regs->usbcmd); + xusbps_writel(temp | USB_CMD_ATDTW, &dr_regs->usbcmd); + + /* Read correct status bit */ + tmp_stat = xusbps_readl(&dr_regs->endptstatus) & + bitmask; + +#ifdef CONFIG_XUSBPS_ERRATA_DT654401 + /* Workaround for USB errata DT# 654401 */ + temp = xusbps_readl(&dr_regs->usbcmd); + if (temp & USB_CMD_ATDTW) { + udelay(5); + if (xusbps_readl(&dr_regs->usbcmd) & USB_CMD_ATDTW) + break; + } + } while (1); +#else + } while (!(xusbps_readl(&dr_regs->usbcmd) & USB_CMD_ATDTW)); +#endif + + /* Write ATDTW bit to 0 */ + temp = xusbps_readl(&dr_regs->usbcmd); + xusbps_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd); + + if (tmp_stat) + goto out; + } + + /* Write dQH next pointer and terminate bit to 0 */ + temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; + dQH->next_dtd_ptr = cpu_to_le32(temp); + + /* Clear active and halt bit */ + temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE + | EP_QUEUE_HEAD_STATUS_HALT)); + dQH->size_ioc_int_sts &= temp; + + /* Ensure that updates to the QH will occure before priming. */ + wmb(); + + /* Prime endpoint by writing 1 to ENDPTPRIME */ + temp = ep_is_in(ep) + ? (1 << (ep_index(ep) + 16)) + : (1 << (ep_index(ep))); + xusbps_writel(temp, &dr_regs->endpointprime); +out: + return; +} + +/* Fill in the dTD structure + * @req: request that the transfer belongs to + * @length: return actually data length of the dTD + * @dma: return dma address of the dTD + * @is_last: return flag if it is the last dTD of the request + * return: pointer to the built dTD */ +static struct ep_td_struct *xusbps_build_dtd(struct xusbps_req *req, unsigned + *length, dma_addr_t *dma, int *is_last) +{ + u32 swap_temp; + struct ep_td_struct *dtd; + + /* how big will this transfer be? */ + *length = min(req->req.length - req->req.actual, + (unsigned)EP_MAX_LENGTH_TRANSFER); + + dtd = dma_pool_alloc(udc_controller->td_pool, GFP_ATOMIC, dma); + if (dtd == NULL) + return dtd; + + dtd->td_dma = *dma; + /* Clear reserved field */ + swap_temp = cpu_to_le32(dtd->size_ioc_sts); + swap_temp &= ~DTD_RESERVED_FIELDS; + dtd->size_ioc_sts = cpu_to_le32(swap_temp); + + /* Init all of buffer page pointers */ + swap_temp = (u32) (req->req.dma + req->req.actual); + dtd->buff_ptr0 = cpu_to_le32(swap_temp); + dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000); + dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000); + dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000); + dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000); + + req->req.actual += *length; + + /* zlp is needed if req->req.zero is set */ + if (req->req.zero) { + if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) + *is_last = 1; + else + *is_last = 0; + } else if (req->req.length == req->req.actual) + *is_last = 1; + else + *is_last = 0; + + if ((*is_last) == 0) + VDBG("multi-dtd request!"); + /* Fill in the transfer size; set active bit */ + swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE); + + /* Enable interrupt for the last dtd of a request */ + if (*is_last && !req->req.no_interrupt) + swap_temp |= DTD_IOC; + + dtd->size_ioc_sts = cpu_to_le32(swap_temp); + + mb(); + + VDBG("length = %d address= 0x%x", *length, (int)*dma); + + return dtd; +} + +/* Generate dtd chain for a request */ +static int xusbps_req_to_dtd(struct xusbps_req *req) +{ + unsigned count; + int is_last; + int is_first = 1; + struct ep_td_struct *last_dtd = NULL, *dtd; + dma_addr_t dma; + + do { + dtd = xusbps_build_dtd(req, &count, &dma, &is_last); + if (dtd == NULL) + return -ENOMEM; + + if (is_first) { + is_first = 0; + req->head = dtd; + } else { + last_dtd->next_td_ptr = cpu_to_le32(dma); + last_dtd->next_td_virt = dtd; + } + last_dtd = dtd; + + req->dtd_count++; + } while (!is_last); + + dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE); + + mb(); + req->tail = dtd; + + return 0; +} + +/* queues (submits) an I/O request to an endpoint */ +static int +xusbps_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct xusbps_ep *ep = container_of(_ep, struct xusbps_ep, ep); + struct xusbps_req *req = container_of(_req, struct xusbps_req, req); + struct xusbps_udc *udc; + unsigned long flags; + + /* catch various bogus parameters */ + if (!_req || !req->req.complete || !req->req.buf + || !list_empty(&req->queue)) { + VDBG("%s, bad params", __func__); + return -EINVAL; + } + if (unlikely(!_ep || !ep->ep.desc)) { + VDBG("%s, bad ep", __func__); + return -EINVAL; + } + if (usb_endpoint_xfer_isoc(ep->ep.desc)) { + if (req->req.length > ep->ep.maxpacket) + return -EMSGSIZE; + } + + udc = ep->udc; + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + req->ep = ep; + + /* map virtual address to hardware */ + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, + req->req.buf, + req->req.length, ep_is_in(ep) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + ep_is_in(ep) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->mapped = 0; + } + + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->dtd_count = 0; + + spin_lock_irqsave(&udc->lock, flags); + + /* build dtds and push them to device queue */ + if (!xusbps_req_to_dtd(req)) { + xusbps_queue_td(ep, req); + } else { + spin_unlock_irqrestore(&udc->lock, flags); + return -ENOMEM; + } + + /* Update ep0 state */ + if ((ep_index(ep) == 0)) + udc->ep0_state = DATA_STATE_XMIT; + + /* irq handler advances the queue */ + if (req != NULL) + list_add_tail(&req->queue, &ep->queue); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/* dequeues (cancels, unlinks) an I/O request from an endpoint */ +static int xusbps_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct xusbps_ep *ep = container_of(_ep, struct xusbps_ep, ep); + struct xusbps_req *req; + unsigned long flags; + int ep_num, stopped, ret = 0; + u32 epctrl; + + if (!_ep || !_req) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + stopped = ep->stopped; + + /* Stop the ep before we deal with the queue */ + ep->stopped = 1; + ep_num = ep_index(ep); + epctrl = xusbps_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl &= ~EPCTRL_TX_ENABLE; + else + epctrl &= ~EPCTRL_RX_ENABLE; + xusbps_writel(epctrl, &dr_regs->endptctrl[ep_num]); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + ret = -EINVAL; + goto out; + } + + /* The request is in progress, or completed but not dequeued */ + if (ep->queue.next == &req->queue) { + _req->status = -ECONNRESET; + xusbps_ep_fifo_flush(_ep); /* flush current transfer */ + + /* The request isn't the last request in this ep queue */ + if (req->queue.next != &ep->queue) { + struct ep_queue_head *qh; + struct xusbps_req *next_req; + + qh = ep->qh; + next_req = list_entry(req->queue.next, struct + xusbps_req, queue); + + /* Point the QH to the first TD of next request */ + xusbps_writel((u32) next_req->head, + (void __force __iomem *)&qh->curr_dtd_ptr); + } + + /* The request hasn't been processed, patch up the TD chain */ + } else { + struct xusbps_req *prev_req; + + prev_req = list_entry(req->queue.prev, struct xusbps_req, + queue); + xusbps_writel( + xusbps_readl((void __force __iomem *)&req->tail->next_td_ptr), + (void __force __iomem *)&prev_req->tail->next_td_ptr); + + } + + done(ep, req, -ECONNRESET); + + /* Enable EP */ +out: epctrl = xusbps_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl |= EPCTRL_TX_ENABLE; + else + epctrl |= EPCTRL_RX_ENABLE; + xusbps_writel(epctrl, &dr_regs->endptctrl[ep_num]); + ep->stopped = stopped; + + spin_unlock_irqrestore(&ep->udc->lock, flags); + return ret; +} + +/*-------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------- + * modify the endpoint halt feature + * @ep: the non-isochronous endpoint being stalled + * @value: 1--set halt 0--clear halt + * Returns zero, or a negative error code. +*----------------------------------------------------------------*/ +static int xusbps_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct xusbps_ep *ep = NULL; + unsigned long flags = 0; + int status = -EOPNOTSUPP; /* operation not supported */ + unsigned char ep_dir = 0, ep_num = 0; + struct xusbps_udc *udc = NULL; + + ep = container_of(_ep, struct xusbps_ep, ep); + udc = ep->udc; + if (!_ep || !ep->ep.desc) { + status = -EINVAL; + goto out; + } + + if (usb_endpoint_xfer_isoc(ep->ep.desc)) { + status = -EOPNOTSUPP; + goto out; + } + + /* Attempt to halt IN ep will fail if any transfer requests + * are still queue */ + if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { + status = -EAGAIN; + goto out; + } + + status = 0; + ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV; + ep_num = (unsigned char)(ep_index(ep)); + spin_lock_irqsave(&ep->udc->lock, flags); + if (!value) + ep->wedge = 0; + dr_ep_change_stall(ep_num, ep_dir, value); + spin_unlock_irqrestore(&ep->udc->lock, flags); + + if (ep_index(ep) == 0) { + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; + } +out: + VDBG(" %s %s halt stat %d", ep->ep.name, + value ? "set" : "clear", status); + + return status; +} + +static int xusbps_ep_set_wedge(struct usb_ep *_ep) +{ + struct xusbps_ep *ep = NULL; + unsigned long flags = 0; + + ep = container_of(_ep, struct xusbps_ep, ep); + + if (!ep || !ep->ep.desc) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + ep->wedge = 1; + spin_unlock_irqrestore(&ep->udc->lock, flags); + + return usb_ep_set_halt(_ep); +} + +static void xusbps_ep_fifo_flush(struct usb_ep *_ep) +{ + struct xusbps_ep *ep; + int ep_num, ep_dir; + u32 bits; + unsigned long timeout; +#define XUSBPS_UDC_FLUSH_TIMEOUT 1000 + + if (!_ep) { + return; + } else { + ep = container_of(_ep, struct xusbps_ep, ep); + if (!ep->ep.desc) + return; + } + ep_num = ep_index(ep); + ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV; + + if (ep_num == 0) + bits = (1 << 16) | 1; + else if (ep_dir == USB_SEND) + bits = 1 << (16 + ep_num); + else + bits = 1 << ep_num; + + timeout = jiffies + XUSBPS_UDC_FLUSH_TIMEOUT; + do { + xusbps_writel(bits, &dr_regs->endptflush); + + /* Wait until flush complete */ + while (xusbps_readl(&dr_regs->endptflush)) { + if (time_after(jiffies, timeout)) { + ERR("ep flush timeout\n"); + return; + } + cpu_relax(); + } + /* See if we need to flush again */ + } while (xusbps_readl(&dr_regs->endptstatus) & bits); +} + +static struct usb_ep_ops xusbps_ep_ops = { + .enable = xusbps_ep_enable, + .disable = xusbps_ep_disable, + + .alloc_request = xusbps_alloc_request, + .free_request = xusbps_free_request, + + .queue = xusbps_ep_queue, + .dequeue = xusbps_ep_dequeue, + + .set_halt = xusbps_ep_set_halt, + .set_wedge = xusbps_ep_set_wedge, + .fifo_flush = xusbps_ep_fifo_flush, /* flush fifo */ +}; + +/*------------------------------------------------------------------------- + Gadget Driver Layer Operations +-------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------- + * Get the current frame number (from DR frame_index Reg ) + *----------------------------------------------------------------------*/ +static int xusbps_get_frame(struct usb_gadget *gadget) +{ + return (int)(xusbps_readl(&dr_regs->frindex) & USB_FRINDEX_MASKS); +} + +/*----------------------------------------------------------------------- + * Tries to wake up the host connected to this gadget + -----------------------------------------------------------------------*/ +static int xusbps_wakeup(struct usb_gadget *gadget) +{ + struct xusbps_udc *udc = container_of(gadget, struct xusbps_udc, + gadget); + u32 portsc; + + /* Remote wakeup feature not enabled by host */ + if (!udc->remote_wakeup) + return -ENOTSUPP; + + portsc = xusbps_readl(&dr_regs->portsc1); + /* not suspended? */ + if (!(portsc & PORTSCX_PORT_SUSPEND)) + return 0; + /* trigger force resume */ + portsc |= PORTSCX_PORT_FORCE_RESUME; + xusbps_writel(portsc, &dr_regs->portsc1); + return 0; +} + +static int can_pullup(struct xusbps_udc *udc) +{ + return udc->driver && udc->softconnect && udc->vbus_active; +} + +/* Notify controller that VBUS is powered, Called by whatever + detects VBUS sessions */ +static int xusbps_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct xusbps_udc *udc; + unsigned long flags; + + udc = container_of(gadget, struct xusbps_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + VDBG("VBUS %s", is_active ? "on" : "off"); + udc->vbus_active = (is_active != 0); + if (can_pullup(udc)) + xusbps_writel((xusbps_readl(&dr_regs->usbcmd) | + USB_CMD_RUN_STOP), &dr_regs->usbcmd); + else + xusbps_writel((xusbps_readl(&dr_regs->usbcmd) & + ~USB_CMD_RUN_STOP), &dr_regs->usbcmd); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +/* constrain controller's VBUS power usage + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +static int xusbps_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + struct xusbps_udc *udc; + + udc = container_of(gadget, struct xusbps_udc, gadget); + if (udc->transceiver) + return usb_phy_set_power(udc->transceiver, mA); + return -ENOTSUPP; +} + +/* Change Data+ pullup status + * this func is used by usb_gadget_connect/disconnet + */ +static int xusbps_pullup(struct usb_gadget *gadget, int is_on) +{ + struct xusbps_udc *udc; + + udc = container_of(gadget, struct xusbps_udc, gadget); + udc->softconnect = (is_on != 0); + if (can_pullup(udc)) + xusbps_writel((xusbps_readl(&dr_regs->usbcmd) | + USB_CMD_RUN_STOP), &dr_regs->usbcmd); + else + xusbps_writel((xusbps_readl(&dr_regs->usbcmd) & + ~USB_CMD_RUN_STOP), &dr_regs->usbcmd); + + return 0; +} + +static void udc_reset_ep_queue(struct xusbps_udc *udc, u8 pipe) +{ + struct xusbps_ep *ep = get_ep_by_pipe(udc, pipe); + + if (ep->name) + nuke(ep, -ESHUTDOWN); +} + +/* Clear up all ep queues */ +static int reset_queues(struct xusbps_udc *udc) +{ + u8 pipe; + + for (pipe = 0; pipe < udc->max_pipes; pipe++) + udc_reset_ep_queue(udc, pipe); + + /* report disconnect; the driver is already quiesced */ + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + + return 0; +} + +#ifdef CONFIG_USB_ZYNQ_PHY +/*---------------------------------------------------------------- + * OTG Related changes + *--------------------------------------------------------------*/ +static int xusbps_udc_start_peripheral(struct usb_phy *otg) +{ + struct usb_gadget *gadget = otg->otg->gadget; + struct xusbps_udc *udc = container_of(gadget, struct xusbps_udc, + gadget); + unsigned long flags = 0; + unsigned int tmp; + + spin_lock_irqsave(&udc->lock, flags); + + if (!otg->otg->default_a) { + dr_controller_setup(udc); + reset_queues(udc); + } else { + /* A-device HABA resets the controller */ + tmp = udc->ep_qh_dma; + tmp &= USB_EP_LIST_ADDRESS_MASK; + xusbps_writel(tmp, &dr_regs->endpointlistaddr); + } + ep0_setup(udc); + dr_controller_run(udc); + + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int xusbps_udc_stop_peripheral(struct usb_phy *otg) +{ + struct usb_gadget *gadget = otg->otg->gadget; + struct xusbps_udc *udc = container_of(gadget, struct xusbps_udc, + gadget); + + dr_controller_stop(udc); + + /* refer to USB OTG 6.6.2.3 b_hnp_en is cleared */ + if (!udc->xotg->otg.otg->default_a) + udc->xotg->hsm.b_hnp_enable = 0; + + return 0; +} +#endif + +/*----------------------------------------------------------------* + * Hook to gadget drivers + * Called by initialization code of gadget drivers +*----------------------------------------------------------------*/ +static int xusbps_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) +{ + int retval = 0; + unsigned long flags = 0; + + /* lock is needed but whether should use this lock or another */ + spin_lock_irqsave(&udc_controller->lock, flags); + + driver->driver.bus = NULL; + /* hook up the driver */ + udc_controller->driver = driver; + udc_controller->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc_controller->lock, flags); + +#ifdef CONFIG_USB_ZYNQ_PHY + if (gadget_is_otg(&udc_controller->gadget)) { + retval = otg_set_peripheral(udc_controller->transceiver->otg, + &udc_controller->gadget); + if (retval < 0) { + VDBG("can't bind to otg transceiver\n"); + driver->unbind(&udc_controller->gadget); + udc_controller->gadget.dev.driver = NULL; + udc_controller->driver = NULL; + return retval; + } + /* Exporting start and stop routines */ + udc_controller->xotg->start_peripheral = + xusbps_udc_start_peripheral; + udc_controller->xotg->stop_peripheral = + xusbps_udc_stop_peripheral; + + if (!udc_controller->transceiver->otg->default_a && + udc_controller->stopped && + udc_controller->xotg->hsm.b_sess_vld) { + dr_controller_setup(udc_controller); + ep0_setup(udc_controller); + /* Enable DR IRQ reg and Set usbcmd reg Run bit */ + dr_controller_run(udc_controller); + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; + xusbps_update_transceiver(); + } + } else { + /* Enable DR IRQ reg and Set usbcmd reg Run bit */ + dr_controller_run(udc_controller); + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; + } +#else + /* Enable DR IRQ reg and Set usbcmd reg Run bit */ + dr_controller_run(udc_controller); + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; +#endif + + pr_info("%s: bind to driver %s\n", + udc_controller->gadget.name, driver->driver.name); + if (retval) + pr_warn("gadget driver register failed %d\n", retval); + + return retval; +} + +/* Disconnect from gadget driver */ +static int xusbps_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) +{ + struct xusbps_ep *loop_ep; + unsigned long flags; + + if (udc_controller->transceiver) + otg_set_peripheral(udc_controller->transceiver->otg, NULL); + + /* stop DR, disable intr */ + dr_controller_stop(udc_controller); + + /* in fact, no needed */ + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; + + /* stand operation */ + spin_lock_irqsave(&udc_controller->lock, flags); + udc_controller->gadget.speed = USB_SPEED_UNKNOWN; + nuke(&udc_controller->eps[0], -ESHUTDOWN); + list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list, + ep.ep_list) + nuke(loop_ep, -ESHUTDOWN); + spin_unlock_irqrestore(&udc_controller->lock, flags); + +#ifdef CONFIG_USB_ZYNQ_PHY + if (gadget_is_otg(&udc_controller->gadget)) { + udc_controller->xotg->start_peripheral = NULL; + udc_controller->xotg->stop_peripheral = NULL; + } +#endif + udc_controller->gadget.dev.driver = NULL; + udc_controller->driver = NULL; + + return 0; +} + +/* defined in gadget.h */ +static struct usb_gadget_ops xusbps_gadget_ops = { + .get_frame = xusbps_get_frame, + .wakeup = xusbps_wakeup, +/* .set_selfpowered = xusbps_set_selfpowered, */ /* Always selfpowered */ + .vbus_session = xusbps_vbus_session, + .vbus_draw = xusbps_vbus_draw, + .pullup = xusbps_pullup, + .udc_start = xusbps_udc_start, + .udc_stop = xusbps_udc_stop, +}; + +/* Set protocol stall on ep0, protocol stall will automatically be cleared + on new transaction */ +static void ep0stall(struct xusbps_udc *udc) +{ + u32 tmp; + + /* must set tx and rx to stall at the same time */ + tmp = xusbps_readl(&dr_regs->endptctrl[0]); + tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL; + xusbps_writel(tmp, &dr_regs->endptctrl[0]); + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; +} + +/* Prime a status phase for ep0 */ +static int ep0_prime_status(struct xusbps_udc *udc, int direction) +{ + struct xusbps_req *req = udc->status_req; + struct xusbps_ep *ep; + + if (direction == EP_DIR_IN) + udc->ep0_dir = USB_DIR_IN; + else + udc->ep0_dir = USB_DIR_OUT; + + ep = &udc->eps[0]; + udc->ep0_state = WAIT_FOR_OUT_STATUS; + + req->ep = ep; + req->req.length = 0; + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->req.complete = NULL; + req->dtd_count = 0; + req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, + req->req.buf, req->req.length, + ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + + if (xusbps_req_to_dtd(req) == 0) + xusbps_queue_td(ep, req); + else + return -ENOMEM; + + list_add_tail(&req->queue, &ep->queue); + + return 0; +} + +/* + * ch9 Set address + */ +static void ch9setaddress(struct xusbps_udc *udc, u16 value, u16 index, u16 + length) +{ + /* Save the new address to device struct */ + udc->device_address = (u8) value; + /* Update usb state */ + udc->usb_state = USB_STATE_ADDRESS; + /* Status phase */ + if (ep0_prime_status(udc, EP_DIR_IN)) + ep0stall(udc); +} + +/* + * ch9 Get status + */ +static void ch9getstatus(struct xusbps_udc *udc, u8 request_type, u16 value, + u16 index, u16 length) +{ + u16 tmp = 0; /* Status, cpu endian */ + struct xusbps_req *req; + struct xusbps_ep *ep; + + ep = &udc->eps[0]; + + if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { + /* Get device status */ + tmp = 1 << USB_DEVICE_SELF_POWERED; + tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; + } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { + /* Get interface status */ + /* We don't have interface information in udc driver */ + tmp = 0; + } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { + /* Get endpoint status */ + struct xusbps_ep *target_ep; + + target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index)); + + /* stall if endpoint doesn't exist */ + if (!target_ep->ep.desc) + goto stall; + tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep)) + << USB_ENDPOINT_HALT; + } + + udc->ep0_dir = USB_DIR_IN; + /* Borrow the per device status_req */ + req = udc->status_req; + /* Fill in the reqest structure */ + *((u16 *) req->req.buf) = cpu_to_le16(tmp); + req->ep = ep; + req->req.length = 2; + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->req.complete = NULL; + req->dtd_count = 0; + req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, + req->req.buf, req->req.length, + ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + + /* prime the data phase */ + if ((xusbps_req_to_dtd(req) == 0)) + xusbps_queue_td(ep, req); + else /* no mem */ + goto stall; + + list_add_tail(&req->queue, &ep->queue); + udc->ep0_state = DATA_STATE_XMIT; + return; +stall: + ep0stall(udc); +} + +static void setup_received_irq(struct xusbps_udc *udc, + struct usb_ctrlrequest *setup) +{ + u16 wValue = le16_to_cpu(setup->wValue); + u16 wIndex = le16_to_cpu(setup->wIndex); + u16 wLength = le16_to_cpu(setup->wLength); + u16 testsel = 0; + + udc_reset_ep_queue(udc, 0); + + /* We process some stardard setup requests here */ + switch (setup->bRequest) { + case USB_REQ_GET_STATUS: + /* Data+Status phase from udc */ + if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) + != (USB_DIR_IN | USB_TYPE_STANDARD)) + break; + ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength); + return; + + case USB_REQ_SET_ADDRESS: + /* Status phase from udc */ + if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD + | USB_RECIP_DEVICE)) + break; + ch9setaddress(udc, wValue, wIndex, wLength); + return; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + /* Status phase from udc */ + { + int rc = -EOPNOTSUPP; + + if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) + == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { + int pipe = get_pipe_by_windex(wIndex); + struct xusbps_ep *ep; + + if (wValue != 0 || wLength != 0 || pipe > udc->max_ep) + break; + ep = get_ep_by_pipe(udc, pipe); + + spin_unlock(&udc->lock); + if (setup->bRequest == USB_REQ_SET_FEATURE) { + rc = xusbps_ep_set_halt(&ep->ep, 1); + } else { + if (!ep->wedge) + rc = xusbps_ep_set_halt(&ep->ep, 0); + else + rc = 0; + } + spin_lock(&udc->lock); + + } else if ((setup->bRequestType & (USB_RECIP_MASK + | USB_TYPE_MASK)) == (USB_RECIP_DEVICE + | USB_TYPE_STANDARD)) { + /* TEST MODE feature */ + if (wValue == USB_DEVICE_TEST_MODE) { + testsel = (wIndex >> 8) & 0xff; + rc = 0; + goto status_phase; + } + + /* Note: The driver has not include OTG support yet. + * This will be set when OTG support is added */ + if (!gadget_is_otg(&udc->gadget)) + break; + else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) { + udc->gadget.b_hnp_enable = 1; +#ifdef CONFIG_USB_ZYNQ_PHY + if (!udc->xotg->otg.otg->default_a) + udc->xotg->hsm.b_hnp_enable = 1; +#endif + } else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT) + udc->gadget.a_hnp_support = 1; + else if (setup->bRequest == + USB_DEVICE_A_ALT_HNP_SUPPORT) + udc->gadget.a_alt_hnp_support = 1; + else + break; + rc = 0; + } else + break; + +status_phase: + if (rc == 0) { + if (ep0_prime_status(udc, EP_DIR_IN)) { + ep0stall(udc); + } else { + if (testsel) { + u32 tmp; + /* Wait for status phase to complete */ + mdelay(1); + tmp = xusbps_readl(&dr_regs->portsc1); + tmp |= (testsel << 16); + xusbps_writel(tmp, &dr_regs->portsc1); + } + } + } + return; + } + + default: + break; + } + + /* Requests handled by gadget */ + if (wLength) { + /* Data phase from gadget, status phase from udc */ + udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) + ? USB_DIR_IN : USB_DIR_OUT; + spin_unlock(&udc->lock); + if (udc->driver->setup(&udc->gadget, + &udc->local_setup_buff) < 0) + ep0stall(udc); + spin_lock(&udc->lock); + udc->ep0_state = (setup->bRequestType & USB_DIR_IN) + ? DATA_STATE_XMIT : DATA_STATE_RECV; + } else { + /* No data phase, IN status from gadget */ + udc->ep0_dir = USB_DIR_IN; + spin_unlock(&udc->lock); + if (udc->driver->setup(&udc->gadget, + &udc->local_setup_buff) < 0) + ep0stall(udc); + spin_lock(&udc->lock); + udc->ep0_state = WAIT_FOR_OUT_STATUS; + } +} + +/* Process request for Data or Status phase of ep0 + * prime status phase if needed */ +static void ep0_req_complete(struct xusbps_udc *udc, struct xusbps_ep *ep0, + struct xusbps_req *req) +{ + if (udc->usb_state == USB_STATE_ADDRESS) { + /* Set the new address */ + u32 new_address = (u32) udc->device_address; + xusbps_writel(new_address << USB_DEVICE_ADDRESS_BIT_POS, + &dr_regs->deviceaddr); + } + + done(ep0, req, 0); + + switch (udc->ep0_state) { + case DATA_STATE_XMIT: + /* receive status phase */ + if (ep0_prime_status(udc, EP_DIR_OUT)) + ep0stall(udc); + break; + case DATA_STATE_RECV: + /* send status phase */ + if (ep0_prime_status(udc, EP_DIR_IN)) + ep0stall(udc); + break; + case WAIT_FOR_OUT_STATUS: + udc->ep0_state = WAIT_FOR_SETUP; + break; + case WAIT_FOR_SETUP: + ERR("Unexpect ep0 packets\n"); + break; + default: + ep0stall(udc); + break; + } +} + +/* Tripwire mechanism to ensure a setup packet payload is extracted without + * being corrupted by another incoming setup packet */ +static void tripwire_handler(struct xusbps_udc *udc, u8 ep_num, u8 *buffer_ptr) +{ + u32 temp; + struct ep_queue_head *qh; + + qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT]; + + /* Clear bit in ENDPTSETUPSTAT */ + temp = xusbps_readl(&dr_regs->endptsetupstat); + xusbps_writel(temp | (1 << ep_num), &dr_regs->endptsetupstat); + + /* while a hazard exists when setup package arrives */ + do { + /* Set Setup Tripwire */ + temp = xusbps_readl(&dr_regs->usbcmd); + xusbps_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd); + + /* Copy the setup packet to local buffer */ + memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8); + } while (!(xusbps_readl(&dr_regs->usbcmd) & USB_CMD_SUTW)); + + /* Clear Setup Tripwire */ + temp = xusbps_readl(&dr_regs->usbcmd); + xusbps_writel(temp & ~USB_CMD_SUTW, &dr_regs->usbcmd); +} + +/* process-ep_req(): free the completed Tds for this req */ +static int process_ep_req(struct xusbps_udc *udc, int pipe, + struct xusbps_req *curr_req) +{ + struct ep_td_struct *curr_td; + int td_complete, actual, remaining_length, j, tmp; + int status = 0; + int errors = 0; + struct ep_queue_head *curr_qh = &udc->ep_qh[pipe]; + int direction = pipe % 2; + + curr_td = curr_req->head; + td_complete = 0; + actual = curr_req->req.length; + + for (j = 0; j < curr_req->dtd_count; j++) { + remaining_length = (le32_to_cpu(curr_td->size_ioc_sts) + & DTD_PACKET_SIZE) + >> DTD_LENGTH_BIT_POS; + actual -= remaining_length; + errors = le32_to_cpu(curr_td->size_ioc_sts) & + DTD_ERROR_MASK; + if (errors) { + if (errors & DTD_STATUS_HALTED) { + ERR("dTD error %08x QH=%d\n", errors, pipe); + /* Clear the errors and Halt condition */ + tmp = le32_to_cpu(curr_qh->size_ioc_int_sts); + tmp &= ~errors; + curr_qh->size_ioc_int_sts = cpu_to_le32(tmp); + status = -EPIPE; + /* FIXME: continue with next queued TD? */ + + break; + } + if (errors & DTD_STATUS_DATA_BUFF_ERR) { + VDBG("Transfer overflow"); + status = -EPROTO; + break; + } else if (errors & DTD_STATUS_TRANSACTION_ERR) { + VDBG("ISO error"); + status = -EILSEQ; + break; + } else + ERR("Unknown error has occured (0x%x)!\n", + errors); + + } else if (le32_to_cpu(curr_td->size_ioc_sts) + & DTD_STATUS_ACTIVE) { + VDBG("Request not complete"); + status = REQ_UNCOMPLETE; + return status; + } else if (remaining_length) { + if (direction) { + VDBG("Transmit dTD remaining length not zero"); + status = -EPROTO; + break; + } else { + td_complete++; + break; + } + } else { + td_complete++; + VDBG("dTD transmitted successful"); + } + + if (j != curr_req->dtd_count - 1) + curr_td = (struct ep_td_struct *)curr_td->next_td_virt; + } + + if (status) + return status; + + curr_req->req.actual = actual; + + return 0; +} + +/* Process a DTD completion interrupt */ +static void dtd_complete_irq(struct xusbps_udc *udc) +{ + u32 bit_pos; + int i, ep_num, direction, bit_mask, status; + struct xusbps_ep *curr_ep; + struct xusbps_req *curr_req, *temp_req; + + /* Clear the bits in the register */ + bit_pos = xusbps_readl(&dr_regs->endptcomplete); + xusbps_writel(bit_pos, &dr_regs->endptcomplete); + + if (!bit_pos) + return; + + for (i = 0; i < udc->max_ep; i++) { + ep_num = i >> 1; + direction = i % 2; + + bit_mask = 1 << (ep_num + 16 * direction); + + if (!(bit_pos & bit_mask)) + continue; + + curr_ep = get_ep_by_pipe(udc, i); + + /* If the ep is configured */ + if (curr_ep->name == NULL) { + WARNING("Invalid EP?"); + continue; + } + + /* process the req queue until an uncomplete request */ + list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue, + queue) { + status = process_ep_req(udc, i, curr_req); + + VDBG("status of process_ep_req= %d, ep = %d", + status, ep_num); + if (status == REQ_UNCOMPLETE) + break; + /* Clear the endpoint complete events */ + xusbps_writel(bit_pos, &dr_regs->endptcomplete); + /* write back status to req */ + curr_req->req.status = status; + + if (ep_num == 0) { + ep0_req_complete(udc, curr_ep, curr_req); + break; + } else + done(curr_ep, curr_req, status); + } + } +} + +/* Process a port change interrupt */ +static void port_change_irq(struct xusbps_udc *udc) +{ + u32 speed; + + /* Bus resetting is finished */ + if (!(xusbps_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) { + /* Get the speed */ + speed = (xusbps_readl(&dr_regs->portsc1) + & PORTSCX_PORT_SPEED_MASK); + switch (speed) { + case PORTSCX_PORT_SPEED_HIGH: + udc->gadget.speed = USB_SPEED_HIGH; + break; + case PORTSCX_PORT_SPEED_FULL: + udc->gadget.speed = USB_SPEED_FULL; + break; + case PORTSCX_PORT_SPEED_LOW: + udc->gadget.speed = USB_SPEED_LOW; + break; + default: + udc->gadget.speed = USB_SPEED_UNKNOWN; + break; + } + } + + /* Update USB state */ + if (!udc->resume_state) + udc->usb_state = USB_STATE_DEFAULT; +} + +/* Process suspend interrupt */ +static void suspend_irq(struct xusbps_udc *udc) +{ + udc->resume_state = udc->usb_state; + udc->usb_state = USB_STATE_SUSPENDED; + +#ifdef CONFIG_USB_ZYNQ_PHY + if (gadget_is_otg(&udc->gadget)) { + if (udc->xotg->otg.otg->default_a) { + udc->xotg->hsm.b_bus_suspend = 1; + /* notify transceiver the state changes */ + if (spin_trylock(&udc->xotg->wq_lock)) { + xusbps_update_transceiver(); + spin_unlock(&udc->xotg->wq_lock); + } + } else { + if (!udc->xotg->hsm.a_bus_suspend) { + udc->xotg->hsm.a_bus_suspend = 1; + udc->xotg->hsm.b_bus_req = 1; + /* notify transceiver the state changes */ + if (spin_trylock(&udc->xotg->wq_lock)) { + xusbps_update_transceiver(); + spin_unlock(&udc->xotg->wq_lock); + } + } + } + } +#endif + /* report suspend to the driver, serial.c does not support this */ + if (udc->driver->suspend) + udc->driver->suspend(&udc->gadget); +} + +static void bus_resume(struct xusbps_udc *udc) +{ + udc->usb_state = udc->resume_state; + udc->resume_state = 0; + + /* report resume to the driver, serial.c does not support this */ + if (udc->driver->resume) + udc->driver->resume(&udc->gadget); +} + +/* Process reset interrupt */ +static void reset_irq(struct xusbps_udc *udc) +{ + u32 temp; + unsigned long timeout; + + /* Clear the device address */ + temp = xusbps_readl(&dr_regs->deviceaddr); + xusbps_writel(temp & ~USB_DEVICE_ADDRESS_MASK, &dr_regs->deviceaddr); + + udc->device_address = 0; + + /* Clear usb state */ + udc->resume_state = 0; + udc->ep0_dir = 0; + udc->ep0_state = WAIT_FOR_SETUP; + udc->remote_wakeup = 0; /* default to 0 on reset */ + udc->gadget.b_hnp_enable = 0; + udc->gadget.a_hnp_support = 0; + udc->gadget.a_alt_hnp_support = 0; + + /* Clear all the setup token semaphores */ + temp = xusbps_readl(&dr_regs->endptsetupstat); + xusbps_writel(temp, &dr_regs->endptsetupstat); + + /* Clear all the endpoint complete status bits */ + temp = xusbps_readl(&dr_regs->endptcomplete); + xusbps_writel(temp, &dr_regs->endptcomplete); + + timeout = jiffies + 100; + while (xusbps_readl(&dr_regs->endpointprime)) { + /* Wait until all endptprime bits cleared */ + if (time_after(jiffies, timeout)) { + ERR("Timeout for reset\n"); + break; + } + cpu_relax(); + } + + /* Write 1s to the flush register */ + xusbps_writel(0xffffffff, &dr_regs->endptflush); + + VDBG("Bus reset"); + /* Reset all the queues, include XD, dTD, EP queue + * head and TR Queue */ + reset_queues(udc); + udc->usb_state = USB_STATE_DEFAULT; +} + +/* + * USB device controller interrupt handler + */ +static irqreturn_t xusbps_udc_irq(int irq, void *_udc) +{ + struct xusbps_udc *udc = _udc; + u32 irq_src, otg_sts; + irqreturn_t status = IRQ_NONE; + unsigned long flags; +#ifdef CONFIG_USB_ZYNQ_PHY + unsigned long temp; +#endif + + /* Disable ISR for OTG host mode */ + if (udc->stopped) + return IRQ_NONE; +#ifdef CONFIG_USB_ZYNQ_PHY + if (gadget_is_otg(&udc->gadget)) { + /* A-device */ + if (udc->transceiver->otg->default_a && + (udc->transceiver->state != OTG_STATE_A_PERIPHERAL)) + return IRQ_NONE; + /* B-device */ + if ((udc->transceiver->state == OTG_STATE_B_WAIT_ACON) || + (udc->transceiver->state == OTG_STATE_B_HOST)) + return IRQ_NONE; + } +#endif + spin_lock_irqsave(&udc->lock, flags); + irq_src = xusbps_readl(&dr_regs->usbsts) & + xusbps_readl(&dr_regs->usbintr); + + /* Clear notification bits */ + xusbps_writel(irq_src, &dr_regs->usbsts); + + /* + * Check disconnect event from B session end interrupt. + * This is a SW workaround for USB disconnect detection as mentioned + * in AR# 47538 + */ + if (!gadget_is_otg(&udc->gadget)) { + otg_sts = xusbps_readl(&dr_regs->otgsc); + if (otg_sts & OTGSC_BSEIS) { + xusbps_writel(otg_sts, &dr_regs->otgsc); + reset_queues(udc); + status = IRQ_HANDLED; + } + } + + /* VDBG("irq_src [0x%8x]", irq_src); */ + + /* Need to resume? */ + if (udc->usb_state == USB_STATE_SUSPENDED) + if ((xusbps_readl(&dr_regs->portsc1) & + PORTSCX_PORT_SUSPEND) == 0) + bus_resume(udc); + + /* USB Interrupt */ + if (irq_src & USB_STS_INT) { + VDBG("Packet int"); + /* Setup package, we only support ep0 as control ep */ + if (xusbps_readl(&dr_regs->endptsetupstat) & + EP_SETUP_STATUS_EP0) { + tripwire_handler(udc, 0, + (u8 *) (&udc->local_setup_buff)); + setup_received_irq(udc, &udc->local_setup_buff); + status = IRQ_HANDLED; + } + + /* completion of dtd */ + if (xusbps_readl(&dr_regs->endptcomplete)) { + dtd_complete_irq(udc); + status = IRQ_HANDLED; + } + } + + /* SOF (for ISO transfer) */ + if (irq_src & USB_STS_SOF) + status = IRQ_HANDLED; + + /* Port Change */ + if (irq_src & USB_STS_PORT_CHANGE) { + port_change_irq(udc); + status = IRQ_HANDLED; + } + + /* Reset Received */ + if (irq_src & USB_STS_RESET) { + reset_irq(udc); +#ifdef CONFIG_USB_ZYNQ_PHY + if (gadget_is_otg(&udc->gadget)) { + /* Clear any previous suspend status bit */ + temp = xusbps_readl(&dr_regs->usbsts); + if (temp & USB_INTR_DEVICE_SUSPEND) { + udc->usb_state = USB_STATE_SUSPENDED; + temp |= USB_INTR_DEVICE_SUSPEND; + xusbps_writel(temp, &dr_regs->usbsts); + } + /* Enable suspend interrupt */ + temp = xusbps_readl(&dr_regs->usbintr); + temp |= USB_INTR_DEVICE_SUSPEND; + xusbps_writel(temp, &dr_regs->usbintr); + } +#endif + status = IRQ_HANDLED; + } + + /* Sleep Enable (Suspend) */ + if (irq_src & USB_STS_SUSPEND) { + suspend_irq(udc); + status = IRQ_HANDLED; + } + + if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) + VDBG("Error IRQ %x", irq_src); + + spin_unlock_irqrestore(&udc->lock, flags); + return status; +} + +/*------------------------------------------------------------------------- + PROC File System Support +-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +#include <linux/seq_file.h> + +static const char proc_filename[] = "driver/xusbps_udc"; + +static int xusbps_proc_read(struct seq_file *m, void *v) +{ + unsigned long flags; + int i; + u32 tmp_reg; + struct xusbps_ep *ep = NULL; + struct xusbps_req *req; + struct xusbps_udc *udc = udc_controller; + + spin_lock_irqsave(&udc->lock, flags); + + /* ------basic driver information ---- */ + seq_printf(m, DRIVER_DESC "\n" + "%s version: %s\n" + "Gadget driver: %s\n\n", + driver_name, DRIVER_VERSION, + udc->driver ? udc->driver->driver.name : "(none)"); + + /* ------ DR Registers ----- */ + tmp_reg = xusbps_readl(&dr_regs->usbcmd); + seq_printf(m, "USBCMD reg:\n" + "SetupTW: %d\n" + "Run/Stop: %s\n\n", + (tmp_reg & USB_CMD_SUTW) ? 1 : 0, + (tmp_reg & USB_CMD_RUN_STOP) ? "Run" : "Stop"); + + tmp_reg = xusbps_readl(&dr_regs->usbsts); + seq_printf(m, "USB Status Reg:\n" + "Dr Suspend: %d Reset Received: %d System Error: %s " + "USB Error Interrupt: %s\n\n", + (tmp_reg & USB_STS_SUSPEND) ? 1 : 0, + (tmp_reg & USB_STS_RESET) ? 1 : 0, + (tmp_reg & USB_STS_SYS_ERR) ? "Err" : "Normal", + (tmp_reg & USB_STS_ERR) ? "Err detected" : "No err"); + + tmp_reg = xusbps_readl(&dr_regs->usbintr); + seq_printf(m, "USB Intrrupt Enable Reg:\n" + "Sleep Enable: %d SOF Received Enable: %d " + "Reset Enable: %d\n" + "System Error Enable: %d " + "Port Change Dectected Enable: %d\n" + "USB Error Intr Enable: %d USB Intr Enable: %d\n\n", + (tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0, + (tmp_reg & USB_INTR_SOF_EN) ? 1 : 0, + (tmp_reg & USB_INTR_RESET_EN) ? 1 : 0, + (tmp_reg & USB_INTR_SYS_ERR_EN) ? 1 : 0, + (tmp_reg & USB_INTR_PTC_DETECT_EN) ? 1 : 0, + (tmp_reg & USB_INTR_ERR_INT_EN) ? 1 : 0, + (tmp_reg & USB_INTR_INT_EN) ? 1 : 0); + + tmp_reg = xusbps_readl(&dr_regs->frindex); + seq_printf(m, "USB Frame Index Reg: Frame Number is 0x%x\n\n", + (tmp_reg & USB_FRINDEX_MASKS)); + + tmp_reg = xusbps_readl(&dr_regs->deviceaddr); + seq_printf(m, "USB Device Address Reg: Device Addr is 0x%x\n\n", + (tmp_reg & USB_DEVICE_ADDRESS_MASK)); + + tmp_reg = xusbps_readl(&dr_regs->endpointlistaddr); + seq_printf(m, "USB Endpoint List Address Reg: " + "Device Addr is 0x%x\n\n", + (tmp_reg & USB_EP_LIST_ADDRESS_MASK)); + + tmp_reg = xusbps_readl(&dr_regs->portsc1); + seq_printf(m, "USB Port Status&Control Reg:\n" + "Port Transceiver Type : %s Port Speed: %s\n" + "PHY Low Power Suspend: %s Port Reset: %s " + "Port Suspend Mode: %s\n" + "Over-current Change: %s " + "Port Enable/Disable Change: %s\n" + "Port Enabled/Disabled: %s " + "Current Connect Status: %s\n\n", ({ + char *s; + switch (tmp_reg & PORTSCX_PTS_FSLS) { + case PORTSCX_PTS_UTMI: + s = "UTMI"; break; + case PORTSCX_PTS_ULPI: + s = "ULPI "; break; + case PORTSCX_PTS_FSLS: + s = "FS/LS Serial"; break; + default: + s = "None"; break; + } + s; }), ({ + char *s; + switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) { + case PORTSCX_PORT_SPEED_FULL: + s = "Full Speed"; break; + case PORTSCX_PORT_SPEED_LOW: + s = "Low Speed"; break; + case PORTSCX_PORT_SPEED_HIGH: + s = "High Speed"; break; + default: + s = "Undefined"; break; + } + s; + }), + (tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ? + "Normal PHY mode" : "Low power mode", + (tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" : + "Not in Reset", + (tmp_reg & PORTSCX_PORT_SUSPEND) ? "In " : "Not in", + (tmp_reg & PORTSCX_OVER_CURRENT_CHG) ? "Dected" : "No", + (tmp_reg & PORTSCX_PORT_EN_DIS_CHANGE) ? "Disable" : + "Not change", + (tmp_reg & PORTSCX_PORT_ENABLE) ? "Enable" : "Not correct", + (tmp_reg & PORTSCX_CURRENT_CONNECT_STATUS) ? + "Attached" : "Not-Att"); + + tmp_reg = xusbps_readl(&dr_regs->usbmode); + seq_printf(m, "USB Mode Reg: Controller Mode is: %s\n\n", ({ + char *s; + switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) { + case USB_MODE_CTRL_MODE_IDLE: + s = "Idle"; break; + case USB_MODE_CTRL_MODE_DEVICE: + s = "Device Controller"; break; + case USB_MODE_CTRL_MODE_HOST: + s = "Host Controller"; break; + default: + s = "None"; break; + } + s; + })); + + tmp_reg = xusbps_readl(&dr_regs->endptsetupstat); + seq_printf(m, "Endpoint Setup Status Reg: SETUP on ep 0x%x\n\n", + (tmp_reg & EP_SETUP_STATUS_MASK)); + + for (i = 0; i < udc->max_ep / 2; i++) { + tmp_reg = xusbps_readl(&dr_regs->endptctrl[i]); + seq_printf(m, "EP Ctrl Reg [0x%x]: = [0x%x]\n", + i, tmp_reg); + } + tmp_reg = xusbps_readl(&dr_regs->endpointprime); + seq_printf(m, "EP Prime Reg = [0x%x]\n\n", tmp_reg); + + /* ------xusbps_udc, xusbps_ep, xusbps_request structure information + * ----- */ + ep = &udc->eps[0]; + seq_printf(m, "For %s Maxpkt is 0x%x index is 0x%x\n", + ep->ep.name, ep_maxpacket(ep), ep_index(ep)); + + if (list_empty(&ep->queue)) { + seq_puts(m, "its req queue is empty\n\n"); + } else { + list_for_each_entry(req, &ep->queue, queue) { + seq_printf(m, + "req %p actual 0x%x length 0x%x buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + } + } + /* other gadget->eplist ep */ + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->ep.desc) { + seq_printf(m, "\nFor %s Maxpkt is 0x%x " + "index is 0x%x\n", + ep->ep.name, ep_maxpacket(ep), + ep_index(ep)); + + if (list_empty(&ep->queue)) { + seq_puts(m, "its req queue is empty\n\n"); + } else { + list_for_each_entry(req, &ep->queue, queue) { + seq_printf(m, + "req %p actual 0x%x length " + "0x%x buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + } /* end for each_entry of ep req */ + } /* end for else */ + } /* end for if(ep->queue) */ + } /* end (ep->desc) */ + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/* + * seq_file wrappers for procfile show routines. + */ +static int xusbps_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, xusbps_proc_read, NULL); +} + +static const struct file_operations proc_xusbps_fops = { + .open = xusbps_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#define create_proc_file() proc_create(proc_filename, \ + 0, NULL, &proc_xusbps_fops) + +#define remove_proc_file() remove_proc_entry(proc_filename, NULL) + +#else /* !CONFIG_USB_GADGET_DEBUG_FILES */ + +#define create_proc_file() do {} while (0) +#define remove_proc_file() do {} while (0) + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + +/*-------------------------------------------------------------------------*/ + +/* Release udc structures */ +static void xusbps_udc_release(struct device *dev) +{ + complete(udc_controller->done); + dma_free_coherent(dev->parent, udc_controller->ep_qh_size, + udc_controller->ep_qh, udc_controller->ep_qh_dma); + kfree(udc_controller); +} + +/****************************************************************** + Internal structure setup functions +*******************************************************************/ +/*------------------------------------------------------------------ + * init resource for globle controller + * Return the udc handle on success or NULL on failure + ------------------------------------------------------------------*/ +static int struct_udc_setup(struct xusbps_udc *udc, + struct platform_device *pdev) +{ + struct xusbps_usb2_platform_data *pdata; + size_t size; + + pdata = pdev->dev.platform_data; + udc->phy_mode = pdata->phy_mode; + + udc->eps = kzalloc(sizeof(*udc->eps) * udc->max_ep, GFP_KERNEL); + if (!udc->eps) { + dev_err(&pdev->dev, "malloc xusbps_ep failed\n"); + return -1; + } + + /* initialized QHs, take care of alignment */ + size = udc->max_ep * sizeof(struct ep_queue_head); + if (size < QH_ALIGNMENT) + size = QH_ALIGNMENT; + else if ((size % QH_ALIGNMENT) != 0) { + size += QH_ALIGNMENT + 1; + size &= ~(QH_ALIGNMENT - 1); + } + udc->ep_qh = dma_alloc_coherent(&pdev->dev, size, + &udc->ep_qh_dma, GFP_KERNEL); + if (!udc->ep_qh) { + dev_err(&pdev->dev, "malloc QHs for udc failed\n"); + kfree(udc->eps); + return -1; + } + + udc->ep_qh_size = size; + + /* Initialize ep0 status request structure */ + /* FIXME: xusbps_alloc_request() ignores ep argument */ + udc->status_req = container_of(xusbps_alloc_request(NULL, GFP_KERNEL), + struct xusbps_req, req); + /* allocate a small amount of memory to get valid address */ + udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); + + udc->resume_state = USB_STATE_NOTATTACHED; + udc->usb_state = USB_STATE_POWERED; + udc->ep0_dir = 0; + udc->remote_wakeup = 0; /* default to 0 on reset */ + + return 0; +} + +/*---------------------------------------------------------------- + * Setup the xusbps_ep struct for eps + * Link xusbps_ep->ep to gadget->ep_list + * ep0out is not used so do nothing here + * ep0in should be taken care + *--------------------------------------------------------------*/ +static int struct_ep_setup(struct xusbps_udc *udc, + unsigned char index, char *name, int link) +{ + struct xusbps_ep *ep = &udc->eps[index]; + + ep->udc = udc; + strcpy(ep->name, name); + ep->ep.name = ep->name; + + ep->ep.ops = &xusbps_ep_ops; + ep->stopped = 0; + + /* for ep0: maxP defined in desc + * for other eps, maxP is set by epautoconfig() called by gadget layer + */ + ep->ep.maxpacket = (unsigned short) ~0; + + /* the queue lists any req for this ep */ + INIT_LIST_HEAD(&ep->queue); + + /* gagdet.ep_list used for ep_autoconfig so no ep0 */ + if (link) + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + ep->gadget = &udc->gadget; + ep->qh = &udc->ep_qh[index]; + + return 0; +} + +/* Driver probe function + * all intialization operations implemented here except enabling usb_intr reg + * board setup should have been done in the platform code + */ +static int xusbps_udc_probe(struct platform_device *pdev) +{ + int ret = -ENODEV; + unsigned int i; + u32 dccparams; + struct xusbps_usb2_platform_data *pdata; + + pdata = pdev->dev.platform_data; + if (!pdata) { + VDBG("Wrong device"); + return -ENODEV; + } + + if (strcmp(pdev->name, driver_name)) { + VDBG("Wrong device"); + return -ENODEV; + } + + udc_controller = kzalloc(sizeof(*udc_controller), GFP_KERNEL); + if (udc_controller == NULL) { + dev_err(&pdev->dev, "malloc udc failed\n"); + return -ENOMEM; + } + + spin_lock_init(&udc_controller->lock); + udc_controller->stopped = 1; + + dr_regs = (struct usb_dr_device __iomem *)pdata->regs; + if (!dr_regs) { + ret = -ENOMEM; + goto err_kfree; + } +#ifdef CONFIG_USB_ZYNQ_PHY + if (pdata->otg) { + udc_controller->transceiver = pdata->otg; + udc_controller->xotg = + xceiv_to_xotg(udc_controller->transceiver); + } +#endif + /* Initialize USB clocks */ + ret = xusbps_udc_clk_init(pdev); + if (ret < 0) + goto err_kfree; + + /* Read Device Controller Capability Parameters register */ + dccparams = xusbps_readl(&dr_regs->dccparams); + if (!(dccparams & DCCPARAMS_DC)) { + dev_err(&pdev->dev, "This SOC doesn't support device role\n"); + ret = -ENODEV; + goto err_iounmap; + } + /* Get max device endpoints */ + /* DEN is bidirectional ep number, max_ep doubles the number */ + udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2; + + udc_controller->irq = pdata->irq; + if (!udc_controller->irq) { + ret = -ENODEV; + goto err_iounmap; + } + + ret = devm_request_irq(&pdev->dev, udc_controller->irq, xusbps_udc_irq, + IRQF_SHARED, driver_name, udc_controller); + if (ret != 0) { + dev_err(&pdev->dev, "cannot request irq %d err %d\n", + udc_controller->irq, ret); + goto err_iounmap; + } + + /* Initialize the udc structure including QH member and other member */ + if (struct_udc_setup(udc_controller, pdev)) { + dev_err(&pdev->dev, "Can't initialize udc data structure\n"); + ret = -ENOMEM; + goto err_iounmap; + } + + /* initialize usb hw reg except for regs for EP, + * leave usbintr reg untouched */ +#ifdef CONFIG_USB_ZYNQ_PHY + if (!pdata->otg) + dr_controller_setup(udc_controller); +#else + dr_controller_setup(udc_controller); +#endif + + /* Setup gadget structure */ + udc_controller->gadget.ops = &xusbps_gadget_ops; + udc_controller->gadget.max_speed = USB_SPEED_HIGH; + udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; + INIT_LIST_HEAD(&udc_controller->gadget.ep_list); + udc_controller->gadget.name = driver_name; +#ifdef CONFIG_USB_ZYNQ_PHY + udc_controller->gadget.is_otg = (pdata->otg != NULL); +#endif + + /* Setup gadget.dev and register with kernel */ + dev_set_name(&udc_controller->gadget.dev, "gadget"); + udc_controller->gadget.dev.release = xusbps_udc_release; + udc_controller->gadget.dev.parent = &pdev->dev; + + /* setup QH and epctrl for ep0 */ + ep0_setup(udc_controller); + + /* setup udc->eps[] for ep0 */ + struct_ep_setup(udc_controller, 0, "ep0", 0); + /* for ep0: the desc defined here; + * for other eps, gadget layer called ep_enable with defined desc + */ + udc_controller->eps[0].ep.desc = &xusbps_ep0_desc; + udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD; + + /* setup the udc->eps[] for non-control endpoints and link + * to gadget.ep_list */ + for (i = 1; i < (int)(udc_controller->max_ep / 2); i++) { + char name[14]; + + sprintf(name, "ep%dout", i); + struct_ep_setup(udc_controller, i * 2, name, 1); + sprintf(name, "ep%din", i); + struct_ep_setup(udc_controller, i * 2 + 1, name, 1); + } + + /* use dma_pool for TD management */ + udc_controller->td_pool = dma_pool_create("udc_td", &pdev->dev, + sizeof(struct ep_td_struct), + DTD_ALIGNMENT, UDC_DMA_BOUNDARY); + if (udc_controller->td_pool == NULL) { + ret = -ENOMEM; + goto err_unregister; + } + + /* TODO: Check if VBUS can be dynamically detected by VBUS session + * interrupts using OTGSC register */ + udc_controller->vbus_active = 1; + + ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget); + if (ret) + goto err_del_udc; + + create_proc_file(); + return 0; + +err_del_udc: + dma_pool_destroy(udc_controller->td_pool); +err_unregister: + device_unregister(&udc_controller->gadget.dev); +err_iounmap: + xusbps_udc_clk_release(pdev); +err_kfree: + kfree(udc_controller); + udc_controller = NULL; + return ret; +} + +/* Driver removal function + * Free resources and finish pending transactions + */ +static int __exit xusbps_udc_remove(struct platform_device *pdev) +{ + DECLARE_COMPLETION(done); + + if (!udc_controller) + return -ENODEV; + + usb_del_gadget_udc(&udc_controller->gadget); + udc_controller->done = &done; + + xusbps_udc_clk_release(pdev); + + /* DR has been stopped in usb_gadget_unregister_driver() */ + remove_proc_file(); + + /* Free allocated memory */ + kfree(udc_controller->status_req->req.buf); + kfree(udc_controller->status_req); + kfree(udc_controller->eps); + + dma_pool_destroy(udc_controller->td_pool); + free_irq(udc_controller->irq, udc_controller); + device_unregister(&udc_controller->gadget.dev); + /* free udc --wait for the release() finished */ + wait_for_completion(&done); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +/*----------------------------------------------------------------- + * Modify Power management attributes + * Used by OTG statemachine to disable gadget temporarily + -----------------------------------------------------------------*/ +static int xusbps_udc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xusbps_usb2_platform_data *pdata = pdev->dev.platform_data; + + dr_controller_stop(udc_controller); + + clk_disable(pdata->clk); + + return 0; +} + +/*----------------------------------------------------------------- + * Invoked on USB resume. May be called in_interrupt. + * Here we start the DR controller and enable the irq + *-----------------------------------------------------------------*/ +static int xusbps_udc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xusbps_usb2_platform_data *pdata = pdev->dev.platform_data; + int ret; + + ret = clk_enable(pdata->clk); + if (ret) { + dev_err(dev, "Cannot enable APER clock.\n"); + return ret; + } + + /* Enable DR irq reg and set controller Run */ + if (udc_controller->stopped) { + dr_controller_setup(udc_controller); + dr_controller_run(udc_controller); + } + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; + return 0; +} + +static const struct dev_pm_ops xusbps_udc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xusbps_udc_suspend, xusbps_udc_resume) +}; +#define XUSBPS_UDC_PM (&xusbps_udc_dev_pm_ops) + +#else /* ! CONFIG_PM_SLEEP */ +#define XUSBPS_UDC_PM NULL +#endif /* ! CONFIG_PM_SLEEP */ + +/*------------------------------------------------------------------------- + Register entry point for the peripheral controller driver +--------------------------------------------------------------------------*/ + +static struct platform_driver udc_driver = { + .probe = xusbps_udc_probe, + .remove = xusbps_udc_remove, + /* these suspend and resume are not usb suspend and resume */ + .driver = { + .name = (char *)driver_name, + .owner = THIS_MODULE, + .pm = XUSBPS_UDC_PM, + }, +}; + +module_platform_driver(udc_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:xusbps-udc"); Index: linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/host/ehci.h 2014-07-20 22:05:50.231066703 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci.h 2014-07-20 22:06:38.210275137 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:182 @ unsigned long resuming_ports; /* which ports have started to resume */ +#ifdef CONFIG_USB_ZYNQ_PHY + /* + * OTG controllers and transceivers need software interaction; + * other external transceivers should be software-transparent + */ + void (*start_hnp)(struct ehci_hcd *ehci); +#endif + /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ struct dma_pool *qtd_pool; /* one or more per qh */ Index: linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci-hcd.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/host/ehci-hcd.c 2014-07-20 22:05:50.234066654 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci-hcd.c 2014-07-20 22:06:38.225274889 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:341 @ */ static void ehci_silence_controller(struct ehci_hcd *ehci) { +#ifdef CONFIG_USB_ZYNQ_PHY + struct usb_hcd *hcd = ehci_to_hcd(ehci); +#endif + ehci_halt(ehci); spin_lock_irq(&ehci->lock); ehci->rh_state = EHCI_RH_HALTED; +#ifdef CONFIG_USB_ZYNQ_PHY + /* turn off for non-otg port */ + if(!hcd->phy) + ehci_turn_off_all_ports(ehci); +#else ehci_turn_off_all_ports(ehci); +#endif /* make BIOS/etc use companion controller during reboot */ ehci_writel(ehci, 0, &ehci->regs->configured_flag); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:438 @ ehci_quiesce(ehci); ehci_silence_controller(ehci); +#ifdef CONFIG_USB_ZYNQ_PHY + if(!hcd->phy) + ehci_reset (ehci); +#else ehci_reset (ehci); +#endif hrtimer_cancel(&ehci->hrtimer); remove_sysfs_files(ehci); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:583 @ struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; u32 hcc_params; +#if defined(CONFIG_ARCH_ZYNQ) + void __iomem *non_ehci = hcd->regs; +#endif hcd->uses_new_polling = 1; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:655 @ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ - +#if defined(CONFIG_ARCH_ZYNQ) + /* Modifying FIFO Burst Threshold value from 2 to 8 */ + temp = readl(non_ehci + 0x164); + ehci_writel(ehci, 0x00080000, non_ehci + 0x164); +#endif /* GRR this is run-once init(), being done every time the HC starts. * So long as they're part of class devices, we can't do it init() * since the class device isn't created that early. @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:708 @ u32 status, masked_status, pcd_status = 0, cmd; int bh; unsigned long flags; + u32 intr_en; /* * For threadirqs option we use spin_lock_irqsave() variant to prevent @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:719 @ spin_lock_irqsave(&ehci->lock, flags); status = ehci_readl(ehci, &ehci->regs->status); + intr_en = ehci_readl(ehci, &ehci->regs->intr_enable); +#ifdef CONFIG_USB_ZYNQ_PHY + if(hcd->phy) { + /* A device */ + if (hcd->phy->otg->default_a && + (hcd->phy->state == OTG_STATE_A_PERIPHERAL)) { + spin_unlock(&ehci->lock); + return IRQ_NONE; + } + /* B device */ + if (!hcd->phy->otg->default_a && + ((hcd->phy->state != OTG_STATE_B_WAIT_ACON) && + (hcd->phy->state != OTG_STATE_B_HOST))) { + spin_unlock(&ehci->lock); + return IRQ_NONE; + } + /* If HABA is set and B-disconnect occurs, don't process that interrupt */ + if (ehci_is_TDI(ehci) && tdi_in_host_mode(ehci) == 0) { + spin_unlock(&ehci->lock); + return IRQ_NONE; + } + } +#endif /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { ehci_dbg (ehci, "device removed\n"); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1294 @ #define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver #endif +#ifdef CONFIG_USB_EHCI_XUSBPS +#include "ehci-xilinx-usbps.c" +#define PLATFORM_DRIVER ehci_xusbps_driver +#endif + #ifdef CONFIG_USB_W90X900_EHCI #include "ehci-w90x900.c" #define PLATFORM_DRIVER ehci_hcd_w90x900_driver Index: linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci-hub.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/host/ehci-hub.c 2014-07-20 22:05:50.235066638 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci-hub.c 2014-07-20 22:06:38.241274626 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1183 @ * Set appropriate bit thus could put phy into low power * mode if we have tdi_phy_lpm feature */ +#ifdef CONFIG_USB_ZYNQ_PHY + if (hcd->phy && (hcd->self.otg_port == (wIndex + 1)) + && (hcd->self.b_hnp_enable || hcd->self.is_b_host)) + ehci->start_hnp(ehci); + else { + temp &= ~PORT_WKCONN_E; + temp |= PORT_WKDISC_E | PORT_WKOC_E; + ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); + } +#else temp &= ~PORT_WKCONN_E; temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); +#endif if (ehci->has_tdi_phy_lpm) { spin_unlock_irqrestore(&ehci->lock, flags); msleep(5);/* 5ms for HCD enter low pwr mode */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1212 @ set_bit(wIndex, &ehci->suspended_ports); break; case USB_PORT_FEAT_POWER: +#ifdef CONFIG_USB_ZYNQ_PHY + /* Check if otg is enabled */ + if(!hcd->phy) { + if (HCS_PPC (ehci->hcs_params)) + ehci_writel(ehci, temp | PORT_POWER, + status_reg); + } +#else if (HCS_PPC (ehci->hcs_params)) ehci_writel(ehci, temp | PORT_POWER, status_reg); +#endif break; case USB_PORT_FEAT_RESET: if (temp & (PORT_SUSPEND|PORT_RESUME)) Index: linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci-xilinx-usbps.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci-xilinx-usbps.c 2014-07-20 22:06:38.253274428 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PS USB Host Controller Driver. + * + * Copyright (C) 2011 Xilinx, Inc. + * + * This file is based on ehci-fsl.c file with few minor modifications + * to support Xilinx PS USB controller. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/clk.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/xilinx_devices.h> +#include <linux/usb/otg.h> +#include <linux/usb/xilinx_usbps_otg.h> + +#include "ehci-xilinx-usbps.h" + +#ifdef CONFIG_USB_ZYNQ_PHY +/******************************************************************** + * OTG related functions + ********************************************************************/ +static int ehci_xusbps_reinit(struct ehci_hcd *ehci); + +/* This connection event is useful when a OTG test device is connected. + In that case, the device connect notify event will not be generated + since the device will be suspended before complete enumeration. +*/ +static int ehci_xusbps_update_device(struct usb_hcd *hcd, struct usb_device + *udev) +{ + struct xusbps_otg *xotg = xceiv_to_xotg(hcd->phy); + + if (udev->portnum == hcd->self.otg_port) { + /* HNP test device */ + if ((le16_to_cpu(udev->descriptor.idVendor) == 0x1a0a && + le16_to_cpu(udev->descriptor.idProduct) == 0xbadd)) { + if (xotg->otg.otg->default_a == 1) + xotg->hsm.b_conn = 1; + else + xotg->hsm.a_conn = 1; + xusbps_update_transceiver(); + } + } + return 0; +} + +static void ehci_xusbps_start_hnp(struct ehci_hcd *ehci) +{ + const unsigned port = ehci_to_hcd(ehci)->self.otg_port - 1; + struct usb_hcd *hcd = ehci_to_hcd(ehci); + unsigned long flags; + u32 portsc; + + local_irq_save(flags); + portsc = ehci_readl(ehci, &ehci->regs->port_status[port]); + portsc |= PORT_SUSPEND; + ehci_writel(ehci, portsc, &ehci->regs->port_status[port]); + local_irq_restore(flags); + + otg_start_hnp(hcd->phy->otg); +} + +static int ehci_xusbps_otg_start_host(struct usb_phy *otg) +{ + struct usb_hcd *hcd = bus_to_hcd(otg->otg->host); + struct xusbps_otg *xotg = + xceiv_to_xotg(hcd->phy); + + usb_add_hcd(hcd, xotg->irq, IRQF_SHARED); + return 0; +} + +static int ehci_xusbps_otg_stop_host(struct usb_phy *otg) +{ + struct usb_hcd *hcd = bus_to_hcd(otg->otg->host); + + usb_remove_hcd(hcd); + return 0; +} +#endif + +static int xusbps_ehci_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + + switch (event) { + case PRE_RATE_CHANGE: + /* if a rate change is announced we need to check whether we can + * maintain the current frequency by changing the clock + * dividers. + */ + /* fall through */ + case POST_RATE_CHANGE: + return NOTIFY_OK; + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_hcd_xusbps_probe - initialize XUSBPS-based HCDs + * @driver: Driver to be used for this HCD + * @pdev: USB Host Controller being probed + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller. + * + */ +static int usb_hcd_xusbps_probe(const struct hc_driver *driver, + struct platform_device *pdev) +{ + struct xusbps_usb2_platform_data *pdata; + struct usb_hcd *hcd; + int irq; + int retval; + + pr_debug("initializing XUSBPS-SOC USB Controller\n"); + + /* Need platform data for setup */ + pdata = (struct xusbps_usb2_platform_data *)pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, + "No platform data for %s.\n", dev_name(&pdev->dev)); + return -ENODEV; + } + + /* + * This is a host mode driver, verify that we're supposed to be + * in host mode. + */ + if (!((pdata->operating_mode == XUSBPS_USB2_DR_HOST) || + (pdata->operating_mode == XUSBPS_USB2_MPH_HOST) || + (pdata->operating_mode == XUSBPS_USB2_DR_OTG))) { + dev_err(&pdev->dev, "Non Host Mode configured for %s. Wrong \ + driver linked.\n", dev_name(&pdev->dev)); + return -ENODEV; + } + + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + retval = -ENOMEM; + goto err1; + } + + irq = pdata->irq; + hcd->regs = pdata->regs; + + if (hcd->regs == NULL) { + dev_dbg(&pdev->dev, "error mapping memory\n"); + retval = -EFAULT; + goto err2; + } + + retval = clk_prepare_enable(pdata->clk); + if (retval) { + dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + goto err2; + } + + pdata->clk_rate_change_nb.notifier_call = xusbps_ehci_clk_notifier_cb; + pdata->clk_rate_change_nb.next = NULL; + if (clk_notifier_register(pdata->clk, &pdata->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); + + + /* + * do platform specific init: check the clock, grab/config pins, etc. + */ + if (pdata->init && pdata->init(pdev)) { + retval = -ENODEV; + goto err_out_clk_unreg_notif; + } + +#ifdef CONFIG_USB_ZYNQ_PHY + if (pdata->otg) { + struct xusbps_otg *xotg; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + hcd->self.otg_port = 1; + hcd->phy = pdata->otg; + retval = otg_set_host(hcd->phy->otg, + &ehci_to_hcd(ehci)->self); + if (retval) + goto err_out_clk_unreg_notif; + xotg = xceiv_to_xotg(hcd->phy); + ehci->start_hnp = ehci_xusbps_start_hnp; + xotg->start_host = ehci_xusbps_otg_start_host; + xotg->stop_host = ehci_xusbps_otg_stop_host; + /* inform otg driver about host driver */ + xusbps_update_transceiver(); + } else { + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval) + goto err_out_clk_unreg_notif; + + /* + * Enable vbus on ULPI - zedboard requirement + * to get host mode to work + */ + if (pdata->ulpi) + otg_set_vbus(pdata->ulpi->otg, 1); + } +#else + /* Don't need to set host mode here. It will be done by tdi_reset() */ + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval) + goto err_out_clk_unreg_notif; +#endif + return retval; + +err_out_clk_unreg_notif: + clk_notifier_unregister(pdata->clk, &pdata->clk_rate_change_nb); + clk_disable_unprepare(pdata->clk); +err2: + usb_put_hcd(hcd); +err1: + dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); + if (pdata->exit) + pdata->exit(pdev); + + return retval; +} + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_xusbps_remove - shutdown processing for XUSBPS-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_xusbps_probe(). + * + */ +static void usb_hcd_xusbps_remove(struct usb_hcd *hcd, + struct platform_device *pdev) +{ + struct xusbps_usb2_platform_data *pdata = pdev->dev.platform_data; + + usb_remove_hcd(hcd); + + /* + * do platform specific un-initialization: + * release iomux pins, disable clock, etc. + */ + if (pdata->exit) + pdata->exit(pdev); + usb_put_hcd(hcd); + clk_notifier_unregister(pdata->clk, &pdata->clk_rate_change_nb); + clk_disable_unprepare(pdata->clk); +} + +static void ehci_xusbps_setup_phy(struct ehci_hcd *ehci, + enum xusbps_usb2_phy_modes phy_mode, + unsigned int port_offset) +{ + u32 portsc; + + portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); + portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); + + switch (phy_mode) { + case XUSBPS_USB2_PHY_ULPI: + portsc |= PORT_PTS_ULPI; + break; + case XUSBPS_USB2_PHY_SERIAL: + portsc |= PORT_PTS_SERIAL; + break; + case XUSBPS_USB2_PHY_UTMI_WIDE: + portsc |= PORT_PTS_PTW; + /* fall through */ + case XUSBPS_USB2_PHY_UTMI: + portsc |= PORT_PTS_UTMI; + break; + case XUSBPS_USB2_PHY_NONE: + break; + } + ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); +} + +static void ehci_xusbps_usb_setup(struct ehci_hcd *ehci) +{ + struct usb_hcd *hcd = ehci_to_hcd(ehci); + struct xusbps_usb2_platform_data *pdata; + + pdata = hcd->self.controller->platform_data; + + if ((pdata->operating_mode == XUSBPS_USB2_DR_HOST) || + (pdata->operating_mode == XUSBPS_USB2_DR_OTG)) + ehci_xusbps_setup_phy(ehci, pdata->phy_mode, 0); + + if (pdata->operating_mode == XUSBPS_USB2_MPH_HOST) { + if (pdata->port_enables & XUSBPS_USB2_PORT0_ENABLED) + ehci_xusbps_setup_phy(ehci, pdata->phy_mode, 0); + if (pdata->port_enables & XUSBPS_USB2_PORT1_ENABLED) + ehci_xusbps_setup_phy(ehci, pdata->phy_mode, 1); + } +} + +/* + * FIXME USB: EHCI: remove ehci_port_power() routine + *(sha1: c73cee717e7d5da0698acb720ad1219646fe4f46) + */ +static void ehci_port_power (struct ehci_hcd *ehci, int is_on) +{ + unsigned port; + + if (!HCS_PPC (ehci->hcs_params)) + return; + + ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down"); + for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) + (void) ehci_hub_control(ehci_to_hcd(ehci), + is_on ? SetPortFeature : ClearPortFeature, + USB_PORT_FEAT_POWER, + port--, NULL, 0); + /* Flush those writes */ + ehci_readl(ehci, &ehci->regs->command); + msleep(20); +} + +/* called after powerup, by probe or system-pm "wakeup" */ +static int ehci_xusbps_reinit(struct ehci_hcd *ehci) +{ +#ifdef CONFIG_USB_ZYNQ_PHY + struct usb_hcd *hcd = ehci_to_hcd(ehci); +#endif + + ehci_xusbps_usb_setup(ehci); +#ifdef CONFIG_USB_ZYNQ_PHY + /* Don't turn off port power in OTG mode */ + if (!hcd->phy) +#endif + ehci_port_power(ehci, 0); + + return 0; +} + +struct ehci_xusbps { + struct ehci_hcd ehci; + +#ifdef CONFIG_PM + /* Saved USB PHY settings, need to restore after deep sleep. */ + u32 usb_ctrl; +#endif +}; + +/* called during probe() after chip reset completes */ +static int ehci_xusbps_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + + /* EHCI registers start at offset 0x100 */ + ehci->caps = hcd->regs + 0x100; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + hcd->has_tt = 1; + + /* data structure init */ + retval = ehci_init(hcd); + if (retval) + return retval; + + retval = ehci_halt(ehci); + if (retval) + return retval; + + ehci->sbrn = 0x20; + + ehci_reset(ehci); + + retval = ehci_xusbps_reinit(ehci); + return retval; +} + +static void ehci_xusbps_shutdown(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + if (ehci->regs) + ehci_shutdown(hcd); +} + +#ifdef CONFIG_PM_SLEEP +static int ehci_xusbps_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xusbps_usb2_platform_data *pdata = dev->platform_data; + + ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), + device_may_wakeup(dev)); + + clk_disable(pdata->clk); + + return 0; +} + +static int ehci_xusbps_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct xusbps_usb2_platform_data *pdata = dev->platform_data; + int ret; + + ret = clk_enable(pdata->clk); + if (ret) { + dev_err(dev, "cannot enable clock. resume failed\n"); + return ret; + } + + ehci_prepare_ports_for_controller_resume(ehci); + + usb_root_hub_lost_power(hcd->self.root_hub); + + ehci_reset(ehci); + ehci_xusbps_reinit(ehci); + + return 0; +} + +static const struct dev_pm_ops ehci_xusbps_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ehci_xusbps_drv_suspend, ehci_xusbps_drv_resume) +}; +#define EHCI_XUSBPS_PM_OPS (&ehci_xusbps_pm_ops) + +#else /* ! CONFIG_PM_SLEEP */ +#define EHCI_XUSBPS_PM_OPS NULL +#endif /* ! CONFIG_PM_SLEEP */ + + +static const struct hc_driver ehci_xusbps_hc_driver = { + .description = hcd_name, + .product_desc = "Xilinx PS USB EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_xusbps), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_USB2 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .reset = ehci_xusbps_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_xusbps_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +#ifdef CONFIG_USB_ZYNQ_PHY + .update_device = ehci_xusbps_update_device, +#endif +}; + +static int ehci_xusbps_drv_probe(struct platform_device *pdev) +{ + if (usb_disabled()) + return -ENODEV; + + /* FIXME we only want one one probe() not two */ + return usb_hcd_xusbps_probe(&ehci_xusbps_hc_driver, pdev); +} + +static int ehci_xusbps_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + /* FIXME we only want one one remove() not two */ + usb_hcd_xusbps_remove(hcd, pdev); + return 0; +} + +MODULE_ALIAS("platform:xusbps-ehci"); + +static struct platform_driver ehci_xusbps_driver = { + .probe = ehci_xusbps_drv_probe, + .remove = ehci_xusbps_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "xusbps-ehci", + .pm = EHCI_XUSBPS_PM_OPS, + }, +}; Index: linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci-xilinx-usbps.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/usb/host/ehci-xilinx-usbps.h 2014-07-20 22:06:38.260274312 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PS USB Host Controller Driver Header file. + * + * Copyright (C) 2011 Xilinx, Inc. + * + * This file is based on ehci-fsl.h file with few minor modifications + * to support Xilinx PS USB controller. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _EHCI_XILINX_XUSBPS_H +#define _EHCI_XILINX_XUSBPS_H + +#include <linux/usb/xilinx_usbps_otg.h> + +/* offsets for the non-ehci registers in the XUSBPS SOC USB controller */ +#define XUSBPS_SOC_USB_ULPIVP 0x170 +#define XUSBPS_SOC_USB_PORTSC1 0x184 +#define PORT_PTS_MSK (3<<30) +#define PORT_PTS_UTMI (0<<30) +#define PORT_PTS_ULPI (2<<30) +#define PORT_PTS_SERIAL (3<<30) +#define PORT_PTS_PTW (1<<28) +#define XUSBPS_SOC_USB_PORTSC2 0x188 + +#endif /* _EHCI_XILINX_XUSBPS_H */ Index: linux-3.12.24-rt38-xilinx/drivers/usb/host/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/host/Kconfig 2014-07-20 22:05:50.233066671 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/host/Kconfig 2014-07-20 22:06:38.270274147 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:118 @ support both high speed and full speed devices, or high speed devices only. +config USB_XUSBPS_DR_OF + tristate + select USB_PHY + select USB_ULPI + select USB_ULPI_VIEWPORT + +config USB_EHCI_XUSBPS + bool "Support for Xilinx PS EHCI USB controller" + depends on USB_EHCI_HCD && ARCH_ZYNQ + select USB_EHCI_ROOT_HUB_TT + select USB_XUSBPS_DR_OF + ---help--- + Xilinx PS USB host controller core is EHCI compilant and has + transaction translator built-in. + config USB_EHCI_FSL bool "Support for Freescale PPC on-chip EHCI USB controller" depends on FSL_SOC Index: linux-3.12.24-rt38-xilinx/drivers/usb/host/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/host/Makefile 2014-07-20 22:05:50.232066687 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/host/Makefile 2014-07-20 22:06:38.280273982 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:61 @ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o +obj-$(CONFIG_USB_XUSBPS_DR_OF) += xusbps-dr-of.o obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o Index: linux-3.12.24-rt38-xilinx/drivers/usb/host/xusbps-dr-of.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/usb/host/xusbps-dr-of.c 2014-07-20 22:06:38.290273817 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PS USB Driver for device tree support. + * + * Copyright (C) 2011 Xilinx, Inc. + * + * This file is based on fsl-mph-dr-of.c file with few minor modifications + * to support Xilinx PS USB controller. + * + * Setup platform devices needed by the dual-role USB controller modules + * based on the description in flat device tree. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/xilinx_devices.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of_platform.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/clk.h> +#include <linux/usb/ulpi.h> + +#include "ehci-xilinx-usbps.h" + +static u64 dma_mask = 0xFFFFFFF0; + +struct xusbps_dev_data { + char *dr_mode; /* controller mode */ + char *drivers[3]; /* drivers to instantiate for this mode */ + enum xusbps_usb2_operating_modes op_mode; /* operating mode */ +}; + +struct xusbps_host_data { + struct clk *clk; +}; + +static struct xusbps_dev_data dr_mode_data[] = { + { + .dr_mode = "host", + .drivers = { "xusbps-ehci", NULL, NULL, }, + .op_mode = XUSBPS_USB2_DR_HOST, + }, + { + .dr_mode = "otg", + .drivers = { "xusbps-otg", "xusbps-ehci", "xusbps-udc", }, + .op_mode = XUSBPS_USB2_DR_OTG, + }, + { + .dr_mode = "peripheral", + .drivers = { "xusbps-udc", NULL, NULL, }, + .op_mode = XUSBPS_USB2_DR_DEVICE, + }, +}; + +static struct xusbps_dev_data * get_dr_mode_data( + struct device_node *np) +{ + const unsigned char *prop; + int i; + + prop = of_get_property(np, "dr_mode", NULL); + if (prop) { + for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) { + if (!strcmp(prop, dr_mode_data[i].dr_mode)) + return &dr_mode_data[i]; + } + } + pr_warn("%s: Invalid 'dr_mode' property, fallback to host mode\n", + np->full_name); + return &dr_mode_data[0]; /* mode not specified, use host */ +} + +static enum xusbps_usb2_phy_modes determine_usb_phy(const char *phy_type) +{ + if (!phy_type) + return XUSBPS_USB2_PHY_NONE; + if (!strcasecmp(phy_type, "ulpi")) + return XUSBPS_USB2_PHY_ULPI; + if (!strcasecmp(phy_type, "utmi")) + return XUSBPS_USB2_PHY_UTMI; + if (!strcasecmp(phy_type, "utmi_wide")) + return XUSBPS_USB2_PHY_UTMI_WIDE; + if (!strcasecmp(phy_type, "serial")) + return XUSBPS_USB2_PHY_SERIAL; + + return XUSBPS_USB2_PHY_NONE; +} + +static struct platform_device * xusbps_device_register( + struct platform_device *ofdev, + struct xusbps_usb2_platform_data *pdata, + const char *name, int id) +{ + struct platform_device *pdev; + const struct resource *res = ofdev->resource; + unsigned int num = ofdev->num_resources; + struct xusbps_usb2_platform_data *pdata1; + int retval; + + pdev = platform_device_alloc(name, id); + if (!pdev) { + retval = -ENOMEM; + goto error; + } + + pdev->dev.parent = &ofdev->dev; + + pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask; + pdev->dev.dma_mask = &dma_mask; + + retval = platform_device_add_data(pdev, pdata, sizeof(*pdata)); + if (retval) + goto error; + + if (num) { + retval = platform_device_add_resources(pdev, res, num); + if (retval) + goto error; + } + + retval = platform_device_add(pdev); + if (retval) + goto error; + + pdata1 = pdev->dev.platform_data; + /* Copy the otg transceiver pointer into host/device platform data */ + if (pdata1->otg) + pdata->otg = pdata1->otg; + + return pdev; + +error: + platform_device_put(pdev); + return ERR_PTR(retval); +} + +static int xusbps_dr_of_probe(struct platform_device *ofdev) +{ + struct device_node *np = ofdev->dev.of_node; + struct platform_device *usb_dev; + struct xusbps_usb2_platform_data data, *pdata; + struct xusbps_dev_data *dev_data; + struct xusbps_host_data *hdata; + const unsigned char *prop; + static unsigned int idx; + struct resource *res; + int i, phy_init; + int ret; + + pdata = &data; + memset(pdata, 0, sizeof(data)); + + res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0); + if (IS_ERR(res)) { + dev_err(&ofdev->dev, + "IRQ not found\n"); + return PTR_ERR(res); + } + pdata->irq = res->start; + + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + pdata->regs = devm_ioremap_resource(&ofdev->dev, res); + if (IS_ERR(pdata->regs)) { + dev_err(&ofdev->dev, "unable to iomap registers\n"); + return PTR_ERR(pdata->regs); + } + + dev_data = get_dr_mode_data(np); + pdata->operating_mode = dev_data->op_mode; + + prop = of_get_property(np, "phy_type", NULL); + pdata->phy_mode = determine_usb_phy(prop); + + hdata = devm_kzalloc(&ofdev->dev, sizeof(*hdata), GFP_KERNEL); + if (!hdata) + return -ENOMEM; + platform_set_drvdata(ofdev, hdata); + + hdata->clk = devm_clk_get(&ofdev->dev, NULL); + if (IS_ERR(hdata->clk)) { + dev_err(&ofdev->dev, "input clock not found.\n"); + return PTR_ERR(hdata->clk); + } + + ret = clk_prepare_enable(hdata->clk); + if (ret) { + dev_err(&ofdev->dev, "Unable to enable APER clock.\n"); + return ret; + } + + pdata->clk = hdata->clk; + + /* If ULPI phy type, set it up */ + if (pdata->phy_mode == XUSBPS_USB2_PHY_ULPI) { + pdata->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); + if (pdata->ulpi) { + pdata->ulpi->io_priv = pdata->regs + + XUSBPS_SOC_USB_ULPIVP; + + phy_init = usb_phy_init(pdata->ulpi); + if (phy_init) { + dev_err(&ofdev->dev, + "Unable to init USB phy, missing?\n"); + ret = -ENODEV; + goto err_out_clk_disable; + } + } else { + dev_err(&ofdev->dev, + "Unable to create ULPI transceiver\n"); + } + } + + for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) { + if (!dev_data->drivers[i]) + continue; + usb_dev = xusbps_device_register(ofdev, pdata, + dev_data->drivers[i], idx); + if (IS_ERR(usb_dev)) { + dev_err(&ofdev->dev, "Can't register usb device\n"); + ret = PTR_ERR(usb_dev); + goto err_out_clk_disable; + } + } + idx++; + return 0; + +err_out_clk_disable: + clk_disable_unprepare(hdata->clk); + + return ret; +} + +static int __unregister_subdev(struct device *dev, void *d) +{ + platform_device_unregister(to_platform_device(dev)); + return 0; +} + +static int xusbps_dr_of_remove(struct platform_device *ofdev) +{ + struct xusbps_host_data *hdata = platform_get_drvdata(ofdev); + + device_for_each_child(&ofdev->dev, NULL, __unregister_subdev); + clk_disable_unprepare(hdata->clk); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int xusbps_dr_of_suspend(struct device *dev) +{ + struct xusbps_host_data *hdata = dev_get_drvdata(dev); + + clk_disable(hdata->clk); + + return 0; +} + +static int xusbps_dr_of_resume(struct device *dev) +{ + struct xusbps_host_data *hdata = dev_get_drvdata(dev); + int ret; + + ret = clk_enable(hdata->clk); + if (ret) { + dev_err(dev, "cannot enable clock. resume failed\n"); + return ret; + } + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(xusbps_pm_ops, xusbps_dr_of_suspend, + xusbps_dr_of_resume); + +static const struct of_device_id xusbps_dr_of_match[] = { + { .compatible = "xlnx,ps7-usb-1.00.a" }, + {}, +}; +MODULE_DEVICE_TABLE(of, xusbps_dr_of_match); + +static struct platform_driver xusbps_dr_driver = { + .driver = { + .name = "xusbps-dr", + .owner = THIS_MODULE, + .of_match_table = xusbps_dr_of_match, + .pm = &xusbps_pm_ops, + }, + .probe = xusbps_dr_of_probe, + .remove = xusbps_dr_of_remove, +}; + +#ifdef CONFIG_USB_ZYNQ_PHY +extern struct platform_driver xusbps_otg_driver; + +static int __init xusbps_dr_init(void) +{ + int retval; + + /* Register otg driver first */ + retval = platform_driver_register(&xusbps_otg_driver); + if (retval != 0) + return retval; + + return platform_driver_register(&xusbps_dr_driver); +} +module_init(xusbps_dr_init); + +static void __exit xusbps_dr_exit(void) +{ + platform_driver_unregister(&xusbps_dr_driver); +} +module_exit(xusbps_dr_exit); +#else +module_platform_driver(xusbps_dr_driver); +#endif + +MODULE_DESCRIPTION("XUSBPS DR OF devices driver"); +MODULE_AUTHOR("Xilinx"); +MODULE_LICENSE("GPL"); Index: linux-3.12.24-rt38-xilinx/drivers/usb/phy/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/phy/Kconfig 2014-07-20 22:05:50.230066720 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/phy/Kconfig 2014-07-20 22:06:38.303273603 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:231 @ Provides read/write operations to the ULPI phy register set for controllers with a viewport register (e.g. Chipidea/ARC controllers). +config USB_ZYNQ_PHY + tristate "Xilinx Zynq USB OTG dual-role support" + depends on USB && ARCH_ZYNQ && USB_EHCI_XUSBPS && USB_GADGET_XUSBPS && USB_OTG + select USB_OTG_UTILS + help + Say Y here if you want to build Xilinx USB PS OTG + driver in kernel. This driver implements role + switch between EHCI host driver and USB gadget driver. + + To compile this driver as a module, choose M here: the + module will be called xilinx_usbps_otg. + endmenu Index: linux-3.12.24-rt38-xilinx/drivers/usb/phy/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/usb/phy/Makefile 2014-07-20 22:05:50.229066737 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/usb/phy/Makefile 2014-07-20 22:06:38.312273454 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:34 @ obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o obj-$(CONFIG_USB_ULPI) += phy-ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o +obj-$(CONFIG_USB_ZYNQ_PHY) += phy-zynq-usb.o Index: linux-3.12.24-rt38-xilinx/drivers/usb/phy/phy-zynq-usb.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/usb/phy/phy-zynq-usb.c 2014-07-20 22:06:38.341272976 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PS USB otg driver. + * + * Copyright 2011 Xilinx, Inc. + * + * This file is based on langwell_otg.c file with few minor modifications + * to support Xilinx PS USB controller. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* This driver helps to switch Xilinx OTG controller function between host + * and peripheral. It works with EHCI driver and Xilinx client controller + * driver together. + */ +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/moduleparam.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb.h> +#include <linux/usb/otg.h> +#include <linux/usb/hcd.h> +#include <linux/notifier.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/io.h> + +#include "../core/usb.h" + +#include <linux/xilinx_devices.h> +#include <linux/usb/xilinx_usbps_otg.h> + +#define DRIVER_NAME "xusbps-otg" + +static const char driver_name[] = DRIVER_NAME; + +/* HSM timers */ +static inline struct xusbps_otg_timer *otg_timer_initializer +(void (*function)(unsigned long), unsigned long expires, unsigned long data) +{ + struct xusbps_otg_timer *timer; + timer = kmalloc(sizeof(struct xusbps_otg_timer), GFP_KERNEL); + if (timer == NULL) + return timer; + + timer->function = function; + timer->expires = expires; + timer->data = data; + return timer; +} + +static struct xusbps_otg_timer *a_wait_vrise_tmr, *a_aidl_bdis_tmr, + *b_se0_srp_tmr, *b_srp_init_tmr; + +static struct list_head active_timers; + +static struct xusbps_otg *the_transceiver; + +/* host/client notify transceiver when event affects HNP state */ +void xusbps_update_transceiver(void) +{ + struct xusbps_otg *xotg = the_transceiver; + + dev_dbg(xotg->dev, "transceiver is updated\n"); + + if (!xotg->qwork) + return ; + + queue_work(xotg->qwork, &xotg->work); +} +EXPORT_SYMBOL(xusbps_update_transceiver); + +static int xusbps_otg_set_host(struct usb_otg *otg, + struct usb_bus *host) +{ + otg->host = host; + + if (host) { + if (otg->default_a) + host->is_b_host = 0; + else + host->is_b_host = 1; + } + + return 0; +} + +static int xusbps_otg_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + + if (gadget) { + if (otg->default_a) + gadget->is_a_peripheral = 1; + else + gadget->is_a_peripheral = 0; + } + + return 0; +} + +static int xusbps_otg_set_power(struct usb_phy *otg, + unsigned mA) +{ + return 0; +} + +/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/ +static int xusbps_otg_set_vbus(struct usb_otg *otg, bool enabled) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val; + + dev_dbg(xotg->dev, "%s <--- %s\n", __func__, enabled ? "on" : "off"); + + /* Enable ulpi VBUS if required */ + if (xotg->ulpi) + otg_set_vbus(xotg->ulpi->otg, enabled); + + val = readl(xotg->base + CI_PORTSC1); + + if (enabled) + writel((val | PORTSC_PP), xotg->base + CI_PORTSC1); + else + writel((val & ~PORTSC_PP), xotg->base + CI_PORTSC1); + + dev_dbg(xotg->dev, "%s --->\n", __func__); + + return 0; +} + +/* Charge vbus for VBUS pulsing in SRP */ +static void xusbps_otg_chrg_vbus(int on) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val; + + val = readl(xotg->base + CI_OTGSC) & ~OTGSC_INTSTS_MASK; + + if (on) + /* stop discharging, start charging */ + val = (val & ~OTGSC_VD) | OTGSC_VC; + else + /* stop charging */ + val &= ~OTGSC_VC; + + writel(val, xotg->base + CI_OTGSC); +} + +#if 0 + +/* Discharge vbus through a resistor to ground */ +static void xusbps_otg_dischrg_vbus(int on) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val; + + val = readl(xotg->base + CI_OTGSC) & ~OTGSC_INTSTS_MASK; + + if (on) + /* stop charging, start discharging */ + val = (val & ~OTGSC_VC) | OTGSC_VD; + else + val &= ~OTGSC_VD; + + writel(val, xotg->base + CI_OTGSC); +} + +#endif + +/* Start SRP */ +static int xusbps_otg_start_srp(struct usb_otg *otg) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val; + + dev_warn(xotg->dev, "Starting SRP...\n"); + dev_dbg(xotg->dev, "%s --->\n", __func__); + + val = readl(xotg->base + CI_OTGSC); + + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, + xotg->base + CI_OTGSC); + + /* Check if the data plus is finished or not */ + msleep(8); + val = readl(xotg->base + CI_OTGSC); + if (val & (OTGSC_HADP | OTGSC_DP)) + dev_dbg(xotg->dev, "DataLine SRP Error\n"); + + /* If Vbus is valid, then update the hsm */ + if (val & OTGSC_BSV) { + dev_dbg(xotg->dev, "no b_sess_vld interrupt\n"); + + xotg->hsm.b_sess_vld = 1; + xusbps_update_transceiver(); + return 0; + } + + dev_warn(xotg->dev, "Starting VBUS Pulsing...\n"); + + /* Disable interrupt - b_sess_vld */ + val = readl(xotg->base + CI_OTGSC); + val &= (~(OTGSC_BSVIE | OTGSC_BSEIE)); + writel(val, xotg->base + CI_OTGSC); + + /* Start VBus SRP, drive vbus to generate VBus pulse */ + xusbps_otg_chrg_vbus(1); + msleep(15); + xusbps_otg_chrg_vbus(0); + + /* Enable interrupt - b_sess_vld*/ + val = readl(xotg->base + CI_OTGSC); + dev_dbg(xotg->dev, "after VBUS pulse otgsc = %x\n", val); + + val |= (OTGSC_BSVIE | OTGSC_BSEIE); + writel(val, xotg->base + CI_OTGSC); + + /* If Vbus is valid, then update the hsm */ + if (val & OTGSC_BSV) { + dev_dbg(xotg->dev, "no b_sess_vld interrupt\n"); + + xotg->hsm.b_sess_vld = 1; + xusbps_update_transceiver(); + } + + dev_dbg(xotg->dev, "%s <---\n", __func__); + return 0; +} + +/* Start HNP */ +static int xusbps_otg_start_hnp(struct usb_otg *otg) +{ + struct xusbps_otg *xotg = the_transceiver; + unsigned long flag = 0; + + dev_warn(xotg->dev, "Starting HNP...\n"); + dev_dbg(xotg->dev, "%s --->\n", __func__); + + if (xotg->otg.otg->default_a && xotg->otg.otg->host && + xotg->otg.otg->host->b_hnp_enable) { + xotg->hsm.a_suspend_req = 1; + flag = 1; + } + + if (!xotg->otg.otg->default_a && xotg->otg.otg->host && + xotg->hsm.b_bus_req) { + xotg->hsm.b_bus_req = 0; + flag = 1; + } + + if (flag) { + if (spin_trylock(&xotg->wq_lock)) { + xusbps_update_transceiver(); + spin_unlock(&xotg->wq_lock); + } + } else + dev_warn(xotg->dev, "HNP not supported\n"); + + dev_dbg(xotg->dev, "%s <---\n", __func__); + return 0; +} + +/* stop SOF via bus_suspend */ +static void xusbps_otg_loc_sof(int on) +{ + /* Not used */ +} + +static void xusbps_otg_phy_low_power(int on) +{ + /* Not used */ +} + +/* After drv vbus, add 2 ms delay to set PHCD */ +static void xusbps_otg_phy_low_power_wait(int on) +{ + struct xusbps_otg *xotg = the_transceiver; + + dev_dbg(xotg->dev, "add 2ms delay before programing PHCD\n"); + + mdelay(2); + xusbps_otg_phy_low_power(on); +} + +#ifdef CONFIG_PM_SLEEP +/* Enable/Disable OTG interrupt */ +static void xusbps_otg_intr(int on) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val; + + dev_dbg(xotg->dev, "%s ---> %s\n", __func__, on ? "on" : "off"); + + val = readl(xotg->base + CI_OTGSC); + + /* OTGSC_INT_MASK doesn't contains 1msInt */ + if (on) { + val = val | (OTGSC_INT_MASK); + writel(val, xotg->base + CI_OTGSC); + } else { + val = val & ~(OTGSC_INT_MASK); + writel(val, xotg->base + CI_OTGSC); + } + + dev_dbg(xotg->dev, "%s <---\n", __func__); +} +#endif + +/* set HAAR: Hardware Assist Auto-Reset */ +static void xusbps_otg_HAAR(int on) +{ + /* Not used */ +} + +/* set HABA: Hardware Assist B-Disconnect to A-Connect */ +static void xusbps_otg_HABA(int on) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val; + + dev_dbg(xotg->dev, "%s ---> %s\n", __func__, on ? "on" : "off"); + + val = readl(xotg->base + CI_OTGSC); + if (on) + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA, + xotg->base + CI_OTGSC); + else + writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA, + xotg->base + CI_OTGSC); + + dev_dbg(xotg->dev, "%s <---\n", __func__); +} + +static int xusbps_otg_check_se0_srp(int on) +{ + struct xusbps_otg *xotg = the_transceiver; + int delay_time = TB_SE0_SRP * 10; + u32 val; + + dev_dbg(xotg->dev, "%s --->\n", __func__); + + do { + udelay(100); + if (!delay_time--) + break; + val = readl(xotg->base + CI_PORTSC1); + val &= PORTSC_LS; + } while (!val); + + dev_dbg(xotg->dev, "%s <---\n", __func__); + return val; +} + +/* The timeout callback function to set time out bit */ +static void set_tmout(unsigned long indicator) +{ + *(int *)indicator = 1; +} + +static void xusbps_otg_msg(unsigned long indicator) +{ + struct xusbps_otg *xotg = the_transceiver; + + switch (indicator) { + case 2: + case 4: + case 6: + case 7: + dev_warn(xotg->dev, + "OTG:%lu - deivce not responding\n", indicator); + break; + case 3: + dev_warn(xotg->dev, + "OTG:%lu - deivce not supported\n", indicator); + break; + default: + dev_warn(xotg->dev, "Do not have this msg\n"); + break; + } +} + +/* Initialize timers */ +static int xusbps_otg_init_timers(struct otg_hsm *hsm) +{ + /* HSM used timers */ + a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE, + (unsigned long)&hsm->a_wait_vrise_tmout); + if (a_wait_vrise_tmr == NULL) + return -ENOMEM; + a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS, + (unsigned long)&hsm->a_aidl_bdis_tmout); + if (a_aidl_bdis_tmr == NULL) + return -ENOMEM; + b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP, + (unsigned long)&hsm->b_se0_srp); + if (b_se0_srp_tmr == NULL) + return -ENOMEM; + b_srp_init_tmr = otg_timer_initializer(&set_tmout, TB_SRP_INIT, + (unsigned long)&hsm->b_srp_init_tmout); + if (b_srp_init_tmr == NULL) + return -ENOMEM; + + return 0; +} + +/* Free timers */ +static void xusbps_otg_free_timers(void) +{ + kfree(a_wait_vrise_tmr); + kfree(a_aidl_bdis_tmr); + kfree(b_se0_srp_tmr); + kfree(b_srp_init_tmr); +} + +/* The timeout callback function to set time out bit */ +static void xusbps_otg_timer_fn(unsigned long indicator) +{ + struct xusbps_otg *xotg = the_transceiver; + + *(int *)indicator = 1; + + dev_dbg(xotg->dev, "kernel timer - timeout\n"); + + xusbps_update_transceiver(); +} + +/* kernel timer used instead of HW based interrupt */ +static void xusbps_otg_add_ktimer(enum xusbps_otg_timer_type timers) +{ + struct xusbps_otg *xotg = the_transceiver; + unsigned long j = jiffies; + unsigned long data, time; + + switch (timers) { + case TA_WAIT_VRISE_TMR: + xotg->hsm.a_wait_vrise_tmout = 0; + data = (unsigned long)&xotg->hsm.a_wait_vrise_tmout; + time = TA_WAIT_VRISE; + break; + case TA_WAIT_BCON_TMR: + xotg->hsm.a_wait_bcon_tmout = 0; + data = (unsigned long)&xotg->hsm.a_wait_bcon_tmout; + time = TA_WAIT_BCON; + break; + case TA_AIDL_BDIS_TMR: + xotg->hsm.a_aidl_bdis_tmout = 0; + data = (unsigned long)&xotg->hsm.a_aidl_bdis_tmout; + time = TA_AIDL_BDIS; + break; + case TB_ASE0_BRST_TMR: + xotg->hsm.b_ase0_brst_tmout = 0; + data = (unsigned long)&xotg->hsm.b_ase0_brst_tmout; + time = TB_ASE0_BRST; + break; + case TB_SRP_INIT_TMR: + xotg->hsm.b_srp_init_tmout = 0; + data = (unsigned long)&xotg->hsm.b_srp_init_tmout; + time = TB_SRP_INIT; + break; + case TB_SRP_FAIL_TMR: + xotg->hsm.b_srp_fail_tmout = 0; + data = (unsigned long)&xotg->hsm.b_srp_fail_tmout; + time = TB_SRP_FAIL; + break; + case TB_BUS_SUSPEND_TMR: + xotg->hsm.b_bus_suspend_tmout = 0; + data = (unsigned long)&xotg->hsm.b_bus_suspend_tmout; + time = TB_BUS_SUSPEND; + break; + default: + dev_dbg(xotg->dev, "unkown timer, cannot enable it\n"); + return; + } + + xotg->hsm_timer.data = data; + xotg->hsm_timer.function = xusbps_otg_timer_fn; + xotg->hsm_timer.expires = j + time * HZ / 1000; /* milliseconds */ + + add_timer(&xotg->hsm_timer); + + dev_dbg(xotg->dev, "add timer successfully\n"); +} + +/* Add timer to timer list */ +static void xusbps_otg_add_timer(void *gtimer) +{ + struct xusbps_otg *xotg = the_transceiver; + struct xusbps_otg_timer *timer = (struct xusbps_otg_timer *)gtimer; + struct xusbps_otg_timer *tmp_timer; + u32 val32; + + /* Check if the timer is already in the active list, + * if so update timer count + */ + list_for_each_entry(tmp_timer, &active_timers, list) + if (tmp_timer == timer) { + timer->count = timer->expires; + return; + } + timer->count = timer->expires; + + if (list_empty(&active_timers)) { + val32 = readl(xotg->base + CI_OTGSC); + writel(val32 | OTGSC_1MSE, xotg->base + CI_OTGSC); + } + + list_add_tail(&timer->list, &active_timers); +} + +/* Remove timer from the timer list; clear timeout status */ +static void xusbps_otg_del_timer(void *gtimer) +{ + struct xusbps_otg *xotg = the_transceiver; + struct xusbps_otg_timer *timer = (struct xusbps_otg_timer *)gtimer; + struct xusbps_otg_timer *tmp_timer, *del_tmp; + u32 val32; + + list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) + if (tmp_timer == timer) + list_del(&timer->list); + + if (list_empty(&active_timers)) { + val32 = readl(xotg->base + CI_OTGSC); + writel(val32 & ~OTGSC_1MSE, xotg->base + CI_OTGSC); + } +} + +/* Reduce timer count by 1, and find timeout conditions.*/ +static int xusbps_otg_tick_timer(u32 *int_sts) +{ + struct xusbps_otg *xotg = the_transceiver; + struct xusbps_otg_timer *tmp_timer, *del_tmp; + int expired = 0; + + list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) { + tmp_timer->count--; + /* check if timer expires */ + if (!tmp_timer->count) { + list_del(&tmp_timer->list); + tmp_timer->function(tmp_timer->data); + expired = 1; + } + } + + if (list_empty(&active_timers)) { + dev_dbg(xotg->dev, "tick timer: disable 1ms int\n"); + *int_sts = *int_sts & ~OTGSC_1MSE; + } + return expired; +} + +static void reset_otg(void) +{ + struct xusbps_otg *xotg = the_transceiver; + int delay_time = 1000; + u32 val; + + dev_dbg(xotg->dev, "reseting OTG controller ...\n"); + val = readl(xotg->base + CI_USBCMD); + writel(val | USBCMD_RST, xotg->base + CI_USBCMD); + do { + udelay(100); + if (!delay_time--) + dev_dbg(xotg->dev, "reset timeout\n"); + val = readl(xotg->base + CI_USBCMD); + val &= USBCMD_RST; + } while (val != 0); + dev_dbg(xotg->dev, "reset done.\n"); +} + +static void set_host_mode(void) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val; + + reset_otg(); + val = readl(xotg->base + CI_USBMODE); + val = (val & (~USBMODE_CM)) | USBMODE_HOST; + writel(val, xotg->base + CI_USBMODE); +} + +static void set_client_mode(void) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val; + + reset_otg(); + val = readl(xotg->base + CI_USBMODE); + val = (val & (~USBMODE_CM)) | USBMODE_DEVICE; + writel(val, xotg->base + CI_USBMODE); +} + +static void init_hsm(void) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val32; + + /* read OTGSC after reset */ + val32 = readl(xotg->base + CI_OTGSC); + + /* set init state */ + if (val32 & OTGSC_ID) { + xotg->hsm.id = 1; + xotg->otg.otg->default_a = 0; + set_client_mode(); + xotg->otg.state = OTG_STATE_B_IDLE; + } else { + xotg->hsm.id = 0; + xotg->otg.otg->default_a = 1; + set_host_mode(); + xotg->otg.state = OTG_STATE_A_IDLE; + } + + /* set session indicator */ + if (!xotg->otg.otg->default_a) { + if (val32 & OTGSC_BSE) + xotg->hsm.b_sess_end = 1; + if (val32 & OTGSC_BSV) + xotg->hsm.b_sess_vld = 1; + } else { + if (val32 & OTGSC_ASV) + xotg->hsm.a_sess_vld = 1; + if (val32 & OTGSC_AVV) + xotg->hsm.a_vbus_vld = 1; + } + + /* defautly power the bus */ + xotg->hsm.a_bus_req = 0; + xotg->hsm.a_bus_drop = 0; + /* defautly don't request bus as B device */ + xotg->hsm.b_bus_req = 0; + /* no system error */ + xotg->hsm.a_clr_err = 0; + + xusbps_otg_phy_low_power_wait(1); +} + +#ifdef CONFIG_PM_SLEEP +static void update_hsm(void) +{ + struct xusbps_otg *xotg = the_transceiver; + u32 val32; + + /* read OTGSC */ + val32 = readl(xotg->base + CI_OTGSC); + + xotg->hsm.id = !!(val32 & OTGSC_ID); + if (!xotg->otg.otg->default_a) { + xotg->hsm.b_sess_end = !!(val32 & OTGSC_BSE); + xotg->hsm.b_sess_vld = !!(val32 & OTGSC_BSV); + } else { + xotg->hsm.a_sess_vld = !!(val32 & OTGSC_ASV); + xotg->hsm.a_vbus_vld = !!(val32 & OTGSC_AVV); + } +} +#endif + +static irqreturn_t otg_dummy_irq(int irq, void *_dev) +{ + struct xusbps_otg *xotg = the_transceiver; + void __iomem *reg_base = _dev; + u32 val; + u32 int_mask = 0; + + val = readl(reg_base + CI_USBMODE); + if ((val & USBMODE_CM) != USBMODE_DEVICE) + return IRQ_NONE; + + val = readl(reg_base + CI_USBSTS); + int_mask = val & INTR_DUMMY_MASK; + + if (int_mask == 0) + return IRQ_NONE; + + /* Clear interrupts */ + writel(int_mask, reg_base + CI_USBSTS); + + /* clear hsm.b_conn here since host driver can't detect it + * otg_dummy_irq called means B-disconnect happened. + */ + if (xotg->hsm.b_conn) { + xotg->hsm.b_conn = 0; + if (spin_trylock(&xotg->wq_lock)) { + xusbps_update_transceiver(); + spin_unlock(&xotg->wq_lock); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t otg_irq(int irq, void *_dev) +{ + struct xusbps_otg *xotg = _dev; + u32 int_sts, int_en; + u32 int_mask = 0; + int flag = 0; + unsigned long flags; + + spin_lock_irqsave(&xotg->lock, flags); + int_sts = readl(xotg->base + CI_OTGSC); + int_en = (int_sts & OTGSC_INTEN_MASK) >> 8; + int_mask = int_sts & int_en; + + if (int_mask == 0) { + spin_unlock_irqrestore(&xotg->lock, flags); + return IRQ_NONE; + } + + writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask, + xotg->base + CI_OTGSC); + if (int_mask & OTGSC_IDIS) { + dev_dbg(xotg->dev, "%s: id change int\n", __func__); + xotg->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0; + dev_dbg(xotg->dev, "id = %d\n", xotg->hsm.id); + flag = 1; + } + if (int_mask & OTGSC_DPIS) { + dev_dbg(xotg->dev, "%s: data pulse int\n", __func__); + if (xotg->otg.otg->default_a) + xotg->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0; + dev_dbg(xotg->dev, "data pulse = %d\n", xotg->hsm.a_srp_det); + flag = 1; + } + if (int_mask & OTGSC_BSEIS) { + dev_dbg(xotg->dev, "%s: b session end int\n", __func__); + if (!xotg->otg.otg->default_a) + xotg->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0; + dev_dbg(xotg->dev, "b_sess_end = %d\n", xotg->hsm.b_sess_end); + flag = 1; + } + if (int_mask & OTGSC_BSVIS) { + dev_dbg(xotg->dev, "%s: b session valid int\n", __func__); + if (!xotg->otg.otg->default_a) + xotg->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0; + dev_dbg(xotg->dev, "b_sess_vld = %d\n", xotg->hsm.b_sess_vld); + flag = 1; + } + if (int_mask & OTGSC_ASVIS) { + dev_dbg(xotg->dev, "%s: a session valid int\n", __func__); + if (xotg->otg.otg->default_a) + xotg->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0; + dev_dbg(xotg->dev, "a_sess_vld = %d\n", xotg->hsm.a_sess_vld); + flag = 1; + } + if (int_mask & OTGSC_AVVIS) { + dev_dbg(xotg->dev, "%s: a vbus valid int\n", __func__); + if (xotg->otg.otg->default_a) + xotg->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0; + dev_dbg(xotg->dev, "a_vbus_vld = %d\n", xotg->hsm.a_vbus_vld); + flag = 1; + } + + if (int_mask & OTGSC_1MSS) { + /* need to schedule otg_work if any timer is expired */ + if (xusbps_otg_tick_timer(&int_sts)) + flag = 1; + } + + if (flag) + xusbps_update_transceiver(); + + spin_unlock_irqrestore(&xotg->lock, flags); + return IRQ_HANDLED; +} + +/** + * xotg_usbdev_notify - Notifier function called by usb core. + * @self: Pointer to notifier_block structure + * @action: action which caused the notifier function call. + * @dev: Pointer to the usb device structure. + * + * This function is a call back function used by usb core to notify + * device attach/detach events. This is used by OTG state machine. + * + * returns: Always returns NOTIFY_OK. + **/ +static int xotg_usbdev_notify(struct notifier_block *self, + unsigned long action, void *dev) +{ + struct xusbps_otg *xotg = the_transceiver; + struct usb_phy *otg = &xotg->otg; + unsigned long otg_port; + struct usb_device *udev_otg = NULL; + struct usb_device *udev; + u32 flag; + + udev = (struct usb_device *)dev; + + if (!otg->otg->host) + return NOTIFY_OK; + + otg_port = otg->otg->host->otg_port; + + if (otg->otg->host->root_hub) + udev_otg = usb_hub_find_child(otg->otg->host->root_hub, + otg_port - 1); + + /* Not otg device notification */ + if (udev != udev_otg) + return NOTIFY_OK; + + switch (action) { + case USB_DEVICE_ADD: + if (xotg->otg.otg->default_a == 1) + xotg->hsm.b_conn = 1; + else + xotg->hsm.a_conn = 1; + flag = 1; + break; + case USB_DEVICE_REMOVE: + if (xotg->otg.otg->default_a == 1) + xotg->hsm.b_conn = 0; + else + xotg->hsm.a_conn = 0; + flag = 1; + break; + } + if (flag) + xusbps_update_transceiver(); + + return NOTIFY_OK; +} + +static void xusbps_otg_work(struct work_struct *work) +{ + struct xusbps_otg *xotg; + int retval; + + xotg = container_of(work, struct xusbps_otg, work); + + dev_dbg(xotg->dev, "%s: old state = %s\n", __func__, + usb_otg_state_string(xotg->otg.state)); + + switch (xotg->otg.state) { + case OTG_STATE_UNDEFINED: + case OTG_STATE_B_IDLE: + if (!xotg->hsm.id) { + xusbps_otg_del_timer(b_srp_init_tmr); + del_timer_sync(&xotg->hsm_timer); + + xotg->otg.otg->default_a = 1; + xotg->hsm.a_srp_det = 0; + + xusbps_otg_chrg_vbus(0); + set_host_mode(); + xusbps_otg_phy_low_power(1); + + xotg->otg.state = OTG_STATE_A_IDLE; + xusbps_update_transceiver(); + } else if (xotg->hsm.b_sess_vld) { + xusbps_otg_del_timer(b_srp_init_tmr); + del_timer_sync(&xotg->hsm_timer); + xotg->hsm.b_bus_req = 0; + xotg->hsm.b_sess_end = 0; + xotg->hsm.a_bus_suspend = 0; + xusbps_otg_chrg_vbus(0); + + if (xotg->start_peripheral) { + xotg->start_peripheral(&xotg->otg); + xotg->otg.state = OTG_STATE_B_PERIPHERAL; + } else + dev_dbg(xotg->dev, + "client driver not loaded\n"); + } else if (xotg->hsm.b_srp_init_tmout) { + xotg->hsm.b_srp_init_tmout = 0; + dev_warn(xotg->dev, "SRP init timeout\n"); + } else if (xotg->hsm.b_srp_fail_tmout) { + xotg->hsm.b_srp_fail_tmout = 0; + xotg->hsm.b_bus_req = 0; + + /* No silence failure */ + xusbps_otg_msg(6); + dev_warn(xotg->dev, "SRP failed\n"); + } else if (xotg->hsm.b_bus_req && xotg->hsm.b_sess_end) { + del_timer_sync(&xotg->hsm_timer); + /* workaround for b_se0_srp detection */ + retval = xusbps_otg_check_se0_srp(0); + if (retval) { + xotg->hsm.b_bus_req = 0; + dev_dbg(xotg->dev, "LS isn't SE0, try later\n"); + } else { + /* clear the PHCD before start srp */ + xusbps_otg_phy_low_power(0); + + /* Start SRP */ + xusbps_otg_add_timer(b_srp_init_tmr); + xotg->otg.otg->start_srp(xotg->otg.otg); + xusbps_otg_del_timer(b_srp_init_tmr); + xusbps_otg_add_ktimer(TB_SRP_FAIL_TMR); + + /* reset PHY low power mode here */ + xusbps_otg_phy_low_power_wait(1); + } + } + break; + case OTG_STATE_B_SRP_INIT: + if (!xotg->hsm.id) { + xotg->otg.otg->default_a = 1; + xotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xusbps_otg_chrg_vbus(0); + set_host_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_A_IDLE; + xusbps_update_transceiver(); + } else if (xotg->hsm.b_sess_vld) { + xusbps_otg_chrg_vbus(0); + if (xotg->start_peripheral) { + xotg->start_peripheral(&xotg->otg); + xotg->otg.state = OTG_STATE_B_PERIPHERAL; + } else + dev_dbg(xotg->dev, + "client driver not loaded\n"); + } + break; + case OTG_STATE_B_PERIPHERAL: + if (!xotg->hsm.id) { + xotg->otg.otg->default_a = 1; + xotg->hsm.a_srp_det = 0; + + xusbps_otg_chrg_vbus(0); + + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver has been removed.\n"); + + set_host_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_A_IDLE; + xusbps_update_transceiver(); + } else if (!xotg->hsm.b_sess_vld) { + xotg->hsm.b_hnp_enable = 0; + xotg->hsm.b_bus_req = 0; + + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver has been removed.\n"); + + xotg->otg.state = OTG_STATE_B_IDLE; + } else if (xotg->hsm.b_bus_req && xotg->otg.otg->gadget && + xotg->otg.otg->gadget->b_hnp_enable && + xotg->hsm.a_bus_suspend) { + dev_warn(xotg->dev, "HNP detected\n"); + + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver has been removed.\n"); + + xusbps_otg_HAAR(1); + xotg->hsm.a_conn = 0; + + xotg->otg.state = OTG_STATE_B_WAIT_ACON; + if (xotg->start_host) { + xotg->start_host(&xotg->otg); + } else + dev_dbg(xotg->dev, + "host driver not loaded.\n"); + + xotg->hsm.a_bus_resume = 0; + xusbps_otg_add_ktimer(TB_ASE0_BRST_TMR); + } + break; + + case OTG_STATE_B_WAIT_ACON: + if (!xotg->hsm.id) { + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&xotg->hsm_timer); + + xotg->otg.otg->default_a = 1; + xotg->hsm.a_srp_det = 0; + + xusbps_otg_chrg_vbus(0); + + xusbps_otg_HAAR(0); + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + set_host_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_A_IDLE; + xusbps_update_transceiver(); + } else if (!xotg->hsm.b_sess_vld) { + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&xotg->hsm_timer); + + xotg->hsm.b_hnp_enable = 0; + xotg->hsm.b_bus_req = 0; + + xusbps_otg_chrg_vbus(0); + xusbps_otg_HAAR(0); + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + set_client_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_B_IDLE; + } else if (xotg->hsm.a_conn) { + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&xotg->hsm_timer); + + xusbps_otg_HAAR(0); + xotg->otg.state = OTG_STATE_B_HOST; + xusbps_update_transceiver(); + } else if (xotg->hsm.a_bus_resume || + xotg->hsm.b_ase0_brst_tmout) { + dev_warn(xotg->dev, "A device connect failed\n"); + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&xotg->hsm_timer); + + xusbps_otg_HAAR(0); + xusbps_otg_msg(7); + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + xotg->hsm.a_bus_suspend = 0; + xotg->hsm.b_bus_req = 0; + xotg->otg.state = OTG_STATE_B_PERIPHERAL; + if (xotg->start_peripheral) + xotg->start_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver not loaded.\n"); + } + break; + + case OTG_STATE_B_HOST: + if (!xotg->hsm.id) { + xotg->otg.otg->default_a = 1; + xotg->hsm.a_srp_det = 0; + + xusbps_otg_chrg_vbus(0); + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + set_host_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_A_IDLE; + xusbps_update_transceiver(); + } else if (!xotg->hsm.b_sess_vld) { + xotg->hsm.b_hnp_enable = 0; + xotg->hsm.b_bus_req = 0; + + xusbps_otg_chrg_vbus(0); + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + set_client_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_B_IDLE; + } else if ((!xotg->hsm.b_bus_req) || + (!xotg->hsm.a_conn)) { + xotg->hsm.b_bus_req = 0; + xusbps_otg_loc_sof(0); + + /* Fix: The kernel crash in usb_port_suspend + during HNP */ + msleep(20); + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + xotg->hsm.a_bus_suspend = 0; + xotg->otg.state = OTG_STATE_B_PERIPHERAL; + if (xotg->start_peripheral) + xotg->start_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver not loaded.\n"); + } + break; + + case OTG_STATE_A_IDLE: + xotg->otg.otg->default_a = 1; + if (xotg->hsm.id) { + xotg->otg.otg->default_a = 0; + xotg->hsm.b_bus_req = 0; + xotg->hsm.vbus_srp_up = 0; + + xusbps_otg_chrg_vbus(0); + set_client_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_B_IDLE; + xusbps_update_transceiver(); + } else if (!xotg->hsm.a_bus_drop && + (xotg->hsm.a_srp_det || xotg->hsm.a_bus_req)) { + dev_warn(xotg->dev, + "SRP detected or User has requested for the Bus\n"); + xusbps_otg_phy_low_power(0); + + /* Turn on VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, true); + + xotg->hsm.vbus_srp_up = 0; + xotg->hsm.a_wait_vrise_tmout = 0; + xusbps_otg_add_timer(a_wait_vrise_tmr); + xotg->otg.state = OTG_STATE_A_WAIT_VRISE; + xusbps_update_transceiver(); + } else if (!xotg->hsm.a_bus_drop && xotg->hsm.a_sess_vld) { + xotg->hsm.vbus_srp_up = 1; + } else if (!xotg->hsm.a_sess_vld && xotg->hsm.vbus_srp_up) { + msleep(10); + xusbps_otg_phy_low_power(0); + + /* Turn on VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, true); + xotg->hsm.a_srp_det = 1; + xotg->hsm.vbus_srp_up = 0; + xotg->hsm.a_wait_vrise_tmout = 0; + xusbps_otg_add_timer(a_wait_vrise_tmr); + xotg->otg.state = OTG_STATE_A_WAIT_VRISE; + xusbps_update_transceiver(); + } else if (!xotg->hsm.a_sess_vld && + !xotg->hsm.vbus_srp_up) { + xusbps_otg_phy_low_power(1); + } + break; + case OTG_STATE_A_WAIT_VRISE: + if (xotg->hsm.id) { + xusbps_otg_del_timer(a_wait_vrise_tmr); + xotg->hsm.b_bus_req = 0; + xotg->otg.otg->default_a = 0; + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + set_client_mode(); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_B_IDLE; + } else if (xotg->hsm.a_vbus_vld) { + xusbps_otg_del_timer(a_wait_vrise_tmr); + xotg->hsm.b_conn = 0; + if (xotg->start_host) + xotg->start_host(&xotg->otg); + else { + dev_dbg(xotg->dev, "host driver not loaded.\n"); + break; + } + xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR); + xotg->otg.state = OTG_STATE_A_WAIT_BCON; + } else if (xotg->hsm.a_wait_vrise_tmout) { + xotg->hsm.b_conn = 0; + if (xotg->hsm.a_vbus_vld) { + if (xotg->start_host) + xotg->start_host(&xotg->otg); + else { + dev_dbg(xotg->dev, + "host driver not loaded.\n"); + break; + } + xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR); + xotg->otg.state = OTG_STATE_A_WAIT_BCON; + } else { + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_A_VBUS_ERR; + } + } + break; + case OTG_STATE_A_WAIT_BCON: + if (xotg->hsm.id) { + /* delete hsm timer for a_wait_bcon_tmr */ + del_timer_sync(&xotg->hsm_timer); + + xotg->otg.otg->default_a = 0; + xotg->hsm.b_bus_req = 0; + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + set_client_mode(); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_B_IDLE; + xusbps_update_transceiver(); + } else if (!xotg->hsm.a_vbus_vld) { + /* delete hsm timer for a_wait_bcon_tmr */ + del_timer_sync(&xotg->hsm_timer); + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (xotg->hsm.a_bus_drop || + (xotg->hsm.a_wait_bcon_tmout && + !xotg->hsm.a_bus_req)) { + dev_warn(xotg->dev, "B connect timeout\n"); + /* delete hsm timer for a_wait_bcon_tmr */ + del_timer_sync(&xotg->hsm_timer); + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (xotg->hsm.b_conn) { + /* delete hsm timer for a_wait_bcon_tmr */ + del_timer_sync(&xotg->hsm_timer); + + xotg->hsm.a_suspend_req = 0; + /* Make it zero as it should not be used by driver */ + xotg->hsm.a_bus_req = 0; + xotg->hsm.a_srp_det = 0; + xotg->otg.state = OTG_STATE_A_HOST; + } + break; + case OTG_STATE_A_HOST: + if (xotg->hsm.id) { + xotg->otg.otg->default_a = 0; + xotg->hsm.b_bus_req = 0; + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + set_client_mode(); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_B_IDLE; + xusbps_update_transceiver(); + } else if (xotg->hsm.a_bus_drop || + (xotg->otg.otg->host && + !xotg->otg.otg->host->b_hnp_enable && + !xotg->hsm.a_bus_req)) { + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (!xotg->hsm.a_vbus_vld) { + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (xotg->otg.otg->host && + xotg->otg.otg->host->b_hnp_enable && + (!xotg->hsm.a_bus_req || + xotg->hsm.a_suspend_req)) { + /* Set HABA to enable hardware assistance to signal + * A-connect after receiver B-disconnect. Hardware + * will then set client mode and enable URE, SLE and + * PCE after the assistance. otg_dummy_irq is used to + * clean these ints when client driver is not resumed. + */ + if (request_irq(xotg->irq, otg_dummy_irq, IRQF_SHARED, + driver_name, xotg->base) != 0) { + dev_dbg(xotg->dev, + "request interrupt %d failed\n", + xotg->irq); + } + /* set HABA */ + xusbps_otg_HABA(1); + xotg->hsm.b_bus_resume = 0; + xotg->hsm.a_aidl_bdis_tmout = 0; + xusbps_otg_loc_sof(0); + /* clear PHCD to enable HW timer */ + xusbps_otg_phy_low_power(0); + xusbps_otg_add_timer(a_aidl_bdis_tmr); + xotg->otg.state = OTG_STATE_A_SUSPEND; + } else if (!xotg->hsm.b_conn || !xotg->hsm.a_bus_req) { + xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR); + xotg->otg.state = OTG_STATE_A_WAIT_BCON; + } + break; + case OTG_STATE_A_SUSPEND: + if (xotg->hsm.id) { + xusbps_otg_del_timer(a_aidl_bdis_tmr); + xusbps_otg_HABA(0); + free_irq(xotg->irq, xotg->base); + xotg->otg.otg->default_a = 0; + xotg->hsm.b_bus_req = 0; + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + set_client_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_B_IDLE; + xusbps_update_transceiver(); + } else if (xotg->hsm.a_bus_req || + xotg->hsm.b_bus_resume) { + xusbps_otg_del_timer(a_aidl_bdis_tmr); + xusbps_otg_HABA(0); + free_irq(xotg->irq, xotg->base); + xotg->hsm.a_suspend_req = 0; + xusbps_otg_loc_sof(1); + xotg->otg.state = OTG_STATE_A_HOST; + } else if (xotg->hsm.a_aidl_bdis_tmout || + xotg->hsm.a_bus_drop) { + dev_warn(xotg->dev, "B disconnect timeout\n"); + xusbps_otg_del_timer(a_aidl_bdis_tmr); + xusbps_otg_HABA(0); + free_irq(xotg->irq, xotg->base); + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (!xotg->hsm.b_conn && xotg->otg.otg->host && + xotg->otg.otg->host->b_hnp_enable) { + xusbps_otg_del_timer(a_aidl_bdis_tmr); + xusbps_otg_HABA(0); + free_irq(xotg->irq, xotg->base); + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + xotg->hsm.b_bus_suspend = 0; + xotg->hsm.b_bus_suspend_vld = 0; + + xotg->otg.state = OTG_STATE_A_PERIPHERAL; + /* msleep(200); */ + if (xotg->start_peripheral) + xotg->start_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver not loaded.\n"); + xusbps_otg_add_ktimer(TB_BUS_SUSPEND_TMR); + break; + } else if (!xotg->hsm.a_vbus_vld) { + xusbps_otg_del_timer(a_aidl_bdis_tmr); + xusbps_otg_HABA(0); + free_irq(xotg->irq, xotg->base); + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_A_VBUS_ERR; + } + break; + case OTG_STATE_A_PERIPHERAL: + if (xotg->hsm.id) { + /* delete hsm timer for b_bus_suspend_tmr */ + del_timer_sync(&xotg->hsm_timer); + xotg->otg.otg->default_a = 0; + xotg->hsm.b_bus_req = 0; + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + set_client_mode(); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_B_IDLE; + xusbps_update_transceiver(); + } else if (!xotg->hsm.a_vbus_vld) { + /* delete hsm timer for b_bus_suspend_tmr */ + del_timer_sync(&xotg->hsm_timer); + + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xusbps_otg_phy_low_power_wait(1); + xotg->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (xotg->hsm.a_bus_drop) { + /* delete hsm timer for b_bus_suspend_tmr */ + del_timer_sync(&xotg->hsm_timer); + + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver has been removed.\n"); + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (xotg->hsm.b_bus_suspend) { + dev_warn(xotg->dev, "HNP detected\n"); + /* delete hsm timer for b_bus_suspend_tmr */ + del_timer_sync(&xotg->hsm_timer); + + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver has been removed.\n"); + + xotg->otg.state = OTG_STATE_A_WAIT_BCON; + if (xotg->start_host) + xotg->start_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver not loaded.\n"); + xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR); + } else if (xotg->hsm.b_bus_suspend_tmout) { + u32 val; + val = readl(xotg->base + CI_PORTSC1); + if (!(val & PORTSC_SUSP)) + break; + + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(xotg->dev, + "client driver has been removed.\n"); + + xotg->otg.state = OTG_STATE_A_WAIT_BCON; + if (xotg->start_host) + xotg->start_host(&xotg->otg); + else + dev_dbg(xotg->dev, + "host driver not loaded.\n"); + xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR); + } + break; + case OTG_STATE_A_VBUS_ERR: + if (xotg->hsm.id) { + xotg->otg.otg->default_a = 0; + xotg->hsm.a_clr_err = 0; + xotg->hsm.a_srp_det = 0; + set_client_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_B_IDLE; + xusbps_update_transceiver(); + } else if (xotg->hsm.a_clr_err) { + xotg->hsm.a_clr_err = 0; + xotg->hsm.a_srp_det = 0; + reset_otg(); + init_hsm(); + if (xotg->otg.state == OTG_STATE_A_IDLE) + xusbps_update_transceiver(); + } else { + /* FW will clear PHCD bit when any VBus + * event detected. Reset PHCD to 1 again */ + xusbps_otg_phy_low_power(1); + } + break; + case OTG_STATE_A_WAIT_VFALL: + if (xotg->hsm.id) { + xotg->otg.otg->default_a = 0; + set_client_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_B_IDLE; + xusbps_update_transceiver(); + } else if (xotg->hsm.a_bus_req) { + + /* Turn on VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, true); + xotg->hsm.a_wait_vrise_tmout = 0; + xusbps_otg_add_timer(a_wait_vrise_tmr); + xotg->otg.state = OTG_STATE_A_WAIT_VRISE; + } else if (!xotg->hsm.a_sess_vld) { + xotg->hsm.a_srp_det = 0; + set_host_mode(); + xusbps_otg_phy_low_power(1); + xotg->otg.state = OTG_STATE_A_IDLE; + } + break; + default: + ; + } + + dev_dbg(xotg->dev, "%s: new state = %s\n", __func__, + usb_otg_state_string(xotg->otg.state)); +} + +static ssize_t +show_registers(struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct xusbps_otg *xotg = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, + "\n" + "USBCMD = 0x%08x\n" + "USBSTS = 0x%08x\n" + "USBINTR = 0x%08x\n" + "ASYNCLISTADDR = 0x%08x\n" + "PORTSC1 = 0x%08x\n" + "OTGSC = 0x%08x\n" + "USBMODE = 0x%08x\n", + readl(xotg->base + 0x140), + readl(xotg->base + 0x144), + readl(xotg->base + 0x148), + readl(xotg->base + 0x158), + readl(xotg->base + 0x184), + readl(xotg->base + 0x1a4), + readl(xotg->base + 0x1a8) + ); + size -= t; + next += t; + + return PAGE_SIZE - size; +} +static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); + +static ssize_t +show_hsm(struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct xusbps_otg *xotg = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + if (xotg->otg.otg->host) + xotg->hsm.a_set_b_hnp_en = xotg->otg.otg->host->b_hnp_enable; + + if (xotg->otg.otg->gadget) + xotg->hsm.b_hnp_enable = xotg->otg.otg->gadget->b_hnp_enable; + + t = scnprintf(next, size, + "\n" + "current state = %s\n" + "a_bus_resume = \t%d\n" + "a_bus_suspend = \t%d\n" + "a_conn = \t%d\n" + "a_sess_vld = \t%d\n" + "a_srp_det = \t%d\n" + "a_vbus_vld = \t%d\n" + "b_bus_resume = \t%d\n" + "b_bus_suspend = \t%d\n" + "b_conn = \t%d\n" + "b_se0_srp = \t%d\n" + "b_sess_end = \t%d\n" + "b_sess_vld = \t%d\n" + "id = \t%d\n" + "a_set_b_hnp_en = \t%d\n" + "b_srp_done = \t%d\n" + "b_hnp_enable = \t%d\n" + "a_wait_vrise_tmout = \t%d\n" + "a_wait_bcon_tmout = \t%d\n" + "a_aidl_bdis_tmout = \t%d\n" + "b_ase0_brst_tmout = \t%d\n" + "a_bus_drop = \t%d\n" + "a_bus_req = \t%d\n" + "a_clr_err = \t%d\n" + "a_suspend_req = \t%d\n" + "b_bus_req = \t%d\n" + "b_bus_suspend_tmout = \t%d\n" + "b_bus_suspend_vld = \t%d\n", + usb_otg_state_string(xotg->otg.state), + xotg->hsm.a_bus_resume, + xotg->hsm.a_bus_suspend, + xotg->hsm.a_conn, + xotg->hsm.a_sess_vld, + xotg->hsm.a_srp_det, + xotg->hsm.a_vbus_vld, + xotg->hsm.b_bus_resume, + xotg->hsm.b_bus_suspend, + xotg->hsm.b_conn, + xotg->hsm.b_se0_srp, + xotg->hsm.b_sess_end, + xotg->hsm.b_sess_vld, + xotg->hsm.id, + xotg->hsm.a_set_b_hnp_en, + xotg->hsm.b_srp_done, + xotg->hsm.b_hnp_enable, + xotg->hsm.a_wait_vrise_tmout, + xotg->hsm.a_wait_bcon_tmout, + xotg->hsm.a_aidl_bdis_tmout, + xotg->hsm.b_ase0_brst_tmout, + xotg->hsm.a_bus_drop, + xotg->hsm.a_bus_req, + xotg->hsm.a_clr_err, + xotg->hsm.a_suspend_req, + xotg->hsm.b_bus_req, + xotg->hsm.b_bus_suspend_tmout, + xotg->hsm.b_bus_suspend_vld + ); + size -= t; + next += t; + + return PAGE_SIZE - size; +} +static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL); + +static ssize_t +get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct xusbps_otg *xotg = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", xotg->hsm.a_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct xusbps_otg *xotg = the_transceiver; + + if (!xotg->otg.otg->default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '0') { + xotg->hsm.a_bus_req = 0; + dev_dbg(xotg->dev, "User request: a_bus_req = 0\n"); + } else if (buf[0] == '1') { + /* If a_bus_drop is TRUE, a_bus_req can't be set */ + if (xotg->hsm.a_bus_drop) + return -1; + xotg->hsm.a_bus_req = 1; + dev_dbg(xotg->dev, "User request: a_bus_req = 1\n"); + } + if (spin_trylock(&xotg->wq_lock)) { + xusbps_update_transceiver(); + spin_unlock(&xotg->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req); + +static ssize_t +get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct xusbps_otg *xotg = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", xotg->hsm.a_bus_drop); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_drop(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct xusbps_otg *xotg = the_transceiver; + + if (!xotg->otg.otg->default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '0') { + xotg->hsm.a_bus_drop = 0; + dev_dbg(xotg->dev, "User request: a_bus_drop = 0\n"); + } else if (buf[0] == '1') { + xotg->hsm.a_bus_drop = 1; + xotg->hsm.a_bus_req = 0; + dev_dbg(xotg->dev, "User request: a_bus_drop = 1\n"); + dev_dbg(xotg->dev, "User request: and a_bus_req = 0\n"); + } + if (spin_trylock(&xotg->wq_lock)) { + xusbps_update_transceiver(); + spin_unlock(&xotg->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, + set_a_bus_drop); + +static ssize_t +get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct xusbps_otg *xotg = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", xotg->hsm.b_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_b_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct xusbps_otg *xotg = the_transceiver; + + if (xotg->otg.otg->default_a) + return -1; + + if (count > 2) + return -1; + + if (buf[0] == '0') { + xotg->hsm.b_bus_req = 0; + dev_dbg(xotg->dev, "User request: b_bus_req = 0\n"); + } else if (buf[0] == '1') { + xotg->hsm.b_bus_req = 1; + dev_dbg(xotg->dev, "User request: b_bus_req = 1\n"); + } + if (spin_trylock(&xotg->wq_lock)) { + xusbps_update_transceiver(); + spin_unlock(&xotg->wq_lock); + } + return count; +} +static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req); + +static ssize_t +set_a_clr_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct xusbps_otg *xotg = the_transceiver; + + if (!xotg->otg.otg->default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '1') { + xotg->hsm.a_clr_err = 1; + dev_dbg(xotg->dev, "User request: a_clr_err = 1\n"); + } + if (spin_trylock(&xotg->wq_lock)) { + xusbps_update_transceiver(); + spin_unlock(&xotg->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); + +/** + * suspend_otg_device - suspend the otg device. + * + * @otg: Pointer to the otg transceiver structure. + * + * This function suspends usb devices connected to the otg port + * of the host controller. + * + * returns: 0 on success or error value on failure + **/ +static int suspend_otg_device(struct usb_phy *otg) +{ + struct xusbps_otg *xotg = the_transceiver; + unsigned long otg_port = otg->otg->host->otg_port; + struct usb_device *udev; + int err; + + udev = usb_hub_find_child(otg->otg->host->root_hub, otg_port - 1); + + if (udev) { + err = usb_port_suspend(udev, PMSG_SUSPEND); + if (err < 0) + dev_dbg(xotg->dev, "HNP fail, %d\n", err); + + /* Change the state of the usb device if HNP is successful */ + usb_set_device_state(udev, USB_STATE_NOTATTACHED); + } else { + err = -ENODEV; + dev_dbg(xotg->dev, "No device connected to roothub\n"); + } + return err; +} + +static ssize_t +do_hnp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct xusbps_otg *xotg = the_transceiver; + unsigned long ret; + + if (count > 2) + return -1; + + if (buf[0] == '1') { + if (xotg->otg.otg->default_a && xotg->otg.otg->host && + xotg->otg.otg->host->b_hnp_enable && + (xotg->otg.state == OTG_STATE_A_HOST)) { + ret = suspend_otg_device(&xotg->otg); + if (ret) + return -1; + } + + if (!xotg->otg.otg->default_a && xotg->otg.otg->host && + xotg->hsm.b_bus_req) { + ret = suspend_otg_device(&xotg->otg); + if (ret) + return -1; + } + } + return count; +} +static DEVICE_ATTR(do_hnp, S_IWUSR, NULL, do_hnp); + +static int xusbps_otg_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + + switch (event) { + case PRE_RATE_CHANGE: + /* if a rate change is announced we need to check whether we can + * maintain the current frequency by changing the clock + * dividers. + */ + /* fall through */ + case POST_RATE_CHANGE: + return NOTIFY_OK; + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +static struct attribute *inputs_attrs[] = { + &dev_attr_a_bus_req.attr, + &dev_attr_a_bus_drop.attr, + &dev_attr_b_bus_req.attr, + &dev_attr_a_clr_err.attr, + &dev_attr_do_hnp.attr, + NULL, +}; + +static struct attribute_group debug_dev_attr_group = { + .name = "inputs", + .attrs = inputs_attrs, +}; + +static int xusbps_otg_remove(struct platform_device *pdev) +{ + struct xusbps_otg *xotg = the_transceiver; + + if (xotg->qwork) { + flush_workqueue(xotg->qwork); + destroy_workqueue(xotg->qwork); + } + xusbps_otg_free_timers(); + + /* disable OTGSC interrupt as OTGSC doesn't change in reset */ + writel(0, xotg->base + CI_OTGSC); + + usb_remove_phy(&xotg->otg); + sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group); + device_remove_file(&pdev->dev, &dev_attr_hsm); + device_remove_file(&pdev->dev, &dev_attr_registers); + clk_notifier_unregister(xotg->clk, &xotg->clk_rate_change_nb); + clk_disable_unprepare(xotg->clk); + + return 0; +} + +static int xusbps_otg_probe(struct platform_device *pdev) +{ + int retval; + u32 val32; + struct xusbps_otg *xotg; + char qname[] = "xusbps_otg_queue"; + struct xusbps_usb2_platform_data *pdata; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -ENODEV; + + dev_dbg(&pdev->dev, "\notg controller is detected.\n"); + + xotg = devm_kzalloc(&pdev->dev, sizeof(*xotg), GFP_KERNEL); + if (xotg == NULL) + return -ENOMEM; + + the_transceiver = xotg; + + /* Setup ulpi phy for OTG */ + xotg->ulpi = pdata->ulpi; + + xotg->otg.otg = devm_kzalloc(&pdev->dev, sizeof(*xotg->otg.otg), + GFP_KERNEL); + if (!xotg->otg.otg) + return -ENOMEM; + + xotg->base = pdata->regs; + xotg->irq = pdata->irq; + if (!xotg->base || !xotg->irq) { + retval = -ENODEV; + goto err; + } + + xotg->qwork = create_singlethread_workqueue(qname); + if (!xotg->qwork) { + dev_dbg(&pdev->dev, "cannot create workqueue %s\n", qname); + retval = -ENOMEM; + goto err; + } + INIT_WORK(&xotg->work, xusbps_otg_work); + + xotg->clk = pdata->clk; + retval = clk_prepare_enable(xotg->clk); + if (retval) { + dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + goto err; + } + + xotg->clk_rate_change_nb.notifier_call = xusbps_otg_clk_notifier_cb; + xotg->clk_rate_change_nb.next = NULL; + if (clk_notifier_register(xotg->clk, &xotg->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); + + /* OTG common part */ + xotg->dev = &pdev->dev; + xotg->otg.dev = xotg->dev; + xotg->otg.label = driver_name; + xotg->otg.otg->set_host = xusbps_otg_set_host; + xotg->otg.otg->set_peripheral = xusbps_otg_set_peripheral; + xotg->otg.set_power = xusbps_otg_set_power; + xotg->otg.otg->set_vbus = xusbps_otg_set_vbus; + xotg->otg.otg->start_srp = xusbps_otg_start_srp; + xotg->otg.otg->start_hnp = xusbps_otg_start_hnp; + xotg->otg.state = OTG_STATE_UNDEFINED; + + if (usb_add_phy(&xotg->otg, USB_PHY_TYPE_USB2)) { + dev_dbg(xotg->dev, "can't set transceiver\n"); + retval = -EBUSY; + goto err_out_clk_disable; + } + + pdata->otg = &xotg->otg; + reset_otg(); + init_hsm(); + + spin_lock_init(&xotg->lock); + spin_lock_init(&xotg->wq_lock); + INIT_LIST_HEAD(&active_timers); + retval = xusbps_otg_init_timers(&xotg->hsm); + if (retval) { + dev_dbg(&pdev->dev, "Failed to init timers\n"); + goto err_out_clk_disable; + } + + init_timer(&xotg->hsm_timer); + + xotg->xotg_notifier.notifier_call = xotg_usbdev_notify; + usb_register_notify((struct notifier_block *) + &xotg->xotg_notifier.notifier_call); + + retval = devm_request_irq(&pdev->dev, xotg->irq, otg_irq, IRQF_SHARED, + driver_name, xotg); + if (retval) { + dev_dbg(xotg->dev, "request interrupt %d failed\n", xotg->irq); + retval = -EBUSY; + goto err_out_clk_disable; + } + + /* enable OTGSC int */ + val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE | + OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU; + writel(val32, xotg->base + CI_OTGSC); + + retval = device_create_file(&pdev->dev, &dev_attr_registers); + if (retval < 0) { + dev_dbg(xotg->dev, + "Can't register sysfs attribute: %d\n", retval); + goto err_out_clk_disable; + } + + retval = device_create_file(&pdev->dev, &dev_attr_hsm); + if (retval < 0) { + dev_dbg(xotg->dev, "Can't hsm sysfs attribute: %d\n", retval); + goto err_out_clk_disable; + } + + retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group); + if (retval < 0) { + dev_dbg(xotg->dev, + "Can't register sysfs attr group: %d\n", retval); + goto err_out_clk_disable; + } + + if (xotg->otg.state == OTG_STATE_A_IDLE) + xusbps_update_transceiver(); + + return 0; + +err_out_clk_disable: + clk_notifier_unregister(xotg->clk, &xotg->clk_rate_change_nb); + clk_disable_unprepare(xotg->clk); +err: + xusbps_otg_remove(pdev); + + return retval; +} + +#ifdef CONFIG_PM_SLEEP +static void transceiver_suspend(struct platform_device *pdev) +{ + xusbps_otg_phy_low_power(1); +} + +static int xusbps_otg_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xusbps_otg *xotg = the_transceiver; + int ret = 0; + + /* Disbale OTG interrupts */ + xusbps_otg_intr(0); + + if (xotg->irq) + free_irq(xotg->irq, xotg); + + /* Prevent more otg_work */ + flush_workqueue(xotg->qwork); + destroy_workqueue(xotg->qwork); + xotg->qwork = NULL; + + /* start actions */ + switch (xotg->otg.state) { + case OTG_STATE_A_WAIT_VFALL: + xotg->otg.state = OTG_STATE_A_IDLE; + case OTG_STATE_A_IDLE: + case OTG_STATE_B_IDLE: + case OTG_STATE_A_VBUS_ERR: + transceiver_suspend(pdev); + break; + case OTG_STATE_A_WAIT_VRISE: + xusbps_otg_del_timer(a_wait_vrise_tmr); + xotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_WAIT_BCON: + del_timer_sync(&xotg->hsm_timer); + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(&pdev->dev, "host driver has been removed.\n"); + + xotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_HOST: + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(&pdev->dev, "host driver has been removed.\n"); + + xotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + + xotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_SUSPEND: + xusbps_otg_del_timer(a_aidl_bdis_tmr); + xusbps_otg_HABA(0); + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(xotg->dev, "host driver has been removed.\n"); + xotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_PERIPHERAL: + del_timer_sync(&xotg->hsm_timer); + + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(&pdev->dev, + "client driver has been removed.\n"); + xotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + xotg->otg.otg->set_vbus(xotg->otg.otg, false); + xotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_B_HOST: + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(&pdev->dev, "host driver has been removed.\n"); + xotg->hsm.b_bus_req = 0; + xotg->otg.state = OTG_STATE_B_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_B_PERIPHERAL: + if (xotg->stop_peripheral) + xotg->stop_peripheral(&xotg->otg); + else + dev_dbg(&pdev->dev, + "client driver has been removed.\n"); + xotg->otg.state = OTG_STATE_B_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_B_WAIT_ACON: + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&xotg->hsm_timer); + + xusbps_otg_HAAR(0); + + if (xotg->stop_host) + xotg->stop_host(&xotg->otg); + else + dev_dbg(&pdev->dev, "host driver has been removed.\n"); + xotg->hsm.b_bus_req = 0; + xotg->otg.state = OTG_STATE_B_IDLE; + transceiver_suspend(pdev); + break; + default: + dev_dbg(xotg->dev, "error state before suspend\n"); + break; + } + + if (!ret) + clk_disable(xotg->clk); + return ret; +} + +static void transceiver_resume(struct platform_device *pdev) +{ + /* Not used */ +} + +static int xusbps_otg_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xusbps_otg *xotg = the_transceiver; + int ret = 0; + + ret = clk_enable(xotg->clk); + if (ret) { + dev_err(&pdev->dev, "cannot enable clock. resume failed.\n"); + return ret; + } + + transceiver_resume(pdev); + + xotg->qwork = create_singlethread_workqueue("xusbps_otg_queue"); + if (!xotg->qwork) { + dev_dbg(&pdev->dev, "cannot create xusbps otg workqueuen"); + ret = -ENOMEM; + goto error; + } + + if (request_irq(xotg->irq, otg_irq, IRQF_SHARED, + driver_name, xotg) != 0) { + dev_dbg(&pdev->dev, "request interrupt %d failed\n", xotg->irq); + ret = -EBUSY; + goto error; + } + + /* enable OTG interrupts */ + xusbps_otg_intr(1); + + update_hsm(); + + xusbps_update_transceiver(); + + return ret; +error: + xusbps_otg_intr(0); + transceiver_suspend(pdev); + return ret; +} + +static const struct dev_pm_ops xusbps_otg_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xusbps_otg_suspend, xusbps_otg_resume) +}; +#define XUSBPS_OTG_PM (&xusbps_otg_dev_pm_ops) + +#else /* ! CONFIG_PM_SLEEP */ +#define XUSBPS_OTG_PM NULL +#endif /* ! CONFIG_PM_SLEEP */ + +#ifndef CONFIG_USB_XUSBPS_DR_OF +static struct platform_driver xusbps_otg_driver = { +#else +struct platform_driver xusbps_otg_driver = { +#endif + .probe = xusbps_otg_probe, + .remove = xusbps_otg_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .pm = XUSBPS_OTG_PM, + }, +}; + +#ifndef CONFIG_USB_XUSBPS_DR_OF +module_platform_driver(xusbps_otg_driver); +#endif + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx PS USB OTG driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); Index: linux-3.12.24-rt38-xilinx/drivers/video/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/video/Kconfig 2014-07-20 22:05:50.244066489 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/video/Kconfig 2014-07-20 22:06:38.366272564 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2469 @ Configuration re: surface address, size, and format must be provided through device tree, or plain old platform data. +source "drivers/video/xylon/Kconfig" source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" source "drivers/video/exynos/Kconfig" Index: linux-3.12.24-rt38-xilinx/drivers/video/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/video/Makefile 2014-07-20 22:05:50.243066505 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/video/Makefile 2014-07-20 22:06:38.377272383 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:153 @ obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o +obj-y += xylon/ # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o Index: linux-3.12.24-rt38-xilinx/drivers/video/xilinxfb.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/video/xilinxfb.c 2014-07-20 22:05:50.245066473 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/video/xilinxfb.c 2014-07-20 22:06:38.458271046 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:372 @ err_region: kfree(drvdata); - dev_set_drvdata(dev, NULL); return rc; } @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:406 @ #endif kfree(drvdata); - dev_set_drvdata(dev, NULL); return 0; } Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/Kconfig 2014-07-20 22:06:38.470270848 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ +source "drivers/video/xylon/xylonfb/Kconfig" Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/Makefile 2014-07-20 22:06:38.476270749 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ +obj-$(CONFIG_FB_XYLON) += xylonfb/ Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/logiclk.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/logiclk.c 2014-07-20 22:06:38.491270502 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver: + * pixel clock generation using logiCLK IP core + * + * Author: Xylon d.o.o. + * e-mail: goran.pantar@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/math64.h> +#include "logiclk.h" + + +#define FRAC_PRECISION 10 + +#define FVCO_MIN 800 +#define FVCO_MAX 1600 + +#define NUM_OF_MULT_STEPS 64 +#define NUM_OF_DIV_INPUT_STEPS 56 +#define NUM_OF_DIV_OUTPUT_STEPS 128 + +#define CLK_FB_OUT_DUTY 50000 +#define DIV_CLK_PHASE 0 + + +static inline u32 get_bits(u64 input, u32 msb, u32 lsb) +{ + return (input >> lsb) & ((1 << (msb-lsb+1)) - 1); +} + +static u32 round_frac(u32 decimal, u32 precision) +{ + u32 ret; + + if (decimal & (1 << (FRAC_PRECISION-precision-1))) + ret = decimal + (1 << (FRAC_PRECISION-precision-1)); + else + ret = decimal; + + return ret; +} + +static u32 pll_divider(u32 divide, u32 duty_cycle) +{ + u32 duty_cycle_fix; + u32 high_time; + u32 low_time; + u32 w_edge; + u32 no_count; + u32 temp; + + if (duty_cycle <= 0 || duty_cycle >= 100000) { + pr_err("%s: invalid duty_cycle %d", __func__, duty_cycle); + return -1; + } + duty_cycle_fix = (duty_cycle << FRAC_PRECISION) / 100000; + + if (divide == 1) { + high_time = 1; + w_edge = 0; + low_time = 1; + no_count = 1; + } else { + temp = round_frac(duty_cycle_fix * divide, 1); + high_time = get_bits(temp, FRAC_PRECISION+6, FRAC_PRECISION); + w_edge = get_bits(temp, FRAC_PRECISION-1, FRAC_PRECISION-1); + + if (high_time == 0) { + high_time = 1; + w_edge = 0; + } + if (high_time == divide) { + high_time = divide - 1; + w_edge = 1; + } + low_time = divide - high_time; + no_count = 0; + } + + return (((low_time & 0x3F) << 0) | + ((high_time & 0x3F) << 6) | + ((no_count & 0x01) << 12) | + ((w_edge & 0x01) << 13)); +} + +static u32 pll_phase(u32 divide, s32 phase) +{ + u32 phase_in_cycles; + u32 phase_fixed; + u32 mx; + u32 delay_time; + u32 phase_mux; + u32 temp; + + if ((phase < -360000) || (phase > 360000)) + return -1; + + if (phase < 0) + phase_fixed = ((phase + 360000) << FRAC_PRECISION) / 1000; + else + phase_fixed = (phase << FRAC_PRECISION) / 1000; + + phase_in_cycles = (phase_fixed * divide) / 360; + + temp = round_frac(phase_in_cycles, 3); + + mx = 0; + phase_mux = get_bits(temp, FRAC_PRECISION-1, FRAC_PRECISION-3); + delay_time = get_bits(temp, FRAC_PRECISION+5, FRAC_PRECISION); + + return ((delay_time & 0x3F) << 0) | + ((phase_mux & 0x07) << 6) | + ((mx & 0x03) << 9); +} + +static u64 pll_lock_lookup(u32 divide) +{ + u64 lookup[] = { + 0x31BE8FA401, + 0x31BE8FA401, + 0x423E8FA401, + 0x5AFE8FA401, + 0x73BE8FA401, + 0x8C7E8FA401, + 0x9CFE8FA401, + 0xB5BE8FA401, + 0xCE7E8FA401, + 0xE73E8FA401, + 0xFFF84FA401, + 0xFFF39FA401, + 0xFFEEEFA401, + 0xFFEBCFA401, + 0xFFE8AFA401, + 0xFFE71FA401, + 0xFFE3FFA401, + 0xFFE26FA401, + 0xFFE0DFA401, + 0xFFDF4FA401, + 0xFFDDBFA401, + 0xFFDC2FA401, + 0xFFDA9FA401, + 0xFFD90FA401, + 0xFFD90FA401, + 0xFFD77FA401, + 0xFFD5EFA401, + 0xFFD5EFA401, + 0xFFD45FA401, + 0xFFD45FA401, + 0xFFD2CFA401, + 0xFFD2CFA401, + 0xFFD2CFA401, + 0xFFD13FA401, + 0xFFD13FA401, + 0xFFD13FA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401, + 0xFFCFAFA401 + }; + return lookup[divide-1]; +} + +static u32 pll_filter_lookup(u32 divide, bool bw_low) +{ + u32 lookup_entry; + u32 lookup_low[] = { + 0x5F, + 0x57, + 0x7B, + 0x5B, + 0x6B, + 0x73, + 0x73, + 0x73, + 0x73, + 0x4B, + 0x4B, + 0x4B, + 0xB3, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x63, + 0x93, + 0x93, + 0x93, + 0x93, + 0x93, + 0x93, + 0x93, + 0x93, + 0x93, + 0x93, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3, + 0xA3 + }; + u32 lookup_high[] = { + 0x17C, + 0x3FC, + 0x3F4, + 0x3E4, + 0x3F8, + 0x3C4, + 0x3C4, + 0x3D8, + 0x3E8, + 0x3E8, + 0x3E8, + 0x3B0, + 0x3F0, + 0x3F0, + 0x3F0, + 0x3F0, + 0x3F0, + 0x3F0, + 0x3F0, + 0x3F0, + 0x3B0, + 0x3B0, + 0x3B0, + 0x3E8, + 0x370, + 0x308, + 0x370, + 0x370, + 0x3E8, + 0x3E8, + 0x3E8, + 0x1C8, + 0x330, + 0x330, + 0x3A8, + 0x188, + 0x188, + 0x188, + 0x1F0, + 0x188, + 0x110, + 0x110, + 0x110, + 0x110, + 0x110, + 0x110, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0, + 0x0E0 + }; + + if (bw_low) + lookup_entry = lookup_low[divide-1]; + else + lookup_entry = lookup_high[divide-1]; + + return lookup_entry; +} + +static u32 calc_pll_count(u32 divide, s32 phase, u32 duty_cycle) +{ + u32 div_calc; + u32 phase_calc; + u32 ret; + + div_calc = pll_divider(divide, duty_cycle); + phase_calc = pll_phase(divide, phase); + + ret = ((get_bits(div_calc, 11, 0) << 0) | + (get_bits(phase_calc, 8, 6) << 13) | + (get_bits(phase_calc, 5, 0) << 16) | + (get_bits(div_calc, 13, 12) << 22) | + (get_bits(phase_calc, 10, 9) << 24)); + + return ret; +} + +static void calc_pll_mult(u32 osc_clk_freq, u32 out_clk_freq, + u32 *p_mult, u32 *p_div_in) +{ + u32 freq_err = 0xFFFFFFFF; + u32 din; + u32 dout; + u32 mult; + u32 fvco; + u64 freq_err_new; + u64 freq_hz; + u32 remainder; + + *p_mult = 0; + *p_div_in = 0; + + for (din = 1; din <= NUM_OF_DIV_INPUT_STEPS; din++) { + for (mult = 2; mult <= NUM_OF_MULT_STEPS; mult++) { + for (dout = 1; dout <= NUM_OF_DIV_OUTPUT_STEPS; dout++) { + freq_hz = osc_clk_freq; + freq_hz *= mult; + freq_hz = div_u64_rem(freq_hz, din, &remainder); + fvco = (u32)(div_u64_rem(freq_hz, 1000000, &remainder)); + if ((fvco >= FVCO_MIN) && (fvco <= FVCO_MAX)) { + freq_hz = div_u64_rem(freq_hz, dout, &remainder); + if (((u64)out_clk_freq) >= freq_hz) + freq_err_new = ((u64)out_clk_freq) - freq_hz; + else + freq_err_new = freq_hz - ((u64)out_clk_freq); + if (freq_err_new < freq_err) { + freq_err = (u32)freq_err_new; + *p_mult = mult; + *p_div_in = din; + } + } + } + } + } +} + +static u32 calc_pll_div(u32 osc_clk_freq, u32 out_clk_freq, + u32 mult, u32 div_in) +{ + u32 div_out = 0; + u32 freq_err = 0xFFFFFFFF; + u32 dout; + u32 khz; + u32 freq_err_new; + + for (dout = 1; dout <= NUM_OF_DIV_OUTPUT_STEPS; dout++) { + khz = (osc_clk_freq / 1000 * mult) / (dout * div_in); + freq_err_new = abs((int)(out_clk_freq - (1000 * khz))); + if (freq_err_new < freq_err) { + freq_err = freq_err_new; + div_out = dout; + } + } + + return div_out; +} + +int logiclk_calc_regs(struct logiclk_freq_out *freq_out, + u32 c_osc_clk_freq_hz, u32 *regs_out) +{ + u32 clkout_phase = 0; + u32 clkfbout_phase = 0; + u32 clkout_duty = 50000; + u32 bandwith = 0; + u32 divclk_divide = 1; + u64 lock; + u32 clkout_divide[LOGICLK_OUTPUTS]; + u32 clkfbout_mult; + u32 clkout[LOGICLK_OUTPUTS]; + u32 divclk; + u32 clkfbout; + u32 digital_filt; + int i; + + calc_pll_mult(c_osc_clk_freq_hz, (u32)freq_out->freq_out_hz[0], + &clkfbout_mult, &divclk_divide); + if ((clkfbout_mult == 0) || (divclk_divide == 0)) + return -EINVAL; + + for (i = 0; i < LOGICLK_OUTPUTS; i++) + clkout_divide[i] = calc_pll_div(c_osc_clk_freq_hz, + freq_out->freq_out_hz[i], clkfbout_mult, divclk_divide); + + for (i = 0; i < LOGICLK_OUTPUTS; i++) + clkout[i] = calc_pll_count( + clkout_divide[i], clkout_phase, clkout_duty); + + divclk = calc_pll_count(divclk_divide, DIV_CLK_PHASE, CLK_FB_OUT_DUTY); + clkfbout = calc_pll_count(clkfbout_mult, clkfbout_phase, clkout_duty); + + digital_filt = pll_filter_lookup(clkfbout_mult-1, bandwith); + lock = pll_lock_lookup(clkfbout_mult-1); + + regs_out[0] = 0xFFFF; + for (i = 0; i < LOGICLK_OUTPUTS; i++) { + regs_out[1 + i*2 + 0] = get_bits(clkout[i], 15, 0); + regs_out[1 + i*2 + 1] = get_bits(clkout[i], 31, 16); + } + + /* DIVCLK[23:22] & DIVCLK[11:0] */ + regs_out[13] = (get_bits(divclk, 23, 22) << 12) | + (get_bits(divclk, 11, 0) << 0); + /* CLKFBOUT[15:0] */ + regs_out[14] = get_bits(clkfbout, 15, 0); + /* CLKFBOUT[31:16] */ + regs_out[15] = get_bits(clkfbout, 31, 16); + /* LOCK[29:20] */ + regs_out[16] = get_bits(lock, 29, 20); + /* LOCK[34:30] & LOCK[9:0] */ + regs_out[17] = (get_bits(lock, 34, 30) << 10) | + get_bits(lock, 9, 0); + /* LOCK[39:35] & S10_LOCK[19:10] */ + regs_out[18] = (get_bits(lock, 39, 35) << 10) | + get_bits(lock, 19, 10); + /* DIGITAL_FILT[9] & 00 & DIGITAL_FILT[8:7] & 00 & + DIGITAL_FILT[6] & 0000000 */ + regs_out[19] = (get_bits(digital_filt, 6, 6) << 8) | + (get_bits(digital_filt, 8, 7) << 11) | + (get_bits(digital_filt, 9, 9) << 15); + /* DIGITAL_FILT[5] & 00 & DIGITAL_FILT[4:3] & 00 & + DIGITAL_FILT[2:1] & 00 & DIGITAL_FILT[0] & 0000 */ + regs_out[20] = (get_bits(digital_filt, 0, 0) << 4) | + (get_bits(digital_filt, 2, 1) << 7) | + (get_bits(digital_filt, 4, 3) << 11) | + (get_bits(digital_filt, 5, 5) << 15); + +#ifdef LOGICLK_DUMP_REGS + for (i = 0; i < LOGICLK_REGS; i++) + pr_info("reg[%d]=0x%lx\n", i, regs_out[i]); +#endif + + return 0; +} Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/logiclk.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/logiclk.h 2014-07-20 22:06:38.497270403 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC pixel clock generation logiCLK IP core interface + * + * Author: Xylon d.o.o. + * e-mail: goran.pantar@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/types.h> + + +#define LOGICLK_REGS 21 +#define LOGICLK_OUTPUTS 6 +#define LOGICLK_RST_REG_OFF 0 +#define LOGICLK_PLL_REG_OFF 1 +#define LOGICLK_PLL_MANUAL_REG_OFF 3 +#define LOGICLK_PLL_RDY 0x01 +#define LOGICLK_PLL_EN 0x01 +#define LOGICLK_PLL_REG_EN 0x02 + + +struct logiclk_freq_out { + u32 freq_out_hz[LOGICLK_OUTPUTS]; +}; + +/* + Calculates the output register valuess depending on the + "freq_out" and "c_osc_clk_freq_hz" inputs. + Writes them to array of LOGICLK_REGS over "regs_out" pointer. +*/ +int logiclk_calc_regs(struct logiclk_freq_out *freq_out, + u32 c_osc_clk_freq_hz, u32 *regs_out); Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/logicvc.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/logicvc.h 2014-07-20 22:06:38.505270271 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC IP core v2.05c definitions + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __LOGICVC_H__ +#define __LOGICVC_H__ + +/* All logiCVC registers are 32 bit registers */ +/* All logiCVC registers are at 8 byte distance */ +#define LOGICVC_REG_DIST_USED 8 +/* R_HSY_FP */ +#define LOGICVC_SHSY_FP_ROFF (0 * LOGICVC_REG_DIST_USED) +/* R_HSY */ +#define LOGICVC_SHSY_ROFF (1 * LOGICVC_REG_DIST_USED) +/* R_HSY_BP */ +#define LOGICVC_SHSY_BP_ROFF (2 * LOGICVC_REG_DIST_USED) +/* R_HSY_RES */ +#define LOGICVC_SHSY_RES_ROFF (3 * LOGICVC_REG_DIST_USED) +/* R_VSY_FP */ +#define LOGICVC_SVSY_FP_ROFF (4 * LOGICVC_REG_DIST_USED) +/* R_VSY */ +#define LOGICVC_SVSY_ROFF (5 * LOGICVC_REG_DIST_USED) +/* R_VSY_BP */ +#define LOGICVC_SVSY_BP_ROFF (6 * LOGICVC_REG_DIST_USED) +/* R_VSY_RES */ +#define LOGICVC_SVSY_RES_ROFF (7 * LOGICVC_REG_DIST_USED) +/* R_CTRL */ +#define LOGICVC_SCTRL_ROFF (8 * LOGICVC_REG_DIST_USED) +/* R_DTYPE */ +#define LOGICVC_SDTYPE_ROFF (9 * LOGICVC_REG_DIST_USED) +/* R_BACKGROUND */ +#define LOGICVC_BACKCOL_ROFF (10 * LOGICVC_REG_DIST_USED) +/* R_DOUBLE_VBUFF */ +#define LOGICVC_DOUBLE_VBUFF_ROFF (11 * LOGICVC_REG_DIST_USED) +/* R_DOUBLE_CLUT */ +#define LOGICVC_DOUBLE_CLUT_ROFF (12 * LOGICVC_REG_DIST_USED) +/* R_INT_STAT */ +#define LOGICVC_INT_STAT_ROFF (13 * LOGICVC_REG_DIST_USED) +/* R_INT_MASK */ +#define LOGICVC_INT_MASK_ROFF (14 * LOGICVC_REG_DIST_USED) +/* R_PWRCTRL */ +#define LOGICVC_SPWRCTRL_ROFF (15 * LOGICVC_REG_DIST_USED) +/* R_IPVER */ +#define LOGICVC_IPVER_ROFF (18 * LOGICVC_REG_DIST_USED) + +/* logiCVC layer registers base and distance between the layers */ +/* distance between groups of layer registers */ +#define LOGICVC_LAYER_DISTANCE (16 * LOGICVC_REG_DIST_USED) +/* offset to the beginning of layer 0 registers */ +#define LOGICVC_LAYER0_BASE_ROFF (32 * LOGICVC_REG_DIST_USED) +/* offset to the beginning of layer 1 registers */ +#define LOGICVC_LAYER1_BASE_ROFF \ + (LOGICVC_LAYER0_BASE_ROFF + LOGICVC_LAYER_DISTANCE * 1) +/* offset to the beginning of layer 2 registers */ +#define LOGICVC_LAYER2_BASE_ROFF \ + (LOGICVC_LAYER0_BASE_ROFF + LOGICVC_LAYER_DISTANCE * 2) +/* offset to the beginning of layer 3 registers */ +#define LOGICVC_LAYER3_BASE_ROFF \ + (LOGICVC_LAYER0_BASE_ROFF + LOGICVC_LAYER_DISTANCE * 3) +/* offset to the beginning of layer 4 registers */ +#define LOGICVC_LAYER4_BASE_ROFF \ + (LOGICVC_LAYER0_BASE_ROFF + LOGICVC_LAYER_DISTANCE * 4) + +/* logiCVC layer registers offsets (common for each layer) */ +/* LH_OFFSET */ +#define LOGICVC_LAYER_HOR_OFF_ROFF (0 * LOGICVC_REG_DIST_USED) +/* LV_OFFSET */ +#define LOGICVC_LAYER_VER_OFF_ROFF (1 * LOGICVC_REG_DIST_USED) +/* LH_POSITION */ +#define LOGICVC_LAYER_HOR_POS_ROFF (2 * LOGICVC_REG_DIST_USED) +/* LV_POSITION */ +#define LOGICVC_LAYER_VER_POS_ROFF (3 * LOGICVC_REG_DIST_USED) +/* LH_WIDTH */ +#define LOGICVC_LAYER_WIDTH_ROFF (4 * LOGICVC_REG_DIST_USED) +/* LV_HEIGHT */ +#define LOGICVC_LAYER_HEIGHT_ROFF (5 * LOGICVC_REG_DIST_USED) +/* ALPHA */ +#define LOGICVC_LAYER_ALPHA_ROFF (6 * LOGICVC_REG_DIST_USED) +/* CTRL */ +#define LOGICVC_LAYER_CTRL_ROFF (7 * LOGICVC_REG_DIST_USED) +/* TRANSPARENT */ +#define LOGICVC_LAYER_TRANSP_ROFF (8 * LOGICVC_REG_DIST_USED) + +/* logiCVC interrupt bits */ +#define LOGICVC_L0_VBUFF_SW_INT 0x01 +#define LOGICVC_L1_VBUFF_SW_INT 0x02 +#define LOGICVC_L2_VBUFF_SW_INT 0x04 +#define LOGICVC_L3_VBUFF_SW_INT 0x08 +#define LOGICVC_L4_VBUFF_SW_INT 0x10 +#define LOGICVC_V_SYNC_INT 0x20 +#define LOGICVC_E_VIDEO_VALID_INT 0x40 +#define LOGICVC_L0_CLUT_SW_INT 0x100 +#define LOGICVC_L1_CLUT_SW_INT 0x200 +#define LOGICVC_L2_CLUT_SW_INT 0x400 +#define LOGICVC_L3_CLUT_SW_INT 0x800 +#define LOGICVC_L4_CLUT_SW_INT 0x1000 + +/* logiCVC layer base offsets */ +#define LOGICVC_LAYER_OFFSET 0x80 +#define LOGICVC_LAYER_BASE_OFFSET 0x100 +#define LOGICVC_LAYER_0_OFFSET 0 +#define LOGICVC_LAYER_1_OFFSET \ + (LOGICVC_LAYER_0_OFFSET + LOGICVC_LAYER_OFFSET) +#define LOGICVC_LAYER_2_OFFSET \ + (LOGICVC_LAYER_1_OFFSET + LOGICVC_LAYER_OFFSET) +#define LOGICVC_LAYER_3_OFFSET \ + (LOGICVC_LAYER_2_OFFSET + LOGICVC_LAYER_OFFSET) +#define LOGICVC_LAYER_4_OFFSET \ + (LOGICVC_LAYER_3_OFFSET + LOGICVC_LAYER_OFFSET) +#define LOGICVC_LAYER_BASE_END 0x338 + +/* logiCVC layer CLUT base offsets */ +#define LOGICVC_CLUT_OFFSET 0x800 +#define LOGICVC_CLUT_BASE_OFFSET 0x1000 +#define LOGICVC_CLUT_L0_CLUT_0_OFFSET 0 +#define LOGICVC_CLUT_L0_CLUT_1_OFFSET \ + (LOGICVC_CLUT_L0_CLUT_0_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_L1_CLUT_0_OFFSET \ + (LOGICVC_CLUT_L0_CLUT_1_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_L1_CLUT_1_OFFSET \ + (LOGICVC_CLUT_L1_CLUT_0_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_L2_CLUT_0_OFFSET \ + (LOGICVC_CLUT_L1_CLUT_1_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_L2_CLUT_1_OFFSET \ + (LOGICVC_CLUT_L2_CLUT_0_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_L3_CLUT_0_OFFSET \ + (LOGICVC_CLUT_L2_CLUT_1_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_L3_CLUT_1_OFFSET \ + (LOGICVC_CLUT_L3_CLUT_0_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_L4_CLUT_0_OFFSET \ + (LOGICVC_CLUT_L3_CLUT_1_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_L4_CLUT_1_OFFSET \ + (LOGICVC_CLUT_L4_CLUT_0_OFFSET + LOGICVC_CLUT_OFFSET) +#define LOGICVC_CLUT_REGISTER_SIZE 8 +#define LOGICVC_CLUT_0_INDEX_OFFSET 2 +#define LOGICVC_CLUT_1_INDEX_OFFSET 1 + +/* logiCVC register and CLUT base offsets */ +#define LOGICVC_GENERAL_REGISTERS_RANGE 0x100 +#define LOGICVC_REGISTERS_RANGE 0x6000 + +/* logiCVC register initial values */ +#define CTRL_REG_INIT 0x001F +#define SD_REG_INIT 0 + +/* logiCVC display power signals */ +#define LOGICVC_EN_BLIGHT_MSK 0x01 +#define LOGICVC_EN_VDD_MSK 0x02 +#define LOGICVC_EN_VEE_MSK 0x04 +#define LOGICVC_V_EN_MSK 0x08 + +/* logiCVC various definitions */ +#define LOGICVC_PIX_DATA_INVERT 0x80 +#define LOGICVC_PIX_ACT_HIGH 0x100 +#define LOGICVC_LAYER_ON 0x01 +#define LOGICVC_SWAP_RB 0x10 +#define LOGICVC_MAX_LAYERS 5 +#define LOGICVC_MAX_LAYER_BUFFERS 3 +#define LOGICVC_MIN_XRES 64 +#define LOGICVC_MAX_XRES 2048 +#define LOGICVC_MIN_VRES 1 +#define LOGICVC_MAX_VRES 2048 +#define LOGICVC_MAX_LINES 4096 +#define LOGICVC_CLUT_SIZE 256 +#define TRANSPARENT_COLOR_8BPP 0x25 /* dummy */ +#define TRANSPARENT_COLOR_8BPP_CLUT_16 0xF813 /* dummy */ +#define TRANSPARENT_COLOR_8BPP_CLUT_24 0x00FF009C /* dummy */ +#define TRANSPARENT_COLOR_16BPP 0xF813 /* dummy */ +#define TRANSPARENT_COLOR_24BPP 0x00FF009C /* dummy */ +#define BACKGROUND_COLOR 0x00000000 + +#define LOGICVC_READABLE_REGS 0x01 + +enum xylonfb_layer_type { + LOGICVC_RGB_LAYER = 0, + LOGICVC_YCBCR_LAYER, + LOGICVC_ALPHA_LAYER +}; + +enum xylonfb_alpha_format { + LOGICVC_LAYER_ALPHA = 0, + LOGICVC_PIXEL_ALPHA, + LOGICVC_CLUT_16BPP_ALPHA, + LOGICVC_CLUT_32BPP_ALPHA +}; + +enum xylonfb_display_interface { + LOGICVC_DI_PARALLEL = 0, + LOGICVC_DI_ITU656, + LOGICVC_DI_LVDS_4bit, + LOGICVC_DI_CAMERA_LINK_4bit, + LOGICVC_DI_LVDS_3bit, + LOGICVC_DI_DVI +}; + +enum xylonfb_display_color_space { + LOGICVC_DCS_RGB = 0, + LOGICVC_DCS_YUV422, + LOGICVC_DCS_YUV444 +}; + +#endif /* __LOGICVC_H__ */ Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/Makefile 2014-07-20 22:06:38.511270172 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +xylonfb_core-y := xylonfb.o xylonfb-ioctl.o xylonfb-pixclk.o +xylonfb_core-$(CONFIG_FB_XYLON_PIXCLK_LOGICLK) += logiclk.o + +xylonfb_core-$(CONFIG_FB_XYLON_MISC) += ../misc/xylonfb-misc.o +xylonfb_core-$(CONFIG_FB_XYLON_MISC_ADV7511) += ../misc/xylonfb-adv7511.o + +obj-y += xylonfb_core.o Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/xylonfb.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/xylonfb.c 2014-07-20 22:06:38.532269826 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver core functions + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * This driver was based on skeletonfb.c and other framebuffer video drivers. + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/console.h> +#include <linux/videodev2.h> +#include "xylonfb.h" +#if defined(CONFIG_FB_XYLON_MISC) +#include "../misc/xylonfb-misc.h" +#endif + + +#define XYLONFB_PSEUDO_PALETTE_SZ 256 + +#define LOGICVC_PIX_FMT_AYUV v4l2_fourcc('A', 'Y', 'U', 'V') +#define LOGICVC_PIX_FMT_AVUY v4l2_fourcc('A', 'V', 'U', 'Y') +#define LOGICVC_PIX_FMT_ALPHA v4l2_fourcc('A', '8', ' ', ' ') + + +static struct xylonfb_vmode_data xylonfb_vmode = { + .fb_vmode = { + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = KHZ2PICOS(65000), + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .vmode = FB_VMODE_NONINTERLACED + }, + .fb_vmode_name = "1024x768" +}; + +static unsigned short logicvc_layer_reg_offset[] = { + (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_0_OFFSET), + (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_1_OFFSET), + (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_2_OFFSET), + (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_3_OFFSET), + (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_4_OFFSET) +}; + +static unsigned short logicvc_clut_reg_offset[] = { + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L0_CLUT_0_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L0_CLUT_1_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L1_CLUT_0_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L1_CLUT_1_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L2_CLUT_0_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L2_CLUT_1_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L3_CLUT_0_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L3_CLUT_1_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L4_CLUT_0_OFFSET), + (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L4_CLUT_1_OFFSET) +}; + +static char *xylonfb_mode_option; + +/* Function declarations */ +static int xylonfb_set_timings(struct fb_info *fbi, int bpp); +static void xylonfb_logicvc_disp_ctrl(struct fb_info *fbi, bool enable); +static void xylonfb_enable_logicvc_output(struct fb_info *fbi); +static void xylonfb_disable_logicvc_output(struct fb_info *fbi); +static void xylonfb_enable_logicvc_layer(struct fb_info *fbi); +static void xylonfb_disable_logicvc_layer(struct fb_info *fbi); +static void xylonfb_fbi_update(struct fb_info *fbi); + +/******************************************************************************/ + +static u32 xylonfb_get_reg(void *base_virt, unsigned long offset, + struct xylonfb_layer_data *ld) +{ + return readl(base_virt + offset); +} + +static void xylonfb_set_reg(u32 value, + void *base_virt, unsigned long offset, + struct xylonfb_layer_data *ld) +{ + writel(value, (base_virt + offset)); +} + +static unsigned long xylonfb_get_reg_mem_addr( + void *base_virt, unsigned long offset, + struct xylonfb_layer_data *ld) +{ + unsigned long ordinal = offset >> 3; + + if ((unsigned long)base_virt - (unsigned long)ld->reg_base_virt) { + return (unsigned long)(&ld->layer_reg_list->hpos_reg) + + (ordinal * sizeof(unsigned long)); + } else { + return (unsigned long)(&ld->xylonfb_cd->reg_list->dtype_reg) + + (ordinal * sizeof(unsigned long)); + } +} + +static u32 xylonfb_get_reg_mem( + void *base_virt, unsigned long offset, + struct xylonfb_layer_data *ld) +{ + return *((unsigned long *)xylonfb_get_reg_mem_addr( + base_virt, offset, ld)); +} + +static void xylonfb_set_reg_mem(u32 value, + void *base_virt, unsigned long offset, + struct xylonfb_layer_data *ld) +{ + unsigned long *reg_mem_addr = + (unsigned long *)xylonfb_get_reg_mem_addr( + base_virt, offset, ld); + *reg_mem_addr = value; + writel((*reg_mem_addr), (base_virt + offset)); +} + +/******************************************************************************/ + +static irqreturn_t xylonfb_isr(int irq, void *dev_id) +{ + struct fb_info **afbi = dev_get_drvdata(dev_id); + struct fb_info *fbi = afbi[0]; + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + u32 isr; + + driver_devel("%s IRQ %d\n", __func__, irq); + + isr = readl(ld->reg_base_virt + LOGICVC_INT_STAT_ROFF); + if (isr & LOGICVC_V_SYNC_INT) { + writel(LOGICVC_V_SYNC_INT, + ld->reg_base_virt + LOGICVC_INT_STAT_ROFF); + cd->vsync.cnt++; + wake_up_interruptible(&cd->vsync.wait); + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } +} + +/******************************************************************************/ + +static int xylonfb_open(struct fb_info *fbi, int user) +{ + struct xylonfb_layer_data *ld = fbi->par; + + driver_devel("%s\n", __func__); + + if (ld->layer_use_ref == 0) { + /* turn on layer */ + xylonfb_enable_logicvc_layer(fbi); + } + ld->layer_use_ref++; + ld->xylonfb_cd->xylonfb_use_ref++; + + return 0; +} + +static int xylonfb_release(struct fb_info *fbi, int user) +{ + struct xylonfb_layer_data *ld = fbi->par; + + driver_devel("%s\n", __func__); + + ld->layer_use_ref--; + if (ld->layer_use_ref == 0) { + /* turn off layer */ + xylonfb_disable_logicvc_layer(fbi); + } + ld->xylonfb_cd->xylonfb_use_ref--; + + return 0; +} + +/******************************************************************************/ + +static int xylonfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_layer_fix_data *lfdata = &ld->layer_fix; + + driver_devel("%s\n", __func__); + + if (var->xres < LOGICVC_MIN_XRES) + var->xres = LOGICVC_MIN_XRES; + if (var->xres > LOGICVC_MAX_XRES) + var->xres = LOGICVC_MAX_XRES; + if (var->yres < LOGICVC_MIN_VRES) + var->yres = LOGICVC_MIN_VRES; + if (var->yres > LOGICVC_MAX_VRES) + var->yres = LOGICVC_MAX_VRES; + + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->xres_virtual > lfdata->width) + var->xres_virtual = lfdata->width; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + if (var->yres_virtual > lfdata->height) + var->yres_virtual = lfdata->height; + + if ((var->xoffset + var->xres) >= var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres - 1; + if ((var->yoffset + var->yres) >= var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres - 1; + + if (var->bits_per_pixel != fbi->var.bits_per_pixel) { + if (var->bits_per_pixel == 24) + var->bits_per_pixel = 32; + else + var->bits_per_pixel = fbi->var.bits_per_pixel; + } + + var->grayscale = fbi->var.grayscale; + + var->transp.offset = fbi->var.transp.offset; + var->transp.length = fbi->var.transp.length; + var->transp.msb_right = fbi->var.transp.msb_right; + var->red.offset = fbi->var.red.offset; + var->red.length = fbi->var.red.length; + var->red.msb_right = fbi->var.red.msb_right; + var->green.offset = fbi->var.green.offset; + var->green.length = fbi->var.green.length; + var->green.msb_right = fbi->var.green.msb_right; + var->blue.offset = fbi->var.blue.offset; + var->blue.length = fbi->var.blue.length; + var->blue.msb_right = fbi->var.blue.msb_right; + var->height = fbi->var.height; + var->width = fbi->var.width; + var->sync = fbi->var.sync; + var->rotate = fbi->var.rotate; + + return 0; +} + +static int xylonfb_set_par(struct fb_info *fbi) +{ + struct fb_info **afbi = NULL; + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + int rc = 0; + int i; + char vmode_opt[VMODE_NAME_SZ]; + bool resolution_change, layer_on[LOGICVC_MAX_LAYERS]; + + driver_devel("%s\n", __func__); + + if (cd->xylonfb_flags & XYLONFB_FLAG_VMODE_SET) + return 0; + + if (!(cd->xylonfb_flags & XYLONFB_FLAG_EDID_VMODE) && + ((fbi->var.xres == + cd->vmode_data_current.fb_vmode.xres) || + (fbi->var.yres == + cd->vmode_data_current.fb_vmode.yres))) { + resolution_change = false; + } else { + resolution_change = true; + } + + if (resolution_change || + (cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT)) { + + if (!(cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT)) { + struct xylonfb_layer_data *ld; + /* store id's of enabled layers */ + afbi = dev_get_drvdata(fbi->device); + for (i = 0; i < cd->xylonfb_layers; i++) { + ld = afbi[i]->par; + if (ld->layer_ctrl_flags & LOGICVC_LAYER_ON) + layer_on[i] = true; + else + layer_on[i] = false; + } + } + + xylonfb_disable_logicvc_output(fbi); + xylonfb_logicvc_disp_ctrl(fbi, false); + + if (!(cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT)) { + /* we want 60Hz refresh rate */ + cd->vmode_data_current.fb_vmode.refresh = 60; + sprintf(vmode_opt, "%dx%d%s-%d@%d%s", + fbi->var.xres, fbi->var.yres, + cd->vmode_data_current.fb_vmode_opts_cvt, + fbi->var.bits_per_pixel, + cd->vmode_data_current.fb_vmode.refresh, + cd->vmode_data_current.fb_vmode_opts_ext); + if (!strcmp(cd->vmode_data.fb_vmode_name, vmode_opt)) { + cd->vmode_data_current = cd->vmode_data; + } else { + xylonfb_mode_option = vmode_opt; + rc = xylonfb_set_timings( + fbi, fbi->var.bits_per_pixel); + xylonfb_mode_option = NULL; + } + } + if (!rc) { + if (cd->xylonfb_flags & XYLONFB_FLAG_PIXCLK_VALID) { + rc = xylonfb_hw_pixclk_set( + cd->xylonfb_pixclk_src_id, + PICOS2KHZ(cd->vmode_data_current.fb_vmode.pixclock)); + if (rc) + pr_err("Error xylonfb changing pixel clock\n"); + } + xylonfb_fbi_update(fbi); + pr_info("xylonfb video mode: %dx%d%s-%d@%d%s\n", + fbi->var.xres, fbi->var.yres, + cd->vmode_data_current.fb_vmode_opts_cvt, + fbi->var.bits_per_pixel, + cd->vmode_data_current.fb_vmode.refresh, + cd->vmode_data_current.fb_vmode_opts_ext); + } + + xylonfb_enable_logicvc_output(fbi); + xylonfb_logicvc_disp_ctrl(fbi, true); + + /* set flag used for finding video mode only once */ + if (cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT) + cd->xylonfb_flags |= XYLONFB_FLAG_VMODE_SET; + /* used only when resolution is changed */ + if (!(cd->xylonfb_flags & XYLONFB_FLAG_VMODE_SET)) { + if (afbi) { + for (i = 0; i < cd->xylonfb_layers; i++) + if (layer_on[i]) + xylonfb_enable_logicvc_layer(afbi[i]); + } else { + xylonfb_enable_logicvc_layer(fbi); + } + } + } + + return rc; +} + +static int xylonfb_set_color_hw_rgb_to_yuv( + u16 *transp, u16 *red, u16 *green, u16 *blue, int len, int idx, + struct xylonfb_layer_data *ld) +{ + struct xylonfb_common_data *cd = ld->xylonfb_cd; + u32 yuv_pixel; + u32 y, cb, cr; + u32 ykr, ykg, ykb, yk; + u32 crkr, crkg, crkb; + u32 cbkr, cbkg, cbkb; + + driver_devel("%s\n", __func__); + + if (idx > (LOGICVC_CLUT_SIZE-1) || len > LOGICVC_CLUT_SIZE) + return -EINVAL; + + if ((cd->xylonfb_display_interface_type >> 4) == LOGICVC_DI_ITU656) { + ykr = 29900; + ykg = 58700; + ykb = 11400; + yk = 1600000; + crkr = 51138; + crkg = 42820; + crkb = 8316; + cbkr = 17258; + cbkg = 33881; + cbkb = 51140; + } else { + ykr = 29900; + ykg = 58700; + ykb = 11400; + yk = 0; + crkr = 49980; + crkg = 41850; + crkb = 8128; + cbkr = 16868; + cbkg = 33107; + cbkb = 49970; + } + + while (len > 0) { + y = ( + (ykr * (red[idx] & 0xFF)) + + + (ykg * (green[idx] & 0xFF)) + + + (ykb * (blue[idx] & 0xFF)) + + + yk + ) + / + 100000; + cr = ( + (crkr * (red[idx] & 0xFF)) + - + (crkg * (green[idx] & 0xFF)) + - + (crkb * (blue[idx] & 0xFF)) + + + 12800000 + ) + / + 100000; + cb = ( + (-cbkr * (red[idx] & 0xFF)) + - + (cbkg * (green[idx] & 0xFF)) + + + (cbkb * (blue[idx] & 0xFF)) + + + 12800000 + ) + / + 100000; + if (transp) { + yuv_pixel = (((u32)transp[idx] & 0xFF) << 24) | + (y << 16) | (cb << 8) | cr; + } else { + yuv_pixel = + (0xFF << 24) | (y << 16) | (cb << 8) | cr; + } + writel(yuv_pixel, ld->layer_clut_base_virt + + (idx*LOGICVC_CLUT_REGISTER_SIZE)); + len--; + idx++; + } + + return 0; +} + +static int xylonfb_set_color_hw(u16 *transp, u16 *red, u16 *green, u16 *blue, + int len, int idx, struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_layer_fix_data *lfdata = &ld->layer_fix; + u32 pixel; + int bpp_virt, toff, roff, goff, boff; + + driver_devel("%s\n", __func__); + + if ((fbi->fix.visual == FB_VISUAL_FOURCC) && + (fbi->var.grayscale == LOGICVC_PIX_FMT_AYUV)) { + return xylonfb_set_color_hw_rgb_to_yuv( + transp, red, green, blue, len, idx, ld); + } + + bpp_virt = lfdata->bpp_virt; + + toff = fbi->var.transp.offset; + roff = fbi->var.red.offset; + goff = fbi->var.green.offset; + boff = fbi->var.blue.offset; + + if (fbi->fix.visual == FB_VISUAL_PSEUDOCOLOR) { + u32 clut_value; + + if (idx > (LOGICVC_CLUT_SIZE-1) || len > LOGICVC_CLUT_SIZE) + return -EINVAL; + + if (lfdata->alpha_mode == LOGICVC_CLUT_16BPP_ALPHA) { + if (transp) { + while (len > 0) { + clut_value = + ((((transp[idx] & 0xFC) >> 2) << toff) | + (((red[idx] & 0xF8) >> 3) << roff) | + (((green[idx] & 0xFC) >> 2) << goff) | + (((blue[idx] & 0xF8) >> 3) << boff)); + writel(clut_value, + ld->layer_clut_base_virt + + (idx*LOGICVC_CLUT_REGISTER_SIZE)); + len--; + idx++; + } + } else { + while (len > 0) { + clut_value = + ((0x3F << toff) | + (((red[idx] & 0xF8) >> 3) << roff) | + (((green[idx] & 0xFC) >> 2) << goff) | + (((blue[idx] & 0xF8) >> 3) << boff)); + writel(clut_value, + ld->layer_clut_base_virt + + (idx*LOGICVC_CLUT_REGISTER_SIZE)); + len--; + idx++; + } + } + } else if (lfdata->alpha_mode == LOGICVC_CLUT_32BPP_ALPHA) { + if (transp) { + while (len > 0) { + clut_value = + (((transp[idx] & 0xFF) << toff) | + ((red[idx] & 0xFF) << roff) | + ((green[idx] & 0xFF) << goff) | + ((blue[idx] & 0xFF) << boff)); + writel(clut_value, + ld->layer_clut_base_virt + + (idx*LOGICVC_CLUT_REGISTER_SIZE)); + len--; + idx++; + } + } else { + while (len > 0) { + clut_value = + ((0xFF << toff) | + ((red[idx] & 0xFF) << roff) | + ((green[idx] & 0xFF) << goff) | + ((blue[idx] & 0xFF) << boff)); + writel(clut_value, + ld->layer_clut_base_virt + + (idx*LOGICVC_CLUT_REGISTER_SIZE)); + len--; + idx++; + } + } + } + } else if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) { + if (bpp_virt == 8) { + if (lfdata->alpha_mode == LOGICVC_LAYER_ALPHA) { + while (len > 0) { + pixel = ((((red[idx] & 0xE0) >> 5) << roff) | + (((green[idx] & 0xE0) >> 5) << goff) | + (((blue[idx] & 0xC0) >> 6) << boff)); + ((u32 *)(fbi->pseudo_palette))[idx] = + (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel; + len--; + idx++; + } + } else if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA) { + if (transp) { + while (len > 0) { + pixel = ((((transp[idx] & 0xE0) >> 5) << toff) | + (((red[idx] & 0xE0) >> 5) << roff) | + (((green[idx] & 0xE0) >> 5) << goff) | + (((blue[idx] & 0xC0) >> 6) << boff)); + ((u32 *)(fbi->pseudo_palette))[idx] = + (pixel << 16) | pixel; + len--; + idx++; + } + } else { + while (len > 0) { + pixel = ((0x07 << toff) | + (((red[idx] & 0xE0) >> 5) << roff) | + (((green[idx] & 0xE0) >> 5) << goff) | + (((blue[idx] & 0xC0) >> 6) << boff)); + ((u32 *)(fbi->pseudo_palette))[idx] = + (pixel << 16) | pixel; + len--; + idx++; + } + } + } + } else if (bpp_virt == 16) { + if (lfdata->alpha_mode == LOGICVC_LAYER_ALPHA) { + while (len > 0) { + pixel = ((((red[idx] & 0xF8) >> 3) << roff) | + (((green[idx] & 0xFC) >> 2) << goff) | + (((blue[idx] & 0xF8) >> 3) << boff)); + ((u32 *)(fbi->pseudo_palette))[idx] = + (pixel << 16) | pixel; + len--; + idx++; + } + } else if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA) { + if (transp) { + while (len > 0) { + ((u32 *)(fbi->pseudo_palette))[idx] = + ((((transp[idx] & 0xFC) >> 2) << toff) | + (((red[idx] & 0xF8) >> 3) << roff) | + (((green[idx] & 0xFC) >> 2) << goff) | + (((blue[idx] & 0xF8) >> 3) << boff)); + len--; + idx++; + } + } else { + while (len > 0) { + ((u32 *)(fbi->pseudo_palette))[idx] = + ((0x3F << toff) | + (((red[idx] & 0xF8) >> 3) << roff) | + (((green[idx] & 0xFC) >> 2) << goff) | + (((blue[idx] & 0xF8) >> 3) << boff)); + len--; + idx++; + } + } + } + } else if (bpp_virt == 32) { + if (lfdata->alpha_mode == LOGICVC_LAYER_ALPHA) { + while (len > 0) { + ((u32 *)(fbi->pseudo_palette))[idx] = + (((red[idx] & 0xFF) << roff) | + ((green[idx] & 0xFF) << goff) | + ((blue[idx] & 0xFF) << boff)); + len--; + idx++; + } + } else if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA) { + if (transp) { + while (len > 0) { + ((u32 *)(fbi->pseudo_palette))[idx] = + (((transp[idx] & 0xFF) << toff) | + ((red[idx] & 0xFF) << roff) | + ((green[idx] & 0xFF) << goff) | + ((blue[idx] & 0xFF) << boff)); + len--; + idx++; + } + } else { + while (len > 0) { + ((u32 *)(fbi->pseudo_palette))[idx] = + ((0xFF << toff) | + ((red[idx] & 0xFF) << roff) | + ((green[idx] & 0xFF) << goff) | + ((blue[idx] & 0xFF) << boff)); + len--; + idx++; + } + } + } + } + } else { + return -EINVAL; + } + + return 0; +} + +static int xylonfb_set_color_reg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *fbi) +{ + driver_devel("%s\n", __func__); + + return xylonfb_set_color_hw( + (u16 *)&transp, (u16 *)&red, (u16 *)&green, (u16 *)&blue, + 1, regno, fbi); +} + +static int xylonfb_set_cmap(struct fb_cmap *cmap, struct fb_info *fbi) +{ + driver_devel("%s\n", __func__); + + return xylonfb_set_color_hw( + cmap->transp, cmap->red, cmap->green, cmap->blue, + cmap->len, cmap->start, fbi); +} + +static void xylonfb_set_pixels(struct fb_info *fbi, + struct xylonfb_layer_data *ld, int bpp, unsigned int pix) +{ + u32 *vmem; + u8 *vmem8; + u16 *vmem16; + u32 *vmem32; + int x, y, pix_off; + + driver_devel("%s\n", __func__); + + vmem = ld->fb_virt + + (fbi->var.xoffset * (fbi->var.bits_per_pixel/4)) + + (fbi->var.yoffset * fbi->var.xres_virtual * + (fbi->var.bits_per_pixel/4)); + + switch (bpp) { + case 8: + vmem8 = (u8 *)vmem; + for (y = fbi->var.yoffset; y < fbi->var.yres; y++) { + pix_off = (y * fbi->var.xres_virtual); + for (x = fbi->var.xoffset; x < fbi->var.xres; x++) + vmem8[pix_off+x] = pix; + } + break; + case 16: + vmem16 = (u16 *)vmem; + for (y = fbi->var.yoffset; y < fbi->var.yres; y++) { + pix_off = (y * fbi->var.xres_virtual); + for (x = fbi->var.xoffset; x < fbi->var.xres; x++) + vmem16[pix_off+x] = pix; + } + break; + case 32: + vmem32 = (u32 *)vmem; + for (y = fbi->var.yoffset; y < fbi->var.yres; y++) { + pix_off = (y * fbi->var.xres_virtual); + for (x = fbi->var.xoffset; x < fbi->var.xres; x++) + vmem32[pix_off+x] = pix; + } + break; + } +} + +static int xylonfb_blank(int blank_mode, struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_layer_fix_data *lfdata = &ld->layer_fix; + u32 reg; + + driver_devel("%s\n", __func__); + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + driver_devel("FB_BLANK_UNBLANK\n"); + reg = readl(ld->reg_base_virt + LOGICVC_SPWRCTRL_ROFF); + reg |= LOGICVC_V_EN_MSK; + writel(reg, ld->reg_base_virt + LOGICVC_SPWRCTRL_ROFF); + mdelay(50); + break; + + case FB_BLANK_NORMAL: + driver_devel("FB_BLANK_NORMAL\n"); + switch (lfdata->bpp_virt) { + case 8: + switch (lfdata->alpha_mode) { + case LOGICVC_LAYER_ALPHA: + xylonfb_set_pixels(fbi, ld, 8, 0x00); + break; + case LOGICVC_PIXEL_ALPHA: + xylonfb_set_pixels(fbi, ld, 16, 0xFF00); + break; + case LOGICVC_CLUT_16BPP_ALPHA: + case LOGICVC_CLUT_32BPP_ALPHA: + xylonfb_set_color_reg(0, 0, 0, 0, 0xFF, fbi); + xylonfb_set_pixels(fbi, ld, 8, 0); + break; + } + break; + case 16: + switch (lfdata->alpha_mode) { + case LOGICVC_LAYER_ALPHA: + xylonfb_set_pixels(fbi, ld, 16, 0x0000); + break; + case LOGICVC_PIXEL_ALPHA: + xylonfb_set_pixels(fbi, ld, 32, 0xFF000000); + break; + } + break; + case 32: + xylonfb_set_pixels(fbi, ld, 32, 0xFF000000); + break; + } + break; + + case FB_BLANK_POWERDOWN: + driver_devel("FB_BLANK_POWERDOWN\n"); + reg = readl(ld->reg_base_virt + LOGICVC_SPWRCTRL_ROFF); + reg &= ~LOGICVC_V_EN_MSK; + writel(reg, ld->reg_base_virt + LOGICVC_SPWRCTRL_ROFF); + mdelay(50); + break; + + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + default: + driver_devel("FB_BLANK_ not supported!\n"); + return -EINVAL; + } + + return 0; +} + +static int xylonfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + + driver_devel("%s\n", __func__); + + if (fbi->var.xoffset == var->xoffset && + fbi->var.yoffset == var->yoffset) + return 0; + + if (fbi->var.vmode & FB_VMODE_YWRAP) { + return -EINVAL; + } else { + if (var->xoffset + fbi->var.xres > fbi->var.xres_virtual || + var->yoffset + fbi->var.yres > fbi->var.yres_virtual) { + /* if smaller then physical layer video memory + allow panning */ + if ((var->xoffset + fbi->var.xres > ld->layer_fix.width) + || + (var->yoffset + fbi->var.yres > ld->layer_fix.height)) { + return -EINVAL; + } + } + } + /* YCbCr 4:2:2 layer type can only have even layer xoffset */ + if (ld->layer_fix.layer_type == LOGICVC_YCBCR_LAYER && + ld->layer_fix.bpp_virt == 16) { + var->xoffset &= ~1; + } + + fbi->var.xoffset = var->xoffset; + fbi->var.yoffset = var->yoffset; + /* set layer memory X offset */ + cd->reg_access.xylonfb_set_reg_val(var->xoffset, + ld->layer_reg_base_virt, LOGICVC_LAYER_HOR_OFF_ROFF, + ld); + /* set layer memory Y offset */ + cd->reg_access.xylonfb_set_reg_val(var->yoffset, + ld->layer_reg_base_virt, LOGICVC_LAYER_VER_OFF_ROFF, + ld); + cd->reg_access.xylonfb_set_reg_val((fbi->var.xres-1), + ld->layer_reg_base_virt, LOGICVC_LAYER_HOR_POS_ROFF, + ld); + /* apply changes in logiCVC */ + cd->reg_access.xylonfb_set_reg_val((fbi->var.yres-1), + ld->layer_reg_base_virt, LOGICVC_LAYER_VER_POS_ROFF, + ld); + + return 0; +} + + +static struct fb_ops xylonfb_ops = { + .owner = THIS_MODULE, + .fb_open = xylonfb_open, + .fb_release = xylonfb_release, + .fb_check_var = xylonfb_check_var, + .fb_set_par = xylonfb_set_par, + .fb_setcolreg = xylonfb_set_color_reg, + .fb_setcmap = xylonfb_set_cmap, + .fb_blank = xylonfb_blank, + .fb_pan_display = xylonfb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_rotate = NULL, + .fb_sync = NULL, + .fb_ioctl = xylonfb_ioctl, + .fb_mmap = NULL, + .fb_get_caps = NULL, + .fb_destroy = NULL, +}; + +/******************************************************************************/ + +static int xylonfb_find_next_layer(struct xylonfb_layer_fix_data *lfdata, + int layers, int curr) +{ + unsigned long address, temp_address, loop_address; + int i, next; + + driver_devel("%s\n", __func__); + + address = lfdata[curr].offset * lfdata[curr].width * lfdata[curr].bpp; + temp_address = ~0; + next = -1; + + for (i = 0; i < layers; i++) { + loop_address = + lfdata[i].offset * lfdata[i].width * lfdata[i].bpp; + if (address < loop_address + && + loop_address < temp_address) { + next = i; + temp_address = loop_address; + } + } + + return next; +} + +static void xylonfb_set_yvirt(struct xylonfb_init_data *init_data, + int layers, int curr) +{ + struct xylonfb_layer_fix_data *lfdata; + unsigned long vmem_base_addr, vmem_high_addr; + int next; + + driver_devel("%s\n", __func__); + + lfdata = init_data->lfdata; + vmem_base_addr = init_data->vmem_base_addr; + vmem_high_addr = init_data->vmem_high_addr; + + next = xylonfb_find_next_layer(lfdata, layers, curr); + + if (next != -1) { + lfdata[curr].height = + ((lfdata[next].width * (lfdata[next].bpp/8) * + lfdata[next].offset) + - + (lfdata[curr].width * (lfdata[curr].bpp/8) * + lfdata[curr].offset)) + / + (lfdata[curr].width * (lfdata[curr].bpp/8)); + } else { /* last physical logiCVC layer */ + lfdata[curr].height = LOGICVC_MAX_LINES + 1; + while (1) { + if (((lfdata[curr].width * (lfdata[curr].bpp/8) * + lfdata[curr].height) + + + (lfdata[curr].width * (lfdata[curr].bpp/8) * + lfdata[curr].offset)) + <= + (vmem_high_addr - vmem_base_addr)) + break; + /* FIXME - magic decrease step */ + lfdata[curr].height -= 64; + } + } + + if (lfdata[curr].height > + (lfdata[curr].buffer_offset * LOGICVC_MAX_LAYER_BUFFERS)) { + lfdata[curr].height = + lfdata[curr].buffer_offset * LOGICVC_MAX_LAYER_BUFFERS; + } + + lfdata[curr].layer_fix_info |= + ((lfdata[curr].height / lfdata[curr].buffer_offset) << 4); +} + +static int xylonfb_map(int id, int layers, struct device *dev, + struct xylonfb_layer_data *ld, + unsigned long vmem_base_addr, + unsigned long reg_base_phys, void *reg_base_virt, + int memmap) +{ + struct xylonfb_layer_fix_data *lfdata = &ld->layer_fix; + + driver_devel("%s\n", __func__); + + /* logiCVC register mapping */ + ld->reg_base_phys = reg_base_phys; + ld->reg_base_virt = reg_base_virt; + /* check register mappings */ + if (!ld->reg_base_virt) { + pr_err("Error xylonfb registers mapping\n"); + return -ENOMEM; + } + /* Video memory mapping */ + ld->fb_phys = vmem_base_addr + + (lfdata->width * (lfdata->bpp/8) * lfdata->offset); + ld->fb_size = + lfdata->width * (lfdata->bpp/8) * lfdata->height; + + if (memmap) { + if (ld->xylonfb_cd->xylonfb_flags & XYLONFB_FLAG_DMA_BUFFER) { + /* NOT USED FOR NOW! */ + ld->fb_virt = dma_alloc_coherent(NULL, + PAGE_ALIGN(ld->fb_size), + &ld->fb_phys, GFP_KERNEL); + } else { + ld->fb_virt = + ioremap_wc(ld->fb_phys, ld->fb_size); + } + /* check memory mappings */ + if (!ld->fb_virt) { + pr_err("Error xylonfb vmem mapping\n"); + return -ENOMEM; + } + } + ld->layer_reg_base_virt = ld->reg_base_virt + + logicvc_layer_reg_offset[id]; + ld->layer_clut_base_virt = ld->reg_base_virt + + logicvc_clut_reg_offset[id*LOGICVC_CLUT_0_INDEX_OFFSET]; + ld->layer_use_ref = 0; + ld->layer_ctrl_flags = 0; + + return 0; +} + +static void xylonfb_set_fbi_var_screeninfo(struct fb_var_screeninfo *var, + struct xylonfb_common_data *cd) +{ + driver_devel("%s\n", __func__); + + var->xres = cd->vmode_data_current.fb_vmode.xres; + var->yres = cd->vmode_data_current.fb_vmode.yres; + var->pixclock = cd->vmode_data_current.fb_vmode.pixclock; + var->left_margin = cd->vmode_data_current.fb_vmode.left_margin; + var->right_margin = cd->vmode_data_current.fb_vmode.right_margin; + var->upper_margin = cd->vmode_data_current.fb_vmode.upper_margin; + var->lower_margin = cd->vmode_data_current.fb_vmode.lower_margin; + var->hsync_len = cd->vmode_data_current.fb_vmode.hsync_len; + var->vsync_len = cd->vmode_data_current.fb_vmode.vsync_len; + var->sync = cd->vmode_data_current.fb_vmode.sync; + var->vmode = cd->vmode_data_current.fb_vmode.vmode; +} + +static void xylonfb_fbi_update(struct fb_info *fbi) +{ + struct fb_info **afbi = dev_get_drvdata(fbi->device); + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + int i, layers, layer_id; + + driver_devel("%s\n", __func__); + + if (!(cd->xylonfb_flags & XYLONFB_FLAG_EDID_VMODE) || + !(cd->xylonfb_flags & XYLONFB_FLAG_EDID_RDY) || + !afbi) + return; + + layers = cd->xylonfb_layers; + layer_id = ld->layer_fix.layer_fix_info & 0x0F; + + for (i = 0; i < layers; i++) { + if (i == layer_id) + continue; + xylonfb_set_fbi_var_screeninfo(&afbi[i]->var, cd); + afbi[i]->monspecs = afbi[layer_id]->monspecs; + } +} + +static void xylonfb_set_hw_specifics(struct fb_info *fbi, + struct xylonfb_layer_data *ld, + struct xylonfb_layer_fix_data *lfdata, + unsigned long reg_base_phys) +{ + driver_devel("%s\n", __func__); + + fbi->fix.smem_start = ld->fb_phys; + fbi->fix.smem_len = ld->fb_size; + if (lfdata->layer_type == LOGICVC_RGB_LAYER) + fbi->fix.type = FB_TYPE_PACKED_PIXELS; + else if (lfdata->layer_type == LOGICVC_YCBCR_LAYER) + fbi->fix.type = FB_TYPE_FOURCC; + if ((lfdata->layer_type == LOGICVC_YCBCR_LAYER) || + (lfdata->layer_type == LOGICVC_ALPHA_LAYER)) { + fbi->fix.visual = FB_VISUAL_FOURCC; + } else if ((lfdata->layer_type == LOGICVC_RGB_LAYER) && + (lfdata->bpp == 8) && + ((lfdata->alpha_mode == LOGICVC_CLUT_16BPP_ALPHA) || + (lfdata->alpha_mode == LOGICVC_CLUT_32BPP_ALPHA))) { + fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR; + } else { + /* + Other logiCVC layer pixel formats: + - 8 bpp: LAYER or PIXEL alpha + It is not true color, RGB triplet is stored in 8 bits. + - 16 bpp: + LAYER alpha: RGB triplet is stored in 16 bits + PIXEL alpha: ARGB quadriplet is stored in 32 bits + - 32 bpp: LAYER or PIXEL alpha + True color, RGB triplet or ARGB quadriplet + is stored in 32 bits. + */ + fbi->fix.visual = FB_VISUAL_TRUECOLOR; + } + /* sanity check */ + if ((lfdata->bpp != 8) && + ((lfdata->alpha_mode == LOGICVC_CLUT_16BPP_ALPHA) || + (lfdata->alpha_mode == LOGICVC_CLUT_32BPP_ALPHA))) { + pr_warn("xylonfb invalid layer alpha!\n"); + lfdata->alpha_mode = LOGICVC_LAYER_ALPHA; + } + fbi->fix.xpanstep = 1; + fbi->fix.ypanstep = 1; + fbi->fix.ywrapstep = 0; + fbi->fix.line_length = lfdata->width * (lfdata->bpp/8); + fbi->fix.mmio_start = reg_base_phys; + fbi->fix.mmio_len = LOGICVC_REGISTERS_RANGE; + fbi->fix.accel = FB_ACCEL_NONE; + + fbi->var.xres_virtual = lfdata->width; + if (lfdata->height <= LOGICVC_MAX_LINES) + fbi->var.yres_virtual = lfdata->height; + else + fbi->var.yres_virtual = LOGICVC_MAX_LINES; + fbi->var.bits_per_pixel = lfdata->bpp; + switch (lfdata->layer_type) { + case LOGICVC_RGB_LAYER: + fbi->var.grayscale = 0; + break; + case LOGICVC_YCBCR_LAYER: + if (lfdata->bpp == 8) { + fbi->var.grayscale = LOGICVC_PIX_FMT_AYUV; + } else if (lfdata->bpp == 16) { + if (ld->layer_ctrl_flags & LOGICVC_SWAP_RB) + fbi->var.grayscale = V4L2_PIX_FMT_YVYU; + else + fbi->var.grayscale = V4L2_PIX_FMT_VYUY; + } else if (lfdata->bpp == 32) { + if (ld->layer_ctrl_flags & LOGICVC_SWAP_RB) + fbi->var.grayscale = LOGICVC_PIX_FMT_AVUY; + else + fbi->var.grayscale = LOGICVC_PIX_FMT_AYUV; + } + break; + case LOGICVC_ALPHA_LAYER: + /* logiCVC Alpha layer 8bpp */ + fbi->var.grayscale = LOGICVC_PIX_FMT_ALPHA; + break; + } + + /* + Set values according to logiCVC layer data width configuration: + - layer data width can be 1, 2, 4 bytes + - layer data width for 16 bpp can be 2 or 4 bytes + */ + if (lfdata->alpha_mode == LOGICVC_LAYER_ALPHA) { + fbi->var.transp.offset = 0; + fbi->var.transp.length = 0; + } + switch (lfdata->bpp_virt) { + case 8: + switch (lfdata->alpha_mode) { + case LOGICVC_PIXEL_ALPHA: + fbi->var.transp.offset = 8; + fbi->var.transp.length = 3; + + case LOGICVC_LAYER_ALPHA: + fbi->var.red.offset = 5; + fbi->var.red.length = 3; + fbi->var.green.offset = 2; + fbi->var.green.length = 3; + fbi->var.blue.offset = 0; + fbi->var.blue.length = 2; + break; + + case LOGICVC_CLUT_16BPP_ALPHA: + fbi->var.transp.offset = 24; + fbi->var.transp.length = 6; + fbi->var.red.offset = 19; + fbi->var.red.length = 5; + fbi->var.green.offset = 10; + fbi->var.green.length = 6; + fbi->var.blue.offset = 3; + fbi->var.blue.length = 5; + break; + + case LOGICVC_CLUT_32BPP_ALPHA: + fbi->var.transp.offset = 24; + fbi->var.transp.length = 8; + fbi->var.red.offset = 16; + fbi->var.red.length = 8; + fbi->var.green.offset = 8; + fbi->var.green.length = 8; + fbi->var.blue.offset = 0; + fbi->var.blue.length = 8; + break; + } + break; + case 16: + switch (lfdata->alpha_mode) { + case LOGICVC_PIXEL_ALPHA: + fbi->var.transp.offset = 24; + fbi->var.transp.length = 6; + + case LOGICVC_LAYER_ALPHA: + fbi->var.red.offset = 11; + fbi->var.red.length = 5; + fbi->var.green.offset = 5; + fbi->var.green.length = 6; + fbi->var.blue.offset = 0; + fbi->var.blue.length = 5; + break; + } + break; + case 32: + switch (lfdata->alpha_mode) { + case LOGICVC_PIXEL_ALPHA: + fbi->var.transp.offset = 24; + fbi->var.transp.length = 8; + + case LOGICVC_LAYER_ALPHA: + fbi->var.red.offset = 16; + fbi->var.red.length = 8; + fbi->var.green.offset = 8; + fbi->var.green.length = 8; + fbi->var.blue.offset = 0; + fbi->var.blue.length = 8; + break; + } + break; + } + fbi->var.transp.msb_right = 0; + fbi->var.red.msb_right = 0; + fbi->var.green.msb_right = 0; + fbi->var.blue.msb_right = 0; + fbi->var.activate = FB_ACTIVATE_NOW; + fbi->var.height = 0; + fbi->var.width = 0; + fbi->var.sync = 0; + fbi->var.rotate = 0; +} + +static int xylonfb_set_timings(struct fb_info *fbi, int bpp) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + struct fb_var_screeninfo fb_var; + int rc; + + driver_devel("%s\n", __func__); + + if ((cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT) && + (!(cd->xylonfb_flags & XYLONFB_FLAG_EDID_RDY)) && + memchr(cd->vmode_data.fb_vmode_name, 'x', 10)) { + cd->vmode_data_current = cd->vmode_data; + return 0; + } + + /* switch-case to default */ + rc = 255; + if ((cd->xylonfb_flags & XYLONFB_FLAG_EDID_VMODE) && + (cd->xylonfb_flags & XYLONFB_FLAG_EDID_RDY)) { + if (cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT) { +#if defined(CONFIG_FB_XYLON_MISC) + fb_var = *(cd->xylonfb_misc->var_screeninfo); +#endif + } else { + rc = fb_find_mode(&fb_var, fbi, xylonfb_mode_option, + fbi->monspecs.modedb, fbi->monspecs.modedb_len, + &xylonfb_vmode.fb_vmode, bpp); + if ((rc != 1) && (rc != 2)) + return -EINVAL; +#if defined(CONFIG_FB_XYLON_MISC) + if (fbi->monspecs.modedb && + cd->xylonfb_misc->monspecs->misc & FB_MISC_1ST_DETAIL) + if ((fbi->var.xres == fbi->monspecs.modedb[0].xres) && + (fbi->var.yres == fbi->monspecs.modedb[0].yres)) { + fb_videomode_to_var(&fb_var, &fbi->monspecs.modedb[0]); + } +#endif + } + } else { + rc = fb_find_mode(&fb_var, fbi, xylonfb_mode_option, NULL, 0, + &xylonfb_vmode.fb_vmode, bpp); + } +#ifdef DEBUG + switch (rc) { + case 0: + pr_err("Error xylonfb video mode\n" + "using driver default mode %dx%dM-%d@%d\n", + xylonfb_vmode.fb_vmode.xres, + xylonfb_vmode.fb_vmode.yres, + bpp, + xylonfb_vmode.fb_vmode.refresh); + break; + case 1: + driver_devel("xylonfb video mode %s\n", xylonfb_mode_option); + break; + case 2: + pr_notice("xylonfb video mode %s with ignored refresh rate\n", + xylonfb_mode_option); + break; + case 3: + pr_notice("xylonfb default video mode %dx%dM-%d@%d\n", + xylonfb_vmode.fb_vmode.xres, + xylonfb_vmode.fb_vmode.yres, + bpp, + xylonfb_vmode.fb_vmode.refresh); + break; + case 4: + pr_notice("xylonfb video mode fallback\n"); + break; + default: + break; + } +#endif + + cd->vmode_data_current.ctrl_reg = cd->vmode_data.ctrl_reg; + cd->vmode_data_current.fb_vmode.xres = fb_var.xres; + cd->vmode_data_current.fb_vmode.yres = fb_var.yres; + cd->vmode_data_current.fb_vmode.pixclock = fb_var.pixclock; + cd->vmode_data_current.fb_vmode.left_margin = fb_var.left_margin; + cd->vmode_data_current.fb_vmode.right_margin = fb_var.right_margin; + cd->vmode_data_current.fb_vmode.upper_margin = fb_var.upper_margin; + cd->vmode_data_current.fb_vmode.lower_margin = fb_var.lower_margin; + cd->vmode_data_current.fb_vmode.hsync_len = fb_var.hsync_len; + cd->vmode_data_current.fb_vmode.vsync_len = fb_var.vsync_len; + cd->vmode_data_current.fb_vmode.sync = fb_var.sync; + cd->vmode_data_current.fb_vmode.vmode = fb_var.vmode; + cd->vmode_data_current.fb_vmode.refresh = + DIV_ROUND_CLOSEST( + (PICOS2KHZ(fb_var.pixclock) * 1000), + ((fb_var.xres + fb_var.left_margin + + fb_var.right_margin + fb_var.hsync_len) + * + (fb_var.yres + fb_var.upper_margin + + fb_var.lower_margin + fb_var.vsync_len))); + strcpy(cd->vmode_data_current.fb_vmode_opts_cvt, + cd->vmode_data.fb_vmode_opts_cvt); + strcpy(cd->vmode_data_current.fb_vmode_opts_ext, + cd->vmode_data.fb_vmode_opts_ext); + sprintf(cd->vmode_data_current.fb_vmode_name, + "%dx%d%s-%d@%d%s", + fb_var.xres, fb_var.yres, + cd->vmode_data_current.fb_vmode_opts_cvt, + fb_var.bits_per_pixel, + cd->vmode_data_current.fb_vmode.refresh, + cd->vmode_data_current.fb_vmode_opts_ext); + + if ((cd->xylonfb_flags & XYLONFB_FLAG_EDID_RDY) || + !memchr(cd->vmode_data.fb_vmode_name, 'x', 10)) { + cd->vmode_data = cd->vmode_data_current; + } + + return 0; +} + +static int xylonfb_register_fb(struct fb_info *fbi, + struct xylonfb_layer_data *ld, + unsigned long reg_base_phys, int id, int *regfb) +{ + struct xylonfb_common_data *cd = ld->xylonfb_cd; + struct xylonfb_layer_fix_data *lfdata = &ld->layer_fix; + int alpha; + + driver_devel("%s\n", __func__); + + fbi->flags = FBINFO_DEFAULT; + fbi->screen_base = (char __iomem *)ld->fb_virt; + fbi->screen_size = ld->fb_size; + fbi->pseudo_palette = + kzalloc(sizeof(u32) * XYLONFB_PSEUDO_PALETTE_SZ, GFP_KERNEL); + fbi->fbops = &xylonfb_ops; + + sprintf(fbi->fix.id, "Xylon FB%d", id); + xylonfb_set_hw_specifics(fbi, ld, lfdata, reg_base_phys); + if (!(cd->xylonfb_flags & XYLONFB_FLAG_DEFAULT_VMODE_SET)) { + xylonfb_set_timings(fbi, fbi->var.bits_per_pixel); + cd->xylonfb_flags |= XYLONFB_FLAG_DEFAULT_VMODE_SET; + } + xylonfb_set_fbi_var_screeninfo(&fbi->var, cd); + fbi->mode = &cd->vmode_data_current.fb_vmode; + fbi->mode->name = cd->vmode_data_current.fb_vmode_name; + + if (lfdata->alpha_mode == LOGICVC_LAYER_ALPHA) + alpha = 0; + else + alpha = 1; + if (fb_alloc_cmap(&fbi->cmap, XYLONFB_PSEUDO_PALETTE_SZ, alpha)) + return -ENOMEM; + + *regfb = register_framebuffer(fbi); + if (*regfb) { + pr_err("Error xylonfb registering xylonfb %d\n", id); + return -EINVAL; + } + pr_info("xylonfb %d registered\n", id); + /* after fb driver registration, values in struct fb_info + must not be changed anywhere else except in xylonfb_set_par */ + + return 0; +} + +static void xylonfb_init_layer_regs(struct xylonfb_layer_data *ld) +{ + struct xylonfb_common_data *cd = ld->xylonfb_cd; + u32 reg_val; + + switch (ld->layer_fix.bpp_virt) { + case 8: + switch (ld->layer_fix.alpha_mode) { + case LOGICVC_CLUT_16BPP_ALPHA: + reg_val = TRANSPARENT_COLOR_8BPP_CLUT_16; + break; + case LOGICVC_CLUT_32BPP_ALPHA: + reg_val = TRANSPARENT_COLOR_8BPP_CLUT_24; + break; + default: + reg_val = TRANSPARENT_COLOR_8BPP; + break; + } + break; + case 16: + reg_val = TRANSPARENT_COLOR_16BPP; + break; + case 32: + reg_val = TRANSPARENT_COLOR_24BPP; + break; + default: + reg_val = TRANSPARENT_COLOR_24BPP; + break; + } + cd->reg_access.xylonfb_set_reg_val(reg_val, + ld->layer_reg_base_virt, LOGICVC_LAYER_TRANSP_ROFF, + ld); + + if (!(cd->xylonfb_flags & LOGICVC_READABLE_REGS)) + cd->reg_access.xylonfb_set_reg_val(0xFF, + ld->layer_reg_base_virt, LOGICVC_LAYER_ALPHA_ROFF, + ld); + + reg_val = ld->layer_ctrl_flags; + cd->reg_access.xylonfb_set_reg_val(reg_val, + ld->layer_reg_base_virt, LOGICVC_LAYER_CTRL_ROFF, + ld); +} + +static void xylonfb_logicvc_disp_ctrl(struct fb_info *fbi, bool enable) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + u32 val; + + driver_devel("%s\n", __func__); + + if (enable) { + val = LOGICVC_EN_VDD_MSK; + writel(val, ld->reg_base_virt + LOGICVC_SPWRCTRL_ROFF); + mdelay(cd->power_on_delay); + val |= LOGICVC_V_EN_MSK; + writel(val, ld->reg_base_virt + LOGICVC_SPWRCTRL_ROFF); + mdelay(cd->signal_on_delay); + val |= LOGICVC_EN_BLIGHT_MSK; + writel(val, ld->reg_base_virt + LOGICVC_SPWRCTRL_ROFF); + } else { + writel(0, ld->reg_base_virt + LOGICVC_SPWRCTRL_ROFF); + } +} + +static void xylonfb_enable_logicvc_layer(struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + + driver_devel("%s\n", __func__); + + ld->layer_ctrl_flags |= LOGICVC_LAYER_ON; + ld->xylonfb_cd->reg_access.xylonfb_set_reg_val( + ld->layer_ctrl_flags, + ld->layer_reg_base_virt, LOGICVC_LAYER_CTRL_ROFF, + ld); +} + +static void xylonfb_disable_logicvc_layer(struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + + driver_devel("%s\n", __func__); + + ld->layer_ctrl_flags &= (~LOGICVC_LAYER_ON); + ld->xylonfb_cd->reg_access.xylonfb_set_reg_val( + ld->layer_ctrl_flags, + ld->layer_reg_base_virt, LOGICVC_LAYER_CTRL_ROFF, + ld); +} + +static void xylonfb_enable_logicvc_output(struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + + driver_devel("%s\n", __func__); + + writel(cd->vmode_data_current.fb_vmode.right_margin-1, + ld->reg_base_virt + LOGICVC_SHSY_FP_ROFF); + writel(cd->vmode_data_current.fb_vmode.hsync_len-1, + ld->reg_base_virt + LOGICVC_SHSY_ROFF); + writel(cd->vmode_data_current.fb_vmode.left_margin-1, + ld->reg_base_virt + LOGICVC_SHSY_BP_ROFF); + writel(cd->vmode_data_current.fb_vmode.xres-1, + ld->reg_base_virt + LOGICVC_SHSY_RES_ROFF); + writel(cd->vmode_data_current.fb_vmode.lower_margin-1, + ld->reg_base_virt + LOGICVC_SVSY_FP_ROFF); + writel(cd->vmode_data_current.fb_vmode.vsync_len-1, + ld->reg_base_virt + LOGICVC_SVSY_ROFF); + writel(cd->vmode_data_current.fb_vmode.upper_margin-1, + ld->reg_base_virt + LOGICVC_SVSY_BP_ROFF); + writel(cd->vmode_data_current.fb_vmode.yres-1, + ld->reg_base_virt + LOGICVC_SVSY_RES_ROFF); + cd->reg_access.xylonfb_set_reg_val( + cd->vmode_data_current.ctrl_reg, + ld->reg_base_virt, + LOGICVC_SCTRL_ROFF, + ld); + writel(SD_REG_INIT, ld->reg_base_virt + LOGICVC_SDTYPE_ROFF); + + driver_devel("\n" \ + "logiCVC HW parameters:\n" \ + " Horizontal Front Porch: %d pixclks\n" \ + " Horizontal Sync: %d pixclks\n" \ + " Horizontal Back Porch: %d pixclks\n" \ + " Vertical Front Porch: %d pixclks\n" \ + " Vertical Sync: %d pixclks\n" \ + " Vertical Back Porch: %d pixclks\n" \ + " Pixel Clock: %d ps\n" \ + " Horizontal Res: %d\n" \ + " Vertical Res: %d\n" \ + "\n", \ + cd->vmode_data_current.fb_vmode.right_margin, + cd->vmode_data_current.fb_vmode.hsync_len, + cd->vmode_data_current.fb_vmode.left_margin, + cd->vmode_data_current.fb_vmode.lower_margin, + cd->vmode_data_current.fb_vmode.vsync_len, + cd->vmode_data_current.fb_vmode.upper_margin, + cd->vmode_data_current.fb_vmode.pixclock, + cd->vmode_data_current.fb_vmode.xres, + cd->vmode_data_current.fb_vmode.yres); +} + +static void xylonfb_disable_logicvc_output(struct fb_info *fbi) +{ + struct fb_info **afbi = dev_get_drvdata(fbi->device); + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + int i; + + driver_devel("%s\n", __func__); + + if (afbi) { + for (i = 0; i < cd->xylonfb_layers; i++) + xylonfb_disable_logicvc_layer(afbi[i]); + } +} + +static void xylonfb_start(struct fb_info **afbi, int layers) +{ + struct xylonfb_layer_data *ld; + int i; + + driver_devel("%s\n", __func__); + + /* turn OFF all layers except already used ones */ + for (i = 0; i < layers; i++) { + ld = afbi[i]->par; + if (ld->layer_ctrl_flags & LOGICVC_LAYER_ON) + continue; + /* turn off layer */ + xylonfb_disable_logicvc_layer(afbi[i]); + } + /* print layer parameters */ + for (i = 0; i < layers; i++) { + ld = afbi[i]->par; + driver_devel("logiCVC layer %d\n" \ + " Registers Base Address: 0x%lX\n" \ + " Layer Video Memory Address: 0x%lX\n" \ + " X resolution: %d\n" \ + " Y resolution: %d\n" \ + " X resolution (virtual): %d\n" \ + " Y resolution (virtual): %d\n" \ + " Line length (bytes): %d\n" \ + " Bits per Pixel: %d\n" \ + "\n", \ + i, + (unsigned long)ld->reg_base_phys, + (unsigned long)ld->fb_phys, + afbi[i]->var.xres, + afbi[i]->var.yres, + afbi[i]->var.xres_virtual, + afbi[i]->var.yres_virtual, + afbi[i]->fix.line_length, + afbi[i]->var.bits_per_pixel); + } +} + +/******************************************************************************/ + +static int xylonfb_event_notify(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct fb_event *fbe = data; + struct fb_info *fbi = fbe->info; + int ret = 0; + + driver_devel("%s\n", __func__); + + switch (event) { + case XYLONFB_EVENT_FBI_UPDATE: + xylonfb_fbi_update(fbi); + break; + } + + return ret; +} + +/******************************************************************************/ + +static void xylonfb_get_vmode_opts( + struct xylonfb_init_data *init_data, + struct xylonfb_common_data *cd) +{ + char cvt_opt[VMODE_OPTS_SZ] = "MR"; + char ext_opt[VMODE_OPTS_SZ] = "im"; + char *s, *opt, *ext, *c, *pco, *peo; + + if (cd->xylonfb_flags & XYLONFB_FLAG_EDID_VMODE) + return; + + s = init_data->vmode_data.fb_vmode_name; + opt = cd->vmode_data.fb_vmode_opts_cvt; + ext = cd->vmode_data.fb_vmode_opts_ext; + pco = cvt_opt; + peo = ext_opt; + + while (*pco) { + c = strchr(s, (int)(*pco)); + if (c) + *opt++ = *c; + pco++; + } + while (*peo) { + c = strchr(s, (int)(*peo)); + if (c) + *ext++ = *c; + peo++; + } +} + +int xylonfb_init_driver(struct xylonfb_init_data *init_data) +{ + struct device *dev; + struct fb_info **afbi; + struct fb_info *fbi; + struct xylonfb_common_data *cd; + struct xylonfb_layer_data *ld; + struct resource *reg_res, *irq_res; + void *reg_base_virt; + unsigned long reg_base_phys; + int reg_range, layers, active_layer; + int i, rc, memmap; + int regfb[LOGICVC_MAX_LAYERS]; + + driver_devel("%s\n", __func__); + + dev = &init_data->pdev->dev; + + reg_res = platform_get_resource(init_data->pdev, IORESOURCE_MEM, 0); + irq_res = platform_get_resource(init_data->pdev, IORESOURCE_IRQ, 0); + if ((!reg_res) || (!irq_res)) { + pr_err("Error xylonfb resources\n"); + return -ENODEV; + } + + layers = init_data->layers; + if (layers == 0) { + pr_err("Error xylonfb zero layers\n"); + return -ENODEV; + } + active_layer = init_data->active_layer; + if (active_layer >= layers) { + pr_err("Error xylonfb default layer: set to 0\n"); + active_layer = 0; + } + + afbi = kzalloc(sizeof(struct fb_info *) * layers, GFP_KERNEL); + cd = kzalloc(sizeof(struct xylonfb_common_data), GFP_KERNEL); + if (!afbi || !cd) { + pr_err("Error xylonfb allocating internal data\n"); + rc = -ENOMEM; + goto err_mem; + } + + BLOCKING_INIT_NOTIFIER_HEAD(&cd->xylonfb_notifier_list); + cd->xylonfb_nb.notifier_call = xylonfb_event_notify; + blocking_notifier_chain_register( + &cd->xylonfb_notifier_list, &cd->xylonfb_nb); + + cd->xylonfb_display_interface_type = + init_data->display_interface_type; + cd->xylonfb_layers = layers; + cd->xylonfb_flags |= XYLONFB_FLAG_VMODE_INIT; + cd->xylonfb_console_layer = active_layer; + if (init_data->flags & XYLONFB_FLAG_ADV7511_SKIP) { + cd->xylonfb_flags |= XYLONFB_FLAG_ADV7511_SKIP; + } else { + if (init_data->flags & XYLONFB_FLAG_EDID_VMODE) + cd->xylonfb_flags |= XYLONFB_FLAG_EDID_VMODE; + if (init_data->flags & XYLONFB_FLAG_EDID_PRINT) + cd->xylonfb_flags |= XYLONFB_FLAG_EDID_PRINT; + } + if (init_data->flags & LOGICVC_READABLE_REGS) { + cd->xylonfb_flags |= LOGICVC_READABLE_REGS; + cd->reg_access.xylonfb_get_reg_val = xylonfb_get_reg; + cd->reg_access.xylonfb_set_reg_val = xylonfb_set_reg; + } else { + cd->reg_list = + kzalloc(sizeof(struct xylonfb_registers), GFP_KERNEL); + cd->reg_access.xylonfb_get_reg_val = xylonfb_get_reg_mem; + cd->reg_access.xylonfb_set_reg_val = xylonfb_set_reg_mem; + } + + sprintf(init_data->vmode_data.fb_vmode_name, "%s-%d@%d", + init_data->vmode_data.fb_vmode_name, + init_data->lfdata[active_layer].bpp, + init_data->vmode_data.fb_vmode.refresh); + if (init_data->vmode_params_set) { + cd->vmode_data = init_data->vmode_data; + } else { + xylonfb_mode_option = init_data->vmode_data.fb_vmode_name; + cd->vmode_data.ctrl_reg = init_data->vmode_data.ctrl_reg; + cd->vmode_data.fb_vmode.refresh = + init_data->vmode_data.fb_vmode.refresh; + } + xylonfb_get_vmode_opts(init_data, cd); + + if (init_data->pixclk_src_id) { + if (xylonfb_hw_pixclk_supported(init_data->pixclk_src_id)) { + cd->xylonfb_pixclk_src_id = init_data->pixclk_src_id; + cd->xylonfb_flags |= XYLONFB_FLAG_PIXCLK_VALID; + } else { + pr_info("xylonfb pixel clock not supported\n"); + } + } else { + pr_info("xylonfb external pixel clock\n"); + } + + ld = NULL; + + reg_base_phys = reg_res->start; + reg_range = resource_size(reg_res); + reg_base_virt = ioremap_nocache(reg_base_phys, reg_range); + + /* load layer parameters for all layers */ + for (i = 0; i < layers; i++) + regfb[i] = -1; + memmap = 1; + + /* make /dev/fb0 to be default active layer + regardless how logiCVC layers are organized */ + for (i = active_layer; i < layers; i++) { + if (regfb[i] != -1) + continue; + + fbi = framebuffer_alloc(sizeof(struct xylonfb_layer_data), dev); + if (!fbi) { + pr_err("Error xylonfb allocate info\n"); + rc = -ENOMEM; + goto err_fb; + } + afbi[i] = fbi; + ld = fbi->par; + ld->xylonfb_cd = cd; + +#if defined(CONFIG_FB_XYLON_MISC) + if (!cd->xylonfb_misc) { + cd->xylonfb_misc = kzalloc( + sizeof(struct xylonfb_misc_data), GFP_KERNEL); + if (cd->xylonfb_misc) { + xylonfb_misc_init(fbi); + } else { + pr_err("Error xylonfb allocating misc internal data\n"); + goto err_fb; + } + } +#endif + + xylonfb_set_yvirt(init_data, layers, i); + + ld->layer_fix = init_data->lfdata[i]; + if (!(cd->xylonfb_flags & LOGICVC_READABLE_REGS)) { + ld->layer_reg_list = + kzalloc(sizeof(struct xylonfb_layer_registers), GFP_KERNEL); + } + + rc = xylonfb_map(i, layers, dev, ld, init_data->vmem_base_addr, + reg_base_phys, reg_base_virt, memmap); + if (rc) + goto err_fb; + memmap = 0; + + ld->layer_ctrl_flags = init_data->layer_ctrl_flags[i]; + xylonfb_init_layer_regs(ld); + + rc = xylonfb_register_fb(fbi, ld, reg_base_phys, i, ®fb[i]); + if (rc) + goto err_fb; + + fbi->monspecs = afbi[cd->xylonfb_console_layer]->monspecs; + + mutex_init(&ld->layer_mutex); + + /* register following layers in HW configuration order */ + if (active_layer > 0) { + i = -1; /* after for loop increment i will be zero */ + active_layer = -1; + } + + driver_devel( \ + " Layer ID %d\n" \ + " Layer offset %u\n" \ + " Layer buffer offset %hd\n" \ + " Layer buffers %d\n" \ + " Layer width %d pixels\n" \ + " Layer height %d lines\n" \ + " Layer bits per pixel %d\n" \ + " Layer bits per pixel (virtual) %d\n" \ + " Layer FB size %ld bytes\n", \ + (ld->layer_fix.layer_fix_info & 0x0F), + ld->layer_fix.offset, + ld->layer_fix.buffer_offset, + (ld->layer_fix.layer_fix_info >> 4), + ld->layer_fix.width, + ld->layer_fix.height, + ld->layer_fix.bpp, + ld->layer_fix.bpp_virt, + ld->fb_size); + } + + if (ld) { + if (!(cd->xylonfb_flags & LOGICVC_READABLE_REGS)) + cd->reg_access.xylonfb_set_reg_val(0xFFFF, + ld->reg_base_virt, LOGICVC_INT_MASK_ROFF, + ld); + } else { + pr_warn("Warning xylonfb initialization not completed\n"); + } + + cd->xylonfb_bg_layer_bpp = init_data->bg_layer_bpp; + cd->xylonfb_bg_layer_alpha_mode = init_data->bg_layer_alpha_mode; + driver_devel("BG layer %dbpp\n", init_data->bg_layer_bpp); + + cd->xylonfb_irq = irq_res->start; + rc = request_irq(cd->xylonfb_irq, xylonfb_isr, + IRQF_TRIGGER_HIGH, DEVICE_NAME, dev); + if (rc) { + cd->xylonfb_irq = 0; + goto err_fb; + } + +#if defined(__LITTLE_ENDIAN) + cd->xylonfb_flags |= XYLONFB_FLAG_MEMORY_LE; +#endif + mutex_init(&cd->irq_mutex); + init_waitqueue_head(&cd->vsync.wait); + cd->xylonfb_use_ref = 0; + + dev_set_drvdata(dev, (void *)afbi); + + cd->xylonfb_flags &= ~(XYLONFB_FLAG_VMODE_INIT | + XYLONFB_FLAG_DEFAULT_VMODE_SET | XYLONFB_FLAG_VMODE_SET); + xylonfb_mode_option = NULL; + + /* start HW */ + xylonfb_start(afbi, layers); + + return 0; + +err_fb: + if (cd->xylonfb_irq != 0) + free_irq(cd->xylonfb_irq, dev); + for (i = layers-1; i >= 0; i--) { + fbi = afbi[i]; + if (!fbi) + continue; + ld = fbi->par; + if (regfb[i] == 0) + unregister_framebuffer(fbi); + else + regfb[i] = 0; + if (fbi->cmap.red) + fb_dealloc_cmap(&fbi->cmap); + if (ld) { + if (cd->xylonfb_flags & XYLONFB_FLAG_DMA_BUFFER) { + /* NOT USED FOR NOW! */ + dma_free_coherent(dev, + PAGE_ALIGN(fbi->fix.smem_len), + ld->fb_virt, ld->fb_phys); + } else { + if (ld->fb_virt) + iounmap(ld->fb_virt); + } + kfree(ld->layer_reg_list); + kfree(fbi->pseudo_palette); + framebuffer_release(fbi); + } + } + if (reg_base_virt) + iounmap(reg_base_virt); + +err_mem: + if (cd) { + kfree(cd->reg_list); +#if defined(CONFIG_FB_XYLON_MISC) + kfree(cd->xylonfb_misc); +#endif + kfree(cd); + } + kfree(afbi); + + dev_set_drvdata(dev, NULL); + + return rc; +} + +int xylonfb_deinit_driver(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fb_info **afbi = dev_get_drvdata(dev); + struct fb_info *fbi = afbi[0]; + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + void *reg_base_virt = NULL; + int i; + bool logicvc_unmap = false; + + driver_devel("%s\n", __func__); + + if (cd->xylonfb_use_ref) { + pr_err("Error xylonfb in use\n"); + return -EINVAL; + } + + xylonfb_disable_logicvc_output(fbi); + +#if defined(CONFIG_FB_XYLON_MISC) + xylonfb_misc_deinit(fbi); + kfree(cd->xylonfb_misc); +#endif + + free_irq(cd->xylonfb_irq, dev); + for (i = cd->xylonfb_layers-1; i >= 0; i--) { + fbi = afbi[i]; + ld = fbi->par; + + if (!logicvc_unmap) { + reg_base_virt = ld->reg_base_virt; + logicvc_unmap = true; + } + unregister_framebuffer(fbi); + fb_dealloc_cmap(&fbi->cmap); + if (cd->xylonfb_flags & XYLONFB_FLAG_DMA_BUFFER) { + dma_free_coherent(dev, PAGE_ALIGN(fbi->fix.smem_len), + ld->fb_virt, ld->fb_phys); + } else { + iounmap(ld->fb_virt); + } + if (!(cd->xylonfb_flags & LOGICVC_READABLE_REGS)) + kfree(ld->layer_reg_list); + kfree(fbi->pseudo_palette); + framebuffer_release(fbi); + } + + if (reg_base_virt) + iounmap(reg_base_virt); + + if (!(cd->xylonfb_flags & LOGICVC_READABLE_REGS)) + kfree(cd->reg_list); + kfree(cd); + kfree(afbi); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +#ifndef MODULE +int xylonfb_get_params(char *options) +{ + char *this_opt; + + driver_devel("%s\n", __func__); + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + xylonfb_mode_option = this_opt; + } + return 0; +} +#endif Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/xylonfb.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/xylonfb.h 2014-07-20 22:06:38.542269661 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver internal data structures + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __XYLON_FB_DATA_H__ +#define __XYLON_FB_DATA_H__ + + +#include <linux/wait.h> +#include <linux/mutex.h> +#include <linux/notifier.h> +#include <linux/fb.h> +#include <linux/xylonfb.h> +#include "logicvc.h" + + +#define DRIVER_NAME "xylonfb" +#define DEVICE_NAME "logicvc" +#define DRIVER_DESCRIPTION "Xylon logiCVC frame buffer driver" +#define DRIVER_VERSION "2.1" + +/* XylonFB driver flags */ +#define XYLONFB_FLAG_RESERVED_0x01 LOGICVC_READABLE_REGS +#define XYLONFB_FLAG_DMA_BUFFER 0x02 +#define XYLONFB_FLAG_MEMORY_LE 0x04 +#define XYLONFB_FLAG_PIXCLK_VALID 0x08 +#define XYLONFB_FLAG_VMODE_INIT 0x10 +#define XYLONFB_FLAG_EDID_VMODE 0x20 +#define XYLONFB_FLAG_EDID_PRINT 0x40 +#define XYLONFB_FLAG_DEFAULT_VMODE_SET 0x80 +#define XYLONFB_FLAG_VMODE_SET 0x100 +/* + Following flags must be updated in xylonfb miscellaneous + header files for every functionality specifically +*/ +#define XYLONFB_FLAG_MISC_ADV7511 0x1000 +#define XYLONFB_FLAG_ADV7511_SKIP 0x2000 +#define XYLONFB_FLAG_EDID_RDY 0x4000 +#define XYLONFB_EDID_SIZE 256 +#define XYLONFB_EDID_WAIT_TOUT 60 + + +#ifdef DEBUG +#define driver_devel(format, ...) pr_info(format, ## __VA_ARGS__); +#else +#define driver_devel(format, ...) +#endif + +struct xylonfb_layer_data; + +#define VMODE_NAME_SZ (20+1) +#define VMODE_OPTS_SZ (2+1) +struct xylonfb_vmode_data { + u32 ctrl_reg; + struct fb_videomode fb_vmode; + char fb_vmode_name[VMODE_NAME_SZ]; + char fb_vmode_opts_cvt[VMODE_OPTS_SZ]; + char fb_vmode_opts_ext[VMODE_OPTS_SZ]; +}; + +struct xylonfb_registers { + u32 ctrl_reg; + u32 dtype_reg; + u32 bg_reg; + u32 unused_reg[3]; + u32 int_mask_reg; +}; + +struct xylonfb_layer_registers { + u32 hoff_reg; + u32 voff_reg; + u32 hpos_reg; + u32 vpos_reg; + u32 width_reg; + u32 height_reg; + u32 alpha_reg; + u32 ctrl_reg; + u32 trans_reg; +}; + +struct xylonfb_register_access { + u32 (*xylonfb_get_reg_val) + (void *reg_base_virt, unsigned long offset, + struct xylonfb_layer_data *layer_data); + void (*xylonfb_set_reg_val) + (u32 value, void *reg_base_virt, unsigned long offset, + struct xylonfb_layer_data *layer_data); +}; + +struct xylonfb_layer_fix_data { + unsigned int offset; + unsigned short buffer_offset; + unsigned short width; + unsigned short height; + unsigned char bpp; + unsigned char bpp_virt; + unsigned char layer_type; + unsigned char alpha_mode; + /* higher 4 bits: number of layer buffers, lower 4 bits: layer ID */ + unsigned char layer_fix_info; +}; + +struct xylonfb_sync { + wait_queue_head_t wait; + unsigned int cnt; +}; + +struct xylonfb_common_data { + struct mutex irq_mutex; + struct xylonfb_register_access reg_access; + struct xylonfb_registers *reg_list; + struct xylonfb_sync vsync; + struct xylonfb_vmode_data vmode_data; + struct xylonfb_vmode_data vmode_data_current; + struct blocking_notifier_head xylonfb_notifier_list; + struct notifier_block xylonfb_nb; + /* Delay after applying display power and + before applying display signals */ + unsigned int power_on_delay; + /* Delay after applying display signal and + before applying display backlight power supply */ + unsigned int signal_on_delay; + unsigned long xylonfb_flags; + unsigned char xylonfb_pixclk_src_id; + unsigned char xylonfb_layers; + unsigned char xylonfb_irq; + unsigned char xylonfb_use_ref; + unsigned char xylonfb_console_layer; + unsigned char xylonfb_bg_layer_bpp; + unsigned char xylonfb_bg_layer_alpha_mode; + /* higher 4 bits: display interface + lower 4 bits: display color space */ + unsigned char xylonfb_display_interface_type; +#if defined(CONFIG_FB_XYLON_MISC) + struct xylonfb_misc_data *xylonfb_misc; +#endif +}; + +struct xylonfb_layer_data { + struct xylonfb_common_data *xylonfb_cd; + struct mutex layer_mutex; + dma_addr_t reg_base_phys; + dma_addr_t fb_phys; + void *reg_base_virt; + void *fb_virt; + unsigned long fb_size; + void *layer_reg_base_virt; + void *layer_clut_base_virt; + struct xylonfb_layer_fix_data layer_fix; + struct xylonfb_layer_registers *layer_reg_list; + unsigned char layer_ctrl_flags; + unsigned char layer_use_ref; +}; + +struct xylonfb_init_data { + struct platform_device *pdev; + struct xylonfb_vmode_data vmode_data; + struct xylonfb_layer_fix_data lfdata[LOGICVC_MAX_LAYERS]; + unsigned long vmem_base_addr; + unsigned long vmem_high_addr; + unsigned char pixclk_src_id; + unsigned char layer_ctrl_flags[LOGICVC_MAX_LAYERS]; + unsigned char layers; + unsigned char active_layer; + unsigned char bg_layer_bpp; + unsigned char bg_layer_alpha_mode; + unsigned char display_interface_type; + unsigned short flags; + bool vmode_params_set; +}; + + +/* xylonfb core pixel clock interface functions */ +extern bool xylonfb_hw_pixclk_supported(int); +extern int xylonfb_hw_pixclk_set(int, unsigned long); + +/* xylonfb core interface functions */ +extern int xylonfb_get_params(char *options); +extern int xylonfb_init_driver(struct xylonfb_init_data *init_data); +extern int xylonfb_deinit_driver(struct platform_device *pdev); +extern int xylonfb_ioctl(struct fb_info *fbi, + unsigned int cmd, unsigned long arg); + +#endif /* __XYLON_FB_DATA_H__ */ Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/xylonfb-ioctl.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/xylonfb-ioctl.c 2014-07-20 22:06:38.553269479 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver IOCTL functionality + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/uaccess.h> +#include "logicvc.h" +#include "xylonfb.h" +#if defined(CONFIG_FB_XYLON_MISC) +#include "../misc/xylonfb-misc.h" +#endif + + +static int xylonfb_get_vblank(struct fb_vblank *vblank, struct fb_info *fbi) +{ + vblank->flags |= FB_VBLANK_HAVE_VSYNC; + + return 0; +} + +static int xylonfb_wait_for_vsync(u32 crt, struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + u32 imr; + int ret, cnt; + + mutex_lock(&cd->irq_mutex); + + cnt = cd->vsync.cnt; + + /* prepare LOGICVC V-sync interrupt */ + imr = cd->reg_access.xylonfb_get_reg_val( + ld->reg_base_virt, LOGICVC_INT_MASK_ROFF, ld); + imr &= (~LOGICVC_V_SYNC_INT); + /* clear LOGICVC V-sync interrupt */ + writel(LOGICVC_V_SYNC_INT, + ld->reg_base_virt + LOGICVC_INT_STAT_ROFF); + /* enable LOGICVC V-sync interrupt */ + cd->reg_access.xylonfb_set_reg_val(imr, + ld->reg_base_virt, LOGICVC_INT_MASK_ROFF, ld); + + ret = wait_event_interruptible_timeout(cd->vsync.wait, + (cnt != cd->vsync.cnt), HZ/10); + + /* disable LOGICVC V-sync interrupt */ + imr |= LOGICVC_V_SYNC_INT; + cd->reg_access.xylonfb_set_reg_val(imr, + ld->reg_base_virt, LOGICVC_INT_MASK_ROFF, ld); + + mutex_unlock(&cd->irq_mutex); + + if (ret < 0) + return ret; + else if (ret == 0) + return -ETIMEDOUT; + + return 0; +} + +static unsigned int alpha_normalized(unsigned int alpha, + unsigned int used_bits, bool get) +{ + if (get) + return (((255 << 16) / ((1 << used_bits)-1)) * alpha) >> 16; + else + return alpha / (255 / ((1 << used_bits)-1)); +} + +static int xylonfb_layer_alpha(struct xylonfb_layer_data *ld, + unsigned int *alpha, bool get) +{ + struct xylonfb_common_data *cd = ld->xylonfb_cd; + unsigned int used_bits; + + if (ld->layer_fix.alpha_mode != LOGICVC_LAYER_ALPHA) + return -EPERM; + + switch (ld->layer_fix.layer_type) { + case LOGICVC_YCBCR_LAYER: + used_bits = 8; + break; + case LOGICVC_RGB_LAYER: + switch (ld->layer_fix.bpp_virt) { + case 8: + used_bits = 3; + break; + case 16: + used_bits = 6; + break; + case 32: + used_bits = 8; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + if (get) { + *alpha = cd->reg_access.xylonfb_get_reg_val( + ld->layer_reg_base_virt, LOGICVC_LAYER_ALPHA_ROFF, ld); + *alpha &= (0xFF >> (8-used_bits)); + } + + /* get/set normalized alpha value */ + *alpha = alpha_normalized(*alpha, used_bits, get); + + if (!get) + cd->reg_access.xylonfb_set_reg_val(*alpha, + ld->layer_reg_base_virt, LOGICVC_LAYER_ALPHA_ROFF, ld); + + return 0; +} + +static int xylonfb_layer_color_rgb(struct xylonfb_layer_data *ld, + struct xylonfb_layer_color *layer_color, unsigned int reg_offset, + bool get) +{ + struct xylonfb_common_data *cd = ld->xylonfb_cd; + void *base; + u32 raw_rgb, r, g, b; + int bpp, alpha_mode; + + if (reg_offset == LOGICVC_LAYER_TRANSP_ROFF) { + base = ld->layer_reg_base_virt; + bpp = ld->layer_fix.bpp_virt; + alpha_mode = ld->layer_fix.alpha_mode; + } else /* if (reg_offset == LOGICVC_BACKCOL_ROFF) */ { + base = ld->reg_base_virt; + bpp = ld->xylonfb_cd->xylonfb_bg_layer_bpp; + alpha_mode = ld->xylonfb_cd->xylonfb_bg_layer_alpha_mode; + } + + if (get) { + raw_rgb = cd->reg_access.xylonfb_get_reg_val( + base, reg_offset, ld); +check_bpp_get: + /* convert HW color format to RGB-888 */ + switch (bpp) { + case 8: + switch (alpha_mode) { + case LOGICVC_CLUT_16BPP_ALPHA: + /* RGB-565 */ + bpp = 16; + goto check_bpp_get; + break; + case LOGICVC_CLUT_32BPP_ALPHA: + /* RGB-888 */ + bpp = 32; + goto check_bpp_get; + break; + default: + /* RGB-332 */ + r = raw_rgb >> 5; + r = (((r << 3) | r) << 2) | (r >> 1); + g = (raw_rgb >> 2) & 0x07; + g = (((g << 3) | g) << 2) | (g >> 1); + b = raw_rgb & 0x03; + b = (b << 6) | (b << 4) | (b << 2) | b; + break; + } + break; + case 16: + /* RGB-565 */ + r = raw_rgb >> 11; + r = (r << 3) | (r >> 2); + g = (raw_rgb >> 5) & 0x3F; + g = (g << 2) | (g >> 4); + b = raw_rgb & 0x1F; + b = (b << 3) | (b >> 2); + break; + case 32: + /* RGB-888 */ + r = raw_rgb >> 16; + g = (raw_rgb >> 8) & 0xFF; + b = raw_rgb & 0xFF; + break; + default: + raw_rgb = r = g = b = 0; + } + layer_color->raw_rgb = raw_rgb; + layer_color->r = (u8)r; + layer_color->g = (u8)g; + layer_color->b = (u8)b; + } else { + if (layer_color->use_raw) { + raw_rgb = layer_color->raw_rgb; + } else { + r = layer_color->r; + g = layer_color->g; + b = layer_color->b; +check_bpp_set: + /* convert RGB-888 to HW color format */ + switch (bpp) { + case 8: + switch (alpha_mode) { + case LOGICVC_CLUT_16BPP_ALPHA: + /* RGB-565 */ + bpp = 16; + goto check_bpp_set; + break; + case LOGICVC_CLUT_32BPP_ALPHA: + /* RGB-888 */ + bpp = 32; + goto check_bpp_set; + break; + default: + raw_rgb = + (r & 0xE0) | + ((g & 0xE0) >> 3) | + ((b & 0xC0) >> 6); + break; + } + break; + case 16: + raw_rgb = + ((r & 0xF8) << 8) | + ((g & 0xFC) << 3) | + ((b & 0xF8) >> 3); + break; + case 32: + raw_rgb = + (r << 16) | + (g << 8) | + b; + break; + default: + raw_rgb = 0; + } + } + cd->reg_access.xylonfb_set_reg_val(raw_rgb, + base, reg_offset, ld); + } + + return 0; +} + +static int xylonfb_layer_pos_sz(struct fb_info *fbi, + struct xylonfb_layer_pos_size *layer_pos_sz, bool get) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + u32 x, y, width, height, xres, yres; + + xres = fbi->var.xres; + yres = fbi->var.yres; + + if (get) { + x = cd->reg_access.xylonfb_get_reg_val( + ld->layer_reg_base_virt, LOGICVC_LAYER_HOR_POS_ROFF, ld); + layer_pos_sz->x = xres - (x + 1); + y = cd->reg_access.xylonfb_get_reg_val( + ld->layer_reg_base_virt, LOGICVC_LAYER_VER_POS_ROFF, ld); + layer_pos_sz->y = yres - (y + 1); + layer_pos_sz->width = cd->reg_access.xylonfb_get_reg_val( + ld->layer_reg_base_virt, LOGICVC_LAYER_WIDTH_ROFF, ld); + layer_pos_sz->width += 1; + layer_pos_sz->height = cd->reg_access.xylonfb_get_reg_val( + ld->layer_reg_base_virt, LOGICVC_LAYER_HEIGHT_ROFF, ld); + layer_pos_sz->height += 1; + } else { + x = layer_pos_sz->x; + y = layer_pos_sz->y; + width = layer_pos_sz->width; + height = layer_pos_sz->height; + + if ((x > xres) || (y > yres)) + return -EINVAL; + + if ((width == 0) || (height == 0)) + return -EINVAL; + + if ((x + width) > xres) { + width = xres - x; + layer_pos_sz->width = width; + } + if ((y + height) > yres) { + height = yres - y; + layer_pos_sz->height = height; + } + /* YCbCr 4:2:2 layer type can only have even layer width */ + if ((width > 2) + && + (ld->layer_fix.layer_type == LOGICVC_YCBCR_LAYER) + && + (ld->layer_fix.bpp_virt == 16)) { + width &= ~1; + } + + cd->reg_access.xylonfb_set_reg_val((width - 1), + ld->layer_reg_base_virt, LOGICVC_LAYER_WIDTH_ROFF, ld); + cd->reg_access.xylonfb_set_reg_val((height - 1), + ld->layer_reg_base_virt, LOGICVC_LAYER_HEIGHT_ROFF, ld); + cd->reg_access.xylonfb_set_reg_val((xres - (x + 1)), + ld->layer_reg_base_virt, LOGICVC_LAYER_HOR_POS_ROFF, ld); + cd->reg_access.xylonfb_set_reg_val((yres - (y + 1)), + ld->layer_reg_base_virt, LOGICVC_LAYER_VER_POS_ROFF, ld); + } + + return 0; +} + +static int xylonfb_layer_reg_access( + struct xylonfb_layer_data *ld, + struct xylonfb_common_data *cd, + struct xylonfb_hw_access *hw_access, + bool read) +{ + u32 rel_offset; + + if ((hw_access->offset < LOGICVC_LAYER_BASE_OFFSET) || + (hw_access->offset > LOGICVC_LAYER_BASE_END)) + return -EPERM; + + rel_offset = hw_access->offset - + ((ld->layer_fix.layer_fix_info & 0x0F) * 0x80) - + LOGICVC_LAYER_BASE_OFFSET; + + if (read) { + hw_access->value = cd->reg_access.xylonfb_get_reg_val( + ld->layer_reg_base_virt, rel_offset, ld); + } else { + cd->reg_access.xylonfb_set_reg_val(hw_access->value, + ld->layer_reg_base_virt, rel_offset, ld); + } + + return 0; +} + +int xylonfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + union { + struct fb_vblank vblank; + struct xylonfb_layer_color layer_color; + struct xylonfb_layer_pos_size layer_pos_sz; + struct xylonfb_hw_access hw_access; + } ioctl; + void __user *argp = (void __user *)arg; + u32 var32; + unsigned long val, layer_buffs, layer_id; + int ret = 0; + + switch (cmd) { + case FBIOGET_VBLANK: + driver_devel("FBIOGET_VBLANK\n"); + if (copy_from_user(&ioctl.vblank, argp, sizeof(ioctl.vblank))) + return -EFAULT; + ret = xylonfb_get_vblank(&ioctl.vblank, fbi); + if (!ret && copy_to_user(argp, &ioctl.vblank, sizeof(ioctl.vblank))) + ret = -EFAULT; + break; + + case FBIO_WAITFORVSYNC: + driver_devel("FBIO_WAITFORVSYNC\n"); + if (get_user(var32, (u32 __user *)arg)) + return -EFAULT; + ret = xylonfb_wait_for_vsync(var32, fbi); + break; + + case XYLONFB_GET_LAYER_IDX: + driver_devel("XYLONFB_GET_LAYER_IDX\n"); + val = ld->layer_fix.layer_fix_info & 0x0F; + put_user(val, (unsigned long __user *)arg); + break; + + case XYLONFB_GET_LAYER_ALPHA: + driver_devel("XYLONFB_GET_LAYER_ALPHA\n"); + ret = xylonfb_layer_alpha(ld, (unsigned int *)&val, true); + if (!ret) + put_user(val, (unsigned long __user *)arg); + break; + + case XYLONFB_SET_LAYER_ALPHA: + driver_devel("XYLONFB_SET_LAYER_ALPHA\n"); + if (get_user(val, (unsigned long __user *)arg)) + return -EFAULT; + mutex_lock(&ld->layer_mutex); + ret = xylonfb_layer_alpha(ld, (unsigned int *)&val, false); + mutex_unlock(&ld->layer_mutex); + break; + + case XYLONFB_LAYER_COLOR_TRANSP: + driver_devel("XYLONFB_LAYER_COLOR_TRANSP\n"); + if (get_user(val, (unsigned long __user *)arg)) + return -EFAULT; + mutex_lock(&ld->layer_mutex); + var32 = cd->reg_access.xylonfb_get_reg_val( + ld->layer_reg_base_virt, LOGICVC_LAYER_CTRL_ROFF, ld); + if (val) + var32 |= (1 << 1); /* transparency disabled */ + else + var32 &= ~(1 << 1); /* transparency enabled */ + cd->reg_access.xylonfb_set_reg_val(var32, + ld->layer_reg_base_virt, LOGICVC_LAYER_CTRL_ROFF, ld); + mutex_unlock(&ld->layer_mutex); + break; + + case XYLONFB_GET_LAYER_COLOR_TRANSP: + driver_devel("XYLONFB_GET_LAYER_COLOR_TRANSP\n"); + if (copy_from_user(&ioctl.layer_color, argp, + sizeof(ioctl.layer_color))) + return -EFAULT; + ret = xylonfb_layer_color_rgb(ld, &ioctl.layer_color, + LOGICVC_LAYER_TRANSP_ROFF, true); + if (!ret) + if (copy_to_user(argp, &ioctl.layer_color, + sizeof(ioctl.layer_color))) + ret = -EFAULT; + break; + + case XYLONFB_SET_LAYER_COLOR_TRANSP: + driver_devel("XYLONFB_SET_LAYER_COLOR_TRANSP\n"); + if (copy_from_user(&ioctl.layer_color, argp, + sizeof(ioctl.layer_color))) + return -EFAULT; + mutex_lock(&ld->layer_mutex); + ret = xylonfb_layer_color_rgb(ld, &ioctl.layer_color, + LOGICVC_LAYER_TRANSP_ROFF, false); + mutex_unlock(&ld->layer_mutex); + break; + + case XYLONFB_GET_LAYER_SIZE_POS: + driver_devel("XYLONFB_GET_LAYER_SIZE_POS\n"); + if (copy_from_user(&ioctl.layer_pos_sz, argp, + sizeof(ioctl.layer_pos_sz))) + return -EFAULT; + ret = xylonfb_layer_pos_sz(fbi, &ioctl.layer_pos_sz, true); + if (!ret) + if (copy_to_user(argp, &ioctl.layer_pos_sz, + sizeof(ioctl.layer_pos_sz))) + ret = -EFAULT; + break; + + case XYLONFB_SET_LAYER_SIZE_POS: + driver_devel("XYLONFB_SET_LAYER_SIZE_POS\n"); + if (copy_from_user(&ioctl.layer_pos_sz, argp, + sizeof(ioctl.layer_pos_sz))) + return -EFAULT; + mutex_lock(&ld->layer_mutex); + ret = xylonfb_layer_pos_sz(fbi, &ioctl.layer_pos_sz, false); + if (!ret) + if (copy_to_user(argp, &ioctl.layer_pos_sz, + sizeof(ioctl.layer_pos_sz))) + ret = -EFAULT; + mutex_unlock(&ld->layer_mutex); + break; + + case XYLONFB_GET_LAYER_BUFFER: + driver_devel("XYLONFB_GET_LAYER_BUFFER\n"); + layer_id = ld->layer_fix.layer_fix_info & 0x0F; + var32 = readl(ld->reg_base_virt + LOGICVC_DOUBLE_VBUFF_ROFF); + var32 >>= ((layer_id << 1)); /* get buffer */ + val = var32 & 0x03; + put_user(val, (unsigned long __user *)arg); + break; + + case XYLONFB_SET_LAYER_BUFFER: + driver_devel("XYLONFB_SET_LAYER_BUFFER\n"); + if (get_user(val, (unsigned long __user *)arg)) + return -EFAULT; + layer_buffs = ld->layer_fix.layer_fix_info >> 4; + if (val >= layer_buffs) + return -EINVAL; + layer_id = ld->layer_fix.layer_fix_info & 0x0F; + mutex_lock(&ld->layer_mutex); + var32 = readl(ld->reg_base_virt + LOGICVC_DOUBLE_VBUFF_ROFF); + var32 |= (1 << (10 + layer_id)); /* set layer */ + var32 &= ~(0x03 << (layer_id << 1)); /* clear previous buffer */ + var32 |= (val << (layer_id << 1)); /* set buffer */ + writel(var32, ld->reg_base_virt + LOGICVC_DOUBLE_VBUFF_ROFF); + ret = xylonfb_wait_for_vsync(var32, fbi); + mutex_unlock(&ld->layer_mutex); + break; + + case XYLONFB_GET_LAYER_BUFFER_OFFSET: + driver_devel("XYLONFB_GET_LAYER_BUFFER_OFFSET\n"); + layer_id = ld->layer_fix.layer_fix_info & 0x0F; + var32 = readl(ld->reg_base_virt + LOGICVC_DOUBLE_VBUFF_ROFF); + var32 >>= ((layer_id << 1)); /* get buffer */ + var32 &= 0x03; + val = ld->layer_fix.buffer_offset; + val *= var32; + put_user(val, (unsigned long __user *)arg); + break; + + case XYLONFB_GET_LAYER_BUFFERS_NUM: + driver_devel("XYLONFB_GET_LAYER_BUFFERS_NUM\n"); + layer_buffs = ld->layer_fix.layer_fix_info >> 4; + put_user(layer_buffs, (unsigned long __user *)arg); + break; + + case XYLONFB_GET_BACKGROUND_COLOR: + driver_devel("XYLONFB_GET_BACKGROUND_COLOR\n"); + if (ld->xylonfb_cd->xylonfb_bg_layer_bpp == 0) + return -EPERM; + if (copy_from_user(&ioctl.layer_color, argp, + sizeof(ioctl.layer_color))) + return -EFAULT; + ret = xylonfb_layer_color_rgb(ld, &ioctl.layer_color, + LOGICVC_BACKCOL_ROFF, true); + if (!ret) + if (copy_to_user(argp, &ioctl.layer_color, + sizeof(ioctl.layer_color))) + ret = -EFAULT; + break; + + case XYLONFB_SET_BACKGROUND_COLOR: + driver_devel("XYLONFB_SET_BACKGROUND_COLOR\n"); + if (ld->xylonfb_cd->xylonfb_bg_layer_bpp == 0) + return -EPERM; + if (copy_from_user(&ioctl.layer_color, argp, + sizeof(ioctl.layer_color))) + return -EFAULT; + mutex_lock(&ld->layer_mutex); + ret = xylonfb_layer_color_rgb(ld, &ioctl.layer_color, + LOGICVC_BACKCOL_ROFF, false); + mutex_unlock(&ld->layer_mutex); + break; + + case XYLONFB_LAYER_EXT_BUFF_SWITCH: + driver_devel("XYLONFB_LAYER_EXT_BUFF_SWITCH\n"); + if (get_user(val, (unsigned long __user *)arg)) + return -EFAULT; + mutex_lock(&ld->layer_mutex); + var32 = cd->reg_access.xylonfb_get_reg_val( + ld->layer_reg_base_virt, LOGICVC_LAYER_CTRL_ROFF, ld); + if (val) + var32 |= (1 << 2); + else + var32 &= ~(1 << 2); + cd->reg_access.xylonfb_set_reg_val(var32, + ld->layer_reg_base_virt, LOGICVC_LAYER_CTRL_ROFF, ld); + mutex_unlock(&ld->layer_mutex); + break; + + case XYLONFB_READ_HW_REG: + driver_devel("XYLONFB_READ_HW_REG\n"); + if (copy_from_user(&ioctl.hw_access, argp, + sizeof(ioctl.hw_access))) + return -EFAULT; + if (cd->xylonfb_flags & LOGICVC_READABLE_REGS) { + ioctl.hw_access.value = + cd->reg_access.xylonfb_get_reg_val( + ld->reg_base_virt, ioctl.hw_access.offset, ld); + } else { + ret = xylonfb_layer_reg_access(ld, cd, &ioctl.hw_access, true); + if (ret) + break; + } + if (copy_to_user(argp, &ioctl.hw_access, + sizeof(ioctl.hw_access))) + ret = -EFAULT; + break; + + case XYLONFB_WRITE_HW_REG: + driver_devel("XYLONFB_WRITE_HW_REG\n"); + if (copy_from_user(&ioctl.hw_access, argp, + sizeof(ioctl.hw_access))) + return -EFAULT; + if (cd->xylonfb_flags & LOGICVC_READABLE_REGS) { + cd->reg_access.xylonfb_set_reg_val(ioctl.hw_access.value, + ld->reg_base_virt, ioctl.hw_access.offset, ld); + } else { + ret = xylonfb_layer_reg_access(ld, cd, &ioctl.hw_access, false); + if (ret) + break; + } + if (copy_to_user(argp, &ioctl.hw_access, + sizeof(ioctl.hw_access))) + ret = -EFAULT; + break; + + case XYLONFB_WAIT_EDID: + driver_devel("XYLONFB_WAIT_EDID\n"); +#if defined(CONFIG_FB_XYLON_MISC) + if (cd->xylonfb_flags & XYLONFB_FLAG_EDID_RDY) + break; + if (get_user(val, (unsigned long __user *)arg)) + return -EFAULT; + if ((val == 0) || (val < 0)) + val = XYLONFB_EDID_WAIT_TOUT; + ret = wait_event_interruptible_timeout(cd->xylonfb_misc->wait, + (cd->xylonfb_flags & XYLONFB_FLAG_EDID_RDY), (val * HZ)); + if (ret == 0) + return -ETIMEDOUT; + else + ret = 0; +#else + return -EPERM; +#endif + break; + + case XYLONFB_GET_EDID: + driver_devel("XYLONFB_GET_EDID\n"); +#if defined(CONFIG_FB_XYLON_MISC) + if (cd->xylonfb_flags & XYLONFB_FLAG_EDID_RDY) { + if (cd->xylonfb_misc->edid) { + if (copy_to_user(argp, cd->xylonfb_misc->edid, + XYLONFB_EDID_SIZE)) + ret = -EFAULT; + } else { + return -EPERM; + } + } else { + return -EPERM; + } +#else + return -EPERM; +#endif + break; + + default: + driver_devel("UNKNOWN_IOCTL\n"); + ret = -EINVAL; + } + + return ret; +} Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/xylonfb-pixclk.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/core/xylonfb-pixclk.c 2014-07-20 22:06:38.561269347 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver pixel clock generation + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +/* + * This file implements HW dependent functionality for controlling pixel clock + * generation on various HW platforms. + */ + + +#include <linux/kernel.h> + + +#define XYLONFB_PIXCLK_GEN_DEVS 8 + +static int (*xylonfb_hw_pixclk_set_fn[XYLONFB_PIXCLK_GEN_DEVS])(unsigned long); +static bool xylonfb_hw_pixclk_init; + +#if defined(CONFIG_FB_XYLON_PIXCLK_ZYNQ_PS) + +#define XYLONFB_PIXCLK_ZYNQ_PS 1 + +#include <linux/io.h> +#include <linux/errno.h> + +int xylonfb_hw_pixclk_set_zynq_ps(unsigned long pixclk_khz) +{ + unsigned long pllclk, sysclk; + unsigned long div, delta, delta_dec, delta_inc; + void *slcr_regs, *clk_regs, *rst_reg; + + /* all clock values are in kHz */ + pllclk = 1000000; + sysclk = 100000; + + slcr_regs = ioremap_nocache(0xF8000004, 8); + if (!slcr_regs) { + pr_err("Error mapping SLCR\n"); + return -EBUSY; + } + clk_regs = ioremap_nocache(0xF8000170, 32); + if (!clk_regs) { + pr_err("Error setting xylonfb pixelclock\n"); + iounmap(slcr_regs); + return -EBUSY; + } + rst_reg = ioremap_nocache(0xF8000240, 4); + if (!rst_reg) { + pr_err("Error setting xylonfb pixelclock\n"); + iounmap(clk_regs); + iounmap(slcr_regs); + return -EBUSY; + } + + /* unlock register access */ + writel(0xDF0D, (slcr_regs+4)); +#if 0 + /* calculate system clock divisor */ + div = pllclk / sysclk; + /* prepare for register writting */ + div = (div + 0x1000) << 8; + /* set system clock */ + writel(div, clk_regs); + /* calculate video clock divisor */ +#endif + div = pllclk / pixclk_khz; + delta = (pllclk / div) - pixclk_khz; + if (delta != 0) { + delta_inc = pixclk_khz - (pllclk / (div+1)); + delta_dec = (pllclk / (div-1)) - pixclk_khz; + if (delta < delta_inc) { + if (delta > delta_dec) + div--; +#if 0 + else + div = div; +#endif + } else { + if (delta > delta_dec) { + if (delta_inc > delta_dec) + div--; + else + div++; + } else { + div++; + } + } + } + /* prepare for register writting */ + div = (div + 0x1000) << 8; + /* set video clock */ + writel(div, (clk_regs+0x10)); + /* lock register access */ + writel(0x767B, slcr_regs); + + iounmap(rst_reg); + iounmap(clk_regs); + iounmap(slcr_regs); + + return 0; +} + +#endif /* #if defined(CONFIG_FB_XYLON_PIXCLK_ZYNQ_PS) */ + +#if defined(CONFIG_FB_XYLON_PIXCLK_LOGICLK) + +#define XYLONFB_PIXCLK_LOGICLK 2 + +#include <linux/io.h> +#include <linux/errno.h> +#include <linux/delay.h> +#ifdef CONFIG_OF +/* For open firmware. */ +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#endif +#include "logiclk.h" + +int xylonfb_hw_pixclk_set_logiclk(unsigned long pixclk_khz) +{ +#ifdef CONFIG_OF + struct device_node *dn; + const unsigned int *val; + int len; +#endif + u32 *logiclk_regs; + struct logiclk_freq_out freq_out; + u32 logiclk[LOGICLK_REGS]; + u32 address, osc_freq_hz; + int i, size; + + address = 0x40010000; + size = LOGICLK_REGS * sizeof(u32); + osc_freq_hz = 100000000; + +#ifdef CONFIG_OF + dn = of_find_node_by_name(NULL, "logiclk"); + if (dn) { + val = of_get_property(dn, "reg", &len); + address = be32_to_cpu(val[0]); + size = be32_to_cpu(val[1]); + val = of_get_property(dn, "osc-clk-freq-hz", &len); + osc_freq_hz = be32_to_cpu(val[0]); + } +#endif + + logiclk_regs = ioremap_nocache(address, size); + if (!logiclk_regs) { + pr_err("Error mapping logiCLK\n"); + return -EBUSY; + } + + for (i = 0; i < LOGICLK_OUTPUTS; i++) + freq_out.freq_out_hz[i] = pixclk_khz * 1000; + + if (logiclk_calc_regs(&freq_out, osc_freq_hz, logiclk)) { + pr_err("Error calculating logiCLK parameters\n"); + return -EINVAL; + } + writel(1, logiclk_regs+LOGICLK_RST_REG_OFF); + udelay(10); + writel(0, logiclk_regs+LOGICLK_RST_REG_OFF); + + for (i = 0; i < LOGICLK_REGS; i++) + writel(logiclk[i], logiclk_regs+LOGICLK_PLL_MANUAL_REG_OFF+i); + + while (1) { + if (readl(logiclk_regs+LOGICLK_PLL_REG_OFF) & LOGICLK_PLL_RDY) { + writel((LOGICLK_PLL_REG_EN | LOGICLK_PLL_EN), + logiclk_regs+LOGICLK_PLL_REG_OFF); + break; + } + } + + iounmap(logiclk_regs); + + return 0; +} + +#endif /* #if defined(CONFIG_FB_XYLON_PIXCLK_LOGICLK) */ + +#if defined(CONFIG_FB_XYLON_PIXCLK_SI570) + +#define XYLONFB_PIXCLK_SI570 3 + +#include <linux/i2c/si570.h> + +int xylonfb_hw_pixclk_set_si570(unsigned long pixclk_khz) +{ + struct i2c_client *si570_client; + + si570_client = get_i2c_client_si570(); + if (si570_client) + return set_frequency_si570(&si570_client->dev, (pixclk_khz * 1000)); + else + return -EPERM; +} + +#endif /* #if defined(CONFIG_FB_XYLON_PIXCLK_SI570) */ + + +bool xylonfb_hw_pixclk_supported(int id) +{ + if (!xylonfb_hw_pixclk_init) { +#if defined(XYLONFB_PIXCLK_ZYNQ_PS) + xylonfb_hw_pixclk_set_fn[XYLONFB_PIXCLK_ZYNQ_PS] = + xylonfb_hw_pixclk_set_zynq_ps; +#endif +#if defined(XYLONFB_PIXCLK_LOGICLK) + xylonfb_hw_pixclk_set_fn[XYLONFB_PIXCLK_LOGICLK] = + xylonfb_hw_pixclk_set_logiclk; +#endif +#if defined(XYLONFB_PIXCLK_SI570) + xylonfb_hw_pixclk_set_fn[XYLONFB_PIXCLK_SI570] = + xylonfb_hw_pixclk_set_si570; +#endif + xylonfb_hw_pixclk_init = true; + } + + return xylonfb_hw_pixclk_set_fn[id] ? true : false; +} + +#if !defined(CONFIG_FB_XYLON_PIXCLK) + +int xylonfb_hw_pixclk_set(int id, unsigned long pixclk_khz) +{ + pr_info("Pixel clock change not supported\n"); + return 0; +} + +#else + +int xylonfb_hw_pixclk_set(int id, unsigned long pixclk_khz) +{ + return xylonfb_hw_pixclk_set_fn[id](pixclk_khz); +} + +#endif /* #if defined(CONFIG_FB_XYLON_PIXCLK) */ Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/Kconfig 2014-07-20 22:06:38.567269248 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +menuconfig FB_XYLON + tristate "Xylon logiCVC frame buffer support" + depends on FB + default n + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + Choose this option if you want to use the Xylon logiCVC as frame + buffer device. Without the support of PCI & AGP. + +choice + prompt "Xylon frame buffer driver type" + depends on FB_XYLON + default FB_XYLON_PLATFORM + +config FB_XYLON_PLATFORM + bool "Xylon logiCVC frame buffer platform driver" + help + Choose this option if you want to use the Xylon frame buffer driver + as platform driver type. This is usefull if OpenFirmware support is + not compiled in the kernel. + This is default selection. + +config FB_XYLON_OF + bool "Xylon logiCVC frame buffer Open Firmware driver" + help + Choose this option if you want to use the Xylon frame buffer driver + as Open Firmware driver type. Driver reads hardware configuration + from Device Tree Blob binary file which must be loaded to + system memory. +endchoice + +config FB_XYLON_PIXCLK + bool "Xylon logiCVC pixel clock" + depends on FB_XYLON + default n + help + logiCVC pixel clock generated from: + - External generator not controllable by Xylon framebuffer driver + This is default selection. + - Generators controllable by Xylon framebuffer driver + +config FB_XYLON_PIXCLK_ZYNQ_PS + bool "Zynq PS PLL pixel clock generator" + depends on FB_XYLON && FB_XYLON_PIXCLK + default n + help + Support for controlling pixel clock generation from + Zynq-PS internal PLL clock generator. + +config FB_XYLON_PIXCLK_LOGICLK + bool "Xylon logiCLK pixel clock generator" + depends on FB_XYLON && FB_XYLON_PIXCLK + default n + help + Support for controlling pixel clock generation from + Xylon logiCLK FGPA IP core. + +config FB_XYLON_PIXCLK_SI570 + bool "SI570 pixel clock generator" + depends on FB_XYLON && FB_XYLON_PIXCLK + default n + select SYSFS + select I2C + select MISC_DEVICES + select SI570 + help + Support for controlling pixel clock generation from + SI570 clock generator. + +menuconfig FB_XYLON_MISC + bool "Xylon logiCVC frame buffer miscellaneous support" + depends on FB_XYLON + default n + help + Choose this option if you want to use the Xylon logiCVC with + miscellaneous device functionality for various improvements. + Currently supported: + - ADV7511 HDMI transmitter + +config FB_XYLON_MISC_ADV7511 + bool "Xylon logiCVC frame buffer ADV7511" + depends on FB_XYLON_MISC && VIDEO_ADV7511 + select FB_MODE_HELPERS + default n + ---help--- + Support for ADV7511 HDMI transmitter so that logiCVC can be configured + with parameters read from monitor EDID. Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/Makefile 2014-07-20 22:06:38.590268869 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ +obj-$(CONFIG_FB_XYLON_OF) += of/ +obj-$(CONFIG_FB_XYLON_PLATFORM) += platform/ Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/misc/xylonfb-adv7511.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/misc/xylonfb-adv7511.c 2014-07-20 22:06:38.605268622 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver miscellaneous ADV7511 functionality + * interface for V4L2 adv7511 (Copyright 2012 Cisco Systems, Inc. + * and/or its affiliates) driver + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/interrupt.h> +#include <linux/atomic.h> +#include <linux/workqueue.h> +#include <linux/completion.h> +#include <linux/console.h> +#include <linux/notifier.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/adv7511.h> +#include "xylonfb-misc.h" +#include "xylonfb-adv7511.h" + + +#define ADV7511_NAME "adv7511" +#define ADV7511_FLAG_INIT 0x01 + + +struct xylonfb_adv7511 { + atomic_t edid_lock; + struct completion edid_done; + struct v4l2_device v4l2_dev; + struct v4l2_subdev *sd; + struct work_struct irq_work; + struct workqueue_struct *irq_work_queue; + struct fb_info *fbi; + struct fb_var_screeninfo *var_screeninfo; + struct fb_monspecs *monspecs; + wait_queue_head_t *misc_wait; + unsigned long *xfb_flags; + unsigned long timeout; + unsigned char flags; + u8 edid[256]; +}; + + +static struct xylonfb_adv7511 *xfb_adv7511; + + +static void xylonfb_adv7511_get_monspecs(u8 *edid, + struct fb_monspecs *monspecs, struct fb_var_screeninfo *var) +{ + driver_devel("%s\n", __func__); + + fb_edid_to_monspecs(edid, monspecs); + + if (*(xfb_adv7511->xfb_flags) & XYLONFB_FLAG_EDID_PRINT) { + pr_info("========================================\n"); + pr_info("Display Information (EDID)\n"); + pr_info("========================================\n"); + pr_info("EDID Version %d.%d\n", + (int)monspecs->version, (int)monspecs->revision); + pr_info("Manufacturer: %s\n", monspecs->manufacturer); + pr_info("Model: %x\n", monspecs->model); + pr_info("Serial Number: %u\n", monspecs->serial); + pr_info("Year: %u Week %u\n", monspecs->year, monspecs->week); + pr_info("Display Characteristics:\n"); + pr_info(" Monitor Operating Limits from EDID\n"); + pr_info(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", + monspecs->hfmin/1000, monspecs->hfmax/1000, + monspecs->vfmin, monspecs->vfmax, + monspecs->dclkmax/1000000); + if (monspecs->input & FB_DISP_DDI) { + pr_info(" Digital Display Input\n"); + } else { + pr_info(" Analog Display Input:\n"); + pr_info(" Input Voltage:\n"); + if (monspecs->input & FB_DISP_ANA_700_300) + pr_info(" 0.700V/0.300V"); + else if (monspecs->input & FB_DISP_ANA_714_286) + pr_info(" 0.714V/0.286V"); + else if (monspecs->input & FB_DISP_ANA_1000_400) + pr_info(" 1.000V/0.400V"); + else if (monspecs->input & FB_DISP_ANA_700_000) + pr_info(" 0.700V/0.000V"); + } + if (monspecs->signal) { + pr_info(" Synchronization:\n"); + if (monspecs->signal & FB_SIGNAL_BLANK_BLANK) + pr_info(" Blank to Blank\n"); + if (monspecs->signal & FB_SIGNAL_SEPARATE) + pr_info(" Separate\n"); + if (monspecs->signal & FB_SIGNAL_COMPOSITE) + pr_info(" Composite\n"); + if (monspecs->signal & FB_SIGNAL_SYNC_ON_GREEN) + pr_info(" Sync on Green\n"); + if (monspecs->signal & FB_SIGNAL_SERRATION_ON) + pr_info(" Serration on\n"); + } + if (monspecs->max_x) + pr_info(" Max H-size %dcm\n", monspecs->max_x); + else + pr_info(" Variable H-size\n"); + if (monspecs->max_y) + pr_info(" Max V-size %dcm\n", monspecs->max_y); + else + pr_info(" Variable V-size\n"); + pr_info(" Display Gamma %d.%d\n", + monspecs->gamma/100, monspecs->gamma % 100); + pr_info(" DPMS: Active %s, Suspend %s, Standby %s\n", + (monspecs->dpms & FB_DPMS_ACTIVE_OFF) ? "yes" : "no", + (monspecs->dpms & FB_DPMS_SUSPEND) ? "yes" : "no", + (monspecs->dpms & FB_DPMS_STANDBY) ? "yes" : "no"); + if (monspecs->input & FB_DISP_MONO) + pr_info(" Monochrome/Grayscale\n"); + else if (monspecs->input & FB_DISP_RGB) + pr_info(" RGB Color Display\n"); + else if (monspecs->input & FB_DISP_MULTI) + pr_info(" Non-RGB Multicolor Display\n"); + else if (monspecs->input & FB_DISP_UNKNOWN) + pr_info(" Unknown\n"); + pr_info(" Chromaticity coordinates:\n"); + pr_info(" RedX: 0.%03d\n", monspecs->chroma.redx); + pr_info(" RedY: 0.%03d\n", monspecs->chroma.redy); + pr_info(" GreenX: 0.%03d\n", monspecs->chroma.greenx); + pr_info(" GreenY: 0.%03d\n", monspecs->chroma.greeny); + pr_info(" BlueX: 0.%03d\n", monspecs->chroma.bluex); + pr_info(" BlueY: 0.%03d\n", monspecs->chroma.bluey); + pr_info(" WhiteX: 0.%03d\n", monspecs->chroma.whitex); + pr_info(" WhiteY: 0.%03d\n", monspecs->chroma.whitey); + if (monspecs->misc) { + if (monspecs->misc & FB_MISC_PRIM_COLOR) + pr_info(" Default color format is primary\n"); + if (monspecs->misc & FB_MISC_1ST_DETAIL) + pr_info(" First DETAILED Timing is preferred\n"); + if (monspecs->gtf == 1) + pr_info(" Display is GTF capable\n"); + } + pr_info("Monitor Timings\n"); + pr_info(" Resolution %dx%d\n", var->xres, var->yres); + pr_info(" Pixel Clock %d MHz ", + (int)PICOS2KHZ(var->pixclock)/1000); + pr_info(" H sync:\n"); + pr_info(" Front porch %d Length %d Back porch %d\n", + var->right_margin, var->hsync_len, var->left_margin); + pr_info(" V sync:\n"); + pr_info(" Front porch %d Length %d Back porch %d\n", + var->lower_margin, var->vsync_len, var->upper_margin); + pr_info(" %sHSync %sVSync\n", + (var->sync & FB_SYNC_HOR_HIGH_ACT) ? "+" : "-", + (var->sync & FB_SYNC_VERT_HIGH_ACT) ? "+" : "-"); + pr_info("========================================\n"); + } +} + +static void xylonfb_adv7511_set_v4l2_timings(struct v4l2_subdev *sd, + struct fb_var_screeninfo *var) +{ + struct v4l2_dv_timings dv_timings; + + driver_devel("%s\n", __func__); + + dv_timings.type = V4L2_DV_BT_656_1120; + + dv_timings.bt.width = var->xres; + dv_timings.bt.height = var->yres; + dv_timings.bt.interlaced = 0; + dv_timings.bt.polarities = 0; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + dv_timings.bt.polarities |= V4L2_DV_VSYNC_POS_POL; + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + dv_timings.bt.polarities |= V4L2_DV_HSYNC_POS_POL; + dv_timings.bt.pixelclock = (__u64)PICOS2KHZ(var->pixclock) * 1000; + dv_timings.bt.hfrontporch = var->right_margin; + dv_timings.bt.hsync = var->hsync_len; + dv_timings.bt.hbackporch = var->left_margin; + dv_timings.bt.vfrontporch = var->lower_margin; + dv_timings.bt.vsync = var->vsync_len; + dv_timings.bt.vbackporch = var->upper_margin; + dv_timings.bt.il_vfrontporch = 0; + dv_timings.bt.il_vsync = 0; + dv_timings.bt.il_vbackporch = 0; + dv_timings.bt.standards = 0; + dv_timings.bt.standards = V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861; + dv_timings.bt.flags = 0; + + sd->ops->video->s_dv_timings(sd, &dv_timings); +} + +static int xylonfb_adv7511_update(struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_misc_data *misc_data = + ld->xylonfb_cd->xylonfb_misc; + int ret; + + driver_devel("%s\n", __func__); + + fbi->monspecs = *(misc_data->monspecs); + + console_lock(); + misc_data->var_screeninfo->xres_virtual = fbi->var.xres_virtual; + misc_data->var_screeninfo->yres_virtual = fbi->var.yres_virtual; + misc_data->var_screeninfo->xoffset = fbi->var.xoffset; + misc_data->var_screeninfo->yoffset = fbi->var.yoffset; + misc_data->var_screeninfo->bits_per_pixel = fbi->var.bits_per_pixel; + fbi->flags |= FBINFO_MISC_USEREVENT; + misc_data->var_screeninfo->activate |= FB_ACTIVATE_ALL; + ret = fb_set_var(fbi, misc_data->var_screeninfo); + misc_data->var_screeninfo->activate &= ~FB_ACTIVATE_ALL; + console_unlock(); + + return ret; +} + +static irqreturn_t xylonfb_adv7511_isr(int irq, void *dev_id) +{ + struct xylonfb_adv7511 *xfb_adv7511 = dev_id; + + driver_devel("%s\n", __func__); + + queue_work(xfb_adv7511->irq_work_queue, &xfb_adv7511->irq_work); + + return IRQ_HANDLED; +} + +static void xylonfb_adv7511_handler(struct work_struct *work) +{ + struct xylonfb_adv7511 *xfb_adv7511 = + container_of(work, struct xylonfb_adv7511, irq_work); + + driver_devel("%s\n", __func__); + + xfb_adv7511->sd->ops->core->interrupt_service_routine( + xfb_adv7511->sd, 0, NULL); +} + +static void xylonfb_adv7511_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + union notify_data { + struct adv7511_monitor_detect *md; + struct adv7511_edid_detect *ed; + } nd; + struct v4l2_subdev_edid sd_edid; + int ret; + + driver_devel("%s\n", __func__); + + switch (notification) { + case ADV7511_MONITOR_DETECT: + nd.md = arg; + driver_devel("ADV7511 monitor%sdetected\n", + nd.md->present ? " " : " not "); + if (nd.md->present) { + xfb_adv7511->timeout = HZ; + } else { + xfb_adv7511->timeout = 0; + *(xfb_adv7511->xfb_flags) &= ~XYLONFB_FLAG_EDID_RDY; + atomic_set(&xfb_adv7511->edid_lock, 0); + } + break; + case ADV7511_EDID_DETECT: + if (*(xfb_adv7511->xfb_flags) & XYLONFB_FLAG_EDID_VMODE) { + if (!atomic_read(&xfb_adv7511->edid_lock)) { + nd.ed = arg; + driver_devel("ADV7511 EDID%sread\n", + nd.ed->present ? " " : " not "); + if (nd.ed->present) { + atomic_set(&xfb_adv7511->edid_lock, 1); + pr_debug("EDID segment: %d\n", nd.ed->segment); + + memset(xfb_adv7511->edid, 0, XYLONFB_EDID_SIZE); + + sd_edid.pad = 0; + sd_edid.start_block = 0; + sd_edid.blocks = 1; + sd_edid.edid = xfb_adv7511->edid; + ret = xfb_adv7511->sd->ops->core->ioctl( + sd, VIDIOC_SUBDEV_G_EDID, (void *)&sd_edid); + if (ret) { + pr_warn("xylonfb ADV7511 IOCTL error %d\n", ret); + break; + } + + fb_parse_edid(xfb_adv7511->edid, + xfb_adv7511->var_screeninfo); + xylonfb_adv7511_get_monspecs(xfb_adv7511->edid, + xfb_adv7511->monspecs, xfb_adv7511->var_screeninfo); + xylonfb_adv7511_set_v4l2_timings(xfb_adv7511->sd, + xfb_adv7511->var_screeninfo); + + *(xfb_adv7511->xfb_flags) |= XYLONFB_FLAG_EDID_RDY; + + wake_up_interruptible(xfb_adv7511->misc_wait); + + if (xfb_adv7511->flags & ADV7511_FLAG_INIT) + complete(&xfb_adv7511->edid_done); + else + xylonfb_adv7511_update(xfb_adv7511->fbi); + } + } + } else { + *(xfb_adv7511->xfb_flags) |= XYLONFB_FLAG_EDID_RDY; + wake_up_interruptible(xfb_adv7511->misc_wait); + } + break; + default: + pr_warn("xylonfb ADV7511 false notify (%d)\n", notification); + break; + } +} + +extern struct v4l2_subdev *adv7511_subdev(struct v4l2_subdev *sd); + +int xylonfb_adv7511_register(struct fb_info *fbi) +{ + struct v4l2_subdev *sd; + struct i2c_client *client; + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + struct xylonfb_misc_data *misc_data = cd->xylonfb_misc; + int ret; + + driver_devel("%s\n", __func__); + + if (xfb_adv7511) + return -EEXIST; + + xfb_adv7511 = kzalloc(sizeof(struct xylonfb_adv7511), GFP_KERNEL); + if (!xfb_adv7511) { + pr_err("xylonfb ADV7511 error allocating data\n"); + return -ENOMEM; + } + + strlcpy(xfb_adv7511->v4l2_dev.name, DRIVER_NAME, + sizeof(xfb_adv7511->v4l2_dev.name)); + ret = v4l2_device_register(NULL, &xfb_adv7511->v4l2_dev); + if (ret) { + pr_err("xylonfb ADV7511 registering V4L2 device error\n"); + return ret; + } + + xfb_adv7511->flags |= ADV7511_FLAG_INIT; + xfb_adv7511->v4l2_dev.notify = xylonfb_adv7511_notify; + + init_completion(&xfb_adv7511->edid_done); + + xfb_adv7511->var_screeninfo = + kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL); + xfb_adv7511->monspecs = + kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL); + xfb_adv7511->xfb_flags = &cd->xylonfb_flags; + xfb_adv7511->fbi = fbi; + + misc_data->var_screeninfo = xfb_adv7511->var_screeninfo; + misc_data->monspecs = xfb_adv7511->monspecs; + misc_data->edid = xfb_adv7511->edid; + + xfb_adv7511->misc_wait = &misc_data->wait; + + sd = adv7511_subdev(NULL); + if (!sd) { + pr_err("xylonfb ADV7511 getting V4L2 subdevice error %s\n", + ADV7511_NAME); + ret = -ENODEV; + goto error_subdev; + } + sd->v4l2_dev = &xfb_adv7511->v4l2_dev; + xfb_adv7511->sd = sd; + + client = v4l2_get_subdevdata(sd); + if (!client) { + pr_err("xylonfb ADV7511 getting V4L2 subdevice client error\n"); + ret = -ENODEV; + goto error_subdev; + } + + xfb_adv7511->irq_work_queue = create_singlethread_workqueue(ADV7511_NAME); + if (xfb_adv7511->irq_work_queue == NULL) { + pr_err("xylonfb ADV7511 workqueue error\n"); + goto error_subdev; + } + INIT_WORK(&xfb_adv7511->irq_work, xylonfb_adv7511_handler); + + if (client->irq > 0) { + ret = request_irq(client->irq, xylonfb_adv7511_isr, + IRQF_TRIGGER_RISING, ADV7511_NAME, xfb_adv7511); + if (ret) { + pr_err("xylonfb ADV7511 registering interrupt error %d at %d\n", + ret, client->irq); + goto error_irq; + } + } else { + pr_err("xylonfb ADV7511 error no IRQ registered\n"); + } + + sd->ops->core->interrupt_service_routine(sd, 0, NULL); + + if (*(xfb_adv7511->xfb_flags) & XYLONFB_FLAG_EDID_VMODE) { + if (xfb_adv7511->timeout) { + ret = wait_for_completion_timeout( + &xfb_adv7511->edid_done, xfb_adv7511->timeout); + } else { + ret = 0; + } + xfb_adv7511->flags &= ~ADV7511_FLAG_INIT; + if (ret == 0) { + if (xfb_adv7511->timeout) { + pr_err("xylonfb ADV7511 EDID error\n"); + return -ETIMEDOUT; + } else { + return -ENODEV; + } + } + } + + return 0; + +error_irq: + flush_work(&xfb_adv7511->irq_work); + flush_workqueue(xfb_adv7511->irq_work_queue); + destroy_workqueue(xfb_adv7511->irq_work_queue); +error_subdev: + v4l2_device_unregister(&xfb_adv7511->v4l2_dev); + + kfree(xfb_adv7511->monspecs); + kfree(xfb_adv7511->var_screeninfo); + misc_data->edid = NULL; + misc_data->monspecs = NULL; + misc_data->var_screeninfo = NULL; + + kfree(xfb_adv7511); + + return ret; +} + +void xylonfb_adv7511_unregister(struct fb_info *fbi) +{ + struct i2c_client *client = v4l2_get_subdevdata(xfb_adv7511->sd); + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + struct xylonfb_misc_data *misc_data = cd->xylonfb_misc; + + driver_devel("%s\n", __func__); + + if (!xfb_adv7511) + return; + + free_irq(client->irq, xfb_adv7511); + flush_work(&xfb_adv7511->irq_work); + flush_workqueue(xfb_adv7511->irq_work_queue); + destroy_workqueue(xfb_adv7511->irq_work_queue); + + kfree(xfb_adv7511->monspecs); + kfree(xfb_adv7511->var_screeninfo); + misc_data->edid = NULL; + misc_data->monspecs = NULL; + misc_data->var_screeninfo = NULL; + + v4l2_device_unregister(&xfb_adv7511->v4l2_dev); + + kfree(xfb_adv7511); + xfb_adv7511 = NULL; +} Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/misc/xylonfb-adv7511.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/misc/xylonfb-adv7511.h 2014-07-20 22:06:38.611268523 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver miscellaneous ADV7511 functionality + * header file + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#ifndef __XYLON_FB_MISC_ADV7511_H__ +#define __XYLON_FB_MISC_ADV7511_H__ + + +#include <linux/types.h> + + +int xylonfb_adv7511_register(struct fb_info *fbi); +void xylonfb_adv7511_unregister(struct fb_info *fbi); + + +#endif /* #ifndef __XYLON_FB_MISC_ADV7511_H__ */ Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/misc/xylonfb-misc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/misc/xylonfb-misc.c 2014-07-20 22:06:38.618268407 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver miscellaneous interface functionality + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include "xylonfb-misc.h" + +#if defined(CONFIG_FB_XYLON_MISC_ADV7511) + +#include "../misc/xylonfb-adv7511.h" + +static void xylonfb_misc_adv7511(struct fb_info *fbi, bool init) +{ + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + struct xylonfb_misc_data *misc_data = cd->xylonfb_misc; + + driver_devel("%s\n", __func__); + + if (cd->xylonfb_flags & XYLONFB_FLAG_ADV7511_SKIP) + return; + + if (init) { + if (cd->xylonfb_flags & XYLONFB_FLAG_MISC_ADV7511) + return; + + if (!xylonfb_adv7511_register(fbi)) { + fbi->monspecs = *(misc_data->monspecs); + cd->xylonfb_flags |= XYLONFB_FLAG_MISC_ADV7511; + } else { + pr_warn("Warning xylonfb ADV7511 already initialized\n"); + } + } else { + xylonfb_adv7511_unregister(fbi); + cd->xylonfb_flags &= ~XYLONFB_FLAG_MISC_ADV7511; + } +} +#endif + +static void xylonfb_misc_init_wait(struct fb_info *fbi) +{ + struct xylonfb_layer_data *ld = fbi->par; + + driver_devel("%s\n", __func__); + + init_waitqueue_head(&ld->xylonfb_cd->xylonfb_misc->wait); +} + +void xylonfb_misc_init(struct fb_info *fbi) +{ + xylonfb_misc_init_wait(fbi); +#if defined(CONFIG_FB_XYLON_MISC_ADV7511) + xylonfb_misc_adv7511(fbi, true); +#endif +} + +void xylonfb_misc_deinit(struct fb_info *fbi) +{ +#if defined(CONFIG_FB_XYLON_MISC_ADV7511) + xylonfb_misc_adv7511(fbi, false); +#endif +} Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/misc/xylonfb-misc.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/misc/xylonfb-misc.h 2014-07-20 22:06:38.623268325 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver miscellaneous interface functionality + * header file + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#ifndef __XYLON_FB_MISC__ +#define __XYLON_FB_MISC__ + + +#include "../core/xylonfb.h" + + +struct xylonfb_misc_data { + wait_queue_head_t wait; + struct fb_var_screeninfo *var_screeninfo; + struct fb_monspecs *monspecs; + u8 *edid; +}; + + +void xylonfb_misc_init(struct fb_info *fbi); +void xylonfb_misc_deinit(struct fb_info *fbi); + +#endif /* #ifndef __XYLON_FB_MISC__ */ Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/of/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/of/Makefile 2014-07-20 22:06:38.634268143 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +obj-y += ../core/ + +xylonfb_of-objs := xylonfb-of.o +ifeq ($(CONFIG_FB_XYLON),m) +xylonfb_of-objs += ../core/xylonfb_core.o +endif +obj-$(CONFIG_FB_XYLON) += xylonfb_of.o Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/of/xylonfb-of.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/of/xylonfb-of.c 2014-07-20 22:06:38.644267978 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer Open Firmware driver + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/errno.h> +#include <linux/of.h> +#include "../core/xylonfb.h" + + +static void xylonfb_set_ctrl_reg(struct xylonfb_init_data *init_data, + unsigned long pix_data_invert, unsigned long pix_clk_act_high) +{ + u32 sync = init_data->vmode_data.fb_vmode.sync; + u32 ctrl = CTRL_REG_INIT; + + driver_devel("%s\n", __func__); + + /* FB_SYNC_HOR_HIGH_ACT */ + if (!(sync & (1<<0))) + ctrl &= (~(1<<1)); + /* FB_SYNC_VERT_HIGH_ACT */ + if (!(sync & (1<<1))) + ctrl &= (~(1<<3)); + if (pix_data_invert) + ctrl |= LOGICVC_PIX_DATA_INVERT; + if (pix_clk_act_high) + ctrl |= LOGICVC_PIX_ACT_HIGH; + + init_data->vmode_data.ctrl_reg = ctrl; +} + +static int xylonfb_parse_hw_info(struct device_node *np, + struct xylonfb_init_data *init_data) +{ + u32 const *prop; + int size; + + driver_devel("%s\n", __func__); + + prop = of_get_property(np, "xlnx,display-interface", &size); + if (!prop) { + pr_err("Error xylonfb getting display interface\n"); + return -EINVAL; + } + init_data->display_interface_type = be32_to_cpup(prop) << 4; + + prop = of_get_property(np, "xlnx,display-color-space", &size); + if (!prop) { + pr_err("Error xylonfb getting display color space\n"); + return -EINVAL; + } + init_data->display_interface_type |= be32_to_cpup(prop); + + prop = of_get_property(np, "xlnx,readable-regs", &size); + if (!prop) { + pr_warn("xylonfb registers not readable\n"); + } else { + if (be32_to_cpup(prop)) + init_data->flags |= LOGICVC_READABLE_REGS; + } + + return 0; +} + +static int xylonfb_parse_vram_info(struct device_node *np, + unsigned long *vmem_base_addr, unsigned long *vmem_high_addr) +{ + u32 const *prop; + int size; + + driver_devel("%s\n", __func__); + + prop = of_get_property(np, "xlnx,vmem-baseaddr", &size); + if (!prop) { + pr_err("Error xylonfb getting VRAM address begin\n"); + return -EINVAL; + } + *vmem_base_addr = be32_to_cpup(prop); + + prop = of_get_property(np, "xlnx,vmem-highaddr", &size); + if (!prop) { + pr_err("Error xylonfb getting VRAM address end\n"); + return -EINVAL; + } + *vmem_high_addr = be32_to_cpup(prop); + + return 0; +} + +static int xylonfb_parse_layer_info(struct device_node *np, + struct xylonfb_init_data *init_data) +{ + u32 const *prop; + unsigned int layers, bg_bpp, bg_alpha_mode; + int size; + char bg_layer_name[25]; + + driver_devel("%s\n", __func__); + + prop = of_get_property(np, "xlnx,num-of-layers", &size); + if (!prop) { + pr_err("Error getting number of layers\n"); + return -EINVAL; + } + layers = be32_to_cpup(prop); + + bg_bpp = 0; + bg_alpha_mode = 0; + prop = of_get_property(np, "xlnx,use-background", &size); + if (!prop) { + pr_warn("xylonfb no BG layer\n"); + } else { + if (be32_to_cpup(prop) == 1) { + layers--; + + sprintf(bg_layer_name, "xlnx,layer-%d-data-width", layers); + prop = of_get_property(np, bg_layer_name, &size); + if (!prop) + bg_bpp = 16; + else + bg_bpp = be32_to_cpup(prop); + if (bg_bpp == 24) + bg_bpp = 32; + + sprintf(bg_layer_name, "xlnx,layer-%d-alpha-mode", layers); + prop = of_get_property(np, bg_layer_name, &size); + if (!prop) + bg_alpha_mode = LOGICVC_LAYER_ALPHA; + else + bg_alpha_mode = be32_to_cpup(prop); + } else { + pr_debug("xylonfb no BG layer\n"); + } + } + + init_data->layers = (unsigned char)layers; + init_data->bg_layer_bpp = (unsigned char)bg_bpp; + init_data->bg_layer_alpha_mode = (unsigned char)bg_alpha_mode; + + return 0; +} + +static int xylonfb_parse_vmode_info(struct device_node *np, + struct xylonfb_init_data *init_data) +{ + struct device_node *dn, *vmode_np; + u32 const *prop; + char *c; + unsigned long pix_data_invert, pix_clk_act_high; + int size, tmp; + + driver_devel("%s\n", __func__); + + vmode_np = NULL; + init_data->vmode_data.fb_vmode.refresh = 60; + init_data->active_layer = 0; + init_data->vmode_params_set = false; + + prop = of_get_property(np, "pixel-clock-source", &size); + if (!prop) { + pr_info("No pixel clock source\n"); + init_data->pixclk_src_id = 0; + } else { + tmp = be32_to_cpup(prop); + init_data->pixclk_src_id = (u16)tmp; + } + pix_data_invert = 0; + prop = of_get_property(np, "pixel-data-invert", &size); + if (!prop) + pr_err("Error getting pixel data invert\n"); + else + pix_data_invert = be32_to_cpup(prop); + pix_clk_act_high = 0; + prop = of_get_property(np, "pixel-clock-active-high", &size); + if (!prop) + pr_err("Error getting pixel active edge\n"); + else + pix_clk_act_high = be32_to_cpup(prop); + + prop = of_get_property(np, "pixel-component-format", &size); + if (prop) { + if (!strcmp("ABGR", (char *)prop)) { + prop = of_get_property(np, "pixel-component-layer", &size); + if (prop) { + while (size > 0) { + tmp = be32_to_cpup(prop); + init_data->layer_ctrl_flags[tmp] = LOGICVC_SWAP_RB; + prop++; + size -= sizeof(prop); + } + } + } + } + + prop = of_get_property(np, "active-layer", &size); + if (prop) { + tmp = be32_to_cpup(prop); + init_data->active_layer = (unsigned char)tmp; + } else { + pr_info("xylonfb setting default layer to %d\n", + init_data->active_layer); + } + + dn = of_get_child_by_name(np, "edid"); + if (dn) { + prop = of_get_property(dn, "preffered-videomode", &size); + if (prop) { + tmp = be32_to_cpup(prop); + if (tmp) + init_data->flags |= XYLONFB_FLAG_EDID_VMODE; + } + prop = of_get_property(dn, "display-data", &size); + if (prop) { + tmp = be32_to_cpup(prop); + if (tmp) + init_data->flags |= XYLONFB_FLAG_EDID_PRINT; + } + } else { + init_data->flags |= XYLONFB_FLAG_ADV7511_SKIP; + } + of_node_put(dn); + + prop = of_get_property(np, "videomode", &size); + if (prop) { + if (strlen((char *)prop) <= VMODE_NAME_SZ) { + dn = NULL; + dn = of_find_node_by_name(NULL, "xylon-video-params"); + if (dn) { + strcpy(init_data->vmode_data.fb_vmode_name, + (char *)prop); + vmode_np = of_find_node_by_name(dn, + init_data->vmode_data.fb_vmode_name); + c = strchr((char *)prop, '_'); + if (c) + *c = 0; + strcpy(init_data->vmode_data.fb_vmode_name, (char *)prop); + } else { + strcpy(init_data->vmode_data.fb_vmode_name, (char *)prop); + } + of_node_put(dn); + } else { + pr_err("Error videomode name to long\n"); + } + if (vmode_np) { + prop = of_get_property(vmode_np, "refresh", &size); + if (!prop) + pr_err("Error getting refresh rate\n"); + else + init_data->vmode_data.fb_vmode.refresh = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "xres", &size); + if (!prop) + pr_err("Error getting xres\n"); + else + init_data->vmode_data.fb_vmode.xres = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "yres", &size); + if (!prop) + pr_err("Error getting yres\n"); + else + init_data->vmode_data.fb_vmode.yres = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "pixclock-khz", &size); + if (!prop) + pr_err("Error getting pixclock-khz\n"); + else + init_data->vmode_data.fb_vmode.pixclock = + KHZ2PICOS(be32_to_cpup(prop)); + + prop = of_get_property(vmode_np, "left-margin", &size); + if (!prop) + pr_err("Error getting left-margin\n"); + else + init_data->vmode_data.fb_vmode.left_margin = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "right-margin", &size); + if (!prop) + pr_err("Error getting right-margin\n"); + else + init_data->vmode_data.fb_vmode.right_margin = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "upper-margin", &size); + if (!prop) + pr_err("Error getting upper-margin\n"); + else + init_data->vmode_data.fb_vmode.upper_margin = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "lower-margin", &size); + if (!prop) + pr_err("Error getting lower-margin\n"); + else + init_data->vmode_data.fb_vmode.lower_margin = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "hsync-len", &size); + if (!prop) + pr_err("Error getting hsync-len\n"); + else + init_data->vmode_data.fb_vmode.hsync_len = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "vsync-len", &size); + if (!prop) + pr_err("Error getting vsync-len\n"); + else + init_data->vmode_data.fb_vmode.vsync_len = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "sync", &size); + if (!prop) + pr_err("Error getting sync\n"); + else + init_data->vmode_data.fb_vmode.sync = + be32_to_cpup(prop); + + prop = of_get_property(vmode_np, "vmode", &size); + if (!prop) + pr_err("Error getting vmode\n"); + else + init_data->vmode_data.fb_vmode.vmode = + be32_to_cpup(prop); + + init_data->vmode_params_set = true; + } + } else { + pr_info("xylonfb using default driver video mode\n"); + } + + xylonfb_set_ctrl_reg(init_data, pix_data_invert, pix_clk_act_high); + + return 0; +} + +static int xylonfb_parse_layer_params(struct device_node *np, + int id, struct xylonfb_layer_fix_data *lfdata) +{ + u32 const *prop; + int size; + char layer_property_name[25]; + + driver_devel("%s\n", __func__); + + sprintf(layer_property_name, "xlnx,layer-%d-offset", id); + prop = of_get_property(np, layer_property_name, &size); + if (!prop) { + pr_err("Error getting layer offset\n"); + return -EINVAL; + } else { + lfdata->offset = be32_to_cpup(prop); + } + + sprintf(layer_property_name, "xlnx,buffer-%d-offset", id); + prop = of_get_property(np, layer_property_name, &size); + if (!prop) { + pr_err("Error getting buffer offset\n"); + return -EINVAL; + } else { + lfdata->buffer_offset = be32_to_cpup(prop); + } + + prop = of_get_property(np, "xlnx,row-stride", &size); + if (!prop) + lfdata->width = 1024; + else + lfdata->width = be32_to_cpup(prop); + + sprintf(layer_property_name, "xlnx,layer-%d-type", id); + prop = of_get_property(np, layer_property_name, &size); + if (!prop) { + pr_err("Error getting layer type\n"); + return -EINVAL; + } else { + lfdata->layer_type = be32_to_cpup(prop); + } + + sprintf(layer_property_name, "xlnx,layer-%d-alpha-mode", id); + prop = of_get_property(np, layer_property_name, &size); + if (!prop) { + pr_err("Error getting layer alpha mode\n"); + return -EINVAL; + } else { + lfdata->alpha_mode = be32_to_cpup(prop); + /* If logiCVC layer is Alpha layer, override DT value */ + if (lfdata->layer_type == LOGICVC_ALPHA_LAYER) + lfdata->alpha_mode = LOGICVC_LAYER_ALPHA; + } + + sprintf(layer_property_name, "xlnx,layer-%d-data-width", id); + prop = of_get_property(np, layer_property_name, &size); + if (!prop) + lfdata->bpp = 16; + else + lfdata->bpp = be32_to_cpup(prop); + if (lfdata->bpp == 24) + lfdata->bpp = 32; + + lfdata->bpp_virt = lfdata->bpp; + + switch (lfdata->bpp) { + case 8: + if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA) + lfdata->bpp = 16; + break; + case 16: + if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA) + lfdata->bpp = 32; + break; + } + + lfdata->layer_fix_info = id; + + return 0; +} + + +static int xylonfb_of_probe(struct platform_device *pdev) +{ + struct xylonfb_init_data init_data; + int i, rc; + + driver_devel("%s\n", __func__); + + memset(&init_data, 0, sizeof(struct xylonfb_init_data)); + + init_data.pdev = pdev; + + rc = xylonfb_parse_hw_info(pdev->dev.of_node, &init_data); + if (rc) + return rc; + rc = xylonfb_parse_vram_info(pdev->dev.of_node, + &init_data.vmem_base_addr, &init_data.vmem_high_addr); + if (rc) + return rc; + rc = xylonfb_parse_layer_info(pdev->dev.of_node, &init_data); + if (rc) + return rc; + /* if Device-Tree contains video mode options do not use + kernel command line video mode options */ + xylonfb_parse_vmode_info(pdev->dev.of_node, &init_data); + + for (i = 0; i < init_data.layers; i++) { + rc = xylonfb_parse_layer_params(pdev->dev.of_node, i, + &init_data.lfdata[i]); + if (rc) + return rc; + } + + return xylonfb_init_driver(&init_data); +} + +static int xylonfb_of_remove(struct platform_device *pdev) +{ + driver_devel("%s\n", __func__); + + return xylonfb_deinit_driver(pdev); +} + + +static struct of_device_id xylonfb_of_match[] = { + { .compatible = "xylon,logicvc-3.00.a" }, + { .compatible = "xylon,logicvc-3.01.a" }, + { .compatible = "xylon,logicvc-3.02.a" }, + {/* end of table */}, +}; +MODULE_DEVICE_TABLE(of, xylonfb_of_match); + + +static struct platform_driver xylonfb_of_driver = { + .probe = xylonfb_of_probe, + .remove = xylonfb_of_remove, + .driver = { + .owner = THIS_MODULE, + .name = DEVICE_NAME, + .of_match_table = xylonfb_of_match, + }, +}; + + +static int xylonfb_of_init(void) +{ +#ifndef MODULE + char *option = NULL; + /* + * For kernel boot options (in 'video=xxxfb:<options>' format) + */ + if (fb_get_options(DRIVER_NAME, &option)) + return -ENODEV; + /* Set internal module parameters */ + xylonfb_get_params(option); +#endif + if (platform_driver_register(&xylonfb_of_driver)) { + pr_err("Error xylonfb driver registration\n"); + return -ENODEV; + } + + return 0; +} + +static void __exit xylonfb_of_exit(void) +{ + platform_driver_unregister(&xylonfb_of_driver); +} + + +#ifndef MODULE +late_initcall(xylonfb_of_init); +#else +module_init(xylonfb_of_init); +module_exit(xylonfb_of_exit); +#endif + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); +MODULE_VERSION(DRIVER_VERSION); Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/platform/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/platform/Makefile 2014-07-20 22:06:38.655267797 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +obj-y += ../core/ + +xylonfb_platform-objs := xylonfb-platform.o +ifeq ($(CONFIG_FB_XYLON),m) +xylonfb_platform-objs += ../core/xylonfb_core.o +endif +obj-$(CONFIG_FB_XYLON) += xylonfb_platform.o Index: linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/platform/xylonfb-platform.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/video/xylon/xylonfb/platform/xylonfb-platform.c 2014-07-20 22:06:38.663267665 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer platform driver + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * This driver was primarily based on skeletonfb.c and other fb video drivers. + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/errno.h> +#include <linux/xylonfb_platform.h> +#include "../core/xylonfb.h" + + +static void xylonfb_get_platform_layer_params( + struct xylonfb_platform_layer_params *lparams, + struct xylonfb_layer_fix_data *lfdata, int id) +{ + driver_devel("%s\n", __func__); + + lfdata->offset = lparams->offset; + lfdata->buffer_offset = lparams->buffer_offset; + lfdata->layer_type = lparams->type; + lfdata->bpp = lparams->bpp; + lfdata->bpp_virt = lparams->bpp; + lfdata->alpha_mode = lparams->alpha_mode; + if (lfdata->layer_type == LOGICVC_ALPHA_LAYER) + lfdata->alpha_mode = LOGICVC_LAYER_ALPHA; + + switch (lfdata->bpp) { + case 8: + if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA) + lfdata->bpp = 16; + break; + case 16: + if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA) + lfdata->bpp = 32; + break; + } + + lfdata->layer_fix_info = id; +} + +static int xylonfb_platform_probe(struct platform_device *pdev) +{ + struct xylonfb_init_data init_data; + struct xylonfb_platform_data *pdata; + int i; + + driver_devel("%s\n", __func__); + + memset(&init_data, 0, sizeof(struct xylonfb_init_data)); + + init_data.pdev = pdev; + + pdata = (struct xylonfb_platform_data *)pdev->dev.platform_data; + init_data.vmem_base_addr = pdata->vmem_base_addr; + init_data.vmem_high_addr = pdata->vmem_high_addr; + init_data.pixclk_src_id = pdata->pixclk_src_id; + init_data.vmode_data.ctrl_reg = pdata->ctrl_reg; + strcpy(init_data.vmode_data.fb_vmode_name, pdata->vmode); + init_data.vmode_data.fb_vmode.refresh = 60; + init_data.layers = pdata->num_layers; + init_data.active_layer = pdata->active_layer; + init_data.bg_layer_bpp = pdata->bg_layer_bpp; + init_data.bg_layer_alpha_mode = pdata->bg_layer_alpha_mode; + init_data.display_interface_type = pdata->display_interface_type; + init_data.flags = pdata->flags; + init_data.vmode_params_set = false; + + for (i = 0; i < init_data.layers; i++) { + xylonfb_get_platform_layer_params( + &pdata->layer_params[i], &init_data.lfdata[i], i); + init_data.lfdata[i].width = pdata->row_stride; + init_data.layer_ctrl_flags[i] = pdata->layer_params[i].ctrl_flags; + } + + return xylonfb_init_driver(&init_data); +} + +static int xylonfb_platform_remove(struct platform_device *pdev) +{ + driver_devel("%s\n", __func__); + + return xylonfb_deinit_driver(pdev); +} + + +void xylonfb_platform_release(struct device *dev) +{ + driver_devel("%s\n", __func__); + + return; +} + + +/* logiCVC parameters for Xylon Zynq-ZC702 2D3D referent design */ +static struct xylonfb_platform_layer_params + logicvc_0_layer_params[] = { + { + .offset = 7290, + .buffer_offset = 1080, + .type = LOGICVC_RGB_LAYER, + .bpp = 32, + .alpha_mode = LOGICVC_PIXEL_ALPHA, + .ctrl_flags = 0, + }, + { + .offset = 4050, + .buffer_offset = 1080, + .type = LOGICVC_RGB_LAYER, + .bpp = 32, + .alpha_mode = LOGICVC_LAYER_ALPHA, + .ctrl_flags = 0, + }, + { + .offset = 0, + .buffer_offset = 1080, + .type = LOGICVC_RGB_LAYER, + .bpp = 32, + .alpha_mode = LOGICVC_LAYER_ALPHA, + .ctrl_flags = 0, + }, + { + .offset = 12960, + .buffer_offset = 1080, + .type = LOGICVC_RGB_LAYER, + .bpp = 8, + .alpha_mode = LOGICVC_CLUT_32BPP_ALPHA, + .ctrl_flags = 0, + }, +}; + +static struct xylonfb_platform_data logicvc_0_platform_data = { + .layer_params = logicvc_0_layer_params, + .vmode = "1024x768", + .ctrl_reg = (CTRL_REG_INIT | LOGICVC_PIX_ACT_HIGH), + .vmem_base_addr = 0x30000000, + .vmem_high_addr = 0x3FFFFFFF, + .pixclk_src_id = 3, + .row_stride = 2048, + .num_layers = ARRAY_SIZE(logicvc_0_layer_params), + .active_layer = 3, + .bg_layer_bpp = 32, + .bg_layer_alpha_mode = LOGICVC_LAYER_ALPHA, + .display_interface_type = + (LOGICVC_DI_PARALLEL << 4) | (LOGICVC_DCS_YUV422), + /* + Available flags: + LOGICVC_READABLE_REGS + XYLONFB_FLAG_EDID_VMODE + XYLONFB_FLAG_EDID_PRINT + */ + .flags = 0, +}; + +static struct resource logicvc_0_resource[] = { + { + .start = 0x40030000, + .end = (0x40030000 + LOGICVC_REGISTERS_RANGE), + .flags = IORESOURCE_MEM, + }, + { + .start = 90, + .end = 90, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device logicvc_0_device = { + .name = DEVICE_NAME, + .id = 0, + .dev = { + .platform_data = &logicvc_0_platform_data, + .release = xylonfb_platform_release, + }, + .resource = logicvc_0_resource, + .num_resources = ARRAY_SIZE(logicvc_0_resource), +}; + + +static struct platform_driver xylonfb_driver = { + .probe = xylonfb_platform_probe, + .remove = xylonfb_platform_remove, + .driver = { + .owner = THIS_MODULE, + .name = DEVICE_NAME, + }, +}; + + +static int xylonfb_platform_init(void) +{ +#ifndef MODULE + char *option = NULL; +#endif + int err; + + driver_devel("%s\n", __func__); + +#ifndef MODULE + /* + * For kernel boot options (in 'video=xxxfb:<options>' format) + */ + if (fb_get_options(DRIVER_NAME, &option)) + return -ENODEV; + /* Set internal module parameters */ + xylonfb_get_params(option); +#endif + err = platform_device_register(&logicvc_0_device); + if (err) { + pr_err("Error xylonfb device registration\n"); + return err; + } + err = platform_driver_register(&xylonfb_driver); + if (err) { + pr_err("Error xylonfb driver registration\n"); + platform_device_unregister(&logicvc_0_device); + return err; + } + + return 0; +} + +static void __exit xylonfb_platform_exit(void) +{ + platform_driver_unregister(&xylonfb_driver); + platform_device_unregister(&logicvc_0_device); +} + + +#ifndef MODULE +late_initcall(xylonfb_platform_init); +#else +module_init(xylonfb_platform_init); +module_exit(xylonfb_platform_exit); +#endif + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); +MODULE_VERSION(DRIVER_VERSION); Index: linux-3.12.24-rt38-xilinx/drivers/watchdog/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/watchdog/Kconfig 2014-07-20 22:05:50.201067198 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/watchdog/Kconfig 2014-07-20 22:06:38.680267385 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:341 @ To compile this driver as a module, choose M here: the module will be called nuc900_wdt. +config ZYNQ_WATCHDOG + tristate "Xilinx PS Watchdog Timer" + depends on ARCH_ZYNQ + select WATCHDOG_CORE + help + Say Y here if you want to include support for the watchdog + timer in the Xilinx Zynq. + config TS72XX_WATCHDOG tristate "TS-72XX SBC Watchdog" depends on MACH_TS72XX @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:999 @ config XILINX_WATCHDOG tristate "Xilinx Watchdog timer" - depends on MICROBLAZE + depends on MICROBLAZE || ARCH_ZYNQ + select WATCHDOG_CORE ---help--- Watchdog driver for the xps_timebase_wdt ip core. - IMPORTANT: The xps_timebase_wdt parent must have the property - "clock-frequency" at device tree. - To compile this driver as a module, choose M here: the module will be called of_xilinx_wdt. Index: linux-3.12.24-rt38-xilinx/drivers/watchdog/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/watchdog/Makefile 2014-07-20 22:05:50.200067215 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/watchdog/Makefile 2014-07-20 22:06:38.691267203 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:53 @ obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o +obj-$(CONFIG_ZYNQ_WATCHDOG) += zynq_wdt.o obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o Index: linux-3.12.24-rt38-xilinx/drivers/watchdog/of_xilinx_wdt.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/drivers/watchdog/of_xilinx_wdt.c 2014-07-20 22:05:50.202067182 +0200 +++ linux-3.12.24-rt38-xilinx/drivers/watchdog/of_xilinx_wdt.c 2014-07-20 22:06:38.704266989 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ /* * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt * + * (C) Copyright 2013 Xilinx, Inc. * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>) * * This program is free software; you can redistribute it and/or @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:13 @ * 2 of the License, or (at your option) any later version. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include <linux/err.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/watchdog.h> #include <linux/io.h> -#include <linux/uaccess.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_address.h> @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:43 @ #define XWT_TIMER_FAILED 0xFFFFFFFF #define WATCHDOG_NAME "Xilinx Watchdog" -#define PFX WATCHDOG_NAME ": " -struct xwdt_device { - struct resource res; +struct xilinx_wdt_device { void __iomem *base; - u32 nowayout; u32 wdt_interval; - u32 boot_status; + spinlock_t spinlock; + struct watchdog_device xilinx_wdt_wdd; }; -static struct xwdt_device xdev; - -static u32 timeout; -static u32 control_status_reg; -static u8 expect_close; -static u8 no_timeout; -static unsigned long driver_open; - -static DEFINE_SPINLOCK(spinlock); - -static void xwdt_start(void) +static int xilinx_wdt_start(struct watchdog_device *wdd) { - spin_lock(&spinlock); + u32 control_status_reg; + struct xilinx_wdt_device *xilinx_wdt = watchdog_get_drvdata(wdd); + + spin_lock(&xilinx_wdt->spinlock); /* Clean previous status and enable the watchdog timer */ - control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); + control_status_reg = ioread32(xilinx_wdt->base + XWT_TWCSR0_OFFSET); control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK), - xdev.base + XWT_TWCSR0_OFFSET); + xilinx_wdt->base + XWT_TWCSR0_OFFSET); - iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET); + iowrite32(XWT_CSRX_EWDT2_MASK, xilinx_wdt->base + XWT_TWCSR1_OFFSET); - spin_unlock(&spinlock); + spin_unlock(&xilinx_wdt->spinlock); + + return 0; } -static void xwdt_stop(void) +static int xilinx_wdt_stop(struct watchdog_device *wdd) { - spin_lock(&spinlock); + u32 control_status_reg; + struct xilinx_wdt_device *xilinx_wdt = watchdog_get_drvdata(wdd); + + spin_lock(&xilinx_wdt->spinlock); - control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); + control_status_reg = ioread32(xilinx_wdt->base + XWT_TWCSR0_OFFSET); iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK), - xdev.base + XWT_TWCSR0_OFFSET); + xilinx_wdt->base + XWT_TWCSR0_OFFSET); - iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET); + iowrite32(0, xilinx_wdt->base + XWT_TWCSR1_OFFSET); - spin_unlock(&spinlock); + spin_unlock(&xilinx_wdt->spinlock); pr_info("Stopped!\n"); + + return 0; } -static void xwdt_keepalive(void) +static int xilinx_wdt_keepalive(struct watchdog_device *wdd) { - spin_lock(&spinlock); + u32 control_status_reg; + struct xilinx_wdt_device *xilinx_wdt = watchdog_get_drvdata(wdd); - control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); + spin_lock(&xilinx_wdt->spinlock); + + control_status_reg = ioread32(xilinx_wdt->base + XWT_TWCSR0_OFFSET); control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); - iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET); + iowrite32(control_status_reg, xilinx_wdt->base + XWT_TWCSR0_OFFSET); - spin_unlock(&spinlock); -} + spin_unlock(&xilinx_wdt->spinlock); -static void xwdt_get_status(int *status) -{ - int new_status; + return 0; +} - spin_lock(&spinlock); +static const struct watchdog_info xilinx_wdt_ident = { + .options = WDIOF_MAGICCLOSE | + WDIOF_KEEPALIVEPING, + .firmware_version = 1, + .identity = WATCHDOG_NAME, +}; - control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); - new_status = ((control_status_reg & - (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK)) != 0); - spin_unlock(&spinlock); - - *status = 0; - if (new_status & 1) - *status |= WDIOF_CARDRESET; -} +static const struct watchdog_ops xilinx_wdt_ops = { + .owner = THIS_MODULE, + .start = xilinx_wdt_start, + .stop = xilinx_wdt_stop, + .ping = xilinx_wdt_keepalive, +}; -static u32 xwdt_selftest(void) +static u32 xilinx_wdt_selftest(struct xilinx_wdt_device *xilinx_wdt) { int i; u32 timer_value1; u32 timer_value2; - spin_lock(&spinlock); + spin_lock(&xilinx_wdt->spinlock); - timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET); - timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET); + timer_value1 = ioread32(xilinx_wdt->base + XWT_TBR_OFFSET); + timer_value2 = ioread32(xilinx_wdt->base + XWT_TBR_OFFSET); for (i = 0; ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) && (timer_value2 == timer_value1)); i++) { - timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET); + timer_value2 = ioread32(xilinx_wdt->base + XWT_TBR_OFFSET); } - spin_unlock(&spinlock); + spin_unlock(&xilinx_wdt->spinlock); if (timer_value2 != timer_value1) return ~XWT_TIMER_FAILED; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:147 @ return XWT_TIMER_FAILED; } -static int xwdt_open(struct inode *inode, struct file *file) -{ - /* Only one process can handle the wdt at a time */ - if (test_and_set_bit(0, &driver_open)) - return -EBUSY; - - /* Make sure that the module are always loaded...*/ - if (xdev.nowayout) - __module_get(THIS_MODULE); - - xwdt_start(); - pr_info("Started...\n"); - - return nonseekable_open(inode, file); -} - -static int xwdt_release(struct inode *inode, struct file *file) -{ - if (expect_close == 42) { - xwdt_stop(); - } else { - pr_crit("Unexpected close, not stopping watchdog!\n"); - xwdt_keepalive(); - } - - clear_bit(0, &driver_open); - expect_close = 0; - return 0; -} - -/* - * xwdt_write: - * @file: file handle to the watchdog - * @buf: buffer to write (unused as data does not matter here - * @count: count of bytes - * @ppos: pointer to the position to write. No seeks allowed - * - * A write to a watchdog device is defined as a keepalive signal. Any - * write of data will do, as we don't define content meaning. - */ -static ssize_t xwdt_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) -{ - if (len) { - if (!xdev.nowayout) { - size_t i; - - /* In case it was set long ago */ - expect_close = 0; - - for (i = 0; i != len; i++) { - char c; - - if (get_user(c, buf + i)) - return -EFAULT; - if (c == 'V') - expect_close = 42; - } - } - xwdt_keepalive(); - } - return len; -} - -static const struct watchdog_info ident = { - .options = WDIOF_MAGICCLOSE | - WDIOF_KEEPALIVEPING, - .firmware_version = 1, - .identity = WATCHDOG_NAME, -}; - -/* - * xwdt_ioctl: - * @file: file handle to the device - * @cmd: watchdog command - * @arg: argument pointer - * - * The watchdog API defines a common set of functions for all watchdogs - * according to their available features. - */ -static long xwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int status; - - union { - struct watchdog_info __user *ident; - int __user *i; - } uarg; - - uarg.i = (int __user *)arg; - - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(uarg.ident, &ident, - sizeof(ident)) ? -EFAULT : 0; - - case WDIOC_GETBOOTSTATUS: - return put_user(xdev.boot_status, uarg.i); - - case WDIOC_GETSTATUS: - xwdt_get_status(&status); - return put_user(status, uarg.i); - - case WDIOC_KEEPALIVE: - xwdt_keepalive(); - return 0; - - case WDIOC_GETTIMEOUT: - if (no_timeout) - return -ENOTTY; - else - return put_user(timeout, uarg.i); - - default: - return -ENOTTY; - } -} - -static const struct file_operations xwdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = xwdt_write, - .open = xwdt_open, - .release = xwdt_release, - .unlocked_ioctl = xwdt_ioctl, -}; - -static struct miscdevice xwdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &xwdt_fops, -}; - -static int xwdt_probe(struct platform_device *pdev) +static int xilinx_wdt_probe(struct platform_device *pdev) { int rc; - u32 *tmptr; - u32 *pfreq; - - no_timeout = 0; - - pfreq = (u32 *)of_get_property(pdev->dev.of_node, - "clock-frequency", NULL); + u32 pfreq, enable_once; + struct resource *res; + struct xilinx_wdt_device *xilinx_wdt; + bool no_timeout = false; + struct watchdog_device *xilinx_wdt_wdd; + + xilinx_wdt = devm_kzalloc(&pdev->dev, sizeof(*xilinx_wdt), GFP_KERNEL); + if (!xilinx_wdt) + return -ENOMEM; + + xilinx_wdt_wdd = &xilinx_wdt->xilinx_wdt_wdd; + xilinx_wdt_wdd->info = &xilinx_wdt_ident; + xilinx_wdt_wdd->ops = &xilinx_wdt_ops; + xilinx_wdt_wdd->parent = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xilinx_wdt->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xilinx_wdt->base)) + return PTR_ERR(xilinx_wdt->base); - if (pfreq == NULL) { - pr_warn("The watchdog clock frequency cannot be obtained!\n"); - no_timeout = 1; - } - - rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res); + rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &pfreq); if (rc) { - pr_warn("invalid address!\n"); - return rc; + dev_warn(&pdev->dev, + "The watchdog clock frequency cannot be obtained\n"); + no_timeout = true; } - tmptr = (u32 *)of_get_property(pdev->dev.of_node, - "xlnx,wdt-interval", NULL); - if (tmptr == NULL) { - pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n"); - no_timeout = 1; - } else { - xdev.wdt_interval = *tmptr; + rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-interval", + &xilinx_wdt->wdt_interval); + if (rc) { + dev_warn(&pdev->dev, + "Parameter \"xlnx,wdt-interval\" not found\n"); + no_timeout = true; } - tmptr = (u32 *)of_get_property(pdev->dev.of_node, - "xlnx,wdt-enable-once", NULL); - if (tmptr == NULL) { - pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n"); - xdev.nowayout = WATCHDOG_NOWAYOUT; + /* FIXME this is weird */ + rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-enable-once", + &enable_once); + if (rc || enable_once) { + dev_warn(&pdev->dev, + "Parameter \"xlnx,wdt-enable-once\" not found\n"); + watchdog_set_nowayout(xilinx_wdt_wdd, true); } /* @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:199 @ * ignored (interrupt), reset is only generated at second wdt overflow */ if (!no_timeout) - timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq); + xilinx_wdt_wdd->timeout = 2 * ((1 << xilinx_wdt->wdt_interval) / + pfreq); - if (!request_mem_region(xdev.res.start, - xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) { - rc = -ENXIO; - pr_err("memory request failure!\n"); - goto err_out; - } - - xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1); - if (xdev.base == NULL) { - rc = -ENOMEM; - pr_err("ioremap failure!\n"); - goto release_mem; - } + spin_lock_init(&xilinx_wdt->spinlock); + watchdog_set_drvdata(xilinx_wdt_wdd, xilinx_wdt); - rc = xwdt_selftest(); + rc = xilinx_wdt_selftest(xilinx_wdt); if (rc == XWT_TIMER_FAILED) { - pr_err("SelfTest routine error!\n"); - goto unmap_io; + dev_err(&pdev->dev, "SelfTest routine error\n"); + return rc; } - xwdt_get_status(&xdev.boot_status); - - rc = misc_register(&xwdt_miscdev); + rc = watchdog_register_device(xilinx_wdt_wdd); if (rc) { - pr_err("cannot register miscdev on minor=%d (err=%d)\n", - xwdt_miscdev.minor, rc); - goto unmap_io; + dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc); + return rc; } - if (no_timeout) - pr_info("driver loaded (timeout=? sec, nowayout=%d)\n", - xdev.nowayout); - else - pr_info("driver loaded (timeout=%d sec, nowayout=%d)\n", - timeout, xdev.nowayout); + dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", + xilinx_wdt->base, xilinx_wdt_wdd->timeout); - expect_close = 0; - clear_bit(0, &driver_open); + platform_set_drvdata(pdev, xilinx_wdt); return 0; - -unmap_io: - iounmap(xdev.base); -release_mem: - release_mem_region(xdev.res.start, resource_size(&xdev.res)); -err_out: - return rc; } -static int xwdt_remove(struct platform_device *dev) +static int xilinx_wdt_remove(struct platform_device *pdev) { - misc_deregister(&xwdt_miscdev); - iounmap(xdev.base); - release_mem_region(xdev.res.start, resource_size(&xdev.res)); + struct xilinx_wdt_device *xilinx_wdt = platform_get_drvdata(pdev); + + watchdog_unregister_device(&xilinx_wdt->xilinx_wdt_wdd); return 0; } /* Match table for of_platform binding */ -static struct of_device_id xwdt_of_match[] = { +static struct of_device_id xilinx_wdt_of_match[] = { { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, {}, }; -MODULE_DEVICE_TABLE(of, xwdt_of_match); +MODULE_DEVICE_TABLE(of, xilinx_wdt_of_match); -static struct platform_driver xwdt_driver = { - .probe = xwdt_probe, - .remove = xwdt_remove, +static struct platform_driver xilinx_wdt_driver = { + .probe = xilinx_wdt_probe, + .remove = xilinx_wdt_remove, .driver = { .owner = THIS_MODULE, .name = WATCHDOG_NAME, - .of_match_table = xwdt_of_match, + .of_match_table = xilinx_wdt_of_match, }, }; -module_platform_driver(xwdt_driver); +module_platform_driver(xilinx_wdt_driver); MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>"); MODULE_DESCRIPTION("Xilinx Watchdog driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); Index: linux-3.12.24-rt38-xilinx/drivers/watchdog/zynq_wdt.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/watchdog/zynq_wdt.c 2014-07-20 22:06:38.716266791 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Zynq WDT driver + * + * Copyright (c) 2010-2013 Xilinx Inc. + * + * 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. + * + * 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., 675 Mass Ave, Cambridge, MA + * 02139, USA. + */ + +#include <linux/clk.h> +#include <linux/export.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/watchdog.h> + +#define ZYNQ_WDT_DEFAULT_TIMEOUT 10 +/* Supports 1 - 516 sec */ +#define ZYNQ_WDT_MIN_TIMEOUT 1 +#define ZYNQ_WDT_MAX_TIMEOUT 516 + +static int wdt_timeout = ZYNQ_WDT_DEFAULT_TIMEOUT; +static int nowayout = WATCHDOG_NOWAYOUT; + +module_param(wdt_timeout, int, 0); +MODULE_PARM_DESC(wdt_timeout, + "Watchdog time in seconds. (default=" + __MODULE_STRING(ZYNQ_WDT_DEFAULT_TIMEOUT) ")"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +/** + * struct zynq_wdt - Watchdog device structure. + * @regs: baseaddress of device. + * @busy: flag for the device. + * + * Structure containing parameters specific to ps watchdog. + */ +struct zynq_wdt { + void __iomem *regs; /* Base address */ + u32 rst; /* Reset flag */ + struct clk *clk; + u32 prescalar; + u32 ctrl_clksel; + spinlock_t io_lock; +}; +static struct zynq_wdt *wdt; + +/* + * Info structure used to indicate the features supported by the device + * to the upper layers. This is defined in watchdog.h header file. + */ +static struct watchdog_info zynq_wdt_info = { + .identity = "zynq_wdt watchdog", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +/* Write access to Registers */ +#define zynq_wdt_writereg(val, offset) __raw_writel(val, (wdt->regs) + offset) + +/*************************Register Map**************************************/ + +/* Register Offsets for the WDT */ +#define ZYNQ_WDT_ZMR_OFFSET 0x0 /* Zero Mode Register */ +#define ZYNQ_WDT_CCR_OFFSET 0x4 /* Counter Control Register */ +#define ZYNQ_WDT_RESTART_OFFSET 0x8 /* Restart Register */ +#define ZYNQ_WDT_SR_OFFSET 0xC /* Status Register */ + +/* + * Zero Mode Register - This register controls how the time out is indicated + * and also contains the access code to allow writes to the register (0xABC). + */ +#define ZYNQ_WDT_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */ +#define ZYNQ_WDT_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */ +#define ZYNQ_WDT_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */ +#define ZYNQ_WDT_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */ +#define ZYNQ_WDT_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */ +/* + * Counter Control register - This register controls how fast the timer runs + * and the reset value and also contains the access code to allow writes to + * the register. + */ +#define ZYNQ_WDT_CCR_CRV_MASK 0x00003FFC /* Counter reset value */ + +/** + * zynq_wdt_stop - Stop the watchdog. + * + * Read the contents of the ZMR register, clear the WDEN bit + * in the register and set the access key for successful write. + */ +static int zynq_wdt_stop(struct watchdog_device *wdd) +{ + spin_lock(&wdt->io_lock); + zynq_wdt_writereg((ZYNQ_WDT_ZMR_ZKEY_VAL & (~ZYNQ_WDT_ZMR_WDEN_MASK)), + ZYNQ_WDT_ZMR_OFFSET); + spin_unlock(&wdt->io_lock); + return 0; +} + +/** + * zynq_wdt_reload - Reload the watchdog timer (i.e. pat the watchdog). + * + * Write the restart key value (0x00001999) to the restart register. + */ +static int zynq_wdt_reload(struct watchdog_device *wdd) +{ + spin_lock(&wdt->io_lock); + zynq_wdt_writereg(0x00001999, ZYNQ_WDT_RESTART_OFFSET); + spin_unlock(&wdt->io_lock); + return 0; +} + +/** + * zynq_wdt_start - Enable and start the watchdog. + * + * The counter value is calculated according to the formula: + * calculated count = (timeout * clock) / prescalar + 1. + * The calculated count is divided by 0x1000 to obtain the field value + * to write to counter control register. + * Clears the contents of prescalar and counter reset value. Sets the + * prescalar to 4096 and the calculated count and access key + * to write to CCR Register. + * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit) + * or Interrupt signal(IRQEN) with a specified cycles and the access + * key to write to ZMR Register. + */ +static int zynq_wdt_start(struct watchdog_device *wdd) +{ + unsigned int data = 0; + unsigned short count; + unsigned long clock_f = clk_get_rate(wdt->clk); + + /* + * 0x1000 - Counter Value Divide, to obtain the value of counter + * reset to write to control register. + */ + count = (wdd->timeout * (clock_f / (wdt->prescalar))) / 0x1000 + 1; + + /* Check for boundary conditions of counter value */ + if (count > 0xFFF) + count = 0xFFF; + + spin_lock(&wdt->io_lock); + zynq_wdt_writereg(ZYNQ_WDT_ZMR_ZKEY_VAL, ZYNQ_WDT_ZMR_OFFSET); + + /* Shift the count value to correct bit positions */ + count = (count << 2) & ZYNQ_WDT_CCR_CRV_MASK; + + /* 0x00920000 - Counter register key value. */ + data = (count | 0x00920000 | (wdt->ctrl_clksel)); + zynq_wdt_writereg(data, ZYNQ_WDT_CCR_OFFSET); + data = ZYNQ_WDT_ZMR_WDEN_MASK | ZYNQ_WDT_ZMR_RSTLEN_16 | + ZYNQ_WDT_ZMR_ZKEY_VAL; + + /* Reset on timeout if specified in device tree. */ + if (wdt->rst) { + data |= ZYNQ_WDT_ZMR_RSTEN_MASK; + data &= ~ZYNQ_WDT_ZMR_IRQEN_MASK; + } else { + data &= ~ZYNQ_WDT_ZMR_RSTEN_MASK; + data |= ZYNQ_WDT_ZMR_IRQEN_MASK; + } + zynq_wdt_writereg(data, ZYNQ_WDT_ZMR_OFFSET); + spin_unlock(&wdt->io_lock); + zynq_wdt_writereg(0x00001999, ZYNQ_WDT_RESTART_OFFSET); + return 0; +} + +/** + * zynq_wdt_settimeout - Set a new timeout value for the watchdog device. + * + * @new_time: new timeout value that needs to be set. + * Returns 0 on success. + * + * Update the watchdog_device timeout with new value which is used when + * zynq_wdt_start is called. + */ +static int zynq_wdt_settimeout(struct watchdog_device *wdd, + unsigned int new_time) +{ + wdd->timeout = new_time; + return zynq_wdt_start(wdd); +} + +/** + * zynq_wdt_irq_handler - Notifies of watchdog timeout. + * + * @irq: interrupt number + * @dev_id: pointer to a platform device structure + * Returns IRQ_HANDLED + * + * The handler is invoked when the watchdog times out and a + * reset on timeout has not been enabled. + */ +static irqreturn_t zynq_wdt_irq_handler(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + dev_info(&pdev->dev, "Watchdog timed out.\n"); + return IRQ_HANDLED; +} + +/* Watchdog Core Ops */ +static struct watchdog_ops zynq_wdt_ops = { + .owner = THIS_MODULE, + .start = zynq_wdt_start, + .stop = zynq_wdt_stop, + .ping = zynq_wdt_reload, + .set_timeout = zynq_wdt_settimeout, +}; + +/* Watchdog Core Device */ +static struct watchdog_device zynq_wdt_device = { + .info = &zynq_wdt_info, + .ops = &zynq_wdt_ops, + .timeout = ZYNQ_WDT_DEFAULT_TIMEOUT, + .min_timeout = ZYNQ_WDT_MIN_TIMEOUT, + .max_timeout = ZYNQ_WDT_MAX_TIMEOUT, +}; + +/** + * zynq_wdt_notify_sys - Notifier for reboot or shutdown. + * + * @this: handle to notifier block. + * @code: turn off indicator. + * @unused: unused. + * Returns NOTIFY_DONE. + * + * This notifier is invoked whenever the system reboot or shutdown occur + * because we need to disable the WDT before system goes down as WDT might + * reset on the next boot. + */ +static int zynq_wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + /* Stop the watchdog */ + zynq_wdt_stop(&zynq_wdt_device); + return NOTIFY_DONE; +} + +/* Notifier Structure */ +static struct notifier_block zynq_wdt_notifier = { + .notifier_call = zynq_wdt_notify_sys, +}; + +/************************Platform Operations*****************************/ +/** + * zynq_wdt_probe - Probe call for the device. + * + * @pdev: handle to the platform device structure. + * Returns 0 on success, negative error otherwise. + * + * It does all the memory allocation and registration for the device. + */ +static int zynq_wdt_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret; + int irq; + unsigned long clock_f; + + /* Check whether WDT is in use, just for safety */ + if (wdt) { + dev_err(&pdev->dev, + "Device Busy, only 1 zynq_wdt instance supported.\n"); + return -EBUSY; + } + + /* Allocate an instance of the zynq_wdt structure */ + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + wdt->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(wdt->regs)) + return PTR_ERR(wdt->regs); + + /* Register the reboot notifier */ + ret = register_reboot_notifier(&zynq_wdt_notifier); + if (ret != 0) { + dev_err(&pdev->dev, "cannot register reboot notifier err=%d)\n", + ret); + return ret; + } + + /* Register the interrupt */ + of_property_read_u32(pdev->dev.of_node, "reset", &wdt->rst); + irq = platform_get_irq(pdev, 0); + if (!wdt->rst && irq >= 0) { + ret = devm_request_irq(&pdev->dev, irq, zynq_wdt_irq_handler, 0, + pdev->name, pdev); + if (ret) { + dev_err(&pdev->dev, + "cannot register interrupt handler err=%d\n", + ret); + goto err_notifier; + } + } + + /* Initialize the members of zynq_wdt structure */ + zynq_wdt_device.parent = &pdev->dev; + of_get_property(pdev->dev.of_node, "timeout", &zynq_wdt_device.timeout); + if (wdt_timeout < ZYNQ_WDT_MAX_TIMEOUT && + wdt_timeout > ZYNQ_WDT_MIN_TIMEOUT) + zynq_wdt_device.timeout = wdt_timeout; + else + dev_info(&pdev->dev, + "timeout limited to 1 - %d sec, using default=%d\n", + ZYNQ_WDT_MAX_TIMEOUT, ZYNQ_WDT_DEFAULT_TIMEOUT); + + watchdog_set_nowayout(&zynq_wdt_device, nowayout); + watchdog_set_drvdata(&zynq_wdt_device, &wdt); + + wdt->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(wdt->clk)) { + dev_err(&pdev->dev, "input clock not found\n"); + ret = PTR_ERR(wdt->clk); + goto err_notifier; + } + + ret = clk_prepare_enable(wdt->clk); + if (ret) { + dev_err(&pdev->dev, "unable to enable clock\n"); + goto err_notifier; + } + + clock_f = clk_get_rate(wdt->clk); + if (clock_f <= 10000000) {/* For PEEP */ + wdt->prescalar = 64; + wdt->ctrl_clksel = 1; + } else if (clock_f <= 75000000) { + wdt->prescalar = 256; + wdt->ctrl_clksel = 2; + } else { /* For Zynq */ + wdt->prescalar = 4096; + wdt->ctrl_clksel = 3; + } + + spin_lock_init(&wdt->io_lock); + + /* Register the WDT */ + ret = watchdog_register_device(&zynq_wdt_device); + if (ret) { + dev_err(&pdev->dev, "Failed to register wdt device\n"); + goto err_clk_disable; + } + platform_set_drvdata(pdev, wdt); + + dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n", + wdt->regs, zynq_wdt_device.timeout, + nowayout ? ", nowayout" : ""); + + return 0; + +err_clk_disable: + clk_disable_unprepare(wdt->clk); +err_notifier: + unregister_reboot_notifier(&zynq_wdt_notifier); + return ret; +} + +/** + * zynq_wdt_remove - Probe call for the device. + * + * @pdev: handle to the platform device structure. + * Returns 0 on success, otherwise negative error. + * + * Unregister the device after releasing the resources. + * Stop is allowed only when nowayout is disabled. + */ +static int __exit zynq_wdt_remove(struct platform_device *pdev) +{ + int res = 0; + int irq; + + if (wdt && !nowayout) { + zynq_wdt_stop(&zynq_wdt_device); + watchdog_unregister_device(&zynq_wdt_device); + unregister_reboot_notifier(&zynq_wdt_notifier); + irq = platform_get_irq(pdev, 0); + clk_disable_unprepare(wdt->clk); + } else { + dev_err(&pdev->dev, "Cannot stop watchdog, still ticking\n"); + return -ENOTSUPP; + } + return res; +} + +/** + * zynq_wdt_shutdown - Stop the device. + * + * @pdev: handle to the platform structure. + * + */ +static void zynq_wdt_shutdown(struct platform_device *pdev) +{ + /* Stop the device */ + zynq_wdt_stop(&zynq_wdt_device); + clk_disable_unprepare(wdt->clk); +} + +#ifdef CONFIG_PM_SLEEP +/** + * zynq_wdt_suspend - Stop the device. + * + * @dev: handle to the device structure. + * Returns 0 always. + */ +static int zynq_wdt_suspend(struct device *dev) +{ + /* Stop the device */ + zynq_wdt_stop(&zynq_wdt_device); + clk_disable(wdt->clk); + return 0; +} + +/** + * zynq_wdt_resume - Resume the device. + * + * @dev: handle to the device structure. + * Returns 0 on success, errno otherwise. + */ +static int zynq_wdt_resume(struct device *dev) +{ + int ret; + + ret = clk_enable(wdt->clk); + if (ret) { + dev_err(dev, "unable to enable clock\n"); + return ret; + } + /* Start the device */ + zynq_wdt_start(&zynq_wdt_device); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(zynq_wdt_pm_ops, zynq_wdt_suspend, zynq_wdt_resume); + +static struct of_device_id zynq_wdt_of_match[] = { + { .compatible = "xlnx,ps7-wdt-1.00.a", }, + { /* end of table */} +}; +MODULE_DEVICE_TABLE(of, zynq_wdt_of_match); + +/* Driver Structure */ +static struct platform_driver zynq_wdt_driver = { + .probe = zynq_wdt_probe, + .remove = zynq_wdt_remove, + .shutdown = zynq_wdt_shutdown, + .driver = { + .name = "zynq_wdt", + .owner = THIS_MODULE, + .of_match_table = zynq_wdt_of_match, + .pm = &zynq_wdt_pm_ops, + }, +}; + +/** + * zynq_wdt_init - Register the WDT. + * + * Returns 0 on success, otherwise negative error. + * + * If using noway out, the use count will be incremented. + * This will prevent unloading the module. An attempt to + * unload the module will result in a warning from the kernel. + */ +static int __init zynq_wdt_init(void) +{ + int res = platform_driver_register(&zynq_wdt_driver); + if (!res && nowayout) + try_module_get(THIS_MODULE); + return res; +} + +/** + * zynq_wdt_exit - Unregister the WDT. + */ +static void __exit zynq_wdt_exit(void) +{ + platform_driver_unregister(&zynq_wdt_driver); +} + +module_init(zynq_wdt_init); +module_exit(zynq_wdt_exit); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Watchdog driver for PS WDT"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform: zynq_wdt"); Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/Kconfig 2014-07-20 22:06:38.743266345 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +config XILINX_EDK + bool + depends on XILINX_VIRTEX || MICROBLAZE + default y + +config XILINX_LLDMA_USE_DCR + bool + depends on NEED_XILINX_LLDMA + default XILINX_VIRTEX_5_FXT + + +# +# Xilinx devices and common device driver infrastructure +# + +config XILINX_DRIVERS + bool + depends on PPC32 || MICROBLAZE + default y + ---help--- + This option is used to enable all of the Xilinx drivers on + supported architectures. This is often useful if you have a + Xilinx FPGA in a system, either using embedded processors + internal to the FPGA or external processors. + +config NEED_XILINX_DMAV3 + bool + +config NEED_XILINX_LLDMA + bool + +config NEED_XILINX_IPIF + bool Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/Makefile 2014-07-20 22:06:38.749266246 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# The Xilinx OS common code + +obj-$(CONFIG_XILINX_EDK) += xbasic_types.o xilinx_syms.o \ + xversion.o xpacket_fifo_v2_00_a.o xpacket_fifo_l_v2_00_a.o \ + xdma_channel.o xdma_channel_sg.o xio.o xil_assert.o + +obj-$(CONFIG_NEED_XILINX_DMAV3) += \ + xdmav3.o xdmav3_intr.o xdmav3_sg.o \ + xdmav3_selftest.o xdmav3_simple.o + +obj-$(CONFIG_NEED_XILINX_LLDMA) += \ + xlldma_bdring.o xlldma.o \ + xllfifo.o xstreamer.o + +obj-$(CONFIG_XILINX_LLDMA_USE_DCR) += \ + xio_dcr.o + +obj-$(CONFIG_NEED_XILINX_IPIF) += \ + xipif_v1_23_b.o Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xbasic_types.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xbasic_types.c 2014-07-20 22:06:38.756266131 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002-2003 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xbasic_types.c +* +* This file contains basic functions for Xilinx software IP. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a rpm 11/07/03 Added XNullHandler function as a stub interrupt handler +* 1.00a xd 11/03/04 Improved support for doxygen. +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/** + * This variable allows testing to be done easier with asserts. An assert + * sets this variable such that a driver can evaluate this variable + * to determine if an assert occurred. + */ +unsigned int XAssertStatus; + +/** + * This variable allows the assert functionality to be changed for testing + * such that it does not wait infinitely. Use the debugger to disable the + * waiting during testing of asserts. + */ +u32 XWaitInAssert = TRUE; + +/* The callback function to be invoked when an assert is taken */ +static XAssertCallback XAssertCallbackRoutine = (XAssertCallback) NULL; + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* +* Implements assert. Currently, it calls a user-defined callback function +* if one has been set. Then, it potentially enters an infinite loop depending +* on the value of the XWaitInAssert variable. +* +* @param File is the name of the filename of the source +* @param Line is the linenumber within File +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAssert(char *File, int Line) +{ + /* if the callback has been set then invoke it */ + if (XAssertCallbackRoutine != NULL) { + (*XAssertCallbackRoutine) (File, Line); + } + + /* if specified, wait indefinitely such that the assert will show up + * in testing + */ + while (XWaitInAssert) { + } +} + +/*****************************************************************************/ +/** +* +* Sets up a callback function to be invoked when an assert occurs. If there +* was already a callback installed, then it is replaced. +* +* @param Routine is the callback to be invoked when an assert is taken +* +* @return None. +* +* @note This function has no effect if NDEBUG is set +* +******************************************************************************/ +void XAssertSetCallback(XAssertCallback Routine) +{ + XAssertCallbackRoutine = Routine; +} + + +/*****************************************************************************/ +/** +* +* Null handler function. This follows the XInterruptHandler signature for +* interrupt handlers. It can be used to assign a null handler (a stub) to an +* interrupt controller vector table. +* +* @param NullParameter is an arbitrary void pointer and not used. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XNullHandler(void *NullParameter) +{ +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xbasic_types.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xbasic_types.h 2014-07-20 22:06:38.765265983 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xbasic_types.h,v 1.1 2006/12/13 14:21:22 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002-2004 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xbasic_types.h +* +* This file contains basic types for Xilinx software IP. These types do not +* follow the standard naming convention with respect to using the component +* name in front of each name because they are considered to be primitives. +* +* @note +* +* This file contains items which are architecture dependent. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a rmm 12/14/01 First release +* rmm 05/09/03 Added "xassert always" macros to rid ourselves of diab +* compiler warnings +* 1.00a rpm 11/07/03 Added XNullHandler function as a stub interrupt handler +* 1.00a rpm 07/21/04 Added XExceptionHandler typedef for processor exceptions +* 1.00a xd 11/03/04 Improved support for doxygen. +* </pre> +* +******************************************************************************/ + +#ifndef XBASIC_TYPES_H /* prevent circular inclusions */ +#define XBASIC_TYPES_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + +#include <linux/types.h> + +/************************** Constant Definitions *****************************/ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE !(TRUE) +#endif + +#define XCOMPONENT_IS_READY 0x11111111 /**< component has been initialized */ +#define XCOMPONENT_IS_STARTED 0x22222222 /**< component has been started */ + +/* the following constants and declarations are for unit test purposes and are + * designed to be used in test applications. + */ +#define XTEST_PASSED 0 +#define XTEST_FAILED 1 + +#define XASSERT_NONE 0 +#define XASSERT_OCCURRED 1 + +extern unsigned int XAssertStatus; +extern void XAssert(char *, int); + +/**************************** Type Definitions *******************************/ +/** + * This data type defines an interrupt handler for a device. + * The argument points to the instance of the component + */ +typedef void (*XInterruptHandler) (void *InstancePtr); + +/** + * This data type defines an exception handler for a processor. + * The argument points to the instance of the component + */ +typedef void (*XExceptionHandler) (void *InstancePtr); + +/** + * This data type defines a callback to be invoked when an + * assert occurs. The callback is invoked only when asserts are enabled + */ +typedef void (*XAssertCallback) (char *FilenamePtr, int LineNumber); + +/***************** Macros (Inline Functions) Definitions *********************/ + +#ifndef NDEBUG + +/*****************************************************************************/ +/** +* This assert macro is to be used for functions that do not return anything +* (void). This in conjunction with the XWaitInAssert boolean can be used to +* accomodate tests so that asserts which fail allow execution to continue. +* +* @param expression is the expression to evaluate. If it evaluates to +* false, the assert occurs. +* +* @return Returns void unless the XWaitInAssert variable is true, in which +* case no return is made and an infinite loop is entered. +* +* @note None. +* +******************************************************************************/ +#define XASSERT_VOID(expression) \ +{ \ + if (expression) \ + { \ + XAssertStatus = XASSERT_NONE; \ + } \ + else \ + { \ + XAssert(__FILE__, __LINE__); \ + XAssertStatus = XASSERT_OCCURRED; \ + return; \ + } \ +} + +/*****************************************************************************/ +/** +* This assert macro is to be used for functions that do return a value. This in +* conjunction with the XWaitInAssert boolean can be used to accomodate tests so +* that asserts which fail allow execution to continue. +* +* @param expression is the expression to evaluate. If it evaluates to false, +* the assert occurs. +* +* @return Returns 0 unless the XWaitInAssert variable is true, in which case +* no return is made and an infinite loop is entered. +* +* @note None. +* +******************************************************************************/ +#define XASSERT_NONVOID(expression) \ +{ \ + if (expression) \ + { \ + XAssertStatus = XASSERT_NONE; \ + } \ + else \ + { \ + XAssert(__FILE__, __LINE__); \ + XAssertStatus = XASSERT_OCCURRED; \ + return 0; \ + } \ +} + +/*****************************************************************************/ +/** +* Always assert. This assert macro is to be used for functions that do not +* return anything (void). Use for instances where an assert should always +* occur. +* +* @return Returns void unless the XWaitInAssert variable is true, in which case +* no return is made and an infinite loop is entered. +* +* @note None. +* +******************************************************************************/ +#define XASSERT_VOID_ALWAYS() \ +{ \ + XAssert(__FILE__, __LINE__); \ + XAssertStatus = XASSERT_OCCURRED; \ + return; \ +} + +/*****************************************************************************/ +/** +* Always assert. This assert macro is to be used for functions that do return +* a value. Use for instances where an assert should always occur. +* +* @return Returns void unless the XWaitInAssert variable is true, in which case +* no return is made and an infinite loop is entered. +* +* @note None. +* +******************************************************************************/ +#define XASSERT_NONVOID_ALWAYS() \ +{ \ + XAssert(__FILE__, __LINE__); \ + XAssertStatus = XASSERT_OCCURRED; \ + return 0; \ +} + + +#else + +#define XASSERT_VOID(expression) +#define XASSERT_VOID_ALWAYS() +#define XASSERT_NONVOID(expression) +#define XASSERT_NONVOID_ALWAYS() +#endif + +/************************** Function Prototypes ******************************/ + +void XAssertSetCallback(XAssertCallback Routine); +void XNullHandler(void *NullParameter); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xbuf_descriptor.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xbuf_descriptor.h 2014-07-20 22:06:38.790265570 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xbuf_descriptor.h,v 1.1 2006/12/13 14:21:30 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2001-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xbuf_descriptor.h +* +* <b>Description</b> +* +* This file contains the interface for the XBufDescriptor component. +* The XBufDescriptor component is a passive component that only maps over +* a buffer descriptor data structure shared by the scatter gather DMA hardware +* and software. The component's primary purpose is to provide encapsulation of +* the buffer descriptor processing. See the source file xbuf_descriptor.c for +* details. +* +* @note +* +* Most of the functions of this component are implemented as macros in order +* to optimize the processing. The names are not all uppercase such that they +* can be switched between macros and functions easily. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a xd 10/27/04 Doxygenated for inclusion in API documentation +* 1.00b ecm 10/31/05 Updated for the check sum offload changes. +* </pre> +* +******************************************************************************/ + +#ifndef XBUF_DESCRIPTOR_H /* prevent circular inclusions */ +#define XBUF_DESCRIPTOR_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xdma_channel_i.h" + +/************************** Constant Definitions *****************************/ + +/** @name Buffer Descriptor fields + * + * @{ + */ +/** This constant allows access to fields of a buffer descriptor + * and is necessary at this level of visibility to allow macros to access + * and modify the fields of a buffer descriptor. It is not expected that the + * user of a buffer descriptor would need to use this constant. + */ +#define XBD_DEVICE_STATUS_OFFSET 0 +#define XBD_CONTROL_OFFSET 1 +#define XBD_SOURCE_OFFSET 2 +#define XBD_DESTINATION_OFFSET 3 +#define XBD_LENGTH_OFFSET 4 +#define XBD_STATUS_OFFSET 5 +#define XBD_NEXT_PTR_OFFSET 6 +#define XBD_ID_OFFSET 7 +#define XBD_FLAGS_OFFSET 8 +#define XBD_RQSTED_LENGTH_OFFSET 9 +#define XBD_SIZE_IN_WORDS 10 +/* @} */ + +/** + * The following constants define the bits of the flags field of a buffer + * descriptor + */ +#define XBD_FLAGS_LOCKED_MASK 1UL + +/**************************** Type Definitions *******************************/ + +typedef u32 XBufDescriptor[XBD_SIZE_IN_WORDS]; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/** + * each of the following macros are named the same as functions rather than all + * upper case in order to allow either the macros or the functions to be + * used, see the source file xbuf_descriptor.c for documentation + */ + + +/*****************************************************************************/ +/** +* +* This function initializes a buffer descriptor component by zeroing all of the +* fields of the buffer descriptor. This function should be called prior to +* using a buffer descriptor. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_Initialize(InstancePtr) \ +{ \ + (*((u32 *)InstancePtr + XBD_CONTROL_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_SOURCE_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_LENGTH_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_STATUS_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_DEVICE_STATUS_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_NEXT_PTR_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_ID_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_FLAGS_OFFSET) = 0); \ + (*((u32 *)InstancePtr + XBD_RQSTED_LENGTH_OFFSET) = 0); \ +} + +/*****************************************************************************/ +/** +* +* This function gets the control field of a buffer descriptor component. The +* DMA channel hardware transfers the control field from the buffer descriptor +* into the DMA control register when a buffer descriptor is processed. It +* controls the details of the DMA transfer. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The control field contents of the buffer descriptor. One or more of the +* following values may be contained the field. Each of the values are +* unique bit masks. +* <br><br> +* - XDC_DMACR_SOURCE_INCR_MASK Increment the source address +* <br><br> +* - XDC_DMACR_DEST_INCR_MASK Increment the destination address +* <br><br> +* - XDC_DMACR_SOURCE_LOCAL_MASK Local source address +* <br><br> +* - XDC_DMACR_DEST_LOCAL_MASK Local destination address +* <br><br> +* - XDC_DMACR_SG_ENABLE_MASK Scatter gather enable +* <br><br> +* - XDC_DMACR_GEN_BD_INTR_MASK Individual buffer descriptor interrupt +* <br><br> +* - XDC_DMACR_LAST_BD_MASK Last buffer descriptor in a packet +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetControl(InstancePtr) \ + (u32)(*((u32 *)InstancePtr + XBD_CONTROL_OFFSET)) + +/*****************************************************************************/ +/** +* +* This function sets the control field of a buffer descriptor component. The +* DMA channel hardware transfers the control field from the buffer descriptor +* into the DMA control register when a buffer descriptor is processed. It +* controls the details of the DMA transfer such as +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* Control contains the value to be written to the control field of the buffer +* descriptor. One or more of the following values may be contained the field. +* Each of the values are unique bit masks such that they may be ORed together +* to enable multiple bits or inverted and ANDed to disable multiple bits. +* - XDC_DMACR_SOURCE_INCR_MASK Increment the source address +* - XDC_DMACR_DEST_INCR_MASK Increment the destination address +* - XDC_DMACR_SOURCE_LOCAL_MASK Local source address +* - XDC_DMACR_DEST_LOCAL_MASK Local destination address +* - XDC_DMACR_SG_ENABLE_MASK Scatter gather enable +* - XDC_DMACR_GEN_BD_INTR_MASK Individual buffer descriptor interrupt +* - XDC_DMACR_LAST_BD_MASK Last buffer descriptor in a packet +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetControl(InstancePtr, Control) \ + (*((u32 *)InstancePtr + XBD_CONTROL_OFFSET) = (u32)Control) + +/*****************************************************************************/ +/** +* +* This function determines if this buffer descriptor is marked as being the +* last in the control field. A packet may be broken up across multiple +* buffer descriptors such that the last buffer descriptor is the end of the +* packet. The DMA channel hardware copies the control field from the buffer +* descriptor to the control register of the DMA channel when the buffer +* descriptor is processed. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* TRUE if the buffer descriptor is marked as last in the control field, +* otherwise, FALSE. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_IsLastControl(InstancePtr) \ + (u32)((*((u32 *)InstancePtr + XBD_CONTROL_OFFSET) & \ + XDC_CONTROL_LAST_BD_MASK) == XDC_CONTROL_LAST_BD_MASK) + +/*****************************************************************************/ +/** +* +* This function marks the buffer descriptor as being last in the control +* field of the buffer descriptor. A packet may be broken up across multiple +* buffer descriptors such that the last buffer descriptor is the end of the +* packet. The DMA channel hardware copies the control field from the buffer +* descriptor to the control register of the DMA channel when the buffer +* descriptor is processed. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetLast(InstancePtr) \ + (*((u32 *)InstancePtr + XBD_CONTROL_OFFSET) |= XDC_CONTROL_LAST_BD_MASK) + +/*****************************************************************************/ +/** +* +* This function gets the source address field of the buffer descriptor. +* The source address indicates the address of memory which is the +* source of a DMA scatter gather operation. The DMA channel hardware +* copies the source address from the buffer descriptor to the source +* address register of the DMA channel when the buffer descriptor is processed. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The source address field of the buffer descriptor. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetSrcAddress(InstancePtr) \ + ((u32 *)(*((u32 *)InstancePtr + XBD_SOURCE_OFFSET))) + +/*****************************************************************************/ +/** +* +* This function sets the source address field of the buffer descriptor. +* The source address indicates the address of memory which is the +* source of a DMA scatter gather operation. The DMA channel hardware +* copies the source address from the buffer descriptor to the source +* address register of the DMA channel when the buffer descriptor is processed. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* SourceAddress contains the source address field for the buffer descriptor. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetSrcAddress(InstancePtr, Source) \ + (*((u32 *)InstancePtr + XBD_SOURCE_OFFSET) = (u32)Source) + +/*****************************************************************************/ +/** +* +* This function gets the destination address field of the buffer descriptor. +* The destination address indicates the address of memory which is the +* destination of a DMA scatter gather operation. The DMA channel hardware +* copies the destination address from the buffer descriptor to the destination +* address register of the DMA channel when the buffer descriptor is processed. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The destination address field of the buffer descriptor. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetDestAddress(InstancePtr) \ + ((u32 *)(*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET))) + +/*****************************************************************************/ +/** +* +* This function sets the destination address field of the buffer descriptor. +* The destination address indicates the address of memory which is the +* destination of a DMA scatter gather operation. The DMA channel hardware +* copies the destination address from the buffer descriptor to the destination +* address register of the DMA channel when the buffer descriptor is processed. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* DestinationAddress contains the destination address field for the buffer +* descriptor. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetDestAddress(InstancePtr, Destination) \ + (*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET) = (u32)Destination) + +/*****************************************************************************/ +/** +* +* This function gets the length of the data transfer if the buffer descriptor +* has been processed by the DMA channel hardware. If the buffer descriptor +* has not been processed, the return value will be zero indicating that no data +* has been transferred yet. This function uses both the length and requested +* length fields of the buffer descriptor to determine the number of bytes +* transferred by the DMA operation. The length field of the buffer descriptor +* contains the number of bytes remaining from the requested length. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The number of bytes which have been transferred by a DMA operation on the +* buffer descriptor. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetLength(InstancePtr) \ + (u32)(*((u32 *)InstancePtr + XBD_RQSTED_LENGTH_OFFSET) - \ + *((u32 *)InstancePtr + XBD_LENGTH_OFFSET)) + +/*****************************************************************************/ +/** +* +* This function sets the length and the requested length fields of the buffer +* descriptor. The length field indicates the number of bytes to transfer for +* the DMA operation and the requested length is written with the same value. +* The requested length is not modified by the DMA hardware while the length +* field is modified by the hardware to indicate the number of bytes remaining +* in the transfer after the transfer is complete. The requested length allows +* the software to calculate the actual number of bytes transferred for the DMA +* operation. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* Length contains the length to put in the length and requested length fields +* of the buffer descriptor. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetLength(InstancePtr, Length) \ +{ \ + (*((u32 *)InstancePtr + XBD_LENGTH_OFFSET) = (u32)(Length)); \ + (*((u32 *)InstancePtr + XBD_RQSTED_LENGTH_OFFSET) = (u32)(Length));\ +} + +/*****************************************************************************/ +/** +* +* This function gets the status field of a buffer descriptor component. The +* status field is written to the buffer descriptor by the DMA channel hardware +* after processing of a buffer descriptor is complete. The status field +* indicates the status of the DMA operation. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The status field contents of the buffer descriptor. One or more of the +* following values may be contained the field. Each of the values are +* unique bit masks. +* <br><br> +* - XDC_DMASR_BUSY_MASK The DMA channel is busy +* <br><br> +* - XDC_DMASR_BUS_ERROR_MASK A bus error occurred +* <br><br> +* - XDC_DMASR_BUS_TIMEOUT_MASK A bus timeout occurred +* <br><br> +* - XDC_DMASR_LAST_BD_MASK The last buffer descriptor of a packet +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetStatus(InstancePtr) \ + (u32)(*((u32 *)InstancePtr + XBD_STATUS_OFFSET)) + +/*****************************************************************************/ +/** +* +* This function sets the status field of a buffer descriptor component. The +* status field is written to the buffer descriptor by the DMA channel hardware +* after processing of a buffer descriptor is complete. This function would +* typically be used during debugging of buffer descriptor processing. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* Status contains the status field for the buffer descriptor. +* The status register contents of the DMA channel. One or more of the +* following values may be contained the register. Each of the values are +* unique bit masks. +* - XDC_DMASR_BUSY_MASK The DMA channel is busy +* - XDC_DMASR_BUS_ERROR_MASK A bus error occurred +* - XDC_DMASR_BUS_TIMEOUT_MASK A bus timeout occurred +* - XDC_DMASR_LAST_BD_MASK The last buffer descriptor of a packet +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetStatus(InstancePtr, Status) \ + (*((u32 *)InstancePtr + XBD_STATUS_OFFSET) = (u32)Status) + +/*****************************************************************************/ +/** +* +* This function determines if this buffer descriptor is marked as being the +* last in the status field. A packet may be broken up across multiple +* buffer descriptors such that the last buffer descriptor is the end of the +* packet. The DMA channel hardware copies the status register contents to +* the buffer descriptor of the DMA channel after processing of the buffer +* descriptor is complete. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* TRUE if the buffer descriptor is marked as last in the status field, +* otherwise, FALSE. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_IsLastStatus(InstancePtr) \ + (u32)((*((u32 *)InstancePtr + XBD_STATUS_OFFSET) & \ + XDC_STATUS_LAST_BD_MASK) == XDC_STATUS_LAST_BD_MASK) + +/*****************************************************************************/ +/** +* +* This function gets the device status field of the buffer descriptor. The +* device status is device specific such that the definition of the contents +* of this field are not defined in this function. The device is defined as the +* device which is using the DMA channel, such as an ethernet controller. The +* DMA channel hardware copies the contents of the device status register into +* the buffer descriptor when processing of the buffer descriptor is complete. +* This value is typically used by the device driver for the device to determine +* the status of the DMA operation with respect to the device. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The device status field of the buffer descriptor. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetDeviceStatus(InstancePtr) \ + ((u32)(*((u32 *)InstancePtr + XBD_DEVICE_STATUS_OFFSET))) + +/*****************************************************************************/ +/** +* +* This function sets the device status field of the buffer descriptor. The +* device status is device specific such that the definition of the contents +* of this field are not defined in this function. The device is defined as the +* device which is using the DMA channel, such as an ethernet controller. This +* function is typically only used for debugging/testing. +* +* The DMA channel hardware copies the contents of the device status register +* into the buffer descriptor when processing of the buffer descriptor is +* complete. This value is typically used by the device driver for the device +* to determine the status of the DMA operation with respect to the device. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* Status contains the device status field for the buffer descriptor. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetDeviceStatus(InstancePtr, Status) \ +{ \ + u32 Register; \ + Register = (*((u32 *)InstancePtr + XBD_DEVICE_STATUS_OFFSET)); \ + Register &= XDC_DMASR_RX_CS_RAW_MASK; \ + (*((u32 *)InstancePtr + XBD_DEVICE_STATUS_OFFSET)) = \ + Register | ((u32) (Status)); \ +} + +/*****************************************************************************/ +/** +* +* This function gets the next pointer field of the buffer descriptor. This +* field is used to link the buffer descriptors together such that multiple DMA +* operations can be automated for scatter gather. It also allows a single +* packet to be broken across multiple buffer descriptors. The DMA channel +* hardware traverses the list of buffer descriptors using the next pointer +* of each buffer descriptor. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The next pointer field of the buffer descriptor. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetNextPtr(InstancePtr) \ + (XBufDescriptor *)(*((u32 *)InstancePtr + XBD_NEXT_PTR_OFFSET)) + +/*****************************************************************************/ +/** +* +* This function sets the next pointer field of the buffer descriptor. This +* field is used to link the buffer descriptors together such that many DMA +* operations can be automated for scatter gather. It also allows a single +* packet to be broken across multiple buffer descriptors. The DMA channel +* hardware traverses the list of buffer descriptors using the next pointer +* of each buffer descriptor. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* NextPtr contains the next pointer field for the buffer descriptor. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetNextPtr(InstancePtr, NextPtr) \ + (*((u32 *)InstancePtr + XBD_NEXT_PTR_OFFSET) = (u32)NextPtr) + +/*****************************************************************************/ +/** +* +* This function gets the ID field of the buffer descriptor. The ID field is +* provided to allow a device driver to correlate the buffer descriptor to other +* data structures which may be operating system specific, such as a pointer to +* a higher level memory block. The ID field is not used by the DMA channel +* hardware and is application specific. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The ID field of the buffer descriptor. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetId(InstancePtr) \ + (u32)(*((u32 *)InstancePtr + XBD_ID_OFFSET)) + +/*****************************************************************************/ +/** +* +* This function sets the ID field of the buffer descriptor. The ID field is +* provided to allow a device driver to correlate the buffer descriptor to other +* data structures which may be operating system specific, such as a pointer to +* a higher level memory block. The ID field is not used by the DMA channel +* hardware and is application specific. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* Id contains the ID field for the buffer descriptor. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetId(InstancePtr, Id) \ + (*((u32 *)InstancePtr + XBD_ID_OFFSET) = (u32)Id) + +/*****************************************************************************/ +/** +* +* This function gets the flags field of the buffer descriptor. The flags +* field is not used by the DMA channel hardware and is used for software +* processing of buffer descriptors. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* The flags field of the buffer descriptor. The field may contain one or more +* of the following values which are bit masks. +* <br><br> +* - XBD_FLAGS_LOCKED_MASK Indicates the buffer descriptor is locked +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetFlags(InstancePtr) \ + (u32)(*((u32 *)InstancePtr + XBD_FLAGS_OFFSET)) + +/*****************************************************************************/ +/** +* +* This function sets the flags field of the buffer descriptor. The flags +* field is not used by the DMA channel hardware and is used for software +* processing of buffer descriptors. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @param +* +* Flags contains the flags field for the buffer descriptor. The field may +* contain one or more of the following values which are bit masks. +* - XBD_FLAGS_LOCKED_MASK Indicates the buffer descriptor is locked +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetFlags(InstancePtr, Flags) \ + (*((u32 *)InstancePtr + XBD_FLAGS_OFFSET) = (u32)Flags) + +/*****************************************************************************/ +/** +* +* This function locks the buffer descriptor. A lock is specific to the +* scatter gather processing and prevents a buffer descriptor from being +* overwritten in the scatter gather list. This field is not used by the DMA +* channel hardware such that the hardware could still write to the buffer +* descriptor. Locking a buffer descriptor is application specific and not +* necessary to allow the DMA channel to use the buffer descriptor, but is +* provided for flexibility in designing device drivers. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_Lock(InstancePtr) \ + (*((u32 *)InstancePtr + XBD_FLAGS_OFFSET) |= XBD_FLAGS_LOCKED_MASK) + +/*****************************************************************************/ +/** +* +* This function unlocks the buffer descriptor. A lock is specific to the +* scatter gather processing and prevents a buffer descriptor from being +* overwritten in the scatter gather list. This field is not used by the DMA +* channel hardware such that the hardware could still write to the buffer +* descriptor. Locking a buffer descriptor is application specific and not +* necessary to allow the DMA channel to use the buffer descriptor, but is +* provided for flex ability in designing device drivers. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_Unlock(InstancePtr) \ + (*((u32 *)InstancePtr + XBD_FLAGS_OFFSET) &= ~XBD_FLAGS_LOCKED_MASK) + +/*****************************************************************************/ +/** +* +* This function determines if the buffer descriptor is locked. The lock +* is not used by the DMA channel hardware and is used for software processing +* of buffer descriptors. +* +* @param +* +* InstancePtr points to the buffer descriptor to operate on. +* +* @return +* +* TRUE if the buffer descriptor is locked, otherwise FALSE. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_IsLocked(InstancePtr) \ + (u32) ((*((u32 *)InstancePtr + XBD_FLAGS_OFFSET) & \ + XBD_FLAGS_LOCKED_MASK) == XBD_FLAGS_LOCKED_MASK) + +/*****************************************************************************/ +/** +* +* This function gets the Initial value for the CS offload function. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* The initial value that will be used for checksum offload operation as DMA +* moves the data. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetCSInit(InstancePtr)\ +(*((u32 *)InstancePtr + XBD_CONTROL_OFFSET) &= XDC_DMACR_TX_CS_INIT_MASK) + +/*****************************************************************************/ +/** +* +* This function Sets the Initial value for the CS offload function. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* None +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetCSInit(InstancePtr, InitialValue) \ +{ \ + u32 Register; \ + Register = (*((u32 *)InstancePtr + XBD_CONTROL_OFFSET)); \ + Register &= ~XDC_DMACR_TX_CS_INIT_MASK; \ + (*((u32 *)InstancePtr + XBD_CONTROL_OFFSET)) = \ + Register | ((u32) (InitialValue)); \ +} +/*****************************************************************************/ +/** +* +* This function gets the byte position where the CS offload function +* inserts the calculated checksum. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* The insert byte location value that will be used to place the results of +* the checksum offload. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetCSInsertLoc(InstancePtr) \ +(*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET) &= XDC_DAREG_CS_INSERT_MASK) + +/*****************************************************************************/ +/** +* +* This function sets the byte position where the CS offload function +* inserts the calculated checksum. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* None +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetCSInsertLoc(InstancePtr, InsertLocation) \ +{ \ + u32 Register; \ + Register = (*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET)); \ + Register &= ~XDC_DAREG_CS_INSERT_MASK; \ + (*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET)) = \ + Register | ((u32) (InsertLocation)); \ +} + +/*****************************************************************************/ +/** +* +* This function gets the byte position where the CS offload function +* begins the calculation of the checksum. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* The insert byte location value that will be used to place the results of +* the checksum offload. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetCSBegin(InstancePtr) \ +(u16)((*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET)) >> 16) +/*****************************************************************************/ +/** +* +* This function sets the byte position where the CS offload function +* begins the calculation of the checksum. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* None +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_SetCSBegin(InstancePtr, BeginLocation) \ +{ \ + u32 Register; \ + Register = (*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET)); \ + Register &= ~XDC_DAREG_CS_BEGIN_MASK; \ + (*((u32 *)InstancePtr + XBD_DESTINATION_OFFSET)) = \ + Register | (((u32) (BeginLocation)) << 16); \ +} +/*****************************************************************************/ +/** +* +* This function gets the resulting checksum from the rx channel. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* The raw checksum calculation from the receive operation. It needs to +* be adjusted to remove the header and packet FCS to be correct. +* +* @note +* +* None. +* +******************************************************************************/ +#define XBufDescriptor_GetCSRaw(InstancePtr) \ +(u16)((*((u32 *)InstancePtr + XBD_DEVICE_STATUS_OFFSET)) >> 16) + +/************************** Function Prototypes ******************************/ + +/* The following prototypes are provided to allow each of the functions to + * be implemented as a function rather than a macro, and to provide the + * syntax to allow users to understand how to call the macros, they are + * commented out to prevent linker errors + * + +u32 XBufDescriptor_Initialize(XBufDescriptor* InstancePtr); + +u32 XBufDescriptor_GetControl(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetControl(XBufDescriptor* InstancePtr, u32 Control); + +u32 XBufDescriptor_IsLastControl(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetLast(XBufDescriptor* InstancePtr); + +u32 XBufDescriptor_GetLength(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetLength(XBufDescriptor* InstancePtr, u32 Length); + +u32 XBufDescriptor_GetStatus(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetStatus(XBufDescriptor* InstancePtr, u32 Status); +u32 XBufDescriptor_IsLastStatus(XBufDescriptor* InstancePtr); + +u32 XBufDescriptor_GetDeviceStatus(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetDeviceStatus(XBufDescriptor* InstancePtr, + u32 Status); + +u32 XBufDescriptor_GetSrcAddress(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetSrcAddress(XBufDescriptor* InstancePtr, + u32 SourceAddress); + +u32 XBufDescriptor_GetDestAddress(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetDestAddress(XBufDescriptor* InstancePtr, + u32 DestinationAddress); + +XBufDescriptor* XBufDescriptor_GetNextPtr(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetNextPtr(XBufDescriptor* InstancePtr, + XBufDescriptor* NextPtr); + +u32 XBufDescriptor_GetId(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetId(XBufDescriptor* InstancePtr, u32 Id); + +u32 XBufDescriptor_GetFlags(XBufDescriptor* InstancePtr); +void XBufDescriptor_SetFlags(XBufDescriptor* InstancePtr, u32 Flags); + +void XBufDescriptor_Lock(XBufDescriptor* InstancePtr); +void XBufDescriptor_Unlock(XBufDescriptor* InstancePtr); +u32 XBufDescriptor_IsLocked(XBufDescriptor* InstancePtr); + +u16 XBufDescriptor_GetCSInit(XBufDescriptor* InstancePtr) +void XBufDescriptor_SetCSInit(XBufDescriptor* InstancePtr, u16 InitialValue) + +u16 XBufDescriptor_GetCSInsertLoc(XBufDescriptor* InstancePtr) +void XBufDescriptor_SetCSInsertLoc(XBufDescriptor* InstancePtr, u16 InsertLocation) + +u16 XBufDescriptor_GetCSBegin(XBufDescriptor* InstancePtr) +void XBufDescriptor_SetCSBegin(XBufDescriptor* InstancePtr, u16 BeginLocation) + +u16 XBufDescriptor_GetCSRaw(XBufDescriptor* InstancePtr) + +void XBufDescriptor_Copy(XBufDescriptor* InstancePtr, + XBufDescriptor* DestinationPtr); + +*/ + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdebug.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdebug.h 2014-07-20 22:06:38.806265306 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +#ifndef XDEBUG +#define XDEBUG + +#undef DEBUG + +#if defined(DEBUG) && !defined(NDEBUG) + +#ifndef XDEBUG_WARNING +#define XDEBUG_WARNING +#warning DEBUG is enabled +#endif + +int printf(const char *format, ...); + +#define XDBG_DEBUG_ERROR 0x00000001 /* error condition messages */ +#define XDBG_DEBUG_GENERAL 0x00000002 /* general debug messages */ +#define XDBG_DEBUG_ALL 0xFFFFFFFF /* all debugging data */ + +#define XDBG_DEBUG_FIFO_REG 0x00000100 /* display register reads/writes */ +#define XDBG_DEBUG_FIFO_RX 0x00000101 /* receive debug messages */ +#define XDBG_DEBUG_FIFO_TX 0x00000102 /* transmit debug messages */ +#define XDBG_DEBUG_FIFO_ALL 0x0000010F /* all fifo debug messages */ + +#define XDBG_DEBUG_TEMAC_REG 0x00000400 /* display register reads/writes */ +#define XDBG_DEBUG_TEMAC_RX 0x00000401 /* receive debug messages */ +#define XDBG_DEBUG_TEMAC_TX 0x00000402 /* transmit debug messages */ +#define XDBG_DEBUG_TEMAC_ALL 0x0000040F /* all temac debug messages */ + +#define XDBG_DEBUG_TEMAC_ADPT_RX 0x00000800 /* receive debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_TX 0x00000801 /* transmit debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_IOCTL 0x00000802 /* ioctl debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_MISC 0x00000803 /* debug msg for other routines */ +#define XDBG_DEBUG_TEMAC_ADPT_ALL 0x0000080F /* all temac adapter debug messages */ + +#define xdbg_current_types (XDBG_DEBUG_ERROR | XDBG_DEBUG_GENERAL | XDBG_DEBUG_FIFO_REG | XDBG_DEBUG_TEMAC_REG) + +#define xdbg_stmnt(x) x +#define xdbg_printf(type, ...) (if ((type) & xdbg_current_types) printf (__VA_ARGS__) : 0) + +#else +#define xdbg_stmnt(x) +#define xdbg_printf(...) +#endif + + + + +#endif /* XDEBUG */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmabdv3.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmabdv3.h 2014-07-20 22:06:38.817265125 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2006 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xdmabdv3.h + * + * This header provides operations to manage buffer descriptors in support + * of simple and scatter-gather DMA (see xdmav3.h). + * + * The API exported by this header defines abstracted macros that allow the + * user to read/write specific BD fields. + * + * <b>Buffer Descriptors</b> + * + * A buffer descriptor (BD) defines a DMA transaction (see "Transaction" + * section in xdmav3.h). The macros defined by this header file allow access + * to most fields within a BD to tailor a DMA transaction according to user + * and HW requirements. See the HW IP DMA spec for more information on BD + * fields and how they affect transfers. + * + * The XDmaBdV3 structure defines a BD. The organization of this structure is + * driven mainly by the hardware for use in scatter-gather DMA transfers. + * + * <b>Accessor Macros</b> + * + * Most of the BD attributes can be accessed through macro functions defined + * here in this API. Words such as XDMAV3_BD_USR0_OFFSET (see xdmav3_l.h) + * should be accessed using XDmaV3_mReadBd() and XDmaV3_mWriteBd() as defined in + * xdmav3_l.h. The USR words are implementation dependent. For example, they may + * implement checksum offloading fields for Ethernet devices. Accessor macros + * may be defined in the device specific API to get at this data. + * + * <b>Performance</b> + * + * BDs are typically in a non-cached memory space. Limiting I/O to BDs can + * improve overall performance of the DMA channel. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 3.00a rmm 03/11/06 First release + * rmm 06/22/06 Added extern "C" + * </pre> + * + * *************************************************************************** + */ + +#ifndef XDMABD_H /* prevent circular inclusions */ +#define XDMABD_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include <asm/delay.h> +#include "xdmav3_l.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/** + * The XDmaBdV3 is the type for buffer descriptors (BDs). + */ +typedef u32 XDmaBdV3[XDMAV3_BD_NUM_WORDS]; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** + * Zero out BD fields + * + * @param BdPtr is the BD to operate on + * + * @return Nothing + * + * @note + * C-style signature: + * void XDmaBdV3_mClear(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mClear(BdPtr) \ + memset((BdPtr), 0, sizeof(XDmaBdV3)) + + +/*****************************************************************************/ +/** + * Retrieve the BD's Packet DMA transfer status word. + * + * @param BdPtr is the BD to operate on + * + * @return Word at offset XDMAV3_BD_DMASR_OFFSET + * + * @note + * C-style signature: + * u32 XDmaBdV3_mGetStatus(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mGetStatus(BdPtr) \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMASR_OFFSET) + + +/*****************************************************************************/ +/** + * Retrieve the BD's Packet status word. This is the first word of local link + * footer information for receive channels. + * + * @param BdPtr is the BD to operate on + * + * @return Word at offset XDMAV3_BD_SR_OFFSET + * + * @note + * C-style signature: + * u32 XDmaBdV3_mGetPacketStatus(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mGetPacketStatus(BdPtr) \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_SR_OFFSET) + + +/*****************************************************************************/ +/** + * Retrieve the BD length field. + * + * For Tx channels, the returned value is the same as that written with + * XDmaBdV3_mSetLength(). + * + * For Rx channels, the returned value is the size of the received packet. + * + * @param BdPtr is the BD to operate on + * + * @return Bytes processed by HW or set by XDmaBdV3_mSetLength(). + * + * @note + * C-style signature: + * u32 XDmaBdV3_mGetLength(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mGetLength(BdPtr) \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_LENGTH_OFFSET) + + +/*****************************************************************************/ +/** + * Retrieve the BD length copy field. See XDmaBdV3_mSetLengthCopy() for + * more information. + * + * @param BdPtr is the BD to operate on + * + * @return Value as set by XDmaBdV3_mSetLengthCopy(). + * + * @note + * C-style signature: + * u32 XDmaBdV3_mGetLengthCopy(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mGetLengthCopy(BdPtr) \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_LENCPY_OFFSET) + + +/*****************************************************************************/ +/** + * Test whether the given BD has been marked as the last BD of a packet. + * + * @param BdPtr is the BD to operate on + * + * @return TRUE if BD represents the "Last" BD of a packet, FALSE otherwise + * + * @note + * C-style signature: + * u32 XDmaBdV3_mIsLast(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mIsLast(BdPtr) \ + ((XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET) & XDMAV3_DMACR_LAST_MASK) ? \ + TRUE : FALSE) + +/*****************************************************************************/ +/** + * Set the ID field of the given BD. The ID is an arbitrary piece of data the + * user can associate with a specific BD. + * + * @param BdPtr is the BD to operate on + * @param Id is a 32 bit quantity to set in the BD + * + * @note + * C-style signature: + * void XDmaBdV3_mSetId(XDmaBdV3* BdPtr, void Id) + * + *****************************************************************************/ +#define XDmaBdV3_mSetId(BdPtr, Id) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_ID_OFFSET, (u32)Id)) + + +/*****************************************************************************/ +/** + * Retrieve the ID field of the given BD previously set with XDmaBdV3_mSetId. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * u32 XDmaBdV3_mGetId(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mGetId(BdPtr) (XDmaV3_mReadBd((BdPtr), XDMAV3_BD_ID_OFFSET)) + + +/*****************************************************************************/ +/** + * Causes the DMA engine to increment the buffer address during the DMA + * transfer for this BD. This is the desirable setting when the buffer data + * occupies a memory range. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * void XDmaBdV3_mSetBufIncrement(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mSetBufIncrement(BdPtr) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET) | XDMAV3_DMACR_AINC_MASK)) + + +/*****************************************************************************/ +/** + * Cause the DMA engine to use the same memory buffer address during the DMA + * transfer for this BD. This is the desirable setting when the buffer data + * occupies a single address as may be the case if transferring to/from a FIFO. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * void XDmaBdV3_mSetBufNoIncrement(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mSetBufNoIncrement(BdPtr) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET) & ~XDMAV3_DMACR_AINC_MASK)) + + +/*****************************************************************************/ +/** + * Bypass data realignment engine (DRE) if DMA channel has DRE capability. + * Has no effect if channel does not have DRE. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * void XDmaBdV3_mIgnoreDre(XDmaBdV3* BdPtr) + * + ******************************************************************************/ +#define XDmaBdV3_mIgnoreDre(BdPtr) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET) | XDMAV3_DMACR_BPDRE_MASK)) + + +/*****************************************************************************/ +/** + * Use data realignment engine (DRE) if DMA channel has DRE capability. + * Has no effect if channel does not have DRE. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * void XDmaBdV3_mUseDre(XDmaBdV3* BdPtr) + * + ******************************************************************************/ +#define XDmaBdV3_mUseDre(BdPtr) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET) & ~XDMAV3_DMACR_BPDRE_MASK)) + + +/*****************************************************************************/ +/** + * Tell the SG DMA engine that the given BD marks the end of the current packet + * to be processed. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * void XDmaBdV3_mSetLast(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mSetLast(BdPtr) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET) | XDMAV3_DMACR_LAST_MASK)) + + +/*****************************************************************************/ +/** + * Tell the SG DMA engine that the current packet does not end with the given + * BD. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * void XDmaBdV3_mClearLast(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mClearLast(BdPtr) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET) & ~XDMAV3_DMACR_LAST_MASK)) + + +/*****************************************************************************/ +/** + * Set the Device Select field of the given BD. + * + * @param BdPtr is the BD to operate on + * @param DevSel is the IP device select to use with LSB of 1. This value + * selects which IP block the transaction will address. Normally this + * is set to 0, but complex IP may require a specific DEVSEL. + * + * @note + * C-style signature: + * void XDmaBdV3_mSetDevSel(XDmaBdV3* BdPtr, unsigned DevSel) + * + *****************************************************************************/ +#define XDmaBdV3_mSetDevSel(BdPtr, DevSel) \ + { \ + u32 Dmacr; \ + Dmacr = XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET); \ + Dmacr = Dmacr | (((DevSel) << XDMAV3_DMACR_DEVSEL_SHIFT) & \ + XDMAV3_DMACR_DEVSEL_MASK); \ + XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, Dmacr); \ + } + + +/*****************************************************************************/ +/** + * Set the Page field of the given BD. The Page must be in terms of a physical + * address. Use this macro if using 36 bit bus addressing. + * + * @param BdPtr is the BD to operate on + * @param Page is the page to set. LSB=1 + * + * @note + * C-style signature: + * void XDmaBdV3_mSetBdPage(XDmaBdV3* BdPtr, unsigned Page) + * + *****************************************************************************/ +#define XDmaBdV3_mSetBdPage(BdPtr, Page) \ + { \ + u32 Dmacr; \ + Dmacr = XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET); \ + Dmacr = Dmacr | (((Page) << XDMAV3_DMACR_BDPAGE_SHIFT) & \ + XDMAV3_DMACR_BDPAGE_MASK); \ + XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, Dmacr); \ + } + + +/*****************************************************************************/ +/** + * Set transfer attributes for the given BD. + * + * @param BdPtr is the BD to operate on + * @param Type defines whether the transfer occurs with single beat or burst + * transfers on the target bus. This parameter must be one of the + * XDMAV3_DMACR_TYPE_*_MASK constants defined in xdma_l.h. + * @param Width defines the width of the transfer as it occurs on the target + * bus. This parameter must be one of the XDMAV3_DMACR_DSIZE_*_MASK + * constants defined in xdma_l.h + * + * @note + * C-style signature: + * void XDmaBdV3_mSetTransferType(XDmaBdV3* BdPtr, unsigned Type, + * unsigned Width) + * + *****************************************************************************/ +#define XDmaBdV3_mSetTransferType(BdPtr, Type, Width) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_DMACR_OFFSET, \ + XDmaV3_mReadBd((BdPtr), XDMAV3_BD_DMACR_OFFSET) | \ + ((Type) & XDMAV3_DMACR_TYPE_MASK) | ((Width) & XDMAV3_DMACR_DSIZE_MASK))) + + +/*****************************************************************************/ +/** + * Set transfer length in bytes for the given BD. The length must be set each + * time a BD is submitted to HW. + * + * @param BdPtr is the BD to operate on + * @param LenBytes is the number of bytes to transfer. + * + * @note + * C-style signature: + * void XDmaBdV3_mSetLength(XDmaBdV3* BdPtr, u32 LenBytes) + * + *****************************************************************************/ +#define XDmaBdV3_mSetLength(BdPtr, LenBytes) \ + XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_LENGTH_OFFSET, (LenBytes)) + + +/*****************************************************************************/ +/** + * Write the given length to the length copy offset of the BD. This function + * is useful only if an application needs to recover the number of bytes + * originally set by XDmaBdV3_mSetLength() for Rx channels. + * + * To effectively use this function, an application would call + * XDmaBdV3_mSetLength() to set the length on a Rx descriptor, followed by a + * call to this macro to set the same length. When HW has processed the Rx + * descriptor it will overwrite the BD length field with the actual length of + * the packet. When the application performs post processing of the Rx + * descriptor, it can call XDmaBdV3_mGetLengthCopy() to find out how many bytes + * were originally allocated to the descriptor. + * + * @param BdPtr is the BD to operate on + * @param LenBytes is the number of bytes to transfer. + * + * @note + * C-style signature: + * void XDmaBdV3_mSetLengthCopy(XDmaBdV3* BdPtr, u32 LenBytes) + * + *****************************************************************************/ +#define XDmaBdV3_mSetLengthCopy(BdPtr, LenBytes) \ + XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_LENCPY_OFFSET, (LenBytes)) + + +/*****************************************************************************/ +/** + * Set the high order address of the BD's buffer address. Use this macro when + * the address bus width is greater than 32 bits. + * + * @param BdPtr is the BD to operate on + * @param HighAddr is the high order address bits to set, LSB = 2^32. + * + * @note + * C-style signature: + * void XDmaBdV3_mSetBufAddrHigh(XDmaBdV3* BdPtr, u32 HighAddr) + * + *****************************************************************************/ +#define XDmaBdV3_mSetBufAddrHigh(BdPtr, HighAddr) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_MSBA_OFFSET, (u32)(HighAddr))) + + +/*****************************************************************************/ +/** + * Set the low order address (bits 0..31) of the BD's buffer address. + * + * @param BdPtr is the BD to operate on + * @param LowAddr is the low order address bits to set, LSB = 1. + * + * @note + * C-style signature: + * void XDmaBdV3_mSetBufAddrLow(XDmaBdV3* BdPtr, u32 LowAddr) + * + *****************************************************************************/ +#define XDmaBdV3_mSetBufAddrLow(BdPtr, LowAddr) \ + (XDmaV3_mWriteBd((BdPtr), XDMAV3_BD_LSBA_OFFSET, (u32)(LowAddr))) + + +/*****************************************************************************/ +/** + * Get the high order address of the BD's buffer address. Use this macro when + * the address bus width is greater than 32 bits. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * u32 XDmaBdV3_mGetBufAddrHigh(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mGetBufAddrHigh(BdPtr) \ + (XDmaV3_mReadBd((BdPtr), XDMAV3_BD_MSBA_OFFSET)) + + +/*****************************************************************************/ +/** + * Get the low order address (bits 0..31) of the BD's buffer address. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * u32 XDmaBdV3_mGetBufAddrLow(XDmaBdV3* BdPtr) + * + *****************************************************************************/ +#define XDmaBdV3_mGetBufAddrLow(BdPtr) \ + (XDmaV3_mReadBd((BdPtr), XDMAV3_BD_LSBA_OFFSET)) + + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdma_channel.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdma_channel.c 2014-07-20 22:06:38.831264894 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xdma_channel.c,v 1.1 2006/12/13 14:21:45 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2001-2004 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xdma_channel.c +* +* <b>Description</b> +* +* This file contains the DMA channel component. This component supports +* a distributed DMA design in which each device can have it's own dedicated +* DMA channel, as opposed to a centralized DMA design. This component +* performs processing for DMA on all devices. +* +* See xdma_channel.h for more information about this component. +* +* @note +* +* None. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a xd 10/27/04 Doxygenated for inclusion in API documentation +* 1.00b ecm 10/31/05 Updated for the check sum offload changes. +* 1.00b xd 03/22/06 Fixed a multi-descriptor packet related bug that sgdma +* engine is restarted in case no scatter gather disabled +* bit is set yet +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xdma_channel.h" +#include "xbasic_types.h" +#include "xio.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/*****************************************************************************/ +/** +* +* This function initializes a DMA channel. This function must be called +* prior to using a DMA channel. Initialization of a channel includes setting +* up the registers base address, and resetting the channel such that it's in a +* known state. Interrupts for the channel are disabled when the channel is +* reset. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @param +* +* BaseAddress contains the base address of the registers for the DMA channel. +* +* @return +* +* XST_SUCCESS indicating initialization was successful. +* +* @note +* +* None. +* +******************************************************************************/ +int XDmaChannel_Initialize(XDmaChannel * InstancePtr, u32 BaseAddress) +{ + /* assert to verify input arguments, don't assert base address */ + + XASSERT_NONVOID(InstancePtr != NULL); + + /* setup the base address of the registers for the DMA channel such + * that register accesses can be done + */ + InstancePtr->RegBaseAddress = BaseAddress; + + /* initialize the scatter gather list such that it indicates it has not + * been created yet and the DMA channel is ready to use (initialized) + */ + InstancePtr->GetPtr = NULL; + InstancePtr->PutPtr = NULL; + InstancePtr->CommitPtr = NULL; + InstancePtr->LastPtr = NULL; + + InstancePtr->TotalDescriptorCount = 0; + InstancePtr->ActiveDescriptorCount = 0; + + InstancePtr->ActivePacketCount = 0; + InstancePtr->Committed = FALSE; + + InstancePtr->IsReady = XCOMPONENT_IS_READY; + + /* initialize the version of the component + */ + XVersion_FromString(&InstancePtr->Version, "1.00a"); + + /* reset the DMA channel such that it's in a known state and ready + * and indicate the initialization occurred with no errors, note that + * the is ready variable must be set before this call or reset will assert + */ + XDmaChannel_Reset(InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function determines if a DMA channel component has been successfully +* initialized such that it's ready to use. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* TRUE if the DMA channel component is ready, FALSE otherwise. +* +* @note +* +* None. +* +******************************************************************************/ +u32 XDmaChannel_IsReady(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments used by the base component */ + + XASSERT_NONVOID(InstancePtr != NULL); + + return InstancePtr->IsReady == XCOMPONENT_IS_READY; +} + +/*****************************************************************************/ +/** +* +* This function gets the software version for the specified DMA channel +* component. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* A pointer to the software version of the specified DMA channel. +* +* @note +* +* None. +* +******************************************************************************/ +XVersion *XDmaChannel_GetVersion(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* return a pointer to the version of the DMA channel */ + + return &InstancePtr->Version; +} + +/*****************************************************************************/ +/** +* +* This function performs a self test on the specified DMA channel. This self +* test is destructive as the DMA channel is reset and a register default is +* verified. +* +* @param +* +* InstancePtr is a pointer to the DMA channel to be operated on. +* +* @return +* +* XST_SUCCESS is returned if the self test is successful, or one of the +* following errors. +* <br><br> +* - XST_DMA_RESET_REGISTER_ERROR Indicates the control register value +* after a reset was not correct +* +* @note +* +* This test does not performs a DMA transfer to test the channel because the +* DMA hardware will not currently allow a non-local memory transfer to non-local +* memory (memory copy), but only allows a non-local memory to or from the device +* memory (typically a FIFO). +* +******************************************************************************/ + +#define XDC_CONTROL_REG_RESET_MASK 0x98000000UL /* control reg reset value */ + +int XDmaChannel_SelfTest(XDmaChannel * InstancePtr) +{ + u32 ControlReg; + + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* reset the DMA channel such that it's in a known state before the test + * it resets to no interrupts enabled, the desired state for the test + */ + XDmaChannel_Reset(InstancePtr); + + /* this should be the first test to help prevent a lock up with the polling + * loop that occurs later in the test, check the reset value of the DMA + * control register to make sure it's correct, return with an error if not + */ + ControlReg = XDmaChannel_GetControl(InstancePtr); + if (ControlReg != XDC_CONTROL_REG_RESET_MASK) { + return XST_DMA_RESET_REGISTER_ERROR; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function resets the DMA channel. This is a destructive operation such +* that it should not be done while a channel is being used. If the DMA channel +* is transferring data into other blocks, such as a FIFO, it may be necessary +* to reset other blocks. This function does not modify the contents of a +* scatter gather list for a DMA channel such that the user is responsible for +* getting buffer descriptors from the list if necessary. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XDmaChannel_Reset(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* reset the DMA channel such that it's in a known state, the reset + * register is self clearing such that it only has to be set + */ + XIo_Out32(InstancePtr->RegBaseAddress + XDC_RST_REG_OFFSET, + XDC_RESET_MASK); +} + +/*****************************************************************************/ +/** +* +* This function gets the control register contents of the DMA channel. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* The control register contents of the DMA channel. One or more of the +* following values may be contained the register. Each of the values are +* unique bit masks. +* <br><br> +* - XDC_DMACR_SOURCE_INCR_MASK Increment the source address +* <br><br> +* - XDC_DMACR_DEST_INCR_MASK Increment the destination address +* <br><br> +* - XDC_DMACR_SOURCE_LOCAL_MASK Local source address +* <br><br> +* - XDC_DMACR_DEST_LOCAL_MASK Local destination address +* <br><br> +* - XDC_DMACR_SG_ENABLE_MASK Scatter gather enable +* <br><br> +* - XDC_DMACR_GEN_BD_INTR_MASK Individual buffer descriptor interrupt +* <br><br> +* - XDC_DMACR_LAST_BD_MASK Last buffer descriptor in a packet +* +* @note +* +* None. +* +******************************************************************************/ +u32 XDmaChannel_GetControl(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* return the contents of the DMA control register */ + + return XIo_In32(InstancePtr->RegBaseAddress + XDC_DMAC_REG_OFFSET); +} + +/*****************************************************************************/ +/** +* +* This function sets the control register of the specified DMA channel. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @param +* +* Control contains the value to be written to the control register of the DMA +* channel. One or more of the following values may be contained the register. +* Each of the values are unique bit masks such that they may be ORed together +* to enable multiple bits or inverted and ANDed to disable multiple bits. +* - XDC_DMACR_SOURCE_INCR_MASK Increment the source address +* - XDC_DMACR_DEST_INCR_MASK Increment the destination address +* - XDC_DMACR_SOURCE_LOCAL_MASK Local source address +* - XDC_DMACR_DEST_LOCAL_MASK Local destination address +* - XDC_DMACR_SG_ENABLE_MASK Scatter gather enable +* - XDC_DMACR_GEN_BD_INTR_MASK Individual buffer descriptor interrupt +* - XDC_DMACR_LAST_BD_MASK Last buffer descriptor in a packet +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XDmaChannel_SetControl(XDmaChannel * InstancePtr, u32 Control) +{ + u32 Register; + + /* assert to verify input arguments except the control which can't be + * asserted since all values are valid + */ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* + * set the DMA control register to the specified value, not altering the + * other fields in the register + */ + + Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_DMAC_REG_OFFSET); + Register &= XDC_DMACR_TX_CS_INIT_MASK; + XIo_Out32(InstancePtr->RegBaseAddress + XDC_DMAC_REG_OFFSET, + Register | Control); +} + +/*****************************************************************************/ +/** +* +* This function gets the status register contents of the DMA channel. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* The status register contents of the DMA channel. One or more of the +* following values may be contained the register. Each of the values are +* unique bit masks. +* <br><br> +* - XDC_DMASR_BUSY_MASK The DMA channel is busy +* <br><br> +* - XDC_DMASR_BUS_ERROR_MASK A bus error occurred +* <br><br> +* - XDC_DMASR_BUS_TIMEOUT_MASK A bus timeout occurred +* <br><br> +* - XDC_DMASR_LAST_BD_MASK The last buffer descriptor of a packet +* +* @note +* +* None. +* +******************************************************************************/ +u32 XDmaChannel_GetStatus(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* return the contents of the DMA status register */ + + return XIo_In32(InstancePtr->RegBaseAddress + XDC_DMAS_REG_OFFSET); +} + +/*****************************************************************************/ +/** +* +* This function sets the interrupt status register of the specified DMA channel. +* Setting any bit of the interrupt status register will clear the bit to +* indicate the interrupt processing has been completed. The definitions of each +* bit in the register match the definition of the bits in the interrupt enable +* register. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @param +* +* Status contains the value to be written to the status register of the DMA +* channel. One or more of the following values may be contained the register. +* Each of the values are unique bit masks such that they may be ORed together +* to enable multiple bits or inverted and ANDed to disable multiple bits. +* - XDC_IXR_DMA_DONE_MASK The dma operation is done +* - XDC_IXR_DMA_ERROR_MASK The dma operation had an error +* - XDC_IXR_PKT_DONE_MASK A packet is complete +* - XDC_IXR_PKT_THRESHOLD_MASK The packet count threshold reached +* - XDC_IXR_PKT_WAIT_BOUND_MASK The packet wait bound reached +* - XDC_IXR_SG_DISABLE_ACK_MASK The scatter gather disable completed +* - XDC_IXR_BD_MASK A buffer descriptor is done +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XDmaChannel_SetIntrStatus(XDmaChannel * InstancePtr, u32 Status) +{ + /* assert to verify input arguments except the status which can't be + * asserted since all values are valid + */ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* set the interrupt status register with the specified value such that + * all bits which are set in the register are cleared effectively clearing + * any active interrupts + */ + XIo_Out32(InstancePtr->RegBaseAddress + XDC_IS_REG_OFFSET, Status); +} + +/*****************************************************************************/ +/** +* +* This function gets the interrupt status register of the specified DMA channel. +* The interrupt status register indicates which interrupts are active +* for the DMA channel. If an interrupt is active, the status register must be +* set (written) with the bit set for each interrupt which has been processed +* in order to clear the interrupts. The definitions of each bit in the register +* match the definition of the bits in the interrupt enable register. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* The interrupt status register contents of the specified DMA channel. +* One or more of the following values may be contained the register. +* Each of the values are unique bit masks. +* <br><br> +* - XDC_IXR_DMA_DONE_MASK The dma operation is done +* <br><br> +* - XDC_IXR_DMA_ERROR_MASK The dma operation had an error +* <br><br> +* - XDC_IXR_PKT_DONE_MASK A packet is complete +* <br><br> +* - XDC_IXR_PKT_THRESHOLD_MASK The packet count threshold reached +* <br><br> +* - XDC_IXR_PKT_WAIT_BOUND_MASK The packet wait bound reached +* <br><br> +* - XDC_IXR_SG_DISABLE_ACK_MASK The scatter gather disable completed +* <br><br> +* - XDC_IXR_SG_END_MASK Current descriptor was the end of the list +* <br><br> +* - XDC_IXR_BD_MASK A buffer descriptor is done +* +* @note +* +* None. +* +******************************************************************************/ +u32 XDmaChannel_GetIntrStatus(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* return the contents of the interrupt status register */ + + return XIo_In32(InstancePtr->RegBaseAddress + XDC_IS_REG_OFFSET); +} + +/*****************************************************************************/ +/** +* +* This function sets the interrupt enable register of the specified DMA +* channel. The interrupt enable register contains bits which enable +* individual interrupts for the DMA channel. The definitions of each bit +* in the register match the definition of the bits in the interrupt status +* register. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @param +* +* Enable contains the interrupt enable register contents to be written +* in the DMA channel. One or more of the following values may be contained +* the register. Each of the values are unique bit masks such that they may be +* ORed together to enable multiple bits or inverted and ANDed to disable +* multiple bits. +* - XDC_IXR_DMA_DONE_MASK The dma operation is done +* - XDC_IXR_DMA_ERROR_MASK The dma operation had an error +* - XDC_IXR_PKT_DONE_MASK A packet is complete +* - XDC_IXR_PKT_THRESHOLD_MASK The packet count threshold reached +* - XDC_IXR_PKT_WAIT_BOUND_MASK The packet wait bound reached +* - XDC_IXR_SG_DISABLE_ACK_MASK The scatter gather disable completed +* - XDC_IXR_SG_END_MASK Current descriptor was the end of the list +* - XDC_IXR_BD_MASK A buffer descriptor is done +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XDmaChannel_SetIntrEnable(XDmaChannel * InstancePtr, u32 Enable) +{ + /* assert to verify input arguments except the enable which can't be + * asserted since all values are valid + */ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* set the interrupt enable register to the specified value */ + + XIo_Out32(InstancePtr->RegBaseAddress + XDC_IE_REG_OFFSET, Enable); +} + +/*****************************************************************************/ +/** +* +* This function gets the interrupt enable of the DMA channel. The +* interrupt enable contains flags which enable individual interrupts for the +* DMA channel. The definitions of each bit in the register match the definition +* of the bits in the interrupt status register. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @return +* +* The interrupt enable of the DMA channel. One or more of the following values +* may be contained the register. Each of the values are unique bit masks. +* <br><br> +* - XDC_IXR_DMA_DONE_MASK The dma operation is done +* <br><br> +* - XDC_IXR_DMA_ERROR_MASK The dma operation had an error +* <br><br> +* - XDC_IXR_PKT_DONE_MASK A packet is complete +* <br><br> +* - XDC_IXR_PKT_THRESHOLD_MASK The packet count threshold reached +* <br><br> +* - XDC_IXR_PKT_WAIT_BOUND_MASK The packet wait bound reached +* <br><br> +* - XDC_IXR_SG_DISABLE_ACK_MASK The scatter gather disable completed +* <br><br> +* - XDC_IXR_BD_MASK A buffer descriptor is done +* +* @note +* +* None. +* +******************************************************************************/ +u32 XDmaChannel_GetIntrEnable(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* return the contents of the interrupt enable register */ + + return XIo_In32(InstancePtr->RegBaseAddress + XDC_IE_REG_OFFSET); +} + +/*****************************************************************************/ +/** +* +* This function starts the DMA channel transferring data from a memory source +* to a memory destination. This function only starts the operation and returns +* before the operation may be complete. If the interrupt is enabled, an +* interrupt will be generated when the operation is complete, otherwise it is +* necessary to poll the channel status to determine when it's complete. It is +* the responsibility of the caller to determine when the operation is complete +* by handling the generated interrupt or polling the status. It is also the +* responsibility of the caller to ensure that the DMA channel is not busy with +* another transfer before calling this function. +* +* @param +* +* InstancePtr contains a pointer to the DMA channel to operate on. +* +* @param +* +* SourcePtr contains a pointer to the source memory where the data is to +* be transferred from and must be 32 bit aligned. +* +* @param +* +* DestinationPtr contains a pointer to the destination memory where the data +* is to be transferred and must be 32 bit aligned. +* +* @param +* +* ByteCount contains the number of bytes to transfer during the DMA operation. +* +* @return +* +* None. +* +* @note +* +* The DMA hw will not currently allow a non-local memory transfer to non-local +* memory (memory copy), but only allows a non-local memory to or from the device +* memory (typically a FIFO). +* <br><br> +* It is the responsibility of the caller to ensure that the cache is +* flushed and invalidated both before and after the DMA operation completes +* if the memory pointed to is cached. The caller must also ensure that the +* pointers contain a physical address rather than a virtual address +* if address translation is being used. +* +******************************************************************************/ +void XDmaChannel_Transfer(XDmaChannel * InstancePtr, + u32 *SourcePtr, u32 *DestinationPtr, u32 ByteCount) +{ + /* assert to verify input arguments and the alignment of any arguments + * which have expected alignments + */ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(SourcePtr != NULL); + XASSERT_VOID(((u32) SourcePtr & 3) == 0); + XASSERT_VOID(DestinationPtr != NULL); + XASSERT_VOID(((u32) DestinationPtr & 3) == 0); + XASSERT_VOID(ByteCount != 0); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* setup the source and destination address registers for the transfer */ + + XIo_Out32(InstancePtr->RegBaseAddress + XDC_SA_REG_OFFSET, + (u32) SourcePtr); + + XIo_Out32(InstancePtr->RegBaseAddress + XDC_DA_REG_OFFSET, + (u32) DestinationPtr); + + /* start the DMA transfer to copy from the source buffer to the + * destination buffer by writing the length to the length register + */ + XIo_Out32(InstancePtr->RegBaseAddress + XDC_LEN_REG_OFFSET, ByteCount); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdma_channel.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdma_channel.h 2014-07-20 22:06:38.841264729 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/****************************************************************************** +* +* Author: Xilinx, Inc. +* +* +* 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. +* +* +* 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 THIRD PARTY 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. +* +* +* Xilinx hardware products are not intended for use in life support +* appliances, devices, or systems. Use in such applications is +* expressly prohibited. +* +* +* (c) Copyright 2002-2004 Xilinx Inc. +* All rights reserved. +* +* +* 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., +* 675 Mass Ave, Cambridge, MA 02139, USA. +* +* FILENAME: +* +* xdma_channel.h +* +* DESCRIPTION: +* +* This file contains the DMA channel component implementation. This component +* supports a distributed DMA design in which each device can have it's own +* dedicated DMA channel, as opposed to a centralized DMA design. +* A device which uses DMA typically contains two DMA channels, one for +* sending data and the other for receiving data. +* +* This component is designed to be used as a basic building block for +* designing a device driver. It provides registers accesses such that all +* DMA processing can be maintained easier, but the device driver designer +* must still understand all the details of the DMA channel. +* +* The DMA channel allows a CPU to minimize the CPU interaction required to move +* data between a memory and a device. The CPU requests the DMA channel to +* perform a DMA operation and typically continues performing other processing +* until the DMA operation completes. DMA could be considered a primitive form +* of multiprocessing such that caching and address translation can be an issue. +* +* Scatter Gather Operations +* +* The DMA channel may support scatter gather operations. A scatter gather +* operation automates the DMA channel such that multiple buffers can be +* sent or received with minimal software interaction with the hardware. Buffer +* descriptors, contained in the XBufDescriptor component, are used by the +* scatter gather operations of the DMA channel to describe the buffers to be +* processed. +* +* Scatter Gather List Operations +* +* A scatter gather list may be supported by each DMA channel. The scatter +* gather list allows buffer descriptors to be put into the list by a device +* driver which requires scatter gather. The hardware processes the buffer +* descriptors which are contained in the list and modifies the buffer +* descriptors to reflect the status of the DMA operations. The device driver +* is notified by interrupt that specific DMA events occur including scatter +* gather events. The device driver removes the completed buffer descriptors +* from the scatter gather list to evaluate the status of each DMA operation. +* +* The scatter gather list is created and buffer descriptors are inserted into +* the list. Buffer descriptors are never removed from the list after it's +* creation such that a put operation copies from a temporary buffer descriptor +* to a buffer descriptor in the list. Get operations don't copy from the list +* to a temporary, but return a pointer to the buffer descriptor in the list. +* A buffer descriptor in the list may be locked to prevent it from being +* overwritten by a put operation. This allows the device driver to get a +* descriptor from a scatter gather list and prevent it from being overwritten +* until the buffer associated with the buffer descriptor has been processed. +* +* Typical Scatter Gather Processing +* +* The following steps illustrate the typical processing to use the +* scatter gather features of a DMA channel. +* +* 1. Create a scatter gather list for the DMA channel which puts empty buffer +* descriptors into the list. +* 2. Create buffer descriptors which describe the buffers to be filled with +* receive data or the buffers which contain data to be sent. +* 3. Put buffer descriptors into the DMA channel scatter list such that scatter +* gather operations are requested. +* 4. Commit the buffer descriptors in the list such that they are ready to be +* used by the DMA channel hardware. +* 5. Start the scatter gather operations of the DMA channel. +* 6. Process any interrupts which occur as a result of the scatter gather +* operations or poll the DMA channel to determine the status. +* +* Interrupts +* +* Each DMA channel has the ability to generate an interrupt. This component +* does not perform processing for the interrupt as this processing is typically +* tightly coupled with the device which is using the DMA channel. It is the +* responsibility of the caller of DMA functions to manage the interrupt +* including connecting to the interrupt and enabling/disabling the interrupt. +* +* Critical Sections +* +* It is the responsibility of the device driver designer to use critical +* sections as necessary when calling functions of the DMA channel. This +* component does not use critical sections and it does access registers using +* read-modify-write operations. Calls to DMA functions from a main thread +* and from an interrupt context could produce unpredictable behavior such that +* the caller must provide the appropriate critical sections. +* +* Address Translation +* +* All addresses of data structures which are passed to DMA functions must +* be physical (real) addresses as opposed to logical (virtual) addresses. +* +* Caching +* +* The memory which is passed to the function which creates the scatter gather +* list must not be cached such that buffer descriptors are non-cached. This +* is necessary because the buffer descriptors are kept in a ring buffer and +* not directly accessible to the caller of DMA functions. +* +* The caller of DMA functions is responsible for ensuring that any data +* buffers which are passed to the DMA channel are cache-line aligned if +* necessary. +* +* The caller of DMA functions is responsible for ensuring that any data +* buffers which are passed to the DMA channel have been flushed from the cache. +* +* The caller of DMA functions is responsible for ensuring that the cache is +* invalidated prior to using any data buffers which are the result of a DMA +* operation. +* +* Memory Alignment +* +* The addresses of data buffers which are passed to DMA functions must be +* 32 bit word aligned since the DMA hardware performs 32 bit word transfers. +* +* Mutual Exclusion +* +* The functions of the DMA channel are not thread safe such that the caller +* of all DMA functions is responsible for ensuring mutual exclusion for a +* DMA channel. Mutual exclusion across multiple DMA channels is not +* necessary. +* +* NOTES: +* +* Many of the provided functions which are register accessors don't provide +* a lot of error detection. The caller is expected to understand the impact +* of a function call based upon the current state of the DMA channel. This +* is done to minimize the overhead in this component. +* +******************************************************************************/ + +#ifndef XDMA_CHANNEL_H /* prevent circular inclusions */ +#define XDMA_CHANNEL_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xstatus.h" +#include "xversion.h" +#include "xbuf_descriptor.h" +#include "xdma_channel_i.h" /* constants shared with buffer descriptor */ + +/************************** Constant Definitions *****************************/ + +/* the following constants provide access to the bit fields of the DMA control + * register (DMACR) + */ +#define XDC_DMACR_SOURCE_INCR_MASK 0x80000000UL /* increment source address */ +#define XDC_DMACR_DEST_INCR_MASK 0x40000000UL /* increment dest address */ +#define XDC_DMACR_SOURCE_LOCAL_MASK 0x20000000UL /* local source address */ +#define XDC_DMACR_DEST_LOCAL_MASK 0x10000000UL /* local dest address */ +#define XDC_DMACR_SG_DISABLE_MASK 0x08000000UL /* scatter gather disable */ +#define XDC_DMACR_GEN_BD_INTR_MASK 0x04000000UL /* descriptor interrupt */ +#define XDC_DMACR_LAST_BD_MASK XDC_CONTROL_LAST_BD_MASK /* last buffer */ + /* descriptor */ +#define XDC_DMACR_DRE_MODE_MASK 0x01000000UL /* DRE/normal mode */ + +#define XDC_DMACR_TX_CS_INIT_MASK 0x0000FFFFUL /* Initial value for TX + CS offload */ +#define XDC_DMACR_CS_OFFLOAD_MASK 0x00800000UL /* Enable CS offload */ + +/* the following constants provide access to the bit fields of the DMA status + * register (DMASR) + */ +#define XDC_DMASR_BUSY_MASK 0x80000000UL /* channel is busy */ +#define XDC_DMASR_BUS_ERROR_MASK 0x40000000UL /* bus error occurred */ +#define XDC_DMASR_BUS_TIMEOUT_MASK 0x20000000UL /* bus timeout occurred */ +#define XDC_DMASR_LAST_BD_MASK XDC_STATUS_LAST_BD_MASK /* last buffer */ + /* descriptor */ +#define XDC_DMASR_SG_BUSY_MASK 0x08000000UL /* scatter gather is busy */ +/* @} */ + +/** @name DMA destination address register bit fields when checksum offload is + * used + * + * the following constants provide access to the bit fields of the + * Destination Address Register (DAREG) + * @{ + */ +#define XDC_DAREG_CS_BEGIN_MASK 0xFFFF0000UL /* byte position to begin + checksum calculation */ +#define XDC_DAREG_CS_INSERT_MASK 0x0000FFFFUL /* byte position to place + calculated checksum */ +/* the following constants provide access to the bit fields of the interrupt + * status register (ISR) and the interrupt enable register (IER), bit masks + * match for both registers such that they are named IXR + */ +#define XDC_IXR_DMA_DONE_MASK 0x1UL /* dma operation done */ +#define XDC_IXR_DMA_ERROR_MASK 0x2UL /* dma operation error */ +#define XDC_IXR_PKT_DONE_MASK 0x4UL /* packet done */ +#define XDC_IXR_PKT_THRESHOLD_MASK 0x8UL /* packet count threshold */ +#define XDC_IXR_PKT_WAIT_BOUND_MASK 0x10UL /* packet wait bound reached */ +#define XDC_IXR_SG_DISABLE_ACK_MASK 0x20UL /* scatter gather disable + acknowledge occurred */ +#define XDC_IXR_SG_END_MASK 0x40UL /* last buffer descriptor + disabled scatter gather */ +#define XDC_IXR_BD_MASK 0x80UL /* buffer descriptor done */ + +/**************************** Type Definitions *******************************/ + +/* + * the following structure contains data which is on a per instance basis + * for the XDmaChannel component + */ +typedef struct XDmaChannelTag { + XVersion Version; /* version of the driver */ + u32 RegBaseAddress; /* base address of registers */ + u32 IsReady; /* device is initialized and ready */ + + XBufDescriptor *PutPtr; /* keep track of where to put into list */ + XBufDescriptor *GetPtr; /* keep track of where to get from list */ + XBufDescriptor *CommitPtr; /* keep track of where to commit in list */ + XBufDescriptor *LastPtr; /* keep track of the last put in the list */ + void *VirtPtr; /* virtual base of memory */ + void *PhyPtr; /* physical base of memory */ + u32 TotalDescriptorCount; /* total # of descriptors in the list */ + u32 ActiveDescriptorCount; /* # of descriptors pointing to buffers + * in the buffer descriptor list */ + u32 ActivePacketCount; /* # of packets that have been put into + the list and transmission confirmation + have not been received by the driver */ + u32 Committed; /* CommitPuts is called? */ +} XDmaChannel; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int XDmaChannel_Initialize(XDmaChannel * InstancePtr, u32 BaseAddress); +u32 XDmaChannel_IsReady(XDmaChannel * InstancePtr); +XVersion *XDmaChannel_GetVersion(XDmaChannel * InstancePtr); +int XDmaChannel_SelfTest(XDmaChannel * InstancePtr); +void XDmaChannel_Reset(XDmaChannel * InstancePtr); + +/* Control functions */ + +u32 XDmaChannel_GetControl(XDmaChannel * InstancePtr); +void XDmaChannel_SetControl(XDmaChannel * InstancePtr, u32 Control); + +/* Status functions */ + +u32 XDmaChannel_GetStatus(XDmaChannel * InstancePtr); +void XDmaChannel_SetIntrStatus(XDmaChannel * InstancePtr, u32 Status); +u32 XDmaChannel_GetIntrStatus(XDmaChannel * InstancePtr); +void XDmaChannel_SetIntrEnable(XDmaChannel * InstancePtr, u32 Enable); +u32 XDmaChannel_GetIntrEnable(XDmaChannel * InstancePtr); + +/* DMA without scatter gather functions */ + +void XDmaChannel_Transfer(XDmaChannel * InstancePtr, + u32 *SourcePtr, u32 *DestinationPtr, u32 ByteCount); + +/* Scatter gather functions */ + +int XDmaChannel_SgStart(XDmaChannel * InstancePtr); +int XDmaChannel_SgStop(XDmaChannel * InstancePtr, + XBufDescriptor ** BufDescriptorPtr); +int XDmaChannel_CreateSgList(XDmaChannel * InstancePtr, + u32 *MemoryPtr, u32 ByteCount, void *PhyPtr); +u32 XDmaChannel_IsSgListEmpty(XDmaChannel * InstancePtr); + +int XDmaChannel_PutDescriptor(XDmaChannel * InstancePtr, + XBufDescriptor * BufDescriptorPtr); +int XDmaChannel_CommitPuts(XDmaChannel * InstancePtr); +int XDmaChannel_GetDescriptor(XDmaChannel * InstancePtr, + XBufDescriptor ** BufDescriptorPtr); + +/* Packet functions for interrupt collescing */ + +u32 XDmaChannel_GetPktCount(XDmaChannel * InstancePtr); +void XDmaChannel_DecrementPktCount(XDmaChannel * InstancePtr); +int XDmaChannel_SetPktThreshold(XDmaChannel * InstancePtr, u8 Threshold); +u8 XDmaChannel_GetPktThreshold(XDmaChannel * InstancePtr); +void XDmaChannel_SetPktWaitBound(XDmaChannel * InstancePtr, u32 WaitBound); +u32 XDmaChannel_GetPktWaitBound(XDmaChannel * InstancePtr); + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdma_channel_i.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdma_channel_i.h 2014-07-20 22:06:38.849264597 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xdma_channel_i.h,v 1.1 2006/12/13 14:22:04 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2001-2004 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xdma_channel_i.h +* +* <b>Description</b> +* +* This file contains data which is shared internal data for the DMA channel +* component. It is also shared with the buffer descriptor component which is +* very tightly coupled with the DMA channel component. +* +* @note +* +* The last buffer descriptor constants must be located here to prevent a +* circular dependency between the DMA channel component and the buffer +* descriptor component. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a xd 10/27/04 Doxygenated for inclusion in API documentation +* 1.00b ecm 10/31/05 Updated for the check sum offload changes. +* </pre> +* +******************************************************************************/ + +#ifndef XDMA_CHANNEL_I_H /* prevent circular inclusions */ +#define XDMA_CHANNEL_I_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xstatus.h" +#include "xversion.h" + +/************************** Constant Definitions *****************************/ + +#define XDC_DMA_CHANNEL_V1_00_B "1.00b" + +/** @name DMA control register bit fields + * + * the following constant provides access to the bit fields of the DMA control + * register (DMACR) which must be shared between the DMA channel component + * and the buffer descriptor component + * @{ + */ +#define XDC_CONTROL_LAST_BD_MASK 0x02000000UL /**< last buffer descriptor */ +/* @} */ + +/** @name DMA status register bit fields + * + * the following constant provides access to the bit fields of the DMA status + * register (DMASR) which must be shared between the DMA channel component + * and the buffer descriptor component + * @{ + */ +#define XDC_STATUS_LAST_BD_MASK 0x10000000UL /**< last buffer descriptor */ + +#define XDC_DMASR_RX_CS_RAW_MASK 0xFFFF0000UL /**< RAW CS value for RX data */ +/* @} */ + +/** @name DMA Channel register offsets + * + * the following constants provide access to each of the registers of a DMA + * channel + * @{ + */ +#define XDC_RST_REG_OFFSET 0 /**< reset register */ +#define XDC_MI_REG_OFFSET 0 /**< module information register */ +#define XDC_DMAC_REG_OFFSET 4 /**< DMA control register */ +#define XDC_SA_REG_OFFSET 8 /**< source address register */ +#define XDC_DA_REG_OFFSET 12 /**< destination address register */ +#define XDC_LEN_REG_OFFSET 16 /**< length register */ +#define XDC_DMAS_REG_OFFSET 20 /**< DMA status register */ +#define XDC_BDA_REG_OFFSET 24 /**< buffer descriptor address register */ +#define XDC_SWCR_REG_OFFSET 28 /**< software control register */ +#define XDC_UPC_REG_OFFSET 32 /**< unserviced packet count register */ +#define XDC_PCT_REG_OFFSET 36 /**< packet count threshold register */ +#define XDC_PWB_REG_OFFSET 40 /**< packet wait bound register */ +#define XDC_IS_REG_OFFSET 44 /**< interrupt status register */ +#define XDC_IE_REG_OFFSET 48 /**< interrupt enable register */ +/* @} */ + +/** + * the following constant is written to the reset register to reset the + * DMA channel + */ +#define XDC_RESET_MASK 0x0000000AUL + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdma_channel_sg.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdma_channel_sg.c 2014-07-20 22:06:38.869264267 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/****************************************************************************** +* +* Author: Xilinx, Inc. +* +* +* 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. +* +* +* 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 THIRD PARTY 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. +* +* +* Xilinx hardware products are not intended for use in life support +* appliances, devices, or systems. Use in such applications is +* expressly prohibited. +* +* +* (c) Copyright 2002-2004 Xilinx Inc. +* All rights reserved. +* +* +* 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., +* 675 Mass Ave, Cambridge, MA 02139, USA. +* +* FILENAME: +* +* xdma_channel_sg.c +* +* DESCRIPTION: +* +* This file contains the implementation of the XDmaChannel component which is +* related to scatter gather operations. +* +* Scatter Gather Operations +* +* The DMA channel may support scatter gather operations. A scatter gather +* operation automates the DMA channel such that multiple buffers can be +* sent or received with minimal software interaction with the hardware. Buffer +* descriptors, contained in the XBufDescriptor component, are used by the +* scatter gather operations of the DMA channel to describe the buffers to be +* processed. +* +* Scatter Gather List Operations +* +* A scatter gather list may be supported by each DMA channel. The scatter +* gather list allows buffer descriptors to be put into the list by a device +* driver which requires scatter gather. The hardware processes the buffer +* descriptors which are contained in the list and modifies the buffer +* descriptors to reflect the status of the DMA operations. The device driver +* is notified by interrupt that specific DMA events occur including scatter +* gather events. The device driver removes the completed buffer descriptors +* from the scatter gather list to evaluate the status of each DMA operation. +* +* The scatter gather list is created and buffer descriptors are inserted into +* the list. Buffer descriptors are never removed from the list after it's +* creation such that a put operation copies from a temporary buffer descriptor +* to a buffer descriptor in the list. Get operations don't copy from the list +* to a temporary, but return a pointer to the buffer descriptor in the list. +* A buffer descriptor in the list may be locked to prevent it from being +* overwritten by a put operation. This allows the device driver to get a +* descriptor from a scatter gather list and prevent it from being overwritten +* until the buffer associated with the buffer descriptor has been processed. +* +* The get and put functions only operate on the list and are asynchronous from +* the hardware which may be using the list of descriptors. This is important +* because there are no checks in the get and put functions to ensure that the +* hardware has processed the descriptors. This must be handled by the driver +* using the DMA scatter gather channel through the use of the other functions. +* When a scatter gather operation is started, the start function does ensure +* that the descriptor to start has not already been processed by the hardware +* and is not the first of a series of descriptors that have not been committed +* yet. +* +* Descriptors are put into the list but not marked as ready to use by the +* hardware until a commit operation is done. This allows multiple descriptors +* which may contain a single packet of information for a protocol to be +* guaranteed not to cause any underflow conditions during transmission. The +* hardware design only allows descriptors to cause it to stop after a descriptor +* has been processed rather than before it is processed. A series of +* descriptors are put into the list followed by a commit operation, or each +* descriptor may be commited. A commit operation is performed by changing a +* single descriptor, the first of the series of puts, to indicate that the +* hardware may now use all descriptors after it. The last descriptor in the +* list is always set to cause the hardware to stop after it is processed. +* +* Typical Scatter Gather Processing +* +* The following steps illustrate the typical processing to use the +* scatter gather features of a DMA channel. +* +* 1. Create a scatter gather list for the DMA channel which puts empty buffer +* descriptors into the list. +* 2. Create buffer descriptors which describe the buffers to be filled with +* receive data or the buffers which contain data to be sent. +* 3. Put buffer descriptors into the DMA channel scatter list such that scatter +* gather operations are requested. +* 4. Commit the buffer descriptors in the list such that they are ready to be +* used by the DMA channel hardware. +* 5. Start the scatter gather operations of the DMA channel. +* 6. Process any interrupts which occur as a result of the scatter gather +* operations or poll the DMA channel to determine the status. This may +* be accomplished by getting the packet count for the channel and then +* getting the appropriate number of descriptors from the list for that +* number of packets. +* +* Minimizing Interrupts +* +* The Scatter Gather operating mode is designed to reduce the amount of CPU +* throughput necessary to manage the hardware for devices. A key to the CPU +* throughput is the number and rate of interrupts that the CPU must service. +* Devices with higher data rates can cause larger numbers of interrupts and +* higher frequency interrupts. Ideally the number of interrupts can be reduced +* by only generating an interrupt when a specific amount of data has been +* received from the interface. This design suffers from a lack of interrupts +* when the amount of data received is less than the specified amount of data +* to generate an interrupt. In order to help minimize the number of interrupts +* which the CPU must service, an algorithm referred to as "interrupt coalescing" +* is utilized. +* +* Interrupt Coalescing +* +* The principle of interrupt coalescing is to wait before generating an +* interrupt until a certain number of packets have been received or sent. An +* interrupt is also generated if a smaller number of packets have been received +* followed by a certain period of time with no packet reception. This is a +* trade-off of latency for bandwidth and is accomplished using several +* mechanisms of the hardware including a counter for packets received or +* transmitted and a packet timer. These two hardware mechanisms work in +* combination to allow a reduction in the number of interrupts processed by the +* CPU for packet reception. +* +* Unserviced Packet Count +* +* The purpose of the packet counter is to count the number of packets received +* or transmitted and provide an interrupt when a specific number of packets +* have been processed by the hardware. An interrupt is generated whenever the +* counter is greater than or equal to the Packet Count Threshold. This counter +* contains an accurate count of the number of packets that the hardware has +* processed, either received or transmitted, and the software has not serviced. +* +* The packet counter allows the number of interrupts to be reduced by waiting +* to generate an interrupt until enough packets are received. For packet +* reception, packet counts of less than the number to generate an interrupt +* would not be serviced without the addition of a packet timer. This counter is +* continuously updated by the hardware, not latched to the value at the time +* the interrupt occurred. +* +* The packet counter can be used within the interrupt service routine for the +* device to reduce the number of interrupts. The interrupt service routine +* loops while performing processing for each packet which has been received or +* transmitted and decrements the counter by a specified value. At the same time, +* the hardware is possibly continuing to receive or transmit more packets such +* that the software may choose, based upon the value in the packet counter, to +* remain in the interrupt service routine rather than exiting and immediately +* returning. This feature should be used with caution as reducing the number of +* interrupts is beneficial, but unbounded interrupt processing is not desirable. +* +* Since the hardware may be incrementing the packet counter simultaneously +* with the software decrementing the counter, there is a need for atomic +* operations. The hardware ensures that the operation is atomic such that +* simultaneous accesses are properly handled. +* +* Packet Wait Bound +* +* The purpose of the packet wait bound is to augment the unserviced packet +* count. Whenever there is no pending interrupt for the channel and the +* unserviced packet count is non-zero, a timer starts counting timeout at the +* value contained the the packet wait bound register. If the timeout is +* reached, an interrupt is generated such that the software may service the +* data which was buffered. +* +* NOTES: +* +* Special Test Conditions: +* +* The scatter gather list processing must be thoroughly tested if changes are +* made. Testing should include putting and committing single descriptors and +* putting multiple descriptors followed by a single commit. There are some +* conditions in the code which handle the exception conditions. +* +* The Put Pointer points to the next location in the descriptor list to copy +* in a new descriptor. The Get Pointer points to the next location in the +* list to get a descriptor from. The Get Pointer only allows software to +* have a traverse the list after the hardware has finished processing some +* number of descriptors. The Commit Pointer points to the descriptor in the +* list which is to be committed. It is also used to determine that no +* descriptor is waiting to be commited (NULL). The Last Pointer points to +* the last descriptor that was put into the list. It typically points +* to the previous descriptor to the one pointed to by the Put Pointer. +* Comparisons are done between these pointers to determine when the following +* special conditions exist. + +* Single Put And Commit +* +* The buffer descriptor is ready to be used by the hardware so it is important +* for the descriptor to not appear to be waiting to be committed. The commit +* pointer is reset when a commit is done indicating there are no descriptors +* waiting to be committed. In all cases but this one, the descriptor is +* changed to cause the hardware to go to the next descriptor after processing +* this one. But in this case, this is the last descriptor in the list such +* that it must not be changed. +* +* 3 Or More Puts And Commit +* +* A series of 3 or more puts followed by a single commit is different in that +* only the 1st descriptor put into the list is changed when the commit is done. +* This requires each put starting on the 3rd to change the previous descriptor +* so that it allows the hardware to continue to the next descriptor in the list. +* +* The 1st Put Following A Commit +* +* The commit caused the commit pointer to be NULL indicating that there are no +* descriptors waiting to be committed. It is necessary for the next put to set +* the commit pointer so that a commit must follow the put for the hardware to +* use the descriptor. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------ +* 1.00a rpm 02/03/03 Removed the XST_DMA_SG_COUNT_EXCEEDED return code +* from SetPktThreshold. +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xdma_channel.h" +#include "xbasic_types.h" +#include "xio.h" +#include "xbuf_descriptor.h" +#include "xstatus.h" + +/* simple virt<-->phy pointer conversions for a single dma channel */ +#define P_TO_V(p) \ + ((p) ? \ + (InstancePtr->VirtPtr + ((u32)(p) - (u32)InstancePtr->PhyPtr)) : \ + 0) + +#define V_TO_P(v) \ + ((v) ? \ + (InstancePtr->PhyPtr + ((u32)(v) - (u32)InstancePtr->VirtPtr)) : \ + 0) + +/************************** Constant Definitions *****************************/ + +#define XDC_SWCR_SG_ENABLE_MASK 0x80000000UL /* scatter gather enable */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/* the following macro copies selected fields of a buffer descriptor to another + * buffer descriptor, this was provided by the buffer descriptor component but + * was moved here since it is only used internally to this component and since + * it does not copy all fields + */ +#define CopyBufferDescriptor(InstancePtr, DestinationPtr) \ +{ \ + *((u32 *)DestinationPtr + XBD_CONTROL_OFFSET) = \ + *((u32 *)InstancePtr + XBD_CONTROL_OFFSET); \ + *((u32 *)DestinationPtr + XBD_SOURCE_OFFSET) = \ + *((u32 *)InstancePtr + XBD_SOURCE_OFFSET); \ + *((u32 *)DestinationPtr + XBD_DESTINATION_OFFSET) = \ + *((u32 *)InstancePtr + XBD_DESTINATION_OFFSET); \ + *((u32 *)DestinationPtr + XBD_LENGTH_OFFSET) = \ + *((u32 *)InstancePtr + XBD_LENGTH_OFFSET); \ + *((u32 *)DestinationPtr + XBD_STATUS_OFFSET) = \ + *((u32 *)InstancePtr + XBD_STATUS_OFFSET); \ + *((u32 *)DestinationPtr + XBD_DEVICE_STATUS_OFFSET) = \ + *((u32 *)InstancePtr + XBD_DEVICE_STATUS_OFFSET); \ + *((u32 *)DestinationPtr + XBD_ID_OFFSET) = \ + *((u32 *)InstancePtr + XBD_ID_OFFSET); \ + *((u32 *)DestinationPtr + XBD_FLAGS_OFFSET) = \ + *((u32 *)InstancePtr + XBD_FLAGS_OFFSET); \ + *((u32 *)DestinationPtr + XBD_RQSTED_LENGTH_OFFSET) = \ + *((u32 *)InstancePtr + XBD_RQSTED_LENGTH_OFFSET); \ +} + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_SgStart +* +* DESCRIPTION: +* +* This function starts a scatter gather operation for a scatter gather +* DMA channel. The first buffer descriptor in the buffer descriptor list +* will be started with the scatter gather operation. A scatter gather list +* should have previously been created for the DMA channel and buffer +* descriptors put into the scatter gather list such that there are scatter +* operations ready to be performed. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* RETURN VALUE: +* +* A status containing XST_SUCCESS if scatter gather was started successfully +* for the DMA channel. +* +* A value of XST_DMA_SG_NO_LIST indicates the scatter gather list has not +* been created. +* +* A value of XST_DMA_SG_LIST_EMPTY indicates scatter gather was not started +* because the scatter gather list of the DMA channel does not contain any +* buffer descriptors that are ready to be processed by the hardware. +* +* A value of XST_DMA_SG_IS_STARTED indicates scatter gather was not started +* because the scatter gather was not stopped, but was already started. +* +* A value of XST_DMA_SG_BD_NOT_COMMITTED indicates the buffer descriptor of +* scatter gather list which was to be started is not committed to the list. +* This status is more likely if this function is being called from an ISR +* and non-ISR processing is putting descriptors into the list. +* +* A value of XST_DMA_SG_NO_DATA indicates that the buffer descriptor of the +* scatter gather list which was to be started had already been used by the +* hardware for a DMA transfer that has been completed. +* +* NOTES: +* +* It is the responsibility of the caller to get all the buffer descriptors +* after performing a stop operation and before performing a start operation. +* If buffer descriptors are not retrieved between stop and start operations, +* buffer descriptors may be processed by the hardware more than once. +* +******************************************************************************/ +int XDmaChannel_SgStart(XDmaChannel * InstancePtr) +{ + u32 Register; + XBufDescriptor *LastDescriptorPtr; + + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* if a scatter gather list has not been created yet, return a status */ + + if (InstancePtr->TotalDescriptorCount == 0) { + return XST_DMA_SG_NO_LIST; + } + + /* if the scatter gather list exists but is empty then return a status */ + + if (XDmaChannel_IsSgListEmpty(InstancePtr)) { + return XST_DMA_SG_LIST_EMPTY; + } + + /* if scatter gather is busy for the DMA channel, return a status because + * restarting it could lose data + */ + + Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_DMAS_REG_OFFSET); + if (Register & XDC_DMASR_SG_BUSY_MASK) { + return XST_DMA_SG_IS_STARTED; + } + + /* get the address of the last buffer descriptor which the DMA hardware + * finished processing + */ + LastDescriptorPtr = (XBufDescriptor *) + P_TO_V(XIo_In32 + (InstancePtr->RegBaseAddress + XDC_BDA_REG_OFFSET)); + + /* setup the first buffer descriptor that will be sent when the scatter + * gather channel is enabled, this is only necessary one time since + * the BDA register of the channel maintains the last buffer descriptor + * processed + */ + if (LastDescriptorPtr == NULL) { + XIo_Out32(InstancePtr->RegBaseAddress + XDC_BDA_REG_OFFSET, + (u32) V_TO_P(InstancePtr->GetPtr)); + } + else { + XBufDescriptor *NextDescriptorPtr; + + /* get the next descriptor to be started, if the status indicates it + * hasn't already been used by the h/w, then it's OK to start it, + * s/w sets the status of each descriptor to busy and then h/w clears + * the busy when it is complete + */ + NextDescriptorPtr = + P_TO_V(XBufDescriptor_GetNextPtr(LastDescriptorPtr)); + + if ((XBufDescriptor_GetStatus(NextDescriptorPtr) & + XDC_DMASR_BUSY_MASK) == 0) { + return XST_DMA_SG_NO_DATA; + } + /* don't start the DMA SG channel if the descriptor to be processed + * by h/w is to be committed by the s/w, this function can be called + * such that it interrupts a thread that was putting into the list + */ + if (NextDescriptorPtr == InstancePtr->CommitPtr) { + return XST_DMA_SG_BD_NOT_COMMITTED; + } + } + + /* start the scatter gather operation by clearing the stop bit in the + * control register and setting the enable bit in the s/w control register, + * both of these are necessary to cause it to start, right now the order of + * these statements is important, the software control register should be + * set 1st. The other order can cause the CPU to have a loss of sync + * because it cannot read/write the register while the DMA operation is + * running + */ + + Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_SWCR_REG_OFFSET); + + XIo_Out32(InstancePtr->RegBaseAddress + XDC_SWCR_REG_OFFSET, + Register | XDC_SWCR_SG_ENABLE_MASK); + + Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_DMAC_REG_OFFSET); + + XIo_Out32(InstancePtr->RegBaseAddress + XDC_DMAC_REG_OFFSET, + Register & ~XDC_DMACR_SG_DISABLE_MASK); + + /* indicate the DMA channel scatter gather operation was started + * successfully + */ + return XST_SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_SgStop +* +* DESCRIPTION: +* +* This function stops a scatter gather operation for a scatter gather +* DMA channel. This function starts the process of stopping a scatter +* gather operation that is in progress and waits for the stop to be completed. +* Since it waits for the operation to stopped before returning, this function +* could take an amount of time relative to the size of the DMA scatter gather +* operation which is in progress. The scatter gather list of the DMA channel +* is not modified by this function such that starting the scatter gather +* channel after stopping it will cause it to resume. This operation is +* considered to be a graceful stop in that the scatter gather operation +* completes the current buffer descriptor before stopping. +* +* If the interrupt is enabled, an interrupt will be generated when the +* operation is stopped and the caller is responsible for handling the +* interrupt. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* BufDescriptorPtr is also a return value which contains a pointer to the +* buffer descriptor which the scatter gather operation completed when it +* was stopped. +* +* RETURN VALUE: +* +* A status containing XST_SUCCESS if scatter gather was stopped successfully +* for the DMA channel. +* +* A value of XST_DMA_SG_IS_STOPPED indicates scatter gather was not stoppped +* because the scatter gather is not started, but was already stopped. +* +* BufDescriptorPtr contains a pointer to the buffer descriptor which was +* completed when the operation was stopped. +* +* NOTES: +* +* This function implements a loop which polls the hardware for an infinite +* amount of time. If the hardware is not operating correctly, this function +* may never return. +* +******************************************************************************/ +int +XDmaChannel_SgStop(XDmaChannel * InstancePtr, + XBufDescriptor ** BufDescriptorPtr) +{ + u32 Register; + + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(BufDescriptorPtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* get the contents of the software control register, if scatter gather is not + * enabled (started), then return a status because the disable acknowledge + * would not be generated + */ + Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_SWCR_REG_OFFSET); + + if ((Register & XDC_SWCR_SG_ENABLE_MASK) == 0) { + return XST_DMA_SG_IS_STOPPED; + } + + /* disable scatter gather by writing to the software control register + * without modifying any other bits of the register + */ + XIo_Out32(InstancePtr->RegBaseAddress + XDC_SWCR_REG_OFFSET, + Register & ~XDC_SWCR_SG_ENABLE_MASK); + + /* scatter gather does not disable immediately, but after the current + * buffer descriptor is complete, so wait for the DMA channel to indicate + * the disable is complete + */ + do { + Register = + XIo_In32(InstancePtr->RegBaseAddress + + XDC_DMAS_REG_OFFSET); + } + while (Register & XDC_DMASR_SG_BUSY_MASK); + + /* set the specified buffer descriptor pointer to point to the buffer + * descriptor that the scatter gather DMA channel was processing + */ + *BufDescriptorPtr = (XBufDescriptor *) + P_TO_V(XIo_In32 + (InstancePtr->RegBaseAddress + XDC_BDA_REG_OFFSET)); + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_CreateSgList +* +* DESCRIPTION: +* +* This function creates a scatter gather list in the DMA channel. A scatter +* gather list consists of a list of buffer descriptors that are available to +* be used for scatter gather operations. Buffer descriptors are put into the +* list to request a scatter gather operation to be performed. +* +* A number of buffer descriptors are created from the specified memory and put +* into a buffer descriptor list as empty buffer descriptors. This function must +* be called before non-empty buffer descriptors may be put into the DMA channel +* to request scatter gather operations. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* MemoryPtr contains a pointer to the memory which is to be used for buffer +* descriptors and must not be cached (virtual). +* +* ByteCount contains the number of bytes for the specified memory to be used +* for buffer descriptors. +* +* PhyPtr contains a pointer to the physical memory use for buffer descriptors. +* +* RETURN VALUE: +* +* A status contains XST_SUCCESS if the scatter gather list was successfully +* created. +* +* A value of XST_DMA_SG_LIST_EXISTS indicates that the scatter gather list +* was not created because the list has already been created. +* +* NOTES: +* +* None. +* +******************************************************************************/ +int +XDmaChannel_CreateSgList(XDmaChannel * InstancePtr, + u32 *MemoryPtr, u32 ByteCount, void *PhyPtr) +{ + XBufDescriptor *BufferDescriptorPtr = (XBufDescriptor *) MemoryPtr; + XBufDescriptor *PreviousDescriptorPtr = NULL; + XBufDescriptor *StartOfListPtr = BufferDescriptorPtr; + u32 UsedByteCount; + + /* assert to verify valid input arguments, alignment for those + * arguments that have alignment restrictions, and at least enough + * memory for one buffer descriptor + */ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(MemoryPtr != NULL); + XASSERT_NONVOID(((u32) MemoryPtr & 3) == 0); + XASSERT_NONVOID(ByteCount != 0); + XASSERT_NONVOID(ByteCount >= sizeof(XBufDescriptor)); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* if the scatter gather list has already been created, then return + * with a status + */ + if (InstancePtr->TotalDescriptorCount != 0) { + return XST_DMA_SG_LIST_EXISTS; + } + + /* save this up front so V_TO_P() works correctly */ + InstancePtr->VirtPtr = MemoryPtr; + InstancePtr->PhyPtr = PhyPtr; + + /* loop thru the specified memory block and create as many buffer + * descriptors as possible putting each into the list which is + * implemented as a ring buffer, make sure not to use any memory which + * is not large enough for a complete buffer descriptor + */ + UsedByteCount = 0; + while ((UsedByteCount + sizeof(XBufDescriptor)) <= ByteCount) { + /* setup a pointer to the next buffer descriptor in the memory and + * update # of used bytes to know when all of memory is used + */ + BufferDescriptorPtr = (XBufDescriptor *) ((u32) MemoryPtr + + UsedByteCount); + + /* initialize the new buffer descriptor such that it doesn't contain + * garbage which could be used by the DMA hardware + */ + XBufDescriptor_Initialize(BufferDescriptorPtr); + + /* if this is not the first buffer descriptor to be created, + * then link it to the last created buffer descriptor + */ + if (PreviousDescriptorPtr != NULL) { + XBufDescriptor_SetNextPtr(PreviousDescriptorPtr, + V_TO_P(BufferDescriptorPtr)); + } + + /* always keep a pointer to the last created buffer descriptor such + * that they can be linked together in the ring buffer + */ + PreviousDescriptorPtr = BufferDescriptorPtr; + + /* keep a count of the number of descriptors in the list to allow + * error processing to be performed + */ + InstancePtr->TotalDescriptorCount++; + + UsedByteCount += sizeof(XBufDescriptor); + } + + /* connect the last buffer descriptor created and inserted in the list + * to the first such that a ring buffer is created + */ + XBufDescriptor_SetNextPtr(BufferDescriptorPtr, V_TO_P(StartOfListPtr)); + + /* initialize the ring buffer to indicate that there are no + * buffer descriptors in the list which point to valid data buffers + */ + InstancePtr->PutPtr = BufferDescriptorPtr; + InstancePtr->GetPtr = BufferDescriptorPtr; + InstancePtr->CommitPtr = NULL; + InstancePtr->LastPtr = BufferDescriptorPtr; + InstancePtr->ActiveDescriptorCount = 0; + InstancePtr->ActivePacketCount = 0; + InstancePtr->Committed = FALSE; + + /* indicate the scatter gather list was successfully created */ + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_IsSgListEmpty +* +* DESCRIPTION: +* +* This function determines if the scatter gather list of a DMA channel is +* empty with regard to buffer descriptors which are pointing to buffers to be +* used for scatter gather operations. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* RETURN VALUE: +* +* A value of TRUE if the scatter gather list is empty, otherwise a value of +* FALSE. +* +* NOTES: +* +* None. +* +******************************************************************************/ +u32 XDmaChannel_IsSgListEmpty(XDmaChannel * InstancePtr) +{ + /* assert to verify valid input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* if the number of descriptors which are being used in the list is zero + * then the list is empty + */ + return (InstancePtr->ActiveDescriptorCount == 0); +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_PutDescriptor +* +* DESCRIPTION: +* +* This function puts a buffer descriptor into the DMA channel scatter +* gather list. A DMA channel maintains a list of buffer descriptors which are +* to be processed. This function puts the specified buffer descriptor +* at the next location in the list. Note that since the list is already intact, +* the information in the parameter is copied into the list (rather than modify +* list pointers on the fly). +* +* After buffer descriptors are put into the list, they must also be committed +* by calling another function. This allows multiple buffer descriptors which +* span a single packet to be put into the list while preventing the hardware +* from starting the first buffer descriptor of the packet. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* BufferDescriptorPtr is a pointer to the buffer descriptor to be put into +* the next available location of the scatter gather list. +* +* RETURN VALUE: +* +* A status which indicates XST_SUCCESS if the buffer descriptor was +* successfully put into the scatter gather list. +* +* A value of XST_DMA_SG_NO_LIST indicates the scatter gather list has not +* been created. +* +* A value of XST_DMA_SG_LIST_FULL indicates the buffer descriptor was not +* put into the list because the list was full. +* +* A value of XST_DMA_SG_BD_LOCKED indicates the buffer descriptor was not +* put into the list because the buffer descriptor in the list which is to +* be overwritten was locked. A locked buffer descriptor indicates the higher +* layered software is still using the buffer descriptor. +* +* NOTES: +* +* It is necessary to create a scatter gather list for a DMA channel before +* putting buffer descriptors into it. +* +******************************************************************************/ +int +XDmaChannel_PutDescriptor(XDmaChannel * InstancePtr, + XBufDescriptor * BufferDescriptorPtr) +{ + u32 Control; + + /* assert to verify valid input arguments and alignment for those + * arguments that have alignment restrictions + */ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(BufferDescriptorPtr != NULL); + XASSERT_NONVOID(((u32) BufferDescriptorPtr & 3) == 0); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* if a scatter gather list has not been created yet, return a status */ + + if (InstancePtr->TotalDescriptorCount == 0) { + return XST_DMA_SG_NO_LIST; + } + + /* if the list is full because all descriptors are pointing to valid + * buffers, then indicate an error, this code assumes no list or an + * empty list is detected above + */ + if (InstancePtr->ActiveDescriptorCount == + InstancePtr->TotalDescriptorCount) { + return XST_DMA_SG_LIST_FULL; + } + + /* if the buffer descriptor in the list which is to be overwritten is + * locked, then don't overwrite it and return a status + */ + if (XBufDescriptor_IsLocked(InstancePtr->PutPtr)) { + return XST_DMA_SG_BD_LOCKED; + } + + /* set the scatter gather stop bit in the control word of the descriptor + * to cause the h/w to stop after it processes this descriptor since it + * will be the last in the list + */ + Control = XBufDescriptor_GetControl(BufferDescriptorPtr); + XBufDescriptor_SetControl(BufferDescriptorPtr, + Control | XDC_DMACR_SG_DISABLE_MASK); + + /* set both statuses in the descriptor so we tell if they are updated with + * the status of the transfer, the hardware should change the busy in the + * DMA status to be false when it completes + */ + XBufDescriptor_SetStatus(BufferDescriptorPtr, XDC_DMASR_BUSY_MASK); + XBufDescriptor_SetDeviceStatus(BufferDescriptorPtr, 0); + + /* copy the descriptor into the next position in the list so it's ready to + * be used by the h/w, this assumes the descriptor in the list prior to this + * one still has the stop bit in the control word set such that the h/w + * use this one yet + */ + CopyBufferDescriptor(BufferDescriptorPtr, InstancePtr->PutPtr); + + /* End of a packet is reached. Bump the packet counter */ + if (XBufDescriptor_IsLastControl(InstancePtr->PutPtr)) { + InstancePtr->ActivePacketCount++; + } + + /* only the last in the list and the one to be committed have scatter gather + * disabled in the control word, a commit requires only one descriptor + * to be changed, when # of descriptors to commit > 2 all others except the + * 1st and last have scatter gather enabled + */ + if ((InstancePtr->CommitPtr != InstancePtr->LastPtr) && + (InstancePtr->CommitPtr != NULL)) { + Control = XBufDescriptor_GetControl(InstancePtr->LastPtr); + XBufDescriptor_SetControl(InstancePtr->LastPtr, + Control & ~XDC_DMACR_SG_DISABLE_MASK); + } + + /* update the list data based upon putting a descriptor into the list, + * these operations must be last + */ + InstancePtr->ActiveDescriptorCount++; + + /* only update the commit pointer if it is not already active, this allows + * it to be deactivated after every commit such that a single descriptor + * which is committed does not appear to be waiting to be committed + */ + if (InstancePtr->CommitPtr == NULL) { + InstancePtr->CommitPtr = InstancePtr->LastPtr; + } + + /* these updates MUST BE LAST after the commit pointer update in order for + * the commit pointer to track the correct descriptor to be committed + */ + InstancePtr->LastPtr = InstancePtr->PutPtr; + InstancePtr->PutPtr = + P_TO_V(XBufDescriptor_GetNextPtr(InstancePtr->PutPtr)); + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_CommitPuts +* +* DESCRIPTION: +* +* This function commits the buffer descriptors which have been put into the +* scatter list for the DMA channel since the last commit operation was +* performed. This enables the calling functions to put several buffer +* descriptors into the list (e.g.,a packet's worth) before allowing the scatter +* gather operations to start. This prevents the DMA channel hardware from +* starting to use the buffer descriptors in the list before they are ready +* to be used (multiple buffer descriptors for a single packet). +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* RETURN VALUE: +* +* A status indicating XST_SUCCESS if the buffer descriptors of the list were +* successfully committed. +* +* A value of XST_DMA_SG_NOTHING_TO_COMMIT indicates that the buffer descriptors +* were not committed because there was nothing to commit in the list. All the +* buffer descriptors which are in the list are commited. +* +* NOTES: +* +* None. +* +******************************************************************************/ +int XDmaChannel_CommitPuts(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* if the buffer descriptor to be committed is already committed or + * the list is empty (none have been put in), then indicate an error + */ + if ((InstancePtr->CommitPtr == NULL) || + XDmaChannel_IsSgListEmpty(InstancePtr)) { + return XST_DMA_SG_NOTHING_TO_COMMIT; + } + + /* last descriptor in the list must have scatter gather disabled so the end + * of the list is hit by h/w, if descriptor to commit is not last in list, + * commit descriptors by enabling scatter gather in the descriptor + */ + if (InstancePtr->CommitPtr != InstancePtr->LastPtr) { + u32 Control; + + Control = XBufDescriptor_GetControl(InstancePtr->CommitPtr); + XBufDescriptor_SetControl(InstancePtr->CommitPtr, Control & + ~XDC_DMACR_SG_DISABLE_MASK); + } + + /* Buffer Descriptors are committed. DMA is ready to be enabled */ + InstancePtr->Committed = TRUE; + + /* Update the commit pointer to indicate that there is nothing to be + * committed, this state is used by start processing to know that the + * buffer descriptor to start is not waiting to be committed + */ + InstancePtr->CommitPtr = NULL; + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_GetDescriptor +* +* DESCRIPTION: +* +* This function gets a buffer descriptor from the scatter gather list of the +* DMA channel. The buffer descriptor is retrieved from the scatter gather list +* and the scatter gather list is updated to not include the retrieved buffer +* descriptor. This is typically done after a scatter gather operation +* completes indicating that a data buffer has been successfully sent or data +* has been received into the data buffer. The purpose of this function is to +* allow the device using the scatter gather operation to get the results of the +* operation. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* BufDescriptorPtr is a pointer to a pointer to the buffer descriptor which +* was retrieved from the list. The buffer descriptor is not really removed +* from the list, but it is changed to a state such that the hardware will not +* use it again until it is put into the scatter gather list of the DMA channel. +* +* RETURN VALUE: +* +* A status indicating XST_SUCCESS if a buffer descriptor was retrieved from +* the scatter gather list of the DMA channel. +* +* A value of XST_DMA_SG_NO_LIST indicates the scatter gather list has not +* been created. +* +* A value of XST_DMA_SG_LIST_EMPTY indicates no buffer descriptor was +* retrieved from the list because there are no buffer descriptors to be +* processed in the list. +* +* BufDescriptorPtr is updated to point to the buffer descriptor which was +* retrieved from the list if the status indicates success. +* +* NOTES: +* +* None. +* +******************************************************************************/ +int +XDmaChannel_GetDescriptor(XDmaChannel * InstancePtr, + XBufDescriptor ** BufDescriptorPtr) +{ + u32 Control; + + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(BufDescriptorPtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* if a scatter gather list has not been created yet, return a status */ + + if (InstancePtr->TotalDescriptorCount == 0) { + return XST_DMA_SG_NO_LIST; + } + + /* if the buffer descriptor list is empty, then indicate an error */ + + if (XDmaChannel_IsSgListEmpty(InstancePtr)) { + return XST_DMA_SG_LIST_EMPTY; + } + + /* retrieve the next buffer descriptor which is ready to be processed from + * the buffer descriptor list for the DMA channel, set the control word + * such that hardware will stop after the descriptor has been processed + */ + Control = XBufDescriptor_GetControl(InstancePtr->GetPtr); + XBufDescriptor_SetControl(InstancePtr->GetPtr, + Control | XDC_DMACR_SG_DISABLE_MASK); + + /* set the input argument, which is also an output, to point to the + * buffer descriptor which is to be retrieved from the list + */ + *BufDescriptorPtr = InstancePtr->GetPtr; + + /* update the pointer of the DMA channel to reflect the buffer descriptor + * was retrieved from the list by setting it to the next buffer descriptor + * in the list and indicate one less descriptor in the list now + */ + InstancePtr->GetPtr = + P_TO_V(XBufDescriptor_GetNextPtr(InstancePtr->GetPtr)); + InstancePtr->ActiveDescriptorCount--; + + return XST_SUCCESS; +} + +/*********************** Interrupt Collescing Functions **********************/ + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_GetPktCount +* +* DESCRIPTION: +* +* This function returns the value of the unserviced packet count register of +* the DMA channel. This count represents the number of packets that have been +* sent or received by the hardware, but not processed by software. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* RETURN VALUE: +* +* The unserviced packet counter register contents for the DMA channel. +* +* NOTES: +* +* None. +* +******************************************************************************/ +u32 XDmaChannel_GetPktCount(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* get the unserviced packet count from the register and return it */ + + return XIo_In32(InstancePtr->RegBaseAddress + XDC_UPC_REG_OFFSET); +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_DecrementPktCount +* +* DESCRIPTION: +* +* This function decrements the value of the unserviced packet count register. +* This informs the hardware that the software has processed a packet. The +* unserviced packet count register may only be decremented by one in the +* hardware. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* RETURN VALUE: +* +* None. +* +* NOTES: +* +* None. +* +******************************************************************************/ +void XDmaChannel_DecrementPktCount(XDmaChannel * InstancePtr) +{ + u32 Register; + + /* assert to verify input arguments */ + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* if the unserviced packet count register can be decremented (rather + * than rolling over) decrement it by writing a 1 to the register, + * this is the only valid write to the register as it serves as an + * acknowledge that a packet was handled by the software + */ + Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_UPC_REG_OFFSET); + if (Register > 0) { + XIo_Out32(InstancePtr->RegBaseAddress + XDC_UPC_REG_OFFSET, + 1UL); + } +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_SetPktThreshold +* +* DESCRIPTION: +* +* This function sets the value of the packet count threshold register of the +* DMA channel. It reflects the number of packets that must be sent or +* received before generating an interrupt. This value helps implement +* a concept called "interrupt coalescing", which is used to reduce the number +* of interrupts from devices with high data rates. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* Threshold is the value that is written to the threshold register of the +* DMA channel. +* +* RETURN VALUE: +* +* A status containing XST_SUCCESS if the packet count threshold was +* successfully set. +* +* NOTES: +* +* The packet threshold could be set to larger than the number of descriptors +* allocated to the DMA channel. In this case, the wait bound will take over +* and always indicate data arrival. There was a check in this function that +* returned an error if the treshold was larger than the number of descriptors, +* but that was removed because users would then have to set the threshold +* only after they set descriptor space, which is an order dependency that +* caused confustion. +* +******************************************************************************/ +int XDmaChannel_SetPktThreshold(XDmaChannel * InstancePtr, u8 Threshold) +{ + /* assert to verify input arguments, don't assert the threshold since + * it's range is unknown + */ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* set the packet count threshold in the register such that an interrupt + * may be generated, if enabled, when the packet count threshold is + * reached or exceeded + */ + XIo_Out32(InstancePtr->RegBaseAddress + XDC_PCT_REG_OFFSET, + (u32) Threshold); + + /* indicate the packet count threshold was successfully set */ + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_GetPktThreshold +* +* DESCRIPTION: +* +* This function gets the value of the packet count threshold register of the +* DMA channel. This value reflects the number of packets that must be sent or +* received before generating an interrupt. This value helps implement a concept +* called "interrupt coalescing", which is used to reduce the number of +* interrupts from devices with high data rates. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* RETURN VALUE: +* +* The packet threshold register contents for the DMA channel and is a value in +* the range 0 - 1023. A value of 0 indicates the packet wait bound timer is +* disabled. +* +* NOTES: +* +* None. +* +******************************************************************************/ +u8 XDmaChannel_GetPktThreshold(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* get the packet count threshold from the register and return it, + * since only 8 bits are used, cast it to return only those bits */ + + return (u8) XIo_In32(InstancePtr->RegBaseAddress + XDC_PCT_REG_OFFSET); +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_SetPktWaitBound +* +* DESCRIPTION: +* +* This function sets the value of the packet wait bound register of the +* DMA channel. This value reflects the timer value used to trigger an +* interrupt when not enough packets have been received to reach the packet +* count threshold. +* +* The timer is in millisecond units with +/- 33% accuracy. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* WaitBound is the value, in milliseconds, to be stored in the wait bound +* register of the DMA channel and is a value in the range 0 - 1023. A value +* of 0 disables the packet wait bound timer. +* +* RETURN VALUE: +* +* None. +* +* NOTES: +* +* None. +* +******************************************************************************/ +void XDmaChannel_SetPktWaitBound(XDmaChannel * InstancePtr, u32 WaitBound) +{ + /* assert to verify input arguments */ + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(WaitBound < 1024); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* set the packet wait bound in the register such that interrupt may be + * generated, if enabled, when packets have not been handled for a specific + * amount of time + */ + XIo_Out32(InstancePtr->RegBaseAddress + XDC_PWB_REG_OFFSET, WaitBound); +} + +/****************************************************************************** +* +* FUNCTION: +* +* XDmaChannel_GetPktWaitBound +* +* DESCRIPTION: +* +* This function gets the value of the packet wait bound register of the +* DMA channel. This value contains the timer value used to trigger an +* interrupt when not enough packets have been received to reach the packet +* count threshold. +* +* The timer is in millisecond units with +/- 33% accuracy. +* +* ARGUMENTS: +* +* InstancePtr contains a pointer to the DMA channel to operate on. The DMA +* channel should be configured to use scatter gather in order for this function +* to be called. +* +* RETURN VALUE: +* +* The packet wait bound register contents for the DMA channel. +* +* NOTES: +* +* None. +* +******************************************************************************/ +u32 XDmaChannel_GetPktWaitBound(XDmaChannel * InstancePtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* get the packet wait bound from the register and return it */ + + return XIo_In32(InstancePtr->RegBaseAddress + XDC_PWB_REG_OFFSET); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3.c 2014-07-20 22:06:38.877264135 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2006 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xdmav3.c +* +* This file implements initialization and control related functions. For more +* information on this driver, see xdmav3.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 3.00a rmm 03/11/05 First release +* </pre> +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include <linux/string.h> +#include <asm/delay.h> + +#include "xdmav3.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* This function initializes a DMA channel. This function must be called +* prior to using a DMA channel. Initialization of a channel includes setting +* up the register base address, setting up the instance data, and ensuring the +* HW is in a quiescent state. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param BaseAddress is where the registers for this channel can be found. +* If address translation is being used, then this parameter must +* reflect the virtual base address. +* +* @return +* - XST_SUCCESS if initialization was successful +* +******************************************************************************/ +int XDmaV3_Initialize(XDmaV3 * InstancePtr, u32 BaseAddress) +{ + u32 Dmasr; + + /* Setup the instance */ + memset(InstancePtr, 0, sizeof(XDmaV3)); + InstancePtr->RegBase = BaseAddress; + InstancePtr->IsReady = XCOMPONENT_IS_READY; + InstancePtr->BdRing.RunState = XST_DMA_SG_IS_STOPPED; + + /* If this is SGDMA channel, then make sure it is stopped */ + Dmasr = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); + if (Dmasr & (XDMAV3_DMASR_DMACNFG_SGDMARX_MASK | + XDMAV3_DMASR_DMACNFG_SGDMATX_MASK | + XDMAV3_DMASR_DMACNFG_SSGDMA_MASK)) { + XDmaV3_SgStop(InstancePtr); + } + + return (XST_SUCCESS); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3.h 2014-07-20 22:06:38.889263937 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2006 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xdmav3.h +* +* The Xilinx Simple and Scatter Gather DMA driver. This component supports a +* distributed DMA design in which each device can have it's own dedicated DMA +* channel, as opposed to a centralized DMA design. A device which uses DMA +* typically contains two DMA channels, one for sending data and the other for +* receiving data. +* +* This component is designed to be used as a basic building block for +* designing a device driver. It provides registers accesses such that all +* DMA processing can be maintained easier, but the device driver designer +* must still understand all the details of the DMA channel. +* +* For a full description of DMA features, please see the HW spec. This driver +* supports the following features: +* - Simple DMA +* - Scatter-Gather DMA (SGDMA) +* - Interrupts +* - Programmable interrupt coalescing for SGDMA +* - 36 Bit bus addressing +* - Programmable transaction types +* - APIs to manage Buffer Descriptors (BD) movement to and from the SGDMA +* engine +* - Virtual memory support +* +* <b>Transactions</b> +* +* To describe a DMA transaction in its simplest form, you need a source address, +* destination address, and the number of bytes to transfer. When using a DMA +* receive channel, the source address is within some piece of IP HW and doesn't +* require the user explicitly set it. Likewise with a transmit channel and the +* destination address. So this leaves a user buffer address and the number +* bytes to transfer as the primary transaction attributes. There are more +* obscure attributes such as: +* +* - Is the user buffer a fixed address FIFO or a range of memory +* - The size of the data bus over which the transaction occurs. +* - Does the transfer use single beat or bursting capabilities of the +* bus over which the transaction occurs. +* - If the transaction occurs on a bus wider than 32 bits, what are the +* highest order address bits. +* - If SGDMA, does this transaction represent the end of a packet. +* +* The object used to describe a transaction is referred to as a Buffer +* Descriptor (BD). The format of a BD closely matches that of the DMA HW. +* Many fields within the BD correspond directly with the same fields within the +* HW registers. See xdmabdv3.h for a detailed description of and the API for +* manipulation of these objects. +* +* <b>Simple DMA</b> +* +* Simple DMA is a single transaction type of operation. The user uses this +* driver to setup a transaction, initiate the transaction, then either wait for +* an interrupt or poll the HW for completion of the transaction. A new +* transaction may not be initiated until the current one completes. +* +* <b>Scatter-Gather DMA</b> +* +* SGDMA is more sophisticated in that it allows the user to define a list of +* transactions in memory which the HW will process without further user +* intervention. During this time, the user is free to continue adding more work +* to keep the HW busy. +* +* Notification of completed transactions can be done either by polling the HW, +* or using interrupts that signal a transaction has completed or a series of +* transactions have been processed. +* +* SGDMA processes in units of packets. A packet is defined as a series of +* data bytes that represent a message. SGDMA allows a packet of data to be +* broken up into one or more transactions. For example, take an Ethernet IP +* packet which consists of a 14 byte header followed by a 1 or more byte +* payload. With SGDMA, the user may point a BD to the header and another BD to +* the payload, then transfer them as a single message. This strategy can make a +* TCP/IP stack more efficient by allowing it to keep packet headers and data in +* different memory regions instead of assembling packets into contiguous blocks +* of memory. +* +* <b>Interrupt Coalescing</b> +* +* SGDMA provides control over the frequency of interrupts. On a high speed link +* significant processor overhead may be used servicing interrupts. Interrupt +* coalescing provides two mechanisms that help control interrupt frequency. +* +* The packet threshold will hold off interrupting the CPU until a programmable +* number of packets have been processed by the engine. The packet waitbound +* timer is used to interrupt the CPU if after a programmable amount of time +* after processing the last packet, no new packets were processed. +* +* <b>Interrupts</b> +* +* This driver does not service interrupts. This is done typically within +* a higher level driver that uses DMA. This driver does provide an API to +* enable or disable specific interrupts. +* +* <b>SGDMA List Management</b> +* +* The HW expectes BDs to be setup as a singly linked list. As BDs are completed, +* the DMA engine will dereference BD.Next and load the next BD to process. +* This driver uses a fixed buffer ring where all BDs are linked to the next +* adjacent BD in memory. The last BD in the ring is linked to the first. +* +* Within the BD ring, the driver maintains four groups of BDs. Each group +* consists of 0 or more adjacent BDs: +* +* - Free group: Those BDs that can be allocated by the user with +* XDmaV3_SgBdAlloc(). These BDs are under driver control. +* +* - Pre-work group: Those BDs that have been allocated with +* XDmaV3_SgBdAlloc(). These BDs are under user control. The user modifies +* these BDs in preparation for future DMA transactions. +* +* - Work group: Those BDs that have been enqueued to HW with +* XDmaV3_SgBdToHw(). These BDs are under HW control and may be in a +* state of awaiting HW processing, in process, or processed by HW. +* +* - Post-work group: Those BDs that have been processed by HW and have been +* extracted from the work group with XDmaV3_SgBdFromHw(). These BDs are under +* user control. The user may access these BDs to determine the result +* of DMA transactions. When the user is finished, XDmaV3_SgBdFree() should +* be called to place them back into the Free group. +* +* It is considered an error for the user to change BDs while they are in the +* Work group. Doing so can cause data corruption and lead to system instability. +* +* The API provides macros that allow BD list traversal. These macros should be +* used with care as they do not understand where one group ends and another +* begins. +* +* The driver does not cache or keep copies of any BD. When the user modifies +* BDs returned by XDmaV3_SgBdAlloc() or XDmaV3_SgBdFromHw(), they are modifying +* the same BD list that HW accesses. +* +* Certain pairs of list modification functions have usage restrictions. See +* the function headers for XDmaV3_SgBdAlloc() and XDmaV3_SgBdFromHw() for +* more information. +* +* <b>SGDMA List Creation</b> +* +* During initialization, the function XDmaV3_SgListCreate() is used to setup +* a user supplied memory block to contain all BDs for the DMA channel. This +* function takes as an argument the number of BDs to place in the list. To +* arrive at this number, the user is given two methods of calculating it. +* +* The first method assumes the user has a block of memory and they just +* want to fit as many BDs as possible into it. The user must calculate the +* number of BDs that will fit with XDmaV3_mSgListCntCalc(), then supply that +* number into the list creation function. +* +* The second method allows the user to just supply the number directly. The +* driver assumes the memory block is large enough to contain them all. To +* double-check, the user should invoke XDmaV3_mSgListMemCalc() to verify the +* memory block is adequate. +* +* Once the list has been created, it can be used right away to perform DMA +* transactions. However, there are optional steps that can be done to increase +* throughput and decrease user code complexity by the use of XDmaV3_SgListClone(). +* +* BDs have many user accessible attributes that affect how DMA transactions are +* carried out. Many of these attributes (such as the bus width) will probably +* be constant at run-time. The cloning function can be used to copy a template +* BD to every BD in the list relieving the user of having to setup transactions +* from scratch every time a BD is submitted to HW. +* +* Ideally, the only transaction parameters that need to be set at run-time +* should be: buffer address, bytes to transfer, and whether the BD is the +* "Last" BD of a packet. +* +* <b>Adding / Removing BDs from the SGDMA Engine</b> +* +* BDs may be enqueued (see XDmaV3_SgBdToHw()) to the engine any time after +* the SGDMA list is created. If the channel is running (see XDmaV3_SgStart()), +* then newly added BDs will be processed as soon as the engine reaches them. +* If the channel is stopped (see XDmaV3_SgStop()), the newly added BDs will +* be accepted but not processed by the engine until it is restarted. +* +* Processed BDs may be removed (see XDmaV3_SgBdFromHw()) at any time +* after the SGDMA list is created provided the engine has processed any. +* +* <b>Address Translation</b> +* +* When the BD list is setup with XDmaV3_SgListCreate(), a physical and +* virtual address is supplied for the segment of memory containing the +* descriptors. The driver will handle any translations internally. Subsequent +* access of descriptors by the user is done in terms of the virtual address. +* +* <b>Alignment</b> +* +* Except for 4 byte alignment of BDs there are no other alignment restrictions +* imposed by this driver. Individual DMA channels may, based on their +* capabilities or which bus they are a master of, have more stringent alignment +* requirements. It is up to the user to match the requirements of the DMA +* channel being used. +* +* Aside from the initial creation of BD list (see XDmaV3_SgListCreate()), +* there are no other run-time checks for proper alignment. Misaligned user +* buffers or BDs may result in corrupted data. +* +* <b>Cache Coherency</b> +* +* This driver expects all user buffers attached to BDs to be in cache coherent +* memory. Buffers for transmit should be flushed from the cache before passing +* the associated BD to this driver. Buffers for receive should be invalidated +* before being accessed. +* +* If the user wishes that the BD space itself be in cached memory, then +* modification of this driver is required. The driver helps the user in +* this area by: 1) Allowing the user to specify what alignment BDs should +* use (ie. aligned along cache lines); 2) Provide unimplemented invalidate/flush +* macro placeholders in the driver source code where needed. +* +* <b>Reset After Stopping</b> +* +* This driver is designed to allow for stop-reset-start cycles of the DMA +* HW while keeping the BD list intact. When restarted after a reset, this +* driver will point the DMA engine to where it left off after stopping it. +* +* <b>Limitations</b> +* +* This driver requires exclusive use of the hardware DMACR.SGS bit. This +* applies to the actual HW register and BDs submitted through this driver to +* be processed. If a BD is encountered with this bit set, then it will be +* cleared within the driver. +* +* This driver does not have any mechanism for mutual exclusion. It is up to the +* user to provide this protection. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 3.00a rmm 03/11/06 First release +* rmm 06/22/06 Added extern "C" +* </pre> +* +******************************************************************************/ + +#ifndef XDMAV3_H /* prevent circular inclusions */ +#define XDMAV3_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xdmabdv3.h" +#include "xstatus.h" + +/************************** Constant Definitions *****************************/ + +/* Minimum alignment */ +#define XDMABDV3_MINIMUM_ALIGNMENT 4 + + +/**************************** Type Definitions *******************************/ + +/** This is an internal structure used to maintain the SGDMA list */ +typedef struct { + u32 PhysBaseAddr; + /**< Physical address of 1st BD in list */ + u32 BaseAddr; /**< Virtual address of 1st BD in list */ + u32 HighAddr; /**< Virtual address of last BD in the list */ + u32 Length; /**< Total size of ring in bytes */ + u32 RunState; /**< Flag to indicate SGDMA is started */ + u32 Separation;/**< Number of bytes between the starting address + of adjacent BDs */ + XDmaBdV3 *FreeHead;/**< First BD in the free group */ + XDmaBdV3 *PreHead; /**< First BD in the pre-work group */ + XDmaBdV3 *HwHead; /**< First BD in the work group */ + XDmaBdV3 *HwTail; /**< Last BD in the work group */ + XDmaBdV3 *PostHead;/**< First BD in the post-work group */ + XDmaBdV3 *BdaRestart; + /**< BDA to load when channel is started */ + unsigned HwCnt; /**< Number of BDs in work group */ + unsigned PreCnt; /**< Number of BDs in pre-work group */ + unsigned FreeCnt; /**< Number of allocatable BDs in the free group */ + unsigned PostCnt; /**< Number of BDs in post-work group */ + unsigned AllCnt; /**< Total Number of BDs for channel */ +} XDmaV3_BdRing; + +/** + * The XDmaV3 driver instance data. An instance must be allocated for each DMA + * channel in use. If address translation is enabled, then all addresses and + * pointers excluding PhysBase are expressed in terms of the virtual address. + */ +typedef struct XDmaV3 { + u32 RegBase; /**< Base address of channel registers */ + u32 IsReady; /**< Flag to indicate device is ready to use */ + XDmaV3_BdRing BdRing; /**< BD storage for SGDMA */ +} XDmaV3; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many BDs will fit +* in a BD list within the given memory constraints. +* +* The results of this macro can be provided to XDmaV3_SgListCreate(). +* +* @param Alignment specifies what byte alignment the BDs must fall on and +* must be a power of 2 to get an accurate calculation (32, 64, 126,...) +* @param Bytes is the number of bytes to be used to store BDs. +* +* @return Number of BDs that can fit in the given memory area +* +* @note +* C-style signature: +* u32 XDmaV3_mSgListCntCalc(u32 Alignment, u32 Bytes) +* +******************************************************************************/ +#define XDmaV3_mSgListCntCalc(Alignment, Bytes) \ + (u32)((Bytes) / ((sizeof(XDmaBdV3) + ((Alignment)-1)) & ~((Alignment)-1))) + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many bytes of memory +* is required to contain a given number of BDs at a given alignment. +* +* @param Alignment specifies what byte alignment the BDs must fall on. This +* parameter must be a power of 2 to get an accurate calculation (32, 64, +* 128,...) +* @param NumBd is the number of BDs to calculate memory size requirements for +* +* @return The number of bytes of memory required to create a BD list with the +* given memory constraints. +* +* @note +* C-style signature: +* u32 XDmaV3_mSgListMemCalc(u32 Alignment, u32 NumBd) +* +******************************************************************************/ +#define XDmaV3_mSgListMemCalc(Alignment, NumBd) \ + (u32)((sizeof(XDmaBdV3) + ((Alignment)-1)) & ~((Alignment)-1)) * (NumBd) + + +/****************************************************************************/ +/** +* Return the total number of BDs allocated by this channel with +* XDmaV3_SgListCreate(). +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return The total number of BDs allocated for this channel. +* +* @note +* C-style signature: +* u32 XDmaBdV3_mSgGetCnt(XDmaV3* InstancePtr) +* +*****************************************************************************/ +#define XDmaV3_mSgGetCnt(InstancePtr) ((InstancePtr)->BdRing.AllCnt) + + +/****************************************************************************/ +/** +* Return the number of BDs allocatable with XDmaV3_SgBdAlloc() for pre- +* processing. +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return The number of BDs currently allocatable. +* +* @note +* C-style signature: +* u32 XDmaBdV3_mSgGetFreeCnt(XDmaV3* InstancePtr) +* +*****************************************************************************/ +#define XDmaV3_mSgGetFreeCnt(InstancePtr) ((InstancePtr)->BdRing.FreeCnt) + + +/****************************************************************************/ +/** +* Return the next BD in a list. +* +* @param InstancePtr is the DMA channel to operate on. +* @param BdPtr is the BD to operate on. +* +* @return The next BD in the list relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XDmaBdV3 *XDmaV3_mSgBdNext(XDmaV3* InstancePtr, XDmaBdV3 *BdPtr) +* +*****************************************************************************/ +#define XDmaV3_mSgBdNext(InstancePtr, BdPtr) \ + (((u32)(BdPtr) >= (InstancePtr)->BdRing.HighAddr) ? \ + (XDmaBdV3*)(InstancePtr)->BdRing.BaseAddr : \ + (XDmaBdV3*)((u32)(BdPtr) + (InstancePtr)->BdRing.Separation)) + + +/****************************************************************************/ +/** +* Return the previous BD in the list. +* +* @param InstancePtr is the DMA channel to operate on. +* @param BdPtr is the BD to operate on +* +* @return The previous BD in the list relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XDmaBdV3 *XDmaV3_mSgBdPrev(XDmaV3* InstancePtr, XDmaBdV3 *BdPtr) +* +*****************************************************************************/ +#define XDmaV3_mSgBdPrev(InstancePtr, BdPtr) \ + (((u32)(BdPtr) <= (InstancePtr)->BdRing.BaseAddr) ? \ + (XDmaBdV3*)(InstancePtr)->BdRing.HighAddr : \ + (XDmaBdV3*)((u32)(BdPtr) - (InstancePtr)->BdRing.Separation)) + + +/****************************************************************************/ +/** +* Retrieve the current contents of the DMASR register. This macro can be +* used to poll the DMA HW for completion of a transaction. +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return The current contents of the DMASR register. +* +* @note +* C-style signature: +* u32 XDmaV3_mGetStatus(XDmaV3* InstancePtr) +* +*****************************************************************************/ +#define XDmaV3_mGetStatus(InstancePtr) \ + XDmaV3_mReadReg((InstancePtr)->RegBase, XDMAV3_DMASR_OFFSET) + + +/************************** Function Prototypes ******************************/ + +/* + * Initialization and control functions in xdmav3.c + */ +int XDmaV3_Initialize(XDmaV3 * InstancePtr, u32 BaseAddress); + +/* + * Interrupt related functions in xdmav3_intr.c + */ +void XDmaV3_SetInterruptStatus(XDmaV3 * InstancePtr, u32 Mask); +u32 XDmaV3_GetInterruptStatus(XDmaV3 * InstancePtr); +void XDmaV3_SetInterruptEnable(XDmaV3 * InstancePtr, u32 Mask); +u32 XDmaV3_GetInterruptEnable(XDmaV3 * InstancePtr); + +/* + * Simple DMA related functions in xdmav3_simple.c + */ +int XDmaV3_SimpleTransfer(XDmaV3 * InstancePtr, XDmaBdV3 * Bdptr); + +/* + * Scatter gather DMA related functions in xdmav3_sg.c + */ +int XDmaV3_SgStart(XDmaV3 * InstancePtr); +void XDmaV3_SgStop(XDmaV3 * InstancePtr); +int XDmaV3_SgSetPktThreshold(XDmaV3 * InstancePtr, u16 Threshold); +int XDmaV3_SgSetPktWaitbound(XDmaV3 * InstancePtr, u16 TimerVal); +u16 XDmaV3_SgGetPktThreshold(XDmaV3 * InstancePtr); +u16 XDmaV3_SgGetPktWaitbound(XDmaV3 * InstancePtr); + +int XDmaV3_SgListCreate(XDmaV3 * InstancePtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, unsigned BdCount); +int XDmaV3_SgListClone(XDmaV3 * InstancePtr, XDmaBdV3 * SrcBdPtr); +int XDmaV3_SgCheck(XDmaV3 * InstancePtr); +int XDmaV3_SgBdAlloc(XDmaV3 * InstancePtr, unsigned NumBd, + XDmaBdV3 ** BdSetPtr); +int XDmaV3_SgBdUnAlloc(XDmaV3 * InstancePtr, unsigned NumBd, + XDmaBdV3 * BdSetPtr); +int XDmaV3_SgBdToHw(XDmaV3 * InstancePtr, unsigned NumBd, XDmaBdV3 * BdSetPtr); +int XDmaV3_SgBdFree(XDmaV3 * InstancePtr, unsigned NumBd, XDmaBdV3 * BdSetPtr); +unsigned XDmaV3_SgBdFromHw(XDmaV3 * InstancePtr, unsigned BdLimit, + XDmaBdV3 ** BdSetPtr); + +/* + * Selftest functions in xdmav3_selftest.c + */ +int XDmaV3_SelfTest(XDmaV3 * InstancePtr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_intr.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_intr.c 2014-07-20 22:06:38.896263822 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2006 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xdmav3_intr.c +* +* This file implements interrupt control related functions. For more +* information on this driver, see xdmav3.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 3.00a rmm 03/11/06 First release +* </pre> +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xdmav3.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* Set the interrupt status register for this channel. Use this function +* to ack pending interrupts. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Mask is a logical OR of XDMAV3_IPXR_*_MASK constants found in +* xdmav3_l.h. +* +******************************************************************************/ +void XDmaV3_SetInterruptStatus(XDmaV3 * InstancePtr, u32 Mask) +{ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_ISR_OFFSET, Mask); +} + + +/*****************************************************************************/ +/** +* Retrieve the interrupt status for this channel. OR the results of this +* function with results from XDmaV3_GetInterruptEnable() to determine which +* interrupts are currently pending to the processor. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return Mask of interrupt bits made up of XDMAV3_IPXR_*_MASK constants found +* in xdmav3_l.h. +* +******************************************************************************/ +u32 XDmaV3_GetInterruptStatus(XDmaV3 * InstancePtr) +{ + return (XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_ISR_OFFSET)); +} + + +/*****************************************************************************/ +/** +* Enable specific DMA interrupts. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Mask is a logical OR of of XDMAV3_IPXR_*_MASK constants found in +* xdmav3_l.h. +* +******************************************************************************/ +void XDmaV3_SetInterruptEnable(XDmaV3 * InstancePtr, u32 Mask) +{ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_IER_OFFSET, Mask); +} + + +/*****************************************************************************/ +/** +* Retrieve the interrupt enable register for this channel. Use this function to +* determine which interrupts are currently enabled to the processor. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return Mask of interrupt bits made up of XDMAV3_IPXR_*_MASK constants found in +* xdmav3_l.h. +* +******************************************************************************/ +u32 XDmaV3_GetInterruptEnable(XDmaV3 * InstancePtr) +{ + return (XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_IER_OFFSET)); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_l.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_l.h 2014-07-20 22:06:38.905263673 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ + +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2006 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xdmav3_l.h +* +* This header file contains identifiers and low-level driver functions (or +* macros) that can be used to access the Direct Memory Access and Scatter +* Gather (SG DMA) device. +* +* For more information about the operation of this device, see the hardware +* specification and documentation in the higher level driver xdma.h source +* code file. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 3.00a rmm 03/11/06 First release +* rmm 06/22/06 Added extern "C" +* </pre> +* +******************************************************************************/ + +#ifndef XDMAV3_L_H /* prevent circular inclusions */ +#define XDMAV3_L_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xio.h" + +/************************** Constant Definitions *****************************/ + + +/* Register offset definitions. Unless otherwise noted, register access is + * 32 bit. + */ + +/** @name DMA channel registers + * @{ + */ +#define XDMAV3_DMASR_OFFSET 0x00000000 /**< DMA Status Register */ +#define XDMAV3_DMACR_OFFSET 0x00000004 /**< DMA Control Register */ +#define XDMAV3_MSBA_OFFSET 0x00000008 /**< Most Significant Bus Address */ +#define XDMAV3_LSBA_OFFSET 0x0000000C /**< Least Significant Bus Address */ +#define XDMAV3_BDA_OFFSET 0x00000010 /**< Buffer Descriptor Address */ +#define XDMAV3_LENGTH_OFFSET 0x00000014 /**< DMA Length */ +#define XDMAV3_ISR_OFFSET 0x00000018 /**< Interrupt Status Register */ +#define XDMAV3_IER_OFFSET 0x0000001C /**< Interrupt Enable Register */ +#define XDMAV3_SWCR_OFFSET 0x00000020 /**< Software Control Register */ +/*@}*/ + +/** @name Buffer Descriptor register offsets + * @{ + */ +#define XDMAV3_BD_DMASR_OFFSET 0x00 /**< Channel DMASR register contents */ +#define XDMAV3_BD_DMACR_OFFSET 0x04 /**< Channel DMACR register contents */ +#define XDMAV3_BD_MSBA_OFFSET 0x08 /**< Channel MSBA register contents */ +#define XDMAV3_BD_LSBA_OFFSET 0x0C /**< Channel LSBA register contents */ +#define XDMAV3_BD_BDA_OFFSET 0x10 /**< Next buffer descriptor pointer */ +#define XDMAV3_BD_LENGTH_OFFSET 0x14 /**< Channel LENGTH register contents */ +#define XDMAV3_BD_SR_OFFSET 0x18 /**< Packet Status */ +#define XDMAV3_BD_RSVD_OFFSET 0x1C /**< Reserved */ +#define XDMAV3_BD_USR0_OFFSET 0x20 /**< HW User defined */ +#define XDMAV3_BD_USR1_OFFSET 0x24 /**< HW User defined */ +#define XDMAV3_BD_USR2_OFFSET 0x28 /**< HW User defined */ +#define XDMAV3_BD_USR3_OFFSET 0x2C /**< HW User defined */ +#define XDMAV3_BD_USR4_OFFSET 0x30 /**< HW User defined */ +#define XDMAV3_BD_USR5_OFFSET 0x34 /**< HW User defined */ +#define XDMAV3_BD_LENCPY_OFFSET 0x38 /**< SW Driver usage */ +#define XDMAV3_BD_ID_OFFSET 0x3C /**< SW Driver usage */ + +#define XDMAV3_BD_NUM_WORDS 16 /**< Number of 32-bit words that make + up a BD */ +/*@}*/ + +/* Register masks. The following constants define bit locations of various + * control bits in the registers. Constants are not defined for those registers + * that have a single bit field representing all 32 bits. For further + * information on the meaning of the various bit masks, refer to the HW spec. + */ + + +/** @name DMA Status Register (DMASR) bitmasks + * @note These bitmasks are identical between XDMAV3_DMASR_OFFSET and + * XDMAV3_BD_DMASR_OFFSET + * @{ + */ +#define XDMAV3_DMASR_DMABSY_MASK 0x80000000 /**< DMA busy */ +#define XDMAV3_DMASR_DBE_MASK 0x40000000 /**< Bus error */ +#define XDMAV3_DMASR_DBT_MASK 0x20000000 /**< Bus timeout */ +#define XDMAV3_DMASR_DMADONE_MASK 0x10000000 /**< DMA done */ +#define XDMAV3_DMASR_SGBSY_MASK 0x08000000 /**< SG channel busy */ +#define XDMAV3_DMASR_LAST_MASK 0x04000000 /**< Last BD of packet */ +#define XDMAV3_DMASR_SGDONE_MASK 0x01000000 /**< SGDMA done */ +#define XDMAV3_DMASR_DMACNFG_MASK 0x00300000 /**< DMA configuration */ + +#define XDMAV3_DMASR_DMACNFG_SIMPLE_MASK 0x00000000 /**< Simple DMA config */ +#define XDMAV3_DMASR_DMACNFG_SSGDMA_MASK 0x00100000 /**< Simple SGDMA config */ +#define XDMAV3_DMASR_DMACNFG_SGDMATX_MASK 0x00200000 /**< SGDMA xmit config */ +#define XDMAV3_DMASR_DMACNFG_SGDMARX_MASK 0x00300000 /**< SGDMA recv config */ +#define XDMAV3_DMASR_DMACNFG_MASK 0x00300000 /**< Mask for all */ + +/*@}*/ + +/** @name DMA Control Register (DMACR) bitmasks + * @note These bitmasks are identical between XDMAV3_DMACR_OFFSET and + * XDMAV3_BD_DMACR_OFFSET + * @{ + */ +#define XDMAV3_DMACR_AINC_MASK 0x80000000 /**< Address increment */ +#define XDMAV3_DMACR_BPDRE_MASK 0x20000000 /**< Bypass DRE */ +#define XDMAV3_DMACR_SGS_MASK 0x08000000 /**< Scatter gather stop */ +#define XDMAV3_DMACR_LAST_MASK 0x04000000 /**< Last BD of packet */ +#define XDMAV3_DMACR_DEVSEL_MASK 0x00FF0000 /**< Device select */ +#define XDMAV3_DMACR_BDPAGE_MASK 0x00000F00 /**< BD page address */ +#define XDMAV3_DMACR_TYPE_MASK 0x00000070 /**< DMA transfer type */ +#define XDMAV3_DMACR_DSIZE_MASK 0x00000007 /**< DMA transfer width */ + +/* Sub-fields within XDMAV3_DMACR_DIR_MASK */ +#define XDMAV3_DMACR_DIR_RX_MASK 0x40000000 /**< Xfer in Rx direction */ +#define XDMAV3_DMACR_DIR_TX_MASK 0x00000000 /**< Xfer in Tx direction */ + +/* Sub-fields within XDMAV3_DMACR_TYPE_MASK */ +#define XDMAV3_DMACR_TYPE_BFBURST_MASK 0x00000010 /**< Bounded fixed length + burst */ +#define XDMAV3_DMACR_TYPE_BIBURST_MASK 0x00000020 /**< Bounded indeterminate + burst */ + +/* Sub-fields within XDMAV3_DMACR_DSIZE_MASK */ +#define XDMAV3_DMACR_DSIZE_8_MASK 0x00000000 /**< Xfer width = 8 bits */ +#define XDMAV3_DMACR_DSIZE_16_MASK 0x00000001 /**< Xfer width = 16 bits */ +#define XDMAV3_DMACR_DSIZE_32_MASK 0x00000002 /**< Xfer width = 32 bits */ +#define XDMAV3_DMACR_DSIZE_64_MASK 0x00000003 /**< Xfer width = 64 bits */ +#define XDMAV3_DMACR_DSIZE_128_MASK 0x00000004 /**< Xfer width = 128 bits */ + +/* Left shift values for selected masks */ +#define XDMAV3_DMACR_DEVSEL_SHIFT 16 +#define XDMAV3_DMACR_BDPAGE_SHIFT 8 +/*@}*/ + +/** @name Interrupt status bits for MAC interrupts + * These bits are associated with XDMAV3_ISR_OFFSET and + * XDMAV3_IER_OFFSET registers. + * @{ + */ +#define XDMAV3_IPXR_DD_MASK 0x00000040 /**< DMA complete */ +#define XDMAV3_IPXR_DE_MASK 0x00000020 /**< DMA error */ +#define XDMAV3_IPXR_PD_MASK 0x00000010 /**< Pkt done */ +#define XDMAV3_IPXR_PCTR_MASK 0x00000008 /**< Pkt count threshold reached */ +#define XDMAV3_IPXR_PWBR_MASK 0x00000004 /**< Pkt waitbound reached */ +#define XDMAV3_IPXR_SGDA_MASK 0x00000002 /**< SG Disable ack */ +#define XDMAV3_IPXR_SGEND_MASK 0x00000001 /**< SG End */ +/*@}*/ + +/** @name Software control register (SWCR) bitmasks + * @{ + */ +#define XDMAV3_SWCR_SGE_MASK 0x80000000 /**< SG Enable */ +#define XDMAV3_SWCR_SGD_MASK 0x40000000 /**< SG Disable */ +#define XDMAV3_SWCR_DSGAR_MASK 0x20000000 /**< SG Disable auto-restart */ +#define XDMAV3_SWCR_PWB_MASK 0x00FFF000 /**< Pkt waitbound */ +#define XDMAV3_SWCR_PCT_MASK 0x00000FFF /**< Pkt threshold count */ + +/* Left shift values for selected masks */ +#define XDMAV3_SWCR_PCT_SHIFT 0 +#define XDMAV3_SWCR_PWB_SHIFT 12 +/*@}*/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/****************************************************************************/ +/** +* +* Read the given IPIF register. +* +* @param BaseAddress is the IPIF base address of the device +* @param RegOffset is the register offset to be read +* +* @return The 32-bit value of the register +* +* @note +* C-style signature: +* u32 XDmaV3_mReadReg(u32 BaseAddress, u32 RegOffset) +* +*****************************************************************************/ +#define XDmaV3_mReadReg(BaseAddress, RegOffset) \ + XIo_In32((u32)(BaseAddress) + (u32)(RegOffset)) + + +/****************************************************************************/ +/** +* +* Write the given IPIF register. +* +* @param BaseAddress is the IPIF base address of the device +* @param RegOffset is the register offset to be written +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note +* C-style signature: +* void XDmaV3_mWriteReg(u32 BaseAddress, u32 RegOffset, u32 Data) +* +*****************************************************************************/ +#define XDmaV3_mWriteReg(BaseAddress, RegOffset, Data) \ + XIo_Out32((u32)(BaseAddress) + (u32)(RegOffset), (u32)(Data)) + + +/****************************************************************************/ +/** +* +* Read the given Buffer Descriptor word. +* +* @param BaseAddress is the base address of the BD to read +* @param Offset is the word offset to be read +* +* @return The 32-bit value of the field +* +* @note +* C-style signature: +* u32 XDmaV3_mReadBd(u32 BaseAddress, u32 Offset) +* +*****************************************************************************/ +#define XDmaV3_mReadBd(BaseAddress, Offset) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset))) + + +/****************************************************************************/ +/** +* +* Write the given Buffer Descriptor word. +* +* @param BaseAddress is the base address of the BD to write +* @param Offset is the word offset to be written +* @param Data is the 32-bit value to write to the field +* +* @return None. +* +* @note +* C-style signature: +* void XDmaV3_mWriteReg(u32 BaseAddress, u32 Offset, u32 Data) +* +*****************************************************************************/ +#define XDmaV3_mWriteBd(BaseAddress, Offset, Data) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset)) = (Data)) + + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_selftest.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_selftest.c 2014-07-20 22:06:38.914263525 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2006 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xdmav3_selftest.c +* +* This file implements DMA selftest related functions. For more +* information on this driver, see xdmav3.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 3.00a rmm 03/11/06 First release +* </pre> +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xdmav3.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* Selftest is not implemented. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return +* - XST_SUCCESS if the self test passes +* +******************************************************************************/ +int XDmaV3_SelfTest(XDmaV3 * InstancePtr) +{ + return (XST_SUCCESS); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_sg.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_sg.c 2014-07-20 22:06:38.932263228 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2006 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xdmav3_sg.c +* +* This file implements Scatter-Gather DMA (SGDMA) related functions. For more +* information on this driver, see xdmav3.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 3.00a rmm 03/11/06 First release +* rmm 06/22/06 Fixed C++ compiler warnings +* </pre> +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include <linux/string.h> +#include <asm/delay.h> + +#include "xdmav3.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/**************************************************************************** + * These cache macros are used throughout this source code file to show + * users where cache operations should occur if BDs were to be placed in + * a cached memory region. Cacheing BD regions, however, is not common. + * + * The macros are implemented as NULL operations, but may be hooked into + * XENV macros in future revisions of this driver. + ****************************************************************************/ +#define XDMAV3_CACHE_FLUSH(BdPtr) +#define XDMAV3_CACHE_INVALIDATE(BdPtr) + +/**************************************************************************** + * Compute the virtual address of a descriptor from its physical address + * + * @param Ring is the ring BdPtr appears in + * @param BdPtr is the physical address of the BD + * + * @returns Virtual address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + ****************************************************************************/ +#define XDMAV3_PHYS_TO_VIRT(Ring, BdPtr) \ + ((u32)BdPtr + (Ring->BaseAddr - Ring->PhysBaseAddr)) + +/**************************************************************************** + * Compute the physical address of a descriptor from its virtual address + * + * @param Ring is the ring BdPtr appears in + * @param BdPtr is the physical address of the BD + * + * @returns Physical address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + ****************************************************************************/ +#define XDMAV3_VIRT_TO_PHYS(Ring, BdPtr) \ + ((u32)BdPtr - (Ring->BaseAddr - Ring->PhysBaseAddr)) + +/**************************************************************************** + * Clear or set the SGS bit of the DMACR register + ****************************************************************************/ +#define XDMAV3_HW_SGS_CLEAR \ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_DMACR_OFFSET, \ + XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMACR_OFFSET) \ + & ~XDMAV3_DMACR_SGS_MASK) + +#define XDMAV3_HW_SGS_SET \ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_DMACR_OFFSET, \ + XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMACR_OFFSET) \ + | XDMAV3_DMACR_SGS_MASK) + +/**************************************************************************** + * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around + * to the beginning of the ring if needed. + * + * We know if a wrapaound should occur if the new BdPtr is greater than + * the high address in the ring OR if the new BdPtr crosses over the + * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not + * allow a BD space to span this boundary. + * + * @param Ring is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + ****************************************************************************/ +#define XDMAV3_RING_SEEKAHEAD(Ring, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)BdPtr; \ + \ + Addr += (Ring->Separation * NumBd); \ + if ((Addr > Ring->HighAddr) || ((u32)BdPtr > Addr)) \ + { \ + Addr -= Ring->Length; \ + } \ + \ + BdPtr = (XDmaBdV3*)Addr; \ + } + +/**************************************************************************** + * Move the BdPtr argument backwards an arbitrary number of BDs wrapping + * around to the end of the ring if needed. + * + * We know if a wrapaound should occur if the new BdPtr is less than + * the base address in the ring OR if the new BdPtr crosses over the + * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not + * allow a BD space to span this boundary. + * + * @param Ring is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + ****************************************************************************/ +#define XDMAV3_RING_SEEKBACK(Ring, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)BdPtr; \ + \ + Addr -= (Ring->Separation * NumBd); \ + if ((Addr < Ring->BaseAddr) || ((u32)BdPtr < Addr)) \ + { \ + Addr += Ring->Length; \ + } \ + \ + BdPtr = (XDmaBdV3*)Addr; \ + } + + +/************************** Function Prototypes ******************************/ + +static int IsSgDmaChannel(XDmaV3 * InstancePtr); + + +/************************** Variable Definitions *****************************/ + +/******************************************************************************/ +/** + * Start the SGDMA channel. + * + * @param InstancePtr is a pointer to the instance to be started. + * + * @return + * - XST_SUCCESS if channel was started. + * - XST_DMA_SG_NO_LIST if the channel has no initialized BD ring. + * + ******************************************************************************/ +int XDmaV3_SgStart(XDmaV3 * InstancePtr) +{ + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + u32 Swcr; + + /* BD list has yet to be created for this channel */ + if (Ring->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Do nothing if already started */ + if (Ring->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_SUCCESS); + } + + /* Note as started */ + Ring->RunState = XST_DMA_SG_IS_STARTED; + + /* Restore BDA */ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_BDA_OFFSET, + Ring->BdaRestart); + + /* If there are unprocessed BDs then we want to channel to begin processing + * right away + */ + if ((XDmaV3_mReadBd(XDMAV3_PHYS_TO_VIRT(Ring, Ring->BdaRestart), + XDMAV3_BD_DMASR_OFFSET) & XDMAV3_DMASR_DMADONE_MASK) + == 0) { + /* DMACR.SGS = 0 */ + XDMAV3_HW_SGS_CLEAR; + } + + /* To start, clear SWCR.DSGAR, and set SWCR.SGE */ + Swcr = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); + Swcr &= ~XDMAV3_SWCR_DSGAR_MASK; + Swcr |= XDMAV3_SWCR_SGE_MASK; + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET, Swcr); + + return (XST_SUCCESS); +} + + +/******************************************************************************/ +/** + * Stop the SGDMA or Simple SGDMA channel gracefully. Any DMA operation + * currently in progress is allowed to finish. + * + * An interrupt may be generated as the DMA engine finishes the packet in + * process. To prevent this (if desired) then disabled DMA interrupts prior to + * invoking this function. + * + * If after stopping the channel, new BDs are enqueued with XDmaV3_SgBdToHw(), + * then those BDs will not be processed until after XDmaV3_SgStart() is called. + * + * @param InstancePtr is a pointer to the instance to be stopped. + * + * @note This function will block until the HW indicates that DMA has stopped. + * + ******************************************************************************/ +void XDmaV3_SgStop(XDmaV3 * InstancePtr) +{ + volatile u32 Swcr; + u32 Dmasr; + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + u32 Ier; + + /* Save the contents of the interrupt enable register then disable + * interrupts. This register will be restored at the end of the function + */ + Ier = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_IER_OFFSET); + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_IER_OFFSET, 0); + + /* Stopping the HW is a three step process: + * 1. Set SWCR.SGD=1 + * 2. Wait for SWCR.SGE=0 + * 3. Set SWCR.DSGAR=0 and SWCR.SGE=1 + * + * Once we've successfully gone through this process, the HW is fully + * stopped. To restart we must give the HW a new BDA. + */ + Swcr = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); + + /* If the channel is currently active, stop it by setting SWCR.SGD=1 + * and waiting for SWCR.SGE to toggle to 0 + */ + if (Swcr & XDMAV3_SWCR_SGE_MASK) { + Swcr |= XDMAV3_SWCR_SGD_MASK; + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET, + Swcr); + + while (Swcr & XDMAV3_SWCR_SGE_MASK) { + Swcr = XDmaV3_mReadReg(InstancePtr->RegBase, + XDMAV3_SWCR_OFFSET); + } + } + + /* Note as stopped */ + Ring->RunState = XST_DMA_SG_IS_STOPPED; + + /* Save the BDA to restore when channel is restarted */ + Ring->BdaRestart = + (XDmaBdV3 *) XDmaV3_mReadReg(InstancePtr->RegBase, + XDMAV3_BDA_OFFSET); + + /* If this is a receive channel, then the BDA restore may require a more + * complex treatment. If the channel stopped without processing a packet, + * then DMASR.SGDONE will be clear. The BDA we've already read in this case + * is really BDA->BDA so we need to backup one BDA to get the correct + * restart point. + */ + Dmasr = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); + if ((Dmasr & XDMAV3_DMASR_DMACNFG_MASK) == + XDMAV3_DMASR_DMACNFG_SGDMARX_MASK) { + if (!(Dmasr & XDMAV3_DMASR_SGDONE_MASK)) { + Ring->BdaRestart = + (XDmaBdV3 *) XDMAV3_PHYS_TO_VIRT(Ring, + Ring-> + BdaRestart); + Ring->BdaRestart = + XDmaV3_mSgBdPrev(InstancePtr, Ring->BdaRestart); + Ring->BdaRestart = + (XDmaBdV3 *) XDMAV3_VIRT_TO_PHYS(Ring, + Ring-> + BdaRestart); + } + } + + Swcr |= XDMAV3_SWCR_DSGAR_MASK; + Swcr &= ~XDMAV3_SWCR_SGD_MASK; + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET, Swcr); + + /* Restore interrupt enables. If an interrupt occurs due to this function + * stopping the channel then it will happen right here + */ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_IER_OFFSET, Ier); +} + + +/******************************************************************************/ +/** + * Set the packet threshold for this SGDMA channel. This has the effect of + * delaying processor interrupts until the given number of packets (not BDs) + * have been processed. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Threshold is the packet threshold to set. If 0 is specified, then + * this feature is disabled. Maximum threshold is 2^12 - 1. + * + * @return + * - XST_SUCCESS if threshold set properly. + * - XST_NO_FEATURE if this function was called on a DMA channel that does not + * have interrupt coalescing capabilities. + * + * @note This function should not be prempted by another XDmaV3 function. + * + ******************************************************************************/ +int XDmaV3_SgSetPktThreshold(XDmaV3 * InstancePtr, u16 Threshold) +{ + u32 Reg; + + /* Is this a SGDMA channel */ + Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); + if (!IsSgDmaChannel(InstancePtr)) { + return (XST_NO_FEATURE); + } + + /* Replace the pkt threshold field in the SWCR */ + Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); + Reg &= ~XDMAV3_SWCR_PCT_MASK; + Reg |= ((Threshold << XDMAV3_SWCR_PCT_SHIFT) & XDMAV3_SWCR_PCT_MASK); + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET, Reg); + + /* Finished */ + return (XST_SUCCESS); +} + + +/******************************************************************************/ +/** + * Set the packet waitbound timer for this SGDMA channel. See xdmav3.h for more + * information on interrupt coalescing and the effects of the waitbound timer. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param TimerVal is the waitbound period to set. If 0 is specified, then + * this feature is disabled. Maximum waitbound is 2^12 - 1. LSB is + * 1 millisecond (approx). + * + * @return + * - XST_SUCCESS if waitbound set properly. + * - XST_NO_FEATURE if this function was called on a DMA channel that does not + * have interrupt coalescing capabilities. + * + * @note This function should not be prempted by another XDmaV3 function. + * + ******************************************************************************/ +int XDmaV3_SgSetPktWaitbound(XDmaV3 * InstancePtr, u16 TimerVal) +{ + u32 Reg; + + /* Is this a SGDMA channel */ + Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); + if (!IsSgDmaChannel(InstancePtr)) { + return (XST_NO_FEATURE); + } + + /* Replace the waitbound field in the SWCR */ + Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); + Reg &= ~XDMAV3_SWCR_PWB_MASK; + Reg |= ((TimerVal << XDMAV3_SWCR_PWB_SHIFT) & XDMAV3_SWCR_PWB_MASK); + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET, Reg); + + /* Finished */ + return (XST_SUCCESS); +} + + +/******************************************************************************/ +/** + * Get the packet threshold for this channel that was set with + * XDmaV3_SgSetPktThreshold(). + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return Current packet threshold as reported by HW. If the channel does not + * include interrupt coalescing, then the return value will always be 0. + ******************************************************************************/ +u16 XDmaV3_SgGetPktThreshold(XDmaV3 * InstancePtr) +{ + u32 Reg; + + /* Is this a SGDMA channel */ + Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); + if (!IsSgDmaChannel(InstancePtr)) { + return (0); + } + + /* Get the threshold */ + Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); + Reg &= XDMAV3_SWCR_PCT_MASK; + Reg >>= XDMAV3_SWCR_PCT_SHIFT; + return ((u16) Reg); +} + + +/******************************************************************************/ +/** + * Get the waitbound timer for this channel that was set with + * XDmaV3_SgSetPktWaitbound(). + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return Current waitbound timer as reported by HW. If the channel does not + * include interrupt coalescing, then the return value will always be 0. + ******************************************************************************/ +u16 XDmaV3_SgGetPktWaitbound(XDmaV3 * InstancePtr) +{ + u32 Reg; + + /* Is this a SGDMA channel */ + Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); + if (!IsSgDmaChannel(InstancePtr)) { + return (0); + } + + /* Get the threshold */ + Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); + Reg &= XDMAV3_SWCR_PWB_MASK; + Reg >>= XDMAV3_SWCR_PWB_SHIFT; + return ((u16) Reg); +} + + +/******************************************************************************/ +/** + * Using a memory segment allocated by the caller, create and setup the BD list + * for the given SGDMA channel. + * + * @param InstancePtr is the instance to be worked on. + * @param PhysAddr is the physical base address of user memory region. + * @param VirtAddr is the virtual base address of the user memory region. If + * address translation is not being utilized, then VirtAddr should be + * equivalent to PhysAddr. + * @param Alignment governs the byte alignment of individual BDs. This function + * will enforce a minimum alignment of 4 bytes with no maximum as long as + * it is specified as a power of 2. + * @param BdCount is the number of BDs to setup in the user memory region. It is + * assumed the region is large enough to contain the BDs. Refer to the + * "SGDMA List Creation" section in xdmav3.h for more information on + * list creation. + * + * @return + * + * - XST_SUCCESS if initialization was successful + * - XST_NO_FEATURE if the provided instance is a non SGDMA type of DMA + * channel. + * - XST_INVALID_PARAM under any of the following conditions: 1) PhysAddr and/or + * VirtAddr are not aligned to the given Alignment parameter; 2) Alignment + * parameter does not meet minimum requirements or is not a power of 2 value; + * 3) BdCount is 0. + * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans + * over address 0x00000000 in virtual address space. + * + * @note + * + * Some DMA HW requires 8 or more byte alignments of BDs. Make sure the correct + * value is passed into the Alignment parameter to meet individual DMA HW + * requirements. + * + ******************************************************************************/ +int XDmaV3_SgListCreate(XDmaV3 * InstancePtr, u32 PhysAddr, u32 VirtAddr, + u32 Alignment, unsigned BdCount) +{ + unsigned i; + u32 BdV; + u32 BdP; + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + + /* In case there is a failure prior to creating list, make sure the following + * attributes are 0 to prevent calls to other SG functions from doing anything + */ + Ring->AllCnt = 0; + Ring->FreeCnt = 0; + Ring->HwCnt = 0; + Ring->PreCnt = 0; + Ring->PostCnt = 0; + + /* Is this a SGDMA channel */ + if (!IsSgDmaChannel(InstancePtr)) { + return (XST_NO_FEATURE); + } + + /* Make sure Alignment parameter meets minimum requirements */ + if (Alignment < XDMABDV3_MINIMUM_ALIGNMENT) { + return (XST_INVALID_PARAM); + } + + /* Make sure Alignment is a power of 2 */ + if ((Alignment - 1) & Alignment) { + return (XST_INVALID_PARAM); + } + + /* Make sure PhysAddr and VirtAddr are on same Alignment */ + if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) { + return (XST_INVALID_PARAM); + } + + /* Is BdCount reasonable? */ + if (BdCount == 0) { + return (XST_INVALID_PARAM); + } + + /* Parameters are sane. Stop the HW just to be safe */ + XDmaV3_SgStop(InstancePtr); + + /* Figure out how many bytes will be between the start of adjacent BDs */ + Ring->Separation = + (sizeof(XDmaBdV3) + (Alignment - 1)) & ~(Alignment - 1); + + /* Must make sure the ring doesn't span address 0x00000000. If it does, + * then the next/prev BD traversal macros will fail. + */ + if (VirtAddr > (VirtAddr + (Ring->Separation * BdCount) - 1)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Initial ring setup: + * - Clear the entire space + * - Setup each BD's BDA field with the physical address of the next BD + * - Set each BD's DMASR.DMADONE bit + */ + memset((void *) VirtAddr, 0, (Ring->Separation * BdCount)); + + BdV = VirtAddr; + BdP = PhysAddr + Ring->Separation; + for (i = 1; i < BdCount; i++) { + XDmaV3_mWriteBd(BdV, XDMAV3_BD_BDA_OFFSET, BdP); + XDmaV3_mWriteBd(BdV, XDMAV3_BD_DMASR_OFFSET, + XDMAV3_DMASR_DMADONE_MASK); + XDMAV3_CACHE_FLUSH(BdV); + BdV += Ring->Separation; + BdP += Ring->Separation; + } + + /* At the end of the ring, link the last BD back to the top */ + XDmaV3_mWriteBd(BdV, XDMAV3_BD_BDA_OFFSET, PhysAddr); + + /* Setup and initialize pointers and counters */ + InstancePtr->BdRing.RunState = XST_DMA_SG_IS_STOPPED; + Ring->BaseAddr = VirtAddr; + Ring->PhysBaseAddr = PhysAddr; + Ring->HighAddr = BdV; + Ring->Length = Ring->HighAddr - Ring->BaseAddr + Ring->Separation; + Ring->AllCnt = BdCount; + Ring->FreeCnt = BdCount; + Ring->FreeHead = (XDmaBdV3 *) VirtAddr; + Ring->PreHead = (XDmaBdV3 *) VirtAddr; + Ring->HwHead = (XDmaBdV3 *) VirtAddr; + Ring->HwTail = (XDmaBdV3 *) VirtAddr; + Ring->PostHead = (XDmaBdV3 *) VirtAddr; + Ring->BdaRestart = (XDmaBdV3 *) PhysAddr; + + /* Make sure the DMACR.SGS is 1 so that no DMA operations proceed until + * the start function is called. + */ + XDMAV3_HW_SGS_SET; + + return (XST_SUCCESS); +} + + +/******************************************************************************/ +/** + * Clone the given BD into every BD in the list. Except for XDMAV3_BD_BDA_OFFSET, + * every field of the source BD is replicated in every BD of the list. + * + * This function can be called only when all BDs are in the free group such as + * they are immediately after initialization with XDmaV3_SgListCreate(). This + * prevents modification of BDs while they are in use by HW or the user. + * + * @param InstancePtr is the instance to be worked on. + * @param SrcBdPtr is the source BD template to be cloned into the list. This BD + * will be modified. + * + * @return + * - XST_SUCCESS if the list was modified. + * - XST_DMA_SG_NO_LIST if a list has not been created. + * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under HW + * or user control. + * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped. + * + ******************************************************************************/ +int XDmaV3_SgListClone(XDmaV3 * InstancePtr, XDmaBdV3 * SrcBdPtr) +{ + unsigned i; + u32 CurBd; + u32 Save; + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + + /* Can't do this function if there isn't a ring */ + if (Ring->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Can't do this function with the channel running */ + if (Ring->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Can't do this function with some of the BDs in use */ + if (Ring->FreeCnt != Ring->AllCnt) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Modify the template by setting DMASR.DMADONE */ + Save = XDmaV3_mReadBd(SrcBdPtr, XDMAV3_BD_DMASR_OFFSET); + Save |= XDMAV3_DMASR_DMADONE_MASK; + XDmaV3_mWriteBd(SrcBdPtr, XDMAV3_BD_DMASR_OFFSET, Save); + + /* Starting from the top of the ring, save BD.Next, overwrite the entire BD + * with the template, then restore BD.Next + */ + for (i = 0, CurBd = Ring->BaseAddr; + i < Ring->AllCnt; i++, CurBd += Ring->Separation) { + Save = XDmaV3_mReadBd(CurBd, XDMAV3_BD_BDA_OFFSET); + memcpy((void *) CurBd, SrcBdPtr, sizeof(XDmaBdV3)); + XDmaV3_mWriteBd(CurBd, XDMAV3_BD_BDA_OFFSET, Save); + XDMAV3_CACHE_FLUSH(CurBd); + } + + return (XST_SUCCESS); +} + + +/******************************************************************************/ +/** + * Reserve locations in the BD list. The set of returned BDs may be modified in + * preparation for future DMA transaction(s). Once the BDs are ready to be + * submitted to HW, the user must call XDmaV3_SgBdToHw() in the same order which + * they were allocated here. Example: + * + * <pre> + * NumBd = 2; + * Status = XDmaV3_SgBdAlloc(MyDmaInstPtr, NumBd, &MyBdSet); + * + * if (Status != XST_SUCCESS) + * { + * // Not enough BDs available for the request + * } + * + * CurBd = MyBdSet; + * for (i=0; i<NumBd; i++) + * { + * // Prepare CurBd..... + * + * // Onto next BD + * CurBd = XDmaV3_mSgBdNext(MyDmaInstPtr, CurBd); + * } + * + * // Give list to HW + * Status = XDmaV3_SgBdToHw(MyDmaInstPtr, NumBd, MyBdSet); + * </pre> + * + * A more advanced use of this function may allocate multiple sets of BDs. + * They must be allocated and given to HW in the correct sequence: + * <pre> + * // Legal + * XDmaV3_SgBdAlloc(MyDmaInstPtr, NumBd1, &MySet1); + * XDmaV3_SgBdToHw(MyDmaInstPtr, NumBd1, MySet1); + * + * // Legal + * XDmaV3_SgBdAlloc(MyDmaInstPtr, NumBd1, &MySet1); + * XDmaV3_SgBdAlloc(MyDmaInstPtr, NumBd2, &MySet2); + * XDmaV3_SgBdToHw(MyDmaInstPtr, NumBd1, MySet1); + * XDmaV3_SgBdToHw(MyDmaInstPtr, NumBd2, MySet2); + * + * // Not legal + * XDmaV3_SgBdAlloc(MyDmaInstPtr, NumBd1, &MySet1); + * XDmaV3_SgBdAlloc(MyDmaInstPtr, NumBd2, &MySet2); + * XDmaV3_SgBdToHw(MyDmaInstPtr, NumBd2, MySet2); + * XDmaV3_SgBdToHw(MyDmaInstPtr, NumBd1, MySet1); + * </pre> + * + * Use the API defined in xdmabdv3.h to modify individual BDs. Traversal of the + * BD set can be done using XDmaV3_mSgBdNext() and XDmaV3_mSgBdPrev(). + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs to allocate + * @param BdSetPtr is an output parameter, it points to the first BD available + * for modification. + * + * @return + * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr + * parameter. + * - XST_FAILURE if there were not enough free BDs to satisfy the request. + * + * @note This function should not be preempted by another XDmaV3 function call + * that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + * @note Do not modify more BDs than the number requested with the NumBd + * parameter. Doing so will lead to data corruption and system + * instability. + * + ******************************************************************************/ +int XDmaV3_SgBdAlloc(XDmaV3 * InstancePtr, unsigned NumBd, XDmaBdV3 ** BdSetPtr) +{ + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + + /* Enough free BDs available for the request? */ + if (Ring->FreeCnt < NumBd) { + return (XST_FAILURE); + } + + /* Set the return argument and move FreeHead forward */ + *BdSetPtr = Ring->FreeHead; + XDMAV3_RING_SEEKAHEAD(Ring, Ring->FreeHead, NumBd); + Ring->FreeCnt -= NumBd; + Ring->PreCnt += NumBd; + return (XST_SUCCESS); +} + +/******************************************************************************/ +/** + * Fully or partially undo an XDmaV3_SgBdAlloc() operation. Use this function + * if all the BDs allocated by XDmaV3_SgBdAlloc() could not be transferred to + * HW with XDmaV3_SgBdToHw(). + * + * This function helps out in situations when an unrelated error occurs after + * BDs have been allocated but before they have been given to HW. An example of + * this type of error would be an OS running out of resources. + * + * This function is not the same as XDmaV3_SgBdFree(). The Free function returns + * BDs to the free list after they have been processed by HW, while UnAlloc + * returns them before being processed by HW. + * + * There are two scenarios where this function can be used. Full UnAlloc or + * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned: + * + * <pre> + * Status = XDmaV3_SgBdAlloc(Inst, 10, &BdPtr); + * . + * . + * if (Error) + * { + * Status = XDmaV3_SgBdUnAlloc(Inst, 10, &BdPtr); + * } + * </pre> + * + * A partial UnAlloc means some of the BDs Alloc'd will be returned: + * + * <pre> + * Status = XDmaV3_SgBdAlloc(Inst, 10, &BdPtr); + * BdsLeft = 10; + * CurBdPtr = BdPtr; + * + * while (BdsLeft) + * { + * if (Error) + * { + * Status = XDmaV3_SgBdUnAlloc(Inst, BdsLeft, CurBdPtr); + * } + * + * CurBdPtr = XDmaV3_SgBdNext(Inst, CurBdPtr); + * BdsLeft--; + * } + * </pre> + * + * A partial UnAlloc must include the last BD in the list that was Alloc'd. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs to allocate + * @param BdSetPtr is an output parameter, it points to the first BD available + * for modification. + * + * @return + * - XST_SUCCESS if the BDs were unallocated. + * - XST_FAILURE if NumBd parameter was greater that the number of BDs in the + * preprocessing state. + * + * @note This function should not be preempted by another XDmaV3 function call + * that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + ******************************************************************************/ +int XDmaV3_SgBdUnAlloc(XDmaV3 * InstancePtr, unsigned NumBd, + XDmaBdV3 * BdSetPtr) +{ + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + + /* Enough BDs in the free state for the request? */ + if (Ring->PreCnt < NumBd) { + return (XST_FAILURE); + } + + /* Set the return argument and move FreeHead backward */ + XDMAV3_RING_SEEKBACK(Ring, Ring->FreeHead, NumBd); + Ring->FreeCnt += NumBd; + Ring->PreCnt -= NumBd; + return (XST_SUCCESS); +} + + +/******************************************************************************/ +/** + * Enqueue a set of BDs to HW that were previously allocated by + * XDmaV3_SgBdAlloc(). Once this function returns, the argument BD set goes + * under HW control. Any changes made to these BDs after this point will corrupt + * the BD list leading to data corruption and system instability. + * + * The set will be rejected if the last BD of the set does not mark the end of + * a packet (see XDmaBdV3_mSetLast()). + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs in the set. + * @param BdSetPtr is the first BD of the set to commit to HW. + * + * @return + * - XST_SUCCESS if the set of BDs was accepted and enqueued to HW. + * - XST_FAILURE if the set of BDs was rejected because the last BD of the set + * did not have its "last" bit set. + * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with + * XDmaV3_SgBdAlloc(). + * + * @note This function should not be preempted by another XDmaV3 function call + * that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + ******************************************************************************/ +int XDmaV3_SgBdToHw(XDmaV3 * InstancePtr, unsigned NumBd, XDmaBdV3 * BdSetPtr) +{ + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + XDmaBdV3 *LastBdPtr; + unsigned i; + u32 Dmacr; + u32 Swcr; + + /* Make sure we are in sync with XDmaV3_SgBdAlloc() */ + if ((Ring->PreCnt < NumBd) || (Ring->PreHead != BdSetPtr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* For all BDs in this set (except the last one) + * - Clear DMASR except for DMASR.DMABSY + * - Clear DMACR.SGS + * + * For the last BD in this set + * - Clear DMASR except for DMASR.DMABSY + * - Set DMACR.SGS (marks the end of the new active list) + */ + LastBdPtr = BdSetPtr; + for (i = 1; i < NumBd; i++) { + XDmaV3_mWriteBd(LastBdPtr, XDMAV3_BD_DMASR_OFFSET, + XDMAV3_DMASR_DMABSY_MASK); + + Dmacr = XDmaV3_mReadBd(LastBdPtr, XDMAV3_BD_DMACR_OFFSET); + XDmaV3_mWriteBd(LastBdPtr, XDMAV3_BD_DMACR_OFFSET, /* DMACR.SGS = 0 */ + Dmacr & ~XDMAV3_DMACR_SGS_MASK); + XDMAV3_CACHE_FLUSH(LastBdPtr); + + LastBdPtr = XDmaV3_mSgBdNext(InstancePtr, LastBdPtr); + } + + /* Last BD */ + XDmaV3_mWriteBd(LastBdPtr, XDMAV3_BD_DMASR_OFFSET, + XDMAV3_DMASR_DMABSY_MASK); + + Dmacr = XDmaV3_mReadBd(LastBdPtr, XDMAV3_BD_DMACR_OFFSET); + XDmaV3_mWriteBd(LastBdPtr, XDMAV3_BD_DMACR_OFFSET, /* DMACR.SGS = 1 */ + Dmacr | XDMAV3_DMACR_SGS_MASK); + XDMAV3_CACHE_FLUSH(LastBdPtr); + + /* The last BD should have DMACR.LAST set */ + if (!(Dmacr & XDMAV3_DMACR_LAST_MASK)) { + return (XST_FAILURE); + } + + /* This set has completed pre-processing, adjust ring pointers & counters */ + XDMAV3_RING_SEEKAHEAD(Ring, Ring->PreHead, NumBd); + Ring->PreCnt -= NumBd; + + /* If it is running, tell the DMA engine to pause */ + Swcr = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); + if (Ring->RunState == XST_DMA_SG_IS_STARTED) { + Swcr |= XDMAV3_SWCR_SGD_MASK; + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET, + Swcr); + } + + /* Transfer control of the BDs to the DMA engine. There are two cases to + * consider: + * + * 1) No currently active list. + * In this case, just resume the engine. + * + * 2) Active list. + * In this case, the last BD in the current list should have DMACR.SGS + * cleared so the engine will never stop there. The new stopping + * point is at the end of the extended list. Once the SGS bits are + * changed, resume the engine. + */ + if (Ring->HwCnt != 0) { + /* Handle case 2 */ + Dmacr = XDmaV3_mReadBd(Ring->HwTail, XDMAV3_BD_DMACR_OFFSET); + Dmacr &= ~XDMAV3_DMACR_SGS_MASK; + XDmaV3_mWriteBd(Ring->HwTail, XDMAV3_BD_DMACR_OFFSET, Dmacr); + XDMAV3_CACHE_FLUSH(Ring->HwTail); + } + + /* Adjust Hw pointers and counters. XDMAV3_RING_SEEKAHEAD could be used to + * advance HwTail, but it will always evaluate to LastBdPtr + */ + Ring->HwTail = LastBdPtr; + Ring->HwCnt += NumBd; + + /* If it was enabled, tell the engine to resume */ + if (Ring->RunState == XST_DMA_SG_IS_STARTED) { + Swcr &= ~XDMAV3_SWCR_SGD_MASK; + Swcr |= XDMAV3_SWCR_SGE_MASK; + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET, + Swcr); + } + + return (XST_SUCCESS); +} + + +/******************************************************************************/ +/** + * Returns a set of BD(s) that have been processed by HW. The returned BDs may + * be examined to determine the outcome of the DMA transaction(s). Once the BDs + * have been examined, the user must call XDmaV3_SgBdFree() in the same order + * which they were retrieved here. Example: + * + * <pre> + * MaxBd = 0xFFFFFFFF; // Ensure we get all that are ready + * + * NumBd = XDmaV3_SgBdFromHw(MyDmaInstPtr, MaxBd, &MyBdSet); + * + * if (NumBd == 0) + * { + * // HW has nothing ready for us yet + * } + * + * CurBd = MyBdSet; + * for (i=0; i<NumBd; i++) + * { + * // Examine CurBd for post processing..... + * + * // Onto next BD + * CurBd = XDmaV3_mSgBdNext(MyDmaInstPtr, CurBd); + * } + * + * XDmaV3_SgBdFree(MyDmaInstPtr, NumBd, MyBdSet); // Return the list + * } + * </pre> + * + * A more advanced use of this function may allocate multiple sets of BDs. + * They must be retrieved from HW and freed in the correct sequence: + * <pre> + * // Legal + * XDmaV3_SgBdFromHw(MyDmaInstPtr, NumBd1, &MySet1); + * XDmaV3_SgBdFree(MyDmaInstPtr, NumBd1, MySet1); + * + * // Legal + * XDmaV3_SgBdFromHw(MyDmaInstPtr, NumBd1, &MySet1); + * XDmaV3_SgBdFromHw(MyDmaInstPtr, NumBd2, &MySet2); + * XDmaV3_SgBdFree(MyDmaInstPtr, NumBd1, MySet1); + * XDmaV3_SgBdFree(MyDmaInstPtr, NumBd2, MySet2); + * + * // Not legal + * XDmaV3_SgBdFromHw(MyDmaInstPtr, NumBd1, &MySet1); + * XDmaV3_SgBdFromHw(MyDmaInstPtr, NumBd2, &MySet2); + * XDmaV3_SgBdFree(MyDmaInstPtr, NumBd2, MySet2); + * XDmaV3_SgBdFree(MyDmaInstPtr, NumBd1, MySet1); + * </pre> + * + * If HW has only partially completed a packet spanning multiple BDs, then none + * of the BDs for that packet will be included in the results. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param BdLimit is the maximum number of BDs to return in the set. + * @param BdSetPtr is an output parameter, it points to the first BD available + * for examination. + * + * @return + * The number of BDs processed by HW. A value of 0 indicates that no data + * is available. No more than BdLimit BDs will be returned. + * + * @note Treat BDs returned by this function as read-only. + * + * @note This function should not be preempted by another XDmaV3 function call + * that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + ******************************************************************************/ +unsigned XDmaV3_SgBdFromHw(XDmaV3 * InstancePtr, unsigned BdLimit, + XDmaBdV3 ** BdSetPtr) +{ + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + XDmaBdV3 *CurBd; + unsigned BdCount; + unsigned BdPartialCount; + u32 Dmasr; + + CurBd = Ring->HwHead; + BdCount = 0; + BdPartialCount = 0; + + /* If no BDs in work group, then there's nothing to search */ + if (Ring->HwCnt == 0) { + *BdSetPtr = NULL; + return (0); + } + + /* Starting at HwHead, keep moving forward in the list until: + * - A BD is encountered with its DMASR.DMABSY bit set which means HW has + * not completed processing of that BD. + * - Ring->HwTail is reached + * - The number of requested BDs has been processed + */ + while (BdCount < BdLimit) { + /* Read the status */ + XDMAV3_CACHE_INVALIDATE(CurBd); + Dmasr = XDmaV3_mReadBd(CurBd, XDMAV3_BD_DMASR_OFFSET); + + /* If the HW still hasn't processed this BD then we are done */ + if (Dmasr & XDMAV3_DMASR_DMABSY_MASK) { + break; + } + + BdCount++; + + /* HW has processed this BD so check the "last" bit. If it is clear, + * then there are more BDs for the current packet. Keep a count of + * these partial packet BDs. + */ + if (Dmasr & XDMAV3_DMASR_LAST_MASK) { + BdPartialCount = 0; + } + else { + BdPartialCount++; + } + + /* Reached the end of the work group */ + if (CurBd == Ring->HwTail) { + break; + } + + /* Move on to next BD in work group */ + CurBd = XDmaV3_mSgBdNext(InstancePtr, CurBd); + } + + /* Subtract off any partial packet BDs found */ + BdCount -= BdPartialCount; + + /* If BdCount is non-zero then BDs were found to return. Set return + * parameters, update pointers and counters, return success + */ + if (BdCount) { + *BdSetPtr = Ring->HwHead; + Ring->HwCnt -= BdCount; + Ring->PostCnt += BdCount; + XDMAV3_RING_SEEKAHEAD(Ring, Ring->HwHead, BdCount); + return (BdCount); + } + else { + *BdSetPtr = NULL; + return (0); + } +} + + +/******************************************************************************/ +/** + * Frees a set of BDs that had been previously retrieved with XDmaV3_SgBdFromHw(). + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs to free. + * @param BdSetPtr is the head of a list of BDs returned by XDmaV3_SgBdFromHw(). + * + * @return + * - XST_SUCCESS if the set of BDs was freed. + * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with + * XDmaV3_SgBdFromHw(). + * + * @note This function should not be preempted by another XDmaV3 function call + * that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + ******************************************************************************/ +int XDmaV3_SgBdFree(XDmaV3 * InstancePtr, unsigned NumBd, XDmaBdV3 * BdSetPtr) +{ + XDmaV3_BdRing *Ring = &InstancePtr->BdRing; + + /* Make sure we are in sync with XDmaV3_SgBdFromHw() */ + if ((Ring->PostCnt < NumBd) || (Ring->PostHead != BdSetPtr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Update pointers and counters */ + Ring->FreeCnt += NumBd; + Ring->PostCnt -= NumBd; + XDMAV3_RING_SEEKAHEAD(Ring, Ring->PostHead, NumBd); + return (XST_SUCCESS); +} + + +/******************************************************************************/ +/** + * Check the internal data structures of the BD ring for the provided channel. + * The following checks are made: + * + * - Is the BD ring linked correctly in physical address space. + * - Do the internal pointers point to BDs in the ring. + * - Do the internal counters add up. + * + * The channel should be stopped prior to calling this function. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return + * - XST_SUCCESS if the set of BDs was freed. + * - XST_DMA_SG_NO_LIST if the list has not been created. + * - XST_IS_STARTED if the channel is not stopped. + * - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data + * structures. If this value is returned, the channel should be reset to + * avoid data corruption or system instability. + * + * @note This function should not be preempted by another XDmaV3 function call + * that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + ******************************************************************************/ +int XDmaV3_SgCheck(XDmaV3 * InstancePtr) +{ + XDmaV3_BdRing *RingPtr = &InstancePtr->BdRing; + u32 AddrV, AddrP; + unsigned i; + + /* Is the list created */ + if (RingPtr->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Can't check if channel is running */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_IS_STARTED); + } + + /* RunState doesn't make sense */ + else if (RingPtr->RunState != XST_DMA_SG_IS_STOPPED) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify internal pointers point to correct memory space */ + AddrV = (u32) RingPtr->FreeHead; + if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->PreHead; + if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->HwHead; + if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->HwTail; + if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->PostHead; + if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify internal counters add up */ + if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt + + RingPtr->PostCnt) != RingPtr->AllCnt) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify BDs are linked correctly */ + AddrV = RingPtr->BaseAddr; + AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation; + for (i = 1; i < RingPtr->AllCnt; i++) { + /* Check BDA for this BD. It should point to next physical addr */ + if (XDmaV3_mReadBd(AddrV, XDMAV3_BD_BDA_OFFSET) != AddrP) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Move on to next BD */ + AddrV += RingPtr->Separation; + AddrP += RingPtr->Separation; + } + + /* Last BD should point back to the beginning of ring */ + if (XDmaV3_mReadBd(AddrV, XDMAV3_BD_BDA_OFFSET) != + RingPtr->PhysBaseAddr) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* No problems found */ + return (XST_SUCCESS); +} + + +/****************************************************************************** + * Verify given channel is of the SGDMA variety. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return + * - 1 if channel is of type SGDMA + * - 0 if channel is not of type SGDMA + ******************************************************************************/ +static int IsSgDmaChannel(XDmaV3 * InstancePtr) +{ + u32 Dmasr; + + Dmasr = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); + if (Dmasr & (XDMAV3_DMASR_DMACNFG_SGDMARX_MASK | + XDMAV3_DMASR_DMACNFG_SGDMATX_MASK | + XDMAV3_DMASR_DMACNFG_SSGDMA_MASK)) { + return (1); + } + else { + return (0); + } +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_simple.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xdmav3_simple.c 2014-07-20 22:06:38.939263112 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2006 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xdmav3_simple.c +* +* This file implements Simple DMA related functions. For more +* information on this driver, see xdmav3.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 3.00a rmm 03/11/06 First release +* </pre> +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xdmav3.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* Initiate a simple DMA transfer. The BD argument sets the parameters of the +* transfer. Since the BD is also used for SG DMA transfers, some fields of the +* BD will be ignored. The following BD macros will have no effect on the +* transfer: +* +* - XDmaBdV3_mSetLast() +* - XDmaBdV3_mClearLast() +* - XDmaBdV3_mSetBdPage() +* +* To determine when the transfer has completed, the user can poll the device +* with XDmaV3_mGetStatus() and test the XDMAV3_DMASR_DMABSY_MASK bit, or wait for +* an interrupt. When the DMA operation has completed, the outcome of the +* transfer can be retrieved by calling XDmaV3_mGetStatus() and testing for DMA +* bus errors bits. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param BdPtr sets the parameters of the transfer. +* +* @return +* - XST_SUCCESS if the transfer was initated +* - XST_DEVICE_BUSY if a transfer is already in progress +* +******************************************************************************/ +int XDmaV3_SimpleTransfer(XDmaV3 * InstancePtr, XDmaBdV3 * BdPtr) +{ + u32 Dmasr; + + /* Is the channel busy */ + Dmasr = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); + if (Dmasr & (XDMAV3_DMASR_DMABSY_MASK | XDMAV3_DMASR_SGBSY_MASK)) { + return (XST_DEVICE_BUSY); + } + + /* Copy BdPtr fields into the appropriate HW registers */ + + /* DMACR: SGS bit is set always. This is done in case the transfer + * occurs on a SGDMA channel and will prevent the HW from fetching the + * next BD. + */ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_DMACR_OFFSET, + XDmaV3_mReadBd(BdPtr, XDMAV3_BD_DMACR_OFFSET) + | XDMAV3_DMACR_SGS_MASK); + + /* MSBA */ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_MSBA_OFFSET, + XDmaV3_mReadBd(BdPtr, XDMAV3_BD_MSBA_OFFSET)); + + /* LSBA */ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_LSBA_OFFSET, + XDmaV3_mReadBd(BdPtr, XDMAV3_BD_LSBA_OFFSET)); + + /* LENGTH: Writing this register starts HW */ + XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_LENGTH_OFFSET, + XDmaV3_mReadBd(BdPtr, XDMAV3_BD_LENGTH_OFFSET)); + + return (XST_SUCCESS); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xenv.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xenv.h 2014-07-20 22:06:38.947262981 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xenv_linux.h +* +* Defines common services specified by xenv.h. +* +* @note +* This file is not intended to be included directly by driver code. +* Instead, the generic xenv.h file is intended to be included by driver +* code. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a wgr 02/28/07 Added cache handling macros. +* 1.00a wgr 02/27/07 Simplified code. Deprecated old-style macro names. +* 1.00a xd 11/03/04 Improved support for doxygen. +* 1.00a ch 10/24/02 First release +* 1.10a wgr 03/22/07 Converted to new coding style. +* </pre> +* +* +******************************************************************************/ + +#ifndef XENV_LINUX_H +#define XENV_LINUX_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + +#include <asm/cache.h> +#include <asm/cacheflush.h> +#include <linux/string.h> +#include <linux/delay.h> + + +/****************************************************************************** + * + * MEMCPY / MEMSET related macros. + * + * Those macros are defined to catch legacy code in Xilinx drivers. The + * XENV_MEM_COPY and XENV_MEM_FILL macros were used in early Xilinx driver + * code. They are being replaced by memcpy() and memset() function calls. These + * macros are defined to catch any remaining occurences of those macros. + * + ******************************************************************************/ + +/*****************************************************************************/ +/** + * + * Copies a non-overlapping block of memory. + * + * @param DestPtr + * Destination address to copy data to. + * + * @param SrcPtr + * Source address to copy data from. + * + * @param Bytes + * Number of bytes to copy. + * + * @return None. + * + *****************************************************************************/ + +#define XENV_MEM_COPY(DestPtr, SrcPtr, Bytes) \ + memcpy(DestPtr, SrcPtr, Bytes) +/* do_not_use_XENV_MEM_COPY_use_memcpy_instead */ + + +/*****************************************************************************/ +/** + * + * Fills an area of memory with constant data. + * + * @param DestPtr + * Destination address to copy data to. + * + * @param Data + * Value to set. + * + * @param Bytes + * Number of bytes to copy. + * + * @return None. + * + *****************************************************************************/ + +#define XENV_MEM_FILL(DestPtr, Data, Bytes) \ + memset(DestPtr, Data, Bytes) +/* do_not_use_XENV_MEM_FILL_use_memset_instead */ + + +/****************************************************************************** + * + * TIME related macros + * + ******************************************************************************/ +/** + * A structure that contains a time stamp used by other time stamp macros + * defined below. This structure is processor dependent. + */ +typedef int XENV_TIME_STAMP; + +/*****************************************************************************/ +/** + * + * Time is derived from the 64 bit PPC timebase register + * + * @param StampPtr is the storage for the retrieved time stamp. + * + * @return None. + * + * @note + * + * Signature: void XENV_TIME_STAMP_GET(XTIME_STAMP *StampPtr) + * <br><br> + * This macro must be implemented by the user. + * + *****************************************************************************/ +#define XENV_TIME_STAMP_GET(StampPtr) + +/*****************************************************************************/ +/** + * + * This macro is not yet implemented and always returns 0. + * + * @param Stamp1Ptr is the first sampled time stamp. + * @param Stamp2Ptr is the second sampled time stamp. + * + * @return 0 + * + * @note + * + * This macro must be implemented by the user. + * + *****************************************************************************/ +#define XENV_TIME_STAMP_DELTA_US(Stamp1Ptr, Stamp2Ptr) (0) + +/*****************************************************************************/ +/** + * + * This macro is not yet implemented and always returns 0. + * + * @param Stamp1Ptr is the first sampled time stamp. + * @param Stamp2Ptr is the second sampled time stamp. + * + * @return 0 + * + * @note + * + * This macro must be implemented by the user + * + *****************************************************************************/ +#define XENV_TIME_STAMP_DELTA_MS(Stamp1Ptr, Stamp2Ptr) (0) + +/*****************************************************************************/ +/** + * + * Delay the specified number of microseconds. + * + * @param delay + * Number of microseconds to delay. + * + * @return None. + * + * @note XENV_USLEEP is deprecated. Use udelay() instead. + * + *****************************************************************************/ + +#define XENV_USLEEP(delay) udelay(delay) +/* do_not_use_XENV_MEM_COPY_use_memcpy_instead */ + + +/****************************************************************************** + * + * CACHE handling macros / mappings + * + * The implementation of the cache handling functions can be found in + * arch/microblaze. + * + * These #defines are simple mappings to the Linux API. + * + * The underlying Linux implementation will take care of taking the right + * actions depending on the configuration of the MicroBlaze processor in the + * system. + * + ******************************************************************************/ + +#define XCACHE_ENABLE_DCACHE() __enable_dcache() +#define XCACHE_DISABLE_DCACHE() __disable_dcache() +#define XCACHE_ENABLE_ICACHE() __enable_icache() +#define XCACHE_DISABLE_ICACHE() __disable_icache() + +#define XCACHE_INVALIDATE_DCACHE_RANGE(Addr, Len) \ + invalidate_dcache_range((unsigned long)(Addr), ((unsigned long)(Addr)+(Len))) +#define XCACHE_FLUSH_DCACHE_RANGE(Addr, Len) \ + flush_dcache_range((unsigned long)(Addr), ((unsigned long)(Addr)+(Len))) + +#define XCACHE_INVALIDATE_ICACHE_RANGE(Addr, Len) "XCACHE_INVALIDATE_ICACHE_RANGE unsupported" +#define XCACHE_FLUSH_ICACHE_RANGE(Addr, Len) flush_icache_range(Addr, Len) + +#define XCACHE_ENABLE_CACHE() \ + { XCACHE_ENABLE_DCACHE(); XCACHE_ENABLE_ICACHE(); } + +#define XCACHE_DISABLE_CACHE() \ + { XCACHE_DISABLE_DCACHE(); XCACHE_DISABLE_ICACHE(); } + + + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ + Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xil_assert.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xil_assert.c 2014-07-20 22:06:38.958262799 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/****************************************************************************** +* +* +* (c) Copyright 2009 Xilinx, Inc. All rights reserved. +* 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. +* +* 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 +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xil_assert.c +* +* This file contains basic assert related functions for Xilinx software IP. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a hbm 07/14/09 Initial release +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/** + * This variable allows testing to be done easier with asserts. An assert + * sets this variable such that a driver can evaluate this variable + * to determine if an assert occurred. + */ +unsigned int Xil_AssertStatus; + +/** + * This variable allows the assert functionality to be changed for testing + * such that it does not wait infinitely. Use the debugger to disable the + * waiting during testing of asserts. + */ +int Xil_AssertWait = TRUE; + +/* The callback function to be invoked when an assert is taken */ +static Xil_AssertCallback Xil_AssertCallbackRoutine = NULL; + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* +* Implement assert. Currently, it calls a user-defined callback function +* if one has been set. Then, it potentially enters an infinite loop depending +* on the value of the Xil_AssertWait variable. +* +* @param file is the name of the filename of the source +* @param line is the linenumber within File +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void Xil_Assert(char *File, int Line) +{ + /* if the callback has been set then invoke it */ + if (Xil_AssertCallbackRoutine != 0) { + (*Xil_AssertCallbackRoutine)(File, Line); + } + + /* if specified, wait indefinitely such that the assert will show up + * in testing + */ + while (Xil_AssertWait) { + } +} + +/*****************************************************************************/ +/** +* +* Set up a callback function to be invoked when an assert occurs. If there +* was already a callback installed, then it is replaced. +* +* @param routine is the callback to be invoked when an assert is taken +* +* @return None. +* +* @note This function has no effect if NDEBUG is set +* +******************************************************************************/ +void Xil_AssertSetCallback(Xil_AssertCallback Routine) +{ + Xil_AssertCallbackRoutine = Routine; +} + + Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xil_assert.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xil_assert.h 2014-07-20 22:06:38.965262684 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/****************************************************************************** +* +* (c) Copyright 2009 Xilinx, Inc. All rights reserved. +* 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. +* +* 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 +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xil_assert.h +* +* This file contains assert related functions. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a hbm 07/14/09 First release +* </pre> +* +******************************************************************************/ + +#ifndef XIL_ASSERT_H /* prevent circular inclusions */ +#define XIL_ASSERT_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + + +/************************** Constant Definitions *****************************/ + +#define XIL_ASSERT_NONE 0 +#define XIL_ASSERT_OCCURRED 1 + +extern unsigned int Xil_AssertStatus; +extern void Xil_Assert(char *, int); + + +/** + * This data type defines a callback to be invoked when an + * assert occurs. The callback is invoked only when asserts are enabled + */ +typedef void (*Xil_AssertCallback) (char *File, int Line); + +/***************** Macros (Inline Functions) Definitions *********************/ + +#ifndef NDEBUG + +/*****************************************************************************/ +/** +* This assert macro is to be used for functions that do not return anything +* (void). This in conjunction with the Xil_AssertWait boolean can be used to +* accomodate tests so that asserts which fail allow execution to continue. +* +* @param expression is the expression to evaluate. If it evaluates to +* false, the assert occurs. +* +* @return Returns void unless the Xil_AssertWait variable is true, in which +* case no return is made and an infinite loop is entered. +* +* @note None. +* +******************************************************************************/ +#define Xil_AssertVoid(Expression) \ +{ \ + if (Expression) { \ + Xil_AssertStatus = XIL_ASSERT_NONE; \ + } else { \ + Xil_Assert(__FILE__, __LINE__); \ + Xil_AssertStatus = XIL_ASSERT_OCCURRED; \ + return; \ + } \ +} + +/*****************************************************************************/ +/** +* This assert macro is to be used for functions that do return a value. This in +* conjunction with the Xil_AssertWait boolean can be used to accomodate tests +* so that asserts which fail allow execution to continue. +* +* @param expression is the expression to evaluate. If it evaluates to false, +* the assert occurs. +* +* @return Returns 0 unless the Xil_AssertWait variable is true, in which +* case no return is made and an infinite loop is entered. +* +* @note None. +* +******************************************************************************/ +#define Xil_AssertNonvoid(Expression) \ +{ \ + if (Expression) { \ + Xil_AssertStatus = XIL_ASSERT_NONE; \ + } else { \ + Xil_Assert(__FILE__, __LINE__); \ + Xil_AssertStatus = XIL_ASSERT_OCCURRED; \ + return 0; \ + } \ +} + +/*****************************************************************************/ +/** +* Always assert. This assert macro is to be used for functions that do not +* return anything (void). Use for instances where an assert should always +* occur. +* +* @return Returns void unless the Xil_AssertWait variable is true, in which +* case no return is made and an infinite loop is entered. +* +* @note None. +* +******************************************************************************/ +#define Xil_AssertVoidAlways() \ +{ \ + Xil_Assert(__FILE__, __LINE__); \ + Xil_AssertStatus = XIL_ASSERT_OCCURRED; \ + return; \ +} + +/*****************************************************************************/ +/** +* Always assert. This assert macro is to be used for functions that do return +* a value. Use for instances where an assert should always occur. +* +* @return Returns void unless the Xil_AssertWait variable is true, in which +* case no return is made and an infinite loop is entered. +* +* @note None. +* +******************************************************************************/ +#define Xil_AssertNonvoidAlways() \ +{ \ + Xil_Assert(__FILE__, __LINE__); \ + Xil_AssertStatus = XIL_ASSERT_OCCURRED; \ + return 0; \ +} + + +#else + +#define Xil_AssertVoid(Expression) +#define Xil_AssertVoidAlways() +#define Xil_AssertNonvoid(Expression) +#define Xil_AssertNonvoidAlways() + +#endif + +/************************** Function Prototypes ******************************/ + +void Xil_AssertSetCallback(Xil_AssertCallback Routine); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xilinx_syms.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xilinx_syms.c 2014-07-20 22:06:38.972262568 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * xilinx_syms.c + * + * This file EXPORT_SYMBOL_GPL's all of the Xilinx entry points. + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under the terms + * of the GNU General Public License version 2. This program is licensed + * "as is" without any warranty of any kind, whether express or implied. + */ + +#include <linux/module.h> + +#include "xbasic_types.h" +EXPORT_SYMBOL_GPL(XAssert); +EXPORT_SYMBOL_GPL(XAssertSetCallback); +EXPORT_SYMBOL_GPL(XAssertStatus); +extern u32 XWaitInAssert; +EXPORT_SYMBOL_GPL(XWaitInAssert); + +#include "xdma_channel.h" +EXPORT_SYMBOL_GPL(XDmaChannel_CommitPuts); +EXPORT_SYMBOL_GPL(XDmaChannel_CreateSgList); +EXPORT_SYMBOL_GPL(XDmaChannel_DecrementPktCount); +EXPORT_SYMBOL_GPL(XDmaChannel_GetControl); +EXPORT_SYMBOL_GPL(XDmaChannel_GetDescriptor); +EXPORT_SYMBOL_GPL(XDmaChannel_GetIntrEnable); +EXPORT_SYMBOL_GPL(XDmaChannel_GetIntrStatus); +EXPORT_SYMBOL_GPL(XDmaChannel_GetPktCount); +EXPORT_SYMBOL_GPL(XDmaChannel_GetPktThreshold); +EXPORT_SYMBOL_GPL(XDmaChannel_GetPktWaitBound); +EXPORT_SYMBOL_GPL(XDmaChannel_GetStatus); +EXPORT_SYMBOL_GPL(XDmaChannel_GetVersion); +EXPORT_SYMBOL_GPL(XDmaChannel_Initialize); +EXPORT_SYMBOL_GPL(XDmaChannel_IsReady); +EXPORT_SYMBOL_GPL(XDmaChannel_IsSgListEmpty); +EXPORT_SYMBOL_GPL(XDmaChannel_PutDescriptor); +EXPORT_SYMBOL_GPL(XDmaChannel_Reset); +EXPORT_SYMBOL_GPL(XDmaChannel_SelfTest); +EXPORT_SYMBOL_GPL(XDmaChannel_SetControl); +EXPORT_SYMBOL_GPL(XDmaChannel_SetIntrEnable); +EXPORT_SYMBOL_GPL(XDmaChannel_SetIntrStatus); +EXPORT_SYMBOL_GPL(XDmaChannel_SetPktThreshold); +EXPORT_SYMBOL_GPL(XDmaChannel_SetPktWaitBound); +EXPORT_SYMBOL_GPL(XDmaChannel_SgStart); +EXPORT_SYMBOL_GPL(XDmaChannel_SgStop); +EXPORT_SYMBOL_GPL(XDmaChannel_Transfer); + +#include "xipif_v1_23_b.h" +//EXPORT_SYMBOL_GPL(XIpIfV123b_SelfTest); + +#include "xpacket_fifo_v2_00_a.h" +EXPORT_SYMBOL_GPL(XPacketFifoV200a_Initialize); +EXPORT_SYMBOL_GPL(XPacketFifoV200a_Read); +EXPORT_SYMBOL_GPL(XPacketFifoV200a_SelfTest); +EXPORT_SYMBOL_GPL(XPacketFifoV200a_Write); + +#include "xio.h" +EXPORT_SYMBOL_GPL(XIo_Out8); +EXPORT_SYMBOL_GPL(XIo_In8); +EXPORT_SYMBOL_GPL(XIo_Out16); +EXPORT_SYMBOL_GPL(XIo_In16); +EXPORT_SYMBOL_GPL(XIo_Out32); +EXPORT_SYMBOL_GPL(XIo_In32); + +#include "xversion.h" +EXPORT_SYMBOL_GPL(XVersion_Copy); +EXPORT_SYMBOL_GPL(XVersion_FromString); +EXPORT_SYMBOL_GPL(XVersion_IsEqual); +EXPORT_SYMBOL_GPL(XVersion_Pack); +EXPORT_SYMBOL_GPL(XVersion_ToString); +EXPORT_SYMBOL_GPL(XVersion_UnPack); Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xil_io.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xil_io.h 2014-07-20 22:06:38.978262469 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/****************************************************************************** +* +* (c) Copyright 2009 Xilinx, Inc. All rights reserved. +* 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. +* +* 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 +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xil_io.h +* +* This file contains IO functions for Xilinx OCP in terms of Linux primitives. +* +******************************************************************************/ +#ifndef XIL_IO_H +#define XIL_IO_H + +#include "xil_types.h" +#include <asm/io.h> + +extern inline u8 +Xil_In8(u32 InAddress) +{ + return (u8) in_8((volatile unsigned char *) InAddress); +} +extern inline u16 +Xil_In16(u32 InAddress) +{ + return (u16) in_be16((volatile unsigned short *) InAddress); +} +extern inline u32 +Xil_In32(u32 InAddress) +{ + return (u32) in_be32((volatile unsigned *) InAddress); +} +extern inline void +Xil_Out8(u32 OutAddress, u8 Value) +{ + out_8((volatile unsigned char *) OutAddress, Value); +} +extern inline void +Xil_Out16(u32 OutAddress, u16 Value) +{ + out_be16((volatile unsigned short *) OutAddress, Value); +} +extern inline void +Xil_Out32(u32 OutAddress, u32 Value) +{ + out_be32((volatile unsigned *) OutAddress, Value); +} +extern inline u16 +Xil_In16LE(u32 Addr) +{ + u16 Value; + + __asm__ volatile ("eieio; lhbrx %0,0,%1":"=r" (Value):"b" (Addr)); + return Value; +} +extern inline u32 +Xil_In32LE(u32 Addr) +{ + u32 Value; + + __asm__ volatile ("eieio; lwbrx %0,0,%1":"=r" (Value):"b" (Addr)); + return Value; +} +extern inline void +Xil_Out16LE(u32 Addr, u16 Value) +{ + __asm__ volatile ("sthbrx %0,0,%1; eieio"::"r" (Value), "b"(Addr)); +} +extern inline void +Xil_Out32LE(u32 Addr, u32 Value) +{ + __asm__ volatile ("stwbrx %0,0,%1; eieio"::"r" (Value), "b"(Addr)); +} + +#endif /* XIL_IO_H */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xil_types.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xil_types.h 2014-07-20 22:06:38.986262337 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/****************************************************************************** +* +* (c) Copyright 2009 Xilinx, Inc. All rights reserved. +* 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. +* +* 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 +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xil_types.h +* +* This file contains basic types for Xilinx software IP. + +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a hbm 07/14/09 First release +* </pre> +* +******************************************************************************/ + +#ifndef XIL_TYPES_H /* prevent circular inclusions */ +#define XIL_TYPES_H /* by using protection macros */ + + +/************************** Constant Definitions *****************************/ + +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define XIL_COMPONENT_IS_READY 0x11111111 /**< component has been initialized */ +#define XIL_COMPONENT_IS_STARTED 0x22222222 /**< component has been started */ + +/** @name New types + * New simple types. + * @{ + */ +#ifndef __KERNEL__ +#ifndef XBASIC_TYPES_H +/** + * guarded against xbasic_types.h. + */ +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +#endif +/** + * xbasic_types.h does not typedef u64 + */ +typedef unsigned long long u64; +#else +#include <linux/types.h> +#endif + + +/*@}*/ + + +/************************** Constant Definitions *****************************/ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xio.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xio.c 2014-07-20 22:06:38.996262172 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xio.c,v 1.5 2007/07/24 22:01:35 xduan Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xio.c +* +* Contains I/O functions for memory-mapped or non-memory-mapped I/O +* architectures. These functions encapsulate PowerPC architecture-specific +* I/O requirements. +* +* @note +* +* This file contains architecture-dependent code. +* +* The order of the SYNCHRONIZE_IO and the read or write operation is +* important. For the Read operation, all I/O needs to complete prior +* to the desired read to insure valid data from the address. The PPC +* is a weakly ordered I/O model and reads can and will occur prior +* to writes and the SYNCHRONIZE_IO ensures that any writes occur prior +* to the read. For the Write operation the SYNCHRONIZE_IO occurs +* after the desired write to ensure that the address is updated with +* the new value prior to any subsequent read. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- -------------------------------------------------------- +* 1.00a ecm 10/18/05 initial release +* needs to be updated to replace eieio with mbar when +* compilers support this mnemonic. +* +* 1.00a ecm 01/24/07 update for new coding standard. +* 1.10a xd 07/24/07 Corrected the format in asm functions in __DCC__ mode. +* </pre> +******************************************************************************/ + + +/***************************** Include Files *********************************/ +#include "xio.h" +#include "xbasic_types.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +/*****************************************************************************/ +/** +* +* Performs a 16-bit endian converion. +* +* @param Source contains the value to be converted. +* @param DestPtr contains a pointer to the location to put the +* converted value. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void OutSwap16(u16 Source, u16 *DestPtr) +{ + *DestPtr = (u16) (((Source & 0xFF00) >> 8) | ((Source & 0x00FF) << 8)); +} + +u16 InSwap16(u16 *DestPtr) +{ + u16 Source = *DestPtr; + return (u16) (((Source & 0xFF00) >> 8) | ((Source & 0x00FF) << 8)); +} +/*****************************************************************************/ +/** +* +* Performs a 32-bit endian converion. +* +* @param Source contains the value to be converted. +* @param DestPtr contains a pointer to the location to put the +* converted value. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void OutSwap32(u32 Source, u32 *DestPtr) +{ + + /* get each of the half words from the 32 bit word */ + + u16 LoWord = (u16) (Source & 0x0000FFFF); + u16 HiWord = (u16) ((Source & 0xFFFF0000) >> 16); + + /* byte swap each of the 16 bit half words */ + + LoWord = (((LoWord & 0xFF00) >> 8) | ((LoWord & 0x00FF) << 8)); + HiWord = (((HiWord & 0xFF00) >> 8) | ((HiWord & 0x00FF) << 8)); + + /* swap the half words before returning the value */ + + *DestPtr = (u32) ((LoWord << 16) | HiWord); +} + +u32 InSwap32(u32 *DestPtr) +{ + /* get each of the half words from the 32 bit word */ + u32 Source = *DestPtr; + + u16 LoWord = (u16) (Source & 0x0000FFFF); + u16 HiWord = (u16) ((Source & 0xFFFF0000) >> 16); + + /* byte swap each of the 16 bit half words */ + + LoWord = (((LoWord & 0xFF00) >> 8) | ((LoWord & 0x00FF) << 8)); + HiWord = (((HiWord & 0xFF00) >> 8) | ((HiWord & 0x00FF) << 8)); + + /* swap the half words before returning the value */ + + return (u32) ((LoWord << 16) | HiWord); +} + +/*****************************************************************************/ +/** +* +* Performs an input operation for an 8-bit memory location by reading from the +* specified address and returning the value read from that address. +* +* @param InAddress contains the address to perform the input operation at. +* +* @return +* +* The value read from the specified input address. +* +* @note +* +* None. +* +******************************************************************************/ + u8 XIo_In8(XIo_Address InAddress) +{ + /* read the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ + +#if defined CONFIG_PPC + + u8 IoContents; + __asm__ volatile ("eieio; lbz %0,0(%1)":"=r" (IoContents):"b" + (InAddress)); + return IoContents; + +#else + + SYNCHRONIZE_IO; + return *(u8 *) InAddress; + +#endif + +} + +/*****************************************************************************/ +/** +* +* Performs an input operation for a 16-bit memory location by reading from the +* specified address and returning the value read from that address. +* +* @param InAddress contains the address to perform the input operation at. +* +* @return +* +* The value read from the specified input address. +* +* @note +* +* None. +* +******************************************************************************/ +u16 XIo_In16(XIo_Address InAddress) +{ + /* read the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ + +#if defined CONFIG_PPC + + u16 IoContents; + __asm__ volatile ("eieio; lhz %0,0(%1)":"=r" (IoContents):"b" + (InAddress)); + return IoContents; + +#else + + SYNCHRONIZE_IO; + return *(u16 *) InAddress; + +#endif +} + +/*****************************************************************************/ +/** +* +* Performs an input operation for a 32-bit memory location by reading from the +* specified address and returning the value read from that address. +* +* @param InAddress contains the address to perform the input operation at. +* +* @return +* +* The value read from the specified input address. +* +* @note +* +* None. +* +******************************************************************************/ +u32 XIo_In32(XIo_Address InAddress) +{ + /* read the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ + +#ifdef CONFIG_PPC + + u32 IoContents; + __asm__ volatile ("eieio; lwz %0,0(%1)":"=r" (IoContents):"b" + (InAddress)); + return IoContents; + +#else + + SYNCHRONIZE_IO; + return *(u32 *) InAddress; + +#endif + +} + +/*****************************************************************************/ +/** +* +* Performs an input operation for a 16-bit memory location by reading from the +* specified address and returning the byte-swapped value read from that +* address. +* +* @param InAddress contains the address to perform the input operation at. +* +* @return +* +* The byte-swapped value read from the specified input address. +* +* @note +* +* None. +* +******************************************************************************/ +u16 XIo_InSwap16(XIo_Address InAddress) +{ + /* read the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ +#ifdef CONFIG_PPC + u16 IoContents; + + __asm__ volatile ("eieio; lhbrx %0,0,%1":"=r" (IoContents):"b" + (InAddress)); + return IoContents; +#else + return InSwap16(InAddress); +#endif +} + +/*****************************************************************************/ +/** +* +* Performs an input operation for a 32-bit memory location by reading from the +* specified address and returning the byte-swapped value read from that +* address. +* +* @param InAddress contains the address to perform the input operation at. +* +* @return +* +* The byte-swapped value read from the specified input address. +* +* @note +* +* None. +* +******************************************************************************/ +u32 XIo_InSwap32(XIo_Address InAddress) +{ + /* read the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ +#ifdef CONFIG_PPC + u32 IoContents; + + __asm__ volatile ("eieio; lwbrx %0,0,%1":"=r" (IoContents):"b" + (InAddress)); + return IoContents; +#else + return InSwap32(InAddress); +#endif + +} + + +/*****************************************************************************/ +/** +* +* Performs an output operation for an 8-bit memory location by writing the +* specified value to the the specified address. +* +* @param OutAddress contains the address to perform the output operation at. +* @param Value contains the value to be output at the specified address. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XIo_Out8(XIo_Address OutAddress, u8 Value) +{ + /* write the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ + +#ifdef CONFIG_PPC + + __asm__ volatile ("stb %0,0(%1); eieio"::"r" (Value), "b"(OutAddress)); + +#else + + *(volatile u8 *) OutAddress = Value; + SYNCHRONIZE_IO; + +#endif + +} + +/*****************************************************************************/ +/** +* +* Performs an output operation for a 16-bit memory location by writing the +* specified value to the the specified address. +* +* @param OutAddress contains the address to perform the output operation at. +* @param Value contains the value to be output at the specified address. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XIo_Out16(XIo_Address OutAddress, u16 Value) +{ + /* write the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ + +#ifdef CONFIG_PPC + + __asm__ volatile ("sth %0,0(%1); eieio"::"r" (Value), "b"(OutAddress)); + +#else + + *(volatile u16 *) OutAddress = Value; + SYNCHRONIZE_IO; + +#endif +} + +/*****************************************************************************/ +/** +* +* Performs an output operation for a 32-bit memory location by writing the +* specified value to the the specified address. +* +* @param OutAddress contains the address to perform the output operation at. +* @param Value contains the value to be output at the specified address. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XIo_Out32(XIo_Address OutAddress, u32 Value) +{ + /* write the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ + +#ifdef CONFIG_PPC + + __asm__ volatile ("stw %0,0(%1); eieio"::"r" (Value), "b"(OutAddress)); + +#else + + *(volatile u32 *) OutAddress = Value; + SYNCHRONIZE_IO; + +#endif +} + +/*****************************************************************************/ +/** +* +* Performs an output operation for a 16-bit memory location by writing the +* specified value to the the specified address. The value is byte-swapped +* before being written. +* +* @param OutAddress contains the address to perform the output operation at. +* @param Value contains the value to be output at the specified address. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XIo_OutSwap16(XIo_Address OutAddress, u16 Value) +{ + /* write the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ +#ifdef CONFIG_PPC + __asm__ volatile ("sthbrx %0,0,%1; eieio"::"r" (Value), + "b"(OutAddress)); +#else + OutSwap16(OutAddress, Value); +#endif +} + +/*****************************************************************************/ +/** +* +* Performs an output operation for a 32-bit memory location by writing the +* specified value to the the specified address. The value is byte-swapped +* before being written. +* +* @param OutAddress contains the address to perform the output operation at. +* @param Value contains the value to be output at the specified address. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XIo_OutSwap32(XIo_Address OutAddress, u32 Value) +{ + /* write the contents of the I/O location and then synchronize the I/O + * such that the I/O operation completes before proceeding on + */ +#ifdef CONFIG_PPC + __asm__ volatile ("stwbrx %0,0,%1; eieio"::"r" (Value), + "b"(OutAddress)); +#else + OutSwap32(OutAddress, Value); +#endif +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xio_dcr.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xio_dcr.c 2014-07-20 22:06:39.008261975 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xio_dcr.c,v 1.9 2007/01/24 17:00:16 meinelte Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xio_dcr.c +* +* The implementation of the XDcrIo interface. See xio_dcr.h for more +* information about the component. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a ecm 11/09/06 Modified from the PPC405 version to use the indirect +* addressing that is available in the PPC440 block in V5. +* Removed the jump table structure in xio_dcr.c also. +* Added functionality from the SEG driver to allow for +* one file pair. +* 1.00a ecm 01/02/07 Incorporated changes from testing with multiple DCR +* masters, discovered and fixed several concurrency +* issues. +* 1.00a ecm 01/24/07 update for new coding standard. +* </pre> +* +* @internal +* +* The C functions which subsequently call into either the assembly code or into +* the provided table of functions are required since the registers assigned to +* the calling and return from functions are strictly defined in the ABI and that +* definition is used in the low-level functions directly. The use of macros is +* not recommended since the temporary registers in the ABI are defined but there +* is no way to force the compiler to use a specific register in a block of code. +* +*****************************************************************************/ + +/***************************** Include Files ********************************/ + +#include <asm/dcr.h> +#include <asm/reg.h> + +#include "xstatus.h" +#include "xbasic_types.h" +#include "xio.h" +#include "xio_dcr.h" + +/************************** Constant Definitions ****************************/ + +/* + * base address defines for each of the four possible DCR base + * addresses a processor can have + */ +#define XDCR_0_BASEADDR 0x000 +#define XDCR_1_BASEADDR 0x100 +#define XDCR_2_BASEADDR 0x200 +#define XDCR_3_BASEADDR 0x300 + + +#define MAX_DCR_REGISTERS 4096 +#define MAX_DCR_REGISTER MAX_DCR_REGISTERS - 1 +#define MIN_DCR_REGISTER 0 + +/**************************** Type Definitions ******************************/ + + +/***************** Macros (Inline Functions) Definitions ********************/ + +/************************** Variable Definitions ****************************/ + + + +/************************** Function Prototypes *****************************/ + +/*****************************************************************************/ +/** +* +* Outputs value provided to specified register defined in the header file. +* +* @param DcrRegister is the intended destination DCR register +* @param Data is the value to be placed into the specified DCR register +* +* @return +* +* None. +* +* @note +* +* None. +* +****************************************************************************/ +void XIo_DcrOut(u32 DcrRegister, u32 Data) +{ + /* + * Assert validates the register number + */ + XASSERT_VOID(DcrRegister < MAX_DCR_REGISTERS); + + /* + * pass the call on to the proper function + */ + XIo_mDcrIndirectAddrWriteReg(XDCR_0_BASEADDR, DcrRegister, Data); +} + +/*****************************************************************************/ +/** +* +* Reads value from specified register. +* +* @param DcrRegister is the intended source DCR register +* +* @return +* +* Contents of the specified DCR register. +* +* @note +* +* None. +* +****************************************************************************/ +u32 XIo_DcrIn(u32 DcrRegister) +{ + /* + * Assert validates the register number + */ + XASSERT_NONVOID(DcrRegister < MAX_DCR_REGISTERS); + + /* + * pass the call on to the proper function + */ + return (XIo_mDcrIndirectAddrReadReg(XDCR_0_BASEADDR, DcrRegister)); +} + +/*****************************************************************************/ +/** +* +* Reads the value of the specified register using the indirect access method. +* +* @param DcrBase is the base of the block of DCR registers +* @param DcrRegister is the intended destination DCR register +* +* @return +* +* Contents of the specified DCR register. +* +* @note +* +* Uses the indirect addressing method available in V5 with PPC440. +* +****************************************************************************/ +u32 XIo_DcrReadReg(u32 DcrBase, u32 DcrRegister) +{ + switch (DcrBase) { + case 0x000: + return XIo_mDcrIndirectAddrReadReg(XDCR_0_BASEADDR, + DcrRegister); + case 0x100: + return XIo_mDcrIndirectAddrReadReg(XDCR_1_BASEADDR, + DcrRegister); + case 0x200: + return XIo_mDcrIndirectAddrReadReg(XDCR_2_BASEADDR, + DcrRegister); + case 0x300: + return XIo_mDcrIndirectAddrReadReg(XDCR_3_BASEADDR, + DcrRegister); + default: + return XIo_mDcrIndirectAddrReadReg(XDCR_0_BASEADDR, + DcrRegister); + } +} + +/*****************************************************************************/ +/** +* +* Writes the value to the specified register using the indirect access method. +* +* @param DcrBase is the base of the block of DCR registers +* @param DcrRegister is the intended destination DCR register +* @param Data is the value to be placed into the specified DCR register +* +* @return +* +* None +* +* @note +* +* Uses the indirect addressing method available in V5 with PPC440. +* +****************************************************************************/ +void XIo_DcrWriteReg(u32 DcrBase, u32 DcrRegister, u32 Data) +{ + switch (DcrBase) { + case 0x000: + XIo_mDcrIndirectAddrWriteReg(XDCR_0_BASEADDR, DcrRegister, + Data); + return; + case 0x100: + XIo_mDcrIndirectAddrWriteReg(XDCR_1_BASEADDR, DcrRegister, + Data); + return; + case 0x200: + XIo_mDcrIndirectAddrWriteReg(XDCR_2_BASEADDR, DcrRegister, + Data); + return; + case 0x300: + XIo_mDcrIndirectAddrWriteReg(XDCR_3_BASEADDR, DcrRegister, + Data); + return; + default: + XIo_mDcrIndirectAddrWriteReg(XDCR_0_BASEADDR, DcrRegister, + Data); + return; + } +} + +/*****************************************************************************/ +/** +* +* Explicitly acquires and release DCR lock--Auto-Lock is disabled. +* Reads the value of the specified register using the indirect access method. +* This function is provided because the most common usecase is to enable +* Auto-Lock. Checking for Auto-Lock in every indirect access would defeat the +* purpose of having Auto-Lock. +* Auto-Lock can only be enable/disabled in hardware. +* +* @param DcrBase is the base of the block of DCR registers +* @param DcrRegister is the intended destination DCR register +* +* @return +* +* Contents of the specified DCR register. +* +* @note +* +* Uses the indirect addressing method available in V5 with PPC440. +* +****************************************************************************/ +u32 XIo_DcrLockAndReadReg(u32 DcrBase, u32 DcrRegister) +{ + unsigned int rVal; + + switch (DcrBase) { + case 0x000: + XIo_mDcrLock(XDCR_0_BASEADDR); + rVal = XIo_mDcrIndirectAddrReadReg(XDCR_0_BASEADDR, + DcrRegister); + XIo_mDcrUnlock(XDCR_0_BASEADDR); + case 0x100: + XIo_mDcrLock(XDCR_1_BASEADDR); + rVal = XIo_mDcrIndirectAddrReadReg(XDCR_1_BASEADDR, + DcrRegister); + XIo_mDcrUnlock(XDCR_1_BASEADDR); + case 0x200: + XIo_mDcrLock(XDCR_2_BASEADDR); + rVal = XIo_mDcrIndirectAddrReadReg(XDCR_2_BASEADDR, + DcrRegister); + XIo_mDcrUnlock(XDCR_2_BASEADDR); + case 0x300: + XIo_mDcrLock(XDCR_3_BASEADDR); + rVal = XIo_mDcrIndirectAddrReadReg(XDCR_3_BASEADDR, + DcrRegister); + XIo_mDcrUnlock(XDCR_3_BASEADDR); + default: + XIo_mDcrLock(XDCR_0_BASEADDR); + rVal = XIo_mDcrIndirectAddrReadReg(XDCR_0_BASEADDR, + DcrRegister); + XIo_mDcrUnlock(XDCR_0_BASEADDR); + } + return rVal; +} + +/*****************************************************************************/ +/** +* +* Explicitly acquires and release DCR lock--Auto-Lock is disabled. +* Writes the value to the specified register using the indirect access method. +* This function is provided because the most common usecase is to enable +* Auto-Lock. Checking for Auto-Lock in every indirect access would defeat the +* purpose of having Auto-Lock. +* Auto-Lock can only be enable/disabled in hardware. +* +* @param DcrBase is the base of the block of DCR registers +* @param DcrRegister is the intended destination DCR register +* @param Data is the value to be placed into the specified DCR register +* +* @return +* +* None +* +* @note +* +* Uses the indirect addressing method available in V5 with PPC440. +* +****************************************************************************/ +void XIo_DcrLockAndWriteReg(u32 DcrBase, u32 DcrRegister, u32 Data) +{ + switch (DcrBase) { + case 0x000: + XIo_mDcrLock(XDCR_0_BASEADDR); + XIo_mDcrIndirectAddrWriteReg(XDCR_0_BASEADDR, DcrRegister, + Data); + XIo_mDcrUnlock(XDCR_0_BASEADDR); + return; + case 0x100: + XIo_mDcrLock(XDCR_1_BASEADDR); + XIo_mDcrIndirectAddrWriteReg(XDCR_1_BASEADDR, DcrRegister, + Data); + XIo_mDcrUnlock(XDCR_1_BASEADDR); + return; + case 0x200: + XIo_mDcrLock(XDCR_2_BASEADDR); + XIo_mDcrIndirectAddrWriteReg(XDCR_2_BASEADDR, DcrRegister, + Data); + XIo_mDcrUnlock(XDCR_2_BASEADDR); + return; + case 0x300: + XIo_mDcrLock(XDCR_3_BASEADDR); + XIo_mDcrIndirectAddrWriteReg(XDCR_3_BASEADDR, DcrRegister, + Data); + XIo_mDcrUnlock(XDCR_3_BASEADDR); + return; + default: + XIo_mDcrLock(XDCR_0_BASEADDR); + XIo_mDcrIndirectAddrWriteReg(XDCR_0_BASEADDR, DcrRegister, + Data); + XIo_mDcrUnlock(XDCR_0_BASEADDR); + return; + } +} + +/*****************************************************************************/ +/** +* +* Read APU UDI DCR via indirect addressing. +* +* @param DcrBase is the base of the block of DCR registers +* @param UDInum is the desired APU UDI register +* +* @return +* +* Contents of the specified APU register. +* +* @note +* +* Uses the indirect addressing method available in V5 with PPC440. +* +****************************************************************************/ +u32 XIo_DcrReadAPUUDIReg(u32 DcrBase, short UDInum) +{ + switch (DcrBase) { + case 0x000: + return XIo_mDcrIndirectAddrReadAPUUDIReg(XDCR_0_BASEADDR, + UDInum); + case 0x100: + return XIo_mDcrIndirectAddrReadAPUUDIReg(XDCR_1_BASEADDR, + UDInum); + case 0x200: + return XIo_mDcrIndirectAddrReadAPUUDIReg(XDCR_2_BASEADDR, + UDInum); + case 0x300: + return XIo_mDcrIndirectAddrReadAPUUDIReg(XDCR_3_BASEADDR, + UDInum); + default: + return XIo_mDcrIndirectAddrReadAPUUDIReg(XDCR_0_BASEADDR, + UDInum); + } +} + +/*****************************************************************************/ +/** +* +* Writes the value to the APU UDI DCR using the indirect access method. +* +* @param DcrBase is the base of the block of DCR registers +* @param UDInum is the intended destination APU register +* @param Data is the value to be placed into the specified APU register +* +* @return +* +* None +* +* @note +* +* Uses the indirect addressing method available in V5 with PPC440. +* +****************************************************************************/ +void XIo_DcrWriteAPUUDIReg(u32 DcrBase, short UDInum, u32 Data) +{ + switch (DcrBase) { + case 0x000: + XIo_mDcrIndirectAddrWriteAPUUDIReg(XDCR_0_BASEADDR, UDInum, + Data); + return; + case 0x100: + XIo_mDcrIndirectAddrWriteAPUUDIReg(XDCR_1_BASEADDR, UDInum, + Data); + return; + case 0x200: + XIo_mDcrIndirectAddrWriteAPUUDIReg(XDCR_2_BASEADDR, UDInum, + Data); + return; + case 0x300: + XIo_mDcrIndirectAddrWriteAPUUDIReg(XDCR_3_BASEADDR, UDInum, + Data); + return; + default: + XIo_mDcrIndirectAddrWriteAPUUDIReg(XDCR_0_BASEADDR, UDInum, + Data); + return; + } +} + +/*****************************************************************************/ +/** +* +* Locks DCR bus via the Global Status/Control register. +* +* @param DcrBase is the base of the block of DCR registers +* +* @return +* +* None +* +* @note +* +* Care must be taken to not write a '1' to either timeout bit because +* it will be cleared. The internal PPC440 can clear both timeout bits but an +* external DCR master can only clear the external DCR master's timeout bit. +* +* Only available in V5 with PPC440. +* +****************************************************************************/ +void XIo_DcrLock(u32 DcrBase) +{ + switch (DcrBase) { + case 0x000: + XIo_mDcrLock(XDCR_0_BASEADDR); + return; + case 0x100: + XIo_mDcrLock(XDCR_1_BASEADDR); + return; + case 0x200: + XIo_mDcrLock(XDCR_2_BASEADDR); + return; + case 0x300: + XIo_mDcrLock(XDCR_3_BASEADDR); + return; + default: + XIo_mDcrLock(XDCR_0_BASEADDR); + return; + } +} + +/*****************************************************************************/ +/** +* +* Unlocks DCR bus via the Global Status/Control register. +* +* @param DcrBase is the base of the block of DCR registers +* +* @return +* +* None +* +* @note +* +* Care must be taken to not write a '1' to either timeout bit because +* it will be cleared. The internal PPC440 can clear both timeout bits but an +* external DCR master can only clear the external DCR master's timeout bit. +* +* Only available in V5 with PPC440. +* +****************************************************************************/ +void XIo_DcrUnlock(u32 DcrBase) +{ + switch (DcrBase) { + case 0x000: + XIo_mDcrUnlock(XDCR_0_BASEADDR); + return; + case 0x100: + XIo_mDcrUnlock(XDCR_1_BASEADDR); + return; + case 0x200: + XIo_mDcrUnlock(XDCR_2_BASEADDR); + return; + case 0x300: + XIo_mDcrUnlock(XDCR_3_BASEADDR); + return; + default: + XIo_mDcrUnlock(XDCR_0_BASEADDR); + return; + } +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xio_dcr.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xio_dcr.h 2014-07-20 22:06:39.021261760 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xio_dcr.h,v 1.8 2007/01/24 17:00:16 meinelte Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xio_dcr.h +* +* The DCR I/O access functions. +* +* @note +* +* These access functions are specific to the PPC440 CPU. Changes might be +* necessary for other members of the IBM PPC Family. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a ecm 10/18/05 First release +* Need to verify opcodes for mt/mfdcr remain the same. +* 1.00a ecm 11/09/06 Modified from the PPC405 version to use the indirect +* addressing that is available in the PPC440 block in V5. +* Removed the jump table structure in xio_dcr.c also. +* Added functionality from the SEG driver to allow for +* one file pair. +* 1.00a ecm 01/02/07 Incorporated changes from testing with multiple DCR +* masters, discovered and fixed several concurrency +* issues. +* 1.00a ecm 01/24/07 update for new coding standard. +* </pre> +* +* @internal +* +* This code WILL NOT FUNCTION on the PPC405 based architectures, V2P and V4. +* +******************************************************************************/ + +#ifndef XDCRIO_H /* prevent circular inclusions */ +#define XDCRIO_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ +#include "xbasic_types.h" + +/************************** Constant Definitions *****************************/ +/* + * 256 internal DCR registers + * Base address: 2 most signifcant bits of 10-bit addr taken from + * the C_DCRBASEADDR parameter of the processor block. + * Offset: 8 least significant bits + */ +/* register base addresses */ + +#define XDCR_APU_BASE 0x04 +#define XDCR_MIB_BASE 0x10 +#define XDCR_XB_BASE 0x20 +#define XDCR_PLBS0_BASE 0x34 +#define XDCR_PLBS1_BASE 0x44 +#define XDCR_PLBM_BASE 0x54 +#define XDCR_DMA0_BASE 0x80 +#define XDCR_DMA1_BASE 0x98 +#define XDCR_DMA2_BASE 0xB0 +#define XDCR_DMA3_BASE 0xC8 + +/* register offsets */ +/* global registers 0x00-0x02 */ + +#define XDCR_IDA_ADDR 0x00 +#define XDCR_IDA_ACC 0x01 +#define XDCR_CTRLCFGSTAT 0x02 + +/* Auxiliary Processor Unit Controller (APU) 0x04-0x05 */ + +#define XDCR_APU_UDI (XDCR_APU_BASE+0x00) +#define XDCR_APU_CTRL (XDCR_APU_BASE+0x01) + +/* Memory Interface Bridge (MIB) 0x10-0x13 */ + +#define XDCR_MIB_CTRL (XDCR_MIB_BASE+0x00) +#define XDCR_MIB_RCON (XDCR_MIB_BASE+0x01) +#define XDCR_MIB_BCON (XDCR_MIB_BASE+0x02) + +/* Crossbar (XB) 0x20-0x33 */ + +#define XDCR_XB_IST (XDCR_XB_BASE+0x00) +#define XDCR_XB_IMASK (XDCR_XB_BASE+0x01) +#define XDCR_XB_ARBCFGX (XDCR_XB_BASE+0x03) +#define XDCR_XB_FIFOSTX (XDCR_XB_BASE+0x04) +#define XDCR_XB_SMSTX (XDCR_XB_BASE+0x05) +#define XDCR_XB_MISCX (XDCR_XB_BASE+0x06) +#define XDCR_XB_ARBCFGM (XDCR_XB_BASE+0x08) +#define XDCR_XB_FIFOSTM (XDCR_XB_BASE+0x09) +#define XDCR_XB_SMSTM (XDCR_XB_BASE+0x0A) +#define XDCR_XB_MISCM (XDCR_XB_BASE+0x0B) +#define XDCR_XB_TMPL0MAP (XDCR_XB_BASE+0x0D) +#define XDCR_XB_TMPL1MAP (XDCR_XB_BASE+0x0E) +#define XDCR_XB_TMPL2MAP (XDCR_XB_BASE+0x0F) +#define XDCR_XB_TMPL3MAP (XDCR_XB_BASE+0x10) +#define XDCR_XB_TMPLSEL (XDCR_XB_BASE+0x11) + +/* PLB Slave DCR offsets only */ + +#define XDCR_PLBS_CFG 0x00 +#define XDCR_PLBS_SEARU 0x02 +#define XDCR_PLBS_SEARL 0x03 +#define XDCR_PLBS_SESR 0x04 +#define XDCR_PLBS_MISCST 0x05 +#define XDCR_PLBS_PLBERRST 0x06 +#define XDCR_PLBS_SMST 0x07 +#define XDCR_PLBS_MISC 0x08 +#define XDCR_PLBS_CMDSNIFF 0x09 +#define XDCR_PLBS_CMDSNIFFA 0x0A +#define XDCR_PLBS_TMPL0MAP 0x0C +#define XDCR_PLBS_TMPL1MAP 0x0D +#define XDCR_PLBS_TMPL2MAP 0x0E +#define XDCR_PLBS_TMPL3MAP 0x0F + +/* PLB Slave 0 (PLBS0) 0x34-0x43 */ + +#define XDCR_PLBS0_CFG (XDCR_PLBS0_BASE+0x00) +#define XDCR_PLBS0_CNT (XDCR_PLBS0_BASE+0x01) +#define XDCR_PLBS0_SEARU (XDCR_PLBS0_BASE+0x02) +#define XDCR_PLBS0_SEARL (XDCR_PLBS0_BASE+0x03) +#define XDCR_PLBS0_SESR (XDCR_PLBS0_BASE+0x04) +#define XDCR_PLBS0_MISCST (XDCR_PLBS0_BASE+0x05) +#define XDCR_PLBS0_PLBERRST (XDCR_PLBS0_BASE+0x06) +#define XDCR_PLBS0_SMST (XDCR_PLBS0_BASE+0x07) +#define XDCR_PLBS0_MISC (XDCR_PLBS0_BASE+0x08) +#define XDCR_PLBS0_CMDSNIFF (XDCR_PLBS0_BASE+0x09) +#define XDCR_PLBS0_CMDSNIFFA (XDCR_PLBS0_BASE+0x0A) +#define XDCR_PLBS0_TMPL0MAP (XDCR_PLBS0_BASE+0x0C) +#define XDCR_PLBS0_TMPL1MAP (XDCR_PLBS0_BASE+0x0D) +#define XDCR_PLBS0_TMPL2MAP (XDCR_PLBS0_BASE+0x0E) +#define XDCR_PLBS0_TMPL3MAP (XDCR_PLBS0_BASE+0x0F) + +/* PLB Slave 1 (PLBS1) 0x44-0x53 */ + +#define XDCR_PLBS1_CFG (XDCR_PLBS1_BASE+0x00) +#define XDCR_PLBS1_CNT (XDCR_PLBS1_BASE+0x01) +#define XDCR_PLBS1_SEARU (XDCR_PLBS1_BASE+0x02) +#define XDCR_PLBS1_SEARL (XDCR_PLBS1_BASE+0x03) +#define XDCR_PLBS1_SESR (XDCR_PLBS1_BASE+0x04) +#define XDCR_PLBS1_MISCST (XDCR_PLBS1_BASE+0x05) +#define XDCR_PLBS1_PLBERRST (XDCR_PLBS1_BASE+0x06) +#define XDCR_PLBS1_SMST (XDCR_PLBS1_BASE+0x07) +#define XDCR_PLBS1_MISC (XDCR_PLBS1_BASE+0x08) +#define XDCR_PLBS1_CMDSNIFF (XDCR_PLBS1_BASE+0x09) +#define XDCR_PLBS1_CMDSNIFFA (XDCR_PLBS1_BASE+0x0A) +#define XDCR_PLBS1_TMPL0MAP (XDCR_PLBS1_BASE+0x0C) +#define XDCR_PLBS1_TMPL1MAP (XDCR_PLBS1_BASE+0x0D) +#define XDCR_PLBS1_TMPL2MAP (XDCR_PLBS1_BASE+0x0E) +#define XDCR_PLBS1_TMPL3MAP (XDCR_PLBS1_BASE+0x0F) + +/* PLB Master (PLBM) 0x54-0x5F */ + +#define XDCR_PLBM_CFG (XDCR_PLBM_BASE+0x00) +#define XDCR_PLBM_CNT (XDCR_PLBM_BASE+0x01) +#define XDCR_PLBM_FSEARU (XDCR_PLBM_BASE+0x02) +#define XDCR_PLBM_FSEARL (XDCR_PLBM_BASE+0x03) +#define XDCR_PLBM_FSESR (XDCR_PLBM_BASE+0x04) +#define XDCR_PLBM_MISCST (XDCR_PLBM_BASE+0x05) +#define XDCR_PLBM_PLBERRST (XDCR_PLBM_BASE+0x06) +#define XDCR_PLBM_SMST (XDCR_PLBM_BASE+0x07) +#define XDCR_PLBM_MISC (XDCR_PLBM_BASE+0x08) +#define XDCR_PLBM_CMDSNIFF (XDCR_PLBM_BASE+0x09) +#define XDCR_PLBM_CMDSNIFFA (XDCR_PLBM_BASE+0x0A) + +/* DMA Controller DCR offsets only */ +#define XDCR_DMA_TXNXTDESCPTR 0x00 +#define XDCR_DMA_TXCURBUFADDR 0x01 +#define XDCR_DMA_TXCURBUFLEN 0x02 +#define XDCR_DMA_TXCURDESCPTR 0x03 +#define XDCR_DMA_TXTAILDESCPTR 0x04 +#define XDCR_DMA_TXCHANNELCTRL 0x05 +#define XDCR_DMA_TXIRQ 0x06 +#define XDCR_DMA_TXSTATUS 0x07 +#define XDCR_DMA_RXNXTDESCPTR 0x08 +#define XDCR_DMA_RXCURBUFADDR 0x09 +#define XDCR_DMA_RXCURBUFLEN 0x0A +#define XDCR_DMA_RXCURDESCPTR 0x0B +#define XDCR_DMA_RXTAILDESCPTR 0x0C +#define XDCR_DMA_RXCHANNELCTRL 0x0D +#define XDCR_DMA_RXIRQ 0x0E +#define XDCR_DMA_RXSTATUS 0x0F +#define XDCR_DMA_CTRL 0x10 + +/* DMA Controller 0 (DMA0) 0x80-0x90 */ + +#define XDCR_DMA0_TXNXTDESCPTR (XDCR_DMA0_BASE+0x00) +#define XDCR_DMA0_TXCURBUFADDR (XDCR_DMA0_BASE+0x01) +#define XDCR_DMA0_TXCURBUFLEN (XDCR_DMA0_BASE+0x02) +#define XDCR_DMA0_TXCURDESCPTR (XDCR_DMA0_BASE+0x03) +#define XDCR_DMA0_TXTAILDESCPTR (XDCR_DMA0_BASE+0x04) +#define XDCR_DMA0_TXCHANNELCTRL (XDCR_DMA0_BASE+0x05) +#define XDCR_DMA0_TXIRQ (XDCR_DMA0_BASE+0x06) +#define XDCR_DMA0_TXSTATUS (XDCR_DMA0_BASE+0x07) +#define XDCR_DMA0_RXNXTDESCPTR (XDCR_DMA0_BASE+0x08) +#define XDCR_DMA0_RXCURBUFADDR (XDCR_DMA0_BASE+0x09) +#define XDCR_DMA0_RXCURBUFLEN (XDCR_DMA0_BASE+0x0A) +#define XDCR_DMA0_RXCURDESCPTR (XDCR_DMA0_BASE+0x0B) +#define XDCR_DMA0_RXTAILDESCPTR (XDCR_DMA0_BASE+0x0C) +#define XDCR_DMA0_RXCHANNELCTRL (XDCR_DMA0_BASE+0x0D) +#define XDCR_DMA0_RXIRQ (XDCR_DMA0_BASE+0x0E) +#define XDCR_DMA0_RXSTATUS (XDCR_DMA0_BASE+0x0F) +#define XDCR_DMA0_CTRL (XDCR_DMA0_BASE+0x10) + +/* DMA Controller 1 (DMA1) 0x98-0xA8 */ + +#define XDCR_DMA1_TXNXTDESCPTR (XDCR_DMA1_BASE+0x00) +#define XDCR_DMA1_TXCURBUFADDR (XDCR_DMA1_BASE+0x01) +#define XDCR_DMA1_TXCURBUFLEN (XDCR_DMA1_BASE+0x02) +#define XDCR_DMA1_TXCURDESCPTR (XDCR_DMA1_BASE+0x03) +#define XDCR_DMA1_TXTAILDESCPTR (XDCR_DMA1_BASE+0x04) +#define XDCR_DMA1_TXCHANNELCTRL (XDCR_DMA1_BASE+0x05) +#define XDCR_DMA1_TXIRQ (XDCR_DMA1_BASE+0x06) +#define XDCR_DMA1_TXSTATUS (XDCR_DMA1_BASE+0x07) +#define XDCR_DMA1_RXNXTDESCPTR (XDCR_DMA1_BASE+0x08) +#define XDCR_DMA1_RXCURBUFADDR (XDCR_DMA1_BASE+0x09) +#define XDCR_DMA1_RXCURBUFLEN (XDCR_DMA1_BASE+0x0A) +#define XDCR_DMA1_RXCURDESCPTR (XDCR_DMA1_BASE+0x0B) +#define XDCR_DMA1_RXTAILDESCPTR (XDCR_DMA1_BASE+0x0C) +#define XDCR_DMA1_RXCHANNELCTRL (XDCR_DMA1_BASE+0x0D) +#define XDCR_DMA1_RXIRQ (XDCR_DMA1_BASE+0x0E) +#define XDCR_DMA1_RXSTATUS (XDCR_DMA1_BASE+0x0F) +#define XDCR_DMA1_CTRL (XDCR_DMA1_BASE+0x10) + +/* DMA Controller 2 (DMA2) 0xB0-0xC0 */ + +#define XDCR_DMA2_TXNXTDESCPTR (XDCR_DMA2_BASE+0x00) +#define XDCR_DMA2_TXCURBUFADDR (XDCR_DMA2_BASE+0x01) +#define XDCR_DMA2_TXCURBUFLEN (XDCR_DMA2_BASE+0x02) +#define XDCR_DMA2_TXCURDESCPTR (XDCR_DMA2_BASE+0x03) +#define XDCR_DMA2_TXTAILDESCPTR (XDCR_DMA2_BASE+0x04) +#define XDCR_DMA2_TXCHANNELCTRL (XDCR_DMA2_BASE+0x05) +#define XDCR_DMA2_TXIRQ (XDCR_DMA2_BASE+0x06) +#define XDCR_DMA2_TXSTATUS (XDCR_DMA2_BASE+0x07) +#define XDCR_DMA2_RXNXTDESCPTR (XDCR_DMA2_BASE+0x08) +#define XDCR_DMA2_RXCURBUFADDR (XDCR_DMA2_BASE+0x09) +#define XDCR_DMA2_RXCURBUFLEN (XDCR_DMA2_BASE+0x0A) +#define XDCR_DMA2_RXCURDESCPTR (XDCR_DMA2_BASE+0x0B) +#define XDCR_DMA2_RXTAILDESCPTR (XDCR_DMA2_BASE+0x0C) +#define XDCR_DMA2_RXCHANNELCTRL (XDCR_DMA2_BASE+0x0D) +#define XDCR_DMA2_RXIRQ (XDCR_DMA2_BASE+0x0E) +#define XDCR_DMA2_RXSTATUS (XDCR_DMA2_BASE+0x0F) +#define XDCR_DMA2_CTRL (XDCR_DMA2_BASE+0x10) + +/* DMA Controller 3 (DMA3) 0xC8-0xD8 */ + +#define XDCR_DMA3_TXNXTDESCPTR (XDCR_DMA3_BASE+0x00) +#define XDCR_DMA3_TXCURBUFADDR (XDCR_DMA3_BASE+0x01) +#define XDCR_DMA3_TXCURBUFLEN (XDCR_DMA3_BASE+0x02) +#define XDCR_DMA3_TXCURDESCPTR (XDCR_DMA3_BASE+0x03) +#define XDCR_DMA3_TXTAILDESCPTR (XDCR_DMA3_BASE+0x04) +#define XDCR_DMA3_TXCHANNELCTRL (XDCR_DMA3_BASE+0x05) +#define XDCR_DMA3_TXIRQ (XDCR_DMA3_BASE+0x06) +#define XDCR_DMA3_TXSTATUS (XDCR_DMA3_BASE+0x07) +#define XDCR_DMA3_RXNXTDESCPTR (XDCR_DMA3_BASE+0x08) +#define XDCR_DMA3_RXCURBUFADDR (XDCR_DMA3_BASE+0x09) +#define XDCR_DMA3_RXCURBUFLEN (XDCR_DMA3_BASE+0x0A) +#define XDCR_DMA3_RXCURDESCPTR (XDCR_DMA3_BASE+0x0B) +#define XDCR_DMA3_RXTAILDESCPTR (XDCR_DMA3_BASE+0x0C) +#define XDCR_DMA3_RXCHANNELCTRL (XDCR_DMA3_BASE+0x0D) +#define XDCR_DMA3_RXIRQ (XDCR_DMA3_BASE+0x0E) +#define XDCR_DMA3_RXSTATUS (XDCR_DMA3_BASE+0x0F) +#define XDCR_DMA3_CTRL (XDCR_DMA3_BASE+0x10) + + +/** + * <pre + * These are the bit defines for the Control, Configuration, and Status + * register (XDCR_CTRLCFGSTAT) + * @{ + */ +#define XDCR_INT_MSTR_LOCK_MASK 0x80000000 /* Internal Master Bus Lock */ +#define XDCR_INT_MSTR_AUTO_LOCK_MASK 0x40000000 /* Internal Master Bus Auto Lock, RO */ +#define XDCR_EXT_MSTR_LOCK_MASK 0x20000000 /* External Master Bus Master Lock */ +#define XDCR_EXT_MSTR_AUTO_LOCK_MASK 0x10000000 /* External Master Bus Auto Lock, RO */ +#define XDCR_ENB_DCR_AUTO_LOCK_MASK 0x08000000 /* Enable Auto Bus Lock */ +#define XDCR_ENB_MSTR_ASYNC_MASK 0x04000000 /* External Master in Async Mode */ +#define XDCR_ENB_SLV_ASYNC_MASK 0x02000000 /* External Slave in Async Mode */ +#define XDCR_ENB_DCR_TIMEOUT_SUPP_MASK 0x01000000 /* Enable Timeout Support */ +#define XDCR_INT_MSTR_TIMEOUT_BIT 0x00000002 /* Internal Master Bus Timeout Occurred */ +#define XDCR_EXT_MSTR_TIMEOUT_BIT 0x00000001 /* External Master Bus Timeout Occurred */ + +/* + * Mask to disable exceptions in PPC440 MSR + * Bit 14: Critical Interrupt Enable 0x00020000 + * Bit 16: External Interrupt Enable 0x00008000 + * Bit 20: Floating-point Exceptions Mode 0 0x00000800 + * Bit 23: Floating-point Exceptions Mode 1 0x00000100 + */ +#define XDCR_DISABLE_EXCEPTIONS 0xFFFD76FF +#define XDCR_ALL_LOCK (XDCR_INT_MSTR_LOCK_MASK | XDCR_EXT_MSTR_LOCK_MASK) +#define XDCR_ALL_TIMEOUT (XDCR_INT_MSTR_TIMEOUT_BIT | XDCR_EXT_MSTR_TIMEOUT_BIT) + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/******************************************************************************/ +/** +* Reads the register at the specified DCR address. +* +* +* @param DcrRegister is the intended source DCR register +* +* @return +* +* Contents of the specified DCR register. +* +* @note +* +* C-style signature: +* void XIo_mDcrReadReg(u32 DcrRegister) +* +*******************************************************************************/ +#define XIo_mDcrReadReg(DcrRegister) ({ mfdcr((DcrRegister)); }) + +/******************************************************************************/ +/** +* Writes the register at specified DCR address. +* +* +* @param DcrRegister is the intended destination DCR register +* @param Data is the value to be placed into the specified DRC register +* +* @return +* +* None +* +* @note +* +* C-style signature: +* void XIo_mDcrWriteReg(u32 DcrRegister, u32 Data) +* +*******************************************************************************/ +#define XIo_mDcrWriteReg(DcrRegister, Data) ({ mtdcr((DcrRegister), (Data)); }) + +/******************************************************************************/ +/** +* Explicitly locks the DCR bus +* +* @param DcrBase is the base of the block of DCR registers +* +* @return +* +* None +* +* @note +* +* C-style signature: +* void XIo_mDcrLock(u32 DcrBase) +* +* Sets either Lock bit. Since a master cannot edit another master's Lock bit, +* the macro can be simplified. +* Care must be taken to not write a '1' to either timeout bit because +* it will be cleared. +* +*******************************************************************************/ +#define XIo_mDcrLock(DcrBase) \ +({ \ + u32 temp; \ + temp = mfdcr((DcrBase) + XDCR_CTRLCFGSTAT); \ + temp = (temp | XDCR_ALL_LOCK) & ~XDCR_ALL_TIMEOUT; \ + mtdcr(((DcrBase) + XDCR_CTRLCFGSTAT), temp); \ +}) + +/******************************************************************************/ +/** +* Explicitly locks the DCR bus +* +* @param DcrBase is the base of the block of DCR registers +* +* @return +* +* None +* +* @note +* +* C-style signature: +* void XIo_mDcrUnlock(u32 DcrBase) +* +* Unsets either Lock bit. Since a master cannot edit another master's Lock bit, +* the macro can be simplified. +* Care must be taken to not write a '1' to either timeout bit because +* it will be cleared. +* +*******************************************************************************/ +#define XIo_mDcrUnlock(DcrBase) \ +({ \ + u32 temp; \ + temp = mfdcr((DcrBase) + XDCR_CTRLCFGSTAT); \ + temp = temp & ~(XDCR_ALL_LOCK | XDCR_ALL_TIMEOUT); \ + mtdcr(((DcrBase) + XDCR_CTRLCFGSTAT), temp); \ +}) + +/******************************************************************************/ +/** +* Reads the APU UDI register at the specified APU address. +* +* +* @param DcrBase is the base of the block of DCR registers +* @param UDInum is the intended source APU register +* +* @return +* +* Contents of the specified APU register. +* +* @note +* +* C-style signature: +* u32 XIo_mDcrReadAPUUDIReg(u32 DcrRegister, u32 UDInum) +* +* Since reading an APU UDI DCR requires a dummy write to the same DCR, +* the target UDI number is required. In order to make this operation atomic, +* interrupts are disabled before and enabled after the DCR accesses. +* Because an APU UDI access involves two DCR accesses, the DCR bus must be +* locked to ensure that another master doesn't access the APU UDI register +* at the same time. +* Care must be taken to not write a '1' to either timeout bit because +* it will be cleared. +* Steps: +* - save old MSR +* - disable interrupts by writing mask to MSR +* - acquire lock; since the PPC440 supports timeout wait, it will wait until +* it successfully acquires the DCR bus lock +* - shift and mask the UDI number to its bit position of [22:25] +* - add the DCR base address to the UDI number and perform the read +* - release DCR bus lock +* - restore MSR +* - return value read +* +*******************************************************************************/ +#define XIo_mDcrReadAPUUDIReg(DcrBase, UDInum) \ +({ \ + unsigned int rVal; \ + unsigned int oldMSR = mfmsr(); \ + mtmsr(oldMSR & XDCR_DISABLE_EXCEPTIONS); \ + XIo_DcrLock((DcrBase)); \ + mtdcr((DcrBase) | XDCR_APU_UDI, (((UDInum) << 6) & 0x000003c0) | 0x00000030); \ + rVal = mfdcr((DcrBase) | XDCR_APU_UDI); \ + XIo_DcrUnlock((DcrBase)); \ + mtmsr(oldMSR); \ + rVal; \ +}) + +/******************************************************************************/ +/** +* Writes the data to the APU UDI register at the specified APU address. +* +* +* @param DcrBase is the base of the block of DCR registers +* @param UDInum is the intended source APU register +* @param Data is the value to be placed into the specified APU register +* +* @return +* +* None +* +* @note +* +* C-style signature: +* void XIo_mDcrWriteAPUUDIReg(u32 DcrRegister, u32 UDInum, u32 Data) +* +* Since writing an APU UDI DCR requires a dummy write to the same DCR, +* the target UDI number is required. In order to make this operation atomic, +* interrupts are disabled before and enabled after the DCR accesses. +* Because an APU UDI access involves two DCR accesses, the DCR bus must be +* locked to ensure that another master doesn't access the APU UDI register +* at the same time. +* Care must be taken to not write a '1' to either timeout bit because +* it will be cleared. +* Steps: +* - save old MSR +* - disable interrupts by writing mask to MSR +* - acquire lock, since the PPC440 supports timeout wait, it will wait until +* it successfully acquires the DCR bus lock +* - shift and mask the UDI number to its bit position of [22:25] +* - add DCR base address to UDI number offset and perform the write +* - release DCR bus lock +* - restore MSR +* +*******************************************************************************/ +#define XIo_mDcrWriteAPUUDIReg(DcrBase, UDInum, Data) \ +({ \ + unsigned int oldMSR = mfmsr(); \ + mtmsr(oldMSR & XDCR_DISABLE_EXCEPTIONS); \ + XIo_DcrLock((DcrBase)); \ + mtdcr((DcrBase) | XDCR_APU_UDI, (((UDInum) << 6) & 0x000003c0) | 0x00000030); \ + mtdcr((DcrBase) | XDCR_APU_UDI, (Data)); \ + XIo_DcrUnlock((DcrBase)); \ + mtmsr(oldMSR); \ +}) + +/******************************************************************************/ +/** +* Reads the register at the specified DCR address using the indirect addressing +* method. +* +* +* @param DcrBase is the base of the block of DCR registers +* @param DcrRegister is the intended source DCR register +* +* @return +* +* Contents of the specified DCR register. +* +* @note +* +* C-style signature: +* void XIo_mDcrIndirectAddrReadReg(u32 DcrBase, u32 DcrRegister) +* +* Assumes auto-buslocking feature is ON. +* In order to make this operation atomic, interrupts are disabled before +* and enabled after the DCR accesses. +* +*******************************************************************************/ +#define XIo_mDcrIndirectAddrReadReg(DcrBase, DcrRegister) \ +({ \ + unsigned int rVal; \ + unsigned int oldMSR = mfmsr(); \ + mtmsr(oldMSR & XDCR_DISABLE_EXCEPTIONS); \ + XIo_mDcrWriteReg((DcrBase) | XDCR_IDA_ADDR, (DcrBase) | DcrRegister); \ + rVal = XIo_mDcrReadReg((DcrBase) | XDCR_IDA_ACC); \ + mtmsr(oldMSR); \ + rVal; \ +}) + +/******************************************************************************/ +/** +* Writes the register at specified DCR address using the indirect addressing +* method. +* +* +* @param DcrBase is the base of the block of DCR registers +* @param DcrRegister is the intended destination DCR register +* @param Data is the value to be placed into the specified DRC register +* +* @return +* +* None +* +* @note +* +* C-style signature: +* void XIo_mDcrIndirectAddrWriteReg(u32 DcrBase, u32 DcrRegister, +* u32 Data) +* +* Assumes auto-buslocking feature is ON. +* In order to make this operation atomic, interrupts are disabled before +* and enabled after the DCR accesses. +* +*******************************************************************************/ +#define XIo_mDcrIndirectAddrWriteReg(DcrBase, DcrRegister, Data) \ +({ \ + unsigned int oldMSR = mfmsr(); \ + mtmsr(oldMSR & XDCR_DISABLE_EXCEPTIONS); \ + XIo_mDcrWriteReg((DcrBase) | XDCR_IDA_ADDR, (DcrBase) | DcrRegister); \ + XIo_mDcrWriteReg((DcrBase) | XDCR_IDA_ACC, Data); \ + mtmsr(oldMSR); \ +}) + +/******************************************************************************/ +/** +* Reads the APU UDI register at the specified DCR address using the indirect +* addressing method. +* +* +* @param DcrBase is the base of the block of DCR registers +* @param UDInum is the intended source DCR register +* +* @return +* +* Contents of the specified APU register. +* +* @note +* +* C-style signature: +* void XIo_mDcrIndirectAddrReadAPUUDIReg(u32 DcrBase, u32 UDInum) +* +* An indirect APU UDI read requires three DCR accesses: +* 1) Indirect address reg write +* 2) Indirect access reg write to specify the UDI number +* 3) Indirect access reg read of the actual data +* Since (2) unlocks the DCR bus, the DCR bus must be explicitly locked +* instead of relying on the auto-lock feature. +* In order to make this operation atomic, interrupts are disabled before +* and enabled after the DCR accesses. +* Care must be taken to not write a '1' to either timeout bit because +* it will be cleared. +* +*******************************************************************************/ +#define XIo_mDcrIndirectAddrReadAPUUDIReg(DcrBase, UDInum) \ +({ \ + unsigned int rVal; \ + unsigned int oldMSR = mfmsr(); \ + mtmsr(oldMSR & XDCR_DISABLE_EXCEPTIONS); \ + XIo_DcrLock((DcrBase)); \ + XIo_mDcrWriteReg((DcrBase) | XDCR_IDA_ADDR, (DcrBase) | XDCR_APU_UDI); \ + XIo_mDcrWriteReg((DcrBase) | XDCR_IDA_ACC, ((UDInum << 6) & 0x000003c0) | 0x00000030); \ + rVal = XIo_mDcrReadReg((DcrBase) | XDCR_IDA_ACC); \ + XIo_DcrUnlock((DcrBase)); \ + mtmsr(oldMSR); \ + rVal; \ +}) + +/******************************************************************************/ +/** +* Writes the APU UDI register at specified DCR address using the indirect +* addressing method. +* +* +* @param DcrBase is the base of the block of DCR registers +* @param UDInum is the intended source DCR register +* @param Data is the value to be placed into the specified DRC register +* +* @return +* +* None +* +* @note +* +* C-style signature: +* void XIo_mDcrIndirectAddrWriteReg(u32 DcrBase, u32 UDInum, u32 Data) +* +* An indirect APU UDI write requires three DCR accesses: +* 1) Indirect address reg write +* 2) Indirect access reg write to specify the UDI number +* 3) Indirect access reg write of the actual data +* Since (2) unlocks the DCR bus, the DCR bus must be explicitly locked +* instead of relying on the auto-lock feature. +* In order to make this operation atomic, interrupts are disabled before +* and enabled after the DCR accesses. +* Care must be taken to not write a '1' to either timeout bit because +* it will be cleared. +* +*******************************************************************************/ +#define XIo_mDcrIndirectAddrWriteAPUUDIReg(DcrBase, UDInum, Data) \ +({ \ + unsigned int oldMSR = mfmsr(); \ + mtmsr(oldMSR & XDCR_DISABLE_EXCEPTIONS); \ + XIo_DcrLock((DcrBase)); \ + XIo_mDcrWriteReg((DcrBase) | XDCR_IDA_ADDR, (DcrBase) | XDCR_APU_UDI); \ + XIo_mDcrWriteReg((DcrBase) | XDCR_IDA_ACC, ((UDInum << 6) & 0x000003c0) | 0x00000030); \ + XIo_mDcrWriteReg((DcrBase) | XDCR_IDA_ACC, Data);\ + XIo_DcrUnlock((DcrBase)); \ + mtmsr(oldMSR); \ +}) + +/************************** Function Prototypes ******************************/ +void XIo_DcrOut(u32 DcrRegister, u32 Data); +u32 XIo_DcrIn(u32 DcrRegister); + +u32 XIo_DcrReadReg(u32 DcrBase, u32 DcrRegister); +void XIo_DcrWriteReg(u32 DcrBase, u32 DcrRegister, u32 Data); +u32 XIo_DcrLockAndReadReg(u32 DcrBase, u32 DcrRegister); +void XIo_DcrLockAndWriteReg(u32 DcrBase, u32 DcrRegister, u32 Data); + +void XIo_DcrWriteAPUUDIReg(u32 DcrBase, short UDInum, u32 Data); +u32 XIo_DcrReadAPUUDIReg(u32 DcrBase, short UDInum); + +void XIo_DcrLock(u32 DcrBase); +void XIo_DcrUnlock(u32 DcrBase); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xio.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xio.h 2014-07-20 22:06:39.031261595 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xio.h,v 1.4 2007/07/24 22:01:35 xduan Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xio.h +* +* This file contains the interface for the XIo component, which encapsulates +* the Input/Output functions for the PowerPC architecture. +* This header file needs to be updated to replace eieio with mbar when +* compilers support the mbar mnemonic. +* +* @note +* +* This file contains architecture-dependent items (memory mapped or non memory +* mapped I/O). +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- -------------------------------------------------------- +* 1.00a ecm 10/18/05 initial release +* needs to be updated to replace eieio with mbar when +* compilers support this mnemonic. +* +* 1.00a ecm 01/24/07 update for new coding standard. +* 1.10a xd 07/24/07 Corrected the format in asm functions in __DCC__ mode. +* </pre> +******************************************************************************/ + +#ifndef XIO_H /* prevent circular inclusions */ +#define XIO_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + +/** + * Typedef for an I/O address. Typically correlates to the width of the + * address bus. + */ +typedef u32 XIo_Address; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/* The following macro is specific to the GNU compiler and PowerPC family. It + * performs an EIEIO instruction such that I/O operations are synced correctly. + * This macro is not necessarily portable across compilers since it uses + * inline assembly. + */ +#ifdef CONFIG_PPC +# define SYNCHRONIZE_IO __asm__ volatile ("eieio") /* should be 'mbar' ultimately */ +#else +# define SYNCHRONIZE_IO +#endif + +/* The following macros allow the software to be transportable across + * processors which use big or little endian memory models. + * + * Defined first are processor-specific endian conversion macros specific to + * the GNU compiler and the PowerPC family, as well as a no-op endian conversion + * macro. These macros are not to be used directly by software. Instead, the + * XIo_To/FromLittleEndianXX and XIo_To/FromBigEndianXX macros below are to be + * used to allow the endian conversion to only be performed when necessary + */ + +#define XIo_EndianNoop(Source, DestPtr) (*DestPtr = Source) + +#ifdef CONFIG_PPC + +#define XIo_EndianSwap16(Source, DestPtr) __asm__ __volatile__(\ + "sthbrx %0,0,%1\n"\ + : : "r" (Source), "r" (DestPtr)\ + ) + +#define XIo_EndianSwap32(Source, DestPtr) __asm__ __volatile__(\ + "stwbrx %0,0,%1\n"\ + : : "r" (Source), "r" (DestPtr)\ + ) +#else + +#define XIo_EndianSwap16(Source, DestPtr) \ +{\ + u16 src = (Source); \ + u16 *destptr = (DestPtr); \ + *destptr = src >> 8; \ + *destptr |= (src << 8); \ +} + +#define XIo_EndianSwap32(Source, DestPtr) \ +{\ + u32 src = (Source); \ + u32 *destptr = (DestPtr); \ + *destptr = src >> 24; \ + *destptr |= ((src >> 8) & 0x0000FF00); \ + *destptr |= ((src << 8) & 0x00FF0000); \ + *destptr |= ((src << 24) & 0xFF000000); \ +} + +#endif + +// #ifdef XLITTLE_ENDIAN +// /* little-endian processor */ + +// #define XIo_ToLittleEndian16 XIo_EndianNoop +// #define XIo_ToLittleEndian32 XIo_EndianNoop +// #define XIo_FromLittleEndian16 XIo_EndianNoop +// #define XIo_FromLittleEndian32 XIo_EndianNoop + +// #define XIo_ToBigEndian16(Source, DestPtr) XIo_EndianSwap16(Source, DestPtr) +// #define XIo_ToBigEndian32(Source, DestPtr) XIo_EndianSwap32(Source, DestPtr) +// #define XIo_FromBigEndian16 XIo_ToBigEndian16 +// #define XIo_FromBigEndian32 XIo_ToBigEndian32 + +// #else +/* big-endian processor */ // ppc or microblaze + +#define XIo_ToLittleEndian16(Source, DestPtr) XIo_EndianSwap16(Source, DestPtr) +#define XIo_ToLittleEndian32(Source, DestPtr) XIo_EndianSwap32(Source, DestPtr) +#define XIo_FromLittleEndian16 XIo_ToLittleEndian16 +#define XIo_FromLittleEndian32 XIo_ToLittleEndian32 + +#define XIo_ToBigEndian16 XIo_EndianNoop +#define XIo_ToBigEndian32 XIo_EndianNoop +#define XIo_FromBigEndian16 XIo_EndianNoop +#define XIo_FromBigEndian32 XIo_EndianNoop + +// #endif + + +/************************** Function Prototypes ******************************/ + +/* The following macros allow optimized I/O operations for memory mapped I/O + * Note that the SYNCHRONIZE_IO may be moved by the compiler during + * optimization. + */ + +u8 XIo_In8(XIo_Address InAddress); +u16 XIo_In16(XIo_Address InAddress); +u32 XIo_In32(XIo_Address InAddress); + +void XIo_Out8(XIo_Address OutAddress, u8 Value); +void XIo_Out16(XIo_Address OutAddress, u16 Value); +void XIo_Out32(XIo_Address OutAddress, u32 Value); + + +/* +#define XIo_In8(InputPtr) (*(volatile u8 *)(InputPtr)); SYNCHRONIZE_IO; +#define XIo_In16(InputPtr) (*(volatile u16 *)(InputPtr)); SYNCHRONIZE_IO; +#define XIo_In32(InputPtr) (*(volatile u32 *)(InputPtr)); SYNCHRONIZE_IO; + +#define XIo_Out8(OutputPtr, Value) \ + { (*(volatile u8 *)(OutputPtr) = Value); SYNCHRONIZE_IO; } +#define XIo_Out16(OutputPtr, Value) \ + { (*(volatile u16 *)(OutputPtr) = Value); SYNCHRONIZE_IO; } +#define XIo_Out32(OutputPtr, Value) \ + { (*(volatile u32 *)(OutputPtr) = Value); SYNCHRONIZE_IO; } + */ + +/* The following functions handle IO addresses where data must be swapped + * They cannot be implemented as macros + */ +u16 XIo_InSwap16(XIo_Address InAddress); +u32 XIo_InSwap32(XIo_Address InAddress); +void XIo_OutSwap16(XIo_Address OutAddress, u16 Value); +void XIo_OutSwap32(XIo_Address OutAddress, u32 Value); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xipif_v1_23_b.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xipif_v1_23_b.c 2014-07-20 22:06:39.041261430 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xipif_v1_23_b.c,v 1.3 2004/11/15 20:31:35 xduan Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002-2004 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xipif_v1_23_b.c +* +* This file contains the implementation of the XIpIf component. The +* XIpIf component encapsulates the IPIF, which is the standard interface +* that IP must adhere to when connecting to a bus. The purpose of this +* component is to encapsulate the IPIF processing such that maintainability +* is increased. This component does not provide a lot of abstraction from +* from the details of the IPIF as it is considered a building block for +* device drivers. A device driver designer must be familiar with the +* details of the IPIF hardware to use this component. +* +* The IPIF hardware provides a building block for all hardware devices such +* that each device does not need to reimplement these building blocks. The +* IPIF contains other building blocks, such as FIFOs and DMA channels, which +* are also common to many devices. These blocks are implemented as separate +* hardware blocks and instantiated within the IPIF. The primary hardware of +* the IPIF which is implemented by this software component is the interrupt +* architecture. Since there are many blocks of a device which may generate +* interrupts, all the interrupt processing is contained in the common part +* of the device, the IPIF. This interrupt processing is for the device level +* only and does not include any processing for the interrupt controller. +* +* A device is a mechanism such as an Ethernet MAC. The device is made +* up of several parts which include an IPIF and the IP. The IPIF contains most +* of the device infrastructure which is common to all devices, such as +* interrupt processing, DMA channels, and FIFOs. The infrastructure may also +* be referred to as IPIF internal blocks since they are part of the IPIF and +* are separate blocks that can be selected based upon the needs of the device. +* The IP of the device is the logic that is unique to the device and interfaces +* to the IPIF of the device. +* +* In general, there are two levels of registers within the IPIF. The first +* level, referred to as the device level, contains registers which are for the +* entire device. The second level, referred to as the IP level, contains +* registers which are specific to the IP of the device. The two levels of +* registers are designed to be hierarchical such that the device level is +* is a more general register set above the more specific registers of the IP. +* The IP level of registers provides functionality which is typically common +* across all devices and allows IP designers to focus on the unique aspects +* of the IP. +* +* The interrupt registers of the IPIF are parameterizable such that the only +* the number of bits necessary for the device are implemented. The functions +* of this component do not attempt to validate that the passed in arguments are +* valid based upon the number of implemented bits. This is necessary to +* maintain the level of performance required for the common components. Bits +* of the registers are assigned starting at the least significant bit of the +* registers. +* +* <b>Critical Sections</b> +* +* It is the responsibility of the device driver designer to use critical +* sections as necessary when calling functions of the IPIF. This component +* does not use critical sections and it does access registers using +* read-modify-write operations. Calls to IPIF functions from a main thread +* and from an interrupt context could produce unpredictable behavior such that +* the caller must provide the appropriate critical sections. +* +* <b>Mutual Exclusion</b> +* +* The functions of the IPIF are not thread safe such that the caller of all +* functions is responsible for ensuring mutual exclusion for an IPIF. Mutual +* exclusion across multiple IPIF components is not necessary. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.23b jhl 02/27/01 Repartioned to reduce size +* 1.23b rpm 08/17/04 Doxygenated for inclusion in API documentation +* 1.23b xd 10/27/04 Improve Doxygen format +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xipif_v1_23_b.h" +#include "xio.h" + +/************************** Constant Definitions *****************************/ + +/* the following constant is used to generate bit masks for register testing + * in the self test functions, it defines the starting bit mask that is to be + * shifted from the LSB to MSB in creating a register test mask + */ +#define XIIF_V123B_FIRST_BIT_MASK 1UL + + +/* the following constant defines the maximum number of bits which may be + * used in the registers at the device and IP levels, this is based upon the + * number of bits available in the registers + */ +#define XIIF_V123B_MAX_REG_BIT_COUNT 32 + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Variable Definitions *****************************/ + + +/************************** Function Prototypes ******************************/ + +static int IpIntrSelfTest(u32 RegBaseAddress, u32 IpRegistersWidth); + +/*****************************************************************************/ +/** +* +* This function performs a self test on the specified IPIF component. Many +* of the registers in the IPIF are tested to ensure proper operation. This +* function is destructive because the IPIF is reset at the start of the test +* and at the end of the test to ensure predictable results. The IPIF reset +* also resets the entire device that uses the IPIF. This function exits with +* all interrupts for the device disabled. +* +* @param RegBaseAddress is the base address of the device's IPIF registers +* +* @param IpRegistersWidth contains the number of bits in the IP interrupt +* registers of the device. The hardware is parameterizable such that +* only the number of bits necessary to support a device are implemented. +* This value must be between 0 and 32 with 0 indicating there are no IP +* interrupt registers used. +* +* @return +* +* A value of XST_SUCCESS indicates the test was successful with no errors. +* Any one of the following error values may also be returned. +* <br><br> +* - XST_IPIF_RESET_REGISTER_ERROR The value of a register at reset was +* not valid +* <br><br> +* - XST_IPIF_IP_STATUS_ERROR A write to the IP interrupt status +* register did not read back correctly +* <br><br> +* - XST_IPIF_IP_ACK_ERROR One or more bits in the IP interrupt +* status register did not reset when acked +* <br><br> +* - XST_IPIF_IP_ENABLE_ERROR The IP interrupt enable register +* did not read back correctly based upon +* what was written to it +* +* @note +* +* None. +* +******************************************************************************/ +int XIpIfV123b_SelfTest(u32 RegBaseAddress, u8 IpRegistersWidth) +{ + int Status; + + /* assert to verify arguments are valid */ + + XASSERT_NONVOID(IpRegistersWidth <= XIIF_V123B_MAX_REG_BIT_COUNT); + + /* reset the IPIF such that it's in a known state before the test + * and interrupts are globally disabled + */ + XIIF_V123B_RESET(RegBaseAddress); + + /* perform the self test on the IP interrupt registers, if + * it is not successful exit with the status + */ + Status = IpIntrSelfTest(RegBaseAddress, IpRegistersWidth); + if (Status != XST_SUCCESS) { + return Status; + } + + /* reset the IPIF such that it's in a known state before exiting test */ + + XIIF_V123B_RESET(RegBaseAddress); + + /* reaching this point means there were no errors, return success */ + + return XST_SUCCESS; +} + +/***************************************************************************** +* +* Perform a self test on the IP interrupt registers of the IPIF. This +* function modifies registers of the IPIF such that they are not guaranteed +* to be in the same state when it returns. Any bits in the IP interrupt +* status register which are set are assumed to be set by default after a reset +* and are not tested in the test. +* +* @param RegBaseAddress is the base address of the device's IPIF registers +* +* @param IpRegistersWidth contains the number of bits in the IP interrupt +* registers of the device. The hardware is parameterizable such that +* only the number of bits necessary to support a device are implemented. +* This value must be between 0 and 32 with 0 indicating there are no IP +* interrupt registers used. +* +* @return +* +* A status indicating XST_SUCCESS if the test was successful. Otherwise, one +* of the following values is returned. +* - XST_IPIF_RESET_REGISTER_ERROR The value of a register at reset was +* not valid +* <br><br> +* - XST_IPIF_IP_STATUS_ERROR A write to the IP interrupt status +* register did not read back correctly +* <br><br> +* - XST_IPIF_IP_ACK_ERROR One or more bits in the IP status +* register did not reset when acked +* <br><br> +* - XST_IPIF_IP_ENABLE_ERROR The IP interrupt enable register +* did not read back correctly based upon +* what was written to it +* @note +* +* None. +* +******************************************************************************/ +static int IpIntrSelfTest(u32 RegBaseAddress, u32 IpRegistersWidth) +{ + /* ensure that the IP interrupt enable register is zero + * as it should be at reset, the interrupt status is dependent upon the + * IP such that it's reset value is not known + */ + if (XIIF_V123B_READ_IIER(RegBaseAddress) != 0) { + return XST_IPIF_RESET_REGISTER_ERROR; + } + + /* if there are any used IP interrupts, then test all of the interrupt + * bits in all testable registers + */ + if (IpRegistersWidth > 0) { + u32 BitCount; + u32 IpInterruptMask = XIIF_V123B_FIRST_BIT_MASK; + u32 Mask = XIIF_V123B_FIRST_BIT_MASK; /* bits assigned MSB to LSB */ + u32 InterruptStatus; + + /* generate the register masks to be used for IP register tests, the + * number of bits supported by the hardware is parameterizable such + * that only that number of bits are implemented in the registers, the + * bits are allocated starting at the MSB of the registers + */ + for (BitCount = 1; BitCount < IpRegistersWidth; BitCount++) { + Mask = Mask << 1; + IpInterruptMask |= Mask; + } + + /* get the current IP interrupt status register contents, any bits + * already set must default to 1 at reset in the device and these + * bits can't be tested in the following test, remove these bits from + * the mask that was generated for the test + */ + InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); + IpInterruptMask &= ~InterruptStatus; + + /* set the bits in the device status register and verify them by reading + * the register again, all bits of the register are latched + */ + XIIF_V123B_WRITE_IISR(RegBaseAddress, IpInterruptMask); + InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); + if ((InterruptStatus & IpInterruptMask) != IpInterruptMask) + { + return XST_IPIF_IP_STATUS_ERROR; + } + + /* test to ensure that the bits set in the IP interrupt status register + * can be cleared by acknowledging them in the IP interrupt status + * register then read it again and verify it was cleared + */ + XIIF_V123B_WRITE_IISR(RegBaseAddress, IpInterruptMask); + InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); + if ((InterruptStatus & IpInterruptMask) != 0) { + return XST_IPIF_IP_ACK_ERROR; + } + + /* set the IP interrupt enable set register and then read the IP + * interrupt enable register and verify the interrupts were enabled + */ + XIIF_V123B_WRITE_IIER(RegBaseAddress, IpInterruptMask); + if (XIIF_V123B_READ_IIER(RegBaseAddress) != IpInterruptMask) { + return XST_IPIF_IP_ENABLE_ERROR; + } + + /* clear the IP interrupt enable register and then read the + * IP interrupt enable register and verify the interrupts were disabled + */ + XIIF_V123B_WRITE_IIER(RegBaseAddress, 0); + if (XIIF_V123B_READ_IIER(RegBaseAddress) != 0) { + return XST_IPIF_IP_ENABLE_ERROR; + } + } + return XST_SUCCESS; +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xipif_v1_23_b.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xipif_v1_23_b.h 2014-07-20 22:06:39.055261199 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xipif_v1_23_b.h,v 1.5 2005/09/26 16:04:52 trujillo Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002-2004 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xipif_v1_23_b.h +* +* The XIpIf component encapsulates the IPIF, which is the standard interface +* that IP must adhere to when connecting to a bus. The purpose of this +* component is to encapsulate the IPIF processing such that maintainability +* is increased. This component does not provide a lot of abstraction from +* from the details of the IPIF as it is considered a building block for +* device drivers. A device driver designer must be familiar with the +* details of the IPIF hardware to use this component. +* +* The IPIF hardware provides a building block for all hardware devices such +* that each device does not need to reimplement these building blocks. The +* IPIF contains other building blocks, such as FIFOs and DMA channels, which +* are also common to many devices. These blocks are implemented as separate +* hardware blocks and instantiated within the IPIF. The primary hardware of +* the IPIF which is implemented by this software component is the interrupt +* architecture. Since there are many blocks of a device which may generate +* interrupts, all the interrupt processing is contained in the common part +* of the device, the IPIF. This interrupt processing is for the device level +* only and does not include any processing for the interrupt controller. +* +* A device is a mechanism such as an Ethernet MAC. The device is made +* up of several parts which include an IPIF and the IP. The IPIF contains most +* of the device infrastructure which is common to all devices, such as +* interrupt processing, DMA channels, and FIFOs. The infrastructure may also +* be referred to as IPIF internal blocks since they are part of the IPIF and +* are separate blocks that can be selected based upon the needs of the device. +* The IP of the device is the logic that is unique to the device and interfaces +* to the IPIF of the device. +* +* In general, there are two levels of registers within the IPIF. The first +* level, referred to as the device level, contains registers which are for the +* entire device. The second level, referred to as the IP level, contains +* registers which are specific to the IP of the device. The two levels of +* registers are designed to be hierarchical such that the device level is +* is a more general register set above the more specific registers of the IP. +* The IP level of registers provides functionality which is typically common +* across all devices and allows IP designers to focus on the unique aspects +* of the IP. +* +* <b>Critical Sections</b> +* +* It is the responsibility of the device driver designer to use critical +* sections as necessary when calling functions of the IPIF. This component +* does not use critical sections and it does access registers using +* read-modify-write operations. Calls to IPIF functions from a main thread +* and from an interrupt context could produce unpredictable behavior such that +* the caller must provide the appropriate critical sections. +* +* <b>Mutual Exclusion</b> +* +* The functions of the IPIF are not thread safe such that the caller of all +* functions is responsible for ensuring mutual exclusion for an IPIF. Mutual +* exclusion across multiple IPIF components is not necessary. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.23b jhl 02/27/01 Repartioned to minimize size +* 1.23b rpm 07/16/04 Changed ifdef for circular inclusion to be more qualified +* 1.23b rpm 08/17/04 Doxygenated for inclusion of API documentation +* 1.23b xd 10/27/04 Improve Doxygen format +* </pre> +* +******************************************************************************/ + +#ifndef XIPIF_V123B_H /* prevent circular inclusions */ +#define XIPIF_V123B_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ +#include "xbasic_types.h" +#include "xstatus.h" +#include "xversion.h" + +/************************** Constant Definitions *****************************/ + +/** @name Register Offsets + * + * The following constants define the register offsets for the registers of the + * IPIF, there are some holes in the memory map for reserved addresses to allow + * other registers to be added and still match the memory map of the interrupt + * controller registers + * @{ + */ +#define XIIF_V123B_DISR_OFFSET 0UL /**< device interrupt status register */ +#define XIIF_V123B_DIPR_OFFSET 4UL /**< device interrupt pending register */ +#define XIIF_V123B_DIER_OFFSET 8UL /**< device interrupt enable register */ +#define XIIF_V123B_DIIR_OFFSET 24UL /**< device interrupt ID register */ +#define XIIF_V123B_DGIER_OFFSET 28UL /**< device global interrupt enable register */ +#define XIIF_V123B_IISR_OFFSET 32UL /**< IP interrupt status register */ +#define XIIF_V123B_IIER_OFFSET 40UL /**< IP interrupt enable register */ +#define XIIF_V123B_RESETR_OFFSET 64UL /**< reset register */ +/* @} */ + +/** + * The value used for the reset register to reset the IPIF + */ +#define XIIF_V123B_RESET_MASK 0xAUL + +/** + * The following constant is used for the device global interrupt enable + * register, to enable all interrupts for the device, this is the only bit + * in the register + */ +#define XIIF_V123B_GINTR_ENABLE_MASK 0x80000000UL + +/** + * The mask to identify each internal IPIF error condition in the device + * registers of the IPIF. Interrupts are assigned in the register from LSB + * to the MSB + */ +#define XIIF_V123B_ERROR_MASK 1UL /**< LSB of the register */ + +/** @name Interrupt IDs + * + * The interrupt IDs which identify each internal IPIF condition, this value + * must correlate with the mask constant for the error + * @{ + */ +#define XIIF_V123B_ERROR_INTERRUPT_ID 0 /**< interrupt bit #, (LSB = 0) */ +#define XIIF_V123B_NO_INTERRUPT_ID 128 /**< no interrupts are pending */ +/* @} */ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/*****************************************************************************/ +/** +* +* Reset the IPIF component and hardware. This is a destructive operation that +* could cause the loss of data since resetting the IPIF of a device also +* resets the device using the IPIF and any blocks, such as FIFOs or DMA +* channels, within the IPIF. All registers of the IPIF will contain their +* reset value when this function returns. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return None +* +* @note None +* +******************************************************************************/ +#define XIIF_V123B_RESET(RegBaseAddress) \ + XIo_Out32(RegBaseAddress + XIIF_V123B_RESETR_OFFSET, XIIF_V123B_RESET_MASK) + +/*****************************************************************************/ +/** +* +* This macro sets the device interrupt status register to the value. +* This register indicates the status of interrupt sources for a device +* which contains the IPIF. The status is independent of whether interrupts +* are enabled and could be used for polling a device at a higher level rather +* than a more detailed level. +* +* Each bit of the register correlates to a specific interrupt source within the +* device which contains the IPIF. With the exception of some internal IPIF +* conditions, the contents of this register are not latched but indicate +* the live status of the interrupt sources within the device. Writing any of +* the non-latched bits of the register will have no effect on the register. +* +* For the latched bits of this register only, setting a bit which is zero +* within this register causes an interrupt to generated. The device global +* interrupt enable register and the device interrupt enable register must be set +* appropriately to allow an interrupt to be passed out of the device. The +* interrupt is cleared by writing to this register with the bits to be +* cleared set to a one and all others to zero. This register implements a +* toggle on write functionality meaning any bits which are set in the value +* written cause the bits in the register to change to the opposite state. +* +* This function writes the specified value to the register such that +* some bits may be set and others cleared. It is the caller's responsibility +* to get the value of the register prior to setting the value to prevent a +* destructive behavior. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @param Status contains the value to be written to the interrupt status +* register of the device. The only bits which can be written are +* the latched bits which contain the internal IPIF conditions. The +* following values may be used to set the status register or clear an +* interrupt condition. +* - XIIF_V123B_ERROR_MASK Indicates a device error in the IPIF +* +* @return None. +* +* @note None. +* +******************************************************************************/ +#define XIIF_V123B_WRITE_DISR(RegBaseAddress, Status) \ + XIo_Out32((RegBaseAddress) + XIIF_V123B_DISR_OFFSET, (Status)) + +/*****************************************************************************/ +/** +* +* This macro gets the device interrupt status register contents. +* This register indicates the status of interrupt sources for a device +* which contains the IPIF. The status is independent of whether interrupts +* are enabled and could be used for polling a device at a higher level. +* +* Each bit of the register correlates to a specific interrupt source within the +* device which contains the IPIF. With the exception of some internal IPIF +* conditions, the contents of this register are not latched but indicate +* the live status of the interrupt sources within the device. +* +* For only the latched bits of this register, the interrupt may be cleared by +* writing to these bits in the status register. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* A status which contains the value read from the interrupt status register of +* the device. The bit definitions are specific to the device with +* the exception of the latched internal IPIF condition bits. The following +* values may be used to detect internal IPIF conditions in the status. +* <br><br> +* - XIIF_V123B_ERROR_MASK Indicates a device error in the IPIF +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_READ_DISR(RegBaseAddress) \ + XIo_In32((RegBaseAddress) + XIIF_V123B_DISR_OFFSET) + +/*****************************************************************************/ +/** +* +* This function sets the device interrupt enable register contents. +* This register controls which interrupt sources of the device are allowed to +* generate an interrupt. The device global interrupt enable register must also +* be set appropriately for an interrupt to be passed out of the device. +* +* Each bit of the register correlates to a specific interrupt source within the +* device which contains the IPIF. Setting a bit in this register enables that +* interrupt source to generate an interrupt. Clearing a bit in this register +* disables interrupt generation for that interrupt source. +* +* This function writes only the specified value to the register such that +* some interrupts source may be enabled and others disabled. It is the +* caller's responsibility to get the value of the interrupt enable register +* prior to setting the value to prevent an destructive behavior. +* +* An interrupt source may not be enabled to generate an interrupt, but can +* still be polled in the interrupt status register. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @param +* +* Enable contains the value to be written to the interrupt enable register +* of the device. The bit definitions are specific to the device with +* the exception of the internal IPIF conditions. The following +* values may be used to enable the internal IPIF conditions interrupts. +* - XIIF_V123B_ERROR_MASK Indicates a device error in the IPIF +* +* @return +* +* None. +* +* @note +* +* Signature: u32 XIIF_V123B_WRITE_DIER(u32 RegBaseAddress, +* u32 Enable) +* +******************************************************************************/ +#define XIIF_V123B_WRITE_DIER(RegBaseAddress, Enable) \ + XIo_Out32((RegBaseAddress) + XIIF_V123B_DIER_OFFSET, (Enable)) + +/*****************************************************************************/ +/** +* +* This function gets the device interrupt enable register contents. +* This register controls which interrupt sources of the device +* are allowed to generate an interrupt. The device global interrupt enable +* register and the device interrupt enable register must also be set +* appropriately for an interrupt to be passed out of the device. +* +* Each bit of the register correlates to a specific interrupt source within the +* device which contains the IPIF. Setting a bit in this register enables that +* interrupt source to generate an interrupt if the global enable is set +* appropriately. Clearing a bit in this register disables interrupt generation +* for that interrupt source regardless of the global interrupt enable. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* The value read from the interrupt enable register of the device. The bit +* definitions are specific to the device with the exception of the internal +* IPIF conditions. The following values may be used to determine from the +* value if the internal IPIF conditions interrupts are enabled. +* <br><br> +* - XIIF_V123B_ERROR_MASK Indicates a device error in the IPIF +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_READ_DIER(RegBaseAddress) \ + XIo_In32((RegBaseAddress) + XIIF_V123B_DIER_OFFSET) + +/*****************************************************************************/ +/** +* +* This function gets the device interrupt pending register contents. +* This register indicates the pending interrupt sources, those that are waiting +* to be serviced by the software, for a device which contains the IPIF. +* An interrupt must be enabled in the interrupt enable register of the IPIF to +* be pending. +* +* Each bit of the register correlates to a specific interrupt source within the +* the device which contains the IPIF. With the exception of some internal IPIF +* conditions, the contents of this register are not latched since the condition +* is latched in the IP interrupt status register, by an internal block of the +* IPIF such as a FIFO or DMA channel, or by the IP of the device. This register +* is read only and is not latched, but it is necessary to acknowledge (clear) +* the interrupt condition by performing the appropriate processing for the IP +* or block within the IPIF. +* +* This register can be thought of as the contents of the interrupt status +* register ANDed with the contents of the interrupt enable register. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* The value read from the interrupt pending register of the device. The bit +* definitions are specific to the device with the exception of the latched +* internal IPIF condition bits. The following values may be used to detect +* internal IPIF conditions in the value. +* <br><br> +* - XIIF_V123B_ERROR_MASK Indicates a device error in the IPIF +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_READ_DIPR(RegBaseAddress) \ + XIo_In32((RegBaseAddress) + XIIF_V123B_DIPR_OFFSET) + +/*****************************************************************************/ +/** +* +* This macro gets the device interrupt ID for the highest priority interrupt +* which is pending from the interrupt ID register. This function provides +* priority resolution such that faster interrupt processing is possible. +* Without priority resolution, it is necessary for the software to read the +* interrupt pending register and then check each interrupt source to determine +* if an interrupt is pending. Priority resolution becomes more important as the +* number of interrupt sources becomes larger. +* +* Interrupt priorities are based upon the bit position of the interrupt in the +* interrupt pending register with bit 0 being the highest priority. The +* interrupt ID is the priority of the interrupt, 0 - 31, with 0 being the +* highest priority. The interrupt ID register is live rather than latched such +* that multiple calls to this function may not yield the same results. A +* special value, outside of the interrupt priority range of 0 - 31, is +* contained in the register which indicates that no interrupt is pending. This +* may be useful for allowing software to continue processing interrupts in a +* loop until there are no longer any interrupts pending. +* +* The interrupt ID is designed to allow a function pointer table to be used +* in the software such that the interrupt ID is used as an index into that +* table. The function pointer table could contain an instance pointer, such +* as to DMA channel, and a function pointer to the function which handles +* that interrupt. This design requires the interrupt processing of the device +* driver to be partitioned into smaller more granular pieces based upon +* hardware used by the device, such as DMA channels and FIFOs. +* +* It is not mandatory that this function be used by the device driver software. +* It may choose to read the pending register and resolve the pending interrupt +* priorities on it's own. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* An interrupt ID, 0 - 31, which identifies the highest priority interrupt +* which is pending. A value of XIIF_NO_INTERRUPT_ID indicates that there is +* no interrupt pending. The following values may be used to identify the +* interrupt ID for the internal IPIF interrupts. +* <br><br> +* - XIIF_V123B_ERROR_INTERRUPT_ID Indicates a device error in the IPIF +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_READ_DIIR(RegBaseAddress) \ + XIo_In32((RegBaseAddress) + XIIF_V123B_DIIR_OFFSET) + +/*****************************************************************************/ +/** +* +* This function disables all interrupts for the device by writing to the global +* interrupt enable register. This register provides the ability to disable +* interrupts without any modifications to the interrupt enable register such +* that it is minimal effort to restore the interrupts to the previous enabled +* state. The corresponding function, XIpIf_GlobalIntrEnable, is provided to +* restore the interrupts to the previous enabled state. This function is +* designed to be used in critical sections of device drivers such that it is +* not necessary to disable other device interrupts. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_GINTR_DISABLE(RegBaseAddress) \ + XIo_Out32((RegBaseAddress) + XIIF_V123B_DGIER_OFFSET, 0) + +/*****************************************************************************/ +/** +* +* This function writes to the global interrupt enable register to enable +* interrupts from the device. This register provides the ability to enable +* interrupts without any modifications to the interrupt enable register such +* that it is minimal effort to restore the interrupts to the previous enabled +* state. This function does not enable individual interrupts as the interrupt +* enable register must be set appropriately. This function is designed to be +* used in critical sections of device drivers such that it is not necessary to +* disable other device interrupts. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_GINTR_ENABLE(RegBaseAddress) \ + XIo_Out32((RegBaseAddress) + XIIF_V123B_DGIER_OFFSET, \ + XIIF_V123B_GINTR_ENABLE_MASK) + +/*****************************************************************************/ +/** +* +* This function determines if interrupts are enabled at the global level by +* reading the global interrupt register. This register provides the ability to +* disable interrupts without any modifications to the interrupt enable register +* such that it is minimal effort to restore the interrupts to the previous +* enabled state. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* TRUE if interrupts are enabled for the IPIF, FALSE otherwise. +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_IS_GINTR_ENABLED(RegBaseAddress) \ + (XIo_In32((RegBaseAddress) + XIIF_V123B_DGIER_OFFSET) == \ + XIIF_V123B_GINTR_ENABLE_MASK) + +/*****************************************************************************/ +/** +* +* This function sets the IP interrupt status register to the specified value. +* This register indicates the status of interrupt sources for the IP of the +* device. The IP is defined as the part of the device that connects to the +* IPIF. The status is independent of whether interrupts are enabled such that +* the status register may also be polled when interrupts are not enabled. +* +* Each bit of the register correlates to a specific interrupt source within the +* IP. All bits of this register are latched. Setting a bit which is zero +* within this register causes an interrupt to be generated. The device global +* interrupt enable register and the device interrupt enable register must be set +* appropriately to allow an interrupt to be passed out of the device. The +* interrupt is cleared by writing to this register with the bits to be +* cleared set to a one and all others to zero. This register implements a +* toggle on write functionality meaning any bits which are set in the value +* written cause the bits in the register to change to the opposite state. +* +* This function writes only the specified value to the register such that +* some status bits may be set and others cleared. It is the caller's +* responsibility to get the value of the register prior to setting the value +* to prevent an destructive behavior. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @param Status contains the value to be written to the IP interrupt status +* register. The bit definitions are specific to the device IP. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_WRITE_IISR(RegBaseAddress, Status) \ + XIo_Out32((RegBaseAddress) + XIIF_V123B_IISR_OFFSET, (Status)) + +/*****************************************************************************/ +/** +* +* This macro gets the contents of the IP interrupt status register. +* This register indicates the status of interrupt sources for the IP of the +* device. The IP is defined as the part of the device that connects to the +* IPIF. The status is independent of whether interrupts are enabled such +* that the status register may also be polled when interrupts are not enabled. +* +* Each bit of the register correlates to a specific interrupt source within the +* device. All bits of this register are latched. Writing a 1 to a bit within +* this register causes an interrupt to be generated if enabled in the interrupt +* enable register and the global interrupt enable is set. Since the status is +* latched, each status bit must be acknowledged in order for the bit in the +* status register to be updated. Each bit can be acknowledged by writing a +* 0 to the bit in the status register. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* A status which contains the value read from the IP interrupt status register. +* The bit definitions are specific to the device IP. +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_READ_IISR(RegBaseAddress) \ + XIo_In32((RegBaseAddress) + XIIF_V123B_IISR_OFFSET) + +/*****************************************************************************/ +/** +* +* This macro sets the IP interrupt enable register contents. This register +* controls which interrupt sources of the IP are allowed to generate an +* interrupt. The global interrupt enable register and the device interrupt +* enable register must also be set appropriately for an interrupt to be +* passed out of the device containing the IPIF and the IP. +* +* Each bit of the register correlates to a specific interrupt source within the +* IP. Setting a bit in this register enables the interrupt source to generate +* an interrupt. Clearing a bit in this register disables interrupt generation +* for that interrupt source. +* +* This function writes only the specified value to the register such that +* some interrupt sources may be enabled and others disabled. It is the +* caller's responsibility to get the value of the interrupt enable register +* prior to setting the value to prevent an destructive behavior. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @param Enable contains the value to be written to the IP interrupt enable +* register. The bit definitions are specific to the device IP. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +#define XIIF_V123B_WRITE_IIER(RegBaseAddress, Enable) \ + XIo_Out32((RegBaseAddress) + XIIF_V123B_IIER_OFFSET, (Enable)) + +/*****************************************************************************/ +/** +* +* This macro gets the IP interrupt enable register contents. This register +* controls which interrupt sources of the IP are allowed to generate an +* interrupt. The global interrupt enable register and the device interrupt +* enable register must also be set appropriately for an interrupt to be +* passed out of the device containing the IPIF and the IP. +* +* Each bit of the register correlates to a specific interrupt source within the +* IP. Setting a bit in this register enables the interrupt source to generate +* an interrupt. Clearing a bit in this register disables interrupt generation +* for that interrupt source. +* +* @param RegBaseAddress contains the base address of the IPIF registers. +* +* @return +* +* The contents read from the IP interrupt enable register. The bit definitions +* are specific to the device IP. +* +* @note +* +* Signature: u32 XIIF_V123B_READ_IIER(u32 RegBaseAddress) +* +******************************************************************************/ +#define XIIF_V123B_READ_IIER(RegBaseAddress) \ + XIo_In32((RegBaseAddress) + XIIF_V123B_IIER_OFFSET) + +/************************** Function Prototypes ******************************/ + +/** + * Initialization Functions + */ +int XIpIfV123b_SelfTest(u32 RegBaseAddress, u8 IpRegistersWidth); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_bd.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_bd.h 2014-07-20 22:06:39.065261034 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xlldma_bd.h + * + * This header provides operations to manage buffer descriptors (BD) in support + * of Local-Link scatter-gather DMA (see xlldma.h). + * + * The API exported by this header defines abstracted macros that allow the + * application to read/write specific BD fields. + * + * <b>Buffer Descriptors</b> + * + * A buffer descriptor defines a DMA transaction (see "Transaction" + * section in xlldma.h). The macros defined by this header file allow access + * to most fields within a BD to tailor a DMA transaction according to + * application and hardware requirements. See the hardware IP DMA spec for + * more information on BD fields and how they affect transfers. + * + * The XLlDma_Bd structure defines a BD. The organization of this structure is + * driven mainly by the hardware for use in scatter-gather DMA transfers. + * + * <b>Accessor Macros</b> + * + * Most of the BD attributes can be accessed through macro functions defined + * here in this API. Words such as XLLDMA_BD_USR1_OFFSET (see xlldma_hw.h) + * should be accessed using XLlDma_mBdRead() and XLlDma_mBdWrite() as defined + * in xlldma_hw.h. The USR words are implementation dependent. For example, + * they may implement checksum offloading fields for Ethernet devices. Accessor + * macros may be defined in the device specific API to get at this data. + * + * <b>Performance</b> + * + * BDs are typically in a non-cached memory space. Limiting I/O to BDs can + * improve overall performance of the DMA channel. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a xd 12/21/06 First release + * </pre> + * + *****************************************************************************/ + +#ifndef XLLDMA_BD_H /* prevent circular inclusions */ +#define XLLDMA_BD_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xenv.h" +#include "xlldma_hw.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/** + * The XLlDma_Bd is the type for buffer descriptors (BDs). + */ +typedef u32 XLlDma_Bd[XLLDMA_BD_NUM_WORDS]; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* +* Read the given Buffer Descriptor word. +* +* @param BaseAddress is the base address of the BD to read +* @param Offset is the word offset to be read +* +* @return The 32-bit value of the field +* +* @note +* C-style signature: +* u32 XLlDma_mBdRead(u32 BaseAddress, u32 Offset) +* +******************************************************************************/ +#define XLlDma_mBdRead(BaseAddress, Offset) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset))) + + +/*****************************************************************************/ +/** +* +* Write the given Buffer Descriptor word. +* +* @param BaseAddress is the base address of the BD to write +* @param Offset is the word offset to be written +* @param Data is the 32-bit value to write to the field +* +* @return None. +* +* @note +* C-style signature: +* void XLlDma_mBdWrite(u32 BaseAddress, u32 RegOffset, u32 Data) +* +******************************************************************************/ +#define XLlDma_mBdWrite(BaseAddress, Offset, Data) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset)) = (Data)) + + +/*****************************************************************************/ +/** + * Zero out all BD fields + * + * @param BdPtr is the BD to operate on + * + * @return Nothing + * + * @note + * C-style signature: + * void XLlDma_mBdClear(XLlDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XLlDma_mBdClear(BdPtr) \ + memset((BdPtr), 0, sizeof(XLlDma_Bd)) + + +/*****************************************************************************/ +/** + * Set the BD's STS/CTRL field. The word containing STS/CTRL also contains the + * USR0 field. USR0 will not be modified. This operation requires a read- + * modify-write operation. If it is wished to set both STS/CTRL and USR0 with + * a single write operation, then use XLlDma_mBdWrite(BdPtr, + * XLLDMA_BD_STSCTRL_USR0_OFFSET, Data). + * + * @param BdPtr is the BD to operate on + * @param Data is the value to write to STS/CTRL. Or 0 or more + * XLLDMA_BD_STSCTRL_*** values defined in xlldma_hw.h to create a + * valid value for this parameter + * + * @note + * C-style signature: + * u32 XLlDma_mBdSetStsCtrl(XLlDma_Bd* BdPtr, u32 Data) + * + *****************************************************************************/ +#define XLlDma_mBdSetStsCtrl(BdPtr, Data) \ + XLlDma_mBdWrite((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET, \ + (XLlDma_mBdRead((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET) \ + & XLLDMA_BD_STSCTRL_USR0_MASK) | \ + ((Data) & XLLDMA_BD_STSCTRL_MASK)) + + +/*****************************************************************************/ +/** + * Retrieve the word containing the BD's STS/CTRL field. This word also + * contains the USR0 field. + * + * @param BdPtr is the BD to operate on + * + * @return Word at offset XLLDMA_BD_DMASR_OFFSET. Use XLLDMA_BD_STSCTRL_*** + * values defined in xlldma_hw.h to interpret this returned value + * + * @note + * C-style signature: + * u32 XLlDma_mBdGetStsCtrl(XLlDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XLlDma_mBdGetStsCtrl(BdPtr) \ + XLlDma_mBdRead((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET) + + +/*****************************************************************************/ +/** + * Set transfer length in bytes for the given BD. The length must be set each + * time a BD is submitted to hardware. + * + * @param BdPtr is the BD to operate on + * @param LenBytes is the number of bytes to transfer. + * + * @note + * C-style signature: + * void XLlDma_mBdSetLength(XLlDma_Bd* BdPtr, u32 LenBytes) + * + *****************************************************************************/ +#define XLlDma_mBdSetLength(BdPtr, LenBytes) \ + XLlDma_mBdWrite((BdPtr), XLLDMA_BD_BUFL_OFFSET, (LenBytes)) + + +/*****************************************************************************/ +/** + * Retrieve the BD length field. + * + * For TX channels, the returned value is the same as that written with + * XLlDma_mBdSetLength(). + * + * For RX channels, the returned value is what was written by the DMA engine + * after processing the BD. This value represents the number of bytes + * processed. + * + * @param BdPtr is the BD to operate on + * + * @return Bytes processed by hardware or set by XLlDma_mBdSetLength(). + * + * @note + * C-style signature: + * u32 XLlDma_mBdGetLength(XLlDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XLlDma_mBdGetLength(BdPtr) \ + XLlDma_mBdRead((BdPtr), XLLDMA_BD_BUFL_OFFSET) + + +/*****************************************************************************/ +/** + * Set the ID field of the given BD. The ID is an arbitrary piece of data the + * application can associate with a specific BD. + * + * @param BdPtr is the BD to operate on + * @param Id is a 32 bit quantity to set in the BD + * + * @note + * C-style signature: + * void XLlDma_mBdSetId(XLlDma_Bd* BdPtr, void Id) + * + *****************************************************************************/ +#define XLlDma_mBdSetId(BdPtr, Id) \ + (XLlDma_mBdWrite((BdPtr), XLLDMA_BD_ID_OFFSET, (u32)(Id))) + + +/*****************************************************************************/ +/** + * Retrieve the ID field of the given BD previously set with XLlDma_mBdSetId. + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * u32 XLlDma_mBdGetId(XLlDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XLlDma_mBdGetId(BdPtr) (XLlDma_mBdRead((BdPtr), XLLDMA_BD_ID_OFFSET)) + + +/*****************************************************************************/ +/** + * Set the BD's buffer address. + * + * @param BdPtr is the BD to operate on + * @param Addr is the address to set + * + * @note + * C-style signature: + * void XLlDma_mBdSetBufAddr(XLlDma_Bd* BdPtr, u32 Addr) + * + *****************************************************************************/ +#define XLlDma_mBdSetBufAddr(BdPtr, Addr) \ + (XLlDma_mBdWrite((BdPtr), XLLDMA_BD_BUFA_OFFSET, (u32)(Addr))) + + +/*****************************************************************************/ +/** + * Get the BD's buffer address + * + * @param BdPtr is the BD to operate on + * + * @note + * C-style signature: + * u32 XLlDma_mBdGetBufAddrLow(XLlDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XLlDma_mBdGetBufAddr(BdPtr) \ + (XLlDma_mBdRead((BdPtr), XLLDMA_BD_BUFA_OFFSET)) + + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_bdring.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_bdring.c 2014-07-20 22:06:39.082260754 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xlldma_bdring.c +* +* This file implements buffer descriptor ring related functions. For more +* information on this driver, see xlldma.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a xd 12/21/06 First release +* </pre> +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include <linux/string.h> + +#include "xlldma.h" +#include "xenv.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/****************************************************************************** + * Define methods to flush and invalidate cache for BDs should they be + * located in cached memory. These macros may NOPs if the underlying + * XCACHE_FLUSH_DCACHE_RANGE and XCACHE_INVALIDATE_DCACHE_RANGE macros are not + * implemented or they do nothing. + *****************************************************************************/ +#ifdef XCACHE_FLUSH_DCACHE_RANGE +# define XLLDMA_CACHE_FLUSH(BdPtr) \ + XCACHE_FLUSH_DCACHE_RANGE((BdPtr), XLLDMA_BD_HW_NUM_BYTES) +#else +# define XLLDMA_CACHE_FLUSH(BdPtr) +#endif + +#ifdef XCACHE_INVALIDATE_DCACHE_RANGE +# define XLLDMA_CACHE_INVALIDATE(BdPtr) \ + XCACHE_INVALIDATE_DCACHE_RANGE((BdPtr), XLLDMA_BD_HW_NUM_BYTES) +#else +# define XLLDMA_CACHE_INVALIDATE(BdPtr) +#endif + +/****************************************************************************** + * Compute the virtual address of a descriptor from its physical address + * + * @param BdPtr is the physical address of the BD + * + * @returns Virtual address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + * @note RingPtr is an implicit parameter + *****************************************************************************/ +#define XLLDMA_PHYS_TO_VIRT(BdPtr) \ + ((u32)(BdPtr) + (RingPtr->FirstBdAddr - RingPtr->FirstBdPhysAddr)) + +/****************************************************************************** + * Compute the physical address of a descriptor from its virtual address + * + * @param BdPtr is the virtual address of the BD + * + * @returns Physical address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + * @note RingPtr is an implicit parameter + *****************************************************************************/ +#define XLLDMA_VIRT_TO_PHYS(BdPtr) \ + ((u32)(BdPtr) - (RingPtr->FirstBdAddr - RingPtr->FirstBdPhysAddr)) + +/****************************************************************************** + * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around + * to the beginning of the ring if needed. + * + * We know if a wraparound should occur if the new BdPtr is greater than + * the high address in the ring OR if the new BdPtr crosses the 0xFFFFFFFF + * to 0 boundary. + * + * @param RingPtr is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + *****************************************************************************/ +#define XLLDMA_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)(BdPtr); \ + \ + Addr += ((RingPtr)->Separation * (NumBd)); \ + if ((Addr > (RingPtr)->LastBdAddr) || ((u32)(BdPtr) > Addr))\ + { \ + Addr -= (RingPtr)->Length; \ + } \ + \ + (BdPtr) = (XLlDma_Bd*)Addr; \ + } + +/****************************************************************************** + * Move the BdPtr argument backwards an arbitrary number of BDs wrapping + * around to the end of the ring if needed. + * + * We know if a wraparound should occur if the new BdPtr is less than + * the base address in the ring OR if the new BdPtr crosses the 0xFFFFFFFF + * to 0 boundary. + * + * @param RingPtr is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + *****************************************************************************/ +#define XLLDMA_RING_SEEKBACK(RingPtr, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)(BdPtr); \ + \ + Addr -= ((RingPtr)->Separation * (NumBd)); \ + if ((Addr < (RingPtr)->FirstBdAddr) || ((u32)(BdPtr) < Addr)) \ + { \ + Addr += (RingPtr)->Length; \ + } \ + \ + (BdPtr) = (XLlDma_Bd*)Addr; \ + } + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** + * Using a memory segment allocated by the caller, create and setup the BD list + * for the given SGDMA ring. + * + * @param InstancePtr is the instance to be worked on. + * @param PhysAddr is the physical base address of application memory region. + * @param VirtAddr is the virtual base address of the application memory + * region.If address translation is not being utilized, then VirtAddr + * should be equivalent to PhysAddr. + * @param Alignment governs the byte alignment of individual BDs. This function + * will enforce a minimum alignment of XLLDMA_BD_MINIMUM_ALIGNMENT bytes + * with no maximum as long as it is specified as a power of 2. + * @param BdCount is the number of BDs to setup in the application memory + * region. It is assumed the region is large enough to contain the BDs. + * Refer to the "SGDMA Ring Creation" section in xlldma.h for more + * information. The minimum valid value for this parameter is 1. + * + * @return + * + * - XST_SUCCESS if initialization was successful + * - XST_NO_FEATURE if the provided instance is a non SGDMA type of DMA + * channel. + * - XST_INVALID_PARAM under any of the following conditions: 1) PhysAddr + * and/or VirtAddr are not aligned to the given Alignment parameter; + * 2) Alignment parameter does not meet minimum requirements or is not a + * power of 2 value; 3) BdCount is 0. + * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans + * over address 0x00000000 in virtual address space. + * + *****************************************************************************/ +int XLlDma_BdRingCreate(XLlDma_BdRing * RingPtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, unsigned BdCount) +{ + unsigned i; + u32 BdVirtAddr; + u32 BdPhysAddr; + + /* In case there is a failure prior to creating list, make sure the + * following attributes are 0 to prevent calls to other SG functions + * from doing anything + */ + RingPtr->AllCnt = 0; + RingPtr->FreeCnt = 0; + RingPtr->HwCnt = 0; + RingPtr->PreCnt = 0; + RingPtr->PostCnt = 0; + + /* Make sure Alignment parameter meets minimum requirements */ + if (Alignment < XLLDMA_BD_MINIMUM_ALIGNMENT) { + return (XST_INVALID_PARAM); + } + + /* Make sure Alignment is a power of 2 */ + if ((Alignment - 1) & Alignment) { + return (XST_INVALID_PARAM); + } + + /* Make sure PhysAddr and VirtAddr are on same Alignment */ + if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) { + return (XST_INVALID_PARAM); + } + + /* Is BdCount reasonable? */ + if (BdCount == 0) { + return (XST_INVALID_PARAM); + } + + /* Compute how many bytes will be between the start of adjacent BDs */ + RingPtr->Separation = + (sizeof(XLlDma_Bd) + (Alignment - 1)) & ~(Alignment - 1); + + /* Must make sure the ring doesn't span address 0x00000000. If it does, + * then the next/prev BD traversal macros will fail. + */ + if (VirtAddr > (VirtAddr + (RingPtr->Separation * BdCount) - 1)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Initial ring setup: + * - Clear the entire space + * - Setup each BD's next pointer with the physical address of the + * next BD + * - Set each BD's DMA complete status bit + */ + memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount)); + + BdVirtAddr = VirtAddr; + BdPhysAddr = PhysAddr + RingPtr->Separation; + for (i = 1; i < BdCount; i++) { + XLlDma_mBdWrite(BdVirtAddr, XLLDMA_BD_NDESC_OFFSET, BdPhysAddr); + XLlDma_mBdWrite(BdVirtAddr, XLLDMA_BD_STSCTRL_USR0_OFFSET, + XLLDMA_BD_STSCTRL_COMPLETED_MASK); + XLLDMA_CACHE_FLUSH(BdVirtAddr); + BdVirtAddr += RingPtr->Separation; + BdPhysAddr += RingPtr->Separation; + } + + /* At the end of the ring, link the last BD back to the top */ + XLlDma_mBdWrite(BdVirtAddr, XLLDMA_BD_NDESC_OFFSET, PhysAddr); + XLLDMA_CACHE_FLUSH(BdVirtAddr); + + /* Setup and initialize pointers and counters */ + RingPtr->RunState = XST_DMA_SG_IS_STOPPED; + RingPtr->FirstBdAddr = VirtAddr; + RingPtr->FirstBdPhysAddr = PhysAddr; + RingPtr->LastBdAddr = BdVirtAddr; + RingPtr->Length = RingPtr->LastBdAddr - RingPtr->FirstBdAddr + + RingPtr->Separation; + RingPtr->AllCnt = BdCount; + RingPtr->FreeCnt = BdCount; + RingPtr->FreeHead = (XLlDma_Bd *) VirtAddr; + RingPtr->PreHead = (XLlDma_Bd *) VirtAddr; + RingPtr->HwHead = (XLlDma_Bd *) VirtAddr; + RingPtr->HwTail = (XLlDma_Bd *) VirtAddr; + RingPtr->PostHead = (XLlDma_Bd *) VirtAddr; + RingPtr->BdaRestart = (XLlDma_Bd *) PhysAddr; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Clone the given BD into every BD in the ring. Except for + * XLLDMA_BD_NDESC_OFFSET, every field of the source BD is replicated in every + * BD in the ring. + * + * This function can be called only when all BDs are in the free group such as + * they are immediately after creation of the ring. This prevents modification + * of BDs while they are in use by hardware or the application. + * + * @param InstancePtr is the instance to be worked on. + * @param SrcBdPtr is the source BD template to be cloned into the list. + * + * @return + * - XST_SUCCESS if the list was modified. + * - XST_DMA_SG_NO_LIST if a list has not been created. + * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under + * hardware or application control. + * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped. + * + *****************************************************************************/ +int XLlDma_BdRingClone(XLlDma_BdRing * RingPtr, XLlDma_Bd * SrcBdPtr) +{ + unsigned i; + u32 CurBd; + u32 Save; + XLlDma_Bd TmpBd; + + /* Can't do this function if there isn't a ring */ + if (RingPtr->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Can't do this function with the channel running */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Can't do this function with some of the BDs in use */ + if (RingPtr->FreeCnt != RingPtr->AllCnt) { + return (XST_DMA_SG_LIST_ERROR); + } + + + /* Make a copy of the template then modify it by setting complete bit + * in status/control field + */ + memcpy(&TmpBd, SrcBdPtr, sizeof(XLlDma_Bd)); + Save = XLlDma_mBdRead(&TmpBd, XLLDMA_BD_STSCTRL_USR0_OFFSET); + Save |= XLLDMA_BD_STSCTRL_COMPLETED_MASK; + XLlDma_mBdWrite(&TmpBd, XLLDMA_BD_STSCTRL_USR0_OFFSET, Save); + + /* Starting from the top of the ring, save BD.Next, overwrite the + * entire BD with the template, then restore BD.Next + */ + for (i = 0, CurBd = RingPtr->FirstBdAddr; + i < RingPtr->AllCnt; i++, CurBd += RingPtr->Separation) { + Save = XLlDma_mBdRead(CurBd, XLLDMA_BD_NDESC_OFFSET); + memcpy((void *) CurBd, (void *) &TmpBd, sizeof(XLlDma_Bd)); + XLlDma_mBdWrite(CurBd, XLLDMA_BD_NDESC_OFFSET, Save); + XLLDMA_CACHE_FLUSH(CurBd); + } + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Allow DMA transactions to commence on the given channels if descriptors are + * ready to be processed. + * + * @param RingPtr is a pointer to the descriptor ring instance to be worked on. + * + * @return + * - XST_SUCCESS if the channel) were started. + * - XST_DMA_SG_NO_LIST if the channel) have no initialized BD ring. + * + *****************************************************************************/ +int XLlDma_BdRingStart(XLlDma_BdRing * RingPtr) +{ + /* BD list has yet to be created for this channel */ + if (RingPtr->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Do nothing if already started */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_SUCCESS); + } + + /* Sync hardware and driver with the last unprocessed BD or the 1st BD + * in the ring if this is the first time starting the channel + */ + XLlDma_mWriteReg(RingPtr->ChanBase, XLLDMA_CDESC_OFFSET, + (u32) RingPtr->BdaRestart); + + /* Note as started */ + RingPtr->RunState = XST_DMA_SG_IS_STARTED; + + /* If there are unprocessed BDs then we want to channel to begin + * processing right away + */ + if (RingPtr->HwCnt > 0) { + XLLDMA_CACHE_INVALIDATE(RingPtr->HwTail); + + if ((XLlDma_mBdRead(RingPtr->HwTail, + XLLDMA_BD_STSCTRL_USR0_OFFSET) & + XLLDMA_BD_STSCTRL_COMPLETED_MASK) == 0) { + XLlDma_mWriteReg(RingPtr->ChanBase, + XLLDMA_TDESC_OFFSET, + XLLDMA_VIRT_TO_PHYS(RingPtr->HwTail)); + } + } + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Set interrupt coalescing parameters for the given descriptor ring channel. + * + * @param RingPtr is a pointer to the descriptor ring instance to be worked on. + * @param Counter sets the packet counter on the channel. Valid range is + * 1..255, or XLLDMA_NO_CHANGE to leave this setting unchanged. + * @param Timer sets the waitbound timer on the channel. Valid range is + * 1..255, or XLLDMA_NO_CHANGE to leave this setting unchanged. LSB is + * in units of 1 / (local link clock). + * + * @return + * - XST_SUCCESS if interrupt coalescing settings updated + * - XST_FAILURE if Counter or Timer parameters are out of range + *****************************************************************************/ +int XLlDma_BdRingSetCoalesce(XLlDma_BdRing * RingPtr, u32 Counter, u32 Timer) +{ + u32 Cr = XLlDma_mReadReg(RingPtr->ChanBase, XLLDMA_CR_OFFSET); + + if (Counter != XLLDMA_NO_CHANGE) { + if ((Counter == 0) || (Counter > 0xFF)) { + return (XST_FAILURE); + } + + Cr = (Cr & ~XLLDMA_CR_IRQ_COUNT_MASK) | + (Counter << XLLDMA_CR_IRQ_COUNT_SHIFT); + Cr |= XLLDMA_CR_LD_IRQ_CNT_MASK; + } + + if (Timer != XLLDMA_NO_CHANGE) { + if ((Timer == 0) || (Timer > 0xFF)) { + return (XST_FAILURE); + } + + Cr = (Cr & ~XLLDMA_CR_IRQ_TIMEOUT_MASK) | + (Timer << XLLDMA_CR_IRQ_TIMEOUT_SHIFT); + Cr |= XLLDMA_CR_LD_IRQ_CNT_MASK; + } + + XLlDma_mWriteReg(RingPtr->ChanBase, XLLDMA_CR_OFFSET, Cr); + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Retrieve current interrupt coalescing parameters from the given descriptor + * ring channel. + * + * @param RingPtr is a pointer to the descriptor ring instance to be worked on. + * @param CounterPtr points to a memory location where the current packet + * counter will be written. + * @param TimerPtr points to a memory location where the current waitbound + * timer will be written. + *****************************************************************************/ +void XLlDma_BdRingGetCoalesce(XLlDma_BdRing * RingPtr, + u32 *CounterPtr, u32 *TimerPtr) +{ + u32 Cr = XLlDma_mReadReg(RingPtr->ChanBase, XLLDMA_CR_OFFSET); + + *CounterPtr = + ((Cr & XLLDMA_CR_IRQ_COUNT_MASK) >> XLLDMA_CR_IRQ_COUNT_SHIFT); + *TimerPtr = + ((Cr & XLLDMA_CR_IRQ_TIMEOUT_MASK) >> + XLLDMA_CR_IRQ_TIMEOUT_SHIFT); +} + + +/*****************************************************************************/ +/** + * Reserve locations in the BD ring. The set of returned BDs may be modified in + * preparation for future DMA transactions). Once the BDs are ready to be + * submitted to hardware, the application must call XLlDma_BdRingToHw() in the + * same order which they were allocated here. Example: + * + * <pre> + * NumBd = 2; + * Status = XDsma_RingBdAlloc(MyRingPtr, NumBd, &MyBdSet); + * + * if (Status != XST_SUCCESS) + * { + * // Not enough BDs available for the request + * } + * + * CurBd = MyBdSet; + * for (i=0; i<NumBd; i++) + * { + * // Prepare CurBd..... + * + * // Onto next BD + * CurBd = XLlDma_mBdRingNext(MyRingPtr, CurBd); + * } + * + * // Give list to hardware + * Status = XLlDma_BdRingToHw(MyRingPtr, NumBd, MyBdSet); + * </pre> + * + * A more advanced use of this function may allocate multiple sets of BDs. + * They must be allocated and given to hardware in the correct sequence: + * <pre> + * // Legal + * XLlDma_BdRingAlloc(MyRingPtr, NumBd1, &MySet1); + * XLlDma_BdRingToHw(MyRingPtr, NumBd1, MySet1); + * + * // Legal + * XLlDma_BdRingAlloc(MyRingPtr, NumBd1, &MySet1); + * XLlDma_BdRingAlloc(MyRingPtr, NumBd2, &MySet2); + * XLlDma_BdRingToHw(MyRingPtr, NumBd1, MySet1); + * XLlDma_BdRingToHw(MyRingPtr, NumBd2, MySet2); + * + * // Not legal + * XLlDma_BdRingAlloc(MyRingPtr, NumBd1, &MySet1); + * XLlDma_BdRingAlloc(MyRingPtr, NumBd2, &MySet2); + * XLlDma_BdRingToHw(MyRingPtr, NumBd2, MySet2); + * XLlDma_BdRingToHw(MyRingPtr, NumBd1, MySet1); + * </pre> + * + * Use the API defined in xlldmabd.h to modify individual BDs. Traversal of the + * BD set can be done using XLlDma_mBdRingNext() and XLlDma_mBdRingPrev(). + * + * @param RingPtr is a pointer to the descriptor ring instance to be worked on. + * @param NumBd is the number of BDs to allocate + * @param BdSetPtr is an output parameter, it points to the first BD available + * for modification. + * + * @return + * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr + * parameter. + * - XST_FAILURE if there were not enough free BDs to satisfy the request. + * + * @note This function should not be preempted by another XLlDma_BdRing + * function call that modifies the BD space. It is the caller's + * responsibility to provide a mutual exclusion mechanism. + * + * @note Do not modify more BDs than the number requested with the NumBd + * parameter. Doing so will lead to data corruption and system + * instability. + * + *****************************************************************************/ +int XLlDma_BdRingAlloc(XLlDma_BdRing * RingPtr, unsigned NumBd, + XLlDma_Bd ** BdSetPtr) +{ + /* Enough free BDs available for the request? */ + if (RingPtr->FreeCnt < NumBd) { + return (XST_FAILURE); + } + + /* Set the return argument and move FreeHead forward */ + *BdSetPtr = RingPtr->FreeHead; + XLLDMA_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd); + RingPtr->FreeCnt -= NumBd; + RingPtr->PreCnt += NumBd; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Fully or partially undo an XLlDma_BdRingAlloc() operation. Use this function + * if all the BDs allocated by XLlDma_BdRingAlloc() could not be transferred to + * hardware with XLlDma_BdRingToHw(). + * + * This function helps out in situations when an unrelated error occurs after + * BDs have been allocated but before they have been given to hardware. + * + * This function is not the same as XLlDma_BdRingFree(). The Free function + * returns BDs to the free list after they have been processed by hardware, + * while UnAlloc returns them before being processed by hardware. + * + * There are two scenarios where this function can be used. Full UnAlloc or + * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned: + * + * <pre> + * Status = XLlDma_BdRingAlloc(MyRingPtr, 10, &BdPtr); + * . + * . + * if (Error) + * { + * Status = XLlDma_BdRingUnAlloc(MyRingPtr, 10, &BdPtr); + * } + * </pre> + * + * A partial UnAlloc means some of the BDs Alloc'd will be returned: + * + * <pre> + * Status = XLlDma_BdRingAlloc(MyRingPtr, 10, &BdPtr); + * BdsLeft = 10; + * CurBdPtr = BdPtr; + * + * while (BdsLeft) + * { + * if (Error) + * { + * Status = XLlDma_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr); + * } + * + * CurBdPtr = XLlDma_mBdRingNext(MyRingPtr, CurBdPtr); + * BdsLeft--; + * } + * </pre> + * + * A partial UnAlloc must include the last BD in the list that was Alloc'd. + * + * @param RingPtr is a pointer to the descriptor ring instance to be worked on. + * @param NumBd is the number of BDs to unallocate + * @param BdSetPtr points to the first of the BDs to be returned. + * + * @return + * - XST_SUCCESS if the BDs were unallocated. + * - XST_FAILURE if NumBd parameter was greater that the number of BDs in the + * preprocessing state. + * + * @note This function should not be preempted by another XLlDma ring function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XLlDma_BdRingUnAlloc(XLlDma_BdRing * RingPtr, unsigned NumBd, + XLlDma_Bd * BdSetPtr) +{ + /* Enough BDs in the free state for the request? */ + if (RingPtr->PreCnt < NumBd) { + return (XST_FAILURE); + } + + /* Set the return argument and move FreeHead backward */ + XLLDMA_RING_SEEKBACK(RingPtr, RingPtr->FreeHead, NumBd); + RingPtr->FreeCnt += NumBd; + RingPtr->PreCnt -= NumBd; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Enqueue a set of BDs to hardware that were previously allocated by + * XLlDma_BdRingAlloc(). Once this function returns, the argument BD set goes + * under hardware control. Any changes made to these BDs after this point will + * corrupt the BD list leading to data corruption and system instability. + * + * The set will be rejected if the last BD of the set does not mark the end of + * a packet. + * + * @param RingPtr is a pointer to the descriptor ring instance to be worked on. + * @param NumBd is the number of BDs in the set. + * @param BdSetPtr is the first BD of the set to commit to hardware. + * + * @return + * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware + * - XST_FAILURE if the set of BDs was rejected because the first BD + * did not have its start-of-packet bit set, the last BD did not have + * its end-of-packet bit set, or any one of the BD set has 0 as length + * value + * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with + * XLlDma_BdRingAlloc() + * + * @note This function should not be preempted by another XLlDma ring function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XLlDma_BdRingToHw(XLlDma_BdRing * RingPtr, unsigned NumBd, + XLlDma_Bd * BdSetPtr) +{ + XLlDma_Bd *CurBdPtr; + unsigned i; + u32 BdStsCr; + + /* If the commit set is empty, do nothing */ + if (NumBd == 0) { + return (XST_SUCCESS); + } + + /* Make sure we are in sync with XLlDma_BdRingAlloc() */ + if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + CurBdPtr = BdSetPtr; + BdStsCr = XLlDma_mBdRead(CurBdPtr, XLLDMA_BD_STSCTRL_USR0_OFFSET); + + /* The first BD should have been marked as start-of-packet */ + if (!(BdStsCr & XLLDMA_BD_STSCTRL_SOP_MASK)) { + return (XST_FAILURE); + } + + /* For each BD being submitted except the last one, clear the completed + * bit and stop_on_end bit in the status word + */ + for (i = 0; i < NumBd - 1; i++) { + + /* Make sure the length value in the BD is non-zero. */ + if (XLlDma_mBdGetLength(CurBdPtr) == 0) { + return (XST_FAILURE); + } + + BdStsCr &= + ~(XLLDMA_BD_STSCTRL_COMPLETED_MASK | + XLLDMA_BD_STSCTRL_SOE_MASK); + XLlDma_mBdWrite(CurBdPtr, XLLDMA_BD_STSCTRL_USR0_OFFSET, + BdStsCr); + + /* In RX channel case, the current BD should have the + * XLLDMA_USERIP_APPWORD_OFFSET initialized to + * XLLDMA_USERIP_APPWORD_INITVALUE + */ + if (RingPtr->IsRxChannel) { + XLlDma_mBdWrite(CurBdPtr, XLLDMA_USERIP_APPWORD_OFFSET, + XLLDMA_USERIP_APPWORD_INITVALUE); + } + + /* Flush the current BD so DMA core could see the updates */ + XLLDMA_CACHE_FLUSH(CurBdPtr); + + CurBdPtr = XLlDma_mBdRingNext(RingPtr, CurBdPtr); + BdStsCr = + XLlDma_mBdRead(CurBdPtr, XLLDMA_BD_STSCTRL_USR0_OFFSET); + } + + /* The last BD should have end-of-packet bit set */ + if (!(BdStsCr & XLLDMA_BD_STSCTRL_EOP_MASK)) { + return (XST_FAILURE); + } + + /* Make sure the length value in the last BD is non-zero. */ + if (XLlDma_mBdGetLength(CurBdPtr) == 0) { + return (XST_FAILURE); + } + + /* The last BD should also have the completed and stop-on-end bits + * cleared + */ + BdStsCr &= + ~(XLLDMA_BD_STSCTRL_COMPLETED_MASK | + XLLDMA_BD_STSCTRL_SOE_MASK); + XLlDma_mBdWrite(CurBdPtr, XLLDMA_BD_STSCTRL_USR0_OFFSET, BdStsCr); + + /* In RX channel case, the last BD should have the + * XLLDMA_USERIP_APPWORD_OFFSET initialized to + * XLLDMA_USERIP_APPWORD_INITVALUE + */ + if (RingPtr->IsRxChannel) { + XLlDma_mBdWrite(CurBdPtr, XLLDMA_USERIP_APPWORD_OFFSET, + XLLDMA_USERIP_APPWORD_INITVALUE); + } + + /* Flush the last BD so DMA core could see the updates */ + XLLDMA_CACHE_FLUSH(CurBdPtr); + + /* This set has completed pre-processing, adjust ring pointers and + * counters + */ + XLLDMA_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd); + RingPtr->PreCnt -= NumBd; + RingPtr->HwTail = CurBdPtr; + RingPtr->HwCnt += NumBd; + + /* If it was enabled, tell the engine to begin processing */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + XLlDma_mWriteReg(RingPtr->ChanBase, XLLDMA_TDESC_OFFSET, + XLLDMA_VIRT_TO_PHYS(RingPtr->HwTail)); + } + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Returns a set of BD(s) that have been processed by hardware. The returned + * BDs may be examined by the application to determine the outcome of the DMA + * transactions). Once the BDs have been examined, the application must call + * XLlDma_BdRingFree() in the same order which they were retrieved here. + * + * Example: + * + * <pre> + * NumBd = XLlDma_BdRingFromHw(MyRingPtr, XLLDMA_ALL_BDS, &MyBdSet); + * + * if (NumBd == 0) + * { + * // hardware has nothing ready for us yet + * } + * + * CurBd = MyBdSet; + * for (i=0; i<NumBd; i++) + * { + * // Examine CurBd for post processing..... + * + * // Onto next BD + * CurBd = XLlDma_mBdRingNext(MyRingPtr, CurBd); + * } + * + * XLlDma_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return the list + * </pre> + * + * A more advanced use of this function may allocate multiple sets of BDs. + * They must be retrieved from hardware and freed in the correct sequence: + * <pre> + * // Legal + * XLlDma_BdRingFromHw(MyRingPtr, NumBd1, &MySet1); + * XLlDma_BdRingFree(MyRingPtr, NumBd1, MySet1); + * + * // Legal + * XLlDma_BdRingFromHw(MyRingPtr, NumBd1, &MySet1); + * XLlDma_BdRingFromHw(MyRingPtr, NumBd2, &MySet2); + * XLlDma_BdRingFree(MyRingPtr, NumBd1, MySet1); + * XLlDma_BdRingFree(MyRingPtr, NumBd2, MySet2); + * + * // Not legal + * XLlDma_BdRingFromHw(MyRingPtr, NumBd1, &MySet1); + * XLlDma_BdRingFromHw(MyRingPtr, NumBd2, &MySet2); + * XLlDma_BdRingFree(MyRingPtr, NumBd2, MySet2); + * XLlDma_BdRingFree(MyRingPtr, NumBd1, MySet1); + * </pre> + * + * If hardware has partially completed a packet spanning multiple BDs, then + * none of the BDs for that packet will be included in the results. + * + * @param RingPtr is a pointer to the descriptor ring instance to be worked on. + * @param BdLimit is the maximum number of BDs to return in the set. Use + * XLLDMA_ALL_BDS to return all BDs that have been processed. + * @param BdSetPtr is an output parameter, it points to the first BD available + * for examination. + * + * @return + * The number of BDs processed by hardware. A value of 0 indicates that no + * data is available. No more than BdLimit BDs will be returned. + * + * @note Treat BDs returned by this function as read-only. + * + * @note This function should not be preempted by another XLlDma ring function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +unsigned XLlDma_BdRingFromHw(XLlDma_BdRing * RingPtr, unsigned BdLimit, + XLlDma_Bd ** BdSetPtr) +{ + XLlDma_Bd *CurBdPtr; + unsigned BdCount; + unsigned BdPartialCount; + u32 BdStsCr; + u32 UserIpAppWord; + + CurBdPtr = RingPtr->HwHead; + BdCount = 0; + BdPartialCount = 0; + + /* If no BDs in work group, then there's nothing to search */ + if (RingPtr->HwCnt == 0) { + *BdSetPtr = NULL; + return (0); + } + + /* Starting at HwHead, keep moving forward in the list until: + * - A BD is encountered with its completed bit clear in the status + * word which means hardware has not completed processing of that + * BD. + * - A BD is encountered with its XLLDMA_USERIP_APPWORD_OFFSET field + * with value XLLDMA_USERIP_APPWORD_INITVALUE which means hardware + * has not completed updating the BD structure. + * - RingPtr->HwTail is reached + * - The number of requested BDs has been processed + */ + while (BdCount < BdLimit) { + /* Read the status */ + XLLDMA_CACHE_INVALIDATE(CurBdPtr); + BdStsCr = XLlDma_mBdRead(CurBdPtr, + XLLDMA_BD_STSCTRL_USR0_OFFSET); + + /* If the hardware still hasn't processed this BD then we are + * done + */ + if (!(BdStsCr & XLLDMA_BD_STSCTRL_COMPLETED_MASK)) { + break; + } + + /* In RX channel case, check if XLLDMA_USERIP_APPWORD_OFFSET + * field of the BD has been updated. If not, RX channel has + * not completed updating the BD structure and we delay + * the processing of this BD to next time + */ + if (RingPtr->IsRxChannel) { + UserIpAppWord = XLlDma_mBdRead(CurBdPtr, + XLLDMA_USERIP_APPWORD_OFFSET); + if (UserIpAppWord == XLLDMA_USERIP_APPWORD_INITVALUE) { + break; + } + } + + + BdCount++; + + /* Hardware has processed this BD so check the "last" bit. If + * it is clear, then there are more BDs for the current packet. + * Keep a count of these partial packet BDs. + */ + if (BdStsCr & XLLDMA_BD_STSCTRL_EOP_MASK) { + BdPartialCount = 0; + } + else { + BdPartialCount++; + } + + /* Reached the end of the work group */ + if (CurBdPtr == RingPtr->HwTail) { + break; + } + + /* Move on to next BD in work group */ + CurBdPtr = XLlDma_mBdRingNext(RingPtr, CurBdPtr); + } + + /* Subtract off any partial packet BDs found */ + BdCount -= BdPartialCount; + + /* If BdCount is non-zero then BDs were found to return. Set return + * parameters, update pointers and counters, return success + */ + if (BdCount) { + *BdSetPtr = RingPtr->HwHead; + RingPtr->HwCnt -= BdCount; + RingPtr->PostCnt += BdCount; + XLLDMA_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount); + return (BdCount); + } + else { + *BdSetPtr = NULL; + return (0); + } +} + + +/*****************************************************************************/ +/** + * Frees a set of BDs that had been previously retrieved with + * XLlDma_BdRingFromHw(). + * + * @param RingPtr is a pointer to the descriptor ring instance to be worked on. + * @param NumBd is the number of BDs to free. + * @param BdSetPtr is the head of a list of BDs returned by + * XLlDma_BdRingFromHw(). + * + * @return + * - XST_SUCCESS if the set of BDs was freed. + * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with + * XLlDma_BdRingFromHw(). + * + * @note This function should not be preempted by another XLlDma function call + * that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + * @internal + * This Interrupt handler provided by application MUST clear pending + * interrupts before handling them by calling the call back. Otherwise + * the following corner case could raise some issue: + * + * - A packet was transmitted and asserted an TX interrupt, and if + * this interrupt handler calls the call back before clears the + * interrupt, another packet could get transmitted (and assert the + * interrupt) between when the call back function returned and when + * the interrupt clearing operation begins, and the interrupt + * clearing operation will clear the interrupt raised by the second + * packet and won't never process its according buffer descriptors + * until a new interrupt occurs. + * + * Changing the sequence to "Clear interrupts, then handle" solve this + * issue. If the interrupt raised by the second packet is before the + * the interrupt clearing operation, the descriptors associated with + * the second packet must have been finished by hardware and ready for + * the handling by the call back; otherwise, the interrupt raised by + * the second packet is after the interrupt clearing operation, + * the packet's buffer descriptors will be handled by the call back in + * current pass, if the descriptors are finished before the call back + * is invoked, or next pass otherwise. + * + * Please note that if the second packet is handled by the call back + * in current pass, the next pass could find no buffer descriptor + * finished by the hardware. (i.e., XLlDma_BdRingFromHw() returns 0). + * As XLlDma_BdRingFromHw() and XLlDma_BdRingFree() are used in pair, + * XLlDma_BdRingFree() covers this situation by checking if the BD + * list to free is empty + *****************************************************************************/ +int XLlDma_BdRingFree(XLlDma_BdRing * RingPtr, unsigned NumBd, + XLlDma_Bd * BdSetPtr) +{ + /* If the BD Set to free is empty, return immediately with value + * XST_SUCCESS. See the @internal comment block above for detailed + * information + */ + if (NumBd == 0) { + return XST_SUCCESS; + } + + /* Make sure we are in sync with XLlDma_BdRingFromHw() */ + if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Update pointers and counters */ + RingPtr->FreeCnt += NumBd; + RingPtr->PostCnt -= NumBd; + XLLDMA_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Check the internal data structures of the BD ring for the provided channel. + * The following checks are made: + * + * - Is the BD ring linked correctly in physical address space. + * - Do the internal pointers point to BDs in the ring. + * - Do the internal counters add up. + * + * The channel should be stopped prior to calling this function. + * + * @param RingPtr is a pointer to the descriptor ring to be worked on. + * + * @return + * - XST_SUCCESS if no errors were found. + * - XST_DMA_SG_NO_LIST if the ring has not been created. + * - XST_IS_STARTED if the channel is not stopped. + * - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data + * structures. If this value is returned, the channel should be reset to + * avoid data corruption or system instability. + * + * @note This function should not be preempted by another XLlDma ring function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XLlDma_BdRingCheck(XLlDma_BdRing * RingPtr) +{ + u32 AddrV, AddrP; + unsigned i; + + /* Is the list created */ + if (RingPtr->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Can't check if channel is running */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_IS_STARTED); + } + + /* RunState doesn't make sense */ + else if (RingPtr->RunState != XST_DMA_SG_IS_STOPPED) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify internal pointers point to correct memory space */ + AddrV = (u32) RingPtr->FreeHead; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->PreHead; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->HwHead; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->HwTail; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->PostHead; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify internal counters add up */ + if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt + + RingPtr->PostCnt) != RingPtr->AllCnt) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify BDs are linked correctly */ + AddrV = RingPtr->FirstBdAddr; + AddrP = RingPtr->FirstBdPhysAddr + RingPtr->Separation; + for (i = 1; i < RingPtr->AllCnt; i++) { + XLLDMA_CACHE_INVALIDATE(AddrV); + /* Check next pointer for this BD. It should equal to the + * physical address of next BD + */ + if (XLlDma_mBdRead(AddrV, XLLDMA_BD_NDESC_OFFSET) != AddrP) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Move on to next BD */ + AddrV += RingPtr->Separation; + AddrP += RingPtr->Separation; + } + + XLLDMA_CACHE_INVALIDATE(AddrV); + /* Last BD should point back to the beginning of ring */ + if (XLlDma_mBdRead(AddrV, XLLDMA_BD_NDESC_OFFSET) != + RingPtr->FirstBdPhysAddr) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* No problems found */ + return (XST_SUCCESS); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_bdring.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_bdring.h 2014-07-20 22:06:39.097260507 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xlldma_bdring.h +* +* This file contains DMA channel related structure and constant definition +* as well as function prototypes. Each DMA channel is managed by a Buffer +* Descriptor ring, and so XLlDma_BdRing is chosen as the symbol prefix used in +* this file. See xlldma.h for more information. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a xd 12/21/06 First release +* </pre> +* +******************************************************************************/ + +#ifndef XLLDMA_BDRING_H /* prevent circular inclusions */ +#define XLLDMA_BDRING_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xbasic_types.h" +#include "xstatus.h" +#include "xlldma_hw.h" +#include "xlldma_bd.h" + +/** Container structure for descriptor storage control. If address translation + * is enabled, then all addresses and pointers excluding FirstBdPhysAddr are + * expressed in terms of the virtual address. + */ +typedef struct { + u32 ChanBase; /**< Virtual base address of channel registers + */ + u32 IsRxChannel; /**< Is this a receive channel ? */ + u32 FirstBdPhysAddr; /**< Physical address of 1st BD in list */ + u32 FirstBdAddr; /**< Virtual address of 1st BD in list */ + u32 LastBdAddr; /**< Virtual address of last BD in the list */ + u32 Length; /**< Total size of ring in bytes */ + u32 RunState; /**< Flag to indicate channel is started */ + u32 Separation; /**< Number of bytes between the starting + address of adjacent BDs */ + XLlDma_Bd *FreeHead; /**< First BD in the free group */ + XLlDma_Bd *PreHead; /**< First BD in the pre-work group */ + XLlDma_Bd *HwHead; /**< First BD in the work group */ + XLlDma_Bd *HwTail; /**< Last BD in the work group */ + XLlDma_Bd *PostHead; /**< First BD in the post-work group */ + XLlDma_Bd *BdaRestart; /**< BD to load when channel is started */ + u32 FreeCnt; /**< Number of allocatable BDs in free group */ + u32 PreCnt; /**< Number of BDs in pre-work group */ + u32 HwCnt; /**< Number of BDs in work group */ + u32 PostCnt; /**< Number of BDs in post-work group */ + u32 AllCnt; /**< Total Number of BDs for channel */ +} XLlDma_BdRing; + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many BDs will fit +* within the given memory constraints. +* +* The results of this macro can be provided to XLlDma_BdRingCreate(). +* +* @param Alignment specifies what byte alignment the BDs must fall on and +* must be a power of 2 to get an accurate calculation (32, 64, 126,...) +* @param Bytes is the number of bytes to be used to store BDs. +* +* @return Number of BDs that can fit in the given memory area +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingCntCalc(u32 Alignment, u32 Bytes) +* +******************************************************************************/ +#define XLlDma_mBdRingCntCalc(Alignment, Bytes) \ + (u32)((Bytes)/((sizeof(XLlDma_Bd)+((Alignment)-1))&~((Alignment)-1))) + + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many bytes of memory +* are required to contain a given number of BDs at a given alignment. +* +* @param Alignment specifies what byte alignment the BDs must fall on. This +* parameter must be a power of 2 to get an accurate calculation (32, 64, +* 128,...) +* @param NumBd is the number of BDs to calculate memory size requirements for +* +* @return The number of bytes of memory required to create a BD list with the +* given memory constraints. +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingMemCalc(u32 Alignment, u32 NumBd) +* +******************************************************************************/ +#define XLlDma_mBdRingMemCalc(Alignment, NumBd) \ + (u32)((sizeof(XLlDma_Bd)+((Alignment)-1))&~((Alignment)-1))*(NumBd) + + +/****************************************************************************/ +/** +* Return the total number of BDs allocated by this channel with +* XLlDma_BdRingCreate(). +* +* @param RingPtr is the BD ring to operate on. +* +* @return The total number of BDs allocated for this channel. +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingGetCnt(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingGetCnt(RingPtr) ((RingPtr)->AllCnt) + + +/****************************************************************************/ +/** +* Return the number of BDs allocatable with XLlDma_BdRingAlloc() for pre- +* processing. +* +* @param RingPtr is the BD ring to operate on. +* +* @return The number of BDs currently allocatable. +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingGetFreeCnt(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingGetFreeCnt(RingPtr) ((RingPtr)->FreeCnt) + + +/****************************************************************************/ +/** +* Snap shot the latest BD a BD ring is processing. +* +* @param RingPtr is the BD ring to operate on. +* +* @return None +* +* @note +* C-style signature: +* void XLlDma_mBdRingSnapShotCurrBd(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingSnapShotCurrBd(RingPtr) \ + { \ + (RingPtr)->BdaRestart = \ + (XLlDma_Bd *)XLlDma_mReadReg((RingPtr)->ChanBase, \ + XLLDMA_CDESC_OFFSET); \ + } + + +/****************************************************************************/ +/** +* Return the next BD in the ring. +* +* @param RingPtr is the BD ring to operate on. +* @param BdPtr is the current BD. +* +* @return The next BD in the ring relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XLlDma_Bd *XLlDma_mBdRingNext(XLlDma_BdRing* RingPtr, XLlDma_Bd *BdPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingNext(RingPtr, BdPtr) \ + (((u32)(BdPtr) >= (RingPtr)->LastBdAddr) ? \ + (XLlDma_Bd*)(RingPtr)->FirstBdAddr : \ + (XLlDma_Bd*)((u32)(BdPtr) + (RingPtr)->Separation)) + + +/****************************************************************************/ +/** +* Return the previous BD in the ring. +* +* @param InstancePtr is the DMA channel to operate on. +* @param BdPtr is the current BD. +* +* @return The previous BD in the ring relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XLlDma_Bd *XLlDma_mBdRingPrev(XLlDma_BdRing* RingPtr, XLlDma_Bd *BdPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingPrev(RingPtr, BdPtr) \ + (((u32)(BdPtr) <= (RingPtr)->FirstBdAddr) ? \ + (XLlDma_Bd*)(RingPtr)->LastBdAddr : \ + (XLlDma_Bd*)((u32)(BdPtr) - (RingPtr)->Separation)) + +/****************************************************************************/ +/** +* Retrieve the contents of the channel status register XLLDMA_SR_OFFSET +* +* @param RingPtr is the channel instance to operate on. +* +* @return Current contents of SR_OFFSET +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingGetSr(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingGetSr(RingPtr) \ + XLlDma_mReadReg((RingPtr)->ChanBase, XLLDMA_SR_OFFSET) + + +/****************************************************************************/ +/** +* Retrieve the contents of the channel control register XLLDMA_CR_OFFSET +* +* @param RingPtr is the channel instance to operate on. +* +* @return Current contents of CR_OFFSET +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingGetCr(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingGetCr(RingPtr) \ + XLlDma_mReadReg((RingPtr)->ChanBase, XLLDMA_CR_OFFSET) + + +/****************************************************************************/ +/** +* Set the contents of the channel control register XLLDMA_CR_OFFSET. This +* register does not affect the other DMA channel. +* +* @param RingPtr is the channel instance to operate on. +* @param Data is the data to write to CR_OFFSET +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingSetCr(XLlDma_BdRing* RingPtr, u32 Data) +* +*****************************************************************************/ +#define XLlDma_mBdRingSetCr(RingPtr, Data) \ + XLlDma_mWriteReg((RingPtr)->ChanBase, XLLDMA_CR_OFFSET, (Data)) + + +/****************************************************************************/ +/** +* Check if the current DMA channel is busy with a DMA operation. +* +* @param RingPtr is the channel instance to operate on. +* +* @return TRUE if the DMA is busy. FALSE otherwise +* +* @note +* C-style signature: +* XBoolean XLlDma_mBdRingBusy(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingBusy(RingPtr) \ + ((XLlDma_mReadReg((RingPtr)->ChanBase, XLLDMA_SR_OFFSET) \ + & XLLDMA_SR_ENGINE_BUSY_MASK) ? TRUE : FALSE) + + +/****************************************************************************/ +/** +* Set interrupt enable bits for a channel. This operation will modify the +* XLLDMA_CR_OFFSET register. +* +* @param RingPtr is the channel instance to operate on. +* @param Mask consists of the interrupt signals to enable. They are formed by +* OR'ing one or more of the following bitmasks together: +* XLLDMA_CR_IRQ_EN_MASK, XLLDMA_CR_IRQ_ERROR_EN_MASK, +* XLLDMA_CR_IRQ_DELAY_EN_MASK, XLLDMA_CR_IRQ_COALESCE_EN_MASK and +* XLLDMA_CR_IRQ_ALL_EN_MASK. Bits not specified in the mask are not +* affected. +* +* @note +* C-style signature: +* void XLlDma_mBdRingIntEnable(XLlDma_BdRing* RingPtr, u32 Mask) +* +*****************************************************************************/ +#define XLlDma_mBdRingIntEnable(RingPtr, Mask) \ + { \ + u32 Reg = XLlDma_mReadReg((RingPtr)->ChanBase, \ + XLLDMA_CR_OFFSET); \ + Reg |= ((Mask) & XLLDMA_CR_IRQ_ALL_EN_MASK); \ + XLlDma_mWriteReg((RingPtr)->ChanBase, XLLDMA_CR_OFFSET, Reg);\ + } + + +/****************************************************************************/ +/** +* Clear interrupt enable bits for a channel. This operation will modify the +* XLLDMA_CR_OFFSET register. +* +* @param RingPtr is the channel instance to operate on. +* @param Mask consists of the interrupt signals to disable. They are formed +* by OR'ing one or more of the following bitmasks together: +* XLLDMA_CR_IRQ_EN_MASK, XLLDMA_CR_IRQ_ERROR_EN_MASK, +* XLLDMA_CR_IRQ_DELAY_EN_MASK, XLLDMA_CR_IRQ_COALESCE_EN_MASK and +* XLLDMA_CR_IRQ_ALL_EN_MASK. Bits not specified in the mask are not +* affected. +* +* @note +* C-style signature: +* void XLlDma_mBdRingIntDisable(XLlDma_BdRing* RingPtr, u32 Mask) +* +*****************************************************************************/ +#define XLlDma_mBdRingIntDisable(RingPtr, Mask) \ + { \ + u32 Reg = XLlDma_mReadReg((RingPtr)->ChanBase, \ + XLLDMA_CR_OFFSET); \ + Reg &= ~((Mask) & XLLDMA_CR_IRQ_ALL_EN_MASK); \ + XLlDma_mWriteReg((RingPtr)->ChanBase, XLLDMA_CR_OFFSET, Reg);\ + } + + +/****************************************************************************/ +/** +* Get enabled interrupts of a channel. +* +* @param RingPtr is the channel instance to operate on. +* @return Enabled interrupts of a channel. Use XLLDMA_CR_IRQ_* defined in +* xlldma_hw.h to interpret this returned value. +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingIntGetEnabled(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingIntGetEnabled(RingPtr) \ + (XLlDma_mReadReg((RingPtr)->ChanBase, XLLDMA_CR_OFFSET) \ + & XLLDMA_CR_IRQ_ALL_EN_MASK) + + +/****************************************************************************/ +/** +* Retrieve the contents of the channel's IRQ register XDMACR_IRQ_OFFSET. This +* operation can be used to see which interrupts are pending. +* +* @param RingPtr is the channel instance to operate on. +* +* @return Current contents of the IRQ_OFFSET register. Use XLLDMA_IRQ_*** +* values defined in xlldma_hw.h to interpret the returned value. +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingGetIrq(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingGetIrq(RingPtr) \ + XLlDma_mReadReg((RingPtr)->ChanBase, XLLDMA_IRQ_OFFSET) + + +/****************************************************************************/ +/** +* Acknowledge asserted interrupts. +* +* @param RingPtr is the channel instance to operate on. +* @param Mask are the interrupt signals to acknowledge and are made by Or'ing +* one or more of the following bits: XLLDMA_IRQ_ERROR_MASK, +* XLLDMA_IRQ_DELAY_MASK, XLLDMA_IRQ_COALESCE_MASK, XLLDMA_IRQ_ALL_MASK. +* Any mask bit set for an unasserted interrupt has no effect. +* +* @note +* C-style signature: +* u32 XLlDma_mBdRingAckIrq(XLlDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XLlDma_mBdRingAckIrq(RingPtr, Mask) \ + XLlDma_mWriteReg((RingPtr)->ChanBase, XLLDMA_IRQ_OFFSET,\ + (Mask) & XLLDMA_IRQ_ALL_MASK) + +/************************* Function Prototypes ******************************/ + +/* + * Descriptor ring functions xlldma_bdring.c + */ +int XLlDma_BdRingCreate(XLlDma_BdRing * RingPtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, unsigned BdCount); +int XLlDma_BdRingCheck(XLlDma_BdRing * RingPtr); +int XLlDma_BdRingClone(XLlDma_BdRing * RingPtr, XLlDma_Bd * SrcBdPtr); +int XLlDma_BdRingAlloc(XLlDma_BdRing * RingPtr, unsigned NumBd, + XLlDma_Bd ** BdSetPtr); +int XLlDma_BdRingUnAlloc(XLlDma_BdRing * RingPtr, unsigned NumBd, + XLlDma_Bd * BdSetPtr); +int XLlDma_BdRingToHw(XLlDma_BdRing * RingPtr, unsigned NumBd, + XLlDma_Bd * BdSetPtr); +unsigned XLlDma_BdRingFromHw(XLlDma_BdRing * RingPtr, unsigned BdLimit, + XLlDma_Bd ** BdSetPtr); +int XLlDma_BdRingFree(XLlDma_BdRing * RingPtr, unsigned NumBd, + XLlDma_Bd * BdSetPtr); +int XLlDma_BdRingStart(XLlDma_BdRing * RingPtr); +int XLlDma_BdRingSetCoalesce(XLlDma_BdRing * RingPtr, u32 Counter, u32 Timer); +void XLlDma_BdRingGetCoalesce(XLlDma_BdRing * RingPtr, + u32 *CounterPtr, u32 *TimerPtr); +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma.c 2014-07-20 22:06:39.105260375 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xlldma.c +* +* This file implements initialization and control related functions. For more +* information on this driver, see xlldma.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a xd 12/21/06 First release +* </pre> +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include <linux/string.h> + +#include "xlldma.h" +#include "xenv.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** + * This function initializes a DMA engine. This function must be called + * prior to using a DMA engine. Initialization of a engine includes setting + * up the register base address, setting up the instance data, and ensuring the + * hardware is in a quiescent state. + * + * @param InstancePtr is a pointer to the DMA engine instance to be worked on. + * @param BaseAddress is where the registers for this engine can be found. + * If address translation is being used, then this parameter must + * reflect the virtual base address. + * @return None. + * + *****************************************************************************/ +void XLlDma_Initialize(XLlDma * InstancePtr, u32 BaseAddress) +{ + /* Setup the instance */ + memset(InstancePtr, 0, sizeof(XLlDma)); + InstancePtr->RegBase = BaseAddress; + + /* Initialize the ring structures */ + InstancePtr->TxBdRing.RunState = XST_DMA_SG_IS_STOPPED; + InstancePtr->TxBdRing.ChanBase = BaseAddress + XLLDMA_TX_OFFSET; + InstancePtr->TxBdRing.IsRxChannel = 0; + InstancePtr->RxBdRing.RunState = XST_DMA_SG_IS_STOPPED; + InstancePtr->RxBdRing.ChanBase = BaseAddress + XLLDMA_RX_OFFSET; + InstancePtr->RxBdRing.IsRxChannel = 1; + + /* Reset the device and return */ + XLlDma_Reset(InstancePtr); +} + +/*****************************************************************************/ +/** +* Reset both TX and RX channels of a DMA engine. +* +* Any DMA transaction in progress aborts immediately. The DMA engine is in +* stop state after the reset. +* +* @param InstancePtr is a pointer to the DMA engine instance to be worked on. +* +* @return None. +* +* @note +* - If the hardware is not working properly, this function will enter +* infinite loop and never return. +* - After the reset, the Normal mode is enabled, and the overflow error +* for both TX/RX channels are disabled. +* - After the reset, the DMA engine is no longer in pausing state, if +* the DMA engine is paused before the reset operation. +* - After the reset, the coalescing count value and the delay timeout +* value are both set to 1 for TX and RX channels. +* - After the reset, all interrupts are disabled. +* +******************************************************************************/ +void XLlDma_Reset(XLlDma * InstancePtr) +{ + u32 IrqStatus; + XLlDma_BdRing *TxRingPtr, *RxRingPtr; + + TxRingPtr = &XLlDma_mGetTxRing(InstancePtr); + RxRingPtr = &XLlDma_mGetRxRing(InstancePtr); + + /* Save the locations of current BDs both rings are working on + * before the reset so later we can resume the rings smoothly. + */ + XLlDma_mBdRingSnapShotCurrBd(TxRingPtr); + XLlDma_mBdRingSnapShotCurrBd(RxRingPtr); + + /* Start reset process then wait for completion */ + XLlDma_mSetCr(InstancePtr, XLLDMA_DMACR_SW_RESET_MASK); + + /* Loop until the reset is done */ + while ((XLlDma_mGetCr(InstancePtr) & XLLDMA_DMACR_SW_RESET_MASK)) { + } + + /* Disable all interrupts after issue software reset */ + XLlDma_mBdRingIntDisable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); + XLlDma_mBdRingIntDisable(RxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); + + /* Clear Interrupt registers of both channels, as the software reset + * does not clear any register values. Not doing so will cause + * interrupts asserted after the software reset if there is any + * interrupt left over before. + */ + IrqStatus = XLlDma_mBdRingGetIrq(TxRingPtr); + XLlDma_mBdRingAckIrq(TxRingPtr, IrqStatus); + IrqStatus = XLlDma_mBdRingGetIrq(RxRingPtr); + XLlDma_mBdRingAckIrq(RxRingPtr, IrqStatus); + + /* Enable Normal mode, and disable overflow errors for both channels */ + XLlDma_mSetCr(InstancePtr, XLLDMA_DMACR_TAIL_PTR_EN_MASK | + XLLDMA_DMACR_RX_OVERFLOW_ERR_DIS_MASK | + XLLDMA_DMACR_TX_OVERFLOW_ERR_DIS_MASK); + + /* Set TX/RX Channel coalescing setting */ + XLlDma_BdRingSetCoalesce(TxRingPtr, 1, 1); + XLlDma_BdRingSetCoalesce(RxRingPtr, 1, 1); + + TxRingPtr->RunState = XST_DMA_SG_IS_STOPPED; + RxRingPtr->RunState = XST_DMA_SG_IS_STOPPED; +} + +/*****************************************************************************/ +/** +* Pause DMA transactions on both channels. The DMA enters the pausing state +* immediately. So if a DMA transaction is in progress, it will be left +* unfinished and will be continued once the DMA engine is resumed +* (see XLlDma_Resume()). +* +* @param InstancePtr is a pointer to the DMA engine instance to be worked on. +* +* @return None. +* +* @note +* - If the hardware is not working properly, this function will enter +* infinite loop and never return. +* - After the DMA is paused, DMA channels still could accept more BDs +* from software (see XLlDma_BdRingToHw()), but new BDs will not be +* processed until the DMA is resumed (see XLlDma_Resume()). +* +*****************************************************************************/ +void XLlDma_Pause(XLlDma * InstancePtr) +{ + u32 RegValue; + XLlDma_BdRing *TxRingPtr, *RxRingPtr; + + TxRingPtr = &XLlDma_mGetTxRing(InstancePtr); + RxRingPtr = &XLlDma_mGetRxRing(InstancePtr); + + /* Do nothing if both channels already stopped */ + if ((TxRingPtr->RunState == XST_DMA_SG_IS_STOPPED) && + (RxRingPtr->RunState == XST_DMA_SG_IS_STOPPED)) { + return; + } + + /* Enable pause bits for both TX/ RX channels */ + RegValue = XLlDma_mGetCr(InstancePtr); + XLlDma_mSetCr(InstancePtr, RegValue | XLLDMA_DMACR_TX_PAUSE_MASK | + XLLDMA_DMACR_RX_PAUSE_MASK); + + /* Loop until Write Command Queue of RX channel is empty, which + * indicates that all the write data associated with the pending + * commands has been flushed.*/ + while (!(XLlDma_mBdRingGetIrq(RxRingPtr) | XLLDMA_IRQ_WRQ_EMPTY_MASK)); + + TxRingPtr->RunState = XST_DMA_SG_IS_STOPPED; + RxRingPtr->RunState = XST_DMA_SG_IS_STOPPED; +} + +/*****************************************************************************/ +/** +* Resume DMA transactions on both channels. Any interrupted DMA transaction +* caused by DMA pause operation (see XLlDma_Pause()) and all committed +* transactions after DMA is paused will be continued upon the return of this +* function. +* +* @param InstancePtr is a pointer to the DMA engine instance to be worked on. +* +* @return None. +* +*****************************************************************************/ +void XLlDma_Resume(XLlDma * InstancePtr) +{ + u32 RegValue; + XLlDma_BdRing *TxRingPtr, *RxRingPtr; + + TxRingPtr = &XLlDma_mGetTxRing(InstancePtr); + RxRingPtr = &XLlDma_mGetRxRing(InstancePtr); + + /* Do nothing if both channels already started */ + if ((TxRingPtr->RunState == XST_DMA_SG_IS_STARTED) && + (RxRingPtr->RunState == XST_DMA_SG_IS_STARTED)) { + return; + } + + /* Clear pause bits for both TX/ RX channels */ + RegValue = XLlDma_mGetCr(InstancePtr); + XLlDma_mSetCr(InstancePtr, RegValue & ~(XLLDMA_DMACR_TX_PAUSE_MASK | + XLLDMA_DMACR_RX_PAUSE_MASK)); + + TxRingPtr->RunState = XST_DMA_SG_IS_STARTED; + RxRingPtr->RunState = XST_DMA_SG_IS_STARTED; +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma.h 2014-07-20 22:06:39.119260144 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xlldma.h +* +* The Xilinx Local-Link Scatter Gather DMA driver. This driver supports Soft +* DMA (SDMA) engines. Each SDMA engine contains two separate DMA channels (TX +* and RX). +* +* This component is designed to be used as a basic building block for +* designing a device driver. It provides registers accesses such that all +* DMA processing can be maintained easier, but the device driver designer +* must still understand all the details of the DMA channel. +* +* For a full description of DMA features, please see the hardware spec. This +* driver supports the following features: +* +* - Scatter-Gather DMA (SGDMA) +* - Interrupts +* - Programmable interrupt coalescing for SGDMA +* - Capable of using 32 bit addressing for buffer. (Hardware spec states +* 36 Bit bus addressing, which includes Msb 4-bits of DMA address +* configurable on each channel through the Channel Control Registers) +* - APIs to manage Buffer Descriptors (BD) movement to and from the SGDMA +* engine +* - Virtual memory support +* +* <b>Transactions</b> +* +* To describe a DMA transaction in its simplest form, you need source address, +* destination address, and the number of bytes to transfer. When using a DMA +* receive channel, the source address is within some piece of IP Hardware and +* doesn't require the application explicitly set it. Likewise with a transmit +* channel and the destination address. So this leaves a application buffer +* address and the number bytes to transfer as the primary transaction +* attributes. Other attributes include: +* +* - If the transaction occurs on a bus wider than 32 bits, what are the +* highest order address bits. +* - Does this transaction represent the start of a packet, or end of a +* packet. +* +* The object used to describe a transaction is referred to as a Buffer +* Descriptor (BD). The format of a BD closely matches that of the DMA hardware. +* Many fields within the BD correspond directly with the same fields within the +* hardware registers. See xlldmabd.h for a detailed description of and the API +* for manipulation of these objects. +* +* <b>Scatter-Gather DMA</b> +* +* SGDMA allows the application to define a list of transactions in memory which +* the hardware will process without further application intervention. During +* this time, the application is free to continue adding more work to keep the +* Hardware busy. +* +* Notification of completed transactions can be done either by polling the +* hardware, or using interrupts that signal a transaction has completed or a +* series of transactions have been completed. +* +* SGDMA processes whole packets. A packet is defined as a series of +* data bytes that represent a message. SGDMA allows a packet of data to be +* broken up into one or more transactions. For example, take an Ethernet IP +* packet which consists of a 14 byte header followed by a 1 or more byte +* payload. With SGDMA, the application may point a BD to the header and another +* BD to the payload, then transfer them as a single message. This strategy can +* make a TCP/IP stack more efficient by allowing it to keep packet headers and +* data in different memory regions instead of assembling packets into +* contiguous blocks of memory. +* +* <b>SGDMA Ring Management</b> +* +* The hardware expects BDs to be setup as a singly linked list. As a BD is +* completed, the DMA engine will dereference BD.Next and load the next BD to +* process. This driver uses a fixed buffer ring where all BDs are linked to the +* next BD in adjacent memory. The last BD in the ring is linked to the first. +* +* Within the ring, the driver maintains four groups of BDs. Each group consists +* of 0 or more adjacent BDs: +* +* - Free: Those BDs that can be allocated by the application with +* XLlDma_BdRingAlloc(). These BDs are under driver control and may not be +* modified by the application +* +* - Pre-process: Those BDs that have been allocated with +* XLlDma_BdRingAlloc(). These BDs are under application control. The +* application modifies these BDs in preparation for future DMA +* transactions. +* +* - Hardware: Those BDs that have been enqueued to hardware with +* XLlDma_BdRingToHw(). These BDs are under hardware control and may be in a +* state of awaiting hardware processing, in process, or processed by +* hardware. It is considered an error for the application to change BDs +* while they are in this group. Doing so can cause data corruption and lead +* to system instability. +* +* - Post-process: Those BDs that have been processed by hardware and have +* been extracted from the work group with XLlDma_BdRingFromHw(). These BDs +* are under application control. The application may access these BDs to +* determine the result of DMA transactions. When the application is +* finished, XLlDma_BdRingFree() should be called to place them back into +* the Free group. +* +* +* Normally BDs are moved in the following way: +* <pre> +* +* XLlDma_BdRingAlloc() XLlDma_BdRingToHw() +* Free ------------------------> Pre-process ----------------------> Hardware +* | +* /|\ | +* | XLlDma_BdRingFree() XLlDma_BdRingFromHw() | +* +--------------------------- Post-process <----------------------+ +* +* </pre> +* +* The only exception to the flow above is that after BDs are moved from Free +* group to Pre-process group, the application decide for whatever reason these +* BDs are not ready and could not be given to hardware. In this case these BDs +* could be moved back to Free group using XLlDma_BdRingUnAlloc() function to +* help keep the BD ring in great shape and recover the error. See comments of +* the function for details +* +* <pre> +* +* XLlDma_BdRingUnAlloc() +* Free <----------------------- Pre-process +* +* </pre> +* +* The API provides macros that allow BD list traversal. These macros should be +* used with care as they do not understand where one group ends and another +* begins. +* +* The driver does not cache or keep copies of any BD. When the application +* modifies BDs returned by XLlDma_BdRingAlloc() or XLlDma_BdRingFromHw(), they +* are modifying the same BD that hardware accesses. +* +* Certain pairs of list modification functions have usage restrictions. See +* the function headers for XLlDma_BdRingAlloc() and XLlDma_BdRingFromHw() for +* more information. +* +* <b>SGDMA Descriptor Ring Creation</b> +* +* During initialization, the function XLlDma_BdRingCreate() is used to setup +* a application supplied memory block to contain all BDs for the DMA channel. +* This function takes as an argument the number of BDs to place in the list. To +* arrive at this number, the application is given two methods of calculating +* it. +* +* The first method assumes the application has a block of memory and they just +* want to fit as many BDs as possible into it. The application must calculate +* the number of BDs that will fit with XLlDma_mBdRingCntCalc(), then supply +* that number into the list creation function. +* +* The second method allows the application to just supply the number directly. +* The driver assumes the memory block is large enough to contain them all. To +* double-check, the application should invoke XLlDma_mBdRingMemCalc() to verify +* the memory block size is adequate. +* +* Once the list has been created, it can be used right away to perform DMA +* transactions. However, there are optional steps that can be done to increase +* throughput and decrease application code complexity by the use of +* XLlDma_BdRingClone(). +* +* BDs have several application accessible attributes that affect how DMA +* transactions are carried out. Some of these attributes will probably be +* constant at run-time. The cloning function can be used to copy a template BD +* to every BD in the ring relieving the application of having to setup +* transactions from scratch every time a BD is submitted to hardware. +* +* Ideally, the only transaction parameters that need to be set by application +* should be: buffer address, bytes to transfer, and whether the BD is the +* Start and/or End of a packet. +* +* <b>Interrupt Coalescing</b> +* +* SGDMA provides control over the frequency of interrupts. On a high speed link +* significant processor overhead may be used servicing interrupts. Interrupt +* coalescing provides two mechanisms that help control interrupt frequency: +* +* - The packet threshold counter will hold off interrupting the CPU until a +* programmable number of packets have been processed by the engine. +* - The packet waitbound timer is used to interrupt the CPU if after a +* programmable amount of time after processing the last packet, no new +* packets were processed. +* +* <b>Interrupt Service </b> +* +* This driver does not service interrupts. This is done typically by a +* interrupt handler within a higher level driver/application that uses DMA. +* This driver does provide an API to enable or disable specific interrupts. +* +* This interrupt handler provided by the higher level driver/application +* !!!MUST!!! clear pending interrupts before handling the BDs processed by the +* DMA. Otherwise the following corner case could raise some issue: +* +* - A packet is transmitted(/received) and asserts a TX(/RX) interrupt, and if +* this interrupt handler deals with the BDs finished by the DMA before clears +* the interrupt, another packet could get transmitted(/received) and assert +* the interrupt between when the BDs are taken care and when the interrupt +* clearing operation begins, and the interrupt clearing operation will clear +* the interrupt raised by the second packet and will never process its +* according BDs until a new interrupt occurs. +* +* Changing the sequence to "Clear interrupts before handle BDs" solves this +* issue: +* +* - If the interrupt raised by the second packet is before the interrupt +* clearing operation, the descriptors associated with the second packet must +* have been finished by hardware and ready for the handler to deal with, +* and those descriptors will processed with those BDs of the first packet +* during the handling of the interrupt asserted by the first packet. +* +* - if the interrupt of the second packet is asserted after the interrupt +* clearing operation but its BDs are finished before the handler starts to +* deal with BDs, the packet's buffer descriptors will be handled with +* those of the first packet during the handling of the interrupt asserted +* by the first packet. +* +* - Otherwise, the BDs of the second packet is not ready when the interrupt +* handler starts to deal with the BDs of the first packet. Those BDs will +* be handled next time the interrupt handled gets invoked as the interrupt +* of the second packet is not cleared in current pass and thereby will +* cause the handler to get invoked again +* +* Please note if the second case above occurs, the handler will find +* NO buffer descriptor is finished by the hardware (i.e., +* XLlDma_BdRingFromHw() returns 0) during the handling of the interrupt +* asserted by the second packet. This is valid and the application should NOT +* consider this is a hardware error and have no need to reset the hardware. +* +* <b> Software Initialization </b> +* +* The application needs to do following steps in order for preparing DMA engine +* to be ready to process DMA transactions: +* +* - DMA Initialization using XLlDma_Initialize() function. This step +* initializes a driver instance for the given DMA engine and resets the +* engine. +* - BD Ring creation. A BD ring is needed per channel and can be built by +* calling XLlDma_BdRingCreate(). A parameter passed to this function is the +* number of BD fit in a given memory range, and XLlDma_mBdRingCntCalc() helps +* calculate the value. +* - (Optional) BD setup using a template. Once a BD ring is created, the +* application could populate a template BD and then invoke +* XLlDma_BdRingClone() to set the same attributes on all BDs on the BD ring. +* This saves the application some effort to populate all fixed attributes of +* each BD before passing it to the hardware. +* - (RX channel only) Prepare BDs with attached data buffers and give them to +* RX channel. First allocate BDs using XLlDma_BdRingAlloc(), then populate +* data buffer address, data buffer size and the control word fields of each +* allocated BD with valid values. Last call XLlDma_BdRingToHw() to give the +* BDs to the channel. +* - Enable interrupts if interrupt mode is chosen. The application is +* responsible for setting up the interrupt system, which includes providing +* and connecting interrupt handlers and call back functions, before +* the interrupts are enabled. +* - Start DMA channels: Call XLlDma_BdRingStart() to start a channel +* +* <b> How to start DMA transactions </b> +* +* RX channel is ready to start RX transactions once the initialization (see +* Initialization section above) is finished. The DMA transactions are triggered +* by the user IP (like Local Link TEMAC). +* +* Starting TX transactions needs some work. The application calls +* XLlDma_BdRingAlloc() to allocate a BD list, then populates necessary +* attributes of each allocated BD including data buffer address, data size, +* and control word, and last passes those BDs to the TX channel +* (see XLlDma_BdRingToHw()). The added BDs will be processed as soon as the +* TX channel reaches them. +* +* For both channels, If the DMA engine is currently paused (see +* XLlDma_Pause()), the newly added BDs will be accepted but not processed +* until the DMA engine is resumed (see XLlDma_Resume()). +* +* <b> Software Post-Processing on completed DMA transactions </b> +* +* Some software post-processing is needed after DMA transactions are finished. +* +* if interrupt system are set up and enabled, DMA channels notify the software +* the finishing of DMA transactions using interrupts, Otherwise the +* application could poll the channels (see XLlDma_BdRingFromHw()). +* +* - Once BDs are finished by a channel, the application first needs to fetch +* them from the channel (see XLlDma_BdRingFromHw()). +* - On TX side, the application now could free the data buffers attached to +* those BDs as the data in the buffers has been transmitted. +* - On RX side, the application now could use the received data in the buffers +* attached to those BDs +* - For both channels, those BDs need to be freed back to the Free group (see +* XLlDma_BdRingFree()) so they are allocatable for future transactions. +* - On RX side, it is the application's responsibility for having BDs ready +* to receive data at any time. Otherwise the RX channel will refuse to +* accept any data once it runs out of RX BDs. As we just freed those hardware +* completed BDs in the previous step, it is good timing to allocate them +* back (see XLlDma_BdRingAlloc()), prepare them, and feed them to the RX +* channel again (see XLlDma_BdRingToHw()) +* +* <b> Examples </b> +* +* Two examples are provided with this driver to demonstrate the driver usage: +* One for interrupt mode and one for polling mode. +* +* <b>Address Translation</b> +* +* When the BD list is setup with XLlDma_BdRingCreate(), a physical and +* virtual address is supplied for the segment of memory containing the +* descriptors. The driver will handle any translations internally. Subsequent +* access of descriptors by the application is done in terms of their virtual +* address. +* +* Any application data buffer address attached to a BD must be physical +* address. The application is responsible for calculating the physical address +* before assigns it to the buffer address field in the BD. +* +* <b>Cache Coherency</b> +* +* This driver expects all application buffers attached to BDs to be in cache +* coherent memory. Buffers for transmit MUST be flushed from the cache before +* passing the associated BD to this driver. Buffers for receive MUST be +* invalidated before passing the associated BD to this driver. +* +* <b>Alignment</b> +* +* For BDs: +* +* Minimum alignment is defined by the constant XLLDMA_BD_MINIMUM_ALIGNMENT. +* This is the smallest alignment allowed by both hardware and software for them +* to properly work. Other than XLLDMA_BD_MINIMUM_ALIGNMENT, multiples of the +* constant are the only valid alignments for BDs. +* +* If the descriptor ring is to be placed in cached memory, alignment also MUST +* be at least the processor's cache-line size. If this requirement is not met +* then system instability will result. This is also true if the length of a BD +* is longer than one cache-line, in which case multiple cache-lines are needed +* to accommodate each BD. +* +* Aside from the initial creation of the descriptor ring (see +* XLlDma_BdRingCreate()), there are no other run-time checks for proper +* alignment. +* +* For application data buffers: +* +* Application data buffers may reside on any alignment. +* +* <b>Reset After Stopping</b> +* +* This driver is designed to allow for stop-reset-start cycles of the DMA +* hardware while keeping the BD list intact. When restarted after a reset, this +* driver will point the DMA engine to where it left off after stopping it. +* +* <b>Limitations</b> +* +* This driver only supports Normal mode (i.e., Tail Descriptor Pointer mode). +* In this mode write of a Tail Descriptor Pointer register (which is done in +* XLlDma_BdRingStart() and XLlDma_BdRingToHw()) starts DMA transactions. +* +* Legacy mode is NOT supported by this driver. +* +* This driver does not have any mechanism for mutual exclusion. It is up to the +* application to provide this protection. +* +* <b>Hardware Defaults & Exclusive Use</b> +* +* During initialization, this driver will override the following hardware +* default settings. If desired, the application may change these settings back +* to their hardware defaults: +* +* - Normal mode (Tail Descriptor Pointer mode) will be enabled. +* - Interrupt coalescing timer and counter overflow errors will be disabled +* (XLLDMA_DMACR_RX_OVERFLOW_ERR_DIS_MASK and TX_OVERFLOW_ERR_DIS_MASK will +* be set to 1). These two items control interrupt "overflow" behavior. +* When enabled, the hardware may signal an error if interrupts are not +* processed fast enough even though packets were correctly processed. This +* error is triggered when certain internal counters overflow. The driver +* disables this feature so no such error will be reported. +* +* The driver requires exclusive use of the following hardware features. If any +* are changed by the application then the driver will not operate properly: +* +* - XLLDMA_DMACR_TAIL_PTR_ENABLE_MASK. The driver controls this bit +* in the DMACR register. +* - XLLDMA_BD_STSCTRL_COMPLETED_MASK. The driver controls this bit in each BD +* - XLLDMA_NDESC_OFFSET. The driver controls this register +* - XLLDMA_DMACR_SW_RESET_MASK. The driver controls this bit in the DMACR +* register +* +* <b>BUS Interface</b> +* +* The constant CONFIG_XILINX_LLDMA_USE_DCR (see xlldma_hw.h) is used +* to inform the driver the type of the BUS the DMA device is on. If +* the DMA device is on DCR BUS, CONFIG_XILINX_LLDMA_USE_DCR must be +* defined as a compiler option used in the Makefile BEFORE this driver +* is compiled; Otherwise, the constant must NOT be defined. +* +* <b>User-IP Specific Definition</b> +* +* This driver relies on two User-IP (like Local-Link TEMAC) specific constants +* (see xlldma_userip.h) to work properly: +* +* - XLLDMA_USR_APPWORD_OFFSET defines a user word the User-IP always updates +* in the RX Buffer Descriptors (BD) during <b>ALL</b> Receive transactions. +* This driver uses XLLDMA_BD_USR4_OFFSET as the default value of this +* constant. +* +* - XLLDMA_USR_APPWORD_INITVALUE defines the value the DMA driver uses to +* populate the XLLDMA_USR_APPWORD_OFFSET field in any RX BD before giving +* the BD to the RX channel for receive transaction. It must be ensured +* that the User-IP will always populates a different value into the +* XLLDMA_USR_APPWORD_OFFSET field during any receive transaction. Failing +* to do so will cause the DMA driver to work improperly. This driver uses +* 0xFFFFFFFF as the default value of this constant. +* +* If the User-IP uses different setting, the correct setting must be defined as +* compiler options used in the Makefile BEFORE this driver is compiled. In +* either case the default definition of the constants in this driver will be +* discarded. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a xd 12/21/06 First release +* </pre> +* +******************************************************************************/ + +#ifndef XLLDMA_H /* prevent circular inclusions */ +#define XLLDMA_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xlldma_bd.h" +#include "xlldma_bdring.h" +#include "xlldma_userip.h" +#include "xstatus.h" + +/************************** Constant Definitions *****************************/ + +#define XLLDMA_NO_CHANGE 0xFFFF /* Used as API argument */ +#define XLLDMA_ALL_BDS 0xFFFFFFFF /* Used as API argument */ + +/**************************** Type Definitions *******************************/ + + +/** + * The XLlDma driver instance data. An instance must be allocated for each DMA + * engine in use. Each DMA engine includes a TX channel and a RX channel. + */ +typedef struct XLlDma { + u32 RegBase; /**< Virtual base address of DMA engine */ + XLlDma_BdRing TxBdRing; /**< BD container management for TX channel */ + XLlDma_BdRing RxBdRing; /**< BD container management for RX channel */ + +} XLlDma; + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/****************************************************************************/ +/** +* Retrieve the TX ring object. This object can be used in the various Ring +* API functions. +* +* @param InstancePtr is the DMA engine to operate on. +* +* @return TxBdRing object +* +* @note +* C-style signature: +* XLlDma_BdRing XLlDma_mGetTxRing(XLlDma* InstancePtr) +* +*****************************************************************************/ +#define XLlDma_mGetTxRing(InstancePtr) ((InstancePtr)->TxBdRing) + + +/****************************************************************************/ +/** +* Retrieve the RX ring object. This object can be used in the various Ring +* API functions. +* +* @param InstancePtr is the DMA engine to operate on. +* +* @return RxBdRing object +* +* @note +* C-style signature: +* XLlDma_BdRing XLlDma_mGetRxRing(XLlDma* InstancePtr) +* +*****************************************************************************/ +#define XLlDma_mGetRxRing(InstancePtr) ((InstancePtr)->RxBdRing) + + +/****************************************************************************/ +/** +* Retrieve the contents of the DMA engine control register +* (XLLDMA_DMACR_OFFSET). +* +* @param InstancePtr is the DMA engine instance to operate on. +* +* @return Current contents of the DMA engine control register. +* +* @note +* C-style signature: +* u32 XLlDma_mGetCr(XLlDma* InstancePtr) +* +*****************************************************************************/ +#define XLlDma_mGetCr(InstancePtr) \ + XLlDma_mReadReg((InstancePtr)->RegBase, XLLDMA_DMACR_OFFSET) + + +/****************************************************************************/ +/** +* Set the contents of the DMA engine control register (XLLDMA_DMACR_OFFSET). +* This control register affects both DMA channels. +* +* @param InstancePtr is the DMA engine instance to operate on. +* @param Data is the data to write to the DMA engine control register. +* +* @note +* C-style signature: +* u32 XLlDma_mSetCr(XLlDma* InstancePtr, u32 Data) +* +*****************************************************************************/ +#define XLlDma_mSetCr(InstancePtr, Data) \ + XLlDma_mWriteReg((InstancePtr)->RegBase, XLLDMA_DMACR_OFFSET, (Data)) + + +/************************** Function Prototypes ******************************/ + +/* + * Initialization and control functions in xlldma.c + */ +void XLlDma_Initialize(XLlDma * InstancePtr, u32 BaseAddress); +void XLlDma_Reset(XLlDma * InstancePtr); +void XLlDma_Pause(XLlDma * InstancePtr); +void XLlDma_Resume(XLlDma * InstancePtr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_hw.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_hw.h 2014-07-20 22:06:39.131259946 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ + +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xlldma_hw.h +* +* This header file contains identifiers and register-level driver functions (or +* macros) that can be used to access the Local-Link Scatter-gather Direct +* Memory Access Gather (LLDMA) device. +* +* For more information about the operation of this device, see the hardware +* specification and documentation in the higher level driver xlldma.h source +* code file. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a xd 12/21/06 First release +* </pre> +* +******************************************************************************/ + +#ifndef XLLDMA_HW_H /* prevent circular inclusions */ +#define XLLDMA_HW_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" + +/** @name Device Bus Type definition The constant + * CONFIG_XILINX_LLDMA_USE_DCR is used to inform this driver the type + * of the BUS the DMA device is on. If the DMA core is on DCR BUS + * using indirect addressing, which currently only happens on V5FX, + * then this option must be set. On other architectures where dma + * ports are accessed through memory mapped io, this must not be set. + *@{ + */ +#ifdef CONFIG_XILINX_LLDMA_USE_DCR +#include "xio_dcr.h" +#else +#include "xio.h" +#endif +/*@}*/ + +/************************** Constant Definitions *****************************/ + +/** @name Buffer Descriptor Alignment + * @{ + */ +#define XLLDMA_BD_MINIMUM_ALIGNMENT 0x40 /**< Minimum byte alignment + requirement for descriptors to + satisfy both hardware/software + needs */ +/*@}*/ + + +/* Register offset definitions. Unless otherwise noted, register access is + * 32 bit. + */ + +#ifdef CONFIG_XILINX_LLDMA_USE_DCR + +/* DMA core is on DCR BUS */ + +/** @name Device registers for DCR based systems. + * Offsets defined in DCR address space. TX and RX channels consist of + * identical registers + * @{ + */ +#define XLLDMA_TX_OFFSET 0x00000000 /**< TX channel registers base + offset [0..7] */ +#define XLLDMA_RX_OFFSET 0x00000008 /**< RX channel registers base + offset [8..F] */ +#define XLLDMA_DMACR_OFFSET 0x00000010 /**< DMA control register */ + +/* This set of registers are applicable for both channels. Add + * XLLDMA_TX_OFFSET to get to TX channel, and XLLDMA_RX_OFFSET to get to RX + * channel + */ +#define XLLDMA_NDESC_OFFSET 0x00000000 /**< Next descriptor pointer */ +#define XLLDMA_BUFA_OFFSET 0x00000001 /**< Current buffer address */ +#define XLLDMA_BUFL_OFFSET 0x00000002 /**< Current buffer length */ +#define XLLDMA_CDESC_OFFSET 0x00000003 /**< Current descriptor pointer */ +#define XLLDMA_TDESC_OFFSET 0x00000004 /**< Tail descriptor pointer */ +#define XLLDMA_CR_OFFSET 0x00000005 /**< Channel control */ +#define XLLDMA_IRQ_OFFSET 0x00000006 /**< Interrupt register */ +#define XLLDMA_SR_OFFSET 0x00000007 /**< Status */ +/*@}*/ + +#else /* Non-DCR interface is used */ + +/** @name Device registers for Non-DCR based systems. + * Offsets defined in Non-DCR address space. TX and RX channels consist of + * identical registers + * @{ + */ +#define XLLDMA_TX_OFFSET 0x00000000 /**< TX channel registers base + offset */ +#define XLLDMA_RX_OFFSET 0x00000020 /**< RX channel registers base + offset */ +#define XLLDMA_DMACR_OFFSET 0x00000040 /**< DMA control register */ + +/* This set of registers are applicable for both channels. Add + * XLLDMA_TX_OFFSET to get to TX channel, and XLLDMA_RX_OFFSET to get to RX + * channel + */ +#define XLLDMA_NDESC_OFFSET 0x00000000 /**< Next descriptor pointer */ +#define XLLDMA_BUFA_OFFSET 0x00000004 /**< Current buffer address */ +#define XLLDMA_BUFL_OFFSET 0x00000008 /**< Current buffer length */ +#define XLLDMA_CDESC_OFFSET 0x0000000C /**< Current descriptor pointer */ +#define XLLDMA_TDESC_OFFSET 0x00000010 /**< Tail descriptor pointer */ +#define XLLDMA_CR_OFFSET 0x00000014 /**< Channel control */ +#define XLLDMA_IRQ_OFFSET 0x00000018 /**< Interrupt register */ +#define XLLDMA_SR_OFFSET 0x0000001C /**< Status */ + +/*@}*/ + +#endif /* #ifdef CONFIG_XILINX_LLDMA_USE_DCR */ + +/** @name Buffer Descriptor register offsets + * USR fields are defined by higher level IP. For example, checksum offload + * setup for EMAC type devices. The 1st 8 words are utilized by hardware. Any + * words after the 8th are for software use only. + * @{ + */ +#define XLLDMA_BD_NDESC_OFFSET 0x00 /**< Next descriptor pointer */ +#define XLLDMA_BD_BUFA_OFFSET 0x04 /**< Buffer address */ +#define XLLDMA_BD_BUFL_OFFSET 0x08 /**< Buffer length */ +#define XLLDMA_BD_STSCTRL_USR0_OFFSET 0x0C /**< Status and Control and + hardware implementation + specific */ +#define XLLDMA_BD_USR1_OFFSET 0x10 /**< Hardware implementation + specific */ +#define XLLDMA_BD_USR2_OFFSET 0x14 /**< Hardware implementation + specific */ +#define XLLDMA_BD_USR3_OFFSET 0x18 /**< Hardware implementation + specific */ +#define XLLDMA_BD_USR4_OFFSET 0x1C /**< Hardware implementation + specific */ +#define XLLDMA_BD_ID_OFFSET 0x20 /**< Software application use */ + +#define XLLDMA_BD_NUM_WORDS 9 /**< Number of 32-bit words that + make up a full BD */ +#define XLLDMA_BD_HW_NUM_WORDS 8 /**< Number of 32-bit words that + make up the hardware + accessible portion of a BD */ +#define XLLDMA_BD_HW_NUM_BYTES 32 /**< Number of bytes that make up + the hardware accessible + portion of a BD */ +/*@}*/ + + +/* Register masks. The following constants define bit locations of various + * control bits in the registers. Constants are not defined for those registers + * that have a single bit field representing all 32 bits. For further + * information on the meaning of the various bit masks, refer to the hardware + * spec. + */ + + +/** @name Bitmasks of XLLDMA_TX_CR_OFFSET and XLLDMA_RX_CR_OFFSET registers + * @{ + */ +#define XLLDMA_CR_IRQ_TIMEOUT_MASK 0xFF000000 /**< Interrupt coalesce + waitbound timeout */ +#define XLLDMA_CR_IRQ_COUNT_MASK 0x00FF0000 /**< Interrupt coalesce + count threshold */ +#define XLLDMA_CR_MSB_ADDR_MASK 0x0000F000 /**< MSB address of DMA + buffers and descriptors + for 36 bit + addressing */ +#define XLLDMA_CR_APP_EN_MASK 0x00000800 /**< Application data mask + enable */ +#define XLLDMA_CR_USE_1_BIT_CNT_MASK 0x00000400 /**< Turn 4 and 2 bit + interrupt counters into + 1 bit counters */ +#define XLLDMA_CR_USE_INT_ON_END_MASK 0x00000200 /**< Use interrupt-on-end */ +#define XLLDMA_CR_LD_IRQ_CNT_MASK 0x00000100 /**< Load IRQ_COUNT */ +#define XLLDMA_CR_IRQ_EN_MASK 0x00000080 /**< Master interrupt + enable */ +#define XLLDMA_CR_IRQ_ERROR_EN_MASK 0x00000004 /**< Enable error + interrupt */ +#define XLLDMA_CR_IRQ_DELAY_EN_MASK 0x00000002 /**< Enable coalesce delay + interrupt */ +#define XLLDMA_CR_IRQ_COALESCE_EN_MASK 0x00000001 /**< Enable coalesce count + interrupt */ +#define XLLDMA_CR_IRQ_ALL_EN_MASK 0x00000087 /**< All interrupt enable + bits */ + +/* Shift constants for selected masks */ +#define XLLDMA_CR_IRQ_TIMEOUT_SHIFT 24 +#define XLLDMA_CR_IRQ_COUNT_SHIFT 16 +#define XLLDMA_CR_MSB_ADDR_SHIFT 12 + +/*@}*/ + + +/** @name Bitmasks of XLLDMA_TX_IRQ_OFFSET & XLLDMA_RX_IRQ_OFFSET registers + * @{ + */ +#define XLLDMA_IRQ_WRQ_EMPTY_MASK 0x00004000 /**< Write Command Queue + Empty -- RX channel + Only */ +#define XLLDMA_IRQ_COALESCE_COUNTER_MASK 0x00003C00 /**< Coalesce IRQ 4 bit + counter */ +#define XLLDMA_IRQ_DELAY_COUNTER_MASK 0x00000300 /**< Coalesce delay IRQ 2 + bit counter */ +#define XLLDMA_IRQ_PLB_RD_ERROR_MASK 0x00000010 /**< PLB Read Error IRQ */ +#define XLLDMA_IRQ_PLB_WR_ERROR_MASK 0x00000008 /**< PLB Write Error IRQ */ +#define XLLDMA_IRQ_ERROR_MASK 0x00000004 /**< Error IRQ */ +#define XLLDMA_IRQ_DELAY_MASK 0x00000002 /**< Coalesce delay IRQ */ +#define XLLDMA_IRQ_COALESCE_MASK 0x00000001 /**< Coalesce threshold + IRQ */ +#define XLLDMA_IRQ_ALL_ERR_MASK 0x0000001C /**< All error interrupt */ +#define XLLDMA_IRQ_ALL_MASK 0x0000001F /**< All interrupt bits */ + +/* Shift constants for selected masks */ +#define XLLDMA_IRQ_COALESCE_COUNTER_SHIFT 10 +#define XLLDMA_IRQ_DELAY_COUNTER_SHIFT 8 + +/*@}*/ + + +/** @name Bitmasks of XLLDMA_TX_SR_OFFSET and XLLDMA_RX_SR_OFFSET registers + * @{ + */ +#define XLLDMA_SR_IRQ_ON_END_MASK 0x00000040 /**< IRQ on end has occurred */ +#define XLLDMA_SR_STOP_ON_END_MASK 0x00000020 /**< Stop on end has occurred */ +#define XLLDMA_SR_COMPLETED_MASK 0x00000010 /**< BD completed */ +#define XLLDMA_SR_SOP_MASK 0x00000008 /**< Current BD has SOP set */ +#define XLLDMA_SR_EOP_MASK 0x00000004 /**< Current BD has EOP set */ +#define XLLDMA_SR_ENGINE_BUSY_MASK 0x00000002 /**< Channel is busy */ +/*@}*/ + + +/** @name Bitmasks associated with XLLDMA_DMACR_OFFSET register + * @{ + */ +#define XLLDMA_DMACR_TX_PAUSE_MASK 0x20000000 /**< Pause TX channel + */ +#define XLLDMA_DMACR_RX_PAUSE_MASK 0x10000000 /**< Pause RX channel + */ +#define XLLDMA_DMACR_PLB_ERR_DIS_MASK 0x00000020 /**< Disable PLB + error detection + */ +#define XLLDMA_DMACR_RX_OVERFLOW_ERR_DIS_MASK 0x00000010 /**< Disable error + when 2 or 4 bit + coalesce counter + overflows */ +#define XLLDMA_DMACR_TX_OVERFLOW_ERR_DIS_MASK 0x00000008 /**< Disable error + when 2 or 4 bit + coalesce counter + overflows */ +#define XLLDMA_DMACR_TAIL_PTR_EN_MASK 0x00000004 /**< Enable use of + tail pointer + register */ +#define XLLDMA_DMACR_EN_ARB_HOLD_MASK 0x00000002 /**< Enable + arbitration + hold */ +#define XLLDMA_DMACR_SW_RESET_MASK 0x00000001 /**< Assert Software + reset for both + channels */ +/*@}*/ + + +/** @name Bitmasks of XLLDMA_BD_STSCTRL_USR0_OFFSET descriptor word + * @{ + */ +#define XLLDMA_BD_STSCTRL_ERROR_MASK 0x80000000 /**< DMA error */ +#define XLLDMA_BD_STSCTRL_IOE_MASK 0x40000000 /**< Interrupt on end */ +#define XLLDMA_BD_STSCTRL_SOE_MASK 0x20000000 /**< Stop on end */ +#define XLLDMA_BD_STSCTRL_COMPLETED_MASK 0x10000000 /**< DMA completed */ +#define XLLDMA_BD_STSCTRL_SOP_MASK 0x08000000 /**< Start of packet */ +#define XLLDMA_BD_STSCTRL_EOP_MASK 0x04000000 /**< End of packet */ +#define XLLDMA_BD_STSCTRL_BUSY_MASK 0x02000000 /**< DMA channel busy */ + +#define XLLDMA_BD_STSCTRL_MASK 0xFF000000 /**< Status/Control field + */ +#define XLLDMA_BD_STSCTRL_USR0_MASK 0x00FFFFFF /**< User field #0 */ +/*@}*/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#ifdef CONFIG_XILINX_LLDMA_USE_DCR + +/* DCR interface is used */ + +#define XLlDma_In32 XIo_DcrIn +#define XLlDma_Out32 XIo_DcrOut + +#else + +/* Non-DCR interface is used */ + +#define XLlDma_In32 XIo_In32 +#define XLlDma_Out32 XIo_Out32 + +#endif + +/*****************************************************************************/ +/** +* +* Read the given register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be read +* +* @return The 32-bit value of the register +* +* @note +* C-style signature: +* u32 XLlDma_mReadReg(u32 BaseAddress, u32 RegOffset) +* +******************************************************************************/ +#define XLlDma_mReadReg(BaseAddress, RegOffset) \ + XLlDma_In32((BaseAddress) + (RegOffset)) + +/*****************************************************************************/ +/** +* +* Write the given register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be written +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note +* C-style signature: +* void XLlDma_mWriteReg(u32 BaseAddress, u32 RegOffset, u32 Data) +* +******************************************************************************/ +#define XLlDma_mWriteReg(BaseAddress, RegOffset, Data) \ + XLlDma_Out32((BaseAddress) + (RegOffset), (Data)) + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_userip.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xlldma_userip.h 2014-07-20 22:06:39.138259830 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2007 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xlldma_userip.h +* +* This file is for the User-IP core (like Local-Link TEMAC) to define constants +* that are the User-IP core specific. DMA driver requires the constants to work +* correctly. Two constants must be defined in this file: +* +* - XLLDMA_USR_APPWORD_OFFSET: +* +* This constant defines a user word the User-IP always updates in the RX +* Buffer Descriptors (BD) during any Receive transaction. +* +* The DMA driver initializes this chosen user word of any RX BD to the +* pre-defined value (see XLLDMA_USR_APPWORD_INITVALUE below) before +* giving it to the RX channel. The DMA relies on its updation (by the +* User-IP) to ensure the BD has been completed by the RX channel besides +* checking the COMPLETE bit in XLLDMA_BD_STSCTRL_USR0_OFFSET field (see +* xlldma_hw.h). +* +* The only valid options for this constant are XLLDMA_BD_USR1_OFFSET, +* XLLDMA_BD_USR2_OFFSET, XLLDMA_BD_USR3_OFFSET and XLLDMA_BD_USR4_OFFSET. +* +* If the User-IP does not update any of the option fields above, the DMA +* driver will not work properly. +* +* - XLLDMA_USR_APPWORD_INITVALUE: +* +* This constant defines the value the DMA driver uses to populate the +* XLLDMA_USR_APPWORD_OFFSET field (see above) in any RX BD before giving +* the BD to the RX channel for receive transaction. +* +* It must be ensured that the User-IP will always populates a different +* value from this constant into the XLLDMA_USR_APPWORD_OFFSET field at +* the end of any receive transaction. Failing to do so will cause the +* DMA driver to work improperly. +* +* If the User-IP uses different setting, the correct setting must be defined as +* a compiler options used in the Makefile. In either case the default +* definition of the constants in this file will be discarded. +* +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a xd 02/21/07 First release +* </pre> +* +******************************************************************************/ + +#ifndef XLLDMA_USERIP_H /* prevent circular inclusions */ +#define XLLDMA_USERIP_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xlldma_hw.h" + +/************************** Constant Definitions *****************************/ + +#ifndef XLLDMA_USERIP_APPWORD_OFFSET +#define XLLDMA_USERIP_APPWORD_OFFSET XLLDMA_BD_USR4_OFFSET +#endif + +#ifndef XLLDMA_USERIP_APPWORD_INITVALUE +#define XLLDMA_USERIP_APPWORD_INITVALUE 0xFFFFFFFF +#endif + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xllfifo.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xllfifo.c 2014-07-20 22:06:39.148259665 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file llfifo.c + * + * The Xilinx local link FIFO driver component. This driver supports the + * Xilinx xps_ll_fifo core. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a jvb 10/13/06 First release + * </pre> + ******************************************************************************/ + + +/***************************** Include Files *********************************/ + +#include <linux/string.h> + +#include "xllfifo_hw.h" +#include "xllfifo.h" +#include "xstatus.h" + +/************************** Constant Definitions *****************************/ + +#define FIFO_WIDTH_BYTES 4 + +/* + * Implementation Notes: + * + * This Fifo driver makes use of a byte streamer driver (xstreamer.h). The code + * is structured like so: + * + * +--------------------+ + * | llfifo | + * | +----------------+ + * | | +--------------+ + * | | | xstreamer | + * | | +--------------+ + * | +----------------+ + * | | + * +--------------------+ + * + * Initialization + * At initialization time this driver (llfifo) sets up the streamer objects to + * use routines in this driver (llfifo) to perform the actual I/O to the H/W + * FIFO core. + * + * Operation + * Once the streamer objects are set up, the API routines in this driver, just + * call through to the streamer driver to perform the read/write operations. + * The streamer driver will eventually make calls back into the routines (which + * reside in this driver) given at initialization to peform the actual I/O. + * + * Interrupts + * Interrupts are handled in the OS/Application layer above this driver. + */ + +xdbg_stmnt(u32 _xllfifo_rr_value;) +xdbg_stmnt(u32 _xllfifo_ipie_value;) +xdbg_stmnt(u32 _xllfifo_ipis_value;) + +/****************************************************************************/ +/* +* +* XLlFifo_RxGetWord reads one 32 bit word from the FIFO specified by +* <i>InstancePtr</i>. +* +* XLlFifo_RxGetLen or XLlFifo_iRxGetLen must be called before calling +* XLlFifo_RxGetWord. Otherwise, the hardware will raise an <i>Over Read +* Exception</i>. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_RxGetWord returns the 32 bit word read from the FIFO. +* +* @note +* C-style signature: +* u32 XLlFifo_RxGetWord(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#define XLlFifo_RxGetWord(InstancePtr) \ + XLlFifo_ReadReg((InstancePtr)->BaseAddress, XLLF_RDFD_OFFSET) + +/****************************************************************************/ +/* +* +* XLlFifo_TxPutWord writes the 32 bit word, <i>Word</i> to the FIFO specified by +* <i>InstancePtr</i>. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlFifo_TxPutWord(XLlFifo *InstancePtr, u32 Word) +* +*****************************************************************************/ +#define XLlFifo_TxPutWord(InstancePtr, Word) \ + XLlFifo_WriteReg((InstancePtr)->BaseAddress, XLLF_TDFD_OFFSET, \ + (Word)) + +/*****************************************************************************/ +/* +* +* XLlFifo_iRxOccupancy returns the number of 32-bit words available (occupancy) +* to be read from the receive channel of the FIFO, specified by +* <i>InstancePtr</i>. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_iRxOccupancy returns the occupancy count in 32-bit words for +* the specified FIFO. +* +******************************************************************************/ +static u32 XLlFifo_iRxOccupancy(XLlFifo *InstancePtr) +{ + XASSERT_NONVOID(InstancePtr); + + return XLlFifo_ReadReg(InstancePtr->BaseAddress, + XLLF_RDFO_OFFSET); +} + +/*****************************************************************************/ +/* +* +* XLlFifo_iRxGetLen notifies the hardware that the program is ready to receive the +* next frame from the receive channel of the FIFO specified by <i>InstancePtr</i>. +* +* Note that the program must first call XLlFifo_iRxGetLen before pulling data +* out of the receive channel of the FIFO with XLlFifo_Read. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_iRxGetLen returns the number of bytes available in the next +* frame. +* +******************************************************************************/ +static u32 XLlFifo_iRxGetLen(XLlFifo *InstancePtr) +{ + XASSERT_NONVOID(InstancePtr); + + return XLlFifo_ReadReg(InstancePtr->BaseAddress, + XLLF_RLF_OFFSET); +} + +/*****************************************************************************/ +/* +* +* XLlFifo_iRead_Aligned reads, <i>WordCount</i>, words from the FIFO referenced by +* <i>InstancePtr</i> to the block of memory, referenced by <i>BufPtr</i>. +* +* XLlFifo_iRead_Aligned assumes that <i>BufPtr</i> is already aligned according +* to the following hardware limitations: +* ppc - aligned on 32 bit boundaries to avoid performance penalties +* from unaligned exception handling. +* microblaze - aligned on 32 bit boundaries as microblaze does not handle +* unaligned transfers. +* +* Care must be taken to ensure that the number of words read with one or more +* calls to XLlFifo_Read() does not exceed the number of bytes (rounded up to +* the nearest whole 32 bit word) available given from the last call to +* XLlFifo_RxGetLen(). +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param BufPtr specifies the memory address to place the data read. +* +* @param WordCount specifies the number of 32 bit words to read. +* +* @return XLlFifo_iRead_Aligned always returns XST_SUCCESS. Error handling is +* otherwise handled through hardware exceptions and interrupts. +* +* @note +* +* C Signature: int XLlFifo_iRead_Aligned(XLlFifo *InstancePtr, +* void *BufPtr, unsigned WordCount); +* +******************************************************************************/ +/* static */ int XLlFifo_iRead_Aligned(XLlFifo *InstancePtr, void *BufPtr, + unsigned WordCount) +{ + unsigned WordsRemaining = WordCount; + u32 *BufPtrIdx = BufPtr; + + xdbg_printf(XDBG_DEBUG_FIFO_RX, "XLlFifo_iRead_Aligned: start\n"); + XASSERT_NONVOID(InstancePtr); + XASSERT_NONVOID(BufPtr); + /* assert bufer is 32 bit aligned */ + XASSERT_NONVOID(((unsigned)BufPtr & 0x3) == 0x0); + xdbg_printf(XDBG_DEBUG_FIFO_RX, "XLlFifo_iRead_Aligned: after asserts\n"); + + while (WordsRemaining) { +/* xdbg_printf(XDBG_DEBUG_FIFO_RX, + "XLlFifo_iRead_Aligned: WordsRemaining: %d\n", + WordsRemaining); +*/ + *BufPtrIdx = XLlFifo_RxGetWord(InstancePtr); + BufPtrIdx++; + WordsRemaining--; + } + xdbg_printf(XDBG_DEBUG_FIFO_RX, + "XLlFifo_iRead_Aligned: returning SUCCESS\n"); + return XST_SUCCESS; +} + +/****************************************************************************/ +/* +* +* XLlFifo_iTxVacancy returns the number of unused 32 bit words available +* (vacancy) in the send channel of the FIFO, specified by <i>InstancePtr</i>. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_iTxVacancy returns the vacancy count in 32-bit words for +* the specified FIFO. +* +*****************************************************************************/ +static u32 XLlFifo_iTxVacancy(XLlFifo *InstancePtr) +{ + XASSERT_NONVOID(InstancePtr); + + return XLlFifo_ReadReg(InstancePtr->BaseAddress, + XLLF_TDFV_OFFSET); +} + +/*****************************************************************************/ +/* +* +* XLlFifo_iTxSetLen begins a hardware transfer of data out of the transmit +* channel of the FIFO, specified by <i>InstancePtr</i>. <i>Bytes</i> specifies the number +* of bytes in the frame to transmit. +* +* Note that <i>Bytes</i> (rounded up to the nearest whole 32 bit word) must be same +* number of words just written using one or more calls to +* XLlFifo_iWrite_Aligned() +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param Bytes specifies the number of bytes to transmit. +* +* @return N/A +* +******************************************************************************/ +static void XLlFifo_iTxSetLen(XLlFifo *InstancePtr, u32 Bytes) +{ + XASSERT_VOID(InstancePtr); + + XLlFifo_WriteReg(InstancePtr->BaseAddress, XLLF_TLF_OFFSET, + Bytes); +} + +/*****************************************************************************/ +/* +* +* XLlFifo_iWrite_Aligned writes, <i>WordCount</i>, words to the FIFO referenced by +* <i>InstancePtr</i> from the block of memory, referenced by <i>BufPtr</i>. +* +* XLlFifo_iWrite_Aligned assumes that <i>BufPtr</i> is already aligned according +* to the following hardware limitations: +* ppc - aligned on 32 bit boundaries to avoid performance penalties +* from unaligned exception handling. +* microblaze - aligned on 32 bit boundaries as microblaze does not handle +* unaligned transfers. +* +* Care must be taken to ensure that the number of words written with one or +* more calls to XLlFifo_iWrite_Aligned() matches the number of bytes (rounded up +* to the nearest whole 32 bit word) given in the next call to +* XLlFifo_iTxSetLen(). +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param BufPtr specifies the memory address to place the data read. +* +* @param WordCount specifies the number of 32 bit words to read. +* +* @return XLlFifo_iWrite_Aligned always returns XST_SUCCESS. Error handling is +* otherwise handled through hardware exceptions and interrupts. +* +* @note +* +* C Signature: int XLlFifo_iWrite_Aligned(XLlFifo *InstancePtr, +* void *BufPtr, unsigned WordCount); +* +******************************************************************************/ +/* static */ int XLlFifo_iWrite_Aligned(XLlFifo *InstancePtr, void *BufPtr, + unsigned WordCount) +{ + unsigned WordsRemaining = WordCount; + u32 *BufPtrIdx = BufPtr; + + xdbg_printf(XDBG_DEBUG_FIFO_TX, + "XLlFifo_iWrite_Aligned: Inst: %p; Buff: %p; Count: %d\n", + InstancePtr, BufPtr, WordCount); + XASSERT_NONVOID(InstancePtr); + XASSERT_NONVOID(BufPtr); + /* assert bufer is 32 bit aligned */ + XASSERT_NONVOID(((unsigned)BufPtr & 0x3) == 0x0); + + xdbg_printf(XDBG_DEBUG_FIFO_TX, + "XLlFifo_iWrite_Aligned: WordsRemaining: %d\n", + WordsRemaining); + while (WordsRemaining) { + XLlFifo_TxPutWord(InstancePtr, *BufPtrIdx); + BufPtrIdx++; + WordsRemaining--; + } + + xdbg_printf(XDBG_DEBUG_FIFO_TX, + "XLlFifo_iWrite_Aligned: returning SUCCESS\n"); + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* XLlFifo_Initialize initializes an XPS_ll_Fifo device along with the +* <i>InstancePtr</i> that references it. +* +* @param InstancePtr references the memory instance to be associated with +* the FIFO device upon initialization. +* +* @param BaseAddress is the processor address used to access the +* base address of the Fifo device. +* +* @return N/A +* +******************************************************************************/ +void XLlFifo_Initialize(XLlFifo *InstancePtr, u32 BaseAddress) +{ + XASSERT_VOID(InstancePtr); + XASSERT_VOID(BaseAddress); + + /* Clear instance memory */ + memset(InstancePtr, 0, sizeof(XLlFifo)); + + /* + * We don't care about the physical base address, just copy the + * processor address over it. + */ + InstancePtr->BaseAddress = BaseAddress; + + InstancePtr->IsReady = XCOMPONENT_IS_READY; + + XLlFifo_TxReset(InstancePtr); + XLlFifo_RxReset(InstancePtr); + + XStrm_RxInitialize(&(InstancePtr->RxStreamer), FIFO_WIDTH_BYTES, + (void *)InstancePtr, + (XStrm_XferFnType)XLlFifo_iRead_Aligned, + (XStrm_GetLenFnType)XLlFifo_iRxGetLen, + (XStrm_GetOccupancyFnType)XLlFifo_iRxOccupancy); + + XStrm_TxInitialize(&(InstancePtr->TxStreamer), FIFO_WIDTH_BYTES, + (void *)InstancePtr, + (XStrm_XferFnType)XLlFifo_iWrite_Aligned, + (XStrm_SetLenFnType)XLlFifo_iTxSetLen, + (XStrm_GetVacancyFnType)XLlFifo_iTxVacancy); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xllfifo.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xllfifo.h 2014-07-20 22:06:39.160259467 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file llfifo.h + * + * The Xilinx Dual Channel Fifo driver component. This driver supports the + * Virtex-5(TM) and Virtex-4(TM) XPS_ll_Fifo. + * + * For a full description of the bridge features, please see the HW spec. This driver + * supports the following features: + * - Memory mapped access to host interface registers + * - API for polled frame transfers + * - API for interrupt driven frame transfers + * - Virtual memory support + * - Full duplex operation + * + * <h2>Driver Description</h2> + * + * This driver enables higher layer software to access the XPS_llFifo core + * using any alignment in the data buffers. + * + * This driver supports send and receive channels in the same instance + * structure in the same fashion as the hardware core. + * + * <h2>Initialization</h2> + * + * An instance of this driver is initialized using a call to Initialize(). + * + * <h2>Usage</h2> + * + * It is fairly simple to use the API provided by this FIFO driver. The + * only somewhat tricky part is that the calling code must correctly call + * a couple routines in the right sequence for receive and transmit. + * + * This sequence is described here. Check the routine functional + * descriptions for information on how to use a specific API routine. + * + * <h3>Receive</h3> + * + * A frame is received by using the following sequence:<br> + * 1) call XLlFifo_RxGetLen() to get the length of the next incoming frame<br> + * 2) call XLlFifo_Read() one or more times to read the number of bytes + * reported by XLlFifo_RxGetLen().<br> + * + * For example: + * <pre> + * frame_len = XLlFifo_RxGetLen(&RxInstance); + * while (frame_len) { + * unsigned bytes = min(sizeof(buffer), frame_len); + * XLlFifo_Read(&RxInstance, buffer, bytes); + * // ******** + * // do something with buffer here + * // ******** + * frame_len -= bytes; + * } + * </pre> + * + * This FIFO hardware core does <b>not</b> support a sequence where the + * calling code calls RxGetLen() twice in a row and then receive the data + * for two frames. Each frame must be read in by calling RxGetLen() just + * prior to reading the data. + * + * <h3>Transmit</h3> + * A frame is transmittted by using the following sequence:<br> + * 1) call XLlFifo_Write() one or more times to write all the of bytes in + * the next frame.<br> + * 2) call XLlFifo_TxSetLen() to begin the transmission of frame just + * written.<br> + * + * For example: + * <pre> + * frame_left = frame_len; + * while (frame_left) { + * unsigned bytes = min(sizeof(buffer), frame_left); + * XLlFifo_Write(&TxInstance, buffer, bytes); + * // ******** + * // do something here to refill buffer + * // ******** + * } + * XLlFifo_TxSetLen(&RxInstance, frame_len); + * </pre> + * + * This FIFO hardware core does <b>not</b> support a sequence where the + * calling code writes the data for two frames and then calls TxSetLen() + * twice in a row. Each frame must be written by writting the data for one + * frame and then calling TxSetLen(). + * + * <h2>Interrupts</h2> + * This driver does not handle interrupts from the FIFO hardware. The + * software layer above may make use of the interrupts by setting up its + * own handlers for the interrupts. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a jvb 10/12/06 First release + * </pre> + * + *****************************************************************************/ +#ifndef XLLFIFO_H /* prevent circular inclusions */ +#define XLLFIFO_H /* by using preprocessor symbols */ + +/* force C linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xllfifo_hw.h" +#include "xstreamer.h" + +/**************************** Type Definitions *******************************/ + +/** + * This typedef defines a run-time instance of an XLlFifo device. + */ +typedef struct XLlFifo { + u32 BaseAddress; /**< BaseAddress is the physical base address of the + * device's registers + */ + + u32 IsReady; /**< IsReady is non-zero if the driver instance + * has been initialized. + */ + XStrm_RxFifoStreamer RxStreamer; /**< RxStreamer is the byte streamer + * instance for the receive channel. + */ + XStrm_TxFifoStreamer TxStreamer; /**< TxStreamer is the byte streamer + * instance for the transmit channel. + */ +} XLlFifo; + +/****************************************************************************/ +/** +* +* XLlFifo_Reset resets both the Tx and Rx channels and the local link interface +* the FIFO specified by <i>InstancePtr</i>. XLlFifo_TxReset resets also sends a +* reset pulse to the downstream device (e.g. TEMAC). XLlFifo_Reset drops any +* bytes in the FIFO not yet retrieved. XLlFifo_Reset drops any bytes in the FIFO +* not yet transmitted. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlFifo_Reset(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#define XLlFifo_Reset(InstancePtr) \ + XLlFifo_WriteReg((InstancePtr)->BaseAddress, XLLF_LLR_OFFSET, \ + XLLF_LLR_RESET_MASK) + + +/****************************************************************************/ +/** +* +* XLlFifo_Status returns a bit mask of the interrupt status register (ISR) +* for the FIFO specified by <i>InstancePtr</i>. XLlFifo_Status can be used +* to query the status of the FIFO without having to have interrupts enabled. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_IntStatus returns a bit mask of the status conditions. +* The mask will be a set of bitwise or'd values from the +* <code>XLLF_INT_*_MASK</code> preprocessor symbols. +* +* @note +* C-style signature: +* u32 XLlFifo_IntStatus(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#define XLlFifo_Status(InstancePtr) \ + XLlFifo_ReadReg((InstancePtr)->BaseAddress, XLLF_ISR_OFFSET) + +/****************************************************************************/ +/** +* +* XLlFifo_IntEnable enables the interrupts specified in <i>Mask</i> for the +* FIFO specified by <i>InstancePtr</i>. The corresponding interrupt for each bit +* set to 1 in <i>Mask</i>, will be enabled. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param Mask contains a bit mask of the interrupts to enable. The mask +* can be formed using a set of bitwise or'd values from the +* <code>XLLF_INT_*_MASK</code> preprocessor symbols. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlFifo_IntEnable(XLlFifo *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XLlFifo_IntEnable(InstancePtr, Mask) \ +{ \ + u32 Reg = XLlFifo_ReadReg((InstancePtr)->BaseAddress, \ + XLLF_IER_OFFSET); \ + Reg |= ((Mask) & XLLF_INT_ALL_MASK); \ + XLlFifo_WriteReg((InstancePtr)->BaseAddress, XLLF_IER_OFFSET, \ + Reg); \ +} + +/****************************************************************************/ +/** +* +* XLlFifo_IntDisable disables the interrupts specified in <i>Mask</i> for the +* FIFO specified by <i>InstancePtr</i>. The corresponding interrupt for each bit +* set to 1 in <i>Mask</i>, will be disabled. In other words, XLlFifo_IntDisable +* uses the "set a bit to clear it" scheme. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param Mask contains a bit mask of the interrupts to disable. The mask +* can be formed using a set of bitwise or'd values from the +* <code>XLLF_INT_*_MASK</code> preprocessor symbols. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlFifo_IntDisable(XLlFifo *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XLlFifo_IntDisable(InstancePtr, Mask) \ +{ \ + u32 Reg = XLlFifo_ReadReg((InstancePtr)->BaseAddress, \ + XLLF_IER_OFFSET); \ + Reg &= ~((Mask) & XLLF_INT_ALL_MASK); \ + XLlFifo_WriteReg((InstancePtr)->BaseAddress, XLLF_IER_OFFSET, \ + Reg); \ +} + +/****************************************************************************/ +/** +* +* XLlFifo_IntPending returns a bit mask of the pending interrupts for the +* FIFO specified by <i>InstancePtr</i>. Each bit set to 1 in the return value +* represents a pending interrupt. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_IntPending returns a bit mask of the interrupts that are +* pending. The mask will be a set of bitwise or'd values from the +* <code>XLLF_INT_*_MASK</code> preprocessor symbols. +* +* @note +* C-style signature: +* u32 XLlFifo_IntPending(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#ifdef DEBUG +extern u32 _xllfifo_ipie_value; +extern u32 _xllfifo_ipis_value; +#define XLlFifo_IntPending(InstancePtr) \ + (_xllfifo_ipie_value = XLlFifo_ReadReg( \ + (InstancePtr)->BaseAddress, XLLF_IER_OFFSET), \ + _xllfifo_ipis_value = XLlFifo_ReadReg( \ + (InstancePtr)->BaseAddress, XLLF_ISR_OFFSET), \ + (_xllfifo_ipie_value & _xllfifo_ipis_value)) +#else +#define XLlFifo_IntPending(InstancePtr) \ + (XLlFifo_ReadReg((InstancePtr)->BaseAddress, XLLF_IER_OFFSET) & \ + XLlFifo_ReadReg((InstancePtr)->BaseAddress, XLLF_ISR_OFFSET)) +#endif + +/****************************************************************************/ +/** +* +* XLlFifo_IntClear clears pending interrupts specified in <i>Mask</i> for the +* FIFO specified by <i>InstancePtr</i>. The corresponding pending interrupt for +* each bit set to 1 in <i>Mask</i>, will be cleared. In other words, +* XLlFifo_IntClear uses the "set a bit to clear it" scheme. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param Mask contains a bit mask of the pending interrupts to clear. The +* mask can be formed using a set of bitwise or'd values from the +* <code>XLLF_INT_*_MASK</code> preprocessor symbols. +* +* @note +* C-style signature: +* void XLlFifo_IntClear(XLlFifo *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XLlFifo_IntClear(InstancePtr, Mask) \ + XLlFifo_WriteReg((InstancePtr)->BaseAddress, XLLF_ISR_OFFSET, \ + ((Mask) & XLLF_INT_ALL_MASK)) + +/****************************************************************************/ +/** +* +* XLlFifo_RxReset resets the receive channel of the FIFO specified by +* <i>InstancePtr</i>. XLlFifo_RxReset drops any bytes in the FIFO not yet +* retrieved. +* +* The calling software may want to test for the completion of the reset by +* reading the interrupt status (IS) register and testing for the Rx Reset +* complete (RRC) bit. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlFifo_RxReset(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#define XLlFifo_RxReset(InstancePtr) \ + XLlFifo_WriteReg((InstancePtr)->BaseAddress, XLLF_RDFR_OFFSET, \ + XLLF_RDFR_RESET_MASK) + +/****************************************************************************/ +/** +* +* XLlFifo_IsRxEmpty returns true if the receive channel of the FIFO, specified +* by <i>InstancePtr</i>, is empty. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_IsRxEmpty returns TRUE when the receive channel of the +* FIFO is empty. Otherwise, XLlFifo_IsRxEmpty returns FALSE. +* +* @note +* C-style signature: +* int XLlFifo_IsRxEmpty(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#define XLlFifo_IsRxEmpty(InstancePtr) \ + ((XStrm_IsRxInternalEmpty(&((InstancePtr)->RxStreamer)) && \ + ((XLlFifo_ReadReg((InstancePtr)->BaseAddress, \ + XLLF_RDFO_OFFSET) == 0))) \ + ? TRUE : FALSE) + + +/*****************************************************************************/ +/** +* +* XLlFifo_RxOccupancy returns the number of 32-bit words available (occupancy) to +* be read from the receive channel of the FIFO, specified by <i>InstancePtr</i>. +* +* The xps_ll_fifo core uses the same fifo to store data values and frame length +* values. Upon initialization, the XLlFifo_RxOccupancy will give the value of +* 1, which means one length value (a reserved fifo location) and no data +* values. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_RxOccupancy returns the occupancy count for the specified +* packet FIFO. +* +* @note +* +* C Signature: u32 XLlFifo_RxOccupancy(XLlFifo *InstancePtr) +* +******************************************************************************/ +#define XLlFifo_RxOccupancy(InstancePtr) \ + XStrm_RxOccupancy(&((InstancePtr)->RxStreamer)) + +/*****************************************************************************/ +/** +* +* XLlFifo_RxGetLen notifies the hardware that the program is ready to receive +* the next frame from the receive channel of the FIFO, specified by +* <i>InstancePtr</i>. +* +* Note that the program must first call XLlFifo_RxGetLen before pulling data +* out of the receive channel of the FIFO with XLlFifo_Read. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_RxGetLen returns the number of bytes available in the next +* frame. +* +* @note +* +* C Signature: u32 XLlFifo_RxGetLen(XLlFifo *InstancePtr) +* +******************************************************************************/ +#define XLlFifo_RxGetLen(InstancePtr) \ + XStrm_RxGetLen(&((InstancePtr)->RxStreamer)) + +/*****************************************************************************/ +/** +* +* XLlFifo_Read reads <i>Bytes</i> bytes from the receive channel of the FIFO +* referenced by <i>InstancePtr</i> to the block of memory, referenced by +* <i>BufPtr</i>. +* +* Care must be taken to ensure that the number of bytes read with one or more +* calls to XLlFifo_Read() does not exceed the number of bytes available given +* from the last call to XLlFifo_RxGetLen(). +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param BufPtr specifies the memory address to place the data read. +* +* @param Bytes specifies the number of bytes to read. +* +* @return N/A +* +* @note +* Error handling is handled through hardware exceptions and interrupts. +* +* C Signature: void XLlFifo_Read(XLlFifo *InstancePtr, void *BufPtr, unsigned Bytes) +* +******************************************************************************/ +#define XLlFifo_Read(InstancePtr, BufPtr, Bytes) \ + XStrm_Read(&((InstancePtr)->RxStreamer), (BufPtr), (Bytes)) + +/****************************************************************************/ +/** +* +* XLlFifo_TxReset resets the transmit channel of the FIFO specified by +* <i>InstancePtr</i>. XLlFifo_TxReset drops any bytes in the FIFO not yet +* transmitted. +* +* The calling software may want to test for the completion of the reset by +* reading the interrupt status (IS) register and testing for the Tx Reset +* complete (TRC) bit. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlFifo_TxReset(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#define XLlFifo_TxReset(InstancePtr) \ + XLlFifo_WriteReg((InstancePtr)->BaseAddress, XLLF_TDFR_OFFSET, \ + XLLF_TDFR_RESET_MASK) + +/****************************************************************************/ +/** +* +* XLlFifo_IsTxDone returns true if the transmission in the transmit channel +* of the FIFO, specified by <i>InstancePtr</i>, is complete. XLlFifo_IsTxDone +* works only if the TC bit in the IS register is cleared before sending a +* frame. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_IsTxDone returns TRUE when the transmit channel of the +* FIFO is complete. Otherwise, XLlFifo_IsTxDone returns FALSE. +* +* @note +* C-style signature: +* int XLlFifo_IsTxDone(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#define XLlFifo_IsTxDone(InstancePtr) \ + ((XLlFifo_ReadReg((InstancePtr)->BaseAddress, XLLF_ISR_OFFSET) & \ + XLLF_INT_TC_MASK) \ + ? TRUE : FALSE) + +/****************************************************************************/ +/** +* +* XLlFifo_TxVacancy returns the number of unused 32 bit words available +* (vacancy) in the send channel of the FIFO specified by <i>InstancePtr</i>. +* +* The xps_ll_fifo core uses tXLLF_he same fifo to store data values and frame length +* values. Upon initialization, the XLlFifo_TxVacancy will give the value of +* FIFO_WIDTH - 1, which means one length value used (a reserved fifo location) +* and no data values yet present. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XLlFifo_TxVacancy returns the vacancy count in 32-bit words for +* the specified FIFO. +* +* @note +* C-style signature: +* u32 XLlFifo_TxVacancy(XLlFifo *InstancePtr) +* +*****************************************************************************/ +#define XLlFifo_TxVacancy(InstancePtr) \ + XStrm_TxVacancy(&((InstancePtr)->TxStreamer)) + +/*****************************************************************************/ +/** +* +* XLlFifo_TxSetLen begins a hardware transfer of <i>Bytes</i> bytes out of the +* transmit channel of the FIFO specified by <i>InstancePtr</i>. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param Bytes specifies the frame length in bytes. +* +* @return N/A +* +* @note +* +* C Signature: void XLlFifo_TxSetLen(XLlFifo *InstancePtr, u32 Bytes) +* +******************************************************************************/ +#define XLlFifo_TxSetLen(InstancePtr, Bytes) \ + XStrm_TxSetLen(&((InstancePtr)->TxStreamer), (Bytes)) + +/*****************************************************************************/ +/** +* +* XLlFifo_Write writes <i>Bytes</i> bytes of the block of memory, referenced by +* <i>BufPtr</i>, to the transmit channel of the FIFO referenced by +* <i>InstancePtr</i>. +* +* Care must be taken to ensure that the number of bytes written with one or +* more calls to XLlFifo_Write() matches the number of bytes given in the next +* call to XLlFifo_TxSetLen(). +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param BufPtr specifies the memory address of data to write. +* +* @param Bytes specifies the number of bytes to write. +* +* @return N/A +* +* @note +* Error handling is handled through hardware exceptions and interrupts. +* +* C Signature: void XLlFifo_Write(XLlFifo *InstancePtr, void *BufPtr, unsigned Bytes) +* +******************************************************************************/ +#define XLlFifo_Write(InstancePtr, BufPtr, Bytes) \ + XStrm_Write(&((InstancePtr)->TxStreamer), (BufPtr), (Bytes)) + + +/************************** Function Prototypes ******************************/ +/* + * Initialization functions in xtemac_sinit.c + */ +void XLlFifo_Initialize(XLlFifo *InstancePtr, u32 BaseAddress); + +#ifdef __cplusplus +} +#endif +#endif /* XLLFIFO_H end of preprocessor protection symbols */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xllfifo_hw.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xllfifo_hw.h 2014-07-20 22:06:39.169259319 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2004-2006 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file llfifo_hw.h +* +* This header file contains identifiers and low-level driver functions (or +* macros) that can be used to access the xps_ll_fifo core. +* High-level driver functions are defined in xpfifo.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a jvb 10/16/06 First release. +* </pre> +* +******************************************************************************/ + +#ifndef XLLFIFO_HW_H /* prevent circular inclusions */ +#define XLLFIFO_HW_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xio.h" +#include "xdebug.h" + +/************************** Constant Definitions *****************************/ + +/* Register offset definitions. Unless otherwise noted, register access is + * 32 bit. + */ + +/** @name Registers + * @{ + */ +#define XLLF_ISR_OFFSET 0x00000000 /**< Interrupt Status */ +#define XLLF_IER_OFFSET 0x00000004 /**< Interrupt Enable */ + +#define XLLF_TDFR_OFFSET 0x00000008 /**< Transmit Reset */ +#define XLLF_TDFV_OFFSET 0x0000000c /**< Transmit Vacancy */ +#define XLLF_TDFD_OFFSET 0x00000010 /**< Transmit Data */ +#define XLLF_TLF_OFFSET 0x00000014 /**< Transmit Length */ + +#define XLLF_RDFR_OFFSET 0x00000018 /**< Receive Reset */ +#define XLLF_RDFO_OFFSET 0x0000001c /**< Receive Occupancy */ +#define XLLF_RDFD_OFFSET 0x00000020 /**< Receive Data */ +#define XLLF_RLF_OFFSET 0x00000024 /**< Receive Length */ +#define XLLF_LLR_OFFSET 0x00000028 /**< Local Link Reset */ + +/*@}*/ + +/* Register masks. The following constants define bit locations of various + * control bits in the registers. Constants are not defined for those registers + * that have a single bit field representing all 32 bits. For further + * information on the meaning of the various bit masks, refer to the HW spec. + */ + +/** @name Interrupt bits + * These bits are associated with the XLLF_IER_OFFSET and XLLF_ISR_OFFSET + * registers. + * @{ + */ +#define XLLF_INT_RPURE_MASK 0x80000000 /**< Receive under-read */ +#define XLLF_INT_RPORE_MASK 0x40000000 /**< Receive over-read */ +#define XLLF_INT_RPUE_MASK 0x20000000 /**< Receive underrun (empty) */ +#define XLLF_INT_TPOE_MASK 0x10000000 /**< Transmit overrun */ +#define XLLF_INT_TC_MASK 0x08000000 /**< Transmit complete */ +#define XLLF_INT_RC_MASK 0x04000000 /**< Receive complete */ +#define XLLF_INT_TSE_MASK 0x02000000 /**< Transmit length mismatch */ +#define XLLF_INT_TRC_MASK 0x01000000 /**< Transmit reset complete */ +#define XLLF_INT_RRC_MASK 0x00800000 /**< Receive reset complete */ +#define XLLF_INT_ALL_MASK 0xff800000 /**< All the ints */ +#define XLLF_INT_ERROR_MASK 0xf2000000 /**< Error status ints */ +#define XLLF_INT_RXERROR_MASK 0xe0000000 /**< Receive Error status ints */ +#define XLLF_INT_TXERROR_MASK 0x12000000 /**< Transmit Error status ints */ +/*@}*/ + +/** @name Reset register values + * These bits are associated with the XLLF_TDFR_OFFSET and XLLF_RDFR_OFFSET + * reset registers. + * @{ + */ +#define XLLF_RDFR_RESET_MASK 0x000000a5 /**< receive reset value */ +#define XLLF_TDFR_RESET_MASK 0x000000a5 /**< Transmit reset value */ +#define XLLF_LLR_RESET_MASK 0x000000a5 /**< Local Link reset value */ +/*@}*/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/**** debug macros ****/ +#define XLlFifo_reg_name(RegOffset) \ + (((RegOffset) == XLLF_ISR_OFFSET) ? "ISR": \ + ((RegOffset) == XLLF_IER_OFFSET) ? "IER": \ + ((RegOffset) == XLLF_TDFR_OFFSET) ? "TDFR {tx reset}": \ + ((RegOffset) == XLLF_TDFV_OFFSET) ? "TDFV {tx vacancy}": \ + ((RegOffset) == XLLF_TDFD_OFFSET) ? "TDFD {tx data}": \ + ((RegOffset) == XLLF_TLF_OFFSET) ? "TLF {tx length}": \ + ((RegOffset) == XLLF_RDFR_OFFSET) ? "RDFR {rx reset}": \ + ((RegOffset) == XLLF_RDFO_OFFSET) ? "RDFO {rx occupancy}": \ + ((RegOffset) == XLLF_RDFD_OFFSET) ? "RDFD {rx data}": \ + ((RegOffset) == XLLF_RLF_OFFSET) ? "RLF {rx length}": \ + "unknown") + +#define XLlFifo_print_reg_o(BaseAddress, RegOffset, Value) \ + xdbg_printf(XDBG_DEBUG_FIFO_REG, "0x%08x -> %s(0x%08x)\n", (Value), \ + XLlFifo_reg_name(RegOffset), \ + (RegOffset) + (BaseAddress)) + +#define XLlFifo_print_reg_i(BaseAddress, RegOffset, Value) \ + xdbg_printf(XDBG_DEBUG_FIFO_REG, "%s(0x%08x) -> 0x%08x\n", \ + XLlFifo_reg_name(RegOffset), \ + (RegOffset) + (BaseAddress), (Value)) +/**** end debug macros ****/ + +/****************************************************************************/ +/** +* +* XLlFifo_ReadReg returns the value of the register at the offet, +* <i>RegOffset</i>, from the memory mapped base address, <i>BaseAddress</i>. +* +* @param BaseAddress specifies the base address of the device. +* +* @param RegOffset specifies the offset from BaseAddress. +* +* @return XLlFifo_ReadReg returns the value of the specified register. +* +* @note +* C-style signature: +* u32 XLlFifo_ReadReg(u32 BaseAddress, u32 RegOffset) +* +*****************************************************************************/ +#ifdef DEBUG +extern u32 _xllfifo_rr_value; +#define XLlFifo_ReadReg(BaseAddress, RegOffset) \ + ((((RegOffset) > 0x24) ? xdbg_printf(XDBG_DEBUG_ERROR, \ + "XLlFifo_WriteReg: Woah! wrong reg addr: 0x%08x\n", \ + (RegOffset)) : 0), \ + _xllfifo_rr_value = XIo_In32((BaseAddress) + (RegOffset)), \ + XLlFifo_print_reg_i((BaseAddress), (RegOffset), _xllfifo_rr_value), \ + _xllfifo_rr_value) +#else +#define XLlFifo_ReadReg(BaseAddress, RegOffset) \ + (XIo_In32((BaseAddress) + (RegOffset))) +#endif + +/****************************************************************************/ +/** +* +* XLlFifo_WriteReg writes the value, <i>Value</i>, to the register at the +* offet, <i>RegOffset</i>, from the memory mapped base address, +* <i>BaseAddress</i>. +* +* @param BaseAddress specifies the base address of the device. +* +* @param RegOffset specifies the offset from BaseAddress. +* +* @param Value is value to write to the register. +* +* @return N/A +* +* @note +* C-style signature: +* void XLlFifo_WriteReg(u32 BaseAddress, u32 RegOffset, u32 Value) +* +*****************************************************************************/ +#ifdef DEBUG +#define XLlFifo_WriteReg(BaseAddress, RegOffset, Value) \ + (((RegOffset) > 0x24) ? xdbg_printf(XDBG_DEBUG_ERROR, \ + "XLlFifo_WriteReg: Woah! wrong reg addr: 0x%08x\n", \ + (RegOffset)) : 0), \ + XLlFifo_print_reg_o((BaseAddress), (RegOffset), (Value)), \ + (XIo_Out32((BaseAddress) + (RegOffset), (Value))) +#else +#define XLlFifo_WriteReg(BaseAddress, RegOffset, Value) \ + ((XIo_Out32((BaseAddress) + (RegOffset), (Value)))) +#endif + +#ifdef __cplusplus +} +#endif +#endif /* XLLFIFO_HW_H end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xpacket_fifo_l_v2_00_a.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xpacket_fifo_l_v2_00_a.c 2014-07-20 22:06:39.184259072 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xpacket_fifo_l_v2_00_a.c,v 1.1 2006/12/13 14:22:53 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2003-2004 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xpacket_fifo_l_v2_00_a.c +* +* Contains low-level (Level 0) functions for the XPacketFifoV200a driver. +* See xpacket_fifo_v2_00_a.h for information about the high-level (Level 1) +* driver. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------ +* 2.00a rpm 10/22/03 First release. Moved most of Level 1 driver functions +* into this layer. +* 2.00a rmm 02/24/04 Added L0WriteDRE function. +* 2.00a xd 10/27/04 Changed comments to support doxygen for API +* documentation. +* </pre> +* +*****************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xio.h" +#include "xpacket_fifo_l_v2_00_a.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************* Variable Definitions ******************************/ + + +/************************** Function Prototypes ******************************/ + +static int Write32(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount); + +static int Write64(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount); + +static int Read32(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount); + +static int Read64(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount); + + +/*****************************************************************************/ +/** +* +* Read data from a FIFO and puts it into a specified buffer. The packet FIFO is +* currently 32 or 64 bits wide such that an input buffer which is a series of +* bytes is filled from the FIFO a word at a time. If the requested byte count +* is not a multiple of 32/64 bit words, it is necessary for this function to +* format the remaining 32/64 bit word from the FIFO into a series of bytes in +* the buffer. There may be up to 3/7 extra bytes which must be extracted from +* the last word of the FIFO and put into the buffer. +* +* @param RegBaseAddress is the base address of the FIFO registers. +* +* @param DataBaseAddress is the base address of the FIFO keyhole. +* +* @param BufferPtr points to the memory buffer to write the data into. This +* buffer must be 32 bit aligned or an alignment exception could be +* generated. Since this buffer is a byte buffer, the data is assumed to +* be endian independent. +* +* @param ByteCount contains the number of bytes to read from the FIFO. This +* number of bytes must be present in the FIFO or an error will be +* returned. +* +* @return +* +* XST_SUCCESS indicates the operation was successful. If the number of +* bytes specified by the byte count is not present in the FIFO +* XST_PFIFO_LACK_OF_DATA is returned. +* <br><br> +* If the function was successful, the specified buffer is modified to contain +* the bytes which were removed from the FIFO. +* +* @note +* +* Note that the exact number of bytes which are present in the FIFO is +* not known by this function. It can only check for a number of 32/64 bit +* words such that if the byte count specified is incorrect, but is still +* possible based on the number of words in the FIFO, up to 3/7 garbage bytes +* may be present at the end of the buffer. +* <br><br> +* This function assumes that if the device consuming data from the FIFO is +* a byte device, the order of the bytes to be consumed is from the most +* significant byte to the least significant byte of a 32/64 bit word removed +* from the FIFO. +* +******************************************************************************/ +int XPacketFifoV200a_L0Read(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount) +{ + u32 Width; + int Result = XST_FIFO_ERROR; + + /* determine the width of the FIFO + */ + Width = XIo_In32(RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & + XPF_V200A_FIFO_WIDTH_MASK; + + if ((Width == XPF_V200A_FIFO_WIDTH_LEGACY_TYPE) || + (Width == XPF_V200A_FIFO_WIDTH_32BITS_TYPE)) { + Result = Read32(RegBaseAddress, DataBaseAddress, BufferPtr, + ByteCount); + } + else if (Width == XPF_V200A_FIFO_WIDTH_64BITS_TYPE) { + Result = Read64(RegBaseAddress, DataBaseAddress, BufferPtr, + ByteCount); + } + + return Result; + +} + +/*****************************************************************************/ +/** +* +* Write data into a packet FIFO. The packet FIFO is currently 32 or 64 bits +* wide such that an input buffer which is a series of bytes must be written +* into the FIFO a word at a time. If the buffer is not a multiple of 32 bit +* words, it is necessary for this function to format the remaining bytes into +* a single 32 bit word to be inserted into the FIFO. This is necessary to +* avoid any accesses past the end of the buffer. +* +* @param RegBaseAddress is the base address of the FIFO registers. +* +* @param DataBaseAddress is the base address of the FIFO keyhole. +* +* @param BufferPtr points to the memory buffer that data is to be read from +* and written into the FIFO. Since this buffer is a byte buffer, the +* data is assumed to be endian independent. This buffer must be 32 bit +* aligned or an alignment exception could be generated. +* +* @param ByteCount contains the number of bytes to read from the buffer and to +* write to the FIFO. +* +* @return +* +* XST_SUCCESS is returned if the operation succeeded. If there is not enough +* room in the FIFO to hold the specified bytes, XST_PFIFO_NO_ROOM is +* returned. +* +* @note +* +* This function assumes that if the device inserting data into the FIFO is +* a byte device, the order of the bytes in each 32/64 bit word is from the most +* significant byte to the least significant byte. +* +******************************************************************************/ +int XPacketFifoV200a_L0Write(u32 RegBaseAddress, + u32 DataBaseAddress, u8 *BufferPtr, u32 ByteCount) +{ + u32 Width; + int Result = XST_FIFO_ERROR; + + + /* determine the width of the FIFO + */ + Width = XIo_In32(RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & + XPF_V200A_FIFO_WIDTH_MASK; + + if ((Width == XPF_V200A_FIFO_WIDTH_LEGACY_TYPE) || + (Width == XPF_V200A_FIFO_WIDTH_32BITS_TYPE)) { + Result = Write32(RegBaseAddress, DataBaseAddress, BufferPtr, + ByteCount); + } + else if (Width == XPF_V200A_FIFO_WIDTH_64BITS_TYPE) { + Result = Write64(RegBaseAddress, DataBaseAddress, BufferPtr, + ByteCount); + } + + return Result; + +} + +/*****************************************************************************/ +/** +* +* Write data into a packet FIFO configured for the Data Realignment Engine +* (DRE). A packet FIFO channel configured in this way will accept any +* combination of byte, half-word, or word writes. The DRE will shift the data +* into the correct byte lane. +* +* @param RegBaseAddress is the base address of the FIFO registers. +* +* @param DataBaseAddress is the base address of the FIFO keyhole. +* +* @param BufferPtr points to the memory buffer that data is to be read from +* and written into the FIFO. Since this buffer is a byte buffer, the +* data is assumed to be endian independent. There are no alignment +* restrictions. +* +* @param ByteCount contains the number of bytes to read from the buffer and to +* write to the FIFO. +* +* @return +* +* XST_SUCCESS is returned if the operation succeeded. If there is not enough +* room in the FIFO to hold the specified bytes, XST_PFIFO_NO_ROOM is +* returned. +* +* @note +* +* This function assumes that if the device inserting data into the FIFO is +* a byte device, the order of the bytes in each 32/64 bit word is from the most +* significant byte to the least significant byte. +* +******************************************************************************/ +int XPacketFifoV200a_L0WriteDre(u32 RegBaseAddress, + u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount) +{ + u32 FifoRoomLeft; + u32 BytesLeft; + u32 Width; + + /* calculate how many slots are left in the FIFO + */ + FifoRoomLeft = + XIo_In32(RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) + & XPF_V200A_COUNT_MASK; + + /* determine the width of the FIFO + */ + Width = XIo_In32(RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & + XPF_V200A_FIFO_WIDTH_MASK; + + /* from the width, determine how many bytes can be written to the FIFO + */ + if ((Width == XPF_V200A_FIFO_WIDTH_LEGACY_TYPE) || + (Width == XPF_V200A_FIFO_WIDTH_32BITS_TYPE)) { + FifoRoomLeft *= 4; + } + else if (Width == XPF_V200A_FIFO_WIDTH_64BITS_TYPE) { + FifoRoomLeft *= 8; + } + + /* Make sure there's enough room in the FIFO */ + if (FifoRoomLeft < ByteCount) { + return XST_PFIFO_NO_ROOM; + } + + /* Determine the number of bytes to write until 32 bit alignment is + * reached, then write those bytes to the FIFO one byte at a time + */ + BytesLeft = (unsigned) BufferPtr % sizeof(u32); + ByteCount -= BytesLeft; + while (BytesLeft--) { + XIo_Out8(DataBaseAddress, *BufferPtr++); + } + + /* Write as many 32 bit words as we can */ + BytesLeft = ByteCount; + while (BytesLeft >= sizeof(u32)) { + XIo_Out32(DataBaseAddress, *(u32 *) BufferPtr); + BufferPtr += sizeof(u32); + BytesLeft -= sizeof(u32); + } + + /* Write remaining bytes */ + while (BytesLeft--) { + XIo_Out8(DataBaseAddress, *BufferPtr++); + } + + return XST_SUCCESS; + +} + +/*****************************************************************************/ +/** +* +* Read data from a FIFO and puts it into a specified buffer. The packet FIFO +* is 32 bits wide such that an input buffer which is a series of bytes is +* filled from the FIFO a word at a time. If the requested byte count is not +* a multiple of 32 bit words, it is necessary for this function to format the +* remaining 32 bit word from the FIFO into a series of bytes in the buffer. +* There may be up to 3 extra bytes which must be extracted from the last word +* of the FIFO and put into the buffer. +* +* @param RegBaseAddress is the base address of the FIFO registers. +* +* @param DataBaseAddress is the base address of the FIFO keyhole. +* +* @param BufferPtr points to the memory buffer to write the data into. This +* buffer must be 32 bit aligned or an alignment exception could be +* generated. Since this buffer is a byte buffer, the data is assumed to +* be endian independent. +* +* @param ByteCount contains the number of bytes to read from the FIFO. This +* number of bytes must be present in the FIFO or an error will be +* returned. +* +* @return +* +* XST_SUCCESS indicates the operation was successful. If the number of +* bytes specified by the byte count is not present in the FIFO +* XST_PFIFO_LACK_OF_DATA is returned. +* <br><br> +* If the function was successful, the specified buffer is modified to contain +* the bytes which were removed from the FIFO. +* +* @note +* +* Note that the exact number of bytes which are present in the FIFO is +* not known by this function. It can only check for a number of 32 bit +* words such that if the byte count specified is incorrect, but is still +* possible based on the number of words in the FIFO, up to 3 garbage bytes +* may be present at the end of the buffer. +* <br><br> +* This function assumes that if the device consuming data from the FIFO is +* a byte device, the order of the bytes to be consumed is from the most +* significant byte to the least significant byte of a 32 bit word removed +* from the FIFO. +* +******************************************************************************/ +static int Read32(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount) +{ + u32 FifoCount; + u32 WordCount; + u32 ExtraByteCount; + u32 *WordBuffer = (u32 *) BufferPtr; + + /* get the count of how many 32 bit words are in the FIFO, if there + * aren't enough words to satisfy the request, return an error + */ + + FifoCount = + XIo_In32(RegBaseAddress + + XPF_V200A_COUNT_STATUS_REG_OFFSET) & + XPF_V200A_COUNT_MASK; + + if ((FifoCount * XPF_V200A_32BIT_FIFO_WIDTH_BYTE_COUNT) < ByteCount) { + return XST_PFIFO_LACK_OF_DATA; + } + + /* calculate the number of words to read from the FIFO before the word + * containing the extra bytes, and calculate the number of extra bytes + * the extra bytes are defined as those at the end of the buffer when + * the buffer does not end on a 32 bit boundary + */ + WordCount = ByteCount / XPF_V200A_32BIT_FIFO_WIDTH_BYTE_COUNT; + ExtraByteCount = ByteCount % XPF_V200A_32BIT_FIFO_WIDTH_BYTE_COUNT; + + /* Read the 32 bit words from the FIFO for all the buffer except the + * last word which contains the extra bytes, the following code assumes + * that the buffer is 32 bit aligned, otherwise an alignment exception + * could be generated + */ + for (FifoCount = 0; FifoCount < WordCount; FifoCount++) { + WordBuffer[FifoCount] = XIo_In32(DataBaseAddress); + } + + /* if there are extra bytes to handle, read the last word from the FIFO + * and insert the extra bytes into the buffer + */ + if (ExtraByteCount > 0) { + u32 LastWord; + u8 *WordPtr; + u8 *ExtraBytesBuffer = (u8 *) (WordBuffer + WordCount); + + /* get the last word from the FIFO for the extra bytes */ + + LastWord = XIo_In32(DataBaseAddress); + + /* one extra byte in the last word, put the byte into the next + * location of the buffer, bytes in a word of the FIFO are ordered + * from most significant byte to least + */ + WordPtr = (u8 *) &LastWord; + if (ExtraByteCount == 1) { + ExtraBytesBuffer[0] = WordPtr[0]; + } + + /* two extra bytes in the last word, put each byte into the next + * two locations of the buffer + */ + else if (ExtraByteCount == 2) { + ExtraBytesBuffer[0] = WordPtr[0]; + ExtraBytesBuffer[1] = WordPtr[1]; + } + /* three extra bytes in the last word, put each byte into the next + * three locations of the buffer + */ + else if (ExtraByteCount == 3) { + ExtraBytesBuffer[0] = WordPtr[0]; + ExtraBytesBuffer[1] = WordPtr[1]; + ExtraBytesBuffer[2] = WordPtr[2]; + } + } + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* Read data from a FIFO and puts it into a specified buffer. The packet FIFO +* is 64 bits wide such that an input buffer which is a series of bytes is +* filled from the FIFO a word at a time. If the requested byte count is not +* a multiple of 64 bit words, it is necessary for this function to format the +* remaining 64 bit word from the FIFO into a series of bytes in the buffer. +* There may be up to 7 extra bytes which must be extracted from the last word +* of the FIFO and put into the buffer. +* +* @param RegBaseAddress is the base address of the FIFO registers. +* +* @param DataBaseAddress is the base address of the FIFO keyhole. +* +* @param BufferPtr points to the memory buffer to write the data into. This +* buffer must be 32 bit aligned or an alignment exception could be +* generated. Since this buffer is a byte buffer, the data is assumed to +* be endian independent. +* +* @param ByteCount contains the number of bytes to read from the FIFO. This +* number of bytes must be present in the FIFO or an error will be +* returned. +* +* @return +* +* XST_SUCCESS indicates the operation was successful. If the number of +* bytes specified by the byte count is not present in the FIFO +* XST_PFIFO_LACK_OF_DATA is returned. +* <br><br> +* If the function was successful, the specified buffer is modified to contain +* the bytes which were removed from the FIFO. +* +* @note +* +* Note that the exact number of bytes which are present in the FIFO is +* not known by this function. It can only check for a number of 64 bit +* words such that if the byte count specified is incorrect, but is still +* possible based on the number of words in the FIFO, up to 7 garbage bytes +* may be present at the end of the buffer. +* <br><br> +* This function assumes that if the device consuming data from the FIFO is +* a byte device, the order of the bytes to be consumed is from the most +* significant byte to the least significant byte of a 64 bit word removed +* from the FIFO. +* +******************************************************************************/ +static int Read64(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount) +{ + u32 FifoCount; + u32 WordCount; + u32 ExtraByteCount; + u32 *WordBuffer = (u32 *) BufferPtr; + + /* get the count of how many 64 bit words are in the FIFO, if there + * aren't enough words to satisfy the request, return an error + */ + + FifoCount = + XIo_In32(RegBaseAddress + + XPF_V200A_COUNT_STATUS_REG_OFFSET) & + XPF_V200A_COUNT_MASK; + + if ((FifoCount * XPF_V200A_64BIT_FIFO_WIDTH_BYTE_COUNT) < ByteCount) { + return XST_PFIFO_LACK_OF_DATA; + } + + /* calculate the number of words to read from the FIFO before the word + * containing the extra bytes, and calculate the number of extra bytes + * the extra bytes are defined as those at the end of the buffer when + * the buffer does not end on a 32 bit boundary + */ + WordCount = ByteCount / XPF_V200A_64BIT_FIFO_WIDTH_BYTE_COUNT; + ExtraByteCount = ByteCount % XPF_V200A_64BIT_FIFO_WIDTH_BYTE_COUNT; + + /* Read the 64 bit words from the FIFO for all the buffer except the + * last word which contains the extra bytes, the following code assumes + * that the buffer is 32 bit aligned, otherwise an alignment exception + * could be generated. The MSWord must be read first followed by the + * LSWord + */ + for (FifoCount = 0; FifoCount < WordCount; FifoCount++) { + WordBuffer[(FifoCount * 2)] = XIo_In32(DataBaseAddress); + WordBuffer[(FifoCount * 2) + 1] = XIo_In32(DataBaseAddress + 4); + } + + /* if there are extra bytes to handle, read the last word from the FIFO + * and insert the extra bytes into the buffer + */ + if (ExtraByteCount > 0) { + u32 MSLastWord; + u32 LSLastWord; + u8 *WordPtr; + u8 *ExtraBytesBuffer = (u8 *) (WordBuffer + (WordCount * 2)); + u8 Index = 0; + + /* get the last word from the FIFO for the extra bytes */ + + MSLastWord = XIo_In32(DataBaseAddress); + LSLastWord = XIo_In32(DataBaseAddress + 4); + + /* four or more extra bytes in the last word, put the byte into + * the next location of the buffer, bytes in a word of the FIFO + * are ordered from most significant byte to least + */ + WordPtr = (u8 *) &MSLastWord; + if (ExtraByteCount >= 4) { + ExtraBytesBuffer[Index] = WordPtr[0]; + ExtraBytesBuffer[Index + 1] = WordPtr[1]; + ExtraBytesBuffer[Index + 2] = WordPtr[2]; + ExtraBytesBuffer[Index + 3] = WordPtr[3]; + ExtraByteCount = ExtraByteCount - 4; + MSLastWord = LSLastWord; + Index = 4; + } + + /* one extra byte in the last word, put the byte into the next + * location of the buffer, bytes in a word of the FIFO are + * ordered from most significant byte to least + */ + if (ExtraByteCount == 1) { + ExtraBytesBuffer[Index] = WordPtr[0]; + } + + /* two extra bytes in the last word, put each byte into the next + * two locations of the buffer + */ + else if (ExtraByteCount == 2) { + ExtraBytesBuffer[Index] = WordPtr[0]; + ExtraBytesBuffer[Index + 1] = WordPtr[1]; + } + /* three extra bytes in the last word, put each byte into the next + * three locations of the buffer + */ + else if (ExtraByteCount == 3) { + ExtraBytesBuffer[Index] = WordPtr[0]; + ExtraBytesBuffer[Index + 1] = WordPtr[1]; + ExtraBytesBuffer[Index + 2] = WordPtr[2]; + } + } + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* Write data into a 32 bit packet FIFO. The packet FIFO is 32 bits wide in this +* function call such that an input buffer which is a series of bytes must be +* written into the FIFO a word at a time. If the buffer is not a multiple of +* 32 bit words, it is necessary for this function to format the remaining bytes +* into a single 32 bit word to be inserted into the FIFO. This is necessary to +* avoid any accesses past the end of the buffer. +* +* @param RegBaseAddress is the base address of the FIFO registers. +* +* @param DataBaseAddress is the base address of the FIFO keyhole. +* +* @param BufferPtr points to the memory buffer that data is to be read from +* and written into the FIFO. Since this buffer is a byte buffer, the +* data is assumed to be endian independent. This buffer must be 32 bit +* aligned or an alignment exception could be generated. +* @param ByteCount contains the number of bytes to read from the buffer and to +* write to the FIFO. +* +* @return +* +* XST_SUCCESS is returned if the operation succeeded. If there is not enough +* room in the FIFO to hold the specified bytes, XST_PFIFO_NO_ROOM is +* returned. +* +* @note +* +* This function assumes that if the device inserting data into the FIFO is +* a byte device, the order of the bytes in each 32 bit word is from the most +* significant byte to the least significant byte. +* +******************************************************************************/ +static int Write32(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount) +{ + u32 FifoCount; + u32 WordCount; + u32 ExtraByteCount; + u32 *WordBuffer = (u32 *) BufferPtr; + + /* get the count of how many words may be inserted into the FIFO */ + + FifoCount = + XIo_In32(RegBaseAddress + + XPF_V200A_COUNT_STATUS_REG_OFFSET) & + XPF_V200A_COUNT_MASK; + + /* Calculate the number of 32 bit words required to insert the + * specified number of bytes in the FIFO and determine the number + * of extra bytes if the buffer length is not a multiple of 32 bit + * words + */ + + WordCount = ByteCount / XPF_V200A_32BIT_FIFO_WIDTH_BYTE_COUNT; + ExtraByteCount = ByteCount % XPF_V200A_32BIT_FIFO_WIDTH_BYTE_COUNT; + + /* take into account the extra bytes in the total word count */ + + if (ExtraByteCount > 0) { + WordCount++; + } + + /* if there's not enough room in the FIFO to hold the specified + * number of bytes, then indicate an error, + */ + if (FifoCount < WordCount) { + return XST_PFIFO_NO_ROOM; + } + + /* readjust the word count to not take into account the extra bytes */ + + if (ExtraByteCount > 0) { + WordCount--; + } + + /* Write all the bytes of the buffer which can be written as 32 bit + * words into the FIFO, waiting to handle the extra bytes separately + */ + for (FifoCount = 0; FifoCount < WordCount; FifoCount++) { + XIo_Out32(DataBaseAddress, WordBuffer[FifoCount]); + } + + /* if there are extra bytes to handle, extract them from the buffer + * and create a 32 bit word and write it to the FIFO + */ + if (ExtraByteCount > 0) { + u32 LastWord = 0; + u8 *WordPtr; + u8 *ExtraBytesBuffer = (u8 *) (WordBuffer + WordCount); + + /* one extra byte in the buffer, put the byte into the last word + * to be inserted into the FIFO, perform this processing inline + * rather than in a loop to help performance + */ + WordPtr = (u8 *) &LastWord; + if (ExtraByteCount == 1) { + WordPtr[0] = ExtraBytesBuffer[0]; + } + + /* two extra bytes in the buffer, put each byte into the last word + * to be inserted into the FIFO + */ + else if (ExtraByteCount == 2) { + WordPtr[0] = ExtraBytesBuffer[0]; + WordPtr[1] = ExtraBytesBuffer[1]; + } + + /* three extra bytes in the buffer, put each byte into the last + * word to be inserted into the FIFO + */ + else if (ExtraByteCount == 3) { + WordPtr[0] = ExtraBytesBuffer[0]; + WordPtr[1] = ExtraBytesBuffer[1]; + WordPtr[2] = ExtraBytesBuffer[2]; + } + + /* write the last 32 bit word to the FIFO and return with + * no errors + */ + + XIo_Out32(DataBaseAddress, LastWord); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Write data into a 64 bit packet FIFO. The packet FIFO is 64 bits wide in this +* function call such that an input buffer which is a series of bytes must be +* written into the FIFO a word at a time. If the buffer is not a multiple of +* 64 bit words, it is necessary for this function to format the remaining bytes +* into two 32 bit words to be inserted into the FIFO. This is necessary to +* avoid any accesses past the end of the buffer. +* +* @param RegBaseAddress is the base address of the FIFO registers. +* +* @param DataBaseAddress is the base address of the FIFO keyhole. +* +* @param BufferPtr points to the memory buffer that data is to be read from +* and written into the FIFO. Since this buffer is a byte buffer, the +* data is assumed to be endian independent. This buffer must be 32 bit +* aligned or an alignment exception could be generated. +* +* @param ByteCount contains the number of bytes to read from the buffer and to +* write to the FIFO. +* +* @return +* +* XST_SUCCESS is returned if the operation succeeded. If there is not enough +* room in the FIFO to hold the specified bytes, XST_PFIFO_NO_ROOM is +* returned. +* +* @note +* +* This function assumes that if the device inserting data into the FIFO is +* a byte device, the order of the bytes in each 64 bit word is from the most +* significant byte to the least significant byte. +* +******************************************************************************/ +static int Write64(u32 RegBaseAddress, u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount) +{ + u32 FifoCount; + u32 WordCount; + u32 ExtraByteCount; + u32 *WordBuffer = (u32 *) BufferPtr; + + /* get the count of how many words may be inserted into the FIFO */ + + FifoCount = + XIo_In32(RegBaseAddress + + XPF_V200A_COUNT_STATUS_REG_OFFSET) & + XPF_V200A_COUNT_MASK; + + /* Calculate the number of 64 bit words required to insert the + * specified number of bytes in the FIFO and determine the number + * of extra bytes if the buffer length is not a multiple of 64 bit + * words + */ + + WordCount = ByteCount / XPF_V200A_64BIT_FIFO_WIDTH_BYTE_COUNT; + ExtraByteCount = ByteCount % XPF_V200A_64BIT_FIFO_WIDTH_BYTE_COUNT; + + /* take into account the extra bytes in the total word count */ + + if (ExtraByteCount > 0) { + WordCount++; + } + + /* if there's not enough room in the FIFO to hold the specified + * number of bytes, then indicate an error, + */ + if (FifoCount < WordCount) { + return XST_PFIFO_NO_ROOM; + } + + /* readjust the word count to not take into account the extra bytes */ + + if (ExtraByteCount > 0) { + WordCount--; + } + + /* Write all the bytes of the buffer which can be written as 32 bit + * words into the FIFO, waiting to handle the extra bytes separately + * The MSWord must be written first followed by the LSWord + */ + for (FifoCount = 0; FifoCount < WordCount; FifoCount++) { + XIo_Out32(DataBaseAddress, WordBuffer[(FifoCount * 2)]); + XIo_Out32(DataBaseAddress + 4, WordBuffer[(FifoCount * 2) + 1]); + } + + /* if there are extra bytes to handle, extract them from the buffer + * and create two 32 bit words and write to the FIFO + */ + if (ExtraByteCount > 0) { + + u32 MSLastWord = 0; + u32 LSLastWord = 0; + u8 Index = 0; + u8 *WordPtr; + u8 *ExtraBytesBuffer = (u8 *) (WordBuffer + (WordCount * 2)); + + /* four extra bytes in the buffer, put the bytes into the last word + * to be inserted into the FIFO, perform this processing inline + * rather than in a loop to help performance + */ + WordPtr = (u8 *) &MSLastWord; + + if (ExtraByteCount >= 4) { + WordPtr[0] = ExtraBytesBuffer[Index]; + WordPtr[1] = ExtraBytesBuffer[Index + 1]; + WordPtr[2] = ExtraBytesBuffer[Index + 2]; + WordPtr[3] = ExtraBytesBuffer[Index + 3]; + ExtraByteCount = ExtraByteCount - 4; + WordPtr = (u8 *) &LSLastWord; + Index = 4; + } + + /* one extra byte in the buffer, put the byte into the last word + * to be inserted into the FIFO, perform this processing inline + * rather than in a loop to help performance + */ + if (ExtraByteCount == 1) { + WordPtr[0] = ExtraBytesBuffer[Index]; + } + + /* two extra bytes in the buffer, put each byte into the last word + * to be inserted into the FIFO + */ + else if (ExtraByteCount == 2) { + WordPtr[0] = ExtraBytesBuffer[Index]; + WordPtr[1] = ExtraBytesBuffer[Index + 1]; + } + + /* three extra bytes in the buffer, put each byte into the last + * word to be inserted into the FIFO + */ + else if (ExtraByteCount == 3) { + WordPtr[0] = ExtraBytesBuffer[Index]; + WordPtr[1] = ExtraBytesBuffer[Index + 1]; + WordPtr[2] = ExtraBytesBuffer[Index + 2]; + } + + /* write the last 64 bit word to the FIFO and return with no errors + * The MSWord must be written first followed by the LSWord + */ + XIo_Out32(DataBaseAddress, MSLastWord); + XIo_Out32(DataBaseAddress + 4, LSLastWord); + } + + return XST_SUCCESS; +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xpacket_fifo_l_v2_00_a.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xpacket_fifo_l_v2_00_a.h 2014-07-20 22:06:39.191258956 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xpacket_fifo_l_v2_00_a.h,v 1.1 2006/12/13 14:23:01 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2003-2004 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xpacket_fifo_l_v2_00_a.h +* +* This header file contains identifiers and low-level (Level 0) driver +* functions (or macros) that can be used to access the FIFO. High-level driver +* (Level 1) functions are defined in xpacket_fifo_v2_00_a.h. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------ +* 2.00a rpm 10/22/03 First release. Moved most of Level 1 driver functions +* into this layer. +* 2.00a rmm 02/24/04 Added L0WriteDre function. +* 2.00a xd 10/27/04 Changed comments to support doxygen for API +* documentation. +* </pre> +* +*****************************************************************************/ +#ifndef XPACKET_FIFO_L_V200A_H /* prevent circular inclusions */ +#define XPACKET_FIFO_L_V200A_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xstatus.h" + +/************************** Constant Definitions *****************************/ + +/** @name FIFO types + * + * These constants specify the FIFO type and are mutually exclusive + * @{ + */ +#define XPF_V200A_READ_FIFO_TYPE 0 /**< a read FIFO */ +#define XPF_V200A_WRITE_FIFO_TYPE 1 /**< a write FIFO */ +/* @} */ + +/** @name Register offsets + * + * These constants define the offsets to each of the registers from the + * register base address, each of the constants are a number of bytes + * @{ + */ +#define XPF_V200A_RESET_REG_OFFSET 0UL /**< Reset register */ +#define XPF_V200A_MODULE_INFO_REG_OFFSET 0UL /**< MIR register */ +#define XPF_V200A_COUNT_STATUS_REG_OFFSET 4UL /**< Count/Status register */ +/* @} */ + +/** + * This constant is used with the Reset Register + */ +#define XPF_V200A_RESET_FIFO_MASK 0x0000000A + +/** @name Occupancy/Vacancy Count Register constants + * @{ + */ +/** Constant used with the Occupancy/Vacancy Count Register. This + * register also contains FIFO status + */ +#define XPF_V200A_COUNT_MASK 0x00FFFFFF +#define XPF_V200A_DEADLOCK_MASK 0x20000000 +#define XPF_V200A_ALMOST_EMPTY_FULL_MASK 0x40000000 +#define XPF_V200A_EMPTY_FULL_MASK 0x80000000 +#define XPF_V200A_VACANCY_SCALED_MASK 0x10000000 +/* @} */ + +/** + * This constant is used to mask the Width field + */ +#define XPF_V200A_FIFO_WIDTH_MASK 0x0E000000 + +/** @name Width field + * @{ + */ +/** Constant used with the Width field */ +#define XPF_V200A_FIFO_WIDTH_LEGACY_TYPE 0x00000000 +#define XPF_V200A_FIFO_WIDTH_8BITS_TYPE 0x02000000 +#define XPF_V200A_FIFO_WIDTH_16BITS_TYPE 0x04000000 +#define XPF_V200A_FIFO_WIDTH_32BITS_TYPE 0x06000000 +#define XPF_V200A_FIFO_WIDTH_64BITS_TYPE 0x08000000 +#define XPF_V200A_FIFO_WIDTH_128BITS_TYPE 0x0A000000 +#define XPF_V200A_FIFO_WIDTH_256BITS_TYPE 0x0C000000 +#define XPF_V200A_FIFO_WIDTH_512BITS_TYPE 0x0E000000 +/* @} */ + +/** @name FIFO word width + * @{ + */ +/** Width of a FIFO word */ +#define XPF_V200A_32BIT_FIFO_WIDTH_BYTE_COUNT 4 +#define XPF_V200A_64BIT_FIFO_WIDTH_BYTE_COUNT 8 +/* @} */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int XPacketFifoV200a_L0Read(u32 RegBaseAddress, + u32 DataBaseAddress, + u8 *ReadBufferPtr, u32 ByteCount); + +int XPacketFifoV200a_L0Write(u32 RegBaseAddress, + u32 DataBaseAddress, + u8 *WriteBufferPtr, u32 ByteCount); + +int XPacketFifoV200a_L0WriteDre(u32 RegBaseAddress, + u32 DataBaseAddress, + u8 *BufferPtr, u32 ByteCount); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xpacket_fifo_v2_00_a.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xpacket_fifo_v2_00_a.c 2014-07-20 22:06:39.200258808 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xpacket_fifo_v2_00_a.c,v 1.1 2006/12/13 14:23:11 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002-2003 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xpacket_fifo_v2_00_a.c +* +* Contains functions for the XPacketFifoV200a component. See +* xpacket_fifo_v2_00_a.h for more information about the component. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 2.00a ecm 12/30/02 First release +* 2.00a rmm 05/14/03 Fixed diab compiler warnings +* 2.00a rpm 10/22/03 Created and made use of Level 0 driver +* 2.00a rmm 02/24/04 Added WriteDRE function. +* 2.00a xd 10/27/04 Changed comments to support doxygen for API +* documentation. +* </pre> +* +*****************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xio.h" +#include "xstatus.h" +#include "xpacket_fifo_v2_00_a.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************* Variable Definitions ******************************/ + + +/************************** Function Prototypes ******************************/ + + +/*****************************************************************************/ +/** +* +* This function initializes a packet FIFO. Initialization resets the +* FIFO such that it's empty and ready to use. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @param RegBaseAddress contains the base address of the registers for +* the packet FIFO. +* +* @param DataBaseAddress contains the base address of the data for +* the packet FIFO. +* +* @return Always returns XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +int XPacketFifoV200a_Initialize(XPacketFifoV200a * InstancePtr, + u32 RegBaseAddress, u32 DataBaseAddress) +{ + /* assert to verify input argument are valid */ + + XASSERT_NONVOID(InstancePtr != NULL); + + /* initialize the component variables to the specified state */ + + InstancePtr->RegBaseAddress = RegBaseAddress; + InstancePtr->DataBaseAddress = DataBaseAddress; + InstancePtr->IsReady = XCOMPONENT_IS_READY; + + /* reset the FIFO such that it's empty and ready to use and indicate the + * initialization was successful, note that the is ready variable must be + * set prior to calling the reset function to prevent an assert + */ + XPF_V200A_RESET(InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function performs a self-test on the specified packet FIFO. The self +* test resets the FIFO and reads a register to determine if it is the correct +* reset value. This test is destructive in that any data in the FIFO will +* be lost. +* +* @param InstancePtr is a pointer to the packet FIFO to be operated on. +* +* @param FifoType specifies the type of FIFO, read or write, for the self test. +* The FIFO type is specified by the values XPF_V200A_READ_FIFO_TYPE or +* XPF_V200A_WRITE_FIFO_TYPE. +* +* @return +* +* XST_SUCCESS is returned if the selftest is successful, or +* XST_PFIFO_BAD_REG_VALUE indicating that the value read back from the +* occupancy/vacancy count register after a reset does not match the +* specified reset value. +* +* @note +* +* None. +* +******************************************************************************/ +int XPacketFifoV200a_SelfTest(XPacketFifoV200a * InstancePtr, u32 FifoType) +{ + u32 Register; + + /* assert to verify valid input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID((FifoType == XPF_V200A_READ_FIFO_TYPE) || + (FifoType == XPF_V200A_WRITE_FIFO_TYPE)); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* reset the FIFO and then check to make sure the occupancy/vacancy + * register contents are correct for a reset condition + */ + XPF_V200A_RESET(InstancePtr); + + Register = XIo_In32(InstancePtr->RegBaseAddress + + XPF_V200A_COUNT_STATUS_REG_OFFSET); + + /* check the value of the register to ensure that it's correct for the + * specified FIFO type since both FIFO types reset to empty, but a bit + * in the register changes definition based upon FIFO type + */ + + if (FifoType == XPF_V200A_READ_FIFO_TYPE) { + /* check the register value for a read FIFO which should be empty */ + + if ((Register & ~(XPF_V200A_FIFO_WIDTH_MASK)) != + XPF_V200A_EMPTY_FULL_MASK) { + return XST_PFIFO_BAD_REG_VALUE; + } + } + else { + /* check the register value for a write FIFO which should not be full + * on reset + */ + if (((Register & ~(XPF_V200A_FIFO_WIDTH_MASK) & + XPF_V200A_EMPTY_FULL_MASK)) != 0) { + return XST_PFIFO_BAD_REG_VALUE; + } + } + + /* check the register value for the proper FIFO width */ + + Register &= ~XPF_V200A_EMPTY_FULL_MASK; + + if (((Register & XPF_V200A_FIFO_WIDTH_MASK) != + XPF_V200A_FIFO_WIDTH_LEGACY_TYPE) && + ((Register & XPF_V200A_FIFO_WIDTH_MASK) != + XPF_V200A_FIFO_WIDTH_32BITS_TYPE) && + ((Register & XPF_V200A_FIFO_WIDTH_MASK) != + XPF_V200A_FIFO_WIDTH_64BITS_TYPE)) { + return XST_PFIFO_BAD_REG_VALUE; + } + + /* the test was successful */ + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* Read data from a FIFO and puts it into a specified buffer. This function +* invokes the Level 0 driver function to read the FIFO. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @param BufferPtr points to the memory buffer to write the data into. This +* buffer must be 32 bit aligned or an alignment exception could be +* generated. Since this buffer is a byte buffer, the data is assumed to +* be endian independent. +* +* @param ByteCount contains the number of bytes to read from the FIFO. This +* number of bytes must be present in the FIFO or an error will be +* returned. +* +* @return +* - XST_SUCCESS if the operation was successful +* <br><br> +* - XST_PFIFO_LACK_OF_DATA if the number of bytes specified by the byte count +* is not present in the FIFO. +* +* @note +* +* None. +* +******************************************************************************/ +int XPacketFifoV200a_Read(XPacketFifoV200a * InstancePtr, + u8 *BufferPtr, u32 ByteCount) +{ + /* assert to verify valid input arguments including 32 bit alignment of + * the buffer pointer + */ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(BufferPtr != NULL); + XASSERT_NONVOID(((u32) BufferPtr & + (XPF_V200A_32BIT_FIFO_WIDTH_BYTE_COUNT - 1)) == 0); + XASSERT_NONVOID(ByteCount != 0); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + return XPacketFifoV200a_L0Read(InstancePtr->RegBaseAddress, + InstancePtr->DataBaseAddress, + BufferPtr, ByteCount); +} + +/*****************************************************************************/ +/** +* +* Write data into a packet FIFO. This function invokes the Level 0 driver +* function to read the FIFO. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @param BufferPtr points to the memory buffer that data is to be read from +* and written into the FIFO. Since this buffer is a byte buffer, the +* data is assumed to be endian independent. This buffer must be 32 bit +* aligned or an alignment exception could be generated. +* +* @param ByteCount contains the number of bytes to read from the buffer and to +* write to the FIFO. +* +* @return +* - XST_SUCCESS is returned if the operation succeeded. +* <br><br> +* - XST_PFIFO_NO_ROOM is returned if there is not enough room in the FIFO to +* hold the specified bytes. +* +* @note +* +* None. +* +******************************************************************************/ +int XPacketFifoV200a_Write(XPacketFifoV200a * InstancePtr, + u8 *BufferPtr, u32 ByteCount) +{ + /* assert to verify valid input arguments including 32 bit alignment of + * the buffer pointer + */ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(BufferPtr != NULL); + XASSERT_NONVOID(((u32) BufferPtr & + (XPF_V200A_32BIT_FIFO_WIDTH_BYTE_COUNT - 1)) == 0); + XASSERT_NONVOID(ByteCount != 0); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + + return XPacketFifoV200a_L0Write(InstancePtr->RegBaseAddress, + InstancePtr->DataBaseAddress, + BufferPtr, ByteCount); +} + + +/*****************************************************************************/ +/** +* +* Write data into a packet FIFO configured with the Data Realignment engine +* (DRE). There are no alignment restrictions. The FIFO can be written on any +* byte boundary. The FIFO must be at least 32 bits wide. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @param BufferPtr points to the memory buffer that data is to be read from +* and written into the FIFO. Since this buffer is a byte buffer, the +* data is assumed to be endian independent. +* +* @param ByteCount contains the number of bytes to read from the buffer and to +* write to the FIFO. +* +* @return +* +* XST_SUCCESS is returned if the operation succeeded. If there is not enough +* room in the FIFO to hold the specified bytes, XST_PFIFO_NO_ROOM is +* returned. +* +* @note +* +* This function assumes that if the device inserting data into the FIFO is +* a byte device, the order of the bytes in each 32/64 bit word is from the most +* significant byte to the least significant byte. +* +******************************************************************************/ +int XPacketFifoV200a_WriteDre(XPacketFifoV200a * InstancePtr, + u8 *BufferPtr, u32 ByteCount) +{ + /* assert to verify valid input arguments */ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(BufferPtr != NULL); + XASSERT_NONVOID(ByteCount != 0); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + return XPacketFifoV200a_L0WriteDre(InstancePtr->RegBaseAddress, + InstancePtr->DataBaseAddress, + BufferPtr, ByteCount); +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xpacket_fifo_v2_00_a.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xpacket_fifo_v2_00_a.h 2014-07-20 22:06:39.208258675 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xpacket_fifo_v2_00_a.h,v 1.1 2006/12/13 14:23:19 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002-2004 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xpacket_fifo_v2_00_a.h +* +* This component is a common component because it's primary purpose is to +* prevent code duplication in drivers. A driver which must handle a packet +* FIFO uses this component rather than directly manipulating a packet FIFO. +* +* A FIFO is a device which has dual port memory such that one user may be +* inserting data into the FIFO while another is consuming data from the FIFO. +* A packet FIFO is designed for use with packet protocols such as Ethernet and +* ATM. It is typically only used with devices when DMA and/or Scatter Gather +* is used. It differs from a nonpacket FIFO in that it does not provide any +* interrupts for thresholds of the FIFO such that it is less useful without +* DMA. +* +* @note +* +* This component has the capability to generate an interrupt when an error +* condition occurs. It is the user's responsibility to provide the interrupt +* processing to handle the interrupt. This component provides the ability to +* determine if that interrupt is active, a deadlock condition, and the ability +* to reset the FIFO to clear the condition. In this condition, the device which +* is using the FIFO should also be reset to prevent other problems. This error +* condition could occur as a normal part of operation if the size of the FIFO +* is not setup correctly. See the hardware IP specification for more details. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 2.00a ecm 12/30/02 First release +* 2.00a rpm 10/22/03 Created and made use of Level 0 driver +* 2.00a rmm 02/24/04 Added WriteDre function. +* 2.00a xd 10/27/04 Changed comments to support doxygen for API +* documentation. +* </pre> +* +*****************************************************************************/ +#ifndef XPACKET_FIFO_V200A_H /* prevent circular inclusions */ +#define XPACKET_FIFO_V200A_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xstatus.h" +#include "xpacket_fifo_l_v2_00_a.h" + +/************************** Constant Definitions *****************************/ + +/* See the low-level header file for constant definitions */ + +/**************************** Type Definitions *******************************/ + +/** + * The XPacketFifo driver instance data. The driver is required to allocate a + * variable of this type for every packet FIFO in the device. + */ +typedef struct { + u32 RegBaseAddress; /**< Base address of registers */ + u32 IsReady; /**< Device is initialized and ready */ + u32 DataBaseAddress;/**< Base address of data for FIFOs */ +} XPacketFifoV200a; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* +* Reset the specified packet FIFO. Resetting a FIFO will cause any data +* contained in the FIFO to be lost. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @return None. +* +* @note C Signature: void XPF_V200A_RESET(XPacketFifoV200a *InstancePtr) +* +******************************************************************************/ +#define XPF_V200A_RESET(InstancePtr) \ + XIo_Out32((InstancePtr)->RegBaseAddress + XPF_V200A_RESET_REG_OFFSET, XPF_V200A_RESET_FIFO_MASK); + + +/*****************************************************************************/ +/** +* +* Get the occupancy count for a read packet FIFO and the vacancy count for a +* write packet FIFO. These counts indicate the number of 32-bit words +* contained (occupancy) in the FIFO or the number of 32-bit words available +* to write (vacancy) in the FIFO. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @return The occupancy or vacancy count for the specified packet FIFO. +* +* @note +* +* C Signature: u32 XPF_V200A_GET_COUNT(XPacketFifoV200a *InstancePtr) +* +******************************************************************************/ +#define XPF_V200A_GET_COUNT(InstancePtr) \ + (XIo_In32((InstancePtr)->RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & \ + XPF_V200A_COUNT_MASK) + + +/*****************************************************************************/ +/** +* +* Determine if the specified packet FIFO is almost empty. Almost empty is +* defined for a read FIFO when there is only one data word in the FIFO. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @return +* +* TRUE if the packet FIFO is almost empty, FALSE otherwise. +* +* @note +* +* C Signature: u32 XPF_V200A_IS_ALMOST_EMPTY(XPacketFifoV200a *InstancePtr) +* +******************************************************************************/ +#define XPF_V200A_IS_ALMOST_EMPTY(InstancePtr) \ + (XIo_In32((InstancePtr)->RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & \ + XPF_V200A_ALMOST_EMPTY_FULL_MASK) + + +/*****************************************************************************/ +/** +* +* Determine if the specified packet FIFO is almost full. Almost full is +* defined for a write FIFO when there is only one available data word in the +* FIFO. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @return +* +* TRUE if the packet FIFO is almost full, FALSE otherwise. +* +* @note +* +* C Signature: u32 XPF_V200A_IS_ALMOST_FULL(XPacketFifoV200a *InstancePtr) +* +******************************************************************************/ +#define XPF_V200A_IS_ALMOST_FULL(InstancePtr) \ + (XIo_In32((InstancePtr)->RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & \ + XPF_V200A_ALMOST_EMPTY_FULL_MASK) + + +/*****************************************************************************/ +/** +* +* Determine if the specified packet FIFO is empty. This applies only to a +* read FIFO. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @return +* +* TRUE if the packet FIFO is empty, FALSE otherwise. +* +* @note +* +* C Signature: u32 XPF_V200A_IS_EMPTY(XPacketFifoV200a *InstancePtr) +* +******************************************************************************/ +#define XPF_V200A_IS_EMPTY(InstancePtr) \ + (XIo_In32((InstancePtr)->RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & \ + XPF_V200A_EMPTY_FULL_MASK) + + +/*****************************************************************************/ +/** +* +* Determine if the specified packet FIFO is full. This applies only to a +* write FIFO. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @return +* +* TRUE if the packet FIFO is full, FALSE otherwise. +* +* @note +* +* C Signature: u32 XPF_V200A_IS_FULL(XPacketFifoV200a *InstancePtr) +* +******************************************************************************/ +#define XPF_V200A_IS_FULL(InstancePtr) \ + (XIo_In32((InstancePtr)->RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & \ + XPF_V200A_EMPTY_FULL_MASK) + + +/*****************************************************************************/ +/** +* +* Determine if the specified packet FIFO is deadlocked. This condition occurs +* when the FIFO is full and empty at the same time and is caused by a packet +* being written to the FIFO which exceeds the total data capacity of the FIFO. +* It occurs because of the mark/restore features of the packet FIFO which allow +* retransmission of a packet. The software should reset the FIFO and any devices +* using the FIFO when this condition occurs. +* +* @param InstancePtr contains a pointer to the FIFO to operate on. +* +* @return +* +* TRUE if the packet FIFO is deadlocked, FALSE otherwise. +* +* @note +* +* This component has the capability to generate an interrupt when an error +* condition occurs. It is the user's responsibility to provide the interrupt +* processing to handle the interrupt. This function provides the ability to +* determine if a deadlock condition, and the ability to reset the FIFO to +* clear the condition. +* <br><br> +* In this condition, the device which is using the FIFO should also be reset +* to prevent other problems. This error condition could occur as a normal part +* of operation if the size of the FIFO is not setup correctly. +* <br><br> +* C Signature: u32 XPF_V200A_IS_DEADLOCKED(XPacketFifoV200a *InstancePtr) +* +******************************************************************************/ +#define XPF_V200A_IS_DEADLOCKED(InstancePtr) \ + (XIo_In32((InstancePtr)->RegBaseAddress + XPF_V200A_COUNT_STATUS_REG_OFFSET) & \ + XPF_V200A_DEADLOCK_MASK) + + +/************************** Function Prototypes ******************************/ + +/** + * Standard functions + */ +int XPacketFifoV200a_Initialize(XPacketFifoV200a * InstancePtr, + u32 RegBaseAddress, u32 DataBaseAddress); +int XPacketFifoV200a_SelfTest(XPacketFifoV200a * InstancePtr, u32 FifoType); + +/** + * Data functions + */ +int XPacketFifoV200a_Read(XPacketFifoV200a * InstancePtr, + u8 *ReadBufferPtr, u32 ByteCount); +int XPacketFifoV200a_Write(XPacketFifoV200a * InstancePtr, + u8 *WriteBufferPtr, u32 ByteCount); +int XPacketFifoV200a_WriteDre(XPacketFifoV200a * InstancePtr, + u8 *WriteBufferPtr, u32 ByteCount); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xstatus.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xstatus.h 2014-07-20 22:06:39.220258478 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xstatus.h,v 1.1 2006/12/13 14:23:26 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xstatus.h +* +* This file contains Xilinx software status codes. Status codes have their +* own data type called int. These codes are used throughout the Xilinx +* device drivers. +* +******************************************************************************/ + +#ifndef XSTATUS_H /* prevent circular inclusions */ +#define XSTATUS_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +/************************** Constant Definitions *****************************/ + +/*********************** Common statuses 0 - 500 *****************************/ + +#define XST_SUCCESS 0L +#define XST_FAILURE 1L +#define XST_DEVICE_NOT_FOUND 2L +#define XST_DEVICE_BLOCK_NOT_FOUND 3L +#define XST_INVALID_VERSION 4L +#define XST_DEVICE_IS_STARTED 5L +#define XST_DEVICE_IS_STOPPED 6L +#define XST_FIFO_ERROR 7L /* an error occurred during an + operation with a FIFO such as + an underrun or overrun, this + error requires the device to + be reset */ +#define XST_RESET_ERROR 8L /* an error occurred which requires + the device to be reset */ +#define XST_DMA_ERROR 9L /* a DMA error occurred, this error + typically requires the device + using the DMA to be reset */ +#define XST_NOT_POLLED 10L /* the device is not configured for + polled mode operation */ +#define XST_FIFO_NO_ROOM 11L /* a FIFO did not have room to put + the specified data into */ +#define XST_BUFFER_TOO_SMALL 12L /* the buffer is not large enough + to hold the expected data */ +#define XST_NO_DATA 13L /* there was no data available */ +#define XST_REGISTER_ERROR 14L /* a register did not contain the + expected value */ +#define XST_INVALID_PARAM 15L /* an invalid parameter was passed + into the function */ +#define XST_NOT_SGDMA 16L /* the device is not configured for + scatter-gather DMA operation */ +#define XST_LOOPBACK_ERROR 17L /* a loopback test failed */ +#define XST_NO_CALLBACK 18L /* a callback has not yet been + registered */ +#define XST_NO_FEATURE 19L /* device is not configured with + the requested feature */ +#define XST_NOT_INTERRUPT 20L /* device is not configured for + interrupt mode operation */ +#define XST_DEVICE_BUSY 21L /* device is busy */ +#define XST_ERROR_COUNT_MAX 22L /* the error counters of a device + have maxed out */ +#define XST_IS_STARTED 23L /* used when part of device is + already started i.e. + sub channel */ +#define XST_IS_STOPPED 24L /* used when part of device is + already stopped i.e. + sub channel */ +#define XST_DATA_LOST 26L /* driver defined error */ +#define XST_RECV_ERROR 27L /* generic receive error */ +#define XST_SEND_ERROR 28L /* generic transmit error */ +#define XST_NOT_ENABLED 29L /* a requested service is not + available because it has not + been enabled */ + +/***************** Utility Component statuses 401 - 500 *********************/ + +#define XST_MEMTEST_FAILED 401L /* memory test failed */ + + +/***************** Common Components statuses 501 - 1000 *********************/ + +/********************* Packet Fifo statuses 501 - 510 ************************/ + +#define XST_PFIFO_LACK_OF_DATA 501L /* not enough data in FIFO */ +#define XST_PFIFO_NO_ROOM 502L /* not enough room in FIFO */ +#define XST_PFIFO_BAD_REG_VALUE 503L /* self test, a register value + was invalid after reset */ +#define XST_PFIFO_ERROR 504L /* generic packet FIFO error */ +#define XST_PFIFO_DEADLOCK 505L /* packet FIFO is reporting + * empty and full simultaneously + */ + +/************************** DMA statuses 511 - 530 ***************************/ + +#define XST_DMA_TRANSFER_ERROR 511L /* self test, DMA transfer + failed */ +#define XST_DMA_RESET_REGISTER_ERROR 512L /* self test, a register value + was invalid after reset */ +#define XST_DMA_SG_LIST_EMPTY 513L /* scatter gather list contains + no buffer descriptors ready + to be processed */ +#define XST_DMA_SG_IS_STARTED 514L /* scatter gather not stopped */ +#define XST_DMA_SG_IS_STOPPED 515L /* scatter gather not running */ +#define XST_DMA_SG_LIST_FULL 517L /* all the buffer desciptors of + the scatter gather list are + being used */ +#define XST_DMA_SG_BD_LOCKED 518L /* the scatter gather buffer + descriptor which is to be + copied over in the scatter + list is locked */ +#define XST_DMA_SG_NOTHING_TO_COMMIT 519L /* no buffer descriptors have been + put into the scatter gather + list to be commited */ +#define XST_DMA_SG_COUNT_EXCEEDED 521L /* the packet count threshold + specified was larger than the + total # of buffer descriptors + in the scatter gather list */ +#define XST_DMA_SG_LIST_EXISTS 522L /* the scatter gather list has + already been created */ +#define XST_DMA_SG_NO_LIST 523L /* no scatter gather list has + been created */ +#define XST_DMA_SG_BD_NOT_COMMITTED 524L /* the buffer descriptor which was + being started was not committed + to the list */ +#define XST_DMA_SG_NO_DATA 525L /* the buffer descriptor to start + has already been used by the + hardware so it can't be reused + */ +#define XST_DMA_SG_LIST_ERROR 526L /* general purpose list access + error */ +#define XST_DMA_BD_ERROR 527L /* general buffer descriptor + error */ + +/************************** IPIF statuses 531 - 550 ***************************/ + +#define XST_IPIF_REG_WIDTH_ERROR 531L /* an invalid register width + was passed into the function */ +#define XST_IPIF_RESET_REGISTER_ERROR 532L /* the value of a register at + reset was not valid */ +#define XST_IPIF_DEVICE_STATUS_ERROR 533L /* a write to the device interrupt + status register did not read + back correctly */ +#define XST_IPIF_DEVICE_ACK_ERROR 534L /* the device interrupt status + register did not reset when + acked */ +#define XST_IPIF_DEVICE_ENABLE_ERROR 535L /* the device interrupt enable + register was not updated when + other registers changed */ +#define XST_IPIF_IP_STATUS_ERROR 536L /* a write to the IP interrupt + status register did not read + back correctly */ +#define XST_IPIF_IP_ACK_ERROR 537L /* the IP interrupt status register + did not reset when acked */ +#define XST_IPIF_IP_ENABLE_ERROR 538L /* IP interrupt enable register was + not updated correctly when other + registers changed */ +#define XST_IPIF_DEVICE_PENDING_ERROR 539L /* The device interrupt pending + register did not indicate the + expected value */ +#define XST_IPIF_DEVICE_ID_ERROR 540L /* The device interrupt ID register + did not indicate the expected + value */ +#define XST_IPIF_ERROR 541L /* generic ipif error */ + +/****************** Device specific statuses 1001 - 4095 *********************/ + +/********************* Ethernet statuses 1001 - 1050 *************************/ + +#define XST_EMAC_MEMORY_SIZE_ERROR 1001L /* Memory space is not big enough + * to hold the minimum number of + * buffers or descriptors */ +#define XST_EMAC_MEMORY_ALLOC_ERROR 1002L /* Memory allocation failed */ +#define XST_EMAC_MII_READ_ERROR 1003L /* MII read error */ +#define XST_EMAC_MII_BUSY 1004L /* An MII operation is in progress */ +#define XST_EMAC_OUT_OF_BUFFERS 1005L /* Adapter is out of buffers */ +#define XST_EMAC_PARSE_ERROR 1006L /* Invalid adapter init string */ +#define XST_EMAC_COLLISION_ERROR 1007L /* Excess deferral or late + * collision on polled send */ + +/*********************** UART statuses 1051 - 1075 ***************************/ +#define XST_UART + +#define XST_UART_INIT_ERROR 1051L +#define XST_UART_START_ERROR 1052L +#define XST_UART_CONFIG_ERROR 1053L +#define XST_UART_TEST_FAIL 1054L +#define XST_UART_BAUD_ERROR 1055L +#define XST_UART_BAUD_RANGE 1056L + + +/************************ IIC statuses 1076 - 1100 ***************************/ + +#define XST_IIC_SELFTEST_FAILED 1076 /* self test failed */ +#define XST_IIC_BUS_BUSY 1077 /* bus found busy */ +#define XST_IIC_GENERAL_CALL_ADDRESS 1078 /* mastersend attempted with */ + /* general call address */ +#define XST_IIC_STAND_REG_RESET_ERROR 1079 /* A non parameterizable reg */ + /* value after reset not valid */ +#define XST_IIC_TX_FIFO_REG_RESET_ERROR 1080 /* Tx fifo included in design */ + /* value after reset not valid */ +#define XST_IIC_RX_FIFO_REG_RESET_ERROR 1081 /* Rx fifo included in design */ + /* value after reset not valid */ +#define XST_IIC_TBA_REG_RESET_ERROR 1082 /* 10 bit addr incl in design */ + /* value after reset not valid */ +#define XST_IIC_CR_READBACK_ERROR 1083 /* Read of the control register */ + /* didn't return value written */ +#define XST_IIC_DTR_READBACK_ERROR 1084 /* Read of the data Tx reg */ + /* didn't return value written */ +#define XST_IIC_DRR_READBACK_ERROR 1085 /* Read of the data Receive reg */ + /* didn't return value written */ +#define XST_IIC_ADR_READBACK_ERROR 1086 /* Read of the data Tx reg */ + /* didn't return value written */ +#define XST_IIC_TBA_READBACK_ERROR 1087 /* Read of the 10 bit addr reg */ + /* didn't return written value */ +#define XST_IIC_NOT_SLAVE 1088 /* The device isn't a slave */ + +/*********************** ATMC statuses 1101 - 1125 ***************************/ + +#define XST_ATMC_ERROR_COUNT_MAX 1101L /* the error counters in the ATM + controller hit the max value + which requires the statistics + to be cleared */ + +/*********************** Flash statuses 1126 - 1150 **************************/ + +#define XST_FLASH_BUSY 1126L /* Flash is erasing or programming */ +#define XST_FLASH_READY 1127L /* Flash is ready for commands */ +#define XST_FLASH_ERROR 1128L /* Flash had detected an internal + error. Use XFlash_DeviceControl + to retrieve device specific codes */ +#define XST_FLASH_ERASE_SUSPENDED 1129L /* Flash is in suspended erase state */ +#define XST_FLASH_WRITE_SUSPENDED 1130L /* Flash is in suspended write state */ +#define XST_FLASH_PART_NOT_SUPPORTED 1131L /* Flash type not supported by + driver */ +#define XST_FLASH_NOT_SUPPORTED 1132L /* Operation not supported */ +#define XST_FLASH_TOO_MANY_REGIONS 1133L /* Too many erase regions */ +#define XST_FLASH_TIMEOUT_ERROR 1134L /* Programming or erase operation + aborted due to a timeout */ +#define XST_FLASH_ADDRESS_ERROR 1135L /* Accessed flash outside its + addressible range */ +#define XST_FLASH_ALIGNMENT_ERROR 1136L /* Write alignment error */ +#define XST_FLASH_BLOCKING_CALL_ERROR 1137L /* Couldn't return immediately from + write/erase function with + XFL_NON_BLOCKING_WRITE/ERASE + option cleared */ +#define XST_FLASH_CFI_QUERY_ERROR 1138L /* Failed to query the device */ + +/*********************** SPI statuses 1151 - 1175 ****************************/ + +#define XST_SPI_MODE_FAULT 1151 /* master was selected as slave */ +#define XST_SPI_TRANSFER_DONE 1152 /* data transfer is complete */ +#define XST_SPI_TRANSMIT_UNDERRUN 1153 /* slave underruns transmit register */ +#define XST_SPI_RECEIVE_OVERRUN 1154 /* device overruns receive register */ +#define XST_SPI_NO_SLAVE 1155 /* no slave has been selected yet */ +#define XST_SPI_TOO_MANY_SLAVES 1156 /* more than one slave is being + * selected */ +#define XST_SPI_NOT_MASTER 1157 /* operation is valid only as master */ +#define XST_SPI_SLAVE_ONLY 1158 /* device is configured as slave-only */ +#define XST_SPI_SLAVE_MODE_FAULT 1159 /* slave was selected while disabled */ + +/********************** OPB Arbiter statuses 1176 - 1200 *********************/ + +#define XST_OPBARB_INVALID_PRIORITY 1176 /* the priority registers have either + * one master assigned to two or more + * priorities, or one master not + * assigned to any priority + */ +#define XST_OPBARB_NOT_SUSPENDED 1177 /* an attempt was made to modify the + * priority levels without first + * suspending the use of priority + * levels + */ +#define XST_OPBARB_PARK_NOT_ENABLED 1178 /* bus parking by id was enabled but + * bus parking was not enabled + */ +#define XST_OPBARB_NOT_FIXED_PRIORITY 1179 /* the arbiter must be in fixed + * priority mode to allow the + * priorities to be changed + */ + +/************************ Intc statuses 1201 - 1225 **************************/ + +#define XST_INTC_FAIL_SELFTEST 1201 /* self test failed */ +#define XST_INTC_CONNECT_ERROR 1202 /* interrupt already in use */ + +/********************** TmrCtr statuses 1226 - 1250 **************************/ + +#define XST_TMRCTR_TIMER_FAILED 1226 /* self test failed */ + +/********************** WdtTb statuses 1251 - 1275 ***************************/ + +#define XST_WDTTB_TIMER_FAILED 1251L + +/********************** PlbArb statuses 1276 - 1300 **************************/ + +#define XST_PLBARB_FAIL_SELFTEST 1276L + +/********************** Plb2Opb statuses 1301 - 1325 *************************/ + +#define XST_PLB2OPB_FAIL_SELFTEST 1301L + +/********************** Opb2Plb statuses 1326 - 1350 *************************/ + +#define XST_OPB2PLB_FAIL_SELFTEST 1326L + +/********************** SysAce statuses 1351 - 1360 **************************/ + +#define XST_SYSACE_NO_LOCK 1351L /* No MPU lock has been granted */ + +/********************** PCI Bridge statuses 1361 - 1375 **********************/ + +#define XST_PCI_INVALID_ADDRESS 1361L + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xstreamer.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xstreamer.c 2014-07-20 22:06:39.231258296 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/* +* @file xstreamer.c +* +* See xtreamer.h for a description on how to use this driver. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a jvb 10/13/06 First release - based on Robert McGee's streaming packet +* fifo driver. +* </pre> +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xstreamer.h" + +/* + * Implementation Notes + * + * --- Receive --- + * + * The basic algorithm for receiving bytes through this byte streamer copies a + * fifo key-hole width chunk from the fifo into a holding buffer and then doles + * out the bytes from the holding buffer. In some cases, when the buffer given + * happens to already be aligned in memory, this algorithm will bypass the + * holding buffer. + * + * Here is a picture to depict this process: + * + * Initial state: holding buffer + * +--------------+ + * | <empty> | + * +--------------+ + * ^ + * | + * index + * + * during XStrm_Read(): + * first holding buffer fill: holding buffer + * +--------------+ + * |////<full>////| + * +--------------+ + * ^ + * | + * index + * + * first holding buffer read: holding buffer + * read unread + * +--------------+ + * | |///////| + * +--------------+ + * ^ + * | + * index + * + * ... + * + * last holding buffer read: holding buffer + * +--------------+ + * | <empty> | + * +--------------+ + * ^ + * | + * index + * + * repeat this process ^^^ + * + * + * --- Transmit --- + * + * The basic algorithm for transmitting bytes through this byte streamer copies + * bytes into a holding buffer and then writes the holding buffer into the fifo + * when it is full. In some cases, when the buffer given happens to already be + * aligned in memory, this algorithm will bypass the holding buffer. + * + * Here is a picture to depict this process: + * + * Initial state: holding buffer + * +--------------+ + * | <empty> | + * +--------------+ + * ^ + * | + * index + * + * during XStrm_Write(): + * first holding buffer write: holding buffer + * writen empty + * +--------------+ + * |//////| | + * +--------------+ + * ^ + * | + * index + * + * ... + * last holding buffer write: holding buffer + * +--------------+ + * |////<full>////| + * +--------------+ + * ^ + * | + * index + * + * holding buffer flush: holding buffer + * +--------------+ + * | <empty> | + * +--------------+ + * ^ + * | + * index + * + * repeat this process ^^^ + */ + +#ifndef min +#define min(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +/*****************************************************************************/ +/* +* +* XStrm_RxInitialize initializes the XStrm_RxFifoStreamer object referenced by +* <i>InstancePtr</i>. +* +* @param InstancePtr references the tx streamer on which to operate. +* +* @param FifoWidth specifies the FIFO keyhole size in bytes. +* +* @param FifoInstance references the FIFO driver instance that this streamer +* object should use to transfer data into the the actual fifo. +* +* @param ReadFn specifies a routine to use to read data from the actual +* FIFO. It is assumed that this read routine will handle only reads +* from an aligned buffer. (Otherwise, why are we using this streamer +* driver?) +* +* @param GetLenFn specifies a routine to use to initiate a receive on the +* actual FIFO. +* +* @param GetOccupancyFn specifies a routine to use to retrieve the occupancy +* in the actual FIFO. The true occupancy value needs to come through +* this streamer driver becuase it holds some of the bytes. +* +* @return N/A +* +******************************************************************************/ +void XStrm_RxInitialize(XStrm_RxFifoStreamer * InstancePtr, + unsigned FifoWidth, void *FifoInstance, + XStrm_XferFnType ReadFn, + XStrm_GetLenFnType GetLenFn, + XStrm_GetOccupancyFnType GetOccupancyFn) +{ + /* Verify arguments */ + XASSERT_VOID(InstancePtr != NULL); + + InstancePtr->HeadIndex = FifoWidth; + InstancePtr->FifoWidth = FifoWidth; + InstancePtr->FifoInstance = FifoInstance; + InstancePtr->ReadFn = ReadFn; + InstancePtr->GetLenFn = GetLenFn; + InstancePtr->GetOccupancyFn = GetOccupancyFn; +} + +/*****************************************************************************/ +/* +* +* XStrm_TxInitialize initializes the XStrm_TxFifoStreamer object referenced by +* <i>InstancePtr</i>. +* +* @param InstancePtr references the tx streamer on which to operate. +* +* @param FifoWidth specifies the FIFO keyhole size in bytes. +* +* @param FifoInstance references the FIFO driver instance that this streamer +* object should use to transfer data into the the actual fifo. +* +* @param WriteFn specifies a routine to use to write data into the actual +* FIFO. It is assumed that this write routine will handle only writes +* from an aligned buffer. (Otherwise, why are we using this streamer +* driver?) +* +* @param SetLenFn specifies a routine to use to initiate a transmit on the +* actual FIFO. +* +* @param GetVacancyFn specifies a routine to use to retrieve the vacancy in +* the actual FIFO. The true vacancy value needs to come through this +* streamer driver becuase it holds some of the bytes. +* +* @return N/A +* +******************************************************************************/ +void XStrm_TxInitialize(XStrm_TxFifoStreamer * InstancePtr, unsigned FifoWidth, + void *FifoInstance, XStrm_XferFnType WriteFn, + XStrm_SetLenFnType SetLenFn, + XStrm_GetVacancyFnType GetVacancyFn) +{ + /* Verify arguments */ + XASSERT_VOID(InstancePtr != NULL); + + InstancePtr->TailIndex = 0; + InstancePtr->FifoWidth = FifoWidth; + InstancePtr->FifoInstance = FifoInstance; + InstancePtr->WriteFn = WriteFn; + InstancePtr->SetLenFn = SetLenFn; + InstancePtr->GetVacancyFn = GetVacancyFn; +} + +/*****************************************************************************/ +/* +* +* XStrm_RxGetLen notifies the hardware that the program is ready to receive the +* next frame from the receive channel of the FIFO, specified by +* <i>InstancePtr</i>. +* +* Note that the program must first call XStrm_RxGetLen before pulling data +* out of the receive channel of the FIFO with XStrm_Read. +* +* @param InstancePtr references the FIFO on which to operate. +* +* @return XStrm_RxGetLen returns the number of bytes available in the next +* frame. +* +******************************************************************************/ +u32 XStrm_RxGetLen(XStrm_RxFifoStreamer * InstancePtr) +{ + u32 len; + + InstancePtr->HeadIndex = InstancePtr->FifoWidth; + len = (*InstancePtr->GetLenFn) (InstancePtr->FifoInstance); + InstancePtr->FrmByteCnt = len; + return len; +} + +/*****************************************************************************/ +/* +* +* XStrm_Read reads <i>Bytes</i> bytes from the FIFO specified by +* <i>InstancePtr</i> to the block of memory, referenced by <i>BufPtr</i>. +* +* Care must be taken to ensure that the number of bytes read with one or more +* calls to XStrm_Read() does not exceed the number of bytes available given +* from the last call to XStrm_RxGetLen(). +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param BufPtr specifies the memory address to place the data read. +* +* @param Bytes specifies the number of bytes to read. +* +* @return N/A +* +******************************************************************************/ +void XStrm_Read(XStrm_RxFifoStreamer * InstancePtr, void *BufPtr, + unsigned Bytes) +{ + u8 *DestPtr = (u8 *) BufPtr; + unsigned BytesRemaining = Bytes; + unsigned FifoWordsToXfer; + unsigned PartialBytes; + unsigned i; + + while (BytesRemaining) { + xdbg_printf(XDBG_DEBUG_FIFO_RX, + "XStrm_Read: BytesRemaining: %d\n", BytesRemaining); + /* Case 1: There are bytes in the holding buffer + * + * 1) Read the bytes from the holding buffer to the target buffer. + * 2) Loop back around and handle the rest of the transfer. + */ + if (InstancePtr->HeadIndex != InstancePtr->FifoWidth) { + xdbg_printf(XDBG_DEBUG_FIFO_RX, + "XStrm_Read: Case 1: InstancePtr->HeadIndex [%d] != InstancePtr->FifoWidth [%d]\n", + InstancePtr->HeadIndex, + InstancePtr->FifoWidth); + i = InstancePtr->HeadIndex; + + PartialBytes = min(BytesRemaining, + InstancePtr->FifoWidth - + InstancePtr->HeadIndex); + InstancePtr->HeadIndex += PartialBytes; + BytesRemaining -= PartialBytes; + InstancePtr->FrmByteCnt -= PartialBytes; + while (PartialBytes--) { + *DestPtr = InstancePtr->AlignedBuffer.bytes[i]; + i++; + DestPtr++; + } + } + /* Case 2: There are no more bytes in the holding buffer and + * the target buffer is 32 bit aligned and + * the number of bytes remaining to transfer is greater + * than or equal to the fifo width. + * + * 1) We can go fast by reading a long string of fifo words right out + * of the fifo into the target buffer. + * 2) Loop back around to transfer the last few bytes. + */ + else if ((((unsigned) DestPtr & 3) == 0) && + (BytesRemaining >= InstancePtr->FifoWidth)) { + xdbg_printf(XDBG_DEBUG_FIFO_RX, + "XStrm_Read: Case 2: DestPtr: %p, BytesRemaining: %d, InstancePtr->FifoWidth: %d\n", + DestPtr, BytesRemaining, + InstancePtr->FifoWidth); + FifoWordsToXfer = + BytesRemaining / InstancePtr->FifoWidth; + + (*(InstancePtr->ReadFn)) (InstancePtr->FifoInstance, + DestPtr, FifoWordsToXfer); + DestPtr += FifoWordsToXfer * InstancePtr->FifoWidth; + BytesRemaining -= + FifoWordsToXfer * InstancePtr->FifoWidth; + InstancePtr->FrmByteCnt -= + FifoWordsToXfer * InstancePtr->FifoWidth; + } + /* Case 3: There are no more bytes in the holding buffer and + * the number of bytes remaining to transfer is less than + * the fifo width or + * things just don't line up. + * + * 1) Fill the holding buffer. + * 2) Loop back around and handle the rest of the transfer. + */ + else { + xdbg_printf(XDBG_DEBUG_FIFO_RX, "XStrm_Read: Case 3\n"); + /* + * At the tail end, read one fifo word into the local holding + * buffer and loop back around to take care of the transfer. + */ + (*InstancePtr->ReadFn) (InstancePtr->FifoInstance, + &(InstancePtr->AlignedBuffer. + bytes[0]), 1); + InstancePtr->HeadIndex = 0; + } + } +} + +/*****************************************************************************/ +/* +* +* XStrm_TxSetLen flushes to the FIFO, specified by <i>InstancePtr</i>, any +* bytes remaining in internal buffers and begins a hardware transfer of data +* out of the transmit channel of the FIFO. <i>Bytes</i> specifies the number +* of bytes in the frame to transmit. +* +* @param InstancePtr references the FIFO Streamer on which to operate. +* +* @param Bytes specifies the frame length in bytes. +* +* @return N/A +* +******************************************************************************/ +void XStrm_TxSetLen(XStrm_TxFifoStreamer * InstancePtr, u32 Bytes) +{ + /* + * First flush what's in the holding buffer + */ + if (InstancePtr->TailIndex != 0) { + (*InstancePtr->WriteFn) (InstancePtr->FifoInstance, + &(InstancePtr->AlignedBuffer.bytes[0]), + 1); + InstancePtr->TailIndex = 0; + } + + /* + * Kick off the hw write + */ + (*(InstancePtr)->SetLenFn) (InstancePtr->FifoInstance, Bytes); +} + +/*****************************************************************************/ +/* +* +* XStrm_Write writes <i>Bytes</i> bytes of the block of memory, referenced by +* <i>BufPtr</i>, to the transmit channel of the FIFO referenced by +* <i>InstancePtr</i>. +* +* Care must be taken to ensure that the number of bytes written with one or +* more calls to XStrm_Write() matches the number of bytes given in the next +* call to XStrm_TxSetLen(). +* +* @param InstancePtr references the FIFO on which to operate. +* +* @param BufPtr specifies the memory address of data to write. +* +* @param Bytes specifies the number of bytes to write. +* +* @return N/A +* +******************************************************************************/ +void XStrm_Write(XStrm_TxFifoStreamer * InstancePtr, void *BufPtr, + unsigned Bytes) +{ + u8 *SrcPtr = (u8 *) BufPtr; + unsigned BytesRemaining = Bytes; + unsigned FifoWordsToXfer; + unsigned PartialBytes; + unsigned i; + + while (BytesRemaining) { + xdbg_printf(XDBG_DEBUG_FIFO_TX, + "XStrm_Write: BytesRemaining: %d\n", + BytesRemaining); + /* Case 1: The holding buffer is full + * + * 1) Write it to the fifo. + * 2) Fall through to transfer more bytes in this iteration. + */ + if (InstancePtr->TailIndex == InstancePtr->FifoWidth) { + xdbg_printf(XDBG_DEBUG_FIFO_TX, + "XStrm_Write: (case 1) TailIndex: %d; FifoWidth: %d; WriteFn: %p\n", + InstancePtr->TailIndex, + InstancePtr->FifoWidth, + InstancePtr->WriteFn); + (*InstancePtr->WriteFn) (InstancePtr->FifoInstance, + &(InstancePtr->AlignedBuffer. + bytes[0]), 1); + InstancePtr->TailIndex = 0; + } + /* Case 2: There are no bytes in the holding buffer and + * the target buffer is 32 bit aligned and + * the number of bytes remaining to transfer is greater + * than or equal to the fifo width. + * + * 1) We can go fast by writing a long string of fifo words right out + * of the source buffer into the fifo. + * 2) Loop back around to transfer the last few bytes. + */ + if ((InstancePtr->TailIndex == 0) && + (BytesRemaining >= InstancePtr->FifoWidth) && + (((unsigned) SrcPtr & 3) == 0)) { + FifoWordsToXfer = + BytesRemaining / InstancePtr->FifoWidth; + + xdbg_printf(XDBG_DEBUG_FIFO_TX, + "XStrm_Write: (case 2) TailIndex: %d; BytesRemaining: %d; FifoWidth: %d; SrcPtr: %p;\n InstancePtr: %p; WriteFn: %p (XLlFifo_iWrite_Aligned: %p),\nFifoWordsToXfer: %d (BytesRemaining: %d)\n", + InstancePtr->TailIndex, BytesRemaining, + InstancePtr->FifoWidth, SrcPtr, InstancePtr, + InstancePtr->WriteFn, + XLlFifo_iWrite_Aligned, FifoWordsToXfer, + BytesRemaining); + + (*InstancePtr->WriteFn) (InstancePtr->FifoInstance, + SrcPtr, FifoWordsToXfer); + SrcPtr += FifoWordsToXfer * InstancePtr->FifoWidth; + BytesRemaining -= + FifoWordsToXfer * InstancePtr->FifoWidth; + xdbg_printf(XDBG_DEBUG_FIFO_TX, + "XStrm_Write: (end case 2) TailIndex: %d; BytesRemaining: %d; SrcPtr: %p\n", + InstancePtr->TailIndex, BytesRemaining, + SrcPtr); + } + /* Case 3: The alignment of the "galaxies" didn't occur in + * Case 2 above, so we must pump the bytes through the + * holding buffer. + * + * 1) Write bytes from the source buffer to the holding buffer + * 2) Loop back around and handle the rest of the transfer. + */ + else { + i = InstancePtr->TailIndex; + + PartialBytes = + min(BytesRemaining, + InstancePtr->FifoWidth - + InstancePtr->TailIndex); + BytesRemaining -= PartialBytes; + InstancePtr->TailIndex += PartialBytes; + while (PartialBytes--) { + xdbg_printf(XDBG_DEBUG_FIFO_TX, + "XStrm_Write: (case 3) PartialBytes: %d\n", + PartialBytes); + InstancePtr->AlignedBuffer.bytes[i] = *SrcPtr; + i++; + SrcPtr++; + } + } + } +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xstreamer.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xstreamer.h 2014-07-20 22:06:39.241258131 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2005-2008 Xilinx Inc. +* All rights reserved. +* 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. +* +* 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 +* +******************************************************************************/ +/*****************************************************************************/ +/* + * + * @file xstreamer.h + * + * The Xilinx byte streamer for packet FIFOs. + * + * <h2>Driver Description</h2> + * + * This driver enables higher layer software to access a hardware FIFO using + * any alignment in the data buffers while preserving alignment for the hardware + * FIFO access. + * + * This driver treats send and receive channels separately, using different + * types of instance objects for each. + * + * This driver makes use of another FIFO driver to access the specific FIFO + * hardware through use of the routines passed into the Tx/RxInitialize + * routines. + * + * <h2>Initialization</h2> + * + * Send and receive channels are intialized separately. The receive channel is + * initiailzed using XStrm_RxInitialize(). The send channel is initialized + * using XStrm_TxInitialize(). + * + * + * <h2>Usage</h2> + * It is fairly simple to use the API provided by this byte streamer + * driver. The only somewhat tricky part is that the calling code must + * correctly call a couple routines in the right sequence for receive and + * transmit. + * + * This sequence is described here. Check the routine functional + * descriptions for information on how to use a specific API routine. + * + * <h3>Receive</h3> + * A frame is received by using the following sequence:<br> + * 1) call XStrm_RxGetLen() to get the length of the next incoming frame.<br> + * 2) call XStrm_Read() one or more times to read the number of bytes + * reported by XStrm_RxGetLen().<br> + * + * For example: + * <pre> + * frame_len = XStrm_RxGetLen(&RxInstance); + * while (frame_len) { + * unsigned bytes = min(sizeof(buffer), frame_len); + * XStrm_Read(&RxInstance, buffer, bytes); + * // do something with buffer here + * frame_len -= bytes; + * } + * </pre> + * + * Other restrictions on the sequence of API calls may apply depending on + * the specific FIFO driver used by this byte streamer driver. + * + * <h3>Transmit</h3> + * A frame is transmittted by using the following sequence:<br> + * 1) call XStrm_Write() one or more times to write all the of bytes in + * the next frame.<br> + * 2) call XStrm_TxSetLen() to begin the transmission of frame just + * written.<br> + * + * For example: + * <pre> + * frame_left = frame_len; + * while (frame_left) { + * unsigned bytes = min(sizeof(buffer), frame_left); + * XStrm_Write(&TxInstance, buffer, bytes); + * // do something here to refill buffer + * } + * XStrm_TxSetLen(&RxInstance, frame_len); + * </pre> + * + * Other restrictions on the sequence of API calls may apply depending on + * the specific FIFO driver used by this byte streamer driver. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- ---- -------- ------------------------------------------------------- + * 1.00a jvb 10/12/06 First release + * </pre> + * + *****************************************************************************/ +#ifndef XSTREAMER_H /* prevent circular inclusions */ +#define XSTREAMER_H /* by using preprocessor symbols */ + +/* force C linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "xbasic_types.h" +#include "xstatus.h" +#include "xdebug.h" + +/* + * key hole size in 32 bit words + */ +#define LARGEST_FIFO_KEYHOLE_SIZE_WORDS 4 + +/* + * This union is used simply to force a 32bit alignment on the + * buffer. Only the 'bytes' member is really used. + */ +union XStrm_AlignedBufferType { + u32 _words[LARGEST_FIFO_KEYHOLE_SIZE_WORDS]; + char bytes[LARGEST_FIFO_KEYHOLE_SIZE_WORDS * 4]; +}; + +typedef int(*XStrm_XferFnType) (void *FifoInstance, void *BufPtr, + unsigned WordCount); +typedef u32 (*XStrm_GetLenFnType) (void *FifoInstance); +typedef void (*XStrm_SetLenFnType) (void *FifoInstance, + u32 ByteCount); +typedef u32 (*XStrm_GetOccupancyFnType) (void *FifoInstance); +typedef u32 (*XStrm_GetVacancyFnType) (void *FifoInstance); + +/** + * This typedef defines a run-time instance of a receive byte-streamer. + */ +typedef struct XStrm_RxFifoStreamer { + union XStrm_AlignedBufferType AlignedBuffer; + unsigned HeadIndex; /**< HeadIndex is the index to the AlignedBuffer + * as bytes. + */ + unsigned FifoWidth; /**< FifoWidth is the FIFO key hole width in bytes. + */ + unsigned FrmByteCnt; /**< FrmByteCnt is the number of bytes in the next + * Frame. + */ + void *FifoInstance; /**< FifoInstance is the FIFO driver instance to + * pass to ReadFn, GetLenFn, and GetOccupancyFn + * routines. + */ + XStrm_XferFnType ReadFn; /**< ReadFn is the routine the streamer + * uses to receive bytes from the Fifo. + */ + XStrm_GetLenFnType GetLenFn; /**< GetLenFn is the routine the streamer + * uses to initiate receive operations + * on the FIFO. + */ + XStrm_GetOccupancyFnType GetOccupancyFn; /**< GetOccupancyFn is the + * routine the streamer uses + * to get the occupancy from + * the FIFO. + */ +} XStrm_RxFifoStreamer; + +/** + * This typedef defines a run-time instance of a transmit byte-streamer. + */ +typedef struct XStrm_TxFifoStreamer { + union XStrm_AlignedBufferType AlignedBuffer; + unsigned TailIndex; /**< TailIndex is the index to the AlignedBuffer + * as bytes + */ + unsigned FifoWidth; /**< FifoWidth is the FIFO key hole width in bytes. + */ + + void *FifoInstance; /**< FifoInstance is the FIFO driver instance to + * pass to WriteFn, SetLenFn, and GetVacancyFn + * routines. + */ + XStrm_XferFnType WriteFn; /**< WriteFn is the routine the streamer + * uses to transmit bytes to the Fifo. + */ + XStrm_SetLenFnType SetLenFn; /**< SetLenFn is the routine the streamer + * uses to initiate transmit operations + * on the FIFO. + */ + XStrm_GetVacancyFnType GetVacancyFn; /**< GetVaccancyFn is the routine + * the streamer uses to get the + * vacancy from the FIFO. + */ +} XStrm_TxFifoStreamer; + +/*****************************************************************************/ +/* +* +* XStrm_TxVacancy returns the number of unused 32-bit words available (vacancy) +* between the streamer, specified by <i>InstancePtr</i>, and the FIFO this +* streamer is using. +* +* @param InstancePtr references the streamer on which to operate. +* +* @return XStrm_TxVacancy returns the vacancy count in number of 32 bit words. +* +* @note +* +* C Signature: u32 XStrm_TxVacancy(XStrm_TxFifoStreamer *InstancePtr) +* +* The amount of bytes in the holding buffer (rounded up to whole 32-bit words) +* is subtracted from the vacancy value of FIFO this streamer is using. This is +* to ensure the caller can write the number words given in the return value and +* not overflow the FIFO. +* +******************************************************************************/ +#define XStrm_TxVacancy(InstancePtr) \ + (((*(InstancePtr)->GetVacancyFn)((InstancePtr)->FifoInstance)) - \ + (((InstancePtr)->TailIndex + 3) / 4)) + +/*****************************************************************************/ +/* +* +* XStrm_RxOccupancy returns the number of 32-bit words available (occupancy) to +* be read from the streamer, specified by <i>InstancePtr</i>, and FIFO this +* steamer is using. +* +* @param InstancePtr references the streamer on which to operate. +* +* @return XStrm_RxOccupancy returns the occupancy count in number of 32 bit +* words. +* +* @note +* +* C Signature: u32 XStrm_RxOccupancy(XStrm_RxFifoStreamer *InstancePtr) +* +* The amount of bytes in the holding buffer (rounded up to whole 32-bit words) +* is added to the occupancy value of FIFO this streamer is using. This is to +* ensure the caller will get a little more accurate occupancy value. +* +******************************************************************************/ +#ifdef DEBUG +extern u32 _xstrm_ro_value; +extern u32 _xstrm_buffered; +#define XStrm_RxOccupancy(InstancePtr) \ + (_xstrm_ro_value = ((*(InstancePtr)->GetOccupancyFn)((InstancePtr)->FifoInstance)), \ + xdbg_printf(XDBG_DEBUG_FIFO_RX, "reg: %d; frmbytecnt: %d\n", \ + _xstrm_ro_value, (InstancePtr)->FrmByteCnt), \ + (((InstancePtr)->FrmByteCnt) ? \ + _xstrm_buffered = ((InstancePtr)->FifoWidth - (InstancePtr)->HeadIndex) : \ + 0), \ + xdbg_printf(XDBG_DEBUG_FIFO_RX, "buffered_bytes: %d\n", _xstrm_buffered), \ + xdbg_printf(XDBG_DEBUG_FIFO_RX, "buffered (rounded): %d\n", _xstrm_buffered), \ + (_xstrm_ro_value + _xstrm_buffered)) +#else +#define XStrm_RxOccupancy(InstancePtr) \ + ( \ + ((*(InstancePtr)->GetOccupancyFn)((InstancePtr)->FifoInstance)) + \ + ( \ + ((InstancePtr)->FrmByteCnt) ? \ + ((InstancePtr)->FifoWidth - (InstancePtr)->HeadIndex) : \ + 0 \ + ) \ + ) +#endif + +/****************************************************************************/ +/* +* +* XStrm_IsRxInternalEmpty returns true if the streamer, specified by +* <i>InstancePtr</i>, is not holding any bytes in it's internal buffers. Note +* that this routine does not reflect information about the state of the +* FIFO used by this streamer. +* +* @param InstancePtr references the streamer on which to operate. +* +* @return XStrm_IsRxInternalEmpty returns TRUE when the streamer is not +* holding any bytes in it's internal buffers. Otherwise, +* XStrm_IsRxInternalEmpty returns FALSE. +* +* @note +* C-style signature: +* int XStrm_IsRxInternalEmpty(XStrm_RxFifoStreamer *InstancePtr) +* +*****************************************************************************/ +#define XStrm_IsRxInternalEmpty(InstancePtr) \ + (((InstancePtr)->HeadIndex == (InstancePtr)->FifoWidth) ? TRUE : FALSE) + +void XStrm_RxInitialize(XStrm_RxFifoStreamer *InstancePtr, + unsigned FifoWidth, void *FifoInstance, + XStrm_XferFnType ReadFn, + XStrm_GetLenFnType GetLenFn, + XStrm_GetOccupancyFnType GetOccupancyFn); + +void XStrm_TxInitialize(XStrm_TxFifoStreamer *InstancePtr, + unsigned FifoWidth, void *FifoInstance, + XStrm_XferFnType WriteFn, + XStrm_SetLenFnType SetLenFn, + XStrm_GetVacancyFnType GetVacancyFn); + +void XStrm_TxSetLen(XStrm_TxFifoStreamer *InstancePtr, u32 Bytes); +void XStrm_Write(XStrm_TxFifoStreamer *InstancePtr, void *BufPtr, + unsigned bytes); + +u32 XStrm_RxGetLen(XStrm_RxFifoStreamer *InstancePtr); +void XStrm_Read(XStrm_RxFifoStreamer *InstancePtr, void *BufPtr, + unsigned bytes); + +#ifdef __cplusplus +} +#endif +#endif /* XSTREAMER_H end of preprocessor protection symbols */ Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xversion.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xversion.c 2014-07-20 22:06:39.252257950 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xversion.c,v 1.1 2006/12/13 14:23:34 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xversion.c +* +* This file contains the implementation of the XVersion component. This +* component represents a version ID. It is encapsulated within a component +* so that it's type and implementation can change without affecting users of +* it. +* +* The version is formatted as X.YYZ where X = 0 - 9, Y = 00 - 99, Z = a - z +* X is the major revision, YY is the minor revision, and Z is the +* compatability revision. +* +* Packed versions are also utilized for the configuration ROM such that +* memory is minimized. A packed version consumes only 16 bits and is +* formatted as follows. +* +* <pre> +* Revision Range Bit Positions +* +* Major Revision 0 - 9 Bits 15 - 12 +* Minor Revision 0 - 99 Bits 11 - 5 +* Compatability Revision a - z Bits 4 - 0 +* +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a xd 11/03/04 Improved support for doxygen. +</pre> +* +******************************************************************************/ + + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xversion.h" + +/************************** Constant Definitions *****************************/ + +/* the following constants define the masks and shift values to allow the + * revisions to be packed and unpacked, a packed version is packed into a 16 + * bit value in the following format, XXXXYYYYYYYZZZZZ, where XXXX is the + * major revision, YYYYYYY is the minor revision, and ZZZZZ is the compatability + * revision + */ +#define XVE_MAJOR_SHIFT_VALUE 12 +#define XVE_MINOR_ONLY_MASK 0x0FE0 +#define XVE_MINOR_SHIFT_VALUE 5 +#define XVE_COMP_ONLY_MASK 0x001F + +/* the following constants define the specific characters of a version string + * for each character of the revision, a version string is in the following + * format, "X.YYZ" where X is the major revision (0 - 9), YY is the minor + * revision (00 - 99), and Z is the compatability revision (a - z) + */ +#define XVE_MAJOR_CHAR 0 /* major revision 0 - 9 */ +#define XVE_MINOR_TENS_CHAR 2 /* minor revision tens 0 - 9 */ +#define XVE_MINOR_ONES_CHAR 3 /* minor revision ones 0 - 9 */ +#define XVE_COMP_CHAR 4 /* compatability revision a - z */ +#define XVE_END_STRING_CHAR 5 + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +static u32 IsVersionStringValid(s8 *StringPtr); + +/*****************************************************************************/ +/** +* +* Unpacks a packed version into the specified version. Versions are packed +* into the configuration ROM to reduce the amount storage. A packed version +* is a binary format as oppossed to a non-packed version which is implemented +* as a string. +* +* @param InstancePtr points to the version to unpack the packed version into. +* @param PackedVersion contains the packed version to unpack. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XVersion_UnPack(XVersion * InstancePtr, u16 PackedVersion) +{ + /* not implemented yet since CROM related */ +} + +/*****************************************************************************/ +/** +* +* Packs a version into the specified packed version. Versions are packed into +* the configuration ROM to reduce the amount storage. +* +* @param InstancePtr points to the version to pack. +* @param PackedVersionPtr points to the packed version which will receive +* the new packed version. +* +* @return +* +* A status, XST_SUCCESS, indicating the packing was accomplished +* successfully, or an error, XST_INVALID_VERSION, indicating the specified +* input version was not valid such that the pack did not occur +* <br><br> +* The packed version pointed to by PackedVersionPtr is modified with the new +* packed version if the status indicates success. +* +* @note +* +* None. +* +******************************************************************************/ +int XVersion_Pack(XVersion * InstancePtr, u16 *PackedVersionPtr) +{ + /* not implemented yet since CROM related */ + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Determines if two versions are equal. +* +* @param InstancePtr points to the first version to be compared. +* @param VersionPtr points to a second version to be compared. +* +* @return +* +* TRUE if the versions are equal, FALSE otherwise. +* +* @note +* +* None. +* +******************************************************************************/ +u32 XVersion_IsEqual(XVersion * InstancePtr, XVersion * VersionPtr) +{ + u8 *Version1 = (u8 *) InstancePtr; + u8 *Version2 = (u8 *) VersionPtr; + int Index; + + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(VersionPtr != NULL); + + /* check each byte of the versions to see if they are the same, + * return at any point a byte differs between them + */ + for (Index = 0; Index < sizeof(XVersion); Index++) { + if (Version1[Index] != Version2[Index]) { + return FALSE; + } + } + + /* No byte was found to be different between the versions, so indicate + * the versions are equal + */ + return TRUE; +} + +/*****************************************************************************/ +/** +* +* Converts a version to a null terminated string. +* +* @param InstancePtr points to the version to convert. +* @param StringPtr points to the string which will be the result of the +* conversion. This does not need to point to a null terminated +* string as an input, but must point to storage which is an adequate +* amount to hold the result string. +* +* @return +* +* The null terminated string is inserted at the location pointed to by +* StringPtr if the status indicates success. +* +* @note +* +* It is necessary for the caller to have already allocated the storage to +* contain the string. The amount of memory necessary for the string is +* specified in the version header file. +* +******************************************************************************/ +void XVersion_ToString(XVersion * InstancePtr, s8 *StringPtr) +{ + /* assert to verify input arguments */ + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(StringPtr != NULL); + + /* since version is implemented as a string, just copy the specified + * input into the specified output + */ + XVersion_Copy(InstancePtr, (XVersion *) StringPtr); +} + +/*****************************************************************************/ +/** +* +* Initializes a version from a null terminated string. Since the string may not +* be a format which is compatible with the version, an error could occur. +* +* @param InstancePtr points to the version which is to be initialized. +* @param StringPtr points to a null terminated string which will be +* converted to a version. The format of the string must match the +* version string format which is X.YYX where X = 0 - 9, YY = 00 - 99, +* Z = a - z. +* +* @return +* +* A status, XST_SUCCESS, indicating the conversion was accomplished +* successfully, or XST_INVALID_VERSION indicating the version string format +* was not valid. +* +* @note +* +* None. +* +******************************************************************************/ +int XVersion_FromString(XVersion * InstancePtr, s8 *StringPtr) +{ + /* assert to verify input arguments */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(StringPtr != NULL); + + /* if the version string specified is not valid, return an error */ + + if (!IsVersionStringValid(StringPtr)) { + return XST_INVALID_VERSION; + } + + /* copy the specified string into the specified version and indicate the + * conversion was successful + */ + XVersion_Copy((XVersion *) StringPtr, InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Copies the contents of a version to another version. +* +* @param InstancePtr points to the version which is the source of data for +* the copy operation. +* @param VersionPtr points to another version which is the destination of +* the copy operation. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void XVersion_Copy(XVersion * InstancePtr, XVersion * VersionPtr) +{ + u8 *Source = (u8 *) InstancePtr; + u8 *Destination = (u8 *) VersionPtr; + int Index; + + /* assert to verify input arguments */ + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(VersionPtr != NULL); + + /* copy each byte of the source version to the destination version */ + + for (Index = 0; Index < sizeof(XVersion); Index++) { + Destination[Index] = Source[Index]; + } +} + +/*****************************************************************************/ +/** +* +* Determines if the specified version is valid. +* +* @param StringPtr points to the string to be validated. +* +* @return +* +* TRUE if the version string is a valid format, FALSE otherwise. +* +* @note +* +* None. +* +******************************************************************************/ +static u32 IsVersionStringValid(s8 *StringPtr) +{ + /* if the input string is not a valid format, "X.YYZ" where X = 0 - 9, + * YY = 00 - 99, and Z = a - z, then indicate it's not valid + */ + if ((StringPtr[XVE_MAJOR_CHAR] < '0') || + (StringPtr[XVE_MAJOR_CHAR] > '9') || + (StringPtr[XVE_MINOR_TENS_CHAR] < '0') || + (StringPtr[XVE_MINOR_TENS_CHAR] > '9') || + (StringPtr[XVE_MINOR_ONES_CHAR] < '0') || + (StringPtr[XVE_MINOR_ONES_CHAR] > '9') || + (StringPtr[XVE_COMP_CHAR] < 'a') || + (StringPtr[XVE_COMP_CHAR] > 'z')) { + return FALSE; + } + + return TRUE; +} Index: linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xversion.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/drivers/xilinx_common/xversion.h 2014-07-20 22:06:39.258257851 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* $Id: xversion.h,v 1.1 2006/12/13 14:23:41 imanuilov Exp $ */ +/****************************************************************************** +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" +* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND +* SOLUTIONS FOR XILINX DEVICES. 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. +* +* (c) Copyright 2002 Xilinx Inc. +* All rights reserved. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* @file xversion.h +* +* This file contains the interface for the XVersion component. This +* component represents a version ID. It is encapsulated within a component +* so that it's type and implementation can change without affecting users of +* it. +* +* The version is formatted as X.YYZ where X = 0 - 9, Y = 00 - 99, Z = a - z +* X is the major revision, YY is the minor revision, and Z is the +* compatability revision. +* +* Packed versions are also utilized for the configuration ROM such that +* memory is minimized. A packed version consumes only 16 bits and is +* formatted as follows. +* +* <pre> +* Revision Range Bit Positions +* +* Major Revision 0 - 9 Bits 15 - 12 +* Minor Revision 0 - 99 Bits 11 - 5 +* Compatability Revision a - z Bits 4 - 0 +* +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a xd 11/03/04 Improved support for doxygen. +* </pre> +* +******************************************************************************/ + +#ifndef XVERSION_H /* prevent circular inclusions */ +#define XVERSION_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xstatus.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + +/* the following data type is used to hold a null terminated version string + * consisting of the following format, "X.YYX" + */ +typedef s8 XVersion[6]; + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +void XVersion_UnPack(XVersion * InstancePtr, u16 PackedVersion); + +int XVersion_Pack(XVersion * InstancePtr, u16 *PackedVersion); + +u32 XVersion_IsEqual(XVersion * InstancePtr, XVersion * VersionPtr); + +void XVersion_ToString(XVersion * InstancePtr, s8 *StringPtr); + +int XVersion_FromString(XVersion * InstancePtr, s8 *StringPtr); + +void XVersion_Copy(XVersion * InstancePtr, XVersion * VersionPtr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ Index: linux-3.12.24-rt38-xilinx/include/asm-generic/dma-mapping-common.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/asm-generic/dma-mapping-common.h 2014-07-20 22:05:50.339064921 +0200 +++ linux-3.12.24-rt38-xilinx/include/asm-generic/dma-mapping-common.h 2014-07-20 22:06:39.274257587 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:19 @ dma_addr_t addr; kmemcheck_mark_initialized(ptr, size); + BUG_ON(!ops); BUG_ON(!valid_dma_direction(dir)); addr = ops->map_page(dev, virt_to_page(ptr), (unsigned long)ptr & ~PAGE_MASK, size, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:37 @ { struct dma_map_ops *ops = get_dma_ops(dev); + BUG_ON(!ops); BUG_ON(!valid_dma_direction(dir)); if (ops->unmap_page) ops->unmap_page(dev, addr, size, dir, attrs); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:54 @ for_each_sg(sg, s, nents, i) kmemcheck_mark_initialized(sg_virt(s), s->length); + BUG_ON(!ops); BUG_ON(!valid_dma_direction(dir)); ents = ops->map_sg(dev, sg, nents, dir, attrs); debug_dma_map_sg(dev, sg, nents, ents, dir); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:68 @ { struct dma_map_ops *ops = get_dma_ops(dev); + BUG_ON(!ops); BUG_ON(!valid_dma_direction(dir)); debug_dma_unmap_sg(dev, sg, nents, dir); if (ops->unmap_sg) @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:83 @ dma_addr_t addr; kmemcheck_mark_initialized(page_address(page) + offset, size); + BUG_ON(!ops); BUG_ON(!valid_dma_direction(dir)); addr = ops->map_page(dev, page, offset, size, dir, NULL); debug_dma_map_page(dev, page, offset, size, dir, addr, false); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:96 @ { struct dma_map_ops *ops = get_dma_ops(dev); + BUG_ON(!ops); BUG_ON(!valid_dma_direction(dir)); if (ops->unmap_page) ops->unmap_page(dev, addr, size, dir, NULL); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:161 @ { struct dma_map_ops *ops = get_dma_ops(dev); + BUG_ON(!ops); BUG_ON(!valid_dma_direction(dir)); if (ops->sync_sg_for_cpu) ops->sync_sg_for_cpu(dev, sg, nelems, dir); @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:174 @ { struct dma_map_ops *ops = get_dma_ops(dev); + BUG_ON(!ops); BUG_ON(!valid_dma_direction(dir)); if (ops->sync_sg_for_device) ops->sync_sg_for_device(dev, sg, nelems, dir); Index: linux-3.12.24-rt38-xilinx/include/asm-generic/vmlinux.lds.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/asm-generic/vmlinux.lds.h 2014-07-20 22:05:50.340064905 +0200 +++ linux-3.12.24-rt38-xilinx/include/asm-generic/vmlinux.lds.h 2014-07-20 22:06:39.288257356 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:473 @ } #ifdef CONFIG_CONSTRUCTORS -#define KERNEL_CTORS() . = ALIGN(8); \ - VMLINUX_SYMBOL(__ctors_start) = .; \ - *(.ctors) \ +#define KERNEL_CTORS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__ctors_start) = .; \ + *(CONFIG_CONSTRUCTORS_NAME) \ VMLINUX_SYMBOL(__ctors_end) = .; #else #define KERNEL_CTORS() Index: linux-3.12.24-rt38-xilinx/include/drm/drm_edid.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/drm/drm_edid.h 2014-07-20 22:05:50.335064988 +0200 +++ linux-3.12.24-rt38-xilinx/include/drm/drm_edid.h 2014-07-20 22:06:39.303257109 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:277 @ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, const struct drm_display_mode *mode); +struct edid *drm_do_get_edid(struct drm_connector *connector, + int (*get_edid_block)(void *, unsigned char *buf, int, int), + void *data); + #endif /* __DRM_EDID_H__ */ Index: linux-3.12.24-rt38-xilinx/include/drm/i2c/adv7511.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/drm/i2c/adv7511.h 2014-07-20 22:06:39.321256812 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Analog Devices ADV7511 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#ifndef __DRM_I2C_ADV7511_H__ +#define __DRM_I2C_ADV7511_H__ + +#include <linux/hdmi.h> + +#define ADV7511_REG_CHIP_REVISION 0x00 +#define ADV7511_REG_N0 0x01 +#define ADV7511_REG_N1 0x02 +#define ADV7511_REG_N2 0x03 +#define ADV7511_REG_SPDIF_FREQ 0x04 +#define ADV7511_REG_CTS_AUTOMATIC1 0x05 +#define ADV7511_REG_CTS_AUTOMATIC2 0x06 +#define ADV7511_REG_CTS_MANUAL0 0x07 +#define ADV7511_REG_CTS_MANUAL1 0x08 +#define ADV7511_REG_CTS_MANUAL2 0x09 +#define ADV7511_REG_AUDIO_SOURCE 0x0a +#define ADV7511_REG_AUDIO_CONFIG 0x0b +#define ADV7511_REG_I2S_CONFIG 0x0c +#define ADV7511_REG_I2S_WIDTH 0x0d +#define ADV7511_REG_AUDIO_SUB_SRC0 0x0e +#define ADV7511_REG_AUDIO_SUB_SRC1 0x0f +#define ADV7511_REG_AUDIO_SUB_SRC2 0x10 +#define ADV7511_REG_AUDIO_SUB_SRC3 0x11 +#define ADV7511_REG_AUDIO_CFG1 0x12 +#define ADV7511_REG_AUDIO_CFG2 0x13 +#define ADV7511_REG_AUDIO_CFG3 0x14 +#define ADV7511_REG_I2C_FREQ_ID_CFG 0x15 +#define ADV7511_REG_VIDEO_INPUT_CFG1 0x16 +#define ADV7511_REG_CSC_UPPER(x) (0x18 + (x) * 2) +#define ADV7511_REG_CSC_LOWER(x) (0x19 + (x) * 2) +#define ADV7511_REG_SYNC_DECODER(x) (0x30 + (x)) +#define ADV7511_REG_DE_GENERATOR (0x35 + (x)) +#define ADV7511_REG_PIXEL_REPETITION 0x3b +#define ADV7511_REG_VIC_MANUAL 0x3c +#define ADV7511_REG_VIC_SEND 0x3d +#define ADV7511_REG_VIC_DETECTED 0x3e +#define ADV7511_REG_AUX_VIC_DETECTED 0x3f +#define ADV7511_REG_PACKET_ENABLE0 0x40 +#define ADV7511_REG_POWER 0x41 +#define ADV7511_REG_STATUS 0x42 +#define ADV7511_REG_EDID_I2C_ADDR 0x43 +#define ADV7511_REG_PACKET_ENABLE1 0x44 +#define ADV7511_REG_PACKET_I2C_ADDR 0x45 +#define ADV7511_REG_DSD_ENABLE 0x46 +#define ADV7511_REG_VIDEO_INPUT_CFG2 0x48 +#define ADV7511_REG_INFOFRAME_UPDATE 0x4a +#define ADV7511_REG_GC(x) (0x4b + (x)) /* 0x4b - 0x51 */ +#define ADV7511_REG_AVI_INFOFRAME_VERSION 0x52 +#define ADV7511_REG_AVI_INFOFRAME_LENGTH 0x53 +#define ADV7511_REG_AVI_INFOFRAME_CHECKSUM 0x54 +#define ADV7511_REG_AVI_INFOFRAME(x) (0x55 + (x)) /* 0x55 - 0x6f */ +#define ADV7511_REG_AUDIO_INFOFRAME_VERSION 0x70 +#define ADV7511_REG_AUDIO_INFOFRAME_LENGTH 0x71 +#define ADV7511_REG_AUDIO_INFOFRAME_CHECKSUM 0x72 +#define ADV7511_REG_AUDIO_INFOFRAME(x) (0x73 + (x)) /* 0x73 - 0x7c */ +#define ADV7511_REG_INT_ENABLE(x) (0x94 + (x)) +#define ADV7511_REG_INT(x) (0x96 + (x)) +#define ADV7511_REG_INPUT_CLK_DIV 0x9d +#define ADV7511_REG_PLL_STATUS 0x9e +#define ADV7511_REG_HDMI_POWER 0xa1 +#define ADV7511_REG_HDCP_HDMI_CFG 0xaf +#define ADV7511_REG_AN(x) (0xb0 + (x)) /* 0xb0 - 0xb7 */ +#define ADV7511_REG_HDCP_STATUS 0xb8 +#define ADV7511_REG_BCAPS 0xbe +#define ADV7511_REG_BKSV(x) (0xc0 + (x)) /* 0xc0 - 0xc3 */ +#define ADV7511_REG_EDID_SEGMENT 0xc4 +#define ADV7511_REG_DDC_STATUS 0xc8 +#define ADV7511_REG_EDID_READ_CTRL 0xc9 +#define ADV7511_REG_BSTATUS(x) (0xca + (x)) /* 0xca - 0xcb */ +#define ADV7511_REG_TIMING_GEN_SEQ 0xd0 +#define ADV7511_REG_POWER2 0xd6 +#define ADV7511_REG_HSYNC_PLACEMENT_MSB 0xfa + +#define ADV7511_REG_SYNC_ADJUSTMENT(x) (0xd7 + (x)) /* 0xd7 - 0xdc */ +#define ADV7511_REG_TMDS_CLOCK_INV 0xde +#define ADV7511_REG_ARC_CTRL 0xdf +#define ADV7511_REG_CEC_I2C_ADDR 0xe1 +#define ADV7511_REG_CEC_CTRL 0xe2 +#define ADV7511_REG_CHIP_ID_HIGH 0xf5 +#define ADV7511_REG_CHIP_ID_LOW 0xf6 + +#define ADV7511_CSC_ENABLE BIT(7) +#define ADV7511_CSC_UPDATE_MODE BIT(5) + +#define ADV7511_INT0_HDP BIT(7) +#define ADV7511_INT0_VSYNC BIT(5) +#define ADV7511_INT0_AUDIO_FIFO_FULL BIT(4) +#define ADV7511_INT0_EDID_READY BIT(2) +#define ADV7511_INT0_HDCP_AUTHENTICATED BIT(1) + +#define ADV7511_INT1_DDC_ERROR BIT(7) +#define ADV7511_INT1_BKSV BIT(6) +#define ADV7511_INT1_CEC_TX_READY BIT(5) +#define ADV7511_INT1_CEC_TX_ARBIT_LOST BIT(4) +#define ADV7511_INT1_CEC_TX_RETRY_TIMEOUT BIT(3) +#define ADV7511_INT1_CEC_RX_READY3 BIT(2) +#define ADV7511_INT1_CEC_RX_READY2 BIT(1) +#define ADV7511_INT1_CEC_RX_READY1 BIT(0) + +#define ADV7511_ARC_CTRL_POWER_DOWN BIT(0) + +#define ADV7511_CEC_CTRL_POWER_DOWN BIT(0) + +#define ADV7511_POWER_POWER_DOWN BIT(6) + +#define ADV7511_AUDIO_SELECT_I2C 0x0 +#define ADV7511_AUDIO_SELECT_SPDIF 0x1 +#define ADV7511_AUDIO_SELECT_DSD 0x2 +#define ADV7511_AUDIO_SELECT_HBR 0x3 +#define ADV7511_AUDIO_SELECT_DST 0x4 + +#define ADV7511_I2S_SAMPLE_LEN_16 0x2 +#define ADV7511_I2S_SAMPLE_LEN_20 0x3 +#define ADV7511_I2S_SAMPLE_LEN_18 0x4 +#define ADV7511_I2S_SAMPLE_LEN_22 0x5 +#define ADV7511_I2S_SAMPLE_LEN_19 0x8 +#define ADV7511_I2S_SAMPLE_LEN_23 0x9 +#define ADV7511_I2S_SAMPLE_LEN_24 0xb +#define ADV7511_I2S_SAMPLE_LEN_17 0xc +#define ADV7511_I2S_SAMPLE_LEN_21 0xd + +#define ADV7511_SAMPLE_FREQ_44100 0x0 +#define ADV7511_SAMPLE_FREQ_48000 0x2 +#define ADV7511_SAMPLE_FREQ_32000 0x3 +#define ADV7511_SAMPLE_FREQ_88200 0x8 +#define ADV7511_SAMPLE_FREQ_96000 0xa +#define ADV7511_SAMPLE_FREQ_176400 0xc +#define ADV7511_SAMPLE_FREQ_192000 0xe + +#define ADV7511_STATUS_POWER_DOWN_POLARITY BIT(7) +#define ADV7511_STATUS_HPD BIT(6) +#define ADV7511_STATUS_MONITOR_SENSE BIT(5) +#define ADV7511_STATUS_I2S_32BIT_MODE BIT(3) + +#define ADV7511_PACKET_ENABLE_N_CTS BIT(8+6) +#define ADV7511_PACKET_ENABLE_AUDIO_SAMPLE BIT(8+5) +#define ADV7511_PACKET_ENABLE_AVI_INFOFRAME BIT(8+4) +#define ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME BIT(8+3) +#define ADV7511_PACKET_ENABLE_GC BIT(7) +#define ADV7511_PACKET_ENABLE_SPD BIT(6) +#define ADV7511_PACKET_ENABLE_MPEG BIT(5) +#define ADV7511_PACKET_ENABLE_ACP BIT(4) +#define ADV7511_PACKET_ENABLE_ISRC BIT(3) +#define ADV7511_PACKET_ENABLE_GM BIT(2) +#define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) +#define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) + +#define ADV7511_REG_POWER2_HDP_SRC_MASK 0xc0 +#define ADV7511_REG_POWER2_HDP_SRC_BOTH 0x00 +#define ADV7511_REG_POWER2_HDP_SRC_HDP 0x40 +#define ADV7511_REG_POWER2_HDP_SRC_CEC 0x80 +#define ADV7511_REG_POWER2_HDP_SRC_NONE 0xc0 +#define ADV7511_REG_POWER2_TDMS_ENABLE BIT(4) +#define ADV7511_REG_POWER2_GATE_INPUT_CLK BIT(0) + +#define ADV7511_LOW_REFRESH_RATE_NONE 0x0 +#define ADV7511_LOW_REFRESH_RATE_24HZ 0x1 +#define ADV7511_LOW_REFRESH_RATE_25HZ 0x2 +#define ADV7511_LOW_REFRESH_RATE_30HZ 0x3 + +#define ADV7511_AUDIO_CFG3_LEN_MASK 0x0f +#define ADV7511_I2C_FREQ_ID_CFG_RATE_MASK 0xf0 + +#define ADV7511_AUDIO_SOURCE_I2S 0 +#define ADV7511_AUDIO_SOURCE_SPDIF 1 + +#define ADV7511_I2S_FORMAT_I2S 0 +#define ADV7511_I2S_FORMAT_RIGHT_J 1 +#define ADV7511_I2S_FORMAT_LEFT_J 2 + +#define ADV7511_PACKET(p, x) ((p) * 0x20 + (x)) +#define ADV7511_PACKET_SDP(x) ADV7511_PACKET(0, x) +#define ADV7511_PACKET_MPEG(x) ADV7511_PACKET(1, x) +#define ADV7511_PACKET_ACP(x) ADV7511_PACKET(2, x) +#define ADV7511_PACKET_ISRC1(x) ADV7511_PACKET(3, x) +#define ADV7511_PACKET_ISRC2(x) ADV7511_PACKET(4, x) +#define ADV7511_PACKET_GM(x) ADV7511_PACKET(5, x) +#define ADV7511_PACKET_SPARE(x) ADV7511_PACKET(6, x) + +#include <drm/drmP.h> + +struct i2c_client; +struct regmap; +struct adv7511; + +int adv7511_packet_enable(struct adv7511 *adv7511, unsigned int packet); +int adv7511_packet_disable(struct adv7511 *adv7511, unsigned int packet); + +int adv7511_audio_init(struct device *dev); +void adv7511_audio_exit(struct device *dev); + +/** + * enum adv7511_input_style - Selects the input format style + * @ADV7511_INPUT_STYLE1: Use input style 1 + * @ADV7511_INPUT_STYLE2: Use input style 2 + * @ADV7511_INPUT_STYLE3: Use input style 3 + */ +enum adv7511_input_style { + ADV7511_INPUT_STYLE1 = 2, + ADV7511_INPUT_STYLE2 = 1, + ADV7511_INPUT_STYLE3 = 3, +}; + +/** + * enum adv7511_input_id - Selects the input format id + * @ADV7511_INPUT_ID_24BIT_RGB444_YCbCr444: Input pixel format is 24-bit 444 RGB + * or 444 YCbCR with separate syncs + * @ADV7511_INPUT_ID_16_20_24BIT_YCbCr422_SEPARATE_SYNC: FIXME + * @ADV7511_INPUT_ID_16_20_24BIT_YCbCr422_EMBEDDED_SYNC: FIXME + * @ADV7511_INPUT_ID_8_10_12BIT_YCbCr422_SEPARATE_SYNC: FIXME + * @ADV7511_INPUT_ID_8_10_12BIT_YCbCr422_EMBEDDED_SYNC: FIXME + * @ADV7511_INPUT_ID_12_15_16BIT_RGB444_YCbCr444: FIXME + */ +enum adv7511_input_id { + ADV7511_INPUT_ID_24BIT_RGB444_YCbCr444 = 0, + ADV7511_INPUT_ID_16_20_24BIT_YCbCr422_SEPARATE_SYNC = 1, + ADV7511_INPUT_ID_16_20_24BIT_YCbCr422_EMBEDDED_SYNC = 2, + ADV7511_INPUT_ID_8_10_12BIT_YCbCr422_SEPARATE_SYNC = 3, + ADV7511_INPUT_ID_8_10_12BIT_YCbCr422_EMBEDDED_SYNC = 4, + ADV7511_INPUT_ID_12_15_16BIT_RGB444_YCbCr444 = 5, +}; + +/** + * enum adv7511_input_bit_justifiction - Selects the input format bit + * justifiction + * @ADV7511_INPUT_BIT_JUSTIFICATION_EVENLY: Input bits are evenly distributed + * @ADV7511_INPUT_BIT_JUSTIFICATION_RIGHT: Input bit signals have right + * justification + * @ADV7511_INPUT_BIT_JUSTIFICATION_LEFT: Input bit signals have left + * justification + */ +enum adv7511_input_bit_justifiction { + ADV7511_INPUT_BIT_JUSTIFICATION_EVENLY = 0, + ADV7511_INPUT_BIT_JUSTIFICATION_RIGHT = 1, + ADV7511_INPUT_BIT_JUSTIFICATION_LEFT = 2, +}; + +/** + * enum adv7511_input_color_depth - Selects the input format color depth + * @ADV7511_INPUT_COLOR_DEPTH_8BIT: Input format color depth is 8 bits per + * channel + * @ADV7511_INPUT_COLOR_DEPTH_10BIT: Input format color dpeth is 10 bits per + * channel + * @ADV7511_INPUT_COLOR_DEPTH_12BIT: Input format color depth is 12 bits per + * channel + */ +enum adv7511_input_color_depth { + ADV7511_INPUT_COLOR_DEPTH_8BIT = 3, + ADV7511_INPUT_COLOR_DEPTH_10BIT = 1, + ADV7511_INPUT_COLOR_DEPTH_12BIT = 2, +}; + +/** + * enum adv7511_input_sync_pulse - Selects the sync pulse + * @ADV7511_INPUT_SYNC_PULSE_DE: Use the DE signal as sync pulse + * @ADV7511_INPUT_SYNC_PULSE_HSYNC: Use the HSYNC signal as sync pulse + * @ADV7511_INPUT_SYNC_PULSE_VSYNC: Use the VSYNC signal as sync pulse + * @ADV7511_INPUT_SYNC_PULSE_NONE: No external sync pulse signal + */ +enum adv7511_input_sync_pulse { + ADV7511_INPUT_SYNC_PULSE_DE = 0, + ADV7511_INPUT_SYNC_PULSE_HSYNC = 1, + ADV7511_INPUT_SYNC_PULSE_VSYNC = 2, + ADV7511_INPUT_SYNC_PULSE_NONE = 3, +}; + +/** + * enum adv7511_input_clock_delay - Delay for the video data input clock + * @ADV7511_INPUT_CLOCK_DELAY_MINUS_1200PS: -1200 pico seconds delay + * @ADV7511_INPUT_CLOCK_DELAY_MINUS_800PS: -800 pico seconds delay + * @ADV7511_INPUT_CLOCK_DELAY_MINUS_400PS: -400 pico seconds delay + * @ADV7511_INPUT_CLOCK_DELAY_NONE: No delay + * @ADV7511_INPUT_CLOCK_DELAY_PLUS_400PS: 400 pico seconds delay + * @ADV7511_INPUT_CLOCK_DELAY_PLUS_800PS: 800 pico seconds delay + * @ADV7511_INPUT_CLOCK_DELAY_PLUS_1200PS: 1200 pico seconds delay + * @ADV7511_INPUT_CLOCK_DELAY_PLUS_1600PS: 1600 pico seconds delay + */ +enum adv7511_input_clock_delay { + ADV7511_INPUT_CLOCK_DELAY_MINUS_1200PS = 0, + ADV7511_INPUT_CLOCK_DELAY_MINUS_800PS = 1, + ADV7511_INPUT_CLOCK_DELAY_MINUS_400PS = 2, + ADV7511_INPUT_CLOCK_DELAY_NONE = 3, + ADV7511_INPUT_CLOCK_DELAY_PLUS_400PS = 4, + ADV7511_INPUT_CLOCK_DELAY_PLUS_800PS = 5, + ADV7511_INPUT_CLOCK_DELAY_PLUS_1200PS = 6, + ADV7511_INPUT_CLOCK_DELAY_PLUS_1600PS = 7, +}; + +/** + * enum adv7511_sync_polarity - Polarity for the input sync signals + * @ADV7511_SYNC_POLARITY_PASSTHROUGH: Sync polarity matches that of + * the currently configured mode. + * @ADV7511_SYNC_POLARITY_LOW: Sync polarity is low + * @ADV7511_SYNC_POLARITY_HIGH: Sync polarity is high + * + * If the polarity is set to either ADV7511_SYNC_POLARITY_LOW or + * ADV7511_SYNC_POLARITY_HIGH the ADV7511 will internally invert the signal if + * it is required to match the sync polarity setting for the currently selected + * mode. If the polarity is set to ADV7511_SYNC_POLARITY_PASSTHROUGH, + * the ADV7511 will route the signal unchanged, this is useful if the upstream + * graphics core will already generate the sync singals with the correct + * polarity. + */ +enum adv7511_sync_polarity { + ADV7511_SYNC_POLARITY_PASSTHROUGH, + ADV7511_SYNC_POLARITY_LOW, + ADV7511_SYNC_POLARITY_HIGH, +}; + +/** + * enum adv7511_timing_gen_seq - Selects the order in which timing adjustments + * are performed + * @ADV7511_TIMING_GEN_SEQ_SYN_ADJ_FIRST: Sync adjustment first, + * then DE generation + * @ADV7511_TIMING_GEN_SEQ_DE_GEN_FIRST: DE generation first, + * then sync adjustment + * + * This setting is only relevant if both DE generation and sync adjustment are + * active. + */ +enum adv7511_timing_gen_seq { + ADV7511_TIMING_GEN_SEQ_SYN_ADJ_FIRST = 0, + ADV7511_TIMING_GEN_SEQ_DE_GEN_FIRST = 1, +}; + +/** + * enum adv7511_up_conversion - Selects the upscaling conversion method + * @ADV7511_UP_CONVERSION_ZERO_ORDER: Use zero order up conversion + * @ADV7511_UP_CONVERSION_FIRST_ORDER: Use first order up conversion + * + * This used when converting from a 4:2:2 format to a 4:4:4 format. + */ +enum adv7511_up_conversion { + ADV7511_UP_CONVERSION_ZERO_ORDER = 0, + ADV7511_UP_CONVERSION_FIRST_ORDER = 1, +}; + +/** + * struct adv7511_link_config - Describes adv7511 hardware configuration + * @id: Video input format id + * @input_style: Video input format style + * @sync_pulse: Select the sync pulse + * @clock_delay: Clock delay for the input clock + * @reverse_bitorder: Reverse video input signal bitorder + * @bit_justification: Video input format bit justification + * @up_conversion: Selects the upscaling conversion method + * @input_color_depth: Input video format color depth + * @tmds_clock_inversion: Whether to invert the TDMS clock + * @timing_gen_seq: Selects the order in which sync DE generation + * and sync adjustment are performt. + * @vsync_polarity: vsync input signal configuration + * @hsync_polarity: hsync input signal configuration + * @gpio_pd: GPIO controlling the PD (powerdown) pin + */ +struct adv7511_link_config { + enum adv7511_input_id id; + enum adv7511_input_style input_style; + enum adv7511_input_sync_pulse sync_pulse; + enum adv7511_input_clock_delay clock_delay; + bool reverse_bitorder; + enum adv7511_input_bit_justifiction bit_justification; + enum adv7511_up_conversion up_conversion; + enum adv7511_input_color_depth input_color_depth; + bool tmds_clock_inversion; + enum adv7511_timing_gen_seq timing_gen_seq; + + enum adv7511_sync_polarity vsync_polarity; + enum adv7511_sync_polarity hsync_polarity; + + int gpio_pd; +}; + +/* + * adi,input-style = 1|2|3; + * adi,input-id = + * "24-bit-rgb444-ycbcr444", + * "16-20-24-bit-ycbcr422-separate-sync" | + * "16-20-24-bit-ycbcr422-embedded-sync" | + * "8-10-12-bit-ycbcr422-separate-sync" | + * "8-10-12-bit-ycbcr422-embedded-sync" | + * "12-15-16-bit-rgb444-ycbcr444" + * adi,sync-pulse = "de","vsync","hsync","none" + * adi,clock-delay = -1200|-800|-400|0|400|800|1200|1600 + * adi,reverse-bitorder + * adi,bit-justification = "left"|"right"|"evently"; + * adi,up-conversion = "zero-order"|"first-order" + * adi,input-color-depth = 8|10|12 + * adi,tdms-clock-inversion + * adi,vsync-polarity = "low"|"high"|"passthrough" + * adi,hsync-polarity = "low"|"high"|"passtrhough" + * adi,timing-gen-seq = "sync-adjustment-first"|"de-generation-first" + */ + +/** + * enum adv7511_csc_scaling - Scaling factor for the ADV7511 CSC + * @ADV7511_CSC_SCALING_1: CSC results are not scaled + * @ADV7511_CSC_SCALING_2: CSC results are scaled by a factor of two + * @ADV7511_CSC_SCALING_4: CSC results are scalled by a factor of four + */ +enum adv7511_csc_scaling { + ADV7511_CSC_SCALING_1 = 0, + ADV7511_CSC_SCALING_2 = 1, + ADV7511_CSC_SCALING_4 = 2, +}; + +/** + * struct adv7511_video_config - Describes adv7511 hardware configuration + * @csc_enable: Whether to enable color space conversion + * @csc_scaling_factor: Color space conversion scaling factor + * @csc_coefficents: Color space conversion coefficents + * @hdmi_mode: Whether to use HDMI or DVI output mode + * @avi_infoframe: HDMI infoframe + */ +struct adv7511_video_config { + bool csc_enable; + enum adv7511_csc_scaling csc_scaling_factor; + const uint16_t *csc_coefficents; + + bool hdmi_mode; + struct hdmi_avi_infoframe avi_infoframe; +}; + +struct adv7511 { + struct i2c_client *i2c_main; + struct i2c_client *i2c_edid; + struct i2c_client *i2c_packet; + struct i2c_client *i2c_cec; + + struct regmap *regmap; + struct regmap *packet_memory_regmap; + enum drm_connector_status status; + int dpms_mode; + + unsigned int f_tmds; + unsigned int f_audio; + + unsigned int audio_source; + + unsigned int current_edid_segment; + uint8_t edid_buf[256]; + + wait_queue_head_t wq; + struct drm_encoder *encoder; + + bool embedded_sync; + enum adv7511_sync_polarity vsync_polarity; + enum adv7511_sync_polarity hsync_polarity; + + struct edid *edid; + + int gpio_pd; +}; + +struct edid *adv7511_get_edid(struct drm_encoder *encoder); + +#endif /* __DRM_I2C_ADV7511_H__ */ Index: linux-3.12.24-rt38-xilinx/include/linux/amba/bus.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/amba/bus.h 2014-07-20 22:05:50.350064740 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/amba/bus.h 2014-07-20 22:06:39.335256581 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:24 @ #include <linux/resource.h> #include <linux/regulator/consumer.h> -#define AMBA_NR_IRQS 2 +#define AMBA_NR_IRQS 10 #define AMBA_CID 0xb105f00d struct clk; Index: linux-3.12.24-rt38-xilinx/include/linux/amba/xilinx_dma.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/linux/amba/xilinx_dma.h 2014-07-20 22:06:39.344256432 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx DMA Engines support header file + * + * Copyright (C) 2010 Xilinx, Inc. All rights reserved. + * + * Based on the Freescale DMA driver. + * + * Description: + * . Axi CDMA engine, it does transfers between memory and memory, it + * only has one channel. + * . Axi DMA engine, it does transfers between memory and device. It can be + * configured to have one channel or two channels. If configured as two + * channels, one is to transmit to device and another is to receive from + * device. + * . Axi VDMA engine, it does transfers between memory and video devices. + * It can be configured to have one channel or two channels. If configured + * as two channels, one is to transmit to the video device and another is + * to receive from the video device. + * + * This 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 __DMA_XILINX_DMA_H +#define __DMA_XILINX_DMA_H + +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> + +/* Specific hardware configuration-related constants */ +#define XILINX_DMA_NO_CHANGE 0xFFFF; + +/* DMA IP masks */ +#define XILINX_DMA_IP_DMA 0x00100000 /* A DMA IP */ +#define XILINX_DMA_IP_CDMA 0x00200000 /* A Central DMA IP */ +#define XILINX_DMA_IP_VDMA 0x00400000 /* A Video DMA IP */ +#define XILINX_DMA_IP_MASK 0x00700000 /* DMA IP MASK */ + +/* Device Id in the private structure */ +#define XILINX_DMA_DEVICE_ID_SHIFT 28 + +/* + * Device configuration structure + * + * If used to start/stop parking mode for Xilinx VDMA, vsize must be -1 + * If used to set interrupt coalescing and delay counter only for + * Xilinx VDMA, hsize must be -1 + */ +struct xilinx_vdma_config { + int reserved; /* Not used */ + int vsize; /* Vertical size */ + int hsize; /* Horizontal size */ + int stride; /* Stride */ + int frm_dly; /* Frame delay */ + int gen_lock; /* Whether in gen-lock mode */ + int master; /* Master that it syncs to */ + int frm_cnt_en; /* Enable frame count enable */ + int park; /* Whether wants to park */ + int park_frm; /* Frame to park on */ + int coalesc; /* Interrupt coalescing threshold */ + int delay; /* Delay counter */ + int reset; /* Reset Channel */ + int ext_fsync; /* External Frame Sync */ +}; + +/* Device configuration structure for DMA */ +struct xilinx_dma_config { + enum dma_transfer_direction direction; + /* Channel direction */ + int coalesc; /* Interrupt coalescing threshold */ + int delay; /* Delay counter */ + int reset; /* Reset Channel */ +}; + +/* Device configuration structure for CDMA */ +struct xilinx_cdma_config { + enum dma_transfer_direction direction; + /* Channel direction */ + int coalesc; /* Interrupt coalescing threshold */ + int delay; /* Delay counter */ + int reset; /* Reset Channel */ +}; + +#endif Index: linux-3.12.24-rt38-xilinx/include/linux/clk/zynq.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/clk/zynq.h 2014-07-20 22:05:50.347064789 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/clk/zynq.h 2014-07-20 22:06:39.358256202 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:25 @ #include <linux/spinlock.h> +extern unsigned int zynq_clk_suspended; + +int zynq_clk_suspend_early(void); +void zynq_clk_resume_late(void); +void zynq_clk_topswitch_enable(void); +void zynq_clk_topswitch_disable(void); void zynq_clock_init(void __iomem *slcr); struct clk *clk_register_zynq_pll(const char *name, const char *parent, Index: linux-3.12.24-rt38-xilinx/include/linux/clk.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/clk.h 2014-07-20 22:05:50.349064756 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/clk.h 2014-07-20 22:06:39.369256020 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:227 @ /** - * clk_round_rate - adjust a rate to the exact rate a clock can provide + * clk_round_rate - round a rate to the exact rate a clock can provide not + * exceeding @rate * @clk: clock source * @rate: desired clock rate in Hz * - * Returns rounded clock rate in Hz, or negative errno. + * Returns rounded clock rate in Hz, or parent rate */ long clk_round_rate(struct clk *clk, unsigned long rate); /** + * clk_round_rate_nearest - round a rate to the exact rate a clock can provide + * @clk: the clk for which we are rounding a rate + * @rate: the rate which is to be rounded + * + * Returns rounded clock rate in Hz, or parent rate + */ +long clk_round_rate_nearest(struct clk *clk, unsigned long rate); + +/** * clk_set_rate - set the clock rate for a clock source * @clk: clock source * @rate: desired clock rate in Hz Index: linux-3.12.24-rt38-xilinx/include/linux/i2c/si570.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/linux/i2c/si570.h 2014-07-20 22:06:39.382255806 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * si570.h - Configuration for si570 misc driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License only). + * + * 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 __LINUX_SI570_H +#define __LINUX_SI570_H + +#include <linux/types.h> +#include <linux/device.h> +#include <linux/i2c.h> + +struct si570_platform_data { + u64 factory_fout; /* Factory default output frequency */ + unsigned long initial_fout; /* Requested initial frequency */ +}; + +int get_frequency_si570(struct device *dev, unsigned long *freq); +int set_frequency_si570(struct device *dev, unsigned long freq); +int reset_si570(struct device *dev, int id); +struct i2c_client *get_i2c_client_si570(void); + +#endif /* __LINUX_SI570_H */ Index: linux-3.12.24-rt38-xilinx/include/linux/irqchip/arm-gic.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/irqchip/arm-gic.h 2014-07-20 22:05:50.343064855 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/irqchip/arm-gic.h 2014-07-20 22:06:39.394255608 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:70 @ u32 offset, struct device_node *); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); void gic_cpu_if_down(void); +void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); + +void gic_set_cpu(unsigned int cpu, unsigned int irq); static inline void gic_init(unsigned int nr, int start, void __iomem *dist , void __iomem *cpu) Index: linux-3.12.24-rt38-xilinx/include/linux/memory/zynq-smc.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/linux/memory/zynq-smc.h 2014-07-20 22:06:39.406255410 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx Zynq SMC Driver Header + * + * Copyright (C) 2012 Xilinx, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_MEMORY_ZYNQ_SMC_H +#define __LINUX_MEMORY_ZYNQ_SMC_H + +enum xsmcps_ecc_mode { + XSMCPS_ECCMODE_BYPASS = 0, + XSMCPS_ECCMODE_APB = 1, + XSMCPS_ECCMODE_MEM = 2 +}; + +u32 xsmcps_get_ecc_val(int ecc_reg); +int xsmcps_ecc_is_busy(void); +int xsmcps_get_nand_int_status_raw(void); +void xsmcps_clr_nand_int(void); +int xsmcps_set_ecc_mode(enum xsmcps_ecc_mode mode); +int xsmcps_set_ecc_pg_size(unsigned int pg_sz); + +#endif Index: linux-3.12.24-rt38-xilinx/include/linux/remoteproc.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/remoteproc.h 2014-07-20 22:05:50.346064806 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/remoteproc.h 2014-07-20 22:06:39.416255245 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:118 @ RSC_DEVMEM = 1, RSC_TRACE = 2, RSC_VDEV = 3, - RSC_LAST = 4, + RSC_MMU = 4, + RSC_LAST = 5, }; #define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF) Index: linux-3.12.24-rt38-xilinx/include/linux/rpmsg.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/rpmsg.h 2014-07-20 22:05:50.342064872 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/rpmsg.h 2014-07-20 22:06:39.438254882 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:332 @ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); } +int get_virtproc_id(struct virtproc_info *vrp); +struct rpmsg_channel *rpmsg_create_channel(int vrp_id, const char *name, + int src, int dst); + #endif /* _LINUX_RPMSG_H */ Index: linux-3.12.24-rt38-xilinx/include/linux/rpmsg_omx.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/linux/rpmsg_omx.h 2014-07-20 22:06:39.446254750 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * OMX offloading remote processor driver + * + * Copyright(c) 2011 Texas Instruments. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Texas Instruments nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RPMSG_OMX_H +#define RPMSG_OMX_H + +#include <linux/ioctl.h> + +#define OMX_IOC_MAGIC 'X' + +#define OMX_IOCCONNECT _IOW(OMX_IOC_MAGIC, 1, char *) + +#define OMX_IOC_MAXNR (1) + +#ifdef __KERNEL__ + +/** + * enum omx_msg_types - various message types currently supported + * + * @OMX_CONN_REQ: a connection request message type. the message should carry + * the name of the OMX service which we try to connect to. An instance of + * that service will be created remotely, and its address will be sent as + * a reply. + * + * @OMX_CONN_RSP: a response to a connection request. the message will carry + * an error code (success/failure), and if connection established successfully, + * the addr field will carry the address of the newly created OMX instance. + * + * @OMX_DISCONNECT: disconnect remote OMX instance. this message tells + * remote processor to release the resources coupled with this connection + * + * @OMX_RAW_MSG: a message that should be propagated as-is to the user. + * this would immediately enable user space development to start. + * as we progress, most likely this message won't be needed anymore. + */ +enum omx_msg_types { + OMX_CONN_REQ = 0, + OMX_CONN_RSP = 1, + OMX_DISCONNECT = 4, + OMX_RAW_MSG = 5, + /* todo: do we need a disconnect response ? ION refcounts should allow + * asynchronous release of relevant buffers */ +}; + +/** + * enum omx_error_codes - various error codes that will be used + * + * @OMX_SUCCESS: success + * + * @OMX_NOTSUPP: not supported + * + * @OMX_NOMEM: remote processor is out of memory + */ +enum omx_error_codes { + OMX_SUCCESS = 0, + OMX_NOTSUPP = 1, + OMX_NOMEM = 2, +}; + +/* keep documenting... */ +enum omx_state { + OMX_UNCONNECTED, + OMX_CONNECTED, + OMX_FAIL, +}; + +/** + * struct omx_msg_hdr - common header for all OMX messages + * @type: type of message, see enum omx_msg_types + * @flags: currently unused, should be zero + * @len: length of msg payload (in bytes) + * @data: the msg payload (depends on the message type) + * + * All OMX messages will start with this common header (which will begin + * right after the standard rpmsg header ends). + */ +struct omx_msg_hdr { + u32 type; + u32 flags; + u32 len; + char data[0]; +} __packed; + +struct omx_conn_rsp { + u32 status; + u32 addr; +} __packed; + +struct omx_disc_req { + u32 addr; +} __packed; + + +#endif /* __KERNEL__ */ + +/* temporarily exposed to user space too */ +struct omx_conn_req { + char name[48]; +} __packed; + +#endif /* RPMSG_OMX_H */ Index: linux-3.12.24-rt38-xilinx/include/linux/socket.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/socket.h 2014-07-20 22:05:50.344064839 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/socket.h 2014-07-20 22:06:39.455254601 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:183 @ #define AF_ALG 38 /* Algorithm sockets */ #define AF_NFC 39 /* NFC sockets */ #define AF_VSOCK 40 /* vSockets */ -#define AF_MAX 41 /* For now.. */ +#define AF_RPMSG 41 /* Remote-processor messaging */ +#define AF_MAX 42 /* For now.. */ /* Protocol families, same as address families. */ #define PF_UNSPEC AF_UNSPEC @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:230 @ #define PF_NFC AF_NFC #define PF_VSOCK AF_VSOCK #define PF_MAX AF_MAX +#define PF_RPMSG AF_RPMSG /* Maximum queue length specifiable by listen. */ #define SOMAXCONN 128 Index: linux-3.12.24-rt38-xilinx/include/linux/spi/spi.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/spi/spi.h 2014-07-20 22:05:50.341064888 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/spi/spi.h 2014-07-20 22:06:39.592252342 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:333 @ #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */ #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */ #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ +#define SPI_MASTER_U_PAGE BIT(3) /* select upper flash */ +#define SPI_MASTER_QUAD_MODE BIT(4) /* support quad mode */ /* lock and mutex for SPI bus locking */ spinlock_t bus_lock_spinlock; Index: linux-3.12.24-rt38-xilinx/include/linux/usb/c67x00.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/linux/usb/c67x00.h 2014-07-20 22:05:50.348064773 +0200 +++ linux-3.12.24-rt38-xilinx/include/linux/usb/c67x00.h 2014-07-20 22:06:39.606252111 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:44 @ #define C67X00_SIE2_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 4) struct c67x00_platform_data { - int sie_config; /* SIEs config (C67X00_SIEx_*) */ - unsigned long hpi_regstep; /* Step between HPI registers */ + u32 sie_config; /* SIEs config (C67X00_SIEx_*) */ + u32 hpi_regstep; /* Step between HPI registers */ }; #endif /* _LINUX_USB_C67X00_H */ Index: linux-3.12.24-rt38-xilinx/include/linux/usb/xilinx_usbps_otg.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/linux/usb/xilinx_usbps_otg.h 2014-07-20 22:06:39.616251946 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx PS USB OTG Driver Header file. + * + * Copyright 2011 Xilinx, Inc. + * + * This file is based on langwell_otg.h file with few minor modifications + * to support Xilinx PS USB controller. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __XILINX_XUSBPS_OTG_H +#define __XILINX_XUSBPS_OTG_H + +#define CI_USBCMD 0x140 +# define USBCMD_RST BIT(1) +# define USBCMD_RS BIT(0) +#define CI_USBSTS 0x144 +# define USBSTS_SLI BIT(8) +# define USBSTS_URI BIT(6) +# define USBSTS_PCI BIT(2) +#define CI_PORTSC1 0x184 +# define PORTSC_PP BIT(12) +# define PORTSC_LS (BIT(11) | BIT(10)) +# define PORTSC_SUSP BIT(7) +# define PORTSC_CCS BIT(0) +#define CI_OTGSC 0x1a4 +# define OTGSC_DPIE BIT(30) +# define OTGSC_1MSE BIT(29) +# define OTGSC_BSEIE BIT(28) +# define OTGSC_BSVIE BIT(27) +# define OTGSC_ASVIE BIT(26) +# define OTGSC_AVVIE BIT(25) +# define OTGSC_IDIE BIT(24) +# define OTGSC_DPIS BIT(22) +# define OTGSC_1MSS BIT(21) +# define OTGSC_BSEIS BIT(20) +# define OTGSC_BSVIS BIT(19) +# define OTGSC_ASVIS BIT(18) +# define OTGSC_AVVIS BIT(17) +# define OTGSC_IDIS BIT(16) +# define OTGSC_DPS BIT(14) +# define OTGSC_1MST BIT(13) +# define OTGSC_BSE BIT(12) +# define OTGSC_BSV BIT(11) +# define OTGSC_ASV BIT(10) +# define OTGSC_AVV BIT(9) +# define OTGSC_ID BIT(8) +# define OTGSC_HABA BIT(7) +# define OTGSC_HADP BIT(6) +# define OTGSC_IDPU BIT(5) +# define OTGSC_DP BIT(4) +# define OTGSC_OT BIT(3) +# define OTGSC_HAAR BIT(2) +# define OTGSC_VC BIT(1) +# define OTGSC_VD BIT(0) +# define OTGSC_INTEN_MASK (0x7f << 24) +# define OTGSC_INT_MASK (0x5f << 24) +# define OTGSC_INTSTS_MASK (0x7f << 16) +#define CI_USBMODE 0x1a8 +# define USBMODE_CM (BIT(1) | BIT(0)) +# define USBMODE_IDLE 0 +# define USBMODE_DEVICE 0x2 +# define USBMODE_HOST 0x3 + +#define INTR_DUMMY_MASK (USBSTS_SLI | USBSTS_URI | USBSTS_PCI) + +enum xusbps_otg_timer_type { + TA_WAIT_VRISE_TMR, + TA_WAIT_BCON_TMR, + TA_AIDL_BDIS_TMR, + TB_ASE0_BRST_TMR, + TB_SE0_SRP_TMR, + TB_SRP_INIT_TMR, + TB_SRP_FAIL_TMR, + TB_BUS_SUSPEND_TMR +}; + +#define TA_WAIT_VRISE 100 +#define TA_WAIT_BCON 30000 +#define TA_AIDL_BDIS 15000 +#define TB_ASE0_BRST 5000 +#define TB_SE0_SRP 2 +#define TB_SRP_INIT 100 +#define TB_SRP_FAIL 5500 +#define TB_BUS_SUSPEND 500 + +struct xusbps_otg_timer { + unsigned long expires; /* Number of count increase to timeout */ + unsigned long count; /* Tick counter */ + void (*function)(unsigned long); /* Timeout function */ + unsigned long data; /* Data passed to function */ + struct list_head list; +}; + +/* This is a common data structure to + * save values of the OTG state machine */ +struct otg_hsm { + /* Input */ + int a_bus_resume; + int a_bus_suspend; + int a_conn; + int a_sess_vld; + int a_srp_det; + int a_vbus_vld; + int b_bus_resume; + int b_bus_suspend; + int b_conn; + int b_se0_srp; + int b_ssend_srp; + int b_sess_end; + int b_sess_vld; + int id; +/* id values */ +#define ID_B 0x05 +#define ID_A 0x04 +#define ID_ACA_C 0x03 +#define ID_ACA_B 0x02 +#define ID_ACA_A 0x01 + int power_up; + int adp_change; + int test_device; + + /* Internal variables */ + int a_set_b_hnp_en; + int b_srp_done; + int b_hnp_enable; + int hnp_poll_enable; + + /* Timeout indicator for timers */ + int a_wait_vrise_tmout; + int a_wait_bcon_tmout; + int a_aidl_bdis_tmout; + int a_bidl_adis_tmout; + int a_bidl_adis_tmr; + int a_wait_vfall_tmout; + int b_ase0_brst_tmout; + int b_bus_suspend_tmout; + int b_srp_init_tmout; + int b_srp_fail_tmout; + int b_srp_fail_tmr; + int b_adp_sense_tmout; + + /* Informative variables */ + int a_bus_drop; + int a_bus_req; + int a_clr_err; + int b_bus_req; + int a_suspend_req; + int b_bus_suspend_vld; + + /* Output */ + int drv_vbus; + int loc_conn; + int loc_sof; + + /* Others */ + int vbus_srp_up; +}; + +struct xusbps_otg { + struct usb_phy otg; + struct usb_phy *ulpi; + + struct otg_hsm hsm; + + /* base address */ + void __iomem *base; + + /* irq */ + int irq; + + /* clk */ + struct clk *clk; + struct notifier_block clk_rate_change_nb; + + /* atomic notifier for interrupt context */ + struct atomic_notifier_head otg_notifier; + + /* start/stop USB Host function */ + int (*start_host)(struct usb_phy *otg); + int (*stop_host)(struct usb_phy *otg); + + /* start/stop USB Peripheral function */ + int (*start_peripheral)(struct usb_phy *otg); + int (*stop_peripheral)(struct usb_phy *otg); + + struct device *dev; + + unsigned region; + + struct work_struct work; + struct workqueue_struct *qwork; + struct timer_list hsm_timer; + + spinlock_t lock; + spinlock_t wq_lock; + + struct notifier_block xotg_notifier; +}; + +static inline +struct xusbps_otg *xceiv_to_xotg(struct usb_phy *otg) +{ + return container_of(otg, struct xusbps_otg, otg); +} + +void xusbps_update_transceiver(void); + +#endif /* __XILINX_XUSBPS_OTG_H__ */ Index: linux-3.12.24-rt38-xilinx/include/linux/xilinx_devices.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/linux/xilinx_devices.h 2014-07-20 22:06:39.621251863 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * include/linux/xilinx_devices.h + * + * Definitions for any platform device related flags or structures for + * Xilinx EDK IPs + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002-2005 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is licensed + * "as is" without any warranty of any kind, whether express or implied. + */ + +#ifdef __KERNEL__ +#ifndef _XILINX_DEVICE_H_ +#define _XILINX_DEVICE_H_ + +#include <linux/types.h> +#include <linux/version.h> +#include <linux/platform_device.h> + +/*- PS USB Controller IP -*/ +enum xusbps_usb2_operating_modes { + XUSBPS_USB2_MPH_HOST, + XUSBPS_USB2_DR_HOST, + XUSBPS_USB2_DR_DEVICE, + XUSBPS_USB2_DR_OTG, +}; + +enum xusbps_usb2_phy_modes { + XUSBPS_USB2_PHY_NONE, + XUSBPS_USB2_PHY_ULPI, + XUSBPS_USB2_PHY_UTMI, + XUSBPS_USB2_PHY_UTMI_WIDE, + XUSBPS_USB2_PHY_SERIAL, +}; + +struct clk; +struct platform_device; + +struct xusbps_usb2_platform_data { + /* board specific information */ + enum xusbps_usb2_operating_modes operating_mode; + enum xusbps_usb2_phy_modes phy_mode; + unsigned int port_enables; + unsigned int workaround; + + int (*init)(struct platform_device *); + void (*exit)(struct platform_device *); + void __iomem *regs; /* ioremap'd register base */ + struct usb_phy *otg; + struct usb_phy *ulpi; + int irq; + struct clk *clk; + struct notifier_block clk_rate_change_nb; + unsigned big_endian_mmio:1; + unsigned big_endian_desc:1; + unsigned es:1; /* need USBMODE:ES */ + unsigned le_setup_buf:1; + unsigned have_sysif_regs:1; + unsigned invert_drvvbus:1; + unsigned invert_pwr_fault:1; +}; + +#define XUSBPS_USB2_PORT0_ENABLED 0x00000001 +#define XUSBPS_USB2_PORT1_ENABLED 0x00000002 + +#endif /* _XILINX_DEVICE_H_ */ +#endif /* __KERNEL__ */ Index: linux-3.12.24-rt38-xilinx/include/linux/xylonfb.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/linux/xylonfb.h 2014-07-20 22:06:39.627251765 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver IOCTL parameters + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __XYLON_FB_H__ +#define __XYLON_FB_H__ + + +#include <linux/types.h> + + +struct xylonfb_layer_color { + __u32 raw_rgb; + __u8 use_raw; + __u8 r; + __u8 g; + __u8 b; +}; + +struct xylonfb_layer_pos_size { + __u16 x; + __u16 y; + __u16 width; + __u16 height; +}; + +struct xylonfb_hw_access { + __u32 offset; + __u32 value; +}; + +/* XylonFB events */ +#define XYLONFB_EVENT_FBI_UPDATE 0x01 + +/* XylonFB IOCTL's */ +#define XYLONFB_IOW(num, dtype) _IOW('x', num, dtype) +#define XYLONFB_IOR(num, dtype) _IOR('x', num, dtype) +#define XYLONFB_IOWR(num, dtype) _IOWR('x', num, dtype) +#define XYLONFB_IO(num) _IO('x', num) + +#define XYLONFB_GET_LAYER_IDX XYLONFB_IOR(30, unsigned int) +#define XYLONFB_GET_LAYER_ALPHA XYLONFB_IOR(31, unsigned int) +#define XYLONFB_SET_LAYER_ALPHA XYLONFB_IOW(32, unsigned int) +#define XYLONFB_LAYER_COLOR_TRANSP XYLONFB_IOW(33, unsigned int) +#define XYLONFB_GET_LAYER_COLOR_TRANSP \ + XYLONFB_IOR(34, struct xylonfb_layer_color) +#define XYLONFB_SET_LAYER_COLOR_TRANSP \ + XYLONFB_IOW(35, struct xylonfb_layer_color) +#define XYLONFB_GET_LAYER_SIZE_POS \ + XYLONFB_IOR(36, struct xylonfb_layer_pos_size) +#define XYLONFB_SET_LAYER_SIZE_POS \ + XYLONFB_IOW(37, struct xylonfb_layer_pos_size) +#define XYLONFB_GET_LAYER_BUFFER XYLONFB_IOR(38, unsigned int) +#define XYLONFB_SET_LAYER_BUFFER XYLONFB_IOW(39, unsigned int) +#define XYLONFB_GET_LAYER_BUFFER_OFFSET XYLONFB_IOR(40, unsigned int) +#define XYLONFB_GET_LAYER_BUFFERS_NUM XYLONFB_IOR(41, unsigned int) +#define XYLONFB_GET_BACKGROUND_COLOR \ + XYLONFB_IOR(42, struct xylonfb_layer_color) +#define XYLONFB_SET_BACKGROUND_COLOR \ + XYLONFB_IOW(43, struct xylonfb_layer_color) +#define XYLONFB_LAYER_EXT_BUFF_SWITCH XYLONFB_IOW(43, unsigned int) +#define XYLONFB_READ_HW_REG \ + XYLONFB_IOR(44, struct xylonfb_hw_access) +#define XYLONFB_WRITE_HW_REG \ + XYLONFB_IOW(45, struct xylonfb_hw_access) +#define XYLONFB_WAIT_EDID XYLONFB_IOW(46, unsigned int) +#define XYLONFB_GET_EDID XYLONFB_IOR(47, char) + +#endif /* __XYLON_FB_H__ */ Index: linux-3.12.24-rt38-xilinx/include/linux/xylonfb_platform.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/linux/xylonfb_platform.h 2014-07-20 22:06:39.633251666 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xylon logiCVC frame buffer driver platform data structures + * + * Author: Xylon d.o.o. + * e-mail: davor.joja@logicbricks.com + * + * 2013 Xylon d.o.o. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __XYLON_FB_PLATFORM_H__ +#define __XYLON_FB_PLATFORM_H__ + + +#include <linux/types.h> + + +/* Framebuffer driver platform layer structure */ +struct xylonfb_platform_layer_params { + /* Layer memory offset in lines */ + unsigned int offset; + /* Layer buffer memory offset in lines */ + unsigned short buffer_offset; + /* Layer type */ + unsigned char type; + /* Layer bits per pixel */ + unsigned char bpp; + /* Layer alpha mode */ + unsigned char alpha_mode; + /* Layer control flags */ + unsigned char ctrl_flags; +}; + +/* Framebuffer driver platform data structure */ +struct xylonfb_platform_data { + struct xylonfb_platform_layer_params *layer_params; + /* logiCVC video mode */ + char *vmode; + /* logiCVC Control Register value */ + u32 ctrl_reg; + /* Physical starting address of the video memory */ + unsigned long vmem_base_addr; + /* Physical ending address of the video memory */ + unsigned long vmem_high_addr; + /* Layer row stride in pixels */ + unsigned short row_stride; + /* ID of driver supported pixel clock generator */ + unsigned char pixclk_src_id; + /* Number of logiCVC layers */ + unsigned char num_layers; + /* logiCVC layer ID for FB console */ + unsigned char active_layer; + /* Background layer bits per pixel */ + unsigned char bg_layer_bpp; + /* Background layer alpha mode */ + unsigned char bg_layer_alpha_mode; + /* Display interface and color space type */ + /* higher 4 bits: display interface + lower 4 bits: display color space */ + unsigned char display_interface_type; + /* logiCVC specific flags */ + unsigned short flags; +}; + +#endif /* __XYLON_FB_PLATFORM_H__ */ Index: linux-3.12.24-rt38-xilinx/include/media/adv7604.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/media/adv7604.h 2014-07-20 22:05:50.336064971 +0200 +++ linux-3.12.24-rt38-xilinx/include/media/adv7604.h 2014-07-20 22:06:39.645251468 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:81 @ ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE2 = 0x8a, }; +enum adv7604_int1_config { + ADV7604_INT1_CONFIG_OPEN_DRAIN, + ADV7604_INT1_CONFIG_ACTIVE_LOW, + ADV7604_INT1_CONFIG_ACTIVE_HIGH, + ADV7604_INT1_CONFIG_DISABLED, +}; + /* Platform dependent definition */ struct adv7604_platform_data { /* connector - HDMI or DVI? */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:108 @ /* Select output format */ enum adv7604_op_format_sel op_format_sel; + /* Configuration of the INT1 pin */ + enum adv7604_int1_config int1_config; + /* IO register 0x02 */ unsigned alt_gamma:1; unsigned op_656_range:1; Index: linux-3.12.24-rt38-xilinx/include/media/v4l2-hdmi.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/media/v4l2-hdmi.h 2014-07-20 22:06:39.656251286 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * v4l2-hdmi.h - HDMI extensions to the V4L2 API + * + * Copyright 2011 Tandberg Telecom AS. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _V4L2_HDMI_H_ +#define _V4L2_HDMI_H_ + +#ifdef __KERNEL__ +#include <linux/ioctl.h> +#include <linux/videodev2.h> +#else +#include <sys/ioctl.h> +/* + videodev2.h, including patched version from released os + */ +#include "videodev2.h" +#endif + + +/* data[0] == 0 if format is invalid, == 1 if format is valid. */ +#define V4L2_EVENT_FMT_CHANGED (V4L2_EVENT_PRIVATE_START + 0) + +/* data[0] == 0 if EDID was not found, == 1 if EDID was found. + * data[1] == EDID segment that was found. */ +#define V4L2_EVENT_EDID (V4L2_EVENT_PRIVATE_START + 1) + +/* data[0] == cec tx status field */ +#define V4L2_EVENT_CEC_TX (V4L2_EVENT_PRIVATE_START + 2) + +/* data[0] == cec rx status field */ +#define V4L2_EVENT_CEC_RX (V4L2_EVENT_PRIVATE_START + 3) + +/* data[0] == hotplug present or not */ +#define V4L2_EVENT_TX_HOTPLUG (V4L2_EVENT_PRIVATE_START + 4) + +struct v4l2_edid { + __u32 port; + __u32 segment; + __u8 edid[256]; +}; + +struct v4l2_cec_cap { + __u32 logicaldevices; + __u32 reserved[7]; +}; + +struct v4l2_cec_cmd { + __u32 cmd; + __u32 reserved[7]; + union { + struct { + __u32 id; + __u32 enable; + __u32 addr; + } conf; + struct { + __u32 len; + __u8 msg[16]; + __u32 status; + } data; + __u32 raw[8]; + }; +}; + +/* cec commands */ +#define V4L2_CEC_CMD_CONF (0) +#define V4L2_CEC_CMD_TX (1) +#define V4L2_CEC_CMD_RX (2) + +/* cec status field */ +#define V4L2_CEC_TX_STATUS_OK (1 << 0) +#define V4L2_CEC_TX_STATUS_ARB_LOST (1 << 1) +#define V4L2_CEC_TX_STATUS_RETRY_TIMEOUT (1 << 2) +#define V4L2_CEC_RX_STATUS_READY (1 << 0) + +/* ioctls */ + +/* set a new EDID segment for a receiver */ +#define V4L2_S_EDID _IOW('a', 1, struct v4l2_edid) +/* get the CEC capabilities */ +#define V4L2_CEC_CAP _IOR('a', 2, struct v4l2_cec_cap) +/* issue a CEC command */ +#define V4L2_CEC_CMD _IOWR('a', 3, struct v4l2_cec_cmd) +/* request a new EDID segment */ +#define V4L2_REQ_EDID_SEGMENT _IOW('a', 4, int) +/* get a EDID segment */ +#define V4L2_G_EDID _IOWR('a', 5, struct v4l2_edid) + +/* controls */ +#define V4L2_CID_DV_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) +/* hdmi or dvi-d mode */ +#define V4L2_CID_DV_TX_DVI_HDMI_MODE (V4L2_CID_DV_CID_CUSTOM_BASE + 0) +/* audio sample frequency */ +#define V4L2_CID_DV_TX_AUDIO_SAMPLE_FREQ (V4L2_CID_DV_CID_CUSTOM_BASE + 1) +/* audio word length */ +#define V4L2_CID_DV_TX_AUDIO_WORD_LEN (V4L2_CID_DV_CID_CUSTOM_BASE + 2) +/* audio channel count */ +#define V4L2_CID_DV_TX_AUDIO_CH_COUNT (V4L2_CID_DV_CID_CUSTOM_BASE + 3) +/* audio i2s format */ +#define V4L2_CID_DV_TX_AUDIO_I2S_FORMAT (V4L2_CID_DV_CID_CUSTOM_BASE + 4) +/* to be hooked up to events */ +/* hotplug present or not */ +#define V4L2_CID_DV_TX_HOTPLUG (V4L2_CID_DV_CID_CUSTOM_BASE + 5) +/* rx sense */ +#define V4L2_CID_DV_TX_RXSENSE (V4L2_CID_DV_CID_CUSTOM_BASE + 6) +/* edid present */ +#define V4L2_CID_DV_TX_EDID_SEGMENT0_PRESENT (V4L2_CID_DV_CID_CUSTOM_BASE + 7) +/* audio channel mapping - refer to CEA 861D */ +#define V4L2_CID_DV_TX_AUDIO_CH_MAP (V4L2_CID_DV_CID_CUSTOM_BASE + 8) +/* cable detect */ +#define V4L2_CID_DV_CABLE_DETECT (V4L2_CID_DV_CID_CUSTOM_BASE + 9) +/* 5v from source detected */ +#define V4L2_CID_DV_RX_TX_POWER (V4L2_CID_DV_CID_CUSTOM_BASE + 10) +/* dvi-a sync detection */ +#define V4L2_CID_DV_SYNC_DETECT (V4L2_CID_DV_CID_CUSTOM_BASE + 11) +/* analog sampling phase */ +#define V4L2_CID_DV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CID_CUSTOM_BASE + 12) +/* free run color manual */ +#define V4L2_CID_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CID_CUSTOM_BASE + 13) +/* free run color */ +#define V4L2_CID_FREE_RUN_COLOR (V4L2_CID_DV_CID_CUSTOM_BASE + 14) +/* hdmi/dvi-d RGB limited range */ +#define V4L2_CID_RGB_QUANTIZATION_RANGE (V4L2_CID_DV_CID_CUSTOM_BASE + 15) + +/* + * D V P R E S E T V A L U E S + */ +#define V4L2_DV_PRESET_MASK 0xf0000000 + +/* 0x00000000 - 0x000000ff reserved for CEA 861 formats */ +#define V4L2_DV_CEA_861_FORMAT 0x00000000 + +/* 0x10000000 - 0x100000ff reserved for DMT formats */ +#define V4L2_DV_DMT_FORMAT 0x10000000 + +#define V4L2_DV_DMT_640X350P85 (V4L2_DV_DMT_FORMAT + 0x01) +#define V4L2_DV_DMT_640X400P85 (V4L2_DV_DMT_FORMAT + 0x02) +#define V4L2_DV_DMT_720X400P85 (V4L2_DV_DMT_FORMAT + 0x03) +#define V4L2_DV_DMT_640X480P60 (V4L2_DV_DMT_FORMAT + 0x04) +#define V4L2_DV_DMT_640X480P72 (V4L2_DV_DMT_FORMAT + 0x05) +#define V4L2_DV_DMT_640X480P75 (V4L2_DV_DMT_FORMAT + 0x06) +#define V4L2_DV_DMT_640X480P85 (V4L2_DV_DMT_FORMAT + 0x07) +#define V4L2_DV_DMT_800X600P56 (V4L2_DV_DMT_FORMAT + 0x08) +#define V4L2_DV_DMT_800X600P60 (V4L2_DV_DMT_FORMAT + 0x09) +#define V4L2_DV_DMT_800X600P72 (V4L2_DV_DMT_FORMAT + 0x0a) +#define V4L2_DV_DMT_800X600P75 (V4L2_DV_DMT_FORMAT + 0x0b) +#define V4L2_DV_DMT_800X600P85 (V4L2_DV_DMT_FORMAT + 0x0c) +#define V4L2_DV_DMT_800X600P120RB (V4L2_DV_DMT_FORMAT + 0x0d) +#define V4L2_DV_DMT_848X480P60 (V4L2_DV_DMT_FORMAT + 0x0e) +#define V4L2_DV_DMT_1024X768I43 (V4L2_DV_DMT_FORMAT + 0x0f) +#define V4L2_DV_DMT_1024X768P60 (V4L2_DV_DMT_FORMAT + 0x10) +#define V4L2_DV_DMT_1024X768P70 (V4L2_DV_DMT_FORMAT + 0x11) +#define V4L2_DV_DMT_1024X768P75 (V4L2_DV_DMT_FORMAT + 0x12) +#define V4L2_DV_DMT_1024X768P85 (V4L2_DV_DMT_FORMAT + 0x13) +#define V4L2_DV_DMT_1024X768P120RB (V4L2_DV_DMT_FORMAT + 0x14) +#define V4L2_DV_DMT_1152X864P75 (V4L2_DV_DMT_FORMAT + 0x15) +#define V4L2_DV_DMT_1280X768P60RB (V4L2_DV_DMT_FORMAT + 0x16) +#define V4L2_DV_DMT_1280X768P60 (V4L2_DV_DMT_FORMAT + 0x17) +#define V4L2_DV_DMT_1280X768P75 (V4L2_DV_DMT_FORMAT + 0x18) +#define V4L2_DV_DMT_1280X768P85 (V4L2_DV_DMT_FORMAT + 0x19) +#define V4L2_DV_DMT_1280X768P120RB (V4L2_DV_DMT_FORMAT + 0x1a) +#define V4L2_DV_DMT_1280X800P60RB (V4L2_DV_DMT_FORMAT + 0x1b) +#define V4L2_DV_DMT_1280X800P60 (V4L2_DV_DMT_FORMAT + 0x1c) +#define V4L2_DV_DMT_1280X800P75 (V4L2_DV_DMT_FORMAT + 0x1d) +#define V4L2_DV_DMT_1280X800P85 (V4L2_DV_DMT_FORMAT + 0x1e) +#define V4L2_DV_DMT_1280X800P120RB (V4L2_DV_DMT_FORMAT + 0x1f) +#define V4L2_DV_DMT_1280X960P60 (V4L2_DV_DMT_FORMAT + 0x20) +#define V4L2_DV_DMT_1280X960P85 (V4L2_DV_DMT_FORMAT + 0x21) +#define V4L2_DV_DMT_1280X960P120RB (V4L2_DV_DMT_FORMAT + 0x22) +#define V4L2_DV_DMT_1280X1024P60 (V4L2_DV_DMT_FORMAT + 0x23) +#define V4L2_DV_DMT_1280X1024P75 (V4L2_DV_DMT_FORMAT + 0x24) +#define V4L2_DV_DMT_1280X1024P85 (V4L2_DV_DMT_FORMAT + 0x25) +#define V4L2_DV_DMT_1280X1024P120RB (V4L2_DV_DMT_FORMAT + 0x26) +#define V4L2_DV_DMT_1360X768P60 (V4L2_DV_DMT_FORMAT + 0x27) +#define V4L2_DV_DMT_1360X768P120RB (V4L2_DV_DMT_FORMAT + 0x28) +#define V4L2_DV_DMT_1400X1050P60RB (V4L2_DV_DMT_FORMAT + 0x29) +#define V4L2_DV_DMT_1400X1050P60 (V4L2_DV_DMT_FORMAT + 0x2a) +#define V4L2_DV_DMT_1400X1050P75 (V4L2_DV_DMT_FORMAT + 0x2b) +#define V4L2_DV_DMT_1400X1050P85 (V4L2_DV_DMT_FORMAT + 0x2c) +#define V4L2_DV_DMT_1400X1050P120RB (V4L2_DV_DMT_FORMAT + 0x2d) +#define V4L2_DV_DMT_1440X900P60RB (V4L2_DV_DMT_FORMAT + 0x2e) +#define V4L2_DV_DMT_1440X900P60 (V4L2_DV_DMT_FORMAT + 0x2f) +#define V4L2_DV_DMT_1440X900P75 (V4L2_DV_DMT_FORMAT + 0x30) +#define V4L2_DV_DMT_1440X900P85 (V4L2_DV_DMT_FORMAT + 0x31) +#define V4L2_DV_DMT_1440X900P120RB (V4L2_DV_DMT_FORMAT + 0x32) +#define V4L2_DV_DMT_1600X1200P60 (V4L2_DV_DMT_FORMAT + 0x33) +#define V4L2_DV_DMT_1600X1200P65 (V4L2_DV_DMT_FORMAT + 0x34) +#define V4L2_DV_DMT_1600X1200P70 (V4L2_DV_DMT_FORMAT + 0x35) +#define V4L2_DV_DMT_1600X1200P75 (V4L2_DV_DMT_FORMAT + 0x36) +#define V4L2_DV_DMT_1600X1200P85 (V4L2_DV_DMT_FORMAT + 0x37) +#define V4L2_DV_DMT_1600X1200P120RB (V4L2_DV_DMT_FORMAT + 0x38) +#define V4L2_DV_DMT_1680X1050P60RB (V4L2_DV_DMT_FORMAT + 0x39) +#define V4L2_DV_DMT_1680X1050P60 (V4L2_DV_DMT_FORMAT + 0x3a) +#define V4L2_DV_DMT_1680X1050P75 (V4L2_DV_DMT_FORMAT + 0x3b) +#define V4L2_DV_DMT_1680X1050P85 (V4L2_DV_DMT_FORMAT + 0x3c) +#define V4L2_DV_DMT_1680X1050P120RB (V4L2_DV_DMT_FORMAT + 0x3d) +#define V4L2_DV_DMT_1792X1344P60 (V4L2_DV_DMT_FORMAT + 0x3e) +#define V4L2_DV_DMT_1792X1344P75 (V4L2_DV_DMT_FORMAT + 0x3f) +#define V4L2_DV_DMT_1792X1344P120RB (V4L2_DV_DMT_FORMAT + 0x40) +#define V4L2_DV_DMT_1856X1392P60 (V4L2_DV_DMT_FORMAT + 0x41) +#define V4L2_DV_DMT_1856X1392P75 (V4L2_DV_DMT_FORMAT + 0x42) +#define V4L2_DV_DMT_1856X1392P120RB (V4L2_DV_DMT_FORMAT + 0x43) +#define V4L2_DV_DMT_1920X1200P60RB (V4L2_DV_DMT_FORMAT + 0x44) +#define V4L2_DV_DMT_1920X1200P60 (V4L2_DV_DMT_FORMAT + 0x45) +#define V4L2_DV_DMT_1920X1200P75 (V4L2_DV_DMT_FORMAT + 0x46) +#define V4L2_DV_DMT_1920X1200P85 (V4L2_DV_DMT_FORMAT + 0x47) +#define V4L2_DV_DMT_1920X1200P120RB (V4L2_DV_DMT_FORMAT + 0x48) +#define V4L2_DV_DMT_1920X1440P60 (V4L2_DV_DMT_FORMAT + 0x49) +#define V4L2_DV_DMT_1920X1440P75 (V4L2_DV_DMT_FORMAT + 0x4a) +#define V4L2_DV_DMT_1920X1440P120RB (V4L2_DV_DMT_FORMAT + 0x4b) +#define V4L2_DV_DMT_2560X1600P60RB (V4L2_DV_DMT_FORMAT + 0x4c) +#define V4L2_DV_DMT_2560X1600P60 (V4L2_DV_DMT_FORMAT + 0x4d) +#define V4L2_DV_DMT_2560X1600P75 (V4L2_DV_DMT_FORMAT + 0x4e) +#define V4L2_DV_DMT_2560X1600P85 (V4L2_DV_DMT_FORMAT + 0x4f) +#define V4L2_DV_DMT_2560X1600P120RB (V4L2_DV_DMT_FORMAT + 0x50) +#define V4L2_DV_DMT_1366X768P60 (V4L2_DV_DMT_FORMAT + 0x51) +#define V4L2_DV_DMT_1920X1080P60 (V4L2_DV_DMT_FORMAT + 0x52) + +/* CVT format */ +#define V4L2_DV_CVT_FORMAT 0x20000000 +/* GTF format */ +#define V4L2_DV_GTF_FORMAT 0x30000000 +/* Special formats that doesn't follow any standard */ +#define V4L2_DV_SPECIAL_FORMAT 0xe0000000 +/* Error codes */ +#define V4L2_DV_UNSUPPORTED_SIGNAL 0xf0000000 + +#endif Index: linux-3.12.24-rt38-xilinx/include/media/v4l2-of.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/media/v4l2-of.h 2014-07-20 22:05:50.337064954 +0200 +++ linux-3.12.24-rt38-xilinx/include/media/v4l2-of.h 2014-07-20 22:06:39.664251154 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:56 @ * @port: identifier (value of reg property) of a port this endpoint belongs to * @id: identifier (value of reg property) of this endpoint * @local_node: pointer to device_node of this endpoint - * @remote: phandle to remote endpoint node * @bus_type: bus type * @bus: bus configuration data structure * @head: list head for this structure @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:64 @ unsigned int port; unsigned int id; const struct device_node *local_node; - const __be32 *remote; enum v4l2_mbus_type bus_type; union { struct v4l2_of_bus_parallel parallel; @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:72 @ struct list_head head; }; +/** + * struct v4l2_of_link - a link between two endpoints + * @local_node: pointer to device_node of this endpoint + * @local_port: identifier of the port this endpoint belongs to + * @remote_node: pointer to device_node of the remote endpoint + * @remote_port: identifier of the port the remote endpoint belongs to + */ +struct v4l2_of_link { + struct device_node *local_node; + unsigned int local_port; + struct device_node *remote_node; + unsigned int remote_port; +}; + #ifdef CONFIG_OF -void v4l2_of_parse_endpoint(const struct device_node *node, - struct v4l2_of_endpoint *link); +int v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *endpoint); +int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link); +void v4l2_of_put_link(struct v4l2_of_link *link); struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, struct device_node *previous); struct device_node *v4l2_of_get_remote_port_parent( @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:105 @ return -ENOSYS; } +static inline int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link) +{ + return -ENOSYS; +} + +static inline void v4l2_of_put_link(struct v4l2_of_link *link) +{ +} + static inline struct device_node *v4l2_of_get_next_endpoint( const struct device_node *parent, struct device_node *previous) Index: linux-3.12.24-rt38-xilinx/include/net/rpmsg.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/include/net/rpmsg.h 2014-07-20 22:06:39.675250973 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Remote processor messaging sockets + * + * Copyright (C) 2011 Texas Instruments, Inc + * + * Ohad Ben-Cohen <ohad@wizery.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 __NET_RPMSG_H +#define __NET_RPMSG_H + +#include <linux/types.h> +#include <linux/socket.h> + +/* user space needs this */ +#ifndef AF_RPMSG +#define AF_RPMSG 41 +#define PF_RPMSG AF_RPMSG +#endif + +/* Connection and socket states */ +enum { + RPMSG_CONNECTED = 1, /* wait_for_packet() wants this... */ + RPMSG_OPEN, + RPMSG_LISTENING, + RPMSG_CLOSED, +}; + +struct sockaddr_rpmsg { + sa_family_t family; + __u32 vproc_id; + __u32 addr; +}; + +#define RPMSG_LOCALHOST ((__u32) ~0UL) + +#ifdef __KERNEL__ + +#include <net/sock.h> +#include <linux/rpmsg.h> + +struct rpmsg_socket { + struct sock sk; + struct rpmsg_channel *rpdev; + bool unregister_rpdev; +}; + +#endif /* __KERNEL__ */ +#endif /* __NET_RPMSG_H */ Index: linux-3.12.24-rt38-xilinx/include/sound/soc-dai.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/sound/soc-dai.h 2014-07-20 22:05:50.334065004 +0200 +++ linux-3.12.24-rt38-xilinx/include/sound/soc-dai.h 2014-07-20 22:06:39.687250775 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:36 @ #define SND_SOC_DAIFMT_DSP_B 5 /* L data MSB during FRM LRC */ #define SND_SOC_DAIFMT_AC97 6 /* AC97 */ #define SND_SOC_DAIFMT_PDM 7 /* Pulse density modulation */ +#define SND_SOC_DAIFMT_SPDIF 8 /* SPDIF */ /* left and right justified also known as MSB and LSB respectively */ #define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J Index: linux-3.12.24-rt38-xilinx/include/uapi/linux/v4l2-mediabus.h =================================================================== --- linux-3.12.24-rt38-xilinx.orig/include/uapi/linux/v4l2-mediabus.h 2014-07-20 22:05:50.338064938 +0200 +++ linux-3.12.24-rt38-xilinx/include/uapi/linux/v4l2-mediabus.h 2014-07-20 22:06:39.702250527 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:40 @ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_FIXED = 0x0001, - /* RGB - next is 0x100e */ + /* RGB - next is 0x1010 */ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001, V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002, V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:54 @ V4L2_MBUS_FMT_RGB888_2X12_BE = 0x100b, V4L2_MBUS_FMT_RGB888_2X12_LE = 0x100c, V4L2_MBUS_FMT_ARGB8888_1X32 = 0x100d, + V4L2_MBUS_FMT_RBG888_1X24 = 0x100e, + V4L2_MBUS_FMT_RGB888_1X32_PADHI = 0x100f, - /* YUV (including grey) - next is 0x2018 */ + /* YUV (including grey) - next is 0x201a */ V4L2_MBUS_FMT_Y8_1X8 = 0x2001, V4L2_MBUS_FMT_UV8_1X8 = 0x2015, V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002, @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:81 @ V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e, V4L2_MBUS_FMT_YUV10_1X30 = 0x2016, V4L2_MBUS_FMT_AYUV8_1X32 = 0x2017, + V4L2_MBUS_FMT_YUYV10_1X24_PADHI = 0x2018, + V4L2_MBUS_FMT_YUYV12_1X24 = 0x2019, /* Bayer - next is 0x3019 */ V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001, Index: linux-3.12.24-rt38-xilinx/init/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/init/Kconfig 2014-07-20 22:05:50.328065103 +0200 +++ linux-3.12.24-rt38-xilinx/init/Kconfig 2014-07-20 22:10:26.384515092 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:23 @ bool depends on !UML +config CONSTRUCTORS_NAME + string + depends on CONSTRUCTORS + default ".init_array" if ARM && AEABI + default ".ctors" + config IRQ_WORK bool Index: linux-3.12.24-rt38-xilinx/kernel/gcov/Kconfig =================================================================== --- linux-3.12.24-rt38-xilinx.orig/kernel/gcov/Kconfig 2014-07-20 22:05:50.327065119 +0200 +++ linux-3.12.24-rt38-xilinx/kernel/gcov/Kconfig 2014-07-20 22:06:39.736249967 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:38 @ config GCOV_PROFILE_ALL bool "Profile entire Kernel" depends on GCOV_KERNEL - depends on SUPERH || S390 || X86 || PPC || MICROBLAZE + depends on SUPERH || S390 || X86 || PPC || MICROBLAZE || ARM default n ---help--- This options activates profiling for the entire kernel. Index: linux-3.12.24-rt38-xilinx/kernel/module.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/kernel/module.c 2014-07-20 22:05:50.326065136 +0200 +++ linux-3.12.24-rt38-xilinx/kernel/module.c 2014-07-20 22:06:39.759249587 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:2769 @ mod->unused_gpl_crcs = section_addr(info, "__kcrctab_unused_gpl"); #endif #ifdef CONFIG_CONSTRUCTORS - mod->ctors = section_objs(info, ".ctors", + mod->ctors = section_objs(info, CONFIG_CONSTRUCTORS_NAME, sizeof(*mod->ctors), &mod->num_ctors); #endif Index: linux-3.12.24-rt38-xilinx/MAINTAINERS =================================================================== --- linux-3.12.24-rt38-xilinx.orig/MAINTAINERS 2014-07-20 22:05:50.266066126 +0200 +++ linux-3.12.24-rt38-xilinx/MAINTAINERS 2014-07-20 22:06:39.808248779 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1360 @ S: Supported F: arch/arm/mach-zynq/ F: drivers/cpuidle/cpuidle-zynq.c +N: [^a-z]zynq +N: [^a-z]xilinx +F: drivers/clocksource/cadence_ttc_timer.c ARM SMMU DRIVER M: Will Deacon <will.deacon@arm.com> Index: linux-3.12.24-rt38-xilinx/net/Makefile =================================================================== --- linux-3.12.24-rt38-xilinx.orig/net/Makefile 2014-07-20 22:05:50.333065020 +0200 +++ linux-3.12.24-rt38-xilinx/net/Makefile 2014-07-20 22:06:39.914247031 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:73 @ obj-$(CONFIG_NFC) += nfc/ obj-$(CONFIG_OPENVSWITCH) += openvswitch/ obj-$(CONFIG_VSOCKETS) += vmw_vsock/ +obj-$(CONFIG_RPMSG) += rpmsg/ obj-$(CONFIG_NET_MPLS_GSO) += mpls/ Index: linux-3.12.24-rt38-xilinx/net/rpmsg/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/net/rpmsg/Makefile 2014-07-20 22:06:39.925246849 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:1 @ +obj-$(CONFIG_RPMSG) += rpmsg_proto.o Index: linux-3.12.24-rt38-xilinx/net/rpmsg/rpmsg_proto.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/net/rpmsg/rpmsg_proto.c 2014-07-20 22:06:39.935246684 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * AF_RPMSG: Remote processor messaging sockets + * + * Copyright (C) 2011 Texas Instruments, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/skbuff.h> +#include <linux/rwlock_rt.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/rpmsg.h> +#include <net/sock.h> +#include <net/rpmsg.h> +#include <linux/radix-tree.h> + +#define RPMSG_CB(skb) (*(struct sockaddr_rpmsg *)&((skb)->cb)) + +/* + * A two-level radix-tree-based scheme is used to maintain the rpmsg channels + * we're exposing to userland. The first radix tree maps vproc index id + * to its channels, and the second radix tree associates each channel + * with its destination addresses (so sockaddr_rpmsg lookups are quick). + * + * Currently only channels with a valid dst address are supported (aka 'client' + * channels as opposed to 'server' channels which usually only have a valid + * src address). + */ +static RADIX_TREE(rpmsg_channels, GFP_KERNEL); + +/* + * Synchronization of access to the tree is achieved using a mutex, + * because we're using non-atomic radix tree allocations. + */ +static DEFINE_MUTEX(rpmsg_channels_lock); + +static struct proto rpmsg_proto = { + .name = "RPMSG", + .owner = THIS_MODULE, + .obj_size = sizeof(struct rpmsg_socket), +}; + +static int rpmsg_sock_connect(struct socket *sock, struct sockaddr *addr, + int alen, int flags) +{ + struct sock *sk = sock->sk; + struct rpmsg_socket *rpsk; + struct sockaddr_rpmsg *sa; + int err = 0; + struct radix_tree_root *vrp_channels; + struct rpmsg_channel *rpdev; + + pr_debug("sk %p\n", sk); + + if (sk->sk_state != RPMSG_OPEN) + return -EBADFD; + + if (sk->sk_type != SOCK_SEQPACKET) + return -EINVAL; + + if (!addr || addr->sa_family != AF_RPMSG) + return -EINVAL; + + if (alen < sizeof(*sa)) + return -EINVAL; + + sa = (struct sockaddr_rpmsg *) addr; + + lock_sock(sk); + + rpsk = container_of(sk, struct rpmsg_socket, sk); + + mutex_lock(&rpmsg_channels_lock); + + /* find the set of channels exposed by this remote processor */ + vrp_channels = radix_tree_lookup(&rpmsg_channels, sa->vproc_id); + if (!vrp_channels) { + err = -EINVAL; + goto out; + } + + /* find the specific channel we need to connect with */ + rpdev = radix_tree_lookup(vrp_channels, sa->addr); + if (!rpdev) { + err = -EINVAL; + goto out; + } + + rpsk->rpdev = rpdev; + + /* bind this socket with its rpmsg endpoint */ + rpdev->ept->priv = sk; + + /* XXX take care of disconnection state too */ + sk->sk_state = RPMSG_CONNECTED; + +out: + mutex_unlock(&rpmsg_channels_lock); + release_sock(sk); + return err; +} + +static int rpmsg_sock_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + struct rpmsg_socket *rpsk; + char payload[512];/* todo: sane payload length methodology */ + int err; + + pr_debug("sk %p len %d\n", sk, len); + + /* XXX check for sock_error as well ? */ + /* XXX handle noblock ? */ + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + /* no payload ? */ + if (msg->msg_iov->iov_base == NULL) + return -EINVAL; + + lock_sock(sk); + + /* we don't support loopback at this point */ + if (sk->sk_state != RPMSG_CONNECTED) { + release_sock(sk); + return -ENOTCONN; + } + + rpsk = container_of(sk, struct rpmsg_socket, sk); + + /* XXX for now, ignore the peer address. later use it + * with rpmsg_sendto, but only if user is root */ + + err = memcpy_fromiovec(payload, msg->msg_iov, len); + if (err) + goto out; + + /* XXX add length validation */ + err = rpmsg_send(rpsk->rpdev, payload, len); + if (err) + pr_err("rpmsg_send failed: %d\n", err); + +out: + release_sock(sk); + return err; +} + +static int rpmsg_sock_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags) +{ + struct sock *sk = sock->sk; + struct sockaddr_rpmsg *sa; + struct sk_buff *skb; + int noblock = flags & MSG_DONTWAIT; + int ret; + + pr_debug("sk %p len %d\n", sk, len); + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + msg->msg_namelen = 0; + + skb = skb_recv_datagram(sk, flags, noblock, &ret); + if (!skb) + /* check for shutdown ? */ + return ret; + + if (msg->msg_name) { + msg->msg_namelen = sizeof(*sa); + sa = (struct sockaddr_rpmsg *) msg->msg_name; + sa->vproc_id = RPMSG_CB(skb).vproc_id; + sa->addr = RPMSG_CB(skb).addr; + sa->family = AF_RPMSG; + } + + if (len > skb->len) { + len = skb->len; + } else if (len < skb->len) { + pr_warn("user buffer is too small\n"); + /* XXX truncate or error ? */ + msg->msg_flags |= MSG_TRUNC; + } + + ret = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); + if (ret) { + pr_warn("error copying skb data: %d\n", ret); + goto out_free; + } + + ret = len; + +out_free: + skb_free_datagram(sk, skb); + return ret; +} + +static unsigned int rpmsg_sock_poll(struct file *file, struct socket *sock, + poll_table *wait) +{ + struct sock *sk = sock->sk; + unsigned int mask = 0; + + pr_debug("sk %p\n", sk); + + poll_wait(file, sk_sleep(sk), wait); + + /* exceptional events? */ + if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) + mask |= POLLERR; + if (sk->sk_shutdown & RCV_SHUTDOWN) + mask |= POLLRDHUP; + if (sk->sk_shutdown == SHUTDOWN_MASK) + mask |= POLLHUP; + + /* readable? */ + if (!skb_queue_empty(&sk->sk_receive_queue) || + (sk->sk_shutdown & RCV_SHUTDOWN)) + mask |= POLLIN | POLLRDNORM; + + if (sk->sk_state == RPMSG_CLOSED) + mask |= POLLHUP; + + /* + * XXX is writable ? + * this depends on the destination processor. + * if loopback: we're writable unless no memory + * if to remote: we need enabled rpmsg buffer or user supplied bufs + * for now, let's always be writable. + */ + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + + return mask; +} +EXPORT_SYMBOL(rpmsg_sock_poll); + +/* + * return bound socket address information, either local or remote + * note: len is just an output parameter, doesn't carry any input value + */ +static int rpmsg_sock_getname(struct socket *sock, struct sockaddr *addr, + int *len, int peer) +{ + struct sock *sk = sock->sk; + struct rpmsg_socket *rpsk; + struct rpmsg_channel *rpdev; + struct sockaddr_rpmsg *sa; + + pr_debug("sk %p\n", sk); + + rpsk = container_of(sk, struct rpmsg_socket, sk); + rpdev = rpsk->rpdev; + + if (!rpdev) + return -ENOTCONN; + + addr->sa_family = AF_RPMSG; + + sa = (struct sockaddr_rpmsg *) addr; + + *len = sizeof(*sa); + + if (peer) { + sa->vproc_id = get_virtproc_id(rpdev->vrp); + sa->addr = rpdev->dst; + } else { + sa->vproc_id = RPMSG_LOCALHOST; + sa->addr = rpsk->rpdev->src; + } + + return 0; +} + +static int rpmsg_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct rpmsg_socket *rpsk = container_of(sk, struct rpmsg_socket, sk); + + pr_debug("sk %p\n", sk); + + if (!sk) + return 0; + + if (rpsk->unregister_rpdev) + device_unregister(&rpsk->rpdev->dev); + + sock_put(sock->sk); + + return 0; +} + +/* + * Notes: + * - calling connect after bind isn't currently supported (is it even needed ?). + * - userspace arguments to bind aren't intuitive: one needs to provide + * the vproc id of the remote processor he wants the channel to be shared + * with, and the -local- address he wants the channel to be bind with + */ +static int +rpmsg_sock_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +{ + struct sock *sk = sock->sk; + struct rpmsg_socket *rpsk = container_of(sk, struct rpmsg_socket, sk); + struct rpmsg_channel *rpdev; + struct sockaddr_rpmsg *sa = (struct sockaddr_rpmsg *)uaddr; + + pr_debug("sk %p\n", sk); + + if (sock->state == SS_CONNECTED) + return -EINVAL; + + if (addr_len != sizeof(*sa)) + return -EINVAL; + + if (sa->family != AF_RPMSG) + return -EINVAL; + + if (rpsk->rpdev) + return -EBUSY; + + if (sk->sk_state != RPMSG_OPEN) + return -EINVAL; + + rpdev = rpmsg_create_channel(sa->vproc_id, "rpmsg-proto", sa->addr, + RPMSG_ADDR_ANY); + if (!rpdev) + return -EINVAL; + + rpsk->rpdev = rpdev; + rpsk->unregister_rpdev = true; + + /* bind this socket with its rpmsg endpoint */ + rpdev->ept->priv = sk; + + sk->sk_state = RPMSG_LISTENING; + + return 0; +} + +static const struct proto_ops rpmsg_sock_ops = { + .family = PF_RPMSG, + .owner = THIS_MODULE, + + .release = rpmsg_sock_release, + .connect = rpmsg_sock_connect, + .getname = rpmsg_sock_getname, + .sendmsg = rpmsg_sock_sendmsg, + .recvmsg = rpmsg_sock_recvmsg, + .poll = rpmsg_sock_poll, + .bind = rpmsg_sock_bind, + + .listen = sock_no_listen, + .accept = sock_no_accept, + .ioctl = sock_no_ioctl, + .mmap = sock_no_mmap, + .socketpair = sock_no_socketpair, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt +}; + +static void rpmsg_sock_destruct(struct sock *sk) +{ +} + +static int rpmsg_sock_create(struct net *net, struct socket *sock, int proto, + int kern) +{ + struct sock *sk; + + if (sock->type != SOCK_SEQPACKET) + return -ESOCKTNOSUPPORT; + if (proto != 0) + return -EPROTONOSUPPORT; + + sk = sk_alloc(net, PF_RPMSG, GFP_KERNEL, &rpmsg_proto); + if (!sk) + return -ENOMEM; + + pr_debug("sk %p\n", sk); + + sock->state = SS_UNCONNECTED; + sock->ops = &rpmsg_sock_ops; + sock_init_data(sock, sk); + + sk->sk_destruct = rpmsg_sock_destruct; + sk->sk_protocol = proto; + + sk->sk_state = RPMSG_OPEN; + + return 0; +} + +static const struct net_proto_family rpmsg_proto_family = { + .family = PF_RPMSG, + .create = rpmsg_sock_create, + .owner = THIS_MODULE, +}; + +static void __rpmsg_proto_cb(struct device *dev, int from_vproc_id, void *data, + int len, struct sock *sk, u32 src) +{ + struct rpmsg_socket *rpsk = container_of(sk, struct rpmsg_socket, sk); + struct sk_buff *skb; + int ret; + + print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1, + data, len, true); + + lock_sock(sk); + + switch (sk->sk_state) { + case RPMSG_CONNECTED: + if (rpsk->rpdev->dst != src) + dev_warn(dev, "unexpected source address: %d\n", src); + break; + case RPMSG_LISTENING: + /* When an inbound message is received while we're listening, + * we implicitly become connected */ + sk->sk_state = RPMSG_CONNECTED; + rpsk->rpdev->dst = src; + break; + default: + dev_warn(dev, "unexpected inbound message (from %d)\n", src); + break; + } + + skb = sock_alloc_send_skb(sk, len, 1, &ret); + if (!skb) { + dev_err(dev, "sock_alloc_send_skb failed: %d\n", ret); + ret = -ENOMEM; + goto out; + } + + RPMSG_CB(skb).vproc_id = from_vproc_id; + RPMSG_CB(skb).addr = src; + RPMSG_CB(skb).family = AF_RPMSG; + + memcpy(skb_put(skb, len), data, len); + + ret = sock_queue_rcv_skb(sk, skb); + if (ret) { + dev_err(dev, "sock_queue_rcv_skb failed: %d\n", ret); + kfree_skb(skb); + } + +out: + release_sock(sk); +} + +static void rpmsg_proto_cb(struct rpmsg_channel *rpdev, void *data, int len, + void *priv, u32 src) +{ + int id = get_virtproc_id(rpdev->vrp); + + __rpmsg_proto_cb(&rpdev->dev, id, data, len, priv, src); +} + +/* every channel we're probed with is exposed to userland via the Socket API */ +static int rpmsg_proto_probe(struct rpmsg_channel *rpdev) +{ + struct device *dev = &rpdev->dev; + int ret, dst = rpdev->dst, id; + struct radix_tree_root *vrp_channels; + + if (dst == RPMSG_ADDR_ANY) + return 0; + + id = get_virtproc_id(rpdev->vrp); + + mutex_lock(&rpmsg_channels_lock); + + /* are we exposing channels for this remote processor yet ? */ + vrp_channels = radix_tree_lookup(&rpmsg_channels, id); + /* not yet ? let's prepare the 2nd radix tree level then */ + if (!vrp_channels) { + vrp_channels = kzalloc(sizeof(*vrp_channels), GFP_KERNEL); + INIT_RADIX_TREE(vrp_channels, GFP_KERNEL); + /* now let's associate the new channel with its vrp */ + ret = radix_tree_insert(&rpmsg_channels, id, vrp_channels); + if (ret) { + dev_err(dev, "radix_tree_insert failed: %d\n", ret); + kfree(vrp_channels); + return ret; + } + } + + /* let's associate the new channel with its dst */ + ret = radix_tree_insert(vrp_channels, dst, rpdev); + if (ret) + dev_err(dev, "failed to add rpmsg addr %d: %d\n", dst, ret); + + mutex_unlock(&rpmsg_channels_lock); + + return ret; +} + +static void rpmsg_proto_remove(struct rpmsg_channel *rpdev) +{ + struct device *dev = &rpdev->dev; + int id, dst = rpdev->dst; + struct radix_tree_root *vrp_channels; + + if (dst == RPMSG_ADDR_ANY) + return; + + id = get_virtproc_id(rpdev->vrp); + + mutex_lock(&rpmsg_channels_lock); + + vrp_channels = radix_tree_lookup(&rpmsg_channels, id); + if (!vrp_channels) { + dev_err(dev, "can't find channels for this vrp: %d\n", id); + goto out; + } + + if (!radix_tree_delete(vrp_channels, dst)) + dev_err(dev, "failed to delete rpmsg %d\n", dst); + +out: + mutex_unlock(&rpmsg_channels_lock); +} + +static struct rpmsg_device_id rpmsg_proto_id_table[] = { + { .name = "rpmsg-proto" }, + { }, +}; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_proto_id_table); + +static struct rpmsg_driver rpmsg_proto_drv = { + .drv.name = KBUILD_MODNAME, + .drv.owner = THIS_MODULE, + .id_table = rpmsg_proto_id_table, + .probe = rpmsg_proto_probe, + .callback = rpmsg_proto_cb, + .remove = rpmsg_proto_remove, +}; + +int __init rpmsg_proto_init(void) +{ + int ret; + + ret = proto_register(&rpmsg_proto, 0); + if (ret) { + pr_err("proto_register failed: %d\n", ret); + return ret; + } + + ret = sock_register(&rpmsg_proto_family); + if (ret) { + pr_err("sock_register failed: %d\n", ret); + goto proto_unreg; + } + + /* gimme rpmsg channels to expose ! */ + ret = register_rpmsg_driver(&rpmsg_proto_drv); + if (ret) { + pr_err("register_rpmsg_driver failed: %d\n", ret); + goto sock_unreg; + } + + return 0; + +sock_unreg: + sock_unregister(PF_RPMSG); +proto_unreg: + proto_unregister(&rpmsg_proto); + return ret; +} + +void __exit rpmsg_proto_exit(void) +{ + unregister_rpmsg_driver(&rpmsg_proto_drv); + sock_unregister(PF_RPMSG); + proto_unregister(&rpmsg_proto); +} + +module_init(rpmsg_proto_init); +module_exit(rpmsg_proto_exit); + +MODULE_DESCRIPTION("Remote processor messaging protocol"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_NETPROTO(AF_RPMSG); Index: linux-3.12.24-rt38-xilinx/samples/xilinx_apm/main.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/samples/xilinx_apm/main.c 2014-07-20 22:06:39.946246503 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * Xilinx AXI Performance Monitor Example + * + * Copyright (c) 2013 Xilinx Inc. + * + * The code may be used by anyone for any purpose and can serve as a + * starting point for developing applications using Xilinx AXI + * Performance Monitor. + * + * This example based on Xilinx AXI Performance Monitor UIO driver shows + * sequence to read metrics from Xilinx AXI Performance Monitor IP. + * User need to provide the uio device file with option -d: + * main -d /dev/uio0, say /dev/uio0 as device file for AXI Performance + * Monitor driver. User need not clear Interrupt Status Register after + * waiting for interrupt on read since driver clears it. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <sys/msg.h> +#include <sys/ipc.h> +#include <stdint.h> +#include "xaxipmon.h" + +#define MAP_SIZE 4096 + +void usage(void) +{ + printf("*argv[0] -d <UIO_DEV_FILE> -i|-o <VALUE>\n"); + printf(" -d UIO device file. e.g. /dev/uio0"); + return; +} + +static void start(int fd) +{ + u8 slot = 2; + int tmp; + u32 isr; + + setmetrics(slot, XAPM_METRIC_SET_4, XAPM_METRIC_COUNTER_0); + setsampleinterval(0x3FFFFFF); + + loadsic(); + + intrenable(XAPM_IXR_SIC_OVERFLOW_MASK); + + intrglobalenable(); + + enablemetricscounter(); + + enablesic(); + + isr = intrgetstatus(); + /* Wait for SIC overflow interrupt */ + if (read(fd, &tmp, 4) < 0) + perror("Read\n"); + /* Driver clears the interrupt and occured interrupt status is + stored in param->isr */ + isr = intrgetstatus(); + if (isr & XAPM_IXR_SIC_OVERFLOW_MASK) + disablesic(); + + disablemetricscounter(); + + intrdisable(XAPM_IXR_SIC_OVERFLOW_MASK); + + intrglobaldisable(); + + printf("Required metrics: %u\n", + getsampledmetriccounter(XAPM_METRIC_COUNTER_0) * + params->scalefactor); +} + +int main(int argc, char *argv[]) +{ + int c; + char *uiod; + int fd; + + while ((c = getopt(argc, argv, "d:h")) != -1) { + switch (c) { + case 'd': + uiod = optarg; + break; + case 'h': + usage(); + return 0; + default: + printf("invalid option: %c\n", (char)c); + usage(); + return -1; + } + } + + /* Open the UIO device file */ + fd = open(uiod, O_RDWR); + if (fd < 1) { + perror(argv[0]); + printf("Invalid UIO device file:%s.\n", uiod); + usage(); + return -1; + } + + baseaddr = (u32)mmap(0, MAP_SIZE , PROT_READ|PROT_WRITE, + MAP_SHARED , fd, 0); + if ((u32 *)baseaddr == MAP_FAILED) + perror("mmap failed\n"); + + /* mmap the UIO device */ + params = (struct xapm_param *)mmap(0, MAP_SIZE , PROT_READ|PROT_WRITE, + MAP_SHARED , fd, getpagesize()); + if (params == MAP_FAILED) + perror("mmap failed\n"); + + if (params->mode == 1) + printf("AXI PMON is in Advanced Mode\n"); + else if (params->mode == 2) + printf("AXI PMON is in Profile Mode\n"); + else + printf("AXI PMON is in trace Mode\n"); + + start(fd); + + close(fd); + munmap((u32 *)baseaddr, MAP_SIZE); + munmap(params, MAP_SIZE); + + return 0; +} Index: linux-3.12.24-rt38-xilinx/samples/xilinx_apm/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/samples/xilinx_apm/Makefile 2014-07-20 22:06:39.951246420 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +# +# 'make depend' uses makedepend to automatically generate dependencies +# (dependencies are added to end of Makefile) +# 'make' build executable file 'mycc' +# 'make clean' removes all .o and executable files +# + +# define the C compiler to use +CC = $(CROSS_COMPILE)gcc + +# define any compile-time flags +CFLAGS = -Wall -g + +# define any directories containing header files other than /usr/include +# +INCLUDES = + +# define library paths in addition to /usr/lib +# if I wanted to include libraries not in /usr/lib I'd specify +# their path using -Lpath, something like: +LFLAGS = + +# define any libraries to link into executable: +# if I want to link in libraries (libx.so or libx.a) I use the -llibname +# option, something like (this will link in libmylib.so and libm.so: +LIBS = -lm + +# define the C source files +SRCS = main.c xaxipmon.c + +# define the C object files +# +# This uses Suffix Replacement within a macro: +# $(name:string1=string2) +# For each word in 'name' replace 'string1' with 'string2' +# Below we are replacing the suffix .c of all words in the macro SRCS +# with the .o suffix +# +OBJS = $(SRCS:.c=.o) + +# define the executable file +MAIN = main + +# +# The following part of the makefile is generic; it can be used to +# build any executable just by changing the definitions above and by +# deleting dependencies appended to the file from 'make depend' +# + +.PHONY: depend clean + +all: $(MAIN) + @echo Xilinx AXI Performance Monitor application compiled + +$(MAIN): $(OBJS) + $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS) + +# this is a suffix replacement rule for building .o's from .c's +# it uses automatic variables $<: the name of the prerequisite of +# the rule(a .c file) and $@: the name of the target of the rule (a .o file) +# (see the gnu make manual section about automatic variables) +.c.o: + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +clean: + $(RM) *.o *~ $(MAIN) + +depend: $(SRCS) + makedepend $(INCLUDES) $^ + +# DO NOT DELETE THIS LINE -- make depend needs it Index: linux-3.12.24-rt38-xilinx/samples/xilinx_apm/xaxipmon.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/samples/xilinx_apm/xaxipmon.c 2014-07-20 22:06:39.966246173 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +#include "xaxipmon.h" +/*****************************************************************************/ +/** +* +* This function resets all Metric Counters and Sampled Metric Counters of +* AXI Performance Monitor. +* +* @return XST_SUCCESS +* +* +* @note None. +* +******************************************************************************/ +int resetmetriccounter(void) +{ + u32 regval; + + /* + * Write the reset value to the Control register to reset + * Metric counters + */ + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + writereg(baseaddr, XAPM_CTL_OFFSET, + (regval | XAPM_CR_MCNTR_RESET_MASK)); + /* + * Release from Reset + */ + writereg(baseaddr, XAPM_CTL_OFFSET, + (regval & ~(XAPM_CR_MCNTR_RESET_MASK))); + return XST_SUCCESS; + +} + +/*****************************************************************************/ +/** +* +* This function resets Global Clock Counter of AXI Performance Monitor +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void resetglobalclkcounter(void) +{ + + u32 regval; + + /* + * Write the reset value to the Control register to reset + * Global Clock Counter + */ + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + writereg(baseaddr, XAPM_CTL_OFFSET, + (regval | XAPM_CR_GCC_RESET_MASK)); + + /* + * Release from Reset + */ + writereg(baseaddr, XAPM_CTL_OFFSET, + (regval & ~(XAPM_CR_GCC_RESET_MASK))); + +} + +/*****************************************************************************/ +/** +* +* This function resets Streaming FIFO of AXI Performance Monitor +* +* @return XST_SUCCESS +* +* @note None. +* +******************************************************************************/ +int resetfifo(void) +{ + u32 regval; + + /* Check Event Logging is enabled in Hardware */ + if (params->eventlog == 0) + /*Event Logging not enabled in Hardware*/ + return XST_SUCCESS; + + /* + * Write the reset value to the Control register to reset + * FIFO + */ + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + writereg(baseaddr, XAPM_CTL_OFFSET, + (regval | XAPM_CR_FIFO_RESET_MASK)); + /* + * Release from Reset + */ + writereg(baseaddr, XAPM_CTL_OFFSET, + (regval & ~(XAPM_CR_FIFO_RESET_MASK))); + + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* +* This function sets Ranges for Incrementers depending on parameters passed. +* +* @param incrementer specifies the Incrementer for which Ranges +* need to be set +* @param rangehigh specifies the Upper limit in 32 bit Register +* @param rangelow specifies the Lower limit in 32 bit Register +* +* @return None. +* +* @note None +* +*****************************************************************************/ +void setincrementerrange(u8 incrementer, u16 rangehigh, u16 rangelow) +{ + u32 regval; + + /* + * Write to the specified Range register + */ + regval = rangehigh << 16; + regval |= rangelow; + writereg(baseaddr, + (XAPM_RANGE0_OFFSET + (incrementer * 16)), regval); +} + +/****************************************************************************/ +/** +* +* This function returns the Ranges of Incrementers Registers. +* +* @param incrementer specifies the Incrementer for which Ranges +* need to be returned. +* @param rangehigh specifies the user reference variable which returns +* the Upper Range Value of the specified Incrementer. +* @param rangelow specifies the user reference variable which returns +* the Lower Range Value of the specified Incrementer. +* +* @return None. +* +* @note None +* +*****************************************************************************/ +void getincrementerrange(u8 incrementer, u16 *rangehigh, u16 *rangelow) +{ + u32 regval; + + regval = readreg(baseaddr, (XAPM_RANGE0_OFFSET + + (incrementer * 16))); + + *rangelow = regval & 0xFFFF; + *rangehigh = (regval >> 16) & 0xFFFF; +} + +/****************************************************************************/ +/** +* +* This function sets the Sample Interval Register +* +* @param sampleinterval is the Sample Interval +* +* @return None +* +* @note None. +* +*****************************************************************************/ +void setsampleinterval(u32 sampleinterval) +{ + /* + * Set Sample Interval + */ + writereg(baseaddr, XAPM_SI_LOW_OFFSET, sampleinterval); + +} + +/****************************************************************************/ +/** +* +* This function returns the contents of Sample Interval Register +* +* @param sampleinterval is a pointer where Sample Interval register +* contents are returned. +* @return None. +* +* @note None. +* +******************************************************************************/ +void getsampleinterval(u32 *sampleinterval) +{ + /* + * Set Sample Interval Lower + */ + *sampleinterval = readreg(baseaddr, XAPM_SI_LOW_OFFSET); + +} + +/****************************************************************************/ +/** +* +* This function sets metrics for specified Counter in the corresponding +* Metric Selector Register. +* +* @param slot is the slot ID for which specified counter has to +* be connected. +* @param metrics is one of the Metric Sets. User has to use +* XAPM_METRIC_SET_* macros in xaxipmon.h for this parameter +* @param counter is the Counter Number. +* The valid values are 0 to 9. +* +* @return XST_SUCCESS if Success +* XST_FAILURE if Failure +* +* @note None. +* +*****************************************************************************/ +int setmetrics(u8 slot, u8 metrics, u8 counter) +{ + u32 regval; + u32 mask; + + /* Find mask value to force zero in counternum byte range */ + if (counter == 0 || counter == 4 || counter == 8) + mask = 0xFFFFFF00; + else if (counter == 1 || counter == 5 || counter == 9) + mask = 0xFFFF00FF; + else if (counter == 2 || counter == 6) + mask = 0xFF00FFFF; + else + mask = 0x00FFFFFF; + + if (counter <= 3) { + regval = readreg(baseaddr, XAPM_MSR0_OFFSET); + regval = regval & mask; + regval = regval | (metrics << (counter * 8)); + regval = regval | (slot << (counter * 8 + 5)); + writereg(baseaddr, XAPM_MSR0_OFFSET, regval); + } else if ((counter >= 4) && (counter <= 7)) { + counter = counter - 4; + regval = readreg(baseaddr, XAPM_MSR1_OFFSET); + regval = regval & mask; + regval = regval | (metrics << (counter * 8)); + regval = regval | (slot << (counter * 8 + 5)); + writereg(baseaddr, XAPM_MSR1_OFFSET, regval); + } else { + counter = counter - 8; + regval = readreg(baseaddr, XAPM_MSR2_OFFSET); + + regval = regval & mask; + regval = regval | (metrics << (counter * 8)); + regval = regval | (slot << (counter * 8 + 5)); + writereg(baseaddr, XAPM_MSR2_OFFSET, regval); + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function returns metrics in the specified Counter from the corresponding +* Metric Selector Register. +* +* @param counter is the Counter Number. +* The valid values are 0 to 9. +* @param metrics is a reference parameter from application where metrics +* of specified counter is filled. +* @praram slot is a reference parameter in which slot Id of +* specified counter is filled +* @return XST_SUCCESS if Success +* XST_FAILURE if Failure +* +* @note None. +* +*****************************************************************************/ +int getmetrics(u8 counter, u8 *metrics, u8 *slot) +{ + u32 regval; + + if (counter <= 3) { + regval = readreg(baseaddr, XAPM_MSR0_OFFSET); + *metrics = (regval >> (counter * 8)) & 0x1F; + *slot = (regval >> (counter * 8 + 5)) & 0x7; + } else if ((counter >= 4) && (counter <= 7)) { + counter = counter - 4; + regval = readreg(baseaddr, XAPM_MSR1_OFFSET); + *metrics = (regval >> (counter * 8)) & 0x1F; + *slot = (regval >> (counter * 8 + 5)) & 0x7; + } else { + counter = counter - 8; + regval = readreg(baseaddr, XAPM_MSR2_OFFSET); + *metrics = (regval >> (counter * 8)) & 0x1F; + *slot = (regval >> (counter * 8 + 5)) & 0x7; + } + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* +* This function returns the contents of the Global Clock Counter Register. +* +* @param cnthigh is the user space pointer with which upper 32 bits +* of Global Clock Counter has to be filled +* @param cntlow is the user space pointer with which lower 32 bits +* of Global Clock Counter has to be filled +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void getglobalclkcounter(u32 *cnthigh, u32 *cntlow) +{ + *cnthigh = 0x0; + *cntlow = 0x0; + + /* + * If Counter width is 64 bit then Counter Value has to be + * filled at CntHighValue address also. + */ + if (params->globalcntwidth == 64) { + /* Bits[63:32] exists at XAPM_GCC_HIGH_OFFSET */ + *cnthigh = readreg(baseaddr, XAPM_GCC_HIGH_OFFSET); + } + /* Bits[31:0] exists at XAPM_GCC_LOW_OFFSET */ + *cntlow = readreg(baseaddr, XAPM_GCC_LOW_OFFSET); +} + +/****************************************************************************/ +/** +* +* This function returns the contents of the Metric Counter Register. +* +* @param counter is the number of the Metric Counter to be read. +* Use the XAPM_METRIC_COUNTER* defines for the counter number in +* xaxipmon.h. The valid values are 0 (XAPM_METRIC_COUNTER_0) to +* 9 (XAPM_METRIC_COUNTER_9). +* @return regval is the content of specified Metric Counter. +* +* @note None. +* +*****************************************************************************/ +u32 getmetriccounter(u32 counter) +{ + u32 regval; + + regval = readreg(baseaddr, + (XAPM_MC0_OFFSET + (counter * 16))); + return regval; +} + +/****************************************************************************/ +/** +* +* This function returns the contents of the Sampled Metric Counter Register. +* +* @param counter is the number of the Sampled Metric Counter to read. +* Use the XAPM_METRIC_COUNTER* defines for the counter number in +* xaxipmon.h. The valid values are 0 (XAPM_METRIC_COUNTER_0) to +* 9 (XAPM_METRIC_COUNTER_9). +* +* @return regval is the content of specified Sampled Metric Counter. +* +* @note None. +* +*****************************************************************************/ +u32 getsampledmetriccounter(u32 counter) +{ + u32 regval; + + regval = readreg(baseaddr, (XAPM_SMC0_OFFSET + + (counter * 16))); + return regval; +} + +/****************************************************************************/ +/** +* +* This function returns the contents of the Incrementer Register. +* +* @param incrementer is the number of the Incrementer register to +* read.Use the XAPM_INCREMENTER_* defines for the Incrementer +* number.The valid values are 0 (XAPM_INCREMENTER_0) to +* 9 (XAPM_INCREMENTER_9). +* @param incrementer is the number of the specified Incrementer +* register +* @return regval is content of specified Metric Incrementer register. +* +* @note None. +* +*****************************************************************************/ +u32 getincrementer(u32 incrementer) +{ + u32 regval; + + regval = readreg(baseaddr, (XAPM_INC0_OFFSET + + (incrementer * 16))); + return regval; +} + +/****************************************************************************/ +/** +* +* This function returns the contents of the Sampled Incrementer Register. +* +* @param incrementer is the number of the Sampled Incrementer +* register to read.Use the XAPM_INCREMENTER_* defines for the +* Incrementer number.The valid values are 0 (XAPM_INCREMENTER_0) +* to 9 (XAPM_INCREMENTER_9). +* @param incrementer is the number of the specified Sampled +* Incrementer register +* @return regval is content of specified Sampled Incrementer register. +* +* @note None. +* +*****************************************************************************/ +u32 getsampledincrementer(u32 incrementer) +{ + u32 regval; + + regval = readreg(baseaddr, (XAPM_SINC0_OFFSET + + (incrementer * 16))); + return regval; +} + +/****************************************************************************/ +/** +* +* This function sets Software-written Data Register. +* +* @param swdata is the Software written Data. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void setswdatareg(u32 swdata) +{ + /* + * Set Software-written Data Register + */ + writereg(baseaddr, XAPM_SWD_OFFSET, swdata); +} + +/****************************************************************************/ +/** +* +* This function returns contents of Software-written Data Register. +* +* @return swdata. +* +* @note None. +* +*****************************************************************************/ +u32 getswdatareg(void) +{ + u32 swdata; + + /* + * Set Metric Selector Register + */ + swdata = (u32)readreg(baseaddr, XAPM_SWD_OFFSET); + return swdata; +} + +/*****************************************************************************/ +/** +* +* This function enables the following in the AXI Performance Monitor: +* - Event logging +* +* @param flagenables is a value to write to the flag enables +* register defined by XAPM_FEC_OFFSET. It is recommended +* to use the XAPM_FEC_*_MASK mask bits to generate. +* A value of 0x0 will disable all events to the event +* log streaming FIFO. +* +* @return XST_SUCCESS +* +* @note None +* +******************************************************************************/ +int starteventlog(u32 flagenables) +{ + u32 regval; + + /* Read current register value */ + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + /* Now write to flag enables register */ + writereg(baseaddr, XAPM_FEC_OFFSET, flagenables); + /* Write the new value to the Control register to + * enable event logging */ + writereg(baseaddr, XAPM_CTL_OFFSET, + regval | XAPM_CR_EVENTLOG_ENABLE_MASK); + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the following in the AXI Performance Monitor: +* - Event logging +* +* @return XST_SUCCESS +* +* @note None +* +******************************************************************************/ +int stopeventlog(void) +{ + u32 regval; + + /* Read current register value */ + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + + /* Write the new value to the Control register to disable + * event logging */ + writereg(baseaddr, XAPM_CTL_OFFSET, + regval & ~XAPM_CR_EVENTLOG_ENABLE_MASK); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enables the following in the AXI Performance Monitor: +* - Global clock counter +* - All metric counters +* - All sampled metric counters +* +* @param sampleinterval is the sample interval +* @return XST_SUCCESS +* +* @note None +******************************************************************************/ +int startcounters(u32 sampleinterval) +{ + u32 regval; + + /* Read current register value */ + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + + /* Global Clock Counter is present in Advanced Mode only */ + if (params->mode == 1) + regval = regval | XAPM_CR_GCC_ENABLE_MASK; + /* + * Write the new value to the Control register to enable + * global clock counter and metric counters + */ + writereg(baseaddr, XAPM_CTL_OFFSET, regval | XAPM_CR_MCNTR_ENABLE_MASK); + + /* Set, enable, and load sampled counters */ + setsampleinterval(sampleinterval); + loadsic(); + enablesic(); + + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* +* This function disables the following in the AXI Performance Monitor: +* - Global clock counter +* - All metric counters +* +* @return XST_SUCCESS +* +* @note None +* +******************************************************************************/ +int stopcounters(void) +{ + u32 regval; + + /* Read current register value */ + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + + /* Global Clock Counter is present in Advanced Mode only */ + if (params->mode == 1) + regval = regval & ~XAPM_CR_GCC_ENABLE_MASK; + + /* + * Write the new value to the Control register to disable + * global clock counter and metric counters + */ + writereg(baseaddr, XAPM_CTL_OFFSET, + regval & ~XAPM_CR_MCNTR_ENABLE_MASK); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enables Metric Counters. +* +* @return None +* +* @note None +* +******************************************************************************/ +void enablemetricscounter(void) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + writereg(baseaddr, XAPM_CTL_OFFSET, + regval | XAPM_CR_MCNTR_ENABLE_MASK); +} +/****************************************************************************/ +/** +* +* This function disables the Metric Counters. +* +* @return None +* +* @note None +* +*****************************************************************************/ +void disablemetricscounter(void) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + + writereg(baseaddr, XAPM_CTL_OFFSET, + regval & ~(XAPM_CR_MCNTR_ENABLE_MASK)); +} + +/****************************************************************************/ +/** +* +* This function sets the Upper and Lower Ranges for specified Metric Counter +* Log Enable Register.Event Logging starts when corresponding Metric Counter +* value falls in between these ranges +* +* @param counter is the Metric Counter number for which +* Ranges are to be assigned.Use the XAPM_METRIC_COUNTER* +* defines for the counter number in xaxipmon.h. +* The valid values are 0 (XAPM_METRIC_COUNTER_0) to +* 9 (XAPM_METRIC_COUNTER_9). +* @param rangehigh specifies the Upper limit in 32 bit Register +* @param rangelow specifies the Lower limit in 32 bit Register +* @return None +* +* @note None. +* +*****************************************************************************/ +void setlogenableranges(u32 counter, u16 rangehigh, u16 rangelow) +{ + u32 regval; + + /* + * Write the specified Ranges to corresponding Metric Counter Log + * Enable Register + */ + regval = rangehigh << 16; + regval |= rangelow; + writereg(baseaddr, (XAPM_MC0LOGEN_OFFSET + + (counter * 16)), regval); +} + +/****************************************************************************/ +/** +* +* This function returns the Ranges of specified Metric Counter Log +* Enable Register. +* +* @param counter is the Metric Counter number for which +* Ranges are to be returned.Use the XAPM_METRIC_COUNTER* +* defines for the counter number in xaxipmon.h. +* The valid values are 0 (XAPM_METRIC_COUNTER_0) to +* 9 (XAPM_METRIC_COUNTER_9). +* +* @param rangehigh specifies the user reference variable which returns +* the Upper Range Value of the specified Metric Counter +* Log Enable Register. +* @param rangelow specifies the user reference variable which returns +* the Lower Range Value of the specified Metric Counter +* Log Enable Register. +* +* @note None. +* +*****************************************************************************/ +void getlogenableranges(u32 counter, u16 *rangehigh, u16 *rangelow) +{ + u32 regval; + + regval = readreg(baseaddr, + (XAPM_MC0LOGEN_OFFSET + (counter * 16))); + + *rangelow = regval & 0xFFFF; + *rangehigh = (regval >> 16) & 0xFFFF; +} + +/*****************************************************************************/ +/** +* +* This function enables Event Logging. +* +* @return None +* +* @note None +* +******************************************************************************/ +void enableeventlog(void) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + writereg(baseaddr, XAPM_CTL_OFFSET, + regval | XAPM_CR_EVENTLOG_ENABLE_MASK); +} + +/*****************************************************************************/ +/** +* +* This function enables External trigger pulse so that Metric Counters can be +* started on external trigger pulse for a slot. +* +* +* @return None +* +* @note None +* +******************************************************************************/ +void enablemctrigger(void) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + writereg(baseaddr, XAPM_CTL_OFFSET, + regval | XAPM_CR_MCNTR_EXTTRIGGER_MASK); +} + +/****************************************************************************/ +/** +* +* This function disables the External trigger pulse used to start Metric +* Counters on external trigger pulse for a slot. +* +* @return None +* +* @note None +* +*****************************************************************************/ +void disablemctrigger(void) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + + writereg(baseaddr, XAPM_CTL_OFFSET, + regval & ~(XAPM_CR_MCNTR_EXTTRIGGER_MASK)); +} + +/*****************************************************************************/ +/** +* +* This function enables External trigger pulse for Event Log +* so that Event Logging can be started on external trigger pulse for a slot. +* +* @return None +* +* @note None +* +******************************************************************************/ +void enableeventlogtrigger(void) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + writereg(baseaddr, XAPM_CTL_OFFSET, + regval | XAPM_CR_EVTLOG_EXTTRIGGER_MASK); +} + +/****************************************************************************/ +/** +* +* This function disables the External trigger pulse used to start Event +* Log on external trigger pulse for a slot. +* +* @return None +* +* @note None +* +*****************************************************************************/ +void disableeventlogtrigger(void) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + + writereg(baseaddr, XAPM_CTL_OFFSET, + regval & ~(XAPM_CR_EVTLOG_EXTTRIGGER_MASK)); +} + +/****************************************************************************/ +/** +* +* This function returns a name for a given Metric. +* +* @param metrics is one of the Metric Sets. User has to use +* XAPM_METRIC_SET_* macros in xaxipmon.h for this parameter +* +* @return const char * +* +* @note None +* +*****************************************************************************/ +const char *getmetricname(u8 metrics) +{ + if (metrics == XAPM_METRIC_SET_0) + return "Write Transaction Count"; + if (metrics == XAPM_METRIC_SET_1) + return "Read Transaction Count"; + if (metrics == XAPM_METRIC_SET_2) + return "Write Byte Count"; + if (metrics == XAPM_METRIC_SET_3) + return "Read Byte Count"; + if (metrics == XAPM_METRIC_SET_4) + return "Write Beat Count"; + if (metrics == XAPM_METRIC_SET_5) + return "Total Read Latency"; + if (metrics == XAPM_METRIC_SET_6) + return "Total Write Latency"; + if (metrics == XAPM_METRIC_SET_7) + return "Slv_Wr_Idle_Cnt"; + if (metrics == XAPM_METRIC_SET_8) + return "Mst_Rd_Idle_Cnt"; + if (metrics == XAPM_METRIC_SET_9) + return "Num_BValids"; + if (metrics == XAPM_METRIC_SET_10) + return "Num_WLasts"; + if (metrics == XAPM_METRIC_SET_11) + return "Num_RLasts"; + if (metrics == XAPM_METRIC_SET_12) + return "Minimum Write Latency"; + if (metrics == XAPM_METRIC_SET_13) + return "Maximum Write Latency"; + if (metrics == XAPM_METRIC_SET_14) + return "Minimum Read Latency"; + if (metrics == XAPM_METRIC_SET_15) + return "Maximum Read Latency"; + if (metrics == XAPM_METRIC_SET_16) + return "Transfer Cycle Count"; + if (metrics == XAPM_METRIC_SET_17) + return "Packet Count"; + if (metrics == XAPM_METRIC_SET_18) + return "Data Byte Count"; + if (metrics == XAPM_METRIC_SET_19) + return "Position Byte Count"; + if (metrics == XAPM_METRIC_SET_20) + return "Null Byte Count"; + if (metrics == XAPM_METRIC_SET_21) + return "Slv_Idle_Cnt"; + if (metrics == XAPM_METRIC_SET_22) + return "Mst_Idle_Cnt"; + if (metrics == XAPM_METRIC_SET_30) + return "External event count"; + return "Unsupported"; +} + +/****************************************************************************/ +/** +* +* This function sets Write ID in Latency ID register to capture Write +* Latency metrics. +* +* @param writeid is the Write ID to be written in Latency ID register. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void setwriteid(u16 writeid) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_ID_OFFSET); + regval = regval & ~(XAPM_ID_WID_MASK); + regval = regval | writeid; + writereg(baseaddr, XAPM_ID_OFFSET, regval); +} + +/****************************************************************************/ +/** +* +* This function sets Read ID in Latency ID register to capture +* Read Latency metrics. +* +* @param readid is the Read ID to be written in Latency ID register. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void setreadid(u16 readid) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_ID_OFFSET); + regval = regval & ~(XAPM_ID_RID_MASK); + regval = regval | (readid << 16); + writereg(baseaddr, XAPM_ID_OFFSET, regval); +} + +/****************************************************************************/ +/** +* +* This function returns Write ID in Latency ID register. +* +* @return writeid is the required Write ID in Latency ID register. +* +* @note None. +* +*****************************************************************************/ +u16 getwriteid(void) +{ + + u16 writeid; + u32 regval; + + regval = readreg(baseaddr, XAPM_ID_OFFSET); + writeid = regval & XAPM_ID_WID_MASK; + + return writeid; +} + +/****************************************************************************/ +/** +* +* This function returns Read ID in Latency ID register. +* +* @return readid is the required Read ID in Latency ID register. +* +* @note None. +* +*****************************************************************************/ +u16 getreadid(void) +{ + + u16 readid; + u32 regval; + + regval = readreg(baseaddr, XAPM_ID_OFFSET); + regval = regval & XAPM_ID_RID_MASK; + readid = regval >> 16; + + return readid; +} + +/*****************************************************************************/ +/** +* +* This function sets Latency Start point to calculate write latency. +* +* @param Param can be 0 - XAPM_LATENCY_ADDR_ISSUE +* or 1 - XAPM_LATENCY_ADDR_ACCEPT +* @return None +* +* @note None +* +******************************************************************************/ +void setwrlatencystart(u8 param) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + if (param == XAPM_LATENCY_ADDR_ACCEPT) + writereg(baseaddr, XAPM_CTL_OFFSET, regval | + XAPM_CR_WRLATENCY_START_MASK); + else + writereg(baseaddr, XAPM_CTL_OFFSET, readreg(baseaddr, + XAPM_CTL_OFFSET) & ~(XAPM_CR_WRLATENCY_START_MASK)); +} + +/*****************************************************************************/ +/** +* +* This function sets Latency End point to calculate write latency. +* +* @param Param can be 0 - XAPM_LATENCY_LASTWR +* or 1 - XAPM_LATENCY_FIRSTWR +* @return None +* +* @note None +* +******************************************************************************/ +void setwrlatencyend(u8 param) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + if (param == XAPM_LATENCY_FIRSTWR) + writereg(baseaddr, XAPM_CTL_OFFSET, regval | + XAPM_CR_WRLATENCY_END_MASK); + else + writereg(baseaddr, XAPM_CTL_OFFSET, readreg(baseaddr, + XAPM_CTL_OFFSET) & ~(XAPM_CR_WRLATENCY_END_MASK)); +} + +/*****************************************************************************/ +/** +* +* This function sets Latency Start point to calculate read latency. +* +* @param Param can be 0 - XAPM_LATENCY_ADDR_ISSUE +* or 1 - XAPM_LATENCY_ADDR_ACCEPT +* @return None +* +* @note None +* +******************************************************************************/ +void setrdlatencystart(u8 param) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + if (param == XAPM_LATENCY_ADDR_ACCEPT) + writereg(baseaddr, XAPM_CTL_OFFSET, regval | + XAPM_CR_RDLATENCY_START_MASK); + else + writereg(baseaddr, XAPM_CTL_OFFSET, readreg(baseaddr, + XAPM_CTL_OFFSET) & ~(XAPM_CR_RDLATENCY_START_MASK)); +} + +/*****************************************************************************/ +/** +* +* This function sets Latency End point to calculate read latency. +* +* @param Param can be 0 - XAPM_LATENCY_LASTRD +* or 1 - XAPM_LATENCY_FIRSTRD +* @return None +* +* @note None +* +******************************************************************************/ +void setrdlatencyend(u8 param) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + if (param == XAPM_LATENCY_FIRSTRD) + writereg(baseaddr, XAPM_CTL_OFFSET, regval | + XAPM_CR_RDLATENCY_END_MASK); + else + writereg(baseaddr, XAPM_CTL_OFFSET, readreg(baseaddr, + XAPM_CTL_OFFSET) & ~(XAPM_CR_RDLATENCY_END_MASK)); +} + +/*****************************************************************************/ +/** +* +* This function returns Write Latency Start point. +* +* @return Returns 0 - XAPM_LATENCY_ADDR_ISSUE or +* 1 - XAPM_LATENCY_ADDR_ACCEPT +* +* @note None +* +******************************************************************************/ +u8 getwrlatencystart(void) +{ + u8 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + regval = regval & XAPM_CR_WRLATENCY_START_MASK; + if (regval != XAPM_LATENCY_ADDR_ISSUE) + return XAPM_LATENCY_ADDR_ACCEPT; + else + return XAPM_LATENCY_ADDR_ISSUE; +} + +/*****************************************************************************/ +/** +* +* This function returns Write Latency End point. +* +* @return Returns 0 - XAPM_LATENCY_LASTWR or +* 1 - XAPM_LATENCY_FIRSTWR. +* +* @note None +* +******************************************************************************/ +u8 getwrlatencyend(void) +{ + u8 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + regval = regval & XAPM_CR_WRLATENCY_END_MASK; + if (regval != XAPM_LATENCY_LASTWR) + return XAPM_LATENCY_FIRSTWR; + else + return XAPM_LATENCY_LASTWR; +} + +/*****************************************************************************/ +/** +* +* This function returns read Latency Start point. +* +* @return Returns 0 - XAPM_LATENCY_ADDR_ISSUE or +* 1 - XAPM_LATENCY_ADDR_ACCEPT +* +* @note None +* +******************************************************************************/ +u8 getrdlatencystart(void) +{ + u8 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + regval = regval & XAPM_CR_RDLATENCY_START_MASK; + + if (regval != XAPM_LATENCY_ADDR_ISSUE) + return XAPM_LATENCY_ADDR_ACCEPT; + else + return XAPM_LATENCY_ADDR_ISSUE; +} + +/*****************************************************************************/ +/** +* +* This function returns Read Latency End point. +* +* @return Returns 0 - XAPM_LATENCY_LASTRD or +* 1 - XAPM_LATENCY_FIRSTRD. +* +* @note None +* +******************************************************************************/ +u8 getrdlatencyend(void) +{ + u8 regval; + + regval = readreg(baseaddr, XAPM_CTL_OFFSET); + regval = regval & XAPM_CR_RDLATENCY_END_MASK; + if (regval != XAPM_LATENCY_LASTRD) + return XAPM_LATENCY_FIRSTRD; + else + return XAPM_LATENCY_LASTRD; + +} + +/****************************************************************************/ +/** +* +* This function sets Write ID Mask in ID Mask register. +* +* @param wrmask is the Write ID mask to be written in ID register. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void setwriteidmask(u16 wrmask) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_IDMASK_OFFSET); + regval = regval & ~(XAPM_MASKID_WID_MASK); + regval = regval | wrmask; + writereg(baseaddr, XAPM_IDMASK_OFFSET, regval); +} + +/****************************************************************************/ +/** +* +* This function sets Read ID Mask in ID Mask register. +* +* @param rdmask is the Read ID mask to be written in ID Mask register. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void setreadidmask(u16 rdmask) +{ + u32 regval; + + regval = readreg(baseaddr, XAPM_IDMASK_OFFSET); + regval = regval & ~(XAPM_MASKID_RID_MASK); + regval = regval | (rdmask << 16); + writereg(baseaddr, XAPM_IDMASK_OFFSET, regval); +} + +/****************************************************************************/ +/** +* +* This function returns Write ID Mask in ID Mask register. +* +* @return wrmask is the required Write ID Mask in ID Mask register. +* +* @note None. +* +*****************************************************************************/ +u16 getwriteidmask(void) +{ + + u16 wrmask; + u32 regval; + + regval = readreg(baseaddr, XAPM_IDMASK_OFFSET); + wrmask = regval & XAPM_MASKID_WID_MASK; + + return wrmask; +} + +/****************************************************************************/ +/** +* +* This function returns Read ID Mask in ID Mask register. +* +* @return rdmask is the required Read ID Mask in ID Mask register. +* +* @note None. +* +*****************************************************************************/ +u16 getreadidmask(void) +{ + + u16 rdmask; + u32 regval; + + regval = readreg(baseaddr, XAPM_IDMASK_OFFSET); + regval = regval & XAPM_MASKID_RID_MASK; + rdmask = regval >> 16; + + return rdmask; +} Index: linux-3.12.24-rt38-xilinx/samples/xilinx_apm/xaxipmon.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/samples/xilinx_apm/xaxipmon.h 2014-07-20 22:06:39.981245925 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +#ifndef XAXIPMON_H /* Prevent circular inclusions */ +#define XAXIPMON_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + + +#define XST_SUCCESS 0 +#define XST_FAILURE 1 + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define XAPM_GCC_HIGH_OFFSET 0x0000 /* Global Clock Counter + 32 to 63 bits */ +#define XAPM_GCC_LOW_OFFSET 0x0004 /* Global Clock Counter Lower + 0-31 bits */ +#define XAPM_SI_HIGH_OFFSET 0x0020 /* Sample Interval MSB */ +#define XAPM_SI_LOW_OFFSET 0x0024 /* Sample Interval LSB */ +#define XAPM_SICR_OFFSET 0x0028 /* Sample Interval Control + Register */ +#define XAPM_SR_OFFSET 0x002C /* Sample Register */ +#define XAPM_GIE_OFFSET 0x0030 /* Global Interrupt Enable + Register */ +#define XAPM_IE_OFFSET 0x0034 /* Interrupt Enable Register */ +#define XAPM_IS_OFFSET 0x0038 /* Interrupt Status Register */ + +#define XAPM_MSR0_OFFSET 0x0044 /* Metric Selector 0 Register*/ +#define XAPM_MSR1_OFFSET 0x0048 /* Metric Selector 1 Register*/ +#define XAPM_MSR2_OFFSET 0x004C /* Metric Selector 2 Register*/ + +#define XAPM_MC0_OFFSET 0x0100 /* Metric Counter 0 Register */ +#define XAPM_INC0_OFFSET 0x0104 /* Incrementer 0 Register */ +#define XAPM_RANGE0_OFFSET 0x0108 /* Range 0 Register */ +#define XAPM_MC0LOGEN_OFFSET 0x010C /* Metric Counter 0 + Log Enable Register */ +#define XAPM_MC1_OFFSET 0x0110 /* Metric Counter 1 Register */ +#define XAPM_INC1_OFFSET 0x0114 /* Incrementer 1 Register */ +#define XAPM_RANGE1_OFFSET 0x0118 /* Range 1 Register */ +#define XAPM_MC1LOGEN_OFFSET 0x011C /* Metric Counter 1 + Log Enable Register */ +#define XAPM_MC2_OFFSET 0x0120 /* Metric Counter 2 Register */ +#define XAPM_INC2_OFFSET 0x0124 /* Incrementer 2 Register */ +#define XAPM_RANGE2_OFFSET 0x0128 /* Range 2 Register */ +#define XAPM_MC2LOGEN_OFFSET 0x012C /* Metric Counter 2 + Log Enable Register */ +#define XAPM_MC3_OFFSET 0x0130 /* Metric Counter 3 Register */ +#define XAPM_INC3_OFFSET 0x0134 /* Incrementer 3 Register */ +#define XAPM_RANGE3_OFFSET 0x0138 /* Range 3 Register */ +#define XAPM_MC3LOGEN_OFFSET 0x013C /* Metric Counter 3 + Log Enable Register */ +#define XAPM_MC4_OFFSET 0x0140 /* Metric Counter 4 Register */ +#define XAPM_INC4_OFFSET 0x0144 /* Incrementer 4 Register */ +#define XAPM_RANGE4_OFFSET 0x0148 /* Range 4 Register */ +#define XAPM_MC4LOGEN_OFFSET 0x014C /* Metric Counter 4 + Log Enable Register */ +#define XAPM_MC5_OFFSET 0x0150 /* Metric Counter 5 + Register */ +#define XAPM_INC5_OFFSET 0x0154 /* Incrementer 5 Register */ +#define XAPM_RANGE5_OFFSET 0x0158 /* Range 5 Register */ +#define XAPM_MC5LOGEN_OFFSET 0x015C /* Metric Counter 5 + Log Enable Register */ +#define XAPM_MC6_OFFSET 0x0160 /* Metric Counter 6 + Register */ +#define XAPM_INC6_OFFSET 0x0164 /* Incrementer 6 Register */ +#define XAPM_RANGE6_OFFSET 0x0168 /* Range 6 Register */ +#define XAPM_MC6LOGEN_OFFSET 0x016C /* Metric Counter 6 + Log Enable Register */ +#define XAPM_MC7_OFFSET 0x0170 /* Metric Counter 7 + Register */ +#define XAPM_INC7_OFFSET 0x0174 /* Incrementer 7 Register */ +#define XAPM_RANGE7_OFFSET 0x0178 /* Range 7 Register */ +#define XAPM_MC7LOGEN_OFFSET 0x017C /* Metric Counter 7 + Log Enable Register */ +#define XAPM_MC8_OFFSET 0x0180 /* Metric Counter 8 + Register */ +#define XAPM_INC8_OFFSET 0x0184 /* Incrementer 8 Register */ +#define XAPM_RANGE8_OFFSET 0x0188 /* Range 8 Register */ +#define XAPM_MC8LOGEN_OFFSET 0x018C /* Metric Counter 8 + Log Enable Register */ +#define XAPM_MC9_OFFSET 0x0190 /* Metric Counter 9 + Register */ +#define XAPM_INC9_OFFSET 0x0194 /* Incrementer 9 Register */ +#define XAPM_RANGE9_OFFSET 0x0198 /* Range 9 Register */ +#define XAPM_MC9LOGEN_OFFSET 0x019C /* Metric Counter 9 + Log Enable Register */ + +#define XAPM_MC10_OFFSET 0x01A0 /* Metric Counter 10 + Register */ +#define XAPM_MC11_OFFSET 0x01B0 /* Metric Counter 11 + Register */ +#define XAPM_MC12_OFFSET 0x0500 /* Metric Counter 12 + Register */ +#define XAPM_MC13_OFFSET 0x0510 /* Metric Counter 13 + Register */ +#define XAPM_MC14_OFFSET 0x0520 /* Metric Counter 14 + Register */ +#define XAPM_MC15_OFFSET 0x0530 /* Metric Counter 15 + Register */ +#define XAPM_MC16_OFFSET 0x0540 /* Metric Counter 16 + Register */ +#define XAPM_MC17_OFFSET 0x0550 /* Metric Counter 17 + Register */ +#define XAPM_MC18_OFFSET 0x0560 /* Metric Counter 18 + Register */ +#define XAPM_MC19_OFFSET 0x0570 /* Metric Counter 19 + Register */ +#define XAPM_MC20_OFFSET 0x0580 /* Metric Counter 20 + Register */ +#define XAPM_MC21_OFFSET 0x0590 /* Metric Counter 21 + Register */ +#define XAPM_MC22_OFFSET 0x05A0 /* Metric Counter 22 + Register */ +#define XAPM_MC23_OFFSET 0x05B0 /* Metric Counter 23 + Register */ +#define XAPM_MC24_OFFSET 0x0700 /* Metric Counter 24 + Register */ +#define XAPM_MC25_OFFSET 0x0710 /* Metric Counter 25 + Register */ +#define XAPM_MC26_OFFSET 0x0720 /* Metric Counter 26 + Register */ +#define XAPM_MC27_OFFSET 0x0730 /* Metric Counter 27 + Register */ +#define XAPM_MC28_OFFSET 0x0740 /* Metric Counter 28 + Register */ +#define XAPM_MC29_OFFSET 0x0750 /* Metric Counter 29 + Register */ +#define XAPM_MC30_OFFSET 0x0760 /* Metric Counter 30 + Register */ +#define XAPM_MC31_OFFSET 0x0770 /* Metric Counter 31 + Register */ +#define XAPM_MC32_OFFSET 0x0780 /* Metric Counter 32 + Register */ +#define XAPM_MC33_OFFSET 0x0790 /* Metric Counter 33 + Register */ +#define XAPM_MC34_OFFSET 0x07A0 /* Metric Counter 34 + Register */ +#define XAPM_MC35_OFFSET 0x07B0 /* Metric Counter 35 + Register */ +#define XAPM_MC36_OFFSET 0x0900 /* Metric Counter 36 + Register */ +#define XAPM_MC37_OFFSET 0x0910 /* Metric Counter 37 + Register */ +#define XAPM_MC38_OFFSET 0x0920 /* Metric Counter 38 + Register */ +#define XAPM_MC39_OFFSET 0x0930 /* Metric Counter 39 + Register */ +#define XAPM_MC40_OFFSET 0x0940 /* Metric Counter 40 + Register */ +#define XAPM_MC41_OFFSET 0x0950 /* Metric Counter 41 + Register */ +#define XAPM_MC42_OFFSET 0x0960 /* Metric Counter 42 + Register */ +#define XAPM_MC43_OFFSET 0x0970 /* Metric Counter 43 + Register */ +#define XAPM_MC44_OFFSET 0x0980 /* Metric Counter 44 + Register */ +#define XAPM_MC45_OFFSET 0x0990 /* Metric Counter 45 + Register */ +#define XAPM_MC46_OFFSET 0x09A0 /* Metric Counter 46 + Register */ +#define XAPM_MC47_OFFSET 0x09B0 /* Metric Counter 47 + Register */ + +#define XAPM_SMC0_OFFSET 0x0200 /* Sampled Metric Counter + 0 Register */ +#define XAPM_SINC0_OFFSET 0x0204 /* Sampled Incrementer + 0 Register */ +#define XAPM_SMC1_OFFSET 0x0210 /* Sampled Metric Counter + 1 Register */ +#define XAPM_SINC1_OFFSET 0x0214 /* Sampled Incrementer + 1 Register */ +#define XAPM_SMC2_OFFSET 0x0220 /* Sampled Metric Counter + 2 Register */ +#define XAPM_SINC2_OFFSET 0x0224 /* Sampled Incrementer + 2 Register */ +#define XAPM_SMC3_OFFSET 0x0230 /* Sampled Metric Counter + 3 Register */ +#define XAPM_SINC3_OFFSET 0x0234 /* Sampled Incrementer + 3 Register */ +#define XAPM_SMC4_OFFSET 0x0240 /* Sampled Metric Counter + 4 Register */ +#define XAPM_SINC4_OFFSET 0x0244 /* Sampled Incrementer + 4 Register */ +#define XAPM_SMC5_OFFSET 0x0250 /* Sampled Metric Counter + 5 Register */ +#define XAPM_SINC5_OFFSET 0x0254 /* Sampled Incrementer + 5 Register */ +#define XAPM_SMC6_OFFSET 0x0260 /* Sampled Metric Counter + 6 Register */ +#define XAPM_SINC6_OFFSET 0x0264 /* Sampled Incrementer + 6 Register */ +#define XAPM_SMC7_OFFSET 0x0270 /* Sampled Metric Counter + 7 Register */ +#define XAPM_SINC7_OFFSET 0x0274 /* Sampled Incrementer + 7 Register */ +#define XAPM_SMC8_OFFSET 0x0280 /* Sampled Metric Counter + 8 Register */ +#define XAPM_SINC8_OFFSET 0x0284 /* Sampled Incrementer + 8 Register */ +#define XAPM_SMC9_OFFSET 0x0290 /* Sampled Metric Counter + 9 Register */ +#define XAPM_SINC9_OFFSET 0x0294 /* Sampled Incrementer + 9 Register */ +#define XAPM_SMC10_OFFSET 0x02A0 /* Sampled Metric Counter + 10 Register */ +#define XAPM_SMC11_OFFSET 0x02B0 /* Sampled Metric Counter + 11 Register */ +#define XAPM_SMC12_OFFSET 0x0600 /* Sampled Metric Counter + 12 Register */ +#define XAPM_SMC13_OFFSET 0x0610 /* Sampled Metric Counter + 13 Register */ +#define XAPM_SMC14_OFFSET 0x0620 /* Sampled Metric Counter + 14 Register */ +#define XAPM_SMC15_OFFSET 0x0630 /* Sampled Metric Counter + 15 Register */ +#define XAPM_SMC16_OFFSET 0x0640 /* Sampled Metric Counter + 16 Register */ +#define XAPM_SMC17_OFFSET 0x0650 /* Sampled Metric Counter + 17 Register */ +#define XAPM_SMC18_OFFSET 0x0660 /* Sampled Metric Counter + 18 Register */ +#define XAPM_SMC19_OFFSET 0x0670 /* Sampled Metric Counter + 19 Register */ +#define XAPM_SMC20_OFFSET 0x0680 /* Sampled Metric Counter + 20 Register */ +#define XAPM_SMC21_OFFSET 0x0690 /* Sampled Metric Counter + 21 Register */ +#define XAPM_SMC22_OFFSET 0x06A0 /* Sampled Metric Counter + 22 Register */ +#define XAPM_SMC23_OFFSET 0x06B0 /* Sampled Metric Counter + 23 Register */ +#define XAPM_SMC24_OFFSET 0x0800 /* Sampled Metric Counter + 24 Register */ +#define XAPM_SMC25_OFFSET 0x0810 /* Sampled Metric Counter + 25 Register */ +#define XAPM_SMC26_OFFSET 0x0820 /* Sampled Metric Counter + 26 Register */ +#define XAPM_SMC27_OFFSET 0x0830 /* Sampled Metric Counter + 27 Register */ +#define XAPM_SMC28_OFFSET 0x0840 /* Sampled Metric Counter + 28 Register */ +#define XAPM_SMC29_OFFSET 0x0850 /* Sampled Metric Counter + 29 Register */ +#define XAPM_SMC30_OFFSET 0x0860 /* Sampled Metric Counter + 30 Register */ +#define XAPM_SMC31_OFFSET 0x0870 /* Sampled Metric Counter + 31 Register */ +#define XAPM_SMC32_OFFSET 0x0880 /* Sampled Metric Counter + 32 Register */ +#define XAPM_SMC33_OFFSET 0x0890 /* Sampled Metric Counter + 33 Register */ +#define XAPM_SMC34_OFFSET 0x08A0 /* Sampled Metric Counter + 34 Register */ +#define XAPM_SMC35_OFFSET 0x08B0 /* Sampled Metric Counter + 35 Register */ +#define XAPM_SMC36_OFFSET 0x0A00 /* Sampled Metric Counter + 36 Register */ +#define XAPM_SMC37_OFFSET 0x0A10 /* Sampled Metric Counter + 37 Register */ +#define XAPM_SMC38_OFFSET 0x0A20 /* Sampled Metric Counter + 38 Register */ +#define XAPM_SMC39_OFFSET 0x0A30 /* Sampled Metric Counter + 39 Register */ +#define XAPM_SMC40_OFFSET 0x0A40 /* Sampled Metric Counter + 40 Register */ +#define XAPM_SMC41_OFFSET 0x0A50 /* Sampled Metric Counter + 41 Register */ +#define XAPM_SMC42_OFFSET 0x0A60 /* Sampled Metric Counter + 42 Register */ +#define XAPM_SMC43_OFFSET 0x0A70 /* Sampled Metric Counter + 43 Register */ +#define XAPM_SMC44_OFFSET 0x0A80 /* Sampled Metric Counter + 44 Register */ +#define XAPM_SMC45_OFFSET 0x0A90 /* Sampled Metric Counter + 45 Register */ +#define XAPM_SMC46_OFFSET 0x0AA0 /* Sampled Metric Counter + 46 Register */ +#define XAPM_SMC47_OFFSET 0x0AB0 /* Sampled Metric Counter + 47 Register */ + +#define XAPM_CTL_OFFSET 0x0300 /* Control Register */ + +#define XAPM_ID_OFFSET 0x0304 /* Latency ID Register */ + +#define XAPM_IDMASK_OFFSET 0x0308 /* ID Mask Register */ + +#define XAPM_FEC_OFFSET 0x0400 /* flag Enable + Control Register */ + +#define XAPM_SWD_OFFSET 0x0404 /* Software-written + Data Register */ + +#define XAPM_SICR_MCNTR_RST_MASK 0x00000100 /* Enable the Metric + Counter Reset */ +#define XAPM_SICR_LOAD_MASK 0x00000002 /* Load the Sample Interval + Register Value into + the counter */ +#define XAPM_SICR_ENABLE_MASK 0x00000001 /* Enable the downcounter */ + +#define XAPM_IXR_MC9_OVERFLOW_MASK 0x00001000 /**< Metric Counter 9 + * Overflow> */ +#define XAPM_IXR_MC8_OVERFLOW_MASK 0x00000800 /**< Metric Counter 8 + * Overflow> */ +#define XAPM_IXR_MC7_OVERFLOW_MASK 0x00000400 /**< Metric Counter 7 + * Overflow> */ +#define XAPM_IXR_MC6_OVERFLOW_MASK 0x00000200 /**< Metric Counter 6 + * Overflow> */ +#define XAPM_IXR_MC5_OVERFLOW_MASK 0x00000100 /**< Metric Counter 5 + * Overflow> */ +#define XAPM_IXR_MC4_OVERFLOW_MASK 0x00000080 /**< Metric Counter 4 + * Overflow> */ +#define XAPM_IXR_MC3_OVERFLOW_MASK 0x00000040 /**< Metric Counter 3 + * Overflow> */ +#define XAPM_IXR_MC2_OVERFLOW_MASK 0x00000020 /**< Metric Counter 2 + * Overflow> */ +#define XAPM_IXR_MC1_OVERFLOW_MASK 0x00000010 /**< Metric Counter 1 + * Overflow> */ +#define XAPM_IXR_MC0_OVERFLOW_MASK 0x00000008 /**< Metric Counter 0 + * Overflow> */ +#define XAPM_IXR_FIFO_FULL_MASK 0x00000004 /**< Event Log FIFO + * full> */ +#define XAPM_IXR_SIC_OVERFLOW_MASK 0x00000002 /**< Sample Interval + * Counter Overflow */ +#define XAPM_IXR_GCC_OVERFLOW_MASK 0x00000001 /**< Global Clock + Counter Overflow */ +#define XAPM_IXR_ALL_MASK (XAPM_IXR_SIC_OVERFLOW_MASK | \ + XAPM_IXR_GCC_OVERFLOW_MASK | \ + XAPM_IXR_FIFO_FULL_MASK | \ + XAPM_IXR_MC0_OVERFLOW_MASK | \ + XAPM_IXR_MC1_OVERFLOW_MASK | \ + XAPM_IXR_MC2_OVERFLOW_MASK | \ + XAPM_IXR_MC3_OVERFLOW_MASK | \ + XAPM_IXR_MC4_OVERFLOW_MASK | \ + XAPM_IXR_MC5_OVERFLOW_MASK | \ + XAPM_IXR_MC6_OVERFLOW_MASK | \ + XAPM_IXR_MC7_OVERFLOW_MASK | \ + XAPM_IXR_MC8_OVERFLOW_MASK | \ + XAPM_IXR_MC9_OVERFLOW_MASK) + +#define XAPM_CR_FIFO_RESET_MASK 0x02000000 + /**< FIFO Reset */ +#define XAPM_CR_MUXSEL_MASK 0x01000000 + /**< Mux Selector mask */ +#define XAPM_CR_GCC_RESET_MASK 0x00020000 + /**< Global Clk + Counter Reset */ +#define XAPM_CR_GCC_ENABLE_MASK 0x00010000 + /**< Global Clk + Counter Enable */ +#define XAPM_CR_EVTLOG_EXTTRIGGER_MASK 0x00000200 + /**< Enable External trigger + to start event Log */ +#define XAPM_CR_EVENTLOG_ENABLE_MASK 0x00000100 + /**< Event Log Enable */ +#define XAPM_CR_RDLATENCY_END_MASK 0x00000080 + /**< Write Latency + End point */ +#define XAPM_CR_RDLATENCY_START_MASK 0x00000040 + /**< Read Latency + Start point */ +#define XAPM_CR_WRLATENCY_END_MASK 0x00000020 + /**< Write Latency + End point */ +#define XAPM_CR_WRLATENCY_START_MASK 0x00000010 + /**< Write Latency + Start point */ +#define XAPM_CR_IDFILTER_ENABLE_MASK 0x00000008 + /**< ID Filter Enable */ +#define XAPM_CR_MCNTR_EXTTRIGGER_MASK 0x00000004 + /**< Enable External + trigger to start + Metric Counters */ +#define XAPM_CR_MCNTR_RESET_MASK 0x00000002 + /**< Metrics Counter + Reset */ +#define XAPM_CR_MCNTR_ENABLE_MASK 0x00000001 + /**< Metrics Counter + Enable */ + +#define XAPM_ID_RID_MASK 0xFFFF0000 /**< Read ID */ + +#define XAPM_ID_WID_MASK 0x0000FFFF /**< Write ID */ + +#define XAPM_MASKID_RID_MASK 0xFFFF0000 /**< Read ID Mask */ + +#define XAPM_MASKID_WID_MASK 0x0000FFFF /**< Write ID Mask*/ + + +#define XAPM_MAX_COUNTERS 10 /**< Maximum number of Counters */ +#define XAPM_MAX_COUNTERS_PROFILE 48 /**< Maximum number of Counters in + profile mode */ + +#define XAPM_METRIC_COUNTER_0 0 /**< Metric Counter 0 Register Index */ +#define XAPM_METRIC_COUNTER_1 1 /**< Metric Counter 1 Register Index */ +#define XAPM_METRIC_COUNTER_2 2 /**< Metric Counter 2 Register Index */ +#define XAPM_METRIC_COUNTER_3 3 /**< Metric Counter 3 Register Index */ +#define XAPM_METRIC_COUNTER_4 4 /**< Metric Counter 4 Register Index */ +#define XAPM_METRIC_COUNTER_5 5 /**< Metric Counter 5 Register Index */ +#define XAPM_METRIC_COUNTER_6 6 /**< Metric Counter 6 Register Index */ +#define XAPM_METRIC_COUNTER_7 7 /**< Metric Counter 7 Register Index */ +#define XAPM_METRIC_COUNTER_8 8 /**< Metric Counter 8 Register Index */ +#define XAPM_METRIC_COUNTER_9 9 /**< Metric Counter 9 Register Index */ + +#define XAPM_INCREMENTER_0 0 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_1 1 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_2 2 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_3 3 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_4 4 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_5 5 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_6 6 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_7 7 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_8 8 /**< Metric Counter 0 Register Index */ +#define XAPM_INCREMENTER_9 9 /**< Metric Counter 0 Register Index */ + +#define XAPM_METRIC_SET_0 0 /**< Write Transaction Count */ +#define XAPM_METRIC_SET_1 1 /**< Read Transaction Count */ +#define XAPM_METRIC_SET_2 2 /**< Write Byte Count */ +#define XAPM_METRIC_SET_3 3 /**< Read Byte Count */ +#define XAPM_METRIC_SET_4 4 /**< Write Beat Count */ +#define XAPM_METRIC_SET_5 5 /**< Total Read Latency */ +#define XAPM_METRIC_SET_6 6 /**< Total Write Latency */ +#define XAPM_METRIC_SET_7 7 /**< Slv_Wr_Idle_Cnt */ +#define XAPM_METRIC_SET_8 8 /**< Mst_Rd_Idle_Cnt */ +#define XAPM_METRIC_SET_9 9 /**< Num_BValids */ +#define XAPM_METRIC_SET_10 10 /**< Num_WLasts */ +#define XAPM_METRIC_SET_11 11 /**< Num_RLasts */ +#define XAPM_METRIC_SET_12 12 /**< Minimum Write Latency */ +#define XAPM_METRIC_SET_13 13 /**< Maximum Write Latency */ +#define XAPM_METRIC_SET_14 14 /**< Minimum Read Latency */ +#define XAPM_METRIC_SET_15 15 /**< Maximum Read Latency */ +#define XAPM_METRIC_SET_16 16 /**< Transfer Cycle Count */ +#define XAPM_METRIC_SET_17 17 /**< Packet Count */ +#define XAPM_METRIC_SET_18 18 /**< Data Byte Count */ +#define XAPM_METRIC_SET_19 19 /**< Position Byte Count */ +#define XAPM_METRIC_SET_20 20 /**< Null Byte Count */ +#define XAPM_METRIC_SET_21 21 /**< Slv_Idle_Cnt */ +#define XAPM_METRIC_SET_22 22 /**< Mst_Idle_Cnt */ +#define XAPM_METRIC_SET_30 30 /**< External event count */ + +#define XAPM_MAX_AGENTS 8 /**< Maximum number of Agents */ + +#define XAPM_FLAG_WRADDR 0x00000001 /**< Write Address flag */ +#define XAPM_FLAG_FIRSTWR 0x00000002 /**< First Write flag */ +#define XAPM_FLAG_LASTWR 0x00000004 /**< Last Write flag */ +#define XAPM_FLAG_RESPONSE 0x00000008 /**< Response flag */ +#define XAPM_FLAG_RDADDR 0x00000010 /**< Read Address flag */ +#define XAPM_FLAG_FIRSTRD 0x00000020 /**< First Read flag */ +#define XAPM_FLAG_LASTRD 0x00000040 /**< Last Read flag */ +#define XAPM_FLAG_SWDATA 0x00010000 /**< Software-written Data flag */ +#define XAPM_FLAG_EVENT 0x00020000 /**< Last Read flag */ +#define XAPM_FLAG_EVNTSTOP 0x00040000 /**< Last Read flag */ +#define XAPM_FLAG_EVNTSTART 0x00080000 /**< Last Read flag */ +#define XAPM_FLAG_GCCOVF 0x00100000 /**< Global Clock Counter Overflow + * flag */ +#define XAPM_FLAG_SCLAPSE 0x00200000 /**< Sample Counter Lapse flag */ +#define XAPM_FLAG_MC0 0x00400000 /**< Metric Counter 0 flag */ +#define XAPM_FLAG_MC1 0x00800000 /**< Metric Counter 1 flag */ +#define XAPM_FLAG_MC2 0x01000000 /**< Metric Counter 2 flag */ +#define XAPM_FLAG_MC3 0x02000000 /**< Metric Counter 3 flag */ +#define XAPM_FLAG_MC4 0x04000000 /**< Metric Counter 4 flag */ +#define XAPM_FLAG_MC5 0x08000000 /**< Metric Counter 5 flag */ +#define XAPM_FLAG_MC6 0x10000000 /**< Metric Counter 6 flag */ +#define XAPM_FLAG_MC7 0x20000000 /**< Metric Counter 7 flag */ +#define XAPM_FLAG_MC8 0x40000000 /**< Metric Counter 8 flag */ +#define XAPM_FLAG_MC9 0x80000000 /**< Metric Counter 9 flag */ + +#define XAPM_LATENCY_ADDR_ISSUE 0 /**< Address Issue as start + point for Latency calculation*/ +#define XAPM_LATENCY_ADDR_ACCEPT 1 /**< Address Acceptance as start + point for Latency calculation*/ +#define XAPM_LATENCY_LASTRD 0 /**< Last Read as end point for + Latency calculation */ +#define XAPM_LATENCY_LASTWR 0 /**< Last Write as end point for + Latency calculation */ +#define XAPM_LATENCY_FIRSTRD 1 /**< First Read as end point for + Latency calculation */ +#define XAPM_LATENCY_FIRSTWR 1 /**< First Write as end point for + Latency calculation */ + +#define XAPM_MODE_TRACE 2 /**< APM in Trace mode */ + +#define XAPM_MODE_PROFILE 1 /**< APM in Profile mode */ + +#define XAPM_MODE_ADVANCED 0 /**< APM in Advanced mode */ + +typedef unsigned char u8; +typedef uint16_t u16; +typedef uint32_t u32; + +u32 baseaddr; + +struct xapm_param { + u32 mode; + u32 maxslots; + u32 eventcnt; + u32 eventlog; + u32 sampledcnt; + u32 numcounters; + u32 metricwidth; + u32 sampledwidth; + u32 globalcntwidth; + u32 scalefactor; + u32 isr; +}; + +static struct xapm_param *params; + +/*****************************************************************************/ +/** +* +* Read a register of the AXI Performance Monitor device. This macro provides +* register access to all registers using the register offsets defined above. +* +* @param baseaddr contains the base address of the device. +* @param regoffset is the offset of the register to read. +* +* @return The contents of the register. +* +* @note C-style Signature: +* u32 readreg(u32 baseaddr, u32 regoffset); +* +******************************************************************************/ +#define readreg(baseaddr, regoffset) \ + (*(u32 *)(baseaddr + regoffset)) + +/*****************************************************************************/ +/** +* +* Write a register of the AXI Performance Monitor device. This macro provides +* register access to all registers using the register offsets defined above. +* +* @param baseaddr contains the base address of the device. +* @param regoffset is the offset of the register to write. +* @param data is the value to write to the register. +* +* @return None. +* +* @note C-style Signature: +* void writereg(u32 baseaddr, +* u32 regoffset,u32 Data) +* +******************************************************************************/ +#define writereg(baseaddr, regoffset, data) \ + (*(u32 *)(baseaddr + regoffset) = data) + +/****************************************************************************/ +/** +* +* This routine enables the Global Interrupt. +* +* @note C-Style signature: +* void intrglobalenable() +* +*****************************************************************************/ +#define intrglobalenable() \ + writereg(baseaddr, XAPM_GIE_OFFSET, 1) + + +/****************************************************************************/ +/** +* +* This routine disables the Global Interrupt. +* +* @note C-Style signature: +* void intrglobaldisable(void) +* +*****************************************************************************/ +#define intrglobaldisable() \ + writereg(baseaddr, XAPM_GIE_OFFSET, 0) + +/****************************************************************************/ +/** +* +* This routine enables interrupt(s). Use the XAPM_IXR_* constants defined in +* xaxipmon_hw.h to create the bit-mask to enable interrupts. +* +* @param mask is the mask to enable. Bit positions of 1 will be enabled. +* Bit positions of 0 will keep the previous setting. This mask is +* formed by OR'ing XAPM_IXR__* bits defined in xaxipmon_hw.h. +* +* @return None. +* +* @note C-Style signature: +* void intrenable(u32 mask) +* +*****************************************************************************/ +#define intrenable(mask) \ + writereg(baseaddr, XAPM_IE_OFFSET, readreg(baseaddr, \ + XAPM_IE_OFFSET) | mask); + + +/****************************************************************************/ +/** +* +* This routine disable interrupt(s). Use the XAPM_IXR_* constants defined in +* xaxipmon_hw.h to create the bit-mask to disable interrupts. +* +* @param mask is the mask to disable. Bit positions of 1 will be +* disabled. Bit positions of 0 will keep the previous setting. +* This mask is formed by OR'ing XAPM_IXR_* bits defined in +* xaxipmon_hw.h. +* +* @return None. +* +* @note C-Style signature: +* void intrdisable(u32 mask) +* +*****************************************************************************/ +#define intrdisable(mask) \ + writereg(baseaddr, XAPM_IE_OFFSET, readreg(baseaddr, \ + XAPM_IE_OFFSET) | mask); + +/****************************************************************************/ +/** +* +* This routine clears the specified interrupt(s). +* +* @param mask is the mask to clear. Bit positions of 1 will be cleared. +* This mask is formed by OR'ing XAPM_IXR_* bits defined in +* xaxipmon_hw.h. +* +* @return None. +* +* @note C-Style signature: +* void intrclear(u32 mask) +* +*****************************************************************************/ +#define intrclear(mask) \ + writereg(baseaddr, XAPM_IS_OFFSET, readreg(baseaddr, \ + XAPM_IS_OFFSET) | mask); + +/****************************************************************************/ +/** +* +* This routine returns the Interrupt Status Register. +* +* @return isr value updated by kernel driver +* +* @note This macro returns isr value updated by kernel driver. +* C-Style signature: +* void intrgetstatus(void) +* +*****************************************************************************/ +#define intrgetstatus() (params->isr) + +/****************************************************************************/ +/** +* +* This routine returns the Interrupt Status Register. +* +* @return Interrupt Status Register contents +* +* @note C-Style signature: +* void intrhwgetstatus(void) +* +*****************************************************************************/ +#define intrhwgetstatus() (params->isr) + +/****************************************************************************/ +/** +* +* This function enables the Global Clock Counter. +* +* @note C-Style signature: +* void enablegcc(void); +* +*****************************************************************************/ +#define enablegcc() \ + writereg(baseaddr, XAPM_CTL_OFFSET, readreg(baseaddr, \ + XAPM_CTL_OFFSET) | XAPM_CR_GCC_ENABLE_MASK); + +/****************************************************************************/ +/** +* +* This function disbles the Global Clock Counter. +* +* @note C-Style signature: +* void disablegcc(void); +* +*****************************************************************************/ +#define disablegcc() \ + writereg(baseaddr, XAPM_CTL_OFFSET, readreg(baseaddr, \ + XAPM_CTL_OFFSET) & ~(XAPM_CR_GCC_ENABLE_MASK)); + +/****************************************************************************/ +/** +* +* This function enables the specified flag in flag Control Register. +* +* @param flag is one of the XAPM_FLAG_* masks defined in xaxipmon.h +* +* @return None +* +* @note C-Style signature: +* void enableflag(void); +* +*****************************************************************************/ +#define enableflag(flag) \ + writereg(baseaddr, XAPM_FEC_OFFSET, \ + readreg(baseaddr, XAPM_FEC_OFFSET) | flag); + +/****************************************************************************/ +/** +* +* This function disables the specified flag in flag Control Register. +* +* @param flag is one of the XAPM_FLAG_* masks defined in xaxipmon.h* +* @return None +* +* @note C-Style signature: +* void disableflag(void); +* +*****************************************************************************/ +#define disableflag(flag) \ + writereg(baseaddr, XAPM_FEC_OFFSET, \ + readreg(baseaddr, XAPM_FEC_OFFSET) & ~(flag)); + +/****************************************************************************/ +/** +* +* This function loads the sample interval register value into the sample +* interval counter. +* +* @note C-Style signature: +* void loadsic(void); +* +*****************************************************************************/ +#define loadsic() \ + writereg(baseaddr, XAPM_SICR_OFFSET, XAPM_SICR_LOAD_MASK) + + +/****************************************************************************/ +/** +* +* This enables the down count of the sample interval counter. +* +* @note C-Style signature: +* void enablesic(void); +* +*****************************************************************************/ +#define enablesic() \ + writereg(baseaddr, XAPM_SICR_OFFSET, XAPM_SICR_ENABLE_MASK) + +/****************************************************************************/ +/** +* +* This disables the down count of the sample interval counter. +* +* @note C-Style signature: +* void disablesic(void); +* +*****************************************************************************/ +#define disablesic() \ + writereg(baseaddr, XAPM_SICR_OFFSET, \ + readreg(baseaddr, XAPM_SICR_OFFSET) & ~(XAPM_SICR_ENABLE_MASK)); + +/****************************************************************************/ +/** +* +* This enables Reset of Metric Counters when Sample Interval Counter lapses. +* +* @note C-Style signature: +* void enablemcreset(void); +* +*****************************************************************************/ +#define enablemcreset() \ + writereg(baseaddr, XAPM_SICR_OFFSET, XAPM_SICR_MCNTR_RST_MASK); + +/****************************************************************************/ +/** +* +* This disables the down count of the sample interval counter. +* +* @note C-Style signature: +* void disablemcreset(void); +* +*****************************************************************************/ +#define disablemcreset() \ + writereg(baseaddr, XAPM_SICR_OFFSET, \ + readreg(baseaddr, XAPM_SICR_OFFSET) & ~(XAPM_SICR_MCNTR_RST_MASK)); + +/****************************************************************************/ +/** +* +* This function enables the ID Filter Masking. +* +* @note C-Style signature: +* void enableidfilter(void); +* +*****************************************************************************/ +#define enableidfilter() \ + writereg(baseaddr, XAPM_CTL_OFFSET, readreg(baseaddr, \ + XAPM_CTL_OFFSET) | XAPM_CR_IDFILTER_ENABLE_MASK); + +/****************************************************************************/ +/** +* +* This function disbles the ID Filter masking. +* +* @note C-Style signature: +* void disableidfilter(void); +* +*****************************************************************************/ +#define disableidfilter() \ + writereg(baseaddr, XAPM_CTL_OFFSET, readreg(baseaddr, \ + XAPM_CTL_OFFSET) & ~(XAPM_CR_IDFILTER_ENABLE_MASK)); + +/****************************************************************************/ +/** +* +* This function samples Metric Counters to Sampled Metric Counters by +* reading Sample Register and also returns interval. i.e. the number of +* clocks in between previous read to the current read of sample register. +* +* @return Interval. i.e. the number of clocks in between previous +* read to the current read of sample register. +* +* @note C-Style signature: +* u32 samplemetrics(void); +* +*****************************************************************************/ +#define samplemetrics() readreg(baseaddr, XAPM_SR_OFFSET); + + +/************************** Function Prototypes *****************************/ + +int resetmetriccounter(void); + +void resetglobalclkcounter(void); + +int resetfifo(void); + +void setincrementerrange(u8 incrementer, u16 rangehigh, u16 rangelow); + +void getincrementerrange(u8 incrementer, u16 *rangehigh, u16 *rangelow); + +void setsampleinterval(u32 sampleinterval); + +void getsampleinterval(u32 *sampleinterval); + +int setmetrics(u8 slot, u8 metrics, u8 counter); + +int getmetrics(u8 counter, u8 *metrics, u8 *slot); +void getglobalclkcounter(u32 *cnthigh, u32 *cntlow); + +u32 getmetriccounter(u32 counter); + +u32 getsampledmetriccounter(u32 counter); + +u32 getincrementer(u32 incrementer); + +u32 getsampledincrementer(u32 incrementer); + +void setswdatareg(u32 swdata); + +u32 getswdatareg(void); + +int starteventlog(u32 flagenables); + +int stopeventlog(void); + +int startcounters(u32 sampleinterval); + +int stopcounters(void); + +void enablemetricscounter(void); + +void disablemetricscounter(void); + +void setlogenableranges(u32 counter, u16 rangehigh, u16 rangelow); + +void getlogenableranges(u32 counter, u16 *rangehigh, u16 *rangelow); + +void enableeventlog(void); + +void enablemctrigger(void); + +void disablemctrigger(void); + +void enableeventlogtrigger(void); + +void disableeventlogtrigger(void); + +const char *getmetricname(u8 metrics); + +void setwriteid(u16 writeid); + +void setreadid(u16 readid); + +u16 getwriteid(void); + +u16 getreadid(void); + +void setwrlatencystart(u8 param); + +void setwrlatencyend(u8 param); + +void setrdlatencystart(u8 param); + +void setrdlatencyend(u8 param); + +u8 getwrlatencystart(void); + +u8 getwrlatencyend(void); + +u8 getrdlatencystart(void); + +u8 getrdlatencyend(void); + +void setwriteidmask(u16 wrmask); + +void setreadidmask(u16 rdmask); + +u16 getwriteidmask(void); + +u16 getreadidmask(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* End of protection macro. */ Index: linux-3.12.24-rt38-xilinx/scripts/package/builddeb =================================================================== --- linux-3.12.24-rt38-xilinx.orig/scripts/package/builddeb 2014-07-20 22:05:50.325065152 +0200 +++ linux-3.12.24-rt38-xilinx/scripts/package/builddeb 2014-07-20 22:06:39.997245662 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:82 @ kernel_headers_dir="$objtree/debian/hdrtmp" libc_headers_dir="$objtree/debian/headertmp" dbg_dir="$objtree/debian/dbgtmp" -packagename=linux-image-$version -fwpackagename=linux-firmware-image-$version -kernel_headers_packagename=linux-headers-$version +packagename=linux-image-zedboard-$version +fwpackagename=linux-firmware-image-zedboard-$version +kernel_headers_packagename=linux-headers-zedboard-$version libc_headers_packagename=linux-libc-dev dbg_packagename=$packagename-dbg @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:139 @ fi # Not all arches include the boot path in KBUILD_IMAGE if [ -e $KBUILD_IMAGE ]; then - cp $KBUILD_IMAGE "$tmpdir/$installed_image_path" + cp $KBUILD_IMAGE "$tmpdir/boot/" else - cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/$installed_image_path" + cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/boot/" fi +cp arch/arm/boot/dts/zynq-zed.dtb "$tmpdir/boot/" + if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then INSTALL_MOD_PATH="$tmpdir" $MAKE KBUILD_SRC= modules_install rm -f "$tmpdir/lib/modules/$version/build" @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:212 @ fi maintainer="$name <$email>" +mkdir -p debian/source +# Generate a source format template +cat <<EOF > debian/source/format +3.0 (git) +EOF + +# Generate the source option file +cat <<EOF > debian/source/options +git-ref=HEAD +git-depth=3 +EOF + # Generate a simple changelog template cat <<EOF > debian/changelog -linux-upstream ($packageversion) unstable; urgency=low +$packagename ($KDEB_PKGVERSION) unstable; urgency=low * Custom built Linux kernel. @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:255 @ # Generate a control file cat <<EOF > debian/control -Source: linux-upstream +Source: $packagename Section: kernel Priority: optional Maintainer: $maintainer @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:325 @ cat <<EOF >> debian/control Package: $fwpackagename -Architecture: all +Architecture: any Description: Linux kernel firmware, version $version This package contains firmware from the Linux kernel, version $version. EOF @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:377 @ create_package "$dbg_packagename" "$dbg_dir" fi +if [ -x source ] ; then + mkdir -p source/debian + cp debian/changelog source/debian/ + cp debian/control source/debian/ + cp debian/copyright source/debian/ + cp -a debian/source source/debian/ + cp .config source/config + cd source + git add -f debian/changelog + git add -f debian/control + git add -f debian/copyright + git add -f debian/source + git commit -sm "add debian directory" + git add -f config + git commit -sm "add kernel config" + dpkg-source -b . + + git reset --hard HEAD~2 +else + cp .config config + git add -f debian/changelog + git add -f debian/control + git add -f debian/copyright + git add -f debian/source + git commit -sm "add debian directory" + git add -f config + git commit -sm "add kernel config" + + dpkg-source -b . + + git reset --hard HEAD~2 +fi + exit 0 Index: linux-3.12.24-rt38-xilinx/scripts/sortextable.c =================================================================== --- linux-3.12.24-rt38-xilinx.orig/scripts/sortextable.c 2014-07-20 22:05:50.324065169 +0200 +++ linux-3.12.24-rt38-xilinx/scripts/sortextable.c 2014-07-20 22:06:40.007245497 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:38 @ #define EM_AARCH64 183 #endif +#ifndef EM_MICROBLAZE +#define EM_MICROBLAZE 189 +#endif + static int fd_map; /* File descriptor for file being modified. */ static int mmap_failed; /* Boolean flag. */ static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:253 @ break; case EM_ARM: case EM_AARCH64: + case EM_MICROBLAZE: case EM_MIPS: break; } /* end switch */ Index: linux-3.12.24-rt38-xilinx/tools/rpmsg_proto.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/tools/rpmsg_proto.c 2014-07-20 22:06:40.018245315 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "../include/net/rpmsg.h" + +#define M3_CORE0 (0) + +int main(void) +{ + int sock, sock2, err; + struct sockaddr_rpmsg src_addr, dst_addr; + socklen_t len; + const char *msg = "Hello there!"; + char buf[512]; + + /* create an RPMSG socket */ + sock = socket(AF_RPMSG, SOCK_SEQPACKET, 0); + if (sock < 0) { + printf("socket failed: %s (%d)\n", strerror(errno), errno); + return -1; + } + + /* connect to remote service */ + memset(&dst_addr, 0, sizeof(dst_addr)); + dst_addr.family = AF_RPMSG; + dst_addr.vproc_id = M3_CORE0; + dst_addr.addr = 51; + + printf("Connecting to address 0x%x on processor %d\n", + dst_addr.addr, dst_addr.vproc_id); + + len = sizeof(struct sockaddr_rpmsg); + err = connect(sock, (struct sockaddr *)&dst_addr, len); + if (err < 0) { + printf("connect failed: %s (%d)\n", strerror(errno), errno); + return -1; + } + + /* let's see what local address did we get */ + err = getsockname(sock, (struct sockaddr *)&src_addr, &len); + if (err < 0) { + printf("getpeername failed: %s (%d)\n", strerror(errno), errno); + return -1; + } + + printf("Our address: socket family: %d, proc id = %d, addr = %d\n", + src_addr.family, src_addr.vproc_id, src_addr.addr); + + printf("Sending \"%s\"\n", msg); + err = send(sock, msg, strlen(msg) + 1, 0); + if (err < 0) { + printf("sendto failed: %s (%d)\n", strerror(errno), errno); + return -1; + } + + memset(&src_addr, 0, sizeof(src_addr)); + + len = sizeof(src_addr); + + err = recvfrom(sock, buf, sizeof(buf), 0, + (struct sockaddr *)&src_addr, &len); + if (err < 0) { + printf("recvfrom failed: %s (%d)\n", strerror(errno), errno); + return -1; + } + if (len != sizeof(src_addr)) { + printf("recvfrom: got bad addr len (%d)\n", len); + return -1; + } + + printf("Received a msg from address 0x%x on processor %d\n", + src_addr.addr, src_addr.vproc_id); + printf("Message content: \"%s\".\n", buf); + + + close(sock); + + /* create another RPMSG socket */ + sock2 = socket(AF_RPMSG, SOCK_SEQPACKET, 0); + if (sock2 < 0) { + printf("socket failed: %s (%d)\n", strerror(errno), errno); + return -1; + } + + /* bind a local addr */ + memset(&src_addr, 0, sizeof(src_addr)); + src_addr.family = AF_RPMSG; + src_addr.vproc_id = M3_CORE0; + src_addr.addr = 99; + + + printf("Exposing address %d to processor %d\n", + src_addr.addr, src_addr.vproc_id); + + len = sizeof(struct sockaddr_rpmsg); + err = bind(sock2, (struct sockaddr *)&src_addr, len); + if (err < 0) { + printf("bind failed: %s (%d)\n", strerror(errno), errno); + return -1; + } + + /* let's see what local address did we bind */ + err = getsockname(sock2, (struct sockaddr *)&src_addr, &len); + if (err < 0) { + printf("getpeername failed: %s (%d)\n", strerror(errno), errno); + return -1; + } + + printf("Our address: socket family: %d, proc id = %d, addr = %d\n", + src_addr.family, src_addr.vproc_id, src_addr.addr); + + return 0; +} Index: linux-3.12.24-rt38-xilinx/tools/test_rpmsg_omx.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-3.12.24-rt38-xilinx/tools/test_rpmsg_omx.c 2014-07-20 22:06:40.026245183 +0200 @ linux-3.12.24-rt38-xilinx/arch/arm/boot/bootp/Makefile:4 @ +/* + * test_rpmsg_omx + * + * user space testing tool for the rpmsg_omx driver + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * Ohad Ben-Cohen <ohad@wizery.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> +#include <sys/eventfd.h> + +#include "../include/linux/rpmsg_omx.h" + +static pthread_t listener; +static int omxfd; +static int die_now_fd; + +static void *listener_cb(void *arg) +{ + fd_set rfds; + struct timeval tv; + int ret = 0, maxfd; + char buf[512]; + + do { + /* Wait for OMX messages or self die_now notification */ + FD_ZERO(&rfds); + FD_SET(omxfd, &rfds); + FD_SET(die_now_fd, &rfds); + + maxfd = (die_now_fd > omxfd ? die_now_fd : omxfd) + 1; + ret = select(maxfd, &rfds, NULL, NULL, NULL); + if (ret == -1) { + perror("select()"); + break; + } + + if (FD_ISSET(omxfd, &rfds)) { + ret = read(omxfd, buf, sizeof(buf)); + if (ret < 0) { + perror("Can't connect to OMX instance"); + break; + } + + printf("RX: %s\n", buf); + } + + if (FD_ISSET(die_now_fd, &rfds)) { + printf("Need to die!\n"); + break; + } + + } while (1); + + return (void *)ret; +} + +int send_messages(void) +{ + const char *msg = "Hello there!"; + int ret, i; + + /* blather */ + for (i = 0; i < 10; i++) { + ret = write(omxfd, msg, strlen(msg) + 1); + if (ret < 0) { + perror("Can't connect to OMX instance"); + return -1; + } + + printf("TX: %s\n", msg); + sleep(5); + } + + return i; +} + +int main(void) +{ + int ret; + uint64_t die_event = 1; + ssize_t s; + struct omx_conn_req connreq = { .name = "OMX" }; + + /* open the first OMX device */ + omxfd = open("/dev/rpmsg-omx0", O_RDWR); + if (omxfd < 0) { + perror("Can't open OMX device"); + return 1; + } + + printf("Connecting to %s\n", connreq.name); + /* connect to an h264_decode instance */ + ret = ioctl(omxfd, OMX_IOCCONNECT, &connreq); + if (ret < 0) { + perror("Can't connect to OMX instance"); + return 1; + } + + printf("Connected!\n", connreq.name); + + die_now_fd = eventfd(0, 0); + if (die_now_fd < 0) { + perror("eventfd failed"); + return 1; + } + + ret = pthread_create(&listener, NULL, listener_cb, NULL); + if (ret) { + printf("can't spawn thread: %s\n", strerror(ret)); + return 1; + } + + ret = send_messages(); + if (ret < 0) + return 1; + + /* terminate connection and destroy OMX instance */ + ret = close(omxfd); + if (ret < 0) { + perror("Can't close OMX fd ??"); + return 1; + } + + s = write(die_now_fd, &die_event, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) { + printf("failed to write die_now event\n"); + return 1; + } + + ret = pthread_join(listener, NULL); + if (ret) { + printf("can't join thread: %s\n", strerror(ret)); + return 1; + } + + printf("Bye!\n"); + + return 0; +}