Skip to content

Commit

Permalink
boards: intel_s1000_crb: enable DMA
Browse files Browse the repository at this point in the history
Enable the CAVS DMA on intel_s1000. Also, introduce a test to
validate the DMA.

Change-Id: I2ff233c45cfd8aea55e254d905350a666aa649a0
Signed-off-by: Rajavardhan Gundi <[email protected]>
Signed-off-by: Anas Nashif <[email protected]>
  • Loading branch information
rgundi authored and Anas Nashif committed May 1, 2018
1 parent bd0d513 commit cea1c75
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 0 deletions.
6 changes: 6 additions & 0 deletions arch/xtensa/soc/intel_s1000/soc.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <logging/sys_log.h>
#include <board.h>
#include <irq_nextlevel.h>
#include <xtensa/hal.h>

void _soc_irq_enable(u32_t irq)
{
Expand Down Expand Up @@ -154,3 +155,8 @@ void setup_ownership_dma2(void)
{
*(volatile u16_t *)CAVS_DMA2_OWNERSHIP_REG = 0x80FF;
}

void dcache_writeback_region(void *addr, size_t size)
{
xthal_dcache_region_writeback(addr, size);
}
22 changes: 22 additions & 0 deletions arch/xtensa/soc/intel_s1000/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,39 @@
#define I2C_DW_IRQ_FLAGS 0
#define I2C_DW_CLOCK_SPEED 38

/* low power DMACs */
#define LP_GP_DMA_SIZE 0x00001000
#define DW_DMA0_BASE_ADDR 0x0007C000
#define DW_DMA1_BASE_ADDR (0x0007C000 +\
1 * LP_GP_DMA_SIZE)
#define DW_DMA2_BASE_ADDR (0x0007C000 +\
2 * LP_GP_DMA_SIZE)

#define DW_DMA0_IRQ 0x00001110
#define DW_DMA1_IRQ 0x0000010A
#define DW_DMA2_IRQ 0x0000010D

/* address of DMA ownership register. We need to properly configure
* this register in order to access the DMA registers.
*/
#define CAVS_DMA0_OWNERSHIP_REG (0x00071A60)
#define CAVS_DMA1_OWNERSHIP_REG (0x00071A62)
#define CAVS_DMA2_OWNERSHIP_REG (0x00071A64)

#define DMA_HANDSHAKE_SSP0_TX 2
#define DMA_HANDSHAKE_SSP0_RX 3
#define DMA_HANDSHAKE_SSP1_TX 4
#define DMA_HANDSHAKE_SSP1_RX 5
#define DMA_HANDSHAKE_SSP2_TX 6
#define DMA_HANDSHAKE_SSP2_RX 7
#define DMA_HANDSHAKE_SSP3_TX 8
#define DMA_HANDSHAKE_SSP3_RX 9

extern void _soc_irq_enable(u32_t irq);
extern void _soc_irq_disable(u32_t irq);
extern void setup_ownership_dma0(void);
extern void setup_ownership_dma1(void);
extern void setup_ownership_dma2(void);
extern void dcache_writeback_region(void *addr, size_t size);

#endif /* __INC_SOC_H */
7 changes: 7 additions & 0 deletions boards/xtensa/intel_s1000_crb/Kconfig.defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ config I2C_0_DEFAULT_CFG
config I2C_0_IRQ_PRI
default 0

if DMA_CAVS

config HEAP_MEM_POOL_SIZE
default 1024

endif # DMA_CAVS

if UART_NS16550

config UART_NS16550_PORT_0
Expand Down
4 changes: 4 additions & 0 deletions boards/xtensa/intel_s1000_crb/intel_s1000_crb_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ CONFIG_I2C=y
CONFIG_I2C_DW=y
CONFIG_I2C_0=y

CONFIG_DMA=y
CONFIG_DMA_CAVS=y
CONFIG_DCACHE_WRITEBACK=y

CONFIG_CONSOLE=y
CONFIG_SERIAL_HAS_DRIVER=y
CONFIG_SERIAL=y
Expand Down
241 changes: 241 additions & 0 deletions tests/boards/intel_s1000_crb/src/dma_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @file Sample app to illustrate dma transfer on Intel_S1000.
*
* Intel_S1000 - Xtensa
* --------------------
*
* The dma_cavs driver is being used.
*
* In this sample app, multi-block dma is tested in the following manner
* - Define 2 strings which will serve as 2 blocks of source data.
* - Define 2 empty buffers to receive the data from the DMA operation.
* - Set dma channel configuration including source/dest addr, burstlen etc.
* - Set direction memory-to-memory
* - Start transfer
*
* - Expected Results
* - Data is transferred correctly from src to dest. The DMAed string should
* be printed on to the console. No error should be seen.
*/

#include <zephyr.h>
#include <misc/printk.h>

#include <device.h>
#include <dma.h>

#include <string.h>
#include <xtensa/hal.h>

/* size of stack area used by each thread */
#define STACKSIZE 1024

/* scheduling priority used by each thread */
#define PRIORITY 7

/* delay between greetings (in ms) */
#define SLEEPTIME 500

/* max time to be waited for dma to complete (in ms) */
#define WAITTIME 1000

/* This semaphore is used as a signal from the dma isr to the app
* to let it know the DMA is complete. The app should wait till
* this event comes indicating the completion of DMA.
*/
K_SEM_DEFINE(dma_sem, 0, 1);

extern struct k_sem thread_sem;

#define DMA_DEVICE_NAME CONFIG_DMA_0_NAME
#define RX_BUFF_SIZE (48)

static const char tx_data[] = "It is harder to be kind than to be wise";
static const char tx_data2[] = "India have a good cricket team";
static const char tx_data3[] = "Virat: the best ever?";
static const char tx_data4[] = "Phenomenon";
static char rx_data[RX_BUFF_SIZE] = { 0 };
static char rx_data2[RX_BUFF_SIZE] = { 0 };
static char rx_data3[RX_BUFF_SIZE] = { 0 };
static char rx_data4[RX_BUFF_SIZE] = { 0 };

static void test_done(struct device *dev, u32_t id, int error_code)
{
if (error_code == 0) {
printk("DMA transfer done\n");
} else {
printk("DMA transfer met an error = 0x%x\n", error_code);
}

k_sem_give(&dma_sem);
}

static int test_task(u32_t chan_id, u32_t blen, u32_t block_count)
{
struct dma_config dma_cfg = {0};

struct dma_block_config dma_block_cfg = {
.block_size = sizeof(tx_data),
.source_address = (u32_t)tx_data,
.dest_address = (u32_t)rx_data,
};

struct dma_block_config dma_block_cfg2 = {
.block_size = sizeof(tx_data2),
.source_address = (u32_t)tx_data2,
.dest_address = (u32_t)rx_data2,
};

struct dma_block_config dma_block_cfg3 = {
.block_size = sizeof(tx_data3),
.source_address = (u32_t)tx_data3,
.dest_address = (u32_t)rx_data3,
};

struct dma_block_config dma_block_cfg4 = {
.block_size = sizeof(tx_data4),
.source_address = (u32_t)tx_data4,
.dest_address = (u32_t)rx_data4,
};

struct device *dma = device_get_binding(DMA_DEVICE_NAME);

if (!dma) {
printk("Cannot get dma controller\n");
return -1;
}

dma_cfg.channel_direction = MEMORY_TO_MEMORY;
dma_cfg.source_data_size = 1;
dma_cfg.dest_data_size = 1;
dma_cfg.source_burst_length = blen;
dma_cfg.dest_burst_length = blen;
dma_cfg.dma_callback = test_done;
dma_cfg.complete_callback_en = 0;
dma_cfg.error_callback_en = 1;
dma_cfg.block_count = block_count;
dma_cfg.head_block = &dma_block_cfg;

printk("Preparing DMA Controller: Chan_ID=%u, BURST_LEN=%u\n",
chan_id, blen);

memset(rx_data, 0, sizeof(rx_data));
memset(rx_data2, 0, sizeof(rx_data2));
memset(rx_data3, 0, sizeof(rx_data3));
memset(rx_data4, 0, sizeof(rx_data4));

dma_block_cfg.next_block = &dma_block_cfg2;
dma_block_cfg2.next_block = &dma_block_cfg3;
dma_block_cfg3.next_block = &dma_block_cfg4;

/* dma_block_cfg4 is assigned to 0 by default. Hence if next_block is
* not configured, it will be 0 implying the last block in the chain
*/

if (dma_config(dma, chan_id, &dma_cfg)) {
printk("ERROR: configuring\n");
return -1;
}

printk("Starting the transfer\n");
if (dma_start(dma, chan_id)) {
printk("ERROR: transfer\n");
return -1;
}

xthal_dcache_region_invalidate(rx_data, RX_BUFF_SIZE);
xthal_dcache_region_invalidate(rx_data2, RX_BUFF_SIZE);
xthal_dcache_region_invalidate(rx_data3, RX_BUFF_SIZE);
xthal_dcache_region_invalidate(rx_data4, RX_BUFF_SIZE);

/* Wait a while for the dma to complete */
if (k_sem_take(&dma_sem, WAITTIME)) {
printk("*** timed out waiting for dma to complete ***\n");
}

if (dma_stop(dma, chan_id)) {
printk("ERROR: stopping\n");
return -1;
}

/* Intentionally break has been omitted (fall-through) */
switch (dma_cfg.block_count) {
case 4:
if (strcmp(tx_data4, rx_data4) != 0)
return -1;
printk("%s\n", rx_data4);

case 3:
if (strcmp(tx_data3, rx_data3) != 0)
return -1;
printk("%s\n", rx_data3);

case 2:
if (strcmp(tx_data2, rx_data2) != 0)
return -1;
printk("%s\n", rx_data2);

case 1:
if (strcmp(tx_data, rx_data) != 0)
return -1;
printk("%s\n", rx_data);
break;

default:
printk("Invalid block count %d\n", dma_cfg.block_count);
return -1;
}

return 0;
}

/* export test cases */
void dma_thread(void)
{
while (1) {
k_sem_take(&thread_sem, K_FOREVER);
if (test_task(0, 8, 2) == 0) {
printk("DMA Passed\n");
} else {
printk("DMA Failed\n");
}
k_sem_give(&thread_sem);
k_sleep(SLEEPTIME);

k_sem_take(&thread_sem, K_FOREVER);
if (test_task(1, 8, 3) == 0) {
printk("DMA Passed\n");
} else {
printk("DMA Failed\n");
}
k_sem_give(&thread_sem);
k_sleep(SLEEPTIME);

k_sem_take(&thread_sem, K_FOREVER);
if (test_task(0, 16, 4) == 0) {
printk("DMA Passed\n");
} else {
printk("DMA Failed\n");
}
k_sem_give(&thread_sem);
k_sleep(SLEEPTIME);

k_sem_take(&thread_sem, K_FOREVER);
if (test_task(1, 16, 1) == 0) {
printk("DMA Passed\n");
} else {
printk("DMA Failed\n");
}
k_sem_give(&thread_sem);
k_sleep(SLEEPTIME);
}
}

K_THREAD_DEFINE(dma_thread_id, STACKSIZE, dma_thread, NULL, NULL, NULL,
PRIORITY, 0, K_NO_WAIT);

0 comments on commit cea1c75

Please sign in to comment.