diff options
Diffstat (limited to 'drivers')
95 files changed, 6624 insertions, 1619 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 29be78a3f28..78dcf62f76a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/ obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/ obj-$(CONFIG_$(SPL_)SYSINFO) += sysinfo/ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/ +obj-$(CONFIG_$(SPL_)NVME) += nvme/ obj-$(CONFIG_XEN) += xen/ obj-$(CONFIG_$(SPL_)FPGA) += fpga/ obj-y += bus/ diff --git a/drivers/axi/axi-emul-uclass.c b/drivers/axi/axi-emul-uclass.c index 793336d8c47..e6f3ef07200 100644 --- a/drivers/axi/axi-emul-uclass.c +++ b/drivers/axi/axi-emul-uclass.c @@ -14,7 +14,7 @@ #include <asm/axi.h> int axi_sandbox_get_emul(struct udevice *bus, ulong address, - enum axi_size_t size, struct udevice **emulp) + const enum axi_size_t size, struct udevice **emulp) { struct udevice *dev; u32 reg[2]; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 5a1aeb3d2b4..6baaa6f0711 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -107,6 +107,13 @@ config EFI_MEDIA For sandbox there is a test driver. +config SPL_BLK_FS + bool "Load images from filesystems on block devices" + depends on SPL_BLK + help + Use generic support to load images from fat/ext filesystems on + different types of block devices such as NVMe. + if EFI_MEDIA config EFI_MEDIA_SANDBOX diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 184d426d0b3..017f25f7a5a 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -184,7 +184,7 @@ struct clk *clk_hw_register_mux_table(struct device *dev, const char *name, if (!mux) return ERR_PTR(-ENOMEM); - /* U-boot specific assignments */ + /* U-Boot specific assignments */ mux->parent_names = parent_names; mux->num_parents = num_parents; diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c index 45c679a627b..be0ee50e0e4 100644 --- a/drivers/clk/clk_zynqmp.c +++ b/drivers/clk/clk_zynqmp.c @@ -691,6 +691,7 @@ static ulong zynqmp_clk_get_rate(struct clk *clk) case topsw_lsbus: case sata_ref ... gpu_pp1_ref: two_divs = true; + fallthrough; case cpu_r5: case dbg_fpd: case ams_ref: diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile index 51348b1ddc0..84859d92aba 100644 --- a/drivers/clk/sifive/Makefile +++ b/drivers/clk/sifive/Makefile @@ -1,5 +1,3 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-y += sifive-prci.o - -obj-$(CONFIG_CLK_SIFIVE_PRCI) += fu540-prci.o fu740-prci.o +obj-$(CONFIG_CLK_SIFIVE_PRCI) += sifive-prci.o fu540-prci.o fu740-prci.o diff --git a/drivers/clk/starfive/clk-jh7110-pll.c b/drivers/clk/starfive/clk-jh7110-pll.c index 02e6d9000e2..7492b1f70dd 100644 --- a/drivers/clk/starfive/clk-jh7110-pll.c +++ b/drivers/clk/starfive/clk-jh7110-pll.c @@ -185,7 +185,7 @@ static void jh7110_pll_set_rate(struct clk_jh7110_pllx *pll, PLLX_SET(pll->offset->dsmpd, pll->offset->dsmpd_mask, 1); PLLX_SET(pll->offset->prediv, pll->offset->prediv_mask, rate->prediv); PLLX_SET(pll->offset->fbdiv, pll->offset->fbdiv_mask, rate->fbdiv); - PLLX_SET(pll->offset->postdiv1, pll->offset->postdiv1, 0); + PLLX_SET(pll->offset->postdiv1, pll->offset->postdiv1_mask, 0); PLLX_SET(pll->offset->pd, pll->offset->pd_mask, PLL_PD_ON); if (set) { diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index 8d7f13dcb0b..c3a0b93b25e 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -41,7 +41,6 @@ config DFU_MMC config DFU_MTD bool "MTD back end for DFU" depends on DM_MTD - depends on CMD_MTDPARTS help This option enables using DFU to read and write to on any MTD device. diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 516dda61796..b2ee5f1ede6 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -135,6 +135,7 @@ int dfu_config_interfaces(char *env) a = s; do { part = strsep(&a, ";"); + part = skip_spaces(part); ret = dfu_alt_add(dfu, i, d, part); if (ret) return ret; @@ -629,6 +630,7 @@ int dfu_config_entities(char *env, char *interface, char *devstr) for (i = 0; i < dfu_alt_num; i++) { s = strsep(&env, ";"); + s = skip_spaces(s); ret = dfu_alt_add(dfu, interface, devstr, s); if (ret) { /* We will free "dfu" in dfu_free_entities() */ diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c index c7075f12eca..75e2f6a4215 100644 --- a/drivers/dfu/dfu_mtd.c +++ b/drivers/dfu/dfu_mtd.c @@ -10,7 +10,6 @@ #include <common.h> #include <dfu.h> #include <mtd.h> -#include <jffs2/load_kernel.h> #include <linux/err.h> #include <linux/ctype.h> @@ -275,7 +274,7 @@ int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char **argv, int a { char *s; struct mtd_info *mtd; - int ret, part; + int part; mtd = get_mtd_device_nm(devstr); if (IS_ERR_OR_NULL(mtd)) @@ -299,10 +298,9 @@ int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char **argv, int a if (*s) return -EINVAL; } else if ((!strcmp(argv[0], "part")) || (!strcmp(argv[0], "partubi"))) { - char mtd_id[32]; - struct mtd_device *mtd_dev; - u8 part_num; - struct part_info *pi; + struct mtd_info *partition; + int partnum = 0; + bool part_found = false; if (argc != 2) return -EINVAL; @@ -313,19 +311,25 @@ int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char **argv, int a if (*s) return -EINVAL; - sprintf(mtd_id, "%s,%d", devstr, part - 1); - printf("using id '%s'\n", mtd_id); + /* register partitions with MTDIDS/MTDPARTS or OF fallback */ + mtd_probe_devices(); - mtdparts_init(); - - ret = find_dev_and_part(mtd_id, &mtd_dev, &part_num, &pi); - if (ret != 0) { - printf("Could not locate '%s'\n", mtd_id); + partnum = 0; + list_for_each_entry(partition, &mtd->partitions, node) { + partnum++; + if (partnum == part) { + part_found = true; + break; + } + } + if (!part_found) { + printf("No partition %d in %s\n", part, mtd->name); return -1; } + log_debug("partition %d:%s in %s\n", partnum, partition->name, mtd->name); - dfu->data.mtd.start = pi->offset; - dfu->data.mtd.size = pi->size; + dfu->data.mtd.start = partition->offset; + dfu->data.mtd.size = partition->size; if (!strcmp(argv[0], "partubi")) dfu->data.mtd.ubi = 1; } else { diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c index 621146bc6b0..4e9d9b719c6 100644 --- a/drivers/fastboot/fb_common.c +++ b/drivers/fastboot/fb_common.c @@ -135,7 +135,7 @@ void fastboot_boot(void) s = env_get("fastboot_bootcmd"); if (s) { run_command(s, CMD_FLAG_ENV); - } else { + } else if (IS_ENABLED(CONFIG_CMD_BOOTM)) { static char boot_addr_start[20]; static char *const bootm_args[] = { "bootm", boot_addr_start, NULL diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index dc8e3ad2b9d..ab4c4f1a690 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -23,10 +23,10 @@ #define XST_PM_NO_ACCESS 2002L #define XST_PM_ALREADY_CONFIGURED 2009L -struct zynqmp_power { +static struct zynqmp_power { struct mbox_chan tx_chan; struct mbox_chan rx_chan; -} zynqmp_power = {}; +} zynqmp_power __section(".data"); #define NODE_ID_LOCATION 5 @@ -63,29 +63,32 @@ static unsigned int xpm_configobject_close[] = { int zynqmp_pmufw_config_close(void) { - zynqmp_pmufw_load_config_object(xpm_configobject_close, - sizeof(xpm_configobject_close)); - return 0; + return zynqmp_pmufw_load_config_object(xpm_configobject_close, + sizeof(xpm_configobject_close)); } int zynqmp_pmufw_node(u32 id) { - static bool skip_config; - int ret; + static bool check = true; + static bool permission = true; + + if (check) { + check = false; + + if (zynqmp_pmufw_node(NODE_OCM_BANK_0) == -EACCES) { + printf("PMUFW: No permission to change config object\n"); + permission = false; + } + } - if (skip_config) + if (!permission) return 0; /* Record power domain id */ xpm_configobject[NODE_ID_LOCATION] = id; - ret = zynqmp_pmufw_load_config_object(xpm_configobject, - sizeof(xpm_configobject)); - - if (ret == XST_PM_NO_ACCESS && id == NODE_OCM_BANK_0) - skip_config = true; - - return 0; + return zynqmp_pmufw_load_config_object(xpm_configobject, + sizeof(xpm_configobject)); } static int do_pm_probe(void) @@ -235,8 +238,7 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) * * @cfg_obj: Pointer to the configuration object * @size: Size of @cfg_obj in bytes - * Return: 0 on success otherwise negative errno. If the config object - * is not loadable returns positive errno XST_PM_NO_ACCESS(2002) + * Return: 0 on success otherwise negative errno. */ int zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) { @@ -251,10 +253,6 @@ int zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) err = xilinx_pm_request(PM_SET_CONFIGURATION, (u32)(u64)cfg_obj, 0, 0, 0, ret_payload); if (err == XST_PM_NO_ACCESS) { - if (((u32 *)cfg_obj)[NODE_ID_LOCATION] == NODE_OCM_BANK_0) { - printf("PMUFW: No permission to change config object\n"); - return err; - } return -EACCES; } @@ -298,9 +296,6 @@ static int zynqmp_power_probe(struct udevice *dev) ret >> ZYNQMP_PM_VERSION_MAJOR_SHIFT, ret & ZYNQMP_PM_VERSION_MINOR_MASK); - if (IS_ENABLED(CONFIG_ARCH_ZYNQMP)) - zynqmp_pmufw_node(NODE_OCM_BANK_0); - return 0; }; @@ -320,7 +315,8 @@ U_BOOT_DRIVER(zynqmp_power) = { int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 *ret_payload) { - debug("%s at EL%d, API ID: 0x%0x\n", __func__, current_el(), api_id); + debug("%s at EL%d, API ID: 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x\n", + __func__, current_el(), api_id, arg0, arg1, arg2, arg3); if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { #if defined(CONFIG_ZYNQMP_IPI) @@ -398,7 +394,7 @@ static int zynqmp_firmware_bind(struct udevice *dev) } } - return dm_scan_fdt_dev(dev); + return 0; } U_BOOT_DRIVER(zynqmp_firmware) = { diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index bd7379ae555..72f572d8248 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -265,7 +265,7 @@ static int ti_sci_do_xfer(struct ti_sci_info *info, if (xfer->rx_len) { ret = ti_sci_get_response(info, xfer, &info->chan_rx); if (!ti_sci_is_response_ack(xfer->tx_message.buf)) { - dev_err(info->dev, "Message not acknowledged"); + dev_err(info->dev, "Message not acknowledged\n"); ret = -ENODEV; } } diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig index 36c4479a59e..42736a5e43b 100644 --- a/drivers/fwu-mdata/Kconfig +++ b/drivers/fwu-mdata/Kconfig @@ -6,6 +6,11 @@ config FWU_MDATA FWU Metadata partitions reside on the same storage device which contains the other FWU updatable firmware images. +choice + prompt "Storage Layout Scheme" + depends on FWU_MDATA + default FWU_MDATA_GPT_BLK + config FWU_MDATA_GPT_BLK bool "FWU Metadata access for GPT partitioned Block devices" select PARTITION_TYPE_GUID @@ -14,3 +19,13 @@ config FWU_MDATA_GPT_BLK help Enable support for accessing FWU Metadata on GPT partitioned block devices. + +config FWU_MDATA_MTD + bool "Raw MTD devices" + depends on MTD + help + Enable support for accessing FWU Metadata on non-partitioned + (or non-GPT partitioned, e.g. partition nodes in devicetree) + MTD devices. + +endchoice diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile index 3fee64c10c9..06c49747ba8 100644 --- a/drivers/fwu-mdata/Makefile +++ b/drivers/fwu-mdata/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_FWU_MDATA) += fwu-mdata-uclass.o obj-$(CONFIG_FWU_MDATA_GPT_BLK) += gpt_blk.o +obj-$(CONFIG_FWU_MDATA_MTD) += raw_mtd.o diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c index b477e9603fb..0a8edaaa418 100644 --- a/drivers/fwu-mdata/fwu-mdata-uclass.c +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c @@ -14,170 +14,39 @@ #include <linux/errno.h> #include <linux/types.h> -#include <u-boot/crc.h> /** - * fwu_get_mdata_part_num() - Get the FWU metadata partition numbers - * @dev: FWU metadata device - * @mdata_parts: array for storing the metadata partition numbers - * - * Get the partition numbers on the storage device on which the - * FWU metadata is stored. Two partition numbers will be returned. - * - * Return: 0 if OK, -ve on error - * - */ -int fwu_get_mdata_part_num(struct udevice *dev, uint *mdata_parts) -{ - const struct fwu_mdata_ops *ops = device_get_ops(dev); - - if (!ops->get_mdata_part_num) { - log_debug("get_mdata_part_num() method not defined\n"); - return -ENOSYS; - } - - return ops->get_mdata_part_num(dev, mdata_parts); -} - -/** - * fwu_read_mdata_partition() - Read the FWU metadata from a partition - * @dev: FWU metadata device - * @mdata: Copy of the FWU metadata - * @part_num: Partition number from which FWU metadata is to be read - * - * Read the FWU metadata from the specified partition number - * - * Return: 0 if OK, -ve on error - * - */ -int fwu_read_mdata_partition(struct udevice *dev, struct fwu_mdata *mdata, - uint part_num) -{ - const struct fwu_mdata_ops *ops = device_get_ops(dev); - - if (!ops->read_mdata_partition) { - log_debug("read_mdata_partition() method not defined\n"); - return -ENOSYS; - } - - return ops->read_mdata_partition(dev, mdata, part_num); -} - -/** - * fwu_write_mdata_partition() - Write the FWU metadata to a partition - * @dev: FWU metadata device - * @mdata: Copy of the FWU metadata - * @part_num: Partition number to which FWU metadata is to be written - * - * Write the FWU metadata to the specified partition number - * - * Return: 0 if OK, -ve on error - * - */ -int fwu_write_mdata_partition(struct udevice *dev, struct fwu_mdata *mdata, - uint part_num) -{ - const struct fwu_mdata_ops *ops = device_get_ops(dev); - - if (!ops->write_mdata_partition) { - log_debug("write_mdata_partition() method not defined\n"); - return -ENOSYS; - } - - return ops->write_mdata_partition(dev, mdata, part_num); -} - -/** - * fwu_mdata_check() - Check if the FWU metadata is valid - * @dev: FWU metadata device - * - * Validate both copies of the FWU metadata. If one of the copies - * has gone bad, restore it from the other copy. - * - * Return: 0 if OK, -ve on error - * - */ -int fwu_mdata_check(struct udevice *dev) -{ - const struct fwu_mdata_ops *ops = device_get_ops(dev); - - if (!ops->check_mdata) { - log_debug("check_mdata() method not defined\n"); - return -ENOSYS; - } - - return ops->check_mdata(dev); -} - -/** - * fwu_get_mdata() - Get a FWU metadata copy - * @dev: FWU metadata device - * @mdata: Copy of the FWU metadata - * - * Get a valid copy of the FWU metadata. - * - * Note: This function is to be called first when modifying any fields - * in the metadata. The sequence of calls to modify any field in the - * metadata would be 1) fwu_get_mdata 2) Modify metadata, followed by - * 3) fwu_update_mdata + * fwu_read_mdata() - Wrapper around fwu_mdata_ops.read_mdata() * * Return: 0 if OK, -ve on error - * */ -int fwu_get_mdata(struct udevice *dev, struct fwu_mdata *mdata) +int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary) { const struct fwu_mdata_ops *ops = device_get_ops(dev); - if (!ops->get_mdata) { - log_debug("get_mdata() method not defined\n"); + if (!ops->read_mdata) { + log_debug("read_mdata() method not defined\n"); return -ENOSYS; } - return ops->get_mdata(dev, mdata); + return ops->read_mdata(dev, mdata, primary); } /** - * fwu_update_mdata() - Update the FWU metadata - * @dev: FWU metadata device - * @mdata: Copy of the FWU metadata - * - * Update the FWU metadata structure by writing to the - * FWU metadata partitions. - * - * Note: This function is not to be called directly to update the - * metadata fields. The sequence of function calls should be - * 1) fwu_get_mdata() 2) Modify the medata fields 3) fwu_update_mdata() - * - * The sequence of updating the partitions should be, update the - * primary metadata partition (first partition encountered), followed - * by updating the secondary partition. With this update sequence, in - * the rare scenario that the two metadata partitions are valid but do - * not match, maybe due to power outage at the time of updating the - * metadata copies, the secondary partition can be updated from the - * primary. + * fwu_write_mdata() - Wrapper around fwu_mdata_ops.write_mdata() * * Return: 0 if OK, -ve on error - * */ -int fwu_update_mdata(struct udevice *dev, struct fwu_mdata *mdata) +int fwu_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary) { - void *buf; const struct fwu_mdata_ops *ops = device_get_ops(dev); - if (!ops->update_mdata) { - log_debug("get_mdata() method not defined\n"); + if (!ops->write_mdata) { + log_debug("write_mdata() method not defined\n"); return -ENOSYS; } - /* - * Calculate the crc32 for the updated FWU metadata - * and put the updated value in the FWU metadata crc32 - * field - */ - buf = &mdata->version; - mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); - - return ops->update_mdata(dev, mdata); + return ops->write_mdata(dev, mdata, primary); } UCLASS_DRIVER(fwu_mdata) = { diff --git a/drivers/fwu-mdata/gpt_blk.c b/drivers/fwu-mdata/gpt_blk.c index d35ce49c5c1..c7284916c4e 100644 --- a/drivers/fwu-mdata/gpt_blk.c +++ b/drivers/fwu-mdata/gpt_blk.c @@ -24,38 +24,40 @@ enum { MDATA_WRITE, }; -static int gpt_get_mdata_partitions(struct blk_desc *desc, - uint mdata_parts[2]) +static uint g_mdata_part[2]; /* = {0, 0} to check against uninit parts */ + +static int gpt_get_mdata_partitions(struct blk_desc *desc) { - int i, ret; + int i; u32 nparts; efi_guid_t part_type_guid; struct disk_partition info; const efi_guid_t fwu_mdata_guid = FWU_MDATA_GUID; + /* if primary and secondary partitions already found */ + if (g_mdata_part[0] && g_mdata_part[1]) + return 0; + nparts = 0; - for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) { + for (i = 1; i < MAX_SEARCH_PARTITIONS && nparts < 2; i++) { if (part_get_info(desc, i, &info)) continue; uuid_str_to_bin(info.type_guid, part_type_guid.b, UUID_STR_FORMAT_GUID); - if (!guidcmp(&fwu_mdata_guid, &part_type_guid)) { - if (nparts < 2) - mdata_parts[nparts] = i; - ++nparts; - } + if (!guidcmp(&fwu_mdata_guid, &part_type_guid)) + g_mdata_part[nparts++] = i; } if (nparts != 2) { log_debug("Expect two copies of the FWU metadata instead of %d\n", nparts); - ret = -EINVAL; - } else { - ret = 0; + g_mdata_part[0] = 0; + g_mdata_part[1] = 0; + return -EINVAL; } - return ret; + return 0; } static int gpt_get_mdata_disk_part(struct blk_desc *desc, @@ -123,112 +125,6 @@ static int gpt_read_write_mdata(struct blk_desc *desc, return 0; } -static int fwu_gpt_update_mdata(struct udevice *dev, struct fwu_mdata *mdata) -{ - int ret; - struct blk_desc *desc; - uint mdata_parts[2]; - struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev); - - desc = dev_get_uclass_plat(priv->blk_dev); - - ret = gpt_get_mdata_partitions(desc, mdata_parts); - if (ret < 0) { - log_debug("Error getting the FWU metadata partitions\n"); - return -ENOENT; - } - - /* First write the primary partition */ - ret = gpt_read_write_mdata(desc, mdata, MDATA_WRITE, mdata_parts[0]); - if (ret < 0) { - log_debug("Updating primary FWU metadata partition failed\n"); - return ret; - } - - /* And now the replica */ - ret = gpt_read_write_mdata(desc, mdata, MDATA_WRITE, mdata_parts[1]); - if (ret < 0) { - log_debug("Updating secondary FWU metadata partition failed\n"); - return ret; - } - - return 0; -} - -static int gpt_get_mdata(struct blk_desc *desc, struct fwu_mdata *mdata) -{ - int ret; - uint mdata_parts[2]; - - ret = gpt_get_mdata_partitions(desc, mdata_parts); - - if (ret < 0) { - log_debug("Error getting the FWU metadata partitions\n"); - return -ENOENT; - } - - ret = gpt_read_write_mdata(desc, mdata, MDATA_READ, mdata_parts[0]); - if (ret < 0) { - log_debug("Failed to read the FWU metadata from the device\n"); - return -EIO; - } - - ret = fwu_verify_mdata(mdata, 1); - if (!ret) - return 0; - - /* - * Verification of the primary FWU metadata copy failed. - * Try to read the replica. - */ - memset(mdata, '\0', sizeof(struct fwu_mdata)); - ret = gpt_read_write_mdata(desc, mdata, MDATA_READ, mdata_parts[1]); - if (ret < 0) { - log_debug("Failed to read the FWU metadata from the device\n"); - return -EIO; - } - - ret = fwu_verify_mdata(mdata, 0); - if (!ret) - return 0; - - /* Both the FWU metadata copies are corrupted. */ - return -EIO; -} - -static int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata *mdata) -{ - struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev); - - return gpt_get_mdata(dev_get_uclass_plat(priv->blk_dev), mdata); -} - -static int fwu_gpt_get_mdata_partitions(struct udevice *dev, uint *mdata_parts) -{ - struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev); - - return gpt_get_mdata_partitions(dev_get_uclass_plat(priv->blk_dev), - mdata_parts); -} - -static int fwu_gpt_read_mdata_partition(struct udevice *dev, - struct fwu_mdata *mdata, uint part_num) -{ - struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev); - - return gpt_read_write_mdata(dev_get_uclass_plat(priv->blk_dev), - mdata, MDATA_READ, part_num); -} - -static int fwu_gpt_write_mdata_partition(struct udevice *dev, - struct fwu_mdata *mdata, uint part_num) -{ - struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev); - - return gpt_read_write_mdata(dev_get_uclass_plat(priv->blk_dev), - mdata, MDATA_WRITE, part_num); -} - static int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev) { u32 phandle; @@ -267,12 +163,43 @@ static int fwu_mdata_gpt_blk_probe(struct udevice *dev) return 0; } +static int fwu_gpt_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, + bool primary) +{ + struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev); + struct blk_desc *desc = dev_get_uclass_plat(priv->blk_dev); + int ret; + + ret = gpt_get_mdata_partitions(desc); + if (ret < 0) { + log_debug("Error getting the FWU metadata partitions\n"); + return -ENOENT; + } + + return gpt_read_write_mdata(desc, mdata, MDATA_READ, + primary ? g_mdata_part[0] : g_mdata_part[1]); +} + +static int fwu_gpt_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, + bool primary) +{ + struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev); + struct blk_desc *desc = dev_get_uclass_plat(priv->blk_dev); + int ret; + + ret = gpt_get_mdata_partitions(desc); + if (ret < 0) { + log_debug("Error getting the FWU metadata partitions\n"); + return -ENOENT; + } + + return gpt_read_write_mdata(desc, mdata, MDATA_WRITE, + primary ? g_mdata_part[0] : g_mdata_part[1]); +} + static const struct fwu_mdata_ops fwu_gpt_blk_ops = { - .get_mdata = fwu_gpt_get_mdata, - .update_mdata = fwu_gpt_update_mdata, - .get_mdata_part_num = fwu_gpt_get_mdata_partitions, - .read_mdata_partition = fwu_gpt_read_mdata_partition, - .write_mdata_partition = fwu_gpt_write_mdata_partition, + .read_mdata = fwu_gpt_read_mdata, + .write_mdata = fwu_gpt_write_mdata, }; static const struct udevice_id fwu_mdata_ids[] = { diff --git a/drivers/fwu-mdata/raw_mtd.c b/drivers/fwu-mdata/raw_mtd.c new file mode 100644 index 00000000000..17e45179738 --- /dev/null +++ b/drivers/fwu-mdata/raw_mtd.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023, Linaro Limited + */ + +#define LOG_CATEGORY UCLASS_FWU_MDATA + +#include <fwu.h> +#include <fwu_mdata.h> +#include <memalign.h> + +#include <linux/errno.h> +#include <linux/types.h> + +/* Internal helper structure to move data around */ +struct fwu_mdata_mtd_priv { + struct mtd_info *mtd; + char pri_label[50]; + char sec_label[50]; + u32 pri_offset; + u32 sec_offset; +}; + +enum fwu_mtd_op { + FWU_MTD_READ, + FWU_MTD_WRITE, +}; + +extern struct fwu_mtd_image_info fwu_mtd_images[]; + +static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size) +{ + return !do_div(size, mtd->erasesize); +} + +static int mtd_io_data(struct mtd_info *mtd, u32 offs, u32 size, void *data, + enum fwu_mtd_op op) +{ + struct mtd_oob_ops io_op = {}; + u64 lock_len; + size_t len; + void *buf; + int ret; + + if (!mtd_is_aligned_with_block_size(mtd, offs)) { + log_err("Offset unaligned with a block (0x%x)\n", mtd->erasesize); + return -EINVAL; + } + + /* This will expand erase size to align with the block size */ + lock_len = round_up(size, mtd->erasesize); + + ret = mtd_unlock(mtd, offs, lock_len); + if (ret && ret != -EOPNOTSUPP) + return ret; + + if (op == FWU_MTD_WRITE) { + struct erase_info erase_op = {}; + + erase_op.mtd = mtd; + erase_op.addr = offs; + erase_op.len = lock_len; + erase_op.scrub = 0; + + ret = mtd_erase(mtd, &erase_op); + if (ret) + goto lock; + } + + /* Also, expand the write size to align with the write size */ + len = round_up(size, mtd->writesize); + + buf = memalign(ARCH_DMA_MINALIGN, len); + if (!buf) { + ret = -ENOMEM; + goto lock; + } + memset(buf, 0xff, len); + + io_op.mode = MTD_OPS_AUTO_OOB; + io_op.len = len; + io_op.datbuf = buf; + + if (op == FWU_MTD_WRITE) { + memcpy(buf, data, size); + ret = mtd_write_oob(mtd, offs, &io_op); + } else { + ret = mtd_read_oob(mtd, offs, &io_op); + if (!ret) + memcpy(data, buf, size); + } + free(buf); + +lock: + mtd_lock(mtd, offs, lock_len); + + return ret; +} + +static int fwu_mtd_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary) +{ + struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); + struct mtd_info *mtd = mtd_priv->mtd; + u32 offs = primary ? mtd_priv->pri_offset : mtd_priv->sec_offset; + + return mtd_io_data(mtd, offs, sizeof(struct fwu_mdata), mdata, FWU_MTD_READ); +} + +static int fwu_mtd_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary) +{ + struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); + struct mtd_info *mtd = mtd_priv->mtd; + u32 offs = primary ? mtd_priv->pri_offset : mtd_priv->sec_offset; + + return mtd_io_data(mtd, offs, sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE); +} + +static int flash_partition_offset(struct udevice *dev, const char *part_name, fdt_addr_t *offset) +{ + ofnode node, parts_node; + fdt_addr_t size = 0; + + parts_node = ofnode_by_compatible(dev_ofnode(dev), "fixed-partitions"); + node = ofnode_by_prop_value(parts_node, "label", part_name, strlen(part_name) + 1); + if (!ofnode_valid(node)) { + log_err("Warning: Failed to find partition by label <%s>\n", part_name); + return -ENOENT; + } + + *offset = ofnode_get_addr_size_index_notrans(node, 0, &size); + + return (int)size; +} + +static int fwu_mdata_mtd_of_to_plat(struct udevice *dev) +{ + struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); + const fdt32_t *phandle_p = NULL; + struct udevice *mtd_dev; + struct mtd_info *mtd; + const char *label; + fdt_addr_t offset; + int ret, size; + u32 phandle; + ofnode bank; + int off_img; + + /* Find the FWU mdata storage device */ + phandle_p = ofnode_get_property(dev_ofnode(dev), + "fwu-mdata-store", &size); + if (!phandle_p) { + log_err("FWU meta data store not defined in device-tree\n"); + return -ENOENT; + } + + phandle = fdt32_to_cpu(*phandle_p); + + ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle), + &mtd_dev); + if (ret) { + log_err("FWU: failed to get mtd device\n"); + return ret; + } + + mtd_probe_devices(); + + mtd_for_each_device(mtd) { + if (mtd->dev == mtd_dev) { + mtd_priv->mtd = mtd; + log_debug("Found the FWU mdata mtd device %s\n", mtd->name); + break; + } + } + if (!mtd_priv->mtd) { + log_err("Failed to find mtd device by fwu-mdata-store\n"); + return -ENODEV; + } + + /* Get the offset of primary and secondary mdata */ + ret = ofnode_read_string_index(dev_ofnode(dev), "mdata-parts", 0, &label); + if (ret) + return ret; + strncpy(mtd_priv->pri_label, label, 50); + + ret = flash_partition_offset(mtd_dev, mtd_priv->pri_label, &offset); + if (ret <= 0) + return ret; + mtd_priv->pri_offset = offset; + + ret = ofnode_read_string_index(dev_ofnode(dev), "mdata-parts", 1, &label); + if (ret) + return ret; + strncpy(mtd_priv->sec_label, label, 50); + + ret = flash_partition_offset(mtd_dev, mtd_priv->sec_label, &offset); + if (ret <= 0) + return ret; + mtd_priv->sec_offset = offset; + + off_img = 0; + + ofnode_for_each_subnode(bank, dev_ofnode(dev)) { + int bank_num, bank_offset, bank_size; + const char *bank_name; + ofnode image; + + ofnode_read_u32(bank, "id", &bank_num); + bank_name = ofnode_read_string(bank, "label"); + bank_size = flash_partition_offset(mtd_dev, bank_name, &offset); + if (bank_size <= 0) + return bank_size; + bank_offset = offset; + log_debug("Bank%d: %s [0x%x - 0x%x]\n", + bank_num, bank_name, bank_offset, bank_offset + bank_size); + + ofnode_for_each_subnode(image, bank) { + int image_num, image_offset, image_size; + const char *uuid; + + if (off_img == CONFIG_FWU_NUM_BANKS * + CONFIG_FWU_NUM_IMAGES_PER_BANK) { + log_err("DT provides more images than configured!\n"); + break; + } + + uuid = ofnode_read_string(image, "uuid"); + ofnode_read_u32(image, "id", &image_num); + ofnode_read_u32(image, "offset", &image_offset); + ofnode_read_u32(image, "size", &image_size); + + fwu_mtd_images[off_img].start = bank_offset + image_offset; + fwu_mtd_images[off_img].size = image_size; + fwu_mtd_images[off_img].bank_num = bank_num; + fwu_mtd_images[off_img].image_num = image_num; + strcpy(fwu_mtd_images[off_img].uuidbuf, uuid); + log_debug("\tImage%d: %s @0x%x\n\n", + image_num, uuid, bank_offset + image_offset); + off_img++; + } + } + + return 0; +} + +static int fwu_mdata_mtd_probe(struct udevice *dev) +{ + /* Ensure the metadata can be read. */ + return fwu_get_mdata(NULL); +} + +static struct fwu_mdata_ops fwu_mtd_ops = { + .read_mdata = fwu_mtd_read_mdata, + .write_mdata = fwu_mtd_write_mdata, +}; + +static const struct udevice_id fwu_mdata_ids[] = { + { .compatible = "u-boot,fwu-mdata-mtd" }, + { } +}; + +U_BOOT_DRIVER(fwu_mdata_mtd) = { + .name = "fwu-mdata-mtd", + .id = UCLASS_FWU_MDATA, + .of_match = fwu_mdata_ids, + .ops = &fwu_mtd_ops, + .probe = fwu_mdata_mtd_probe, + .of_to_plat = fwu_mdata_mtd_of_to_plat, + .priv_auto = sizeof(struct fwu_mdata_mtd_priv), +}; diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c index 902da050fbf..ca7aa14eeb2 100644 --- a/drivers/gpio/gpio-fxl6408.c +++ b/drivers/gpio/gpio-fxl6408.c @@ -27,7 +27,7 @@ * https://patchwork.kernel.org/patch/9148419/ * - the Toradex version by Max Krummenacher <max.krummenacher@toradex.com>: * http://git.toradex.com/cgit/linux-toradex.git/tree/drivers/gpio/gpio-fxl6408.c?h=toradex_5.4-2.3.x-imx - * - the U-boot PCA953x driver by Peng Fan <van.freenix@gmail.com>: + * - the U-Boot PCA953x driver by Peng Fan <van.freenix@gmail.com>: * drivers/gpio/pca953x_gpio.c * * TODO: diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 9ffb4a56258..d6cfbd231a8 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -130,20 +130,9 @@ static int rcar_gpio_get_function(struct udevice *dev, unsigned offset) return GPIOF_INPUT; } -static int rcar_gpio_request(struct udevice *dev, unsigned offset, - const char *label) -{ - return pinctrl_gpio_request(dev, offset, label); -} - -static int rcar_gpio_free(struct udevice *dev, unsigned offset) -{ - return pinctrl_gpio_free(dev, offset); -} - static const struct dm_gpio_ops rcar_gpio_ops = { - .request = rcar_gpio_request, - .rfree = rcar_gpio_free, + .request = pinctrl_gpio_request, + .rfree = pinctrl_gpio_free, .direction_input = rcar_gpio_direction_input, .direction_output = rcar_gpio_direction_output, .get_value = rcar_gpio_get_value, diff --git a/drivers/gpio/npcm_gpio.c b/drivers/gpio/npcm_gpio.c index 8afd57fa8e5..98e5dc79c1c 100644 --- a/drivers/gpio/npcm_gpio.c +++ b/drivers/gpio/npcm_gpio.c @@ -37,14 +37,14 @@ static int npcm_gpio_direction_output(struct udevice *dev, unsigned int offset, { struct npcm_gpio_priv *priv = dev_get_priv(dev); - clrbits_le32(priv->base + GPIO_IEM, BIT(offset)); - writel(BIT(offset), priv->base + GPIO_OES); - if (value) setbits_le32(priv->base + GPIO_DOUT, BIT(offset)); else clrbits_le32(priv->base + GPIO_DOUT, BIT(offset)); + clrbits_le32(priv->base + GPIO_IEM, BIT(offset)); + writel(BIT(offset), priv->base + GPIO_OES); + return 0; } diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 05b14d2451c..5e81698143a 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -744,7 +744,6 @@ config SYS_I2C_SPEED config SYS_I2C_BUS_MAX int "Max I2C busses" depends on ARCH_OMAP2PLUS || ARCH_SOCFPGA - default 2 if TI816X default 3 if OMAP34XX || AM33XX || AM43XX default 4 if ARCH_SOCFPGA || OMAP44XX default 5 if OMAP54XX diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 1af6af82e6b..72c1076c56d 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2262,7 +2262,7 @@ static int mmc_startup_v4(struct mmc *mmc) return 0; if (!mmc->ext_csd) - memset(ext_csd_bkup, 0, sizeof(ext_csd_bkup)); + memset(ext_csd_bkup, 0, MMC_MAX_BLOCK_LEN); err = mmc_send_ext_csd(mmc, ext_csd); if (err) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index e44868aaec5..e779251ce34 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -873,7 +873,7 @@ static int arasan_sdhci_set_tapdelay(struct sdhci_host *host) if (ret) return ret; } else if (IS_ENABLED(CONFIG_ARCH_VERSAL_NET) && - device_is_compatible(dev, "xlnx,versal-net-5.1-emmc")) { + device_is_compatible(dev, "xlnx,versal-net-emmc")) { if (mmc->clock >= MIN_PHY_CLK_HZ) if (iclk_phase == VERSAL_NET_EMMC_ICLK_PHASE_DDR52_DLY_CHAIN) iclk_phase = VERSAL_NET_EMMC_ICLK_PHASE_DDR52_DLL; @@ -948,7 +948,7 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev) } if (IS_ENABLED(CONFIG_ARCH_VERSAL_NET) && - device_is_compatible(dev, "xlnx,versal-net-5.1-emmc")) { + device_is_compatible(dev, "xlnx,versal-net-emmc")) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { clk_data->clk_phase_in[i] = versal_net_emmc_iclk_phases[i]; clk_data->clk_phase_out[i] = versal_net_emmc_oclk_phases[i]; @@ -1102,7 +1102,7 @@ static int arasan_sdhci_probe(struct udevice *dev) } } #endif - if (device_is_compatible(dev, "xlnx,versal-net-5.1-emmc")) + if (device_is_compatible(dev, "xlnx,versal-net-emmc")) priv->internal_phy_reg = true; ret = clk_get_by_index(dev, 0, &clk); @@ -1136,7 +1136,7 @@ static int arasan_sdhci_probe(struct udevice *dev) host->quirks |= SDHCI_QUIRK_NO_1_8_V; if (CONFIG_IS_ENABLED(ARCH_VERSAL_NET) && - device_is_compatible(dev, "xlnx,versal-net-5.1-emmc")) + device_is_compatible(dev, "xlnx,versal-net-emmc")) host->quirks |= SDHCI_QUIRK_CAPS_BIT63_FOR_HS400; plat->cfg.f_max = CONFIG_ZYNQ_SDHCI_MAX_FREQ; @@ -1219,7 +1219,7 @@ static int arasan_sdhci_bind(struct udevice *dev) static const struct udevice_id arasan_sdhci_ids[] = { { .compatible = "arasan,sdhci-8.9a" }, - { .compatible = "xlnx,versal-net-5.1-emmc" }, + { .compatible = "xlnx,versal-net-emmc" }, { } }; diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index d115fcf841f..d624589a892 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -553,7 +553,7 @@ config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS bool "Enable use of 1st stage bootloader timing for NAND" depends on NAND_ZYNQ help - This flag prevent U-boot reconfigure NAND flash controller and reuse + This flag prevent U-Boot reconfigure NAND flash controller and reuse the NAND timing from 1st stage bootloader. config NAND_OCTEONTX @@ -732,10 +732,10 @@ config SYS_NAND_BAD_BLOCK_POS default 5 if HAS_NAND_SMALL_BADBLOCK_POS config SYS_NAND_U_BOOT_LOCATIONS - bool "Define U-boot binaries locations in NAND" + bool "Define U-Boot binaries locations in NAND" help Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig. - This option should not be enabled when compiling U-boot for boards + This option should not be enabled when compiling U-Boot for boards defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/<board>.h file. diff --git a/drivers/mtd/nand/raw/fsl_ifc_spl.c b/drivers/mtd/nand/raw/fsl_ifc_spl.c index 60a865b5667..c67065eaf8c 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_spl.c +++ b/drivers/mtd/nand/raw/fsl_ifc_spl.c @@ -275,8 +275,8 @@ void nand_boot(void) #ifdef CONFIG_CHAIN_OF_TRUST /* - * U-Boot header is appended at end of U-boot image, so - * calculate U-boot header address using U-boot header size. + * U-Boot header is appended at end of U-Boot image, so + * calculate U-Boot header address using U-Boot header size. */ #define FSL_U_BOOT_HDR_ADDR \ ((CFG_SYS_NAND_U_BOOT_START + \ diff --git a/drivers/mtd/nvmxip/nvmxip.h b/drivers/mtd/nvmxip/nvmxip.h deleted file mode 100644 index f4ef37725d2..00000000000 --- a/drivers/mtd/nvmxip/nvmxip.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com> - * - * Authors: - * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> - */ - -#ifndef __DRIVER_NVMXIP_H__ -#define __DRIVER_NVMXIP_H__ - -#include <blk.h> - -#define NVMXIP_BLKDRV_NAME "nvmxip-blk" -#define NVMXIP_BLKDEV_NAME_SZ 20 - -/** - * struct nvmxip_plat - the NVMXIP driver plat - * - * @phys_base: NVM XIP device base address - * @lba_shift: block size shift count - * @lba: number of blocks - * - * The NVMXIP information read from the DT. - */ -struct nvmxip_plat { - phys_addr_t phys_base; - u32 lba_shift; - lbaint_t lba; -}; - -#endif /* __DRIVER_NVMXIP_H__ */ diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 39eee98ca79..d662dd34989 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -696,6 +696,7 @@ config SUN8I_EMAC config SH_ETHER bool "Renesas SH Ethernet MAC" select PHYLIB + select PHY_ETHERNET_ID help This driver supports the Ethernet for Renesas SH and ARM SoCs. @@ -765,6 +766,7 @@ config RENESAS_RAVB bool "Renesas Ethernet AVB MAC" depends on RCAR_64 select PHYLIB + select PHY_ETHERNET_ID help This driver implements support for the Ethernet AVB block in Renesas M3 and H3 SoCs. diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index 912d28fca2e..e2340936fa6 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -430,17 +430,11 @@ static int tse_mdio_init(const char *name, struct altera_tse_priv *priv) static int tse_phy_init(struct altera_tse_priv *priv, void *dev) { struct phy_device *phydev; - unsigned int mask = 0xffffffff; - if (priv->phyaddr) - mask = 1 << priv->phyaddr; - - phydev = phy_find_by_mask(priv->bus, mask); + phydev = phy_connect(priv->bus, -1, dev, priv->interface); if (!phydev) return -ENODEV; - phy_connect_dev(phydev, dev, priv->interface); - phydev->supported &= PHY_GBIT_FEATURES; phydev->advertising = phydev->supported; diff --git a/drivers/net/eth-phy-uclass.c b/drivers/net/eth-phy-uclass.c index 27b77444a0c..9d1e8d38ffa 100644 --- a/drivers/net/eth-phy-uclass.c +++ b/drivers/net/eth-phy-uclass.c @@ -144,10 +144,18 @@ static int eth_phy_of_to_plat(struct udevice *dev) uc_priv->reset_assert_delay = dev_read_u32_default(dev, "reset-assert-us", 0); uc_priv->reset_deassert_delay = dev_read_u32_default(dev, "reset-deassert-us", 0); + /* These are used by some DTs, try these as a fallback. */ + if (!uc_priv->reset_assert_delay && !uc_priv->reset_deassert_delay) { + uc_priv->reset_assert_delay = + dev_read_u32_default(dev, "reset-delay-us", 0); + uc_priv->reset_deassert_delay = + dev_read_u32_default(dev, "reset-post-delay-us", 0); + } + return 0; } -void eth_phy_reset(struct udevice *dev, int value) +static void eth_phy_reset(struct udevice *dev, int value) { struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev); u32 delay; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 29067e9e949..13fad8119bb 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -608,18 +608,16 @@ static int ethoc_mdio_init(const char *name, struct ethoc *priv) static int ethoc_phy_init(struct ethoc *priv, void *dev) { struct phy_device *phydev; - int mask = 0xffffffff; + int mask = -1; #ifdef CONFIG_PHY_ADDR - mask = 1 << CONFIG_PHY_ADDR; + mask = CONFIG_PHY_ADDR; #endif - phydev = phy_find_by_mask(priv->bus, mask); + phydev = phy_connect(priv->bus, mask, dev, PHY_INTERFACE_MODE_MII); if (!phydev) return -ENODEV; - phy_connect_dev(phydev, dev, PHY_INTERFACE_MODE_MII); - phydev->supported &= PHY_BASIC_FEATURES; phydev->advertising = phydev->supported; diff --git a/drivers/net/fsl-mc/dpbp.c b/drivers/net/fsl-mc/dpbp.c index c609efb9abc..5e17ccf73d3 100644 --- a/drivers/net/fsl-mc/dpbp.c +++ b/drivers/net/fsl-mc/dpbp.c @@ -3,25 +3,40 @@ * Freescale Layerscape MC I/O wrapper * * Copyright 2013-2016 Freescale Semiconductor, Inc. - * Copyright 2017 NXP + * Copyright 2017-2023 NXP */ #include <fsl-mc/fsl_mc_sys.h> #include <fsl-mc/fsl_mc_cmd.h> #include <fsl-mc/fsl_dpbp.h> -int dpbp_open(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - int dpbp_id, - uint16_t *token) +/** + * dpbp_open() - Open a control session for the specified object. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpbp_id: DPBP unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dpbp_create function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent commands for + * this specific object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpbp_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpbp_id, u16 *token) { + struct dpbp_cmd_open *cmd_params; struct mc_command cmd = { 0 }; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_OPEN, - cmd_flags, - 0); - DPBP_CMD_OPEN(cmd, dpbp_id); + cmd_flags, 0); + cmd_params = (struct dpbp_cmd_open *)cmd.params; + cmd_params->dpbp_id = cpu_to_le32(dpbp_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -29,14 +44,23 @@ int dpbp_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return err; } -int dpbp_close(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpbp_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPBP object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpbp_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -48,11 +72,26 @@ int dpbp_close(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpbp_create(struct fsl_mc_io *mc_io, - uint16_t dprc_token, - uint32_t cmd_flags, - const struct dpbp_cfg *cfg, - uint32_t *obj_id) +/** + * dpbp_create() - Create the DPBP object. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @cfg: Configuration structure + * @obj_id: Returned object id; use in subsequent API calls + * + * Create the DPBP object, allocate required resources and + * perform required initialization. + * + * This function accepts an authentication token of a parent + * container that this object should be assigned to and returns + * an object id. This object_id will be used in all subsequent calls to + * this specific object. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpbp_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, + const struct dpbp_cfg *cfg, u32 *obj_id) { struct mc_command cmd = { 0 }; int err; @@ -61,8 +100,7 @@ int dpbp_create(struct fsl_mc_io *mc_io, /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_CREATE, - cmd_flags, - dprc_token); + cmd_flags, dprc_token); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -70,33 +108,46 @@ int dpbp_create(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - MC_CMD_READ_OBJ_ID(cmd, *obj_id); + *obj_id = mc_cmd_read_object_id(&cmd); return 0; } -int dpbp_destroy(struct fsl_mc_io *mc_io, - uint16_t dprc_token, - uint32_t cmd_flags, - uint32_t obj_id) +/** + * dpbp_destroy() - Destroy the DPBP object and release all its resources. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @obj_id: ID of DPBP object + * + * Return: '0' on Success; error code otherwise. + */ +int dpbp_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, + u32 obj_id) { + struct dpbp_cmd_destroy *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_DESTROY, - cmd_flags, - dprc_token); + cmd_flags, dprc_token); - /* set object id to destroy */ - CMD_DESTROY_SET_OBJ_ID_PARAM0(cmd, obj_id); + cmd_params = (struct dpbp_cmd_destroy *)cmd.params; + cmd_params->object_id = cpu_to_le32(obj_id); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpbp_enable(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpbp_enable() - Enable the DPBP. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPBP object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpbp_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -108,48 +159,66 @@ int dpbp_enable(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpbp_disable(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpbp_disable() - Disable the DPBP. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPBP object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpbp_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_DISABLE, - cmd_flags, - token); + cmd_flags, token); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpbp_reset(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpbp_reset() - Reset the DPBP, returns the object to initial state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPBP object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpbp_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_RESET, - cmd_flags, - token); + cmd_flags, token); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpbp_get_attributes(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dpbp_get_attributes - Retrieve DPBP attributes. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPBP object + * @attr: Returned object's attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpbp_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, struct dpbp_attr *attr) { + struct dpbp_rsp_get_attributes *rsp_params; struct mc_command cmd = { 0 }; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_ATTR, - cmd_flags, - token); + cmd_flags, token); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -157,15 +226,24 @@ int dpbp_get_attributes(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPBP_RSP_GET_ATTRIBUTES(cmd, attr); + rsp_params = (struct dpbp_rsp_get_attributes *)cmd.params; + attr->bpid = le16_to_cpu(rsp_params->bpid); + attr->id = le32_to_cpu(rsp_params->id); return 0; } -int dpbp_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) +/** + * dpbp_get_api_version - Get Data Path Buffer Pool API version + * @mc_io: Pointer to Mc portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: Major version of Buffer Pool API + * @minor_ver: Minor version of Buffer Pool API + * + * Return: '0' on Success; Error code otherwise. + */ +int dpbp_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 *major_ver, u16 *minor_ver) { struct mc_command cmd = { 0 }; int err; diff --git a/drivers/net/fsl-mc/dpio/dpio.c b/drivers/net/fsl-mc/dpio/dpio.c index 8884455963d..d17210bf451 100644 --- a/drivers/net/fsl-mc/dpio/dpio.c +++ b/drivers/net/fsl-mc/dpio/dpio.c @@ -1,18 +1,34 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2013-2016 Freescale Semiconductor, Inc. - * Copyright 2017 NXP + * Copyright 2017, 2023 NXP */ #include <fsl-mc/fsl_mc_sys.h> #include <fsl-mc/fsl_mc_cmd.h> #include <fsl-mc/fsl_dpio.h> -int dpio_open(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint32_t dpio_id, - uint16_t *token) +/** + * dpio_open() - Open a control session for the specified object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpio_id: DPIO unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dpio_create() function. + * This function returns a unique authentication token, + * associated with the specific object ID and any MC portals + * assigned to the parent container; this token must be used in + * all subsequent commands for this specific object. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpio_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpio_id, + u16 *token) { + struct dpio_cmd_open *cmd_params; struct mc_command cmd = { 0 }; int err; @@ -20,7 +36,8 @@ int dpio_open(struct fsl_mc_io *mc_io, cmd.header = mc_encode_cmd_header(DPIO_CMDID_OPEN, cmd_flags, 0); - DPIO_CMD_OPEN(cmd, dpio_id); + cmd_params = (struct dpio_cmd_open *)cmd.params; + cmd_params->dpio_id = cpu_to_le32(dpio_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -28,14 +45,20 @@ int dpio_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return 0; } -int dpio_close(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpio_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPIO object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpio_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -48,12 +71,32 @@ int dpio_close(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpio_create(struct fsl_mc_io *mc_io, - uint16_t dprc_token, - uint32_t cmd_flags, - const struct dpio_cfg *cfg, - uint32_t *obj_id) +/** + * dpio_create() - Create the DPIO object. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @cfg: Configuration structure + * @obj_id: Returned object id + * + * Create the DPIO object, allocate required resources and + * perform required initialization. + * + * The object can be created either by declaring it in the + * DPL file, or by calling this function. + * + * The function accepts an authentication token of a parent + * container that this object should be assigned to. The token + * can be '0' so the object will be assigned to the default container. + * The newly created object can be opened with the returned + * object id and using the container's associated tokens and MC portals. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpio_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, + const struct dpio_cfg *cfg, u32 *obj_id) { + struct dpio_cmd_create *cmd_params; struct mc_command cmd = { 0 }; int err; @@ -61,7 +104,11 @@ int dpio_create(struct fsl_mc_io *mc_io, cmd.header = mc_encode_cmd_header(DPIO_CMDID_CREATE, cmd_flags, dprc_token); - DPIO_CMD_CREATE(cmd, cfg); + cmd_params = (struct dpio_cmd_create *)cmd.params; + cmd_params->num_priorities = cfg->num_priorities; + dpio_set_field(cmd_params->channel_mode, + CHANNEL_MODE, + cfg->channel_mode); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -69,33 +116,54 @@ int dpio_create(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - MC_CMD_READ_OBJ_ID(cmd, *obj_id); + *obj_id = mc_cmd_read_object_id(&cmd); return 0; } -int dpio_destroy(struct fsl_mc_io *mc_io, - uint16_t dprc_token, - uint32_t cmd_flags, - uint32_t obj_id) +/** + * dpio_destroy() - Destroy the DPIO object and release all its resources. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @object_id: The object id; it must be a valid id within the container that + * created this object; + * + * The function accepts the authentication token of the parent container that + * created the object (not the one that currently owns the object). The object + * is searched within parent using the provided 'object_id'. + * All tokens to the object must be closed before calling destroy. + * + * Return: '0' on Success; Error code otherwise + */ +int dpio_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, + u32 object_id) { + struct dpio_cmd_destroy *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPIO_CMDID_DESTROY, - cmd_flags, - dprc_token); + cmd_flags, + dprc_token); /* set object id to destroy */ - CMD_DESTROY_SET_OBJ_ID_PARAM0(cmd, obj_id); + cmd_params = (struct dpio_cmd_destroy *)cmd.params; + cmd_params->dpio_id = cpu_to_le32(object_id); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpio_enable(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpio_enable() - Enable the DPIO, allow I/O portal operations. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPIO object + * + * Return: '0' on Success; Error code otherwise + */ +int dpio_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -108,9 +176,15 @@ int dpio_enable(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpio_disable(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpio_disable() - Disable the DPIO, stop any I/O portal operation. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPIO object + * + * Return: '0' on Success; Error code otherwise + */ +int dpio_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -123,26 +197,19 @@ int dpio_disable(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpio_reset(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPIO_CMDID_RESET, - cmd_flags, - token); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dpio_get_attributes(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dpio_get_attributes() - Retrieve DPIO attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPIO object + * @attr: Returned object's attributes + * + * Return: '0' on Success; Error code otherwise + */ +int dpio_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, struct dpio_attr *attr) { + struct dpio_rsp_get_attr *rsp_params; struct mc_command cmd = { 0 }; int err; @@ -157,29 +224,42 @@ int dpio_get_attributes(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPIO_RSP_GET_ATTR(cmd, attr); + rsp_params = (struct dpio_rsp_get_attr *)cmd.params; + attr->id = le32_to_cpu(rsp_params->id); + attr->qbman_portal_id = le16_to_cpu(rsp_params->qbman_portal_id); + attr->num_priorities = rsp_params->num_priorities; + attr->qbman_portal_ce_offset = le64_to_cpu(rsp_params->qbman_portal_ce_offset); + attr->qbman_portal_ci_offset = le64_to_cpu(rsp_params->qbman_portal_ci_offset); + attr->qbman_version = le32_to_cpu(rsp_params->qbman_version); + attr->clk = le32_to_cpu(rsp_params->clk); + attr->channel_mode = dpio_get_field(rsp_params->channel_mode, ATTR_CHANNEL_MODE); return 0; } -int dpio_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) +/** + * dpio_get_api_version() - Get Data Path I/O API version + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: Major version of data path i/o API + * @minor_ver: Minor version of data path i/o API + * + * Return: '0' on Success; Error code otherwise. + */ +int dpio_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 *major_ver, u16 *minor_ver) { struct mc_command cmd = { 0 }; int err; - /* prepare command */ cmd.header = mc_encode_cmd_header(DPIO_CMDID_GET_API_VERSION, - cmd_flags, 0); + cmd_flags, + 0); - /* send command to mc */ err = mc_send_command(mc_io, &cmd); if (err) return err; - /* retrieve response parameters */ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); return 0; diff --git a/drivers/net/fsl-mc/dpmac.c b/drivers/net/fsl-mc/dpmac.c index 43a2ff43f88..5d4f6c67fd0 100644 --- a/drivers/net/fsl-mc/dpmac.c +++ b/drivers/net/fsl-mc/dpmac.c @@ -11,19 +11,33 @@ #include <fsl-mc/fsl_mc_cmd.h> #include <fsl-mc/fsl_dpmac.h> -int dpmac_open(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - int dpmac_id, - uint16_t *token) +/** + * dpmac_open() - Open a control session for the specified object. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpmac_id: DPMAC unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dpmac_create function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent commands for + * this specific object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpmac_id, u16 *token) { + struct dpmac_cmd_open *cmd_params; struct mc_command cmd = { 0 }; int err; /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN, - cmd_flags, - 0); - DPMAC_CMD_OPEN(cmd, dpmac_id); + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN, cmd_flags, 0); + cmd_params = (struct dpmac_cmd_open *)cmd.params; + cmd_params->dpmac_id = cpu_to_le32(dpmac_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -31,39 +45,63 @@ int dpmac_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return err; } -int dpmac_close(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpmac_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPMAC object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags, - token); + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags, token); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpmac_create(struct fsl_mc_io *mc_io, - uint16_t dprc_token, - uint32_t cmd_flags, - const struct dpmac_cfg *cfg, - uint32_t *obj_id) +/** + * dpmac_create() - Create the DPMAC object. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @cfg: Configuration structure + * @obj_id: Returned object id + * + * Create the DPMAC object, allocate required resources and + * perform required initialization. + * + * The function accepts an authentication token of a parent + * container that this object should be assigned to. The token + * can be '0' so the object will be assigned to the default container. + * The newly created object can be opened with the returned + * object id and using the container's associated tokens and MC portals. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, + const struct dpmac_cfg *cfg, u32 *obj_id) { + struct dpmac_cmd_create *cmd_params; struct mc_command cmd = { 0 }; int err; /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CREATE, - cmd_flags, - dprc_token); - DPMAC_CMD_CREATE(cmd, cfg); + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CREATE, cmd_flags, dprc_token); + cmd_params = (struct dpmac_cmd_create *)cmd.params; + cmd_params->mac_id = cpu_to_le32(cfg->mac_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -71,142 +109,87 @@ int dpmac_create(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - MC_CMD_READ_OBJ_ID(cmd, *obj_id); + *obj_id = mc_cmd_read_object_id(&cmd); return 0; } -int dpmac_destroy(struct fsl_mc_io *mc_io, - uint16_t dprc_token, - uint32_t cmd_flags, - uint32_t obj_id) +/** + * dpmac_destroy() - Destroy the DPMAC object and release all its resources. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @object_id: The object id; it must be a valid id within the container that + * created this object; + * + * The function accepts the authentication token of the parent container that + * created the object (not the one that currently owns the object). The object + * is searched within parent using the provided 'object_id'. + * All tokens to the object must be closed before calling destroy. + * + * Return: '0' on Success; error code otherwise. + */ +int dpmac_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, + u32 object_id) { + struct dpmac_cmd_destroy *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_DESTROY, cmd_flags, dprc_token); - - /* set object id to destroy */ - CMD_DESTROY_SET_OBJ_ID_PARAM0(cmd, obj_id); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dpmac_get_attributes(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - struct dpmac_attr *attr) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_ATTR, - cmd_flags, - token); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPMAC_RSP_GET_ATTRIBUTES(cmd, attr); - - return 0; -} - -int dpmac_mdio_read(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - struct dpmac_mdio_cfg *cfg) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMAC_CMDID_MDIO_READ, - cmd_flags, - token); - DPMAC_CMD_MDIO_READ(cmd, cfg); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPMAC_RSP_MDIO_READ(cmd, cfg->data); - - return 0; -} - -int dpmac_mdio_write(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - struct dpmac_mdio_cfg *cfg) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMAC_CMDID_MDIO_WRITE, - cmd_flags, - token); - DPMAC_CMD_MDIO_WRITE(cmd, cfg); + cmd_params = (struct dpmac_cmd_destroy *)cmd.params; + cmd_params->dpmac_id = cpu_to_le32(object_id); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpmac_get_link_cfg(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - struct dpmac_link_cfg *cfg) -{ - struct mc_command cmd = { 0 }; - int err = 0; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_LINK_CFG, - cmd_flags, - token); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - DPMAC_RSP_GET_LINK_CFG(cmd, cfg); - - return 0; -} - -int dpmac_set_link_state(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dpmac_set_link_state() - Set the Ethernet link status + * @mc_io: Pointer to opaque I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPMAC object + * @link_state: Link state configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_set_link_state(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, struct dpmac_link_state *link_state) { + struct dpmac_cmd_set_link_state *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE, - cmd_flags, - token); - DPMAC_CMD_SET_LINK_STATE(cmd, link_state); + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE, cmd_flags, token); + cmd_params = (struct dpmac_cmd_set_link_state *)cmd.params; + cmd_params->options = cpu_to_le64(link_state->options); + cmd_params->rate = cpu_to_le32(link_state->rate); + cmd_params->up = dpmac_get_field(link_state->up, STATE); + dpmac_set_field(cmd_params->up, STATE_VALID, link_state->state_valid); + cmd_params->supported = cpu_to_le64(link_state->supported); + cmd_params->advertising = cpu_to_le64(link_state->advertising); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpmac_get_counter(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - enum dpmac_counter type, - uint64_t *counter) +/** + * dpmac_get_counter() - Read a specific DPMAC counter + * @mc_io: Pointer to opaque I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPMAC object + * @type: The requested counter + * @counter: Returned counter value + * + * Return: The requested counter; '0' otherwise. + */ +int dpmac_get_counter(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + enum dpmac_counter type, uint64_t *counter) { + struct dpmac_cmd_get_counter *dpmac_cmd; + struct dpmac_rsp_get_counter *dpmac_rsp; struct mc_command cmd = { 0 }; int err = 0; @@ -214,36 +197,43 @@ int dpmac_get_counter(struct fsl_mc_io *mc_io, cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_COUNTER, cmd_flags, token); - DPMAC_CMD_GET_COUNTER(cmd, type); + dpmac_cmd = (struct dpmac_cmd_get_counter *)cmd.params; + dpmac_cmd->type = type; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); if (err) return err; - DPMAC_RSP_GET_COUNTER(cmd, *counter); + dpmac_rsp = (struct dpmac_rsp_get_counter *)cmd.params; + *counter = le64_to_cpu(dpmac_rsp->counter); return 0; } -int dpmac_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) +/** + * dpmac_get_api_version() - Get Data Path MAC version + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: Major version of data path mac API + * @minor_ver: Minor version of data path mac API + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 *major_ver, u16 *minor_ver) { struct mc_command cmd = { 0 }; int err; - /* prepare command */ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_API_VERSION, - cmd_flags, 0); + cmd_flags, + 0); - /* send command to mc */ err = mc_send_command(mc_io, &cmd); if (err) return err; - /* retrieve response parameters */ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); return 0; diff --git a/drivers/net/fsl-mc/dpmng.c b/drivers/net/fsl-mc/dpmng.c index 8314243f356..147ca6da9e1 100644 --- a/drivers/net/fsl-mc/dpmng.c +++ b/drivers/net/fsl-mc/dpmng.c @@ -1,15 +1,24 @@ // SPDX-License-Identifier: GPL-2.0+ /* Copyright 2013-2015 Freescale Semiconductor Inc. + * Copyright 2023 NXP */ #include <fsl-mc/fsl_mc_sys.h> #include <fsl-mc/fsl_mc_cmd.h> #include <fsl-mc/fsl_dpmng.h> #include "fsl_dpmng_cmd.h" -int mc_get_version(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - struct mc_version *mc_ver_info) +/** + * mc_get_version() - Retrieves the Management Complex firmware + * version information + * @mc_io: Pointer to opaque I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @mc_ver_info: Returned version information structure + * + * Return: '0' on Success; Error code otherwise. + */ +int mc_get_version(struct fsl_mc_io *mc_io, uint32_t cmd_flags, struct mc_version *mc_ver_info) { + struct dpmng_rsp_get_version *rsp_params; struct mc_command cmd = { 0 }; int err; @@ -24,7 +33,10 @@ int mc_get_version(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPMNG_RSP_GET_VERSION(cmd, mc_ver_info); + rsp_params = (struct dpmng_rsp_get_version *)cmd.params; + mc_ver_info->revision = le32_to_cpu(rsp_params->revision); + mc_ver_info->major = le32_to_cpu(rsp_params->version_major); + mc_ver_info->minor = le32_to_cpu(rsp_params->version_minor); return 0; } diff --git a/drivers/net/fsl-mc/dpni.c b/drivers/net/fsl-mc/dpni.c index 5290be20c85..5b815a45a99 100644 --- a/drivers/net/fsl-mc/dpni.c +++ b/drivers/net/fsl-mc/dpni.c @@ -1,46 +1,43 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2013-2016 Freescale Semiconductor, Inc. - * Copyright 2017 NXP + * Copyright 2017, 2023 NXP */ #include <fsl-mc/fsl_mc_sys.h> #include <fsl-mc/fsl_mc_cmd.h> #include <fsl-mc/fsl_dpni.h> -int dpni_prepare_cfg(const struct dpni_cfg *cfg, - uint8_t *cfg_buf) -{ - uint64_t *params = (uint64_t *)cfg_buf; - - DPNI_PREP_CFG(params, cfg); - - return 0; -} - -int dpni_extract_cfg(struct dpni_cfg *cfg, - const uint8_t *cfg_buf) -{ - uint64_t *params = (uint64_t *)cfg_buf; - - DPNI_EXT_CFG(params, cfg); - - return 0; -} - -int dpni_open(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - int dpni_id, - uint16_t *token) +/** + * dpni_open() - Open a control session for the specified object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpni_id: DPNI unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dpni_create() function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent commands for + * this specific object. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpni_id, u16 *token) { + struct dpni_cmd_open *cmd_params; struct mc_command cmd = { 0 }; + int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_OPEN, cmd_flags, 0); - DPNI_CMD_OPEN(cmd, dpni_id); + cmd_params = (struct dpni_cmd_open *)cmd.params; + cmd_params->dpni_id = cpu_to_le32(dpni_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -48,14 +45,23 @@ int dpni_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return 0; } -int dpni_close(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpni_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -68,12 +74,32 @@ int dpni_close(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpni_create(struct fsl_mc_io *mc_io, - uint16_t dprc_token, - uint32_t cmd_flags, - const struct dpni_cfg *cfg, - uint32_t *obj_id) +/** + * dpni_create() - Create the DPNI object + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @cfg: Configuration structure + * @obj_id: Returned object id + * + * Create the DPNI object, allocate required resources and + * perform required initialization. + * + * The object can be created either by declaring it in the + * DPL file, or by calling this function. + * + * The function accepts an authentication token of a parent + * container that this object should be assigned to. The token + * can be '0' so the object will be assigned to the default container. + * The newly created object can be opened with the returned + * object id and using the container's associated tokens and MC portals. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, + const struct dpni_cfg *cfg, u32 *obj_id) { + struct dpni_cmd_create *cmd_params; struct mc_command cmd = { 0 }; int err; @@ -81,7 +107,19 @@ int dpni_create(struct fsl_mc_io *mc_io, cmd.header = mc_encode_cmd_header(DPNI_CMDID_CREATE, cmd_flags, dprc_token); - DPNI_CMD_CREATE(cmd, cfg); + cmd_params = (struct dpni_cmd_create *)cmd.params; + cmd_params->options = cpu_to_le32(cfg->options); + cmd_params->num_queues = cfg->num_queues; + cmd_params->num_tcs = cfg->num_tcs; + cmd_params->mac_filter_entries = cfg->mac_filter_entries; + cmd_params->num_rx_tcs = cfg->num_rx_tcs; + cmd_params->vlan_filter_entries = cfg->vlan_filter_entries; + cmd_params->qos_entries = cfg->qos_entries; + cmd_params->fs_entries = cpu_to_le16(cfg->fs_entries); + cmd_params->num_cgs = cfg->num_cgs; + cmd_params->num_opr = cfg->num_opr; + cmd_params->dist_key_size = cfg->dist_key_size; + cmd_params->num_channels = cfg->num_channels; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -89,50 +127,94 @@ int dpni_create(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - MC_CMD_READ_OBJ_ID(cmd, *obj_id); + *obj_id = mc_cmd_read_object_id(&cmd); return 0; } -int dpni_destroy(struct fsl_mc_io *mc_io, - uint16_t dprc_token, - uint32_t cmd_flags, - uint32_t obj_id) +/** + * dpni_destroy() - Destroy the DPNI object and release all its resources. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @object_id: The object id; it must be a valid id within the container that + * created this object; + * + * The function accepts the authentication token of the parent container that + * created the object (not the one that currently owns the object). The object + * is searched within parent using the provided 'object_id'. + * All tokens to the object must be closed before calling destroy. + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, + u32 object_id) { + struct dpni_cmd_destroy *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_DESTROY, cmd_flags, dprc_token); - /* set object id to destroy */ - CMD_DESTROY_SET_OBJ_ID_PARAM0(cmd, obj_id); + cmd_params = (struct dpni_cmd_destroy *)cmd.params; + cmd_params->dpni_id = cpu_to_le32(object_id); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpni_set_pools(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dpni_set_pools() - Set buffer pools configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Buffer pools configuration + * + * mandatory for DPNI operation + * warning:Allowed only when DPNI is disabled + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_pools(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, const struct dpni_pools_cfg *cfg) { struct mc_command cmd = { 0 }; + struct dpni_cmd_set_pools *cmd_params; + int i; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_POOLS, cmd_flags, token); - DPNI_CMD_SET_POOLS(cmd, cfg); + cmd_params = (struct dpni_cmd_set_pools *)cmd.params; + cmd_params->num_dpbp = cfg->num_dpbp; + cmd_params->pool_options = cfg->pool_options; + for (i = 0; i < DPNI_MAX_DPBP; i++) { + cmd_params->pool[i].dpbp_id = + cpu_to_le16(cfg->pools[i].dpbp_id); + cmd_params->pool[i].priority_mask = + cfg->pools[i].priority_mask; + cmd_params->buffer_size[i] = + cpu_to_le16(cfg->pools[i].buffer_size); + cmd_params->backup_pool_mask |= + DPNI_BACKUP_POOL(cfg->pools[i].backup_pool, i); + } /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpni_enable(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpni_enable() - Enable the DPNI, allow sending and receiving frames. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -145,9 +227,15 @@ int dpni_enable(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpni_disable(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpni_disable() - Disable the DPNI, stop sending and receiving frames. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -160,9 +248,15 @@ int dpni_disable(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpni_reset(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dpni_reset() - Reset the DPNI, returns the object to initial state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -175,76 +269,121 @@ int dpni_reset(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpni_get_attributes(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dpni_get_attributes() - Retrieve DPNI attributes. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @attr: Object's attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, struct dpni_attr *attr) { struct mc_command cmd = { 0 }; + struct dpni_rsp_get_attr *rsp_params; + int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_ATTR, cmd_flags, token); + /* send command to mc*/ err = mc_send_command(mc_io, &cmd); if (err) return err; /* retrieve response parameters */ - DPNI_RSP_GET_ATTR(cmd, attr); + rsp_params = (struct dpni_rsp_get_attr *)cmd.params; + attr->options = le32_to_cpu(rsp_params->options); + attr->num_queues = rsp_params->num_queues; + attr->num_rx_tcs = rsp_params->num_rx_tcs; + attr->num_tx_tcs = rsp_params->num_tx_tcs; + attr->mac_filter_entries = rsp_params->mac_filter_entries; + attr->vlan_filter_entries = rsp_params->vlan_filter_entries; + attr->num_channels = rsp_params->num_channels; + attr->qos_entries = rsp_params->qos_entries; + attr->fs_entries = le16_to_cpu(rsp_params->fs_entries); + attr->num_opr = le16_to_cpu(rsp_params->num_opr); + attr->qos_key_size = rsp_params->qos_key_size; + attr->fs_key_size = rsp_params->fs_key_size; + attr->wriop_version = le16_to_cpu(rsp_params->wriop_version); + attr->num_cgs = rsp_params->num_cgs; return 0; } -int dpni_set_errors_behavior(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - struct dpni_error_cfg *cfg) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_ERRORS_BEHAVIOR, - cmd_flags, - token); - DPNI_CMD_SET_ERRORS_BEHAVIOR(cmd, cfg); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dpni_set_buffer_layout(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - const struct dpni_buffer_layout *layout, - enum dpni_queue_type type) +/** + * dpni_set_buffer_layout() - Set buffer layout configuration. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @qtype: Type of queue this configuration applies to + * @layout: Buffer layout configuration + * + * Return: '0' on Success; Error code otherwise. + * + * @warning Allowed only when DPNI is disabled + */ +int dpni_set_buffer_layout(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + enum dpni_queue_type qtype, + const struct dpni_buffer_layout *layout) { + struct dpni_cmd_set_buffer_layout *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_BUFFER_LAYOUT, cmd_flags, token); - DPNI_CMD_SET_BUFFER_LAYOUT(cmd, layout, type); + cmd_params = (struct dpni_cmd_set_buffer_layout *)cmd.params; + cmd_params->qtype = qtype; + cmd_params->options = cpu_to_le16((u16)layout->options); + dpni_set_field(cmd_params->flags, PASS_TS, layout->pass_timestamp); + dpni_set_field(cmd_params->flags, PASS_PR, layout->pass_parser_result); + dpni_set_field(cmd_params->flags, PASS_FS, layout->pass_frame_status); + dpni_set_field(cmd_params->flags, PASS_SWO, layout->pass_sw_opaque); + cmd_params->private_data_size = cpu_to_le16(layout->private_data_size); + cmd_params->data_align = cpu_to_le16(layout->data_align); + cmd_params->head_room = cpu_to_le16(layout->data_head_room); + cmd_params->tail_room = cpu_to_le16(layout->data_tail_room); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpni_get_qdid(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - uint16_t *qdid) +/** + * dpni_get_qdid() - Get the Queuing Destination ID (QDID) that should be used + * for enqueue operations + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @qtype: Type of queue to receive QDID for + * @qdid: Returned virtual QDID value that should be used as an argument + * in all enqueue operations + * + * Return: '0' on Success; Error code otherwise. + * + * If dpni object is created using multiple Tc channels this function will return + * qdid value for the first channel + */ +int dpni_get_qdid(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + enum dpni_queue_type qtype, u16 *qdid) { struct mc_command cmd = { 0 }; + struct dpni_cmd_get_qdid *cmd_params; + struct dpni_rsp_get_qdid *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QDID, cmd_flags, token); + cmd_params = (struct dpni_cmd_get_qdid *)cmd.params; + cmd_params->qtype = qtype; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -252,17 +391,26 @@ int dpni_get_qdid(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPNI_RSP_GET_QDID(cmd, *qdid); + rsp_params = (struct dpni_rsp_get_qdid *)cmd.params; + *qdid = le16_to_cpu(rsp_params->qdid); return 0; } -int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - uint16_t *data_offset) +/** + * dpni_get_tx_data_offset() - Get the Tx data offset (from start of buffer) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @data_offset: Tx data offset (from start of buffer) + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u16 *data_offset) { struct mc_command cmd = { 0 }; + struct dpni_rsp_get_tx_data_offset *rsp_params; int err; /* prepare command */ @@ -276,34 +424,54 @@ int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPNI_RSP_GET_TX_DATA_OFFSET(cmd, *data_offset); + rsp_params = (struct dpni_rsp_get_tx_data_offset *)cmd.params; + *data_offset = le16_to_cpu(rsp_params->data_offset); return 0; } -int dpni_set_link_cfg(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dpni_set_link_cfg() - set the link configuration. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Link configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_link_cfg(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, const struct dpni_link_cfg *cfg) { struct mc_command cmd = { 0 }; + struct dpni_cmd_set_link_cfg *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG, cmd_flags, token); - DPNI_CMD_SET_LINK_CFG(cmd, cfg); + cmd_params = (struct dpni_cmd_set_link_cfg *)cmd.params; + cmd_params->rate = cpu_to_le32(cfg->rate); + cmd_params->options = cpu_to_le64(cfg->options); + cmd_params->advertising = cpu_to_le64(cfg->advertising); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpni_get_link_state(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dpni_get_link_state() - Return the link state (either up or down) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @state: Returned link state; + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_link_state(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, struct dpni_link_state *state) { struct mc_command cmd = { 0 }; + struct dpni_rsp_get_link_state *rsp_params; int err; /* prepare command */ @@ -317,211 +485,279 @@ int dpni_get_link_state(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPNI_RSP_GET_LINK_STATE(cmd, state); - - return 0; -} - - -int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - const uint8_t mac_addr[6]) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_PRIM_MAC, - cmd_flags, - token); - DPNI_CMD_SET_PRIMARY_MAC_ADDR(cmd, mac_addr); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - uint8_t mac_addr[6]) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PRIM_MAC, - cmd_flags, - token); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPNI_RSP_GET_PRIMARY_MAC_ADDR(cmd, mac_addr); + rsp_params = (struct dpni_rsp_get_link_state *)cmd.params; + state->up = dpni_get_field(rsp_params->flags, LINK_STATE); + state->state_valid = dpni_get_field(rsp_params->flags, STATE_VALID); + state->rate = le32_to_cpu(rsp_params->rate); + state->options = le64_to_cpu(rsp_params->options); + state->supported = le64_to_cpu(rsp_params->supported); + state->advertising = le64_to_cpu(rsp_params->advertising); return 0; } -int dpni_add_mac_addr(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - const uint8_t mac_addr[6]) +/** + * dpni_add_mac_addr() - Add MAC address filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mac_addr: MAC address to add + * @flags :0 - tc_id and flow_id will be ignored. + * Pkt with this mac_id will be passed to the next + * classification stages + * DPNI_MAC_SET_QUEUE_ACTION + * Pkt with this mac will be forward directly to + * queue defined by the tc_id and flow_id + * @tc_id : Traffic class selection (0-7) + * @flow_id : Selects the specific queue out of the set allocated for the + * same as tc_id. Value must be in range 0 to NUM_QUEUES - 1 + * Return: '0' on Success; Error code otherwise. + */ +int dpni_add_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + const u8 mac_addr[6], u8 flags, + u8 tc_id, u8 flow_id) { + struct dpni_cmd_add_mac_addr *cmd_params; struct mc_command cmd = { 0 }; + int i; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_MAC_ADDR, cmd_flags, token); - DPNI_CMD_ADD_MAC_ADDR(cmd, mac_addr); + cmd_params = (struct dpni_cmd_add_mac_addr *)cmd.params; + cmd_params->flags = flags; + cmd_params->tc_id = tc_id; + cmd_params->fq_id = flow_id; - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - const uint8_t mac_addr[6]) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_MAC_ADDR, - cmd_flags, - token); - DPNI_CMD_REMOVE_MAC_ADDR(cmd, mac_addr); + for (i = 0; i < 6; i++) + cmd_params->mac_addr[i] = mac_addr[5 - i]; /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpni_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) +/** + * dpni_get_api_version() - Get Data Path Network Interface API version + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: Major version of data path network interface API + * @minor_ver: Minor version of data path network interface API + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 *major_ver, u16 *minor_ver) { struct mc_command cmd = { 0 }; int err; - /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_API_VERSION, - cmd_flags, 0); + cmd_flags, + 0); - /* send command to mc */ err = mc_send_command(mc_io, &cmd); if (err) return err; - /* retrieve response parameters */ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); return 0; } -int dpni_set_queue(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - enum dpni_queue_type type, - uint8_t tc, - uint8_t index, - const struct dpni_queue *queue) +/** + * dpni_set_queue() - Set queue parameters + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @qtype: Type of queue - all queue types are supported, although + * the command is ignored for Tx + * @tc: Traffic class, in range 0 to NUM_TCS - 1 + * @index: Selects the specific queue out of the set allocated for the + * same TC. Value must be in range 0 to NUM_QUEUES - 1 + * @options: A combination of DPNI_QUEUE_OPT_ values that control what + * configuration options are set on the queue + * @queue: Queue structure + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + enum dpni_queue_type qtype, u16 param, u8 index, + u8 options, const struct dpni_queue *queue) { struct mc_command cmd = { 0 }; + struct dpni_cmd_set_queue *cmd_params; + /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_QUEUE, cmd_flags, token); - DPNI_CMD_SET_QUEUE(cmd, type, tc, index, queue); + cmd_params = (struct dpni_cmd_set_queue *)cmd.params; + cmd_params->qtype = qtype; + cmd_params->tc = (u8)(param & 0xff); + cmd_params->channel_id = (u8)((param >> 8) & 0xff); + cmd_params->index = index; + cmd_params->options = options; + cmd_params->dest_id = cpu_to_le32(queue->destination.id); + cmd_params->dest_prio = queue->destination.priority; + dpni_set_field(cmd_params->flags, DEST_TYPE, queue->destination.type); + dpni_set_field(cmd_params->flags, STASH_CTRL, queue->flc.stash_control); + dpni_set_field(cmd_params->flags, HOLD_ACTIVE, + queue->destination.hold_active); + cmd_params->flc = cpu_to_le64(queue->flc.value); + cmd_params->user_context = cpu_to_le64(queue->user_context); + cmd_params->cgid = queue->cgid; - /* send command to mc*/ + /* send command to mc */ return mc_send_command(mc_io, &cmd); } -int dpni_get_queue(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - enum dpni_queue_type type, - uint8_t tc, - uint8_t index, - struct dpni_queue *queue) +/** + * dpni_get_queue() - Get queue parameters + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @qtype: Type of queue - all queue types are supported + * @param: Traffic class and channel ID. + * MSB - channel id; used only for DPNI_QUEUE_TX and + * DPNI_QUEUE_TX_CONFIRM, ignored for the rest + * LSB - traffic class + * Use macro DPNI_BUILD_PARAM() to build correct value. + * If dpni uses a single channel (uses only channel zero) + * the parameter can receive traffic class directly. + * @index: Selects the specific queue out of the set allocated for the + * same TC. Value must be in range 0 to NUM_QUEUES - 1 + * @queue: Queue configuration structure + * @qid: Queue identification + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + enum dpni_queue_type qtype, u16 param, u8 index, + struct dpni_queue *queue, struct dpni_queue_id *qid) { struct mc_command cmd = { 0 }; + struct dpni_cmd_get_queue *cmd_params; + struct dpni_rsp_get_queue *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QUEUE, cmd_flags, token); - DPNI_CMD_GET_QUEUE(cmd, type, tc, index); + cmd_params = (struct dpni_cmd_get_queue *)cmd.params; + cmd_params->qtype = qtype; + cmd_params->tc = (u8)(param & 0xff); + cmd_params->index = index; + cmd_params->channel_id = (u8)((param >> 8) & 0xff); - /* send command to mc*/ + /* send command to mc */ err = mc_send_command(mc_io, &cmd); if (err) return err; /* retrieve response parameters */ - DPNI_RSP_GET_QUEUE(cmd, queue); + rsp_params = (struct dpni_rsp_get_queue *)cmd.params; + queue->destination.id = le32_to_cpu(rsp_params->dest_id); + queue->destination.priority = rsp_params->dest_prio; + queue->destination.type = dpni_get_field(rsp_params->flags, DEST_TYPE); + queue->flc.stash_control = dpni_get_field(rsp_params->flags, STASH_CTRL); + queue->destination.hold_active = dpni_get_field(rsp_params->flags, HOLD_ACTIVE); + queue->flc.value = le64_to_cpu(rsp_params->flc); + queue->user_context = le64_to_cpu(rsp_params->user_context); + qid->fqid = le32_to_cpu(rsp_params->fqid); + qid->qdbin = le16_to_cpu(rsp_params->qdbin); + if (dpni_get_field(rsp_params->flags, CGID_VALID)) + queue->cgid = rsp_params->cgid; + else + queue->cgid = -1; + return 0; } -int dpni_set_tx_confirmation_mode(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - enum dpni_confirmation_mode mode) +/** + * dpni_set_tx_confirmation_mode() - Tx confirmation mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @ceetm_ch_idx: ceetm channel index + * @mode: Tx confirmation mode + * + * This function is useful only when 'DPNI_OPT_TX_CONF_DISABLED' is not + * selected at DPNI creation. + * Calling this function with 'mode' set to DPNI_CONF_DISABLE disables all + * transmit confirmation (including the private confirmation queues), regardless + * of previous settings; Note that in this case, Tx error frames are still + * enqueued to the general transmit errors queue. + * Calling this function with 'mode' set to DPNI_CONF_SINGLE switches all + * Tx confirmations to a shared Tx conf queue. 'index' field in dpni_get_queue + * command will be ignored. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_tx_confirmation_mode(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u8 ceetm_ch_idx, enum dpni_confirmation_mode mode) { struct dpni_tx_confirmation_mode *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONFIRMATION_MODE, - cmd_flags, - token); - + cmd_flags, token); cmd_params = (struct dpni_tx_confirmation_mode *)cmd.params; + cmd_params->ceetm_ch_idx = ceetm_ch_idx; cmd_params->confirmation_mode = mode; /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpni_get_statistics(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - uint8_t page, - struct dpni_statistics *stat) +/** + * dpni_get_statistics() - Get DPNI statistics + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @page: Selects the statistics page to retrieve, see + * DPNI_GET_STATISTICS output. Pages are numbered 0 to 6. + * @param: Custom parameter for some pages used to select + * a certain statistic source, for example the TC. + * - page_0: not used + * - page_1: not used + * - page_2: not used + * - page_3: high_byte - channel_id, low_byte - traffic class + * - page_4: high_byte - queue_index have meaning only if dpni is + * created using option DPNI_OPT_CUSTOM_CG, low_byte - traffic class + * - page_5: not used + * - page_6: not used + * @stat: Structure containing the statistics + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_statistics(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u8 page, u16 param, union dpni_statistics *stat) { + struct dpni_cmd_get_statistics *cmd_params; + struct dpni_rsp_get_statistics *rsp_params; struct mc_command cmd = { 0 }; - int err; + int i, err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_STATISTICS, - cmd_flags, token); - DPNI_CMD_GET_STATISTICS(cmd, page); + cmd_flags, + token); + cmd_params = (struct dpni_cmd_get_statistics *)cmd.params; + cmd_params->page_number = page; + cmd_params->param = param; - /* send command to mc*/ + /* send command to mc */ err = mc_send_command(mc_io, &cmd); if (err) return err; /* retrieve response parameters */ - DPNI_RSP_GET_STATISTICS(cmd, stat); + rsp_params = (struct dpni_rsp_get_statistics *)cmd.params; + for (i = 0; i < DPNI_STATISTICS_CNT; i++) + stat->raw.counter[i] = le64_to_cpu(rsp_params->counter[i]); return 0; } - -int dpni_reset_statistics(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET_STATISTICS, - cmd_flags, token); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} diff --git a/drivers/net/fsl-mc/dprc.c b/drivers/net/fsl-mc/dprc.c index e0a2865ab8f..d1a74ab47a9 100644 --- a/drivers/net/fsl-mc/dprc.c +++ b/drivers/net/fsl-mc/dprc.c @@ -3,16 +3,22 @@ * Freescale Layerscape MC I/O wrapper * * Copyright 2013-2016 Freescale Semiconductor, Inc. - * Copyright 2017 NXP + * Copyright 2017, 2023 NXP */ #include <fsl-mc/fsl_mc_sys.h> #include <fsl-mc/fsl_mc_cmd.h> #include <fsl-mc/fsl_dprc.h> -int dprc_get_container_id(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - int *container_id) +/** + * dprc_get_container_id - Get container ID associated with a given portal. + * @mc_io: Pointer to Mc portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @container_id: Requested container id + * + * Return: '0' on Success; Error code otherwise. + */ +int dprc_get_container_id(struct fsl_mc_io *mc_io, u32 cmd_flags, int *container_id) { struct mc_command cmd = { 0 }; int err; @@ -28,23 +34,33 @@ int dprc_get_container_id(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPRC_RSP_GET_CONTAINER_ID(cmd, *container_id); + *container_id = (int)mc_cmd_read_object_id(&cmd); return 0; } -int dprc_open(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - int container_id, - uint16_t *token) +/** + * dprc_open() - Open DPRC object for use + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @container_id: Container ID to open + * @token: Returned token of DPRC object + * + * Return: '0' on Success; Error code otherwise. + * + * @warning Required before any operation on the object. + */ +int dprc_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int container_id, u16 *token) { + struct dprc_cmd_open *cmd_params; struct mc_command cmd = { 0 }; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_OPEN, cmd_flags, 0); - DPRC_CMD_OPEN(cmd, container_id); + cmd_params = (struct dprc_cmd_open *)cmd.params; + cmd_params->container_id = cpu_to_le32(container_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -52,14 +68,23 @@ int dprc_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return 0; } -int dprc_close(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token) +/** + * dprc_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRC object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprc_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -71,22 +96,35 @@ int dprc_close(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dprc_create_container(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - struct dprc_cfg *cfg, - int *child_container_id, - uint64_t *child_portal_paddr) +/** + * dprc_create_container() - Create child container + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRC object + * @cfg: Child container configuration + * @child_container_id: Returned child container ID + * @child_portal_offset:Returned child portal offset from MC portal base + * + * Return: '0' on Success; Error code otherwise. + */ +int dprc_create_container(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + struct dprc_cfg *cfg, int *child_container_id, + uint64_t *child_portal_offset) { + struct dprc_cmd_create_container *cmd_params; + struct dprc_rsp_create_container *rsp_params; struct mc_command cmd = { 0 }; - int err; + int err, i; /* prepare command */ - DPRC_CMD_CREATE_CONTAINER(cmd, cfg); - cmd.header = mc_encode_cmd_header(DPRC_CMDID_CREATE_CONT, - cmd_flags, - token); + cmd_flags, token); + cmd_params = (struct dprc_cmd_create_container *)cmd.params; + cmd_params->options = cpu_to_le32(cfg->options); + cmd_params->icid = cpu_to_le32(cfg->icid); + cmd_params->portal_id = cpu_to_le32(cfg->portal_id); + for (i = 0; i < 16; i++) + cmd_params->label[i] = cfg->label[i]; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -94,253 +132,156 @@ int dprc_create_container(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPRC_RSP_CREATE_CONTAINER(cmd, *child_container_id, - *child_portal_paddr); + rsp_params = (struct dprc_rsp_create_container *)cmd.params; + *child_container_id = le32_to_cpu(rsp_params->child_container_id); + *child_portal_offset = le64_to_cpu(rsp_params->child_portal_addr); return 0; } -int dprc_destroy_container(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dprc_destroy_container() - Destroy child container. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRC object + * @child_container_id: ID of the container to destroy + * + * This function terminates the child container, so following this call the + * child container ID becomes invalid. + * + * Notes: + * - All resources and objects of the destroyed container are returned to the + * parent container or destroyed if were created be the destroyed container. + * - This function destroy all the child containers of the specified + * container prior to destroying the container itself. + * + * warning: Only the parent container is allowed to destroy a child policy + * Container 0 can't be destroyed + * + * Return: '0' on Success; Error code otherwise. + * + */ +int dprc_destroy_container(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, int child_container_id) { + struct dprc_cmd_destroy_container *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_DESTROY_CONT, - cmd_flags, - token); - DPRC_CMD_DESTROY_CONTAINER(cmd, child_container_id); + cmd_flags, token); + cmd_params = (struct dprc_cmd_destroy_container *)cmd.params; + cmd_params->child_container_id = cpu_to_le32(child_container_id); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dprc_reset_container(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - int child_container_id) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_RESET_CONT, - cmd_flags, - token); - DPRC_CMD_RESET_CONTAINER(cmd, child_container_id); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dprc_get_attributes(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - struct dprc_attributes *attr) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_ATTR, - cmd_flags, - token); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPRC_RSP_GET_ATTRIBUTES(cmd, attr); - - return 0; -} - -int dprc_get_obj_count(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - int *obj_count) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_COUNT, - cmd_flags, - token); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPRC_RSP_GET_OBJ_COUNT(cmd, *obj_count); - - return 0; -} - -int dprc_get_obj(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - int obj_index, - struct dprc_obj_desc *obj_desc) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ, - cmd_flags, - token); - DPRC_CMD_GET_OBJ(cmd, obj_index); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPRC_RSP_GET_OBJ(cmd, obj_desc); - - return 0; -} - -int dprc_get_res_count(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - char *type, - int *res_count) -{ - struct mc_command cmd = { 0 }; - int err; - - *res_count = 0; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_COUNT, - cmd_flags, - token); - DPRC_CMD_GET_RES_COUNT(cmd, type); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPRC_RSP_GET_RES_COUNT(cmd, *res_count); - - return 0; -} - -int dprc_get_res_ids(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - char *type, - struct dprc_res_ids_range_desc *range_desc) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_IDS, - cmd_flags, - token); - DPRC_CMD_GET_RES_IDS(cmd, range_desc, type); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPRC_RSP_GET_RES_IDS(cmd, range_desc); - - return 0; -} - -int dprc_get_obj_region(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, - char *obj_type, - int obj_id, - uint8_t region_index, - struct dprc_region_desc *region_desc) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, - cmd_flags, - token); - DPRC_CMD_GET_OBJ_REGION(cmd, obj_type, obj_id, region_index); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - DPRC_RSP_GET_OBJ_REGION(cmd, region_desc); - - return 0; -} - -int dprc_connect(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dprc_connect() - Connect two endpoints to create a network link between them + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRC object + * @endpoint1: Endpoint 1 configuration parameters + * @endpoint2: Endpoint 2 configuration parameters + * @cfg: Connection configuration. The connection configuration + * is ignored for connections made to DPMAC objects, where + * rate is retrieved from the MAC configuration. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprc_connect(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, const struct dprc_endpoint *endpoint1, const struct dprc_endpoint *endpoint2, const struct dprc_connection_cfg *cfg) { + struct dprc_cmd_connect *cmd_params; struct mc_command cmd = { 0 }; + int i; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CONNECT, cmd_flags, token); - DPRC_CMD_CONNECT(cmd, endpoint1, endpoint2, cfg); + cmd_params = (struct dprc_cmd_connect *)cmd.params; + cmd_params->ep1_id = cpu_to_le32(endpoint1->id); + cmd_params->ep1_interface_id = cpu_to_le16(endpoint1->if_id); + cmd_params->ep2_id = cpu_to_le32(endpoint2->id); + cmd_params->ep2_interface_id = cpu_to_le16(endpoint2->if_id); + cmd_params->max_rate = cpu_to_le32(cfg->max_rate); + cmd_params->committed_rate = cpu_to_le32(cfg->committed_rate); + for (i = 0; i < 16; i++) { + cmd_params->ep1_type[i] = endpoint1->type[i]; + cmd_params->ep2_type[i] = endpoint2->type[i]; + } /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dprc_disconnect(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dprc_disconnect() - Disconnect one endpoint to remove its network connection + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRC object + * @endpoint: Endpoint configuration parameters + * + * Return: '0' on Success; Error code otherwise. + */ +int dprc_disconnect(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, const struct dprc_endpoint *endpoint) { + struct dprc_cmd_disconnect *cmd_params; struct mc_command cmd = { 0 }; + int i; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_DISCONNECT, cmd_flags, token); - DPRC_CMD_DISCONNECT(cmd, endpoint); + cmd_params = (struct dprc_cmd_disconnect *)cmd.params; + cmd_params->id = cpu_to_le32(endpoint->id); + cmd_params->interface_id = cpu_to_le32(endpoint->if_id); + for (i = 0; i < 16; i++) + cmd_params->type[i] = endpoint->type[i]; /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dprc_get_connection(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token, +/** + * dprc_get_connection() - Get connected endpoint and link status if connection + * exists. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRC object + * @endpoint1: Endpoint 1 configuration parameters + * @endpoint2: Returned endpoint 2 configuration parameters + * @state: Returned link state: + * 1 - link is up; + * 0 - link is down; + * -1 - no connection (endpoint2 information is irrelevant) + * + * Return: '0' on Success; -ENAVAIL if connection does not exist. + */ +int dprc_get_connection(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, const struct dprc_endpoint *endpoint1, - struct dprc_endpoint *endpoint2, - int *state) + struct dprc_endpoint *endpoint2, int *state) { + struct dprc_cmd_get_connection *cmd_params; + struct dprc_rsp_get_connection *rsp_params; struct mc_command cmd = { 0 }; - int err; + int err, i; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION, cmd_flags, token); - DPRC_CMD_GET_CONNECTION(cmd, endpoint1); + cmd_params = (struct dprc_cmd_get_connection *)cmd.params; + cmd_params->ep1_id = cpu_to_le32(endpoint1->id); + cmd_params->ep1_interface_id = cpu_to_le16(endpoint1->if_id); + for (i = 0; i < 16; i++) + cmd_params->ep1_type[i] = endpoint1->type[i]; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -348,15 +289,27 @@ int dprc_get_connection(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - DPRC_RSP_GET_CONNECTION(cmd, endpoint2, *state); + rsp_params = (struct dprc_rsp_get_connection *)cmd.params; + endpoint2->id = le32_to_cpu(rsp_params->ep2_id); + endpoint2->if_id = le16_to_cpu(rsp_params->ep2_interface_id); + *state = le32_to_cpu(rsp_params->state); + for (i = 0; i < 16; i++) + endpoint2->type[i] = rsp_params->ep2_type[i]; return 0; } -int dprc_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) +/** + * dprc_get_api_version - Get Data Path Resource Container API version + * @mc_io: Pointer to Mc portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: Major version of Data Path Resource Container API + * @minor_ver: Minor version of Data Path Resource Container API + * + * Return: '0' on Success; Error code otherwise. + */ +int dprc_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 *major_ver, u16 *minor_ver) { struct mc_command cmd = { 0 }; int err; diff --git a/drivers/net/fsl-mc/dpsparser.c b/drivers/net/fsl-mc/dpsparser.c index cfd1ba66a05..09dfb8f1fc0 100644 --- a/drivers/net/fsl-mc/dpsparser.c +++ b/drivers/net/fsl-mc/dpsparser.c @@ -2,15 +2,29 @@ /* * Data Path Soft Parser * - * Copyright 2018 NXP + * Copyright 2018, 2023 NXP */ #include <fsl-mc/fsl_mc_sys.h> #include <fsl-mc/fsl_mc_cmd.h> #include <fsl-mc/fsl_dpsparser.h> -int dpsparser_open(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *token) +/** + * dpsparser_open() - Open a control session for the specified object. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dpsparser_create function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent commands for + * this specific object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsparser_open(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 *token) { struct mc_command cmd = { 0 }; int err; @@ -26,14 +40,23 @@ int dpsparser_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return err; } -int dpsparser_close(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token) +/** + * dpsparser_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSPARSER object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsparser_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { struct mc_command cmd = { 0 }; @@ -45,9 +68,27 @@ int dpsparser_close(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -int dpsparser_create(struct fsl_mc_io *mc_io, - u16 token, - u32 cmd_flags, +/** + * dpsparser_create() - Create the DPSPARSER object. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Returned token; use in subsequent API calls + * + * Create the DPSPARSER object, allocate required resources and + * perform required initialization. + * + * The object can be created either by declaring it in the + * DPL file, or by calling this function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent calls to + * this specific object. For objects that are created using the + * DPL file, call dpsparser_open function to get an authentication + * token first. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsparser_create(struct fsl_mc_io *mc_io, u16 token, u32 cmd_flags, u32 *obj_id) { struct mc_command cmd = { 0 }; @@ -64,36 +105,51 @@ int dpsparser_create(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - MC_CMD_READ_OBJ_ID(cmd, *obj_id); + *obj_id = mc_cmd_read_object_id(&cmd); return 0; } -int dpsparser_destroy(struct fsl_mc_io *mc_io, - u16 token, - u32 cmd_flags, +/** + * dpsparser_destroy() - Destroy the DPSPARSER object and release all its resources. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSPARSER object + * + * Return: '0' on Success; error code otherwise. + */ +int dpsparser_destroy(struct fsl_mc_io *mc_io, u16 token, u32 cmd_flags, u32 obj_id) { + struct dpsparser_cmd_destroy *cmd_params; struct mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPSPARSER_CMDID_DESTROY, cmd_flags, token); - - /* set object id to destroy */ - CMD_DESTROY_SET_OBJ_ID_PARAM0(cmd, obj_id); + cmd_params = (struct dpsparser_cmd_destroy *)cmd.params; + cmd_params->dpsparser_id = cpu_to_le32(obj_id); /* send command to mc*/ return mc_send_command(mc_io, &cmd); } -int dpsparser_apply_spb(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u64 blob_addr, - u16 *error) +/** + * dpsparser_apply_spb() - Applies the Soft Parser Blob loaded at specified address. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSPARSER object + * @blob_addr: Blob loading address + * @error: Error reported by MC related to SP Blob parsing and apply + * + * Return: '0' on Success; error code otherwise. + */ +int dpsparser_apply_spb(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u64 blob_addr, u16 *error) { + struct dpsparser_rsp_blob_report_error *rsp_params; + struct dpsparser_cmd_blob_set_address *cmd_params; struct mc_command cmd = { 0 }; int err; @@ -101,7 +157,8 @@ int dpsparser_apply_spb(struct fsl_mc_io *mc_io, cmd.header = mc_encode_cmd_header(DPSPARSER_CMDID_APPLY_SPB, cmd_flags, token); - DPSPARSER_CMD_BLOB_SET_ADDR(cmd, blob_addr); + cmd_params = (struct dpsparser_cmd_blob_set_address *)cmd.params; + cmd_params->blob_addr = cpu_to_le64(blob_addr); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -109,15 +166,24 @@ int dpsparser_apply_spb(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters: MC error code */ - DPSPARSER_CMD_BLOB_REPORT_ERROR(cmd, *error); + rsp_params = (struct dpsparser_rsp_blob_report_error *)cmd.params; + *error = le16_to_cpu(rsp_params->error); return 0; } -int dpsparser_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) +/** + * dpsparser_get_api_version - Retrieve DPSPARSER Major and Minor version info. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: DPSPARSER major version + * @minor_ver: DPSPARSER minor version + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsparser_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 *major_ver, u16 *minor_ver) { struct mc_command cmd = { 0 }; int err; diff --git a/drivers/net/fsl-mc/fsl_dpmng_cmd.h b/drivers/net/fsl-mc/fsl_dpmng_cmd.h index e18c88da097..e6efceab7ac 100644 --- a/drivers/net/fsl-mc/fsl_dpmng_cmd.h +++ b/drivers/net/fsl-mc/fsl_dpmng_cmd.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* Copyright 2013-2016 Freescale Semiconductor, Inc. - * Copyright 2017 NXP + * Copyright 2017, 2023 NXP */ #ifndef __FSL_DPMNG_CMD_H #define __FSL_DPMNG_CMD_H @@ -8,12 +8,13 @@ /* Command IDs */ #define DPMNG_CMDID_GET_VERSION 0x8311 -/* cmd, param, offset, width, type, arg_name */ -#define DPMNG_RSP_GET_VERSION(cmd, mc_ver_info) \ -do { \ - MC_RSP_OP(cmd, 0, 0, 32, uint32_t, mc_ver_info->revision); \ - MC_RSP_OP(cmd, 0, 32, 32, uint32_t, mc_ver_info->major); \ - MC_RSP_OP(cmd, 1, 0, 32, uint32_t, mc_ver_info->minor); \ -} while (0) +#pragma pack(push, 1) +struct dpmng_rsp_get_version { + __le32 revision; + __le32 version_major; + __le32 version_minor; +}; + +#pragma pack(pop) #endif /* __FSL_DPMNG_CMD_H */ diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index 78a40f285aa..984616fb65c 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -1353,10 +1353,9 @@ err: static int dpni_init(void) { - int err; - uint8_t cfg_buf[256] = {0}; - struct dpni_cfg dpni_cfg; + struct dpni_cfg dpni_cfg = {0}; uint16_t major_ver, minor_ver; + int err; dflt_dpni = calloc(sizeof(struct fsl_dpni_obj), 1); if (!dflt_dpni) { @@ -1365,14 +1364,6 @@ static int dpni_init(void) goto err_calloc; } - memset(&dpni_cfg, 0, sizeof(dpni_cfg)); - err = dpni_prepare_cfg(&dpni_cfg, &cfg_buf[0]); - if (err < 0) { - err = -ENODEV; - printf("dpni_prepare_cfg() failed: %d\n", err); - goto err_prepare_cfg; - } - err = dpni_create(dflt_mc_io, dflt_dprc_handle, MC_CMD_NO_FLAGS, @@ -1429,7 +1420,6 @@ err_get_version: MC_CMD_NO_FLAGS, dflt_dpni->dpni_id); err_create: -err_prepare_cfg: free(dflt_dpni); err_calloc: return err; diff --git a/drivers/net/fsl-mc/mc_sys.c b/drivers/net/fsl-mc/mc_sys.c index b5ae2ea3eb5..4d32516b005 100644 --- a/drivers/net/fsl-mc/mc_sys.c +++ b/drivers/net/fsl-mc/mc_sys.c @@ -13,8 +13,13 @@ #include <asm/io.h> #include <linux/delay.h> -#define MC_CMD_HDR_READ_CMDID(_hdr) \ - ((uint16_t)mc_dec((_hdr), MC_CMD_HDR_CMDID_O, MC_CMD_HDR_CMDID_S)) +static u16 mc_cmd_hdr_read_cmdid(struct mc_command *cmd) +{ + struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; + u16 cmd_id = le16_to_cpu(hdr->cmd_id); + + return cmd_id; +} /** * mc_send_command - Send MC command and wait for response @@ -52,8 +57,8 @@ int mc_send_command(struct fsl_mc_io *mc_io, if (status != MC_CMD_STATUS_OK) { printf("Error: MC command failed (portal: %p, obj handle: %#x, command: %#x, status: %#x)\n", mc_io->mmio_regs, - (unsigned int)MC_CMD_HDR_READ_TOKEN(cmd->header), - (unsigned int)MC_CMD_HDR_READ_CMDID(cmd->header), + (unsigned int)mc_cmd_hdr_read_token(cmd), + (unsigned int)mc_cmd_hdr_read_cmdid(cmd), (unsigned int)status); return -EIO; diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index 2cb6e9b7d70..87fbada06ba 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -38,146 +38,90 @@ static void init_phy(struct udevice *dev) } #endif -#ifdef DEBUG - -#define DPNI_STATS_PER_PAGE 6 - -static const char *dpni_statistics[][DPNI_STATS_PER_PAGE] = { - { - "DPNI_CNT_ING_ALL_FRAMES", - "DPNI_CNT_ING_ALL_BYTES", - "DPNI_CNT_ING_MCAST_FRAMES", - "DPNI_CNT_ING_MCAST_BYTES", - "DPNI_CNT_ING_BCAST_FRAMES", - "DPNI_CNT_ING_BCAST_BYTES", - }, { - "DPNI_CNT_EGR_ALL_FRAMES", - "DPNI_CNT_EGR_ALL_BYTES", - "DPNI_CNT_EGR_MCAST_FRAMES", - "DPNI_CNT_EGR_MCAST_BYTES", - "DPNI_CNT_EGR_BCAST_FRAMES", - "DPNI_CNT_EGR_BCAST_BYTES", - }, { - "DPNI_CNT_ING_FILTERED_FRAMES", - "DPNI_CNT_ING_DISCARDED_FRAMES", - "DPNI_CNT_ING_NOBUFFER_DISCARDS", - "DPNI_CNT_EGR_DISCARDED_FRAMES", - "DPNI_CNT_EGR_CNF_FRAMES", - "" - }, -}; - -static void print_dpni_stats(const char *strings[], - struct dpni_statistics dpni_stats) +static void ldpaa_eth_collect_dpni_stats(struct udevice *dev, u64 *data) { - uint64_t *stat; - int i; + union dpni_statistics dpni_stats; + int dpni_stats_page_size[DPNI_STATISTICS_CNT] = { + sizeof(dpni_stats.page_0), + sizeof(dpni_stats.page_1), + sizeof(dpni_stats.page_2), + sizeof(dpni_stats.page_3), + sizeof(dpni_stats.page_4), + sizeof(dpni_stats.page_5), + sizeof(dpni_stats.page_6), + }; + int j, k, num_cnt, err, i = 0; - stat = (uint64_t *)&dpni_stats; - for (i = 0; i < DPNI_STATS_PER_PAGE; i++) { - if (strcmp(strings[i], "\0") == 0) - break; - printf("%s= %llu\n", strings[i], *stat); - stat++; + for (j = 0; j <= 6; j++) { + /* We're not interested in pages 4 & 5 for now */ + if (j == 4 || j == 5) + continue; + err = dpni_get_statistics(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, + j, 0, &dpni_stats); + if (err) { + memset(&dpni_stats, 0, sizeof(dpni_stats)); + printf("dpni_get_stats(%d) failed\n", j); + } + + num_cnt = dpni_stats_page_size[j] / sizeof(u64); + for (k = 0; k < num_cnt; k++) + *(data + i++) = dpni_stats.raw.counter[k]; } } -static void ldpaa_eth_get_dpni_counter(void) +static void ldpaa_eth_add_dpni_stats(struct udevice *dev, u64 *data) { - int err = 0; - unsigned int page = 0; - struct dpni_statistics dpni_stats; + struct ldpaa_eth_priv *priv = dev_get_priv(dev); + int i; - printf("DPNI counters ..\n"); - for (page = 0; page < 3; page++) { - err = dpni_get_statistics(dflt_mc_io, MC_CMD_NO_FLAGS, - dflt_dpni->dpni_handle, page, - &dpni_stats); - if (err < 0) { - printf("dpni_get_statistics: failed:"); - printf("%d for page[%d]\n", err, page); - return; - } - print_dpni_stats(dpni_statistics[page], dpni_stats); - } + for (i = 0; i < LDPAA_ETH_DPNI_NUM_STATS; i++) + priv->dpni_stats[i] += data[i]; } -static void ldpaa_eth_get_dpmac_counter(struct udevice *dev) +static void ldpaa_eth_collect_dpmac_stats(struct udevice *dev, u64 *data) { struct ldpaa_eth_priv *priv = dev_get_priv(dev); - int err = 0; + int err, i; u64 value; - err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpmac_handle, - DPMAC_CNT_ING_BYTE, - &value); - if (err < 0) { - printf("dpmac_get_counter: DPMAC_CNT_ING_BYTE failed\n"); - return; - } - printf("\nDPMAC counters ..\n"); - printf("DPMAC_CNT_ING_BYTE=%lld\n", value); + for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) { + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, i, + &value); + if (err) + printf("dpmac_get_counter(%d) failed\n", i); - err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpmac_handle, - DPMAC_CNT_ING_FRAME_DISCARD, - &value); - if (err < 0) { - printf("dpmac_get_counter: DPMAC_CNT_ING_FRAME_DISCARD failed\n"); - return; + *(data + i) = value; } - printf("DPMAC_CNT_ING_FRAME_DISCARD=%lld\n", value); +} - err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpmac_handle, - DPMAC_CNT_ING_ALIGN_ERR, - &value); - if (err < 0) { - printf("dpmac_get_counter: DPMAC_CNT_ING_ALIGN_ERR failed\n"); - return; - } - printf("DPMAC_CNT_ING_ALIGN_ERR =%lld\n", value); +static void ldpaa_eth_add_dpmac_stats(struct udevice *dev, u64 *data) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); + int i; - err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpmac_handle, - DPMAC_CNT_ING_BYTE, - &value); - if (err < 0) { - printf("dpmac_get_counter: DPMAC_CNT_ING_BYTE failed\n"); - return; - } - printf("DPMAC_CNT_ING_BYTE=%lld\n", value); + for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) + priv->dpmac_stats[i] += data[i]; +} - err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpmac_handle, - DPMAC_CNT_ING_ERR_FRAME, - &value); - if (err < 0) { - printf("dpmac_get_counter: DPMAC_CNT_ING_ERR_FRAME failed\n"); - return; - } - printf("DPMAC_CNT_ING_ERR_FRAME=%lld\n", value); +#ifdef DEBUG +static void ldpaa_eth_dump_dpni_stats(struct udevice *dev, u64 *data) +{ + int i; - err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpmac_handle, - DPMAC_CNT_EGR_BYTE , - &value); - if (err < 0) { - printf("dpmac_get_counter: DPMAC_CNT_EGR_BYTE failed\n"); - return; - } - printf("DPMAC_CNT_EGR_BYTE =%lld\n", value); + printf("DPNI counters:\n"); + for (i = 0; i < LDPAA_ETH_DPNI_NUM_STATS; i++) + printf(" %s: %llu\n", ldpaa_eth_dpni_stat_strings[i], data[i]); +} - err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpmac_handle, - DPMAC_CNT_EGR_ERR_FRAME , - &value); - if (err < 0) { - printf("dpmac_get_counter: DPMAC_CNT_EGR_ERR_FRAME failed\n"); - return; - } - printf("DPMAC_CNT_EGR_ERR_FRAME =%lld\n", value); +static void ldpaa_eth_dump_dpmac_stats(struct udevice *dev, u64 *data) +{ + int i; + + printf("DPMAC counters:\n"); + for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) + printf(" %s: %llu\n", ldpaa_eth_dpmac_stat_strings[i], data[i]); } #endif @@ -434,7 +378,8 @@ static int ldpaa_eth_open(struct udevice *dev) struct dpni_link_state link_state; #endif int err = 0; - struct dpni_queue d_queue; + struct dpni_queue d_queue_cfg = { 0 }; + struct dpni_queue_id d_queue; if (eth_is_active(dev)) return 0; @@ -478,7 +423,7 @@ static int ldpaa_eth_open(struct udevice *dev) goto err_dpni_bind; err = dpni_add_mac_addr(dflt_mc_io, MC_CMD_NO_FLAGS, - dflt_dpni->dpni_handle, plat->enetaddr); + dflt_dpni->dpni_handle, plat->enetaddr, 0, 0, 0); if (err) { printf("dpni_add_mac_addr() failed\n"); return err; @@ -517,7 +462,7 @@ static int ldpaa_eth_open(struct udevice *dev) memset(&d_queue, 0, sizeof(struct dpni_queue)); err = dpni_get_queue(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, DPNI_QUEUE_RX, - 0, 0, &d_queue); + 0, 0, &d_queue_cfg, &d_queue); if (err) { printf("dpni_get_queue failed\n"); goto err_get_queue; @@ -526,7 +471,7 @@ static int ldpaa_eth_open(struct udevice *dev) priv->rx_dflt_fqid = d_queue.fqid; err = dpni_get_qdid(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, - &priv->tx_qdid); + DPNI_QUEUE_TX, &priv->tx_qdid); if (err) { printf("dpni_get_qdid() failed\n"); goto err_qdid; @@ -556,14 +501,30 @@ static void ldpaa_eth_stop(struct udevice *dev) struct ldpaa_eth_priv *priv = dev_get_priv(dev); struct phy_device *phydev = NULL; int err = 0; + u64 *data; if (!eth_is_active(dev)) return; + data = kzalloc(sizeof(u64) * LDPAA_ETH_DPNI_NUM_STATS, GFP_KERNEL); + if (data) { + ldpaa_eth_collect_dpni_stats(dev, data); + ldpaa_eth_add_dpni_stats(dev, data); #ifdef DEBUG - ldpaa_eth_get_dpni_counter(); - ldpaa_eth_get_dpmac_counter(dev); + ldpaa_eth_dump_dpni_stats(dev, data); #endif + } + kfree(data); + + data = kzalloc(sizeof(u64) * LDPAA_ETH_DPMAC_NUM_STATS, GFP_KERNEL); + if (data) { + ldpaa_eth_collect_dpmac_stats(dev, data); + ldpaa_eth_add_dpmac_stats(dev, data); +#ifdef DEBUG + ldpaa_eth_dump_dpmac_stats(dev, data); +#endif + } + kfree(data); err = dprc_disconnect(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dprc_handle, &dpmac_endpoint); @@ -885,7 +846,7 @@ static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv) /* ...rx, ... */ err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, - &dflt_dpni->buf_layout, DPNI_QUEUE_RX); + DPNI_QUEUE_RX, &dflt_dpni->buf_layout); if (err) { printf("dpni_set_buffer_layout() failed"); goto err_buf_layout; @@ -897,7 +858,7 @@ static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv) DPNI_BUF_LAYOUT_OPT_PARSER_RESULT); err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, - &dflt_dpni->buf_layout, DPNI_QUEUE_TX); + DPNI_QUEUE_TX, &dflt_dpni->buf_layout); if (err) { printf("dpni_set_buffer_layout() failed"); goto err_buf_layout; @@ -907,8 +868,7 @@ static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv) dflt_dpni->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, - &dflt_dpni->buf_layout, - DPNI_QUEUE_TX_CONFIRM); + DPNI_QUEUE_TX_CONFIRM, &dflt_dpni->buf_layout); if (err) { printf("dpni_set_buffer_layout() failed"); goto err_buf_layout; @@ -963,7 +923,7 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) err = dpni_set_queue(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, - DPNI_QUEUE_TX, 0, 0, &tx_queue); + DPNI_QUEUE_TX, 0, 0, 0, &tx_queue); if (err) { printf("dpni_set_queue() failed\n"); @@ -972,7 +932,7 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) err = dpni_set_tx_confirmation_mode(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, - DPNI_CONF_DISABLE); + 0, DPNI_CONF_DISABLE); if (err) { printf("dpni_set_tx_confirmation_mode() failed\n"); return err; @@ -1038,11 +998,47 @@ static int ldpaa_eth_of_to_plat(struct udevice *dev) return 0; } +static int ldpaa_eth_get_sset_count(struct udevice *dev) +{ + return LDPAA_ETH_DPNI_NUM_STATS + LDPAA_ETH_DPMAC_NUM_STATS; +} + +static void ldpaa_eth_get_strings(struct udevice *dev, u8 *data) +{ + u8 *p = data; + int i; + + for (i = 0; i < LDPAA_ETH_DPNI_NUM_STATS; i++) { + strlcpy(p, ldpaa_eth_dpni_stat_strings[i], ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + + for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) { + strlcpy(p, ldpaa_eth_dpmac_stat_strings[i], ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } +} + +static void ldpaa_eth_get_stats(struct udevice *dev, u64 *data) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); + int i, j = 0; + + for (i = 0; i < LDPAA_ETH_DPNI_NUM_STATS; i++) + *(data + j++) = priv->dpni_stats[i]; + + for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) + *(data + j++) = priv->dpmac_stats[i]; +} + static const struct eth_ops ldpaa_eth_ops = { - .start = ldpaa_eth_open, - .send = ldpaa_eth_tx, - .recv = ldpaa_eth_pull_dequeue_rx, - .stop = ldpaa_eth_stop, + .start = ldpaa_eth_open, + .send = ldpaa_eth_tx, + .recv = ldpaa_eth_pull_dequeue_rx, + .stop = ldpaa_eth_stop, + .get_sset_count = ldpaa_eth_get_sset_count, + .get_strings = ldpaa_eth_get_strings, + .get_stats = ldpaa_eth_get_stats, }; static const struct udevice_id ldpaa_eth_of_ids[] = { diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.h b/drivers/net/ldpaa_eth/ldpaa_eth.h index 16d0106233e..af082e34cae 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.h +++ b/drivers/net/ldpaa_eth/ldpaa_eth.h @@ -115,6 +115,66 @@ struct ldpaa_fas { LDPAA_ETH_FAS_MNLE | \ LDPAA_ETH_FAS_TIDE) +static const char ldpaa_eth_dpni_stat_strings[][ETH_GSTRING_LEN] = { + "[dpni ] rx frames", + "[dpni ] rx bytes", + "[dpni ] rx mcast frames", + "[dpni ] rx mcast bytes", + "[dpni ] rx bcast frames", + "[dpni ] rx bcast bytes", + "[dpni ] tx frames", + "[dpni ] tx bytes", + "[dpni ] tx mcast frames", + "[dpni ] tx mcast bytes", + "[dpni ] tx bcast frames", + "[dpni ] tx bcast bytes", + "[dpni ] rx filtered frames", + "[dpni ] rx discarded frames", + "[dpni ] rx nobuffer discards", + "[dpni ] tx discarded frames", + "[dpni ] tx confirmed frames", + "[dpni ] tx dequeued bytes", + "[dpni ] tx dequeued frames", + "[dpni ] tx rejected bytes", + "[dpni ] tx rejected frames", + "[dpni ] tx pending frames", +}; + +#define LDPAA_ETH_DPNI_NUM_STATS ARRAY_SIZE(ldpaa_eth_dpni_stat_strings) + +static const char ldpaa_eth_dpmac_stat_strings[][ETH_GSTRING_LEN] = { + [DPMAC_CNT_ING_ALL_FRAME] = "[mac] rx all frames", + [DPMAC_CNT_ING_GOOD_FRAME] = "[mac] rx frames ok", + [DPMAC_CNT_ING_ERR_FRAME] = "[mac] rx frame errors", + [DPMAC_CNT_ING_FRAME_DISCARD] = "[mac] rx frame discards", + [DPMAC_CNT_ING_UCAST_FRAME] = "[mac] rx u-cast", + [DPMAC_CNT_ING_BCAST_FRAME] = "[mac] rx b-cast", + [DPMAC_CNT_ING_MCAST_FRAME] = "[mac] rx m-cast", + [DPMAC_CNT_ING_FRAME_64] = "[mac] rx 64 bytes", + [DPMAC_CNT_ING_FRAME_127] = "[mac] rx 65-127 bytes", + [DPMAC_CNT_ING_FRAME_255] = "[mac] rx 128-255 bytes", + [DPMAC_CNT_ING_FRAME_511] = "[mac] rx 256-511 bytes", + [DPMAC_CNT_ING_FRAME_1023] = "[mac] rx 512-1023 bytes", + [DPMAC_CNT_ING_FRAME_1518] = "[mac] rx 1024-1518 bytes", + [DPMAC_CNT_ING_FRAME_1519_MAX] = "[mac] rx 1519-max bytes", + [DPMAC_CNT_ING_FRAG] = "[mac] rx frags", + [DPMAC_CNT_ING_JABBER] = "[mac] rx jabber", + [DPMAC_CNT_ING_ALIGN_ERR] = "[mac] rx align errors", + [DPMAC_CNT_ING_OVERSIZED] = "[mac] rx oversized", + [DPMAC_CNT_ING_VALID_PAUSE_FRAME] = "[mac] rx pause", + [DPMAC_CNT_ING_BYTE] = "[mac] rx bytes", + [DPMAC_CNT_EGR_GOOD_FRAME] = "[mac] tx frames ok", + [DPMAC_CNT_EGR_UCAST_FRAME] = "[mac] tx u-cast", + [DPMAC_CNT_EGR_MCAST_FRAME] = "[mac] tx m-cast", + [DPMAC_CNT_EGR_BCAST_FRAME] = "[mac] tx b-cast", + [DPMAC_CNT_EGR_ERR_FRAME] = "[mac] tx frame errors", + [DPMAC_CNT_EGR_UNDERSIZED] = "[mac] tx undersized", + [DPMAC_CNT_EGR_VALID_PAUSE_FRAME] = "[mac] tx b-pause", + [DPMAC_CNT_EGR_BYTE] = "[mac] tx bytes", +}; + +#define LDPAA_ETH_DPMAC_NUM_STATS ARRAY_SIZE(ldpaa_eth_dpmac_stat_strings) + struct ldpaa_eth_priv { struct phy_device *phy; int phy_mode; @@ -129,6 +189,10 @@ struct ldpaa_eth_priv { uint16_t tx_flow_id; enum ldpaa_eth_type type; /* 1G or 10G ethernet */ + + /* SW kept statistics */ + u64 dpni_stats[LDPAA_ETH_DPNI_NUM_STATS]; + u64 dpmac_stats[LDPAA_ETH_DPMAC_NUM_STATS]; }; struct dprc_endpoint dpmac_endpoint; diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c index ad7b5b8e99b..ecf8c28fe41 100644 --- a/drivers/net/pch_gbe.c +++ b/drivers/net/pch_gbe.c @@ -414,16 +414,13 @@ static int pch_gbe_phy_init(struct udevice *dev) struct pch_gbe_priv *priv = dev_get_priv(dev); struct eth_pdata *plat = dev_get_plat(dev); struct phy_device *phydev; - int mask = 0xffffffff; - phydev = phy_find_by_mask(priv->bus, mask); + phydev = phy_connect(priv->bus, -1, dev, plat->phy_interface); if (!phydev) { printf("pch_gbe: cannot find the phy\n"); return -1; } - phy_connect_dev(phydev, dev, plat->phy_interface); - phydev->supported &= PHY_GBIT_FEATURES; phydev->advertising = phydev->supported; diff --git a/drivers/net/pfe_eth/pfe_hw.c b/drivers/net/pfe_eth/pfe_hw.c index 4db6f3158c3..9f2f92d116d 100644 --- a/drivers/net/pfe_eth/pfe_hw.c +++ b/drivers/net/pfe_eth/pfe_hw.c @@ -814,7 +814,7 @@ static inline void class_set_config(struct class_cfg *cfg) writel(0x1, CLASS_AXI_CTRL); /*Make Util AXI transactions non-bufferable */ - /*Util is disabled in U-boot, do it from here */ + /*Util is disabled in U-Boot, do it from here */ writel(0x1, UTIL_AXI_CTRL); } diff --git a/drivers/net/phy/ethernet_id.c b/drivers/net/phy/ethernet_id.c index a715e83db98..877a51c3d00 100644 --- a/drivers/net/phy/ethernet_id.c +++ b/drivers/net/phy/ethernet_id.c @@ -7,6 +7,8 @@ #include <common.h> #include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> #include <phy.h> #include <linux/delay.h> #include <asm/gpio.h> @@ -17,6 +19,8 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, struct phy_device *phydev; struct ofnode_phandle_args phandle_args; struct gpio_desc gpio; + const char *node_name; + struct udevice *pdev; ofnode node; u32 id, assert, deassert; u16 vendor, device; @@ -72,5 +76,18 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, if (phydev) phydev->node = node; + if (IS_ENABLED(CONFIG_DM_ETH_PHY) && ofnode_valid(node)) { + node_name = ofnode_get_name(node); + ret = device_bind_driver_to_node(dev, "eth_phy_generic_drv", + node_name, node, + &pdev); + if (ret) + return NULL; + + ret = device_probe(pdev); + if (ret) + return NULL; + } + return phydev; } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 0eeb0cb3a85..ae21acb059b 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -812,8 +812,8 @@ struct phy_device *phy_find_by_mask(struct mii_dev *bus, uint phy_mask) return get_phy_device_by_mask(bus, phy_mask); } -void phy_connect_dev(struct phy_device *phydev, struct udevice *dev, - phy_interface_t interface) +static void phy_connect_dev(struct phy_device *phydev, struct udevice *dev, + phy_interface_t interface) { /* Soft Reset the PHY */ phy_reset(phydev); diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index c74c8a81f94..0bcd6cfd3f3 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -131,7 +131,6 @@ struct ravb_priv { struct mii_dev *bus; void __iomem *iobase; struct clk_bulk clks; - struct gpio_desc reset_gpio; }; static inline void ravb_flush_dcache(u32 addr, u32 len) @@ -312,13 +311,6 @@ static int ravb_phy_config(struct udevice *dev) struct phy_device *phydev; int reg; - if (dm_gpio_is_valid(ð->reset_gpio)) { - dm_gpio_set_value(ð->reset_gpio, 1); - mdelay(20); - dm_gpio_set_value(ð->reset_gpio, 0); - mdelay(1); - } - phydev = phy_connect(eth->bus, -1, dev, pdata->phy_interface); if (!phydev) return -ENODEV; @@ -503,7 +495,6 @@ static int ravb_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); struct ravb_priv *eth = dev_get_priv(dev); - struct ofnode_phandle_args phandle_args; struct mii_dev *mdiodev; void __iomem *iobase; int ret; @@ -515,17 +506,6 @@ static int ravb_probe(struct udevice *dev) if (ret < 0) goto err_mdio_alloc; - ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, &phandle_args); - if (!ret) { - gpio_request_by_name_nodev(phandle_args.node, "reset-gpios", 0, - ð->reset_gpio, GPIOD_IS_OUT); - } - - if (!dm_gpio_is_valid(ð->reset_gpio)) { - gpio_request_by_name(dev, "reset-gpios", 0, ð->reset_gpio, - GPIOD_IS_OUT); - } - mdiodev = mdio_alloc(); if (!mdiodev) { ret = -ENOMEM; @@ -576,8 +556,6 @@ static int ravb_remove(struct udevice *dev) free(eth->phydev); mdio_unregister(eth->bus); mdio_free(eth->bus); - if (dm_gpio_is_valid(ð->reset_gpio)) - dm_gpio_free(dev, ð->reset_gpio); unmap_physmem(eth->iobase, MAP_NOCACHE); return 0; diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 8f162ca58fb..7b1f59dc498 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -129,11 +129,11 @@ static int sh_eth_recv_start(struct sh_eth_dev *eth) /* Check if the rx descriptor is ready */ invalidate_cache(port_info->rx_desc_cur, sizeof(struct rx_desc_s)); if (port_info->rx_desc_cur->rd0 & RD_RACT) - return -EINVAL; + return -EAGAIN; /* Check for errors */ if (port_info->rx_desc_cur->rd0 & RD_RFE) - return -EINVAL; + return 0; return port_info->rx_desc_cur->rd1 & 0xffff; } @@ -142,6 +142,8 @@ static void sh_eth_recv_finish(struct sh_eth_dev *eth) { struct sh_eth_info *port_info = ð->port_info[eth->port]; + invalidate_cache(ADDR_TO_P2(port_info->rx_desc_cur->rd2), MAX_BUF_SIZE); + /* Make current descriptor available again */ if (port_info->rx_desc_cur->rd0 & RD_RDLE) port_info->rx_desc_cur->rd0 = RD_RACT | RD_RDLE; @@ -210,8 +212,6 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) goto err; } - flush_cache_wback(port_info->tx_desc_alloc, alloc_desc_size); - /* Make sure we use a P2 address (non-cacheable) */ port_info->tx_desc_base = (struct tx_desc_s *)ADDR_TO_P2((uintptr_t)port_info->tx_desc_alloc); @@ -229,6 +229,7 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) cur_tx_desc--; cur_tx_desc->td0 |= TD_TDLE; + flush_cache_wback(port_info->tx_desc_alloc, alloc_desc_size); /* * Point the controller to the tx descriptor list. Must use physical * addresses @@ -264,8 +265,6 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) goto err; } - flush_cache_wback(port_info->rx_desc_alloc, alloc_desc_size); - /* Make sure we use a P2 address (non-cacheable) */ port_info->rx_desc_base = (struct rx_desc_s *)ADDR_TO_P2((uintptr_t)port_info->rx_desc_alloc); @@ -299,6 +298,9 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) cur_rx_desc--; cur_rx_desc->rd0 |= RD_RDLE; + invalidate_cache(port_info->rx_buf_alloc, NUM_RX_DESC * MAX_BUF_SIZE); + flush_cache_wback(port_info->rx_desc_alloc, alloc_desc_size); + /* Point the controller to the rx descriptor list */ sh_eth_write(port_info, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR); #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) @@ -530,7 +532,6 @@ struct sh_ether_priv { struct mii_dev *bus; phys_addr_t iobase; struct clk clk; - struct gpio_desc reset_gpio; }; static int sh_ether_send(struct udevice *dev, void *packet, int len) @@ -555,15 +556,13 @@ static int sh_ether_recv(struct udevice *dev, int flags, uchar **packetp) *packetp = packet; return len; - } else { - len = 0; + } - /* Restart the receiver if disabled */ - if (!(sh_eth_read(port_info, EDRRR) & EDRRR_R)) - sh_eth_write(port_info, EDRRR_R, EDRRR); + /* Restart the receiver if disabled */ + if (!(sh_eth_read(port_info, EDRRR) & EDRRR_R)) + sh_eth_write(port_info, EDRRR_R, EDRRR); - return -EAGAIN; - } + return len; } static int sh_ether_free_pkt(struct udevice *dev, uchar *packet, int length) @@ -601,14 +600,11 @@ static int sh_eth_phy_config(struct udevice *dev) int ret = 0; struct sh_eth_info *port_info = ð->port_info[eth->port]; struct phy_device *phydev; - int mask = 0xffffffff; - phydev = phy_find_by_mask(priv->bus, mask); + phydev = phy_connect(priv->bus, -1, dev, pdata->phy_interface); if (!phydev) return -ENODEV; - phy_connect_dev(phydev, dev, pdata->phy_interface); - port_info->phydev = phydev; phy_config(phydev); @@ -653,7 +649,6 @@ static int sh_ether_probe(struct udevice *udev) struct eth_pdata *pdata = dev_get_plat(udev); struct sh_ether_priv *priv = dev_get_priv(udev); struct sh_eth_dev *eth = &priv->shdev; - struct ofnode_phandle_args phandle_args; struct mii_dev *mdiodev; int ret; @@ -664,18 +659,6 @@ static int sh_ether_probe(struct udevice *udev) if (ret < 0) return ret; #endif - - ret = dev_read_phandle_with_args(udev, "phy-handle", NULL, 0, 0, &phandle_args); - if (!ret) { - gpio_request_by_name_nodev(phandle_args.node, "reset-gpios", 0, - &priv->reset_gpio, GPIOD_IS_OUT); - } - - if (!dm_gpio_is_valid(&priv->reset_gpio)) { - gpio_request_by_name(udev, "reset-gpios", 0, &priv->reset_gpio, - GPIOD_IS_OUT); - } - mdiodev = mdio_alloc(); if (!mdiodev) { ret = -ENOMEM; @@ -738,9 +721,6 @@ static int sh_ether_remove(struct udevice *udev) mdio_unregister(priv->bus); mdio_free(priv->bus); - if (dm_gpio_is_valid(&priv->reset_gpio)) - dm_gpio_free(udev, &priv->reset_gpio); - return 0; } diff --git a/drivers/net/sni_ave.c b/drivers/net/sni_ave.c index 014b070d9e5..f5a0d80af7a 100644 --- a/drivers/net/sni_ave.c +++ b/drivers/net/sni_ave.c @@ -391,14 +391,12 @@ static int ave_mdiobus_init(struct ave_private *priv, const char *name) static int ave_phy_init(struct ave_private *priv, void *dev) { struct phy_device *phydev; - int mask = GENMASK(31, 0), ret; + int ret; - phydev = phy_find_by_mask(priv->bus, mask); + phydev = phy_connect(priv->bus, -1, dev, priv->phy_mode); if (!phydev) return -ENODEV; - phy_connect_dev(phydev, dev, priv->phy_mode); - phydev->supported &= PHY_GBIT_FEATURES; if (priv->max_speed) { ret = phy_set_supported(phydev, priv->max_speed); diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index ad9e1abd161..4c90d4b4981 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -248,10 +248,10 @@ static int emac_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, static int sunxi_emac_init_phy(struct emac_eth_dev *priv, void *dev) { - int ret, mask = 0xffffffff; + int ret, mask = -1; #ifdef CONFIG_PHY_ADDR - mask = 1 << CONFIG_PHY_ADDR; + mask = CONFIG_PHY_ADDR; #endif priv->bus = mdio_alloc(); @@ -269,11 +269,10 @@ static int sunxi_emac_init_phy(struct emac_eth_dev *priv, void *dev) if (ret) return ret; - priv->phydev = phy_find_by_mask(priv->bus, mask); + priv->phydev = phy_connect(priv->bus, mask, dev, PHY_INTERFACE_MODE_MII); if (!priv->phydev) return -ENODEV; - phy_connect_dev(priv->phydev, dev, PHY_INTERFACE_MODE_MII); phy_config(priv->phydev); return 0; diff --git a/drivers/net/ti/davinci_emac.c b/drivers/net/ti/davinci_emac.c index 29d2fc9b54e..034877a7690 100644 --- a/drivers/net/ti/davinci_emac.c +++ b/drivers/net/ti/davinci_emac.c @@ -833,9 +833,9 @@ static int davinci_emac_probe(struct udevice *dev) #endif } -#if defined(CONFIG_TI816X) || (defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ +#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ defined(CONFIG_MACH_DAVINCI_DA850_EVM) && \ - !defined(CONFIG_DRIVER_TI_EMAC_RMII_NO_NEGOTIATE)) + !defined(CONFIG_DRIVER_TI_EMAC_RMII_NO_NEGOTIATE) for (i = 0; i < num_phy; i++) { if (phy[i].is_phy_connected(i)) phy[i].auto_negotiate(i); diff --git a/drivers/nvme/Makefile b/drivers/nvme/Makefile index fa7b6194460..fd3e68a91dc 100644 --- a/drivers/nvme/Makefile +++ b/drivers/nvme/Makefile @@ -4,4 +4,4 @@ obj-y += nvme-uclass.o nvme.o nvme_show.o obj-$(CONFIG_NVME_APPLE) += nvme_apple.o -obj-$(CONFIG_NVME_PCI) += nvme_pci.o +obj-$(CONFIG_$(SPL_)NVME_PCI) += nvme_pci.o diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index ef328d26525..84a2ae951f7 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -40,6 +40,12 @@ config PCI_PNP help Enable PCI memory and I/O space resource allocation and assignment. +config SPL_PCI_PNP + bool "Enable Plug & Play support for PCI" + help + Enable PCI memory and I/O space resource allocation and assignment. + This is required to auto configure the enumerated devices. + config PCI_REGION_MULTI_ENTRY bool "Enable Multiple entries of region type MEMORY in ranges for PCI" help @@ -374,4 +380,11 @@ config PCIE_UNIPHIER Say Y here if you want to enable PCIe controller support on UniPhier SoCs. +config PCIE_XILINX_NWL + bool "Xilinx NWL PCIe controller" + depends on ARCH_ZYNQMP + help + Say 'Y' here if you want support for Xilinx / AMD NWL PCIe + controller as Root Port. + endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 49506e7ba59..11f60c6991d 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o obj-$(CONFIG_PCIE_OCTEON) += pcie_octeon.o obj-$(CONFIG_PCIE_DW_SIFIVE) += pcie_dw_sifive.o obj-$(CONFIG_PCIE_UNIPHIER) += pcie_uniphier.o +obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o diff --git a/drivers/pci/pcie-xilinx-nwl.c b/drivers/pci/pcie-xilinx-nwl.c new file mode 100644 index 00000000000..7ef2bdf57b5 --- /dev/null +++ b/drivers/pci/pcie-xilinx-nwl.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe host bridge driver for Xilinx / AMD ZynqMP NWL PCIe Bridge + * + * Based on the Linux driver which is: + * (C) Copyright 2014 - 2015, Xilinx, Inc. + * + * Author: Stefan Roese <sr@denx.de> + */ + +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <mapmem.h> +#include <pci.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/ioport.h> + +/* Bridge core config registers */ +#define BRCFG_PCIE_RX0 0x00000000 +#define BRCFG_PCIE_RX1 0x00000004 +#define BRCFG_INTERRUPT 0x00000010 +#define BRCFG_PCIE_RX_MSG_FILTER 0x00000020 + +/* Egress - Bridge translation registers */ +#define E_BREG_CAPABILITIES 0x00000200 +#define E_BREG_CONTROL 0x00000208 +#define E_BREG_BASE_LO 0x00000210 +#define E_BREG_BASE_HI 0x00000214 +#define E_ECAM_CAPABILITIES 0x00000220 +#define E_ECAM_CONTROL 0x00000228 +#define E_ECAM_BASE_LO 0x00000230 +#define E_ECAM_BASE_HI 0x00000234 + +#define I_ISUB_CONTROL 0x000003E8 +#define SET_ISUB_CONTROL BIT(0) +/* Rxed msg fifo - Interrupt status registers */ +#define MSGF_MISC_STATUS 0x00000400 +#define MSGF_MISC_MASK 0x00000404 +#define MSGF_LEG_STATUS 0x00000420 +#define MSGF_LEG_MASK 0x00000424 +#define MSGF_MSI_STATUS_LO 0x00000440 +#define MSGF_MSI_STATUS_HI 0x00000444 +#define MSGF_MSI_MASK_LO 0x00000448 +#define MSGF_MSI_MASK_HI 0x0000044C + +/* Msg filter mask bits */ +#define CFG_ENABLE_PM_MSG_FWD BIT(1) +#define CFG_ENABLE_INT_MSG_FWD BIT(2) +#define CFG_ENABLE_ERR_MSG_FWD BIT(3) +#define CFG_ENABLE_MSG_FILTER_MASK (CFG_ENABLE_PM_MSG_FWD | \ + CFG_ENABLE_INT_MSG_FWD | \ + CFG_ENABLE_ERR_MSG_FWD) + +/* Misc interrupt status mask bits */ +#define MSGF_MISC_SR_RXMSG_AVAIL BIT(0) +#define MSGF_MISC_SR_RXMSG_OVER BIT(1) +#define MSGF_MISC_SR_SLAVE_ERR BIT(4) +#define MSGF_MISC_SR_MASTER_ERR BIT(5) +#define MSGF_MISC_SR_I_ADDR_ERR BIT(6) +#define MSGF_MISC_SR_E_ADDR_ERR BIT(7) +#define MSGF_MISC_SR_FATAL_AER BIT(16) +#define MSGF_MISC_SR_NON_FATAL_AER BIT(17) +#define MSGF_MISC_SR_CORR_AER BIT(18) +#define MSGF_MISC_SR_UR_DETECT BIT(20) +#define MSGF_MISC_SR_NON_FATAL_DEV BIT(22) +#define MSGF_MISC_SR_FATAL_DEV BIT(23) +#define MSGF_MISC_SR_LINK_DOWN BIT(24) +#define MSGF_MSIC_SR_LINK_AUTO_BWIDTH BIT(25) +#define MSGF_MSIC_SR_LINK_BWIDTH BIT(26) + +#define MSGF_MISC_SR_MASKALL (MSGF_MISC_SR_RXMSG_AVAIL | \ + MSGF_MISC_SR_RXMSG_OVER | \ + MSGF_MISC_SR_SLAVE_ERR | \ + MSGF_MISC_SR_MASTER_ERR | \ + MSGF_MISC_SR_I_ADDR_ERR | \ + MSGF_MISC_SR_E_ADDR_ERR | \ + MSGF_MISC_SR_FATAL_AER | \ + MSGF_MISC_SR_NON_FATAL_AER | \ + MSGF_MISC_SR_CORR_AER | \ + MSGF_MISC_SR_UR_DETECT | \ + MSGF_MISC_SR_NON_FATAL_DEV | \ + MSGF_MISC_SR_FATAL_DEV | \ + MSGF_MISC_SR_LINK_DOWN | \ + MSGF_MSIC_SR_LINK_AUTO_BWIDTH | \ + MSGF_MSIC_SR_LINK_BWIDTH) + +/* Legacy interrupt status mask bits */ +#define MSGF_LEG_SR_INTA BIT(0) +#define MSGF_LEG_SR_INTB BIT(1) +#define MSGF_LEG_SR_INTC BIT(2) +#define MSGF_LEG_SR_INTD BIT(3) +#define MSGF_LEG_SR_MASKALL (MSGF_LEG_SR_INTA | MSGF_LEG_SR_INTB | \ + MSGF_LEG_SR_INTC | MSGF_LEG_SR_INTD) + +/* MSI interrupt status mask bits */ +#define MSGF_MSI_SR_LO_MASK GENMASK(31, 0) +#define MSGF_MSI_SR_HI_MASK GENMASK(31, 0) + +/* Bridge config interrupt mask */ +#define BRCFG_INTERRUPT_MASK BIT(0) +#define BREG_PRESENT BIT(0) +#define BREG_ENABLE BIT(0) +#define BREG_ENABLE_FORCE BIT(1) + +/* E_ECAM status mask bits */ +#define E_ECAM_PRESENT BIT(0) +#define E_ECAM_CR_ENABLE BIT(0) +#define E_ECAM_SIZE_LOC GENMASK(20, 16) +#define E_ECAM_SIZE_SHIFT 16 +#define NWL_ECAM_VALUE_DEFAULT 12 + +#define CFG_DMA_REG_BAR GENMASK(2, 0) +#define CFG_PCIE_CACHE GENMASK(7, 0) + +/* Readin the PS_LINKUP */ +#define PS_LINKUP_OFFSET 0x00000238 +#define PCIE_PHY_LINKUP_BIT BIT(0) +#define PHY_RDY_LINKUP_BIT BIT(1) + +/* Parameters for the waiting for link up routine */ +#define LINK_WAIT_MAX_RETRIES 10 +#define LINK_WAIT_USLEEP_MIN 90000 +#define LINK_WAIT_USLEEP_MAX 100000 + +struct nwl_pcie { + struct udevice *dev; + void __iomem *breg_base; + void __iomem *pcireg_base; + void __iomem *ecam_base; + phys_addr_t phys_breg_base; /* Physical Bridge Register Base */ + phys_addr_t phys_ecam_base; /* Physical Configuration Base */ + u32 ecam_value; +}; + +static int nwl_pcie_config_address(const struct udevice *bus, + pci_dev_t bdf, uint offset, + void **paddress) +{ + struct nwl_pcie *pcie = dev_get_priv(bus); + void *addr; + + addr = pcie->ecam_base; + addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf) - dev_seq(bus), + PCI_DEV(bdf), PCI_FUNC(bdf), offset); + *paddress = addr; + + return 0; +} + +static int nwl_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + return pci_generic_mmap_read_config(bus, nwl_pcie_config_address, + bdf, offset, valuep, size); +} + +static int nwl_pcie_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + return pci_generic_mmap_write_config(bus, nwl_pcie_config_address, + bdf, offset, value, size); +} + +static const struct dm_pci_ops nwl_pcie_ops = { + .read_config = nwl_pcie_read_config, + .write_config = nwl_pcie_write_config, +}; + +static inline u32 nwl_bridge_readl(struct nwl_pcie *pcie, u32 off) +{ + return readl(pcie->breg_base + off); +} + +static inline void nwl_bridge_writel(struct nwl_pcie *pcie, u32 val, u32 off) +{ + writel(val, pcie->breg_base + off); +} + +static bool nwl_pcie_link_up(struct nwl_pcie *pcie) +{ + if (readl(pcie->pcireg_base + PS_LINKUP_OFFSET) & PCIE_PHY_LINKUP_BIT) + return true; + return false; +} + +static bool nwl_phy_link_up(struct nwl_pcie *pcie) +{ + if (readl(pcie->pcireg_base + PS_LINKUP_OFFSET) & PHY_RDY_LINKUP_BIT) + return true; + return false; +} + +static int nwl_wait_for_link(struct nwl_pcie *pcie) +{ + struct udevice *dev = pcie->dev; + int retries; + + /* check if the link is up or not */ + for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) { + if (nwl_phy_link_up(pcie)) + return 0; + udelay(LINK_WAIT_USLEEP_MIN); + } + + dev_warn(dev, "PHY link never came up\n"); + return -ETIMEDOUT; +} + +static int nwl_pcie_bridge_init(struct nwl_pcie *pcie) +{ + struct udevice *dev = pcie->dev; + u32 breg_val, ecam_val; + int err; + + breg_val = nwl_bridge_readl(pcie, E_BREG_CAPABILITIES) & BREG_PRESENT; + if (!breg_val) { + dev_err(dev, "BREG is not present\n"); + return breg_val; + } + + /* Write bridge_off to breg base */ + nwl_bridge_writel(pcie, lower_32_bits(pcie->phys_breg_base), + E_BREG_BASE_LO); + nwl_bridge_writel(pcie, upper_32_bits(pcie->phys_breg_base), + E_BREG_BASE_HI); + + /* Enable BREG */ + nwl_bridge_writel(pcie, ~BREG_ENABLE_FORCE & BREG_ENABLE, + E_BREG_CONTROL); + + /* Disable DMA channel registers */ + nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, BRCFG_PCIE_RX0) | + CFG_DMA_REG_BAR, BRCFG_PCIE_RX0); + + /* Enable Ingress subtractive decode translation */ + nwl_bridge_writel(pcie, SET_ISUB_CONTROL, I_ISUB_CONTROL); + + /* Enable msg filtering details */ + nwl_bridge_writel(pcie, CFG_ENABLE_MSG_FILTER_MASK, + BRCFG_PCIE_RX_MSG_FILTER); + + err = nwl_wait_for_link(pcie); + if (err) + return err; + + ecam_val = nwl_bridge_readl(pcie, E_ECAM_CAPABILITIES) & E_ECAM_PRESENT; + if (!ecam_val) { + dev_err(dev, "ECAM is not present\n"); + return ecam_val; + } + + /* Enable ECAM */ + nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) | + E_ECAM_CR_ENABLE, E_ECAM_CONTROL); + + nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) | + (pcie->ecam_value << E_ECAM_SIZE_SHIFT), + E_ECAM_CONTROL); + + nwl_bridge_writel(pcie, lower_32_bits(pcie->phys_ecam_base), + E_ECAM_BASE_LO); + nwl_bridge_writel(pcie, upper_32_bits(pcie->phys_ecam_base), + E_ECAM_BASE_HI); + + if (nwl_pcie_link_up(pcie)) + dev_info(dev, "Link is UP\n"); + else + dev_info(dev, "Link is DOWN\n"); + + /* Disable all misc interrupts */ + nwl_bridge_writel(pcie, (u32)~MSGF_MISC_SR_MASKALL, MSGF_MISC_MASK); + + /* Clear pending misc interrupts */ + nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_MISC_STATUS) & + MSGF_MISC_SR_MASKALL, MSGF_MISC_STATUS); + + /* Disable all legacy interrupts */ + nwl_bridge_writel(pcie, (u32)~MSGF_LEG_SR_MASKALL, MSGF_LEG_MASK); + + /* Clear pending legacy interrupts */ + nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_LEG_STATUS) & + MSGF_LEG_SR_MASKALL, MSGF_LEG_STATUS); + + return 0; +} + +static int nwl_pcie_parse_dt(struct nwl_pcie *pcie) +{ + struct udevice *dev = pcie->dev; + struct resource res; + int ret; + + ret = dev_read_resource_byname(dev, "breg", &res); + if (ret) + return ret; + pcie->breg_base = devm_ioremap(dev, res.start, resource_size(&res)); + if (IS_ERR(pcie->breg_base)) + return PTR_ERR(pcie->breg_base); + pcie->phys_breg_base = res.start; + + ret = dev_read_resource_byname(dev, "cfg", &res); + if (ret) + return ret; + pcie->ecam_base = devm_ioremap(dev, res.start, resource_size(&res)); + if (IS_ERR(pcie->ecam_base)) + return PTR_ERR(pcie->ecam_base); + pcie->phys_ecam_base = res.start; + + return 0; +} + +static int nwl_pcie_probe(struct udevice *dev) +{ + struct nwl_pcie *pcie = dev_get_priv(dev); + int err; + + pcie->dev = dev; + pcie->ecam_value = NWL_ECAM_VALUE_DEFAULT; + + err = nwl_pcie_parse_dt(pcie); + if (err) { + dev_err(dev, "Parsing DT failed\n"); + return err; + } + + err = nwl_pcie_bridge_init(pcie); + if (err) { + dev_err(dev, "HW Initialization failed\n"); + return err; + } + + return 0; +} + +static const struct udevice_id nwl_pcie_of_match[] = { + { .compatible = "xlnx,nwl-pcie-2.11", }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(nwl_pcie) = { + .name = "nwl-pcie", + .id = UCLASS_PCI, + .of_match = nwl_pcie_of_match, + .probe = nwl_pcie_probe, + .priv_auto = sizeof(struct nwl_pcie), + .ops = &nwl_pcie_ops, +}; diff --git a/drivers/phy/marvell/comphy_cp110.c b/drivers/phy/marvell/comphy_cp110.c index e063b51c6dd..a7e0099045f 100644 --- a/drivers/phy/marvell/comphy_cp110.c +++ b/drivers/phy/marvell/comphy_cp110.c @@ -25,7 +25,7 @@ DECLARE_GLOBAL_DATA_PTR; #define MV_SIP_COMPHY_PLL_LOCK 0x82000003 #define MV_SIP_COMPHY_XFI_TRAIN 0x82000004 -/* Used to distinguish between different possible callers (U-boot/Linux) */ +/* Used to distinguish between different possible callers (U-Boot/Linux) */ #define COMPHY_CALLER_UBOOT (0x1 << 21) #define COMPHY_FW_MODE_FORMAT(mode) ((mode) << 12) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 23397175d34..34314d0bd1e 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -256,6 +256,7 @@ enum wiz_type { J721E_WIZ_10G, AM64_WIZ_10G, J784S4_WIZ_10G, + J721S2_WIZ_10G, }; struct wiz_data { @@ -307,6 +308,15 @@ static struct wiz_data j784s4_wiz_10g = { .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, }; +static struct wiz_data j721s2_10g_data = { + .type = J721S2_WIZ_10G, + .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, + .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, + .refclk_dig_sel = &refclk_dig_sel_10g, + .clk_mux_sel = clk_mux_sel_10g, + .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, +}; + #define WIZ_TYPEC_DIR_DEBOUNCE_MIN 100 /* ms */ #define WIZ_TYPEC_DIR_DEBOUNCE_MAX 1000 @@ -1037,8 +1047,14 @@ static int j721e_wiz_bind_of_clocks(struct wiz *wiz) ofnode node; int i, rc; - if (type == AM64_WIZ_10G || type == J784S4_WIZ_10G) + switch (type) { + case AM64_WIZ_10G: + case J784S4_WIZ_10G: + case J721S2_WIZ_10G: return j721e_wiz_bind_clocks(wiz); + default: + break; + }; div_clk_drv = lists_driver_lookup_name("wiz_div_clk"); if (!div_clk_drv) { @@ -1282,6 +1298,9 @@ static const struct udevice_id j721e_wiz_ids[] = { { .compatible = "ti,j784s4-wiz-10g", .data = (ulong)&j784s4_wiz_10g, }, + { + .compatible = "ti,j721s2-wiz-10g", .data = (ulong)&j721s2_10g_data, + }, {} }; diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.h b/drivers/pinctrl/exynos/pinctrl-exynos.h index a7788b76d90..cbc5174b48c 100644 --- a/drivers/pinctrl/exynos/pinctrl-exynos.h +++ b/drivers/pinctrl/exynos/pinctrl-exynos.h @@ -6,7 +6,7 @@ */ #ifndef __PINCTRL_EXYNOS_H_ -#define __PINCTRL_EXYNOS__H_ +#define __PINCTRL_EXYNOS_H_ #define PIN_CON 0x00 /* Offset of pin function register */ #define PIN_DAT 0x04 /* Offset of pin data register */ diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig index ef02087ed23..97e574330fb 100644 --- a/drivers/pinctrl/meson/Kconfig +++ b/drivers/pinctrl/meson/Kconfig @@ -29,4 +29,8 @@ config PINCTRL_MESON_G12A bool "Amlogic Meson G12a SoC pinctrl driver" select PINCTRL_MESON_AXG_PMX +config PINCTRL_MESON_A1 + bool "Amlogic Meson A1 SoC pinctrl driver" + select PINCTRL_MESON_AXG_PMX + endif diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile index 80dba65e1bd..8d10d027ac6 100644 --- a/drivers/pinctrl/meson/Makefile +++ b/drivers/pinctrl/meson/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_PINCTRL_MESON_GXBB) += pinctrl-meson-gxbb.o obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o obj-$(CONFIG_PINCTRL_MESON_G12A) += pinctrl-meson-g12a.o +obj-$(CONFIG_PINCTRL_MESON_A1) += pinctrl-meson-a1.o diff --git a/drivers/pinctrl/meson/pinctrl-meson-a1.c b/drivers/pinctrl/meson/pinctrl-meson-a1.c new file mode 100644 index 00000000000..30cf3bc0be4 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-a1.c @@ -0,0 +1,867 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * Author: Qianggui Song <qianggui.song@amlogic.com> + * Copyright (C) 2023 SberDevices, Inc. + * Author: Igor Prusov <ivprusov@sberdevices.ru> + */ + +#include <common.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <dt-bindings/gpio/meson-a1-gpio.h> + +#include "pinctrl-meson.h" +#include "pinctrl-meson-axg.h" + +/* psram */ +static const unsigned int psram_clkn_pins[] = { GPIOP_0 }; +static const unsigned int psram_clkp_pins[] = { GPIOP_1 }; +static const unsigned int psram_ce_n_pins[] = { GPIOP_2 }; +static const unsigned int psram_rst_n_pins[] = { GPIOP_3 }; +static const unsigned int psram_adq0_pins[] = { GPIOP_4 }; +static const unsigned int psram_adq1_pins[] = { GPIOP_5 }; +static const unsigned int psram_adq2_pins[] = { GPIOP_6 }; +static const unsigned int psram_adq3_pins[] = { GPIOP_7 }; +static const unsigned int psram_adq4_pins[] = { GPIOP_8 }; +static const unsigned int psram_adq5_pins[] = { GPIOP_9 }; +static const unsigned int psram_adq6_pins[] = { GPIOP_10 }; +static const unsigned int psram_adq7_pins[] = { GPIOP_11 }; +static const unsigned int psram_dqs_dm_pins[] = { GPIOP_12 }; + +/* sdcard */ +static const unsigned int sdcard_d0_b_pins[] = { GPIOB_0 }; +static const unsigned int sdcard_d1_b_pins[] = { GPIOB_1 }; +static const unsigned int sdcard_d2_b_pins[] = { GPIOB_2 }; +static const unsigned int sdcard_d3_b_pins[] = { GPIOB_3 }; +static const unsigned int sdcard_clk_b_pins[] = { GPIOB_4 }; +static const unsigned int sdcard_cmd_b_pins[] = { GPIOB_5 }; + +static const unsigned int sdcard_d0_x_pins[] = { GPIOX_0 }; +static const unsigned int sdcard_d1_x_pins[] = { GPIOX_1 }; +static const unsigned int sdcard_d2_x_pins[] = { GPIOX_2 }; +static const unsigned int sdcard_d3_x_pins[] = { GPIOX_3 }; +static const unsigned int sdcard_clk_x_pins[] = { GPIOX_4 }; +static const unsigned int sdcard_cmd_x_pins[] = { GPIOX_5 }; + +/* spif */ +static const unsigned int spif_mo_pins[] = { GPIOB_0 }; +static const unsigned int spif_mi_pins[] = { GPIOB_1 }; +static const unsigned int spif_wp_n_pins[] = { GPIOB_2 }; +static const unsigned int spif_hold_n_pins[] = { GPIOB_3 }; +static const unsigned int spif_clk_pins[] = { GPIOB_4 }; +static const unsigned int spif_cs_pins[] = { GPIOB_5 }; + +/* i2c0 */ +static const unsigned int i2c0_sck_f9_pins[] = { GPIOF_9 }; +static const unsigned int i2c0_sda_f10_pins[] = { GPIOF_10 }; +static const unsigned int i2c0_sck_f11_pins[] = { GPIOF_11 }; +static const unsigned int i2c0_sda_f12_pins[] = { GPIOF_12 }; + +/* i2c1 */ +static const unsigned int i2c1_sda_x_pins[] = { GPIOX_9 }; +static const unsigned int i2c1_sck_x_pins[] = { GPIOX_10 }; +static const unsigned int i2c1_sda_a_pins[] = { GPIOA_10 }; +static const unsigned int i2c1_sck_a_pins[] = { GPIOA_11 }; + +/* i2c2 */ +static const unsigned int i2c2_sck_x0_pins[] = { GPIOX_0 }; +static const unsigned int i2c2_sda_x1_pins[] = { GPIOX_1 }; +static const unsigned int i2c2_sck_x15_pins[] = { GPIOX_15 }; +static const unsigned int i2c2_sda_x16_pins[] = { GPIOX_16 }; +static const unsigned int i2c2_sck_a4_pins[] = { GPIOA_4 }; +static const unsigned int i2c2_sda_a5_pins[] = { GPIOA_5 }; +static const unsigned int i2c2_sck_a8_pins[] = { GPIOA_8 }; +static const unsigned int i2c2_sda_a9_pins[] = { GPIOA_9 }; + +/* i2c3 */ +static const unsigned int i2c3_sck_f_pins[] = { GPIOF_4 }; +static const unsigned int i2c3_sda_f_pins[] = { GPIOF_5 }; +static const unsigned int i2c3_sck_x_pins[] = { GPIOX_11 }; +static const unsigned int i2c3_sda_x_pins[] = { GPIOX_12 }; + +/* i2c slave */ +static const unsigned int i2c_slave_sck_a_pins[] = { GPIOA_10 }; +static const unsigned int i2c_slave_sda_a_pins[] = { GPIOA_11 }; +static const unsigned int i2c_slave_sck_f_pins[] = { GPIOF_11 }; +static const unsigned int i2c_slave_sda_f_pins[] = { GPIOF_12 }; + +/* uart_a */ +static const unsigned int uart_a_tx_pins[] = { GPIOX_11 }; +static const unsigned int uart_a_rx_pins[] = { GPIOX_12 }; +static const unsigned int uart_a_cts_pins[] = { GPIOX_13 }; +static const unsigned int uart_a_rts_pins[] = { GPIOX_14 }; + +/* uart_b */ +static const unsigned int uart_b_tx_x_pins[] = { GPIOX_7 }; +static const unsigned int uart_b_rx_x_pins[] = { GPIOX_8 }; +static const unsigned int uart_b_tx_f_pins[] = { GPIOF_0 }; +static const unsigned int uart_b_rx_f_pins[] = { GPIOF_1 }; + +/* uart_c */ +static const unsigned int uart_c_tx_x0_pins[] = { GPIOX_0 }; +static const unsigned int uart_c_rx_x1_pins[] = { GPIOX_1 }; +static const unsigned int uart_c_cts_pins[] = { GPIOX_2 }; +static const unsigned int uart_c_rts_pins[] = { GPIOX_3 }; +static const unsigned int uart_c_tx_x15_pins[] = { GPIOX_15 }; +static const unsigned int uart_c_rx_x16_pins[] = { GPIOX_16 }; + +/* pmw_a */ +static const unsigned int pwm_a_x6_pins[] = { GPIOX_6 }; +static const unsigned int pwm_a_x7_pins[] = { GPIOX_7 }; +static const unsigned int pwm_a_f6_pins[] = { GPIOF_6 }; +static const unsigned int pwm_a_f10_pins[] = { GPIOF_10 }; +static const unsigned int pwm_a_a_pins[] = { GPIOA_5 }; + +/* pmw_b */ +static const unsigned int pwm_b_x_pins[] = { GPIOX_8 }; +static const unsigned int pwm_b_f_pins[] = { GPIOF_7 }; +static const unsigned int pwm_b_a_pins[] = { GPIOA_11 }; + +/* pmw_c */ +static const unsigned int pwm_c_x_pins[] = { GPIOX_9 }; +static const unsigned int pwm_c_f3_pins[] = { GPIOF_3 }; +static const unsigned int pwm_c_f8_pins[] = { GPIOF_8 }; +static const unsigned int pwm_c_a_pins[] = { GPIOA_10 }; + +/* pwm_d */ +static const unsigned int pwm_d_x10_pins[] = { GPIOX_10 }; +static const unsigned int pwm_d_x13_pins[] = { GPIOX_13 }; +static const unsigned int pwm_d_x15_pins[] = { GPIOX_15 }; +static const unsigned int pwm_d_f_pins[] = { GPIOF_11 }; + +/* pwm_e */ +static const unsigned int pwm_e_p_pins[] = { GPIOP_3 }; +static const unsigned int pwm_e_x2_pins[] = { GPIOX_2 }; +static const unsigned int pwm_e_x14_pins[] = { GPIOX_14 }; +static const unsigned int pwm_e_x16_pins[] = { GPIOX_16 }; +static const unsigned int pwm_e_f_pins[] = { GPIOF_3 }; +static const unsigned int pwm_e_a_pins[] = { GPIOA_0 }; + +/* pwm_f */ +static const unsigned int pwm_f_b_pins[] = { GPIOB_6 }; +static const unsigned int pwm_f_x_pins[] = { GPIOX_3 }; +static const unsigned int pwm_f_f4_pins[] = { GPIOF_4 }; +static const unsigned int pwm_f_f12_pins[] = { GPIOF_12 }; + +/* pwm_a_hiz */ +static const unsigned int pwm_a_hiz_f8_pins[] = { GPIOF_8 }; +static const unsigned int pwm_a_hiz_f10_pins[] = { GPIOF_10 }; +static const unsigned int pmw_a_hiz_f6_pins[] = { GPIOF_6 }; + +/* pwm_b_hiz */ +static const unsigned int pwm_b_hiz_pins[] = { GPIOF_7 }; + +/* pmw_c_hiz */ +static const unsigned int pwm_c_hiz_pins[] = { GPIOF_8 }; + +/* tdm_a */ +static const unsigned int tdm_a_dout1_pins[] = { GPIOX_7 }; +static const unsigned int tdm_a_dout0_pins[] = { GPIOX_8 }; +static const unsigned int tdm_a_fs_pins[] = { GPIOX_9 }; +static const unsigned int tdm_a_sclk_pins[] = { GPIOX_10 }; +static const unsigned int tdm_a_din1_pins[] = { GPIOX_7 }; +static const unsigned int tdm_a_din0_pins[] = { GPIOX_8 }; +static const unsigned int tdm_a_slv_fs_pins[] = { GPIOX_9 }; +static const unsigned int tdm_a_slv_sclk_pins[] = { GPIOX_10 }; + +/* spi_a */ +static const unsigned int spi_a_mosi_x2_pins[] = { GPIOX_2 }; +static const unsigned int spi_a_ss0_x3_pins[] = { GPIOX_3 }; +static const unsigned int spi_a_sclk_x4_pins[] = { GPIOX_4 }; +static const unsigned int spi_a_miso_x5_pins[] = { GPIOX_5 }; +static const unsigned int spi_a_mosi_x7_pins[] = { GPIOX_7 }; +static const unsigned int spi_a_miso_x8_pins[] = { GPIOX_8 }; +static const unsigned int spi_a_ss0_x9_pins[] = { GPIOX_9 }; +static const unsigned int spi_a_sclk_x10_pins[] = { GPIOX_10 }; + +static const unsigned int spi_a_mosi_a_pins[] = { GPIOA_6 }; +static const unsigned int spi_a_miso_a_pins[] = { GPIOA_7 }; +static const unsigned int spi_a_ss0_a_pins[] = { GPIOA_8 }; +static const unsigned int spi_a_sclk_a_pins[] = { GPIOA_9 }; + +/* pdm */ +static const unsigned int pdm_din0_x_pins[] = { GPIOX_7 }; +static const unsigned int pdm_din1_x_pins[] = { GPIOX_8 }; +static const unsigned int pdm_din2_x_pins[] = { GPIOX_9 }; +static const unsigned int pdm_dclk_x_pins[] = { GPIOX_10 }; + +static const unsigned int pdm_din2_a_pins[] = { GPIOA_6 }; +static const unsigned int pdm_din1_a_pins[] = { GPIOA_7 }; +static const unsigned int pdm_din0_a_pins[] = { GPIOA_8 }; +static const unsigned int pdm_dclk_pins[] = { GPIOA_9 }; + +/* gen_clk */ +static const unsigned int gen_clk_x_pins[] = { GPIOX_7 }; +static const unsigned int gen_clk_f8_pins[] = { GPIOF_8 }; +static const unsigned int gen_clk_f10_pins[] = { GPIOF_10 }; +static const unsigned int gen_clk_a_pins[] = { GPIOA_11 }; + +/* jtag_a */ +static const unsigned int jtag_a_clk_pins[] = { GPIOF_4 }; +static const unsigned int jtag_a_tms_pins[] = { GPIOF_5 }; +static const unsigned int jtag_a_tdi_pins[] = { GPIOF_6 }; +static const unsigned int jtag_a_tdo_pins[] = { GPIOF_7 }; + +/* clk_32_in */ +static const unsigned int clk_32k_in_pins[] = { GPIOF_2 }; + +/* ir in */ +static const unsigned int remote_input_f_pins[] = { GPIOF_3 }; +static const unsigned int remote_input_a_pins[] = { GPIOA_11 }; + +/* ir out */ +static const unsigned int remote_out_pins[] = { GPIOF_5 }; + +/* spdif */ +static const unsigned int spdif_in_f6_pins[] = { GPIOF_6 }; +static const unsigned int spdif_in_f7_pins[] = { GPIOF_7 }; + +/* sw */ +static const unsigned int swclk_pins[] = { GPIOF_4 }; +static const unsigned int swdio_pins[] = { GPIOF_5 }; + +/* clk_25 */ +static const unsigned int clk25_pins[] = { GPIOF_10 }; + +/* cec_a */ +static const unsigned int cec_a_pins[] = { GPIOF_2 }; + +/* cec_b */ +static const unsigned int cec_b_pins[] = { GPIOF_2 }; + +/* clk12_24 */ +static const unsigned int clk12_24_pins[] = { GPIOF_10 }; + +/* mclk_0 */ +static const unsigned int mclk_0_pins[] = { GPIOA_0 }; + +/* tdm_b */ +static const unsigned int tdm_b_sclk_pins[] = { GPIOA_1 }; +static const unsigned int tdm_b_fs_pins[] = { GPIOA_2 }; +static const unsigned int tdm_b_dout0_pins[] = { GPIOA_3 }; +static const unsigned int tdm_b_dout1_pins[] = { GPIOA_4 }; +static const unsigned int tdm_b_dout2_pins[] = { GPIOA_5 }; +static const unsigned int tdm_b_dout3_pins[] = { GPIOA_6 }; +static const unsigned int tdm_b_dout4_pins[] = { GPIOA_7 }; +static const unsigned int tdm_b_dout5_pins[] = { GPIOA_8 }; +static const unsigned int tdm_b_slv_sclk_pins[] = { GPIOA_5 }; +static const unsigned int tdm_b_slv_fs_pins[] = { GPIOA_6 }; +static const unsigned int tdm_b_din0_pins[] = { GPIOA_7 }; +static const unsigned int tdm_b_din1_pins[] = { GPIOA_8 }; +static const unsigned int tdm_b_din2_pins[] = { GPIOA_9 }; + +/* mclk_vad */ +static const unsigned int mclk_vad_pins[] = { GPIOA_0 }; + +/* tdm_vad */ +static const unsigned int tdm_vad_sclk_a1_pins[] = { GPIOA_1 }; +static const unsigned int tdm_vad_fs_a2_pins[] = { GPIOA_2 }; +static const unsigned int tdm_vad_sclk_a5_pins[] = { GPIOA_5 }; +static const unsigned int tdm_vad_fs_a6_pins[] = { GPIOA_6 }; + +/* tst_out */ +static const unsigned int tst_out0_pins[] = { GPIOA_0 }; +static const unsigned int tst_out1_pins[] = { GPIOA_1 }; +static const unsigned int tst_out2_pins[] = { GPIOA_2 }; +static const unsigned int tst_out3_pins[] = { GPIOA_3 }; +static const unsigned int tst_out4_pins[] = { GPIOA_4 }; +static const unsigned int tst_out5_pins[] = { GPIOA_5 }; +static const unsigned int tst_out6_pins[] = { GPIOA_6 }; +static const unsigned int tst_out7_pins[] = { GPIOA_7 }; +static const unsigned int tst_out8_pins[] = { GPIOA_8 }; +static const unsigned int tst_out9_pins[] = { GPIOA_9 }; +static const unsigned int tst_out10_pins[] = { GPIOA_10 }; +static const unsigned int tst_out11_pins[] = { GPIOA_11 }; + +/* mute */ +static const unsigned int mute_key_pins[] = { GPIOA_4 }; +static const unsigned int mute_en_pins[] = { GPIOA_5 }; + +static struct meson_pmx_group meson_a1_periphs_groups[] = { + GPIO_GROUP(GPIOP_0, 0), + GPIO_GROUP(GPIOP_1, 0), + GPIO_GROUP(GPIOP_2, 0), + GPIO_GROUP(GPIOP_3, 0), + GPIO_GROUP(GPIOP_4, 0), + GPIO_GROUP(GPIOP_5, 0), + GPIO_GROUP(GPIOP_6, 0), + GPIO_GROUP(GPIOP_7, 0), + GPIO_GROUP(GPIOP_8, 0), + GPIO_GROUP(GPIOP_9, 0), + GPIO_GROUP(GPIOP_10, 0), + GPIO_GROUP(GPIOP_11, 0), + GPIO_GROUP(GPIOP_12, 0), + GPIO_GROUP(GPIOB_0, 0), + GPIO_GROUP(GPIOB_1, 0), + GPIO_GROUP(GPIOB_2, 0), + GPIO_GROUP(GPIOB_3, 0), + GPIO_GROUP(GPIOB_4, 0), + GPIO_GROUP(GPIOB_5, 0), + GPIO_GROUP(GPIOB_6, 0), + GPIO_GROUP(GPIOX_0, 0), + GPIO_GROUP(GPIOX_1, 0), + GPIO_GROUP(GPIOX_2, 0), + GPIO_GROUP(GPIOX_3, 0), + GPIO_GROUP(GPIOX_4, 0), + GPIO_GROUP(GPIOX_5, 0), + GPIO_GROUP(GPIOX_6, 0), + GPIO_GROUP(GPIOX_7, 0), + GPIO_GROUP(GPIOX_8, 0), + GPIO_GROUP(GPIOX_9, 0), + GPIO_GROUP(GPIOX_10, 0), + GPIO_GROUP(GPIOX_11, 0), + GPIO_GROUP(GPIOX_12, 0), + GPIO_GROUP(GPIOX_13, 0), + GPIO_GROUP(GPIOX_14, 0), + GPIO_GROUP(GPIOX_15, 0), + GPIO_GROUP(GPIOX_16, 0), + GPIO_GROUP(GPIOF_0, 0), + GPIO_GROUP(GPIOF_1, 0), + GPIO_GROUP(GPIOF_2, 0), + GPIO_GROUP(GPIOF_3, 0), + GPIO_GROUP(GPIOF_4, 0), + GPIO_GROUP(GPIOF_5, 0), + GPIO_GROUP(GPIOF_6, 0), + GPIO_GROUP(GPIOF_7, 0), + GPIO_GROUP(GPIOF_8, 0), + GPIO_GROUP(GPIOF_9, 0), + GPIO_GROUP(GPIOF_10, 0), + GPIO_GROUP(GPIOF_11, 0), + GPIO_GROUP(GPIOF_12, 0), + GPIO_GROUP(GPIOA_0, 0), + GPIO_GROUP(GPIOA_1, 0), + GPIO_GROUP(GPIOA_2, 0), + GPIO_GROUP(GPIOA_3, 0), + GPIO_GROUP(GPIOA_4, 0), + GPIO_GROUP(GPIOA_5, 0), + GPIO_GROUP(GPIOA_6, 0), + GPIO_GROUP(GPIOA_7, 0), + GPIO_GROUP(GPIOA_8, 0), + GPIO_GROUP(GPIOA_9, 0), + GPIO_GROUP(GPIOA_10, 0), + GPIO_GROUP(GPIOA_11, 0), + + /* bank P func1 */ + GROUP(psram_clkn, 1), + GROUP(psram_clkp, 1), + GROUP(psram_ce_n, 1), + GROUP(psram_rst_n, 1), + GROUP(psram_adq0, 1), + GROUP(psram_adq1, 1), + GROUP(psram_adq2, 1), + GROUP(psram_adq3, 1), + GROUP(psram_adq4, 1), + GROUP(psram_adq5, 1), + GROUP(psram_adq6, 1), + GROUP(psram_adq7, 1), + GROUP(psram_dqs_dm, 1), + + /* bank P func2 */ + GROUP(pwm_e_p, 2), + + /* bank B func1 */ + GROUP(spif_mo, 1), + GROUP(spif_mi, 1), + GROUP(spif_wp_n, 1), + GROUP(spif_hold_n, 1), + GROUP(spif_clk, 1), + GROUP(spif_cs, 1), + GROUP(pwm_f_b, 1), + + /* bank B func2 */ + GROUP(sdcard_d0_b, 2), + GROUP(sdcard_d1_b, 2), + GROUP(sdcard_d2_b, 2), + GROUP(sdcard_d3_b, 2), + GROUP(sdcard_clk_b, 2), + GROUP(sdcard_cmd_b, 2), + + /* bank X func1 */ + GROUP(sdcard_d0_x, 1), + GROUP(sdcard_d1_x, 1), + GROUP(sdcard_d2_x, 1), + GROUP(sdcard_d3_x, 1), + GROUP(sdcard_clk_x, 1), + GROUP(sdcard_cmd_x, 1), + GROUP(pwm_a_x6, 1), + GROUP(tdm_a_dout1, 1), + GROUP(tdm_a_dout0, 1), + GROUP(tdm_a_fs, 1), + GROUP(tdm_a_sclk, 1), + GROUP(uart_a_tx, 1), + GROUP(uart_a_rx, 1), + GROUP(uart_a_cts, 1), + GROUP(uart_a_rts, 1), + GROUP(pwm_d_x15, 1), + GROUP(pwm_e_x16, 1), + + /* bank X func2 */ + GROUP(i2c2_sck_x0, 2), + GROUP(i2c2_sda_x1, 2), + GROUP(spi_a_mosi_x2, 2), + GROUP(spi_a_ss0_x3, 2), + GROUP(spi_a_sclk_x4, 2), + GROUP(spi_a_miso_x5, 2), + GROUP(tdm_a_din1, 2), + GROUP(tdm_a_din0, 2), + GROUP(tdm_a_slv_fs, 2), + GROUP(tdm_a_slv_sclk, 2), + GROUP(i2c3_sck_x, 2), + GROUP(i2c3_sda_x, 2), + GROUP(pwm_d_x13, 2), + GROUP(pwm_e_x14, 2), + GROUP(i2c2_sck_x15, 2), + GROUP(i2c2_sda_x16, 2), + + /* bank X func3 */ + GROUP(uart_c_tx_x0, 3), + GROUP(uart_c_rx_x1, 3), + GROUP(uart_c_cts, 3), + GROUP(uart_c_rts, 3), + GROUP(pdm_din0_x, 3), + GROUP(pdm_din1_x, 3), + GROUP(pdm_din2_x, 3), + GROUP(pdm_dclk_x, 3), + GROUP(uart_c_tx_x15, 3), + GROUP(uart_c_rx_x16, 3), + + /* bank X func4 */ + GROUP(pwm_e_x2, 4), + GROUP(pwm_f_x, 4), + GROUP(spi_a_mosi_x7, 4), + GROUP(spi_a_miso_x8, 4), + GROUP(spi_a_ss0_x9, 4), + GROUP(spi_a_sclk_x10, 4), + + /* bank X func5 */ + GROUP(uart_b_tx_x, 5), + GROUP(uart_b_rx_x, 5), + GROUP(i2c1_sda_x, 5), + GROUP(i2c1_sck_x, 5), + + /* bank X func6 */ + GROUP(pwm_a_x7, 6), + GROUP(pwm_b_x, 6), + GROUP(pwm_c_x, 6), + GROUP(pwm_d_x10, 6), + + /* bank X func7 */ + GROUP(gen_clk_x, 7), + + /* bank F func1 */ + GROUP(uart_b_tx_f, 1), + GROUP(uart_b_rx_f, 1), + GROUP(remote_input_f, 1), + GROUP(jtag_a_clk, 1), + GROUP(jtag_a_tms, 1), + GROUP(jtag_a_tdi, 1), + GROUP(jtag_a_tdo, 1), + GROUP(gen_clk_f8, 1), + GROUP(pwm_a_f10, 1), + GROUP(i2c0_sck_f11, 1), + GROUP(i2c0_sda_f12, 1), + + /* bank F func2 */ + GROUP(clk_32k_in, 2), + GROUP(pwm_e_f, 2), + GROUP(pwm_f_f4, 2), + GROUP(remote_out, 2), + GROUP(spdif_in_f6, 2), + GROUP(spdif_in_f7, 2), + GROUP(pwm_a_hiz_f8, 2), + GROUP(pwm_a_hiz_f10, 2), + GROUP(pwm_d_f, 2), + GROUP(pwm_f_f12, 2), + + /* bank F func3 */ + GROUP(pwm_c_f3, 3), + GROUP(swclk, 3), + GROUP(swdio, 3), + GROUP(pwm_a_f6, 3), + GROUP(pwm_b_f, 3), + GROUP(pwm_c_f8, 3), + GROUP(clk25, 3), + GROUP(i2c_slave_sck_f, 3), + GROUP(i2c_slave_sda_f, 3), + + /* bank F func4 */ + GROUP(cec_a, 4), + GROUP(i2c3_sck_f, 4), + GROUP(i2c3_sda_f, 4), + GROUP(pmw_a_hiz_f6, 4), + GROUP(pwm_b_hiz, 4), + GROUP(pwm_c_hiz, 4), + GROUP(i2c0_sck_f9, 4), + GROUP(i2c0_sda_f10, 4), + + /* bank F func5 */ + GROUP(cec_b, 5), + GROUP(clk12_24, 5), + + /* bank F func7 */ + GROUP(gen_clk_f10, 7), + + /* bank A func1 */ + GROUP(mclk_0, 1), + GROUP(tdm_b_sclk, 1), + GROUP(tdm_b_fs, 1), + GROUP(tdm_b_dout0, 1), + GROUP(tdm_b_dout1, 1), + GROUP(tdm_b_dout2, 1), + GROUP(tdm_b_dout3, 1), + GROUP(tdm_b_dout4, 1), + GROUP(tdm_b_dout5, 1), + GROUP(remote_input_a, 1), + + /* bank A func2 */ + GROUP(pwm_e_a, 2), + GROUP(tdm_b_slv_sclk, 2), + GROUP(tdm_b_slv_fs, 2), + GROUP(tdm_b_din0, 2), + GROUP(tdm_b_din1, 2), + GROUP(tdm_b_din2, 2), + GROUP(i2c1_sda_a, 2), + GROUP(i2c1_sck_a, 2), + + /* bank A func3 */ + GROUP(i2c2_sck_a4, 3), + GROUP(i2c2_sda_a5, 3), + GROUP(pdm_din2_a, 3), + GROUP(pdm_din1_a, 3), + GROUP(pdm_din0_a, 3), + GROUP(pdm_dclk, 3), + GROUP(pwm_c_a, 3), + GROUP(pwm_b_a, 3), + + /* bank A func4 */ + GROUP(pwm_a_a, 4), + GROUP(spi_a_mosi_a, 4), + GROUP(spi_a_miso_a, 4), + GROUP(spi_a_ss0_a, 4), + GROUP(spi_a_sclk_a, 4), + GROUP(i2c_slave_sck_a, 4), + GROUP(i2c_slave_sda_a, 4), + + /* bank A func5 */ + GROUP(mclk_vad, 5), + GROUP(tdm_vad_sclk_a1, 5), + GROUP(tdm_vad_fs_a2, 5), + GROUP(tdm_vad_sclk_a5, 5), + GROUP(tdm_vad_fs_a6, 5), + GROUP(i2c2_sck_a8, 5), + GROUP(i2c2_sda_a9, 5), + + /* bank A func6 */ + GROUP(tst_out0, 6), + GROUP(tst_out1, 6), + GROUP(tst_out2, 6), + GROUP(tst_out3, 6), + GROUP(tst_out4, 6), + GROUP(tst_out5, 6), + GROUP(tst_out6, 6), + GROUP(tst_out7, 6), + GROUP(tst_out8, 6), + GROUP(tst_out9, 6), + GROUP(tst_out10, 6), + GROUP(tst_out11, 6), + + /* bank A func7 */ + GROUP(mute_key, 7), + GROUP(mute_en, 7), + GROUP(gen_clk_a, 7), +}; + +static const char * const gpio_periphs_groups[] = { + "GPIOP_0", "GPIOP_1", "GPIOP_2", "GPIOP_3", "GPIOP_4", + "GPIOP_5", "GPIOP_6", "GPIOP_7", "GPIOP_8", "GPIOP_9", + "GPIOP_10", "GPIOP_11", "GPIOP_12", + + "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", + "GPIOB_5", "GPIOB_6", + + "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4", + "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9", + "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14", + "GPIOX_15", "GPIOX_16", + + "GPIOF_0", "GPIOF_1", "GPIOF_2", "GPIOF_3", "GPIOF_4", + "GPIOF_5", "GPIOF_6", "GPIOF_7", "GPIOF_8", "GPIOF_9", + "GPIOF_10", "GPIOF_11", "GPIOF_12", + + "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", + "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", + "GPIOA_10", "GPIOA_11", +}; + +static const char * const psram_groups[] = { + "psram_clkn", "psram_clkp", "psram_ce_n", "psram_rst_n", "psram_adq0", + "psram_adq1", "psram_adq2", "psram_adq3", "psram_adq4", "psram_adq5", + "psram_adq6", "psram_adq7", "psram_dqs_dm", +}; + +static const char * const pwm_a_groups[] = { + "pwm_a_x6", "pwm_a_x7", "pwm_a_f10", "pwm_a_f6", "pwm_a_a", +}; + +static const char * const pwm_b_groups[] = { + "pwm_b_x", "pwm_b_f", "pwm_b_a", +}; + +static const char * const pwm_c_groups[] = { + "pwm_c_x", "pwm_c_f3", "pwm_c_f8", "pwm_c_a", +}; + +static const char * const pwm_d_groups[] = { + "pwm_d_x15", "pwm_d_x13", "pwm_d_x10", "pwm_d_f", +}; + +static const char * const pwm_e_groups[] = { + "pwm_e_p", "pwm_e_x16", "pwm_e_x14", "pwm_e_x2", "pwm_e_f", + "pwm_e_a", +}; + +static const char * const pwm_f_groups[] = { + "pwm_f_b", "pwm_f_x", "pwm_f_f4", "pwm_f_f12", +}; + +static const char * const pwm_a_hiz_groups[] = { + "pwm_a_hiz_f8", "pwm_a_hiz_f10", "pwm_a_hiz_f6", +}; + +static const char * const pwm_b_hiz_groups[] = { + "pwm_b_hiz", +}; + +static const char * const pwm_c_hiz_groups[] = { + "pwm_c_hiz", +}; + +static const char * const spif_groups[] = { + "spif_mo", "spif_mi", "spif_wp_n", "spif_hold_n", "spif_clk", + "spif_cs", +}; + +static const char * const sdcard_groups[] = { + "sdcard_d0_b", "sdcard_d1_b", "sdcard_d2_b", "sdcard_d3_b", + "sdcard_clk_b", "sdcard_cmd_b", + + "sdcard_d0_x", "sdcard_d1_x", "sdcard_d2_x", "sdcard_d3_x", + "sdcard_clk_x", "sdcard_cmd_x", +}; + +static const char * const tdm_a_groups[] = { + "tdm_a_din0", "tdm_a_din1", "tdm_a_fs", "tdm_a_sclk", + "tdm_a_slv_fs", "tdm_a_slv_sclk", "tdm_a_dout0", "tdm_a_dout1", +}; + +static const char * const uart_a_groups[] = { + "uart_a_tx", "uart_a_rx", "uart_a_cts", "uart_a_rts", +}; + +static const char * const uart_b_groups[] = { + "uart_b_tx_x", "uart_b_rx_x", "uart_b_tx_f", "uart_b_rx_f", +}; + +static const char * const uart_c_groups[] = { + "uart_c_tx_x0", "uart_c_rx_x1", "uart_c_cts", "uart_c_rts", + "uart_c_tx_x15", "uart_c_rx_x16", +}; + +static const char * const i2c0_groups[] = { + "i2c0_sck_f11", "i2c0_sda_f12", "i2c0_sck_f9", "i2c0_sda_f10", +}; + +static const char * const i2c1_groups[] = { + "i2c1_sda_x", "i2c1_sck_x", "i2c1_sda_a", "i2c1_sck_a", +}; + +static const char * const i2c2_groups[] = { + "i2c2_sck_x0", "i2c2_sda_x1", "i2c2_sck_x15", "i2c2_sda_x16", + "i2c2_sck_a4", "i2c2_sda_a5", "i2c2_sck_a8", "i2c2_sda_a9", +}; + +static const char * const i2c3_groups[] = { + "i2c3_sck_x", "i2c3_sda_x", "i2c3_sck_f", "i2c3_sda_f", +}; + +static const char * const spi_a_groups[] = { + "spi_a_mosi_x2", "spi_a_ss0_x3", "spi_a_sclk_x4", "spi_a_miso_x5", + "spi_a_mosi_x7", "spi_a_miso_x8", "spi_a_ss0_x9", "spi_a_sclk_x10", + + "spi_a_mosi_a", "spi_a_miso_a", "spi_a_ss0_a", "spi_a_sclk_a", +}; + +static const char * const pdm_groups[] = { + "pdm_din0_x", "pdm_din1_x", "pdm_din2_x", "pdm_dclk_x", "pdm_din2_a", + "pdm_din1_a", "pdm_din0_a", "pdm_dclk", +}; + +static const char * const gen_clk_groups[] = { + "gen_clk_x", "gen_clk_f8", "gen_clk_f10", "gen_clk_a", +}; + +static const char * const remote_input_groups[] = { + "remote_input_f", + "remote_input_a", +}; + +static const char * const jtag_a_groups[] = { + "jtag_a_clk", "jtag_a_tms", "jtag_a_tdi", "jtag_a_tdo", +}; + +static const char * const clk_32k_in_groups[] = { + "clk_32k_in", +}; + +static const char * const remote_out_groups[] = { + "remote_out", +}; + +static const char * const spdif_in_groups[] = { + "spdif_in_f6", "spdif_in_f7", +}; + +static const char * const sw_groups[] = { + "swclk", "swdio", +}; + +static const char * const clk25_groups[] = { + "clk_25", +}; + +static const char * const cec_a_groups[] = { + "cec_a", +}; + +static const char * const cec_b_groups[] = { + "cec_b", +}; + +static const char * const clk12_24_groups[] = { + "clk12_24", +}; + +static const char * const mclk_0_groups[] = { + "mclk_0", +}; + +static const char * const tdm_b_groups[] = { + "tdm_b_din0", "tdm_b_din1", "tdm_b_din2", + "tdm_b_sclk", "tdm_b_fs", "tdm_b_dout0", "tdm_b_dout1", + "tdm_b_dout2", "tdm_b_dout3", "tdm_b_dout4", "tdm_b_dout5", + "tdm_b_slv_sclk", "tdm_b_slv_fs", +}; + +static const char * const mclk_vad_groups[] = { + "mclk_vad", +}; + +static const char * const tdm_vad_groups[] = { + "tdm_vad_sclk_a1", "tdm_vad_fs_a2", "tdm_vad_sclk_a5", "tdm_vad_fs_a6", +}; + +static const char * const tst_out_groups[] = { + "tst_out0", "tst_out1", "tst_out2", "tst_out3", + "tst_out4", "tst_out5", "tst_out6", "tst_out7", + "tst_out8", "tst_out9", "tst_out10", "tst_out11", +}; + +static const char * const mute_groups[] = { + "mute_key", "mute_en", +}; + +static struct meson_pmx_func meson_a1_periphs_functions[] = { + FUNCTION(gpio_periphs), + FUNCTION(psram), + FUNCTION(pwm_a), + FUNCTION(pwm_b), + FUNCTION(pwm_c), + FUNCTION(pwm_d), + FUNCTION(pwm_e), + FUNCTION(pwm_f), + FUNCTION(pwm_a_hiz), + FUNCTION(pwm_b_hiz), + FUNCTION(pwm_c_hiz), + FUNCTION(spif), + FUNCTION(sdcard), + FUNCTION(tdm_a), + FUNCTION(uart_a), + FUNCTION(uart_b), + FUNCTION(uart_c), + FUNCTION(i2c0), + FUNCTION(i2c1), + FUNCTION(i2c2), + FUNCTION(i2c3), + FUNCTION(spi_a), + FUNCTION(pdm), + FUNCTION(gen_clk), + FUNCTION(remote_input), + FUNCTION(jtag_a), + FUNCTION(clk_32k_in), + FUNCTION(remote_out), + FUNCTION(spdif_in), + FUNCTION(sw), + FUNCTION(clk25), + FUNCTION(cec_a), + FUNCTION(cec_b), + FUNCTION(clk12_24), + FUNCTION(mclk_0), + FUNCTION(tdm_b), + FUNCTION(mclk_vad), + FUNCTION(tdm_vad), + FUNCTION(tst_out), + FUNCTION(mute), +}; + +static struct meson_bank meson_a1_periphs_banks[] = { + /* name first last pullen pull dir out in ds */ + BANK_DS("P", GPIOP_0, GPIOP_12, 0x3, 0, 0x4, 0, 0x2, 0, 0x1, 0, 0x0, 0, 0x5, 0), + BANK_DS("B", GPIOB_0, GPIOB_6, 0x13, 0, 0x14, 0, 0x12, 0, 0x11, 0, 0x10, 0, 0x15, 0), + BANK_DS("X", GPIOX_0, GPIOX_16, 0x23, 0, 0x24, 0, 0x22, 0, 0x21, 0, 0x20, 0, 0x25, 0), + BANK_DS("F", GPIOF_0, GPIOF_12, 0x33, 0, 0x34, 0, 0x32, 0, 0x31, 0, 0x30, 0, 0x35, 0), + BANK_DS("A", GPIOA_0, GPIOA_11, 0x43, 0, 0x44, 0, 0x42, 0, 0x41, 0, 0x40, 0, 0x45, 0), +}; + +static struct meson_pmx_bank meson_a1_periphs_pmx_banks[] = { + /* name first last reg offset */ + BANK_PMX("P", GPIOP_0, GPIOP_12, 0x0, 0), + BANK_PMX("B", GPIOB_0, GPIOB_6, 0x2, 0), + BANK_PMX("X", GPIOX_0, GPIOX_16, 0x3, 0), + BANK_PMX("F", GPIOF_0, GPIOF_12, 0x6, 0), + BANK_PMX("A", GPIOA_0, GPIOA_11, 0x8, 0), +}; + +static struct meson_axg_pmx_data meson_a1_periphs_pmx_banks_data = { + .pmx_banks = meson_a1_periphs_pmx_banks, + .num_pmx_banks = ARRAY_SIZE(meson_a1_periphs_pmx_banks), +}; + +static struct meson_pinctrl_data meson_a1_periphs_pinctrl_data = { + .name = "periphs-banks", + .groups = meson_a1_periphs_groups, + .funcs = meson_a1_periphs_functions, + .banks = meson_a1_periphs_banks, + .num_pins = 62, + .num_groups = ARRAY_SIZE(meson_a1_periphs_groups), + .num_funcs = ARRAY_SIZE(meson_a1_periphs_functions), + .num_banks = ARRAY_SIZE(meson_a1_periphs_banks), + .pmx_data = &meson_a1_periphs_pmx_banks_data, +}; + +static const struct udevice_id meson_a1_pinctrl_match[] = { + { + .compatible = "amlogic,meson-a1-periphs-pinctrl", + .data = (ulong)&meson_a1_periphs_pinctrl_data, + }, + { }, +}; + +U_BOOT_DRIVER(meson_a1_pinctrl) = { + .name = "meson-a1-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(meson_a1_pinctrl_match), + .probe = meson_pinctrl_probe, + .priv_auto = sizeof(struct meson_pinctrl), + .ops = &meson_axg_pinctrl_ops, +}; diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index 1ad8bfbd880..92513822e70 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -1552,12 +1552,12 @@ static int npcm7xx_pinconf_set(struct udevice *dev, unsigned int pin, setbits_le32(base + NPCM7XX_GP_N_OES, BIT(gpio)); case PIN_CONFIG_OUTPUT: dev_dbg(dev, "set pin %d output %d\n", pin, arg); - clrbits_le32(base + NPCM7XX_GP_N_IEM, BIT(gpio)); - setbits_le32(base + NPCM7XX_GP_N_OES, BIT(gpio)); if (arg) setbits_le32(base + NPCM7XX_GP_N_DOUT, BIT(gpio)); else clrbits_le32(base + NPCM7XX_GP_N_DOUT, BIT(gpio)); + clrbits_le32(base + NPCM7XX_GP_N_IEM, BIT(gpio)); + setbits_le32(base + NPCM7XX_GP_N_OES, BIT(gpio)); break; case PIN_CONFIG_DRIVE_PUSH_PULL: dev_dbg(dev, "set pin %d push pull\n", pin); diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index 0ec47e9577e..f18be08518e 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -900,12 +900,12 @@ static int npcm8xx_pinconf_set(struct udevice *dev, unsigned int selector, setbits_le32(base + GPIO_OES, BIT(gpio)); case PIN_CONFIG_OUTPUT: dev_dbg(dev, "set pin %d output %d\n", pin, arg); - clrbits_le32(base + GPIO_IEM, BIT(gpio)); - setbits_le32(base + GPIO_OES, BIT(gpio)); if (arg) setbits_le32(base + GPIO_DOUT, BIT(gpio)); else clrbits_le32(base + GPIO_DOUT, BIT(gpio)); + clrbits_le32(base + GPIO_IEM, BIT(gpio)); + setbits_le32(base + GPIO_OES, BIT(gpio)); break; case PIN_CONFIG_DRIVE_PUSH_PULL: dev_dbg(dev, "set pin %d push pull\n", pin); diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 7e1b8c072fa..411c210756a 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -68,6 +68,13 @@ config MESON_EE_POWER_DOMAIN Enable support for manipulating Amlogic Meson Everything-Else power domains. +config MESON_SECURE_POWER_DOMAIN + bool "Enable Amlogic Secure power domain driver" + depends on POWER_DOMAIN && ARCH_MESON && MESON_A1 + help + Enable support for manipulating Amlogic Meson Secure power domains. + Support for Amlogic A1 series. + config SANDBOX_POWER_DOMAIN bool "Enable the sandbox power domain test driver" depends on POWER_DOMAIN && SANDBOX diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index e6244776216..aa5a4ba57cd 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_IMX8MP_HSIOMIX_BLKCTRL) += imx8mp-hsiomix.o obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o +obj-$(CONFIG_MESON_SECURE_POWER_DOMAIN) += meson-secure-pwrc.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o diff --git a/drivers/power/domain/meson-secure-pwrc.c b/drivers/power/domain/meson-secure-pwrc.c new file mode 100644 index 00000000000..f70f8e02423 --- /dev/null +++ b/drivers/power/domain/meson-secure-pwrc.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * Author: Alexey Romanov <avromanov@sberdevices.ru> + */ + +#include <dm.h> +#include <asm/arch/sm.h> +#include <power-domain.h> +#include <power-domain-uclass.h> +#include <dt-bindings/power/meson-a1-power.h> + +struct meson_secure_pwrc_domain_desc { + char *name; + size_t index; +}; + +struct meson_secure_pwrc_domain_data { + unsigned int count; + struct meson_secure_pwrc_domain_desc *domains; +}; + +struct meson_secure_pwrc_priv { + const struct meson_secure_pwrc_domain_data *data; +}; + +static int meson_secure_pwrc_on(struct power_domain *power_domain) +{ + struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev); + struct meson_secure_pwrc_domain_desc *pwrc_domain; + int err; + + pwrc_domain = &priv->data->domains[power_domain->id]; + + err = meson_sm_pwrdm_on(pwrc_domain->index); + if (err) { + pr_err("meson_sm_pwrdm_on() failed (%d)\n", err); + return err; + } + + pr_debug("enable %s power domain\n", pwrc_domain->name); + + return 0; +} + +static int meson_secure_pwrc_off(struct power_domain *power_domain) +{ + struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev); + struct meson_secure_pwrc_domain_desc *pwrc_domain; + int err; + + pwrc_domain = &priv->data->domains[power_domain->id]; + + err = meson_sm_pwrdm_off(pwrc_domain->index); + if (err) { + pr_err("meson_sm_pwrdm_off() failed (%d)\n", err); + return err; + } + + pr_debug("disable %s power domain\n", pwrc_domain->name); + + return 0; +} + +static int meson_secure_pwrc_of_xlate(struct power_domain *power_domain, + struct ofnode_phandle_args *args) +{ + struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev); + struct meson_secure_pwrc_domain_desc *pwrc_domain; + + if (args->args_count < 1) { + pr_err("invalid args count: %d\n", args->args_count); + return -EINVAL; + } + + power_domain->id = args->args[0]; + + if (power_domain->id >= priv->data->count) { + pr_err("domain with ID=%lu is invalid\n", power_domain->id); + return -EINVAL; + } + + pwrc_domain = &priv->data->domains[power_domain->id]; + + if (!pwrc_domain->name) { + pr_err("domain with ID=%lu is invalid\n", power_domain->id); + return -EINVAL; + } + + return 0; +} + +#define SEC_PD(__name) \ +[PWRC_##__name##_ID] = \ +{ \ + .name = #__name, \ + .index = PWRC_##__name##_ID, \ +} + +static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = { + SEC_PD(DSPA), + SEC_PD(DSPB), + SEC_PD(UART), + SEC_PD(DMC), + SEC_PD(I2C), + SEC_PD(PSRAM), + SEC_PD(ACODEC), + SEC_PD(AUDIO), + SEC_PD(OTP), + SEC_PD(DMA), + SEC_PD(SD_EMMC), + SEC_PD(RAMA), + SEC_PD(RAMB), + SEC_PD(IR), + SEC_PD(SPICC), + SEC_PD(SPIFC), + SEC_PD(USB), + SEC_PD(NIC), + SEC_PD(PDMIN), + SEC_PD(RSA), +}; + +struct power_domain_ops meson_secure_pwrc_ops = { + .on = meson_secure_pwrc_on, + .off = meson_secure_pwrc_off, + .of_xlate = meson_secure_pwrc_of_xlate, +}; + +static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = { + .count = ARRAY_SIZE(a1_pwrc_domains), + .domains = a1_pwrc_domains, +}; + +static const struct udevice_id meson_secure_pwrc_ids[] = { + { + .compatible = "amlogic,meson-a1-pwrc", + .data = (unsigned long)&meson_secure_a1_pwrc_data, + }, + { } +}; + +static int meson_secure_pwrc_probe(struct udevice *dev) +{ + struct meson_secure_pwrc_priv *priv = dev_get_priv(dev); + + priv->data = (void *)dev_get_driver_data(dev); + if (!priv->data) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(meson_secure_pwrc) = { + .name = "meson_secure_pwrc", + .id = UCLASS_POWER_DOMAIN, + .of_match = meson_secure_pwrc_ids, + .probe = meson_secure_pwrc_probe, + .ops = &meson_secure_pwrc_ops, + .priv_auto = sizeof(struct meson_secure_pwrc_priv), +}; diff --git a/drivers/power/domain/zynqmp-power-domain.c b/drivers/power/domain/zynqmp-power-domain.c index adbbb5fdd93..5ee9e020fb3 100644 --- a/drivers/power/domain/zynqmp-power-domain.c +++ b/drivers/power/domain/zynqmp-power-domain.c @@ -23,12 +23,17 @@ static int zynqmp_pm_request_node(const u32 node, const u32 capabilities, static int zynqmp_power_domain_request(struct power_domain *power_domain) { + int ret = 0; + dev_dbg(power_domain->dev, "Request for id: %ld\n", power_domain->id); - if (IS_ENABLED(CONFIG_ARCH_ZYNQMP)) - return zynqmp_pmufw_node(power_domain->id); + if (IS_ENABLED(CONFIG_ARCH_ZYNQMP)) { + ret = zynqmp_pmufw_node(power_domain->id); + if (ret == -ENODEV) + ret = 0; + } - return 0; + return ret; } static int zynqmp_power_domain_free(struct power_domain *power_domain) diff --git a/drivers/power/pmic/stpmic1.c b/drivers/power/pmic/stpmic1.c index 2c85410b1bf..8701d4f971c 100644 --- a/drivers/power/pmic/stpmic1.c +++ b/drivers/power/pmic/stpmic1.c @@ -34,7 +34,9 @@ static const struct pmic_child_info stpmic1_children_info[] = { { .prefix = "ldo", .driver = "stpmic1_ldo" }, { .prefix = "buck", .driver = "stpmic1_buck" }, { .prefix = "vref_ddr", .driver = "stpmic1_vref_ddr" }, + { .prefix = "vref-ddr", .driver = "stpmic1_vref_ddr" }, { .prefix = "pwr_sw", .driver = "stpmic1_pwr_sw" }, + { .prefix = "pwr-sw", .driver = "stpmic1_pwr_sw" }, { .prefix = "boost", .driver = "stpmic1_boost" }, { }, }; diff --git a/drivers/power/regulator/fan53555.c b/drivers/power/regulator/fan53555.c index 5681206bbaf..815f96beef6 100644 --- a/drivers/power/regulator/fan53555.c +++ b/drivers/power/regulator/fan53555.c @@ -101,7 +101,7 @@ struct fan53555_priv { static int fan53555_regulator_of_to_plat(struct udevice *dev) { - struct fan53555_plat *dev_pdata = dev_get_plat(dev); + struct fan53555_plat *plat = dev_get_plat(dev); struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); u32 sleep_vsel; @@ -118,12 +118,12 @@ static int fan53555_regulator_of_to_plat(struct udevice *dev) */ switch (sleep_vsel) { case FAN53555_VSEL0: - dev_pdata->sleep_reg = FAN53555_VSEL0; - dev_pdata->vol_reg = FAN53555_VSEL1; + plat->sleep_reg = FAN53555_VSEL0; + plat->vol_reg = FAN53555_VSEL1; break; case FAN53555_VSEL1: - dev_pdata->sleep_reg = FAN53555_VSEL1; - dev_pdata->vol_reg = FAN53555_VSEL0; + plat->sleep_reg = FAN53555_VSEL1; + plat->vol_reg = FAN53555_VSEL0; break; default: pr_err("%s: invalid vsel id %d\n", dev->name, sleep_vsel); diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index 90004d1601a..ad3b4b98d66 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -24,16 +24,16 @@ struct fixed_clock_regulator_plat { static int fixed_regulator_of_to_plat(struct udevice *dev) { struct dm_regulator_uclass_plat *uc_pdata; - struct regulator_common_plat *dev_pdata; + struct regulator_common_plat *plat; - dev_pdata = dev_get_plat(dev); + plat = dev_get_plat(dev); uc_pdata = dev_get_uclass_plat(dev); if (!uc_pdata) return -ENXIO; uc_pdata->type = REGULATOR_TYPE_FIXED; - return regulator_common_of_to_plat(dev, dev_pdata, "gpio"); + return regulator_common_of_to_plat(dev, plat, "gpio"); } static int fixed_regulator_get_value(struct udevice *dev) @@ -88,7 +88,7 @@ static int fixed_clock_regulator_get_enable(struct udevice *dev) static int fixed_clock_regulator_set_enable(struct udevice *dev, bool enable) { struct fixed_clock_regulator_plat *priv = dev_get_priv(dev); - struct regulator_common_plat *dev_pdata = dev_get_plat(dev); + struct regulator_common_plat *plat = dev_get_plat(dev); int ret = 0; if (enable) { @@ -101,11 +101,11 @@ static int fixed_clock_regulator_set_enable(struct udevice *dev, bool enable) if (ret) return ret; - if (enable && dev_pdata->startup_delay_us) - udelay(dev_pdata->startup_delay_us); + if (enable && plat->startup_delay_us) + udelay(plat->startup_delay_us); - if (!enable && dev_pdata->off_on_delay_us) - udelay(dev_pdata->off_on_delay_us); + if (!enable && plat->off_on_delay_us) + udelay(plat->off_on_delay_us); return ret; } diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c index 9c0a68aa5af..ded7be059bb 100644 --- a/drivers/power/regulator/gpio-regulator.c +++ b/drivers/power/regulator/gpio-regulator.c @@ -27,12 +27,12 @@ struct gpio_regulator_plat { static int gpio_regulator_of_to_plat(struct udevice *dev) { struct dm_regulator_uclass_plat *uc_pdata; - struct gpio_regulator_plat *dev_pdata; + struct gpio_regulator_plat *plat; struct gpio_desc *gpio; int ret, count, i, j; u32 states_array[GPIO_REGULATOR_MAX_STATES * 2]; - dev_pdata = dev_get_plat(dev); + plat = dev_get_plat(dev); uc_pdata = dev_get_uclass_plat(dev); if (!uc_pdata) return -ENXIO; @@ -47,7 +47,7 @@ static int gpio_regulator_of_to_plat(struct udevice *dev) * per gpio-regulator. As of now no instance with multiple * gpios is presnt */ - gpio = &dev_pdata->gpio; + gpio = &plat->gpio; ret = gpio_request_by_name(dev, "gpios", 0, gpio, GPIOD_IS_OUT); if (ret) debug("regulator gpio - not found! Error: %d", ret); @@ -68,21 +68,21 @@ static int gpio_regulator_of_to_plat(struct udevice *dev) return ret; for (i = 0, j = 0; i < count; i += 2) { - dev_pdata->voltages[j] = states_array[i]; - dev_pdata->states[j] = states_array[i + 1]; + plat->voltages[j] = states_array[i]; + plat->states[j] = states_array[i + 1]; j++; } - return regulator_common_of_to_plat(dev, &dev_pdata->common, "enable-gpios"); + return regulator_common_of_to_plat(dev, &plat->common, "enable-gpios"); } static int gpio_regulator_get_value(struct udevice *dev) { struct dm_regulator_uclass_plat *uc_pdata; - struct gpio_regulator_plat *dev_pdata = dev_get_plat(dev); + struct gpio_regulator_plat *plat = dev_get_plat(dev); int enable; - if (!dev_pdata->gpio.dev) + if (!plat->gpio.dev) return -ENOSYS; uc_pdata = dev_get_uclass_plat(dev); @@ -91,30 +91,30 @@ static int gpio_regulator_get_value(struct udevice *dev) return -EINVAL; } - enable = dm_gpio_get_value(&dev_pdata->gpio); - if (enable == dev_pdata->states[0]) - return dev_pdata->voltages[0]; + enable = dm_gpio_get_value(&plat->gpio); + if (enable == plat->states[0]) + return plat->voltages[0]; else - return dev_pdata->voltages[1]; + return plat->voltages[1]; } static int gpio_regulator_set_value(struct udevice *dev, int uV) { - struct gpio_regulator_plat *dev_pdata = dev_get_plat(dev); + struct gpio_regulator_plat *plat = dev_get_plat(dev); int ret; bool enable; - if (!dev_pdata->gpio.dev) + if (!plat->gpio.dev) return -ENOSYS; - if (uV == dev_pdata->voltages[0]) - enable = dev_pdata->states[0]; - else if (uV == dev_pdata->voltages[1]) - enable = dev_pdata->states[1]; + if (uV == plat->voltages[0]) + enable = plat->states[0]; + else if (uV == plat->voltages[1]) + enable = plat->states[1]; else return -EINVAL; - ret = dm_gpio_set_value(&dev_pdata->gpio, enable); + ret = dm_gpio_set_value(&plat->gpio, enable); if (ret) { pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, enable); @@ -126,14 +126,14 @@ static int gpio_regulator_set_value(struct udevice *dev, int uV) static int gpio_regulator_get_enable(struct udevice *dev) { - struct gpio_regulator_plat *dev_pdata = dev_get_plat(dev); - return regulator_common_get_enable(dev, &dev_pdata->common); + struct gpio_regulator_plat *plat = dev_get_plat(dev); + return regulator_common_get_enable(dev, &plat->common); } static int gpio_regulator_set_enable(struct udevice *dev, bool enable) { - struct gpio_regulator_plat *dev_pdata = dev_get_plat(dev); - return regulator_common_set_enable(dev, &dev_pdata->common, enable); + struct gpio_regulator_plat *plat = dev_get_plat(dev); + return regulator_common_set_enable(dev, &plat->common, enable); } static const struct dm_regulator_ops gpio_regulator_ops = { diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index d608f7c2365..3a6ba69f6d5 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -197,6 +197,12 @@ int regulator_set_enable_if_allowed(struct udevice *dev, bool enable) ret = regulator_set_enable(dev, enable); if (ret == -ENOSYS || ret == -EACCES) return 0; + /* if we want to disable but it's in use by someone else */ + if (!enable && ret == -EBUSY) + return 0; + /* if it's already enabled/disabled */ + if (ret == -EALREADY) + return 0; return ret; } diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c index 93d8196b381..e26f5ebec34 100644 --- a/drivers/power/regulator/regulator_common.c +++ b/drivers/power/regulator/regulator_common.c @@ -13,7 +13,7 @@ #include "regulator_common.h" int regulator_common_of_to_plat(struct udevice *dev, - struct regulator_common_plat *dev_pdata, + struct regulator_common_plat *plat, const char *enable_gpio_name) { struct gpio_desc *gpio; @@ -26,7 +26,7 @@ int regulator_common_of_to_plat(struct udevice *dev, flags |= GPIOD_IS_OUT_ACTIVE; /* Get optional enable GPIO desc */ - gpio = &dev_pdata->gpio; + gpio = &plat->gpio; ret = gpio_request_by_name(dev, enable_gpio_name, 0, gpio, flags); if (ret) { debug("Regulator '%s' optional enable GPIO - not found! Error: %d\n", @@ -36,12 +36,11 @@ int regulator_common_of_to_plat(struct udevice *dev, } /* Get optional ramp up delay */ - dev_pdata->startup_delay_us = dev_read_u32_default(dev, - "startup-delay-us", 0); - dev_pdata->off_on_delay_us = - dev_read_u32_default(dev, "off-on-delay-us", 0); - if (!dev_pdata->off_on_delay_us) { - dev_pdata->off_on_delay_us = + plat->startup_delay_us = dev_read_u32_default(dev, + "startup-delay-us", 0); + plat->off_on_delay_us = dev_read_u32_default(dev, "off-on-delay-us", 0); + if (!plat->off_on_delay_us) { + plat->off_on_delay_us = dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0); } @@ -49,43 +48,65 @@ int regulator_common_of_to_plat(struct udevice *dev, } int regulator_common_get_enable(const struct udevice *dev, - struct regulator_common_plat *dev_pdata) + struct regulator_common_plat *plat) { /* Enable GPIO is optional */ - if (!dev_pdata->gpio.dev) + if (!plat->gpio.dev) return true; - return dm_gpio_get_value(&dev_pdata->gpio); + return dm_gpio_get_value(&plat->gpio); } int regulator_common_set_enable(const struct udevice *dev, - struct regulator_common_plat *dev_pdata, bool enable) + struct regulator_common_plat *plat, bool enable) { int ret; debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__, - dev->name, enable, dev_pdata->startup_delay_us, - dm_gpio_is_valid(&dev_pdata->gpio)); + dev->name, enable, plat->startup_delay_us, + dm_gpio_is_valid(&plat->gpio)); /* Enable GPIO is optional */ - if (!dm_gpio_is_valid(&dev_pdata->gpio)) { + if (!dm_gpio_is_valid(&plat->gpio)) { if (!enable) return -ENOSYS; return 0; } - ret = dm_gpio_set_value(&dev_pdata->gpio, enable); + /* If previously enabled, increase count */ + if (enable && plat->enable_count > 0) { + plat->enable_count++; + return -EALREADY; + } + + if (!enable) { + if (plat->enable_count > 1) { + /* If enabled multiple times, decrease count */ + plat->enable_count--; + return -EBUSY; + } else if (!plat->enable_count) { + /* If already disabled, do nothing */ + return -EALREADY; + } + } + + ret = dm_gpio_set_value(&plat->gpio, enable); if (ret) { pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, enable); return ret; } - if (enable && dev_pdata->startup_delay_us) - udelay(dev_pdata->startup_delay_us); + if (enable && plat->startup_delay_us) + udelay(plat->startup_delay_us); debug("%s: done\n", __func__); - if (!enable && dev_pdata->off_on_delay_us) - udelay(dev_pdata->off_on_delay_us); + if (!enable && plat->off_on_delay_us) + udelay(plat->off_on_delay_us); + + if (enable) + plat->enable_count++; + else + plat->enable_count--; return 0; } diff --git a/drivers/power/regulator/regulator_common.h b/drivers/power/regulator/regulator_common.h index c10492f0167..d4962899d83 100644 --- a/drivers/power/regulator/regulator_common.h +++ b/drivers/power/regulator/regulator_common.h @@ -13,14 +13,35 @@ struct regulator_common_plat { struct gpio_desc gpio; /* GPIO for regulator enable control */ unsigned int startup_delay_us; unsigned int off_on_delay_us; + unsigned int enable_count; }; int regulator_common_of_to_plat(struct udevice *dev, - struct regulator_common_plat *dev_pdata, const + struct regulator_common_plat *plat, const char *enable_gpio_name); int regulator_common_get_enable(const struct udevice *dev, - struct regulator_common_plat *dev_pdata); + struct regulator_common_plat *plat); +/* + * Enable or Disable a regulator + * + * This is a reentrant function and subsequent calls that enable will + * increase an internal counter, and disable calls will decrease the counter. + * The actual resource will be enabled when the counter gets to 1 coming from 0, + * and disabled when it reaches 0 coming from 1. + * + * @dev: regulator device + * @plat: Platform data + * @enable: bool indicating whether to enable or disable the regulator + * @return: + * 0 on Success + * -EBUSY if the regulator cannot be disabled because it's requested by + * another device + * -EALREADY if the regulator has already been enabled or has already been + * disabled + * -EACCES if there is no possibility to enable/disable the regulator + * -ve on different error situation + */ int regulator_common_set_enable(const struct udevice *dev, - struct regulator_common_plat *dev_pdata, bool enable); + struct regulator_common_plat *plat, bool enable); #endif /* _REGULATOR_COMMON_H */ diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index 2ba92bf9c48..0085113f674 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -18,6 +18,7 @@ #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/delay.h> +#include <linux/iopoll.h> #include "serial_stm32.h" #include <dm/device_compat.h> @@ -28,6 +29,10 @@ static void _stm32_serial_setbrg(fdt_addr_t base, { bool stm32f4 = uart_info->stm32f4; u32 int_div, mantissa, fraction, oversampling; + u8 uart_enable_bit = uart_info->uart_enable_bit; + + /* BRR register must be set when uart is disabled */ + clrbits_le32(base + CR1_OFFSET(stm32f4), BIT(uart_enable_bit)); int_div = DIV_ROUND_CLOSEST(clock_rate, baudrate); @@ -43,6 +48,8 @@ static void _stm32_serial_setbrg(fdt_addr_t base, fraction = int_div % oversampling; writel(mantissa | fraction, base + BRR_OFFSET(stm32f4)); + + setbits_le32(base + CR1_OFFSET(stm32f4), BIT(uart_enable_bit)); } static int stm32_serial_setbrg(struct udevice *dev, int baudrate) @@ -181,9 +188,12 @@ static int stm32_serial_probe(struct udevice *dev) struct stm32x7_serial_plat *plat = dev_get_plat(dev); struct clk clk; struct reset_ctl reset; + u32 isr; int ret; + bool stm32f4; plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev); + stm32f4 = plat->uart_info->stm32f4; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) @@ -195,6 +205,17 @@ static int stm32_serial_probe(struct udevice *dev) return ret; } + /* + * before uart initialization, wait for TC bit (Transmission Complete) + * in case there is still chars from previous bootstage to transmit + */ + ret = read_poll_timeout(readl, isr, isr & USART_ISR_TC, 10, 150, + plat->base + ISR_OFFSET(stm32f4)); + if (ret) { + clk_disable(&clk); + return ret; + } + ret = reset_get_by_index(dev, 0, &reset); if (!ret) { reset_assert(&reset); diff --git a/drivers/serial/serial_stm32.h b/drivers/serial/serial_stm32.h index 5bee68fa9c2..b7e7a90b931 100644 --- a/drivers/serial/serial_stm32.h +++ b/drivers/serial/serial_stm32.h @@ -66,6 +66,7 @@ struct stm32x7_serial_plat { #define USART_CR3_OVRDIS BIT(12) #define USART_ISR_TXE BIT(7) +#define USART_ISR_TC BIT(6) #define USART_ISR_RXNE BIT(5) #define USART_ISR_ORE BIT(3) #define USART_ISR_FE BIT(1) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 4f435fd2681..453a5983b2a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -382,7 +382,7 @@ config SPI_QUP config RENESAS_RPC_SPI bool "Renesas RPC SPI driver" depends on RCAR_64 || RZA1 - imply SPI_FLASH_BAR + imply SPI_FLASH_SFDP_SUPPORT help Enable the Renesas RPC SPI driver, used to access SPI NOR flash on Renesas RCar Gen3 SoCs. This uses driver model and requires a diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 1cbb5d46fd6..ff7b55f8707 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -347,20 +347,28 @@ static void _omap3_spi_set_wordlen(struct omap3_spi_priv *priv) omap3_spi_write_chconf(priv, confr); } -static void spi_reset(struct mcspi *regs) +static void spi_reset(struct omap3_spi_priv *priv) { unsigned int tmp; - writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, ®s->sysconfig); + writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &priv->regs->sysconfig); do { - tmp = readl(®s->sysstatus); + tmp = readl(&priv->regs->sysstatus); } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE)); writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE | OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP | - OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, ®s->sysconfig); + OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, &priv->regs->sysconfig); - writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, ®s->wakeupenable); + writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &priv->regs->wakeupenable); + + /* + * Set the same default mode for each channel, especially CS polarity + * which must be common for all SPI slaves before any transfer. + */ + for (priv->cs = 0 ; priv->cs < OMAP4_MCSPI_CHAN_NB ; priv->cs++) + _omap3_spi_set_mode(priv); + priv->cs = 0; } static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv) @@ -430,7 +438,7 @@ static int omap3_spi_probe(struct udevice *dev) priv->pin_dir = plat->pin_dir; priv->wordlen = SPI_DEFAULT_WORDLEN; - spi_reset(priv->regs); + spi_reset(priv); return 0; } diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c index cb2b8fb64de..51c37d72eb6 100644 --- a/drivers/spi/renesas_rpc_spi.c +++ b/drivers/spi/renesas_rpc_spi.c @@ -17,6 +17,7 @@ #include <linux/bug.h> #include <linux/errno.h> #include <spi.h> +#include <spi-mem.h> #include <wait_bit.h> #define RPC_CMNCR 0x0000 /* R/W */ @@ -140,6 +141,7 @@ #define PRC_PHYCNT_EXDS BIT(21) #define RPC_PHYCNT_OCT BIT(20) #define RPC_PHYCNT_STRTIM(v) (((v) & 0x7) << 15) +#define RPC_PHYCNT_STRTIM2(v) ((((v) & 0x7) << 15) | (((v) & 0x8) << 24)) #define RPC_PHYCNT_WBUF2 BIT(4) #define RPC_PHYCNT_WBUF BIT(2) #define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0) @@ -167,10 +169,6 @@ struct rpc_spi_priv { fdt_addr_t regs; fdt_addr_t extr; struct clk clk; - - u8 cmdcopy[8]; - u32 cmdlen; - bool cmdstarted; }; static int rpc_spi_wait_sslf(struct udevice *dev) @@ -202,18 +200,35 @@ static void rpc_spi_flush_read_cache(struct udevice *dev) } +static u32 rpc_spi_get_strobe_delay(void) +{ +#ifndef CONFIG_RZA1 + u32 cpu_type = rmobile_get_cpu_type(); + + /* + * NOTE: RPC_PHYCNT_STRTIM value: + * 0: On H3 ES1.x (not supported in mainline U-Boot) + * 6: On M3 ES1.x + * 7: On other R-Car Gen3 + * 15: On R-Car Gen4 + */ + if (cpu_type == RMOBILE_CPU_TYPE_R8A7796 && rmobile_get_cpu_rev_integer() == 1) + return RPC_PHYCNT_STRTIM(6); + else if (cpu_type == RMOBILE_CPU_TYPE_R8A779F0 || + cpu_type == RMOBILE_CPU_TYPE_R8A779G0) + return RPC_PHYCNT_STRTIM2(15); + else +#endif + return RPC_PHYCNT_STRTIM(7); +} + static int rpc_spi_claim_bus(struct udevice *dev, bool manual) { struct udevice *bus = dev->parent; struct rpc_spi_priv *priv = dev_get_priv(bus); - /* - * NOTE: The 0x260 are undocumented bits, but they must be set. - * NOTE: On H3 ES1.x (not supported in mainline U-Boot), the - * RPC_PHYCNT_STRTIM shall be 0, while on newer parts, the - * RPC_PHYCNT_STRTIM shall be 6. - */ - writel(RPC_PHYCNT_CAL | RPC_PHYCNT_STRTIM(6) | 0x260, + /* NOTE: The 0x260 are undocumented bits, but they must be set. */ + writel(RPC_PHYCNT_CAL | rpc_spi_get_strobe_delay() | 0x260, priv->regs + RPC_PHYCNT); writel((manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_SFDE | RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | RPC_CMNCR_BSZ(0), @@ -233,79 +248,91 @@ static int rpc_spi_release_bus(struct udevice *dev) struct rpc_spi_priv *priv = dev_get_priv(bus); /* NOTE: The 0x260 are undocumented bits, but they must be set. */ - writel(RPC_PHYCNT_STRTIM(6) | 0x260, priv->regs + RPC_PHYCNT); + writel(rpc_spi_get_strobe_delay() | 0x260, priv->regs + RPC_PHYCNT); rpc_spi_flush_read_cache(dev); return 0; } -static int rpc_spi_xfer(struct udevice *dev, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int rpc_spi_mem_exec_op(struct spi_slave *spi, + const struct spi_mem_op *op) { - struct udevice *bus = dev->parent; + struct udevice *bus = spi->dev->parent; struct rpc_spi_priv *priv = dev_get_priv(bus); - u32 wlen = dout ? (bitlen / 8) : 0; - u32 rlen = din ? (bitlen / 8) : 0; - u32 wloop = DIV_ROUND_UP(wlen, 4); - u32 smenr, smcr, offset; + const void *dout = op->data.buf.out ? op->data.buf.out : NULL; + void *din = op->data.buf.in ? op->data.buf.in : NULL; int ret = 0; - - if (!priv->cmdstarted) { - if (!wlen || rlen) - BUG(); - - memcpy(priv->cmdcopy, dout, wlen); - priv->cmdlen = wlen; - - /* Command transfer start */ - priv->cmdstarted = true; - if (!(flags & SPI_XFER_END)) - return 0; - } - - offset = (priv->cmdcopy[1] << 16) | (priv->cmdcopy[2] << 8) | - (priv->cmdcopy[3] << 0); + u32 offset = 0; + u32 smenr, smcr; smenr = 0; + offset = op->addr.val; + + switch (op->data.dir) { + case SPI_MEM_DATA_IN: + rpc_spi_claim_bus(spi->dev, false); + + writel(0, priv->regs + RPC_DRCMR); + writel(RPC_DRCMR_CMD(op->cmd.opcode), priv->regs + RPC_DRCMR); + smenr |= RPC_DRENR_CDE; + + writel(0, priv->regs + RPC_DREAR); + if (op->addr.nbytes == 4) { + writel(RPC_DREAR_EAV(offset >> 25) | RPC_DREAR_EAC(1), + priv->regs + RPC_DREAR); + smenr |= RPC_DRENR_ADE(0xF); + } else if (op->addr.nbytes == 3) { + smenr |= RPC_DRENR_ADE(0x7); + } else { + smenr |= RPC_DRENR_ADE(0); + } - if (wlen || (!rlen && !wlen) || flags == SPI_XFER_ONCE) { - if (wlen && flags == SPI_XFER_END) - smenr = RPC_SMENR_SPIDE(0xf); + writel(0, priv->regs + RPC_DRDMCR); + if (op->dummy.nbytes) { + writel(8 * op->dummy.nbytes - 1, priv->regs + RPC_DRDMCR); + smenr |= RPC_DRENR_DME; + } - rpc_spi_claim_bus(dev, true); + writel(0, priv->regs + RPC_DROPR); + writel(smenr, priv->regs + RPC_DRENR); - writel(0, priv->regs + RPC_SMCR); + memcpy_fromio(din, (void *)(priv->extr + offset), op->data.nbytes); - if (priv->cmdlen >= 1) { /* Command(1) */ - writel(RPC_SMCMR_CMD(priv->cmdcopy[0]), - priv->regs + RPC_SMCMR); - smenr |= RPC_SMENR_CDE; - } else { - writel(0, priv->regs + RPC_SMCMR); - } + rpc_spi_release_bus(spi->dev); + break; + case SPI_MEM_DATA_OUT: + case SPI_MEM_NO_DATA: + rpc_spi_claim_bus(spi->dev, true); - if (priv->cmdlen >= 4) { /* Address(3) */ - writel(offset, priv->regs + RPC_SMADR); - smenr |= RPC_SMENR_ADE(7); - } else { - writel(0, priv->regs + RPC_SMADR); - } + writel(0, priv->regs + RPC_SMCR); + writel(0, priv->regs + RPC_SMCMR); + writel(RPC_SMCMR_CMD(op->cmd.opcode), priv->regs + RPC_SMCMR); + smenr |= RPC_SMENR_CDE; + + writel(0, priv->regs + RPC_SMADR); + if (op->addr.nbytes == 4) + smenr |= RPC_SMENR_ADE(0xF); + else if (op->addr.nbytes == 3) + smenr |= RPC_SMENR_ADE(0x7); + else + smenr |= RPC_SMENR_ADE(0); + writel(offset, priv->regs + RPC_SMADR); - if (priv->cmdlen >= 5) { /* Dummy(n) */ - writel(8 * (priv->cmdlen - 4) - 1, - priv->regs + RPC_SMDMCR); + writel(0, priv->regs + RPC_SMDMCR); + if (op->dummy.nbytes) { + writel(8 * op->dummy.nbytes - 1, priv->regs + RPC_SMDMCR); smenr |= RPC_SMENR_DME; - } else { - writel(0, priv->regs + RPC_SMDMCR); } writel(0, priv->regs + RPC_SMOPR); - writel(0, priv->regs + RPC_SMDRENR); - if (wlen && flags == SPI_XFER_END) { + if (dout && op->data.nbytes) { u32 *datout = (u32 *)dout; + u32 wloop = DIV_ROUND_UP(op->data.nbytes, 4); + + smenr |= RPC_SMENR_SPIDE(0xF); while (wloop--) { smcr = RPC_SMCR_SPIWE | RPC_SMCR_SPIE; @@ -314,57 +341,28 @@ static int rpc_spi_xfer(struct udevice *dev, unsigned int bitlen, writel(smenr, priv->regs + RPC_SMENR); writel(*datout, priv->regs + RPC_SMWDR0); writel(smcr, priv->regs + RPC_SMCR); - ret = rpc_spi_wait_tend(dev); - if (ret) - goto err; + ret = rpc_spi_wait_tend(spi->dev); + if (ret) { + rpc_spi_release_bus(spi->dev); + return ret; + } datout++; - smenr = RPC_SMENR_SPIDE(0xf); + smenr &= (~RPC_SMENR_CDE & ~RPC_SMENR_ADE(0xF)); } - ret = rpc_spi_wait_sslf(dev); - + ret = rpc_spi_wait_sslf(spi->dev); } else { writel(smenr, priv->regs + RPC_SMENR); writel(RPC_SMCR_SPIE, priv->regs + RPC_SMCR); - ret = rpc_spi_wait_tend(dev); - } - } else { /* Read data only, using DRx ext access */ - rpc_spi_claim_bus(dev, false); - - if (priv->cmdlen >= 1) { /* Command(1) */ - writel(RPC_DRCMR_CMD(priv->cmdcopy[0]), - priv->regs + RPC_DRCMR); - smenr |= RPC_DRENR_CDE; - } else { - writel(0, priv->regs + RPC_DRCMR); - } - - if (priv->cmdlen >= 4) /* Address(3) */ - smenr |= RPC_DRENR_ADE(7); - - if (priv->cmdlen >= 5) { /* Dummy(n) */ - writel(8 * (priv->cmdlen - 4) - 1, - priv->regs + RPC_DRDMCR); - smenr |= RPC_DRENR_DME; - } else { - writel(0, priv->regs + RPC_DRDMCR); + ret = rpc_spi_wait_tend(spi->dev); } - writel(0, priv->regs + RPC_DROPR); - - writel(smenr, priv->regs + RPC_DRENR); - - if (rlen) - memcpy_fromio(din, (void *)(priv->extr + offset), rlen); - else - readl(priv->extr); /* Dummy read */ + rpc_spi_release_bus(spi->dev); + break; + default: + break; } -err: - priv->cmdstarted = false; - - rpc_spi_release_bus(dev); - return ret; } @@ -380,6 +378,10 @@ static int rpc_spi_set_mode(struct udevice *bus, uint mode) return 0; } +static const struct spi_controller_mem_ops rpc_spi_mem_ops = { + .exec_op = rpc_spi_mem_exec_op +}; + static int rpc_spi_bind(struct udevice *parent) { const void *fdt = gd->fdt_blob; @@ -443,9 +445,9 @@ static int rpc_spi_of_to_plat(struct udevice *bus) } static const struct dm_spi_ops rpc_spi_ops = { - .xfer = rpc_spi_xfer, .set_speed = rpc_spi_set_speed, .set_mode = rpc_spi_set_mode, + .mem_ops = &rpc_spi_mem_ops }; static const struct udevice_id rpc_spi_ids[] = { diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 7b64532e50b..572cef1694c 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -9,7 +9,7 @@ * Author: Robert Marko <robert.marko@sartura.hr> * Author: Luka Kovacic <luka.kovacic@sartura.hr> * - * Based on stock U-boot and Linux drivers + * Based on stock U-Boot and Linux drivers */ #include <asm/gpio.h> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 94fb32d107c..a972d87c7ad 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -126,6 +126,28 @@ config USB_HUB_DEBOUNCE_TIMEOUT value = 1s because some usb device needs around 1.5s to be initialized and a 2s value should solve detection issue on problematic USB keys. +if SPL_USB_HOST + +comment "USB peripherals in SPL" + +config SPL_USB_STORAGE + bool "Support loading from USB" + help + Enable support for USB devices in SPL. This allows use of USB + devices such as hard drives and flash drivers for loading U-Boot. + The actual drivers are enabled separately using the normal U-Boot + config options. This enables loading from USB using a configured + device. + +config SYS_USB_FAT_BOOT_PARTITION + int "Partition on USB to use to load U-Boot from" + depends on SPL_USB_STORAGE + default 1 + help + Partition on the USB storage device to load U-Boot from. + +endif + if USB_KEYBOARD config USB_KEYBOARD_FN_KEYS diff --git a/drivers/usb/eth/lan78xx.c b/drivers/usb/eth/lan78xx.c index 37912a1d040..1d8267c80bb 100644 --- a/drivers/usb/eth/lan78xx.c +++ b/drivers/usb/eth/lan78xx.c @@ -146,11 +146,9 @@ static int lan78xx_read_otp(struct usb_device *udev, u32 offset, ret = lan78xx_read_raw_otp(udev, 0, 1, &sig); if (!ret) { - if (sig == LAN78XX_OTP_INDICATOR_1) - offset = offset; - else if (sig == LAN78XX_OTP_INDICATOR_2) + if (sig == LAN78XX_OTP_INDICATOR_2) offset += 0x100; - else + else if (sig != LAN78XX_OTP_INDICATOR_1) return -EINVAL; ret = lan78xx_read_raw_otp(udev, offset, length, data); if (ret) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 941f97c96d0..1cfe6022842 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -36,6 +36,12 @@ menuconfig USB_GADGET peripheral/device side bus controller, and a "gadget driver" for your peripheral protocol. +config SPL_USB_GADGET + bool "USB Gadget Support in SPL" + help + Enable USB Gadget API which allows to enable USB device functions + in SPL. + if USB_GADGET config USB_GADGET_MANUFACTURER @@ -265,3 +271,85 @@ config USBNET_HOST_ADDR endif # USB_ETHER endif # USB_GADGET + +if SPL_USB_GADGET + +config SPL_USB_ETHER + bool "Support USB Ethernet drivers in SPL" + depends on SPL_NET + help + Enable access to the USB network subsystem and associated + drivers in SPL. This permits SPL to load U-Boot over a + USB-connected Ethernet link (such as a USB Ethernet dongle) rather + than from an onboard peripheral. Environment support is required + since the network stack uses a number of environment variables. + See also SPL_NET and SPL_ETH. + +if SPL_USB_ETHER + +choice + prompt "USB Ethernet Gadget Model in SPL" + default SPL_USB_ETH_RNDIS + help + There is several models (protocols) to implement Ethernet over USB + devices. The main ones are Microsoft's RNDIS and USB's CDC-Ethernet + (also called CDC-ECM). RNDIS is obviously compatible with Windows, + while CDC-ECM is not. Most other operating systems support both, so + if inter-operability is a concern, RNDIS is to be preferred. + +config SPL_USB_ETH_RNDIS + bool "RNDIS Protocol" + help + The RNDIS (Remote Network Driver Interface Specification) is a + Microsoft proprietary protocol to create an Ethernet device over USB. + Windows obviously supports it, as well as all the major operating + systems, so it's the best option for compatibility. + +endchoice + +endif # SPL_USB_ETHER + +config SPL_DFU + bool "Support DFU (Device Firmware Upgrade) in SPL" + select SPL_HASH + select SPL_DFU_NO_RESET + depends on SPL_RAM_SUPPORT + help + This feature enables the DFU (Device Firmware Upgrade) in SPL with + RAM memory device support. The ROM code will load and execute + the SPL built with dfu. The user can load binaries (u-boot/kernel) to + selected device partition from host-pc using dfu-utils. + This feature is useful to flash the binaries to factory or bare-metal + boards using USB interface. + +choice + bool "DFU device selection in SPL" + depends on SPL_DFU + +config SPL_DFU_RAM + bool "RAM device" + depends on SPL_DFU && SPL_RAM_SUPPORT + help + select RAM/DDR memory device for loading binary images + (u-boot/kernel) to the selected device partition using + DFU and execute the u-boot/kernel from RAM. + +endchoice + +config SPL_USB_SDP_SUPPORT + bool "Support SDP (Serial Download Protocol) in SPL" + depends on SPL_SERIAL + help + Enable Serial Download Protocol (SDP) device support in SPL. This + allows to download images into memory and execute (jump to) them + using the same protocol as implemented by the i.MX family's boot ROM. + +config SPL_SDP_USB_DEV + int "SDP USB controller index in SPL" + default 0 + depends on SPL_USB_SDP_SUPPORT + help + Some boards have USB controller other than 0. Define this option + so it can be used in compiled environment. + +endif # SPL_USB_GADGET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 6cfe0f3a041..6abcce0d9c7 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -3,8 +3,9 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_USB_GADGET) += epautoconf.o config.o usbstring.o -obj-$(CONFIG_USB_ETHER) += epautoconf.o config.o usbstring.o +obj-$(CONFIG_$(SPL_TPL_)USB_GADGET) += epautoconf.o config.o usbstring.o +obj-$(CONFIG_$(SPL_TPL_)USB_ETHER) += epautoconf.o config.o usbstring.o ether.o +obj-$(CONFIG_$(SPL_TPL_)USB_ETH_RNDIS) += rndis.o ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_USB_GADGET) += g_dnl.o @@ -34,9 +35,6 @@ endif obj-$(CONFIG_CI_UDC) += ci_udc.o -obj-$(CONFIG_USB_ETHER) += ether.o -obj-$(CONFIG_USB_ETH_RNDIS) += rndis.o - # Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE # This is really only N900 and USBTTY now. obj-$(CONFIG_USB_DEVICE) += core.o ep0.o diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 6213b3c95fa..1a883babf4c 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -6,6 +6,19 @@ comment "USB Host Controller Drivers" config USB_HOST bool select DM_USB + help + Enable access to USB (Universal Serial Bus) host devices so that + SPL can load U-Boot from a connected USB peripheral, such as a USB + flash stick. While USB takes a little longer to start up than most + buses, it is very flexible since many different types of storage + device can be attached. + +config SPL_USB_HOST + bool "Support USB host drivers" + depends on SPL + help + For detailed help see USB_HOST Kconfig symbol. This option enables + the drivers in drivers/usb/host as part of an SPL build. config USB_XHCI_HCD bool "xHCI HCD (USB 3.0) support" diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 1e2f4e6de4a..49762950719 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -740,14 +740,7 @@ config VIDEO_SEPS525 Enable support for the Syncoam PM-OLED display driver (RGB 160x128). Currently driver is supporting only SPI interface. -config VIDEO_ZYNQMP_DPSUB - bool "Enable video support for ZynqMP Display Port" - depends on ZYNQMP_POWER_DOMAIN - help - Enable support for Xilinx ZynqMP Display Port. Currently this file - is used as placeholder for driver. The main reason is to record - compatible string and calling power domain driver. - +source "drivers/video/zynqmp/Kconfig" source "drivers/video/nexell/Kconfig" config CONSOLE_SCROLL_LINES diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9a53cd14187..f99d7e3c3d9 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -73,7 +73,7 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o obj-$(CONFIG_VIDEO_VESA) += vesa.o obj-$(CONFIG_VIDEO_SEPS525) += seps525.o -obj-$(CONFIG_VIDEO_ZYNQMP_DPSUB) += zynqmp_dpsub.o +obj-$(CONFIG_VIDEO_ZYNQMP_DPSUB) += zynqmp/ obj-y += bridge/ obj-y += sunxi/ diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 8396bdfb11e..1b66a8061a7 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -220,14 +220,20 @@ u32 video_index_to_colour(struct video_priv *priv, unsigned int idx) break; case VIDEO_BPP32: if (CONFIG_IS_ENABLED(VIDEO_BPP32)) { - if (priv->format == VIDEO_X2R10G10B10) + switch (priv->format) { + case VIDEO_X2R10G10B10: return (colours[idx].r << 22) | (colours[idx].g << 12) | (colours[idx].b << 2); - else + case VIDEO_RGBA8888: + return (colours[idx].r << 24) | + (colours[idx].g << 16) | + (colours[idx].b << 8) | 0xff; + default: return (colours[idx].r << 16) | (colours[idx].g << 8) | (colours[idx].b << 0); + } } break; default: diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c index 47e52c4f69c..45f003c8251 100644 --- a/drivers/video/video_bmp.c +++ b/drivers/video/video_bmp.c @@ -43,6 +43,18 @@ static u32 get_bmp_col_x2r10g10b10(struct bmp_color_table_entry *cte) } /** + * get_bmp_col_rgba8888() - Convert a colour-table entry into a rgba8888 pixel value + * + * Return: value to write to the rgba8888 frame buffer for this palette entry + */ +static u32 get_bmp_col_rgba8888(struct bmp_color_table_entry *cte) +{ + return ((cte->red) | + (cte->green << 8U) | + (cte->blue << 16U) | 0xff << 24U); +} + +/** * write_pix8() - Write a pixel from a BMP image into the framebuffer * * This handles frame buffers with 8, 16, 24 or 32 bits per pixel @@ -71,6 +83,8 @@ static void write_pix8(u8 *fb, uint bpix, enum video_format eformat, *fb++ = cte->blue; } else if (eformat == VIDEO_X2R10G10B10) { *(u32 *)fb = get_bmp_col_x2r10g10b10(cte); + } else if (eformat == VIDEO_RGBA8888) { + *(u32 *)fb = get_bmp_col_rgba8888(cte); } else { *fb++ = cte->blue; *fb++ = cte->green; @@ -382,6 +396,17 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, *fb++ = (pix >> 8) & 0xff; *fb++ = (pix >> 16) & 0xff; *fb++ = pix >> 24; + } else if (eformat == VIDEO_RGBA8888) { + u32 pix; + + pix = *bmap++ << 8U; /* blue */ + pix |= *bmap++ << 16U; /* green */ + pix |= *bmap++ << 24U; /* red */ + + *fb++ = (pix >> 24) & 0xff; + *fb++ = (pix >> 16) & 0xff; + *fb++ = (pix >> 8) & 0xff; + *fb++ = 0xff; } else { *fb++ = *bmap++; *fb++ = *bmap++; @@ -409,6 +434,17 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, *fb++ = (pix >> 8) & 0xff; *fb++ = (pix >> 16) & 0xff; *fb++ = pix >> 24; + } else if (eformat == VIDEO_RGBA8888) { + u32 pix; + + pix = *bmap++ << 8U; /* blue */ + pix |= *bmap++ << 16U; /* green */ + pix |= *bmap++ << 24U; /* red */ + bmap++; + *fb++ = (pix >> 24) & 0xff; + *fb++ = (pix >> 16) & 0xff; + *fb++ = (pix >> 8) & 0xff; + *fb++ = 0xff; /* opacity */ } else { *fb++ = *bmap++; *fb++ = *bmap++; diff --git a/drivers/video/zynqmp/Kconfig b/drivers/video/zynqmp/Kconfig new file mode 100644 index 00000000000..b35cd1fb342 --- /dev/null +++ b/drivers/video/zynqmp/Kconfig @@ -0,0 +1,8 @@ + +config VIDEO_ZYNQMP_DPSUB + bool "Enable video support for ZynqMP Display Port" + depends on ZYNQMP_POWER_DOMAIN + help + Enable support for Xilinx ZynqMP Display Port. Currently this file + is used as placeholder for driver. The main reason is to record + compatible string and calling power domain driver. diff --git a/drivers/video/zynqmp/Makefile b/drivers/video/zynqmp/Makefile new file mode 100644 index 00000000000..cc057f53560 --- /dev/null +++ b/drivers/video/zynqmp/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2023, Advanced Micro Devices, Inc. + +obj-y += zynqmp_dpsub.o diff --git a/drivers/video/zynqmp/zynqmp_dpsub.c b/drivers/video/zynqmp/zynqmp_dpsub.c new file mode 100644 index 00000000000..def4dcf6261 --- /dev/null +++ b/drivers/video/zynqmp/zynqmp_dpsub.c @@ -0,0 +1,2225 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 - 2022, Xilinx Inc. + * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc. + * + * Xilinx displayport(DP) Tx Subsytem driver + */ + +#include <common.h> +#include <clk.h> +#include <cpu_func.h> +#include <dm.h> +#include <errno.h> +#include <generic-phy.h> +#include <stdlib.h> +#include <video.h> +#include <wait_bit.h> +#include <dm/device_compat.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <dm/device_compat.h> +#include <asm/global_data.h> + +#include "zynqmp_dpsub.h" + +DECLARE_GLOBAL_DATA_PTR; + +/* Maximum supported resolution */ +#define WIDTH 1024 +#define HEIGHT 768 + +static struct dp_dma dp_dma; +static struct dp_dma_descriptor cur_desc __aligned(256); + +static void dma_init_video_descriptor(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + struct dp_dma_frame_buffer *frame_buffer = &dp_sub->frame_buffer; + + cur_desc.control = DPDMA_DESC_PREAMBLE | DPDMA_DESC_IGNR_DONE | + DPDMA_DESC_LAST_FRAME; + cur_desc.dscr_id = 0; + cur_desc.xfer_size = frame_buffer->size; + cur_desc.line_size_stride = ((frame_buffer->stride >> 4) << + DPDMA_DESCRIPTOR_LINE_SIZE_STRIDE_SHIFT) | + (frame_buffer->line_size); + cur_desc.addr_ext = (((u32)(frame_buffer->address >> + DPDMA_DESCRIPTOR_SRC_ADDR_WIDTH) << + DPDMA_DESCRIPTOR_ADDR_EXT_SRC_ADDR_EXT_SHIFT) | + (upper_32_bits((u64)&cur_desc))); + cur_desc.next_desr = lower_32_bits((u64)&cur_desc); + cur_desc.src_addr = lower_32_bits((u64)gd->fb_base); +} + +static void dma_set_descriptor_address(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + flush_dcache_range((u64)&cur_desc, + ALIGN(((u64)&cur_desc + sizeof(cur_desc)), + CONFIG_SYS_CACHELINE_SIZE)); + writel(upper_32_bits((u64)&cur_desc), dp_sub->dp_dma->base_addr + + DPDMA_CH3_DSCR_STRT_ADDRE); + writel(lower_32_bits((u64)&cur_desc), dp_sub->dp_dma->base_addr + + DPDMA_CH3_DSCR_STRT_ADDR); +} + +static void dma_setup_channel(struct udevice *dev) +{ + dma_init_video_descriptor(dev); + dma_set_descriptor_address(dev); +} + +static void dma_set_channel_state(struct udevice *dev) +{ + u32 mask = 0, regval = 0; + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + mask = DPDMA_CH_CNTL_EN_MASK | DPDMA_CH_CNTL_PAUSE_MASK; + regval = DPDMA_CH_CNTL_EN_MASK; + + clrsetbits_le32(dp_sub->dp_dma->base_addr + DPDMA_CH3_CNTL, + mask, regval); +} + +static void dma_trigger(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 trigger; + + trigger = DPDMA_GBL_TRG_CH3_MASK; + dp_sub->dp_dma->gfx.trigger_status = DPDMA_TRIGGER_DONE; + writel(trigger, dp_sub->dp_dma->base_addr + DPDMA_GBL); +} + +static void dma_vsync_intr_handler(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + dma_setup_channel(dev); + dma_set_channel_state(dev); + dma_trigger(dev); + + /* Clear VSync Interrupt */ + writel(DPDMA_ISR_VSYNC_INT_MASK, dp_sub->dp_dma->base_addr + DPDMA_ISR); +} + +/** + * wait_phy_ready() - Wait for the DisplayPort PHY to come out of reset + * @dev: The DP device + * + * Return: 0 if wait succeeded, -ve if error occurred + */ +static int wait_phy_ready(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 timeout = 100, phy_status; + u8 phy_ready_mask = DP_PHY_STATUS_RESET_LANE_0_DONE_MASK | + DP_PHY_STATUS_GT_PLL_LOCK_MASK; + + /* Wait until the PHY is ready. */ + do { + udelay(20); + phy_status = readl(dp_sub->base_addr + DP_PHY_STATUS); + phy_status &= phy_ready_mask; + /* Protect against an infinite loop. */ + if (!timeout--) + return -ETIMEDOUT; + } while (phy_status != phy_ready_mask); + + return 0; +} + +static int init_dp_tx(struct udevice *dev) +{ + u32 status, phyval, regval, rate; + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + phyval = readl(dp_sub->base_addr + DP_PHY_CONFIG); + writel(DP_SOFT_RESET_EN, dp_sub->base_addr + DP_SOFT_RESET); + status = readl(dp_sub->base_addr + DP_SOFT_RESET); + writel(DP_DISABLE, dp_sub->base_addr + DP_ENABLE); + + regval = (readl(dp_sub->base_addr + DP_AUX_CLK_DIVIDER) & + ~DP_AUX_CLK_DIVIDER_VAL_MASK) | + (60 << 8) | + (dp_sub->clock / 1000000); + writel(regval, dp_sub->base_addr + DP_AUX_CLK_DIVIDER); + + writel(DP_PHY_CLOCK_SELECT_540GBPS, dp_sub->base_addr + DP_PHY_CLOCK_SELECT); + + regval = phyval & ~DP_PHY_CONFIG_GT_ALL_RESET_MASK; + writel(regval, dp_sub->base_addr + DP_PHY_CONFIG); + status = wait_phy_ready(dev); + if (status) + return -EINVAL; + + writel(DP_ENABLE, dp_sub->base_addr + DP_ENABLE); + + rate = ~DP_INTR_HPD_PULSE_DETECTED_MASK & ~DP_INTR_HPD_EVENT_MASK + & ~DP_INTR_HPD_IRQ_MASK; + writel(rate, dp_sub->base_addr + DP_INTR_MASK); + return 0; +} + +static int set_nonlive_gfx_format(struct udevice *dev, enum av_buf_video_format format) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + struct av_buf_vid_attribute *ptr = (struct av_buf_vid_attribute *)avbuf_supported_formats; + + while (1) { + dev_dbg(dev, "Format %d\n", ptr->video_format); + + if (!ptr->video_format) + return -EINVAL; + + if (ptr->video_format == format) { + dp_sub->non_live_graphics = ptr; + break; + } + ptr++; + } + dev_dbg(dev, "Video format found. BPP %d\n", dp_sub->non_live_graphics->bpp); + return 0; +} + +/* DP dma setup */ +static void set_qos(struct udevice *dev, u8 qos) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 index; + u32 regval = 0, mask; + + regval = (((u32)qos << DPDMA_CH_CNTL_QOS_DATA_RD_SHIFT) | + ((u32)qos << DPDMA_CH_CNTL_QOS_DSCR_RD_SHIFT) | + ((u32)qos << DPDMA_CH_CNTL_QOS_DSCR_WR_SHIFT)); + + mask = DPDMA_CH_CNTL_QOS_DATA_RD_MASK | + DPDMA_CH_CNTL_QOS_DSCR_RD_MASK | + DPDMA_CH_CNTL_QOS_DSCR_WR_MASK; + for (index = 0; index <= DPDMA_AUDIO_CHANNEL1; index++) { + clrsetbits_le32(dp_sub->dp_dma->base_addr + + DPDMA_CH0_CNTL + + (DPDMA_CH_OFFSET * (u32)index), + mask, regval); + } +} + +static void enable_gfx_buffers(struct udevice *dev, u8 enable) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 regval = 0; + + regval = (0xF << AVBUF_CHBUF3_BURST_LEN_SHIFT) | + AVBUF_CHBUF3_FLUSH_MASK; + writel(regval, dp_sub->base_addr + AVBUF_CHBUF3); + if (enable) { + regval = (0xF << AVBUF_CHBUF3_BURST_LEN_SHIFT) | + AVBUF_CHBUF0_EN_MASK; + writel(regval, dp_sub->base_addr + AVBUF_CHBUF3); + } +} + +static void avbuf_video_select(struct udevice *dev, enum av_buf_video_stream vid_stream, + enum av_buf_gfx_stream gfx_stream) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + dp_sub->av_mode.video_src = vid_stream; + dp_sub->av_mode.gfx_src = gfx_stream; + + clrsetbits_le32(dp_sub->base_addr + + AVBUF_BUF_OUTPUT_AUD_VID_SELECT, + AVBUF_BUF_OUTPUT_AUD_VID_SELECT_VID_STREAM2_SEL_MASK | + AVBUF_BUF_OUTPUT_AUD_VID_SELECT_VID_STREAM1_SEL_MASK, + vid_stream | gfx_stream); +} + +static void config_gfx_pipeline(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u16 *csc_matrix, *offset_matrix; + u32 regval = 0, index = 0, *scaling_factors = NULL; + u16 rgb_coeffs[] = { 0x1000, 0x0000, 0x0000, + 0x0000, 0x1000, 0x0000, + 0x0000, 0x0000, 0x1000 }; + u16 rgb_offset[] = { 0x0000, 0x0000, 0x0000 }; + struct av_buf_vid_attribute *video = dp_sub->non_live_graphics; + + scaling_factors = video->sf; + + clrsetbits_le32(dp_sub->base_addr + AVBUF_BUF_FORMAT, + AVBUF_BUF_FORMAT_NL_GRAPHX_FORMAT_MASK, + (video->value) << AVBUF_BUF_FORMAT_NL_GRAPHX_FORMAT_SHIFT); + + for (index = 0; index < 3; index++) { + writel(scaling_factors[index], dp_sub->base_addr + + AVBUF_BUF_GRAPHICS_COMP0_SCALE_FACTOR + (index * 4)); + } + regval = (video->is_rgb << AVBUF_V_BLEND_LAYER0_CONTROL_RGB_MODE_SHIFT) | + video->sampling_en; + writel(regval, dp_sub->base_addr + AVBUF_V_BLEND_LAYER1_CONTROL); + + if (video->is_rgb) { + csc_matrix = rgb_coeffs; + offset_matrix = rgb_offset; + } + /* Program Colorspace conversion coefficients */ + for (index = 9; index < 12; index++) { + writel(offset_matrix[index - 9], dp_sub->base_addr + + AVBUF_V_BLEND_IN2CSC_COEFF0 + (index * 4)); + } + + /* Program Colorspace conversion matrix */ + for (index = 0; index < 9; index++) { + writel(csc_matrix[index], dp_sub->base_addr + + AVBUF_V_BLEND_IN2CSC_COEFF0 + (index * 4)); + } +} + +static void set_blender_alpha(struct udevice *dev, u8 alpha, u8 enable) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 regval; + + regval = enable; + regval |= alpha << AVBUF_V_BLEND_SET_GLOBAL_ALPHA_REG_VALUE_SHIFT; + writel(regval, dp_sub->base_addr + + AVBUF_V_BLEND_SET_GLOBAL_ALPHA_REG); +} + +static void config_output_video(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 regval = 0, index; + u16 rgb_coeffs[] = { 0x1000, 0x0000, 0x0000, + 0x0000, 0x1000, 0x0000, + 0x0000, 0x0000, 0x1000 }; + u16 rgb_offset[] = { 0x0000, 0x0000, 0x0000 }; + u16 *matrix_coeff = rgb_coeffs, *matrix_offset = rgb_offset; + + struct av_buf_vid_attribute *output_video = dp_sub->non_live_graphics; + + regval |= output_video->sampling_en << + AVBUF_V_BLEND_OUTPUT_VID_FORMAT_EN_DOWNSAMPLE_SHIFT; + regval |= output_video->value; + writel(regval, dp_sub->base_addr + AVBUF_V_BLEND_OUTPUT_VID_FORMAT); + + for (index = 0; index < 9; index++) { + writel(matrix_coeff[index], dp_sub->base_addr + + AVBUF_V_BLEND_RGB2YCBCR_COEFF0 + (index * 4)); + } + + for (index = 0; index < 3; index++) { + writel((matrix_offset[index] << + AVBUF_V_BLEND_LUMA_IN1CSC_OFFSET_POST_OFFSET_SHIFT), + dp_sub->base_addr + + AVBUF_V_BLEND_LUMA_OUTCSC_OFFSET + + (index * 4)); + } + + set_blender_alpha(dev, 0, 0); +} + +static void config_msa_sync_clk_mode(struct udevice *dev, u8 enable) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + struct main_stream_attributes *msa_config; + + msa_config = &dp_sub->msa_config; + msa_config->synchronous_clock_mode = enable; + + if (enable == 1) { + msa_config->misc0 |= (1 << + DP_MAIN_STREAM_MISC0_COMPONENT_FORMAT_SHIFT); + } else { + msa_config->misc0 &= ~(1 << + DP_MAIN_STREAM_MISC0_COMPONENT_FORMAT_SHIFT); + } +} + +static void av_buf_soft_reset(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + writel(AVBUF_BUF_SRST_REG_VID_RST_MASK, + dp_sub->base_addr + AVBUF_BUF_SRST_REG); + writel(0, dp_sub->base_addr + AVBUF_BUF_SRST_REG); +} + +static void set_video_clk_source(struct udevice *dev, u8 video_clk, u8 audio_clk) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 regval = 0; + + if (dp_sub->av_mode.video_src != AVBUF_VIDSTREAM1_LIVE && + dp_sub->av_mode.gfx_src != AVBUF_VIDSTREAM2_LIVE_GFX) { + regval = 1 << AVBUF_BUF_AUD_VID_CLK_SOURCE_VID_TIMING_SRC_SHIFT; + } else if (dp_sub->av_mode.video_src == AVBUF_VIDSTREAM1_LIVE || + dp_sub->av_mode.gfx_src == AVBUF_VIDSTREAM2_LIVE_GFX) { + video_clk = AVBUF_PL_CLK; + } + + regval |= (video_clk << AVBUF_BUF_AUD_VID_CLK_SOURCE_VID_CLK_SRC_SHIFT) | + (audio_clk << AVBUF_BUF_AUD_VID_CLK_SOURCE_AUD_CLK_SRC_SHIFT); + writel(regval, dp_sub->base_addr + AVBUF_BUF_AUD_VID_CLK_SOURCE); + + av_buf_soft_reset(dev); +} + +static int init_dpdma_subsys(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + dp_sub->dp_dma->base_addr = DPDMA_BASE_ADDRESS; + dp_sub->dp_dma->gfx.channel.cur = NULL; + dp_sub->dp_dma->gfx.trigger_status = DPDMA_TRIGGER_DONE; + + set_qos(dev, 11); + return 0; +} + +/** + * is_dp_connected() - Check if there is a connected RX device + * @dev: The DP device + * + * + * Return: true if a connected RX device was detected, false otherwise + */ +static bool is_dp_connected(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status; + u8 retries = 0; + + do { + status = readl(dp_sub->base_addr + + DP_INTERRUPT_SIG_STATE) + & DP_INTERRUPT_SIG_STATE_HPD_STATE_MASK; + + if (retries > DP_IS_CONNECTED_MAX_TIMEOUT_COUNT) + return 0; + + retries++; + udelay(1000); + } while (status == 0); + + return 1; +} + +/** + * aux_wait_ready() - Wait until another request is no longer in progress + * @dev: The DP device + * + * Return: 0 if wait succeeded, -ve if error occurred + */ +static int aux_wait_ready(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status, timeout = 100; + + do { + status = readl(dp_sub->base_addr + + DP_INTERRUPT_SIG_STATE); + if (!timeout--) + return -ETIMEDOUT; + + udelay(20); + } while (status & DP_REPLY_STATUS_REPLY_IN_PROGRESS_MASK); + + return 0; +} + +/** + * aux_wait_reply() - Wait for reply on AUX channel + * @dev: The DP device + * + * Wait for a reply indicating that the most recent AUX request + * has been received by the RX device. + * + * Return: 0 if wait succeeded, -ve if error occurred + */ +static int aux_wait_reply(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 timeout = DP_AUX_MAX_WAIT, status; + + while (timeout > 0) { + status = readl(dp_sub->base_addr + DP_REPLY_STATUS); + if (status & DP_REPLY_STATUS_REPLY_ERROR_MASK) + return -ETIMEDOUT; + + if ((status & DP_REPLY_STATUS_REPLY_RECEIVED_MASK) && + !(status & DP_REPLY_STATUS_REQUEST_IN_PROGRESS_MASK) && + !(status & DP_REPLY_STATUS_REPLY_IN_PROGRESS_MASK)) { + return 0; + } + timeout--; + udelay(20); + } + return -ETIMEDOUT; +} + +/** + * aux_request_send() - Send request on the AUX channel + * @dev: The DP device + * @request: The request to send + * + * Submit the supplied AUX request to the RX device over the AUX + * channel by writing the command, the destination address, (the write buffer + * for write commands), and the data size to the DisplayPort TX core. + * + * This is the lower-level sending routine, which is called by aux_request(). + * + * Return: 0 if request was sent successfully, -ve on error + */ +static int aux_request_send(struct udevice *dev, struct aux_transaction *request) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 timeout_count = 0, status; + u8 index; + + do { + status = readl(dp_sub->base_addr + + DP_REPLY_STATUS); + + udelay(20); + timeout_count++; + if (timeout_count >= DP_AUX_MAX_TIMEOUT_COUNT) + return -ETIMEDOUT; + + } while ((status & DP_REPLY_STATUS_REQUEST_IN_PROGRESS_MASK) || + (status & DP_REPLY_STATUS_REPLY_IN_PROGRESS_MASK)); + /* Set the address for the request. */ + writel(request->address, dp_sub->base_addr + DP_AUX_ADDRESS); + + if (request->cmd_code == DP_AUX_CMD_WRITE || + request->cmd_code == DP_AUX_CMD_I2C_WRITE || + request->cmd_code == DP_AUX_CMD_I2C_WRITE_MOT) { + /* Feed write data into the DisplayPort TX core's write FIFO. */ + for (index = 0; index < request->num_bytes; index++) { + writel(request->data[index], + dp_sub->base_addr + + DP_AUX_WRITE_FIFO); + } + } + + status = ((request->cmd_code << DP_AUX_CMD_SHIFT) | + ((request->num_bytes - 1) & + DP_AUX_CMD_NBYTES_TRANSFER_MASK)); + + /* Submit the command and the data size. */ + writel(((request->cmd_code << DP_AUX_CMD_SHIFT) | + ((request->num_bytes - 1) & DP_AUX_CMD_NBYTES_TRANSFER_MASK)), + dp_sub->base_addr + DP_AUX_CMD); + + /* Check for a reply from the RX device to the submitted request. */ + status = aux_wait_reply(dev); + if (status) + /* Waiting for a reply timed out. */ + return -ETIMEDOUT; + + /* Analyze the reply. */ + status = readl(dp_sub->base_addr + DP_AUX_REPLY_CODE); + if (status == DP_AUX_REPLY_CODE_DEFER || + status == DP_AUX_REPLY_CODE_I2C_DEFER) { + /* The request was deferred. */ + return -EAGAIN; + } else if (status == DP_AUX_REPLY_CODE_NACK || + status == DP_AUX_REPLY_CODE_I2C_NACK) { + /* The request was not acknowledged. */ + return -EIO; + } + + /* The request was acknowledged. */ + if (request->cmd_code == DP_AUX_CMD_READ || + request->cmd_code == DP_AUX_CMD_I2C_READ || + request->cmd_code == DP_AUX_CMD_I2C_READ_MOT) { + /* Wait until all data has been received. */ + timeout_count = 0; + do { + status = readl(dp_sub->base_addr + + DP_REPLY_DATA_COUNT); + udelay(100); + timeout_count++; + if (timeout_count >= DP_AUX_MAX_TIMEOUT_COUNT) + return -ETIMEDOUT; + } while (status != request->num_bytes); + + /* Obtain the read data from the reply FIFO. */ + for (index = 0; index < request->num_bytes; index++) { + request->data[index] = readl(dp_sub->base_addr + + DP_AUX_REPLY_DATA); + } + } + return 0; +} + +/** + * aux_request() - Submit request on the AUX channel + * @dev: The DP device + * @request: The request to submit + * + * Submit the supplied AUX request to the RX device over the AUX + * channel. If waiting for a reply times out, or if the DisplayPort TX core + * indicates that the request was deferred, the request is sent again (up to a + * maximum specified by DP_AUX_MAX_DEFER_COUNT|DP_AUX_MAX_TIMEOUT_COUNT). + * + * Return: 0 if request was submitted successfully, -ve on error + */ +static int aux_request(struct udevice *dev, struct aux_transaction *request) +{ + u32 status, defer_count = 0, timeout_count = 0; + + do { + status = aux_wait_ready(dev); + if (status) { + /* The RX device isn't ready yet. */ + timeout_count++; + continue; + } + /* Send the request. */ + status = aux_request_send(dev, request); + if (status == -EAGAIN) { + /* The request was deferred. */ + defer_count++; + } else if (status == -ETIMEDOUT) { + /* Waiting for a reply timed out. */ + timeout_count++; + } else { + return status; + } + + udelay(100); + } while ((defer_count < DP_AUX_MAX_DEFER_COUNT) && + (timeout_count < DP_AUX_MAX_TIMEOUT_COUNT)); + + /* The request was not successfully received by the RX device. */ + return -ETIMEDOUT; +} + +/** + * aux_common() - Common (read/write) AUX communication transmission + * @dev: The DP device + * @cmd_type: Command code of the transaction + * @address: The DPCD address of the transaction + * @num_bytes: Number of bytes in the payload data + * @data: The payload data of the AUX command + * + * Common sequence of submitting an AUX command for AUX read, AUX write, + * I2C-over-AUX read, and I2C-over-AUX write transactions. If required, the + * reads and writes are split into multiple requests, each acting on a maximum + * of 16 bytes. + * + * Return: 0 if OK, -ve on error + */ +static int aux_common(struct udevice *dev, u32 cmd_type, u32 address, + u32 num_bytes, u8 *data) +{ + u32 status, bytes_left; + struct aux_transaction request; + + if (!is_dp_connected(dev)) + return -ENODEV; + + /* + * Set the start address for AUX transactions. For I2C transactions, + * this is the address of the I2C bus. + */ + request.address = address; + bytes_left = num_bytes; + while (bytes_left > 0) { + request.cmd_code = cmd_type; + + if (cmd_type == DP_AUX_CMD_READ || + cmd_type == DP_AUX_CMD_WRITE) { + /* Increment address for normal AUX transactions. */ + request.address = address + (num_bytes - bytes_left); + } + + /* Increment the pointer to the supplied data buffer. */ + request.data = &data[num_bytes - bytes_left]; + + if (bytes_left > 16) + request.num_bytes = 16; + else + request.num_bytes = bytes_left; + + bytes_left -= request.num_bytes; + + if (cmd_type == DP_AUX_CMD_I2C_READ && bytes_left > 0) { + /* + * Middle of a transaction I2C read request. Override + * the command code that was set to CmdType. + */ + request.cmd_code = DP_AUX_CMD_I2C_READ_MOT; + } else if (cmd_type == DP_AUX_CMD_I2C_WRITE && bytes_left > 0) { + /* + * Middle of a transaction I2C write request. Override + * the command code that was set to CmdType. + */ + request.cmd_code = DP_AUX_CMD_I2C_WRITE_MOT; + } + + status = aux_request(dev, &request); + if (status) + return status; + } + return 0; +} + +/** + * aux_write() - Issue AUX write request + * @dev: The DP device + * @dpcd_address: The DPCD address to write to + * @bytes_to_write: Number of bytes to write + * @write_data: Buffer containig data to be written + * + * Issue a write request over the AUX channel that will write to + * the RX device's DisplayPort Configuration data (DPCD) address space. The + * write message will be divided into multiple transactions which write a + * maximum of 16 bytes each. + * + * Return: 0 if write operation was successful, -ve on error + */ +static int aux_write(struct udevice *dev, u32 dpcd_address, u32 bytes_to_write, + void *write_data) +{ + return aux_common(dev, DP_AUX_CMD_WRITE, dpcd_address, + bytes_to_write, (u8 *)write_data); +} + +/** + * aux_read() - Issue AUX read request + * @dev: The DP device + * @dpcd_address: The DPCD address to read from + * @bytes_to_read: Number of bytes to read + * @read_data: Buffer to receive the read data + * + * Issue a read request over the AUX channel that will read from the RX + * device's DisplayPort Configuration data (DPCD) address space. The read + * message will be divided into multiple transactions which read a maximum of + * 16 bytes each. + * + * Return: 0 if read operation was successful, -ve on error + */ +static int aux_read(struct udevice *dev, u32 dpcd_address, u32 bytes_to_read, void *read_data) +{ + return aux_common(dev, DP_AUX_CMD_READ, dpcd_address, + bytes_to_read, (u8 *)read_data); +} + +static int dp_tx_wakeup(struct udevice *dev) +{ + u32 status; + u8 aux_data; + + aux_data = 0x1; + status = aux_write(dev, DP_DPCD_SET_POWER_DP_PWR_VOLTAGE, 1, &aux_data); + if (status) + debug("! 1st power wake-up - AUX write failed.\n"); + status = aux_write(dev, DP_DPCD_SET_POWER_DP_PWR_VOLTAGE, 1, &aux_data); + if (status) + debug("! 2nd power wake-up - AUX write failed.\n"); + + return status; +} + +/** + * enable_main_link() - Switch on main link for a device + * @dev: The DP device + */ +static void enable_main_link(struct udevice *dev, u8 enable) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + /* Reset the scrambler. */ + writel(1, dp_sub->base_addr + DP_FORCE_SCRAMBLER_RESET); + /* Enable the main stream. */ + writel(enable, dp_sub->base_addr + DP_ENABLE_MAIN_STREAM); +} + +/** + * get_rx_capabilities() - Check if capabilities of RX device are valid for TX + * device + * @dev: The DP device + * + * Return: 0 if the capabilities of the RX device are valid for the TX device, + * -ve if not, of an error occurred during capability determination + */ +static int get_rx_capabilities(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 rx_max_link_rate, rx_max_lane_count, *dpcd = NULL; + u32 status; + struct link_config *link_config = NULL; + + dpcd = dp_sub->dpcd_rx_caps; + link_config = &dp_sub->link_config; + + status = aux_read(dev, DP_DPCD_RECEIVER_CAP_FIELD_START, 16, dpcd); + if (status) + return status; + + rx_max_link_rate = dpcd[DP_DPCD_MAX_LINK_RATE]; + rx_max_lane_count = dpcd[DP_DPCD_MAX_LANE_COUNT] & DP_DPCD_MAX_LANE_COUNT_MASK; + link_config->max_link_rate = (rx_max_link_rate > DP_0_LINK_RATE) ? + DP_0_LINK_RATE : rx_max_link_rate; + link_config->max_lane_count = (rx_max_lane_count > DP_0_LANE_COUNT) ? + DP_0_LANE_COUNT : rx_max_lane_count; + link_config->support_enhanced_framing_mode = dpcd[DP_DPCD_MAX_LANE_COUNT] & + DP_DPCD_ENHANCED_FRAME_SUPPORT_MASK; + link_config->support_downspread_control = dpcd[DP_DPCD_MAX_DOWNSPREAD] & + DP_DPCD_MAX_DOWNSPREAD_MASK; + + return 0; +} + +/** + * set_enhanced_frame_mode() - Enable/Disable enhanced frame mode + * @dev: The DP device + * @enable: Flag to determine whether to enable (1) or disable (0) the enhanced + * frame mode + * + * Enable or disable the enhanced framing symbol sequence for + * both the DisplayPort TX core and the RX device. + * + * Return: 0 if enabling/disabling the enhanced frame mode was successful, -ve + * on error + */ +static int set_enhanced_frame_mode(struct udevice *dev, u8 enable) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status; + u8 regval; + + dp_sub->link_config.enhanced_framing_mode = enable; + /* Write enhanced frame mode enable to the DisplayPort TX core. */ + writel(dp_sub->link_config.enhanced_framing_mode, + dp_sub->base_addr + DP_ENHANCED_FRAME_EN); + + /* Preserve the current RX device settings. */ + status = aux_read(dev, DP_DPCD_LANE_COUNT_SET, 0x1, ®val); + if (status) + return status; + + if (dp_sub->link_config.enhanced_framing_mode) + regval |= DP_DPCD_ENHANCED_FRAME_EN_MASK; + else + regval &= ~DP_DPCD_ENHANCED_FRAME_EN_MASK; + + /* Write enhanced frame mode enable to the RX device. */ + return aux_write(dev, DP_DPCD_LANE_COUNT_SET, 0x1, ®val); +} + +/** + * set_lane_count() - Set the lane count + * @dev: The DP device + * @lane_count: Lane count to set + * + * Set the number of lanes to be used by the main link for both + * the DisplayPort TX core and the RX device. + * + * Return: 0 if setting the lane count was successful, -ve on error + */ +static int set_lane_count(struct udevice *dev, u8 lane_count) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status; + u8 regval; + + dp_sub->link_config.lane_count = lane_count; + /* Write the new lane count to the DisplayPort TX core. */ + writel(dp_sub->link_config.lane_count, + dp_sub->base_addr + DP_LANE_COUNT_SET); + + /* Preserve the current RX device settings. */ + status = aux_read(dev, DP_DPCD_LANE_COUNT_SET, 0x1, ®val); + if (status) + return status; + + regval &= ~DP_DPCD_LANE_COUNT_SET_MASK; + regval |= dp_sub->link_config.lane_count; + + /* Write the new lane count to the RX device. */ + return aux_write(dev, DP_DPCD_LANE_COUNT_SET, 0x1, ®val); +} + +/** + * set_clk_speed() - Set DP phy clock speed + * @dev: The DP device + * @speed: The clock frquency to set (one of PHY_CLOCK_SELECT_*) + * + * Set the clock frequency for the DisplayPort PHY corresponding to a desired + * data rate. + * + * Return: 0 if setting the DP phy clock speed was successful, -ve on error + */ +static int set_clk_speed(struct udevice *dev, u32 speed) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 regval; + + /* Disable the DisplayPort TX core first. */ + regval = readl(dp_sub->base_addr + DP_ENABLE); + writel(0, dp_sub->base_addr + DP_ENABLE); + + /* Change speed of the feedback clock. */ + writel(speed, dp_sub->base_addr + DP_PHY_CLOCK_SELECT); + + /* Re-enable the DisplayPort TX core if it was previously enabled. */ + if (regval) + writel(regval, dp_sub->base_addr + DP_ENABLE); + + /* Wait until the PHY is ready. */ + return wait_phy_ready(dev); +} + +/** + * set_link_rate() - Set the link rate + * @dev: The DP device + * @link_rate: The link rate to set (one of LINK_BW_SET_*) + * + * Set the data rate to be used by the main link for both the DisplayPort TX + * core and the RX device. + * + * Return: 0 if setting the link rate was successful, -ve on error + */ +static int set_link_rate(struct udevice *dev, u8 link_rate) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status; + + /* Write a corresponding clock frequency to the DisplayPort TX core. */ + switch (link_rate) { + case DP_LINK_BW_SET_162GBPS: + status = set_clk_speed(dev, DP_PHY_CLOCK_SELECT_162GBPS); + break; + case DP_LINK_BW_SET_270GBPS: + status = set_clk_speed(dev, DP_PHY_CLOCK_SELECT_270GBPS); + break; + case DP_LINK_BW_SET_540GBPS: + status = set_clk_speed(dev, DP_PHY_CLOCK_SELECT_540GBPS); + break; + default: + status = -EINVAL; + break; + } + if (status) + return status; + + dp_sub->link_config.link_rate = link_rate; + /* Write new link rate to the DisplayPort TX core. */ + writel(dp_sub->link_config.link_rate, + dp_sub->base_addr + + DP_LINK_BW_SET); + + /* Write new link rate to the RX device. */ + return aux_write(dev, DP_DPCD_LINK_BW_SET, 0x1, + &dp_sub->link_config.link_rate); +} + +static int set_downspread(struct udevice *dev, u8 enable) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status; + u8 regval; + + dp_sub->link_config.support_downspread_control = enable; + /* Write downspread enable to the DisplayPort TX core. */ + writel(dp_sub->link_config.support_downspread_control, + dp_sub->base_addr + DP_DOWNSPREAD_CTRL); + + /* Preserve the current RX device settings. */ + status = aux_read(dev, DP_DPCD_DOWNSPREAD_CTRL, 0x1, ®val); + if (status) + return status; + + if (dp_sub->link_config.support_downspread_control) + regval |= DP_DPCD_SPREAD_AMP_MASK; + else + regval &= ~DP_DPCD_SPREAD_AMP_MASK; + + /* Write downspread enable to the RX device. */ + return aux_write(dev, DP_DPCD_DOWNSPREAD_CTRL, 0x1, ®val); +} + +static void set_serdes_vswing_preemp(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 index; + u8 vs_level_rx = dp_sub->link_config.vs_level; + u8 pe_level_rx = dp_sub->link_config.pe_level; + + for (index = 0; index < dp_sub->link_config.lane_count; index++) { + /* Write new voltage swing levels to the TX registers. */ + writel(vs[pe_level_rx][vs_level_rx], (ulong)SERDES_BASEADDR + + SERDES_L0_TX_MARGININGF + index * SERDES_LANE_OFFSET); + /* Write new pre-emphasis levels to the TX registers. */ + writel(pe[pe_level_rx][vs_level_rx], (ulong)SERDES_BASEADDR + + SERDES_L0_TX_DEEMPHASIS + index * SERDES_LANE_OFFSET); + } +} + +/** + * set_vswing_preemp() - Build AUX data to set voltage swing and pre-emphasis + * @dev: The DP device + * @aux_data: Buffer to receive the built AUX data + * + * Build AUX data to set current voltage swing and pre-emphasis level settings; + * the necessary data is taken from the link_config structure. + */ +static void set_vswing_preemp(struct udevice *dev, u8 *aux_data) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 data = 0; + u8 vs_level_rx = dp_sub->link_config.vs_level; + u8 pe_level_rx = dp_sub->link_config.pe_level; + + if (vs_level_rx >= DP_MAXIMUM_VS_LEVEL) + data |= DP_DPCD_TRAINING_LANEX_SET_MAX_VS_MASK; + + /* The maximum pre-emphasis level has been reached. */ + if (pe_level_rx >= DP_MAXIMUM_PE_LEVEL) + data |= DP_DPCD_TRAINING_LANEX_SET_MAX_PE_MASK; + + /* Set up the data buffer for writing to the RX device. */ + data |= (pe_level_rx << DP_DPCD_TRAINING_LANEX_SET_PE_SHIFT) | + vs_level_rx; + memset(aux_data, data, 4); + + set_serdes_vswing_preemp(dev); +} + +static int set_training_pattern(struct udevice *dev, u32 pattern) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 aux_data[5]; + + writel(pattern, dp_sub->base_addr + TRAINING_PATTERN_SET); + + aux_data[0] = pattern; + switch (pattern) { + case TRAINING_PATTERN_SET_OFF: + writel(0, dp_sub->base_addr + SCRAMBLING_DISABLE); + dp_sub->link_config.scrambler_en = 1; + break; + case TRAINING_PATTERN_SET_TP1: + case TRAINING_PATTERN_SET_TP2: + case TRAINING_PATTERN_SET_TP3: + aux_data[0] |= DP_DPCD_TP_SET_SCRAMB_DIS_MASK; + writel(1, dp_sub->base_addr + SCRAMBLING_DISABLE); + dp_sub->link_config.scrambler_en = 0; + break; + default: + break; + } + /* + * Make the adjustments to both the DisplayPort TX core and the RX + * device. + */ + set_vswing_preemp(dev, &aux_data[1]); + /* + * Write the voltage swing and pre-emphasis levels for each lane to the + * RX device. + */ + if (pattern == TRAINING_PATTERN_SET_OFF) + return aux_write(dev, DP_DPCD_TP_SET, 1, aux_data); + else + return aux_write(dev, DP_DPCD_TP_SET, 5, aux_data); +} + +static int get_lane_status_adj_reqs(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status; + u8 aux_data[8]; + + status = aux_read(dev, DP_DPCD_SINK_COUNT, 8, aux_data); + if (status) + return status; + + /* Save XDPPSU_DPCD_SINK_COUNT contents. */ + dp_sub->sink_count = + ((aux_data[0] & DP_DPCD_SINK_COUNT_HIGH_MASK) >> + DP_DPCD_SINK_COUNT_HIGH_LOW_SHIFT) | + (aux_data[0] & DP_DPCD_SINK_COUNT_LOW_MASK); + memcpy(dp_sub->lane_status_ajd_reqs, &aux_data[2], 6); + return 0; +} + +/** + * check_clock_recovery() - Check clock recovery success + * @dev: The LogiCore DP TX device in question + * @lane_count: The number of lanes for which to check clock recovery success + * + * Check if the RX device's DisplayPort Configuration data (DPCD) indicates + * that the clock recovery sequence during link training was successful - the + * RX device's link clock and data recovery unit has realized and maintained + * the frequency lock for all lanes currently in use. + * + * Return: 0 if clock recovery was successful on all lanes in question, -ve if + * not + */ +static int check_clock_recovery(struct udevice *dev, u8 lane_count) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 *lane_status = dp_sub->lane_status_ajd_reqs; + + switch (lane_count) { + case DP_LANE_COUNT_SET_2: + if (!(lane_status[0] & DP_DPCD_STATUS_LANE_1_CR_DONE_MASK)) + return -EINVAL; + case DP_LANE_COUNT_SET_1: + if (!(lane_status[0] & DP_DPCD_STATUS_LANE_0_CR_DONE_MASK)) + return -EINVAL; + default: + /* All (LaneCount) lanes have achieved clock recovery. */ + break; + } + return 0; +} + +/** + * adj_vswing_preemp() - Adjust voltage swing and pre-emphasis + * @dev: The DP device + * + * Set new voltage swing and pre-emphasis levels using the + * adjustment requests obtained from the RX device. + * + * Return: 0 if voltage swing and pre-emphasis could be adjusted successfully, + * -ve on error + */ +static int adj_vswing_preemp(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 index, vs_level_adj_req[4], pe_level_adj_req[4]; + u8 aux_data[4]; + u8 *adj_reqs = &dp_sub->lane_status_ajd_reqs[4]; + + /* + * Analyze the adjustment requests for changes in voltage swing and + * pre-emphasis levels. + */ + vs_level_adj_req[0] = adj_reqs[0] & DP_DPCD_ADJ_REQ_LANE_0_2_VS_MASK; + vs_level_adj_req[1] = (adj_reqs[0] & DP_DPCD_ADJ_REQ_LANE_1_3_VS_MASK) >> + DP_DPCD_ADJ_REQ_LANE_1_3_VS_SHIFT; + pe_level_adj_req[0] = (adj_reqs[0] & DP_DPCD_ADJ_REQ_LANE_0_2_PE_MASK) >> + DP_DPCD_ADJ_REQ_LANE_0_2_PE_SHIFT; + pe_level_adj_req[1] = (adj_reqs[0] & DP_DPCD_ADJ_REQ_LANE_1_3_PE_MASK) >> + DP_DPCD_ADJ_REQ_LANE_1_3_PE_SHIFT; + + /* + * Change the drive settings to match the adjustment requests. Use the + * greatest level requested. + */ + dp_sub->link_config.vs_level = 0; + dp_sub->link_config.pe_level = 0; + for (index = 0; index < dp_sub->link_config.lane_count; index++) { + if (vs_level_adj_req[index] > dp_sub->link_config.vs_level) + dp_sub->link_config.vs_level = vs_level_adj_req[index]; + + if (pe_level_adj_req[index] > dp_sub->link_config.pe_level) + dp_sub->link_config.pe_level = pe_level_adj_req[index]; + } + + if (dp_sub->link_config.pe_level > DP_MAXIMUM_PE_LEVEL) + dp_sub->link_config.pe_level = DP_MAXIMUM_PE_LEVEL; + + if (dp_sub->link_config.vs_level > DP_MAXIMUM_VS_LEVEL) + dp_sub->link_config.vs_level = DP_MAXIMUM_VS_LEVEL; + + if (dp_sub->link_config.pe_level > + (4 - dp_sub->link_config.vs_level)) { + dp_sub->link_config.pe_level = + 4 - dp_sub->link_config.vs_level; + } + /* + * Make the adjustments to both the DisplayPort TX core and the RX + * device. + */ + set_vswing_preemp(dev, aux_data); + /* + * Write the voltage swing and pre-emphasis levels for each lane to the + * RX device. + */ + return aux_write(dev, DP_DPCD_TRAINING_LANE0_SET, 2, aux_data); +} + +/** + * get_training_delay() - Get training delay + * @dev: The DP device + * @training_state: The training state for which the required training delay + * should be queried + * + * Determine what the RX device's required training delay is for + * link training. + * + * Return: The training delay in us + */ +static u32 get_training_delay(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 *dpcd = dp_sub->dpcd_rx_caps; + + if (dpcd[DP_DPCD_TRAIN_AUX_RD_INTERVAL]) + return 400 * dpcd[DP_DPCD_TRAIN_AUX_RD_INTERVAL] * 10; + + return 400; +} + +/** + * training_state_clock_recovery() - Run clock recovery part of link training + * @dev: The DP device + * + * Run the clock recovery sequence as part of link training. The + * sequence is as follows: + * + * 0) Start signaling at the minimum voltage swing, pre-emphasis, and + * post- cursor levels. + * 1) Transmit training pattern 1 over the main link with symbol + * scrambling disabled. + * 2) The clock recovery loop. If clock recovery is unsuccessful after + * MaxIterations loop iterations, return. + * 2a) Wait for at least the period of time specified in the RX device's + * DisplayPort Configuration data (DPCD) register, + * TRAINING_AUX_RD_INTERVAL. + * 2b) Check if all lanes have achieved clock recovery lock. If so, + * return. + * 2c) Check if the same voltage swing level has been used 5 consecutive + * times or if the maximum level has been reached. If so, return. + * 2d) Adjust the voltage swing, pre-emphasis, and post-cursor levels as + * requested by the RX device. + * 2e) Loop back to 2a. + * + * For a more detailed description of the clock recovery sequence, see section + * 3.5.1.2.1 of the DisplayPort 1.2a specification document. + * + * Return: The next state machine state to advance to + */ +static enum link_training_states training_state_clock_recovery(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status, delay_us; + u8 prev_vs_level = 0, same_vs_level_count = 0; + struct link_config *link_config = &dp_sub->link_config; + + delay_us = get_training_delay(dev); + /* Start CRLock. */ + /* Start from minimal voltage swing and pre-emphasis levels. */ + dp_sub->link_config.vs_level = 0; + dp_sub->link_config.pe_level = 0; + /* Transmit training pattern 1. */ + status = set_training_pattern(dev, TRAINING_PATTERN_SET_TP1); + if (status) + return TS_FAILURE; + + while (1) { + /* Wait delay specified in TRAINING_AUX_RD_INTERVAL. */ + udelay(delay_us); + /* Get lane and adjustment requests. */ + status = get_lane_status_adj_reqs(dev); + if (status) + /* The AUX read failed. */ + return TS_FAILURE; + + /* + * Check if all lanes have realized and maintained the frequency + * lock and get adjustment requests. + */ + status = check_clock_recovery(dev, dp_sub->link_config.lane_count); + if (status == 0) + return TS_CHANNEL_EQUALIZATION; + /* + * Check if the same voltage swing for each lane has been used 5 + * consecutive times. + */ + if (prev_vs_level == link_config->vs_level) { + same_vs_level_count++; + } else { + same_vs_level_count = 0; + prev_vs_level = link_config->vs_level; + } + if (same_vs_level_count >= 5) + break; + + /* Only try maximum voltage swing once. */ + if (link_config->vs_level == DP_MAXIMUM_VS_LEVEL) + break; + + /* Adjust the drive settings as requested by the RX device. */ + status = adj_vswing_preemp(dev); + if (status) + /* The AUX write failed. */ + return TS_FAILURE; + } + return TS_ADJUST_LINK_RATE; +} + +/** + * check_channel_equalization() - Check channel equalization success + * @dev: The DP device + * @lane_count: The number of lanes for which to check channel equalization + * success + * + * Check if the RX device's DisplayPort Configuration data (DPCD) indicates + * that the channel equalization sequence during link training was successful - + * the RX device has achieved channel equalization, symbol lock, and interlane + * alignment for all lanes currently in use. + * + * Return: 0 if channel equalization was successful on all lanes in question, + * -ve if not + */ +static int check_channel_equalization(struct udevice *dev, u8 lane_count) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 *lane_status = dp_sub->lane_status_ajd_reqs; + + /* Check that all LANEx_CHANNEL_EQ_DONE bits are set. */ + switch (lane_count) { + case DP_LANE_COUNT_SET_2: + if (!(lane_status[0] & DP_DPCD_STATUS_LANE_1_CE_DONE_MASK)) + return -EINVAL; + case DP_LANE_COUNT_SET_1: + if (!(lane_status[0] & DP_DPCD_STATUS_LANE_0_CE_DONE_MASK)) + return -EINVAL; + default: + /* All (LaneCount) lanes have achieved channel equalization. */ + break; + } + + /* Check that all LANEx_SYMBOL_LOCKED bits are set. */ + switch (lane_count) { + case DP_LANE_COUNT_SET_2: + if (!(lane_status[0] & DP_DPCD_STATUS_LANE_1_SL_DONE_MASK)) + return -EINVAL; + case DP_LANE_COUNT_SET_1: + if (!(lane_status[0] & DP_DPCD_STATUS_LANE_0_SL_DONE_MASK)) + return -EINVAL; + default: + /* All (LaneCount) lanes have achieved symbol lock. */ + break; + } + + /* Check that interlane alignment is done. */ + if (!(lane_status[2] & DP_DPCD_LANE_ALIGN_STATUS_UPDATED_IA_DONE_MASK)) + return -EINVAL; + return 0; +} + +/** + * training_state_channel_equalization() - Run channel equalization part of + * link training + * @dev: The DP device + * + * Run the channel equalization sequence as part of link + * training. The sequence is as follows: + * + * 0) Start signaling with the same drive settings used at the end of the + * clock recovery sequence. + * 1) Transmit training pattern 2 (or 3) over the main link with symbol + * scrambling disabled. + * 2) The channel equalization loop. If channel equalization is + * unsuccessful after 5 loop iterations, return. + * 2a) Wait for at least the period of time specified in the RX device's + * DisplayPort Configuration data (DPCD) register, + * TRAINING_AUX_RD_INTERVAL. + * 2b) Check if all lanes have achieved channel equalization, symbol lock, + * and interlane alignment. If so, return. + * 2c) Check if the same voltage swing level has been used 5 consecutive + * times or if the maximum level has been reached. If so, return. + * 2d) Adjust the voltage swing, pre-emphasis, and post-cursor levels as + * requested by the RX device. + * 2e) Loop back to 2a. + * + * For a more detailed description of the channel equalization sequence, see + * section 3.5.1.2.2 of the DisplayPort 1.2a specification document. + * + * Return: The next state machine state to advance to + */ +static enum link_training_states training_state_channel_equalization(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status, delay_us = 400, iteration_count = 0; + + /* Write the current drive settings. */ + /* Transmit training pattern 2/3. */ + if (dp_sub->dpcd_rx_caps[DP_DPCD_MAX_LANE_COUNT] & + DP_DPCD_TPS3_SUPPORT_MASK) + status = set_training_pattern(dev, TRAINING_PATTERN_SET_TP3); + else + status = set_training_pattern(dev, TRAINING_PATTERN_SET_TP2); + + if (status) + return TS_FAILURE; + + while (iteration_count < 5) { + /* Wait delay specified in TRAINING_AUX_RD_INTERVAL. */ + udelay(delay_us); + + /* Get lane and adjustment requests. */ + status = get_lane_status_adj_reqs(dev); + if (status) + /* The AUX read failed. */ + return TS_FAILURE; + + /* Adjust the drive settings as requested by the RX device. */ + status = adj_vswing_preemp(dev); + if (status) + /* The AUX write failed. */ + return TS_FAILURE; + + /* Check that all lanes still have their clocks locked. */ + status = check_clock_recovery(dev, dp_sub->link_config.lane_count); + if (status) + break; + /* + * Check that all lanes have accomplished channel + * equalization, symbol lock, and interlane alignment. + */ + status = check_channel_equalization(dev, dp_sub->link_config.lane_count); + if (status == 0) + return TS_SUCCESS; + iteration_count++; + } + + /* + * Tried 5 times with no success. Try a reduced bitrate first, then + * reduce the number of lanes. + */ + return TS_ADJUST_LINK_RATE; +} + +static int check_lane_align(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u8 *lane_status = dp_sub->lane_status_ajd_reqs; + + if (!(lane_status[2] & DP_DPCD_LANE_ALIGN_STATUS_UPDATED_IA_DONE_MASK)) + return -EINVAL; + return 0; +} + +/** + * check_link_status() - Check status of link + * @dev: The DP device + * @lane_count: The lane count to use for the check + * + * Check if the receiver's DisplayPort Configuration data (DPCD) indicates the + * receiver has achieved and maintained clock recovery, channel equalization, + * symbol lock, and interlane alignment for all lanes currently in use. + * + * Return: 0 if the link status is OK, -ve if a error occurred during checking + */ +static int check_link_status(struct udevice *dev, u8 lane_count) +{ + u32 status; + + status = get_lane_status_adj_reqs(dev); + if (status) + /* The AUX read failed. */ + return status; + + /* Check if the link needs training. */ + if ((check_clock_recovery(dev, lane_count) == 0) && + (check_channel_equalization(dev, lane_count) == 0) && + (check_lane_align(dev) == 0)) { + return 0; + } + return -EINVAL; +} + +/** + * run_training() - Run link training + * @dev: The DP device + * + * Run the link training process. It is implemented as a state machine, with + * each state returning the next state. First, the clock recovery sequence will + * be run; if successful, the channel equalization sequence will run. If either + * the clock recovery or channel equalization sequence failed, the link rate or + * the number of lanes used will be reduced and training will be re-attempted. + * If training fails at the minimal data rate, 1.62 Gbps with a single lane, + * training will no longer re-attempt and fail. + * + * There are undocumented timeout constraints in the link training process. In + * DP v1.2a spec, Chapter 3.5.1.2.2 a 10ms limit for the complete training + * process is mentioned. Which individual timeouts are derived and implemented + * by sink manufacturers is unknown. So each step should be as short as + * possible and link training should start as soon as possible after HPD. + * + * Return: 0 if the training sequence ran successfully, -ve if a error occurred + * or the training failed + */ +static int run_training(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status; + enum link_training_states training_state = TS_CLOCK_RECOVERY; + + while (1) { + switch (training_state) { + case TS_CLOCK_RECOVERY: + training_state = training_state_clock_recovery(dev); + break; + case TS_CHANNEL_EQUALIZATION: + training_state = training_state_channel_equalization(dev); + break; + default: + break; + } + + if (training_state == TS_SUCCESS) + break; + else if (training_state == TS_FAILURE) + return -EINVAL; + + if (training_state == TS_ADJUST_LANE_COUNT || + training_state == TS_ADJUST_LINK_RATE) { + status = set_training_pattern(dev, TRAINING_PATTERN_SET_OFF); + if (status) + return -EINVAL; + } + } + + /* Final status check. */ + return check_link_status(dev, dp_sub->link_config.lane_count); +} + +void reset_dp_phy(struct udevice *dev, u32 reset) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 phyval, regval; + + writel(0, dp_sub->base_addr + DP_ENABLE); + phyval = readl(dp_sub->base_addr + DP_PHY_CONFIG); + regval = phyval | reset; + writel(regval, dp_sub->base_addr + DP_PHY_CONFIG); + /* Remove the reset. */ + writel(phyval, dp_sub->base_addr + DP_PHY_CONFIG); + /* Wait for the PHY to be ready. */ + wait_phy_ready(dev); + + writel(1, dp_sub->base_addr + DP_ENABLE); +} + +/** + * establish_link() - Establish a link + * @dev: The DP device + * + * Check if the link needs training and run the training sequence if training + * is required. + * + * Return: 0 if the link was established successfully, -ve on error + */ +static int establish_link(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 status, re_enable_main_link; + + reset_dp_phy(dev, DP_PHY_CONFIG_TX_PHY_8B10BEN_MASK | + DP_PHY_CONFIG_PHY_RESET_MASK); + + re_enable_main_link = readl(dp_sub->base_addr + DP_ENABLE_MAIN_STREAM); + if (re_enable_main_link) + enable_main_link(dev, 0); + + status = run_training(dev); + if (status) + return status; + + status = set_training_pattern(dev, TRAINING_PATTERN_SET_OFF); + if (status) + return status; + + if (re_enable_main_link) + enable_main_link(dev, 1); + + return check_link_status(dev, dp_sub->link_config.lane_count); +} + +static int dp_hpd_train(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + struct link_config *link_config = &dp_sub->link_config; + u32 status; + + status = get_rx_capabilities(dev); + if (status) { + debug("! Error getting RX caps.\n"); + return status; + } + + status = set_enhanced_frame_mode(dev, link_config->support_enhanced_framing_mode ? 1 : 0); + if (status) { + debug("! EFM set failed.\n"); + return status; + } + + status = set_lane_count(dev, (dp_sub->use_max_lane_count) ? + link_config->max_lane_count : dp_sub->lane_count); + if (status) { + debug("! Lane count set failed.\n"); + return status; + } + + status = set_link_rate(dev, (dp_sub->use_max_link_rate) ? + link_config->max_link_rate : dp_sub->link_rate); + if (status) { + debug("! Link rate set failed.\n"); + return status; + } + + status = set_downspread(dev, link_config->support_downspread_control); + if (status) { + debug("! Setting downspread failed.\n"); + return status; + } + + debug("Lane count =%d\n", dp_sub->link_config.lane_count); + debug("Link rate =%d\n", dp_sub->link_config.link_rate); + + debug("Starting Training...\n"); + status = establish_link(dev); + if (status == 0) + debug("! Training succeeded.\n"); + else + debug("! Training failed.\n"); + + return status; +} + +static void display_gfx_frame_buffer(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + if (!dp_sub->dp_dma->gfx.channel.cur) + dp_sub->dp_dma->gfx.trigger_status = DPDMA_TRIGGER_EN; +} + +static void set_color_encode(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + struct main_stream_attributes *msa_config = &dp_sub->msa_config; + + msa_config->y_cb_cr_colorimetry = 0; + msa_config->dynamic_range = 0; + msa_config->component_format = 0; + msa_config->misc0 = 0; + msa_config->misc1 = 0; + msa_config->component_format = DP_MAIN_STREAM_MISC0_COMPONENT_FORMAT_RGB; +} + +static void config_msa_recalculate(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + u32 video_bw, link_bw, words_per_line; + u8 bits_per_pixel; + struct main_stream_attributes *msa_config; + struct link_config *link_config; + + msa_config = &dp_sub->msa_config; + link_config = &dp_sub->link_config; + + msa_config->user_pixel_width = 1; + + /* Compute the rest of the MSA values. */ + msa_config->n_vid = 27 * 1000 * link_config->link_rate; + msa_config->h_start = msa_config->vid_timing_mode.video_timing.h_sync_width + + msa_config->vid_timing_mode.video_timing.h_back_porch; + msa_config->v_start = msa_config->vid_timing_mode.video_timing.f0_pv_sync_width + + msa_config->vid_timing_mode.video_timing.f0_pv_back_porch; + + /* Miscellaneous attributes. */ + if (msa_config->bits_per_color == 6) + msa_config->misc0 = DP_MAIN_STREAM_MISC0_BDC_6BPC; + else if (msa_config->bits_per_color == 8) + msa_config->misc0 = DP_MAIN_STREAM_MISC0_BDC_8BPC; + else if (msa_config->bits_per_color == 10) + msa_config->misc0 = DP_MAIN_STREAM_MISC0_BDC_10BPC; + else if (msa_config->bits_per_color == 12) + msa_config->misc0 = DP_MAIN_STREAM_MISC0_BDC_12BPC; + else if (msa_config->bits_per_color == 16) + msa_config->misc0 = DP_MAIN_STREAM_MISC0_BDC_16BPC; + + msa_config->misc0 <<= DP_MAIN_STREAM_MISC0_BDC_SHIFT; + + /* Need to set this. */ + msa_config->misc0 |= msa_config->component_format << + DP_MAIN_STREAM_MISC0_COMPONENT_FORMAT_SHIFT; + + msa_config->misc0 |= msa_config->dynamic_range << + DP_MAIN_STREAM_MISC0_DYNAMIC_RANGE_SHIFT; + + msa_config->misc0 |= msa_config->y_cb_cr_colorimetry << + DP_MAIN_STREAM_MISC0_YCBCR_COLORIMETRY_SHIFT; + + msa_config->misc0 |= msa_config->synchronous_clock_mode; + /* + * Determine the number of bits per pixel for the specified color + * component format. + */ + if (msa_config->misc1 == DP_MAIN_STREAM_MISC1_Y_ONLY_EN_MASK) + bits_per_pixel = msa_config->bits_per_color; + else if (msa_config->component_format == + DP_MAIN_STREAM_MISC0_COMPONENT_FORMAT_YCBCR422) + /* YCbCr422 color component format. */ + bits_per_pixel = msa_config->bits_per_color * 2; + else + /* RGB or YCbCr 4:4:4 color component format. */ + bits_per_pixel = msa_config->bits_per_color * 3; + + /* Calculate the data per lane. */ + words_per_line = msa_config->vid_timing_mode.video_timing.h_active * bits_per_pixel; + if (words_per_line % 16) + words_per_line += 16; + + words_per_line /= 16; + msa_config->data_per_lane = words_per_line - link_config->lane_count; + if (words_per_line % link_config->lane_count) + msa_config->data_per_lane += (words_per_line % link_config->lane_count); + + /* Allocate a fixed size for single-stream transport (SST) operation. */ + msa_config->transfer_unit_size = 64; + + /* + * Calculate the average number of bytes per transfer unit. + * Note: Both the integer and the fractional part is stored in + * AvgBytesPerTU. + */ + video_bw = ((msa_config->pixel_clock_hz / 1000) * bits_per_pixel) / 8; + link_bw = (link_config->lane_count * link_config->link_rate * 27); + msa_config->avg_bytes_per_tu = ((10 * + (video_bw * msa_config->transfer_unit_size) + / link_bw) + 5) / 10; + /* + * The number of initial wait cycles at the start of a new line by the + * framing logic. This allows enough data to be buffered in the input + * FIFO before video is sent. + */ + if ((msa_config->avg_bytes_per_tu / 1000) <= 4) + msa_config->init_wait = 64; + else + msa_config->init_wait = msa_config->transfer_unit_size - + (msa_config->avg_bytes_per_tu / 1000); +} + +static void set_msa_bpc(struct udevice *dev, u8 bits_per_color) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + dp_sub->msa_config.bits_per_color = bits_per_color; + /* Calculate the rest of the MSA values. */ + config_msa_recalculate(dev); +} + +const struct video_timing_mode *get_video_mode_data(enum video_mode vm_id) +{ + if (vm_id < VIDC_VM_NUM_SUPPORTED) + return &vidc_video_timing_modes[vm_id]; + + return NULL; +} + +static u64 get_pixelclk_by_vmid(enum video_mode vm_id) +{ + const struct video_timing_mode *vm; + u64 clk_hz; + + vm = get_video_mode_data(vm_id); + /* For progressive mode, use only frame 0 vertical total. */ + clk_hz = vm->video_timing.f0_pv_total; + /* Multiply the number of pixels by the frame rate. */ + clk_hz *= vm->frame_rate; + + /* + * Multiply the vertical total by the horizontal total for number of + * pixels. + */ + clk_hz *= vm->video_timing.h_total; + + return clk_hz; +} + +/** + * config_msa_video_mode() - Enable video output + * @dev: The DP device + * @msa: The MSA values to set for the device + * + * Return: 0 if the video was enabled successfully, -ve on error + */ +static void config_msa_video_mode(struct udevice *dev, enum video_mode videomode) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + struct main_stream_attributes *msa_config; + + msa_config = &dp_sub->msa_config; + + /* Configure the MSA values from the display monitor DMT table. */ + msa_config->vid_timing_mode.vid_mode = vidc_video_timing_modes[videomode].vid_mode; + msa_config->vid_timing_mode.frame_rate = vidc_video_timing_modes[videomode].frame_rate; + msa_config->vid_timing_mode.video_timing.h_active = + vidc_video_timing_modes[videomode].video_timing.h_active; + msa_config->vid_timing_mode.video_timing.h_front_porch = + vidc_video_timing_modes[videomode].video_timing.h_front_porch; + msa_config->vid_timing_mode.video_timing.h_sync_width = + vidc_video_timing_modes[videomode].video_timing.h_sync_width; + msa_config->vid_timing_mode.video_timing.h_back_porch = + vidc_video_timing_modes[videomode].video_timing.h_back_porch; + msa_config->vid_timing_mode.video_timing.h_total = + vidc_video_timing_modes[videomode].video_timing.h_total; + msa_config->vid_timing_mode.video_timing.h_sync_polarity = + vidc_video_timing_modes[videomode].video_timing.h_sync_polarity; + msa_config->vid_timing_mode.video_timing.v_active = + vidc_video_timing_modes[videomode].video_timing.v_active; + msa_config->vid_timing_mode.video_timing.f0_pv_front_porch = + vidc_video_timing_modes[videomode].video_timing.f0_pv_front_porch; + msa_config->vid_timing_mode.video_timing.f0_pv_sync_width = + vidc_video_timing_modes[videomode].video_timing.f0_pv_sync_width; + msa_config->vid_timing_mode.video_timing.f0_pv_back_porch = + vidc_video_timing_modes[videomode].video_timing.f0_pv_back_porch; + msa_config->vid_timing_mode.video_timing.f0_pv_total = + vidc_video_timing_modes[videomode].video_timing.f0_pv_total; + msa_config->vid_timing_mode.video_timing.f1_v_front_porch = + vidc_video_timing_modes[videomode].video_timing.f1_v_front_porch; + msa_config->vid_timing_mode.video_timing.f1_v_sync_width = + vidc_video_timing_modes[videomode].video_timing.f1_v_sync_width; + msa_config->vid_timing_mode.video_timing.f1_v_back_porch = + vidc_video_timing_modes[videomode].video_timing.f1_v_back_porch; + msa_config->vid_timing_mode.video_timing.f1_v_total = + vidc_video_timing_modes[videomode].video_timing.f1_v_total; + msa_config->vid_timing_mode.video_timing.v_sync_polarity = + vidc_video_timing_modes[videomode].video_timing.v_sync_polarity; + msa_config->pixel_clock_hz = get_pixelclk_by_vmid(msa_config->vid_timing_mode.vid_mode); + + /* Calculate the rest of the MSA values. */ + config_msa_recalculate(dev); +} + +static void set_pixel_clock(u64 freq_hz) +{ + u64 ext_divider, vco, vco_int_frac; + u32 pll_assigned, frac_int_fb_div, fraction, regpll = 0; + u8 pll; + + pll_assigned = readl(CLK_FPD_BASEADDR + VIDEO_REF_CTRL) & VIDEO_REF_CTRL_SRCSEL_MASK; + if (pll_assigned) + pll = VPLL; + + ext_divider = PLL_OUT_FREQ / freq_hz; + vco = freq_hz * ext_divider * 2; + vco_int_frac = (vco * INPUT_FREQ_PRECISION * SHIFT_DECIMAL) / + AVBUF_INPUT_REF_CLK; + frac_int_fb_div = vco_int_frac >> PRECISION; + fraction = vco_int_frac & AVBUF_DECIMAL; + + regpll |= ENABLE_BIT << PLL_CTRL_BYPASS_SHIFT; + regpll |= frac_int_fb_div << PLL_CTRL_FBDIV_SHIFT; + regpll |= (1 << PLL_CTRL_DIV2_SHIFT); + regpll |= (PSS_REF_CLK << PLL_CTRL_PRE_SRC_SHIFT); + writel(regpll, CLK_FPD_BASEADDR + VPLL_CTRL); + + regpll = 0; + regpll |= VPLL_CFG_CP << PLL_CFG_CP_SHIFT; + regpll |= VPLL_CFG_RES << PLL_CFG_RES_SHIFT; + regpll |= VPLL_CFG_LFHF << PLL_CFG_LFHF_SHIFT; + regpll |= VPLL_CFG_LOCK_DLY << PLL_CFG_LOCK_DLY_SHIFT; + regpll |= VPLL_CFG_LOCK_CNT << PLL_CFG_LOCK_CNT_SHIFT; + writel(regpll, CLK_FPD_BASEADDR + VPLL_CFG); + + regpll = (1U << PLL_FRAC_CFG_ENABLED_SHIFT) | + (fraction << PLL_FRAC_CFG_DATA_SHIFT); + writel(regpll, CLK_FPD_BASEADDR + VPLL_FRAC_CFG); + + clrsetbits_le32(CLK_FPD_BASEADDR + VPLL_CTRL, + PLL_CTRL_RESET_MASK, + (ENABLE_BIT << PLL_CTRL_RESET_SHIFT)); + + /* Deassert reset to the PLL. */ + clrsetbits_le32(CLK_FPD_BASEADDR + VPLL_CTRL, + PLL_CTRL_RESET_MASK, + (DISABLE_BIT << PLL_CTRL_RESET_SHIFT)); + + while (!(readl(CLK_FPD_BASEADDR + PLL_STATUS) & + (1 << PLL_STATUS_VPLL_LOCK))) + ; + + /* Deassert Bypass. */ + clrsetbits_le32(CLK_FPD_BASEADDR + VPLL_CTRL, + PLL_CTRL_BYPASS_MASK, + (DISABLE_BIT << PLL_CTRL_BYPASS_SHIFT)); + udelay(1); + + clrsetbits_le32(CLK_FPD_BASEADDR + VIDEO_REF_CTRL, + VIDEO_REF_CTRL_CLKACT_MASK, + (DISABLE_BIT << VIDEO_REF_CTRL_CLKACT_SHIFT)); + + clrsetbits_le32(CLK_FPD_BASEADDR + VIDEO_REF_CTRL, + VIDEO_REF_CTRL_DIVISOR1_MASK, + (ENABLE_BIT << VIDEO_REF_CTRL_DIVISOR1_SHIFT)); + + clrsetbits_le32(CLK_FPD_BASEADDR + VIDEO_REF_CTRL, + VIDEO_REF_CTRL_DIVISOR0_MASK, + (ext_divider << VIDEO_REF_CTRL_DIVISOR0_SHIFT)); + + clrsetbits_le32(CLK_FPD_BASEADDR + VIDEO_REF_CTRL, + VIDEO_REF_CTRL_CLKACT_MASK, + (ENABLE_BIT << VIDEO_REF_CTRL_CLKACT_SHIFT)); +} + +/** + * set_msa_values() - Set MSA values + * @dev: The DP device + * + * Set the main stream attributes registers of the DisplayPort TX + * core with the values specified in the main stream attributes configuration + * structure. + */ +static void set_msa_values(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + struct main_stream_attributes *msa_config; + + msa_config = &dp_sub->msa_config; + + /* + * Set the main stream attributes to the associated DisplayPort TX core + * registers. + */ + writel(msa_config->vid_timing_mode.video_timing.h_total, + dp_sub->base_addr + DP_MAIN_STREAM_HTOTAL); + writel(msa_config->vid_timing_mode.video_timing.f0_pv_total, + dp_sub->base_addr + DP_MAIN_STREAM_VTOTAL); + writel(msa_config->vid_timing_mode.video_timing.h_sync_polarity | + (msa_config->vid_timing_mode.video_timing.v_sync_polarity + << DP_MAIN_STREAM_POLARITY_VSYNC_POL_SHIFT), + dp_sub->base_addr + DP_MAIN_STREAM_POLARITY); + writel(msa_config->vid_timing_mode.video_timing.h_sync_width, + dp_sub->base_addr + DP_MAIN_STREAM_HSWIDTH); + writel(msa_config->vid_timing_mode.video_timing.f0_pv_sync_width, + dp_sub->base_addr + DP_MAIN_STREAM_VSWIDTH); + writel(msa_config->vid_timing_mode.video_timing.h_active, + dp_sub->base_addr + DP_MAIN_STREAM_HRES); + writel(msa_config->vid_timing_mode.video_timing.v_active, + dp_sub->base_addr + DP_MAIN_STREAM_VRES); + writel(msa_config->h_start, dp_sub->base_addr + DP_MAIN_STREAM_HSTART); + writel(msa_config->v_start, dp_sub->base_addr + DP_MAIN_STREAM_VSTART); + writel(msa_config->misc0, dp_sub->base_addr + DP_MAIN_STREAM_MISC0); + writel(msa_config->misc1, dp_sub->base_addr + DP_MAIN_STREAM_MISC1); + writel(msa_config->pixel_clock_hz / 1000, dp_sub->base_addr + DP_M_VID); + writel(msa_config->n_vid, dp_sub->base_addr + DP_N_VID); + writel(msa_config->user_pixel_width, dp_sub->base_addr + DP_USER_PIXEL_WIDTH); + writel(msa_config->data_per_lane, dp_sub->base_addr + DP_USER_DATA_COUNT_PER_LANE); + /* + * Set the transfer unit values to the associated DisplayPort TX core + * registers. + */ + writel(msa_config->transfer_unit_size, dp_sub->base_addr + DP_TU_SIZE); + writel(msa_config->avg_bytes_per_tu / 1000, + dp_sub->base_addr + DP_MIN_BYTES_PER_TU); + writel((msa_config->avg_bytes_per_tu % 1000) * 1000, + dp_sub->base_addr + DP_FRAC_BYTES_PER_TU); + writel(msa_config->init_wait, dp_sub->base_addr + DP_INIT_WAIT); +} + +static void setup_video_stream(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + struct main_stream_attributes *msa_config = &dp_sub->msa_config; + + set_color_encode(dev); + set_msa_bpc(dev, dp_sub->bpc); + config_msa_video_mode(dev, dp_sub->video_mode); + + /* Set pixel clock. */ + dp_sub->pix_clk = msa_config->pixel_clock_hz; + set_pixel_clock(dp_sub->pix_clk); + + /* Reset the transmitter. */ + writel(1, dp_sub->base_addr + DP_SOFT_RESET); + udelay(10); + writel(0, dp_sub->base_addr + DP_SOFT_RESET); + + set_msa_values(dev); + + /* Issuing a soft-reset (AV_BUF_SRST_REG). */ + writel(3, dp_sub->base_addr + AVBUF_BUF_SRST_REG); // Assert reset. + udelay(10); + writel(0, dp_sub->base_addr + AVBUF_BUF_SRST_REG); // De-ssert reset. + + enable_main_link(dev, 1); + + debug("DONE!\n"); +} + +static int dp_tx_start_link_training(struct udevice *dev) +{ + u32 status; + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + enable_main_link(dev, 0); + + if (!is_dp_connected(dev)) { + debug("! Disconnected.\n"); + return -ENODEV; + } + + status = dp_tx_wakeup(dev); + if (status) { + debug("! Wakeup failed.\n"); + return -EIO; + } + + do { + mdelay(100); + status = dp_hpd_train(dev); + if (status == -EINVAL) { + debug("Lost connection\n\r"); + return -EIO; + } else if (status) { + continue; + } + display_gfx_frame_buffer(dev); + setup_video_stream(dev); + status = check_link_status(dev, dp_sub->link_config.lane_count); + if (status == -EINVAL) + return -EIO; + } while (status != 0); + + return 0; +} + +static void init_run_config(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + dp_sub->dp_dma = &dp_dma; + dp_sub->video_mode = VIDC_VM_1024x768_60_P; + dp_sub->bpc = VIDC_BPC_8; + dp_sub->color_encode = DP_CENC_RGB; + dp_sub->use_max_cfg_caps = 1; + dp_sub->lane_count = LANE_COUNT_1; + dp_sub->link_rate = LINK_RATE_540GBPS; + dp_sub->en_sync_clk_mode = 0; + dp_sub->use_max_lane_count = 1; + dp_sub->use_max_link_rate = 1; +} + +static int dpdma_setup(struct udevice *dev) +{ + int status; + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + writel(DPDMA_ISR_VSYNC_INT_MASK, dp_sub->dp_dma->base_addr + DPDMA_IEN); + status = wait_for_bit_le32((u32 *)dp_sub->dp_dma->base_addr + DPDMA_ISR, + DPDMA_ISR_VSYNC_INT_MASK, false, 1000, false); + if (status) { + debug("%s: INTR TIMEDOUT\n", __func__); + return status; + } + debug("INTR dma_vsync_intr_handler called...\n"); + dma_vsync_intr_handler(dev); + + return 0; +} + +static int zynqmp_dpsub_init(struct udevice *dev) +{ + int status; + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + /* Initialize the dpdma configuration */ + status = init_dpdma_subsys(dev); + if (status) + return -EINVAL; + + config_msa_sync_clk_mode(dev, dp_sub->en_sync_clk_mode); + set_video_clk_source(dev, AVBUF_PS_CLK, AVBUF_PS_CLK); + + return 0; +} + +static int dp_tx_run(struct udevice *dev) +{ + u32 interrupt_signal_state, interrupt_status, hpd_state, hpd_event; + u32 hpd_pulse_detected, hpd_duration, status; + int attempts = 0; + struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); + + /* Continuously poll for HPD events. */ + while (attempts < 5) { + /* Read interrupt registers. */ + interrupt_signal_state = readl(dp_sub->base_addr + DP_INTERRUPT_SIG_STATE); + interrupt_status = readl(dp_sub->base_addr + DP_INTR_STATUS); + /* Check for HPD events. */ + hpd_state = interrupt_signal_state & DP_INTERRUPT_SIG_STATE_HPD_STATE_MASK; + hpd_event = interrupt_status & DP_INTR_HPD_EVENT_MASK; + hpd_pulse_detected = interrupt_status & DP_INTR_HPD_PULSE_DETECTED_MASK; + if (hpd_pulse_detected) + hpd_duration = readl(dp_sub->base_addr + DP_HPD_DURATION); + else + attempts++; + + /* HPD event handling. */ + if (hpd_state && hpd_event) { + debug("+===> HPD connection event detected.\n"); + /* Initiate link training. */ + status = dp_tx_start_link_training(dev); + if (status) { + debug("Link training failed\n"); + return status; + } + return 0; + } else if (hpd_state && hpd_pulse_detected && (hpd_duration >= 250)) { + debug("===> HPD pulse detected.\n"); + /* Re-train if needed. */ + status = dp_tx_start_link_training(dev); + if (status) { + debug("HPD pulse detection failed\n"); + return status; + } + return 0; + } else if (!hpd_state && hpd_event) { + debug("+===> HPD disconnection event detected.\n\n"); + /* Disable main link. */ + enable_main_link(dev, 0); + break; + } + } + return -EINVAL; +} + +static int zynqmp_dpsub_probe(struct udevice *dev) +{ + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct zynqmp_dpsub_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + int mode = RGBA8888; + + ret = clk_get_by_name(dev, "dp_apb_clk", &clk); + if (ret < 0) { + dev_err(dev, "failed to get clock\n"); + return ret; + } + + priv->clock = clk_get_rate(&clk); + if (IS_ERR_VALUE(priv->clock)) { + dev_err(dev, "failed to get rate\n"); + return priv->clock; + } + + ret = clk_enable(&clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + dev_dbg(dev, "Base addr 0x%x, clock %d\n", (u32)priv->base_addr, + priv->clock); + + /* Initialize the DisplayPort TX core. */ + ret = init_dp_tx(dev); + if (ret) + return -EINVAL; + + /* Initialize the runtime configuration */ + init_run_config(dev); + /* Set the format graphics frame for Video Pipeline */ + ret = set_nonlive_gfx_format(dev, mode); + if (ret) + return ret; + + uc_priv->bpix = ffs(priv->non_live_graphics->bpp) - 1; + dev_dbg(dev, "BPP in bits %d, bpix %d\n", + priv->non_live_graphics->bpp, uc_priv->bpix); + + uc_priv->fb = (void *)gd->fb_base; + uc_priv->xsize = vidc_video_timing_modes[priv->video_mode].video_timing.h_active; + uc_priv->ysize = vidc_video_timing_modes[priv->video_mode].video_timing.v_active; + /* Calculated by core but need it for my own setup */ + uc_priv->line_length = uc_priv->xsize * VNBYTES(uc_priv->bpix); + /* Will be calculated again in video_post_probe() but I need that value now */ + uc_priv->fb_size = uc_priv->line_length * uc_priv->ysize; + + switch (mode) { + case RGBA8888: + uc_priv->format = VIDEO_RGBA8888; + break; + default: + debug("Unsupported mode\n"); + return -EINVAL; + } + + video_set_flush_dcache(dev, true); + debug("Video: WIDTH[%d]xHEIGHT[%d]xBPP[%d/%d] -- line length %d\n", uc_priv->xsize, + uc_priv->ysize, uc_priv->bpix, VNBYTES(uc_priv->bpix), uc_priv->line_length); + + enable_gfx_buffers(dev, 1); + avbuf_video_select(dev, AVBUF_VIDSTREAM1_NONE, AVBUF_VIDSTREAM2_NONLIVE_GFX); + config_gfx_pipeline(dev); + config_output_video(dev); + + ret = zynqmp_dpsub_init(dev); + if (ret) + return ret; + + /* Populate the FrameBuffer structure with the frame attributes */ + priv->frame_buffer.stride = uc_priv->line_length; + priv->frame_buffer.line_size = priv->frame_buffer.stride; + priv->frame_buffer.size = priv->frame_buffer.line_size * uc_priv->ysize; + + ret = dp_tx_run(dev); + if (ret) + return ret; + + return dpdma_setup(dev); +} + +static int zynqmp_dpsub_bind(struct udevice *dev) +{ + struct video_uc_plat *plat = dev_get_uclass_plat(dev); + + /* This is maximum size to allocate - it depends on BPP setting */ + plat->size = WIDTH * HEIGHT * 4; + /* plat->align is not defined that's why 1MB alignment is used */ + + /* + * plat->base can be used for allocating own location for FB + * if not defined then it is allocated by u-boot itself + */ + + return 0; +} + +static int zynqmp_dpsub_of_to_plat(struct udevice *dev) +{ + struct zynqmp_dpsub_priv *priv = dev_get_priv(dev); + struct resource res; + int ret; + + ret = dev_read_resource_byname(dev, "dp", &res); + if (ret) + return ret; + + priv->base_addr = res.start; + + return 0; +} + +static const struct udevice_id zynqmp_dpsub_ids[] = { + { .compatible = "xlnx,zynqmp-dpsub-1.7" }, + { } +}; + +U_BOOT_DRIVER(zynqmp_dpsub_video) = { + .name = "zynqmp_dpsub_video", + .id = UCLASS_VIDEO, + .of_match = zynqmp_dpsub_ids, + .plat_auto = sizeof(struct video_uc_plat), + .bind = zynqmp_dpsub_bind, + .probe = zynqmp_dpsub_probe, + .priv_auto = sizeof(struct zynqmp_dpsub_priv), + .of_to_plat = zynqmp_dpsub_of_to_plat, +}; diff --git a/drivers/video/zynqmp/zynqmp_dpsub.h b/drivers/video/zynqmp/zynqmp_dpsub.h new file mode 100644 index 00000000000..7d2737e31aa --- /dev/null +++ b/drivers/video/zynqmp/zynqmp_dpsub.h @@ -0,0 +1,680 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023, Advanced Micro Devices, Inc. + * + */ + +#ifndef _VIDEO_ZYNQMP_DPSUB_H +#define _VIDEO_ZYNQMP_DPSUB_H + +enum video_mode { + VIDC_VM_640x480_60_P = 0, + VIDC_VM_1024x768_60_P = 1, +}; + +enum { + LANE_COUNT_1 = 1, + LANE_COUNT_2 = 2, +}; + +enum { + LINK_RATE_162GBPS = 0x06, + LINK_RATE_270GBPS = 0x0A, + LINK_RATE_540GBPS = 0x14, +}; + +enum video_color_depth { + VIDC_BPC_6 = 6, + VIDC_BPC_8 = 8, + VIDC_BPC_10 = 10, + VIDC_BPC_12 = 12, + VIDC_BPC_14 = 14, + VIDC_BPC_16 = 16, + VIDC_BPC_NUM_SUPPORTED = 6, + VIDC_BPC_UNKNOWN +}; + +enum video_color_encoding { + DP_CENC_RGB = 0, + DP_CENC_YONLY, +}; + +enum dp_dma_channel_type { + VIDEO_CHAN, + GRAPHICS_CHAN, +}; + +enum dp_dma_channel_state { + DPDMA_DISABLE, + DPDMA_ENABLE, + DPDMA_IDLE, + DPDMA_PAUSE +}; + +enum link_training_states { + TS_CLOCK_RECOVERY, + TS_CHANNEL_EQUALIZATION, + TS_ADJUST_LINK_RATE, + TS_ADJUST_LANE_COUNT, + TS_FAILURE, + TS_SUCCESS +}; + +enum video_frame_rate { + VIDC_FR_60HZ = 60, + VIDC_FR_NUM_SUPPORTED = 2, + VIDC_FR_UNKNOWN +}; + +enum av_buf_video_modes { + INTERLEAVED, + SEMIPLANAR +}; + +enum av_buf_video_format { + RGBA8888 = 1, +}; + +enum av_buf_video_stream { + AVBUF_VIDSTREAM1_LIVE, + AVBUF_VIDSTREAM1_NONLIVE, + AVBUF_VIDSTREAM1_TPG, + AVBUF_VIDSTREAM1_NONE, +}; + +enum av_buf_gfx_stream { + AVBUF_VIDSTREAM2_DISABLEGFX = 0x0, + AVBUF_VIDSTREAM2_NONLIVE_GFX = 0x4, + AVBUF_VIDSTREAM2_LIVE_GFX = 0x8, + AVBUF_VIDSTREAM2_NONE = 0xC0, +}; + +/** + * struct aux_transaction - Description of an AUX channel transaction + * @cmd_code: Command code of the transaction + * @num_bytes: The number of bytes in the transaction's payload data + * @address: The DPCD address of the transaction + * @data: Payload data of the AUX channel transaction + */ +struct aux_transaction { + u16 cmd_code; + u8 num_bytes; + u32 address; + u8 *data; +}; + +/** + * struct link_config - Description of link configuration + * @lane_count: Currently selected lane count for this link + * @link_rate: Currently selected link rate for this link + * @scrambler_en: Flag to determine whether the scrambler is + * enabled for this link + * @enhanced_framing_mode: Flag to determine whether enhanced framing + * mode is active for this link + * @max_lane_count: Maximum lane count for this link + * @max_link_rate: Maximum link rate for this link + * @support_enhanced_framing_mode: Flag to indicate whether the link supports + * enhanced framing mode + * @vs_level: Voltage swing for each lane + * @pe_level: Pre-emphasis/cursor level for each lane + * @pattern: The current pattern currently in use over the main link + */ +struct link_config { + u8 lane_count; + u8 link_rate; + u8 scrambler_en; + u8 enhanced_framing_mode; + u8 max_lane_count; + u8 max_link_rate; + u8 support_enhanced_framing_mode; + u8 support_downspread_control; + u8 vs_level; + u8 pe_level; + u8 pattern; +}; + +struct video_timing { + u16 h_active; + u16 h_front_porch; + u16 h_sync_width; + u16 h_back_porch; + u16 h_total; + bool h_sync_polarity; + u16 v_active; + u16 f0_pv_front_porch; + u16 f0_pv_sync_width; + u16 f0_pv_back_porch; + u16 f0_pv_total; + u16 f1_v_front_porch; + u16 f1_v_sync_width; + u16 f1_v_back_porch; + u16 f1_v_total; + bool v_sync_polarity; +}; + +struct video_timing_mode { + enum video_mode vid_mode; + char name[21]; + enum video_frame_rate frame_rate; + struct video_timing video_timing; +}; + +/* + * struct main_stream_attributes - Main Stream Attributes (MSA) + * @pixel_clock_hz: The pixel clock of the stream (in Hz) + * @h_start: Horizontal blank start (in pixels) + * @v_start: Vertical blank start (in lines). + * @misc0: Miscellaneous stream attributes 0 + * @misc1: Miscellaneous stream attributes 1 + * @n_vid N value for the video stream + * @user_pixel_width: The width of the user data input port. + * @data_per_plane: Used to translate the number of pixels per + * line to the native internal 16-bit datapath. + * @avg_bytes_per_tu: Average number of bytes per transfer unit, + * scaled up by a factor of 1000. + * @transfer_unit_size: Size of the transfer unit in the + * framing logic. + * @init_wait: Number of initial wait cycles at the start + * of a new line by the framing logic. + * @bits_per_color: Number of bits per color component. + * @component_format: The component format currently in + * use by the video stream. + * @dynamic_range: The dynamic range currently in use + * by the video stream. + * @y_cb_cr_colorimetry: The YCbCr colorimetry currently in + * use by the video stream. + * @synchronous_clock_mode: Synchronous clock mode is currently + * in use by the video stream. + */ +struct main_stream_attributes { + struct video_timing_mode vid_timing_mode; + u32 pixel_clock_hz; + u32 h_start; + u32 v_start; + u32 misc0; + u32 misc1; + u32 n_vid; + u32 user_pixel_width; + u32 data_per_lane; + u32 avg_bytes_per_tu; + u32 transfer_unit_size; + u32 init_wait; + u32 bits_per_color; + u8 component_format; + u8 dynamic_range; + u8 y_cb_cr_colorimetry; + u8 synchronous_clock_mode; +}; + +struct av_buf_vid_attribute { + enum av_buf_video_format video_format; + u8 value; + enum av_buf_video_modes mode; + u32 sf[3]; + u8 sampling_en; + u8 is_rgb; + u8 swap; + u8 bpp; +}; + +struct av_buf_mode { + enum av_buf_video_stream video_src; + enum av_buf_gfx_stream gfx_src; + u8 video_clk; +}; + +struct dp_dma_descriptor { + u32 control; + u32 dscr_id; + u32 xfer_size; + u32 line_size_stride; + u32 lsb_timestamp; + u32 msb_timestamp; + u32 addr_ext; + u32 next_desr; + u32 src_addr; + u32 addr_ext_23; + u32 addr_ext_45; + u32 src_addr2; + u32 src_addr3; + u32 src_addr4; + u32 src_addr5; + u32 crc; +}; + +struct dp_dma_channel { + struct dp_dma_descriptor *cur; +}; + +struct dp_dma_frame_buffer { + u64 address; + u32 size; + u32 stride; + u32 line_size; +}; + +struct dp_dma_gfx_channel { + struct dp_dma_channel channel; + u8 trigger_status; + u8 av_buf_en; + struct dp_dma_frame_buffer *frame_buffer; +}; + +struct dp_dma { + phys_addr_t base_addr; + struct dp_dma_gfx_channel gfx; +}; + +/** + * struct zynqmp_dpsub_priv - Private structure + * @dev: Device uclass for video_ops + */ +struct zynqmp_dpsub_priv { + phys_addr_t base_addr; + u32 clock; + struct av_buf_vid_attribute *non_live_graphics; + struct av_buf_mode av_mode; + struct dp_dma_frame_buffer frame_buffer; + + struct link_config link_config; + struct main_stream_attributes msa_config; + struct dp_dma *dp_dma; + enum video_mode video_mode; + enum video_color_depth bpc; + enum video_color_encoding color_encode; + u32 pix_clk; + u8 dpcd_rx_caps[16]; + u8 lane_status_ajd_reqs[6]; + u8 sink_count; + u8 use_max_lane_count; + u8 use_max_link_rate; + u8 lane_count; + u8 link_rate; + u8 use_max_cfg_caps; + u8 en_sync_clk_mode; +}; + +/**************************** Variable Definitions ****************************/ +#define TRAINING_PATTERN_SET 0x000C +#define TRAINING_PATTERN_SET_OFF 0x0 +#define SCRAMBLING_DISABLE 0x0014 +#define TRAINING_PATTERN_SET_TP1 0x1 +#define TRAINING_PATTERN_SET_TP2 0x2 +#define TRAINING_PATTERN_SET_TP3 0x3 + +#define AVBUF_BUF_4BIT_SF 0x11111 +#define AVBUF_BUF_5BIT_SF 0x10842 +#define AVBUF_BUF_6BIT_SF 0x10410 +#define AVBUF_BUF_8BIT_SF 0x10101 +#define AVBUF_BUF_10BIT_SF 0x10040 +#define AVBUF_BUF_12BIT_SF 0x10000 +#define AVBUF_BUF_6BPC 0x000 +#define AVBUF_BUF_8BPC 0x001 +#define AVBUF_BUF_10BPC 0x010 +#define AVBUF_BUF_12BPC 0x011 +#define AVBUF_CHBUF3 0x0000B01C +#define AVBUF_CHBUF3_BURST_LEN_SHIFT 2 +#define AVBUF_CHBUF3_FLUSH_MASK 0x00000002 +#define AVBUF_CHBUF0_EN_MASK 0x00000001 +#define AVBUF_BUF_OUTPUT_AUD_VID_SELECT 0x0000B070 +#define AVBUF_BUF_OUTPUT_AUD_VID_SELECT_VID_STREAM2_SEL_MASK 0x0000000C +#define AVBUF_BUF_OUTPUT_AUD_VID_SELECT_VID_STREAM1_SEL_MASK 0x00000003 +#define AVBUF_BUF_OUTPUT_AUD_VID_SELECT 0x0000B070 +#define AVBUF_BUF_GRAPHICS_COMP0_SCALE_FACTOR 0x0000B200 +#define AVBUF_V_BLEND_LAYER1_CONTROL 0x0000A01C +#define AVBUF_V_BLEND_IN2CSC_COEFF0 0x0000A080 +#define AVBUF_BUF_FORMAT 0x0000B000 +#define AVBUF_BUF_FORMAT_NL_VID_FORMAT_MASK 0x0000001F +#define AVBUF_BUF_FORMAT_NL_GRAPHX_FORMAT_MASK 0x00000F00 +#define AVBUF_BUF_FORMAT_NL_GRAPHX_FORMAT_SHIFT 8 +#define AVBUF_V_BLEND_LAYER0_CONTROL_RGB_MODE_SHIFT 1 +#define AVBUF_V_BLEND_OUTPUT_VID_FORMAT_EN_DOWNSAMPLE_SHIFT 4 +#define AVBUF_V_BLEND_OUTPUT_VID_FORMAT 0x0000A014 +#define AVBUF_V_BLEND_RGB2YCBCR_COEFF0 0x0000A020 +#define AVBUF_V_BLEND_LUMA_OUTCSC_OFFSET 0x0000A074 +#define AVBUF_V_BLEND_LUMA_IN1CSC_OFFSET_POST_OFFSET_SHIFT 16 +#define AVBUF_V_BLEND_SET_GLOBAL_ALPHA_REG_VALUE_SHIFT 1 +#define AVBUF_V_BLEND_SET_GLOBAL_ALPHA_REG 0x0000A00C +#define DP_MAIN_STREAM_MISC0_COMPONENT_FORMAT_SHIFT 1 +#define DP_MAIN_STREAM_MISC0_DYNAMIC_RANGE_SHIFT 3 +#define DP_MAIN_STREAM_MISC0_YCBCR_COLORIMETRY_SHIFT 4 +#define DP_MAIN_STREAM_MISC1_Y_ONLY_EN_MASK 0x00000080 +#define DP_MAIN_STREAM_MISC0_COMPONENT_FORMAT_YCBCR422 0x1 +#define AVBUF_PL_CLK 0x0 +#define AVBUF_PS_CLK 0x1 +#define AVBUF_BUF_AUD_VID_CLK_SOURCE_VID_TIMING_SRC_SHIFT 2 +#define AVBUF_BUF_AUD_VID_CLK_SOURCE_VID_CLK_SRC_SHIFT 0 +#define AVBUF_BUF_AUD_VID_CLK_SOURCE_AUD_CLK_SRC_SHIFT 1 +#define AVBUF_BUF_AUD_VID_CLK_SOURCE 0x0000B120 +#define AVBUF_BUF_SRST_REG 0x0000B124 +#define AVBUF_BUF_SRST_REG_VID_RST_MASK 0x00000002 +#define AVBUF_CLK_FPD_BASEADDR 0xFD1A0000 +#define AVBUF_CLK_LPD_BASEADDR 0xFF5E0000 +#define AVBUF_LPD_CTRL_OFFSET 16 +#define AVBUF_FPD_CTRL_OFFSET 12 +#define AVBUF_EXTERNAL_DIVIDER 2 +#define AVBUF_VIDEO_REF_CTRL 0x00000070 +#define AVBUF_VIDEO_REF_CTRL_SRCSEL_MASK 0x00000007 +#define AVBUF_VPLL_SRC_SEL 0 +#define AVBUF_DPLL_SRC_SEL 2 +#define AVBUF_RPLL_TO_FPD_SRC_SEL 3 +#define AVBUF_INPUT_REF_CLK 3333333333 +#define AVBUF_PLL_OUT_FREQ 1450000000 +#define AVBUF_INPUT_FREQ_PRECISION 100 +#define AVBUF_PRECISION 16 +#define AVBUF_SHIFT_DECIMAL BIT(16) +#define AVBUF_DECIMAL (AVBUF_SHIFT_DECIMAL - 1) +#define AVBUF_ENABLE_BIT 1 +#define AVBUF_DISABLE_BIT 0 +#define AVBUF_PLL_CTRL_BYPASS_SHIFT 3 +#define AVBUF_PLL_CTRL_FBDIV_SHIFT 8 +#define AVBUF_PLL_CTRL_DIV2_SHIFT 16 +#define AVBUF_PLL_CTRL_PRE_SRC_SHIFT 20 +#define AVBUF_PLL_CTRL 0x00000020 +#define AVBUF_PLL_CFG_CP_SHIFT 5 +#define AVBUF_PLL_CFG_RES_SHIFT 0 +#define AVBUF_PLL_CFG_LFHF_SHIFT 10 +#define AVBUF_PLL_CFG_LOCK_DLY_SHIFT 25 +#define AVBUF_PLL_CFG_LOCK_CNT_SHIFT 13 +#define AVBUF_PLL_FRAC_CFG 0x00000028 +#define AVBUF_PLL_FRAC_CFG_ENABLED_SHIFT 31 +#define AVBUF_PLL_FRAC_CFG_DATA_SHIFT 0 +#define AVBUF_PLL_CTRL_RESET_MASK 0x00000001 +#define AVBUF_PLL_CTRL_RESET_SHIFT 0 +#define AVBUF_PLL_STATUS 0x00000044 +#define AVBUF_REG_OFFSET 4 +#define AVBUF_PLL_CTRL_BYPASS_MASK 0x00000008 +#define AVBUF_PLL_CTRL_BYPASS_SHIFT 3 +#define AVBUF_DOMAIN_SWITCH_CTRL 0x00000044 +#define AVBUF_DOMAIN_SWITCH_DIVISOR0_MASK 0x00003F00 +#define AVBUF_DOMAIN_SWITCH_DIVISOR0_SHIFT 8 +#define AVBUF_PLL_CFG 0x00000024 +#define AVBUF_BUF_AUD_VID_CLK_SOURCE_VID_CLK_SRC_SHIFT 0 +#define AVBUF_VIDEO_REF_CTRL_CLKACT_MASK 0x01000000 +#define AVBUF_VIDEO_REF_CTRL_CLKACT_SHIFT 24 +#define AVBUF_VIDEO_REF_CTRL_DIVISOR1_MASK 0x003F0000 +#define AVBUF_VIDEO_REF_CTRL_DIVISOR1_SHIFT 16 +#define AVBUF_VIDEO_REF_CTRL_DIVISOR0_MASK 0x00003F00 +#define AVBUF_VIDEO_REF_CTRL_DIVISOR0_SHIFT 8 +#define AVBUF_VIDEO_REF_CTRL_CLKACT_MASK 0x01000000 +#define AVBUF_VIDEO_REF_CTRL_CLKACT_SHIFT 24 + +#define DP_INTERRUPT_SIG_STATE 0x0130 +#define DP_INTR_STATUS 0x03A0 +#define DP_INTERRUPT_SIG_STATE_HPD_STATE_MASK 0x00000001 +#define DP_INTR_HPD_EVENT_MASK 0x00000002 +#define DP_INTR_HPD_PULSE_DETECTED_MASK 0x00000010 +#define DP_HPD_DURATION 0x0150 +#define DP_FORCE_SCRAMBLER_RESET 0x00C0 +#define DP_ENABLE_MAIN_STREAM 0x0084 +#define DP_IS_CONNECTED_MAX_TIMEOUT_COUNT 50 +#define DP_0_LINK_RATE 20 +#define DP_0_LANE_COUNT 1 +#define DP_ENHANCED_FRAME_EN 0x0008 +#define DP_LANE_COUNT_SET 0x0004 +#define DP_LINK_BW_SET_162GBPS 0x06 +#define DP_LINK_BW_SET_270GBPS 0x0A +#define DP_LINK_BW_SET_540GBPS 0x14 +#define DP_LINK_BW_SET 0x0000 +#define DP_DOWNSPREAD_CTRL 0x0018 +#define DP_SCRAMBLING_DISABLE 0x0014 +#define DP_AUX_CMD_READ 0x9 +#define DP_AUX_CMD_WRITE 0x8 +#define DP_AUX_CMD_I2C_READ 0x1 +#define DP_AUX_CMD_I2C_READ_MOT 0x5 +#define DP_AUX_CMD_I2C_WRITE 0x0 +#define DP_AUX_CMD_I2C_WRITE_MOT 0x4 +#define DP_REPLY_STATUS_REPLY_IN_PROGRESS_MASK 0x00000002 +#define DP_REPLY_STATUS_REQUEST_IN_PROGRESS_MASK 0x00000004 +#define DP_REPLY_STATUS 0x014C +#define DP_AUX_MAX_TIMEOUT_COUNT 50 +#define DP_AUX_MAX_DEFER_COUNT 50 +#define DP_AUX_ADDRESS 0x0108 +#define DP_AUX_WRITE_FIFO 0x0104 +#define DP_AUX_CMD 0x0100 +#define DP_AUX_CMD_SHIFT 8 +#define DP_AUX_CMD_NBYTES_TRANSFER_MASK 0x0000000F +#define DP_AUX_REPLY_CODE 0x0138 +#define DP_AUX_REPLY_CODE_DEFER 0x2 +#define DP_AUX_REPLY_CODE_I2C_DEFER 0x8 +#define DP_AUX_REPLY_CODE_NACK 0x1 +#define DP_AUX_REPLY_CODE_I2C_NACK 0x4 +#define DP_REPLY_DATA_COUNT 0x0148 +#define DP_AUX_REPLY_DATA 0x0134 +#define DP_LANE_COUNT_SET_1 0x01 +#define DP_LANE_COUNT_SET_2 0x02 +#define DP_MAXIMUM_PE_LEVEL 2 +#define DP_MAXIMUM_VS_LEVEL 3 +#define DP_MAIN_STREAM_MISC0_COMPONENT_FORMAT_RGB 0x0 +#define DP_MAIN_STREAM_MISC0_BDC_6BPC 0x0 +#define DP_MAIN_STREAM_MISC0_BDC_8BPC 0x1 +#define DP_MAIN_STREAM_MISC0_BDC_10BPC 0x2 +#define DP_MAIN_STREAM_MISC0_BDC_12BPC 0x3 +#define DP_MAIN_STREAM_MISC0_BDC_16BPC 0x4 +#define DP_MAIN_STREAM_MISC0_BDC_SHIFT 5 +#define DP_PHY_CONFIG_TX_PHY_8B10BEN_MASK 0x0010000 +#define DP_PHY_CONFIG_PHY_RESET_MASK 0x0000001 +#define DP_ENABLE_MAIN_STREAM 0x0084 +#define DP_SOFT_RESET 0x001C +#define DP_MAIN_STREAM_HTOTAL 0x0180 +#define DP_MAIN_STREAM_VTOTAL 0x0184 +#define DP_MAIN_STREAM_POLARITY 0x0188 +#define DP_MAIN_STREAM_POLARITY_VSYNC_POL_SHIFT 1 +#define DP_MAIN_STREAM_HSWIDTH 0x018C +#define DP_MAIN_STREAM_VSWIDTH 0x0190 +#define DP_MAIN_STREAM_HRES 0x0194 +#define DP_MAIN_STREAM_VRES 0x0198 +#define DP_MAIN_STREAM_HSTART 0x019C +#define DP_MAIN_STREAM_VSTART 0x01A0 +#define DP_MAIN_STREAM_MISC0 0x01A4 +#define DP_MAIN_STREAM_MISC1 0x01A8 +#define DP_M_VID 0x01AC +#define DP_N_VID 0x01B4 +#define DP_USER_PIXEL_WIDTH 0x01B8 +#define DP_USER_DATA_COUNT_PER_LANE 0x01BC +#define DP_TU_SIZE 0x01B0 +#define DP_MIN_BYTES_PER_TU 0x01C4 +#define DP_FRAC_BYTES_PER_TU 0x01C8 +#define DP_INIT_WAIT 0x01CC +#define DP_PHY_CLOCK_SELECT_162GBPS 0x1 +#define DP_PHY_CLOCK_SELECT_270GBPS 0x3 +#define DP_PHY_CLOCK_SELECT_540GBPS 0x5 +#define DP_PHY_STATUS 0x0280 +#define DP_PHY_STATUS_ALL_LANES_READY_MASK 0x00000013 +#define DP_PHY_STATUS_GT_PLL_LOCK_MASK 0x00000010 +#define DP_PHY_STATUS_RESET_LANE_0_DONE_MASK 0x00000001 +#define DP_INTR_HPD_IRQ_MASK 0x00000001 +#define DP_INTR_MASK 0x03A4 +#define DP_DP_ENABLE 0x1 +#define DP_PHY_CONFIG_GT_ALL_RESET_MASK 0x0000003 +#define DP_PHY_CLOCK_SELECT 0x0234 +#define DP_AUX_CLK_DIVIDER_VAL_MASK 0x000000FF +#define DP_AUX_CLK_DIVIDER 0x010C +#define DP_DISABLE 0x0 +#define DP_ENABLE 0x0080 +#define DP_SOFT_RESET_EN 0x1 +#define DP_PHY_CONFIG 0x0200 +#define DP_REPLY_STATUS_REPLY_RECEIVED_MASK 0x00000001 +#define DP_REPLY_STATUS_REPLY_IN_PROGRESS_MASK 0x00000002 +#define DP_REPLY_STATUS_REPLY_ERROR_MASK 0x00000008 +#define DP_AUX_MAX_WAIT 20000 + +#define DP_DPCD_SINK_COUNT 0x00200 +#define DP_DPCD_TP_SET_SCRAMB_DIS_MASK 0x20 +#define DP_DPCD_STATUS_LANE_1_CR_DONE_MASK 0x10 +#define DP_DPCD_STATUS_LANE_0_CR_DONE_MASK 0x01 +#define DP_DPCD_STATUS_LANE_1_CE_DONE_MASK 0x20 +#define DP_DPCD_STATUS_LANE_0_CE_DONE_MASK 0x02 +#define DP_DPCD_STATUS_LANE_1_SL_DONE_MASK 0x40 +#define DP_DPCD_STATUS_LANE_0_SL_DONE_MASK 0x04 +#define DP_DPCD_LANE_ALIGN_STATUS_UPDATED_IA_DONE_MASK 0x01 +#define DP_DPCD_ADJ_REQ_LANE_0_2_VS_MASK 0x03 +#define DP_DPCD_ADJ_REQ_LANE_1_3_VS_MASK 0x30 +#define DP_DPCD_ADJ_REQ_LANE_1_3_VS_SHIFT 4 +#define DP_DPCD_ADJ_REQ_LANE_0_2_PE_MASK 0x0C +#define DP_DPCD_ADJ_REQ_LANE_0_2_PE_SHIFT 2 +#define DP_DPCD_ADJ_REQ_LANE_1_3_PE_MASK 0xC0 +#define DP_DPCD_ADJ_REQ_LANE_1_3_PE_SHIFT 6 +#define DP_DPCD_TRAINING_LANE0_SET 0x00103 +#define DP_DPCD_TRAINING_LANEX_SET_MAX_VS_MASK 0x04 +#define DP_DPCD_TRAINING_LANEX_SET_MAX_PE_MASK 0x20 +#define DP_DPCD_TRAINING_LANEX_SET_PE_SHIFT 3 +#define DP_DPCD_SET_POWER_DP_PWR_VOLTAGE 0x00600 +#define DP_DPCD_RECEIVER_CAP_FIELD_START 0x00000 +#define DP_DPCD_MAX_LINK_RATE 0x00001 +#define DP_DPCD_MAX_LANE_COUNT 0x00002 +#define DP_DPCD_MAX_LANE_COUNT_MASK 0x1F +#define DP_DPCD_ENHANCED_FRAME_SUPPORT_MASK 0x80 +#define DP_DPCD_MAX_DOWNSPREAD 0x00003 +#define DP_DPCD_MAX_DOWNSPREAD_MASK 0x01 +#define DP_DPCD_LANE_COUNT_SET 0x00101 +#define DP_DPCD_ENHANCED_FRAME_EN_MASK 0x80 +#define DP_DPCD_LINK_BW_SET 0x00100 +#define DP_DPCD_DOWNSPREAD_CTRL 0x00107 +#define DP_DPCD_SPREAD_AMP_MASK 0x10 +#define DP_DPCD_LANE_COUNT_SET_MASK 0x1F +#define DP_DPCD_TPS3_SUPPORT_MASK 0x40 +#define DP_DPCD_TRAIN_AUX_RD_INTERVAL 0x0000E +#define DP_DPCD_SINK_COUNT_HIGH_MASK 0x80 +#define DP_DPCD_SINK_COUNT_HIGH_LOW_SHIFT 1 +#define DP_DPCD_SINK_COUNT_LOW_MASK 0x3F +#define DP_DPCD_TP_SET 0x00102 + +#define SERDES_BASEADDR 0xFD400000 +#define SERDES_L0_TX_MARGININGF 0x0CC0 +#define SERDES_L0_TX_DEEMPHASIS 0x0048 +#define SERDES_LANE_OFFSET 0x4000 + +#define DPDMA_TRIGGER_EN 1U +#define DPDMA_RETRIGGER_EN 2U +#define DPDMA_DESC_PREAMBLE 0xA5U +#define DPDMA_DESC_IGNR_DONE 0x400U +#define DPDMA_DESC_LAST_FRAME 0x200000U +#define DPDMA_DESCRIPTOR_LINE_SIZE_STRIDE_SHIFT 18 +#define DPDMA_DESCRIPTOR_SRC_ADDR_WIDTH 32U +#define DPDMA_DESCRIPTOR_ADDR_EXT_SRC_ADDR_EXT_SHIFT 16U +#define DPDMA_CH0_DSCR_STRT_ADDR 0X0204U +#define DPDMA_CH_OFFSET 0x100U +#define DPDMA_CH0_CNTL 0x0218U +#define DPDMA_CH3_CNTL 0x0518U +#define DPDMA_CH0_DSCR_STRT_ADDRE 0x0200U +#define DPDMA_CH3_DSCR_STRT_ADDR 0x0504 +#define DPDMA_CH3_DSCR_STRT_ADDRE 0x0500 +#define DPDMA_CH_CNTL_EN_MASK 0x1U +#define DPDMA_CH_CNTL_PAUSE_MASK 0x2U +#define DPDMA_GBL 0x0104U +#define DPDMA_GBL_TRG_CH3_MASK 0x8 +#define DPDMA_TRIGGER_DONE 0U +#define DPDMA_CH_CNTL_EN_MASK 0x1U +#define DPDMA_CH_CNTL_PAUSE_MASK 0x2U +#define DPDMA_CH_CNTL_QOS_DATA_RD_SHIFT 10U +#define DPDMA_CH_CNTL_QOS_DATA_RD_MASK 0x3C00U +#define DPDMA_CH_CNTL_QOS_DSCR_RD_SHIFT 6U +#define DPDMA_CH_CNTL_QOS_DSCR_RD_MASK 0x03C0U +#define DPDMA_CH_CNTL_QOS_DSCR_WR_SHIFT 2U +#define DPDMA_CH_CNTL_QOS_DSCR_WR_MASK 0x3CU +#define DPDMA_CH_OFFSET 0x100U +#define DPDMA_WAIT_TIMEOUT 10000U +#define DPDMA_AUDIO_ALIGNMENT 128U +#define DPDMA_VIDEO_CHANNEL0 0U +#define DPDMA_VIDEO_CHANNEL1 1U +#define DPDMA_VIDEO_CHANNEL2 2U +#define DPDMA_GRAPHICS_CHANNEL 3U +#define DPDMA_AUDIO_CHANNEL0 4U +#define DPDMA_AUDIO_CHANNEL1 5U +#define DPDMA_DESC_PREAMBLE 0xA5U +#define DPDMA_DESC_IGNR_DONE 0x400U +#define DPDMA_DESC_UPDATE 0x200U +#define DPDMA_DESC_COMP_INTR 0x100U +#define DPDMA_DESC_LAST_FRAME 0x200000U +#define DPDMA_DESC_DONE_SHIFT 31U +#define DPDMA_QOS_MIN 4U +#define DPDMA_QOS_MAX 11U +#define DPDMA_BASE_ADDRESS 0xFD4C0000 +#define DPDMA_ISR 0x0004U +#define DPDMA_IEN 0x000CU +#define DPDMA_ISR_VSYNC_INT_MASK 0x08000000 + +#define CLK_FPD_BASEADDR 0xFD1A0000 +#define VIDEO_REF_CTRL 0x00000070 +#define VIDEO_REF_CTRL_SRCSEL_MASK 0x00000007 +#define PLL_OUT_FREQ 1450000000 +#define INPUT_FREQ_PRECISION 100 +#define PRECISION 16 +#define SHIFT_DECIMAL BIT(16) +#define ENABLE_BIT 1 +#define DISABLE_BIT 0 +#define PLL_CTRL_BYPASS_SHIFT 3 +#define PLL_CTRL_FBDIV_SHIFT 8 +#define PLL_CTRL_DIV2_SHIFT 16 +#define PLL_CTRL_PRE_SRC_SHIFT 20 +#define PLL_CTRL 0x00000020 +#define VPLL_CTRL 0x00000038 +#define PLL_CFG 0x00000024 +#define VPLL 2 +#define VPLL_CFG 0x0000003C +#define VPLL_CFG_CP 4 +#define VPLL_CFG_RES 6 +#define VPLL_CFG_LFHF 3 +#define VPLL_CFG_LOCK_DLY 63 +#define VPLL_CFG_LOCK_CNT 600 +#define PLL_STATUS_VPLL_LOCK 2 +#define PLL_CFG_CP_SHIFT 5 +#define PLL_CFG_RES_SHIFT 0 +#define PLL_CFG_LFHF_SHIFT 10 +#define PLL_CFG_LOCK_DLY_SHIFT 25 +#define PLL_CFG_LOCK_CNT_SHIFT 13 +#define PLL_FRAC_CFG 0x00000028 +#define VPLL_FRAC_CFG 0x00000040 +#define PLL_FRAC_CFG_ENABLED_SHIFT 31 +#define PLL_FRAC_CFG_DATA_SHIFT 0 +#define PLL_CTRL_RESET_MASK 0x00000001 +#define PLL_CTRL_RESET_SHIFT 0 +#define PLL_STATUS 0x00000044 +#define REG_OFFSET 4 +#define PLL_CTRL_BYPASS_MASK 0x00000008 +#define PLL_CTRL_BYPASS_SHIFT 3 +#define DOMAIN_SWITCH_CTRL 0x00000044 +#define DOMAIN_SWITCH_DIVISOR0_MASK 0x00003F00 +#define DOMAIN_SWITCH_DIVISOR0_SHIFT 8 +#define VIDEO_REF_CTRL_CLKACT_MASK 0x01000000 +#define VIDEO_REF_CTRL_CLKACT_SHIFT 24 +#define VIDEO_REF_CTRL_DIVISOR1_MASK 0x003F0000 +#define VIDEO_REF_CTRL_DIVISOR1_SHIFT 16 +#define VIDEO_REF_CTRL_DIVISOR0_MASK 0x00003F00 +#define VIDEO_REF_CTRL_DIVISOR0_SHIFT 8 +#define PSS_REF_CLK 0 +#define FPD_CTRL_OFFSET 12 +#define VIDC_VM_NUM_SUPPORTED 2 + +static const u32 vs[4][4] = { + { 0x2a, 0x27, 0x24, 0x20 }, + { 0x27, 0x23, 0x20, 0xff }, + { 0x24, 0x20, 0xff, 0xff }, + { 0xff, 0xff, 0xff, 0xff }, +}; + +static const u32 pe[4][4] = { + { 0x02, 0x02, 0x02, 0x02 }, + { 0x01, 0x01, 0x01, 0xff }, + { 0x00, 0x00, 0xff, 0xff }, + { 0xff, 0xff, 0xff, 0xff }, +}; + +const struct video_timing_mode vidc_video_timing_modes[VIDC_VM_NUM_SUPPORTED] = { + { VIDC_VM_640x480_60_P, "640x480@60Hz", VIDC_FR_60HZ, + {640, 16, 96, 48, 800, 0, + 480, 10, 2, 33, 525, 0, 0, 0, 0, 0} }, + { VIDC_VM_1024x768_60_P, "1024x768@60Hz", VIDC_FR_60HZ, + {1024, 24, 136, 160, 1344, 0, + 768, 3, 6, 29, 806, 0, 0, 0, 0, 0} }, +}; + +const struct av_buf_vid_attribute avbuf_supported_formats[] = { + /* Non-Live Graphics formats */ + { RGBA8888, 0, INTERLEAVED, + {AVBUF_BUF_8BIT_SF, AVBUF_BUF_8BIT_SF, AVBUF_BUF_8BIT_SF}, + 0, 1, 0, 32}, +}; + +#endif diff --git a/drivers/video/zynqmp_dpsub.c b/drivers/video/zynqmp_dpsub.c deleted file mode 100644 index 4ead663cd59..00000000000 --- a/drivers/video/zynqmp_dpsub.c +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2021 Xilinx Inc. - */ - -#include <common.h> -#include <cpu_func.h> -#include <dm.h> -#include <errno.h> -#include <video.h> -#include <dm/device_compat.h> - -#define WIDTH 640 -#define HEIGHT 480 - -/** - * struct zynqmp_dpsub_priv - Private structure - * @dev: Device uclass for video_ops - */ -struct zynqmp_dpsub_priv { - struct udevice *dev; -}; - -static int zynqmp_dpsub_probe(struct udevice *dev) -{ - struct video_priv *uc_priv = dev_get_uclass_priv(dev); - struct zynqmp_dpsub_priv *priv = dev_get_priv(dev); - - uc_priv->bpix = VIDEO_BPP16; - uc_priv->xsize = WIDTH; - uc_priv->ysize = HEIGHT; - uc_priv->rot = 0; - - priv->dev = dev; - - /* Only placeholder for power domain driver */ - return 0; -} - -static int zynqmp_dpsub_bind(struct udevice *dev) -{ - struct video_uc_plat *plat = dev_get_uclass_plat(dev); - - plat->size = WIDTH * HEIGHT * 16; - - return 0; -} - -static const struct video_ops zynqmp_dpsub_ops = { -}; - -static const struct udevice_id zynqmp_dpsub_ids[] = { - { .compatible = "xlnx,zynqmp-dpsub-1.7" }, - { } -}; - -U_BOOT_DRIVER(zynqmp_dpsub_video) = { - .name = "zynqmp_dpsub_video", - .id = UCLASS_VIDEO, - .of_match = zynqmp_dpsub_ids, - .ops = &zynqmp_dpsub_ops, - .plat_auto = sizeof(struct video_uc_plat), - .bind = zynqmp_dpsub_bind, - .probe = zynqmp_dpsub_probe, - .priv_auto = sizeof(struct zynqmp_dpsub_priv), -}; |