// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
*/
#include <linux/module.h>
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include "clk-cv1800.h"
#include "clk-cv18xx-common.h"
#include "clk-cv18xx-ip.h"
#include "clk-cv18xx-pll.h"
struct cv1800_clk_ctrl;
struct cv1800_clk_desc {
struct clk_hw_onecell_data *clks_data;
int (*pre_init)(struct device *dev, void __iomem *base,
struct cv1800_clk_ctrl *ctrl,
const struct cv1800_clk_desc *desc);
};
struct cv1800_clk_ctrl {
const struct cv1800_clk_desc *desc;
spinlock_t lock;
};
#define CV1800_DIV_FLAG \
(CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST)
static const struct clk_parent_data osc_parents[] = {
{ .index = 0 },
};
static const struct cv1800_clk_pll_limit pll_limits[] = {
{
.pre_div = _CV1800_PLL_LIMIT(1, 127),
.div = _CV1800_PLL_LIMIT(6, 127),
.post_div = _CV1800_PLL_LIMIT(1, 127),
.ictrl = _CV1800_PLL_LIMIT(0, 7),
.mode = _CV1800_PLL_LIMIT(0, 3),
},
{
.pre_div = _CV1800_PLL_LIMIT(1, 127),
.div = _CV1800_PLL_LIMIT(6, 127),
.post_div = _CV1800_PLL_LIMIT(1, 127),
.ictrl = _CV1800_PLL_LIMIT(0, 7),
.mode = _CV1800_PLL_LIMIT(0, 3),
},
};
static CV1800_INTEGRAL_PLL(clk_fpll, osc_parents,
REG_FPLL_CSR,
REG_PLL_G6_CTRL, 8,
REG_PLL_G6_STATUS, 2,
pll_limits,
CLK_IS_CRITICAL);
static CV1800_INTEGRAL_PLL(clk_mipimpll, osc_parents,
REG_MIPIMPLL_CSR,
REG_PLL_G2_CTRL, 0,
REG_PLL_G2_STATUS, 0,
pll_limits,
CLK_IS_CRITICAL);
static const struct clk_parent_data clk_mipimpll_parents[] = {
{ .hw = &clk_mipimpll.common.hw },
};
static const struct clk_parent_data clk_bypass_mipimpll_parents[] = {
{ .index = 0 },
{ .hw = &clk_mipimpll.common.hw },
};
static const struct clk_parent_data clk_bypass_fpll_parents[] = {
{ .index = 0 },
{ .hw = &clk_fpll.common.hw },
};
static struct cv1800_clk_pll_synthesizer clk_mpll_synthesizer = {
.en = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 2),
.clk_half = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 0),
.ctrl = REG_MPLL_SSC_SYN_CTRL,
.set = REG_MPLL_SSC_SYN_SET,
};
static CV1800_FACTIONAL_PLL(clk_mpll, clk_bypass_mipimpll_parents,
REG_MPLL_CSR,
REG_PLL_G6_CTRL, 0,
REG_PLL_G6_STATUS, 0,
pll_limits,
&clk_mpll_synthesizer,
CLK_IS_CRITICAL);
static struct cv1800_clk_pll_synthesizer clk_tpll_synthesizer = {
.en = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 3),
.clk_half = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 0),
.ctrl = REG_TPLL_SSC_SYN_CTRL,
.set = REG_TPLL_SSC_SYN_SET,
};
static CV1800_FACTIONAL_PLL(clk_tpll, clk_bypass_mipimpll_parents,
REG_TPLL_CSR,
REG_PLL_G6_CTRL, 4,
REG_PLL_G6_STATUS, 1,
pll_limits,
&clk_tpll_synthesizer,
CLK_IS_CRITICAL);
static struct cv1800_clk_pll_synthesizer clk_a0pll_synthesizer = {
.en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 2),
.clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0),
.ctrl = REG_A0PLL_SSC_SYN_CTRL,
.set = REG_A0PLL_SSC_SYN_SET,
};
static CV1800_FACTIONAL_PLL(clk_a0pll, clk_bypass_mipimpll_parents,
REG_A0PLL_CSR,
REG_PLL_G2_CTRL, 4,
REG_PLL_G2_STATUS, 1,
pll_limits,
&clk_a0pll_synthesizer,
CLK_IS_CRITICAL);
static struct cv1800_clk_pll_synthesizer clk_disppll_synthesizer = {
.en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 3),
.clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0),
.ctrl = REG_DISPPLL_SSC_SYN_CTRL,
.set = REG_DISPPLL_SSC_SYN_SET,
};
static CV1800_FACTIONAL_PLL(clk_disppll, clk_bypass_mipimpll_parents,
REG_DISPPLL_CSR,
REG_PLL_G2_CTRL, 8,
REG_PLL_G2_STATUS, 2,
pll_limits,
&clk_disppll_synthesizer,
CLK_IS_CRITICAL);
static struct cv1800_clk_pll_synthesizer clk_cam0pll_synthesizer = {
.en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 4),
.clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0),
.ctrl = REG_CAM0PLL_SSC_SYN_CTRL,
.set = REG_CAM0PLL_SSC_SYN_SET,
};
static CV1800_FACTIONAL_PLL(clk_cam0pll, clk_bypass_mipimpll_parents,
REG_CAM0PLL_CSR,
REG_PLL_G2_CTRL, 12,
REG_PLL_G2_STATUS, 3,
pll_limits,
&clk_cam0pll_synthesizer,
CLK_IGNORE_UNUSED);
static struct cv1800_clk_pll_synthesizer clk_cam1pll_synthesizer = {
.en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 5),
.clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0),
.ctrl = REG_CAM1PLL_SSC_SYN_CTRL,
.set = REG_CAM1PLL_SSC_SYN_SET,
};
static CV1800_FACTIONAL_PLL(clk_cam1pll, clk_bypass_mipimpll_parents,
REG_CAM1PLL_CSR,
REG_PLL_G2_CTRL, 16,
REG_PLL_G2_STATUS, 4,
pll_limits,
&clk_cam1pll_synthesizer,
CLK_IS_CRITICAL);
static const struct clk_parent_data clk_cam0pll_parents[] = {
{ .hw = &clk_cam0pll.common.hw },
};
/* G2D */
static CV1800_FIXED_DIV(clk_cam0pll_d2, clk_cam0pll_parents,
REG_CAM0PLL_CLK_CSR, 1,
2,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
static CV1800_FIXED_DIV(clk_cam0pll_d3, clk_cam0pll_parents,
REG_CAM0PLL_CLK_CSR, 2,
3,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
static CV1800_FIXED_DIV(clk_mipimpll_d3, clk_mipimpll_parents,
REG_MIPIMPLL_CLK_CSR, 2,
3,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
/* TPU */
static const struct clk_parent_data clk_tpu_parents[] = {
{ .index = 0 },
{ .hw = &clk_tpll.common.hw },
{ .hw = &clk_a0pll.common.hw },
{ .hw = &clk_mipimpll.common.hw },
{ .hw = &clk_fpll.common.hw },
};
static CV1800_BYPASS_MUX(clk_tpu, clk_tpu_parents,
REG_CLK_EN_0, 4,
REG_DIV_CLK_TPU, 16, 4, 3, CV1800_DIV_FLAG,
REG_DIV_CLK_TPU, 8, 2,
REG_CLK_BYP_0, 3,
0);
static CV1800_GATE(clk_tpu_fab, clk_mipimpll_parents,
REG_CLK_EN_0, 5,
0);
/* FABRIC_AXI6 */
static CV1800_BYPASS_DIV(clk_axi6, clk_bypass_fpll_parents,
REG_CLK_EN_2, 2,
REG_DIV_CLK_AXI6, 16, 4, 15, CV1800_DIV_FLAG,
REG_CLK_BYP_0, 20,
CLK_IS_CRITICAL);
static const struct clk_parent_data clk_axi6_bus_parents[] = {
{ .hw = &clk_axi6.div.common.hw },
};
static const struct clk_parent_data clk_bypass_axi6_bus_parents[] = {
{ .index = 0 },
{ .hw = &clk_axi6.div.common.hw },
};
/* FABRIC_AXI4 */
static const struct clk_parent_data clk_axi4_parents[] = {
{ .index = 0 },
{ .hw = &clk_fpll.common.hw },
{ .hw = &clk_disppll.common.hw },
};
static CV1800_BYPASS_MUX(clk_axi4, clk_axi4_parents,
REG_CLK_EN_2, 1,
REG_DIV_CLK_AXI4, 16, 4, 5, CV1800_DIV_FLAG,
REG_DIV_CLK_AXI4, 8, 2,
REG_CLK_BYP_0, 19,
CLK_IS_CRITICAL);
static const struct clk_parent_data clk_axi4_bus_parents[] = {
{ .hw = &clk_axi4.mux.common.hw },
};
/* XTAL_MISC */
static CV1800_GATE(clk_xtal_misc, osc_parents,
REG_CLK_EN_0, 14,
CLK_IS_CRITICAL);
static const struct clk_parent_data clk_timer_parents[] = {
{ .hw = &clk_xtal_misc.common.hw },
};
/* TOP */
static const struct clk_parent_data clk_cam0_200_paren
|