blob: 28c091d1a1a1ef0a60a352b92a85b28b1b8918a9 [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-asr1803.h"
#include "reset.h"
#define APBC_RTC 0x28
#define APBC_TWSI0 0x2c
#define APBC_KPC 0x30
#define APBC_UART0 0x0
#define APBC_UART1 0x4
#define APBC_UART3 0x74
#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_ONEWIRE 0x48
#define APBC_SSP2 0x4c
#define APBC_TIMER0 0x34
#define APBC_TIMER1 0x44
#define APBC_DROTS 0x58
#define APBC_TWSI1 0x60
#define APBC_TSEN 0x6c
#define APBC_TWSI3 0x78
#define APBC_TSC 0x7c
#define ASR1903_APBC_PWR_TWSI 0x78
#define ASR1903_APBC_TWSI2 0x7c
#define ASR1903_APBC_RIPC 0x80
#define ASR1903_APBC_UART2 0x84
#define ASR1903_APBC_UART3 0x8C
#define ASR1903_APBC_GNSS 0x94
#define ASR1903_APBC_BT 0x98
#define ASR1903_APBC_TSC 0x9C
#define APBSPARE3_REG 0x108
#ifdef CONFIG_CPU_ASR1903
#define APBSPARE12_REG 0x12c
#endif
#define APBCP_TWSI2 0x28
#define APBCP_UART2 0x1c
#define APBCP_AICER 0x38
#define APMU_CAM 0x50
#define APMU_SDH0 0x54
#define APMU_SDH1 0x58
#define APMU_SDH2 0xe0
#ifdef CONFIG_USB_DWC3
#ifdef CONFIG_CPU_ASR1903
#define APMU_USB 0x5c
#else
#define APMU_USB 0x170
#endif
#else
#define APMU_USB 0x5c
#endif
#define APMU_QSPI 0x60
#define APMU_GEU 0x68
#define APMU_TRACE 0x108
#ifdef CONFIG_CPU_ASR1903
#define APMU_EMAC 0x164
#define APMU_PCIE0 0x170
#define APMU_PCIE1 0x1c0
#else
#define APMU_EMAC 0x160
#define APMU_PCIE0 0x164
#define APMU_PCIE1 0x16c
#endif
#define MPMU_UART_PLL 0x14
#define MPMU_PLL2CR 0x34
#define MPMU_I2S_PLL 0x44
#define MPMU_FCCR 0x08
#define MPMU_UART_PLL2 0x1084
#define CIU_MC_CONF 0x0040
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_VCO, "pll1vco", NULL, 0, 2457600000UL},
{ASR1803_CLK_PLL2_VCO, "pll2vco", NULL, 0, 3000000000UL},
{ASR1803_CLK_PLL2_1500, "pll2_1500", NULL, 0, 1500000000},
{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, "dpll_1066", NULL, 0, 1066000000},
{ASR1803_CLK_I2S_PLL, "i2s_pll", NULL, 0, 307200000},
};
static struct mmp_param_fixed_rate_clk asr1803_uart_fixed_parent [] = {
{ASR1803_CLK_UART_58P5M, "uart_58p5m", NULL, 0, 57600000},
{ASR1803_CLK_UART_PLL1P, "uart_pll1p", NULL, 0, 153600000},
};
static struct mmp_param_fixed_rate_clk asr1806_1903_uart_fixed_parent [] = {
{ASR1803_CLK_UART_58P5M, "uart_58p5m", NULL, 0, 57600000},
{ASR1803_CLK_UART_PLL1P, "uart_pll1p", NULL, 0, 153600000},
{ASR1803_CLK_UART_PLL2P, "uart_pll2p", NULL, 0, 614400000},
/* nonexistent pll to prevent asr1806 ap uarts from using uart_pll1 */
{ASR1803_CLK_UART_PLLNE, "uart_pllne", NULL, 0, 20000000},
};
static struct mmp_param_fixed_rate_clk asr1828_uart_fixed_parent [] = {
{ASR1803_CLK_UART_58P5M, "uart_58p5m", NULL, 0, 58500000},
{ASR1803_CLK_UART_PLL1P, "uart_pll1p", NULL, 0, 156000000},
};
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_2, "pll1_3", "pll1_624", 1, 3, 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},
{ASR1803_CLK_PLL1_3_16, "pll1_3_32", "pll1_624", 3, 32, 0},
{ASR1803_CLK_I2S_PLL_2, "i2s_pll_2", "i2s_pll", 1, 2, 0},
#ifdef CONFIG_CPU_ASR1903
{ASR1803_CLK_PLL1_38M4, "pll1_38m", "pll1vco", 1, 64, 0},
#endif
{0, "pll1_div5", "pll1vco", 1, 5, 0},
{0, "pll1_div6", "pll1vco", 1, 6, 0},
{0, "pll1_div7", "pll1vco", 1, 7, 0},
{0, "pll1_div8", "pll1vco", 1, 8, 0},
{0, "pll1_div9", "pll1vco", 1, 9, 0},
{0, "pll1_div11req", "pll1vco", 1, 11, 0},
{0, "pll1_div13req", "pll1vco", 1, 13, 0},
{0, "pll1_div23req", "pll1vco", 1, 23, 0},
{0, "pll2vco_div6req", "pll2vco_req", 1, 6, 0},
{0, "pll2_100m", "pll2vco_div6", 1, 5, 0},
};
static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2,
.num_mask = 0x1fff,
.den_mask = 0x1fff,
.num_shift = 16,
.den_shift = 0,
};
/* asr180x */
static struct mmp_clk_factor_tbl asr180x_uart_factor_tbl[] = {
{.num = 7998, .den = 1536}, /*14.745MHZ */
{.num = 3840, .den = 2000}, /*40 MHZ */
{.num = 3200, .den = 2000}, /*48 MHZ */
{.num = 2400, .den = 2000}, /*64 MHZ */
};
/* asr1828 */
static struct mmp_clk_factor_tbl asr1828_uart_factor_tbl[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */
{.num = 3900, .den = 2000}, /*40 MHZ */
{.num = 3250, .den = 2000}, /*48 MHZ */
{.num = 4875, .den = 4000}, /*64 MHZ */
};
/* asr1806&asr1903 */
static struct mmp_clk_factor_tbl uart_factor_tbl_14m[] = {
{.num = 7998, .den = 1536}, /*14.745MHZ */
{.num = 3840, .den = 2000}, /*40 MHZ */
{.num = 2400, .den = 2000}, /*64 MHZ */
};
/* asr1903 */
static struct mmp_clk_factor_tbl asr1903_uart_factor_tbl_48m[] = {
{.num = 6144, .den = 960}, /*48MHZ */
};
/* for 1806, 48M is only used for 3 AP UARTs, CP UART can't used it */
static struct mmp_clk_factor_tbl asr1806_uart_factor_tbl_48m[] = {
{.num = 7998, .den = 384}, /*14.745MHZ */
{.num = 3840, .den = 500}, /*40 MHZ */
{.num = 6144, .den = 960}, /*48 MHZ */
{.num = 2400, .den = 500}, /*64 MHZ */
};
static struct mmp_clk_factor_masks i2s_factor_masks = {
.factor = 1,
.num_mask = 0x7FFF,
.den_mask = 0xFFF,
.num_shift = 0,
.den_shift = 15,
};
/* the order of table has influence to i2s_clock output ,if
you want to use preference ,plz read source code
*/
static struct mmp_clk_factor_tbl i2s_factor_tbl[] = {
{.num = 0x3C00, .den = 0x14}, /* 200KHz, ISCCRx: 0xE00A3C00, FCCR: 0*/
{.num = 0x72D8, .den = 0x31}, /* 256KHz/8KHz,ISCCRx:0xE018F2D8, FCCR: 0*/
{.num = 0x72D8, .den = 0x62}, /* 512KHz/16KHz,ISCCRx:0xE03172D8, FCCR: 0*/
{.num = 0x72D8, .den = 0x126}, /* 1536KHz/48KHz,ISCCRx:0xE09372D8, FCCR: 0*/
{.num = 0x600, .den = 0x14}, /* 2MHz, ISCCRx: 0xE00A0600, FCCR: 0 */
{.num = 0x72D8, .den = 0x188}, /* 2.048MHz,ISCCRx:0xE0C472D8, FCCR: 0 */
{.num = 0x600, .den = 0x28}, /* 4MHz, ISCCRx: 0xF0140600, FCCR: 0 */
{.num = 0x72D8, .den = 0x310}, /* 4.096MHz,ISCCRx:0xF18872D8, FCCR: 0 */
{.num = 0x600, .den = 0x50}, /* 8MHz, ISCCRx: 0xE0280600, FCCR: 0 */
{.num = 0x1770, .den = 0x1B9}, /*11.2896Mhz,ISCCRx:0xE1B1770, FCCR: 0 */
{.num = 0x72D8, .den = 0x930}, /*12.288Mhz, ISCCRx:0xE1B72D8, FCCR: 0 */
/* Add by mbtk */
{.num = 0x600, .den = 0x82}, /* 13MHz */
{.num = 0x600, .den = 0xA0}, /* 16MHz, ISCCRx: 0xE0500600, FCCR: 0 */
{.num = 0x600, .den = 0x104}, /* 26MHz */
{.num = 0x600, .den = 0x64}, /* 10MHz */
{.num = 0x600, .den = 0x78}, /* 12MHz */
};
static struct clk_div_table i2s_ssp_tbl[] = {
{ .val = 0, .div = 2 },
{ .val = 1, .div = 4 },
{ .val = 2, .div = 6 },
{ .val = 3, .div = 8 },
{ /* sentinel */ },
};
static void asr1803_pll_init(struct asr1803_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));
if (cpu_is_asr1828())
mmp_register_fixed_rate_clks(unit, asr1828_uart_fixed_parent,
ARRAY_SIZE(asr1828_uart_fixed_parent));
else if(cpu_is_asr1803())
mmp_register_fixed_rate_clks(unit, asr1803_uart_fixed_parent,
ARRAY_SIZE(asr1803_uart_fixed_parent));
else
mmp_register_fixed_rate_clks(unit, asr1806_1903_uart_fixed_parent,
ARRAY_SIZE(asr1806_1903_uart_fixed_parent));
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
ARRAY_SIZE(fixed_factor_clks));
if (cpu_is_asr1803() || cpu_is_asr1806()) {
clk = mmp_clk_register_factor("uart_pll", "uart_pll1p",
CLK_SET_RATE_PARENT,
asr_unit->mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, asr180x_uart_factor_tbl,
ARRAY_SIZE(asr180x_uart_factor_tbl), NULL);
mmp_clk_add(unit, ASR1803_CLK_UART_PLL, clk);
} else if(cpu_is_asr1828()) {
clk = mmp_clk_register_factor("uart_pll", "uart_pll1p",
CLK_SET_RATE_PARENT,
asr_unit->mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, asr1828_uart_factor_tbl,
ARRAY_SIZE(asr1828_uart_factor_tbl), NULL);
mmp_clk_add(unit, ASR1803_CLK_UART_PLL, clk);
} else {
clk = mmp_clk_register_factor("uart_pll", "uart_pll1p",
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);
}
if (cpu_is_asr1806 ()) {
clk = mmp_clk_register_factor("uart_pll2", "uart_pll2p",
CLK_SET_RATE_PARENT,
asr_unit->mpmu_base + MPMU_UART_PLL2,
&uart_factor_masks, asr1806_uart_factor_tbl_48m,
ARRAY_SIZE(asr1806_uart_factor_tbl_48m), NULL);
mmp_clk_add(unit, ASR1803_CLK_UART_PLL2, clk);
}
if (cpu_is_asr1903()) {
clk = mmp_clk_register_factor("uart_pll2", "uart_pll2p",
CLK_SET_RATE_PARENT,
asr_unit->mpmu_base + MPMU_UART_PLL2,
&uart_factor_masks, asr1903_uart_factor_tbl_48m,
ARRAY_SIZE(asr1903_uart_factor_tbl_48m), NULL);
mmp_clk_add(unit, ASR1803_CLK_UART_PLL2, clk);
}
clk = mmp_clk_register_factor("i2s_sys_clk", "i2s_pll_2",
CLK_SET_RATE_PARENT,
asr_unit->mpmu_base + MPMU_I2S_PLL,
&i2s_factor_masks, i2s_factor_tbl,
ARRAY_SIZE(i2s_factor_tbl), NULL);
mmp_clk_add(unit, ASR1803_CLK_I2S_SYSCLK, clk);
clk = clk_register_divider_table(NULL, "i2s_sys_ssp", "i2s_sys_clk",
CLK_SET_RATE_PARENT, asr_unit->mpmu_base + MPMU_I2S_PLL, 27, 2, 0,
i2s_ssp_tbl, NULL);
mmp_clk_add(unit, ASR1803_CLK_I2S_SSP, clk);
}
static DEFINE_SPINLOCK(uart0_lock);
static DEFINE_SPINLOCK(uart1_lock);
static DEFINE_SPINLOCK(uart2_lock);
static DEFINE_SPINLOCK(uart3_lock);
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", "pll1_192",
"pll1_384", "pll1_768", "i2s_sys_ssp"};
//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);
#ifdef CONFIG_CPU_ASR1903
static const char *uart_parent_names_48m[] = {"uart_58p5m", "uart_pll", "uart_pll2"};
static struct mmp_param_mux_clk asr1903_uart_mux_clks[] = { /* 1903 */
{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, ASR1903_APBC_UART2, 4, 3, 0, &uart2_lock},
{0, "uart3_mux", uart_parent_names_48m, ARRAY_SIZE(uart_parent_names_48m), CLK_SET_RATE_PARENT, ASR1903_APBC_UART3, 4, 3, 0, &uart3_lock},
};
#else
static const char *uart_parent_names[] = {"uart_58p5m", "uart_pll"};
static const char *asr1806_apuart_parent_names[] = {"uart_58p5m", "uart_pllne", "uart_pll2"};
static const char *cpuart_parent_names[] = {"uart_pll", "uart_58p5m"};
static struct mmp_param_mux_clk asr18xx_apuart_mux_clks[] = { /* 1803, 1806, 1828 */
{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},
};
static struct mmp_param_mux_clk asr1806_apuart_mux_clks[] = { /* 1806 */
{0, "uart0_mux", asr1806_apuart_parent_names, ARRAY_SIZE(asr1806_apuart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
{0, "uart1_mux", asr1806_apuart_parent_names, ARRAY_SIZE(asr1806_apuart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
{0, "uart3_mux", asr1806_apuart_parent_names, ARRAY_SIZE(asr1806_apuart_parent_names), CLK_SET_RATE_PARENT, APBC_UART3, 4, 3, 0, &uart3_lock},
};
static struct mmp_param_mux_clk apbcp_mux_clks[] = {
{0, "uart2_mux", cpuart_parent_names, ARRAY_SIZE(cpuart_parent_names), CLK_SET_RATE_PARENT, APBCP_UART2, 3, 1, 0, &uart2_lock},
};
#endif
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},
#ifdef CONFIG_CPU_ASR1903
{ASR1803_CLK_TWSI2, "twsi2_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, ASR1903_APBC_TWSI2, 0x7, 0x3, 0x0, 0, &reset_lock},
#endif
{ASR1803_CLK_TWSI3, "twsi3_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI3, 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, 0x3, 0x1, 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_APUART1, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x7, 0x3, 0x0, 0, &uart0_lock},
{ASR1803_CLK_APUART2, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x7, 0x3, 0x0, 0, &uart1_lock},
{ASR1803_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0xF, 0xB, 0x0, 0, &ssp0_lock},
{ASR1803_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0xF, 0xB, 0x0, 0, &ssp1_lock},
{ASR1803_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0xF, 0xB, 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},
#ifndef CONFIG_CPU_ASR1903
{ASR1806_CLK_TSC, "tsc_clk", NULL, CLK_SET_RATE_PARENT, APBC_TSC, 0x3, 0x1, 0x2, 0, &reset_lock},
#else
{ASR1806_CLK_TSC, "tsc_clk", NULL, CLK_SET_RATE_PARENT, ASR1903_APBC_TSC, 0x3, 0x1, 0x2, 0, &reset_lock},
{ASR1803_CLK_APUART3, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, ASR1903_APBC_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock},
{ASR1803_CLK_APUART4, "uart3_clk", "uart3_mux", CLK_SET_RATE_PARENT, ASR1903_APBC_UART3, 0x7, 0x3, 0x0, 0, &uart3_lock},
{ASR1803_CLK_RIPC, "ripc_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, ASR1903_APBC_RIPC, 0x7, 0x3, 0x0, 0, &reset_lock},
#endif
};
#ifndef CONFIG_CPU_ASR1903
static struct mmp_param_gate_clk asr1806_uart3_gate_clks[] = {
{ASR1803_CLK_APUART3, "uart3_clk", "uart3_mux", CLK_SET_RATE_PARENT, APBC_UART3, 0x7, 0x3, 0x0, 0, &uart3_lock},
};
static struct mmp_param_gate_clk apbcp_gate_clks[] = {
{ASR1803_CLK_TWSI2, "twsi2_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBCP_TWSI2, 0x7, 0x3, 0x0, 0, &reset_lock},
{ASR1803_CLK_RIPC, "ripc_clk", NULL, CLK_SET_RATE_PARENT, APBCP_AICER, 0x6, 0x2, 0x0, 0, &reset_lock},
/* The gate clocks has mux parent. */
{ASR1803_CLK_CPUART, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBCP_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock},
};
#endif
static struct mmp_param_gate_clk mpmu_gate_clks[] = {
/*VCXO_OUT & VCXO1 all enabled. */
{ASR1803_CLK_VCTCXO_REQ, "vctcxo_req", "vctcxo", CLK_SET_RATE_PARENT, 0x18, 0x3, 0x3, 0x0, 0, &reset_lock},
};
static struct mmp_param_gate_clk apbs_gate_clks[] = {
{0, "pll2vco_req", "pll2vco", CLK_SET_RATE_PARENT, 0x128, 0x80000000, 0x80000000, 0x80000000, 0, &reset_lock},
{0, "pll2vco_div6", "pll2vco_div6req", CLK_SET_RATE_PARENT, 0x124, 0x80000000, 0x8, 0x8, 0, &reset_lock},
#ifdef CONFIG_CPU_ASR1903
{0, "pll1_div11", "pll1_div11req", CLK_SET_RATE_PARENT, APBSPARE12_REG, 0x10000, 0x10000, 0x0, 0, &reset_lock},
{0, "pll1_div13", "pll1_div13req", CLK_SET_RATE_PARENT, APBSPARE12_REG, 0x20000, 0x20000, 0x0, 0, &reset_lock},
{0, "pll1_div23", "pll1_div23req", CLK_SET_RATE_PARENT, APBSPARE12_REG, 0x40000, 0x40000, 0x0, 0, &reset_lock},
#else
{0, "pll1_div11", "pll1_div11req", CLK_SET_RATE_PARENT, APBSPARE3_REG, 0x1, 0x1, 0x0, 0, &reset_lock},
{0, "pll1_div13", "pll1_div13req", CLK_SET_RATE_PARENT, APBSPARE3_REG, 0x2, 0x2, 0x0, 0, &reset_lock},
{0, "pll1_div23", "pll1_div23req", CLK_SET_RATE_PARENT, APBSPARE3_REG, 0x4, 0x4, 0x0, 0, &reset_lock},
#endif
};
static void asr1803_apb_periph_clk_init(struct asr1803_clk_unit *asr_unit)
{
struct mmp_clk_unit *unit = &asr_unit->unit;
mmp_register_mux_clks(unit, apbc_mux_clks, asr_unit->apbc_base,
ARRAY_SIZE(apbc_mux_clks));
#ifdef CONFIG_CPU_ASR1903
mmp_register_mux_clks(unit, asr1903_uart_mux_clks, asr_unit->apbc_base,
ARRAY_SIZE(asr1903_uart_mux_clks));
#else
if (cpu_is_asr1806())
mmp_register_mux_clks(unit, asr1806_apuart_mux_clks, asr_unit->apbc_base,
ARRAY_SIZE(asr1806_apuart_mux_clks));
else
mmp_register_mux_clks(unit, asr18xx_apuart_mux_clks, asr_unit->apbc_base,
ARRAY_SIZE(asr18xx_apuart_mux_clks)); /* 1803 & 1828 */
mmp_register_mux_clks(unit, apbcp_mux_clks, asr_unit->apbcp_base,
ARRAY_SIZE(apbcp_mux_clks));
#endif
mmp_register_gate_clks(unit, apbc_gate_clks, asr_unit->apbc_base,
ARRAY_SIZE(apbc_gate_clks));
#ifndef CONFIG_CPU_ASR1903
if (cpu_is_asr1806())
mmp_register_gate_clks(unit, asr1806_uart3_gate_clks, asr_unit->apbc_base,
ARRAY_SIZE(asr1806_uart3_gate_clks));
mmp_register_gate_clks(unit, apbcp_gate_clks, asr_unit->apbcp_base,
ARRAY_SIZE(apbcp_gate_clks));
#endif
mmp_register_gate_clks(unit, mpmu_gate_clks, asr_unit->mpmu_base,
ARRAY_SIZE(mpmu_gate_clks));
mmp_register_gate_clks(unit, apbs_gate_clks, asr_unit->apbs_base,
ARRAY_SIZE(apbs_gate_clks));
}
static DEFINE_SPINLOCK(sdh0_lock);
static DEFINE_SPINLOCK(sdh1_lock);
static DEFINE_SPINLOCK(usb_lock);
static DEFINE_SPINLOCK(aes_lock);
static DEFINE_SPINLOCK(emac_lock);
static DEFINE_SPINLOCK(trace_lock);
static DEFINE_SPINLOCK(qspi_lock);
static DEFINE_SPINLOCK(pcie0_lock);
static DEFINE_SPINLOCK(pcie1_lock);
static DEFINE_SPINLOCK(camera_lock);
static const char * const sdh_parent_names[] = {"pll1_416", "pll1_624", "pll1_13"};
#ifdef CONFIG_CPU_ASR1903
static const char * const sdh_parent_names2[] = {
"pll1_416", "pll1_div7", "pll1_312", "pll1_div9",
"pll1_div11", "pll1_div23", "pll2_div6", "pll1_div13"
};
#else
/* New clock source added for sdh on 1806 */
static const char * const sdh_parent_names2[] = {
"pll1_416", "pll1_624", "pll2_div8", "pll1_13",
"pll1_div7", "pll1_div9", "pll1_div11", "pll1_div23",
};
static struct mmp_clk_mix_config sdh_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 8, 2, 6, 11),
};
#endif
static struct mmp_clk_mix_config sdh_mix_config2 = {
.reg_info = DEFINE_MIX_REG_INFO(3, 8, 3, 5, 11),
};
static const char *qspi_clk_parents[] = {
"pll1_24", "pll1_12", "pll1_8", "pll1_6",
"pll1_4", "pll1_3", "pll1_2", "pll1_416"
};
#ifdef CONFIG_CPU_ASR1903
static const char *emac_ptp_clk_parents[] = {
"pll2_100m", "pll1_38m"
};
#endif
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},
#ifdef CONFIG_CPU_ASR1903
{0, "ptp_mux", emac_ptp_clk_parents, ARRAY_SIZE(emac_ptp_clk_parents), CLK_SET_RATE_PARENT, APMU_EMAC, 14, 1, 0, &emac_lock},
#endif
};
#ifdef CONFIG_CPU_ASR1903
/* qspi on 1903 and later platform use new clk/res control */
static const char *qspi_clk_parents3[] = {
"pll1_div6", "pll1_div7", "pll1_div8", "pll1_div9",
"pll1_div11", "pll1_div23", "pll2_div8", "pll1_div13"
};
#else
/* qspi on 1806 and later platform use new clk/res control */
static const char *qspi_clk_parents2[] = {
"pll1_div6", "pll1_div7", "pll1_div8", "pll1_div9",
"pll1_div11", "pll1_div23", "pll1_div5","pll1_div13"
};
#endif
static struct mmp_clk_mix_config qspi_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 9, 3, 6, 12),
};
static const char * const cam_parent_names[] = {"pll1_416", "pll1_624"};
static struct mmp_clk_mix_config cam_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 19, 2, 17, 22),
};
static struct mmp_param_gate_clk apmu_gate_clks[] = {
#ifdef CONFIG_USB_DWC3
#ifdef CONFIG_CPU_ASR1903
{ASR1803_CLK_USB, "usb_clk", NULL, 0, APMU_USB, 0xD, 0xD, 0x0, 0, &usb_lock},
#else
{ASR1803_CLK_USB, "usb_clk", NULL, 0, APMU_USB, 0x1E000, 0x1E000, 0x0, 0, &usb_lock},
#endif
#else
{ASR1803_CLK_USB, "usb_clk", NULL, 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock},
#endif
#if (defined(CONFIG_CPU_ASR1901) || defined(CONFIG_CPU_ASR1906))
{ASR1803_CLK_GEU, "aes_clk", NULL, 0, APMU_GEU, 0x30, 0x30, 0x0, 0, &aes_lock},
#else
{ASR1803_CLK_GEU, "aes_clk", NULL, 0, APMU_GEU, 0x9, 0x9, 0x0, 0, &aes_lock},
#endif
{ASR1803_CLK_EMAC, "emac_clk", NULL, 0, APMU_EMAC, 0x3, 0x3, 0x0, 0, &emac_lock},
#ifdef CONFIG_CPU_ASR1903
{ASR1803_CLK_EMAC_PTP, "ptp_clk", "ptp_mux", CLK_SET_RATE_PARENT, APMU_EMAC, 0x8000, 0x8000, 0, 0, &emac_lock},
#else
{ASR1803_CLK_EMAC_PTP, "ptp_clk", "pll2_100m", 0, APMU_EMAC, 0x40000, 0x40000, 0, 0, &emac_lock},
#endif
{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},
{ASR1803_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", CLK_SET_RATE_PARENT, APMU_QSPI, 0x12, 0x12, 0x10, 0, &qspi_lock},
{ASR1803_CLK_CAMERA, "camera_clk", NULL, 0, APMU_CAM, 0x12, 0x12, 0x10, 0, &camera_lock},
};
static void asr1803_axi_periph_clk_init(struct asr1803_clk_unit *asr_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &asr_unit->unit;
struct mmp_clk_mix_config *sdh_config;
char *sdh_parent;
int parent_size;
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 (cpu_is_asr1828()) {
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, ASR1803_CLK_PCIE1, clk);
}
#ifdef CONFIG_CPU_ASR1903
sdh_parent = (char *)sdh_parent_names2;
sdh_config = &sdh_mix_config2;
parent_size = ARRAY_SIZE(sdh_parent_names2);
#else
if (cpu_is_asr1806()) {
sdh_parent = (char *)sdh_parent_names2;
sdh_config = &sdh_mix_config2;
parent_size = ARRAY_SIZE(sdh_parent_names2);
} else {
sdh_parent = (char *)sdh_parent_names;
sdh_config = &sdh_mix_config;
parent_size = ARRAY_SIZE(sdh_parent_names);
}
#endif
sdh_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, parent_size,
CLK_SET_RATE_PARENT,
sdh_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_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, parent_size,
CLK_SET_RATE_PARENT,
sdh_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);
#ifdef CONFIG_CPU_ASR1903
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_parents3, ARRAY_SIZE(qspi_clk_parents3),
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
if (cpu_is_asr1806()) {
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);
}
#endif
/* 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);
/* CAMERA clock */
if (cpu_is_asr1806()|| cpu_is_asr1903()) {
cam_mix_config.reg_info.reg_clk_ctrl = asr_unit->apmu_base + APMU_SDH1;
clk = mmp_clk_register_mix(NULL, "cam_mix_clk",
(const char **)cam_parent_names, ARRAY_SIZE(cam_parent_names),
CLK_SET_RATE_PARENT,
&cam_mix_config, &camera_lock);
clk = mmp_clk_register_gate(NULL, "cam_clk", "cam_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
asr_unit->apmu_base + APMU_CAM,
0x81003, 0x81003, 0x0, 0, &camera_lock);
mmp_clk_add(unit, ASR1803_CLK_CAMERA, clk);
}
}
static void asr1803_clk_reset_init(struct device_node *np,
struct asr1803_clk_unit *asr_unit)
{
struct mmp_clk_reset_cell *cells;
int i, base, nr_resets_apbc, nr_resets_apbcp, nr_resets;
nr_resets_apbc = ARRAY_SIZE(apbc_gate_clks);
#ifndef CONFIG_CPU_ASR1903
nr_resets_apbcp = ARRAY_SIZE(apbcp_gate_clks);
#else
nr_resets_apbcp = 0;
#endif
nr_resets = nr_resets_apbc + nr_resets_apbcp;
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;
}
#ifndef CONFIG_CPU_ASR1903
base = nr_resets_apbc;
for (i = 0; i < nr_resets_apbcp; i++) {
cells[base + i].clk_id = apbcp_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;
}
#endif
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 asr1803_clk_misc_init(struct asr1803_clk_unit *asr_unit)
{
unsigned int dcg_regval = 0;
/* enable all MCK and AXI fabric dynamic clk gating */
dcg_regval = __raw_readl(asr_unit->ciu_base + CIU_MC_CONF);
/* enable dclk gating */
dcg_regval &= ~(1 << 19);
dcg_regval |= (0xff << 8) | /* MCK5 P0~P7*/
(1 << 17) | (1 << 18);
/* dcg_regval |= (1 << 21);*//* fabric0 DAP AHB CLK gating */
__raw_writel(dcg_regval, asr_unit->ciu_base + CIU_MC_CONF);
/* close the usb clk and keep dongle mode clk gating en */
if (cpu_is_asr1803() || cpu_is_asr1802s()) {
__raw_writel(0x2 | __raw_readl(asr_unit->apmu_base + APMU_USB),
asr_unit->apmu_base + APMU_USB);
} else if (cpu_is_asr1806() || cpu_is_asr1903()) {
__raw_writel(0x2, asr_unit->apmu_base + APMU_USB);
} else {
/* do an usb phy controller reset to prepare clean start point for kernel */
__raw_writel(0x0, (asr_unit->apmu_base + APMU_USB));
}
/* Initialize I2S clock source */
dcg_regval = __raw_readl(asr_unit->mpmu_base + MPMU_FCCR);
dcg_regval &= ~(3 << 27); /* I2S clock derive from 307.2M, enable DIV2 */
__raw_writel(dcg_regval, (asr_unit->mpmu_base + MPMU_FCCR));
dcg_regval = __raw_readl(asr_unit->mpmu_base + MPMU_I2S_PLL);
dcg_regval |= (1 << 31);
dcg_regval |= (1 << 30);
dcg_regval |= (1 << 29);
__raw_writel(dcg_regval, (asr_unit->mpmu_base + MPMU_I2S_PLL));
}
struct asr1803_clk_unit *global_clk_unit;
static void __init asr1803_clk_init(struct device_node *np)
{
struct asr1803_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->apbcp_base = of_iomap(np, 3);
if (!asr_unit->apbcp_base) {
pr_err("failed to map apbcp registers\n");
goto unmap_apbc_region;
}
asr_unit->apbs_base = of_iomap(np, 4);
if (!asr_unit->apbs_base) {
pr_err("failed to map apbs registers\n");
goto unmap_apbs_region;
}
asr_unit->ciu_base = of_iomap(np, 5);
if (!asr_unit->ciu_base) {
pr_err("failed to map ciu registers\n");
goto unmap_ciu_region;
}
asr_unit->ddrc_base = of_iomap(np, 6);
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);
asr1803_clk_misc_init(asr_unit);
asr1803_pll_init(asr_unit);
asr1803_apb_periph_clk_init(asr_unit);
asr1803_axi_periph_clk_init(asr_unit);
asr1803_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_asr18xx_dvfs_platinfo();
#endif
asr1803_acpu_init(asr_unit);
asr1803_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->apbcp_base);
unmap_apbc_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(asr1803_clk, "asr,asr1803-clock", asr1803_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 asr1803_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, *apbcp_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;
}
apbcp_base = ioremap(APB_PHYS_BASE + 0x3b000, SZ_4K);
if (apbcp_base == NULL) {
pr_err("error to ioremap APBC extension 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");
#ifdef CONFIG_USB_DWC3
reg = __raw_readl(apmu_base + APMU_USB);
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");
#else
reg = __raw_readl(apmu_base + APMU_USB);
if ((reg & 0x9) == 0x9)
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");
#endif
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(apbcp_base + APBCP_TWSI2);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "TWSI2 CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "TWSI2 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);
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");
reg = __raw_readl(apbcp_base + APBCP_AICER);
if ((reg & 0x5) == 0x1)
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "RIPC CLK", "on");
else
len += snprintf(buf + len, size,
"|%14s\t|%5s\t|\n", "RIPC 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 asr1803_clk_stats_ops = {
.owner = THIS_MODULE,
.read = asr1803_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, &asr1803_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