mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJZhPRKAAoJEK0CiJfG5JUlY7MP/3hSev0xnS7HDLdaVfyMDGuI RMo4wNmScma098CeEoGXCHw+Sd2i4HqqrbEPh0dohJSCPm2kotS5zjf7UhCKNROt VKKykz9p/YdBvC01txzqRwOr/iwTASt1981C/vjorxvoE7LaYT1qduY4OBrhFhce CyIRljk7fuoX01I5jEp/VwShlO+Pn5PxJ44jImBXd/A7SWX/wiviXOvHsZLNStVn PLDlS2EW5B7nLwqWFuUu9/UMOjdpstgS4vCfksYeeEwc9llLg/Fm40m+rPMNOHl8 A+bxYVRU273Wzp8HM2bLzq7JDJZ8mlgGF5ov2ARNaUB1ZYixPVTQPhtfWo918hhC M+Fj5PBlzL5Hnm5rG0fqfABn/QUvSj6BUh4ykUwao3sF/hSK1f8WUcltE/+p30UP DPotIrcNUZsshXRcKEOY4NwXs4pAAEjRAdmgh+vZRblbvuUZayDcdmti9l7LFvBo 6RtAKXIZFtOQ5IdHwkmHRYYcKCHnJTnuyao0VRid6cnJ6x11wwjmwP8M71C1kJ83 LOWVz4/vys6tD59xOm+oriGJwQATscOlkt7QsbVJLhSIsZ37NxLdnPVY0W/HLMK+ RpWyHXwW9tHWRpYmMM0luQm/UhWNXVxV8VezaTIU+NBq41vGJPYOMPLUUhHHLC9N UDqN6Rnr15NvhoeUnYlg =/JMb -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
ef9ca02baa
9 changed files with 90 additions and 33 deletions
|
@ -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);
|
||||
clk = bsearch(&key, provider->clocks, provider->num_clocks,
|
||||
sizeof(clk), _cmp_sci_clk);
|
||||
|
||||
return clocks[clk_id];
|
||||
}
|
||||
if (!clk)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
clks++;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue