[RFC PATCH] mips: dts: add initial support for ls1c300 SoC

Sean Anderson seanga2 at gmail.com
Wed Mar 30 22:46:40 CEST 2022


On 3/29/22 3:30 PM, Du Huanpeng wrote:
> Loongson 1C is a cost-effective SOC chip for industrial control and
> the Internet of Things. The Loongson 1C includes a floating-point
> processing unit, supports multiple types of memory, and supports
> high-capacity MLC NAND Flash. Loongson 1C provides developers with a
> wealth of peripheral interfaces and on-chip modules, including Camera
> controller, USB OTG and USB HOST interfaces, AC97/I2S controller, LCD
> controller, SPI interface, UART interface, etc., providing sufficient
> computing power and multi-application connectivity.
> 
> Some highlights of this SoC are:
> - Single core LS232, MIPS32 instruction set compatible, main frequency
> 300MHZ
> - 16KB data cache and 16KB instruction cache
> - 64 bit float unit, hardware division
> - 8/16 bit SDRAM controller, 45 ~ 133MHz
> - 8/16 bit SRAM, NAND
> - I2S/AC97, LCD, MAC, USB, OTG, SPI, I2C, PWM, CAN, SDIO, ADC
> - 12 UARTs
> 
> See Techinical Reference Manual for details: https://www.loongson.cn/

Can you provide a direct link please? I looked around a bit but I don't
read Chinese and I was unable to figure out where to find more
documentation on this CPU.

> 
> introduce base support for the ls1c300 SoC.
> - debug UART2
> - serial console
> - clock
> - watchdog
> - sysreset
> - many uarts
> 
> Signed-off-by: Du Huanpeng <dhu at hodcarrier.org>
> ---
>   arch/mips/Kconfig                             |  25 +++
>   arch/mips/Makefile                            |   1 +
>   arch/mips/dts/Makefile                        |   1 +
>   arch/mips/dts/loongson32-ls1c300b.dtsi        | 138 +++++++++++++++++
>   arch/mips/dts/ls1c300-eval.dts                |  27 ++++
>   arch/mips/mach-lsmips/Kconfig                 |  77 ++++++++++
>   arch/mips/mach-lsmips/Makefile                |   6 +
>   arch/mips/mach-lsmips/cpu.c                   |  24 +++
>   arch/mips/mach-lsmips/include/mach/serial.h   |  16 ++
>   arch/mips/mach-lsmips/ls1c300/Makefile        |   6 +
>   arch/mips/mach-lsmips/ls1c300/gpio.c          |  60 ++++++++
>   arch/mips/mach-lsmips/ls1c300/init.c          |  60 ++++++++
>   arch/mips/mach-lsmips/ls1c300/lowlevel_init.S | 123 +++++++++++++++
>   arch/mips/mach-lsmips/ls1c300/ls1c300.h       |  52 +++++++
>   arch/mips/mach-lsmips/ls1c300/serial.c        | 112 ++++++++++++++
>   arch/mips/mach-lsmips/spl.c                   |  47 ++++++
>   board/loongson/ls1c300-eval/Kconfig           |  12 ++
>   board/loongson/ls1c300-eval/MAINTAINERS       |   7 +
>   board/loongson/ls1c300-eval/Makefile          |   3 +
>   board/loongson/ls1c300-eval/board.c           |  20 +++
>   configs/ls1c300_defconfig                     |  65 ++++++++
>   drivers/clk/Makefile                          |   1 +
>   drivers/clk/lsmips/Makefile                   |   3 +
>   drivers/clk/lsmips/clk-ls1c300.c              | 145 ++++++++++++++++++
>   drivers/watchdog/Kconfig                      |   8 +
>   drivers/watchdog/Makefile                     |   1 +
>   drivers/watchdog/lsmips_wdt.c                 | 126 +++++++++++++++
>   include/configs/ls1c300.h                     |  61 ++++++++
>   include/dt-bindings/clock/ls1c300-clk.h       |  48 ++++++
>   29 files changed, 1275 insertions(+)
>   create mode 100644 arch/mips/dts/loongson32-ls1c300b.dtsi
>   create mode 100644 arch/mips/dts/ls1c300-eval.dts
>   create mode 100644 arch/mips/mach-lsmips/Kconfig
>   create mode 100644 arch/mips/mach-lsmips/Makefile
>   create mode 100644 arch/mips/mach-lsmips/cpu.c
>   create mode 100644 arch/mips/mach-lsmips/include/mach/serial.h
>   create mode 100644 arch/mips/mach-lsmips/ls1c300/Makefile
>   create mode 100644 arch/mips/mach-lsmips/ls1c300/gpio.c
>   create mode 100644 arch/mips/mach-lsmips/ls1c300/init.c
>   create mode 100644 arch/mips/mach-lsmips/ls1c300/lowlevel_init.S
>   create mode 100644 arch/mips/mach-lsmips/ls1c300/ls1c300.h
>   create mode 100644 arch/mips/mach-lsmips/ls1c300/serial.c
>   create mode 100644 arch/mips/mach-lsmips/spl.c
>   create mode 100644 board/loongson/ls1c300-eval/Kconfig
>   create mode 100644 board/loongson/ls1c300-eval/MAINTAINERS
>   create mode 100644 board/loongson/ls1c300-eval/Makefile
>   create mode 100644 board/loongson/ls1c300-eval/board.c
>   create mode 100644 configs/ls1c300_defconfig
>   create mode 100644 drivers/clk/lsmips/Makefile
>   create mode 100644 drivers/clk/lsmips/clk-ls1c300.c
>   create mode 100644 drivers/watchdog/lsmips_wdt.c
>   create mode 100644 include/configs/ls1c300.h
>   create mode 100644 include/dt-bindings/clock/ls1c300-clk.h

I'm mainly going to comment on clocks becuase you asked me about that,
but note that this should all be split up into several commits, one
per driver/subsystem.

You will also need some kind of entry in doc/boards.

> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 28234aa0bb..d95868ef4b 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -93,6 +93,30 @@ config ARCH_MTMIPS
>   	select SUPPORTS_LITTLE_ENDIAN
>   	select SUPPORT_SPL
>   
> +config ARCH_LSMIPS
> +	bool "Support Loongson MIPS platforms"
> +	select CLK
> +	imply CMD_DM
> +	select DISPLAY_CPUINFO
> +	select DM
> +	imply DM_ETH
> +	imply DM_GPIO
> +	select DM_RESET
> +	select DM_SERIAL
> +	select PINCTRL
> +	select PINMUX
> +	select PINCONF
> +	select RESET_LSMIPS
> +	imply DM_SPI
> +	imply DM_SPI_FLASH
> +	select OF_CONTROL
> +	select ROM_EXCEPTION_VECTORS
> +	select SUPPORTS_CPU_MIPS32_R1
> +	select SUPPORTS_CPU_MIPS32_R2
> +	select SUPPORTS_LITTLE_ENDIAN
> +	select SYSRESET
> +	select SUPPORT_SPL
> +
>   config ARCH_JZ47XX
>   	bool "Support Ingenic JZ47xx"
>   	select SUPPORT_SPL
> @@ -174,6 +198,7 @@ source "arch/mips/mach-bmips/Kconfig"
>   source "arch/mips/mach-jz47xx/Kconfig"
>   source "arch/mips/mach-pic32/Kconfig"
>   source "arch/mips/mach-mtmips/Kconfig"
> +source "arch/mips/mach-lsmips/Kconfig"
>   source "arch/mips/mach-octeon/Kconfig"
>   
>   if MIPS
> diff --git a/arch/mips/Makefile b/arch/mips/Makefile
> index 6502aebd29..e944502497 100644
> --- a/arch/mips/Makefile
> +++ b/arch/mips/Makefile
> @@ -16,6 +16,7 @@ machine-$(CONFIG_ARCH_BMIPS) += bmips
>   machine-$(CONFIG_ARCH_JZ47XX) += jz47xx
>   machine-$(CONFIG_MACH_PIC32) += pic32
>   machine-$(CONFIG_ARCH_MTMIPS) += mtmips
> +machine-$(CONFIG_ARCH_LSMIPS) += lsmips
>   machine-$(CONFIG_ARCH_MSCC) += mscc
>   machine-${CONFIG_ARCH_OCTEON} += octeon
>   
> diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
> index 95144b24dc..915acfd573 100644
> --- a/arch/mips/dts/Makefile
> +++ b/arch/mips/dts/Makefile
> @@ -19,6 +19,7 @@ dtb-$(CONFIG_BOARD_MT7620_MT7530_RFB) += mediatek,mt7620-mt7530-rfb.dtb
>   dtb-$(CONFIG_BOARD_MT7628_RFB) += mediatek,mt7628-rfb.dtb
>   dtb-$(CONFIG_BOARD_GARDENA_SMART_GATEWAY_MT7688) += gardena-smart-gateway-mt7688.dtb
>   dtb-$(CONFIG_BOARD_LINKIT_SMART_7688) += linkit-smart-7688.dtb
> +dtb-$(CONFIG_BOARD_LS1C300) += ls1c300-eval.dtb
>   dtb-$(CONFIG_TARGET_OCTEON_EBB7304) += mrvl,octeon-ebb7304.dtb
>   dtb-$(CONFIG_TARGET_OCTEON_NIC23) += mrvl,octeon-nic23.dtb
>   dtb-$(CONFIG_BOARD_NETGEAR_CG3100D) += netgear,cg3100d.dtb
> diff --git a/arch/mips/dts/loongson32-ls1c300b.dtsi b/arch/mips/dts/loongson32-ls1c300b.dtsi
> new file mode 100644
> index 0000000000..a574495301
> --- /dev/null
> +++ b/arch/mips/dts/loongson32-ls1c300b.dtsi
> @@ -0,0 +1,138 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <dt-bindings/clock/ls1c300-clk.h>
> +
> +/ {
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	compatible = "loongson,ls1c300-soc";
> +
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		cpu at 0 {
> +			device_type = "cpu";
> +			reg = <0>;
> +			compatible = "loongson,gs232", "mips,mips4Kc";
> +			clocks = <&acc CLK_CPU>;
> +		};
> +	};
> +
> +	xtal: oscillator at 0 {

No @address if there's no address.

> +		compatible = "fixed-clock";
> +		clock-frequency = <24000000>;
> +		#clock-cells = <0>;
> +	};

Should go under a "clocks" node (e.g. /clocks/osc)

> +
> +	soc {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		compatible = "simple-bus";
> +		ranges;
> +
> +		// TODO: add more device.
> +
> +		acc: clock-controller at 1fe78030 {
> +			compatible = "loongson,ls1c300-clk";
> +			clocks = <&xtal>;
> +			#clock-cells = <1>;
> +			reg = <0x1fe78030 0x8>, <0x1fe7c010 0x4>;
> +			u-boot,dm-pre-reloc;
> +		};
> +
> +		uart0: serial at 1fe40000 {
> +			compatible = "ns16550a";

Please add a soc-specific compatible here as well e.g.

	compatible = "loongson,ls1c300-uart", "ns16550a";

This goes for most things with generic bindings as well.

> +			clocks = <&acc CLK_UART0>;
> +			reg = <0x1fe40000 0x100>;
> +			reg-shift = <0>;
Do you have byte-sized registers?

> +		};
> +
> +		uart1: serial at 1fe44000 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART1>;
> +			reg = <0x1fe44000 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart2: serial at bfe48000 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART2>;
> +			reg = <0xbfe48000 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart3: serial at 1fe4c000 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART3>;
> +			reg = <0x1fe4c000 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart4:  serial at 1fe4c400 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART4>;
> +			reg = <0x1fe4c400 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart5:  serial at 1fe4c500 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART5>;
> +			reg = <0x1fe4c500 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart6:  serial at 1fe4c600 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART6>;
> +			reg = <0x1fe4c600 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart7:  serial at 1fe4c700 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART7>;
> +			reg = <0x1fe4c700 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart8:  serial at 1fe4c800 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART8>;
> +			reg = <0x1fe4c800 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart9:  serial at 1fe4c900 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART9>;
> +			reg = <0x1fe4c900 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart10: serial at 1fe4ca00 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART10>;
> +			reg = <0x1fe4ca00 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		uart11: serial at 1fe4cb00 {
> +			compatible = "ns16550a";
> +			clocks = <&acc CLK_UART11>;
> +			reg = <0x1fe4cb00 0x100>;
> +			reg-shift = <0>;
> +		};
> +
> +		wdt: watchdog at 1fe5c060 {
> +			compatible = "loongson,ls1c300-wdt";
> +			clocks = <&acc CLK_WDT>;
> +			reg = <0x1fe5c060 0x10>;
> +		};
> +
> +		reset-controller {
> +			compatible = "wdt-reboot";
> +			wdt = <&wdt>;
> +		};
> +
> +	};
> +};

You are missing some kind of memory node (and perhaps aliases).

How does this boot? JTAG?

