diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dma/imx-dma.c | 2 | ||||
-rw-r--r-- | drivers/dma/imx-sdma.c | 76 | ||||
-rw-r--r-- | drivers/firmware/Kconfig | 9 | ||||
-rw-r--r-- | drivers/firmware/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/mtk-adsp-ipc.c | 157 | ||||
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-lpspi.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-imx.c | 2 | ||||
-rw-r--r-- | drivers/staging/greybus/audio_codec.c | 12 | ||||
-rw-r--r-- | drivers/tty/serial/imx.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/mx3fb.c | 2 |
11 files changed, 251 insertions, 16 deletions
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 <linux/of_dma.h> #include <asm/irq.h> -#include <linux/platform_data/dma-imx.h> +#include <linux/dma/imx-dma.h> #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..95367a8a81a5 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -14,6 +14,7 @@ #include <linux/iopoll.h> #include <linux/module.h> #include <linux/types.h> +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -35,7 +36,7 @@ #include <linux/workqueue.h> #include <asm/irq.h> -#include <linux/platform_data/dma-imx.h> +#include <linux/dma/imx-dma.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> @@ -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) @@ -940,7 +959,7 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id) /* * sets the pc of SDMA script according to the peripheral type */ -static void sdma_get_pc(struct sdma_channel *sdmac, +static int sdma_get_pc(struct sdma_channel *sdmac, enum sdma_peripheral_type peripheral_type) { struct sdma_engine *sdma = sdmac->sdma; @@ -1038,14 +1057,22 @@ static void sdma_get_pc(struct sdma_channel *sdmac, case IMX_DMATYPE_IPU_MEMORY: emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; break; - default: + 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); + return -EINVAL; } sdmac->pc_from_device = per_2_emi; sdmac->pc_to_device = emi_2_per; sdmac->device_to_device = per_2_per; sdmac->pc_to_pc = emi_2_emi; + + return 0; } static int sdma_load_context(struct sdma_channel *sdmac) @@ -1210,9 +1237,26 @@ 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); + int ret; sdma_disable_channel(chan); @@ -1233,7 +1277,9 @@ static int sdma_config_channel(struct dma_chan *chan) break; } - sdma_get_pc(sdmac, sdmac->peripheral_type); + ret = sdma_get_pc(sdmac, sdmac->peripheral_type); + if (ret) + return ret; if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) && (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { @@ -1243,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); } @@ -1349,7 +1399,9 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan) mem_data.dma_request2 = 0; data = &mem_data; - sdma_get_pc(sdmac, IMX_DMATYPE_MEMORY); + ret = sdma_get_pc(sdmac, IMX_DMATYPE_MEMORY); + if (ret) + return ret; } switch (data->priority) { @@ -1698,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/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 <allen-kh.cheng@mediatek.com> + */ + +#include <linux/firmware/mediatek/mtk-adsp-ipc.h> +#include <linux/kernel.h> +#include <linux/mailbox_client.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* + * 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 <allen-kh.cheng@mediatek.com>"); +MODULE_DESCRIPTION("MTK ADSP IPC Driver"); +MODULE_LICENSE("GPL"); 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 <asm/irq.h> #include <linux/platform_data/mmc-mxcmmc.h> -#include <linux/platform_data/dma-imx.h> +#include <linux/dma/imx-dma.h> #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 <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> -#include <linux/platform_data/dma-imx.h> +#include <linux/dma/imx-dma.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/spi/spi.h> 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 <linux/of_device.h> #include <linux/property.h> -#include <linux/platform_data/dma-imx.h> +#include <linux/dma/imx-dma.h> #define DRIVER_NAME "spi_imx" diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c index b589cf6b1d03..db0b600ee5d1 100644 --- a/drivers/staging/greybus/audio_codec.c +++ b/drivers/staging/greybus/audio_codec.c @@ -702,8 +702,9 @@ static int gbaudio_init_jack(struct gbaudio_module_info *module, headset->pin = module->jack_name; headset->mask = module->jack_mask; - ret = snd_soc_card_jack_new(card, module->jack_name, module->jack_mask, - &module->headset.jack, headset, 1); + ret = snd_soc_card_jack_new_pins(card, module->jack_name, + module->jack_mask, + &module->headset.jack, headset, 1); if (ret) { dev_err(module->dev, "Failed to create new jack\n"); return ret; @@ -725,9 +726,10 @@ static int gbaudio_init_jack(struct gbaudio_module_info *module, button->pin = module->button_name; button->mask = module->button_mask; - ret = snd_soc_card_jack_new(card, module->button_name, - module->button_mask, &module->button.jack, - button, 1); + ret = snd_soc_card_jack_new_pins(card, module->button_name, + module->button_mask, + &module->button.jack, + button, 1); if (ret) { dev_err(module->dev, "Failed to create button jack\n"); goto free_jacks; 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 <linux/dma-mapping.h> #include <asm/irq.h> -#include <linux/platform_data/dma-imx.h> +#include <linux/dma/imx-dma.h> #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 <linux/dma/ipu-dma.h> #include <linux/backlight.h> -#include <linux/platform_data/dma-imx.h> +#include <linux/dma/imx-dma.h> #include <linux/platform_data/video-mx3fb.h> #include <asm/io.h> |