[PATCH RFC 00/20] MIPS: Add support for JZ4730 and Skytone Alpha 400

Hi,
chained to his message are patches that implement support for the Ingenic JZ4730 MIPS SoC and a laptop that's based around it.
Please consider this RFC-quality: there are some known issues that need to be resolved before some of the patches could be applied (indicated in some of the patches themselves) and there are also certainly issues unknown to me that would be obvious to others given I haven't really submitted code to U-Boot apart from some very trifial stuff. I'll be very thankful for any feeback.
The hardware support added by this patch set is essentially equivalent to vendor U-Boot that's shipped with the machine: boot off NAND works, MMC, UART and Ethernet are supported. LCD, GPIO matrix keyboard and OHCI USB don't work at this point. CONFIG_DISTRO_DEFAULT makes it convenient to run custom kernels in place of the vendor's one, but the compatibility with the vendor kernels is retained.
The first three patches are not actually JZ4730 specific, but they are dependend on by the JZ4730 work:
[PATCH RFC 01/20] config: Remove CONFIG_SYS_ID_EEPROM [PATCH RFC 02/20] mtd: Allow building nand_spl_simple w/o SPL_NAND_ECC [PATCH RFC 03/20] cmd/mac: Don't build unless CONFIG_CMD_MAC is enabled
The rest of the patches implement JZ4730 hardware support:
[PATCH RFC 04/20] mips: Don't access CP0_EBASE on JZ47XX [PATCH RFC 05/20] ns16550: Turn on the UME bit if on ARCH_JZ47XX [PATCH RFC 06/20] clk: Add driver for Ingenic JZ4730 CGU [PATCH RFC 07/20] timer-uclass: Tolerate failure to get clock rate in [PATCH RFC 08/20] timer: Add Ingenic JZ4730 timer driver [PATCH RFC 09/20] mmc: Default to JZ47XX_MMC=y on ARCH_JZ47XX [PATCH RFC 10/20] mmc/jz_mmc: Add a JZ4740 compatible string [PATCH RFC 11/20] mmc/jz_mmc: Support wp-gpio/cd-gpio [PATCH RFC 12/20] pinctrl: Add Ingenic JZ4730 pin control and GPIO driver [PATCH RFC 13/20] nand: Use correct prototype of board_nand_init() with [PATCH RFC 14/20] nand/raw: Add Ingenic JZ4730 NAND flash driver [PATCH RFC 15/20] watchdog: Add Ingenic JZ4730 watchdog timer driver [PATCH RFC 16/20] net: Add Ingenic JZ4730 Ethernet driver [PATCH RFC 17/20] mips: dts: Add Ingenic JZ4730 [PATCH RFC 18/20] mips/mach-jz47xx: Add Ingenic JZ4730 support [PATCH RFC 19/20] mips: dts: Add Skytone Alpha 400 [PATCH RFC 20/20] board: Add Skytone Alpha 400
In case someone finds git more convenient to work with than e-mail, here you go:
git pull git://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/u-boot.git lr/alpha400
Thank you Lubo

It seems to be a vestige of a somewhat messed up attempt to rename CFG_ID_EEPROM -- the name that actually got used is CONFIG_ID_EEPROM. Remove it.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- include/configs/MPC8541CDS.h | 1 - include/configs/MPC8548CDS.h | 1 - include/configs/MPC8555CDS.h | 1 - scripts/config_whitelist.txt | 1 - 4 files changed, 4 deletions(-)
diff --git a/include/configs/MPC8541CDS.h b/include/configs/MPC8541CDS.h index b1c8917f216..58d5ed158a3 100644 --- a/include/configs/MPC8541CDS.h +++ b/include/configs/MPC8541CDS.h @@ -241,7 +241,6 @@ extern unsigned long get_clock_freq(void); /* EEPROM */ #define CONFIG_ID_EEPROM #define CONFIG_SYS_I2C_EEPROM_CCID -#define CONFIG_SYS_ID_EEPROM #define CONFIG_SYS_I2C_EEPROM_ADDR 0x57 #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
diff --git a/include/configs/MPC8548CDS.h b/include/configs/MPC8548CDS.h index 4efc182ef83..4fce6be8407 100644 --- a/include/configs/MPC8548CDS.h +++ b/include/configs/MPC8548CDS.h @@ -312,7 +312,6 @@ extern unsigned long get_clock_freq(void); /* EEPROM */ #define CONFIG_ID_EEPROM #define CONFIG_SYS_I2C_EEPROM_CCID -#define CONFIG_SYS_ID_EEPROM #define CONFIG_SYS_I2C_EEPROM_ADDR 0x57 #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
diff --git a/include/configs/MPC8555CDS.h b/include/configs/MPC8555CDS.h index 88999ef2b85..8e4ba3601ab 100644 --- a/include/configs/MPC8555CDS.h +++ b/include/configs/MPC8555CDS.h @@ -239,7 +239,6 @@ extern unsigned long get_clock_freq(void); /* EEPROM */ #define CONFIG_ID_EEPROM #define CONFIG_SYS_I2C_EEPROM_CCID -#define CONFIG_SYS_ID_EEPROM #define CONFIG_SYS_I2C_EEPROM_ADDR 0x57 #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 0aabe7a4516..291de2a65ac 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -2789,7 +2789,6 @@ CONFIG_SYS_ICACHE_INV CONFIG_SYS_ICS8N3QV01_I2C CONFIG_SYS_IDE_MAXBUS CONFIG_SYS_IDE_MAXDEVICE -CONFIG_SYS_ID_EEPROM CONFIG_SYS_IFC_ADDR CONFIG_SYS_IFC_CCR CONFIG_SYS_INIT_DBCR

The Skytone Alpha 400 boards don't use ECC.
It's probably and oversignt and certainly a bad idea, nevertheless enforcing ECC on existing boards would break boot. Sigh.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/mtd/nand/raw/nand_spl_simple.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_spl_simple.c b/drivers/mtd/nand/raw/nand_spl_simple.c index 09e053541a9..ea5bcaf3982 100644 --- a/drivers/mtd/nand/raw/nand_spl_simple.c +++ b/drivers/mtd/nand/raw/nand_spl_simple.c @@ -9,14 +9,16 @@ #include <asm/io.h> #include <linux/mtd/nand_ecc.h>
-static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; static struct mtd_info *mtd; static struct nand_chip nand_chip;
+#if IS_ENABLED(CONFIG_SPL_NAND_ECC) +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; + #define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ CONFIG_SYS_NAND_ECCSIZE) #define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) - +#endif
#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512) /* @@ -166,7 +168,7 @@ static int nand_read_page(int block, int page, uchar *dst)
return 0; } -#else +#elif IS_ENABLED(CONFIG_SPL_NAND_ECC) static int nand_read_page(int block, int page, void *dst) { struct nand_chip *this = mtd_to_nand(mtd); @@ -206,6 +208,16 @@ static int nand_read_page(int block, int page, void *dst)
return 0; } +#else +static int nand_read_page(int block, int page, void *dst) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + nand_command(block, page, 0, NAND_CMD_READ0); + this->read_buf(mtd, dst, CONFIG_SYS_NAND_PAGE_SIZE); + + return 0; +} #endif
/* nand_init() - initialize data to make nand usable by SPL */

This allows us to enable CONFIG_ID_EEPROM to add a hook to read ethaddr off a ROM without having to implement do_mac().
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- arch/arm/Kconfig | 19 +++++++++++++++++++ arch/powerpc/cpu/mpc85xx/Kconfig | 17 +++++++++++++++++ cmd/Kconfig | 3 +++ cmd/Makefile | 2 +- 4 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b2f7fcbd6ec..884e6f11365 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1245,6 +1245,7 @@ config TARGET_LS1088AQDS select BOARD_LATE_INIT select SUPPORT_SPL select FSL_DDR_INTERACTIVE if !SD_BOOT + select CMD_MAC help Support for NXP LS1088AQDS platform. The LS1088A Development System (QDS) is a high-performance @@ -1263,6 +1264,7 @@ config TARGET_LS2080AQDS imply SCSI_AHCI select FSL_DDR_BIST select FSL_DDR_INTERACTIVE if !SPL + select CMD_MAC help Support for Freescale LS2080AQDS platform. The LS2080A Development System (QDS) is a high-performance @@ -1279,6 +1281,7 @@ config TARGET_LS2080ARDB select SUPPORT_SPL select FSL_DDR_BIST select FSL_DDR_INTERACTIVE if !SPL + select CMD_MAC imply SCSI imply SCSI_AHCI help @@ -1294,6 +1297,7 @@ config TARGET_LS2081ARDB select ARMV8_MULTIENTRY select BOARD_LATE_INIT select SUPPORT_SPL + select CMD_MAC help Support for Freescale LS2081ARDB platform. The LS2081A Reference design board (RDB) is a high-performance @@ -1307,6 +1311,7 @@ config TARGET_LX2160ARDB select ARMV8_MULTIENTRY select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT + select CMD_MAC help Support for NXP LX2160ARDB platform. The lx2160ardb (LX2160A Reference design board (RDB) @@ -1320,6 +1325,7 @@ config TARGET_LX2160AQDS select ARMV8_MULTIENTRY select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT + select CMD_MAC help Support for NXP LX2160AQDS platform. The lx2160aqds (LX2160A QorIQ Development System (QDS) @@ -1373,6 +1379,7 @@ config TARGET_LS1012AQDS select ARM64 select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT + select CMD_MAC help Support for Freescale LS1012AQDS platform. The LS1012A Development System (QDS) is a high-performance @@ -1438,6 +1445,7 @@ config TARGET_LS1028AQDS select ARMV8_MULTIENTRY select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT + select CMD_MAC help Support for Freescale LS1028AQDS platform The LS1028A Development System (QDS) is a high-performance @@ -1451,6 +1459,7 @@ config TARGET_LS1028ARDB select ARMV8_MULTIENTRY select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT + select CMD_MAC help Support for Freescale LS1028ARDB platform The LS1028A Development System (RDB) is a high-performance @@ -1466,6 +1475,7 @@ config TARGET_LS1088ARDB select BOARD_LATE_INIT select SUPPORT_SPL select FSL_DDR_INTERACTIVE if !SD_BOOT + select CMD_MAC help Support for NXP LS1088ARDB platform. The LS1088A Reference design board (RDB) is a high-performance @@ -1487,6 +1497,7 @@ config TARGET_LS1021AQDS select FSL_DDR_INTERACTIVE select DM_SPI_FLASH if FSL_DSPI || FSL_QSPI select SPI_FLASH_DATAFLASH if FSL_DSPI || FSL_QSPI + select CMD_MAC imply SCSI
config TARGET_LS1021ATWR @@ -1501,6 +1512,7 @@ config TARGET_LS1021ATWR select LS1_DEEP_SLEEP select SUPPORT_SPL select DM_SPI_FLASH if FSL_DSPI || FSL_QSPI + select CMD_MAC imply SCSI
config TARGET_LS1021ATSN @@ -1514,6 +1526,7 @@ config TARGET_LS1021ATSN select CPU_V7_HAS_VIRT select LS1_DEEP_SLEEP select SUPPORT_SPL + select CMD_MAC imply SCSI
config TARGET_LS1021AIOT @@ -1526,6 +1539,7 @@ config TARGET_LS1021AIOT select CPU_V7_HAS_VIRT select SUPPORT_SPL select DM_SPI_FLASH if FSL_DSPI || FSL_QSPI + select CMD_MAC imply SCSI help Support for Freescale LS1021AIOT platform. @@ -1545,6 +1559,7 @@ config TARGET_LS1043AQDS select FSL_DDR_INTERACTIVE if !SPL select FSL_DSPI if !SPL_NO_DSPI select DM_SPI_FLASH if FSL_DSPI + select CMD_MAC imply SCSI imply SCSI_AHCI help @@ -1561,6 +1576,7 @@ config TARGET_LS1043ARDB select SUPPORT_SPL select FSL_DSPI if !SPL_NO_DSPI select DM_SPI_FLASH if FSL_DSPI + select CMD_MAC help Support for Freescale LS1043ARDB platform.
@@ -1577,6 +1593,7 @@ config TARGET_LS1046AQDS select FSL_DDR_BIST if !SPL select FSL_DDR_INTERACTIVE if !SPL select FSL_DDR_INTERACTIVE if !SPL + select CMD_MAC imply SCSI help Support for Freescale LS1046AQDS platform. @@ -1597,6 +1614,7 @@ config TARGET_LS1046ARDB select SUPPORT_SPL select FSL_DDR_BIST select FSL_DDR_INTERACTIVE if !SPL + select CMD_MAC imply SCSI help Support for Freescale LS1046ARDB platform. @@ -1613,6 +1631,7 @@ config TARGET_LS1046AFRWY select BOARD_EARLY_INIT_F select BOARD_LATE_INIT select DM_SPI_FLASH if DM_SPI + select CMD_MAC imply SCSI help Support for Freescale LS1046AFRWY platform. diff --git a/arch/powerpc/cpu/mpc85xx/Kconfig b/arch/powerpc/cpu/mpc85xx/Kconfig index 54c7fd9522a..a1bbab64991 100644 --- a/arch/powerpc/cpu/mpc85xx/Kconfig +++ b/arch/powerpc/cpu/mpc85xx/Kconfig @@ -29,6 +29,7 @@ config TARGET_P3041DS select PHYS_64BIT select ARCH_P3041 select BOARD_LATE_INIT if CHAIN_OF_TRUST + select CMD_MAC imply CMD_SATA imply PANIC_HANG
@@ -37,6 +38,7 @@ config TARGET_P4080DS select PHYS_64BIT select ARCH_P4080 select BOARD_LATE_INIT if CHAIN_OF_TRUST + select CMD_MAC imply CMD_SATA imply PANIC_HANG
@@ -45,12 +47,14 @@ config TARGET_P5040DS select PHYS_64BIT select ARCH_P5040 select BOARD_LATE_INIT if CHAIN_OF_TRUST + select CMD_MAC imply CMD_SATA imply PANIC_HANG
config TARGET_MPC8541CDS bool "Support MPC8541CDS" select ARCH_MPC8541 + select CMD_MAC
config TARGET_MPC8544DS bool "Support MPC8544DS" @@ -60,10 +64,12 @@ config TARGET_MPC8544DS config TARGET_MPC8548CDS bool "Support MPC8548CDS" select ARCH_MPC8548 + select CMD_MAC
config TARGET_MPC8555CDS bool "Support MPC8555CDS" select ARCH_MPC8555 + select CMD_MAC
config TARGET_MPC8568MDS bool "Support MPC8568MDS" @@ -72,12 +78,14 @@ config TARGET_MPC8568MDS config TARGET_MPC8569MDS bool "Support MPC8569MDS" select ARCH_MPC8569 + select CMD_MAC
config TARGET_MPC8572DS bool "Support MPC8572DS" select ARCH_MPC8572 # Use DDR3 controller with DDR2 DIMMs on this board select SYS_FSL_DDRC_GEN3 + select CMD_MAC imply SCSI imply PANIC_HANG
@@ -97,6 +105,7 @@ config TARGET_P1010RDB_PB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select SUPPORT_TPL + select CMD_MAC imply CMD_EEPROM imply CMD_SATA imply PANIC_HANG @@ -133,6 +142,7 @@ config TARGET_P2041RDB select ARCH_P2041 select BOARD_LATE_INIT if CHAIN_OF_TRUST select PHYS_64BIT + select CMD_MAC imply CMD_SATA imply FSL_SATA
@@ -148,6 +158,7 @@ config TARGET_T1023RDB select SUPPORT_SPL select PHYS_64BIT select FSL_DDR_INTERACTIVE + select CMD_MAC imply CMD_EEPROM imply PANIC_HANG
@@ -158,6 +169,7 @@ config TARGET_T1024RDB select SUPPORT_SPL select PHYS_64BIT select FSL_DDR_INTERACTIVE + select CMD_MAC imply CMD_EEPROM imply PANIC_HANG
@@ -213,6 +225,7 @@ config TARGET_T2080QDS select PHYS_64BIT select FSL_DDR_FIRST_SLOT_QUAD_CAPABLE select FSL_DDR_INTERACTIVE + select CMD_MAC imply CMD_SATA
config TARGET_T2080RDB @@ -221,6 +234,7 @@ config TARGET_T2080RDB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT + select CMD_MAC imply CMD_SATA imply PANIC_HANG
@@ -231,6 +245,7 @@ config TARGET_T2081QDS select PHYS_64BIT select FSL_DDR_FIRST_SLOT_QUAD_CAPABLE select FSL_DDR_INTERACTIVE + select CMD_MAC
config TARGET_T4160RDB bool "Support T4160RDB" @@ -280,12 +295,14 @@ config TARGET_CYRUS_P5020 bool "Support Varisys Cyrus P5020" select ARCH_P5020 select PHYS_64BIT + select CMD_MAC imply PANIC_HANG
config TARGET_CYRUS_P5040 bool "Support Varisys Cyrus P5040" select ARCH_P5040 select PHYS_64BIT + select CMD_MAC imply PANIC_HANG
endchoice diff --git a/cmd/Kconfig b/cmd/Kconfig index 1595de999b5..652e9cc4f88 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1696,6 +1696,9 @@ config CMD_LED with led on/off/togle/blink. Any LED drivers can be controlled with this command, e.g. led_gpio.
+config CMD_MAC + bool + config CMD_DATE bool "date" default y if DM_RTC diff --git a/cmd/Makefile b/cmd/Makefile index dd86675bf2a..9d85217b544 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -88,7 +88,7 @@ obj-$(CONFIG_CMD_LICENSE) += license.o obj-y += load.o obj-$(CONFIG_CMD_LOG) += log.o obj-$(CONFIG_CMD_LSBLK) += lsblk.o -obj-$(CONFIG_ID_EEPROM) += mac.o +obj-$(CONFIG_CMD_MAC) += mac.o obj-$(CONFIG_CMD_MD5SUM) += md5sum.o obj-$(CONFIG_CMD_MEMORY) += mem.o obj-$(CONFIG_CMD_IO) += io.o

Am Dienstag, den 17.11.2020, 22:00 +0100 schrieb Lubomir Rintel:
This allows us to enable CONFIG_ID_EEPROM to add a hook to read ethaddr off a ROM without having to implement do_mac().
Signed-off-by: Lubomir Rintel lkundrak@v3.sk
arch/arm/Kconfig | 19 +++++++++++++++++++ arch/powerpc/cpu/mpc85xx/Kconfig | 17 +++++++++++++++++
you should also cc Tom Rini and Priyanka Jain priyanka.jain@nxp.com
cmd/Kconfig | 3 +++ cmd/Makefile | 2 +- 4 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b2f7fcbd6ec..884e6f11365 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1245,6 +1245,7 @@ config TARGET_LS1088AQDS select BOARD_LATE_INIT select SUPPORT_SPL select FSL_DDR_INTERACTIVE if !SD_BOOT
- select CMD_MAC
commands should be selected with "imply CMD_XXX" so the user can deselect them when needed. This also means that CMD_MAC should be visible to the user:
config CMD_MAC bool "mac"
help Support for NXP LS1088AQDS platform. The LS1088A Development System (QDS) is a high-performance @@ -1263,6 +1264,7 @@ config TARGET_LS2080AQDS imply SCSI_AHCI select FSL_DDR_BIST select FSL_DDR_INTERACTIVE if !SPL
- select CMD_MAC help Support for Freescale LS2080AQDS platform. The LS2080A Development System (QDS) is a high-performance
@@ -1279,6 +1281,7 @@ config TARGET_LS2080ARDB select SUPPORT_SPL select FSL_DDR_BIST select FSL_DDR_INTERACTIVE if !SPL
- select CMD_MAC imply SCSI imply SCSI_AHCI help
@@ -1294,6 +1297,7 @@ config TARGET_LS2081ARDB select ARMV8_MULTIENTRY select BOARD_LATE_INIT select SUPPORT_SPL
- select CMD_MAC help Support for Freescale LS2081ARDB platform. The LS2081A Reference design board (RDB) is a high-performance
@@ -1307,6 +1311,7 @@ config TARGET_LX2160ARDB select ARMV8_MULTIENTRY select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT
- select CMD_MAC help Support for NXP LX2160ARDB platform. The lx2160ardb (LX2160A Reference design board (RDB)
@@ -1320,6 +1325,7 @@ config TARGET_LX2160AQDS select ARMV8_MULTIENTRY select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT
- select CMD_MAC help Support for NXP LX2160AQDS platform. The lx2160aqds (LX2160A QorIQ Development System (QDS)
@@ -1373,6 +1379,7 @@ config TARGET_LS1012AQDS select ARM64 select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT
- select CMD_MAC help Support for Freescale LS1012AQDS platform. The LS1012A Development System (QDS) is a high-performance
@@ -1438,6 +1445,7 @@ config TARGET_LS1028AQDS select ARMV8_MULTIENTRY select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT
- select CMD_MAC help Support for Freescale LS1028AQDS platform The LS1028A Development System (QDS) is a high-performance
@@ -1451,6 +1459,7 @@ config TARGET_LS1028ARDB select ARMV8_MULTIENTRY select ARCH_SUPPORT_TFABOOT select BOARD_LATE_INIT
- select CMD_MAC help Support for Freescale LS1028ARDB platform The LS1028A Development System (RDB) is a high-performance
@@ -1466,6 +1475,7 @@ config TARGET_LS1088ARDB select BOARD_LATE_INIT select SUPPORT_SPL select FSL_DDR_INTERACTIVE if !SD_BOOT
- select CMD_MAC help Support for NXP LS1088ARDB platform. The LS1088A Reference design board (RDB) is a high-performance
@@ -1487,6 +1497,7 @@ config TARGET_LS1021AQDS select FSL_DDR_INTERACTIVE select DM_SPI_FLASH if FSL_DSPI || FSL_QSPI select SPI_FLASH_DATAFLASH if FSL_DSPI || FSL_QSPI
- select CMD_MAC imply SCSI
config TARGET_LS1021ATWR @@ -1501,6 +1512,7 @@ config TARGET_LS1021ATWR select LS1_DEEP_SLEEP select SUPPORT_SPL select DM_SPI_FLASH if FSL_DSPI || FSL_QSPI
- select CMD_MAC imply SCSI
config TARGET_LS1021ATSN @@ -1514,6 +1526,7 @@ config TARGET_LS1021ATSN select CPU_V7_HAS_VIRT select LS1_DEEP_SLEEP select SUPPORT_SPL
- select CMD_MAC imply SCSI
config TARGET_LS1021AIOT @@ -1526,6 +1539,7 @@ config TARGET_LS1021AIOT select CPU_V7_HAS_VIRT select SUPPORT_SPL select DM_SPI_FLASH if FSL_DSPI || FSL_QSPI
- select CMD_MAC imply SCSI help Support for Freescale LS1021AIOT platform.
@@ -1545,6 +1559,7 @@ config TARGET_LS1043AQDS select FSL_DDR_INTERACTIVE if !SPL select FSL_DSPI if !SPL_NO_DSPI select DM_SPI_FLASH if FSL_DSPI
- select CMD_MAC imply SCSI imply SCSI_AHCI help
@@ -1561,6 +1576,7 @@ config TARGET_LS1043ARDB select SUPPORT_SPL select FSL_DSPI if !SPL_NO_DSPI select DM_SPI_FLASH if FSL_DSPI
- select CMD_MAC help Support for Freescale LS1043ARDB platform.
@@ -1577,6 +1593,7 @@ config TARGET_LS1046AQDS select FSL_DDR_BIST if !SPL select FSL_DDR_INTERACTIVE if !SPL select FSL_DDR_INTERACTIVE if !SPL
- select CMD_MAC imply SCSI help Support for Freescale LS1046AQDS platform.
@@ -1597,6 +1614,7 @@ config TARGET_LS1046ARDB select SUPPORT_SPL select FSL_DDR_BIST select FSL_DDR_INTERACTIVE if !SPL
- select CMD_MAC imply SCSI help Support for Freescale LS1046ARDB platform.
@@ -1613,6 +1631,7 @@ config TARGET_LS1046AFRWY select BOARD_EARLY_INIT_F select BOARD_LATE_INIT select DM_SPI_FLASH if DM_SPI
- select CMD_MAC imply SCSI help Support for Freescale LS1046AFRWY platform.
diff --git a/arch/powerpc/cpu/mpc85xx/Kconfig b/arch/powerpc/cpu/mpc85xx/Kconfig index 54c7fd9522a..a1bbab64991 100644 --- a/arch/powerpc/cpu/mpc85xx/Kconfig +++ b/arch/powerpc/cpu/mpc85xx/Kconfig @@ -29,6 +29,7 @@ config TARGET_P3041DS select PHYS_64BIT select ARCH_P3041 select BOARD_LATE_INIT if CHAIN_OF_TRUST
- select CMD_MAC imply CMD_SATA imply PANIC_HANG
@@ -37,6 +38,7 @@ config TARGET_P4080DS select PHYS_64BIT select ARCH_P4080 select BOARD_LATE_INIT if CHAIN_OF_TRUST
- select CMD_MAC imply CMD_SATA imply PANIC_HANG
@@ -45,12 +47,14 @@ config TARGET_P5040DS select PHYS_64BIT select ARCH_P5040 select BOARD_LATE_INIT if CHAIN_OF_TRUST
- select CMD_MAC imply CMD_SATA imply PANIC_HANG
config TARGET_MPC8541CDS bool "Support MPC8541CDS" select ARCH_MPC8541
- select CMD_MAC
config TARGET_MPC8544DS bool "Support MPC8544DS" @@ -60,10 +64,12 @@ config TARGET_MPC8544DS config TARGET_MPC8548CDS bool "Support MPC8548CDS" select ARCH_MPC8548
- select CMD_MAC
config TARGET_MPC8555CDS bool "Support MPC8555CDS" select ARCH_MPC8555
- select CMD_MAC
config TARGET_MPC8568MDS bool "Support MPC8568MDS" @@ -72,12 +78,14 @@ config TARGET_MPC8568MDS config TARGET_MPC8569MDS bool "Support MPC8569MDS" select ARCH_MPC8569
- select CMD_MAC
config TARGET_MPC8572DS bool "Support MPC8572DS" select ARCH_MPC8572 # Use DDR3 controller with DDR2 DIMMs on this board select SYS_FSL_DDRC_GEN3
- select CMD_MAC imply SCSI imply PANIC_HANG
@@ -97,6 +105,7 @@ config TARGET_P1010RDB_PB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select SUPPORT_TPL
- select CMD_MAC imply CMD_EEPROM imply CMD_SATA imply PANIC_HANG
@@ -133,6 +142,7 @@ config TARGET_P2041RDB select ARCH_P2041 select BOARD_LATE_INIT if CHAIN_OF_TRUST select PHYS_64BIT
- select CMD_MAC imply CMD_SATA imply FSL_SATA
@@ -148,6 +158,7 @@ config TARGET_T1023RDB select SUPPORT_SPL select PHYS_64BIT select FSL_DDR_INTERACTIVE
- select CMD_MAC imply CMD_EEPROM imply PANIC_HANG
@@ -158,6 +169,7 @@ config TARGET_T1024RDB select SUPPORT_SPL select PHYS_64BIT select FSL_DDR_INTERACTIVE
- select CMD_MAC imply CMD_EEPROM imply PANIC_HANG
@@ -213,6 +225,7 @@ config TARGET_T2080QDS select PHYS_64BIT select FSL_DDR_FIRST_SLOT_QUAD_CAPABLE select FSL_DDR_INTERACTIVE
- select CMD_MAC imply CMD_SATA
config TARGET_T2080RDB @@ -221,6 +234,7 @@ config TARGET_T2080RDB select BOARD_LATE_INIT if CHAIN_OF_TRUST select SUPPORT_SPL select PHYS_64BIT
- select CMD_MAC imply CMD_SATA imply PANIC_HANG
@@ -231,6 +245,7 @@ config TARGET_T2081QDS select PHYS_64BIT select FSL_DDR_FIRST_SLOT_QUAD_CAPABLE select FSL_DDR_INTERACTIVE
- select CMD_MAC
config TARGET_T4160RDB bool "Support T4160RDB" @@ -280,12 +295,14 @@ config TARGET_CYRUS_P5020 bool "Support Varisys Cyrus P5020" select ARCH_P5020 select PHYS_64BIT
- select CMD_MAC imply PANIC_HANG
config TARGET_CYRUS_P5040 bool "Support Varisys Cyrus P5040" select ARCH_P5040 select PHYS_64BIT
- select CMD_MAC imply PANIC_HANG
endchoice diff --git a/cmd/Kconfig b/cmd/Kconfig index 1595de999b5..652e9cc4f88 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1696,6 +1696,9 @@ config CMD_LED with led on/off/togle/blink. Any LED drivers can be controlled with this command, e.g. led_gpio.
+config CMD_MAC
- bool
config CMD_DATE bool "date" default y if DM_RTC diff --git a/cmd/Makefile b/cmd/Makefile index dd86675bf2a..9d85217b544 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -88,7 +88,7 @@ obj-$(CONFIG_CMD_LICENSE) += license.o obj-y += load.o obj-$(CONFIG_CMD_LOG) += log.o obj-$(CONFIG_CMD_LSBLK) += lsblk.o -obj-$(CONFIG_ID_EEPROM) += mac.o +obj-$(CONFIG_CMD_MAC) += mac.o obj-$(CONFIG_CMD_MD5SUM) += md5sum.o obj-$(CONFIG_CMD_MEMORY) += mem.o obj-$(CONFIG_CMD_IO) += io.o

On JZ4730 (and I guess all Ingenic/XBurst cores), the CP0 register 15 doesn't support a selector 1 or, for that matter, any selector and always behaves as if the selector is zero.
We don't need it anyways, these SoCs have just a single processor core.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- arch/mips/cpu/start.S | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index d0c412236dd..1402fa3d176 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -136,6 +136,8 @@ reset: #ifdef CONFIG_ARCH_BMIPS 1: mfc0 t0, CP0_DIAGNOSTIC, 3 and t0, t0, (1 << 31) +#elif CONFIG_ARCH_JZ47XX +1: and t0, t0, zero #else 1: mfc0 t0, CP0_EBASE and t0, t0, MIPS_EBASE_CPUNUM

The jz47xx serial port is essentially a ns16550 with an extra bit that needs to be turned on. The driver already takes care of it, but not in the early debug config path.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/serial/ns16550.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 702109b23b6..0cf667c2731 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -326,6 +326,7 @@ static inline void _debug_uart_init(void) { struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; int baud_divisor; + int fcr = UART_FCR_DEFVAL;
/* * We copy the code from above because it is already horribly messy. @@ -335,9 +336,13 @@ static inline void _debug_uart_init(void) */ baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); + + if (IS_ENABLED(CONFIG_ARCH_JZ47XX)) + fcr |= UART_FCR_UME; + serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER); serial_dout(&com_port->mcr, UART_MCRVAL); - serial_dout(&com_port->fcr, UART_FCR_DEFVAL); + serial_dout(&com_port->fcr, fcr);
serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL); serial_dout(&com_port->dll, baud_divisor & 0xff);

Am Dienstag, den 17.11.2020, 22:00 +0100 schrieb Lubomir Rintel:
The jz47xx serial port is essentially a ns16550 with an extra bit that needs to be turned on. The driver already takes care of it, but not in the early debug config path.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk
drivers/serial/ns16550.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 702109b23b6..0cf667c2731 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -326,6 +326,7 @@ static inline void _debug_uart_init(void) { struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; int baud_divisor;
int fcr = UART_FCR_DEFVAL;
/*
- We copy the code from above because it is already horribly messy.
@@ -335,9 +336,13 @@ static inline void _debug_uart_init(void) */ baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
- if (IS_ENABLED(CONFIG_ARCH_JZ47XX))
fcr |= UART_FCR_UME;
do you use that driver without CONFIG_OF_CONTROL?
There is already code for UME bit on JS4780 when you use the compatible "ingenic,jz4780-uart":
plat->fcr = UART_FCR_DEFVAL; if (port_type == PORT_JZ4780) plat->fcr |= UART_FCR_UME;
- serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER); serial_dout(&com_port->mcr, UART_MCRVAL);
- serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
serial_dout(&com_port->fcr, fcr);
serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL); serial_dout(&com_port->dll, baud_divisor & 0xff);

On Tue, Nov 17, 2020 at 11:29:01PM +0100, Daniel Schwierzeck wrote:
Am Dienstag, den 17.11.2020, 22:00 +0100 schrieb Lubomir Rintel:
The jz47xx serial port is essentially a ns16550 with an extra bit that needs to be turned on. The driver already takes care of it, but not in the early debug config path.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk
drivers/serial/ns16550.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 702109b23b6..0cf667c2731 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -326,6 +326,7 @@ static inline void _debug_uart_init(void) { struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; int baud_divisor;
int fcr = UART_FCR_DEFVAL;
/*
- We copy the code from above because it is already horribly messy.
@@ -335,9 +336,13 @@ static inline void _debug_uart_init(void) */ baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
- if (IS_ENABLED(CONFIG_ARCH_JZ47XX))
fcr |= UART_FCR_UME;
do you use that driver without CONFIG_OF_CONTROL?
Yes. This is indeed for the debug uart output only. I needed in SPL which is too constrained for OF_CONTROL to fit on my board, but I think it could be used to get debug output very early even if OF_CONTROL is enabled.
I actually tried to indicate that in the patch description, perhaps I could reword that somehow to make it clearer.
Thank you Lubo
There is already code for UME bit on JS4780 when you use the compatible "ingenic,jz4780-uart":
plat->fcr = UART_FCR_DEFVAL; if (port_type == PORT_JZ4780) plat->fcr |= UART_FCR_UME;
- serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER); serial_dout(&com_port->mcr, UART_MCRVAL);
- serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
serial_dout(&com_port->fcr, fcr);
serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL); serial_dout(&com_port->dll, baud_divisor & 0xff);
--
- Daniel

