modClock.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #ifndef Lynx
  5. #include <fnmatch.h>
  6. #endif
  7. #include "iopl.h"
  8. #define tolerance 0.01 /* +/- 1% */
  9. #define CT65520 0x1
  10. #define CT65525 0x2
  11. #define CT65530 0x3
  12. #define CT64200 0x4
  13. #define CT65535 0x11
  14. #define CT65540 0x12
  15. #define CT65545 0x13
  16. #define CT65546 0x14
  17. #define CT65548 0x15
  18. #define CT64300 0x16
  19. #define CT65550 0x31
  20. #define CT65554 0x32
  21. #define CT65555 0x33
  22. #define CT68554 0x34
  23. #define CT69000 0x35
  24. #define CT69030 0x36
  25. #define IS_Programmable(X) X&0x10
  26. #define IS_HiQV(X) X&0x20
  27. #define DotClk 0
  28. #define MemClk 1
  29. #define IS_MemClk(X) X&0x1
  30. int compute_clock (
  31. unsigned int ChipType,
  32. double target,
  33. double Fref,
  34. unsigned int ClkMaxN,
  35. unsigned int ClkMaxM,
  36. unsigned int *bestM,
  37. unsigned int *bestN,
  38. unsigned int *bestP,
  39. unsigned int *bestPSN) {
  40. unsigned int M, N, P, PSN, PSNx;
  41. double bestError = 0, abest = 42, bestFout = 0;
  42. double Fvco, Fout;
  43. double error, aerror;
  44. unsigned int M_min = 3;
  45. unsigned int M_max = ClkMaxM;
  46. if (target < 1e6){
  47. fprintf (stderr, "MHz assumed, changed to %g MHz\n", target);
  48. target *= 1e6;
  49. }
  50. if (target > 220.0e6) {
  51. fprintf (stderr, "too large\n");
  52. return 1;
  53. }
  54. /* Other parameters available onthe 65548 but not the 65545, and
  55. not documented in the Clock Synthesizer doc in rev 1.0 of the
  56. 65548 datasheet:
  57. + XR30[4] = 0, VCO divider loop uses divide by 4 (same as 65545)
  58. 1, VCO divider loop uses divide by 16
  59. + XR30[5] = 1, reference clock is divided by 5
  60. I haven't put in any support for those here. For simplicity,
  61. they should be set to 0 on the 65548, and left untouched on
  62. earlier chips. */
  63. for (PSNx = ((ChipType == CT69000) || (ChipType == CT69030)) ? 1 : 0;
  64. PSNx <= 1; PSNx++) {
  65. unsigned int low_N, high_N;
  66. double Fref4PSN;
  67. PSN = PSNx ? 1 : 4;
  68. low_N = 3;
  69. high_N = ClkMaxN;
  70. while (Fref / (PSN * low_N) > (((ChipType == CT69000) ||
  71. (ChipType == CT69030)) ? 5.0e6 : 2.0e6))
  72. low_N++;
  73. while (Fref / (PSN * high_N) < 150.0e3)
  74. high_N--;
  75. Fref4PSN = Fref * 4 / PSN;
  76. for (N = low_N; N <= high_N; N++) {
  77. double tmp = Fref4PSN / N;
  78. for (P = (IS_HiQV(ChipType) && (ChipType != CT69000) &&
  79. (ChipType != CT69030)) ? 1 : 0; P <= 5; P++) {
  80. double Fvco_desired = target * (1 << P);
  81. double M_desired = Fvco_desired / tmp;
  82. /* Which way will M_desired be rounded? Do all three just to
  83. be safe. */
  84. unsigned int M_low = M_desired - 1;
  85. unsigned int M_hi = M_desired + 1;
  86. if (M_hi < M_min || M_low > M_max)
  87. continue;
  88. if (M_low < M_min)
  89. M_low = M_min;
  90. if (M_hi > M_max)
  91. M_hi = M_max;
  92. for (M = M_low; M <= M_hi; M++) {
  93. Fvco = tmp * M;
  94. if (Fvco <= ((ChipType == CT69000) || (ChipType == CT69030) ?
  95. 100e6 : 48.0e6))
  96. continue;
  97. if (Fvco > 220.0e6)
  98. break;
  99. Fout = Fvco / (1 << P);
  100. error = (target - Fout) / target;
  101. aerror = (error < 0) ? -error : error;
  102. if (aerror < abest) {
  103. abest = aerror;
  104. bestError = error;
  105. *bestM = M;
  106. *bestN = N;
  107. *bestP = P;
  108. *bestPSN = PSN;
  109. bestFout = Fout;
  110. }
  111. }
  112. }
  113. }
  114. }
  115. if (abest < tolerance) {
  116. printf ("best: M=%d N=%d P=%d PSN=%d\n", *bestM, *bestN, *bestP, *bestPSN);
  117. if (bestFout > 1.0e6)
  118. printf ("Fout = %g MHz", bestFout / 1.0e6);
  119. else if (bestFout > 1.0e3)
  120. printf ("Fout = %g kHz", bestFout / 1.0e3);
  121. else
  122. printf ("Fout = %g Hz", bestFout);
  123. printf (", error = %g\n", bestError);
  124. return 0;
  125. }
  126. printf ("can't do it with less than %g error\n", bestError);
  127. return 1;
  128. }
  129. int set_clock(
  130. unsigned int ChipType,
  131. unsigned int ClockType,
  132. unsigned int ProgClock,
  133. unsigned int M,
  134. unsigned int N,
  135. unsigned int P,
  136. unsigned int PSN) {
  137. unsigned int tmp, idx;
  138. SET_IOPL();
  139. idx = inb(0x3D6);
  140. if (IS_HiQV(ChipType)) {
  141. if (IS_MemClk(ClockType)) {
  142. printf ("XRCC = 0x%02X\n", M - 2);
  143. printf ("XRCD = 0x%02X\n", N - 2);
  144. printf ("XRCE = 0x%02X\n", (0x80 | (P * 16 + (PSN == 1))));
  145. outb(0x3D6, 0xCE); /* Select Fix MClk before */
  146. tmp = inb(0x3D7);
  147. outb(0x3D7, tmp & 0x7F);
  148. outb(0x3D6, 0xCC);
  149. outb(0x3D7, (M - 2));
  150. outb(0x3D6, 0xCD);
  151. outb(0x3D7, (N - 2));
  152. outb(0x3D6, 0xCE);
  153. outb(0x3D7, (0x80 | (P * 16 + (PSN == 1))));
  154. } else {
  155. printf ("XR%X = 0x%02X\n", 0xC0 + 4 * ProgClock, M - 2);
  156. printf ("XR%X = 0x%02X\n", 0xC1 + 4 * ProgClock, N - 2);
  157. printf ("XR%X = 0x%02X\n", 0xC2 + 4 * ProgClock, 0);
  158. printf ("XR%X = 0x%02X\n", 0xC3 + 4 * ProgClock, P * 16 + (PSN == 1));
  159. outb(0x3D6, 0xC0 + 4 * ProgClock);
  160. outb(0x3D7, (M - 2));
  161. outb(0x3D6, 0xC1 + 4 * ProgClock);
  162. outb(0x3D7, (N - 2));
  163. outb(0x3D6, 0xC2 + 4 * ProgClock);
  164. outb(0x3D7, 0x0);
  165. outb(0x3D6, 0xC3 + 4 * ProgClock);
  166. outb(0x3D7, (P * 16 + (PSN == 1)));
  167. }
  168. } else {
  169. printf ("XR30 = 0x%02X\n", P * 2 + (PSN == 1));
  170. printf ("XR31 = 0x%02X\n", M - 2);
  171. printf ("XR32 = 0x%02X\n", N - 2);
  172. outb(0x3D6, 0x33);
  173. tmp = inb(0x3D7);
  174. if (IS_MemClk(ClockType)) {
  175. outb(0x3D7, tmp | 0x20);
  176. } else {
  177. outb(0x3D7, tmp & ~0x20);
  178. }
  179. outb(0x3D6, 0x30);
  180. outb(0x3D7, (P * 2 + (PSN == 1)));
  181. outb(0x3D6, 0x31);
  182. outb(0x3D7, (M - 2));
  183. outb(0x3D6, 0x32);
  184. outb(0x3D7, (N - 2));
  185. outb(0x3D6, 0x33);
  186. outb(0x3D7, tmp);
  187. }
  188. outb(0x3D6, idx);
  189. RESET_IOPL();
  190. return 0;
  191. }
  192. unsigned int probe_chip(void) {
  193. unsigned int ChipType, temp;
  194. SET_IOPL();
  195. outb(0x3D6, 0x00);
  196. temp = inb(0x3D7);
  197. ChipType = 0;
  198. if (temp != 0xA5) {
  199. if ((temp & 0xF0) == 0x70) {
  200. ChipType = CT65520;
  201. }
  202. if ((temp & 0xF0) == 0x80) { /* could also be a 65525 */
  203. ChipType = CT65530;
  204. }
  205. if ((temp & 0xF0) == 0xA0) {
  206. ChipType = CT64200;
  207. }
  208. if ((temp & 0xF0) == 0xB0) {
  209. ChipType = CT64300;
  210. }
  211. if ((temp & 0xF0) == 0xC0) {
  212. ChipType = CT65535;
  213. }
  214. if ((temp & 0xF8) == 0xD0) {
  215. ChipType = CT65540;
  216. }
  217. if ((temp & 0xF8) == 0xD8) {
  218. switch (temp & 0x07) {
  219. case 3:
  220. ChipType = CT65546;
  221. break;
  222. case 4:
  223. ChipType = CT65548;
  224. break;
  225. default:
  226. ChipType = CT65545;
  227. }
  228. }
  229. }
  230. /* At this point the chip could still be a HiQV, so check for
  231. * that. This test needs some looking at */
  232. if ((temp != 0) && (ChipType == 0)) {
  233. outb(0x3D6, 0x02);
  234. temp = inb(0x03D7);
  235. if (temp == 0xE0) {
  236. ChipType = CT65550;
  237. }
  238. if (temp == 0xE4) {
  239. ChipType = CT65554;
  240. }
  241. if (temp == 0xE5) {
  242. ChipType = CT65555;
  243. }
  244. if (temp == 0xF4) {
  245. ChipType = CT68554;
  246. }
  247. if (temp == 0xC0) {
  248. ChipType = CT69000;
  249. }
  250. if (temp == 0x30) {
  251. outb(0x3D6, 0x03);
  252. temp = inb(0x03D7);
  253. if (temp == 0x0C) ChipType = CT69030;
  254. }
  255. }
  256. RESET_IOPL();
  257. if (ChipType == 0) { /* failure */
  258. fprintf(stderr, "Not a Chips and Technologies Chipset\n");
  259. }
  260. return ChipType;
  261. }
  262. int main (int argc, char *argv[]) {
  263. double target;
  264. double Fref = 14318180;
  265. unsigned int M, N, P, PSN, ChipType, ClockType, progclock;
  266. switch (argc) {
  267. case 2:
  268. progclock = 2;
  269. target = atof (argv[1]);
  270. break;
  271. case 3:
  272. progclock = abs(atof (argv[1]));
  273. target = atof (argv[2]);
  274. break;
  275. default:
  276. fprintf (stderr, "usage: %s [-0|-1|-2] freq\n", argv[0]);
  277. return 1;
  278. }
  279. ClockType = DotClk;
  280. #ifndef Lynx
  281. if (! fnmatch("*memClock",argv[0],FNM_PATHNAME)) {
  282. #else
  283. if (strstr("memClock",argv[0]) != NULL) {
  284. #endif
  285. ClockType = MemClk;
  286. }
  287. ChipType = probe_chip();
  288. if (!ChipType) {
  289. return 1;
  290. }
  291. if (! IS_Programmable(ChipType)) {
  292. fprintf(stderr, "No programmable Clock!\n");
  293. return 1;
  294. }
  295. if (IS_HiQV(ChipType)) {
  296. if (! compute_clock(ChipType, target, Fref, 63, 127, &M, &N, &P, &PSN)) {
  297. return set_clock(ChipType, ClockType, progclock, M, N, P, PSN);
  298. } else {
  299. return 1;
  300. }
  301. } else {
  302. if (! compute_clock(ChipType, target, Fref, 127, 127, &M, &N, &P, &PSN)) {
  303. return set_clock(ChipType, ClockType, progclock, M, N, P, PSN);
  304. } else {
  305. return 1;
  306. }
  307. }
  308. }