123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- (**
- AUTHOR: Alexey Morozov
- PURPOSE: Interface for system level configuration/control of Zynq Processing System (PS)
- *)
- MODULE PsConfig;
- IMPORT
- SYSTEM, Platform, BootConfig, Trace;
- CONST
- (** error codes *)
- Ok* = 0;
- InvalidChannel* = 1; (** invalid channel (e.g. PL clock channel) specified *)
- InvalidClockSource* = 2; (** invalid clock source specified *)
- InvalidDivisor* = 3; (** invalid clock divisor value specified *)
- InvalidModule* = 4; (** invalid I/O module specified *)
- InvalidDevice* = 5; (** invalid I/O device for specified module *)
- UnknownError* = 256;
- (** PLL clock source types *)
- IoPll* = 0; (** IO PLL used as a clock source for IO peripherals *)
- ArmPll* = 1; (** ARM PLL used as a clock source for the CPU *)
- DdrPll* = 3; (** DDR PLL used as a clock source for DDR memory *)
- (** I/O Clock Modules *)
- IoUsb* = 0;
- IoGem* = 1;
- IoSdio* = 2;
- IoSmc* = 3;
- IoSpi* = 4;
- IoQuadSpi* = 5;
- IoUart* = 6;
- IoCan* = 7;
- IoGpio* = 8;
- IoI2c* = 9;
- VAR
- psRefClockHz: HUGEINT;
- (**
- Get clock frequency of a given PLL clock source
- srcSel: source selector (either of IoPll, ArmPll, DdrPll)
- res: result code; zero in case of success
- Returns the frequency in Hz
- *)
- PROCEDURE GetPllClockFrequency*(srcSel: LONGINT; VAR res: WORD): HUGEINT;
- BEGIN
- CASE srcSel OF
- |IoPll: RETURN HUGEINT(LSH(SYSTEM.MSK(Platform.slcr.IO_PLL_CTRL,0x7F000),-12)) * psRefClockHz;
- |ArmPll: RETURN HUGEINT(LSH(SYSTEM.MSK(Platform.slcr.ARM_PLL_CTRL,0x7F000),-12)) * psRefClockHz;
- |DdrPll: RETURN HUGEINT(LSH(SYSTEM.MSK(Platform.slcr.DDR_PLL_CTRL,0x7F000),-12)) * psRefClockHz;
- ELSE
- res := InvalidClockSource; RETURN 0;
- END;
- END GetPllClockFrequency;
- (**
- Setup reset signals to programming logic
- assertedChannels: specifies the set of PL channels with asserted reset; can include 0, 1, 2, 3
- res: result code; zero in case of success
- Returns TRUE in case of success
- *)
- PROCEDURE SetPlResets*(assertedChannels: SET; VAR res: WORD): BOOLEAN;
- BEGIN
- IF assertedChannels * {4..31} # {} THEN res := InvalidChannel; RETURN FALSE; END;
- Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
- Platform.slcr.FPGA_RST_CTRL := assertedChannels;
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := Ok;
- RETURN TRUE;
- END SetPlResets;
- (**
- Setup a given channel of Programming Logic (PL) clock
- channel: selected channel (either of 0, 1, 2, 3)
- srcSel: source selector (either of IoPll, ArmPll, DdrPll)
- divisor0: provides the divisor used to divide the source clock to generate the required generated clock frequency. First cascade divider.
- divisor1: provides the divisor used to divide the source clock to generate the required generated clock frequency. Second cascade divider.
- res: result code; zero in case of success
- Returns TRUE in case of success
- *)
- PROCEDURE SetPlClock*(channel: LONGINT; srcSel: LONGINT; divisor0, divisor1: LONGINT; VAR res: WORD): BOOLEAN;
- BEGIN
- IF (srcSel > 0) OR (srcSel > 3) THEN res := InvalidClockSource; RETURN FALSE; END;
- IF (divisor0 < 1) OR (divisor0 > 63) OR (divisor1 < 0) OR (divisor1 > 63) THEN res := InvalidDivisor; RETURN FALSE; END;
- Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
- CASE channel OF
- |0: Platform.slcr.FPGA0_CLK_CTRL := srcSel + LSH(divisor0,8) + LSH(divisor1,20);
- |1: Platform.slcr.FPGA1_CLK_CTRL := srcSel + LSH(divisor0,8) + LSH(divisor1,20);
- |2: Platform.slcr.FPGA2_CLK_CTRL := srcSel + LSH(divisor0,8) + LSH(divisor1,20);
- |3: Platform.slcr.FPGA3_CLK_CTRL := srcSel + LSH(divisor0,8) + LSH(divisor1,20);
- ELSE
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := InvalidChannel;
- RETURN FALSE;
- END;
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := Ok;
- RETURN TRUE;
- END SetPlClock;
- (**
- Get clock frequency of a given PL clock channel
- res: result code; zero in case of success
- Returns the frequency in Hz
- *)
- PROCEDURE GetPlClockFrequency*(channel: LONGINT; VAR res: WORD): HUGEINT;
- VAR
- d, srcSel, divisor0, divisor1: LONGINT;
- BEGIN
- CASE channel OF
- |0: d := Platform.slcr.FPGA0_CLK_CTRL;
- |1: d := Platform.slcr.FPGA1_CLK_CTRL;
- |2: d := Platform.slcr.FPGA2_CLK_CTRL;
- |3: d := Platform.slcr.FPGA3_CLK_CTRL;
- ELSE
- res := InvalidChannel;
- RETURN 0;
- END;
- srcSel := LSH(SYSTEM.MSK(d,0x30),-4);
- divisor0 := LSH(SYSTEM.MSK(d,0x3F00),-8);
- divisor1 := LSH(SYSTEM.MSK(d,0x3F00000),-20);
- RETURN GetPllClockFrequency(srcSel,res) DIV (divisor0*divisor1);
- END GetPlClockFrequency;
- (**
- Stop a given PL clock
- channel: clock channel number
- res: result code; zero in case of success
- Returns TRUE in case of success
- *)
- PROCEDURE StopPlClock*(channel: LONGINT; VAR res: WORD): BOOLEAN;
- BEGIN
- Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
- CASE channel OF
- |0: Platform.slcr.FPGA0_THR_CNT := 1;
- |1: Platform.slcr.FPGA1_THR_CNT := 1;
- |2: Platform.slcr.FPGA2_THR_CNT := 1;
- |3: Platform.slcr.FPGA3_THR_CNT := 1;
- ELSE
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := InvalidChannel;
- RETURN FALSE;
- END;
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := Ok;
- RETURN TRUE;
- END StopPlClock;
- (**
- Start a given PL clock
- channel: clock channel number
- res: result code; zero in case of success
- Returns TRUE in case of success
- *)
- PROCEDURE StartPlClock*(channel: LONGINT; VAR res: WORD): BOOLEAN;
- BEGIN
- Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
- CASE channel OF
- |0: Platform.slcr.FPGA0_THR_CNT := 0;
- |1: Platform.slcr.FPGA1_THR_CNT := 0;
- |2: Platform.slcr.FPGA2_THR_CNT := 0;
- |3: Platform.slcr.FPGA3_THR_CNT := 0;
- ELSE
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := InvalidChannel;
- RETURN FALSE;
- END;
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := Ok;
- RETURN TRUE;
- END StartPlClock;
- (**
- Stop given PL clocks
- channels: a set of clock channels to stop
- res: result code; zero in case of success
- Returns TRUE in case of success
- *)
- PROCEDURE StopPlClocks*(channels: SET; VAR res: WORD): BOOLEAN;
- BEGIN
- IF channels * {0,1,2,3} = {} THEN res := InvalidChannel; RETURN FALSE; END;
- Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
- IF 0 IN channels THEN Platform.slcr.FPGA0_THR_CNT := 1; END;
- IF 1 IN channels THEN Platform.slcr.FPGA1_THR_CNT := 1; END;
- IF 2 IN channels THEN Platform.slcr.FPGA2_THR_CNT := 1; END;
- IF 3 IN channels THEN Platform.slcr.FPGA3_THR_CNT := 1; END;
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := Ok;
- RETURN TRUE;
- END StopPlClocks;
- (**
- Start given PL clocks
- channels: a set of clock channels to start
- res: result code; zero in case of success
- Returns TRUE in case of success
- *)
- PROCEDURE StartPlClocks*(channels: SET; VAR res: WORD): BOOLEAN;
- BEGIN
- IF channels * {0,1,2,3} = {} THEN res := InvalidChannel; RETURN FALSE; END;
- Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
- IF 0 IN channels THEN Platform.slcr.FPGA0_THR_CNT := 0; END;
- IF 1 IN channels THEN Platform.slcr.FPGA1_THR_CNT := 0; END;
- IF 2 IN channels THEN Platform.slcr.FPGA2_THR_CNT := 0; END;
- IF 3 IN channels THEN Platform.slcr.FPGA3_THR_CNT := 0; END;
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- res := Ok;
- RETURN TRUE;
- END StartPlClocks;
- PROCEDURE GetIoClockFrequency*(module: LONGINT; VAR res: WORD): HUGEINT;
- VAR
- baseFreq: HUGEINT;
- val: LONGINT;
- BEGIN
- CASE module OF
- IoUsb: (*!TODO*)
- |IoGem: (*!TODO*)
- |IoSdio: val := Platform.slcr.SDIO_CLK_CTRL;
- |IoSmc: val := Platform.slcr.SMC_CLK_CTRL;
- |IoSpi: val := Platform.slcr.SPI_CLK_CTRL;
- |IoQuadSpi: val := Platform.slcr.LQSPI_CLK_CTRL;
- |IoUart: val := Platform.slcr.UART_CLK_CTRL;
- |IoCan: (*!TODO*)
- |IoGpio: (*!TODO*)
- |IoI2c: (*!TODO*)
- ELSE
- res := InvalidModule;
- RETURN 0;
- END;
- CASE module OF
- IoUsb: (*!TODO*)
- |IoGem: (*!TODO*)
- |IoSdio, IoSmc, IoSpi, IoQuadSpi, IoUart:
- val := LSH(SYSTEM.MSK(val, 0x3f00), -8)
- |IoCan:(*!TODO*)
- |IoGpio:(*!TODO*)
- |IoI2c:(*!TODO*)
- END;
- baseFreq := GetPllClockFrequency(GetIoClockSource(module, res), res);
- IF res # Ok THEN RETURN 0 END;
- RETURN baseFreq DIV val
- END GetIoClockFrequency;
- PROCEDURE GetIoClockSource*(module: LONGINT; VAR res: WORD): LONGINT;
- VAR
- pll, val: LONGINT;
- BEGIN
- res := Ok;
- CASE module OF
- IoUsb: (*!TODO*)
- |IoGem: (*!TODO*)
- |IoSdio: val := Platform.slcr.SDIO_CLK_CTRL;
- |IoSmc: val := Platform.slcr.SMC_CLK_CTRL;
- |IoSpi: val := Platform.slcr.SPI_CLK_CTRL;
- |IoQuadSpi: val := Platform.slcr.LQSPI_CLK_CTRL;
- |IoUart: val := Platform.slcr.UART_CLK_CTRL;
- |IoCan: (*!TODO*)
- |IoGpio: (*!TODO*)
- |IoI2c: (*!TODO*)
- ELSE
- res := InvalidModule;
- RETURN -1;
- END;
- CASE module OF
- IoUsb: (*!TODO*)
- |IoGem: (*!TODO*)
- |IoSdio, IoSmc, IoSpi, IoQuadSpi, IoUart:
- pll := LSH(SYSTEM.MSK(val, 0x30), -4);
- IF pll = 2 THEN pll := ArmPll END;
- |IoCan:(*!TODO*)
- |IoGpio:(*!TODO*)
- |IoI2c:(*!TODO*)
- END;
- RETURN pll
- END GetIoClockSource;
- PROCEDURE SetIoClockFrequency*(module: LONGINT; freq: HUGEINT; VAR res: WORD): BOOLEAN;
- VAR
- baseFreq: HUGEINT;
- val, div: LONGINT;
- BEGIN
- res := Ok;
- CASE module OF
- IoUsb: (*!TODO*)
- |IoGem: (*!TODO*)
- |IoSdio: val := Platform.slcr.SDIO_CLK_CTRL;
- |IoSmc: val := Platform.slcr.SMC_CLK_CTRL;
- |IoSpi: val := Platform.slcr.SPI_CLK_CTRL;
- |IoQuadSpi: val := Platform.slcr.LQSPI_CLK_CTRL;
- |IoUart: val := Platform.slcr.UART_CLK_CTRL;
- |IoCan: (*!TODO*)
- |IoGpio: (*!TODO*)
- |IoI2c: (*!TODO*)
- ELSE
- res := InvalidModule;
- RETURN FALSE;
- END;
- baseFreq := GetPllClockFrequency(GetIoClockSource(module, res), res);
- IF res # Ok THEN RETURN FALSE END;
- Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey; (* enable writing to SLCR registers *)
- CASE module OF
- IoUsb: (*!TODO*)
- |IoGem: (*!TODO*)
- |IoSdio, IoSmc, IoSpi, IoQuadSpi, IoUart:
- div := LONGINT(baseFreq DIV freq);
- val := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, val) - {8 .. 13} + SYSTEM.VAL(SET, LSH(div, 8)) * {8 .. 13});
- Platform.slcr.SDIO_CLK_CTRL := val
- |IoCan:(*!TODO*)
- |IoGpio:(*!TODO*)
- |IoI2c:(*!TODO*)
- END;
- Platform.slcr.SLCR_LOCK := Platform.SlcrLockKey; (* disable writing to SLCR registers *)
- RETURN TRUE
- END SetIoClockFrequency;
- PROCEDURE SetIoClockSource*(module, source: LONGINT; VAR res: WORD): BOOLEAN;
- BEGIN
-
- END SetIoClockSource;
- PROCEDURE StartIoClock*(module, device: LONGINT; VAR res: WORD): BOOLEAN;
- BEGIN
-
- END StartIoClock;
- PROCEDURE StopIoClock*(module, device: LONGINT; VAR res: WORD): BOOLEAN;
- BEGIN
-
- END StopIoClock;
- BEGIN
- psRefClockHz := BootConfig.GetIntValue("PsRefClockHz");
- END PsConfig.
|