A rather minimal driver for that reads back configured clock rates for hardware we support.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/clk/Kconfig | 8 +++ drivers/clk/Makefile | 1 + drivers/clk/clk-jz4730.c | 121 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 drivers/clk/clk-jz4730.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 4dfbad7986b..a138c6ebcde 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -113,6 +113,14 @@ config CLK_HSDK Enable this to support the cgu clocks on Synopsys ARC HSDK and Synopsys ARC HSDK-4xD boards
+config CLK_JZ4730 + bool "Enable clock driver for Ingenic JZ4730 cgu" + depends on CLK && SOC_JZ4730 + default y + help + This clock driver adds support for clock generators present on + Ingenic JZ4730 SoC. + config CLK_VERSAL bool "Enable clock driver support for Versal" depends on ARCH_VERSAL diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d1e295ac7c1..daad6333b36 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o +obj-$(CONFIG_CLK_JZ4730) += clk-jz4730.o obj-$(CONFIG_CLK_K210) += kendryte/ obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o diff --git a/drivers/clk/clk-jz4730.c b/drivers/clk/clk-jz4730.c new file mode 100644 index 00000000000..332b1ea82d6 --- /dev/null +++ b/drivers/clk/clk-jz4730.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * JZ4730 Clock Generation Unit driver. + * + * Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk + */ + +#include <dt-bindings/clock/jz4730-cgu.h> +#include <common.h> +#include <dm.h> +#include <clk-uclass.h> +#include <div64.h> +#include <linux/bitops.h> +#include <asm/io.h> + +#define CPM_CFCR 0x00 +#define CPM_PLCR1 0x10 +#define CPM_OCR 0x1c + +#define CPM_OCR_EXT_RTC_CLK BIT(8) + +#define CPM_PLCR1_PLL1EN BIT(8) + +#define CPM_CFCR_PFR_SHIFT 8 + +#define CPM_PLCR1_PLL1FD_SHIFT 23 +#define CPM_PLCR1_PLL1FD_MASK (0x1ff << CPM_PLCR1_PLL1FD_SHIFT) +#define CPM_PLCR1_PLL1RD_SHIFT 18 +#define CPM_PLCR1_PLL1RD_MASK (0x1f << CPM_PLCR1_PLL1RD_SHIFT) +#define CPM_PLCR1_PLL1OD_SHIFT 16 +#define CPM_PLCR1_PLL1OD_MASK (0x03 << CPM_PLCR1_PLL1OD_SHIFT) + +struct jz4730_cgu_priv { + void __iomem *base; + unsigned long ext_rate; +}; + +static inline unsigned int pdiv(u32 cfcr, u32 shift) +{ + static unsigned int pdiv_table[] = { 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 }; + + return pdiv_table[cfcr >> shift & 0xf]; +} + +static inline unsigned long pll_rate(u32 plcr1, unsigned long ext_rate) +{ + unsigned long long rate; + + rate = ext_rate; + rate *= ((plcr1 & CPM_PLCR1_PLL1FD_MASK) >> CPM_PLCR1_PLL1FD_SHIFT) + 2; + do_div(rate, ((plcr1 & CPM_PLCR1_PLL1RD_MASK) >> CPM_PLCR1_PLL1RD_SHIFT) + 2); + + return rate; +} + +static ulong jz4730_cgu_clk_get_rate(struct clk *clk) +{ + struct jz4730_cgu_priv *priv = dev_get_priv(clk->dev); + u32 cfcr, plcr1, ocr; + + switch (clk->id) { + case JZ4730_CLK_PCLK: + plcr1 = readl(priv->base + CPM_PLCR1); + if (plcr1 & CPM_PLCR1_PLL1EN) { + cfcr = readl(priv->base + CPM_CFCR); + return pll_rate(plcr1, priv->ext_rate) / + pdiv(cfcr, CPM_CFCR_PFR_SHIFT); + } + return priv->ext_rate; + case JZ4730_CLK_WDT: + ocr = readl(priv->base + CPM_OCR); + if (ocr & CPM_OCR_EXT_RTC_CLK) + return -EINVAL; + return priv->ext_rate / 128; + case JZ4730_CLK_UART0: + case JZ4730_CLK_UART1: + case JZ4730_CLK_UART2: + case JZ4730_CLK_UART3: + case JZ4730_CLK_I2C: + case JZ4730_CLK_TCU: + return priv->ext_rate; + default: + return -EINVAL; + } +} + +static const struct clk_ops jz4730_cgu_clk_ops = { + .get_rate = jz4730_cgu_clk_get_rate, +}; + +static int jz4730_cgu_clk_probe(struct udevice *dev) +{ + struct jz4730_cgu_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + ret = clk_get_by_name(dev, "ext", &clk); + if (ret) + return ret; + priv->ext_rate = clk_get_rate(&clk); + + return 0; +} + +static const struct udevice_id jz4730_cgu_clk_of_match[] = { + { .compatible = "ingenic,jz4730-cgu" }, + { }, +}; + +U_BOOT_DRIVER(jz4730_cgu_clk) = { + .name = "jz4730-cgu", + .id = UCLASS_CLK, + .of_match = jz4730_cgu_clk_of_match, + .probe = jz4730_cgu_clk_probe, + .priv_auto_alloc_size = sizeof(struct jz4730_cgu_priv), + .ops = &jz4730_cgu_clk_ops, +};

Pre-probe merely guesses that the first clock is the right one -- a different one might actually be picked by probe(). In case it does not, post_probe() already has a check that will fail.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/timer/timer-uclass.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c index 62d0e860e80..f734fa8b405 100644 --- a/drivers/timer/timer-uclass.c +++ b/drivers/timer/timer-uclass.c @@ -61,9 +61,11 @@ static int timer_pre_probe(struct udevice *dev) if (!err) { ret = clk_get_rate(&timer_clk); if (IS_ERR_VALUE(ret)) - return ret; - uc_priv->clock_rate = ret; - } else { + err = ret; + else + uc_priv->clock_rate = ret; + } + if (err) { uc_priv->clock_rate = dev_read_u32_default(dev, "clock-frequency", 0); }

This adds support for a timer block on JZ4730 SoC.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/timer/Kconfig | 8 ++++ drivers/timer/Makefile | 1 + drivers/timer/jz4730_timer.c | 83 ++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 drivers/timer/jz4730_timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 80743a25519..9d5a84c03ea 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -110,6 +110,14 @@ config DESIGNWARE_APB_TIMER Enables support for the Designware APB Timer driver. This timer is present on Altera SoCFPGA SoCs.
+config JZ4730_TIMER + bool "Ingenic JZ4730 timer support" + depends on TIMER + default y if SOC_JZ4730 + help + Select this to enable support for the timer found on + devices based on the Ingenic JZ4730 SoC. + config MPC83XX_TIMER bool "MPC83xx timer support" depends on TIMER diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index eb5c48cc6ce..67529c78e59 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o +obj-$(CONFIG_JZ4730_TIMER) += jz4730_timer.o obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o obj-$(CONFIG_NOMADIK_MTU_TIMER) += nomadik-mtu-timer.o obj-$(CONFIG_OMAP_TIMER) += omap-timer.o diff --git a/drivers/timer/jz4730_timer.c b/drivers/timer/jz4730_timer.c new file mode 100644 index 00000000000..d2c77a20993 --- /dev/null +++ b/drivers/timer/jz4730_timer.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * JZ4730 Timer driver. + * + * Copyright (c) 2020 Lubomir Rintel lkundrak@v3.sk + */ + +#include <common.h> +#include <config.h> +#include <clk.h> +#include <dm.h> +#include <timer.h> +#include <time.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <linux/bitops.h> + +#define CHANNEL_ID 0 + +#define OST_TER (0x00) +#define OST_TRDR(n) (0x10 + ((n) * 0x20)) +#define OST_TCNT(n) (0x14 + ((n) * 0x20)) +#define OST_TCSR(n) (0x18 + ((n) * 0x20)) +#define OST_TCRB(n) (0x1c + ((n) * 0x20)) + +#define OST_TCSR_CKS_PCLK_256 0x0003 + +struct jz4730_timer_priv { + void __iomem *base; +}; + +static u64 jz4730_timer_get_count(struct udevice *dev) +{ + struct jz4730_timer_priv *priv = dev_get_priv(dev); + u32 val = readl(priv->base + OST_TCNT(CHANNEL_ID)); + + return timer_conv_64(U32_MAX - val); +} + +static int jz4730_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct jz4730_timer_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + ret = clk_get_by_name(dev, "pclk", &clk); + if (ret) + return ret; + + uc_priv->clock_rate = clk_get_rate(&clk); + uc_priv->clock_rate /= 256; + + writew(OST_TCSR_CKS_PCLK_256, priv->base + OST_TCSR(CHANNEL_ID)); + writel(U32_MAX, priv->base + OST_TRDR(CHANNEL_ID)); + writel(U32_MAX, priv->base + OST_TCNT(CHANNEL_ID)); + writeb(BIT(CHANNEL_ID), priv->base + OST_TER); + + return 0; +} + +static const struct timer_ops jz4730_timer_ops = { + .get_count = jz4730_timer_get_count, +}; + +static const struct udevice_id jz4730_timer_ids[] = { + { .compatible = "ingenic,jz4730-tcu" }, + { } +}; + +U_BOOT_DRIVER(jz4730_timer) = { + .name = "jz4730_timer", + .id = UCLASS_TIMER, + .of_match = jz4730_timer_ids, + .priv_auto_alloc_size = sizeof(struct jz4730_timer_priv), + .probe = jz4730_timer_probe, + .ops = &jz4730_timer_ops, + .flags = DM_FLAG_PRE_RELOC, +};

It's basically certain we want this MMC driver if we have MMC support turned on JZ47XX. A sane default here will keep the defconfig cleaner.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/mmc/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 14d79139864..4ad166a15ad 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -407,6 +407,7 @@ config MMC_BCM2835 config JZ47XX_MMC bool "Ingenic JZ47xx SD/MMC Host Controller support" depends on ARCH_JZ47XX + default y help This selects support for the SD Card Controller on Ingenic JZ47xx SoCs.

The driver doesn't use the jz4780's extra DMA channels and handles jz4740 just fine.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/mmc/jz_mmc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mmc/jz_mmc.c b/drivers/mmc/jz_mmc.c index b33f0850738..d4b9d15ef2e 100644 --- a/drivers/mmc/jz_mmc.c +++ b/drivers/mmc/jz_mmc.c @@ -490,6 +490,7 @@ static int jz_mmc_probe(struct udevice *dev) }
static const struct udevice_id jz_mmc_ids[] = { + { .compatible = "ingenic,jz4740-mmc" }, { .compatible = "ingenic,jz4780-mmc" }, { } };

Hi Lubomir,
On Tue, 2020-11-17 at 22:00 +0100, Lubomir Rintel wrote:
The driver doesn't use the jz4780's extra DMA channels and handles jz4740 just fine.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk
drivers/mmc/jz_mmc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mmc/jz_mmc.c b/drivers/mmc/jz_mmc.c index b33f0850738..d4b9d15ef2e 100644 --- a/drivers/mmc/jz_mmc.c +++ b/drivers/mmc/jz_mmc.c @@ -490,6 +490,7 @@ static int jz_mmc_probe(struct udevice *dev) }
static const struct udevice_id jz_mmc_ids[] = {
- { .compatible = "ingenic,jz4740-mmc" },
Normally, you don't need to add another compatible if there's nothing in the implementation to distinguish them.
However, I'm guessing here you want to add the compatible so you can support kernel compatibles such as ingenic,jz4740-mmc?
Regards, Ezequiel
{ .compatible = "ingenic,jz4780-mmc" }, { } };

This adds support for using GPIO lines for detecting Write-Protect and Card-Detect status.
This way the driver can fail fast if there's no card inserted.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/mmc/jz_mmc.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/drivers/mmc/jz_mmc.c b/drivers/mmc/jz_mmc.c index d4b9d15ef2e..03fb506e571 100644 --- a/drivers/mmc/jz_mmc.c +++ b/drivers/mmc/jz_mmc.c @@ -9,6 +9,7 @@ #include <common.h> #include <malloc.h> #include <mmc.h> +#include <asm/gpio.h> #include <asm/io.h> #include <asm/unaligned.h> #include <errno.h> @@ -130,6 +131,11 @@ struct jz_mmc_priv { #define JZ_MMC_BUS_WIDTH_4 0x2 #define JZ_MMC_BUS_WIDTH_8 0x3 #define JZ_MMC_SENT_INIT BIT(2) + +#if CONFIG_IS_ENABLED(DM_GPIO) + struct gpio_desc gpio_wp; + struct gpio_desc gpio_cd; +#endif };
static int jz_mmc_clock_rate(void) @@ -438,9 +444,33 @@ static int jz_mmc_dm_set_ios(struct udevice *dev) return jz_mmc_set_ios(mmc, priv); };
+#if CONFIG_IS_ENABLED(DM_GPIO) +static int jz_mmc_dm_get_cd(struct udevice *dev) +{ + struct jz_mmc_priv *priv = dev_get_priv(dev); + + if (priv->gpio_cd.dev) + return dm_gpio_get_value(&priv->gpio_cd); + return -ENOSYS; +} + +static int jz_mmc_dm_get_wp(struct udevice *dev) +{ + struct jz_mmc_priv *priv = dev_get_priv(dev); + + if (priv->gpio_wp.dev) + dm_gpio_get_value(&priv->gpio_wp); + return -ENOSYS; +} +#endif + static const struct dm_mmc_ops jz_msc_ops = { .send_cmd = jz_mmc_dm_send_cmd, .set_ios = jz_mmc_dm_set_ios, +#if CONFIG_IS_ENABLED(DM_GPIO) + .get_cd = jz_mmc_dm_get_cd, + .get_wp = jz_mmc_dm_get_wp, +#endif };
static int jz_mmc_ofdata_to_platdata(struct udevice *dev) @@ -484,6 +514,11 @@ static int jz_mmc_probe(struct udevice *dev) struct jz_mmc_priv *priv = dev_get_priv(dev); struct jz_mmc_plat *plat = dev_get_platdata(dev);
+#if CONFIG_IS_ENABLED(DM_GPIO) + gpio_request_by_name(dev, "wp-gpios", 0, &priv->gpio_wp, GPIOD_IS_IN); + gpio_request_by_name(dev, "cd-gpios", 0, &priv->gpio_cd, GPIOD_IS_IN); +#endif + plat->mmc.priv = priv; upriv->mmc = &plat->mmc; return jz_mmc_core_init(&plat->mmc);

