// 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/conn/v3/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) }