mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-09 17:11:42 +00:00
mec1322: DMA driver
This implements the DMA driver using the same DMA interface we are using now. BUG=chrome-os-partner:29805 TEST=Along with the following SPI driver, read manufacturer ID from SPI flash. BRANCH=None Change-Id: Ife3c0c8b414568ff1cab7d072901ba2d11142a17 Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/205067 Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
a56f966556
commit
598c92b2cc
@@ -20,3 +20,4 @@ chip-$(CONFIG_LPC)+=lpc.o
|
||||
chip-$(CONFIG_PWM)+=pwm.o
|
||||
chip-$(CONFIG_WATCHDOG)+=watchdog.o
|
||||
chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
|
||||
chip-$(CONFIG_DMA)+=dma.o
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
#define CONFIG_I2C
|
||||
#define CONFIG_LPC
|
||||
#define CONFIG_FPU
|
||||
#define CONFIG_DMA
|
||||
|
||||
#undef CONFIG_FLASH
|
||||
|
||||
|
||||
129
chip/mec1322/dma.c
Normal file
129
chip/mec1322/dma.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "dma.h"
|
||||
#include "hooks.h"
|
||||
#include "registers.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPUTS(outstr) cputs(CC_DMA, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_DMA, format, ## args)
|
||||
|
||||
mec1322_dma_chan_t *dma_get_channel(enum dma_channel channel)
|
||||
{
|
||||
mec1322_dma_regs_t *dma = MEC1322_DMA_REGS;
|
||||
|
||||
return &dma->chan[channel];
|
||||
}
|
||||
|
||||
void dma_disable(enum dma_channel channel)
|
||||
{
|
||||
mec1322_dma_chan_t *chan = dma_get_channel(channel);
|
||||
|
||||
if (chan->ctrl & (1 << 0))
|
||||
chan->ctrl &= ~(1 << 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a channel for use and start it
|
||||
*
|
||||
* @param chan Channel to read
|
||||
* @param count Number of bytes to transfer
|
||||
* @param periph Pointer to peripheral data register
|
||||
* @param memory Pointer to memory address for receive/transmit
|
||||
* @param flags DMA flags for the control register, normally:
|
||||
* MEC1322_DMA_INC_MEM | MEC1322_DMA_TO_DEV for tx
|
||||
* MEC1322_DMA_INC_MEM for rx
|
||||
*/
|
||||
static void prepare_channel(mec1322_dma_chan_t *chan, unsigned count,
|
||||
void *periph, void *memory, unsigned flags)
|
||||
{
|
||||
int xfer_size = (flags >> 20) & 0x7;
|
||||
|
||||
if (chan->ctrl & (1 << 0))
|
||||
chan->ctrl &= ~(1 << 0);
|
||||
|
||||
chan->act |= 0x1;
|
||||
chan->dev = (uint32_t)periph;
|
||||
chan->mem_start = MEC1322_RAM_ALIAS((uint32_t)memory);
|
||||
chan->mem_end = MEC1322_RAM_ALIAS((uint32_t)memory) + xfer_size * count;
|
||||
chan->ctrl = flags;
|
||||
}
|
||||
|
||||
void dma_go(mec1322_dma_chan_t *chan)
|
||||
{
|
||||
/* Flush data in write buffer so that DMA can get the lastest data */
|
||||
asm volatile("dsb;");
|
||||
|
||||
/* Fire it up */
|
||||
chan->ctrl |= MEC1322_DMA_RUN;
|
||||
}
|
||||
|
||||
void dma_prepare_tx(const struct dma_option *option, unsigned count,
|
||||
const void *memory)
|
||||
{
|
||||
mec1322_dma_chan_t *chan = dma_get_channel(option->channel);
|
||||
|
||||
/*
|
||||
* Cast away const for memory pointer; this is ok because we know
|
||||
* we're preparing the channel for transmit.
|
||||
*/
|
||||
prepare_channel(chan, count, option->periph, (void *)memory,
|
||||
MEC1322_DMA_INC_MEM | MEC1322_DMA_TO_DEV |
|
||||
MEC1322_DMA_DEV(option->channel) | option->flags);
|
||||
}
|
||||
|
||||
void dma_start_rx(const struct dma_option *option, unsigned count,
|
||||
void *memory)
|
||||
{
|
||||
mec1322_dma_chan_t *chan = dma_get_channel(option->channel);
|
||||
|
||||
prepare_channel(chan, count, option->periph, memory,
|
||||
MEC1322_DMA_INC_MEM | MEC1322_DMA_DEV(option->channel) |
|
||||
option->flags);
|
||||
dma_go(chan);
|
||||
}
|
||||
|
||||
int dma_bytes_done(mec1322_dma_chan_t *chan, int orig_count)
|
||||
{
|
||||
int xfer_size = (chan->ctrl >> 20) & 0x7;
|
||||
|
||||
if (!(chan->ctrl & MEC1322_DMA_RUN))
|
||||
return 0;
|
||||
return orig_count - (chan->mem_end - chan->mem_start) / xfer_size;
|
||||
}
|
||||
|
||||
void dma_init(void)
|
||||
{
|
||||
mec1322_dma_regs_t *dma = MEC1322_DMA_REGS;
|
||||
dma->ctrl |= 0x1;
|
||||
}
|
||||
|
||||
int dma_wait(enum dma_channel channel)
|
||||
{
|
||||
mec1322_dma_chan_t *chan = dma_get_channel(channel);
|
||||
timestamp_t deadline;
|
||||
|
||||
deadline.val = get_time().val + DMA_TRANSFER_TIMEOUT_US;
|
||||
while (!(chan->int_status & 0x4)) {
|
||||
if (deadline.val <= get_time().val)
|
||||
return EC_ERROR_TIMEOUT;
|
||||
|
||||
udelay(DMA_POLLING_INTERVAL_US);
|
||||
}
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
void dma_clear_isr(enum dma_channel channel)
|
||||
{
|
||||
mec1322_dma_chan_t *chan = dma_get_channel(channel);
|
||||
|
||||
chan->int_status |= 0x4;
|
||||
}
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* Helper function for RAM address aliasing */
|
||||
#define MEC1322_RAM_ALIAS(x) \
|
||||
((x) >= 0x118000 ? (x) - 0x118000 + 0x20000000 : (x))
|
||||
|
||||
/* EC Chip Configuration */
|
||||
#define MEC1322_CHIP_BASE 0x400fff00
|
||||
#define MEC1322_CHIP_DEV_ID REG8(MEC1322_CHIP_BASE + 0x20)
|
||||
@@ -293,6 +297,77 @@ static inline uintptr_t gpio_port_base(int port_id)
|
||||
#define MEC1322_HTIMER_COUNT REG16(MEC1322_HTIMER_BASE + 0x8)
|
||||
|
||||
|
||||
/* DMA */
|
||||
#define MEC1322_DMA_BASE 0x40002400
|
||||
|
||||
/*
|
||||
* Available DMA channels.
|
||||
*
|
||||
* On MEC1322, any DMA channel may serve any device. Since we have
|
||||
* 12 channels and 12 devices, we make each channel dedicated to the
|
||||
* device of the same number.
|
||||
*/
|
||||
enum dma_channel {
|
||||
/* Channel numbers */
|
||||
MEC1322_DMAC_I2C0_SLAVE = 0,
|
||||
MEC1322_DMAC_I2C0_MASTER = 1,
|
||||
MEC1322_DMAC_I2C1_SLAVE = 2,
|
||||
MEC1322_DMAC_I2C1_MASTER = 3,
|
||||
MEC1322_DMAC_I2C2_SLAVE = 4,
|
||||
MEC1322_DMAC_I2C2_MASTER = 5,
|
||||
MEC1322_DMAC_I2C3_SLAVE = 6,
|
||||
MEC1322_DMAC_I2C3_MASTER = 7,
|
||||
MEC1322_DMAC_SPI0_TX = 8,
|
||||
MEC1322_DMAC_SPI0_RX = 9,
|
||||
MEC1322_DMAC_SPI1_TX = 10,
|
||||
MEC1322_DMAC_SPI1_RX = 11,
|
||||
|
||||
/* Channel count */
|
||||
MEC1322_DMAC_COUNT = 12,
|
||||
};
|
||||
|
||||
/* Registers for a single channel of the DMA controller */
|
||||
struct mec1322_dma_chan {
|
||||
uint32_t act; /* Activate */
|
||||
uint32_t mem_start; /* Memory start address */
|
||||
uint32_t mem_end; /* Memory end address */
|
||||
uint32_t dev; /* Device address */
|
||||
uint32_t ctrl; /* Control */
|
||||
uint32_t int_status; /* Interrupt status */
|
||||
uint32_t int_enabled; /* Interrupt enabled */
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
/* Always use mec1322_dma_chan_t so volatile keyword is included! */
|
||||
typedef volatile struct mec1322_dma_chan mec1322_dma_chan_t;
|
||||
|
||||
/* Common code and header file must use this */
|
||||
typedef mec1322_dma_chan_t dma_chan_t;
|
||||
|
||||
/* Registers for the DMA controller */
|
||||
struct mec1322_dma_regs {
|
||||
uint32_t ctrl;
|
||||
uint32_t data;
|
||||
uint32_t pad[2];
|
||||
mec1322_dma_chan_t chan[MEC1322_DMAC_COUNT];
|
||||
};
|
||||
|
||||
/* Always use mec1322_dma_regs_t so volatile keyword is included! */
|
||||
typedef volatile struct mec1322_dma_regs mec1322_dma_regs_t;
|
||||
|
||||
#define MEC1322_DMA_REGS ((mec1322_dma_regs_t *)MEC1322_DMA_BASE)
|
||||
|
||||
/* Bits for DMA channel regs */
|
||||
#define MEC1322_DMA_ACT_EN (1 << 0)
|
||||
#define MEC1322_DMA_XFER_SIZE(x) ((x) << 20)
|
||||
#define MEC1322_DMA_INC_DEV (1 << 17)
|
||||
#define MEC1322_DMA_INC_MEM (1 << 16)
|
||||
#define MEC1322_DMA_DEV(x) ((x) << 9)
|
||||
#define MEC1322_DMA_TO_DEV (1 << 8)
|
||||
#define MEC1322_DMA_DONE (1 << 2)
|
||||
#define MEC1322_DMA_RUN (1 << 0)
|
||||
|
||||
|
||||
/* IRQ Numbers */
|
||||
#define MEC1322_IRQ_I2C_0 0
|
||||
#define MEC1322_IRQ_I2C_1 1
|
||||
|
||||
Reference in New Issue
Block a user