Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
# SPDX-License-Identifier: GPL-2.0-only
config COMMON_CLK_HI3516CV300
tristate "HI3516CV300 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_HISI
default ARCH_HISI
help
Build the clock driver for hi3516cv300.
config COMMON_CLK_HI3519
tristate "Hi3519 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_HISI
default ARCH_HISI
help
Build the clock driver for hi3519.
config COMMON_CLK_HI3559A
bool "Hi3559A Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_HISI
default ARCH_HISI
help
Build the clock driver for hi3559a.
config COMMON_CLK_HI3660
bool "Hi3660 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
default ARCH_HISI
help
Build the clock driver for hi3660.
config COMMON_CLK_HI3670
bool "Hi3670 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
default ARCH_HISI
help
Build the clock driver for hi3670.
config COMMON_CLK_HI3798CV200
tristate "Hi3798CV200 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_HISI
default ARCH_HISI
help
Build the clock driver for hi3798cv200.
config COMMON_CLK_HI6220
bool "Hi6220 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
default ARCH_HISI
help
Build the Hisilicon Hi6220 clock driver based on the common clock framework.
config RESET_HISI
bool "HiSilicon Reset Controller Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_CONTROLLER
help
Build reset controller driver for HiSilicon device chipsets.
config STUB_CLK_HI6220
bool "Hi6220 Stub Clock Driver" if EXPERT
depends on (COMMON_CLK_HI6220 || COMPILE_TEST)
depends on MAILBOX
default COMMON_CLK_HI6220
help
Build the Hisilicon Hi6220 stub clock driver.
config STUB_CLK_HI3660
bool "Hi3660 Stub Clock Driver" if EXPERT
depends on (COMMON_CLK_HI3660 || COMPILE_TEST)
depends on MAILBOX
default COMMON_CLK_HI3660
help
Build the Hisilicon Hi3660 stub clock driver.
@@ -0,0 +1,20 @@
# SPDX-License-Identifier: GPL-2.0
#
# Hisilicon Clock specific Makefile
#
obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o clk-hisi-phase.o
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
obj-$(CONFIG_COMMON_CLK_HI3516CV300) += crg-hi3516cv300.o
obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o
obj-$(CONFIG_COMMON_CLK_HI3559A) += clk-hi3559a.o
obj-$(CONFIG_COMMON_CLK_HI3660) += clk-hi3660.o
obj-$(CONFIG_COMMON_CLK_HI3670) += clk-hi3670.o
obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o
obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
obj-$(CONFIG_RESET_HISI) += reset.o
obj-$(CONFIG_STUB_CLK_HI6220) += clk-hi6220-stub.o
obj-$(CONFIG_STUB_CLK_HI3660) += clk-hi3660-stub.o
@@ -0,0 +1,202 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hi3519 Clock Driver
*
* Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd.
*/
#include <dt-bindings/clock/hi3519-clock.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "clk.h"
#include "reset.h"
#define HI3519_INNER_CLK_OFFSET 64
#define HI3519_FIXED_24M 65
#define HI3519_FIXED_50M 66
#define HI3519_FIXED_75M 67
#define HI3519_FIXED_125M 68
#define HI3519_FIXED_150M 69
#define HI3519_FIXED_200M 70
#define HI3519_FIXED_250M 71
#define HI3519_FIXED_300M 72
#define HI3519_FIXED_400M 73
#define HI3519_FMC_MUX 74
#define HI3519_NR_CLKS 128
struct hi3519_crg_data {
struct hisi_clock_data *clk_data;
struct hisi_reset_controller *rstc;
};
static const struct hisi_fixed_rate_clock hi3519_fixed_rate_clks[] = {
{ HI3519_FIXED_24M, "24m", NULL, 0, 24000000, },
{ HI3519_FIXED_50M, "50m", NULL, 0, 50000000, },
{ HI3519_FIXED_75M, "75m", NULL, 0, 75000000, },
{ HI3519_FIXED_125M, "125m", NULL, 0, 125000000, },
{ HI3519_FIXED_150M, "150m", NULL, 0, 150000000, },
{ HI3519_FIXED_200M, "200m", NULL, 0, 200000000, },
{ HI3519_FIXED_250M, "250m", NULL, 0, 250000000, },
{ HI3519_FIXED_300M, "300m", NULL, 0, 300000000, },
{ HI3519_FIXED_400M, "400m", NULL, 0, 400000000, },
};
static const char *const fmc_mux_p[] = {
"24m", "75m", "125m", "150m", "200m", "250m", "300m", "400m", };
static u32 fmc_mux_table[] = {0, 1, 2, 3, 4, 5, 6, 7};
static const struct hisi_mux_clock hi3519_mux_clks[] = {
{ HI3519_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, },
};
static const struct hisi_gate_clock hi3519_gate_clks[] = {
{ HI3519_FMC_CLK, "clk_fmc", "fmc_mux",
CLK_SET_RATE_PARENT, 0xc0, 1, 0, },
{ HI3519_UART0_CLK, "clk_uart0", "24m",
CLK_SET_RATE_PARENT, 0xe4, 20, 0, },
{ HI3519_UART1_CLK, "clk_uart1", "24m",
CLK_SET_RATE_PARENT, 0xe4, 21, 0, },
{ HI3519_UART2_CLK, "clk_uart2", "24m",
CLK_SET_RATE_PARENT, 0xe4, 22, 0, },
{ HI3519_UART3_CLK, "clk_uart3", "24m",
CLK_SET_RATE_PARENT, 0xe4, 23, 0, },
{ HI3519_UART4_CLK, "clk_uart4", "24m",
CLK_SET_RATE_PARENT, 0xe4, 24, 0, },
{ HI3519_SPI0_CLK, "clk_spi0", "50m",
CLK_SET_RATE_PARENT, 0xe4, 16, 0, },
{ HI3519_SPI1_CLK, "clk_spi1", "50m",
CLK_SET_RATE_PARENT, 0xe4, 17, 0, },
{ HI3519_SPI2_CLK, "clk_spi2", "50m",
CLK_SET_RATE_PARENT, 0xe4, 18, 0, },
};
static struct hisi_clock_data *hi3519_clk_register(struct platform_device *pdev)
{
struct hisi_clock_data *clk_data;
int ret;
clk_data = hisi_clk_alloc(pdev, HI3519_NR_CLKS);
if (!clk_data)
return ERR_PTR(-ENOMEM);
ret = hisi_clk_register_fixed_rate(hi3519_fixed_rate_clks,
ARRAY_SIZE(hi3519_fixed_rate_clks),
clk_data);
if (ret)
return ERR_PTR(ret);
ret = hisi_clk_register_mux(hi3519_mux_clks,
ARRAY_SIZE(hi3519_mux_clks),
clk_data);
if (ret)
goto unregister_fixed_rate;
ret = hisi_clk_register_gate(hi3519_gate_clks,
ARRAY_SIZE(hi3519_gate_clks),
clk_data);
if (ret)
goto unregister_mux;
ret = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, &clk_data->clk_data);
if (ret)
goto unregister_gate;
return clk_data;
unregister_fixed_rate:
hisi_clk_unregister_fixed_rate(hi3519_fixed_rate_clks,
ARRAY_SIZE(hi3519_fixed_rate_clks),
clk_data);
unregister_mux:
hisi_clk_unregister_mux(hi3519_mux_clks,
ARRAY_SIZE(hi3519_mux_clks),
clk_data);
unregister_gate:
hisi_clk_unregister_gate(hi3519_gate_clks,
ARRAY_SIZE(hi3519_gate_clks),
clk_data);
return ERR_PTR(ret);
}
static void hi3519_clk_unregister(struct platform_device *pdev)
{
struct hi3519_crg_data *crg = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
hisi_clk_unregister_gate(hi3519_gate_clks,
ARRAY_SIZE(hi3519_gate_clks),
crg->clk_data);
hisi_clk_unregister_mux(hi3519_mux_clks,
ARRAY_SIZE(hi3519_mux_clks),
crg->clk_data);
hisi_clk_unregister_fixed_rate(hi3519_fixed_rate_clks,
ARRAY_SIZE(hi3519_fixed_rate_clks),
crg->clk_data);
}
static int hi3519_clk_probe(struct platform_device *pdev)
{
struct hi3519_crg_data *crg;
crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
if (!crg)
return -ENOMEM;
crg->rstc = hisi_reset_init(pdev);
if (!crg->rstc)
return -ENOMEM;
crg->clk_data = hi3519_clk_register(pdev);
if (IS_ERR(crg->clk_data)) {
hisi_reset_exit(crg->rstc);
return PTR_ERR(crg->clk_data);
}
platform_set_drvdata(pdev, crg);
return 0;
}
static void hi3519_clk_remove(struct platform_device *pdev)
{
struct hi3519_crg_data *crg = platform_get_drvdata(pdev);
hisi_reset_exit(crg->rstc);
hi3519_clk_unregister(pdev);
}
static const struct of_device_id hi3519_clk_match_table[] = {
{ .compatible = "hisilicon,hi3519-crg" },
{ }
};
MODULE_DEVICE_TABLE(of, hi3519_clk_match_table);
static struct platform_driver hi3519_clk_driver = {
.probe = hi3519_clk_probe,
.remove = hi3519_clk_remove,
.driver = {
.name = "hi3519-clk",
.of_match_table = hi3519_clk_match_table,
},
};
static int __init hi3519_clk_init(void)
{
return platform_driver_register(&hi3519_clk_driver);
}
core_initcall(hi3519_clk_init);
static void __exit hi3519_clk_exit(void)
{
platform_driver_unregister(&hi3519_clk_driver);
}
module_exit(hi3519_clk_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("HiSilicon Hi3519 Clock Driver");
@@ -0,0 +1,840 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon Hi3559A clock driver
*
* Copyright (c) 2019-2020, Huawei Tech. Co., Ltd.
*
* Author: Dongjiu Geng <gengdongjiu@huawei.com>
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <dt-bindings/clock/hi3559av100-clock.h>
#include "clk.h"
#include "crg.h"
#include "reset.h"
#define CRG_BASE_ADDR 0x18020000
#define PLL_MASK_WIDTH 24
struct hi3559av100_pll_clock {
u32 id;
const char *name;
const char *parent_name;
const u32 ctrl_reg1;
const u8 frac_shift;
const u8 frac_width;
const u8 postdiv1_shift;
const u8 postdiv1_width;
const u8 postdiv2_shift;
const u8 postdiv2_width;
const u32 ctrl_reg2;
const u8 fbdiv_shift;
const u8 fbdiv_width;
const u8 refdiv_shift;
const u8 refdiv_width;
};
struct hi3559av100_clk_pll {
struct clk_hw hw;
u32 id;
void __iomem *ctrl_reg1;
u8 frac_shift;
u8 frac_width;
u8 postdiv1_shift;
u8 postdiv1_width;
u8 postdiv2_shift;
u8 postdiv2_width;
void __iomem *ctrl_reg2;
u8 fbdiv_shift;
u8 fbdiv_width;
u8 refdiv_shift;
u8 refdiv_width;
};
/* soc clk config */
static const struct hisi_fixed_rate_clock hi3559av100_fixed_rate_clks_crg[] = {
{ HI3559AV100_FIXED_1188M, "1188m", NULL, 0, 1188000000, },
{ HI3559AV100_FIXED_1000M, "1000m", NULL, 0, 1000000000, },
{ HI3559AV100_FIXED_842M, "842m", NULL, 0, 842000000, },
{ HI3559AV100_FIXED_792M, "792m", NULL, 0, 792000000, },
{ HI3559AV100_FIXED_750M, "750m", NULL, 0, 750000000, },
{ HI3559AV100_FIXED_710M, "710m", NULL, 0, 710000000, },
{ HI3559AV100_FIXED_680M, "680m", NULL, 0, 680000000, },
{ HI3559AV100_FIXED_667M, "667m", NULL, 0, 667000000, },
{ HI3559AV100_FIXED_631M, "631m", NULL, 0, 631000000, },
{ HI3559AV100_FIXED_600M, "600m", NULL, 0, 600000000, },
{ HI3559AV100_FIXED_568M, "568m", NULL, 0, 568000000, },
{ HI3559AV100_FIXED_500M, "500m", NULL, 0, 500000000, },
{ HI3559AV100_FIXED_475M, "475m", NULL, 0, 475000000, },
{ HI3559AV100_FIXED_428M, "428m", NULL, 0, 428000000, },
{ HI3559AV100_FIXED_400M, "400m", NULL, 0, 400000000, },
{ HI3559AV100_FIXED_396M, "396m", NULL, 0, 396000000, },
{ HI3559AV100_FIXED_300M, "300m", NULL, 0, 300000000, },
{ HI3559AV100_FIXED_250M, "250m", NULL, 0, 250000000, },
{ HI3559AV100_FIXED_200M, "200m", NULL, 0, 200000000, },
{ HI3559AV100_FIXED_198M, "198m", NULL, 0, 198000000, },
{ HI3559AV100_FIXED_187p5M, "187p5m", NULL, 0, 187500000, },
{ HI3559AV100_FIXED_150M, "150m", NULL, 0, 150000000, },
{ HI3559AV100_FIXED_148p5M, "148p5m", NULL, 0, 1485000000, },
{ HI3559AV100_FIXED_125M, "125m", NULL, 0, 125000000, },
{ HI3559AV100_FIXED_107M, "107m", NULL, 0, 107000000, },
{ HI3559AV100_FIXED_100M, "100m", NULL, 0, 100000000, },
{ HI3559AV100_FIXED_99M, "99m", NULL, 0, 99000000, },
{ HI3559AV100_FIXED_75M, "75m", NULL, 0, 75000000, },
{ HI3559AV100_FIXED_74p25M, "74p25m", NULL, 0, 74250000, },
{ HI3559AV100_FIXED_72M, "72m", NULL, 0, 72000000, },
{ HI3559AV100_FIXED_60M, "60m", NULL, 0, 60000000, },
{ HI3559AV100_FIXED_54M, "54m", NULL, 0, 54000000, },
{ HI3559AV100_FIXED_50M, "50m", NULL, 0, 50000000, },
{ HI3559AV100_FIXED_49p5M, "49p5m", NULL, 0, 49500000, },
{ HI3559AV100_FIXED_37p125M, "37p125m", NULL, 0, 37125000, },
{ HI3559AV100_FIXED_36M, "36m", NULL, 0, 36000000, },
{ HI3559AV100_FIXED_32p4M, "32p4m", NULL, 0, 32400000, },
{ HI3559AV100_FIXED_27M, "27m", NULL, 0, 27000000, },
{ HI3559AV100_FIXED_25M, "25m", NULL, 0, 25000000, },
{ HI3559AV100_FIXED_24M, "24m", NULL, 0, 24000000, },
{ HI3559AV100_FIXED_12M, "12m", NULL, 0, 12000000, },
{ HI3559AV100_FIXED_3M, "3m", NULL, 0, 3000000, },
{ HI3559AV100_FIXED_1p6M, "1p6m", NULL, 0, 1600000, },
{ HI3559AV100_FIXED_400K, "400k", NULL, 0, 400000, },
{ HI3559AV100_FIXED_100K, "100k", NULL, 0, 100000, },
};
static const char *fmc_mux_p[] = {
"24m", "75m", "125m", "150m", "200m", "250m", "300m", "400m"
};
static const char *mmc_mux_p[] = {
"100k", "25m", "49p5m", "99m", "187p5m", "150m", "198m", "400k"
};
static const char *sysapb_mux_p[] = {
"24m", "50m",
};
static const char *sysbus_mux_p[] = {
"24m", "300m"
};
static const char *uart_mux_p[] = { "50m", "24m", "3m" };
static const char *a73_clksel_mux_p[] = {
"24m", "apll", "1000m"
};
static const u32 fmc_mux_table[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
static const u32 mmc_mux_table[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
static const u32 sysapb_mux_table[] = { 0, 1 };
static const u32 sysbus_mux_table[] = { 0, 1 };
static const u32 uart_mux_table[] = { 0, 1, 2 };
static const u32 a73_clksel_mux_table[] = { 0, 1, 2 };
static struct hisi_mux_clock hi3559av100_mux_clks_crg[] = {
{
HI3559AV100_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
CLK_SET_RATE_PARENT, 0x170, 2, 3, 0, fmc_mux_table,
},
{
HI3559AV100_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
CLK_SET_RATE_PARENT, 0x1a8, 24, 3, 0, mmc_mux_table,
},
{
HI3559AV100_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
CLK_SET_RATE_PARENT, 0x1ec, 24, 3, 0, mmc_mux_table,
},
{
HI3559AV100_MMC2_MUX, "mmc2_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
CLK_SET_RATE_PARENT, 0x214, 24, 3, 0, mmc_mux_table,
},
{
HI3559AV100_MMC3_MUX, "mmc3_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
CLK_SET_RATE_PARENT, 0x23c, 24, 3, 0, mmc_mux_table,
},
{
HI3559AV100_SYSAPB_MUX, "sysapb_mux", sysapb_mux_p, ARRAY_SIZE(sysapb_mux_p),
CLK_SET_RATE_PARENT, 0xe8, 3, 1, 0, sysapb_mux_table
},
{
HI3559AV100_SYSBUS_MUX, "sysbus_mux", sysbus_mux_p, ARRAY_SIZE(sysbus_mux_p),
CLK_SET_RATE_PARENT, 0xe8, 0, 1, 0, sysbus_mux_table
},
{
HI3559AV100_UART_MUX, "uart_mux", uart_mux_p, ARRAY_SIZE(uart_mux_p),
CLK_SET_RATE_PARENT, 0x198, 28, 2, 0, uart_mux_table
},
{
HI3559AV100_A73_MUX, "a73_mux", a73_clksel_mux_p, ARRAY_SIZE(a73_clksel_mux_p),
CLK_SET_RATE_PARENT, 0xe4, 0, 2, 0, a73_clksel_mux_table
},
};
static struct hisi_gate_clock hi3559av100_gate_clks[] = {
{
HI3559AV100_FMC_CLK, "clk_fmc", "fmc_mux",
CLK_SET_RATE_PARENT, 0x170, 1, 0,
},
{
HI3559AV100_MMC0_CLK, "clk_mmc0", "mmc0_mux",
CLK_SET_RATE_PARENT, 0x1a8, 28, 0,
},
{
HI3559AV100_MMC1_CLK, "clk_mmc1", "mmc1_mux",
CLK_SET_RATE_PARENT, 0x1ec, 28, 0,
},
{
HI3559AV100_MMC2_CLK, "clk_mmc2", "mmc2_mux",
CLK_SET_RATE_PARENT, 0x214, 28, 0,
},
{
HI3559AV100_MMC3_CLK, "clk_mmc3", "mmc3_mux",
CLK_SET_RATE_PARENT, 0x23c, 28, 0,
},
{
HI3559AV100_UART0_CLK, "clk_uart0", "uart_mux",
CLK_SET_RATE_PARENT, 0x198, 23, 0,
},
{
HI3559AV100_UART1_CLK, "clk_uart1", "uart_mux",
CLK_SET_RATE_PARENT, 0x198, 24, 0,
},
{
HI3559AV100_UART2_CLK, "clk_uart2", "uart_mux",
CLK_SET_RATE_PARENT, 0x198, 25, 0,
},
{
HI3559AV100_UART3_CLK, "clk_uart3", "uart_mux",
CLK_SET_RATE_PARENT, 0x198, 26, 0,
},
{
HI3559AV100_UART4_CLK, "clk_uart4", "uart_mux",
CLK_SET_RATE_PARENT, 0x198, 27, 0,
},
{
HI3559AV100_ETH_CLK, "clk_eth", NULL,
CLK_SET_RATE_PARENT, 0x0174, 1, 0,
},
{
HI3559AV100_ETH_MACIF_CLK, "clk_eth_macif", NULL,
CLK_SET_RATE_PARENT, 0x0174, 5, 0,
},
{
HI3559AV100_ETH1_CLK, "clk_eth1", NULL,
CLK_SET_RATE_PARENT, 0x0174, 3, 0,
},
{
HI3559AV100_ETH1_MACIF_CLK, "clk_eth1_macif", NULL,
CLK_SET_RATE_PARENT, 0x0174, 7, 0,
},
{
HI3559AV100_I2C0_CLK, "clk_i2c0", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 16, 0,
},
{
HI3559AV100_I2C1_CLK, "clk_i2c1", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 17, 0,
},
{
HI3559AV100_I2C2_CLK, "clk_i2c2", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 18, 0,
},
{
HI3559AV100_I2C3_CLK, "clk_i2c3", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 19, 0,
},
{
HI3559AV100_I2C4_CLK, "clk_i2c4", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 20, 0,
},
{
HI3559AV100_I2C5_CLK, "clk_i2c5", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 21, 0,
},
{
HI3559AV100_I2C6_CLK, "clk_i2c6", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 22, 0,
},
{
HI3559AV100_I2C7_CLK, "clk_i2c7", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 23, 0,
},
{
HI3559AV100_I2C8_CLK, "clk_i2c8", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 24, 0,
},
{
HI3559AV100_I2C9_CLK, "clk_i2c9", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 25, 0,
},
{
HI3559AV100_I2C10_CLK, "clk_i2c10", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 26, 0,
},
{
HI3559AV100_I2C11_CLK, "clk_i2c11", "50m",
CLK_SET_RATE_PARENT, 0x01a0, 27, 0,
},
{
HI3559AV100_SPI0_CLK, "clk_spi0", "100m",
CLK_SET_RATE_PARENT, 0x0198, 16, 0,
},
{
HI3559AV100_SPI1_CLK, "clk_spi1", "100m",
CLK_SET_RATE_PARENT, 0x0198, 17, 0,
},
{
HI3559AV100_SPI2_CLK, "clk_spi2", "100m",
CLK_SET_RATE_PARENT, 0x0198, 18, 0,
},
{
HI3559AV100_SPI3_CLK, "clk_spi3", "100m",
CLK_SET_RATE_PARENT, 0x0198, 19, 0,
},
{
HI3559AV100_SPI4_CLK, "clk_spi4", "100m",
CLK_SET_RATE_PARENT, 0x0198, 20, 0,
},
{
HI3559AV100_SPI5_CLK, "clk_spi5", "100m",
CLK_SET_RATE_PARENT, 0x0198, 21, 0,
},
{
HI3559AV100_SPI6_CLK, "clk_spi6", "100m",
CLK_SET_RATE_PARENT, 0x0198, 22, 0,
},
{
HI3559AV100_EDMAC_AXICLK, "axi_clk_edmac", NULL,
CLK_SET_RATE_PARENT, 0x16c, 6, 0,
},
{
HI3559AV100_EDMAC_CLK, "clk_edmac", NULL,
CLK_SET_RATE_PARENT, 0x16c, 5, 0,
},
{
HI3559AV100_EDMAC1_AXICLK, "axi_clk_edmac1", NULL,
CLK_SET_RATE_PARENT, 0x16c, 9, 0,
},
{
HI3559AV100_EDMAC1_CLK, "clk_edmac1", NULL,
CLK_SET_RATE_PARENT, 0x16c, 8, 0,
},
{
HI3559AV100_VDMAC_CLK, "clk_vdmac", NULL,
CLK_SET_RATE_PARENT, 0x14c, 5, 0,
},
};
static struct hi3559av100_pll_clock hi3559av100_pll_clks[] = {
{
HI3559AV100_APLL_CLK, "apll", NULL, 0x0, 0, 24, 24, 3, 28, 3,
0x4, 0, 12, 12, 6
},
{
HI3559AV100_GPLL_CLK, "gpll", NULL, 0x20, 0, 24, 24, 3, 28, 3,
0x24, 0, 12, 12, 6
},
};
#define to_pll_clk(_hw) container_of(_hw, struct hi3559av100_clk_pll, hw)
static void hi3559av100_calc_pll(u32 *frac_val, u32 *postdiv1_val,
u32 *postdiv2_val,
u32 *fbdiv_val, u32 *refdiv_val, u64 rate)
{
u64 rem;
*postdiv1_val = 2;
*postdiv2_val = 1;
rate = rate * ((*postdiv1_val) * (*postdiv2_val));
*frac_val = 0;
rem = do_div(rate, 1000000);
rem = do_div(rate, PLL_MASK_WIDTH);
*fbdiv_val = rate;
*refdiv_val = 1;
rem = rem * (1 << PLL_MASK_WIDTH);
do_div(rem, PLL_MASK_WIDTH);
*frac_val = rem;
}
static int clk_pll_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct hi3559av100_clk_pll *clk = to_pll_clk(hw);
u32 frac_val, postdiv1_val, postdiv2_val, fbdiv_val, refdiv_val;
u32 val;
postdiv1_val = postdiv2_val = 0;
hi3559av100_calc_pll(&frac_val, &postdiv1_val, &postdiv2_val,
&fbdiv_val, &refdiv_val, (u64)rate);
val = readl_relaxed(clk->ctrl_reg1);
val &= ~(((1 << clk->frac_width) - 1) << clk->frac_shift);
val &= ~(((1 << clk->postdiv1_width) - 1) << clk->postdiv1_shift);
val &= ~(((1 << clk->postdiv2_width) - 1) << clk->postdiv2_shift);
val |= frac_val << clk->frac_shift;
val |= postdiv1_val << clk->postdiv1_shift;
val |= postdiv2_val << clk->postdiv2_shift;
writel_relaxed(val, clk->ctrl_reg1);
val = readl_relaxed(clk->ctrl_reg2);
val &= ~(((1 << clk->fbdiv_width) - 1) << clk->fbdiv_shift);
val &= ~(((1 << clk->refdiv_width) - 1) << clk->refdiv_shift);
val |= fbdiv_val << clk->fbdiv_shift;
val |= refdiv_val << clk->refdiv_shift;
writel_relaxed(val, clk->ctrl_reg2);
return 0;
}
static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct hi3559av100_clk_pll *clk = to_pll_clk(hw);
u64 frac_val, fbdiv_val;
u32 postdiv1_val, postdiv2_val;
u32 val;
u64 tmp, rate;
val = readl_relaxed(clk->ctrl_reg1);
val = val >> clk->frac_shift;
val &= ((1 << clk->frac_width) - 1);
frac_val = val;
val = readl_relaxed(clk->ctrl_reg1);
val = val >> clk->postdiv1_shift;
val &= ((1 << clk->postdiv1_width) - 1);
postdiv1_val = val;
val = readl_relaxed(clk->ctrl_reg1);
val = val >> clk->postdiv2_shift;
val &= ((1 << clk->postdiv2_width) - 1);
postdiv2_val = val;
val = readl_relaxed(clk->ctrl_reg2);
val = val >> clk->fbdiv_shift;
val &= ((1 << clk->fbdiv_width) - 1);
fbdiv_val = val;
val = readl_relaxed(clk->ctrl_reg2);
val = val >> clk->refdiv_shift;
val &= ((1 << clk->refdiv_width) - 1);
/* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv */
rate = 0;
tmp = 24000000 * fbdiv_val + (24000000 * frac_val) / (1 << 24);
rate += tmp;
rate = div_u64(rate, val);
rate = div_u64(rate, postdiv1_val * postdiv2_val);
return rate;
}
static const struct clk_ops hisi_clk_pll_ops = {
.set_rate = clk_pll_set_rate,
.recalc_rate = clk_pll_recalc_rate,
};
static void hisi_clk_register_pll(struct hi3559av100_pll_clock *clks,
int nums, struct hisi_clock_data *data, struct device *dev)
{
void __iomem *base = data->base;
struct hi3559av100_clk_pll *p_clk = NULL;
struct clk *clk = NULL;
struct clk_init_data init;
int i;
p_clk = devm_kcalloc(dev, nums, sizeof(*p_clk), GFP_KERNEL);
if (!p_clk)
return;
for (i = 0; i < nums; i++) {
init.name = clks[i].name;
init.flags = 0;
init.parent_names =
(clks[i].parent_name ? &clks[i].parent_name : NULL);
init.num_parents = (clks[i].parent_name ? 1 : 0);
init.ops = &hisi_clk_pll_ops;
p_clk->ctrl_reg1 = base + clks[i].ctrl_reg1;
p_clk->frac_shift = clks[i].frac_shift;
p_clk->frac_width = clks[i].frac_width;
p_clk->postdiv1_shift = clks[i].postdiv1_shift;
p_clk->postdiv1_width = clks[i].postdiv1_width;
p_clk->postdiv2_shift = clks[i].postdiv2_shift;
p_clk->postdiv2_width = clks[i].postdiv2_width;
p_clk->ctrl_reg2 = base + clks[i].ctrl_reg2;
p_clk->fbdiv_shift = clks[i].fbdiv_shift;
p_clk->fbdiv_width = clks[i].fbdiv_width;
p_clk->refdiv_shift = clks[i].refdiv_shift;
p_clk->refdiv_width = clks[i].refdiv_width;
p_clk->hw.init = &init;
clk = clk_register(NULL, &p_clk->hw);
if (IS_ERR(clk)) {
dev_err(dev, "%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
data->clk_data.clks[clks[i].id] = clk;
p_clk++;
}
}
static struct hisi_clock_data *hi3559av100_clk_register(
struct platform_device *pdev)
{
struct hisi_clock_data *clk_data;
int ret;
clk_data = hisi_clk_alloc(pdev, HI3559AV100_CRG_NR_CLKS);
if (!clk_data)
return ERR_PTR(-ENOMEM);
ret = hisi_clk_register_fixed_rate(hi3559av100_fixed_rate_clks_crg,
ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), clk_data);
if (ret)
return ERR_PTR(ret);
hisi_clk_register_pll(hi3559av100_pll_clks,
ARRAY_SIZE(hi3559av100_pll_clks), clk_data, &pdev->dev);
ret = hisi_clk_register_mux(hi3559av100_mux_clks_crg,
ARRAY_SIZE(hi3559av100_mux_clks_crg), clk_data);
if (ret)
goto unregister_fixed_rate;
ret = hisi_clk_register_gate(hi3559av100_gate_clks,
ARRAY_SIZE(hi3559av100_gate_clks), clk_data);
if (ret)
goto unregister_mux;
ret = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, &clk_data->clk_data);
if (ret)
goto unregister_gate;
return clk_data;
unregister_gate:
hisi_clk_unregister_gate(hi3559av100_gate_clks,
ARRAY_SIZE(hi3559av100_gate_clks), clk_data);
unregister_mux:
hisi_clk_unregister_mux(hi3559av100_mux_clks_crg,
ARRAY_SIZE(hi3559av100_mux_clks_crg), clk_data);
unregister_fixed_rate:
hisi_clk_unregister_fixed_rate(hi3559av100_fixed_rate_clks_crg,
ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), clk_data);
return ERR_PTR(ret);
}
static void hi3559av100_clk_unregister(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
hisi_clk_unregister_gate(hi3559av100_gate_clks,
ARRAY_SIZE(hi3559av100_gate_clks), crg->clk_data);
hisi_clk_unregister_mux(hi3559av100_mux_clks_crg,
ARRAY_SIZE(hi3559av100_mux_clks_crg), crg->clk_data);
hisi_clk_unregister_fixed_rate(hi3559av100_fixed_rate_clks_crg,
ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), crg->clk_data);
}
static const struct hisi_crg_funcs hi3559av100_crg_funcs = {
.register_clks = hi3559av100_clk_register,
.unregister_clks = hi3559av100_clk_unregister,
};
static struct hisi_fixed_rate_clock hi3559av100_shub_fixed_rate_clks[] = {
{ HI3559AV100_SHUB_SOURCE_SOC_24M, "clk_source_24M", NULL, 0, 24000000UL, },
{ HI3559AV100_SHUB_SOURCE_SOC_200M, "clk_source_200M", NULL, 0, 200000000UL, },
{ HI3559AV100_SHUB_SOURCE_SOC_300M, "clk_source_300M", NULL, 0, 300000000UL, },
{ HI3559AV100_SHUB_SOURCE_PLL, "clk_source_PLL", NULL, 0, 192000000UL, },
{ HI3559AV100_SHUB_I2C0_CLK, "clk_shub_i2c0", NULL, 0, 48000000UL, },
{ HI3559AV100_SHUB_I2C1_CLK, "clk_shub_i2c1", NULL, 0, 48000000UL, },
{ HI3559AV100_SHUB_I2C2_CLK, "clk_shub_i2c2", NULL, 0, 48000000UL, },
{ HI3559AV100_SHUB_I2C3_CLK, "clk_shub_i2c3", NULL, 0, 48000000UL, },
{ HI3559AV100_SHUB_I2C4_CLK, "clk_shub_i2c4", NULL, 0, 48000000UL, },
{ HI3559AV100_SHUB_I2C5_CLK, "clk_shub_i2c5", NULL, 0, 48000000UL, },
{ HI3559AV100_SHUB_I2C6_CLK, "clk_shub_i2c6", NULL, 0, 48000000UL, },
{ HI3559AV100_SHUB_I2C7_CLK, "clk_shub_i2c7", NULL, 0, 48000000UL, },
{ HI3559AV100_SHUB_UART_CLK_32K, "clk_uart_32K", NULL, 0, 32000UL, },
};
/* shub mux clk */
static u32 shub_source_clk_mux_table[] = {0, 1, 2, 3};
static const char *shub_source_clk_mux_p[] = {
"clk_source_24M", "clk_source_200M", "clk_source_300M", "clk_source_PLL"
};
static u32 shub_uart_source_clk_mux_table[] = {0, 1, 2, 3};
static const char *shub_uart_source_clk_mux_p[] = {
"clk_uart_32K", "clk_uart_div_clk", "clk_uart_div_clk", "clk_source_24M"
};
static struct hisi_mux_clock hi3559av100_shub_mux_clks[] = {
{
HI3559AV100_SHUB_SOURCE_CLK, "shub_clk", shub_source_clk_mux_p,
ARRAY_SIZE(shub_source_clk_mux_p),
0, 0x0, 0, 2, 0, shub_source_clk_mux_table,
},
{
HI3559AV100_SHUB_UART_SOURCE_CLK, "shub_uart_source_clk",
shub_uart_source_clk_mux_p, ARRAY_SIZE(shub_uart_source_clk_mux_p),
0, 0x1c, 28, 2, 0, shub_uart_source_clk_mux_table,
},
};
/* shub div clk */
static struct clk_div_table shub_spi_clk_table[] = {{0, 8}, {1, 4}, {2, 2}, {/*sentinel*/}};
static struct clk_div_table shub_uart_div_clk_table[] = {{1, 8}, {2, 4}, {/*sentinel*/}};
static struct hisi_divider_clock hi3559av100_shub_div_clks[] = {
{ HI3559AV100_SHUB_SPI_SOURCE_CLK, "clk_spi_clk", "shub_clk", 0, 0x20, 24, 2,
CLK_DIVIDER_ALLOW_ZERO, shub_spi_clk_table,
},
{ HI3559AV100_SHUB_UART_DIV_CLK, "clk_uart_div_clk", "shub_clk", 0, 0x1c, 28, 2,
CLK_DIVIDER_ALLOW_ZERO, shub_uart_div_clk_table,
},
};
/* shub gate clk */
static struct hisi_gate_clock hi3559av100_shub_gate_clks[] = {
{
HI3559AV100_SHUB_SPI0_CLK, "clk_shub_spi0", "clk_spi_clk",
0, 0x20, 1, 0,
},
{
HI3559AV100_SHUB_SPI1_CLK, "clk_shub_spi1", "clk_spi_clk",
0, 0x20, 5, 0,
},
{
HI3559AV100_SHUB_SPI2_CLK, "clk_shub_spi2", "clk_spi_clk",
0, 0x20, 9, 0,
},
{
HI3559AV100_SHUB_UART0_CLK, "clk_shub_uart0", "shub_uart_source_clk",
0, 0x1c, 1, 0,
},
{
HI3559AV100_SHUB_UART1_CLK, "clk_shub_uart1", "shub_uart_source_clk",
0, 0x1c, 5, 0,
},
{
HI3559AV100_SHUB_UART2_CLK, "clk_shub_uart2", "shub_uart_source_clk",
0, 0x1c, 9, 0,
},
{
HI3559AV100_SHUB_UART3_CLK, "clk_shub_uart3", "shub_uart_source_clk",
0, 0x1c, 13, 0,
},
{
HI3559AV100_SHUB_UART4_CLK, "clk_shub_uart4", "shub_uart_source_clk",
0, 0x1c, 17, 0,
},
{
HI3559AV100_SHUB_UART5_CLK, "clk_shub_uart5", "shub_uart_source_clk",
0, 0x1c, 21, 0,
},
{
HI3559AV100_SHUB_UART6_CLK, "clk_shub_uart6", "shub_uart_source_clk",
0, 0x1c, 25, 0,
},
{
HI3559AV100_SHUB_EDMAC_CLK, "clk_shub_dmac", "shub_clk",
0, 0x24, 4, 0,
},
};
static int hi3559av100_shub_default_clk_set(void)
{
void __iomem *crg_base;
unsigned int val;
crg_base = ioremap(CRG_BASE_ADDR, SZ_4K);
/* SSP: 192M/2 */
val = readl_relaxed(crg_base + 0x20);
val |= (0x2 << 24);
writel_relaxed(val, crg_base + 0x20);
/* UART: 192M/8 */
val = readl_relaxed(crg_base + 0x1C);
val |= (0x1 << 28);
writel_relaxed(val, crg_base + 0x1C);
iounmap(crg_base);
crg_base = NULL;
return 0;
}
static struct hisi_clock_data *hi3559av100_shub_clk_register(
struct platform_device *pdev)
{
struct hisi_clock_data *clk_data = NULL;
int ret;
hi3559av100_shub_default_clk_set();
clk_data = hisi_clk_alloc(pdev, HI3559AV100_SHUB_NR_CLKS);
if (!clk_data)
return ERR_PTR(-ENOMEM);
ret = hisi_clk_register_fixed_rate(hi3559av100_shub_fixed_rate_clks,
ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), clk_data);
if (ret)
return ERR_PTR(ret);
ret = hisi_clk_register_mux(hi3559av100_shub_mux_clks,
ARRAY_SIZE(hi3559av100_shub_mux_clks), clk_data);
if (ret)
goto unregister_fixed_rate;
ret = hisi_clk_register_divider(hi3559av100_shub_div_clks,
ARRAY_SIZE(hi3559av100_shub_div_clks), clk_data);
if (ret)
goto unregister_mux;
ret = hisi_clk_register_gate(hi3559av100_shub_gate_clks,
ARRAY_SIZE(hi3559av100_shub_gate_clks), clk_data);
if (ret)
goto unregister_factor;
ret = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, &clk_data->clk_data);
if (ret)
goto unregister_gate;
return clk_data;
unregister_gate:
hisi_clk_unregister_gate(hi3559av100_shub_gate_clks,
ARRAY_SIZE(hi3559av100_shub_gate_clks), clk_data);
unregister_factor:
hisi_clk_unregister_divider(hi3559av100_shub_div_clks,
ARRAY_SIZE(hi3559av100_shub_div_clks), clk_data);
unregister_mux:
hisi_clk_unregister_mux(hi3559av100_shub_mux_clks,
ARRAY_SIZE(hi3559av100_shub_mux_clks), clk_data);
unregister_fixed_rate:
hisi_clk_unregister_fixed_rate(hi3559av100_shub_fixed_rate_clks,
ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), clk_data);
return ERR_PTR(ret);
}
static void hi3559av100_shub_clk_unregister(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
hisi_clk_unregister_gate(hi3559av100_shub_gate_clks,
ARRAY_SIZE(hi3559av100_shub_gate_clks), crg->clk_data);
hisi_clk_unregister_divider(hi3559av100_shub_div_clks,
ARRAY_SIZE(hi3559av100_shub_div_clks), crg->clk_data);
hisi_clk_unregister_mux(hi3559av100_shub_mux_clks,
ARRAY_SIZE(hi3559av100_shub_mux_clks), crg->clk_data);
hisi_clk_unregister_fixed_rate(hi3559av100_shub_fixed_rate_clks,
ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), crg->clk_data);
}
static const struct hisi_crg_funcs hi3559av100_shub_crg_funcs = {
.register_clks = hi3559av100_shub_clk_register,
.unregister_clks = hi3559av100_shub_clk_unregister,
};
static const struct of_device_id hi3559av100_crg_match_table[] = {
{
.compatible = "hisilicon,hi3559av100-clock",
.data = &hi3559av100_crg_funcs
},
{
.compatible = "hisilicon,hi3559av100-shub-clock",
.data = &hi3559av100_shub_crg_funcs
},
{ }
};
MODULE_DEVICE_TABLE(of, hi3559av100_crg_match_table);
static int hi3559av100_crg_probe(struct platform_device *pdev)
{
struct hisi_crg_dev *crg;
crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
if (!crg)
return -ENOMEM;
crg->funcs = of_device_get_match_data(&pdev->dev);
if (!crg->funcs)
return -ENOENT;
crg->rstc = hisi_reset_init(pdev);
if (!crg->rstc)
return -ENOMEM;
crg->clk_data = crg->funcs->register_clks(pdev);
if (IS_ERR(crg->clk_data)) {
hisi_reset_exit(crg->rstc);
return PTR_ERR(crg->clk_data);
}
platform_set_drvdata(pdev, crg);
return 0;
}
static void hi3559av100_crg_remove(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
hisi_reset_exit(crg->rstc);
crg->funcs->unregister_clks(pdev);
}
static struct platform_driver hi3559av100_crg_driver = {
.probe = hi3559av100_crg_probe,
.remove = hi3559av100_crg_remove,
.driver = {
.name = "hi3559av100-clock",
.of_match_table = hi3559av100_crg_match_table,
},
};
static int __init hi3559av100_crg_init(void)
{
return platform_driver_register(&hi3559av100_crg_driver);
}
core_initcall(hi3559av100_crg_init);
static void __exit hi3559av100_crg_exit(void)
{
platform_driver_unregister(&hi3559av100_crg_driver);
}
module_exit(hi3559av100_crg_exit);
MODULE_DESCRIPTION("HiSilicon Hi3559AV100 CRG Driver");
@@ -0,0 +1,484 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hisilicon Hi3620 clock driver
*
* Copyright (c) 2012-2013 Hisilicon Limited.
* Copyright (c) 2012-2013 Linaro Limited.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
* Xin Li <li.xin@linaro.org>
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <dt-bindings/clock/hi3620-clock.h>
#include "clk.h"
/* clock parent list */
static const char *const timer0_mux_p[] __initconst = { "osc32k", "timerclk01", };
static const char *const timer1_mux_p[] __initconst = { "osc32k", "timerclk01", };
static const char *const timer2_mux_p[] __initconst = { "osc32k", "timerclk23", };
static const char *const timer3_mux_p[] __initconst = { "osc32k", "timerclk23", };
static const char *const timer4_mux_p[] __initconst = { "osc32k", "timerclk45", };
static const char *const timer5_mux_p[] __initconst = { "osc32k", "timerclk45", };
static const char *const timer6_mux_p[] __initconst = { "osc32k", "timerclk67", };
static const char *const timer7_mux_p[] __initconst = { "osc32k", "timerclk67", };
static const char *const timer8_mux_p[] __initconst = { "osc32k", "timerclk89", };
static const char *const timer9_mux_p[] __initconst = { "osc32k", "timerclk89", };
static const char *const uart0_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *const uart1_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *const uart2_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *const uart3_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *const uart4_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *const spi0_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
static const char *const spi1_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
static const char *const spi2_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
/* share axi parent */
static const char *const saxi_mux_p[] __initconst = { "armpll3", "armpll2", };
static const char *const pwm0_mux_p[] __initconst = { "osc32k", "osc26m", };
static const char *const pwm1_mux_p[] __initconst = { "osc32k", "osc26m", };
static const char *const sd_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const mmc1_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const mmc1_mux2_p[] __initconst = { "osc26m", "mmc1_div", };
static const char *const g2d_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const venc_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const vdec_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const vpp_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const edc0_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const ldi0_mux_p[] __initconst = { "armpll2", "armpll4",
"armpll3", "armpll5", };
static const char *const edc1_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const ldi1_mux_p[] __initconst = { "armpll2", "armpll4",
"armpll3", "armpll5", };
static const char *const rclk_hsic_p[] __initconst = { "armpll3", "armpll2", };
static const char *const mmc2_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *const mmc3_mux_p[] __initconst = { "armpll2", "armpll3", };
/* fixed rate clocks */
static struct hisi_fixed_rate_clock hi3620_fixed_rate_clks[] __initdata = {
{ HI3620_OSC32K, "osc32k", NULL, 0, 32768, },
{ HI3620_OSC26M, "osc26m", NULL, 0, 26000000, },
{ HI3620_PCLK, "pclk", NULL, 0, 26000000, },
{ HI3620_PLL_ARM0, "armpll0", NULL, 0, 1600000000, },
{ HI3620_PLL_ARM1, "armpll1", NULL, 0, 1600000000, },
{ HI3620_PLL_PERI, "armpll2", NULL, 0, 1440000000, },
{ HI3620_PLL_USB, "armpll3", NULL, 0, 1440000000, },
{ HI3620_PLL_HDMI, "armpll4", NULL, 0, 1188000000, },
{ HI3620_PLL_GPU, "armpll5", NULL, 0, 1300000000, },
};
/* fixed factor clocks */
static struct hisi_fixed_factor_clock hi3620_fixed_factor_clks[] __initdata = {
{ HI3620_RCLK_TCXO, "rclk_tcxo", "osc26m", 1, 4, 0, },
{ HI3620_RCLK_CFGAXI, "rclk_cfgaxi", "armpll2", 1, 30, 0, },
{ HI3620_RCLK_PICO, "rclk_pico", "hsic_div", 1, 40, 0, },
};
static struct hisi_mux_clock hi3620_mux_clks[] __initdata = {
{ HI3620_TIMER0_MUX, "timer0_mux", timer0_mux_p, ARRAY_SIZE(timer0_mux_p), CLK_SET_RATE_PARENT, 0, 15, 2, 0, },
{ HI3620_TIMER1_MUX, "timer1_mux", timer1_mux_p, ARRAY_SIZE(timer1_mux_p), CLK_SET_RATE_PARENT, 0, 17, 2, 0, },
{ HI3620_TIMER2_MUX, "timer2_mux", timer2_mux_p, ARRAY_SIZE(timer2_mux_p), CLK_SET_RATE_PARENT, 0, 19, 2, 0, },
{ HI3620_TIMER3_MUX, "timer3_mux", timer3_mux_p, ARRAY_SIZE(timer3_mux_p), CLK_SET_RATE_PARENT, 0, 21, 2, 0, },
{ HI3620_TIMER4_MUX, "timer4_mux", timer4_mux_p, ARRAY_SIZE(timer4_mux_p), CLK_SET_RATE_PARENT, 0x18, 0, 2, 0, },
{ HI3620_TIMER5_MUX, "timer5_mux", timer5_mux_p, ARRAY_SIZE(timer5_mux_p), CLK_SET_RATE_PARENT, 0x18, 2, 2, 0, },
{ HI3620_TIMER6_MUX, "timer6_mux", timer6_mux_p, ARRAY_SIZE(timer6_mux_p), CLK_SET_RATE_PARENT, 0x18, 4, 2, 0, },
{ HI3620_TIMER7_MUX, "timer7_mux", timer7_mux_p, ARRAY_SIZE(timer7_mux_p), CLK_SET_RATE_PARENT, 0x18, 6, 2, 0, },
{ HI3620_TIMER8_MUX, "timer8_mux", timer8_mux_p, ARRAY_SIZE(timer8_mux_p), CLK_SET_RATE_PARENT, 0x18, 8, 2, 0, },
{ HI3620_TIMER9_MUX, "timer9_mux", timer9_mux_p, ARRAY_SIZE(timer9_mux_p), CLK_SET_RATE_PARENT, 0x18, 10, 2, 0, },
{ HI3620_UART0_MUX, "uart0_mux", uart0_mux_p, ARRAY_SIZE(uart0_mux_p), CLK_SET_RATE_PARENT, 0x100, 7, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_UART1_MUX, "uart1_mux", uart1_mux_p, ARRAY_SIZE(uart1_mux_p), CLK_SET_RATE_PARENT, 0x100, 8, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_UART2_MUX, "uart2_mux", uart2_mux_p, ARRAY_SIZE(uart2_mux_p), CLK_SET_RATE_PARENT, 0x100, 9, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_UART3_MUX, "uart3_mux", uart3_mux_p, ARRAY_SIZE(uart3_mux_p), CLK_SET_RATE_PARENT, 0x100, 10, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_UART4_MUX, "uart4_mux", uart4_mux_p, ARRAY_SIZE(uart4_mux_p), CLK_SET_RATE_PARENT, 0x100, 11, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_SPI0_MUX, "spi0_mux", spi0_mux_p, ARRAY_SIZE(spi0_mux_p), CLK_SET_RATE_PARENT, 0x100, 12, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_SPI1_MUX, "spi1_mux", spi1_mux_p, ARRAY_SIZE(spi1_mux_p), CLK_SET_RATE_PARENT, 0x100, 13, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_SPI2_MUX, "spi2_mux", spi2_mux_p, ARRAY_SIZE(spi2_mux_p), CLK_SET_RATE_PARENT, 0x100, 14, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_SAXI_MUX, "saxi_mux", saxi_mux_p, ARRAY_SIZE(saxi_mux_p), CLK_SET_RATE_PARENT, 0x100, 15, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_PWM0_MUX, "pwm0_mux", pwm0_mux_p, ARRAY_SIZE(pwm0_mux_p), CLK_SET_RATE_PARENT, 0x104, 10, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_PWM1_MUX, "pwm1_mux", pwm1_mux_p, ARRAY_SIZE(pwm1_mux_p), CLK_SET_RATE_PARENT, 0x104, 11, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_SD_MUX, "sd_mux", sd_mux_p, ARRAY_SIZE(sd_mux_p), CLK_SET_RATE_PARENT, 0x108, 4, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_MMC1_MUX, "mmc1_mux", mmc1_mux_p, ARRAY_SIZE(mmc1_mux_p), CLK_SET_RATE_PARENT, 0x108, 9, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_MMC1_MUX2, "mmc1_mux2", mmc1_mux2_p, ARRAY_SIZE(mmc1_mux2_p), CLK_SET_RATE_PARENT, 0x108, 10, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_G2D_MUX, "g2d_mux", g2d_mux_p, ARRAY_SIZE(g2d_mux_p), CLK_SET_RATE_PARENT, 0x10c, 5, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_VENC_MUX, "venc_mux", venc_mux_p, ARRAY_SIZE(venc_mux_p), CLK_SET_RATE_PARENT, 0x10c, 11, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_VDEC_MUX, "vdec_mux", vdec_mux_p, ARRAY_SIZE(vdec_mux_p), CLK_SET_RATE_PARENT, 0x110, 5, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_VPP_MUX, "vpp_mux", vpp_mux_p, ARRAY_SIZE(vpp_mux_p), CLK_SET_RATE_PARENT, 0x110, 11, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_EDC0_MUX, "edc0_mux", edc0_mux_p, ARRAY_SIZE(edc0_mux_p), CLK_SET_RATE_PARENT, 0x114, 6, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_LDI0_MUX, "ldi0_mux", ldi0_mux_p, ARRAY_SIZE(ldi0_mux_p), CLK_SET_RATE_PARENT, 0x114, 13, 2, CLK_MUX_HIWORD_MASK, },
{ HI3620_EDC1_MUX, "edc1_mux", edc1_mux_p, ARRAY_SIZE(edc1_mux_p), CLK_SET_RATE_PARENT, 0x118, 6, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_LDI1_MUX, "ldi1_mux", ldi1_mux_p, ARRAY_SIZE(ldi1_mux_p), CLK_SET_RATE_PARENT, 0x118, 14, 2, CLK_MUX_HIWORD_MASK, },
{ HI3620_RCLK_HSIC, "rclk_hsic", rclk_hsic_p, ARRAY_SIZE(rclk_hsic_p), CLK_SET_RATE_PARENT, 0x130, 2, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_MMC2_MUX, "mmc2_mux", mmc2_mux_p, ARRAY_SIZE(mmc2_mux_p), CLK_SET_RATE_PARENT, 0x140, 4, 1, CLK_MUX_HIWORD_MASK, },
{ HI3620_MMC3_MUX, "mmc3_mux", mmc3_mux_p, ARRAY_SIZE(mmc3_mux_p), CLK_SET_RATE_PARENT, 0x140, 9, 1, CLK_MUX_HIWORD_MASK, },
};
static struct hisi_divider_clock hi3620_div_clks[] __initdata = {
{ HI3620_SHAREAXI_DIV, "saxi_div", "saxi_mux", 0, 0x100, 0, 5, CLK_DIVIDER_HIWORD_MASK, NULL, },
{ HI3620_CFGAXI_DIV, "cfgaxi_div", "saxi_div", 0, 0x100, 5, 2, CLK_DIVIDER_HIWORD_MASK, NULL, },
{ HI3620_SD_DIV, "sd_div", "sd_mux", 0, 0x108, 0, 4, CLK_DIVIDER_HIWORD_MASK, NULL, },
{ HI3620_MMC1_DIV, "mmc1_div", "mmc1_mux", 0, 0x108, 5, 4, CLK_DIVIDER_HIWORD_MASK, NULL, },
{ HI3620_HSIC_DIV, "hsic_div", "rclk_hsic", 0, 0x130, 0, 2, CLK_DIVIDER_HIWORD_MASK, NULL, },
{ HI3620_MMC2_DIV, "mmc2_div", "mmc2_mux", 0, 0x140, 0, 4, CLK_DIVIDER_HIWORD_MASK, NULL, },
{ HI3620_MMC3_DIV, "mmc3_div", "mmc3_mux", 0, 0x140, 5, 4, CLK_DIVIDER_HIWORD_MASK, NULL, },
};
static struct hisi_gate_clock hi3620_separated_gate_clks[] __initdata = {
{ HI3620_TIMERCLK01, "timerclk01", "timer_rclk01", CLK_SET_RATE_PARENT, 0x20, 0, 0, },
{ HI3620_TIMER_RCLK01, "timer_rclk01", "rclk_tcxo", CLK_SET_RATE_PARENT, 0x20, 1, 0, },
{ HI3620_TIMERCLK23, "timerclk23", "timer_rclk23", CLK_SET_RATE_PARENT, 0x20, 2, 0, },
{ HI3620_TIMER_RCLK23, "timer_rclk23", "rclk_tcxo", CLK_SET_RATE_PARENT, 0x20, 3, 0, },
{ HI3620_RTCCLK, "rtcclk", "pclk", CLK_SET_RATE_PARENT, 0x20, 5, 0, },
{ HI3620_KPC_CLK, "kpc_clk", "pclk", CLK_SET_RATE_PARENT, 0x20, 6, 0, },
{ HI3620_GPIOCLK0, "gpioclk0", "pclk", CLK_SET_RATE_PARENT, 0x20, 8, 0, },
{ HI3620_GPIOCLK1, "gpioclk1", "pclk", CLK_SET_RATE_PARENT, 0x20, 9, 0, },
{ HI3620_GPIOCLK2, "gpioclk2", "pclk", CLK_SET_RATE_PARENT, 0x20, 10, 0, },
{ HI3620_GPIOCLK3, "gpioclk3", "pclk", CLK_SET_RATE_PARENT, 0x20, 11, 0, },
{ HI3620_GPIOCLK4, "gpioclk4", "pclk", CLK_SET_RATE_PARENT, 0x20, 12, 0, },
{ HI3620_GPIOCLK5, "gpioclk5", "pclk", CLK_SET_RATE_PARENT, 0x20, 13, 0, },
{ HI3620_GPIOCLK6, "gpioclk6", "pclk", CLK_SET_RATE_PARENT, 0x20, 14, 0, },
{ HI3620_GPIOCLK7, "gpioclk7", "pclk", CLK_SET_RATE_PARENT, 0x20, 15, 0, },
{ HI3620_GPIOCLK8, "gpioclk8", "pclk", CLK_SET_RATE_PARENT, 0x20, 16, 0, },
{ HI3620_GPIOCLK9, "gpioclk9", "pclk", CLK_SET_RATE_PARENT, 0x20, 17, 0, },
{ HI3620_GPIOCLK10, "gpioclk10", "pclk", CLK_SET_RATE_PARENT, 0x20, 18, 0, },
{ HI3620_GPIOCLK11, "gpioclk11", "pclk", CLK_SET_RATE_PARENT, 0x20, 19, 0, },
{ HI3620_GPIOCLK12, "gpioclk12", "pclk", CLK_SET_RATE_PARENT, 0x20, 20, 0, },
{ HI3620_GPIOCLK13, "gpioclk13", "pclk", CLK_SET_RATE_PARENT, 0x20, 21, 0, },
{ HI3620_GPIOCLK14, "gpioclk14", "pclk", CLK_SET_RATE_PARENT, 0x20, 22, 0, },
{ HI3620_GPIOCLK15, "gpioclk15", "pclk", CLK_SET_RATE_PARENT, 0x20, 23, 0, },
{ HI3620_GPIOCLK16, "gpioclk16", "pclk", CLK_SET_RATE_PARENT, 0x20, 24, 0, },
{ HI3620_GPIOCLK17, "gpioclk17", "pclk", CLK_SET_RATE_PARENT, 0x20, 25, 0, },
{ HI3620_GPIOCLK18, "gpioclk18", "pclk", CLK_SET_RATE_PARENT, 0x20, 26, 0, },
{ HI3620_GPIOCLK19, "gpioclk19", "pclk", CLK_SET_RATE_PARENT, 0x20, 27, 0, },
{ HI3620_GPIOCLK20, "gpioclk20", "pclk", CLK_SET_RATE_PARENT, 0x20, 28, 0, },
{ HI3620_GPIOCLK21, "gpioclk21", "pclk", CLK_SET_RATE_PARENT, 0x20, 29, 0, },
{ HI3620_DPHY0_CLK, "dphy0_clk", "osc26m", CLK_SET_RATE_PARENT, 0x30, 15, 0, },
{ HI3620_DPHY1_CLK, "dphy1_clk", "osc26m", CLK_SET_RATE_PARENT, 0x30, 16, 0, },
{ HI3620_DPHY2_CLK, "dphy2_clk", "osc26m", CLK_SET_RATE_PARENT, 0x30, 17, 0, },
{ HI3620_USBPHY_CLK, "usbphy_clk", "rclk_pico", CLK_SET_RATE_PARENT, 0x30, 24, 0, },
{ HI3620_ACP_CLK, "acp_clk", "rclk_cfgaxi", CLK_SET_RATE_PARENT, 0x30, 28, 0, },
{ HI3620_TIMERCLK45, "timerclk45", "rclk_tcxo", CLK_SET_RATE_PARENT, 0x40, 3, 0, },
{ HI3620_TIMERCLK67, "timerclk67", "rclk_tcxo", CLK_SET_RATE_PARENT, 0x40, 4, 0, },
{ HI3620_TIMERCLK89, "timerclk89", "rclk_tcxo", CLK_SET_RATE_PARENT, 0x40, 5, 0, },
{ HI3620_PWMCLK0, "pwmclk0", "pwm0_mux", CLK_SET_RATE_PARENT, 0x40, 7, 0, },
{ HI3620_PWMCLK1, "pwmclk1", "pwm1_mux", CLK_SET_RATE_PARENT, 0x40, 8, 0, },
{ HI3620_UARTCLK0, "uartclk0", "uart0_mux", CLK_SET_RATE_PARENT, 0x40, 16, 0, },
{ HI3620_UARTCLK1, "uartclk1", "uart1_mux", CLK_SET_RATE_PARENT, 0x40, 17, 0, },
{ HI3620_UARTCLK2, "uartclk2", "uart2_mux", CLK_SET_RATE_PARENT, 0x40, 18, 0, },
{ HI3620_UARTCLK3, "uartclk3", "uart3_mux", CLK_SET_RATE_PARENT, 0x40, 19, 0, },
{ HI3620_UARTCLK4, "uartclk4", "uart4_mux", CLK_SET_RATE_PARENT, 0x40, 20, 0, },
{ HI3620_SPICLK0, "spiclk0", "spi0_mux", CLK_SET_RATE_PARENT, 0x40, 21, 0, },
{ HI3620_SPICLK1, "spiclk1", "spi1_mux", CLK_SET_RATE_PARENT, 0x40, 22, 0, },
{ HI3620_SPICLK2, "spiclk2", "spi2_mux", CLK_SET_RATE_PARENT, 0x40, 23, 0, },
{ HI3620_I2CCLK0, "i2cclk0", "pclk", CLK_SET_RATE_PARENT, 0x40, 24, 0, },
{ HI3620_I2CCLK1, "i2cclk1", "pclk", CLK_SET_RATE_PARENT, 0x40, 25, 0, },
{ HI3620_SCI_CLK, "sci_clk", "osc26m", CLK_SET_RATE_PARENT, 0x40, 26, 0, },
{ HI3620_I2CCLK2, "i2cclk2", "pclk", CLK_SET_RATE_PARENT, 0x40, 28, 0, },
{ HI3620_I2CCLK3, "i2cclk3", "pclk", CLK_SET_RATE_PARENT, 0x40, 29, 0, },
{ HI3620_DDRC_PER_CLK, "ddrc_per_clk", "rclk_cfgaxi", CLK_SET_RATE_PARENT, 0x50, 9, 0, },
{ HI3620_DMAC_CLK, "dmac_clk", "rclk_cfgaxi", CLK_SET_RATE_PARENT, 0x50, 10, 0, },
{ HI3620_USB2DVC_CLK, "usb2dvc_clk", "rclk_cfgaxi", CLK_SET_RATE_PARENT, 0x50, 17, 0, },
{ HI3620_SD_CLK, "sd_clk", "sd_div", CLK_SET_RATE_PARENT, 0x50, 20, 0, },
{ HI3620_MMC_CLK1, "mmc_clk1", "mmc1_mux2", CLK_SET_RATE_PARENT, 0x50, 21, 0, },
{ HI3620_MMC_CLK2, "mmc_clk2", "mmc2_div", CLK_SET_RATE_PARENT, 0x50, 22, 0, },
{ HI3620_MMC_CLK3, "mmc_clk3", "mmc3_div", CLK_SET_RATE_PARENT, 0x50, 23, 0, },
{ HI3620_MCU_CLK, "mcu_clk", "acp_clk", CLK_SET_RATE_PARENT, 0x50, 24, 0, },
};
static void __init hi3620_clk_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
clk_data = hisi_clk_init(np, HI3620_NR_CLKS);
if (!clk_data)
return;
hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks,
ARRAY_SIZE(hi3620_fixed_rate_clks),
clk_data);
hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks,
ARRAY_SIZE(hi3620_fixed_factor_clks),
clk_data);
hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks),
clk_data);
hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks),
clk_data);
hisi_clk_register_gate_sep(hi3620_separated_gate_clks,
ARRAY_SIZE(hi3620_separated_gate_clks),
clk_data);
}
CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
struct hisi_mmc_clock {
unsigned int id;
const char *name;
const char *parent_name;
unsigned long flags;
u32 clken_reg;
u32 clken_bit;
u32 div_reg;
u32 div_off;
u32 div_bits;
u32 drv_reg;
u32 drv_off;
u32 drv_bits;
u32 sam_reg;
u32 sam_off;
u32 sam_bits;
};
struct clk_mmc {
struct clk_hw hw;
u32 id;
void __iomem *clken_reg;
u32 clken_bit;
void __iomem *div_reg;
u32 div_off;
u32 div_bits;
void __iomem *drv_reg;
u32 drv_off;
u32 drv_bits;
void __iomem *sam_reg;
u32 sam_off;
u32 sam_bits;
};
#define to_mmc(_hw) container_of(_hw, struct clk_mmc, hw)
static struct hisi_mmc_clock hi3620_mmc_clks[] __initdata = {
{ HI3620_SD_CIUCLK, "sd_bclk1", "sd_clk", CLK_SET_RATE_PARENT, 0x1f8, 0, 0x1f8, 1, 3, 0x1f8, 4, 4, 0x1f8, 8, 4},
{ HI3620_MMC_CIUCLK1, "mmc_bclk1", "mmc_clk1", CLK_SET_RATE_PARENT, 0x1f8, 12, 0x1f8, 13, 3, 0x1f8, 16, 4, 0x1f8, 20, 4},
{ HI3620_MMC_CIUCLK2, "mmc_bclk2", "mmc_clk2", CLK_SET_RATE_PARENT, 0x1f8, 24, 0x1f8, 25, 3, 0x1f8, 28, 4, 0x1fc, 0, 4},
{ HI3620_MMC_CIUCLK3, "mmc_bclk3", "mmc_clk3", CLK_SET_RATE_PARENT, 0x1fc, 4, 0x1fc, 5, 3, 0x1fc, 8, 4, 0x1fc, 12, 4},
};
static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
switch (parent_rate) {
case 26000000:
return 13000000;
case 180000000:
return 25000000;
case 360000000:
return 50000000;
case 720000000:
return 100000000;
case 1440000000:
return 180000000;
default:
return parent_rate;
}
}
static int mmc_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_mmc *mclk = to_mmc(hw);
if ((req->rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
req->rate = 13000000;
req->best_parent_rate = 26000000;
} else if (req->rate <= 26000000) {
req->rate = 25000000;
req->best_parent_rate = 180000000;
} else if (req->rate <= 52000000) {
req->rate = 50000000;
req->best_parent_rate = 360000000;
} else if (req->rate <= 100000000) {
req->rate = 100000000;
req->best_parent_rate = 720000000;
} else {
/* max is 180M */
req->rate = 180000000;
req->best_parent_rate = 1440000000;
}
return -EINVAL;
}
static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
{
u32 i;
for (i = 0; i < len; i++) {
if (para % 2)
val |= 1 << (off + i);
else
val &= ~(1 << (off + i));
para = para >> 1;
}
return val;
}
static int mmc_clk_set_timing(struct clk_hw *hw, unsigned long rate)
{
struct clk_mmc *mclk = to_mmc(hw);
unsigned long flags;
u32 sam, drv, div, val;
static DEFINE_SPINLOCK(mmc_clk_lock);
switch (rate) {
case 13000000:
sam = 3;
drv = 1;
div = 1;
break;
case 25000000:
sam = 13;
drv = 6;
div = 6;
break;
case 50000000:
sam = 3;
drv = 6;
div = 6;
break;
case 100000000:
sam = 6;
drv = 4;
div = 6;
break;
case 180000000:
sam = 6;
drv = 4;
div = 7;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&mmc_clk_lock, flags);
val = readl_relaxed(mclk->clken_reg);
val &= ~(1 << mclk->clken_bit);
writel_relaxed(val, mclk->clken_reg);
val = readl_relaxed(mclk->sam_reg);
val = mmc_clk_delay(val, sam, mclk->sam_off, mclk->sam_bits);
writel_relaxed(val, mclk->sam_reg);
val = readl_relaxed(mclk->drv_reg);
val = mmc_clk_delay(val, drv, mclk->drv_off, mclk->drv_bits);
writel_relaxed(val, mclk->drv_reg);
val = readl_relaxed(mclk->div_reg);
val = mmc_clk_delay(val, div, mclk->div_off, mclk->div_bits);
writel_relaxed(val, mclk->div_reg);
val = readl_relaxed(mclk->clken_reg);
val |= 1 << mclk->clken_bit;
writel_relaxed(val, mclk->clken_reg);
spin_unlock_irqrestore(&mmc_clk_lock, flags);
return 0;
}
static int mmc_clk_prepare(struct clk_hw *hw)
{
struct clk_mmc *mclk = to_mmc(hw);
unsigned long rate;
if (mclk->id == HI3620_MMC_CIUCLK1)
rate = 13000000;
else
rate = 25000000;
return mmc_clk_set_timing(hw, rate);
}
static int mmc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
return mmc_clk_set_timing(hw, rate);
}
static const struct clk_ops clk_mmc_ops = {
.prepare = mmc_clk_prepare,
.determine_rate = mmc_clk_determine_rate,
.set_rate = mmc_clk_set_rate,
.recalc_rate = mmc_clk_recalc_rate,
};
static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk,
void __iomem *base, struct device_node *np)
{
struct clk_mmc *mclk;
struct clk *clk;
struct clk_init_data init;
mclk = kzalloc_obj(*mclk);
if (!mclk)
return ERR_PTR(-ENOMEM);
init.name = mmc_clk->name;
init.ops = &clk_mmc_ops;
init.flags = mmc_clk->flags;
init.parent_names = (mmc_clk->parent_name ? &mmc_clk->parent_name : NULL);
init.num_parents = (mmc_clk->parent_name ? 1 : 0);
mclk->hw.init = &init;
mclk->id = mmc_clk->id;
mclk->clken_reg = base + mmc_clk->clken_reg;
mclk->clken_bit = mmc_clk->clken_bit;
mclk->div_reg = base + mmc_clk->div_reg;
mclk->div_off = mmc_clk->div_off;
mclk->div_bits = mmc_clk->div_bits;
mclk->drv_reg = base + mmc_clk->drv_reg;
mclk->drv_off = mmc_clk->drv_off;
mclk->drv_bits = mmc_clk->drv_bits;
mclk->sam_reg = base + mmc_clk->sam_reg;
mclk->sam_off = mmc_clk->sam_off;
mclk->sam_bits = mmc_clk->sam_bits;
clk = clk_register(NULL, &mclk->hw);
if (WARN_ON(IS_ERR(clk)))
kfree(mclk);
return clk;
}
static void __init hi3620_mmc_clk_init(struct device_node *node)
{
void __iomem *base;
int i, num = ARRAY_SIZE(hi3620_mmc_clks);
struct clk_onecell_data *clk_data;
if (!node) {
pr_err("failed to find pctrl node in DTS\n");
return;
}
base = of_iomap(node, 0);
if (!base) {
pr_err("failed to map pctrl\n");
return;
}
clk_data = kzalloc_obj(*clk_data);
if (WARN_ON(!clk_data))
return;
clk_data->clks = kzalloc_objs(*clk_data->clks, num);
if (!clk_data->clks) {
kfree(clk_data);
return;
}
for (i = 0; i < num; i++) {
struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i];
clk_data->clks[mmc_clk->id] =
hisi_register_clk_mmc(mmc_clk, base, node);
}
clk_data->clk_num = num;
of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
}
CLK_OF_DECLARE(hi3620_mmc_clk, "hisilicon,hi3620-mmc-clock", hi3620_mmc_clk_init);
@@ -0,0 +1,178 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hisilicon clock driver
*
* Copyright (c) 2013-2017 Hisilicon Limited.
* Copyright (c) 2017 Linaro Limited.
*
* Author: Kai Zhao <zhaokai1@hisilicon.com>
* Tao Wang <kevin.wangtao@hisilicon.com>
* Leo Yan <leo.yan@linaro.org>
*/
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/hi3660-clock.h>
#define HI3660_STUB_CLOCK_DATA (0x70)
#define MHZ (1000 * 1000)
#define DEFINE_CLK_STUB(_id, _cmd, _name) \
{ \
.id = (_id), \
.cmd = (_cmd), \
.hw.init = &(struct clk_init_data) { \
.name = #_name, \
.ops = &hi3660_stub_clk_ops, \
.num_parents = 0, \
.flags = CLK_GET_RATE_NOCACHE, \
}, \
}
#define to_stub_clk(_hw) container_of(_hw, struct hi3660_stub_clk, hw)
struct hi3660_stub_clk_chan {
struct mbox_client cl;
struct mbox_chan *mbox;
};
struct hi3660_stub_clk {
unsigned int id;
struct clk_hw hw;
unsigned int cmd;
unsigned int msg[8];
unsigned int rate;
};
static void __iomem *freq_reg;
static struct hi3660_stub_clk_chan stub_clk_chan;
static unsigned long hi3660_stub_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct hi3660_stub_clk *stub_clk = to_stub_clk(hw);
/*
* LPM3 writes back the CPU frequency in shared SRAM so read
* back the frequency.
*/
stub_clk->rate = readl(freq_reg + (stub_clk->id << 2)) * MHZ;
return stub_clk->rate;
}
static int hi3660_stub_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
/*
* LPM3 handles rate rounding so just return whatever
* rate is requested.
*/
return 0;
}
static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct hi3660_stub_clk *stub_clk = to_stub_clk(hw);
stub_clk->msg[0] = stub_clk->cmd;
stub_clk->msg[1] = rate / MHZ;
dev_dbg(stub_clk_chan.cl.dev, "set rate msg[0]=0x%x msg[1]=0x%x\n",
stub_clk->msg[0], stub_clk->msg[1]);
mbox_send_message(stub_clk_chan.mbox, stub_clk->msg);
mbox_client_txdone(stub_clk_chan.mbox, 0);
stub_clk->rate = rate;
return 0;
}
static const struct clk_ops hi3660_stub_clk_ops = {
.recalc_rate = hi3660_stub_clk_recalc_rate,
.determine_rate = hi3660_stub_clk_determine_rate,
.set_rate = hi3660_stub_clk_set_rate,
};
static struct hi3660_stub_clk hi3660_stub_clks[HI3660_CLK_STUB_NUM] = {
DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER0, 0x0001030A, "cpu-cluster.0"),
DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER1, 0x0002030A, "cpu-cluster.1"),
DEFINE_CLK_STUB(HI3660_CLK_STUB_GPU, 0x0003030A, "clk-g3d"),
DEFINE_CLK_STUB(HI3660_CLK_STUB_DDR, 0x00040309, "clk-ddrc"),
};
static struct clk_hw *hi3660_stub_clk_hw_get(struct of_phandle_args *clkspec,
void *data)
{
unsigned int idx = clkspec->args[0];
if (idx >= HI3660_CLK_STUB_NUM) {
pr_err("%s: invalid index %u\n", __func__, idx);
return ERR_PTR(-EINVAL);
}
return &hi3660_stub_clks[idx].hw;
}
static int hi3660_stub_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
unsigned int i;
int ret;
/* Use mailbox client without blocking */
stub_clk_chan.cl.dev = dev;
stub_clk_chan.cl.tx_done = NULL;
stub_clk_chan.cl.tx_block = false;
stub_clk_chan.cl.knows_txdone = false;
/* Allocate mailbox channel */
stub_clk_chan.mbox = mbox_request_channel(&stub_clk_chan.cl, 0);
if (IS_ERR(stub_clk_chan.mbox))
return PTR_ERR(stub_clk_chan.mbox);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
freq_reg = devm_ioremap(dev, res->start, resource_size(res));
if (!freq_reg)
return -ENOMEM;
freq_reg += HI3660_STUB_CLOCK_DATA;
for (i = 0; i < HI3660_CLK_STUB_NUM; i++) {
ret = devm_clk_hw_register(&pdev->dev, &hi3660_stub_clks[i].hw);
if (ret)
return ret;
}
return devm_of_clk_add_hw_provider(&pdev->dev, hi3660_stub_clk_hw_get,
hi3660_stub_clks);
}
static const struct of_device_id hi3660_stub_clk_of_match[] = {
{ .compatible = "hisilicon,hi3660-stub-clk", },
{}
};
static struct platform_driver hi3660_stub_clk_driver = {
.probe = hi3660_stub_clk_probe,
.driver = {
.name = "hi3660-stub-clk",
.of_match_table = hi3660_stub_clk_of_match,
},
};
static int __init hi3660_stub_clk_init(void)
{
return platform_driver_register(&hi3660_stub_clk_driver);
}
subsys_initcall(hi3660_stub_clk_init);
@@ -0,0 +1,637 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2016-2017 Linaro Ltd.
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
*/
#include <dt-bindings/clock/hi3660-clock.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "clk.h"
static const struct hisi_fixed_rate_clock hi3660_fixed_rate_clks[] = {
{ HI3660_CLKIN_SYS, "clkin_sys", NULL, 0, 19200000, },
{ HI3660_CLKIN_REF, "clkin_ref", NULL, 0, 32764, },
{ HI3660_CLK_FLL_SRC, "clk_fll_src", NULL, 0, 128000000, },
{ HI3660_CLK_PPLL0, "clk_ppll0", NULL, 0, 1600000000, },
{ HI3660_CLK_PPLL1, "clk_ppll1", NULL, 0, 1866000000, },
{ HI3660_CLK_PPLL2, "clk_ppll2", NULL, 0, 2880000000UL, },
{ HI3660_CLK_PPLL3, "clk_ppll3", NULL, 0, 1290000000, },
{ HI3660_CLK_SCPLL, "clk_scpll", NULL, 0, 245760000, },
{ HI3660_PCLK, "pclk", NULL, 0, 20000000, },
{ HI3660_CLK_UART0_DBG, "clk_uart0_dbg", NULL, 0, 19200000, },
{ HI3660_CLK_UART6, "clk_uart6", NULL, 0, 19200000, },
{ HI3660_OSC32K, "osc32k", NULL, 0, 32764, },
{ HI3660_OSC19M, "osc19m", NULL, 0, 19200000, },
{ HI3660_CLK_480M, "clk_480m", NULL, 0, 480000000, },
{ HI3660_CLK_INV, "clk_inv", NULL, 0, 10000000, },
};
/* crgctrl */
static const struct hisi_fixed_factor_clock hi3660_crg_fixed_factor_clks[] = {
{ HI3660_FACTOR_UART3, "clk_factor_uart3", "iomcu_peri0", 1, 16, 0, },
{ HI3660_CLK_FACTOR_MMC, "clk_factor_mmc", "clkin_sys", 1, 6, 0, },
{ HI3660_CLK_GATE_I2C0, "clk_gate_i2c0", "clk_i2c0_iomcu", 1, 4, 0, },
{ HI3660_CLK_GATE_I2C1, "clk_gate_i2c1", "clk_i2c1_iomcu", 1, 4, 0, },
{ HI3660_CLK_GATE_I2C2, "clk_gate_i2c2", "clk_i2c2_iomcu", 1, 4, 0, },
{ HI3660_CLK_GATE_I2C6, "clk_gate_i2c6", "clk_i2c6_iomcu", 1, 4, 0, },
{ HI3660_CLK_DIV_SYSBUS, "clk_div_sysbus", "clk_mux_sysbus", 1, 7, 0, },
{ HI3660_CLK_DIV_320M, "clk_div_320m", "clk_320m_pll_gt", 1, 5, 0, },
{ HI3660_CLK_DIV_A53, "clk_div_a53hpm", "clk_a53hpm_andgt", 1, 6, 0, },
{ HI3660_CLK_GATE_SPI0, "clk_gate_spi0", "clk_ppll0", 1, 8, 0, },
{ HI3660_CLK_GATE_SPI2, "clk_gate_spi2", "clk_ppll0", 1, 8, 0, },
{ HI3660_PCIEPHY_REF, "clk_pciephy_ref", "clk_div_pciephy", 1, 1, 0, },
{ HI3660_CLK_ABB_USB, "clk_abb_usb", "clk_gate_usb_tcxo_en", 1, 1, 0 },
{ HI3660_VENC_VOLT_HOLD, "venc_volt_hold", "peri_volt_hold", 1, 1, 0, },
{ HI3660_CLK_FAC_ISP_SNCLK, "clk_isp_snclk_fac", "clk_isp_snclk_angt",
1, 10, 0, },
};
static const struct hisi_gate_clock hi3660_crgctrl_gate_sep_clks[] = {
{ HI3660_PERI_VOLT_HOLD, "peri_volt_hold", "clkin_sys",
CLK_SET_RATE_PARENT, 0x0, 0, 0, },
{ HI3660_HCLK_GATE_SDIO0, "hclk_gate_sdio0", "clk_div_sysbus",
CLK_SET_RATE_PARENT, 0x0, 21, 0, },
{ HI3660_HCLK_GATE_SD, "hclk_gate_sd", "clk_div_sysbus",
CLK_SET_RATE_PARENT, 0x0, 30, 0, },
{ HI3660_CLK_GATE_AOMM, "clk_gate_aomm", "clk_div_aomm",
CLK_SET_RATE_PARENT, 0x0, 31, 0, },
{ HI3660_PCLK_GPIO0, "pclk_gpio0", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 0, 0, },
{ HI3660_PCLK_GPIO1, "pclk_gpio1", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 1, 0, },
{ HI3660_PCLK_GPIO2, "pclk_gpio2", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 2, 0, },
{ HI3660_PCLK_GPIO3, "pclk_gpio3", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 3, 0, },
{ HI3660_PCLK_GPIO4, "pclk_gpio4", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 4, 0, },
{ HI3660_PCLK_GPIO5, "pclk_gpio5", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 5, 0, },
{ HI3660_PCLK_GPIO6, "pclk_gpio6", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 6, 0, },
{ HI3660_PCLK_GPIO7, "pclk_gpio7", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 7, 0, },
{ HI3660_PCLK_GPIO8, "pclk_gpio8", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 8, 0, },
{ HI3660_PCLK_GPIO9, "pclk_gpio9", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 9, 0, },
{ HI3660_PCLK_GPIO10, "pclk_gpio10", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 10, 0, },
{ HI3660_PCLK_GPIO11, "pclk_gpio11", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 11, 0, },
{ HI3660_PCLK_GPIO12, "pclk_gpio12", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 12, 0, },
{ HI3660_PCLK_GPIO13, "pclk_gpio13", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 13, 0, },
{ HI3660_PCLK_GPIO14, "pclk_gpio14", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 14, 0, },
{ HI3660_PCLK_GPIO15, "pclk_gpio15", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 15, 0, },
{ HI3660_PCLK_GPIO16, "pclk_gpio16", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 16, 0, },
{ HI3660_PCLK_GPIO17, "pclk_gpio17", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 17, 0, },
{ HI3660_PCLK_GPIO18, "pclk_gpio18", "clk_div_ioperi",
CLK_SET_RATE_PARENT, 0x10, 18, 0, },
{ HI3660_PCLK_GPIO19, "pclk_gpio19", "clk_div_ioperi",
CLK_SET_RATE_PARENT, 0x10, 19, 0, },
{ HI3660_PCLK_GPIO20, "pclk_gpio20", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 20, 0, },
{ HI3660_PCLK_GPIO21, "pclk_gpio21", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x10, 21, 0, },
{ HI3660_CLK_GATE_SPI3, "clk_gate_spi3", "clk_div_ioperi",
CLK_SET_RATE_PARENT, 0x10, 30, 0, },
{ HI3660_CLK_GATE_I2C7, "clk_gate_i2c7", "clk_mux_i2c",
CLK_SET_RATE_PARENT, 0x10, 31, 0, },
{ HI3660_CLK_GATE_I2C3, "clk_gate_i2c3", "clk_mux_i2c",
CLK_SET_RATE_PARENT, 0x20, 7, 0, },
{ HI3660_CLK_GATE_SPI1, "clk_gate_spi1", "clk_mux_spi",
CLK_SET_RATE_PARENT, 0x20, 9, 0, },
{ HI3660_CLK_GATE_UART1, "clk_gate_uart1", "clk_mux_uarth",
CLK_SET_RATE_PARENT, 0x20, 11, 0, },
{ HI3660_CLK_GATE_UART2, "clk_gate_uart2", "clk_mux_uart1",
CLK_SET_RATE_PARENT, 0x20, 12, 0, },
{ HI3660_CLK_GATE_UART4, "clk_gate_uart4", "clk_mux_uarth",
CLK_SET_RATE_PARENT, 0x20, 14, 0, },
{ HI3660_CLK_GATE_UART5, "clk_gate_uart5", "clk_mux_uart1",
CLK_SET_RATE_PARENT, 0x20, 15, 0, },
{ HI3660_CLK_GATE_I2C4, "clk_gate_i2c4", "clk_mux_i2c",
CLK_SET_RATE_PARENT, 0x20, 27, 0, },
{ HI3660_CLK_GATE_DMAC, "clk_gate_dmac", "clk_div_sysbus",
CLK_SET_RATE_PARENT, 0x30, 1, 0, },
{ HI3660_CLK_GATE_VENC, "clk_gate_venc", "clk_div_venc",
CLK_SET_RATE_PARENT, 0x30, 10, 0, },
{ HI3660_CLK_GATE_VDEC, "clk_gate_vdec", "clk_div_vdec",
CLK_SET_RATE_PARENT, 0x30, 11, 0, },
{ HI3660_PCLK_GATE_DSS, "pclk_gate_dss", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x30, 12, 0, },
{ HI3660_ACLK_GATE_DSS, "aclk_gate_dss", "clk_gate_vivobus",
CLK_SET_RATE_PARENT, 0x30, 13, 0, },
{ HI3660_CLK_GATE_LDI1, "clk_gate_ldi1", "clk_div_ldi1",
CLK_SET_RATE_PARENT, 0x30, 14, 0, },
{ HI3660_CLK_GATE_LDI0, "clk_gate_ldi0", "clk_div_ldi0",
CLK_SET_RATE_PARENT, 0x30, 15, 0, },
{ HI3660_CLK_GATE_VIVOBUS, "clk_gate_vivobus", "clk_div_vivobus",
CLK_SET_RATE_PARENT, 0x30, 16, 0, },
{ HI3660_CLK_GATE_EDC0, "clk_gate_edc0", "clk_div_edc0",
CLK_SET_RATE_PARENT, 0x30, 17, 0, },
{ HI3660_CLK_GATE_TXDPHY0_CFG, "clk_gate_txdphy0_cfg", "clkin_sys",
CLK_SET_RATE_PARENT, 0x30, 28, 0, },
{ HI3660_CLK_GATE_TXDPHY0_REF, "clk_gate_txdphy0_ref", "clkin_sys",
CLK_SET_RATE_PARENT, 0x30, 29, 0, },
{ HI3660_CLK_GATE_TXDPHY1_CFG, "clk_gate_txdphy1_cfg", "clkin_sys",
CLK_SET_RATE_PARENT, 0x30, 30, 0, },
{ HI3660_CLK_GATE_TXDPHY1_REF, "clk_gate_txdphy1_ref", "clkin_sys",
CLK_SET_RATE_PARENT, 0x30, 31, 0, },
{ HI3660_ACLK_GATE_USB3OTG, "aclk_gate_usb3otg", "clk_div_mmc0bus",
CLK_SET_RATE_PARENT, 0x40, 1, 0, },
{ HI3660_CLK_GATE_SPI4, "clk_gate_spi4", "clk_mux_spi",
CLK_SET_RATE_PARENT, 0x40, 4, 0, },
{ HI3660_CLK_GATE_SD, "clk_gate_sd", "clk_mux_sd_sys",
CLK_SET_RATE_PARENT, 0x40, 17, 0, },
{ HI3660_CLK_GATE_SDIO0, "clk_gate_sdio0", "clk_mux_sdio_sys",
CLK_SET_RATE_PARENT, 0x40, 19, 0, },
{ HI3660_CLK_GATE_ISP_SNCLK0, "clk_gate_isp_snclk0",
"clk_isp_snclk_mux", CLK_SET_RATE_PARENT, 0x50, 16, 0, },
{ HI3660_CLK_GATE_ISP_SNCLK1, "clk_gate_isp_snclk1",
"clk_isp_snclk_mux", CLK_SET_RATE_PARENT, 0x50, 17, 0, },
{ HI3660_CLK_GATE_ISP_SNCLK2, "clk_gate_isp_snclk2",
"clk_isp_snclk_mux", CLK_SET_RATE_PARENT, 0x50, 18, 0, },
/*
* clk_gate_ufs_subsys is a system bus clock, mark it as critical
* clock and keep it on for system suspend and resume.
*/
{ HI3660_CLK_GATE_UFS_SUBSYS, "clk_gate_ufs_subsys", "clk_div_sysbus",
CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0x50, 21, 0, },
{ HI3660_PCLK_GATE_DSI0, "pclk_gate_dsi0", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x50, 28, 0, },
{ HI3660_PCLK_GATE_DSI1, "pclk_gate_dsi1", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x50, 29, 0, },
{ HI3660_ACLK_GATE_PCIE, "aclk_gate_pcie", "clk_div_mmc1bus",
CLK_SET_RATE_PARENT, 0x420, 5, 0, },
{ HI3660_PCLK_GATE_PCIE_SYS, "pclk_gate_pcie_sys", "clk_div_mmc1bus",
CLK_SET_RATE_PARENT, 0x420, 7, 0, },
{ HI3660_CLK_GATE_PCIEAUX, "clk_gate_pcieaux", "clkin_sys",
CLK_SET_RATE_PARENT, 0x420, 8, 0, },
{ HI3660_PCLK_GATE_PCIE_PHY, "pclk_gate_pcie_phy", "clk_div_mmc1bus",
CLK_SET_RATE_PARENT, 0x420, 9, 0, },
};
static const struct hisi_gate_clock hi3660_crgctrl_gate_clks[] = {
{ HI3660_CLK_ANDGT_LDI0, "clk_andgt_ldi0", "clk_mux_ldi0",
CLK_SET_RATE_PARENT, 0xf0, 6, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_LDI1, "clk_andgt_ldi1", "clk_mux_ldi1",
CLK_SET_RATE_PARENT, 0xf0, 7, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_EDC0, "clk_andgt_edc0", "clk_mux_edc0",
CLK_SET_RATE_PARENT, 0xf0, 8, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_VDEC, "clk_andgt_vdec", "clk_mux_vdec",
CLK_SET_RATE_PARENT, 0xf0, 15, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_VENC, "clk_andgt_venc", "clk_mux_venc",
CLK_SET_RATE_PARENT, 0xf4, 0, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_GATE_UFSPHY_GT, "clk_gate_ufsphy_gt", "clk_div_ufsperi",
CLK_SET_RATE_PARENT, 0xf4, 1, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_MMC, "clk_andgt_mmc", "clk_mux_mmc_pll",
CLK_SET_RATE_PARENT, 0xf4, 2, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_SD, "clk_andgt_sd", "clk_mux_sd_pll",
CLK_SET_RATE_PARENT, 0xf4, 3, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_A53HPM_ANDGT, "clk_a53hpm_andgt", "clk_mux_a53hpm",
CLK_SET_RATE_PARENT, 0xf4, 7, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_SDIO, "clk_andgt_sdio", "clk_mux_sdio_pll",
CLK_SET_RATE_PARENT, 0xf4, 8, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_UART0, "clk_andgt_uart0", "clk_div_320m",
CLK_SET_RATE_PARENT, 0xf4, 9, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_UART1, "clk_andgt_uart1", "clk_div_320m",
CLK_SET_RATE_PARENT, 0xf4, 10, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_UARTH, "clk_andgt_uarth", "clk_div_320m",
CLK_SET_RATE_PARENT, 0xf4, 11, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_ANDGT_SPI, "clk_andgt_spi", "clk_div_320m",
CLK_SET_RATE_PARENT, 0xf4, 13, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_VIVOBUS_ANDGT, "clk_vivobus_andgt", "clk_mux_vivobus",
CLK_SET_RATE_PARENT, 0xf8, 1, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_AOMM_ANDGT, "clk_aomm_andgt", "clk_ppll2",
CLK_SET_RATE_PARENT, 0xf8, 3, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_320M_PLL_GT, "clk_320m_pll_gt", "clk_mux_320m",
CLK_SET_RATE_PARENT, 0xf8, 10, 0, },
{ HI3660_CLK_ANGT_ISP_SNCLK, "clk_isp_snclk_angt", "clk_div_a53hpm",
CLK_SET_RATE_PARENT, 0x108, 2, CLK_GATE_HIWORD_MASK, },
{ HI3660_AUTODIV_EMMC0BUS, "autodiv_emmc0bus", "autodiv_sysbus",
CLK_SET_RATE_PARENT, 0x404, 1, CLK_GATE_HIWORD_MASK, },
{ HI3660_AUTODIV_SYSBUS, "autodiv_sysbus", "clk_div_sysbus",
CLK_SET_RATE_PARENT, 0x404, 5, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_GATE_UFSPHY_CFG, "clk_gate_ufsphy_cfg",
"clk_div_ufsphy_cfg", CLK_SET_RATE_PARENT, 0x420, 12, 0, },
{ HI3660_CLK_GATE_UFSIO_REF, "clk_gate_ufsio_ref",
"clk_gate_ufs_tcxo_en", CLK_SET_RATE_PARENT, 0x420, 14, 0, },
};
static const char *const
clk_mux_sysbus_p[] = {"clk_ppll1", "clk_ppll0"};
static const char *const
clk_mux_sdio_sys_p[] = {"clk_factor_mmc", "clk_div_sdio",};
static const char *const
clk_mux_sd_sys_p[] = {"clk_factor_mmc", "clk_div_sd",};
static const char *const
clk_mux_pll_p[] = {"clk_ppll0", "clk_ppll1", "clk_ppll2", "clk_ppll2",};
static const char *const
clk_mux_pll0123_p[] = {"clk_ppll0", "clk_ppll1", "clk_ppll2", "clk_ppll3",};
static const char *const
clk_mux_edc0_p[] = {"clk_inv", "clk_ppll0", "clk_ppll1", "clk_inv",
"clk_ppll2", "clk_inv", "clk_inv", "clk_inv",
"clk_ppll3", "clk_inv", "clk_inv", "clk_inv",
"clk_inv", "clk_inv", "clk_inv", "clk_inv",};
static const char *const
clk_mux_ldi0_p[] = {"clk_inv", "clk_ppll0", "clk_ppll2", "clk_inv",
"clk_ppll1", "clk_inv", "clk_inv", "clk_inv",
"clk_ppll3", "clk_inv", "clk_inv", "clk_inv",
"clk_inv", "clk_inv", "clk_inv", "clk_inv",};
static const char *const
clk_mux_uart0_p[] = {"clkin_sys", "clk_div_uart0",};
static const char *const
clk_mux_uart1_p[] = {"clkin_sys", "clk_div_uart1",};
static const char *const
clk_mux_uarth_p[] = {"clkin_sys", "clk_div_uarth",};
static const char *const
clk_mux_pll02p[] = {"clk_ppll0", "clk_ppll2",};
static const char *const
clk_mux_ioperi_p[] = {"clk_div_320m", "clk_div_a53hpm",};
static const char *const
clk_mux_spi_p[] = {"clkin_sys", "clk_div_spi",};
static const char *const
clk_mux_i2c_p[] = {"clkin_sys", "clk_div_i2c",};
static const char *const
clk_mux_venc_p[] = {"clk_ppll0", "clk_ppll1", "clk_ppll3", "clk_ppll3",};
static const char *const
clk_mux_isp_snclk_p[] = {"clkin_sys", "clk_isp_snclk_div"};
static const struct hisi_mux_clock hi3660_crgctrl_mux_clks[] = {
{ HI3660_CLK_MUX_SYSBUS, "clk_mux_sysbus", clk_mux_sysbus_p,
ARRAY_SIZE(clk_mux_sysbus_p), CLK_SET_RATE_PARENT, 0xac, 0, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_UART0, "clk_mux_uart0", clk_mux_uart0_p,
ARRAY_SIZE(clk_mux_uart0_p), CLK_SET_RATE_PARENT, 0xac, 2, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_UART1, "clk_mux_uart1", clk_mux_uart1_p,
ARRAY_SIZE(clk_mux_uart1_p), CLK_SET_RATE_PARENT, 0xac, 3, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_UARTH, "clk_mux_uarth", clk_mux_uarth_p,
ARRAY_SIZE(clk_mux_uarth_p), CLK_SET_RATE_PARENT, 0xac, 4, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_SPI, "clk_mux_spi", clk_mux_spi_p,
ARRAY_SIZE(clk_mux_spi_p), CLK_SET_RATE_PARENT, 0xac, 8, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_I2C, "clk_mux_i2c", clk_mux_i2c_p,
ARRAY_SIZE(clk_mux_i2c_p), CLK_SET_RATE_PARENT, 0xac, 13, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_MMC_PLL, "clk_mux_mmc_pll", clk_mux_pll02p,
ARRAY_SIZE(clk_mux_pll02p), CLK_SET_RATE_PARENT, 0xb4, 0, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_LDI1, "clk_mux_ldi1", clk_mux_ldi0_p,
ARRAY_SIZE(clk_mux_ldi0_p), CLK_SET_RATE_PARENT, 0xb4, 8, 4,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_LDI0, "clk_mux_ldi0", clk_mux_ldi0_p,
ARRAY_SIZE(clk_mux_ldi0_p), CLK_SET_RATE_PARENT, 0xb4, 12, 4,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_SD_PLL, "clk_mux_sd_pll", clk_mux_pll_p,
ARRAY_SIZE(clk_mux_pll_p), CLK_SET_RATE_PARENT, 0xb8, 4, 2,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_SD_SYS, "clk_mux_sd_sys", clk_mux_sd_sys_p,
ARRAY_SIZE(clk_mux_sd_sys_p), CLK_SET_RATE_PARENT, 0xb8, 6, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_EDC0, "clk_mux_edc0", clk_mux_edc0_p,
ARRAY_SIZE(clk_mux_edc0_p), CLK_SET_RATE_PARENT, 0xbc, 6, 4,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_SDIO_SYS, "clk_mux_sdio_sys", clk_mux_sdio_sys_p,
ARRAY_SIZE(clk_mux_sdio_sys_p), CLK_SET_RATE_PARENT, 0xc0, 6, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_SDIO_PLL, "clk_mux_sdio_pll", clk_mux_pll_p,
ARRAY_SIZE(clk_mux_pll_p), CLK_SET_RATE_PARENT, 0xc0, 4, 2,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_VENC, "clk_mux_venc", clk_mux_venc_p,
ARRAY_SIZE(clk_mux_venc_p), CLK_SET_RATE_PARENT, 0xc8, 11, 2,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_VDEC, "clk_mux_vdec", clk_mux_pll0123_p,
ARRAY_SIZE(clk_mux_pll0123_p), CLK_SET_RATE_PARENT, 0xcc, 5, 2,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_VIVOBUS, "clk_mux_vivobus", clk_mux_pll0123_p,
ARRAY_SIZE(clk_mux_pll0123_p), CLK_SET_RATE_PARENT, 0xd0, 12, 2,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_A53HPM, "clk_mux_a53hpm", clk_mux_pll02p,
ARRAY_SIZE(clk_mux_pll02p), CLK_SET_RATE_PARENT, 0xd4, 9, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_320M, "clk_mux_320m", clk_mux_pll02p,
ARRAY_SIZE(clk_mux_pll02p), CLK_SET_RATE_PARENT, 0x100, 0, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_ISP_SNCLK, "clk_isp_snclk_mux", clk_mux_isp_snclk_p,
ARRAY_SIZE(clk_mux_isp_snclk_p), CLK_SET_RATE_PARENT, 0x108, 3, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_MUX_IOPERI, "clk_mux_ioperi", clk_mux_ioperi_p,
ARRAY_SIZE(clk_mux_ioperi_p), CLK_SET_RATE_PARENT, 0x108, 10, 1,
CLK_MUX_HIWORD_MASK, },
};
static const struct hisi_divider_clock hi3660_crgctrl_divider_clks[] = {
{ HI3660_CLK_DIV_UART0, "clk_div_uart0", "clk_andgt_uart0",
CLK_SET_RATE_PARENT, 0xb0, 4, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_UART1, "clk_div_uart1", "clk_andgt_uart1",
CLK_SET_RATE_PARENT, 0xb0, 8, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_UARTH, "clk_div_uarth", "clk_andgt_uarth",
CLK_SET_RATE_PARENT, 0xb0, 12, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_MMC, "clk_div_mmc", "clk_andgt_mmc",
CLK_SET_RATE_PARENT, 0xb4, 3, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_SD, "clk_div_sd", "clk_andgt_sd",
CLK_SET_RATE_PARENT, 0xb8, 0, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_EDC0, "clk_div_edc0", "clk_andgt_edc0",
CLK_SET_RATE_PARENT, 0xbc, 0, 6, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_LDI0, "clk_div_ldi0", "clk_andgt_ldi0",
CLK_SET_RATE_PARENT, 0xbc, 10, 6, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_SDIO, "clk_div_sdio", "clk_andgt_sdio",
CLK_SET_RATE_PARENT, 0xc0, 0, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_LDI1, "clk_div_ldi1", "clk_andgt_ldi1",
CLK_SET_RATE_PARENT, 0xc0, 8, 6, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_SPI, "clk_div_spi", "clk_andgt_spi",
CLK_SET_RATE_PARENT, 0xc4, 12, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_VENC, "clk_div_venc", "clk_andgt_venc",
CLK_SET_RATE_PARENT, 0xc8, 6, 5, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_VDEC, "clk_div_vdec", "clk_andgt_vdec",
CLK_SET_RATE_PARENT, 0xcc, 0, 5, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_VIVOBUS, "clk_div_vivobus", "clk_vivobus_andgt",
CLK_SET_RATE_PARENT, 0xd0, 7, 5, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_I2C, "clk_div_i2c", "clk_div_320m",
CLK_SET_RATE_PARENT, 0xe8, 4, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_UFSPHY, "clk_div_ufsphy_cfg", "clk_gate_ufsphy_gt",
CLK_SET_RATE_PARENT, 0xe8, 9, 2, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_CFGBUS, "clk_div_cfgbus", "clk_div_sysbus",
CLK_SET_RATE_PARENT, 0xec, 0, 2, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_MMC0BUS, "clk_div_mmc0bus", "autodiv_emmc0bus",
CLK_SET_RATE_PARENT, 0xec, 2, 1, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_MMC1BUS, "clk_div_mmc1bus", "clk_div_sysbus",
CLK_SET_RATE_PARENT, 0xec, 3, 1, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_UFSPERI, "clk_div_ufsperi", "clk_gate_ufs_subsys",
CLK_SET_RATE_PARENT, 0xec, 14, 1, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_AOMM, "clk_div_aomm", "clk_aomm_andgt",
CLK_SET_RATE_PARENT, 0x100, 7, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_ISP_SNCLK, "clk_isp_snclk_div", "clk_isp_snclk_fac",
CLK_SET_RATE_PARENT, 0x108, 0, 2, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_IOPERI, "clk_div_ioperi", "clk_mux_ioperi",
CLK_SET_RATE_PARENT, 0x108, 11, 4, CLK_DIVIDER_HIWORD_MASK, },
};
/* clk_pmuctrl */
/* pmu register need shift 2 bits */
static const struct hisi_gate_clock hi3660_pmu_gate_clks[] = {
{ HI3660_GATE_ABB_192, "clk_gate_abb_192", "clkin_sys",
CLK_SET_RATE_PARENT, (0x10a << 2), 3, 0, },
};
/* clk_pctrl */
static const struct hisi_gate_clock hi3660_pctrl_gate_clks[] = {
{ HI3660_GATE_UFS_TCXO_EN, "clk_gate_ufs_tcxo_en",
"clk_gate_abb_192", CLK_SET_RATE_PARENT, 0x10, 0,
CLK_GATE_HIWORD_MASK, },
{ HI3660_GATE_USB_TCXO_EN, "clk_gate_usb_tcxo_en", "clk_gate_abb_192",
CLK_SET_RATE_PARENT, 0x10, 1, CLK_GATE_HIWORD_MASK, },
};
/* clk_sctrl */
static const struct hisi_gate_clock hi3660_sctrl_gate_sep_clks[] = {
{ HI3660_PCLK_AO_GPIO0, "pclk_ao_gpio0", "clk_div_aobus",
CLK_SET_RATE_PARENT, 0x160, 11, 0, },
{ HI3660_PCLK_AO_GPIO1, "pclk_ao_gpio1", "clk_div_aobus",
CLK_SET_RATE_PARENT, 0x160, 12, 0, },
{ HI3660_PCLK_AO_GPIO2, "pclk_ao_gpio2", "clk_div_aobus",
CLK_SET_RATE_PARENT, 0x160, 13, 0, },
{ HI3660_PCLK_AO_GPIO3, "pclk_ao_gpio3", "clk_div_aobus",
CLK_SET_RATE_PARENT, 0x160, 14, 0, },
{ HI3660_PCLK_AO_GPIO4, "pclk_ao_gpio4", "clk_div_aobus",
CLK_SET_RATE_PARENT, 0x160, 21, 0, },
{ HI3660_PCLK_AO_GPIO5, "pclk_ao_gpio5", "clk_div_aobus",
CLK_SET_RATE_PARENT, 0x160, 22, 0, },
{ HI3660_PCLK_AO_GPIO6, "pclk_ao_gpio6", "clk_div_aobus",
CLK_SET_RATE_PARENT, 0x160, 25, 0, },
{ HI3660_PCLK_GATE_MMBUF, "pclk_gate_mmbuf", "pclk_div_mmbuf",
CLK_SET_RATE_PARENT, 0x170, 23, 0, },
{ HI3660_CLK_GATE_DSS_AXI_MM, "clk_gate_dss_axi_mm", "aclk_mux_mmbuf",
CLK_SET_RATE_PARENT, 0x170, 24, 0, },
};
static const struct hisi_gate_clock hi3660_sctrl_gate_clks[] = {
{ HI3660_PCLK_MMBUF_ANDGT, "pclk_mmbuf_andgt", "clk_sw_mmbuf",
CLK_SET_RATE_PARENT, 0x258, 7, CLK_GATE_HIWORD_MASK, },
{ HI3660_CLK_MMBUF_PLL_ANDGT, "clk_mmbuf_pll_andgt", "clk_ppll0",
CLK_SET_RATE_PARENT, 0x260, 11, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_FLL_MMBUF_ANDGT, "clk_fll_mmbuf_andgt", "clk_fll_src",
CLK_SET_RATE_PARENT, 0x260, 12, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_SYS_MMBUF_ANDGT, "clk_sys_mmbuf_andgt", "clkin_sys",
CLK_SET_RATE_PARENT, 0x260, 13, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_GATE_PCIEPHY_GT, "clk_gate_pciephy_gt", "clk_ppll0",
CLK_SET_RATE_PARENT, 0x268, 11, CLK_DIVIDER_HIWORD_MASK, },
};
static const char *const
aclk_mux_mmbuf_p[] = {"aclk_div_mmbuf", "clk_gate_aomm",};
static const char *const
clk_sw_mmbuf_p[] = {"clk_sys_mmbuf_andgt", "clk_fll_mmbuf_andgt",
"aclk_mux_mmbuf", "aclk_mux_mmbuf"};
static const struct hisi_mux_clock hi3660_sctrl_mux_clks[] = {
{ HI3660_ACLK_MUX_MMBUF, "aclk_mux_mmbuf", aclk_mux_mmbuf_p,
ARRAY_SIZE(aclk_mux_mmbuf_p), CLK_SET_RATE_PARENT, 0x250, 12, 1,
CLK_MUX_HIWORD_MASK, },
{ HI3660_CLK_SW_MMBUF, "clk_sw_mmbuf", clk_sw_mmbuf_p,
ARRAY_SIZE(clk_sw_mmbuf_p), CLK_SET_RATE_PARENT, 0x258, 8, 2,
CLK_MUX_HIWORD_MASK, },
};
static const struct hisi_divider_clock hi3660_sctrl_divider_clks[] = {
{ HI3660_CLK_DIV_AOBUS, "clk_div_aobus", "clk_ppll0",
CLK_SET_RATE_PARENT, 0x254, 0, 6, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_PCLK_DIV_MMBUF, "pclk_div_mmbuf", "pclk_mmbuf_andgt",
CLK_SET_RATE_PARENT, 0x258, 10, 2, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_ACLK_DIV_MMBUF, "aclk_div_mmbuf", "clk_mmbuf_pll_andgt",
CLK_SET_RATE_PARENT, 0x258, 12, 4, CLK_DIVIDER_HIWORD_MASK, },
{ HI3660_CLK_DIV_PCIEPHY, "clk_div_pciephy", "clk_gate_pciephy_gt",
CLK_SET_RATE_PARENT, 0x268, 12, 4, CLK_DIVIDER_HIWORD_MASK, },
};
/* clk_iomcu */
static const struct hisi_gate_clock hi3660_iomcu_gate_sep_clks[] = {
{ HI3660_CLK_I2C0_IOMCU, "clk_i2c0_iomcu", "clk_fll_src",
CLK_SET_RATE_PARENT, 0x10, 3, 0, },
{ HI3660_CLK_I2C1_IOMCU, "clk_i2c1_iomcu", "clk_fll_src",
CLK_SET_RATE_PARENT, 0x10, 4, 0, },
{ HI3660_CLK_I2C2_IOMCU, "clk_i2c2_iomcu", "clk_fll_src",
CLK_SET_RATE_PARENT, 0x10, 5, 0, },
{ HI3660_CLK_I2C6_IOMCU, "clk_i2c6_iomcu", "clk_fll_src",
CLK_SET_RATE_PARENT, 0x10, 27, 0, },
{ HI3660_CLK_IOMCU_PERI0, "iomcu_peri0", "clk_ppll0",
CLK_SET_RATE_PARENT, 0x90, 0, 0, },
};
static struct hisi_clock_data *clk_crgctrl_data;
static void hi3660_clk_iomcu_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
int nr = ARRAY_SIZE(hi3660_iomcu_gate_sep_clks);
clk_data = hisi_clk_init(np, nr);
if (!clk_data)
return;
hisi_clk_register_gate_sep(hi3660_iomcu_gate_sep_clks,
ARRAY_SIZE(hi3660_iomcu_gate_sep_clks),
clk_data);
}
static void hi3660_clk_pmuctrl_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
int nr = ARRAY_SIZE(hi3660_pmu_gate_clks);
clk_data = hisi_clk_init(np, nr);
if (!clk_data)
return;
hisi_clk_register_gate(hi3660_pmu_gate_clks,
ARRAY_SIZE(hi3660_pmu_gate_clks), clk_data);
}
static void hi3660_clk_pctrl_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
int nr = ARRAY_SIZE(hi3660_pctrl_gate_clks);
clk_data = hisi_clk_init(np, nr);
if (!clk_data)
return;
hisi_clk_register_gate(hi3660_pctrl_gate_clks,
ARRAY_SIZE(hi3660_pctrl_gate_clks), clk_data);
}
static void hi3660_clk_sctrl_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
int nr = ARRAY_SIZE(hi3660_sctrl_gate_clks) +
ARRAY_SIZE(hi3660_sctrl_gate_sep_clks) +
ARRAY_SIZE(hi3660_sctrl_mux_clks) +
ARRAY_SIZE(hi3660_sctrl_divider_clks);
clk_data = hisi_clk_init(np, nr);
if (!clk_data)
return;
hisi_clk_register_gate(hi3660_sctrl_gate_clks,
ARRAY_SIZE(hi3660_sctrl_gate_clks), clk_data);
hisi_clk_register_gate_sep(hi3660_sctrl_gate_sep_clks,
ARRAY_SIZE(hi3660_sctrl_gate_sep_clks),
clk_data);
hisi_clk_register_mux(hi3660_sctrl_mux_clks,
ARRAY_SIZE(hi3660_sctrl_mux_clks), clk_data);
hisi_clk_register_divider(hi3660_sctrl_divider_clks,
ARRAY_SIZE(hi3660_sctrl_divider_clks),
clk_data);
}
static void hi3660_clk_crgctrl_early_init(struct device_node *np)
{
int nr = ARRAY_SIZE(hi3660_fixed_rate_clks) +
ARRAY_SIZE(hi3660_crgctrl_gate_sep_clks) +
ARRAY_SIZE(hi3660_crgctrl_gate_clks) +
ARRAY_SIZE(hi3660_crgctrl_mux_clks) +
ARRAY_SIZE(hi3660_crg_fixed_factor_clks) +
ARRAY_SIZE(hi3660_crgctrl_divider_clks);
int i;
clk_crgctrl_data = hisi_clk_init(np, nr);
if (!clk_crgctrl_data)
return;
for (i = 0; i < nr; i++)
clk_crgctrl_data->clk_data.clks[i] = ERR_PTR(-EPROBE_DEFER);
hisi_clk_register_fixed_rate(hi3660_fixed_rate_clks,
ARRAY_SIZE(hi3660_fixed_rate_clks),
clk_crgctrl_data);
}
CLK_OF_DECLARE_DRIVER(hi3660_clk_crgctrl, "hisilicon,hi3660-crgctrl",
hi3660_clk_crgctrl_early_init);
static void hi3660_clk_crgctrl_init(struct device_node *np)
{
struct clk **clks;
int i;
if (!clk_crgctrl_data)
hi3660_clk_crgctrl_early_init(np);
/* clk_crgctrl_data initialization failed */
if (!clk_crgctrl_data)
return;
hisi_clk_register_gate_sep(hi3660_crgctrl_gate_sep_clks,
ARRAY_SIZE(hi3660_crgctrl_gate_sep_clks),
clk_crgctrl_data);
hisi_clk_register_gate(hi3660_crgctrl_gate_clks,
ARRAY_SIZE(hi3660_crgctrl_gate_clks),
clk_crgctrl_data);
hisi_clk_register_mux(hi3660_crgctrl_mux_clks,
ARRAY_SIZE(hi3660_crgctrl_mux_clks),
clk_crgctrl_data);
hisi_clk_register_fixed_factor(hi3660_crg_fixed_factor_clks,
ARRAY_SIZE(hi3660_crg_fixed_factor_clks),
clk_crgctrl_data);
hisi_clk_register_divider(hi3660_crgctrl_divider_clks,
ARRAY_SIZE(hi3660_crgctrl_divider_clks),
clk_crgctrl_data);
clks = clk_crgctrl_data->clk_data.clks;
for (i = 0; i < clk_crgctrl_data->clk_data.clk_num; i++) {
if (IS_ERR(clks[i]) && PTR_ERR(clks[i]) != -EPROBE_DEFER)
pr_err("Failed to register crgctrl clock[%d] err=%ld\n",
i, PTR_ERR(clks[i]));
}
}
static const struct of_device_id hi3660_clk_match_table[] = {
{ .compatible = "hisilicon,hi3660-crgctrl",
.data = hi3660_clk_crgctrl_init },
{ .compatible = "hisilicon,hi3660-pctrl",
.data = hi3660_clk_pctrl_init },
{ .compatible = "hisilicon,hi3660-pmuctrl",
.data = hi3660_clk_pmuctrl_init },
{ .compatible = "hisilicon,hi3660-sctrl",
.data = hi3660_clk_sctrl_init },
{ .compatible = "hisilicon,hi3660-iomcu",
.data = hi3660_clk_iomcu_init },
{ }
};
static int hi3660_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
void (*init_func)(struct device_node *np);
init_func = of_device_get_match_data(dev);
if (!init_func)
return -ENODEV;
init_func(np);
return 0;
}
static struct platform_driver hi3660_clk_driver = {
.probe = hi3660_clk_probe,
.driver = {
.name = "hi3660-clk",
.of_match_table = hi3660_clk_match_table,
},
};
static int __init hi3660_clk_init(void)
{
return platform_driver_register(&hi3660_clk_driver);
}
core_initcall(hi3660_clk_init);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,274 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Hi6220 stub clock driver
*
* Copyright (c) 2015 Hisilicon Limited.
* Copyright (c) 2015 Linaro Limited.
*
* Author: Leo Yan <leo.yan@linaro.org>
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/mailbox_client.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* Stub clocks id */
#define HI6220_STUB_ACPU0 0
#define HI6220_STUB_ACPU1 1
#define HI6220_STUB_GPU 2
#define HI6220_STUB_DDR 5
/* Mailbox message */
#define HI6220_MBOX_MSG_LEN 8
#define HI6220_MBOX_FREQ 0xA
#define HI6220_MBOX_CMD_SET 0x3
#define HI6220_MBOX_OBJ_AP 0x0
/* CPU dynamic frequency scaling */
#define ACPU_DFS_FREQ_MAX 0x1724
#define ACPU_DFS_CUR_FREQ 0x17CC
#define ACPU_DFS_FLAG 0x1B30
#define ACPU_DFS_FREQ_REQ 0x1B34
#define ACPU_DFS_FREQ_LMT 0x1B38
#define ACPU_DFS_LOCK_FLAG 0xAEAEAEAE
#define to_stub_clk(hw) container_of(hw, struct hi6220_stub_clk, hw)
struct hi6220_stub_clk {
u32 id;
struct device *dev;
struct clk_hw hw;
struct regmap *dfs_map;
struct mbox_client cl;
struct mbox_chan *mbox;
};
struct hi6220_mbox_msg {
unsigned char type;
unsigned char cmd;
unsigned char obj;
unsigned char src;
unsigned char para[4];
};
union hi6220_mbox_data {
unsigned int data[HI6220_MBOX_MSG_LEN];
struct hi6220_mbox_msg msg;
};
static unsigned int hi6220_acpu_get_freq(struct hi6220_stub_clk *stub_clk)
{
unsigned int freq;
regmap_read(stub_clk->dfs_map, ACPU_DFS_CUR_FREQ, &freq);
return freq;
}
static int hi6220_acpu_set_freq(struct hi6220_stub_clk *stub_clk,
unsigned int freq)
{
union hi6220_mbox_data data;
/* set the frequency in sram */
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, freq);
/* compound mailbox message */
data.msg.type = HI6220_MBOX_FREQ;
data.msg.cmd = HI6220_MBOX_CMD_SET;
data.msg.obj = HI6220_MBOX_OBJ_AP;
data.msg.src = HI6220_MBOX_OBJ_AP;
mbox_send_message(stub_clk->mbox, &data);
return 0;
}
static int hi6220_acpu_round_freq(struct hi6220_stub_clk *stub_clk,
unsigned int freq)
{
unsigned int limit_flag, limit_freq = UINT_MAX;
unsigned int max_freq;
/* check the constrained frequency */
regmap_read(stub_clk->dfs_map, ACPU_DFS_FLAG, &limit_flag);
if (limit_flag == ACPU_DFS_LOCK_FLAG)
regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, &limit_freq);
/* check the supported maximum frequency */
regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_MAX, &max_freq);
/* calculate the real maximum frequency */
max_freq = min(max_freq, limit_freq);
if (WARN_ON(freq > max_freq))
freq = max_freq;
return freq;
}
static unsigned long hi6220_stub_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u32 rate = 0;
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
switch (stub_clk->id) {
case HI6220_STUB_ACPU0:
rate = hi6220_acpu_get_freq(stub_clk);
/* convert from kHz to Hz */
rate *= 1000;
break;
default:
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
__func__, stub_clk->id);
break;
}
return rate;
}
static int hi6220_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
unsigned long new_rate = rate / 1000; /* kHz */
int ret = 0;
switch (stub_clk->id) {
case HI6220_STUB_ACPU0:
ret = hi6220_acpu_set_freq(stub_clk, new_rate);
if (ret < 0)
return ret;
break;
default:
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
__func__, stub_clk->id);
break;
}
pr_debug("%s: set rate=%ldkHz\n", __func__, new_rate);
return ret;
}
static int hi6220_stub_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
unsigned long new_rate = req->rate / 1000; /* kHz */
switch (stub_clk->id) {
case HI6220_STUB_ACPU0:
new_rate = hi6220_acpu_round_freq(stub_clk, new_rate);
/* convert from kHz to Hz */
new_rate *= 1000;
break;
default:
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
__func__, stub_clk->id);
break;
}
req->rate = new_rate;
return 0;
}
static const struct clk_ops hi6220_stub_clk_ops = {
.recalc_rate = hi6220_stub_clk_recalc_rate,
.determine_rate = hi6220_stub_clk_determine_rate,
.set_rate = hi6220_stub_clk_set_rate,
};
static int hi6220_stub_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct clk_init_data init;
struct hi6220_stub_clk *stub_clk;
struct clk *clk;
struct device_node *np = pdev->dev.of_node;
int ret;
stub_clk = devm_kzalloc(dev, sizeof(*stub_clk), GFP_KERNEL);
if (!stub_clk)
return -ENOMEM;
stub_clk->dfs_map = syscon_regmap_lookup_by_phandle(np,
"hisilicon,hi6220-clk-sram");
if (IS_ERR(stub_clk->dfs_map)) {
dev_err(dev, "failed to get sram regmap\n");
return PTR_ERR(stub_clk->dfs_map);
}
stub_clk->hw.init = &init;
stub_clk->dev = dev;
stub_clk->id = HI6220_STUB_ACPU0;
/* Use mailbox client with blocking mode */
stub_clk->cl.dev = dev;
stub_clk->cl.tx_done = NULL;
stub_clk->cl.tx_block = true;
stub_clk->cl.tx_tout = 500;
stub_clk->cl.knows_txdone = false;
/* Allocate mailbox channel */
stub_clk->mbox = mbox_request_channel(&stub_clk->cl, 0);
if (IS_ERR(stub_clk->mbox)) {
dev_err(dev, "failed get mailbox channel\n");
return PTR_ERR(stub_clk->mbox);
}
init.name = "acpu0";
init.ops = &hi6220_stub_clk_ops;
init.num_parents = 0;
init.flags = 0;
clk = devm_clk_register(dev, &stub_clk->hw);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
if (ret) {
dev_err(dev, "failed to register OF clock provider\n");
return ret;
}
/* initialize buffer to zero */
regmap_write(stub_clk->dfs_map, ACPU_DFS_FLAG, 0x0);
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, 0x0);
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, 0x0);
dev_dbg(dev, "Registered clock '%s'\n", init.name);
return 0;
}
static const struct of_device_id hi6220_stub_clk_of_match[] = {
{ .compatible = "hisilicon,hi6220-stub-clk", },
{}
};
static struct platform_driver hi6220_stub_clk_driver = {
.driver = {
.name = "hi6220-stub-clk",
.of_match_table = hi6220_stub_clk_of_match,
},
.probe = hi6220_stub_clk_probe,
};
static int __init hi6220_stub_clk_init(void)
{
return platform_driver_register(&hi6220_stub_clk_driver);
}
subsys_initcall(hi6220_stub_clk_init);
@@ -0,0 +1,304 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon Hi6220 clock driver
*
* Copyright (c) 2015 Hisilicon Limited.
*
* Author: Bintian Wang <bintian.wang@huawei.com>
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <dt-bindings/clock/hi6220-clock.h>
#include "clk.h"
/* clocks in AO (always on) controller */
static struct hisi_fixed_rate_clock hi6220_fixed_rate_clks[] __initdata = {
{ HI6220_REF32K, "ref32k", NULL, 0, 32764, },
{ HI6220_CLK_TCXO, "clk_tcxo", NULL, 0, 19200000, },
{ HI6220_MMC1_PAD, "mmc1_pad", NULL, 0, 100000000, },
{ HI6220_MMC2_PAD, "mmc2_pad", NULL, 0, 100000000, },
{ HI6220_MMC0_PAD, "mmc0_pad", NULL, 0, 200000000, },
{ HI6220_PLL_BBP, "bbppll0", NULL, 0, 245760000, },
{ HI6220_PLL_GPU, "gpupll", NULL, 0, 1000000000,},
{ HI6220_PLL1_DDR, "ddrpll1", NULL, 0, 1066000000,},
{ HI6220_PLL_SYS, "syspll", NULL, 0, 1190400000,},
{ HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, 0, 1190400000,},
{ HI6220_DDR_SRC, "ddr_sel_src", NULL, 0, 1200000000,},
{ HI6220_PLL_MEDIA, "media_pll", NULL, 0, 1440000000,},
{ HI6220_PLL_DDR, "ddrpll0", NULL, 0, 1600000000,},
};
static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
{ HI6220_300M, "clk_300m", "syspll", 1, 4, 0, },
{ HI6220_150M, "clk_150m", "clk_300m", 1, 2, 0, },
{ HI6220_PICOPHY_SRC, "picophy_src", "clk_150m", 1, 4, 0, },
{ HI6220_MMC0_SRC_SEL, "mmc0srcsel", "mmc0_sel", 1, 8, 0, },
{ HI6220_MMC1_SRC_SEL, "mmc1srcsel", "mmc1_sel", 1, 8, 0, },
{ HI6220_MMC2_SRC_SEL, "mmc2srcsel", "mmc2_sel", 1, 8, 0, },
{ HI6220_VPU_CODEC, "vpucodec", "codec_jpeg_aclk", 1, 2, 0, },
{ HI6220_MMC0_SMP, "mmc0_sample", "mmc0_sel", 1, 8, 0, },
{ HI6220_MMC1_SMP, "mmc1_sample", "mmc1_sel", 1, 8, 0, },
{ HI6220_MMC2_SMP, "mmc2_sample", "mmc2_sel", 1, 8, 0, },
};
static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
{ HI6220_WDT0_PCLK, "wdt0_pclk", "ref32k", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
{ HI6220_WDT1_PCLK, "wdt1_pclk", "ref32k", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
{ HI6220_WDT2_PCLK, "wdt2_pclk", "ref32k", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
{ HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
{ HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
{ HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
{ HI6220_TIMER3_PCLK, "timer3_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 18, 0, },
{ HI6220_TIMER4_PCLK, "timer4_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 19, 0, },
{ HI6220_TIMER5_PCLK, "timer5_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 20, 0, },
{ HI6220_TIMER6_PCLK, "timer6_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 21, 0, },
{ HI6220_TIMER7_PCLK, "timer7_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 22, 0, },
{ HI6220_TIMER8_PCLK, "timer8_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 23, 0, },
{ HI6220_UART0_PCLK, "uart0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 24, 0, },
{ HI6220_RTC0_PCLK, "rtc0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 25, 0, },
{ HI6220_RTC1_PCLK, "rtc1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 26, 0, },
};
static void __init hi6220_clk_ao_init(struct device_node *np)
{
struct hisi_clock_data *clk_data_ao;
clk_data_ao = hisi_clk_init(np, HI6220_AO_NR_CLKS);
if (!clk_data_ao)
return;
hisi_clk_register_fixed_rate(hi6220_fixed_rate_clks,
ARRAY_SIZE(hi6220_fixed_rate_clks), clk_data_ao);
hisi_clk_register_fixed_factor(hi6220_fixed_factor_clks,
ARRAY_SIZE(hi6220_fixed_factor_clks), clk_data_ao);
hisi_clk_register_gate_sep(hi6220_separated_gate_clks_ao,
ARRAY_SIZE(hi6220_separated_gate_clks_ao), clk_data_ao);
}
/* Allow reset driver to probe as well */
CLK_OF_DECLARE_DRIVER(hi6220_clk_ao, "hisilicon,hi6220-aoctrl", hi6220_clk_ao_init);
/* clocks in sysctrl */
static const char *mmc0_mux0_p[] __initdata = { "pll_ddr_gate", "syspll", };
static const char *mmc0_mux1_p[] __initdata = { "mmc0_mux0", "pll_media_gate", };
static const char *mmc0_src_p[] __initdata = { "mmc0srcsel", "mmc0_div", };
static const char *mmc1_mux0_p[] __initdata = { "pll_ddr_gate", "syspll", };
static const char *mmc1_mux1_p[] __initdata = { "mmc1_mux0", "pll_media_gate", };
static const char *mmc1_src_p[] __initdata = { "mmc1srcsel", "mmc1_div", };
static const char *mmc2_mux0_p[] __initdata = { "pll_ddr_gate", "syspll", };
static const char *mmc2_mux1_p[] __initdata = { "mmc2_mux0", "pll_media_gate", };
static const char *mmc2_src_p[] __initdata = { "mmc2srcsel", "mmc2_div", };
static const char *mmc0_sample_in[] __initdata = { "mmc0_sample", "mmc0_pad", };
static const char *mmc1_sample_in[] __initdata = { "mmc1_sample", "mmc1_pad", };
static const char *mmc2_sample_in[] __initdata = { "mmc2_sample", "mmc2_pad", };
static const char *uart1_src[] __initdata = { "clk_tcxo", "clk_150m", };
static const char *uart2_src[] __initdata = { "clk_tcxo", "clk_150m", };
static const char *uart3_src[] __initdata = { "clk_tcxo", "clk_150m", };
static const char *uart4_src[] __initdata = { "clk_tcxo", "clk_150m", };
static const char *hifi_src[] __initdata = { "syspll", "pll_media_gate", };
static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = {
{ HI6220_MMC0_CLK, "mmc0_clk", "mmc0_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
{ HI6220_MMC0_CIUCLK, "mmc0_ciuclk", "mmc0_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
{ HI6220_MMC1_CLK, "mmc1_clk", "mmc1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
{ HI6220_MMC1_CIUCLK, "mmc1_ciuclk", "mmc1_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
{ HI6220_MMC2_CLK, "mmc2_clk", "mmc2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
{ HI6220_MMC2_CIUCLK, "mmc2_ciuclk", "mmc2_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
{ HI6220_USBOTG_HCLK, "usbotg_hclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 4, 0, },
{ HI6220_CLK_PICOPHY, "clk_picophy", "cs_dapb", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 5, 0, },
{ HI6220_HIFI, "hifi_clk", "hifi_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 0, 0, },
{ HI6220_DACODEC_PCLK, "dacodec_pclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 5, 0, },
{ HI6220_EDMAC_ACLK, "edmac_aclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x220, 2, 0, },
{ HI6220_CS_ATB, "cs_atb", "cs_atb_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 0, 0, },
{ HI6220_I2C0_CLK, "i2c0_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 1, 0, },
{ HI6220_I2C1_CLK, "i2c1_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 2, 0, },
{ HI6220_I2C2_CLK, "i2c2_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 3, 0, },
{ HI6220_I2C3_CLK, "i2c3_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 4, 0, },
{ HI6220_UART1_PCLK, "uart1_pclk", "uart1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 5, 0, },
{ HI6220_UART2_PCLK, "uart2_pclk", "uart2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 6, 0, },
{ HI6220_UART3_PCLK, "uart3_pclk", "uart3_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 7, 0, },
{ HI6220_UART4_PCLK, "uart4_pclk", "uart4_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 8, 0, },
{ HI6220_SPI_CLK, "spi_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 9, 0, },
{ HI6220_TSENSOR_CLK, "tsensor_clk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 12, 0, },
{ HI6220_DAPB_CLK, "dapb_clk", "cs_dapb", CLK_SET_RATE_PARENT|CLK_IS_CRITICAL, 0x230, 18, 0, },
{ HI6220_MMU_CLK, "mmu_clk", "ddrc_axi1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x240, 11, 0, },
{ HI6220_HIFI_SEL, "hifi_sel", "hifi_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 0, 0, },
{ HI6220_MMC0_SYSPLL, "mmc0_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 1, 0, },
{ HI6220_MMC1_SYSPLL, "mmc1_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 2, 0, },
{ HI6220_MMC2_SYSPLL, "mmc2_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 3, 0, },
{ HI6220_MMC0_SEL, "mmc0_sel", "mmc0_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 6, 0, },
{ HI6220_MMC1_SEL, "mmc1_sel", "mmc1_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 7, 0, },
{ HI6220_BBPPLL_SEL, "bbppll_sel", "pll0_bbp_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9, 0, },
{ HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, },
{ HI6220_MMC2_SEL, "mmc2_sel", "mmc2_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, },
{ HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IS_CRITICAL, 0x270, 12, 0, },
};
static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = {
{ HI6220_MMC0_SRC, "mmc0_src", mmc0_src_p, ARRAY_SIZE(mmc0_src_p), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
{ HI6220_MMC0_SMP_IN, "mmc0_smp_in", mmc0_sample_in, ARRAY_SIZE(mmc0_sample_in), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
{ HI6220_MMC1_SRC, "mmc1_src", mmc1_src_p, ARRAY_SIZE(mmc1_src_p), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
{ HI6220_MMC1_SMP_IN, "mmc1_smp_in", mmc1_sample_in, ARRAY_SIZE(mmc1_sample_in), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
{ HI6220_MMC2_SRC, "mmc2_src", mmc2_src_p, ARRAY_SIZE(mmc2_src_p), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
{ HI6220_MMC2_SMP_IN, "mmc2_smp_in", mmc2_sample_in, ARRAY_SIZE(mmc2_sample_in), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
{ HI6220_HIFI_SRC, "hifi_src", hifi_src, ARRAY_SIZE(hifi_src), CLK_SET_RATE_PARENT, 0x400, 0, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_UART1_SRC, "uart1_src", uart1_src, ARRAY_SIZE(uart1_src), CLK_SET_RATE_PARENT, 0x400, 1, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_UART2_SRC, "uart2_src", uart2_src, ARRAY_SIZE(uart2_src), CLK_SET_RATE_PARENT, 0x400, 2, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_UART3_SRC, "uart3_src", uart3_src, ARRAY_SIZE(uart3_src), CLK_SET_RATE_PARENT, 0x400, 3, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_UART4_SRC, "uart4_src", uart4_src, ARRAY_SIZE(uart4_src), CLK_SET_RATE_PARENT, 0x400, 4, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_MMC0_MUX0, "mmc0_mux0", mmc0_mux0_p, ARRAY_SIZE(mmc0_mux0_p), CLK_SET_RATE_PARENT, 0x400, 5, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_MMC1_MUX0, "mmc1_mux0", mmc1_mux0_p, ARRAY_SIZE(mmc1_mux0_p), CLK_SET_RATE_PARENT, 0x400, 11, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_MMC2_MUX0, "mmc2_mux0", mmc2_mux0_p, ARRAY_SIZE(mmc2_mux0_p), CLK_SET_RATE_PARENT, 0x400, 12, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_MMC0_MUX1, "mmc0_mux1", mmc0_mux1_p, ARRAY_SIZE(mmc0_mux1_p), CLK_SET_RATE_PARENT, 0x400, 13, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_MMC1_MUX1, "mmc1_mux1", mmc1_mux1_p, ARRAY_SIZE(mmc1_mux1_p), CLK_SET_RATE_PARENT, 0x400, 14, 1, CLK_MUX_HIWORD_MASK,},
{ HI6220_MMC2_MUX1, "mmc2_mux1", mmc2_mux1_p, ARRAY_SIZE(mmc2_mux1_p), CLK_SET_RATE_PARENT, 0x400, 15, 1, CLK_MUX_HIWORD_MASK,},
};
static struct hi6220_divider_clock hi6220_div_clks_sys[] __initdata = {
{ HI6220_CLK_BUS, "clk_bus", "clk_300m", CLK_SET_RATE_PARENT, 0x490, 0, 4, 7, },
{ HI6220_MMC0_DIV, "mmc0_div", "mmc0_syspll", CLK_SET_RATE_PARENT, 0x494, 0, 6, 7, },
{ HI6220_MMC1_DIV, "mmc1_div", "mmc1_syspll", CLK_SET_RATE_PARENT, 0x498, 0, 6, 7, },
{ HI6220_MMC2_DIV, "mmc2_div", "mmc2_syspll", CLK_SET_RATE_PARENT, 0x49c, 0, 6, 7, },
{ HI6220_HIFI_DIV, "hifi_div", "hifi_sel", CLK_SET_RATE_PARENT, 0x4a0, 0, 4, 7, },
{ HI6220_BBPPLL0_DIV, "bbppll0_div", "bbppll_sel", CLK_SET_RATE_PARENT, 0x4a0, 8, 6, 15,},
{ HI6220_CS_DAPB, "cs_dapb", "picophy_src", CLK_SET_RATE_PARENT, 0x4a0, 24, 2, 31,},
{ HI6220_CS_ATB_DIV, "cs_atb_div", "cs_atb_syspll", CLK_SET_RATE_PARENT, 0x4a4, 0, 4, 7, },
};
static void __init hi6220_clk_sys_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
clk_data = hisi_clk_init(np, HI6220_SYS_NR_CLKS);
if (!clk_data)
return;
hisi_clk_register_gate_sep(hi6220_separated_gate_clks_sys,
ARRAY_SIZE(hi6220_separated_gate_clks_sys), clk_data);
hisi_clk_register_mux(hi6220_mux_clks_sys,
ARRAY_SIZE(hi6220_mux_clks_sys), clk_data);
hi6220_clk_register_divider(hi6220_div_clks_sys,
ARRAY_SIZE(hi6220_div_clks_sys), clk_data);
}
CLK_OF_DECLARE_DRIVER(hi6220_clk_sys, "hisilicon,hi6220-sysctrl", hi6220_clk_sys_init);
/* clocks in media controller */
static const char *clk_1000_1200_src[] __initdata = { "pll_gpu_gate", "media_syspll_src", };
static const char *clk_1440_1200_src[] __initdata = { "media_syspll_src", "media_pll_src", };
static const char *clk_1000_1440_src[] __initdata = { "pll_gpu_gate", "media_pll_src", };
static struct hisi_gate_clock hi6220_separated_gate_clks_media[] __initdata = {
{ HI6220_DSI_PCLK, "dsi_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 0, 0, },
{ HI6220_G3D_PCLK, "g3d_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 1, 0, },
{ HI6220_ACLK_CODEC_VPU, "aclk_codec_vpu", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 3, 0, },
{ HI6220_ISP_SCLK, "isp_sclk", "isp_sclk_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 5, 0, },
{ HI6220_ADE_CORE, "ade_core", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 6, 0, },
{ HI6220_MED_MMU, "media_mmu", "mmu_clk", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 8, 0, },
{ HI6220_CFG_CSI4PHY, "cfg_csi4phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 9, 0, },
{ HI6220_CFG_CSI2PHY, "cfg_csi2phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 10, 0, },
{ HI6220_ISP_SCLK_GATE, "isp_sclk_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 11, 0, },
{ HI6220_ISP_SCLK_GATE1, "isp_sclk_gate1", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 12, 0, },
{ HI6220_ADE_CORE_GATE, "ade_core_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 14, 0, },
{ HI6220_CODEC_VPU_GATE, "codec_vpu_gate", "clk_1000_1440", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 15, 0, },
{ HI6220_MED_SYSPLL, "media_syspll_src", "media_syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 17, 0, },
};
static struct hisi_mux_clock hi6220_mux_clks_media[] __initdata = {
{ HI6220_1440_1200, "clk_1440_1200", clk_1440_1200_src, ARRAY_SIZE(clk_1440_1200_src), CLK_SET_RATE_PARENT, 0x51c, 0, 1, 0, },
{ HI6220_1000_1200, "clk_1000_1200", clk_1000_1200_src, ARRAY_SIZE(clk_1000_1200_src), CLK_SET_RATE_PARENT, 0x51c, 1, 1, 0, },
{ HI6220_1000_1440, "clk_1000_1440", clk_1000_1440_src, ARRAY_SIZE(clk_1000_1440_src), CLK_SET_RATE_PARENT, 0x51c, 6, 1, 0, },
};
static struct hi6220_divider_clock hi6220_div_clks_media[] __initdata = {
{ HI6220_CODEC_JPEG, "codec_jpeg_aclk", "media_pll_src", CLK_SET_RATE_PARENT, 0xcbc, 0, 4, 23, },
{ HI6220_ISP_SCLK_SRC, "isp_sclk_src", "isp_sclk_gate", CLK_SET_RATE_PARENT, 0xcbc, 8, 4, 15, },
{ HI6220_ISP_SCLK1, "isp_sclk1", "isp_sclk_gate1", CLK_SET_RATE_PARENT, 0xcbc, 24, 4, 31, },
{ HI6220_ADE_CORE_SRC, "ade_core_src", "ade_core_gate", CLK_SET_RATE_PARENT, 0xcc0, 16, 3, 23, },
{ HI6220_ADE_PIX_SRC, "ade_pix_src", "clk_1440_1200", CLK_SET_RATE_PARENT, 0xcc0, 24, 6, 31, },
{ HI6220_G3D_CLK, "g3d_clk", "clk_1000_1200", CLK_SET_RATE_PARENT, 0xcc4, 8, 4, 15, },
{ HI6220_CODEC_VPU_SRC, "codec_vpu_src", "codec_vpu_gate", CLK_SET_RATE_PARENT, 0xcc4, 24, 6, 31, },
};
static void __init hi6220_clk_media_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
clk_data = hisi_clk_init(np, HI6220_MEDIA_NR_CLKS);
if (!clk_data)
return;
hisi_clk_register_gate_sep(hi6220_separated_gate_clks_media,
ARRAY_SIZE(hi6220_separated_gate_clks_media), clk_data);
hisi_clk_register_mux(hi6220_mux_clks_media,
ARRAY_SIZE(hi6220_mux_clks_media), clk_data);
hi6220_clk_register_divider(hi6220_div_clks_media,
ARRAY_SIZE(hi6220_div_clks_media), clk_data);
}
CLK_OF_DECLARE_DRIVER(hi6220_clk_media, "hisilicon,hi6220-mediactrl", hi6220_clk_media_init);
/* clocks in pmctrl */
static struct hisi_gate_clock hi6220_gate_clks_power[] __initdata = {
{ HI6220_PLL_GPU_GATE, "pll_gpu_gate", "gpupll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x8, 0, 0, },
{ HI6220_PLL1_DDR_GATE, "pll1_ddr_gate", "ddrpll1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x10, 0, 0, },
{ HI6220_PLL_DDR_GATE, "pll_ddr_gate", "ddrpll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x18, 0, 0, },
{ HI6220_PLL_MEDIA_GATE, "pll_media_gate", "media_pll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x38, 0, 0, },
{ HI6220_PLL0_BBP_GATE, "pll0_bbp_gate", "bbppll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x48, 0, 0, },
};
static struct hi6220_divider_clock hi6220_div_clks_power[] __initdata = {
{ HI6220_DDRC_SRC, "ddrc_src", "ddr_sel_src", CLK_SET_RATE_PARENT, 0x5a8, 0, 4, 0, },
{ HI6220_DDRC_AXI1, "ddrc_axi1", "ddrc_src", CLK_SET_RATE_PARENT, 0x5a8, 8, 2, 0, },
};
static void __init hi6220_clk_power_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
clk_data = hisi_clk_init(np, HI6220_POWER_NR_CLKS);
if (!clk_data)
return;
hisi_clk_register_gate(hi6220_gate_clks_power,
ARRAY_SIZE(hi6220_gate_clks_power), clk_data);
hi6220_clk_register_divider(hi6220_div_clks_power,
ARRAY_SIZE(hi6220_div_clks_power), clk_data);
}
CLK_OF_DECLARE(hi6220_clk_power, "hisilicon,hi6220-pmctrl", hi6220_clk_power_init);
/* clocks in acpu */
static const struct hisi_gate_clock hi6220_acpu_sc_gate_sep_clks[] = {
{ HI6220_ACPU_SFT_AT_S, "sft_at_s", "cs_atb",
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0xc, 11, 0, },
};
static void __init hi6220_clk_acpu_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
int nr = ARRAY_SIZE(hi6220_acpu_sc_gate_sep_clks);
clk_data = hisi_clk_init(np, nr);
if (!clk_data)
return;
hisi_clk_register_gate_sep(hi6220_acpu_sc_gate_sep_clks,
ARRAY_SIZE(hi6220_acpu_sc_gate_sep_clks),
clk_data);
}
CLK_OF_DECLARE(hi6220_clk_acpu, "hisilicon,hi6220-acpu-sctrl", hi6220_clk_acpu_init);
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hisilicon HiP04 clock driver
*
* Copyright (c) 2013-2014 Hisilicon Limited.
* Copyright (c) 2013-2014 Linaro Limited.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <dt-bindings/clock/hip04-clock.h>
#include "clk.h"
/* fixed rate clocks */
static struct hisi_fixed_rate_clock hip04_fixed_rate_clks[] __initdata = {
{ HIP04_OSC50M, "osc50m", NULL, 0, 50000000, },
{ HIP04_CLK_50M, "clk50m", NULL, 0, 50000000, },
{ HIP04_CLK_168M, "clk168m", NULL, 0, 168750000, },
};
static void __init hip04_clk_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
clk_data = hisi_clk_init(np, HIP04_NR_CLKS);
if (!clk_data)
return;
hisi_clk_register_fixed_rate(hip04_fixed_rate_clks,
ARRAY_SIZE(hip04_fixed_rate_clks),
clk_data);
}
CLK_OF_DECLARE(hip04_clk, "hisilicon,hip04-clock", hip04_clk_init);
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017 HiSilicon Technologies Co., Ltd.
*
* Simple HiSilicon phase clock implementation.
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk.h"
struct clk_hisi_phase {
struct clk_hw hw;
void __iomem *reg;
u32 *phase_degrees;
u32 *phase_regvals;
u8 phase_num;
u32 mask;
u8 shift;
u8 flags;
spinlock_t *lock;
};
#define to_clk_hisi_phase(_hw) container_of(_hw, struct clk_hisi_phase, hw)
static int hisi_phase_regval_to_degrees(struct clk_hisi_phase *phase,
u32 regval)
{
int i;
for (i = 0; i < phase->phase_num; i++)
if (phase->phase_regvals[i] == regval)
return phase->phase_degrees[i];
return -EINVAL;
}
static int hisi_clk_get_phase(struct clk_hw *hw)
{
struct clk_hisi_phase *phase = to_clk_hisi_phase(hw);
u32 regval;
regval = readl(phase->reg);
regval = (regval & phase->mask) >> phase->shift;
return hisi_phase_regval_to_degrees(phase, regval);
}
static int hisi_phase_degrees_to_regval(struct clk_hisi_phase *phase,
int degrees)
{
int i;
for (i = 0; i < phase->phase_num; i++)
if (phase->phase_degrees[i] == degrees)
return phase->phase_regvals[i];
return -EINVAL;
}
static int hisi_clk_set_phase(struct clk_hw *hw, int degrees)
{
struct clk_hisi_phase *phase = to_clk_hisi_phase(hw);
unsigned long flags = 0;
int regval;
u32 val;
regval = hisi_phase_degrees_to_regval(phase, degrees);
if (regval < 0)
return regval;
spin_lock_irqsave(phase->lock, flags);
val = readl(phase->reg);
val &= ~phase->mask;
val |= regval << phase->shift;
writel(val, phase->reg);
spin_unlock_irqrestore(phase->lock, flags);
return 0;
}
static const struct clk_ops clk_phase_ops = {
.get_phase = hisi_clk_get_phase,
.set_phase = hisi_clk_set_phase,
};
struct clk *clk_register_hisi_phase(struct device *dev,
const struct hisi_phase_clock *clks,
void __iomem *base, spinlock_t *lock)
{
struct clk_hisi_phase *phase;
struct clk_init_data init;
phase = devm_kzalloc(dev, sizeof(struct clk_hisi_phase), GFP_KERNEL);
if (!phase)
return ERR_PTR(-ENOMEM);
init.name = clks->name;
init.ops = &clk_phase_ops;
init.flags = clks->flags;
init.parent_names = clks->parent_names ? &clks->parent_names : NULL;
init.num_parents = clks->parent_names ? 1 : 0;
phase->reg = base + clks->offset;
phase->shift = clks->shift;
phase->mask = (BIT(clks->width) - 1) << clks->shift;
phase->lock = lock;
phase->phase_degrees = clks->phase_degrees;
phase->phase_regvals = clks->phase_regvals;
phase->phase_num = clks->phase_num;
phase->hw.init = &init;
return devm_clk_register(dev, &phase->hw);
}
EXPORT_SYMBOL_GPL(clk_register_hisi_phase);
@@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Linaro Ltd.
* Copyright (c) 2014 Hisilicon Limited.
*/
#include <linux/of_address.h>
#include <dt-bindings/clock/hix5hd2-clock.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "clk.h"
static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = {
{ HIX5HD2_FIXED_1200M, "1200m", NULL, 0, 1200000000, },
{ HIX5HD2_FIXED_400M, "400m", NULL, 0, 400000000, },
{ HIX5HD2_FIXED_48M, "48m", NULL, 0, 48000000, },
{ HIX5HD2_FIXED_24M, "24m", NULL, 0, 24000000, },
{ HIX5HD2_FIXED_600M, "600m", NULL, 0, 600000000, },
{ HIX5HD2_FIXED_300M, "300m", NULL, 0, 300000000, },
{ HIX5HD2_FIXED_75M, "75m", NULL, 0, 75000000, },
{ HIX5HD2_FIXED_200M, "200m", NULL, 0, 200000000, },
{ HIX5HD2_FIXED_100M, "100m", NULL, 0, 100000000, },
{ HIX5HD2_FIXED_40M, "40m", NULL, 0, 40000000, },
{ HIX5HD2_FIXED_150M, "150m", NULL, 0, 150000000, },
{ HIX5HD2_FIXED_1728M, "1728m", NULL, 0, 1728000000, },
{ HIX5HD2_FIXED_28P8M, "28p8m", NULL, 0, 28000000, },
{ HIX5HD2_FIXED_432M, "432m", NULL, 0, 432000000, },
{ HIX5HD2_FIXED_345P6M, "345p6m", NULL, 0, 345000000, },
{ HIX5HD2_FIXED_288M, "288m", NULL, 0, 288000000, },
{ HIX5HD2_FIXED_60M, "60m", NULL, 0, 60000000, },
{ HIX5HD2_FIXED_750M, "750m", NULL, 0, 750000000, },
{ HIX5HD2_FIXED_500M, "500m", NULL, 0, 500000000, },
{ HIX5HD2_FIXED_54M, "54m", NULL, 0, 54000000, },
{ HIX5HD2_FIXED_27M, "27m", NULL, 0, 27000000, },
{ HIX5HD2_FIXED_1500M, "1500m", NULL, 0, 1500000000, },
{ HIX5HD2_FIXED_375M, "375m", NULL, 0, 375000000, },
{ HIX5HD2_FIXED_187M, "187m", NULL, 0, 187000000, },
{ HIX5HD2_FIXED_250M, "250m", NULL, 0, 250000000, },
{ HIX5HD2_FIXED_125M, "125m", NULL, 0, 125000000, },
{ HIX5HD2_FIXED_2P02M, "2m", NULL, 0, 2000000, },
{ HIX5HD2_FIXED_50M, "50m", NULL, 0, 50000000, },
{ HIX5HD2_FIXED_25M, "25m", NULL, 0, 25000000, },
{ HIX5HD2_FIXED_83M, "83m", NULL, 0, 83333333, },
};
static const char *const sfc_mux_p[] __initconst = {
"24m", "150m", "200m", "100m", "75m", };
static u32 sfc_mux_table[] = {0, 4, 5, 6, 7};
static const char *const sdio_mux_p[] __initconst = {
"75m", "100m", "50m", "15m", };
static u32 sdio_mux_table[] = {0, 1, 2, 3};
static const char *const fephy_mux_p[] __initconst = { "25m", "125m"};
static u32 fephy_mux_table[] = {0, 1};
static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = {
{ HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p),
CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, },
{ HIX5HD2_MMC_MUX, "mmc_mux", sdio_mux_p, ARRAY_SIZE(sdio_mux_p),
CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio_mux_table, },
{ HIX5HD2_SD_MUX, "sd_mux", sdio_mux_p, ARRAY_SIZE(sdio_mux_p),
CLK_SET_RATE_PARENT, 0x9c, 8, 2, 0, sdio_mux_table, },
{ HIX5HD2_FEPHY_MUX, "fephy_mux",
fephy_mux_p, ARRAY_SIZE(fephy_mux_p),
CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, },
};
static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = {
/* sfc */
{ HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux",
CLK_SET_RATE_PARENT, 0x5c, 0, 0, },
{ HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc",
CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, },
/* sdio0 */
{ HIX5HD2_SD_BIU_CLK, "clk_sd_biu", "200m",
CLK_SET_RATE_PARENT, 0x9c, 0, 0, },
{ HIX5HD2_SD_CIU_CLK, "clk_sd_ciu", "sd_mux",
CLK_SET_RATE_PARENT, 0x9c, 1, 0, },
{ HIX5HD2_SD_CIU_RST, "rst_sd_ciu", "clk_sd_ciu",
CLK_SET_RATE_PARENT, 0x9c, 4, CLK_GATE_SET_TO_DISABLE, },
/* sdio1 */
{ HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m",
CLK_SET_RATE_PARENT, 0xa0, 0, 0, },
{ HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux",
CLK_SET_RATE_PARENT, 0xa0, 1, 0, },
{ HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu",
CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, },
/* gsf */
{ HIX5HD2_FWD_BUS_CLK, "clk_fwd_bus", NULL, 0, 0xcc, 0, 0, },
{ HIX5HD2_FWD_SYS_CLK, "clk_fwd_sys", "clk_fwd_bus", 0, 0xcc, 5, 0, },
{ HIX5HD2_MAC0_PHY_CLK, "clk_fephy", "clk_fwd_sys",
CLK_SET_RATE_PARENT, 0x120, 0, 0, },
/* wdg0 */
{ HIX5HD2_WDG0_CLK, "clk_wdg0", "24m",
CLK_SET_RATE_PARENT, 0x178, 0, 0, },
{ HIX5HD2_WDG0_RST, "rst_wdg0", "clk_wdg0",
CLK_SET_RATE_PARENT, 0x178, 4, CLK_GATE_SET_TO_DISABLE, },
/* I2C */
{HIX5HD2_I2C0_CLK, "clk_i2c0", "100m",
CLK_SET_RATE_PARENT, 0x06c, 4, 0, },
{HIX5HD2_I2C0_RST, "rst_i2c0", "clk_i2c0",
CLK_SET_RATE_PARENT, 0x06c, 5, CLK_GATE_SET_TO_DISABLE, },
{HIX5HD2_I2C1_CLK, "clk_i2c1", "100m",
CLK_SET_RATE_PARENT, 0x06c, 8, 0, },
{HIX5HD2_I2C1_RST, "rst_i2c1", "clk_i2c1",
CLK_SET_RATE_PARENT, 0x06c, 9, CLK_GATE_SET_TO_DISABLE, },
{HIX5HD2_I2C2_CLK, "clk_i2c2", "100m",
CLK_SET_RATE_PARENT, 0x06c, 12, 0, },
{HIX5HD2_I2C2_RST, "rst_i2c2", "clk_i2c2",
CLK_SET_RATE_PARENT, 0x06c, 13, CLK_GATE_SET_TO_DISABLE, },
{HIX5HD2_I2C3_CLK, "clk_i2c3", "100m",
CLK_SET_RATE_PARENT, 0x06c, 16, 0, },
{HIX5HD2_I2C3_RST, "rst_i2c3", "clk_i2c3",
CLK_SET_RATE_PARENT, 0x06c, 17, CLK_GATE_SET_TO_DISABLE, },
{HIX5HD2_I2C4_CLK, "clk_i2c4", "100m",
CLK_SET_RATE_PARENT, 0x06c, 20, 0, },
{HIX5HD2_I2C4_RST, "rst_i2c4", "clk_i2c4",
CLK_SET_RATE_PARENT, 0x06c, 21, CLK_GATE_SET_TO_DISABLE, },
{HIX5HD2_I2C5_CLK, "clk_i2c5", "100m",
CLK_SET_RATE_PARENT, 0x06c, 0, 0, },
{HIX5HD2_I2C5_RST, "rst_i2c5", "clk_i2c5",
CLK_SET_RATE_PARENT, 0x06c, 1, CLK_GATE_SET_TO_DISABLE, },
};
enum hix5hd2_clk_type {
TYPE_COMPLEX,
TYPE_ETHER,
};
struct hix5hd2_complex_clock {
const char *name;
const char *parent_name;
u32 id;
u32 ctrl_reg;
u32 ctrl_clk_mask;
u32 ctrl_rst_mask;
u32 phy_reg;
u32 phy_clk_mask;
u32 phy_rst_mask;
enum hix5hd2_clk_type type;
};
struct hix5hd2_clk_complex {
struct clk_hw hw;
u32 id;
void __iomem *ctrl_reg;
u32 ctrl_clk_mask;
u32 ctrl_rst_mask;
void __iomem *phy_reg;
u32 phy_clk_mask;
u32 phy_rst_mask;
};
static struct hix5hd2_complex_clock hix5hd2_complex_clks[] __initdata = {
{"clk_mac0", "clk_fephy", HIX5HD2_MAC0_CLK,
0xcc, 0xa, 0x500, 0x120, 0, 0x10, TYPE_ETHER},
{"clk_mac1", "clk_fwd_sys", HIX5HD2_MAC1_CLK,
0xcc, 0x14, 0xa00, 0x168, 0x2, 0, TYPE_ETHER},
{"clk_sata", NULL, HIX5HD2_SATA_CLK,
0xa8, 0x1f, 0x300, 0xac, 0x1, 0x0, TYPE_COMPLEX},
{"clk_usb", NULL, HIX5HD2_USB_CLK,
0xb8, 0xff, 0x3f000, 0xbc, 0x7, 0x3f00, TYPE_COMPLEX},
};
#define to_complex_clk(_hw) container_of(_hw, struct hix5hd2_clk_complex, hw)
static int clk_ether_prepare(struct clk_hw *hw)
{
struct hix5hd2_clk_complex *clk = to_complex_clk(hw);
u32 val;
val = readl_relaxed(clk->ctrl_reg);
val |= clk->ctrl_clk_mask | clk->ctrl_rst_mask;
writel_relaxed(val, clk->ctrl_reg);
val &= ~(clk->ctrl_rst_mask);
writel_relaxed(val, clk->ctrl_reg);
val = readl_relaxed(clk->phy_reg);
val |= clk->phy_clk_mask;
val &= ~(clk->phy_rst_mask);
writel_relaxed(val, clk->phy_reg);
mdelay(10);
val &= ~(clk->phy_clk_mask);
val |= clk->phy_rst_mask;
writel_relaxed(val, clk->phy_reg);
mdelay(10);
val |= clk->phy_clk_mask;
val &= ~(clk->phy_rst_mask);
writel_relaxed(val, clk->phy_reg);
mdelay(30);
return 0;
}
static void clk_ether_unprepare(struct clk_hw *hw)
{
struct hix5hd2_clk_complex *clk = to_complex_clk(hw);
u32 val;
val = readl_relaxed(clk->ctrl_reg);
val &= ~(clk->ctrl_clk_mask);
writel_relaxed(val, clk->ctrl_reg);
}
static const struct clk_ops clk_ether_ops = {
.prepare = clk_ether_prepare,
.unprepare = clk_ether_unprepare,
};
static int clk_complex_enable(struct clk_hw *hw)
{
struct hix5hd2_clk_complex *clk = to_complex_clk(hw);
u32 val;
val = readl_relaxed(clk->ctrl_reg);
val |= clk->ctrl_clk_mask;
val &= ~(clk->ctrl_rst_mask);
writel_relaxed(val, clk->ctrl_reg);
val = readl_relaxed(clk->phy_reg);
val |= clk->phy_clk_mask;
val &= ~(clk->phy_rst_mask);
writel_relaxed(val, clk->phy_reg);
return 0;
}
static void clk_complex_disable(struct clk_hw *hw)
{
struct hix5hd2_clk_complex *clk = to_complex_clk(hw);
u32 val;
val = readl_relaxed(clk->ctrl_reg);
val |= clk->ctrl_rst_mask;
val &= ~(clk->ctrl_clk_mask);
writel_relaxed(val, clk->ctrl_reg);
val = readl_relaxed(clk->phy_reg);
val |= clk->phy_rst_mask;
val &= ~(clk->phy_clk_mask);
writel_relaxed(val, clk->phy_reg);
}
static const struct clk_ops clk_complex_ops = {
.enable = clk_complex_enable,
.disable = clk_complex_disable,
};
static void __init
hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, int nums,
struct hisi_clock_data *data)
{
void __iomem *base = data->base;
int i;
for (i = 0; i < nums; i++) {
struct hix5hd2_clk_complex *p_clk;
struct clk *clk;
struct clk_init_data init;
p_clk = kzalloc_obj(*p_clk);
if (!p_clk)
return;
init.name = clks[i].name;
if (clks[i].type == TYPE_ETHER)
init.ops = &clk_ether_ops;
else
init.ops = &clk_complex_ops;
init.flags = 0;
init.parent_names =
(clks[i].parent_name ? &clks[i].parent_name : NULL);
init.num_parents = (clks[i].parent_name ? 1 : 0);
p_clk->ctrl_reg = base + clks[i].ctrl_reg;
p_clk->ctrl_clk_mask = clks[i].ctrl_clk_mask;
p_clk->ctrl_rst_mask = clks[i].ctrl_rst_mask;
p_clk->phy_reg = base + clks[i].phy_reg;
p_clk->phy_clk_mask = clks[i].phy_clk_mask;
p_clk->phy_rst_mask = clks[i].phy_rst_mask;
p_clk->hw.init = &init;
clk = clk_register(NULL, &p_clk->hw);
if (IS_ERR(clk)) {
kfree(p_clk);
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
data->clk_data.clks[clks[i].id] = clk;
}
}
static void __init hix5hd2_clk_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
clk_data = hisi_clk_init(np, HIX5HD2_NR_CLKS);
if (!clk_data)
return;
hisi_clk_register_fixed_rate(hix5hd2_fixed_rate_clks,
ARRAY_SIZE(hix5hd2_fixed_rate_clks),
clk_data);
hisi_clk_register_mux(hix5hd2_mux_clks, ARRAY_SIZE(hix5hd2_mux_clks),
clk_data);
hisi_clk_register_gate(hix5hd2_gate_clks,
ARRAY_SIZE(hix5hd2_gate_clks), clk_data);
hix5hd2_clk_register_complex(hix5hd2_complex_clks,
ARRAY_SIZE(hix5hd2_complex_clks),
clk_data);
}
CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init);
+345
View File
@@ -0,0 +1,345 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hisilicon clock driver
*
* Copyright (c) 2012-2013 Hisilicon Limited.
* Copyright (c) 2012-2013 Linaro Limited.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
* Xin Li <li.xin@linaro.org>
*/
#include <linux/kernel.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk.h"
static DEFINE_SPINLOCK(hisi_clk_lock);
struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev,
int nr_clks)
{
struct hisi_clock_data *clk_data;
struct resource *res;
struct clk **clk_table;
clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
if (!clk_data)
return NULL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return NULL;
clk_data->base = devm_ioremap(&pdev->dev,
res->start, resource_size(res));
if (!clk_data->base)
return NULL;
clk_table = devm_kmalloc_array(&pdev->dev, nr_clks,
sizeof(*clk_table),
GFP_KERNEL);
if (!clk_table)
return NULL;
clk_data->clk_data.clks = clk_table;
clk_data->clk_data.clk_num = nr_clks;
return clk_data;
}
EXPORT_SYMBOL_GPL(hisi_clk_alloc);
struct hisi_clock_data *hisi_clk_init(struct device_node *np,
int nr_clks)
{
struct hisi_clock_data *clk_data;
struct clk **clk_table;
void __iomem *base;
base = of_iomap(np, 0);
if (!base) {
pr_err("%s: failed to map clock registers\n", __func__);
goto err;
}
clk_data = kzalloc_obj(*clk_data);
if (!clk_data)
goto err_base;
clk_data->base = base;
clk_table = kzalloc_objs(*clk_table, nr_clks);
if (!clk_table)
goto err_data;
clk_data->clk_data.clks = clk_table;
clk_data->clk_data.clk_num = nr_clks;
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
return clk_data;
err_data:
kfree(clk_data);
err_base:
iounmap(base);
err:
return NULL;
}
EXPORT_SYMBOL_GPL(hisi_clk_init);
int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
int i;
for (i = 0; i < nums; i++) {
clk = clk_register_fixed_rate(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
clks[i].fixed_rate);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
goto err;
}
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);
int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
int nums,
struct hisi_clock_data *data)
{
struct clk *clk;
int i;
for (i = 0; i < nums; i++) {
clk = clk_register_fixed_factor(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags, clks[i].mult,
clks[i].div);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
goto err;
}
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);
int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
void __iomem *base = data->base;
int i;
for (i = 0; i < nums; i++) {
u32 mask = BIT(clks[i].width) - 1;
clk = clk_register_mux_table(NULL, clks[i].name,
clks[i].parent_names,
clks[i].num_parents, clks[i].flags,
base + clks[i].offset, clks[i].shift,
mask, clks[i].mux_flags,
clks[i].table, &hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
goto err;
}
if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL);
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_mux(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_mux);
int hisi_clk_register_phase(struct device *dev,
const struct hisi_phase_clock *clks,
int nums, struct hisi_clock_data *data)
{
void __iomem *base = data->base;
struct clk *clk;
int i;
for (i = 0; i < nums; i++) {
clk = clk_register_hisi_phase(dev, &clks[i], base,
&hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
clks[i].name);
return PTR_ERR(clk);
}
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
}
EXPORT_SYMBOL_GPL(hisi_clk_register_phase);
int hisi_clk_register_divider(const struct hisi_divider_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
void __iomem *base = data->base;
int i;
for (i = 0; i < nums; i++) {
clk = clk_register_divider_table(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].shift, clks[i].width,
clks[i].div_flags,
clks[i].table,
&hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
goto err;
}
if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL);
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_divider(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_divider);
int hisi_clk_register_gate(const struct hisi_gate_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
void __iomem *base = data->base;
int i;
for (i = 0; i < nums; i++) {
clk = clk_register_gate(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].bit_idx,
clks[i].gate_flags,
&hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
goto err;
}
if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL);
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_gate(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_gate);
void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
void __iomem *base = data->base;
int i;
for (i = 0; i < nums; i++) {
clk = hisi_register_clkgate_sep(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].bit_idx,
clks[i].gate_flags,
&hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL);
data->clk_data.clks[clks[i].id] = clk;
}
}
EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep);
void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
void __iomem *base = data->base;
int i;
for (i = 0; i < nums; i++) {
clk = hi6220_register_clkdiv(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].shift,
clks[i].width,
clks[i].mask_bit,
&hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL);
data->clk_data.clks[clks[i].id] = clk;
}
}
+157
View File
@@ -0,0 +1,157 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Hisilicon Hi3620 clock gate driver
*
* Copyright (c) 2012-2013 Hisilicon Limited.
* Copyright (c) 2012-2013 Linaro Limited.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
* Xin Li <li.xin@linaro.org>
*/
#ifndef __HISI_CLK_H
#define __HISI_CLK_H
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/spinlock.h>
struct platform_device;
struct hisi_clock_data {
struct clk_onecell_data clk_data;
void __iomem *base;
};
struct hisi_fixed_rate_clock {
unsigned int id;
char *name;
const char *parent_name;
unsigned long flags;
unsigned long fixed_rate;
};
struct hisi_fixed_factor_clock {
unsigned int id;
char *name;
const char *parent_name;
unsigned long mult;
unsigned long div;
unsigned long flags;
};
struct hisi_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;
const u32 *table;
const char *alias;
};
struct hisi_phase_clock {
unsigned int id;
const char *name;
const char *parent_names;
unsigned long flags;
unsigned long offset;
u8 shift;
u8 width;
u32 *phase_degrees;
u32 *phase_regvals;
u8 phase_num;
};
struct hisi_divider_clock {
unsigned int id;
const char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u8 shift;
u8 width;
u8 div_flags;
struct clk_div_table *table;
const char *alias;
};
struct hi6220_divider_clock {
unsigned int id;
const char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u8 shift;
u8 width;
u32 mask_bit;
const char *alias;
};
struct hisi_gate_clock {
unsigned int id;
const char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u8 bit_idx;
u8 gate_flags;
const char *alias;
};
struct clk *hisi_register_clkgate_sep(struct device *, const char *,
const char *, unsigned long,
void __iomem *, u8,
u8, spinlock_t *);
struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, void __iomem *reg,
u8 shift, u8 width, u32 mask_bit, spinlock_t *lock);
struct hisi_clock_data *hisi_clk_alloc(struct platform_device *, int);
struct hisi_clock_data *hisi_clk_init(struct device_node *, int);
int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *,
int, struct hisi_clock_data *);
int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *,
int, struct hisi_clock_data *);
int hisi_clk_register_mux(const struct hisi_mux_clock *, int,
struct hisi_clock_data *);
struct clk *clk_register_hisi_phase(struct device *dev,
const struct hisi_phase_clock *clks,
void __iomem *base, spinlock_t *lock);
int hisi_clk_register_phase(struct device *dev,
const struct hisi_phase_clock *clks,
int nums, struct hisi_clock_data *data);
int hisi_clk_register_divider(const struct hisi_divider_clock *,
int, struct hisi_clock_data *);
int hisi_clk_register_gate(const struct hisi_gate_clock *,
int, struct hisi_clock_data *);
void hisi_clk_register_gate_sep(const struct hisi_gate_clock *,
int, struct hisi_clock_data *);
void hi6220_clk_register_divider(const struct hi6220_divider_clock *,
int, struct hisi_clock_data *);
#define hisi_clk_unregister(type) \
static inline \
void hisi_clk_unregister_##type(const struct hisi_##type##_clock *clks, \
int nums, struct hisi_clock_data *data) \
{ \
struct clk **clocks = data->clk_data.clks; \
int i; \
for (i = 0; i < nums; i++) { \
int id = clks[i].id; \
if (clocks[id]) \
clk_unregister_##type(clocks[id]); \
} \
}
hisi_clk_unregister(fixed_rate)
hisi_clk_unregister(fixed_factor)
hisi_clk_unregister(mux)
hisi_clk_unregister(divider)
hisi_clk_unregister(gate)
#endif /* __HISI_CLK_H */
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon hi6220 SoC divider clock driver
*
* Copyright (c) 2015 Hisilicon Limited.
*
* Author: Bintian Wang <bintian.wang@huawei.com>
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/spinlock.h>
#include "clk.h"
#define div_mask(width) ((1 << (width)) - 1)
/**
* struct hi6220_clk_divider - divider clock for hi6220
*
* @hw: handle between common and hardware-specific interfaces
* @reg: register containing divider
* @shift: shift to the divider bit field
* @width: width of the divider bit field
* @mask: mask for setting divider rate
* @lock: register lock
* @table: the div table that the divider supports
*/
struct hi6220_clk_divider {
struct clk_hw hw;
void __iomem *reg;
u8 shift;
u8 width;
u32 mask;
spinlock_t *lock;
struct clk_div_table table[];
};
#define to_hi6220_clk_divider(_hw) \
container_of(_hw, struct hi6220_clk_divider, hw)
static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
unsigned int val;
struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
val = readl_relaxed(dclk->reg) >> dclk->shift;
val &= div_mask(dclk->width);
return divider_recalc_rate(hw, parent_rate, val, dclk->table,
CLK_DIVIDER_ROUND_CLOSEST, dclk->width);
}
static int hi6220_clkdiv_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
return divider_determine_rate(hw, req, dclk->table, dclk->width,
CLK_DIVIDER_ROUND_CLOSEST);
}
static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
int value;
unsigned long flags = 0;
u32 data;
struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
value = divider_get_val(rate, parent_rate, dclk->table,
dclk->width, CLK_DIVIDER_ROUND_CLOSEST);
if (dclk->lock)
spin_lock_irqsave(dclk->lock, flags);
data = readl_relaxed(dclk->reg);
data &= ~(div_mask(dclk->width) << dclk->shift);
data |= value << dclk->shift;
data |= dclk->mask;
writel_relaxed(data, dclk->reg);
if (dclk->lock)
spin_unlock_irqrestore(dclk->lock, flags);
return 0;
}
static const struct clk_ops hi6220_clkdiv_ops = {
.recalc_rate = hi6220_clkdiv_recalc_rate,
.determine_rate = hi6220_clkdiv_determine_rate,
.set_rate = hi6220_clkdiv_set_rate,
};
struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, void __iomem *reg,
u8 shift, u8 width, u32 mask_bit, spinlock_t *lock)
{
struct hi6220_clk_divider *div;
struct clk *clk;
struct clk_init_data init;
struct clk_div_table *table;
u32 max_div, min_div;
int i;
/* Init the divider table */
max_div = div_mask(width) + 1;
min_div = 1;
/* allocate the divider */
div = kzalloc_flex(*div, table, max_div + 1);
if (!div)
return ERR_PTR(-ENOMEM);
for (i = 0; i < max_div; i++) {
table = &div->table[i];
table->div = min_div + i;
table->val = table->div - 1;
}
init.name = name;
init.ops = &hi6220_clkdiv_ops;
init.flags = flags;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
/* struct hi6220_clk_divider assignments */
div->reg = reg;
div->shift = shift;
div->width = width;
div->mask = mask_bit ? BIT(mask_bit) : 0;
div->lock = lock;
div->hw.init = &init;
/* register the clock */
clk = clk_register(dev, &div->hw);
if (IS_ERR(clk))
kfree(div);
return clk;
}
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hisilicon clock separated gate driver
*
* Copyright (c) 2012-2013 Hisilicon Limited.
* Copyright (c) 2012-2013 Linaro Limited.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
* Xin Li <li.xin@linaro.org>
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/slab.h>
#include "clk.h"
/* clock separated gate register offset */
#define CLKGATE_SEPARATED_ENABLE 0x0
#define CLKGATE_SEPARATED_DISABLE 0x4
#define CLKGATE_SEPARATED_STATUS 0x8
struct clkgate_separated {
struct clk_hw hw;
void __iomem *enable; /* enable register */
u8 bit_idx; /* bits in enable/disable register */
u8 flags;
spinlock_t *lock;
};
static int clkgate_separated_enable(struct clk_hw *hw)
{
struct clkgate_separated *sclk;
unsigned long flags = 0;
u32 reg;
sclk = container_of(hw, struct clkgate_separated, hw);
if (sclk->lock)
spin_lock_irqsave(sclk->lock, flags);
reg = BIT(sclk->bit_idx);
writel_relaxed(reg, sclk->enable);
readl_relaxed(sclk->enable + CLKGATE_SEPARATED_STATUS);
if (sclk->lock)
spin_unlock_irqrestore(sclk->lock, flags);
return 0;
}
static void clkgate_separated_disable(struct clk_hw *hw)
{
struct clkgate_separated *sclk;
unsigned long flags = 0;
u32 reg;
sclk = container_of(hw, struct clkgate_separated, hw);
if (sclk->lock)
spin_lock_irqsave(sclk->lock, flags);
reg = BIT(sclk->bit_idx);
writel_relaxed(reg, sclk->enable + CLKGATE_SEPARATED_DISABLE);
readl_relaxed(sclk->enable + CLKGATE_SEPARATED_STATUS);
if (sclk->lock)
spin_unlock_irqrestore(sclk->lock, flags);
}
static int clkgate_separated_is_enabled(struct clk_hw *hw)
{
struct clkgate_separated *sclk;
u32 reg;
sclk = container_of(hw, struct clkgate_separated, hw);
reg = readl_relaxed(sclk->enable + CLKGATE_SEPARATED_STATUS);
reg &= BIT(sclk->bit_idx);
return reg ? 1 : 0;
}
static const struct clk_ops clkgate_separated_ops = {
.enable = clkgate_separated_enable,
.disable = clkgate_separated_disable,
.is_enabled = clkgate_separated_is_enabled,
};
struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name,
const char *parent_name,
unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock)
{
struct clkgate_separated *sclk;
struct clk *clk;
struct clk_init_data init;
sclk = kzalloc_obj(*sclk);
if (!sclk)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &clkgate_separated_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
sclk->enable = reg + CLKGATE_SEPARATED_ENABLE;
sclk->bit_idx = bit_idx;
sclk->flags = clk_gate_flags;
sclk->hw.init = &init;
sclk->lock = lock;
clk = clk_register(dev, &sclk->hw);
if (IS_ERR(clk))
kfree(sclk);
return clk;
}
@@ -0,0 +1,317 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hi3516CV300 Clock and Reset Generator Driver
*
* Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
*/
#include <dt-bindings/clock/hi3516cv300-clock.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "clk.h"
#include "crg.h"
#include "reset.h"
/* hi3516CV300 core CRG */
#define HI3516CV300_INNER_CLK_OFFSET 64
#define HI3516CV300_FIXED_3M 65
#define HI3516CV300_FIXED_6M 66
#define HI3516CV300_FIXED_24M 67
#define HI3516CV300_FIXED_49P5 68
#define HI3516CV300_FIXED_50M 69
#define HI3516CV300_FIXED_83P3M 70
#define HI3516CV300_FIXED_99M 71
#define HI3516CV300_FIXED_100M 72
#define HI3516CV300_FIXED_148P5M 73
#define HI3516CV300_FIXED_198M 74
#define HI3516CV300_FIXED_297M 75
#define HI3516CV300_UART_MUX 76
#define HI3516CV300_FMC_MUX 77
#define HI3516CV300_MMC0_MUX 78
#define HI3516CV300_MMC1_MUX 79
#define HI3516CV300_MMC2_MUX 80
#define HI3516CV300_MMC3_MUX 81
#define HI3516CV300_PWM_MUX 82
#define HI3516CV300_CRG_NR_CLKS 128
static const struct hisi_fixed_rate_clock hi3516cv300_fixed_rate_clks[] = {
{ HI3516CV300_FIXED_3M, "3m", NULL, 0, 3000000, },
{ HI3516CV300_FIXED_6M, "6m", NULL, 0, 6000000, },
{ HI3516CV300_FIXED_24M, "24m", NULL, 0, 24000000, },
{ HI3516CV300_FIXED_49P5, "49.5m", NULL, 0, 49500000, },
{ HI3516CV300_FIXED_50M, "50m", NULL, 0, 50000000, },
{ HI3516CV300_FIXED_83P3M, "83.3m", NULL, 0, 83300000, },
{ HI3516CV300_FIXED_99M, "99m", NULL, 0, 99000000, },
{ HI3516CV300_FIXED_100M, "100m", NULL, 0, 100000000, },
{ HI3516CV300_FIXED_148P5M, "148.5m", NULL, 0, 148500000, },
{ HI3516CV300_FIXED_198M, "198m", NULL, 0, 198000000, },
{ HI3516CV300_FIXED_297M, "297m", NULL, 0, 297000000, },
{ HI3516CV300_APB_CLK, "apb", NULL, 0, 50000000, },
};
static const char *const uart_mux_p[] = {"24m", "6m"};
static const char *const fmc_mux_p[] = {
"24m", "83.3m", "148.5m", "198m", "297m"
};
static const char *const mmc_mux_p[] = {"49.5m"};
static const char *const mmc2_mux_p[] = {"99m", "49.5m"};
static const char *const pwm_mux_p[] = {"3m", "50m", "24m", "24m"};
static u32 uart_mux_table[] = {0, 1};
static u32 fmc_mux_table[] = {0, 1, 2, 3, 4};
static u32 mmc_mux_table[] = {0};
static u32 mmc2_mux_table[] = {0, 2};
static u32 pwm_mux_table[] = {0, 1, 2, 3};
static const struct hisi_mux_clock hi3516cv300_mux_clks[] = {
{ HI3516CV300_UART_MUX, "uart_mux", uart_mux_p, ARRAY_SIZE(uart_mux_p),
CLK_SET_RATE_PARENT, 0xe4, 19, 1, 0, uart_mux_table, },
{ HI3516CV300_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, },
{ HI3516CV300_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
CLK_SET_RATE_PARENT, 0xc4, 4, 2, 0, mmc_mux_table, },
{ HI3516CV300_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
CLK_SET_RATE_PARENT, 0xc4, 12, 2, 0, mmc_mux_table, },
{ HI3516CV300_MMC2_MUX, "mmc2_mux", mmc2_mux_p, ARRAY_SIZE(mmc2_mux_p),
CLK_SET_RATE_PARENT, 0xc4, 20, 2, 0, mmc2_mux_table, },
{ HI3516CV300_MMC3_MUX, "mmc3_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
CLK_SET_RATE_PARENT, 0xc8, 4, 2, 0, mmc_mux_table, },
{ HI3516CV300_PWM_MUX, "pwm_mux", pwm_mux_p, ARRAY_SIZE(pwm_mux_p),
CLK_SET_RATE_PARENT, 0x38, 2, 2, 0, pwm_mux_table, },
};
static const struct hisi_gate_clock hi3516cv300_gate_clks[] = {
{ HI3516CV300_UART0_CLK, "clk_uart0", "uart_mux", CLK_SET_RATE_PARENT,
0xe4, 15, 0, },
{ HI3516CV300_UART1_CLK, "clk_uart1", "uart_mux", CLK_SET_RATE_PARENT,
0xe4, 16, 0, },
{ HI3516CV300_UART2_CLK, "clk_uart2", "uart_mux", CLK_SET_RATE_PARENT,
0xe4, 17, 0, },
{ HI3516CV300_SPI0_CLK, "clk_spi0", "100m", CLK_SET_RATE_PARENT,
0xe4, 13, 0, },
{ HI3516CV300_SPI1_CLK, "clk_spi1", "100m", CLK_SET_RATE_PARENT,
0xe4, 14, 0, },
{ HI3516CV300_FMC_CLK, "clk_fmc", "fmc_mux", CLK_SET_RATE_PARENT,
0xc0, 1, 0, },
{ HI3516CV300_MMC0_CLK, "clk_mmc0", "mmc0_mux", CLK_SET_RATE_PARENT,
0xc4, 1, 0, },
{ HI3516CV300_MMC1_CLK, "clk_mmc1", "mmc1_mux", CLK_SET_RATE_PARENT,
0xc4, 9, 0, },
{ HI3516CV300_MMC2_CLK, "clk_mmc2", "mmc2_mux", CLK_SET_RATE_PARENT,
0xc4, 17, 0, },
{ HI3516CV300_MMC3_CLK, "clk_mmc3", "mmc3_mux", CLK_SET_RATE_PARENT,
0xc8, 1, 0, },
{ HI3516CV300_ETH_CLK, "clk_eth", NULL, 0, 0xec, 1, 0, },
{ HI3516CV300_DMAC_CLK, "clk_dmac", NULL, 0, 0xd8, 5, 0, },
{ HI3516CV300_PWM_CLK, "clk_pwm", "pwm_mux", CLK_SET_RATE_PARENT,
0x38, 1, 0, },
{ HI3516CV300_USB2_BUS_CLK, "clk_usb2_bus", NULL, 0, 0xb8, 0, 0, },
{ HI3516CV300_USB2_OHCI48M_CLK, "clk_usb2_ohci48m", NULL, 0,
0xb8, 1, 0, },
{ HI3516CV300_USB2_OHCI12M_CLK, "clk_usb2_ohci12m", NULL, 0,
0xb8, 2, 0, },
{ HI3516CV300_USB2_OTG_UTMI_CLK, "clk_usb2_otg_utmi", NULL, 0,
0xb8, 3, 0, },
{ HI3516CV300_USB2_HST_PHY_CLK, "clk_usb2_hst_phy", NULL, 0,
0xb8, 4, 0, },
{ HI3516CV300_USB2_UTMI0_CLK, "clk_usb2_utmi0", NULL, 0, 0xb8, 5, 0, },
{ HI3516CV300_USB2_PHY_CLK, "clk_usb2_phy", NULL, 0, 0xb8, 7, 0, },
};
static struct hisi_clock_data *hi3516cv300_clk_register(
struct platform_device *pdev)
{
struct hisi_clock_data *clk_data;
int ret;
clk_data = hisi_clk_alloc(pdev, HI3516CV300_CRG_NR_CLKS);
if (!clk_data)
return ERR_PTR(-ENOMEM);
ret = hisi_clk_register_fixed_rate(hi3516cv300_fixed_rate_clks,
ARRAY_SIZE(hi3516cv300_fixed_rate_clks), clk_data);
if (ret)
return ERR_PTR(ret);
ret = hisi_clk_register_mux(hi3516cv300_mux_clks,
ARRAY_SIZE(hi3516cv300_mux_clks), clk_data);
if (ret)
goto unregister_fixed_rate;
ret = hisi_clk_register_gate(hi3516cv300_gate_clks,
ARRAY_SIZE(hi3516cv300_gate_clks), clk_data);
if (ret)
goto unregister_mux;
ret = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, &clk_data->clk_data);
if (ret)
goto unregister_gate;
return clk_data;
unregister_gate:
hisi_clk_unregister_gate(hi3516cv300_gate_clks,
ARRAY_SIZE(hi3516cv300_gate_clks), clk_data);
unregister_mux:
hisi_clk_unregister_mux(hi3516cv300_mux_clks,
ARRAY_SIZE(hi3516cv300_mux_clks), clk_data);
unregister_fixed_rate:
hisi_clk_unregister_fixed_rate(hi3516cv300_fixed_rate_clks,
ARRAY_SIZE(hi3516cv300_fixed_rate_clks), clk_data);
return ERR_PTR(ret);
}
static void hi3516cv300_clk_unregister(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
hisi_clk_unregister_gate(hi3516cv300_gate_clks,
ARRAY_SIZE(hi3516cv300_gate_clks), crg->clk_data);
hisi_clk_unregister_mux(hi3516cv300_mux_clks,
ARRAY_SIZE(hi3516cv300_mux_clks), crg->clk_data);
hisi_clk_unregister_fixed_rate(hi3516cv300_fixed_rate_clks,
ARRAY_SIZE(hi3516cv300_fixed_rate_clks), crg->clk_data);
}
static const struct hisi_crg_funcs hi3516cv300_crg_funcs = {
.register_clks = hi3516cv300_clk_register,
.unregister_clks = hi3516cv300_clk_unregister,
};
/* hi3516CV300 sysctrl CRG */
#define HI3516CV300_SYSCTRL_NR_CLKS 16
static const char *const wdt_mux_p[] __initconst = { "3m", "apb" };
static u32 wdt_mux_table[] = {0, 1};
static const struct hisi_mux_clock hi3516cv300_sysctrl_mux_clks[] = {
{ HI3516CV300_WDT_CLK, "wdt", wdt_mux_p, ARRAY_SIZE(wdt_mux_p),
CLK_SET_RATE_PARENT, 0x0, 23, 1, 0, wdt_mux_table, },
};
static struct hisi_clock_data *hi3516cv300_sysctrl_clk_register(
struct platform_device *pdev)
{
struct hisi_clock_data *clk_data;
int ret;
clk_data = hisi_clk_alloc(pdev, HI3516CV300_SYSCTRL_NR_CLKS);
if (!clk_data)
return ERR_PTR(-ENOMEM);
ret = hisi_clk_register_mux(hi3516cv300_sysctrl_mux_clks,
ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks), clk_data);
if (ret)
return ERR_PTR(ret);
ret = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, &clk_data->clk_data);
if (ret)
goto unregister_mux;
return clk_data;
unregister_mux:
hisi_clk_unregister_mux(hi3516cv300_sysctrl_mux_clks,
ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks), clk_data);
return ERR_PTR(ret);
}
static void hi3516cv300_sysctrl_clk_unregister(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
hisi_clk_unregister_mux(hi3516cv300_sysctrl_mux_clks,
ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks),
crg->clk_data);
}
static const struct hisi_crg_funcs hi3516cv300_sysctrl_funcs = {
.register_clks = hi3516cv300_sysctrl_clk_register,
.unregister_clks = hi3516cv300_sysctrl_clk_unregister,
};
static const struct of_device_id hi3516cv300_crg_match_table[] = {
{
.compatible = "hisilicon,hi3516cv300-crg",
.data = &hi3516cv300_crg_funcs
},
{
.compatible = "hisilicon,hi3516cv300-sysctrl",
.data = &hi3516cv300_sysctrl_funcs
},
{ }
};
MODULE_DEVICE_TABLE(of, hi3516cv300_crg_match_table);
static int hi3516cv300_crg_probe(struct platform_device *pdev)
{
struct hisi_crg_dev *crg;
crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
if (!crg)
return -ENOMEM;
crg->funcs = of_device_get_match_data(&pdev->dev);
if (!crg->funcs)
return -ENOENT;
crg->rstc = hisi_reset_init(pdev);
if (!crg->rstc)
return -ENOMEM;
crg->clk_data = crg->funcs->register_clks(pdev);
if (IS_ERR(crg->clk_data)) {
hisi_reset_exit(crg->rstc);
return PTR_ERR(crg->clk_data);
}
platform_set_drvdata(pdev, crg);
return 0;
}
static void hi3516cv300_crg_remove(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
hisi_reset_exit(crg->rstc);
crg->funcs->unregister_clks(pdev);
}
static struct platform_driver hi3516cv300_crg_driver = {
.probe = hi3516cv300_crg_probe,
.remove = hi3516cv300_crg_remove,
.driver = {
.name = "hi3516cv300-crg",
.of_match_table = hi3516cv300_crg_match_table,
},
};
static int __init hi3516cv300_crg_init(void)
{
return platform_driver_register(&hi3516cv300_crg_driver);
}
core_initcall(hi3516cv300_crg_init);
static void __exit hi3516cv300_crg_exit(void)
{
platform_driver_unregister(&hi3516cv300_crg_driver);
}
module_exit(hi3516cv300_crg_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("HiSilicon Hi3516CV300 CRG Driver");
@@ -0,0 +1,400 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hi3798CV200 Clock and Reset Generator Driver
*
* Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
*/
#include <dt-bindings/clock/histb-clock.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "clk.h"
#include "crg.h"
#include "reset.h"
/* hi3798CV200 core CRG */
#define HI3798CV200_INNER_CLK_OFFSET 64
#define HI3798CV200_FIXED_24M 65
#define HI3798CV200_FIXED_25M 66
#define HI3798CV200_FIXED_50M 67
#define HI3798CV200_FIXED_75M 68
#define HI3798CV200_FIXED_100M 69
#define HI3798CV200_FIXED_150M 70
#define HI3798CV200_FIXED_200M 71
#define HI3798CV200_FIXED_250M 72
#define HI3798CV200_FIXED_300M 73
#define HI3798CV200_FIXED_400M 74
#define HI3798CV200_MMC_MUX 75
#define HI3798CV200_ETH_PUB_CLK 76
#define HI3798CV200_ETH_BUS_CLK 77
#define HI3798CV200_ETH_BUS0_CLK 78
#define HI3798CV200_ETH_BUS1_CLK 79
#define HI3798CV200_COMBPHY1_MUX 80
#define HI3798CV200_FIXED_12M 81
#define HI3798CV200_FIXED_48M 82
#define HI3798CV200_FIXED_60M 83
#define HI3798CV200_FIXED_166P5M 84
#define HI3798CV200_SDIO0_MUX 85
#define HI3798CV200_COMBPHY0_MUX 86
#define HI3798CV200_CRG_NR_CLKS 128
static const struct hisi_fixed_rate_clock hi3798cv200_fixed_rate_clks[] = {
{ HISTB_OSC_CLK, "clk_osc", NULL, 0, 24000000, },
{ HISTB_APB_CLK, "clk_apb", NULL, 0, 100000000, },
{ HISTB_AHB_CLK, "clk_ahb", NULL, 0, 200000000, },
{ HI3798CV200_FIXED_12M, "12m", NULL, 0, 12000000, },
{ HI3798CV200_FIXED_24M, "24m", NULL, 0, 24000000, },
{ HI3798CV200_FIXED_25M, "25m", NULL, 0, 25000000, },
{ HI3798CV200_FIXED_48M, "48m", NULL, 0, 48000000, },
{ HI3798CV200_FIXED_50M, "50m", NULL, 0, 50000000, },
{ HI3798CV200_FIXED_60M, "60m", NULL, 0, 60000000, },
{ HI3798CV200_FIXED_75M, "75m", NULL, 0, 75000000, },
{ HI3798CV200_FIXED_100M, "100m", NULL, 0, 100000000, },
{ HI3798CV200_FIXED_150M, "150m", NULL, 0, 150000000, },
{ HI3798CV200_FIXED_166P5M, "166p5m", NULL, 0, 165000000, },
{ HI3798CV200_FIXED_200M, "200m", NULL, 0, 200000000, },
{ HI3798CV200_FIXED_250M, "250m", NULL, 0, 250000000, },
};
static const char *const mmc_mux_p[] = {
"100m", "50m", "25m", "200m", "150m" };
static u32 mmc_mux_table[] = {0, 1, 2, 3, 6};
static const char *const comphy_mux_p[] = {
"100m", "25m"};
static u32 comphy_mux_table[] = {2, 3};
static const char *const sdio_mux_p[] = {
"100m", "50m", "150m", "166p5m" };
static u32 sdio_mux_table[] = {0, 1, 2, 3};
static struct hisi_mux_clock hi3798cv200_mux_clks[] = {
{ HI3798CV200_MMC_MUX, "mmc_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
CLK_SET_RATE_PARENT, 0xa0, 8, 3, 0, mmc_mux_table, },
{ HI3798CV200_COMBPHY0_MUX, "combphy0_mux",
comphy_mux_p, ARRAY_SIZE(comphy_mux_p),
CLK_SET_RATE_PARENT, 0x188, 2, 2, 0, comphy_mux_table, },
{ HI3798CV200_COMBPHY1_MUX, "combphy1_mux",
comphy_mux_p, ARRAY_SIZE(comphy_mux_p),
CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy_mux_table, },
{ HI3798CV200_SDIO0_MUX, "sdio0_mux", sdio_mux_p,
ARRAY_SIZE(sdio_mux_p), CLK_SET_RATE_PARENT,
0x9c, 8, 2, 0, sdio_mux_table, },
};
static u32 mmc_phase_regvals[] = {0, 1, 2, 3, 4, 5, 6, 7};
static u32 mmc_phase_degrees[] = {0, 45, 90, 135, 180, 225, 270, 315};
static struct hisi_phase_clock hi3798cv200_phase_clks[] = {
{ HISTB_MMC_SAMPLE_CLK, "mmc_sample", "clk_mmc_ciu",
CLK_SET_RATE_PARENT, 0xa0, 12, 3, mmc_phase_degrees,
mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) },
{ HISTB_MMC_DRV_CLK, "mmc_drive", "clk_mmc_ciu",
CLK_SET_RATE_PARENT, 0xa0, 16, 3, mmc_phase_degrees,
mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) },
};
static const struct hisi_gate_clock hi3798cv200_gate_clks[] = {
/* UART */
{ HISTB_UART2_CLK, "clk_uart2", "75m",
CLK_SET_RATE_PARENT, 0x68, 4, 0, },
/* I2C */
{ HISTB_I2C0_CLK, "clk_i2c0", "clk_apb",
CLK_SET_RATE_PARENT, 0x6C, 4, 0, },
{ HISTB_I2C1_CLK, "clk_i2c1", "clk_apb",
CLK_SET_RATE_PARENT, 0x6C, 8, 0, },
{ HISTB_I2C2_CLK, "clk_i2c2", "clk_apb",
CLK_SET_RATE_PARENT, 0x6C, 12, 0, },
{ HISTB_I2C3_CLK, "clk_i2c3", "clk_apb",
CLK_SET_RATE_PARENT, 0x6C, 16, 0, },
{ HISTB_I2C4_CLK, "clk_i2c4", "clk_apb",
CLK_SET_RATE_PARENT, 0x6C, 20, 0, },
/* SPI */
{ HISTB_SPI0_CLK, "clk_spi0", "clk_apb",
CLK_SET_RATE_PARENT, 0x70, 0, 0, },
/* SDIO */
{ HISTB_SDIO0_BIU_CLK, "clk_sdio0_biu", "200m",
CLK_SET_RATE_PARENT, 0x9c, 0, 0, },
{ HISTB_SDIO0_CIU_CLK, "clk_sdio0_ciu", "sdio0_mux",
CLK_SET_RATE_PARENT, 0x9c, 1, 0, },
/* EMMC */
{ HISTB_MMC_BIU_CLK, "clk_mmc_biu", "200m",
CLK_SET_RATE_PARENT, 0xa0, 0, 0, },
{ HISTB_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux",
CLK_SET_RATE_PARENT, 0xa0, 1, 0, },
/* PCIE*/
{ HISTB_PCIE_BUS_CLK, "clk_pcie_bus", "200m",
CLK_SET_RATE_PARENT, 0x18c, 0, 0, },
{ HISTB_PCIE_SYS_CLK, "clk_pcie_sys", "100m",
CLK_SET_RATE_PARENT, 0x18c, 1, 0, },
{ HISTB_PCIE_PIPE_CLK, "clk_pcie_pipe", "250m",
CLK_SET_RATE_PARENT, 0x18c, 2, 0, },
{ HISTB_PCIE_AUX_CLK, "clk_pcie_aux", "24m",
CLK_SET_RATE_PARENT, 0x18c, 3, 0, },
/* Ethernet */
{ HI3798CV200_ETH_PUB_CLK, "clk_pub", NULL,
CLK_SET_RATE_PARENT, 0xcc, 5, 0, },
{ HI3798CV200_ETH_BUS_CLK, "clk_bus", "clk_pub",
CLK_SET_RATE_PARENT, 0xcc, 0, 0, },
{ HI3798CV200_ETH_BUS0_CLK, "clk_bus_m0", "clk_bus",
CLK_SET_RATE_PARENT, 0xcc, 1, 0, },
{ HI3798CV200_ETH_BUS1_CLK, "clk_bus_m1", "clk_bus",
CLK_SET_RATE_PARENT, 0xcc, 2, 0, },
{ HISTB_ETH0_MAC_CLK, "clk_mac0", "clk_bus_m0",
CLK_SET_RATE_PARENT, 0xcc, 3, 0, },
{ HISTB_ETH0_MACIF_CLK, "clk_macif0", "clk_bus_m0",
CLK_SET_RATE_PARENT, 0xcc, 24, 0, },
{ HISTB_ETH1_MAC_CLK, "clk_mac1", "clk_bus_m1",
CLK_SET_RATE_PARENT, 0xcc, 4, 0, },
{ HISTB_ETH1_MACIF_CLK, "clk_macif1", "clk_bus_m1",
CLK_SET_RATE_PARENT, 0xcc, 25, 0, },
/* COMBPHY0 */
{ HISTB_COMBPHY0_CLK, "clk_combphy0", "combphy0_mux",
CLK_SET_RATE_PARENT, 0x188, 0, 0, },
/* COMBPHY1 */
{ HISTB_COMBPHY1_CLK, "clk_combphy1", "combphy1_mux",
CLK_SET_RATE_PARENT, 0x188, 8, 0, },
/* USB2 */
{ HISTB_USB2_BUS_CLK, "clk_u2_bus", "clk_ahb",
CLK_SET_RATE_PARENT, 0xb8, 0, 0, },
{ HISTB_USB2_PHY_CLK, "clk_u2_phy", "60m",
CLK_SET_RATE_PARENT, 0xb8, 4, 0, },
{ HISTB_USB2_12M_CLK, "clk_u2_12m", "12m",
CLK_SET_RATE_PARENT, 0xb8, 2, 0 },
{ HISTB_USB2_48M_CLK, "clk_u2_48m", "48m",
CLK_SET_RATE_PARENT, 0xb8, 1, 0 },
{ HISTB_USB2_UTMI_CLK, "clk_u2_utmi", "60m",
CLK_SET_RATE_PARENT, 0xb8, 5, 0 },
{ HISTB_USB2_OTG_UTMI_CLK, "clk_u2_otg_utmi", "60m",
CLK_SET_RATE_PARENT, 0xb8, 3, 0 },
{ HISTB_USB2_PHY1_REF_CLK, "clk_u2_phy1_ref", "24m",
CLK_SET_RATE_PARENT, 0xbc, 0, 0 },
{ HISTB_USB2_PHY2_REF_CLK, "clk_u2_phy2_ref", "24m",
CLK_SET_RATE_PARENT, 0xbc, 2, 0 },
/* USB3 */
{ HISTB_USB3_BUS_CLK, "clk_u3_bus", NULL,
CLK_SET_RATE_PARENT, 0xb0, 0, 0 },
{ HISTB_USB3_UTMI_CLK, "clk_u3_utmi", NULL,
CLK_SET_RATE_PARENT, 0xb0, 4, 0 },
{ HISTB_USB3_PIPE_CLK, "clk_u3_pipe", NULL,
CLK_SET_RATE_PARENT, 0xb0, 3, 0 },
{ HISTB_USB3_SUSPEND_CLK, "clk_u3_suspend", NULL,
CLK_SET_RATE_PARENT, 0xb0, 2, 0 },
{ HISTB_USB3_BUS_CLK1, "clk_u3_bus1", NULL,
CLK_SET_RATE_PARENT, 0xb0, 16, 0 },
{ HISTB_USB3_UTMI_CLK1, "clk_u3_utmi1", NULL,
CLK_SET_RATE_PARENT, 0xb0, 20, 0 },
{ HISTB_USB3_PIPE_CLK1, "clk_u3_pipe1", NULL,
CLK_SET_RATE_PARENT, 0xb0, 19, 0 },
{ HISTB_USB3_SUSPEND_CLK1, "clk_u3_suspend1", NULL,
CLK_SET_RATE_PARENT, 0xb0, 18, 0 },
};
static struct hisi_clock_data *hi3798cv200_clk_register(
struct platform_device *pdev)
{
struct hisi_clock_data *clk_data;
int ret;
clk_data = hisi_clk_alloc(pdev, HI3798CV200_CRG_NR_CLKS);
if (!clk_data)
return ERR_PTR(-ENOMEM);
/* hisi_phase_clock is resource managed */
ret = hisi_clk_register_phase(&pdev->dev,
hi3798cv200_phase_clks,
ARRAY_SIZE(hi3798cv200_phase_clks),
clk_data);
if (ret)
return ERR_PTR(ret);
ret = hisi_clk_register_fixed_rate(hi3798cv200_fixed_rate_clks,
ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
clk_data);
if (ret)
return ERR_PTR(ret);
ret = hisi_clk_register_mux(hi3798cv200_mux_clks,
ARRAY_SIZE(hi3798cv200_mux_clks),
clk_data);
if (ret)
goto unregister_fixed_rate;
ret = hisi_clk_register_gate(hi3798cv200_gate_clks,
ARRAY_SIZE(hi3798cv200_gate_clks),
clk_data);
if (ret)
goto unregister_mux;
ret = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, &clk_data->clk_data);
if (ret)
goto unregister_gate;
return clk_data;
unregister_gate:
hisi_clk_unregister_gate(hi3798cv200_gate_clks,
ARRAY_SIZE(hi3798cv200_gate_clks),
clk_data);
unregister_mux:
hisi_clk_unregister_mux(hi3798cv200_mux_clks,
ARRAY_SIZE(hi3798cv200_mux_clks),
clk_data);
unregister_fixed_rate:
hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks,
ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
clk_data);
return ERR_PTR(ret);
}
static void hi3798cv200_clk_unregister(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
hisi_clk_unregister_gate(hi3798cv200_gate_clks,
ARRAY_SIZE(hi3798cv200_gate_clks),
crg->clk_data);
hisi_clk_unregister_mux(hi3798cv200_mux_clks,
ARRAY_SIZE(hi3798cv200_mux_clks),
crg->clk_data);
hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks,
ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
crg->clk_data);
}
static const struct hisi_crg_funcs hi3798cv200_crg_funcs = {
.register_clks = hi3798cv200_clk_register,
.unregister_clks = hi3798cv200_clk_unregister,
};
/* hi3798CV200 sysctrl CRG */
#define HI3798CV200_SYSCTRL_NR_CLKS 16
static const struct hisi_gate_clock hi3798cv200_sysctrl_gate_clks[] = {
{ HISTB_IR_CLK, "clk_ir", "24m",
CLK_SET_RATE_PARENT, 0x48, 4, 0, },
{ HISTB_TIMER01_CLK, "clk_timer01", "24m",
CLK_SET_RATE_PARENT, 0x48, 6, 0, },
{ HISTB_UART0_CLK, "clk_uart0", "75m",
CLK_SET_RATE_PARENT, 0x48, 10, 0, },
};
static struct hisi_clock_data *hi3798cv200_sysctrl_clk_register(
struct platform_device *pdev)
{
struct hisi_clock_data *clk_data;
int ret;
clk_data = hisi_clk_alloc(pdev, HI3798CV200_SYSCTRL_NR_CLKS);
if (!clk_data)
return ERR_PTR(-ENOMEM);
ret = hisi_clk_register_gate(hi3798cv200_sysctrl_gate_clks,
ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
clk_data);
if (ret)
return ERR_PTR(ret);
ret = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, &clk_data->clk_data);
if (ret)
goto unregister_gate;
return clk_data;
unregister_gate:
hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks,
ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
clk_data);
return ERR_PTR(ret);
}
static void hi3798cv200_sysctrl_clk_unregister(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks,
ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
crg->clk_data);
}
static const struct hisi_crg_funcs hi3798cv200_sysctrl_funcs = {
.register_clks = hi3798cv200_sysctrl_clk_register,
.unregister_clks = hi3798cv200_sysctrl_clk_unregister,
};
static const struct of_device_id hi3798cv200_crg_match_table[] = {
{ .compatible = "hisilicon,hi3798cv200-crg",
.data = &hi3798cv200_crg_funcs },
{ .compatible = "hisilicon,hi3798cv200-sysctrl",
.data = &hi3798cv200_sysctrl_funcs },
{ }
};
MODULE_DEVICE_TABLE(of, hi3798cv200_crg_match_table);
static int hi3798cv200_crg_probe(struct platform_device *pdev)
{
struct hisi_crg_dev *crg;
crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
if (!crg)
return -ENOMEM;
crg->funcs = of_device_get_match_data(&pdev->dev);
if (!crg->funcs)
return -ENOENT;
crg->rstc = hisi_reset_init(pdev);
if (!crg->rstc)
return -ENOMEM;
crg->clk_data = crg->funcs->register_clks(pdev);
if (IS_ERR(crg->clk_data)) {
hisi_reset_exit(crg->rstc);
return PTR_ERR(crg->clk_data);
}
platform_set_drvdata(pdev, crg);
return 0;
}
static void hi3798cv200_crg_remove(struct platform_device *pdev)
{
struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
hisi_reset_exit(crg->rstc);
crg->funcs->unregister_clks(pdev);
}
static struct platform_driver hi3798cv200_crg_driver = {
.probe = hi3798cv200_crg_probe,
.remove = hi3798cv200_crg_remove,
.driver = {
.name = "hi3798cv200-crg",
.of_match_table = hi3798cv200_crg_match_table,
},
};
static int __init hi3798cv200_crg_init(void)
{
return platform_driver_register(&hi3798cv200_crg_driver);
}
core_initcall(hi3798cv200_crg_init);
static void __exit hi3798cv200_crg_exit(void)
{
platform_driver_unregister(&hi3798cv200_crg_driver);
}
module_exit(hi3798cv200_crg_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("HiSilicon Hi3798CV200 CRG Driver");
+25
View File
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* HiSilicon Clock and Reset Driver Header
*
* Copyright (c) 2016 HiSilicon Limited.
*/
#ifndef __HISI_CRG_H
#define __HISI_CRG_H
struct hisi_clock_data;
struct hisi_reset_controller;
struct hisi_crg_funcs {
struct hisi_clock_data* (*register_clks)(struct platform_device *pdev);
void (*unregister_clks)(struct platform_device *pdev);
};
struct hisi_crg_dev {
struct hisi_clock_data *clk_data;
struct hisi_reset_controller *rstc;
const struct hisi_crg_funcs *funcs;
};
#endif /* __HISI_CRG_H */
+118
View File
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hisilicon Reset Controller Driver
*
* Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd.
*/
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "reset.h"
#define HISI_RESET_BIT_MASK 0x1f
#define HISI_RESET_OFFSET_SHIFT 8
#define HISI_RESET_OFFSET_MASK 0xffff00
struct hisi_reset_controller {
spinlock_t lock;
void __iomem *membase;
struct reset_controller_dev rcdev;
};
#define to_hisi_reset_controller(rcdev) \
container_of(rcdev, struct hisi_reset_controller, rcdev)
static int hisi_reset_of_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec)
{
u32 offset;
u8 bit;
offset = (reset_spec->args[0] << HISI_RESET_OFFSET_SHIFT)
& HISI_RESET_OFFSET_MASK;
bit = reset_spec->args[1] & HISI_RESET_BIT_MASK;
return (offset | bit);
}
static int hisi_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct hisi_reset_controller *rstc = to_hisi_reset_controller(rcdev);
unsigned long flags;
u32 offset, reg;
u8 bit;
offset = (id & HISI_RESET_OFFSET_MASK) >> HISI_RESET_OFFSET_SHIFT;
bit = id & HISI_RESET_BIT_MASK;
spin_lock_irqsave(&rstc->lock, flags);
reg = readl(rstc->membase + offset);
writel(reg | BIT(bit), rstc->membase + offset);
spin_unlock_irqrestore(&rstc->lock, flags);
return 0;
}
static int hisi_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct hisi_reset_controller *rstc = to_hisi_reset_controller(rcdev);
unsigned long flags;
u32 offset, reg;
u8 bit;
offset = (id & HISI_RESET_OFFSET_MASK) >> HISI_RESET_OFFSET_SHIFT;
bit = id & HISI_RESET_BIT_MASK;
spin_lock_irqsave(&rstc->lock, flags);
reg = readl(rstc->membase + offset);
writel(reg & ~BIT(bit), rstc->membase + offset);
spin_unlock_irqrestore(&rstc->lock, flags);
return 0;
}
static const struct reset_control_ops hisi_reset_ops = {
.assert = hisi_reset_assert,
.deassert = hisi_reset_deassert,
};
struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev)
{
struct hisi_reset_controller *rstc;
rstc = devm_kmalloc(&pdev->dev, sizeof(*rstc), GFP_KERNEL);
if (!rstc)
return NULL;
rstc->membase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(rstc->membase))
return NULL;
spin_lock_init(&rstc->lock);
rstc->rcdev.owner = THIS_MODULE;
rstc->rcdev.ops = &hisi_reset_ops;
rstc->rcdev.of_node = pdev->dev.of_node;
rstc->rcdev.of_reset_n_cells = 2;
rstc->rcdev.of_xlate = hisi_reset_of_xlate;
reset_controller_register(&rstc->rcdev);
return rstc;
}
EXPORT_SYMBOL_GPL(hisi_reset_init);
void hisi_reset_exit(struct hisi_reset_controller *rstc)
{
reset_controller_unregister(&rstc->rcdev);
}
EXPORT_SYMBOL_GPL(hisi_reset_exit);
+25
View File
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
*/
#ifndef __HISI_RESET_H
#define __HISI_RESET_H
struct device_node;
struct hisi_reset_controller;
#ifdef CONFIG_RESET_CONTROLLER
struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev);
void hisi_reset_exit(struct hisi_reset_controller *rstc);
#else
static inline
struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev)
{
return 0;
}
static inline void hisi_reset_exit(struct hisi_reset_controller *rstc)
{}
#endif
#endif /* __HISI_RESET_H */