Zynq.PsConfig.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. (**
  2. AUTHOR: Alexey Morozov
  3. PURPOSE: Interface for system level configuration/control of Zynq Processing System (PS)
  4. *)
  5. MODULE PsConfig;
  6. IMPORT
  7. SYSTEM, Platform, BootConfig, Trace;
  8. CONST
  9. (** error codes *)
  10. Ok* = 0;
  11. InvalidChannel* = 1; (** invalid channel (e.g. PL clock channel) specified *)
  12. InvalidClockSource* = 2; (** invalid clock source specified *)
  13. InvalidDivisor* = 3; (** invalid clock divisor value specified *)
  14. InvalidModule* = 4; (** invalid I/O module specified *)
  15. InvalidDevice* = 5; (** invalid I/O device for specified module *)
  16. UnknownError* = 256;
  17. (** PLL clock source types *)
  18. IoPll* = 0; (** IO PLL used as a clock source for IO peripherals *)
  19. ArmPll* = 1; (** ARM PLL used as a clock source for the CPU *)
  20. DdrPll* = 3; (** DDR PLL used as a clock source for DDR memory *)
  21. (** I/O Clock Modules *)
  22. IoUsb* = 0;
  23. IoGem* = 1;
  24. IoSdio* = 2;
  25. IoSmc* = 3;
  26. IoSpi* = 4;
  27. IoQuadSpi* = 5;
  28. IoUart* = 6;
  29. IoCan* = 7;
  30. IoGpio* = 8;
  31. IoI2c* = 9;
  32. VAR
  33. psRefClockHz: HUGEINT;
  34. (**
  35. Get clock frequency of a given PLL clock source
  36. srcSel: source selector (either of IoPll, ArmPll, DdrPll)
  37. res: result code; zero in case of success
  38. Returns the frequency in Hz
  39. *)
  40. PROCEDURE GetPllClockFrequency*(srcSel: LONGINT; VAR res: WORD): HUGEINT;
  41. BEGIN
  42. CASE srcSel OF
  43. |IoPll: RETURN HUGEINT(LSH(SYSTEM.MSK(Platform.slcr.IO_PLL_CTRL,0x7F000),-12)) * psRefClockHz;
  44. |ArmPll: RETURN HUGEINT(LSH(SYSTEM.MSK(Platform.slcr.ARM_PLL_CTRL,0x7F000),-12)) * psRefClockHz;
  45. |DdrPll: RETURN HUGEINT(LSH(SYSTEM.MSK(Platform.slcr.DDR_PLL_CTRL,0x7F000),-12)) * psRefClockHz;
  46. ELSE
  47. res := InvalidClockSource; RETURN 0;
  48. END;
  49. END GetPllClockFrequency;
  50. (**
  51. Setup reset signals to programming logic
  52. assertedChannels: specifies the set of PL channels with asserted reset; can include 0, 1, 2, 3
  53. res: result code; zero in case of success
  54. Returns TRUE in case of success
  55. *)
  56. PROCEDURE SetPlResets*(assertedChannels: SET; VAR res: WORD): BOOLEAN;
  57. BEGIN
  58. IF assertedChannels * {4..31} # {} THEN res := InvalidChannel; RETURN FALSE; END;
  59. Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
  60. Platform.slcr.FPGA_RST_CTRL := assertedChannels;
  61. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  62. res := Ok;
  63. RETURN TRUE;
  64. END SetPlResets;
  65. (**
  66. Setup a given channel of Programming Logic (PL) clock
  67. channel: selected channel (either of 0, 1, 2, 3)
  68. srcSel: source selector (either of IoPll, ArmPll, DdrPll)
  69. divisor0: provides the divisor used to divide the source clock to generate the required generated clock frequency. First cascade divider.
  70. divisor1: provides the divisor used to divide the source clock to generate the required generated clock frequency. Second cascade divider.
  71. res: result code; zero in case of success
  72. Returns TRUE in case of success
  73. *)
  74. PROCEDURE SetPlClock*(channel: LONGINT; srcSel: LONGINT; divisor0, divisor1: LONGINT; VAR res: WORD): BOOLEAN;
  75. BEGIN
  76. IF (srcSel > 0) OR (srcSel > 3) THEN res := InvalidClockSource; RETURN FALSE; END;
  77. IF (divisor0 < 1) OR (divisor0 > 63) OR (divisor1 < 0) OR (divisor1 > 63) THEN res := InvalidDivisor; RETURN FALSE; END;
  78. Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
  79. CASE channel OF
  80. |0: Platform.slcr.FPGA0_CLK_CTRL := srcSel + LSH(divisor0,8) + LSH(divisor1,20);
  81. |1: Platform.slcr.FPGA1_CLK_CTRL := srcSel + LSH(divisor0,8) + LSH(divisor1,20);
  82. |2: Platform.slcr.FPGA2_CLK_CTRL := srcSel + LSH(divisor0,8) + LSH(divisor1,20);
  83. |3: Platform.slcr.FPGA3_CLK_CTRL := srcSel + LSH(divisor0,8) + LSH(divisor1,20);
  84. ELSE
  85. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  86. res := InvalidChannel;
  87. RETURN FALSE;
  88. END;
  89. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  90. res := Ok;
  91. RETURN TRUE;
  92. END SetPlClock;
  93. (**
  94. Get clock frequency of a given PL clock channel
  95. res: result code; zero in case of success
  96. Returns the frequency in Hz
  97. *)
  98. PROCEDURE GetPlClockFrequency*(channel: LONGINT; VAR res: WORD): HUGEINT;
  99. VAR
  100. d, srcSel, divisor0, divisor1: LONGINT;
  101. BEGIN
  102. CASE channel OF
  103. |0: d := Platform.slcr.FPGA0_CLK_CTRL;
  104. |1: d := Platform.slcr.FPGA1_CLK_CTRL;
  105. |2: d := Platform.slcr.FPGA2_CLK_CTRL;
  106. |3: d := Platform.slcr.FPGA3_CLK_CTRL;
  107. ELSE
  108. res := InvalidChannel;
  109. RETURN 0;
  110. END;
  111. srcSel := LSH(SYSTEM.MSK(d,0x30),-4);
  112. divisor0 := LSH(SYSTEM.MSK(d,0x3F00),-8);
  113. divisor1 := LSH(SYSTEM.MSK(d,0x3F00000),-20);
  114. RETURN GetPllClockFrequency(srcSel,res) DIV (divisor0*divisor1);
  115. END GetPlClockFrequency;
  116. (**
  117. Stop a given PL clock
  118. channel: clock channel number
  119. res: result code; zero in case of success
  120. Returns TRUE in case of success
  121. *)
  122. PROCEDURE StopPlClock*(channel: LONGINT; VAR res: WORD): BOOLEAN;
  123. BEGIN
  124. Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
  125. CASE channel OF
  126. |0: Platform.slcr.FPGA0_THR_CNT := 1;
  127. |1: Platform.slcr.FPGA1_THR_CNT := 1;
  128. |2: Platform.slcr.FPGA2_THR_CNT := 1;
  129. |3: Platform.slcr.FPGA3_THR_CNT := 1;
  130. ELSE
  131. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  132. res := InvalidChannel;
  133. RETURN FALSE;
  134. END;
  135. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  136. res := Ok;
  137. RETURN TRUE;
  138. END StopPlClock;
  139. (**
  140. Start a given PL clock
  141. channel: clock channel number
  142. res: result code; zero in case of success
  143. Returns TRUE in case of success
  144. *)
  145. PROCEDURE StartPlClock*(channel: LONGINT; VAR res: WORD): BOOLEAN;
  146. BEGIN
  147. Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
  148. CASE channel OF
  149. |0: Platform.slcr.FPGA0_THR_CNT := 0;
  150. |1: Platform.slcr.FPGA1_THR_CNT := 0;
  151. |2: Platform.slcr.FPGA2_THR_CNT := 0;
  152. |3: Platform.slcr.FPGA3_THR_CNT := 0;
  153. ELSE
  154. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  155. res := InvalidChannel;
  156. RETURN FALSE;
  157. END;
  158. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  159. res := Ok;
  160. RETURN TRUE;
  161. END StartPlClock;
  162. (**
  163. Stop given PL clocks
  164. channels: a set of clock channels to stop
  165. res: result code; zero in case of success
  166. Returns TRUE in case of success
  167. *)
  168. PROCEDURE StopPlClocks*(channels: SET; VAR res: WORD): BOOLEAN;
  169. BEGIN
  170. IF channels * {0,1,2,3} = {} THEN res := InvalidChannel; RETURN FALSE; END;
  171. Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
  172. IF 0 IN channels THEN Platform.slcr.FPGA0_THR_CNT := 1; END;
  173. IF 1 IN channels THEN Platform.slcr.FPGA1_THR_CNT := 1; END;
  174. IF 2 IN channels THEN Platform.slcr.FPGA2_THR_CNT := 1; END;
  175. IF 3 IN channels THEN Platform.slcr.FPGA3_THR_CNT := 1; END;
  176. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  177. res := Ok;
  178. RETURN TRUE;
  179. END StopPlClocks;
  180. (**
  181. Start given PL clocks
  182. channels: a set of clock channels to start
  183. res: result code; zero in case of success
  184. Returns TRUE in case of success
  185. *)
  186. PROCEDURE StartPlClocks*(channels: SET; VAR res: WORD): BOOLEAN;
  187. BEGIN
  188. IF channels * {0,1,2,3} = {} THEN res := InvalidChannel; RETURN FALSE; END;
  189. Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
  190. IF 0 IN channels THEN Platform.slcr.FPGA0_THR_CNT := 0; END;
  191. IF 1 IN channels THEN Platform.slcr.FPGA1_THR_CNT := 0; END;
  192. IF 2 IN channels THEN Platform.slcr.FPGA2_THR_CNT := 0; END;
  193. IF 3 IN channels THEN Platform.slcr.FPGA3_THR_CNT := 0; END;
  194. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  195. res := Ok;
  196. RETURN TRUE;
  197. END StartPlClocks;
  198. PROCEDURE GetIoClockFrequency*(module: LONGINT; VAR res: WORD): HUGEINT;
  199. VAR
  200. baseFreq: HUGEINT;
  201. val: LONGINT;
  202. BEGIN
  203. CASE module OF
  204. IoUsb: (*!TODO*)
  205. |IoGem: (*!TODO*)
  206. |IoSdio: val := Platform.slcr.SDIO_CLK_CTRL;
  207. |IoSmc: val := Platform.slcr.SMC_CLK_CTRL;
  208. |IoSpi: val := Platform.slcr.SPI_CLK_CTRL;
  209. |IoQuadSpi: val := Platform.slcr.LQSPI_CLK_CTRL;
  210. |IoUart: val := Platform.slcr.UART_CLK_CTRL;
  211. |IoCan: (*!TODO*)
  212. |IoGpio: (*!TODO*)
  213. |IoI2c: (*!TODO*)
  214. ELSE
  215. res := InvalidModule;
  216. RETURN 0;
  217. END;
  218. CASE module OF
  219. IoUsb: (*!TODO*)
  220. |IoGem: (*!TODO*)
  221. |IoSdio, IoSmc, IoSpi, IoQuadSpi, IoUart:
  222. val := LSH(SYSTEM.MSK(val, 0x3f00), -8)
  223. |IoCan:(*!TODO*)
  224. |IoGpio:(*!TODO*)
  225. |IoI2c:(*!TODO*)
  226. END;
  227. baseFreq := GetPllClockFrequency(GetIoClockSource(module, res), res);
  228. IF res # Ok THEN RETURN 0 END;
  229. RETURN baseFreq DIV val
  230. END GetIoClockFrequency;
  231. PROCEDURE GetIoClockSource*(module: LONGINT; VAR res: WORD): LONGINT;
  232. VAR
  233. pll, val: LONGINT;
  234. BEGIN
  235. res := Ok;
  236. CASE module OF
  237. IoUsb: (*!TODO*)
  238. |IoGem: (*!TODO*)
  239. |IoSdio: val := Platform.slcr.SDIO_CLK_CTRL;
  240. |IoSmc: val := Platform.slcr.SMC_CLK_CTRL;
  241. |IoSpi: val := Platform.slcr.SPI_CLK_CTRL;
  242. |IoQuadSpi: val := Platform.slcr.LQSPI_CLK_CTRL;
  243. |IoUart: val := Platform.slcr.UART_CLK_CTRL;
  244. |IoCan: (*!TODO*)
  245. |IoGpio: (*!TODO*)
  246. |IoI2c: (*!TODO*)
  247. ELSE
  248. res := InvalidModule;
  249. RETURN -1;
  250. END;
  251. CASE module OF
  252. IoUsb: (*!TODO*)
  253. |IoGem: (*!TODO*)
  254. |IoSdio, IoSmc, IoSpi, IoQuadSpi, IoUart:
  255. pll := LSH(SYSTEM.MSK(val, 0x30), -4);
  256. IF pll = 2 THEN pll := ArmPll END;
  257. |IoCan:(*!TODO*)
  258. |IoGpio:(*!TODO*)
  259. |IoI2c:(*!TODO*)
  260. END;
  261. RETURN pll
  262. END GetIoClockSource;
  263. PROCEDURE SetIoClockFrequency*(module: LONGINT; freq: HUGEINT; VAR res: WORD): BOOLEAN;
  264. VAR
  265. baseFreq: HUGEINT;
  266. val, div: LONGINT;
  267. BEGIN
  268. res := Ok;
  269. CASE module OF
  270. IoUsb: (*!TODO*)
  271. |IoGem: (*!TODO*)
  272. |IoSdio: val := Platform.slcr.SDIO_CLK_CTRL;
  273. |IoSmc: val := Platform.slcr.SMC_CLK_CTRL;
  274. |IoSpi: val := Platform.slcr.SPI_CLK_CTRL;
  275. |IoQuadSpi: val := Platform.slcr.LQSPI_CLK_CTRL;
  276. |IoUart: val := Platform.slcr.UART_CLK_CTRL;
  277. |IoCan: (*!TODO*)
  278. |IoGpio: (*!TODO*)
  279. |IoI2c: (*!TODO*)
  280. ELSE
  281. res := InvalidModule;
  282. RETURN FALSE;
  283. END;
  284. baseFreq := GetPllClockFrequency(GetIoClockSource(module, res), res);
  285. IF res # Ok THEN RETURN FALSE END;
  286. Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
  287. CASE module OF
  288. IoUsb: (*!TODO*)
  289. |IoGem: (*!TODO*)
  290. |IoSdio, IoSmc, IoSpi, IoQuadSpi, IoUart:
  291. div := LONGINT(baseFreq DIV freq);
  292. val := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, val) - {8 .. 13} + SYSTEM.VAL(SET, LSH(div, 8)) * {8 .. 13});
  293. Platform.slcr.SDIO_CLK_CTRL := val
  294. |IoCan:(*!TODO*)
  295. |IoGpio:(*!TODO*)
  296. |IoI2c:(*!TODO*)
  297. END;
  298. Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
  299. RETURN TRUE
  300. END SetIoClockFrequency;
  301. PROCEDURE SetIoClockSource*(module, source: LONGINT; VAR res: WORD): BOOLEAN;
  302. BEGIN
  303. END SetIoClockSource;
  304. PROCEDURE StartIoClock*(module, device: LONGINT; VAR res: WORD): BOOLEAN;
  305. BEGIN
  306. END StartIoClock;
  307. PROCEDURE StopIoClock*(module, device: LONGINT; VAR res: WORD): BOOLEAN;
  308. BEGIN
  309. END StopIoClock;
  310. BEGIN
  311. psRefClockHz := BootConfig.GetIntValue("PsRefClockHz");
  312. END PsConfig.