.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * clk-dfll.c - Tegra DFLL clock source common code |
---|
3 | 4 | * |
---|
4 | | - * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved. |
---|
| 5 | + * Copyright (C) 2012-2019 NVIDIA Corporation. All rights reserved. |
---|
5 | 6 | * |
---|
6 | 7 | * Aleksandr Frid <afrid@nvidia.com> |
---|
7 | 8 | * Paul Walmsley <pwalmsley@nvidia.com> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License version 2 as |
---|
11 | | - * published by the Free Software Foundation. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
14 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
15 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
16 | | - * more details. |
---|
17 | 9 | * |
---|
18 | 10 | * This library is for the DVCO and DFLL IP blocks on the Tegra124 |
---|
19 | 11 | * SoC. These IP blocks together are also known at NVIDIA as |
---|
.. | .. |
---|
34 | 26 | * CPU cycle time will vary. This has implications for |
---|
35 | 27 | * performance-measurement code and any code that relies on the CPU |
---|
36 | 28 | * cycle time to delay for a certain length of time. |
---|
37 | | - * |
---|
38 | 29 | */ |
---|
39 | 30 | |
---|
40 | 31 | #include <linux/clk.h> |
---|
.. | .. |
---|
47 | 38 | #include <linux/kernel.h> |
---|
48 | 39 | #include <linux/module.h> |
---|
49 | 40 | #include <linux/of.h> |
---|
| 41 | +#include <linux/pinctrl/consumer.h> |
---|
50 | 42 | #include <linux/pm_opp.h> |
---|
51 | 43 | #include <linux/pm_runtime.h> |
---|
52 | 44 | #include <linux/regmap.h> |
---|
.. | .. |
---|
243 | 235 | DFLL_TUNE_LOW = 1, |
---|
244 | 236 | }; |
---|
245 | 237 | |
---|
| 238 | + |
---|
| 239 | +enum tegra_dfll_pmu_if { |
---|
| 240 | + TEGRA_DFLL_PMU_I2C = 0, |
---|
| 241 | + TEGRA_DFLL_PMU_PWM = 1, |
---|
| 242 | +}; |
---|
| 243 | + |
---|
246 | 244 | /** |
---|
247 | 245 | * struct dfll_rate_req - target DFLL rate request data |
---|
248 | 246 | * @rate: target frequency, after the postscaling |
---|
.. | .. |
---|
300 | 298 | u32 i2c_reg; |
---|
301 | 299 | u32 i2c_slave_addr; |
---|
302 | 300 | |
---|
303 | | - /* i2c_lut array entries are regulator framework selectors */ |
---|
304 | | - unsigned i2c_lut[MAX_DFLL_VOLTAGES]; |
---|
305 | | - int i2c_lut_size; |
---|
306 | | - u8 lut_min, lut_max, lut_safe; |
---|
| 301 | + /* lut array entries are regulator framework selectors or PWM values*/ |
---|
| 302 | + unsigned lut[MAX_DFLL_VOLTAGES]; |
---|
| 303 | + unsigned long lut_uv[MAX_DFLL_VOLTAGES]; |
---|
| 304 | + int lut_size; |
---|
| 305 | + u8 lut_bottom, lut_min, lut_max, lut_safe; |
---|
| 306 | + |
---|
| 307 | + /* PWM interface */ |
---|
| 308 | + enum tegra_dfll_pmu_if pmu_if; |
---|
| 309 | + unsigned long pwm_rate; |
---|
| 310 | + struct pinctrl *pwm_pin; |
---|
| 311 | + struct pinctrl_state *pwm_enable_state; |
---|
| 312 | + struct pinctrl_state *pwm_disable_state; |
---|
| 313 | + u32 reg_init_uV; |
---|
307 | 314 | }; |
---|
308 | 315 | |
---|
309 | 316 | #define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw) |
---|
.. | .. |
---|
490 | 497 | } |
---|
491 | 498 | |
---|
492 | 499 | /* |
---|
| 500 | + * DVCO rate control |
---|
| 501 | + */ |
---|
| 502 | + |
---|
| 503 | +static unsigned long get_dvco_rate_below(struct tegra_dfll *td, u8 out_min) |
---|
| 504 | +{ |
---|
| 505 | + struct dev_pm_opp *opp; |
---|
| 506 | + unsigned long rate, prev_rate; |
---|
| 507 | + unsigned long uv, min_uv; |
---|
| 508 | + |
---|
| 509 | + min_uv = td->lut_uv[out_min]; |
---|
| 510 | + for (rate = 0, prev_rate = 0; ; rate++) { |
---|
| 511 | + opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); |
---|
| 512 | + if (IS_ERR(opp)) |
---|
| 513 | + break; |
---|
| 514 | + |
---|
| 515 | + uv = dev_pm_opp_get_voltage(opp); |
---|
| 516 | + dev_pm_opp_put(opp); |
---|
| 517 | + |
---|
| 518 | + if (uv && uv > min_uv) |
---|
| 519 | + return prev_rate; |
---|
| 520 | + |
---|
| 521 | + prev_rate = rate; |
---|
| 522 | + } |
---|
| 523 | + |
---|
| 524 | + return prev_rate; |
---|
| 525 | +} |
---|
| 526 | + |
---|
| 527 | +/* |
---|
493 | 528 | * DFLL-to-I2C controller interface |
---|
494 | 529 | */ |
---|
495 | 530 | |
---|
.. | .. |
---|
518 | 553 | return 0; |
---|
519 | 554 | } |
---|
520 | 555 | |
---|
| 556 | + |
---|
| 557 | +/* |
---|
| 558 | + * DFLL-to-PWM controller interface |
---|
| 559 | + */ |
---|
| 560 | + |
---|
| 561 | +/** |
---|
| 562 | + * dfll_pwm_set_output_enabled - enable/disable PWM voltage requests |
---|
| 563 | + * @td: DFLL instance |
---|
| 564 | + * @enable: whether to enable or disable the PWM voltage requests |
---|
| 565 | + * |
---|
| 566 | + * Set the master enable control for PWM control value updates. If disabled, |
---|
| 567 | + * then the PWM signal is not driven. Also configure the PWM output pad |
---|
| 568 | + * to the appropriate state. |
---|
| 569 | + */ |
---|
| 570 | +static int dfll_pwm_set_output_enabled(struct tegra_dfll *td, bool enable) |
---|
| 571 | +{ |
---|
| 572 | + int ret; |
---|
| 573 | + u32 val, div; |
---|
| 574 | + |
---|
| 575 | + if (enable) { |
---|
| 576 | + ret = pinctrl_select_state(td->pwm_pin, td->pwm_enable_state); |
---|
| 577 | + if (ret < 0) { |
---|
| 578 | + dev_err(td->dev, "setting enable state failed\n"); |
---|
| 579 | + return -EINVAL; |
---|
| 580 | + } |
---|
| 581 | + val = dfll_readl(td, DFLL_OUTPUT_CFG); |
---|
| 582 | + val &= ~DFLL_OUTPUT_CFG_PWM_DIV_MASK; |
---|
| 583 | + div = DIV_ROUND_UP(td->ref_rate, td->pwm_rate); |
---|
| 584 | + val |= (div << DFLL_OUTPUT_CFG_PWM_DIV_SHIFT) |
---|
| 585 | + & DFLL_OUTPUT_CFG_PWM_DIV_MASK; |
---|
| 586 | + dfll_writel(td, val, DFLL_OUTPUT_CFG); |
---|
| 587 | + dfll_wmb(td); |
---|
| 588 | + |
---|
| 589 | + val |= DFLL_OUTPUT_CFG_PWM_ENABLE; |
---|
| 590 | + dfll_writel(td, val, DFLL_OUTPUT_CFG); |
---|
| 591 | + dfll_wmb(td); |
---|
| 592 | + } else { |
---|
| 593 | + ret = pinctrl_select_state(td->pwm_pin, td->pwm_disable_state); |
---|
| 594 | + if (ret < 0) |
---|
| 595 | + dev_warn(td->dev, "setting disable state failed\n"); |
---|
| 596 | + |
---|
| 597 | + val = dfll_readl(td, DFLL_OUTPUT_CFG); |
---|
| 598 | + val &= ~DFLL_OUTPUT_CFG_PWM_ENABLE; |
---|
| 599 | + dfll_writel(td, val, DFLL_OUTPUT_CFG); |
---|
| 600 | + dfll_wmb(td); |
---|
| 601 | + } |
---|
| 602 | + |
---|
| 603 | + return 0; |
---|
| 604 | +} |
---|
| 605 | + |
---|
| 606 | +/** |
---|
| 607 | + * dfll_set_force_output_value - set fixed value for force output |
---|
| 608 | + * @td: DFLL instance |
---|
| 609 | + * @out_val: value to force output |
---|
| 610 | + * |
---|
| 611 | + * Set the fixed value for force output, DFLL will output this value when |
---|
| 612 | + * force output is enabled. |
---|
| 613 | + */ |
---|
| 614 | +static u32 dfll_set_force_output_value(struct tegra_dfll *td, u8 out_val) |
---|
| 615 | +{ |
---|
| 616 | + u32 val = dfll_readl(td, DFLL_OUTPUT_FORCE); |
---|
| 617 | + |
---|
| 618 | + val = (val & DFLL_OUTPUT_FORCE_ENABLE) | (out_val & OUT_MASK); |
---|
| 619 | + dfll_writel(td, val, DFLL_OUTPUT_FORCE); |
---|
| 620 | + dfll_wmb(td); |
---|
| 621 | + |
---|
| 622 | + return dfll_readl(td, DFLL_OUTPUT_FORCE); |
---|
| 623 | +} |
---|
| 624 | + |
---|
| 625 | +/** |
---|
| 626 | + * dfll_set_force_output_enabled - enable/disable force output |
---|
| 627 | + * @td: DFLL instance |
---|
| 628 | + * @enable: whether to enable or disable the force output |
---|
| 629 | + * |
---|
| 630 | + * Set the enable control for fouce output with fixed value. |
---|
| 631 | + */ |
---|
| 632 | +static void dfll_set_force_output_enabled(struct tegra_dfll *td, bool enable) |
---|
| 633 | +{ |
---|
| 634 | + u32 val = dfll_readl(td, DFLL_OUTPUT_FORCE); |
---|
| 635 | + |
---|
| 636 | + if (enable) |
---|
| 637 | + val |= DFLL_OUTPUT_FORCE_ENABLE; |
---|
| 638 | + else |
---|
| 639 | + val &= ~DFLL_OUTPUT_FORCE_ENABLE; |
---|
| 640 | + |
---|
| 641 | + dfll_writel(td, val, DFLL_OUTPUT_FORCE); |
---|
| 642 | + dfll_wmb(td); |
---|
| 643 | +} |
---|
| 644 | + |
---|
| 645 | +/** |
---|
| 646 | + * dfll_force_output - force output a fixed value |
---|
| 647 | + * @td: DFLL instance |
---|
| 648 | + * @out_sel: value to force output |
---|
| 649 | + * |
---|
| 650 | + * Set the fixed value for force output, DFLL will output this value. |
---|
| 651 | + */ |
---|
| 652 | +static int dfll_force_output(struct tegra_dfll *td, unsigned int out_sel) |
---|
| 653 | +{ |
---|
| 654 | + u32 val; |
---|
| 655 | + |
---|
| 656 | + if (out_sel > OUT_MASK) |
---|
| 657 | + return -EINVAL; |
---|
| 658 | + |
---|
| 659 | + val = dfll_set_force_output_value(td, out_sel); |
---|
| 660 | + if ((td->mode < DFLL_CLOSED_LOOP) && |
---|
| 661 | + !(val & DFLL_OUTPUT_FORCE_ENABLE)) { |
---|
| 662 | + dfll_set_force_output_enabled(td, true); |
---|
| 663 | + } |
---|
| 664 | + |
---|
| 665 | + return 0; |
---|
| 666 | +} |
---|
| 667 | + |
---|
521 | 668 | /** |
---|
522 | 669 | * dfll_load_lut - load the voltage lookup table |
---|
523 | 670 | * @td: struct tegra_dfll * |
---|
.. | .. |
---|
539 | 686 | lut_index = i; |
---|
540 | 687 | |
---|
541 | 688 | val = regulator_list_hardware_vsel(td->vdd_reg, |
---|
542 | | - td->i2c_lut[lut_index]); |
---|
| 689 | + td->lut[lut_index]); |
---|
543 | 690 | __raw_writel(val, td->lut_base + i * 4); |
---|
544 | 691 | } |
---|
545 | 692 | |
---|
.. | .. |
---|
594 | 741 | { |
---|
595 | 742 | u32 val; |
---|
596 | 743 | |
---|
597 | | - td->lut_min = 0; |
---|
598 | | - td->lut_max = td->i2c_lut_size - 1; |
---|
599 | | - td->lut_safe = td->lut_min + 1; |
---|
| 744 | + td->lut_min = td->lut_bottom; |
---|
| 745 | + td->lut_max = td->lut_size - 1; |
---|
| 746 | + td->lut_safe = td->lut_min + (td->lut_min < td->lut_max ? 1 : 0); |
---|
600 | 747 | |
---|
601 | | - dfll_i2c_writel(td, 0, DFLL_OUTPUT_CFG); |
---|
| 748 | + /* clear DFLL_OUTPUT_CFG before setting new value */ |
---|
| 749 | + dfll_writel(td, 0, DFLL_OUTPUT_CFG); |
---|
| 750 | + dfll_wmb(td); |
---|
| 751 | + |
---|
602 | 752 | val = (td->lut_safe << DFLL_OUTPUT_CFG_SAFE_SHIFT) | |
---|
603 | | - (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) | |
---|
604 | | - (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT); |
---|
605 | | - dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG); |
---|
606 | | - dfll_i2c_wmb(td); |
---|
| 753 | + (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) | |
---|
| 754 | + (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT); |
---|
| 755 | + dfll_writel(td, val, DFLL_OUTPUT_CFG); |
---|
| 756 | + dfll_wmb(td); |
---|
607 | 757 | |
---|
608 | 758 | dfll_writel(td, 0, DFLL_OUTPUT_FORCE); |
---|
609 | 759 | dfll_i2c_writel(td, 0, DFLL_INTR_EN); |
---|
610 | 760 | dfll_i2c_writel(td, DFLL_INTR_MAX_MASK | DFLL_INTR_MIN_MASK, |
---|
611 | 761 | DFLL_INTR_STS); |
---|
612 | 762 | |
---|
613 | | - dfll_load_i2c_lut(td); |
---|
614 | | - dfll_init_i2c_if(td); |
---|
| 763 | + if (td->pmu_if == TEGRA_DFLL_PMU_PWM) { |
---|
| 764 | + u32 vinit = td->reg_init_uV; |
---|
| 765 | + int vstep = td->soc->alignment.step_uv; |
---|
| 766 | + unsigned long vmin = td->lut_uv[0]; |
---|
| 767 | + |
---|
| 768 | + /* set initial voltage */ |
---|
| 769 | + if ((vinit >= vmin) && vstep) { |
---|
| 770 | + unsigned int vsel; |
---|
| 771 | + |
---|
| 772 | + vsel = DIV_ROUND_UP((vinit - vmin), vstep); |
---|
| 773 | + dfll_force_output(td, vsel); |
---|
| 774 | + } |
---|
| 775 | + } else { |
---|
| 776 | + dfll_load_i2c_lut(td); |
---|
| 777 | + dfll_init_i2c_if(td); |
---|
| 778 | + } |
---|
615 | 779 | } |
---|
616 | 780 | |
---|
617 | 781 | /* |
---|
.. | .. |
---|
631 | 795 | static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate) |
---|
632 | 796 | { |
---|
633 | 797 | struct dev_pm_opp *opp; |
---|
634 | | - int i, uv; |
---|
| 798 | + int i, align_step; |
---|
635 | 799 | |
---|
636 | 800 | opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); |
---|
637 | 801 | if (IS_ERR(opp)) |
---|
638 | 802 | return PTR_ERR(opp); |
---|
639 | 803 | |
---|
640 | | - uv = dev_pm_opp_get_voltage(opp); |
---|
| 804 | + align_step = dev_pm_opp_get_voltage(opp) / td->soc->alignment.step_uv; |
---|
641 | 805 | dev_pm_opp_put(opp); |
---|
642 | 806 | |
---|
643 | | - for (i = 0; i < td->i2c_lut_size; i++) { |
---|
644 | | - if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv) |
---|
| 807 | + for (i = td->lut_bottom; i < td->lut_size; i++) { |
---|
| 808 | + if ((td->lut_uv[i] / td->soc->alignment.step_uv) >= align_step) |
---|
645 | 809 | return i; |
---|
646 | 810 | } |
---|
647 | 811 | |
---|
.. | .. |
---|
863 | 1027 | return -EINVAL; |
---|
864 | 1028 | } |
---|
865 | 1029 | |
---|
866 | | - dfll_i2c_set_output_enabled(td, true); |
---|
| 1030 | + if (td->pmu_if == TEGRA_DFLL_PMU_PWM) |
---|
| 1031 | + dfll_pwm_set_output_enabled(td, true); |
---|
| 1032 | + else |
---|
| 1033 | + dfll_i2c_set_output_enabled(td, true); |
---|
| 1034 | + |
---|
867 | 1035 | dfll_set_mode(td, DFLL_CLOSED_LOOP); |
---|
868 | 1036 | dfll_set_frequency_request(td, req); |
---|
| 1037 | + dfll_set_force_output_enabled(td, false); |
---|
869 | 1038 | return 0; |
---|
870 | 1039 | |
---|
871 | 1040 | default: |
---|
.. | .. |
---|
889 | 1058 | case DFLL_CLOSED_LOOP: |
---|
890 | 1059 | dfll_set_open_loop_config(td); |
---|
891 | 1060 | dfll_set_mode(td, DFLL_OPEN_LOOP); |
---|
892 | | - dfll_i2c_set_output_enabled(td, false); |
---|
| 1061 | + if (td->pmu_if == TEGRA_DFLL_PMU_PWM) |
---|
| 1062 | + dfll_pwm_set_output_enabled(td, false); |
---|
| 1063 | + else |
---|
| 1064 | + dfll_i2c_set_output_enabled(td, false); |
---|
893 | 1065 | return 0; |
---|
894 | 1066 | |
---|
895 | 1067 | case DFLL_OPEN_LOOP: |
---|
.. | .. |
---|
1112 | 1284 | |
---|
1113 | 1285 | return val ? dfll_enable(td) : dfll_disable(td); |
---|
1114 | 1286 | } |
---|
1115 | | -DEFINE_SIMPLE_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, |
---|
1116 | | - "%llu\n"); |
---|
| 1287 | +DEFINE_DEBUGFS_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, |
---|
| 1288 | + "%llu\n"); |
---|
1117 | 1289 | |
---|
1118 | 1290 | static int attr_lock_get(void *data, u64 *val) |
---|
1119 | 1291 | { |
---|
.. | .. |
---|
1129 | 1301 | |
---|
1130 | 1302 | return val ? dfll_lock(td) : dfll_unlock(td); |
---|
1131 | 1303 | } |
---|
1132 | | -DEFINE_SIMPLE_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set, |
---|
1133 | | - "%llu\n"); |
---|
| 1304 | +DEFINE_DEBUGFS_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set, "%llu\n"); |
---|
1134 | 1305 | |
---|
1135 | 1306 | static int attr_rate_get(void *data, u64 *val) |
---|
1136 | 1307 | { |
---|
.. | .. |
---|
1147 | 1318 | |
---|
1148 | 1319 | return dfll_request_rate(td, val); |
---|
1149 | 1320 | } |
---|
1150 | | -DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n"); |
---|
| 1321 | +DEFINE_DEBUGFS_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n"); |
---|
1151 | 1322 | |
---|
1152 | 1323 | static int attr_registers_show(struct seq_file *s, void *data) |
---|
1153 | 1324 | { |
---|
.. | .. |
---|
1171 | 1342 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, |
---|
1172 | 1343 | dfll_i2c_readl(td, offs)); |
---|
1173 | 1344 | |
---|
1174 | | - seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n"); |
---|
1175 | | - offs = DFLL_I2C_CLK_DIVISOR; |
---|
1176 | | - seq_printf(s, "[0x%02x] = 0x%08x\n", offs, |
---|
1177 | | - __raw_readl(td->i2c_controller_base + offs)); |
---|
1178 | | - |
---|
1179 | | - seq_puts(s, "\nLUT:\n"); |
---|
1180 | | - for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4) |
---|
| 1345 | + if (td->pmu_if == TEGRA_DFLL_PMU_I2C) { |
---|
| 1346 | + seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n"); |
---|
| 1347 | + offs = DFLL_I2C_CLK_DIVISOR; |
---|
1181 | 1348 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, |
---|
1182 | | - __raw_readl(td->lut_base + offs)); |
---|
| 1349 | + __raw_readl(td->i2c_controller_base + offs)); |
---|
| 1350 | + |
---|
| 1351 | + seq_puts(s, "\nLUT:\n"); |
---|
| 1352 | + for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4) |
---|
| 1353 | + seq_printf(s, "[0x%02x] = 0x%08x\n", offs, |
---|
| 1354 | + __raw_readl(td->lut_base + offs)); |
---|
| 1355 | + } |
---|
1183 | 1356 | |
---|
1184 | 1357 | return 0; |
---|
1185 | 1358 | } |
---|
1186 | 1359 | |
---|
1187 | | -static int attr_registers_open(struct inode *inode, struct file *file) |
---|
1188 | | -{ |
---|
1189 | | - return single_open(file, attr_registers_show, inode->i_private); |
---|
1190 | | -} |
---|
1191 | | - |
---|
1192 | | -static const struct file_operations attr_registers_fops = { |
---|
1193 | | - .open = attr_registers_open, |
---|
1194 | | - .read = seq_read, |
---|
1195 | | - .llseek = seq_lseek, |
---|
1196 | | - .release = single_release, |
---|
1197 | | -}; |
---|
| 1360 | +DEFINE_SHOW_ATTRIBUTE(attr_registers); |
---|
1198 | 1361 | |
---|
1199 | 1362 | static void dfll_debug_init(struct tegra_dfll *td) |
---|
1200 | 1363 | { |
---|
.. | .. |
---|
1206 | 1369 | root = debugfs_create_dir("tegra_dfll_fcpu", NULL); |
---|
1207 | 1370 | td->debugfs_dir = root; |
---|
1208 | 1371 | |
---|
1209 | | - debugfs_create_file("enable", S_IRUGO | S_IWUSR, root, td, &enable_fops); |
---|
1210 | | - debugfs_create_file("lock", S_IRUGO, root, td, &lock_fops); |
---|
1211 | | - debugfs_create_file("rate", S_IRUGO, root, td, &rate_fops); |
---|
1212 | | - debugfs_create_file("registers", S_IRUGO, root, td, &attr_registers_fops); |
---|
| 1372 | + debugfs_create_file_unsafe("enable", 0644, root, td, |
---|
| 1373 | + &enable_fops); |
---|
| 1374 | + debugfs_create_file_unsafe("lock", 0444, root, td, &lock_fops); |
---|
| 1375 | + debugfs_create_file_unsafe("rate", 0444, root, td, &rate_fops); |
---|
| 1376 | + debugfs_create_file("registers", 0444, root, td, &attr_registers_fops); |
---|
1213 | 1377 | } |
---|
1214 | 1378 | |
---|
1215 | 1379 | #else |
---|
.. | .. |
---|
1349 | 1513 | return ret; |
---|
1350 | 1514 | } |
---|
1351 | 1515 | |
---|
| 1516 | +/** |
---|
| 1517 | + * tegra_dfll_suspend - check DFLL is disabled |
---|
| 1518 | + * @dev: DFLL instance |
---|
| 1519 | + * |
---|
| 1520 | + * DFLL clock should be disabled by the CPUFreq driver. So, make |
---|
| 1521 | + * sure it is disabled and disable all clocks needed by the DFLL. |
---|
| 1522 | + */ |
---|
| 1523 | +int tegra_dfll_suspend(struct device *dev) |
---|
| 1524 | +{ |
---|
| 1525 | + struct tegra_dfll *td = dev_get_drvdata(dev); |
---|
| 1526 | + |
---|
| 1527 | + if (dfll_is_running(td)) { |
---|
| 1528 | + dev_err(td->dev, "DFLL still enabled while suspending\n"); |
---|
| 1529 | + return -EBUSY; |
---|
| 1530 | + } |
---|
| 1531 | + |
---|
| 1532 | + reset_control_assert(td->dvco_rst); |
---|
| 1533 | + |
---|
| 1534 | + return 0; |
---|
| 1535 | +} |
---|
| 1536 | +EXPORT_SYMBOL(tegra_dfll_suspend); |
---|
| 1537 | + |
---|
| 1538 | +/** |
---|
| 1539 | + * tegra_dfll_resume - reinitialize DFLL on resume |
---|
| 1540 | + * @dev: DFLL instance |
---|
| 1541 | + * |
---|
| 1542 | + * DFLL is disabled and reset during suspend and resume. |
---|
| 1543 | + * So, reinitialize the DFLL IP block back for use. |
---|
| 1544 | + * DFLL clock is enabled later in closed loop mode by CPUFreq |
---|
| 1545 | + * driver before switching its clock source to DFLL output. |
---|
| 1546 | + */ |
---|
| 1547 | +int tegra_dfll_resume(struct device *dev) |
---|
| 1548 | +{ |
---|
| 1549 | + struct tegra_dfll *td = dev_get_drvdata(dev); |
---|
| 1550 | + |
---|
| 1551 | + reset_control_deassert(td->dvco_rst); |
---|
| 1552 | + |
---|
| 1553 | + pm_runtime_get_sync(td->dev); |
---|
| 1554 | + |
---|
| 1555 | + dfll_set_mode(td, DFLL_DISABLED); |
---|
| 1556 | + dfll_set_default_params(td); |
---|
| 1557 | + |
---|
| 1558 | + if (td->soc->init_clock_trimmers) |
---|
| 1559 | + td->soc->init_clock_trimmers(); |
---|
| 1560 | + |
---|
| 1561 | + dfll_set_open_loop_config(td); |
---|
| 1562 | + |
---|
| 1563 | + dfll_init_out_if(td); |
---|
| 1564 | + |
---|
| 1565 | + pm_runtime_put_sync(td->dev); |
---|
| 1566 | + |
---|
| 1567 | + return 0; |
---|
| 1568 | +} |
---|
| 1569 | +EXPORT_SYMBOL(tegra_dfll_resume); |
---|
| 1570 | + |
---|
1352 | 1571 | /* |
---|
1353 | 1572 | * DT data fetch |
---|
1354 | 1573 | */ |
---|
.. | .. |
---|
1359 | 1578 | */ |
---|
1360 | 1579 | static int find_vdd_map_entry_exact(struct tegra_dfll *td, int uV) |
---|
1361 | 1580 | { |
---|
1362 | | - int i, n_voltages, reg_uV; |
---|
| 1581 | + int i, n_voltages, reg_uV,reg_volt_id, align_step; |
---|
1363 | 1582 | |
---|
| 1583 | + if (WARN_ON(td->pmu_if == TEGRA_DFLL_PMU_PWM)) |
---|
| 1584 | + return -EINVAL; |
---|
| 1585 | + |
---|
| 1586 | + align_step = uV / td->soc->alignment.step_uv; |
---|
1364 | 1587 | n_voltages = regulator_count_voltages(td->vdd_reg); |
---|
1365 | 1588 | for (i = 0; i < n_voltages; i++) { |
---|
1366 | 1589 | reg_uV = regulator_list_voltage(td->vdd_reg, i); |
---|
1367 | 1590 | if (reg_uV < 0) |
---|
1368 | 1591 | break; |
---|
1369 | 1592 | |
---|
1370 | | - if (uV == reg_uV) |
---|
| 1593 | + reg_volt_id = reg_uV / td->soc->alignment.step_uv; |
---|
| 1594 | + |
---|
| 1595 | + if (align_step == reg_volt_id) |
---|
1371 | 1596 | return i; |
---|
1372 | 1597 | } |
---|
1373 | 1598 | |
---|
.. | .. |
---|
1381 | 1606 | * */ |
---|
1382 | 1607 | static int find_vdd_map_entry_min(struct tegra_dfll *td, int uV) |
---|
1383 | 1608 | { |
---|
1384 | | - int i, n_voltages, reg_uV; |
---|
| 1609 | + int i, n_voltages, reg_uV, reg_volt_id, align_step; |
---|
1385 | 1610 | |
---|
| 1611 | + if (WARN_ON(td->pmu_if == TEGRA_DFLL_PMU_PWM)) |
---|
| 1612 | + return -EINVAL; |
---|
| 1613 | + |
---|
| 1614 | + align_step = uV / td->soc->alignment.step_uv; |
---|
1386 | 1615 | n_voltages = regulator_count_voltages(td->vdd_reg); |
---|
1387 | 1616 | for (i = 0; i < n_voltages; i++) { |
---|
1388 | 1617 | reg_uV = regulator_list_voltage(td->vdd_reg, i); |
---|
1389 | 1618 | if (reg_uV < 0) |
---|
1390 | 1619 | break; |
---|
1391 | 1620 | |
---|
1392 | | - if (uV <= reg_uV) |
---|
| 1621 | + reg_volt_id = reg_uV / td->soc->alignment.step_uv; |
---|
| 1622 | + |
---|
| 1623 | + if (align_step <= reg_volt_id) |
---|
1393 | 1624 | return i; |
---|
1394 | 1625 | } |
---|
1395 | 1626 | |
---|
.. | .. |
---|
1397 | 1628 | return -EINVAL; |
---|
1398 | 1629 | } |
---|
1399 | 1630 | |
---|
| 1631 | +/* |
---|
| 1632 | + * dfll_build_pwm_lut - build the PWM regulator lookup table |
---|
| 1633 | + * @td: DFLL instance |
---|
| 1634 | + * @v_max: Vmax from OPP table |
---|
| 1635 | + * |
---|
| 1636 | + * Look-up table in h/w is ignored when PWM is used as DFLL interface to PMIC. |
---|
| 1637 | + * In this case closed loop output is controlling duty cycle directly. The s/w |
---|
| 1638 | + * look-up that maps PWM duty cycle to voltage is still built by this function. |
---|
| 1639 | + */ |
---|
| 1640 | +static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max) |
---|
| 1641 | +{ |
---|
| 1642 | + int i; |
---|
| 1643 | + unsigned long rate, reg_volt; |
---|
| 1644 | + u8 lut_bottom = MAX_DFLL_VOLTAGES; |
---|
| 1645 | + int v_min = td->soc->cvb->min_millivolts * 1000; |
---|
| 1646 | + |
---|
| 1647 | + for (i = 0; i < MAX_DFLL_VOLTAGES; i++) { |
---|
| 1648 | + reg_volt = td->lut_uv[i]; |
---|
| 1649 | + |
---|
| 1650 | + /* since opp voltage is exact mv */ |
---|
| 1651 | + reg_volt = (reg_volt / 1000) * 1000; |
---|
| 1652 | + if (reg_volt > v_max) |
---|
| 1653 | + break; |
---|
| 1654 | + |
---|
| 1655 | + td->lut[i] = i; |
---|
| 1656 | + if ((lut_bottom == MAX_DFLL_VOLTAGES) && (reg_volt >= v_min)) |
---|
| 1657 | + lut_bottom = i; |
---|
| 1658 | + } |
---|
| 1659 | + |
---|
| 1660 | + /* determine voltage boundaries */ |
---|
| 1661 | + td->lut_size = i; |
---|
| 1662 | + if ((lut_bottom == MAX_DFLL_VOLTAGES) || |
---|
| 1663 | + (lut_bottom + 1 >= td->lut_size)) { |
---|
| 1664 | + dev_err(td->dev, "no voltage above DFLL minimum %d mV\n", |
---|
| 1665 | + td->soc->cvb->min_millivolts); |
---|
| 1666 | + return -EINVAL; |
---|
| 1667 | + } |
---|
| 1668 | + td->lut_bottom = lut_bottom; |
---|
| 1669 | + |
---|
| 1670 | + /* determine rate boundaries */ |
---|
| 1671 | + rate = get_dvco_rate_below(td, td->lut_bottom); |
---|
| 1672 | + if (!rate) { |
---|
| 1673 | + dev_err(td->dev, "no opp below DFLL minimum voltage %d mV\n", |
---|
| 1674 | + td->soc->cvb->min_millivolts); |
---|
| 1675 | + return -EINVAL; |
---|
| 1676 | + } |
---|
| 1677 | + td->dvco_rate_min = rate; |
---|
| 1678 | + |
---|
| 1679 | + return 0; |
---|
| 1680 | +} |
---|
| 1681 | + |
---|
1400 | 1682 | /** |
---|
1401 | 1683 | * dfll_build_i2c_lut - build the I2C voltage register lookup table |
---|
1402 | 1684 | * @td: DFLL instance |
---|
| 1685 | + * @v_max: Vmax from OPP table |
---|
1403 | 1686 | * |
---|
1404 | 1687 | * The DFLL hardware has 33 bytes of look-up table RAM that must be filled with |
---|
1405 | 1688 | * PMIC voltage register values that span the entire DFLL operating range. |
---|
.. | .. |
---|
1407 | 1690 | * the soc-specific platform driver (td->soc->opp_dev) and the PMIC |
---|
1408 | 1691 | * register-to-voltage mapping queried from the regulator framework. |
---|
1409 | 1692 | * |
---|
1410 | | - * On success, fills in td->i2c_lut and returns 0, or -err on failure. |
---|
| 1693 | + * On success, fills in td->lut and returns 0, or -err on failure. |
---|
1411 | 1694 | */ |
---|
1412 | | -static int dfll_build_i2c_lut(struct tegra_dfll *td) |
---|
| 1695 | +static int dfll_build_i2c_lut(struct tegra_dfll *td, unsigned long v_max) |
---|
1413 | 1696 | { |
---|
| 1697 | + unsigned long rate, v, v_opp; |
---|
1414 | 1698 | int ret = -EINVAL; |
---|
1415 | | - int j, v, v_max, v_opp; |
---|
1416 | | - int selector; |
---|
1417 | | - unsigned long rate; |
---|
1418 | | - struct dev_pm_opp *opp; |
---|
1419 | | - int lut; |
---|
1420 | | - |
---|
1421 | | - rate = ULONG_MAX; |
---|
1422 | | - opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate); |
---|
1423 | | - if (IS_ERR(opp)) { |
---|
1424 | | - dev_err(td->dev, "couldn't get vmax opp, empty opp table?\n"); |
---|
1425 | | - goto out; |
---|
1426 | | - } |
---|
1427 | | - v_max = dev_pm_opp_get_voltage(opp); |
---|
1428 | | - dev_pm_opp_put(opp); |
---|
| 1699 | + int j, selector, lut; |
---|
1429 | 1700 | |
---|
1430 | 1701 | v = td->soc->cvb->min_millivolts * 1000; |
---|
1431 | 1702 | lut = find_vdd_map_entry_exact(td, v); |
---|
1432 | 1703 | if (lut < 0) |
---|
1433 | 1704 | goto out; |
---|
1434 | | - td->i2c_lut[0] = lut; |
---|
| 1705 | + td->lut[0] = lut; |
---|
| 1706 | + td->lut_bottom = 0; |
---|
1435 | 1707 | |
---|
1436 | 1708 | for (j = 1, rate = 0; ; rate++) { |
---|
| 1709 | + struct dev_pm_opp *opp; |
---|
| 1710 | + |
---|
1437 | 1711 | opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); |
---|
1438 | 1712 | if (IS_ERR(opp)) |
---|
1439 | 1713 | break; |
---|
.. | .. |
---|
1445 | 1719 | dev_pm_opp_put(opp); |
---|
1446 | 1720 | |
---|
1447 | 1721 | for (;;) { |
---|
1448 | | - v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j)); |
---|
| 1722 | + v += max(1UL, (v_max - v) / (MAX_DFLL_VOLTAGES - j)); |
---|
1449 | 1723 | if (v >= v_opp) |
---|
1450 | 1724 | break; |
---|
1451 | 1725 | |
---|
1452 | 1726 | selector = find_vdd_map_entry_min(td, v); |
---|
1453 | 1727 | if (selector < 0) |
---|
1454 | 1728 | goto out; |
---|
1455 | | - if (selector != td->i2c_lut[j - 1]) |
---|
1456 | | - td->i2c_lut[j++] = selector; |
---|
| 1729 | + if (selector != td->lut[j - 1]) |
---|
| 1730 | + td->lut[j++] = selector; |
---|
1457 | 1731 | } |
---|
1458 | 1732 | |
---|
1459 | 1733 | v = (j == MAX_DFLL_VOLTAGES - 1) ? v_max : v_opp; |
---|
1460 | 1734 | selector = find_vdd_map_entry_exact(td, v); |
---|
1461 | 1735 | if (selector < 0) |
---|
1462 | 1736 | goto out; |
---|
1463 | | - if (selector != td->i2c_lut[j - 1]) |
---|
1464 | | - td->i2c_lut[j++] = selector; |
---|
| 1737 | + if (selector != td->lut[j - 1]) |
---|
| 1738 | + td->lut[j++] = selector; |
---|
1465 | 1739 | |
---|
1466 | 1740 | if (v >= v_max) |
---|
1467 | 1741 | break; |
---|
1468 | 1742 | } |
---|
1469 | | - td->i2c_lut_size = j; |
---|
| 1743 | + td->lut_size = j; |
---|
1470 | 1744 | |
---|
1471 | 1745 | if (!td->dvco_rate_min) |
---|
1472 | 1746 | dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n", |
---|
1473 | 1747 | td->soc->cvb->min_millivolts); |
---|
1474 | | - else |
---|
| 1748 | + else { |
---|
1475 | 1749 | ret = 0; |
---|
| 1750 | + for (j = 0; j < td->lut_size; j++) |
---|
| 1751 | + td->lut_uv[j] = |
---|
| 1752 | + regulator_list_voltage(td->vdd_reg, |
---|
| 1753 | + td->lut[j]); |
---|
| 1754 | + } |
---|
1476 | 1755 | |
---|
1477 | 1756 | out: |
---|
1478 | 1757 | return ret; |
---|
| 1758 | +} |
---|
| 1759 | + |
---|
| 1760 | +static int dfll_build_lut(struct tegra_dfll *td) |
---|
| 1761 | +{ |
---|
| 1762 | + unsigned long rate, v_max; |
---|
| 1763 | + struct dev_pm_opp *opp; |
---|
| 1764 | + |
---|
| 1765 | + rate = ULONG_MAX; |
---|
| 1766 | + opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate); |
---|
| 1767 | + if (IS_ERR(opp)) { |
---|
| 1768 | + dev_err(td->dev, "couldn't get vmax opp, empty opp table?\n"); |
---|
| 1769 | + return -EINVAL; |
---|
| 1770 | + } |
---|
| 1771 | + v_max = dev_pm_opp_get_voltage(opp); |
---|
| 1772 | + dev_pm_opp_put(opp); |
---|
| 1773 | + |
---|
| 1774 | + if (td->pmu_if == TEGRA_DFLL_PMU_PWM) |
---|
| 1775 | + return dfll_build_pwm_lut(td, v_max); |
---|
| 1776 | + else |
---|
| 1777 | + return dfll_build_i2c_lut(td, v_max); |
---|
1479 | 1778 | } |
---|
1480 | 1779 | |
---|
1481 | 1780 | /** |
---|
.. | .. |
---|
1536 | 1835 | } |
---|
1537 | 1836 | td->i2c_reg = vsel_reg; |
---|
1538 | 1837 | |
---|
1539 | | - ret = dfll_build_i2c_lut(td); |
---|
1540 | | - if (ret) { |
---|
1541 | | - dev_err(td->dev, "couldn't build I2C LUT\n"); |
---|
1542 | | - return ret; |
---|
| 1838 | + return 0; |
---|
| 1839 | +} |
---|
| 1840 | + |
---|
| 1841 | +static int dfll_fetch_pwm_params(struct tegra_dfll *td) |
---|
| 1842 | +{ |
---|
| 1843 | + int ret, i; |
---|
| 1844 | + u32 pwm_period; |
---|
| 1845 | + |
---|
| 1846 | + if (!td->soc->alignment.step_uv || !td->soc->alignment.offset_uv) { |
---|
| 1847 | + dev_err(td->dev, |
---|
| 1848 | + "Missing step or alignment info for PWM regulator"); |
---|
| 1849 | + return -EINVAL; |
---|
| 1850 | + } |
---|
| 1851 | + for (i = 0; i < MAX_DFLL_VOLTAGES; i++) |
---|
| 1852 | + td->lut_uv[i] = td->soc->alignment.offset_uv + |
---|
| 1853 | + i * td->soc->alignment.step_uv; |
---|
| 1854 | + |
---|
| 1855 | + ret = read_dt_param(td, "nvidia,pwm-tristate-microvolts", |
---|
| 1856 | + &td->reg_init_uV); |
---|
| 1857 | + if (!ret) { |
---|
| 1858 | + dev_err(td->dev, "couldn't get initialized voltage\n"); |
---|
| 1859 | + return -EINVAL; |
---|
| 1860 | + } |
---|
| 1861 | + |
---|
| 1862 | + ret = read_dt_param(td, "nvidia,pwm-period-nanoseconds", &pwm_period); |
---|
| 1863 | + if (!ret) { |
---|
| 1864 | + dev_err(td->dev, "couldn't get PWM period\n"); |
---|
| 1865 | + return -EINVAL; |
---|
| 1866 | + } |
---|
| 1867 | + td->pwm_rate = (NSEC_PER_SEC / pwm_period) * (MAX_DFLL_VOLTAGES - 1); |
---|
| 1868 | + |
---|
| 1869 | + td->pwm_pin = devm_pinctrl_get(td->dev); |
---|
| 1870 | + if (IS_ERR(td->pwm_pin)) { |
---|
| 1871 | + dev_err(td->dev, "DT: missing pinctrl device\n"); |
---|
| 1872 | + return PTR_ERR(td->pwm_pin); |
---|
| 1873 | + } |
---|
| 1874 | + |
---|
| 1875 | + td->pwm_enable_state = pinctrl_lookup_state(td->pwm_pin, |
---|
| 1876 | + "dvfs_pwm_enable"); |
---|
| 1877 | + if (IS_ERR(td->pwm_enable_state)) { |
---|
| 1878 | + dev_err(td->dev, "DT: missing pwm enabled state\n"); |
---|
| 1879 | + return PTR_ERR(td->pwm_enable_state); |
---|
| 1880 | + } |
---|
| 1881 | + |
---|
| 1882 | + td->pwm_disable_state = pinctrl_lookup_state(td->pwm_pin, |
---|
| 1883 | + "dvfs_pwm_disable"); |
---|
| 1884 | + if (IS_ERR(td->pwm_disable_state)) { |
---|
| 1885 | + dev_err(td->dev, "DT: missing pwm disabled state\n"); |
---|
| 1886 | + return PTR_ERR(td->pwm_disable_state); |
---|
1543 | 1887 | } |
---|
1544 | 1888 | |
---|
1545 | 1889 | return 0; |
---|
.. | .. |
---|
1607 | 1951 | |
---|
1608 | 1952 | td->soc = soc; |
---|
1609 | 1953 | |
---|
1610 | | - td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu"); |
---|
1611 | | - if (IS_ERR(td->vdd_reg)) { |
---|
1612 | | - dev_err(td->dev, "couldn't get vdd_cpu regulator\n"); |
---|
1613 | | - return PTR_ERR(td->vdd_reg); |
---|
1614 | | - } |
---|
1615 | | - |
---|
1616 | 1954 | td->dvco_rst = devm_reset_control_get(td->dev, "dvco"); |
---|
1617 | 1955 | if (IS_ERR(td->dvco_rst)) { |
---|
1618 | 1956 | dev_err(td->dev, "couldn't get dvco reset\n"); |
---|
.. | .. |
---|
1625 | 1963 | return ret; |
---|
1626 | 1964 | } |
---|
1627 | 1965 | |
---|
1628 | | - ret = dfll_fetch_i2c_params(td); |
---|
| 1966 | + if (of_property_read_bool(td->dev->of_node, "nvidia,pwm-to-pmic")) { |
---|
| 1967 | + td->pmu_if = TEGRA_DFLL_PMU_PWM; |
---|
| 1968 | + ret = dfll_fetch_pwm_params(td); |
---|
| 1969 | + } else { |
---|
| 1970 | + td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu"); |
---|
| 1971 | + if (IS_ERR(td->vdd_reg)) { |
---|
| 1972 | + dev_err(td->dev, "couldn't get vdd_cpu regulator\n"); |
---|
| 1973 | + return PTR_ERR(td->vdd_reg); |
---|
| 1974 | + } |
---|
| 1975 | + td->pmu_if = TEGRA_DFLL_PMU_I2C; |
---|
| 1976 | + ret = dfll_fetch_i2c_params(td); |
---|
| 1977 | + } |
---|
1629 | 1978 | if (ret) |
---|
1630 | 1979 | return ret; |
---|
1631 | 1980 | |
---|
| 1981 | + ret = dfll_build_lut(td); |
---|
| 1982 | + if (ret) { |
---|
| 1983 | + dev_err(td->dev, "couldn't build LUT\n"); |
---|
| 1984 | + return ret; |
---|
| 1985 | + } |
---|
| 1986 | + |
---|
1632 | 1987 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
1633 | 1988 | if (!mem) { |
---|
1634 | 1989 | dev_err(td->dev, "no control register resource\n"); |
---|