// SPDX-License-Identifier: GPL-2.0
/*
* MTMIPS SoCs Clock Driver
* Author: Sergio Paracuellos <sergio.paracuellos@gmail.com>
*/
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
/* Configuration registers */
#define SYSC_REG_SYSTEM_CONFIG 0x10
#define SYSC_REG_CLKCFG0 0x2c
#define SYSC_REG_RESET_CTRL 0x34
#define SYSC_REG_CPU_SYS_CLKCFG 0x3c
#define SYSC_REG_CPLL_CONFIG0 0x54
#define SYSC_REG_CPLL_CONFIG1 0x58
/* RT2880 SoC */
#define RT2880_CONFIG_CPUCLK_SHIFT 20
#define RT2880_CONFIG_CPUCLK_MASK 0x3
#define RT2880_CONFIG_CPUCLK_250 0x0
#define RT2880_CONFIG_CPUCLK_266 0x1
#define RT2880_CONFIG_CPUCLK_280 0x2
#define RT2880_CONFIG_CPUCLK_300 0x3
/* RT305X SoC */
#define RT305X_SYSCFG_CPUCLK_SHIFT 18
#define RT305X_SYSCFG_CPUCLK_MASK 0x1
#define RT305X_SYSCFG_CPUCLK_LOW 0x0
#define RT305X_SYSCFG_CPUCLK_HIGH 0x1
/* RT3352 SoC */
#define RT3352_SYSCFG0_CPUCLK_SHIFT 8
#define RT3352_SYSCFG0_CPUCLK_MASK 0x1
#define RT3352_SYSCFG0_CPUCLK_LOW 0x0
#define RT3352_SYSCFG0_CPUCLK_HIGH 0x1
/* RT3383 SoC */
#define RT3883_SYSCFG0_DRAM_TYPE_DDR2 BIT(17)
#define RT3883_SYSCFG0_CPUCLK_SHIFT 8
#define RT3883_SYSCFG0_CPUCLK_MASK 0x3
#define RT3883_SYSCFG0_CPUCLK_250 0x0
#define RT3883_SYSCFG0_CPUCLK_384 0x1
#define RT3883_SYSCFG0_CPUCLK_480 0x2
#define RT3883_SYSCFG0_CPUCLK_500 0x3
/* RT5350 SoC */
#define RT5350_CLKCFG0_XTAL_SEL BIT(20)
#define RT5350_SYSCFG0_CPUCLK_SHIFT 8
#define RT5350_SYSCFG0_CPUCLK_MASK 0x3
#define RT5350_SYSCFG0_CPUCLK_360 0x0
#define RT5350_SYSCFG0_CPUCLK_320 0x2
#define RT5350_SYSCFG0_CPUCLK_300 0x3
/* MT7620 and MT76x8 SoCs */
#define MT7620_XTAL_FREQ_SEL BIT(6)
#define CPLL_CFG0_SW_CFG BIT(31)
#define CPLL_CFG0_PLL_MULT_RATIO_SHIFT 16
#define CPLL_CFG0_PLL_MULT_RATIO_MASK 0x7
#define CPLL_CFG0_LC_CURFCK BIT(15)
#define CPLL_CFG0_BYPASS_REF_CLK BIT(14)
#define CPLL_CFG0_PLL_DIV_RATIO_SHIFT 10
#define CPLL_CFG0_PLL_DIV_RATIO_MASK 0x3
#define CPLL_CFG1_CPU_AUX1 BIT(25)
#define CPLL_CFG1_CPU_AUX0 BIT(24)
#define CLKCFG0_PERI_CLK_SEL BIT(4)
#define CPU_SYS_CLKCFG_OCP_RATIO_SHIFT 16
#define CPU_SYS_CLKCFG_OCP_RATIO_MASK 0xf
#define CPU_SYS_CLKCFG_OCP_RATIO_1 0 /* 1:1 (Reserved) */
#define CPU_SYS_CLKCFG_OCP_RATIO_1_5 1 /* 1:1.5 (Reserved) */
#define CPU_SYS_CLKCFG_OCP_RATIO_2 2 /* 1:2 */
#define CPU_SYS_CLKCFG_OCP_RATIO_2_5 3 /* 1:2.5 (Reserved) */
#define CPU_SYS_CLKCFG_OCP_RATIO_3 4 /* 1:3 */
#define CPU_SYS_CLKCFG_OCP_RATIO_3_5 5 /* 1:3.5 (Reserved) */
#define CPU_SYS_CLKCFG_OCP_RATIO_4 6 /* 1:4 */
#define CPU_SYS_CLKCFG_OCP_RATIO_5 7 /* 1:5 */
#define CPU_SYS_CLKCFG_OCP_RATIO_10 8 /* 1:10 */
#define CPU_SYS_CLKCFG_CPU_FDIV_SHIFT 8
#define CPU_SYS_CLKCFG_CPU_FDIV_MASK 0x1f
#define CPU_SYS_CLKCFG_CPU_FFRAC_SHIFT 0
#define CPU_SYS_CLKCFG_CPU_FFRAC_MASK 0x1f
/* clock scaling */
#define CLKCFG_FDIV_MASK 0x1f00
#define CLKCFG_FDIV_USB_VAL 0x0300
#define CLKCFG_FFRAC_MASK 0x001f
#define CLKCFG_FFRAC_USB_VAL 0x0003
struct mtmips_clk;
struct mtmips_clk_fixed;
struct mtmips_clk_factor;
struct mtmips_clk_data {
struct mtmips_clk *clk_base;
size_t num_clk_base;
struct mtmips_clk_fixed *clk_fixed;
size_t num_clk_fixed;
struct mtmips_clk_factor *clk_factor;
size_t num_clk_factor;
struct mtmips_clk *clk_periph;
size_t num_clk_periph;
};
struct mtmips_clk_priv {
struct regmap *sysc;
const struct mtmips_clk_data *data;
};
struct mtmips_clk {
struct clk_hw hw;
struct mtmips_clk_priv *priv;
};
struct mtmips_clk_fixed {
const char *name;
const char *parent;
unsigned long rate;
struct clk_hw *hw;
};
struct mtmips_clk_factor {
const char *name;
const char *parent;
int mult;
int div;
unsigned long flags;
struct clk_hw *hw;
};
static unsigned long mtmips_pherip_clk_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return parent_rate;
}
static const struct clk_ops mtmips_periph_clk_ops = {
.recalc_rate = mtmips_pherip_clk_rate,
};
#define CLK_PERIPH(_name, _parent) { \
.init = &(const struct clk_init_data) { \
.name = _name, \
.ops = &mtmips_periph_clk_ops, \
.parent_data = &(const struct clk_parent_data) {\
.name = _parent, \
.fw_name = _parent \
}, \
.num_parents = 1, \
/* \
* There are drivers for these SoCs that are \
* older than clock driver and are not prepared \
* for the clock. We don't want the kernel to \
* disable anything so we add CLK_IS_CRITICAL \
* flag here. \
*/ \
.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL \
}, \
}
static struct mtmips_clk rt2880_pherip_clks[] = {
{ CLK_PERIPH("300100.timer", "bus") },
{ CLK_PERIPH("300120.watchdog", "bus") },
{ CLK_PERIPH("300500.uart", "bus") },
{ CLK_PERIPH("300900.i2c", "bus") },
{ CLK_PERIPH("300c00.uartlite", "bus") },
{ CLK_PERIPH("400000.ethernet", "bus") },
{ CLK_PERIPH("480000.wmac", "xtal") }
};
static struct mtmips_clk rt305x_pherip_clks[] = {
{ CLK_PERIPH("10000100.timer", "bus") },
{ CLK_PERIPH("10000120.watchdog", "bus") },
{ CLK_PERIPH