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

classic Classic list List threaded Threaded
26 messages Options
12
Reply | Threaded
Open this post in threaded view
|

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

Lubomir Rintel
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

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 01/20] config: Remove CONFIG_SYS_ID_EEPROM

Lubomir Rintel
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 <[hidden email]>
---
 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
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 02/20] mtd: Allow building nand_spl_simple w/o SPL_NAND_ECC

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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 */
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 03/20] cmd/mac: Don't build unless CONFIG_CMD_MAC is enabled

Lubomir Rintel
In reply to this post by 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 <[hidden email]>
---
 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
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 04/20] mips: Don't access CP0_EBASE on JZ47XX

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 05/20] ns16550: Turn on the UME bit if on ARCH_JZ47XX

Lubomir Rintel
In reply to this post by 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 <[hidden email]>
---
 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);
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 06/20] clk: Add driver for Ingenic JZ4730 CGU

Lubomir Rintel
In reply to this post by Lubomir Rintel
A rather minimal driver for that reads back configured clock rates for
hardware we support.

Signed-off-by: Lubomir Rintel <[hidden email]>
---
 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 <[hidden email]>
+ */
+
+#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,
+};
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 07/20] timer-uclass: Tolerate failure to get clock rate in pre_probe

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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);
  }
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 08/20] timer: Add Ingenic JZ4730 timer driver

Lubomir Rintel
In reply to this post by Lubomir Rintel
This adds support for a timer block on JZ4730 SoC.

Signed-off-by: Lubomir Rintel <[hidden email]>
---
 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 <[hidden email]>
+ */
+
+#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,
+};
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 09/20] mmc: Default to JZ47XX_MMC=y on ARCH_JZ47XX

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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.
 
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 10/20] mmc/jz_mmc: Add a JZ4740 compatible string

Lubomir Rintel
In reply to this post by Lubomir Rintel
The driver doesn't use the jz4780's extra DMA channels and handles jz4740
just fine.

Signed-off-by: Lubomir Rintel <[hidden email]>
---
 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" },
  { }
 };
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 11/20] mmc/jz_mmc: Support wp-gpio/cd-gpio

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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);
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 12/20] pinctrl: Add Ingenic JZ4730 pin control and GPIO driver

Lubomir Rintel
In reply to this post by Lubomir Rintel
This is a fairly minimal driver for the pin controller on JZ4730 SoC.

Signed-off-by: Lubomir Rintel <[hidden email]>
---
 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 <[hidden email]>
+ */
+
+#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,
+};
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 13/20] nand: Use correct prototype of board_nand_init() with SPL_NAND_SIMPLE

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 14/20] nand/raw: Add Ingenic JZ4730 NAND flash driver

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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: <[hidden email]>
+ *
+ * Copyright (C) 2020 Lubomir Rintel <[hidden email]>
+ */
+
+#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 */
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 15/20] watchdog: Add Ingenic JZ4730 watchdog timer driver

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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 <[hidden email]>
+ */
+
+#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,
+};
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 16/20] net: Add Ingenic JZ4730 Ethernet driver

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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 <[hidden email]>
+ * Copyright (C) 2020 Lubomir Rintel <[hidden email]>
+ */
+
+#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),
+};
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 17/20] mips: dts: Add Ingenic JZ4730

Lubomir Rintel
In reply to this post by Lubomir Rintel
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/dt-mipsbook400

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 <[hidden email]>
Cc: H. Nikolaus Schaller <[hidden email]>
Signed-off-by: Lubomir Rintel <[hidden email]>
---
 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__ */
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 18/20] mips/mach-jz47xx: Add Ingenic JZ4730 support

Lubomir Rintel
In reply to this post by Lubomir Rintel
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 <[hidden email]>
---
 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 <[hidden email]>
+ *
+ * Derived from work that's Copyright (c) 2003
+ * Wolfgang Denk <[hidden email]>
+ */
+
+#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 <[hidden email]>
+ *
+ * Based on code that's (C) Copyright 2006
+ * Stefan Roese, DENX Software Engineering, [hidden email].
+ */
+
+#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;
+}
--
2.28.0

Reply | Threaded
Open this post in threaded view
|

[PATCH RFC 19/20] mips: dts: Add Skytone Alpha 400

Lubomir Rintel
In reply to this post by Lubomir Rintel
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/dt-mipsbook400

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 <[hidden email]>
Cc: H. Nikolaus Schaller <[hidden email]>
Signed-off-by: Lubomir Rintel <[hidden email]>
---
 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,[hidden email]
 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/bin/view/Epc700/KeyBoard
+ * ...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>;
+};
+
+&ethernet {
+ phy-handle = <&ethphy>;
+ 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
+ */
--
2.28.0

12