Merge branch 'mpc85xx'
[platform/kernel/u-boot.git] / tools / mpc86x_clk.c
1 /*
2  * (C) Copyright 2003 Intracom S.A.
3  * Pantelis Antoniou <panto@intracom.gr>
4  *
5  * This little program makes an exhaustive search for the
6  * correct terms of pdf, mfi, mfn, mfd, s, dbrmo, in PLPRCR.
7  * The goal is to produce a gclk2 from a xin input, while respecting
8  * all the restrictions on their combination.
9  *
10  * Generaly you select the first row of the produced table.
11  *
12  * See file CREDITS for list of people who contributed to this
13  * project.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of
18  * the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28  * MA 02111-1307 USA
29  */
30
31
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #define DPREF_MIN        10000000
36 #define DPREF_MAX        32000000
37
38 #define DPGDCK_MAX      320000000
39 #define DPGDCK_MIN      160000000
40
41 #define S_MIN           0
42 #define S_MAX           2
43
44 #define MFI_MIN         5
45 #define MFI_MAX         15
46
47 #define MFN_MIN         0
48 #define MFN_MAX         15
49
50 #define MFD_MIN         0
51 #define MFD_MAX         31
52
53 #define MF_MIN          5
54 #define MF_MAX          15
55
56 #define PDF_MIN         0
57 #define PDF_MAX         15
58
59 #define GCLK2_MAX       150000000
60
61 static int calculate (int xin, int target_clock,
62                       int ppm, int pdf, int mfi, int mfn, int mfd, int s,
63                       int *dprefp, int *dpgdckp, int *jdbckp,
64                       int *gclk2p, int *dbrmop)
65 {
66         unsigned int dpref, dpgdck, jdbck, gclk2, t1, t2, dbrmo;
67
68         /* valid MFI? */
69         if (mfi < MFI_MIN)
70                 return -1;
71
72         /* valid num, denum? */
73         if (mfn > 0 && mfn >= mfd)
74                 return -1;
75
76         dpref = xin / (pdf + 1);
77
78         /* valid dpef? */
79         if (dpref < DPREF_MIN || dpref > DPREF_MAX)
80                 return -1;
81
82         if (mfn == 0) {
83                 dpgdck  = (2 * mfi * xin) / (pdf + 1) ;
84                 dbrmo = 0;
85         } else {
86                 /* 5 <= mfi + (mfn / mfd + 1) <= 15 */
87                 t1 = mfd + 1;
88                 t2 = mfi * t1 + mfn;
89                 if ( MF_MIN * t1 > t2 || MF_MAX * t1 < t2)
90                         return -1;
91
92                 dpgdck  = (unsigned int)(2 * (mfi * mfd + mfi + mfn) *
93                                 (unsigned int)xin) /
94                                 ((mfd + 1) * (pdf + 1));
95
96                 dbrmo = 10 * mfn < (mfd + 1);
97         }
98
99         /* valid dpgclk? */
100         if (dpgdck < DPGDCK_MIN || dpgdck > DPGDCK_MAX)
101                 return -1;
102
103         jdbck = dpgdck >> s;
104         gclk2 = jdbck / 2;
105
106         /* valid gclk2 */
107         if (gclk2 > GCLK2_MAX)
108                 return -1;
109
110         t1 = abs(gclk2 - target_clock);
111
112         /* XXX max 1MHz dev. in clock */
113         if (t1 > 1000000)
114                 return -1;
115
116         /* dev within range (XXX gclk2 scaled to avoid overflow) */
117         if (t1 * 1000 > (unsigned int)ppm * (gclk2 / 1000))
118                 return -1;
119
120         *dprefp = dpref;
121         *dpgdckp = dpgdck;
122         *jdbckp = jdbck;
123         *gclk2p = gclk2;
124         *dbrmop = dbrmo;
125
126         return gclk2;
127 }
128
129 int conf_clock(int xin, int target_clock, int ppm)
130 {
131         int pdf, s, mfn, mfd, mfi;
132         int dpref, dpgdck, jdbck, gclk2, xout, dbrmo;
133         int found = 0;
134
135         /* integer multipliers */
136         for (pdf = PDF_MIN; pdf <= PDF_MAX; pdf++) {
137                 for (mfi = MFI_MIN; mfi <= MFI_MAX; mfi++) {
138                         for (s = 0; s <= S_MAX; s++) {
139                                 xout = calculate(xin, target_clock,
140                                                  ppm, pdf, mfi, 0, 0, s,
141                                                  &dpref, &dpgdck, &jdbck,
142                                                  &gclk2, &dbrmo);
143                                 if (xout < 0)
144                                         continue;
145
146                                 if (found == 0) {
147                                         printf("pdf mfi mfn mfd s dbrmo     dpref    dpgdck     jdbck     gclk2 exact?\n");
148                                         printf("--- --- --- --- - -----     -----    ------     -----     ----- ------\n");
149                                 }
150
151                                 printf("%3d %3d --- --- %1d %5d %9d %9d %9d %9d%s\n",
152                                         pdf, mfi, s, dbrmo,
153                                         dpref, dpgdck, jdbck, gclk2,
154                                         gclk2 == target_clock ? "    YES" : "");
155
156                                 found++;
157                         }
158                 }
159         }
160
161         /* fractional multipliers */
162         for (pdf = PDF_MIN; pdf <= PDF_MAX; pdf++) {
163                 for (mfi = MFI_MIN; mfi <= MFI_MAX; mfi++) {
164                         for (mfn = 1; mfn <= MFN_MAX; mfn++) {
165                                 for (mfd = 1; mfd <= MFD_MAX; mfd++) {
166                                         for (s = 0; s <= S_MAX; s++) {
167                                                 xout = calculate(xin, target_clock,
168                                                             ppm, pdf, mfi, mfn, mfd, s,
169                                                             &dpref, &dpgdck, &jdbck,
170                                                             &gclk2, &dbrmo);
171                                                 if (xout < 0)
172                                                         continue;
173
174                                                 if (found == 0) {
175                                                         printf("pdf mfi mfn mfd s dbrmo     dpref    dpgdck     jdbck     gclk2 exact?\n");
176                                                         printf("--- --- --- --- - -----     -----    ------     -----     ----- ------\n");
177                                                 }
178
179                                                 printf("%3d %3d %3d %3d %1d %5d %9d %9d %9d %9d%s\n",
180                                                         pdf, mfi, mfn, mfd, s,
181                                                         dbrmo, dpref, dpgdck, jdbck, gclk2,
182                                                         gclk2 == target_clock ? "    YES" : "");
183
184                                                 found++;
185                                         }
186                                 }
187                         }
188
189                 }
190         }
191
192         return found;
193 }
194
195 int main(int argc, char *argv[])
196 {
197         int xin, want_gclk2, found, ppm = 100;
198
199         if (argc < 3) {
200                 fprintf(stderr, "usage: mpc86x_clk <xin> <want_gclk2> [ppm]\n");
201                 fprintf(stderr, "       default ppm is 100\n");
202                 return 10;
203         }
204
205         xin  = atoi(argv[1]);
206         want_gclk2 = atoi(argv[2]);
207         if (argc >= 4)
208                 ppm = atoi(argv[3]);
209
210         found = conf_clock(xin, want_gclk2, ppm);
211         if (found <= 0) {
212                 fprintf(stderr, "cannot produce gclk2 %d from xin %d\n",
213                         want_gclk2, xin);
214                 return EXIT_FAILURE;
215         }
216
217         return EXIT_SUCCESS;
218 }