1 # SPDX-License-Identifier: GPL-2.0-or-later
4 # Utility code for DaVinci-family chips
7 # davinci_pinmux: assigns PINMUX$reg <== $value
8 proc davinci_pinmux {soc reg value} {
9 mww [expr {[dict get $soc sysbase] + 4 * $reg}] $value
12 source [find mem_helper.tcl]
15 # pll_setup: initialize PLL
16 # - pll_addr ... physical addr of controller
17 # - mult ... pll multiplier
18 # - config ... dict mapping { prediv, postdiv, div[1-9] } to dividers
20 # For PLLs that don't have a given register (e.g. plldiv8), or where a
21 # given divider is non-programmable, caller provides *NO* config mapping.
24 # PLL version 0x02: tested on dm355
25 # REVISIT: On dm6446/dm357 the PLLRST polarity is different.
26 proc pll_v02_setup {pll_addr mult config} {
27 set pll_ctrl_addr [expr {$pll_addr + 0x100}]
28 set pll_ctrl [mrw $pll_ctrl_addr]
30 # 1 - clear CLKMODE (bit 8) iff using on-chip oscillator
31 # NOTE: this assumes we should clear that bit
32 set pll_ctrl [expr {$pll_ctrl & ~0x0100}]
33 mww $pll_ctrl_addr $pll_ctrl
35 # 2 - clear PLLENSRC (bit 5)
36 set pll_ctrl [expr {$pll_ctrl & ~0x0020}]
37 mww $pll_ctrl_addr $pll_ctrl
39 # 3 - clear PLLEN (bit 0) ... enter bypass mode
40 set pll_ctrl [expr {$pll_ctrl & ~0x0001}]
41 mww $pll_ctrl_addr $pll_ctrl
43 # 4 - wait at least 4 refclk cycles
46 # 5 - set PLLRST (bit 3)
47 set pll_ctrl [expr {$pll_ctrl | 0x0008}]
48 mww $pll_ctrl_addr $pll_ctrl
50 # 6 - set PLLDIS (bit 4)
51 set pll_ctrl [expr {$pll_ctrl | 0x0010}]
52 mww $pll_ctrl_addr $pll_ctrl
54 # 7 - clear PLLPWRDN (bit 1)
55 set pll_ctrl [expr {$pll_ctrl & ~0x0002}]
56 mww $pll_ctrl_addr $pll_ctrl
58 # 8 - clear PLLDIS (bit 4)
59 set pll_ctrl [expr {$pll_ctrl & ~0x0010}]
60 mww $pll_ctrl_addr $pll_ctrl
62 # 9 - optional: write prediv, postdiv, and pllm
63 # NOTE: for dm355 PLL1, postdiv is controlled via MISC register
64 mww [expr {$pll_addr + 0x0110}] [expr {($mult - 1) & 0xff}]
65 if { [dict exists $config prediv] } {
66 set div [dict get $config prediv]
67 set div [expr {0x8000 | ($div - 1)}]
68 mww [expr {$pll_addr + 0x0114}] $div
70 if { [dict exists $config postdiv] } {
71 set div [dict get $config postdiv]
72 set div [expr {0x8000 | ($div - 1)}]
73 mww [expr {$pll_addr + 0x0128}] $div
76 # 10 - optional: set plldiv1, plldiv2, ...
77 # NOTE: this assumes some registers have their just-reset values:
78 # - PLLSTAT.GOSTAT is clear when we enter
79 # - ALNCTL has everything set
81 if { [dict exists $config div1] } {
82 set div [dict get $config div1]
83 set div [expr {0x8000 | ($div - 1)}]
84 mww [expr {$pll_addr + 0x0118}] $div
87 if { [dict exists $config div2] } {
88 set div [dict get $config div2]
89 set div [expr {0x8000 | ($div - 1)}]
90 mww [expr {$pll_addr + 0x011c}] $div
93 if { [dict exists $config div3] } {
94 set div [dict get $config div3]
95 set div [expr {0x8000 | ($div - 1)}]
96 mww [expr {$pll_addr + 0x0120}] $div
99 if { [dict exists $config div4] } {
100 set div [dict get $config div4]
101 set div [expr {0x8000 | ($div - 1)}]
102 mww [expr {$pll_addr + 0x0160}] $div
105 if { [dict exists $config div5] } {
106 set div [dict get $config div5]
107 set div [expr {0x8000 | ($div - 1)}]
108 mww [expr {$pll_addr + 0x0164}] $div
112 # write pllcmd.GO; poll pllstat.GO
113 mww [expr {$pll_addr + 0x0138}] 0x01
114 set pllstat [expr {$pll_addr + 0x013c}]
115 while {[expr {[mrw $pllstat] & 0x01}] != 0} { sleep 1 }
117 mww [expr {$pll_addr + 0x0138}] 0x00
119 # 11 - wait at least 5 usec for reset to finish
120 # (assume covered by overheads including JTAG messaging)
122 # 12 - clear PLLRST (bit 3)
123 set pll_ctrl [expr {$pll_ctrl & ~0x0008}]
124 mww $pll_ctrl_addr $pll_ctrl
126 # 13 - wait at least 8000 refclk cycles for PLL to lock
127 # if we assume 24 MHz (slowest osc), that's 1/3 msec
130 # 14 - set PLLEN (bit 0) ... leave bypass mode
131 set pll_ctrl [expr {$pll_ctrl | 0x0001}]
132 mww $pll_ctrl_addr $pll_ctrl
135 # PLL version 0x03: tested on dm365
136 proc pll_v03_setup {pll_addr mult config} {
137 set pll_ctrl_addr [expr {$pll_addr + 0x100}]
138 set pll_secctrl_addr [expr {$pll_addr + 0x108}]
139 set pll_ctrl [mrw $pll_ctrl_addr]
141 # 1 - power up the PLL
142 set pll_ctrl [expr {$pll_ctrl & ~0x0002}]
143 mww $pll_ctrl_addr $pll_ctrl
145 # 2 - clear PLLENSRC (bit 5)
146 set pll_ctrl [expr {$pll_ctrl & ~0x0020}]
147 mww $pll_ctrl_addr $pll_ctrl
149 # 2 - clear PLLEN (bit 0) ... enter bypass mode
150 set pll_ctrl [expr {$pll_ctrl & ~0x0001}]
151 mww $pll_ctrl_addr $pll_ctrl
153 # 3 - wait at least 4 refclk cycles
156 # 4 - set PLLRST (bit 3)
157 set pll_ctrl [expr {$pll_ctrl | 0x0008}]
158 mww $pll_ctrl_addr $pll_ctrl
160 # 5 - wait at least 5 usec
163 # 6 - clear PLLRST (bit 3)
164 set pll_ctrl [expr {$pll_ctrl & ~0x0008}]
165 mww $pll_ctrl_addr $pll_ctrl
167 # 9 - optional: write prediv, postdiv, and pllm
168 mww [expr {$pll_addr + 0x0110}] [expr {($mult / 2) & 0x1ff}]
169 if { [dict exists $config prediv] } {
170 set div [dict get $config prediv]
171 set div [expr {0x8000 | ($div - 1)}]
172 mww [expr {$pll_addr + 0x0114}] $div
174 if { [dict exists $config postdiv] } {
175 set div [dict get $config postdiv]
176 set div [expr {0x8000 | ($div - 1)}]
177 mww [expr {$pll_addr + 0x0128}] $div
180 # 10 - write start sequence to PLLSECCTL
181 mww $pll_secctrl_addr 0x00470000
182 mww $pll_secctrl_addr 0x00460000
183 mww $pll_secctrl_addr 0x00400000
184 mww $pll_secctrl_addr 0x00410000
186 # 11 - optional: set plldiv1, plldiv2, ...
187 # NOTE: this assumes some registers have their just-reset values:
188 # - PLLSTAT.GOSTAT is clear when we enter
190 if { [dict exists $config div1] } {
191 set div [dict get $config div1]
192 set div [expr {0x8000 | ($div - 1)}]
193 mww [expr {$pll_addr + 0x0118}] $div
194 set aln [expr {$aln | 0x1}]
196 mww [expr {$pll_addr + 0x0118}] 0
198 if { [dict exists $config div2] } {
199 set div [dict get $config div2]
200 set div [expr {0x8000 | ($div - 1)}]
201 mww [expr {$pll_addr + 0x011c}] $div
202 set aln [expr {$aln | 0x2}]
204 mww [expr {$pll_addr + 0x011c}] 0
206 if { [dict exists $config div3] } {
207 set div [dict get $config div3]
208 set div [expr {0x8000 | ($div - 1)}]
209 mww [expr {$pll_addr + 0x0120}] $div
210 set aln [expr {$aln | 0x4}]
212 mww [expr {$pll_addr + 0x0120}] 0
214 if { [dict exists $config oscdiv] } {
215 set div [dict get $config oscdiv]
216 set div [expr {0x8000 | ($div - 1)}]
217 mww [expr {$pll_addr + 0x0124}] $div
219 mww [expr {$pll_addr + 0x0124}] 0
221 if { [dict exists $config div4] } {
222 set div [dict get $config div4]
223 set div [expr {0x8000 | ($div - 1)}]
224 mww [expr {$pll_addr + 0x0160}] $div
225 set aln [expr {$aln | 0x8}]
227 mww [expr {$pll_addr + 0x0160}] 0
229 if { [dict exists $config div5] } {
230 set div [dict get $config div5]
231 set div [expr {0x8000 | ($div - 1)}]
232 mww [expr {$pll_addr + 0x0164}] $div
233 set aln [expr {$aln | 0x10}]
235 mww [expr {$pll_addr + 0x0164}] 0
237 if { [dict exists $config div6] } {
238 set div [dict get $config div6]
239 set div [expr {0x8000 | ($div - 1)}]
240 mww [expr {$pll_addr + 0x0168}] $div
241 set aln [expr {$aln | 0x20}]
243 mww [expr {$pll_addr + 0x0168}] 0
245 if { [dict exists $config div7] } {
246 set div [dict get $config div7]
247 set div [expr {0x8000 | ($div - 1)}]
248 mww [expr {$pll_addr + 0x016c}] $div
249 set aln [expr {$aln | 0x40}]
251 mww [expr {$pll_addr + 0x016c}] 0
253 if { [dict exists $config div8] } {
254 set div [dict get $config div8]
255 set div [expr {0x8000 | ($div - 1)}]
256 mww [expr {$pll_addr + 0x0170}] $div
257 set aln [expr {$aln | 0x80}]
259 mww [expr {$pll_addr + 0x0170}] 0
261 if { [dict exists $config div9] } {
262 set div [dict get $config div9]
263 set div [expr {0x8000 | ($div - 1)}]
264 mww [expr {$pll_addr + 0x0174}] $div
265 set aln [expr {$aln | 0x100}]
267 mww [expr {$pll_addr + 0x0174}] 0
271 mww [expr {$pll_addr + 0x0138}] 0x00
272 # write alignment flags
273 mww [expr {$pll_addr + 0x0140}] $aln
274 # write pllcmd.GO; poll pllstat.GO
275 mww [expr {$pll_addr + 0x0138}] 0x01
276 set pllstat [expr {$pll_addr + 0x013c}]
277 while {[expr {[mrw $pllstat] & 0x01}] != 0} { sleep 1 }
279 mww [expr {$pll_addr + 0x0138}] 0x00
280 set addr [dict get $config ctladdr]
281 while {[expr {[mrw $addr] & 0x0e000000}] != 0x0e000000} { sleep 1 }
283 # 12 - set PLLEN (bit 0) ... leave bypass mode
284 set pll_ctrl [expr {$pll_ctrl | 0x0001}]
285 mww $pll_ctrl_addr $pll_ctrl
288 # NOTE: dm6446 requires EMURSTIE set in MDCTL before certain
289 # modules can be enabled.
291 # prepare a non-DSP module to be enabled; finish with psc_go
292 proc psc_enable {module} {
293 set psc_addr 0x01c41000
295 mmw [expr {$psc_addr + 0x0a00 + (4 * $module)}] 0x03 0x1f
298 # prepare a non-DSP module to be reset; finish with psc_go
299 proc psc_reset {module} {
300 set psc_addr 0x01c41000
302 mmw [expr {$psc_addr + 0x0a00 + (4 * $module)}] 0x01 0x1f
305 # execute non-DSP PSC transition(s) set up by psc_enable, psc_reset, etc
307 set psc_addr 0x01c41000
308 set ptstat_addr [expr {$psc_addr + 0x0128}]
310 # just in case PTSTAT.go isn't clear
311 while { [expr {[mrw $ptstat_addr] & 0x01}] != 0 } { sleep 1 }
313 # write PTCMD.go ... ignoring any DSP power domain
314 mww [expr {$psc_addr + 0x0120}] 1
316 # wait for PTSTAT.go to clear (again ignoring DSP power domain)
317 while { [expr {[mrw $ptstat_addr] & 0x01}] != 0 } { sleep 1 }
321 # A reset using only SRST is a "Warm Reset", resetting everything in the
322 # chip except ARM emulation (and everything _outside_ the chip that hooks
323 # up to SRST). But many boards don't expose SRST via their JTAG connectors
324 # (it's not present on TI-14 headers).
326 # From the chip-only perspective, a "Max Reset" is a "Warm" reset ... except
327 # without any board-wide side effects, since it's triggered using JTAG using
328 # either (a) ARM watchdog timer, or (b) ICEpick.
330 proc davinci_wdog_reset {} {
331 set timer2_phys 0x01c21c00
334 # - JTAG communication with the ARM *must* be working OK; this
335 # may imply using adaptive clocking or disabling WFI-in-idle
336 # - current target must be the DaVinci ARM
337 # - that ARM core must be halted
338 # - timer2 clock is still enabled (PSC 29 on most chips)
341 # Part I -- run regardless of being halted via JTAG
343 # NOTE: for now, we assume there's no DSP that could control the
344 # watchdog; or, equivalently, SUSPSRC.TMR2SRC says the watchdog
345 # suspend signal is controlled via ARM emulation suspend.
348 # EMUMGT_CLKSPEED: write FREE bit to run despite emulation halt
349 mww phys [expr {$timer2_phys + 0x28}] 0x00004000
352 # Part II -- in case watchdog hasn't been set up
355 # TCR: disable, force internal clock source
356 mww phys [expr {$timer2_phys + 0x20}] 0
358 # TGCR: reset, force to 64-bit wdog mode, un-reset ("initial" state)
359 mww phys [expr {$timer2_phys + 0x24}] 0
360 mww phys [expr {$timer2_phys + 0x24}] 0x110b
362 # clear counter (TIM12, TIM34) and period (PRD12, PRD34) registers
363 # so watchdog triggers ASAP
364 mww phys [expr {$timer2_phys + 0x10}] 0
365 mww phys [expr {$timer2_phys + 0x14}] 0
366 mww phys [expr {$timer2_phys + 0x18}] 0
367 mww phys [expr {$timer2_phys + 0x1c}] 0
369 # WDTCR: put into pre-active state, then active
370 mww phys [expr {$timer2_phys + 0x28}] 0xa5c64000
371 mww phys [expr {$timer2_phys + 0x28}] 0xda7e4000
374 # Part III -- it's ready to rumble
377 # WDTCR: write invalid WDKEY to trigger reset
378 mww phys [expr {$timer2_phys + 0x28}] 0x00004000