blob: 53c677f628609870e053a14a221e9698152a5402 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Support for asr spi controller
*
* Copyright (C) 2021 ASR Micro Limited
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/of_address.h>
#include <linux/cputype.h>
#include <linux/clk/mmp.h>
#include <soc/asr/asrdcstat.h>
#include <soc/asr/addr-map.h>
#include <soc/asr/regs-addr.h>
#include <dt-bindings/clock/asr,asr1803.h>
#ifdef CONFIG_ASR_DEBUG
#include <soc/asr/debugfs-asr.h>
#endif
#include "clk.h"
#include "clk-asr1901.h"
#include "reset.h"
#define APBC_RTC 0x28
#define APBC_TWSI0 0x2c
#define APBC_KPC 0x30
#define APBC_TWSI1 0x60
#define APBC_TWSI2 0x70
#define APBC_TWSI3 0x74
#define APBC_TWSI4 0x7C
#define APBC_UART0 0x0
#define APBC_UART1 0x4
#define APBC_UART2 0x78
#define APBC_GPIO 0x8
#define APBC_PWM0 0xc
#define APBC_PWM1 0x10
#define APBC_PWM2 0x14
#define APBC_PWM3 0x18
#define APBC_SSP0 0x1c
#define APBC_SSP1 0x20
#define APBC_IPC 0x24
#define APBC_TIMER0 0x34
#define APBC_TIMER1 0x44
#define APBC_TIMER2 0x68
#define APBC_ONEWIRE 0x48
#define APBC_SSP2 0x4c
#define APBC_TSEN 0x6c
#define APBC_AUXADC 0xA8
#define APMU_SDH0 0x54
#define APMU_SDH1 0x58
#define APMU_SDH2 0xe0
#define APMU_USB0 0x3B8
#define APMU_USB1 0x3C0
#define APMU_PCIE 0x3CC
#define APMU_QSPI 0x60
#define MPMU_PLL2CR 0x34
#define MPMU_UART_PLL 0x14
#define MPMU_UART_PLL2 0x10CC
#define MPMU_VRCR 0x18
#define MPMU_FCCR 0x8
#define MPMU_ISCCR0 0x40
#define MPMU_ISCCR1 0x44
#define APMU_TRACE 0x108
#define APMU_GEU 0x68
#define APMU_XGMAC 0x3D4
#define CIU_MC_CONF 0x0040
#define CIU_AP_DMA_AXI_XTC 0x00f8
#define APMU_CORE_STATUS 0x090
#define APMU_PRBC 0x200
/* GBS: clock for GSSP */
#define APBC_GBS 0xc
#define APBC_GCER 0x34
#define APBC_DROTS 0x058
/* IPC clock */
#define APBC_IPC_CLK_RST 0x24
/* pll1 d1p gating feature */
#define APMU_CLK_GATE_CTRL 0x040
#define APMU_DDR_FC_CTRL (0x15C)
#define APMU_EMAC_CLK_RST_CTRL 0x3D4
static int __init __init_dcstat_debugfs_node(void);
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
{ASR1803_CLK_CLK32, "clk32", NULL, 0, 32768},
{ASR1803_CLK_VCTCXO, "vctcxo", NULL, 0, 26000000},
{ASR1803_CLK_PLL1, "pll1_624", NULL, 0, 624000000},
{ASR1803_CLK_PLL1_1248, "pll1_1248", NULL, 0, 1248000000},
{ASR1803_CLK_PLL1_1475, "pll1_1475", NULL, 0, 1475000000},
{ASR1803_CLK_PLL1_983, "pll1_983", NULL, 0, 983000000},
{ASR1803_CLK_PLL1_832, "pll1_832", NULL, 0, 832000000},
{ASR1803_CLK_PLL1_416, "pll1_416", NULL, 0, 416000000},
{ASR1803_CLK_PLL1_312, "pll1_312", NULL, 0, 312000000},
{ASR1803_CLK_PLL1_208, "pll1_208", NULL, 0, 208000000},
{ASR1803_CLK_PLL1_156, "pll1_156", NULL, 0, 156000000},
{ASR1803_CLK_DPLL_1600, "dpll_1600", NULL, 0, 1600000000},
{ASR1803_CLK_DPLL_2000, "dpll_2000", NULL, 0, 2000000000},
{ASR1803_CLK_DPLL_2133, "dpll_2133", NULL, 0, 2133000000},
{ASR1803_CLK_PLL1_249, "pll1_249", NULL, 249000000},
{ASR1803_CLK_PLL1_52, "pll1_52", NULL, 52000000},
{ASR1803_CLK_UART_58P5M, "uart_58p5m", NULL, 0, 58500000},
};
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
{ASR1803_CLK_CLK16, "clk16", "clk32", 1, 2, 0},
{ASR1803_CLK_PLL1_2, "pll1_2", "pll1_624", 1, 2, 0},
{ASR1803_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
{ASR1803_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0},
{ASR1803_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0},
{ASR1803_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0},
{ASR1803_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0},
{ASR1803_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0},
{ASR1803_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0},
{ASR1803_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0},
{ASR1803_CLK_PLL1_192, "pll1_192", "pll1_96", 1, 2, 0},
{ASR1803_CLK_PLL1_384, "pll1_384", "pll1_192", 1, 2, 0},
{ASR1803_CLK_PLL1_768, "pll1_768", "pll1_384", 1, 2, 0},
{ASR1803_CLK_PLL1_13, "pll1_13", "pll1_624", 1, 13, 0},
{ASR1803_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0},
{ASR1803_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0},
};
static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2,
.num_mask = 0x1fff,
.den_mask = 0x1fff,
.num_shift = 16,
.den_shift = 0,
};
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */
{.num = 7998, .den = 1536}, /*14.97MHZ */
{.num = 8156, .den = 1673}, /*15.99MHZ */
{.num = 3250, .den = 2000}, /*48 MHZ */
{.num = 2100, .den = 1600}, /*59.429MHZ */
{.num = 2039, .den = 1673}, /*63.999MHZ */
};
static struct mmp_clk_factor_tbl uart_factor_tbl_14m[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */
{.num = 7998, .den = 1536}, /*14.97MHZ */
{.num = 8156, .den = 418}, /*15.99MHZ */
{.num = 2039, .den = 1673}, /*63.999MHZ */
};
static struct mmp_clk_factor_tbl uart_factor_tbl_48m[] = {
{.num = 6144, .den = 960}, /*48MHZ */
{.num = 2100, .den = 400}, /*59.429MHZ */
};
static void asr1901_pll_init(struct asr1901_clk_unit *asr_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &asr_unit->unit;
mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
ARRAY_SIZE(fixed_rate_clks));
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
ARRAY_SIZE(fixed_factor_clks));
if (cpu_is_asr1906 () ) {
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
CLK_SET_RATE_PARENT,
asr_unit->mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl_14m,
ARRAY_SIZE(uart_factor_tbl_14m), NULL);
mmp_clk_add(unit, ASR1803_CLK_UART_PLL, clk);
clk = mmp_clk_register_factor("uart_pll2", "pll1_624",
CLK_SET_RATE_PARENT,
asr_unit->mpmu_base + MPMU_UART_PLL2,
&uart_factor_masks, uart_factor_tbl_48m,
ARRAY_SIZE(uart_factor_tbl_48m), NULL);
mmp_clk_add(unit, ASR1803_CLK_UART_PLL2, clk);
} else {
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
CLK_SET_RATE_PARENT,
asr_unit->mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl,
ARRAY_SIZE(uart_factor_tbl), NULL);
mmp_clk_add(unit, ASR1803_CLK_UART_PLL, clk);
}
}
static DEFINE_SPINLOCK(uart0_lock);
static DEFINE_SPINLOCK(uart1_lock);
static DEFINE_SPINLOCK(uart2_lock);
static const char *uart_parent_names[] = {"uart_58p5m", "uart_pll"};
static const char *uart_parent_names_48m[] = {"uart_58p5m", "uart_pll", "uart_pll2"};
static DEFINE_SPINLOCK(ssp0_lock);
static DEFINE_SPINLOCK(ssp1_lock);
static DEFINE_SPINLOCK(ssp2_lock);
static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
//static DEFINE_SPINLOCK(timer0_lock);
//static DEFINE_SPINLOCK(timer1_lock);
static DEFINE_SPINLOCK(kpc_lock);
//static const char *timer_parent_names[] = {"pll1_48", "clk32", "pll1_96", "pll1_192"};
static const char *kpc_parent_names[] = {"clk32", "clk32", "pll1_24"};
static DEFINE_SPINLOCK(reset_lock);
static struct mmp_param_mux_clk asr1901_uart_mux_clks[] = { /* 1901 */
{0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
{0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
{0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock},
};
static struct mmp_param_mux_clk asr1906_uart_mux_clks[] = { /* 1906 */
{0, "uart0_mux", uart_parent_names_48m, ARRAY_SIZE(uart_parent_names_48m), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
{0, "uart1_mux", uart_parent_names_48m, ARRAY_SIZE(uart_parent_names_48m), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
{0, "uart2_mux", uart_parent_names_48m, ARRAY_SIZE(uart_parent_names_48m), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock},
};
static struct mmp_param_mux_clk apbc_mux_clks[] = {
{0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock},
{0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
{0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock},
// {0, "timer0_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER0, 4, 3, 0, &timer0_lock},
// {0, "timer1_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER1, 4, 3, 0, &timer1_lock},
{0, "kpc_mux", kpc_parent_names, ARRAY_SIZE(kpc_parent_names), CLK_SET_RATE_PARENT, APBC_KPC, 4, 3, 0, &kpc_lock},
};
static struct mmp_param_gate_clk apbc_gate_clks[] = {
{ASR1803_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_TWSI2, "twsi2_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI2, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_TWSI3, "twsi3_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI3, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_TWSI4, "twsi4_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI4, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_TSEN, "tsen_clk", NULL, CLK_SET_RATE_PARENT, APBC_TSEN, 0x7, 0x3, 0x0, 0, &reset_lock},
#ifdef CONFIG_PXA_DS1WM
{ASR1803_CLK_ONWIRE, "onewire", "vctcxo", CLK_SET_RATE_PARENT, APBC_ONEWIRE, 0x7, 0x3, 0x0, 0, &reset_lock},
#endif
{ASR1803_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x87, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
{ASR1803_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_IPC, "ipc_clk", NULL, CLK_SET_RATE_PARENT, APBC_IPC, 0x7, 0x3, 0x0, 0, &reset_lock},
/* The gate clocks has mux parent. */
{ASR1803_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x7, 0x3, 0x0, 0, &uart0_lock},
{ASR1803_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x7, 0x3, 0x0, 0, &uart1_lock},
{ASR1803_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock},
{ASR1803_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x7, 0x3, 0x0, 0, &ssp0_lock},
{ASR1803_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x7, 0x3, 0x0, 0, &ssp1_lock},
{ASR1803_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock},
// {ASR1803_CLK_TIMER0, "timer0_clk", "timer0_mux", CLK_SET_RATE_PARENT, APBC_TIMER0, 0x3, 0x3, 0x0, 0, &timer0_lock},
// {ASR1803_CLK_TIMER1, "timer1_clk", "timer1_mux", CLK_SET_RATE_PARENT, APBC_TIMER1, 0x3, 0x3, 0x0, 0, &timer1_lock},
{ASR1803_CLK_KPC, "kpc_clk", "kpc_mux", CLK_SET_RATE_PARENT, APBC_KPC, 0x7, 0x3, 0x0, 0, &kpc_lock},
{ASR1803_CLK_AUXADC, "auxadc_clk", NULL, CLK_SET_RATE_PARENT, APBC_AUXADC, 0x7, 0x3, 0x0, 0, &reset_lock},
};
static void asr1901_apb_periph_clk_init(struct asr1901_clk_unit *asr_unit)
{
struct mmp_clk_unit *unit = &asr_unit->unit;
if (cpu_is_asr1901())
mmp_register_mux_clks(unit, asr1901_uart_mux_clks, asr_unit->apbc_base,
ARRAY_SIZE(asr1901_uart_mux_clks));
else
mmp_register_mux_clks(unit, asr1906_uart_mux_clks, asr_unit->apbc_base,
ARRAY_SIZE(asr1906_uart_mux_clks));
mmp_register_mux_clks(unit, apbc_mux_clks, asr_unit->apbc_base,
ARRAY_SIZE(apbc_mux_clks));
mmp_register_gate_clks(unit, apbc_gate_clks, asr_unit->apbc_base,
ARRAY_SIZE(apbc_gate_clks));
}
static DEFINE_SPINLOCK(sdh0_lock);
static DEFINE_SPINLOCK(sdh1_lock);
static const char *qspi_clk_parents[] = {
"pll1_24", "pll1_12", "pll1_8", "pll1_6",
"pll1_4", "pll1_3", "pll1_2", "pll1_416"
};
/* qspi on 1906 and later platform use new clk/res control */
static const char *qspi_clk_parents2[] = {
"pll1_416", "pll1_312", "pll1_249", "pll3_614",
"pll3_368", "pll2_737", "pll2_590", "pll1_52"
};
static struct mmp_clk_mix_config qspi_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 9, 3, 6, 12),
};
static DEFINE_SPINLOCK(usb_lock);
static DEFINE_SPINLOCK(aes_lock);
static DEFINE_SPINLOCK(xgmac_lock);
static DEFINE_SPINLOCK(trace_lock);
static DEFINE_SPINLOCK(qspi_lock);
//static DEFINE_SPINLOCK(pcie0_lock);
//static DEFINE_SPINLOCK(pcie1_lock);
static const char * const sdh_parent_names[] = {"pll1_416", "pll1_624", "pll1_13"};
static struct mmp_clk_mix_config sdh_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 8, 2, 6, 11),
};
static struct mmp_param_mux_clk apmu_mux_clks[] = {
{0, "qspi_mux", qspi_clk_parents, ARRAY_SIZE(qspi_clk_parents), CLK_SET_RATE_PARENT, APMU_QSPI, 6, 3, 0, &qspi_lock},
};
static struct mmp_param_gate_clk apmu_gate_clks[] = {
{ASR1803_CLK_USB, "usb_clk", NULL, 0, APMU_USB0, 0x1E000, 0x1E000, 0x0, 0, &usb_lock},
{ASR1803_CLK_GEU, "aes_clk", NULL, 0, APMU_GEU, 0x30, 0x30, 0x10, 0, &aes_lock},
{ASR1901_CLK_XGMAC, "xgmac-clk", NULL, 0, APMU_XGMAC, 0x3, 0x3, 0x0, 0, &xgmac_lock},
{ASR1803_CLK_DBG, "dbg_clk", NULL, 0, APMU_TRACE, 0x10008, 0x10008, 0x10000, 0, &trace_lock},
{ASR1803_CLK_TRACE, "trace_clk", NULL, 0, APMU_TRACE, 0x10010, 0x10010, 0x10000, 0, &trace_lock},
{ASR1803_CLK_SDH_AXI, "sdh_axi", NULL, 0, APMU_SDH0, 0x9, 0x9, 0x1, 0, &sdh0_lock},
// {asr1901_CLK_PCIE0, "pcie0_clk", NULL, 0, APMU_PCIE0, 0xff, 0xff, 0x0, 0, &pcie0_lock},
/* The gate clocks has mux parent. */
{ASR1803_CLK_QSPI_FCLK, "qspi_fclk", "qspi_mux", 0, APMU_QSPI, 0x12, 0x12, 0x10, 0, &qspi_lock},
};
static void asr1901_axi_periph_clk_init(struct asr1901_clk_unit *asr_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &asr_unit->unit;
mmp_register_mux_clks(unit, apmu_mux_clks, asr_unit->apmu_base,
ARRAY_SIZE(apmu_mux_clks));
mmp_register_gate_clks(unit, apmu_gate_clks, asr_unit->apmu_base,
ARRAY_SIZE(apmu_gate_clks));
#if 0
if (cpu_is_asr1826s()) {
clk = mmp_clk_register_gate(NULL, "pcie1_clk", NULL, 0,
asr_unit->apmu_base + APMU_PCIE1, 0xff, 0xff, 0x0, 0, &pcie1_lock);
mmp_clk_add(unit, asr1901_CLK_PCIE1, clk);
}
#endif
sdh_mix_config.reg_info.reg_clk_ctrl = asr_unit->apmu_base + APMU_SDH0;
clk = mmp_clk_register_mix(NULL, "sdh0_mix_clk",
(const char **)sdh_parent_names, ARRAY_SIZE(sdh_parent_names),
CLK_SET_RATE_PARENT,
&sdh_mix_config, &sdh0_lock);
clk = mmp_clk_register_gate(NULL, "sdh0_clk", "sdh0_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
asr_unit->apmu_base + APMU_SDH0,
0x12, 0x12, 0x0, 0, &sdh0_lock);
mmp_clk_add(unit, ASR1803_CLK_SDH0, clk);
clk = mmp_clk_register_dvfs_dummy("SDH0", NULL,
0, DUMMY_VL_TO_KHZ(VL0));
mmp_clk_add(unit, ASR1803_CLK_SDH0_TUNE, clk);
sdh_mix_config.reg_info.reg_clk_ctrl = asr_unit->apmu_base + APMU_SDH1;
clk = mmp_clk_register_mix(NULL, "sdh1_mix_clk",
(const char **)sdh_parent_names, ARRAY_SIZE(sdh_parent_names),
CLK_SET_RATE_PARENT,
&sdh_mix_config, &sdh1_lock);
clk = mmp_clk_register_gate(NULL, "sdh1_clk", "sdh1_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
asr_unit->apmu_base + APMU_SDH1,
0x12, 0x12, 0x0, 0, &sdh1_lock);
mmp_clk_add(unit, ASR1803_CLK_SDH1, clk);
clk = mmp_clk_register_dvfs_dummy("SDH1", NULL,
0, DUMMY_VL_TO_KHZ(VL0));
mmp_clk_add(unit, ASR1803_CLK_SDH1_TUNE, clk);
if (cpu_is_asr1906()) {
qspi_mix_config.reg_info.reg_clk_ctrl = asr_unit->apmu_base + APMU_QSPI;
clk = mmp_clk_register_mix(NULL, "qspi_mix_clk",
(const char **)qspi_clk_parents2, ARRAY_SIZE(qspi_clk_parents2),
CLK_SET_RATE_PARENT,
&qspi_mix_config, &qspi_lock);
clk = mmp_clk_register_gate(NULL, "qspi_bus", "qspi_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
asr_unit->apmu_base + APMU_QSPI,
0x12, 0x12, 0x0, 0, &qspi_lock);
mmp_clk_add(unit, ASR1803_CLK_QSPI, clk);
clk = clk_register_fixed_factor(NULL, "qspi_bus_dtr", "qspi_bus",
CLK_SET_RATE_PARENT, 1, 4);
mmp_clk_add(unit, ASR1803_CLK_QSPI_DTR, clk);
} else {
/* QSPI Bus clock */
clk = clk_register_fixed_factor(NULL, "qspi_bus", "qspi_fclk",
CLK_SET_RATE_PARENT, 1, 4);
mmp_clk_add(unit, ASR1803_CLK_QSPI, clk);
/* dummy clk for xgmac to set dvc */
clk = mmp_clk_register_dvfs_dummy("ETH", NULL,
0, DUMMY_VL_TO_KHZ(VL0));
mmp_clk_add(unit, ASR1803_CLK_XGMAC_DUMMY, clk);
}
/* QSPI bus clock */
clk = mmp_clk_register_gate(NULL, "qspi_bus_clk", NULL, 0,
asr_unit->apmu_base + APMU_QSPI,
0x9, 0x9, 0x9, 0, &qspi_lock);
mmp_clk_add(unit, ASR1803_CLK_QSPI_BUS, clk);
}
static void asr1901_clk_reset_init(struct device_node *np,
struct asr1901_clk_unit *asr_unit)
{
struct mmp_clk_reset_cell *cells;
int i, base, nr_resets_apbc, nr_resets;
nr_resets_apbc = ARRAY_SIZE(apbc_gate_clks);
nr_resets = nr_resets_apbc;
cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL);
if (!cells)
return;
base = 0;
for (i = 0; i < nr_resets_apbc; i++) {
cells[base + i].clk_id = apbc_gate_clks[i].id;
cells[base + i].reg =
asr_unit->apbc_base + apbc_gate_clks[i].offset;
cells[base + i].flags = 0;
cells[base + i].lock = apbc_gate_clks[i].lock;
cells[base + i].bits = 0x4;
}
mmp_clk_reset_register(np, cells, nr_resets);
}
static const char * const bootup_on_clock_tbl[] = {
"ipc_clk", "ripc_clk", "aes_clk", "trace_clk"
};
static const char * const bootup_off_clock_tbl[] = {
"aes_clk", "trace_clk"
};
void asr_clocks_enable(const char * const *clk_table,
int clk_table_size)
{
int i;
struct clk *clk;
for (i = 0; i < clk_table_size; i++) {
clk = __clk_lookup(clk_table[i]);
if (!IS_ERR_OR_NULL(clk))
clk_prepare_enable(clk);
else
pr_err("%s : can't find clk %s\n", __func__,
clk_table[i]);
}
}
void asr_clocks_disable(const char * const *clk_table,
int clk_table_size)
{
int i;
struct clk *clk;
for (i = 0; i < clk_table_size; i++) {
clk = __clk_lookup(clk_table[i]);
if (!IS_ERR_OR_NULL(clk))
clk_disable_unprepare(clk);
else
pr_err("%s : can't find clk %s\n", __func__,
clk_table[i]);
}
}
static void __init __maybe_unused asr1901_clk_misc_init(struct asr1901_clk_unit *asr_unit)
{
/* reset usb to prepare clean start point */
writel(0x0, asr_unit->apmu_base + APMU_USB0);
}
struct asr1901_clk_unit *global_clk_unit;
void __init asr1901_clk_init(struct device_node *np)
{
struct asr1901_clk_unit *asr_unit;
regs_addr_iomap();
asr_unit = kzalloc(sizeof(*asr_unit), GFP_KERNEL);
if (!asr_unit)
return;
asr_unit->mpmu_base = of_iomap(np, 0);
if (!asr_unit->mpmu_base) {
pr_err("failed to map mpmu registers\n");
goto free_memory;
}
asr_unit->apmu_base = of_iomap(np, 1);
if (!asr_unit->apmu_base) {
pr_err("failed to map apmu registers\n");
goto unmap_mpmu_region;
}
asr_unit->apbc_base = of_iomap(np, 2);
if (!asr_unit->apbc_base) {
pr_err("failed to map apbc registers\n");
goto unmap_apmu_region;
}
asr_unit->apbs_base = of_iomap(np, 3);
if (!asr_unit->apbs_base) {
pr_err("failed to map apbs registers\n");
goto unmap_apbs_region;
}
asr_unit->ciu_base = of_iomap(np, 4);
if (!asr_unit->ciu_base) {
pr_err("failed to map ciu registers\n");
goto unmap_ciu_region;
}
asr_unit->ddrc_base = of_iomap(np, 5);
if (!asr_unit->ddrc_base) {
pr_err("failed to map ddrc registers\n");
goto unmap_ddrc_region;
}
mmp_clk_init(np, &asr_unit->unit, ASR1803_NR_CLKS);
asr1901_clk_misc_init(asr_unit);
asr1901_pll_init(asr_unit);
asr1901_apb_periph_clk_init(asr_unit);
asr1901_axi_periph_clk_init(asr_unit);
asr1901_clk_reset_init(np, asr_unit);
asr_clocks_enable(bootup_on_clock_tbl, ARRAY_SIZE(bootup_on_clock_tbl));
/* init clock and ddr will use the dvfs_platinfo.
* make sure initialize dvfs_platinfo before clock and ddr init.
*/
#if defined(CONFIG_ASR_DVFS)
setup_asr1901_dvfs_platinfo();
#endif
asr1901_acpu_init(asr_unit);
asr1901_ddrc_init(asr_unit);
asr_clocks_disable(bootup_off_clock_tbl, ARRAY_SIZE(bootup_off_clock_tbl));
global_clk_unit = asr_unit;
return;
unmap_ddrc_region:
iounmap(asr_unit->ciu_base);
unmap_ciu_region:
iounmap(asr_unit->apbs_base);
unmap_apbs_region:
iounmap(asr_unit->apbc_base);
unmap_apmu_region:
iounmap(asr_unit->apmu_base);
unmap_mpmu_region:
iounmap(asr_unit->mpmu_base);
free_memory:
kfree(asr_unit);
}
CLK_OF_DECLARE(asr1901_clk, "asr,asr1803-clock", asr1901_clk_init);
#ifdef CONFIG_ASR_DEBUG
static struct dentry *stat;
CLK_DCSTAT_OPS(global_clk_unit->unit.clk_table[ASR1803_CLK_DDR], ddr)
CLK_DCSTAT_OPS(global_clk_unit->unit.clk_table[ASR1803_CLK_DDR], axi)
static ssize_t asr1901_clk_stats_read(struct file *filp,
char __user *buffer, size_t count, loff_t *ppos)
{
char *buf;
int len = 0, ret = 0;
unsigned int reg, size = PAGE_SIZE - 1;
void __iomem *apbc_base, *mpmu_base, *apmu_base;
apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
if (apbc_base == NULL) {
pr_err("error to ioremap APBC base\n");
return ret;
}
mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
if (mpmu_base == NULL) {
pr_err("error to ioremap MPMU base\n");
return ret;
}
apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
if (apmu_base == NULL) {
pr_err("error to ioremap APMU base\n");
return ret;
}
buf = (char *)__get_free_pages(GFP_NOIO, 0);
if (!buf)
return -ENOMEM;
len += snprintf(buf + len, size,
"|---------------|-------|\n|%14s\t|%s|\n"
"|---------------|-------|\n", "Clock Name", " Status");
/* PMU */
reg = __raw_readl(mpmu_base + MPMU_PLL2CR);
if (((reg & (3 << 8)) >> 8) == 2)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "PLL2", "off");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "PLL2", "on");
reg = __raw_readl(apmu_base + APMU_SDH0);
if ((((reg & (1 << 3)) >> 3) == 1) && (((reg & (1 << 0)) >> 0) == 1))
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SDH ACLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SDH ACLK", "off");
if ((((reg & (1 << 4)) >> 4) == 1) && (((reg & (1 << 1)) >> 1) == 1))
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SDH0 FCLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SDH0 FCLK", "off");
reg = __raw_readl(apmu_base + APMU_SDH1);
if ((((reg & (1 << 4)) >> 4) == 1) && (((reg & (1 << 1)) >> 1) == 1))
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SDH1 FCLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SDH1 FCLK", "off");
reg = __raw_readl(apmu_base + APMU_SDH2);
if ((((reg & (1 << 4)) >> 4) == 1) && (((reg & (1 << 1)) >> 1) == 1))
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SDH2 FCLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SDH2 FCLK", "off");
reg = __raw_readl(apmu_base + APMU_USB0);
if ((reg & 0x1E000) == 0x1E000)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "USB ACLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "USB ACLK", "off");
reg = __raw_readl(apmu_base + APMU_TRACE);
if (((reg & (1 << 3)) >> 3) == 1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "DBG CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "DBG CLK", "off");
if (((reg & (1 << 4)) >> 4) == 1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "TRACE CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "TRACE CLK", "off");
reg = __raw_readl(apmu_base + APMU_GEU);
if ((reg & 0x9) == 0x8)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "AES CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "AES CLK", "off");
reg = __raw_readl(apmu_base + APMU_QSPI);
if ((reg & 0x19b) == 0x19b)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "DFC CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "DFC CLK", "off");
/* APB */
reg = __raw_readl(apbc_base + APBC_TWSI0);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "TWSI0 CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "TWSI0 CLK", "off");
reg = __raw_readl(apbc_base + APBC_GPIO);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "GPIO CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "GPIO CLK", "off");
reg = __raw_readl(apbc_base + APBC_RTC);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "RTC CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "RTC CLK", "off");
reg = __raw_readl(apbc_base + APBC_UART0);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "UART0 CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "UART0 CLK", "off");
reg = __raw_readl(apbc_base + APBC_UART1);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "UART1 CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "UART1 CLK", "off");
reg = __raw_readl(apbc_base + APBC_SSP0);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SSP0 CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "SSP0 CLK", "off");
reg = __raw_readl(apbc_base + APBC_DROTS);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "THERMAL CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "THERMAL CLK", "off");
reg = __raw_readl(apbc_base + APBC_PWM0);
if ((reg & 0x1) == 0x1) {
if ((reg & 0x6) == 0x2)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "PWM0 CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "PWM0 CLK", "off");
reg = __raw_readl(apbc_base + APBC_PWM1);
if ((reg & 0x6) == 0x2)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "PWM1 CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "PWM1 CLK", "off");
} else {
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "PWM0 CLK", "off");
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "PWM1 CLK", "off");
}
reg = __raw_readl(apbc_base + APBC_IPC_CLK_RST);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "IPC CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "IPC CLK", "off");
len += snprintf(buf + len, size, "|---------------|-------|\n\n");
ret = simple_read_from_buffer(buffer, count, ppos, buf, len);
free_pages((unsigned long)buf, 0);
return ret;
}
static const struct file_operations asr1901_clk_stats_ops = {
.owner = THIS_MODULE,
.read = asr1901_clk_stats_read,
};
static int __init __init_dcstat_debugfs_node(void)
{
struct dentry *cpu_dc_stat = NULL, *ddr_dc_stat = NULL;
struct dentry *axi_dc_stat = NULL;
struct dentry *clock_status = NULL;
stat = debugfs_create_dir("stat", asr_debug_entry);
if (!stat)
return -ENOENT;
cpu_dc_stat = cpu_dcstat_file_create("cpu_dc_stat", stat);
if (!cpu_dc_stat)
goto err_cpu_dc_stat;
ddr_dc_stat = clk_dcstat_file_create("ddr_dc_stat", stat,
&ddr_dc_ops);
if (!ddr_dc_stat)
goto err_ddr_dc_stat;
axi_dc_stat = clk_dcstat_file_create("axi_dc_stat", stat,
&axi_dc_ops);
if (!axi_dc_stat)
goto err_axi_dc_stat;
clock_status = debugfs_create_file("clock_status", 0444,
asr_debug_entry, NULL, &asr1901_clk_stats_ops);
if (!clock_status)
goto err_clk_stats;
return 0;
err_clk_stats:
debugfs_remove(axi_dc_stat);
err_axi_dc_stat:
debugfs_remove(ddr_dc_stat);
err_ddr_dc_stat:
debugfs_remove(cpu_dc_stat);
err_cpu_dc_stat:
debugfs_remove(stat);
return -ENOENT;
}
arch_initcall(__init_dcstat_debugfs_node);
#endif