diff options
Diffstat (limited to 'drivers')
62 files changed, 1794 insertions, 1559 deletions
diff --git a/drivers/adc/imx93-adc.c b/drivers/adc/imx93-adc.c index f593fb6447b..d671df79f68 100644 --- a/drivers/adc/imx93-adc.c +++ b/drivers/adc/imx93-adc.c @@ -221,7 +221,7 @@ static int imx93_adc_stop(struct udevice *dev) static int imx93_adc_probe(struct udevice *dev) { struct imx93_adc_priv *adc = dev_get_priv(dev); - unsigned int ret; + int ret; ret = imx93_adc_calibration(adc); if (ret < 0) @@ -238,7 +238,7 @@ static int imx93_adc_of_to_plat(struct udevice *dev) { struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); struct imx93_adc_priv *adc = dev_get_priv(dev); - unsigned int ret; + int ret; adc->regs = dev_read_addr_ptr(dev); if (adc->regs == (struct imx93_adc *)FDT_ADDR_T_NONE) { diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index f3ac8db9464..73c24fd9176 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -611,30 +611,6 @@ static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags) return flags & req_flags ? 0 : 1; } -int blk_find_first(enum blk_flag_t flags, struct udevice **devp) -{ - int ret; - - for (ret = uclass_find_first_device(UCLASS_BLK, devp); - *devp && !blk_flags_check(*devp, flags); - ret = uclass_find_next_device(devp)) - return 0; - - return -ENODEV; -} - -int blk_find_next(enum blk_flag_t flags, struct udevice **devp) -{ - int ret; - - for (ret = uclass_find_next_device(devp); - *devp && !blk_flags_check(*devp, flags); - ret = uclass_find_next_device(devp)) - return 0; - - return -ENODEV; -} - int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp) { for (uclass_first_device(UCLASS_BLK, devp); diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index b80ad05b8ad..822cf0809d5 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -32,6 +32,7 @@ struct ccu_internal { struct ccu_div_internal { u8 shift; u8 width; + unsigned long flags; }; struct ccu_common { @@ -79,6 +80,7 @@ struct ccu_pll { { \ .shift = _shift, \ .width = _width, \ + .flags = _flags, \ } #define CCU_GATE(_clkid, _struct, _name, _parent, _reg, _gate, _flags) \ @@ -182,7 +184,7 @@ static unsigned long ccu_div_get_rate(struct clk *clk) val = val >> cd->div.shift; val &= GENMASK(cd->div.width - 1, 0); rate = divider_recalc_rate(clk, clk_get_parent_rate(clk), val, NULL, - 0, cd->div.width); + cd->div.flags, cd->div.width); return rate; } diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index ce5e61bbaa6..5365ac68f9e 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -261,17 +261,14 @@ int uclass_find_first_device(enum uclass_id id, struct udevice **devp) return 0; } -int uclass_find_next_device(struct udevice **devp) +void uclass_find_next_device(struct udevice **devp) { struct udevice *dev = *devp; *devp = NULL; - if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head)) - return 0; - - *devp = list_entry(dev->uclass_node.next, struct udevice, uclass_node); - - return 0; + if (!list_is_last(&dev->uclass_node, &dev->uclass->dev_head)) + *devp = list_entry(dev->uclass_node.next, struct udevice, + uclass_node); } int uclass_find_device_by_namelen(enum uclass_id id, const char *name, int len, @@ -675,11 +672,8 @@ int uclass_first_device_check(enum uclass_id id, struct udevice **devp) int uclass_next_device_check(struct udevice **devp) { - int ret; + uclass_find_next_device(devp); - ret = uclass_find_next_device(devp); - if (ret) - return ret; if (!*devp) return 0; diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 70207573de2..843171902ae 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -91,7 +91,7 @@ config FASTBOOT_USB_DEV config FASTBOOT_FLASH bool "Enable FASTBOOT FLASH command" default y if ARCH_SUNXI || ARCH_ROCKCHIP - depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS) + depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS) || DM_SPI_FLASH select IMAGE_SPARSE help The fastboot protocol includes a "flash" command for writing @@ -119,6 +119,10 @@ config FASTBOOT_FLASH_NAND bool "FASTBOOT on NAND" depends on MTD_RAW_NAND && CMD_MTDPARTS +config FASTBOOT_FLASH_SPI + bool "FASTBOOT on SPI flash" + depends on DM_SPI_FLASH + endchoice config FASTBOOT_FLASH_MMC_DEV diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile index 048af5aa823..adedba0bf24 100644 --- a/drivers/fastboot/Makefile +++ b/drivers/fastboot/Makefile @@ -5,3 +5,4 @@ obj-y += fb_getvar.o obj-y += fb_command.o obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o +obj-$(CONFIG_FASTBOOT_FLASH_SPI) += fb_spi_flash.o diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index 2cdbac50ac4..791088bc094 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -10,6 +10,7 @@ #include <fastboot-internal.h> #include <fb_mmc.h> #include <fb_nand.h> +#include <fb_spi_flash.h> #include <part.h> #include <stdlib.h> #include <vsprintf.h> @@ -344,6 +345,10 @@ static void __maybe_unused flash(char *cmd_parameter, char *response) if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND)) fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size, response); + + if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_SPI)) + fastboot_spi_flash_write(cmd_parameter, fastboot_buf_addr, + image_size, response); } /** @@ -362,6 +367,9 @@ static void __maybe_unused erase(char *cmd_parameter, char *response) if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND)) fastboot_nand_erase(cmd_parameter, response); + + if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_SPI)) + fastboot_spi_flash_erase(cmd_parameter, response); } /** @@ -405,7 +413,7 @@ static void __maybe_unused run_acmd(char *cmd_parameter, char *response) return; } - if (strlen(cmd_parameter) > sizeof(g_a_cmd_buff)) { + if (strlen(cmd_parameter) >= sizeof(g_a_cmd_buff)) { pr_err("too long command\n"); fastboot_fail("too long command", response); return; diff --git a/drivers/fastboot/fb_getvar.c b/drivers/fastboot/fb_getvar.c index 9c2ce65a4e5..6775ea397ab 100644 --- a/drivers/fastboot/fb_getvar.c +++ b/drivers/fastboot/fb_getvar.c @@ -8,6 +8,7 @@ #include <fastboot-internal.h> #include <fb_mmc.h> #include <fb_nand.h> +#include <fb_spi_flash.h> #include <fs.h> #include <part.h> #include <version.h> @@ -123,6 +124,11 @@ static int getvar_get_part_info(const char *part_name, char *response, r = fastboot_nand_get_part_info(part_name, &part_info, response); if (r >= 0 && size) *size = part_info->size; + } else if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_SPI)) { + r = fastboot_spi_flash_get_part_info(part_name, &disk_part, + response); + if (r >= 0 && size) + *size = disk_part.size * disk_part.blksz; } else { fastboot_fail("this storage is not supported in bootloader", response); r = -ENODEV; diff --git a/drivers/fastboot/fb_spi_flash.c b/drivers/fastboot/fb_spi_flash.c new file mode 100644 index 00000000000..691be7c7ef7 --- /dev/null +++ b/drivers/fastboot/fb_spi_flash.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2025 Collabora Ltd. + */ + +#include <blk.h> +#include <config.h> +#include <env.h> +#include <fastboot.h> +#include <image-sparse.h> +#include <spi.h> +#include <spi_flash.h> +#include <dm.h> +#include <dm/device-internal.h> + +static struct spi_flash *flash; + +__weak int board_fastboot_spi_flash_write_setup(void) +{ + return 0; +} + +__weak int board_fastboot_spi_flash_erase_setup(void) +{ + return 0; +} + +static int raw_part_get_info_by_name(const char *name, + struct disk_partition *part_info) +{ + /* strlen("fastboot_raw_partition_") + PART_NAME_LEN + 1 */ + char env_desc_name[23 + PART_NAME_LEN + 1]; + char *raw_part_desc; + const char *argv[2]; + const char **parg = argv; + + /* check for raw partition descriptor */ + strcpy(env_desc_name, "fastboot_raw_partition_"); + strlcat(env_desc_name, name, sizeof(env_desc_name)); + raw_part_desc = strdup(env_get(env_desc_name)); + if (!raw_part_desc) + return -ENODEV; + + /* parse partition descriptor: <start> <size> */ + for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) { + *parg = strsep(&raw_part_desc, " "); + if (!*parg) { + pr_err("Invalid number of arguments.\n"); + return -ENODEV; + } + } + + part_info->start = simple_strtoul(argv[0], NULL, 0); + part_info->size = simple_strtoul(argv[1], NULL, 0); + strlcpy((char *)part_info->name, name, PART_NAME_LEN); + + return 0; +} + +static int fastboot_spi_flash_probe(void) +{ + unsigned int bus = CONFIG_SF_DEFAULT_BUS; + unsigned int cs = CONFIG_SF_DEFAULT_CS; + struct udevice *new, *bus_dev; + int ret; + + /* Remove the old device, otherwise probe will just be a nop */ + ret = spi_find_bus_and_cs(bus, cs, &bus_dev, &new); + if (!ret) + device_remove(new, DM_REMOVE_NORMAL); + + spi_flash_probe_bus_cs(bus, cs, &new); + flash = dev_get_uclass_priv(new); + if (!flash) { + printf("Failed to initialize SPI flash at %u:%u (error %d)\n", + bus, cs, ret); + return 1; + } + + return 0; +} + +static int fastboot_spi_flash_unlock(struct spi_flash *flash, + struct disk_partition *part_info) +{ + int ret = spi_flash_protect(flash, part_info->start, part_info->size, + false); + + if (ret && ret != -EOPNOTSUPP) { + printf("Failed to unlock SPI flash (%d)\n", ret); + return ret; + } + + return 0; +} + +static lbaint_t fb_spi_flash_sparse_write(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt, + const void *buffer) +{ + size_t len = blkcnt * info->blksz; + u32 offset = blk * info->blksz; + int ret; + + ret = spi_flash_erase(flash, offset, ROUND(len, flash->erase_size)); + if (ret < 0) { + printf("Failed to erase sparse chunk (%d)\n", ret); + return ret; + } + + ret = spi_flash_write(flash, offset, len, buffer); + if (ret < 0) { + printf("Failed to write sparse chunk (%d)\n", ret); + return ret; + } + + return blkcnt; +} + +static lbaint_t fb_spi_flash_sparse_reserve(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt) +{ + return blkcnt; +} + +/** + * fastboot_spi_flash_get_part_info() - Lookup SPI partition by name + * + * @part_name: Named device to lookup + * @part_info: Pointer to returned struct disk_partition + * @response: Pointer to fastboot response buffer + * Return: 0 if OK, -ENOENT if no partition name was given, -ENODEV on invalid + * raw partition descriptor + */ +int fastboot_spi_flash_get_part_info(const char *part_name, + struct disk_partition *part_info, + char *response) +{ + int ret; + + if (!part_name || !strcmp(part_name, "")) { + fastboot_fail("partition not given", response); + return -ENOENT; + } + + /* TODO: Support partitions on the device */ + ret = raw_part_get_info_by_name(part_name, part_info); + if (ret < 0) + fastboot_fail("invalid partition or device", response); + + return ret; +} + +/** + * fastboot_spi_flash_write() - Write image to SPI for fastboot + * + * @cmd: Named device to write image to + * @download_buffer: Pointer to image data + * @download_bytes: Size of image data + * @response: Pointer to fastboot response buffer + */ +void fastboot_spi_flash_write(const char *cmd, void *download_buffer, + u32 download_bytes, char *response) +{ + struct disk_partition part_info; + int ret; + + if (fastboot_spi_flash_get_part_info(cmd, &part_info, response)) + return; + + if (fastboot_spi_flash_probe()) + return; + + if (board_fastboot_spi_flash_write_setup()) + return; + + if (fastboot_spi_flash_unlock(flash, &part_info)) + return; + + if (is_sparse_image(download_buffer)) { + struct sparse_storage sparse; + + sparse.blksz = flash->sector_size; + sparse.start = part_info.start / sparse.blksz; + sparse.size = part_info.size / sparse.blksz; + sparse.write = fb_spi_flash_sparse_write; + sparse.reserve = fb_spi_flash_sparse_reserve; + sparse.mssg = fastboot_fail; + + printf("Flashing sparse image at offset " LBAFU "\n", + sparse.start); + + ret = write_sparse_image(&sparse, cmd, download_buffer, + response); + } else { + printf("Flashing raw image at offset " LBAFU "\n", + part_info.start); + + ret = spi_flash_erase(flash, part_info.start, + ROUND(download_bytes, flash->erase_size)); + if (ret < 0) { + printf("Failed to erase raw image (%d)\n", ret); + return; + } + ret = spi_flash_write(flash, part_info.start, download_bytes, + download_buffer); + if (ret < 0) { + printf("Failed to write raw image (%d)\n", ret); + return; + } + printf("........ wrote %u bytes\n", download_bytes); + } + + if (ret) + fastboot_fail("error writing the image", response); + else + fastboot_okay(NULL, response); +} + +/** + * fastboot_spi_flash_erase() - Erase SPI for fastboot + * + * @cmd: Named device to erase + * @response: Pointer to fastboot response buffer + */ +void fastboot_spi_flash_erase(const char *cmd, char *response) +{ + struct disk_partition part_info; + int ret; + + if (fastboot_spi_flash_get_part_info(cmd, &part_info, response)) + return; + + if (fastboot_spi_flash_probe()) + return; + + if (board_fastboot_spi_flash_erase_setup()) + return; + + if (fastboot_spi_flash_unlock(flash, &part_info)) + return; + + ret = spi_flash_erase(flash, part_info.start, part_info.size); + if (ret < 0) { + pr_err("failed erasing from SPI flash"); + fastboot_fail("failed erasing from SPI flash", response); + return; + } + + fastboot_okay(NULL, response); +} diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index d18ae523b6b..e07ec3929b2 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -500,11 +500,8 @@ static int zynqmp_firmware_bind(struct udevice *dev) if (!smc_call_handler) return -EINVAL; - if ((IS_ENABLED(CONFIG_XPL_BUILD) && - IS_ENABLED(CONFIG_SPL_POWER_DOMAIN) && - IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN)) || - (!IS_ENABLED(CONFIG_XPL_BUILD) && - IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN))) { + if (CONFIG_IS_ENABLED(POWER_DOMAIN) && + IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN)) { ret = device_bind_driver_to_node(dev, "zynqmp_power_domain", "zynqmp_power_domain", dev_ofnode(dev), &child); diff --git a/drivers/fpga/ACEX1K.c b/drivers/fpga/ACEX1K.c index 3de9011ac06..e1514fc56d0 100644 --- a/drivers/fpga/ACEX1K.c +++ b/drivers/fpga/ACEX1K.c @@ -14,6 +14,7 @@ #include <log.h> #include <ACEX1K.h> /* ACEX device family */ #include <linux/delay.h> +#include <time.h> /* Note: The assumption is that we cannot possibly run fast enough to * overrun the device (the Slave Parallel mode can free run at 50MHz). diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 62cb77b098c..9456ca3149a 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -15,6 +15,7 @@ config FPGA_ALTERA config FPGA_SOCFPGA bool "Enable Gen5 and Arria10 common FPGA drivers" + depends on ARCH_SOCFPGA select FPGA_ALTERA help Say Y here to enable the Gen5 and Arria10 common FPGA driver diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c index f88267e01b6..2297fefd149 100644 --- a/drivers/fpga/fpga.c +++ b/drivers/fpga/fpga.c @@ -16,20 +16,6 @@ static int next_desc = FPGA_INVALID_DEVICE; static fpga_desc desc_table[CONFIG_MAX_FPGA_DEVICES]; -/* - * fpga_no_sup - * 'no support' message function - */ -static void fpga_no_sup(char *fn, char *msg) -{ - if (fn && msg) - printf("%s: No support for %s.\n", fn, msg); - else if (msg) - printf("No support for %s.\n", msg); - else - printf("No FPGA support!\n"); -} - /* fpga_get_desc * map a device number to a descriptor */ @@ -39,8 +25,8 @@ const fpga_desc *fpga_get_desc(int devnum) if ((devnum >= 0) && (devnum < next_desc)) { desc = &desc_table[devnum]; - debug("%s: found fpga descriptor #%d @ 0x%p\n", - __func__, devnum, desc); + log_debug("found fpga descriptor #%d @ 0x%p\n", + devnum, desc); } return desc; @@ -51,15 +37,15 @@ const fpga_desc *fpga_get_desc(int devnum) * generic parameter checking code */ const fpga_desc *fpga_validate(int devnum, const void *buf, - size_t bsize, char *fn) + size_t bsize) { const fpga_desc *desc = fpga_get_desc(devnum); if (!desc) - printf("%s: Invalid device number %d\n", fn, devnum); + log_err("Invalid device number %d\n", devnum); if (!buf) { - printf("%s: Null buffer.\n", fn); + log_err("Null buffer.\n"); return NULL; } return desc; @@ -75,40 +61,40 @@ static int fpga_dev_info(int devnum) const fpga_desc *desc = fpga_get_desc(devnum); if (desc) { - debug("%s: Device Descriptor @ 0x%p\n", - __func__, desc->devdesc); + log_info("Device Descriptor @ 0x%p\n", + desc->devdesc); switch (desc->devtype) { case fpga_xilinx: #if defined(CONFIG_FPGA_XILINX) - printf("Xilinx Device\nDescriptor @ 0x%p\n", desc); + log_info("Xilinx Device\nDescriptor @ 0x%p\n", desc); ret_val = xilinx_info(desc->devdesc); #else - fpga_no_sup((char *)__func__, "Xilinx devices"); + log_err("No support for Xilinx devices.\n"); #endif break; case fpga_altera: #if defined(CONFIG_FPGA_ALTERA) - printf("Altera Device\nDescriptor @ 0x%p\n", desc); + log_info("Altera Device\nDescriptor @ 0x%p\n", desc); ret_val = altera_info(desc->devdesc); #else - fpga_no_sup((char *)__func__, "Altera devices"); + log_err("No support for Altera devices.\n"); #endif break; case fpga_lattice: #if defined(CONFIG_FPGA_LATTICE) - printf("Lattice Device\nDescriptor @ 0x%p\n", desc); + log_info("Lattice Device\nDescriptor @ 0x%p\n", desc); ret_val = lattice_info(desc->devdesc); #else - fpga_no_sup((char *)__func__, "Lattice devices"); + log_err("No support for Lattice devices.\n"); #endif break; default: - printf("%s: Invalid or unsupported device type %d\n", - __func__, desc->devtype); + log_err("Invalid or unsupported device type %d\n", + desc->devtype); } } else { - printf("%s: Invalid device number %d\n", __func__, devnum); + log_err("Invalid device number %d\n", devnum); } return ret_val; @@ -144,23 +130,22 @@ int fpga_add(fpga_type devtype, void *desc) int devnum = FPGA_INVALID_DEVICE; if (!desc) { - printf("%s: NULL device descriptor\n", __func__); + log_err("NULL device descriptor\n"); return devnum; } if (next_desc < 0) { - printf("%s: FPGA support not initialized!\n", __func__); + log_err("FPGA support not initialized!\n"); } else if ((devtype > fpga_min_type) && (devtype < fpga_undefined)) { if (next_desc < CONFIG_MAX_FPGA_DEVICES) { devnum = next_desc; desc_table[next_desc].devtype = devtype; desc_table[next_desc++].devdesc = desc; } else { - printf("%s: Exceeded Max FPGA device count\n", - __func__); + log_err("Exceeded Max FPGA device count\n"); } } else { - printf("%s: Unsupported FPGA type %d\n", __func__, devtype); + log_err("Unsupported FPGA type %d\n", devtype); } return devnum; @@ -181,7 +166,7 @@ int __weak fpga_is_partial_data(int devnum, size_t img_len) int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size, bitstream_type bstype) { - printf("Bitstream support not implemented for this FPGA device\n"); + log_err("Bitstream support not implemented for this FPGA device\n"); return FPGA_FAIL; } @@ -190,8 +175,7 @@ int fpga_fsload(int devnum, const void *buf, size_t size, fpga_fs_info *fpga_fsinfo) { int ret_val = FPGA_FAIL; /* assume failure */ - const fpga_desc *desc = fpga_validate(devnum, buf, size, - (char *)__func__); + const fpga_desc *desc = fpga_validate(devnum, buf, size); if (desc) { switch (desc->devtype) { @@ -200,12 +184,12 @@ int fpga_fsload(int devnum, const void *buf, size_t size, ret_val = xilinx_loadfs(desc->devdesc, buf, size, fpga_fsinfo); #else - fpga_no_sup((char *)__func__, "Xilinx devices"); + log_err("No support for Xilinx devices.\n"); #endif break; default: - printf("%s: Invalid or unsupported device type %d\n", - __func__, desc->devtype); + log_err("Invalid or unsupported device type %d\n", + desc->devtype); } } @@ -219,8 +203,7 @@ int fpga_loads(int devnum, const void *buf, size_t size, { int ret_val = FPGA_FAIL; - const fpga_desc *desc = fpga_validate(devnum, buf, size, - (char *)__func__); + const fpga_desc *desc = fpga_validate(devnum, buf, size); if (desc) { switch (desc->devtype) { @@ -229,12 +212,12 @@ int fpga_loads(int devnum, const void *buf, size_t size, ret_val = xilinx_loads(desc->devdesc, buf, size, fpga_sec_info); #else - fpga_no_sup((char *)__func__, "Xilinx devices"); + log_err("No support for Xilinx devices.\n"); #endif break; default: - printf("%s: Invalid or unsupported device type %d\n", - __func__, desc->devtype); + log_err("Invalid or unsupported device type %d\n", + desc->devtype); } } @@ -265,8 +248,7 @@ int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype, { int ret_val = FPGA_FAIL; /* assume failure */ int ret_notify; - const fpga_desc *desc = fpga_validate(devnum, buf, bsize, - (char *)__func__); + const fpga_desc *desc = fpga_validate(devnum, buf, bsize); if (desc) { switch (desc->devtype) { @@ -275,26 +257,26 @@ int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype, ret_val = xilinx_load(desc->devdesc, buf, bsize, bstype, flags); #else - fpga_no_sup((char *)__func__, "Xilinx devices"); + log_err("No support for Xilinx devices.\n"); #endif break; case fpga_altera: #if defined(CONFIG_FPGA_ALTERA) ret_val = altera_load(desc->devdesc, buf, bsize); #else - fpga_no_sup((char *)__func__, "Altera devices"); + log_err("No support for Altera devices.\n"); #endif break; case fpga_lattice: #if defined(CONFIG_FPGA_LATTICE) ret_val = lattice_load(desc->devdesc, buf, bsize); #else - fpga_no_sup((char *)__func__, "Lattice devices"); + log_err("No support for Lattice devices.\n"); #endif break; default: - printf("%s: Invalid or unsupported device type %d\n", - __func__, desc->devtype); + log_err("Invalid or unsupported device type %d\n", + desc->devtype); } } @@ -312,8 +294,7 @@ int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype, int fpga_dump(int devnum, const void *buf, size_t bsize) { int ret_val = FPGA_FAIL; /* assume failure */ - const fpga_desc *desc = fpga_validate(devnum, buf, bsize, - (char *)__func__); + const fpga_desc *desc = fpga_validate(devnum, buf, bsize); if (desc) { switch (desc->devtype) { @@ -321,26 +302,26 @@ int fpga_dump(int devnum, const void *buf, size_t bsize) #if defined(CONFIG_FPGA_XILINX) ret_val = xilinx_dump(desc->devdesc, buf, bsize); #else - fpga_no_sup((char *)__func__, "Xilinx devices"); + log_err("No support for Xilinx devices.\n"); #endif break; case fpga_altera: #if defined(CONFIG_FPGA_ALTERA) ret_val = altera_dump(desc->devdesc, buf, bsize); #else - fpga_no_sup((char *)__func__, "Altera devices"); + log_err("No support for Altera devices.\n"); #endif break; case fpga_lattice: #if defined(CONFIG_FPGA_LATTICE) ret_val = lattice_dump(desc->devdesc, buf, bsize); #else - fpga_no_sup((char *)__func__, "Lattice devices"); + log_err("No support for Lattice devices.\n"); #endif break; default: - printf("%s: Invalid or unsupported device type %d\n", - __func__, desc->devtype); + log_err("Invalid or unsupported device type %d\n", + desc->devtype); } } @@ -363,7 +344,7 @@ int fpga_info(int devnum) return FPGA_SUCCESS; } else { - printf("%s: No FPGA devices available.\n", __func__); + log_err("No FPGA devices available.\n"); return FPGA_FAIL; } } diff --git a/drivers/fpga/ivm_core.c b/drivers/fpga/ivm_core.c index 3c9a01e5110..37d5c5ec9ec 100644 --- a/drivers/fpga/ivm_core.c +++ b/drivers/fpga/ivm_core.c @@ -33,6 +33,7 @@ #include <linux/string.h> #include <malloc.h> #include <lattice.h> +#include <vsprintf.h> #define vme_out_char(c) printf("%c", c) #define vme_out_hex(c) printf("%x", c) @@ -291,7 +292,7 @@ unsigned short g_usLVDSPairCount; */ static signed char ispVMDataCode(void); -static long int ispVMDataSize(void); +static long ispVMDataSize(void); static void ispVMData(unsigned char *Data); static signed char ispVMShift(signed char Code); static signed char ispVMAmble(signed char Code); @@ -589,7 +590,7 @@ void ispVMFreeMem(void) * */ -long int ispVMDataSize() +long ispVMDataSize(void) { /* 09/11/07 NN added local variables initialization */ long int iSize = 0; @@ -614,7 +615,7 @@ long int ispVMDataSize() * */ -signed char ispVMCode() +signed char ispVMCode(void) { /* 09/11/07 NN added local variables initialization */ unsigned short iRepeatSize = 0; @@ -1113,7 +1114,7 @@ signed char ispVMCode() * */ -signed char ispVMDataCode() +signed char ispVMDataCode(void) { /* 09/11/07 NN added local variables initialization */ signed char cDataByte = 0; @@ -2475,7 +2476,7 @@ void ispVMStateMachine(signed char cNextJTAGState) * */ -void ispVMStart() +void ispVMStart(void) { #ifdef DEBUG printf("// ISPVM EMBEDDED ADDED\n"); @@ -2504,7 +2505,7 @@ void ispVMStart() * */ -void ispVMEnd() +void ispVMEnd(void) { #ifdef DEBUG printf("// ISPVM EMBEDDED ADDED\n"); diff --git a/drivers/fpga/lattice.c b/drivers/fpga/lattice.c index 3f481e38565..29cf2f60974 100644 --- a/drivers/fpga/lattice.c +++ b/drivers/fpga/lattice.c @@ -350,8 +350,8 @@ int lattice_info(Lattice_desc *desc) printf("Unsupported interface type, %d\n", desc->iface); } - printf("Device Size: \t%d bytes\n", - desc->size); + printf("Device Size: \t%zu bytes\n", + desc->size); if (desc->iface_fns) { printf("Device Function Table @ 0x%p\n", diff --git a/drivers/fpga/spartan2.c b/drivers/fpga/spartan2.c index 906649ea181..792e4033428 100644 --- a/drivers/fpga/spartan2.c +++ b/drivers/fpga/spartan2.c @@ -9,6 +9,7 @@ #include <config.h> /* core U-Boot definitions */ #include <log.h> #include <spartan2.h> /* Spartan-II device family */ +#include <time.h> /* Note: The assumption is that we cannot possibly run fast enough to * overrun the device (the Slave Parallel mode can free run at 50MHz). diff --git a/drivers/fpga/stratixII.c b/drivers/fpga/stratixII.c index 73fecd9dca5..3f984385316 100644 --- a/drivers/fpga/stratixII.c +++ b/drivers/fpga/stratixII.c @@ -5,92 +5,41 @@ */ #include <altera.h> +#include <stratixII.h> #include <linux/delay.h> -int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, - int isSerial, int isSecure); -int StratixII_ps_fpp_dump (Altera_desc * desc, void *buf, size_t bsize); - /****************************************************************/ /* Stratix II Generic Implementation */ -int StratixII_load (Altera_desc * desc, void *buf, size_t bsize) -{ - int ret_val = FPGA_FAIL; - - switch (desc->iface) { - case passive_serial: - ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 1, 0); - break; - case fast_passive_parallel: - ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 0, 0); - break; - case fast_passive_parallel_security: - ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 0, 1); - break; - - /* Add new interface types here */ - default: - printf ("%s: Unsupported interface type, %d\n", __FUNCTION__, - desc->iface); - } - return ret_val; -} - -int StratixII_dump (Altera_desc * desc, void *buf, size_t bsize) -{ - int ret_val = FPGA_FAIL; - - switch (desc->iface) { - case passive_serial: - case fast_passive_parallel: - case fast_passive_parallel_security: - ret_val = StratixII_ps_fpp_dump (desc, buf, bsize); - break; - /* Add new interface types here */ - default: - printf ("%s: Unsupported interface type, %d\n", __FUNCTION__, - desc->iface); - } - return ret_val; -} - -int StratixII_info (Altera_desc * desc) -{ - return FPGA_SUCCESS; -} - -int StratixII_ps_fpp_dump (Altera_desc * desc, void *buf, size_t bsize) +int StratixII_ps_fpp_dump(Altera_desc *desc, const void *buf, size_t bsize) { - printf ("Stratix II Fast Passive Parallel dump is not implemented\n"); + printf("Stratix II Fast Passive Parallel dump is not implemented\n"); return FPGA_FAIL; } -int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, - int isSerial, int isSecure) +int StratixII_ps_fpp_load(Altera_desc *desc, const void *buf, size_t bsize, + int isSerial, int isSecure) { altera_board_specific_func *fns; int cookie; int ret_val = FPGA_FAIL; int bytecount; - char *buff = buf; + const char *buff = buf; int i; if (!desc) { - printf ("%s(%d) Altera_desc missing\n", __FUNCTION__, __LINE__); + log_err("Altera_desc missing\n"); return FPGA_FAIL; } if (!buff) { - printf ("%s(%d) buffer is missing\n", __FUNCTION__, __LINE__); + log_err("buffer is missing\n"); return FPGA_FAIL; } if (!bsize) { - printf ("%s(%d) size is zero\n", __FUNCTION__, __LINE__); + log_err("size is zero\n"); return FPGA_FAIL; } if (!desc->iface_fns) { - printf - ("%s(%d) Altera_desc function interface table is missing\n", - __FUNCTION__, __LINE__); + log_err("Altera_desc function interface table is missing\n"); return FPGA_FAIL; } fns = (altera_board_specific_func *) (desc->iface_fns); @@ -99,9 +48,7 @@ int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, if (! (fns->config && fns->status && fns->done && fns->data && fns->abort)) { - printf - ("%s(%d) Missing some function in the function interface table\n", - __FUNCTION__, __LINE__); + log_err("Missing some function in the function interface table\n"); return FPGA_FAIL; } @@ -124,13 +71,12 @@ int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, bytecount = 0; fns->clk (0, 1, cookie); - printf ("loading to fpga "); + printf("loading to fpga "); while (bytecount < bsize) { /* 3.1 check stratix has not signaled us an error */ if (fns->status (cookie) != 1) { - printf - ("\n%s(%d) Stratix failed (byte transferred till failure 0x%x)\n", - __FUNCTION__, __LINE__, bytecount); + log_err("\nStratix failed (byte transferred till failure 0x%x)\n", + bytecount); fns->abort (cookie); return FPGA_FAIL; } @@ -162,7 +108,7 @@ int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, /* 3.5 while clk is deasserted it is safe to print some progress indication */ if ((bytecount % (bsize / 100)) == 0) { - printf ("\b\b\b%02d\%", bytecount * 100 / bsize); + printf("\b\b\b%02zu\%%", bytecount * 100 / bsize); } } @@ -170,11 +116,11 @@ int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, fns->clk (1, 1, cookie); udelay(100); if (!fns->done (cookie)) { - printf (" error!.\n"); + printf(" error!.\n"); fns->abort (cookie); return FPGA_FAIL; } else { - printf ("\b\b\b done.\n"); + printf("\b\b\b done.\n"); } /* 5. call lower layer post configuration */ @@ -187,3 +133,47 @@ int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, return FPGA_SUCCESS; } + +int StratixII_load(Altera_desc *desc, const void *buf, size_t size) +{ + int ret_val = FPGA_FAIL; + + switch (desc->iface) { + case passive_serial: + ret_val = StratixII_ps_fpp_load(desc, buf, size, 1, 0); + break; + case fast_passive_parallel: + ret_val = StratixII_ps_fpp_load(desc, buf, size, 0, 0); + break; + case fast_passive_parallel_security: + ret_val = StratixII_ps_fpp_load(desc, buf, size, 0, 1); + break; + + /* Add new interface types here */ + default: + log_err("Unsupported interface type, %d\n", desc->iface); + } + return ret_val; +} + +int StratixII_dump(Altera_desc *desc, const void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; + + switch (desc->iface) { + case passive_serial: + case fast_passive_parallel: + case fast_passive_parallel_security: + ret_val = StratixII_ps_fpp_dump(desc, buf, bsize); + break; + /* Add new interface types here */ + default: + log_err("Unsupported interface type, %d\n", desc->iface); + } + return ret_val; +} + +int StratixII_info(Altera_desc *desc) +{ + return FPGA_SUCCESS; +} diff --git a/drivers/fpga/stratixv.c b/drivers/fpga/stratixv.c index 372f16d92d1..4b251994598 100644 --- a/drivers/fpga/stratixv.c +++ b/drivers/fpga/stratixv.c @@ -48,7 +48,7 @@ int stratixv_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) int spi_dev; int ret = 0; - if ((u32)rbf_data & 0x3) { + if ((size_t)rbf_data & 0x3) { puts("FPGA: Unaligned data, realign to 32bit boundary.\n"); return -EINVAL; } diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c index d691f135e89..624493ad838 100644 --- a/drivers/fpga/versalpl.c +++ b/drivers/fpga/versalpl.c @@ -6,7 +6,6 @@ #include <cpu_func.h> #include <log.h> -#include <asm/arch/sys_proto.h> #include <memalign.h> #include <versalpl.h> #include <zynqmp_firmware.h> diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c index 8e2c12bb58b..805cbac8082 100644 --- a/drivers/fpga/virtex2.c +++ b/drivers/fpga/virtex2.c @@ -19,6 +19,7 @@ #include <log.h> #include <virtex2.h> #include <linux/delay.h> +#include <time.h> /* * If the SelectMap interface can be overrun by the processor, enable @@ -301,6 +302,7 @@ static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize) size_t bytecount = 0; unsigned char *data = (unsigned char *)buf; int cookie = desc->cookie; + unsigned long ts; ret_val = virtex2_slave_pre(fn, cookie); if (ret_val != FPGA_SUCCESS) diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index c46513226d9..28c68faba55 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -49,7 +49,7 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size, dataptr = (unsigned char *)fpgadata; /* Find out fpga_description */ - desc = fpga_validate(devnum, dataptr, 0, (char *)__func__); + desc = fpga_validate(devnum, dataptr, 0); /* Assign xilinx device description */ xdesc = desc->devdesc; diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c index 2b62bbbe3cf..1199b249e36 100644 --- a/drivers/fpga/zynqmppl.c +++ b/drivers/fpga/zynqmppl.c @@ -191,8 +191,8 @@ static int zynqmp_validate_bitstream(xilinx_desc *desc, const void *buf, } if ((ulong)buf < SZ_1M) { - printf("%s: Bitstream has to be placed up to 1MB (%px)\n", - __func__, buf); + log_err("Bitstream has to be placed above 1MB (%px)\n", + buf); return FPGA_FAIL; } diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index 3e86d854a01..5a37a33b0a7 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -360,8 +360,8 @@ static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf, } if ((u32)buf < SZ_1M) { - printf("%s: Bitstream has to be placed up to 1MB (%x)\n", - __func__, (u32)buf); + log_err("Bitstream has to be placed above 1MB (%x)\n", + (u32)buf); return FPGA_FAIL; } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c7da1f8a52a..58e464106a3 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -719,5 +719,10 @@ config SPL_ADP5585_GPIO depends on SPL_DM_GPIO && SPL_I2C help Support ADP5585 GPIO expander in SPL. +config MPFS_GPIO + bool "Enable Polarfire SoC GPIO driver" + depends on DM_GPIO + help + Enable to support the GPIO driver on Polarfire SoC endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a5ef1c9e0d8..83e10c79b91 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -80,3 +80,4 @@ obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o obj-$(CONFIG_FTGPIO010) += ftgpio010.o obj-$(CONFIG_$(PHASE_)ADP5585_GPIO) += adp5585_gpio.o obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o +obj-$(CONFIG_MPFS_GPIO) += mpfs_gpio.o diff --git a/drivers/gpio/mpfs_gpio.c b/drivers/gpio/mpfs_gpio.c new file mode 100644 index 00000000000..9bbeada4ef5 --- /dev/null +++ b/drivers/gpio/mpfs_gpio.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Microchip Technology Inc. + * Eoin Dickson <eoin.dickson@microchip.com> + */ + +#include <dm.h> +#include <asm-generic/gpio.h> +#include <asm/io.h> +#include <errno.h> +#include <asm/gpio.h> +#include <linux/bitops.h> + +#define MPFS_INP_REG 0x84 +#define COREGPIO_INP_REG 0x90 +#define MPFS_OUTP_REG 0x88 +#define COREGPIO_OUTP_REG 0xA0 +#define MPFS_GPIO_CTRL(i) (0x4 * (i)) +#define MPFS_MAX_NUM_GPIO 32 +#define MPFS_GPIO_EN_OUT_BUF BIT(2) +#define MPFS_GPIO_EN_IN BIT(1) +#define MPFS_GPIO_EN_OUT BIT(0) + +struct mpfs_gpio_reg_offsets { + u8 inp; + u8 outp; +}; + +struct mchp_gpio_plat { + void *base; + const struct mpfs_gpio_reg_offsets *regs; +}; + +static void mchp_update_gpio_reg(void *bptr, u32 offset, bool value) +{ + void __iomem *ptr = (void __iomem *)bptr; + + u32 old = readl(ptr); + + if (value) + writel(old | offset, ptr); + else + writel(old & ~offset, ptr); +} + +static int mchp_gpio_direction_input(struct udevice *dev, u32 offset) +{ + struct mchp_gpio_plat *plat = dev_get_plat(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + if (offset > uc_priv->gpio_count) + return -EINVAL; + + mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_IN, true); + mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_OUT, false); + mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_OUT_BUF, false); + + return 0; +} + +static int mchp_gpio_direction_output(struct udevice *dev, u32 offset, int value) +{ + struct mchp_gpio_plat *plat = dev_get_plat(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + if (offset > uc_priv->gpio_count) + return -EINVAL; + + mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_IN, false); + mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_OUT, true); + mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_OUT_BUF, true); + + mchp_update_gpio_reg(plat->base + plat->regs->outp, BIT(offset), value); + + return 0; +} + +static bool mchp_gpio_get_value(struct udevice *dev, u32 offset) +{ + struct mchp_gpio_plat *plat = dev_get_plat(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + int val, input; + + if (offset > uc_priv->gpio_count) + return -EINVAL; + + input = readl(plat->base + MPFS_GPIO_CTRL(offset)) & MPFS_GPIO_EN_IN; + + if (input) + val = (readl(plat->base + plat->regs->inp) & BIT(offset)); + else + val = (readl(plat->base + plat->regs->outp) & BIT(offset)); + + return val >> offset; +} + +static int mchp_gpio_set_value(struct udevice *dev, u32 offset, int value) +{ + struct mchp_gpio_plat *plat = dev_get_plat(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + if (offset > uc_priv->gpio_count) + return -EINVAL; + + mchp_update_gpio_reg(plat->base + plat->regs->outp, BIT(offset), value); + + return 0; +} + +static int mchp_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + struct mchp_gpio_plat *plat = dev_get_plat(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + u32 outdir, indir, val; + + if (offset > uc_priv->gpio_count) + return -EINVAL; + + /* Get direction of the pin */ + outdir = readl(plat->base + MPFS_GPIO_CTRL(offset)) & MPFS_GPIO_EN_OUT; + indir = readl(plat->base + MPFS_GPIO_CTRL(offset)) & MPFS_GPIO_EN_IN; + + if (outdir) + val = GPIOF_OUTPUT; + else if (indir) + val = GPIOF_INPUT; + else + val = GPIOF_UNUSED; + + return val; +} + +static int mchp_gpio_probe(struct udevice *dev) +{ + struct mchp_gpio_plat *plat = dev_get_plat(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + char name[18], *str; + + plat->regs = dev_get_driver_data(dev); + sprintf(name, "gpio@%4lx_", (uintptr_t)plat->base); + str = strdup(name); + if (!str) + return -ENOMEM; + uc_priv->bank_name = str; + uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", MPFS_MAX_NUM_GPIO); + + return 0; +} + +static const struct mpfs_gpio_reg_offsets mpfs_reg_offsets = { + .inp = MPFS_INP_REG, + .outp = MPFS_OUTP_REG, +}; + +static const struct mpfs_gpio_reg_offsets coregpio_reg_offsets = { + .inp = COREGPIO_INP_REG, + .outp = COREGPIO_OUTP_REG, +}; + +static const struct udevice_id mchp_gpio_match[] = { + { + .compatible = "microchip,mpfs-gpio", + .data = &mpfs_reg_offsets, + }, { + .compatible = "microchip,coregpio-rtl-v3", + .data = &coregpio_reg_offsets, + }, + { /* end of list */ } +}; + +static const struct dm_gpio_ops mchp_gpio_ops = { + .direction_input = mchp_gpio_direction_input, + .direction_output = mchp_gpio_direction_output, + .get_value = mchp_gpio_get_value, + .set_value = mchp_gpio_set_value, + .get_function = mchp_gpio_get_function, +}; + +static int mchp_gpio_of_to_plat(struct udevice *dev) +{ + struct mchp_gpio_plat *plat = dev_get_plat(dev); + + plat->base = dev_read_addr_ptr(dev); + if (!plat->base) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(gpio_mpfs) = { + .name = "gpio_mpfs", + .id = UCLASS_GPIO, + .of_match = mchp_gpio_match, + .of_to_plat = of_match_ptr(mchp_gpio_of_to_plat), + .plat_auto = sizeof(struct mchp_gpio_plat), + .ops = &mchp_gpio_ops, + .probe = mchp_gpio_probe, +}; diff --git a/drivers/gpio/zynq_gpio.c b/drivers/gpio/zynq_gpio.c index 7db58c70663..ef4f33f84e9 100644 --- a/drivers/gpio/zynq_gpio.c +++ b/drivers/gpio/zynq_gpio.c @@ -184,6 +184,7 @@ static const struct zynq_platform_data zynq_gpio_def = { * pin * @bank_pin_num: an output parameter used to return pin number within a bank * for the given gpio pin + * @dev: Pointer to our device structure. * * Returns the bank number and pin offset within the bank. */ diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 775b2b4e9af..108b24b3dd2 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -181,6 +181,7 @@ config SYS_I2C_IPROC config SYS_I2C_FSL bool "Freescale I2C bus driver" + depends on M68K || PPC help Add support for Freescale I2C busses as used on MPC8240, MPC8245, and MPC85xx processors. @@ -240,7 +241,7 @@ config SYS_I2C_DW config SYS_I2C_DW_PCI bool "Designware PCI I2C Controller" - depends on SYS_I2C_DW && PCI && ACPIGEN + depends on SYS_I2C_DW && PCI && ACPIGEN && X86 default y help Say yes here to select the Designware PCI I2C Host Controller. @@ -277,6 +278,7 @@ config SYS_I2C_INTEL config SYS_I2C_IMX_LPI2C bool "NXP i.MX LPI2C driver" + depends on MACH_IMX help Add support for the NXP i.MX LPI2C driver. @@ -314,6 +316,7 @@ config SYS_I2C_MICROCHIP config SYS_I2C_MXC bool "NXP MXC I2C driver" + depends on ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 || MACH_IMX help Add support for the NXP I2C driver. This supports up to four bus channels and operating on standard mode up to 100 kbits/s and fast @@ -485,7 +488,7 @@ endif config SYS_I2C_NEXELL bool "Nexell I2C driver" - depends on DM_I2C + depends on DM_I2C && ARCH_NEXELL help Add support for the Nexell I2C driver. This is used with various Nexell parts such as S5Pxx18 series SoCs. All chips @@ -494,6 +497,7 @@ config SYS_I2C_NEXELL config SYS_I2C_NPCM bool "Nuvoton NPCM I2C driver" + depends on ARCH_NPCM help Support for Nuvoton I2C controller driver. @@ -533,7 +537,7 @@ config SYS_I2C_RCAR_IIC config SYS_I2C_ROCKCHIP bool "Rockchip I2C driver" - depends on DM_I2C + depends on DM_I2C && ARCH_ROCKCHIP help Add support for the Rockchip I2C driver. This is used with various Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips @@ -751,6 +755,7 @@ config SYS_I2C_MV config SYS_I2C_MVTWSI bool "Marvell I2C driver" + depends on ARCH_KIRKWOOD || ARCH_MVEBU || ARCH_SUNXI help Support for Marvell I2C controllers as used on the orion5x and kirkwood SoC families. diff --git a/drivers/i2c/iproc_i2c.c b/drivers/i2c/iproc_i2c.c index 6570f64fe77..8f94dfe117e 100644 --- a/drivers/i2c/iproc_i2c.c +++ b/drivers/i2c/iproc_i2c.c @@ -8,6 +8,7 @@ #include <asm/io.h> #include <config.h> #include <dm.h> +#include <linux/delay.h> #include <linux/printk.h> #include "errno.h" #include <i2c.h> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index cd5579aa55a..65319bb6fd8 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -25,6 +25,13 @@ config I2C_ARB_GPIO_CHALLENGE response mechanism where masters have to claim the bus by asserting a GPIO. +config I2C_MUX_PCA9541 + tristate "NXP PCA9541 I2C Master Selector" + depends on I2C_MUX + help + If you say yes here you get support for the NXP PCA9541 + I2C Master Selector. + config I2C_MUX_PCA954x tristate "TI PCA954x I2C Mux/switches" depends on I2C_MUX diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index b690821199f..844d4520e43 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -3,5 +3,6 @@ # Copyright (c) 2015 Google, Inc obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_I2C_MUX) += i2c-mux-uclass.o +obj-$(CONFIG_I2C_MUX_PCA9541) += pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o diff --git a/drivers/i2c/muxes/pca9541.c b/drivers/i2c/muxes/pca9541.c new file mode 100644 index 00000000000..021088acaee --- /dev/null +++ b/drivers/i2c/muxes/pca9541.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it> + * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it> + * Copyright (c) 2010 Ericsson AB. + * Copyright (c) 2025 Advanced Micro Devices, Inc. + */ + +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <log.h> +#include <malloc.h> +#include <linux/delay.h> + +/* + * The PCA9541 is a bus master selector. It supports two I2C masters connected + * to a single slave bus. + * + * Before each bus transaction, a master has to acquire bus ownership. After the + * transaction is complete, bus ownership has to be released. This fits well + * into the I2C multiplexer framework, which provides select and release + * functions for this purpose. For this reason, this driver is modeled as + * single-channel I2C bus multiplexer. + * + * This driver assumes that the two bus masters are controlled by two different + * hosts. If a single host controls both masters, platform code has to ensure + * that only one of the masters is instantiated at any given time. + */ + +#define PCA9541_CONTROL 0x01 +#define PCA9541_ISTAT 0x02 + +#define PCA9541_CTL_MYBUS BIT(0) +#define PCA9541_CTL_NMYBUS BIT(1) +#define PCA9541_CTL_BUSON BIT(2) +#define PCA9541_CTL_NBUSON BIT(3) +#define PCA9541_CTL_BUSINIT BIT(4) +#define PCA9541_CTL_TESTON BIT(6) +#define PCA9541_CTL_NTESTON BIT(7) + +#define PCA9541_ISTAT_INTIN BIT(0) +#define PCA9541_ISTAT_BUSINIT BIT(1) +#define PCA9541_ISTAT_BUSOK BIT(2) +#define PCA9541_ISTAT_BUSLOST BIT(3) +#define PCA9541_ISTAT_MYTEST BIT(6) +#define PCA9541_ISTAT_NMYTEST BIT(7) + +#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON) +#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS) + +/* arbitration timeouts, in jiffies */ +#define ARB_TIMEOUT_US 125000 /* 125 ms until forcing bus ownership */ +#define ARB2_TIMEOUT_US 250000 /* 250 ms until acquisition failure */ + +/* arbitration retry delays, in us */ +#define SELECT_DELAY_SHORT 50 +#define SELECT_DELAY_LONG 1000 + +struct pca9541_plat { + u32 addr; +}; + +struct pca9541_priv { + u32 addr; + unsigned long select_timeout; + long arb_timeout; +}; + +static inline int mybus(int x) +{ + return !(x & MYBUS) || ((x & MYBUS) == MYBUS); +} + +static inline int busoff(int x) +{ + return !(x & BUSON) || ((x & BUSON) == BUSON); +} + +static int pca9541_reg_write(struct udevice *mux, struct pca9541_priv *client, + u8 command, u8 val) +{ + return dm_i2c_write(mux, command, &val, 1); +} + +static int pca9541_reg_read(struct udevice *mux, struct pca9541_priv *client, + u8 command) +{ + int ret; + uchar byte; + + ret = dm_i2c_read(mux, command, &byte, 1); + + return ret ?: byte; +} + +/* + * Arbitration management functions + */ + +/* Release bus. Also reset NTESTON and BUSINIT if it was set. */ +static void pca9541_release_bus(struct udevice *mux, struct pca9541_priv *client) +{ + int reg; + + reg = pca9541_reg_read(mux, client, PCA9541_CONTROL); + if (reg >= 0 && !busoff(reg) && mybus(reg)) + pca9541_reg_write(mux, client, PCA9541_CONTROL, + (reg & PCA9541_CTL_NBUSON) >> 1); +} + +/* + * Arbitration is defined as a two-step process. A bus master can only activate + * the slave bus if it owns it; otherwise it has to request ownership first. + * This multi-step process ensures that access contention is resolved + * gracefully. + * + * Bus Ownership Other master Action + * state requested access + * ---------------------------------------------------- + * off - yes wait for arbitration timeout or + * for other master to drop request + * off no no take ownership + * off yes no turn on bus + * on yes - done + * on no - wait for arbitration timeout or + * for other master to release bus + * + * The main contention point occurs if the slave bus is off and both masters + * request ownership at the same time. In this case, one master will turn on + * the slave bus, believing that it owns it. The other master will request + * bus ownership. Result is that the bus is turned on, and master which did + * _not_ own the slave bus before ends up owning it. + */ + +/* Control commands per PCA9541 datasheet */ +static const u8 pca9541_control[16] = { + 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1 +}; + +/* + * Channel arbitration + * + * Return values: + * <0: error + * 0 : bus not acquired + * 1 : bus acquired + */ +static int pca9541_arbitrate(struct udevice *mux, struct pca9541_priv *client) +{ + int reg, ret = 0; + + reg = pca9541_reg_read(mux, client, PCA9541_CONTROL); + if (reg < 0) + return reg; + + if (busoff(reg)) { + int istat; + + /* + * Bus is off. Request ownership or turn it on unless + * other master requested ownership. + */ + istat = pca9541_reg_read(mux, client, PCA9541_ISTAT); + if (!(istat & PCA9541_ISTAT_NMYTEST) || + client->arb_timeout <= 0) { + /* + * Other master did not request ownership, + * or arbitration timeout expired. Take the bus. + */ + pca9541_reg_write(mux, client, PCA9541_CONTROL, + pca9541_control[reg & 0x0f] + | PCA9541_CTL_NTESTON); + client->select_timeout = SELECT_DELAY_SHORT; + } else { + /* + * Other master requested ownership. + * Set extra long timeout to give it time to acquire it. + */ + client->select_timeout = SELECT_DELAY_LONG * 2; + } + } else if (mybus(reg)) { + /* + * Bus is on, and we own it. We are done with acquisition. + * Reset NTESTON and BUSINIT, then return success. + */ + if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT)) + pca9541_reg_write(mux, client, PCA9541_CONTROL, + reg & ~(PCA9541_CTL_NTESTON + | PCA9541_CTL_BUSINIT)); + ret = 1; + } else { + /* + * Other master owns the bus. + * If arbitration timeout has expired, force ownership. + * Otherwise request it. + */ + client->select_timeout = SELECT_DELAY_LONG; + if (client->arb_timeout <= 0) { + /* Time is up, take the bus and reset it. */ + pca9541_reg_write(mux, client, PCA9541_CONTROL, + pca9541_control[reg & 0x0f] + | PCA9541_CTL_BUSINIT + | PCA9541_CTL_NTESTON); + } else { + /* Request bus ownership if needed */ + if (!(reg & PCA9541_CTL_NTESTON)) + pca9541_reg_write(mux, client, PCA9541_CONTROL, + reg | PCA9541_CTL_NTESTON); + } + } + + return ret; +} + +static int pca9541_select_chan(struct udevice *mux, struct udevice *bus, + uint channel) +{ + struct pca9541_priv *priv = dev_get_priv(mux); + int ret; + long timeout = ARB2_TIMEOUT_US; /* Give up after this time */ + + /* Force bus ownership after this time */ + priv->arb_timeout = ARB_TIMEOUT_US; + do { + ret = pca9541_arbitrate(mux, priv); + if (ret) + return ret < 0 ? ret : 0; + + udelay(priv->select_timeout); + timeout -= priv->select_timeout; + priv->arb_timeout -= priv->select_timeout; + } while (timeout > 0); + + debug("I2C Arbitration select timeout\n"); + + return -ETIMEDOUT; +} + +static int pca9541_release_chan(struct udevice *mux, struct udevice *bus, + uint channel) +{ + struct pca9541_priv *priv = dev_get_priv(mux); + + pca9541_release_bus(mux, priv); + + return 0; +} + +/* + * I2C init/probing/exit functions + */ +static int pca9541_of_to_plat(struct udevice *dev) +{ + struct pca9541_plat *plat = dev_get_plat(dev); + + plat->addr = dev_read_u32_default(dev, "reg", 0); + if (!plat->addr) { + debug("Reg property is not found\n"); + return -ENODEV; + } + + debug("Device %s at 0x%x\n", dev->name, plat->addr); + + return 0; +} + +static int pca9541_probe(struct udevice *dev) +{ + struct pca9541_plat *plat = dev_get_plat(dev); + struct pca9541_priv *priv = dev_get_priv(dev); + + priv->addr = plat->addr; + + return 0; +} + +static const struct i2c_mux_ops pca9541_ops = { + .select = pca9541_select_chan, + .deselect = pca9541_release_chan, +}; + +static const struct udevice_id pca9541_ids[] = { + { .compatible = "nxp,pca9541", }, + { } +}; + +U_BOOT_DRIVER(pca9541) = { + .name = "pca9541", + .id = UCLASS_I2C_MUX, + .of_match = pca9541_ids, + .probe = pca9541_probe, + .ops = &pca9541_ops, + .of_to_plat = pca9541_of_to_plat, + .plat_auto = sizeof(struct pca9541_plat), + .priv_auto = sizeof(struct pca9541_priv), +}; diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c index 9dd26972703..d13947a0d9c 100644 --- a/drivers/i2c/muxes/pca954x.c +++ b/drivers/i2c/muxes/pca954x.c @@ -22,6 +22,7 @@ enum pca_type { MAX7369, PCA9543, PCA9544, + PCA9545, PCA9546, PCA9547, PCA9548, @@ -79,6 +80,10 @@ static const struct chip_desc chips[] = { .muxtype = pca954x_ismux, .width = 4, }, + [PCA9545] = { + .muxtype = pca954x_isswi, + .width = 4, + }, [PCA9546] = { .muxtype = pca954x_isswi, .width = 4, @@ -141,6 +146,7 @@ static const struct udevice_id pca954x_ids[] = { { .compatible = "maxim,max7369", .data = MAX7369 }, { .compatible = "nxp,pca9543", .data = PCA9543 }, { .compatible = "nxp,pca9544", .data = PCA9544 }, + { .compatible = "nxp,pca9545", .data = PCA9545 }, { .compatible = "nxp,pca9546", .data = PCA9546 }, { .compatible = "nxp,pca9547", .data = PCA9547 }, { .compatible = "nxp,pca9548", .data = PCA9548 }, diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index c09f0ae795e..47ce0ea690f 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -98,6 +98,7 @@ config I8042_KEYB config TEGRA_KEYBOARD bool "NVIDIA Tegra internal matrix keyboard controller support" + depends on ARCH_TEGRA help A matrix keyboard connected directly to the internal keyboard controller on Tegra SoCs. diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index cbc45ed7b97..0f753b9dbb9 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -290,40 +290,10 @@ config CROS_EC_SPI provides a faster and more robust interface than I2C but the bugs are less interesting. -config DS4510 - bool "Enable support for DS4510 CPU supervisor" - help - Enable support for the Maxim DS4510 CPU supervisor. It has an - integrated 64-byte EEPROM, four programmable non-volatile I/O pins - and a configurable timer for the supervisor function. The device is - connected over I2C. - config FSL_IIM bool "Enable FSL IC Identification Module (IIM) driver" depends on ARCH_MX5 -config FSL_SEC_MON - bool "Enable FSL SEC_MON Driver" - help - Freescale Security Monitor block is responsible for monitoring - system states. - Security Monitor can be transitioned on any security failures, - like software violations or hardware security violations. - -choice - prompt "Security monitor interaction endianess" - depends on FSL_SEC_MON - default SYS_FSL_SEC_MON_BE if PPC - default SYS_FSL_SEC_MON_LE - -config SYS_FSL_SEC_MON_LE - bool "Security monitor interactions are little endian" - -config SYS_FSL_SEC_MON_BE - bool "Security monitor interactions are big endian" - -endchoice - config IRQ bool "Interrupt controller" help @@ -458,19 +428,6 @@ config SPL_PWRSEQ device. When the device is started up, its power sequence can be initiated. -config PCA9551_LED - bool "Enable PCA9551 LED driver" - help - Enable driver for PCA9551 LED controller. This controller - is connected via I2C. So I2C needs to be enabled. - -config PCA9551_I2C_ADDR - hex "I2C address of PCA9551 LED controller" - depends on PCA9551_LED - default 0x60 - help - The I2C address of the PCA9551 LED controller. - config STM32MP_FUSE bool "Enable STM32MP fuse wrapper providing the fuse API" depends on ARCH_STM32MP && MISC @@ -672,7 +629,7 @@ config GDSYS_SOC config IHS_FPGA bool "Enable IHS FPGA driver" - depends on MISC + depends on MISC && (GDSYS_LEGACY_DRIVERS || SYS_FPGA_FLAVOR_GAZERBEAM) help Support IHS (Integrated Hardware Systems) FPGA, the main FPGAs on gdsys devices, which supply the majority of the functionality offered diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 279dbcbdd30..f7422c8e95a 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -32,7 +32,6 @@ endif obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o -obj-$(CONFIG_DS4510) += ds4510.o obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o obj-$(CONFIG_FSL_IIM) += fsl_iim.o @@ -59,7 +58,6 @@ obj-$(CONFIG_NPCM_OTP) += npcm_otp.o obj-$(CONFIG_NPCM_HOST) += npcm_host_intf.o obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o obj-$(CONFIG_P2SB) += p2sb-uclass.o -obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(PHASE_)PWRSEQ) += pwrseq-uclass.o ifdef CONFIG_QFW obj-y += qfw.o diff --git a/drivers/misc/ds4510.c b/drivers/misc/ds4510.c deleted file mode 100644 index 302015e2793..00000000000 --- a/drivers/misc/ds4510.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright 2008 Extreme Engineering Solutions, Inc. - */ - -/* - * Driver for DS4510, a CPU supervisor with integrated EEPROM, SRAM, - * and 4 programmable non-volatile GPIO pins. - */ - -#include <i2c.h> -#include <command.h> -#include <linux/delay.h> -#include "ds4510.h" - -enum { - DS4510_CMD_INFO, - DS4510_CMD_DEVICE, - DS4510_CMD_NV, - DS4510_CMD_RSTDELAY, - DS4510_CMD_OUTPUT, - DS4510_CMD_INPUT, - DS4510_CMD_PULLUP, - DS4510_CMD_EEPROM, - DS4510_CMD_SEEPROM, - DS4510_CMD_SRAM, -}; - -/* - * Write to DS4510, taking page boundaries into account - */ -static int ds4510_mem_write(uint8_t chip, int offset, uint8_t *buf, int count) -{ - int wrlen; - int i = 0; - - do { - wrlen = DS4510_EEPROM_PAGE_SIZE - - DS4510_EEPROM_PAGE_OFFSET(offset); - if (count < wrlen) - wrlen = count; - if (i2c_write(chip, offset, 1, &buf[i], wrlen)) - return -1; - - /* - * This delay isn't needed for SRAM writes but shouldn't delay - * things too much, so do it unconditionally for simplicity - */ - udelay(DS4510_EEPROM_PAGE_WRITE_DELAY_MS * 1000); - count -= wrlen; - offset += wrlen; - i += wrlen; - } while (count > 0); - - return 0; -} - -/* - * General read from DS4510 - */ -static int ds4510_mem_read(uint8_t chip, int offset, uint8_t *buf, int count) -{ - return i2c_read(chip, offset, 1, buf, count); -} - -/* - * Write SEE bit in config register. - * nv = 0 - Writes to SEEPROM registers behave like EEPROM - * nv = 1 - Writes to SEEPROM registers behave like SRAM - */ -static int ds4510_see_write(uint8_t chip, uint8_t nv) -{ - uint8_t data; - - if (i2c_read(chip, DS4510_CFG, 1, &data, 1)) - return -1; - - if (nv) /* Treat SEEPROM bits as EEPROM */ - data &= ~DS4510_CFG_SEE; - else /* Treat SEEPROM bits as SRAM */ - data |= DS4510_CFG_SEE; - - return ds4510_mem_write(chip, DS4510_CFG, &data, 1); -} - -/* - * Write de-assertion of reset signal delay - */ -static int ds4510_rstdelay_write(uint8_t chip, uint8_t delay) -{ - uint8_t data; - - if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1)) - return -1; - - data &= ~DS4510_RSTDELAY_MASK; - data |= delay & DS4510_RSTDELAY_MASK; - - return ds4510_mem_write(chip, DS4510_RSTDELAY, &data, 1); -} - -/* - * Write pullup characteristics of IO pins - */ -static int ds4510_pullup_write(uint8_t chip, uint8_t val) -{ - val &= DS4510_IO_MASK; - - return ds4510_mem_write(chip, DS4510_PULLUP, (uint8_t *)&val, 1); -} - -/* - * Read pullup characteristics of IO pins - */ -static int ds4510_pullup_read(uint8_t chip) -{ - uint8_t val; - - if (i2c_read(chip, DS4510_PULLUP, 1, &val, 1)) - return -1; - - return val & DS4510_IO_MASK; -} - -/* - * Write drive level of IO pins - */ -static int ds4510_gpio_write(uint8_t chip, uint8_t val) -{ - uint8_t data; - int i; - - for (i = 0; i < DS4510_NUM_IO; i++) { - if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1)) - return -1; - - if (val & (0x1 << i)) - data |= 0x1; - else - data &= ~0x1; - - if (ds4510_mem_write(chip, DS4510_IO0 - i, &data, 1)) - return -1; - } - - return 0; -} - -/* - * Read drive level of IO pins - */ -static int ds4510_gpio_read(uint8_t chip) -{ - uint8_t data; - int val = 0; - int i; - - for (i = 0; i < DS4510_NUM_IO; i++) { - if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1)) - return -1; - - if (data & 1) - val |= (1 << i); - } - - return val; -} - -/* - * Read physical level of IO pins - */ -static int ds4510_gpio_read_val(uint8_t chip) -{ - uint8_t val; - - if (i2c_read(chip, DS4510_IO_STATUS, 1, &val, 1)) - return -1; - - return val & DS4510_IO_MASK; -} - -/* - * Display DS4510 information - */ -static int ds4510_info(uint8_t chip) -{ - int i; - int tmp; - uint8_t data; - - printf("DS4510 @ 0x%x:\n\n", chip); - - if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1)) - return -1; - printf("rstdelay = 0x%x\n\n", data & DS4510_RSTDELAY_MASK); - - if (i2c_read(chip, DS4510_CFG, 1, &data, 1)) - return -1; - printf("config = 0x%x\n", data); - printf(" /ready = %d\n", data & DS4510_CFG_READY ? 1 : 0); - printf(" trip pt = %d\n", data & DS4510_CFG_TRIP_POINT ? 1 : 0); - printf(" rst sts = %d\n", data & DS4510_CFG_RESET ? 1 : 0); - printf(" /see = %d\n", data & DS4510_CFG_SEE ? 1 : 0); - printf(" swrst = %d\n\n", data & DS4510_CFG_SWRST ? 1 : 0); - - printf("gpio pins: 3210\n"); - printf("---------------\n"); - printf("pullup "); - - tmp = ds4510_pullup_read(chip); - if (tmp == -1) - return tmp; - for (i = DS4510_NUM_IO - 1; i >= 0; i--) - printf("%d", (tmp & (1 << i)) ? 1 : 0); - printf("\n"); - - printf("driven "); - tmp = ds4510_gpio_read(chip); - if (tmp == -1) - return -1; - for (i = DS4510_NUM_IO - 1; i >= 0; i--) - printf("%d", (tmp & (1 << i)) ? 1 : 0); - printf("\n"); - - printf("read "); - tmp = ds4510_gpio_read_val(chip); - if (tmp == -1) - return -1; - for (i = DS4510_NUM_IO - 1; i >= 0; i--) - printf("%d", (tmp & (1 << i)) ? 1 : 0); - printf("\n"); - - return 0; -} - -struct cmd_tbl cmd_ds4510[] = { - U_BOOT_CMD_MKENT(device, 3, 0, (void *)DS4510_CMD_DEVICE, "", ""), - U_BOOT_CMD_MKENT(nv, 3, 0, (void *)DS4510_CMD_NV, "", ""), - U_BOOT_CMD_MKENT(output, 4, 0, (void *)DS4510_CMD_OUTPUT, "", ""), - U_BOOT_CMD_MKENT(input, 3, 0, (void *)DS4510_CMD_INPUT, "", ""), - U_BOOT_CMD_MKENT(pullup, 4, 0, (void *)DS4510_CMD_PULLUP, "", ""), - U_BOOT_CMD_MKENT(info, 2, 0, (void *)DS4510_CMD_INFO, "", ""), - U_BOOT_CMD_MKENT(rstdelay, 3, 0, (void *)DS4510_CMD_RSTDELAY, "", ""), - U_BOOT_CMD_MKENT(eeprom, 6, 0, (void *)DS4510_CMD_EEPROM, "", ""), - U_BOOT_CMD_MKENT(seeprom, 6, 0, (void *)DS4510_CMD_SEEPROM, "", ""), - U_BOOT_CMD_MKENT(sram, 6, 0, (void *)DS4510_CMD_SRAM, "", ""), -}; - -int do_ds4510(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{ - static uint8_t chip = 0x51; - struct cmd_tbl *c; - ulong ul_arg2 = 0; - ulong ul_arg3 = 0; - int tmp; - ulong addr; - ulong off; - ulong cnt; - int end; - int (*rw_func)(uint8_t, int, uint8_t *, int); - - c = find_cmd_tbl(argv[1], cmd_ds4510, ARRAY_SIZE(cmd_ds4510)); - - /* All commands but "device" require 'maxargs' arguments */ - if (!c || !((argc == (c->maxargs)) || - (((int)c->cmd == DS4510_CMD_DEVICE) && - (argc == (c->maxargs - 1))))) { - return cmd_usage(cmdtp); - } - - /* arg2 used as chip addr and pin number */ - if (argc > 2) - ul_arg2 = hextoul(argv[2], NULL); - - /* arg3 used as output/pullup value */ - if (argc > 3) - ul_arg3 = hextoul(argv[3], NULL); - - switch ((int)c->cmd) { - case DS4510_CMD_DEVICE: - if (argc == 3) - chip = ul_arg2; - printf("Current device address: 0x%x\n", chip); - return 0; - case DS4510_CMD_NV: - return ds4510_see_write(chip, ul_arg2); - case DS4510_CMD_OUTPUT: - tmp = ds4510_gpio_read(chip); - if (tmp == -1) - return -1; - if (ul_arg3) - tmp |= (1 << ul_arg2); - else - tmp &= ~(1 << ul_arg2); - return ds4510_gpio_write(chip, tmp); - case DS4510_CMD_INPUT: - tmp = ds4510_gpio_read_val(chip); - if (tmp == -1) - return -1; - return (tmp & (1 << ul_arg2)) != 0; - case DS4510_CMD_PULLUP: - tmp = ds4510_pullup_read(chip); - if (tmp == -1) - return -1; - if (ul_arg3) - tmp |= (1 << ul_arg2); - else - tmp &= ~(1 << ul_arg2); - return ds4510_pullup_write(chip, tmp); - case DS4510_CMD_INFO: - return ds4510_info(chip); - case DS4510_CMD_RSTDELAY: - return ds4510_rstdelay_write(chip, ul_arg2); - case DS4510_CMD_EEPROM: - end = DS4510_EEPROM + DS4510_EEPROM_SIZE; - off = DS4510_EEPROM; - break; - case DS4510_CMD_SEEPROM: - end = DS4510_SEEPROM + DS4510_SEEPROM_SIZE; - off = DS4510_SEEPROM; - break; - case DS4510_CMD_SRAM: - end = DS4510_SRAM + DS4510_SRAM_SIZE; - off = DS4510_SRAM; - break; - default: - /* We should never get here... */ - return 1; - } - - /* Only eeprom, seeprom, and sram commands should make it here */ - if (strcmp(argv[2], "read") == 0) - rw_func = ds4510_mem_read; - else if (strcmp(argv[2], "write") == 0) - rw_func = ds4510_mem_write; - else - return cmd_usage(cmdtp); - - addr = hextoul(argv[3], NULL); - off += hextoul(argv[4], NULL); - cnt = hextoul(argv[5], NULL); - - if ((off + cnt) > end) { - printf("ERROR: invalid len\n"); - return -1; - } - - return rw_func(chip, off, (uint8_t *)addr, cnt); -} - -U_BOOT_CMD( - ds4510, 6, 1, do_ds4510, - "ds4510 eeprom/seeprom/sram/gpio access", - "device [dev]\n" - " - show or set current device address\n" - "ds4510 info\n" - " - display ds4510 info\n" - "ds4510 output pin 0|1\n" - " - set pin low or high-Z\n" - "ds4510 input pin\n" - " - read value of pin\n" - "ds4510 pullup pin 0|1\n" - " - disable/enable pullup on specified pin\n" - "ds4510 nv 0|1\n" - " - make gpio and seeprom writes volatile/non-volatile" - "\n" - "ds4510 rstdelay 0-3\n" - " - set reset output delay" - "\n" - "ds4510 eeprom read addr off cnt\n" - "ds4510 eeprom write addr off cnt\n" - " - read/write 'cnt' bytes at EEPROM offset 'off'\n" - "ds4510 seeprom read addr off cnt\n" - "ds4510 seeprom write addr off cnt\n" - " - read/write 'cnt' bytes at SRAM-shadowed EEPROM offset 'off'\n" - "ds4510 sram read addr off cnt\n" - "ds4510 sram write addr off cnt\n" - " - read/write 'cnt' bytes at SRAM offset 'off'" -); diff --git a/drivers/misc/ds4510.h b/drivers/misc/ds4510.h deleted file mode 100644 index 5c7a1a8c737..00000000000 --- a/drivers/misc/ds4510.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright 2008 Extreme Engineering Solutions, Inc. - */ - -#ifndef __DS4510_H_ -#define __DS4510_H_ - -/* General defines */ -#define DS4510_NUM_IO 0x04 -#define DS4510_IO_MASK ((1 << DS4510_NUM_IO) - 1) -#define DS4510_EEPROM_PAGE_WRITE_DELAY_MS 20 - -/* EEPROM from 0x00 - 0x39 */ -#define DS4510_EEPROM 0x00 -#define DS4510_EEPROM_SIZE 0x40 -#define DS4510_EEPROM_PAGE_SIZE 0x08 -#define DS4510_EEPROM_PAGE_OFFSET(x) ((x) & (DS4510_EEPROM_PAGE_SIZE - 1)) - -/* SEEPROM from 0xf0 - 0xf7 */ -#define DS4510_SEEPROM 0xf0 -#define DS4510_SEEPROM_SIZE 0x08 - -/* Registers overlapping SEEPROM from 0xf0 - 0xf7 */ -#define DS4510_PULLUP 0xF0 -#define DS4510_PULLUP_DIS 0x00 -#define DS4510_PULLUP_EN 0x01 -#define DS4510_RSTDELAY 0xF1 -#define DS4510_RSTDELAY_MASK 0x03 -#define DS4510_RSTDELAY_125 0x00 -#define DS4510_RSTDELAY_250 0x01 -#define DS4510_RSTDELAY_500 0x02 -#define DS4510_RSTDELAY_1000 0x03 -#define DS4510_IO3 0xF4 -#define DS4510_IO2 0xF5 -#define DS4510_IO1 0xF6 -#define DS4510_IO0 0xF7 - -/* Status configuration registers from 0xf8 - 0xf9*/ -#define DS4510_IO_STATUS 0xF8 -#define DS4510_CFG 0xF9 -#define DS4510_CFG_READY 0x80 -#define DS4510_CFG_TRIP_POINT 0x40 -#define DS4510_CFG_RESET 0x20 -#define DS4510_CFG_SEE 0x10 -#define DS4510_CFG_SWRST 0x08 - -/* SRAM from 0xfa - 0xff */ -#define DS4510_SRAM 0xfa -#define DS4510_SRAM_SIZE 0x06 - -#endif /* __DS4510_H_ */ diff --git a/drivers/misc/pca9551_led.c b/drivers/misc/pca9551_led.c deleted file mode 100644 index 040d0d5cf48..00000000000 --- a/drivers/misc/pca9551_led.c +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2015 Stefan Roese <sr@denx.de> - */ - -#include <errno.h> -#include <i2c.h> -#include <status_led.h> - -#ifndef CONFIG_PCA9551_I2C_ADDR -#error "CONFIG_PCA9551_I2C_ADDR not defined!" -#endif - -#define PCA9551_REG_INPUT 0x00 /* Input register (read only) */ -#define PCA9551_REG_PSC0 0x01 /* Frequency prescaler 0 */ -#define PCA9551_REG_PWM0 0x02 /* PWM0 */ -#define PCA9551_REG_PSC1 0x03 /* Frequency prescaler 1 */ -#define PCA9551_REG_PWM1 0x04 /* PWM1 */ -#define PCA9551_REG_LS0 0x05 /* LED0 to LED3 selector */ -#define PCA9551_REG_LS1 0x06 /* LED4 to LED7 selector */ - -#define PCA9551_CTRL_AI (1 << 4) /* Auto-increment flag */ - -#define PCA9551_LED_STATE_ON 0x00 -#define PCA9551_LED_STATE_OFF 0x01 -#define PCA9551_LED_STATE_BLINK0 0x02 -#define PCA9551_LED_STATE_BLINK1 0x03 - -struct pca9551_blink_rate { - u8 psc; /* Frequency preescaler, see PCA9551_7.pdf p. 6 */ - u8 pwm; /* Pulse width modulation, see PCA9551_7.pdf p. 6 */ -}; - -static int freq_last = -1; -static int mask_last = -1; -static int idx_last = -1; -static int mode_last; - -static int pca9551_led_get_state(int led, int *state) -{ - unsigned int reg; - u8 shift, buf; - int ret; - - if (led < 0 || led > 7) { - return -EINVAL; - } else if (led < 4) { - reg = PCA9551_REG_LS0; - shift = led << 1; - } else { - reg = PCA9551_REG_LS1; - shift = (led - 4) << 1; - } - - ret = i2c_read(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); - if (ret) - return ret; - - *state = (buf >> shift) & 0x03; - return 0; -} - -static int pca9551_led_set_state(int led, int state) -{ - unsigned int reg; - u8 shift, buf, mask; - int ret; - - if (led < 0 || led > 7) { - return -EINVAL; - } else if (led < 4) { - reg = PCA9551_REG_LS0; - shift = led << 1; - } else { - reg = PCA9551_REG_LS1; - shift = (led - 4) << 1; - } - mask = 0x03 << shift; - - ret = i2c_read(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); - if (ret) - return ret; - - buf = (buf & ~mask) | ((state & 0x03) << shift); - - ret = i2c_write(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); - if (ret) - return ret; - - return 0; -} - -static int pca9551_led_set_blink_rate(int idx, struct pca9551_blink_rate rate) -{ - unsigned int reg; - int ret; - - switch (idx) { - case 0: - reg = PCA9551_REG_PSC0; - break; - case 1: - reg = PCA9551_REG_PSC1; - break; - default: - return -EINVAL; - } - reg |= PCA9551_CTRL_AI; - - ret = i2c_write(CONFIG_PCA9551_I2C_ADDR, reg, 1, (u8 *)&rate, 2); - if (ret) - return ret; - - return 0; -} - -/* - * Functions referenced by cmd_led.c or status_led.c - */ -void __led_init(led_id_t id, int state) -{ -} - -void __led_set(led_id_t mask, int state) -{ - if (state == CONFIG_LED_STATUS_OFF) - pca9551_led_set_state(mask, PCA9551_LED_STATE_OFF); - else - pca9551_led_set_state(mask, PCA9551_LED_STATE_ON); -} - -void __led_toggle(led_id_t mask) -{ - int state = 0; - - pca9551_led_get_state(mask, &state); - pca9551_led_set_state(mask, !state); -} - -void __led_blink(led_id_t mask, int freq) -{ - struct pca9551_blink_rate rate; - int mode; - int idx; - - if ((freq == freq_last) || (mask == mask_last)) { - idx = idx_last; - mode = mode_last; - } else { - /* Toggle blink index */ - if (idx_last == 0) { - idx = 1; - mode = PCA9551_LED_STATE_BLINK1; - } else { - idx = 0; - mode = PCA9551_LED_STATE_BLINK0; - } - - idx_last = idx; - mode_last = mode; - } - freq_last = freq; - mask_last = mask; - - rate.psc = ((freq * 38) / 1000) - 1; - rate.pwm = 128; /* 50% duty cycle */ - - pca9551_led_set_blink_rate(idx, rate); - pca9551_led_set_state(mask, mode); -} diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 1c9b6898bff..4c46df0ffb8 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -284,7 +284,7 @@ config MMC_DW_K3 config MMC_DW_ROCKCHIP bool "Rockchip SD/MMC controller support" - depends on OF_CONTROL + depends on OF_CONTROL && ARCH_ROCKCHIP depends on MMC_DW help This enables support for the Rockchip SD/MMM controller, which is @@ -333,15 +333,6 @@ config MMC_MESON_GX help Support for EMMC host controller on Meson GX ARM SoCs platform (S905) -config MMC_MXC - bool "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" - help - This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x - Multimedia Card Interface. If you have an i.MX or MPC512x platform - with a Multimedia Card slot, say Y here. - - If unsure, say N. - config MMC_OWL bool "Actions OWL Multimedia Card Interface support" depends on ARCH_OWL @@ -391,6 +382,7 @@ config MVEBU_MMC config MMC_OMAP_HS bool "TI OMAP High Speed Multimedia Card Interface support" + depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS select DM_REGULATOR_PBIAS if DM_REGULATOR help This selects the TI OMAP High Speed Multimedia card Interface. @@ -597,7 +589,7 @@ config MMC_SDHCI_BCM2835 config MMC_SDHCI_BCMSTB tristate "SDHCI support for the BCMSTB SD/MMC Controller" - depends on MMC_SDHCI + depends on MMC_SDHCI && (ARCH_BCMSTB || ARCH_BCM283X) help This selects the Broadcom set-top box SD/MMC controller. @@ -660,19 +652,9 @@ config MMC_SDHCI_F_SDH30 If you have a controller with this interface, say Y here. If unsure, say N. -config MMC_SDHCI_KONA - bool "SDHCI support on Broadcom KONA platform" - depends on MMC_SDHCI - help - This selects the Broadcom Kona Secure Digital Host Controller - Interface(SDHCI) support. - This is used in Broadcom mobile SoCs. - - If you have a controller with this interface, say Y here. - config MMC_SDHCI_MSM bool "Qualcomm SDHCI controller" - depends on MMC_SDHCI + depends on MMC_SDHCI && ARCH_SNAPDRAGON help Enables support for SDHCI 2.0 controller present on some Qualcomm Snapdragon devices. This device is compatible with eMMC v4.5 and @@ -718,7 +700,7 @@ config MMC_SDHCI_ROCKCHIP config MMC_SDHCI_S5P bool "SDHCI support on Samsung S5P SoC" - depends on MMC_SDHCI + depends on MMC_SDHCI && S5P help This selects the Secure Digital Host Controller Interface (SDHCI) on Samsung S5P SoCs. @@ -740,7 +722,7 @@ config MMC_SDHCI_SNPS config MMC_SDHCI_STI bool "SDHCI support for STMicroelectronics SoC" - depends on MMC_SDHCI && OF_CONTROL + depends on MMC_SDHCI && OF_CONTROL && ARCH_STI help This selects the Secure Digital Host Controller Interface (SDHCI) on STMicroelectronics STiH410 SoC. @@ -794,6 +776,7 @@ config TEGRA124_MMC_DISABLE_EXT_LOOPBACK config MMC_SDHCI_ZYNQ bool "Arasan SDHCI controller support" depends on OF_CONTROL + depends on ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2 || ARCH_ZYNQ || ARCH_ZYNQMP depends on MMC_SDHCI help Support for Arasan SDHCI host controller on Zynq/ZynqMP ARM SoCs platform @@ -852,7 +835,7 @@ config GENERIC_ATMEL_MCI config STM32_SDMMC2 bool "STMicroelectronics STM32H7 SD/MMC Host Controller support" - depends on OF_CONTROL + depends on OF_CONTROL && (ARCH_STM32 || ARCH_STM32MP) help This selects support for the SD/MMC controller on STM32H7 SoCs. If you have a board based on such a SoC and with a SD/MMC slot, @@ -886,6 +869,7 @@ config FSL_SDHC_V2_3 config FSL_ESDHC bool "Freescale/NXP eSDHC controller support" + depends on ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 || PPC select FSL_SDHC_V2_3 if ARCH_P1010 || ARCH_BSC9131 || ARCH_BSC9132 \ || ARCH_C29X help @@ -938,6 +922,7 @@ config ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE config FSL_ESDHC_IMX bool "Freescale/NXP i.MX eSDHC controller support" + depends on MACH_IMX help This selects support for the i.MX eSDHC (Enhanced Secure Digital Host Controller) found on numerous Freescale/NXP SoCs. diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 360706f53d2..a23336d7d8d 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_MMC_MESON_GX) += meson_gx_mmc.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MVEBU_MMC) += mvebu_mmc.o obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o -obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxsmmc.o obj-$(CONFIG_MMC_OCTEONTX) += octeontx_hsmmc.o obj-$(CONFIG_MMC_OWL) += owl_mmc.o @@ -64,7 +63,6 @@ obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence6.o obj-$(CONFIG_MMC_SDHCI_CV1800B) += cv1800b_sdhci.o obj-$(CONFIG_MMC_SDHCI_AM654) += am654_sdhci.o obj-$(CONFIG_MMC_SDHCI_IPROC) += iproc_sdhci.o -obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o obj-$(CONFIG_MMC_SDHCI_NPCM) += npcm_sdhci.o diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index c8bf89d6d35..12e37cb4b78 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -373,6 +373,12 @@ static const struct udevice_id exynos_dwmmc_ids[] = { .compatible = "samsung,exynos4412-dw-mshc", .data = (ulong)&exynos4_drv_data, }, { + .compatible = "samsung,exynos5420-dw-mshc-smu", + .data = (ulong)&exynos5_drv_data, + }, { + .compatible = "samsung,exynos5420-dw-mshc", + .data = (ulong)&exynos5_drv_data, + }, { .compatible = "samsung,exynos-dwmmc", .data = (ulong)&exynos5_drv_data, }, { diff --git a/drivers/mmc/kona_sdhci.c b/drivers/mmc/kona_sdhci.c deleted file mode 100644 index 83f14122632..00000000000 --- a/drivers/mmc/kona_sdhci.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2013 Broadcom Corporation. - */ - -#include <malloc.h> -#include <sdhci.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <asm/kona-common/clk.h> - -#define SDHCI_CORECTRL_OFFSET 0x00008000 -#define SDHCI_CORECTRL_EN 0x01 -#define SDHCI_CORECTRL_RESET 0x02 - -#define SDHCI_CORESTAT_OFFSET 0x00008004 -#define SDHCI_CORESTAT_CD_SW 0x01 - -#define SDHCI_COREIMR_OFFSET 0x00008008 -#define SDHCI_COREIMR_IP 0x01 - -static int init_kona_mmc_core(struct sdhci_host *host) -{ - unsigned int mask; - unsigned int timeout; - - if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) { - printf("%s: sd host controller reset error\n", __func__); - return -EBUSY; - } - - /* For kona a hardware reset before anything else. */ - mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET; - sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET); - - /* Wait max 100 ms */ - timeout = 1000; - do { - if (timeout == 0) { - printf("%s: reset timeout error\n", __func__); - return -ETIMEDOUT; - } - timeout--; - udelay(100); - } while (0 == - (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) & - SDHCI_CORECTRL_RESET)); - - /* Clear the reset bit. */ - mask = mask & ~SDHCI_CORECTRL_RESET; - sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET); - - /* Enable AHB clock */ - mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET); - sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET); - - /* Enable interrupts */ - sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET); - - /* Make sure Card is detected in controller */ - mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET); - sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET); - - /* Wait max 100 ms */ - timeout = 1000; - while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - if (timeout == 0) { - printf("%s: CARD DETECT timeout error\n", __func__); - return -ETIMEDOUT; - } - timeout--; - udelay(100); - } - return 0; -} - -int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks) -{ - int ret = 0; - u32 max_clk; - void *reg_base; - struct sdhci_host *host = NULL; - - host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); - if (!host) { - printf("%s: sdhci host malloc fail!\n", __func__); - return -ENOMEM; - } - switch (dev_index) { - case 0: - reg_base = (void *)CONFIG_SYS_SDIO_BASE0; - ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO0_MAX_CLK, - &max_clk); - break; - case 1: - reg_base = (void *)CONFIG_SYS_SDIO_BASE1; - ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO1_MAX_CLK, - &max_clk); - break; - case 2: - reg_base = (void *)CONFIG_SYS_SDIO_BASE2; - ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO2_MAX_CLK, - &max_clk); - break; - case 3: - reg_base = (void *)CONFIG_SYS_SDIO_BASE3; - ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO3_MAX_CLK, - &max_clk); - break; - default: - printf("%s: sdio dev index %d not supported\n", - __func__, dev_index); - ret = -EINVAL; - } - if (ret) { - free(host); - return ret; - } - - host->name = "kona-sdhci"; - host->ioaddr = reg_base; - host->quirks = quirks; - host->max_clk = max_clk; - - if (init_kona_mmc_core(host)) { - free(host); - return -EINVAL; - } - - add_sdhci(host, 0, min_clk); - return ret; -} diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2c1f4f9c336..5f2efbe6df9 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2365,8 +2365,10 @@ static int mmc_startup_v4(struct mmc *mmc) return -ENOMEM; memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN); #endif - if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions)) - return -EINVAL; + if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions)) { + err = -EINVAL; + goto error; + } mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]]; diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 90fcf2679bb..928c05872ca 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -155,6 +155,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, struct mmc_cmd cmd; struct mmc_data data; int timeout_ms = 1000; + int err; if ((start + blkcnt) > mmc_get_blk_desc(mmc)->lba) { printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", @@ -181,9 +182,13 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, data.blocksize = mmc->write_bl_len; data.flags = MMC_DATA_WRITE; - if (mmc_send_cmd(mmc, &cmd, &data)) { + err = mmc_send_cmd(mmc, &cmd, &data); + if (err) { printf("mmc write failed\n"); - return 0; + /* + * Don't return 0 here since the emmc will still be in data + * transfer mode continue to send the STOP_TRANSMISSION command + */ } /* SPI multiblock writes terminate using a special @@ -203,6 +208,9 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, if (mmc_poll_for_busy(mmc, timeout_ms)) return 0; + if (err) + return 0; + return blkcnt; } diff --git a/drivers/mmc/mxcmmc.c b/drivers/mmc/mxcmmc.c deleted file mode 100644 index 1acea6f820b..00000000000 --- a/drivers/mmc/mxcmmc.c +++ /dev/null @@ -1,523 +0,0 @@ -/* - * This is a driver for the SDHC controller found in Freescale MX2/MX3 - * SoCs. It is basically the same hardware as found on MX1 (imxmmc.c). - * Unlike the hardware found on MX1, this hardware just works and does - * not need all the quirks found in imxmmc.c, hence the seperate driver. - * - * Copyright (C) 2009 Ilya Yanok, <yanok@emcraft.com> - * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> - * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> - * - * derived from pxamci.c by Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <config.h> -#include <command.h> -#include <mmc.h> -#include <part.h> -#include <malloc.h> -#include <mmc.h> -#include <time.h> -#include <linux/errno.h> -#include <asm/io.h> -#include <asm/arch/clock.h> - -#define DRIVER_NAME "mxc-mmc" - -struct mxcmci_regs { - u32 str_stp_clk; - u32 status; - u32 clk_rate; - u32 cmd_dat_cont; - u32 res_to; - u32 read_to; - u32 blk_len; - u32 nob; - u32 rev_no; - u32 int_cntr; - u32 cmd; - u32 arg; - u32 pad; - u32 res_fifo; - u32 buffer_access; -}; - -#define STR_STP_CLK_RESET (1 << 3) -#define STR_STP_CLK_START_CLK (1 << 1) -#define STR_STP_CLK_STOP_CLK (1 << 0) - -#define STATUS_CARD_INSERTION (1 << 31) -#define STATUS_CARD_REMOVAL (1 << 30) -#define STATUS_YBUF_EMPTY (1 << 29) -#define STATUS_XBUF_EMPTY (1 << 28) -#define STATUS_YBUF_FULL (1 << 27) -#define STATUS_XBUF_FULL (1 << 26) -#define STATUS_BUF_UND_RUN (1 << 25) -#define STATUS_BUF_OVFL (1 << 24) -#define STATUS_SDIO_INT_ACTIVE (1 << 14) -#define STATUS_END_CMD_RESP (1 << 13) -#define STATUS_WRITE_OP_DONE (1 << 12) -#define STATUS_DATA_TRANS_DONE (1 << 11) -#define STATUS_READ_OP_DONE (1 << 11) -#define STATUS_WR_CRC_ERROR_CODE_MASK (3 << 10) -#define STATUS_CARD_BUS_CLK_RUN (1 << 8) -#define STATUS_BUF_READ_RDY (1 << 7) -#define STATUS_BUF_WRITE_RDY (1 << 6) -#define STATUS_RESP_CRC_ERR (1 << 5) -#define STATUS_CRC_READ_ERR (1 << 3) -#define STATUS_CRC_WRITE_ERR (1 << 2) -#define STATUS_TIME_OUT_RESP (1 << 1) -#define STATUS_TIME_OUT_READ (1 << 0) -#define STATUS_ERR_MASK 0x2f - -#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1 << 12) -#define CMD_DAT_CONT_STOP_READWAIT (1 << 11) -#define CMD_DAT_CONT_START_READWAIT (1 << 10) -#define CMD_DAT_CONT_BUS_WIDTH_4 (2 << 8) -#define CMD_DAT_CONT_INIT (1 << 7) -#define CMD_DAT_CONT_WRITE (1 << 4) -#define CMD_DAT_CONT_DATA_ENABLE (1 << 3) -#define CMD_DAT_CONT_RESPONSE_48BIT_CRC (1 << 0) -#define CMD_DAT_CONT_RESPONSE_136BIT (2 << 0) -#define CMD_DAT_CONT_RESPONSE_48BIT (3 << 0) - -#define INT_SDIO_INT_WKP_EN (1 << 18) -#define INT_CARD_INSERTION_WKP_EN (1 << 17) -#define INT_CARD_REMOVAL_WKP_EN (1 << 16) -#define INT_CARD_INSERTION_EN (1 << 15) -#define INT_CARD_REMOVAL_EN (1 << 14) -#define INT_SDIO_IRQ_EN (1 << 13) -#define INT_DAT0_EN (1 << 12) -#define INT_BUF_READ_EN (1 << 4) -#define INT_BUF_WRITE_EN (1 << 3) -#define INT_END_CMD_RES_EN (1 << 2) -#define INT_WRITE_OP_DONE_EN (1 << 1) -#define INT_READ_OP_EN (1 << 0) - -struct mxcmci_host { - struct mmc *mmc; - struct mxcmci_regs *base; - int irq; - int detect_irq; - int dma; - int do_dma; - unsigned int power_mode; - - struct mmc_cmd *cmd; - struct mmc_data *data; - - unsigned int dma_nents; - unsigned int datasize; - unsigned int dma_dir; - - u16 rev_no; - unsigned int cmdat; - - int clock; -}; - -static struct mxcmci_host mxcmci_host; - -/* maintainer note: do we really want to have a global host pointer? */ -static struct mxcmci_host *host = &mxcmci_host; - -static inline int mxcmci_use_dma(struct mxcmci_host *host) -{ - return host->do_dma; -} - -static void mxcmci_softreset(struct mxcmci_host *host) -{ - int i; - - /* reset sequence */ - writel(STR_STP_CLK_RESET, &host->base->str_stp_clk); - writel(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, - &host->base->str_stp_clk); - - for (i = 0; i < 8; i++) - writel(STR_STP_CLK_START_CLK, &host->base->str_stp_clk); - - writel(0xff, &host->base->res_to); -} - -static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) -{ - unsigned int nob = data->blocks; - unsigned int blksz = data->blocksize; - unsigned int datasize = nob * blksz; - - host->data = data; - - writel(nob, &host->base->nob); - writel(blksz, &host->base->blk_len); - host->datasize = datasize; -} - -static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_cmd *cmd, - unsigned int cmdat) -{ - if (host->cmd != NULL) - printf("mxcmci: error!\n"); - host->cmd = cmd; - - switch (cmd->resp_type) { - case MMC_RSP_R1: /* short CRC, OPCODE */ - case MMC_RSP_R1b:/* short CRC, OPCODE, BUSY */ - cmdat |= CMD_DAT_CONT_RESPONSE_48BIT_CRC; - break; - case MMC_RSP_R2: /* long 136 bit + CRC */ - cmdat |= CMD_DAT_CONT_RESPONSE_136BIT; - break; - case MMC_RSP_R3: /* short */ - cmdat |= CMD_DAT_CONT_RESPONSE_48BIT; - break; - case MMC_RSP_NONE: - break; - default: - printf("mxcmci: unhandled response type 0x%x\n", - cmd->resp_type); - return -EINVAL; - } - - writel(cmd->cmdidx, &host->base->cmd); - writel(cmd->cmdarg, &host->base->arg); - writel(cmdat, &host->base->cmd_dat_cont); - - return 0; -} - -static void mxcmci_finish_request(struct mxcmci_host *host, - struct mmc_cmd *cmd, struct mmc_data *data) -{ - host->cmd = NULL; - host->data = NULL; -} - -static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) -{ - int data_error = 0; - - if (stat & STATUS_ERR_MASK) { - printf("request failed. status: 0x%08x\n", - stat); - if (stat & STATUS_CRC_READ_ERR) { - data_error = -EILSEQ; - } else if (stat & STATUS_CRC_WRITE_ERR) { - u32 err_code = (stat >> 9) & 0x3; - if (err_code == 2) /* No CRC response */ - data_error = -ETIMEDOUT; - else - data_error = -EILSEQ; - } else if (stat & STATUS_TIME_OUT_READ) { - data_error = -ETIMEDOUT; - } else { - data_error = -EIO; - } - } - - host->data = NULL; - - return data_error; -} - -static int mxcmci_read_response(struct mxcmci_host *host, unsigned int stat) -{ - struct mmc_cmd *cmd = host->cmd; - int i; - u32 a, b, c; - u32 *resp = (u32 *)cmd->response; - - if (!cmd) - return 0; - - if (stat & STATUS_TIME_OUT_RESP) { - printf("CMD TIMEOUT\n"); - return -ETIMEDOUT; - } else if (stat & STATUS_RESP_CRC_ERR && cmd->resp_type & MMC_RSP_CRC) { - printf("cmd crc error\n"); - return -EILSEQ; - } - - if (cmd->resp_type & MMC_RSP_PRESENT) { - if (cmd->resp_type & MMC_RSP_136) { - for (i = 0; i < 4; i++) { - a = readl(&host->base->res_fifo) & 0xFFFF; - b = readl(&host->base->res_fifo) & 0xFFFF; - resp[i] = a << 16 | b; - } - } else { - a = readl(&host->base->res_fifo) & 0xFFFF; - b = readl(&host->base->res_fifo) & 0xFFFF; - c = readl(&host->base->res_fifo) & 0xFFFF; - resp[0] = a << 24 | b << 8 | c >> 8; - } - } - return 0; -} - -static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask) -{ - u32 stat; - unsigned long timeout = get_ticks() + CONFIG_SYS_HZ; - - do { - stat = readl(&host->base->status); - if (stat & STATUS_ERR_MASK) - return stat; - if (timeout < get_ticks()) - return STATUS_TIME_OUT_READ; - if (stat & mask) - return 0; - } while (1); -} - -static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) -{ - unsigned int stat; - u32 *buf = _buf; - - while (bytes > 3) { - stat = mxcmci_poll_status(host, - STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); - if (stat) - return stat; - *buf++ = readl(&host->base->buffer_access); - bytes -= 4; - } - - if (bytes) { - u8 *b = (u8 *)buf; - u32 tmp; - - stat = mxcmci_poll_status(host, - STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); - if (stat) - return stat; - tmp = readl(&host->base->buffer_access); - memcpy(b, &tmp, bytes); - } - - return 0; -} - -static int mxcmci_push(struct mxcmci_host *host, const void *_buf, int bytes) -{ - unsigned int stat; - const u32 *buf = _buf; - - while (bytes > 3) { - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - writel(*buf++, &host->base->buffer_access); - bytes -= 4; - } - - if (bytes) { - const u8 *b = (u8 *)buf; - u32 tmp; - - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - - memcpy(&tmp, b, bytes); - writel(tmp, &host->base->buffer_access); - } - - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - - return 0; -} - -static int mxcmci_transfer_data(struct mxcmci_host *host) -{ - struct mmc_data *data = host->data; - int stat; - unsigned long length; - - length = data->blocks * data->blocksize; - host->datasize = 0; - - if (data->flags & MMC_DATA_READ) { - stat = mxcmci_pull(host, data->dest, length); - if (stat) - return stat; - host->datasize += length; - } else { - stat = mxcmci_push(host, (const void *)(data->src), length); - if (stat) - return stat; - host->datasize += length; - stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE); - if (stat) - return stat; - } - return 0; -} - -static int mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) -{ - int datastat; - int ret; - - ret = mxcmci_read_response(host, stat); - - if (ret) { - mxcmci_finish_request(host, host->cmd, host->data); - return ret; - } - - if (!host->data) { - mxcmci_finish_request(host, host->cmd, host->data); - return 0; - } - - datastat = mxcmci_transfer_data(host); - ret = mxcmci_finish_data(host, datastat); - mxcmci_finish_request(host, host->cmd, host->data); - return ret; -} - -static int mxcmci_request(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ - struct mxcmci_host *host = mmc->priv; - unsigned int cmdat = host->cmdat; - u32 stat; - int ret; - - host->cmdat &= ~CMD_DAT_CONT_INIT; - if (data) { - mxcmci_setup_data(host, data); - - cmdat |= CMD_DAT_CONT_DATA_ENABLE; - - if (data->flags & MMC_DATA_WRITE) - cmdat |= CMD_DAT_CONT_WRITE; - } - - if ((ret = mxcmci_start_cmd(host, cmd, cmdat))) { - mxcmci_finish_request(host, cmd, data); - return ret; - } - - do { - stat = readl(&host->base->status); - writel(stat, &host->base->status); - } while (!(stat & STATUS_END_CMD_RESP)); - - return mxcmci_cmd_done(host, stat); -} - -static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) -{ - unsigned int divider; - int prescaler = 0; - unsigned long clk_in = mxc_get_clock(MXC_ESDHC_CLK); - - while (prescaler <= 0x800) { - for (divider = 1; divider <= 0xF; divider++) { - int x; - - x = (clk_in / (divider + 1)); - - if (prescaler) - x /= (prescaler * 2); - - if (x <= clk_ios) - break; - } - if (divider < 0x10) - break; - - if (prescaler == 0) - prescaler = 1; - else - prescaler <<= 1; - } - - writel((prescaler << 4) | divider, &host->base->clk_rate); -} - -static int mxcmci_set_ios(struct mmc *mmc) -{ - struct mxcmci_host *host = mmc->priv; - if (mmc->bus_width == 4) - host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; - else - host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; - - if (mmc->clock) { - mxcmci_set_clk_rate(host, mmc->clock); - writel(STR_STP_CLK_START_CLK, &host->base->str_stp_clk); - } else { - writel(STR_STP_CLK_STOP_CLK, &host->base->str_stp_clk); - } - - host->clock = mmc->clock; - - return 0; -} - -static int mxcmci_init(struct mmc *mmc) -{ - struct mxcmci_host *host = mmc->priv; - - mxcmci_softreset(host); - - host->rev_no = readl(&host->base->rev_no); - if (host->rev_no != 0x400) { - printf("wrong rev.no. 0x%08x. aborting.\n", - host->rev_no); - return -ENODEV; - } - - /* recommended in data sheet */ - writel(0x2db4, &host->base->read_to); - - writel(0, &host->base->int_cntr); - - return 0; -} - -static const struct mmc_ops mxcmci_ops = { - .send_cmd = mxcmci_request, - .set_ios = mxcmci_set_ios, - .init = mxcmci_init, -}; - -static struct mmc_config mxcmci_cfg = { - .name = "MXC MCI", - .ops = &mxcmci_ops, - .host_caps = MMC_MODE_4BIT, - .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, - .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, -}; - -static int mxcmci_initialize(struct bd_info *bis) -{ - host->base = (struct mxcmci_regs *)CONFIG_MXC_MCI_REGS_BASE; - - mxcmci_cfg.f_min = mxc_get_clock(MXC_ESDHC_CLK) >> 7; - mxcmci_cfg.f_max = mxc_get_clock(MXC_ESDHC_CLK) >> 1; - - host->mmc = mmc_create(&mxcmci_cfg, host); - if (host->mmc == NULL) - return -1; - - return 0; -} - -int mxc_mmc_init(struct bd_info *bis) -{ - return mxcmci_initialize(bis); -} diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index 278019f02ab..c80033d8752 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -141,14 +141,6 @@ static int do_sdhci_init(struct sdhci_host *host) } } - if (dm_gpio_is_valid(&host->cd_gpio)) { - ret = dm_gpio_get_value(&host->cd_gpio); - if (ret) { - debug("no SD card detected (%d)\n", ret); - return -ENODEV; - } - } - return s5p_sdhci_core_init(host); } @@ -183,8 +175,6 @@ static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) gpio_request_by_name_nodev(offset_to_ofnode(node), "pwr-gpios", 0, &host->pwr_gpio, GPIOD_IS_OUT); - gpio_request_by_name_nodev(offset_to_ofnode(node), "cd-gpios", 0, - &host->cd_gpio, GPIOD_IS_IN); return 0; } @@ -236,6 +226,7 @@ static int s5p_sdhci_bind(struct udevice *dev) static const struct udevice_id s5p_sdhci_ids[] = { { .compatible = "samsung,exynos4412-sdhci"}, + { .compatible = "samsung,exynos4210-sdhci"}, { } }; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 950ed0f25a9..d942fa4e202 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -411,6 +411,14 @@ config ETH_DESIGNWARE_S700 This provides glue layer to use Synopsys Designware Ethernet MAC present on Actions S700 SoC. +config ETH_DESIGNWARE_THEAD + bool "T-Head glue driver for Synopsys Designware Ethernet MAC" + depends on ETH_DESIGNWARE + select DW_ALTDESCRIPTOR + help + This provides glue layer to use Synopsys Designware Ethernet MAC + present on T-Head SoCs. + config DW_ALTDESCRIPTOR bool "Designware Ethernet MAC uses alternate (enhanced) descriptors" depends on ETH_DESIGNWARE diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 67bba3a8536..79cc8b422b0 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_ETH_DESIGNWARE) += designware.o obj-$(CONFIG_ETH_DESIGNWARE_MESON8B) += dwmac_meson8b.o obj-$(CONFIG_ETH_DESIGNWARE_S700) += dwmac_s700.o obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o +obj-$(CONFIG_ETH_DESIGNWARE_THEAD) += dwmac_thead.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-bus.o obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o diff --git a/drivers/net/dwmac_thead.c b/drivers/net/dwmac_thead.c new file mode 100644 index 00000000000..138d71a6202 --- /dev/null +++ b/drivers/net/dwmac_thead.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * T-HEAD DWMAC platform driver + * + * Copyright (C) 2021 Alibaba Group Holding Limited. + * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org> + * Copyright (C) 2025 Yao Zi <ziyao@disroot.org> + * + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <linux/bitfield.h> +#include <phy.h> + +#include "designware.h" + +#define GMAC_CLK_EN 0x00 +#define GMAC_TX_CLK_EN BIT(1) +#define GMAC_TX_CLK_N_EN BIT(2) +#define GMAC_TX_CLK_OUT_EN BIT(3) +#define GMAC_RX_CLK_EN BIT(4) +#define GMAC_RX_CLK_N_EN BIT(5) +#define GMAC_EPHY_REF_CLK_EN BIT(6) +#define GMAC_RXCLK_DELAY_CTRL 0x04 +#define GMAC_RXCLK_BYPASS BIT(15) +#define GMAC_RXCLK_INVERT BIT(14) +#define GMAC_RXCLK_DELAY GENMASK(4, 0) +#define GMAC_TXCLK_DELAY_CTRL 0x08 +#define GMAC_TXCLK_BYPASS BIT(15) +#define GMAC_TXCLK_INVERT BIT(14) +#define GMAC_TXCLK_DELAY GENMASK(4, 0) +#define GMAC_PLLCLK_DIV 0x0c +#define GMAC_PLLCLK_DIV_EN BIT(31) +#define GMAC_PLLCLK_DIV_NUM GENMASK(7, 0) +#define GMAC_GTXCLK_SEL 0x18 +#define GMAC_GTXCLK_SEL_PLL BIT(0) +#define GMAC_INTF_CTRL 0x1c +#define PHY_INTF_MASK BIT(0) +#define PHY_INTF_RGMII FIELD_PREP(PHY_INTF_MASK, 1) +#define PHY_INTF_MII_GMII FIELD_PREP(PHY_INTF_MASK, 0) +#define GMAC_TXCLK_OEN 0x20 +#define TXCLK_DIR_MASK BIT(0) +#define TXCLK_DIR_OUTPUT FIELD_PREP(TXCLK_DIR_MASK, 0) +#define TXCLK_DIR_INPUT FIELD_PREP(TXCLK_DIR_MASK, 1) + +#define GMAC_RGMII_CLK_RATE 125000000 + +struct dwmac_thead_plat { + struct dw_eth_pdata dw_eth_pdata; + void __iomem *apb_base; +}; + +static int dwmac_thead_set_phy_if(struct dwmac_thead_plat *plat) +{ + u32 phyif; + + switch (plat->dw_eth_pdata.eth_pdata.phy_interface) { + case PHY_INTERFACE_MODE_MII: + phyif = PHY_INTF_MII_GMII; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + phyif = PHY_INTF_RGMII; + break; + default: + return -EINVAL; + } + + writel(phyif, plat->apb_base + GMAC_INTF_CTRL); + return 0; +} + +static int dwmac_thead_set_txclk_dir(struct dwmac_thead_plat *plat) +{ + u32 txclk_dir; + + switch (plat->dw_eth_pdata.eth_pdata.phy_interface) { + case PHY_INTERFACE_MODE_MII: + txclk_dir = TXCLK_DIR_INPUT; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + txclk_dir = TXCLK_DIR_OUTPUT; + break; + default: + return -EINVAL; + } + + writel(txclk_dir, plat->apb_base + GMAC_TXCLK_OEN); + return 0; +} + +static unsigned long dwmac_thead_rgmii_tx_rate(int speed) +{ + switch (speed) { + case 10: + return 2500000; + case 100: + return 25000000; + case 1000: + return 125000000; + } + + return -EINVAL; +} + +static int dwmac_thead_set_clk_tx_rate(struct dwmac_thead_plat *plat, + struct dw_eth_dev *edev, + unsigned long tx_rate) +{ + unsigned long rate; + u32 div, reg; + + rate = clk_get_rate(&edev->clocks[0]); + + writel(0, plat->apb_base + GMAC_PLLCLK_DIV); + + div = rate / tx_rate; + if (rate != tx_rate * div) { + pr_err("invalid gmac rate %lu\n", rate); + return -EINVAL; + } + + reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) | + FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div); + writel(reg, plat->apb_base + GMAC_PLLCLK_DIV); + + return 0; +} + +static int dwmac_thead_enable_clk(struct dwmac_thead_plat *plat) +{ + u32 reg; + + switch (plat->dw_eth_pdata.eth_pdata.phy_interface) { + case PHY_INTERFACE_MODE_MII: + reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + /* use pll */ + writel(GMAC_GTXCLK_SEL_PLL, plat->apb_base + GMAC_GTXCLK_SEL); + reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN | + GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN; + break; + + default: + return -EINVAL; + } + + writel(reg, plat->apb_base + GMAC_CLK_EN); + return 0; +} + +static int dwmac_thead_eth_start(struct udevice *dev) +{ + struct dwmac_thead_plat *plat = dev_get_plat(dev); + struct dw_eth_dev *edev = dev_get_priv(dev); + phy_interface_t interface; + bool is_rgmii; + long tx_rate; + int ret; + + interface = plat->dw_eth_pdata.eth_pdata.phy_interface; + is_rgmii = (interface == PHY_INTERFACE_MODE_RGMII) | + (interface == PHY_INTERFACE_MODE_RGMII_ID) | + (interface == PHY_INTERFACE_MODE_RGMII_RXID) | + (interface == PHY_INTERFACE_MODE_RGMII_TXID); + + /* + * When operating in RGMII mode, the TX clock is generated by an + * internal divider and fed to the MAC. Configure and enable it before + * initializing the MAC. + */ + if (is_rgmii) { + ret = dwmac_thead_set_clk_tx_rate(plat, edev, + GMAC_RGMII_CLK_RATE); + if (ret) + return ret; + } + + ret = designware_eth_init(edev, plat->dw_eth_pdata.eth_pdata.enetaddr); + if (ret) + return ret; + + if (is_rgmii) { + tx_rate = dwmac_thead_rgmii_tx_rate(edev->phydev->speed); + if (tx_rate < 0) + return tx_rate; + + ret = dwmac_thead_set_clk_tx_rate(plat, edev, tx_rate); + if (ret) + return ret; + } + + ret = designware_eth_enable(edev); + if (ret) + return ret; + + return 0; +} + +static int dwmac_thead_probe(struct udevice *dev) +{ + struct dwmac_thead_plat *plat = dev_get_plat(dev); + unsigned int reg; + int ret; + + ret = designware_eth_probe(dev); + if (ret) + return ret; + + ret = dwmac_thead_set_phy_if(plat); + if (ret) { + pr_err("failed to set phy interface: %d\n", ret); + return ret; + } + + ret = dwmac_thead_set_txclk_dir(plat); + if (ret) { + pr_err("failed to set TX clock direction: %d\n", ret); + return ret; + } + + reg = readl(plat->apb_base + GMAC_RXCLK_DELAY_CTRL); + reg &= ~(GMAC_RXCLK_DELAY); + reg |= FIELD_PREP(GMAC_RXCLK_DELAY, 0); + writel(reg, plat->apb_base + GMAC_RXCLK_DELAY_CTRL); + + reg = readl(plat->apb_base + GMAC_TXCLK_DELAY_CTRL); + reg &= ~(GMAC_TXCLK_DELAY); + reg |= FIELD_PREP(GMAC_TXCLK_DELAY, 0); + writel(reg, plat->apb_base + GMAC_TXCLK_DELAY_CTRL); + + ret = dwmac_thead_enable_clk(plat); + if (ret) + pr_err("failed to enable clock: %d\n", ret); + + return ret; +} + +static int dwmac_thead_of_to_plat(struct udevice *dev) +{ + struct dwmac_thead_plat *pdata = dev_get_plat(dev); + + pdata->apb_base = dev_read_addr_index_ptr(dev, 1); + if (!pdata->apb_base) { + pr_err("failed to get apb registers\n"); + return -ENOENT; + } + + return designware_eth_of_to_plat(dev); +} + +static const struct eth_ops dwmac_thead_eth_ops = { + .start = dwmac_thead_eth_start, + .send = designware_eth_send, + .recv = designware_eth_recv, + .free_pkt = designware_eth_free_pkt, + .stop = designware_eth_stop, + .write_hwaddr = designware_eth_write_hwaddr, +}; + +static const struct udevice_id dwmac_thead_match[] = { + { .compatible = "thead,th1520-gmac" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(dwmac_thead) = { + .name = "dwmac_thead", + .id = UCLASS_ETH, + .of_match = dwmac_thead_match, + .of_to_plat = dwmac_thead_of_to_plat, + .probe = dwmac_thead_probe, + .ops = &dwmac_thead_eth_ops, + .priv_auto = sizeof(struct dw_eth_dev), + .plat_auto = sizeof(struct dwmac_thead_plat), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/net/sandbox-raw-bus.c b/drivers/net/sandbox-raw-bus.c index 15670d6d24a..c698a07c784 100644 --- a/drivers/net/sandbox-raw-bus.c +++ b/drivers/net/sandbox-raw-bus.c @@ -42,7 +42,7 @@ static int eth_raw_bus_post_bind(struct udevice *dev) device_probe(child); priv = dev_get_priv(child); if (priv) { - strcpy(priv->host_ifname, i->if_name); + strlcpy(priv->host_ifname, i->if_name, IFNAMSIZ); priv->host_ifindex = i->if_index; priv->local = local; } diff --git a/drivers/net/xilinx_axi_mrmac.c b/drivers/net/xilinx_axi_mrmac.c index 555651937f8..56f877c20a6 100644 --- a/drivers/net/xilinx_axi_mrmac.c +++ b/drivers/net/xilinx_axi_mrmac.c @@ -346,7 +346,7 @@ static bool isrxready(struct axi_mrmac_priv *priv) * axi_mrmac_recv - MRMAC Rx function * @dev: udevice structure * @flags: flags from network stack - * @packetp pointer to received data + * @packetp: pointer to received data * * Return: received data length on success, negative value on errors * @@ -399,7 +399,7 @@ static int axi_mrmac_recv(struct udevice *dev, int flags, uchar **packetp) * axi_mrmac_free_pkt - MRMAC free packet function * @dev: udevice structure * @packet: receive buffer pointer - * @length received data length + * @length: received data length * * Return: 0 on success, negative value on errors * diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index d3fe90d939e..c297fa03ea7 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -259,6 +259,15 @@ config MT76X8_USB_PHY This PHY is found on MT76x8 devices supporting USB. +config PHY_EXYNOS_USBDRD + bool "Exynos SoC series USB DRD PHY driver" + depends on PHY && CLK + depends on ARCH_EXYNOS + select REGMAP + select SYSCON + help + Enable USB DRD PHY support for Exynos SoC series. + config PHY_MTK_TPHY bool "MediaTek T-PHY Driver" depends on PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index b4d01fc700d..98c1ef8683b 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o obj-$(CONFIG_MT7620_USB_PHY) += mt7620-usb-phy.o obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o +obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o diff --git a/drivers/phy/phy-exynos-usbdrd.c b/drivers/phy/phy-exynos-usbdrd.c new file mode 100644 index 00000000000..db5815ed184 --- /dev/null +++ b/drivers/phy/phy-exynos-usbdrd.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Linaro Ltd. + * Sam Protsenko <semen.protsenko@linaro.org> + * + * Samsung Exynos SoC series USB DRD PHY driver. + * Based on Linux kernel PHY driver: drivers/phy/samsung/phy-exynos5-usbdrd.c + */ + +#include <clk.h> +#include <dm.h> +#include <generic-phy.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> + +/* Offset of PMU register controlling USB PHY output isolation */ +#define EXYNOS_USBDRD_PHY_CONTROL 0x0704 +#define EXYNOS_PHY_ENABLE BIT(0) + +/* Exynos USB PHY registers */ +#define EXYNOS5_FSEL_9MHZ6 0x0 +#define EXYNOS5_FSEL_10MHZ 0x1 +#define EXYNOS5_FSEL_12MHZ 0x2 +#define EXYNOS5_FSEL_19MHZ2 0x3 +#define EXYNOS5_FSEL_20MHZ 0x4 +#define EXYNOS5_FSEL_24MHZ 0x5 +#define EXYNOS5_FSEL_26MHZ 0x6 +#define EXYNOS5_FSEL_50MHZ 0x7 + +/* Exynos850: USB DRD PHY registers */ +#define EXYNOS850_DRD_LINKCTRL 0x04 +#define LINKCTRL_FORCE_QACT BIT(8) +#define LINKCTRL_BUS_FILTER_BYPASS GENMASK(7, 4) + +#define EXYNOS850_DRD_CLKRST 0x20 +#define CLKRST_LINK_SW_RST BIT(0) +#define CLKRST_PORT_RST BIT(1) +#define CLKRST_PHY_SW_RST BIT(3) + +#define EXYNOS850_DRD_SSPPLLCTL 0x30 +#define SSPPLLCTL_FSEL GENMASK(2, 0) + +#define EXYNOS850_DRD_UTMI 0x50 +#define UTMI_FORCE_SLEEP BIT(0) +#define UTMI_FORCE_SUSPEND BIT(1) +#define UTMI_DM_PULLDOWN BIT(2) +#define UTMI_DP_PULLDOWN BIT(3) +#define UTMI_FORCE_BVALID BIT(4) +#define UTMI_FORCE_VBUSVALID BIT(5) + +#define EXYNOS850_DRD_HSP 0x54 +#define HSP_COMMONONN BIT(8) +#define HSP_EN_UTMISUSPEND BIT(9) +#define HSP_VBUSVLDEXT BIT(12) +#define HSP_VBUSVLDEXTSEL BIT(13) +#define HSP_FSV_OUT_EN BIT(24) + +#define EXYNOS850_DRD_HSP_TEST 0x5c +#define HSP_TEST_SIDDQ BIT(24) + +#define KHZ 1000 +#define MHZ (KHZ * KHZ) + +/** + * struct exynos_usbdrd_phy - driver data for Exynos USB PHY + * @reg_phy: USB PHY controller register memory base + * @clk: clock for register access + * @core_clk: core clock for phy (ref clock) + * @reg_pmu: regmap for PMU block + * @extrefclk: frequency select settings when using 'separate reference clocks' + */ +struct exynos_usbdrd_phy { + void __iomem *reg_phy; + struct clk *clk; + struct clk *core_clk; + struct regmap *reg_pmu; + u32 extrefclk; +}; + +static void exynos_usbdrd_phy_isol(struct regmap *reg_pmu, bool isolate) +{ + unsigned int val; + + if (!reg_pmu) + return; + + val = isolate ? 0 : EXYNOS_PHY_ENABLE; + regmap_update_bits(reg_pmu, EXYNOS_USBDRD_PHY_CONTROL, + EXYNOS_PHY_ENABLE, val); +} + +/* + * Convert the supplied clock rate to the value that can be written to the PHY + * register. + */ +static unsigned int exynos_rate_to_clk(unsigned long rate, u32 *reg) +{ + switch (rate) { + case 9600 * KHZ: + *reg = EXYNOS5_FSEL_9MHZ6; + break; + case 10 * MHZ: + *reg = EXYNOS5_FSEL_10MHZ; + break; + case 12 * MHZ: + *reg = EXYNOS5_FSEL_12MHZ; + break; + case 19200 * KHZ: + *reg = EXYNOS5_FSEL_19MHZ2; + break; + case 20 * MHZ: + *reg = EXYNOS5_FSEL_20MHZ; + break; + case 24 * MHZ: + *reg = EXYNOS5_FSEL_24MHZ; + break; + case 26 * MHZ: + *reg = EXYNOS5_FSEL_26MHZ; + break; + case 50 * MHZ: + *reg = EXYNOS5_FSEL_50MHZ; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void exynos850_usbdrd_utmi_init(struct phy *phy) +{ + struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev); + void __iomem *regs_base = phy_drd->reg_phy; + u32 reg; + + /* + * Disable HWACG (hardware auto clock gating control). This will force + * QACTIVE signal in Q-Channel interface to HIGH level, to make sure + * the PHY clock is not gated by the hardware. + */ + reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); + reg |= LINKCTRL_FORCE_QACT; + writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); + + /* Start PHY Reset (POR=high) */ + reg = readl(regs_base + EXYNOS850_DRD_CLKRST); + reg |= CLKRST_PHY_SW_RST; + writel(reg, regs_base + EXYNOS850_DRD_CLKRST); + + /* Enable UTMI+ */ + reg = readl(regs_base + EXYNOS850_DRD_UTMI); + reg &= ~(UTMI_FORCE_SUSPEND | UTMI_FORCE_SLEEP | UTMI_DP_PULLDOWN | + UTMI_DM_PULLDOWN); + writel(reg, regs_base + EXYNOS850_DRD_UTMI); + + /* Set PHY clock and control HS PHY */ + reg = readl(regs_base + EXYNOS850_DRD_HSP); + reg |= HSP_EN_UTMISUSPEND | HSP_COMMONONN; + writel(reg, regs_base + EXYNOS850_DRD_HSP); + + /* Set VBUS Valid and D+ pull-up control by VBUS pad usage */ + reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); + reg |= FIELD_PREP(LINKCTRL_BUS_FILTER_BYPASS, 0xf); + writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); + + reg = readl(regs_base + EXYNOS850_DRD_UTMI); + reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID; + writel(reg, regs_base + EXYNOS850_DRD_UTMI); + + reg = readl(regs_base + EXYNOS850_DRD_HSP); + reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL; + writel(reg, regs_base + EXYNOS850_DRD_HSP); + + reg = readl(regs_base + EXYNOS850_DRD_SSPPLLCTL); + reg &= ~SSPPLLCTL_FSEL; + switch (phy_drd->extrefclk) { + case EXYNOS5_FSEL_50MHZ: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 7); + break; + case EXYNOS5_FSEL_26MHZ: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 6); + break; + case EXYNOS5_FSEL_24MHZ: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 2); + break; + case EXYNOS5_FSEL_20MHZ: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 1); + break; + case EXYNOS5_FSEL_19MHZ2: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 0); + break; + default: + dev_warn(phy->dev, "unsupported ref clk: %#.2x\n", + phy_drd->extrefclk); + break; + } + writel(reg, regs_base + EXYNOS850_DRD_SSPPLLCTL); + + /* Power up PHY analog blocks */ + reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST); + reg &= ~HSP_TEST_SIDDQ; + writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST); + + /* Finish PHY reset (POR=low) */ + udelay(10); /* required before doing POR=low */ + reg = readl(regs_base + EXYNOS850_DRD_CLKRST); + reg &= ~(CLKRST_PHY_SW_RST | CLKRST_PORT_RST); + writel(reg, regs_base + EXYNOS850_DRD_CLKRST); + udelay(75); /* required after POR=low for guaranteed PHY clock */ + + /* Disable single ended signal out */ + reg = readl(regs_base + EXYNOS850_DRD_HSP); + reg &= ~HSP_FSV_OUT_EN; + writel(reg, regs_base + EXYNOS850_DRD_HSP); +} + +static void exynos850_usbdrd_utmi_exit(struct phy *phy) +{ + struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev); + void __iomem *regs_base = phy_drd->reg_phy; + u32 reg; + + /* Set PHY clock and control HS PHY */ + reg = readl(regs_base + EXYNOS850_DRD_UTMI); + reg &= ~(UTMI_DP_PULLDOWN | UTMI_DM_PULLDOWN); + reg |= UTMI_FORCE_SUSPEND | UTMI_FORCE_SLEEP; + writel(reg, regs_base + EXYNOS850_DRD_UTMI); + + /* Power down PHY analog blocks */ + reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST); + reg |= HSP_TEST_SIDDQ; + writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST); + + /* Link reset */ + reg = readl(regs_base + EXYNOS850_DRD_CLKRST); + reg |= CLKRST_LINK_SW_RST; + writel(reg, regs_base + EXYNOS850_DRD_CLKRST); + udelay(10); /* required before doing POR=low */ + reg &= ~CLKRST_LINK_SW_RST; + writel(reg, regs_base + EXYNOS850_DRD_CLKRST); +} + +static int exynos_usbdrd_phy_init(struct phy *phy) +{ + struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev); + int ret; + + ret = clk_prepare_enable(phy_drd->clk); + if (ret) + return ret; + + exynos850_usbdrd_utmi_init(phy); + + clk_disable_unprepare(phy_drd->clk); + + return 0; +} + +static int exynos_usbdrd_phy_exit(struct phy *phy) +{ + struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev); + int ret; + + ret = clk_prepare_enable(phy_drd->clk); + if (ret) + return ret; + + exynos850_usbdrd_utmi_exit(phy); + + clk_disable_unprepare(phy_drd->clk); + + return 0; +} + +static int exynos_usbdrd_phy_power_on(struct phy *phy) +{ + struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev); + int ret; + + dev_dbg(phy->dev, "Request to power_on usbdrd_phy phy\n"); + + ret = clk_prepare_enable(phy_drd->core_clk); + if (ret) + return ret; + + /* Power-on PHY */ + exynos_usbdrd_phy_isol(phy_drd->reg_pmu, false); + + return 0; +} + +static int exynos_usbdrd_phy_power_off(struct phy *phy) +{ + struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev); + + dev_dbg(phy->dev, "Request to power_off usbdrd_phy phy\n"); + + /* Power-off the PHY */ + exynos_usbdrd_phy_isol(phy_drd->reg_pmu, true); + + clk_disable_unprepare(phy_drd->core_clk); + + return 0; +} + +static int exynos_usbdrd_phy_init_clk(struct udevice *dev) +{ + struct exynos_usbdrd_phy *phy_drd = dev_get_priv(dev); + unsigned long ref_rate; + int err; + + phy_drd->clk = devm_clk_get(dev, "phy"); + if (IS_ERR(phy_drd->clk)) { + err = PTR_ERR(phy_drd->clk); + dev_err(dev, "Failed to get phy clock (err=%d)\n", err); + return err; + } + + phy_drd->core_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(phy_drd->core_clk)) { + err = PTR_ERR(phy_drd->core_clk); + dev_err(dev, "Failed to get ref clock (err=%d)\n", err); + return err; + } + + ref_rate = clk_get_rate(phy_drd->core_clk); + err = exynos_rate_to_clk(ref_rate, &phy_drd->extrefclk); + if (err) { + dev_err(dev, "Clock rate %lu not supported\n", ref_rate); + return err; + } + + return 0; +} + +static int exynos_usbdrd_phy_probe(struct udevice *dev) +{ + struct exynos_usbdrd_phy *phy_drd = dev_get_priv(dev); + int err; + + phy_drd->reg_phy = dev_read_addr_ptr(dev); + if (!phy_drd->reg_phy) + return -EINVAL; + + err = exynos_usbdrd_phy_init_clk(dev); + if (err) + return err; + + phy_drd->reg_pmu = syscon_regmap_lookup_by_phandle(dev, + "samsung,pmu-syscon"); + if (IS_ERR(phy_drd->reg_pmu)) { + err = PTR_ERR(phy_drd->reg_pmu); + dev_err(dev, "Failed to lookup PMU regmap\n"); + return err; + } + + return 0; +} + +static const struct phy_ops exynos_usbdrd_phy_ops = { + .init = exynos_usbdrd_phy_init, + .exit = exynos_usbdrd_phy_exit, + .power_on = exynos_usbdrd_phy_power_on, + .power_off = exynos_usbdrd_phy_power_off, +}; + +static const struct udevice_id exynos_usbdrd_phy_of_match[] = { + { + .compatible = "samsung,exynos850-usbdrd-phy", + }, + { } +}; + +U_BOOT_DRIVER(exynos_usbdrd_phy) = { + .name = "exynos-usbdrd-phy", + .id = UCLASS_PHY, + .of_match = exynos_usbdrd_phy_of_match, + .probe = exynos_usbdrd_phy_probe, + .ops = &exynos_usbdrd_phy_ops, + .priv_auto = sizeof(struct exynos_usbdrd_phy), +}; diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index b44aae78e6d..a7e64971a2a 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -468,6 +468,8 @@ out_clk_disable: static int imx8m_power_domain_of_xlate(struct power_domain *power_domain, struct ofnode_phandle_args *args) { + power_domain->id = 0; + return 0; } diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 09567eb9dbb..2a59a1b79c2 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -260,13 +260,13 @@ int regulator_get_by_platname(const char *plat_name, struct udevice **devp) *devp = NULL; - for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev; - ret = uclass_find_next_device(&dev)) { - if (ret) { - dev_dbg(dev, "ret=%d\n", ret); - continue; - } + ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); + if (ret) { + dev_dbg(dev, "ret=%d\n", ret); + return ret; + } + for (; dev; uclass_find_next_device(&dev)) { uc_pdata = dev_get_uclass_plat(dev); if (!uc_pdata || strcmp(plat_name, uc_pdata->name)) continue; @@ -410,9 +410,12 @@ static bool regulator_name_is_unique(struct udevice *check_dev, int ret; int len; - for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev; - ret = uclass_find_next_device(&dev)) { - if (ret || dev == check_dev) + ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); + if (ret) + return true; + + for (; dev; uclass_find_next_device(&dev)) { + if (dev == check_dev) continue; uc_pdata = dev_get_uclass_plat(dev); diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index 3233ff80419..2dbd3a21cea 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -55,9 +55,12 @@ static int for_each_remoteproc_device(int (*fn) (struct udevice *dev, struct dm_rproc_uclass_pdata *uc_pdata; int ret; - for (ret = uclass_find_first_device(UCLASS_REMOTEPROC, &dev); dev; - ret = uclass_find_next_device(&dev)) { - if (ret || dev == skip_dev) + ret = uclass_find_first_device(UCLASS_REMOTEPROC, &dev); + if (ret) + return ret; + + for (; dev; uclass_find_next_device(&dev)) { + if (dev == skip_dev) continue; uc_pdata = dev_get_uclass_plat(dev); ret = fn(dev, uc_pdata, data); diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 6f89d3add5d..4696c09f754 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -559,9 +559,6 @@ int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv, u8 opcode; if (priv->dtr) - txlen += txlen & 1; - - if (priv->dtr) opcode = op->cmd.opcode >> 8; else opcode = op->cmd.opcode; diff --git a/drivers/spi/microchip_coreqspi.c b/drivers/spi/microchip_coreqspi.c index 234b1688272..a84b257fb1a 100644 --- a/drivers/spi/microchip_coreqspi.c +++ b/drivers/spi/microchip_coreqspi.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/types.h> #include <linux/sizes.h> +#include <asm/gpio.h> DECLARE_GLOBAL_DATA_PTR; @@ -97,6 +98,8 @@ DECLARE_GLOBAL_DATA_PTR; #define REG_X4_TX_DATA (0x4c) #define REG_FRAMESUP (0x50) +#define MAX_CS_COUNT 1 + /** * struct mchp_coreqspi - Defines qspi driver instance * @regs: Address of the QSPI controller registers @@ -113,6 +116,7 @@ struct mchp_coreqspi { u8 *rxbuf; int tx_len; int rx_len; + struct gpio_desc cs_gpios[MAX_CS_COUNT]; }; static void mchp_coreqspi_init_hw(struct mchp_coreqspi *qspi) @@ -172,7 +176,7 @@ static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word) while (qspi->tx_len >= 4) { while (readl(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) ; - data = *(u32 *)qspi->txbuf; + data = qspi->txbuf ? *((u32 *)qspi->txbuf) : 0xFF; qspi->txbuf += 4; qspi->tx_len -= 4; writel(data, qspi->regs + REG_X4_TX_DATA); @@ -184,7 +188,7 @@ static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word) while (qspi->tx_len--) { while (readl(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) ; - data = *qspi->txbuf++; + data = qspi->txbuf ? *qspi->txbuf++ : 0xFF; writel(data, qspi->regs + REG_TX_DATA); } } @@ -471,6 +475,110 @@ static int mchp_coreqspi_probe(struct udevice *dev) /* Init the mpfs qspi hw */ mchp_coreqspi_init_hw(qspi); + if (CONFIG_IS_ENABLED(DM_GPIO)) { + int i; + + ret = gpio_request_list_by_name(dev, "cs-gpios", qspi->cs_gpios, + ARRAY_SIZE(qspi->cs_gpios), 0); + + if (ret < 0) { + pr_err("Can't get %s gpios! Error: %d", dev->name, ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(qspi->cs_gpios); i++) { + if (!dm_gpio_is_valid(&qspi->cs_gpios[i])) + continue; + dm_gpio_set_dir_flags(&qspi->cs_gpios[i], GPIOD_IS_OUT); + } + } + + u32 control = readl(qspi->regs + REG_CONTROL); + + control |= (CONTROL_MASTER | CONTROL_ENABLE); + control &= ~CONTROL_CLKIDLE; + writel(control, qspi->regs + REG_CONTROL); + + return 0; +} + +static void mchp_coreqspi_cs_activate(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct mchp_coreqspi *qspi = dev_get_priv(bus); + struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); + u32 cs = slave_plat->cs[0]; + + if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&qspi->cs_gpios[cs])) + dm_gpio_set_value(&qspi->cs_gpios[cs], 1); +} + +static void mchp_coreqspi_cs_deactivate(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct mchp_coreqspi *qspi = dev_get_priv(bus); + struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); + u32 cs = slave_plat->cs[0]; + + if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&qspi->cs_gpios[cs])) + dm_gpio_set_value(&qspi->cs_gpios[cs], 0); +} + +static int mchp_coreqspi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(dev); + struct mchp_coreqspi *qspi = dev_get_priv(bus); + struct spi_slave *slave = dev_get_parent_priv(dev); + uint total_bytes = bitlen >> 3; /* fixed 8-bit word length */ + u32 control, frames; + + int err = 0; + + err = mchp_coreqspi_wait_for_ready(slave); + if (err) + return err; + + control = readl(qspi->regs + REG_CONTROL); + control &= ~(CONTROL_MODE12_MASK | CONTROL_MODE0); + writel(control, qspi->regs + REG_CONTROL); + + frames = total_bytes & BYTESUPPER_MASK; + writel(frames, qspi->regs + REG_FRAMESUP); + + frames |= FRAMES_FLAGBYTE; + writel(frames, qspi->regs + REG_FRAMES); + + if (flags & SPI_XFER_BEGIN) + mchp_coreqspi_cs_activate(dev); + + if (bitlen == 0) + goto out; + + if (bitlen % 8) { // Non byte aligned SPI transfer + flags |= SPI_XFER_END; + goto out; + } + + qspi->txbuf = (u8 *)dout; + qspi->rxbuf = (u8 *)din; + + while (total_bytes) { + qspi->tx_len = 1; + qspi->rx_len = 1; + total_bytes--; + + if (din) { + mchp_coreqspi_write_op(qspi, true); + mchp_coreqspi_read_op(qspi); + } else { + mchp_coreqspi_write_op(qspi, true); + } + } +out: + if (flags & SPI_XFER_END) + mchp_coreqspi_cs_deactivate(dev); + return 0; } @@ -483,6 +591,7 @@ static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = { static const struct dm_spi_ops mchp_coreqspi_ops = { .claim_bus = mchp_coreqspi_claim_bus, .release_bus = mchp_coreqspi_release_bus, + .xfer = mchp_coreqspi_xfer, .set_speed = mchp_coreqspi_set_speed, .set_mode = mchp_coreqspi_set_mode, .mem_ops = &mchp_coreqspi_mem_ops, diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index aa83073c96a..67edf004205 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -176,7 +176,7 @@ config SYSRESET_PALMAS config SYSRESET_PSCI bool "Enable support for PSCI System Reset" depends on ARM_PSCI_FW - select SPL_ARM_PSCI_FW if SPL + select SPL_ARM_PSCI_FW if SPL_SYSRESET help Enable PSCI SYSTEM_RESET function call. To use this, PSCI firmware must be running on your system. diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 21452ad1569..3cda2b74b7e 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -704,6 +704,7 @@ static const struct udevice_id dwc3_glue_ids[] = { { .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops }, { .compatible = "fsl,imx8mq-dwc3" }, { .compatible = "intel,tangier-dwc3" }, + { .compatible = "samsung,exynos850-dwusb3" }, { } }; |