tcl: add SPDX tag
[fw/openocd] / tcl / fpga / xilinx-xadc.cfg
1 # SPDX-License-Identifier: GPL-2.0-or-later
2
3 # Xilinx XADC support for 7 Series FPGAs
4 #
5 # The 7 Series FPGAs contain an on-chip 12 bit ADC that can probe die
6 # temperature, internal power supply rail voltages as well as external
7 # voltages. The XADC is available both from fabric as well as through the
8 # JTAG TAP.
9 #
10 # This code implements access through the JTAG TAP.
11 #
12 # https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf
13
14 # build a 32 bit DRP command for the XADC DR
15 proc xadc_cmd {cmd addr data} {
16         array set cmds {
17                 NOP 0x00
18                 READ 0x01
19                 WRITE 0x02
20         }
21         return [expr {($cmds($cmd) << 26) | ($addr << 16) | ($data << 0)}]
22 }
23
24 # XADC register addresses
25 # Some addresses (status registers 0-3) have special function when written to.
26 proc XADC {key} {
27         array set addrs {
28                 TEMP 0x00
29                 LOCK 0x00
30                 VCCINT 0x01
31                 VCCAUX 0x02
32                 VAUXEN 0x02
33                 VPVN 0x03
34                 RESET 0x03
35                 VREFP 0x04
36                 VREFN 0x05
37                 VCCBRAM 0x06
38                 SUPAOFFS 0x08
39                 ADCAOFFS 0x09
40                 ADCAGAIN 0x0a
41                 VCCPINT 0x0d
42                 VCCPAUX 0x0e
43                 VCCODDR 0x0f
44                 VAUX0 0x10
45                 VAUX1 0x11
46                 VAUX2 0x12
47                 VAUX3 0x13
48                 VAUX4 0x14
49                 VAUX5 0x15
50                 VAUX6 0x16
51                 VAUX7 0x17
52                 VAUX8 0x18
53                 VAUX9 0x19
54                 VAUX10 0x1a
55                 VAUX11 0x1b
56                 VAUX12 0x1c
57                 VAUX13 0x1d
58                 VAUX14 0x1e
59                 VAUX15 0x1f
60                 SUPBOFFS 0x30
61                 ADCBOFFS 0x31
62                 ADCBGAIN 0x32
63                 FLAG 0x3f
64                 CFG0 0x40
65                 CFG1 0x41
66                 CFG2 0x42
67                 SEQ0 0x48
68                 SEQ1 0x49
69                 SEQ2 0x4a
70                 SEQ3 0x4b
71                 SEQ4 0x4c
72                 SEQ5 0x4d
73                 SEQ6 0x4e
74                 SEQ7 0x4f
75                 ALARM0 0x50
76                 ALARM1 0x51
77                 ALARM2 0x52
78                 ALARM3 0x53
79                 ALARM4 0x54
80                 ALARM5 0x55
81                 ALARM6 0x56
82                 ALARM7 0x57
83                 ALARM8 0x58
84                 ALARM9 0x59
85                 ALARM10 0x5a
86                 ALARM11 0x5b
87                 ALARM12 0x5c
88                 ALARM13 0x5d
89                 ALARM14 0x5e
90                 ALARM15 0x5f
91         }
92         return $addrs($key)
93 }
94
95 # Select the XADC DR
96 proc xadc_select {tap} {
97         set XADC_IR 0x37
98         irscan $tap $XADC_IR
99         runtest 10
100 }
101
102 # XADC transfer
103 proc xadc_xfer {tap cmd addr data} {
104         set ret [drscan $tap 32 [xadc_cmd $cmd $addr $data]]
105         runtest 10
106         return [expr "0x$ret"]
107 }
108
109 # XADC register write
110 proc xadc_write {tap addr data} {
111         xadc_xfer $tap WRITE $addr $data
112 }
113
114 # XADC register read, non-pipelined
115 proc xadc_read {tap addr} {
116         xadc_xfer $tap READ $addr 0
117         return [xadc_xfer $tap NOP 0 0]
118 }
119
120 # convert 16 bit register code from ADC measurement on
121 # external voltages (VAUX) to Volt
122 proc xadc_volt {code} {
123         return [expr {$code * 1./(1 << 16)}]
124 }
125
126 # convert 16 bit temperature measurement to Celsius
127 proc xadc_temp {code} {
128         return [expr {$code * 503.975/(1 << 16) - 273.15}]
129 }
130
131 # convert 16 bit suppply voltage measurement to Volt
132 proc xadc_sup {code} {
133         return [expr {$code * 3./(1 << 16)}]
134 }
135
136 # perform a single channel measurement using default settings
137 proc xadc_single {tap ch} {
138         set cfg0 [xadc_read $tap [XADC CFG0]]
139         set cfg1 [xadc_read $tap [XADC CFG1]]
140         # set channel
141         xadc_write $tap [XADC CFG0] $cfg0
142         # single channel, disable the sequencer
143         xadc_write $tap [XADC CFG1] 0x3000
144         # leave some time for the conversion
145         runtest 100
146         set ret [xadc_read $tap [XADC $ch]]
147         # restore CFG0/1
148         xadc_write $tap [XADC CFG0] $cfg0
149         xadc_write $tap [XADC CFG1] $cfg1
150         return $ret
151 }
152
153 # measure all internal voltages
154 proc xadc_report {tap} {
155         xadc_select $tap
156         echo "TEMP [format %.2f [xadc_temp [xadc_single $tap TEMP]]] C"
157         foreach ch [list VCCINT VCCAUX VCCBRAM VPVN VREFP VREFN \
158                 VCCPINT VCCPAUX VCCODDR] {
159                 echo "$ch [format %.3f [xadc_sup [xadc_single $tap $ch]]] V"
160         }
161 }