diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index d73d0a87e0..8b91184cc2 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -23,6 +23,7 @@ zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_ADSP_HDA_HOST_OUT dma_intel_adsp_h zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_ADSP_HDA_LINK_IN dma_intel_adsp_hda_link_in.c) zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_ADSP_HDA_LINK_OUT dma_intel_adsp_hda_link_out.c) zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_ADSP_GPDMA dma_intel_adsp_gpdma.c dma_dw_common.c) +zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_LPSS dma_intel_lpss.c dma_dw_common.c) zephyr_library_sources_ifdef(CONFIG_DMA_GD32 dma_gd32.c) zephyr_library_sources_ifdef(CONFIG_DMA_ESP32 dma_esp32_gdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCHP_XEC dma_mchp_xec.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index ad0df00b2c..d88d2bbd83 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -58,4 +58,5 @@ source "drivers/dma/Kconfig.xmc4xxx" source "drivers/dma/Kconfig.rpi_pico" +source "drivers/dma/Kconfig.intel_lpss" endif # DMA diff --git a/drivers/dma/Kconfig.dw_common b/drivers/dma/Kconfig.dw_common index c522b7cc70..8b81d4ad3b 100644 --- a/drivers/dma/Kconfig.dw_common +++ b/drivers/dma/Kconfig.dw_common @@ -38,3 +38,9 @@ config DMA_DW_HOST_MASK help Some instances of the DesignWare DMAC require a mask applied to source/destination addresses to signifiy the memory space the address is in. + +config DMA_DW_CHANNEL_COUNT + int "dw max channel count" + default 8 + help + Channel count for designware DMA instances. diff --git a/drivers/dma/Kconfig.intel_lpss b/drivers/dma/Kconfig.intel_lpss new file mode 100644 index 0000000000..d475c74278 --- /dev/null +++ b/drivers/dma/Kconfig.intel_lpss @@ -0,0 +1,17 @@ +# LPSS DMA configuration options + +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config DMA_INTEL_LPSS + bool "INTEL LPSS DMA driver" + default n + depends on DT_HAS_INTEL_LPSS_ENABLED + help + INTEL LPSS DMA driver. + +if DMA_INTEL_LPSS + +source "drivers/dma/Kconfig.dw_common" + +endif # DMA_INTEL_LPSS diff --git a/drivers/dma/dma_dw_common.c b/drivers/dma/dma_dw_common.c index dd389f9663..e3210658df 100644 --- a/drivers/dma/dma_dw_common.c +++ b/drivers/dma/dma_dw_common.c @@ -132,7 +132,7 @@ int dw_dma_config(const struct device *dev, uint32_t channel, uint32_t msize = 3;/* default msize, 8 bytes */ int ret = 0; - if (channel >= DW_MAX_CHAN) { + if (channel >= DW_CHAN_COUNT) { LOG_ERR("%s: invalid dma channel %d", __func__, channel); ret = -EINVAL; goto out; @@ -444,7 +444,7 @@ int dw_dma_start(const struct device *dev, uint32_t channel) int ret = 0; /* validate channel */ - if (channel >= DW_MAX_CHAN) { + if (channel >= DW_CHAN_COUNT) { ret = -EINVAL; goto out; } @@ -492,10 +492,10 @@ int dw_dma_start(const struct device *dev, uint32_t channel) /* channel needs to start from scratch, so write SAR and DAR */ #ifdef CONFIG_DMA_64BIT - dw_write(dev_cfg->base, DW_SAR(channel), (uint32_t)(lli->sar & BIT_MASK(32))); - dw_write(dev_cfg->base, DW_SAR_HI(channel), (uint32_t)(lli->sar >> 32)); - dw_write(dev_cfg->base, DW_DAR(channel), (uint32_t)(lli->dar & BIT_MASK(32))); - dw_write(dev_cfg->base, DW_DAR_HI(channel), (uint32_t)(lli->dar >> 32)); + dw_write(dev_cfg->base, DW_SAR(channel), (uint32_t)(lli->sar & DW_ADDR_MASK_32)); + dw_write(dev_cfg->base, DW_SAR_HI(channel), (uint32_t)(lli->sar >> DW_ADDR_RIGHT_SHIFT)); + dw_write(dev_cfg->base, DW_DAR(channel), (uint32_t)(lli->dar & DW_ADDR_MASK_32)); + dw_write(dev_cfg->base, DW_DAR_HI(channel), (uint32_t)(lli->dar >> DW_ADDR_RIGHT_SHIFT)); #else dw_write(dev_cfg->base, DW_SAR(channel), lli->sar); dw_write(dev_cfg->base, DW_DAR(channel), lli->dar); @@ -548,7 +548,7 @@ int dw_dma_stop(const struct device *dev, uint32_t channel) struct dw_dma_chan_data *chan_data = &dev_data->chan[channel]; int ret = 0; - if (channel >= DW_MAX_CHAN) { + if (channel >= DW_CHAN_COUNT) { ret = -EINVAL; goto out; } @@ -617,7 +617,7 @@ int dw_dma_resume(const struct device *dev, uint32_t channel) int ret = 0; /* Validate channel index */ - if (channel >= DW_MAX_CHAN) { + if (channel >= DW_CHAN_COUNT) { ret = -EINVAL; goto out; } @@ -649,7 +649,7 @@ int dw_dma_suspend(const struct device *dev, uint32_t channel) int ret = 0; /* Validate channel index */ - if (channel >= DW_MAX_CHAN) { + if (channel >= DW_CHAN_COUNT) { ret = -EINVAL; goto out; } @@ -704,7 +704,7 @@ int dw_dma_setup(const struct device *dev) LOG_DBG("%s: dma %s", __func__, dev->name); - for (i = 0; i < DW_MAX_CHAN; i++) { + for (i = 0; i < DW_CHAN_COUNT; i++) { dw_read(dev_cfg->base, DW_DMA_CHAN_EN); } diff --git a/drivers/dma/dma_dw_common.h b/drivers/dma/dma_dw_common.h index 56d70686fb..5d61911e6d 100644 --- a/drivers/dma/dma_dw_common.h +++ b/drivers/dma/dma_dw_common.h @@ -21,8 +21,11 @@ extern "C" { (((x) & ((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL)) << (b_lo)) #define DW_MAX_CHAN 8 +#define DW_CHAN_COUNT CONFIG_DMA_DW_CHANNEL_COUNT #define DW_CH_SIZE 0x58 #define DW_CHAN_OFFSET(chan) (DW_CH_SIZE * chan) +#define DW_ADDR_MASK_32 BIT_MASK(32) +#define DW_ADDR_RIGHT_SHIFT 32 #define DW_SAR(chan) \ (0x0000 + DW_CHAN_OFFSET(chan)) @@ -176,7 +179,7 @@ struct dw_chan_arbit_data { }; struct dw_drv_plat_data { - struct dw_chan_arbit_data chan[DW_MAX_CHAN]; + struct dw_chan_arbit_data chan[DW_CHAN_COUNT]; }; /* DMA descriptor used by HW */ @@ -187,6 +190,7 @@ struct dw_lli { #else uint32_t sar; uint32_t dar; +#endif uint32_t llp; uint32_t ctrl_lo; uint32_t ctrl_hi; @@ -242,10 +246,10 @@ static const uint32_t burst_elems[] = {1, 2, 4, 8}; struct dw_dma_dev_data { struct dma_context dma_ctx; struct dw_drv_plat_data *channel_data; - struct dw_dma_chan_data chan[DW_MAX_CHAN]; - struct dw_lli lli_pool[DW_MAX_CHAN][CONFIG_DMA_DW_LLI_POOL_SIZE] __aligned(64); + struct dw_dma_chan_data chan[DW_CHAN_COUNT]; + struct dw_lli lli_pool[DW_CHAN_COUNT][CONFIG_DMA_DW_LLI_POOL_SIZE] __aligned(64); - ATOMIC_DEFINE(channels_atomic, DW_MAX_CHAN); + ATOMIC_DEFINE(channels_atomic, DW_CHAN_COUNT); }; /* Device constant configuration parameters */ diff --git a/drivers/dma/dma_intel_lpss.c b/drivers/dma/dma_intel_lpss.c new file mode 100644 index 0000000000..c1ae1763e5 --- /dev/null +++ b/drivers/dma/dma_intel_lpss.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT intel_lpss + +#include + +#include +#include +#include +#include +#include +#include +#include +#include "dma_dw_common.h" +#include + +#include +#include +LOG_MODULE_REGISTER(dma_intel_lpss, CONFIG_DMA_LOG_LEVEL); + +struct dma_intel_lpss_cfg { + struct dw_dma_dev_cfg dw_cfg; + const struct device *parent; +}; + +static int dma_intel_lpss_init(const struct device *dev) +{ + struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; + uint32_t base; + int ret; + + if (!device_is_ready(dev_cfg->parent)) { + LOG_ERR("LPSS DMA parent not ready"); + ret = -ENODEV; + goto out; + } + + base = DEVICE_MMIO_GET(dev_cfg->parent) + DMA_INTEL_LPSS_OFFSET; + dev_cfg->dw_cfg.base = base; + + ret = dw_dma_setup(dev); + + if (ret != 0) { + LOG_ERR("failed to initialize LPSS DMA %s", dev->name); + goto out; + } + ret = 0; +out: + return ret; +} + +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, + .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, \ + }, \ + .parent = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + }; \ + \ + static struct dw_dma_dev_data dma_intel_lpss##n##_data = { \ + .channel_data = &dma_intel_lpss##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + &dma_intel_lpss_init, \ + NULL, \ + &dma_intel_lpss##n##_data, \ + &dma_intel_lpss##n##_config, POST_KERNEL, \ + DMA_INTEL_LPSS_INIT_PRIORITY, \ + &dma_intel_lpss_driver_api); \ + +DT_INST_FOREACH_STATUS_OKAY(DMA_INTEL_LPSS_INIT) diff --git a/dts/bindings/dma/intel,lpss.yaml b/dts/bindings/dma/intel,lpss.yaml new file mode 100644 index 0000000000..d9fc4a60f1 --- /dev/null +++ b/dts/bindings/dma/intel,lpss.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: LPSS DMA Controller node + +compatible: "intel,lpss" + +include: dma-controller.yaml + +properties: + "#dma-cells": + const: 1 + +dma-cells: + - channel diff --git a/include/zephyr/drivers/dma/dma_intel_lpss.h b/include/zephyr/drivers/dma/dma_intel_lpss.h new file mode 100644 index 0000000000..c3cf3bef81 --- /dev/null +++ b/include/zephyr/drivers/dma/dma_intel_lpss.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ +#define ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ + +#define DMA_INTEL_LPSS_INIT_PRIORITY 80 +#define DMA_INTEL_LPSS_OFFSET 0x800 +#define DMA_INTEL_LPSS_REMAP_LOW 0x240 +#define DMA_INTEL_LPSS_REMAP_HI 0x244 +#define DMA_INTEL_LPSS_TX_CHAN 0 +#define DMA_INTEL_LPSS_RX_CHAN 1 +#define DMA_INTEL_LPSS_ADDR_RIGHT_SHIFT 32 + +void dma_intel_lpss_isr(const struct device *dev); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ */