clk: exynos: Add Samsung clock framework

Heavily based on Linux kernel Samsung clock framework, with some changes
to accommodate the differences in U-Boot CCF implementation. It's also
quite minimal as compared to the Linux version.

Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
Reviewed-by: Chanho Park <chanho61.park@samsung.com>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
diff --git a/drivers/clk/exynos/clk.h b/drivers/clk/exynos/clk.h
new file mode 100644
index 0000000..91a51b8
--- /dev/null
+++ b/drivers/clk/exynos/clk.h
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Linaro Ltd.
+ * Sam Protsenko <semen.protsenko@linaro.org>
+ *
+ * Common Clock Framework support for all Samsung platforms.
+ */
+
+#ifndef __EXYNOS_CLK_H
+#define __EXYNOS_CLK_H
+
+#include <errno.h>
+#include <linux/clk-provider.h>
+#include "clk-pll.h"
+
+/**
+ * struct samsung_mux_clock - information about mux clock
+ * @id: platform specific id of the clock
+ * @name: name of this mux clock
+ * @parent_names: array of pointer to parent clock names
+ * @num_parents: number of parents listed in @parent_names
+ * @flags: optional flags for basic clock
+ * @offset: offset of the register for configuring the mux
+ * @shift: starting bit location of the mux control bit-field in @reg
+ * @width: width of the mux control bit-field in @reg
+ * @mux_flags: flags for mux-type clock
+ */
+struct samsung_mux_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		* const *parent_names;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			mux_flags;
+};
+
+#define PNAME(x) static const char * const x[]
+
+#define __MUX(_id, cname, pnames, o, s, w, f, mf)			\
+	{								\
+		.id		= _id,					\
+		.name		= cname,				\
+		.parent_names	= pnames,				\
+		.num_parents	= ARRAY_SIZE(pnames),			\
+		.flags		= (f) | CLK_SET_RATE_NO_REPARENT,	\
+		.offset		= o,					\
+		.shift		= s,					\
+		.width		= w,					\
+		.mux_flags	= mf,					\
+	}
+
+#define MUX(_id, cname, pnames, o, s, w)				\
+	__MUX(_id, cname, pnames, o, s, w, 0, 0)
+
+#define MUX_F(_id, cname, pnames, o, s, w, f, mf)			\
+	__MUX(_id, cname, pnames, o, s, w, f, mf)
+
+/**
+ * struct samsung_div_clock - information about div clock
+ * @id: platform specific id of the clock
+ * @name: name of this div clock
+ * @parent_name: name of the parent clock
+ * @flags: optional flags for basic clock
+ * @offset: offset of the register for configuring the div
+ * @shift: starting bit location of the div control bit-field in @reg
+ * @width: width of the bitfield
+ * @div_flags: flags for div-type clock
+ */
+struct samsung_div_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+};
+
+#define __DIV(_id, cname, pname, o, s, w, f, df)	\
+	{						\
+		.id		= _id,			\
+		.name		= cname,		\
+		.parent_name	= pname,		\
+		.flags		= f,			\
+		.offset		= o,			\
+		.shift		= s,			\
+		.width		= w,			\
+		.div_flags	= df,			\
+	}
+
+#define DIV(_id, cname, pname, o, s, w)			\
+	__DIV(_id, cname, pname, o, s, w, 0, 0)
+
+#define DIV_F(_id, cname, pname, o, s, w, f, df)	\
+	__DIV(_id, cname, pname, o, s, w, f, df)
+
+/**
+ * struct samsung_gate_clock - information about gate clock
+ * @id: platform specific id of the clock
+ * @name: name of this gate clock
+ * @parent_name: name of the parent clock
+ * @flags: optional flags for basic clock
+ * @offset: offset of the register for configuring the gate
+ * @bit_idx: bit index of the gate control bit-field in @reg
+ * @gate_flags: flags for gate-type clock
+ */
+struct samsung_gate_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			bit_idx;
+	u8			gate_flags;
+};
+
+#define __GATE(_id, cname, pname, o, b, f, gf)			\
+	{							\
+		.id		= _id,				\
+		.name		= cname,			\
+		.parent_name	= pname,			\
+		.flags		= f,				\
+		.offset		= o,				\
+		.bit_idx	= b,				\
+		.gate_flags	= gf,				\
+	}
+
+#define GATE(_id, cname, pname, o, b, f, gf)			\
+	__GATE(_id, cname, pname, o, b, f, gf)
+
+/**
+ * struct samsung_pll_clock - information about pll clock
+ * @id: platform specific id of the clock
+ * @name: name of this pll clock
+ * @parent_name: name of the parent clock
+ * @flags: optional flags for basic clock
+ * @con_offset: offset of the register for configuring the PLL
+ * @type: type of PLL to be registered
+ */
+struct samsung_pll_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	int			con_offset;
+	enum samsung_pll_type	type;
+};
+
+#define PLL(_typ, _id, _name, _pname, _con)		\
+	{						\
+		.id		= _id,			\
+		.name		= _name,		\
+		.parent_name	= _pname,		\
+		.flags		= CLK_GET_RATE_NOCACHE,	\
+		.con_offset	= _con,			\
+		.type		= _typ,			\
+	}
+
+enum samsung_clock_type {
+	S_CLK_MUX,
+	S_CLK_DIV,
+	S_CLK_GATE,
+	S_CLK_PLL,
+};
+
+/**
+ * struct samsung_clock_group - contains a list of clocks of one type
+ * @type: type of clocks this structure contains
+ * @clk_list: list of clocks
+ * @nr_clk: count of clocks in @clk_list
+ */
+struct samsung_clk_group {
+	enum samsung_clock_type type;
+	const void *clk_list;
+	unsigned int nr_clk;
+};
+
+void samsung_clk_register_mux(void __iomem *base,
+			      const struct samsung_mux_clock *clk_list,
+			      unsigned int nr_clk);
+void samsung_clk_register_div(void __iomem *base,
+			      const struct samsung_div_clock *clk_list,
+			      unsigned int nr_clk);
+void samsung_clk_register_gate(void __iomem *base,
+			       const struct samsung_gate_clock *clk_list,
+			       unsigned int nr_clk);
+void samsung_clk_register_pll(void __iomem *base,
+			      const struct samsung_pll_clock *clk_list,
+			      unsigned int nr_clk);
+
+void samsung_cmu_register_clocks(void __iomem *base,
+				 const struct samsung_clk_group *clk_groups,
+				 unsigned int nr_groups);
+int samsung_cmu_register_one(struct udevice *dev,
+			     const struct samsung_clk_group *clk_groups,
+			     unsigned int nr_groups);
+
+/**
+ * samsung_register_cmu - Register CMU clocks ensuring parent CMU is present
+ * @dev: CMU device
+ * @clk_groups: list of CMU clock groups
+ * @parent_drv: name of parent CMU driver
+ *
+ * Register provided CMU clocks, but make sure CMU_TOP driver is instantiated
+ * first.
+ *
+ * Return: 0 on success or negative value on error.
+ */
+#define samsung_register_cmu(dev, clk_groups, parent_drv)		\
+({									\
+	struct udevice *__parent;					\
+	int __ret;							\
+									\
+	__ret = uclass_get_device_by_driver(UCLASS_CLK,			\
+		DM_DRIVER_GET(parent_drv), &__parent);			\
+	if (__ret || !__parent)						\
+		__ret = -ENOENT;					\
+	else								\
+		__ret = samsung_cmu_register_one(dev, clk_groups,	\
+			ARRAY_SIZE(clk_groups));			\
+	__ret;								\
+})
+
+#endif /* __EXYNOS_CLK_H */