U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
October 2021
- 190 participants
- 666 discussions
This patchset adds the support for following:
1) CAAM Driver model for all i.MX, layerscape, PPC platforms.
2) Added crypto node in device tree files.
3) CAAM support for blob key encryption key(bkek), random number generation.
4) fix build issue for mx6sabre: Remove SPL DTB related configs and SPL_OF_CONTROL.
5) fixed hwrng performance issue in kernel.
i.MX platforms:
i.MX6, i.MX7, i.MX7ULP, i.MX8MM/MN/MP/MQ, i.MX8QM/QXP
Layerscape platforms:
LS1021, LS1012, LS1028, LS1043, LS1046, LS1088, LS2088, LX2160, LX2162
Powerpc platforms:
P3041, P4080, P5040, P2041, T1024, T1042, T2080, T4240
changes since v3:
- rebase to latest master
- fixed build error when new file arch/powerpc/include/asm/u-boot-ppc.h is
included from assembly files.
- removed arch/arm/dts/fsl-ls1028a.dtsi as it is conflicting with the series
https://lore.kernel.org/u-boot/20211013161427.612033-1-michael@walle.cc/
Gaurav Jain (14):
crypto/fsl: Add support for CAAM Job ring driver model
crypto/fsl: Add CAAM support for bkek, random number generation
i.MX8M: crypto: updated device tree for supporting DM in SPL
crypto/fsl: i.MX8M: Enable Job ring driver model in SPL and U-Boot.
i.MX6: Enable Job ring driver model in U-Boot.
i.MX7: Enable Job ring driver model in U-Boot.
i.MX7ULP: Enable Job ring driver model in U-Boot.
i.MX8: Add crypto node in device tree
crypto/fsl: i.MX8: Enable Job ring driver model in SPL and U-Boot.
Layerscape: Add crypto node in device tree
Layerscape: Enable Job ring driver model in U-Boot.
PPC: Add crypto node in device tree
PPC: Enable Job ring driver model in U-Boot
update CAAM MAINTAINER
Ye Li (2):
mx6sabre: Remove unnecessary SPL configs
crypto/fsl: Fix kick_trng
MAINTAINERS | 7 +
arch/arm/Kconfig | 9 +-
arch/arm/cpu/armv7/ls102xa/Kconfig | 4 +
arch/arm/cpu/armv7/ls102xa/cpu.c | 16 +
arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 27 +
arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 10 +-
arch/arm/dts/fsl-imx8dx.dtsi | 61 ++-
arch/arm/dts/fsl-imx8qm-mek-u-boot.dtsi | 34 +-
arch/arm/dts/fsl-imx8qm.dtsi | 61 ++-
arch/arm/dts/fsl-imx8qxp-mek-u-boot.dtsi | 34 +-
arch/arm/dts/fsl-ls1012a.dtsi | 46 +-
arch/arm/dts/fsl-ls1043a.dtsi | 45 +-
arch/arm/dts/fsl-ls1046a.dtsi | 44 ++
arch/arm/dts/fsl-ls1088a.dtsi | 39 ++
arch/arm/dts/fsl-ls2080a.dtsi | 39 ++
arch/arm/dts/fsl-lx2160a.dtsi | 41 +-
arch/arm/dts/imx7ulp.dtsi | 24 +
arch/arm/dts/imx8mm-evk-u-boot.dtsi | 18 +-
arch/arm/dts/imx8mm.dtsi | 1 +
arch/arm/dts/imx8mn-ddr4-evk-u-boot.dtsi | 18 +-
arch/arm/dts/imx8mn.dtsi | 1 +
arch/arm/dts/imx8mp-evk-u-boot.dtsi | 18 +-
arch/arm/dts/imx8mp.dtsi | 1 +
arch/arm/dts/imx8mq.dtsi | 1 +
arch/arm/dts/ls1021a.dtsi | 40 ++
arch/arm/include/asm/arch-imx8/imx-regs.h | 5 +-
arch/arm/include/asm/arch-imx8m/imx-regs.h | 1 +
arch/arm/mach-imx/cmd_dek.c | 1 +
arch/arm/mach-imx/imx8/Kconfig | 9 +
arch/arm/mach-imx/imx8/cpu.c | 16 +-
arch/arm/mach-imx/imx8m/Kconfig | 23 +
arch/arm/mach-imx/imx8m/soc.c | 10 +-
arch/arm/mach-imx/mx6/Kconfig | 20 +
arch/arm/mach-imx/mx6/soc.c | 12 +-
arch/arm/mach-imx/mx7/Kconfig | 3 +
arch/arm/mach-imx/mx7/soc.c | 11 +-
arch/arm/mach-imx/mx7ulp/Kconfig | 4 +
arch/arm/mach-imx/mx7ulp/soc.c | 16 +
arch/powerpc/cpu/mpc85xx/Kconfig | 44 ++
arch/powerpc/cpu/mpc85xx/cpu_init.c | 17 +-
arch/powerpc/dts/p2041si-post.dtsi | 1 +
arch/powerpc/dts/p3041si-post.dtsi | 1 +
arch/powerpc/dts/p4080si-post.dtsi | 1 +
arch/powerpc/dts/p5040si-post.dtsi | 1 +
arch/powerpc/dts/qoriq-sec4.0-0.dtsi | 74 +++
arch/powerpc/dts/qoriq-sec4.2-0.dtsi | 83 ++++
arch/powerpc/dts/qoriq-sec5.2-0.dtsi | 92 ++++
arch/powerpc/dts/t1023si-post.dtsi | 1 +
arch/powerpc/dts/t1042si-post.dtsi | 1 +
arch/powerpc/dts/t2080si-post.dtsi | 1 +
arch/powerpc/dts/t4240si-post.dtsi | 1 +
arch/powerpc/include/asm/u-boot-ppc.h | 17 +
arch/powerpc/include/asm/u-boot.h | 1 +
board/freescale/imx8mm_evk/spl.c | 9 +-
board/freescale/imx8mn_evk/spl.c | 8 +-
board/freescale/imx8mp_evk/spl.c | 13 +-
board/freescale/imx8mq_evk/spl.c | 9 +-
board/freescale/imx8qm_mek/spl.c | 6 +-
board/freescale/imx8qxp_mek/spl.c | 6 +-
board/freescale/ls1012afrdm/ls1012afrdm.c | 7 +-
board/freescale/ls1012aqds/ls1012aqds.c | 6 +-
board/freescale/ls1012ardb/ls1012ardb.c | 6 +-
board/freescale/ls1021aiot/ls1021aiot.c | 6 +-
board/freescale/ls1021aqds/ls1021aqds.c | 6 +-
board/freescale/ls1021atsn/ls1021atsn.c | 7 +-
board/freescale/ls1021atwr/ls1021atwr.c | 8 +-
board/freescale/ls1028a/ls1028a.c | 6 +-
board/freescale/ls1043ardb/ls1043ardb.c | 6 +-
board/freescale/ls1046afrwy/ls1046afrwy.c | 7 +-
board/freescale/ls1046aqds/ls1046aqds.c | 7 +-
board/freescale/ls1046ardb/ls1046ardb.c | 6 +-
board/freescale/ls1088a/ls1088a.c | 6 +-
board/freescale/ls2080aqds/ls2080aqds.c | 6 +-
board/freescale/ls2080ardb/ls2080ardb.c | 9 +-
board/freescale/lx2160a/lx2160a.c | 5 -
cmd/Kconfig | 1 +
configs/P2041RDB_defconfig | 1 -
configs/P3041DS_defconfig | 1 -
configs/P4080DS_defconfig | 1 -
configs/P5040DS_defconfig | 1 -
configs/T1024RDB_defconfig | 1 -
configs/T1042D4RDB_defconfig | 1 -
configs/T2080QDS_defconfig | 1 -
configs/T2080RDB_defconfig | 1 -
configs/T4240RDB_defconfig | 1 -
configs/ls1021aiot_qspi_defconfig | 1 -
configs/ls1021aqds_nor_defconfig | 1 -
configs/ls1021aqds_qspi_defconfig | 1 -
configs/ls1021atsn_qspi_defconfig | 1 -
configs/ls1021atwr_nor_defconfig | 1 -
...s1021atwr_sdcard_ifc_SECURE_BOOT_defconfig | 1 +
configs/ls1028ardb_tfa_defconfig | 1 -
configs/ls1043ardb_tfa_defconfig | 1 -
configs/ls1046afrwy_tfa_defconfig | 1 -
configs/ls1046aqds_tfa_defconfig | 1 -
configs/ls1046ardb_tfa_defconfig | 1 -
configs/ls2088aqds_tfa_defconfig | 1 -
configs/ls2088ardb_tfa_defconfig | 1 -
configs/lx2160aqds_tfa_defconfig | 1 -
configs/lx2160ardb_tfa_defconfig | 1 -
configs/lx2162aqds_tfa_defconfig | 1 -
configs/mx6sabreauto_defconfig | 2 -
configs/mx6sabresd_defconfig | 4 -
drivers/crypto/fsl/Kconfig | 9 +-
drivers/crypto/fsl/Makefile | 4 +-
drivers/crypto/fsl/desc.h | 5 +
drivers/crypto/fsl/fsl_blob.c | 82 ++++
drivers/crypto/fsl/jobdesc.c | 20 +-
drivers/crypto/fsl/jobdesc.h | 4 +
drivers/crypto/fsl/jr.c | 461 +++++++++++++-----
drivers/crypto/fsl/jr.h | 14 +
include/fsl_sec.h | 13 +-
scripts/config_whitelist.txt | 1 +
113 files changed, 1614 insertions(+), 292 deletions(-)
create mode 100644 arch/powerpc/dts/qoriq-sec4.0-0.dtsi
create mode 100644 arch/powerpc/dts/qoriq-sec4.2-0.dtsi
create mode 100644 arch/powerpc/dts/qoriq-sec5.2-0.dtsi
create mode 100644 arch/powerpc/include/asm/u-boot-ppc.h
--
2.17.1
5
32

