Skip to content

Rpi 4.4.y clk driver fixes #1472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions drivers/clk/bcm/clk-bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ struct bcm2835_clock_data {
/* Number of fractional bits in the divider */
u32 frac_bits;

u32 flags;

bool is_vpu_clock;
bool is_mash_clock;
};
Expand Down Expand Up @@ -1018,23 +1020,46 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
return 0;
}

static bool
bcm2835_clk_is_pllc(struct clk_hw *hw)
{
if (!hw)
return false;

return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
}

static int bcm2835_clock_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct clk_hw *parent, *best_parent = NULL;
bool current_parent_is_pllc;
unsigned long rate, best_rate = 0;
unsigned long prate, best_prate = 0;
size_t i;
u32 div;

current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw));

/*
* Select parent clock that results in the closest but lower rate
*/
for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;

/*
* Don't choose a PLLC-derived clock as our parent
* unless it had been manually set that way. PLLC's
* frequency gets adjusted by the firmware due to
* over-temp or under-voltage conditions, without
* prior notification to our clock consumer.
*/
if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
continue;

prate = clk_hw_get_rate(parent);
div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
Expand Down Expand Up @@ -1242,7 +1267,16 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
init.parent_names = parents;
init.num_parents = data->num_mux_parents;
init.name = data->name;
init.flags = CLK_IGNORE_UNUSED;
init.flags = data->flags | CLK_IGNORE_UNUSED;

/*
* Some GPIO clocks for ethernet/wifi PLLs are marked as
* critical (since some platforms use them), but if the
* firmware didn't have them turned on then they clearly
* aren't actually critical.
*/
if ((cprman_read(cprman, data->ctl_reg) & CM_ENABLE) == 0)
init.flags &= ~CLK_IS_CRITICAL;

if (data->is_vpu_clock) {
init.ops = &bcm2835_vpu_clock_clk_ops;
Expand Down Expand Up @@ -1661,6 +1695,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.div_reg = CM_VPUDIV,
.int_bits = 12,
.frac_bits = 8,
.flags = CLK_IS_CRITICAL,
.is_vpu_clock = true),

/* clocks with per parent mux */
Expand Down Expand Up @@ -1717,13 +1752,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.div_reg = CM_GP1DIV,
.int_bits = 12,
.frac_bits = 12,
.flags = CLK_IS_CRITICAL,
.is_mash_clock = true),
[BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
.name = "gp2",
.ctl_reg = CM_GP2CTL,
.div_reg = CM_GP2DIV,
.int_bits = 12,
.frac_bits = 12),
.frac_bits = 12,
.flags = CLK_IS_CRITICAL),

/* HDMI state machine */
[BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
Expand Down
5 changes: 5 additions & 0 deletions drivers/clk/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -2466,6 +2466,11 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
if (core->ops->init)
core->ops->init(core->hw);

if (core->flags & CLK_IS_CRITICAL) {
clk_core_prepare(core);
clk_core_enable(core);
}

kref_init(&core->ref);
out:
clk_prepare_unlock();
Expand Down
1 change: 1 addition & 0 deletions include/linux/clk-provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
#define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */
#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */

struct clk;
struct clk_hw;
Expand Down