Skip to content

Commit

Permalink
Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
Linus Torvalds committed Aug 4, 2017
2 parents 6999507 + f54d2cd commit ef9ca02
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 33 deletions.
14 changes: 14 additions & 0 deletions drivers/clk/clk-gemini.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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,
};

Expand Down
66 changes: 42 additions & 24 deletions drivers/clk/keystone/sci-clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -44,29 +45,29 @@ 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;
const struct ti_sci_clk_ops *ops;
struct device *dev;
const struct sci_clk_data *clk_data;
struct clk_hw **clocks;
int num_clocks;
};

/**
* struct sci_clk - TI SCI clock representation
* @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
*/
struct sci_clk {
struct clk_hw hw;
u16 dev_id;
u8 clk_id;
struct list_head node;
struct sci_clk_provider *provider;
u8 flags;
};
Expand Down Expand Up @@ -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
Expand All @@ -380,48 +394,52 @@ 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)
{
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;
}

Expand Down
7 changes: 7 additions & 0 deletions drivers/clk/meson/clk-mpll.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions drivers/clk/meson/clkc.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ struct meson_clk_mpll {
struct parm sdm_en;
struct parm n2;
struct parm en;
struct parm ssen;
spinlock_t *lock;
};

Expand Down
5 changes: 5 additions & 0 deletions drivers/clk/meson/gxbb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 5 additions & 0 deletions drivers/clk/meson/meson8b.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
16 changes: 8 additions & 8 deletions drivers/clk/samsung/clk-exynos5420.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
2 changes: 1 addition & 1 deletion drivers/clk/sunxi-ng/ccu-sun5i.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
};

Expand Down
7 changes: 7 additions & 0 deletions drivers/clk/x86/clk-pmc-atom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit ef9ca02

Please sign in to comment.