diff options
author | Dmitry Osipenko <digetx@gmail.com> | 2019-04-14 15:23:18 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2019-04-25 16:54:20 -0400 |
commit | 888ca40e2843a24d2d4830780a4a5705a3fb219a (patch) | |
tree | c86bc1c8a807f67eaa80d0c392a349f0bc566cb3 | |
parent | 924ee3d551c9deb16090230b824988bd37e72aa8 (diff) |
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>
-rw-r--r-- | drivers/clk/tegra/clk-emc.c | 37 |
1 files changed, 23 insertions, 14 deletions
diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 23416982e7c7..28068584ff6e 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c | |||
@@ -121,18 +121,23 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) | |||
121 | struct tegra_clk_emc *tegra; | 121 | struct tegra_clk_emc *tegra; |
122 | u8 ram_code = tegra_read_ram_code(); | 122 | u8 ram_code = tegra_read_ram_code(); |
123 | struct emc_timing *timing = NULL; | 123 | struct emc_timing *timing = NULL; |
124 | int i; | 124 | int i, k; |
125 | 125 | ||
126 | tegra = container_of(hw, struct tegra_clk_emc, hw); | 126 | tegra = container_of(hw, struct tegra_clk_emc, hw); |
127 | 127 | ||
128 | for (i = 0; i < tegra->num_timings; i++) { | 128 | for (k = 0; k < tegra->num_timings; k++) { |
129 | if (tegra->timings[k].ram_code == ram_code) | ||
130 | break; | ||
131 | } | ||
132 | |||
133 | for (i = k; i < tegra->num_timings; i++) { | ||
129 | if (tegra->timings[i].ram_code != ram_code) | 134 | if (tegra->timings[i].ram_code != ram_code) |
130 | continue; | 135 | break; |
131 | 136 | ||
132 | timing = tegra->timings + i; | 137 | timing = tegra->timings + i; |
133 | 138 | ||
134 | if (timing->rate > req->max_rate) { | 139 | if (timing->rate > req->max_rate) { |
135 | i = max(i, 1); | 140 | i = max(i, k + 1); |
136 | req->rate = tegra->timings[i - 1].rate; | 141 | req->rate = tegra->timings[i - 1].rate; |
137 | return 0; | 142 | return 0; |
138 | } | 143 | } |
@@ -282,7 +287,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra, | |||
282 | for (i = timing_index+1; i < tegra->num_timings; i++) { | 287 | for (i = timing_index+1; i < tegra->num_timings; i++) { |
283 | timing = tegra->timings + i; | 288 | timing = tegra->timings + i; |
284 | if (timing->ram_code != ram_code) | 289 | if (timing->ram_code != ram_code) |
285 | continue; | 290 | break; |
286 | 291 | ||
287 | if (emc_parent_clk_sources[timing->parent_index] != | 292 | if (emc_parent_clk_sources[timing->parent_index] != |
288 | emc_parent_clk_sources[ | 293 | emc_parent_clk_sources[ |
@@ -293,7 +298,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra, | |||
293 | for (i = timing_index-1; i >= 0; --i) { | 298 | for (i = timing_index-1; i >= 0; --i) { |
294 | timing = tegra->timings + i; | 299 | timing = tegra->timings + i; |
295 | if (timing->ram_code != ram_code) | 300 | if (timing->ram_code != ram_code) |
296 | continue; | 301 | break; |
297 | 302 | ||
298 | if (emc_parent_clk_sources[timing->parent_index] != | 303 | if (emc_parent_clk_sources[timing->parent_index] != |
299 | emc_parent_clk_sources[ | 304 | emc_parent_clk_sources[ |
@@ -433,19 +438,23 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra, | |||
433 | struct device_node *node, | 438 | struct device_node *node, |
434 | u32 ram_code) | 439 | u32 ram_code) |
435 | { | 440 | { |
441 | struct emc_timing *timings_ptr; | ||
436 | struct device_node *child; | 442 | struct device_node *child; |
437 | int child_count = of_get_child_count(node); | 443 | int child_count = of_get_child_count(node); |
438 | int i = 0, err; | 444 | int i = 0, err; |
445 | size_t size; | ||
446 | |||
447 | size = (tegra->num_timings + child_count) * sizeof(struct emc_timing); | ||
439 | 448 | ||
440 | tegra->timings = kcalloc(child_count, sizeof(struct emc_timing), | 449 | tegra->timings = krealloc(tegra->timings, size, GFP_KERNEL); |
441 | GFP_KERNEL); | ||
442 | if (!tegra->timings) | 450 | if (!tegra->timings) |
443 | return -ENOMEM; | 451 | return -ENOMEM; |
444 | 452 | ||
445 | tegra->num_timings = child_count; | 453 | timings_ptr = tegra->timings + tegra->num_timings; |
454 | tegra->num_timings += child_count; | ||
446 | 455 | ||
447 | for_each_child_of_node(node, child) { | 456 | for_each_child_of_node(node, child) { |
448 | struct emc_timing *timing = tegra->timings + (i++); | 457 | struct emc_timing *timing = timings_ptr + (i++); |
449 | 458 | ||
450 | err = load_one_timing_from_dt(tegra, timing, child); | 459 | err = load_one_timing_from_dt(tegra, timing, child); |
451 | if (err) { | 460 | if (err) { |
@@ -456,7 +465,7 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra, | |||
456 | timing->ram_code = ram_code; | 465 | timing->ram_code = ram_code; |
457 | } | 466 | } |
458 | 467 | ||
459 | sort(tegra->timings, tegra->num_timings, sizeof(struct emc_timing), | 468 | sort(timings_ptr, child_count, sizeof(struct emc_timing), |
460 | cmp_timings, NULL); | 469 | cmp_timings, NULL); |
461 | 470 | ||
462 | return 0; | 471 | return 0; |
@@ -499,10 +508,10 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, | |||
499 | * fuses until the apbmisc driver is loaded. | 508 | * fuses until the apbmisc driver is loaded. |
500 | */ | 509 | */ |
501 | err = load_timings_from_dt(tegra, node, node_ram_code); | 510 | err = load_timings_from_dt(tegra, node, node_ram_code); |
502 | of_node_put(node); | 511 | if (err) { |
503 | if (err) | 512 | of_node_put(node); |
504 | return ERR_PTR(err); | 513 | return ERR_PTR(err); |
505 | break; | 514 | } |
506 | } | 515 | } |
507 | 516 | ||
508 | if (tegra->num_timings == 0) | 517 | if (tegra->num_timings == 0) |