root/drivers/clk/sophgo/clk-cv18xx-pll.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
 */

#ifndef _CLK_SOPHGO_CV1800_PLL_H_
#define _CLK_SOPHGO_CV1800_PLL_H_

#include "clk-cv18xx-common.h"

struct cv1800_clk_pll_limit {
        struct {
                u8 min;
                u8 max;
        } pre_div, div, post_div, ictrl, mode;
};

#define _CV1800_PLL_LIMIT(_min, _max)   \
        {                               \
                .min = _min,            \
                .max = _max,            \
        }                               \

#define for_each_pll_limit_range(_var, _restrict) \
        for (_var = (_restrict)->min; _var <= (_restrict)->max; _var++)

struct cv1800_clk_pll_synthesizer {
        struct cv1800_clk_regbit        en;
        struct cv1800_clk_regbit        clk_half;
        u32                             ctrl;
        u32                             set;
};

#define _PLL_PRE_DIV_SEL_FIELD          GENMASK(6, 0)
#define _PLL_POST_DIV_SEL_FIELD         GENMASK(14, 8)
#define _PLL_SEL_MODE_FIELD             GENMASK(16, 15)
#define _PLL_DIV_SEL_FIELD              GENMASK(23, 17)
#define _PLL_ICTRL_FIELD                GENMASK(26, 24)

#define _PLL_ALL_FIELD_MASK \
        (_PLL_PRE_DIV_SEL_FIELD | \
         _PLL_POST_DIV_SEL_FIELD | \
         _PLL_SEL_MODE_FIELD | \
         _PLL_DIV_SEL_FIELD | \
         _PLL_ICTRL_FIELD)

#define PLL_COPY_REG(_dest, _src) \
        (((_dest) & (~_PLL_ALL_FIELD_MASK)) | ((_src) & _PLL_ALL_FIELD_MASK))

#define PLL_GET_PRE_DIV_SEL(_reg) \
        FIELD_GET(_PLL_PRE_DIV_SEL_FIELD, (_reg))
#define PLL_GET_POST_DIV_SEL(_reg) \
        FIELD_GET(_PLL_POST_DIV_SEL_FIELD, (_reg))
#define PLL_GET_SEL_MODE(_reg) \
        FIELD_GET(_PLL_SEL_MODE_FIELD, (_reg))
#define PLL_GET_DIV_SEL(_reg) \
        FIELD_GET(_PLL_DIV_SEL_FIELD, (_reg))
#define PLL_GET_ICTRL(_reg) \
        FIELD_GET(_PLL_ICTRL_FIELD, (_reg))

#define PLL_SET_PRE_DIV_SEL(_reg, _val) \
        _CV1800_SET_FIELD((_reg), (_val), _PLL_PRE_DIV_SEL_FIELD)
#define PLL_SET_POST_DIV_SEL(_reg, _val) \
        _CV1800_SET_FIELD((_reg), (_val), _PLL_POST_DIV_SEL_FIELD)
#define PLL_SET_SEL_MODE(_reg, _val) \
        _CV1800_SET_FIELD((_reg), (_val), _PLL_SEL_MODE_FIELD)
#define PLL_SET_DIV_SEL(_reg, _val) \
        _CV1800_SET_FIELD((_reg), (_val), _PLL_DIV_SEL_FIELD)
#define PLL_SET_ICTRL(_reg, _val) \
        _CV1800_SET_FIELD((_reg), (_val), _PLL_ICTRL_FIELD)

struct cv1800_clk_pll {
        struct cv1800_clk_common                common;
        u32                                     pll_reg;
        struct cv1800_clk_regbit                pll_pwd;
        struct cv1800_clk_regbit                pll_status;
        const struct cv1800_clk_pll_limit       *pll_limit;
        struct cv1800_clk_pll_synthesizer       *pll_syn;
};

#define CV1800_INTEGRAL_PLL(_name, _parent, _pll_reg,                   \
                             _pll_pwd_reg, _pll_pwd_shift,              \
                             _pll_status_reg, _pll_status_shift,        \
                             _pll_limit, _flags)                        \
        struct cv1800_clk_pll _name = {                                 \
                .common         = CV1800_CLK_COMMON(#_name, _parent,    \
                                                    &cv1800_clk_ipll_ops,\
                                                    _flags),            \
                .pll_reg        = _pll_reg,                             \
                .pll_pwd        = CV1800_CLK_BIT(_pll_pwd_reg,          \
                                               _pll_pwd_shift),         \
                .pll_status     = CV1800_CLK_BIT(_pll_status_reg,       \
                                               _pll_status_shift),      \
                .pll_limit      = _pll_limit,                           \
                .pll_syn        = NULL,                                 \
        }

#define CV1800_FACTIONAL_PLL(_name, _parent, _pll_reg,                  \
                             _pll_pwd_reg, _pll_pwd_shift,              \
                             _pll_status_reg, _pll_status_shift,        \
                             _pll_limit, _pll_syn, _flags)              \
        struct cv1800_clk_pll _name = {                                 \
                .common         = CV1800_CLK_COMMON(#_name, _parent,    \
                                                    &cv1800_clk_fpll_ops,\
                                                    _flags),            \
                .pll_reg        = _pll_reg,                             \
                .pll_pwd        = CV1800_CLK_BIT(_pll_pwd_reg,          \
                                               _pll_pwd_shift),         \
                .pll_status     = CV1800_CLK_BIT(_pll_status_reg,       \
                                               _pll_status_shift),      \
                .pll_limit      = _pll_limit,                           \
                .pll_syn        = _pll_syn,                             \
        }

extern const struct clk_ops cv1800_clk_ipll_ops;
extern const struct clk_ops cv1800_clk_fpll_ops;

#endif // _CLK_SOPHGO_CV1800_PLL_H_