> diff --git a/arch/mips/dts/ls1c300-eval.dts b/arch/mips/dts/ls1c300-eval.dts
> new file mode 100644
> index 0000000000..5bf1ec0985
> --- /dev/null
> +++ b/arch/mips/dts/ls1c300-eval.dts
> @@ -0,0 +1,27 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +/dts-v1/;
> +
> +#include "loongson32-ls1c300b.dtsi"
> +
> +/ {
> +	compatible = "lsmips,ls1c300-soc";
> +	model = "ls1c300-eval";
> +
> +	aliases {
> +		console = &uart2;

uarts use serialX aliases.

> +	};
> +
> +	chosen {
> +		bootargs = "console=ttyS0,115200";
> +		stdout-path = &uart2;
> +	};
> +};
> +
> +&uart2 {
> +	status = "okay";

All devices implicitly have status = "okay". You should disable most
devices in the soc dtsi, and then re-enable them in the board dts.

> +};
> +
> diff --git a/arch/mips/mach-lsmips/Kconfig b/arch/mips/mach-lsmips/Kconfig
> new file mode 100644
> index 0000000000..cb679875a7
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/Kconfig
> @@ -0,0 +1,77 @@
> +menu "Loongson MIPS platforms"
> +	depends on ARCH_LSMIPS
> +
> +config SYS_MALLOC_F_LEN
> +	default 0x1000
> +
> +config SYS_SOC
> +	default "ls1c300" if SOC_LS1C300
> +
> +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_TEXT_BASE
> +	default 0xbfc00000 if !SPL
> +	default 0x80200000 if SPL
> +
> +config SPL_TEXT_BASE
> +	default 0xbfc00000
> +
> +config SPL_PAYLOAD
> +	default "u-boot-lzma.img" if SPL_LZMA
> +
> +config BUILD_TARGET
> +	default "u-boot-with-spl.bin" if SPL
> +
> +choice
> +	prompt "Loongson MIPS SoC select"
> +
> +config SOC_LS1C300
> +	bool "LS1C300"
> +	select MIPS_L1_CACHE_SHIFT_5
> +	select PINCTRL_LS1C300
> +	select CLK_CCF
> +	select SPL_SEPARATE_BSS if SPL
> +	select SPL_INIT_STACK_WITHOUT_MALLOC_F if SPL
> +	select SPL_LOADER_SUPPORT if SPL
> +	select SPL_OF_CONTROL if SPL_DM
> +	select SPL_SIMPLE_BUS if SPL_DM
> +	select SPL_DM_SERIAL if SPL_DM
> +	select SPL_CLK if SPL_DM && SPL_SERIAL
> +	select SPL_SYSRESET if SPL_DM
> +	select SPL_OF_LIBFDT if SPL_OF_CONTROL
> +	help
> +	  This supports Loongson LS1C300
> +
> +endchoice
> +
> +choice
> +	prompt "Board select"
> +
> +config BOARD_LS1C300
> +	bool "Loongson LS1C300 Eval"
> +	depends on SOC_LS1C300
> +	help
> +	  ls1c300-eval board has a LS1C300 SoC with 64MiB of SDRAM
> +	  and 512KiB of flash (SPI NOR) and additional NAND storage.
> +
> +endchoice
> +
> +config CONS_PIN_SELECT
> +	int "pin group used in uart"
> +	default 0
> +	help
> +	  Select pin group connected to UART for your board.
> +
> +source "board/loongson/ls1c300-eval/Kconfig"
> +
> +endmenu
> diff --git a/arch/mips/mach-lsmips/Makefile b/arch/mips/mach-lsmips/Makefile
> new file mode 100644
> index 0000000000..654143a5f7
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +
> +obj-y += cpu.o
> +obj-$(CONFIG_SPL_BUILD) += spl.o
> +
> +obj-$(CONFIG_SOC_LS1C300) += ls1c300/
> diff --git a/arch/mips/mach-lsmips/cpu.c b/arch/mips/mach-lsmips/cpu.c
> new file mode 100644
> index 0000000000..00513253e8
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/cpu.c
> @@ -0,0 +1,24 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2018 Stefan Roese <sr at denx.de>
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <malloc.h>
> +#include <linux/bitops.h>
> +#include <linux/io.h>
> +#include <linux/sizes.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +int dram_init(void)
> +{
> +#ifdef CONFIG_SKIP_LOWLEVEL_INIT

if (CONFIG_IS_ENABLED(SKIP_LOWLEVEL_INIT))

> +	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_256M);
> +#else
> +	gd->ram_size = SZ_64M;
> +#endif
> +
> +	return 0;
> +}
> diff --git a/arch/mips/mach-lsmips/include/mach/serial.h b/arch/mips/mach-lsmips/include/mach/serial.h
> new file mode 100644
> index 0000000000..4da1cb434c
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/include/mach/serial.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + *
> + * Author:  Gao Weijie <weijie.gao at mediatek.com>
> + *
> + * Copyright (C) 2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#ifndef __LSMIPS_SERIAL_H_
> +#define __LSMIPS_SERIAL_H_
> +
> +void lsmips_spl_serial_init(void);
> +int gpio_set_alternate(int gpio, int func);
> +
> +#endif /* __LSMIPS_SERIAL_H_ */
> diff --git a/arch/mips/mach-lsmips/ls1c300/Makefile b/arch/mips/mach-lsmips/ls1c300/Makefile
> new file mode 100644
> index 0000000000..d30069e67e
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/ls1c300/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-y += lowlevel_init.o
> +obj-y += init.o
> +obj-y += gpio.o
> +obj-$(CONFIG_SPL_BUILD) += serial.o
> diff --git a/arch/mips/mach-lsmips/ls1c300/gpio.c b/arch/mips/mach-lsmips/ls1c300/gpio.c
> new file mode 100644
> index 0000000000..cca91aed93
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/ls1c300/gpio.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/bitops.h>
> +#include <asm/bitops.h>
> +#include <asm/io.h>
> +
> +#define CBUS_FIRST0	0xbfd011c0
> +#define CBUS_SECOND0	0xbfd011d0
> +#define CBUS_THIRD0	0xbfd011e0
> +#define CBUS_FOURTHT0	0xbfd011f0
> +#define CBUS_FIFTHT0	0xbfd01200
> +
> +#define CBUS_FIRST1	0xbfd011c4
> +#define CBUS_SECOND1	0xbfd011d4
> +#define CBUS_THIRD1	0xbfd011e4
> +#define CBUS_FOURTHT1	0xbfd011f4
> +#define CBUS_FIFTHT1	0xbfd01204
> +
> +#define CBUS_FIRST2	0xbfd011c8
> +#define CBUS_SECOND2	0xbfd011d8
> +#define CBUS_THIRD2	0xbfd011e8
> +#define CBUS_FOURTHT2	0xbfd011f8
> +#define CBUS_FIFTHT2	0xbfd01208
> +
> +#define CBUS_FIRST3	0xbfd011cc
> +#define CBUS_SECOND3	0xbfd011dc
> +#define CBUS_THIRD3	0xbfd011ec
> +#define CBUS_FOURTHT3	0xbfd011fc
> +#define CBUS_FIFTHT3	0xbfd0120c
> +
> +int gpio_set_alternate(int gpio, int func)
> +{
> +	volatile void __iomem *addr;
> +	int i;
> +
> +	if (gpio < 0 || gpio > 104)
> +		return -ENODEV;
> +	if (func < 0)
> +		return -EINVAL;
> +
> +	if (func) {
> +		i = func - 1;
> +		addr = (void *)CBUS_FIRST0 + i * 16;
> +		set_bit(gpio, addr);
> +	} else {
> +		/* GPIO, clear CBUS 1 ~ 5 */
> +		i = 5;
> +	}
> +
> +	while (i--) {
> +		addr = (void *)CBUS_FIRST0 + 16 * i;
> +		clear_bit(gpio, addr);
> +	}
> +
> +	return 0;
> +}

Please consider using a real GPIO driver.

> diff --git a/arch/mips/mach-lsmips/ls1c300/init.c b/arch/mips/mach-lsmips/ls1c300/init.c
> new file mode 100644
> index 0000000000..457beeedca
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/ls1c300/init.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + *
> + * Author:  Gao Weijie <weijie.gao at mediatek.com>
> + *
> + * based on: arch/mips/mach-mtmips/mt7628/init.c
> + * Copyright (C) 2020-2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#include <common.h>
> +#include <clk.h>
> +#include <dm.h>
> +#include <dm/uclass.h>
> +#include <dt-bindings/clock/ls1c300-clk.h>
> +#include <linux/io.h>
> +#include <linux/sizes.h>
> +#include "ls1c300.h"
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +int print_cpuinfo(void)
> +{
> +	struct udevice *udev;
> +	struct clk clk;
> +	int ret;
> +	ulong xtal;
> +	char buf[SZ_32];
> +
> +	printf("CPU: Loongson ls1c300b\n");
> +
> +	ret = uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(ls1c300_clk), &udev);
> +
> +	if (ret) {
> +		printf("error: clock driver not found.\n");
> +		return 0;
> +	}
> +
> +	clk.dev = udev;
> +
> +	clk.id = CLK_XTAL;
> +	xtal = clk_get_rate(&clk);
> +
> +	clk.id = CLK_CPU_THROT;
> +	gd->cpu_clk = clk_get_rate(&clk);
> +
> +	clk.id = CLK_SDRAM;
> +	gd->mem_clk = clk_get_rate(&clk);

You *must* call clk_request() before using a clock.

