endif
endif
+ifneq ($(CONFIG_ZYNQ),)
+ifeq ($(CONFIG_SPL),y)
+ALL-y += boot.bin
+endif
+endif
+
+ # Add optional build target if defined in board/cpu/soc headers
+ ifneq ($(CONFIG_BUILD_TARGET),)
+ ALL-y += $(CONFIG_BUILD_TARGET:"%"=%)
+ endif
+
LDFLAGS_u-boot += $(LDFLAGS_FINAL)
ifneq ($(CONFIG_SYS_TEXT_BASE),)
LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE)
--- /dev/null
+ if ZYNQ
+
+ choice
+ prompt "Xilinx Zynq board select"
+
+ config TARGET_ZYNQ_ZED
+ bool "Zynq ZedBoard"
+
+ config TARGET_ZYNQ_MICROZED
+ bool "Zynq MicroZed"
+
+ config TARGET_ZYNQ_ZC70X
+ bool "Zynq ZC702/ZC706 Board"
+
+ config TARGET_ZYNQ_ZC770
+ bool "Zynq ZC770 Board"
+
+ config TARGET_ZYNQ_ZYBO
+ bool "Zynq Zybo Board"
+
++config TARGET_ZYNQ_AFX
++ bool "Zynq AFX Board"
++
++config TARGET_ZYNQ_CSE
++ bool "Zynq CSE Board"
++
+ endchoice
+
+ config SYS_BOARD
+ default "zynq"
+
+ config SYS_VENDOR
+ default "xilinx"
+
+ config SYS_SOC
+ default "zynq"
+
+ config SYS_CONFIG_NAME
+ default "zynq_zed" if TARGET_ZYNQ_ZED
+ default "zynq_microzed" if TARGET_ZYNQ_MICROZED
+ default "zynq_zc70x" if TARGET_ZYNQ_ZC70X
+ default "zynq_zc770" if TARGET_ZYNQ_ZC770
+ default "zynq_zybo" if TARGET_ZYNQ_ZYBO
++ default "zynq_cse" if TARGET_ZYNQ_CSE
++ default "zynq_afx" if TARGET_ZYNQ_AFX
+
+ endif
* first stage bootloader. To get ECC to work all memory has
* been initialized by writing any value.
*/
+ /* cppcheck-suppress nullPointer */
memset((void *)0, 0, 1 * 1024 * 1024);
+
+ gd->ram_size /= 2;
} else {
puts("ECC disabled ");
}
dtb-$(CONFIG_ZYNQ) += zynq-zc702.dtb \
zynq-zc706.dtb \
zynq-zed.dtb \
+ zynq-zybo.dtb \
zynq-microzed.dtb \
++ zynq-cc108.dtb \
zynq-zc770-xm010.dtb \
++ zynq-zc770-xm011.dtb \
zynq-zc770-xm012.dtb \
zynq-zc770-xm013.dtb
dtb-$(CONFIG_AM33XX) += am335x-boneblack.dtb
/*
-- * Xilinx Zynq 7000 DTSI
-- * Describes the hardware common to all Zynq 7000-based boards.
++ * Copyright (C) 2011 - 2015 Xilinx, Inc.
*
-- * Copyright (C) 2013 Xilinx, Inc.
-- *
-- * SPDX-License-Identifier: GPL-2.0+
++ * SPDX-License-Identifier: GPL-2.0+
*/
/include/ "skeleton.dtsi"
reg = <0>;
clocks = <&clkc 3>;
clock-latency = <1000>;
++ cpu0-supply = <®ulator_vccpint>;
operating-points = <
/* kHz uV */
666667 1000000
333334 1000000
-- 222223 1000000
>;
};
reg = < 0xf8891000 0x1000 0xf8893000 0x1000 >;
};
-- amba {
++ regulator_vccpint: fixedregulator@0 {
++ compatible = "regulator-fixed";
++ regulator-name = "VCCPINT";
++ regulator-min-microvolt = <1000000>;
++ regulator-max-microvolt = <1000000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ amba: amba {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
ranges;
-- i2c0: zynq-i2c@e0004000 {
++ adc: adc@f8007100 {
++ compatible = "xlnx,zynq-xadc-1.00.a";
++ reg = <0xf8007100 0x20>;
++ interrupts = <0 7 4>;
++ interrupt-parent = <&intc>;
++ clocks = <&clkc 12>;
++ };
++
++ can0: can@e0008000 {
++ compatible = "xlnx,zynq-can-1.0";
++ status = "disabled";
++ clocks = <&clkc 19>, <&clkc 36>;
++ clock-names = "can_clk", "pclk";
++ reg = <0xe0008000 0x1000>;
++ interrupts = <0 28 4>;
++ interrupt-parent = <&intc>;
++ tx-fifo-depth = <0x40>;
++ rx-fifo-depth = <0x40>;
++ };
++
++ can1: can@e0009000 {
++ compatible = "xlnx,zynq-can-1.0";
++ status = "disabled";
++ clocks = <&clkc 20>, <&clkc 37>;
++ clock-names = "can_clk", "pclk";
++ reg = <0xe0009000 0x1000>;
++ interrupts = <0 51 4>;
++ interrupt-parent = <&intc>;
++ tx-fifo-depth = <0x40>;
++ rx-fifo-depth = <0x40>;
++ };
++
++ gpio0: gpio@e000a000 {
++ compatible = "xlnx,zynq-gpio-1.0";
++ #gpio-cells = <2>;
++ clocks = <&clkc 42>;
++ gpio-controller;
++ interrupt-parent = <&intc>;
++ interrupts = <0 20 4>;
++ reg = <0xe000a000 0x1000>;
++ };
++
++ i2c0: i2c@e0004000 {
compatible = "cdns,i2c-r1p10";
status = "disabled";
clocks = <&clkc 38>;
#size-cells = <0>;
};
-- i2c1: zynq-i2c@e0005000 {
++ i2c1: i2c@e0005000 {
compatible = "cdns,i2c-r1p10";
status = "disabled";
clocks = <&clkc 39>;
intc: interrupt-controller@f8f01000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
-- #address-cells = <1>;
interrupt-controller;
reg = <0xF8F01000 0x1000>,
<0xF8F00100 0x100>;
};
-- L2: cache-controller {
++ L2: cache-controller@f8f02000 {
compatible = "arm,pl310-cache";
reg = <0xF8F02000 0x1000>;
arm,data-latency = <3 2 2>;
cache-level = <2>;
};
-- uart0: uart@e0000000 {
-- compatible = "xlnx,xuartps";
++ mc0: memory-controller@f8006000 {
++ compatible = "xlnx,zynq-ddrc-a05";
++ reg = <0xf8006000 0x1000>;
++ xlnx,has-ecc = <0x0>;
++ };
++
++ ocmc: ocmc@f800c000 {
++ compatible = "xlnx,zynq-ocmc-1.0";
++ interrupt-parent = <&intc>;
++ interrupts = <0 3 4>;
++ reg = <0xf800c000 0x1000>;
++ };
++
++ uart0: serial@e0000000 {
++ compatible = "xlnx,xuartps", "cdns,uart-r1p8";
status = "disabled";
clocks = <&clkc 23>, <&clkc 40>;
-- clock-names = "ref_clk", "aper_clk";
++ clock-names = "uart_clk", "pclk";
reg = <0xE0000000 0x1000>;
interrupts = <0 27 4>;
};
-- uart1: uart@e0001000 {
-- compatible = "xlnx,xuartps";
++ uart1: serial@e0001000 {
++ compatible = "xlnx,xuartps", "cdns,uart-r1p8";
status = "disabled";
clocks = <&clkc 24>, <&clkc 41>;
-- clock-names = "ref_clk", "aper_clk";
++ clock-names = "uart_clk", "pclk";
reg = <0xE0001000 0x1000>;
interrupts = <0 50 4>;
};
++ spi0: spi@e0006000 {
++ compatible = "xlnx,zynq-spi-r1p6";
++ reg = <0xe0006000 0x1000>;
++ status = "disabled";
++ interrupt-parent = <&intc>;
++ interrupts = <0 26 4>;
++ clocks = <&clkc 25>, <&clkc 34>;
++ clock-names = "ref_clk", "pclk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ spi1: spi@e0007000 {
++ compatible = "xlnx,zynq-spi-r1p6";
++ reg = <0xe0007000 0x1000>;
++ status = "disabled";
++ interrupt-parent = <&intc>;
++ interrupts = <0 49 4>;
++ clocks = <&clkc 26>, <&clkc 35>;
++ clock-names = "ref_clk", "pclk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ qspi: spi@e000d000 {
++ clock-names = "ref_clk", "pclk";
++ clocks = <&clkc 10>, <&clkc 43>;
++ compatible = "xlnx,zynq-qspi-1.0";
++ status = "disabled";
++ interrupt-parent = <&intc>;
++ interrupts = <0 19 4>;
++ reg = <0xe000d000 0x1000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ smcc: memory-controller@e000e000 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ status = "disabled";
++ clock-names = "memclk", "aclk";
++ clocks = <&clkc 11>, <&clkc 44>;
++ compatible = "arm,pl353-smc-r2p1";
++ interrupt-parent = <&intc>;
++ interrupts = <0 18 4>;
++ ranges ;
++ reg = <0xe000e000 0x1000>;
++ nand0: flash@e1000000 {
++ status = "disabled";
++ compatible = "arm,pl353-nand-r2p1";
++ reg = <0xe1000000 0x1000000>;
++ #address-cells = <0x1>;
++ #size-cells = <0x1>;
++ };
++ nor0: flash@e2000000 {
++ status = "disabled";
++ compatible = "cfi-flash";
++ reg = <0xe2000000 0x1000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ };
++ };
++
gem0: ethernet@e000b000 {
-- compatible = "cdns,gem";
-- reg = <0xe000b000 0x4000>;
++ compatible = "xlnx,ps7-ethernet-1.00.a";
++ reg = <0xe000b000 0x1000>;
status = "disabled";
interrupts = <0 22 4>;
-- clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>;
-- clock-names = "pclk", "hclk", "tx_clk";
++ clocks = <&clkc 13>, <&clkc 30>;
++ clock-names = "ref_clk", "aper_clk";
++ local-mac-address = [00 0a 35 00 00 00];
++ xlnx,has-mdio = <0x1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
};
gem1: ethernet@e000c000 {
-- compatible = "cdns,gem";
-- reg = <0xe000c000 0x4000>;
++ compatible = "xlnx,ps7-ethernet-1.00.a";
++ reg = <0xe000c000 0x1000>;
status = "disabled";
interrupts = <0 45 4>;
-- clocks = <&clkc 31>, <&clkc 31>, <&clkc 14>;
-- clock-names = "pclk", "hclk", "tx_clk";
++ clocks = <&clkc 14>, <&clkc 31>;
++ clock-names = "ref_clk", "aper_clk";
++ local-mac-address = [00 0a 35 00 00 00];
++ xlnx,has-mdio = <0x1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
};
-- sdhci0: ps7-sdhci@e0100000 {
++ sdhci0: sdhci@e0100000 {
compatible = "arasan,sdhci-8.9a";
status = "disabled";
clock-names = "clk_xin", "clk_ahb";
interrupt-parent = <&intc>;
interrupts = <0 24 4>;
reg = <0xe0100000 0x1000>;
-- } ;
++ };
-- sdhci1: ps7-sdhci@e0101000 {
++ sdhci1: sdhci@e0101000 {
compatible = "arasan,sdhci-8.9a";
status = "disabled";
clock-names = "clk_xin", "clk_ahb";
interrupt-parent = <&intc>;
interrupts = <0 47 4>;
reg = <0xe0101000 0x1000>;
-- } ;
++ };
slcr: slcr@f8000000 {
#address-cells = <1>;
#clock-cells = <1>;
compatible = "xlnx,ps7-clkc";
ps-clk-frequency = <33333333>;
-- fclk-enable = <0>;
++ fclk-enable = <0xf>;
clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
"dci", "lqspi", "smc", "pcap", "gem0", "gem1",
};
};
++ dmac_s: dmac@f8003000 {
++ compatible = "arm,pl330", "arm,primecell";
++ reg = <0xf8003000 0x1000>;
++ interrupt-parent = <&intc>;
++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
++ "dma4", "dma5", "dma6", "dma7";
++ 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>;
++ #dma-cells = <1>;
++ #dma-channels = <8>;
++ #dma-requests = <4>;
++ clocks = <&clkc 27>;
++ clock-names = "apb_pclk";
++ };
++
++ devcfg: devcfg@f8007000 {
++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>;
++ compatible = "xlnx,zynq-devcfg-1.0";
++ interrupt-parent = <&intc>;
++ interrupts = <0 8 4>;
++ reg = <0xf8007000 0x100>;
++ };
++
global_timer: timer@f8f00200 {
compatible = "arm,cortex-a9-global-timer";
reg = <0xf8f00200 0x20>;
clocks = <&clkc 4>;
};
-- ttc0: ttc0@f8001000 {
++ ttc0: timer@f8001000 {
interrupt-parent = <&intc>;
-- interrupts = < 0 10 4 0 11 4 0 12 4 >;
++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
compatible = "cdns,ttc";
clocks = <&clkc 6>;
reg = <0xF8001000 0x1000>;
};
-- ttc1: ttc1@f8002000 {
++ ttc1: timer@f8002000 {
interrupt-parent = <&intc>;
-- interrupts = < 0 37 4 0 38 4 0 39 4 >;
++ interrupts = <0 37 4>, <0 38 4>, <0 39 4>;
compatible = "cdns,ttc";
clocks = <&clkc 6>;
reg = <0xF8002000 0x1000>;
};
-- scutimer: scutimer@f8f00600 {
++
++ scutimer: timer@f8f00600 {
interrupt-parent = <&intc>;
-- interrupts = < 1 13 0x301 >;
++ interrupts = <1 13 0x301>;
compatible = "arm,cortex-a9-twd-timer";
-- reg = < 0xf8f00600 0x20 >;
++ reg = <0xf8f00600 0x20>;
clocks = <&clkc 4>;
-- } ;
++ };
++
++ watchdog0: watchdog@f8005000 {
++ clocks = <&clkc 45>;
++ compatible = "xlnx,zynq-wdt-r1p2";
++ device_type = "watchdog";
++ interrupt-parent = <&intc>;
++ interrupts = <0 9 1>;
++ reg = <0xf8005000 0x1000>;
++ reset = <0>;
++ timeout-sec = <10>;
++ };
++
++ usb0: usb@e0002000 {
++ clocks = <&clkc 28>;
++ compatible = "xlnx,ps7-usb-1.00.a", "xlnx,zynq-usb-1.00.a";
++ status = "disabled";
++ interrupt-parent = <&intc>;
++ interrupts = <0 21 4>;
++ reg = <0xe0002000 0x1000>;
++ };
++
++ usb1: usb@e0003000 {
++ clocks = <&clkc 29>;
++ compatible = "xlnx,ps7-usb-1.00.a", "xlnx,zynq-usb-1.00.a";
++ status = "disabled";
++ interrupt-parent = <&intc>;
++ interrupts = <0 44 4>;
++ reg = <0xe0003000 0x1000>;
++ };
};
};
--- /dev/null
--- /dev/null
++/*
++ * 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/;
++/include/ "zynq-7000.dtsi"
++
++/ {
++ compatible = "xlnx,zynq-cc108", "xlnx,zynq-7000";
++ model = "Xilinx Zynq";
++
++ aliases {
++ ethernet0 = &gem0;
++ serial0 = &uart1;
++ spi0 = &qspi;
++ };
++
++ chosen {
++ bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk";
++ linux,stdout-path = "/amba/serial@e0001000";
++ };
++
++ memory@0 {
++ device_type = "memory";
++ reg = <0x0 0x20000000>;
++ };
++};
++
++&qspi {
++ status = "okay";
++ is-dual = <0>;
++ num-cs = <1>;
++ flash@0 { /* 16 MB */
++ compatible = "n25q128a11";
++ reg = <0x0>;
++ spi-max-frequency = <50000000>;
++ spi-tx-bus-width = <1>;
++ spi-rx-bus-width = <4>;
++ #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 */
++ };
++ };
++};
++
++&usb0 {
++ status = "okay";
++ dr_mode = "peripheral";
++ phy_type = "ulpi";
++ usb-reset = <&gpio0 9 0>;
++};
++
++&usb1 {
++ status = "okay";
++ dr_mode = "host";
++ phy_type = "ulpi";
++};
++
++
++&gem0 {
++ status = "okay";
++ phy-mode = "rgmii-id";
++ phy-handle = <&phy0>;
++
++ phy0: phy@1 {
++ reg = <1>;
++ };
++};
++
++&sdhci1 {
++ status = "okay";
++ broken-cd ;
++ wp-inverted ;
++};
++
++&uart1 {
++ status = "okay";
++};
--- /dev/null
--- /dev/null
++/*
++ * 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/;
++/include/ "zynq-7000.dtsi"
++
++/ {
++ compatible = "xlnx,zynq-zc770-xm011", "xlnx,zynq-7000";
++ model = "Xilinx Zynq";
++
++ aliases {
++ i2c0 = &i2c1;
++ serial0 = &uart1;
++ spi0 = &spi0;
++ };
++
++ chosen {
++ bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk";
++ linux,stdout-path = "/amba/serial@e0001000";
++ };
++
++ memory@0 {
++ device_type = "memory";
++ reg = <0x0 0x40000000>;
++ };
++};
++
++&smcc {
++ status = "okay";
++ arm,addr25 = <0x0>;
++ arm,nor-chip-sel0 = <0x0>;
++ arm,nor-chip-sel1 = <0x0>;
++ arm,sram-chip-sel0 = <0x0>;
++ arm,sram-chip-sel1 = <0x0>;
++};
++
++&nand0 {
++ status = "okay";
++ arm,nand-cycle-t0 = <0x4>;
++ arm,nand-cycle-t1 = <0x4>;
++ arm,nand-cycle-t2 = <0x1>;
++ arm,nand-cycle-t3 = <0x2>;
++ arm,nand-cycle-t4 = <0x2>;
++ arm,nand-cycle-t5 = <0x2>;
++ arm,nand-cycle-t6 = <0x4>;
++
++ 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>;
++ };
++};
++
++&spi0 {
++ status = "okay";
++ num-cs = <4>;
++ is-decoded-cs = <0>;
++};
++
++&usb1 {
++ status = "okay";
++ dr_mode = "host";
++ phy_type = "ulpi";
++};
++
++
++&can0 {
++ status = "okay";
++};
++
++&i2c1 {
++ status = "okay";
++ clock-frequency = <400000>;
++
++ m24c02_eeprom@52 {
++ compatible = "at,24c02";
++ reg = <0x52>;
++ };
++};
++
++&uart1 {
++ status = "okay";
++};
DECLARE_GLOBAL_DATA_PTR;
- int arch_fixup_memory_node(void *blob)
+ int arch_fixup_fdt(void *blob)
{
- bd_t *bd = gd->bd;
- int bank, ret;
- u64 start[CONFIG_NR_DRAM_BANKS];
- u64 size[CONFIG_NR_DRAM_BANKS];
-
- for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
- start[bank] = bd->bi_dram[bank].start;
- size[bank] = bd->bi_dram[bank].size;
- }
-
- ret = fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
-#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT)
- if (ret)
- return ret;
-
- ret = armv7_update_dt(blob);
-#endif
- return ret;
+ return 0;
}
}
setup_board_tags(¶ms);
setup_end_tag(gd->bd);
- } else {
- printf("FDT and ATAGS support not compiled in - hanging\n");
- hang();
}
- do_nonsec_virt_switch();
}
+ #if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT)
+ bool armv7_boot_nonsec(void)
+ {
+ char *s = getenv("bootm_boot_mode");
+ #ifdef CONFIG_ARMV7_BOOT_SEC_DEFAULT
+ bool nonsec = false;
+ #else
+ bool nonsec = true;
+ #endif
+
+ if (s && !strcmp(s, "sec"))
+ nonsec = false;
+
+ if (s && !strcmp(s, "nonsec"))
+ nonsec = true;
+
+ return nonsec;
+ }
+ #endif
+
/* Subcommand: GO */
static void boot_jump_linux(bootm_headers_t *images, int flag)
{
--- /dev/null
+ menu "Command line interface"
+ depends on !SPL_BUILD
+
+ config HUSH_PARSER
+ bool "Use hush shell"
+ select SYS_HUSH_PARSER
+ help
+ This option enables the "hush" shell (from Busybox) as command line
+ interpreter, thus enabling powerful command line syntax like
+ if...then...else...fi conditionals or `&&' and '||'
+ constructs ("shell scripts").
+
+ If disabled, you get the old, much simpler behaviour with a somewhat
+ smaller memory footprint.
+
+ config SYS_HUSH_PARSER
+ bool
+ help
+ Backward compatibility.
+
+ comment "Commands"
+
+ menu "Info commands"
+
+ config CMD_BDI
+ bool "bdinfo"
+ help
+ Print board info
+
+ config CMD_CONSOLE
+ bool "coninfo"
+ help
+ Print console devices and information.
+
+ config CMD_LICENSE
+ bool "license"
+ help
+ Print GPL license text
+
+ endmenu
+
+ menu "Boot commands"
+
+ config CMD_BOOTD
+ bool "bootd"
+ help
+ Run the command stored in the environment "bootcmd", i.e.
+ "bootd" does the same thing as "run bootcmd".
+
+ config CMD_BOOTM
+ bool "bootm"
+ default y
+ help
+ Boot an application image from the memory.
+
+ config CMD_GO
+ bool "go"
+ default y
+ help
+ Start an application at a given address.
+
+ config CMD_RUN
+ bool "run"
+ help
+ Run the command in the given environment variable.
+
+ config CMD_IMI
+ bool "iminfo"
+ help
+ Print header information for application image.
+
+ config CMD_IMLS
+ bool "imls"
+ help
+ List all images found in flash
+
+ config CMD_XIMG
+ bool "imxtract"
+ help
+ Extract a part of a multi-image.
+
+ endmenu
+
+ menu "Environment commands"
+
+ config CMD_EXPORTENV
+ bool "env export"
+ default y
+ help
+ Export environments.
+
+ config CMD_IMPORTENV
+ bool "env import"
+ default y
+ help
+ Import environments.
+
+ config CMD_EDITENV
+ bool "editenv"
+ help
+ Edit environment variable.
+
+ config CMD_SAVEENV
+ bool "saveenv"
+ help
+ Run the command in the given environment variable.
+
+ endmenu
+
+ menu "Memory commands"
+
+ config CMD_MEMORY
+ bool "md, mm, nm, mw, cp, cmp, base, loop"
+ help
+ Memeory commands.
+ md - memory display
+ mm - memory modify (auto-incrementing address)
+ nm - memory modify (constant address)
+ mw - memory write (fill)
+ cp - memory copy
+ cmp - memory compare
+ base - print or set address offset
+ loop - initinite loop on address range
+
+ config CMD_CRC32
+ bool "crc32"
+ default y
+ help
+ Compute CRC32.
+
+ config LOOPW
+ bool "loopw"
+ help
+ Infinite write loop on address range
+
+ config CMD_MEMTEST
+ bool "crc32"
+ help
+ Simple RAM read/write test.
+
+ config CMD_MX_CYCLIC
+ bool "mdc, mwc"
+ help
+ mdc - memory display cyclic
+ mwc - memory write cyclic
+
+ config CMD_MEMINFO
+ bool "meminfo"
+ help
+ Display memory information.
+
+ endmenu
+
+ menu "Device access commands"
+
+ config CMD_LOADB
+ bool "loadb"
+ help
+ Load a binary file over serial line.
+
+ config CMD_LOADS
+ bool "loads"
+ help
+ Load an S-Record file over serial line
+
+ config CMD_FLASH
+ bool "flinfo, erase, protect"
+ help
+ NOR flash support.
+ flinfo - print FLASH memory information
+ erase - FLASH memory
+ protect - enable or disable FLASH write protection
+
+ config CMD_NAND
+ bool "nand"
+ help
+ NAND support.
+
+ config CMD_SPI
+ bool "sspi"
+ help
+ SPI utility command.
+
+ config CMD_I2C
+ bool "i2c"
+ help
+ I2C support.
+
+ config CMD_USB
+ bool "usb"
+ help
+ USB support.
+
+ config CMD_FPGA
+ bool "fpga"
+ help
+ FPGA support.
+
+ endmenu
+
+
+ menu "Shell scripting commands"
+
+ config CMD_ECHO
+ bool "echo"
+ help
+ Echo args to console
+
+ config CMD_ITEST
+ bool "itest"
+ help
+ Return true/false on integer compare.
+
+ config CMD_SOURCE
+ bool "source"
+ help
+ Run script from memory
+
+ endmenu
+
+ menu "Network commands"
+
+ config CMD_NET
+ bool "bootp, tftpboot"
+ help
+ Network commands.
+ bootp - boot image via network using BOOTP/TFTP protocol
+ tftpboot - boot image via network using TFTP protocol
+
+ config CMD_TFTPPUT
+ bool "tftp put"
+ help
+ TFTP put command, for uploading files to a server
+
+ config CMD_TFTPSRV
+ bool "tftpsrv"
+ help
+ Act as a TFTP server and boot the first received file
+
+ config CMD_RARP
+ bool "rarpboot"
+ help
+ Boot image via network using RARP/TFTP protocol
+
+ config CMD_DHCP
+ bool "dhcp"
+ help
+ Boot image via network using DHCP/TFTP protocol
+
+ config CMD_NFS
+ bool "nfs"
+ help
+ Boot image via network using NFS protocol.
+
+ config CMD_PING
+ bool "ping"
+ help
+ Send ICMP ECHO_REQUEST to network host
+
+ config CMD_CDP
+ bool "cdp"
+ help
+ Perform CDP network configuration
+
+ config CMD_SNTP
+ bool "sntp"
+ help
+ Synchronize RTC via network
+
+ config CMD_DNS
+ bool "dns"
+ help
+ Lookup the IP of a hostname
+
+ config CMD_DNS
+ bool "dns"
+ help
+ Lookup the IP of a hostname
+
+ config CMD_LINK_LOCAL
+ bool "linklocal"
+ help
+ Acquire a network IP address using the link-local protocol
+
+ endmenu
+
+ menu "Misc commands"
+
+ config CMD_TIME
+ bool "time"
+ help
+ Run commands and summarize execution time.
+
+ # TODO: rename to CMD_SLEEP
+ config CMD_MISC
+ bool "sleep"
+ help
+ Delay execution for some time
+
+ config CMD_TIMER
+ bool "timer"
+ help
+ Access the system timer.
+
+ config CMD_SETGETDCR
+ bool "getdcr, setdcr, getidcr, setidcr"
+ depends on 4xx
+ help
+ getdcr - Get an AMCC PPC 4xx DCR's value
+ setdcr - Set an AMCC PPC 4xx DCR's value
+ getidcr - Get a register value via indirect DCR addressing
+ setidcr - Set a register value via indirect DCR addressing
+
++config CMD_ZYNQ_RSA
++ bool "Zynq RSA"
++ help
++ Verifies the authenticated and encrypted zynq images.
++
+ endmenu
+
+ endmenu
}
#endif
- /* FIXME = standard file size + header desc_xilinx->size + 0x6c */
- err = file_fat_read(CONFIG_SPL_FPGA_LOAD_ARGS_NAME,
- (void *)CONFIG_SPL_FPGA_LOAD_ADDR,
- 0);
- if (err <= 0) {
+#ifdef CONFIG_SPL_FPGA_SUPPORT
+static int mmc_load_fpga_image_fat(struct mmc *mmc)
+{
+ int err;
+ int devnum = 0;
+ const fpga_desc *const desc = fpga_get_desc(devnum);
+ xilinx_desc *desc_xilinx = desc->devdesc;
+
- return fpga_loadbitstream(devnum, (char *)CONFIG_SPL_FPGA_LOAD_ADDR,
++ err = spl_load_image_fat(&mmc->block_dev,
++ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
++ CONFIG_SPL_FPGA_LOAD_ARGS_NAME);
++
++ if (err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("spl: error reading image %s, err - %d\n",
+ CONFIG_SPL_FPGA_LOAD_ARGS_NAME, err);
+#endif
+ return -1;
+ }
+#ifdef CONFIG_SPL_FPGA_BIT
- return fpga_load(devnum, (const void *)CONFIG_SPL_FPGA_LOAD_ADDR,
++ return fpga_loadbitstream(devnum, (char *)spl_image.load_addr,
+ desc_xilinx->size, BIT_FULL);
+#else
++ return fpga_load(devnum, (const void *)spl_image.load_addr,
+ desc_xilinx->size, BIT_FULL);
+#endif
+}
+#endif
+
void spl_mmc_load_image(void)
{
struct mmc *mmc;
#ifdef CONFIG_SPL_OS_BOOT
if (spl_start_uboot() || mmc_load_image_raw_os(mmc))
#endif
- err = mmc_load_image_raw(mmc,
+ #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION
+ err = mmc_load_image_raw_partition(mmc,
+ CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION);
+ #else
+ err = mmc_load_image_raw_sector(mmc,
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
+ #endif
+ #if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT)
+ }
+ if (err || boot_mode == MMCSD_MODE_FS) {
+ debug("boot mode - FS\n");
#ifdef CONFIG_SPL_FAT_SUPPORT
- } else if (boot_mode == MMCSD_MODE_FAT) {
- debug("boot mode - FAT\n");
+
+#ifdef CONFIG_SPL_FPGA_SUPPORT
+ mmc_load_fpga_image_fat(mmc);
+#endif
+
#ifdef CONFIG_SPL_OS_BOOT
if (spl_start_uboot() || spl_load_image_fat_os(&mmc->block_dev,
- CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION))
+ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION))
#endif
err = spl_load_image_fat(&mmc->block_dev,
- CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION,
- CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME);
+ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
+ CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
+ if(err)
+ #endif /* CONFIG_SPL_FAT_SUPPORT */
+ {
+ #ifdef CONFIG_SPL_EXT_SUPPORT
+ #ifdef CONFIG_SPL_OS_BOOT
+ if (spl_start_uboot() || spl_load_image_ext_os(&mmc->block_dev,
+ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION))
#endif
+ err = spl_load_image_ext(&mmc->block_dev,
+ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
+ CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
+ #endif /* CONFIG_SPL_EXT_SUPPORT */
+ }
+ #endif /* defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT) */
#ifdef CONFIG_SUPPORT_EMMC_BOOT
} else if (boot_mode == MMCSD_MODE_EMMCBOOT) {
/*
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="AFX_NAND"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_AFX=y
++CONFIG_OF_CONTROL=n
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="AFX_NAND"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_AFX=y
++CONFIG_OF_CONTROL=n
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="AFX_NOR"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_AFX=y
++CONFIG_OF_CONTROL=n
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="AFX_NOR"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_AFX=y
++CONFIG_OF_CONTROL=n
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="AFX_QSPI"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_AFX=y
++CONFIG_OF_CONTROL=n
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="AFX_QSPI"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_AFX=y
++CONFIG_OF_CONTROL=n
--- /dev/null
--- /dev/null
++CONFIG_SPL=y
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_CC108=y
++CONFIG_OF_CONTROL=n
++CONFIG_DEFAULT_DEVICE_TREE="zynq-cc108"
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="CSE_NAND"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_CSE=y
++CONFIG_CMD_BOOTM=n
++CONFIG_CMD_GO=n
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="CSE_NOR"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_CSE=y
++CONFIG_CMD_BOOTM=n
++CONFIG_CMD_GO=n
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="CSE_QSPI"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_CSE=y
++CONFIG_CMD_BOOTM=n
++CONFIG_CMD_GO=n
--- /dev/null
-CONFIG_OF_CONTROL=y
+ CONFIG_SPL=y
+ +S:CONFIG_ARM=y
+ +S:CONFIG_ZYNQ=y
+ +S:CONFIG_TARGET_ZYNQ_MICROZED=y
++CONFIG_OF_CONTROL=n
+ CONFIG_DEFAULT_DEVICE_TREE="zynq-microzed"
--- /dev/null
--- /dev/null
++CONFIG_SPL=y
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_ZC70X=y
++CONFIG_OF_CONTROL=n
++CONFIG_DEFAULT_DEVICE_TREE="zynq-zc702"
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
-CONFIG_OF_CONTROL=y
+ CONFIG_SPL=y
+ +S:CONFIG_ARM=y
+ +S:CONFIG_ZYNQ=y
+ +S:CONFIG_TARGET_ZYNQ_ZC70X=y
++CONFIG_OF_CONTROL=n
+ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc702"
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM010"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_ZC770=y
++CONFIG_OF_CONTROL=n
++CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm010"
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
-CONFIG_SPL=y
++CONFIG_SPL=n
+ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM010"
+ +S:CONFIG_ARM=y
+ +S:CONFIG_ZYNQ=y
+ +S:CONFIG_TARGET_ZYNQ_ZC770=y
-CONFIG_OF_CONTROL=y
++CONFIG_OF_CONTROL=n
+ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm010"
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM011"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_ZC770=y
++CONFIG_OF_CONTROL=n
++CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm011"
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM011"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_ZC770=y
++CONFIG_OF_CONTROL=n
++CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm011"
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM012"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_ZC770=y
++CONFIG_OF_CONTROL=n
++CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm012"
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
-CONFIG_SPL=y
++CONFIG_SPL=n
+ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM012"
+ +S:CONFIG_ARM=y
+ +S:CONFIG_ZYNQ=y
+ +S:CONFIG_TARGET_ZYNQ_ZC770=y
-CONFIG_OF_CONTROL=y
++CONFIG_OF_CONTROL=n
+ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm012"
--- /dev/null
--- /dev/null
++CONFIG_SPL=n
++CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM013"
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_ZC770=y
++CONFIG_OF_CONTROL=n
++CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm013"
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
-CONFIG_SPL=y
++CONFIG_SPL=n
+ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM013"
+ +S:CONFIG_ARM=y
+ +S:CONFIG_ZYNQ=y
+ +S:CONFIG_TARGET_ZYNQ_ZC770=y
-CONFIG_OF_CONTROL=y
++CONFIG_OF_CONTROL=n
+ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm013"
--- /dev/null
--- /dev/null
++CONFIG_SPL=y
+++S:CONFIG_ARM=y
+++S:CONFIG_ZYNQ=y
+++S:CONFIG_TARGET_ZYNQ_ZED=y
++CONFIG_OF_CONTROL=n
++CONFIG_DEFAULT_DEVICE_TREE="zynq-zed"
++CONFIG_CMD_ZYNQ_RSA=y
--- /dev/null
-CONFIG_OF_CONTROL=y
+ CONFIG_SPL=y
+ +S:CONFIG_ARM=y
+ +S:CONFIG_ZYNQ=y
+ +S:CONFIG_TARGET_ZYNQ_ZED=y
++CONFIG_OF_CONTROL=n
+ CONFIG_DEFAULT_DEVICE_TREE="zynq-zed"
--- /dev/null
-CONFIG_OF_CONTROL=y
+ CONFIG_SPL=y
+ +S:CONFIG_ARM=y
+ +S:CONFIG_ZYNQ=y
+ +S:CONFIG_TARGET_ZYNQ_ZYBO=y
++CONFIG_OF_CONTROL=n
+ CONFIG_DEFAULT_DEVICE_TREE="zynq-zybo"
--- /dev/null
- struct nand_chip *chip, u32 data_offs,
- u32 readlen, u8 *buf)
+/*
+ * Xilinx Zynq NAND Flash Controller Driver
+ * This driver is based on plat_nand.c and mxc_nand.c drivers
+ *
+ * Copyright (C) 2009 - 2013 Xilinx, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
++#include <nand.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+
+/* The NAND flash driver defines */
+#define ZYNQ_NAND_CMD_PHASE 1 /* End command valid in command phase */
+#define ZYNQ_NAND_DATA_PHASE 2 /* End command valid in data phase */
+#define ZYNQ_NAND_ECC_SIZE 512 /* Size of data for ECC operation */
+
+/* Flash memory controller operating parameters */
+#define ZYNQ_NAND_CLR_CONFIG ((0x1 << 1) | /* Disable interrupt */ \
+ (0x1 << 4) | /* Clear interrupt */ \
+ (0x1 << 6)) /* Disable ECC interrupt */
+
+/* Assuming 50MHz clock (20ns cycle time) and 3V operation */
+#define ZYNQ_NAND_SET_CYCLES ((0x2 << 20) | /* t_rr from nand_cycles */ \
+ (0x2 << 17) | /* t_ar from nand_cycles */ \
+ (0x1 << 14) | /* t_clr from nand_cycles */ \
+ (0x3 << 11) | /* t_wp from nand_cycles */ \
+ (0x2 << 8) | /* t_rea from nand_cycles */ \
+ (0x5 << 4) | /* t_wc from nand_cycles */ \
+ (0x5 << 0)) /* t_rc from nand_cycles */
+
+#define ZYNQ_NAND_SET_OPMODE 0x0
+
+#define ZYNQ_NAND_DIRECT_CMD ((0x4 << 23) | /* Chip 0 from interface 1 */ \
+ (0x2 << 21)) /* UpdateRegs operation */
+
+#define ZYNQ_NAND_ECC_CONFIG ((0x1 << 2) | /* ECC available on APB */ \
+ (0x1 << 4) | /* ECC read at end of page */ \
+ (0x0 << 5)) /* No Jumping */
+
+#define ZYNQ_NAND_ECC_CMD1 ((0x80) | /* Write command */ \
+ (0x00 << 8) | /* Read command */ \
+ (0x30 << 16) | /* Read End command */ \
+ (0x1 << 24)) /* Read End command calid */
+
+#define ZYNQ_NAND_ECC_CMD2 ((0x85) | /* Write col change cmd */ \
+ (0x05 << 8) | /* Read col change cmd */ \
+ (0xE0 << 16) | /* Read col change end cmd */ \
+ (0x1 << 24)) /* Read col change
+ end cmd valid */
+/* 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 ZYNQ_NAND_ECC_LAST (1 << ECC_LAST_SHIFT) /* Set ECC_Last */
+#define ZYNQ_NAND_CLEAR_CS (1 << CLEAR_CS_SHIFT) /* Clear chip select */
+
+/* ECC block registers bit position and bit mask */
+#define ZYNQ_NAND_ECC_BUSY (1 << 6) /* ECC block is busy */
+#define ZYNQ_NAND_ECC_MASK 0x00FFFFFF /* ECC value mask */
+
+/* NAND MIO buswidth count*/
+#define ZYNQ_NAND_MIO_NUM_NAND_8BIT 13
+#define ZYNQ_NAND_MIO_NUM_NAND_16BIT 8
+
+/* NAND buswidth */
+enum zynq_nand_bus_width {
+ NAND_BW_UNKNOWN = -1,
+ NAND_BW_8BIT,
+ NAND_BW_16BIT,
+};
+
+/* SMC register set */
+struct zynq_nand_smc_regs {
+ u32 csr; /* 0x00 */
+ u32 reserved0[2];
+ u32 cfr; /* 0x0C */
+ u32 dcr; /* 0x10 */
+ u32 scr; /* 0x14 */
+ u32 sor; /* 0x18 */
+ u32 reserved1[249];
+ u32 esr; /* 0x400 */
+ u32 emcr; /* 0x404 */
+ u32 emcmd1r; /* 0x408 */
+ u32 emcmd2r; /* 0x40C */
+ u32 reserved2[2];
+ u32 eval0r; /* 0x418 */
+};
+
+#define zynq_nand_smc_base ((struct zynq_nand_smc_regs *)ZYNQ_SMC_BASEADDR)
+
+/*
+ * struct zynq_nand_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 zynq_nand_command_format {
+ int start_cmd;
+ int end_cmd;
+ u8 addr_cycles;
+ u8 end_cmd_valid;
+};
+
+/*
+ * struct zynq_nand_info - Defines the NAND flash driver instance
+ * @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 zynq_nand_info {
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts;
+#endif
+ void __iomem *nand_base;
+ unsigned long end_cmd_pending;
+ unsigned long end_cmd;
+};
+
+#define ONDIE_ECC_FEATURE_ADDR 0x90
+
+/* The NAND flash operations command format */
+static const struct zynq_nand_command_format zynq_nand_commands[] = {
+ {NAND_CMD_READ0, NAND_CMD_READSTART, 5, ZYNQ_NAND_CMD_PHASE},
+ {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, ZYNQ_NAND_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, ZYNQ_NAND_DATA_PHASE},
+ {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, NAND_CMD_NONE},
+ {NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, ZYNQ_NAND_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, ZYNQ_NAND_YES}
+ */
+};
+
+/* Define default oob placement schemes for large and small page devices */
+static struct nand_ecclayout nand_oob_16 = {
+ .eccbytes = 3,
+ .eccpos = {13, 14, 15},
+ .oobfree = {
+ { .offset = 0, .length = 12 }
+ }
+};
+
+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 u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 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
+};
+
+/*
+ * zynq_nand_waitfor_ecc_completion - Wait for ECC completion
+ *
+ * returns: status for command completion, -1 for Timeout
+ */
+static int zynq_nand_waitfor_ecc_completion(void)
+{
+ unsigned long timeout;
+ u32 status;
+
+ /* Wait max 10ms */
+ timeout = 10;
+ status = readl(&zynq_nand_smc_base->esr);
+ while (status & ZYNQ_NAND_ECC_BUSY) {
+ status = readl(&zynq_nand_smc_base->esr);
+ if (timeout == 0)
+ return -1;
+ timeout--;
+ udelay(1);
+ }
+
+ return status;
+}
+
+/*
+ * zynq_nand_init_nand_flash - Initialize NAND controller
+ * @option: Device property flags
+ *
+ * This function initializes the NAND flash interface on the NAND controller.
+ *
+ * returns: 0 on success or error value on failure
+ */
+static int zynq_nand_init_nand_flash(int option)
+{
+ u32 status;
+
+ /* disable interrupts */
+ writel(ZYNQ_NAND_CLR_CONFIG, &zynq_nand_smc_base->cfr);
+ /* Initialize the NAND interface by setting cycles and operation mode */
+ writel(ZYNQ_NAND_SET_CYCLES, &zynq_nand_smc_base->scr);
+ if (option & NAND_BUSWIDTH_16)
+ writel((ZYNQ_NAND_SET_OPMODE | 0x1), &zynq_nand_smc_base->sor);
+ else
+ writel(ZYNQ_NAND_SET_OPMODE, &zynq_nand_smc_base->sor);
+
+ writel(ZYNQ_NAND_DIRECT_CMD, &zynq_nand_smc_base->dcr);
+
+ /* Wait till the ECC operation is complete */
+ status = zynq_nand_waitfor_ecc_completion();
+ if (status < 0) {
+ printf("%s: Timeout\n", __func__);
+ return status;
+ }
+
+ /* Set the command1 and command2 register */
+ writel(ZYNQ_NAND_ECC_CMD1, &zynq_nand_smc_base->emcmd1r);
+ writel(ZYNQ_NAND_ECC_CMD2, &zynq_nand_smc_base->emcmd2r);
+
+ return 0;
+}
+
+/*
+ * zynq_nand_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 zynq_nand_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 */
+ ecc_status = zynq_nand_waitfor_ecc_completion();
+ if (ecc_status < 0) {
+ printf("%s: Timeout\n", __func__);
+ return ecc_status;
+ }
+
+ for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) {
+ /* Read ECC value for each block */
+ ecc_value = readl(&zynq_nand_smc_base->eval0r + 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 {
+ debug("%s: ecc status failed\n", __func__);
+ }
+ }
+ 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);
+}
+
+/*
+ * zynq_nand_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 zynq_nand_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 */
+ else 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;
+ } else if (onehot(ecc_odd | ecc_even) == 1) {
+ return 1; /* one error in parity */
+ } else {
+ return -1; /* Uncorrectable error */
+ }
+}
+
+/*
+ * zynq_nand_read_oob - [REPLACABLE] the most common OOB data read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ * @sndcmd: flag whether to issue read command or not
+ */
+static int zynq_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ unsigned long data_width = 4;
+ unsigned long data_phase_addr = 0;
+ u8 *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)chip->IO_ADDR_R;
+ data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
+ chip->IO_ADDR_R = (void __iomem *)data_phase_addr;
+ chip->read_buf(mtd, p, data_width);
+
+ return 0;
+}
+
+/*
+ * zynq_nand_write_oob - [REPLACABLE] the most common OOB data write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
+ */
+static int zynq_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ int status = 0;
+ const u8 *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)chip->IO_ADDR_W;
+ data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
+ data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
+ chip->IO_ADDR_W = (void __iomem *)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;
+}
+
+/*
+ * zynq_nand_read_page_raw - [Intern] read raw page data without ecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to read
+ */
+static int zynq_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ u8 *buf, int oob_required, int page)
+{
+ unsigned long data_width = 4;
+ unsigned long data_phase_addr = 0;
+ u8 *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)chip->IO_ADDR_R;
+ data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
+ chip->IO_ADDR_R = (void __iomem *)data_phase_addr;
+
+ chip->read_buf(mtd, p, data_width);
+ return 0;
+}
+
+static int zynq_nand_read_page_raw_nooob(struct mtd_info *mtd,
+ struct nand_chip *chip, u8 *buf, int oob_required, int page)
+{
+ chip->read_buf(mtd, buf, mtd->writesize);
+ return 0;
+}
+
+static int zynq_nand_read_subpage_raw(struct mtd_info *mtd,
- if (data_offs != 0) {
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_offs, -1);
- buf += data_offs;
++ struct nand_chip *chip, uint32_t offs,
++ uint32_t len, uint8_t *buf, int page)
+{
- chip->read_buf(mtd, buf, readlen);
++ if (offs != 0) {
++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offs, -1);
++ buf += offs;
+ }
+
- nand_release(mtd);
++ chip->read_buf(mtd, buf, len);
+ return 0;
+}
+
+/*
+ * zynq_nand_write_page_raw - [Intern] raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ */
+static int zynq_nand_write_page_raw(struct mtd_info *mtd,
+ struct nand_chip *chip, const u8 *buf, int oob_required)
+{
+ unsigned long data_width = 4;
+ unsigned long data_phase_addr = 0;
+ u8 *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)chip->IO_ADDR_W;
+ data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
+ data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
+ chip->IO_ADDR_W = (void __iomem *)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: must write chip->oob_poi to OOB
+ *
+ * This functions writes data and hardware generated ECC values in to the page.
+ */
+static int zynq_nand_write_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, const u8 *buf, int oob_required)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccsteps = chip->ecc.steps;
+ u8 *ecc_calc = chip->buffers->ecccalc;
+ const u8 *p = buf;
+ u32 *eccpos = chip->ecc.layout->eccpos;
+ unsigned long data_phase_addr = 0;
+ unsigned long data_width = 4;
+ u8 *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) chip->IO_ADDR_W;
+ data_phase_addr |= ZYNQ_NAND_ECC_LAST;
+ chip->IO_ADDR_W = (void __iomem *)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)chip->IO_ADDR_W;
+ data_phase_addr &= ~ZYNQ_NAND_ECC_LAST;
+ chip->IO_ADDR_W = (void __iomem *)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)chip->IO_ADDR_W;
+ data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
+ data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
+ chip->IO_ADDR_W = (void __iomem *)data_phase_addr;
+ oob_ptr += (mtd->oobsize - data_width);
+ chip->write_buf(mtd, oob_ptr, data_width);
+
+ return 0;
+}
+
+/*
+ * zynq_nand_write_page_swecc - [REPLACABLE] software ecc based page
+ * write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ */
+static int zynq_nand_write_page_swecc(struct mtd_info *mtd,
+ struct nand_chip *chip, const u8 *buf, int oob_required)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ u8 *ecc_calc = chip->buffers->ecccalc;
+ const u8 *p = buf;
+ u32 *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];
+
+ return chip->ecc.write_page_raw(mtd, chip, buf, 1);
+}
+
+/*
+ * nand_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: must write chip->oob_poi to OOB
+ * @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 zynq_nand_read_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, u8 *buf, int oob_required, int page)
+{
+ int i, stat, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ u8 *p = buf;
+ u8 *ecc_calc = chip->buffers->ecccalc;
+ u8 *ecc_code = chip->buffers->ecccode;
+ u32 *eccpos = chip->ecc.layout->eccpos;
+ unsigned long data_phase_addr = 0;
+ unsigned long data_width = 4;
+ u8 *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)chip->IO_ADDR_R;
+ data_phase_addr |= ZYNQ_NAND_ECC_LAST;
+ chip->IO_ADDR_R = (void __iomem *)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)chip->IO_ADDR_R;
+ data_phase_addr &= ~ZYNQ_NAND_ECC_LAST;
+ chip->IO_ADDR_R = (void __iomem *)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)chip->IO_ADDR_R;
+ data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
+ chip->IO_ADDR_R = (void __iomem *)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;
+}
+
+/*
+ * zynq_nand_read_page_swecc - [REPLACABLE] software ecc based page
+ * read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @page: page number to read
+ */
+static int zynq_nand_read_page_swecc(struct mtd_info *mtd,
+ struct nand_chip *chip, u8 *buf, int oob_required, int page)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ u8 *p = buf;
+ u8 *ecc_calc = chip->buffers->ecccalc;
+ u8 *ecc_code = chip->buffers->ecccode;
+ u32 *eccpos = chip->ecc.layout->eccpos;
+
+ chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
+
+ 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;
+}
+
+/*
+ * zynq_nand_select_chip - Select the flash device
+ * @mtd: Pointer to the mtd_info structure
+ * @chip: Chip number to be selected
+ *
+ * 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 zynq_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+ return;
+}
+
+/*
+ * zynq_nand_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 zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+{
+ struct nand_chip *chip = mtd->priv;
+ const struct zynq_nand_command_format *curr_cmd = NULL;
+ struct zynq_nand_info *xnand;
+ void *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;
+
+ xnand = (struct zynq_nand_info *)chip->priv;
+ 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 > ZYNQ_NAND_ECC_SIZE) &&
+ (command == NAND_CMD_READOOB)) {
+ column += mtd->writesize;
+ command = NAND_CMD_READ0;
+ }
+
+ /* Get the command format */
+ for (i = 0; (zynq_nand_commands[i].start_cmd != NAND_CMD_NONE ||
+ zynq_nand_commands[i].end_cmd != NAND_CMD_NONE); i++) {
+ if (command == zynq_nand_commands[i].start_cmd)
+ curr_cmd = &zynq_nand_commands[i];
+ }
+ if (curr_cmd == NULL)
+ return;
+
+ /* Clear interrupt */
+ writel((1 << 4), &zynq_nand_smc_base->cfr);
+
+ /* Get the command phase address */
+ if (curr_cmd->end_cmd_valid == ZYNQ_NAND_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)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 *)cmd_phase_addr;
+
+ /* Get the data phase address */
+ end_cmd_valid = 0;
+
+ data_phase_addr = (unsigned long)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 *)data_phase_addr;
+ chip->IO_ADDR_W = chip->IO_ADDR_R;
+
+ /* Command phase AXI 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 > ZYNQ_NAND_ECC_SIZE) {
+ cmd_data |= page_addr << 16;
+ /* Another address cycle for devices > 128MiB */
+ if (chip->chipsize > (128 << 20)) {
+ writel(cmd_data, cmd_addr);
+ cmd_data = (page_addr >> 16);
+ }
+ } else {
+ cmd_data |= page_addr << 8;
+ }
+ }
+ /* Erase */
+ else if (page_addr != -1)
+ cmd_data = page_addr;
+ /* Change read/write column, read id etc */
+ else if (column != -1) {
+ /* 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;
+ } else
+ ;
+
+ writel(cmd_data, cmd_addr);
+
+ 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;
+ }
+}
+
+/*
+ * zynq_nand_read_buf - read chip data into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ const u32 *nand = chip->IO_ADDR_R;
+
+ /* Make sure that buf is 32 bit aligned */
+ if (((int)buf & 0x3) != 0) {
+ if (((int)buf & 0x1) != 0) {
+ if (len) {
+ *buf = readb(nand);
+ buf += 1;
+ len--;
+ }
+ }
+
+ if (((int)buf & 0x3) != 0) {
+ if (len >= 2) {
+ *(u16 *)buf = readw(nand);
+ buf += 2;
+ len -= 2;
+ }
+ }
+ }
+
+ /* copy aligned data */
+ while (len >= 4) {
+ *(u32 *)buf = readl(nand);
+ buf += 4;
+ len -= 4;
+ }
+
+ /* mop up any remaining bytes */
+ if (len) {
+ if (len >= 2) {
+ *(u16 *)buf = readw(nand);
+ buf += 2;
+ len -= 2;
+ }
+
+ if (len)
+ *buf = readb(nand);
+ }
+}
+
+/*
+ * zynq_nand_write_buf - write buffer to chip
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void zynq_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ const u32 *nand = chip->IO_ADDR_W;
+
+ /* Make sure that buf is 32 bit aligned */
+ if (((int)buf & 0x3) != 0) {
+ if (((int)buf & 0x1) != 0) {
+ if (len) {
+ writeb(*buf, nand);
+ buf += 1;
+ len--;
+ }
+ }
+
+ if (((int)buf & 0x3) != 0) {
+ if (len >= 2) {
+ writew(*(u16 *)buf, nand);
+ buf += 2;
+ len -= 2;
+ }
+ }
+ }
+
+ /* copy aligned data */
+ while (len >= 4) {
+ writel(*(u32 *)buf, nand);
+ buf += 4;
+ len -= 4;
+ }
+
+ /* mop up any remaining bytes */
+ if (len) {
+ if (len >= 2) {
+ writew(*(u16 *)buf, nand);
+ buf += 2;
+ len -= 2;
+ }
+
+ if (len)
+ writeb(*buf, nand);
+ }
+}
+
+/*
+ * zynq_nand_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 zynq_nand_device_ready(struct mtd_info *mtd)
+{
+ /* Check the raw_int_status1 bit */
+ if ((readl(&zynq_nand_smc_base->csr)) & 0x40) {
+ /* Clear the interrupt condition */
+ writel((1 << 4), &zynq_nand_smc_base->cfr);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * zynq_nand_check_is_16bit_bw_flash - checking for 16 or 8 bit buswidth nand
+ *
+ * This function will check nand buswidth whether it supports 16 or 8 bit
+ * based on the MIO configuration done by FSBL.
+ *
+ * User needs to correctly configure the MIO's based on the
+ * buswidth supported by the nand flash which is present on the board.
+ *
+ * function will return -1, if there is no MIO configuration for
+ * nand flash.
+ */
+static int zynq_nand_check_is_16bit_bw_flash(void)
+{
+ int is_16bit_bw = NAND_BW_UNKNOWN;
+ int mio_num_8bit = 0, mio_num_16bit = 0;
+
+ mio_num_8bit = zynq_slcr_get_mio_pin_status("nand8");
+ if (mio_num_8bit == ZYNQ_NAND_MIO_NUM_NAND_8BIT)
+ is_16bit_bw = NAND_BW_8BIT;
+
+ mio_num_16bit = zynq_slcr_get_mio_pin_status("nand16");
+ if ((mio_num_8bit == ZYNQ_NAND_MIO_NUM_NAND_8BIT) &&
+ (mio_num_16bit == ZYNQ_NAND_MIO_NUM_NAND_16BIT))
+ is_16bit_bw = NAND_BW_16BIT;
+
+ return is_16bit_bw;
+}
+
+static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
+{
+ struct zynq_nand_info *xnand;
+ struct mtd_info *mtd;
+ unsigned long ecc_page_size;
+ int err = -1;
+ u8 maf_id, dev_id, i;
+ u8 get_feature[4];
+ u8 set_feature[4] = {0x08, 0x00, 0x00, 0x00};
+ unsigned long ecc_cfg;
+ int ondie_ecc_enabled = 0;
+ int is_16bit_bw;
+
+ xnand = calloc(1, sizeof(struct zynq_nand_info));
+ if (!xnand) {
+ printf("%s: failed to allocate\n", __func__);
+ goto free;
+ }
+
+ xnand->nand_base = (void *)ZYNQ_NAND_BASEADDR;
+ mtd = &nand_info[0];
+
+ nand_chip->priv = xnand;
+ mtd->priv = nand_chip;
+
+ /* 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 = zynq_nand_cmd_function;
+ nand_chip->dev_ready = zynq_nand_device_ready;
+ nand_chip->select_chip = zynq_nand_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 = zynq_nand_read_buf;
+ nand_chip->write_buf = zynq_nand_write_buf;
+
+ /* Check the NAND buswidth */
+ /* FIXME this will be changed by using NAND_BUSWIDTH_AUTO */
+ is_16bit_bw = zynq_nand_check_is_16bit_bw_flash();
+ if (is_16bit_bw == NAND_BW_UNKNOWN) {
+ printf("%s: Unable detect NAND based on MIO settings\n",
+ __func__);
+ goto free;
+ } else if (is_16bit_bw == NAND_BW_16BIT) {
+ nand_chip->options = NAND_BUSWIDTH_16;
+ }
+ nand_chip->bbt_options = NAND_BBT_USE_FLASH;
+
+ /* Initialize the NAND flash interface on NAND controller */
+ if (zynq_nand_init_nand_flash(nand_chip->options) < 0) {
+ printf("%s: nand flash init failed\n", __func__);
+ goto free;
+ }
+
+ /* first scan to find the device and get the page size */
+ if (nand_scan_ident(mtd, 1, NULL)) {
+ printf("%s: nand_scan_ident failed\n", __func__);
+ goto fail;
+ }
+
+ /* Send the command for reading device ID */
+ 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_SET_FEATURES,
+ ONDIE_ECC_FEATURE_ADDR, -1);
+
+ for (i = 0; i < 4; i++)
+ writeb(set_feature[i], nand_chip->IO_ADDR_W);
+
+ /* wait for 1us after writing data with SET_FEATURES command */
+ ndelay(1000);
+
+ nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
+ ONDIE_ECC_FEATURE_ADDR, -1);
+ nand_chip->read_buf(mtd, get_feature, 4);
+
+ if (get_feature[0] & 0x08) {
+ debug("%s: OnDie ECC flash\n", __func__);
+ ondie_ecc_enabled = 1;
+ } else {
+ printf("%s: Unable to detect OnDie ECC\n", __func__);
+ }
+ }
+
+ if (ondie_ecc_enabled) {
+ /* bypass the controller ECC block */
+ ecc_cfg = readl(&zynq_nand_smc_base->emcr);
+ ecc_cfg &= ~0xc;
+ writel(ecc_cfg, &zynq_nand_smc_base->emcr);
+
+ /* The software ECC routines won't work
+ * with the SMC controller
+ */
+ nand_chip->ecc.mode = NAND_ECC_HW;
+ nand_chip->ecc.strength = 1;
+ nand_chip->ecc.read_page = zynq_nand_read_page_raw_nooob;
+ nand_chip->ecc.read_subpage = zynq_nand_read_subpage_raw;
+ nand_chip->ecc.write_page = zynq_nand_write_page_raw;
+ nand_chip->ecc.read_page_raw = zynq_nand_read_page_raw;
+ nand_chip->ecc.write_page_raw = zynq_nand_write_page_raw;
+ nand_chip->ecc.read_oob = zynq_nand_read_oob;
+ nand_chip->ecc.write_oob = zynq_nand_write_oob;
+ nand_chip->ecc.size = mtd->writesize;
+ nand_chip->ecc.bytes = 0;
+
+ /* NAND with on-die ECC supports subpage reads */
+ nand_chip->options |= NAND_SUBPAGE_READ;
+
+ /* On-Die ECC spare bytes offset 8 is used for ECC codes */
+ if (ondie_ecc_enabled) {
+ nand_chip->ecc.layout = &ondie_nand_oob_64;
+ /* 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.mode = NAND_ECC_HW;
+ nand_chip->ecc.strength = 1;
+ nand_chip->ecc.size = ZYNQ_NAND_ECC_SIZE;
+ nand_chip->ecc.bytes = 3;
+ nand_chip->ecc.calculate = zynq_nand_calculate_hwecc;
+ nand_chip->ecc.correct = zynq_nand_correct_data;
+ nand_chip->ecc.hwctl = NULL;
+ nand_chip->ecc.read_page = zynq_nand_read_page_hwecc;
+ nand_chip->ecc.write_page = zynq_nand_write_page_hwecc;
+ nand_chip->ecc.read_page_raw = zynq_nand_read_page_raw;
+ nand_chip->ecc.write_page_raw = zynq_nand_write_page_raw;
+ nand_chip->ecc.read_oob = zynq_nand_read_oob;
+ nand_chip->ecc.write_oob = zynq_nand_write_oob;
+
+ switch (mtd->writesize) {
+ case 512:
+ ecc_page_size = 0x1;
+ /* Set the ECC memory config register */
+ writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
+ &zynq_nand_smc_base->emcr);
+ break;
+ case 1024:
+ ecc_page_size = 0x2;
+ /* Set the ECC memory config register */
+ writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
+ &zynq_nand_smc_base->emcr);
+ break;
+ case 2048:
+ ecc_page_size = 0x3;
+ /* Set the ECC memory config register */
+ writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
+ &zynq_nand_smc_base->emcr);
+ break;
+ default:
+ /* The software ECC routines won't work with
+ * the SMC controller
+ */
+ nand_chip->ecc.mode = NAND_ECC_HW;
+ nand_chip->ecc.calculate = nand_calculate_ecc;
+ nand_chip->ecc.correct = nand_correct_data;
+ nand_chip->ecc.read_page = zynq_nand_read_page_swecc;
+ /* nand_chip->ecc.read_subpage = nand_read_subpage; */
+ nand_chip->ecc.write_page = zynq_nand_write_page_swecc;
+ nand_chip->ecc.read_page_raw = zynq_nand_read_page_raw;
+ nand_chip->ecc.write_page_raw =
+ zynq_nand_write_page_raw;
+ nand_chip->ecc.read_oob = zynq_nand_read_oob;
+ nand_chip->ecc.write_oob = zynq_nand_write_oob;
+ nand_chip->ecc.size = 256;
+ nand_chip->ecc.bytes = 3;
+ break;
+ }
+
+ if (mtd->oobsize == 16)
+ nand_chip->ecc.layout = &nand_oob_16;
+ else if (mtd->oobsize == 64)
+ nand_chip->ecc.layout = &nand_oob_64;
+ else
+ ;
+ }
+
+ /* second phase scan */
+ if (nand_scan_tail(mtd)) {
+ printf("%s: nand_scan_tailfailed\n", __func__);
+ goto fail;
+ }
+
+ if (nand_register(devnum))
+ goto fail;
+
+ return 0;
+fail:
+free:
+ kfree(xnand);
+ return err;
+}
+
+static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
+
+void board_nand_init(void)
+{
+ struct nand_chip *nand = &nand_chip[0];
+
+ if (zynq_nand_init(nand, 0))
+ puts("ZYNQ NAND init failed\n");
+}
--- /dev/null
+/*
+ * (C) Copyright 2011 - 2013 Xilinx
+ *
+ * Xilinx Zynq Quad-SPI(QSPI) controller driver (master mode only)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <ubi_uboot.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clk.h>
++#include "../mtd/spi/sf_internal.h"
+
+/* QSPI Transmit Data Register */
+#define ZYNQ_QSPI_TXD_00_00_OFFSET 0x1C /* Transmit 4-byte inst, WO */
+#define ZYNQ_QSPI_TXD_00_01_OFFSET 0x80 /* Transmit 1-byte inst, WO */
+#define ZYNQ_QSPI_TXD_00_10_OFFSET 0x84 /* Transmit 2-byte inst, WO */
+#define ZYNQ_QSPI_TXD_00_11_OFFSET 0x88 /* Transmit 3-byte inst, WO */
+
+/*
+ * QSPI Configuration Register bit Masks
+ *
+ * This register contains various control bits that effect the operation
+ * of the QSPI controller
+ */
+#define ZYNQ_QSPI_CONFIG_IFMODE_MASK (1 << 31) /* Flash intrface mode*/
+#define ZYNQ_QSPI_CONFIG_MSA_MASK (1 << 15) /* Manual start enb */
+#define ZYNQ_QSPI_CONFIG_MCS_MASK (1 << 14) /* Manual chip select */
+#define ZYNQ_QSPI_CONFIG_PCS_MASK (1 << 10) /* Peri chip select */
+#define ZYNQ_QSPI_CONFIG_FW_MASK (0x3 << 6) /* FIFO width */
+#define ZYNQ_QSPI_CONFIG_MSTREN_MASK (1 << 0) /* Mode select */
+#define ZYNQ_QSPI_CONFIG_MANSRT_MASK 0x00010000 /* Manual TX Start */
+#define ZYNQ_QSPI_CONFIG_CPHA_MASK 0x00000004 /* Clock Phase Control */
+#define ZYNQ_QSPI_CONFIG_CPOL_MASK 0x00000002 /* Clock Polarity Control */
+#define ZYNQ_QSPI_CONFIG_SSCTRL_MASK 0x00003C00 /* Slave Select Mask */
+/*
+ * QSPI Interrupt Registers bit Masks
+ *
+ * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
+ * bit definitions.
+ */
+#define ZYNQ_QSPI_IXR_TXNFULL_MASK 0x00000004 /* QSPI TX FIFO Overflow */
+#define ZYNQ_QSPI_IXR_TXFULL_MASK 0x00000008 /* QSPI TX FIFO is full */
+#define ZYNQ_QSPI_IXR_RXNEMTY_MASK 0x00000010 /* QSPI RX FIFO Not Empty */
+#define ZYNQ_QSPI_IXR_ALL_MASK (ZYNQ_QSPI_IXR_TXNFULL_MASK | \
+ ZYNQ_QSPI_IXR_RXNEMTY_MASK)
+
+/*
+ * QSPI Enable Register bit Masks
+ *
+ * This register is used to enable or disable the QSPI controller
+ */
+#define ZYNQ_QSPI_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 ZYNQ_QSPI_LCFG_TWO_MEM_MASK 0x40000000 /* QSPI Enable Bit Mask */
+#define ZYNQ_QSPI_LCFG_SEP_BUS_MASK 0x20000000 /* QSPI Enable Bit Mask */
+#define ZYNQ_QSPI_LCFG_U_PAGE 0x10000000 /* QSPI Upper memory set */
+
+#define ZYNQ_QSPI_LCFG_DUMMY_SHIFT 8
+
+#define ZYNQ_QSPI_FR_QOUT_CODE 0x6B /* read instruction code */
+#define ZYNQ_QSPI_FR_DUALIO_CODE 0xBB
+
+/*
+ * 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 ZYNQ_QSPI_QUEUE_STOPPED 0
+#define ZYNQ_QSPI_QUEUE_RUNNING 1
+#define ZYNQ_QSPI_RXFIFO_THRESHOLD 32
+#define ZYNQ_QSPI_FIFO_DEPTH 63
+
+/* QSPI MIO's count for different connection topologies */
+#define ZYNQ_QSPI_MIO_NUM_QSPI0 6
+#define ZYNQ_QSPI_MIO_NUM_QSPI1 5
+#define ZYNQ_QSPI_MIO_NUM_QSPI1_CS 1
+
+/* QSPI MIO's count for different connection topologies */
+#define ZYNQ_QSPI_MIO_NUM_QSPI0_DIO 4
+#define ZYNQ_QSPI_MIO_NUM_QSPI1_DIO 3
+#define ZYNQ_QSPI_MIO_NUM_QSPI1_CS_DIO 1
+
+/* QSPI register offsets */
+struct zynq_qspi_regs {
+ u32 confr; /* 0x00 */
+ u32 isr; /* 0x04 */
+ u32 ier; /* 0x08 */
+ u32 idisr; /* 0x0C */
+ u32 imaskr; /* 0x10 */
+ u32 enbr; /* 0x14 */
+ u32 dr; /* 0x18 */
+ u32 txd0r; /* 0x1C */
+ u32 drxr; /* 0x20 */
+ u32 sicr; /* 0x24 */
+ u32 txftr; /* 0x28 */
+ u32 rxftr; /* 0x2C */
+ u32 gpior; /* 0x30 */
+ u32 reserved0[19];
+ u32 txd1r; /* 0x80 */
+ u32 txd2r; /* 0x84 */
+ u32 txd3r; /* 0x88 */
+ u32 reserved1[5];
+ u32 lcr; /* 0xA0 */
+ u32 reserved2[22];
+ u32 midr; /* 0xFC */
+};
+
+#define zynq_qspi_base ((struct zynq_qspi_regs *)ZYNQ_QSPI_BASEADDR)
+
+struct zynq_qspi {
+ u32 input_clk_hz;
+ u32 speed_hz;
+ const void *txbuf;
+ void *rxbuf;
+ int bytes_to_transfer;
+ int bytes_to_receive;
+ unsigned int is_inst;
+ unsigned int is_dual;
+ unsigned int is_dio;
+ unsigned int u_page;
+};
+
+struct spi_device {
+ struct zynq_qspi master;
+ u32 max_speed_hz;
+ u8 chip_select;
+ u8 mode;
+ u8 bits_per_word;
+};
+
+struct spi_transfer {
+ const void *tx_buf;
+ void *rx_buf;
+ unsigned len;
+ unsigned cs_change:1;
+ u8 bits_per_word;
+ u16 delay_usecs;
+ u32 speed_hz;
+};
+
+struct zynq_qspi_slave {
+ struct spi_slave slave;
+ struct spi_device qspi;
+};
+#define to_zynq_qspi_slave(s) container_of(s, struct zynq_qspi_slave, slave)
+
+/*
+ * zynq_qspi_init_hw - Initialize the hardware
+ * @is_dual: Indicates whether dual memories are used
+ * @cs: Indicates which chip select is used in dual stacked
+ *
+ * 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 zynq_qspi_init_hw(int is_dual, int is_dio, unsigned int cs)
+{
+ u32 config_reg;
+
+ writel(~ZYNQ_QSPI_ENABLE_ENABLE_MASK, &zynq_qspi_base->enbr);
+ writel(0x7F, &zynq_qspi_base->idisr);
+
+ /* Disable linear mode as the boot loader may have used it */
+ writel(0x0, &zynq_qspi_base->lcr);
+
+ /* Clear the TX and RX threshold reg */
+ writel(0x1, &zynq_qspi_base->txftr);
+ writel(ZYNQ_QSPI_RXFIFO_THRESHOLD, &zynq_qspi_base->rxftr);
+
+ /* Clear the RX FIFO */
+ while (readl(&zynq_qspi_base->isr) & ZYNQ_QSPI_IXR_RXNEMTY_MASK)
+ readl(&zynq_qspi_base->drxr);
+
+ writel(0x7F, &zynq_qspi_base->isr);
+ config_reg = readl(&zynq_qspi_base->confr);
+ config_reg |= ZYNQ_QSPI_CONFIG_IFMODE_MASK |
+ ZYNQ_QSPI_CONFIG_MCS_MASK | ZYNQ_QSPI_CONFIG_PCS_MASK |
+ ZYNQ_QSPI_CONFIG_FW_MASK | ZYNQ_QSPI_CONFIG_MSTREN_MASK;
+ if (is_dual == SF_DUAL_STACKED_FLASH)
+ config_reg |= 0x10;
+ writel(config_reg, &zynq_qspi_base->confr);
+
+ if (is_dual == SF_DUAL_PARALLEL_FLASH) {
+ if (is_dio == SF_DUALIO_FLASH)
+ /* Enable two memories on seperate buses */
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ ZYNQ_QSPI_LCFG_SEP_BUS_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_DUALIO_CODE),
+ &zynq_qspi_base->lcr);
+ else
+ /* Enable two memories on seperate buses */
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ ZYNQ_QSPI_LCFG_SEP_BUS_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_QOUT_CODE),
+ &zynq_qspi_base->lcr);
+ } else if (is_dual == SF_DUAL_STACKED_FLASH) {
+ if (is_dio == SF_DUALIO_FLASH)
+ /* Configure two memories on shared bus
+ * by enabling lower mem */
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_DUALIO_CODE),
+ &zynq_qspi_base->lcr);
+ else
+ /* Configure two memories on shared bus
+ * by enabling lower mem */
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_QOUT_CODE),
+ &zynq_qspi_base->lcr);
+ }
+ writel(ZYNQ_QSPI_ENABLE_ENABLE_MASK, &zynq_qspi_base->enbr);
+}
+
+/*
+ * zynq_qspi_copy_read_data - Copy data to RX buffer
+ * @zqspi: Pointer to the zynq_qspi structure
+ * @data: The 32 bit variable where data is stored
+ * @size: Number of bytes to be copied from data to RX buffer
+ */
+static void zynq_qspi_copy_read_data(struct zynq_qspi *zqspi, u32 data, u8 size)
+{
+ u8 byte3;
+
+ debug("%s: data 0x%04x rxbuf addr: 0x%08x size %d\n", __func__ ,
+ data, (unsigned)(zqspi->rxbuf), size);
+
+ if (zqspi->rxbuf) {
+ switch (size) {
+ case 1:
+ *((u8 *)zqspi->rxbuf) = data;
+ zqspi->rxbuf += 1;
+ break;
+ case 2:
+ *((u16 *)zqspi->rxbuf) = data;
+ zqspi->rxbuf += 2;
+ break;
+ case 3:
+ *((u16 *)zqspi->rxbuf) = data;
+ zqspi->rxbuf += 2;
+ byte3 = (u8)(data >> 16);
+ *((u8 *)zqspi->rxbuf) = byte3;
+ zqspi->rxbuf += 1;
+ break;
+ case 4:
+ /* Can not assume word aligned buffer */
+ memcpy(zqspi->rxbuf, &data, size);
+ zqspi->rxbuf += 4;
+ break;
+ default:
+ /* This will never execute */
+ break;
+ }
+ }
+ zqspi->bytes_to_receive -= size;
+ if (zqspi->bytes_to_receive < 0)
+ zqspi->bytes_to_receive = 0;
+}
+
+/*
+ * zynq_qspi_copy_write_data - Copy data from TX buffer
+ * @zqspi: Pointer to the zynq_qspi 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 zynq_qspi_copy_write_data(struct zynq_qspi *zqspi,
+ u32 *data, u8 size)
+{
+ if (zqspi->txbuf) {
+ switch (size) {
+ case 1:
+ *data = *((u8 *)zqspi->txbuf);
+ zqspi->txbuf += 1;
+ *data |= 0xFFFFFF00;
+ break;
+ case 2:
+ *data = *((u16 *)zqspi->txbuf);
+ zqspi->txbuf += 2;
+ *data |= 0xFFFF0000;
+ break;
+ case 3:
+ *data = *((u16 *)zqspi->txbuf);
+ zqspi->txbuf += 2;
+ *data |= (*((u8 *)zqspi->txbuf) << 16);
+ zqspi->txbuf += 1;
+ *data |= 0xFF000000;
+ break;
+ case 4:
+ /* Can not assume word aligned buffer */
+ memcpy(data, zqspi->txbuf, size);
+ zqspi->txbuf += 4;
+ break;
+ default:
+ /* This will never execute */
+ break;
+ }
+ } else {
+ *data = 0;
+ }
+
+ debug("%s: data 0x%08x txbuf addr: 0x%08x size %d\n", __func__,
+ *data, (u32)zqspi->txbuf, size);
+
+ zqspi->bytes_to_transfer -= size;
+ if (zqspi->bytes_to_transfer < 0)
+ zqspi->bytes_to_transfer = 0;
+}
+
+/*
+ * zynq_qspi_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 zynq_qspi_chipselect(struct spi_device *qspi, int is_on)
+{
+ u32 config_reg;
+
+ debug("%s: is_on: %d\n", __func__, is_on);
+
+ config_reg = readl(&zynq_qspi_base->confr);
+
+ if (is_on) {
+ /* Select the slave */
+ config_reg &= ~ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
+ config_reg |= (((~(0x0001 << qspi->chip_select)) << 10) &
+ ZYNQ_QSPI_CONFIG_SSCTRL_MASK);
+ } else
+ /* Deselect the slave */
+ config_reg |= ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
+
+ writel(config_reg, &zynq_qspi_base->confr);
+}
+
+/*
+ * zynq_qspi_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 -1 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 zynq_qspi_setup_transfer(struct spi_device *qspi,
+ struct spi_transfer *transfer)
+{
+ struct zynq_qspi *zqspi = &qspi->master;
+ u8 bits_per_word;
+ u32 config_reg;
+ u32 req_hz;
+ u32 baud_rate_val = 0;
+
+ debug("%s: qspi: 0x%08x transfer: 0x%08x\n", __func__,
+ (u32)qspi, (u32)transfer);
+
+ bits_per_word = (transfer) ?
+ transfer->bits_per_word : qspi->bits_per_word;
+ req_hz = (transfer) ? transfer->speed_hz : qspi->max_speed_hz;
+
+ if (qspi->mode & ~MODEBITS) {
+ printf("%s: Unsupported mode bits %x\n",
+ __func__, qspi->mode & ~MODEBITS);
+ return -1;
+ }
+
+ if (bits_per_word != 32)
+ bits_per_word = 32;
+
+ config_reg = readl(&zynq_qspi_base->confr);
+
+ /* Set the QSPI clock phase and clock polarity */
+ config_reg &= (~ZYNQ_QSPI_CONFIG_CPHA_MASK) &
+ (~ZYNQ_QSPI_CONFIG_CPOL_MASK);
+ if (qspi->mode & SPI_CPHA)
+ config_reg |= ZYNQ_QSPI_CONFIG_CPHA_MASK;
+ if (qspi->mode & SPI_CPOL)
+ config_reg |= ZYNQ_QSPI_CONFIG_CPOL_MASK;
+
+ /* Set the clock frequency */
+ if (zqspi->speed_hz != req_hz) {
+ baud_rate_val = 0;
+ while ((baud_rate_val < 7) &&
+ (zqspi->input_clk_hz / (2 << baud_rate_val)) > req_hz) {
+ baud_rate_val++;
+ }
+ config_reg &= 0xFFFFFFC7;
+ config_reg |= (baud_rate_val << 3);
+ zqspi->speed_hz = req_hz;
+ }
+
+ writel(config_reg, &zynq_qspi_base->confr);
+
+ debug("%s: mode %d, %u bits/w, %u clock speed\n", __func__,
+ qspi->mode & MODEBITS, qspi->bits_per_word, zqspi->speed_hz);
+
+ return 0;
+}
+
+/*
+ * zynq_qspi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
+ * @zqspi: Pointer to the zynq_qspi structure
+ */
+static void zynq_qspi_fill_tx_fifo(struct zynq_qspi *zqspi, u32 size)
+{
+ u32 data = 0;
+ u32 fifocount = 0;
+ unsigned len, offset;
+ static const unsigned offsets[4] = {
+ ZYNQ_QSPI_TXD_00_00_OFFSET, ZYNQ_QSPI_TXD_00_01_OFFSET,
+ ZYNQ_QSPI_TXD_00_10_OFFSET, ZYNQ_QSPI_TXD_00_11_OFFSET };
+
+ while ((fifocount < size) &&
+ (zqspi->bytes_to_transfer > 0)) {
+ if (zqspi->bytes_to_transfer >= 4) {
+ if (zqspi->txbuf) {
+ memcpy(&data, zqspi->txbuf, 4);
+ zqspi->txbuf += 4;
+ } else {
+ data = 0;
+ }
+ writel(data, &zynq_qspi_base->txd0r);
+ zqspi->bytes_to_transfer -= 4;
+ fifocount++;
+ } else {
+ /* Write TXD1, TXD2, TXD3 only if TxFIFO is empty. */
+ if (!(readl(&zynq_qspi_base->isr)
+ & ZYNQ_QSPI_IXR_TXNFULL_MASK) &&
+ !zqspi->rxbuf)
+ return;
+ len = zqspi->bytes_to_transfer;
+ zynq_qspi_copy_write_data(zqspi, &data, len);
+ offset = (zqspi->rxbuf) ? offsets[0] : offsets[len];
+ writel(data, &zynq_qspi_base->confr + (offset / 4));
+ }
+ }
+}
+
+/*
+ * zynq_qspi_irq_poll - Interrupt service routine of the QSPI controller
+ * @zqspi: Pointer to the zynq_qspi 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: 0 for poll timeout
+ * 1 transfer operation complete
+ */
+static int zynq_qspi_irq_poll(struct zynq_qspi *zqspi)
+{
+ int max_loop;
+ u32 intr_status;
+ u32 rxindex = 0;
+ u32 rxcount;
+
+ debug("%s: zqspi: 0x%08x\n", __func__, (u32)zqspi);
+
+ /* Poll until any of the interrupt status bits are set */
+ max_loop = 0;
+ do {
+ intr_status = readl(&zynq_qspi_base->isr);
+ max_loop++;
+ } while ((intr_status == 0) && (max_loop < 100000));
+
+ if (intr_status == 0) {
+ printf("%s: Timeout\n", __func__);
+ return 0;
+ }
+
+ writel(intr_status, &zynq_qspi_base->isr);
+
+ /* Disable all interrupts */
+ writel(ZYNQ_QSPI_IXR_ALL_MASK, &zynq_qspi_base->idisr);
+ if ((intr_status & ZYNQ_QSPI_IXR_TXNFULL_MASK) ||
+ (intr_status & ZYNQ_QSPI_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
+ */
+ rxcount = zqspi->bytes_to_receive - zqspi->bytes_to_transfer;
+ rxcount = (rxcount % 4) ? ((rxcount/4)+1) : (rxcount/4);
+ while ((rxindex < rxcount) &&
+ (rxindex < ZYNQ_QSPI_RXFIFO_THRESHOLD)) {
+ /* Read out the data from the RX FIFO */
+ u32 data;
+ data = readl(&zynq_qspi_base->drxr);
+
+ if (zqspi->bytes_to_receive >= 4) {
+ if (zqspi->rxbuf) {
+ memcpy(zqspi->rxbuf, &data, 4);
+ zqspi->rxbuf += 4;
+ }
+ zqspi->bytes_to_receive -= 4;
+ } else {
+ zynq_qspi_copy_read_data(zqspi, data,
+ zqspi->bytes_to_receive);
+ }
+ rxindex++;
+ }
+
+ if (zqspi->bytes_to_transfer) {
+ /* There is more data to send */
+ zynq_qspi_fill_tx_fifo(zqspi,
+ ZYNQ_QSPI_RXFIFO_THRESHOLD);
+
+ writel(ZYNQ_QSPI_IXR_ALL_MASK, &zynq_qspi_base->ier);
+ } else {
+ /*
+ * If transfer and receive is completed then only send
+ * complete signal
+ */
+ if (!zqspi->bytes_to_receive) {
+ /* return operation complete */
+ writel(ZYNQ_QSPI_IXR_ALL_MASK,
+ &zynq_qspi_base->idisr);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * zynq_qspi_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 zynq_qspi_start_transfer(struct spi_device *qspi,
+ struct spi_transfer *transfer)
+{
+ struct zynq_qspi *zqspi = &qspi->master;
+ static u8 current_u_page;
+ u32 data = 0;
+
+ debug("%s: qspi: 0x%08x transfer: 0x%08x len: %d\n", __func__,
+ (u32)qspi, (u32)transfer, transfer->len);
+
+ zqspi->txbuf = transfer->tx_buf;
+ zqspi->rxbuf = transfer->rx_buf;
+ zqspi->bytes_to_transfer = transfer->len;
+ zqspi->bytes_to_receive = transfer->len;
+
+ if (zqspi->is_inst && (zqspi->is_dual == SF_DUAL_STACKED_FLASH) &&
+ (current_u_page != zqspi->u_page)) {
+ if (zqspi->u_page) {
+ if (zqspi->is_dio == SF_DUALIO_FLASH)
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ ZYNQ_QSPI_LCFG_U_PAGE |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_DUALIO_CODE),
+ &zynq_qspi_base->lcr);
+ else
+ /* Configure two memories on shared bus
+ * by enabling upper mem
+ */
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ ZYNQ_QSPI_LCFG_U_PAGE |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_QOUT_CODE),
+ &zynq_qspi_base->lcr);
+ } else {
+ if (zqspi->is_dio == SF_DUALIO_FLASH)
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_DUALIO_CODE),
+ &zynq_qspi_base->lcr);
+ else
+ /* Configure two memories on shared bus
+ * by enabling lower mem
+ */
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_QOUT_CODE),
+ &zynq_qspi_base->lcr);
+ }
+ current_u_page = zqspi->u_page;
+ }
+
+ if (transfer->len < 4)
+ zynq_qspi_fill_tx_fifo(zqspi, transfer->len);
+ else
+ zynq_qspi_fill_tx_fifo(zqspi, ZYNQ_QSPI_FIFO_DEPTH);
+
+ writel(ZYNQ_QSPI_IXR_ALL_MASK, &zynq_qspi_base->ier);
+ /* Start the transfer by enabling manual start bit */
+
+ /* wait for completion */
+ do {
+ data = zynq_qspi_irq_poll(zqspi);
+ } while (data == 0);
+
+ return (transfer->len) - (zqspi->bytes_to_transfer);
+}
+
+static int zynq_qspi_transfer(struct spi_device *qspi,
+ struct spi_transfer *transfer)
+{
+ struct zynq_qspi *zqspi = &qspi->master;
+ unsigned cs_change = 1;
+ int status = 0;
+
+ debug("%s\n", __func__);
+
+ while (1) {
+ if (transfer->bits_per_word || transfer->speed_hz) {
+ status = zynq_qspi_setup_transfer(qspi, transfer);
+ if (status < 0)
+ break;
+ }
+
+ /* Select the chip if required */
+ if (cs_change)
+ zynq_qspi_chipselect(qspi, 1);
+
+ cs_change = transfer->cs_change;
+
+ if (!transfer->tx_buf && !transfer->rx_buf && transfer->len) {
+ status = -1;
+ break;
+ }
+
+ /* Request the transfer */
+ if (transfer->len) {
+ status = zynq_qspi_start_transfer(qspi, transfer);
+ zqspi->is_inst = 0;
+ }
+
+ if (status != transfer->len) {
+ if (status > 0)
+ status = -EMSGSIZE;
+ break;
+ }
+ status = 0;
+
+ if (transfer->delay_usecs)
+ udelay(transfer->delay_usecs);
+
+ if (cs_change)
+ /* Deselect the chip */
+ zynq_qspi_chipselect(qspi, 0);
+
+ break;
+ }
+
+ zynq_qspi_setup_transfer(qspi, NULL);
+
+ return 0;
+}
+
+/*
+ * zynq_qspi_check_is_dual_flash - checking for dual or single qspi
+ *
+ * This function will check the type of the flash whether it supports
+ * single or dual qspi based on the MIO configuration done by FSBL.
+ *
+ * User needs to correctly configure the MIO's based on the
+ * number of qspi flashes present on the board.
+ *
+ * function will return -1, if there is no MIO configuration for
+ * qspi flash.
+ */
+static int zynq_qspi_check_is_dual_flash(int *is_dio)
+{
+ int is_dual = -1;
+ int lower_mio = 0, upper_mio = 0, upper_mio_cs1 = 0;
+
+ lower_mio = zynq_slcr_get_mio_pin_status("qspi0");
+ if (lower_mio == ZYNQ_QSPI_MIO_NUM_QSPI0) {
+ is_dual = SF_SINGLE_FLASH;
+ } else {
+ lower_mio = zynq_slcr_get_mio_pin_status("qspi0_dio");
+ if (lower_mio == ZYNQ_QSPI_MIO_NUM_QSPI0_DIO) {
+ debug("QSPI in Single 2-bit\n");
+ *is_dio = SF_DUALIO_FLASH;
+ is_dual = SF_SINGLE_FLASH;
+ }
+ }
+
+ if (*is_dio != SF_DUALIO_FLASH) {
+ upper_mio_cs1 = zynq_slcr_get_mio_pin_status("qspi1_cs");
+ if ((lower_mio == ZYNQ_QSPI_MIO_NUM_QSPI0) &&
+ (upper_mio_cs1 == ZYNQ_QSPI_MIO_NUM_QSPI1_CS))
+ is_dual = SF_DUAL_STACKED_FLASH;
+
+ upper_mio = zynq_slcr_get_mio_pin_status("qspi1");
+ if ((lower_mio == ZYNQ_QSPI_MIO_NUM_QSPI0) &&
+ (upper_mio_cs1 == ZYNQ_QSPI_MIO_NUM_QSPI1_CS) &&
+ (upper_mio == ZYNQ_QSPI_MIO_NUM_QSPI1))
+ is_dual = SF_DUAL_PARALLEL_FLASH;
+ } else {
+ upper_mio_cs1 = zynq_slcr_get_mio_pin_status("qspi1_cs_dio");
+ if ((lower_mio == ZYNQ_QSPI_MIO_NUM_QSPI0_DIO) &&
+ (upper_mio_cs1 == ZYNQ_QSPI_MIO_NUM_QSPI1_CS_DIO)) {
+ debug("QSPI in DualStacked 2-bit\n");
+ is_dual = SF_DUAL_STACKED_FLASH;
+ }
+ upper_mio = zynq_slcr_get_mio_pin_status("qspi1_dio");
+ if ((lower_mio == ZYNQ_QSPI_MIO_NUM_QSPI0_DIO) &&
+ (upper_mio_cs1 == ZYNQ_QSPI_MIO_NUM_QSPI1_CS_DIO) &&
+ (upper_mio == ZYNQ_QSPI_MIO_NUM_QSPI1_DIO)) {
+ debug("QSPI in DualParallel 2-bit\n");
+ is_dual = SF_DUAL_PARALLEL_FLASH;
+ }
+ }
+
+ return is_dual;
+}
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ /* 1 bus with 2 chipselect */
+ return bus == 0 && cs < 2;
+}
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+ debug("%s: slave 0x%08x\n", __func__, (unsigned)slave);
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+ debug("%s: slave 0x%08x\n", __func__, (unsigned)slave);
+}
+
+void spi_init()
+{
+ debug("%s\n", __func__);
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ int is_dual;
+ int is_dio = 0;
+ unsigned long lqspi_frequency;
+ struct zynq_qspi_slave *qspi;
+
+ debug("%s: bus: %d cs: %d max_hz: %d mode: %d\n",
+ __func__, bus, cs, max_hz, mode);
+
+ if (!spi_cs_is_valid(bus, cs))
+ return NULL;
+
+ is_dual = zynq_qspi_check_is_dual_flash(&is_dio);
+
+ if (is_dual == -1) {
+ printf("%s: No QSPI device detected based on MIO settings\n",
+ __func__);
+ return NULL;
+ }
+
+ zynq_qspi_init_hw(is_dual, is_dio, cs);
+
+ qspi = spi_alloc_slave(struct zynq_qspi_slave, bus, cs);
+ if (!qspi) {
+ printf("%s: Fail to allocate zynq_qspi_slave\n", __func__);
+ return NULL;
+ }
+
+ lqspi_frequency = zynq_clk_get_rate(lqspi_clk);
+ if (!lqspi_frequency) {
+ debug("Defaulting to 200000000 Hz qspi clk");
+ qspi->qspi.master.input_clk_hz = 200000000;
+ } else {
+ qspi->qspi.master.input_clk_hz = lqspi_frequency;
+ debug("Qspi clk frequency set to %ld Hz\n", lqspi_frequency);
+ }
+
+ qspi->slave.option = is_dual;
+ qspi->slave.dio = is_dio;
+ qspi->slave.op_mode_rx = SPI_OPM_RX_QOF;
+ qspi->slave.op_mode_tx = SPI_OPM_TX_QPP;
+ lqspi_frequency = qspi->qspi.master.input_clk_hz / 2;
+ qspi->qspi.max_speed_hz = min(max_hz, lqspi_frequency);
+ qspi->qspi.master.is_dio = is_dio;
+ qspi->qspi.master.is_dual = is_dual;
+ qspi->qspi.mode = mode;
+ qspi->qspi.chip_select = 0;
+ qspi->qspi.bits_per_word = 32;
+ zynq_qspi_setup_transfer(&qspi->qspi, NULL);
+
+ return &qspi->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct zynq_qspi_slave *qspi;
+
+ debug("%s: slave: 0x%08x\n", __func__, (u32)slave);
+
+ qspi = to_zynq_qspi_slave(slave);
+ free(qspi);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ debug("%s: slave: 0x%08x\n", __func__, (u32)slave);
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ debug("%s: slave: 0x%08x\n", __func__, (u32)slave);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ struct zynq_qspi_slave *qspi;
+ struct spi_transfer transfer;
+
+ debug("%s: slave: 0x%08x bitlen: %d dout: 0x%08x ", __func__,
+ (u32)slave, bitlen, (u32)dout);
+ debug("din: 0x%08x flags: 0x%lx\n", (u32)din, flags);
+
+ qspi = (struct zynq_qspi_slave *)slave;
+ transfer.tx_buf = dout;
+ transfer.rx_buf = din;
+ transfer.len = bitlen / 8;
+
+ /*
+ * Festering sore.
+ * Assume that the beginning of a transfer with bits to
+ * transmit must contain a device command.
+ */
+ if (dout && flags & SPI_XFER_BEGIN)
+ qspi->qspi.master.is_inst = 1;
+ else
+ qspi->qspi.master.is_inst = 0;
+
+ if (flags & SPI_XFER_END)
+ transfer.cs_change = 1;
+ else
+ transfer.cs_change = 0;
+
+ if (flags & SPI_XFER_U_PAGE)
+ qspi->qspi.master.u_page = 1;
+ else
+ qspi->qspi.master.u_page = 0;
+
+ transfer.delay_usecs = 0;
+ transfer.bits_per_word = 32;
+ transfer.speed_hz = qspi->qspi.max_speed_hz;
+
+ zynq_qspi_transfer(&qspi->qspi, &transfer);
+
+ return 0;
+}
/*
* Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr'
* into 'buffer'.
- * Return the number of bytes read or -1 on fatal errors.
+ * Update the number of bytes read in *gotsize or return -1 on fatal errors.
*/
+#ifndef CONFIG_ZYNQ_OCM
+#if defined(CONFIG_ZYNQ) && defined(CONFIG_SPL_BUILD)
+__section(.ddr)
+#endif
__u8 get_contents_vfatname_block[MAX_CLUSTSIZE]
__aligned(ARCH_DMA_MINALIGN);
+#else
+__u8 *get_contents_vfatname_block = (__u8 *)FAT_BUFF_PTR_OCM;
+#endif
- static long
- get_contents(fsdata *mydata, dir_entry *dentptr, unsigned long pos,
- __u8 *buffer, unsigned long maxsize)
+ static int get_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos,
+ __u8 *buffer, loff_t maxsize, loff_t *gotsize)
{
- unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
+ loff_t filesize = FAT2CPU32(dentptr->size);
unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
__u32 curclust = START(dentptr);
__u32 endclust, newclust;
return ret;
}
+#ifndef CONFIG_ZYNQ_OCM
+#if defined(CONFIG_ZYNQ) && defined(CONFIG_SPL_BUILD)
+__section(.ddr)
+#endif
__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
__aligned(ARCH_DMA_MINALIGN);
+#endif
- long
- do_fat_read_at(const char *filename, unsigned long pos, void *buffer,
- unsigned long maxsize, int dols, int dogetsize)
+ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
+ loff_t maxsize, int dols, int dogetsize, loff_t *size)
{
char fnamecopy[2048];
boot_sector bs;
__u32 cursect;
int idx, isdir = 0;
int files = 0, dirs = 0;
- long ret = -1;
+ int ret = -1;
int firsttime;
__u32 root_cluster = 0;
+ __u32 read_blk;
int rootdir_size = 0;
- int j;
+#ifdef CONFIG_ZYNQ_OCM
+ __u8 do_fat_read_at_block[MAX_CLUSTSIZE]
+ __aligned(ARCH_DMA_MINALIGN);
+#endif
+ int buffer_blk_cnt;
+ int do_read;
+ __u8 *dir_ptr;
if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
debug("Error: reading boot sector\n");
#include "../board/xilinx/microblaze-generic/xparameters.h"
-
- #define CONFIG_MICROBLAZE 1 /* MicroBlaze CPU */
-/* MicroBlaze CPU */
#define MICROBLAZE_V5 1
-/* linear and spi flash memory */
-#ifdef XILINX_FLASH_START
-#define FLASH
-#undef SPIFLASH
-#undef RAMENV /* hold environment in flash */
-#else
-#ifdef XILINX_SPI_FLASH_BASEADDR
-#undef FLASH
-#define SPIFLASH
-#undef RAMENV /* hold environment in flash */
-#else
-#undef FLASH
-#undef SPIFLASH
-#define RAMENV /* hold environment in RAM */
-#endif
+/* Memory test handling */
+#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE
+#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x1000)
+
+/* global pointer */
+/* start of global data */
+#define CONFIG_SYS_GBL_DATA_OFFSET (CONFIG_SYS_SDRAM_SIZE - GENERATED_GBL_DATA_SIZE)
+
+/* monitor code */
+#define SIZE 0x40000
+#define CONFIG_SYS_MONITOR_LEN SIZE
+#define CONFIG_SYS_MONITOR_BASE (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET - CONFIG_SYS_MONITOR_LEN - GENERATED_BD_INFO_SIZE)
+
+#define CONFIG_SYS_MONITOR_END (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN)
+#define CONFIG_SYS_MALLOC_LEN SIZE
+#define CONFIG_SYS_MALLOC_BASE (CONFIG_SYS_MONITOR_BASE - CONFIG_SYS_MALLOC_LEN)
+
+/* stack */
+#define CONFIG_SYS_INIT_SP_OFFSET CONFIG_SYS_MALLOC_BASE
+
+#define CONFIG_SYS_BOOTMAPSZ (1 << 31) /* Initial Memory map for Linux */
+
+#undef CONFIG_PHYLIB
+#define CONFIG_LMB 1
+
+/* Default cache size if not specified */
+#ifndef XILINX_DCACHE_BYTE_SIZE
+# define XILINX_DCACHE_BYTE_SIZE 32768
#endif
-/* uart */
+
+/* The following table includes the supported baudrates */
+#define CONFIG_SYS_BAUDRATE_TABLE \
+ {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400}
+
+/* use serial multi for all serial devices */
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV 1
+
#ifdef XILINX_UARTLITE_BASEADDR
# define CONFIG_XILINX_UARTLITE
-# define CONFIG_SERIAL_BASE XILINX_UARTLITE_BASEADDR
-# define CONFIG_BAUDRATE XILINX_UARTLITE_BAUDRATE
-# define CONFIG_SYS_BAUDRATE_TABLE { CONFIG_BAUDRATE }
-# define CONSOLE_ARG "console=console=ttyUL0,115200\0"
-#elif XILINX_UART16550_BASEADDR
-# define CONFIG_SYS_NS16550 1
+# if defined(XILINX_UARTLITE_BAUDRATE)
+# define CONFIG_BAUDRATE XILINX_UARTLITE_BAUDRATE
+# endif
+#endif
+
+#if XILINX_UART16550_BASEADDR
+# define CONFIG_SYS_NS16550 1
# define CONFIG_SYS_NS16550_SERIAL
+# define CONFIG_SYS_NS16550_COM1 ((XILINX_UART16550_BASEADDR & ~0xF) + 0x1000)
+# define CONFIG_SYS_NS16550_CLK XILINX_UART16550_CLOCK_HZ
+
# if defined(__MICROBLAZEEL__)
# define CONFIG_SYS_NS16550_REG_SIZE -4
# else
#define CONFIG_FIT_VERBOSE 1 /* enable fit_format_{error,warning}() */
#define CONFIG_IMAGE_FORMAT_LEGACY /* enable also legacy image format */
-/* RSA support */
-#define CONFIG_FIT_SIGNATURE
-#define CONFIG_RSA
-
+ /* FDT support */
+ #define CONFIG_DISPLAY_BOARDINFO_LATE
+
/* Extend size of kernel image for uncompression */
#define CONFIG_SYS_BOOTM_LEN (60 * 1024 * 1024)
/* Commands */
#include <config_cmd_default.h>
-#define CONFIG_CMD_PING
-#define CONFIG_CMD_DHCP
-#define CONFIG_CMD_MII
-#define CONFIG_CMD_TFTPPUT
+#ifdef CONFIG_SYS_ENET
+# define CONFIG_CMD_PING
+# define CONFIG_CMD_DHCP
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_TFTPPUT
+#else
+# undef CONFIG_CMD_NET
+# undef CONFIG_CMD_NFS
+#endif
+
+#if defined(CONFIG_CMD_ZYNQ_RSA)
+#define CONFIG_RSA
+#define CONFIG_SHA256
+#define CONFIG_CMD_ZYNQ_AES
+#endif
+
+#define CONFIG_CMD_BOOTZ
+#undef CONFIG_BOOTM_NETBSD
+
+#define CONFIG_SYS_HZ 1000
+
+/* For development/debugging */
+#ifdef DEBUG
+# define CONFIG_CMD_REGINFO
+# define CONFIG_PANIC_HANG
+#endif
/* SPL part */
- #define CONFIG_SPL
#define CONFIG_CMD_SPL
#define CONFIG_SPL_FRAMEWORK
#define CONFIG_SPL_LIBCOMMON_SUPPORT
/* Address in RAM where the parameters must be copied by SPL. */
#define CONFIG_SYS_SPL_ARGS_ADDR 0x10000000
+#define CONFIG_SYS_SPI_ARGS_OFFS 0 /* FIXME */
+#define CONFIG_SYS_SPI_ARGS_SIZE 0 /* FIXME */
- #define CONFIG_SPL_FAT_LOAD_ARGS_NAME "system.dtb"
- #define CONFIG_SPL_FAT_LOAD_KERNEL_NAME "uImage"
+ #define CONFIG_SPL_FS_LOAD_ARGS_NAME "system.dtb"
+ #define CONFIG_SPL_FS_LOAD_KERNEL_NAME "uImage"
/* Not using MMC raw mode - just for compilation purpose */
#define CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR 0
#define CONFIG_SPL_SPI_SUPPORT
#define CONFIG_SPL_SPI_LOAD
#define CONFIG_SPL_SPI_FLASH_SUPPORT
- #define CONFIG_SPL_SPI_BUS 0
- #define CONFIG_SYS_SPI_U_BOOT_OFFS 0x80000
- #define CONFIG_SPL_SPI_CS 0
+ #define CONFIG_SYS_SPI_U_BOOT_OFFS 0x100000
#endif
+#ifdef DEBUG
+#define CONFIG_SPL_RAM_DEVICE
+#define CONFIG_SPL_NET_SUPPORT
+#define CONFIG_SPL_ETH_SUPPORT
+#define CONFIG_SPL_ENV_SUPPORT
+#define CONFIG_SPL_ETH_DEVICE "Gem.e000b000"
+#endif
+
/* for booting directly linux */
#define CONFIG_SPL_OS_BOOT
+#define CONFIG_SYS_SPI_KERNEL_OFFS 0 /* FIXME */
/* SP location before relocation, must use scratch RAM */
#define CONFIG_SPL_TEXT_BASE 0x0
--- /dev/null
- #undef CONFIG_CMD_GO
- #undef CONFIG_CMD_BOOTM
+/*
+ * (C) Copyright 2013 Xilinx.
+ *
+ * Configuration settings for the Xilinx Zynq CSE board.
+ * See zynq-common.h for Zynq common configs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_ZYNQ_CSE_H
+#define __CONFIG_ZYNQ_CSE_H
+
+#define CONFIG_SYS_NO_FLASH
+#define CONFIG_ZYNQ_DCC
+#define _CONFIG_CMD_DEFAULT_H
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_SYS_DCACHE_OFF
+
+#if defined(CONFIG_CSE_QSPI)
+# define CONFIG_ZYNQ_QSPI
+
+#elif defined(CONFIG_CSE_NAND)
+# define CONFIG_NAND_ZYNQ
+
+#elif defined(CONFIG_CSE_NOR)
+#undef CONFIG_SYS_NO_FLASH
+
+#endif
+
+#include <configs/zynq-common.h>
+
+/* Undef unneeded configs */
+#undef CONFIG_SYS_SDRAM_BASE
+#undef CONFIG_OF_LIBFDT
+#undef CONFIG_EXTRA_ENV_SETTINGS
+#undef CONFIG_BOARD_LATE_INIT
+#undef CONFIG_FPGA
+#undef CONFIG_FPGA_XILINX
+#undef CONFIG_FPGA_ZYNQPL
+#undef CONFIG_CMD_FPGA
+#undef CONFIG_FIT
+#undef CONFIG_FIT_VERBOSE
+#undef CONFIG_CMD_BOOTZ
+#undef CONFIG_BOOTCOMMAND
+#undef CONFIG_SYS_HUSH_PARSER
+#undef CONFIG_SYS_PROMPT_HUSH_PS2
+#undef CONFIG_BOOTDELAY
+#undef CONFIG_SYS_MALLOC_LEN
+#undef CONFIG_ENV_SIZE
+#undef CONFIG_CMDLINE_EDITING
+#undef CONFIG_AUTO_COMPLETE
+#undef CONFIG_ZLIB
+#undef CONFIG_GZIP
+#undef CONFIG_CMD_SPL
+
+/* Define needed configs */
+#define CONFIG_CMD_MEMORY
+#define CONFIG_BOOTDELAY -1 /* -1 to Disable autoboot */
+#define CONFIG_SYS_MALLOC_LEN 0x4000
+
+#if defined(CONFIG_CSE_QSPI)
+# define CONFIG_SYS_SDRAM_SIZE (256 * 1024)
+# define CONFIG_SYS_SDRAM_BASE 0xFFFD0000
+# define CONFIG_ENV_SIZE 1400
+
+#elif defined(CONFIG_CSE_NAND)
+# define CONFIG_SYS_SDRAM_SIZE (4 * 1024 * 1024)
+# define CONFIG_SYS_SDRAM_BASE 0
+# define CONFIG_ENV_SIZE 0x10000
+
+#elif defined(CONFIG_CSE_NOR)
+# define CONFIG_SYS_SDRAM_SIZE (256 * 1024)
+# define CONFIG_SYS_SDRAM_BASE 0xFFFD0000
+# define CONFIG_ENV_SIZE 1400
+
+#endif
+
+#endif /* __CONFIG_ZYNQ_CSE_H */
# define CONFIG_ZYNQ_GEM0
# define CONFIG_ZYNQ_GEM_PHY_ADDR0 7
# define CONFIG_ZYNQ_SDHCI0
-# define CONFIG_ZYNQ_SPI
+# define CONFIG_ZYNQ_QSPI
- # define CONFIG_DEFAULT_DEVICE_TREE zynq-zc770-xm010
+
+#elif defined(CONFIG_ZC770_XM011)
+# define CONFIG_ZYNQ_SERIAL_UART1
+# define CONFIG_NAND_ZYNQ
- # define CONFIG_DEFAULT_DEVICE_TREE zynq-zc770-xm011
#elif defined(CONFIG_ZC770_XM012)
# define CONFIG_ZYNQ_SERIAL_UART1
# define CONFIG_ZYNQ_SERIAL_UART0
# define CONFIG_ZYNQ_GEM1
# define CONFIG_ZYNQ_GEM_PHY_ADDR1 7
- # define CONFIG_DEFAULT_DEVICE_TREE zynq-zc770-xm013
+# define CONFIG_ZYNQ_QSPI
#else
# define CONFIG_ZYNQ_SERIAL_UART0
#define CONFIG_ZYNQ_USB
#define CONFIG_ZYNQ_SDHCI0
+#define CONFIG_ZYNQ_QSPI
+
#define CONFIG_ZYNQ_BOOT_FREEBSD
- #define CONFIG_DEFAULT_DEVICE_TREE zynq-zed
#include <configs/zynq-common.h>
#ifndef _SPI_FLASH_H_
#define _SPI_FLASH_H_
- #include <spi.h>
+ #include <dm.h> /* Because we dereference struct udevice here */
#include <linux/types.h>
- #include <linux/compiler.h>
-
- /* sf param flags */
- #define SECT_4K 1 << 1
- #define SECT_32K 1 << 2
- #define E_FSR 1 << 3
- #define WR_QPP 1 << 4
-
- /* Enum list - Full read commands */
- enum spi_read_cmds {
- ARRAY_SLOW = 1 << 0,
- DUAL_OUTPUT_FAST = 1 << 1,
- DUAL_IO_FAST = 1 << 2,
- QUAD_OUTPUT_FAST = 1 << 3,
- QUAD_IO_FAST = 1 << 4,
- };
- #define RD_EXTN ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST
- #define RD_FULL RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST
-
- /* Dual SPI flash memories */
- enum spi_dual_flash {
- SF_SINGLE_FLASH = 0,
- SF_DUAL_STACKED_FLASH = 1 << 0,
- SF_DUAL_PARALLEL_FLASH = 1 << 1,
- };
- /**
- * struct spi_flash_params - SPI/QSPI flash device params structure
- *
- * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
- * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
- * @ext_jedec: Device ext_jedec ID
- * @sector_size: Sector size of this device
- * @nr_sectors: No.of sectors on this device
- * @e_rd_cmd: Enum list for read commands
- * @flags: Important param, for flash specific behaviour
- */
- struct spi_flash_params {
- const char *name;
- u32 jedec;
- u16 ext_jedec;
- u32 sector_size;
- u32 nr_sectors;
- u8 e_rd_cmd;
- u16 flags;
- };
+#define SF_DUALIO_FLASH 1
+
+ #ifndef CONFIG_SF_DEFAULT_SPEED
+ # define CONFIG_SF_DEFAULT_SPEED 1000000
+ #endif
+ #ifndef CONFIG_SF_DEFAULT_MODE
+ # define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
+ #endif
+ #ifndef CONFIG_SF_DEFAULT_CS
+ # define CONFIG_SF_DEFAULT_CS 0
+ #endif
+ #ifndef CONFIG_SF_DEFAULT_BUS
+ # define CONFIG_SF_DEFAULT_BUS 0
+ #endif
- extern const struct spi_flash_params spi_flash_params_table[];
+ struct spi_slave;
/**
* struct spi_flash - SPI flash structure
for (i = 0; i < key->len; ++i)
montgomery_mul_add_step(key, result, a[i], b);
}
-
+#if IMAGE_ENABLE_VERIFY
+ /**
+ * num_pub_exponent_bits() - Number of bits in the public exponent
+ *
+ * @key: RSA key
+ * @num_bits: Storage for the number of public exponent bits
+ */
+ static int num_public_exponent_bits(const struct rsa_public_key *key,
+ int *num_bits)
+ {
+ uint64_t exponent;
+ int exponent_bits;
+ const uint max_bits = (sizeof(exponent) * 8);
+
+ exponent = key->exponent;
+ exponent_bits = 0;
+
+ if (!exponent) {
+ *num_bits = exponent_bits;
+ return 0;
+ }
+
+ for (exponent_bits = 1; exponent_bits < max_bits + 1; ++exponent_bits)
+ if (!(exponent >>= 1)) {
+ *num_bits = exponent_bits;
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ /**
+ * is_public_exponent_bit_set() - Check if a bit in the public exponent is set
+ *
+ * @key: RSA key
+ * @pos: The bit position to check
+ */
+ static int is_public_exponent_bit_set(const struct rsa_public_key *key,
+ int pos)
+ {
+ return key->exponent & (1ULL << pos);
+ }
+
/**
* pow_mod() - in-place public exponentiation
*