diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Makefile | 2 | ||||
-rw-r--r-- | drivers/ata/fsl_sata.c | 58 | ||||
-rw-r--r-- | drivers/ata/sata_sil.c | 60 | ||||
-rw-r--r-- | drivers/board/Kconfig | 3 | ||||
-rw-r--r-- | drivers/board/Makefile | 2 | ||||
-rw-r--r-- | drivers/board/board-uclass.c | 11 | ||||
-rw-r--r-- | drivers/ddr/imx/imx8m/ddr_init.c | 11 | ||||
-rw-r--r-- | drivers/ddr/imx/imx8m/ddrphy_train.c | 9 | ||||
-rw-r--r-- | drivers/ddr/imx/imx8m/ddrphy_utils.c | 8 | ||||
-rw-r--r-- | drivers/mtd/spi/spi-nor-core.c | 46 | ||||
-rw-r--r-- | drivers/pci/pcie_imx.c | 1 | ||||
-rw-r--r-- | drivers/power/regulator/regulator_common.c | 4 | ||||
-rw-r--r-- | drivers/remoteproc/rproc-elf-loader.c | 269 | ||||
-rw-r--r-- | drivers/remoteproc/stm32_copro.c | 27 | ||||
-rw-r--r-- | drivers/video/lg4573.c | 175 | ||||
-rw-r--r-- | drivers/video/meson/meson_canvas.c | 4 | ||||
-rw-r--r-- | drivers/video/meson/meson_plane.c | 5 | ||||
-rw-r--r-- | drivers/video/meson/meson_vclk.c | 2 | ||||
-rw-r--r-- | drivers/video/meson/meson_venc.c | 4 | ||||
-rw-r--r-- | drivers/video/meson/meson_vpu.c | 18 | ||||
-rw-r--r-- | drivers/video/meson/meson_vpu.h | 17 | ||||
-rw-r--r-- | drivers/video/meson/meson_vpu_init.c | 4 |
22 files changed, 654 insertions, 86 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index bfc5a253af9..44a08da602a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/ obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/ obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += power/acpi_pmc/ +obj-$(CONFIG_$(SPL_)BOARD) += board/ ifndef CONFIG_TPL_BUILD ifdef CONFIG_SPL_BUILD @@ -76,7 +77,6 @@ obj-y += ata/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ -obj-y += board/ obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ diff --git a/drivers/ata/fsl_sata.c b/drivers/ata/fsl_sata.c index 6609bf8a761..c6680dc1c98 100644 --- a/drivers/ata/fsl_sata.c +++ b/drivers/ata/fsl_sata.c @@ -22,6 +22,7 @@ #include <dm.h> #include <ahci.h> #include <blk.h> +#include <dm/device-internal.h> #else #ifndef CONFIG_SYS_SATA1_FLAGS #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA @@ -122,7 +123,7 @@ static int init_sata(struct fsl_ata_priv *priv, int dev) /* Zero all of the device driver struct */ memset((void *)sata, 0, sizeof(fsl_sata_t)); - snprintf(sata->name, 12, "SATA%d:\n", dev); + snprintf(sata->name, 12, "SATA%d:", dev); /* Set the controller register base address to device struct */ #if !CONFIG_IS_ENABLED(BLK) @@ -233,10 +234,7 @@ static int init_sata(struct fsl_ata_priv *priv, int dev) mdelay(100); /* print sata device name */ - if (!dev) - printf("%s ", sata->name); - else - printf(" %s ", sata->name); + printf("%s ", sata->name); /* Wait PHY RDY signal changed for 500ms */ ata_wait_register(®->hstatus, HSTATUS_PHY_RDY, @@ -917,15 +915,32 @@ static int fsl_ata_ofdata_to_platdata(struct udevice *dev) return 0; } +static int fsl_unbind_device(struct udevice *dev) +{ + int ret; + + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return ret; + + ret = device_unbind(dev); + if (ret) + return ret; + + return 0; +} + static int fsl_ata_probe(struct udevice *dev) { struct fsl_ata_priv *blk_priv, *priv; struct udevice *blk; + int failed_number; char sata_name[10]; int nr_ports; int ret; int i; + failed_number = 0; priv = dev_get_priv(dev); nr_ports = priv->number; nr_ports = min(nr_ports, CONFIG_SYS_SATA_MAX_DEVICE); @@ -943,7 +958,12 @@ static int fsl_ata_probe(struct udevice *dev) ret = init_sata(priv, i); if (ret) { debug("%s: Failed to init sata\n", __func__); - return ret; + ret = fsl_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; } blk_priv = dev_get_platdata(blk); @@ -952,10 +972,33 @@ static int fsl_ata_probe(struct udevice *dev) ret = scan_sata(blk); if (ret) { debug("%s: Failed to scan bus\n", __func__); - return ret; + ret = fsl_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; } } + if (failed_number == nr_ports) + return -ENODEV; + else + return 0; +} + +static int fsl_ata_remove(struct udevice *dev) +{ + fsl_sata_t *sata; + struct fsl_ata_priv *priv; + + priv = dev_get_priv(dev); + sata = priv->fsl_sata; + + free(sata->cmd_hdr_tbl_offset); + free(sata->cmd_desc_offset); + free(sata); + return 0; } @@ -982,6 +1025,7 @@ U_BOOT_DRIVER(fsl_ahci) = { .ops = &sata_fsl_ahci_ops, .ofdata_to_platdata = fsl_ata_ofdata_to_platdata, .probe = fsl_ata_probe, + .remove = fsl_ata_remove, .priv_auto_alloc_size = sizeof(struct fsl_ata_priv), }; #endif diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 4a50460c5ac..71ee0c04efa 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -20,6 +20,7 @@ #if CONFIG_IS_ENABLED(BLK) #include <dm.h> #include <blk.h> +#include <dm/device-internal.h> #endif #include "sata_sil.h" @@ -763,15 +764,33 @@ U_BOOT_DRIVER(sata_sil_driver) = { .platdata_auto_alloc_size = sizeof(struct sil_sata_priv), }; +static int sil_unbind_device(struct udevice *dev) +{ + int ret; + + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return ret; + + ret = device_unbind(dev); + if (ret) + return ret; + + return 0; +} + static int sil_pci_probe(struct udevice *dev) { struct udevice *blk; + int failed_number; char sata_name[10]; pci_dev_t devno; u16 word; int ret; int i; + failed_number = 0; + /* Get PCI device number */ devno = dm_pci_get_bdf(dev); if (devno == -1) @@ -824,12 +843,44 @@ static int sil_pci_probe(struct udevice *dev) } ret = sil_init_sata(blk, i); - if (ret) - return -ENODEV; + if (ret) { + ret = sil_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; + } ret = scan_sata(blk, i); - if (ret) - return -ENODEV; + if (ret) { + ret = sil_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; + } + } + + if (failed_number == sata_info.maxport) + return -ENODEV; + else + return 0; +} + +static int sil_pci_remove(struct udevice *dev) +{ + int i; + struct sil_sata *sata; + struct sil_sata_priv *priv; + + priv = dev_get_priv(dev); + + for (i = sata_info.portbase; i < sata_info.maxport; i++) { + sata = priv->sil_sata_desc[i]; + if (sata) + free(sata); } return 0; @@ -857,6 +908,7 @@ U_BOOT_DRIVER(sil_ahci_pci) = { .of_match = sil_pci_ids, .ops = &sata_sil_ops, .probe = sil_pci_probe, + .remove = sil_pci_remove, .priv_auto_alloc_size = sizeof(struct sil_sata_priv), }; diff --git a/drivers/board/Kconfig b/drivers/board/Kconfig index 2a3fc9c049b..254f657049d 100644 --- a/drivers/board/Kconfig +++ b/drivers/board/Kconfig @@ -8,6 +8,9 @@ menuconfig BOARD if BOARD +config SPL_BOARD + depends on SPL_DM + bool "Enable board driver support in SPL" config BOARD_GAZERBEAM bool "Enable board driver for the Gazerbeam board" diff --git a/drivers/board/Makefile b/drivers/board/Makefile index c8dab4fa0ba..cc16361755a 100644 --- a/drivers/board/Makefile +++ b/drivers/board/Makefile @@ -2,6 +2,6 @@ # # (C) Copyright 2017 # Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc -obj-$(CONFIG_BOARD) += board-uclass.o +obj-y += board-uclass.o obj-$(CONFIG_BOARD_GAZERBEAM) += gazerbeam.o obj-$(CONFIG_BOARD_SANDBOX) += sandbox.o diff --git a/drivers/board/board-uclass.c b/drivers/board/board-uclass.c index a516ba49629..b5485e9895b 100644 --- a/drivers/board/board-uclass.c +++ b/drivers/board/board-uclass.c @@ -23,6 +23,17 @@ int board_detect(struct udevice *dev) return ops->detect(dev); } +int board_get_fit_loadable(struct udevice *dev, int index, + const char *type, const char **strp) +{ + struct board_ops *ops = board_get_ops(dev); + + if (!ops->get_fit_loadable) + return -ENOSYS; + + return ops->get_fit_loadable(dev, index, type, strp); +} + int board_get_bool(struct udevice *dev, int id, bool *val) { struct board_ops *ops = board_get_ops(dev); diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c index 21af66e4e7f..af8c1427d2e 100644 --- a/drivers/ddr/imx/imx8m/ddr_init.c +++ b/drivers/ddr/imx/imx8m/ddr_init.c @@ -20,9 +20,10 @@ void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num) } } -void ddr_init(struct dram_timing_info *dram_timing) +int ddr_init(struct dram_timing_info *dram_timing) { unsigned int tmp, initial_drate, target_freq; + int ret; debug("DDRINFO: start DRAM init\n"); @@ -98,7 +99,11 @@ void ddr_init(struct dram_timing_info *dram_timing) * accessing relevant PUB registers */ debug("DDRINFO:ddrphy config start\n"); - ddr_cfg_phy(dram_timing); + + ret = ddr_cfg_phy(dram_timing); + if (ret) + return ret; + debug("DDRINFO: ddrphy config done\n"); /* @@ -165,4 +170,6 @@ void ddr_init(struct dram_timing_info *dram_timing) /* save the dram timing config into memory */ dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE); + + return 0; } diff --git a/drivers/ddr/imx/imx8m/ddrphy_train.c b/drivers/ddr/imx/imx8m/ddrphy_train.c index 18f7ed7fea9..306af82504f 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_train.c +++ b/drivers/ddr/imx/imx8m/ddrphy_train.c @@ -8,13 +8,14 @@ #include <asm/arch/ddr.h> #include <asm/arch/lpddr4_define.h> -void ddr_cfg_phy(struct dram_timing_info *dram_timing) +int ddr_cfg_phy(struct dram_timing_info *dram_timing) { struct dram_cfg_param *dram_cfg; struct dram_fsp_msg *fsp_msg; unsigned int num; int i = 0; int j = 0; + int ret; /* initialize PHY configuration */ dram_cfg = dram_timing->ddrphy_cfg; @@ -60,7 +61,9 @@ void ddr_cfg_phy(struct dram_timing_info *dram_timing) dwc_ddrphy_apb_wr(0xd0099, 0x0); /* Wait for the training firmware to complete */ - wait_ddrphy_training_complete(); + ret = wait_ddrphy_training_complete(); + if (ret) + return ret; /* Halt the microcontroller. */ dwc_ddrphy_apb_wr(0xd0099, 0x1); @@ -83,4 +86,6 @@ void ddr_cfg_phy(struct dram_timing_info *dram_timing) /* save the ddr PHY trained CSR in memory for low power use */ ddrphy_trained_csr_save(ddrphy_trained_csr, ddrphy_trained_csr_num); + + return 0; } diff --git a/drivers/ddr/imx/imx8m/ddrphy_utils.c b/drivers/ddr/imx/imx8m/ddrphy_utils.c index e60503309eb..863fb438971 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_utils.c +++ b/drivers/ddr/imx/imx8m/ddrphy_utils.c @@ -84,7 +84,7 @@ static inline void decode_streaming_message(void) debug("\n"); } -void wait_ddrphy_training_complete(void) +int wait_ddrphy_training_complete(void) { unsigned int mail; @@ -95,10 +95,10 @@ void wait_ddrphy_training_complete(void) decode_streaming_message(); } else if (mail == 0x07) { debug("Training PASS\n"); - break; + return 0; } else if (mail == 0xff) { - printf("Training FAILED\n"); - break; + debug("Training FAILED\n"); + return -1; } } } diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index eb49a6c11c4..6e7fc2311e1 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -1594,6 +1594,7 @@ struct sfdp_parameter_header { #define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ #define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ +#define SFDP_SST_ID 0x01bf /* Manufacturer specific Table */ #define SFDP_SIGNATURE 0x50444653U #define SFDP_JESD216_MAJOR 1 @@ -1974,6 +1975,34 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, } /** + * spi_nor_parse_microchip_sfdp() - parse the Microchip manufacturer specific + * SFDP table. + * @nor: pointer to a 'struct spi_nor'. + * @param_header: pointer to the SFDP parameter header. + * + * Return: 0 on success, -errno otherwise. + */ +static int +spi_nor_parse_microchip_sfdp(struct spi_nor *nor, + const struct sfdp_parameter_header *param_header) +{ + size_t size; + u32 addr; + int ret; + + size = param_header->length * sizeof(u32); + addr = SFDP_PARAM_HEADER_PTP(param_header); + + nor->manufacturer_sfdp = devm_kmalloc(nor->dev, size, GFP_KERNEL); + if (!nor->manufacturer_sfdp) + return -ENOMEM; + + ret = spi_nor_read_sfdp(nor, addr, size, nor->manufacturer_sfdp); + + return ret; +} + +/** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' * @params: pointer to the 'struct spi_nor_flash_parameter' to be @@ -2069,12 +2098,25 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, dev_info(dev, "non-uniform erase sector maps are not supported yet.\n"); break; + case SFDP_SST_ID: + err = spi_nor_parse_microchip_sfdp(nor, param_header); + break; + default: break; } - if (err) - goto exit; + if (err) { + dev_warn(dev, "Failed to parse optional parameter table: %04x\n", + SFDP_PARAM_HEADER_ID(param_header)); + /* + * Let's not drop all information we extracted so far + * if optional table parsers fail. In case of failing, + * each optional parser is responsible to roll back to + * the previously known spi_nor data. + */ + err = 0; + } } exit: diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index d53d6298bf3..3621636cb28 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -815,6 +815,7 @@ static const struct dm_pci_ops imx_pcie_ops = { static const struct udevice_id imx_pcie_ids[] = { { .compatible = "fsl,imx6q-pcie" }, + { .compatible = "fsl,imx6sx-pcie" }, { } }; diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c index 20410865672..939efb2c0d0 100644 --- a/drivers/power/regulator/regulator_common.c +++ b/drivers/power/regulator/regulator_common.c @@ -37,7 +37,11 @@ int regulator_common_ofdata_to_platdata(struct udevice *dev, dev_pdata->startup_delay_us = dev_read_u32_default(dev, "startup-delay-us", 0); dev_pdata->off_on_delay_us = + dev_read_u32_default(dev, "off-on-delay-us", 0); + if (!dev_pdata->off_on_delay_us) { + dev_pdata->off_on_delay_us = dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0); + } return 0; } diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c index e8026cdfbb4..538481241f8 100644 --- a/drivers/remoteproc/rproc-elf-loader.c +++ b/drivers/remoteproc/rproc-elf-loader.c @@ -8,6 +8,39 @@ #include <elf.h> #include <remoteproc.h> +/** + * struct resource_table - firmware resource table header + * @ver: version number + * @num: number of resource entries + * @reserved: reserved (must be zero) + * @offset: array of offsets pointing at the various resource entries + * + * A resource table is essentially a list of system resources required + * by the remote processor. It may also include configuration entries. + * If needed, the remote processor firmware should contain this table + * as a dedicated ".resource_table" ELF section. + * + * Some resources entries are mere announcements, where the host is informed + * of specific remoteproc configuration. Other entries require the host to + * do something (e.g. allocate a system resource). Sometimes a negotiation + * is expected, where the firmware requests a resource, and once allocated, + * the host should provide back its details (e.g. address of an allocated + * memory region). + * + * The header of the resource table, as expressed by this structure, + * contains a version number (should we need to change this format in the + * future), the number of available resource entries, and their offsets + * in the table. + * + * Immediately following this header are the resource entries themselves. + */ +struct resource_table { + u32 ver; + u32 num; + u32 reserved[2]; + u32 offset[0]; +} __packed; + /* Basic function to verify ELF32 image format */ int rproc_elf32_sanity_check(ulong addr, ulong size) { @@ -276,3 +309,239 @@ ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr) else return rproc_elf32_get_boot_addr(addr); } + +/* + * Search for the resource table in an ELF32 image. + * Returns the address of the resource table section if found, NULL if there is + * no resource table section, or error pointer. + */ +static Elf32_Shdr *rproc_elf32_find_rsc_table(struct udevice *dev, + ulong fw_addr, ulong fw_size) +{ + int ret; + unsigned int i; + const char *name_table; + struct resource_table *table; + const u8 *elf_data = (void *)fw_addr; + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr; + Elf32_Shdr *shdr; + + ret = rproc_elf32_sanity_check(fw_addr, fw_size); + if (ret) { + pr_debug("Invalid ELF32 Image %d\n", ret); + return ERR_PTR(ret); + } + + /* look for the resource table and handle it */ + shdr = (Elf32_Shdr *)(elf_data + ehdr->e_shoff); + name_table = (const char *)(elf_data + + shdr[ehdr->e_shstrndx].sh_offset); + + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + u32 size = shdr->sh_size; + u32 offset = shdr->sh_offset; + + if (strcmp(name_table + shdr->sh_name, ".resource_table")) + continue; + + table = (struct resource_table *)(elf_data + offset); + + /* make sure we have the entire table */ + if (offset + size > fw_size) { + pr_debug("resource table truncated\n"); + return ERR_PTR(-ENOSPC); + } + + /* make sure table has at least the header */ + if (sizeof(*table) > size) { + pr_debug("header-less resource table\n"); + return ERR_PTR(-ENOSPC); + } + + /* we don't support any version beyond the first */ + if (table->ver != 1) { + pr_debug("unsupported fw ver: %d\n", table->ver); + return ERR_PTR(-EPROTONOSUPPORT); + } + + /* make sure reserved bytes are zeroes */ + if (table->reserved[0] || table->reserved[1]) { + pr_debug("non zero reserved bytes\n"); + return ERR_PTR(-EBADF); + } + + /* make sure the offsets array isn't truncated */ + if (table->num * sizeof(table->offset[0]) + + sizeof(*table) > size) { + pr_debug("resource table incomplete\n"); + return ERR_PTR(-ENOSPC); + } + + return shdr; + } + + return NULL; +} + +/* Load the resource table from an ELF32 image */ +int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr, + ulong fw_size, ulong *rsc_addr, ulong *rsc_size) +{ + const struct dm_rproc_ops *ops; + Elf32_Shdr *shdr; + void *src, *dst; + + shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size); + if (!shdr) + return -ENODATA; + if (IS_ERR(shdr)) + return PTR_ERR(shdr); + + ops = rproc_get_ops(dev); + *rsc_addr = (ulong)shdr->sh_addr; + *rsc_size = (ulong)shdr->sh_size; + + src = (void *)fw_addr + shdr->sh_offset; + if (ops->device_to_virt) + dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size); + else + dst = (void *)rsc_addr; + + dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n", + (ulong)dst, *rsc_size); + + memcpy(dst, src, *rsc_size); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + *rsc_size, + ARCH_DMA_MINALIGN) - + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); + + return 0; +} + +/* + * Search for the resource table in an ELF64 image. + * Returns the address of the resource table section if found, NULL if there is + * no resource table section, or error pointer. + */ +static Elf64_Shdr *rproc_elf64_find_rsc_table(struct udevice *dev, + ulong fw_addr, ulong fw_size) +{ + int ret; + unsigned int i; + const char *name_table; + struct resource_table *table; + const u8 *elf_data = (void *)fw_addr; + Elf64_Ehdr *ehdr = (Elf64_Ehdr *)fw_addr; + Elf64_Shdr *shdr; + + ret = rproc_elf64_sanity_check(fw_addr, fw_size); + if (ret) { + pr_debug("Invalid ELF64 Image %d\n", ret); + return ERR_PTR(ret); + } + + /* look for the resource table and handle it */ + shdr = (Elf64_Shdr *)(elf_data + ehdr->e_shoff); + name_table = (const char *)(elf_data + + shdr[ehdr->e_shstrndx].sh_offset); + + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + u64 size = shdr->sh_size; + u64 offset = shdr->sh_offset; + + if (strcmp(name_table + shdr->sh_name, ".resource_table")) + continue; + + table = (struct resource_table *)(elf_data + offset); + + /* make sure we have the entire table */ + if (offset + size > fw_size) { + pr_debug("resource table truncated\n"); + return ERR_PTR(-ENOSPC); + } + + /* make sure table has at least the header */ + if (sizeof(*table) > size) { + pr_debug("header-less resource table\n"); + return ERR_PTR(-ENOSPC); + } + + /* we don't support any version beyond the first */ + if (table->ver != 1) { + pr_debug("unsupported fw ver: %d\n", table->ver); + return ERR_PTR(-EPROTONOSUPPORT); + } + + /* make sure reserved bytes are zeroes */ + if (table->reserved[0] || table->reserved[1]) { + pr_debug("non zero reserved bytes\n"); + return ERR_PTR(-EBADF); + } + + /* make sure the offsets array isn't truncated */ + if (table->num * sizeof(table->offset[0]) + + sizeof(*table) > size) { + pr_debug("resource table incomplete\n"); + return ERR_PTR(-ENOSPC); + } + + return shdr; + } + + return NULL; +} + +/* Load the resource table from an ELF64 image */ +int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr, + ulong fw_size, ulong *rsc_addr, ulong *rsc_size) +{ + const struct dm_rproc_ops *ops; + Elf64_Shdr *shdr; + void *src, *dst; + + shdr = rproc_elf64_find_rsc_table(dev, fw_addr, fw_size); + if (!shdr) + return -ENODATA; + if (IS_ERR(shdr)) + return PTR_ERR(shdr); + + ops = rproc_get_ops(dev); + *rsc_addr = (ulong)shdr->sh_addr; + *rsc_size = (ulong)shdr->sh_size; + + src = (void *)fw_addr + shdr->sh_offset; + if (ops->device_to_virt) + dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size); + else + dst = (void *)rsc_addr; + + dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n", + (ulong)dst, *rsc_size); + + memcpy(dst, src, *rsc_size); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + *rsc_size, + ARCH_DMA_MINALIGN) - + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); + + return 0; +} + +/* Load the resource table from an ELF32 or ELF64 image */ +int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr, + ulong fw_size, ulong *rsc_addr, ulong *rsc_size) + +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr; + + if (!fw_addr) + return -EFAULT; + + if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) + return rproc_elf64_load_rsc_table(dev, fw_addr, fw_size, + rsc_addr, rsc_size); + else + return rproc_elf32_load_rsc_table(dev, fw_addr, fw_size, + rsc_addr, rsc_size); +} diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c index 40bba372119..c25488f54d5 100644 --- a/drivers/remoteproc/stm32_copro.c +++ b/drivers/remoteproc/stm32_copro.c @@ -22,14 +22,14 @@ * @hold_boot_regmap: regmap for remote processor reset hold boot * @hold_boot_offset: offset of the register controlling the hold boot setting * @hold_boot_mask: bitmask of the register for the hold boot field - * @is_running: is the remote processor running + * @rsc_table_addr: resource table address */ struct stm32_copro_privdata { struct reset_ctl reset_ctl; struct regmap *hold_boot_regmap; uint hold_boot_offset; uint hold_boot_mask; - bool is_running; + ulong rsc_table_addr; }; /** @@ -141,6 +141,7 @@ static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da, static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) { struct stm32_copro_privdata *priv; + ulong rsc_table_size; int ret; priv = dev_get_priv(dev); @@ -155,6 +156,12 @@ static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) return ret; } + if (rproc_elf32_load_rsc_table(dev, addr, size, &priv->rsc_table_addr, + &rsc_table_size)) { + priv->rsc_table_addr = 0; + dev_warn(dev, "No valid resource table for this firmware\n"); + } + return rproc_elf32_load_image(dev, addr, size); } @@ -180,7 +187,12 @@ static int stm32_copro_start(struct udevice *dev) * rebooting autonomously */ ret = stm32_copro_set_hold_boot(dev, true); - priv->is_running = !ret; + writel(ret ? TAMP_COPRO_STATE_OFF : TAMP_COPRO_STATE_CRUN, + TAMP_COPRO_STATE); + if (!ret) + /* Store rsc_address in bkp register */ + writel(priv->rsc_table_addr, TAMP_COPRO_RSC_TBL_ADDRESS); + return ret; } @@ -206,7 +218,7 @@ static int stm32_copro_reset(struct udevice *dev) return ret; } - priv->is_running = false; + writel(TAMP_COPRO_STATE_OFF, TAMP_COPRO_STATE); return 0; } @@ -224,14 +236,11 @@ static int stm32_copro_stop(struct udevice *dev) /** * stm32_copro_is_running() - Is the STM32 remote processor running * @dev: corresponding STM32 remote processor device - * @return 1 if the remote processor is running, 0 otherwise + * @return 0 if the remote processor is running, 1 otherwise */ static int stm32_copro_is_running(struct udevice *dev) { - struct stm32_copro_privdata *priv; - - priv = dev_get_priv(dev); - return priv->is_running; + return (readl(TAMP_COPRO_STATE) == TAMP_COPRO_STATE_OFF); } static const struct dm_rproc_ops stm32_copro_ops = { diff --git a/drivers/video/lg4573.c b/drivers/video/lg4573.c index 46d9ec83ce4..997e854ef8f 100644 --- a/drivers/video/lg4573.c +++ b/drivers/video/lg4573.c @@ -5,36 +5,40 @@ * */ #include <common.h> +#include <backlight.h> +#include <display.h> +#include <dm.h> +#include <dm/read.h> +#include <dm/uclass-internal.h> #include <errno.h> #include <spi.h> +#include <asm/gpio.h> #define PWR_ON_DELAY_MSECS 120 -static int lb043wv_spi_write_u16(struct spi_slave *spi, u16 val) +static int lb043wv_spi_write_u16(struct spi_slave *slave, u16 val) { - unsigned long flags = SPI_XFER_BEGIN; unsigned short buf16 = htons(val); int ret = 0; - flags |= SPI_XFER_END; - - ret = spi_xfer(spi, 16, &buf16, NULL, flags); + ret = spi_xfer(slave, 16, &buf16, NULL, + SPI_XFER_BEGIN | SPI_XFER_END); if (ret) debug("%s: Failed to send: %d\n", __func__, ret); return ret; } -static void lb043wv_spi_write_u16_array(struct spi_slave *spi, u16 *buff, +static void lb043wv_spi_write_u16_array(struct spi_slave *slave, u16 *buff, int size) { int i; for (i = 0; i < size; i++) - lb043wv_spi_write_u16(spi, buff[i]); + lb043wv_spi_write_u16(slave, buff[i]); } -static void lb043wv_display_mode_settings(struct spi_slave *spi) +static void lb043wv_display_mode_settings(struct spi_slave *slave) { static u16 display_mode_settings[] = { 0x703A, @@ -72,11 +76,11 @@ static void lb043wv_display_mode_settings(struct spi_slave *spi) }; debug("transfer display mode settings\n"); - lb043wv_spi_write_u16_array(spi, display_mode_settings, + lb043wv_spi_write_u16_array(slave, display_mode_settings, ARRAY_SIZE(display_mode_settings)); } -static void lb043wv_power_settings(struct spi_slave *spi) +static void lb043wv_power_settings(struct spi_slave *slave) { static u16 power_settings[] = { 0x70C0, @@ -103,11 +107,11 @@ static void lb043wv_power_settings(struct spi_slave *spi) }; debug("transfer power settings\n"); - lb043wv_spi_write_u16_array(spi, power_settings, + lb043wv_spi_write_u16_array(slave, power_settings, ARRAY_SIZE(power_settings)); } -static void lb043wv_gamma_settings(struct spi_slave *spi) +static void lb043wv_gamma_settings(struct spi_slave *slave) { static u16 gamma_settings[] = { 0x70D0, @@ -173,54 +177,57 @@ static void lb043wv_gamma_settings(struct spi_slave *spi) }; debug("transfer gamma settings\n"); - lb043wv_spi_write_u16_array(spi, gamma_settings, + lb043wv_spi_write_u16_array(slave, gamma_settings, ARRAY_SIZE(gamma_settings)); } -static void lb043wv_display_on(struct spi_slave *spi) +static void lb043wv_display_on(struct spi_slave *slave) { static u16 sleep_out = 0x7011; static u16 display_on = 0x7029; - lb043wv_spi_write_u16(spi, sleep_out); + lb043wv_spi_write_u16(slave, sleep_out); mdelay(PWR_ON_DELAY_MSECS); - lb043wv_spi_write_u16(spi, display_on); + lb043wv_spi_write_u16(slave, display_on); } -int lg4573_spi_startup(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int spi_mode) +static int lg4573_spi_startup(struct spi_slave *slave) { - struct spi_slave *spi; int ret; - spi = spi_setup_slave(bus, cs, max_hz, spi_mode); - if (!spi) { - debug("%s: Failed to set up slave\n", __func__); - return -1; - } - - ret = spi_claim_bus(spi); - if (ret) { - debug("%s: Failed to claim SPI bus: %d\n", __func__, ret); - goto err_claim_bus; - } + ret = spi_claim_bus(slave); + if (ret) + return ret; - lb043wv_display_mode_settings(spi); - lb043wv_power_settings(spi); - lb043wv_gamma_settings(spi); + lb043wv_display_mode_settings(slave); + lb043wv_power_settings(slave); + lb043wv_gamma_settings(slave); + lb043wv_display_on(slave); - lb043wv_display_on(spi); + spi_release_bus(slave); return 0; -err_claim_bus: - spi_free_slave(spi); - return -1; } static int do_lgset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - lg4573_spi_startup(CONFIG_LG4573_BUS, CONFIG_LG4573_CS, 10000000, - SPI_MODE_0); + struct spi_slave *slave; + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_GET_DRIVER(lg4573_lcd), &dev); + if (ret) { + printf("%s: Could not get lg4573 device\n", __func__); + return ret; + } + slave = dev_get_parent_priv(dev); + if (!slave) { + printf("%s: No slave data\n", __func__); + return -ENODEV; + } + lg4573_spi_startup(slave); + return 0; } @@ -229,3 +236,93 @@ U_BOOT_CMD( "set lgdisplay", "" ); + +static int lg4573_bind(struct udevice *dev) +{ + return 0; +} + +static int lg4573_probe(struct udevice *dev) +{ + return 0; +} + +static const struct udevice_id lg4573_ids[] = { + { .compatible = "lg,lg4573" }, + { } +}; + +struct lg4573_lcd_priv { + struct display_timing timing; + struct udevice *backlight; + struct gpio_desc enable; + int panel_bpp; + u32 power_on_delay; +}; + +static int lg4573_lcd_read_timing(struct udevice *dev, + struct display_timing *timing) +{ + struct lg4573_lcd_priv *priv = dev_get_priv(dev); + + memcpy(timing, &priv->timing, sizeof(struct display_timing)); + + return 0; +} + +static int lg4573_lcd_enable(struct udevice *dev, int bpp, + const struct display_timing *edid) +{ + struct spi_slave *slave = dev_get_parent_priv(dev); + struct lg4573_lcd_priv *priv = dev_get_priv(dev); + int ret = 0; + + dm_gpio_set_value(&priv->enable, 1); + ret = backlight_enable(priv->backlight); + + mdelay(priv->power_on_delay); + lg4573_spi_startup(slave); + + return ret; +}; + +static const struct dm_display_ops lg4573_lcd_ops = { + .read_timing = lg4573_lcd_read_timing, + .enable = lg4573_lcd_enable, +}; + +static int lg4573_ofdata_to_platdata(struct udevice *dev) +{ + struct lg4573_lcd_priv *priv = dev_get_priv(dev); + int ret; + + ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, + "backlight", &priv->backlight); + if (ret) { + debug("%s: Cannot get backlight: ret=%d\n", __func__, ret); + return log_ret(ret); + } + ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable, + GPIOD_IS_OUT); + if (ret) { + debug("%s: Warning: cannot get enable GPIO: ret=%d\n", + __func__, ret); + if (ret != -ENOENT) + return log_ret(ret); + } + + priv->power_on_delay = dev_read_u32_default(dev, "power-on-delay", 10); + + return 0; +} + +U_BOOT_DRIVER(lg4573_lcd) = { + .name = "lg4573", + .id = UCLASS_DISPLAY, + .ops = &lg4573_lcd_ops, + .ofdata_to_platdata = lg4573_ofdata_to_platdata, + .of_match = lg4573_ids, + .bind = lg4573_bind, + .probe = lg4573_probe, + .priv_auto_alloc_size = sizeof(struct lg4573_lcd_priv), +}; diff --git a/drivers/video/meson/meson_canvas.c b/drivers/video/meson/meson_canvas.c index b71cbfcc0b0..eccac2f8f24 100644 --- a/drivers/video/meson/meson_canvas.c +++ b/drivers/video/meson/meson_canvas.c @@ -6,6 +6,10 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ +#include <common.h> +#include <dm.h> +#include <asm/io.h> + #include "meson_vpu.h" /* DMC Registers */ diff --git a/drivers/video/meson/meson_plane.c b/drivers/video/meson/meson_plane.c index 2bc9327e1e2..8edf451f13f 100644 --- a/drivers/video/meson/meson_plane.c +++ b/drivers/video/meson/meson_plane.c @@ -6,6 +6,11 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <linux/bitfield.h> + #include "meson_vpu.h" /* OSDx_BLKx_CFG */ diff --git a/drivers/video/meson/meson_vclk.c b/drivers/video/meson/meson_vclk.c index 0f628e920ba..01bfa4bcb8d 100644 --- a/drivers/video/meson/meson_vclk.c +++ b/drivers/video/meson/meson_vclk.c @@ -6,6 +6,8 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ +#include <common.h> +#include <dm.h> #include <edid.h> #include "meson_vpu.h" #include <linux/iopoll.h> diff --git a/drivers/video/meson/meson_venc.c b/drivers/video/meson/meson_venc.c index 5da4b3f0963..89e859b02a7 100644 --- a/drivers/video/meson/meson_venc.c +++ b/drivers/video/meson/meson_venc.c @@ -6,7 +6,11 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ +#include <common.h> +#include <dm.h> #include <edid.h> +#include <fdtdec.h> +#include <asm/io.h> #include "meson_vpu.h" enum { diff --git a/drivers/video/meson/meson_vpu.c b/drivers/video/meson/meson_vpu.c index c3af9b013c6..4eb66398d09 100644 --- a/drivers/video/meson/meson_vpu.c +++ b/drivers/video/meson/meson_vpu.c @@ -6,13 +6,17 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ -#include "meson_vpu.h" +#include <common.h> +#include <display.h> +#include <dm.h> #include <efi_loader.h> -#include <dm/device-internal.h> -#include <dm/uclass-internal.h> #include <fdt_support.h> #include <linux/sizes.h> #include <asm/arch/mem.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> + +#include "meson_vpu.h" #include "meson_registers.h" #include "simplefb_common.h" @@ -27,6 +31,14 @@ static struct meson_framebuffer { bool is_cvbs; } meson_fb = { 0 }; +bool meson_vpu_is_compatible(struct meson_vpu_priv *priv, + enum vpu_compatible family) +{ + enum vpu_compatible compat = dev_get_driver_data(priv->dev); + + return compat == family; +} + static int meson_vpu_setup_mode(struct udevice *dev, struct udevice *disp) { struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); diff --git a/drivers/video/meson/meson_vpu.h b/drivers/video/meson/meson_vpu.h index 0d9fddad2e7..d9588c3775c 100644 --- a/drivers/video/meson/meson_vpu.h +++ b/drivers/video/meson/meson_vpu.h @@ -9,14 +9,12 @@ #ifndef __MESON_VPU_H__ #define __MESON_VPU_H__ -#include <common.h> -#include <dm.h> #include <video.h> -#include <display.h> -#include <linux/io.h> -#include <linux/bitfield.h> #include "meson_registers.h" +struct display_timing; +struct udevice; + enum { /* Maximum size we support */ VPU_MAX_WIDTH = 3840, @@ -38,13 +36,8 @@ struct meson_vpu_priv { void __iomem *dmc_base; }; -static inline bool meson_vpu_is_compatible(struct meson_vpu_priv *priv, - enum vpu_compatible family) -{ - enum vpu_compatible compat = dev_get_driver_data(priv->dev); - - return compat == family; -} +bool meson_vpu_is_compatible(struct meson_vpu_priv *priv, + enum vpu_compatible family); #define hhi_update_bits(offset, mask, value) \ writel_bits(mask, value, priv->hhi_base + offset) diff --git a/drivers/video/meson/meson_vpu_init.c b/drivers/video/meson/meson_vpu_init.c index 12f8c4194ad..8408c59eaa1 100644 --- a/drivers/video/meson/meson_vpu_init.c +++ b/drivers/video/meson/meson_vpu_init.c @@ -8,6 +8,10 @@ #define DEBUG +#include <common.h> +#include <dm.h> +#include <asm/io.h> + #include "meson_vpu.h" /* HHI Registers */ |