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 -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAlyxC/IRHHNib3lkQGtl cm5lbC5vcmcACgkQrQKIl8bklSWPTg//Q9CXbOYC64u2LEMtMKFtxS0UobjFKyMg EfRnHM3EuRKHCSPLtcr5bKQkFQYJ7Qx9A8oQm4v1d0KlQ2HyrOuAjfAkCaKweKSK iXpvWQMHcyRNPmPhzaDnuGBVXptOQ+kfwjWT4/nbkjW0bnFTwpvx9I5pdUd3UOJv IdnYOLKAF8Uwt2nyJd++Bh0UeBhQ1XIl9P46iZGa43nQsQhgSaru3oBnhVOzEti/ k9Di3H1k1wIKR+xDujl/S3vIIEUcx0eGkL86sFdVq6nYwdQQZKusESC0vh5QJ/Ax LLSJcdoM8B84zStkYgIskdltdMZmsUUjLjjEbF5iq1my+LwQZ3JLWkY/gXMeF2Mu t5S/TVe5GwqKw2tmoQYkR2Qz76x7/DauZEdUcYtu+K9D2ye5aNDsNNCHlFkamN2N EJkBXDqpKGHkyOdUGmL+B0W6D1KxwJEREkCh0aIpbVci1PjfxvI6PLJBF907RkLx UNDF/flLoOMy+iUl0ZC05Ie06CkzJMf1e7mMaIIS/FfC7UJ4yNVEHyCADzyrCLOB XWwmwCea5NnIi3EQP91a7WO/Gr+yUWxfrQ3viNqM3KbPKOurofMp/JvDnu8bX31O l+yiRfpdjIaKUdyDLnTaq3UGBlBlFnqFOWkjRmmMzRZoBmwZhCN7H30LIlqnqnpQ wsvhawe24UY= =JS0o -----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: "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
This commit is contained in:
commit
09bad0df39
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue