292 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Sophgo SG2042 RP clock Driver4 *5 * Copyright (C) 2024 Sophgo Technology Inc.6 * Copyright (C) 2024 Chen Wang <unicorn_wang@outlook.com>7 */8 9#include <linux/array_size.h>10#include <linux/clk-provider.h>11#include <linux/platform_device.h>12 13#include <dt-bindings/clock/sophgo,sg2042-rpgate.h>14 15#include "clk-sg2042.h"16 17#define R_SYSGATE_BEGIN 0x036818#define R_RP_RXU_CLK_ENABLE (0x0368 - R_SYSGATE_BEGIN)19#define R_MP0_STATUS_REG (0x0380 - R_SYSGATE_BEGIN)20#define R_MP0_CONTROL_REG (0x0384 - R_SYSGATE_BEGIN)21#define R_MP1_STATUS_REG (0x0388 - R_SYSGATE_BEGIN)22#define R_MP1_CONTROL_REG (0x038C - R_SYSGATE_BEGIN)23#define R_MP2_STATUS_REG (0x0390 - R_SYSGATE_BEGIN)24#define R_MP2_CONTROL_REG (0x0394 - R_SYSGATE_BEGIN)25#define R_MP3_STATUS_REG (0x0398 - R_SYSGATE_BEGIN)26#define R_MP3_CONTROL_REG (0x039C - R_SYSGATE_BEGIN)27#define R_MP4_STATUS_REG (0x03A0 - R_SYSGATE_BEGIN)28#define R_MP4_CONTROL_REG (0x03A4 - R_SYSGATE_BEGIN)29#define R_MP5_STATUS_REG (0x03A8 - R_SYSGATE_BEGIN)30#define R_MP5_CONTROL_REG (0x03AC - R_SYSGATE_BEGIN)31#define R_MP6_STATUS_REG (0x03B0 - R_SYSGATE_BEGIN)32#define R_MP6_CONTROL_REG (0x03B4 - R_SYSGATE_BEGIN)33#define R_MP7_STATUS_REG (0x03B8 - R_SYSGATE_BEGIN)34#define R_MP7_CONTROL_REG (0x03BC - R_SYSGATE_BEGIN)35#define R_MP8_STATUS_REG (0x03C0 - R_SYSGATE_BEGIN)36#define R_MP8_CONTROL_REG (0x03C4 - R_SYSGATE_BEGIN)37#define R_MP9_STATUS_REG (0x03C8 - R_SYSGATE_BEGIN)38#define R_MP9_CONTROL_REG (0x03CC - R_SYSGATE_BEGIN)39#define R_MP10_STATUS_REG (0x03D0 - R_SYSGATE_BEGIN)40#define R_MP10_CONTROL_REG (0x03D4 - R_SYSGATE_BEGIN)41#define R_MP11_STATUS_REG (0x03D8 - R_SYSGATE_BEGIN)42#define R_MP11_CONTROL_REG (0x03DC - R_SYSGATE_BEGIN)43#define R_MP12_STATUS_REG (0x03E0 - R_SYSGATE_BEGIN)44#define R_MP12_CONTROL_REG (0x03E4 - R_SYSGATE_BEGIN)45#define R_MP13_STATUS_REG (0x03E8 - R_SYSGATE_BEGIN)46#define R_MP13_CONTROL_REG (0x03EC - R_SYSGATE_BEGIN)47#define R_MP14_STATUS_REG (0x03F0 - R_SYSGATE_BEGIN)48#define R_MP14_CONTROL_REG (0x03F4 - R_SYSGATE_BEGIN)49#define R_MP15_STATUS_REG (0x03F8 - R_SYSGATE_BEGIN)50#define R_MP15_CONTROL_REG (0x03FC - R_SYSGATE_BEGIN)51 52/**53 * struct sg2042_rpgate_clock - Gate clock for RP(riscv processors) subsystem54 * @hw: clk_hw for initialization55 * @id: used to map clk_onecell_data56 * @offset_enable: offset of gate enable registers57 * @bit_idx: which bit in the register controls gating of this clock58 */59struct sg2042_rpgate_clock {60 struct clk_hw hw;61 62 unsigned int id;63 64 u32 offset_enable;65 u8 bit_idx;66};67 68/*69 * Clock initialization macro naming rules:70 * FW: use CLK_HW_INIT_FW_NAME71 */72#define SG2042_GATE_FW(_id, _name, _parent, _flags, \73 _r_enable, _bit_idx) { \74 .hw.init = CLK_HW_INIT_FW_NAME( \75 _name, \76 _parent, \77 NULL, \78 _flags), \79 .id = _id, \80 .offset_enable = _r_enable, \81 .bit_idx = _bit_idx, \82 }83 84/*85 * Gate clocks for RP subsystem (including the MP subsystem), which control86 * registers are defined in SYS_CTRL.87 */88static const struct sg2042_rpgate_clock sg2042_gate_rp[] = {89 /* downstream of clk_gate_rp_cpu_normal about rxu */90 SG2042_GATE_FW(GATE_CLK_RXU0, "clk_gate_rxu0", "rpgate",91 0, R_RP_RXU_CLK_ENABLE, 0),92 SG2042_GATE_FW(GATE_CLK_RXU1, "clk_gate_rxu1", "rpgate",93 0, R_RP_RXU_CLK_ENABLE, 1),94 SG2042_GATE_FW(GATE_CLK_RXU2, "clk_gate_rxu2", "rpgate",95 0, R_RP_RXU_CLK_ENABLE, 2),96 SG2042_GATE_FW(GATE_CLK_RXU3, "clk_gate_rxu3", "rpgate",97 0, R_RP_RXU_CLK_ENABLE, 3),98 SG2042_GATE_FW(GATE_CLK_RXU4, "clk_gate_rxu4", "rpgate",99 0, R_RP_RXU_CLK_ENABLE, 4),100 SG2042_GATE_FW(GATE_CLK_RXU5, "clk_gate_rxu5", "rpgate",101 0, R_RP_RXU_CLK_ENABLE, 5),102 SG2042_GATE_FW(GATE_CLK_RXU6, "clk_gate_rxu6", "rpgate",103 0, R_RP_RXU_CLK_ENABLE, 6),104 SG2042_GATE_FW(GATE_CLK_RXU7, "clk_gate_rxu7", "rpgate",105 0, R_RP_RXU_CLK_ENABLE, 7),106 SG2042_GATE_FW(GATE_CLK_RXU8, "clk_gate_rxu8", "rpgate",107 0, R_RP_RXU_CLK_ENABLE, 8),108 SG2042_GATE_FW(GATE_CLK_RXU9, "clk_gate_rxu9", "rpgate",109 0, R_RP_RXU_CLK_ENABLE, 9),110 SG2042_GATE_FW(GATE_CLK_RXU10, "clk_gate_rxu10", "rpgate",111 0, R_RP_RXU_CLK_ENABLE, 10),112 SG2042_GATE_FW(GATE_CLK_RXU11, "clk_gate_rxu11", "rpgate",113 0, R_RP_RXU_CLK_ENABLE, 11),114 SG2042_GATE_FW(GATE_CLK_RXU12, "clk_gate_rxu12", "rpgate",115 0, R_RP_RXU_CLK_ENABLE, 12),116 SG2042_GATE_FW(GATE_CLK_RXU13, "clk_gate_rxu13", "rpgate",117 0, R_RP_RXU_CLK_ENABLE, 13),118 SG2042_GATE_FW(GATE_CLK_RXU14, "clk_gate_rxu14", "rpgate",119 0, R_RP_RXU_CLK_ENABLE, 14),120 SG2042_GATE_FW(GATE_CLK_RXU15, "clk_gate_rxu15", "rpgate",121 0, R_RP_RXU_CLK_ENABLE, 15),122 SG2042_GATE_FW(GATE_CLK_RXU16, "clk_gate_rxu16", "rpgate",123 0, R_RP_RXU_CLK_ENABLE, 16),124 SG2042_GATE_FW(GATE_CLK_RXU17, "clk_gate_rxu17", "rpgate",125 0, R_RP_RXU_CLK_ENABLE, 17),126 SG2042_GATE_FW(GATE_CLK_RXU18, "clk_gate_rxu18", "rpgate",127 0, R_RP_RXU_CLK_ENABLE, 18),128 SG2042_GATE_FW(GATE_CLK_RXU19, "clk_gate_rxu19", "rpgate",129 0, R_RP_RXU_CLK_ENABLE, 19),130 SG2042_GATE_FW(GATE_CLK_RXU20, "clk_gate_rxu20", "rpgate",131 0, R_RP_RXU_CLK_ENABLE, 20),132 SG2042_GATE_FW(GATE_CLK_RXU21, "clk_gate_rxu21", "rpgate",133 0, R_RP_RXU_CLK_ENABLE, 21),134 SG2042_GATE_FW(GATE_CLK_RXU22, "clk_gate_rxu22", "rpgate",135 0, R_RP_RXU_CLK_ENABLE, 22),136 SG2042_GATE_FW(GATE_CLK_RXU23, "clk_gate_rxu23", "rpgate",137 0, R_RP_RXU_CLK_ENABLE, 23),138 SG2042_GATE_FW(GATE_CLK_RXU24, "clk_gate_rxu24", "rpgate",139 0, R_RP_RXU_CLK_ENABLE, 24),140 SG2042_GATE_FW(GATE_CLK_RXU25, "clk_gate_rxu25", "rpgate",141 0, R_RP_RXU_CLK_ENABLE, 25),142 SG2042_GATE_FW(GATE_CLK_RXU26, "clk_gate_rxu26", "rpgate",143 0, R_RP_RXU_CLK_ENABLE, 26),144 SG2042_GATE_FW(GATE_CLK_RXU27, "clk_gate_rxu27", "rpgate",145 0, R_RP_RXU_CLK_ENABLE, 27),146 SG2042_GATE_FW(GATE_CLK_RXU28, "clk_gate_rxu28", "rpgate",147 0, R_RP_RXU_CLK_ENABLE, 28),148 SG2042_GATE_FW(GATE_CLK_RXU29, "clk_gate_rxu29", "rpgate",149 0, R_RP_RXU_CLK_ENABLE, 29),150 SG2042_GATE_FW(GATE_CLK_RXU30, "clk_gate_rxu30", "rpgate",151 0, R_RP_RXU_CLK_ENABLE, 30),152 SG2042_GATE_FW(GATE_CLK_RXU31, "clk_gate_rxu31", "rpgate",153 0, R_RP_RXU_CLK_ENABLE, 31),154 155 /* downstream of clk_gate_rp_cpu_normal about mp */156 SG2042_GATE_FW(GATE_CLK_MP0, "clk_gate_mp0", "rpgate",157 CLK_IS_CRITICAL, R_MP0_CONTROL_REG, 0),158 SG2042_GATE_FW(GATE_CLK_MP1, "clk_gate_mp1", "rpgate",159 CLK_IS_CRITICAL, R_MP1_CONTROL_REG, 0),160 SG2042_GATE_FW(GATE_CLK_MP2, "clk_gate_mp2", "rpgate",161 CLK_IS_CRITICAL, R_MP2_CONTROL_REG, 0),162 SG2042_GATE_FW(GATE_CLK_MP3, "clk_gate_mp3", "rpgate",163 CLK_IS_CRITICAL, R_MP3_CONTROL_REG, 0),164 SG2042_GATE_FW(GATE_CLK_MP4, "clk_gate_mp4", "rpgate",165 CLK_IS_CRITICAL, R_MP4_CONTROL_REG, 0),166 SG2042_GATE_FW(GATE_CLK_MP5, "clk_gate_mp5", "rpgate",167 CLK_IS_CRITICAL, R_MP5_CONTROL_REG, 0),168 SG2042_GATE_FW(GATE_CLK_MP6, "clk_gate_mp6", "rpgate",169 CLK_IS_CRITICAL, R_MP6_CONTROL_REG, 0),170 SG2042_GATE_FW(GATE_CLK_MP7, "clk_gate_mp7", "rpgate",171 CLK_IS_CRITICAL, R_MP7_CONTROL_REG, 0),172 SG2042_GATE_FW(GATE_CLK_MP8, "clk_gate_mp8", "rpgate",173 CLK_IS_CRITICAL, R_MP8_CONTROL_REG, 0),174 SG2042_GATE_FW(GATE_CLK_MP9, "clk_gate_mp9", "rpgate",175 CLK_IS_CRITICAL, R_MP9_CONTROL_REG, 0),176 SG2042_GATE_FW(GATE_CLK_MP10, "clk_gate_mp10", "rpgate",177 CLK_IS_CRITICAL, R_MP10_CONTROL_REG, 0),178 SG2042_GATE_FW(GATE_CLK_MP11, "clk_gate_mp11", "rpgate",179 CLK_IS_CRITICAL, R_MP11_CONTROL_REG, 0),180 SG2042_GATE_FW(GATE_CLK_MP12, "clk_gate_mp12", "rpgate",181 CLK_IS_CRITICAL, R_MP12_CONTROL_REG, 0),182 SG2042_GATE_FW(GATE_CLK_MP13, "clk_gate_mp13", "rpgate",183 CLK_IS_CRITICAL, R_MP13_CONTROL_REG, 0),184 SG2042_GATE_FW(GATE_CLK_MP14, "clk_gate_mp14", "rpgate",185 CLK_IS_CRITICAL, R_MP14_CONTROL_REG, 0),186 SG2042_GATE_FW(GATE_CLK_MP15, "clk_gate_mp15", "rpgate",187 CLK_IS_CRITICAL, R_MP15_CONTROL_REG, 0),188};189 190static DEFINE_SPINLOCK(sg2042_clk_lock);191 192static int sg2042_clk_register_rpgates(struct device *dev,193 struct sg2042_clk_data *clk_data,194 const struct sg2042_rpgate_clock gate_clks[],195 int num_gate_clks)196{197 const struct sg2042_rpgate_clock *gate;198 struct clk_hw *hw;199 int i, ret = 0;200 201 for (i = 0; i < num_gate_clks; i++) {202 gate = &gate_clks[i];203 hw = devm_clk_hw_register_gate_parent_data204 (dev,205 gate->hw.init->name,206 gate->hw.init->parent_data,207 gate->hw.init->flags,208 clk_data->iobase + gate->offset_enable,209 gate->bit_idx,210 0,211 &sg2042_clk_lock);212 if (IS_ERR(hw)) {213 pr_err("failed to register clock %s\n", gate->hw.init->name);214 ret = PTR_ERR(hw);215 break;216 }217 218 clk_data->onecell_data.hws[gate->id] = hw;219 }220 221 return ret;222}223 224static int sg2042_init_clkdata(struct platform_device *pdev,225 int num_clks,226 struct sg2042_clk_data **pp_clk_data)227{228 struct sg2042_clk_data *clk_data;229 230 clk_data = devm_kzalloc(&pdev->dev,231 struct_size(clk_data, onecell_data.hws, num_clks),232 GFP_KERNEL);233 if (!clk_data)234 return -ENOMEM;235 236 clk_data->iobase = devm_platform_ioremap_resource(pdev, 0);237 if (WARN_ON(IS_ERR(clk_data->iobase)))238 return PTR_ERR(clk_data->iobase);239 240 clk_data->onecell_data.num = num_clks;241 242 *pp_clk_data = clk_data;243 244 return 0;245}246 247static int sg2042_rpgate_probe(struct platform_device *pdev)248{249 struct sg2042_clk_data *clk_data = NULL;250 int num_clks;251 int ret;252 253 num_clks = ARRAY_SIZE(sg2042_gate_rp);254 255 ret = sg2042_init_clkdata(pdev, num_clks, &clk_data);256 if (ret)257 goto error_out;258 259 ret = sg2042_clk_register_rpgates(&pdev->dev, clk_data, sg2042_gate_rp,260 num_clks);261 if (ret)262 goto error_out;263 264 return devm_of_clk_add_hw_provider(&pdev->dev,265 of_clk_hw_onecell_get,266 &clk_data->onecell_data);267 268error_out:269 pr_err("%s failed error number %d\n", __func__, ret);270 return ret;271}272 273static const struct of_device_id sg2042_rpgate_match[] = {274 { .compatible = "sophgo,sg2042-rpgate" },275 { /* sentinel */ }276};277MODULE_DEVICE_TABLE(of, sg2042_rpgate_match);278 279static struct platform_driver sg2042_rpgate_driver = {280 .probe = sg2042_rpgate_probe,281 .driver = {282 .name = "clk-sophgo-sg2042-rpgate",283 .of_match_table = sg2042_rpgate_match,284 .suppress_bind_attrs = true,285 },286};287module_platform_driver(sg2042_rpgate_driver);288 289MODULE_AUTHOR("Chen Wang");290MODULE_DESCRIPTION("Sophgo SG2042 rp subsystem clock driver");291MODULE_LICENSE("GPL");292