> +
> +	printf("Clock: CPU: %sMHz, ", strmhz(buf, gd->cpu_clk));
> +	printf("SDRAM: %sMHz, ", strmhz(buf, gd->mem_clk));
> +	printf("XTAL: %sMHz\n", strmhz(buf, xtal));
> +
> +	return 0;
> +}
> +
> +ulong notrace get_tbclk(void)
> +{
> +	return gd->cpu_clk;
> +}
> diff --git a/arch/mips/mach-lsmips/ls1c300/lowlevel_init.S b/arch/mips/mach-lsmips/ls1c300/lowlevel_init.S
> new file mode 100644
> index 0000000000..f9e2f94e83
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/ls1c300/lowlevel_init.S
> @@ -0,0 +1,123 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + *
> + * Author:  Gao Weijie <weijie.gao at mediatek.com>
> + *
> + * Copyright (C) 2020-2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#include <config.h>
> +#include <asm-offsets.h>
> +#include <asm/cacheops.h>
> +#include <asm/regdef.h>
> +#include <asm/mipsregs.h>
> +#include <asm/addrspace.h>
> +#include <asm/asm.h>
> +#include <linux/sizes.h>
> +
> +/* PLL */
> +#define NAND_BASE	0xbfe78000
> +#define START_FREQ	0xbfe78030
> +#define CLK_DIV_PARAM	0xbfe78034
> +
> +/* SPI */
> +#define SPI0_BASE	0xbfe80000
> +
> +/* SDRAM */
> +#define	SD_CONFIG	0xbfd00000
> +#define	SD_CONFIGL	0xbfd00410
> +#define	SD_CONFIGH	0xbfd00414
> +
> +	.set noreorder
> +
> +/*	PLL: 264MHz	CPU: 132MHz	SDRAM: 66MHz	*/
> +LEAF(ls1c300_pll_init)
> +#ifndef CONFIG_SKIP_LOWLEVEL_INIT
> +	li	t0, NAND_BASE
> +	li	t2, 555844098
> +	sw	t2, 0x34 (t0)
> +
> +	li	t1, 2147494924
> +	sw	t1, 0x30 (t0)
> +
> +	ori	t2, 1
> +	sw	t2, 0x34 (t0)
> +#endif
> +/* TODO: recalc rate to v0 */
> +	li	v0, 132000000
> +	jr	ra
> +	  nop
> +END(ls1c300_pll_init)

Why does this need to be done in assembly? Ditto for the rest.

> +
> +/* SPI: Dual IO at 33MHz */
> +LEAF(ls1c300_spi_init)
> +#ifndef CONFIG_SKIP_LOWLEVEL_INIT
> +	li	t0, SPI0_BASE
> +	li	t1, 0x07
> +	li	t2, 0x05
> +	sb	t1, 0x4(t0)
> +	sb	t1, 0x6(t0)
> +#endif
> +	jr	ra
> +	  nop
> +END(ls1c300_spi_init)
> +
> +/* SDRAM: 66MHz */
> +// 8M x 16Bit x 4 Banks */
> +// Organization | Row Address | Column Address
> +// 32Mx16       | A0~A12      | A0-A9
> +
> +// 128Mx4       | A0~A12      | A0-A9, A11, A12
> +// 64Mx8        | A0~A12      | A0-A9, A11
> +// 32Mx16       | A0~A12      | A0-A9
> +
> +LEAF(ls1c300_sdram_init)
> +#ifndef CONFIG_SKIP_LOWLEVEL_INIT
> +	li	t0, SD_CONFIG
> +	li	t1, 0x028A924A
> +	li	t2, 0x00000028
> +sdram_cfg:
> +	sw	t1, 0x410(t0)
> +	sw	t2, 0x414(t0)
> +	nop
> +	sw	t1, 0x410(t0)
> +	sw	t2, 0x414(t0)
> +	ori	t2, 0x200
> +	sw	t1, 0x410(t0)
> +	sw	t2, 0x414(t0)
> +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
> +	li	v0, SZ_64M
> +	jr	ra
> +	 nop
> +END(ls1c300_sdram_init)
> +
> +
> +/*
> + *	SDRAM at 132MHz, CPU at 297MHz, SPI at 33MHz
> + *	SDRAM at 100MHz, CPU at 300MHz, SPI at 50MHz
> + *	SDRAM at 66MHz, CPU at 132MHz, SPI at 33MHz  <--
> + */
> +
> +NESTED(lowlevel_init, 0, ra)
> +	/* Save ra and do real lowlevel initialization */
> +	move	s0, ra
> +	/* Setup PLL @264MHz */
> +	PTR_LA	t9, ls1c300_pll_init
> +	jalr	t9
> +	  nop
> +
> +	/* Setup SPI Dual IO at 33MHz */
> +	PTR_LA	t9, ls1c300_spi_init
> +	jalr	t9
> +	  nop
> +
> +	/* Setup external SDRAM @66MHz */
> +	PTR_LA	t9, ls1c300_sdram_init
> +	jalr	t9
> +	  nop
> +
> +	move	ra, s0
> +	jr	ra
> +	 nop
> +END(lowlevel_init)
> diff --git a/arch/mips/mach-lsmips/ls1c300/ls1c300.h b/arch/mips/mach-lsmips/ls1c300/ls1c300.h
> new file mode 100644
> index 0000000000..70a5def841
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/ls1c300/ls1c300.h
> @@ -0,0 +1,52 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#ifndef __LS1C300_H__
> +#define __LS1C300_H__
> +
> +/* generated, don't edit */
> +
> +#define	SDRAM_BASE	0x00000000
> +#define	CAMERA_BASE	0x1c280000
> +#define	DC_BASE		0x1c300000
> +#define	AXIMUX_BASE	0x1f000000
> +
> +#define	SPI0MEM_BASE	0x1d000000
> +#define	SPI1MEM_BASE	0x1e000000
> +#define	Boot_BASE	0xbfc00000
> +#define	CONFREG_BASE	0x1fd00000
> +#define	OTG_BASE	0x1fe00000
> +#define	MAC_BASE	0x1fe10000
> +#define	USB_BASE	0x1fe20000
> +#define	APB_BASE	0x1fe40000
> +#define	SPI0_BASE	0x1fe80000
> +#define	SPI1_BASE	0x1fec0000
> +
> +#define	UART0_BASE	0x1fe40000
> +#define	UART1_BASE	0x1fe44000
> +#define	UART2_BASE	0x1fe48000
> +#define	UART3_BASE	0x1fe4c000
> +#define	UART4_BASE	0x1fe4c400
> +#define	UART5_BASE	0x1fe4c500
> +#define	UART6_BASE	0x1fe4c600
> +#define	UART7_BASE	0x1fe4c700
> +#define	UART8_BASE	0x1fe4c800
> +#define	UART9_BASE	0x1fe4c900
> +#define	UART10_BASE	0x1fe4ca00
> +#define	UART11_BASE	0x1fe4cb00
> +#define	CAN0_BASE	0x1fe50000
> +#define	CAN1_BASE	0x1fe54000
> +#define	I2C0_BASE	0x1fe58000
> +#define	PWM_BASE	0x1fe5c000
> +#define	I2S_BASE	0x1fe60000
> +#define	RTC_BASE	0x1fe64000
> +#define	I2C1_BASE	0x1fe68000
> +#define	SDIO_BASE	0x1fe6c000
> +#define	I2C2_BASE	0x1fe70000
> +#define	ADC_BASE	0x1fe74000
> +#define	NAND_BASE	0x1fe78000
> +#define	HCNTR_BASE	0x1fe7c000
> +
> +#endif /* __LS1C300_H__ */

All this should go in the device tree.