This is a fairly minimal driver for the pin controller on JZ4730 SoC.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/pinctrl/Kconfig | 8 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-jz4730.c | 346 +++++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-jz4730.c
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 77fb8511144..3bd9552d931 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -177,6 +177,14 @@ config PINCTRL_AT91PIO4 This option is to enable the AT91 pinctrl driver for AT91 PIO4 controller which is available on SAMA5D2 SoC.
+config PINCTRL_JZ4730 + bool "Ingenic JZ4730 pinctrl driver" + depends on DM && SOC_JZ4730 + default y + help + This option is to enable the driver for pinctrl and GPIO + controller which is available on Ingenic JZ4730 SoC. + config PINCTRL_INTEL bool "Standard Intel pin-control and pin-mux driver" help diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 05b71f2f134..27d0ac7735f 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o +obj-$(CONFIG_PINCTRL_JZ4730) += pinctrl-jz4730.o obj-y += nxp/ obj-$(CONFIG_$(SPL_)PINCTRL_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ diff --git a/drivers/pinctrl/pinctrl-jz4730.c b/drivers/pinctrl/pinctrl-jz4730.c new file mode 100644 index 00000000000..1b69ecf17f1 --- /dev/null +++ b/drivers/pinctrl/pinctrl-jz4730.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * JZ4730 Pin control and GPIO driver. + * + * Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk + */ + +#include <common.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/pinctrl.h> +#include <asm/gpio.h> +#include <asm/io.h> + +#define PINCTRL_DR(n) (0x00 + (n) * 0x30) +#define PINCTRL_DIR(n) (0x04 + (n) * 0x30) +#define PINCTRL_ODR(n) (0x08 + (n) * 0x30) +#define PINCTRL_PUR(n) (0x0c + (n) * 0x30) +#define PINCTRL_ALR(n) (0x10 + (n) * 0x30) +#define PINCTRL_AUR(n) (0x14 + (n) * 0x30) +#define PINCTRL_IDLR(n) (0x18 + (n) * 0x30) +#define PINCTRL_IDUR(n) (0x1c + (n) * 0x30) +#define PINCTRL_IER(n) (0x20 + (n) * 0x30) +#define PINCTRL_IMR(n) (0x24 + (n) * 0x30) +#define PINCTRL_FR(n) (0x28 + (n) * 0x30) + +struct jz4730_pinctrl_priv { + void __iomem *base; +}; + +struct jz4730_gpio_priv { + unsigned int bank; +}; + +static int jz4730_gpio_get_value(struct udevice *dev, unsigned int offset) +{ + struct jz4730_gpio_priv *priv = dev_get_priv(dev); + struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent); + + return !!(readl(pc_priv->base + PINCTRL_DR(priv->bank)) & BIT(offset)); +} + +static int jz4730_gpio_set_value(struct udevice *dev, unsigned int offset, int value) +{ + struct jz4730_gpio_priv *priv = dev_get_priv(dev); + struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent); + u32 gpdr = readl(pc_priv->base + PINCTRL_DR(priv->bank)); + + if (value) + gpdr |= BIT(offset); + else + gpdr &= ~BIT(offset); + writel(gpdr, pc_priv->base + PINCTRL_DR(priv->bank)); + + return 0; +} + +static int jz4730_gpio_get_direction(struct udevice *dev, unsigned int offset) +{ + struct jz4730_gpio_priv *priv = dev_get_priv(dev); + struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent); + + if (offset < 16) { + if (readl(pc_priv->base + PINCTRL_ALR(priv->bank)) & (3 << (offset * 2))) + return GPIOF_FUNC; + } else { + if (readl(pc_priv->base + PINCTRL_AUR(priv->bank)) & (3 << ((offset - 16) * 2))) + return GPIOF_FUNC; + } + if (readl(pc_priv->base + PINCTRL_DIR(priv->bank)) & BIT(offset)) + return GPIOF_OUTPUT; + + return GPIOF_INPUT; +} + +static int jz4730_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + struct jz4730_gpio_priv *priv = dev_get_priv(dev); + struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent); + + clrbits_32(pc_priv->base + PINCTRL_IER(priv->bank), BIT(offset)); + clrbits_32(pc_priv->base + PINCTRL_DIR(priv->bank), BIT(offset)); + if (offset < 16) + clrbits_32(pc_priv->base + PINCTRL_ALR(priv->bank), (3 << (offset << 1))); + else + clrbits_32(pc_priv->base + PINCTRL_AUR(priv->bank), (3 << ((offset - 16) << 1))); + + return 0; +} + +static int jz4730_gpio_direction_output(struct udevice *dev, unsigned int offset, int value) +{ + struct jz4730_gpio_priv *priv = dev_get_priv(dev); + struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent); + + jz4730_gpio_set_value(dev, offset, value); + + clrbits_32(pc_priv->base + PINCTRL_IER(priv->bank), BIT(offset)); + setbits_32(pc_priv->base + PINCTRL_DIR(priv->bank), BIT(offset)); + if (offset < 16) + clrbits_32(pc_priv->base + PINCTRL_ALR(priv->bank), (3 << (offset << 1))); + else + clrbits_32(pc_priv->base + PINCTRL_AUR(priv->bank), (3 << ((offset - 16) << 1))); + + return 0; +} + +static int jz4730_gpio_probe(struct udevice *dev) +{ + struct jz4730_gpio_priv *priv = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + int ret; + + ret = ofnode_read_u32(dev_ofnode(dev), "reg", &priv->bank); + if (ret) + return ret; + + uc_priv->bank_name = strdup(dev->name); + uc_priv->gpio_count = 32; + return 0; +} + +static const struct dm_gpio_ops jz4730_gpio_ops = { + .set_value = jz4730_gpio_set_value, + .get_value = jz4730_gpio_get_value, + .get_function = jz4730_gpio_get_direction, + .direction_input = jz4730_gpio_direction_input, + .direction_output = jz4730_gpio_direction_output, +}; + +static struct driver jz4730_gpio_driver = { + .name = "jz4730-gpio", + .id = UCLASS_GPIO, + .probe = jz4730_gpio_probe, + .priv_auto_alloc_size = sizeof(struct jz4730_gpio_priv), + .ops = &jz4730_gpio_ops, +}; + +static const char * const pin_names[] = { + "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7", + "PA8", "PA9", "PA10", "PA11", "PA12", "PA13", "PA14", "PA15", + "PA16", "PA17", "PA18", "PA19", "PA20", "PA21", "PA22", "PA23", + "PA24", "PA25", "PA26", "PA27", "PA28", "PA29", "PA30", "PA31", + "PB0", "PB1", "PB2", "PB3", "PB4", "PB5", "PB6", "PB7", + "PB8", "PB9", "PB10", "PB11", "PB12", "PB13", "PB14", "PB15", + "PB16", "PB17", "PB18", "PB19", "PB20", "PB21", "PB22", "PB23", + "PB24", "PB25", "PB26", "PB27", "PB28", "PB29", "PB30", "PB31", + "PC0", "PC1", "PC2", "PC3", "PC4", "PC5", "PC6", "PC7", + "PC8", "PC9", "PC10", "PC11", "PC12", "PC13", "PC14", "PC15", + "PC16", "PC17", "PC18", "PC19", "PC20", "PC21", "PC22", "PC23", + "PC24", "PC25", "PC26", "PC27", "PC28", "PC29", "PC30", "PC31", + "PD0", "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", + "PD8", "PD9", "PD10", "PD11", "PD12", "PD13", "PD14", "PD15", + "PD16", "PD17", "PD18", "PD19", "PD20", "PD21", "PD22", "PD23", + "PD24", "PD25", "PD26", "PD27", "PD28", "PD29", "PD30", "PD31", +}; + +static int jz4730_pinctrl_get_pins_count(struct udevice *dev) +{ + return ARRAY_SIZE(pin_names); +} + +static const char *jz4730_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + return pin_names[selector]; +} + +static const struct { + const char *name; + struct { u32 gpalr, gpaur; } mask[4]; +} groups[] = { + { "lcd-16bit", { { 0, }, { 0x00000000, 0x00c0ffff }, { 0, }, { 0, 0, } } }, + { "lcd-16bit-tft", { { 0, }, { 0x00000000, 0xff000000 }, { 0, }, { 0, 0, } } }, + { "lcd-8bit", { { 0, }, { 0xffff0000, 0x003f0000 }, { 0, }, { 0, 0, } } }, + { "lcd-no-pins", { { 0, }, { 0, }, { 0, }, { 0, 0, } } }, + { "mac", { { 0, }, { 0, }, { 0, }, { 0, 0x03ffffff, } } }, + { "mmc-1bit", { { 0, }, { 0x0000f030, 0 }, { 0, }, { 0, 0, } } }, + { "mmc-4bit", { { 0, }, { 0x00000fc0, 0 }, { 0, }, { 0, 0, } } }, + { "nand-cs1", { { 0, }, { 0, }, { 0, 0x000000c0 }, { 0, 0, } } }, + { "nand-cs2", { { 0, }, { 0, }, { 0, 0x00000300 }, { 0, 0, } } }, + { "nand-cs3", { { 0, }, { 0, }, { 0, 0x00000c00 }, { 0, 0, } } }, + { "nand-cs4", { { 0, }, { 0, }, { 0, 0x00003000 }, { 0, 0, } } }, + { "nand-cs5", { { 0, }, { 0, }, { 0, 0x0000c000 }, { 0, 0, } } }, + { "pwm0", { { 0, }, { 0, }, { 0, 0x30000000 }, { 0, 0, } } }, + { "pwm1", { { 0, }, { 0, }, { 0, 0xc0000000 }, { 0, 0, } } }, + { "uart0-data", { { 0, }, { 0, }, { 0, }, { 0, 0xf0000000 } } }, +}; + +static int jz4730_pinctrl_get_groups_count(struct udevice *dev) +{ + return ARRAY_SIZE(groups); +} + +static const char *jz4730_pinctrl_get_group_name(struct udevice *dev, + unsigned int group_selector) +{ + return groups[group_selector].name; +} + +static const struct { + const char *name; + struct { u32 gpalr, gpaur; } val[4]; +} funcs[] = { + { "lcd", { { 0, }, { 0x55550000, 0x556a5555 }, { 0, }, { 0, 0, } } }, + { "mac", { { 0, }, { 0, }, { 0, }, { 0, 0x01555555, } } }, + { "mmc", { { 0, }, { 0x00005550, 0 }, { 0, }, { 0, 0, } } }, + { "nand", { { 0, }, { 0, }, { 0, 0x000055c0 }, { 0, 0, } } }, + { "pwm0", { { 0, }, { 0, }, { 0, 0x10000000 }, { 0, 0, } } }, + { "pwm1", { { 0, }, { 0, }, { 0, 0x40000000 }, { 0, 0, } } }, + { "sleep", { { 0, }, { 0, }, { 0, 0 }, { 0, 0, } } }, + { "uart0", { { 0, }, { 0, }, { 0, }, { 0, 0x50000000 } } }, +}; + +static int jz4730_pinctrl_get_funcs_count(struct udevice *dev) +{ + return ARRAY_SIZE(funcs); +} + +static const char *jz4730_pinctrl_get_func_name(struct udevice *dev, + unsigned int func_selector) +{ + return funcs[func_selector].name; +} + +static inline void update_bits(void __iomem *reg, u32 mask, u32 val) +{ + if (mask) + writel((readl(reg) & ~mask) | val, reg); +} + +static int jz4730_pinctrl_set(struct udevice *dev, + unsigned int selector, + unsigned int func_selector) +{ + struct jz4730_pinctrl_priv *priv = dev_get_priv(dev); + int bank = selector / 32; + int pin = selector % 32; + + if (pin < 16) { + update_bits(priv->base + PINCTRL_ALR(bank), + funcs[func_selector].val[bank].gpalr, + 3 << (pin * 2)); + } else { + update_bits(priv->base + PINCTRL_AUR(bank), + funcs[func_selector].val[bank].gpaur, + 3 << ((pin - 16) * 2)); + } + + return 0; +} + +static int jz4730_pinctrl_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int func_selector) +{ + struct jz4730_pinctrl_priv *priv = dev_get_priv(dev); + int bank; + + for (bank = 0; bank < ARRAY_SIZE(groups[0].mask); bank++) { + update_bits(priv->base + PINCTRL_ALR(bank), + groups[group_selector].mask[bank].gpalr, + funcs[func_selector].val[bank].gpalr); + update_bits(priv->base + PINCTRL_AUR(bank), + groups[group_selector].mask[bank].gpaur, + funcs[func_selector].val[bank].gpaur); + } + + return 0; +} + +const int jz4730_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct jz4730_pinctrl_priv *priv = dev_get_priv(dev); + int bank = selector / 32; + int pin = selector % 32; + + snprintf(buf, size, "%3d D%d DI%d OD%d PU%d A%d ID%d IE%d IM%d F%d", + selector, + (readl(priv->base + PINCTRL_DR(bank)) >> pin) & 1, + (readl(priv->base + PINCTRL_DIR(bank)) >> pin) & 1, + (readl(priv->base + PINCTRL_ODR(bank)) >> pin) & 1, + (readl(priv->base + PINCTRL_PUR(bank)) >> pin) & 1, + pin < 16 + ? (readl(priv->base + PINCTRL_ALR(bank)) >> pin * 2) & 3 + : (readl(priv->base + PINCTRL_AUR(bank)) >> (pin - 16) * 2) & 3, + pin < 16 + ? (readl(priv->base + PINCTRL_IDLR(bank)) >> pin * 2) & 3 + : (readl(priv->base + PINCTRL_IDUR(bank)) >> (pin - 16) * 2) & 3, + (readl(priv->base + PINCTRL_IER(bank)) >> pin) & 1, + (readl(priv->base + PINCTRL_IMR(bank)) >> pin) & 1, + (readl(priv->base + PINCTRL_FR(bank)) >> pin) & 1); + + return 0; +} + +const struct pinctrl_ops jz4730_pinctrl_ops = { + .get_pins_count = jz4730_pinctrl_get_pins_count, + .get_pin_name = jz4730_pinctrl_get_pin_name, + .get_groups_count = jz4730_pinctrl_get_groups_count, + .get_group_name = jz4730_pinctrl_get_group_name, + .get_functions_count = jz4730_pinctrl_get_funcs_count, + .get_function_name = jz4730_pinctrl_get_func_name, + .pinmux_set = jz4730_pinctrl_set, + .pinmux_group_set = jz4730_pinctrl_group_set, + .set_state = pinctrl_generic_set_state, + .get_pin_muxing = jz4730_pinctrl_get_pin_muxing, +}; + +int jz4730_pinctrl_probe(struct udevice *dev) +{ + struct jz4730_pinctrl_priv *priv = dev_get_priv(dev); + ofnode node; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + dev_for_each_subnode(node, dev) { + struct udevice *cdev; + + if (!ofnode_read_bool(node, "gpio-controller")) + continue; + + device_bind_ofnode(dev, &jz4730_gpio_driver, ofnode_get_name(node), + priv, node, &cdev); + } + + return 0; +} + +static const struct udevice_id jz4730_pinctrl_of_match[] = { + { .compatible = "ingenic,jz4730-pinctrl", }, + { } +}; + +U_BOOT_DRIVER(jz4730_pinctrl) = { + .name = "jz4730-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(jz4730_pinctrl_of_match), + .probe = jz4730_pinctrl_probe, + .priv_auto_alloc_size = sizeof(struct jz4730_pinctrl_priv), + .ops = &jz4730_pinctrl_ops, +};

Am Dienstag, den 17.11.2020, 22:00 +0100 schrieb Lubomir Rintel:
This is a fairly minimal driver for the pin controller on JZ4730 SoC.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk
drivers/pinctrl/Kconfig | 8 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-jz4730.c | 346 +++++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-jz4730.c
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 77fb8511144..3bd9552d931 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -177,6 +177,14 @@ config PINCTRL_AT91PIO4 This option is to enable the AT91 pinctrl driver for AT91 PIO4 controller which is available on SAMA5D2 SoC.
+config PINCTRL_JZ4730
- bool "Ingenic JZ4730 pinctrl driver"
- depends on DM && SOC_JZ4730
- default y
- help
This option is to enable the driver for pinctrl and GPIO
controller which is available on Ingenic JZ4730 SoC.
config PINCTRL_INTEL bool "Standard Intel pin-control and pin-mux driver" help diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 05b71f2f134..27d0ac7735f 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o +obj-$(CONFIG_PINCTRL_JZ4730) += pinctrl-jz4730.o obj-y += nxp/ obj-$(CONFIG_$(SPL_)PINCTRL_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ diff --git a/drivers/pinctrl/pinctrl-jz4730.c b/drivers/pinctrl/pinctrl-jz4730.c new file mode 100644 index 00000000000..1b69ecf17f1 --- /dev/null +++ b/drivers/pinctrl/pinctrl-jz4730.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- JZ4730 Pin control and GPIO driver.
- Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk
- */
+#include <common.h>
don't use common.h in new code and just include the required header files
+#include <dm.h> +#include <dm/device-internal.h> +#include <dm/pinctrl.h> +#include <asm/gpio.h> +#include <asm/io.h>
+#define PINCTRL_DR(n) (0x00 + (n) * 0x30) +#define PINCTRL_DIR(n) (0x04 + (n) * 0x30) +#define PINCTRL_ODR(n) (0x08 + (n) * 0x30) +#define PINCTRL_PUR(n) (0x0c + (n) * 0x30) +#define PINCTRL_ALR(n) (0x10 + (n) * 0x30) +#define PINCTRL_AUR(n) (0x14 + (n) * 0x30) +#define PINCTRL_IDLR(n) (0x18 + (n) * 0x30) +#define PINCTRL_IDUR(n) (0x1c + (n) * 0x30) +#define PINCTRL_IER(n) (0x20 + (n) * 0x30) +#define PINCTRL_IMR(n) (0x24 + (n) * 0x30) +#define PINCTRL_FR(n) (0x28 + (n) * 0x30)
+struct jz4730_pinctrl_priv {
- void __iomem *base;
+};
+struct jz4730_gpio_priv {
- unsigned int bank;
+};
+static int jz4730_gpio_get_value(struct udevice *dev, unsigned int offset) +{
- struct jz4730_gpio_priv *priv = dev_get_priv(dev);
- struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent);
- return !!(readl(pc_priv->base + PINCTRL_DR(priv->bank)) & BIT(offset));
+}
+static int jz4730_gpio_set_value(struct udevice *dev, unsigned int offset, int value) +{
- struct jz4730_gpio_priv *priv = dev_get_priv(dev);
- struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent);
- u32 gpdr = readl(pc_priv->base + PINCTRL_DR(priv->bank));
- if (value)
gpdr |= BIT(offset);
- else
gpdr &= ~BIT(offset);
- writel(gpdr, pc_priv->base + PINCTRL_DR(priv->bank));
- return 0;
+}
+static int jz4730_gpio_get_direction(struct udevice *dev, unsigned int offset) +{
- struct jz4730_gpio_priv *priv = dev_get_priv(dev);
- struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent);
- if (offset < 16) {
if (readl(pc_priv->base + PINCTRL_ALR(priv->bank)) & (3 << (offset * 2)))
return GPIOF_FUNC;
- } else {
if (readl(pc_priv->base + PINCTRL_AUR(priv->bank)) & (3 << ((offset - 16) * 2)))
return GPIOF_FUNC;
- }
- if (readl(pc_priv->base + PINCTRL_DIR(priv->bank)) & BIT(offset))
return GPIOF_OUTPUT;
- return GPIOF_INPUT;
+}
+static int jz4730_gpio_direction_input(struct udevice *dev, unsigned int offset) +{
- struct jz4730_gpio_priv *priv = dev_get_priv(dev);
- struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent);
- clrbits_32(pc_priv->base + PINCTRL_IER(priv->bank), BIT(offset));
- clrbits_32(pc_priv->base + PINCTRL_DIR(priv->bank), BIT(offset));
- if (offset < 16)
clrbits_32(pc_priv->base + PINCTRL_ALR(priv->bank), (3 << (offset << 1)));
- else
clrbits_32(pc_priv->base + PINCTRL_AUR(priv->bank), (3 << ((offset - 16) << 1)));
- return 0;
+}
+static int jz4730_gpio_direction_output(struct udevice *dev, unsigned int offset, int value) +{
- struct jz4730_gpio_priv *priv = dev_get_priv(dev);
- struct jz4730_pinctrl_priv *pc_priv = dev_get_priv(dev->parent);
- jz4730_gpio_set_value(dev, offset, value);
- clrbits_32(pc_priv->base + PINCTRL_IER(priv->bank), BIT(offset));
- setbits_32(pc_priv->base + PINCTRL_DIR(priv->bank), BIT(offset));
- if (offset < 16)
clrbits_32(pc_priv->base + PINCTRL_ALR(priv->bank), (3 << (offset << 1)));
- else
clrbits_32(pc_priv->base + PINCTRL_AUR(priv->bank), (3 << ((offset - 16) << 1)));
- return 0;
+}
+static int jz4730_gpio_probe(struct udevice *dev) +{
- struct jz4730_gpio_priv *priv = dev_get_priv(dev);
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- int ret;
- ret = ofnode_read_u32(dev_ofnode(dev), "reg", &priv->bank);
you shoud prefer dev_read_u32() respectively the API in include/dm/read.h
- if (ret)
return ret;
- uc_priv->bank_name = strdup(dev->name);
- uc_priv->gpio_count = 32;
- return 0;
+}
+static const struct dm_gpio_ops jz4730_gpio_ops = {
- .set_value = jz4730_gpio_set_value,
- .get_value = jz4730_gpio_get_value,
- .get_function = jz4730_gpio_get_direction,
- .direction_input = jz4730_gpio_direction_input,
- .direction_output = jz4730_gpio_direction_output,
+};
+static struct driver jz4730_gpio_driver = {
- .name = "jz4730-gpio",
- .id = UCLASS_GPIO,
- .probe = jz4730_gpio_probe,
- .priv_auto_alloc_size = sizeof(struct jz4730_gpio_priv),
- .ops = &jz4730_gpio_ops,
+};
+static const char * const pin_names[] = {
- "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7",
- "PA8", "PA9", "PA10", "PA11", "PA12", "PA13", "PA14", "PA15",
- "PA16", "PA17", "PA18", "PA19", "PA20", "PA21", "PA22", "PA23",
- "PA24", "PA25", "PA26", "PA27", "PA28", "PA29", "PA30", "PA31",
- "PB0", "PB1", "PB2", "PB3", "PB4", "PB5", "PB6", "PB7",
- "PB8", "PB9", "PB10", "PB11", "PB12", "PB13", "PB14", "PB15",
- "PB16", "PB17", "PB18", "PB19", "PB20", "PB21", "PB22", "PB23",
- "PB24", "PB25", "PB26", "PB27", "PB28", "PB29", "PB30", "PB31",
- "PC0", "PC1", "PC2", "PC3", "PC4", "PC5", "PC6", "PC7",
- "PC8", "PC9", "PC10", "PC11", "PC12", "PC13", "PC14", "PC15",
- "PC16", "PC17", "PC18", "PC19", "PC20", "PC21", "PC22", "PC23",
- "PC24", "PC25", "PC26", "PC27", "PC28", "PC29", "PC30", "PC31",
- "PD0", "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7",
- "PD8", "PD9", "PD10", "PD11", "PD12", "PD13", "PD14", "PD15",
- "PD16", "PD17", "PD18", "PD19", "PD20", "PD21", "PD22", "PD23",
- "PD24", "PD25", "PD26", "PD27", "PD28", "PD29", "PD30", "PD31",
+};
+static int jz4730_pinctrl_get_pins_count(struct udevice *dev) +{
- return ARRAY_SIZE(pin_names);
+}
+static const char *jz4730_pinctrl_get_pin_name(struct udevice *dev,
unsigned int selector)
+{
- return pin_names[selector];
+}
+static const struct {
- const char *name;
- struct { u32 gpalr, gpaur; } mask[4];
+} groups[] = {
- { "lcd-16bit", { { 0, }, { 0x00000000, 0x00c0ffff }, { 0, }, { 0, 0, } } },
- { "lcd-16bit-tft", { { 0, }, { 0x00000000, 0xff000000 }, { 0, }, { 0, 0, } } },
- { "lcd-8bit", { { 0, }, { 0xffff0000, 0x003f0000 }, { 0, }, { 0, 0, } } },
- { "lcd-no-pins", { { 0, }, { 0, }, { 0, }, { 0, 0, } } },
- { "mac", { { 0, }, { 0, }, { 0, }, { 0, 0x03ffffff, } } },
- { "mmc-1bit", { { 0, }, { 0x0000f030, 0 }, { 0, }, { 0, 0, } } },
- { "mmc-4bit", { { 0, }, { 0x00000fc0, 0 }, { 0, }, { 0, 0, } } },
- { "nand-cs1", { { 0, }, { 0, }, { 0, 0x000000c0 }, { 0, 0, } } },
- { "nand-cs2", { { 0, }, { 0, }, { 0, 0x00000300 }, { 0, 0, } } },
- { "nand-cs3", { { 0, }, { 0, }, { 0, 0x00000c00 }, { 0, 0, } } },
- { "nand-cs4", { { 0, }, { 0, }, { 0, 0x00003000 }, { 0, 0, } } },
- { "nand-cs5", { { 0, }, { 0, }, { 0, 0x0000c000 }, { 0, 0, } } },
- { "pwm0", { { 0, }, { 0, }, { 0, 0x30000000 }, { 0, 0, } } },
- { "pwm1", { { 0, }, { 0, }, { 0, 0xc0000000 }, { 0, 0, } } },
- { "uart0-data", { { 0, }, { 0, }, { 0, }, { 0, 0xf0000000 } } },
+};
+static int jz4730_pinctrl_get_groups_count(struct udevice *dev) +{
- return ARRAY_SIZE(groups);
+}
+static const char *jz4730_pinctrl_get_group_name(struct udevice *dev,
unsigned int group_selector)
+{
- return groups[group_selector].name;
+}
+static const struct {
- const char *name;
- struct { u32 gpalr, gpaur; } val[4];
+} funcs[] = {
- { "lcd", { { 0, }, { 0x55550000, 0x556a5555 }, { 0, }, { 0, 0, } } },
- { "mac", { { 0, }, { 0, }, { 0, }, { 0, 0x01555555, } } },
- { "mmc", { { 0, }, { 0x00005550, 0 }, { 0, }, { 0, 0, } } },
- { "nand", { { 0, }, { 0, }, { 0, 0x000055c0 }, { 0, 0, } } },
- { "pwm0", { { 0, }, { 0, }, { 0, 0x10000000 }, { 0, 0, } } },
- { "pwm1", { { 0, }, { 0, }, { 0, 0x40000000 }, { 0, 0, } } },
- { "sleep", { { 0, }, { 0, }, { 0, 0 }, { 0, 0, } } },
- { "uart0", { { 0, }, { 0, }, { 0, }, { 0, 0x50000000 } } },
+};
+static int jz4730_pinctrl_get_funcs_count(struct udevice *dev) +{
- return ARRAY_SIZE(funcs);
+}
+static const char *jz4730_pinctrl_get_func_name(struct udevice *dev,
unsigned int func_selector)
+{
- return funcs[func_selector].name;
+}
+static inline void update_bits(void __iomem *reg, u32 mask, u32 val) +{
- if (mask)
writel((readl(reg) & ~mask) | val, reg);
+}
+static int jz4730_pinctrl_set(struct udevice *dev,
unsigned int selector,
unsigned int func_selector)
+{
- struct jz4730_pinctrl_priv *priv = dev_get_priv(dev);
- int bank = selector / 32;
- int pin = selector % 32;
- if (pin < 16) {
update_bits(priv->base + PINCTRL_ALR(bank),
funcs[func_selector].val[bank].gpalr,
3 << (pin * 2));
- } else {
update_bits(priv->base + PINCTRL_AUR(bank),
funcs[func_selector].val[bank].gpaur,
3 << ((pin - 16) * 2));
- }
- return 0;
+}
+static int jz4730_pinctrl_group_set(struct udevice *dev,
unsigned int group_selector,
unsigned int func_selector)
+{
- struct jz4730_pinctrl_priv *priv = dev_get_priv(dev);
- int bank;
- for (bank = 0; bank < ARRAY_SIZE(groups[0].mask); bank++) {
update_bits(priv->base + PINCTRL_ALR(bank),
groups[group_selector].mask[bank].gpalr,
funcs[func_selector].val[bank].gpalr);
update_bits(priv->base + PINCTRL_AUR(bank),
groups[group_selector].mask[bank].gpaur,
funcs[func_selector].val[bank].gpaur);
- }
- return 0;
+}
+const int jz4730_pinctrl_get_pin_muxing(struct udevice *dev,
unsigned int selector,
char *buf, int size)
+{
- struct jz4730_pinctrl_priv *priv = dev_get_priv(dev);
- int bank = selector / 32;
- int pin = selector % 32;
- snprintf(buf, size, "%3d D%d DI%d OD%d PU%d A%d ID%d IE%d IM%d F%d",
selector,
(readl(priv->base + PINCTRL_DR(bank)) >> pin) & 1,
(readl(priv->base + PINCTRL_DIR(bank)) >> pin) & 1,
(readl(priv->base + PINCTRL_ODR(bank)) >> pin) & 1,
(readl(priv->base + PINCTRL_PUR(bank)) >> pin) & 1,
pin < 16
? (readl(priv->base + PINCTRL_ALR(bank)) >> pin * 2) & 3
: (readl(priv->base + PINCTRL_AUR(bank)) >> (pin - 16) * 2) & 3,
pin < 16
? (readl(priv->base + PINCTRL_IDLR(bank)) >> pin * 2) & 3
: (readl(priv->base + PINCTRL_IDUR(bank)) >> (pin - 16) * 2) & 3,
(readl(priv->base + PINCTRL_IER(bank)) >> pin) & 1,
(readl(priv->base + PINCTRL_IMR(bank)) >> pin) & 1,
(readl(priv->base + PINCTRL_FR(bank)) >> pin) & 1);
- return 0;
+}
+const struct pinctrl_ops jz4730_pinctrl_ops = {
- .get_pins_count = jz4730_pinctrl_get_pins_count,
- .get_pin_name = jz4730_pinctrl_get_pin_name,
- .get_groups_count = jz4730_pinctrl_get_groups_count,
- .get_group_name = jz4730_pinctrl_get_group_name,
- .get_functions_count = jz4730_pinctrl_get_funcs_count,
- .get_function_name = jz4730_pinctrl_get_func_name,
- .pinmux_set = jz4730_pinctrl_set,
- .pinmux_group_set = jz4730_pinctrl_group_set,
- .set_state = pinctrl_generic_set_state,
- .get_pin_muxing = jz4730_pinctrl_get_pin_muxing,
+};
+int jz4730_pinctrl_probe(struct udevice *dev) +{
- struct jz4730_pinctrl_priv *priv = dev_get_priv(dev);
- ofnode node;
- priv->base = dev_remap_addr(dev);
- if (!priv->base)
return -EINVAL;
- dev_for_each_subnode(node, dev) {
struct udevice *cdev;
if (!ofnode_read_bool(node, "gpio-controller"))
you should prefer dev_read_bool()
continue;
device_bind_ofnode(dev, &jz4730_gpio_driver, ofnode_get_name(node),
priv, node, &cdev);
- }
- return 0;
+}
+static const struct udevice_id jz4730_pinctrl_of_match[] = {
- { .compatible = "ingenic,jz4730-pinctrl", },
- { }
+};
+U_BOOT_DRIVER(jz4730_pinctrl) = {
- .name = "jz4730-pinctrl",
- .id = UCLASS_PINCTRL,
- .of_match = of_match_ptr(jz4730_pinctrl_of_match),
- .probe = jz4730_pinctrl_probe,
- .priv_auto_alloc_size = sizeof(struct jz4730_pinctrl_priv),
- .ops = &jz4730_pinctrl_ops,
+};

nand_spl_simple.c machinery allways passes a nand_chip argument to board_nand_init() even if the main u-boot proper uses the SYS_NAND_SELF_INIT version.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- include/nand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/nand.h b/include/nand.h index 80dd6469bc0..cf3a5e91368 100644 --- a/include/nand.h +++ b/include/nand.h @@ -35,7 +35,7 @@ unsigned long nand_size(void);
int nand_mtd_to_devnum(struct mtd_info *mtd);
-#ifdef CONFIG_SYS_NAND_SELF_INIT +#if defined(CONFIG_SYS_NAND_SELF_INIT) && !CONFIG_IS_ENABLED(NAND_SIMPLE) void board_nand_init(void); int nand_register(int devnum, struct mtd_info *mtd); #else

