Commit 2df2b82b authored by Stephen Boyd's avatar Stephen Boyd

Merge branches 'clk-qcom-rpm8974', 'clk-stm32f4', 'clk-ipq4019' and 'clk-fixes' into clk-next

* clk-qcom-rpm8974:
  clk: qcom: smd-rpmcc: Add msm8974 clocks

* clk-stm32f4:
  clk: stm32f4: SDIO & 48Mhz clock management for STM32F469 board
  clk: stm32f4: Add SAI clocks
  clk: stm32f4: Add I2S clock
  clk: stm32f4: Add lcd-tft clock
  clk: stm32f4: Add post divisor for I2S & SAI PLLs
  clk: stm32f4: Add PLL_I2S & PLL_SAI for STM32F429/469 boards
  clk: stm32f4: Update DT bindings documentation

* clk-ipq4019:
  clk: qcom: ipq4019: Add the cpu clock frequency change notifier
  clk: qcom: ipq4019: Add all the frequencies for apss cpu
  clk: qcom: ipq4019: correct sdcc frequency and parent name
  clk: qcom: ipq4019: Add the nodes for pcnoc
  clk: qcom: ipq4019: Add the apss cpu pll divider clock node
  clk: qcom: ipq4019: remove fixed clocks and add pll clocks

* clk-fixes:
  clk: stm32f4: Use CLK_OF_DECLARE_DRIVER initialization method
  clk: renesas: mstp: Support 8-bit registers for r7s72100
...@@ -11,6 +11,7 @@ Required properties : ...@@ -11,6 +11,7 @@ Required properties :
compatible "qcom,rpmcc" should be also included. compatible "qcom,rpmcc" should be also included.
"qcom,rpmcc-msm8916", "qcom,rpmcc" "qcom,rpmcc-msm8916", "qcom,rpmcc"
"qcom,rpmcc-msm8974", "qcom,rpmcc"
"qcom,rpmcc-apq8064", "qcom,rpmcc" "qcom,rpmcc-apq8064", "qcom,rpmcc"
- #clock-cells : shall contain 1 - #clock-cells : shall contain 1
......
...@@ -17,6 +17,9 @@ Required properties: ...@@ -17,6 +17,9 @@ Required properties:
property, containing a phandle to the clock device node, an index selecting property, containing a phandle to the clock device node, an index selecting
between gated clocks and other clocks and an index specifying the clock to between gated clocks and other clocks and an index specifying the clock to
use. use.
- clocks: External oscillator clock phandle
- high speed external clock signal (HSE)
- external I2S clock (I2S_CKIN)
Example: Example:
...@@ -25,6 +28,7 @@ Example: ...@@ -25,6 +28,7 @@ Example:
#clock-cells = <2> #clock-cells = <2>
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>; reg = <0x40023800 0x400>;
clocks = <&clk_hse>, <&clk_i2s_ckin>;
}; };
Specifying gated clocks Specifying gated clocks
...@@ -66,6 +70,19 @@ The secondary index is bound with the following magic numbers: ...@@ -66,6 +70,19 @@ The secondary index is bound with the following magic numbers:
0 SYSTICK 0 SYSTICK
1 FCLK 1 FCLK
2 CLK_LSI (low-power clock source)
3 CLK_LSE (generated from a 32.768 kHz low-speed external
crystal or ceramic resonator)
4 CLK_HSE_RTC (HSE division factor for RTC clock)
5 CLK_RTC (real-time clock)
6 PLL_VCO_I2S (vco frequency of I2S pll)
7 PLL_VCO_SAI (vco frequency of SAI pll)
8 CLK_LCD (LCD-TFT)
9 CLK_I2S (I2S clocks)
10 CLK_SAI1 (audio clocks)
11 CLK_SAI2
12 CLK_I2SQ_PDIV (post divisor of pll i2s q divisor)
13 CLK_SAIQ_PDIV (post divisor of pll sai q divisor)
Example: Example:
......
...@@ -28,6 +28,14 @@ ...@@ -28,6 +28,14 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
/*
* Include list of clocks wich are not derived from system clock (SYSCLOCK)
* The index of these clocks is the secondary index of DT bindings
*
*/
#include <dt-bindings/clock/stm32fx-clock.h>
#define STM32F4_RCC_CR 0x00
#define STM32F4_RCC_PLLCFGR 0x04 #define STM32F4_RCC_PLLCFGR 0x04
#define STM32F4_RCC_CFGR 0x08 #define STM32F4_RCC_CFGR 0x08
#define STM32F4_RCC_AHB1ENR 0x30 #define STM32F4_RCC_AHB1ENR 0x30
...@@ -37,6 +45,14 @@ ...@@ -37,6 +45,14 @@
#define STM32F4_RCC_APB2ENR 0x44 #define STM32F4_RCC_APB2ENR 0x44
#define STM32F4_RCC_BDCR 0x70 #define STM32F4_RCC_BDCR 0x70
#define STM32F4_RCC_CSR 0x74 #define STM32F4_RCC_CSR 0x74
#define STM32F4_RCC_PLLI2SCFGR 0x84
#define STM32F4_RCC_PLLSAICFGR 0x88
#define STM32F4_RCC_DCKCFGR 0x8c
#define NONE -1
#define NO_IDX NONE
#define NO_MUX NONE
#define NO_GATE NONE
struct stm32f4_gate_data { struct stm32f4_gate_data {
u8 offset; u8 offset;
...@@ -195,7 +211,7 @@ static const struct stm32f4_gate_data stm32f469_gates[] __initconst = { ...@@ -195,7 +211,7 @@ static const struct stm32f4_gate_data stm32f469_gates[] __initconst = {
{ STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" }, { STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" }, { STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" }, { STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 11, "sdio", "pll48" }, { STM32F4_RCC_APB2ENR, 11, "sdio", "sdmux" },
{ STM32F4_RCC_APB2ENR, 12, "spi1", "apb2_div" }, { STM32F4_RCC_APB2ENR, 12, "spi1", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 13, "spi4", "apb2_div" }, { STM32F4_RCC_APB2ENR, 13, "spi4", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 14, "syscfg", "apb2_div" }, { STM32F4_RCC_APB2ENR, 14, "syscfg", "apb2_div" },
...@@ -208,8 +224,6 @@ static const struct stm32f4_gate_data stm32f469_gates[] __initconst = { ...@@ -208,8 +224,6 @@ static const struct stm32f4_gate_data stm32f469_gates[] __initconst = {
{ STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" },
}; };
enum { SYSTICK, FCLK, CLK_LSI, CLK_LSE, CLK_HSE_RTC, CLK_RTC, END_PRIMARY_CLK };
/* /*
* This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
* have gate bits associated with them. Its combined hweight is 71. * have gate bits associated with them. Its combined hweight is 71.
...@@ -324,23 +338,342 @@ static struct clk *clk_register_apb_mul(struct device *dev, const char *name, ...@@ -324,23 +338,342 @@ static struct clk *clk_register_apb_mul(struct device *dev, const char *name,
return clk; return clk;
} }
/* enum {
* Decode current PLL state and (statically) model the state we inherit from PLL,
* the bootloader. PLL_I2S,
*/ PLL_SAI,
static void stm32f4_rcc_register_pll(const char *hse_clk, const char *hsi_clk) };
static const struct clk_div_table pll_divp_table[] = {
{ 0, 2 }, { 1, 4 }, { 2, 6 }, { 3, 8 }, { 0 }
};
static const struct clk_div_table pll_divr_table[] = {
{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 0 }
};
struct stm32f4_pll {
spinlock_t *lock;
struct clk_gate gate;
u8 offset;
u8 bit_rdy_idx;
u8 status;
u8 n_start;
};
#define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate)
struct stm32f4_pll_post_div_data {
int idx;
u8 pll_num;
const char *name;
const char *parent;
u8 flag;
u8 offset;
u8 shift;
u8 width;
u8 flag_div;
const struct clk_div_table *div_table;
};
struct stm32f4_vco_data {
const char *vco_name;
u8 offset;
u8 bit_idx;
u8 bit_rdy_idx;
};
static const struct stm32f4_vco_data vco_data[] = {
{ "vco", STM32F4_RCC_PLLCFGR, 24, 25 },
{ "vco-i2s", STM32F4_RCC_PLLI2SCFGR, 26, 27 },
{ "vco-sai", STM32F4_RCC_PLLSAICFGR, 28, 29 },
};
static const struct clk_div_table post_divr_table[] = {
{ 0, 2 }, { 1, 4 }, { 2, 8 }, { 3, 16 }, { 0 }
};
#define MAX_POST_DIV 3
static const struct stm32f4_pll_post_div_data post_div_data[MAX_POST_DIV] = {
{ CLK_I2SQ_PDIV, PLL_I2S, "plli2s-q-div", "plli2s-q",
CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 0, 5, 0, NULL},
{ CLK_SAIQ_PDIV, PLL_SAI, "pllsai-q-div", "pllsai-q",
CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 8, 5, 0, NULL },
{ NO_IDX, PLL_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
STM32F4_RCC_DCKCFGR, 16, 2, 0, post_divr_table },
};
struct stm32f4_div_data {
u8 shift;
u8 width;
u8 flag_div;
const struct clk_div_table *div_table;
};
#define MAX_PLL_DIV 3
static const struct stm32f4_div_data div_data[MAX_PLL_DIV] = {
{ 16, 2, 0, pll_divp_table },
{ 24, 4, CLK_DIVIDER_ONE_BASED, NULL },
{ 28, 3, 0, pll_divr_table },
};
struct stm32f4_pll_data {
u8 pll_num;
u8 n_start;
const char *div_name[MAX_PLL_DIV];
};
static const struct stm32f4_pll_data stm32f429_pll[MAX_PLL_DIV] = {
{ PLL, 192, { "pll", "pll48", NULL } },
{ PLL_I2S, 192, { NULL, "plli2s-q", "plli2s-r" } },
{ PLL_SAI, 49, { NULL, "pllsai-q", "pllsai-r" } },
};
static const struct stm32f4_pll_data stm32f469_pll[MAX_PLL_DIV] = {
{ PLL, 50, { "pll", "pll-q", NULL } },
{ PLL_I2S, 50, { "plli2s-p", "plli2s-q", "plli2s-r" } },
{ PLL_SAI, 50, { "pllsai-p", "pllsai-q", "pllsai-r" } },
};
static int stm32f4_pll_is_enabled(struct clk_hw *hw)
{
return clk_gate_ops.is_enabled(hw);
}
static int stm32f4_pll_enable(struct clk_hw *hw)
{
struct clk_gate *gate = to_clk_gate(hw);
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
int ret = 0;
unsigned long reg;
ret = clk_gate_ops.enable(hw);
ret = readl_relaxed_poll_timeout_atomic(base + STM32F4_RCC_CR, reg,
reg & (1 << pll->bit_rdy_idx), 0, 10000);
return ret;
}
static void stm32f4_pll_disable(struct clk_hw *hw)
{
clk_gate_ops.disable(hw);
}
static unsigned long stm32f4_pll_recalc(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_gate *gate = to_clk_gate(hw);
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
unsigned long n;
n = (readl(base + pll->offset) >> 6) & 0x1ff;
return parent_rate * n;
}
static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_gate *gate = to_clk_gate(hw);
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
unsigned long n;
n = rate / *prate;
if (n < pll->n_start)
n = pll->n_start;
else if (n > 432)
n = 432;
return *prate * n;
}
static int stm32f4_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_gate *gate = to_clk_gate(hw);
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
unsigned long n;
unsigned long val;
int pll_state;
pll_state = stm32f4_pll_is_enabled(hw);
if (pll_state)
stm32f4_pll_disable(hw);
n = rate / parent_rate;
val = readl(base + pll->offset) & ~(0x1ff << 6);
writel(val | ((n & 0x1ff) << 6), base + pll->offset);
if (pll_state)
stm32f4_pll_enable(hw);
return 0;
}
static const struct clk_ops stm32f4_pll_gate_ops = {
.enable = stm32f4_pll_enable,
.disable = stm32f4_pll_disable,
.is_enabled = stm32f4_pll_is_enabled,
.recalc_rate = stm32f4_pll_recalc,
.round_rate = stm32f4_pll_round_rate,
.set_rate = stm32f4_pll_set_rate,
};
struct stm32f4_pll_div {
struct clk_divider div;
struct clk_hw *hw_pll;
};
#define to_pll_div_clk(_div) container_of(_div, struct stm32f4_pll_div, div)
static unsigned long stm32f4_pll_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return clk_divider_ops.recalc_rate(hw, parent_rate);
}
static long stm32f4_pll_div_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_divider_ops.round_rate(hw, rate, prate);
}
static int stm32f4_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{ {
unsigned long pllcfgr = readl(base + STM32F4_RCC_PLLCFGR); int pll_state, ret;
struct clk_divider *div = to_clk_divider(hw);
struct stm32f4_pll_div *pll_div = to_pll_div_clk(div);
pll_state = stm32f4_pll_is_enabled(pll_div->hw_pll);
if (pll_state)
stm32f4_pll_disable(pll_div->hw_pll);
ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
unsigned long pllm = pllcfgr & 0x3f; if (pll_state)
unsigned long plln = (pllcfgr >> 6) & 0x1ff; stm32f4_pll_enable(pll_div->hw_pll);
unsigned long pllp = BIT(((pllcfgr >> 16) & 3) + 1);
const char *pllsrc = pllcfgr & BIT(22) ? hse_clk : hsi_clk;
unsigned long pllq = (pllcfgr >> 24) & 0xf;
clk_register_fixed_factor(NULL, "vco", pllsrc, 0, plln, pllm); return ret;
clk_register_fixed_factor(NULL, "pll", "vco", 0, 1, pllp); }
clk_register_fixed_factor(NULL, "pll48", "vco", 0, 1, pllq);
static const struct clk_ops stm32f4_pll_div_ops = {
.recalc_rate = stm32f4_pll_div_recalc_rate,
.round_rate = stm32f4_pll_div_round_rate,
.set_rate = stm32f4_pll_div_set_rate,
};
static struct clk_hw *clk_register_pll_div(const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
struct clk_hw *pll_hw, spinlock_t *lock)
{
struct stm32f4_pll_div *pll_div;
struct clk_hw *hw;
struct clk_init_data init;
int ret;
/* allocate the divider */
pll_div = kzalloc(sizeof(*pll_div), GFP_KERNEL);
if (!pll_div)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &stm32f4_pll_div_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
/* struct clk_divider assignments */
pll_div->div.reg = reg;
pll_div->div.shift = shift;
pll_div->div.width = width;
pll_div->div.flags = clk_divider_flags;
pll_div->div.lock = lock;
pll_div->div.table = table;
pll_div->div.hw.init = &init;
pll_div->hw_pll = pll_hw;
/* register the clock */
hw = &pll_div->div.hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(pll_div);
hw = ERR_PTR(ret);
}
return hw;
}
static struct clk_hw *stm32f4_rcc_register_pll(const char *pllsrc,
const struct stm32f4_pll_data *data, spinlock_t *lock)
{
struct stm32f4_pll *pll;
struct clk_init_data init = { NULL };
void __iomem *reg;
struct clk_hw *pll_hw;
int ret;
int i;
const struct stm32f4_vco_data *vco;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
vco = &vco_data[data->pll_num];
init.name = vco->vco_name;
init.ops = &stm32f4_pll_gate_ops;
init.flags = CLK_SET_RATE_GATE;
init.parent_names = &pllsrc;
init.num_parents = 1;
pll->gate.lock = lock;
pll->gate.reg = base + STM32F4_RCC_CR;
pll->gate.bit_idx = vco->bit_idx;
pll->gate.hw.init = &init;
pll->offset = vco->offset;
pll->n_start = data->n_start;
pll->bit_rdy_idx = vco->bit_rdy_idx;
pll->status = (readl(base + STM32F4_RCC_CR) >> vco->bit_idx) & 0x1;
reg = base + pll->offset;
pll_hw = &pll->gate.hw;
ret = clk_hw_register(NULL, pll_hw);
if (ret) {
kfree(pll);
return ERR_PTR(ret);
}
for (i = 0; i < MAX_PLL_DIV; i++)
if (data->div_name[i])
clk_register_pll_div(data->div_name[i],
vco->vco_name,
0,
reg,
div_data[i].shift,
div_data[i].width,
div_data[i].flag_div,
div_data[i].div_table,
pll_hw,
lock);
return pll_hw;
} }
/* /*
...@@ -611,22 +944,121 @@ static const char *rtc_parents[4] = { ...@@ -611,22 +944,121 @@ static const char *rtc_parents[4] = {
"no-clock", "lse", "lsi", "hse-rtc" "no-clock", "lse", "lsi", "hse-rtc"
}; };
static const char *lcd_parent[1] = { "pllsai-r-div" };
static const char *i2s_parents[2] = { "plli2s-r", NULL };
static const char *sai_parents[4] = { "pllsai-q-div", "plli2s-q-div", NULL,
"no-clock" };
static const char *pll48_parents[2] = { "pll-q", "pllsai-p" };
static const char *sdmux_parents[2] = { "pll48", "sys" };
struct stm32_aux_clk {
int idx;
const char *name;
const char * const *parent_names;
int num_parents;
int offset_mux;
u8 shift;
u8 mask;
int offset_gate;
u8 bit_idx;
unsigned long flags;
};
struct stm32f4_clk_data { struct stm32f4_clk_data {
const struct stm32f4_gate_data *gates_data; const struct stm32f4_gate_data *gates_data;
const u64 *gates_map; const u64 *gates_map;
int gates_num; int gates_num;
const struct stm32f4_pll_data *pll_data;
const struct stm32_aux_clk *aux_clk;
int aux_clk_num;
};
static const struct stm32_aux_clk stm32f429_aux_clk[] = {
{
CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
NO_MUX, 0, 0,
STM32F4_RCC_APB2ENR, 26,
CLK_SET_RATE_PARENT
},
{
CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
STM32F4_RCC_CFGR, 23, 1,
NO_GATE, 0,
CLK_SET_RATE_PARENT
},
{
CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
STM32F4_RCC_DCKCFGR, 20, 3,
STM32F4_RCC_APB2ENR, 22,
CLK_SET_RATE_PARENT
},
{
CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
STM32F4_RCC_DCKCFGR, 22, 3,
STM32F4_RCC_APB2ENR, 22,
CLK_SET_RATE_PARENT
},
};
static const struct stm32_aux_clk stm32f469_aux_clk[] = {
{
CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
NO_MUX, 0, 0,
STM32F4_RCC_APB2ENR, 26,
CLK_SET_RATE_PARENT
},
{
CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
STM32F4_RCC_CFGR, 23, 1,
NO_GATE, 0,
CLK_SET_RATE_PARENT
},
{
CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
STM32F4_RCC_DCKCFGR, 20, 3,
STM32F4_RCC_APB2ENR, 22,
CLK_SET_RATE_PARENT
},
{
CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
STM32F4_RCC_DCKCFGR, 22, 3,
STM32F4_RCC_APB2ENR, 22,
CLK_SET_RATE_PARENT
},
{
NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
STM32F4_RCC_DCKCFGR, 27, 1,
NO_GATE, 0,
0
},
{
NO_IDX, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents),
STM32F4_RCC_DCKCFGR, 28, 1,
NO_GATE, 0,
0
},
}; };
static const struct stm32f4_clk_data stm32f429_clk_data = { static const struct stm32f4_clk_data stm32f429_clk_data = {
.gates_data = stm32f429_gates, .gates_data = stm32f429_gates,
.gates_map = stm32f42xx_gate_map, .gates_map = stm32f42xx_gate_map,
.gates_num = ARRAY_SIZE(stm32f429_gates), .gates_num = ARRAY_SIZE(stm32f429_gates),
.pll_data = stm32f429_pll,
.aux_clk = stm32f429_aux_clk,
.aux_clk_num = ARRAY_SIZE(stm32f429_aux_clk),
}; };
static const struct stm32f4_clk_data stm32f469_clk_data = { static const struct stm32f4_clk_data stm32f469_clk_data = {
.gates_data = stm32f469_gates, .gates_data = stm32f469_gates,
.gates_map = stm32f46xx_gate_map, .gates_map = stm32f46xx_gate_map,
.gates_num = ARRAY_SIZE(stm32f469_gates), .gates_num = ARRAY_SIZE(stm32f469_gates),
.pll_data = stm32f469_pll,
.aux_clk = stm32f469_aux_clk,
.aux_clk_num = ARRAY_SIZE(stm32f469_aux_clk),
}; };
static const struct of_device_id stm32f4_of_match[] = { static const struct of_device_id stm32f4_of_match[] = {
...@@ -641,12 +1073,75 @@ static const struct of_device_id stm32f4_of_match[] = { ...@@ -641,12 +1073,75 @@ static const struct of_device_id stm32f4_of_match[] = {
{} {}
}; };
static struct clk_hw *stm32_register_aux_clk(const char *name,
const char * const *parent_names, int num_parents,
int offset_mux, u8 shift, u8 mask,
int offset_gate, u8 bit_idx,
unsigned long flags, spinlock_t *lock)
{
struct clk_hw *hw;
struct clk_gate *gate;
struct clk_mux *mux = NULL;
struct clk_hw *mux_hw = NULL, *gate_hw = NULL;
const struct clk_ops *mux_ops = NULL, *gate_ops = NULL;
if (offset_gate != NO_GATE) {
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) {
hw = ERR_PTR(-EINVAL);
goto fail;
}
gate->reg = base + offset_gate;
gate->bit_idx = bit_idx;
gate->flags = 0;
gate->lock = lock;
gate_hw = &gate->hw;
gate_ops = &clk_gate_ops;
}
if (offset_mux != NO_MUX) {
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux) {
kfree(gate);
hw = ERR_PTR(-EINVAL);
goto fail;
}
mux->reg = base + offset_mux;
mux->shift = shift;
mux->mask = mask;
mux->flags = 0;
mux_hw = &mux->hw;
mux_ops = &clk_mux_ops;
}
if (mux_hw == NULL && gate_hw == NULL)
return ERR_PTR(-EINVAL);
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, mux_ops,
NULL, NULL,
gate_hw, gate_ops,
flags);
if (IS_ERR(hw)) {
kfree(gate);
kfree(mux);
}
fail:
return hw;
}
static void __init stm32f4_rcc_init(struct device_node *np) static void __init stm32f4_rcc_init(struct device_node *np)
{ {
const char *hse_clk; const char *hse_clk, *i2s_in_clk;
int n; int n;
const struct of_device_id *match; const struct of_device_id *match;
const struct stm32f4_clk_data *data; const struct stm32f4_clk_data *data;
unsigned long pllcfgr;
const char *pllsrc;
unsigned long pllm;
base = of_iomap(np, 0); base = of_iomap(np, 0);
if (!base) { if (!base) {
...@@ -675,9 +1170,49 @@ static void __init stm32f4_rcc_init(struct device_node *np) ...@@ -675,9 +1170,49 @@ static void __init stm32f4_rcc_init(struct device_node *np)
hse_clk = of_clk_get_parent_name(np, 0); hse_clk = of_clk_get_parent_name(np, 0);
i2s_in_clk = of_clk_get_parent_name(np, 1);
i2s_parents[1] = i2s_in_clk;
sai_parents[2] = i2s_in_clk;
clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0, clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
16000000, 160000); 16000000, 160000);
stm32f4_rcc_register_pll(hse_clk, "hsi"); pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
pllsrc = pllcfgr & BIT(22) ? hse_clk : "hsi";
pllm = pllcfgr & 0x3f;
clk_hw_register_fixed_factor(NULL, "vco_in", pllsrc,
0, 1, pllm);
stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],
&stm32f4_clk_lock);
clks[PLL_VCO_I2S] = stm32f4_rcc_register_pll("vco_in",
&data->pll_data[1], &stm32f4_clk_lock);
clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in",
&data->pll_data[2], &stm32f4_clk_lock);
for (n = 0; n < MAX_POST_DIV; n++) {
const struct stm32f4_pll_post_div_data *post_div;
struct clk_hw *hw;
post_div = &post_div_data[n];
hw = clk_register_pll_div(post_div->name,
post_div->parent,
post_div->flag,
base + post_div->offset,
post_div->shift,
post_div->width,
post_div->flag_div,
post_div->div_table,
clks[post_div->pll_num],
&stm32f4_clk_lock);
if (post_div->idx != NO_IDX)
clks[post_div->idx] = hw;
}
sys_parents[1] = hse_clk; sys_parents[1] = hse_clk;
clk_register_mux_table( clk_register_mux_table(
...@@ -762,11 +1297,33 @@ static void __init stm32f4_rcc_init(struct device_node *np) ...@@ -762,11 +1297,33 @@ static void __init stm32f4_rcc_init(struct device_node *np)
goto fail; goto fail;
} }
for (n = 0; n < data->aux_clk_num; n++) {
const struct stm32_aux_clk *aux_clk;
struct clk_hw *hw;
aux_clk = &data->aux_clk[n];
hw = stm32_register_aux_clk(aux_clk->name,
aux_clk->parent_names, aux_clk->num_parents,
aux_clk->offset_mux, aux_clk->shift,
aux_clk->mask, aux_clk->offset_gate,
aux_clk->bit_idx, aux_clk->flags,
&stm32f4_clk_lock);
if (IS_ERR(hw)) {
pr_warn("Unable to register %s clk\n", aux_clk->name);
continue;
}
if (aux_clk->idx != NO_IDX)
clks[aux_clk->idx] = hw;
}
of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL); of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);
return; return;
fail: fail:
kfree(clks); kfree(clks);
iounmap(base); iounmap(base);
} }
CLK_OF_DECLARE(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); CLK_OF_DECLARE_DRIVER(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init);
CLK_OF_DECLARE(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); CLK_OF_DECLARE_DRIVER(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init);
...@@ -462,8 +462,79 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = { ...@@ -462,8 +462,79 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
.num_clks = ARRAY_SIZE(msm8916_clks), .num_clks = ARRAY_SIZE(msm8916_clks),
}; };
/* msm8974 */
DEFINE_CLK_SMD_RPM(msm8974, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8974, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8974, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
DEFINE_CLK_SMD_RPM(msm8974, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3);
DEFINE_CLK_SMD_RPM(msm8974, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8974, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8974, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
DEFINE_CLK_SMD_RPM_QDSS(msm8974, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d0, cxo_d0_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d1, cxo_d1_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a0, cxo_a0_a, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a1, cxo_a1_a, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a2, cxo_a2_a, 6);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, diff_clk, diff_a_clk, 7);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk1, div_a_clk1, 11);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk2, div_a_clk2, 12);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d0_pin, cxo_d0_a_pin, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d1_pin, cxo_d1_a_pin, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a0_pin, cxo_a0_a_pin, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a1_pin, cxo_a1_a_pin, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a2_pin, cxo_a2_a_pin, 6);
static struct clk_smd_rpm *msm8974_clks[] = {
[RPM_SMD_PNOC_CLK] = &msm8974_pnoc_clk,
[RPM_SMD_PNOC_A_CLK] = &msm8974_pnoc_a_clk,
[RPM_SMD_SNOC_CLK] = &msm8974_snoc_clk,
[RPM_SMD_SNOC_A_CLK] = &msm8974_snoc_a_clk,
[RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
[RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
[RPM_SMD_MMSSNOC_AHB_CLK] = &msm8974_mmssnoc_ahb_clk,
[RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
[RPM_SMD_BIMC_CLK] = &msm8974_bimc_clk,
[RPM_SMD_BIMC_A_CLK] = &msm8974_bimc_a_clk,
[RPM_SMD_OCMEMGX_CLK] = &msm8974_ocmemgx_clk,
[RPM_SMD_OCMEMGX_A_CLK] = &msm8974_ocmemgx_a_clk,
[RPM_SMD_QDSS_CLK] = &msm8974_qdss_clk,
[RPM_SMD_QDSS_A_CLK] = &msm8974_qdss_a_clk,
[RPM_SMD_CXO_D0] = &msm8974_cxo_d0,
[RPM_SMD_CXO_D0_A] = &msm8974_cxo_d0_a,
[RPM_SMD_CXO_D1] = &msm8974_cxo_d1,
[RPM_SMD_CXO_D1_A] = &msm8974_cxo_d1_a,
[RPM_SMD_CXO_A0] = &msm8974_cxo_a0,
[RPM_SMD_CXO_A0_A] = &msm8974_cxo_a0_a,
[RPM_SMD_CXO_A1] = &msm8974_cxo_a1,
[RPM_SMD_CXO_A1_A] = &msm8974_cxo_a1_a,
[RPM_SMD_CXO_A2] = &msm8974_cxo_a2,
[RPM_SMD_CXO_A2_A] = &msm8974_cxo_a2_a,
[RPM_SMD_DIFF_CLK] = &msm8974_diff_clk,
[RPM_SMD_DIFF_A_CLK] = &msm8974_diff_a_clk,
[RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
[RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
[RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
[RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
[RPM_SMD_CXO_D0_PIN] = &msm8974_cxo_d0_pin,
[RPM_SMD_CXO_D0_A_PIN] = &msm8974_cxo_d0_a_pin,
[RPM_SMD_CXO_D1_PIN] = &msm8974_cxo_d1_pin,
[RPM_SMD_CXO_D1_A_PIN] = &msm8974_cxo_d1_a_pin,
[RPM_SMD_CXO_A0_PIN] = &msm8974_cxo_a0_pin,
[RPM_SMD_CXO_A0_A_PIN] = &msm8974_cxo_a0_a_pin,
[RPM_SMD_CXO_A1_PIN] = &msm8974_cxo_a1_pin,
[RPM_SMD_CXO_A1_A_PIN] = &msm8974_cxo_a1_a_pin,
[RPM_SMD_CXO_A2_PIN] = &msm8974_cxo_a2_pin,
[RPM_SMD_CXO_A2_A_PIN] = &msm8974_cxo_a2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8974 = {
.clks = msm8974_clks,
.num_clks = ARRAY_SIZE(msm8974_clks),
};
static const struct of_device_id rpm_smd_clk_match_table[] = { static const struct of_device_id rpm_smd_clk_match_table[] = {
{ .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 },
{ .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table); MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table);
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/math64.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <dt-bindings/clock/qcom,gcc-ipq4019.h> #include <dt-bindings/clock/qcom,gcc-ipq4019.h>
...@@ -28,6 +31,13 @@ ...@@ -28,6 +31,13 @@
#include "clk-rcg.h" #include "clk-rcg.h"
#include "clk-branch.h" #include "clk-branch.h"
#include "reset.h" #include "reset.h"
#include "clk-regmap-divider.h"
#define to_clk_regmap_div(_hw) container_of(to_clk_regmap(_hw),\
struct clk_regmap_div, clkr)
#define to_clk_fepll(_hw) container_of(to_clk_regmap_div(_hw),\
struct clk_fepll, cdiv)
enum { enum {
P_XO, P_XO,
...@@ -40,6 +50,41 @@ enum { ...@@ -40,6 +50,41 @@ enum {
P_DDRPLLAPSS, P_DDRPLLAPSS,
}; };
/*
* struct clk_fepll_vco - vco feedback divider corresponds for FEPLL clocks
* @fdbkdiv_shift: lowest bit for FDBKDIV
* @fdbkdiv_width: number of bits in FDBKDIV
* @refclkdiv_shift: lowest bit for REFCLKDIV
* @refclkdiv_width: number of bits in REFCLKDIV
* @reg: PLL_DIV register address
*/
struct clk_fepll_vco {
u32 fdbkdiv_shift;
u32 fdbkdiv_width;
u32 refclkdiv_shift;
u32 refclkdiv_width;
u32 reg;
};
/*
* struct clk_fepll - clk divider corresponds to FEPLL clocks
* @fixed_div: fixed divider value if divider is fixed
* @parent_map: map from software's parent index to hardware's src_sel field
* @cdiv: divider values for PLL_DIV
* @pll_vco: vco feedback divider
* @div_table: mapping for actual divider value to register divider value
* in case of non fixed divider
* @freq_tbl: frequency table
*/
struct clk_fepll {
u32 fixed_div;
const u8 *parent_map;
struct clk_regmap_div cdiv;
const struct clk_fepll_vco *pll_vco;
const struct clk_div_table *div_table;
const struct freq_tbl *freq_tbl;
};
static struct parent_map gcc_xo_200_500_map[] = { static struct parent_map gcc_xo_200_500_map[] = {
{ P_XO, 0 }, { P_XO, 0 },
{ P_FEPLL200, 1 }, { P_FEPLL200, 1 },
...@@ -80,7 +125,7 @@ static struct parent_map gcc_xo_sdcc1_500_map[] = { ...@@ -80,7 +125,7 @@ static struct parent_map gcc_xo_sdcc1_500_map[] = {
static const char * const gcc_xo_sdcc1_500[] = { static const char * const gcc_xo_sdcc1_500[] = {
"xo", "xo",
"ddrpll", "ddrpllsdcc",
"fepll500", "fepll500",
}; };
...@@ -121,6 +166,12 @@ static struct parent_map gcc_xo_ddr_500_200_map[] = { ...@@ -121,6 +166,12 @@ static struct parent_map gcc_xo_ddr_500_200_map[] = {
{ P_DDRPLLAPSS, 1 }, { P_DDRPLLAPSS, 1 },
}; };
/*
* Contains index for safe clock during APSS freq change.
* fepll500 is being used as safe clock so initialize it
* with its index in parents list gcc_xo_ddr_500_200.
*/
static const int gcc_ipq4019_cpu_safe_parent = 2;
static const char * const gcc_xo_ddr_500_200[] = { static const char * const gcc_xo_ddr_500_200[] = {
"xo", "xo",
"fepll200", "fepll200",
...@@ -505,7 +556,7 @@ static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = { ...@@ -505,7 +556,7 @@ static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = {
F(25000000, P_FEPLL500, 1, 1, 20), F(25000000, P_FEPLL500, 1, 1, 20),
F(50000000, P_FEPLL500, 1, 1, 10), F(50000000, P_FEPLL500, 1, 1, 10),
F(100000000, P_FEPLL500, 1, 1, 5), F(100000000, P_FEPLL500, 1, 1, 5),
F(193000000, P_DDRPLL, 1, 0, 0), F(192000000, P_DDRPLL, 1, 0, 0),
{ } { }
}; };
...@@ -524,10 +575,20 @@ static struct clk_rcg2 sdcc1_apps_clk_src = { ...@@ -524,10 +575,20 @@ static struct clk_rcg2 sdcc1_apps_clk_src = {
}; };
static const struct freq_tbl ftbl_gcc_apps_clk[] = { static const struct freq_tbl ftbl_gcc_apps_clk[] = {
F(48000000, P_XO, 1, 0, 0), F(48000000, P_XO, 1, 0, 0),
F(200000000, P_FEPLL200, 1, 0, 0), F(200000000, P_FEPLL200, 1, 0, 0),
F(384000000, P_DDRPLLAPSS, 1, 0, 0),
F(413000000, P_DDRPLLAPSS, 1, 0, 0),
F(448000000, P_DDRPLLAPSS, 1, 0, 0),
F(488000000, P_DDRPLLAPSS, 1, 0, 0),
F(500000000, P_FEPLL500, 1, 0, 0), F(500000000, P_FEPLL500, 1, 0, 0),
F(626000000, P_DDRPLLAPSS, 1, 0, 0), F(512000000, P_DDRPLLAPSS, 1, 0, 0),
F(537000000, P_DDRPLLAPSS, 1, 0, 0),
F(565000000, P_DDRPLLAPSS, 1, 0, 0),
F(597000000, P_DDRPLLAPSS, 1, 0, 0),
F(632000000, P_DDRPLLAPSS, 1, 0, 0),
F(672000000, P_DDRPLLAPSS, 1, 0, 0),
F(716000000, P_DDRPLLAPSS, 1, 0, 0),
{ } { }
}; };
...@@ -541,6 +602,7 @@ static struct clk_rcg2 apps_clk_src = { ...@@ -541,6 +602,7 @@ static struct clk_rcg2 apps_clk_src = {
.parent_names = gcc_xo_ddr_500_200, .parent_names = gcc_xo_ddr_500_200,
.num_parents = 4, .num_parents = 4,
.ops = &clk_rcg2_ops, .ops = &clk_rcg2_ops,
.flags = CLK_SET_RATE_PARENT,
}, },
}; };
...@@ -1154,6 +1216,364 @@ static struct clk_branch gcc_wcss5g_rtc_clk = { ...@@ -1154,6 +1216,364 @@ static struct clk_branch gcc_wcss5g_rtc_clk = {
}, },
}; };
/* Calculates the VCO rate for FEPLL. */
static u64 clk_fepll_vco_calc_rate(struct clk_fepll *pll_div,
unsigned long parent_rate)
{
const struct clk_fepll_vco *pll_vco = pll_div->pll_vco;
u32 fdbkdiv, refclkdiv, cdiv;
u64 vco;
regmap_read(pll_div->cdiv.clkr.regmap, pll_vco->reg, &cdiv);
refclkdiv = (cdiv >> pll_vco->refclkdiv_shift) &
(BIT(pll_vco->refclkdiv_width) - 1);
fdbkdiv = (cdiv >> pll_vco->fdbkdiv_shift) &
(BIT(pll_vco->fdbkdiv_width) - 1);
vco = parent_rate / refclkdiv;
vco *= 2;
vco *= fdbkdiv;
return vco;
}
static const struct clk_fepll_vco gcc_apss_ddrpll_vco = {
.fdbkdiv_shift = 16,
.fdbkdiv_width = 8,
.refclkdiv_shift = 24,
.refclkdiv_width = 5,
.reg = 0x2e020,
};
static const struct clk_fepll_vco gcc_fepll_vco = {
.fdbkdiv_shift = 16,
.fdbkdiv_width = 8,
.refclkdiv_shift = 24,
.refclkdiv_width = 5,
.reg = 0x2f020,
};
/*
* Round rate function for APSS CPU PLL Clock divider.
* It looks up the frequency table and returns the next higher frequency
* supported in hardware.
*/
static long clk_cpu_div_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *p_rate)
{
struct clk_fepll *pll = to_clk_fepll(hw);
struct clk_hw *p_hw;
const struct freq_tbl *f;
f = qcom_find_freq(pll->freq_tbl, rate);
if (!f)
return -EINVAL;
p_hw = clk_hw_get_parent_by_index(hw, f->src);
*p_rate = clk_hw_get_rate(p_hw);
return f->freq;
};
/*
* Clock set rate function for APSS CPU PLL Clock divider.
* It looks up the frequency table and updates the PLL divider to corresponding
* divider value.
*/
static int clk_cpu_div_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_fepll *pll = to_clk_fepll(hw);
const struct freq_tbl *f;
u32 mask;
int ret;
f = qcom_find_freq(pll->freq_tbl, rate);
if (!f)
return -EINVAL;
mask = (BIT(pll->cdiv.width) - 1) << pll->cdiv.shift;
ret = regmap_update_bits(pll->cdiv.clkr.regmap,
pll->cdiv.reg, mask,
f->pre_div << pll->cdiv.shift);
/*
* There is no status bit which can be checked for successful CPU
* divider update operation so using delay for the same.
*/
udelay(1);
return 0;
};
/*
* Clock frequency calculation function for APSS CPU PLL Clock divider.
* This clock divider is nonlinear so this function calculates the actual
* divider and returns the output frequency by dividing VCO Frequency
* with this actual divider value.
*/
static unsigned long
clk_cpu_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_fepll *pll = to_clk_fepll(hw);
u32 cdiv, pre_div;
u64 rate;
regmap_read(pll->cdiv.clkr.regmap, pll->cdiv.reg, &cdiv);
cdiv = (cdiv >> pll->cdiv.shift) & (BIT(pll->cdiv.width) - 1);
/*
* Some dividers have value in 0.5 fraction so multiply both VCO
* frequency(parent_rate) and pre_div with 2 to make integer
* calculation.
*/
if (cdiv > 10)
pre_div = (cdiv + 1) * 2;
else
pre_div = cdiv + 12;
rate = clk_fepll_vco_calc_rate(pll, parent_rate) * 2;
do_div(rate, pre_div);
return rate;
};
static const struct clk_ops clk_regmap_cpu_div_ops = {
.round_rate = clk_cpu_div_round_rate,
.set_rate = clk_cpu_div_set_rate,
.recalc_rate = clk_cpu_div_recalc_rate,
};
static const struct freq_tbl ftbl_apss_ddr_pll[] = {
{ 384000000, P_XO, 0xd, 0, 0 },
{ 413000000, P_XO, 0xc, 0, 0 },
{ 448000000, P_XO, 0xb, 0, 0 },
{ 488000000, P_XO, 0xa, 0, 0 },
{ 512000000, P_XO, 0x9, 0, 0 },
{ 537000000, P_XO, 0x8, 0, 0 },
{ 565000000, P_XO, 0x7, 0, 0 },
{ 597000000, P_XO, 0x6, 0, 0 },
{ 632000000, P_XO, 0x5, 0, 0 },
{ 672000000, P_XO, 0x4, 0, 0 },
{ 716000000, P_XO, 0x3, 0, 0 },
{ 768000000, P_XO, 0x2, 0, 0 },
{ 823000000, P_XO, 0x1, 0, 0 },
{ 896000000, P_XO, 0x0, 0, 0 },
{ }
};
static struct clk_fepll gcc_apss_cpu_plldiv_clk = {
.cdiv.reg = 0x2e020,
.cdiv.shift = 4,
.cdiv.width = 4,
.cdiv.clkr = {
.enable_reg = 0x2e000,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "ddrpllapss",
.parent_names = (const char *[]){
"xo",
},
.num_parents = 1,
.ops = &clk_regmap_cpu_div_ops,
},
},
.freq_tbl = ftbl_apss_ddr_pll,
.pll_vco = &gcc_apss_ddrpll_vco,
};
/* Calculates the rate for PLL divider.
* If the divider value is not fixed then it gets the actual divider value
* from divider table. Then, it calculate the clock rate by dividing the
* parent rate with actual divider value.
*/
static unsigned long
clk_regmap_clk_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_fepll *pll = to_clk_fepll(hw);
u32 cdiv, pre_div = 1;
u64 rate;
const struct clk_div_table *clkt;
if (pll->fixed_div) {
pre_div = pll->fixed_div;
} else {
regmap_read(pll->cdiv.clkr.regmap, pll->cdiv.reg, &cdiv);
cdiv = (cdiv >> pll->cdiv.shift) & (BIT(pll->cdiv.width) - 1);
for (clkt = pll->div_table; clkt->div; clkt++) {
if (clkt->val == cdiv)
pre_div = clkt->div;
}
}
rate = clk_fepll_vco_calc_rate(pll, parent_rate);
do_div(rate, pre_div);
return rate;
};
static const struct clk_ops clk_fepll_div_ops = {
.recalc_rate = clk_regmap_clk_div_recalc_rate,
};
static struct clk_fepll gcc_apss_sdcc_clk = {
.fixed_div = 28,
.cdiv.clkr = {
.hw.init = &(struct clk_init_data){
.name = "ddrpllsdcc",
.parent_names = (const char *[]){
"xo",
},
.num_parents = 1,
.ops = &clk_fepll_div_ops,
},
},
.pll_vco = &gcc_apss_ddrpll_vco,
};
static struct clk_fepll gcc_fepll125_clk = {
.fixed_div = 32,
.cdiv.clkr = {
.hw.init = &(struct clk_init_data){
.name = "fepll125",
.parent_names = (const char *[]){
"xo",
},
.num_parents = 1,
.ops = &clk_fepll_div_ops,
},
},
.pll_vco = &gcc_fepll_vco,
};
static struct clk_fepll gcc_fepll125dly_clk = {
.fixed_div = 32,
.cdiv.clkr = {
.hw.init = &(struct clk_init_data){
.name = "fepll125dly",
.parent_names = (const char *[]){
"xo",
},
.num_parents = 1,
.ops = &clk_fepll_div_ops,
},
},
.pll_vco = &gcc_fepll_vco,
};
static struct clk_fepll gcc_fepll200_clk = {
.fixed_div = 20,
.cdiv.clkr = {
.hw.init = &(struct clk_init_data){
.name = "fepll200",
.parent_names = (const char *[]){
"xo",
},
.num_parents = 1,
.ops = &clk_fepll_div_ops,
},
},
.pll_vco = &gcc_fepll_vco,
};
static struct clk_fepll gcc_fepll500_clk = {
.fixed_div = 8,
.cdiv.clkr = {
.hw.init = &(struct clk_init_data){
.name = "fepll500",
.parent_names = (const char *[]){
"xo",
},
.num_parents = 1,
.ops = &clk_fepll_div_ops,
},
},
.pll_vco = &gcc_fepll_vco,
};
static const struct clk_div_table fepllwcss_clk_div_table[] = {
{ 0, 15 },
{ 1, 16 },
{ 2, 18 },
{ 3, 20 },
{ },
};
static struct clk_fepll gcc_fepllwcss2g_clk = {
.cdiv.reg = 0x2f020,
.cdiv.shift = 8,
.cdiv.width = 2,
.cdiv.clkr = {
.hw.init = &(struct clk_init_data){
.name = "fepllwcss2g",
.parent_names = (const char *[]){
"xo",
},
.num_parents = 1,
.ops = &clk_fepll_div_ops,
},
},
.div_table = fepllwcss_clk_div_table,
.pll_vco = &gcc_fepll_vco,
};
static struct clk_fepll gcc_fepllwcss5g_clk = {
.cdiv.reg = 0x2f020,
.cdiv.shift = 12,
.cdiv.width = 2,
.cdiv.clkr = {
.hw.init = &(struct clk_init_data){
.name = "fepllwcss5g",
.parent_names = (const char *[]){
"xo",
},
.num_parents = 1,
.ops = &clk_fepll_div_ops,
},
},
.div_table = fepllwcss_clk_div_table,
.pll_vco = &gcc_fepll_vco,
};
static const struct freq_tbl ftbl_gcc_pcnoc_ahb_clk[] = {
F(48000000, P_XO, 1, 0, 0),
F(100000000, P_FEPLL200, 2, 0, 0),
{ }
};
static struct clk_rcg2 gcc_pcnoc_ahb_clk_src = {
.cmd_rcgr = 0x21024,
.hid_width = 5,
.parent_map = gcc_xo_200_500_map,
.freq_tbl = ftbl_gcc_pcnoc_ahb_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_pcnoc_ahb_clk_src",
.parent_names = gcc_xo_200_500,
.num_parents = 3,
.ops = &clk_rcg2_ops,
},
};
static struct clk_branch pcnoc_clk_src = {
.halt_reg = 0x21030,
.clkr = {
.enable_reg = 0x21030,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "pcnoc_clk_src",
.parent_names = (const char *[]){
"gcc_pcnoc_ahb_clk_src",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
.flags = CLK_SET_RATE_PARENT |
CLK_IS_CRITICAL,
},
},
};
static struct clk_regmap *gcc_ipq4019_clocks[] = { static struct clk_regmap *gcc_ipq4019_clocks[] = {
[AUDIO_CLK_SRC] = &audio_clk_src.clkr, [AUDIO_CLK_SRC] = &audio_clk_src.clkr,
[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
...@@ -1214,6 +1634,16 @@ static struct clk_regmap *gcc_ipq4019_clocks[] = { ...@@ -1214,6 +1634,16 @@ static struct clk_regmap *gcc_ipq4019_clocks[] = {
[GCC_WCSS5G_CLK] = &gcc_wcss5g_clk.clkr, [GCC_WCSS5G_CLK] = &gcc_wcss5g_clk.clkr,
[GCC_WCSS5G_REF_CLK] = &gcc_wcss5g_ref_clk.clkr, [GCC_WCSS5G_REF_CLK] = &gcc_wcss5g_ref_clk.clkr,
[GCC_WCSS5G_RTC_CLK] = &gcc_wcss5g_rtc_clk.clkr, [GCC_WCSS5G_RTC_CLK] = &gcc_wcss5g_rtc_clk.clkr,
[GCC_SDCC_PLLDIV_CLK] = &gcc_apss_sdcc_clk.cdiv.clkr,
[GCC_FEPLL125_CLK] = &gcc_fepll125_clk.cdiv.clkr,
[GCC_FEPLL125DLY_CLK] = &gcc_fepll125dly_clk.cdiv.clkr,
[GCC_FEPLL200_CLK] = &gcc_fepll200_clk.cdiv.clkr,
[GCC_FEPLL500_CLK] = &gcc_fepll500_clk.cdiv.clkr,
[GCC_FEPLL_WCSS2G_CLK] = &gcc_fepllwcss2g_clk.cdiv.clkr,
[GCC_FEPLL_WCSS5G_CLK] = &gcc_fepllwcss5g_clk.cdiv.clkr,
[GCC_APSS_CPU_PLLDIV_CLK] = &gcc_apss_cpu_plldiv_clk.cdiv.clkr,
[GCC_PCNOC_AHB_CLK_SRC] = &gcc_pcnoc_ahb_clk_src.clkr,
[GCC_PCNOC_AHB_CLK] = &pcnoc_clk_src.clkr,
}; };
static const struct qcom_reset_map gcc_ipq4019_resets[] = { static const struct qcom_reset_map gcc_ipq4019_resets[] = {
...@@ -1294,7 +1724,7 @@ static const struct regmap_config gcc_ipq4019_regmap_config = { ...@@ -1294,7 +1724,7 @@ static const struct regmap_config gcc_ipq4019_regmap_config = {
.reg_bits = 32, .reg_bits = 32,
.reg_stride = 4, .reg_stride = 4,
.val_bits = 32, .val_bits = 32,
.max_register = 0x2dfff, .max_register = 0x2ffff,
.fast_io = true, .fast_io = true,
}; };
...@@ -1312,23 +1742,44 @@ static const struct of_device_id gcc_ipq4019_match_table[] = { ...@@ -1312,23 +1742,44 @@ static const struct of_device_id gcc_ipq4019_match_table[] = {
}; };
MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table); MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table);
static int
gcc_ipq4019_cpu_clk_notifier_fn(struct notifier_block *nb,
unsigned long action, void *data)
{
int err = 0;
if (action == PRE_RATE_CHANGE)
err = clk_rcg2_ops.set_parent(&apps_clk_src.clkr.hw,
gcc_ipq4019_cpu_safe_parent);
return notifier_from_errno(err);
}
static struct notifier_block gcc_ipq4019_cpu_clk_notifier = {
.notifier_call = gcc_ipq4019_cpu_clk_notifier_fn,
};
static int gcc_ipq4019_probe(struct platform_device *pdev) static int gcc_ipq4019_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; int err;
clk_register_fixed_rate(dev, "fepll125", "xo", 0, 200000000); err = qcom_cc_probe(pdev, &gcc_ipq4019_desc);
clk_register_fixed_rate(dev, "fepll125dly", "xo", 0, 200000000); if (err)
clk_register_fixed_rate(dev, "fepllwcss2g", "xo", 0, 200000000); return err;
clk_register_fixed_rate(dev, "fepllwcss5g", "xo", 0, 200000000);
clk_register_fixed_rate(dev, "fepll200", "xo", 0, 200000000);
clk_register_fixed_rate(dev, "fepll500", "xo", 0, 200000000);
clk_register_fixed_rate(dev, "ddrpllapss", "xo", 0, 666000000);
return qcom_cc_probe(pdev, &gcc_ipq4019_desc); return clk_notifier_register(apps_clk_src.clkr.hw.clk,
&gcc_ipq4019_cpu_clk_notifier);
}
static int gcc_ipq4019_remove(struct platform_device *pdev)
{
return clk_notifier_unregister(apps_clk_src.clkr.hw.clk,
&gcc_ipq4019_cpu_clk_notifier);
} }
static struct platform_driver gcc_ipq4019_driver = { static struct platform_driver gcc_ipq4019_driver = {
.probe = gcc_ipq4019_probe, .probe = gcc_ipq4019_probe,
.remove = gcc_ipq4019_remove,
.driver = { .driver = {
.name = "qcom,gcc-ipq4019", .name = "qcom,gcc-ipq4019",
.of_match_table = gcc_ipq4019_match_table, .of_match_table = gcc_ipq4019_match_table,
......
...@@ -37,12 +37,14 @@ ...@@ -37,12 +37,14 @@
* @smstpcr: module stop control register * @smstpcr: module stop control register
* @mstpsr: module stop status register (optional) * @mstpsr: module stop status register (optional)
* @lock: protects writes to SMSTPCR * @lock: protects writes to SMSTPCR
* @width_8bit: registers are 8-bit, not 32-bit
*/ */
struct mstp_clock_group { struct mstp_clock_group {
struct clk_onecell_data data; struct clk_onecell_data data;
void __iomem *smstpcr; void __iomem *smstpcr;
void __iomem *mstpsr; void __iomem *mstpsr;
spinlock_t lock; spinlock_t lock;
bool width_8bit;
}; };
/** /**
...@@ -59,6 +61,18 @@ struct mstp_clock { ...@@ -59,6 +61,18 @@ struct mstp_clock {
#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
static inline u32 cpg_mstp_read(struct mstp_clock_group *group,
u32 __iomem *reg)
{
return group->width_8bit ? readb(reg) : clk_readl(reg);
}
static inline void cpg_mstp_write(struct mstp_clock_group *group, u32 val,
u32 __iomem *reg)
{
group->width_8bit ? writeb(val, reg) : clk_writel(val, reg);
}
static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
{ {
struct mstp_clock *clock = to_mstp_clock(hw); struct mstp_clock *clock = to_mstp_clock(hw);
...@@ -70,12 +84,12 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) ...@@ -70,12 +84,12 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
spin_lock_irqsave(&group->lock, flags); spin_lock_irqsave(&group->lock, flags);
value = clk_readl(group->smstpcr); value = cpg_mstp_read(group, group->smstpcr);
if (enable) if (enable)
value &= ~bitmask; value &= ~bitmask;
else else
value |= bitmask; value |= bitmask;
clk_writel(value, group->smstpcr); cpg_mstp_write(group, value, group->smstpcr);
spin_unlock_irqrestore(&group->lock, flags); spin_unlock_irqrestore(&group->lock, flags);
...@@ -83,7 +97,7 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) ...@@ -83,7 +97,7 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
return 0; return 0;
for (i = 1000; i > 0; --i) { for (i = 1000; i > 0; --i) {
if (!(clk_readl(group->mstpsr) & bitmask)) if (!(cpg_mstp_read(group, group->mstpsr) & bitmask))
break; break;
cpu_relax(); cpu_relax();
} }
...@@ -114,9 +128,9 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) ...@@ -114,9 +128,9 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
u32 value; u32 value;
if (group->mstpsr) if (group->mstpsr)
value = clk_readl(group->mstpsr); value = cpg_mstp_read(group, group->mstpsr);
else else
value = clk_readl(group->smstpcr); value = cpg_mstp_read(group, group->smstpcr);
return !(value & BIT(clock->bit_index)); return !(value & BIT(clock->bit_index));
} }
...@@ -188,6 +202,9 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) ...@@ -188,6 +202,9 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
return; return;
} }
if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks"))
group->width_8bit = true;
for (i = 0; i < MSTP_MAX_CLOCKS; ++i) for (i = 0; i < MSTP_MAX_CLOCKS; ++i)
clks[i] = ERR_PTR(-ENOENT); clks[i] = ERR_PTR(-ENOENT);
......
...@@ -81,6 +81,17 @@ ...@@ -81,6 +81,17 @@
#define GCC_WCSS5G_CLK 62 #define GCC_WCSS5G_CLK 62
#define GCC_WCSS5G_REF_CLK 63 #define GCC_WCSS5G_REF_CLK 63
#define GCC_WCSS5G_RTC_CLK 64 #define GCC_WCSS5G_RTC_CLK 64
#define GCC_APSS_DDRPLL_VCO 65
#define GCC_SDCC_PLLDIV_CLK 66
#define GCC_FEPLL_VCO 67
#define GCC_FEPLL125_CLK 68
#define GCC_FEPLL125DLY_CLK 69
#define GCC_FEPLL200_CLK 70
#define GCC_FEPLL500_CLK 71
#define GCC_FEPLL_WCSS2G_CLK 72
#define GCC_FEPLL_WCSS5G_CLK 73
#define GCC_APSS_CPU_PLLDIV_CLK 74
#define GCC_PCNOC_AHB_CLK_SRC 75
#define WIFI0_CPU_INIT_RESET 0 #define WIFI0_CPU_INIT_RESET 0
#define WIFI0_RADIO_SRIF_RESET 1 #define WIFI0_RADIO_SRIF_RESET 1
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#ifndef _DT_BINDINGS_CLK_MSM_RPMCC_H #ifndef _DT_BINDINGS_CLK_MSM_RPMCC_H
#define _DT_BINDINGS_CLK_MSM_RPMCC_H #define _DT_BINDINGS_CLK_MSM_RPMCC_H
/* apq8064 */ /* RPM clocks */
#define RPM_PXO_CLK 0 #define RPM_PXO_CLK 0
#define RPM_PXO_A_CLK 1 #define RPM_PXO_A_CLK 1
#define RPM_CXO_CLK 2 #define RPM_CXO_CLK 2
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#define RPM_SFPB_CLK 20 #define RPM_SFPB_CLK 20
#define RPM_SFPB_A_CLK 21 #define RPM_SFPB_A_CLK 21
/* msm8916 */ /* SMD RPM clocks */
#define RPM_SMD_XO_CLK_SRC 0 #define RPM_SMD_XO_CLK_SRC 0
#define RPM_SMD_XO_A_CLK_SRC 1 #define RPM_SMD_XO_A_CLK_SRC 1
#define RPM_SMD_PCNOC_CLK 2 #define RPM_SMD_PCNOC_CLK 2
...@@ -65,5 +65,41 @@ ...@@ -65,5 +65,41 @@
#define RPM_SMD_RF_CLK1_A_PIN 23 #define RPM_SMD_RF_CLK1_A_PIN 23
#define RPM_SMD_RF_CLK2_PIN 24 #define RPM_SMD_RF_CLK2_PIN 24
#define RPM_SMD_RF_CLK2_A_PIN 25 #define RPM_SMD_RF_CLK2_A_PIN 25
#define RPM_SMD_PNOC_CLK 26
#define RPM_SMD_PNOC_A_CLK 27
#define RPM_SMD_CNOC_CLK 28
#define RPM_SMD_CNOC_A_CLK 29
#define RPM_SMD_MMSSNOC_AHB_CLK 30
#define RPM_SMD_MMSSNOC_AHB_A_CLK 31
#define RPM_SMD_GFX3D_CLK_SRC 32
#define RPM_SMD_GFX3D_A_CLK_SRC 33
#define RPM_SMD_OCMEMGX_CLK 34
#define RPM_SMD_OCMEMGX_A_CLK 35
#define RPM_SMD_CXO_D0 36
#define RPM_SMD_CXO_D0_A 37
#define RPM_SMD_CXO_D1 38
#define RPM_SMD_CXO_D1_A 39
#define RPM_SMD_CXO_A0 40
#define RPM_SMD_CXO_A0_A 41
#define RPM_SMD_CXO_A1 42
#define RPM_SMD_CXO_A1_A 43
#define RPM_SMD_CXO_A2 44
#define RPM_SMD_CXO_A2_A 45
#define RPM_SMD_DIV_CLK1 46
#define RPM_SMD_DIV_A_CLK1 47
#define RPM_SMD_DIV_CLK2 48
#define RPM_SMD_DIV_A_CLK2 49
#define RPM_SMD_DIFF_CLK 50
#define RPM_SMD_DIFF_A_CLK 51
#define RPM_SMD_CXO_D0_PIN 52
#define RPM_SMD_CXO_D0_A_PIN 53
#define RPM_SMD_CXO_D1_PIN 54
#define RPM_SMD_CXO_D1_A_PIN 55
#define RPM_SMD_CXO_A0_PIN 56
#define RPM_SMD_CXO_A0_A_PIN 57
#define RPM_SMD_CXO_A1_PIN 58
#define RPM_SMD_CXO_A1_A_PIN 59
#define RPM_SMD_CXO_A2_PIN 60
#define RPM_SMD_CXO_A2_A_PIN 61
#endif #endif
/*
* stm32fx-clock.h
*
* Copyright (C) 2016 STMicroelectronics
* Author: Gabriel Fernandez for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/
/*
* List of clocks wich are not derived from system clock (SYSCLOCK)
*
* The index of these clocks is the secondary index of DT bindings
* (see Documentatoin/devicetree/bindings/clock/st,stm32-rcc.txt)
*
* e.g:
<assigned-clocks = <&rcc 1 CLK_LSE>;
*/
#ifndef _DT_BINDINGS_CLK_STMFX_H
#define _DT_BINDINGS_CLK_STMFX_H
#define SYSTICK 0
#define FCLK 1
#define CLK_LSI 2
#define CLK_LSE 3
#define CLK_HSE_RTC 4
#define CLK_RTC 5
#define PLL_VCO_I2S 6
#define PLL_VCO_SAI 7
#define CLK_LCD 8
#define CLK_I2S 9
#define CLK_SAI1 10
#define CLK_SAI2 11
#define CLK_I2SQ_PDIV 12
#define CLK_SAIQ_PDIV 13
#define END_PRIMARY_CLK 14
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment