forked from google/periph
-
Notifications
You must be signed in to change notification settings - Fork 0
/
clock.go
330 lines (309 loc) · 10.3 KB
/
clock.go
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// Copyright 2017 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package bcm283x
import (
"errors"
"fmt"
"strings"
"time"
"periph.io/x/periph/conn/physic"
)
// errClockRegister is returned in a situation where the clock memory is not
// working as expected. It is mocked in tests.
var errClockRegister = errors.New("can't write to clock divisor CPU register")
// Clock sources frequency in hertz.
const (
clk19dot2MHz = 19200 * physic.KiloHertz
clk500MHz = 500 * physic.MegaHertz
)
const (
// 31:24 password
clockPasswdCtl clockCtl = 0x5A << 24 // PASSWD
// 23:11 reserved
clockMashMask clockCtl = 3 << 9 // MASH
clockMash0 clockCtl = 0 << 9 // src_freq / divI (ignores divF)
clockMash1 clockCtl = 1 << 9
clockMash2 clockCtl = 2 << 9
clockMash3 clockCtl = 3 << 9 // will cause higher spread
clockFlip clockCtl = 1 << 8 // FLIP
clockBusy clockCtl = 1 << 7 // BUSY
// 6 reserved
clockKill clockCtl = 1 << 5 // KILL
clockEnable clockCtl = 1 << 4 // ENAB
clockSrcMask clockCtl = 0xF << 0 // SRC
clockSrcGND clockCtl = 0 // 0Hz
clockSrc19dot2MHz clockCtl = 1 // 19.2MHz
clockSrcTestDebug0 clockCtl = 2 // 0Hz
clockSrcTestDebug1 clockCtl = 3 // 0Hz
clockSrcPLLA clockCtl = 4 // 0Hz
clockSrcPLLC clockCtl = 5 // 1000MHz (changes with overclock settings)
clockSrcPLLD clockCtl = 6 // 500MHz
clockSrcHDMI clockCtl = 7 // 216MHz; may be disabled
// 8-15 == GND.
)
// clockCtl controls the clock properties.
//
// It must not be changed while busy is set or a glitch may occur.
//
// Page 107
type clockCtl uint32
func (c clockCtl) String() string {
var out []string
if c&0xFF000000 == clockPasswdCtl {
c &^= 0xFF000000
out = append(out, "PWD")
}
switch c & clockMashMask {
case clockMash1:
out = append(out, "Mash1")
case clockMash2:
out = append(out, "Mash2")
case clockMash3:
out = append(out, "Mash3")
default:
}
c &^= clockMashMask
if c&clockFlip != 0 {
out = append(out, "Flip")
c &^= clockFlip
}
if c&clockBusy != 0 {
out = append(out, "Busy")
c &^= clockBusy
}
if c&clockKill != 0 {
out = append(out, "Kill")
c &^= clockKill
}
if c&clockEnable != 0 {
out = append(out, "Enable")
c &^= clockEnable
}
switch x := c & clockSrcMask; x {
case clockSrcGND:
out = append(out, "GND(0Hz)")
case clockSrc19dot2MHz:
out = append(out, "19.2MHz")
case clockSrcTestDebug0:
out = append(out, "Debug0(0Hz)")
case clockSrcTestDebug1:
out = append(out, "Debug1(0Hz)")
case clockSrcPLLA:
out = append(out, "PLLA(0Hz)")
case clockSrcPLLC:
out = append(out, "PLLD(1000MHz)")
case clockSrcPLLD:
out = append(out, "PLLD(500MHz)")
case clockSrcHDMI:
out = append(out, "HDMI(216MHz)")
default:
out = append(out, fmt.Sprintf("GND(%d)", x))
}
c &^= clockSrcMask
if c != 0 {
out = append(out, fmt.Sprintf("clockCtl(0x%0x)", uint32(c)))
}
return strings.Join(out, "|")
}
const (
// 31:24 password
clockPasswdDiv clockDiv = 0x5A << 24 // PASSWD
// Integer part of the divisor
clockDiviShift = 12
clockDiviMax = (1 << 12) - 1
clockDiviMask clockDiv = clockDiviMax << clockDiviShift // DIVI
// Fractional part of the divisor
clockDivfMask clockDiv = (1 << 12) - 1 // DIVF
)
// clockDiv is a 12.12 fixed point value.
//
// The fractional part generates a significant amount of noise so it is
// preferable to not use it.
//
// Page 108
type clockDiv uint32
func (c clockDiv) String() string {
i := (c & clockDiviMask) >> clockDiviShift
c &^= clockDiviMask
if c == 0 {
return fmt.Sprintf("%d.0", i)
}
return fmt.Sprintf("%d.(%d/%d)", i, c, clockDiviMax)
}
// clock is a pair of clockCtl / clockDiv.
//
// It can be set to one of the sources: clockSrc19dot2MHz(19.2MHz) and
// clockSrcPLLD(500Mhz), then divided to a value to get the resulting clock.
// Per spec the resulting frequency should be under 25Mhz.
type clock struct {
ctl clockCtl
div clockDiv
}
// findDivisorExact finds the clock divisor and wait cycles to reduce src to
// desired hz.
//
// The clock divisor is capped to clockDiviMax.
//
// Returns clock divisor, wait cycles. Returns 0, 0 if no exact match is found.
// Favorizes high clock divisor value over high clock wait cycles. This means
// that the function is slower than it could be, but results in more stable
// clock.
func findDivisorExact(src, desired physic.Frequency, maxWaitCycles uint32) (uint32, uint32) {
if src < desired || src%desired != 0 || src/physic.Frequency(maxWaitCycles*clockDiviMax) > desired {
// Can't attain without oversampling (too low) or desired frequency is
// higher than the source (too high) or is not a multiple.
return 0, 0
}
factor := uint32(src / desired)
// TODO(maruel): Only iterate over valid divisors to save a bit more
// calculations. Since it's is only doing 32 loops, this is not a big deal.
for wait := uint32(1); wait <= maxWaitCycles; wait++ {
if rest := factor % wait; rest != 0 {
continue
}
clk := factor / wait
if clk == 0 {
break
}
if clk <= clockDiviMax {
return clk, wait
}
}
return 0, 0
}
// findDivisorOversampled tries to find the lowest allowed oversampling to make
// desiredHz a multiple of srcHz.
//
// Allowed oversampling depends on the desiredHz. Cap oversampling because
// oversampling at 10x in the 1Mhz range becomes unreasonable in term of
// memory usage.
func findDivisorOversampled(src, desired physic.Frequency, maxWaitCycles uint32) (uint32, uint32, physic.Frequency) {
//log.Printf("findDivisorOversampled(%s, %s, %d)", src, desired, maxWaitCycles)
// There are 2 reasons:
// - desired is so low it is not possible to lower src to this frequency
// - not a multiple, there's a need for a prime number
// TODO(maruel): Rewrite without a loop, this is not needed. Leverage primes
// to reduce the number of iterations.
for multiple := physic.Frequency(2); ; multiple++ {
n := multiple * desired
if n > 100*physic.KiloHertz && multiple > 10 {
break
}
if clk, wait := findDivisorExact(src, n, maxWaitCycles); clk != 0 {
return clk, wait, n
}
}
return 0, 0, 0
}
// calcSource choose the best source to get the exact desired clock.
//
// It calculates the clock source, the clock divisor and the wait cycles, if
// applicable. Wait cycles is 'div minus 1'.
func calcSource(f physic.Frequency, maxWaitCycles uint32) (clockCtl, uint32, uint32, physic.Frequency, error) {
if f < physic.Hertz {
return 0, 0, 0, 0, fmt.Errorf("bcm283x-clock: desired frequency %s must be >1hz", f)
}
if f > 125*physic.MegaHertz {
return 0, 0, 0, 0, fmt.Errorf("bcm283x-clock: desired frequency %s is too high", f)
}
// http://elinux.org/BCM2835_datasheet_errata states that clockSrc19dot2MHz
// is the cleanest clock source so try it first.
div, wait := findDivisorExact(clk19dot2MHz, f, maxWaitCycles)
if div != 0 {
return clockSrc19dot2MHz, div, wait, f, nil
}
// Try 500Mhz.
div, wait = findDivisorExact(clk500MHz, f, maxWaitCycles)
if div != 0 {
return clockSrcPLLD, div, wait, f, nil
}
// Try with up to 10x oversampling. This is generally useful for lower
// frequencies, below 10kHz. Prefer the one with less oversampling. Only for
// non-aliased matches.
div19, wait19, f19 := findDivisorOversampled(clk19dot2MHz, f, maxWaitCycles)
div500, wait500, f500 := findDivisorOversampled(clk500MHz, f, maxWaitCycles)
if div19 != 0 && (div500 == 0 || f19 < f500) {
return clockSrc19dot2MHz, div19, wait19, f19, nil
}
if div500 != 0 {
return clockSrcPLLD, div500, wait500, f500, nil
}
return 0, 0, 0, 0, errors.New("failed to find a good clock")
}
// set changes the clock frequency to the desired value or the closest one
// otherwise.
//
// f=0 means disabled.
//
// maxWaitCycles is the maximum oversampling via an additional wait cycles that
// can further divide the clock. Use 1 if no additional wait cycle is
// available. It is expected to be dmaWaitcyclesMax+1.
//
// Returns the actual clock used and divisor.
func (c *clock) set(f physic.Frequency, maxWaitCycles uint32) (physic.Frequency, uint32, error) {
if f == 0 {
c.ctl = clockPasswdCtl | clockKill
for c.ctl&clockBusy != 0 {
}
return 0, 0, nil
}
ctl, div, div2, actual, err := calcSource(f, maxWaitCycles)
if err != nil {
return 0, 0, err
}
return actual, div2, c.setRaw(ctl, div)
}
// setRaw sets the clock speed with the clock source and the divisor.
func (c *clock) setRaw(ctl clockCtl, div uint32) error {
if div < 1 || div > clockDiviMax {
return errors.New("invalid clock divisor")
}
if ctl != clockSrc19dot2MHz && ctl != clockSrcPLLD {
return errors.New("invalid clock control")
}
// Stop the clock.
// TODO(maruel): Do not stop the clock if the current clock rate is the one
// desired.
for c.ctl&clockBusy != 0 {
c.ctl = clockPasswdCtl | clockKill
}
d := clockDiv(div << clockDiviShift)
c.div = clockPasswdDiv | d
Nanospin(10 * time.Nanosecond)
// Page 107
c.ctl = clockPasswdCtl | ctl
Nanospin(10 * time.Nanosecond)
c.ctl = clockPasswdCtl | ctl | clockEnable
if c.div != d {
// This error is mocked out in tests, so the code path of set() callers can
// follow on.
return errClockRegister
}
return nil
}
func (c *clock) String() string {
return fmt.Sprintf("%s / %s", c.ctl, c.div)
}
// clockMap is the memory mapped clock registers.
//
// The clock #1 must not be touched since it is being used by the ethernet
// controller.
//
// Page 107 for gp0~gp2.
// https://scribd.com/doc/127599939/BCM2835-Audio-clocks for PCM/PWM.
type clockMap struct {
reserved0 [0x70 / 4]uint32 //
gp0 clock // CM_GP0CTL+CM_GP0DIV; 0x70-0x74 (125MHz max)
gp1ctl uint32 // CM_GP1CTL+CM_GP1DIV; 0x78-0x7A must not use (used by ethernet)
gp1div uint32 // CM_GP1CTL+CM_GP1DIV; 0x78-0x7A must not use (used by ethernet)
gp2 clock // CM_GP2CTL+CM_GP2DIV; 0x80-0x84 (125MHz max)
reserved1 [(0x98 - 0x88) / 4]uint32 // 0x88-0x94
pcm clock // CM_PCMCTL+CM_PCMDIV 0x98-0x9C
pwm clock // CM_PWMCTL+CM_PWMDIV 0xA0-0xA4
}
func (c *clockMap) GoString() string {
return fmt.Sprintf(
"{\n gp0: %s,\n gp1: %s,\n gp2: %s,\n pcm: %sw,\n pwm: %s,\n}",
&c.gp0, &clock{clockCtl(c.gp1ctl), clockDiv(c.gp1div)}, &c.gp2, &c.pcm, &c.pwm)
}