> diff --git a/arch/mips/mach-lsmips/ls1c300/serial.c b/arch/mips/mach-lsmips/ls1c300/serial.c
> new file mode 100644
> index 0000000000..88bc18ef85
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/ls1c300/serial.c
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + *
> + * Author:  Gao Weijie <weijie.gao at mediatek.com>
> + *
> + * Copyright (C) 2020-2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <mach/serial.h>
> +#include <linux/kernel.h>
> +#include "ls1c300.h"
> +
> +struct uart_pin_config {
> +	char port;
> +	char af;
> +	char rx;
> +	char tx;
> +};
> +
> +struct uart_pin_config con[] = {
> +#if CONFIG_CONS_INDEX == 0
> +{ 0, 2, 74, 75 },
> +{ 0, 3, 23, 24 },
> +{ 0, 3, 99, 100 },
> +
> +#elif CONFIG_CONS_INDEX == 1
> +{ 1, 1, 17, 18 },
> +{ 1, 1, 101, 102 },
> +{ 1, 2, 40, 41 },
> +{ 1, 4, 2, 3 },
> +
> +#elif CONFIG_CONS_INDEX == 2
> +{ 2, 2, 36, 37 },
> +{ 2, 2, 42, 43 },
> +{ 2, 3, 27, 28 },
> +{ 2, 3, 103, 104 },
> +{ 2, 4, 4, 5 },
> +
> +#elif CONFIG_CONS_INDEX == 3
> +{ 3, 2, 17, 18 },
> +{ 3, 2, 33, 34 },
> +{ 3, 2, 44, 45 },
> +{ 3, 4, 0, 1 },
> +
> +#elif CONFIG_CONS_INDEX == 4
> +{ 4, 5, 23, 24 },
> +{ 4, 5, 58, 59 },
> +{ 4, 5, 80, 79 },
> +
> +#elif CONFIG_CONS_INDEX == 5
> +{ 5, 5, 25, 26 },
> +{ 5, 5, 60, 61 },
> +{ 5, 5, 81, 78 },
> +
> +#elif CONFIG_CONS_INDEX == 6
> +{ 6, 5, 27, 46 },
> +{ 6, 5, 62, 63 },
> +
> +#elif CONFIG_CONS_INDEX == 7
> +{ 7, 5, 57, 56 },
> +{ 7, 5, 64, 65 },
> +{ 7, 5, 87, 88 },
> +
> +#elif CONFIG_CONS_INDEX == 8
> +{ 8, 5, 55, 54 },
> +{ 8, 5, 66, 67 },
> +{ 8, 5, 89, 90 },
> +
> +#elif CONFIG_CONS_INDEX == 9
> +{ 9, 5, 53, 52 },
> +{ 9, 5, 68, 69 },
> +{ 9, 5, 85, 86 },
> +
> +#elif CONFIG_CONS_INDEX == 10
> +{ 10, 5, 51, 50 },
> +{ 10, 5, 70, 71 },
> +{ 10, 5, 84, 82 },
> +
> +#elif CONFIG_CONS_INDEX == 11
> +{ 11, 5, 49, 48 },
> +{ 11, 5, 72, 73 },
> +#endif /* CONFIG_CONS_INDEX */
> +};
> +
> +#define UART2_RX	36
> +#define UART2_TX	37
> +#define AFUNC		2
> +
> +void lsmips_spl_serial_init(void)
> +{
> +#ifdef CONFIG_SPL_SERIAL
> +	int pin_rx, pin_tx;
> +	int afunc;
> +
> +	if (CONFIG_CONS_PIN_SELECT < ARRAY_SIZE(con)) {
> +		pin_rx = con[CONFIG_CONS_PIN_SELECT].rx;
> +		pin_tx = con[CONFIG_CONS_PIN_SELECT].tx;
> +		afunc = con[CONFIG_CONS_PIN_SELECT].af;
> +	} else {
> +		pin_rx = UART2_RX;
> +		pin_tx = UART2_TX;
> +		afunc = AFUNC;
> +	}
> +
> +	gpio_set_alternate(pin_rx, afunc);
> +	gpio_set_alternate(pin_tx, afunc);
> +#endif /* CONFIG_SPL_SERIAL */
> +	return ;
> +}

Please use a pinctrl driver for this. In particular, you may be able to use
pinctrl-simple, which can be configured through the device tree.

> diff --git a/arch/mips/mach-lsmips/spl.c b/arch/mips/mach-lsmips/spl.c
> new file mode 100644
> index 0000000000..c7c28989f2
> --- /dev/null
> +++ b/arch/mips/mach-lsmips/spl.c
> @@ -0,0 +1,47 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
> + *
> + * Author: Gao Weijie <weijie.gao at mediatek.com>
> + *
> + * Copyright (C) 2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <spl.h>
> +#include <asm/sections.h>
> +#include <linux/libfdt.h>
> +#include <linux/sizes.h>
> +#include <mach/serial.h>
> +
> +void __noreturn board_init_f(ulong dummy)
> +{
> +	spl_init();
> +
> +#ifdef CONFIG_SPL_SERIAL
> +	/*
> +	 * lsmips_spl_serial_init() is useful if debug uart is enabled,
> +	 * or DM based serial is not enabled.
> +	 */
> +	lsmips_spl_serial_init();
> +	preloader_console_init();
> +#endif
> +
> +	board_init_r(NULL, 0);
> +}
> +
> +void board_boot_order(u32 *spl_boot_list)
> +{
> +	spl_boot_list[0] = BOOT_DEVICE_NOR;
> +}
> +
> +unsigned long spl_nor_get_uboot_base(void)
> +{
> +	void *uboot_base = __image_copy_end;
> +
> +	if (fdt_magic(uboot_base) == FDT_MAGIC)
> +		return (unsigned long)uboot_base + fdt_totalsize(uboot_base);
> +
> +	return (unsigned long)uboot_base;
> +}
> diff --git a/board/loongson/ls1c300-eval/Kconfig b/board/loongson/ls1c300-eval/Kconfig
> new file mode 100644
> index 0000000000..e427570a83
> --- /dev/null
> +++ b/board/loongson/ls1c300-eval/Kconfig
> @@ -0,0 +1,12 @@
> +if BOARD_LS1C300
> +
> +config SYS_BOARD
> +	default "ls1c300-eval"
> +
> +config SYS_VENDOR
> +	default "loongson"
> +
> +config SYS_CONFIG_NAME
> +	default "ls1c300"
> +
> +endif
> diff --git a/board/loongson/ls1c300-eval/MAINTAINERS b/board/loongson/ls1c300-eval/MAINTAINERS
> new file mode 100644
> index 0000000000..5420198dab
> --- /dev/null
> +++ b/board/loongson/ls1c300-eval/MAINTAINERS
> @@ -0,0 +1,7 @@
> +LS1C300_EVAL BOARD
> +M:	Du Huanpeng<dhu at hodcarrier.org>
> +S:	Maintained
> +F:	board/loongson/ls1c300-eval
> +F:	include/configs/ls1c300.h
> +F:	configs/ls1c300_defconfig
> +F:	arch/mips/dts/ls1c300-eval.dts
> diff --git a/board/loongson/ls1c300-eval/Makefile b/board/loongson/ls1c300-eval/Makefile
> new file mode 100644
> index 0000000000..db129c5aba
> --- /dev/null
> +++ b/board/loongson/ls1c300-eval/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-y += board.o
> diff --git a/board/loongson/ls1c300-eval/board.c b/board/loongson/ls1c300-eval/board.c
> new file mode 100644
> index 0000000000..2f588a0dcb
> --- /dev/null
> +++ b/board/loongson/ls1c300-eval/board.c
> @@ -0,0 +1,20 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020-2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#include <common.h>
> +#include <mach/serial.h>
> +
> +#ifdef CONFIG_DEBUG_UART_BOARD_INIT
> +
> +#define UART2_RX	36
> +#define UART2_TX	37
> +#define AFUNC		2
> +
> +void board_debug_uart_init(void)
> +{
> +	gpio_set_alternate(UART2_TX, AFUNC);
> +	gpio_set_alternate(UART2_RX, AFUNC);
> +}
> +#endif
> diff --git a/configs/ls1c300_defconfig b/configs/ls1c300_defconfig
> new file mode 100644
> index 0000000000..c47fe5b98f
> --- /dev/null
> +++ b/configs/ls1c300_defconfig
> @@ -0,0 +1,65 @@
> +CONFIG_MIPS=y
> +CONFIG_SYS_MALLOC_F_LEN=0x40000
> +CONFIG_SPL_LIBCOMMON_SUPPORT=y
> +CONFIG_SPL_LIBGENERIC_SUPPORT=y
> +CONFIG_NR_DRAM_BANKS=1
> +CONFIG_ENV_SIZE=0x1000
> +CONFIG_ENV_OFFSET=0x30000
> +CONFIG_ENV_SECT_SIZE=0x10000
> +CONFIG_DEFAULT_DEVICE_TREE="ls1c300-eval"
> +CONFIG_SPL_SERIAL=y
> +CONFIG_SPL_SIZE_LIMIT=0x100000
> +CONFIG_SPL=y
> +CONFIG_DEBUG_UART_BOARD_INIT=y
> +CONFIG_DEBUG_UART_BASE=0xbfe48000
> +CONFIG_DEBUG_UART_CLOCK=66000000

Do you have normal uart working?

> +CONFIG_ARCH_LSMIPS=y
> +CONFIG_SPL_PAYLOAD="u-boot.img"
> +# CONFIG_MIPS_CACHE_SETUP is not set
> +# CONFIG_MIPS_CACHE_DISABLE is not set
> +CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y
> +CONFIG_MIPS_BOOT_FDT=y
> +CONFIG_DEBUG_UART=y
> +CONFIG_SYS_LOAD_ADDR=0x80010000
> +CONFIG_FIT=y
> +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
> +CONFIG_LOGLEVEL=9
> +CONFIG_DISPLAY_BOARDINFO_LATE=y
> +CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK=y
> +CONFIG_SPL_SYS_MALLOC_SIMPLE=y
> +CONFIG_SPL_NOR_SUPPORT=y
> +# CONFIG_CMD_ELF is not set
> +# CONFIG_CMD_XIMG is not set
> +# CONFIG_CMD_CRC32 is not set
> +CONFIG_CMD_CLK=y
> +# CONFIG_CMD_DM is not set
> +CONFIG_CMD_GPIO=y
> +# CONFIG_CMD_LOADS is not set
> +CONFIG_CMD_SPI=y
> +CONFIG_CMD_WDT=y
> +# CONFIG_PARTITIONS is not set
> +CONFIG_OF_EMBED=y
> +CONFIG_ENV_IS_IN_SPI_FLASH=y

Where is the spi flash driver?

> +CONFIG_SYS_RELOC_GD_ENV_ADDR=y
> +# CONFIG_NET is not set
> +# CONFIG_INPUT is not set
> +CONFIG_SPI_FLASH_EON=y
> +CONFIG_SPI_FLASH_GIGADEVICE=y
> +CONFIG_SPI_FLASH_ISSI=y
> +CONFIG_SPI_FLASH_MACRONIX=y
> +CONFIG_SPI_FLASH_SPANSION=y
> +CONFIG_SPI_FLASH_STMICRO=y
> +CONFIG_SPI_FLASH_WINBOND=y
> +CONFIG_SPI_FLASH_XMC=y
> +CONFIG_CONS_INDEX=2
> +CONFIG_DEBUG_UART_ANNOUNCE=y
> +CONFIG_SYS_NS16550=y
> +CONFIG_SPI=y
> +CONFIG_SYSRESET_WATCHDOG=y
> +CONFIG_SYSRESET_WATCHDOG_AUTO=y
> +CONFIG_WATCHDOG_TIMEOUT_MSECS=3000
> +CONFIG_WDT_LSMIPS=y
> +CONFIG_REGEX=y
> +CONFIG_LZMA=y
> +CONFIG_SPL_LZMA=y
> +CONFIG_SPL_GZIP=y
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index bb4eee5d99..51562ca4a6 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -17,6 +17,7 @@ obj-y += tegra/
>   obj-y += ti/
>   obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/
>   obj-$(CONFIG_ARCH_ASPEED) += aspeed/
> +obj-$(CONFIG_ARCH_LSMIPS) += lsmips/
>   obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
>   obj-$(CONFIG_ARCH_MESON) += meson/
>   obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
> diff --git a/drivers/clk/lsmips/Makefile b/drivers/clk/lsmips/Makefile
> new file mode 100644
> index 0000000000..0a47269cd3
> --- /dev/null
> +++ b/drivers/clk/lsmips/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_SOC_LS1C300) += clk-ls1c300.o
> diff --git a/drivers/clk/lsmips/clk-ls1c300.c b/drivers/clk/lsmips/clk-ls1c300.c
> new file mode 100644
> index 0000000000..c78e23d695
> --- /dev/null
> +++ b/drivers/clk/lsmips/clk-ls1c300.c
> @@ -0,0 +1,145 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * reference:
> + *   drivers/clk/microchip/mpfs_clk.c
> + *   drivers/clk/clk_octeon.c
> + *
> + * Copyright (C) 2020-2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#include <common.h>
> +#include <clk-uclass.h>
> +#include <dm.h>
> +#include <dt-bindings/clock/ls1c300-clk.h>
> +#include <linux/bitops.h>
> +#include <linux/bitfield.h>
> +#include <linux/io.h>
> +#include <linux/clk-provider.h>
> +
> +/* START_FREQ */
> +#define	PLL_VALID	BIT(31)
> +#define	RESERVED0	GENMASK(30, 24)
> +#define	FRAC_N		GENMASK(23, 16)
> +#define	M_PLL		GENMASK(15, 8)
> +#define	RESERVED1	GENMASK(7, 4)
> +#define	RST_TIME	GENMASK(3, 2)
> +#define	SDRAM_DIV	GENMASK(1, 0)
> +/* CLK_DIV_PARAM */
> +#define	PIX_DIV		GENMASK(31, 24)
> +#define	CAM_DIV		GENMASK(23, 16)
> +#define	CPU_DIV		GENMASK(15, 8)
> +#define	RESERVED2	GENMASK(7, 6)
> +#define	PIX_DIV_VALID	BIT(5)
> +#define	PIX_SEL		BIT(4)
> +#define	CAM_DIV_VALID	BIT(3)
> +#define	CAM_SEL		BIT(2)
> +#define	CPU_DIV_VALID	BIT(1)
> +#define	CPU_SEL		BIT(0)
> +/* CPU_THROT */
> +#define	CPU_THROT	GENMASK(3, 0)
> +
> +static const struct clk_div_table sdram_div_table[] = {
> +	{.val = 0, .div = 2},
> +	{.val = 1, .div = 4},
> +	{.val = 2, .div = 3},
> +	{.val = 3, .div = 3},
> +};
> +
> +static ulong ls1c300_clk_get_rate(struct clk *clk)
> +{
> +	struct clk *cl;
> +	ulong rate;
> +	int err;
> +
> +	err = clk_get_by_id(clk->id, &cl);
> +	if (err)
> +		return err;
> +
> +	rate = clk_get_rate(cl);
> +	return rate;
> +}

