aboutsummaryrefslogtreecommitdiff
path: root/tcl/target/davinci.cfg
blob: 07a26b21c19cb9aecc3696560c2d83f5434dde24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#
# Utility code for DaVinci-family chips
#

# davinci_pinmux:  assigns PINMUX$reg <== $value
proc davinci_pinmux {soc reg value} {
	mww [expr [dict get $soc sysbase] + 4 * $reg] $value
}

# mrw: "memory read word", returns value of $reg
proc mrw {reg} {
	set value ""
	ocd_mem2array value 32 $reg 1
	return $value(0)
}

# mmw: "memory modify word", updates value of $reg
#	$reg <== ((value & ~$clearbits) | $setbits)
proc mmw {reg setbits clearbits} {
	set old [mrw $reg]
	set new [expr ($old & ~$clearbits) | $setbits]
	mww $reg $new
}

#
# pll_setup: initialize PLL
#  - pll_addr ... physical addr of controller
#  - mult ... pll multiplier
#  - config ... dict mapping { prediv, postdiv, div[1-9] } to dividers
#
# For PLLs that don't have a given register (e.g. plldiv8), or where a
# given divider is non-programmable, caller provides *NO* config mapping.
#

# PLL version 0x02: tested on dm355
# REVISIT:  On dm6446 and dm357 the PLLRST polarity is different.
proc pll_v02_setup {pll_addr mult config} {
	set pll_ctrl_addr [expr $pll_addr + 0x100]
	set pll_ctrl [mrw $pll_ctrl_addr]

	# 1 - clear CLKMODE (bit 8) iff using on-chip oscillator
	# NOTE:  this assumes we should clear that bit
	set pll_ctrl [expr $pll_ctrl & ~0x0100]
	mww $pll_ctrl_addr $pll_ctrl

	# 2 - clear PLLENSRC (bit 5)
	set pll_ctrl [expr $pll_ctrl & ~0x0020]
	mww $pll_ctrl_addr $pll_ctrl

	# 3 - clear PLLEN (bit 0) ... enter bypass mode
	set pll_ctrl [expr $pll_ctrl & ~0x0001]
	mww $pll_ctrl_addr $pll_ctrl

	# 4 - wait at least 4 refclk cycles
	sleep 1

	# 5 - set PLLRST (bit 3)
	set pll_ctrl [expr $pll_ctrl | 0x0008]
	mww $pll_ctrl_addr $pll_ctrl

	# 6 - set PLLDIS (bit 4)
	set pll_ctrl [expr $pll_ctrl | 0x0010]
	mww $pll_ctrl_addr $pll_ctrl

	# 7 - clear PLLPWRDN (bit 1)
	set pll_ctrl [expr $pll_ctrl & ~0x0002]
	mww $pll_ctrl_addr $pll_ctrl

	# 8 - clear PLLDIS (bit 4)
	set pll_ctrl [expr $pll_ctrl & ~0x0010]
	mww $pll_ctrl_addr $pll_ctrl

	# 9 - optional:  write prediv, postdiv, and pllm
	# NOTE:  for dm355 PLL1, postdiv is controlled via MISC register
	mww [expr $pll_addr + 0x0110] [expr ($mult - 1) & 0xff]
	if { [dict exists $config prediv] } {
		set div [dict get $config prediv]
		set div [expr 0x8000 | ($div - 1)]
		mww [expr $pll_addr + 0x0114] $div
	}
	if { [dict exists $config postdiv] } {
		set div [dict get $config postdiv]
		set div [expr 0x8000 | ($div - 1)]
		mww [expr $pll_addr + 0x0128] $div
	}

	# 10 - optional:  set plldiv1, plldiv2, ...
	# NOTE:  this assumes some registers have their just-reset values:
	#	- PLLSTAT.GOSTAT is clear when we enter
	#	- ALNCTL has everything set
	set go 0
	if { [dict exists $config div1] } {
		set div [dict get $config div1]
		set div [expr 0x8000 | ($div - 1)]
		mww [expr $pll_addr + 0x0118] $div
		set go 1
	}
	if { [dict exists $config div2] } {
		set div [dict get $config div2]
		set div [expr 0x8000 | ($div - 1)]
		mww [expr $pll_addr + 0x011c] $div
		set go 1
	}
	if { [dict exists $config div3] } {
		set div [dict get $config div3]
		set div [expr 0x8000 | ($div - 1)]
		mww [expr $pll_addr + 0x0120] $div
		set go 1
	}
	if { [dict exists $config div4] } {
		set div [dict get $config div4]
		set div [expr 0x8000 | ($div - 1)]
		mww [expr $pll_addr + 0x0160] $div
		set go 1
	}
	if { [dict exists $config div5] } {
		set div [dict get $config div5]
		set div [expr 0x8000 | ($div - 1)]
		mww [expr $pll_addr + 0x0164] $div
		set go 1
	}
	if {$go != 0} {
		# write pllcmd.GO; poll pllstat.GO
		mww [expr $pll_addr + 0x0138] 0x01
		set pllstat [expr $pll_addr + 0x013c]
		while {[expr [mrw $pllstat] & 0x01] != 0} { sleep 1 }
	}

	# 11 - wait at least 5 usec for reset to finish
	# (assume covered by overheads including JTAG messaging)

	# 12 - clear PLLRST (bit 3)
	set pll_ctrl [expr $pll_ctrl & ~0x0008]
	mww $pll_ctrl_addr $pll_ctrl

	# 13 - wait at least 8000 refclk cycles for PLL to lock
	# if we assume 24 MHz (slowest osc), that's 1/3 msec
	sleep 3

	# 14 - set PLLEN (bit 0) ... leave bypass mode
	set pll_ctrl [expr $pll_ctrl | 0x0001]
	mww $pll_ctrl_addr $pll_ctrl
}

# NOTE:  dm6446 requires EMURSTIE set in MDCTL before certain
# modules can be enabled.

# prepare a non-DSP module to be enabled; finish with psc_go
proc psc_enable {module} {
	set psc_addr 0x01c41000
	# write MDCTL
	mmw [expr $psc_addr + 0x0a00 + (4 * $module)] 0x03 0x1f
}

# execute non-DSP PSC transition(s) set up by psc_enable
proc psc_go {} {
	set psc_addr 0x01c41000
	set ptstat_addr [expr $psc_addr + 0x0128]

	# just in case PTSTAT.go isn't clear
	while { [expr [mrw $ptstat_addr] & 0x01] != 0 } { sleep 1 }

	# write PTCMD.go ... ignoring any DSP power domain
	mww [expr $psc_addr + 0x0120] 1

	# wait for PTSTAT.go to clear (again ignoring DSP power domain)
	while { [expr [mrw $ptstat_addr] & 0x01] != 0 } { sleep 1 }
}