// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024 ASPEED Technology Inc.
* Author: Ryan Chen <ryan_chen@aspeedtech.com>
*/
#include <linux/auxiliary_bus.h>
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/units.h>
#include <dt-bindings/clock/aspeed,ast2700-scu.h>
/* SOC0 */
#define SCU0_HWSTRAP1 0x010
#define SCU0_CLK_STOP 0x240
#define SCU0_CLK_SEL1 0x280
#define SCU0_CLK_SEL2 0x284
#define GET_USB_REFCLK_DIV(x) ((GENMASK(23, 20) & (x)) >> 20)
#define UART_DIV13_EN BIT(30)
#define SCU0_HPLL_PARAM 0x300
#define SCU0_DPLL_PARAM 0x308
#define SCU0_MPLL_PARAM 0x310
#define SCU0_D0CLK_PARAM 0x320
#define SCU0_D1CLK_PARAM 0x330
#define SCU0_CRT0CLK_PARAM 0x340
#define SCU0_CRT1CLK_PARAM 0x350
#define SCU0_MPHYCLK_PARAM 0x360
/* SOC1 */
#define SCU1_REVISION_ID 0x0
#define REVISION_ID GENMASK(23, 16)
#define SCU1_CLK_STOP 0x240
#define SCU1_CLK_STOP2 0x260
#define SCU1_CLK_SEL1 0x280
#define SCU1_CLK_SEL2 0x284
#define SCU1_CLK_I3C_DIV_MASK GENMASK(25, 23)
#define SCU1_CLK_I3C_DIV(n) ((n) - 1)
#define UXCLK_MASK GENMASK(1, 0)
#define HUXCLK_MASK GENMASK(4, 3)
#define SCU1_HPLL_PARAM 0x300
#define SCU1_APLL_PARAM 0x310
#define SCU1_DPLL_PARAM 0x320
#define SCU1_UXCLK_CTRL 0x330
#define SCU1_HUXCLK_CTRL 0x334
#define SCU1_MAC12_CLK_DLY 0x390
#define SCU1_MAC12_CLK_DLY_100M 0x394
#define SCU1_MAC12_CLK_DLY_10M 0x398
enum ast2700_clk_type {
CLK_MUX,
CLK_PLL,
CLK_HPLL,
CLK_GATE,
CLK_MISC,
CLK_FIXED,
CLK_DIVIDER,
CLK_UART_PLL,
CLK_GATE_ASPEED,
CLK_FIXED_FACTOR,
CLK_FIXED_DISPLAY,
};
struct ast2700_clk_fixed_factor_data {
unsigned int mult;
unsigned int div;
int parent_id;
};
struct ast2700_clk_gate_data {
int parent_id;
u32 flags;
u32 reg;
u8 bit;
};
struct ast2700_clk_mux_data {
const struct clk_hw **parent_hws;
const unsigned int *parent_ids;
unsigned int num_parents;
u8 bit_shift;
u8 bit_width;
u32 reg;
};
struct ast2700_clk_div_data {
const struct clk_div_table *div_table;
unsigned int parent_id;
u8 bit_shift;
u8 bit_width;
u32 reg;
};
struct ast2700_clk_pll_data {
unsigned int parent_id;
u32 reg;
};
struct ast2700_clk_fixed_rate_data {
unsigned long fixed_rate;
};
struct ast2700_clk_display_fixed_data {
u32 reg;
};
struct ast2700_clk_info {
const char *name;
u32 id;
u32 reg;
u32 type;
union {
struct ast2700_clk_fixed_factor_data factor;
struct ast2700_clk_fixed_rate_data rate;
struct ast2700_clk_display_fixed_data display_rate;
struct ast2700_clk_gate_data gate;
struct ast2700_clk_div_data div;
struct ast2700_clk_pll_data pll;
struct ast2700_clk_mux_data mux;
} data;
};
struct ast2700_clk_data {
const struct ast2700_clk_info *clk_info;
unsigned int nr_clks;
const int scu;
};
struct ast2700_clk_ctrl {
const struct ast2700_clk_data *clk_data;
struct device *dev;
void __iomem *base;
spinlock_t lock; /* clk lock */
};
static const struct clk_div_table ast2700_rgmii_div_table[] = {
{ 0x0, 4 },
{ 0x1, 4 },
{ 0x2, 6 },
{ 0x3, 8 },
{ 0x4, 10 },
{ 0x5, 12 },
{ 0x6, 14 },
{ 0x7, 16 },
{ 0 }
};
static const struct clk_div_table ast2700_rmii_div_table[] = {
{ 0x0, 8 },
{ 0x1, 8 },
{ 0x2, 12 },
{ 0x3, 16 },
{ 0x4, 20 },
{ 0x5, 24 },
{ 0x6, 28 },
{ 0x7, 32 },
{ 0 }
};
static const struct clk_div_table ast2700_clk_div_table[] = {
{ 0x0, 2 },
{ 0x1, 2 },
{ 0x2, 3 },
{ 0x3, 4 },
{ 0x4, 5 },
{ 0x5, 6 },
{ 0x6, 7 },
{ 0x7, 8 },
{