You can use [1] once it is merged.

[1] https://lore.kernel.org/all/a5b44286-e2e3-5069-0c0a-d673b86a6e8b@oss.nxp.com/

> +static int ls1c300_clk_enable(struct clk *clk)
> +{
> +	/* Nothing to do on Octeon */

nit: this isn't octeon :)

> +	return 0;
> +}
> +
> +static const struct clk_ops ls1c300_clk_ops = {
> +	.enable = ls1c300_clk_enable,
> +	.get_rate = ls1c300_clk_get_rate,
> +};
> +
> +static int ls1c300_clk_probe(struct udevice *dev)
> +{
> +	void __iomem *base;
> +	void __iomem *cpu_throt;
> +	void __iomem *addr;
> +
> +	struct clk *cl, clk;
> +
> +	int ret;
> +	const char *parent_name;
> +	unsigned int mult, div;
> +	unsigned int val;
> +	int flags;
> +
> +	base = (void *)dev_remap_addr_index(dev, 0);
> +#define START_FREQ	(0)
> +#define CLK_DIV_PARAM	(4)
> +	cpu_throt  = (void *)dev_remap_addr_index(dev, 1);
> +
> +	debug("     base: %p\n", base);
> +	debug("cpu_throt: %p\n", cpu_throt);
> +
> +	val = readl(base + START_FREQ);
> +	debug("   START_FREQ: [%08x]\n", val);
> +	val = readl(base + CLK_DIV_PARAM);
> +	debug("CLK_DIV_PARAM: [%08x]\n", val);
> +
> +	ret = clk_get_by_index(dev, 0, &clk);
> +	if (ret)
> +		return ret;
> +
> +	ret = clk_get_rate(&clk);
> +
> +	parent_name = clk.dev->name;
> +	val = readl(base + START_FREQ);
> +	mult = FIELD_GET(FRAC_N, val) + FIELD_GET(M_PLL, val); div = 4;

One assignment per line, please.

> +	cl = clk_register_fixed_factor(NULL, "pll", parent_name, 0, mult, div);

You will need to create custom clock ops for your PLL. See e.g. drivers/clk/imx/clk-pllv3.c

> +	clk_dm(CLK_PLL, cl);
> +
> +	addr = base + CLK_DIV_PARAM;
> +	flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
> +	cl = clk_register_divider(NULL, "cpu_div", "pll", 0, addr,  8, 7, flags);
> +	clk_dm(CLK_CPU, cl);
> +	cl = clk_register_divider(NULL, "cam_div", "pll", 0, addr, 16, 7, flags);
> +	clk_dm(CLK_CAMERA, cl);
> +	cl = clk_register_divider(NULL, "pix_div", "pll", 0, addr, 24, 7, flags);
> +	clk_dm(CLK_PIX, cl);
> +
> +	mult = FIELD_GET(CPU_THROT, readl(cpu_throt)) + 1; div = 16;
> +	cl = clk_register_fixed_factor(NULL, "cpu_throt_factor", "cpu_div", CLK_GET_RATE_NOCACHE, mult, div);

This should be a divider, like above. Use CLK_DIVIDER_ONE_BASED. You will need
a second follow-up clock to do the fixed division by 16.

I encourage you to seriously consider not using CCF for your driver :)

> +	clk_dm(CLK_CPU_THROT, cl);
> +
> +	addr = base + START_FREQ;
> +	cl = clk_register_divider(NULL, "sdram_div", "cpu_div", 0, addr, 0, 2, 0);
> +	to_clk_divider(cl)->table = sdram_div_table;

Create a patch to create a clk_register_divider_table() function, and use that.

> +	clk_dm(CLK_SDRAM, cl);
> +
> +	return 0;
> +}
> +
> +static const struct udevice_id ls1c300_clk_ids[] = {
> +	{ .compatible = "loongson,ls1c300-clk" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(ls1c300_clk) = {
> +	.name = "ls1c300-clk",
> +	.id = UCLASS_CLK,
> +	.of_match = ls1c300_clk_ids,
> +	.probe = ls1c300_clk_probe,
> +	.priv_auto = sizeof(struct clk),
> +	.ops = &ls1c300_clk_ops,
> +};
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index f90f0ca02b..289b568188 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -167,6 +167,14 @@ config WDT_GPIO
>   	  doc/device-tree-bindings/watchdog/gpio-wdt.txt for
>   	  information on how to describe the watchdog in device tree.
>   
> +config WDT_LSMIPS
> +	bool "Loongson MIPS watchdog timer support"
> +	depends on WDT
> +	help
> +	  Select this to enable watchdog timer for Loongson SoCs.
> +	  The watchdog timer is stopped when initialized.
> +	  It performs full SoC reset.
> +
>   config WDT_MPC8xx
>   	bool "MPC8xx watchdog timer support"
>   	depends on WDT && MPC8xx
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index a35bd559f5..cb596af904 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
>   obj-$(CONFIG_WDT_ORION) += orion_wdt.o
>   obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
>   obj-$(CONFIG_WDT_GPIO) += gpio_wdt.o
> +obj-$(CONFIG_WDT_LSMIPS) += lsmips_wdt.o
>   obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
>   obj-$(CONFIG_WDT_MT7620) += mt7620_wdt.o
>   obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o
> diff --git a/drivers/watchdog/lsmips_wdt.c b/drivers/watchdog/lsmips_wdt.c
> new file mode 100644
> index 0000000000..ef91cae349
> --- /dev/null
> +++ b/drivers/watchdog/lsmips_wdt.c
> @@ -0,0 +1,126 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Watchdog driver for MediaTek SoCs
> + *
> + * Copyright (C) 2018 MediaTek Inc.
> + * Author: Ryder Lee <ryder.lee at mediatek.com>
> + *
> + * based on: drivers/watchdog/mtk_wdt.c
> + * Copyright (C) 2020-2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <hang.h>
> +#include <wdt.h>
> +#include <asm/io.h>
> +#include <linux/bitops.h>
> +#include <clk.h>
> +
> +#define WDT_EN		(priv->base + 0)
> +#define WDT_TIMER	(priv->base + 4)
> +#define WDT_SET		(priv->base + 8)

Please define this like

#define WDT_EN   0
#define WDT_TIME 4
#define WDT_SET  8

and use it like

writel(priv->timeout, priv->base + WDT_SET)

If you find that too verbose, you can also create a helper function like

static inline void lsmips_wdt_writel(struct lsmips_wdt_priv *priv, ulong val, ptrdiff_t offset)
{
	writel(val, priv->base + offset);
}

> +
> +struct lsmips_wdt_priv {
> +	void __iomem *base;
> +	ulong clock;
> +	unsigned long timeout;
> +};

Docment the fields here please.

> +
> +static int lsmips_wdt_reset(struct udevice *dev)
> +{
> +	struct lsmips_wdt_priv *priv = dev_get_priv(dev);
> +
> +	writel(priv->timeout, WDT_TIMER);
> +	writel(1, WDT_SET);
> +
> +	return 0;
> +}
> +
> +static int lsmips_wdt_stop(struct udevice *dev)
> +{
> +	struct lsmips_wdt_priv *priv = dev_get_priv(dev);
> +
> +	writel(0, WDT_EN);
> +	return 0;
> +}
> +
> +static int lsmips_wdt_expire_now(struct udevice *dev, ulong flags)
> +{
> +	struct lsmips_wdt_priv *priv = dev_get_priv(dev);
> +
> +	writel(1, WDT_EN);
> +	writel(1, WDT_TIMER);
> +	writel(1, WDT_SET);
> +
> +	hang();
> +	return 0;
> +}
> +
> +static int lsmips_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
> +{
> +	struct lsmips_wdt_priv *priv = dev_get_priv(dev);
> +	unsigned int timeout;
> +
> +	timeout = U32_MAX / (priv->clock / 1000);
> +
> +	if (timeout < timeout_ms)
> +		timeout = U32_MAX;
> +	else
> +		timeout = timeout_ms * (priv->clock / 1000);

why not start with this?

Also, please multiply first for better precision. And use MSEC_PER_SEC instead of 1000.

> +
> +	debug("WDT: reload  = %08x\n", timeout);
> +
> +	writel(1, WDT_EN);
> +	writel(timeout, WDT_TIMER);
> +	writel(1, WDT_SET);
> +
> +	priv->timeout = timeout;
> +
> +	return 0;
> +}
> +
> +static int lsmips_wdt_probe(struct udevice *dev)
> +{
> +	struct lsmips_wdt_priv *priv = dev_get_priv(dev);
> +	struct clk cl;
> +
> +	priv->base = dev_remap_addr(dev);
> +	if (!priv->base)
> +		return -ENOENT;
> +
> +	if (clk_get_by_index(dev, 0, &cl) == 0)
> +		priv->clock = clk_get_rate(&cl);
> +
> +	if (priv->clock < 33000000 || priv->clock > 150000000) {
> +		/* assume 67MHz by default */
> +		priv->clock = 67108864;
> +	}

What's the logic here? Why is this clock optional?

> +
> +	debug("WDT: clock = %ld\n", priv->clock);
> +
> +	writel(0, WDT_EN);
> +	return 0;
> +}
> +
> +static const struct wdt_ops lsmips_wdt_ops = {
> +	.start = lsmips_wdt_start,
> +	.reset = lsmips_wdt_reset,
> +	.stop = lsmips_wdt_stop,
> +	.expire_now = lsmips_wdt_expire_now,
> +};
> +
> +static const struct udevice_id lsmips_wdt_ids[] = {
> +	{ .compatible = "loongson,ls1c300-wdt"},
> +	{}
> +};
> +
> +U_BOOT_DRIVER(lsmips_wdt) = {
> +	.name = "lsmips_wdt",
> +	.id = UCLASS_WDT,
> +	.of_match = lsmips_wdt_ids,
> +	.priv_auto = sizeof(struct lsmips_wdt_priv),
> +	.probe = lsmips_wdt_probe,
> +	.ops = &lsmips_wdt_ops,
> +	.flags = DM_FLAG_PRE_RELOC,
> +};
> diff --git a/include/configs/ls1c300.h b/include/configs/ls1c300.h
> new file mode 100644
> index 0000000000..a96deb6bb2
> --- /dev/null
> +++ b/include/configs/ls1c300.h
> @@ -0,0 +1,61 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + *
> + * Author: Gao Weijie <weijie.gao at mediatek.com>
> + * based on: include/configs/mt7628.h
> + * Copyright (C) 2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#ifndef __CONFIG_LS1C300_H__
> +#define __CONFIG_LS1C300_H__
> +
> +#define CONFIG_SYS_HZ			1000
> +
> +#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
> +
> +#define CONFIG_SYS_BOOTPARAMS_LEN	0x20000
> +
> +#define CONFIG_SYS_SDRAM_BASE		0x80000000
> +#define CONFIG_SYS_LOAD_ADDR		0x80010000
> +
> +#define CONFIG_SYS_INIT_SP_OFFSET	0x80000
> +
> +#define CONFIG_SYS_BOOTM_LEN		0x1000000
> +
> +#define CONFIG_SYS_MAXARGS		16
> +#define CONFIG_SYS_CBSIZE		1024
> +
> +/* Serial SPL */
> +#define CONFIG_SYS_NS16550_SERIAL
> +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL)
> +#define CONFIG_SYS_NS16550_CLK		66000000
> +#define CONFIG_SYS_NS16550_REG_SIZE	(-1)
> +#define CONFIG_SYS_NS16550_COM1		0xbfe44000
> +#define CONFIG_SYS_NS16550_COM2		0xbfe48000
> +#define CONFIG_SYS_NS16550_COM3		0xbfe4c000
> +#define CONFIG_SYS_NS16550_COM4		0xbfe4c400
> +#define CONFIG_SYS_NS16550_COM5		0xbfe4c500
> +#define CONFIG_SYS_NS16550_COM6		0xbfe4c600
> +#endif
> +
> +/* Serial common */
> +#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 }
> +
> +/* SPL */
> +#if defined(CONFIG_SPL) && !defined(CONFIG_SPL_BUILD)
> +#define CONFIG_SKIP_LOWLEVEL_INIT
> +#endif
> +
> +#define CONFIG_SYS_UBOOT_START		CONFIG_SYS_TEXT_BASE
> +#define CONFIG_SPL_BSS_START_ADDR	0x80010000
> +#define CONFIG_SPL_BSS_MAX_SIZE		0x10000
> +#define CONFIG_SPL_MAX_SIZE		0x10000
> +#define CONFIG_SPL_PAD_TO		0
> +
> +#define CONFIG_MALLOC_F_ADDR		0x80100000	/* FIXME: find a proper place */
> +
> +/* Dummy value */
> +#define CONFIG_SYS_UBOOT_BASE		0
> +
> +#endif /* __CONFIG_LS1C300_H__ */
> diff --git a/include/dt-bindings/clock/ls1c300-clk.h b/include/dt-bindings/clock/ls1c300-clk.h
> new file mode 100644
> index 0000000000..735fa61789
> --- /dev/null
> +++ b/include/dt-bindings/clock/ls1c300-clk.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2022 Du Huanpeng <dhu at hodcarrier.org>
> + */
> +
> +#ifndef __DT_BINDINGS_LS1C300_CLK_H__
> +#define __DT_BINDINGS_LS1C300_CLK_H__
> +
> +/* Base clocks */
> +#define CLK_XTAL	0
> +#define CLK_PLL		1
> +#define CLK_CPU		2
> +#define CLK_CPU_THROT	7
> +#define CLK_SDRAM	3
> +
> +#define CLK_CAMERA	4
> +#define CLK_DC		5
> +#define CLK_PIX		5
> +#define CLK_AXIMUX	6
> +
> +/* Peripheral clocks */
> +#define CLK_UART0	3
> +#define CLK_UART1	3
> +#define CLK_UART2	3
> +#define CLK_UART3	3
> +#define CLK_UART4	3
> +#define CLK_UART5	3
> +#define CLK_UART6	3
> +#define CLK_UART7	3
> +#define CLK_UART8	3
> +#define CLK_UART9	3
> +#define CLK_UART10	3
> +#define CLK_UART11	3
> +#define CLK_CAN0	3
> +#define CLK_CAN1	3
> +#define CLK_I2C0	3
> +#define CLK_PWM		3
> +#define CLK_I2S		3
> +#define CLK_RTC		3
> +#define CLK_I2C1	3
> +#define CLK_SDIO	3
> +#define CLK_I2C2	3
> +#define CLK_ADC		3
> +#define CLK_NAND	3
> +
> +#define CLK_WDT		3

So are these different clocks? Why do they all have the same id?

> +#endif /* __DT_BINDINGS_LS1C300_CLK_H__ */
> 



More information about the U-Boot mailing list