This adds driver for the NAND flash driver for JZ4730 SoC.
Can also be used in the NAND SPL that is too constrained (needs to fit in 4K) to be DT-driven.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/mtd/nand/raw/Kconfig | 10 ++ drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/jz4730_nand.c | 212 +++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 drivers/mtd/nand/raw/jz4730_nand.c
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 3cf3b14f05b..be6146a71f2 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -121,6 +121,16 @@ config NAND_DENALI_DT Enable the driver for NAND flash on platforms using a Denali NAND controller as a DT device.
+config NAND_JZ4730 + bool "Support JZ4730 NAND controller" + select SYS_NAND_SELF_INIT + depends on DM_MTD && SOC_JZ4730 + imply CMD_NAND + default y + help + Enable this driver for NAND flash controllers available in + Ingenic JZ4730 SoCs. + config NAND_LPC32XX_SLC bool "Support LPC32XX_SLC controller" help diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 24c51b6924a..8a4b18728eb 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o +obj-$(CONFIG_NAND_JZ4730) += jz4730_nand.o obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o diff --git a/drivers/mtd/nand/raw/jz4730_nand.c b/drivers/mtd/nand/raw/jz4730_nand.c new file mode 100644 index 00000000000..aa4631971fc --- /dev/null +++ b/drivers/mtd/nand/raw/jz4730_nand.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * JZ4730 NAND flash driver. + * + * Copyright (c) 2007 Ingenic Semiconductor Inc. + * Author: jlwei@ingenic.cn + * + * Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk + */ + +#include <asm/io.h> +#include <common.h> +#include <dm.h> +#include <nand.h> + +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/rawnand.h> + +#define EMC_SMCR3 0x1c +#define EMC_NFCSR 0x50 +#define EMC_NFECC 0x54 + +#define EMC_NFCSR_NFE BIT(0) +#define EMC_NFCSR_FCE BIT(1) +#define EMC_NFCSR_ECCE BIT(2) +#define EMC_NFCSR_ERST BIT(3) +#define EMC_NFCSR_RB BIT(7) + +struct jz4730_nand_priv { + void __iomem *base; + struct nand_chip nand; +}; + +static inline void __iomem *mtd_to_base(struct mtd_info *mtd); + +static void jz4730_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, uint ctrl) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + void __iomem *base = mtd_to_base(mtd); + unsigned long IO_ADDR_W; + + if (ctrl & NAND_CTRL_CHANGE) { + IO_ADDR_W = (unsigned long)nand->IO_ADDR_W; + + if (ctrl & NAND_NCE) + setbits_32(base + EMC_NFCSR, EMC_NFCSR_FCE); + else + clrbits_32(base + EMC_NFCSR, EMC_NFCSR_FCE); + + IO_ADDR_W &= ~(BIT(18) | BIT(19)); + if (ctrl & NAND_CLE) + IO_ADDR_W |= BIT(18); + if (ctrl & NAND_ALE) + IO_ADDR_W |= BIT(19); + + nand->IO_ADDR_W = (void *)IO_ADDR_W; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, nand->IO_ADDR_W); +} + +static int jz4730_nand_dev_ready(struct mtd_info *mtd) +{ + void __iomem *base = mtd_to_base(mtd); + + return (readl(base + EMC_NFCSR) & EMC_NFCSR_RB) ? 1 : 0; +} + +static void jz4730_nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + unsigned long IO_ADDR_R = (unsigned long)nand->IO_ADDR_R; + unsigned long IO_ADDR_W = (unsigned long)nand->IO_ADDR_W; + + if (chip == 0) { + IO_ADDR_R &= ~(BIT(16) | BIT(17)); + IO_ADDR_W &= ~(BIT(16) | BIT(17)); + } else if (chip == 1) { + IO_ADDR_R |= (BIT(16) | BIT(17)); + IO_ADDR_W |= (BIT(16) | BIT(17)); + } + + nand->IO_ADDR_R = (void *)IO_ADDR_R; + nand->IO_ADDR_W = (void *)IO_ADDR_W; +} + +static void jz4730_nand_ecc_hwctl(struct mtd_info *mtd, int mode) +{ + void __iomem *base = mtd_to_base(mtd); + + setbits_32(base + EMC_NFCSR, EMC_NFCSR_ECCE | EMC_NFCSR_ERST); +} + +static int jz4730_nand_ecc_calculate(struct mtd_info *mtd, + const u_char *dat, u_char *ecc) +{ + void __iomem *base = mtd_to_base(mtd); + u32 val = readl(base + EMC_NFECC); + + clrbits_32(base + EMC_NFCSR, EMC_NFCSR_ECCE); + val = readl(base + EMC_NFECC); + val = ~val | 0x00030000; + + ecc[0] = val >> 8; + ecc[1] = val; + ecc[2] = val >> 16; + + return 0; +} + +void jz4730_nand_chip_init(struct nand_chip *nand) +{ + struct mtd_info *mtd = nand_to_mtd(nand); + void __iomem *base = mtd_to_base(mtd); + + if (!IS_ENABLED(SPL_BUILD) || IS_ENABLED(SPL_NAND_ECC)) { + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.hwctl = jz4730_nand_ecc_hwctl; + nand->ecc.calculate = jz4730_nand_ecc_calculate; + nand->ecc.correct = nand_correct_data; + nand->ecc.bytes = 3; + } + + nand->cmd_ctrl = jz4730_nand_cmd_ctrl; + nand->dev_ready = jz4730_nand_dev_ready; + nand->select_chip = jz4730_nand_select_chip; + nand->IO_ADDR_R = (void __iomem *)CONFIG_SYS_NAND_BASE; + nand->IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE; + nand->chip_delay = 20; + + /* Enable the NAND functionality. */ + setbits_32(base + EMC_NFCSR, EMC_NFCSR_NFE); + + /* Nobody knows what does this do. */ + writel(0x06644400, base + EMC_SMCR3); +} + +#if !defined(CONFIG_SPL_BUILD) + +static inline void __iomem *mtd_to_base(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + + return container_of(nand, struct jz4730_nand_priv, nand)->base; +} + +static int jz4730_nand_probe(struct udevice *dev) +{ + struct jz4730_nand_priv *priv = dev_get_priv(dev); + struct nand_chip *nand = &priv->nand; + struct mtd_info *mtd = nand_to_mtd(nand); + ofnode node; + int ret; + + priv->base = dev_remap_addr(dev->parent); + if (!priv->base) + return -EINVAL; + + jz4730_nand_chip_init(nand); + + ofnode_for_each_subnode(node, dev->node) + nand_set_flash_node(nand, node); + + ret = nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS); + if (ret) + return ret; + + return nand_register(0, mtd); +} + +static const struct udevice_id jz4730_nand_dt_ids[] = { + { .compatible = "ingenic,jz4730-nand", }, + { } +}; + +U_BOOT_DRIVER(jz4730_nand_dt) = { + .name = "jz4730-nand", + .id = UCLASS_MTD, + .of_match = jz4730_nand_dt_ids, + .probe = jz4730_nand_probe, + .priv_auto_alloc_size = sizeof(struct jz4730_nand_priv), +}; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_GET_DRIVER(jz4730_nand_dt), + &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize %s. (error %d)\n", dev->name, ret); +} + +#else /* CONFIG_SPL_BUILD */ + +static inline void __iomem *mtd_to_base(struct mtd_info *mtd) +{ + return (void __iomem *)KSEG1 + 0x13010000; +} + +int board_nand_init(struct nand_chip *nand) +{ + jz4730_nand_chip_init(nand); + nand->read_buf = nand_read_buf; + + return 0; +} + +#endif /* CONFIG_SPL_BUILD */

This adds support for the watchdog timer on JZ4730 SoC.
Once started, the hardware can't be told to stop counting. It is especially inconvenient given the stock kernel on Skytone Alpha 400 (a JZ4730-based laptop) won't poke the watchdog.
We nevertheless want to keep the driver around in order to be able to reset the processor. For now, the driver uses a timeout of 0 to mean it shouldn't set a timout, which should be good enough for the Alpha 400 boards. There's probaby a nicer solution.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/watchdog/Kconfig | 8 ++++ drivers/watchdog/Makefile | 1 + drivers/watchdog/jz4730_wdt.c | 86 +++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 drivers/watchdog/jz4730_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 4532a40e458..ff81344b337 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -118,6 +118,14 @@ config WDT_CORTINA This driver support all CPU ISAs supported by Cortina Access CAxxxx SoCs.
+config WDT_JZ4730 + bool "Ingenic JZ4730 watchdog timer support" + depends on WDT && SOC_JZ4730 + default y + help + Select this to enable watchdog timer, which can be found on + Ingenic JZ4730 chips. + config WDT_MPC8xx bool "MPC8xx watchdog timer support" depends on WDT && MPC8xx diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 01b8231f2bf..ca46befe29d 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o +obj-$(CONFIG_WDT_JZ4730) += jz4730_wdt.o obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o diff --git a/drivers/watchdog/jz4730_wdt.c b/drivers/watchdog/jz4730_wdt.c new file mode 100644 index 00000000000..6a63f3cbb6f --- /dev/null +++ b/drivers/watchdog/jz4730_wdt.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * JZ4730 Watchdog Timer driver. + * + * Copyright (c) 2020 Lubomir Rintel lkundrak@v3.sk + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <wdt.h> +#include <div64.h> +#include <linux/bitops.h> +#include <asm/io.h> + +#define WDT_WTCSR 0x00 +#define WDT_WTCNT 0x04 + +#define WDT_WTCSR_START BIT(4) + +struct jz4730_wdt_priv { + void __iomem *base; + unsigned long clk_rate; + u32 timeout; +}; + +static int jz4730_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct jz4730_wdt_priv *priv = dev_get_priv(dev); + u64 timeout = timeout_ms * priv->clk_rate; + + do_div(timeout, 1000); + priv->timeout = U32_MAX - max_t(u32, timeout, 32); + wdt_reset(dev); + if (timeout) + writeb(WDT_WTCSR_START, priv->base + WDT_WTCSR); + + return 0; +} + +static int jz4730_wdt_reset(struct udevice *dev) +{ + struct jz4730_wdt_priv *priv = dev_get_priv(dev); + + writel(priv->timeout, priv->base + WDT_WTCNT); + + return 0; +} + +static const struct wdt_ops jz4730_wdt_ops = { + .start = jz4730_wdt_start, + .reset = jz4730_wdt_reset, +}; + +static int jz4730_wdt_probe(struct udevice *dev) +{ + struct jz4730_wdt_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + priv->clk_rate = clk_get_rate(&clk); + + return 0; +} + +static const struct udevice_id jz4730_wdt_ids[] = { + { .compatible = "ingenic,jz4730-watchdog" }, + { } +}; + +U_BOOT_DRIVER(wdt_jz4730) = { + .name = "wdt_jz4730", + .id = UCLASS_WDT, + .of_match = jz4730_wdt_ids, + .ops = &jz4730_wdt_ops, + .priv_auto_alloc_size = sizeof(struct jz4730_wdt_priv), + .probe = jz4730_wdt_probe, +};

This adds support for Ethernet MAC block on Ingenic JZ4730 SoC.
Based on old Ingenic GPL code dump, but significantly cleaned up and reworked (e.g. to plug into the MAC framework).
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- drivers/net/Kconfig | 11 + drivers/net/Makefile | 1 + drivers/net/jz4730_eth.c | 447 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 459 insertions(+) create mode 100644 drivers/net/jz4730_eth.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 3a5e0368805..41dd5951981 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -342,6 +342,17 @@ config FSLDMAFEC This driver supports the network interface units in the ColdFire family.
+ +config JZ4730_ETH + bool "Ingenic JZ4730 Ethernet Support" + depends on DM_ETH && SOC_JZ4730 + select PHYLIB + select MII + default y + help + This driver supports the network interface units in the + Ingenic JZ4730 SoC. + config KS8851_MLL bool "Microchip KS8851-MLL controller driver" help diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e3bdda359dc..67297066bc6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC110) += ftmac110.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o +obj-$(CONFIG_JZ4730_ETH) += jz4730_eth.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o obj-$(CONFIG_LAN91C96) += lan91c96.o obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o diff --git a/drivers/net/jz4730_eth.c b/drivers/net/jz4730_eth.c new file mode 100644 index 00000000000..99b9b68a5a0 --- /dev/null +++ b/drivers/net/jz4730_eth.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * JZ4730 Ethernet MAC driver. + * + * Copyright (C) 2005 Ingenic Semiconductor jlwei@ingenic.cn + * Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk + */ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> +#include <phy.h> +#include <eth_phy.h> +#include <miiphy.h> +#include <command.h> +#include <cpu_func.h> +#include <linux/delay.h> +#include <asm/io.h> + +#define ETH_BMR 0x1000 +#define ETH_TPDR 0x1004 +#define ETH_RAR 0x100C +#define ETH_TAR 0x1010 +#define ETH_SR 0x1014 +#define ETH_OMR 0x1018 +#define ETH_IER 0x101C +#define ETH_MFCR 0x1020 +#define ETH_MCR 0x0000 +#define ETH_MAHR 0x0004 +#define ETH_MALR 0x0008 +#define ETH_HTHR 0x000C +#define ETH_HTLR 0x0010 +#define ETH_MIAR 0x0014 +#define ETH_MIDR 0x0018 + +/* Bus Mode Register (DMA_BMR) */ +#define BMR_SWR 0x00000001 /* Software Reset */ + +#define DMA_BURST 4 + +/* Operation Mode Register (DMA_OMR) */ +#define OMR_TTM 0x00400000 /* Transmit Threshold Mode */ +#define OMR_SF 0x00200000 /* Store and Forward */ +#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */ +#define OMR_SR 0x00000002 /* Start/Stop Receive */ + +/* Mac control Register (MAC_MCR) */ +#define MCR_FDX 0x00100000 /* Full Duplex Mode */ +#define MCR_LCC 0x00001000 /* Late Collision control */ +#define MCR_DBF 0x00000800 /* Broadcast frame Disable */ +#define MCR_TE 0x00000008 /* Transmitter enable */ +#define MCR_RE 0x00000004 /* Receiver enable */ + +/* Constants for the intr mask and intr status registers. (DMA_SIS and DMA_IER) */ +#define DMA_INT_FB 0x00002000 /* Fatal bus error */ +#define DMA_INT_RW 0x00000200 /* Receive watchdog timeout */ +#define DMA_INT_RS 0x00000100 /* Receive stop */ +#define DMA_INT_RU 0x00000080 /* Receive buffer unavailble */ +#define DMA_INT_RI 0x00000040 /* Receive interrupt */ +#define DMA_INT_TJ 0x00000008 /* Transmit jabber timeout */ +#define DMA_INT_TU 0x00000004 /* Transmit buffer unavailble */ +#define DMA_INT_TS 0x00000002 /* Transmit stop */ +#define DMA_INT_TI 0x00000001 /* Transmit interrupt */ + +/* Receive Descriptor Bit Summary */ +#define R_OWN 0x80000000 /* Own Bit */ +#define RD_FL 0x3fff0000 /* Frame Length */ +#define RD_ES 0x00008000 /* Error Summary */ + +#define RD_RER 0x02000000 /* Receive End Of Ring */ +#define RD_RCH 0x01000000 /* Second Address Chained */ + +/* Transmit Descriptor Bit Summary */ +#define T_OWN 0x80000000 /* Own Bit */ + +#define TD_LS 0x40000000 /* Last Segment */ +#define TD_FS 0x20000000 /* First Segment */ +#define TD_TER 0x02000000 /* Transmit End Of Ring */ +#define TD_TCH 0x01000000 /* Second Address Chained */ + +#define MAX_WAIT 1000 + +/* Tx and Rx Descriptor */ +struct jz4730_eth_desc { + u32 status; + u32 ctrl; + u32 addr; + u32 next; +}; + +#define NUM_TX_DESCS 4 + +struct jz4730_eth_priv { + void __iomem *base; + struct mii_dev *bus; + struct phy_device *phy; + + int next_rx; + int next_tx; + + struct jz4730_eth_desc rx_desc[PKTBUFSRX]; + struct jz4730_eth_desc tx_desc[NUM_TX_DESCS]; +}; + +#define MII_CMD_ADDR(id, offset) (((id) << 11) | ((offset) << 6)) +#define MII_CMD_READ(id, offset) (MII_CMD_ADDR(id, offset)) +#define MII_CMD_WRITE(id, offset) (MII_CMD_ADDR(id, offset) | 0x2) + +static int jz4730_eth_mdio_read(struct mii_dev *bus, int addr, + int devad, int reg) +{ + struct jz4730_eth_priv *priv = bus->priv; + u32 mii_cmd = MII_CMD_READ(addr, reg); + int i; + + writel(mii_cmd, priv->base + ETH_MIAR); + + /* wait for completion */ + for (i = 0; i < MAX_WAIT; i++) { + if (!(readl(priv->base + ETH_MIAR) & 0x1)) + break; + udelay(1); + } + + if (i == MAX_WAIT) { + printf("MII wait timeout\n"); + return -EIO; + } + + return readl(priv->base + ETH_MIDR) & 0x0000ffff; +} + +static int jz4730_eth_mdio_write(struct mii_dev *bus, int addr, + int devad, int reg, u16 value) +{ + struct jz4730_eth_priv *priv = bus->priv; + u32 mii_cmd = MII_CMD_WRITE(addr, reg); + int i; + + writel(value, priv->base + ETH_MIDR); + writel(mii_cmd, priv->base + ETH_MIAR); + + /* wait for completion */ + for (i = 0; i < MAX_WAIT; i++) { + if (!(readl(priv->base + ETH_MIAR) & 0x1)) + break; + udelay(1); + } + + if (i == MAX_WAIT) { + printf("MII wait timeout\n"); + return -EIO; + } + + return 0; +} + +static int jz4730_eth_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct jz4730_eth_priv *priv = dev_get_priv(dev); + int addr = eth_phy_get_addr(dev); + int ret; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + pdata->iobase = (phys_addr_t)priv->base; + + priv->bus = mdio_alloc(); + if (!priv->bus) + return -ENOMEM; + + priv->bus->read = jz4730_eth_mdio_read; + priv->bus->write = jz4730_eth_mdio_write; + priv->bus->priv = priv; + strcpy(priv->bus->name, "jz4730_eth"); + + ret = mdio_register(priv->bus); + if (ret) + goto free_mdio; + + priv->phy = phy_connect(priv->bus, addr, dev, PHY_INTERFACE_MODE_MII); + if (!priv->phy) { + ret = -EIO; + goto unregister_mdio; + } + + phy_config(priv->phy); + + return 0; + +unregister_mdio: + mdio_unregister(priv->bus); +free_mdio: + mdio_free(priv->bus); + return ret; +} + +static int jz4730_eth_remove(struct udevice *dev) +{ + struct jz4730_eth_priv *priv = dev_get_priv(dev); + + phy_shutdown(priv->phy); + free(priv->phy); + mdio_unregister(priv->bus); + mdio_free(priv->bus); + + return 0; +} + +static void config_mac(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct jz4730_eth_priv *priv = dev_get_priv(dev); + u32 omr, mcr; + + /* Set MAC address */ +#define ea pdata->enetaddr + writel((ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | ea[0], priv->base + ETH_MALR); + writel((ea[5] << 8) | ea[4], priv->base + ETH_MAHR); + + writel(0, priv->base + ETH_HTLR); + writel(0, priv->base + ETH_HTHR); + + /* Assert the MCR_PS bit in CSR */ + if (priv->phy->speed == SPEED_100) + omr = OMR_SF; + else + omr = OMR_TTM | OMR_SF; + + mcr = MCR_TE | MCR_RE | MCR_DBF | MCR_LCC; + + if (priv->phy->duplex == DUPLEX_FULL) + mcr |= MCR_FDX; + + /* Set the Operation Mode (OMR) and Mac Control (MCR) registers */ + writel(omr, priv->base + ETH_OMR); + writel(mcr, priv->base + ETH_MCR); + + /* Set the Programmable Burst Length (BMR.PBL, value 1 or 4 is validate) */ + writel(DMA_BURST << 8, priv->base + ETH_BMR); + + /* Reset csr8 */ + readl(priv->base + ETH_MFCR); /* missed frams counter */ +} + +static int jz4730_eth_start(struct udevice *dev) +{ + struct jz4730_eth_priv *priv = dev_get_priv(dev); + int i; + + /* Reset ethernet unit */ + writel(readl(priv->base + ETH_BMR) | BMR_SWR, priv->base + ETH_BMR); + + for (i = 0; i < MAX_WAIT; i++) { + if (!(readl(priv->base + ETH_BMR) & BMR_SWR)) + break; + udelay(1); + } + + if (i == MAX_WAIT) { + printf("Reset eth timeout\n"); + return -EIO; + } + + /* Disable interrupts: we don't use ethernet interrupts */ + writel(0, priv->base + ETH_IER); + + /* Configure PHY */ + phy_startup(priv->phy); + + /* Configure MAC */ + config_mac(dev); + + /* Setup the Rx&Tx descriptors */ + for (i = 0; i < PKTBUFSRX; i++) { + priv->rx_desc[i].status = R_OWN; + priv->rx_desc[i].ctrl = PKTSIZE_ALIGN | RD_RCH; + priv->rx_desc[i].addr = virt_to_phys(net_rx_packets[i]); + priv->rx_desc[i].next = virt_to_phys(priv->rx_desc + i + 1); + + flush_dcache_range((ulong)net_rx_packets[i], + (ulong)net_rx_packets[i] + PKTSIZE_ALIGN); + } + priv->rx_desc[PKTBUFSRX - 1].next = virt_to_phys(priv->rx_desc); + priv->rx_desc[PKTBUFSRX - 1].ctrl |= RD_RER; + + flush_dcache_range((ulong)priv->rx_desc, + (ulong)priv->rx_desc + sizeof(priv->rx_desc)); + + for (i = 0; i < NUM_TX_DESCS; i++) { + priv->tx_desc[i].status = 0; + priv->tx_desc[i].ctrl = TD_TCH; + priv->tx_desc[i].addr = 0; + priv->tx_desc[i].next = virt_to_phys(priv->tx_desc + i + 1); + } + priv->tx_desc[NUM_TX_DESCS - 1].next = virt_to_phys(priv->tx_desc); + priv->tx_desc[NUM_TX_DESCS - 1].ctrl |= TD_TER; + + flush_dcache_range((ulong)priv->tx_desc, + (ulong)priv->tx_desc + sizeof(priv->tx_desc)); + + writel(virt_to_phys(priv->rx_desc), priv->base + ETH_RAR); + writel(virt_to_phys(priv->tx_desc), priv->base + ETH_TAR); + + priv->next_rx = 0; + priv->next_tx = 0; + + /* Enable ETH */ + writel(readl(priv->base + ETH_OMR) | OMR_ST | OMR_SR, priv->base + ETH_OMR); + + return 0; +} + +static int jz4730_eth_send(struct udevice *dev, void *packet, int length) +{ + struct jz4730_eth_priv *priv = dev_get_priv(dev); + struct jz4730_eth_desc *desc = &priv->tx_desc[priv->next_tx]; + int i; + + /* tx fifo should always be idle */ + desc->addr = virt_to_phys(packet); + desc->ctrl |= TD_LS | TD_FS | length; + desc->status = T_OWN; + + flush_dcache_range((ulong)packet, (ulong)packet + length); + flush_dcache_range((ulong)desc, (ulong)desc + sizeof(*desc)); + + /* Start the tx */ + writel(1, priv->base + ETH_TPDR); + + i = 0; + while (desc->status & T_OWN) { + if (i > MAX_WAIT) { + printf("ETH TX timeout\n"); + break; + } + udelay(1); + i++; + + flush_dcache_range((ulong)desc, (ulong)desc + sizeof(*desc)); + } + + writel(DMA_INT_TI | DMA_INT_TS | DMA_INT_TU | + DMA_INT_TJ | DMA_INT_FB, priv->base + ETH_SR); + + desc->status = 0; + desc->addr = 0; + desc->ctrl &= ~(TD_LS | TD_FS); + + flush_dcache_range((ulong)desc, (ulong)desc + sizeof(*desc)); + + priv->next_tx++; + if (priv->next_tx >= NUM_TX_DESCS) + priv->next_tx = 0; + + return 0; +} + +static int jz4730_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct jz4730_eth_priv *priv = dev_get_priv(dev); + struct jz4730_eth_desc *desc = &priv->rx_desc[priv->next_rx]; + int length; + u32 status; + + flush_dcache_range((ulong)desc, (ulong)desc + sizeof(*desc)); + + status = desc->status; + + if (status & R_OWN) { + /* Nothing has been received */ + return -EINVAL; + } + + length = ((status & RD_FL) >> 16); /* with 4-byte CRC value */ + + if (status & RD_ES) { + printf("ETH RX error 0x%x\n", status); + return 0; + } + + if (length < 4) { + printf("ETH RX buffer too short\n"); + return 0; + } + + flush_dcache_range((ulong)net_rx_packets[priv->next_rx], + (ulong)net_rx_packets[priv->next_rx] + PKTSIZE_ALIGN); + *packetp = net_rx_packets[priv->next_rx]; + + return length - 4; +} + +static int jz4730_eth_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct jz4730_eth_priv *priv = dev_get_priv(dev); + struct jz4730_eth_desc *desc = &priv->rx_desc[priv->next_rx]; + + /* Clear done bits */ + writel(DMA_INT_RI | DMA_INT_RS | DMA_INT_RU | + DMA_INT_RW | DMA_INT_FB, priv->base + ETH_SR); + + desc->status = R_OWN; + + flush_dcache_range((ulong)desc, (ulong)desc + sizeof(*desc)); + + priv->next_rx++; + if (priv->next_rx >= PKTBUFSRX) + priv->next_rx = 0; + + return 0; +} + +static void jz4730_eth_stop(struct udevice *dev) +{ + struct jz4730_eth_priv *priv = dev_get_priv(dev); + + phy_shutdown(priv->phy); + writel(readl(priv->base + ETH_OMR) & ~(OMR_ST | OMR_SR), priv->base + ETH_OMR); +} + +static const struct eth_ops jz4730_eth_ops = { + .start = jz4730_eth_start, + .send = jz4730_eth_send, + .recv = jz4730_eth_recv, + .free_pkt = jz4730_eth_free_pkt, + .stop = jz4730_eth_stop, +}; + +static const struct udevice_id jz4730_eth_ids[] = { + { .compatible = "ingenic,jz4730-ethernet" }, + { } +}; + +U_BOOT_DRIVER(jz4730_eth) = { + .name = "jz4730_eth", + .id = UCLASS_ETH, + .of_match = jz4730_eth_ids, + .probe = jz4730_eth_probe, + .remove = jz4730_eth_remove, + .ops = &jz4730_eth_ops, + .priv_auto_alloc_size = sizeof(struct jz4730_eth_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +};

This generally comes from a mipsbook400 Letux git repository [1], not mainline. It seems to be the work of Paul Boddie and H. Nikolaus Schaller.
[1] https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux/...
Some more things need to be addressed here:
1.) Linux upstream review of the bindings. The tree is generally very nice and complete and bindings look good, but an upstream review could still cut off some rough edges. In particular I think the gpio/pinctrl bindings don't seem to describe the hardware in a very useful way (GPIO split into multiple nodes for ports slaves to the pinctrl node).
2.) Missing copyright/license notices. Probably an oversignt.
3.) I've made some changes that I need to split out into separate patches for upstream and document.
Cc: Paul Boddie paul@boddie.org.uk Cc: H. Nikolaus Schaller hns@goldelico.com Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- arch/mips/dts/jz4730.dtsi | 340 +++++++++++++++++++++++++ include/dt-bindings/clock/jz4730-cgu.h | 47 ++++ 2 files changed, 387 insertions(+) create mode 100644 arch/mips/dts/jz4730.dtsi create mode 100644 include/dt-bindings/clock/jz4730-cgu.h
diff --git a/arch/mips/dts/jz4730.dtsi b/arch/mips/dts/jz4730.dtsi new file mode 100644 index 00000000000..8a986587d9d --- /dev/null +++ b/arch/mips/dts/jz4730.dtsi @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <dt-bindings/clock/jz4730-cgu.h> + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "ingenic,jz4730"; + + cpuintc: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + + intc: interrupt-controller@10001000 { + compatible = "ingenic,jz4730-intc"; + reg = <0x10001000 0x14>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpuintc>; + interrupts = <2>; + }; + + ext: ext { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + rtc: rtc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + + msc16m: msc16m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <16000000>; + }; + + msc24m: msc24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + + usb48m: usb48m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; + + cgu: jz4730-cgu@10000000 { + compatible = "ingenic,jz4730-cgu"; + reg = <0x10000000 0x100>; + + clocks = <&ext>, <&rtc>, <&msc16m>, <&msc24m>, <&usb48m>; + clock-names = "ext", "rtc", "msc16m", "msc24m", "usb48m"; + + #clock-cells = <1>; + }; + + tcu: timer@10002000 { + compatible = "ingenic,jz4730-tcu"; + reg = <0x10002000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x10002000 0x1000>; + + #clock-cells = <1>; + + clocks = <&cgu JZ4730_CLK_RTC>, + <&cgu JZ4730_CLK_EXT>, + <&cgu JZ4730_CLK_PCLK>, + <&cgu JZ4730_CLK_TCU>; + clock-names = "rtc", "ext", "pclk", "tcu"; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&intc>; + interrupts = <24 23 22>; + }; + + watchdog: watchdog@10004000 { + compatible = "ingenic,jz4730-watchdog"; + reg = <0x10004000 0x100>; + + clocks = <&cgu JZ4730_CLK_WDT>; + clock_names = "wdt"; + }; + + pwm: pwm@10050000 { + compatible = "ingenic,jz4730-pwm"; + reg = <0x10050000 0x2000>; + + #pwm-cells = <2>; + + clocks = <&ext>; + clock-names = "ext"; + }; + + rtc_dev: rtc@10003000 { + compatible = "ingenic,jz4740-rtc"; + reg = <0x10003000 0x10>; + + interrupt-parent = <&intc>; + interrupts = <15>; + + clocks = <&cgu JZ4730_CLK_RTC>; + clock-names = "rtc"; + }; + + pinctrl: pin-controller@10010000 { + compatible = "ingenic,jz4730-pinctrl"; + reg = <0x10010000 0x400>; + + #address-cells = <1>; + #size-cells = <0>; + + gpa: gpio@0 { + compatible = "ingenic,jz4730-gpio"; + reg = <0>; + + gpio-controller; + gpio-ranges = <&pinctrl 0 0 32>; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&intc>; + interrupts = <28>; + }; + + gpb: gpio@1 { + compatible = "ingenic,jz4730-gpio"; + reg = <1>; + + gpio-controller; + gpio-ranges = <&pinctrl 0 32 32>; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&intc>; + interrupts = <27>; + }; + + gpc: gpio@2 { + compatible = "ingenic,jz4730-gpio"; + reg = <2>; + + gpio-controller; + gpio-ranges = <&pinctrl 0 64 32>; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&intc>; + interrupts = <26>; + }; + + gpd: gpio@3 { + compatible = "ingenic,jz4730-gpio"; + reg = <3>; + + gpio-controller; + gpio-ranges = <&pinctrl 0 96 32>; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&intc>; + interrupts = <25>; + }; + }; + + i2s: i2s { + compatible = "ingenic,jt4730-dai"; + + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c: i2c@10042000 { + compatible = "ingenic,jz4730-i2c"; + reg = <0x10042000 0x10>; + + #address-cells = <1>; + #size-cells = <0>; + + interrupt-parent = <&intc>; + interrupts = <1>; + + clocks = <&cgu JZ4730_CLK_PLL>; + clock-names = "i2c"; + + clock-frequency = <100000>; + }; + + mmc: mmc@10021000 { + compatible = "ingenic,jz4740-mmc"; + reg = <0x10021000 0x100>; + + interrupt-parent = <&intc>; + interrupts = <14>; + + clocks = <&cgu JZ4730_CLK_MMC>; + clock-names = "mmc"; + }; + + uart0: serial@10030000 { + compatible = "ingenic,jz4740-uart", "ingenic,jz4780-uart"; + reg = <0x10030000 0x100>; + + reg-shift = <2>; + fifo-size = <16>; + tx-threshold = <8>; + + interrupt-parent = <&intc>; + interrupts = <9>; + + clocks = <&ext>, <&cgu JZ4730_CLK_UART0>; + clock-names = "baud", "module"; + }; + + uart1: serial@10031000 { + compatible = "ingenic,jz4740-uart", "ingenic,jz4780-uart"; + reg = <0x10031000 0x100>; + + reg-shift = <2>; + fifo-size = <16>; + tx-threshold = <8>; + + interrupt-parent = <&intc>; + interrupts = <8>; + + clocks = <&ext>, <&cgu JZ4730_CLK_UART1>; + clock-names = "baud", "module"; + }; + + uart2: serial@10032000 { + compatible = "ingenic,jz4740-uart", "ingenic,jz4780-uart"; + reg = <0x10032000 0x100>; + + reg-shift = <2>; + fifo-size = <16>; + tx-threshold = <8>; + + interrupt-parent = <&intc>; + interrupts = <7>; + + clocks = <&ext>, <&cgu JZ4730_CLK_UART2>; + clock-names = "baud", "module"; + }; + + uart3: serial@10033000 { + compatible = "ingenic,jz4740-uart", "ingenic,jz4780-uart"; + reg = <0x10033000 0x100>; + + reg-shift = <2>; + fifo-size = <16>; + tx-threshold = <8>; + + interrupt-parent = <&intc>; + interrupts = <6>; + + clocks = <&ext>, <&cgu JZ4730_CLK_UART3>; + clock-names = "baud", "module"; + }; + + dma: dma@10020000 { + compatible = "ingenic,jz4730-dma"; + reg = <0x10020000 0x100>; + + interrupt-parent = <&intc>; + interrupts = <21>; + + clocks = <&cgu JZ4730_CLK_DMA>; + clock-names = "dma"; + + #dma-cells = <1>; + dma-channels = <6>; + }; + + emc: memory-controller@13010000 { + #address-cells = <0>; + #size-cells = <0>; + compatible = "ingenic,jz4730-emc", "simple-mfd"; + reg = <0x13010000 0xf000>; + + nand: nand-controller { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ingenic,jz4730-nand"; + }; + }; + + uhc: uhc@13030000 { + compatible = "ingenic,jz4740-ohci", "generic-ohci"; + reg = <0x13030000 0x1000>; + + clocks = <&cgu JZ4730_CLK_UHC>; + assigned-clocks = <&cgu JZ4730_CLK_UHC>; + assigned-clock-rates = <48000000>; + + interrupt-parent = <&intc>; + interrupts = <13>; + + status = "disabled"; + }; + + ethernet: ethernet@13100000 { + compatible = "ingenic,jz4730-ethernet"; + reg = <0x13100000 0x1000>; + + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + lcd: lcd@10050000 { + compatible = "ingenic,jz4740-lcd"; + reg = <0x10050000 0x100>; + + interrupt-parent = <&intc>; + interrupts = <30>; + + clocks = <&cgu JZ4730_CLK_LCD>, <&cgu JZ4730_CLK_LCD_PCLK>; + clock-names = "lcd", "lcd_pclk"; + }; +}; diff --git a/include/dt-bindings/clock/jz4730-cgu.h b/include/dt-bindings/clock/jz4730-cgu.h new file mode 100644 index 00000000000..2dbaca52332 --- /dev/null +++ b/include/dt-bindings/clock/jz4730-cgu.h @@ -0,0 +1,47 @@ +/* + * This header provides clock numbers for the ingenic,jz4730-cgu DT binding. + * + * They are roughly ordered as: + * - external clocks + * - PLLs + * - muxes/dividers + * - gates in order of their bit in the MSCR* registers + */ + +#ifndef __DT_BINDINGS_CLOCK_JZ4730_CGU_H__ +#define __DT_BINDINGS_CLOCK_JZ4730_CGU_H__ + +#define JZ4730_CLK_EXT 0 +#define JZ4730_CLK_RTC 1 +#define JZ4730_CLK_MSC16M 2 +#define JZ4730_CLK_MSC24M 3 +#define JZ4730_CLK_USB48M 4 +#define JZ4730_CLK_PLL 5 +#define JZ4730_CLK_PLL_HALF 6 +#define JZ4730_CLK_CCLK_PLL 7 +#define JZ4730_CLK_CCLK 8 +#define JZ4730_CLK_HCLK_PLL 9 +#define JZ4730_CLK_HCLK 10 +#define JZ4730_CLK_PCLK_PLL 11 +#define JZ4730_CLK_PCLK 12 +#define JZ4730_CLK_MCLK_PLL 13 +#define JZ4730_CLK_MCLK 14 +#define JZ4730_CLK_LCD_PLL 15 +#define JZ4730_CLK_LCD 16 +#define JZ4730_CLK_LCD_PCLK 17 +#define JZ4730_CLK_I2S 18 +#define JZ4730_CLK_SPI 19 +#define JZ4730_CLK_DMA 20 +#define JZ4730_CLK_MMC 21 +#define JZ4730_CLK_UHC_IN 22 +#define JZ4730_CLK_UHC 23 +#define JZ4730_CLK_UART0 24 +#define JZ4730_CLK_UART1 25 +#define JZ4730_CLK_UART2 26 +#define JZ4730_CLK_UART3 27 +#define JZ4730_CLK_I2C 28 +#define JZ4730_CLK_TCU 29 +#define JZ4730_CLK_EXT_128 30 +#define JZ4730_CLK_WDT 31 + +#endif /* __DT_BINDINGS_CLOCK_JZ4730_CGU_H__ */

This adds support for the Ingenic JZ4730 SoC. There's not much more than the build machinery and SPL stage because the main stage is entirely DT driven.
The SPL is fairly unsophisticated since it has to fit into 4096 bytes. The serial support didn't fit, and the pinmux and PLL init duplicates some functionality of full drivers for space reasons. A regular NAND flash driver is used though.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- arch/mips/mach-jz47xx/Kconfig | 39 +++ arch/mips/mach-jz47xx/Makefile | 2 + arch/mips/mach-jz47xx/jz4730/Kconfig | 87 ++++++ arch/mips/mach-jz47xx/jz4730/Makefile | 3 + arch/mips/mach-jz47xx/jz4730/lowlevel_init.S | 37 +++ arch/mips/mach-jz47xx/jz4730/spl.c | 293 +++++++++++++++++++ 6 files changed, 461 insertions(+) create mode 100644 arch/mips/mach-jz47xx/jz4730/Kconfig create mode 100644 arch/mips/mach-jz47xx/jz4730/Makefile create mode 100644 arch/mips/mach-jz47xx/jz4730/lowlevel_init.S create mode 100644 arch/mips/mach-jz47xx/jz4730/spl.c
diff --git a/arch/mips/mach-jz47xx/Kconfig b/arch/mips/mach-jz47xx/Kconfig index dcaac016286..6fba38c7363 100644 --- a/arch/mips/mach-jz47xx/Kconfig +++ b/arch/mips/mach-jz47xx/Kconfig @@ -4,6 +4,41 @@ menu "Ingenic JZ47xx platforms" config SYS_SOC default "jz47xx"
+config SPL_TEXT_BASE + default 0x80000000 if ARCH_JZ47XX + +config SYS_TEXT_BASE + default 0x80100000 if ARCH_JZ47XX + +config SOC_JZ4730 + bool + select MIPS_INIT_STACK_IN_SRAM + select SUPPORTS_CPU_MIPS32_R1 + select SUPPORTS_LITTLE_ENDIAN + select SYS_RELOC_GD_ENV_ADDR + select SPL_INIT_STACK_WITHOUT_MALLOC_F if SPL + select SPL_LIBCOMMON_SUPPORT if SPL + select SPL_LIBGENERIC_SUPPORT if SPL + select SPL_LOADER_SUPPORT if SPL + imply CLK + imply CMD_DM + imply DM_GPIO + imply DM_MMC + imply DM_MTD + imply DM_SERIAL + imply FIT + imply MMC + imply MTD + imply MTD_RAW_NAND + imply PINCTRL + imply SPL + imply SYS_NS16550 + imply SYSRESET + imply SYSRESET_WATCHDOG + imply TIMER + help + Support for Ingenic JZ4730 family SoCs. + config SOC_JZ4780 bool select SUPPORTS_LITTLE_ENDIAN @@ -21,6 +56,10 @@ config TARGET_JZ4780_CI20
endchoice
+source "arch/mips/mach-jz47xx/jz4730/Kconfig" + +source "board/skytone/alpha400/Kconfig" + source "board/imgtec/ci20/Kconfig"
endmenu diff --git a/arch/mips/mach-jz47xx/Makefile b/arch/mips/mach-jz47xx/Makefile index dbb8229f785..9c57577440d 100644 --- a/arch/mips/mach-jz47xx/Makefile +++ b/arch/mips/mach-jz47xx/Makefile @@ -2,4 +2,6 @@
extra-$(CONFIG_SPL_BUILD) := start.o
+obj-$(CONFIG_SOC_JZ4730) += jz4730/ + obj-$(CONFIG_SOC_JZ4780) += jz4780/ diff --git a/arch/mips/mach-jz47xx/jz4730/Kconfig b/arch/mips/mach-jz47xx/jz4730/Kconfig new file mode 100644 index 00000000000..392903d208c --- /dev/null +++ b/arch/mips/mach-jz47xx/jz4730/Kconfig @@ -0,0 +1,87 @@ +if SOC_JZ4730 + +config SYS_DCACHE_SIZE + default 16384 + +config SYS_DCACHE_LINE_SIZE + default 32 + +config SYS_ICACHE_SIZE + default 16384 + +config SYS_ICACHE_LINE_SIZE + default 32 + +config SYS_MALLOC_F_LEN + default 0x1000 + +config SPL_SIZE_LIMIT + default 4096 + +config MIPS_CACHE_SETUP + default n + +config MIPS_CACHE_DISABLE + default n + +config JZ4730_SDRAM_BANK_SIZE + int + help + Megabytes per bank. + +config JZ4730_SDRAM_ROW + int + help + Row address. + +config JZ4730_SDRAM_COL + int + help + Column address. + +config JZ4730_SDRAM_BANKS_PER_CHIP + int + help + Banks per chip. + +config JZ4730_SDRAM_WIDTH + int + help + Data bus width. + +config JZ4730_SDRAM_CAS + int + help + CAS latency: 2 or 3. + +config JZ4730_SDRAM_TRAS + int + help + RAS# Active Time. + +config JZ4730_SDRAM_RCD + int + help + RAS# to CAS# Delay. + +config JZ4730_SDRAM_TPC + int + help + RAS# Precharge Time. + +config JZ4730_SDRAM_TRW + int + help + Write Latency Time. + +config JZ4730_SDRAM_TREF + int + help + Refresh period: 8192 refresh cycles/64ms. + +config JZ4730_SDRAM_CKS + int + help + CKO Divider. + +endif diff --git a/arch/mips/mach-jz47xx/jz4730/Makefile b/arch/mips/mach-jz47xx/jz4730/Makefile new file mode 100644 index 00000000000..9a979fa0550 --- /dev/null +++ b/arch/mips/mach-jz47xx/jz4730/Makefile @@ -0,0 +1,3 @@ +obj-y += lowlevel_init.o + +obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/arch/mips/mach-jz47xx/jz4730/lowlevel_init.S b/arch/mips/mach-jz47xx/jz4730/lowlevel_init.S new file mode 100644 index 00000000000..fa7bfe89a3c --- /dev/null +++ b/arch/mips/mach-jz47xx/jz4730/lowlevel_init.S @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk + * + * Derived from work that's Copyright (c) 2003 + * Wolfgang Denk wd@denx.de + */ + +#include <config.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/asm.h> + +LEAF(lowlevel_init) + + /* Invalidate BTB */ + mfc0 t0, CP0_CONFIG, 7 + nop + ori t0, 2 + mtc0 t0, CP0_CONFIG, 7 + nop + + /* + * CU0=UM=EXL=IE=0, BEV=ERL=1, IP2~7=1 + */ + li t0, 0x0040FC04 + mtc0 t0, CP0_STATUS + + /* CAUSE register */ + /* IV=1, use the specical interrupt vector (0x200) */ + li t1, 0x00800000 + mtc0 t1, CP0_CAUSE + + jr ra + nop + + END(lowlevel_init) diff --git a/arch/mips/mach-jz47xx/jz4730/spl.c b/arch/mips/mach-jz47xx/jz4730/spl.c new file mode 100644 index 00000000000..ea823e00f11 --- /dev/null +++ b/arch/mips/mach-jz47xx/jz4730/spl.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * JZ4730 Secondary Program Load. + * + * Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk + * + * Based on code that's (C) Copyright 2006 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + */ + +#include <asm/io.h> +#include <asm/sections.h> +#include <common.h> +#include <cpu_func.h> +#include <hang.h> +#include <init.h> +#include <linux/bitops.h> +#include <spl.h> + +#define C0_CONFIG7_BTBV BIT(1) + +static void early_init(void) +{ + /* + * Enable and clear the branch target buffer + */ + write_c0_config7(read_c0_config7() | C0_CONFIG7_BTBV); + + /* + * Clear the BSS + */ + memset(__bss_start, 0, (char *)&__bss_end - __bss_start); +} + +#define EMC_BASE (void __iomem *)0xb3010000 +#define EMC_BCR 0x00 +#define EMC_DMCR 0x80 +#define EMC_RTCSR 0x84 +#define EMC_RTCNT 0x88 +#define EMC_RTCOR 0x8c +#define EMC_DMAR1 0x90 +#define EMC_DMAR2 0x94 + +#define EMC_BCR_BRE BIT(1) + +#define EMC_DMCR_BW_SHIFT 31 +#define EMC_DMCR_CA_SHIFT 26 +#define EMC_DMCR_RFSH BIT(24) +#define EMC_DMCR_MRSET BIT(23) +#define EMC_DMCR_RA_SHIFT 20 +#define EMC_DMCR_BA_SHIFT 19 +#define EMC_DMCR_EPIN BIT(17) +#define EMC_DMCR_TRAS_SHIFT 13 +#define EMC_DMCR_RCD_SHIFT 11 +#define EMC_DMCR_TPC_SHIFT 8 +#define EMC_DMCR_TRWL_SHIFT 5 +#define EMC_DMCR_TRC_SHIFT 2 +#define EMC_DMCR_TCL_SHIFT 0 + +#define EMC_RTCSR_CKS_SHIFT 0 + +#define EMC_SDMR_CAS_SHIFT 4 +#define EMC_SDMR_BL_SHIFT 0 + +#define EMC_SDMR0 0xa000 +#define EMC_SDMR1 0xb000 + +void sdram_init(void) +{ + register unsigned int dmcr, sdmode, tmp, ns; + + /* + * Enable SPLIT + */ + writel(EMC_BCR_BRE, EMC_BASE + EMC_BCR); + + writew(0 << EMC_RTCSR_CKS_SHIFT, EMC_BASE + EMC_RTCSR); + writew(0, EMC_BASE + EMC_RTCOR); + writew(0, EMC_BASE + EMC_RTCNT); + + /* + * Megabytes per bank + */ + tmp = 0x20f0; + tmp |= CONFIG_JZ4730_SDRAM_BANK_SIZE / 2; + writel(tmp, EMC_BASE + EMC_DMAR1); + tmp |= (CONFIG_JZ4730_SDRAM_BANK_SIZE / 2) << 8; + writel(tmp, EMC_BASE + EMC_DMAR2); + + /* + * Basic DMCR register value + */ + dmcr = (CONFIG_JZ4730_SDRAM_ROW - 11) << EMC_DMCR_RA_SHIFT; + dmcr |= (CONFIG_JZ4730_SDRAM_ROW - 11) << EMC_DMCR_RA_SHIFT; + dmcr |= (CONFIG_JZ4730_SDRAM_COL - 8) << EMC_DMCR_CA_SHIFT; + dmcr |= (CONFIG_JZ4730_SDRAM_BANKS_PER_CHIP / 2 - 1) << EMC_DMCR_BA_SHIFT; + dmcr |= (CONFIG_JZ4730_SDRAM_WIDTH == 32 ? 0 : 1) << EMC_DMCR_BW_SHIFT; + dmcr |= EMC_DMCR_EPIN; + dmcr |= (CONFIG_JZ4730_SDRAM_CAS - 1) << EMC_DMCR_TCL_SHIFT; + + /* + * SDRAM timimg parameters + */ + ns = 1000000000 / (CONFIG_CPU_FREQ_HZ / 3); + tmp = CONFIG_JZ4730_SDRAM_TRAS / ns; + if (tmp < 4) + tmp = 4; + if (tmp > 11) + tmp = 11; + dmcr |= (tmp - 4) << EMC_DMCR_TRAS_SHIFT; + tmp = CONFIG_JZ4730_SDRAM_RCD / ns; + if (tmp > 3) + tmp = 3; + dmcr |= tmp << EMC_DMCR_RCD_SHIFT; + tmp = CONFIG_JZ4730_SDRAM_TPC / ns; + if (tmp > 7) + tmp = 7; + dmcr |= tmp << EMC_DMCR_TPC_SHIFT; + tmp = CONFIG_JZ4730_SDRAM_TRW / ns; + if (tmp > 3) + tmp = 3; + dmcr |= tmp << EMC_DMCR_TRWL_SHIFT; + tmp = (CONFIG_JZ4730_SDRAM_TRAS + CONFIG_JZ4730_SDRAM_TPC) / ns; + if (tmp > 14) + tmp = 14; + dmcr |= ((tmp + 1) >> 1) << EMC_DMCR_TRC_SHIFT; + + /* + * SDRAM mode values + */ + sdmode = (generic_ffs(4) - 1) << EMC_SDMR_BL_SHIFT; + sdmode |= CONFIG_JZ4730_SDRAM_CAS << EMC_SDMR_CAS_SHIFT; + sdmode <<= (CONFIG_JZ4730_SDRAM_WIDTH == 32) ? 2 : 1; + + /* + * Precharge phase + */ + writel(dmcr, EMC_BASE + EMC_DMCR); + + /* + * Set refresh registers + */ + tmp = CONFIG_JZ4730_SDRAM_TREF / ns; + tmp = tmp / 64 + 1; + if (tmp > 0xff) + tmp = 0xff; + + writew(tmp, EMC_BASE + EMC_RTCOR); + + /* + * CKO Divisor + */ + switch (CONFIG_JZ4730_SDRAM_CKS) { + case 4: + writew(1 << EMC_RTCSR_CKS_SHIFT, EMC_BASE + EMC_RTCSR); + break; + case 16: + writew(2 << EMC_RTCSR_CKS_SHIFT, EMC_BASE + EMC_RTCSR); + break; + case 64: + writew(3 << EMC_RTCSR_CKS_SHIFT, EMC_BASE + EMC_RTCSR); + break; + case 256: + writew(4 << EMC_RTCSR_CKS_SHIFT, EMC_BASE + EMC_RTCSR); + break; + case 1024: + writew(5 << EMC_RTCSR_CKS_SHIFT, EMC_BASE + EMC_RTCSR); + break; + case 2048: + writew(6 << EMC_RTCSR_CKS_SHIFT, EMC_BASE + EMC_RTCSR); + break; + case 4096: + writew(7 << EMC_RTCSR_CKS_SHIFT, EMC_BASE + EMC_RTCSR); + break; + } + + /* + * Precharge all chip-selects + */ + writeb(0, EMC_BASE + (EMC_SDMR0 | sdmode)); + writeb(0, EMC_BASE + (EMC_SDMR1 | sdmode)); + + /* + * Wait for precharge, > 200us + */ + tmp = (CONFIG_CPU_FREQ_HZ / 1000000) * 200; + while (tmp--) + ; + + /* + * Enable refresh and set SDRAM mode + */ + writel(dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET, EMC_BASE + EMC_DMCR); + + /* + * Write sdram mode register for each chip-select + */ + writeb(0, EMC_BASE + (EMC_SDMR0 | sdmode)); + writeb(0, EMC_BASE + (EMC_SDMR1 | sdmode)); +} + +#define CPM_BASE (void __iomem *)0xb0000000 +#define CPM_CFCR 0x00 +#define CPM_PLCR1 0x10 + +#define CPM_CFCR_CCLK_PLL_SHIFT 0 +#define CPM_CFCR_HCLK_PLL_SHIFT 4 +#define CPM_CFCR_PCLK_PLL_SHIFT 8 +#define CPM_CFCR_LCD_PLL_SHIFT 12 +#define CPM_CFCR_MCLK_PLL_SHIFT 16 +#define CPM_CFCR_MCLK_COKEN1 BIT(22) +#define CPM_CFCR_UHC_IN_SHIFT 25 + +#define CPM_PLCR1_PLL_STABLE_TIME_SHIFT 0 +#define CPM_PLCR1_PLL_ENABLE BIT(8) +#define CPM_PLCR1_PLL_OD_SHIFT 16 +#define CPM_PLCR1_PLL_N_SHIFT 18 +#define CPM_PLCR1_PLL_M_SHIFT 23 + +static void clock_init(void) +{ + u32 val; + + /* + * Clock divisors + */ + val = CPM_CFCR_MCLK_COKEN1; + val |= 0 << CPM_CFCR_CCLK_PLL_SHIFT; + val |= 2 << CPM_CFCR_HCLK_PLL_SHIFT; + val |= 2 << CPM_CFCR_PCLK_PLL_SHIFT; + val |= 2 << CPM_CFCR_LCD_PLL_SHIFT; + val |= 2 << CPM_CFCR_MCLK_PLL_SHIFT; + val |= (CONFIG_CPU_FREQ_HZ / 48000000 - 1) << CPM_CFCR_UHC_IN_SHIFT; + writel(val, CPM_BASE + CPM_CFCR); + + /* + * Main PLL + */ + val = (CONFIG_CPU_FREQ_HZ * 2 / CONFIG_SYS_CLK - 2) << CPM_PLCR1_PLL_M_SHIFT; + val |= 0 << CPM_PLCR1_PLL_N_SHIFT; + val |= 0 << CPM_PLCR1_PLL_OD_SHIFT; + val |= 0x20 << CPM_PLCR1_PLL_STABLE_TIME_SHIFT; + val |= CPM_PLCR1_PLL_ENABLE; + writel(val, CPM_BASE + CPM_PLCR1); +} + +#define PINCTRL_BASE (void __iomem *)0xb0010000 +#define PINCTRL_ALR(n) (0x10 + (n) * 0x30) +#define PINCTRL_AUR(n) (0x14 + (n) * 0x30) + +static void pinmux_init(void) +{ + /* + * NAND Read Enable function on GP79 + */ + clrbits_32(PINCTRL_BASE + PINCTRL_ALR(2), 0xc0000000); + setbits_32(PINCTRL_BASE + PINCTRL_ALR(2), 0x40000000); + + /* + * NAND Write Enable on GP80, NAND Ready/Busy on GP81 and + * SDRAM CS1 on GP82 + */ + clrbits_32(PINCTRL_BASE + PINCTRL_AUR(2), 0x0000003f); + setbits_32(PINCTRL_BASE + PINCTRL_AUR(2), 0x00000015); + + /* + * UART0 RX/TX on GP126/GP127 + */ + clrbits_32(PINCTRL_BASE + PINCTRL_AUR(3), 0xf0000000); + setbits_32(PINCTRL_BASE + PINCTRL_AUR(3), 0x50000000); +} + +void __noreturn board_init_f(ulong dummy) +{ + early_init(); + + spl_init(); + + pinmux_init(); + + clock_init(); + + sdram_init(); + + board_init_r(NULL, 0); + + hang(); +} + +u32 spl_boot_device(void) +{ + return BOOT_DEVICE_NAND; +}

This generally comes from a mipsbook400 Letux git repository [1], not mainline. It seems to be the work of Paul Boddie and H. Nikolaus Schaller.
[1] https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux/...
Some more things need to be addressed here:
1.) Linux upstream review of the bindings. The tree is generally very nice and complete and bindings look good, but an upstream review could still cut off some rough edges. In particular I think the gpio/pinctrl bindings don't seem to describe the hardware in a very useful way (GPIO split into multiple nodes for ports slaves to the pinctrl node).
2.) Missing copyright/license notices. Probably an oversignt.
3.) I've made some changes that I need to split out into separate patches for upstream and document.
Cc: Paul Boddie paul@boddie.org.uk Cc: H. Nikolaus Schaller hns@goldelico.com Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- arch/mips/dts/Makefile | 1 + arch/mips/dts/alpha400.dts | 542 +++++++++++++++++++++++++++++++++++++ 2 files changed, 543 insertions(+) create mode 100644 arch/mips/dts/alpha400.dts
diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile index dc85901dcaa..62ee25ff341 100644 --- a/arch/mips/dts/Makefile +++ b/arch/mips/dts/Makefile @@ -25,6 +25,7 @@ dtb-$(CONFIG_BOARD_SAGEM_FAST1704) += sagem,f@st1704.dtb dtb-$(CONFIG_BOARD_SFR_NB4_SER) += sfr,nb4-ser.dtb dtb-$(CONFIG_BOARD_TPLINK_WDR4300) += tplink_wdr4300.dtb dtb-$(CONFIG_BOARD_VOCORE2) += vocore_vocore2.dtb +dtb-$(CONFIG_TARGET_JZ4730_ALPHA400) += alpha400.dtb dtb-$(CONFIG_TARGET_JZ4780_CI20) += ci20.dtb dtb-$(CONFIG_SOC_LUTON) += luton_pcb090.dtb luton_pcb091.dtb dtb-$(CONFIG_SOC_OCELOT) += ocelot_pcb120.dtb ocelot_pcb123.dtb diff --git a/arch/mips/dts/alpha400.dts b/arch/mips/dts/alpha400.dts new file mode 100644 index 00000000000..fa02f841d1a --- /dev/null +++ b/arch/mips/dts/alpha400.dts @@ -0,0 +1,542 @@ +/dts-v1/; + +#include "jz4730.dtsi" +#include <dt-bindings/input/input.h> +#include <dt-bindings/gpio/gpio.h> + +/ { + compatible = "letux400,minipc", "ingenic,jz4730"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + wdt-reboot { + compatible = "wdt-reboot"; + wdt = <&watchdog>; + }; + + vcc: regulator@0 { + compatible = "regulator-fixed"; + regulator-name = "vcc"; + + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vmmc_reg: regulator@1 { + compatible = "regulator-fixed"; + regulator-name = "vmmc"; + + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpa 21 GPIO_ACTIVE_LOW>; + }; + + clk_usb: clk-usb { + compatible = "gpio-gate-clock"; + clocks = <&cgu JZ4730_CLK_UHC>; + #clock-cells = <0>; + enable-gpios = <&gpa 29 GPIO_ACTIVE_HIGH>; + }; + + keyboard { + linux,wakeup; + + compatible = "gpio-matrix-keypad"; + debounce-delay-ms = <10>; + col-scan-delay-us = <10>; + + row-gpios = <&gpa 0 0 &gpa 1 0 &gpa 2 0 &gpa 3 0 + &gpa 4 0 &gpa 5 0 &gpa 6 0 &gpa 7 0>; + + col-gpios = <&gpd 0 0 &gpd 1 0 &gpd 2 0 &gpd 3 0 + &gpd 4 0 &gpd 5 0 &gpd 6 0 &gpd 7 0 + &gpd 8 0 &gpd 9 0 &gpd 10 0 &gpd 11 0 + &gpd 12 0 &gpd 13 0 &gpd 14 0 &gpd 15 0 + &gpd 29 0>; + gpio-activelow; + + /* + * Keymap column-by-column, based on... + * https://web.archive.org/web/20120214204001/http://projects.kwaak.net/twiki/b... + * ...and subsequently verified. + */ + + linux,keymap = < + MATRIX_KEY(0, 0, KEY_PAUSE) + MATRIX_KEY(1, 0, 0) + MATRIX_KEY(2, 0, 0) + MATRIX_KEY(3, 0, 0) + MATRIX_KEY(4, 0, 0) + MATRIX_KEY(5, 0, 0) + MATRIX_KEY(6, 0, KEY_LEFTCTRL) + MATRIX_KEY(7, 0, KEY_F5) + + MATRIX_KEY(0, 1, KEY_Q) + MATRIX_KEY(1, 1, KEY_TAB) + MATRIX_KEY(2, 1, KEY_A) + MATRIX_KEY(3, 1, KEY_ESC) + MATRIX_KEY(4, 1, KEY_Z) + MATRIX_KEY(5, 1, 0) + MATRIX_KEY(6, 1, KEY_GRAVE) + MATRIX_KEY(7, 1, KEY_1) + + MATRIX_KEY(0, 2, KEY_W) + MATRIX_KEY(1, 2, KEY_CAPSLOCK) + MATRIX_KEY(2, 2, KEY_S) + MATRIX_KEY(3, 2, KEY_102ND) + MATRIX_KEY(4, 2, KEY_X) + MATRIX_KEY(5, 2, 0) + MATRIX_KEY(6, 2, 0) + MATRIX_KEY(7, 2, KEY_2) + + MATRIX_KEY(0, 3, KEY_E) + MATRIX_KEY(1, 3, KEY_F3) + MATRIX_KEY(2, 3, KEY_D) + MATRIX_KEY(3, 3, KEY_F4) + MATRIX_KEY(4, 3, KEY_C) + MATRIX_KEY(5, 3, 0) + MATRIX_KEY(6, 3, 0) + MATRIX_KEY(7, 3, KEY_3) + + MATRIX_KEY(0, 4, KEY_R) + MATRIX_KEY(1, 4, KEY_T) + MATRIX_KEY(2, 4, KEY_F) + MATRIX_KEY(3, 4, KEY_G) + MATRIX_KEY(4, 4, KEY_V) + MATRIX_KEY(5, 4, KEY_B) + MATRIX_KEY(6, 4, KEY_5) + MATRIX_KEY(7, 4, KEY_4) + + MATRIX_KEY(0, 5, KEY_U) + MATRIX_KEY(1, 5, KEY_Y) + MATRIX_KEY(2, 5, KEY_J) + MATRIX_KEY(3, 5, KEY_H) + MATRIX_KEY(4, 5, KEY_M) + MATRIX_KEY(5, 5, KEY_N) + MATRIX_KEY(6, 5, KEY_6) + MATRIX_KEY(7, 5, KEY_7) + + MATRIX_KEY(0, 6, KEY_I) + MATRIX_KEY(1, 6, KEY_RIGHTBRACE) + MATRIX_KEY(2, 6, KEY_K) + MATRIX_KEY(3, 6, KEY_F6) + MATRIX_KEY(4, 6, KEY_COMMA) + MATRIX_KEY(5, 6, 0) + MATRIX_KEY(6, 6, KEY_EQUAL) + MATRIX_KEY(7, 6, KEY_8) + + MATRIX_KEY(0, 7, KEY_O) + MATRIX_KEY(1, 7, KEY_F7) + MATRIX_KEY(2, 7, KEY_L) + MATRIX_KEY(3, 7, 0) + MATRIX_KEY(4, 7, KEY_DOT) + MATRIX_KEY(5, 7, KEY_F19) + MATRIX_KEY(6, 7, KEY_F8) + MATRIX_KEY(7, 7, KEY_9) + + MATRIX_KEY(0, 8, 0) + MATRIX_KEY(1, 8, 0) + MATRIX_KEY(2, 8, 0) + MATRIX_KEY(3, 8, KEY_SPACE) + MATRIX_KEY(4, 8, KEY_NUMLOCK) + MATRIX_KEY(5, 8, 0) + MATRIX_KEY(6, 8, KEY_DELETE) + MATRIX_KEY(7, 8, 0) + + MATRIX_KEY(0, 9, 0) + MATRIX_KEY(1, 9, KEY_BACKSPACE) + MATRIX_KEY(2, 9, 0) + MATRIX_KEY(3, 9, 0) + MATRIX_KEY(4, 9, KEY_ENTER) + MATRIX_KEY(5, 9, 0) + MATRIX_KEY(6, 9, KEY_F9) + MATRIX_KEY(7, 9, 0) + + MATRIX_KEY(0, 10, 0) + MATRIX_KEY(1, 10, 0) + MATRIX_KEY(2, 10, 0) + MATRIX_KEY(3, 10, KEY_LEFTALT) + MATRIX_KEY(4, 10, 0) + MATRIX_KEY(5, 10, 0) + MATRIX_KEY(6, 10, 0) + MATRIX_KEY(7, 10, KEY_SYSRQ) + + MATRIX_KEY(0, 11, KEY_P) + MATRIX_KEY(1, 11, KEY_LEFTBRACE) + MATRIX_KEY(2, 11, KEY_SEMICOLON) + MATRIX_KEY(3, 11, KEY_APOSTROPHE) + MATRIX_KEY(4, 11, KEY_BACKSLASH) + MATRIX_KEY(5, 11, KEY_SLASH) + MATRIX_KEY(6, 11, KEY_MINUS) + MATRIX_KEY(7, 11, KEY_0) + + MATRIX_KEY(0, 12, 0) + MATRIX_KEY(1, 12, KEY_F20) + MATRIX_KEY(2, 12, 0) + MATRIX_KEY(3, 12, 0) + MATRIX_KEY(4, 12, 0) + MATRIX_KEY(5, 12, 0) + MATRIX_KEY(6, 12, 0) + MATRIX_KEY(7, 12, KEY_F10) + + MATRIX_KEY(0, 13, 0) + MATRIX_KEY(1, 13, 0) + MATRIX_KEY(2, 13, 0) + MATRIX_KEY(3, 13, 0) + MATRIX_KEY(4, 13, 0) + MATRIX_KEY(5, 13, 0) + MATRIX_KEY(6, 13, KEY_F2) + MATRIX_KEY(7, 13, 0) + + MATRIX_KEY(0, 14, 0) + MATRIX_KEY(1, 14, 0) + MATRIX_KEY(2, 14, 0) + MATRIX_KEY(3, 14, 0) + MATRIX_KEY(4, 14, 0) + MATRIX_KEY(5, 14, 0) + MATRIX_KEY(6, 14, KEY_INSERT) + MATRIX_KEY(7, 14, 0) + + MATRIX_KEY(0, 15, 0) + MATRIX_KEY(1, 15, 0) + MATRIX_KEY(2, 15, KEY_UP) + MATRIX_KEY(3, 15, KEY_DOWN) + MATRIX_KEY(4, 15, KEY_LEFT) + MATRIX_KEY(5, 15, KEY_RIGHT) + MATRIX_KEY(6, 15, 0) + MATRIX_KEY(7, 15, 0) + + MATRIX_KEY(0, 16, 0) + MATRIX_KEY(1, 16, KEY_LEFTSHIFT) + MATRIX_KEY(2, 16, KEY_RIGHTSHIFT) + MATRIX_KEY(3, 16, 0) + MATRIX_KEY(4, 16, 0) + MATRIX_KEY(5, 16, 0) + MATRIX_KEY(6, 16, KEY_F1) + MATRIX_KEY(7, 16, KEY_FN) + >; + }; + + buttons { + compatible = "gpio-keys"; + + #address-cells = <7>; + #size-cells = <0>; + + left_touchpad { + label = "Touchpad Left"; + linux,code = <0x110>; /* BTN_LEFT */ + gpios = <&gpa 16 GPIO_ACTIVE_LOW>; + gpio-key,wakeup; + }; + + right_touchpad { + label = "Touchpad Right"; + linux,code = <0x111>; /* BTN_RIGHT */ + gpios = <&gpa 9 GPIO_ACTIVE_LOW>; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + + scroll_lock { + label = "scroll_lock"; + gpios = <&gpa 9 GPIO_ACTIVE_LOW>; + linux,default-trigger = "scroll_lock"; + default-state = "off"; + }; + + caps_lock { + label = "caps_lock"; + gpios = <&gpa 27 GPIO_ACTIVE_LOW>; + linux,default-trigger = "caps_lock"; + default-state = "off"; + }; + + num_lock { + label = "num_lock"; + gpios = <&gpc 22 GPIO_ACTIVE_LOW>; + linux,default-trigger = "num_lock"; + default-state = "off"; + }; + }; + + sound: sound { + compatible = "simple-scu-audio-card"; + + simple-audio-card,name = "sound"; + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + + simple-audio-card,convert-rate = <48000>; + + simple-audio-card,prefix = "ak4642"; + simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", + "DAI0 Capture", "ak4642 Capture"; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&i2s>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&ak4642>; + system-clock-frequency = <11289600>; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + + pwms = <&pwm 0 3906250>; + power-supply = <&vcc>; + + brightness-levels = <150 200 250 300>; + default-brightness-level = <2>; + + default-on; + + pinctrl-names = "default"; + pinctrl-0 = <&pins_pwm0>; + }; + + panel: claa070vc01 { + compatible = "chunghwa,claa070vc01", "panel-dpi"; + + width-mm = <150>; + height-mm = <90>; + + backlight = <&backlight>; + + panel-timing { + clock-frequency = <26400000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <0>; + hback-porch = <0>; + hsync-len = <80>; + vfront-porch = <0>; + vback-porch = <0>; + vsync-len = <20>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + + port { + panel_input: endpoint { + remote-endpoint = <&lcd_output>; + }; + }; + }; +}; + +&ext { + clock-frequency = <3686400>; +}; + +&rtc_dev { + system-power-controller; +}; + +&lcd { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pins_lcd0>; + pinctrl-1 = <&pins_lcd1>; + + port { + lcd_output: endpoint { + remote-endpoint = <&panel_input>; + }; + }; +}; + +&mmc { + status = "okay"; + + bus-width = <4>; + cd-gpios = <&gpc 0 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpc 2 GPIO_ACTIVE_LOW>; + vmmc-supply = <&vmmc_reg>; + + pinctrl-names = "default"; + pinctrl-0 = <&pins_mmc>; +}; + +&nand { + pinctrl-names = "default"; + pinctrl-0 = <&pins_nand>; + + nand0: nand@0 { + #address-cells = <0>; + #size-cells = <0>; + reg = <0>; + wp-gpios = <&gpc 23 GPIO_ACTIVE_LOW>; + + nand-on-flash-bbt; + nand-bus-width = <8>; + + nand-ecc-mode = "none"; + + partitions { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fixed-partitions"; + + bootloader@0 { + label = "bootloader"; + reg = <0x00000000 0x00100000>; + }; + + kernel@100000 { + label = "kernel"; + reg = <0x00100000 0x00300000>; + }; + + mac@400000 { + label = "mac"; + reg = <0x00400000 0x00100000>; + }; + + recovery@500000 { + label = "mini rootfs"; + reg = <0x00500000 0x00500000>; + }; + + root@a00000 { + label = "yaffs2 rootfs"; + reg = <0x00a00000 0x3f600000>; + }; + + extend@40000000 { + label = "extend 1G flash"; + reg = <0x40000000 0x40000000>; + }; + }; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&pins_uart0>; +}; + +&pinctrl { + pins_lcd0: lcd0 { + function = "lcd"; + groups = "lcd-8bit", "lcd-16bit", "lcd-16bit-tft"; + }; + + pins_lcd1: lcd1 { + function = "sleep"; + groups = "lcd-no-pins"; + }; + + pins_mmc: mmc { + mmc { + function = "mmc"; + groups = "mmc-1bit", "mmc-4bit"; + }; + + mmc_ctrl { + function = "mmc"; + pins = "PC0", "PC2", "PA21"; + bias-disable; + }; + }; + + pins_nand: pins_nand { + function = "nand"; + groups = "nand-cs3"; + }; + + pins_pwm0: pwm0 { + function = "pwm0"; + groups = "pwm0"; + }; + + pins_pwm1: pwm1 { + function = "pwm1"; + groups = "pwm1"; + }; + + pins_uart0: uart0 { + function = "uart0"; + groups = "uart0-data"; + bias-disable; + }; + + pins_usb_clk: usb { + pins = "PA29"; + bias-disable; + }; + + pins_mac: pins_mac { + function = "mac"; + groups = "mac"; + }; +}; + +&i2c { + power_controller@28 { + compatible = "minipc,mcu"; + reg = <0x28>; + }; + + ak4642: codec@12 { + compatible = "asahi-kasei,ak4642"; + reg = <0x12>; + #clock-cells = <0>; + clock-frequency = <12000000>; + clock-output-names = "ak4643_mcko"; + }; + + rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + #clock-cells = <0>; + }; + +}; + +&uhc { + clocks = <&clk_usb>; + + pinctrl-names = "default"; + pinctrl-0 = <&pins_usb_clk>; +}; + +ðernet { + phy-handle = <ðphy>; + phy-mode = "mii"; + + pinctrl-names = "default"; + pinctrl-0 = <&pins_mac>; +}; + +&mdio { + ethphy: ethernet-phy@16 { + device_type = "ethernet-phy"; + compatible = "realtek,rtl8201cl", "ethernet-phy-ieee802.3-c22"; + reg = <16>; + }; +}; + +/* + * TODO: + * add LCD + * add proper Pinmux + * finalize sound / codec setup + * add i2c and i2s drivers to the SoC + * add special driver to probe two gpios to detect battery charging and AC present + */

