Commit 09bad0df 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:
 "Here's more than a handful of clk driver fixes for changes that came
  in during the merge window:

   - Fix the AT91 sama5d2 programmable clk prescaler formula

   - A bunch of Amlogic meson clk driver fixes for the VPU clks

   - A DMI quirk for Intel's Bay Trail SoC's driver to properly mark pmc
     clks as critical only when really needed

   - Stop overwriting CLK_SET_RATE_PARENT flag in mediatek's clk gate
     implementation

   - Use the right structure to test for a frequency table in i.MX's
     PLL_1416x driver"

* tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux:
  clk: imx: Fix PLL_1416X not rounding rates
  clk: mediatek: fix clk-gate flag setting
  platform/x86: pmc_atom: Drop __initconst on dmi table
  clk: x86: Add system specific quirk to mark clocks as critical
  clk: meson: vid-pll-div: remove warning and return 0 on invalid config
  clk: meson: pll: fix rounding and setting a rate that matches precisely
  clk: meson-g12a: fix VPU clock parents
  clk: meson: g12a: fix VPU clock muxes mask
  clk: meson-gxbb: round the vdec dividers to closest
  clk: at91: fix programmable clock for sama5d2
parents a3b84248 f89b9e1b
......@@ -20,8 +20,7 @@
#define PROG_ID_MAX 7
#define PROG_STATUS_MASK(id) (1 << ((id) + 8))
#define PROG_PRES_MASK 0x7
#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & layout->pres_mask)
#define PROG_MAX_RM9200_CSS 3
struct clk_programmable {
......@@ -37,20 +36,29 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_programmable *prog = to_clk_programmable(hw);
const struct clk_programmable_layout *layout = prog->layout;
unsigned int pckr;
unsigned long rate;
regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
return parent_rate >> PROG_PRES(prog->layout, pckr);
if (layout->is_pres_direct)
rate = parent_rate / (PROG_PRES(layout, pckr) + 1);
else
rate = parent_rate >> PROG_PRES(layout, pckr);
return rate;
}
static int clk_programmable_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_programmable *prog = to_clk_programmable(hw);
const struct clk_programmable_layout *layout = prog->layout;
struct clk_hw *parent;
long best_rate = -EINVAL;
unsigned long parent_rate;
unsigned long tmp_rate;
unsigned long tmp_rate = 0;
int shift;
int i;
......@@ -60,10 +68,18 @@ static int clk_programmable_determine_rate(struct clk_hw *hw,
continue;
parent_rate = clk_hw_get_rate(parent);
for (shift = 0; shift < PROG_PRES_MASK; shift++) {
tmp_rate = parent_rate >> shift;
if (tmp_rate <= req->rate)
break;
if (layout->is_pres_direct) {
for (shift = 0; shift <= layout->pres_mask; shift++) {
tmp_rate = parent_rate / (shift + 1);
if (tmp_rate <= req->rate)
break;
}
} else {
for (shift = 0; shift < layout->pres_mask; shift++) {
tmp_rate = parent_rate >> shift;
if (tmp_rate <= req->rate)
break;
}
}
if (tmp_rate > req->rate)
......@@ -137,16 +153,23 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
if (!div)
return -EINVAL;
shift = fls(div) - 1;
if (layout->is_pres_direct) {
shift = div - 1;
if (div != (1 << shift))
return -EINVAL;
if (shift > layout->pres_mask)
return -EINVAL;
} else {
shift = fls(div) - 1;
if (shift >= PROG_PRES_MASK)
return -EINVAL;
if (div != (1 << shift))
return -EINVAL;
if (shift >= layout->pres_mask)
return -EINVAL;
}
regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id),
PROG_PRES_MASK << layout->pres_shift,
layout->pres_mask << layout->pres_shift,
shift << layout->pres_shift);
return 0;
......@@ -202,19 +225,25 @@ at91_clk_register_programmable(struct regmap *regmap,
}
const struct clk_programmable_layout at91rm9200_programmable_layout = {
.pres_mask = 0x7,
.pres_shift = 2,
.css_mask = 0x3,
.have_slck_mck = 0,
.is_pres_direct = 0,
};
const struct clk_programmable_layout at91sam9g45_programmable_layout = {
.pres_mask = 0x7,
.pres_shift = 2,
.css_mask = 0x3,
.have_slck_mck = 1,
.is_pres_direct = 0,
};
const struct clk_programmable_layout at91sam9x5_programmable_layout = {
.pres_mask = 0x7,
.pres_shift = 4,
.css_mask = 0x7,
.have_slck_mck = 0,
.is_pres_direct = 0,
};
......@@ -71,9 +71,11 @@ struct clk_pll_characteristics {
};
struct clk_programmable_layout {
u8 pres_mask;
u8 pres_shift;
u8 css_mask;
u8 have_slck_mck;
u8 is_pres_direct;
};
extern const struct clk_programmable_layout at91rm9200_programmable_layout;
......
......@@ -125,6 +125,14 @@ static const struct {
.pll = true },
};
static const struct clk_programmable_layout sama5d2_programmable_layout = {
.pres_mask = 0xff,
.pres_shift = 4,
.css_mask = 0x7,
.have_slck_mck = 0,
.is_pres_direct = 1,
};
static void __init sama5d2_pmc_setup(struct device_node *np)
{
struct clk_range range = CLK_RANGE(0, 0);
......@@ -249,7 +257,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name,
parent_names, 6, i,
&at91sam9x5_programmable_layout);
&sama5d2_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
......
......@@ -362,7 +362,7 @@ struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
switch (pll_clk->type) {
case PLL_1416X:
if (!pll->rate_table)
if (!pll_clk->rate_table)
init.ops = &clk_pll1416x_min_ops;
else
init.ops = &clk_pll1416x_ops;
......
......@@ -169,11 +169,10 @@ struct clk *mtk_clk_register_gate(
return ERR_PTR(-ENOMEM);
init.name = name;
init.flags = CLK_SET_RATE_PARENT;
init.flags = flags | CLK_SET_RATE_PARENT;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
init.ops = ops;
init.flags = flags;
cg->regmap = regmap;
cg->set_ofs = set_ofs;
......
......@@ -120,7 +120,7 @@ static bool meson_clk_pll_is_better(unsigned long rate,
return true;
} else {
/* Round down */
if (now < rate && best < now)
if (now <= rate && best < now)
return true;
}
......
......@@ -960,14 +960,14 @@ static struct clk_regmap g12a_sd_emmc_c_clk0 = {
/* VPU Clock */
static const char * const g12a_vpu_parent_names[] = {
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7",
"fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7",
"mpll1", "vid_pll", "hifi_pll", "gp0_pll",
};
static struct clk_regmap g12a_vpu_0_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 0x3,
.mask = 0x7,
.shift = 9,
},
.hw.init = &(struct clk_init_data){
......@@ -1011,7 +1011,7 @@ static struct clk_regmap g12a_vpu_0 = {
static struct clk_regmap g12a_vpu_1_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 0x3,
.mask = 0x7,
.shift = 25,
},
.hw.init = &(struct clk_init_data){
......
......@@ -2216,6 +2216,7 @@ static struct clk_regmap gxbb_vdec_1_div = {
.offset = HHI_VDEC_CLK_CNTL,
.shift = 0,
.width = 7,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
.name = "vdec_1_div",
......@@ -2261,6 +2262,7 @@ static struct clk_regmap gxbb_vdec_hevc_div = {
.offset = HHI_VDEC2_CLK_CNTL,
.shift = 16,
.width = 7,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
.name = "vdec_hevc_div",
......
......@@ -82,8 +82,8 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
div = _get_table_val(meson_parm_read(clk->map, &pll_div->val),
meson_parm_read(clk->map, &pll_div->sel));
if (!div || !div->divider) {
pr_info("%s: Invalid config value for vid_pll_div\n", __func__);
return parent_rate;
pr_debug("%s: Invalid config value for vid_pll_div\n", __func__);
return 0;
}
return DIV_ROUND_UP_ULL(parent_rate * div->multiplier, div->divider);
......
......@@ -165,7 +165,7 @@ static const struct clk_ops plt_clk_ops = {
};
static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id,
void __iomem *base,
const struct pmc_clk_data *pmc_data,
const char **parent_names,
int num_parents)
{
......@@ -184,9 +184,17 @@ static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id,
init.num_parents = num_parents;
pclk->hw.init = &init;
pclk->reg = base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE;
pclk->reg = pmc_data->base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE;
spin_lock_init(&pclk->lock);
/*
* On some systems, the pmc_plt_clocks already enabled by the
* firmware are being marked as critical to avoid them being
* gated by the clock framework.
*/
if (pmc_data->critical && 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);
......@@ -332,7 +340,7 @@ static int plt_clk_probe(struct platform_device *pdev)
return PTR_ERR(parent_names);
for (i = 0; i < PMC_CLK_NUM; i++) {
data->clks[i] = plt_clk_register(pdev, i, pmc_data->base,
data->clks[i] = plt_clk_register(pdev, i, pmc_data,
parent_names, data->nparents);
if (IS_ERR(data->clks[i])) {
err = PTR_ERR(data->clks[i]);
......
......@@ -17,6 +17,7 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_data/x86/clk-pmc-atom.h>
......@@ -391,11 +392,27 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc)
}
#endif /* CONFIG_DEBUG_FS */
/*
* Some systems need one or more of their pmc_plt_clks to be
* marked as critical.
*/
static const struct dmi_system_id critclk_systems[] = {
{
.ident = "MPL CEC1x",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MPL AG"),
DMI_MATCH(DMI_PRODUCT_NAME, "CEC10 Family"),
},
},
{ /*sentinel*/ }
};
static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap,
const struct pmc_data *pmc_data)
{
struct platform_device *clkdev;
struct pmc_clk_data *clk_data;
const struct dmi_system_id *d = dmi_first_match(critclk_systems);
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data)
......@@ -403,6 +420,10 @@ static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap,
clk_data->base = pmc_regmap; /* offset is added by client */
clk_data->clks = pmc_data->clks;
if (d) {
clk_data->critical = true;
pr_info("%s critclks quirk enabled\n", d->ident);
}
clkdev = platform_device_register_data(&pdev->dev, "clk-pmc-atom",
PLATFORM_DEVID_NONE,
......
......@@ -35,10 +35,13 @@ struct pmc_clk {
*
* @base: PMC clock register base offset
* @clks: pointer to set of registered clocks, typically 0..5
* @critical: flag to indicate if firmware enabled pmc_plt_clks
* should be marked as critial or not
*/
struct pmc_clk_data {
void __iomem *base;
const struct pmc_clk *clks;
bool critical;
};
#endif /* __PLATFORM_DATA_X86_CLK_PMC_ATOM_H */
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