Merge branch 'master' of git://git.denx.de/u-boot-spi

This commit is contained in:
Tom Rini 2016-02-23 08:13:46 -05:00
commit b625fab706
12 changed files with 279 additions and 5 deletions

View file

@ -23,3 +23,4 @@ CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH_BAR=y
CONFIG_TIMER=y
CONFIG_OMAP_TIMER=y
CONFIG_DMA=y

View file

@ -0,0 +1,22 @@
menu "DMA Support"
config DMA
bool "Enable Driver Model for DMA drivers"
depends on DM
help
Enable driver model for DMA. DMA engines can do
asynchronous data transfers without involving the host
CPU. Currently, this framework can be used to offload
memory copies to and from devices like qspi, ethernet
etc Drivers provide methods to access the DMA devices
buses that is used to transfer data to and from memory.
The uclass interface is defined in include/dma.h.
config TI_EDMA3
bool "TI EDMA3 driver"
help
Enable the TI EDMA3 driver for DRA7xx and AM43xx evms.
This driver support data transfer between memory
regions.
endmenu # menu "DMA Support"

View file

@ -5,6 +5,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_DMA) += dma-uclass.o
obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o
obj-$(CONFIG_APBH_DMA) += apbh_dma.o
obj-$(CONFIG_FSL_DMA) += fsl_dma.o

72
drivers/dma/dma-uclass.c Normal file
View file

@ -0,0 +1,72 @@
/*
* Direct Memory Access U-Class driver
*
* (C) Copyright 2015
* Texas Instruments Incorporated, <www.ti.com>
*
* Author: Mugunthan V N <mugunthanvnm@ti.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dma.h>
#include <dm.h>
#include <dm/uclass-internal.h>
#include <dm/device-internal.h>
#include <errno.h>
DECLARE_GLOBAL_DATA_PTR;
int dma_get_device(u32 transfer_type, struct udevice **devp)
{
struct udevice *dev;
int ret;
for (ret = uclass_first_device(UCLASS_DMA, &dev); dev && !ret;
ret = uclass_next_device(&dev)) {
struct dma_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
if (uc_priv->supported & transfer_type)
break;
}
if (!dev) {
error("No DMA device found that supports %x type\n",
transfer_type);
return -EPROTONOSUPPORT;
}
*devp = dev;
return ret;
}
int dma_memcpy(void *dst, void *src, size_t len)
{
struct udevice *dev;
const struct dma_ops *ops;
int ret;
ret = dma_get_device(DMA_SUPPORTS_MEM_TO_MEM, &dev);
if (ret < 0)
return ret;
ops = device_get_ops(dev);
if (!ops->transfer)
return -ENOSYS;
/* Invalidate the area, so no writeback into the RAM races with DMA */
invalidate_dcache_range((unsigned long)dst, (unsigned long)dst +
roundup(len, ARCH_DMA_MINALIGN));
return ops->transfer(dev, DMA_MEM_TO_MEM, dst, src, len);
}
UCLASS_DRIVER(dma) = {
.id = UCLASS_DMA,
.name = "dma",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.per_device_auto_alloc_size = sizeof(struct dma_dev_priv),
};

View file