This is a MIPS subnotebook built around Ingenic JZ4730 SoC. It is known by many names, including CPC400 and Letux 400, but the OEM seems to be Skytone and use the "Alpha 400" designator.
Signed-off-by: Lubomir Rintel lkundrak@v3.sk --- arch/mips/mach-jz47xx/Kconfig | 23 ++++++++ board/skytone/alpha400/Kconfig | 60 +++++++++++++++++++ board/skytone/alpha400/Makefile | 3 + board/skytone/alpha400/alpha400.c | 43 ++++++++++++++ configs/alpha400_nand_defconfig | 11 ++++ include/configs/alpha400.h | 98 +++++++++++++++++++++++++++++++ 6 files changed, 238 insertions(+) create mode 100644 board/skytone/alpha400/Kconfig create mode 100644 board/skytone/alpha400/Makefile create mode 100644 board/skytone/alpha400/alpha400.c create mode 100644 configs/alpha400_nand_defconfig create mode 100644 include/configs/alpha400.h
diff --git a/arch/mips/mach-jz47xx/Kconfig b/arch/mips/mach-jz47xx/Kconfig index 6fba38c7363..6a01394d4e3 100644 --- a/arch/mips/mach-jz47xx/Kconfig +++ b/arch/mips/mach-jz47xx/Kconfig @@ -50,6 +50,29 @@ config SOC_JZ4780 choice prompt "Board select"
+config TARGET_JZ4730_ALPHA400 + bool "Skytone Alpha 400 Mini Notebook" + select SOC_JZ4730 + select CMD_MMC if DISTRO_DEFAULTS + select SPL_NAND_BASE if SPL + select SPL_NAND_DRIVERS if SPL + select SPL_NAND_SIMPLE if SPL + select SPL_NAND_SUPPORT if SPL + select SYS_NAND_U_BOOT_LOCATIONS + imply DISTRO_DEFAULTS + imply DM_ETH + imply DM_ETH_PHY + imply DM_GPIO + imply DM_MMC + imply DM_MTD + imply DM_REGULATOR + imply DM_REGULATOR_FIXED + imply NET_RANDOM_ETHADDR + help + Support for a MIPS subnotebook built around Ingenic JZ4730 SoC. + It is known by many names, including CPC400 and Letux 400, but + the OEM seems to be Skytone and use the "Alpha 400" designator. + config TARGET_JZ4780_CI20 bool "Creator CI20 Reference Board" select SOC_JZ4780 diff --git a/board/skytone/alpha400/Kconfig b/board/skytone/alpha400/Kconfig new file mode 100644 index 00000000000..a8413826a81 --- /dev/null +++ b/board/skytone/alpha400/Kconfig @@ -0,0 +1,60 @@ +if TARGET_JZ4730_ALPHA400 + +config SYS_BOARD + default "alpha400" + +config SYS_VENDOR + default "skytone" + +config SYS_CONFIG_NAME + default "alpha400" + +config DEFAULT_DEVICE_TREE + default "alpha400" + +config BUILD_TARGET + default "u-boot-with-spl.bin" if SPL + +config SYS_NAND_U_BOOT_OFFS + default 0x20000 + +config NR_DRAM_BANKS + default 16 + +config JZ4730_SDRAM_BANK_SIZE + default 8 + +config JZ4730_SDRAM_ROW + default 13 + +config JZ4730_SDRAM_COL + default 9 + +config JZ4730_SDRAM_BANKS_PER_CHIP + default 4 + +config JZ4730_SDRAM_WIDTH + default 32 + +config JZ4730_SDRAM_CAS + default 2 + +config JZ4730_SDRAM_TRAS + default 45 + +config JZ4730_SDRAM_RCD + default 20 + +config JZ4730_SDRAM_TPC + default 20 + +config JZ4730_SDRAM_TRW + default 7 + +config JZ4730_SDRAM_TREF + default 7812 + +config JZ4730_SDRAM_CKS + default 64 + +endif diff --git a/board/skytone/alpha400/Makefile b/board/skytone/alpha400/Makefile new file mode 100644 index 00000000000..b892abd88a4 --- /dev/null +++ b/board/skytone/alpha400/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y := alpha400.o diff --git a/board/skytone/alpha400/alpha400.c b/board/skytone/alpha400/alpha400.c new file mode 100644 index 00000000000..a05d078a661 --- /dev/null +++ b/board/skytone/alpha400/alpha400.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk + * + * Skytone Alpha 400 board support routines. + */ + +#include <common.h> +#include <net.h> +#include <nand.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +int mac_read_from_eeprom(void) +{ + char ethaddr[ARP_HLEN_ASCII + 1] = { 0, }; + size_t ethaddr_len = ARP_HLEN_ASCII; + int ret; + + nand_init(); + ret = nand_read(get_nand_dev_by_index(0), + 0x00400000, ðaddr_len, (void *)ethaddr); + if (ret) { + pr_err("Unable to read MAC address from NAND.\n"); + return 0; /* Not serious enough to fail the boot. */ + } + + env_set("ethaddr", ethaddr); + return ret; +} + +int dram_init(void) +{ + gd->ram_size = SZ_128M; + return 0; +} + +int checkboard(void) +{ + puts("Board: Skytone Alpha 400\n"); + return 0; +} diff --git a/configs/alpha400_nand_defconfig b/configs/alpha400_nand_defconfig new file mode 100644 index 00000000000..cd2daccc821 --- /dev/null +++ b/configs/alpha400_nand_defconfig @@ -0,0 +1,11 @@ +CONFIG_MIPS=y +CONFIG_ARCH_JZ47XX=y +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_JFFS2=y +CONFIG_MTDIDS_DEFAULT="nand0=jz4730-nand.0" +CONFIG_MTDPARTS_DEFAULT="mtdparts=jz4730-nand.0:1m(bootloader),3m(kernel),1m(mac),5m(mini),1014m(yaffs2),-(extend)" +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_MMC_HW_PARTITIONING is not set +CONFIG_NS16550_DYNAMIC=y +CONFIG_WATCHDOG_TIMEOUT_MSECS=0 diff --git a/include/configs/alpha400.h b/include/configs/alpha400.h new file mode 100644 index 00000000000..673b42f372f --- /dev/null +++ b/include/configs/alpha400.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2020 Lubomir Rintel lkundrak@v3.sk + * + * Configuration settings for Skytone Alpha 400 board. + */ + +#ifndef __CONFIG_ALPHA400_H__ +#define __CONFIG_ALPHA400_H__ + +#include <linux/sizes.h> + +#ifndef CONFIG_SPL_BUILD +#define BOOTENV_DEV_NAND_LEGACY(devtypeu, devtypel, instance) \ + "bootcmd_" #devtypel #instance "=" \ + "nboot ${kernel_addr_r} " #instance " 0x100000; bootm\0" + +#define BOOTENV_DEV_NAME_NAND_LEGACY(devtypeu, devtypel, instance) \ + #devtypel #instance " " + +#define BOOT_TARGET_DEVICES(func) \ + func(MMC, mmc, 0) \ + func(NAND_LEGACY, nand, 0) + +#include <config_distro_bootcmd.h> +#endif + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "bootargs=mem=128M console=ttyS0,115200n8 root=/dev/ssfdca1 rw noatime\0" \ + "kernel_addr_r=0x80600000\0" \ + "scriptaddr=0x81000000\0" \ + "fdt_addr_r=0x81100000\0" \ + "ramdisk_addr_r=0x81200000\0" \ + BOOTENV + +#define CONFIG_SYS_MALLOC_LEN SZ_16M +#define CONFIG_SYS_SDRAM_BASE 0x80000000 +#define CONFIG_SYS_INIT_SP_OFFSET 0x00400000 +#define CONFIG_SYS_INIT_SP_ADDR 0x80004000 +#define CONFIG_SYS_LOAD_ADDR 0x81000000 +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE + +#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_NAND_U_BOOT_DST CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_NAND_U_BOOT_SIZE SZ_512K + +#define CONFIG_SPL_MAX_SIZE SZ_4K +#define CONFIG_SPL_BSS_MAX_SIZE SZ_4K +#define CONFIG_SPL_PAD_TO 0x00020000 +#define CONFIG_SPL_BSS_START_ADDR 0x80001000 +#define CONFIG_SPL_STACK 0x80004000 + +#define CONFIG_SPL_NAND_LOAD +#define CONFIG_SPL_NAND_RAW_ONLY + +/* + * NAND flash. + */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#define CONFIG_SYS_NAND_MAX_CHIPS 2 +#define CONFIG_SYS_NAND_5_ADDR_CYCLE +#define CONFIG_SYS_NAND_BASE 0xb4000000 +#define CONFIG_SYS_NAND_PAGE_SIZE SZ_2K +#define CONFIG_SYS_NAND_BLOCK_SIZE SZ_128K +#define CONFIG_SYS_NAND_PAGE_COUNT (CONFIG_SYS_NAND_BLOCK_SIZE / \ + CONFIG_SYS_NAND_PAGE_SIZE) +#define CONFIG_SYS_NAND_OOBSIZE 64 +#define CONFIG_SYS_NAND_BAD_BLOCK_POS NAND_LARGE_BADBLOCK_POS + +/* + * The MAC address is in a NAND flash partition. + */ +#define CONFIG_ID_EEPROM +#define CONFIG_SYS_RX_ETH_BUFFER 16 + +/* + * The "recovery" partition. + */ +#define CONFIG_JFFS2_NAND +#define CONFIG_JFFS2_DEV "nand0" +#define CONFIG_JFFS2_PART_OFFSET 0x00500000 +#define CONFIG_JFFS2_PART_SIZE 0x00500000 + +/* + * Useful for SPL. + */ +#define CONFIG_CPU_FREQ_HZ 336000000 +#define CONFIG_SYS_CLK 3686400 + +/* + * These are only useful for CONFIG_DEBUG_UART. + * The regular serial driver gets its params from DT. + */ +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_CLK CONFIG_SYS_CLK +#define CONFIG_SYS_NS16550_COM1 0xb0030000 + +#endif /* __CONFIG_ALPHA400_H__ */
participants (3)
-
Daniel Schwierzeck
-
Ezequiel Garcia
-
Lubomir Rintel