summaryrefslogtreecommitdiff
path: root/bsp/spacemit/dm/clk/ccu_dpll.c
blob: 80cc0ba74060d19b60dae47e0546f01e1b12263f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-1       GuEe-GUI     first version
 */

#include "ccu_dpll.h"

#define DBG_TAG "clk.ccu.dpll"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#define DPLL_MIN_FREQ                   1700000000
#define DPLL_MAX_FREQ                   3400000000

#define pll_readl(reg)                  HWREG32(reg)
#define pll_readl_pll_swcr1(p)          pll_readl(p.base + p.reg_ctrl)
#define pll_readl_pll_swcr2(p)          pll_readl(p.base + p.reg_sel)

#define pll_writel(val, reg)            HWREG32(reg) = val
#define pll_writel_pll_swcr1(val, p)    pll_writel(val, p.base + p.reg_ctrl)
#define pll_writel_pll_swcr2(val, p)    pll_writel(val, p.base + p.reg_sel)

/* Unified dpllx_swcr1 for dpll1~2 */
union dpllx_swcr1
{
    struct
    {
        rt_uint32_t reg0:8;
        rt_uint32_t reg1:8;
        rt_uint32_t reg2:8;
        rt_uint32_t reg3:8;
    } b;
    rt_uint32_t v;
};

/* Unified dpllx_swcr2 for dpll1~2 */
union dpllx_swcr2
{
    struct
    {
        rt_uint32_t reg4:8;
        rt_uint32_t reg5:8;
        rt_uint32_t reg6:8;
        rt_uint32_t reg7:8;
    } b;
    rt_uint32_t v;
};

/* Frequency unit Mhz, return pll vco freq */
static rt_ubase_t __get_vco_freq_raw(struct rt_clk_cell *cell)
{
    rt_uint32_t reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7, size;
    union dpllx_swcr1 swcr1;
    union dpllx_swcr2 swcr2;
    struct ccu_dpll_rate_tbl *freq_pll_regs_table;
    struct ccu_dpll *p = cell_to_ccu_dpll(cell);

    swcr1.v = pll_readl_pll_swcr1(p->common);
    swcr2.v = pll_readl_pll_swcr2(p->common);

    reg0 = swcr1.b.reg0;
    reg1 = swcr1.b.reg1;
    reg2 = swcr1.b.reg2;
    reg3 = swcr1.b.reg3;
    reg4 = swcr2.b.reg4;
    reg5 = swcr2.b.reg5;
    reg6 = swcr2.b.reg6;
    reg7 = swcr2.b.reg7;

    freq_pll_regs_table = p->dpll.rate_tbl;
    size = p->dpll.tbl_size;

    for (int i = 0; i < size; ++i)
    {
        struct ccu_dpll_rate_tbl *item = &freq_pll_regs_table[i];

        if (item->reg0 == reg0 &&
            item->reg1 == reg1 &&
            item->reg2 == reg2 &&
            item->reg3 == reg3 &&
            item->reg4 == reg4 &&
            item->reg5 == reg5 &&
            item->reg6 == reg6 &&
            item->reg7 == reg7)
        {
            return item->rate;
        }
    }

    LOG_E("Unknown rate for clock %s", cell->name);

    return 0;
}

static rt_ubase_t ccu_dpll_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate)
{
    return __get_vco_freq_raw(cell);
}

static rt_base_t ccu_dpll_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *prate)
{
    rt_ubase_t max_rate = 0;
    struct ccu_dpll *p = cell_to_ccu_dpll(cell);
    struct ccu_dpll_config *params = &p->dpll;

    if (rate > DPLL_MAX_FREQ || rate < DPLL_MIN_FREQ)
    {
        LOG_E("%s %lu rate out of range", cell->name, rate);
        return -RT_EINVAL;
    }

    if (params->rate_tbl)
    {
        for (int i = 0; i < params->tbl_size; ++i)
        {
            struct ccu_dpll_rate_tbl *item = &params->rate_tbl[i];

            if (item->rate <= rate)
            {
                if (max_rate < item->rate)
                {
                    max_rate = item->rate;
                }
            }
        }
    }
    else
    {
        LOG_E("%s don't find freq table for pll", cell->name);
    }

    return max_rate;
}

const struct rt_clk_ops ccu_dpll_ops =
{
    .recalc_rate = ccu_dpll_recalc_rate,
    .round_rate = ccu_dpll_round_rate,
};