* [PATCH v6 1/7] mips: loongson: minimal initial SoC support [not found] <20260311052046.11265-1-sgdfkk@163.com> @ 2026-03-11 5:20 ` sgdfkk 2026-03-11 5:20 ` [PATCH v6 5/7] mips: loongson: add clk driver sgdfkk 1 sibling, 0 replies; 5+ messages in thread From: sgdfkk @ 2026-03-11 5:20 UTC (permalink / raw) To: duhuanpeng, u-boot; +Cc: chenhuacai, jiaxun.yang, Du Huanpeng From: Du Huanpeng <u74147@gmail.com> 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 Links: https://www.loongson.cn/ introduce base support for the ls1c300 SoC. - debug UART2 - serial console - clock - watchdog - sysreset - uart Signed-off-by: Du Huanpeng <u74147@gmail.com> --- MAINTAINERS | 9 ++++ arch/mips/Kconfig | 11 ++++ arch/mips/Makefile | 1 + arch/mips/mach-loongson/Kconfig | 69 ++++++++++++++++++++++++ arch/mips/mach-loongson/Makefile | 6 +++ arch/mips/mach-loongson/cpu.c | 19 +++++++ arch/mips/mach-loongson/ls1c300/Makefile | 7 +++ arch/mips/mach-loongson/ls1c300/init.c | 61 +++++++++++++++++++++ arch/mips/mach-loongson/spl.c | 46 ++++++++++++++++ 9 files changed, 229 insertions(+) create mode 100644 arch/mips/mach-loongson/Kconfig create mode 100644 arch/mips/mach-loongson/Makefile create mode 100644 arch/mips/mach-loongson/cpu.c create mode 100644 arch/mips/mach-loongson/ls1c300/Makefile create mode 100644 arch/mips/mach-loongson/ls1c300/init.c create mode 100644 arch/mips/mach-loongson/spl.c diff --git a/MAINTAINERS b/MAINTAINERS index d2040fee252..d1e6e4bc0da 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1385,6 +1385,15 @@ F: drivers/net/cortina_ni.c F: drivers/net/cortina_ni.h F: drivers/net/phy/ca_phy.c +MIPS LOONGSON LS1C300 +M: Du Huanpeng <u74147@gmail.com> +S: Maintained +F: arch/mips/dts/loongson32-ls1c300b.dtsi +F: arch/mips/mach-loongson/ +F: drivers/clk/loongson/ +F: drivers/watchdog/loongson_wdt.c +F: include/dt-bindings/clock/ls1c300-clk.h + MIPS MEDIATEK M: Weijie Gao <weijie.gao@mediatek.com> R: GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 36612756294..0e3fc9ceeb5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -88,6 +88,16 @@ config ARCH_MTMIPS select SUPPORT_LITTLE_ENDIAN select SUPPORT_SPL +config ARCH_LSMIPS + bool "Support Loongson MIPS platforms" + select DM + select DM_SERIAL + select OF_CONTROL + select SUPPORTS_CPU_MIPS32_R1 + select SUPPORTS_CPU_MIPS32_R2 + select SUPPORTS_LITTLE_ENDIAN + select SUPPORT_SPL + config ARCH_JZ47XX bool "Support Ingenic JZ47xx" select SUPPORT_SPL @@ -202,6 +212,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-loongson/Kconfig" source "arch/mips/mach-octeon/Kconfig" if MIPS diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 453c7885075..72b800c755b 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -19,6 +19,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) += loongson machine-$(CONFIG_ARCH_MSCC) += mscc machine-${CONFIG_ARCH_OCTEON} += octeon diff --git a/arch/mips/mach-loongson/Kconfig b/arch/mips/mach-loongson/Kconfig new file mode 100644 index 00000000000..57d22927270 --- /dev/null +++ b/arch/mips/mach-loongson/Kconfig @@ -0,0 +1,69 @@ +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 SPL_PAYLOAD + default "u-boot-lzma.img" if SPL_LZMA + +config BUILD_TARGET + default "u-boot-with-spl.bin" if SPL + default "u-boot.bin" if !SPL + +choice + prompt "Loongson MIPS SoC select" + +config SOC_LS1C300 + bool "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 + 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-loongson/Makefile b/arch/mips/mach-loongson/Makefile new file mode 100644 index 00000000000..654143a5f70 --- /dev/null +++ b/arch/mips/mach-loongson/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-loongson/cpu.c b/arch/mips/mach-loongson/cpu.c new file mode 100644 index 00000000000..249fdcbdc5f --- /dev/null +++ b/arch/mips/mach-loongson/cpu.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + * Copyright (C) 2022-2026 Du Huanpeng <u74147@gmail.com> + */ + +#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) +{ + gd->ram_size = get_ram_size((void *)KSEG1, SZ_256M) - CONFIG_TEXT_BASE % SZ_256M; + return 0; +} diff --git a/arch/mips/mach-loongson/ls1c300/Makefile b/arch/mips/mach-loongson/ls1c300/Makefile new file mode 100644 index 00000000000..17b9d6fb9ca --- /dev/null +++ b/arch/mips/mach-loongson/ls1c300/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += lowlevel_init.o +obj-y += sdram.o +obj-y += init.o +obj-y += gpio.o +obj-$(CONFIG_SPL_BUILD) += serial.o diff --git a/arch/mips/mach-loongson/ls1c300/init.c b/arch/mips/mach-loongson/ls1c300/init.c new file mode 100644 index 00000000000..aea0a863e3e --- /dev/null +++ b/arch/mips/mach-loongson/ls1c300/init.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. + * + * Author: Gao Weijie <weijie.gao@mediatek.com> + * + * based on: arch/mips/mach-mtmips/mt7628/init.c + * Copyright (C) 2020-2026 Du Huanpeng <u74147@gmail.com> + */ + +#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> + +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; + + ret = clk_request(udev, &clk); + if (ret < 0) + return ret; + + clk.id = CLK_XTAL; + xtal = clk_get_rate(&clk); + + clk.id = CLK_CPU_THROT; + gd->cpu_clk = clk_get_rate(&clk); + + clk.id = CLK_APB; + gd->mem_clk = clk_get_rate(&clk); + + 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 / 2; +} diff --git a/arch/mips/mach-loongson/spl.c b/arch/mips/mach-loongson/spl.c new file mode 100644 index 00000000000..40454d2cbc9 --- /dev/null +++ b/arch/mips/mach-loongson/spl.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Gao Weijie <weijie.gao@mediatek.com> + * + * Copyright (C) 2022-2026 Du Huanpeng <u74147@gmail.com> + */ + +#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 + /* + * loongson_spl_serial_init() is useful if debug uart is enabled, + * or DM based serial is not enabled. + */ + loongson_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; +} -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v6 5/7] mips: loongson: add clk driver [not found] <20260311052046.11265-1-sgdfkk@163.com> 2026-03-11 5:20 ` [PATCH v6 1/7] mips: loongson: minimal initial SoC support sgdfkk @ 2026-03-11 5:20 ` sgdfkk 2026-03-11 17:55 ` Daniel Schwierzeck 1 sibling, 1 reply; 5+ messages in thread From: sgdfkk @ 2026-03-11 5:20 UTC (permalink / raw) To: duhuanpeng, u-boot; +Cc: chenhuacai, jiaxun.yang, Du Huanpeng From: Du Huanpeng <u74147@gmail.com> clk driver loongson mips for embedded SoC ls1c300 Signed-off-by: Du Huanpeng <u74147@gmail.com> --- drivers/clk/Makefile | 1 + drivers/clk/loongson/Makefile | 3 + drivers/clk/loongson/clk-ls1c300.c | 179 +++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 drivers/clk/loongson/Makefile create mode 100644 drivers/clk/loongson/clk-ls1c300.c diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5f0c0d8a5c2..e19bb17276e 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -23,6 +23,7 @@ obj-y += ti/ obj-$(CONFIG_CLK_THEAD) += thead/ obj-$(CONFIG_$(PHASE_)CLK_INTEL) += intel/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_ARCH_LSMIPS) += loongson/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_ARCH_MESON) += meson/ obj-$(CONFIG_ARCH_MTMIPS) += mtmips/ diff --git a/drivers/clk/loongson/Makefile b/drivers/clk/loongson/Makefile new file mode 100644 index 00000000000..0a47269cd30 --- /dev/null +++ b/drivers/clk/loongson/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SOC_LS1C300) += clk-ls1c300.o diff --git a/drivers/clk/loongson/clk-ls1c300.c b/drivers/clk/loongson/clk-ls1c300.c new file mode 100644 index 00000000000..acca92cd657 --- /dev/null +++ b/drivers/clk/loongson/clk-ls1c300.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * reference: + * drivers/clk/microchip/mpfs_clk.c + * drivers/clk/clk_octeon.c + * + * Copyright (C) 2020-2026 Du Huanpeng <u74147@gmail.com> + */ + +#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> + +/* PLL/SDRAM Frequency Configuration Register */ +#define START_FREQ 0 +#define CLK_DIV_PARAM 4 + +/* 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}, +}; + +ulong ls1c300_pll_get_rate(struct clk *clk) +{ + unsigned int mult; + long long parent_rate; + void *base; + unsigned int val; + + parent_rate = clk_get_parent_rate(clk); + base = (void *)clk->data; + + val = readl(base + START_FREQ); + mult = FIELD_GET(FRAC_N, val) + FIELD_GET(M_PLL, val); + return (mult * parent_rate) / 4; +} + +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; +} + +static int ls1c300_clk_probe(struct udevice *dev) +{ + void __iomem *base; + void __iomem *cpu_throt; + void __iomem *addr; + + struct clk *cl, clk; + const char *parent_name; + int flags; + int ret; + + base = (void *)dev_remap_addr_index(dev, 0); + cpu_throt = (void *)dev_remap_addr_index(dev, 1); + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_get_rate(&clk); + + parent_name = clk.dev->name; + + cl = kzalloc(sizeof(*cl), GFP_KERNEL); + cl->data = (unsigned long)base; + ret = clk_register(cl, "clk_ls1c300_pll", "pll", parent_name); + 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); + + cl = kzalloc(sizeof(*cl), GFP_KERNEL); + cl->data = (unsigned long)cpu_throt; + ret = clk_register(cl, "clk_cpu_throt", "cpu_throt_factor", "cpu_div"); + 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; + clk_dm(CLK_APB, cl); + + return 0; +} + +static ulong cpu_throt_get_rate(struct clk *clk) +{ + void __iomem *cpu_throt; + long long parent_rate; + ulong ret; + + parent_rate = clk_get_parent_rate(clk); + cpu_throt = (void *)clk->data; + + ret = readl(cpu_throt) + 1; + ret = parent_rate * ret / 16; + return ret; +} + +static const struct udevice_id ls1c300_clk_ids[] = { + { .compatible = "loongson,ls1c300-clk" }, + { } +}; + +static const struct clk_ops clk_cpu_throt_ops = { + .get_rate = cpu_throt_get_rate, +}; + +static const struct clk_ops clk_ls1c300_pll_ops = { + .get_rate = ls1c300_pll_get_rate, +}; + +static const struct clk_ops ls1c300_clk_ops = { + .get_rate = ls1c300_clk_get_rate, +}; + +U_BOOT_DRIVER(clk_ls1c300_cpu_throt) = { + .name = "clk_cpu_throt", + .id = UCLASS_CLK, + .ops = &clk_cpu_throt_ops, +}; + +U_BOOT_DRIVER(clk_ls1c300_pll) = { + .name = "clk_ls1c300_pll", + .id = UCLASS_CLK, + .ops = &clk_ls1c300_pll_ops, +}; + +U_BOOT_DRIVER(ls1c300_clk) = { + .name = "clk_ls1c300", + .id = UCLASS_CLK, + .of_match = ls1c300_clk_ids, + .probe = ls1c300_clk_probe, + .priv_auto = sizeof(struct clk), + .ops = &ls1c300_clk_ops, +}; -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v6 5/7] mips: loongson: add clk driver 2026-03-11 5:20 ` [PATCH v6 5/7] mips: loongson: add clk driver sgdfkk @ 2026-03-11 17:55 ` Daniel Schwierzeck 2026-04-07 15:41 ` duhuanpeng 0 siblings, 1 reply; 5+ messages in thread From: Daniel Schwierzeck @ 2026-03-11 17:55 UTC (permalink / raw) To: sgdfkk, duhuanpeng, u-boot; +Cc: chenhuacai, jiaxun.yang, Du Huanpeng On 3/11/26 06:20, sgdfkk@163.com wrote: > From: Du Huanpeng <u74147@gmail.com> > > clk driver loongson mips for embedded SoC ls1c300 > > Signed-off-by: Du Huanpeng <u74147@gmail.com> > --- > drivers/clk/Makefile | 1 + > drivers/clk/loongson/Makefile | 3 + > drivers/clk/loongson/clk-ls1c300.c | 179 +++++++++++++++++++++++++++++ > 3 files changed, 183 insertions(+) > create mode 100644 drivers/clk/loongson/Makefile > create mode 100644 drivers/clk/loongson/clk-ls1c300.c > > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile > index 5f0c0d8a5c2..e19bb17276e 100644 > --- a/drivers/clk/Makefile > +++ b/drivers/clk/Makefile > @@ -23,6 +23,7 @@ obj-y += ti/ > obj-$(CONFIG_CLK_THEAD) += thead/ > obj-$(CONFIG_$(PHASE_)CLK_INTEL) += intel/ > obj-$(CONFIG_ARCH_ASPEED) += aspeed/ > +obj-$(CONFIG_ARCH_LSMIPS) += loongson/ > obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ > obj-$(CONFIG_ARCH_MESON) += meson/ > obj-$(CONFIG_ARCH_MTMIPS) += mtmips/ > diff --git a/drivers/clk/loongson/Makefile b/drivers/clk/loongson/Makefile > new file mode 100644 > index 00000000000..0a47269cd30 > --- /dev/null > +++ b/drivers/clk/loongson/Makefile > @@ -0,0 +1,3 @@ > +# SPDX-License-Identifier: GPL-2.0 > + > +obj-$(CONFIG_SOC_LS1C300) += clk-ls1c300.o > diff --git a/drivers/clk/loongson/clk-ls1c300.c b/drivers/clk/loongson/clk-ls1c300.c > new file mode 100644 > index 00000000000..acca92cd657 > --- /dev/null > +++ b/drivers/clk/loongson/clk-ls1c300.c > @@ -0,0 +1,179 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * reference: > + * drivers/clk/microchip/mpfs_clk.c > + * drivers/clk/clk_octeon.c > + * > + * Copyright (C) 2020-2026 Du Huanpeng <u74147@gmail.com> > + */ > + > +#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> > + > +/* PLL/SDRAM Frequency Configuration Register */ > +#define START_FREQ 0 > +#define CLK_DIV_PARAM 4 > + > +/* 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}, > +}; > + > +ulong ls1c300_pll_get_rate(struct clk *clk) > +{ > + unsigned int mult; > + long long parent_rate; > + void *base; > + unsigned int val; > + > + parent_rate = clk_get_parent_rate(clk); > + base = (void *)clk->data; > + > + val = readl(base + START_FREQ); > + mult = FIELD_GET(FRAC_N, val) + FIELD_GET(M_PLL, val); > + return (mult * parent_rate) / 4; > +} > + > +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; > +} > + > +static int ls1c300_clk_probe(struct udevice *dev) > +{ > + void __iomem *base; > + void __iomem *cpu_throt; > + void __iomem *addr; > + > + struct clk *cl, clk; > + const char *parent_name; > + int flags; > + int ret; > + > + base = (void *)dev_remap_addr_index(dev, 0); > + cpu_throt = (void *)dev_remap_addr_index(dev, 1); no casting required, return value is already "void __iomem *" > + > + ret = clk_get_by_index(dev, 0, &clk); > + if (ret) > + return ret; > + > + ret = clk_get_rate(&clk); > + > + parent_name = clk.dev->name; > + > + cl = kzalloc(sizeof(*cl), GFP_KERNEL); > + cl->data = (unsigned long)base; why not create a "struct ls1c300_clk_priv" which embeds stuff like "void __iomem *base" and just use "struct ls1c300_clk_priv *priv = dev_get_priv(dev);" to get a type-safe pointer to the auto-allocated memory? The platform driver itself should not fiddle with "struct clk" and just register "struct clk_ops". > + ret = clk_register(cl, "clk_ls1c300_pll", "pll", parent_name); > + 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); > + > + cl = kzalloc(sizeof(*cl), GFP_KERNEL); > + cl->data = (unsigned long)cpu_throt; > + ret = clk_register(cl, "clk_cpu_throt", "cpu_throt_factor", "cpu_div"); > + 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; > + clk_dm(CLK_APB, cl); > + > + return 0; > +} > + > +static ulong cpu_throt_get_rate(struct clk *clk) > +{ > + void __iomem *cpu_throt; > + long long parent_rate; > + ulong ret; > + > + parent_rate = clk_get_parent_rate(clk); > + cpu_throt = (void *)clk->data; > + > + ret = readl(cpu_throt) + 1; > + ret = parent_rate * ret / 16; > + return ret; > +} > + > +static const struct udevice_id ls1c300_clk_ids[] = { > + { .compatible = "loongson,ls1c300-clk" }, > + { } > +}; > + > +static const struct clk_ops clk_cpu_throt_ops = { > + .get_rate = cpu_throt_get_rate, > +}; > + > +static const struct clk_ops clk_ls1c300_pll_ops = { > + .get_rate = ls1c300_pll_get_rate, > +}; > + > +static const struct clk_ops ls1c300_clk_ops = { > + .get_rate = ls1c300_clk_get_rate, > +}; > + > +U_BOOT_DRIVER(clk_ls1c300_cpu_throt) = { > + .name = "clk_cpu_throt", > + .id = UCLASS_CLK, > + .ops = &clk_cpu_throt_ops, > +}; > + > +U_BOOT_DRIVER(clk_ls1c300_pll) = { > + .name = "clk_ls1c300_pll", > + .id = UCLASS_CLK, > + .ops = &clk_ls1c300_pll_ops, > +}; > + > +U_BOOT_DRIVER(ls1c300_clk) = { > + .name = "clk_ls1c300", > + .id = UCLASS_CLK, > + .of_match = ls1c300_clk_ids, > + .probe = ls1c300_clk_probe, > + .priv_auto = sizeof(struct clk), > + .ops = &ls1c300_clk_ops, > +}; -- - Daniel ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v6 5/7] mips: loongson: add clk driver 2026-03-11 17:55 ` Daniel Schwierzeck @ 2026-04-07 15:41 ` duhuanpeng 0 siblings, 0 replies; 5+ messages in thread From: duhuanpeng @ 2026-04-07 15:41 UTC (permalink / raw) To: Daniel Schwierzeck; +Cc: sgdfkk, u-boot, chenhuacai, jiaxun.yang, Du Huanpeng Dear Daniel, On Wed, Mar 11, 2026 at 06:55:31PM +0100, Daniel Schwierzeck wrote: > > > On 3/11/26 06:20, sgdfkk@163.com wrote: > > From: Du Huanpeng <u74147@gmail.com> > > > > clk driver loongson mips for embedded SoC ls1c300 > > > > Signed-off-by: Du Huanpeng <u74147@gmail.com> > > --- > > drivers/clk/Makefile | 1 + > > drivers/clk/loongson/Makefile | 3 + > > drivers/clk/loongson/clk-ls1c300.c | 179 +++++++++++++++++++++++++++++ > > 3 files changed, 183 insertions(+) > > create mode 100644 drivers/clk/loongson/Makefile > > create mode 100644 drivers/clk/loongson/clk-ls1c300.c > > > > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile > > index 5f0c0d8a5c2..e19bb17276e 100644 > > --- a/drivers/clk/Makefile > > +++ b/drivers/clk/Makefile > > @@ -23,6 +23,7 @@ obj-y += ti/ > > obj-$(CONFIG_CLK_THEAD) += thead/ > > obj-$(CONFIG_$(PHASE_)CLK_INTEL) += intel/ > > obj-$(CONFIG_ARCH_ASPEED) += aspeed/ > > +obj-$(CONFIG_ARCH_LSMIPS) += loongson/ > > obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ > > obj-$(CONFIG_ARCH_MESON) += meson/ > > obj-$(CONFIG_ARCH_MTMIPS) += mtmips/ > > diff --git a/drivers/clk/loongson/Makefile b/drivers/clk/loongson/Makefile > > new file mode 100644 > > index 00000000000..0a47269cd30 > > --- /dev/null > > +++ b/drivers/clk/loongson/Makefile > > @@ -0,0 +1,3 @@ > > +# SPDX-License-Identifier: GPL-2.0 > > + > > +obj-$(CONFIG_SOC_LS1C300) += clk-ls1c300.o > > diff --git a/drivers/clk/loongson/clk-ls1c300.c b/drivers/clk/loongson/clk-ls1c300.c > > new file mode 100644 > > index 00000000000..acca92cd657 > > --- /dev/null > > +++ b/drivers/clk/loongson/clk-ls1c300.c > > @@ -0,0 +1,179 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * reference: > > + * drivers/clk/microchip/mpfs_clk.c > > + * drivers/clk/clk_octeon.c > > + * > > + * Copyright (C) 2020-2026 Du Huanpeng <u74147@gmail.com> > > + */ > > + > > +#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> > > + > > +/* PLL/SDRAM Frequency Configuration Register */ > > +#define START_FREQ 0 > > +#define CLK_DIV_PARAM 4 > > + > > +/* 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}, > > +}; > > + > > +ulong ls1c300_pll_get_rate(struct clk *clk) > > +{ > > + unsigned int mult; > > + long long parent_rate; > > + void *base; > > + unsigned int val; > > + > > + parent_rate = clk_get_parent_rate(clk); > > + base = (void *)clk->data; > > + > > + val = readl(base + START_FREQ); > > + mult = FIELD_GET(FRAC_N, val) + FIELD_GET(M_PLL, val); > > + return (mult * parent_rate) / 4; > > +} > > + > > +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; > > +} > > + > > +static int ls1c300_clk_probe(struct udevice *dev) > > +{ > > + void __iomem *base; > > + void __iomem *cpu_throt; > > + void __iomem *addr; > > + > > + struct clk *cl, clk; > > + const char *parent_name; > > + int flags; > > + int ret; > > + > > + base = (void *)dev_remap_addr_index(dev, 0); > > + cpu_throt = (void *)dev_remap_addr_index(dev, 1); > > no casting required, return value is already "void __iomem *" fixed. > > > + > > + ret = clk_get_by_index(dev, 0, &clk); > > + if (ret) > > + return ret; > > + > > + ret = clk_get_rate(&clk); > > + > > + parent_name = clk.dev->name; > > + > > + cl = kzalloc(sizeof(*cl), GFP_KERNEL); > > + cl->data = (unsigned long)base; > > why not create a "struct ls1c300_clk_priv" which embeds stuff like "void > __iomem *base" and just use "struct ls1c300_clk_priv *priv = > dev_get_priv(dev);" to get a type-safe pointer to the auto-allocated memory? > The platform driver itself should not fiddle with "struct clk" and just > register "struct clk_ops". driver is updated here: https://lists.denx.de/pipermail/u-boot/2026-April/613978.html > > > + ret = clk_register(cl, "clk_ls1c300_pll", "pll", parent_name); > > + 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); > > + > > + cl = kzalloc(sizeof(*cl), GFP_KERNEL); > > + cl->data = (unsigned long)cpu_throt; > > + ret = clk_register(cl, "clk_cpu_throt", "cpu_throt_factor", "cpu_div"); > > + 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; > > + clk_dm(CLK_APB, cl); > > + > > + return 0; > > +} > > + > > +static ulong cpu_throt_get_rate(struct clk *clk) > > +{ > > + void __iomem *cpu_throt; > > + long long parent_rate; > > + ulong ret; > > + > > + parent_rate = clk_get_parent_rate(clk); > > + cpu_throt = (void *)clk->data; > > + > > + ret = readl(cpu_throt) + 1; > > + ret = parent_rate * ret / 16; > > + return ret; > > +} > > + > > +static const struct udevice_id ls1c300_clk_ids[] = { > > + { .compatible = "loongson,ls1c300-clk" }, > > + { } > > +}; > > + > > +static const struct clk_ops clk_cpu_throt_ops = { > > + .get_rate = cpu_throt_get_rate, > > +}; > > + > > +static const struct clk_ops clk_ls1c300_pll_ops = { > > + .get_rate = ls1c300_pll_get_rate, > > +}; > > + > > +static const struct clk_ops ls1c300_clk_ops = { > > + .get_rate = ls1c300_clk_get_rate, > > +}; > > + > > +U_BOOT_DRIVER(clk_ls1c300_cpu_throt) = { > > + .name = "clk_cpu_throt", > > + .id = UCLASS_CLK, > > + .ops = &clk_cpu_throt_ops, > > +}; > > + > > +U_BOOT_DRIVER(clk_ls1c300_pll) = { > > + .name = "clk_ls1c300_pll", > > + .id = UCLASS_CLK, > > + .ops = &clk_ls1c300_pll_ops, > > +}; > > + > > +U_BOOT_DRIVER(ls1c300_clk) = { > > + .name = "clk_ls1c300", > > + .id = UCLASS_CLK, > > + .of_match = ls1c300_clk_ids, > > + .probe = ls1c300_clk_probe, > > + .priv_auto = sizeof(struct clk), > > + .ops = &ls1c300_clk_ops, > > +}; > > -- > - Daniel > ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v6 0/7] add loongson mips ls1c300 initial support @ 2026-03-11 8:41 sgdfkk 2026-03-11 8:41 ` [PATCH v6 5/7] mips: loongson: add clk driver sgdfkk 0 siblings, 1 reply; 5+ messages in thread From: sgdfkk @ 2026-03-11 8:41 UTC (permalink / raw) To: duhuanpeng, u-boot; +Cc: chenhuacai, jiaxun.yang, Du Huanpeng From: Du Huanpeng <u74147@gmail.com> --- Changelog for v6: - rebase to 2026.3.10, version [ba7bf918dafcd093ad733b07ba490baeb20cf5da] - no more includes common.h - use <linux/time.h> MSEC_PER_SEC instead of self made - The board specific parts should be in the board MAINTAINER file - rename arch/mips/mach-lsmips/ to ...mach-loongson/ - rename functions names from lsmips_* to loongson_* - rename drivers/clk/lsmips/ to ...loongson/, rename clk driver name too - move TEXT_BASE, SPL_TEXT_BASE from mach-xxx/Kconfig to ls1c300_defconfig - rename hardware register name CONFIG_VALID to VALID (checkpatch error) - change dt bindings header license to gpl-2.0 OR MIT (checkpatch warning) - change dm-u-boot to bootph- in device tree - remove guards(#if/#endif) from include/configs/ls1c300.h - keep ARCH_LSMIPS macro, should I change it too ??? Changelog for v5: - add detail commit message - small fix in watchdog driver Changelog for v4: - rebase to [247aa5a191159ea7e03bf1918e22fbbb784cd410] - fix rebase issues - use spl without SPL_DM - fix some more codingstyle - fix some more typo - add comments about writing sdram controler - keep .noreoder and do not use delay slot Changelog for v3: - change cpu clock id from CLK_CPU to CLK_CPU_THROT - migrate all APB dev's clock id to CLK_APB - remove uarts' <reg-shift> property to use default value <0> - move /clocks/acc node to /soc/acc - call clk_request() before use a clk - make get_tbclk() return 1/2 clock of cpu - disable debug_uart by default - add ops for cpu_throt_factor clk - declare MSEC_PER_SEC for converting between sec and msec - return a error code when the wdt clock is out of range - minor format and codingstyle fixes - rebase to [9859465bfe838bc8264d45e1a1bed847bba74bad] Changelog for v2: 1. dtsi: add status disabled for uart0 ~ uart11 remove bootargs from chosen make serial0 alias for uart2 oscillator remove @0 unit-address change uart2 address to kuseg 2. cleanup Kconfig and update defconfig - make these options configurable, disabled by default: CMD_DM DM_ETH DM_GPIO DM_SPI DM_SPI_FLASH DM_RESET PINCONF PINCTRL PINMUX RESET_LSMIPS - make these options configurable, enabled by default: CLK DISPLAY_CPUINFO SYSRESET ROM_EXCEPTION_VECTORS - disabled: CONFIG_ENV_IS_IN_SPI_FLASH 3. fix codingstyle drivers/watchdog/lsmips-wdt.c - priv->base + offset - add comment for default clock value 4. remove address base definition header - remove arch/mips/mach-lsmips/ls1c300/ls1c300.h - clean up files uses this header 5. spl and debug uart - add comment for spl & debug uart pinmuxing - cleanup unused registers base header 6. dtsi - add "loongson,ls1c300-uart" to all uart node 7. board dts - add memory node to board dts, start at 0x80000000, size 64MB 8. Kconfig - make ROM_EXCEPTION_VECTORS user configureable - enable ROM_EXCEPTION_VECTORS in defconfig 9. - seperate sdram_init to sdram_init.S - add macro helpers to do sdram, pll lowlevel init 10. dtsi - move clock nodes to /clocks/xxx 11. - define CONFIG_SKIP_LOWLEVEL_INIT to 1 12. - remove option PINCTRL_LS1C300 from Kconfig 13. - dram_init, use get_ram_size() to detect ram size. 14. clk driver - create custom clock ops for PLL - remove debug code 15. - rebase to 59bffec43a657598b194b9eb30dc01eec06078c7 - remove CONFIG_SYS_MONITOR_BASE from include/configs/ Du Huanpeng (7): mips: loongson: minimal initial SoC support mips: loongson: lowlevel initialize mips: loongson: lowlevel debug serial mips: loongson: ls1c300 board support mips: loongson: add clk driver mips: loongson: add watchdog driver mips: loongson: ls1c300 dts and bindings MAINTAINERS | 9 + arch/mips/Kconfig | 11 ++ arch/mips/Makefile | 1 + arch/mips/dts/loongson32-ls1c300b.dtsi | 151 +++++++++++++++ arch/mips/dts/ls1c300-eval.dts | 30 +++ arch/mips/mach-loongson/Kconfig | 69 +++++++ arch/mips/mach-loongson/Makefile | 6 + arch/mips/mach-loongson/cpu.c | 19 ++ arch/mips/mach-loongson/include/mach/serial.h | 16 ++ arch/mips/mach-loongson/ls1c300/Makefile | 7 + arch/mips/mach-loongson/ls1c300/gpio.c | 66 +++++++ arch/mips/mach-loongson/ls1c300/init.c | 61 ++++++ .../mach-loongson/ls1c300/lowlevel_init.S | 134 +++++++++++++ arch/mips/mach-loongson/ls1c300/sdram.S | 95 ++++++++++ arch/mips/mach-loongson/ls1c300/serial.c | 104 ++++++++++ arch/mips/mach-loongson/spl.c | 46 +++++ board/loongson/ls1c300-eval/Kconfig | 12 ++ board/loongson/ls1c300-eval/MAINTAINERS | 7 + board/loongson/ls1c300-eval/Makefile | 3 + board/loongson/ls1c300-eval/board.c | 19 ++ configs/ls1c300_defconfig | 52 +++++ drivers/clk/Makefile | 1 + drivers/clk/loongson/Makefile | 3 + drivers/clk/loongson/clk-ls1c300.c | 179 ++++++++++++++++++ drivers/watchdog/Kconfig | 8 + drivers/watchdog/Makefile | 1 + drivers/watchdog/loongson_wdt.c | 127 +++++++++++++ include/configs/ls1c300.h | 36 ++++ include/dt-bindings/clock/ls1c300-clk.h | 18 ++ include/dt-bindings/reset/ls1c300-reset.h | 36 ++++ 30 files changed, 1327 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-loongson/Kconfig create mode 100644 arch/mips/mach-loongson/Makefile create mode 100644 arch/mips/mach-loongson/cpu.c create mode 100644 arch/mips/mach-loongson/include/mach/serial.h create mode 100644 arch/mips/mach-loongson/ls1c300/Makefile create mode 100644 arch/mips/mach-loongson/ls1c300/gpio.c create mode 100644 arch/mips/mach-loongson/ls1c300/init.c create mode 100644 arch/mips/mach-loongson/ls1c300/lowlevel_init.S create mode 100644 arch/mips/mach-loongson/ls1c300/sdram.S create mode 100644 arch/mips/mach-loongson/ls1c300/serial.c create mode 100644 arch/mips/mach-loongson/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/loongson/Makefile create mode 100644 drivers/clk/loongson/clk-ls1c300.c create mode 100644 drivers/watchdog/loongson_wdt.c create mode 100644 include/configs/ls1c300.h create mode 100644 include/dt-bindings/clock/ls1c300-clk.h create mode 100644 include/dt-bindings/reset/ls1c300-reset.h -- 2.43.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v6 5/7] mips: loongson: add clk driver 2026-03-11 8:41 [PATCH v6 0/7] add loongson mips ls1c300 initial support sgdfkk @ 2026-03-11 8:41 ` sgdfkk 0 siblings, 0 replies; 5+ messages in thread From: sgdfkk @ 2026-03-11 8:41 UTC (permalink / raw) To: duhuanpeng, u-boot; +Cc: chenhuacai, jiaxun.yang, Du Huanpeng From: Du Huanpeng <u74147@gmail.com> clk driver loongson mips for embedded SoC ls1c300 Signed-off-by: Du Huanpeng <u74147@gmail.com> --- drivers/clk/Makefile | 1 + drivers/clk/loongson/Makefile | 3 + drivers/clk/loongson/clk-ls1c300.c | 179 +++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 drivers/clk/loongson/Makefile create mode 100644 drivers/clk/loongson/clk-ls1c300.c diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5f0c0d8a5c2..e19bb17276e 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -23,6 +23,7 @@ obj-y += ti/ obj-$(CONFIG_CLK_THEAD) += thead/ obj-$(CONFIG_$(PHASE_)CLK_INTEL) += intel/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_ARCH_LSMIPS) += loongson/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_ARCH_MESON) += meson/ obj-$(CONFIG_ARCH_MTMIPS) += mtmips/ diff --git a/drivers/clk/loongson/Makefile b/drivers/clk/loongson/Makefile new file mode 100644 index 00000000000..0a47269cd30 --- /dev/null +++ b/drivers/clk/loongson/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SOC_LS1C300) += clk-ls1c300.o diff --git a/drivers/clk/loongson/clk-ls1c300.c b/drivers/clk/loongson/clk-ls1c300.c new file mode 100644 index 00000000000..acca92cd657 --- /dev/null +++ b/drivers/clk/loongson/clk-ls1c300.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * reference: + * drivers/clk/microchip/mpfs_clk.c + * drivers/clk/clk_octeon.c + * + * Copyright (C) 2020-2026 Du Huanpeng <u74147@gmail.com> + */ + +#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> + +/* PLL/SDRAM Frequency Configuration Register */ +#define START_FREQ 0 +#define CLK_DIV_PARAM 4 + +/* 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}, +}; + +ulong ls1c300_pll_get_rate(struct clk *clk) +{ + unsigned int mult; + long long parent_rate; + void *base; + unsigned int val; + + parent_rate = clk_get_parent_rate(clk); + base = (void *)clk->data; + + val = readl(base + START_FREQ); + mult = FIELD_GET(FRAC_N, val) + FIELD_GET(M_PLL, val); + return (mult * parent_rate) / 4; +} + +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; +} + +static int ls1c300_clk_probe(struct udevice *dev) +{ + void __iomem *base; + void __iomem *cpu_throt; + void __iomem *addr; + + struct clk *cl, clk; + const char *parent_name; + int flags; + int ret; + + base = (void *)dev_remap_addr_index(dev, 0); + cpu_throt = (void *)dev_remap_addr_index(dev, 1); + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_get_rate(&clk); + + parent_name = clk.dev->name; + + cl = kzalloc(sizeof(*cl), GFP_KERNEL); + cl->data = (unsigned long)base; + ret = clk_register(cl, "clk_ls1c300_pll", "pll", parent_name); + 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); + + cl = kzalloc(sizeof(*cl), GFP_KERNEL); + cl->data = (unsigned long)cpu_throt; + ret = clk_register(cl, "clk_cpu_throt", "cpu_throt_factor", "cpu_div"); + 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; + clk_dm(CLK_APB, cl); + + return 0; +} + +static ulong cpu_throt_get_rate(struct clk *clk) +{ + void __iomem *cpu_throt; + long long parent_rate; + ulong ret; + + parent_rate = clk_get_parent_rate(clk); + cpu_throt = (void *)clk->data; + + ret = readl(cpu_throt) + 1; + ret = parent_rate * ret / 16; + return ret; +} + +static const struct udevice_id ls1c300_clk_ids[] = { + { .compatible = "loongson,ls1c300-clk" }, + { } +}; + +static const struct clk_ops clk_cpu_throt_ops = { + .get_rate = cpu_throt_get_rate, +}; + +static const struct clk_ops clk_ls1c300_pll_ops = { + .get_rate = ls1c300_pll_get_rate, +}; + +static const struct clk_ops ls1c300_clk_ops = { + .get_rate = ls1c300_clk_get_rate, +}; + +U_BOOT_DRIVER(clk_ls1c300_cpu_throt) = { + .name = "clk_cpu_throt", + .id = UCLASS_CLK, + .ops = &clk_cpu_throt_ops, +}; + +U_BOOT_DRIVER(clk_ls1c300_pll) = { + .name = "clk_ls1c300_pll", + .id = UCLASS_CLK, + .ops = &clk_ls1c300_pll_ops, +}; + +U_BOOT_DRIVER(ls1c300_clk) = { + .name = "clk_ls1c300", + .id = UCLASS_CLK, + .of_match = ls1c300_clk_ids, + .probe = ls1c300_clk_probe, + .priv_auto = sizeof(struct clk), + .ops = &ls1c300_clk_ops, +}; -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-07 21:23 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260311052046.11265-1-sgdfkk@163.com>
2026-03-11 5:20 ` [PATCH v6 1/7] mips: loongson: minimal initial SoC support sgdfkk
2026-03-11 5:20 ` [PATCH v6 5/7] mips: loongson: add clk driver sgdfkk
2026-03-11 17:55 ` Daniel Schwierzeck
2026-04-07 15:41 ` duhuanpeng
2026-03-11 8:41 [PATCH v6 0/7] add loongson mips ls1c300 initial support sgdfkk
2026-03-11 8:41 ` [PATCH v6 5/7] mips: loongson: add clk driver sgdfkk
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox