mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 13:11:31 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-spi
This commit is contained in:
commit
891b487098
57 changed files with 884 additions and 1886 deletions
14
README
14
README
|
@ -3079,26 +3079,12 @@ CBFS (Coreboot Filesystem) support
|
|||
Define this option to include a destructive SPI flash
|
||||
test ('sf test').
|
||||
|
||||
CONFIG_SPI_FLASH_BAR Ban/Extended Addr Reg
|
||||
|
||||
Define this option to use the Bank addr/Extended addr
|
||||
support on SPI flashes which has size > 16Mbytes.
|
||||
|
||||
CONFIG_SF_DUAL_FLASH Dual flash memories
|
||||
|
||||
Define this option to use dual flash support where two flash
|
||||
memories can be connected with a given cs line.
|
||||
Currently Xilinx Zynq qspi supports these type of connections.
|
||||
|
||||
CONFIG_SPI_FLASH_MTD spi-flash MTD layer
|
||||
|
||||
Define this option to use mtd support for spi flash layer, this
|
||||
adapter is for translating mtd_read/mtd_write commands into
|
||||
spi_flash_read/spi_flash_write commands. It is not intended to
|
||||
use it within sf_cmd or the SPI flash subsystem. Such an adapter
|
||||
is needed for subsystems like UBI which can only operate on top
|
||||
of the MTD layer.
|
||||
|
||||
- SystemACE Support:
|
||||
CONFIG_SYSTEMACE
|
||||
|
||||
|
|
|
@ -670,7 +670,11 @@ config ARCH_ZYNQ
|
|||
bool "Xilinx Zynq Platform"
|
||||
select CPU_V7
|
||||
select SUPPORT_SPL
|
||||
select OF_CONTROL
|
||||
select SPL_DISABLE_OF_CONTROL
|
||||
select DM
|
||||
select DM_SPI
|
||||
select DM_SPI_FLASH
|
||||
|
||||
config TARGET_XILINX_ZYNQMP
|
||||
bool "Support Xilinx ZynqMP Platform"
|
||||
|
|
|
@ -109,6 +109,32 @@
|
|||
interrupts = <0 50 4>;
|
||||
};
|
||||
|
||||
spi0: spi@e0006000 {
|
||||
compatible = "xlnx,zynq-spi";
|
||||
reg = <0xe0006000 0x1000>;
|
||||
status = "disabled";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 26 4>;
|
||||
clocks = <&clkc 25>, <&clkc 34>;
|
||||
clock-names = "ref_clk", "pclk";
|
||||
spi-max-frequency = <166666700>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
spi1: spi@e0007000 {
|
||||
compatible = "xlnx,zynq-spi";
|
||||
reg = <0xe0007000 0x1000>;
|
||||
status = "disabled";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 49 4>;
|
||||
clocks = <&clkc 26>, <&clkc 35>;
|
||||
clock-names = "ref_clk", "pclk";
|
||||
spi-max-frequency = <166666700>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
gem0: ethernet@e000b000 {
|
||||
compatible = "cdns,gem";
|
||||
reg = <0xe000b000 0x4000>;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
aliases {
|
||||
serial0 = &uart1;
|
||||
spi1 = &spi1;
|
||||
};
|
||||
|
||||
memory {
|
||||
|
@ -21,3 +22,7 @@
|
|||
reg = <0 0x40000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&spi1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -311,6 +311,11 @@ config CMD_NAND
|
|||
help
|
||||
NAND support.
|
||||
|
||||
config CMD_SF
|
||||
bool "sf"
|
||||
help
|
||||
SPI Flash support
|
||||
|
||||
config CMD_SPI
|
||||
bool "sspi"
|
||||
help
|
||||
|
|
|
@ -17,4 +17,5 @@ CONFIG_TARGET_ALT=y
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
# CONFIG_CMD_MISC is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
CONFIG_SH_SDHI=y
|
||||
|
|
|
@ -5,4 +5,5 @@ CONFIG_SYS_EXTRA_OPTIONS="SERIAL1,CONS_INDEX=1,NAND"
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
CONFIG_SPI_FLASH=y
|
||||
|
|
|
@ -4,3 +4,4 @@ CONFIG_SPL=y
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
|
|
|
@ -8,3 +8,4 @@ CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=1"
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
# CONFIG_CMD_NFS is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
|
|
|
@ -17,4 +17,5 @@ CONFIG_TARGET_GOSE=y
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
# CONFIG_CMD_MISC is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
CONFIG_SH_SDHI=y
|
||||
|
|
|
@ -17,4 +17,5 @@ CONFIG_TARGET_KOELSCH=y
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
# CONFIG_CMD_MISC is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
CONFIG_SH_SDHI=y
|
||||
|
|
|
@ -17,4 +17,5 @@ CONFIG_TARGET_LAGER=y
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
# CONFIG_CMD_MISC is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
CONFIG_SH_SDHI=y
|
||||
|
|
|
@ -5,3 +5,4 @@ CONFIG_SPL=y
|
|||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
|
|
|
@ -5,3 +5,4 @@ CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6sxsabresd/imximage.cfg,M
|
|||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
|
|
|
@ -17,4 +17,5 @@ CONFIG_TARGET_PORTER=y
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
# CONFIG_CMD_MISC is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
CONFIG_SH_SDHI=y
|
||||
|
|
|
@ -17,4 +17,5 @@ CONFIG_TARGET_SILK=y
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
# CONFIG_CMD_MISC is not set
|
||||
CONFIG_SPI_FLASH=y
|
||||
CONFIG_SPI_FLASH_BAR=y
|
||||
CONFIG_SH_SDHI=y
|
||||
|
|
|
@ -10,5 +10,3 @@ CONFIG_FIT_SIGNATURE=y
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_DISABLE_OF_CONTROL=y
|
||||
|
|
|
@ -10,4 +10,3 @@ CONFIG_FIT_SIGNATURE=y
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
|
|
|
@ -10,4 +10,3 @@ CONFIG_FIT_SIGNATURE=y
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
|
|
|
@ -10,5 +10,3 @@ CONFIG_FIT_SIGNATURE=y
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_DISABLE_OF_CONTROL=y
|
||||
|
|
|
@ -11,6 +11,4 @@ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM010"
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_DISABLE_OF_CONTROL=y
|
||||
CONFIG_SPI_FLASH=y
|
||||
|
|
|
@ -9,5 +9,3 @@ CONFIG_FIT_VERBOSE=y
|
|||
CONFIG_FIT_SIGNATURE=y
|
||||
CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM012"
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_DISABLE_OF_CONTROL=y
|
||||
|
|
|
@ -11,5 +11,3 @@ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM013"
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_DISABLE_OF_CONTROL=y
|
||||
|
|
|
@ -10,5 +10,3 @@ CONFIG_FIT_SIGNATURE=y
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_DISABLE_OF_CONTROL=y
|
||||
|
|
|
@ -10,5 +10,3 @@ CONFIG_FIT_SIGNATURE=y
|
|||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_DISABLE_OF_CONTROL=y
|
||||
|
|
29
doc/device-tree-bindings/spi/spi-zynq.txt
Normal file
29
doc/device-tree-bindings/spi/spi-zynq.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
Zynq SPI controller Device Tree Bindings
|
||||
----------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "xlnx,spi-zynq".
|
||||
- reg : Physical base address and size of SPI registers map.
|
||||
- status : Status will be disabled in dtsi and enabled in required dts.
|
||||
- interrupt-parent : Must be core interrupt controller.
|
||||
- interrupts : Property with a value describing the interrupt
|
||||
number.
|
||||
- clocks : Clock phandles (see clock bindings for details).
|
||||
- clock-names : List of input clock names - "ref_clk", "pclk"
|
||||
(See clock bindings for details).
|
||||
- spi-max-frequency : Maximum SPI clocking speed of device in Hz
|
||||
|
||||
Example:
|
||||
|
||||
spi@e0006000 {
|
||||
compatible = "xlnx,zynq-spi";
|
||||
reg = <0xe0006000 0x1000>;
|
||||
status = "disabled";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 26 4>;
|
||||
clocks = <&clkc 25>, <&clkc 34>;
|
||||
clock-names = "ref_clk", "pclk";
|
||||
spi-max-frequency = <166666700>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
} ;
|
|
@ -1,11 +1,4 @@
|
|||
config SPI_FLASH
|
||||
bool "Enable SPI Flash support"
|
||||
help
|
||||
Enable the legacy SPI flash support. This will include basic
|
||||
standard support for things like probing, read / write, and
|
||||
erasing through the MTD layer.
|
||||
|
||||
If unsure, say N
|
||||
menu "SPI Flash Support"
|
||||
|
||||
config DM_SPI_FLASH
|
||||
bool "Enable Driver Model for SPI flash"
|
||||
|
@ -31,3 +24,49 @@ config SPI_FLASH_SANDBOX
|
|||
bus (see CONFIG_SANDBOX_SPI) and SPI traffic will be routed to this
|
||||
device. Typically the contents of the emulated SPI flash device is
|
||||
stored in a file on the host filesystem.
|
||||
|
||||
config SPI_FLASH
|
||||
bool "Legacy SPI Flash Interface support"
|
||||
help
|
||||
Enable the legacy SPI flash support. This will include basic
|
||||
standard support for things like probing, read / write, and
|
||||
erasing through cmd_sf interface.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config SPI_FLASH_BAR
|
||||
bool "SPI flash Bank/Extended address register support"
|
||||
depends on SPI_FLASH
|
||||
help
|
||||
Enable the SPI flash Bank/Extended address register support.
|
||||
Bank/Extended address registers are used to access the flash
|
||||
which has size > 16MiB in 3-byte addressing.
|
||||
|
||||
config SPI_FLASH_DATAFLASH
|
||||
bool "AT45xxx DataFlash support"
|
||||
depends on SPI_FLASH && DM_SPI_FLASH
|
||||
help
|
||||
Enable the access for SPI-flash-based AT45xxx DataFlash chips.
|
||||
DataFlash is a kind of SPI flash. Most AT45 chips have two buffers
|
||||
in each chip, which may be used for double buffered I/O; but this
|
||||
driver doesn't (yet) use these for any kind of i/o overlap or prefetching.
|
||||
|
||||
Sometimes DataFlash is packaged in MMC-format cards, although the
|
||||
MMC stack can't (yet?) distinguish between MMC and DataFlash
|
||||
protocols during enumeration.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config SPI_FLASH_MTD
|
||||
bool "SPI Flash MTD support"
|
||||
depends on SPI_FLASH
|
||||
help
|
||||
Enable the MTD support for spi flash layer, this adapter is for
|
||||
translating mtd_read/mtd_write commands into spi_flash_read/write
|
||||
commands. It is not intended to use it within sf_cmd or the SPI
|
||||
flash subsystem. Such an adapter is needed for subsystems like
|
||||
UBI which can only operate on top of the MTD layer.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
endmenu # menu "SPI Flash Support"
|
||||
|
|
|
@ -15,9 +15,9 @@ endif
|
|||
#ifndef CONFIG_DM_SPI
|
||||
obj-$(CONFIG_SPI_FLASH) += sf_probe.o
|
||||
#endif
|
||||
obj-$(CONFIG_SF_DATAFLASH) += sf_dataflash.o
|
||||
obj-$(CONFIG_CMD_SF) += sf.o
|
||||
obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o
|
||||
obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
|
||||
obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
|
||||
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
|
||||
obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
|
||||
|
|
|
@ -19,16 +19,6 @@
|
|||
|
||||
#include "sf_internal.h"
|
||||
|
||||
/*
|
||||
* DataFlash is a kind of SPI flash. Most AT45 chips have two buffers in
|
||||
* each chip, which may be used for double buffered I/O; but this driver
|
||||
* doesn't (yet) use these for any kind of i/o overlap or prefetching.
|
||||
*
|
||||
* Sometimes DataFlash is packaged in MMC-format cards, although the
|
||||
* MMC stack can't (yet?) distinguish between MMC and DataFlash
|
||||
* protocols during enumeration.
|
||||
*/
|
||||
|
||||
/* reads can bypass the buffers */
|
||||
#define OP_READ_CONTINUOUS 0xE8
|
||||
#define OP_READ_PAGE 0xD2
|
||||
|
|
|
@ -31,9 +31,9 @@ enum spi_read_cmds {
|
|||
};
|
||||
|
||||
/* Normal - Extended - Full command set */
|
||||
#define RD_NORM (ARRAY_SLOW | ARRAY_FAST)
|
||||
#define RD_EXTN (RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
|
||||
#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
|
||||
#define RD_NORM (ARRAY_SLOW | ARRAY_FAST)
|
||||
#define RD_EXTN (RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
|
||||
#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
|
||||
|
||||
/* sf param flags */
|
||||
enum {
|
||||
|
@ -67,12 +67,12 @@ enum {
|
|||
#define CMD_WRITE_STATUS 0x01
|
||||
#define CMD_PAGE_PROGRAM 0x02
|
||||
#define CMD_WRITE_DISABLE 0x04
|
||||
#define CMD_READ_STATUS 0x05
|
||||
#define CMD_READ_STATUS 0x05
|
||||
#define CMD_QUAD_PAGE_PROGRAM 0x32
|
||||
#define CMD_READ_STATUS1 0x35
|
||||
#define CMD_WRITE_ENABLE 0x06
|
||||
#define CMD_READ_CONFIG 0x35
|
||||
#define CMD_FLAG_STATUS 0x70
|
||||
#define CMD_READ_CONFIG 0x35
|
||||
#define CMD_FLAG_STATUS 0x70
|
||||
|
||||
/* Read commands */
|
||||
#define CMD_READ_ARRAY_SLOW 0x03
|
||||
|
@ -99,13 +99,13 @@ enum {
|
|||
|
||||
/* Flash timeout values */
|
||||
#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ)
|
||||
#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ)
|
||||
#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ)
|
||||
#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ)
|
||||
|
||||
/* SST specific */
|
||||
#ifdef CONFIG_SPI_FLASH_SST
|
||||
# define CMD_SST_BP 0x02 /* Byte Program */
|
||||
# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
|
||||
# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
|
||||
|
||||
int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
|
||||
const void *buf);
|
||||
|
@ -121,7 +121,7 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
|
|||
* @ext_jedec: Device ext_jedec ID
|
||||
* @sector_size: Isn't necessarily a sector size from vendor,
|
||||
* the size listed here is what works with CMD_ERASE_64K
|
||||
* @nr_sectors: No.of sectors on 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
|
||||
*/
|
||||
|
|
|
@ -100,7 +100,7 @@ const struct spi_flash_params spi_flash_params_table[] = {
|
|||
{"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, RD_NORM, SECT_4K | SST_WR},
|
||||
{"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, RD_NORM, SECT_4K | SST_WR},
|
||||
{"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
|
||||
{"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
|
||||
{"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K},
|
||||
{"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K | SST_WR},
|
||||
#endif
|
||||
#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
menu "SPI Support"
|
||||
|
||||
config DM_SPI
|
||||
bool "Enable Driver Model for SPI drivers"
|
||||
depends on DM
|
||||
|
@ -11,6 +13,51 @@ config DM_SPI
|
|||
typically use driver-private data instead of extending the
|
||||
spi_slave structure.
|
||||
|
||||
if DM_SPI
|
||||
|
||||
config CADENCE_QSPI
|
||||
bool "Cadence QSPI driver"
|
||||
help
|
||||
Enable the Cadence Quad-SPI (QSPI) driver. This driver can be
|
||||
used to access the SPI NOR flash on platforms embedding this
|
||||
Cadence IP core.
|
||||
|
||||
config DESIGNWARE_SPI
|
||||
bool "Designware SPI driver"
|
||||
help
|
||||
Enable the Designware SPI driver. This driver can be used to
|
||||
access the SPI NOR flash on platforms embedding this Designware
|
||||
IP core.
|
||||
|
||||
config EXYNOS_SPI
|
||||
bool "Samsung Exynos SPI driver"
|
||||
help
|
||||
Enable the Samsung Exynos SPI driver. This driver can be used to
|
||||
access the SPI NOR flash on platforms embedding this Samsung
|
||||
Exynos IP core.
|
||||
|
||||
config FSL_DSPI
|
||||
bool "Freescale DSPI driver"
|
||||
help
|
||||
Enable the Freescale DSPI driver. This driver can be used to
|
||||
access the SPI NOR flash and SPI Data flash on platforms embedding
|
||||
this Freescale DSPI IP core. LS102xA and Colibri VF50/VF61 platforms
|
||||
use this driver.
|
||||
|
||||
config FSL_QSPI
|
||||
bool "Freescale QSPI driver"
|
||||
help
|
||||
Enable the Freescale Quad-SPI (QSPI) driver. This driver can be
|
||||
used to access the SPI NOR flash on platforms embedding this
|
||||
Freescale IP core.
|
||||
|
||||
config ICH_SPI
|
||||
bool "Intel ICH SPI driver"
|
||||
help
|
||||
Enable the Intel ICH SPI driver. This driver can be used to
|
||||
access the SPI NOR flash on platforms embedding this Intel
|
||||
ICH IP core.
|
||||
|
||||
config SANDBOX_SPI
|
||||
bool "Sandbox SPI driver"
|
||||
depends on SANDBOX && DM
|
||||
|
@ -34,20 +81,61 @@ config SANDBOX_SPI
|
|||
spi-max-frequency = <40000000>;
|
||||
sandbox,filename = "spi.bin";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config DESIGNWARE_SPI
|
||||
bool "Designware SPI driver"
|
||||
depends on DM_SPI
|
||||
config TEGRA114_SPI
|
||||
bool "nVidia Tegra114 SPI driver"
|
||||
help
|
||||
Enable the Designware SPI driver. This driver can be used to
|
||||
access the SPI NOR flash on platforms embedding this Designware
|
||||
Enable the nVidia Tegra114 SPI driver. This driver can be used to
|
||||
access the SPI NOR flash on platforms embedding this nVidia Tegra114
|
||||
IP core.
|
||||
|
||||
config CADENCE_QSPI
|
||||
bool "Cadence QSPI driver"
|
||||
depends on DM_SPI
|
||||
This controller is different than the older SoCs SPI controller and
|
||||
also register interface get changed with this controller.
|
||||
|
||||
config TEGRA20_SFLASH
|
||||
bool "nVidia Tegra20 Serial Flash controller driver"
|
||||
help
|
||||
Enable the Cadence Quad-SPI (QSPI) driver. This driver can be
|
||||
used to access the SPI NOR flash on platforms embedding this
|
||||
Cadence IP core.
|
||||
Enable the nVidia Tegra20 Serial Flash controller driver. This driver
|
||||
can be used to access the SPI NOR flash on platforms embedding this
|
||||
nVidia Tegra20 IP core.
|
||||
|
||||
config TEGRA20_SLINK
|
||||
bool "nVidia Tegra20/Tegra30 SLINK driver"
|
||||
help
|
||||
Enable the nVidia Tegra20/Tegra30 SLINK driver. This driver can
|
||||
be used to access the SPI NOR flash on platforms embedding this
|
||||
nVidia Tegra20/Tegra30 IP cores.
|
||||
|
||||
config XILINX_SPI
|
||||
bool "Xilinx SPI driver"
|
||||
help
|
||||
Enable the Xilinx SPI driver from the Xilinx EDK. This SPI
|
||||
controller support 8 bit SPI transfers only, with or w/o FIFO.
|
||||
For more info on Xilinx SPI Register Definitions and Overview
|
||||
see driver file - drivers/spi/xilinx_spi.c
|
||||
|
||||
config ZYNQ_SPI
|
||||
bool "Zynq SPI driver"
|
||||
depends on ARCH_ZYNQ || TARGET_XILINX_ZYNQMP
|
||||
help
|
||||
Enable the Zynq SPI driver. This driver can be used to
|
||||
access the SPI NOR flash on platforms embedding this Zynq
|
||||
SPI IP core.
|
||||
|
||||
endif # if DM_SPI
|
||||
|
||||
config FSL_ESPI
|
||||
bool "Freescale eSPI driver"
|
||||
help
|
||||
Enable the Freescale eSPI driver. This driver can be used to
|
||||
access the SPI interface and SPI NOR flash on platforms embedding
|
||||
this Freescale eSPI IP core.
|
||||
|
||||
config TI_QSPI
|
||||
bool "TI QSPI driver"
|
||||
help
|
||||
Enable the TI Quad-SPI (QSPI) driver for DRA7xx and AM43xx evms.
|
||||
This driver support spi flash single, quad and memory reads.
|
||||
|
||||
endmenu # menu "SPI Support"
|
||||
|
|
|
@ -15,9 +15,7 @@ obj-y += spi.o
|
|||
obj-$(CONFIG_SOFT_SPI) += soft_spi_legacy.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o
|
||||
obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
|
||||
obj-$(CONFIG_ANDES_SPI) += andes_spi.o
|
||||
obj-$(CONFIG_ARMADA100_SPI) += armada100_spi.o
|
||||
obj-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
|
||||
obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
|
||||
|
@ -28,8 +26,11 @@ obj-$(CONFIG_CF_SPI) += cf_spi.o
|
|||
obj-$(CONFIG_CF_QSPI) += cf_qspi.o
|
||||
obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
|
||||
obj-$(CONFIG_DESIGNWARE_SPI) += designware_spi.o
|
||||
obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o
|
||||
obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
|
||||
obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
|
||||
obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
|
||||
obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
|
||||
obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
|
||||
obj-$(CONFIG_ICH_SPI) += ich.o
|
||||
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
|
||||
obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o
|
||||
|
@ -37,17 +38,13 @@ obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
|
|||
obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
|
||||
obj-$(CONFIG_MXC_SPI) += mxc_spi.o
|
||||
obj-$(CONFIG_MXS_SPI) += mxs_spi.o
|
||||
obj-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
|
||||
obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
|
||||
obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
|
||||
obj-$(CONFIG_SH_SPI) += sh_spi.o
|
||||
obj-$(CONFIG_SH_QSPI) += sh_qspi.o
|
||||
obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
|
||||
obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
|
||||
obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
|
||||
obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o
|
||||
obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
|
||||
obj-$(CONFIG_TI_QSPI) += ti_qspi.o
|
||||
obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
|
||||
obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
|
||||
obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
|
||||
obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
|
||||
|
|
|
@ -1,284 +0,0 @@
|
|||
/*
|
||||
* Driver of Andes SPI Controller
|
||||
*
|
||||
* (C) Copyright 2011 Andes Technology
|
||||
* Macpaul Lin <macpaul@andestech.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <spi.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include "andes_spi.h"
|
||||
|
||||
void spi_init(void)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static void andes_spi_spit_en(struct andes_spi_slave *ds)
|
||||
{
|
||||
unsigned int dcr = readl(&ds->regs->dcr);
|
||||
|
||||
debug("%s: dcr: %x, write value: %x\n",
|
||||
__func__, dcr, (dcr | ANDES_SPI_DCR_SPIT));
|
||||
|
||||
writel((dcr | ANDES_SPI_DCR_SPIT), &ds->regs->dcr);
|
||||
}
|
||||
|
||||
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
||||
unsigned int max_hz, unsigned int mode)
|
||||
{
|
||||
struct andes_spi_slave *ds;
|
||||
|
||||
if (!spi_cs_is_valid(bus, cs))
|
||||
return NULL;
|
||||
|
||||
ds = spi_alloc_slave(struct andes_spi_slave, bus, cs);
|
||||
if (!ds)
|
||||
return NULL;
|
||||
|
||||
ds->regs = (struct andes_spi_regs *)CONFIG_SYS_SPI_BASE;
|
||||
|
||||
/*
|
||||
* The hardware of andes_spi will set its frequency according
|
||||
* to APB/AHB bus clock. Hence the hardware doesn't allow changing of
|
||||
* requency and so the user requested speed is always ignored.
|
||||
*/
|
||||
ds->freq = max_hz;
|
||||
|
||||
return &ds->slave;
|
||||
}
|
||||
|
||||
void spi_free_slave(struct spi_slave *slave)
|
||||
{
|
||||
struct andes_spi_slave *ds = to_andes_spi(slave);
|
||||
|
||||
free(ds);
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct andes_spi_slave *ds = to_andes_spi(slave);
|
||||
unsigned int apb;
|
||||
unsigned int baud;
|
||||
|
||||
/* Enable the SPI hardware */
|
||||
writel(ANDES_SPI_CR_SPIRST, &ds->regs->cr);
|
||||
udelay(1000);
|
||||
|
||||
/* setup format */
|
||||
baud = ((CONFIG_SYS_CLK_FREQ / CONFIG_SYS_SPI_CLK / 2) - 1) & 0xFF;
|
||||
|
||||
/*
|
||||
* SPI_CLK = AHB bus clock / ((BAUD + 1)*2)
|
||||
* BAUD = AHB bus clock / SPI_CLK / 2) - 1
|
||||
*/
|
||||
apb = (readl(&ds->regs->apb) & 0xffffff00) | baud;
|
||||
writel(apb, &ds->regs->apb);
|
||||
|
||||
/* no interrupts */
|
||||
writel(0, &ds->regs->ie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct andes_spi_slave *ds = to_andes_spi(slave);
|
||||
|
||||
/* Disable the SPI hardware */
|
||||
writel(ANDES_SPI_CR_SPIRST, &ds->regs->cr);
|
||||
}
|
||||
|
||||
static int andes_spi_read(struct spi_slave *slave, unsigned int len,
|
||||
u8 *rxp, unsigned long flags)
|
||||
{
|
||||
struct andes_spi_slave *ds = to_andes_spi(slave);
|
||||
unsigned int i, left;
|
||||
unsigned int data;
|
||||
|
||||
debug("%s: slave: %x, len: %d, rxp: %x, flags: %d\n",
|
||||
__func__, slave, len, rxp, flags);
|
||||
|
||||
debug("%s: data: ", __func__);
|
||||
while (len > 0) {
|
||||
left = min(len, 4);
|
||||
data = readl(&ds->regs->data);
|
||||
|
||||
debug(" ");
|
||||
for (i = 0; i < left; i++) {
|
||||
debug("%02x ", data & 0xff);
|
||||
*rxp++ = data;
|
||||
data >>= 8;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
debug("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int andes_spi_write(struct spi_slave *slave, unsigned int wlen,
|
||||
unsigned int rlen, const u8 *txp, unsigned long flags)
|
||||
{
|
||||
struct andes_spi_slave *ds = to_andes_spi(slave);
|
||||
unsigned int data;
|
||||
unsigned int i, left;
|
||||
unsigned int spit_enabled = 0;
|
||||
|
||||
debug("%s: slave: %x, wlen: %d, rlen: %d, txp: %x, flags: %x\n",
|
||||
__func__, slave, wlen, rlen, txp, flags);
|
||||
|
||||
/* The value of wlen and rlen wrote to register must minus 1 */
|
||||
if (rlen == 0) /* write only */
|
||||
writel(ANDES_SPI_DCR_MODE_WO | ANDES_SPI_DCR_WCNT(wlen-1) |
|
||||
ANDES_SPI_DCR_RCNT(0), &ds->regs->dcr);
|
||||
else /* write then read */
|
||||
writel(ANDES_SPI_DCR_MODE_WR | ANDES_SPI_DCR_WCNT(wlen-1) |
|
||||
ANDES_SPI_DCR_RCNT(rlen-1), &ds->regs->dcr);
|
||||
|
||||
/* wait till SPIBSY is cleared */
|
||||
while (readl(&ds->regs->st) & ANDES_SPI_ST_SPIBSY)
|
||||
;
|
||||
|
||||
/* data write process */
|
||||
debug("%s: txp: ", __func__);
|
||||
while (wlen > 0) {
|
||||
/* clear the data */
|
||||
data = 0;
|
||||
|
||||
/* data are usually be read 32bits once a time */
|
||||
left = min(wlen, 4);
|
||||
|
||||
for (i = 0; i < left; i++) {
|
||||
debug("%x ", *txp);
|
||||
data |= *txp++ << (i * 8);
|
||||
wlen--;
|
||||
}
|
||||
debug("\n");
|
||||
|
||||
debug("data: %08x\n", data);
|
||||
debug("streg before write: %08x\n", readl(&ds->regs->st));
|
||||
/* wait till TXFULL is deasserted */
|
||||
while (readl(&ds->regs->st) & ANDES_SPI_ST_TXFEL)
|
||||
;
|
||||
writel(data, &ds->regs->data);
|
||||
debug("streg after write: %08x\n", readl(&ds->regs->st));
|
||||
|
||||
|
||||
if (spit_enabled == 0) {
|
||||
/* enable SPIT bit - trigger the tx and rx progress */
|
||||
andes_spi_spit_en(ds);
|
||||
spit_enabled = 1;
|
||||
}
|
||||
|
||||
}
|
||||
debug("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* spi_xfer:
|
||||
* Since andes_spi doesn't support independent command transaction,
|
||||
* that is, write and than read must be operated in continuous
|
||||
* execution, there is no need to set dcr and trigger spit again in
|
||||
* RX process.
|
||||
*/
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
unsigned int len;
|
||||
static int op_nextime;
|
||||
static u8 tmp_cmd[5];
|
||||
static int tmp_wlen;
|
||||
unsigned int i;
|
||||
|
||||
if (bitlen == 0)
|
||||
/* Finish any previously submitted transfers */
|
||||
goto out;
|
||||
|
||||
if (bitlen % 8) {
|
||||
/* Errors always terminate an ongoing transfer */
|
||||
flags |= SPI_XFER_END;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = bitlen / 8;
|
||||
|
||||
debug("%s: slave: %08x, bitlen: %d, dout: "
|
||||
"%08x, din: %08x, flags: %d, len: %d\n",
|
||||
__func__, slave, bitlen, dout, din, flags, len);
|
||||
|
||||
/*
|
||||
* Important:
|
||||
* andes_spi's hardware doesn't support 2 data channel. The read
|
||||
* and write cmd/data share the same register (data register).
|
||||
*
|
||||
* If a command has write and read transaction, you cannot do write
|
||||
* this time and then do read on next time.
|
||||
*
|
||||
* A command writes first with a read response must indicating
|
||||
* the read length in write operation. Hence the write action must
|
||||
* be stored temporary and wait until the next read action has been
|
||||
* arrived. Then we flush the write and read action out together.
|
||||
*/
|
||||
if (!dout) {
|
||||
if (op_nextime == 1) {
|
||||
/* flags should be SPI_XFER_END, value is 2 */
|
||||
op_nextime = 0;
|
||||
andes_spi_write(slave, tmp_wlen, len, tmp_cmd, flags);
|
||||
}
|
||||
return andes_spi_read(slave, len, din, flags);
|
||||
} else if (!din) {
|
||||
if (flags == SPI_XFER_BEGIN) {
|
||||
/* store the write command and do operation next time */
|
||||
op_nextime = 1;
|
||||
memset(tmp_cmd, 0, sizeof(tmp_cmd));
|
||||
memcpy(tmp_cmd, dout, len);
|
||||
|
||||
debug("%s: tmp_cmd: ", __func__);
|
||||
for (i = 0; i < len; i++)
|
||||
debug("%x ", *(tmp_cmd + i));
|
||||
debug("\n");
|
||||
|
||||
tmp_wlen = len;
|
||||
} else {
|
||||
/*
|
||||
* flags should be (SPI_XFER_BEGIN | SPI_XFER_END),
|
||||
* the value is 3.
|
||||
*/
|
||||
if (op_nextime == 1) {
|
||||
/* flags should be SPI_XFER_END, value is 2 */
|
||||
op_nextime = 0;
|
||||
/* flags 3 implies write only */
|
||||
andes_spi_write(slave, tmp_wlen, 0, tmp_cmd, 3);
|
||||
}
|
||||
|
||||
debug("flags: %x\n", flags);
|
||||
return andes_spi_write(slave, len, 0, dout, flags);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
|
||||
{
|
||||
return bus == 0 && cs == 0;
|
||||
}
|
||||
|
||||
void spi_cs_activate(struct spi_slave *slave)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
void spi_cs_deactivate(struct spi_slave *slave)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Register definitions for the Andes SPI Controller
|
||||
*
|
||||
* (C) Copyright 2011 Andes Technology
|
||||
* Macpaul Lin <macpaul@andestech.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __ANDES_SPI_H
|
||||
#define __ANDES_SPI_H
|
||||
|
||||
struct andes_spi_regs {
|
||||
unsigned int apb; /* 0x00 - APB SPI interface setting */
|
||||
unsigned int pio; /* 0x04 - PIO reg */
|
||||
unsigned int cr; /* 0x08 - SPI Control reg */
|
||||
unsigned int st; /* 0x0c - SPI Status reg */
|
||||
unsigned int ie; /* 0x10 - Interrupt Enable reg */
|
||||
unsigned int ist; /* 0x14 - Interrupt Status reg */
|
||||
unsigned int dcr; /* 0x18 - data control reg */
|
||||
unsigned int data; /* 0x1c - data register */
|
||||
unsigned int ahb; /* 0x20 - AHB SPI interface setting */
|
||||
unsigned int ver; /* 0x3c - SPI version reg */
|
||||
};
|
||||
|
||||
#define BIT(x) (1 << (x))
|
||||
|
||||
/* 0x00 - APB SPI interface setting register */
|
||||
#define ANDES_SPI_APB_BAUD(x) (((x) & 0xff) < 0)
|
||||
#define ANDES_SPI_APB_CSHT(x) (((x) & 0xf) < 16)
|
||||
#define ANDES_SPI_APB_SPNTS BIT(20) /* 0: normal, 1: delay */
|
||||
#define ANDES_SPI_APB_CPHA BIT(24) /* 0: Sampling at odd edges */
|
||||
#define ANDES_SPI_APB_CPOL BIT(25) /* 0: SCK low, 1: SCK high */
|
||||
#define ANDES_SPI_APB_MSSL BIT(26) /* 0: SPI Master, 1: slave */
|
||||
|
||||
/* 0x04 - PIO register */
|
||||
#define ANDES_SPI_PIO_MISO BIT(0) /* input value of pin MISO */
|
||||
#define ANDES_SPI_PIO_MOSI BIT(1) /* I/O value of pin MOSI */
|
||||
#define ANDES_SPI_PIO_SCK BIT(2) /* I/O value of pin SCK */
|
||||
#define ANDES_SPI_PIO_CS BIT(3) /* I/O value of pin CS */
|
||||
#define ANDES_SPI_PIO_PIOE BIT(4) /* Programming IO Enable */
|
||||
|
||||
/* 0x08 - SPI Control register */
|
||||
#define ANDES_SPI_CR_SPIRST BIT(0) /* SPI mode reset */
|
||||
#define ANDES_SPI_CR_RXFRST BIT(1) /* RxFIFO reset */
|
||||
#define ANDES_SPI_CR_TXFRST BIT(2) /* TxFIFO reset */
|
||||
#define ANDES_SPI_CR_RXFTH(x) (((x) & 0x1f) << 10) /* RxFIFO Threshold */
|
||||
#define ANDES_SPI_CR_TXFTH(x) (((x) & 0x1f) << 18) /* TxFIFO Threshold */
|
||||
|
||||
/* 0x0c - SPI Status register */
|
||||
#define ANDES_SPI_ST_SPIBSY BIT(0) /* SPI Transfer is active */
|
||||
#define ANDES_SPI_ST_RXFEM BIT(8) /* RxFIFO Empty Flag */
|
||||
#define ANDES_SPI_ST_RXFEL BIT(9) /* RxFIFO Full Flag */
|
||||
#define ANDES_SPI_ST_RXFVE(x) (((x) >> 10) & 0x1f)
|
||||
#define ANDES_SPI_ST_TXFEM BIT(16) /* TxFIFO Empty Flag */
|
||||
#define ANDES_SPI_ST_TXFEL BIT(7) /* TxFIFO Full Flag */
|
||||
#define ANDES_SPI_ST_TXFVE(x) (((x) >> 18) & 0x1f)
|
||||
|
||||
/* 0x10 - Interrupt Enable register */
|
||||
#define ANDES_SPI_IE_RXFORIE BIT(0) /* RxFIFO overrun intr */
|
||||
#define ANDES_SPI_IE_TXFURIE BIT(1) /* TxFOFO underrun intr */
|
||||
#define ANDES_SPI_IE_RXFTHIE BIT(2) /* RxFIFO threshold intr */
|
||||
#define ANDES_SPI_IE_TXFTHIE BIT(3) /* TxFIFO threshold intr */
|
||||
#define ANDES_SPI_IE_SPIEIE BIT(4) /* SPI transmit END intr */
|
||||
#define ANDES_SPI_IE_SPCFIE BIT(5) /* AHB/APB TxReq conflict */
|
||||
|
||||
/* 0x14 - Interrupt Status Register */
|
||||
#define ANDES_SPI_IST_RXFORI BIT(0) /* has RxFIFO overrun */
|
||||
#define ANDES_SPI_IST_TXFURI BIT(1) /* has TxFOFO underrun */
|
||||
#define ANDES_SPI_IST_RXFTHI BIT(2) /* has RxFIFO threshold */
|
||||
#define ANDES_SPI_IST_TXFTHI BIT(3) /* has TxFIFO threshold */
|
||||
#define ANDES_SPI_IST_SPIEI BIT(4) /* has SPI transmit END */
|
||||
#define ANDES_SPI_IST_SPCFI BIT(5) /* has AHB/APB TxReq conflict */
|
||||
|
||||
/* 0x18 - Data Control Register */
|
||||
#define ANDES_SPI_DCR_RCNT(x) (((x) & 0x3ff) << 0)
|
||||
#define ANDES_SPI_DCR_DYCNT(x) (((x) & 0x7) << 12)
|
||||
#define ANDES_SPI_DCR_WCNT(x) (((x) & 0x3ff) << 16)
|
||||
#define ANDES_SPI_DCR_TRAMODE(x) (((x) & 0x7) << 28)
|
||||
#define ANDES_SPI_DCR_SPIT BIT(31) /* SPI bus trigger */
|
||||
|
||||
#define ANDES_SPI_DCR_MODE_WRCON ANDES_SPI_DCR_TRAMODE(0) /* w/r at the same time */
|
||||
#define ANDES_SPI_DCR_MODE_WO ANDES_SPI_DCR_TRAMODE(1) /* write only */
|
||||
#define ANDES_SPI_DCR_MODE_RO ANDES_SPI_DCR_TRAMODE(2) /* read only */
|
||||
#define ANDES_SPI_DCR_MODE_WR ANDES_SPI_DCR_TRAMODE(3) /* write, read */
|
||||
#define ANDES_SPI_DCR_MODE_RW ANDES_SPI_DCR_TRAMODE(4) /* read, write */
|
||||
#define ANDES_SPI_DCR_MODE_WDR ANDES_SPI_DCR_TRAMODE(5) /* write, dummy, read */
|
||||
#define ANDES_SPI_DCR_MODE_RDW ANDES_SPI_DCR_TRAMODE(6) /* read, dummy, write */
|
||||
#define ANDES_SPI_DCR_MODE_RECEIVE ANDES_SPI_DCR_TRAMODE(7) /* receive */
|
||||
|
||||
/* 0x20 - AHB SPI interface setting register */
|
||||
#define ANDES_SPI_AHB_BAUD(x) (((x) & 0xff) < 0)
|
||||
#define ANDES_SPI_AHB_CSHT(x) (((x) & 0xf) < 16)
|
||||
#define ANDES_SPI_AHB_SPNTS BIT(20) /* 0: normal, 1: delay */
|
||||
#define ANDES_SPI_AHB_CPHA BIT(24) /* 0: Sampling at odd edges */
|
||||
#define ANDES_SPI_AHB_CPOL BIT(25) /* 0: SCK low, 1: SCK high */
|
||||
#define ANDES_SPI_AHB_MSSL BIT(26) /* only Master mode */
|
||||
|
||||
/* 0x3c - Version Register - (Year V.MAJOR.MINOR) */
|
||||
#define ANDES_SPI_VER_MINOR(x) (((x) >> 0) & 0xf)
|
||||
#define ANDES_SPI_VER_MAJOR(x) (((x) >> 8) & 0xf)
|
||||
#define ANDES_SPI_VER_YEAR(x) (((x) >> 16) & 0xf)
|
||||
|
||||
struct andes_spi_slave {
|
||||
struct spi_slave slave;
|
||||
struct andes_spi_regs *regs;
|
||||
unsigned int freq;
|
||||
};
|
||||
|
||||
static inline struct andes_spi_slave *to_andes_spi(struct spi_slave *slave)
|
||||
{
|
||||
return container_of(slave, struct andes_spi_slave, slave);
|
||||
}
|
||||
|
||||
#endif /* __ANDES_SPI_H */
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define clamp(x, low, high) (min(max(low, x), high))
|
||||
#define to_cf_qspi_slave(s) container_of(s, struct cf_qspi_slave, slave)
|
||||
|
||||
struct cf_qspi_slave {
|
||||
|
@ -120,7 +119,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
|||
dev->qmr = 2u;
|
||||
else /* Get the closest baud rate */
|
||||
dev->qmr = clamp(((gd->bus_clk >> 2) + max_hz - 1)/max_hz,
|
||||
2u, 255u);
|
||||
2lu, 255lu);
|
||||
|
||||
/* Map mode to QMR[CPOL] and QMR[CPHA] */
|
||||
if (mode & SPI_CPOL)
|
||||
|
|
|
@ -8,116 +8,122 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <spi.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include "davinci_spi.h"
|
||||
|
||||
void spi_init()
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
#define BIT(x) (1 << (x))
|
||||
|
||||
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
||||
unsigned int max_hz, unsigned int mode)
|
||||
{
|
||||
struct davinci_spi_slave *ds;
|
||||
/* SPIGCR0 */
|
||||
#define SPIGCR0_SPIENA_MASK 0x1
|
||||
#define SPIGCR0_SPIRST_MASK 0x0
|
||||
|
||||
if (!spi_cs_is_valid(bus, cs))
|
||||
return NULL;
|
||||
/* SPIGCR0 */
|
||||
#define SPIGCR1_CLKMOD_MASK BIT(1)
|
||||
#define SPIGCR1_MASTER_MASK BIT(0)
|
||||
#define SPIGCR1_SPIENA_MASK BIT(24)
|
||||
|
||||
ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs);
|
||||
if (!ds)
|
||||
return NULL;
|
||||
/* SPIPC0 */
|
||||
#define SPIPC0_DIFUN_MASK BIT(11) /* SIMO */
|
||||
#define SPIPC0_DOFUN_MASK BIT(10) /* SOMI */
|
||||
#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */
|
||||
#define SPIPC0_EN0FUN_MASK BIT(0)
|
||||
|
||||
switch (bus) {
|
||||
case SPI0_BUS:
|
||||
ds->regs = (struct davinci_spi_regs *)SPI0_BASE;
|
||||
break;
|
||||
/* SPIFMT0 */
|
||||
#define SPIFMT_SHIFTDIR_SHIFT 20
|
||||
#define SPIFMT_POLARITY_SHIFT 17
|
||||
#define SPIFMT_PHASE_SHIFT 16
|
||||
#define SPIFMT_PRESCALE_SHIFT 8
|
||||
|
||||
/* SPIDAT1 */
|
||||
#define SPIDAT1_CSHOLD_SHIFT 28
|
||||
#define SPIDAT1_CSNR_SHIFT 16
|
||||
|
||||
/* SPIDELAY */
|
||||
#define SPI_C2TDELAY_SHIFT 24
|
||||
#define SPI_T2CDELAY_SHIFT 16
|
||||
|
||||
/* SPIBUF */
|
||||
#define SPIBUF_RXEMPTY_MASK BIT(31)
|
||||
#define SPIBUF_TXFULL_MASK BIT(29)
|
||||
|
||||
/* SPIDEF */
|
||||
#define SPIDEF_CSDEF0_MASK BIT(0)
|
||||
|
||||
#define SPI0_BUS 0
|
||||
#define SPI0_BASE CONFIG_SYS_SPI_BASE
|
||||
/*
|
||||
* Define default SPI0_NUM_CS as 1 for existing platforms that uses this
|
||||
* driver. Platform can configure number of CS using CONFIG_SYS_SPI0_NUM_CS
|
||||
* if more than one CS is supported and by defining CONFIG_SYS_SPI0.
|
||||
*/
|
||||
#ifndef CONFIG_SYS_SPI0
|
||||
#define SPI0_NUM_CS 1
|
||||
#else
|
||||
#define SPI0_NUM_CS CONFIG_SYS_SPI0_NUM_CS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* define CONFIG_SYS_SPI1 when platform has spi-1 device (bus #1) and
|
||||
* CONFIG_SYS_SPI1_NUM_CS defines number of CS on this bus
|
||||
*/
|
||||
#ifdef CONFIG_SYS_SPI1
|
||||
case SPI1_BUS:
|
||||
ds->regs = (struct davinci_spi_regs *)SPI1_BASE;
|
||||
break;
|
||||
#define SPI1_BUS 1
|
||||
#define SPI1_NUM_CS CONFIG_SYS_SPI1_NUM_CS
|
||||
#define SPI1_BASE CONFIG_SYS_SPI1_BASE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* define CONFIG_SYS_SPI2 when platform has spi-2 device (bus #2) and
|
||||
* CONFIG_SYS_SPI2_NUM_CS defines number of CS on this bus
|
||||
*/
|
||||
#ifdef CONFIG_SYS_SPI2
|
||||
case SPI2_BUS:
|
||||
ds->regs = (struct davinci_spi_regs *)SPI2_BASE;
|
||||
break;
|
||||
#define SPI2_BUS 2
|
||||
#define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS
|
||||
#define SPI2_BASE CONFIG_SYS_SPI2_BASE
|
||||
#endif
|
||||
default: /* Invalid bus number */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ds->freq = max_hz;
|
||||
/* davinci spi register set */
|
||||
struct davinci_spi_regs {
|
||||
dv_reg gcr0; /* 0x00 */
|
||||
dv_reg gcr1; /* 0x04 */
|
||||
dv_reg int0; /* 0x08 */
|
||||
dv_reg lvl; /* 0x0c */
|
||||
dv_reg flg; /* 0x10 */
|
||||
dv_reg pc0; /* 0x14 */
|
||||
dv_reg pc1; /* 0x18 */
|
||||
dv_reg pc2; /* 0x1c */
|
||||
dv_reg pc3; /* 0x20 */
|
||||
dv_reg pc4; /* 0x24 */
|
||||
dv_reg pc5; /* 0x28 */
|
||||
dv_reg rsvd[3];
|
||||
dv_reg dat0; /* 0x38 */
|
||||
dv_reg dat1; /* 0x3c */
|
||||
dv_reg buf; /* 0x40 */
|
||||
dv_reg emu; /* 0x44 */
|
||||
dv_reg delay; /* 0x48 */
|
||||
dv_reg def; /* 0x4c */
|
||||
dv_reg fmt0; /* 0x50 */
|
||||
dv_reg fmt1; /* 0x54 */
|
||||
dv_reg fmt2; /* 0x58 */
|
||||
dv_reg fmt3; /* 0x5c */
|
||||
dv_reg intvec0; /* 0x60 */
|
||||
dv_reg intvec1; /* 0x64 */
|
||||
};
|
||||
|
||||
return &ds->slave;
|
||||
}
|
||||
/* davinci spi slave */
|
||||
struct davinci_spi_slave {
|
||||
struct spi_slave slave;
|
||||
struct davinci_spi_regs *regs;
|
||||
unsigned int freq;
|
||||
};
|
||||
|
||||
void spi_free_slave(struct spi_slave *slave)
|
||||
static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
|
||||
{
|
||||
struct davinci_spi_slave *ds = to_davinci_spi(slave);
|
||||
|
||||
free(ds);
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct davinci_spi_slave *ds = to_davinci_spi(slave);
|
||||
unsigned int scalar;
|
||||
|
||||
/* Enable the SPI hardware */
|
||||
writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
|
||||
udelay(1000);
|
||||
writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
|
||||
|
||||
/* Set master mode, powered up and not activated */
|
||||
writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
|
||||
|
||||
/* CS, CLK, SIMO and SOMI are functional pins */
|
||||
writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK |
|
||||
SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
|
||||
|
||||
/* setup format */
|
||||
scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
|
||||
|
||||
/*
|
||||
* Use following format:
|
||||
* character length = 8,
|
||||
* clock signal delayed by half clk cycle,
|
||||
* clock low in idle state - Mode 0,
|
||||
* MSB shifted out first
|
||||
*/
|
||||
writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
|
||||
(1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
|
||||
|
||||
/*
|
||||
* Including a minor delay. No science here. Should be good even with
|
||||
* no delay
|
||||
*/
|
||||
writel((50 << SPI_C2TDELAY_SHIFT) |
|
||||
(50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
|
||||
|
||||
/* default chip select register */
|
||||
writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
|
||||
|
||||
/* no interrupts */
|
||||
writel(0, &ds->regs->int0);
|
||||
writel(0, &ds->regs->lvl);
|
||||
|
||||
/* enable SPI */
|
||||
writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct davinci_spi_slave *ds = to_davinci_spi(slave);
|
||||
|
||||
/* Disable the SPI hardware */
|
||||
writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
|
||||
return container_of(slave, struct davinci_spi_slave, slave);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -235,6 +241,149 @@ static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
|
|||
}
|
||||
#endif
|
||||
|
||||
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (bus) {
|
||||
case SPI0_BUS:
|
||||
if (cs < SPI0_NUM_CS)
|
||||
ret = 1;
|
||||
break;
|
||||
#ifdef CONFIG_SYS_SPI1
|
||||
case SPI1_BUS:
|
||||
if (cs < SPI1_NUM_CS)
|
||||
ret = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_SPI2
|
||||
case SPI2_BUS:
|
||||
if (cs < SPI2_NUM_CS)
|
||||
ret = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Invalid bus number. Do nothing */
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void spi_cs_activate(struct spi_slave *slave)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
void spi_cs_deactivate(struct spi_slave *slave)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
void spi_init(void)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
||||
unsigned int max_hz, unsigned int mode)
|
||||
{
|
||||
struct davinci_spi_slave *ds;
|
||||
|
||||
if (!spi_cs_is_valid(bus, cs))
|
||||
return NULL;
|
||||
|
||||
ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs);
|
||||
if (!ds)
|
||||
return NULL;
|
||||
|
||||
switch (bus) {
|
||||
case SPI0_BUS:
|
||||
ds->regs = (struct davinci_spi_regs *)SPI0_BASE;
|
||||
break;
|
||||
#ifdef CONFIG_SYS_SPI1
|
||||
case SPI1_BUS:
|
||||
ds->regs = (struct davinci_spi_regs *)SPI1_BASE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_SPI2
|
||||
case SPI2_BUS:
|
||||
ds->regs = (struct davinci_spi_regs *)SPI2_BASE;
|
||||
break;
|
||||
#endif
|
||||
default: /* Invalid bus number */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ds->freq = max_hz;
|
||||
|
||||
return &ds->slave;
|
||||
}
|
||||
|
||||
void spi_free_slave(struct spi_slave *slave)
|
||||
{
|
||||
struct davinci_spi_slave *ds = to_davinci_spi(slave);
|
||||
|
||||
free(ds);
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct davinci_spi_slave *ds = to_davinci_spi(slave);
|
||||
unsigned int scalar;
|
||||
|
||||
/* Enable the SPI hardware */
|
||||
writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
|
||||
udelay(1000);
|
||||
writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
|
||||
|
||||
/* Set master mode, powered up and not activated */
|
||||
writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
|
||||
|
||||
/* CS, CLK, SIMO and SOMI are functional pins */
|
||||
writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK |
|
||||
SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
|
||||
|
||||
/* setup format */
|
||||
scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
|
||||
|
||||
/*
|
||||
* Use following format:
|
||||
* character length = 8,
|
||||
* clock signal delayed by half clk cycle,
|
||||
* clock low in idle state - Mode 0,
|
||||
* MSB shifted out first
|
||||
*/
|
||||
writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
|
||||
(1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
|
||||
|
||||
/*
|
||||
* Including a minor delay. No science here. Should be good even with
|
||||
* no delay
|
||||
*/
|
||||
writel((50 << SPI_C2TDELAY_SHIFT) |
|
||||
(50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
|
||||
|
||||
/* default chip select register */
|
||||
writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
|
||||
|
||||
/* no interrupts */
|
||||
writel(0, &ds->regs->int0);
|
||||
writel(0, &ds->regs->lvl);
|
||||
|
||||
/* enable SPI */
|
||||
writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct davinci_spi_slave *ds = to_davinci_spi(slave);
|
||||
|
||||
/* Disable the SPI hardware */
|
||||
writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
|
||||
}
|
||||
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
|
@ -278,41 +427,3 @@ out:
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (bus) {
|
||||
case SPI0_BUS:
|
||||
if (cs < SPI0_NUM_CS)
|
||||
ret = 1;
|
||||
break;
|
||||
#ifdef CONFIG_SYS_SPI1
|
||||
case SPI1_BUS:
|
||||
if (cs < SPI1_NUM_CS)
|
||||
ret = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_SPI2
|
||||
case SPI2_BUS:
|
||||
if (cs < SPI2_NUM_CS)
|
||||
ret = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Invalid bus number. Do nothing */
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void spi_cs_activate(struct spi_slave *slave)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
void spi_cs_deactivate(struct spi_slave *slave)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* Register definitions for the DaVinci SPI Controller
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _DAVINCI_SPI_H_
|
||||
#define _DAVINCI_SPI_H_
|
||||
|
||||
struct davinci_spi_regs {
|
||||
dv_reg gcr0; /* 0x00 */
|
||||
dv_reg gcr1; /* 0x04 */
|
||||
dv_reg int0; /* 0x08 */
|
||||
dv_reg lvl; /* 0x0c */
|
||||
dv_reg flg; /* 0x10 */
|
||||
dv_reg pc0; /* 0x14 */
|
||||
dv_reg pc1; /* 0x18 */
|
||||
dv_reg pc2; /* 0x1c */
|
||||
dv_reg pc3; /* 0x20 */
|
||||
dv_reg pc4; /* 0x24 */
|
||||
dv_reg pc5; /* 0x28 */
|
||||
dv_reg rsvd[3];
|
||||
dv_reg dat0; /* 0x38 */
|
||||
dv_reg dat1; /* 0x3c */
|
||||
dv_reg buf; /* 0x40 */
|
||||
dv_reg emu; /* 0x44 */
|
||||
dv_reg delay; /* 0x48 */
|
||||
dv_reg def; /* 0x4c */
|
||||
dv_reg fmt0; /* 0x50 */
|
||||
dv_reg fmt1; /* 0x54 */
|
||||
dv_reg fmt2; /* 0x58 */
|
||||
dv_reg fmt3; /* 0x5c */
|
||||
dv_reg intvec0; /* 0x60 */
|
||||
dv_reg intvec1; /* 0x64 */
|
||||
};
|
||||
|
||||
#define BIT(x) (1 << (x))
|
||||
|
||||
/* SPIGCR0 */
|
||||
#define SPIGCR0_SPIENA_MASK 0x1
|
||||
#define SPIGCR0_SPIRST_MASK 0x0
|
||||
|
||||
/* SPIGCR0 */
|
||||
#define SPIGCR1_CLKMOD_MASK BIT(1)
|
||||
#define SPIGCR1_MASTER_MASK BIT(0)
|
||||
#define SPIGCR1_SPIENA_MASK BIT(24)
|
||||
|
||||
/* SPIPC0 */
|
||||
#define SPIPC0_DIFUN_MASK BIT(11) /* SIMO */
|
||||
#define SPIPC0_DOFUN_MASK BIT(10) /* SOMI */
|
||||
#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */
|
||||
#define SPIPC0_EN0FUN_MASK BIT(0)
|
||||
|
||||
/* SPIFMT0 */
|
||||
#define SPIFMT_SHIFTDIR_SHIFT 20
|
||||
#define SPIFMT_POLARITY_SHIFT 17
|
||||
#define SPIFMT_PHASE_SHIFT 16
|
||||
#define SPIFMT_PRESCALE_SHIFT 8
|
||||
|
||||
/* SPIDAT1 */
|
||||
#define SPIDAT1_CSHOLD_SHIFT 28
|
||||
#define SPIDAT1_CSNR_SHIFT 16
|
||||
|
||||
/* SPIDELAY */
|
||||
#define SPI_C2TDELAY_SHIFT 24
|
||||
#define SPI_T2CDELAY_SHIFT 16
|
||||
|
||||
/* SPIBUF */
|
||||
#define SPIBUF_RXEMPTY_MASK BIT(31)
|
||||
#define SPIBUF_TXFULL_MASK BIT(29)
|
||||
|
||||
/* SPIDEF */
|
||||
#define SPIDEF_CSDEF0_MASK BIT(0)
|
||||
|
||||
#define SPI0_BUS 0
|
||||
#define SPI0_BASE CONFIG_SYS_SPI_BASE
|
||||
/*
|
||||
* Define default SPI0_NUM_CS as 1 for existing platforms that uses this
|
||||
* driver. Platform can configure number of CS using CONFIG_SYS_SPI0_NUM_CS
|
||||
* if more than one CS is supported and by defining CONFIG_SYS_SPI0.
|
||||
*/
|
||||
#ifndef CONFIG_SYS_SPI0
|
||||
#define SPI0_NUM_CS 1
|
||||
#else
|
||||
#define SPI0_NUM_CS CONFIG_SYS_SPI0_NUM_CS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* define CONFIG_SYS_SPI1 when platform has spi-1 device (bus #1) and
|
||||
* CONFIG_SYS_SPI1_NUM_CS defines number of CS on this bus
|
||||
*/
|
||||
#ifdef CONFIG_SYS_SPI1
|
||||
#define SPI1_BUS 1
|
||||
#define SPI1_NUM_CS CONFIG_SYS_SPI1_NUM_CS
|
||||
#define SPI1_BASE CONFIG_SYS_SPI1_BASE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* define CONFIG_SYS_SPI2 when platform has spi-2 device (bus #2) and
|
||||
* CONFIG_SYS_SPI2_NUM_CS defines number of CS on this bus
|
||||
*/
|
||||
#ifdef CONFIG_SYS_SPI2
|
||||
#define SPI2_BUS 2
|
||||
#define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS
|
||||
#define SPI2_BASE CONFIG_SYS_SPI2_BASE
|
||||
#endif
|
||||
|
||||
struct davinci_spi_slave {
|
||||
struct spi_slave slave;
|
||||
struct davinci_spi_regs *regs;
|
||||
unsigned int freq;
|
||||
};
|
||||
|
||||
static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
|
||||
{
|
||||
return container_of(slave, struct davinci_spi_slave, slave);
|
||||
}
|
||||
|
||||
#endif /* _DAVINCI_SPI_H_ */
|
|
@ -1,498 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2013
|
||||
* Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
|
||||
* Kuo-Jung Su <dantesu@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/compat.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <spi.h>
|
||||
|
||||
#ifndef CONFIG_FTSSP010_BASE_LIST
|
||||
#define CONFIG_FTSSP010_BASE_LIST { CONFIG_FTSSP010_BASE }
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FTSSP010_GPIO_BASE
|
||||
#define CONFIG_FTSSP010_GPIO_BASE 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FTSSP010_GPIO_LIST
|
||||
#define CONFIG_FTSSP010_GPIO_LIST { CONFIG_FTSSP010_GPIO_BASE }
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FTSSP010_CLOCK
|
||||
#define CONFIG_FTSSP010_CLOCK clk_get_rate("SSP");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FTSSP010_TIMEOUT
|
||||
#define CONFIG_FTSSP010_TIMEOUT 100
|
||||
#endif
|
||||
|
||||
/* FTSSP010 chip registers */
|
||||
struct ftssp010_regs {
|
||||
uint32_t cr[3];/* control register */
|
||||
uint32_t sr; /* status register */
|
||||
uint32_t icr; /* interrupt control register */
|
||||
uint32_t isr; /* interrupt status register */
|
||||
uint32_t dr; /* data register */
|
||||
uint32_t rsvd[17];
|
||||
uint32_t revr; /* revision register */
|
||||
uint32_t fear; /* feature register */
|
||||
};
|
||||
|
||||
/* Control Register 0 */
|
||||
#define CR0_FFMT_MASK (7 << 12)
|
||||
#define CR0_FFMT_SSP (0 << 12)
|
||||
#define CR0_FFMT_SPI (1 << 12)
|
||||
#define CR0_FFMT_MICROWIRE (2 << 12)
|
||||
#define CR0_FFMT_I2S (3 << 12)
|
||||
#define CR0_FFMT_AC97 (4 << 12)
|
||||
#define CR0_FLASH (1 << 11)
|
||||
#define CR0_FSDIST(x) (((x) & 0x03) << 8)
|
||||
#define CR0_LOOP (1 << 7) /* loopback mode */
|
||||
#define CR0_LSB (1 << 6) /* LSB */
|
||||
#define CR0_FSPO (1 << 5) /* fs atcive low (I2S only) */
|
||||
#define CR0_FSJUSTIFY (1 << 4)
|
||||
#define CR0_OPM_SLAVE (0 << 2)
|
||||
#define CR0_OPM_MASTER (3 << 2)
|
||||
#define CR0_OPM_I2S_MSST (3 << 2) /* master stereo mode */
|
||||
#define CR0_OPM_I2S_MSMO (2 << 2) /* master mono mode */
|
||||
#define CR0_OPM_I2S_SLST (1 << 2) /* slave stereo mode */
|
||||
#define CR0_OPM_I2S_SLMO (0 << 2) /* slave mono mode */
|
||||
#define CR0_SCLKPO (1 << 1) /* clock polarity */
|
||||
#define CR0_SCLKPH (1 << 0) /* clock phase */
|
||||
|
||||
/* Control Register 1 */
|
||||
#define CR1_PDL(x) (((x) & 0xff) << 24) /* padding length */
|
||||
#define CR1_SDL(x) ((((x) - 1) & 0x1f) << 16) /* data length */
|
||||
#define CR1_DIV(x) (((x) - 1) & 0xffff) /* clock divider */
|
||||
|
||||
/* Control Register 2 */
|
||||
#define CR2_CS(x) (((x) & 3) << 10) /* CS/FS select */
|
||||
#define CR2_FS (1 << 9) /* CS/FS signal level */
|
||||
#define CR2_TXEN (1 << 8) /* tx enable */
|
||||
#define CR2_RXEN (1 << 7) /* rx enable */
|
||||
#define CR2_RESET (1 << 6) /* chip reset */
|
||||
#define CR2_TXFC (1 << 3) /* tx fifo Clear */
|
||||
#define CR2_RXFC (1 << 2) /* rx fifo Clear */
|
||||
#define CR2_TXDOE (1 << 1) /* tx data output enable */
|
||||
#define CR2_EN (1 << 0) /* chip enable */
|
||||
|
||||
/* Status Register */
|
||||
#define SR_RFF (1 << 0) /* rx fifo full */
|
||||
#define SR_TFNF (1 << 1) /* tx fifo not full */
|
||||
#define SR_BUSY (1 << 2) /* chip busy */
|
||||
#define SR_RFVE(reg) (((reg) >> 4) & 0x1f) /* rx fifo valid entries */
|
||||
#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* tx fifo valid entries */
|
||||
|
||||
/* Feature Register */
|
||||
#define FEAR_BITS(reg) ((((reg) >> 0) & 0xff) + 1) /* data width */
|
||||
#define FEAR_RFSZ(reg) ((((reg) >> 8) & 0xff) + 1) /* rx fifo size */
|
||||
#define FEAR_TFSZ(reg) ((((reg) >> 16) & 0xff) + 1) /* tx fifo size */
|
||||
#define FEAR_AC97 (1 << 24)
|
||||
#define FEAR_I2S (1 << 25)
|
||||
#define FEAR_SPI_MWR (1 << 26)
|
||||
#define FEAR_SSP (1 << 27)
|
||||
#define FEAR_SPDIF (1 << 28)
|
||||
|
||||
/* FTGPIO010 chip registers */
|
||||
struct ftgpio010_regs {
|
||||
uint32_t out; /* 0x00: Data Output */
|
||||
uint32_t in; /* 0x04: Data Input */
|
||||
uint32_t dir; /* 0x08: Direction */
|
||||
uint32_t bypass; /* 0x0c: Bypass */
|
||||
uint32_t set; /* 0x10: Data Set */
|
||||
uint32_t clr; /* 0x14: Data Clear */
|
||||
uint32_t pull_up; /* 0x18: Pull-Up Enabled */
|
||||
uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */
|
||||
};
|
||||
|
||||
struct ftssp010_gpio {
|
||||
struct ftgpio010_regs *regs;
|
||||
uint32_t pin;
|
||||
};
|
||||
|
||||
struct ftssp010_spi {
|
||||
struct spi_slave slave;
|
||||
struct ftssp010_gpio gpio;
|
||||
struct ftssp010_regs *regs;
|
||||
uint32_t fifo;
|
||||
uint32_t mode;
|
||||
uint32_t div;
|
||||
uint32_t clk;
|
||||
uint32_t speed;
|
||||
uint32_t revision;
|
||||
};
|
||||
|
||||
static inline struct ftssp010_spi *to_ftssp010_spi(struct spi_slave *slave)
|
||||
{
|
||||
return container_of(slave, struct ftssp010_spi, slave);
|
||||
}
|
||||
|
||||
static int get_spi_chip(int bus, struct ftssp010_spi *chip)
|
||||
{
|
||||
uint32_t fear, base[] = CONFIG_FTSSP010_BASE_LIST;
|
||||
|
||||
if (bus >= ARRAY_SIZE(base) || !base[bus])
|
||||
return -1;
|
||||
|
||||
chip->regs = (struct ftssp010_regs *)base[bus];
|
||||
|
||||
chip->revision = readl(&chip->regs->revr);
|
||||
|
||||
fear = readl(&chip->regs->fear);
|
||||
chip->fifo = min_t(uint32_t, FEAR_TFSZ(fear), FEAR_RFSZ(fear));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_spi_gpio(int bus, struct ftssp010_gpio *chip)
|
||||
{
|
||||
uint32_t base[] = CONFIG_FTSSP010_GPIO_LIST;
|
||||
|
||||
if (bus >= ARRAY_SIZE(base) || !base[bus])
|
||||
return -1;
|
||||
|
||||
chip->regs = (struct ftgpio010_regs *)(base[bus] & 0xfff00000);
|
||||
chip->pin = base[bus] & 0x1f;
|
||||
|
||||
/* make it an output pin */
|
||||
setbits_le32(&chip->regs->dir, 1 << chip->pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftssp010_wait(struct ftssp010_spi *chip)
|
||||
{
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
ulong t;
|
||||
|
||||
/* wait until device idle */
|
||||
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
|
||||
if (!(readl(®s->sr) & SR_BUSY))
|
||||
return 0;
|
||||
}
|
||||
|
||||
puts("ftspi010: busy timeout\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ftssp010_wait_tx(struct ftssp010_spi *chip)
|
||||
{
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
ulong t;
|
||||
|
||||
/* wait until tx fifo not full */
|
||||
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
|
||||
if (readl(®s->sr) & SR_TFNF)
|
||||
return 0;
|
||||
}
|
||||
|
||||
puts("ftssp010: tx timeout\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ftssp010_wait_rx(struct ftssp010_spi *chip)
|
||||
{
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
ulong t;
|
||||
|
||||
/* wait until rx fifo not empty */
|
||||
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
|
||||
if (SR_RFVE(readl(®s->sr)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
puts("ftssp010: rx timeout\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ftssp010_spi_work_transfer_v2(struct ftssp010_spi *chip,
|
||||
const void *tx_buf, void *rx_buf, int len, uint flags)
|
||||
{
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
const uint8_t *txb = tx_buf;
|
||||
uint8_t *rxb = rx_buf;
|
||||
|
||||
while (len > 0) {
|
||||
int i, depth = min(chip->fifo >> 2, len);
|
||||
uint32_t xmsk = 0;
|
||||
|
||||
if (tx_buf) {
|
||||
for (i = 0; i < depth; ++i) {
|
||||
ftssp010_wait_tx(chip);
|
||||
writel(*txb++, ®s->dr);
|
||||
}
|
||||
xmsk |= CR2_TXEN | CR2_TXDOE;
|
||||
if ((readl(®s->cr[2]) & xmsk) != xmsk)
|
||||
setbits_le32(®s->cr[2], xmsk);
|
||||
}
|
||||
if (rx_buf) {
|
||||
xmsk |= CR2_RXEN;
|
||||
if ((readl(®s->cr[2]) & xmsk) != xmsk)
|
||||
setbits_le32(®s->cr[2], xmsk);
|
||||
for (i = 0; i < depth; ++i) {
|
||||
ftssp010_wait_rx(chip);
|
||||
*rxb++ = (uint8_t)readl(®s->dr);
|
||||
}
|
||||
}
|
||||
|
||||
len -= depth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftssp010_spi_work_transfer_v1(struct ftssp010_spi *chip,
|
||||
const void *tx_buf, void *rx_buf, int len, uint flags)
|
||||
{
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
const uint8_t *txb = tx_buf;
|
||||
uint8_t *rxb = rx_buf;
|
||||
|
||||
while (len > 0) {
|
||||
int i, depth = min(chip->fifo >> 2, len);
|
||||
uint32_t tmp;
|
||||
|
||||
for (i = 0; i < depth; ++i) {
|
||||
ftssp010_wait_tx(chip);
|
||||
writel(txb ? (*txb++) : 0, ®s->dr);
|
||||
}
|
||||
for (i = 0; i < depth; ++i) {
|
||||
ftssp010_wait_rx(chip);
|
||||
tmp = readl(®s->dr);
|
||||
if (rxb)
|
||||
*rxb++ = (uint8_t)tmp;
|
||||
}
|
||||
|
||||
len -= depth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ftssp010_cs_set(struct ftssp010_spi *chip, int high)
|
||||
{
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
struct ftssp010_gpio *gpio = &chip->gpio;
|
||||
uint32_t mask;
|
||||
|
||||
/* cs pull high/low */
|
||||
if (chip->revision >= 0x11900) {
|
||||
mask = CR2_CS(chip->slave.cs) | (high ? CR2_FS : 0);
|
||||
writel(mask, ®s->cr[2]);
|
||||
} else if (gpio->regs) {
|
||||
mask = 1 << gpio->pin;
|
||||
if (high)
|
||||
writel(mask, &gpio->regs->set);
|
||||
else
|
||||
writel(mask, &gpio->regs->clr);
|
||||
}
|
||||
|
||||
/* extra delay for signal propagation */
|
||||
udelay_masked(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if a SPI chipselect is valid.
|
||||
* This function is provided by the board if the low-level SPI driver
|
||||
* needs it to determine if a given chipselect is actually valid.
|
||||
*
|
||||
* Returns: 1 if bus:cs identifies a valid chip on this board, 0
|
||||
* otherwise.
|
||||
*/
|
||||
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
|
||||
{
|
||||
struct ftssp010_spi chip;
|
||||
|
||||
if (get_spi_chip(bus, &chip))
|
||||
return 0;
|
||||
|
||||
if (!cs)
|
||||
return 1;
|
||||
else if ((cs < 4) && (chip.revision >= 0x11900))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Activate a SPI chipselect.
|
||||
* This function is provided by the board code when using a driver
|
||||
* that can't control its chipselects automatically (e.g.
|
||||
* common/soft_spi.c). When called, it should activate the chip select
|
||||
* to the device identified by "slave".
|
||||
*/
|
||||
void spi_cs_activate(struct spi_slave *slave)
|
||||
{
|
||||
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
|
||||
/* cs pull */
|
||||
if (chip->mode & SPI_CS_HIGH)
|
||||
ftssp010_cs_set(chip, 1);
|
||||
else
|
||||
ftssp010_cs_set(chip, 0);
|
||||
|
||||
/* chip enable + fifo clear */
|
||||
setbits_le32(®s->cr[2], CR2_EN | CR2_TXFC | CR2_RXFC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deactivate a SPI chipselect.
|
||||
* This function is provided by the board code when using a driver
|
||||
* that can't control its chipselects automatically (e.g.
|
||||
* common/soft_spi.c). When called, it should deactivate the chip
|
||||
* select to the device identified by "slave".
|
||||
*/
|
||||
void spi_cs_deactivate(struct spi_slave *slave)
|
||||
{
|
||||
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
|
||||
|
||||
/* wait until chip idle */
|
||||
ftssp010_wait(chip);
|
||||
|
||||
/* cs pull */
|
||||
if (chip->mode & SPI_CS_HIGH)
|
||||
ftssp010_cs_set(chip, 0);
|
||||
else
|
||||
ftssp010_cs_set(chip, 1);
|
||||
}
|
||||
|
||||
void spi_init(void)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
|
||||
{
|
||||
struct ftssp010_spi *chip;
|
||||
|
||||
if (mode & SPI_3WIRE) {
|
||||
puts("ftssp010: can't do 3-wire\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mode & SPI_SLAVE) {
|
||||
puts("ftssp010: can't do slave mode\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mode & SPI_PREAMBLE) {
|
||||
puts("ftssp010: can't skip preamble bytes\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!spi_cs_is_valid(bus, cs)) {
|
||||
puts("ftssp010: invalid (bus, cs)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chip = spi_alloc_slave(struct ftssp010_spi, bus, cs);
|
||||
if (!chip)
|
||||
return NULL;
|
||||
|
||||
if (get_spi_chip(bus, chip))
|
||||
goto free_out;
|
||||
|
||||
if (chip->revision < 0x11900 && get_spi_gpio(bus, &chip->gpio)) {
|
||||
puts("ftssp010: Before revision 1.19.0, its clock & cs are\n"
|
||||
"controlled by tx engine which is not synced with rx engine,\n"
|
||||
"so the clock & cs might be shutdown before rx engine\n"
|
||||
"finishs its jobs.\n"
|
||||
"If possible, please add a dedicated gpio for it.\n");
|
||||
}
|
||||
|
||||
chip->mode = mode;
|
||||
chip->clk = CONFIG_FTSSP010_CLOCK;
|
||||
chip->div = 2;
|
||||
if (max_hz) {
|
||||
while (chip->div < 0xffff) {
|
||||
if ((chip->clk / (2 * chip->div)) <= max_hz)
|
||||
break;
|
||||
chip->div += 1;
|
||||
}
|
||||
}
|
||||
chip->speed = chip->clk / (2 * chip->div);
|
||||
|
||||
return &chip->slave;
|
||||
|
||||
free_out:
|
||||
free(chip);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void spi_free_slave(struct spi_slave *slave)
|
||||
{
|
||||
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
|
||||
|
||||
free(chip);
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
|
||||
writel(CR1_SDL(8) | CR1_DIV(chip->div), ®s->cr[1]);
|
||||
|
||||
if (chip->revision >= 0x11900) {
|
||||
writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
|
||||
®s->cr[0]);
|
||||
writel(CR2_TXFC | CR2_RXFC,
|
||||
®s->cr[2]);
|
||||
} else {
|
||||
writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
|
||||
®s->cr[0]);
|
||||
writel(CR2_TXFC | CR2_RXFC | CR2_EN | CR2_TXDOE,
|
||||
®s->cr[2]);
|
||||
}
|
||||
|
||||
if (chip->mode & SPI_LOOP)
|
||||
setbits_le32(®s->cr[0], CR0_LOOP);
|
||||
|
||||
if (chip->mode & SPI_CPOL)
|
||||
setbits_le32(®s->cr[0], CR0_SCLKPO);
|
||||
|
||||
if (chip->mode & SPI_CPHA)
|
||||
setbits_le32(®s->cr[0], CR0_SCLKPH);
|
||||
|
||||
spi_cs_deactivate(slave);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
|
||||
struct ftssp010_regs *regs = chip->regs;
|
||||
|
||||
writel(0, ®s->cr[2]);
|
||||
}
|
||||
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
struct ftssp010_spi *chip = to_ftssp010_spi(slave);
|
||||
uint32_t len = bitlen >> 3;
|
||||
|
||||
if (flags & SPI_XFER_BEGIN)
|
||||
spi_cs_activate(slave);
|
||||
|
||||
if (chip->revision >= 0x11900)
|
||||
ftssp010_spi_work_transfer_v2(chip, dout, din, len, flags);
|
||||
else
|
||||
ftssp010_spi_work_transfer_v1(chip, dout, din, len, flags);
|
||||
|
||||
if (flags & SPI_XFER_END)
|
||||
spi_cs_deactivate(slave);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,245 +0,0 @@
|
|||
/*
|
||||
* Opencore tiny_spi driver
|
||||
*
|
||||
* http://opencores.org/project,tiny_spi
|
||||
*
|
||||
* based on bfin_spi.c
|
||||
* Copyright (c) 2005-2008 Analog Devices Inc.
|
||||
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <spi.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#define TINY_SPI_STATUS_TXE 0x1
|
||||
#define TINY_SPI_STATUS_TXR 0x2
|
||||
|
||||
struct tiny_spi_regs {
|
||||
unsigned rxdata; /* Rx data reg */
|
||||
unsigned txdata; /* Tx data reg */
|
||||
unsigned status; /* Status reg */
|
||||
unsigned control; /* Control reg */
|
||||
unsigned baud; /* Baud reg */
|
||||
};
|
||||
|
||||
struct tiny_spi_host {
|
||||
uint base;
|
||||
uint freq;
|
||||
uint baudwidth;
|
||||
};
|
||||
static const struct tiny_spi_host tiny_spi_host_list[] =
|
||||
CONFIG_SYS_TINY_SPI_LIST;
|
||||
|
||||
struct tiny_spi_slave {
|
||||
struct spi_slave slave;
|
||||
const struct tiny_spi_host *host;
|
||||
uint mode;
|
||||
uint baud;
|
||||
uint flg;
|
||||
};
|
||||
#define to_tiny_spi_slave(s) container_of(s, struct tiny_spi_slave, slave)
|
||||
|
||||
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
|
||||
{
|
||||
return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
|
||||
}
|
||||
|
||||
void spi_cs_activate(struct spi_slave *slave)
|
||||
{
|
||||
struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
|
||||
unsigned int cs = slave->cs;
|
||||
|
||||
gpio_set_value(cs, tiny_spi->flg);
|
||||
debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
|
||||
}
|
||||
|
||||
void spi_cs_deactivate(struct spi_slave *slave)
|
||||
{
|
||||
struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
|
||||
unsigned int cs = slave->cs;
|
||||
|
||||
gpio_set_value(cs, !tiny_spi->flg);
|
||||
debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
|
||||
}
|
||||
|
||||
void spi_set_speed(struct spi_slave *slave, uint hz)
|
||||
{
|
||||
struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
|
||||
const struct tiny_spi_host *host = tiny_spi->host;
|
||||
|
||||
tiny_spi->baud = min(DIV_ROUND_UP(host->freq, hz * 2),
|
||||
(1 << host->baudwidth)) - 1;
|
||||
debug("%s: speed %u actual %u\n", __func__, hz,
|
||||
host->freq / ((tiny_spi->baud + 1) * 2));
|
||||
}
|
||||
|
||||
void spi_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
||||
unsigned int hz, unsigned int mode)
|
||||
{
|
||||
struct tiny_spi_slave *tiny_spi;
|
||||
|
||||
if (!spi_cs_is_valid(bus, cs) || gpio_request(cs, "tiny_spi"))
|
||||
return NULL;
|
||||
|
||||
tiny_spi = spi_alloc_slave(struct tiny_spi_slave, bus, cs);
|
||||
if (!tiny_spi)
|
||||
return NULL;
|
||||
|
||||
tiny_spi->host = &tiny_spi_host_list[bus];
|
||||
tiny_spi->mode = mode & (SPI_CPOL | SPI_CPHA);
|
||||
tiny_spi->flg = mode & SPI_CS_HIGH ? 1 : 0;
|
||||
spi_set_speed(&tiny_spi->slave, hz);
|
||||
|
||||
debug("%s: bus:%i cs:%i base:%lx\n", __func__,
|
||||
bus, cs, tiny_spi->host->base);
|
||||
return &tiny_spi->slave;
|
||||
}
|
||||
|
||||
void spi_free_slave(struct spi_slave *slave)
|
||||
{
|
||||
struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
|
||||
|
||||
gpio_free(slave->cs);
|
||||
free(tiny_spi);
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
|
||||
struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
|
||||
|
||||
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
|
||||
gpio_direction_output(slave->cs, !tiny_spi->flg);
|
||||
writel(tiny_spi->mode, ®s->control);
|
||||
writel(tiny_spi->baud, ®s->baud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
{
|
||||
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TINY_SPI_IDLE_VAL
|
||||
# define CONFIG_TINY_SPI_IDLE_VAL 0xff
|
||||
#endif
|
||||
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
|
||||
void *din, unsigned long flags)
|
||||
{
|
||||
struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
|
||||
struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
|
||||
const u8 *txp = dout;
|
||||
u8 *rxp = din;
|
||||
uint bytes = bitlen / 8;
|
||||
uint i;
|
||||
|
||||
debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
|
||||
slave->bus, slave->cs, bitlen, bytes, flags);
|
||||
if (bitlen == 0)
|
||||
goto done;
|
||||
|
||||
/* assume to do 8 bits transfers */
|
||||
if (bitlen % 8) {
|
||||
flags |= SPI_XFER_END;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (flags & SPI_XFER_BEGIN)
|
||||
spi_cs_activate(slave);
|
||||
|
||||
/* we need to tighten the transfer loop */
|
||||
if (txp && rxp) {
|
||||
writeb(*txp++, ®s->txdata);
|
||||
if (bytes > 1) {
|
||||
writeb(*txp++, ®s->txdata);
|
||||
for (i = 2; i < bytes; i++) {
|
||||
u8 rx, tx = *txp++;
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXR))
|
||||
;
|
||||
rx = readb(®s->txdata);
|
||||
writeb(tx, ®s->txdata);
|
||||
*rxp++ = rx;
|
||||
}
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXR))
|
||||
;
|
||||
*rxp++ = readb(®s->txdata);
|
||||
}
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXE))
|
||||
;
|
||||
*rxp++ = readb(®s->rxdata);
|
||||
} else if (rxp) {
|
||||
writeb(CONFIG_TINY_SPI_IDLE_VAL, ®s->txdata);
|
||||
if (bytes > 1) {
|
||||
writeb(CONFIG_TINY_SPI_IDLE_VAL,
|
||||
®s->txdata);
|
||||
for (i = 2; i < bytes; i++) {
|
||||
u8 rx;
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXR))
|
||||
;
|
||||
rx = readb(®s->txdata);
|
||||
writeb(CONFIG_TINY_SPI_IDLE_VAL,
|
||||
®s->txdata);
|
||||
*rxp++ = rx;
|
||||
}
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXR))
|
||||
;
|
||||
*rxp++ = readb(®s->txdata);
|
||||
}
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXE))
|
||||
;
|
||||
*rxp++ = readb(®s->rxdata);
|
||||
} else if (txp) {
|
||||
writeb(*txp++, ®s->txdata);
|
||||
if (bytes > 1) {
|
||||
writeb(*txp++, ®s->txdata);
|
||||
for (i = 2; i < bytes; i++) {
|
||||
u8 tx = *txp++;
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXR))
|
||||
;
|
||||
writeb(tx, ®s->txdata);
|
||||
}
|
||||
}
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXE))
|
||||
;
|
||||
} else {
|
||||
writeb(CONFIG_TINY_SPI_IDLE_VAL, ®s->txdata);
|
||||
if (bytes > 1) {
|
||||
writeb(CONFIG_TINY_SPI_IDLE_VAL,
|
||||
®s->txdata);
|
||||
for (i = 2; i < bytes; i++) {
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXR))
|
||||
;
|
||||
writeb(CONFIG_TINY_SPI_IDLE_VAL,
|
||||
®s->txdata);
|
||||
}
|
||||
}
|
||||
while (!(readb(®s->status) &
|
||||
TINY_SPI_STATUS_TXE))
|
||||
;
|
||||
}
|
||||
|
||||
done:
|
||||
if (flags & SPI_XFER_END)
|
||||
spi_cs_deactivate(slave);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,149 +1,175 @@
|
|||
/*
|
||||
* Xilinx SPI driver
|
||||
*
|
||||
* supports 8 bit SPI transfers only, with or w/o FIFO
|
||||
* Supports 8 bit SPI transfers only, with or w/o FIFO
|
||||
*
|
||||
* based on bfin_spi.c, by way of altera_spi.c
|
||||
* Copyright (c) 2005-2008 Analog Devices Inc.
|
||||
* Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
|
||||
* Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
|
||||
* Based on bfin_spi.c, by way of altera_spi.c
|
||||
* Copyright (c) 2015 Jagan Teki <jteki@openedev.com>
|
||||
* Copyright (c) 2012 Stephan Linz <linz@li-pro.net>
|
||||
* Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
|
||||
* Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
|
||||
* Copyright (c) 2005-2008 Analog Devices Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* [0]: http://www.xilinx.com/support/documentation
|
||||
*
|
||||
* [S]: [0]/ip_documentation/xps_spi.pdf
|
||||
* [0]/ip_documentation/axi_spi_ds742.pdf
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <spi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "xilinx_spi.h"
|
||||
/*
|
||||
* [0]: http://www.xilinx.com/support/documentation
|
||||
*
|
||||
* Xilinx SPI Register Definitions
|
||||
* [1]: [0]/ip_documentation/xps_spi.pdf
|
||||
* page 8, Register Descriptions
|
||||
* [2]: [0]/ip_documentation/axi_spi_ds742.pdf
|
||||
* page 7, Register Overview Table
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_SYS_XILINX_SPI_LIST
|
||||
#define CONFIG_SYS_XILINX_SPI_LIST { CONFIG_SYS_SPI_BASE }
|
||||
#endif
|
||||
/* SPI Control Register (spicr), [1] p9, [2] p8 */
|
||||
#define SPICR_LSB_FIRST (1 << 9)
|
||||
#define SPICR_MASTER_INHIBIT (1 << 8)
|
||||
#define SPICR_MANUAL_SS (1 << 7)
|
||||
#define SPICR_RXFIFO_RESEST (1 << 6)
|
||||
#define SPICR_TXFIFO_RESEST (1 << 5)
|
||||
#define SPICR_CPHA (1 << 4)
|
||||
#define SPICR_CPOL (1 << 3)
|
||||
#define SPICR_MASTER_MODE (1 << 2)
|
||||
#define SPICR_SPE (1 << 1)
|
||||
#define SPICR_LOOP (1 << 0)
|
||||
|
||||
/* SPI Status Register (spisr), [1] p11, [2] p10 */
|
||||
#define SPISR_SLAVE_MODE_SELECT (1 << 5)
|
||||
#define SPISR_MODF (1 << 4)
|
||||
#define SPISR_TX_FULL (1 << 3)
|
||||
#define SPISR_TX_EMPTY (1 << 2)
|
||||
#define SPISR_RX_FULL (1 << 1)
|
||||
#define SPISR_RX_EMPTY (1 << 0)
|
||||
|
||||
/* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */
|
||||
#define SPIDTR_8BIT_MASK (0xff << 0)
|
||||
#define SPIDTR_16BIT_MASK (0xffff << 0)
|
||||
#define SPIDTR_32BIT_MASK (0xffffffff << 0)
|
||||
|
||||
/* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */
|
||||
#define SPIDRR_8BIT_MASK (0xff << 0)
|
||||
#define SPIDRR_16BIT_MASK (0xffff << 0)
|
||||
#define SPIDRR_32BIT_MASK (0xffffffff << 0)
|
||||
|
||||
/* SPI Slave Select Register (spissr), [1] p13, [2] p13 */
|
||||
#define SPISSR_MASK(cs) (1 << (cs))
|
||||
#define SPISSR_ACT(cs) ~SPISSR_MASK(cs)
|
||||
#define SPISSR_OFF ~0UL
|
||||
|
||||
/* SPI Software Reset Register (ssr) */
|
||||
#define SPISSR_RESET_VALUE 0x0a
|
||||
|
||||
#define XILSPI_MAX_XFER_BITS 8
|
||||
#define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | SPICR_MASTER_MODE | \
|
||||
SPICR_SPE)
|
||||
#define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | SPICR_MANUAL_SS)
|
||||
|
||||
#ifndef CONFIG_XILINX_SPI_IDLE_VAL
|
||||
#define CONFIG_XILINX_SPI_IDLE_VAL 0xff
|
||||
#endif
|
||||
|
||||
#define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | \
|
||||
SPICR_MASTER_MODE | \
|
||||
SPICR_SPE)
|
||||
#ifndef CONFIG_SYS_XILINX_SPI_LIST
|
||||
#define CONFIG_SYS_XILINX_SPI_LIST { CONFIG_SYS_SPI_BASE }
|
||||
#endif
|
||||
|
||||
#define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | \
|
||||
SPICR_MANUAL_SS)
|
||||
/* xilinx spi register set */
|
||||
struct xilinx_spi_regs {
|
||||
u32 __space0__[7];
|
||||
u32 dgier; /* Device Global Interrupt Enable Register (DGIER) */
|
||||
u32 ipisr; /* IP Interrupt Status Register (IPISR) */
|
||||
u32 __space1__;
|
||||
u32 ipier; /* IP Interrupt Enable Register (IPIER) */
|
||||
u32 __space2__[5];
|
||||
u32 srr; /* Softare Reset Register (SRR) */
|
||||
u32 __space3__[7];
|
||||
u32 spicr; /* SPI Control Register (SPICR) */
|
||||
u32 spisr; /* SPI Status Register (SPISR) */
|
||||
u32 spidtr; /* SPI Data Transmit Register (SPIDTR) */
|
||||
u32 spidrr; /* SPI Data Receive Register (SPIDRR) */
|
||||
u32 spissr; /* SPI Slave Select Register (SPISSR) */
|
||||
u32 spitfor; /* SPI Transmit FIFO Occupancy Register (SPITFOR) */
|
||||
u32 spirfor; /* SPI Receive FIFO Occupancy Register (SPIRFOR) */
|
||||
};
|
||||
|
||||
#define XILSPI_MAX_XFER_BITS 8
|
||||
/* xilinx spi priv */
|
||||
struct xilinx_spi_priv {
|
||||
struct xilinx_spi_regs *regs;
|
||||
unsigned int freq;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
static unsigned long xilinx_spi_base_list[] = CONFIG_SYS_XILINX_SPI_LIST;
|
||||
|
||||
__attribute__((weak))
|
||||
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
|
||||
static int xilinx_spi_probe(struct udevice *bus)
|
||||
{
|
||||
return bus < ARRAY_SIZE(xilinx_spi_base_list) && cs < 32;
|
||||
}
|
||||
struct xilinx_spi_priv *priv = dev_get_priv(bus);
|
||||
struct xilinx_spi_regs *regs = priv->regs;
|
||||
|
||||
__attribute__((weak))
|
||||
void spi_cs_activate(struct spi_slave *slave)
|
||||
{
|
||||
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
|
||||
priv->regs = (struct xilinx_spi_regs *)xilinx_spi_base_list[bus->seq];
|
||||
|
||||
writel(SPISSR_ACT(slave->cs), &xilspi->regs->spissr);
|
||||
}
|
||||
writel(SPISSR_RESET_VALUE, ®s->srr);
|
||||
|
||||
__attribute__((weak))
|
||||
void spi_cs_deactivate(struct spi_slave *slave)
|
||||
{
|
||||
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
|
||||
|
||||
writel(SPISSR_OFF, &xilspi->regs->spissr);
|
||||
}
|
||||
|
||||
void spi_init(void)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
void spi_set_speed(struct spi_slave *slave, uint hz)
|
||||
{
|
||||
/* xilinx spi core does not support programmable speed */
|
||||
}
|
||||
|
||||
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
||||
unsigned int max_hz, unsigned int mode)
|
||||
{
|
||||
struct xilinx_spi_slave *xilspi;
|
||||
|
||||
if (!spi_cs_is_valid(bus, cs)) {
|
||||
printf("XILSPI error: %s: unsupported bus %d / cs %d\n",
|
||||
__func__, bus, cs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xilspi = spi_alloc_slave(struct xilinx_spi_slave, bus, cs);
|
||||
if (!xilspi) {
|
||||
printf("XILSPI error: %s: malloc of SPI structure failed\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
xilspi->regs = (struct xilinx_spi_reg *)xilinx_spi_base_list[bus];
|
||||
xilspi->freq = max_hz;
|
||||
xilspi->mode = mode;
|
||||
debug("%s: bus:%i cs:%i base:%p mode:%x max_hz:%d\n", __func__,
|
||||
bus, cs, xilspi->regs, xilspi->mode, xilspi->freq);
|
||||
|
||||
writel(SPISSR_RESET_VALUE, &xilspi->regs->srr);
|
||||
|
||||
return &xilspi->slave;
|
||||
}
|
||||
|
||||
void spi_free_slave(struct spi_slave *slave)
|
||||
{
|
||||
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
|
||||
|
||||
free(xilspi);
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
|
||||
u32 spicr;
|
||||
|
||||
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
|
||||
writel(SPISSR_OFF, &xilspi->regs->spissr);
|
||||
|
||||
spicr = XILSPI_SPICR_DFLT_ON;
|
||||
if (xilspi->mode & SPI_LSB_FIRST)
|
||||
spicr |= SPICR_LSB_FIRST;
|
||||
if (xilspi->mode & SPI_CPHA)
|
||||
spicr |= SPICR_CPHA;
|
||||
if (xilspi->mode & SPI_CPOL)
|
||||
spicr |= SPICR_CPOL;
|
||||
if (xilspi->mode & SPI_LOOP)
|
||||
spicr |= SPICR_LOOP;
|
||||
|
||||
writel(spicr, &xilspi->regs->spicr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
static void spi_cs_activate(struct udevice *dev, uint cs)
|
||||
{
|
||||
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct xilinx_spi_priv *priv = dev_get_priv(bus);
|
||||
struct xilinx_spi_regs *regs = priv->regs;
|
||||
|
||||
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
|
||||
writel(SPISSR_OFF, &xilspi->regs->spissr);
|
||||
writel(XILSPI_SPICR_DFLT_OFF, &xilspi->regs->spicr);
|
||||
writel(SPISSR_ACT(cs), ®s->spissr);
|
||||
}
|
||||
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
|
||||
void *din, unsigned long flags)
|
||||
static void spi_cs_deactivate(struct udevice *dev)
|
||||
{
|
||||
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct xilinx_spi_priv *priv = dev_get_priv(bus);
|
||||
struct xilinx_spi_regs *regs = priv->regs;
|
||||
|
||||
writel(SPISSR_OFF, ®s->spissr);
|
||||
}
|
||||
|
||||
static int xilinx_spi_claim_bus(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct xilinx_spi_priv *priv = dev_get_priv(bus);
|
||||
struct xilinx_spi_regs *regs = priv->regs;
|
||||
|
||||
writel(SPISSR_OFF, ®s->spissr);
|
||||
writel(XILSPI_SPICR_DFLT_ON, ®s->spicr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_spi_release_bus(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct xilinx_spi_priv *priv = dev_get_priv(bus);
|
||||
struct xilinx_spi_regs *regs = priv->regs;
|
||||
|
||||
writel(SPISSR_OFF, ®s->spissr);
|
||||
writel(XILSPI_SPICR_DFLT_OFF, ®s->spicr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct xilinx_spi_priv *priv = dev_get_priv(bus);
|
||||
struct xilinx_spi_regs *regs = priv->regs;
|
||||
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
|
||||
/* assume spi core configured to do 8 bit transfers */
|
||||
unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS;
|
||||
const unsigned char *txp = dout;
|
||||
|
@ -151,65 +177,125 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
|
|||
unsigned rxecount = 17; /* max. 16 elements in FIFO, leftover 1 */
|
||||
unsigned global_timeout;
|
||||
|
||||
debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
|
||||
slave->bus, slave->cs, bitlen, bytes, flags);
|
||||
debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n",
|
||||
bus->seq, slave_plat->cs, bitlen, bytes, flags);
|
||||
|
||||
if (bitlen == 0)
|
||||
goto done;
|
||||
|
||||
if (bitlen % XILSPI_MAX_XFER_BITS) {
|
||||
printf("XILSPI warning: %s: Not a multiple of %d bits\n",
|
||||
__func__, XILSPI_MAX_XFER_BITS);
|
||||
printf("XILSPI warning: Not a multiple of %d bits\n",
|
||||
XILSPI_MAX_XFER_BITS);
|
||||
flags |= SPI_XFER_END;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* empty read buffer */
|
||||
while (rxecount && !(readl(&xilspi->regs->spisr) & SPISR_RX_EMPTY)) {
|
||||
readl(&xilspi->regs->spidrr);
|
||||
while (rxecount && !(readl(®s->spisr) & SPISR_RX_EMPTY)) {
|
||||
readl(®s->spidrr);
|
||||
rxecount--;
|
||||
}
|
||||
|
||||
if (!rxecount) {
|
||||
printf("XILSPI error: %s: Rx buffer not empty\n", __func__);
|
||||
printf("XILSPI error: Rx buffer not empty\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags & SPI_XFER_BEGIN)
|
||||
spi_cs_activate(slave);
|
||||
spi_cs_activate(dev, slave_plat->cs);
|
||||
|
||||
/* at least 1usec or greater, leftover 1 */
|
||||
global_timeout = xilspi->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
|
||||
(XILSPI_MAX_XFER_BITS * 1000000 / xilspi->freq) + 1;
|
||||
global_timeout = priv->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
|
||||
(XILSPI_MAX_XFER_BITS * 1000000 / priv->freq) + 1;
|
||||
|
||||
while (bytes--) {
|
||||
unsigned timeout = global_timeout;
|
||||
/* get Tx element from data out buffer and count up */
|
||||
unsigned char d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
|
||||
debug("%s: tx:%x ", __func__, d);
|
||||
debug("spi_xfer: tx:%x ", d);
|
||||
|
||||
/* write out and wait for processing (receive data) */
|
||||
writel(d & SPIDTR_8BIT_MASK, &xilspi->regs->spidtr);
|
||||
while (timeout && readl(&xilspi->regs->spisr)
|
||||
writel(d & SPIDTR_8BIT_MASK, ®s->spidtr);
|
||||
while (timeout && readl(®s->spisr)
|
||||
& SPISR_RX_EMPTY) {
|
||||
timeout--;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
printf("XILSPI error: %s: Xfer timeout\n", __func__);
|
||||
printf("XILSPI error: Xfer timeout\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read Rx element and push into data in buffer */
|
||||
d = readl(&xilspi->regs->spidrr) & SPIDRR_8BIT_MASK;
|
||||
d = readl(®s->spidrr) & SPIDRR_8BIT_MASK;
|
||||
if (rxp)
|
||||
*rxp++ = d;
|
||||
debug("rx:%x\n", d);
|
||||
debug("spi_xfer: rx:%x\n", d);
|
||||
}
|
||||
|
||||
done:
|
||||
if (flags & SPI_XFER_END)
|
||||
spi_cs_deactivate(slave);
|
||||
spi_cs_deactivate(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_spi_set_speed(struct udevice *bus, uint speed)
|
||||
{
|
||||
struct xilinx_spi_priv *priv = dev_get_priv(bus);
|
||||
|
||||
priv->freq = speed;
|
||||
|
||||
debug("xilinx_spi_set_speed: regs=%p, mode=%d\n", priv->regs,
|
||||
priv->freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_spi_set_mode(struct udevice *bus, uint mode)
|
||||
{
|
||||
struct xilinx_spi_priv *priv = dev_get_priv(bus);
|
||||
struct xilinx_spi_regs *regs = priv->regs;
|
||||
uint32_t spicr;
|
||||
|
||||
spicr = readl(®s->spicr);
|
||||
if (priv->mode & SPI_LSB_FIRST)
|
||||
spicr |= SPICR_LSB_FIRST;
|
||||
if (priv->mode & SPI_CPHA)
|
||||
spicr |= SPICR_CPHA;
|
||||
if (priv->mode & SPI_CPOL)
|
||||
spicr |= SPICR_CPOL;
|
||||
if (priv->mode & SPI_LOOP)
|
||||
spicr |= SPICR_LOOP;
|
||||
|
||||
writel(spicr, ®s->spicr);
|
||||
priv->mode = mode;
|
||||
|
||||
debug("xilinx_spi_set_mode: regs=%p, mode=%d\n", priv->regs,
|
||||
priv->mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_spi_ops xilinx_spi_ops = {
|
||||
.claim_bus = xilinx_spi_claim_bus,
|
||||
.release_bus = xilinx_spi_release_bus,
|
||||
.xfer = xilinx_spi_xfer,
|
||||
.set_speed = xilinx_spi_set_speed,
|
||||
.set_mode = xilinx_spi_set_mode,
|
||||
};
|
||||
|
||||
static const struct udevice_id xilinx_spi_ids[] = {
|
||||
{ .compatible = "xlnx,xilinx-spi" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(xilinx_spi) = {
|
||||
.name = "xilinx_spi",
|
||||
.id = UCLASS_SPI,
|
||||
.of_match = xilinx_spi_ids,
|
||||
.ops = &xilinx_spi_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct xilinx_spi_priv),
|
||||
.probe = xilinx_spi_probe,
|
||||
};
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* Xilinx SPI driver
|
||||
*
|
||||
* XPS/AXI bus interface
|
||||
*
|
||||
* based on bfin_spi.c, by way of altera_spi.c
|
||||
* Copyright (c) 2005-2008 Analog Devices Inc.
|
||||
* Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
|
||||
* Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
|
||||
* Copyright (c) 2012 Stephan Linz <linz@li-pro.net>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* [0]: http://www.xilinx.com/support/documentation
|
||||
*
|
||||
* [S]: [0]/ip_documentation/xps_spi.pdf
|
||||
* [0]/ip_documentation/axi_spi_ds742.pdf
|
||||
*/
|
||||
#ifndef _XILINX_SPI_
|
||||
#define _XILINX_SPI_
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* Xilinx SPI Register Definition
|
||||
*
|
||||
* [1]: [0]/ip_documentation/xps_spi.pdf
|
||||
* page 8, Register Descriptions
|
||||
* [2]: [0]/ip_documentation/axi_spi_ds742.pdf
|
||||
* page 7, Register Overview Table
|
||||
*/
|
||||
struct xilinx_spi_reg {
|
||||
u32 __space0__[7];
|
||||
u32 dgier; /* Device Global Interrupt Enable Register (DGIER) */
|
||||
u32 ipisr; /* IP Interrupt Status Register (IPISR) */
|
||||
u32 __space1__;
|
||||
u32 ipier; /* IP Interrupt Enable Register (IPIER) */
|
||||
u32 __space2__[5];
|
||||
u32 srr; /* Softare Reset Register (SRR) */
|
||||
u32 __space3__[7];
|
||||
u32 spicr; /* SPI Control Register (SPICR) */
|
||||
u32 spisr; /* SPI Status Register (SPISR) */
|
||||
u32 spidtr; /* SPI Data Transmit Register (SPIDTR) */
|
||||
u32 spidrr; /* SPI Data Receive Register (SPIDRR) */
|
||||
u32 spissr; /* SPI Slave Select Register (SPISSR) */
|
||||
u32 spitfor; /* SPI Transmit FIFO Occupancy Register (SPITFOR) */
|
||||
u32 spirfor; /* SPI Receive FIFO Occupancy Register (SPIRFOR) */
|
||||
};
|
||||
|
||||
/* Device Global Interrupt Enable Register (dgier), [1] p15, [2] p15 */
|
||||
#define DGIER_GIE (1 << 31)
|
||||
|
||||
/* IP Interrupt Status Register (ipisr), [1] p15, [2] p15 */
|
||||
#define IPISR_DRR_NOT_EMPTY (1 << 8)
|
||||
#define IPISR_SLAVE_SELECT (1 << 7)
|
||||
#define IPISR_TXF_HALF_EMPTY (1 << 6)
|
||||
#define IPISR_DRR_OVERRUN (1 << 5)
|
||||
#define IPISR_DRR_FULL (1 << 4)
|
||||
#define IPISR_DTR_UNDERRUN (1 << 3)
|
||||
#define IPISR_DTR_EMPTY (1 << 2)
|
||||
#define IPISR_SLAVE_MODF (1 << 1)
|
||||
#define IPISR_MODF (1 << 0)
|
||||
|
||||
/* IP Interrupt Enable Register (ipier), [1] p17, [2] p18 */
|
||||
#define IPIER_DRR_NOT_EMPTY (1 << 8)
|
||||
#define IPIER_SLAVE_SELECT (1 << 7)
|
||||
#define IPIER_TXF_HALF_EMPTY (1 << 6)
|
||||
#define IPIER_DRR_OVERRUN (1 << 5)
|
||||
#define IPIER_DRR_FULL (1 << 4)
|
||||
#define IPIER_DTR_UNDERRUN (1 << 3)
|
||||
#define IPIER_DTR_EMPTY (1 << 2)
|
||||
#define IPIER_SLAVE_MODF (1 << 1)
|
||||
#define IPIER_MODF (1 << 0)
|
||||
|
||||
/* Softare Reset Register (srr), [1] p9, [2] p8 */
|
||||
#define SRR_RESET_CODE 0x0000000A
|
||||
|
||||
/* SPI Control Register (spicr), [1] p9, [2] p8 */
|
||||
#define SPICR_LSB_FIRST (1 << 9)
|
||||
#define SPICR_MASTER_INHIBIT (1 << 8)
|
||||
#define SPICR_MANUAL_SS (1 << 7)
|
||||
#define SPICR_RXFIFO_RESEST (1 << 6)
|
||||
#define SPICR_TXFIFO_RESEST (1 << 5)
|
||||
#define SPICR_CPHA (1 << 4)
|
||||
#define SPICR_CPOL (1 << 3)
|
||||
#define SPICR_MASTER_MODE (1 << 2)
|
||||
#define SPICR_SPE (1 << 1)
|
||||
#define SPICR_LOOP (1 << 0)
|
||||
|
||||
/* SPI Status Register (spisr), [1] p11, [2] p10 */
|
||||
#define SPISR_SLAVE_MODE_SELECT (1 << 5)
|
||||
#define SPISR_MODF (1 << 4)
|
||||
#define SPISR_TX_FULL (1 << 3)
|
||||
#define SPISR_TX_EMPTY (1 << 2)
|
||||
#define SPISR_RX_FULL (1 << 1)
|
||||
#define SPISR_RX_EMPTY (1 << 0)
|
||||
|
||||
/* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */
|
||||
#define SPIDTR_8BIT_MASK (0xff << 0)
|
||||
#define SPIDTR_16BIT_MASK (0xffff << 0)
|
||||
#define SPIDTR_32BIT_MASK (0xffffffff << 0)
|
||||
|
||||
/* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */
|
||||
#define SPIDRR_8BIT_MASK (0xff << 0)
|
||||
#define SPIDRR_16BIT_MASK (0xffff << 0)
|
||||
#define SPIDRR_32BIT_MASK (0xffffffff << 0)
|
||||
|
||||
/* SPI Slave Select Register (spissr), [1] p13, [2] p13 */
|
||||
#define SPISSR_MASK(cs) (1 << (cs))
|
||||
#define SPISSR_ACT(cs) ~SPISSR_MASK(cs)
|
||||
#define SPISSR_OFF ~0UL
|
||||
|
||||
/* SPI Transmit FIFO Occupancy Register (spitfor), [1] p13, [2] p14 */
|
||||
#define SPITFOR_OCYVAL_POS 0
|
||||
#define SPITFOR_OCYVAL_MASK (0xf << SPITFOR_OCYVAL_POS)
|
||||
|
||||
/* SPI Receive FIFO Occupancy Register (spirfor), [1] p14, [2] p14 */
|
||||
#define SPIRFOR_OCYVAL_POS 0
|
||||
#define SPIRFOR_OCYVAL_MASK (0xf << SPIRFOR_OCYVAL_POS)
|
||||
|
||||
/* SPI Software Reset Register (ssr) */
|
||||
#define SPISSR_RESET_VALUE 0x0a
|
||||
|
||||
struct xilinx_spi_slave {
|
||||
struct spi_slave slave;
|
||||
struct xilinx_spi_reg *regs;
|
||||
unsigned int freq;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
static inline struct xilinx_spi_slave *to_xilinx_spi_slave(
|
||||
struct spi_slave *slave)
|
||||
{
|
||||
return container_of(slave, struct xilinx_spi_slave, slave);
|
||||
}
|
||||
|
||||
#endif /* _XILINX_SPI_ */
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* (C) Copyright 2013 Inc.
|
||||
* (C) Copyright 2015 Jagan Teki <jteki@openedev.com>
|
||||
*
|
||||
* Xilinx Zynq PS SPI controller driver (master mode only)
|
||||
*
|
||||
|
@ -8,11 +9,16 @@
|
|||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <spi.h>
|
||||
#include <fdtdec.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* zynq spi register bit masks ZYNQ_SPI_<REG>_<BIT>_MASK */
|
||||
#define ZYNQ_SPI_CR_MSA_MASK (1 << 15) /* Manual start enb */
|
||||
#define ZYNQ_SPI_CR_MCS_MASK (1 << 14) /* Manual chip select */
|
||||
|
@ -44,180 +50,141 @@ struct zynq_spi_regs {
|
|||
u32 rxdr; /* 0x20 */
|
||||
};
|
||||
|
||||
/* zynq spi slave */
|
||||
struct zynq_spi_slave {
|
||||
struct spi_slave slave;
|
||||
struct zynq_spi_regs *base;
|
||||
u8 mode;
|
||||
u8 fifo_depth;
|
||||
|
||||
/* zynq spi platform data */
|
||||
struct zynq_spi_platdata {
|
||||
struct zynq_spi_regs *regs;
|
||||
u32 frequency; /* input frequency */
|
||||
u32 speed_hz;
|
||||
u32 input_hz;
|
||||
u32 req_hz;
|
||||
};
|
||||
|
||||
static inline struct zynq_spi_slave *to_zynq_spi_slave(struct spi_slave *slave)
|
||||
/* zynq spi priv */
|
||||
struct zynq_spi_priv {
|
||||
struct zynq_spi_regs *regs;
|
||||
u8 mode;
|
||||
u8 fifo_depth;
|
||||
u32 freq; /* required frequency */
|
||||
};
|
||||
|
||||
static int zynq_spi_ofdata_to_platdata(struct udevice *bus)
|
||||
{
|
||||
return container_of(slave, struct zynq_spi_slave, slave);
|
||||
struct zynq_spi_platdata *plat = bus->platdata;
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = bus->of_offset;
|
||||
|
||||
plat->regs = (struct zynq_spi_regs *)fdtdec_get_addr(blob, node, "reg");
|
||||
|
||||
/* FIXME: Use 250MHz as a suitable default */
|
||||
plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
|
||||
250000000);
|
||||
plat->speed_hz = plat->frequency / 2;
|
||||
|
||||
debug("zynq_spi_ofdata_to_platdata: regs=%p max-frequency=%d\n",
|
||||
plat->regs, plat->frequency);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct zynq_spi_regs *get_zynq_spi_base(int dev)
|
||||
{
|
||||
if (dev)
|
||||
return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR1;
|
||||
else
|
||||
return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR0;
|
||||
}
|
||||
|
||||
static void zynq_spi_init_hw(struct zynq_spi_slave *zslave)
|
||||
static void zynq_spi_init_hw(struct zynq_spi_priv *priv)
|
||||
{
|
||||
struct zynq_spi_regs *regs = priv->regs;
|
||||
u32 confr;
|
||||
|
||||
/* Disable SPI */
|
||||
writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
|
||||
writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, ®s->enr);
|
||||
|
||||
/* Disable Interrupts */
|
||||
writel(ZYNQ_SPI_IXR_ALL_MASK, &zslave->base->idr);
|
||||
writel(ZYNQ_SPI_IXR_ALL_MASK, ®s->idr);
|
||||
|
||||
/* Clear RX FIFO */
|
||||
while (readl(&zslave->base->isr) &
|
||||
while (readl(®s->isr) &
|
||||
ZYNQ_SPI_IXR_RXNEMPTY_MASK)
|
||||
readl(&zslave->base->rxdr);
|
||||
readl(®s->rxdr);
|
||||
|
||||
/* Clear Interrupts */
|
||||
writel(ZYNQ_SPI_IXR_ALL_MASK, &zslave->base->isr);
|
||||
writel(ZYNQ_SPI_IXR_ALL_MASK, ®s->isr);
|
||||
|
||||
/* Manual slave select and Auto start */
|
||||
confr = ZYNQ_SPI_CR_MCS_MASK | ZYNQ_SPI_CR_CS_MASK |
|
||||
ZYNQ_SPI_CR_MSTREN_MASK;
|
||||
confr &= ~ZYNQ_SPI_CR_MSA_MASK;
|
||||
writel(confr, &zslave->base->cr);
|
||||
writel(confr, ®s->cr);
|
||||
|
||||
/* Enable SPI */
|
||||
writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
|
||||
writel(ZYNQ_SPI_ENR_SPI_EN_MASK, ®s->enr);
|
||||
}
|
||||
|
||||
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
|
||||
static int zynq_spi_probe(struct udevice *bus)
|
||||
{
|
||||
/* 2 bus with 3 chipselect */
|
||||
return bus < 2 && cs < 3;
|
||||
struct zynq_spi_platdata *plat = dev_get_platdata(bus);
|
||||
struct zynq_spi_priv *priv = dev_get_priv(bus);
|
||||
|
||||
priv->regs = plat->regs;
|
||||
priv->fifo_depth = ZYNQ_SPI_FIFO_DEPTH;
|
||||
|
||||
/* init the zynq spi hw */
|
||||
zynq_spi_init_hw(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_cs_activate(struct spi_slave *slave)
|
||||
static void spi_cs_activate(struct udevice *dev, uint cs)
|
||||
{
|
||||
struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
|
||||
struct udevice *bus = dev->parent;
|
||||
struct zynq_spi_priv *priv = dev_get_priv(bus);
|
||||
struct zynq_spi_regs *regs = priv->regs;
|
||||
u32 cr;
|
||||
|
||||
debug("spi_cs_activate: 0x%08x\n", (u32)slave);
|
||||
|
||||
clrbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK);
|
||||
cr = readl(&zslave->base->cr);
|
||||
clrbits_le32(®s->cr, ZYNQ_SPI_CR_CS_MASK);
|
||||
cr = readl(®s->cr);
|
||||
/*
|
||||
* CS cal logic: CS[13:10]
|
||||
* xxx0 - cs0
|
||||
* xx01 - cs1
|
||||
* x011 - cs2
|
||||
*/
|
||||
cr |= (~(0x1 << slave->cs) << 10) & ZYNQ_SPI_CR_CS_MASK;
|
||||
writel(cr, &zslave->base->cr);
|
||||
cr |= (~(0x1 << cs) << 10) & ZYNQ_SPI_CR_CS_MASK;
|
||||
writel(cr, ®s->cr);
|
||||
}
|
||||
|
||||
void spi_cs_deactivate(struct spi_slave *slave)
|
||||
static void spi_cs_deactivate(struct udevice *dev)
|
||||
{
|
||||
struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
|
||||
struct udevice *bus = dev->parent;
|
||||
struct zynq_spi_priv *priv = dev_get_priv(bus);
|
||||
struct zynq_spi_regs *regs = priv->regs;
|
||||
|
||||
debug("spi_cs_deactivate: 0x%08x\n", (u32)slave);
|
||||
|
||||
setbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK);
|
||||
setbits_le32(®s->cr, ZYNQ_SPI_CR_CS_MASK);
|
||||
}
|
||||
|
||||
void spi_init()
|
||||
static int zynq_spi_claim_bus(struct udevice *dev)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
struct udevice *bus = dev->parent;
|
||||
struct zynq_spi_priv *priv = dev_get_priv(bus);
|
||||
struct zynq_spi_regs *regs = priv->regs;
|
||||
|
||||
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
||||
unsigned int max_hz, unsigned int mode)
|
||||
{
|
||||
struct zynq_spi_slave *zslave;
|
||||
|
||||
if (!spi_cs_is_valid(bus, cs))
|
||||
return NULL;
|
||||
|
||||
zslave = spi_alloc_slave(struct zynq_spi_slave, bus, cs);
|
||||
if (!zslave) {
|
||||
printf("SPI_error: Fail to allocate zynq_spi_slave\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
zslave->base = get_zynq_spi_base(bus);
|
||||
zslave->mode = mode;
|
||||
zslave->fifo_depth = ZYNQ_SPI_FIFO_DEPTH;
|
||||
zslave->input_hz = 166666700;
|
||||
zslave->speed_hz = zslave->input_hz / 2;
|
||||
zslave->req_hz = max_hz;
|
||||
|
||||
/* init the zynq spi hw */
|
||||
zynq_spi_init_hw(zslave);
|
||||
|
||||
return &zslave->slave;
|
||||
}
|
||||
|
||||
void spi_free_slave(struct spi_slave *slave)
|
||||
{
|
||||
struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
|
||||
|
||||
debug("spi_free_slave: 0x%08x\n", (u32)slave);
|
||||
free(zslave);
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
{
|
||||
struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
|
||||
u32 confr = 0;
|
||||
u8 baud_rate_val = 0;
|
||||
|
||||
writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
|
||||
|
||||
/* Set the SPI Clock phase and polarities */
|
||||
confr = readl(&zslave->base->cr);
|
||||
confr &= ~(ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK);
|
||||
if (zslave->mode & SPI_CPHA)
|
||||
confr |= ZYNQ_SPI_CR_CPHA_MASK;
|
||||
if (zslave->mode & SPI_CPOL)
|
||||
confr |= ZYNQ_SPI_CR_CPOL_MASK;
|
||||
|
||||
/* Set the clock frequency */
|
||||
if (zslave->req_hz == 0) {
|
||||
/* Set baudrate x8, if the req_hz is 0 */
|
||||
baud_rate_val = 0x2;
|
||||
} else if (zslave->speed_hz != zslave->req_hz) {
|
||||
while ((baud_rate_val < 8) &&
|
||||
((zslave->input_hz /
|
||||
(2 << baud_rate_val)) > zslave->req_hz))
|
||||
baud_rate_val++;
|
||||
zslave->speed_hz = zslave->req_hz / (2 << baud_rate_val);
|
||||
}
|
||||
confr &= ~ZYNQ_SPI_CR_BRD_MASK;
|
||||
confr |= (baud_rate_val << 3);
|
||||
writel(confr, &zslave->base->cr);
|
||||
|
||||
writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
|
||||
writel(ZYNQ_SPI_ENR_SPI_EN_MASK, ®s->enr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
static int zynq_spi_release_bus(struct udevice *dev)
|
||||
{
|
||||
struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
|
||||
struct udevice *bus = dev->parent;
|
||||
struct zynq_spi_priv *priv = dev_get_priv(bus);
|
||||
struct zynq_spi_regs *regs = priv->regs;
|
||||
|
||||
debug("spi_release_bus: 0x%08x\n", (u32)slave);
|
||||
writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
|
||||
writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, ®s->enr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
|
||||
void *din, unsigned long flags)
|
||||
static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
|
||||
struct udevice *bus = dev->parent;
|
||||
struct zynq_spi_priv *priv = dev_get_priv(bus);
|
||||
struct zynq_spi_regs *regs = priv->regs;
|
||||
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
|
||||
u32 len = bitlen / 8;
|
||||
u32 tx_len = len, rx_len = len, tx_tvl;
|
||||
const u8 *tx_buf = dout;
|
||||
|
@ -225,7 +192,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
|
|||
u32 ts, status;
|
||||
|
||||
debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n",
|
||||
slave->bus, slave->cs, bitlen, len, flags);
|
||||
bus->seq, slave_plat->cs, bitlen, len, flags);
|
||||
|
||||
if (bitlen % 8) {
|
||||
debug("spi_xfer: Non byte aligned SPI transfer\n");
|
||||
|
@ -233,45 +200,126 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
|
|||
}
|
||||
|
||||
if (flags & SPI_XFER_BEGIN)
|
||||
spi_cs_activate(slave);
|
||||
spi_cs_activate(dev, slave_plat->cs);
|
||||
|
||||
while (rx_len > 0) {
|
||||
/* Write the data into TX FIFO - tx threshold is fifo_depth */
|
||||
tx_tvl = 0;
|
||||
while ((tx_tvl < zslave->fifo_depth) && tx_len) {
|
||||
while ((tx_tvl < priv->fifo_depth) && tx_len) {
|
||||
if (tx_buf)
|
||||
buf = *tx_buf++;
|
||||
else
|
||||
buf = 0;
|
||||
writel(buf, &zslave->base->txdr);
|
||||
writel(buf, ®s->txdr);
|
||||
tx_len--;
|
||||
tx_tvl++;
|
||||
}
|
||||
|
||||
/* Check TX FIFO completion */
|
||||
ts = get_timer(0);
|
||||
status = readl(&zslave->base->isr);
|
||||
status = readl(®s->isr);
|
||||
while (!(status & ZYNQ_SPI_IXR_TXOW_MASK)) {
|
||||
if (get_timer(ts) > CONFIG_SYS_ZYNQ_SPI_WAIT) {
|
||||
printf("spi_xfer: Timeout! TX FIFO not full\n");
|
||||
return -1;
|
||||
}
|
||||
status = readl(&zslave->base->isr);
|
||||
status = readl(®s->isr);
|
||||
}
|
||||
|
||||
/* Read the data from RX FIFO */
|
||||
status = readl(&zslave->base->isr);
|
||||
status = readl(®s->isr);
|
||||
while (status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) {
|
||||
buf = readl(&zslave->base->rxdr);
|
||||
buf = readl(®s->rxdr);
|
||||
if (rx_buf)
|
||||
*rx_buf++ = buf;
|
||||
status = readl(&zslave->base->isr);
|
||||
status = readl(®s->isr);
|
||||
rx_len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & SPI_XFER_END)
|
||||
spi_cs_deactivate(slave);
|
||||
spi_cs_deactivate(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynq_spi_set_speed(struct udevice *bus, uint speed)
|
||||
{
|
||||
struct zynq_spi_platdata *plat = bus->platdata;
|
||||
struct zynq_spi_priv *priv = dev_get_priv(bus);
|
||||
struct zynq_spi_regs *regs = priv->regs;
|
||||
uint32_t confr;
|
||||
u8 baud_rate_val = 0;
|
||||
|
||||
if (speed > plat->frequency)
|
||||
speed = plat->frequency;
|
||||
|
||||
/* Set the clock frequency */
|
||||
confr = readl(®s->cr);
|
||||
if (speed == 0) {
|
||||
/* Set baudrate x8, if the freq is 0 */
|
||||
baud_rate_val = 0x2;
|
||||
} else if (plat->speed_hz != speed) {
|
||||
while ((baud_rate_val < 8) &&
|
||||
((plat->frequency /
|
||||
(2 << baud_rate_val)) > speed))
|
||||
baud_rate_val++;
|
||||
plat->speed_hz = speed / (2 << baud_rate_val);
|
||||
}
|
||||
confr &= ~ZYNQ_SPI_CR_BRD_MASK;
|
||||
confr |= (baud_rate_val << 3);
|
||||
|
||||
writel(confr, ®s->cr);
|
||||
priv->freq = speed;
|
||||
|
||||
debug("zynq_spi_set_speed: regs=%p, mode=%d\n", priv->regs, priv->freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynq_spi_set_mode(struct udevice *bus, uint mode)
|
||||
{
|
||||
struct zynq_spi_priv *priv = dev_get_priv(bus);
|
||||
struct zynq_spi_regs *regs = priv->regs;
|
||||
uint32_t confr;
|
||||
|
||||
/* Set the SPI Clock phase and polarities */
|
||||
confr = readl(®s->cr);
|
||||
confr &= ~(ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK);
|
||||
|
||||
if (priv->mode & SPI_CPHA)
|
||||
confr |= ZYNQ_SPI_CR_CPHA_MASK;
|
||||
if (priv->mode & SPI_CPOL)
|
||||
confr |= ZYNQ_SPI_CR_CPOL_MASK;
|
||||
|
||||
writel(confr, ®s->cr);
|
||||
priv->mode = mode;
|
||||
|
||||
debug("zynq_spi_set_mode: regs=%p, mode=%d\n", priv->regs, priv->mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_spi_ops zynq_spi_ops = {
|
||||
.claim_bus = zynq_spi_claim_bus,
|
||||
.release_bus = zynq_spi_release_bus,
|
||||
.xfer = zynq_spi_xfer,
|
||||
.set_speed = zynq_spi_set_speed,
|
||||
.set_mode = zynq_spi_set_mode,
|
||||
};
|
||||
|
||||
static const struct udevice_id zynq_spi_ids[] = {
|
||||
{ .compatible = "xlnx,zynq-spi" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(zynq_spi) = {
|
||||
.name = "zynq_spi",
|
||||
.id = UCLASS_SPI,
|
||||
.of_match = zynq_spi_ids,
|
||||
.ops = &zynq_spi_ops,
|
||||
.ofdata_to_platdata = zynq_spi_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct zynq_spi_platdata),
|
||||
.priv_auto_alloc_size = sizeof(struct zynq_spi_priv),
|
||||
.probe = zynq_spi_probe,
|
||||
};
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
|
||||
/* FLASH */
|
||||
#define CONFIG_SPI
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_SH_QSPI
|
||||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
#define CONFIG_SPI_FLASH_QUAD
|
||||
|
|
|
@ -204,7 +204,6 @@
|
|||
#define CONFIG_CMD_SF
|
||||
#define CONFIG_CMD_SPI
|
||||
#define CONFIG_TI_SPI_MMAP
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_QSPI_SEL_GPIO 48
|
||||
#define CONFIG_SF_DEFAULT_SPEED 48000000
|
||||
#define CONFIG_DEFAULT_SPI_MODE SPI_MODE_3
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
|
||||
/* SPI FLASH */
|
||||
#ifdef CONFIG_CMD_SF
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_SPI_FLASH_STMICRO
|
||||
#define CONFIG_SF_DEFAULT_BUS 2
|
||||
#define CONFIG_SF_DEFAULT_CS 0
|
||||
|
|
|
@ -125,7 +125,6 @@
|
|||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
#define CONFIG_CMD_SF
|
||||
#define CONFIG_CMD_SPI
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_TI_SPI_MMAP
|
||||
#define CONFIG_SF_DEFAULT_SPEED 48000000
|
||||
#define CONFIG_DEFAULT_SPI_MODE SPI_MODE_3
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#define CONFIG_SYS_NO_FLASH
|
||||
#define CONFIG_SPI
|
||||
#define CONFIG_SH_QSPI
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
|
||||
/* SH Ether */
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#define CONFIG_SYS_NO_FLASH
|
||||
#define CONFIG_SPI
|
||||
#define CONFIG_SH_QSPI
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
|
||||
/* SH Ether */
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
/* SPI */
|
||||
#define CONFIG_SPI
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_SH_QSPI
|
||||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
#define CONFIG_SYS_NO_FLASH
|
||||
|
|
|
@ -423,7 +423,7 @@ unsigned long get_board_ddr_clk(void);
|
|||
#if defined(CONFIG_FSL_DSPI) || defined(CONFIG_FSL_QSPI)
|
||||
#define CONFIG_CMD_SF
|
||||
#define CONFIG_DM_SPI_FLASH
|
||||
#define CONFIG_SF_DATAFLASH
|
||||
#define CONFIG_SPI_FLASH_DATAFLASH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
|
||||
#define CONFIG_SPI_FLASH_STMICRO
|
||||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
|
||||
/* Environment in SPI NOR flash */
|
||||
#define CONFIG_ENV_IS_IN_SPI_FLASH
|
||||
|
|
|
@ -189,7 +189,6 @@
|
|||
|
||||
#ifdef CONFIG_FSL_QSPI
|
||||
#define CONFIG_CMD_SF
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
#define CONFIG_SPI_FLASH_STMICRO
|
||||
#define CONFIG_SYS_FSL_QSPI_LE
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
/* FLASH */
|
||||
#define CONFIG_SPI
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_SH_QSPI
|
||||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
#define CONFIG_SPI_FLASH_QUAD
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
/* FLASH */
|
||||
#define CONFIG_SPI
|
||||
#define CONFIG_SPI_FLASH_BAR
|
||||
#define CONFIG_SH_QSPI
|
||||
#define CONFIG_SPI_FLASH_SPANSION
|
||||
#define CONFIG_SPI_FLASH_QUAD
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
/* Header byte that marks the start of the message */
|
||||
#define SPI_PREAMBLE_END_BYTE 0xec
|
||||
|
||||
#define SPI_DEFAULT_WORDLEN 8
|
||||
#define SPI_DEFAULT_WORDLEN 8
|
||||
|
||||
#ifdef CONFIG_DM_SPI
|
||||
/* TODO(sjg@chromium.org): Remove this and use max_hz from struct spi_slave */
|
||||
|
|
|
@ -37,13 +37,15 @@ struct spi_slave;
|
|||
* struct spi_flash - SPI flash structure
|
||||
*
|
||||
* @spi: SPI slave
|
||||
* @dev: SPI flash device
|
||||
* @flags: Indication of spi flash flags
|
||||
* @name: Name of SPI flash
|
||||
* @dual_flash: Indicates dual flash memories - dual stacked, parallel
|
||||
* @dual_flash: Indicates dual flash memories - dual stacked, parallel
|
||||
* @shift: Flash shift useful in dual parallel
|
||||
* @size: Total flash size
|
||||
* @page_size: Write (page) size
|
||||
* @sector_size: Sector size
|
||||
* @erase_size: Erase size
|
||||
* @erase_size: Erase size
|
||||
* @bank_read_cmd: Bank read cmd
|
||||
* @bank_write_cmd: Bank write cmd
|
||||
* @bank_curr: Current flash bank
|
||||
|
@ -51,8 +53,8 @@ struct spi_slave;
|
|||
* @erase_cmd: Erase cmd 4K, 32K, 64K
|
||||
* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
|
||||
* @write_cmd: Write cmd - page and quad program.
|
||||
* @dummy_byte: Dummy cycles for read operation.
|
||||
* @memory_map: Address of read-only SPI flash access
|
||||
* @dummy_byte: Dummy cycles for read operation.
|
||||
* @memory_map: Address of read-only SPI flash access
|
||||
* @read: Flash read ops: Read len bytes at offset into buf
|
||||
* Supported cmds: Fast Array Read
|
||||
* @write: Flash write ops: Write len bytes from buf into offset
|
||||
|
|
Loading…
Add table
Reference in a new issue