[RFC 00/22] efi_loader: more tightly integrate UEFI disks to device model
by AKASHI Takahiro 06 Dec '21
by AKASHI Takahiro 06 Dec '21
06 Dec '21
The purpose of this RPC is to reignite the discussion about how UEFI
subystem would best be integrated into U-Boot device model.
In the past, I poposed a couple of patch series, the latest one[1],
while Heinrich revealed his idea[2], and the approach taken here is
something between them, with a focus on block device handlings.
# The code is a PoC and not well tested yet.
Disks in UEFI world:
====================
In general in UEFI world, accessing to any device is performed through
a 'protocol' interface which are installed to (or associated with) the device's
UEFI handle (or an opaque pointer to UEFI object data). Protocols are
implemented by either the UEFI system itself or UEFI drivers.
For block IO's, it is a device which has EFI_BLOCK_IO_PROTOCOL (efi_disk
hereafter). Currently, every efi_disk may have one of two origins:
a.U-Boot's block devices or related partitions
(lib/efi_loader/efi_disk.c)
b.UEFI objects which are implemented as a block device by UEFI drivers.
(lib/efi_driver/efi_block_device.c)
All the efi_diskss as (a) will be enumelated and created only once at UEFI
subsystem initialization (efi_disk_register()), which is triggered by
first executing one of UEFI-related U-Boot commands, like "bootefi",
"setenv -e" or "efidebug".
EFI_BLOCK_IO_PROTOCOL is implemented by UEFI system using blk_desc(->ops)
in the corresponding udevice(UCLASS_BLK).
On the other hand, efi_disk as (b) will be created each time UEFI boot
services' connect_controller() is executed in UEFI app which, as a (device)
controller, gives the method to access the device's data,
ie. EFI_BLOCK_IO_PROTOCOL.
>>> more details >>>
Internally, connect_controller() search for UEFI driver that can support
this controller/protocol, 'efi_block' driver(UCLASS_EFI) in this case,
then calls the driver's 'bind' interface, which eventually installs
the controller's EFI_BLOCK_IO_PROTOCOL to efi_disk object.
'efi_block' driver also create a corresponding udevice(UCLASS_BLK) for
* creating additional partitions efi_disk's, and
* supporting a file system (EFI_SIMPLE_FILE_SYSTEM_PROTOCOL) on it.
<<< <<<
Issues:
=======
1. While an efi_disk represents a device equally for either a whole disk
or a partition in UEFI world, the device model treats only a whole
disk as a real block device or udevice(UCLASS_BLK).
2. efi_disk holds and makes use of "blk_desc" data even though blk_desc
in plat_data is supposed to be private and not to be accessed outside
the device model.
# This issue, though, exists for all the implmenetation of U-Boot
# file systems as well.
For efi_disk(a),
3. A block device can be enumelated dynamically by 'scanning' a device bus
in U-Boot, but UEFI subsystem is not able to update efi_disks accordingly.
For examples,
=> scsi rescan; efidebug devices
=> usb start; efidebug devices ... (A)
(A) doesn't show any usb devices detected.
=> scsi rescan; efidebug boot add -b 0 TEST scsi 0:1 ...
=> scsi rescan ... (B)
=> bootefi bootmgr ... (C)
(C) may de-reference a bogus blk_desc pointer which has been freed by (B).
(Please note that "scsi rescan" removes all udevices/blk_desc and then
re-create them even if nothing is changed on a bus.)
For efi_disk(b),
4. A controller (handle), combined with efi_block driver, has no
corresponding udevice as a parent of efi_disks in DM tree, unlike, say,
a scsi controller, even though it provides methods for block io perations.
5. There is no way supported to remove efi_disk's even after
disconnect_controller() is called.
My approach in this RFC:
========================
Due to functional differences in semantics, it would be difficult
to identify "udevice" structure as a handle in UEFI world. Instead, we will
have to somehow maintain a relationship between a udevice and a handle.
1-1. add a dedicated uclass, UCLASS_PARTITION, for partitions
Currently, the uclass for paritions is not a UCLASS_BLK.
It can be possible to define partitions as UCLASS_BLK
(with IF_TYPE_PARTION?), but
I'm afraid that it may introduce some chaos since udevice(UCLASS_BLK)
is tightly coupled with 'struct blk_desc' data which is still used
as a "structure to a whole disk" in a lot of interfaces.
(I hope that you understand what it means.)
In DM tree, a UCLASS_PARTITON instance has a UCLASS_BLK parent:
For instance,
UCLASS_SCSI --- UCLASS_BLK --- UCLASS_PARTITION
(IF_TYPE_SCSI) |
+- struct blk_desc +- struct disk_part
+- scsi_blk_ops +- blk_part_ops
1-2. create partition udevices in the context of device_probe()
part_init() is already called in blk_post_probe(). See the commit
d0851c893706 ("blk: Call part_init() in the post_probe() method").
Why not enumelate partitions as well in there.
2. add new block access interfaces, which takes "udevice" as a target device,
in U-Boot and use those functions to implement efi_disk operations
(i.e. EFI_BLOCK_IO_PROTOCOL).
3-1. maintain a bi-directional link by adding
- a UEFI handle pointer in "struct udevice"
- a udevice pointer in UEFI handle (in fact, in "struct efi_disk_obj")
3-2. use device model's post_probe/pre_remove hook to synchronize the lifetime
of efi_disk objects in UEFI world with the device model.
4. I have no answer to issue(4) and (5) yet.
Patchs:
=======
For easy understandings, patches may be categorized into seperate groups
of changes.
Patch#1-#9: DM: create udevices for partitions
Patch#11,#12: UEFI: use udevice interfaces
Patch#13-#16: UEFI: sync up with the device model for adding
Patch#17-#19: UEFI: sync up with the device model for removing
For removal case, we may need more consideration since removing handles
unconditionally may end up breaking integrity of handles
(some may still be held and referenced to by a UEFI app).
Patch#20-#22: UEFI: align efi_driver with changes by the integration
[1] https://lists.denx.de/pipermail/u-boot/2019-February/357923.html
[2] https://lists.denx.de/pipermail/u-boot/2021-June/452297.html
AKASHI Takahiro (22):
scsi: call device_probe() after scanning
usb: storage: call device_probe() after scanning
mmc: call device_probe() after scanning
nvme: call device_probe() after scanning
sata: call device_probe() after scanning
block: ide: call device_probe() after scanning
dm: blk: add UCLASS_PARTITION
dm: blk: add a device-probe hook for scanning disk partitions
dm: blk: add read/write interfaces with udevice
efi_loader: disk: use udevice instead of blk_desc
dm: add a hidden link to efi object
efi_loader: remove !CONFIG_BLK code from efi_disk
efi_loader: disk: a helper function to create efi_disk objects from
udevice
dm: blk: call efi's device-probe hook
efi_loader: cleanup after efi_disk-dm integration
efi_loader: add efi_remove_handle()
efi_loader: efi_disk: a helper function to delete efi_disk objects
dm: blk: call efi's device-removal hook
efi_driver: align with efi_disk-dm integration
efi_driver: cleanup after efi_disk-dm integration
efi_selftest: block device: adjust dp for a test disk
(TEST) let dm-tree unchanged after block_io testing is done
common/usb_storage.c | 6 +
drivers/ata/dwc_ahsata.c | 10 +
drivers/ata/fsl_sata.c | 11 +
drivers/ata/sata_mv.c | 9 +
drivers/ata/sata_sil.c | 12 +
drivers/block/blk-uclass.c | 249 ++++++++++++++++
drivers/block/ide.c | 6 +
drivers/mmc/mmc-uclass.c | 7 +
drivers/nvme/nvme.c | 6 +
drivers/scsi/scsi.c | 10 +
include/blk.h | 15 +
include/dm/device.h | 4 +
include/dm/uclass-id.h | 1 +
include/efi_loader.h | 8 +-
lib/efi_driver/efi_block_device.c | 30 +-
lib/efi_loader/efi_boottime.c | 8 +
lib/efi_loader/efi_device_path.c | 29 ++
lib/efi_loader/efi_disk.c | 286 ++++++++++---------
lib/efi_loader/efi_setup.c | 5 -
lib/efi_selftest/efi_selftest_block_device.c | 28 +-
20 files changed, 566 insertions(+), 174 deletions(-)
--
2.33.0
6
156
Set the SF page size, erase block size and total size as an environment
variable after "sf probe". This lets us discern boards with multiple
distinct SPI flash options and also e.g. set mtdparts accordingly.
Signed-off-by: Marek Vasut <marex(a)denx.de>
Cc: Jagan Teki <jagan(a)amarulasolutions.com>
Cc: Vignesh R <vigneshr(a)ti.com>
---
drivers/mtd/spi/spi-nor-core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index d5d905fa5a1..448653b9931 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -15,6 +15,7 @@
#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
+#include <env.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -3829,8 +3830,11 @@ int spi_nor_scan(struct spi_nor *nor)
#ifndef CONFIG_SPL_BUILD
printf("SF: Detected %s with page size ", nor->name);
print_size(nor->page_size, ", erase size ");
+ env_set_hex("sf_pagesize", nor->page_size);
print_size(nor->erase_size, ", total ");
+ env_set_hex("sf_erasesize", nor->erase_size);
print_size(nor->size, "");
+ env_set_hex("sf_size", nor->size);
puts("\n");
#endif
--
2.33.0
4
11
When, for various reasons, a bad FIT image is used where a loadable
image is marked as 0 length, attempt is made for a 0 length allocation and
read of 0 byte read operation.
Instead provide warning in log and skip attempting to do such a load.
Signed-off-by: Nishanth Menon <nm(a)ti.com>
---
common/spl/spl_fit.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index f41abca0ccb5..e9540dc2167a 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -286,6 +286,13 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
if (fit_image_get_data_size(fit, node, &len))
return -ENOENT;
+ /* Dont bother to copy 0 byte data, but warn, though */
+ if (!len) {
+ log_warning("%s: Skip load '%s': image size is 0!\n",
+ __func__, fit_get_name(fit, node, NULL));
+ return 0;
+ }
+
src_ptr = map_sysmem(ALIGN(load_addr, ARCH_DMA_MINALIGN), len);
length = len;
--
2.32.0
3
2
Wait for the read/write transfer finish bit get actually cleared,
this does not happen immediately on at least SoCFPGA Gen5.
Signed-off-by: Marek Vasut <marex(a)denx.de>
Cc: Jagan Teki <jagan(a)amarulasolutions.com>
Cc: Vignesh R <vigneshr(a)ti.com>
Cc: Pratyush Yadav <p.yadav(a)ti.com>
---
drivers/spi/cadence_qspi_apb.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index 429ee335db6..2cdf4c9c9f8 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -858,6 +858,14 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat,
writel(CQSPI_REG_INDIRECTRD_DONE,
plat->regbase + CQSPI_REG_INDIRECTRD);
+ /* Check indirect done status */
+ ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTRD,
+ CQSPI_REG_INDIRECTRD_DONE, 0, 10, 0);
+ if (ret) {
+ printf("Indirect read clear completion error (%i)\n", ret);
+ goto failrd;
+ }
+
return 0;
failrd:
@@ -1012,6 +1020,15 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat,
/* Clear indirect completion status */
writel(CQSPI_REG_INDIRECTWR_DONE,
plat->regbase + CQSPI_REG_INDIRECTWR);
+
+ /* Check indirect done status */
+ ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTWR,
+ CQSPI_REG_INDIRECTWR_DONE, 0, 10, 0);
+ if (ret) {
+ printf("Indirect write clear completion error (%i)\n", ret);
+ goto failwr;
+ }
+
if (bounce_buf)
free(bounce_buf);
return 0;
--
2.33.0
3
12
This change contains update for doc/README.nokia_rx51 documentation file
with information how to load U-Boot image to device RAM without need to
flash it and also how to flash it into OneNAND via 0xFFFF flasher.
Signed-off-by: Pali Rohár <pali(a)kernel.org>
---
doc/README.nokia_rx51 | 45 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/doc/README.nokia_rx51 b/doc/README.nokia_rx51
index 1be077514f03..e739b02088ea 100644
--- a/doc/README.nokia_rx51
+++ b/doc/README.nokia_rx51
@@ -22,6 +22,51 @@ following repository:
https://github.com/pali/u-boot-maemo
+To generate combined.bin image from u-boot.bin and kernel.bin (either uImage
+or zImage) use:
+
+ sh u-boot-gen-combined u-boot.bin kernel.bin combined.bin
+
+Original Maemo Fremantle PR1.3 zImage kernel binary is available at:
+
+ http://repository.maemo.org/pool/maemo5.0/free/k/kernel/kernel_2.6.28-20103…
+
+To unpack it (from DEB/AR, TAR and FIASCO) call commands:
+
+ ar x kernel_2.6.28-20103103+0m5_armel.deb data.tar.gz
+ tar -O -xf data.tar.gz ./boot/zImage-2.6.28-20103103+0m5.fiasco > kernel_2.6.28-20103103+0m5.fiasco
+ 0xFFFF -M kernel_2.6.28-20103103+0m5.fiasco -u
+
+Flashed image must start with 2 kB "NOLO!img" header which contains size of
+the image. Header consist of bytes "NOLO!img\x02\x00\x00\x00\x00\x00\x00\x00"
+followed by 4 byte little endian size of the image and rest of the 2 kB header
+are just zero bytes.
+
+Nokia proprietary flasher and also open source 0xFFFF flasher automatically
+prepend required "NOLO!img" header and both applications expect that image
+does not contain "NOLO!img" header. Adding "NOLO!img" header is required
+only in case using "nandwrite" tool for flashing.
+
+Open source 0xFFFF flasher is available in following repository:
+
+ https://github.com/pali/0xFFFF
+
+It is possible to load u-boot.bin via USB to N900 RAM and boot it without
+need to flashing it. Via 0xFFFF running at host PC it is done:
+
+ 0xFFFF -m u-boot.bin -l -b
+
+0xFFFF support also flashing kernel image either via USB or directly on
+N900 device. Flashing u-boot/kernel/combined image is done as:
+
+ 0xFFFF -m combined.bin -f
+
+Via 0xFFFF is possible to generate also standard flashable image in Nokia
+FIASCO format which contains metadata information like device identification
+(RX-51) and version string (v2021.04):
+
+ 0xFFFF -m RX-51:v2021.04:kernel:u-boot.bin -g u-boot.fiasco
+
There is support for hardware watchdog. Hardware watchdog is started by
NOLO so u-boot must kick watchdog to prevent reboot device (but not very
often, max every 2 seconds). There is also support for framebuffer display
--
2.20.1
2
2

01 Dec '21
The driver is based on the Versaclock driver from the Linux code, but
due differences in the clock API between them, some pieces had to be
changed.
This driver creates a mux, pfd, pll, and a series of fod ouputs.
Rate Usecnt Name
------------------------------------------
25000000 0 `-- x304-clock
25000000 0 `-- clock-controller(a)6a.mux
25000000 0 |-- clock-controller(a)6a.pfd
2800000000 0 | `-- clock-controller(a)6a.pll
33333333 0 | |-- clock-controller(a)6a.fod0
33333333 0 | | `-- clock-controller(a)6a.out1
33333333 0 | |-- clock-controller(a)6a.fod1
33333333 0 | | `-- clock-controller(a)6a.out2
50000000 0 | |-- clock-controller(a)6a.fod2
50000000 0 | | `-- clock-controller(a)6a.out3
125000000 0 | `-- clock-controller(a)6a.fod3
125000000 0 | `-- clock-controller(a)6a.out4
25000000 0 `-- clock-controller(a)6a.out0_sel_i2cb
A translation function is added so the references to <&versaclock X> get routed
to the corresponding clock-controller(a)6a.outX.
Signed-off-by: Adam Ford <aford173(a)gmail.com>
---
V4: Remove a few printf's that I missed when removing debug.
V3: Streamline finding the out OUTx subnodes.
Add error handling.
Replace printf and pr_err with dev_dbg.
Restore registers removed in V2.
V2: Remove unused registers.
Fix spacing in Makefile.
Make the versaclock driver dependent on CCF.
Move the versaclock_ids next to U_BOOT_DRIVER(versaclock)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 40a5a5dd88..2a7507ea18 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -197,4 +197,13 @@ config SANDBOX_CLK_CCF
Enable this option if you want to test the Linux kernel's Common
Clock Framework [CCF] code in U-Boot's Sandbox clock driver.
+config CLK_VERSACLOCK
+ tristate "Enable VersaClock 5/6 devices"
+ depends on CLK
+ depends on CLK_CCF
+ depends on OF_CONTROL
+ help
+ This driver supports the IDT VersaClock 5 and VersaClock 6
+ programmable clock generators.
+
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 645709b855..6f5ddafd64 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
obj-$(CONFIG_STM32H7) += clk_stm32h7.o
obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o
+obj-$(CONFIG_CLK_VERSACLOCK) += clk_versaclock.o
diff --git a/drivers/clk/clk_versaclock.c b/drivers/clk/clk_versaclock.c
new file mode 100644
index 0000000000..578668bcf8
--- /dev/null
+++ b/drivers/clk/clk_versaclock.c
@@ -0,0 +1,1100 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for IDT Versaclock 5/6
+ *
+ * Derived from code Copyright (C) 2017 Marek Vasut <marek.vasut(a)gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <dm/device_compat.h>
+#include <log.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+
+#include <dt-bindings/clk/versaclock.h>
+
+/* VersaClock5 registers */
+#define VC5_OTP_CONTROL 0x00
+
+/* Factory-reserved register block */
+#define VC5_RSVD_DEVICE_ID 0x01
+#define VC5_RSVD_ADC_GAIN_7_0 0x02
+#define VC5_RSVD_ADC_GAIN_15_8 0x03
+#define VC5_RSVD_ADC_OFFSET_7_0 0x04
+#define VC5_RSVD_ADC_OFFSET_15_8 0x05
+#define VC5_RSVD_TEMPY 0x06
+#define VC5_RSVD_OFFSET_TBIN 0x07
+#define VC5_RSVD_GAIN 0x08
+#define VC5_RSVD_TEST_NP 0x09
+#define VC5_RSVD_UNUSED 0x0a
+#define VC5_RSVD_BANDGAP_TRIM_UP 0x0b
+#define VC5_RSVD_BANDGAP_TRIM_DN 0x0c
+#define VC5_RSVD_CLK_R_12_CLK_AMP_4 0x0d
+#define VC5_RSVD_CLK_R_34_CLK_AMP_4 0x0e
+#define VC5_RSVD_CLK_AMP_123 0x0f
+
+/* Configuration register block */
+#define VC5_PRIM_SRC_SHDN 0x10
+#define VC5_PRIM_SRC_SHDN_EN_XTAL BIT(7)
+#define VC5_PRIM_SRC_SHDN_EN_CLKIN BIT(6)
+#define VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ BIT(3)
+#define VC5_PRIM_SRC_SHDN_SP BIT(1)
+#define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN BIT(0)
+
+#define VC5_VCO_BAND 0x11
+#define VC5_XTAL_X1_LOAD_CAP 0x12
+#define VC5_XTAL_X2_LOAD_CAP 0x13
+#define VC5_REF_DIVIDER 0x15
+#define VC5_REF_DIVIDER_SEL_PREDIV2 BIT(7)
+#define VC5_REF_DIVIDER_REF_DIV(n) ((n) & 0x3f)
+
+#define VC5_VCO_CTRL_AND_PREDIV 0x16
+#define VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV BIT(7)
+
+#define VC5_FEEDBACK_INT_DIV 0x17
+#define VC5_FEEDBACK_INT_DIV_BITS 0x18
+#define VC5_FEEDBACK_FRAC_DIV(n) (0x19 + (n))
+#define VC5_RC_CONTROL0 0x1e
+#define VC5_RC_CONTROL1 0x1f
+/* Register 0x20 is factory reserved */
+
+/* Output divider control for divider 1,2,3,4 */
+#define VC5_OUT_DIV_CONTROL(idx) (0x21 + ((idx) * 0x10))
+#define VC5_OUT_DIV_CONTROL_RESET BIT(7)
+#define VC5_OUT_DIV_CONTROL_SELB_NORM BIT(3)
+#define VC5_OUT_DIV_CONTROL_SEL_EXT BIT(2)
+#define VC5_OUT_DIV_CONTROL_INT_MODE BIT(1)
+#define VC5_OUT_DIV_CONTROL_EN_FOD BIT(0)
+
+#define VC5_OUT_DIV_FRAC(idx, n) (0x22 + ((idx) * 0x10) + (n))
+#define VC5_OUT_DIV_FRAC4_OD_SCEE BIT(1)
+
+#define VC5_OUT_DIV_STEP_SPREAD(idx, n) (0x26 + ((idx) * 0x10) + (n))
+#define VC5_OUT_DIV_SPREAD_MOD(idx, n) (0x29 + ((idx) * 0x10) + (n))
+#define VC5_OUT_DIV_SKEW_INT(idx, n) (0x2b + ((idx) * 0x10) + (n))
+#define VC5_OUT_DIV_INT(idx, n) (0x2d + ((idx) * 0x10) + (n))
+#define VC5_OUT_DIV_SKEW_FRAC(idx) (0x2f + ((idx) * 0x10))
+/* Registers 0x30, 0x40, 0x50 are factory reserved */
+
+/* Clock control register for clock 1,2 */
+#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
+#define VC5_CLK_OUTPUT_CFG0_CFG_SHIFT 5
+#define VC5_CLK_OUTPUT_CFG0_CFG_MASK GENMASK(7, VC5_CLK_OUTPUT_CFG0_CFG_SHIFT)
+
+#define VC5_CLK_OUTPUT_CFG0_CFG_LVPECL (VC5_LVPECL)
+#define VC5_CLK_OUTPUT_CFG0_CFG_CMOS (VC5_CMOS)
+#define VC5_CLK_OUTPUT_CFG0_CFG_HCSL33 (VC5_HCSL33)
+#define VC5_CLK_OUTPUT_CFG0_CFG_LVDS (VC5_LVDS)
+#define VC5_CLK_OUTPUT_CFG0_CFG_CMOS2 (VC5_CMOS2)
+#define VC5_CLK_OUTPUT_CFG0_CFG_CMOSD (VC5_CMOSD)
+#define VC5_CLK_OUTPUT_CFG0_CFG_HCSL25 (VC5_HCSL25)
+
+#define VC5_CLK_OUTPUT_CFG0_PWR_SHIFT 3
+#define VC5_CLK_OUTPUT_CFG0_PWR_MASK GENMASK(4, VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
+#define VC5_CLK_OUTPUT_CFG0_PWR_18 (0 << VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
+#define VC5_CLK_OUTPUT_CFG0_PWR_25 (2 << VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
+#define VC5_CLK_OUTPUT_CFG0_PWR_33 (3 << VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
+#define VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT 0
+#define VC5_CLK_OUTPUT_CFG0_SLEW_MASK GENMASK(1, VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
+#define VC5_CLK_OUTPUT_CFG0_SLEW_80 (0 << VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
+#define VC5_CLK_OUTPUT_CFG0_SLEW_85 (1 << VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
+#define VC5_CLK_OUTPUT_CFG0_SLEW_90 (2 << VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
+#define VC5_CLK_OUTPUT_CFG0_SLEW_100 (3 << VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
+#define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0)
+
+#define VC5_CLK_OE_SHDN 0x68
+#define VC5_CLK_OS_SHDN 0x69
+
+#define VC5_GLOBAL_REGISTER 0x76
+#define VC5_GLOBAL_REGISTER_GLOBAL_RESET BIT(5)
+
+/* PLL/VCO runs between 2.5 GHz and 3.0 GHz */
+#define VC5_PLL_VCO_MIN 2500000000UL
+#define VC5_PLL_VCO_MAX 3000000000UL
+
+/* VC5 Input mux settings */
+#define VC5_MUX_IN_XIN BIT(0)
+#define VC5_MUX_IN_CLKIN BIT(1)
+
+/* Maximum number of clk_out supported by this driver */
+#define VC5_MAX_CLK_OUT_NUM 5
+
+/* Maximum number of FODs supported by this driver */
+#define VC5_MAX_FOD_NUM 4
+
+/* flags to describe chip features */
+/* chip has built-in oscilator */
+#define VC5_HAS_INTERNAL_XTAL BIT(0)
+/* chip has PFD requency doubler */
+#define VC5_HAS_PFD_FREQ_DBL BIT(1)
+
+/* Supported IDT VC5 models. */
+enum vc5_model {
+ IDT_VC5_5P49V5923,
+ IDT_VC5_5P49V5925,
+ IDT_VC5_5P49V5933,
+ IDT_VC5_5P49V5935,
+ IDT_VC6_5P49V6901,
+ IDT_VC6_5P49V6965,
+};
+
+/* Structure to describe features of a particular VC5 model */
+struct vc5_chip_info {
+ const enum vc5_model model;
+ const unsigned int clk_fod_cnt;
+ const unsigned int clk_out_cnt;
+ const u32 flags;
+};
+
+struct vc5_driver_data;
+
+struct vc5_hw_data {
+ struct clk hw;
+ struct vc5_driver_data *vc5;
+ u32 div_int;
+ u32 div_frc;
+ unsigned int num;
+};
+
+struct vc5_out_data {
+ struct clk hw;
+ struct vc5_driver_data *vc5;
+ unsigned int num;
+ unsigned int clk_output_cfg0;
+ unsigned int clk_output_cfg0_mask;
+};
+
+struct vc5_driver_data {
+ struct udevice *i2c;
+ const struct vc5_chip_info *chip_info;
+
+ struct clk *pin_xin;
+ struct clk *pin_clkin;
+ unsigned char clk_mux_ins;
+ struct clk clk_mux;
+ struct clk clk_mul;
+ struct clk clk_pfd;
+ struct vc5_hw_data clk_pll;
+ struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
+ struct vc5_out_data clk_out[VC5_MAX_CLK_OUT_NUM];
+};
+
+static const struct vc5_chip_info idt_5p49v5923_info = {
+ .model = IDT_VC5_5P49V5923,
+ .clk_fod_cnt = 2,
+ .clk_out_cnt = 3,
+ .flags = 0,
+};
+
+static const struct vc5_chip_info idt_5p49v5925_info = {
+ .model = IDT_VC5_5P49V5925,
+ .clk_fod_cnt = 4,
+ .clk_out_cnt = 5,
+ .flags = 0,
+};
+
+static const struct vc5_chip_info idt_5p49v5933_info = {
+ .model = IDT_VC5_5P49V5933,
+ .clk_fod_cnt = 2,
+ .clk_out_cnt = 3,
+ .flags = VC5_HAS_INTERNAL_XTAL,
+};
+
+static const struct vc5_chip_info idt_5p49v5935_info = {
+ .model = IDT_VC5_5P49V5935,
+ .clk_fod_cnt = 4,
+ .clk_out_cnt = 5,
+ .flags = VC5_HAS_INTERNAL_XTAL,
+};
+
+static const struct vc5_chip_info idt_5p49v6901_info = {
+ .model = IDT_VC6_5P49V6901,
+ .clk_fod_cnt = 4,
+ .clk_out_cnt = 5,
+ .flags = VC5_HAS_PFD_FREQ_DBL,
+};
+
+static const struct vc5_chip_info idt_5p49v6965_info = {
+ .model = IDT_VC6_5P49V6965,
+ .clk_fod_cnt = 4,
+ .clk_out_cnt = 5,
+ .flags = 0,
+};
+
+static int vc5_update_bits(struct udevice *dev, unsigned int reg, unsigned int mask,
+ unsigned int src)
+{
+ int ret;
+ unsigned char cache;
+
+ ret = dm_i2c_read(dev, reg, &cache, 1);
+ if (ret < 0)
+ return ret;
+
+ cache &= ~mask;
+ cache |= mask & src;
+ ret = dm_i2c_write(dev, reg, (uchar *)&cache, 1);
+
+ return ret;
+}
+
+static unsigned long vc5_mux_get_rate(struct clk *hw)
+{
+ return clk_get_rate(clk_get_parent(hw));
+}
+
+static int vc5_mux_set_parent(struct clk *hw, unsigned char index)
+{
+ struct vc5_driver_data *vc5 = container_of(hw, struct vc5_driver_data, clk_mux);
+ const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
+ u8 src;
+
+ if (index > 1 || !vc5->clk_mux_ins)
+ return -EINVAL;
+
+ if (vc5->clk_mux_ins == (VC5_MUX_IN_CLKIN | VC5_MUX_IN_XIN)) {
+ if (index == 0)
+ src = VC5_PRIM_SRC_SHDN_EN_XTAL;
+ if (index == 1)
+ src = VC5_PRIM_SRC_SHDN_EN_CLKIN;
+ } else {
+ if (index != 0)
+ return -EINVAL;
+
+ if (vc5->clk_mux_ins == VC5_MUX_IN_XIN)
+ src = VC5_PRIM_SRC_SHDN_EN_XTAL;
+ else if (vc5->clk_mux_ins == VC5_MUX_IN_CLKIN)
+ src = VC5_PRIM_SRC_SHDN_EN_CLKIN;
+ else /* Invalid; should have been caught by vc5_probe() */
+ return -EINVAL;
+ }
+
+ return vc5_update_bits(vc5->i2c, VC5_PRIM_SRC_SHDN, mask, src);
+}
+
+static const struct clk_ops vc5_mux_ops = {
+ .get_rate = vc5_mux_get_rate,
+};
+
+static unsigned long vc5_pfd_round_rate(struct clk *hw, unsigned long rate)
+{
+ struct clk *clk_parent = clk_get_parent(hw);
+ unsigned long parent_rate = clk_get_rate(clk_parent);
+ unsigned long idiv;
+
+ /* PLL cannot operate with input clock above 50 MHz. */
+ if (rate > 50000000)
+ return -EINVAL;
+
+ /* CLKIN within range of PLL input, feed directly to PLL. */
+ if (parent_rate <= 50000000)
+ return parent_rate;
+
+ idiv = DIV_ROUND_UP(parent_rate, rate);
+ if (idiv > 127)
+ return -EINVAL;
+
+ return parent_rate / idiv;
+}
+
+static unsigned long vc5_pfd_recalc_rate(struct clk *hw)
+{
+ struct vc5_driver_data *vc5 =
+ container_of(hw, struct vc5_driver_data, clk_pfd);
+ unsigned int prediv, div;
+ struct clk *clk_parent = clk_get_parent(hw);
+ unsigned long parent_rate = clk_get_rate(clk_parent);
+
+ dm_i2c_read(vc5->i2c, VC5_VCO_CTRL_AND_PREDIV, (uchar *)&prediv, 1);
+
+ /* The bypass_prediv is set, PLL fed from Ref_in directly. */
+ if (prediv & VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV)
+ return parent_rate;
+
+ dm_i2c_read(vc5->i2c, VC5_REF_DIVIDER, (uchar *)&div, 1);
+
+ /* The Sel_prediv2 is set, PLL fed from prediv2 (Ref_in / 2) */
+ if (div & VC5_REF_DIVIDER_SEL_PREDIV2)
+ return parent_rate / 2;
+ else
+ return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
+}
+
+static unsigned long vc5_pfd_set_rate(struct clk *hw, unsigned long rate)
+{
+ struct vc5_driver_data *vc5 =
+ container_of(hw, struct vc5_driver_data, clk_pfd);
+ unsigned long idiv;
+ u8 div;
+ struct clk *clk_parent = clk_get_parent(hw);
+ unsigned long parent_rate = clk_get_rate(clk_parent);
+
+ /* CLKIN within range of PLL input, feed directly to PLL. */
+ if (parent_rate <= 50000000) {
+ vc5_update_bits(vc5->i2c, VC5_VCO_CTRL_AND_PREDIV,
+ VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV,
+ VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
+ vc5_update_bits(vc5->i2c, VC5_REF_DIVIDER, 0xff, 0x00);
+ return 0;
+ }
+
+ idiv = DIV_ROUND_UP(parent_rate, rate);
+
+ /* We have dedicated div-2 predivider. */
+ if (idiv == 2)
+ div = VC5_REF_DIVIDER_SEL_PREDIV2;
+ else
+ div = VC5_REF_DIVIDER_REF_DIV(idiv);
+
+ vc5_update_bits(vc5->i2c, VC5_REF_DIVIDER, 0xff, div);
+ vc5_update_bits(vc5->i2c, VC5_VCO_CTRL_AND_PREDIV,
+ VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, 0);
+
+ return 0;
+}
+
+static const struct clk_ops vc5_pfd_ops = {
+ .round_rate = vc5_pfd_round_rate,
+ .get_rate = vc5_pfd_recalc_rate,
+ .set_rate = vc5_pfd_set_rate,
+};
+
+/*
+ * VersaClock5 PLL/VCO
+ */
+static unsigned long vc5_pll_recalc_rate(struct clk *hw)
+{
+ struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+ struct vc5_driver_data *vc = hwdata->vc5;
+ struct clk *clk_parent = clk_get_parent(hw);
+ unsigned long parent_rate = clk_get_rate(clk_parent);
+ u32 div_int, div_frc;
+ u8 fb[5];
+
+ dm_i2c_read(vc->i2c, VC5_FEEDBACK_INT_DIV, fb, 5);
+
+ div_int = (fb[0] << 4) | (fb[1] >> 4);
+ div_frc = (fb[2] << 16) | (fb[3] << 8) | fb[4];
+
+ /* The PLL divider has 12 integer bits and 24 fractional bits */
+ return (parent_rate * div_int) + ((parent_rate * div_frc) >> 24);
+}
+
+static unsigned long vc5_pll_round_rate(struct clk *hw, unsigned long rate)
+{
+ struct clk *clk_parent = clk_get_parent(hw);
+ unsigned long parent_rate = clk_get_rate(clk_parent);
+ struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+ u32 div_int;
+ u64 div_frc;
+
+ if (rate < VC5_PLL_VCO_MIN)
+ rate = VC5_PLL_VCO_MIN;
+ if (rate > VC5_PLL_VCO_MAX)
+ rate = VC5_PLL_VCO_MAX;
+
+ /* Determine integer part, which is 12 bit wide */
+ div_int = rate / parent_rate;
+ if (div_int > 0xfff)
+ rate = parent_rate * 0xfff;
+
+ /* Determine best fractional part, which is 24 bit wide */
+ div_frc = rate % parent_rate;
+ div_frc *= BIT(24) - 1;
+ do_div(div_frc, parent_rate);
+
+ hwdata->div_int = div_int;
+ hwdata->div_frc = (u32)div_frc;
+
+ return (parent_rate * div_int) + ((parent_rate * div_frc) >> 24);
+}
+
+static unsigned long vc5_pll_set_rate(struct clk *hw, unsigned long rate)
+{
+ struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+ struct vc5_driver_data *vc5 = hwdata->vc5;
+ u8 fb[5];
+
+ fb[0] = hwdata->div_int >> 4;
+ fb[1] = hwdata->div_int << 4;
+ fb[2] = hwdata->div_frc >> 16;
+ fb[3] = hwdata->div_frc >> 8;
+ fb[4] = hwdata->div_frc;
+
+ return dm_i2c_write(vc5->i2c, VC5_FEEDBACK_INT_DIV, fb, 5);
+}
+
+static const struct clk_ops vc5_pll_ops = {
+ .round_rate = vc5_pll_round_rate,
+ .get_rate = vc5_pll_recalc_rate,
+ .set_rate = vc5_pll_set_rate,
+};
+
+static unsigned long vc5_fod_recalc_rate(struct clk *hw)
+{
+ struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+ struct vc5_driver_data *vc = hwdata->vc5;
+ struct clk *parent = &vc->clk_pll.hw;
+ unsigned long parent_rate = vc5_pll_recalc_rate(parent);
+
+ /* VCO frequency is divided by two before entering FOD */
+ u32 f_in = parent_rate / 2;
+ u32 div_int, div_frc;
+ u8 od_int[2];
+ u8 od_frc[4];
+
+ dm_i2c_read(vc->i2c, VC5_OUT_DIV_INT(hwdata->num, 0), od_int, 2);
+ dm_i2c_read(vc->i2c, VC5_OUT_DIV_FRAC(hwdata->num, 0), od_frc, 4);
+
+ div_int = (od_int[0] << 4) | (od_int[1] >> 4);
+ div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) |
+ (od_frc[2] << 6) | (od_frc[3] >> 2);
+
+ /* Avoid division by zero if the output is not configured. */
+ if (div_int == 0 && div_frc == 0)
+ return 0;
+
+ /* The PLL divider has 12 integer bits and 30 fractional bits */
+ return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
+}
+
+static unsigned long vc5_fod_round_rate(struct clk *hw, unsigned long rate)
+{
+ struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+ struct vc5_driver_data *vc = hwdata->vc5;
+ struct clk *parent = &vc->clk_pll.hw;
+ unsigned long parent_rate = vc5_pll_recalc_rate(parent);
+
+ /* VCO frequency is divided by two before entering FOD */
+ u32 f_in = parent_rate / 2;
+ u32 div_int;
+ u64 div_frc;
+
+ /* Determine integer part, which is 12 bit wide */
+ div_int = f_in / rate;
+
+ /*
+ * WARNING: The clock chip does not output signal if the integer part
+ * of the divider is 0xfff and fractional part is non-zero.
+ * Clamp the divider at 0xffe to keep the code simple.
+ */
+ if (div_int > 0xffe) {
+ div_int = 0xffe;
+ rate = f_in / div_int;
+ }
+
+ /* Determine best fractional part, which is 30 bit wide */
+ div_frc = f_in % rate;
+ div_frc <<= 24;
+ do_div(div_frc, rate);
+
+ hwdata->div_int = div_int;
+ hwdata->div_frc = (u32)div_frc;
+
+ return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
+}
+
+static unsigned long vc5_fod_set_rate(struct clk *hw, unsigned long rate)
+{
+ struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+ struct vc5_driver_data *vc5 = hwdata->vc5;
+
+ u8 data[14] = {
+ hwdata->div_frc >> 22, hwdata->div_frc >> 14,
+ hwdata->div_frc >> 6, hwdata->div_frc << 2,
+ 0, 0, 0, 0, 0,
+ 0, 0,
+ hwdata->div_int >> 4, hwdata->div_int << 4,
+ 0
+ };
+
+ dm_i2c_write(vc5->i2c, VC5_OUT_DIV_FRAC(hwdata->num, 0), data, 14);
+
+ /*
+ * Toggle magic bit in undocumented register for unknown reason.
+ * This is what the IDT timing commander tool does and the chip
+ * datasheet somewhat implies this is needed, but the register
+ * and the bit is not documented.
+ */
+ vc5_update_bits(vc5->i2c, VC5_GLOBAL_REGISTER,
+ VC5_GLOBAL_REGISTER_GLOBAL_RESET, 0);
+ vc5_update_bits(vc5->i2c, VC5_GLOBAL_REGISTER,
+ VC5_GLOBAL_REGISTER_GLOBAL_RESET,
+ VC5_GLOBAL_REGISTER_GLOBAL_RESET);
+
+ return 0;
+}
+
+static const struct clk_ops vc5_fod_ops = {
+ .round_rate = vc5_fod_round_rate,
+ .get_rate = vc5_fod_recalc_rate,
+ .set_rate = vc5_fod_set_rate,
+};
+
+static int vc5_clk_out_prepare(struct clk *hw)
+{
+ struct udevice *dev;
+ struct vc5_driver_data *vc5;
+ struct vc5_out_data *hwdata;
+
+ const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
+ VC5_OUT_DIV_CONTROL_SEL_EXT |
+ VC5_OUT_DIV_CONTROL_EN_FOD;
+ unsigned int src;
+ int ret;
+
+ uclass_get_device_by_name(UCLASS_CLK, clk_hw_get_name(hw), &dev);
+ vc5 = dev_get_priv(dev);
+ hwdata = &vc5->clk_out[hw->id];
+
+ /*
+ * If the input mux is disabled, enable it first and
+ * select source from matching FOD.
+ */
+
+ dm_i2c_read(vc5->i2c, VC5_OUT_DIV_CONTROL(hwdata->num), (uchar *)&src, 1);
+
+ if ((src & mask) == 0) {
+ src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD;
+ ret = vc5_update_bits(vc5->i2c,
+ VC5_OUT_DIV_CONTROL(hwdata->num),
+ mask | VC5_OUT_DIV_CONTROL_RESET, src);
+ if (ret)
+ return ret;
+ }
+
+ /* Enable the clock buffer */
+ vc5_update_bits(vc5->i2c, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
+ VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
+ VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
+ if (hwdata->clk_output_cfg0_mask) {
+ vc5_update_bits(vc5->i2c, VC5_CLK_OUTPUT_CFG(hwdata->num, 0),
+ hwdata->clk_output_cfg0_mask,
+ hwdata->clk_output_cfg0);
+ }
+
+ return 0;
+}
+
+static int vc5_clk_out_unprepare(struct clk *hw)
+{
+ struct udevice *dev;
+ struct vc5_driver_data *vc5;
+ struct vc5_out_data *hwdata;
+ int ret;
+
+ uclass_get_device_by_name(UCLASS_CLK, clk_hw_get_name(hw), &dev);
+ vc5 = dev_get_priv(dev);
+ hwdata = &vc5->clk_out[hw->id];
+
+ /* Disable the clock buffer */
+ ret = vc5_update_bits(vc5->i2c, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
+ VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0);
+
+ return ret;
+}
+
+static int vc5_clk_out_set_parent(struct vc5_driver_data *vc, u8 num, u8 index)
+{
+ const u8 mask = VC5_OUT_DIV_CONTROL_RESET |
+ VC5_OUT_DIV_CONTROL_SELB_NORM |
+ VC5_OUT_DIV_CONTROL_SEL_EXT |
+ VC5_OUT_DIV_CONTROL_EN_FOD;
+ const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
+ VC5_OUT_DIV_CONTROL_SEL_EXT;
+ u8 src = VC5_OUT_DIV_CONTROL_RESET;
+
+ if (index == 0)
+ src |= VC5_OUT_DIV_CONTROL_EN_FOD;
+ else
+ src |= extclk;
+
+ return vc5_update_bits(vc->i2c, VC5_OUT_DIV_CONTROL(num), mask, src);
+}
+
+/*
+ * The device references to the Versaclock point to the head, so xlate needs to
+ * redirect it to clk_out[idx]
+ */
+static int vc5_clk_out_xlate(struct clk *hw, struct ofnode_phandle_args *args)
+{
+ unsigned int idx = args->args[0];
+
+ if (args->args_count != 1) {
+ debug("Invaild args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ hw->id = idx;
+
+ return 0;
+}
+
+static unsigned long vc5_clk_out_set_rate(struct clk *hw, unsigned long rate)
+{
+ struct udevice *dev;
+ struct vc5_driver_data *vc;
+ struct clk *parent;
+
+ uclass_get_device_by_name(UCLASS_CLK, clk_hw_get_name(hw), &dev);
+ vc = dev_get_priv(dev);
+ parent = clk_get_parent(&vc->clk_out[hw->id].hw);
+
+ /* setting the output rate really means setting the parent FOD rate */
+ return clk_set_rate(parent, clk_round_rate(parent, rate));
+}
+
+static unsigned long vc5_clk_out_get_rate(struct clk *hw)
+{
+ return clk_get_parent_rate(hw);
+}
+
+static const struct clk_ops vc5_clk_out_ops = {
+ .enable = vc5_clk_out_prepare,
+ .disable = vc5_clk_out_unprepare,
+ .set_rate = vc5_clk_out_set_rate,
+ .get_rate = vc5_clk_out_get_rate,
+};
+
+static const struct clk_ops vc5_clk_out_sel_ops = {
+ .enable = vc5_clk_out_prepare,
+ .disable = vc5_clk_out_unprepare,
+ .get_rate = vc5_clk_out_get_rate,
+};
+
+static const struct clk_ops vc5_clk_ops = {
+ .enable = vc5_clk_out_prepare,
+ .disable = vc5_clk_out_unprepare,
+ .of_xlate = vc5_clk_out_xlate,
+ .set_rate = vc5_clk_out_set_rate,
+ .get_rate = vc5_clk_out_get_rate,
+};
+
+static int vc5_map_index_to_output(const enum vc5_model model,
+ const unsigned int n)
+{
+ switch (model) {
+ case IDT_VC5_5P49V5933:
+ return (n == 0) ? 0 : 3;
+ case IDT_VC5_5P49V5923:
+ case IDT_VC5_5P49V5925:
+ case IDT_VC5_5P49V5935:
+ case IDT_VC6_5P49V6901:
+ case IDT_VC6_5P49V6965:
+ default:
+ return n;
+ }
+}
+
+static int vc5_update_mode(ofnode np_output,
+ struct vc5_out_data *clk_out)
+{
+ u32 value;
+
+ if (!ofnode_read_u32(np_output, "idt,mode", &value)) {
+ clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_CFG_MASK;
+ switch (value) {
+ case VC5_CLK_OUTPUT_CFG0_CFG_LVPECL:
+ case VC5_CLK_OUTPUT_CFG0_CFG_CMOS:
+ case VC5_CLK_OUTPUT_CFG0_CFG_HCSL33:
+ case VC5_CLK_OUTPUT_CFG0_CFG_LVDS:
+ case VC5_CLK_OUTPUT_CFG0_CFG_CMOS2:
+ case VC5_CLK_OUTPUT_CFG0_CFG_CMOSD:
+ case VC5_CLK_OUTPUT_CFG0_CFG_HCSL25:
+ clk_out->clk_output_cfg0 |=
+ value << VC5_CLK_OUTPUT_CFG0_CFG_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int vc5_update_power(ofnode np_output, struct vc5_out_data *clk_out)
+{
+ u32 value;
+
+ if (!ofnode_read_u32(np_output, "idt,voltage-microvolt", &value)) {
+ clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_PWR_MASK;
+ switch (value) {
+ case 1800000:
+ clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_18;
+ break;
+ case 2500000:
+ clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_25;
+ break;
+ case 3300000:
+ clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_33;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int vc5_map_cap_value(u32 femtofarads)
+{
+ int mapped_value;
+
+ /*
+ * The datasheet explicitly states 9000 - 25000 with 0.5pF
+ * steps, but the Programmer's guide shows the steps are 0.430pF.
+ * After getting feedback from Renesas, the .5pF steps were the
+ * goal, but 430nF was the actual values.
+ * Because of this, the actual range goes to 22760 instead of 25000
+ */
+ if (femtofarads < 9000 || femtofarads > 22760)
+ return -EINVAL;
+
+ /*
+ * The Programmer's guide shows XTAL[5:0] but in reality,
+ * XTAL[0] and XTAL[1] are both LSB which makes the math
+ * strange. With clarfication from Renesas, setting the
+ * values should be simpler by ignoring XTAL[0]
+ */
+ mapped_value = DIV_ROUND_CLOSEST(femtofarads - 9000, 430);
+
+ /*
+ * Since the calculation ignores XTAL[0], there is one
+ * special case where mapped_value = 32. In reality, this means
+ * the real mapped value should be 111111b. In other cases,
+ * the mapped_value needs to be shifted 1 to the left.
+ */
+ if (mapped_value > 31)
+ mapped_value = 0x3f;
+ else
+ mapped_value <<= 1;
+
+ return mapped_value;
+}
+
+static int vc5_update_cap_load(ofnode node, struct vc5_driver_data *vc5)
+{
+ u32 value;
+ int mapped_value;
+
+ if (!ofnode_read_u32(node, "idt,xtal-load-femtofarads", &value)) {
+ mapped_value = vc5_map_cap_value(value);
+
+ if (mapped_value < 0)
+ return mapped_value;
+
+ /*
+ * The mapped_value is really the high 6 bits of
+ * VC5_XTAL_X1_LOAD_CAP and VC5_XTAL_X2_LOAD_CAP, so
+ * shift the value 2 places.
+ */
+ vc5_update_bits(vc5->i2c, VC5_XTAL_X1_LOAD_CAP, ~0x03, mapped_value << 2);
+ vc5_update_bits(vc5->i2c, VC5_XTAL_X2_LOAD_CAP, ~0x03, mapped_value << 2);
+ }
+
+ return 0;
+}
+
+static int vc5_update_slew(ofnode np_output, struct vc5_out_data *clk_out)
+{
+ u32 value;
+
+ if (!ofnode_read_u32(np_output, "idt,slew-percent", &value)) {
+ clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_SLEW_MASK;
+
+ switch (value) {
+ case 80:
+ clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_80;
+ break;
+ case 85:
+ clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_85;
+ break;
+ case 90:
+ clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_90;
+ break;
+ case 100:
+ clk_out->clk_output_cfg0 |=
+ VC5_CLK_OUTPUT_CFG0_SLEW_100;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int vc5_get_output_config(struct udevice *dev,
+ struct vc5_out_data *clk_out)
+{
+ ofnode np_output;
+ char child_name[5];
+ int ret = 0;
+
+ sprintf(child_name, "OUT%d", clk_out->num + 1);
+
+ np_output = dev_read_subnode(dev, child_name);
+
+ if (!ofnode_valid(np_output)) {
+ dev_dbg(dev, "Invalid clock output configuration OUT%d\n",
+ clk_out->num + 1);
+ return 0;
+ }
+
+ ret = vc5_update_mode(np_output, clk_out);
+ if (ret)
+ return ret;
+
+ ret = vc5_update_power(np_output, clk_out);
+ if (ret)
+ return ret;
+
+ ret = vc5_update_slew(np_output, clk_out);
+
+ return ret;
+}
+
+static char *versaclock_get_name(const char *dev_name, const char *clk_name, int index)
+{
+ int length;
+ char *buf;
+
+ if (index < 0)
+ length = snprintf(NULL, 0, "%s.%s", dev_name, clk_name) + 1;
+ else
+ length = snprintf(NULL, 0, "%s.%s%d", dev_name, clk_name, index) + 1;
+
+ buf = malloc(length);
+ if (!buf)
+ ERR_PTR(-ENOMEM);
+
+ if (index < 0)
+ snprintf(buf, length, "%s.%s", dev_name, clk_name);
+ else
+ snprintf(buf, length, "%s.%s%d", dev_name, clk_name, index);
+
+ return buf;
+}
+
+int versaclock_probe(struct udevice *dev)
+{
+ struct vc5_driver_data *vc5 = dev_get_priv(dev);
+ struct vc5_chip_info *chip = (void *)dev_get_driver_data(dev);
+ unsigned int n, idx = 0;
+ char *mux_name, *pfd_name, *pll_name, *outsel_name;
+ char *out_name[VC5_MAX_CLK_OUT_NUM];
+ char *fod_name[VC5_MAX_FOD_NUM];
+ int ret;
+ u64 val;
+
+ val = (u64)dev_read_addr_ptr(dev);
+ ret = i2c_get_chip(dev->parent, val, 1, &vc5->i2c);
+
+ if (ret) {
+ dev_dbg(dev, "I2C probe failed.\n");
+ return ret;
+ }
+
+ vc5->chip_info = chip;
+ vc5->pin_xin = devm_clk_get(dev, "xin");
+
+ if (IS_ERR(vc5->pin_xin))
+ dev_dbg(dev, "failed to get xin clock\n");
+
+ ret = clk_enable(vc5->pin_xin);
+ if (ret)
+ dev_dbg(dev, "failed to enable XIN clock\n");
+
+ vc5->pin_clkin = devm_clk_get(dev, "clkin");
+
+ /* Register clock input mux */
+ if (!IS_ERR(vc5->pin_xin)) {
+ vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
+ } else if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) {
+ if (IS_ERR(vc5->pin_xin))
+ return PTR_ERR(vc5->pin_xin);
+ vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
+ }
+
+ mux_name = versaclock_get_name(dev->name, "mux", -1);
+ if (IS_ERR(mux_name))
+ return PTR_ERR(mux_name);
+
+ clk_register(&vc5->clk_mux, "versaclock-mux", mux_name, vc5->pin_xin->dev->name);
+
+ if (!IS_ERR(vc5->pin_xin))
+ vc5_mux_set_parent(&vc5->clk_mux, 1);
+ else
+ vc5_mux_set_parent(&vc5->clk_mux, 0);
+
+ /* Configure Optional Loading Capacitance for external XTAL */
+ if (!(vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)) {
+ ret = vc5_update_cap_load(dev_ofnode(dev), vc5);
+ if (ret)
+ dev_dbg(dev, "failed to vc5_update_cap_load\n");
+ }
+
+ /* Register PFD */
+ pfd_name = versaclock_get_name(dev->name, "pfd", -1);
+ if (IS_ERR(pfd_name)) {
+ ret = PTR_ERR(pfd_name);
+ goto free_mux;
+ }
+
+ ret = clk_register(&vc5->clk_pfd, "versaclock-pfd", pfd_name, vc5->clk_mux.dev->name);
+ if (ret)
+ goto free_pfd;
+
+ /* Register PLL */
+ vc5->clk_pll.num = 0;
+ vc5->clk_pll.vc5 = vc5;
+ pll_name = versaclock_get_name(dev->name, "pll", -1);
+ if (IS_ERR(pll_name)) {
+ ret = PTR_ERR(pll_name);
+ goto free_pfd;
+ }
+
+ ret = clk_register(&vc5->clk_pll.hw, "versaclock-pll", pll_name, vc5->clk_pfd.dev->name);
+ if (ret)
+ goto free_pll;
+
+ /* Register FODs */
+ for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
+ fod_name[n] = versaclock_get_name(dev->name, "fod", n);
+ if (IS_ERR(pll_name)) {
+ ret = PTR_ERR(fod_name[n]);
+ goto free_fod;
+ }
+ idx = vc5_map_index_to_output(vc5->chip_info->model, n);
+ vc5->clk_fod[n].num = idx;
+ vc5->clk_fod[n].vc5 = vc5;
+ ret = clk_register(&vc5->clk_fod[n].hw, "versaclock-fod", fod_name[n],
+ vc5->clk_pll.hw.dev->name);
+ if (ret)
+ goto free_fod;
+ }
+
+ /* Register MUX-connected OUT0_I2C_SELB output */
+ vc5->clk_out[0].num = idx;
+ vc5->clk_out[0].vc5 = vc5;
+ outsel_name = versaclock_get_name(dev->name, "out0_sel_i2cb", -1);
+ if (IS_ERR(outsel_name)) {
+ ret = PTR_ERR(outsel_name);
+ goto free_fod;
+ };
+
+ ret = clk_register(&vc5->clk_out[0].hw, "versaclock-outsel", outsel_name,
+ vc5->clk_mux.dev->name);
+ if (ret)
+ goto free_selb;
+
+ /* Register FOD-connected OUTx outputs */
+ for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
+ idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1);
+ out_name[n] = versaclock_get_name(dev->name, "out", n);
+ if (IS_ERR(out_name[n])) {
+ ret = PTR_ERR(out_name[n]);
+ goto free_selb;
+ }
+ vc5->clk_out[n].num = idx;
+ vc5->clk_out[n].vc5 = vc5;
+ ret = clk_register(&vc5->clk_out[n].hw, "versaclock-out", out_name[n],
+ vc5->clk_fod[idx].hw.dev->name);
+ if (ret)
+ goto free_out;
+ vc5_clk_out_set_parent(vc5, idx, 0);
+
+ /* Fetch Clock Output configuration from DT (if specified) */
+ ret = vc5_get_output_config(dev, &vc5->clk_out[n]);
+ if (ret) {
+ dev_dbg(dev, "failed to vc5_get_output_config()\n");
+ goto free_out;
+ }
+ }
+
+ return 0;
+
+free_out:
+ for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
+ clk_free(&vc5->clk_out[n].hw);
+ free(out_name[n]);
+ }
+free_selb:
+ clk_free(&vc5->clk_out[0].hw);
+ free(outsel_name);
+free_fod:
+ for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
+ clk_free(&vc5->clk_fod[n].hw);
+ free(fod_name[n]);
+ }
+free_pll:
+ clk_free(&vc5->clk_pll.hw);
+ free(pll_name);
+free_pfd:
+ clk_free(&vc5->clk_pfd);
+ free(pfd_name);
+free_mux:
+ clk_free(&vc5->clk_mux);
+ free(mux_name);
+
+ return ret;
+}
+
+static const struct udevice_id versaclock_ids[] = {
+ { .compatible = "idt,5p49v5923", .data = (ulong)&idt_5p49v5923_info },
+ { .compatible = "idt,5p49v5925", .data = (ulong)&idt_5p49v5925_info },
+ { .compatible = "idt,5p49v5933", .data = (ulong)&idt_5p49v5933_info },
+ { .compatible = "idt,5p49v5935", .data = (ulong)&idt_5p49v5935_info },
+ { .compatible = "idt,5p49v6901", .data = (ulong)&idt_5p49v6901_info },
+ { .compatible = "idt,5p49v6965", .data = (ulong)&idt_5p49v6965_info },
+ {},
+};
+
+U_BOOT_DRIVER(versaclock) = {
+ .name = "versaclock",
+ .id = UCLASS_CLK,
+ .ops = &vc5_clk_ops,
+ .of_match = versaclock_ids,
+ .probe = versaclock_probe,
+ .priv_auto = sizeof(struct vc5_driver_data),
+};
+
+U_BOOT_DRIVER(versaclock_mux) = {
+ .name = "versaclock-mux",
+ .id = UCLASS_CLK,
+ .ops = &vc5_mux_ops,
+};
+
+U_BOOT_DRIVER(versaclock_pfd) = {
+ .name = "versaclock-pfd",
+ .id = UCLASS_CLK,
+ .ops = &vc5_pfd_ops,
+};
+
+U_BOOT_DRIVER(versaclock_pll) = {
+ .name = "versaclock-pll",
+ .id = UCLASS_CLK,
+ .ops = &vc5_pll_ops,
+};
+
+U_BOOT_DRIVER(versaclock_fod) = {
+ .name = "versaclock-fod",
+ .id = UCLASS_CLK,
+ .ops = &vc5_fod_ops,
+};
+
+U_BOOT_DRIVER(versaclock_out) = {
+ .name = "versaclock-out",
+ .id = UCLASS_CLK,
+ .ops = &vc5_clk_out_ops,
+};
+
+U_BOOT_DRIVER(versaclock_outsel) = {
+ .name = "versaclock-outsel",
+ .id = UCLASS_CLK,
+ .ops = &vc5_clk_out_sel_ops,
+};
--
2.25.1
4
7
From: Mike Karels <karels(a)FreeBSD.org>
Using mmc.dtbo from rpi-firmware to switch the controller for the SD
card slot from sdhci to sdhost causes the numbering to change; the
SD card is then not recognized at boot. Add to the range checked.
---
include/configs/rpi.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/configs/rpi.h b/include/configs/rpi.h
index 55768a46da..4c5c1ac31f 100644
--- a/include/configs/rpi.h
+++ b/include/configs/rpi.h
@@ -137,7 +137,8 @@
#if CONFIG_IS_ENABLED(CMD_MMC)
#define BOOT_TARGET_MMC(func) \
func(MMC, mmc, 0) \
- func(MMC, mmc, 1)
+ func(MMC, mmc, 1) \
+ func(MMC, mmc, 2)
#else
#define BOOT_TARGET_MMC(func)
#endif
--
2.32.0
3
2
Add i.MX8QM DMSSE20 a1 board support
U-Boot 2021.04-rc1-00070-g30e1471671 (Feb 19 2021 - 09:25:19 +0100)
Model: Advantech iMX8QM DMSSE20
Board: DMS-SE20A1 8GB
Build: SCFW 494c97f3, SECO-FW d7523fe8, ATF 09c5cc9
Boot: USB
DRAM: 8 GiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2
Loading Environment from MMC... OK
In: serial@5a060000
Out: serial@5a060000
Err: serial@5a060000
Net: eth0: ethernet@5b040000 [PRIME]
Warning: ethernet@5b050000 (eth1) using random MAC address - fe:ac:c4:1f:d9:9c
, eth1: ethernet@5b050000
Hit any key to stop autoboot: 0
Signed-off-by: Oliver Graute <oliver.graute(a)kococonnector.com>
---
Changes for v2
-replaced bd_t with struct bd_info
-added missing DTS in MAINTAINERS
-replaced README with imx8qm-dmsse20-a1.rst
-move CMD_FUSE to Kconfig
-removed fdt_high
-added i2c support
-added rtc support
arch/arm/dts/Makefile | 1 +
arch/arm/dts/imx8qm-dmsse20-a1.dts | 407 ++++++++++++++++++
arch/arm/mach-imx/imx8/Kconfig | 7 +
board/advantech/imx8qm_dmsse20_a1/Kconfig | 14 +
board/advantech/imx8qm_dmsse20_a1/MAINTAINERS | 7 +
board/advantech/imx8qm_dmsse20_a1/Makefile | 8 +
.../imx8qm_dmsse20_a1/imx8qm_dmsse20_a1.c | 188 ++++++++
.../advantech/imx8qm_dmsse20_a1/imximage.cfg | 21 +
board/advantech/imx8qm_dmsse20_a1/spl.c | 224 ++++++++++
common/Kconfig | 2 +-
configs/imx8qm_dmsse20a1_defconfig | 94 ++++
doc/board/advantech/imx8qm-dmsse20-a1.rst | 58 +++
doc/board/advantech/index.rst | 1 +
include/configs/imx8qm_dmsse20.h | 187 ++++++++
14 files changed, 1218 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/dts/imx8qm-dmsse20-a1.dts
create mode 100644 board/advantech/imx8qm_dmsse20_a1/Kconfig
create mode 100644 board/advantech/imx8qm_dmsse20_a1/MAINTAINERS
create mode 100644 board/advantech/imx8qm_dmsse20_a1/Makefile
create mode 100644 board/advantech/imx8qm_dmsse20_a1/imx8qm_dmsse20_a1.c
create mode 100644 board/advantech/imx8qm_dmsse20_a1/imximage.cfg
create mode 100644 board/advantech/imx8qm_dmsse20_a1/spl.c
create mode 100644 configs/imx8qm_dmsse20a1_defconfig
create mode 100644 doc/board/advantech/imx8qm-dmsse20-a1.rst
create mode 100644 include/configs/imx8qm_dmsse20.h
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index c64ba90f01..db5e465cd7 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -763,6 +763,7 @@ dtb-$(CONFIG_ARCH_IMX8) += \
fsl-imx8qm-apalis.dtb \
fsl-imx8qm-mek.dtb \
imx8qm-cgtqmx8.dtb \
+ imx8qm-dmsse20-a1.dtb \
imx8qm-rom7720-a1.dtb \
fsl-imx8qxp-ai_ml.dtb \
fsl-imx8qxp-colibri.dtb \
diff --git a/arch/arm/dts/imx8qm-dmsse20-a1.dts b/arch/arm/dts/imx8qm-dmsse20-a1.dts
new file mode 100644
index 0000000000..81ef7fb2ce
--- /dev/null
+++ b/arch/arm/dts/imx8qm-dmsse20-a1.dts
@@ -0,0 +1,407 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017 NXP
+ */
+
+/dts-v1/;
+
+/* First 128KB is for PSCI ATF. */
+/memreserve/ 0x80000000 0x00020000;
+
+#include "fsl-imx8qm.dtsi"
+
+/ {
+ model = "Advantech iMX8QM DMSSE20";
+ compatible = "fsl,imx8qm-mek", "fsl,imx8qm";
+
+ aliases {
+ mmc0 = &usdhc1;
+ mmc2 = &usdhc3;
+ };
+
+ chosen {
+ bootargs = "console=ttyLP0,115200 earlycon=lpuart32,0x5a060000,115200";
+ stdout-path = &lpuart0;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_usb_otg1_vbus: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "usb_otg1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio4 3 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_usdhc2_vmmc: usdhc2_vmmc {
+ compatible = "regulator-fixed";
+ regulator-name = "sw-3p3-sd1";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio4 7 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ busfreq {
+ status = "disabled";
+ };
+ };
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hog_1>;
+
+ imx8qm-mek {
+ pinctrl_hog_1: hoggrp-1 {
+ fsl,pins = <
+ SC_P_USB_SS3_TC0_LSIO_GPIO4_IO03 0x06000048
+ >;
+ };
+
+ pinctrl_fec1: fec1grp {
+ fsl,pins = <
+ SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB_PAD 0x000014a0
+ SC_P_ENET0_MDC_CONN_ENET0_MDC 0x06000020
+ SC_P_ENET0_MDIO_CONN_ENET0_MDIO 0x06000020
+ SC_P_ENET0_RGMII_TX_CTL_CONN_ENET0_RGMII_TX_CTL 0x00000060
+ SC_P_ENET0_RGMII_TXC_CONN_ENET0_RGMII_TXC 0x00000060
+ SC_P_ENET0_RGMII_TXD0_CONN_ENET0_RGMII_TXD0 0x00000060
+ SC_P_ENET0_RGMII_TXD1_CONN_ENET0_RGMII_TXD1 0x00000060
+ SC_P_ENET0_RGMII_TXD2_CONN_ENET0_RGMII_TXD2 0x00000060
+ SC_P_ENET0_RGMII_TXD3_CONN_ENET0_RGMII_TXD3 0x00000060
+ SC_P_ENET0_RGMII_RXC_CONN_ENET0_RGMII_RXC 0x00000060
+ SC_P_ENET0_RGMII_RX_CTL_CONN_ENET0_RGMII_RX_CTL 0x00000060
+ SC_P_ENET0_RGMII_RXD0_CONN_ENET0_RGMII_RXD0 0x00000060
+ SC_P_ENET0_RGMII_RXD1_CONN_ENET0_RGMII_RXD1 0x00000060
+ SC_P_ENET0_RGMII_RXD2_CONN_ENET0_RGMII_RXD2 0x00000060
+ SC_P_ENET0_RGMII_RXD3_CONN_ENET0_RGMII_RXD3 0x00000060
+ >;
+ };
+
+ pinctrl_fec2: fec2grp {
+ fsl,pins = <
+ SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETA_PAD 0x000014a0
+ SC_P_ENET1_MDC_CONN_ENET1_MDC 0x06000020
+ SC_P_ENET1_MDIO_CONN_ENET1_MDIO 0x06000020
+ SC_P_ENET1_RGMII_TX_CTL_CONN_ENET1_RGMII_TX_CTL 0x00000060
+ SC_P_ENET1_RGMII_TXC_CONN_ENET1_RGMII_TXC 0x00000060
+ SC_P_ENET1_RGMII_TXD0_CONN_ENET1_RGMII_TXD0 0x00000060
+ SC_P_ENET1_RGMII_TXD1_CONN_ENET1_RGMII_TXD1 0x00000060
+ SC_P_ENET1_RGMII_TXD2_CONN_ENET1_RGMII_TXD2 0x00000060
+ SC_P_ENET1_RGMII_TXD3_CONN_ENET1_RGMII_TXD3 0x00000060
+ SC_P_ENET1_RGMII_RXC_CONN_ENET1_RGMII_RXC 0x00000060
+ SC_P_ENET1_RGMII_RX_CTL_CONN_ENET1_RGMII_RX_CTL 0x00000060
+ SC_P_ENET1_RGMII_RXD0_CONN_ENET1_RGMII_RXD0 0x00000060
+ SC_P_ENET1_RGMII_RXD1_CONN_ENET1_RGMII_RXD1 0x00000060
+ SC_P_ENET1_RGMII_RXD2_CONN_ENET1_RGMII_RXD2 0x00000060
+ SC_P_ENET1_RGMII_RXD3_CONN_ENET1_RGMII_RXD3 0x00000060
+ >;
+ };
+
+ pinctrl_lpi2c1: lpi2c1grp {
+ fsl,pins = <
+ SC_P_GPT0_CLK_DMA_I2C1_SCL 0xc600004c
+ SC_P_GPT0_CAPTURE_DMA_I2C1_SDA 0xc600004c
+ >;
+ };
+
+ pinctrl_lpi2c2: lpi2c2grp {
+ fsl,pins = <
+ SC_P_GPT1_CLK_DMA_I2C2_SCL 0xc600004c
+ SC_P_GPT1_CAPTURE_DMA_I2C2_SDA 0xc600004c
+ >;
+ };
+
+ pinctrl_lpuart0: lpuart0grp {
+ fsl,pins = <
+ SC_P_UART0_RX_DMA_UART0_RX 0x06000020
+ SC_P_UART0_TX_DMA_UART0_TX 0x06000020
+ >;
+ };
+
+ pinctrl_rtc_mc_8803: rtc_mc_8803_grp{
+ fsl,pins = <
+ SC_P_SIM0_POWER_EN_DMA_I2C3_SDA 0xc600004c
+ SC_P_SIM0_PD_DMA_I2C3_SCL 0xc600004c
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ SC_P_EMMC0_CLK_CONN_EMMC0_CLK 0x06000041
+ SC_P_EMMC0_CMD_CONN_EMMC0_CMD 0x00000021
+ SC_P_EMMC0_DATA0_CONN_EMMC0_DATA0 0x00000021
+ SC_P_EMMC0_DATA1_CONN_EMMC0_DATA1 0x00000021
+ SC_P_EMMC0_DATA2_CONN_EMMC0_DATA2 0x00000021
+ SC_P_EMMC0_DATA3_CONN_EMMC0_DATA3 0x00000021
+ SC_P_EMMC0_DATA4_CONN_EMMC0_DATA4 0x00000021
+ SC_P_EMMC0_DATA5_CONN_EMMC0_DATA5 0x00000021
+ SC_P_EMMC0_DATA6_CONN_EMMC0_DATA6 0x00000021
+ SC_P_EMMC0_DATA7_CONN_EMMC0_DATA7 0x00000021
+ SC_P_EMMC0_STROBE_CONN_EMMC0_STROBE 0x06000041
+ SC_P_EMMC0_RESET_B_CONN_EMMC0_RESET_B 0x00000021
+ >;
+ };
+
+ pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
+ fsl,pins = <
+ SC_P_EMMC0_CLK_CONN_EMMC0_CLK 0x06000040
+ SC_P_EMMC0_CMD_CONN_EMMC0_CMD 0x00000020
+ SC_P_EMMC0_DATA0_CONN_EMMC0_DATA0 0x00000020
+ SC_P_EMMC0_DATA1_CONN_EMMC0_DATA1 0x00000020
+ SC_P_EMMC0_DATA2_CONN_EMMC0_DATA2 0x00000020
+ SC_P_EMMC0_DATA3_CONN_EMMC0_DATA3 0x00000020
+ SC_P_EMMC0_DATA4_CONN_EMMC0_DATA4 0x00000020
+ SC_P_EMMC0_DATA5_CONN_EMMC0_DATA5 0x00000020
+ SC_P_EMMC0_DATA6_CONN_EMMC0_DATA6 0x00000020
+ SC_P_EMMC0_DATA7_CONN_EMMC0_DATA7 0x00000020
+ SC_P_EMMC0_STROBE_CONN_EMMC0_STROBE 0x06000040
+ SC_P_EMMC0_RESET_B_CONN_EMMC0_RESET_B 0x00000020
+ >;
+ };
+
+ pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
+ fsl,pins = <
+ SC_P_EMMC0_CLK_CONN_EMMC0_CLK 0x06000040
+ SC_P_EMMC0_CMD_CONN_EMMC0_CMD 0x00000020
+ SC_P_EMMC0_DATA0_CONN_EMMC0_DATA0 0x00000020
+ SC_P_EMMC0_DATA1_CONN_EMMC0_DATA1 0x00000020
+ SC_P_EMMC0_DATA2_CONN_EMMC0_DATA2 0x00000020
+ SC_P_EMMC0_DATA3_CONN_EMMC0_DATA3 0x00000020
+ SC_P_EMMC0_DATA4_CONN_EMMC0_DATA4 0x00000020
+ SC_P_EMMC0_DATA5_CONN_EMMC0_DATA5 0x00000020
+ SC_P_EMMC0_DATA6_CONN_EMMC0_DATA6 0x00000020
+ SC_P_EMMC0_DATA7_CONN_EMMC0_DATA7 0x00000020
+ SC_P_EMMC0_STROBE_CONN_EMMC0_STROBE 0x06000040
+ SC_P_EMMC0_RESET_B_CONN_EMMC0_RESET_B 0x00000020
+ >;
+ };
+
+ pinctrl_usdhc2_gpio: usdhc2grpgpio {
+ fsl,pins = <
+ SC_P_USDHC1_RESET_B_LSIO_GPIO4_IO07 0x00000020
+ SC_P_USDHC1_VSELECT_LSIO_GPIO4_IO08 0x00000020
+ >;
+ };
+
+ pinctrl_usdhc3_gpio: usdhc3grpgpio {
+ fsl,pins = <
+ SC_P_USDHC2_WP_LSIO_GPIO4_IO11 0x00000021
+ SC_P_USDHC2_CD_B_LSIO_GPIO4_IO12 0x00000021
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ SC_P_USDHC1_CLK_CONN_USDHC1_CLK 0x06000041
+ SC_P_USDHC1_CMD_CONN_USDHC1_CMD 0x00000021
+ SC_P_USDHC1_DATA0_CONN_USDHC1_DATA0 0x00000021
+ SC_P_USDHC1_DATA1_CONN_USDHC1_DATA1 0x00000021
+ SC_P_USDHC1_DATA2_CONN_USDHC1_DATA2 0x00000021
+ SC_P_USDHC1_DATA3_CONN_USDHC1_DATA3 0x00000021
+ SC_P_USDHC1_VSELECT_CONN_USDHC1_VSELECT 0x00000021
+ >;
+ };
+
+ pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
+ fsl,pins = <
+ SC_P_USDHC1_CLK_CONN_USDHC1_CLK 0x06000040
+ SC_P_USDHC1_CMD_CONN_USDHC1_CMD 0x00000020
+ SC_P_USDHC1_DATA0_CONN_USDHC1_DATA0 0x00000020
+ SC_P_USDHC1_DATA1_CONN_USDHC1_DATA1 0x00000020
+ SC_P_USDHC1_DATA2_CONN_USDHC1_DATA2 0x00000020
+ SC_P_USDHC1_DATA3_CONN_USDHC1_DATA3 0x00000020
+ SC_P_USDHC1_VSELECT_CONN_USDHC1_VSELECT 0x00000020
+ >;
+ };
+
+ pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
+ fsl,pins = <
+ SC_P_USDHC1_CLK_CONN_USDHC1_CLK 0x06000040
+ SC_P_USDHC1_CMD_CONN_USDHC1_CMD 0x00000020
+ SC_P_USDHC1_DATA0_CONN_USDHC1_DATA0 0x00000020
+ SC_P_USDHC1_DATA1_CONN_USDHC1_DATA1 0x00000020
+ SC_P_USDHC1_DATA2_CONN_USDHC1_DATA2 0x00000020
+ SC_P_USDHC1_DATA3_CONN_USDHC1_DATA3 0x00000020
+ SC_P_USDHC1_VSELECT_CONN_USDHC1_VSELECT 0x00000020
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ SC_P_USDHC2_CLK_CONN_USDHC2_CLK 0x06000041
+ SC_P_USDHC2_CMD_CONN_USDHC2_CMD 0x00000021
+ SC_P_USDHC2_DATA0_CONN_USDHC2_DATA0 0x00000021
+ SC_P_USDHC2_DATA1_CONN_USDHC2_DATA1 0x00000021
+ SC_P_USDHC2_DATA2_CONN_USDHC2_DATA2 0x00000021
+ SC_P_USDHC2_DATA3_CONN_USDHC2_DATA3 0x00000021
+ SC_P_USDHC2_VSELECT_CONN_USDHC2_VSELECT 0x00000021
+ >;
+ };
+
+ pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
+ fsl,pins = <
+ SC_P_USDHC2_CLK_CONN_USDHC2_CLK 0x06000040
+ SC_P_USDHC2_CMD_CONN_USDHC2_CMD 0x00000020
+ SC_P_USDHC2_DATA0_CONN_USDHC2_DATA0 0x00000020
+ SC_P_USDHC2_DATA1_CONN_USDHC2_DATA1 0x00000020
+ SC_P_USDHC2_DATA2_CONN_USDHC2_DATA2 0x00000020
+ SC_P_USDHC2_DATA3_CONN_USDHC2_DATA3 0x00000020
+ SC_P_USDHC2_VSELECT_CONN_USDHC2_VSELECT 0x00000020
+ >;
+ };
+
+ pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
+ fsl,pins = <
+ SC_P_USDHC2_CLK_CONN_USDHC2_CLK 0x06000040
+ SC_P_USDHC2_CMD_CONN_USDHC2_CMD 0x00000020
+ SC_P_USDHC2_DATA0_CONN_USDHC2_DATA0 0x00000020
+ SC_P_USDHC2_DATA1_CONN_USDHC2_DATA1 0x00000020
+ SC_P_USDHC2_DATA2_CONN_USDHC2_DATA2 0x00000020
+ SC_P_USDHC2_DATA3_CONN_USDHC2_DATA3 0x00000020
+ SC_P_USDHC2_VSELECT_CONN_USDHC2_VSELECT 0x00000020
+ >;
+ };
+ };
+};
+
+&gpio2 {
+ status = "okay";
+};
+
+&gpio4 {
+ status = "okay";
+};
+
+&gpio5 {
+ status = "okay";
+};
+
+&usdhc1 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+ bus-width = <8>;
+ non-removable;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+ pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+ pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+ bus-width = <4>;
+ cd-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio5 21 GPIO_ACTIVE_HIGH>;
+ vmmc-supply = <®_usdhc2_vmmc>;
+ status = "okay";
+};
+
+&usdhc3 {
+ pinctrl-names = "default","state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_gpio>;
+ pinctrl-1 = <&pinctrl_usdhc3_100mhz>, <&pinctrl_usdhc3_gpio>;
+ pinctrl-2 = <&pinctrl_usdhc3_200mhz>, <&pinctrl_usdhc3_gpio>;
+ bus-width = <4>;
+ cd-gpios = <&gpio4 12 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio4 11 GPIO_ACTIVE_HIGH>;
+ no-1-8-v;
+ status = "okay";
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec1>;
+ phy-mode = "rgmii-id";
+ phy-handle = <ðphy0>;
+ fsl,ar8031-phy-fixup;
+ fsl,magic-packet;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@4 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <4>;
+ };
+ };
+};
+
+&fec2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec2>;
+ phy-mode = "rgmii-id";
+ phy-handle = <ðphy1>;
+ fsl,ar8031-phy-fixup;
+ fsl,magic-packet;
+ status = "okay";
+ fsl,mii-exclusive;
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy1: ethernet-phy@4 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <4>;
+ };
+ };
+};
+
+&i2c1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpi2c1>;
+ status = "okay";
+};
+
+&i2c2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpi2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rtc_mc_8803>;
+ status = "okay";
+
+ rv8803@32 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "microcrystal,rv8803";
+ reg = <0x32>;
+ };
+
+ 24c02@50 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,24c04";
+ reg = <0x50>;
+ };
+};
+
+&lpuart0 { /* console */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpuart0>;
+ status = "okay";
+};
diff --git a/arch/arm/mach-imx/imx8/Kconfig b/arch/arm/mach-imx/imx8/Kconfig
index 6728d23b6b..0d04ca1939 100644
--- a/arch/arm/mach-imx/imx8/Kconfig
+++ b/arch/arm/mach-imx/imx8/Kconfig
@@ -97,6 +97,12 @@ config TARGET_IMX8QM_ROM7720_A1
select SUPPORT_SPL
select IMX8QM
+config TARGET_IMX8QM_DMSSE20_A1
+ bool "Support i.MX8QM DMS-SE20-A1 board"
+ select BOARD_LATE_INIT
+ select SUPPORT_SPL
+ select IMX8QM
+
config TARGET_IMX8QXP_MEK
bool "Support i.MX8QXP MEK board"
select BOARD_LATE_INIT
@@ -107,6 +113,7 @@ endchoice
source "board/freescale/imx8qm_mek/Kconfig"
source "board/freescale/imx8qxp_mek/Kconfig"
source "board/congatec/cgtqmx8/Kconfig"
+source "board/advantech/imx8qm_dmsse20_a1/Kconfig"
source "board/advantech/imx8qm_rom7720_a1/Kconfig"
source "board/toradex/apalis-imx8/Kconfig"
source "board/toradex/colibri-imx8x/Kconfig"
diff --git a/board/advantech/imx8qm_dmsse20_a1/Kconfig b/board/advantech/imx8qm_dmsse20_a1/Kconfig
new file mode 100644
index 0000000000..1d5e68a96f
--- /dev/null
+++ b/board/advantech/imx8qm_dmsse20_a1/Kconfig
@@ -0,0 +1,14 @@
+if TARGET_IMX8QM_DMSSE20_A1
+
+config SYS_BOARD
+ default "imx8qm_dmsse20_a1"
+
+config SYS_VENDOR
+ default "advantech"
+
+config SYS_CONFIG_NAME
+ default "imx8qm_dmsse20"
+
+source "board/freescale/common/Kconfig"
+
+endif
diff --git a/board/advantech/imx8qm_dmsse20_a1/MAINTAINERS b/board/advantech/imx8qm_dmsse20_a1/MAINTAINERS
new file mode 100644
index 0000000000..8292c6ba71
--- /dev/null
+++ b/board/advantech/imx8qm_dmsse20_a1/MAINTAINERS
@@ -0,0 +1,7 @@
+i.MX8QM ROM DMSSE20 a1 BOARD
+M: Oliver Graute <oliver.graute(a)kococonnector.com>
+S: Maintained
+F: board/advantech/imx8qm_dmsse20_a1/
+F: arch/arm/dts/imx8qm-dmsse20-a1.dtb
+F: include/configs/imx8qm_dmsse20.h
+F: configs/imx8qm_dmsse20a1_defconfig
diff --git a/board/advantech/imx8qm_dmsse20_a1/Makefile b/board/advantech/imx8qm_dmsse20_a1/Makefile
new file mode 100644
index 0000000000..262ffcd683
--- /dev/null
+++ b/board/advantech/imx8qm_dmsse20_a1/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright 2017 NXP
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += imx8qm_dmsse20_a1.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
diff --git a/board/advantech/imx8qm_dmsse20_a1/imx8qm_dmsse20_a1.c b/board/advantech/imx8qm_dmsse20_a1/imx8qm_dmsse20_a1.c
new file mode 100644
index 0000000000..c3c407e355
--- /dev/null
+++ b/board/advantech/imx8qm_dmsse20_a1/imx8qm_dmsse20_a1.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017-2018 NXP
+ * Copyright (C) 2020 Oliver Graute <oliver.graute(a)kococonnector.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <linux/libfdt.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/imx8-pins.h>
+#include <asm/arch/iomux.h>
+#include <asm/arch/sys_proto.h>
+/* #include <power-domain.h> */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define UART_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+static iomux_cfg_t uart0_pads[] = {
+ SC_P_UART0_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
+ SC_P_UART0_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
+};
+
+static void setup_iomux_uart(void)
+{
+ imx8_iomux_setup_multiple_pads(uart0_pads, ARRAY_SIZE(uart0_pads));
+}
+
+int board_early_init_f(void)
+{
+ sc_pm_clock_rate_t rate = SC_80MHZ;
+ int ret;
+
+ /* Set UART0 clock root to 80 MHz */
+ ret = sc_pm_setup_uart(SC_R_UART_0, rate);
+ if (ret)
+ return ret;
+
+ setup_iomux_uart();
+
+ /* This is needed to because Kernel do not Power Up DC_0 */
+ sc_pm_set_resource_power_mode(-1, SC_R_DC_0, SC_PM_PW_MODE_ON);
+ sc_pm_set_resource_power_mode(-1, SC_R_GPIO_5, SC_PM_PW_MODE_ON);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_FEC_MXC)
+#include <miiphy.h>
+
+int board_phy_config(struct phy_device *phydev)
+{
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x8);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x00);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x82ee);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
+
+ if (phydev->drv->config)
+ phydev->drv->config(phydev);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_MXC_GPIO
+
+#define LVDS_ENABLE IMX_GPIO_NR(1, 6)
+#define MIPI_ENABLE IMX_GPIO_NR(1, 7)
+
+#define BB_GPIO_3V3_1 IMX_GPIO_NR(4, 20)
+#define BB_GPIO_3V3_2 IMX_GPIO_NR(4, 24)
+#define BB_GPIO_3V3_3 IMX_GPIO_NR(4, 23)
+
+static void board_gpio_init(void)
+{
+ /* Enable BB 3V3 */
+ gpio_request(BB_GPIO_3V3_1, "bb_3v3_1");
+ gpio_direction_output(BB_GPIO_3V3_1, 1);
+ gpio_request(BB_GPIO_3V3_2, "bb_3v3_2");
+ gpio_direction_output(BB_GPIO_3V3_2, 1);
+ gpio_request(BB_GPIO_3V3_3, "bb_3v3_3");
+ gpio_direction_output(BB_GPIO_3V3_3, 1);
+
+ /* enable LVDS SAS boards */
+ gpio_request(LVDS_ENABLE, "lvds_enable");
+ gpio_direction_output(LVDS_ENABLE, 1);
+
+ /* enable MIPI SAS boards */
+ gpio_request(MIPI_ENABLE, "mipi_enable");
+ gpio_direction_output(MIPI_ENABLE, 1);
+}
+#endif
+
+int checkboard(void)
+{
+ puts("Board: DMS-SE20A1 8GB\n");
+ build_info();
+ print_bootinfo();
+
+ return 0;
+}
+
+int board_init(void)
+{
+ if (IS_ENABLED(CONFIG_XEN))
+ return 0;
+
+#ifdef CONFIG_MXC_GPIO
+ board_gpio_init();
+#endif
+
+ return 0;
+}
+
+void board_quiesce_devices(void)
+{
+ if (IS_ENABLED(CONFIG_XEN)) {
+ /* Clear magic number to let xen know uboot is over */
+ writel(0x0, (void __iomem *)0x80000000);
+ return;
+ }
+}
+
+void detail_board_ddr_info(void)
+{
+ puts("\nDDR ");
+}
+
+/*
+ * Board specific reset that is system reset.
+ */
+void reset_cpu(ulong addr)
+{
+ puts("SCI reboot request");
+
+ while (1)
+ putc('.');
+}
+
+#ifdef CONFIG_OF_BOARD_SETUP
+int ft_board_setup(void *blob, struct bd_info *bd)
+{
+ return 0;
+}
+#endif
+
+int board_mmc_get_env_dev(int devno)
+{
+ /* Use EMMC */
+ if (IS_ENABLED(CONFIG_XEN))
+ return 0;
+
+ return devno;
+}
+
+int mmc_map_to_kernel_blk(int dev_no)
+{
+ /* Use EMMC */
+ if (IS_ENABLED(CONFIG_XEN))
+ return 0;
+
+ return dev_no;
+}
+
+int board_late_init(void)
+{
+#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
+ env_set("board_name", "DMS-SE20A1");
+ env_set("board_rev", "iMX8QM");
+#endif
+
+ env_set("sec_boot", "no");
+#ifdef CONFIG_AHAB_BOOT
+ env_set("sec_boot", "yes");
+#endif
+
+ return 0;
+}
diff --git a/board/advantech/imx8qm_dmsse20_a1/imximage.cfg b/board/advantech/imx8qm_dmsse20_a1/imximage.cfg
new file mode 100644
index 0000000000..e324c7ca37
--- /dev/null
+++ b/board/advantech/imx8qm_dmsse20_a1/imximage.cfg
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ */
+
+#define __ASSEMBLY__
+
+/* Boot from SD, sector size 0x400 */
+BOOT_FROM SD 0x400
+/* SoC type IMX8QM */
+SOC_TYPE IMX8QM
+/* Append seco container image */
+APPEND mx8qm-ahab-container.img
+/* Create the 2nd container */
+CONTAINER
+/* Add scfw image with exec attribute */
+IMAGE SCU mx8qm-val-scfw-tcm.bin
+/* Add ATF image with exec attribute */
+IMAGE A35 bl31.bin 0x80000000
+/* Add U-Boot image with load attribute */
+DATA A35 u-boot-dtb.bin 0x80020000
diff --git a/board/advantech/imx8qm_dmsse20_a1/spl.c b/board/advantech/imx8qm_dmsse20_a1/spl.c
new file mode 100644
index 0000000000..06bb049c3a
--- /dev/null
+++ b/board/advantech/imx8qm_dmsse20_a1/spl.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017-2018 NXP
+ */
+#include <common.h>
+#include <dm.h>
+#include <spl.h>
+#include <fsl_esdhc.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/imx8-pins.h>
+#include <asm/arch/iomux.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ESDHC_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define ESDHC_CLK_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define ENET_INPUT_PAD_CTRL ((SC_PAD_CONFIG_OD_IN << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_18V_10MA << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define ENET_NORMAL_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_18V_10MA << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define FSPI_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define GPIO_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define I2C_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_DV_LOW << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define UART_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
+ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+ (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
+ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+#ifdef CONFIG_FSL_ESDHC_IMX
+
+#define USDHC1_CD_GPIO IMX_GPIO_NR(5, 22)
+#define USDHC2_CD_GPIO IMX_GPIO_NR(4, 12)
+
+static struct fsl_esdhc_cfg usdhc_cfg[CONFIG_SYS_FSL_USDHC_NUM] = {
+ {USDHC1_BASE_ADDR, 0, 8},
+ {USDHC3_BASE_ADDR, 0, 4},
+};
+
+static iomux_cfg_t emmc0[] = {
+ SC_P_EMMC0_CLK | MUX_PAD_CTRL(ESDHC_CLK_PAD_CTRL),
+ SC_P_EMMC0_CMD | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_DATA0 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_DATA1 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_DATA2 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_DATA3 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_DATA4 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_DATA5 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_DATA6 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_DATA7 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_RESET_B | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_EMMC0_STROBE | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+};
+
+static iomux_cfg_t usdhc2_sd[] = {
+ SC_P_USDHC2_CLK | MUX_PAD_CTRL(ESDHC_CLK_PAD_CTRL),
+ SC_P_USDHC2_CMD | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_USDHC2_DATA0 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_USDHC2_DATA1 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_USDHC2_DATA2 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_USDHC2_DATA3 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_USDHC2_RESET_B | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_USDHC2_WP | MUX_MODE_ALT(3) | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+ SC_P_USDHC2_CD_B | MUX_MODE_ALT(3) | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
+};
+
+void init_clk_usdhc(u32 index);
+int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg);
+int arch_cpu_init(void);
+int board_early_init_f(void);
+int timer_init(void);
+void board_init_r(gd_t *id, ulong dest_addr);
+
+int board_mmc_init(struct bd_info *bis)
+{
+ int i, ret;
+
+ /*
+ * According to the board_mmc_init() the following map is done:
+ * (U-Boot device node) (Physical Port)
+ * mmc0 USDHC1
+ * mmc1 USDHC2
+ * mmc2 USDHC3
+ */
+ for (i = 0; i < CONFIG_SYS_FSL_USDHC_NUM; i++) {
+ switch (i) {
+ case 0:
+ ret = sc_pm_set_resource_power_mode(-1, SC_R_SDHC_0, SC_PM_PW_MODE_ON);
+ if (ret != SC_ERR_NONE)
+ return ret;
+
+ imx8_iomux_setup_multiple_pads(emmc0, ARRAY_SIZE(emmc0));
+ init_clk_usdhc(0);
+ usdhc_cfg[i].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
+ break;
+ case 1:
+ ret = sc_pm_set_resource_power_mode(-1, SC_R_SDHC_2, SC_PM_PW_MODE_ON);
+ if (ret != SC_ERR_NONE)
+ return ret;
+ ret = sc_pm_set_resource_power_mode(-1, SC_R_GPIO_4, SC_PM_PW_MODE_ON);
+ if (ret != SC_ERR_NONE)
+ return ret;
+
+ imx8_iomux_setup_multiple_pads(usdhc2_sd, ARRAY_SIZE(usdhc2_sd));
+ init_clk_usdhc(2);
+ usdhc_cfg[i].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
+ gpio_request(USDHC2_CD_GPIO, "sd2_cd");
+ gpio_direction_input(USDHC2_CD_GPIO);
+ break;
+ default:
+ printf("Warning: you configured more USDHC controllers"
+ "(%d) than supported by the board\n", i + 1);
+ return 0;
+ }
+ ret = fsl_esdhc_initialize(bis, &usdhc_cfg[i]);
+ if (ret) {
+ printf("Warning: failed to initialize mmc dev %d\n", i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int board_mmc_getcd(struct mmc *mmc)
+{
+ struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+ int ret = 0;
+
+ switch (cfg->esdhc_base) {
+ case USDHC1_BASE_ADDR:
+ ret = 1;
+ break;
+ case USDHC2_BASE_ADDR:
+ ret = !gpio_get_value(USDHC1_CD_GPIO);
+ break;
+ case USDHC3_BASE_ADDR:
+ ret = !gpio_get_value(USDHC2_CD_GPIO);
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_FSL_ESDHC_IMX */
+
+void spl_board_init(void)
+{
+#if defined(CONFIG_SPL_SPI_SUPPORT)
+ if (sc_rm_is_resource_owned(-1, SC_R_FSPI_0)) {
+ if (sc_pm_set_resource_power_mode(-1, SC_R_FSPI_0, SC_PM_PW_MODE_ON))
+ puts("Warning: failed to initialize FSPI0\n");
+ }
+#endif
+
+ puts("Normal Boot\n");
+}
+
+void spl_board_prepare_for_boot(void)
+{
+#if defined(CONFIG_SPL_SPI_SUPPORT)
+ if (sc_rm_is_resource_owned(-1, SC_R_FSPI_0)) {
+ if (sc_pm_set_resource_power_mode(-1, SC_R_FSPI_0, SC_PM_PW_MODE_OFF))
+ puts("Warning: failed to turn off FSPI0\n");
+ }
+#endif
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+ /* Just empty function now - can't decide what to choose */
+ debug("%s: %s\n", __func__, name);
+
+ return 0;
+}
+#endif
+
+void board_init_f(ulong dummy)
+{
+ /* Clear global data */
+ memset((void *)gd, 0, sizeof(gd_t));
+
+ arch_cpu_init();
+
+ board_early_init_f();
+
+ timer_init();
+
+ preloader_console_init();
+
+ /* Clear the BSS. */
+ memset(__bss_start, 0, __bss_end - __bss_start);
+
+ board_init_r(NULL, 0);
+}
diff --git a/common/Kconfig b/common/Kconfig
index 2bce8c9ba1..8ccd2befd4 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -445,7 +445,7 @@ config BOARD_TYPES
config DISPLAY_CPUINFO
bool "Display information about the CPU during start up"
- default y if ARC|| ARM || NIOS2 || X86 || XTENSA || M68K
+ default y if ARC || ARM || NIOS2 || X86 || XTENSA || M68K
help
Display information about the CPU that U-Boot is running on
when U-Boot starts up. The function print_cpuinfo() is called
diff --git a/configs/imx8qm_dmsse20a1_defconfig b/configs/imx8qm_dmsse20a1_defconfig
new file mode 100644
index 0000000000..2d828f53f6
--- /dev/null
+++ b/configs/imx8qm_dmsse20a1_defconfig
@@ -0,0 +1,94 @@
+CONFIG_ARM=y
+CONFIG_SPL_SYS_ICACHE_OFF=y
+CONFIG_SPL_SYS_DCACHE_OFF=y
+CONFIG_ARCH_IMX8=y
+CONFIG_SYS_TEXT_BASE=0x80020000
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_TARGET_IMX8QM_DMSSE20_A1=y
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_ENV_OFFSET=0x80000
+CONFIG_SPL=y
+CONFIG_FIT=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_FIT_GENERATOR="arch/arm/mach-imx/mkimage_fit_atf.sh"
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/advantech/imx8qm_dmsse20_a1/imximage.cfg"
+CONFIG_OF_CONTROL=y
+CONFIG_CI_UDC=y
+CONFIG_DM_PCA953X=y
+CONFIG_BOOTDELAY=3
+CONFIG_LOG=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SPL_BOARD_INIT=y
+CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_SPL_POWER_SUPPORT=y
+CONFIG_SPL_POWER_DOMAIN=y
+CONFIG_SPL_WATCHDOG_SUPPORT=y
+CONFIG_HUSH_PARSER=y
+CONFIG_IMX_BOOTAUX=y
+CONFIG_FS_FAT=y
+CONFIG_FS_EXT4=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_MMC=y
+CONFIG_DM_MMC=y
+CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_MMC_UHS_SUPPORT=y
+CONFIG_MMC_HS400_SUPPORT=y
+CONFIG_MMC_BROKEN_CD=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FUSE=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_DEFAULT_DEVICE_TREE="imx8qm-dmsse20-a1"
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_SPL_DM=y
+CONFIG_SPL_CLK=y
+CONFIG_CLK_IMX8=y
+CONFIG_CPU=y
+CONFIG_DM_GPIO=y
+CONFIG_DM_I2C=y
+CONFIG_FSL_ESDHC_IMX=y
+CONFIG_PHYLIB=y
+CONFIG_PHY_ADDR_ENABLE=y
+CONFIG_PHY_ATHEROS=y
+CONFIG_DM_ETH=y
+# CONFIG_EFI_LOADER is not set
+CONFIG_FEC_MXC_SHARE_MDIO=y
+CONFIG_FEC_MXC_MDIO_BASE=0x5B040000
+CONFIG_FEC_MXC=y
+CONFIG_MII=y
+CONFIG_PINCTRL=y
+CONFIG_SPL_PINCTRL=y
+CONFIG_PINCTRL_IMX8=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_IMX8_POWER_DOMAIN=y
+CONFIG_DM_REGULATOR=y
+CONFIG_SPL_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_GPIO=y
+CONFIG_SPL_DM_REGULATOR_GPIO=y
+CONFIG_DM_SERIAL=y
+CONFIG_FSL_LPUART=y
+CONFIG_MISC=y
+CONFIG_SMC_FUSE=y
+CONFIG_BOOTAUX_RESERVED_MEM_BASE=0x88000000
+CONFIG_BOOTAUX_RESERVED_MEM_SIZE=0x08000000
+# CONFIG_DISPLAY_CPUINFO is not set
+CONFIG_SPL_TINY_MEMSET=y
+CONFIG_AHAB_BOOT=y
+CONFIG_SYS_I2C_IMX_LPI2C=y
+CONFIG_DM_RTC=y
+CONFIG_RTC_RV8803=y
+CONFIG_CMD_DATE=y
diff --git a/doc/board/advantech/imx8qm-dmsse20-a1.rst b/doc/board/advantech/imx8qm-dmsse20-a1.rst
new file mode 100644
index 0000000000..d6765ce77f
--- /dev/null
+++ b/doc/board/advantech/imx8qm-dmsse20-a1.rst
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+NXP i.MX8QM DMSSE20-a1 board
+============================
+
+Quick Start
+-----------
+
+- Build the ARM Trusted firmware binary
+- Get scfw_tcm.bin and ahab-container.img
+- Get imx-mkimage
+- Build U-Boot
+- Flash the binary into the SD card
+- Boot
+
+Get and Build the ARM Trusted Firmware
+--------------------------------------
+
+.. code-block:: bash
+
+ $ git clone https://source.codeaurora.org/external/imx/imx-atf
+ $ cd imx-atf/
+ $ git checkout origin/imx_4.14.78_1.0.0_ga -b imx_4.14.78_1.0.0_ga
+ $ make PLAT=imx8qm bl31
+
+Get scfw_tcm.bin and ahab-container.img
+---------------------------------------
+
+.. code-block:: bash
+
+ $ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/imx-sc-firmware-1.1.bin
+ $ chmod +x imx-sc-firmware-1.1.bin
+ $ ./imx-sc-firmware-1.1.bin
+ $ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.0.bin
+ $ chmod +x firmware-imx-8.0.bin
+ $ ./firmware-imx-8.0.bin
+
+Or use this to avoid running random scripts from the internet,
+but note that you must agree to the license the script displays:
+
+.. code-block:: bash
+
+ $ dd if=imx-sc-firmware-1.1.bin of=imx-sc-firmware-1.1.tar.bz2 bs=37185 skip=1
+ $ tar -xf imx-sc-firmware-1.1.tar.bz2
+ $ cp imx-sc-firmware-1.1/mx8qm-val-scfw-tcm.bin $(builddir)
+ $ dd if=firmware-imx-8.0.bin of=firmware-imx-8.0.tar.bz2 bs=37180 skip=1
+ $ tar -xf firmware-imx-8.0.tar.bz2
+ $ cp firmware-imx-8.0/firmware/seco/mx8qm-ahab-container.img $(builddir)
+
+Build U-Boot
+------------
+.. code-block:: bash
+
+ $ export ATF_LOAD_ADDR=0x80000000
+ $ export BL33_LOAD_ADDR=0x80020000
+ $ make imx8qm_dmsse20a1_defconfig
+ $ make u-boot.bin
+ $ make flash.bin
diff --git a/doc/board/advantech/index.rst b/doc/board/advantech/index.rst
index e9b198c5c3..125b98c1f7 100644
--- a/doc/board/advantech/index.rst
+++ b/doc/board/advantech/index.rst
@@ -7,3 +7,4 @@ Advantech
:maxdepth: 2
imx8qm-rom7720-a1.rst
+ imx8qm-dmsse20-a1.rst
diff --git a/include/configs/imx8qm_dmsse20.h b/include/configs/imx8qm_dmsse20.h
new file mode 100644
index 0000000000..e1dca2de90
--- /dev/null
+++ b/include/configs/imx8qm_dmsse20.h
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2017-2019 NXP
+ */
+
+#ifndef __IMX8QM_DMSSE20_H
+#define __IMX8QM_DMSSE20_H
+
+#include <linux/sizes.h>
+#include <asm/arch/imx-regs.h>
+#define CONFIG_REMAKE_ELF
+
+#define CONFIG_SPL_MAX_SIZE (124 * 1024)
+#define CONFIG_SPL_BSS_START_ADDR 0x00128000
+#define CONFIG_SPL_BSS_MAX_SIZE 0x1000 /* 4 KB */
+
+#define CONFIG_NR_DRAM_BANKS 4
+
+/* Flat Device Tree Definitions */
+#define CONFIG_OF_BOARD_SETUP
+
+#undef CONFIG_BOOTM_NETBSD
+
+#define CONFIG_FSL_USDHC
+#define CONFIG_SYS_FSL_ESDHC_ADDR 0
+#define USDHC1_BASE_ADDR 0x5B010000
+#define USDHC2_BASE_ADDR 0x5B020000
+#define USDHC3_BASE_ADDR 0x5B030000
+
+#define CONFIG_SUPPORT_EMMC_BOOT /* eMMC specific */
+
+#define CONFIG_ENV_OVERWRITE
+
+#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
+
+#define CONFIG_FEC_XCV_TYPE RGMII
+#define FEC_QUIRK_ENET_MAC
+
+#define CONFIG_PHY_GIGE /* Support for 1000BASE-X */
+
+/* ENET0 connects AR8031 on CPU board */
+#define CONFIG_FEC1_ENET_DEV 0
+
+/* ENET1 connects AR8031 on CPU board */
+#define CONFIG_FEC2_ENET_DEV 1
+#define CONFIG_FEC_MXC_PHYADDR 0x4
+#define IMX_FEC_BASE 0x5B040000
+/* FEC1 */
+#define IMX_FEC1_BASE 0x5B040000
+#define CONFIG_FEC1_MXC_PHYADDR 0x4
+#define CONFIG_ETHPRIME "eth0"
+/* FEC2 */
+#define IMX_FEC2_BASE 0x5B050000
+#define CONFIG_FEC2_MXC_PHYADDR 0x4
+#define CONFIG_ETHPRIME1 "eth1"
+
+#ifdef CONFIG_NAND_BOOT
+#define MFG_NAND_PARTITION "mtdparts=gpmi-nand:128m(boot),32m(kernel),16m(dtb),8m(misc),-(rootfs) "
+#else
+#define MFG_NAND_PARTITION ""
+#endif
+
+/* Initial environment variables */
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "script=boot.scr\0" \
+ "image=Image\0" \
+ "panel=NULL\0" \
+ "console=ttyLP0\0" \
+ "earlycon=lpuart32,0x5a060000\0" \
+ "fdt_addr=0x83000000\0" \
+ "boot_fdt=try\0" \
+ "fdt_file=imx8qm-dmsse20-a1.dtb\0" \
+ "mmcdev=" __stringify(CONFIG_SYS_MMC_ENV_DEV) "\0" \
+ "mmcpart=" __stringify(CONFIG_SYS_MMC_IMG_LOAD_PART) "\0" \
+ "mmcroot=" CONFIG_MMCROOT " rootwait rw\0" \
+ "mmcautodetect=yes\0" \
+ "mmcargs=setenv bootargs console=${console},${baudrate} earlycon=${earlycon},${baudrate} root=${mmcroot}\0 " \
+ "loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};\0" \
+ "bootscript=echo Running bootscript from mmc ...; " \
+ "source\0" \
+ "loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
+ "loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
+ "mmcboot=echo Booting from mmc ...; " \
+ "run mmcargs; " \
+ "if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
+ "if run loadfdt; then " \
+ "booti ${loadaddr} - ${fdt_addr}; " \
+ "else " \
+ "echo WARN: Cannot load the DT; " \
+ "fi; " \
+ "else " \
+ "echo wait for boot; " \
+ "fi;\0" \
+ "netargs=setenv bootargs console=${console},${baudrate} earlycon=${earlycon},${baudrate} " \
+ "root=/dev/nfs " \
+ "ip=dhcp mac=${ethaddr} nfsroot=${serverip}:${nfsroot},v3,tcp rw\0" \
+ "netboot=echo Booting from net ...; " \
+ "run netargs; " \
+ "if test ${ip_dyn} = yes; then " \
+ "setenv get_cmd dhcp; " \
+ "else " \
+ "setenv get_cmd tftp; " \
+ "fi; " \
+ "${get_cmd} ${loadaddr} ${image}; " \
+ "if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
+ "if ${get_cmd} ${fdt_addr} ${fdt_file}; then " \
+ "booti ${loadaddr} - ${fdt_addr}; " \
+ "else " \
+ "echo WARN: Cannot load the DT; " \
+ "fi; " \
+ "else " \
+ "booti; " \
+ "fi;\0"
+
+#define CONFIG_BOOTCOMMAND \
+ "mmc dev ${mmcdev}; if mmc rescan; then " \
+ "if run loadbootscript; then " \
+ "run bootscript; " \
+ "else " \
+ "if run loadimage; then " \
+ "run mmcboot; " \
+ "else run netboot; " \
+ "fi; " \
+ "fi; " \
+ "else booti ${loadaddr} - ${fdt_addr}; fi"
+
+/* Link Definitions */
+#define CONFIG_LOADADDR 0x80280000
+
+#define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR
+
+#define CONFIG_SYS_INIT_SP_ADDR 0x80200000
+
+/* Default environment is in SD */
+
+#ifdef CONFIG_QSPI_BOOT
+#define CONFIG_ENV_SECT_SIZE (128 * 1024)
+#define CONFIG_ENV_SPI_BUS CONFIG_SF_DEFAULT_BUS
+#define CONFIG_ENV_SPI_CS CONFIG_SF_DEFAULT_CS
+#define CONFIG_ENV_SPI_MODE CONFIG_SF_DEFAULT_MODE
+#define CONFIG_ENV_SPI_MAX_HZ CONFIG_SF_DEFAULT_SPEED
+#else
+#define CONFIG_SYS_MMC_ENV_PART 0 /* user area */
+#endif
+
+#define CONFIG_SYS_MMC_IMG_LOAD_PART 0
+
+#define CONFIG_SYS_MMC_ENV_DEV 2 /* USDHC3 */
+#define CONFIG_MMCROOT "/dev/mmcblk1p2" /* USDHC3 */
+#define CONFIG_SYS_FSL_USDHC_NUM 2
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN ((CONFIG_ENV_SIZE + (32 * 1024)) * 1024)
+
+#define CONFIG_SYS_SDRAM_BASE 0x080000000
+#define PHYS_SDRAM_1 0x080000000
+#define PHYS_SDRAM_2 0x880000000
+#define PHYS_SDRAM_1_SIZE 0x080000000 /* 2 GB */
+#define PHYS_SDRAM_2_SIZE 0x180000000 /* 6 GB */
+
+#define CONFIG_SYS_MEMTEST_START 0xA0000000
+#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + (PHYS_SDRAM_1_SIZE >> 2))
+
+/* Serial */
+#define CONFIG_BAUDRATE 115200
+
+/* Generic Timer Definitions */
+#define COUNTER_FREQUENCY 8000000 /* 8MHz */
+
+#define CONFIG_IMX_SMMU
+
+/* MT35XU512ABA1G12 has only one Die, so QSPI0 B won't work */
+#ifdef CONFIG_FSL_FSPI
+#define CONFIG_SF_DEFAULT_BUS 0
+#define CONFIG_SF_DEFAULT_CS 0
+#define CONFIG_SF_DEFAULT_SPEED 40000000
+#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0
+#define FSL_FSPI_FLASH_SIZE SZ_64M
+#define FSL_FSPI_FLASH_NUM 1
+#define FSPI0_BASE_ADDR 0x5d120000
+#define FSPI0_AMBA_BASE 0
+#define CONFIG_SYS_FSL_FSPI_AHB
+#endif
+
+/* #define CONFIG_OF_SYSTEM_SETUP */
+
+#endif /* __IMX8QM_DMSSE20_H */
--
2.17.1
3
2
From: Peng Fan <peng.fan(a)nxp.com>
Current code has a force clk_set_defaults in multiple stages,
U-Boot reuse the same device tree and Linux Kernel device tree,
but we not register all the clks as Linux Kernel, so clk_set_defaults
will fail and cause the clk provider registeration fail.
So introduce a new property to ignore the default settings which could
be used by any node that wanna ignore default settings.
Reviewed-by: Simon Glass <sjg(a)chromium.org>
Signed-off-by: Peng Fan <peng.fan(a)nxp.com>
---
V2:
Add R-b tag
Tom, Simon
After a thought, I think still put it as a u-boot thing. assigned-clock-x is
actually Linux specific, however I could not add the new property to Linux,
because we are supporting SystemReady-IR, we need the assigned-clock-x property
in linux working and ignore it in U-Boot.
doc/device-tree-bindings/device.txt | 3 +++
drivers/clk/clk-uclass.c | 3 +++
2 files changed, 6 insertions(+)
diff --git a/doc/device-tree-bindings/device.txt b/doc/device-tree-bindings/device.txt
index 73ce2a3b5b..fe34ced268 100644
--- a/doc/device-tree-bindings/device.txt
+++ b/doc/device-tree-bindings/device.txt
@@ -28,6 +28,9 @@ the acpi,compatible property.
Linux will only load the driver if the device can be detected (e.g. on I2C
bus). Note that this is an out-of-tree Linux feature.
+Common device bindings that could be shared listed below:
+ - u-boot,ignore-clk-defaults : ignore the assigned-clock-parents
+ and assigned-clock-rates for a device that has the property.
Example
-------
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 493018b33e..6bf3179e7b 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -376,6 +376,9 @@ int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage)
if (!dev_has_ofnode(dev))
return 0;
+ if (ofnode_get_property(dev_ofnode(dev), "u-boot,ignore-clk-defaults", NULL))
+ return 0;
+
/*
* To avoid setting defaults twice, don't set them before relocation.
* However, still set them for SPL. And still set them if explicitly
--
2.30.0
5
20