* [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 an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.