clk: sophgo: Add SG2042 clock driver

Add a driver for the SOPHGO SG2042 clocks.

Signed-off-by: Chen Wang <unicorn_wang@outlook.com>
This commit is contained in:
Chen Wang
2023-11-24 14:15:16 +08:00
parent 5911423798
commit 48cf7e0138
6 changed files with 2063 additions and 0 deletions

View File

@@ -9,3 +9,31 @@ config CLK_SOPHGO_CV1800
The driver require a 25MHz Oscillator to function generate clock.
It includes PLLs, common clock function and some vendor clock for
IPs of CV18XX series SoC
config CLK_SOPHGO_SG2042_PLL
tristate "Sophgo SG2042 PLL clock support"
depends on ARCH_SOPHGO || COMPILE_TEST
help
This driver supports the PLL clock controller on the
Sophgo SG2042 SoC. This clock IP uses three oscillators with
frequency of 25 MHz as input, which are used for Main/Fixed
PLL, DDR PLL 0 and DDR PLL 1 respectively.
config CLK_SOPHGO_SG2042_CLKGEN
tristate "Sophgo SG2042 Clock Generator support"
depends on CLK_SOPHGO_SG2042_PLL
help
This driver supports the Clock Generator on the
Sophgo SG2042 SoC. This clock IP depends on SG2042 PLL clock
because it uses PLL clocks as input.
This driver provides clock function such as DIV/Mux/Gate.
config CLK_SOPHGO_SG2042_RPGATE
tristate "Sophgo SG2042 RP subsystem clock controller support"
depends on CLK_SOPHGO_SG2042_CLKGEN
help
This driver supports the RP((Riscv Processors)) subsystem clock
controller on the Sophgo SG2042 SoC.
This clock IP depends on SG2042 Clock Generator because it uses
clock from Clock Generator IP as input.
This driver provides Gate function for RP.

View File

