clk: tegra: emc: Support multiple RAM codes
The timings parser doesn't append timings, but instead it parses only the first timing and hence doesn't store all of the timings when device-tree has timings for multiple RAM codes. In a result EMC scaling doesn't work if timings are missing. Tested-by: Steev Klimaszewski <steev@kali.org> Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
parent
924ee3d551
commit
888ca40e28
|
@ -121,18 +121,23 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
|
||||||
struct tegra_clk_emc *tegra;
|
struct tegra_clk_emc *tegra;
|
||||||
u8 ram_code = tegra_read_ram_code();
|
u8 ram_code = tegra_read_ram_code();
|
||||||
struct emc_timing *timing = NULL;
|
struct emc_timing *timing = NULL;
|
||||||
int i;
|
int i, k;
|
||||||
|
|
||||||
tegra = container_of(hw, struct tegra_clk_emc, hw);
|
tegra = container_of(hw, struct tegra_clk_emc, hw);
|
||||||
|
|
||||||
for (i = 0; i < tegra->num_timings; i++) {
|
for (k = 0; k < tegra->num_timings; k++) {
|
||||||
|
if (tegra->timings[k].ram_code == ram_code)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = k; i < tegra->num_timings; i++) {
|
||||||
if (tegra->timings[i].ram_code != ram_code)
|
if (tegra->timings[i].ram_code != ram_code)
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
timing = tegra->timings + i;
|
timing = tegra->timings + i;
|
||||||
|
|
||||||
if (timing->rate > req->max_rate) {
|
if (timing->rate > req->max_rate) {
|
||||||
i = max(i, 1);
|
i = max(i, k + 1);
|
||||||
req->rate = tegra->timings[i - 1].rate;
|
req->rate = tegra->timings[i - 1].rate;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +287,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra,
|
||||||
for (i = timing_index+1; i < tegra->num_timings; i++) {
|
for (i = timing_index+1; i < tegra->num_timings; i++) {
|
||||||
timing = tegra->timings + i;
|
timing = tegra->timings + i;
|
||||||
if (timing->ram_code != ram_code)
|
if (timing->ram_code != ram_code)
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
if (emc_parent_clk_sources[timing->parent_index] !=
|
if (emc_parent_clk_sources[timing->parent_index] !=
|
||||||
emc_parent_clk_sources[
|
emc_parent_clk_sources[
|
||||||
|
@ -293,7 +298,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra,
|
||||||
for (i = timing_index-1; i >= 0; --i) {
|
for (i = timing_index-1; i >= 0; --i) {
|
||||||
timing = tegra->timings + i;
|
timing = tegra->timings + i;
|
||||||
if (timing->ram_code != ram_code)
|
if (timing->ram_code != ram_code)
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
if (emc_parent_clk_sources[timing->parent_index] !=
|
if (emc_parent_clk_sources[timing->parent_index] !=
|
||||||
emc_parent_clk_sources[
|
emc_parent_clk_sources[
|
||||||
|
@ -433,19 +438,23 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra,
|
||||||
struct device_node *node,
|
struct device_node *node,
|
||||||
u32 ram_code)
|
u32 ram_code)
|
||||||
{
|
{
|
||||||
|
struct emc_timing *timings_ptr;
|
||||||
struct device_node *child;
|
struct device_node *child;
|
||||||
int child_count = of_get_child_count(node);
|
int child_count = of_get_child_count(node);
|
||||||
int i = 0, err;
|
int i = 0, err;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
tegra->timings = kcalloc(child_count, sizeof(struct emc_timing),
|
size = (tegra->num_timings + child_count) * sizeof(struct emc_timing);
|
||||||
GFP_KERNEL);
|
|
||||||
|
tegra->timings = krealloc(tegra->timings, size, GFP_KERNEL);
|
||||||
if (!tegra->timings)
|
if (!tegra->timings)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
tegra->num_timings = child_count;
|
timings_ptr = tegra->timings + tegra->num_timings;
|
||||||
|
tegra->num_timings += child_count;
|
||||||
|
|
||||||
for_each_child_of_node(node, child) {
|
for_each_child_of_node(node, child) {
|
||||||
struct emc_timing *timing = tegra->timings + (i++);
|
struct emc_timing *timing = timings_ptr + (i++);
|
||||||
|
|
||||||
err = load_one_timing_from_dt(tegra, timing, child);
|
err = load_one_timing_from_dt(tegra, timing, child);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -456,7 +465,7 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra,
|
||||||
timing->ram_code = ram_code;
|
timing->ram_code = ram_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
sort(tegra->timings, tegra->num_timings, sizeof(struct emc_timing),
|
sort(timings_ptr, child_count, sizeof(struct emc_timing),
|
||||||
cmp_timings, NULL);
|
cmp_timings, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -499,10 +508,10 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
|
||||||
* fuses until the apbmisc driver is loaded.
|
* fuses until the apbmisc driver is loaded.
|
||||||
*/
|
*/
|
||||||
err = load_timings_from_dt(tegra, node, node_ram_code);
|
err = load_timings_from_dt(tegra, node, node_ram_code);
|
||||||
|
if (err) {
|
||||||
of_node_put(node);
|
of_node_put(node);
|
||||||
if (err)
|
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tegra->num_timings == 0)
|
if (tegra->num_timings == 0)
|
||||||
|
|
Loading…
Reference in New Issue