Commit | Line | Data |
---|---|---|
62a8a094 TT |
1 | /* |
2 | * Tegra124 DFLL FCPU clock source driver | |
3 | * | |
4 | * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved. | |
5 | * | |
6 | * Aleksandr Frid <afrid@nvidia.com> | |
7 | * 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 | * | |
18 | */ | |
19 | ||
20 | #include <linux/cpu.h> | |
21 | #include <linux/err.h> | |
22 | #include <linux/kernel.h> | |
23 | #include <linux/module.h> | |
24 | #include <linux/platform_device.h> | |
25 | #include <soc/tegra/fuse.h> | |
26 | ||
27 | #include "clk.h" | |
28 | #include "clk-dfll.h" | |
29 | #include "cvb.h" | |
30 | ||
31 | /* Maximum CPU frequency, indexed by CPU speedo id */ | |
32 | static const unsigned long cpu_max_freq_table[] = { | |
33 | [0] = 2014500000UL, | |
34 | [1] = 2320500000UL, | |
35 | [2] = 2116500000UL, | |
36 | [3] = 2524500000UL, | |
37 | }; | |
38 | ||
39 | static const struct cvb_table tegra124_cpu_cvb_tables[] = { | |
40 | { | |
41 | .speedo_id = -1, | |
42 | .process_id = -1, | |
43 | .min_millivolts = 900, | |
44 | .max_millivolts = 1260, | |
45 | .alignment = { | |
46 | .step_uv = 10000, /* 10mV */ | |
47 | }, | |
48 | .speedo_scale = 100, | |
49 | .voltage_scale = 1000, | |
50 | .cvb_table = { | |
51 | {204000000UL, {1112619, -29295, 402} }, | |
52 | {306000000UL, {1150460, -30585, 402} }, | |
53 | {408000000UL, {1190122, -31865, 402} }, | |
54 | {510000000UL, {1231606, -33155, 402} }, | |
55 | {612000000UL, {1274912, -34435, 402} }, | |
56 | {714000000UL, {1320040, -35725, 402} }, | |
57 | {816000000UL, {1366990, -37005, 402} }, | |
58 | {918000000UL, {1415762, -38295, 402} }, | |
59 | {1020000000UL, {1466355, -39575, 402} }, | |
60 | {1122000000UL, {1518771, -40865, 402} }, | |
61 | {1224000000UL, {1573009, -42145, 402} }, | |
62 | {1326000000UL, {1629068, -43435, 402} }, | |
63 | {1428000000UL, {1686950, -44715, 402} }, | |
64 | {1530000000UL, {1746653, -46005, 402} }, | |
65 | {1632000000UL, {1808179, -47285, 402} }, | |
66 | {1734000000UL, {1871526, -48575, 402} }, | |
67 | {1836000000UL, {1936696, -49855, 402} }, | |
68 | {1938000000UL, {2003687, -51145, 402} }, | |
69 | {2014500000UL, {2054787, -52095, 402} }, | |
70 | {2116500000UL, {2124957, -53385, 402} }, | |
71 | {2218500000UL, {2196950, -54665, 402} }, | |
72 | {2320500000UL, {2270765, -55955, 402} }, | |
73 | {2422500000UL, {2346401, -57235, 402} }, | |
74 | {2524500000UL, {2437299, -58535, 402} }, | |
75 | {0, { 0, 0, 0} }, | |
76 | }, | |
77 | .cpu_dfll_data = { | |
78 | .tune0_low = 0x005020ff, | |
79 | .tune0_high = 0x005040ff, | |
80 | .tune1 = 0x00000060, | |
81 | } | |
82 | }, | |
83 | }; | |
84 | ||
85 | static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) | |
86 | { | |
87 | int process_id, speedo_id, speedo_value; | |
88 | struct tegra_dfll_soc_data *soc; | |
89 | const struct cvb_table *cvb; | |
90 | ||
91 | process_id = tegra_sku_info.cpu_process_id; | |
92 | speedo_id = tegra_sku_info.cpu_speedo_id; | |
93 | speedo_value = tegra_sku_info.cpu_speedo_value; | |
94 | ||
95 | if (speedo_id >= ARRAY_SIZE(cpu_max_freq_table)) { | |
96 | dev_err(&pdev->dev, "unknown max CPU freq for speedo_id=%d\n", | |
97 | speedo_id); | |
98 | return -ENODEV; | |
99 | } | |
100 | ||
101 | soc = devm_kzalloc(&pdev->dev, sizeof(*soc), GFP_KERNEL); | |
102 | if (!soc) | |
103 | return -ENOMEM; | |
104 | ||
105 | soc->dev = get_cpu_device(0); | |
106 | if (!soc->dev) { | |
107 | dev_err(&pdev->dev, "no CPU0 device\n"); | |
108 | return -ENODEV; | |
109 | } | |
110 | ||
111 | cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, | |
112 | ARRAY_SIZE(tegra124_cpu_cvb_tables), | |
113 | process_id, speedo_id, speedo_value, | |
114 | cpu_max_freq_table[speedo_id], | |
115 | soc->dev); | |
116 | if (IS_ERR(cvb)) { | |
117 | dev_err(&pdev->dev, "couldn't build OPP table: %ld\n", | |
118 | PTR_ERR(cvb)); | |
119 | return PTR_ERR(cvb); | |
120 | } | |
121 | ||
122 | soc->min_millivolts = cvb->min_millivolts; | |
123 | soc->tune0_low = cvb->cpu_dfll_data.tune0_low; | |
124 | soc->tune0_high = cvb->cpu_dfll_data.tune0_high; | |
125 | soc->tune1 = cvb->cpu_dfll_data.tune1; | |
126 | ||
127 | return tegra_dfll_register(pdev, soc); | |
128 | } | |
129 | ||
130 | static const struct of_device_id tegra124_dfll_fcpu_of_match[] = { | |
131 | { .compatible = "nvidia,tegra124-dfll", }, | |
132 | { }, | |
133 | }; | |
134 | MODULE_DEVICE_TABLE(of, tegra124_dfll_fcpu_of_match); | |
135 | ||
136 | static const struct dev_pm_ops tegra124_dfll_pm_ops = { | |
137 | SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend, | |
138 | tegra_dfll_runtime_resume, NULL) | |
139 | }; | |
140 | ||
141 | static struct platform_driver tegra124_dfll_fcpu_driver = { | |
142 | .probe = tegra124_dfll_fcpu_probe, | |
143 | .remove = tegra_dfll_unregister, | |
144 | .driver = { | |
145 | .name = "tegra124-dfll", | |
146 | .of_match_table = tegra124_dfll_fcpu_of_match, | |
147 | .pm = &tegra124_dfll_pm_ops, | |
148 | }, | |
149 | }; | |
150 | ||
151 | static int __init tegra124_dfll_fcpu_init(void) | |
152 | { | |
153 | return platform_driver_register(&tegra124_dfll_fcpu_driver); | |
154 | } | |
155 | module_init(tegra124_dfll_fcpu_init); | |
156 | ||
157 | static void __exit tegra124_dfll_fcpu_exit(void) | |
158 | { | |
159 | platform_driver_unregister(&tegra124_dfll_fcpu_driver); | |
160 | } | |
161 | module_exit(tegra124_dfll_fcpu_exit); | |
162 | ||
163 | MODULE_DESCRIPTION("Tegra124 DFLL clock source driver"); | |
164 | MODULE_LICENSE("GPL v2"); | |
165 | MODULE_AUTHOR("Aleksandr Frid <afrid@nvidia.com>"); | |
166 | MODULE_AUTHOR("Paul Walmsley <pwalmsley@nvidia.com>"); |