@@ -5,3 +5,7 @@ clk-sophgo-cv1800-y += clk-cv1800.o
clk-sophgo-cv1800-y += clk-cv18xx-common.o
clk-sophgo-cv1800-y += clk-cv18xx-ip.o
clk-sophgo-cv1800-y += clk-cv18xx-pll.o
obj-$(CONFIG_CLK_SOPHGO_SG2042_CLKGEN) += clk-sg2042-clkgen.o
obj-$(CONFIG_CLK_SOPHGO_SG2042_PLL) += clk-sg2042-pll.o
obj-$(CONFIG_CLK_SOPHGO_SG2042_RPGATE) += clk-sg2042-rpgate.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,291 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Sophgo SG2042 RP clock Driver
*
* Copyright (C) 2024 Sophgo Technology Inc.
* Copyright (C) 2024 Chen Wang <unicorn_wang@outlook.com>
*/
#include <linux/array_size.h>
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/sophgo,sg2042-rpgate.h>
#include "clk-sg2042.h"
#define R_SYSGATE_BEGIN 0x0368
#define R_RP_RXU_CLK_ENABLE (0x0368 - R_SYSGATE_BEGIN)
#define R_MP0_STATUS_REG (0x0380 - R_SYSGATE_BEGIN)
#define R_MP0_CONTROL_REG (0x0384 - R_SYSGATE_BEGIN)
#define R_MP1_STATUS_REG (0x0388 - R_SYSGATE_BEGIN)
#define R_MP1_CONTROL_REG (0x038C - R_SYSGATE_BEGIN)
#define R_MP2_STATUS_REG (0x0390 - R_SYSGATE_BEGIN)
#define R_MP2_CONTROL_REG (0x0394 - R_SYSGATE_BEGIN)
#define R_MP3_STATUS_REG (0x0398 - R_SYSGATE_BEGIN)
#define R_MP3_CONTROL_REG (0x039C - R_SYSGATE_BEGIN)
#define R_MP4_STATUS_REG (0x03A0 - R_SYSGATE_BEGIN)
#define R_MP4_CONTROL_REG (0x03A4 - R_SYSGATE_BEGIN)
#define R_MP5_STATUS_REG (0x03A8 - R_SYSGATE_BEGIN)
#define R_MP5_CONTROL_REG (0x03AC - R_SYSGATE_BEGIN)
#define R_MP6_STATUS_REG (0x03B0 - R_SYSGATE_BEGIN)
#define R_MP6_CONTROL_REG (0x03B4 - R_SYSGATE_BEGIN)
#define R_MP7_STATUS_REG (0x03B8 - R_SYSGATE_BEGIN)
#define R_MP7_CONTROL_REG (0x03BC - R_SYSGATE_BEGIN)
#define R_MP8_STATUS_REG (0x03C0 - R_SYSGATE_BEGIN)
#define R_MP8_CONTROL_REG (0x03C4 - R_SYSGATE_BEGIN)
#define R_MP9_STATUS_REG (0x03C8 - R_SYSGATE_BEGIN)
#define R_MP9_CONTROL_REG (0x03CC - R_SYSGATE_BEGIN)
#define R_MP10_STATUS_REG (0x03D0 - R_SYSGATE_BEGIN)
#define R_MP10_CONTROL_REG (0x03D4 - R_SYSGATE_BEGIN)
#define R_MP11_STATUS_REG (0x03D8 - R_SYSGATE_BEGIN)
#define R_MP11_CONTROL_REG (0x03DC - R_SYSGATE_BEGIN)
#define R_MP12_STATUS_REG (0x03E0 - R_SYSGATE_BEGIN)
#define R_MP12_CONTROL_REG (0x03E4 - R_SYSGATE_BEGIN)
#define R_MP13_STATUS_REG (0x03E8 - R_SYSGATE_BEGIN)
#define R_MP13_CONTROL_REG (0x03EC - R_SYSGATE_BEGIN)
#define R_MP14_STATUS_REG (0x03F0 - R_SYSGATE_BEGIN)
#define R_MP14_CONTROL_REG (0x03F4 - R_SYSGATE_BEGIN)
#define R_MP15_STATUS_REG (0x03F8 - R_SYSGATE_BEGIN)
#define R_MP15_CONTROL_REG (0x03FC - R_SYSGATE_BEGIN)
/**
* struct sg2042_rpgate_clock - Gate clock for RP(riscv processors) subsystem
* @hw: clk_hw for initialization
* @id: used to map clk_onecell_data
* @offset_enable: offset of gate enable registers
* @bit_idx: which bit in the register controls gating of this clock
*/
struct sg2042_rpgate_clock {
struct clk_hw hw;
unsigned int id;
u32 offset_enable;
u8 bit_idx;
};
/*
* Clock initialization macro naming rules:
* FW: use CLK_HW_INIT_FW_NAME
*/
#define SG2042_GATE_FW(_id, _name, _parent, _flags, \
_r_enable, _bit_idx) { \
.hw.init = CLK_HW_INIT_FW_NAME( \
_name, \
_parent, \
NULL, \
_flags), \
.id = _id, \
.offset_enable = _r_enable, \
.bit_idx = _bit_idx, \
}
/*
* Gate clocks for RP subsystem (including the MP subsystem), which control
* registers are defined in SYS_CTRL.
*/
static const struct sg2042_rpgate_clock sg2042_gate_rp[] = {
/* downstream of clk_gate_rp_cpu_normal about rxu */
SG2042_GATE_FW(GATE_CLK_RXU0, "clk_gate_rxu0", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 0),
SG2042_GATE_FW(GATE_CLK_RXU1, "clk_gate_rxu1", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 1),
SG2042_GATE_FW(GATE_CLK_RXU2, "clk_gate_rxu2", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 2),
SG2042_GATE_FW(GATE_CLK_RXU3, "clk_gate_rxu3", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 3),
SG2042_GATE_FW(GATE_CLK_RXU4, "clk_gate_rxu4", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 4),
SG2042_GATE_FW(GATE_CLK_RXU5, "clk_gate_rxu5", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 5),
SG2042_GATE_FW(GATE_CLK_RXU6, "clk_gate_rxu6", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 6),
SG2042_GATE_FW(GATE_CLK_RXU7, "clk_gate_rxu7", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 7),
SG2042_GATE_FW(GATE_CLK_RXU8, "clk_gate_rxu8", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 8),
SG2042_GATE_FW(GATE_CLK_RXU9, "clk_gate_rxu9", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 9),
SG2042_GATE_FW(GATE_CLK_RXU10, "clk_gate_rxu10", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 10),
SG2042_GATE_FW(GATE_CLK_RXU11, "clk_gate_rxu11", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 11),
SG2042_GATE_FW(GATE_CLK_RXU12, "clk_gate_rxu12", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 12),
SG2042_GATE_FW(GATE_CLK_RXU13, "clk_gate_rxu13", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 13),
SG2042_GATE_FW(GATE_CLK_RXU14, "clk_gate_rxu14", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 14),
SG2042_GATE_FW(GATE_CLK_RXU15, "clk_gate_rxu15", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 15),
SG2042_GATE_FW(GATE_CLK_RXU16, "clk_gate_rxu16", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 16),
SG2042_GATE_FW(GATE_CLK_RXU17, "clk_gate_rxu17", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 17),
SG2042_GATE_FW(GATE_CLK_RXU18, "clk_gate_rxu18", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 18),
SG2042_GATE_FW(GATE_CLK_RXU19, "clk_gate_rxu19", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 19),
SG2042_GATE_FW(GATE_CLK_RXU20, "clk_gate_rxu20", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 20),
SG2042_GATE_FW(GATE_CLK_RXU21, "clk_gate_rxu21", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 21),
SG2042_GATE_FW(GATE_CLK_RXU22, "clk_gate_rxu22", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 22),
SG2042_GATE_FW(GATE_CLK_RXU23, "clk_gate_rxu23", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 23),
SG2042_GATE_FW(GATE_CLK_RXU24, "clk_gate_rxu24", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 24),
SG2042_GATE_FW(GATE_CLK_RXU25, "clk_gate_rxu25", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 25),
SG2042_GATE_FW(GATE_CLK_RXU26, "clk_gate_rxu26", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 26),
SG2042_GATE_FW(GATE_CLK_RXU27, "clk_gate_rxu27", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 27),
SG2042_GATE_FW(GATE_CLK_RXU28, "clk_gate_rxu28", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 28),
SG2042_GATE_FW(GATE_CLK_RXU29, "clk_gate_rxu29", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 29),
SG2042_GATE_FW(GATE_CLK_RXU30, "clk_gate_rxu30", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 30),
SG2042_GATE_FW(GATE_CLK_RXU31, "clk_gate_rxu31", "rpgate",
0, R_RP_RXU_CLK_ENABLE, 31),
/* downstream of clk_gate_rp_cpu_normal about mp */
SG2042_GATE_FW(GATE_CLK_MP0, "clk_gate_mp0", "rpgate",
CLK_IS_CRITICAL, R_MP0_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP1, "clk_gate_mp1", "rpgate",
CLK_IS_CRITICAL, R_MP1_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP2, "clk_gate_mp2", "rpgate",
CLK_IS_CRITICAL, R_MP2_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP3, "clk_gate_mp3", "rpgate",
CLK_IS_CRITICAL, R_MP3_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP4, "clk_gate_mp4", "rpgate",
CLK_IS_CRITICAL, R_MP4_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP5, "clk_gate_mp5", "rpgate",
CLK_IS_CRITICAL, R_MP5_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP6, "clk_gate_mp6", "rpgate",
CLK_IS_CRITICAL, R_MP6_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP7, "clk_gate_mp7", "rpgate",
CLK_IS_CRITICAL, R_MP7_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP8, "clk_gate_mp8", "rpgate",
CLK_IS_CRITICAL, R_MP8_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP9, "clk_gate_mp9", "rpgate",
CLK_IS_CRITICAL, R_MP9_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP10, "clk_gate_mp10", "rpgate",
CLK_IS_CRITICAL, R_MP10_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP11, "clk_gate_mp11", "rpgate",
CLK_IS_CRITICAL, R_MP11_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP12, "clk_gate_mp12", "rpgate",
CLK_IS_CRITICAL, R_MP12_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP13, "clk_gate_mp13", "rpgate",
CLK_IS_CRITICAL, R_MP13_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP14, "clk_gate_mp14", "rpgate",
CLK_IS_CRITICAL, R_MP14_CONTROL_REG, 0),
SG2042_GATE_FW(GATE_CLK_MP15, "clk_gate_mp15", "rpgate",
CLK_IS_CRITICAL, R_MP15_CONTROL_REG, 0),
};
static DEFINE_SPINLOCK(sg2042_clk_lock);
static int sg2042_clk_register_rpgates(struct device *dev,
struct sg2042_clk_data *clk_data,
const struct sg2042_rpgate_clock gate_clks[],
int num_gate_clks)
{
const struct sg2042_rpgate_clock *gate;
struct clk_hw *hw;
int i, ret = 0;
for (i = 0; i < num_gate_clks; i++) {
gate = &gate_clks[i];
hw = devm_clk_hw_register_gate_parent_data
(dev,
gate->hw.init->name,
gate->hw.init->parent_data,
gate->hw.init->flags,
clk_data->iobase + gate->offset_enable,
gate->bit_idx,
0,
&sg2042_clk_lock);
if (IS_ERR(hw)) {
pr_err("failed to register clock %s\n", gate->hw.init->name);
ret = PTR_ERR(hw);
break;
}
clk_data->onecell_data.hws[gate->id] = hw;
}
return ret;
}
static int sg2042_init_clkdata(struct platform_device *pdev,
int num_clks,
struct sg2042_clk_data **pp_clk_data)
{
struct sg2042_clk_data *clk_data;
clk_data = devm_kzalloc(&pdev->dev,
struct_size(clk_data, onecell_data.hws, num_clks),
GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
clk_data->iobase = devm_platform_ioremap_resource(pdev, 0);
if (WARN_ON(IS_ERR(clk_data->iobase)))
return PTR_ERR(clk_data->iobase);
clk_data->onecell_data.num = num_clks;
*pp_clk_data = clk_data;
return 0;
}
static int sg2042_rpgate_probe(struct platform_device *pdev)
{
struct sg2042_clk_data *clk_data = NULL;
int num_clks;
int ret;
num_clks = ARRAY_SIZE(sg2042_gate_rp);
ret = sg2042_init_clkdata(pdev, num_clks, &clk_data);
if (ret)
goto error_out;
ret = sg2042_clk_register_rpgates(&pdev->dev, clk_data, sg2042_gate_rp,
num_clks);
if (ret)
goto error_out;
return devm_of_clk_add_hw_provider(&pdev->dev,
of_clk_hw_onecell_get,
&clk_data->onecell_data);
error_out:
pr_err("%s failed error number %d\n", __func__, ret);
return ret;
}
static const struct of_device_id sg2042_rpgate_match[] = {
{ .compatible = "sophgo,sg2042-rpgate" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sg2042_rpgate_match);
static struct platform_driver sg2042_rpgate_driver = {
.probe = sg2042_rpgate_probe,
.driver = {
.name = "clk-sophgo-sg2042-rpgate",
.of_match_table = sg2042_rpgate_match,
.suppress_bind_attrs = true,
},
};
module_platform_driver(sg2042_rpgate_driver);
MODULE_AUTHOR("Chen Wang");
MODULE_DESCRIPTION("Sophgo SG2042 rp subsystem clock driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _CLK_SOPHGO_SG2042_H_
#define _CLK_SOPHGO_SG2042_H_
#include <linux/io.h>
#include <linux/clk-provider.h>
/**
* struct sg2042_clk_data - Common data of clock-controller
* @iobase: base address of clock-controller
* @onecell_data: used for adding providers.
*/
struct sg2042_clk_data {
void __iomem *iobase;
struct clk_hw_onecell_data onecell_data;
};
#endif /* _CLK_SOPHGO_SG2042_H_ */