zephyr/drivers/dma/dma_intel_lpss.c

173 lines
4.4 KiB
C

/*
* Copyright (c) 2023 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT intel_lpss
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/dma/dma_intel_lpss.h>
#include "dma_dw_common.h"
#include <soc.h>
#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
LOG_MODULE_REGISTER(dma_intel_lpss, CONFIG_DMA_LOG_LEVEL);
struct dma_intel_lpss_cfg {
struct dw_dma_dev_cfg dw_cfg;
};
int dma_intel_lpss_setup(const struct device *dev)
{
struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config;
if (dev_cfg->dw_cfg.base != 0) {
return dw_dma_setup(dev);
}
return 0;
}
void dma_intel_lpss_set_base(const struct device *dev, uintptr_t base)
{
struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config;
dev_cfg->dw_cfg.base = base;
}
#ifdef CONFIG_DMA_64BIT
int dma_intel_lpss_reload(const struct device *dev, uint32_t channel,
uint64_t src, uint64_t dst, size_t size)
#else
int dma_intel_lpss_reload(const struct device *dev, uint32_t channel,
uint32_t src, uint32_t dst, size_t size)
#endif
{
struct dw_dma_dev_data *const dev_data = dev->data;
struct dma_intel_lpss_cfg *lpss_dev_cfg = (struct dma_intel_lpss_cfg *)dev->config;
struct dw_dma_dev_cfg *const dev_cfg = &lpss_dev_cfg->dw_cfg;
struct dw_dma_chan_data *chan_data;
uint32_t ctrl_hi = 0;
if (channel >= DW_CHAN_COUNT) {
return -EINVAL;
}
chan_data = &dev_data->chan[channel];
chan_data->lli_current->sar = src;
chan_data->lli_current->dar = dst;
chan_data->ptr_data.current_ptr = dst;
chan_data->ptr_data.buffer_bytes = size;
ctrl_hi = dw_read(dev_cfg->base, DW_CTRL_HIGH(channel));
ctrl_hi &= ~(DW_CTLH_DONE(1) | DW_CTLH_BLOCK_TS_MASK);
ctrl_hi |= size & DW_CTLH_BLOCK_TS_MASK;
chan_data->lli_current->ctrl_hi = ctrl_hi;
chan_data->ptr_data.start_ptr = DW_DMA_LLI_ADDRESS(chan_data->lli_current,
chan_data->direction);
chan_data->ptr_data.end_ptr = chan_data->ptr_data.start_ptr +
chan_data->ptr_data.buffer_bytes;
chan_data->ptr_data.hw_ptr = chan_data->ptr_data.start_ptr;
chan_data->state = DW_DMA_PREPARED;
return 0;
}
int dma_intel_lpss_get_status(const struct device *dev, uint32_t channel,
struct dma_status *stat)
{
struct dma_intel_lpss_cfg *lpss_dev_cfg = (struct dma_intel_lpss_cfg *)dev->config;
struct dw_dma_dev_cfg *const dev_cfg = &lpss_dev_cfg->dw_cfg;
struct dw_dma_dev_data *const dev_data = dev->data;
struct dw_dma_chan_data *chan_data;
uint32_t ctrl_hi;
size_t current_length;
bool done;
if (channel >= DW_CHAN_COUNT) {
return -EINVAL;
}
chan_data = &dev_data->chan[channel];
ctrl_hi = dw_read(dev_cfg->base, DW_CTRL_HIGH(channel));
current_length = ctrl_hi & DW_CTLH_BLOCK_TS_MASK;
done = ctrl_hi & DW_CTLH_DONE(1);
if (!(dw_read(dev_cfg->base, DW_DMA_CHAN_EN) & DW_CHAN(channel))) {
stat->busy = false;
stat->pending_length = chan_data->ptr_data.buffer_bytes;
return 0;
}
stat->busy = true;
if (done) {
stat->pending_length = 0;
} else if (current_length == chan_data->ptr_data.buffer_bytes) {
stat->pending_length = chan_data->ptr_data.buffer_bytes;
} else {
stat->pending_length =
chan_data->ptr_data.buffer_bytes - current_length;
}
return 0;
}
void dma_intel_lpss_isr(const struct device *dev)
{
dw_dma_isr(dev);
}
static const struct dma_driver_api dma_intel_lpss_driver_api = {
.config = dw_dma_config,
.start = dw_dma_start,
.reload = dma_intel_lpss_reload,
.get_status = dma_intel_lpss_get_status,
.stop = dw_dma_stop,
};
#define DMA_INTEL_LPSS_INIT(n) \
\
static struct dw_drv_plat_data dma_intel_lpss##n = { \
.chan[0] = { \
.class = 6, \
.weight = 0, \
}, \
.chan[1] = { \
.class = 6, \
.weight = 0, \
}, \
}; \
\
\
static struct dma_intel_lpss_cfg dma_intel_lpss##n##_config = { \
.dw_cfg = { \
.base = 0, \
}, \
}; \
\
static struct dw_dma_dev_data dma_intel_lpss##n##_data = { \
.channel_data = &dma_intel_lpss##n, \
}; \
\
DEVICE_DT_INST_DEFINE(n, \
NULL, \
NULL, \
&dma_intel_lpss##n##_data, \
&dma_intel_lpss##n##_config, PRE_KERNEL_1, \
CONFIG_DMA_INIT_PRIORITY, \
&dma_intel_lpss_driver_api); \
DT_INST_FOREACH_STATUS_OKAY(DMA_INTEL_LPSS_INIT)