@ -11,6 +11,9 @@
#include <asm/io.h>
#include <common.h>
#include <dma.h>
#include <dm/device.h>
#include <asm/omap_common.h>
#include <asm/ti-common/ti-edma3.h>
#define EDMA3_SL_BASE(slot) (0x4000 + ((slot) << 5))
@ -31,6 +34,10 @@
#define EDMA3_QEESR 0x108c
#define EDMA3_QSECR 0x1094
struct ti_edma3_priv {
u32 base;
};
/**
* qedma3_start - start qdma on a channel
* @base: base address of edma
@ -383,8 +390,8 @@ void qedma3_stop(u32 base, struct edma3_channel_config *cfg)
__raw_writel(0, base + EDMA3_QCHMAP(cfg->chnum));
}
void edma3_transfer(unsigned long edma3_base_addr, unsigned int
edma_slot_num, void *dst, void *src, size_t len)
void __edma3_transfer(unsigned long edma3_base_addr, unsigned int edma_slot_num,
void *dst, void *src, size_t len)
{
struct edma3_slot_config slot;
struct edma3_channel_config edma_channel;
@ -460,3 +467,74 @@ void edma3_transfer(unsigned long edma3_base_addr, unsigned int
qedma3_stop(edma3_base_addr, &edma_channel);
}
}
#ifndef CONFIG_DMA
void edma3_transfer(unsigned long edma3_base_addr, unsigned int edma_slot_num,
void *dst, void *src, size_t len)
{
__edma3_transfer(edma3_base_addr, edma_slot_num, dst, src, len);
}
#else
static int ti_edma3_transfer(struct udevice *dev, int direction, void *dst,
void *src, size_t len)
{
struct ti_edma3_priv *priv = dev_get_priv(dev);
/* enable edma3 clocks */
enable_edma3_clocks();
switch (direction) {
case DMA_MEM_TO_MEM:
__edma3_transfer(priv->base, 1, dst, src, len);
break;
default:
error("Transfer type not implemented in DMA driver\n");
break;
}
/* disable edma3 clocks */
disable_edma3_clocks();
return 0;
}
static int ti_edma3_ofdata_to_platdata(struct udevice *dev)
{
struct ti_edma3_priv *priv = dev_get_priv(dev);
priv->base = dev_get_addr(dev);
return 0;
}
static int ti_edma3_probe(struct udevice *dev)
{
struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM;
return 0;
}
static const struct dma_ops ti_edma3_ops = {
.transfer = ti_edma3_transfer,
};
static const struct udevice_id ti_edma3_ids[] = {
{ .compatible = "ti,edma3" },
{ }
};
U_BOOT_DRIVER(ti_edma3) = {
.name = "ti_edma3",
.id = UCLASS_DMA,
.of_match = ti_edma3_ids,
.ops = &ti_edma3_ops,
.ofdata_to_platdata = ti_edma3_ofdata_to_platdata,
.probe = ti_edma3_probe,
.priv_auto_alloc_size = sizeof(struct ti_edma3_priv),
};
#endif /* CONFIG_DMA */

View file

@ -16,6 +16,7 @@
#include <spi.h>
#include <spi_flash.h>
#include <linux/log2.h>
#include <dma.h>
#include "sf_internal.h"
@ -454,8 +455,16 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
return ret;
}
/*
* TODO: remove the weak after all the other spi_flash_copy_mmap
* implementations removed from drivers
*/
void __weak spi_flash_copy_mmap(void *data, void *offset, size_t len)
{
#ifdef CONFIG_DMA
if (!dma_memcpy(data, offset, len))
return;
#endif
memcpy(data, offset, len);
}

View file

@ -336,7 +336,6 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
struct omap3_spi_slave *ds = to_omap3_spi(slave);
ulong start;
int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
int irqstatus = readl(&ds->regs->irqstatus);
int i=0;
/*Enable SPI channel*/
@ -351,7 +350,6 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
/*Shift in and out 1 byte at time*/
for (i=0; i < len; i++){
/* Write: wait for TX empty (TXS == 1)*/
irqstatus |= (1<< (4*(ds->slave.bus)));
start = get_timer(0);
while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
OMAP3_MCSPI_CHSTAT_TXS)) {

View file

@ -158,6 +158,7 @@ static int spi_child_pre_probe(struct udevice *dev)
slave->max_hz = plat->max_hz;
slave->mode = plat->mode;
slave->mode_rx = plat->mode_rx;
slave->wordlen = SPI_DEFAULT_WORDLEN;
return 0;
}

View file

