From baa914cd81f51f4e4f3bae5bb59764b32ad8c353 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 5 Apr 2022 16:22:20 +0900 Subject: firewire: add kernel API to access CYCLE_TIME register 1394 OHCI specification defined Isochronous Cycle Timer Register to get value of CYCLE_TIME register defined by IEEE 1394 for CSR architecture defined by ISO/IEC 13213. Unit driver can calculate packet time by compute with the value of CYCLE_TIME and timeStamp field in descriptor of each isochronous and asynchronous context. The resolution of CYCLE_TIME is 49.576 MHz, while the one of timeStamp is 8,000 Hz. Current implementation of Linux FireWire subsystem allows the driver to get the value of CYCLE_TIMER CSR register by transaction service. The transaction service has overhead in regard of access to MMIO register. This commit adds kernel API for unit driver to access the register directly. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20220405072221.226217-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- include/linux/firewire.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 07967a450eaa..2f467c52bdec 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -150,6 +150,8 @@ static inline void fw_card_put(struct fw_card *card) kref_put(&card->kref, fw_card_release); } +int fw_card_read_cycle_time(struct fw_card *card, u32 *cycle_time); + struct fw_attribute_group { struct attribute_group *groups[2]; struct attribute_group group; -- cgit v1.2.3-59-g8ed1b From b2405aa948b95afc5246fa56fc05c3512cd6185c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 5 Apr 2022 16:22:21 +0900 Subject: firewire: add kernel API to access packet structure in request structure for AR context In 1394 OHCI specification, descriptor of Asynchronous Receive DMA context has timeStamp field in its trailer quadlet. The field is written by the host controller for the time to receive asynchronous request subaction in isochronous cycle time. In Linux FireWire subsystem, the value of field is stored to fw_packet structure and copied to fw_request structure as the part. The fw_request structure is hidden from unit driver and passed as opaque pointer when calling registered handler. It's inconvenient to the unit driver which needs timestamp of packet. This commit adds kernel API to pick up timestamp from opaque pointer to fw_request structure. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20220405072221.226217-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- drivers/firewire/core-transaction.c | 18 ++++++++++++++++++ include/linux/firewire.h | 1 + 2 files changed, 19 insertions(+) (limited to 'include/linux') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index ac487c96bb71..e12a0a4c33f7 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -619,6 +619,7 @@ struct fw_request { struct fw_packet response; u32 request_header[4]; int ack; + u32 timestamp; u32 length; u32 data[]; }; @@ -788,6 +789,7 @@ static struct fw_request *allocate_request(struct fw_card *card, request->response.ack = 0; request->response.callback = free_response_callback; request->ack = p->ack; + request->timestamp = p->timestamp; request->length = length; if (data) memcpy(request->data, data, length); @@ -832,6 +834,22 @@ int fw_get_request_speed(struct fw_request *request) } EXPORT_SYMBOL(fw_get_request_speed); +/** + * fw_request_get_timestamp: Get timestamp of the request. + * @request: The opaque pointer to request structure. + * + * Get timestamp when 1394 OHCI controller receives the asynchronous request subaction. The + * timestamp consists of the low order 3 bits of second field and the full 13 bits of count + * field of isochronous cycle time register. + * + * Returns: timestamp of the request. + */ +u32 fw_request_get_timestamp(const struct fw_request *request) +{ + return request->timestamp; +} +EXPORT_SYMBOL_GPL(fw_request_get_timestamp); + static void handle_exclusive_region_request(struct fw_card *card, struct fw_packet *p, struct fw_request *request, diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 2f467c52bdec..980019053e54 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -354,6 +354,7 @@ void fw_core_remove_address_handler(struct fw_address_handler *handler); void fw_send_response(struct fw_card *card, struct fw_request *request, int rcode); int fw_get_request_speed(struct fw_request *request); +u32 fw_request_get_timestamp(const struct fw_request *request); void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, int destination_id, int generation, int speed, unsigned long long offset, void *payload, size_t length, -- cgit v1.2.3-59-g8ed1b From c6547c2ed0e1487c91983faccad841611ab6a783 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 14 Apr 2022 18:22:37 +0200 Subject: dmaengine: imx: Move header to include/dma/ The i.MX DMA drivers are device tree only, nothing in include/linux/platform_data/dma-imx.h has platform_data in it, so move the file to include/linux/dma/imx-dma.h. Signed-off-by: Sascha Hauer Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20220414162249.3934543-10-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- drivers/dma/imx-dma.c | 2 +- drivers/dma/imx-sdma.c | 2 +- drivers/mmc/host/mxcmmc.c | 2 +- drivers/spi/spi-fsl-lpspi.c | 2 +- drivers/spi/spi-imx.c | 2 +- drivers/tty/serial/imx.c | 2 +- drivers/video/fbdev/mx3fb.c | 2 +- include/linux/dma/imx-dma.h | 68 +++++++++++++++++++++++++++++++++++ include/linux/platform_data/dma-imx.h | 68 ----------------------------------- sound/soc/fsl/fsl_asrc.c | 2 +- sound/soc/fsl/fsl_asrc_dma.c | 2 +- sound/soc/fsl/fsl_easrc.h | 2 +- sound/soc/fsl/imx-pcm.h | 2 +- sound/soc/fsl/imx-ssi.h | 2 +- 14 files changed, 80 insertions(+), 80 deletions(-) create mode 100644 include/linux/dma/imx-dma.h delete mode 100644 include/linux/platform_data/dma-imx.h (limited to 'include/linux') diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 2ddc31e64db0..3bffe3ecbd1b 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include "dmaengine.h" #define IMXDMA_MAX_CHAN_DESCRIPTORS 16 diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 70c0aa931ddf..80261a905eb5 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 40b6878bea6c..de04b5afef2e 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -39,7 +39,7 @@ #include #include -#include +#include #define DRIVER_NAME "mxc-mmc" #define MXCMCI_TIMEOUT_MS 10000 diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 4c601294f8fa..19b1f3d881b0 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index b2dd0a4d2446..a944c787f53f 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -24,7 +24,7 @@ #include #include -#include +#include #define DRIVER_NAME "spi_imx" diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index fd38e6ed4fda..f8b5400e6267 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "serial_mctrl_gpio.h" diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c index fabb271337ed..b945b68984b9 100644 --- a/drivers/video/fbdev/mx3fb.c +++ b/drivers/video/fbdev/mx3fb.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include diff --git a/include/linux/dma/imx-dma.h b/include/linux/dma/imx-dma.h new file mode 100644 index 000000000000..b06cba85a6d4 --- /dev/null +++ b/include/linux/dma/imx-dma.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +#ifndef __LINUX_DMA_IMX_H +#define __LINUX_DMA_IMX_H + +#include +#include +#include + +/* + * This enumerates peripheral types. Used for SDMA. + */ +enum sdma_peripheral_type { + IMX_DMATYPE_SSI, /* MCU domain SSI */ + IMX_DMATYPE_SSI_SP, /* Shared SSI */ + IMX_DMATYPE_MMC, /* MMC */ + IMX_DMATYPE_SDHC, /* SDHC */ + IMX_DMATYPE_UART, /* MCU domain UART */ + IMX_DMATYPE_UART_SP, /* Shared UART */ + IMX_DMATYPE_FIRI, /* FIRI */ + IMX_DMATYPE_CSPI, /* MCU domain CSPI */ + IMX_DMATYPE_CSPI_SP, /* Shared CSPI */ + IMX_DMATYPE_SIM, /* SIM */ + IMX_DMATYPE_ATA, /* ATA */ + IMX_DMATYPE_CCM, /* CCM */ + IMX_DMATYPE_EXT, /* External peripheral */ + IMX_DMATYPE_MSHC, /* Memory Stick Host Controller */ + IMX_DMATYPE_MSHC_SP, /* Shared Memory Stick Host Controller */ + IMX_DMATYPE_DSP, /* DSP */ + IMX_DMATYPE_MEMORY, /* Memory */ + IMX_DMATYPE_FIFO_MEMORY,/* FIFO type Memory */ + IMX_DMATYPE_SPDIF, /* SPDIF */ + IMX_DMATYPE_IPU_MEMORY, /* IPU Memory */ + IMX_DMATYPE_ASRC, /* ASRC */ + IMX_DMATYPE_ESAI, /* ESAI */ + IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ + IMX_DMATYPE_ASRC_SP, /* Shared ASRC */ + IMX_DMATYPE_SAI, /* SAI */ +}; + +enum imx_dma_prio { + DMA_PRIO_HIGH = 0, + DMA_PRIO_MEDIUM = 1, + DMA_PRIO_LOW = 2 +}; + +struct imx_dma_data { + int dma_request; /* DMA request line */ + int dma_request2; /* secondary DMA request line */ + enum sdma_peripheral_type peripheral_type; + int priority; +}; + +static inline int imx_dma_is_ipu(struct dma_chan *chan) +{ + return !strcmp(dev_name(chan->device->dev), "ipu-core"); +} + +static inline int imx_dma_is_general_purpose(struct dma_chan *chan) +{ + return !strcmp(chan->device->dev->driver->name, "imx-sdma") || + !strcmp(chan->device->dev->driver->name, "imx-dma"); +} + +#endif /* __LINUX_DMA_IMX_H */ diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h deleted file mode 100644 index 281adbb26e6b..000000000000 --- a/include/linux/platform_data/dma-imx.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. - */ - -#ifndef __ASM_ARCH_MXC_DMA_H__ -#define __ASM_ARCH_MXC_DMA_H__ - -#include -#include -#include - -/* - * This enumerates peripheral types. Used for SDMA. - */ -enum sdma_peripheral_type { - IMX_DMATYPE_SSI, /* MCU domain SSI */ - IMX_DMATYPE_SSI_SP, /* Shared SSI */ - IMX_DMATYPE_MMC, /* MMC */ - IMX_DMATYPE_SDHC, /* SDHC */ - IMX_DMATYPE_UART, /* MCU domain UART */ - IMX_DMATYPE_UART_SP, /* Shared UART */ - IMX_DMATYPE_FIRI, /* FIRI */ - IMX_DMATYPE_CSPI, /* MCU domain CSPI */ - IMX_DMATYPE_CSPI_SP, /* Shared CSPI */ - IMX_DMATYPE_SIM, /* SIM */ - IMX_DMATYPE_ATA, /* ATA */ - IMX_DMATYPE_CCM, /* CCM */ - IMX_DMATYPE_EXT, /* External peripheral */ - IMX_DMATYPE_MSHC, /* Memory Stick Host Controller */ - IMX_DMATYPE_MSHC_SP, /* Shared Memory Stick Host Controller */ - IMX_DMATYPE_DSP, /* DSP */ - IMX_DMATYPE_MEMORY, /* Memory */ - IMX_DMATYPE_FIFO_MEMORY,/* FIFO type Memory */ - IMX_DMATYPE_SPDIF, /* SPDIF */ - IMX_DMATYPE_IPU_MEMORY, /* IPU Memory */ - IMX_DMATYPE_ASRC, /* ASRC */ - IMX_DMATYPE_ESAI, /* ESAI */ - IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ - IMX_DMATYPE_ASRC_SP, /* Shared ASRC */ - IMX_DMATYPE_SAI, /* SAI */ -}; - -enum imx_dma_prio { - DMA_PRIO_HIGH = 0, - DMA_PRIO_MEDIUM = 1, - DMA_PRIO_LOW = 2 -}; - -struct imx_dma_data { - int dma_request; /* DMA request line */ - int dma_request2; /* secondary DMA request line */ - enum sdma_peripheral_type peripheral_type; - int priority; -}; - -static inline int imx_dma_is_ipu(struct dma_chan *chan) -{ - return !strcmp(dev_name(chan->device->dev), "ipu-core"); -} - -static inline int imx_dma_is_general_purpose(struct dma_chan *chan) -{ - return !strcmp(chan->device->dev->driver->name, "imx-sdma") || - !strcmp(chan->device->dev->driver->name, "imx-dma"); -} - -#endif diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index d7d1536a4f37..ad4e6747b839 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index cd9b36ec0ecb..5038faf035cb 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h index 30620d56252c..86d5c360d4f5 100644 --- a/sound/soc/fsl/fsl_easrc.h +++ b/sound/soc/fsl/fsl_easrc.h @@ -7,7 +7,7 @@ #define _FSL_EASRC_H #include -#include +#include #include "fsl_asrc_common.h" diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 5c6cf1ca8c8a..06b25f4b26b6 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -9,7 +9,7 @@ #ifndef _IMX_PCM_H #define _IMX_PCM_H -#include +#include /* * Do not change this as the FIQ handler depends on this size diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h index 19cd0937e740..2d30d822451a 100644 --- a/sound/soc/fsl/imx-ssi.h +++ b/sound/soc/fsl/imx-ssi.h @@ -182,7 +182,7 @@ #define DRV_NAME "imx-ssi" #include -#include +#include #include #include "imx-pcm.h" -- cgit v1.2.3-59-g8ed1b From 824a0a02cd74776461aaa30d792b1ed9111c9aa5 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 14 Apr 2022 18:22:39 +0200 Subject: dmaengine: imx-sdma: Add multi fifo support The i.MX SDMA engine can read from / write to multiple successive hardware FIFO registers, referred to as "Multi FIFO support". This is needed for the micfil driver and certain configurations of the SAI driver. This patch adds support for this feature. The number of FIFOs to read from / write to must be communicated from the client driver to the SDMA engine. For this the struct dma_slave_config::peripheral_config field is used. Signed-off-by: Sascha Hauer Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20220414162249.3934543-12-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- drivers/dma/imx-sdma.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/dma/imx-dma.h | 20 ++++++++++++++++ 2 files changed, 77 insertions(+) (limited to 'include/linux') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 0e70843567ce..95367a8a81a5 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ #define SDMA_CHNENBL0_IMX35 0x200 #define SDMA_CHNENBL0_IMX31 0x080 #define SDMA_CHNPRI_0 0x100 +#define SDMA_DONE0_CONFIG 0x1000 /* * Buffer descriptor status values. @@ -180,6 +182,12 @@ BIT(DMA_MEM_TO_DEV) | \ BIT(DMA_DEV_TO_DEV)) +#define SDMA_WATERMARK_LEVEL_N_FIFOS GENMASK(15, 12) +#define SDMA_WATERMARK_LEVEL_SW_DONE BIT(23) + +#define SDMA_DONE0_CONFIG_DONE_SEL BIT(7) +#define SDMA_DONE0_CONFIG_DONE_DIS BIT(6) + /** * struct sdma_script_start_addrs - SDMA script start pointers * @@ -441,6 +449,9 @@ struct sdma_channel { struct work_struct terminate_worker; struct list_head terminated; bool is_ram_script; + unsigned int n_fifos_src; + unsigned int n_fifos_dst; + bool sw_done; }; #define IMX_DMA_SG_LOOP BIT(0) @@ -778,6 +789,14 @@ static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event) val = readl_relaxed(sdma->regs + chnenbl); __set_bit(channel, &val); writel_relaxed(val, sdma->regs + chnenbl); + + /* Set SDMA_DONEx_CONFIG is sw_done enabled */ + if (sdmac->sw_done) { + val = readl_relaxed(sdma->regs + SDMA_DONE0_CONFIG); + val |= SDMA_DONE0_CONFIG_DONE_SEL; + val &= ~SDMA_DONE0_CONFIG_DONE_DIS; + writel_relaxed(val, sdma->regs + SDMA_DONE0_CONFIG); + } } static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event) @@ -1038,6 +1057,10 @@ static int sdma_get_pc(struct sdma_channel *sdmac, case IMX_DMATYPE_IPU_MEMORY: emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; break; + case IMX_DMATYPE_MULTI_SAI: + per_2_emi = sdma->script_addrs->sai_2_mcu_addr; + emi_2_per = sdma->script_addrs->mcu_2_sai_addr; + break; default: dev_err(sdma->dev, "Unsupported transfer type %d\n", peripheral_type); @@ -1214,6 +1237,22 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac) sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT; } +static void sdma_set_watermarklevel_for_sais(struct sdma_channel *sdmac) +{ + unsigned int n_fifos; + + if (sdmac->sw_done) + sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SW_DONE; + + if (sdmac->direction == DMA_DEV_TO_MEM) + n_fifos = sdmac->n_fifos_src; + else + n_fifos = sdmac->n_fifos_dst; + + sdmac->watermark_level |= + FIELD_PREP(SDMA_WATERMARK_LEVEL_N_FIFOS, n_fifos); +} + static int sdma_config_channel(struct dma_chan *chan) { struct sdma_channel *sdmac = to_sdma_chan(chan); @@ -1250,6 +1289,10 @@ static int sdma_config_channel(struct dma_chan *chan) sdmac->peripheral_type == IMX_DMATYPE_ASRC) sdma_set_watermarklevel_for_p2p(sdmac); } else { + if (sdmac->peripheral_type == + IMX_DMATYPE_MULTI_SAI) + sdma_set_watermarklevel_for_sais(sdmac); + __set_bit(sdmac->event_id0, sdmac->event_mask); } @@ -1707,9 +1750,23 @@ static int sdma_config(struct dma_chan *chan, struct dma_slave_config *dmaengine_cfg) { struct sdma_channel *sdmac = to_sdma_chan(chan); + struct sdma_engine *sdma = sdmac->sdma; memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg)); + if (dmaengine_cfg->peripheral_config) { + struct sdma_peripheral_config *sdmacfg = dmaengine_cfg->peripheral_config; + if (dmaengine_cfg->peripheral_size != sizeof(struct sdma_peripheral_config)) { + dev_err(sdma->dev, "Invalid peripheral size %zu, expected %zu\n", + dmaengine_cfg->peripheral_size, + sizeof(struct sdma_peripheral_config)); + return -EINVAL; + } + sdmac->n_fifos_src = sdmacfg->n_fifos_src; + sdmac->n_fifos_dst = sdmacfg->n_fifos_dst; + sdmac->sw_done = sdmacfg->sw_done; + } + /* Set ENBLn earlier to make sure dma request triggered after that */ if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events) return -EINVAL; diff --git a/include/linux/dma/imx-dma.h b/include/linux/dma/imx-dma.h index b06cba85a6d4..8887762360d4 100644 --- a/include/linux/dma/imx-dma.h +++ b/include/linux/dma/imx-dma.h @@ -39,6 +39,7 @@ enum sdma_peripheral_type { IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ IMX_DMATYPE_ASRC_SP, /* Shared ASRC */ IMX_DMATYPE_SAI, /* SAI */ + IMX_DMATYPE_MULTI_SAI, /* MULTI FIFOs For Audio */ }; enum imx_dma_prio { @@ -65,4 +66,23 @@ static inline int imx_dma_is_general_purpose(struct dma_chan *chan) !strcmp(chan->device->dev->driver->name, "imx-dma"); } +/** + * struct sdma_peripheral_config - SDMA config for audio + * @n_fifos_src: Number of FIFOs for recording + * @n_fifos_dst: Number of FIFOs for playback + * @sw_done: Use software done. Needed for PDM (micfil) + * + * Some i.MX Audio devices (SAI, micfil) have multiple successive FIFO + * registers. For multichannel recording/playback the SAI/micfil have + * one FIFO register per channel and the SDMA engine has to read/write + * the next channel from/to the next register and wrap around to the + * first register when all channels are handled. The number of active + * channels must be communicated to the SDMA engine using this struct. + */ +struct sdma_peripheral_config { + int n_fifos_src; + int n_fifos_dst; + bool sw_done; +}; + #endif /* __LINUX_DMA_IMX_H */ -- cgit v1.2.3-59-g8ed1b From 430c3500995484962bdbccf358201afef8055535 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 25 Apr 2022 10:51:59 +0100 Subject: firmware: cirrus: cs_dsp: Avoid padding bytes in cs_dsp_coeff_ctl Change the order of members in struct cs_dsp_coeff_ctl to avoid the compiler having to insert alignment padding bytes. On a x86_64 build this saves 16 bytes per control. - Pointers are collected to the top of the struct (with the exception of priv, as noted below), so that they are inherently aligned. - The set and enable bitflags are placed together so they can be merged. - priv is placed at the end of the struct - it is for use by the client so it is helpful to make it stand out, and since the compiler will always pad the struct size to an alignment multiple putting a pointer last won't introduce any more padding. - struct cs_dsp_alg_region is placed at the end, right before priv, for the same reasoning as priv. Signed-off-by: Richard Fitzgerald Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20220425095159.3044527-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/linux/firmware/cirrus/cs_dsp.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 38b4da3ddfe4..30055706cce2 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -68,36 +68,36 @@ struct cs_dsp_alg_region { /** * struct cs_dsp_coeff_ctl - Describes a coefficient control + * @list: List node for internal use + * @dsp: DSP instance associated with this control + * @cache: Cached value of the control * @fw_name: Name of the firmware * @subname: Name of the control parsed from the WMFW * @subname_len: Length of subname - * @alg_region: Logical region associated with this control - * @dsp: DSP instance associated with this control - * @enabled: Flag indicating whether control is enabled - * @list: List node for internal use - * @cache: Cached value of the control * @offset: Offset of control within alg_region in words * @len: Length of the cached value in bytes - * @set: Flag indicating the value has been written by the user - * @flags: Bitfield of WMFW_CTL_FLAG_ control flags defined in wmfw.h * @type: One of the WMFW_CTL_TYPE_ control types defined in wmfw.h + * @flags: Bitfield of WMFW_CTL_FLAG_ control flags defined in wmfw.h + * @set: Flag indicating the value has been written by the user + * @enabled: Flag indicating whether control is enabled + * @alg_region: Logical region associated with this control * @priv: For use by the client */ struct cs_dsp_coeff_ctl { + struct list_head list; + struct cs_dsp *dsp; + void *cache; const char *fw_name; /* Subname is needed to match with firmware */ const char *subname; unsigned int subname_len; - struct cs_dsp_alg_region alg_region; - struct cs_dsp *dsp; - unsigned int enabled:1; - struct list_head list; - void *cache; unsigned int offset; size_t len; - unsigned int set:1; - unsigned int flags; unsigned int type; + unsigned int flags; + unsigned int set:1; + unsigned int enabled:1; + struct cs_dsp_alg_region alg_region; void *priv; }; -- cgit v1.2.3-59-g8ed1b From 9db69df4bdd37eb1f65b6931ee067fb15b9a4d5c Mon Sep 17 00:00:00 2001 From: TingHan Shen Date: Thu, 12 May 2022 16:22:13 +0800 Subject: firmware: mediatek: Add adsp ipc protocol interface Some of mediatek processors contain the Tensilica HiFix DSP for audio processing. The communication between Host CPU and DSP firmware is taking place using a shared memory area for message passing. ADSP IPC protocol offers (send/recv) interfaces using mediatek-mailbox APIs. We use two mbox channels to implement a request-reply protocol. Signed-off-by: Allen-KH Cheng Signed-off-by: TingHan Shen Reviewed-by: Pierre-Louis Bossart Reviewed-by: Curtis Malainey Reviewed-by: Tzung-Bi Shih Reviewed-by: YC Hung Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220512082215.3018-2-tinghan.shen@mediatek.com Signed-off-by: Mark Brown --- drivers/firmware/Kconfig | 9 ++ drivers/firmware/Makefile | 1 + drivers/firmware/mtk-adsp-ipc.c | 157 +++++++++++++++++++++++++ include/linux/firmware/mediatek/mtk-adsp-ipc.h | 65 ++++++++++ 4 files changed, 232 insertions(+) create mode 100644 drivers/firmware/mtk-adsp-ipc.c create mode 100644 include/linux/firmware/mediatek/mtk-adsp-ipc.h (limited to 'include/linux') diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index e5cfb01353d8..f7bc8306631b 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -203,6 +203,15 @@ config INTEL_STRATIX10_RSU Say Y here if you want Intel RSU support. +config MTK_ADSP_IPC + tristate "MTK ADSP IPC Protocol driver" + depends on MTK_ADSP_MBOX + help + Say yes here to add support for the MediaTek ADSP IPC + between host AP (Linux) and the firmware running on ADSP. + ADSP exists on some mtk processors. + Client might use shared memory to exchange information with ADSP. + config QCOM_SCM tristate diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 4e58cb474a68..1be0e8295222 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_INTEL_STRATIX10_RSU) += stratix10-rsu.o obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o +obj-$(CONFIG_MTK_ADSP_IPC) += mtk-adsp-ipc.o obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o obj-$(CONFIG_QCOM_SCM) += qcom-scm.o diff --git a/drivers/firmware/mtk-adsp-ipc.c b/drivers/firmware/mtk-adsp-ipc.c new file mode 100644 index 000000000000..cb255a99170c --- /dev/null +++ b/drivers/firmware/mtk-adsp-ipc.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Corporation. All rights reserved. + * Author: Allen-KH Cheng + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * mtk_adsp_ipc_send - send ipc cmd to MTK ADSP + * + * @ipc: ADSP IPC handle + * @idx: index of the mailbox channel + * @msg: IPC cmd (reply or request) + * + * Returns zero for success from mbox_send_message + * negative value for error + */ +int mtk_adsp_ipc_send(struct mtk_adsp_ipc *ipc, unsigned int idx, uint32_t msg) +{ + struct mtk_adsp_chan *adsp_chan; + int ret; + + if (idx >= MTK_ADSP_MBOX_NUM) + return -EINVAL; + + adsp_chan = &ipc->chans[idx]; + ret = mbox_send_message(adsp_chan->ch, &msg); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_adsp_ipc_send); + +/* + * mtk_adsp_ipc_recv - recv callback used by MTK ADSP mailbox + * + * @c: mbox client + * @msg: message received + * + * Users of ADSP IPC will need to privde handle_reply and handle_request + * callbacks. + */ +static void mtk_adsp_ipc_recv(struct mbox_client *c, void *msg) +{ + struct mtk_adsp_chan *chan = container_of(c, struct mtk_adsp_chan, cl); + struct device *dev = c->dev; + + switch (chan->idx) { + case MTK_ADSP_MBOX_REPLY: + chan->ipc->ops->handle_reply(chan->ipc); + break; + case MTK_ADSP_MBOX_REQUEST: + chan->ipc->ops->handle_request(chan->ipc); + break; + default: + dev_err(dev, "wrong mbox chan %d\n", chan->idx); + break; + } +} + +static int mtk_adsp_ipc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_adsp_ipc *adsp_ipc; + struct mtk_adsp_chan *adsp_chan; + struct mbox_client *cl; + char *chan_name; + int ret; + int i, j; + + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); + + adsp_ipc = devm_kzalloc(dev, sizeof(*adsp_ipc), GFP_KERNEL); + if (!adsp_ipc) + return -ENOMEM; + + for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) { + chan_name = kasprintf(GFP_KERNEL, "mbox%d", i); + if (!chan_name) { + ret = -ENOMEM; + goto out; + } + + adsp_chan = &adsp_ipc->chans[i]; + cl = &adsp_chan->cl; + cl->dev = dev->parent; + cl->tx_block = false; + cl->knows_txdone = false; + cl->tx_prepare = NULL; + cl->rx_callback = mtk_adsp_ipc_recv; + + adsp_chan->ipc = adsp_ipc; + adsp_chan->idx = i; + adsp_chan->ch = mbox_request_channel_byname(cl, chan_name); + if (IS_ERR(adsp_chan->ch)) { + ret = PTR_ERR(adsp_chan->ch); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to request mbox chan %d ret %d\n", + i, ret); + goto out_free; + } + + dev_dbg(dev, "request mbox chan %s\n", chan_name); + kfree(chan_name); + } + + adsp_ipc->dev = dev; + dev_set_drvdata(dev, adsp_ipc); + dev_dbg(dev, "MTK ADSP IPC initialized\n"); + + return 0; + +out_free: + kfree(chan_name); +out: + for (j = 0; j < i; j++) { + adsp_chan = &adsp_ipc->chans[j]; + mbox_free_channel(adsp_chan->ch); + } + + return ret; +} + +static int mtk_adsp_ipc_remove(struct platform_device *pdev) +{ + struct mtk_adsp_ipc *adsp_ipc = dev_get_drvdata(&pdev->dev); + struct mtk_adsp_chan *adsp_chan; + int i; + + for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) { + adsp_chan = &adsp_ipc->chans[i]; + mbox_free_channel(adsp_chan->ch); + } + + return 0; +} + +static struct platform_driver mtk_adsp_ipc_driver = { + .driver = { + .name = "mtk-adsp-ipc", + }, + .probe = mtk_adsp_ipc_probe, + .remove = mtk_adsp_ipc_remove, +}; +builtin_platform_driver(mtk_adsp_ipc_driver); + +MODULE_AUTHOR("Allen-KH Cheng "); +MODULE_DESCRIPTION("MTK ADSP IPC Driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/firmware/mediatek/mtk-adsp-ipc.h b/include/linux/firmware/mediatek/mtk-adsp-ipc.h new file mode 100644 index 000000000000..28fd313340b8 --- /dev/null +++ b/include/linux/firmware/mediatek/mtk-adsp-ipc.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef MTK_ADSP_IPC_H +#define MTK_ADSP_IPC_H + +#include +#include +#include +#include + +#define MTK_ADSP_IPC_REQ 0 +#define MTK_ADSP_IPC_RSP 1 +#define MTK_ADSP_IPC_OP_REQ 0x1 +#define MTK_ADSP_IPC_OP_RSP 0x2 + +enum { + MTK_ADSP_MBOX_REPLY, + MTK_ADSP_MBOX_REQUEST, + MTK_ADSP_MBOX_NUM, +}; + +struct mtk_adsp_ipc; + +struct mtk_adsp_ipc_ops { + void (*handle_reply)(struct mtk_adsp_ipc *ipc); + void (*handle_request)(struct mtk_adsp_ipc *ipc); +}; + +struct mtk_adsp_chan { + struct mtk_adsp_ipc *ipc; + struct mbox_client cl; + struct mbox_chan *ch; + char *name; + int idx; +}; + +struct mtk_adsp_ipc { + struct mtk_adsp_chan chans[MTK_ADSP_MBOX_NUM]; + struct device *dev; + struct mtk_adsp_ipc_ops *ops; + void *private_data; +}; + +static inline void mtk_adsp_ipc_set_data(struct mtk_adsp_ipc *ipc, void *data) +{ + if (!ipc) + return; + + ipc->private_data = data; +} + +static inline void *mtk_adsp_ipc_get_data(struct mtk_adsp_ipc *ipc) +{ + if (!ipc) + return NULL; + + return ipc->private_data; +} + +int mtk_adsp_ipc_send(struct mtk_adsp_ipc *ipc, unsigned int idx, uint32_t op); + +#endif /* MTK_ADSP_IPC_H */ -- cgit v1.2.3-59-g8ed1b