blob: 14da9226ffcf6f1e141f4bf452a6241ac842f2e1 [file] [log] [blame]
/*
* mmp clock driver for pxa1936
*
* Copyright (C) 2014 Marvell
* Zhoujie Wu <zjwu@marvell.com>
* Bill Zhou <zhoub@marvell.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/devfreq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <dt-bindings/clock/marvell-pxa1936.h>
#include <linux/debugfs-pxa.h>
#include <linux/cputype.h>
#include <linux/clk/mmpfuse.h>
#include "clk.h"
#include "clk-pll-helanx.h"
#include "clk-core-helan3.h"
#include "clk-plat.h"
#include <linux/clk/mmpcpdvc.h>
#define APBS_PLL1_CTRL 0x100
#define APBC_RTC 0x28
#define APBC_TWSI0 0x2c
#define APBC_TWSI1 0x60
#define APBC_TWSI3 0x70
#define APBC_KPC 0x30
#define APBC_UART0 0x0
#define APBC_UART1 0x4
#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_SWJTAG 0x40
#define APBC_SSP2 0x4c
#define APBC_TERMAL 0x6c
/* IPC/RIPC clock */
#define APBC_IPC_CLK_RST 0x24
#define APBCP_AICER 0x38
#define APBCP_TWSI2 0x28
#define APBCP_UART2 0x1c
#define MPMU_UART_PLL 0x14
#define APMU_CLK_GATE_CTRL 0x40
#define APMU_CCIC0 0x50
#define APMU_CCIC1 0x24
#define APMU_ISP 0x38
#define APMU_SDH0 0x54
#define APMU_SDH1 0x58
#define APMU_SDH2 0xe0
#define APMU_USB 0x5c
#define APMU_NF 0x60
#define APMU_TRACE 0x108
#define APMU_CCI 0x0300
#define APMU_CORE_STATUS 0x090
#define APMU_DVC_DFC_DEBUG 0x140
/* PLL */
#define MPMU_PLL2CR (0x0034)
#define MPMU_PLL3CR (0x001c)
#define MPMU_PLL4CR (0x0050)
#define MPMU_POSR (0x0010)
#define POSR_PLL2_LOCK (1 << 29)
#define POSR_PLL3_LOCK (1 << 30)
#define POSR_PLL4_LOCK (1 << 31)
#define APB_SPARE_PLL2CR (0x104)
#define APB_SPARE_PLL3CR (0x108)
#define APB_SPARE_PLL4CR (0x124)
#define APB_PLL2_SSC_CTRL (0x130)
#define APB_PLL2_SSC_CONF (0x134)
#define APB_PLL2_FREQOFFSET_CTRL (0x138)
#define APB_PLL3_SSC_CTRL (0x13c)
#define APB_PLL3_SSC_CONF (0x140)
#define APB_PLL3_FREQOFFSET_CTRL (0x144)
#define APB_PLL4_SSC_CTRL (0x148)
#define APB_PLL4_SSC_CONF (0x14c)
#define APB_PLL4_FREQOFFSET_CTRL (0x150)
#define APMU_GC 0xcc
#define APMU_GC2D 0xf4
#define APMU_VPU 0xa4
#define APMU_DSI1 0x44
#define APMU_DISP1 0x4c
#define CIU_MC_CONF 0x0040
#define VPU_XTC 0x00a8
#define GPU2D_XTC 0x00a0
#define GPU_XTC 0x00a4
#define SC2_DESC 0xD420F000
#define ISP_XTC 0x84C
#ifdef CONFIG_SMC91X
#define APMU_SMC 0xd4
#define SMC_CLK 0xd4283890
#endif
struct pxa1936_clk_unit {
struct mmp_clk_unit unit;
void __iomem *mpmu_base;
void __iomem *apmu_base;
void __iomem *apbc_base;
void __iomem *apbcp_base;
void __iomem *apbs_base;
void __iomem *ciu_base;
void __iomem *dciu_base; /* Dragon CIU */
void __iomem *sc2desc_base;
};
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
{PXA1936_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
{PXA1936_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
{PXA1936_CLK_PLL1_624, "pll1_624", NULL, CLK_IS_ROOT, 624000000},
{PXA1936_CLK_PLL1_416, "pll1_416", NULL, CLK_IS_ROOT, 416000000},
{PXA1936_CLK_PLL1_499, "pll1_499", NULL, CLK_IS_ROOT, 499000000},
{PXA1936_CLK_PLL1_832, "pll1_832", NULL, CLK_IS_ROOT, 832000000},
{PXA1936_CLK_PLL1_1248, "pll1_1248", NULL, CLK_IS_ROOT, 1248000000},
};
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
{PXA1936_CLK_PLL1_2, "pll1_2", "pll1_624", 1, 2, 0},
{PXA1936_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
{PXA1936_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0},
{PXA1936_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0},
{PXA1936_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0},
{PXA1936_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0},
{PXA1936_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0},
{PXA1936_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0},
{PXA1936_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0},
{PXA1936_CLK_PLL1_13, "pll1_13", "pll1_624", 1, 13, 0},
{PXA1936_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0},
{PXA1936_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0},
{PXA1936_CLK_PLL1_13_16, "pll1_13_16", "pll1_624", 3, 16, 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 */
};
static DEFINE_SPINLOCK(pll1_lock);
static struct mmp_param_general_gate_clk pll1_gate_clks[] = {
{PXA1936_CLK_PLL1_416_GATE, "pll1_416_gate", "pll1_416", 0,
APMU_CLK_GATE_CTRL, 27, 0, &pll1_lock},
{PXA1936_CLK_PLL1_624_GATE, "pll1_624_gate", "pll1_624", 0,
APMU_CLK_GATE_CTRL, 26, 0, &pll1_lock},
{PXA1936_CLK_PLL1_832_GATE, "pll1_832_gate", "pll1_832", 0,
APMU_CLK_GATE_CTRL, 30, 0, &pll1_lock},
{PXA1936_CLK_PLL1_1248_GATE, "pll1_1248_gate", "pll1_1248", 0,
APMU_CLK_GATE_CTRL, 28, 0, &pll1_lock},
{PXA1936_CLK_PLL1_312_GATE, "pll1_312_gate", "pll1_2", 0,
APMU_CLK_GATE_CTRL, 29, 0, &pll1_lock},
{PXA1936_CLK_PLL1_499_GATE, "pll1_499_gate", "pll1_499_en", 0,
APMU_CLK_GATE_CTRL, 31, 0, &pll1_lock},
};
enum pll {
PLL2 = 0,
PLL3,
PLL4,
MAX_PLL_NUM
};
enum pll_type {
VCO,
OUT,
OUTP,
MAX_PLL_TYPE,
};
static struct mmp_vco_params pllx_vco_params[MAX_PLL_NUM] = {
{
.vco_min = 1200000000UL,
.vco_max = 3000000000UL,
.lock_enable_bit = POSR_PLL2_LOCK,
},
{
.vco_min = 1200000000UL,
.vco_max = 3000000000UL,
.lock_enable_bit = POSR_PLL3_LOCK,
},
{
.vco_min = 1200000000UL,
.vco_max = 3000000000UL,
.lock_enable_bit = POSR_PLL4_LOCK,
}
};
static struct mmp_pll_params pllx_pll_params[MAX_PLL_NUM] = {
};
static struct mmp_pll_params pllx_pllp_params[MAX_PLL_NUM] = {
};
struct plat_pll_info {
spinlock_t lock;
const char *vco_name;
const char *out_name;
const char *outp_name;
const char *vco_div3_name;
/* clk flags */
unsigned long vco_flag;
unsigned long vcoclk_flag;
unsigned long out_flag;
unsigned long outclk_flag;
unsigned long outp_flag;
unsigned long outpclk_flag;
/* dt index */
unsigned int vcodtidx;
unsigned int outdtidx;
unsigned int outpdtidx;
unsigned int vcodiv3dtidx;
};
struct plat_pll_info pllx_platinfo[MAX_PLL_NUM] = {
{
.vco_name = "pll2_vco",
.out_name = "pll2",
.outp_name = "pll2p",
.vco_div3_name = "pll2_div3",
.vcoclk_flag = CLK_IS_ROOT,
.out_flag = HELANX_PLLOUT,
.outp_flag = HELANX_PLLOUTP,
.vcodtidx = PXA1936_CLK_PLL2VCO,
.outdtidx = PXA1936_CLK_PLL2,
.outpdtidx = PXA1936_CLK_PLL2P,
.vcodiv3dtidx = PXA1936_CLK_PLL2VCODIV3,
},
{
.vco_name = "pll3_vco",
.out_name = "pll3",
.outp_name = "pll3p",
.vco_div3_name = "pll3_div3",
.vco_flag = HELANX_PLL_SKIP_DEF_RATE,
.vcoclk_flag = CLK_IS_ROOT,
.outpclk_flag = CLK_SET_RATE_PARENT,
.out_flag = HELANX_PLLOUT,
.outp_flag = HELANX_PLLOUTP,
.vcodtidx = PXA1936_CLK_PLL3VCO,
.outdtidx = PXA1936_CLK_PLL3,
.outpdtidx = PXA1936_CLK_PLL3P,
.vcodiv3dtidx = PXA1936_CLK_PLL3VCODIV3,
},
{
.vco_name = "pll4_vco",
.out_name = "pll4",
.outp_name = "pll4p",
.vco_div3_name = "pll4_div3",
.vcoclk_flag = CLK_IS_ROOT,
.vco_flag = HELANX_PLL_SKIP_DEF_RATE,
/*
* set pll4 flag to allow it change rate
* when lcd choose pll4 as clk source.
*/
.outclk_flag = CLK_SET_RATE_PARENT,
.out_flag = HELANX_PLLOUT,
.outp_flag = HELANX_PLLOUTP,
.vcodtidx = PXA1936_CLK_PLL4VCO,
.outdtidx = PXA1936_CLK_PLL4,
.outpdtidx = PXA1936_CLK_PLL4P,
.vcodiv3dtidx = PXA1936_CLK_PLL4VCODIV3,
}
};
/* pll default rate determined by ddr_mode */
unsigned long pll_dfrate[DDR_TYPE_MAX][MAX_PLL_NUM][MAX_PLL_TYPE] = {
[DDR_533M] = {
{2115 * MHZ, 1057 * MHZ, 528 * MHZ},
{1491 * MHZ, 1491 * MHZ, 1491 * MHZ},
/* for 533M case, reserve pll4 for LCD */
{1595 * MHZ, 1595 * MHZ, 797 * MHZ},
},
[DDR_667M] = {
{2115 * MHZ, 1057 * MHZ, 528 * MHZ},
{1491 * MHZ, 1491 * MHZ, 1491 * MHZ},
{2670lu * MHZ, 1335 * MHZ, 667 * MHZ},
},
[DDR_800M] = {
{2115 * MHZ, 1057 * MHZ, 528 * MHZ},
{1491 * MHZ, 1491 * MHZ, 1491 * MHZ},
{1595 * MHZ, 1595 * MHZ, 797 * MHZ},
},
[DDR_800M_2X] = {
{2115 * MHZ, 1057 * MHZ, 528 * MHZ},
{1491 * MHZ, 1491 * MHZ, 1491 * MHZ},
{1595 * MHZ, 1595 * MHZ, 797 * MHZ},
},
};
static int board_is_fpga(void)
{
static int rc;
if (!rc)
rc = of_machine_is_compatible("marvell,pxa1936-fpga");
return rc;
}
static void pxa1936_dynpll_init(struct pxa1936_clk_unit *pxa_unit)
{
int idx;
struct clk *clk;
struct mmp_clk_unit *unit = &pxa_unit->unit;
pllx_vco_params[PLL2].cr_reg = pxa_unit->mpmu_base + MPMU_PLL2CR;
pllx_vco_params[PLL2].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL2CR;
pllx_vco_params[PLL3].cr_reg = pxa_unit->mpmu_base + MPMU_PLL3CR;
pllx_vco_params[PLL3].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL3CR;
pllx_vco_params[PLL4].cr_reg = pxa_unit->mpmu_base + MPMU_PLL4CR;
pllx_vco_params[PLL4].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL4CR;
pllx_pll_params[PLL2].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL2CR;
pllx_pll_params[PLL3].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL3CR;
pllx_pll_params[PLL4].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL4CR;
pllx_pllp_params[PLL2].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL2CR;
pllx_pllp_params[PLL3].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL3CR;
pllx_pllp_params[PLL4].pll_swcr = pxa_unit->apbs_base + APB_SPARE_PLL4CR;
for (idx = 0; idx < MAX_PLL_NUM; idx++) {
spin_lock_init(&pllx_platinfo[idx].lock);
/* vco */
pllx_vco_params[idx].lock_reg = pxa_unit->mpmu_base + MPMU_POSR;
pllx_vco_params[idx].default_rate =
pll_dfrate[ddr_mode][idx][VCO];
clk = helanx_clk_register_vco(pllx_platinfo[idx].vco_name,
0, pllx_platinfo[idx].vcoclk_flag, pllx_platinfo[idx].vco_flag,
&pllx_platinfo[idx].lock, &pllx_vco_params[idx]);
clk_set_rate(clk, pllx_vco_params[idx].default_rate);
mmp_clk_add(unit, pllx_platinfo[idx].vcodtidx, clk);
/* pll */
pllx_pll_params[idx].default_rate =
pll_dfrate[ddr_mode][idx][OUT];
clk = helanx_clk_register_pll(pllx_platinfo[idx].out_name,
pllx_platinfo[idx].vco_name,
pllx_platinfo[idx].outclk_flag, pllx_platinfo[idx].out_flag,
&pllx_platinfo[idx].lock, &pllx_pll_params[idx]);
clk_set_rate(clk, pllx_pll_params[idx].default_rate);
mmp_clk_add(unit, pllx_platinfo[idx].outdtidx, clk);
/* pllp */
pllx_pllp_params[idx].default_rate =
pll_dfrate[ddr_mode][idx][OUTP];
clk = helanx_clk_register_pll(pllx_platinfo[idx].outp_name,
pllx_platinfo[idx].vco_name,
pllx_platinfo[idx].outpclk_flag, pllx_platinfo[idx].outp_flag,
&pllx_platinfo[idx].lock, &pllx_pllp_params[idx]);
clk_set_rate(clk, pllx_pllp_params[idx].default_rate);
mmp_clk_add(unit, pllx_platinfo[idx].outpdtidx, clk);
/* vco div3 */
clk = clk_register_fixed_factor(NULL,
pllx_platinfo[idx].vco_div3_name,
pllx_platinfo[idx].vco_name, 0, 1, 3);
mmp_clk_add(unit, pllx_platinfo[idx].vcodiv3dtidx, clk);
}
}
static void pxa1936_pll_init(struct pxa1936_clk_unit *pxa_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &pxa_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));
clk = clk_register_gate(NULL, "pll1_499_en", "pll1_499", 0,
pxa_unit->apbs_base + APBS_PLL1_CTRL,
31, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_PLL1_499_EN, clk);
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
CLK_SET_RATE_PARENT,
pxa_unit->mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl,
ARRAY_SIZE(uart_factor_tbl), NULL);
mmp_clk_add(unit, PXA1936_CLK_UART_PLL, clk);
mmp_register_general_gate_clks(unit, pll1_gate_clks,
pxa_unit->apmu_base,
ARRAY_SIZE(pll1_gate_clks));
if (!board_is_fpga())
pxa1936_dynpll_init(pxa_unit);
}
static struct mmp_param_gate_clk apbc_gate_clks[] = {
{PXA1936_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT,
APBC_TWSI0, 0x7, 0x3, 0x0, 0, NULL},
{PXA1936_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT,
APBC_TWSI1, 0x7, 0x3, 0x0, 0, NULL},
{PXA1936_CLK_TWSI3, "twsi3_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT,
APBC_TWSI3, 0x7, 0x3, 0x0, 0, NULL},
{PXA1936_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT,
APBC_GPIO, 0x7, 0x3, 0x0, 0, NULL},
{PXA1936_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT,
APBC_KPC, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
{PXA1936_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT,
APBC_RTC, 0x87, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
{PXA1936_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT,
APBC_PWM0, 0x7, 0x3, 0x0, 0, NULL},
{PXA1936_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT,
APBC_PWM1, 0x7, 0x3, 0x0, 0, NULL},
{PXA1936_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT,
APBC_PWM2, 0x7, 0x3, 0x0, 0, NULL},
{PXA1936_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT,
APBC_PWM3, 0x7, 0x3, 0x0, 0, NULL},
};
static DEFINE_SPINLOCK(uart0_lock);
static DEFINE_SPINLOCK(uart1_lock);
static DEFINE_SPINLOCK(uart2_lock);
static const char * const uart_parent_names[] = {"pll1_3_16", "uart_pll"};
static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
#ifdef CONFIG_CORESIGHT_SUPPORT
static void pxa1936_coresight_clk_init(struct pxa1936_clk_unit *pxa_unit)
{
struct mmp_clk_unit *unit = &pxa_unit->unit;
struct clk *clk;
clk = mmp_clk_register_gate(NULL, "DBGCLK", "pll1_416", 0,
pxa_unit->apmu_base + APMU_TRACE,
0x10008, 0x10008, 0x0, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_DBGCLK, clk);
/* TMC clock */
clk = mmp_clk_register_gate(NULL, "TRACECLK", "DBGCLK", 0,
pxa_unit->apmu_base + APMU_TRACE,
0x10010, 0x10010, 0x0, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_TRACECLK, clk);
}
#endif
static void pxa1936_apb_periph_clk_init(struct pxa1936_clk_unit *pxa_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
ARRAY_SIZE(apbc_gate_clks));
clk = mmp_clk_register_gate(NULL, "ts_clk", NULL, 0,
pxa_unit->apbc_base + APBC_TERMAL, 0x7, 0x3, 0x0, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_THERMAL, clk);
clk = mmp_clk_register_gate(NULL, "twsi2_clk", "pll1_13_1_5",
CLK_SET_RATE_PARENT,
pxa_unit->apbcp_base + APBCP_TWSI2,
0x7, 0x3, 0x0, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_TWSI2, clk);
clk = clk_register_mux(NULL, "uart0_mux", (const char **)uart_parent_names,
ARRAY_SIZE(uart_parent_names),
CLK_SET_RATE_PARENT,
pxa_unit->apbc_base + APBC_UART0,
4, 3, 0, &uart0_lock);
if (board_is_fpga())
clk = clk_register_fixed_rate(NULL,
"uart0_clk", "uart0_mux", 0, 12500000);
else
clk = mmp_clk_register_gate(NULL, "uart0_clk", "uart0_mux",
CLK_SET_RATE_PARENT,
pxa_unit->apbc_base + APBC_UART0,
0x7, 0x3, 0x0, 0, &uart0_lock);
mmp_clk_add(unit, PXA1936_CLK_UART0, clk);
clk = clk_register_mux(NULL, "uart1_mux", (const char **)uart_parent_names,
ARRAY_SIZE(uart_parent_names),
CLK_SET_RATE_PARENT,
pxa_unit->apbc_base + APBC_UART1,
4, 3, 0, &uart1_lock);
clk = mmp_clk_register_gate(NULL, "uart1_clk", "uart1_mux",
CLK_SET_RATE_PARENT,
pxa_unit->apbc_base + APBC_UART1,
0x7, 0x3, 0x0, 0, &uart1_lock);
mmp_clk_add(unit, PXA1936_CLK_UART1, clk);
clk = clk_register_mux(NULL, "uart2_mux", (const char **)uart_parent_names,
ARRAY_SIZE(uart_parent_names),
CLK_SET_RATE_PARENT,
pxa_unit->apbcp_base + APBCP_UART2,
4, 3, 0, &uart2_lock);
clk = mmp_clk_register_gate(NULL, "uart2_clk", "uart2_mux",
CLK_SET_RATE_PARENT,
pxa_unit->apbcp_base + APBCP_UART2,
0x7, 0x3, 0x0, 0, &uart2_lock);
mmp_clk_add(unit, PXA1936_CLK_UART2, clk);
clk = mmp_clk_register_apbc("swjtag", NULL,
pxa_unit->apbc_base + APBC_SWJTAG,
10, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_SWJTAG, clk);
clk = mmp_clk_register_gate(NULL, "ipc_clk", NULL, 0,
pxa_unit->apbc_base + APBC_IPC_CLK_RST,
0x7, 0x3, 0x0, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_IPC_RST, clk);
clk_prepare_enable(clk);
clk = mmp_clk_register_gate(NULL, "ripc_clk", NULL, 0,
pxa_unit->apbcp_base + APBCP_AICER,
0x7, 0x2, 0x0, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_AICER, clk);
clk_prepare_enable(clk);
clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent_names,
ARRAY_SIZE(ssp_parent_names), 0,
pxa_unit->apbc_base + APBC_SSP0, 4, 3, 0, NULL);
clk = mmp_clk_register_gate(NULL, "ssp0_clk", "ssp0_mux",
0,
pxa_unit->apbc_base + APBC_SSP0,
0x7, 0x3, 0x0, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_SSP0, clk);
clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent_names,
ARRAY_SIZE(ssp_parent_names), 0,
pxa_unit->apbc_base + APBC_SSP2, 4, 3, 0, NULL);
clk = mmp_clk_register_gate(NULL, "ssp2_clk", "ssp2_mux",
0,
pxa_unit->apbc_base + APBC_SSP2,
0x7, 0x3, 0x0, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_SSP2, clk);
#ifdef CONFIG_CORESIGHT_SUPPORT
pxa1936_coresight_clk_init(pxa_unit);
#endif
}
static DEFINE_SPINLOCK(sdh0_lock);
static DEFINE_SPINLOCK(sdh1_lock);
static DEFINE_SPINLOCK(sdh2_lock);
static const char * const sdh_parent_names[] = {"pll1_416", "pll1_624"};
static struct mmp_clk_mix_config sdh_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 8, 2, 6, 11),
};
/* Protect GC 3D register access APMU_GC&APMU_GC2D */
static DEFINE_SPINLOCK(gc_lock);
static DEFINE_SPINLOCK(gc2d_lock);
/* GC 3D */
static const char * const gc3d_parent_names[] = {
"pll1_832_gate", "pll1_624_gate", "pll2p", "pll2_div3", "pll3p",
};
static struct mmp_clk_mix_clk_table gc3d_pptbl[] = {
{.rate = 156000000, .parent_index = 1, .xtc = 0x00000044, },
{.rate = 312000000, .parent_index = 1, .xtc = 0x00000044, },
{.rate = 624000000, .parent_index = 1, .xtc = 0x00055555, },
{.rate = 832000000, .parent_index = 0, .xtc = 0x00066655, },
};
static struct mmp_clk_mix_clk_table gc3d_pptbl_pxa1936_TSMC_B0[] = {
{.rate = 156000000, .parent_index = 1, .xtc = 0x00000044, },
{.rate = 312000000, .parent_index = 1, .xtc = 0x00000044, },
{.rate = 416000000, .parent_index = 0, .xtc = 0x00055544, },
{.rate = 528000000, .parent_index = 2, .xtc = 0x00055544, },
{.rate = 624000000, .parent_index = 1, .xtc = 0x00055555, },
{.rate = 705000000, .parent_index = 3, .xtc = 0x00066655, },
{.rate = 832000000, .parent_index = 0, .xtc = 0x00066655, },
};
static struct mmp_clk_mix_config gc3d_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 12, 3, 18, 15),
.table = gc3d_pptbl,
.table_size = ARRAY_SIZE(gc3d_pptbl),
};
static struct mmp_clk_mix_config gc3d_mix_config_pxa1936_TSMC_B0 = {
.reg_info = DEFINE_MIX_REG_INFO(3, 12, 3, 18, 15),
.table = gc3d_pptbl_pxa1936_TSMC_B0,
.table_size = ARRAY_SIZE(gc3d_pptbl_pxa1936_TSMC_B0),
};
/* GC shader */
static const char * const gcsh_parent_names[] = {
"pll1_832_gate", "pll1_624_gate", "pll2p", "pll2_div3", "pll3p",
};
static struct mmp_clk_mix_clk_table gcsh_pptbl[] = {
{.rate = 156000000, .parent_index = 1, },
{.rate = 312000000, .parent_index = 1, },
{.rate = 624000000, .parent_index = 1, },
{.rate = 832000000, .parent_index = 0, },
};
static struct mmp_clk_mix_clk_table gcsh_pptbl_pxa1936_TSMC_B0[] = {
{.rate = 156000000, .parent_index = 1, },
{.rate = 312000000, .parent_index = 1, },
{.rate = 416000000, .parent_index = 0, },
{.rate = 528000000, .parent_index = 2, },
{.rate = 624000000, .parent_index = 1, },
{.rate = 705000000, .parent_index = 3, },
{.rate = 832000000, .parent_index = 0, },
};
static struct mmp_clk_mix_config gcsh_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 28, 3, 21, 31),
.table = gcsh_pptbl,
.table_size = ARRAY_SIZE(gcsh_pptbl),
};
static struct mmp_clk_mix_config gcsh_mix_config_pxa1936_TSMC_B0 = {
.reg_info = DEFINE_MIX_REG_INFO(3, 28, 3, 21, 31),
.table = gcsh_pptbl_pxa1936_TSMC_B0,
.table_size = ARRAY_SIZE(gcsh_pptbl_pxa1936_TSMC_B0),
};
/* GC 2D */
static const char * const gc2d_parent_names[] = {
"pll1_416_gate", "pll1_624_gate", "pll2", "pll2p",
};
/* Helan3 GC2D has compress feature */
static struct mmp_clk_mix_clk_table gc2d_pptbl[] = {
{.rate = 78000000, .parent_index = 1, .xtc = 0x00000044, },
{.rate = 156000000, .parent_index = 1, .xtc = 0x00000044, },
{.rate = 208000000, .parent_index = 0, .xtc = 0x00000044, },
{.rate = 312000000, .parent_index = 1, .xtc = 0x00000044, },
{.rate = 416000000, .parent_index = 0, .xtc = 0x00055544, },
};
static struct mmp_clk_mix_config gc2d_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 12, 2, 6, 15),
.table = gc2d_pptbl,
.table_size = ARRAY_SIZE(gc2d_pptbl),
};
/* GC bus(shared by GC 3D and 2D) */
static const char * const gcbus_parent_names[] = {
"pll1_416_gate", "pll1_624_gate", "pll2", "pll4",
};
/* Helan3 GCbus is 128bit */
static struct mmp_clk_mix_clk_table gcbus_pptbl[] = {
{.rate = 78000000, .parent_index = 1, },
{.rate = 156000000, .parent_index = 1, },
{.rate = 208000000, .parent_index = 0, },
{.rate = 312000000, .parent_index = 1, },
{.rate = 416000000, .parent_index = 0, },
};
static struct mmp_clk_mix_config gcbus_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 17, 2, 20, 16),
.table = gcbus_pptbl,
.table_size = ARRAY_SIZE(gcbus_pptbl),
};
/* Protect register access APMU_VPU */
static DEFINE_SPINLOCK(vpu_lock);
/* VPU fclk */
static const char * const vpufclk_parent_names[] = {
"pll1_416_gate", "pll1_624_gate", "pll1_499_en", "pll2p",
};
static struct mmp_clk_mix_clk_table vpufclk_pptbl[] = {
{.rate = 156000000, .parent_index = 1, .xtc = 0x00380404, },
{.rate = 208000000, .parent_index = 0, .xtc = 0x00380404, },
{.rate = 312000000, .parent_index = 1, .xtc = 0x00385404, },
{.rate = 416000000, .parent_index = 0, .xtc = 0x00B85454, },
{.rate = 499000000, .parent_index = 2, .xtc = 0x00B85454, },
{.rate = 528000000, .parent_index = 3, .xtc = 0x00B855A4, },
};
static struct mmp_clk_mix_config vpufclk_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 8, 2, 6, 20),
.table = vpufclk_pptbl,
.table_size = ARRAY_SIZE(vpufclk_pptbl),
};
/* vpu bus */
static const char * const vpubus_parent_names[] = {
"pll1_416_gate", "pll1_624_gate", "pll2", "pll2_div3",
};
static struct mmp_clk_mix_clk_table vpubus_pptbl[] = {
{.rate = 156000000, .parent_index = 1, },
{.rate = 208000000, .parent_index = 0, },
{.rate = 312000000, .parent_index = 1, },
{.rate = 416000000, .parent_index = 0, },
};
static struct mmp_clk_mix_config vpubus_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 13, 2, 11, 21),
.table = vpubus_pptbl,
.table_size = ARRAY_SIZE(vpubus_pptbl),
};
static DEFINE_SPINLOCK(disp_lock);
static const char * const disp1_parent_names[] = {"pll1_624", "pll1_832", "pll1_499_en"};
static const char * const disp2_parent_names[] = {"pll2", "pll2p", "pll2_div3"};
static const char * const disp3_parent_names[] = {"pll3p", "pll3_div3"};
static const char *disp4_parent_names[] = {"pll4", "pll4_div3"};
static const char * const disp_axi_parent_names[] = {"pll1_416", "pll1_624", "pll2", "pll2p"};
static int disp_axi_mux_table[] = {0x0, 0x1, 0x2, 0x3};
static struct mmp_clk_mix_config disp_axi_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(2, 19, 2, 17, 22),
.mux_table = disp_axi_mux_table,
};
/* sc2 clk */
static DEFINE_SPINLOCK(ccic0_lock);
static DEFINE_SPINLOCK(ccic1_lock);
static DEFINE_SPINLOCK(isp_lock);
static const char *sc2_4x_parent_names[] = {"pll1_832_gate", "pll1_624_gate",
"pll2_div3", "pll2p", "pll4_div3"};
static int sc2_4x_mux_table[] = {0x0, 0x1, 0x02, 0x6, 0x03};
static struct mmp_clk_mix_config sc2_4x_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 18, 3, 23, 15),
.mux_table = sc2_4x_mux_table,
};
static const char *sc2_csi_parent_names[] = {"pll1_416_gate", "pll1_624_gate",
"pll2_div3", "pll2p", "pll4_div3"};
static int sc2_csi_mux_table[] = {0x0, 0x1, 0x02, 0x6, 0x03};
static struct mmp_clk_mix_config sc2_csi_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 19, 3, 16, 15),
.mux_table = sc2_csi_mux_table,
};
static const char *sc2_axi_parent_names[] = {"pll1_416_gate", "pll1_624_gate",
"pll2", "pll2p"};
static struct mmp_clk_mix_config sc2_axi_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 18, 2, 21, 23),
};
static const char *sc2_phy_parent_names[] = {"pll1_6", "pll1_12"};
static struct mmp_clk_mix_clk_table isp_pipe_clk_pptbl[] = {
{.rate = 208000000, .parent_index = 0, .xtc = 0x00110011, },
/*{.rate = 250000000, .parent_index = 3, .xtc = 0x00115511, }, */
{.rate = 312000000, .parent_index = 1, .xtc = 0x00115511, },
{.rate = 416000000, .parent_index = 0, .xtc = 0x00115511, },
{.rate = 499000000, .parent_index = 3, .xtc = 0x00115511, },
};
static const char *isp_pipe_parent_names[] = {"pll1_416_gate", "pll1_624_gate",
"pll4_div3", "pll1_499_gate",};
static struct mmp_clk_mix_config isp_pipe_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 4, 2, 2, 7),
.table = isp_pipe_clk_pptbl,
.table_size = ARRAY_SIZE(isp_pipe_clk_pptbl),
};
#ifdef CONFIG_SMC91X
static void __init smc91x_clk_init(void __iomem *apmu_base)
{
struct device_node *np = of_find_node_by_name(NULL, "smc91x");
const char *str = NULL;
void __iomem *reg;
if (np && !of_property_read_string(np, "clksrc", &str))
if (!strcmp(str, "smc91x")) {
/* Enable clock to SMC Controller */
writel(0x5b, apmu_base + APMU_SMC);
/* Configure SMC Controller */
/* Set CS0 to A\D type memory */
reg = ioremap(SMC_CLK, 4);
writel(0x52880008, reg);
iounmap(reg);
}
}
#endif
struct pxa1936_clk_disp {
struct mmp_clk_gate gate;
struct clk_mux mux;
struct clk_divider divider;
const struct clk_ops *mux_ops;
const struct clk_ops *div_ops;
const struct clk_ops *gate_ops;
};
static struct pxa1936_clk_disp disp1_clks;
static struct pxa1936_clk_disp disp4_clks;
static void pxa1936_axi_periph_clk_init(struct pxa1936_clk_unit *pxa_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &pxa_unit->unit;
const char **parent_names;
u32 parent_num;
clk = mmp_clk_register_gate(NULL, "usb_clk", NULL, 0,
pxa_unit->apmu_base + APMU_USB,
0x9, 0x9, 0x1, 0, NULL);
mmp_clk_add(unit, PXA1936_CLK_USB, clk);
/* nand flash clock, no one use it, expect to be disabled */
clk = mmp_clk_register_gate(NULL, "nf_clk", NULL, 0,
pxa_unit->apmu_base + APMU_NF,
0x1db, 0x1db, 0x0, 0, NULL);
clk = mmp_clk_register_gate(NULL, "sdh_axi_clk", NULL, 0,
pxa_unit->apmu_base + APMU_SDH0,
0x8, 0x8, 0x0, 0, &sdh0_lock);
mmp_clk_add(unit, PXA1936_CLK_SDH_AXI, clk);
sdh_mix_config.reg_info.reg_clk_ctrl = pxa_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,
pxa_unit->apmu_base + APMU_SDH0,
0x12, 0x12, 0x0, 0, &sdh0_lock);
mmp_clk_add(unit, PXA1936_CLK_SDH0, clk);
clk = mmp_clk_register_dvfs_dummy("sdh0_dummy", NULL,
0, DUMMY_VL_TO_KHZ(0));
mmp_clk_add(unit, PXA1936_CLK_SDH0_DUMMY, clk);
sdh_mix_config.reg_info.reg_clk_ctrl = pxa_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,
pxa_unit->apmu_base + APMU_SDH1,
0x12, 0x12, 0x0, 0, &sdh1_lock);
mmp_clk_add(unit, PXA1936_CLK_SDH1, clk);
clk = mmp_clk_register_dvfs_dummy("sdh1_dummy", NULL,
0, DUMMY_VL_TO_KHZ(0));
mmp_clk_add(unit, PXA1936_CLK_SDH1_DUMMY, clk);
sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_SDH2;
clk = mmp_clk_register_mix(NULL, "sdh2_mix_clk",
(const char **)sdh_parent_names, ARRAY_SIZE(sdh_parent_names),
CLK_SET_RATE_PARENT,
&sdh_mix_config, &sdh2_lock);
clk = mmp_clk_register_gate(NULL, "sdh2_clk", "sdh2_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_SDH2,
0x12, 0x12, 0x0, 0, &sdh2_lock);
mmp_clk_add(unit, PXA1936_CLK_SDH2, clk);
clk = mmp_clk_register_dvfs_dummy("sdh2_dummy", NULL,
0, DUMMY_VL_TO_KHZ(0));
mmp_clk_add(unit, PXA1936_CLK_SDH2_DUMMY, clk);
/*
* DE suggest SW to release GC_2D_3D_AXI_Reset
* before both 3D/2D power on sequence
*/
clk = mmp_clk_register_gate(NULL, "gc_axi_rst", NULL,
0, pxa_unit->apmu_base + APMU_GC2D,
0x1, 0x1, 0x0, 0, &gc2d_lock);
clk_prepare_enable(clk);
if (get_helan3_svc_version() == SVC_TSMC_B0) {
gc3d_mix_config_pxa1936_TSMC_B0.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_GC;
gc3d_mix_config_pxa1936_TSMC_B0.reg_info.reg_clk_xtc = pxa_unit->ciu_base + GPU_XTC;
clk = mmp_clk_register_mix(NULL, "gc3d_mix_clk",
(const char **)gc3d_parent_names, ARRAY_SIZE(gc3d_parent_names),
0, &gc3d_mix_config_pxa1936_TSMC_B0, &gc_lock);
} else {
gc3d_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_GC;
gc3d_mix_config.reg_info.reg_clk_xtc = pxa_unit->ciu_base + GPU_XTC;
clk = mmp_clk_register_mix(NULL, "gc3d_mix_clk",
(const char **)gc3d_parent_names, ARRAY_SIZE(gc3d_parent_names),
0, &gc3d_mix_config, &gc_lock);
}
#ifdef CONFIG_PM_DEVFREQ
__init_comp_devfreq_table(clk, DEVFREQ_GPU_3D);
#endif
clk = mmp_clk_register_gate(NULL, "gc3d_clk", "gc3d_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_GC,
(3 << 4), (3 << 4), 0x0, 0, &gc_lock);
clk_set_rate(clk, 312000000);
mmp_clk_add(unit, PXA1936_CLK_GC3D, clk);
register_mixclk_dcstatinfo(clk);
gcsh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_GC;
parent_names = (const char **)gcsh_parent_names;
parent_num = ARRAY_SIZE(gcsh_parent_names);
if (get_helan3_svc_version() == SVC_TSMC_B0) {
gcsh_mix_config_pxa1936_TSMC_B0.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_GC;
clk = mmp_clk_register_mix(NULL, "gcsh_mix_clk",
(const char **)gcsh_parent_names, ARRAY_SIZE(gcsh_parent_names),
0, &gcsh_mix_config_pxa1936_TSMC_B0, &gc_lock);
} else {
gcsh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_GC;
clk = mmp_clk_register_mix(NULL, "gcsh_mix_clk",
(const char **)gcsh_parent_names, ARRAY_SIZE(gcsh_parent_names),
0, &gcsh_mix_config, &gc_lock);
}
#ifdef CONFIG_PM_DEVFREQ
__init_comp_devfreq_table(clk, DEVFREQ_GPU_SH);
#endif
clk = mmp_clk_register_gate(NULL, "gcsh_clk", "gcsh_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_GC,
(1 << 25), (1 << 25), 0x0, 0, &gc_lock);
clk_set_rate(clk, 312000000);
mmp_clk_add(unit, PXA1936_CLK_GCSH, clk);
register_mixclk_dcstatinfo(clk);
gc2d_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_GC2D;
gc2d_mix_config.reg_info.reg_clk_xtc = pxa_unit->ciu_base + GPU2D_XTC;
clk = mmp_clk_register_mix(NULL, "gc2d_mix_clk",
(const char **)gc2d_parent_names, ARRAY_SIZE(gc2d_parent_names),
0, &gc2d_mix_config, &gc2d_lock);
#ifdef CONFIG_PM_DEVFREQ
__init_comp_devfreq_table(clk, DEVFREQ_GPU_2D);
#endif
clk = mmp_clk_register_gate(NULL, "gc2d_clk", "gc2d_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_GC2D,
(3 << 4), (3 << 4), 0x0, 0, &gc2d_lock);
clk_set_rate(clk, 208000000);
mmp_clk_add(unit, PXA1936_CLK_GC2D, clk);
register_mixclk_dcstatinfo(clk);
gcbus_mix_config.reg_info.reg_clk_ctrl =
pxa_unit->apmu_base + APMU_GC2D;
clk = mmp_clk_register_mix(NULL, "gcbus_mix_clk",
(const char **)gcbus_parent_names, ARRAY_SIZE(gcbus_parent_names),
0, &gcbus_mix_config, &gc2d_lock);
clk = mmp_clk_register_gate(NULL, "gcbus_clk", "gcbus_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_GC2D,
(1 << 3), (1 << 3), 0x0, 0, &gc2d_lock);
clk_set_rate(clk, 156000000);
mmp_clk_add(unit, PXA1936_CLK_GCBUS, clk);
vpufclk_mix_config.reg_info.reg_clk_ctrl =
pxa_unit->apmu_base + APMU_VPU;
vpufclk_mix_config.reg_info.reg_clk_xtc =
pxa_unit->ciu_base + VPU_XTC;
clk = mmp_clk_register_mix(NULL, "vpufunc_mix_clk",
(const char **)vpufclk_parent_names, ARRAY_SIZE(vpufclk_parent_names),
0, &vpufclk_mix_config, &vpu_lock);
#ifdef CONFIG_VPU_DEVFREQ
__init_comp_devfreq_table(clk, DEVFREQ_VPU_BASE);
#endif
clk = mmp_clk_register_gate(NULL, "vpufunc_clk", "vpufunc_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_VPU,
(3 << 4), (3 << 4), 0x0, 0, &vpu_lock);
clk_set_rate(clk, 416000000);
mmp_clk_add(unit, PXA1936_CLK_VPU, clk);
register_mixclk_dcstatinfo(clk);
vpubus_mix_config.reg_info.reg_clk_ctrl =
pxa_unit->apmu_base + APMU_VPU;
clk = mmp_clk_register_mix(NULL, "vpubus_mix_clk",
(const char **)vpubus_parent_names, ARRAY_SIZE(vpubus_parent_names),
0, &vpubus_mix_config, &vpu_lock);
clk = mmp_clk_register_gate(NULL, "vpubus_clk", "vpubus_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_VPU,
(1 << 3), (1 << 3), 0x0, 0, &vpu_lock);
clk_set_rate(clk, 416000000);
mmp_clk_add(unit, PXA1936_CLK_VPUBUS, clk);
clk = mmp_clk_register_gate(NULL, "dsi_esc_clk", NULL, 0,
pxa_unit->apmu_base + APMU_DSI1,
0xf, 0xc, 0x0, 0, &disp_lock);
mmp_clk_add(unit, PXA1936_CLK_DSI_ESC, clk);
disp1_clks.mux_ops = &clk_mux_ops;
disp1_clks.mux.mask = 0x2;
disp1_clks.mux.shift = 9;
disp1_clks.mux.reg = pxa_unit->apmu_base + APMU_DISP1;
disp1_clks.gate.mask = 0x20;
disp1_clks.gate.reg = pxa_unit->apmu_base + APMU_DISP1;
disp1_clks.gate.val_disable = 0x0;
disp1_clks.gate.val_enable = 0x20;
disp1_clks.gate.flags = 0x0;
disp1_clks.gate_ops = &mmp_clk_gate_ops;
clk = clk_register_composite(NULL, "disp1_sel_clk", (const char **)disp1_parent_names,
ARRAY_SIZE(disp1_parent_names),
&disp1_clks.mux.hw, disp1_clks.mux_ops,
NULL, NULL,
&disp1_clks.gate.hw, disp1_clks.gate_ops,
CLK_SET_RATE_PARENT);
mmp_clk_add(unit, PXA1936_CLK_DISP1, clk);
clk_register_clkdev(clk, "disp1_sel_clk", NULL);
clk = clk_register_mux(NULL, "disp2_sel_clk",
(const char **)disp2_parent_names, ARRAY_SIZE(disp2_parent_names),
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_DISP1,
11, 2, 0, &disp_lock);
mmp_clk_add(unit, PXA1936_CLK_DISP2, clk);
clk = mmp_clk_register_gate(NULL, "dsip2_clk", "disp2_sel_clk",
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_DISP1,
0x40, 0x40, 0x0, 0, &disp_lock);
mmp_clk_add(unit, PXA1936_CLK_DISP2_EN, clk);
clk = clk_register_mux(NULL, "disp3_sel_clk",
(const char **)disp3_parent_names, ARRAY_SIZE(disp3_parent_names),
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_DISP1,
13, 1, 0, &disp_lock);
mmp_clk_add(unit, PXA1936_CLK_DISP3, clk);
clk = mmp_clk_register_gate(NULL, "dsip3_en_clk", "disp3_sel_clk",
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_DISP1,
0x80, 0x80, 0x0, 0, &disp_lock);
mmp_clk_add(unit, PXA1936_CLK_DISP3_EN, clk);
disp4_clks.mux_ops = &clk_mux_ops;
disp4_clks.mux.mask = 0x1;
disp4_clks.mux.shift = 14;
disp4_clks.mux.reg = pxa_unit->apmu_base + APMU_DISP1;
disp4_clks.gate.mask = 0x100;
disp4_clks.gate.reg = pxa_unit->apmu_base + APMU_DISP1;
disp4_clks.gate.val_disable = 0x0;
disp4_clks.gate.val_enable = 0x100;
disp4_clks.gate.flags = 0x0;
disp4_clks.gate_ops = &mmp_clk_gate_ops;
clk = clk_register_composite(NULL, "dsi_pll", (const char **)disp4_parent_names,
ARRAY_SIZE(disp4_parent_names),
&disp4_clks.mux.hw, disp4_clks.mux_ops,
NULL, NULL,
&disp4_clks.gate.hw, disp4_clks.gate_ops,
0);
mmp_clk_add(unit, PXA1936_CLK_DISP4, clk);
clk_register_clkdev(clk, "dsi_pll", NULL);
disp_axi_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_DISP1;
clk = mmp_clk_register_mix(NULL, "disp_axi_sel_clk",
(const char **)disp_axi_parent_names, ARRAY_SIZE(disp_axi_parent_names),
CLK_SET_RATE_PARENT,
&disp_axi_mix_config, &disp_lock);
mmp_clk_add(unit, PXA1936_CLK_DISP_AXI_SEL_CLK, clk);
clk_set_rate(clk, 104000000);
clk = mmp_clk_register_gate(NULL, "disp_axi_clk", "disp_axi_sel_clk",
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_DISP1,
0x10009, 0x10009, 0x10000, 0, &disp_lock);
mmp_clk_add(unit, PXA1936_CLK_DISP_AXI_CLK, clk);
clk = mmp_clk_register_gate(NULL, "LCDCIHCLK", "disp_axi_clk", 0,
pxa_unit->apmu_base + APMU_DISP1,
0x16, 0x16, 0x4, 0, &disp_lock);
mmp_clk_add(unit, PXA1936_CLK_DISP_HCLK, clk);
/* SC2 VCLK */
clk = clk_register_divider(NULL, "isim_vclk_div", "pll1_312_gate",
0, pxa_unit->apmu_base + APMU_CCIC1,
22, 4, 0, &ccic1_lock);
clk = mmp_clk_register_gate(NULL, "isim_vclk_gate", "isim_vclk_div",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_CCIC1,
0x4000000, 0x4000000, 0x0, 0, &ccic1_lock);
mmp_clk_add(unit, PXA1936_CLK_SC2_MCLK, clk);
sc2_4x_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC0;
clk = mmp_clk_register_mix(NULL, "sc2_4x_mix_clk", sc2_4x_parent_names,
ARRAY_SIZE(sc2_4x_parent_names), 0,
&sc2_4x_mix_config, &ccic0_lock);
clk = mmp_clk_register_gate(NULL, "sc2_4x_clk", "sc2_4x_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_CCIC0,
0x12, 0x12, 0x0, 0, &ccic0_lock);
mmp_clk_add(unit, PXA1936_CLK_SC2_4X_CLK, clk);
sc2_csi_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC1;
clk = mmp_clk_register_mix(NULL, "sc2_csi_mix_clk",
sc2_csi_parent_names,
ARRAY_SIZE(sc2_csi_parent_names), 0,
&sc2_csi_mix_config, &ccic1_lock);
clk = mmp_clk_register_gate(NULL, "sc2_csi_clk", "sc2_csi_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_CCIC1,
0x12, 0x12, 0x0, 0, &ccic1_lock);
mmp_clk_add(unit, PXA1936_CLK_SC2_CSI_CLK, clk);
sc2_axi_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_ISP;
clk = mmp_clk_register_mix(NULL, "sc2_axi_mix_clk",
sc2_axi_parent_names,
ARRAY_SIZE(sc2_axi_parent_names), 0,
&sc2_axi_mix_config, &isp_lock);
clk = mmp_clk_register_gate(NULL, "sc2_axi_clk", "sc2_axi_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_ISP,
0x30000, 0x30000, 0x0, 0, &isp_lock);
mmp_clk_add(unit, PXA1936_CLK_SC2_AXI_CLK, clk);
clk = clk_register_mux(NULL, "sc2_phy2ln_mux", sc2_phy_parent_names,
ARRAY_SIZE(sc2_phy_parent_names), 0, pxa_unit->apmu_base + APMU_CCIC1,
7, 1, 0, &ccic1_lock);
clk = mmp_clk_register_gate(NULL, "sc2_phy2ln_clk", "sc2_phy2ln_mux",
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_CCIC1,
0x24, 0x24, 0x0, 0, &ccic1_lock);
mmp_clk_add(unit, PXA1936_CLK_SC2_PHY2LN_CLK_EN, clk);
clk = clk_register_mux(NULL, "sc2_phy4ln_mux", sc2_phy_parent_names,
ARRAY_SIZE(sc2_phy_parent_names), 0, pxa_unit->apmu_base + APMU_CCIC0,
7, 1, 0, &ccic0_lock);
clk = mmp_clk_register_gate(NULL, "sc2_phy4ln_clk", "sc2_phy4ln_mux",
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_CCIC0,
0x24, 0x24, 0x0, 0, &ccic0_lock);
mmp_clk_add(unit, PXA1936_CLK_SC2_PHY4LN_CLK_EN, clk);
isp_pipe_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_ISP;
isp_pipe_mix_config.reg_info.reg_clk_xtc = pxa_unit->sc2desc_base + ISP_XTC;
clk = mmp_clk_register_mix(NULL, "isp_pipe_mix_clk",
isp_pipe_parent_names,
ARRAY_SIZE(isp_pipe_parent_names), 0,
&isp_pipe_mix_config, &isp_lock);
/* add isp ahb and isp axi reset to pipe clk enable */
clk = mmp_clk_register_gate(NULL, "isp_pipe_clk", "isp_pipe_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_ISP,
0x503, 0x503, 0x0, 0, &isp_lock);
mmp_clk_add(unit, PXA1936_CLK_ISP_PIPE_CLK, clk);
clk = clk_register_divider(NULL, "isp_core_div", "pll1_624_gate",
0, pxa_unit->apmu_base + APMU_ISP,
24, 3, 0, &isp_lock);
clk = mmp_clk_register_gate(NULL, "isp_core_gate", "isp_core_div",
CLK_SET_RATE_PARENT,
pxa_unit->apmu_base + APMU_ISP,
0x18000000, 0x18000000, 0x0, 0, &isp_lock);
mmp_clk_add(unit, PXA1936_CLK_ISP_CORE_CLK_EN, clk);
clk = mmp_clk_register_gate(NULL, "sc2_ahb_gate", NULL, 0,
pxa_unit->apmu_base + APMU_CCIC0,
0x600000, 0x600000, 0x0, 0, &ccic0_lock);
mmp_clk_add(unit, PXA1936_CLK_SC2_AHB_CLK, clk);
}
static DEFINE_SPINLOCK(fc_seq_lock);
static struct cpu_rtcwtc clst0_cpu_rtcwtc_tbl[] = {
{.max_pclk = 416, .l1_xtc = 0x11111111, .l2_xtc = 0x00001111, },
{.max_pclk = 832, .l1_xtc = 0x55555555, .l2_xtc = 0x00005555, },
{.max_pclk = 1057, .l1_xtc = 0x55555555, .l2_xtc = 0x0000555A, },
{.max_pclk = 1248, .l1_xtc = 0xAAAAAAAA, .l2_xtc = 0x0000AAAA, },
};
/* CORE */
static const char * const clst0_core_parent[] = {
"pll1_624", "pll1_1248", "pll2", "pll1_832", "pll3p",
};
static struct parents_table clst0_core_parent_table[] = {
{
.parent_name = "pll1_624",
.hw_sel_val = 0x0,
},
{
.parent_name = "pll1_1248",
.hw_sel_val = 0x1,
},
{
.parent_name = "pll2",
.hw_sel_val = 0x2,
},
{
.parent_name = "pll1_832",
.hw_sel_val = 0x3,
},
{
.parent_name = "pll3p",
.hw_sel_val = 0x5,
},
};
/* NOTE: please update c0clk_cciclk_relationtbl as well if add new pp. */
static struct cpu_opt clst0_op_array[] = {
{
.pclk = 312,
.core_aclk = 156,
.ap_clk_sel = 0x0,
},
{
.pclk = 416,
.core_aclk = 208,
.ap_clk_sel = 0x3,
},
{
.pclk = 624,
.core_aclk = 312,
.ap_clk_sel = 0x0,
},
{
.pclk = 832,
.core_aclk = 416,
.ap_clk_sel = 0x3,
},
{
.pclk = 1057,
.core_aclk = 528,
.ap_clk_sel = 0x2,
.ap_clk_src = 1057,
},
{
.pclk = 1248,
.core_aclk = 624,
.ap_clk_sel = 0x1,
},
};
static struct core_params clst0_core_params = {
.parent_table = clst0_core_parent_table,
.parent_table_size = ARRAY_SIZE(clst0_core_parent_table),
.cpu_opt = clst0_op_array,
.cpu_opt_size = ARRAY_SIZE(clst0_op_array),
.cpu_rtcwtc_table = clst0_cpu_rtcwtc_tbl,
.cpu_rtcwtc_table_size = ARRAY_SIZE(clst0_cpu_rtcwtc_tbl),
.bridge_cpurate = 1248,
.max_cpurate = 1248,
.dcstat_support = true,
};
static struct cpu_rtcwtc clst1_cpu_rtcwtc_tbl[] = {
{.max_pclk = 416, .l1_xtc = 0x11111111, .l2_xtc = 0x00001111, },
{.max_pclk = 832, .l1_xtc = 0x55555555, .l2_xtc = 0x00005555, },
{.max_pclk = 1057, .l1_xtc = 0x55555555, .l2_xtc = 0x0000555A, },
{.max_pclk = 1803, .l1_xtc = 0xAAAAAAAA, .l2_xtc = 0x0000AAAA, },
};
static const char * const clst1_core_parent[] = {
"pll1_832", "pll1_1248", "pll2", "pll3p",
};
static struct parents_table clst1_core_parent_table[] = {
{
.parent_name = "pll1_832",
.hw_sel_val = 0x0,
},
{
.parent_name = "pll1_1248",
.hw_sel_val = 0x1,
},
{
.parent_name = "pll2",
.hw_sel_val = 0x2,
},
{
.parent_name = "pll3p",
.hw_sel_val = 0x3,
},
};
/* NOTE: please update c1clk_cciclk_relationtbl as well if add new pp. */
static struct cpu_opt clst1_op_array[] = {
{
.pclk = 312,
.core_aclk = 156,
.ap_clk_sel = 0x1,
},
{
.pclk = 416,
.core_aclk = 208,
.ap_clk_sel = 0x0,
},
{
.pclk = 624,
.core_aclk = 312,
.ap_clk_sel = 0x1,
},
{
.pclk = 832,
.core_aclk = 416,
.ap_clk_sel = 0x0,
},
{
.pclk = 1057,
.core_aclk = 528,
.ap_clk_sel = 0x2,
.ap_clk_src = 1057,
},
{
.pclk = 1248,
.core_aclk = 624,
.ap_clk_sel = 0x1,
},
{
.pclk = 1491,
.core_aclk = 745,
.ap_clk_sel = 0x3,
.ap_clk_src = 1491,
},
{
.pclk = 1595,
.core_aclk = 797,
.ap_clk_sel = 0x3,
.ap_clk_src = 1595,
},
{
.pclk = 1803,
.core_aclk = 901,
.ap_clk_sel = 0x3,
.ap_clk_src = 1803,
},
};
static struct core_params clst1_core_params = {
.parent_table = clst1_core_parent_table,
.parent_table_size = ARRAY_SIZE(clst1_core_parent_table),
.cpu_opt = clst1_op_array,
.cpu_opt_size = ARRAY_SIZE(clst1_op_array),
.cpu_rtcwtc_table = clst1_cpu_rtcwtc_tbl,
.cpu_rtcwtc_table_size = ARRAY_SIZE(clst1_cpu_rtcwtc_tbl),
.bridge_cpurate = 1248,
.max_cpurate = 1491,
.dcstat_support = true,
};
static struct pxa1936_clk_unit *globla_pxa_unit;
static int pxa1936_powermode(u32 cpu)
{
/* FIXME: register PMU_CORE_STATUS was changed on Helan3 */
unsigned status_temp = 0;
unsigned c1_offset = 0, c2_offset = 0;
if (cpu >= 0 && cpu < 4) {
c1_offset = 6;
c2_offset = 7;
} else if (cpu >= 4 && cpu < 8) {
c1_offset = 9;
c2_offset = 10;
}
status_temp = ((__raw_readl(globla_pxa_unit->apmu_base +
APMU_CORE_STATUS)) &
((1 << (c1_offset + 3 * cpu)) | (1 << (c2_offset + 3 * cpu))));
if (!status_temp)
return MAX_LPM_INDEX;
if (status_temp & (1 << (c1_offset + 3 * cpu)))
return LPM_C1;
else if (status_temp & (1 << (c2_offset + 3 * cpu)))
return LPM_C2;
return 0;
}
/* DDR */
static const char * const ddr_parent[] = {
"pll1_624", "pll1_832", "pll2", "pll4", "pll1_1248", "pll3p",
};
/*
* DDR clock source:
* 0x0 = PLL1 624 MHz
* 0x1 = PLL1 832 MHz
* 0x4 = PLL2_CLKOUT
* 0x5 = PLL4_CLKOUT
* 0x6 = PLL1 1248 MHz
* 0x7 = PLL3_CLKOUTP
*/
static struct parents_table ddr_parent_table[] = {
{
.parent_name = "pll1_624",
.hw_sel_val = 0x0,
},
{
.parent_name = "pll1_832",
.hw_sel_val = 0x1,
},
{
.parent_name = "pll2",
.hw_sel_val = 0x4,
},
{
.parent_name = "pll4",
.hw_sel_val = 0x5,
},
/* pll3p is dedicated for cpu, ignore it */
{
.parent_name = "pll1_1248",
.hw_sel_val = 0x6,
},
};
/*
* FIXME: could assign specific lpm tbl, use 0 for bringup.
*/
static struct ddr_opt lpddr533_op_array[] = {
{
.dclk = 156,
.ddr_tbl_index = 2,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x0,
},
{
.dclk = 312,
.ddr_tbl_index = 4,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x0,
},
{
.dclk = 416,
.ddr_tbl_index = 6,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x1,
},
{
.dclk = 528,
.ddr_tbl_index = 8,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x4,
},
};
/* enable 208/312/416/624 4x, 667 2x, remove 528 */
static struct ddr_opt lpddr667_op_array[] = {
{
.dclk = 208,
.mode_4x_en = 1,
.ddr_tbl_index = 2,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x1,
},
{
.dclk = 312,
.mode_4x_en = 1,
.ddr_tbl_index = 4,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x0,
},
{
.dclk = 416,
.mode_4x_en = 1,
.ddr_tbl_index = 6,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x1,
},
{
.dclk = 624,
.mode_4x_en = 1,
.ddr_tbl_index = 10,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x6,
},
{
.dclk = 667,
.mode_4x_en = 0,
.ddr_tbl_index = 12,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x5,
},
};
static struct ddr_opt lpddr800_op_array[] = {
{
.dclk = 208,
.mode_4x_en = 1,
.ddr_tbl_index = 2,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x1,
},
{
.dclk = 312,
.mode_4x_en = 1,
.ddr_tbl_index = 4,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x0,
},
{
.dclk = 416,
.mode_4x_en = 1,
.ddr_tbl_index = 6,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x1,
},
{
.dclk = 624,
.mode_4x_en = 1,
.ddr_tbl_index = 10,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x6,
},
{
.dclk = 797,
.mode_4x_en = 1,
.ddr_tbl_index = 12,
.ddr_lpmtbl_index = 0,
.ddr_clk_sel = 0x5,
},
};
static struct ddr_params ddr_params = {
.parent_table = ddr_parent_table,
.parent_table_size = ARRAY_SIZE(ddr_parent_table),
.dcstat_support = true,
};
static struct axi_rtcwtc axi_rtcwtc_tbl[] = {
{.max_aclk = 208, .xtc_val = 0xEE006656, },
{.max_aclk = 312, .xtc_val = 0xEE116656, },
};
static const char * const axi_parent[] = {
"pll1_416", "pll1_624", "pll2", "pll2p",
};
/*
* AXI clock source:
* 0x0 = PLL1 416 MHz
* 0x1 = PLL1 624 MHz
* 0x2 = PLL2_CLKOUT
* 0x3 = PLL2_CLKOUTP
*/
static struct parents_table axi_parent_table[] = {
{
.parent_name = "pll1_416",
.hw_sel_val = 0x0,
},
{
.parent_name = "pll1_624",
.hw_sel_val = 0x1,
},
{
.parent_name = "pll2",
.hw_sel_val = 0x2,
},
{
.parent_name = "pll2p",
.hw_sel_val = 0x3,
},
};
static struct axi_opt axi_op_array[] = {
{
.aclk = 156,
.axi_clk_sel = 0x1,
},
{
.aclk = 208,
.axi_clk_sel = 0x0,
},
{
.aclk = 312,
.axi_clk_sel = 0x1,
},
};
static struct axi_params axi_params = {
.parent_table = axi_parent_table,
.parent_table_size = ARRAY_SIZE(axi_parent_table),
.axi_rtcwtc_table = axi_rtcwtc_tbl,
.axi_rtcwtc_table_size = ARRAY_SIZE(axi_rtcwtc_tbl),
.dcstat_support = true,
};
/* CCI-400 mem clk */
static const char * const cci_parent_names[] = {
"pll1_832", "pll1_1248", "pll2", "pll3p"
};
static struct mmp_clk_mix_clk_table cci_memclk_pptbl[] = {
{.rate = 156000000, .parent_index = 1, },
{.rate = 208000000, .parent_index = 0, },
{.rate = 312000000, .parent_index = 1, },
{.rate = 416000000, .parent_index = 0, },
{.rate = 624000000, .parent_index = 1, },
{.rate = 832000000, .parent_index = 0, },
};
static struct mmp_clk_mix_config cci_memclk_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(3, 4, 3, 0, 12),
.table = cci_memclk_pptbl,
.table_size = ARRAY_SIZE(cci_memclk_pptbl),
};
static struct combclk_relation dclk_aclk_relationtbl[] = {
{.mclk_rate = 156000000, .sclk_rate = 156000000},
{.mclk_rate = 208000000, .sclk_rate = 156000000},
{.mclk_rate = 312000000, .sclk_rate = 156000000},
{.mclk_rate = 416000000, .sclk_rate = 208000000},
{.mclk_rate = 528000000, .sclk_rate = 312000000},
{.mclk_rate = 624000000, .sclk_rate = 208000000},
{.mclk_rate = 667000000, .sclk_rate = 312000000},
{.mclk_rate = 797000000, .sclk_rate = 312000000},
};
static struct combclk_relation c0clk_cciclk_relationtbl[] = {
{.mclk_rate = 312000000, .sclk_rate = 156000000},
{.mclk_rate = 416000000, .sclk_rate = 208000000},
{.mclk_rate = 624000000, .sclk_rate = 312000000},
{.mclk_rate = 832000000, .sclk_rate = 416000000},
{.mclk_rate = 1057000000, .sclk_rate = 624000000},
{.mclk_rate = 1248000000, .sclk_rate = 624000000},
};
static struct combclk_relation c1clk_cciclk_relationtbl[] = {
{.mclk_rate = 312000000, .sclk_rate = 156000000},
{.mclk_rate = 416000000, .sclk_rate = 208000000},
{.mclk_rate = 624000000, .sclk_rate = 312000000},
{.mclk_rate = 832000000, .sclk_rate = 416000000},
{.mclk_rate = 1057000000, .sclk_rate = 624000000},
{.mclk_rate = 1248000000, .sclk_rate = 624000000},
{.mclk_rate = 1491000000, .sclk_rate = 624000000},
{.mclk_rate = 1595000000, .sclk_rate = 832000000},
{.mclk_rate = 1803000000, .sclk_rate = 832000000},
};
static void __init pxa1936_acpu_init(struct pxa1936_clk_unit *pxa_unit)
{
struct mmp_clk_unit *unit = &pxa_unit->unit;
struct clk *clk;
int i;
/* make sure cci-400 clock & QoS notifier ready before core clocks */
cci_memclk_mix_config.reg_info.reg_clk_ctrl =
pxa_unit->apmu_base + APMU_CCI;
clk = mmp_clk_register_mix(NULL, "cci_mem_mix_clk",
(const char **)cci_parent_names, ARRAY_SIZE(cci_parent_names),
0, &cci_memclk_mix_config, NULL);
clk = mmp_clk_register_gate(NULL, "cci_memclk", "cci_mem_mix_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
pxa_unit->apmu_base + APMU_CCI,
(1 << 13), (1 << 13), 0x0, 0, NULL);
clk_prepare_enable(clk);
mmp_clk_add(unit, PXA1936_CLK_CCI_MEM, clk);
register_slave_clock(clk, CLST0,
cci_memclk_pptbl[ARRAY_SIZE(cci_memclk_pptbl) - 1].rate,
c0clk_cciclk_relationtbl,
ARRAY_SIZE(c0clk_cciclk_relationtbl));
register_slave_clock(clk, CLST1,
cci_memclk_pptbl[ARRAY_SIZE(cci_memclk_pptbl) - 1].rate,
c1clk_cciclk_relationtbl,
ARRAY_SIZE(c1clk_cciclk_relationtbl));
register_cci_notifier(pxa_unit->apmu_base, clk);
clst0_core_params.apmu_base = pxa_unit->apmu_base;
clst0_core_params.mpmu_base = pxa_unit->mpmu_base;
clst0_core_params.ciu_base = pxa_unit->ciu_base;
clst0_core_params.dciu_base = pxa_unit->dciu_base;
clst0_core_params.pxa_powermode = pxa1936_powermode;
mmp_clk_parents_lookup(clst0_core_params.parent_table,
clst0_core_params.parent_table_size);
clst1_core_params.apmu_base = pxa_unit->apmu_base;
clst1_core_params.mpmu_base = pxa_unit->mpmu_base;
clst1_core_params.ciu_base = pxa_unit->ciu_base;
clst1_core_params.dciu_base = pxa_unit->dciu_base;
clst1_core_params.pxa_powermode = pxa1936_powermode;
mmp_clk_parents_lookup(clst1_core_params.parent_table,
clst1_core_params.parent_table_size);
ddr_params.apmu_base = pxa_unit->apmu_base;
ddr_params.mpmu_base = pxa_unit->mpmu_base;
ddr_params.ddr_opt = lpddr533_op_array;
ddr_params.ddr_opt_size = ARRAY_SIZE(lpddr533_op_array);
if (ddr_mode == DDR_533M)
BUG_ON("mode DDR_533M is not supported now.\n");
if (ddr_mode == DDR_667M) {
ddr_params.ddr_opt = lpddr667_op_array;
ddr_params.ddr_opt_size = ARRAY_SIZE(lpddr667_op_array);
} else if (ddr_mode == DDR_800M) {
ddr_params.ddr_opt = lpddr800_op_array;
ddr_params.ddr_opt_size = ARRAY_SIZE(lpddr800_op_array);
} else if (ddr_mode == DDR_800M_2X) {
/* change DDR800 4x mode by default to 2x mode */
i = ARRAY_SIZE(lpddr800_op_array) - 1;
if (lpddr800_op_array[i].dclk == 797)
lpddr800_op_array[i].mode_4x_en = 0;
ddr_params.ddr_opt = lpddr800_op_array;
ddr_params.ddr_opt_size = ARRAY_SIZE(lpddr800_op_array);
}
mmp_clk_parents_lookup(ddr_params.parent_table,
ddr_params.parent_table_size);
axi_params.apmu_base = pxa_unit->apmu_base;
axi_params.mpmu_base = pxa_unit->mpmu_base;
axi_params.ciu_base = pxa_unit->ciu_base;
axi_params.axi_opt = axi_op_array;
axi_params.axi_opt_size = ARRAY_SIZE(axi_op_array);
mmp_clk_parents_lookup(axi_params.parent_table,
axi_params.parent_table_size);
clk = mmp_clk_register_core(CLST0_CORE_CLK_NAME,
(const char **)clst0_core_parent, ARRAY_SIZE(clst0_core_parent),
CLK_GET_RATE_NOCACHE, 0, &fc_seq_lock, &clst0_core_params);
clk_prepare_enable(clk);
mmp_clk_add(unit, PXA1936_CLK_CLST0, clk);
clk = mmp_clk_register_core(CLST1_CORE_CLK_NAME,
(const char **)clst1_core_parent, ARRAY_SIZE(clst1_core_parent),
CLK_GET_RATE_NOCACHE, 0, &fc_seq_lock, &clst1_core_params);
clk_prepare_enable(clk);
mmp_clk_add(unit, PXA1936_CLK_CLST1, clk);
clk = mmp_clk_register_ddr("ddr", (const char **)ddr_parent,
ARRAY_SIZE(ddr_parent), CLK_GET_RATE_NOCACHE,
0, &fc_seq_lock, &ddr_params);
mmp_clk_add(unit, PXA1936_CLK_DDR, clk);
clk_prepare_enable(clk);
clk = mmp_clk_register_axi("axi", (const char **)axi_parent,
ARRAY_SIZE(axi_parent), CLK_GET_RATE_NOCACHE,
0, &fc_seq_lock, &axi_params);
mmp_clk_add(unit, PXA1936_CLK_AXI, clk);
clk_prepare_enable(clk);
register_slave_clock(clk, DDR,
axi_params.axi_opt[axi_params.axi_opt_size - 1].aclk * MHZ,
dclk_aclk_relationtbl,
ARRAY_SIZE(dclk_aclk_relationtbl));
}
static void __init pxa1936_misc_init(struct pxa1936_clk_unit *pxa_unit)
{
unsigned int val;
/* enable all MCK and AXI fabric dynamic clk gating */
val = readl(pxa_unit->ciu_base + CIU_MC_CONF);
/* enable dclk gating */
val &= ~(1 << 19);
/* enable 1x2 fabric AXI clock dynamic gating */
val |= (0xff << 8) | /* MCK5 P0~P7*/
(1 << 16) | /* CP 2x1 fabric*/
(1 << 17) | (1 << 18) | /* AP&CP */
(1 << 20) | (1 << 21) | /* SP&CSAP 2x1 fabric */
(1 << 26) | (1 << 27) | /* Fabric 0/1 */
(1 << 29) | (1 << 30); /* CA7 2x1 fabric */
writel(val, pxa_unit->ciu_base + CIU_MC_CONF);
/* enable HW-DVC and HW-DFC when CP is fast wakeup */
val = readl(pxa_unit->apmu_base + APMU_DVC_DFC_DEBUG);
val |= (1 << 5);
writel(val, pxa_unit->apmu_base + APMU_DVC_DFC_DEBUG);
/* NOTE: not init GPU/VPU xtc here as we will set rate after register those clocks. */
}
/* unit is MHz */
static unsigned int __init pxa1936_round_max_freq(unsigned int freq)
{
if (freq <= CORE_1p25G)
return CORE_1p25G;
else if (freq <= CORE_1p5G)
return CORE_1p5G;
else if (freq <= CORE_1p8G)
return CORE_1p8G;
else
/* typical value we support */
return CORE_1p5G;
}
unsigned int ddr_800M_4x(void)
{
struct ddr_opt *ddr_op_array = lpddr800_op_array;
int i = ARRAY_SIZE(lpddr800_op_array) - 1;
if ((ddr_op_array[i].dclk == 797)
&& (ddr_op_array[i].mode_4x_en == 1))
return 1;
return 0;
}
static struct ddr_dfc_info ddrdfcinfo;
void find_ddr_level(struct ddr_opt *ddr_op_array)
{
int i;
ddrdfcinfo.ddr_idle = 0;
for (i = 0; i < sizeof(ddr_op_array); i++) {
if (ddrdfcinfo.ddr_active == 0) {
if (((ddr_op_array[i].mode_4x_en == 1)
&& (ddr_op_array[i].dclk > 312))
|| ((ddr_op_array[i].mode_4x_en == 0)
&& (ddr_op_array[i].dclk >= 312))) {
ddrdfcinfo.ddr_active = i;
}
}
if (ddrdfcinfo.ddr_high == 0) {
if (((ddr_op_array[i].mode_4x_en == 1)
&& (ddr_op_array[i].dclk >= 624))
|| ((ddr_op_array[i].mode_4x_en == 0)
&& (ddr_op_array[i].dclk >= 416))) {
ddrdfcinfo.ddr_high = i;
}
}
if (ddrdfcinfo.ddr_active && ddrdfcinfo.ddr_high)
break;
}
return;
}
void init_ddr_dfc(void)
{
memset(&ddrdfcinfo, 0, sizeof(ddrdfcinfo));
if (ddr_mode == DDR_533M)
find_ddr_level(lpddr533_op_array);
else if (ddr_mode == DDR_667M)
find_ddr_level(lpddr667_op_array);
else if (ddr_mode == DDR_800M || ddr_mode == DDR_800M_2X)
find_ddr_level(lpddr800_op_array);
return;
}
/*
* This interface will be used by different platform to fill CP ddr dfc info
*/
int fillddrdfcinfo(struct ddr_dfc_info *dfc_info)
{
if (!dfc_info)
return -EINVAL;
memcpy(&ddrdfcinfo, dfc_info, sizeof(struct ddr_dfc_info));
return 0;
}
/*
* This interface will be used by telephony to get CP ddr dfc info, and
* they will use ACIPC to pass the info to CP
*/
int getddrdfcinfo(struct ddr_dfc_info *dfc_info)
{
if (!dfc_info)
return -EINVAL;
memcpy(dfc_info, &ddrdfcinfo, sizeof(struct ddr_dfc_info));
return 0;
}
EXPORT_SYMBOL(getddrdfcinfo);
static void __init pxa1936_clk_init(struct device_node *np)
{
unsigned int max_freq_fused = CORE_1p5G, profile = 0;
struct pxa1936_clk_unit *pxa_unit;
pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
if (!pxa_unit) {
pr_err("failed to allocate memory for pxa1936 clock unit\n");
return;
}
pxa_unit->mpmu_base = of_iomap(np, 0);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map mpmu registers\n");
return;
}
pxa_unit->apmu_base = of_iomap(np, 1);
if (!pxa_unit->apmu_base) {
pr_err("failed to map apmu registers\n");
return;
}
pxa_unit->apbc_base = of_iomap(np, 2);
if (!pxa_unit->apbc_base) {
pr_err("failed to map apbc registers\n");
return;
}
pxa_unit->apbcp_base = of_iomap(np, 3);
if (!pxa_unit->apbcp_base) {
pr_err("failed to map apbcp registers\n");
return;
}
pxa_unit->apbs_base = of_iomap(np, 4);
if (!pxa_unit->apbs_base) {
pr_err("failed to map apbs registers\n");
return;
}
pxa_unit->ciu_base = of_iomap(np, 5);
if (!pxa_unit->ciu_base) {
pr_err("failed to map ciu registers\n");
return;
}
pxa_unit->dciu_base = of_iomap(np, 6);
if (!pxa_unit->dciu_base) {
pr_err("failed to map dragon ciu registers\n");
return;
}
pxa_unit->sc2desc_base = of_iomap(np, 7);
if (!pxa_unit->sc2desc_base) {
pr_err("failed to map sc2 mmu registers\n");
return;
}
/* init clock and ddr will use the dvfs_platinfo.
* make sure initialize dvfs_platinfo before clock and ddr init.
*/
#if defined(CONFIG_PXA_DVFS)
fill_ddr_800M_4x(ddr_800M_4x());
setup_pxa1936_dvfs_platinfo();
init_ddr_dfc();
/* get big cluster max freq */
max_freq_fused = get_helan3_max_freq();
max_freq_fused = pxa1936_round_max_freq(max_freq_fused);
clst1_core_params.max_cpurate = max_freq_fused;
profile = get_chipprofile();
if (get_helan3_svc_version() == SVC_1_11) {
if ((profile >= 13) && (ddr_mode == DDR_800M_2X) && (max_freq_fused < CORE_1p8G))
panic("<1.8GHz SKU chip Don't support DDR 800 2x mode when profile >= 13 , will panic.\n");
if ((profile >= 13) && (max_freq_fused <= CORE_1p5G)) {
clst0_core_params.max_cpurate = CORE_1p0G;
pr_info("<=1.5GHz SKU chip clst0 support max freq is 1057M when profile >= 13\n");
}
} else if (get_helan3_svc_version() == SEC_SVC_1_01) {
if ((profile >= 4) && (ddr_mode == DDR_800M_2X) && (max_freq_fused < CORE_1p8G))
panic("<1.8GHz SKU chip Don't support DDR 800 2x mode when profile >= 4 , will panic.\n");
if ((profile == 15) && (max_freq_fused <= CORE_1p5G)) {
clst0_core_params.max_cpurate = CORE_0p8G;
pr_info("<=1.5GHz SKU chip clst0 support max freq is 832M when profile == 15\n");
} else if ((profile >= 11) && (profile <= 14) && (max_freq_fused <= CORE_1p5G)) {
clst0_core_params.max_cpurate = CORE_1p0G;
pr_info("<=1.5GHz SKU chip clst0 support max freq is 1057M when profile == (11 ~ 14)\n");
}
} else if (get_helan3_svc_version() == SVC_TSMC_1p8G) {
if ((profile >= 13) && (ddr_mode == DDR_800M_2X))
panic("1.8GHz SKU chip Don't support DDR 800 2x mode when profile >= 13 , will panic.\n");
if (profile >= 12)
panic("1.8GHz SKU chip clst1 max freq doesn't support 1803M when profile >= 12\n");
} else if (get_helan3_svc_version() == SVC_TSMC_B0) {
pr_info("1.5GHz TSMC B0 chip clst0 support max freq is 1248M\n");
}
#endif
/* let uboot cmdline param have the final judge */
if (max_freq) {
max_freq = pxa1936_round_max_freq(max_freq);
if (max_freq < max_freq_fused)
clst1_core_params.max_cpurate = max_freq;
}
pr_info("little cluster max rate: %dMHz\n", clst0_core_params.max_cpurate);
pr_info("big cluster max rate: %dMHz\n", clst1_core_params.max_cpurate);
mmp_clk_init(np, &pxa_unit->unit, PXA1936_NR_CLKS);
pxa1936_misc_init(pxa_unit);
pxa1936_pll_init(pxa_unit);
pxa1936_acpu_init(pxa_unit);
pxa1936_apb_periph_clk_init(pxa_unit);
pxa1936_axi_periph_clk_init(pxa_unit);
#ifdef CONFIG_SMC91X
if (board_is_fpga())
smc91x_clk_init(pxa_unit->apmu_base);
#endif
#ifdef CONFIG_DEBUG_FS
globla_pxa_unit = pxa_unit;
#endif
}
CLK_OF_DECLARE(pxa1936_clk, "marvell,pxa1936-clock", pxa1936_clk_init);
#ifdef CONFIG_DEBUG_FS
static struct dentry *stat;
CLK_DCSTAT_OPS(globla_pxa_unit->unit.clk_table[PXA1936_CLK_DDR], ddr);
CLK_DCSTAT_OPS(globla_pxa_unit->unit.clk_table[PXA1936_CLK_AXI], axi);
CLK_DCSTAT_OPS(globla_pxa_unit->unit.clk_table[PXA1936_CLK_GC3D], gc);
CLK_DCSTAT_OPS(globla_pxa_unit->unit.clk_table[PXA1936_CLK_GC2D], gc2d);
CLK_DCSTAT_OPS(globla_pxa_unit->unit.clk_table[PXA1936_CLK_GCSH], gcsh);
CLK_DCSTAT_OPS(globla_pxa_unit->unit.clk_table[PXA1936_CLK_VPU], vpu);
static int __init __init_pxa1936_dcstat_debugfs_node(void)
{
struct dentry *cpu_dc_stat = NULL;
struct dentry *ddr_dc_stat = NULL, *axi_dc_stat = NULL;
struct dentry *gc_dc_stat = NULL, *vpu_dc_stat = NULL;
struct dentry *gc2d_dc_stat = NULL, *gcsh_dc_stat = NULL;
stat = debugfs_create_dir("stat", pxa);
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;
gc_dc_stat = clk_dcstat_file_create("gc3d_core0_dc_stat",
stat, &gc_dc_ops);
if (!gc_dc_stat)
goto err_gc_dc_stat;
gc2d_dc_stat = clk_dcstat_file_create("gc2d_core0_dc_stat",
stat, &gc2d_dc_ops);
if (!gc2d_dc_stat)
goto err_gc2d_dc_stat;
gcsh_dc_stat = clk_dcstat_file_create("gcsh_core0_dc_stat",
stat, &gcsh_dc_ops);
if (!gcsh_dc_stat)
goto err_gcshader_dc_stat;
vpu_dc_stat = clk_dcstat_file_create("vpu_dc_stat",
stat, &vpu_dc_ops);
if (!vpu_dc_stat)
goto err_vpu_dc_stat;
return 0;
err_vpu_dc_stat:
debugfs_remove(gcsh_dc_stat);
err_gcshader_dc_stat:
debugfs_remove(gc2d_dc_stat);
err_gc2d_dc_stat:
debugfs_remove(gc_dc_stat);
err_gc_dc_stat:
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;
}
/* clock init is before debugfs_create_dir("pxa", NULL), so
* use arch_initcall init the pxa1936 dcstat node.
*/
arch_initcall(__init_pxa1936_dcstat_debugfs_node);
#endif