diff --git a/arch/arm64/configs/deepin_arm64_desktop_defconfig b/arch/arm64/configs/deepin_arm64_desktop_defconfig index 434fd3869131..cab404b1377b 100644 --- a/arch/arm64/configs/deepin_arm64_desktop_defconfig +++ b/arch/arm64/configs/deepin_arm64_desktop_defconfig @@ -2193,6 +2193,7 @@ CONFIG_I2C_SCMI=m CONFIG_I2C_ALTERA=m CONFIG_I2C_BCM2835=m CONFIG_I2C_CADENCE=m +CONFIG_I2C_CIX=m CONFIG_I2C_CBUS_GPIO=m CONFIG_I2C_DESIGNWARE_SLAVE=y CONFIG_I2C_DESIGNWARE_PCI=m @@ -2883,7 +2884,6 @@ CONFIG_DVB_FIREDTV=m CONFIG_PANEL=m CONFIG_DRM=y CONFIG_DRM_LOAD_EDID_FIRMWARE=y -CONFIG_DRM_DP_AUX_CHARDEV=y CONFIG_DRM_DP_CEC=y CONFIG_DRM_I2C_NXP_TDA998X=m CONFIG_DRM_I2C_NXP_TDA9950=m @@ -3064,6 +3064,12 @@ CONFIG_DRM_SSD130X_I2C=m CONFIG_DRM_SSD130X_SPI=m CONFIG_DRM_SPRD=m CONFIG_DRM_PHYTIUM=m +CONFIG_DRM_CIX=m +CONFIG_DRM_LINLONDP=m +CONFIG_DRM_TRILIN_DP_CIX=m +CONFIG_DRM_CIX_EDP_PANEL=m +CONFIG_DRM_TRILIN_DPSUB=m +CONFIG_DRM_TRILIN_CADENCE_PHY=m CONFIG_FB=m CONFIG_FB_TILEBLITTING=y CONFIG_BACKLIGHT_PWM=m @@ -3186,6 +3192,11 @@ CONFIG_SND_SOC_AMD_ACP=m CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH=m CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m CONFIG_SND_ATMEL_SOC=m +CONFIG_SND_SOC_CIX=m +CONFIG_SND_SOC_CDNS_I2S_SC_CIX=m +CONFIG_SND_SOC_CDNS_I2S_MC_CIX=m +CONFIG_SND_SOC_IPBLOQ_HDA_CIX=m +CONFIG_SND_HDACODEC_REALTEK_CIX=m CONFIG_SND_DESIGNWARE_I2S=m CONFIG_SND_DESIGNWARE_PCM=y CONFIG_SND_SOC_FSL_ASRC=m @@ -3460,6 +3471,10 @@ CONFIG_USB_MICROTEK=m CONFIG_USBIP_CORE=m CONFIG_USBIP_VHCI_HCD=m CONFIG_USBIP_HOST=m +CONFIG_USB_CDNS_SUPPORT=m +CONFIG_USB_CDNSP_CIX=y +CONFIG_USB_CDNSP_PCI=m +CONFIG_USB_CDNSP_SKY1=m CONFIG_USB_MUSB_HDRC=m CONFIG_USB_MUSB_HOST=y CONFIG_MUSB_PIO_ONLY=y @@ -3570,6 +3585,7 @@ CONFIG_TYPEC_RT1719=m CONFIG_TYPEC_HD3SS3220=m CONFIG_TYPEC_STUSB160X=m CONFIG_TYPEC_WUSB3801=m +CONFIG_TYPEC_RTS5453=m CONFIG_TYPEC_MUX_PI3USB30532=m CONFIG_TYPEC_DP_ALTMODE=m CONFIG_MMC=m @@ -3743,6 +3759,7 @@ CONFIG_XILINX_XDMA=m CONFIG_XILINX_ZYNQMP_DMA=m CONFIG_XILINX_ZYNQMP_DPDMA=m CONFIG_PHYTIUM_DDMA=y +CONFIG_ARM_DMA350=m CONFIG_MTK_HSDMA=m CONFIG_MTK_CQDMA=m CONFIG_MTK_UART_APDMA=m @@ -3824,12 +3841,14 @@ CONFIG_COMMON_CLK_CDCE706=m CONFIG_COMMON_CLK_CDCE925=m # CONFIG_COMMON_CLK_XGENE is not set CONFIG_COMMON_CLK_PWM=m +CONFIG_COMMON_CLK_CIX=m CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_OMAP=m CONFIG_HWSPINLOCK_PHYTIUM=m CONFIG_HWSPINLOCK_QCOM=m CONFIG_HWSPINLOCK_SPRD=m CONFIG_HWSPINLOCK_SUN6I=m +CONFIG_TIMER_SKY1_GPT=y CONFIG_ARM_MHU=y CONFIG_ARM_MHU_V2=m CONFIG_IMX_MBOX=m @@ -3854,7 +3873,12 @@ CONFIG_IOMMU_IO_PGTABLE_ARMV7S=y CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y CONFIG_ARM_SMMU=y CONFIG_ARM_SMMU_V3=y +CONFIG_REMOTEPROC=y +CONFIG_CIX_DSP_REMOTEPROC=m CONFIG_RPMSG_VIRTIO=m +CONFIG_SOC_CIX=y +CONFIG_CIX_SKY1_SOCINFO=y +CONFIG_CIX_SOC_ACPI=y CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_DEVFREQ_GOV_PERFORMANCE=m CONFIG_DEVFREQ_GOV_POWERSAVE=m @@ -3895,6 +3919,8 @@ CONFIG_IPACK_BUS=m CONFIG_BOARD_TPCI200=m CONFIG_SERIAL_IPOCTAL=m # CONFIG_RESET_MCHP_SPARX5 is not set +CONFIG_RESET_SKY1=m +CONFIG_RESET_SKY1_AUDSS=m CONFIG_BCM_KONA_USB2_PHY=m CONFIG_PHY_HI6220_USB=m CONFIG_PHY_HISTB_COMBPHY=m @@ -3905,6 +3931,9 @@ CONFIG_PHY_MAPPHONE_MDM6600=m CONFIG_PHY_QCOM_USB_HS=m CONFIG_PHY_QCOM_USB_HSIC=m CONFIG_PHY_TUSB1210=m +CONFIG_PHY_CIX_USBDP=m +CONFIG_PHY_CIX_USB2=m +CONFIG_PHY_CIX_USB3=m CONFIG_POWERCAP=y CONFIG_ARM_CCI_PMU=m CONFIG_ARM_CCN=m diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c30099866174..ce1099ea0fb0 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -471,6 +471,7 @@ source "drivers/clk/actions/Kconfig" source "drivers/clk/analogbits/Kconfig" source "drivers/clk/baikal-t1/Kconfig" source "drivers/clk/bcm/Kconfig" +source "drivers/clk/cix/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/imgtec/Kconfig" source "drivers/clk/imx/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 18969cbd4bb1..13abc7e74736 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/ obj-$(CONFIG_CLK_BAIKAL_T1) += baikal-t1/ obj-y += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ +obj-$(CONFIG_COMMON_CLK_CIX) += cix/ obj-$(CONFIG_ARCH_DAVINCI) += davinci/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ obj-y += imgtec/ diff --git a/drivers/clk/cix/Kconfig b/drivers/clk/cix/Kconfig new file mode 100644 index 000000000000..15f520c07e65 --- /dev/null +++ b/drivers/clk/cix/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +# Common clock support for Cixtech SoC family +menu "Clock support for Cixtech" + +comment "Clock options for Cixtech CPUs:" + +config COMMON_CLK_CIX + tristate "Support for Cix's clock controllers" + select REGMAP_MMIO + select RESET_CONTROLLER + help + Say y here to enable common clock controller for Cix platforms. + +endmenu diff --git a/drivers/clk/cix/Makefile b/drivers/clk/cix/Makefile new file mode 100644 index 000000000000..158449931a1c --- /dev/null +++ b/drivers/clk/cix/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# CIX clocks + +obj-y += clk-sky1-audss.o +obj-y += acpi_clk.o +obj-y += clk.o diff --git a/drivers/clk/cix/acpi_clk.c b/drivers/clk/cix/acpi_clk.c new file mode 100644 index 000000000000..033b967dd78a --- /dev/null +++ b/drivers/clk/cix/acpi_clk.c @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + *Copyright 2024 Cix Technology Group Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acpi_clk.h" + +#define GET_CLOCK_RATE 0x00000001 +#define SET_CLOCK_RATE 0X00000002 +#define SET_CLOCK_CONFIG 0X00000003 + +#define CLOCK_REVISION_ID 1 +#define CLOCK_ENABLE BIT(0) +#define CLOCK_DISABLE 0 +#define CLK_MASK (0xffffffff) +#define SUCCESS 0 + +static LIST_HEAD(aclk_list); +static LIST_HEAD(aclk_hw_list); + +static struct acpi_device *acpi_obj_path_to_adev(union acpi_object *obj) +{ + struct acpi_device *adev = NULL; + char *path; + acpi_handle handle; + acpi_status status; + + if (!obj || !obj->string.length) + return NULL; + + path = obj->string.pointer; + status = acpi_get_handle(NULL, path, &handle); + if (ACPI_FAILURE(status)) + return NULL; + + adev = acpi_fetch_acpi_dev(handle); + + return adev; +} + +static struct acpi_device *acpi_obj_to_adev(union acpi_object *obj) +{ + if (!obj) + return NULL; + + if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) + return acpi_fetch_acpi_dev(obj->reference.handle); + else if (obj->type == ACPI_TYPE_STRING) + return acpi_obj_path_to_adev(obj); + else + return NULL; +} + +static int acpi_clock_config_set(struct device *dev, u32 clk_id, u32 config) +{ + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + u32 buf_val[1]; + int ret = 0; + union acpi_object *package; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[2] = { + { .type = ACPI_TYPE_INTEGER, }, + { .type = ACPI_TYPE_INTEGER, }, + }; + + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + + args[0].integer.value = clk_id; + args[1].integer.value = config; + + status = acpi_evaluate_object(handle, "CLKC", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "ACPI evaluation failed\n"); + ret = -ENODEV; + goto OUT; + } + + package = buffer.pointer; + if (!package || package->type != ACPI_TYPE_BUFFER) { + dev_err(dev, "Couldn't locate correct ACPI buffer\n"); + ret = -ENODEV; + goto OUT; + } + + buf_val[0] = *(u32 *)package->buffer.pointer; + if (buf_val[0] != SUCCESS) { + dev_err(dev, "ACPI clk[%u] set config[%u] err:%d\n", + clk_id, config, buf_val[0]); + ret = -ENODEV; + goto OUT; + } + +OUT: + kfree(buffer.pointer); + + return ret; +} + +static int acpi_clk_prepare(struct clk_hw *hw) +{ + struct acpi_clk_hw *aclk = to_acpi_clk_hw(hw); + + if (!aclk) + return -EINVAL; + + return acpi_clock_config_set(aclk->dev, aclk->clk_id, CLOCK_ENABLE); +} + +static void acpi_clk_unprepare(struct clk_hw *hw) +{ + struct acpi_clk_hw *aclk = to_acpi_clk_hw(hw); + + if (!aclk) + return; + + acpi_clock_config_set(aclk->dev, aclk->clk_id, CLOCK_DISABLE); +} + +static unsigned long acpi_cix_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct acpi_clk_hw *aclk_hw = to_acpi_clk_hw(hw); + struct device *dev = aclk_hw->dev; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + unsigned long clk_rate; + u32 buf_val[3] = {0}; + int ret = 0; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[] = { + { .type = ACPI_TYPE_INTEGER, }, + }; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + union acpi_object *package; + + args[0].integer.value = cpu_to_le32(aclk_hw->clk_id); + status = acpi_evaluate_object(handle, "GClK", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "ACPI evaluation failed\n"); + ret = -ENODEV; + goto OUT; + } + + package = buffer.pointer; + if (!package || package->type != ACPI_TYPE_BUFFER) { + dev_err(dev, "Couldn't locate correct ACPI buffer\n"); + ret = -ENODEV; + goto OUT; + } + + buf_val[0] = ((u32 *)package->buffer.pointer)[0]; + buf_val[1] = ((u32 *)package->buffer.pointer)[1]; + buf_val[2] = ((u32 *)package->buffer.pointer)[2]; + if (buf_val[0] != SUCCESS) { + dev_err(dev, "ACPI clk[%u] rec rate err:%d\n", + aclk_hw->clk_id, buf_val[0]); + ret = buf_val[0]; + goto OUT; + } + + clk_rate = ((u64)(buf_val[2] & CLK_MASK) << 32) + | (u64)(buf_val[1] & CLK_MASK); + +OUT: + kfree(buffer.pointer); + + return ret ? 0 : clk_rate; +} + +static int acpi_cix_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct acpi_clk_hw *aclk_hw = to_acpi_clk_hw(hw); + struct device *dev = aclk_hw->dev; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + u32 buf_val[1]; + int ret = 0; + union acpi_object *package; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3] = { + { .type = ACPI_TYPE_INTEGER, }, + { .type = ACPI_TYPE_INTEGER, }, + { .type = ACPI_TYPE_INTEGER, }, + }; + + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + + args[0].integer.value = aclk_hw->clk_id; + args[1].integer.value = (cpu_to_le32(rate & CLK_MASK)); + args[2].integer.value = (cpu_to_le32((rate >> 32) & CLK_MASK)); + + status = acpi_evaluate_object(handle, "SClK", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "ACPI evaluation failed\n"); + ret = -ENODEV; + goto OUT; + } + + package = buffer.pointer; + if (!package || package->type != ACPI_TYPE_BUFFER) { + dev_err(dev, "Couldn't locate ACPI buffer\n"); + ret = -ENODEV; + goto OUT; + } + + buf_val[0] = *(u32 *)package->buffer.pointer; + if (buf_val[0] != SUCCESS) { + dev_err(dev, "ACPI clk[%u] set rate err:%d\n", + aclk_hw->clk_id, buf_val[0]); + goto OUT; + } + +OUT: + kfree(buffer.pointer); + + return ret; +} + +static long cix_acpi_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + /* do not support now */ + return rate; +} + +static const struct clk_ops acpi_clk_ops = { + .prepare = acpi_clk_prepare, + .unprepare = acpi_clk_unprepare, + .recalc_rate = acpi_cix_clk_recalc_rate, + .round_rate = cix_acpi_clk_round_rate, + .set_rate = acpi_cix_clk_set_rate, +}; + +static const char *acpi_clk_get_obj_id(union acpi_object *obj) +{ + if (!obj) + return NULL; + + return obj->string.length ? obj->string.pointer : NULL; +} + +static struct clk_hw *acpi_clk_get_hw(unsigned int clk_id) +{ + struct acpi_clk_hw *aclk_hw; + + list_for_each_entry(aclk_hw, &aclk_hw_list, list) { + if (aclk_hw->clk_id == clk_id) + return &aclk_hw->hw; + } + + return NULL; +} + +static struct clk_hw *devm_acpi_clk_hw_alloc(struct device *dev, + unsigned int clk_id) +{ + struct acpi_clk_hw *aclk_hw = NULL; + + aclk_hw = devm_kzalloc(dev, sizeof(*aclk_hw), GFP_KERNEL); + if (IS_ERR(aclk_hw)) + return ERR_PTR(-ENOMEM); + + aclk_hw->clk_id = clk_id; + INIT_LIST_HEAD(&aclk_hw->list); + list_add_tail(&aclk_hw->list, &aclk_hw_list); + + return &aclk_hw->hw; +} + +static struct clk_hw *acpi_clk_get_or_create_hw(struct device *dev, int clk_id) +{ + struct clk_init_data init; + struct clk_hw *hw; + struct acpi_clk_hw *aclk_hw; + char clk_name[CLK_NAME_LEN]; + int ret; + + hw = acpi_clk_get_hw(clk_id); + if (!hw) { + snprintf(clk_name, CLK_NAME_LEN, "ACLK:%04d", clk_id); + + hw = devm_acpi_clk_hw_alloc(dev, clk_id); + if (!hw) + goto out; + hw->init = &init; + init.name = clk_name; + init.ops = &acpi_clk_ops; + init.num_parents = 0; + init.flags = CLK_GET_RATE_NOCACHE; + + aclk_hw = to_acpi_clk_hw(hw); + aclk_hw->dev = dev; + + /* register hw clk */ + ret = devm_clk_hw_register(dev, hw); + if (ret) + goto out; + } + + return hw; +out: + return NULL; +} + +int cix_acpi_parse_clkt_handle(acpi_handle handle, const char *name, + struct clk_hw *(get_hw)(struct device *, int), + void *data) +{ + struct device *dev = data; + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *out_obj, *clk_obj, *el[ACLK_MAX]; + acpi_status status; + int clk_num, pnum, i, ret = 0; + struct acpi_device *adev; + struct acpi_clk *acpi_clks; + struct clk_hw *hw; + const char *con_id, *dname = NULL; + unsigned int clk_id; + + if (!get_hw) + return -EINVAL; + + /* Parse the ACPI CLKT table for this CPU. */ + status = acpi_evaluate_object_typed(handle, + (acpi_string)name, NULL, &output, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + ret = -ENODEV; + goto out_free; + } + + out_obj = (union acpi_object *) output.pointer; + clk_num = out_obj->package.count; + acpi_clks = devm_kcalloc(dev, clk_num, sizeof(struct acpi_clk), GFP_KERNEL); + if (!acpi_clks) { + ret = -ENOMEM; + goto out_free; + } + + /* acpi clk register */ + for (i = 0; i < clk_num; i++) { + clk_obj = &out_obj->package.elements[i]; + pnum = clk_obj->package.count; + if (pnum < ACLK_DEV) + continue; + + /* clk package: {id, con_id, [dev_id]} */ + el[0] = &clk_obj->package.elements[0]; + el[1] = &clk_obj->package.elements[1]; + el[2] = pnum > ACLK_DEV ? &clk_obj->package.elements[2] : NULL; + + if ((el[0]->type != ACPI_TYPE_INTEGER) + || (el[1]->type != ACPI_TYPE_STRING) + || (el[2] && el[2]->type != ACPI_TYPE_LOCAL_REFERENCE + && el[2]->type != ACPI_TYPE_STRING)) + continue; + + clk_id = el[0]->integer.value; + con_id = acpi_clk_get_obj_id(el[1]); + adev = el[2] ? acpi_obj_to_adev(el[2]) : NULL; + dname = adev ? dev_name(&adev->dev) : NULL; + + if (!con_id && !adev) + continue; + + hw = get_hw(dev, clk_id); + if (!hw) + continue; + + acpi_clks[i].hw = hw; + acpi_clks[i].cl.dev_id = dname; + acpi_clks[i].cl.con_id = devm_kstrdup(dev, con_id, GFP_KERNEL); + acpi_clks[i].cl.clk = hw->clk; + + clkdev_add(&acpi_clks[i].cl); + INIT_LIST_HEAD(&acpi_clks[i].list); + list_add_tail(&acpi_clks[i].list, &aclk_list); + + dev_dbg(dev, "clk: id[%d] con[%s] dev[%s]\n", + clk_id, con_id, dname); + } + +out_free: + kfree(output.pointer); + + return ret; +} + +int cix_acpi_parse_clkt(struct device *dev, const char *cname, + struct clk_hw *(get_hw)(struct device *, int)) +{ + if (!dev) + return -EINVAL; + + return cix_acpi_parse_clkt_handle(ACPI_HANDLE(dev), cname, get_hw, dev); +} +EXPORT_SYMBOL_GPL(cix_acpi_parse_clkt); + + +static acpi_status acpi_bus_clk_scan(acpi_handle handle, u32 level, + void *context, void **ret_p) +{ + struct device *dev = context; + acpi_object_type acpi_type; + int ret; + + if (ACPI_FAILURE(acpi_get_type(handle, &acpi_type))) + return AE_OK; + + if (acpi_type != ACPI_TYPE_DEVICE) + return AE_OK; + + if (!dev) + return AE_OK; + + ret = cix_acpi_parse_clkt_handle(handle, + "CLKT", acpi_clk_get_or_create_hw, dev); + if (ret && ret != -ENODEV) + return AE_ERROR; + + return AE_OK; +} + +static int cix_acpi_clk_probe(struct platform_device *pdev) +{ + acpi_status status; + + status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, acpi_bus_clk_scan, + NULL, &pdev->dev, NULL); + + /* do not ensure every resource since differnt configs */ + return 0; +} + +static int cix_acpi_clk_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct acpi_device_id __maybe_unused cix_acpi_clk_match[] = { + { "CIXHA010", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, cix_acpi_clk_match); + +static struct platform_driver cix_acpi_clk_driver = { + .driver = { + .name = "cix_acpi_clk", + .acpi_match_table = ACPI_PTR(cix_acpi_clk_match), + }, + .probe = cix_acpi_clk_probe, + .remove = cix_acpi_clk_remove, +}; + +static int __init cix_acpi_clk_init(void) +{ + if (acpi_disabled) + return -ENODEV; + + return platform_driver_register(&cix_acpi_clk_driver); +} +core_initcall(cix_acpi_clk_init); + +static void __exit cix_acpi_clk_exit(void) +{ + platform_driver_unregister(&cix_acpi_clk_driver); +} +module_exit(cix_acpi_clk_exit); + +MODULE_AUTHOR("Copyright 2024 Cix Technology Group Co., Ltd."); +MODULE_DESCRIPTION("Cix acpi clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/cix/acpi_clk.h b/drivers/clk/cix/acpi_clk.h new file mode 100644 index 000000000000..2f5e9493e8d5 --- /dev/null +++ b/drivers/clk/cix/acpi_clk.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2024 Cix Technology Group Co., Ltd. + */ + +#ifndef __CIX_APCI_CLK_H__ +#define __CIX_APCI_CLK_H__ + +#include + +enum { + ACLK_ID = 0, + ACLK_CON, + ACLK_DEV, + + ACLK_MAX, +}; + +struct acpi_clk { + struct clk_hw *hw; + struct clk_lookup cl; + + struct list_head list; +}; + +struct acpi_clk_hw { + unsigned int clk_id; + struct clk_hw hw; + struct device *dev; + + struct list_head list; +}; + +#define to_acpi_clk_hw(_hw) container_of(_hw, struct acpi_clk_hw, hw) + +#define CLK_NAME_LEN 32 + +int cix_acpi_parse_clkt(struct device *dev, const char *cname, + struct clk_hw *(*get_hw)(struct device *dev, int id)); + +#endif diff --git a/drivers/clk/cix/clk-sky1-audss.c b/drivers/clk/cix/clk-sky1-audss.c new file mode 100644 index 000000000000..6a74e82c8a23 --- /dev/null +++ b/drivers/clk/cix/clk-sky1-audss.c @@ -0,0 +1,1198 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2024 Cix Technology Group Co., Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "acpi_clk.h" + +#define INFO_HIFI0 0x00 +#define INFO_CLK_GATE 0x10 +#define INFO_CLK_DIV 0x14 +#define INFO_CLK_MUX 0x18 +#define INFO_MCLK 0x70 + +#define SKY1_AUDSS_CLKS_NUM 6 + +#define SKY1_AUDSS_RCSU_ADDR 0x07000000 +#define SKY1_AUDSS_RCSU_LEN 0x10000 + +#define SKY1_AUDSS_RCSU_REMAP 0x34 +#define SKY1_AUDSS_RCSU_REMAP_VAL 0x20000000 + +#define SKY1_AUDSS_RCSU_TIMEOUT 0x1000 +#define SKY1_AUDSS_RCSU_TIMEOUT_EN BIT(31) +#define SKY1_AUDSS_RCSU_TIMEOUT_MASK GENMASK(15, 0) +#define SKY1_AUDSS_RCSU_TIMEOUT_VAL 0x78 + +struct muxdiv_cfg { + int offset; + u8 shift; + u8 width; + u8 flags; +}; + +struct gate_cfg { + int offset; + u8 shift; + u8 flags; +}; + +struct composite_clk_cfg { + u32 id; + const char *name; + const char * const *parent_names; + int num_parents; + struct muxdiv_cfg *mux_cfg; + struct muxdiv_cfg *div_cfg; + struct gate_cfg *gate_cfg; + unsigned long flags; +}; + +static DEFINE_SPINLOCK(lock); +static struct clk_hw_onecell_data *clk_data; + +static u32 reg_save[][2] = { + { INFO_HIFI0, 0 }, + { INFO_CLK_GATE, 0 }, + { INFO_CLK_DIV, 0 }, + { INFO_CLK_MUX, 0 }, + { INFO_MCLK, 0 }, +}; + +static const char *sky1_audss_clks_names[SKY1_AUDSS_CLKS_NUM] = { + "audio_clk0", "audio_clk1", "audio_clk2", + "audio_clk3", "audio_clk4", "audio_clk5", +}; + +static u32 clk_rate_default[SKY1_AUDSS_CLKS_NUM] = { + SKY1_AUDSS_AUDIO_CLK0_RATE, + SKY1_AUDSS_AUDIO_CLK1_RATE, + SKY1_AUDSS_AUDIO_CLK2_RATE, + SKY1_AUDSS_AUDIO_CLK3_RATE, + SKY1_AUDSS_AUDIO_CLK4_RATE, + SKY1_AUDSS_AUDIO_CLK5_RATE, +}; + +struct sky1_clk_divider { + struct clk_divider div; + struct regmap *regmap; + int offset; +}; + +struct sky1_clk_gate { + struct clk_gate gate; + struct regmap *regmap; + int offset; +}; + +struct sky1_clk_mux { + struct clk_mux mux; + struct regmap *regmap; + int offset; +}; + +struct sky1_audss_clks_priv { + struct device *dev; + void __iomem *rcsu_base; + struct regmap *regmap_cru; + struct clk *clks[SKY1_AUDSS_CLKS_NUM]; + struct reset_control *rst_noc; +}; + +/* + * NOTE: + * clock parent names should align to those SoC top clock names + * which feed to audio subsystem. + */ +static const char * const dsp_clk_parent[] = { + "audio_clk4" +}; + +static const char * const dsp_bclk_parent[] = { + "audio_clk4_div2" +}; + +static const char * const dsp_pbclk_parent[] = { + "audio_clk4_div4" +}; + +static const char * const sram_axi_parent[] = { + "audio_clk4_div2" +}; + +static const char * const hda_sys_parent[] = { + "audio_clk4_div2" +}; + +static const char * const hda_hda_parent[] = { + "audio_clk5" +}; + +static const char * const dmac_axi_parent[] = { + "audio_clk4_div2" +}; + +static const char * const wdg_apb_parent[] = { + "audio_clk5_div2" +}; + +static const char * const wdg_wdg_parent[] = { + "audio_clk5_div2" +}; + +static const char * const timer_apb_parent[] = { + "audio_clk4_div4" +}; + +static const char * const timer_timer_parent[] = { + "audio_clk5_div2" +}; + +static const char * const mailbox_apb_parent[] = { + "audio_clk4_div4" +}; + +static const char * const i2s_apb_parent[] = { + "audio_clk4_div4" +}; + +static const char * const i2s0_parents[] = { + "audio_clk0", "audio_clk2" +}; + +static const char * const i2s1_parents[] = { + "audio_clk0", "audio_clk2" +}; + +static const char * const i2s2_parents[] = { + "audio_clk0", "audio_clk2" +}; + +static const char * const i2s3_parents[] = { + "audio_clk0", "audio_clk1", "audio_clk2", "audio_clk3" +}; + +static const char * const i2s4_parents[] = { + "audio_clk0", "audio_clk1", "audio_clk2", "audio_clk3" +}; + +static const char * const i2s5_parents[] = { + "audio_clk0", "audio_clk2" +}; + +static const char * const i2s6_parents[] = { + "audio_clk0", "audio_clk2" +}; + +static const char * const i2s7_parents[] = { + "audio_clk0", "audio_clk2" +}; + +static const char * const i2s8_parents[] = { + "audio_clk0", "audio_clk2" +}; + +static const char * const i2s9_parents[] = { + "audio_clk0", "audio_clk2" +}; + +static const char * const mclk_parents[] = { + "audio_clk0", "audio_clk2" +}; + +#define CFG(_id,\ + _name,\ + _parent_names,\ + _mux_offset, _mux_shift, _mux_width, _mux_flags,\ + _div_offset, _div_shift, _div_width, _div_flags,\ + _gate_offset, _gate_shift, _gate_flags,\ + _flags)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parent_names,\ + .num_parents = ARRAY_SIZE(_parent_names),\ + .mux_cfg = &(struct muxdiv_cfg) { _mux_offset, _mux_shift, _mux_width, _mux_flags },\ + .div_cfg = &(struct muxdiv_cfg) { _div_offset, _div_shift, _div_width, _div_flags },\ + .gate_cfg = &(struct gate_cfg) { _gate_offset, _gate_shift, _gate_flags },\ + .flags = _flags,\ +} + +static const struct composite_clk_cfg audss_clks[] = { + /* dsp */ + CFG(CLK_DSP_CLK, + "audss_dsp_clk", + dsp_clk_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_HIFI0, 0, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_DSP_BCLK, + "audss_dsp_bclk", + dsp_bclk_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + -1, 0, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_DSP_PBCLK, + "audss_dsp_pbclk", + dsp_pbclk_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + -1, 0, 0, + CLK_GET_RATE_NOCACHE), + /* sram */ + CFG(CLK_SRAM_AXI, + "audss_sram_axi", + sram_axi_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 16, 0, + CLK_GET_RATE_NOCACHE), + /* hda */ + CFG(CLK_HDA_SYS, + "audss_hda_sys", + hda_sys_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 14, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_HDA_HDA, + "audss_hda_hda", + hda_hda_parent, + -1, 0, 0, 0, + -1, 0, 0, 0, + INFO_CLK_GATE, 14, 0, + CLK_GET_RATE_NOCACHE), + /* dmac */ + CFG(CLK_DMAC_AXI, + "audss_dmac_axi", + dmac_axi_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 15, 0, + CLK_GET_RATE_NOCACHE), + /* wdg */ + CFG(CLK_WDG_APB, + "audss_wdg_apb", + wdg_apb_parent, + -1, 0, 0, 0, + -1, 0, 0, 0, + INFO_CLK_GATE, 10, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_WDG_WDG, + "audss_wdg_wdg", + wdg_wdg_parent, + -1, 0, 0, 0, + -1, 0, 0, 0, + INFO_CLK_GATE, 10, 0, + CLK_GET_RATE_NOCACHE), + /* timer */ + CFG(CLK_TIMER_APB, + "audss_timer_apb", + timer_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 11, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_TIMER_TIMER, + "audss_timer_timer", + timer_timer_parent, + -1, 0, 0, 0, + -1, 0, 0, 0, + INFO_CLK_GATE, 11, 0, + CLK_GET_RATE_NOCACHE), + /* mailbox: mb0(ap->dsp), mb1(dsp->ap) */ + CFG(CLK_MB_0_APB, + "audss_mb_0_apb", + mailbox_apb_parent, + -1, 0, 0, 0, + -1, 0, 0, 0, + INFO_CLK_GATE, 12, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_MB_1_APB, + "audss_mb_1_apb", + mailbox_apb_parent, + -1, 0, 0, 0, + -1, 0, 0, 0, + INFO_CLK_GATE, 13, 0, + CLK_GET_RATE_NOCACHE), + /* i2s */ + CFG(CLK_I2S0_APB, + "audss_i2s0_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 0, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S1_APB, + "audss_i2s1_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 1, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S2_APB, + "audss_i2s2_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 2, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S3_APB, + "audss_i2s3_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 3, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S4_APB, + "audss_i2s4_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 4, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S5_APB, + "audss_i2s5_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 5, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S6_APB, + "audss_i2s6_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 6, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S7_APB, + "audss_i2s7_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 7, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S8_APB, + "audss_i2s8_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 8, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S9_APB, + "audss_i2s9_apb", + i2s_apb_parent, + -1, 0, 0, 0, + INFO_CLK_DIV, 0, 2, 0, + INFO_CLK_GATE, 9, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S0, + "audss_i2s0", + i2s0_parents, + INFO_CLK_MUX, 0, 2, 0, + INFO_CLK_DIV, 2, 2, 0, + INFO_CLK_GATE, 0, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S1, + "audss_i2s1", + i2s1_parents, + INFO_CLK_MUX, 2, 2, 0, + INFO_CLK_DIV, 4, 2, 0, + INFO_CLK_GATE, 1, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S2, + "audss_i2s2", + i2s2_parents, + INFO_CLK_MUX, 4, 2, 0, + INFO_CLK_DIV, 6, 2, 0, + INFO_CLK_GATE, 2, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S3, + "audss_i2s3", + i2s3_parents, + INFO_CLK_MUX, 6, 2, 0, + INFO_CLK_DIV, 8, 2, 0, + INFO_CLK_GATE, 3, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S4, + "audss_i2s4", + i2s4_parents, + INFO_CLK_MUX, 8, 2, 0, + INFO_CLK_DIV, 10, 2, 0, + INFO_CLK_GATE, 4, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S5, + "audss_i2s5", + i2s5_parents, + INFO_CLK_MUX, 10, 2, 0, + INFO_CLK_DIV, 12, 2, 0, + INFO_CLK_GATE, 5, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S6, + "audss_i2s6", + i2s6_parents, + INFO_CLK_MUX, 12, 2, 0, + INFO_CLK_DIV, 14, 2, 0, + INFO_CLK_GATE, 6, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S7, + "audss_i2s7", + i2s7_parents, + INFO_CLK_MUX, 14, 2, 0, + INFO_CLK_DIV, 16, 2, 0, + INFO_CLK_GATE, 7, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S8, + "audss_i2s8", + i2s8_parents, + INFO_CLK_MUX, 16, 2, 0, + INFO_CLK_DIV, 18, 2, 0, + INFO_CLK_GATE, 8, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_I2S9, + "audss_i2s9", + i2s9_parents, + INFO_CLK_MUX, 18, 2, 0, + INFO_CLK_DIV, 20, 2, 0, + INFO_CLK_GATE, 9, 0, + CLK_GET_RATE_NOCACHE), + /* mclk */ + CFG(CLK_MCLK0, + "audss_mclk0", + mclk_parents, + INFO_MCLK, 5, 1, 0, + -1, 0, 0, 0, + INFO_MCLK, 0, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_MCLK1, + "audss_mclk1", + mclk_parents, + INFO_MCLK, 6, 1, 0, + -1, 0, 0, 0, + INFO_MCLK, 1, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_MCLK2, + "audss_mclk2", + mclk_parents, + INFO_MCLK, 7, 1, 0, + -1, 0, 0, 0, + INFO_MCLK, 2, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_MCLK3, + "audss_mclk3", + mclk_parents, + INFO_MCLK, 8, 1, 0, + -1, 0, 0, 0, + INFO_MCLK, 3, 0, + CLK_GET_RATE_NOCACHE), + CFG(CLK_MCLK4, + "audss_mclk4", + mclk_parents, + INFO_MCLK, 9, 1, 0, + -1, 0, 0, 0, + INFO_MCLK, 4, 0, + CLK_GET_RATE_NOCACHE), +}; + +static inline struct sky1_clk_mux *to_sky1_clk_mux(struct clk_mux *mux) +{ + return container_of(mux, struct sky1_clk_mux, mux); +} + +static u8 sky1_audss_clk_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + struct sky1_clk_mux *sky1_mux = to_sky1_clk_mux(mux); + u32 val; + + regmap_read(sky1_mux->regmap, sky1_mux->offset, &val); + val = val >> mux->shift; + val &= mux->mask; + + return clk_mux_val_to_index(hw, mux->table, mux->flags, val); +} + +static int sky1_audss_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + struct sky1_clk_mux *sky1_mux = to_sky1_clk_mux(mux); + u32 val = clk_mux_index_to_val(mux->table, mux->flags, index); + unsigned long flags = 0; + u32 reg; + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); + + if (mux->flags & CLK_MUX_HIWORD_MASK) { + reg = mux->mask << (mux->shift + 16); + } else { + regmap_read(sky1_mux->regmap, sky1_mux->offset, ®); + reg &= ~(mux->mask << mux->shift); + } + val = val << mux->shift; + reg |= val; + regmap_write(sky1_mux->regmap, sky1_mux->offset, reg); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); + + return 0; +} + +static int sky1_audss_clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_mux *mux = to_clk_mux(hw); + + return clk_mux_determine_rate_flags(hw, req, mux->flags); +} + +/* Derive from drivers/clk/clk-mux.c clk_mux_ops */ +static const struct clk_ops sky1_audss_clk_mux_ops = { + .get_parent = sky1_audss_clk_mux_get_parent, + .set_parent = sky1_audss_clk_mux_set_parent, + .determine_rate = sky1_audss_clk_mux_determine_rate, +}; + +static inline struct sky1_clk_divider *to_sky1_clk_divider(struct clk_divider *div) +{ + return container_of(div, struct sky1_clk_divider, div); +} + +static unsigned long sky1_audss_clk_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider); + unsigned int val; + + regmap_read(sky1_div->regmap, sky1_div->offset, &val); + val = val >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + +static long sky1_audss_clk_divider_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + struct clk_divider *divider = to_clk_divider(hw); + struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider); + + /* if read only, just return current value */ + if (divider->flags & CLK_DIVIDER_READ_ONLY) { + u32 val; + + regmap_read(sky1_div->regmap, sky1_div->offset, &val); + val = val >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_ro_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags, + val); + } + + return divider_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags); +} + +static int sky1_audss_clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_divider *divider = to_clk_divider(hw); + struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider); + + /* if read only, just return current value */ + if (divider->flags & CLK_DIVIDER_READ_ONLY) { + u32 val; + + regmap_read(sky1_div->regmap, sky1_div->offset, &val); + val = val >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_ro_determine_rate(hw, req, divider->table, + divider->width, + divider->flags, val); + } + + return divider_determine_rate(hw, req, divider->table, divider->width, + divider->flags); +} + +static int sky1_audss_clk_divider_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider); + int value; + unsigned long flags = 0; + u32 val; + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = clk_div_mask(divider->width) << (divider->shift + 16); + } else { + val = regmap_read(sky1_div->regmap, sky1_div->offset, &val); + val &= ~(clk_div_mask(divider->width) << divider->shift); + } + val |= (u32)value << divider->shift; + regmap_write(sky1_div->regmap, sky1_div->offset, val); + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return 0; +} + +/* Derive from drivers/clk/clk-divider.c clk_div_ops */ +static const struct clk_ops sky1_audss_clk_divider_ops = { + .recalc_rate = sky1_audss_clk_divider_recalc_rate, + .round_rate = sky1_audss_clk_divider_round_rate, + .determine_rate = sky1_audss_clk_divider_determine_rate, + .set_rate = sky1_audss_clk_divider_set_rate, +}; + +static inline struct sky1_clk_gate *to_sky1_clk_gate(struct clk_gate *gate) +{ + return container_of(gate, struct sky1_clk_gate, gate); +} + +static void sky1_audss_clk_gate_endisable(struct clk_hw *hw, int enable) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct sky1_clk_gate *sky1_gate = to_sky1_clk_gate(gate); + int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; + unsigned long flags; + u32 reg; + + set ^= enable; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + else + __acquire(gate->lock); + + if (gate->flags & CLK_GATE_HIWORD_MASK) { + reg = BIT(gate->bit_idx + 16); + if (set) + reg |= BIT(gate->bit_idx); + } else { + regmap_read(sky1_gate->regmap, sky1_gate->offset, ®); + + if (set) + reg |= BIT(gate->bit_idx); + else + reg &= ~BIT(gate->bit_idx); + } + + regmap_write(sky1_gate->regmap, sky1_gate->offset, reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); + else + __release(gate->lock); +} + +static int sky1_audss_clk_gate_enable(struct clk_hw *hw) +{ + sky1_audss_clk_gate_endisable(hw, 1); + + return 0; +} + +static void sky1_audss_clk_gate_disable(struct clk_hw *hw) +{ + sky1_audss_clk_gate_endisable(hw, 0); +} + +static int sky1_audss_clk_gate_is_enabled(struct clk_hw *hw) +{ + u32 reg; + struct clk_gate *gate = to_clk_gate(hw); + struct sky1_clk_gate *sky1_gate = to_sky1_clk_gate(gate); + + regmap_read(sky1_gate->regmap, sky1_gate->offset, ®); + + /* if a set bit disables this clk, flip it before masking */ + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + reg ^= BIT(gate->bit_idx); + + reg &= BIT(gate->bit_idx); + + return reg ? 1 : 0; +} + +/* Derive from drivers/clk/clk-gate.c clk_gate_ops */ +static const struct clk_ops sky1_audss_clk_gate_ops = { + .enable = sky1_audss_clk_gate_enable, + .disable = sky1_audss_clk_gate_disable, + .is_enabled = sky1_audss_clk_gate_is_enabled, +}; + +static struct clk_hw *sky1_audss_clk_register(struct device *dev, + const char *name, + const char * const *parent_names, + int num_parents, + struct regmap *regmap, + struct muxdiv_cfg *mux_cfg, + struct muxdiv_cfg *div_cfg, + struct gate_cfg *gate_cfg, + unsigned long flags, + spinlock_t *lock) +{ + const struct clk_ops *sky1_mux_ops = NULL; + const struct clk_ops *sky1_div_ops = NULL; + const struct clk_ops *sky1_gate_ops = NULL; + struct clk_hw *hw = ERR_PTR(-ENOMEM); + struct sky1_clk_divider *sky1_div = NULL; + struct sky1_clk_gate *sky1_gate = NULL; + struct sky1_clk_mux *sky1_mux = NULL; + struct clk_parent_data *pdata; + int i; + + pdata = devm_kzalloc(dev, sizeof(*pdata) * num_parents, GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + for (i = 0; i < num_parents; i++) { + (&pdata[i])->fw_name = *(parent_names + i); + (&pdata[i])->index = 0; + } + + if (mux_cfg->offset >= 0) { + sky1_mux = devm_kzalloc(dev, sizeof(*sky1_mux), GFP_KERNEL); + if (!sky1_mux) + return ERR_PTR(-ENOMEM); + + sky1_mux->mux.reg = NULL; + sky1_mux->mux.shift = mux_cfg->shift; + sky1_mux->mux.mask = BIT(mux_cfg->width) - 1; + sky1_mux->mux.flags = mux_cfg->flags; + sky1_mux->mux.lock = lock; + sky1_mux_ops = &sky1_audss_clk_mux_ops; + sky1_mux->regmap = regmap; + sky1_mux->offset = mux_cfg->offset; + } + + if (div_cfg->offset >= 0) { + sky1_div = devm_kzalloc(dev, sizeof(*sky1_div), GFP_KERNEL); + if (!sky1_div) + return ERR_PTR(-ENOMEM); + + sky1_div->div.reg = NULL; + sky1_div->div.shift = div_cfg->shift; + sky1_div->div.width = div_cfg->width; + sky1_div->div.flags = div_cfg->flags | CLK_DIVIDER_POWER_OF_TWO; + sky1_div->div.lock = lock; + sky1_div_ops = &sky1_audss_clk_divider_ops; + sky1_div->regmap = regmap; + sky1_div->offset = div_cfg->offset; + } + + if (gate_cfg->offset >= 0) { + sky1_gate = devm_kzalloc(dev, sizeof(*sky1_gate), GFP_KERNEL); + if (!sky1_gate) + return ERR_PTR(-ENOMEM); + + sky1_gate->gate.reg = NULL; + sky1_gate->gate.bit_idx = gate_cfg->shift; + sky1_gate->gate.flags = gate_cfg->flags; + sky1_gate->gate.lock = lock; + sky1_gate_ops = &sky1_audss_clk_gate_ops; + sky1_gate->regmap = regmap; + sky1_gate->offset = gate_cfg->offset; + } + + hw = devm_clk_hw_register_composite_pdata(dev, name, + pdata, num_parents, + sky1_mux ? &sky1_mux->mux.hw : NULL, sky1_mux_ops, + sky1_div ? &sky1_div->div.hw : NULL, sky1_div_ops, + sky1_gate ? &sky1_gate->gate.hw : NULL, sky1_gate_ops, + flags); + if (IS_ERR(hw)) { + dev_err(dev, "register %s clock failed with err = %ld\n", + name, PTR_ERR(hw)); + return ERR_CAST(hw); + } + + return hw; +} + +static int sky1_audss_clks_get(struct sky1_audss_clks_priv *priv) +{ + int i; + + for (i = 0; i < SKY1_AUDSS_CLKS_NUM; i++) { + priv->clks[i] = devm_clk_get(priv->dev, sky1_audss_clks_names[i]); + if (IS_ERR(priv->clks[i])) { + dev_err(priv->dev, "failed to get clock %s\n", + sky1_audss_clks_names[i]); + return PTR_ERR(priv->clks[i]); + } + } + + return 0; +} + +static int sky1_audss_clks_enable(struct sky1_audss_clks_priv *priv) +{ + int i, err; + + for (i = 0; i < SKY1_AUDSS_CLKS_NUM; i++) { + err = clk_prepare_enable(priv->clks[i]); + if (err) { + dev_err(priv->dev, "failed to enable clock %s\n", + sky1_audss_clks_names[i]); + goto err_clks; + } + } + + return 0; + +err_clks: + while (--i >= 0) + clk_disable_unprepare(priv->clks[i]); + + return err; +} + +static void sky1_audss_clks_disable(struct sky1_audss_clks_priv *priv) +{ + int i; + + for (i = 0; i < SKY1_AUDSS_CLKS_NUM; i++) + clk_disable_unprepare(priv->clks[i]); +} + +static int sky1_audss_clks_set_rate(struct sky1_audss_clks_priv *priv) +{ + int i, err; + + for (i = 0; i < SKY1_AUDSS_CLKS_NUM; i++) { + err = clk_set_rate(priv->clks[i], clk_rate_default[i]); + if (err) { + dev_err(priv->dev, "failed to set clock rate %s\n", + sky1_audss_clks_names[i]); + return err; + } + } + + return 0; +} + +static void sky1_audss_clks_get_rate(struct sky1_audss_clks_priv *priv) +{ + int i; + u32 rate; + + /* + * audio_clk0/1 feeded by audio_pll0, and audio_clk2/3 feeded by audio_pll1, + * need get clk rate after all clocks configed, since they have depenency. + */ + for (i = 0; i < SKY1_AUDSS_CLKS_NUM; i++) { + /* NOTE: + * For now, need call clk_get_rate() for audio ss top clocks, + * so that these clocks' rate would be updated via clock framework, + * then clock rate can propagate up to child clocks. + */ + rate = clk_get_rate(priv->clks[i]); + dev_info(priv->dev, "%s: set rate = %d, get rate = %d\n", + sky1_audss_clks_names[i], clk_rate_default[i], rate); + } +} + +static struct clk_hw *acpi_audss_get_clk_hw(struct device *dev, int clk_id) +{ + if (clk_data && (clk_data->num >= clk_id)) + return clk_data->hws[clk_id]; + + return NULL; +} + +/* register sky1 audio subsystem clocks */ +static int sky1_audss_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct reset_control *rst_noc; + struct sky1_audss_clks_priv *priv; + struct clk_hw **clk_table; + void __iomem *rcsu_base; + struct device_node *parent_np; + struct regmap *regmap_cru; + int i, ret; + + parent_np = of_get_parent(pdev->dev.of_node); + regmap_cru = syscon_node_to_regmap(parent_np); + of_node_put(parent_np); + + if (IS_ERR_OR_NULL(regmap_cru)) + regmap_cru = device_syscon_regmap_lookup_by_property(dev, + "audss_cru"); + if (IS_ERR_OR_NULL(regmap_cru)) + return -EINVAL; + + clk_data = devm_kzalloc(&pdev->dev, + struct_size(clk_data, hws, AUDSS_MAX_CLKS), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = AUDSS_MAX_CLKS; + clk_table = clk_data->hws; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->regmap_cru = regmap_cru; + + + ret = sky1_audss_clks_get(priv); + if (ret) { + dev_err(dev, "failed to get clocks\n"); + return ret; + } + + platform_set_drvdata(pdev, priv); + + /* + * Enable runtime PM here to allow the clock core using runtime PM + * for the registered clocks. + */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret = sky1_audss_clks_set_rate(priv); + if (ret) { + dev_err(dev, "failed to set clocks rate\n"); + goto fail_clks_set; + } + + /* + * enable audio ss clocks since rcsu slave end feeded by + * audio ss internal clocks, but rcsu master end feeded by + * cgc module. + */ + ret = sky1_audss_clks_enable(priv); + if (ret) { + dev_err(dev, "failed to enable clocks\n"); + goto fail_clks_enable; + } + + sky1_audss_clks_get_rate(priv); + + /* reset audio subsystem */ + rst_noc = devm_reset_control_get(dev, "noc"); + if (IS_ERR(rst_noc)) { + dev_err(dev, "failed to get noc reset\n"); + ret = PTR_ERR(rst_noc); + goto fail_reset; + } + priv->rst_noc = rst_noc; + + /* reset */ + reset_control_assert(rst_noc); + usleep_range(1, 2); + + /* release reset */ + reset_control_deassert(rst_noc); + + rcsu_base = ioremap(SKY1_AUDSS_RCSU_ADDR, SKY1_AUDSS_RCSU_LEN); + priv->rcsu_base = rcsu_base; + + /* set audio ss address remap */ + writel(SKY1_AUDSS_RCSU_REMAP_VAL, rcsu_base + SKY1_AUDSS_RCSU_REMAP); + + /* set and enable audio ss timeout */ + writel(SKY1_AUDSS_RCSU_TIMEOUT_EN | + FIELD_PREP(SKY1_AUDSS_RCSU_TIMEOUT_MASK, SKY1_AUDSS_RCSU_TIMEOUT_VAL), + rcsu_base + SKY1_AUDSS_RCSU_TIMEOUT); + + /* audio_clk4 clock fixed divider */ + clk_table[CLK_AUD_CLK4_DIV2] = + devm_clk_hw_register_fixed_factor(dev, + "audio_clk4_div2", + "audio_clk4", + CLK_GET_RATE_NOCACHE, + 1, 2); + clk_table[CLK_AUD_CLK4_DIV4] = + devm_clk_hw_register_fixed_factor(dev, + "audio_clk4_div4", + "audio_clk4", + CLK_GET_RATE_NOCACHE, + 1, 4); + + /* audio_clk5 clock fixed divider */ + clk_table[CLK_AUD_CLK5_DIV2] = + devm_clk_hw_register_fixed_factor(dev, + "audio_clk5_div2", + "audio_clk5", + CLK_GET_RATE_NOCACHE, + 1, 2); + + for (i = 0; i < ARRAY_SIZE(audss_clks); i++) + clk_table[audss_clks[i].id] = sky1_audss_clk_register(dev, + audss_clks[i].name, + audss_clks[i].parent_names, + audss_clks[i].num_parents, + regmap_cru, + audss_clks[i].mux_cfg, + audss_clks[i].div_cfg, + audss_clks[i].gate_cfg, + audss_clks[i].flags, + &lock); + + for (i = 0; i < clk_data->num; i++) { + if (IS_ERR(clk_table[i])) { + ret = PTR_ERR(clk_table[i]); + dev_err(dev, "failed to register clock %d, ret:%d\n", i, ret); + goto fail; + } + } + + if (ACPI_COMPANION(dev)) + ret = cix_acpi_parse_clkt(dev, "CLKA", acpi_audss_get_clk_hw); + else + ret = devm_of_clk_add_hw_provider(dev, + of_clk_hw_onecell_get, clk_data); + if (ret) { + dev_err(dev, "failed to add clock provider: %d\n", ret); + goto fail; + } + + pm_runtime_put_sync(dev); + + return 0; + +fail: + iounmap(rcsu_base); +fail_reset: + pm_runtime_put_sync(dev); +fail_clks_enable: +fail_clks_set: + pm_runtime_disable(dev); + return ret; +} + +static int sky1_audss_clk_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev); + + iounmap(priv->rcsu_base); + + if (!pm_runtime_status_suspended(dev)) + pm_runtime_force_suspend(dev); + + pm_runtime_disable(dev); + + return 0; +} + +static int __maybe_unused sky1_audss_clk_runtime_suspend(struct device *dev) +{ + struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(reg_save); i++) + regmap_read(priv->regmap_cru, reg_save[i][0], ®_save[i][1]); + + sky1_audss_clks_disable(priv); + + return 0; +} + +static int __maybe_unused sky1_audss_clk_runtime_resume(struct device *dev) +{ + struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev); + int i, ret; + + ret = sky1_audss_clks_enable(priv); + if (ret) { + dev_err(dev, "failed to enable clocks\n"); + return ret; + } + + /* release reset */ + reset_control_deassert(priv->rst_noc); + + writel(SKY1_AUDSS_RCSU_REMAP_VAL, priv->rcsu_base + SKY1_AUDSS_RCSU_REMAP); + + for (i = 0; i < ARRAY_SIZE(reg_save); i++) + regmap_write(priv->regmap_cru, reg_save[i][0], reg_save[i][1]); + + return 0; +} + +static const struct dev_pm_ops sky1_audss_clk_pm_ops = { + SET_RUNTIME_PM_OPS(sky1_audss_clk_runtime_suspend, + sky1_audss_clk_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static const struct acpi_device_id sky1_audss_clk_acpi_match[] = { + { "CIXH6061", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, sky1_audss_clk_acpi_match); + +static const struct of_device_id sky1_audss_clk_of_match[] = { + { .compatible = "cix,sky1-audss-clock",}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, sky1_audss_clk_of_match); + +static struct platform_driver sky1_audss_clk_driver = { + .probe = sky1_audss_clk_probe, + .remove = sky1_audss_clk_remove, + .driver = { + .name = "sky1-audss-clk", + .suppress_bind_attrs = true, + .of_match_table = sky1_audss_clk_of_match, + .acpi_match_table = ACPI_PTR(sky1_audss_clk_acpi_match), + .pm = &sky1_audss_clk_pm_ops, + }, +}; +module_platform_driver(sky1_audss_clk_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Joakim Zhang "); +MODULE_DESCRIPTION("Cixtech Sky1 Audio Subsystem Clock Controller Driver"); diff --git a/drivers/clk/cix/clk.c b/drivers/clk/cix/clk.c new file mode 100644 index 000000000000..96611ce114f2 --- /dev/null +++ b/drivers/clk/cix/clk.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + *Copyright 2024 Cix Technology Group Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include "clk.h" + +#ifndef MODULE + +static bool cix_uart_clocks_keep; +static int cix_uart_clocks_enabled; +static struct clk **cix_uart_clocks; + +static int __init cix_uart_clocks_keep_param(char *str) +{ + cix_uart_clocks_keep = 1; + + return 0; +} +early_param("earlycon", cix_uart_clocks_keep_param); + +void cix_uart_clocks_register(void) +{ + unsigned int i, clk_count = 0; + + cix_uart_clocks_enabled = 0; + +#ifdef CONFIG_OF + if (!of_stdout || !cix_uart_clocks_keep) + return; + + clk_count = of_clk_get_parent_count(of_stdout); + pr_info("%s: uart clock count=%d!\n", __func__, clk_count); + + if (!clk_count) { + pr_err("%s: uart clock no need to register, count=%d!\n", + __func__, clk_count); + return; + } + + + cix_uart_clocks = kcalloc(clk_count, sizeof(struct clk *), GFP_KERNEL); + if (!cix_uart_clocks) + return; + + for (i = 0; i < clk_count; i++) { + cix_uart_clocks[cix_uart_clocks_enabled] = of_clk_get(of_stdout, i); + + if (IS_ERR(cix_uart_clocks[cix_uart_clocks_enabled])) + return; + + if (cix_uart_clocks[cix_uart_clocks_enabled]) + clk_prepare_enable(cix_uart_clocks[cix_uart_clocks_enabled++]); + } +#endif +} +EXPORT_SYMBOL_GPL(cix_uart_clocks_register); + +static int __init cix_clk_disable_uart(void) +{ + if (cix_uart_clocks_keep && cix_uart_clocks_enabled) { + int i; + + for (i = 0; i < cix_uart_clocks_enabled; i++) { + clk_disable_unprepare(cix_uart_clocks[i]); + clk_put(cix_uart_clocks[i]); + } + kfree(cix_uart_clocks); + } + + return 0; +} +late_initcall_sync(cix_clk_disable_uart); +#endif + +MODULE_AUTHOR("Copyright 2024 Cix Technology Group Co., Ltd."); +MODULE_DESCRIPTION("Cix clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/cix/clk.h b/drivers/clk/cix/clk.h new file mode 100644 index 000000000000..32d547ada9ef --- /dev/null +++ b/drivers/clk/cix/clk.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2024 Cix Technology Group Co., Ltd. + */ + +#ifndef __CIX_CLK_H__ +#define __CIX_CLK_H__ + +#include + +#ifndef MODULE +void cix_uart_clocks_register(void); +#else +static inline void cix_uart_clocks_register(void) +{ +} +#endif +#endif diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 8208a3d89563..a039335b56a9 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -134,6 +134,12 @@ config RDA_TIMER help Enables the support for the RDA Micro timer driver. +config TIMER_SKY1_GPT + bool "SKY1 timer driver" + select CLKSRC_MMIO + help + Enables the support for the cix sky1 timer driver. + config SUN4I_TIMER bool "Sun4i timer driver" if COMPILE_TEST depends on HAS_IOMEM diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 368c3461dab8..b1b16decf07f 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_MILBEAUT_TIMER) += timer-milbeaut.o obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o obj-$(CONFIG_RDA_TIMER) += timer-rda.o +obj-$(CONFIG_TIMER_SKY1_GPT) += timer-sky1-gpt.o obj-$(CONFIG_ARC_TIMERS) += arc_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o diff --git a/drivers/clocksource/timer-sky1-gpt.c b/drivers/clocksource/timer-sky1-gpt.c new file mode 100644 index 000000000000..4d2e9e314d47 --- /dev/null +++ b/drivers/clocksource/timer-sky1-gpt.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIMER_NAME "sky1_timer" +/*timer registers */ +#define LDINIT_RW 0x0000 /*Contains 32bit initial value to be loaded to Timer*/ +#define CAPT_CNT_0 0x0004 /*Contains 32bit to store the count value from Timer when captured */ +#define CAPT_CNT_1 0x0008 /*Contains 32bit to store the count value from Timer when captured */ +#define CAPT_CNT_2 0x000C /*Contains 32bit to store the count value from Timer when captured */ +#define CAPT_CNT_3 0x0010 /*Contains 32bit to store the count value from Timer when captured */ +#define CAPT_CNT_4 0x0014 /*Contains 32bit to store the count value from Timer when captured */ +#define PULSE_CNT 0x0018 /*Reserved*/ +#define FREE_CNT 0x001C /*Contains 32bit to store real-time Free-running count value*/ +#define COMP 0x0020 /*Contains 32bit to store the compare value in Free-running mode*/ +#define TCTL 0x0024 /*Control register for Timer*/ +#define PWMH 0x0028 /*Contains PWM_HIGH_TIME value to be loaded to Timer*/ +#define PWMPRD 0x002C /*Contains PWM_PERIOD value to be loaded to timer*/ +#define INTSTAT 0x0030 /*Interrupt status register*/ +#define INTCLR 0x0034 /*Clear interrupt status*/ + +/*timer function mode */ +#define GENER_MODE 0x0 /*Generate mode (default)*/ +#define CAP_MODE 0x1 /*Capture mode*/ +#define FREERUN_MODE 0x2 /*Free-running mode*/ +#define PWM_MODE 0x3 /*PWM mode*/ +#define PULSE_MODE 0x4 /*Pulse monitor mode*/ + +/*TCTL register */ +#define ENABLE (1 << 17) /*Enable Timer (This bit should be set finally)*/ +#define FREEENABLE (1 << 15) /*Free-running compare enabled*/ +#define TWID (1 << 12) /*Timer WIDTH 0:32bit 1:64bit */ +#define UPENABLE (0 << 7) /*Count up mode */ +#define INTENABLE (1 << 6) /*Interrupt enabled*/ +#define LOADENABLE (1 << 5) /*load LDINIT value to Timer*/ +#define RELOADENABLE (1 << 4) /*Reload generate value*/ + +/*timer width register*/ +#define TWIDENABLE (1 << 12) /*64-bit timer enable*/ + +/*INTCLR register*/ +#define FREE_INTCLEAR (1 << 5) /*clear free-running mode interrupt status*/ + +/*INTSTATUS register*/ +#define FREE_INTSTATUS (1 << 5) /*free-running mode interrupt status*/ + +/* OFFSET between odd timer and even timer*/ +#define TIMER_OFFSET 0x1000 + +struct sky1_timer { + void __iomem *base; + int irq; + struct clock_event_device ced; + struct clk *pclk, *tclk; + struct reset_control *func_reset; +}; + +static inline struct sky1_timer *to_sky1_timer(struct clock_event_device *ced) +{ + return container_of(ced, struct sky1_timer, ced); +} + +static void sky1_gpt_irq_disable(struct sky1_timer *sky1tm) +{ + u32 tmp; + + tmp = readl_relaxed(sky1tm->base + TIMER_OFFSET + TCTL); + writel_relaxed(tmp & ~INTENABLE, sky1tm->base + TIMER_OFFSET + TCTL); +} + +static void sky1_gpt_irq_enable(struct sky1_timer *sky1tm) +{ + u32 tmp; + + tmp = readl_relaxed(sky1tm->base + TIMER_OFFSET + TCTL); + writel_relaxed(tmp | INTENABLE, sky1tm->base + TIMER_OFFSET + TCTL); +} + +static void sky1_gpt_irq_acknowledge(struct sky1_timer *sky1tm) +{ + writel_relaxed(FREE_INTCLEAR, sky1tm->base + TIMER_OFFSET + INTCLR); +} + +static void sky1_gpt_setup_tctl(struct sky1_timer *sky1tm) +{ + u32 tctl_val; + + tctl_val = FREEENABLE | FREERUN_MODE | INTENABLE; + writel_relaxed(tctl_val, sky1tm->base + TCTL); + + tctl_val = FREEENABLE | TWID | FREERUN_MODE | INTENABLE; + writel_relaxed(tctl_val, sky1tm->base + TIMER_OFFSET + TCTL); + + /* + * Enable bit should be set no earlier than + * any other bits or registers + */ + tctl_val = ENABLE | FREEENABLE | FREERUN_MODE | INTENABLE; + writel_relaxed(tctl_val, sky1tm->base + TCTL); + + tctl_val = ENABLE | FREEENABLE | TWID | FREERUN_MODE | INTENABLE; + writel_relaxed(tctl_val, sky1tm->base + TIMER_OFFSET + TCTL); +} + + +static void __iomem *sched_clock_reg; + +/* + * To get the value from the Global Timer Counter register proceed as follows: + * 1. Read the upper 32-bit timer counter register + * 2. Read the lower 32-bit timer counter register + * 3. Read the upper 32-bit timer counter register again. If the value is + * different to the 32-bit upper value read previously, go back to step 2. + * Otherwise the 64-bit timer counter value is correct. + */ +static u64 notrace _sky1_gt_counter_read(void) +{ + u64 counter; + u32 lower; + u32 upper, old_upper; + + upper = readl_relaxed(sched_clock_reg + TIMER_OFFSET); + do { + old_upper = upper; + lower = readl_relaxed(sched_clock_reg); + upper = readl_relaxed(sched_clock_reg + TIMER_OFFSET); + } while (upper != old_upper); + + counter = upper; + counter <<= 32; + counter |= lower; + return counter; +} + +static u64 __maybe_unused notrace sky1_read_sched_clock(void) +{ + return sched_clock_reg ? _sky1_gt_counter_read() : 0; +} + +static u64 sky1_gt_clocksource_read(struct clocksource *cs) +{ + return _sky1_gt_counter_read(); +} + +static struct clocksource clocksource_gpt = { + .name = "sky1_counter", + .rating = 200, + .read = sky1_gt_clocksource_read, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static int __init sky1_clocksource_init(struct sky1_timer *sky1tm) +{ + unsigned int c = clk_get_rate(sky1tm->tclk); + void __iomem *reg = sky1tm->base + FREE_CNT; + + sched_clock_reg = reg; + + //sched_clock_register(sky1_read_sched_clock, 64, c); + + return clocksource_register_hz(&clocksource_gpt, c); +} + +/* + * clock event + * To ensure that updates to comparator value register do not set the + * Interrupt Status Register proceed as follows: + * 1. Clear the Comp Enable bit in the Timer Control Register. + * 2. Write the lower 32-bit Comparator Value Register. + * 3. Write the upper 32-bit Comparator Value Register. + * 4. Set the Comp Enable bit and, if necessary, the IRQ enable bit. + */ +static int sky1_set_next_event(unsigned long evt, struct clock_event_device *ced) +{ + struct sky1_timer *sky1tm = to_sky1_timer(ced); + u64 tcn; + + tcn = _sky1_gt_counter_read(); + tcn = tcn + evt; + + /* Set event time into far-far future */ + writel_relaxed(tcn >> 32, sky1tm->base + COMP + TIMER_OFFSET); + writel_relaxed((u32)tcn, sky1tm->base + COMP); + + return tcn < _sky1_gt_counter_read() ? -ETIME : 0; +} + +static int sky1_shutdown(struct clock_event_device *ced) +{ + struct sky1_timer *sky1tm = to_sky1_timer(ced); + u64 tcn; + + /* Disable interrupt */ + sky1_gpt_irq_disable(sky1tm); + + tcn = _sky1_gt_counter_read(); + + /* Set event time into far-far future */ + writel_relaxed((tcn - 3) >> 32, sky1tm->base + COMP + TIMER_OFFSET); + writel_relaxed((u32)(tcn - 3), sky1tm->base + COMP); + + /* Clear pending interrupt */ + sky1_gpt_irq_acknowledge(sky1tm); + + return 0; +} + +static int sky1_tick_resume(struct clock_event_device *ced) +{ + struct sky1_timer *sky1tm = to_sky1_timer(ced); + + /* reset timer */ + reset_control_reset(sky1tm->func_reset); + + sky1_gpt_setup_tctl(sky1tm); + + sky1_shutdown(ced); + + return 0; +} + +static int sky1_set_oneshot(struct clock_event_device *ced) +{ + struct sky1_timer *sky1tm = to_sky1_timer(ced); + u64 tcn; + + /* Disable interrupt */ + sky1_gpt_irq_disable(sky1tm); + + if (!clockevent_state_oneshot(ced)) { + tcn = _sky1_gt_counter_read(); + /* Set event time into far-far future */ + writel_relaxed((tcn - 3) >> 32, sky1tm->base + COMP + TIMER_OFFSET); + writel_relaxed((u32)(tcn - 3), sky1tm->base + COMP); + + /* Clear pending interrupt */ + sky1_gpt_irq_acknowledge(sky1tm); + } + + /* + * Do not put overhead of interrupt enable/disable into + * sky1_set_next_event(), the core has about 4 minutes + * to call sky1_set_next_event() or shutdown clock after + * mode switching + */ + sky1_gpt_irq_enable(sky1tm); + return 0; +} + +/* + * IRQ handler for the timer + */ +static irqreturn_t sky1_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ced = dev_id; + struct sky1_timer *sky1tm = to_sky1_timer(ced); + + sky1_gpt_irq_acknowledge(sky1tm); + + ced->event_handler(ced); + + return IRQ_HANDLED; +} + +static int __init sky1_clockevent_init(struct sky1_timer *sky1tm) +{ + struct clock_event_device *ced = &sky1tm->ced; + + ced->name = TIMER_NAME; + ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ; + ced->set_next_event = sky1_set_next_event; + ced->set_state_shutdown = sky1_shutdown; + ced->set_state_oneshot = sky1_set_oneshot; + ced->set_state_oneshot_stopped = sky1_shutdown; + ced->tick_resume = sky1_tick_resume; + ced->rating = 200; + ced->cpumask = cpu_possible_mask; + ced->irq = sky1tm->irq; + clockevents_config_and_register(ced, clk_get_rate(sky1tm->tclk), 1, UINT_MAX); + + return request_irq(sky1tm->irq, sky1_timer_interrupt, + IRQF_TIMER, TIMER_NAME, ced); +} + +static int sky1_timer_probe(struct platform_device *pdev) +{ + struct sky1_timer *sky1tm; + static int initialized; + int ret = 0; + + /* Support one instance only */ + if (initialized) + return 0; + + sky1tm = devm_kzalloc(&pdev->dev, sizeof(*sky1tm), GFP_KERNEL); + if (!sky1tm) + return -ENOMEM; + + /* Acpi resource parse */ + sky1tm->base = devm_platform_ioremap_resource(pdev, 0); + if (!sky1tm->base) + return -ENXIO; + + sky1tm->irq = platform_get_irq(pdev, 0); + if (sky1tm->irq <= 0) + return -EINVAL; + + sky1tm->pclk = devm_clk_get(&pdev->dev, "fch_timer_apb_clk"); + if (IS_ERR(sky1tm->pclk)) + return -EINVAL; + + sky1tm->tclk = devm_clk_get(&pdev->dev, "fch_timer_func_clk"); + if (IS_ERR(sky1tm->tclk)) + return -EINVAL; + + clk_prepare_enable(sky1tm->pclk); + clk_prepare_enable(sky1tm->tclk); + + sky1tm->func_reset = devm_reset_control_get_optional_shared(&pdev->dev, "func_reset"); + if (IS_ERR(sky1tm->func_reset)) { + dev_err(&pdev->dev, "[%s:%d]get reset error\n", __func__, __LINE__); + ret = PTR_ERR(sky1tm->func_reset); + goto err_clk_dis; + } + + /* reset timer */ + if (!screen_info.lfb_linelength) /* already init in uefi */ + reset_control_reset(sky1tm->func_reset); + + sky1_gpt_setup_tctl(sky1tm); + + platform_set_drvdata(pdev, sky1tm); + + /* init and register the timer to the framework */ + ret = sky1_clocksource_init(sky1tm); + if (ret) + return ret; + + sky1_clockevent_init(sky1tm); + + initialized = 1; + + dev_info(&pdev->dev, "sky1 gpt timer init done\n"); + + return 0; + +err_clk_dis: + clk_disable_unprepare(sky1tm->pclk); + clk_disable_unprepare(sky1tm->tclk); + return ret; +} + +static const struct of_device_id sky1_timer_match_table[] = { + { .compatible = "cix,sky1-gpt" }, + { /* sentinel */ }, +}; + +static const struct acpi_device_id sky1_timer_acpi_match[] = { + { "CIXH1007", }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, sky1_timer_acpi_match); + +static struct platform_driver sky1_timer_driver = { + .driver = { + .name = TIMER_NAME, + .of_match_table = sky1_timer_match_table, + .acpi_match_table = ACPI_PTR(sky1_timer_acpi_match), + }, + .probe = sky1_timer_probe, +}; +module_platform_driver(sky1_timer_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jerry Zhu "); diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 253d3d58ebd6..70f88ba86230 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -741,6 +741,13 @@ config PHYTIUM_DDMA help Enable support for Phytium PE220x DDMA controller. +config ARM_DMA350 + tristate "ARM DMA350 support" + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable support for ARM DMA350 controller. + # driver files source "drivers/dma/bestcomm/Kconfig" diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index a1b72ed95891..113cb2c66cb1 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_XGENE_DMA) += xgene-dma.o obj-$(CONFIG_ST_FDMA) += st_fdma.o obj-$(CONFIG_FSL_DPAA2_QDMA) += fsl-dpaa2-qdma/ obj-$(CONFIG_INTEL_LDMA) += lgm/ +obj-$(CONFIG_ARM_DMA350) += arm_dma350.o obj-y += mediatek/ obj-y += qcom/ diff --git a/drivers/dma/arm_dma350.c b/drivers/dma/arm_dma350.c new file mode 100644 index 000000000000..fb68db31a2b1 --- /dev/null +++ b/drivers/dma/arm_dma350.c @@ -0,0 +1,1408 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + *Driver for ARM DMA-350 controller + * + *Copyright 2024 Cix Technology Group Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dma350_ch_drv.h" +#include "virt-dma.h" + +#define DRIVER_NAME "arm-dma350" +#define DMA_ALIGN 4 +#define DMA_MAX_SIZE (0xFFFFFFFF) +#define MAX_BURST_LEN 0xF +#define LLI_BLOCK_SIZE (4 * PAGE_SIZE) +#define CHANNEL_IDX(id) (0x1000 + id * 0x100) +#define CMD_LINK_LEN (512) +#define MAX_DESC_NUM 16 +#define MAX_CHAN_NUM 8 +#define RCSU_OFFSET 0x10000 +#define ARM_DMA350__PM_TIMEOUT_MS 500 + +#define AUDSS_DMAC_INFO_AP_IRQ 0x54 +#define AUDSS_OFFSET (0x30000000-0xc0000000) + +enum arm_dma350_burst_width_t { + DMA350_DMA_WIDTH_8BIT = 0, + DMA350_DMA_WIDTH_16BIT = 1, + DMA350_DMA_WIDTH_32BIT = 2, + DMA350_DMA_WIDTH_64BIT = 3 +}; + +struct dma350_desc_hw { + dma_addr_t saddr; + dma_addr_t daddr; + u32 x_len; + u32 dest_addr_inc; + u32 src_addr_inc; + u32 trig_sel; + u32 burst_size; +} __aligned(32); + +struct arm_dma350_desc_sw { + struct virt_dma_desc vd; + dma_addr_t desc_hw_lli; + size_t desc_num; + size_t size; + struct dma350_desc_hw *desc_hw; +}; + +struct arm_dma350_phy; + +struct arm_dma350_chan { + struct dma_slave_config slave_cfg; + u32 id; /* Request phy chan id */ + u32 req_line; + u32 priority; + u32 cyclic; + u32 transize; + struct virt_dma_chan vc; + struct arm_dma350_phy *phy; + struct list_head node; + dma_addr_t dev_addr; + enum dma_status status; +}; + +struct arm_dma350_phy { + u32 idx; + void __iomem *base; + struct arm_dma350_chan *vchan; + struct arm_dma350_desc_sw *ds_run; + struct arm_dma350_desc_sw *ds_done; +}; + +struct host_remote_map { + u32 reg_host_addr; + u32 reg_remote_addr; + u32 ram_host_addr; + u32 ram_remote_addr; +}; + +struct arm_dma350_drvdata { + bool is_exist_pause; +}; + +struct arm_dma350_dev { + struct dma_device slave; + void __iomem *base; + spinlock_t lock; /* lock for ch and phy */ + struct list_head chan_pending; + struct arm_dma350_phy *phy; + struct arm_dma350_chan *chans; + struct clk *clk; + struct dma_pool *pool; + u32 max_channels; + u32 max_requests; + int irq; + struct host_remote_map map; + struct regmap *regmap; + struct arm_dma350_drvdata *drvdata; + struct reset_control *dma_reset; + bool is_clk_enable_atomic; +}; + +#define to_arm_dma350(dmadev) container_of(dmadev, struct arm_dma350_dev, slave) + +static u32 dmachan[MAX_CHAN_NUM]; +static u32 desnum[MAX_CHAN_NUM]; + +static struct dma350_cmdlink_gencfg_t cmdlink_cfg[MAX_CHAN_NUM][MAX_DESC_NUM]; +static u32 *cmd0[MAX_CHAN_NUM]; + +static dma_addr_t phy_cmd0[MAX_CHAN_NUM]; + +static struct arm_dma350_chan *to_dma350_chan(struct dma_chan *chan) +{ + return container_of(chan, struct arm_dma350_chan, vc.chan); +} + +static u32 *dma350_cmdlink_generate(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + u32 *buffer, u32 *bit) +{ + u32 *cfg; + u32 header_sel; + + cfg = (u32 *) &cmdlink_cfg->cfg; + *(buffer) = cmdlink_cfg->header; + buffer++; + /* + *Note: REGCLEAR (Bit 0) has no associated field and Bit 1 is reserved, + *cfg starts from Bit 2 + */ + for (header_sel = (0x1UL << 2); header_sel; header_sel <<= 1) { + if (cmdlink_cfg->header & header_sel) { + (*bit)++; + *(buffer) = *(cfg); + buffer++; + cfg++; + } else { + cfg++; + } + } + return buffer; +} + +static void dma350_cmdlink_init(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + static const struct dma350_cmdlink_gencfg_t default_cmdlink = { + .header = 0, + .cfg = {.intren = DMA350_CH_INTREN_RESET_VALUE, + .ctrl = DMA350_CH_CTRL_RESET_VALUE, + .srcaddr = 0, + .srcaddrhi = 0, + .desaddr = 0, + .desaddrhi = 0, + .xsize = 0, + .xsizehi = 0, + .srctranscfg = DMA350_CH_SRCTRANSCFG_RESET_VALUE, + .destranscfg = DMA350_CH_DESTRANSCFG_RESET_VALUE, + .xaddrinc = 0, + .yaddrstride = 0, + .fillval = 0, + .ysize = 0, + .tmpltcfg = 0, + .srctmplt = 0, + .destmplt = 0, + .srctrigincfg = 0, + .destrigincfg = 0, + .trigoutcfg = 0, + .gpoen0 = 0, + .reserved0 = 0, + .gpoval0 = 0, + .reserved1 = 0, + .streamintcfg = 0, + .reserved2 = 0, + .linkattr = 0, + .autocfg = DMA350_CH_AUTOCFG_RESET_VALUE, + .linkaddr = DMA350_CH_LINKADDR_RESET_VALUE, + .linkaddrhi = 0 } + }; + *cmdlink_cfg = default_cmdlink; +} + +static void arm_dma350_terminate_chan(struct arm_dma350_phy *phy) +{ + dma350_ch_cmd(phy->base + DMA350_REG_CMD, DMA350_CH_CMD_STOPCMD); +} + +static void arm_dma350_nonsec_intren(struct arm_dma350_dev *d) +{ + writel_relaxed(INTREN_ANYCHINTR_ENABLE, d->base + DMA350_REG_CHINTRSTATUS0 + DMA350_NONSSEC_CTRL); +} + +static void arm_dma350_clear_chan(struct arm_dma350_phy *phy) +{ + dma350_ch_cmd(phy->base + DMA350_REG_CMD, DMA350_CH_CMD_CLEARCMD); +} + +static void arm_dma350_set_xsize(struct arm_dma350_phy *phy, u32 xsize) +{ + u32 val = 0; + + val = ((xsize & 0x0000FFFFUL) << 16U) | (xsize & 0x0000FFFFUL); + writel_relaxed(val, phy->base + DMA350_REG_XSIZE); + val = (xsize & 0xFFFF0000UL) | ((xsize & 0xFFFF0000UL) >> 16U); + writel_relaxed(val, phy->base + DMA350_REG_XSIZEHI); +} + +static void arm_dma350_set_desc(struct arm_dma350_phy *phy, struct dma350_desc_hw *hw) +{ + writel_relaxed(hw->saddr, phy->base + DMA350_REG_SRCADDR); + writel_relaxed(hw->daddr, phy->base + DMA350_REG_DESADDR); + arm_dma350_set_xsize(phy, hw->x_len); + dma350_ch_cmd(phy->base + DMA350_REG_CMD, DMA350_CH_CMD_ENABLECMD); +} + +static void arm_dma350_init_state(struct arm_dma350_phy *phy) +{ + dma350_ch_enable_intr(phy->base + DMA350_REG_INTREN, + DMA350_CH_INTREN_DONE | DMA350_CH_INTREN_ERR | + DMA350_CH_INTREN_DISABLED | + DMA350_CH_INTREN_STOPPED); +} + +static int arm_dma350_start_txd(struct arm_dma350_chan *c) +{ + struct virt_dma_desc *vd = vchan_next_desc(&c->vc); + struct dma_slave_config *cfg = &c->slave_cfg; + u32 timeout = 0; + + if (!c->phy) + return -EAGAIN; + if (vd) { + struct arm_dma350_desc_sw *ds = container_of(vd, struct arm_dma350_desc_sw, vd); + /* + * fetch and remove request from vc->desc_issued + * so vc->desc_issued only contains desc pending + */ + if (!c->cyclic) + list_del(&ds->vd.node); + + c->phy->ds_run = ds; + c->phy->ds_done = NULL; + + /* start dma */ + if (c->cyclic) { + dma350_ch_set_xsize32(c->phy->base + DMA350_REG_XSIZE, 0, 0); + writel_relaxed(0, c->phy->base + DMA350_REG_INTREN); + dma350_ch_cmd(c->phy->base + DMA350_REG_CMD, DMA350_CH_CMD_ENABLECMD); + dma350_ch_set_linkaddr32(c->phy->base + DMA350_REG_LINKADDR, + (u32)(phy_cmd0[c->id] + AUDSS_OFFSET)); + dma350_ch_enable_linkaddr(c->phy->base + DMA350_REG_LINKADDR); + dma350_ch_cmd(c->phy->base + DMA350_REG_CMD, DMA350_CH_CMD_ENABLECMD); + if (cfg->direction == DMA_MEM_TO_DEV) { + timeout = 0; + while ((!(readl_relaxed(c->phy->base + DMA350_REG_STATUS) & + DMA350_CH_STATUS_STAT_DESTRIGINWAIT_Msk))) { + udelay(10); + timeout++; + if (timeout > 10) { + pr_info("channel %d timeout\n", c->id); + break; + } + } + } + if (cfg->direction == DMA_DEV_TO_MEM) { + timeout = 0; + while ((!(readl_relaxed(c->phy->base + DMA350_REG_STATUS) & + DMA350_CH_STATUS_STAT_SRCTRIGINWAIT_Msk))) { + udelay(10); + timeout++; + if (timeout > 10) { + pr_info("channel %d timeout\n", c->id); + break; + } + } + } + } else { + arm_dma350_set_desc(c->phy, ds->desc_hw); + } + return 0; + } + c->phy->ds_done = NULL; + c->phy->ds_run = NULL; + + return -EAGAIN; +} + +static void arm_dma350_task(struct arm_dma350_dev *d) +{ + struct arm_dma350_phy *p; + struct arm_dma350_chan *c; + unsigned int pch, pch_alloc = 0; + unsigned long flags; + + /* check new channel request in d->chan_pending */ + spin_lock_irqsave(&d->lock, flags); + while (!list_empty(&d->chan_pending)) { + c = list_first_entry(&d->chan_pending, + struct arm_dma350_chan, node); + p = &d->phy[c->id]; + /* remove from d->chan_pending */ + list_del_init(&c->node); + pch_alloc |= 1 << c->id; + /* Mark this channel allocated */ + p->vchan = c; + c->phy = p; + } + spin_unlock_irqrestore(&d->lock, flags); + for (pch = 0; pch < d->max_channels; pch++) { + + if (pch_alloc & (1 << pch)) { + p = &d->phy[pch]; + c = p->vchan; + if (c) { + spin_lock_irqsave(&c->vc.lock, flags); + arm_dma350_start_txd(c); + spin_unlock_irqrestore(&c->vc.lock, flags); + } + } + } +} + +static u32 arm_dma_ch_getstatus(struct arm_dma350_dev *d, u32 ch_id) +{ + return readl_relaxed(d->base + DMA350_REG_STATUS + CHANNEL_IDX(ch_id)); +} + +static u32 arm_dma_ch_clrstatus(struct arm_dma350_dev *d, u32 ch_id) +{ + u32 val = arm_dma_ch_getstatus(d, ch_id); + + val &= DMA350_CH_INTREN_DONE | DMA350_CH_INTREN_ERR | DMA350_CH_INTREN_DISABLED | DMA350_CH_INTREN_STOPPED; + writel_relaxed(val << 16, d->base + DMA350_REG_STATUS + CHANNEL_IDX(ch_id)); + return 0; +} + +static irqreturn_t arm_dma350_int_handler(int irq, void *dev_id) +{ + struct arm_dma350_dev *d = (struct arm_dma350_dev *)dev_id; + struct arm_dma350_phy *p; + struct arm_dma350_chan *c; + u32 chstatus = 0, ch_idx = 0; + + while (ch_idx < MAX_CHAN_NUM) { + chstatus = arm_dma_ch_getstatus(d, ch_idx); + if (chstatus == 0) { + ch_idx++; + continue; + } + if (chstatus & DMA350_CH_STATUS_INTR_ERR) { + writel_relaxed(DMA350_CH_STATUS_STAT_ERR, d->base + DMA350_REG_STATUS + CHANNEL_IDX(ch_idx)); + pr_err("transfer error!!!\n"); + } + if ((chstatus & DMA350_CH_STATUS_INTR_DONE) == 0) { + ch_idx++; + continue; + } + + arm_dma_ch_clrstatus(d, ch_idx); + p = &d->phy[ch_idx]; + if (p == NULL) + continue; + c = p->vchan; + if (c) { + spin_lock(&c->vc.lock); + if (c->cyclic) { + desnum[ch_idx]++; + if (dmachan[ch_idx] == (desnum[ch_idx] - 1)) + desnum[ch_idx] = 1; + vchan_cyclic_callback(&p->ds_run->vd); + } else { + vchan_cookie_complete(&p->ds_run->vd); + p->ds_done = p->ds_run; + } + spin_unlock(&c->vc.lock); + } + ch_idx++; + } + return IRQ_HANDLED; +} + +static void arm_dma350_free_chan_resources(struct dma_chan *chan) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_dev *d = to_arm_dma350(chan->device); + unsigned long flags; + + spin_lock_irqsave(&d->lock, flags); + list_del_init(&c->node); + spin_unlock_irqrestore(&d->lock, flags); + + vchan_free_chan_resources(&c->vc); +} + +static u32 get_bytes_in_phy_channel(struct arm_dma350_phy *phy) +{ + u32 witdth; + u32 bytes; + u32 byteslo, byteshi; + + byteslo = readl_relaxed(phy->base + DMA350_REG_XSIZE) & 0xFFFF; + byteshi = (readl_relaxed(phy->base + DMA350_REG_XSIZE) & 0xFFFF0000) >> 16; + if (byteslo > byteshi) + bytes = byteshi; + else + bytes = byteslo; + witdth = readl_relaxed(phy->base + DMA350_REG_CTRL) & DMA350_CH_CTRL_TRANSIZE_Msk; + switch (witdth) { + case DMA350_DMA_WIDTH_8BIT: + break; + case DMA350_DMA_WIDTH_16BIT: + bytes *= 2; + break; + case DMA350_DMA_WIDTH_32BIT: + bytes *= 4; + break; + } + return bytes; +} + +static enum dma_status arm_dma350_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, + struct dma_tx_state *state) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_phy *p; + struct virt_dma_desc *vd; + unsigned long flags; + enum dma_status ret; + size_t bytes = 0; + size_t residue = 0; + + ret = dma_cookie_status(&c->vc.chan, cookie, state); + + if (ret == DMA_COMPLETE || !state) + return ret; + + spin_lock_irqsave(&c->vc.lock, flags); + p = c->phy; + ret = c->status; + + /* + * If the cookie is on our issue queue, then the residue is + * its total size. + */ + if (c->cyclic) { + vd = vchan_find_desc(&c->vc, cookie); + if (vd) { + bytes = container_of(vd, struct arm_dma350_desc_sw, vd)->size; + residue = bytes - bytes / dmachan[c->id] * desnum[c->id]; + } + } else { + residue = get_bytes_in_phy_channel(p); + } + spin_unlock_irqrestore(&c->vc.lock, flags); + dma_set_residue(state, residue); + return ret; +} + +static void arm_dma350_issue_pending(struct dma_chan *chan) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_dev *d = to_arm_dma350(chan->device); + unsigned long flags; + int issue = 0; + + spin_lock_irqsave(&c->vc.lock, flags); + /* add request to vc->desc_issued */ + if (vchan_issue_pending(&c->vc)) { + spin_lock(&d->lock); + if (list_empty(&c->node)) { + /* if new channel, add chan_pending */ + list_add_tail(&c->node, &d->chan_pending); + issue = 1; + } + spin_unlock(&d->lock); + } else { + dev_info(d->slave.dev, "nothing to issue\n"); + } + spin_unlock_irqrestore(&c->vc.lock, flags); + if (issue) + arm_dma350_task(d); +} + +static void arm_dma350_fill_desc(struct arm_dma350_desc_sw *ds, dma_addr_t dst, + dma_addr_t src, size_t len, u32 num) +{ + ds->desc_hw[num].saddr = src; + ds->desc_hw[num].daddr = dst; + ds->desc_hw[num].x_len = len; +} + +static struct arm_dma350_desc_sw *arm_dma350_alloc_desc_resource(int num, + struct dma_chan *chan) +{ + struct arm_dma350_desc_sw *ds; + struct arm_dma350_dev *d = to_arm_dma350(chan->device); + int lli_limit = LLI_BLOCK_SIZE / sizeof(struct dma350_desc_hw); + + if (num > lli_limit) { + dev_err(chan->device->dev, "sg num %d exceed max %d\n", num, lli_limit); + return NULL; + } + ds = kzalloc(sizeof(*ds), GFP_ATOMIC); + if (!ds) + return NULL; + + ds->desc_hw = dma_pool_zalloc(d->pool, GFP_ATOMIC, &ds->desc_hw_lli); + if (!ds->desc_hw) { + dev_err(chan->device->dev, "dma alloc fail\n"); + kfree(ds); + return NULL; + } + ds->desc_num = num; + return ds; +} + +static int arm_dma350_pre_config_sg(struct arm_dma350_chan *c, enum dma_transfer_direction dir) +{ + + struct arm_dma350_dev *dev = to_arm_dma350(c->vc.chan.device); + struct arm_dma350_phy *p = &dev->phy[c->id]; + struct dma_slave_config *cfg = &c->slave_cfg; + u32 maxburst = 0, ret = 0; + + ret = pm_runtime_resume_and_get(dev->slave.dev); + if (ret < 0) { + pr_err("%s,pm get err, %d\n", __func__, ret); + return ret; + } + arm_dma350_nonsec_intren(dev); + dma350_ch_set_xtype(p->base + DMA350_REG_CTRL, DMA350_CH_XTYPE_CONTINUE); + + switch (dir) { + case DMA_MEM_TO_DEV: + dma350_ch_enable_intr(p->base + DMA350_REG_INTREN, DMA350_CH_INTREN_DONE | DMA350_CH_INTREN_ERR); + c->dev_addr = cfg->dst_addr - RCSU_OFFSET; + c->transize = cfg->dst_addr_width; + /* dst len is calculated from src width, len and dst width. + * We need make sure dst len not exceed MAX LEN. + * Trailing single transaction that does not fill a full + * burst also require identical src/dst data width. + */ + maxburst = cfg->dst_maxburst - 1; + maxburst = maxburst < MAX_BURST_LEN ? maxburst : MAX_BURST_LEN; + dma350_ch_set_desmaxburstlen(p->base + DMA350_REG_DESTRANSCFG, maxburst); + dma350_ch_set_transize(p->base + DMA350_REG_CTRL, ffs(cfg->dst_addr_width) - 1); + dma350_ch_enable_destrigin(p->base + DMA350_REG_CTRL); + dma350_ch_src_memattr(p->base + DMA350_REG_SRCTRANSCFG, 4, 4); + dma350_ch_des_memattr(p->base + DMA350_REG_DESTRANSCFG, 0, 0); + dma350_ch_set_destrigintype(p->base + DMA350_REG_DESTRIGINCFG, DMA350_CH_DESTRIGINTYPE_HW); + dma350_ch_set_destriginmode(p->base + DMA350_REG_DESTRIGINCFG, + DMA350_CH_DESTRIGINMODE_PERIPH_FLOW_CTRL); + dma350_ch_set_destriginsel(p->base + DMA350_REG_DESTRIGINCFG, c->req_line); + dma350_ch_set_xaddr_inc(p->base + DMA350_REG_XADDRINC, 1, 0); + + break; + case DMA_DEV_TO_MEM: + c->dev_addr = cfg->src_addr - RCSU_OFFSET; + c->transize = cfg->src_addr_width; + maxburst = cfg->src_maxburst - 1; + maxburst = maxburst < MAX_BURST_LEN ? maxburst : MAX_BURST_LEN; + dma350_ch_set_srcmaxburstlen(p->base + DMA350_REG_DESTRANSCFG, maxburst); + dma350_ch_set_transize(p->base + DMA350_REG_CTRL, ffs(cfg->src_addr_width) - 1); + dma350_ch_enable_srctrigin(p->base + DMA350_REG_CTRL); + + dma350_ch_src_memattr(p->base + DMA350_REG_SRCTRANSCFG, 0, 0); + + /*set des attribute to device memory,to fix the SOCHW-1449 bug */ + dma350_ch_des_memattr(p->base + DMA350_REG_DESTRANSCFG, 0, 0); + dma350_ch_set_srctrigintype(p->base + DMA350_REG_SRCTRIGINCFG, DMA350_CH_SRCTRIGINTYPE_HW); + dma350_ch_set_srctriginmode(p->base + DMA350_REG_SRCTRIGINCFG, + DMA350_CH_SRCTRIGINMODE_PERIPH_FLOW_CTRL); + dma350_ch_set_srctriginsel(p->base + DMA350_REG_SRCTRIGINCFG, c->req_line); + dma350_ch_set_xaddr_inc(p->base + DMA350_REG_XADDRINC, 0, 1); + break; + default: + return -EINVAL; + } + return 0; +} + +static int arm_dma350_pre_config_cyclic(struct arm_dma350_chan *c, enum dma_transfer_direction dir) +{ + + struct arm_dma350_dev *dev = to_arm_dma350(c->vc.chan.device); + struct arm_dma350_phy *p = &dev->phy[c->id]; + struct dma_slave_config *cfg = &c->slave_cfg; + u32 maxburst = 0; + + if (dev->regmap) + regmap_update_bits(dev->regmap, AUDSS_DMAC_INFO_AP_IRQ, + 1 << c->id, 1 << c->id); + + arm_dma350_clear_chan(p); + dma350_ch_set_xtype(p->base + DMA350_REG_CTRL, DMA350_CH_XTYPE_CONTINUE); + dma350_ch_set_chprio(p->base + DMA350_REG_CTRL, c->priority); + + /* Setup first */ + dma350_cmdlink_init(&cmdlink_cfg[c->id][0]); + /* Clear DMA registers upon loading this command */ + dma350_cmdlink_set_regclear(&cmdlink_cfg[c->id][0]); + dma350_cmdlink_set_xtype(&cmdlink_cfg[c->id][0], DMA350_CH_XTYPE_CONTINUE); + switch (dir) { + case DMA_MEM_TO_DEV: + c->dev_addr = cfg->dst_addr; + c->transize = cfg->dst_addr_width; + + /* dst len is calculated from src width, len and dst width. + * We need make sure dst len not exceed MAX LEN. + * Trailing single transaction that does not fill a full + * burst also require identical src/dst data width. + */ + maxburst = cfg->dst_maxburst - 1; + maxburst = maxburst < MAX_BURST_LEN ? maxburst : MAX_BURST_LEN; + dma350_ch_set_transize(p->base + DMA350_REG_CTRL, ffs(cfg->dst_addr_width) - 1); + + /*generate cmd link list*/ + dma350_cmdlink_set_desaddr32(&cmdlink_cfg[c->id][0], c->dev_addr); + dma350_cmdlink_set_transize(&cmdlink_cfg[c->id][0], ffs(cfg->dst_addr_width) - 1); + dma350_cmdlink_set_srcmemattrhi(&cmdlink_cfg[c->id][0], 4); + dma350_cmdlink_set_srcmemattrlo(&cmdlink_cfg[c->id][0], 4); + dma350_cmdlink_set_desmemattrhi(&cmdlink_cfg[c->id][0], 0); + dma350_cmdlink_set_desmemattrlo(&cmdlink_cfg[c->id][0], 0); + dma350_cmdlink_set_desmaxburstlen(&cmdlink_cfg[c->id][0], maxburst); + dma350_cmdlink_enable_intr(&cmdlink_cfg[c->id][0], DMA350_CH_INTREN_DONE | + DMA350_CH_INTREN_ERR | DMA350_CH_INTREN_DISABLED | DMA350_CH_INTREN_STOPPED); + dma350_cmdlink_enable_destrigin(&cmdlink_cfg[c->id][0]); + dma350_cmdlink_set_destriginmode(&cmdlink_cfg[c->id][0], DMA350_CH_DESTRIGINMODE_PERIPH_FLOW_CTRL); + dma350_cmdlink_set_destrigintype(&cmdlink_cfg[c->id][0], DMA350_CH_DESTRIGINTYPE_HW); + dma350_cmdlink_set_xaddrinc(&cmdlink_cfg[c->id][0], 1, 0); + dma350_cmdlink_set_destriginsel(&cmdlink_cfg[c->id][0], c->req_line); + break; + case DMA_DEV_TO_MEM: + c->dev_addr = cfg->src_addr; + c->transize = cfg->src_addr_width; + maxburst = cfg->src_maxburst - 1; + maxburst = maxburst < MAX_BURST_LEN ? maxburst : MAX_BURST_LEN; + dma350_ch_set_transize(p->base + DMA350_REG_CTRL, ffs(cfg->src_addr_width) - 1); + + /*generate cmd link list*/ + dma350_cmdlink_set_srcaddr32(&cmdlink_cfg[c->id][0], c->dev_addr); + dma350_cmdlink_set_transize(&cmdlink_cfg[c->id][0], ffs(cfg->src_addr_width) - 1); + dma350_cmdlink_set_desmemattrhi(&cmdlink_cfg[c->id][0], 4); + dma350_cmdlink_set_desmemattrlo(&cmdlink_cfg[c->id][0], 4); + dma350_cmdlink_set_srcmemattrhi(&cmdlink_cfg[c->id][0], 0); + dma350_cmdlink_set_srcmemattrlo(&cmdlink_cfg[c->id][0], 0); + dma350_cmdlink_set_srcmaxburstlen(&cmdlink_cfg[c->id][0], maxburst); + dma350_cmdlink_enable_intr(&cmdlink_cfg[c->id][0], + DMA350_CH_INTREN_DONE|DMA350_CH_INTREN_ERR | DMA350_CH_INTREN_DISABLED | DMA350_CH_INTREN_STOPPED); + dma350_cmdlink_enable_srctrigin(&cmdlink_cfg[c->id][0]); + dma350_cmdlink_set_srctriginmode(&cmdlink_cfg[c->id][0], DMA350_CH_SRCTRIGINMODE_PERIPH_FLOW_CTRL); + dma350_cmdlink_set_srctrigintype(&cmdlink_cfg[c->id][0], DMA350_CH_SRCTRIGINTYPE_HW); + dma350_cmdlink_set_xaddrinc(&cmdlink_cfg[c->id][0], 0, 1); + dma350_cmdlink_set_srctriginsel(&cmdlink_cfg[c->id][0], c->req_line); + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct dma_async_tx_descriptor *arm_dma350_prep_memcpy(struct dma_chan *chan, + dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_desc_sw *ds; + struct arm_dma350_dev *dev = to_arm_dma350(c->vc.chan.device); + struct arm_dma350_phy *p; + struct dma_slave_config *cfg = &c->slave_cfg; + size_t copy = 0; + int num = 0, ret = 0; + + c->id = chan->chan_id; + p = &dev->phy[c->id]; + + if (!cfg->src_addr_width) + cfg->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + + if (!len) + return NULL; + + ret = pm_runtime_resume_and_get(dev->slave.dev); + if (ret < 0) { + pr_err("%s,pm get err, %d\n", __func__, ret); + return ERR_PTR(ret); + } + + arm_dma350_nonsec_intren(dev); + arm_dma350_init_state(p); + c->dev_addr = cfg->src_addr; + dma350_ch_set_transize(p->base + DMA350_REG_CTRL, ffs(cfg->src_addr_width) - 1); + dma350_ch_src_memattr(p->base + DMA350_REG_SRCTRANSCFG, 4, 4); + dma350_ch_des_memattr(p->base + DMA350_REG_DESTRANSCFG, 4, 4); + dma350_ch_set_xaddr_inc(p->base + DMA350_REG_XADDRINC, 1, 1); + num = DIV_ROUND_UP(len, DMA_MAX_SIZE); + ds = arm_dma350_alloc_desc_resource(num, chan); + if (!ds) + return NULL; + ds->size = len; + num = 0; + do { + copy = min_t(size_t, len, DMA_MAX_SIZE); + arm_dma350_fill_desc(ds, dst, src, copy / cfg->src_addr_width, num++); + + src += copy; + dst += copy; + len -= copy; + } while (len); + + c->cyclic = 0; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static struct dma_async_tx_descriptor *arm_dma350_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen, + enum dma_transfer_direction dir, unsigned long flags, void *context) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_desc_sw *ds; + size_t len, avail, total = 0; + struct scatterlist *sg; + dma_addr_t addr, src = 0, dst = 0; + int num = sglen, i; + + if (!sgl) + return NULL; + if (arm_dma350_pre_config_sg(c, dir)) + return NULL; + + for_each_sg(sgl, sg, sglen, i) { + avail = sg_dma_len(sg); + + if (avail > DMA_MAX_SIZE) + num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1; + } + ds = arm_dma350_alloc_desc_resource(num, chan); + if (!ds) + return NULL; + c->cyclic = 0; + num = 0; + for_each_sg(sgl, sg, sglen, i) { + addr = sg_dma_address(sg); + avail = sg_dma_len(sg); + total += avail; + do { + + len = min_t(size_t, avail, DMA_MAX_SIZE); + + if (dir == DMA_MEM_TO_DEV) { + src = addr; + dst = c->dev_addr; + } else if (dir == DMA_DEV_TO_MEM) { + src = c->dev_addr; + dst = addr; + } + arm_dma350_fill_desc(ds, dst, src, (len / c->transize), num++); + addr += len; + avail -= len; + } while (avail); + } + ds->size = total; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static int arm_dma350_find_idle_channel(struct dma_chan *chan) +{ + u32 ch_idx = 0; + u32 enable_status = 0; + u32 cmdlink_status = 0; + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_dev *d = to_arm_dma350(chan->device); + struct arm_dma350_phy *phy = NULL; + + for (ch_idx = 0; ch_idx < MAX_CHAN_NUM; ch_idx++) { + phy = &d->phy[ch_idx]; + /*cyclic mode use cmd link,so should check dma_enable and linkaddr_en*/ + enable_status = readl_relaxed(phy->base + DMA350_REG_CMD) & DMA350_CH_CMD_ENABLECMD; + cmdlink_status = readl_relaxed(phy->base + DMA350_REG_LINKADDR) & DMA350_CH_LINKADDR_LINKADDREN; + if ((enable_status) || (cmdlink_status)) + continue; + else { + dev_info(d->slave.dev, "use dynamic channel-%d\n", ch_idx); + c->id = ch_idx; + break; + } + } + if (c->id >= MAX_CHAN_NUM) { + dev_err(d->slave.dev, "there is no idle channel to alloc\n"); + return -EINVAL; + } + + return 0; +} + +static struct dma_async_tx_descriptor *arm_dma350_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, + size_t buf_len, size_t period_len, enum dma_transfer_direction dir, unsigned long flags) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_dev *d = to_arm_dma350(chan->device); + struct arm_dma350_desc_sw *ds; + dma_addr_t src = 0, dst = 0; + int num_periods = buf_len / period_len; + int buf = 0, cmd_num = 0; + u32 offset = 0, bit = 0; + int ret = 0; + + if (period_len > DMA_MAX_SIZE) { + dev_err(chan->device->dev, "maximum period size exceeded\n"); + return NULL; + } + if (c->id > MAX_CHAN_NUM) { + dev_err(chan->device->dev, "maximum chan num exceeded\n"); + return NULL; + } + + ret = pm_runtime_resume_and_get(d->slave.dev); + if (ret < 0) { + pr_err("%s,pm get err, %d\n", __func__, ret); + return NULL; + } + /*if channel id is 0xFF,it means we should use dynamic channel*/ + if ((c->id == 0xFF) && (arm_dma350_find_idle_channel(chan))) { + pm_runtime_put_noidle(d->slave.dev); + return NULL; + } + if (arm_dma350_pre_config_cyclic(c, dir)) { + pm_runtime_put_noidle(d->slave.dev); + return NULL; + } + ds = arm_dma350_alloc_desc_resource(num_periods, chan); + if (!ds) { + pm_runtime_put_noidle(d->slave.dev); + return NULL; + } + c->cyclic = 1; + while (buf < buf_len) { + if (cmd_num > 0) + dma350_cmdlink_init(&cmdlink_cfg[c->id][cmd_num]); + if (dir == DMA_MEM_TO_DEV) { + src = dma_addr; + + if (d->map.ram_host_addr && d->map.ram_remote_addr) { + offset = src - d->map.ram_host_addr; + src = d->map.ram_remote_addr + offset; + } + + dst = c->dev_addr; + if (d->map.reg_host_addr && d->map.reg_remote_addr) { + offset = dst - d->map.reg_host_addr; + dst = d->map.reg_remote_addr + offset; + } + + } else if (dir == DMA_DEV_TO_MEM) { + src = c->dev_addr; + if (d->map.reg_host_addr && d->map.reg_remote_addr) { + offset = src - d->map.reg_host_addr; + src = d->map.reg_remote_addr + offset; + } + + dst = dma_addr; + if (d->map.ram_host_addr && d->map.ram_remote_addr) { + offset = dst - d->map.ram_host_addr; + dst = d->map.ram_remote_addr + offset; + } + + } + dma_addr += period_len; + buf += period_len; + + dma350_cmdlink_set_desaddr32(&cmdlink_cfg[c->id][cmd_num], dst); + dma350_cmdlink_set_srcaddr32(&cmdlink_cfg[c->id][cmd_num], src); + dma350_cmdlink_enable_linkaddr(&cmdlink_cfg[c->id][cmd_num]); + dma350_cmdlink_set_xsize32(&cmdlink_cfg[c->id][cmd_num], + (period_len / c->transize), + (period_len / c->transize)); + cmd_num++; + } + cmd0[c->id] = dma_alloc_coherent(chan->device->dev, CMD_LINK_LEN * sizeof(u32), &phy_cmd0[c->id], GFP_ATOMIC); + cmd_num = 0; + while (cmd_num < num_periods) { + /* cmd linklist prepare*/ + dma350_cmdlink_generate(&cmdlink_cfg[c->id][cmd_num], cmd0[c->id] + cmd_num+bit, &bit); + /* + *if not the last command,then fill the next command address to the linkaddr domain + *if the last command, then fill the next command address with the first linkaddr + */ + if (cmd_num == (num_periods - 1)) + *(cmd0[c->id] + bit + cmd_num) = (u32)(phy_cmd0[c->id] + AUDSS_OFFSET) + + DMA350_CH_LINKADDR_LINKADDREN; + else + *(cmd0[c->id] + bit + cmd_num) = (u32)(phy_cmd0[c->id] + (bit + cmd_num + 1) * 4 + + AUDSS_OFFSET) + DMA350_CH_LINKADDR_LINKADDREN; + cmd_num++; + } + dmachan[c->id] = num_periods; + ds->size = buf_len; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static int arm_dma350_config(struct dma_chan *chan, + struct dma_slave_config *cfg) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + + if (!cfg) + return -EINVAL; + + memcpy(&c->slave_cfg, cfg, sizeof(*cfg)); + + return 0; +} + +static int arm_dma350_terminate_all(struct dma_chan *chan) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_dev *d = to_arm_dma350(chan->device); + struct arm_dma350_phy *p = &d->phy[c->id]; + struct dma_slave_config *cfg = &c->slave_cfg; + bool runtimepm_flag = false; + + unsigned long flags; + LIST_HEAD(head); + + dev_dbg(d->slave.dev, "channel-%d terminate all\n", c->id); + + /*if dma prepare not call (which means dma not ready to use), c->phy is null, + *then pm_runtime_resume_and_get should not call + */ + if (c->phy) + runtimepm_flag = true; + desnum[c->id] = 0; + /* Prevent this channel being scheduled */ + spin_lock(&d->lock); + list_del_init(&c->node); + spin_unlock(&d->lock); + + /* Clear the tx descriptor lists */ + spin_lock_irqsave(&c->vc.lock, flags); + vchan_get_all_descriptors(&c->vc, &head); + if (p) { + /* vchan is assigned to a pchan - stop the channel */ + arm_dma350_terminate_chan(p); + dma350_ch_disable_linkaddr(p->base + DMA350_REG_LINKADDR); + arm_dma350_clear_chan(p); + if ((cfg->direction == DMA_DEV_TO_MEM) && !c->cyclic && p->ds_run) + vchan_vdesc_fini(&p->ds_run->vd); + c->phy = NULL; + p->vchan = NULL; + p->ds_run = NULL; + p->ds_done = NULL; + } + spin_unlock_irqrestore(&c->vc.lock, flags); + if (c->cyclic) + dma_free_coherent(chan->device->dev, CMD_LINK_LEN * sizeof(u32), cmd0[c->id], phy_cmd0[c->id]); + vchan_dma_desc_free_list(&c->vc, &head); + + if (runtimepm_flag) { + pm_runtime_mark_last_busy(d->slave.dev); + pm_runtime_put_autosuspend(d->slave.dev); + } + + return 0; +} + +static int arm_dma350_transfer_pause(struct dma_chan *chan) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_dev *d = to_arm_dma350(chan->device); + struct arm_dma350_phy *p = &d->phy[c->id]; + + dma350_ch_cmd(p->base + DMA350_REG_CMD, DMA350_CH_CMD_PAUSECMD); + + return 0; +} + +static int arm_dma350_transfer_resume(struct dma_chan *chan) +{ + struct arm_dma350_chan *c = to_dma350_chan(chan); + struct arm_dma350_dev *d = to_arm_dma350(chan->device); + struct arm_dma350_phy *p = &d->phy[c->id]; + + dma350_ch_cmd(p->base + DMA350_REG_CMD, DMA350_CH_CMD_RESUMECMD); + + return 0; +} + +static void arm_dma350_free_desc(struct virt_dma_desc *vd) +{ + struct arm_dma350_desc_sw *ds = + container_of(vd, struct arm_dma350_desc_sw, vd); + struct arm_dma350_dev *d = to_arm_dma350(vd->tx.chan->device); + + dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli); + kfree(ds); +} + +static const struct arm_dma350_drvdata arm_dma350_no_pause = { + .is_exist_pause = false, +}; + +static const struct arm_dma350_drvdata arm_dma350_full = { + .is_exist_pause = true, +}; + +static const struct of_device_id arm_dma350_dt_ids[] = { + {.compatible = "arm,dma350-no-pause", .data = &arm_dma350_no_pause }, + {.compatible = "arm,dma350-full", .data = &arm_dma350_full }, + { } +}; + +MODULE_DEVICE_TABLE(of, arm_dma350_dt_ids); + +static const struct acpi_device_id arm_dma350_acpi_ids[] = { + { "CIXH1006", .driver_data = (kernel_ulong_t) &arm_dma350_no_pause }, + { "CIXHA014", .driver_data = (kernel_ulong_t) &arm_dma350_full }, + { }, +}; + +MODULE_DEVICE_TABLE(acpi, arm_dma350_acpi_ids); + +static struct dma_chan *arm_dma350_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct arm_dma350_dev *d = ofdma->of_dma_data; + unsigned int channel_pri = 0; + unsigned int channel_id = 0; + unsigned int request = 0; + struct dma_chan *chan; + struct arm_dma350_chan *c; + + if (dma_spec->args_count == 1) + request = dma_spec->args[0]; + else if (dma_spec->args_count == 2) { + request = dma_spec->args[0]; + channel_id = dma_spec->args[1]; + } else if (dma_spec->args_count == 3) { + request = dma_spec->args[0]; + channel_id = dma_spec->args[1]; + channel_pri = dma_spec->args[2]; + } else { + dev_err(d->slave.dev, "para invalid %s %d\n", __func__, __LINE__); + } + + if ((request >= d->max_requests) || (channel_id >= d->max_channels)) { + dev_err(d->slave.dev, "para invalid %s %d\n", __func__, __LINE__); + return NULL; + } + chan = dma_get_any_slave_channel(&d->slave); + if (!chan) { + dev_err(d->slave.dev, "get channel fail in %s.\n", __func__); + return NULL; + } + c = to_dma350_chan(chan); + c->id = channel_id; + c->req_line = request; + c->priority = channel_pri; + return chan; +} + +static struct dma_chan *arm_dma350_acpi_xlate(struct acpi_dma_spec *dma_spec, + struct acpi_dma *adma) +{ + struct arm_dma350_dev *d = adma->data; + unsigned int request, channel_id; + struct dma_chan *chan; + struct arm_dma350_chan *c; + + request = dma_spec->slave_id; + channel_id = dma_spec->chan_id; + + dev_dbg(d->slave.dev, "dma xlate request[%d] channel[%d]\n", + request, channel_id); + + if (request >= d->max_requests) { + dev_err(d->slave.dev, "request or channel_id overflow\n"); + return NULL; + } + chan = dma_get_any_slave_channel(&d->slave); + if (!chan) { + dev_err(d->slave.dev, "get channel fail in %s.\n", __func__); + return NULL; + } + c = to_dma350_chan(chan); + c->id = channel_id; + c->req_line = request; + return chan; +} + +static int arm_dma350_probe(struct platform_device *op) +{ + struct arm_dma350_dev *d; + struct arm_dma350_drvdata *drvdata = NULL; + int i, ret = 0; + u32 out_val[2]; + struct reset_control *dma_reset; + + d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + drvdata = (struct arm_dma350_drvdata *)device_get_match_data(&op->dev); + if (!drvdata) { + dev_err(&op->dev, "unable to find driver data\n"); + return -EINVAL; + } + d->drvdata = drvdata; + d->base = devm_platform_ioremap_resource(op, 0); + if (IS_ERR(d->base)) + return PTR_ERR(d->base); + + device_property_read_u32(&op->dev, "dma-channels", &d->max_channels); + device_property_read_u32(&op->dev, "dma-requests", &d->max_requests); + if (!d->max_requests || !d->max_channels) + return -EINVAL; + if (!device_property_read_u32_array(&op->dev, "arm,reg-map", + out_val, ARRAY_SIZE(out_val))) { + d->map.reg_host_addr = out_val[0]; + d->map.reg_remote_addr = out_val[1]; + } + if (!device_property_read_u32_array(&op->dev, "arm,ram-map", + out_val, ARRAY_SIZE(out_val))) { + d->map.ram_host_addr = out_val[0]; + d->map.ram_remote_addr = out_val[1]; + } + + if (device_property_present(&op->dev, "arm,clk-enable-atomic")) + d->is_clk_enable_atomic = true; + else + d->is_clk_enable_atomic = false; + + d->regmap = device_syscon_regmap_lookup_by_property(&op->dev, + "arm,remote-ctrl"); + if (PTR_ERR(d->regmap) == -ENODEV) + d->regmap = NULL; + else if (IS_ERR(d->regmap)) + return PTR_ERR(d->regmap); + + ret = dma_set_mask_and_coherent(&op->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&op->dev, "Failed to set DMA Mask\n"); + return ret; + } + if (!ACPI_COMPANION(&op->dev)) { + ret = of_reserved_mem_device_init(&op->dev); + if (ret && ret != -ENODEV) { + dev_err(&op->dev, "Failed to init reserved mem for DMA\n"); + return ret; + } + } + d->clk = devm_clk_get(&op->dev, NULL); + if (IS_ERR(d->clk)) { + dev_err(&op->dev, "no dma clk\n"); + return PTR_ERR(d->clk); + } + + d->irq = platform_get_irq(op, 0); + ret = devm_request_irq(&op->dev, d->irq, arm_dma350_int_handler, + 0, DRIVER_NAME, d); + if (ret) + return ret; + + /* A DMA memory pool for LLIs, align on 32-byte boundary */ + d->pool = dmam_pool_create(DRIVER_NAME, &op->dev, + LLI_BLOCK_SIZE, 32, 0); + if (!d->pool) { + dev_err(&op->dev, "alloc dma pool failed\n"); + return -ENOMEM; + } + + /* init phy channel */ + d->phy = devm_kcalloc(&op->dev, + d->max_channels, sizeof(struct arm_dma350_phy), GFP_KERNEL); + if (!d->phy) + return -ENOMEM; + + /* Enable clock before accessing registers */ + ret = clk_prepare_enable(d->clk); + if (ret < 0) { + dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret); + return ret; + } + dma_reset = devm_reset_control_get(&op->dev, "dma_reset"); + if (IS_ERR(dma_reset)) { + dev_err(&op->dev, "get dma reset error\n"); + ret = PTR_ERR(dma_reset); + if (ret != -ENOENT) + goto clk_dis; + } else { + /* reset */ + reset_control_assert(dma_reset); + /* release reset */ + reset_control_deassert(dma_reset); + } + d->dma_reset = dma_reset; + + for (i = 0; i < d->max_channels; i++) { + struct arm_dma350_phy *p = &d->phy[i]; + + p->idx = i; + p->base = d->base + CHANNEL_IDX(i); + desnum[i] = 0; + } + + INIT_LIST_HEAD(&d->slave.channels); + dma_cap_set(DMA_SLAVE, d->slave.cap_mask); + dma_cap_set(DMA_MEMCPY, d->slave.cap_mask); + dma_cap_set(DMA_CYCLIC, d->slave.cap_mask); + dma_cap_set(DMA_PRIVATE, d->slave.cap_mask); + d->slave.dev = &op->dev; + d->slave.device_free_chan_resources = arm_dma350_free_chan_resources; + d->slave.device_tx_status = arm_dma350_tx_status; + d->slave.device_prep_dma_memcpy = arm_dma350_prep_memcpy; + d->slave.device_prep_slave_sg = arm_dma350_prep_slave_sg; + d->slave.device_prep_dma_cyclic = arm_dma350_prep_dma_cyclic; + d->slave.device_issue_pending = arm_dma350_issue_pending; + d->slave.device_config = arm_dma350_config; + d->slave.device_terminate_all = arm_dma350_terminate_all; + if (d->drvdata->is_exist_pause == true) { + d->slave.device_pause = arm_dma350_transfer_pause; + d->slave.device_resume = arm_dma350_transfer_resume; + } + d->slave.copy_align = DMA_ALIGN; + d->slave.src_addr_widths = ARM_DMA350_BUSWIDTHS; + d->slave.dst_addr_widths = ARM_DMA350_BUSWIDTHS; + d->slave.directions = BIT(DMA_MEM_TO_MEM) | BIT(DMA_MEM_TO_DEV) + | BIT(DMA_DEV_TO_MEM); + d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + /* init virtual channel */ + d->chans = devm_kcalloc(&op->dev, + d->max_requests, sizeof(struct arm_dma350_chan), GFP_KERNEL); + if (!d->chans) + return -ENOMEM; + + for (i = 0; i < d->max_requests; i++) { + struct arm_dma350_chan *c = &d->chans[i]; + + c->status = DMA_IN_PROGRESS; + INIT_LIST_HEAD(&c->node); + c->vc.desc_free = arm_dma350_free_desc; + vchan_init(&c->vc, &d->slave); + } + + spin_lock_init(&d->lock); + INIT_LIST_HEAD(&d->chan_pending); + platform_set_drvdata(op, d); + ret = dma_async_device_register(&d->slave); + if (ret) + goto clk_dis; + + pm_runtime_irq_safe(&op->dev); + pm_runtime_set_autosuspend_delay(&op->dev, ARM_DMA350__PM_TIMEOUT_MS); + pm_runtime_use_autosuspend(&op->dev); + pm_runtime_get_noresume(&op->dev); + pm_runtime_set_active(&op->dev); + pm_runtime_enable(&op->dev); + + if (ACPI_COMPANION(&op->dev)) + ret = acpi_dma_controller_register(&op->dev, + arm_dma350_acpi_xlate, d); + else + ret = of_dma_controller_register((&op->dev)->of_node, + arm_dma350_of_xlate, d); + if (ret) + goto of_dma_register_fail; + + pm_runtime_mark_last_busy(&op->dev); + pm_runtime_put_autosuspend(&op->dev); + dev_info(&op->dev, "initialized\n"); + + return 0; + +of_dma_register_fail: + dma_async_device_unregister(&d->slave); +clk_dis: + clk_disable_unprepare(d->clk); + return ret; +} + +static int arm_dma350_remove(struct platform_device *op) +{ + struct arm_dma350_chan *c, *cn; + struct arm_dma350_dev *d = platform_get_drvdata(op); + + /* explicitly free the irq */ + devm_free_irq(&op->dev, d->irq, d); + + dma_async_device_unregister(&d->slave); + of_dma_controller_free((&op->dev)->of_node); + + list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) { + list_del(&c->vc.chan.device_node); + } + clk_disable_unprepare(d->clk); + + return 0; +} + +static int arm_dma350_runtime_suspend_dev(struct device *dev) +{ + struct arm_dma350_dev *d = dev_get_drvdata(dev); + + if (d->is_clk_enable_atomic) + clk_disable(d->clk); + else + clk_disable_unprepare(d->clk); + + return 0; +} + +static int arm_dma350_runtime_resume_dev(struct device *dev) +{ + struct arm_dma350_dev *d = dev_get_drvdata(dev); + int ret = 0; + + if (d->is_clk_enable_atomic) + ret = clk_enable(d->clk); + else + ret = clk_prepare_enable(d->clk); + if (ret < 0) { + dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret); + return ret; + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int arm_dma350_suspend_dev(struct device *dev) +{ + int ret = 0; + + ret = pm_runtime_force_suspend(dev); + if (ret) { + dev_err(dev, "Force suspend error.\n"); + return ret; + } + + return 0; +} + +static int arm_dma350_resume_dev(struct device *dev) +{ + int ret = 0; + struct arm_dma350_dev *d = dev_get_drvdata(dev); + + reset_control_assert(d->dma_reset); + udelay(2); + reset_control_deassert(d->dma_reset); + + ret = pm_runtime_force_resume(dev); + if (ret) { + dev_err(dev, "Force resume error.\n"); + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops arm_dma350_pmops = { + SET_SYSTEM_SLEEP_PM_OPS(arm_dma350_suspend_dev, + arm_dma350_resume_dev) + SET_RUNTIME_PM_OPS(arm_dma350_runtime_suspend_dev, + arm_dma350_runtime_resume_dev, NULL) +}; + +static struct platform_driver arm_dma350_driver = { + .driver = { + .name = DRIVER_NAME, + .pm = &arm_dma350_pmops, + .of_match_table = arm_dma350_dt_ids, + .acpi_match_table = ACPI_PTR(arm_dma350_acpi_ids), + }, + .probe = arm_dma350_probe, + .remove = arm_dma350_remove, +}; + +module_platform_driver(arm_dma350_driver); + +MODULE_AUTHOR("Hongliang yang "); +MODULE_DESCRIPTION("API Driver for ARM DMA350 controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/dma350_ch_drv.h b/drivers/dma/dma350_ch_drv.h new file mode 100644 index 000000000000..a8d4a170e1dc --- /dev/null +++ b/drivers/dma/dma350_ch_drv.h @@ -0,0 +1,2012 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0 + * + * Copyright (c) 2022 Arm Limited. All rights reserved. + * Copyright 2024 Cix Technology Group Co., Ltd. + */ + +#ifndef __DMA350_CH_DRV_H +#define __DMA350_CH_DRV_H + +#include "dma350_regdef.h" +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* DMA350_CH register mask definitions */ + +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_MAX 0x1FUL +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE_MAX 0x1FUL + +#define DMA350_CH_CTRL_RESET_VALUE 0x00200200 +#define DMA350_CH_INTREN_RESET_VALUE 0x00000000 +#define DMA350_CH_LINKADDR_RESET_VALUE 0x00000000 +#define DMA350_CH_DESTRANSCFG_RESET_VALUE 0x000F0400 +#define DMA350_CH_SRCTRANSCFG_RESET_VALUE 0x000F0400 +#define DMA350_CH_AUTOCFG_RESET_VALUE 0x00000000 + +#define DMA350_CMDLINK_CLEAR_SET (0x1UL) +#define DMA350_CMDLINK_INTREN_SET (0x1UL << 2) +#define DMA350_CMDLINK_CTRL_SET (0x1UL << 3) +#define DMA350_CMDLINK_SRC_ADDR_SET (0x1UL << 4) +#define DMA350_CMDLINK_SRC_ADDRHI_SET (0x1UL << 5) +#define DMA350_CMDLINK_DES_ADDR_SET (0x1UL << 6) +#define DMA350_CMDLINK_DES_ADDRHI_SET (0x1UL << 7) +#define DMA350_CMDLINK_XSIZE_SET (0x1UL << 8) +#define DMA350_CMDLINK_XSIZEHI_SET (0x1UL << 9) +#define DMA350_CMDLINK_SRCTRANSCFG_SET (0x1UL << 10) +#define DMA350_CMDLINK_DESTRANSCFG_SET (0x1UL << 11) +#define DMA350_CMDLINK_XADDRINC_SET (0x1UL << 12) +#define DMA350_CMDLINK_YADDRSTRIDE_SET (0x1UL << 13) +#define DMA350_CMDLINK_FILLVAL_SET (0x1UL << 14) +#define DMA350_CMDLINK_YSIZE_SET (0x1UL << 15) +#define DMA350_CMDLINK_TMPLTCFG_SET (0x1UL << 16) +#define DMA350_CMDLINK_SRCTMPLT_SET (0x1UL << 17) +#define DMA350_CMDLINK_DESTMPLT_SET (0x1UL << 18) +#define DMA350_CMDLINK_SRCTRIGINCFG_SET (0x1UL << 19) +#define DMA350_CMDLINK_DESTRIGINCFG_SET (0x1UL << 20) +#define DMA350_CMDLINK_TRIGOUTCFG_SET (0x1UL << 21) +#define DMA350_CMDLINK_GPOEN0_SET (0x1UL << 22) +#define DMA350_CMDLINK_GPOVAL0_SET (0x1UL << 24) +#define DMA350_CMDLINK_STREAMINTCFG_SET (0x1UL << 26) +#define DMA350_CMDLINK_LINKATTR_SET (0x1UL << 28) +#define DMA350_CMDLINK_AUTOCFG_SET (0x1UL << 29) +#define DMA350_CMDLINK_LINKADDR_SET (0x1UL << 30) +#define DMA350_CMDLINK_LINKADDRHI_SET (0x1UL << 31) + +#define ARM_DMA350_BUSWIDTHS \ + (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \ + BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) + +/*Update a addrister (addr) at position (POS) with value (VAL). + *Affected bits are defined by a mask (MSK) + */ +#define SET_FIELD(addr, VAL, POS, MSK) \ + writel((readl(addr) & ~MSK) | (((uint32_t)(VAL) << POS) & MSK), addr) + +/* ARM DMA350 DMA Channel status bits */ +enum dma350_ch_stat_t { + DMA350_CH_STAT_DONE = DMA350_CH_STATUS_STAT_DONE, + DMA350_CH_STAT_ERR = DMA350_CH_STATUS_STAT_ERR, + DMA350_CH_STAT_DISABLED = DMA350_CH_STATUS_STAT_DISABLED, + DMA350_CH_STAT_STOPPED = DMA350_CH_STATUS_STAT_STOPPED, + DMA350_CH_STAT_SRCTRIGINWAIT = DMA350_CH_STATUS_STAT_SRCTRIGINWAIT, + DMA350_CH_STAT_DESTRIGINWAIT = DMA350_CH_STATUS_STAT_DESTRIGINWAIT, + DMA350_CH_STAT_TRIGOUTACKWAIT = DMA350_CH_STATUS_STAT_TRIGOUTACKWAIT, + DMA350_CH_STAT_ALL = + DMA350_CH_STATUS_STAT_DONE | DMA350_CH_STATUS_STAT_ERR | + DMA350_CH_STATUS_STAT_DISABLED | DMA350_CH_STATUS_STAT_STOPPED | + DMA350_CH_STATUS_STAT_SRCTRIGINWAIT | DMA350_CH_STATUS_STAT_DESTRIGINWAIT | + DMA350_CH_STATUS_STAT_TRIGOUTACKWAIT +}; + +/* ARM DMA350 DMA Channel interrupt bits */ +enum dma350_ch_intr_t { + DMA350_CH_INTREN_DONE = DMA350_CH_INTREN_INTREN_DONE, + DMA350_CH_INTREN_ERR = DMA350_CH_INTREN_INTREN_ERR, + DMA350_CH_INTREN_DISABLED = DMA350_CH_INTREN_INTREN_DISABLED, + DMA350_CH_INTREN_STOPPED = DMA350_CH_INTREN_INTREN_STOPPED, + DMA350_CH_INTREN_SRCTRIGINWAIT = DMA350_CH_INTREN_INTREN_SRCTRIGINWAIT, + DMA350_CH_INTREN_DESTRIGINWAIT = DMA350_CH_INTREN_INTREN_DESTRIGINWAIT, + DMA350_CH_INTREN_TRIGOUTACKWAIT = DMA350_CH_INTREN_INTREN_TRIGOUTACKWAIT, + DMA350_CH_INTREN_ALL = + DMA350_CH_INTREN_INTREN_DONE | DMA350_CH_INTREN_INTREN_ERR | + DMA350_CH_INTREN_INTREN_DISABLED | DMA350_CH_INTREN_INTREN_STOPPED | + DMA350_CH_INTREN_INTREN_SRCTRIGINWAIT | + DMA350_CH_INTREN_INTREN_DESTRIGINWAIT | DMA350_CH_INTREN_INTREN_TRIGOUTACKWAIT +}; + + +/* ARM DMA350 DMA Channel XTYPE */ +enum dma350_ch_xtype_t { + DMA350_CH_XTYPE_DISABLE = 0, + DMA350_CH_XTYPE_CONTINUE = DMA350_CH_CTRL_XTYPE_0, + DMA350_CH_XTYPE_WRAP = DMA350_CH_CTRL_XTYPE_1, + DMA350_CH_XTYPE_FILL = DMA350_CH_CTRL_XTYPE_1 | DMA350_CH_CTRL_XTYPE_0 +}; + +/* ARM DMA350 DMA Channel Done type */ +enum dma350_ch_donetype_t { + DMA350_CH_DONETYPE_NONE = 0, + DMA350_CH_DONETYPE_END_OF_CMD = DMA350_CH_CTRL_DONETYPE_0, + DMA350_CH_DONETYPE_END_OF_AUTORESTART = + DMA350_CH_CTRL_DONETYPE_1 | DMA350_CH_CTRL_DONETYPE_0 +}; + +/* ARM DMA350 DMA Channel Source Trigger Input Type */ +enum dma350_ch_srctrigintype_t { + DMA350_CH_SRCTRIGINTYPE_SOFTWARE_ONLY = 0, + DMA350_CH_SRCTRIGINTYPE_HW = DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_1, + DMA350_CH_SRCTRIGINTYPE_INTERNAL = DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_1 | + DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_0 +}; + +/* ARM DMA350 DMA Channel Source Trigger Input Mode */ +enum dma350_ch_srctriginmode_t { + DMA350_CH_SRCTRIGINMODE_CMD = 0, + DMA350_CH_SRCTRIGINMODE_DMA_FLOW_CTRL = DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_1, + DMA350_CH_SRCTRIGINMODE_PERIPH_FLOW_CTRL = + DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_1 | + DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_0 +}; + +/* ARM DMA350 DMA Channel Destination Trigger Input Type */ +enum dma350_ch_destrigintype_t { + DMA350_CH_DESTRIGINTYPE_SOFTWARE_ONLY = 0, + DMA350_CH_DESTRIGINTYPE_HW = DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_1, + DMA350_CH_DESTRIGINTYPE_INTERNAL = DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_1 | + DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_0 +}; + +/* ARM DMA350 DMA Channel Destination Trigger Input Mode */ +enum dma350_ch_destriginmode_t { + DMA350_CH_DESTRIGINMODE_CMD = 0, + DMA350_CH_DESTRIGINMODE_DMA_FLOW_CTRL = DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_1, + DMA350_CH_DESTRIGINMODE_PERIPH_FLOW_CTRL = + DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_1 | + DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_0 +}; + + +/* ARM DMA350 DMA Command link addrister structure */ +/* Note: Field order must match the order of the bits in the header */ +struct dma350_cmdlink_addr_t { + /* Note: addrCLEAR (Bit 0) has no associated field and Bit 1 is reserved */ + uint32_t intren; /* Bit 2 */ + uint32_t ctrl; /* Bit 3 */ + uint32_t srcaddr; /* Bit 4 */ + uint32_t srcaddrhi; /* Bit 5 */ + uint32_t desaddr; /* Bit 6 */ + uint32_t desaddrhi; /* Bit 7 */ + uint32_t xsize; /* Bit 8 */ + uint32_t xsizehi; /* Bit 9 */ + uint32_t srctranscfg; /* Bit 10 */ + uint32_t destranscfg; /* Bit 11 */ + uint32_t xaddrinc; /* Bit 12 */ + uint32_t yaddrstride; /* Bit 13 */ + uint32_t fillval; /* Bit 14 */ + uint32_t ysize; /* Bit 15 */ + uint32_t tmpltcfg; /* Bit 16 */ + uint32_t srctmplt; /* Bit 17 */ + uint32_t destmplt; /* Bit 18 */ + uint32_t srctrigincfg; /* Bit 19 */ + uint32_t destrigincfg; /* Bit 20 */ + uint32_t trigoutcfg; /* Bit 21 */ + uint32_t gpoen0; /* Bit 22 */ + uint32_t reserved0; /* Bit 23 */ + uint32_t gpoval0; /* Bit 24 */ + uint32_t reserved1; /* Bit 25 */ + uint32_t streamintcfg; /* Bit 26 */ + uint32_t reserved2; /* Bit 27 */ + uint32_t linkattr; /* Bit 28 */ + uint32_t autocfg; /* Bit 29 */ + uint32_t linkaddr; /* Bit 30 */ + uint32_t linkaddrhi; /* Bit 31 */ +}; + +/* ARM DMA350 DMA Command link generator config structure */ +struct dma350_cmdlink_gencfg_t { + uint32_t header; + struct dma350_cmdlink_addr_t cfg; +}; + + +/** + * \brief Sets source address[31:0] of channel + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] src_addr source address, where to copy from + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_set_src(void __iomem *addr, uint32_t src_addr); + +/** + * \brief Sets destination address[31:0] of channel + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] des_addr destination address, where to copy to + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_set_des(void __iomem *addr, uint32_t des_addr); + +/** + * \brief Sets Channel Priority + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] chprio Number of priority + * + * \return void + */ +static inline +void dma350_ch_set_chprio(void __iomem *addr, uint8_t chprio); + +/** + * \brief Sets number of copies in the x dimension + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] src_xsize number of source elements in the x dimension + * \param[in] des_xsize number of destination elements in the x dimension + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_set_xsize32(void __iomem *addr, uint32_t src_xsize, + uint32_t des_xsize); + +/** + * \brief Sets size of each transfer + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] transize size of each transfer \ref dma350_ch_transize_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_set_transize(void __iomem *addr, uint32_t transize); + +/** + * \brief Sets type of operation in the x dimension + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] xtype type of operation in the x dimension + * \ref dma350_ch_xtype_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_set_xtype(void __iomem *addr, + enum dma350_ch_xtype_t xtype); + +/** + * \brief Configures when STAT_DONE flag is asserted for this command + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] donetype donetype of command \ref dma350_ch_donetype_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_set_donetype(void __iomem *addr, + enum dma350_ch_donetype_t donetype); + +/** + * \brief Enables Source Trigger Input use for this command + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_enable_srctrigin(void __iomem *addr); + +/** + * \brief Disables Source Trigger Input use for this command + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_disable_srctrigin(void __iomem *addr); + +/** + * \brief Enables Destination Trigger Input use for this command + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_enable_destrigin(void __iomem *addr); + +/** + * \brief Disables Destination Trigger Input use for this command + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_disable_destrigin(void __iomem *addr); + + +/** + * \brief Sets Source Transfer Memory Attribute field[3:0] + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] memattrlo Attribute field (4 bits) + * + * \return void + */ +static inline +void dma350_ch_set_srcmemattrlo(void __iomem *addr, uint8_t memattrlo); + +/** + * \brief Sets Source Transfer Memory Attribute field[7:4] + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] memattrhi Attribute field (4 bits) + * + * \return void + */ +static inline +void dma350_ch_set_srcmemattrhi(void __iomem *addr, uint8_t memattrhi); + +/** + * \brief Sets Destination Transfer Memory Attribute field[3:0] + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] memattrlo Attribute field (4 bits) + * + * \return void + */ +static inline +void dma350_ch_set_desmemattrlo(void __iomem *addr, uint8_t memattrlo); + +/** + * \brief Sets Destination Transfer Memory Attribute field[7:4] + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] memattrhi Attribute field (4 bits) + * + * \return void + */ +static inline +void dma350_ch_set_desmemattrhi(void __iomem *addr, uint8_t memattrhi); + +static inline +void dma350_ch_set_srcmaxburstlen(void __iomem *addr, uint8_t length); + +/** + * \brief Sets Destination Max Burst Length + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] length Value of max burst length + * + * \return void + */ +static inline +void dma350_ch_set_desmaxburstlen(void __iomem *addr, uint8_t length); + +/** + * \brief Sets source and destination address increment after each transfer + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] src_xaddr_inc increment of source address + * \param[in] des_xaddr_inc increment of destination address + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_set_xaddr_inc(void __iomem *addr, int32_t src_xaddr_inc, + int32_t des_xaddr_inc); + +/** + * \brief Commands a channel of DMA350 DMA. + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] cmd DMA350 DMA channel command \ref dma350_ch_cmd_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_cmd(void __iomem *addr, uint32_t cmd); + +/** + * \brief Enables Interrupt for DMA350 DMA channel + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] intr Interrupt(s) to enable \ref dma350_ch_intr_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_enable_intr(void __iomem *addr, enum dma350_ch_intr_t intr); + +/** + * \brief Disables Interrupt for DMA350 DMA channel + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] intr Interrupt(s) to disable \ref dma350_ch_intr_t + * + * \return void + * + * \note This function doesn't check if dev is NULL or if it has been init. + */ +static inline +void dma350_ch_disable_intr(void __iomem *addr, enum dma350_ch_intr_t intr); +/** + * \brief Sets Source Trigger Input Select + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] srctriginsel Input Select value + * + * \return void + */ +static inline +void dma350_ch_set_srctriginsel(void __iomem *addr, + uint8_t srctriginsel); + +/** + * \brief Sets Source Trigger Input Type + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] type Input type \ref dma350_ch_srctrigintype_t + * + * \return void + */ +static inline +void dma350_ch_set_srctrigintype(void __iomem *addr, + enum dma350_ch_srctrigintype_t type); + +/** + * \brief Sets Source Trigger Input Mode + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] mode Mode \ref dma350_ch_srctriginmode_t + * + * \return void + */ +static inline +void dma350_ch_set_srctriginmode(void __iomem *addr, + enum dma350_ch_srctriginmode_t mode); + +/** + * \brief Sets Source Trigger Input Default Transfer Size + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] blksize Size value + * + * \return void + */ +static inline +void dma350_ch_set_srctriginblksize(void __iomem *addr, uint8_t blksize); + +/** + * \brief Sets Destination Trigger Input Select + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] destriginsel Input Select value + * + * \return void + */ +static inline +void dma350_ch_set_destriginsel(void __iomem *addr, uint8_t destriginsel); + +/** + * \brief Sets Destination Trigger Input Type + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] type Input type \ref dma350_ch_destrigintype_t + * + * \return void + */ +static inline +void dma350_ch_set_destrigintype(void __iomem *addr, + enum dma350_ch_destrigintype_t type); + +/** + * \brief Sets Destination Trigger Input Mode + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] mode Mode \ref dma350_ch_destriginmode_t + * + * \return void + */ +static inline +void dma350_ch_set_destriginmode(void __iomem *addr, + enum dma350_ch_destriginmode_t mode); + +/** + * \brief Sets Destination Trigger Input Default Transfer Size + * + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] blksize Size value + * + * \return void + */ +static inline +void dma350_ch_set_destriginblksize(void __iomem *addr, uint8_t blksize); + +/** + * \brief Sets Link Address Read Transfer Memory Attribute[3:0] field + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] memattrlo Attribute field + * + * \return void + */ +static inline +void dma350_ch_set_linkmemattrlo(void __iomem *addr, uint8_t memattrlo); + +/** + * \brief Sets Link Address Read Transfer Memory Attribute[7:4] field + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] memattrlo Attribute field + * + * \return void + */ +static inline +void dma350_ch_set_linkmemattrhi(void __iomem *addr, uint8_t memattrhi); + +/** + * \brief Sets Link Address Transfer Shareability Attribute + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] shareattr Attribute field + * + * \return void + */ +static inline +void dma350_ch_set_linkshareattr(void __iomem *addr, uint8_t shareattr); + +/** + * \brief Enables Link Address + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * + * \return void + */ +static inline +void dma350_ch_enable_linkaddr(void __iomem *addr); + +/** + * \brief Disables Link Address + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * + * \return void + */ +static inline +void dma350_ch_disable_linkaddr(void __iomem *addr); + +/** + * \brief Sets Link Address Pointer [31:2] + * + * \param[in] dev DMA350 channel device struct \ref dma350_ch_dev_t + * \param[in] linkaddr Memory location of the destination + * + * \return void + */ +static inline +void dma350_ch_set_linkaddr32(void __iomem *addr, uint32_t linkaddr); + + +/** + * \brief Sets addrCLEAR header bit in the command structure which clears all + * previous settings from the channel addristers + * + * \param[in] cmldink_cfg Command structure for DMA350 DMA command linking + * feature \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_regclear(struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Enables Interrupt for DMA350 DMA channel in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] intr Interrupt(s) to enable \ref dma350_ch_intr_t + * + * \return void + */ +static inline +void dma350_cmdlink_enable_intr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_intr_t intr); + +/** + * \brief Disables Interrupt for DMA350 DMA channel in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] intr Interrupt(s) to disable \ref dma350_ch_intr_t + * + * \return void + */ +static inline +void dma350_cmdlink_disable_intr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_intr_t intr); + +/** + * \brief Sets Transfer Enitity Size in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] transize size in bytes \ref dma350_ch_transize_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_transize(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint32_t transize); + +/** + * \brief Sets Channel Priority in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] chprio Number of priority + * + * \return void + */ +static inline +void dma350_cmdlink_set_chprio(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint8_t chprio); + +/** + * \brief Sets operation type for X direction in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] xtype type \ref dma350_ch_xtype_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_xtype(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_xtype_t xtype); + +/** + * \brief Sets when the STAT_DONE status flag is asserted during the command + * operation in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] donetype Done type selection \ref dma350_ch_donetype_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_donetype(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_donetype_t donetype); + +/** + * \brief Enables the automatic pause request for the current DMA operation + * if the STAT_DONE flag is asserted in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_enable_donepause( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Disables the automatic pause request for the current DMA operation + * if the STAT_DONE flag is asserted in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_disable_donepause( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Enables Source Trigger Input use in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_enable_srctrigin( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Disables Source Trigger Input use in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_disable_srctrigin( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Enables Destination Trigger Input use in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_enable_destrigin( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Disables Destination Trigger Input use in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_disable_destrigin( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Source Address[31:0] in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] src_addr Memory location of the source + * + * \return void + */ +static inline +void dma350_cmdlink_set_srcaddr32(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint32_t src_addr); + +/** + * \brief Sets Destination Address[31:0] in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] des_addr Memory location of the destination + * + * \return void + */ +static inline +void dma350_cmdlink_set_desaddr32(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint32_t des_addr); + +/** + * \brief Sets the number of data in the command structure units + * copied during the DMA command up to 16 bits in the X dimension + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] src_xsize Source number of transfers + * \param[in] des_xsize Destination number of transfers + * + * \return void + */ +static inline +void dma350_cmdlink_set_xsize16(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint16_t src_xsize, uint16_t des_xsize); + +/** + * \brief Sets the number of data in the command structure units + * copied during the DMA command up to 32 bits in the X dimension + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] src_xsize Source number of transfers + * \param[in] des_xsize Destination number of transfers + * + * \return void + */ +static inline +void dma350_cmdlink_set_xsize32(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint32_t src_xsize, uint32_t des_xsize); + +/** + * \brief Sets Source Transfer Memory Attribute field[3:0] + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] memattrlo Attribute field + * + * \return void + */ +static inline +void dma350_cmdlink_set_srcmemattrlo( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrlo); + +/** + * \brief Sets Source Transfer Memory Attribute field[7:4] + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] memattrhi Attribute field + * + * \return void + */ +static inline +void dma350_cmdlink_set_srcmemattrhi( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrhi); + +/** + * \brief Sets Source Transfer Shareability Attribute in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] shareattr Attribute field + * + * \return void + */ +static inline +void dma350_cmdlink_set_srcshareattr( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t shareattr); + +/** + * \brief Sets Destination Transfer Memory Attribute field[3:0] in the command + * structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] memattrlo Attribute field + * + * \return void + */ +static inline +void dma350_cmdlink_set_desmemattrlo( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrlo); + +/** + * \brief Sets Destination Transfer Memory Attribute field[7:4] in the command + * structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] memattrhi Attribute field + * + * \return void + */ +static inline +void dma350_cmdlink_set_desmemattrhi( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrhi); + +/** + * \brief Sets Destination Transfer Shareability Attribute in the command + * structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] shareattr Attribute field + * + * \return void + */ +static inline +void dma350_cmdlink_set_desshareattr( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t shareattr); + +/** + * \brief Sets Source Transfer Attribute to secure in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_src_trans_secure( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Source Transfer Attribute to non secure in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_src_trans_nonsecure( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Destination Transfer Attribute to secure in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_des_trans_secure( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Destination Transfer Attribute to non secure + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_des_trans_nonsecure( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Source Transfer Privilege to privileged + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_src_trans_privileged( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Source Transfer Privilege to unprivileged + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_src_trans_unprivileged( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Destination Transfer Privilege to privileged + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_des_trans_privileged( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Destination Transfer Privilege to unprivileged + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_des_trans_unprivileged( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Source Max Burst Length in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] length Value of max burst length + * + * \return void + */ +static inline +void dma350_cmdlink_set_srcmaxburstlen( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t length); + +/** + * \brief Sets Destination Max Burst Length in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] length Value of max burst length + * + * \return void + */ +static inline +void dma350_cmdlink_set_desmaxburstlen( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t length); + +/** + * \brief Sets the increment value in the command structure that is used to + * update the source and the destination addresses after each + * transferred data unit + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] src_xaddrinc Source X dimension address increment value + * \param[in] des_xaddrinc Destination X dimension address increment value + * + * \return void + */ +static inline +void dma350_cmdlink_set_xaddrinc(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint16_t src_xaddrinc, uint16_t des_xaddrinc); + +/** + * \brief Sets Source Trigger Input Select in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] srctriginsel Input Select value + * + * \return void + */ +static inline +void dma350_cmdlink_set_srctriginsel( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t srctriginsel); + +/** + * \brief Sets Source Trigger Input Type in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] type Input type \ref dma350_ch_srctrigintype_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_srctrigintype( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_srctrigintype_t type); + +/** + * \brief Sets Source Trigger Input Mode in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] mode Mode \ref dma350_ch_srctriginmode_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_srctriginmode( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_srctriginmode_t mode); + +/** + * \brief Sets Source Trigger Input Default Transfer Size + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] blksize Size value + * + * \return void + */ +static inline +void dma350_cmdlink_set_srctriginblksize( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t blksize); + +/** + * \brief Sets Destination Trigger Input Select in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] destriginsel Input Select value + * + * \return void + */ +static inline +void dma350_cmdlink_set_destriginsel( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t destriginsel); + +/** + * \brief Sets Destination Trigger Input Type in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] type Input type \ref dma350_ch_destrigintype_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_destrigintype( + struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_destrigintype_t type); + +/** + * \brief Sets Destination Trigger Input Mode in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] mode Mode \ref dma350_ch_destriginmode_t + * + * \return void + */ +static inline +void dma350_cmdlink_set_destriginmode(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_destriginmode_t mode); + +/** + * \brief Sets Destination Trigger Input Default Transfer Size + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] blksize Size value + * + * \return void + */ +static inline +void dma350_cmdlink_set_destriginblksize(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t blksize); + +/** + * \brief Sets Link Address Read Transfer Memory Attribute[3:0] field + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] memattrlo Attribute field + * + * \return void + */ +static inline +void dma350_cmdlink_set_linkmemattrlo(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrlo); + +/** + * \brief Sets Link Address Read Transfer Memory Attribute[7:4] field + * in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] memattrlo Attribute field + * + * \return void + */ +static inline +void dma350_cmdlink_set_linkmemattrhi(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrhi); + +/** + * \brief Enables Infinite Automatic Command Restart in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_enable_cmdrestartinfen(struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Disables Infinite Automatic Command Restart in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_disable_cmdrestartinfen(struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Enables Link Address in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_enable_linkaddr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Disables Link Address in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static inline +void dma350_cmdlink_disable_linkaddr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +/** + * \brief Sets Link Address Pointer [31:2] in the command structure + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * \param[in] linkaddr Memory location of the destination + * + * \return void + */ +static inline +void dma350_cmdlink_set_linkaddr32(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint32_t linkaddr); +/** + * \brief Initialize command structure for dma command linking feature + * + * \param[in] cmldink_cfg DMA350 command structure for command linking feature + * \ref dma350_cmdlink_gencfg_t + * + * \return void + */ +static void dma350_cmdlink_init(struct dma350_cmdlink_gencfg_t *cmdlink_cfg); + +static inline +void dma350_ch_set_src(void __iomem *addr, uint32_t src_addr) +{ + writel(src_addr, addr); +} + +static inline +void dma350_ch_set_des(void __iomem *addr, uint32_t des_addr) +{ + writel(des_addr, addr); +} + +static inline +void dma350_ch_set_xsize32(void __iomem *addr, uint32_t src_xsize, uint32_t des_xsize) +{ + writel(((des_xsize & 0x0000FFFFUL) << 16U) | (src_xsize & 0x0000FFFFUL), addr); + writel((des_xsize & 0xFFFF0000UL) | ((src_xsize & 0xFFFF0000UL) >> 16U), addr + 0x4); +} + +static inline +void dma350_ch_set_transize(void __iomem *addr, uint32_t transize) +{ + SET_FIELD(addr, transize, DMA350_CH_CTRL_TRANSIZE_Pos, + DMA350_CH_CTRL_TRANSIZE_Msk); +} + +static inline +void dma350_ch_set_chprio(void __iomem *addr, uint8_t chprio) +{ + SET_FIELD(addr, chprio, DMA350_CH_CTRL_CHPRIO_Pos, + DMA350_CH_CTRL_CHPRIO_Msk); +} + +static inline +void dma350_ch_set_xtype(void __iomem *addr, enum dma350_ch_xtype_t xtype) +{ + writel((readl(addr) & ~DMA350_CH_CTRL_XTYPE_Msk) | ((uint32_t)(xtype)), addr); +} + + +static inline +void dma350_ch_set_donetype(void __iomem *addr, + enum dma350_ch_donetype_t donetype) +{ + SET_FIELD(addr, donetype, DMA350_CH_CTRL_DONETYPE_Pos, + DMA350_CH_CTRL_DONETYPE_Msk); +} + + +static inline +void dma350_ch_enable_srctrigin(void __iomem *addr) +{ + writel(readl(addr) | DMA350_CH_CTRL_USESRCTRIGIN_Msk, addr); +} + +static inline +void dma350_ch_disable_srctrigin(void __iomem *addr) +{ + writel(readl(addr) & (~DMA350_CH_CTRL_USESRCTRIGIN_Msk), addr); +} + +static inline +void dma350_ch_enable_destrigin(void __iomem *addr) +{ + writel(readl(addr) | DMA350_CH_CTRL_USEDESTRIGIN_Msk, addr); +} + +static inline +void dma350_ch_disable_destrigin(void __iomem *addr) +{ + writel(readl(addr) & (~DMA350_CH_CTRL_USEDESTRIGIN_Msk), addr); +} + +static inline +void dma350_ch_set_srcmemattrlo(void __iomem *addr, uint8_t memattrlo) +{ + SET_FIELD(addr, memattrlo, + DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos, + DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Msk); +} + +static inline +void dma350_ch_set_srcmemattrhi(void __iomem *addr, uint8_t memattrhi) +{ + SET_FIELD(addr, memattrhi, + DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos, + DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Msk); +} + +static inline +void dma350_ch_src_memattr(void __iomem *addr, u32 memattrhi, u32 memattrlo) +{ + SET_FIELD(addr, memattrhi, + DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos, + DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Msk); + SET_FIELD(addr, memattrlo, + DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos, + DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Msk); +} + +static inline +void dma350_ch_set_desmemattrlo(void __iomem *addr, uint8_t memattrlo) +{ + SET_FIELD(addr, memattrlo, + DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos, + DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Msk); +} + +static inline +void dma350_ch_set_desmemattrhi(void __iomem *addr, uint8_t memattrhi) +{ + SET_FIELD(addr, memattrhi, + DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos, + DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Msk); +} + +static inline +void dma350_ch_des_memattr(void __iomem *addr, u32 memattrhi, u32 memattrlo) +{ + SET_FIELD(addr, memattrhi, + DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos, + DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Msk); + + SET_FIELD(addr, memattrlo, + DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos, + DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Msk); +} + +static inline +void dma350_ch_set_srcmaxburstlen(void __iomem *addr, uint8_t length) +{ + SET_FIELD(addr, length, + DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Pos, + DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Msk); +} + +static inline +void dma350_ch_set_desmaxburstlen(void __iomem *addr, uint8_t length) +{ + SET_FIELD(addr, length, + DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Pos, + DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Msk); +} + + +static inline +void dma350_ch_set_xaddr_inc(void __iomem *addr, int32_t src_xaddr_inc, + int32_t des_xaddr_inc) +{ + writel(((des_xaddr_inc & 0x0000FFFFUL) << DMA350_CH_XADDRINC_DESXADDRINC_Pos) | + (src_xaddr_inc & 0x0000FFFFUL), addr); +} + +static inline +void dma350_ch_set_srctriginsel(void __iomem *addr, uint8_t srctriginsel) +{ + SET_FIELD(addr, srctriginsel, + DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos, + DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Msk); +} + +static inline +void dma350_ch_set_srctrigintype(void __iomem *addr, enum dma350_ch_srctrigintype_t type) +{ + writel((readl(addr) & ~DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Msk) | ((uint32_t)(type)), addr); +} + +static inline +void dma350_ch_set_srctriginmode(void __iomem *addr, enum dma350_ch_srctriginmode_t mode) +{ + writel((readl(addr) & ~DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Msk) | ((uint32_t)(mode)), addr); +} + +static inline +void dma350_ch_set_srctriginblksize(void __iomem *addr, uint8_t blksize) +{ + SET_FIELD(addr, blksize, + DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos, + DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Msk); +} + +static inline +void dma350_ch_set_destriginsel(void __iomem *addr, uint8_t destriginsel) +{ + SET_FIELD(addr, destriginsel, + DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos, + DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Msk); +} + +static inline +void dma350_ch_set_destrigintype(void __iomem *addr, enum dma350_ch_destrigintype_t type) +{ + writel((readl(addr) & ~DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Msk) | ((uint32_t)(type)), addr); +} + +static inline +void dma350_ch_set_destriginmode(void __iomem *addr, enum dma350_ch_destriginmode_t mode) +{ + writel((readl(addr) & ~DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Msk) | ((uint32_t)(mode)), addr); +} + +static inline +void dma350_ch_set_destriginblksize(void __iomem *addr, uint8_t blksize) +{ + SET_FIELD(addr, blksize, + DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos, + DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Msk); +} + +static inline +void dma350_ch_set_linkmemattrlo(void __iomem *addr, uint8_t memattrlo) +{ + SET_FIELD(addr, memattrlo, + DMA350_CH_LINKATTR_LINKMEMATTRLO_Pos, + DMA350_CH_LINKATTR_LINKMEMATTRLO_Msk); +} + +static inline +void dma350_ch_set_linkmemattrhi(void __iomem *addr, uint8_t memattrhi) +{ + SET_FIELD(addr, memattrhi, + DMA350_CH_LINKATTR_LINKMEMATTRHI_Pos, + DMA350_CH_LINKATTR_LINKMEMATTRHI_Msk); +} + +static inline +void dma350_ch_set_linkshareattr(void __iomem *addr, uint8_t shareattr) +{ + SET_FIELD(addr, shareattr, + DMA350_CH_LINKATTR_LINKSHAREATTR_Pos, + DMA350_CH_LINKATTR_LINKSHAREATTR_Msk); +} + +static inline +void dma350_ch_enable_linkaddr(void __iomem *addr) +{ + writel(readl(addr) | DMA350_CH_LINKADDR_LINKADDREN_Msk, addr); +} + +static inline +void dma350_ch_set_linkaddr32(void __iomem *addr, uint32_t linkaddr) +{ + writel(linkaddr, addr); +} + +static inline +void dma350_ch_disable_linkaddr(void __iomem *addr) +{ + writel(0, addr); +} + +static inline +void dma350_cmdlink_set_regclear(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CLEAR_SET; +} + +static inline +void dma350_cmdlink_enable_intr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_intr_t intr) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_INTREN_SET; + cmdlink_cfg->cfg.intren |= intr; +} + +static inline +void dma350_cmdlink_disable_intr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_intr_t intr) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_INTREN_SET; + cmdlink_cfg->cfg.intren &= (~intr); +} + +static inline +void dma350_cmdlink_set_transize(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint32_t transize) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl = + (cmdlink_cfg->cfg.ctrl & (~DMA350_CH_CTRL_TRANSIZE_Msk)) | + (transize & DMA350_CH_CTRL_TRANSIZE_Msk); +} + +static inline +void dma350_cmdlink_set_chprio(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint8_t chprio) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl = + (cmdlink_cfg->cfg.ctrl & (~DMA350_CH_CTRL_CHPRIO_Msk)) | + (((chprio & 0x000000FFUL) << DMA350_CH_CTRL_CHPRIO_Pos) & + DMA350_CH_CTRL_CHPRIO_Msk); +} + +static inline +void dma350_cmdlink_set_xtype(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_xtype_t xtype) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl = (cmdlink_cfg->cfg.ctrl & (~DMA350_CH_CTRL_XTYPE_Msk)) | + (xtype & DMA350_CH_CTRL_XTYPE_Msk); +} + +static inline +void dma350_cmdlink_set_donetype(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + enum dma350_ch_donetype_t donetype) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl = + (cmdlink_cfg->cfg.ctrl & (~DMA350_CH_CTRL_DONETYPE_Msk)) | + (donetype & DMA350_CH_CTRL_DONETYPE_Msk); +} + +static inline +void dma350_cmdlink_enable_donepause(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl |= DMA350_CH_CTRL_DONEPAUSEEN_Msk; +} + +static inline +void dma350_cmdlink_disable_donepause(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl &= (~DMA350_CH_CTRL_DONEPAUSEEN_Msk); +} + +static inline +void dma350_cmdlink_enable_srctrigin(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl |= DMA350_CH_CTRL_USESRCTRIGIN_Msk; +} + +static inline +void dma350_cmdlink_disable_srctrigin(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl &= (~DMA350_CH_CTRL_USESRCTRIGIN_Msk); +} + +static inline +void dma350_cmdlink_enable_destrigin(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl |= DMA350_CH_CTRL_USEDESTRIGIN_Msk; +} + +static inline +void dma350_cmdlink_disable_destrigin(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl &= (~DMA350_CH_CTRL_USEDESTRIGIN_Msk); +} + +static inline +void dma350_cmdlink_enable_trigout(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl |= DMA350_CH_CTRL_USETRIGOUT_Msk; +} + +static inline +void dma350_cmdlink_disable_trigout(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl &= (~DMA350_CH_CTRL_USETRIGOUT_Msk); +} + +static inline +void dma350_cmdlink_enable_gpo(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl |= DMA350_CH_CTRL_USEGPO_Msk; +} + +static inline +void dma350_cmdlink_disable_gpo(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl &= (~DMA350_CH_CTRL_USEGPO_Msk); +} + +static inline +void dma350_cmdlink_enable_stream(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl |= DMA350_CH_CTRL_USESTREAM_Msk; +} + +static inline +void dma350_cmdlink_disable_stream(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_CTRL_SET; + cmdlink_cfg->cfg.ctrl &= (~DMA350_CH_CTRL_USESTREAM_Msk); +} + +static inline +void dma350_cmdlink_set_srcaddr32(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint32_t src_addr) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRC_ADDR_SET; + cmdlink_cfg->header &= (~DMA350_CMDLINK_SRC_ADDRHI_SET); + cmdlink_cfg->cfg.srcaddr = src_addr; +} + +static inline +void dma350_cmdlink_set_desaddr32(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint32_t des_addr) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DES_ADDR_SET; + cmdlink_cfg->header &= (~DMA350_CMDLINK_DES_ADDRHI_SET); + cmdlink_cfg->cfg.desaddr = des_addr; +} + +static inline +void dma350_cmdlink_set_xsize16(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint16_t src_xsize, uint16_t des_xsize) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_XSIZE_SET; + cmdlink_cfg->header &= (~DMA350_CMDLINK_XSIZEHI_SET); + cmdlink_cfg->cfg.xsize = (des_xsize & 0x0000FFFFUL) + << DMA350_CH_XSIZE_DESXSIZE_Pos; + cmdlink_cfg->cfg.xsize |= (src_xsize & 0x0000FFFFUL) + << DMA350_CH_XSIZE_SRCXSIZE_Pos; +} + +static inline +void dma350_cmdlink_set_xsize32(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint32_t src_xsize, uint32_t des_xsize) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_XSIZE_SET; + cmdlink_cfg->header |= DMA350_CMDLINK_XSIZEHI_SET; + cmdlink_cfg->cfg.xsize = (des_xsize & 0x0000FFFFUL) + << DMA350_CH_XSIZE_DESXSIZE_Pos; + cmdlink_cfg->cfg.xsize |= (src_xsize & 0x0000FFFFUL) + << DMA350_CH_XSIZE_SRCXSIZE_Pos; + cmdlink_cfg->cfg.xsizehi = (des_xsize & 0xFFFF0000UL); + cmdlink_cfg->cfg.xsizehi |= (src_xsize & 0xFFFF0000UL) >> 16; +} + +static inline +void dma350_cmdlink_set_srcmemattrlo(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrlo) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRANSCFG_SET; + cmdlink_cfg->cfg.srctranscfg = (cmdlink_cfg->cfg.srctranscfg & + (~DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Msk)) | + (((memattrlo & 0x000000FFUL) << DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos) & + DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Msk); +} + +static inline +void dma350_cmdlink_set_srcmemattrhi(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrhi) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRANSCFG_SET; + cmdlink_cfg->cfg.srctranscfg = (cmdlink_cfg->cfg.srctranscfg & + (~DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Msk)) | + (((memattrhi & 0x000000FFUL) << DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos) & + DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Msk); +} + +static inline +void dma350_cmdlink_set_srcshareattr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t shareattr) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRANSCFG_SET; + cmdlink_cfg->cfg.srctranscfg = (cmdlink_cfg->cfg.srctranscfg & + (~DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Msk)) | + (((shareattr & 0x000000FFUL) << DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Pos) & + DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Msk); +} + +static inline +void dma350_cmdlink_set_desmemattrlo(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrlo) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRANSCFG_SET; + cmdlink_cfg->cfg.destranscfg = (cmdlink_cfg->cfg.destranscfg & + (~DMA350_CH_DESTRANSCFG_DESSHAREATTR_Msk)) | + (((memattrlo & 0x000000FFUL) << DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos) & + DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Msk); +} + +static inline +void dma350_cmdlink_set_desmemattrhi(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrhi) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRANSCFG_SET; + cmdlink_cfg->cfg.destranscfg = (cmdlink_cfg->cfg.destranscfg & + (~DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Msk)) | + (((memattrhi & 0x000000FFUL) << DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos) & + DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Msk); +} + +static inline +void dma350_cmdlink_set_desshareattr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t shareattr) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRANSCFG_SET; + cmdlink_cfg->cfg.destranscfg = (cmdlink_cfg->cfg.destranscfg & + (~DMA350_CH_DESTRANSCFG_DESSHAREATTR_Msk)) | + (((shareattr & 0x000000FFUL) << DMA350_CH_DESTRANSCFG_DESSHAREATTR_Pos) & + DMA350_CH_DESTRANSCFG_DESSHAREATTR_Msk); +} + +static inline +void dma350_cmdlink_set_src_trans_secure(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRANSCFG_SET; + cmdlink_cfg->cfg.srctranscfg &= (~DMA350_CH_SRCTRANSCFG_SRCNONSECATTR_Msk); +} + +static inline +void dma350_cmdlink_set_src_trans_nonsecure(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->cfg.srctranscfg |= DMA350_CH_SRCTRANSCFG_SRCNONSECATTR_Msk; + if (cmdlink_cfg->cfg.srctranscfg == DMA350_CH_SRCTRANSCFG_RESET_VALUE) + cmdlink_cfg->header &= (~DMA350_CMDLINK_SRCTRANSCFG_SET); +} + +static inline +void dma350_cmdlink_set_des_trans_secure(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRANSCFG_SET; + cmdlink_cfg->cfg.destranscfg &= (~DMA350_CH_DESTRANSCFG_DESNONSECATTR_Msk); +} + +static inline +void dma350_cmdlink_set_des_trans_nonsecure(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->cfg.destranscfg |= DMA350_CH_DESTRANSCFG_DESNONSECATTR_Msk; + if (cmdlink_cfg->cfg.destranscfg == DMA350_CH_DESTRANSCFG_RESET_VALUE) + cmdlink_cfg->header &= (~DMA350_CMDLINK_DESTRANSCFG_SET); +} + +static inline +void dma350_cmdlink_set_src_trans_privileged(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRANSCFG_SET; + cmdlink_cfg->cfg.srctranscfg |= DMA350_CH_SRCTRANSCFG_SRCPRIVATTR_Msk; +} + +static inline +void dma350_cmdlink_set_src_trans_unprivileged(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->cfg.srctranscfg &= (~DMA350_CH_SRCTRANSCFG_SRCPRIVATTR_Msk); + if (cmdlink_cfg->cfg.srctranscfg == DMA350_CH_SRCTRANSCFG_RESET_VALUE) + cmdlink_cfg->header &= (~DMA350_CMDLINK_SRCTRANSCFG_SET); +} + +static inline +void dma350_cmdlink_set_des_trans_privileged(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRANSCFG_SET; + cmdlink_cfg->cfg.destranscfg |= DMA350_CH_DESTRANSCFG_DESPRIVATTR_Msk; +} + +static inline +void dma350_cmdlink_set_des_trans_unprivileged(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->cfg.destranscfg &= (~DMA350_CH_DESTRANSCFG_DESPRIVATTR_Msk); + if (cmdlink_cfg->cfg.destranscfg == DMA350_CH_DESTRANSCFG_RESET_VALUE) + cmdlink_cfg->header &= (~DMA350_CMDLINK_DESTRANSCFG_SET); +} + +static inline +void dma350_cmdlink_set_srcmaxburstlen(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t length) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRANSCFG_SET; + cmdlink_cfg->cfg.srctranscfg = (cmdlink_cfg->cfg.srctranscfg & + (~DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Msk)) | + (((length & 0x000000FFUL) << DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Pos) & + DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Msk); +} + +static inline +void dma350_cmdlink_set_desmaxburstlen(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t length) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRANSCFG_SET; + cmdlink_cfg->cfg.destranscfg = (cmdlink_cfg->cfg.destranscfg & + (~DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Msk)) | + (((length & 0x000000FFUL) << DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Pos) & + DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Msk); +} + +static inline +void dma350_cmdlink_set_xaddrinc(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, + uint16_t src_xaddrinc, uint16_t des_xaddrinc) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_XADDRINC_SET; + cmdlink_cfg->cfg.xaddrinc = (des_xaddrinc & 0x0000FFFFUL) + << DMA350_CH_XADDRINC_DESXADDRINC_Pos; + cmdlink_cfg->cfg.xaddrinc |= (src_xaddrinc & 0x0000FFFFUL) + << DMA350_CH_XADDRINC_SRCXADDRINC_Pos; +} + + +static inline +void dma350_cmdlink_set_srctriginsel(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t srctriginsel) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRIGINCFG_SET; + cmdlink_cfg->cfg.srctrigincfg = (cmdlink_cfg->cfg.srctrigincfg & + (~DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Msk)) | + (((srctriginsel & 0x000000FFUL) + << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) & + DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Msk); +} + +static inline +void dma350_cmdlink_set_srctrigintype(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, enum dma350_ch_srctrigintype_t type) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRIGINCFG_SET; + cmdlink_cfg->cfg.srctrigincfg = (cmdlink_cfg->cfg.srctrigincfg & + (~DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Msk)) | + (type & DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Msk); +} + +static inline +void dma350_cmdlink_set_srctriginmode(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, enum dma350_ch_srctriginmode_t mode) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRIGINCFG_SET; + cmdlink_cfg->cfg.srctrigincfg = (cmdlink_cfg->cfg.srctrigincfg & + (~DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Msk)) | + (mode & DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Msk); +} + +static inline +void dma350_cmdlink_set_srctriginblksize(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t blksize) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_SRCTRIGINCFG_SET; + cmdlink_cfg->cfg.srctrigincfg = (cmdlink_cfg->cfg.srctrigincfg & + (~DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Msk)) | (((blksize & 0x000000FFUL) + << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) & + DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Msk); +} + +static inline +void dma350_cmdlink_set_destriginsel(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t destriginsel) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRIGINCFG_SET; + cmdlink_cfg->cfg.destrigincfg = (cmdlink_cfg->cfg.destrigincfg & + (~DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Msk)) | + (((destriginsel & 0x000000FFUL) << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) & + DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Msk); +} + +static inline +void dma350_cmdlink_set_destrigintype(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, enum dma350_ch_destrigintype_t type) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRIGINCFG_SET; + cmdlink_cfg->cfg.destrigincfg = (cmdlink_cfg->cfg.destrigincfg & + (~DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Msk)) | + (type & DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Msk); +} + +static inline +void dma350_cmdlink_set_destriginmode(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, enum dma350_ch_destriginmode_t mode) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRIGINCFG_SET; + cmdlink_cfg->cfg.destrigincfg = (cmdlink_cfg->cfg.destrigincfg & + (~DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Msk)) | (mode & DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Msk); +} + +static inline +void dma350_cmdlink_set_destriginblksize(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t blksize) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_DESTRIGINCFG_SET; + cmdlink_cfg->cfg.destrigincfg = (cmdlink_cfg->cfg.destrigincfg & + (~DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Msk)) | (((blksize & 0x000000FFUL) + << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) & DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Msk); +} + + +static inline +void dma350_cmdlink_set_linkmemattrlo(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrlo) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_LINKATTR_SET; + cmdlink_cfg->cfg.linkattr = (cmdlink_cfg->cfg.linkattr & (~DMA350_CH_LINKATTR_LINKMEMATTRLO_Msk)) | + (((memattrlo & 0x000000FFUL) << DMA350_CH_LINKATTR_LINKMEMATTRLO_Pos) & + DMA350_CH_LINKATTR_LINKMEMATTRLO_Msk); +} + +static inline +void dma350_cmdlink_set_linkmemattrhi(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t memattrhi) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_LINKATTR_SET; + cmdlink_cfg->cfg.linkattr = (cmdlink_cfg->cfg.linkattr & (~DMA350_CH_LINKATTR_LINKMEMATTRHI_Msk)) | + (((memattrhi & 0x000000FFUL) << DMA350_CH_LINKATTR_LINKMEMATTRHI_Pos) & + DMA350_CH_LINKATTR_LINKMEMATTRHI_Msk); +} + +static inline +void dma350_cmdlink_set_linkshareattr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint8_t shareattr) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_LINKATTR_SET; + cmdlink_cfg->cfg.linkattr = (cmdlink_cfg->cfg.linkattr & (~DMA350_CH_LINKATTR_LINKSHAREATTR_Msk)) | + (((shareattr & 0x000000FFUL) << DMA350_CH_LINKATTR_LINKSHAREATTR_Pos) & + DMA350_CH_LINKATTR_LINKSHAREATTR_Msk); +} + + +static inline +void dma350_cmdlink_enable_cmdrestartinfen(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_AUTOCFG_SET; + cmdlink_cfg->cfg.autocfg |= DMA350_CH_AUTOCFG_CMDRESTARTINFEN_Msk; +} + +static inline +void dma350_cmdlink_disable_cmdrestartinfen(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_AUTOCFG_SET; + cmdlink_cfg->cfg.autocfg &= (~DMA350_CH_AUTOCFG_CMDRESTARTINFEN_Msk); +} + +static inline +void dma350_cmdlink_enable_linkaddr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_LINKADDR_SET; + cmdlink_cfg->cfg.linkaddr |= DMA350_CH_LINKADDR_LINKADDREN_Msk; +} + +static inline +void dma350_cmdlink_disable_linkaddr(struct dma350_cmdlink_gencfg_t *cmdlink_cfg) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_LINKADDR_SET; + cmdlink_cfg->cfg.linkaddr &= ~(DMA350_CH_LINKADDR_LINKADDREN_Msk); +} + +static inline +void dma350_cmdlink_set_linkaddr32(struct dma350_cmdlink_gencfg_t *cmdlink_cfg, uint32_t linkaddr) +{ + cmdlink_cfg->header |= DMA350_CMDLINK_LINKADDR_SET; + cmdlink_cfg->header &= ~(DMA350_CMDLINK_LINKADDRHI_SET); + cmdlink_cfg->cfg.linkaddr = (cmdlink_cfg->cfg.linkaddr & (~DMA350_CH_LINKADDR_LINKADDR_Msk)) | + (linkaddr & DMA350_CH_LINKADDR_LINKADDR_Msk); +} + +static inline +void dma350_ch_cmd(void __iomem *addr, uint32_t cmd) +{ + writel(cmd, addr); +} + +static inline +void dma350_ch_enable_intr(void __iomem *addr, enum dma350_ch_intr_t intr) +{ + writel(readl(addr) | intr, addr); +} + +static inline +void dma350_ch_disable_intr(void __iomem *addr, enum dma350_ch_intr_t intr) +{ + writel(readl(addr) & (~intr), addr); +} + +#ifdef __cplusplus +} +#endif +#endif /* __DMA350_CH_DRV_H */ diff --git a/drivers/dma/dma350_regdef.h b/drivers/dma/dma350_regdef.h new file mode 100644 index 000000000000..2dc313c0a29c --- /dev/null +++ b/drivers/dma/dma350_regdef.h @@ -0,0 +1,1148 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0*/ +/* + * Copyright (c) 2022 Arm Limited. All rights reserved. + * Copyright 2024 Cix Technology Group Co., Ltd. + */ +#ifndef __DMA350_REGDEF_H +#define __DMA350_REGDEF_H + +/*DMA350 register define*/ +/*DMACH register summary*/ + +#define DMA350_REG_CMD 0x000 /* Channel DMA Command Register */ +#define DMA350_REG_STATUS 0x004 /* Channel Status Register */ +#define DMA350_REG_INTREN 0x008 /*Channel Interrupt Enable Register */ +#define DMA350_REG_CTRL 0x00C /*Channel Control Register */ +#define DMA350_REG_SRCADDR 0x010 /*Channel Source Address Register */ +#define DMA350_REG_DESADDR 0x018 /*Channel Destination Address Register */ +#define DMA350_REG_XSIZE 0x020 /*Channel X Dimension Size Register, Lower Bits [15:0] */ +#define DMA350_REG_XSIZEHI 0x024 /*Channel X Dimension Size Register, Lower Bits [31:16] */ +#define DMA350_REG_SRCTRANSCFG 0x028 /*Channel Source Transfer Configuration Register */ +#define DMA350_REG_DESTRANSCFG 0x02C /*Channel Destination Transfer Configuration Register */ +#define DMA350_REG_XADDRINC 0x030 /*Channel X Dimension Address Increment Register */ +#define DMA350_REG_YADDRSTRIDE 0x034 /*Channel Y Dimension Address Stride Register */ +#define DMA350_REG_FILLVAL 0x038 /*Channel Fill Pattern Value Register */ +#define DMA350_REG_YSIZE 0x03C /*Channel Y Dimensions Size Register */ +#define DMA350_REG_TMPLTCFG 0x040 /*Channel Template Configuration Register */ +#define DMA350_REG_SRCTMPLT 0x044 /*Channel Source Template Pattern Register */ +#define DMA350_REG_DESTMPLT 0x048 /*Channel Destination Template Pattern Register */ +#define DMA350_REG_SRCTRIGINCFG 0x04C /*Channel Source Trigger In Configuration Register */ +#define DMA350_REG_DESTRIGINCFG 0x050 /*Channel Destination Trigger In Configuration Register */ +#define DMA350_REG_LINKATTR 0x070 /* Channel Link Address Memory Attributes Register */ +#define DMA350_REG_AUTOCFG 0x074 /*Channel Automatic Command Restart Configuration Register */ +#define DMA350_REG_LINKADDR 0x078 /* Channel Link Address Register */ +#define DMA350_REG_LINKADDRHI 0x07C /* Channel Link Address Register, High Bits [63:32] */ +#define DMA350_REG_GPOREAD0 0x080 /* Channel GPO Read Value Register 0 */ +#define DMA350_REG_WRKREGPTR 0x088 /* Channel Working Register Pointer Register */ +#define DMA350_REG_WRKREGVAL 0x08C /* Channel - Working Register Value Register */ +#define DMA350_REG_ERRINFO 0x090 /* Channel Error Information Register */ +#define DMA350_REG_IIDR 0x0C8 /* Channel Implementation Identification Register */ +#define DMA350_REG_AIDR 0x0CC /* Channel Architecture Identification Register */ +#define DMA350_REG_ISSUECAP 0x0E8 /* Used for setting issuing capability threshold. */ + +#define DMA350_REG_CHINTRSTATUS0 0x200 /*Collated Non-Secure Channel Interrupt flags for channel 0 to channel 31*/ +#define DMA350_NONSSEC_CTRL 0xC + +/******************************************************************************/ +/* Field Definitions of Registers */ +/******************************************************************************/ +/******************************************************************************/ +/* DMACH */ +/******************************************************************************/ +/****************** Field definitions for CH_CMD register *******************/ +#define DMA350_CH_CMD_ENABLECMD_Pos (0U) +#define DMA350_CH_CMD_ENABLECMD_Msk (0x1UL << DMA350_CH_CMD_ENABLECMD_Pos) +#define CMD_ENABLECMD_Msk (1) +#define DMA350_CH_CMD_ENABLECMD (CMD_ENABLECMD_Msk) +/*!< ENABLECMD bit Channel Enable. When set to '1', enables the channel to + * run its programmed task. When set to '1', it cannot be set back to zero, + * and this field will automatically clear to zero when a DMA process is completed. + * To force the DMA to stop prematurely, you must use CH_CMD.STOPCMD instead. + */ + +#define DMA350_CH_CMD_CLEARCMD_Pos (1U) +#define DMA350_CH_CMD_CLEARCMD_Msk (0x1UL << DMA350_CH_CMD_CLEARCMD_Pos) /*!< 0x00000002UL*/ +#define DMA350_CH_CMD_CLEARCMD DMA350_CH_CMD_CLEARCMD_Msk +/*!< CLEARCMD bit DMA Clear command. When set to '1', it will remain high until all DMA + * channel registers and any internal queues and buffers are cleared, before returning to '0'. + * When set at the same time as ENABLECMD or while the DMA channel is already enabled, + * the clear will only occur after any ongoing DMA operation is either completed, + * stopped or disabled and the ENABLECMD bit is deasserted by the DMA. + */ +#define DMA350_CH_CMD_DISABLECMD_Pos (2U) +#define DMA350_CH_CMD_DISABLECMD_Msk (0x1UL << DMA350_CH_CMD_DISABLECMD_Pos) /*!< 0x00000004UL*/ +#define DMA350_CH_CMD_DISABLECMD DMA350_CH_CMD_DISABLECMD_Msk +/*!< DISABLECMD bit Disable DMA Operation at the end of the current DMA + * command operation. Once set to '1', this field will stay high and the current DMA + * command will be allowed to complete, but the DMA will not fetch the next linked + * command or will it auto-restart the DMA command even if they are set. + * Once the DMA has stopped, it will return to '0' and ENABLECMD is also cleared. + * When set at the same time as ENABLECMD or when the channel is not enabled then + * write to this register is ignored. + */ +#define DMA350_CH_CMD_STOPCMD_Pos (3U) +#define DMA350_CH_CMD_STOPCMD_Msk (0x1UL << DMA350_CH_CMD_STOPCMD_Pos) /*!< 0x00000008UL*/ +#define DMA350_CH_CMD_STOPCMD DMA350_CH_CMD_STOPCMD_Msk +/*!< STOPCMD bit Stop Current DMA Operation. Once set to '1', his will remain high until + * the DMA channel is stopped cleanly. Then this will return to '0' and ENABLECMD is + * also cleared. When set at the same time as ENABLECMD or when the channel is not enabled + * then write to this register is ignored. Note that each DMA channel can have other sources + * of a stop request and this field will not reflect the state of the other sources. + */ +#define DMA350_CH_CMD_PAUSECMD_Pos (4U) +#define DMA350_CH_CMD_PAUSECMD_Msk (0x1UL << DMA350_CH_CMD_PAUSECMD_Pos) /*!< 0x00000010UL*/ +#define DMA350_CH_CMD_PAUSECMD DMA350_CH_CMD_PAUSECMD_Msk +/*!< PAUSECMD bit Pause Current DMA Operation. Once set to '1' the status cannot + * change until the DMA operation reached the paused state indicated by the + * STAT_PAUSED and STAT_RESUMEWAIT bits. The bit can be set by SW by writing it to '1', + * the current active DMA operation will be paused as soon as possible, but the ENABLECMD + * bit will remain HIGH to show that the operation is still active. + * Cleared automatically when STAT_RESUMEWAIT is set and the RESUMECMD bit is written to '1', + * meaning that the SW continues the operation of the channel. + * Note that each DMA channel can have other sources of a pause request and this field will + * not reflect the state of the other sources. When set at the same time as ENABLECMD or + * when the channel is not enabled then write to this register is ignored. + */ +#define DMA350_CH_CMD_RESUMECMD_Pos (5U) +#define DMA350_CH_CMD_RESUMECMD_Msk (0x1UL << DMA350_CH_CMD_RESUMECMD_Pos) /*!< 0x00000020UL*/ +#define DMA350_CH_CMD_RESUMECMD DMA350_CH_CMD_RESUMECMD_Msk +/*!< RESUMECMD bit Resume Current DMA Operation. + * Writing this bit to '1' means that the DMAC can continue + * the operation of a paused channel. Can be set to '1' when + * the PAUSECMD or a STAT_DONE assertion with DONEPAUSEEN set + * HIGH results in pausing the current DMA channel operation + * indicated by the STAT_PAUSED and STAT_RESUMEWAIT bits. + * Otherwise, writes to this bit are ignored. + */ +#define DMA350_CH_CMD_SRCSWTRIGINREQ_Pos (16U) +#define DMA350_CH_CMD_SRCSWTRIGINREQ_Msk (0x1UL << DMA350_CH_CMD_SRCSWTRIGINREQ_Pos) /*!< 0x00010000UL*/ +#define DMA350_CH_CMD_SRCSWTRIGINREQ DMA350_CH_CMD_SRCSWTRIGINREQ_Msk +/*!< SRCSWTRIGINREQ bit Software Generated Source Trigger Input Request. + * Write to '1' to create a SW trigger request to the DMA with the specified type + * in the SRCSWTRIGINTYPE register. Once set to '1', this will remain high until + * the DMA accepted the trigger and will return this to '0'. + * It will also be cleared automatically if the current command is completed + * without expecting another trigger event. + * When the channel is not enabled, write to this register is ignored. + */ +#define DMA350_CH_CMD_SRCSWTRIGINTYPE_Pos (17U) +#define DMA350_CH_CMD_SRCSWTRIGINTYPE_Msk (0x3UL << DMA350_CH_CMD_SRCSWTRIGINTYPE_Pos) /*!< 0x00060000UL*/ +#define DMA350_CH_CMD_SRCSWTRIGINTYPE DMA350_CH_CMD_SRCSWTRIGINTYPE_Msk +/*!< SRCSWTRIGINTYPE[ 1:0] bits Software Generated Source Trigger Input Request Type. + * Selects the trigger request type for the source trigger input when the SW triggers the SRCSWTRIGINREQ bit. + *- 00: Single request + *- 01: Last single request + *- 10: Block request + *- 11: Last block request + *This field cannot be changed while the SRCSWTRIGINREQ bit is set. + */ +#define DMA350_CH_CMD_SRCSWTRIGINTYPE_0 (0x1UL << DMA350_CH_CMD_SRCSWTRIGINTYPE_Pos) /*!< 0x00020000UL*/ +#define DMA350_CH_CMD_SRCSWTRIGINTYPE_1 (0x2UL << DMA350_CH_CMD_SRCSWTRIGINTYPE_Pos) /*!< 0x00040000UL*/ +#define DMA350_CH_CMD_DESSWTRIGINREQ_Pos (20U) +#define DMA350_CH_CMD_DESSWTRIGINREQ_Msk (0x1UL << DMA350_CH_CMD_DESSWTRIGINREQ_Pos) /*!< 0x00100000UL*/ +#define DMA350_CH_CMD_DESSWTRIGINREQ DMA350_CH_CMD_DESSWTRIGINREQ_Msk +/*!< DESSWTRIGINREQ bit Software Generated Destination Trigger Input Request. + * Write to '1' to create a SW trigger request to the DMA with the specified + * type in the DESSWTRIGINTYPE register. Once set to '1', this will remain + * high until the DMA is accepted the trigger and will return this to '0'. + * It will also be cleared automatically if the current command is completed + * without expecting another trigger event. + * When the channel is not enabled, write to this register is ignored. + */ +#define DMA350_CH_CMD_DESSWTRIGINTYPE_Pos (21U) +#define DMA350_CH_CMD_DESSWTRIGINTYPE_Msk (0x3UL << DMA350_CH_CMD_DESSWTRIGINTYPE_Pos) /*!< 0x00600000UL*/ +#define DMA350_CH_CMD_DESSWTRIGINTYPE DMA350_CH_CMD_DESSWTRIGINTYPE_Msk +/*!< DESSWTRIGINTYPE[ 1:0] bits Software Generated Destination Trigger Input Request Type. + * Selects the trigger request type for the destination trigger input when the SW triggers the DESSWTRIGINREQ bit. + * - 00: Single request + * - 01: Last single request + * - 10: Block request + * - 11: Last block request + *This field cannot be changed while the DESSWTRIGINREQ bit is set. + */ +#define DMA350_CH_CMD_DESSWTRIGINTYPE_0 (0x1UL << DMA350_CH_CMD_DESSWTRIGINTYPE_Pos) /*!< 0x00200000UL*/ +#define DMA350_CH_CMD_DESSWTRIGINTYPE_1 (0x2UL << DMA350_CH_CMD_DESSWTRIGINTYPE_Pos) /*!< 0x00400000UL*/ +#define DMA350_CH_CMD_SWTRIGOUTACK_Pos (24U) +#define DMA350_CH_CMD_SWTRIGOUTACK_Msk (0x1UL << DMA350_CH_CMD_SWTRIGOUTACK_Pos) /*!< 0x01000000UL*/ +#define DMA350_CH_CMD_SWTRIGOUTACK DMA350_CH_CMD_SWTRIGOUTACK_Msk +/*!< SWTRIGOUTACK bit Software Generated Trigger Output Acknowledge. + * Write '1' to acknowledge a Trigger Output request from the DMA. + * Once set to '1', this will remain high until the DMA Trigger Output + * is raised (either on the trigger output signal or as an interrupt) and + * the acknowledge is accepted. When the channel is not enabled, write to this register is ignored. + */ +/***************** Field definitions for CH_STATUS register *****************/ +#define DMA350_CH_STATUS_INTR_DONE_Pos (0U) +#define DMA350_CH_STATUS_INTR_DONE_Msk (0x1UL << DMA350_CH_STATUS_INTR_DONE_Pos) +#define DMA350_CH_STATUS_INTR_DONE DMA350_CH_STATUS_INTR_DONE_Msk +/*!< INTR_DONE bit Done Interrupt Flag. This interrupt will be set to HIGH if the INTREN_DONE + * is set and the STAT_DONE status flag gets raised. + * Automatically cleared when STAT_DONE is cleared. + */ +#define DMA350_CH_STATUS_INTR_ERR_Pos (1U) +#define DMA350_CH_STATUS_INTR_ERR_Msk (0x1UL << DMA350_CH_STATUS_INTR_ERR_Pos) +#define DMA350_CH_STATUS_INTR_ERR DMA350_CH_STATUS_INTR_ERR_Msk +/*!< INTR_ERR bit Error Interrupt Flag. This interrupt will be set to HIGH if the INTREN_ERR + * is set and the STAT_ERR status flag gets raised. + * Automatically cleared when STAT_ERR is cleared. + */ +#define DMA350_CH_STATUS_INTR_DISABLED_Pos (2U) +#define DMA350_CH_STATUS_INTR_DISABLED_Msk (0x1UL << DMA350_CH_STATUS_INTR_DISABLED_Pos) +#define DMA350_CH_STATUS_INTR_DISABLED DMA350_CH_STATUS_INTR_DISABLED_Msk +/*!< INTR_DISABLED bit Disabled Interrupt Flag. This interrupt will be set to HIGH if the + * INTREN_DISABLED is set and the STAT_DISABLED flag gets raised. + * Automatically cleared when STAT_DISABLED is cleared. + */ +#define DMA350_CH_STATUS_INTR_STOPPED_Pos (3U) +#define DMA350_CH_STATUS_INTR_STOPPED_Msk (0x1UL << DMA350_CH_STATUS_INTR_STOPPED_Pos) +#define DMA350_CH_STATUS_INTR_STOPPED DMA350_CH_STATUS_INTR_STOPPED_Msk +/*!< INTR_STOPPED bit Stopped Interrupt Flag. This interrupt will be set to HIGH if the INTREN_STOPPED + * is set and the STAT_STOPPED flag gets raised. Automatically cleared when STAT_STOPPED is cleared. + */ +#define DMA350_CH_STATUS_INTR_SRCTRIGINWAIT_Pos (8U) +#define DMA350_CH_STATUS_INTR_SRCTRIGINWAIT_Msk (0x1UL << DMA350_CH_STATUS_INTR_SRCTRIGINWAIT_Pos) +#define DMA350_CH_STATUS_INTR_SRCTRIGINWAIT DMA350_CH_STATUS_INTR_SRCTRIGINWAIT_Msk +/*!< INTR_SRCTRIGINWAIT bit Channel is waiting for Source Trigger Interrupt Flag. + * This interrupt will be set to HIGH if the INTREN_SRCTRIGINWAIT is set and the STAT_SRCTRIGINWAIT + * status flag is asserted. Automatically cleared when STAT_SRCTRIGINWAIT is cleared. + */ +#define DMA350_CH_STATUS_INTR_DESTRIGINWAIT_Pos (9U) +#define DMA350_CH_STATUS_INTR_DESTRIGINWAIT_Msk (0x1UL << DMA350_CH_STATUS_INTR_DESTRIGINWAIT_Pos) +#define DMA350_CH_STATUS_INTR_DESTRIGINWAIT DMA350_CH_STATUS_INTR_DESTRIGINWAIT_Msk +/*!< INTR_DESTRIGINWAIT bit Channel is waiting for Destination Trigger Interrupt Flag. + * This interrupt will be set to HIGH if the INTREN_DESTRIGINWAIT is set and the STAT_DESTRIGINWAIT + * status flag is asserted. Automatically cleared when STAT_DESTRIGINWAIT is cleared. + */ +#define DMA350_CH_STATUS_INTR_TRIGOUTACKWAIT_Pos (10U) +#define DMA350_CH_STATUS_INTR_TRIGOUTACKWAIT_Msk (0x1UL << DMA350_CH_STATUS_INTR_TRIGOUTACKWAIT_Pos) +#define DMA350_CH_STATUS_INTR_TRIGOUTACKWAIT DMA350_CH_STATUS_INTR_TRIGOUTACKWAIT_Msk +/*!< INTR_TRIGOUTACKWAIT bit Channel is waiting for output Trigger Acknowledgment Interrupt Flag. + * This interrupt will be set to HIGH if the INTREN_TRIGOUTACKWAIT is set and the STAT_TRIGOUTACKWAIT + * status flag is asserted. Automatically cleared when STAT_TRIGOUTACKWAIT is cleared. + */ +#define DMA350_CH_STATUS_STAT_DONE_Pos (16U) +#define DMA350_CH_STATUS_STAT_DONE_Msk (0x1UL << DMA350_CH_STATUS_STAT_DONE_Pos) /*!< 0x00010000UL*/ +#define DMA350_CH_STATUS_STAT_DONE DMA350_CH_STATUS_STAT_DONE_Msk +/*!< STAT_DONE bit Done Status Flag. This flag will be set to HIGH when the DMA command + * reaches the state defined by the DONETYPE settings. When DONEPAUSEEN is set the DMA + * command operation is paused when this flag is asserted. + * Write '1' to this bit to clear it. Automatically cleared when the ENABLECMD is set. + */ +#define DMA350_CH_STATUS_STAT_ERR_Pos (17U) +#define DMA350_CH_STATUS_STAT_ERR_Msk (0x1UL << DMA350_CH_STATUS_STAT_ERR_Pos) /*!< 0x00020000UL*/ +#define DMA350_CH_STATUS_STAT_ERR DMA350_CH_STATUS_STAT_ERR_Msk +/*!< STAT_ERR bit Error Status Flag. This flag will be set to HIGH if the DMA encounters an error during its operation. + * The details about the error event can be found in the ERRINFO register. Write '1' to this bit to clear it. + * When cleared, it also clears the ERRINFO register. Automatically cleared when the ENABLECMD is set. + */ +#define DMA350_CH_STATUS_STAT_DISABLED_Pos (18U) +#define DMA350_CH_STATUS_STAT_DISABLED_Msk (0x1UL << DMA350_CH_STATUS_STAT_DISABLED_Pos) /*!< 0x00040000UL*/ +#define DMA350_CH_STATUS_STAT_DISABLED DMA350_CH_STATUS_STAT_DISABLED_Msk +/*!< STAT_DISABLED bit Disabled Status Flag. This flag will be set to HIGH if the DMA channel + * is successfully disabled using the DISABLECMD command. + * Write '1' to this bit to clear it. Automatically cleared when the ENABLECMD is set. + */ +#define DMA350_CH_STATUS_STAT_STOPPED_Pos (19U) +#define DMA350_CH_STATUS_STAT_STOPPED_Msk (0x1UL << DMA350_CH_STATUS_STAT_STOPPED_Pos) /*!< 0x00080000UL*/ +#define DMA350_CH_STATUS_STAT_STOPPED DMA350_CH_STATUS_STAT_STOPPED_Msk +/*!< STAT_STOPPED bit Stopped Status Flag. This flag will be set to HIGH if the DMA channel + * successfully reached the stopped state. The stop request can come from many internal or external sources. + * Write '1' to this bit to clear it. Automatically cleared when the ENABLECMD is set. + */ +#define DMA350_CH_STATUS_STAT_PAUSED_Pos (20U) +#define DMA350_CH_STATUS_STAT_PAUSED_Msk (0x1UL << DMA350_CH_STATUS_STAT_PAUSED_Pos) /*!< 0x00100000UL*/ +#define DMA350_CH_STATUS_STAT_PAUSED DMA350_CH_STATUS_STAT_PAUSED_Msk +/*!< STAT_PAUSED bit Paused Status Flag. This flag will be set to HIGH if the DMA channel + * successfully paused the operation of the command. The pause request can come from many + * internal or external sources. When the request to pause is not asserted anymore the + * bit will be cleared automatically and the command operation can continue. + */ +#define DMA350_CH_STATUS_STAT_RESUMEWAIT_Pos (21U) +#define DMA350_CH_STATUS_STAT_RESUMEWAIT_Msk (0x1UL << DMA350_CH_STATUS_STAT_RESUMEWAIT_Pos) +#define DMA350_CH_STATUS_STAT_RESUMEWAIT DMA350_CH_STATUS_STAT_RESUMEWAIT_Msk +/*!< STAT_RESUMEWAIT bit Waiting for resume from software Flag. + * This flag indicates that the DMA channel successfully paused the operation of the command + * and needs SW acknowledgment to resume the operation. Will be set to HIGH if STAT_PAUSED is + * asserted and the PAUSECMD bit set in the command register or when the STAT_DONE is asserted + * and the DONEPAUSEEN bit is set. Cleared when the RESUMECMD bit is set in the command register. + */ +#define DMA350_CH_STATUS_STAT_SRCTRIGINWAIT_Pos (24U) +#define DMA350_CH_STATUS_STAT_SRCTRIGINWAIT_Msk (0x1UL << DMA350_CH_STATUS_STAT_SRCTRIGINWAIT_Pos) +#define DMA350_CH_STATUS_STAT_SRCTRIGINWAIT DMA350_CH_STATUS_STAT_SRCTRIGINWAIT_Msk +/*!< STAT_SRCTRIGINWAIT bit Channel is waiting for Source Trigger Status. + * This bit is set to HIGH when DMA channel starts waiting for source input trigger request. + * Automatically cleared when the source trigger request is received either from HW or SW source. + */ +#define DMA350_CH_STATUS_STAT_DESTRIGINWAIT_Pos (25U) +#define DMA350_CH_STATUS_STAT_DESTRIGINWAIT_Msk (0x1UL << DMA350_CH_STATUS_STAT_DESTRIGINWAIT_Pos) +#define DMA350_CH_STATUS_STAT_DESTRIGINWAIT DMA350_CH_STATUS_STAT_DESTRIGINWAIT_Msk +/*!< STAT_DESTRIGINWAIT bit Channel is waiting for Destination Trigger Status. + * This bit is set to HIGH when DMA channel starts waiting for destination input trigger request. + * Automatically cleared when the destination trigger request is received either from HW or SW source. + */ +#define DMA350_CH_STATUS_STAT_TRIGOUTACKWAIT_Pos (26U) +#define DMA350_CH_STATUS_STAT_TRIGOUTACKWAIT_Msk (0x1UL << DMA350_CH_STATUS_STAT_TRIGOUTACKWAIT_Pos) +#define DMA350_CH_STATUS_STAT_TRIGOUTACKWAIT DMA350_CH_STATUS_STAT_TRIGOUTACKWAIT_Msk +/*!< STAT_TRIGOUTACKWAIT bit Channel is waiting for output Trigger Acknowledgment Status. + * This bit is set to HIGH when DMA channel starts waiting for output trigger acknowledgment. + * Automatically cleared when the output trigger acknowledgment is received either from HW or SW source. + */ +/***************** Field definitions for CH_INTREN register *****************/ +#define DMA350_CH_INTREN_INTREN_DONE_Pos (0U) +#define DMA350_CH_INTREN_INTREN_DONE_Msk (0x1UL << DMA350_CH_INTREN_INTREN_DONE_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_INTREN_INTREN_DONE DMA350_CH_INTREN_INTREN_DONE_Msk +/*!< INTREN_DONE bit Done Interrupt Enable. When set to HIGH, enables the INTR_DONE + * to be set and raise an interrupt when the STAT_DONE status flag is asserted. + * When set to LOW, it prevents INTR_DONE to be asserted. + * Currently pending interrupts are not affected by clearing this bit. + */ +#define DMA350_CH_INTREN_INTREN_ERR_Pos (1U) +#define DMA350_CH_INTREN_INTREN_ERR_Msk (0x1UL << DMA350_CH_INTREN_INTREN_ERR_Pos) /*!< 0x00000002UL*/ +#define DMA350_CH_INTREN_INTREN_ERR DMA350_CH_INTREN_INTREN_ERR_Msk +/*!< INTREN_ERR bit Error Interrupt Enable. When set to HIGH, enables INTR_ERROR to be + * set and raise an interrupt when the STAT_ERR status flag is asserted. + * When set to LOW, it prevents INTR_ERR to be asserted. + * Currently pending interrupts are not affected by clearing this bit. + */ +#define DMA350_CH_INTREN_INTREN_DISABLED_Pos (2U) +#define DMA350_CH_INTREN_INTREN_DISABLED_Msk (0x1UL << DMA350_CH_INTREN_INTREN_DISABLED_Pos) /*!< 0x00000004UL*/ +#define DMA350_CH_INTREN_INTREN_DISABLED DMA350_CH_INTREN_INTREN_DISABLED_Msk +/*!< INTREN_DISABLED bit Disabled Interrupt Enable. When set to HIGH, enables INTR_DISABLED + * to be set and raise an interrupt when STAT_DISABLED status flag is asserted. + * When set to LOW, it prevents INTR_DISABLED to be asserted. + * Currently pending interrupts are not affected by clearing this bit. + */ +#define DMA350_CH_INTREN_INTREN_STOPPED_Pos (3U) +#define DMA350_CH_INTREN_INTREN_STOPPED_Msk (0x1UL << DMA350_CH_INTREN_INTREN_STOPPED_Pos) /*!< 0x00000008UL*/ +#define DMA350_CH_INTREN_INTREN_STOPPED DMA350_CH_INTREN_INTREN_STOPPED_Msk +/*!< INTREN_STOPPED bit Stopped Interrupt Enable. When set to HIGH, enables INTR_STOPPED to be set + * and raise an interrupt when STAT_STOPPED status flag is asserted. + * When set to LOW, it prevents INTR_STOPPED to be asserted. + * Currently pending interrupts are not affected by clearing this bit. + */ +#define DMA350_CH_INTREN_INTREN_SRCTRIGINWAIT_Pos (8U) +#define DMA350_CH_INTREN_INTREN_SRCTRIGINWAIT_Msk (0x1UL << DMA350_CH_INTREN_INTREN_SRCTRIGINWAIT_Pos) +#define DMA350_CH_INTREN_INTREN_SRCTRIGINWAIT DMA350_CH_INTREN_INTREN_SRCTRIGINWAIT_Msk +/*!< INTREN_SRCTRIGINWAIT bit Channel is waiting for Source Trigger Interrupt Enable. + * When set to HIGH, enables INTR_SRCTRIGINWAIT to be set and raise an interrupt when STAT_SRCTRIGINWAIT + * status flag is asserted. When set to LOW, it prevents INTR_SRCTRIGINWAIT to be asserted. + * Currently pending interrupts are not affected by clearing this bit. + */ +#define DMA350_CH_INTREN_INTREN_DESTRIGINWAIT_Pos (9U) +#define DMA350_CH_INTREN_INTREN_DESTRIGINWAIT_Msk (0x1UL << DMA350_CH_INTREN_INTREN_DESTRIGINWAIT_Pos) +#define DMA350_CH_INTREN_INTREN_DESTRIGINWAIT DMA350_CH_INTREN_INTREN_DESTRIGINWAIT_Msk +/*!< INTREN_DESTRIGINWAIT bit Channel is waiting for destination Trigger Interrupt Enable. + * When set to HIGH, enables INTR_DESTRIGINWAIT to be set and raise an interrupt when STAT_DESTRIGINWAIT + * status flag is asserted. When set to LOW, it prevents INTR_DESTRIGINWAIT to be asserted. + * Currently pending interrupts are not affected by clearing this bit. + */ +#define DMA350_CH_INTREN_INTREN_TRIGOUTACKWAIT_Pos (10U) +#define DMA350_CH_INTREN_INTREN_TRIGOUTACKWAIT_Msk (0x1UL << DMA350_CH_INTREN_INTREN_TRIGOUTACKWAIT_Pos) +#define DMA350_CH_INTREN_INTREN_TRIGOUTACKWAIT DMA350_CH_INTREN_INTREN_TRIGOUTACKWAIT_Msk +/*!< INTREN_TRIGOUTACKWAIT bit Channel is waiting for output Trigger Acknowledgment Interrupt Enable. + * When set to HIGH, enables INTR_TRIGOUTACKWAIT to be set and raise an interrupt when STAT_TRIGOUTACKWAIT + * status flag is asserted. When set to LOW, it prevents INTR_TRIGOUTACKWAIT to be asserted. Currently pending + * interrupts are not affected by clearing this bit. + */ +/****************** Field definitions for CH_CTRL register ******************/ +#define DMA350_CH_CTRL_TRANSIZE_Pos (0U) +#define DMA350_CH_CTRL_TRANSIZE_Msk (0x7UL << DMA350_CH_CTRL_TRANSIZE_Pos) /*!< 0x00000007UL*/ +#define DMA350_CH_CTRL_TRANSIZE DMA350_CH_CTRL_TRANSIZE_Msk +/*!< TRANSIZE[ 2:0] bits Transfer Entity Size. Size in bytes = 2^TRANSIZE. + *- 000: Byte + *- 001: Halfworld + *- 010: Word + *- 011: Doubleword + *- 100: 128bits + *- 101: 256bits + *- 110: 512bits + *- 111: 1024bits + *Note that DATA_WIDTH limits this field. Address will be aligned to TRANSIZE by the DMAC by ignoring the lower bits. + */ +#define DMA350_CH_CTRL_TRANSIZE_0 (0x1UL << DMA350_CH_CTRL_TRANSIZE_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_CTRL_TRANSIZE_1 (0x2UL << DMA350_CH_CTRL_TRANSIZE_Pos) /*!< 0x00000002UL*/ +#define DMA350_CH_CTRL_TRANSIZE_2 (0x4UL << DMA350_CH_CTRL_TRANSIZE_Pos) /*!< 0x00000004UL*/ +#define DMA350_CH_CTRL_CHPRIO_Pos (4U) +#define DMA350_CH_CTRL_CHPRIO_Msk (0xFUL << DMA350_CH_CTRL_CHPRIO_Pos) /*!< 0x000000F0UL*/ +#define DMA350_CH_CTRL_CHPRIO DMA350_CH_CTRL_CHPRIO_Msk +/*!< CHPRIO[ 3:0] bits Channel Priority. + *- 0: Lowest Priority + *- 15: Highest Priority + */ +#define DMA350_CH_CTRL_CHPRIO_0 (0x1UL << DMA350_CH_CTRL_CHPRIO_Pos) /*!< 0x00000010UL*/ +#define DMA350_CH_CTRL_CHPRIO_1 (0x2UL << DMA350_CH_CTRL_CHPRIO_Pos) /*!< 0x00000020UL*/ +#define DMA350_CH_CTRL_CHPRIO_2 (0x4UL << DMA350_CH_CTRL_CHPRIO_Pos) /*!< 0x00000040UL*/ +#define DMA350_CH_CTRL_CHPRIO_3 (0x8UL << DMA350_CH_CTRL_CHPRIO_Pos) /*!< 0x00000080UL*/ +#define DMA350_CH_CTRL_XTYPE_Pos (9U) +#define DMA350_CH_CTRL_XTYPE_Msk (0x7UL << DMA350_CH_CTRL_XTYPE_Pos) /*!< 0x00000E00UL*/ +#define DMA350_CH_CTRL_XTYPE DMA350_CH_CTRL_XTYPE_Msk +/*!< XTYPE[ 2:0] bits Operation type for X direction: + *- 000: "disable" - No data transfer will take place for this command. This mode can be used to create + *empty commands that wait for an event or set GPOs. + *- 001: "continue" - Copy data in a continuous manner from source to the destination. + *For 1D operations it is expected that SRCXSIZE is equal to DESXSIZE, other combinations + *result in UNPREDICTABLE behavior. + *For 2D operations, this mode can be used for simple 2D to 2D copy but it also allows the + *reshaping of the data like 1D to + *2D or 2D to 1D conversions. If the DESXSIZE is smaller than SRCXSIZE then the read data + *from the current source line goes + *to the next destination line. If SRCXSIZE is smaller than DESXSIZE then the reads start + *on the next line and data is written + *to the remainder of the current destination line. Note: For 1D to 2D the SRCYSIZE for 2D + *to 1D conversion the DESYSIZE needs + *to be set to 1 when using this mode. + *- 010: "wrap" - Wrap source data within a destination line when the end of the source line is reached. + *Read starts again from the beginning of the source line and copied to the remainder of the destination line. + *If the DESXSIZE is smaller than SRCXSIZE then the behavior is UNPREDICTABLE. Not supported when HAS_WRAP is 0 in HW + *- 011: "fill" - Fill the remainder of the destination line with FILLVAL when the end of the source line is reached. + *If the DESXSIZE is smaller than SRCXSIZE then the behavior is UNPREDICTABLE. Not supported when HAS_WRAP is 0 in HW. + *- Others: Reserved. + */ +#define DMA350_CH_CTRL_XTYPE_0 (0x1UL << DMA350_CH_CTRL_XTYPE_Pos) /*!< 0x00000200UL*/ +#define DMA350_CH_CTRL_XTYPE_1 (0x2UL << DMA350_CH_CTRL_XTYPE_Pos) /*!< 0x00000400UL*/ +#define DMA350_CH_CTRL_XTYPE_2 (0x4UL << DMA350_CH_CTRL_XTYPE_Pos) /*!< 0x00000800UL*/ +#define DMA350_CH_CTRL_YTYPE_Pos (12U) +#define DMA350_CH_CTRL_YTYPE_Msk (0x7UL << DMA350_CH_CTRL_YTYPE_Pos) /*!< 0x00007000UL*/ +#define DMA350_CH_CTRL_YTYPE DMA350_CH_CTRL_YTYPE_Msk +/*!< YTYPE[ 2:0] bits Operation type for Y direction: + *- 000: "disable" - Only do 1D transfers. When HAS_2D is 0, meaning 2D capability is not supported in HW, + *the YTYPE is always "000". + *- 001: "continue" - Copy 2D data in a continuous manner from source area to the destination area by + *using the YSIZE registers. + *The copy stops when the source runs out of data or the destination runs out of space. Not supported + *when HAS_2D is 0 in HW. + *- 010: "wrap" - Wrap the 2D source area within the destination 2D area by starting to copy data + *from the beginning of the first source line to the remaining space in the destination area. + *If the destination area is smaller than the source area + *then the behavior is UNPREDICTABLE. Not supported when HAS_WRAP or HAS_2D is 0 in HW. + *- 011: Fill the remainder of the destination area with FILLVAL when the source area runs out of data. + *If the destination area is smaller than the source area then the behavior is UNPREDICTABLE. + *Not supported when HAS_WRAP or HAS_2D is 0 in HW + *- Others: Reserved + */ +#define DMA350_CH_CTRL_YTYPE_0 (0x1UL << DMA350_CH_CTRL_YTYPE_Pos) /*!< 0x00001000UL*/ +#define DMA350_CH_CTRL_YTYPE_1 (0x2UL << DMA350_CH_CTRL_YTYPE_Pos) /*!< 0x00002000UL*/ +#define DMA350_CH_CTRL_YTYPE_2 (0x4UL << DMA350_CH_CTRL_YTYPE_Pos) /*!< 0x00004000UL*/ +#define DMA350_CH_CTRL_REGRELOADTYPE_Pos (18U) +#define DMA350_CH_CTRL_REGRELOADTYPE_Msk (0x7UL << DMA350_CH_CTRL_REGRELOADTYPE_Pos) /*!< 0x001C0000UL*/ +#define DMA350_CH_CTRL_REGRELOADTYPE DMA350_CH_CTRL_REGRELOADTYPE_Msk +/*!< REGRELOADTYPE[ 2:0] bits Automatic register reload type. Defines how the DMA command reloads + * initial values at the end of a DMA command before autorestarting, ending or linking to a new DMA command: + *- 000: Reload Disabled. + *- 001: Reload source and destination size registers only. + *- 011: Reload source address only and all source and destination size registers. + *- 101: Reload destination address only and all source and destination size registers. + *- 111: Reload source and destination address and all source and destination size registers. + *- Others: Reserved. + *NOTE: When CLEARCMD is set, the reloaded registers will also be cleared. + */ +#define DMA350_CH_CTRL_REGRELOADTYPE_0 (0x1UL << DMA350_CH_CTRL_REGRELOADTYPE_Pos) /*!< 0x00040000UL*/ +#define DMA350_CH_CTRL_REGRELOADTYPE_1 (0x2UL << DMA350_CH_CTRL_REGRELOADTYPE_Pos) /*!< 0x00080000UL*/ +#define DMA350_CH_CTRL_REGRELOADTYPE_2 (0x4UL << DMA350_CH_CTRL_REGRELOADTYPE_Pos) /*!< 0x00100000UL*/ +#define DMA350_CH_CTRL_DONETYPE_Pos (21U) +#define DMA350_CH_CTRL_DONETYPE_Msk (0x7UL << DMA350_CH_CTRL_DONETYPE_Pos) /*!< 0x00E00000UL*/ +#define DMA350_CH_CTRL_DONETYPE DMA350_CH_CTRL_DONETYPE_Msk +/*!< DONETYPE[ 2:0] bits Done type selection. This field defines when the STAT_DONE status flag + * is asserted during the command operation. + *- 000: STAT_DONE flag is not asserted for this command. + *- 001: End of a command, before jumping to the next linked command. (default) + *- 011: End of an autorestart cycle, before starting the next cycle. + *- Others : Reserved. + */ +#define DMA350_CH_CTRL_DONETYPE_0 (0x1UL << DMA350_CH_CTRL_DONETYPE_Pos) /*!< 0x00200000UL*/ +#define DMA350_CH_CTRL_DONETYPE_1 (0x2UL << DMA350_CH_CTRL_DONETYPE_Pos) /*!< 0x00400000UL*/ +#define DMA350_CH_CTRL_DONETYPE_2 (0x4UL << DMA350_CH_CTRL_DONETYPE_Pos) /*!< 0x00800000UL*/ +#define DMA350_CH_CTRL_DONEPAUSEEN_Pos (24U) +#define DMA350_CH_CTRL_DONEPAUSEEN_Msk (0x1UL << DMA350_CH_CTRL_DONEPAUSEEN_Pos) /*!< 0x01000000UL*/ +#define DMA350_CH_CTRL_DONEPAUSEEN DMA350_CH_CTRL_DONEPAUSEEN_Msk +/*!< DONEPAUSEEN bit Done pause enable. When set to HIGH the assertion of the STAT_DONE flag + * results in an automatic pause request for the current DMA operation. + * When the paused state is reached the STAT_RESUMEWAIT flag is also set. + * When set to LOW the assertion of the STAT_DONE does not pause the progress of the + * command and the next operation of the channel will be started immediately after the STAT_DONE flag is set. + */ +#define DMA350_CH_CTRL_USESRCTRIGIN_Pos (25U) +#define DMA350_CH_CTRL_USESRCTRIGIN_Msk (0x1UL << DMA350_CH_CTRL_USESRCTRIGIN_Pos) /*!< 0x02000000UL*/ +#define DMA350_CH_CTRL_USESRCTRIGIN DMA350_CH_CTRL_USESRCTRIGIN_Msk +/*!< USESRCTRIGIN bit Enable Source Trigger Input use for this command. + *- 0: disable + *- 1: enable + */ +#define DMA350_CH_CTRL_USEDESTRIGIN_Pos (26U) +#define DMA350_CH_CTRL_USEDESTRIGIN_Msk (0x1UL << DMA350_CH_CTRL_USEDESTRIGIN_Pos) /*!< 0x04000000UL*/ +#define DMA350_CH_CTRL_USEDESTRIGIN DMA350_CH_CTRL_USEDESTRIGIN_Msk +/*!< USEDESTRIGIN bit Enable Destination Trigger Input use for this command. + *- 0: disable + *- 1: enable + */ +#define DMA350_CH_CTRL_USETRIGOUT_Pos (27U) +#define DMA350_CH_CTRL_USETRIGOUT_Msk (0x1UL << DMA350_CH_CTRL_USETRIGOUT_Pos) /*!< 0x08000000UL*/ +#define DMA350_CH_CTRL_USETRIGOUT DMA350_CH_CTRL_USETRIGOUT_Msk +/*!< USETRIGOUT bit Enable Trigger Output use for this command. + *- 0: disable + *- 1: enable + */ +#define DMA350_CH_CTRL_USEGPO_Pos (28U) +#define DMA350_CH_CTRL_USEGPO_Msk (0x1UL << DMA350_CH_CTRL_USEGPO_Pos) /*!< 0x10000000UL*/ +#define DMA350_CH_CTRL_USEGPO DMA350_CH_CTRL_USEGPO_Msk +/*!< USEGPO bit Enable GPO use for this command. + *- 0: disable + *- 1: enable + */ +#define DMA350_CH_CTRL_USESTREAM_Pos (29U) +#define DMA350_CH_CTRL_USESTREAM_Msk (0x1UL << DMA350_CH_CTRL_USESTREAM_Pos) /*!< 0x20000000UL*/ +#define DMA350_CH_CTRL_USESTREAM DMA350_CH_CTRL_USESTREAM_Msk +/*!< USESTREAM bit Enable Stream Interface use for this command. + *- 0: disable + *- 1: enable + */ +/**************** Field definitions for CH_SRCADDR register *****************/ +#define DMA350_CH_SRCADDR_SRCADDR_Pos (0U) +#define DMA350_CH_SRCADDR_SRCADDR_Msk (0xFFFFFFFFUL << DMA350_CH_SRCADDR_SRCADDR_Pos) /*!< 0xFFFFFFFFUL*/ +#define DMA350_CH_SRCADDR_SRCADDR DMA350_CH_SRCADDR_SRCADDR_Msk +/*!< SRCADDR[31:0] bits Source Address [31:0]. + */ +/*************** Field definitions for CH_SRCADDRHI register ****************/ +#define DMA350_CH_SRCADDRHI_SRCADDRHI_Pos (0U) +#define DMA350_CH_SRCADDRHI_SRCADDRHI_Msk (0xFFFFFFFFUL << DMA350_CH_SRCADDRHI_SRCADDRHI_Pos) /*!< 0xFFFFFFFFUL*/ +#define DMA350_CH_SRCADDRHI_SRCADDRHI DMA350_CH_SRCADDRHI_SRCADDRHI_Msk +/*!< SRCADDRHI[31:0] bits Source Address [63:32]. Allows 64-bit addressing but the system might + * need less address bits defined by ADDR_WIDTH. The not implemented bits remain reserved. + */ +/**************** Field definitions for CH_DESADDR register *****************/ +#define DMA350_CH_DESADDR_DESADDR_Pos (0U) +#define DMA350_CH_DESADDR_DESADDR_Msk (0xFFFFFFFFUL << DMA350_CH_DESADDR_DESADDR_Pos) /*!< 0xFFFFFFFFUL*/ +#define DMA350_CH_DESADDR_DESADDR DMA350_CH_DESADDR_DESADDR_Msk +/*!< DESADDR[31:0] bits Destination Address[31:0] + */ +/*************** Field definitions for CH_DESADDRHI register ****************/ +#define DMA350_CH_DESADDRHI_DESADDRHI_Pos (0U) +#define DMA350_CH_DESADDRHI_DESADDRHI_Msk (0xFFFFFFFFUL << DMA350_CH_DESADDRHI_DESADDRHI_Pos) /*!< 0xFFFFFFFFUL*/ +#define DMA350_CH_DESADDRHI_DESADDRHI DMA350_CH_DESADDRHI_DESADDRHI_Msk +/*!< DESADDRHI[31:0] bits Destination Address[63:32]. Allows 64-bit addressing but the system might + * need less address bits defined by ADDR_WIDTH. The not implemented bits remain reserved. + */ +/***************** Field definitions for CH_XSIZE register ******************/ +#define DMA350_CH_XSIZE_SRCXSIZE_Pos (0U) +#define DMA350_CH_XSIZE_SRCXSIZE_Msk (0xFFFFUL << DMA350_CH_XSIZE_SRCXSIZE_Pos) /*!< 0x0000FFFFUL*/ +#define DMA350_CH_XSIZE_SRCXSIZE DMA350_CH_XSIZE_SRCXSIZE_Msk +/*!< SRCXSIZE[15:0] bits Source Number of Transfers in the X Dimension lower bits [15:0]. + * This register along with SRCXSIZEHI defines the source data block size of the DMA + * operation for any 1D operation, and defines the X dimension of the 2D source block for 2D operation. + */ +#define DMA350_CH_XSIZE_DESXSIZE_Pos (16U) +#define DMA350_CH_XSIZE_DESXSIZE_Msk (0xFFFFUL << DMA350_CH_XSIZE_DESXSIZE_Pos) /*!< 0xFFFF0000UL*/ +#define DMA350_CH_XSIZE_DESXSIZE DMA350_CH_XSIZE_DESXSIZE_Msk +/*!< DESXSIZE[15:0] bits Destination Number of Transfers in the X Dimension lower bits [15:0]. + * This register along with DESXSIZEHI defines the destination data block size of the DMA operation + * for or any 1D operation, and defines the X dimension of the 2D destination block for a 2D operation. + * HAS_WRAP or HAS_STREAM configuration needs to be set to allow writes to this register, otherwise it + * is read-only and writing to SRCXSIZE will also update the value of this register. + */ +/**************** Field definitions for CH_XSIZEHI register *****************/ +#define DMA350_CH_XSIZEHI_SRCXSIZEHI_Pos (0U) +#define DMA350_CH_XSIZEHI_SRCXSIZEHI_Msk (0xFFFFUL << DMA350_CH_XSIZEHI_SRCXSIZEHI_Pos) /*!< 0x0000FFFFUL*/ +#define DMA350_CH_XSIZEHI_SRCXSIZEHI DMA350_CH_XSIZEHI_SRCXSIZEHI_Msk +/*!< SRCXSIZEHI[15:0] bits Source Number of Transfers in the X Dimension high bits [31:16]. + * This register along with SRCXSIZE defines the source data block size of the DMA operation + * for any 1D operation, and defines the X dimension of the 2D source block for 2D operation. + */ +#define DMA350_CH_XSIZEHI_DESXSIZEHI_Pos (16U) +#define DMA350_CH_XSIZEHI_DESXSIZEHI_Msk (0xFFFFUL << DMA350_CH_XSIZEHI_DESXSIZEHI_Pos) /*!< 0xFFFF0000UL*/ +#define DMA350_CH_XSIZEHI_DESXSIZEHI DMA350_CH_XSIZEHI_DESXSIZEHI_Msk +/*!< DESXSIZEHI[15:0] bits Destination Number of Transfers in the X Dimension high bits [31:16]. + * This register along with DESXSIZE defines the destination data block size of the DMA operation + * for or any 1D operation, and defines the X dimension of the 2D destination block for a 2D operation. + * HAS_WRAP or HAS_STREAM configuration needs to be set to allow writes to this register, otherwise it + * is read-only and writing to SRCXSIZEHI will also update the value of this register. + */ +/************** Field definitions for CH_SRCTRANSCFG register ***************/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos (0U) +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Msk (0xFUL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos) /*!< 0x0000000FUL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Msk +/*!< SRCMEMATTRLO[ 3:0] bits Source Transfer Memory Attribute field [3:0]. + * When SRCMEMATTRHI is Device type (0000) then this field means: + *- 0000: Device-nGnRnE + *- 0100: Device-nGnRE + *- 1000: Device-nGRE + *- 1100: Device-GRE + *- Others: Invalid resulting in UNPREDICTABLE behavior + *When SRCMEMATTRHI is Normal memory type (other than 0000) then this field means: + *- 0000: Reserved + *- 0001: Normal memory, Inner Write allocate, Inner Write-through transient + *- 0010: Normal memory, Inner Read allocate, Inner Write-through transient + *- 0011: Normal memory, Inner Read/Write allocate, Inner Write-through transient + *- 0100: Normal memory, Inner non-cacheable + *- 0101: Normal memory, Inner Write allocate, Inner Write-back transient + *- 0110: Normal memory, Inner Read allocate, Inner Write-back transient + *- 0111: Normal memory, Inner Read/Write allocate, Inner Write-back transient + *- 1000: Normal memory, Inner Write-through non-transient + *- 1001: Normal memory, Inner Write allocate, Inner Write-through non-transient + *- 1010: Normal memory, Inner Read allocate, Inner Write-through non-transient + *- 1011: Normal memory, Inner Read/Write allocate, Inner Write-through non-transient + *- 1100: Normal memory, Inner Write-back non-transient + *- 1101: Normal memory, Inner Write allocate, Inner Write-back non-transient + *- 1110: Normal memory, Inner Read allocate, Inner Write-back non-transient + *- 1111: Normal memory, Inner Read/Write allocate, Inner Write-back non-transient + */ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_0 (0x1UL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_1 (0x2UL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos) /*!< 0x00000002UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_2 (0x4UL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos) /*!< 0x00000004UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_3 (0x8UL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRLO_Pos) /*!< 0x00000008UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos (4U) +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Msk (0xFUL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos) /*!< 0x000000F0UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Msk +/*!< SRCMEMATTRHI[ 3:0] bits Source Transfer Memory Attribute field [7:4]. + *- 0000: Device memory + *- 0001: Normal memory, Outer Write allocate, Outer Write-through transient + *- 0010: Normal memory, Outer Read allocate, Outer Write-through transient + *- 0011: Normal memory, Outer Read/Write allocate, Outer Write-through transient + *- 0100: Normal memory, Outer non-cacheable + *- 0101: Normal memory, Outer Write allocate, Outer Write-back transient + *- 0110: Normal memory, Outer Read allocate, Outer Write-back transient + *- 0111: Normal memory, Outer Read/Write allocate, Outer Write-back transient + *- 1000: Normal memory, Outer Write-through non-transient + *- 1001: Normal memory, Outer Write allocate, Outer Write-through non-transient + *- 1010: Normal memory, Outer Read allocate, Outer Write-through non-transient + *- 1011: Normal memory, Outer Read/Write allocate, Outer Write-through non-transient + *- 1100: Normal memory, Outer Write-back non-transient + *- 1101: Normal memory, Outer Write allocate, Outer Write-back non-transient + *- 1110: Normal memory, Outer Read allocate, Outer Write-back non-transient + *- 1111: Normal memory, Outer Read/Write allocate, Outer Write-back non-transient + */ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_0 (0x1UL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos) /*!< 0x00000010UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_1 (0x2UL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos) /*!< 0x00000020UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_2 (0x4UL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos) /*!< 0x00000040UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_3 (0x8UL << DMA350_CH_SRCTRANSCFG_SRCMEMATTRHI_Pos) /*!< 0x00000080UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Pos (8U) +#define DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Msk (0x3UL << DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Pos) /*!< 0x00000300UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCSHAREATTR DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Msk +/*!< SRCSHAREATTR[ 1:0] bits Source Transfer Shareability Attribute. + *- 00: Non-shareable + *- 01: Reserved + *- 10: Outer shareable + *- 11: Inner shareable + */ +#define DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_0 (0x1UL << DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Pos) /*!< 0x00000100UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_1 (0x2UL << DMA350_CH_SRCTRANSCFG_SRCSHAREATTR_Pos) /*!< 0x00000200UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCNONSECATTR_Pos (10U) +#define DMA350_CH_SRCTRANSCFG_SRCNONSECATTR_Msk (0x1UL << DMA350_CH_SRCTRANSCFG_SRCNONSECATTR_Pos) /*!< 0x00000400UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCNONSECATTR DMA350_CH_SRCTRANSCFG_SRCNONSECATTR_Msk +/*!< SRCNONSECATTR bit Source Transfer Non-secure Attribute. + *- 0: Secure + *- 1: Non-secure + *When a channel is Non-secure this bit is tied to 1. + */ +#define DMA350_CH_SRCTRANSCFG_SRCPRIVATTR_Pos (11U) +#define DMA350_CH_SRCTRANSCFG_SRCPRIVATTR_Msk (0x1UL << DMA350_CH_SRCTRANSCFG_SRCPRIVATTR_Pos) /*!< 0x00000800UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCPRIVATTR DMA350_CH_SRCTRANSCFG_SRCPRIVATTR_Msk +/*!< SRCPRIVATTR bit Source Transfer Privilege Attribute. + *- 0: Unprivileged + *- 1: Privileged + *When a channel is unprivileged this bit is tied to 0. + */ +#define DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Pos (16U) +#define DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Msk (0xFUL << DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Pos) +#define DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Msk +/*!< SRCMAXBURSTLEN[ 3:0] bits Source Max Burst Length. Hint for the DMA on what is the maximum allowed + * burst size it can use for read transfers. The maximum number of beats sent by the DMA for a read burst + * is equal to SRCMAXBURSTLEN + 1. Default value is 16 beats, which allows the DMA to set all burst sizes. + * Note: Limited by the DATA_BUFF_SIZE so larger settings may not always result in larger bursts. + */ +#define DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_0 (0x1UL << DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Pos) /*!< 0x00010000UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_1 (0x2UL << DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Pos) /*!< 0x00020000UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_2 (0x4UL << DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Pos) /*!< 0x00040000UL*/ +#define DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_3 (0x8UL << DMA350_CH_SRCTRANSCFG_SRCMAXBURSTLEN_Pos) /*!< 0x00080000UL*/ +/************** Field definitions for CH_DESTRANSCFG register ***************/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos (0U) +#define DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Msk (0xFUL << DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos) /*!< 0x0000000FUL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRLO DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Msk +/*!< DESMEMATTRLO[ 3:0] bits Destination Transfer Memory Attribute field [3:0]. + *When DESMEMATTRHI is Device type (0000) then this field means: + *- 0000: Device-nGnRnE + *- 0100: Device-nGnRE + *- 1000: Device-nGRE + *- 1100: Device-GRE + *- Others: Invalid resulting in UNPREDICTABLE behavior + *When DESMEMATTRHI is Normal Memory type (other than 0000) then this field means: + *- 0000: Reserved + *- 0001: Normal memory, Inner Write allocate, Inner Write-through transient + *- 0010: Normal memory, Inner Read allocate, Inner Write-through transient + *- 0011: Normal memory, Inner Read/Write allocate, Inner Write-through transient + *- 0100: Normal memory, Inner non-cacheable + *- 0101: Normal memory, Inner Write allocate, Inner Write-back transient + *- 0110: Normal memory, Inner Read allocate, Inner Write-back transient + *- 0111: Normal memory, Inner Read/Write allocate, Inner Write-back transient + *- 1000: Normal memory, Inner Write-through non-transient + *- 1001: Normal memory, Inner Write allocate, Inner Write-through non-transient + *- 1010: Normal memory, Inner Read allocate, Inner Write-through non-transient + *- 1011: Normal memory, Inner Read/Write allocate, Inner Write-through non-transient + *- 1100: Normal memory, Inner Write-back non-transient + *- 1101: Normal memory, Inner Write allocate, Inner Write-back non-transient + *- 1110: Normal memory, Inner Read allocate, Inner Write-back non-transient + *- 1111: Normal memory, Inner Read/Write allocate, Inner Write-back non-transient + */ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRLO_0 (0x1UL << DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRLO_1 (0x2UL << DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos) /*!< 0x00000002UL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRLO_2 (0x4UL << DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos) /*!< 0x00000004UL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRLO_3 (0x8UL << DMA350_CH_DESTRANSCFG_DESMEMATTRLO_Pos) /*!< 0x00000008UL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos (4U) +#define DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Msk (0xFUL << DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos) /*!< 0x000000F0UL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRHI DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Msk +/*!< DESMEMATTRHI[ 3:0] bits Destination Transfer Memory Attribute field [7:4]. + *- 0000: Device memory + *- 0001: Normal memory, Outer Write allocate, Outer Write-through transient + *- 0010: Normal memory, Outer Read allocate, Outer Write-through transient + *- 0011: Normal memory, Outer Read/Write allocate, Outer Write-through transient + *- 0100: Normal memory, Outer non-cacheable + *- 0101: Normal memory, Outer Write allocate, Outer Write-back transient + *- 0110: Normal memory, Outer Read allocate, Outer Write-back transient + *- 0111: Normal memory, Outer Read/Write allocate, Outer Write-back transient + *- 1000: Normal memory, Outer Write-through non-transient + *- 1001: Normal memory, Outer Write allocate, Outer Write-through non-transient + *- 1010: Normal memory, Outer Read allocate, Outer Write-through non-transient + *- 1011: Normal memory, Outer Read/Write allocate, Outer Write-through non-transient + *- 1100: Normal memory, Outer Write-back non-transient + *- 1101: Normal memory, Outer Write allocate, Outer Write-back non-transient + *- 1110: Normal memory, Outer Read allocate, Outer Write-back non-transient + *- 1111: Normal memory, Outer Read/Write allocate, Outer Write-back non-transient + */ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRHI_0 (0x1UL << DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos) /*!< 0x00000010UL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRHI_1 (0x2UL << DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos) /*!< 0x00000020UL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRHI_2 (0x4UL << DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos) /*!< 0x00000040UL*/ +#define DMA350_CH_DESTRANSCFG_DESMEMATTRHI_3 (0x8UL << DMA350_CH_DESTRANSCFG_DESMEMATTRHI_Pos) /*!< 0x00000080UL*/ +#define DMA350_CH_DESTRANSCFG_DESSHAREATTR_Pos (8U) +#define DMA350_CH_DESTRANSCFG_DESSHAREATTR_Msk (0x3UL << DMA350_CH_DESTRANSCFG_DESSHAREATTR_Pos) /*!< 0x00000300UL*/ +#define DMA350_CH_DESTRANSCFG_DESSHAREATTR DMA350_CH_DESTRANSCFG_DESSHAREATTR_Msk +/*!< DESSHAREATTR[ 1:0] bits Destination Transfer Shareability Attribute. + *- 00: Non-shareable + *- 01: Reserved + *- 10: Outer shareable + *- 11: Inner shareable + */ +#define DMA350_CH_DESTRANSCFG_DESSHAREATTR_0 (0x1UL << DMA350_CH_DESTRANSCFG_DESSHAREATTR_Pos) /*!< 0x00000100UL*/ +#define DMA350_CH_DESTRANSCFG_DESSHAREATTR_1 (0x2UL << DMA350_CH_DESTRANSCFG_DESSHAREATTR_Pos) /*!< 0x00000200UL*/ +#define DMA350_CH_DESTRANSCFG_DESNONSECATTR_Pos (10U) +#define DMA350_CH_DESTRANSCFG_DESNONSECATTR_Msk (0x1UL << DMA350_CH_DESTRANSCFG_DESNONSECATTR_Pos) /*!< 0x00000400UL*/ +#define DMA350_CH_DESTRANSCFG_DESNONSECATTR DMA350_CH_DESTRANSCFG_DESNONSECATTR_Msk +/*!< DESNONSECATTR bit Destination Transfer Non-secure Attribute. + *- 0: Secure + *- 1: Non-secure + *When a channel is Non-secure this bit is tied to 1. + */ +#define DMA350_CH_DESTRANSCFG_DESPRIVATTR_Pos (11U) +#define DMA350_CH_DESTRANSCFG_DESPRIVATTR_Msk (0x1UL << DMA350_CH_DESTRANSCFG_DESPRIVATTR_Pos) /*!< 0x00000800UL*/ +#define DMA350_CH_DESTRANSCFG_DESPRIVATTR DMA350_CH_DESTRANSCFG_DESPRIVATTR_Msk +/*!< DESPRIVATTR bit Destination Transfer Privilege Attribute. + *- 0: Unprivileged + *- 1: Privileged + *When a channel is unprivileged this bit is tied to 0. + */ +#define DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Pos (16U) +#define DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Msk (0xFUL << DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Pos) /*!< 0x000F0000UL*/ +#define DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Msk + +#define DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_0 (0x1UL << DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Pos) /*!< 0x00010000UL*/ +#define DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_1 (0x2UL << DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Pos) /*!< 0x00020000UL*/ +#define DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_2 (0x4UL << DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Pos) /*!< 0x00040000UL*/ +#define DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_3 (0x8UL << DMA350_CH_DESTRANSCFG_DESMAXBURSTLEN_Pos) /*!< 0x00080000UL*/ +/**************** Field definitions for CH_XADDRINC register ****************/ +#define DMA350_CH_XADDRINC_SRCXADDRINC_Pos (0U) +#define DMA350_CH_XADDRINC_SRCXADDRINC_Msk (0xFFFFUL << DMA350_CH_XADDRINC_SRCXADDRINC_Pos) /*!< 0x0000FFFFUL*/ +#define DMA350_CH_XADDRINC_SRCXADDRINC DMA350_CH_XADDRINC_SRCXADDRINC_Msk +/*!< SRCXADDRINC[15:0] bits Source X dimension Address Increment. + * This value is used as the increment between each TRANSIZE transfer. + * When a single bit is used then only 0 and 1 can be set. For wider increment registers, + * two's complement used with a range between -32768 to 32767 when the counter is 16-bits wide. + * The width of the register is indicated by the INC_WIDTH parameter. SRCADDR_next = SRCADDR + 2^TRANSIZE * SRCXADDRINC + */ +#define DMA350_CH_XADDRINC_DESXADDRINC_Pos (16U) +#define DMA350_CH_XADDRINC_DESXADDRINC_Msk (0xFFFFUL << DMA350_CH_XADDRINC_DESXADDRINC_Pos) /*!< 0xFFFF0000UL*/ +#define DMA350_CH_XADDRINC_DESXADDRINC DMA350_CH_XADDRINC_DESXADDRINC_Msk +/*!< DESXADDRINC[15:0] bits Destination X dimension Address Increment. + * This value is used as the increment between each TRANSIZE transfer. + * When a single bit is used then only 0 and 1 can be set. For wider increment registers, + * two's complement used with a range between -32768 to 32767 when the counter is 16-bits wide. + * The width of the register is indicated by the INC_WIDTH parameter. + * DESADDR_next = DESADDR + 2^TRANSIZE * DESXADDRINC + */ +/************** Field definitions for CH_YADDRSTRIDE register ***************/ +#define DMA350_CH_YADDRSTRIDE_SRCYADDRSTRIDE_Pos (0U) +#define DMA350_CH_YADDRSTRIDE_SRCYADDRSTRIDE_Msk (0xFFFFUL << DMA350_CH_YADDRSTRIDE_SRCYADDRSTRIDE_Pos) +#define DMA350_CH_YADDRSTRIDE_SRCYADDRSTRIDE DMA350_CH_YADDRSTRIDE_SRCYADDRSTRIDE_Msk +/*!< SRCYADDRSTRIDE[15:0] bits Source Address Stride between lines. Calculated in TRANSIZE aligned steps. + * This value is used to increment the SRCADDR after completing the transfer of a source line. + * SRCADDR_next_line_base = SRCADDR_line_base + 2^TRANSIZE * SRCYADDRSTRIDE. + * Two's complement used with a range between -32768 to 32767. + * When set to 0 the SRCADDR is not incremented after completing one line. Not present when HAS_2D is 0. + */ +#define DMA350_CH_YADDRSTRIDE_DESYADDRSTRIDE_Pos (16U) +#define DMA350_CH_YADDRSTRIDE_DESYADDRSTRIDE_Msk (0xFFFFUL << DMA350_CH_YADDRSTRIDE_DESYADDRSTRIDE_Pos) +#define DMA350_CH_YADDRSTRIDE_DESYADDRSTRIDE DMA350_CH_YADDRSTRIDE_DESYADDRSTRIDE_Msk +/*!< DESYADDRSTRIDE[15:0] bits Destination Address Stride between lines. + * Calculated in TRANSIZE aligned steps. This value is used to increment the DESADDR after completing the transfer + * of a destination line. DESADDR_next_line_base = DESADDR_line_base + 2^TRANSIZE * DESYADDRSTRIDE. + * Two's complement used with a range between -32768 to 32767. When set to 0 the DESADDR is not incremented + * after completing one line. Not present when HAS_2D is 0. + */ +/**************** Field definitions for CH_FILLVAL register *****************/ +#define DMA350_CH_FILLVAL_FILLVAL_Pos (0U) +#define DMA350_CH_FILLVAL_FILLVAL_Msk (0xFFFFFFFFUL << DMA350_CH_FILLVAL_FILLVAL_Pos) /*!< 0xFFFFFFFFUL*/ +#define DMA350_CH_FILLVAL_FILLVAL DMA350_CH_FILLVAL_FILLVAL_Msk +/*!< FILLVAL[31:0] bits Fill pattern value. When XTYPE or YTYPE is set to fill mode, + * then this register value is used on the write data bus when the command starts to fill the memory area. + * The TRANSIZE defines the width of the FILLVAL used for the command. For byte transfers the FILLVAL[7:0] is used, + * other bits are ignored. For halfword transfers the FILLVAL[15:0] is used, other bits are ignored. + * For 64-bit and wider transfers the FILLVAL[31:0] pattern is repeated on the full width of the data bus. + * Not present when HAS_WRAP is 0. + */ +/***************** Field definitions for CH_YSIZE register ******************/ +#define DMA350_CH_YSIZE_SRCYSIZE_Pos (0U) +#define DMA350_CH_YSIZE_SRCYSIZE_Msk (0xFFFFUL << DMA350_CH_YSIZE_SRCYSIZE_Pos) /*!< 0x0000FFFFUL*/ +#define DMA350_CH_YSIZE_SRCYSIZE DMA350_CH_YSIZE_SRCYSIZE_Msk +/*!< SRCYSIZE[15:0] bits Source Y dimension or number of lines. Not present when HAS_2D is 0. + */ +#define DMA350_CH_YSIZE_DESYSIZE_Pos (16U) +#define DMA350_CH_YSIZE_DESYSIZE_Msk (0xFFFFUL << DMA350_CH_YSIZE_DESYSIZE_Pos) /*!< 0xFFFF0000UL*/ +#define DMA350_CH_YSIZE_DESYSIZE DMA350_CH_YSIZE_DESYSIZE_Msk +/*!< DESYSIZE[15:0] bits Destination Y dimension or number of lines. Not present when HAS_2D is 0. + * HAS_WRAP or HAS_STREAM configuration needs to be set to allow writes to this register, + * otherwise it is read-only. + */ +/**************** Field definitions for CH_TMPLTCFG register ****************/ +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Pos (8U) +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Msk (0x1FUL << DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Pos) /*!< 0x00001F00UL*/ +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Msk +/*!< SRCTMPLTSIZE[ 4:0] bits Source Template Size in number of transfers plus one. + *- 0: Source template is disabled. + *- 1 to 31: Bits SRCTMPLT[SRCTMPLTSIZE:0] is used as the source template. Not present when HAS_TMPLT is 0. + */ +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_0 (0x1UL << DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Pos) /*!< 0x00000100UL*/ +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_1 (0x2UL << DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Pos) /*!< 0x00000200UL*/ +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_2 (0x4UL << DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Pos) /*!< 0x00000400UL*/ +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_3 (0x8UL << DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Pos) /*!< 0x00000800UL*/ +#define DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_4 (0x10UL << DMA350_CH_TMPLTCFG_SRCTMPLTSIZE_Pos) /*!< 0x00001000UL*/ +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Pos (16U) +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Msk (0x1FUL << DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Pos) /*!< 0x001F0000UL*/ +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Msk +/*!< DESTMPLTSIZE[ 4:0] bits Destination Template Size in number of transfers plus one. + *- 0: Destination template is disabled. + *- 1 to 31: DESTMPLT[DESTMPLTSIZE:0] is used as the destination template. Not present when HAS_TMPLT is 0. + */ +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE_0 (0x1UL << DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Pos) /*!< 0x00010000UL*/ +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE_1 (0x2UL << DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Pos) /*!< 0x00020000UL*/ +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE_2 (0x4UL << DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Pos) /*!< 0x00040000UL*/ +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE_3 (0x8UL << DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Pos) /*!< 0x00080000UL*/ +#define DMA350_CH_TMPLTCFG_DESTMPLTSIZE_4 (0x10UL << DMA350_CH_TMPLTCFG_DESTMPLTSIZE_Pos) /*!< 0x00100000UL*/ +/**************** Field definitions for CH_SRCTMPLT register ****************/ +#define DMA350_CH_SRCTMPLT_SRCTMPLTLSB_Pos (0U) +#define DMA350_CH_SRCTMPLT_SRCTMPLTLSB_Msk (0x1UL << DMA350_CH_SRCTMPLT_SRCTMPLTLSB_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_SRCTMPLT_SRCTMPLTLSB DMA350_CH_SRCTMPLT_SRCTMPLTLSB_Msk +/*!< SRCTMPLTLSB bit Source Packing Template Least Significant Bit. This bit of the template is + * read only and always set to 1 as template patterns can only start from the base address of the transfer. + * Not present when HAS_TMPLT is 0. + */ +#define DMA350_CH_SRCTMPLT_SRCTMPLT_Pos (1U) +#define DMA350_CH_SRCTMPLT_SRCTMPLT_Msk (0x7FFFFFFFUL << DMA350_CH_SRCTMPLT_SRCTMPLT_Pos) /*!< 0xFFFFFFFEUL*/ +#define DMA350_CH_SRCTMPLT_SRCTMPLT DMA350_CH_SRCTMPLT_SRCTMPLT_Msk +/*!< SRCTMPLT[30:0] bits Source Packing Template. Bit[0] is read only and always set to 1 as template + * patterns can only start from the base address of the transfer. Not present when HAS_TMPLT is 0. + */ +/**************** Field definitions for CH_DESTMPLT register ****************/ +#define DMA350_CH_DESTMPLT_DESTMPLTLSB_Pos (0U) +#define DMA350_CH_DESTMPLT_DESTMPLTLSB_Msk (0x1UL << DMA350_CH_DESTMPLT_DESTMPLTLSB_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_DESTMPLT_DESTMPLTLSB DMA350_CH_DESTMPLT_DESTMPLTLSB_Msk +/*!< DESTMPLTLSB bit Destination Packing Template Least Significant Bit. + * This bit of the template is read only and always set to 1 as template patterns can + * only start from the base address of the transfer. Not present when HAS_TMPLT is 0. + */ +#define DMA350_CH_DESTMPLT_DESTMPLT_Pos (1U) +#define DMA350_CH_DESTMPLT_DESTMPLT_Msk (0x7FFFFFFFUL << DMA350_CH_DESTMPLT_DESTMPLT_Pos) /*!< 0xFFFFFFFEUL*/ +#define DMA350_CH_DESTMPLT_DESTMPLT DMA350_CH_DESTMPLT_DESTMPLT_Msk +/*!< DESTMPLT[30:0] bits Destination Packing Template. + * Bit[0] is read only and always set to 1 as template patterns can only start from the + * base address of the transfer. Not present when HAS_TMPLT is 0. + */ +/************** Field definitions for CH_SRCTRIGINCFG register **************/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos (0U) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Msk (0xFFUL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x000000FFUL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Msk +/*!< SRCTRIGINSEL[ 7:0] bits Source Trigger Input Select + */ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_0 (0x1UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_1 (0x2UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x00000002UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_2 (0x4UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x00000004UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_3 (0x8UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x00000008UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_4 (0x10UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x00000010UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_5 (0x20UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x00000020UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_6 (0x40UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x00000040UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_7 (0x80UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINSEL_Pos) /*!< 0x00000080UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Pos (8U) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Msk (0x3UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Pos) /*!< 0x00000300UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Msk +/*!< SRCTRIGINTYPE[ 1:0] bits Source Trigger Input Type: + *- 00: Software only Trigger Request. SRCTRIGINSEL is ignored. + *- 01: Reserved + *- 10: HW Trigger Request. Only allowed when HAS_TRIGIN is enabled. SRCTRIGINSEL selects between external + * trigger inputs if HAS_TRIGSEL is enabled. + *- 11: Internal Trigger Request. Only allowed when HAS_TRIGSEL is enabled and the DMAC has multiple channels, + * otherwise treated as HW Trigger Request. SRCTRIGINSEL selects between DMA channels. + * Note: SW triggers are also available when HW or Internal types are selected, but is not recommended + * and caution must be taken when the these modes are combined. + */ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_0 (0x1UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Pos) /*!< 0x00000100UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_1 (0x2UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINTYPE_Pos) /*!< 0x00000200UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Pos (10U) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Msk (0x3UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Pos) /*!< 0x00000C00UL*/ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Msk +/*!< SRCTRIGINMODE[ 1:0] bits Source Trigger Input Mode: + *- 00: Command + *- 01: Reserved + *- 10: DMA driven Flow control. Only allowed when HAS_TRIGIN is enabled. + *- 11: Peripheral driven Flow control. Only allowed when HAS_TRIGIN is enabled. + *Note: This field is ignored for Internal triggers as they only support Command triggers. + */ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_0 (0x1UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_1 (0x2UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINMODE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos (16U) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Msk (0xFFUL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Msk +/*!< SRCTRIGINBLKSIZE[ 7:0] bits Source Trigger Input Default Transfer Size. Defined transfer size per trigger + 1. + */ +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_0 (0x1UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_1 (0x2UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_2 (0x4UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_3 (0x8UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_4 (0x10UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_5 (0x20UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_6 (0x40UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +#define DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_7 (0x80UL << DMA350_CH_SRCTRIGINCFG_SRCTRIGINBLKSIZE_Pos) +/************** Field definitions for CH_DESTRIGINCFG register **************/ +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos (0U) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Msk (0xFFUL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Msk +/*!< DESTRIGINSEL[ 7:0] bits Destination Trigger Input Select + */ +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_0 (0x1UL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_1 (0x2UL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_2 (0x4UL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_3 (0x8UL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_4 (0x10UL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_5 (0x20UL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_6 (0x40UL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_7 (0x80UL << DMA350_CH_DESTRIGINCFG_DESTRIGINSEL_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Pos (8U) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Msk (0x3UL << DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Msk +/*!< DESTRIGINTYPE[ 1:0] bits Destination Trigger Input Type: + * - 00: Software only Trigger Request. DESTRIGINSEL is ignored. + * - 01: Reserved + * - 10: HW Trigger Request. Only allowed when HAS_TRIGIN is enabled. DESTRIGINSEL selects between external trigger + * inputs if HAS_TRIGSEL is enabled. + * - 11: Internal Trigger Request. Only allowed when HAS_TRIGSEL is enabled and the DMAC has multiple channels, + * otherwise treated as HW Trigger Request. DESTRIGINSEL selects between DMA channels. + *Note: SW triggers are also available when HW or Internal types are selected, but is not recommended and caution + *must be taken when the these modes are combined. + */ +#define DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_0 (0x1UL << DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Pos) /*!< 0x00000100UL*/ +#define DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_1 (0x2UL << DMA350_CH_DESTRIGINCFG_DESTRIGINTYPE_Pos) /*!< 0x00000200UL*/ +#define DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Pos (10U) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Msk (0x3UL << DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINMODE DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Msk +/*!< DESTRIGINMODE[ 1:0] bits Destination Trigger Input Mode: + * - 00: Command + * - 01: Reserved + * - 10: DMA driven Flow control. Only allowed when HAS_TRIGIN is enabled. + * - 11: Peripheral driven Flow control. Only allowed when HAS_TRIGIN is enabled. + * Note: This field is ignored for Internal triggers as they only support Command triggers. + */ +#define DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_0 (0x1UL << DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_1 (0x2UL << DMA350_CH_DESTRIGINCFG_DESTRIGINMODE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos (16U) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Msk (0xFFUL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Msk +/*!< DESTRIGINBLKSIZE[ 7:0] bits Destination Trigger Input Default Transfer Size. + * Defined transfer size per trigger + 1. + */ +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_0 (0x1UL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_1 (0x2UL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_2 (0x4UL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_3 (0x8UL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_4 (0x10UL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_5 (0x20UL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_6 (0x40UL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +#define DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_7 (0x80UL << DMA350_CH_DESTRIGINCFG_DESTRIGINBLKSIZE_Pos) +/*************** Field definitions for CH_TRIGOUTCFG register ***************/ +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Pos (0U) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Msk (0x3FUL << DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Pos) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Msk +/*!< TRIGOUTSEL[ 5:0] bits Trigger Output Select + */ +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_0 (0x1UL << DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Pos) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_1 (0x2UL << DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Pos) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_2 (0x4UL << DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Pos) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_3 (0x8UL << DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Pos) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_4 (0x10UL << DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Pos) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_5 (0x20UL << DMA350_CH_TRIGOUTCFG_TRIGOUTSEL_Pos) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE_Pos (8U) +#define DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE_Msk (0x3UL << DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE_Pos) /*!< 0x00000300UL*/ +#define DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE_Msk +/*!< TRIGOUTTYPE[ 1:0] bits Trigger Output Type + *- 00: Software only Trigger Acknowledgment. + *- 01: Reserved + *- 10: HW Trigger Acknowledgment. Only allowed when HAS_TRIGOUT is enabled. + *- 11: Internal Trigger Acknowledgment. Only allowed when HAS_TRIGSEL is enabled and the DMAC has multiple channels, + *otherwise treated as HW Trigger Acknowledgment. + */ +#define DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE_0 (0x1UL << DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE_Pos) /*!< 0x00000100UL*/ +#define DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE_1 (0x2UL << DMA350_CH_TRIGOUTCFG_TRIGOUTTYPE_Pos) /*!< 0x00000200UL*/ +/***************** Field definitions for CH_GPOEN0 register *****************/ +#define DMA350_CH_GPOEN0_GPOEN0_Pos (0U) +#define DMA350_CH_GPOEN0_GPOEN0_Msk (0xFFFFFFFFUL << DMA350_CH_GPOEN0_GPOEN0_Pos) /*!< 0xFFFFFFFFUL*/ +#define DMA350_CH_GPOEN0_GPOEN0 DMA350_CH_GPOEN0_GPOEN0_Msk +/*!< GPOEN0[31:0] bits Channel General Purpose Output (GPO) bit 0 to 31 enable mask. If bit n is '1', + * then GPO[n] is selected for driving by GPOVAL0[n]. If bit 'n' is '0', then GPO[n] keeps its previous value. + * Only [GPO_WIDTH-1:0] are implemented. All unimplemented bits are RAZWI. + */ +/**************** Field definitions for CH_GPOVAL0 register *****************/ +#define DMA350_CH_GPOVAL0_GPOVAL0_Pos (0U) +#define DMA350_CH_GPOVAL0_GPOVAL0_Msk (0xFFFFFFFFUL << DMA350_CH_GPOVAL0_GPOVAL0_Pos) /*!< 0xFFFFFFFFUL*/ +#define DMA350_CH_GPOVAL0_GPOVAL0 DMA350_CH_GPOVAL0_GPOVAL0_Msk +/*!< GPOVAL0[31:0] bits General Purpose Output Value GPO[31:0]. Write to set output value. + * The actual value on the GPO port will become active when the command is enabled. + * Read returns the register value which might be different from the actual GPO port status. + * Only [GPO_WIDTH-1:0] are implemented. All unimplemented bits are RAZWI. + */ +/************** Field definitions for CH_STREAMINTCFG register **************/ +#define DMA350_CH_STREAMINTCFG_STREAMTYPE_Pos (9U) +#define DMA350_CH_STREAMINTCFG_STREAMTYPE_Msk (0x3UL << DMA350_CH_STREAMINTCFG_STREAMTYPE_Pos) /*!< 0x00000600UL*/ +#define DMA350_CH_STREAMINTCFG_STREAMTYPE DMA350_CH_STREAMINTCFG_STREAMTYPE_Msk +/*!< STREAMTYPE[ 1:0] bits Stream Interface operation Type + * - 00: Stream in and out used. + * - 01: Stream out only + * - 10: Stream in only + * - 11: Reserved + */ +#define DMA350_CH_STREAMINTCFG_STREAMTYPE_0 (0x1UL << DMA350_CH_STREAMINTCFG_STREAMTYPE_Pos) /*!< 0x00000200UL*/ +#define DMA350_CH_STREAMINTCFG_STREAMTYPE_1 (0x2UL << DMA350_CH_STREAMINTCFG_STREAMTYPE_Pos) /*!< 0x00000400UL*/ +/**************** Field definitions for CH_LINKATTR register ****************/ +#define DMA350_CH_LINKATTR_LINKMEMATTRLO_Pos (0U) +#define DMA350_CH_LINKATTR_LINKMEMATTRLO_Msk (0xFUL << DMA350_CH_LINKATTR_LINKMEMATTRLO_Pos) /*!< 0x0000000FUL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRLO DMA350_CH_LINKATTR_LINKMEMATTRLO_Msk +/*!< LINKMEMATTRLO[ 3:0] bits Link Address Read Transfer Memory Attribute field [3:0]. + * When LINKMEMATTRHI is Device type (0000) then this field means: + *- 0000: Device-nGnRnE + *- 0100: Device-nGnRE + *- 1000: Device-nGRE + *- 1100: Device-GRE + *- Others: Invalid resulting in UNPREDICTABLE behavior + *When LINKMEMATTRHI is Normal memory type (other than 0000) then this field means: + *- 0000: Reserved + *- 0001: Normal memory, Inner Write allocate, Inner Write-through transient + *- 0010: Normal memory, Inner Read allocate, Inner Write-through transient + *- 0011: Normal memory, Inner Read/Write allocate, Inner Write-through transient + *- 0100: Normal memory, Inner non-cacheable + *- 0101: Normal memory, Inner Write allocate, Inner Write-back transient + *- 0110: Normal memory, Inner Read allocate, Inner Write-back transient + *- 0111: Normal memory, Inner Read/Write allocate, Inner Write-back transient + *- 1000: Normal memory, Inner Write-through non-transient + *- 1001: Normal memory, Inner Write allocate, Inner Write-through non-transient + *- 1010: Normal memory, Inner Read allocate, Inner Write-through non-transient + *- 1011: Normal memory, Inner Read/Write allocate, Inner Write-through non-transient + *- 1100: Normal memory, Inner Write-back non-transient + *- 1101: Normal memory, Inner Write allocate, Inner Write-back non-transient + *- 1110: Normal memory, Inner Read allocate, Inner Write-back non-transient + *- 1111: Normal memory, Inner Read/Write allocate, Inner Write-back non-transient + */ +#define DMA350_CH_LINKATTR_LINKMEMATTRLO_0 (0x1UL << DMA350_CH_LINKATTR_LINKMEMATTRLO_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRLO_1 (0x2UL << DMA350_CH_LINKATTR_LINKMEMATTRLO_Pos) /*!< 0x00000002UL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRLO_2 (0x4UL << DMA350_CH_LINKATTR_LINKMEMATTRLO_Pos) /*!< 0x00000004UL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRLO_3 (0x8UL << DMA350_CH_LINKATTR_LINKMEMATTRLO_Pos) /*!< 0x00000008UL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRHI_Pos (4U) +#define DMA350_CH_LINKATTR_LINKMEMATTRHI_Msk (0xFUL << DMA350_CH_LINKATTR_LINKMEMATTRHI_Pos) /*!< 0x000000F0UL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRHI DMA350_CH_LINKATTR_LINKMEMATTRHI_Msk +/*!< LINKMEMATTRHI[ 3:0] bits Link Address Read Transfer Memory Attribute field [7:4]. + *- 0000: Device memory + *- 0001: Normal memory, Outer Write allocate, Outer Write-through transient + *- 0010: Normal memory, Outer Read allocate, Outer Write-through transient + *- 0011: Normal memory, Outer Read/Write allocate, Outer Write-through transient + *- 0100: Normal memory, Outer non-cacheable + *- 0101: Normal memory, Outer Write allocate, Outer Write-back transient + *- 0110: Normal memory, Outer Read allocate, Outer Write-back transient + *- 0111: Normal memory, Outer Read/Write allocate, Outer Write-back transient + *- 1000: Normal memory, Outer Write-through non-transient + *- 1001: Normal memory, Outer Write allocate, Outer Write-through non-transient + *- 1010: Normal memory, Outer Read allocate, Outer Write-through non-transient + *- 1011: Normal memory, Outer Read/Write allocate, Outer Write-through non-transient + *- 1100: Normal memory, Outer Write-back non-transient + *- 1101: Normal memory, Outer Write allocate, Outer Write-back non-transient + *- 1110: Normal memory, Outer Read allocate, Outer Write-back non-transient + *- 1111: Normal memory, Outer Read/Write allocate, Outer Write-back non-transient + */ +#define DMA350_CH_LINKATTR_LINKMEMATTRHI_0 (0x1UL << DMA350_CH_LINKATTR_LINKMEMATTRHI_Pos) /*!< 0x00000010UL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRHI_1 (0x2UL << DMA350_CH_LINKATTR_LINKMEMATTRHI_Pos) /*!< 0x00000020UL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRHI_2 (0x4UL << DMA350_CH_LINKATTR_LINKMEMATTRHI_Pos) /*!< 0x00000040UL*/ +#define DMA350_CH_LINKATTR_LINKMEMATTRHI_3 (0x8UL << DMA350_CH_LINKATTR_LINKMEMATTRHI_Pos) /*!< 0x00000080UL*/ +#define DMA350_CH_LINKATTR_LINKSHAREATTR_Pos (8U) +#define DMA350_CH_LINKATTR_LINKSHAREATTR_Msk (0x3UL << DMA350_CH_LINKATTR_LINKSHAREATTR_Pos) /*!< 0x00000300UL*/ +#define DMA350_CH_LINKATTR_LINKSHAREATTR DMA350_CH_LINKATTR_LINKSHAREATTR_Msk +/*!< LINKSHAREATTR[ 1:0] bits Link Address Transfer Shareability Attribute. + * - 00: Non-shareable + * - 01: Reserved + * - 10: Outer shareable + * - 11: Inner shareable + */ +#define DMA350_CH_LINKATTR_LINKSHAREATTR_0 (0x1UL << DMA350_CH_LINKATTR_LINKSHAREATTR_Pos) /*!< 0x00000100UL*/ +#define DMA350_CH_LINKATTR_LINKSHAREATTR_1 (0x2UL << DMA350_CH_LINKATTR_LINKSHAREATTR_Pos) /*!< 0x00000200UL*/ +/**************** Field definitions for CH_AUTOCFG register *****************/ +#define DMA350_CH_AUTOCFG_CMDRESTARTCNT_Pos (0U) +#define DMA350_CH_AUTOCFG_CMDRESTARTCNT_Msk (0xFFFFUL << DMA350_CH_AUTOCFG_CMDRESTARTCNT_Pos) /*!< 0x0000FFFFUL*/ +#define DMA350_CH_AUTOCFG_CMDRESTARTCNT DMA350_CH_AUTOCFG_CMDRESTARTCNT_Msk +/*!< CMDRESTARTCNT[15:0] bits Automatic Command Restart Counter. Defines the number of times automatic + * restarting will occur at end of DMA command. Auto restarting will occur after the command is completed, + * including output triggering if enabled and autoreloading the registers, but it will only perfrom a link + * to the next command when CMDRESTARTCNT == 0. When CMDRESTARTCNT and CMDRESTARTINF + * are both set to '0', autorestart is disabled. + */ +#define DMA350_CH_AUTOCFG_CMDRESTARTINFEN_Pos (16U) +#define DMA350_CH_AUTOCFG_CMDRESTARTINFEN_Msk (0x1UL << DMA350_CH_AUTOCFG_CMDRESTARTINFEN_Pos) /*!< 0x00010000UL*/ +#define DMA350_CH_AUTOCFG_CMDRESTARTINFEN DMA350_CH_AUTOCFG_CMDRESTARTINFEN_Msk +/*!< CMDRESTARTINFEN bit Enable Infinite Automatic Command Restart. + * When set, CMDRESTARTCNT is ignored and the command is always restarted after it is completed, + * including output triggering if enabled and autoreloading the registers but it will not perform + * a link to the next command. + * This means that the infinite loop of automatic restarts can only be broken by DISABLECMD or STOPCMD. + * When CMDRESTARTINFEN is set to '0', then the autorestarting of a command depends on CMDRESTARTCNT and when + * that counter is set to 0 the autorestarting is finished. + * In this case the next linked command is read or the command is complete. + */ +/**************** Field definitions for CH_LINKADDR register ****************/ +#define DMA350_CH_LINKADDR_LINKADDREN_Pos (0U) +#define DMA350_CH_LINKADDR_LINKADDREN_Msk (0x1UL << DMA350_CH_LINKADDR_LINKADDREN_Pos) /*!< 0x00000001UL*/ +#define DMA350_CH_LINKADDR_LINKADDREN DMA350_CH_LINKADDR_LINKADDREN_Msk +/*!< LINKADDREN bit Enable Link Address. When set to '1', the DMAC fetches the next command defined by LINKADDR. + * When set to '0' the DMAC will return to idle at the end of the current command. + * NOTE: the linked command fetched by the DMAC needs to clear this field to mark the end of the command chain. + * Otherwise it may result in an infinite loop of the same command. + */ +#define DMA350_CH_LINKADDR_LINKADDR_Pos (2U) +#define DMA350_CH_LINKADDR_LINKADDR_Msk (0x3FFFFFFFUL << DMA350_CH_LINKADDR_LINKADDR_Pos) /*!< 0xFFFFFFFCUL*/ +#define DMA350_CH_LINKADDR_LINKADDR DMA350_CH_LINKADDR_LINKADDR_Msk +/*!< LINKADDR[29:0] bits Link Address Pointer [31:2]. The DMAC fetches the next command from this address + * if LINKADDREN is set. + * NOTE: Commands are fetched with the security and privilege attribute of the + * channel and cannot be adjusted for the command link reads. + */ +/*************** Field definitions for CH_LINKADDRHI register ***************/ +#define DMA350_CH_LINKADDRHI_LINKADDRHI_Pos (0U) +#define DMA350_CH_LINKADDRHI_LINKADDRHI_Msk (0xFFFFFFFFUL << DMA350_CH_LINKADDRHI_LINKADDRHI_Pos) +#define DMA350_CH_LINKADDRHI_LINKADDRHI DMA350_CH_LINKADDRHI_LINKADDRHI_Msk +/*!< LINKADDRHI[31:0] bits Link Address Pointer [63:32]. Allows 64-bit addressing but the system + * might need less address bits. Limited by ADDR_WIDTH and the not implemented bits remain reserved. + */ + +/*************** Field definitions for Non-Secure Control register ***************/ +#define INTREN_ANYCHINTR_ENABLE (1U) + + +#endif /* __DMA350_REGDEF_H */ diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c index 3720b90cad10..aa5ad5fb7b3f 100644 --- a/drivers/gpio/gpio-cadence.c +++ b/drivers/gpio/gpio-cadence.c @@ -15,6 +15,7 @@ #include #include #include +#include #define CDNS_GPIO_BYPASS_MODE 0x00 #define CDNS_GPIO_DIRECTION_MODE 0x04 @@ -284,10 +285,18 @@ static const struct of_device_id cdns_of_ids[] = { }; MODULE_DEVICE_TABLE(of, cdns_of_ids); +static const struct acpi_device_id cdns_acpi_ids[] = { + { "CIXH1002", 0 }, + { "CIXH1003", 0 }, + { "", 0 }, +}; +MODULE_DEVICE_TABLE(acpi, cdns_acpi_ids); + static struct platform_driver cdns_gpio_driver = { .driver = { .name = "cdns-gpio", .of_match_table = cdns_of_ids, + .acpi_match_table = ACPI_PTR(cdns_acpi_ids), }, .probe = cdns_gpio_probe, .remove = cdns_gpio_remove, diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 13ff4f3120d0..2a167f23afa7 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -407,6 +407,8 @@ config DRM_HYPERV If M is selected the module will be called hyperv_drm. +source "drivers/gpu/drm/cix/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACY diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 896284c7327d..e21c52c50f07 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -200,4 +200,5 @@ obj-y += solomon/ obj-$(CONFIG_DRM_SPRD) += sprd/ obj-y += loongson/ obj-$(CONFIG_DRM_PHYTIUM) += phytium/ +obj-$(CONFIG_DRM_CIX) += cix/ obj-$(CONFIG_DRM_ARISE) += arise/ diff --git a/drivers/gpu/drm/cix/Kconfig b/drivers/gpu/drm/cix/Kconfig new file mode 100644 index 000000000000..737513524aab --- /dev/null +++ b/drivers/gpu/drm/cix/Kconfig @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_CIX + tristate "DRM Support for CiX Socs" + select DRM_KMS_HELPER + select VIDEOMODE_HELPERS + select DRM_GEM_DMA_HELPER + depends on DRM + help + enable CiX DRM display support + +config DRM_LINLONDP + tristate "ARMCHINA LINLON display driver" + depends on DRM && OF + depends on COMMON_CLK + depends on DRM_CIX + select DRM_KMS_HELPER + select DRM_GEM_DMA_HELPER + select VIDEOMODE_HELPERS + help + Choose this option if you want to compile the ARMCHINA Linlon display + Processor driver. It supports the DP variants of the hardware. + If compiled as a module it will be called linlondp. + +config DRM_CIX_VIRTUAL + tristate "DRM Support for CiX Virtual Encoder" + depends on DRM_CIX + default y + help + This is a virtual encoder and connector support which is + mainly used on EMU and FPGA. Disabled in default. + +config DRM_LINLONDP_CLOCK_FIXED + bool "linlondp clocks use fixed frequency" + depends on DRM_CIX + help + Choose this if linlondp clocks use fixed frequency + +config DRM_TRILIN_DP_CIX + tristate "DRM Support for Trilinear DisplayPort on CiX platforms" + depends on DRM_CIX + help + Choose this if you want to use DP display on CiX Socs + +config DRM_CIX_EDP_PANEL + tristate "DRM Support for edp panel on CiX platforms" + help + Choose this if you want to use edp panel on CiX Socs + +source "drivers/gpu/drm/cix/dptx/Kconfig" diff --git a/drivers/gpu/drm/cix/Makefile b/drivers/gpu/drm/cix/Makefile new file mode 100644 index 000000000000..10ff04825a6a --- /dev/null +++ b/drivers/gpu/drm/cix/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_DRM_CIX_VIRTUAL) += cix_virtual.o +obj-$(CONFIG_DRM_LINLONDP) += linlon-dp/ +obj-$(CONFIG_DRM_TRILIN_DPSUB) += dptx/ diff --git a/drivers/gpu/drm/cix/cix_display.c b/drivers/gpu/drm/cix/cix_display.c new file mode 100644 index 000000000000..9b19098bf03a --- /dev/null +++ b/drivers/gpu/drm/cix/cix_display.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 Cix Technology Group Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include + +#define DPU0_RESET_MASK BIT(16) +#define DPU1_RESET_MASK BIT(17) +#define DPU2_RESET_MASK BIT(18) +#define DPU3_RESET_MASK BIT(19) +#define DPU4_RESET_MASK BIT(20) + +#define DP0_RESET_MASK BIT(21) +#define DP1_RESET_MASK BIT(22) +#define DP2_RESET_MASK BIT(23) +#define DP3_RESET_MASK BIT(24) +#define DP4_RESET_MASK BIT(25) + +#define MMHUB_RESET_MASK BIT(4) + +#define DISPLAY0_RESET_MASK (DPU0_RESET_MASK | DP0_RESET_MASK) +#define DISPLAY1_RESET_MASK (DPU1_RESET_MASK | DP1_RESET_MASK) +#define DISPLAY2_RESET_MASK (DPU2_RESET_MASK | DP2_RESET_MASK) +#define DISPLAY3_RESET_MASK (DPU3_RESET_MASK | DP3_RESET_MASK) +#define DISPLAY4_RESET_MASK (DPU4_RESET_MASK | DP4_RESET_MASK) + +#define DISPLAY_RESET_REG 0x16000400 + +struct cix_display_dev { + struct device *dev; + u32 reset_mask[5]; + bool reset_need[5]; +}; + +struct cix_acpi_display { + u32 reset_mask[5]; + bool reset_need[5]; +}; + +static const struct of_device_id cix_display_dt_ids[] = { + {.compatible = "cix,display", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, cix_display_dt_ids); + +static const struct acpi_device_id cix_display_acpi_ids[] = { + {.id = "CIXH5008", .driver_data = 0, }, + { }, +}; + +MODULE_DEVICE_TABLE(acpi, cix_display_acpi_ids); + +static int cix_display_probe(struct platform_device *pdev) +{ + struct cix_display_dev *cix_display; + struct device *dev = &pdev->dev; + void *base; + int i, ret; + u32 control, value, count; + + cix_display = devm_kzalloc(dev, sizeof(*cix_display), GFP_KERNEL); + if (!cix_display) + return -ENOMEM; + + ret = device_property_read_u32(dev, "reset-control", (u32 *) &control); + if (ret) { + control = 0; + dev_info(dev, "failed to get reset-control, use default value\n"); + } + + cix_display->reset_mask[0] = DISPLAY0_RESET_MASK; + cix_display->reset_mask[1] = DISPLAY1_RESET_MASK; + cix_display->reset_mask[2] = DISPLAY2_RESET_MASK; + cix_display->reset_mask[3] = DISPLAY3_RESET_MASK; + cix_display->reset_mask[4] = DISPLAY4_RESET_MASK; + + base = ioremap(DISPLAY_RESET_REG, 0x4); + + value = readl(base); + dev_info(dev, "current reset value = 0x%x, reset-control=%d\n", value, control); + + count = 0; + for (i = 0; i < 5; i++) { + cix_display->reset_need[i] = (control >> i) & 0x1; + if (cix_display->reset_need[i]) { + count++; + value &= (~cix_display->reset_mask[i]); + } + } + + if (count) { + value &= (~MMHUB_RESET_MASK); + writel(value, base); + dev_info(dev, "assert reset, value = 0x%x, count=%d\n", value, count); + } + + for (i = 0; i < 5; i++) { + if (cix_display->reset_need[i]) + value |= cix_display->reset_mask[i]; + + if (count) { + value |= MMHUB_RESET_MASK; + writel(value, base); + dev_info(dev, "deassert reset, value = 0x%x\n", value); + } + + value = readl(base); + dev_info(dev, "current reset value = 0x%x\n", value); + + iounmap(base); + + cix_display->dev = dev; + + dev_set_drvdata(dev, cix_display); + + return 0; +} + +static struct cix_acpi_display cix_acpi_display; +static int __init cix_acpi_display_probe(void) +{ + void *base; + int i, ret; + u32 control, value, count; + struct cix_acpi_display *cix_display = &cix_acpi_display; + + memset(cix_display, 0, sizeof(*cix_display)); + control = 4; + + cix_display->reset_mask[0] = DISPLAY0_RESET_MASK; + cix_display->reset_mask[1] = DISPLAY1_RESET_MASK; + cix_display->reset_mask[2] = DISPLAY2_RESET_MASK; + cix_display->reset_mask[3] = DISPLAY3_RESET_MASK; + cix_display->reset_mask[4] = DISPLAY4_RESET_MASK; + + base = ioremap(DISPLAY_RESET_REG, 0x4); + + value = readl(base); + + count = 0; + for (i = 0; i < 5; i++) { + cix_display->reset_need[i] = (control >> i) & 0x1; + if (cix_display->reset_need[i]) { + count++; + value &= (~cix_display->reset_mask[i]); + } + } + + if (count) { + value &= (~MMHUB_RESET_MASK); + writel(value, base); + } + + for (i = 0; i < 5; i++) { + if (cix_display->reset_need[i]) + value |= cix_display->reset_mask[i]; + + if (count) { + value |= MMHUB_RESET_MASK; + writel(value, base); + } + + value = readl(base); + + iounmap(base); + + return 0; +} + +static int cix_display_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + dev_set_drvdata(dev, NULL); + + return 0; +} + +struct platform_driver cix_display_driver = { + .probe = cix_display_probe, + .remove = cix_display_remove, + .driver = { + .name = "cix-display", + .of_match_table = of_match_ptr(cix_display_dt_ids), + .acpi_match_table = ACPI_PTR(cix_display_acpi_ids), + }, +}; + +core_initcall(cix_acpi_display_probe); + +MODULE_DESCRIPTION("Cix Display Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cix-display"); diff --git a/drivers/gpu/drm/cix/cix_virtual.c b/drivers/gpu/drm/cix/cix_virtual.c new file mode 100644 index 000000000000..343dbd567992 --- /dev/null +++ b/drivers/gpu/drm/cix/cix_virtual.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 Cix Technology Group Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define XRES_MAX 4096 +#define YRES_MAX 4096 + +#define XRES_DEF 640 +#define YRES_DEF 480 + +struct cix_virtual_dev { + struct device *dev; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static const struct drm_display_mode cix_drm_dmt_modes[] = { + /* 0x04 - 640x480@60Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 0x09 - 800x600@60Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, + 968, 1056, 0, 600, 601, 605, 628, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 0x10 - 1024x768@60Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, + 1184, 1344, 0, 768, 771, 777, 806, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 0x55 - 1280x720@60Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, + 1430, 1650, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 0x52 - 1920x1080@60Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 0x51 - 3840x2160@60Hz 16:9 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, + 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 0x52 - 3840x2160@90Hz 16:9 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 891000, 3840, 4016, + 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 0x53 - 3840x2160@120Hz 16:9 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 1075804, 3840, 3848, + 3880, 3920, 0, 2160, 2273, 2281, 2287, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 0x54 - 3840x1080@90Hz 16:9 */ + { DRM_MODE("3840x1080", DRM_MODE_TYPE_DRIVER, 397605, 3840, 3848, + 3880, 3920, 0, 1080, 1113, 1121, 1127, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, +}; + +static int +cix_virtual_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + /* TODO */ + + return 0; +} + +static const struct drm_encoder_helper_funcs +cix_virtual_encoder_helper_funcs = { + .atomic_check = cix_virtual_encoder_atomic_check, +}; + +static int cix_virtual_add_modes_noedid(struct drm_connector *connector, + int hdisplay, int vdisplay) +{ + int i, count, num_modes = 0; + struct drm_display_mode *mode; + struct drm_device *dev = connector->dev; + + count = ARRAY_SIZE(cix_drm_dmt_modes); + + for (i = 0; i < count; i++) { + const struct drm_display_mode *ptr = &cix_drm_dmt_modes[i]; + + if (hdisplay && vdisplay) { + if (ptr->hdisplay > hdisplay || + ptr->vdisplay > vdisplay) + continue; + } + + mode = drm_mode_duplicate(dev, ptr); + if (mode) { + drm_mode_probed_add(connector, mode); + num_modes++; + } + } + return num_modes; +} + +static int +cix_virtual_connector_get_modes(struct drm_connector *connector) +{ + int count; + + count = cix_virtual_add_modes_noedid(connector, XRES_MAX, YRES_MAX); + drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); + + return count; +} + +static const struct drm_connector_helper_funcs +cix_virtual_connector_helper_funcs = { + .get_modes = cix_virtual_connector_get_modes, +}; + +static const struct drm_connector_funcs +cix_virtual_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static uint32_t drm_acpi_crtc_port_mask(struct drm_device *dev, + struct fwnode_handle *port) +{ + unsigned int index = 0; + struct drm_crtc *tmp; + + drm_for_each_crtc(tmp, dev) { + if ((struct fwnode_handle *)tmp->port == port) { + pr_info("cix_virtual.%s, port=%s\n", __func__, + port->ops->get_name(port)); + return 1 << index; + } + + index++; + } + + return 0; +} + +static uint32_t drm_acpi_find_possible_crtcs(struct drm_device *dev, + struct fwnode_handle *port) +{ + struct fwnode_handle *remote_port, *ep; + uint32_t possible_crtcs = 0; + + fwnode_graph_for_each_endpoint(port, ep) { + remote_port = fwnode_graph_get_remote_port(ep); + if (!remote_port) { + fwnode_handle_put(ep); + return 0; + } + + possible_crtcs |= drm_acpi_crtc_port_mask(dev, remote_port); + + fwnode_handle_put(remote_port); + } + + return possible_crtcs; +} + +static int +cix_virtual_bind(struct device *comp, struct device *master, + void *master_data) +{ + int ret; + struct drm_encoder *encoder; + struct drm_connector *connector; + struct drm_device *drm = master_data; + void *np; + + struct cix_virtual_dev *vd = dev_get_drvdata(comp); + + /* TODO: parse dt */ + + /* Init virtual encoder */ + encoder = &vd->encoder; + + drm_encoder_helper_add(encoder, &cix_virtual_encoder_helper_funcs); + + ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_VIRTUAL); + if (ret) { + dev_err(vd->dev, "failed to init simple encoder : %d\n", ret); + return ret; + } + + if (has_acpi_companion(comp)) { + pr_info("dwx: cix_virtual start to call %s via ACPI.\n", __func__); + np = comp->fwnode; + encoder->possible_crtcs = drm_acpi_find_possible_crtcs(drm, (struct fwnode_handle *)np); + } else { + pr_info("dwx: cix_virtual start to call %s via DT.\n", __func__); + np = comp->of_node; + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, (struct device_node *)np); + } + + if (encoder->possible_crtcs == 0) + return -EPROBE_DEFER; + + /* Init virtual connector */ + connector = &vd->connector; + + drm_connector_helper_add(connector, &cix_virtual_connector_helper_funcs); + + ret = drm_connector_init(drm, connector, &cix_virtual_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL); + if (ret) { + dev_err(vd->dev, "failed to init connector: %d\n", ret); + return ret; + } + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + dev_err(vd->dev, "Failed to attach connector to encoder\n"); + return ret; + } + + /* Set supported color formats */ + connector->display_info.color_formats = DRM_COLOR_FORMAT_RGB444 | + DRM_COLOR_FORMAT_YCBCR422 | + DRM_COLOR_FORMAT_YCBCR420; + + return 0; +} + +static void +cix_virtual_unbind(struct device *comp, struct device *master, + void *master_data) +{ + struct cix_virtual_dev *vd = dev_get_drvdata(comp); + + drm_connector_cleanup(&vd->connector); + drm_encoder_cleanup(&vd->encoder); +} + +const struct component_ops cix_virtual_ops = { + .bind = cix_virtual_bind, + .unbind = cix_virtual_unbind, +}; + +static const struct of_device_id cix_virtual_dt_ids[] = { + { .compatible = "cix,virtual-display", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, cix_virtual_dt_ids); + +static const struct acpi_device_id cix_virtual_acpi_ids[] = { + { .id = "CIXH503F", 0}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(acpi, cix_virtual_acpi_ids); + +static int cix_virtual_probe(struct platform_device *pdev) +{ + struct cix_virtual_dev *vd; + struct device *dev = &pdev->dev; + + vd = devm_kzalloc(dev, sizeof(*vd), GFP_KERNEL); + if (!vd) + return -ENOMEM; + + vd->dev = dev; + + dev_set_drvdata(dev, vd); + + return component_add(dev, &cix_virtual_ops); +} + +static int cix_virtual_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + component_del(dev, &cix_virtual_ops); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +struct platform_driver cix_virtual_driver = { + .probe = cix_virtual_probe, + .remove = cix_virtual_remove, + .driver = { + .name = "cix-virtual-display", + .of_match_table = of_match_ptr(cix_virtual_dt_ids), + .acpi_match_table = ACPI_PTR(cix_virtual_acpi_ids), + }, +}; + +module_platform_driver(cix_virtual_driver); + +MODULE_AUTHOR("Fancy Fang "); +MODULE_DESCRIPTION("Cix DRM Virtual Display Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cix-virtual"); diff --git a/drivers/gpu/drm/cix/dptx/Kconfig b/drivers/gpu/drm/cix/dptx/Kconfig new file mode 100644 index 000000000000..557f5a1681ef --- /dev/null +++ b/drivers/gpu/drm/cix/dptx/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_TRILIN_DPSUB + tristate "Trilinear Technologies DisplayPort Controller Driver" + depends on COMMON_CLK && DRM && OF + select DRM_KMS_HELPER + select DRM_DISPLAY_HELPER + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HDMI_HELPER + select DRM_DP_AUX_CHARDEV + select GENERIC_PHY + select SND_SOC_HDMI_CODEC if SND_SOC + help + This is a DRM/KMS driver for Trilinear Technologies DisplayPort controller. + Choose this option if you are using an SoC with a Trilinear Technologies + DisplayPort subsystem. + +config DRM_TRILIN_CADENCE_PHY + tristate "Trilinear DisplayPort Controller with Cadence PHY" + depends on DRM_TRILIN_DPSUB + help + Choose this option if you are using a proper platform with a Trilinear + Technologies DisplayPort subsystem. diff --git a/drivers/gpu/drm/cix/dptx/Makefile b/drivers/gpu/drm/cix/dptx/Makefile new file mode 100644 index 000000000000..477dc21723f6 --- /dev/null +++ b/drivers/gpu/drm/cix/dptx/Makefile @@ -0,0 +1,8 @@ +trilin-dpsub-y := trilin_dptx_cix.o trilin_dptx.o trilin_host_tmr.o dptx_infoframe.o trilin_dptx_audio.o trilin_drm.o trilin_drm_mst.o +trilin-dpsub-y += trilin_edp_phy.o trilin_usbdp_phy.o +trilin-dpsub-y += hdcp/hdcp2_tx_tmr.o +trilin-dpsub-y += hdcp/cix_hdcp_ioctl.o +trilin-dpsub-y += hdcp/cix_hdcp.o +trilin-dpsub-y += cix_edp_panel.o + +obj-$(CONFIG_DRM_TRILIN_DPSUB) += trilin-dpsub.o diff --git a/drivers/gpu/drm/cix/dptx/cix_edp_panel.c b/drivers/gpu/drm/cix/dptx/cix_edp_panel.c new file mode 100644 index 000000000000..f9160fce4d6a --- /dev/null +++ b/drivers/gpu/drm/cix/dptx/cix_edp_panel.c @@ -0,0 +1,872 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include