Commit ef9ca02b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk fixes from Stephen Boyd:
 "A handful of critical fixes for changes introduce this merge window.

   - The TI sci_clk_get() API was pretty broken and nobody noticed.

   - There were some CPUfreq crashes on C.H.I.P devices because we
     failed to propagate rates up the clk tree.

   - Also, the Intel Atom PMC clk driver needs to mark a clk critical if
     the firmware has it enabled already so that audio doesn't get
     killed on Baytrail.

   - Gemini devices have a dead serial console because the reset control
     usage in the serial driver assume one method of reset that gemini
     doesn't support (this will be fixed in the next version in the
     reset framework so this is the small fix for -rc series).

   - Finally we have two rate calculation fixes, one for Exynos and one
     for Meson SoCs, that fix rate inconsistencies"

* tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux:
  clk: keystone: sci-clk: Fix sci_clk_get
  clk: meson: mpll: fix mpll0 fractional part ignored
  clk: samsung: exynos5420: The EPLL rate table corrections
  clk: sunxi-ng: sun5i: Add clk_set_rate_parent to the CPU clock
  clk: x86: Do not gate clocks enabled by the firmware
  clk: gemini: Fix reset regression
parents 69995074 f54d2cd3
......@@ -237,6 +237,18 @@ static int gemini_reset(struct reset_controller_dev *rcdev,
BIT(GEMINI_RESET_CPU1) | BIT(id));
}
static int gemini_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return 0;
}
static int gemini_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return 0;
}
static int gemini_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
......@@ -253,6 +265,8 @@ static int gemini_reset_status(struct reset_controller_dev *rcdev,
static const struct reset_control_ops gemini_reset_ops = {
.reset = gemini_reset,
.assert = gemini_reset_assert,
.deassert = gemini_reset_deassert,
.status = gemini_reset_status,
};
......
......@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include <linux/bsearch.h>
#define SCI_CLK_SSC_ENABLE BIT(0)
#define SCI_CLK_ALLOW_FREQ_CHANGE BIT(1)
......@@ -44,6 +45,7 @@ struct sci_clk_data {
* @dev: Device pointer for the clock provider
* @clk_data: Clock data
* @clocks: Clocks array for this device
* @num_clocks: Total number of clocks for this provider
*/
struct sci_clk_provider {
const struct ti_sci_handle *sci;
......@@ -51,6 +53,7 @@ struct sci_clk_provider {
struct device *dev;
const struct sci_clk_data *clk_data;
struct clk_hw **clocks;
int num_clocks;
};
/**
......@@ -58,7 +61,6 @@ struct sci_clk_provider {
* @hw: Hardware clock cookie for common clock framework
* @dev_id: Device index
* @clk_id: Clock index
* @node: Clocks list link
* @provider: Master clock provider
* @flags: Flags for the clock
*/
......@@ -66,7 +68,6 @@ struct sci_clk {
struct clk_hw hw;
u16 dev_id;
u8 clk_id;
struct list_head node;
struct sci_clk_provider *provider;
u8 flags;
};
......@@ -367,6 +368,19 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider,
return &sci_clk->hw;
}
static int _cmp_sci_clk(const void *a, const void *b)
{
const struct sci_clk *ca = a;
const struct sci_clk *cb = *(struct sci_clk **)b;
if (ca->dev_id == cb->dev_id && ca->clk_id == cb->clk_id)
return 0;
if (ca->dev_id > cb->dev_id ||
(ca->dev_id == cb->dev_id && ca->clk_id > cb->clk_id))
return 1;
return -1;
}
/**
* sci_clk_get - Xlate function for getting clock handles
* @clkspec: device tree clock specifier
......@@ -380,29 +394,22 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider,
static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data)
{
struct sci_clk_provider *provider = data;
u16 dev_id;
u8 clk_id;
const struct sci_clk_data *clks = provider->clk_data;
struct clk_hw **clocks = provider->clocks;
struct sci_clk **clk;
struct sci_clk key;
if (clkspec->args_count != 2)
return ERR_PTR(-EINVAL);
dev_id = clkspec->args[0];
clk_id = clkspec->args[1];
key.dev_id = clkspec->args[0];
key.clk_id = clkspec->args[1];
while (clks->num_clks) {
if (clks->dev == dev_id) {
if (clk_id >= clks->num_clks)
return ERR_PTR(-EINVAL);
return clocks[clk_id];
}
clk = bsearch(&key, provider->clocks, provider->num_clocks,
sizeof(clk), _cmp_sci_clk);
clks++;
}
if (!clk)
return ERR_PTR(-ENODEV);
return ERR_PTR(-ENODEV);
return &(*clk)->hw;
}
static int ti_sci_init_clocks(struct sci_clk_provider *p)
......@@ -410,18 +417,29 @@ static int ti_sci_init_clocks(struct sci_clk_provider *p)
const struct sci_clk_data *data = p->clk_data;
struct clk_hw *hw;
int i;
int num_clks = 0;
while (data->num_clks) {
p->clocks = devm_kcalloc(p->dev, data->num_clks,
sizeof(struct sci_clk),
GFP_KERNEL);
if (!p->clocks)
return -ENOMEM;
num_clks += data->num_clks;
data++;
}
p->num_clocks = num_clks;
p->clocks = devm_kcalloc(p->dev, num_clks, sizeof(struct sci_clk),
GFP_KERNEL);
if (!p->clocks)
return -ENOMEM;
num_clks = 0;
data = p->clk_data;
while (data->num_clks) {
for (i = 0; i < data->num_clks; i++) {
hw = _sci_clk_build(p, data->dev, i);
if (!IS_ERR(hw)) {
p->clocks[i] = hw;
p->clocks[num_clks++] = hw;
continue;
}
......
......@@ -161,6 +161,13 @@ static int mpll_set_rate(struct clk_hw *hw,
reg = PARM_SET(p->width, p->shift, reg, 1);
writel(reg, mpll->base + p->reg_off);
p = &mpll->ssen;
if (p->width != 0) {
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, 1);
writel(reg, mpll->base + p->reg_off);
}
p = &mpll->n2;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, n2);
......
......@@ -118,6 +118,7 @@ struct meson_clk_mpll {
struct parm sdm_en;
struct parm n2;
struct parm en;
struct parm ssen;
spinlock_t *lock;
};
......
......@@ -528,6 +528,11 @@ static struct meson_clk_mpll gxbb_mpll0 = {
.shift = 14,
.width = 1,
},
.ssen = {
.reg_off = HHI_MPLL_CNTL,
.shift = 25,
.width = 1,
},
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll0",
......
......@@ -267,6 +267,11 @@ static struct meson_clk_mpll meson8b_mpll0 = {
.shift = 14,
.width = 1,
},
.ssen = {
.reg_off = HHI_MPLL_CNTL,
.shift = 25,
.width = 1,
},
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll0",
......
......@@ -1283,16 +1283,16 @@ static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __ini
static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = {
PLL_36XX_RATE(600000000U, 100, 2, 1, 0),
PLL_36XX_RATE(400000000U, 200, 3, 2, 0),
PLL_36XX_RATE(393216000U, 197, 3, 2, 25690),
PLL_36XX_RATE(361267200U, 301, 5, 2, 3671),
PLL_36XX_RATE(393216003U, 197, 3, 2, -25690),
PLL_36XX_RATE(361267218U, 301, 5, 2, 3671),
PLL_36XX_RATE(200000000U, 200, 3, 3, 0),
PLL_36XX_RATE(196608000U, 197, 3, 3, -25690),
PLL_36XX_RATE(180633600U, 301, 5, 3, 3671),
PLL_36XX_RATE(131072000U, 131, 3, 3, 4719),
PLL_36XX_RATE(196608001U, 197, 3, 3, -25690),
PLL_36XX_RATE(180633609U, 301, 5, 3, 3671),
PLL_36XX_RATE(131072006U, 131, 3, 3, 4719),
PLL_36XX_RATE(100000000U, 200, 3, 4, 0),
PLL_36XX_RATE(65536000U, 131, 3, 4, 4719),
PLL_36XX_RATE(49152000U, 197, 3, 5, 25690),
PLL_36XX_RATE(32768000U, 131, 3, 5, 4719),
PLL_36XX_RATE( 65536003U, 131, 3, 4, 4719),
PLL_36XX_RATE( 49152000U, 197, 3, 5, -25690),
PLL_36XX_RATE( 32768001U, 131, 3, 5, 4719),
};
static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = {
......
......@@ -184,7 +184,7 @@ static struct ccu_mux cpu_clk = {
.hw.init = CLK_HW_INIT_PARENTS("cpu",
cpu_parents,
&ccu_mux_ops,
CLK_IS_CRITICAL),
CLK_SET_RATE_PARENT | CLK_IS_CRITICAL),
}
};
......
......@@ -186,6 +186,13 @@ static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id,
pclk->reg = base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE;
spin_lock_init(&pclk->lock);
/*
* If the clock was already enabled by the firmware mark it as critical
* to avoid it being gated by the clock framework if no driver owns it.
*/
if (plt_clk_is_enabled(&pclk->hw))
init.flags |= CLK_IS_CRITICAL;
ret = devm_clk_hw_register(&pdev->dev, &pclk->hw);
if (ret) {
pclk = ERR_PTR(ret);
......
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