@ -277,7 +277,7 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen,
}
/* TODO: control from sf layer to here through dm-spi */
#ifdef CONFIG_TI_EDMA3
#if defined(CONFIG_TI_EDMA3) && !defined(CONFIG_DMA)
void spi_flash_copy_mmap(void *data, void *offset, size_t len)
{
unsigned int addr = (unsigned int) (data);

View file

@ -197,7 +197,11 @@
/* Environment */
#ifndef CONFIG_ENV_IS_NOWHERE
# ifndef CONFIG_SYS_NO_FLASH
/* Environment in NOR flash */
# define CONFIG_ENV_IS_IN_FLASH
# elif defined(CONFIG_ZYNQ_QSPI)
/* Environment in Serial Flash */
# define CONFIG_ENV_IS_IN_SPI_FLASH
# elif defined(CONFIG_SYS_NO_FLASH)
# define CONFIG_ENV_IS_NOWHERE
# endif

View file

@ -31,6 +31,7 @@ enum uclass_id {
UCLASS_CROS_EC, /* Chrome OS EC */
UCLASS_DISK, /* Disk controller, e.g. SATA */
UCLASS_DISPLAY, /* Display (e.g. DisplayPort, HDMI) */
UCLASS_DMA, /* Direct Memory Access */
UCLASS_RAM, /* RAM controller */
UCLASS_ETH, /* Ethernet device */
UCLASS_GPIO, /* Bank of general-purpose I/O pins */

86
include/dma.h Normal file
View file

@ -0,0 +1,86 @@
/*
* (C) Copyright 2015
* Texas Instruments Incorporated, <www.ti.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _DMA_H_
#define _DMA_H_
/*
* enum dma_direction - dma transfer direction indicator
* @DMA_MEM_TO_MEM: Memcpy mode
* @DMA_MEM_TO_DEV: From Memory to Device
* @DMA_DEV_TO_MEM: From Device to Memory
* @DMA_DEV_TO_DEV: From Device to Device
*/
enum dma_direction {
DMA_MEM_TO_MEM,
DMA_MEM_TO_DEV,
DMA_DEV_TO_MEM,
DMA_DEV_TO_DEV,
};
#define DMA_SUPPORTS_MEM_TO_MEM BIT(0)
#define DMA_SUPPORTS_MEM_TO_DEV BIT(1)
#define DMA_SUPPORTS_DEV_TO_MEM BIT(2)
#define DMA_SUPPORTS_DEV_TO_DEV BIT(3)
/*
* struct dma_ops - Driver model DMA operations
*
* The uclass interface is implemented by all DMA devices which use
* driver model.
*/
struct dma_ops {
/*
* Get the current timer count
*
* @dev: The DMA device
* @direction: direction of data transfer should be one from
enum dma_direction
* @dst: Destination pointer
* @src: Source pointer
* @len: Length of the data to be copied.
* @return: 0 if OK, -ve on error
*/
int (*transfer)(struct udevice *dev, int direction, void *dst,
void *src, size_t len);
};
/*
* struct dma_dev_priv - information about a device used by the uclass
*
* @supported: mode of transfers that DMA can support, should be
* one/multiple of DMA_SUPPORTS_*
*/
struct dma_dev_priv {
u32 supported;
};
/*
* dma_get_device - get a DMA device which supports transfer
* type of transfer_type
*
* @transfer_type - transfer type should be one/multiple of
* DMA_SUPPORTS_*
* @devp - udevice pointer to return the found device
* @return - will return on success and devp will hold the
* pointer to the device
*/
int dma_get_device(u32 transfer_type, struct udevice **devp);
/*
* dma_memcpy - try to use DMA to do a mem copy which will be
* much faster than CPU mem copy
*
* @dst - destination pointer
* @src - souce pointer
* @len - data length to be copied
* @return - on successful transfer returns no of bytes
transferred and on failure return error code.
*/
int dma_memcpy(void *dst, void *src, size_t len);
#endif /* _DMA_H_ */