chore: refactoring

Signed-off-by: Matthias Riegler <matthias.riegler@ankorstore.com>
This commit is contained in:
Matthias Riegler
2023-07-10 07:26:18 +02:00
parent 4542e970a7
commit ddc1dbe1e8
2 changed files with 110 additions and 105 deletions

View File

@@ -12,7 +12,7 @@ import (
const (
bcm2711PeripheryBaseAddr = 0xFE000000
bcm2711PwmAddr = bcm2711PeripheryBaseAddr + 0x20C000
bcm2711RegPwmAddr = bcm2711PeripheryBaseAddr + 0x20C000
bcm2711GpioAddr = bcm2711PeripheryBaseAddr + 0x200000
bcm2711ClkAddr = bcm2711PeripheryBaseAddr + 0x101000
bcm2711ClkManagerPwd = (0x5A << 24) //(31 - 24) on CM_GP0CTL/CM_GP1CTL/CM_GP2CTL regs
@@ -20,44 +20,32 @@ const (
bcm2711FrontButtonPin = 20
bcm2711StealthPin = 21
bcm2711PwmTachPin = 13
bcm2711RegPwmTachPin = 13
GPFSEL0 = 0x00
GPFSEL1 = 0x01
GPFSEL2 = 0x02
bcm2711RegGpfsel0 = 0x00
bcm2711RegGpfsel1 = 0x01
bcm2711RegGpfsel2 = 0x02
PWM_CTL = 0x00
PWM_STA = 0x01
PWM_DMAC = 0x02
PWM_RNG1 = 0x04
PWM_DAT1 = 0x05
PWM_FIF1 = 0x06
bcm2711RegPwmCtl = 0x00
bcm2711RegPwmSta = 0x01
bcm2711RegPwmRng1 = 0x04
bcm2711RegPwmFif1 = 0x06
PWM_CTL_PWEN2 = 8 // Enable (pwm2)
PWM_CTL_CLRF1 = 6 // Clear FIFO
PWM_CTL_MSEN1 = 7 // Use M/S algorithm
PWM_CTL_USEF1 = 5 // Use FIFO
PWM_CTL_POLA1 = 4 // Invert polarity
PWM_CTL_SBIT1 = 3 // Line level when not transmitting
PWM_CTL_RPTL1 = 2 // Repeat last data when FIFO is empty
PWM_CTL_MODE1 = 1 // Mode; 0: PWM, 1: Serializer
PWM_CTL_PWEN1 = 0 // Enable (pwm1)
bcm2711RegPwmCtlBitPwen2 = 8 // Enable (pwm2)
bcm2711RegPwmCtlBitClrf1 = 6 // Clear FIFO
bcm2711RegPwmCtlBitUsef1 = 5 // Use FIFO
bcm2711RegPwmCtlBitSbit1 = 3 // Line level when not transmitting
bcm2711RegPwmCtlBitRptl1 = 2 // Repeat last data when FIFO is empty
bcm2711RegPwmCtlBitMode1 = 1 // Mode; 0: PWM, 1: Serializer
bcm2711RegPwmCtlBitPwen1 = 0 // Enable (pwm1)
PWM_STA_STA1 = 9 // Status
PWM_STA_BERR = 8 // Bus Error
PWM_STA_GAPO1 = 4 // Gap detected
PWM_STA_RERR1 = 3 // FIFO Read Error
PWM_STA_WERR1 = 2 // FIFO Write Error
PWM_STA_EMPT1 = 1 // FIFO Empty
PWM_STA_FULL1 = 0 // FIFO Full
PWMCLK_CNTL = 0x28
PWMCLK_CNTL_SRC_OSC = 0
PWMCLK_CNTL_ENABLE = 4
PWMCLK_DIV = 0x29
bcm2711RegPwmclkCntrl = 0x28
bcm2711RegPwmclkDiv = 0x29
bcm2711RegPwmclkCntrlBitSrcOsc = 0
bcm2711RegPwmclkCntrlBitEnable = 4
)
type bcm2711bcm struct {
type bcm2711 struct {
// Config options
opts hal.ComputeBladeHalOpts
@@ -76,7 +64,7 @@ type bcm2711bcm struct {
clkMem []uint32
}
func New(opts hal.ComputeBladeHalOpts) (*bcm2711bcm, error) {
func New(opts hal.ComputeBladeHalOpts) (*bcm2711, error) {
// /dev/gpiomem doesn't allow complex operations for PWM fan control or WS281x
devmem, err := os.OpenFile("/dev/mem", os.O_RDWR|os.O_SYNC, os.ModePerm)
if err != nil {
@@ -94,7 +82,7 @@ func New(opts hal.ComputeBladeHalOpts) (*bcm2711bcm, error) {
if err != nil {
return nil, err
}
pwmMem, pwmMem8, err := mmap(devmem, bcm2711PwmAddr, bcm2711PageSize)
pwmMem, pwmMem8, err := mmap(devmem, bcm2711RegPwmAddr, bcm2711PageSize)
if err != nil {
return nil, err
}
@@ -103,7 +91,7 @@ func New(opts hal.ComputeBladeHalOpts) (*bcm2711bcm, error) {
return nil, err
}
return &bcm2711bcm{
return &bcm2711{
devmem: devmem,
mbox: mbox,
gpioMem: gpioMem,
@@ -117,7 +105,7 @@ func New(opts hal.ComputeBladeHalOpts) (*bcm2711bcm, error) {
}
// Close cleans all memory mappings
func (bcm *bcm2711bcm) Close() error {
func (bcm *bcm2711) Close() error {
return errors.Join(
syscall.Munmap(bcm.gpioMem8),
syscall.Munmap(bcm.pwmMem8),
@@ -128,51 +116,53 @@ func (bcm *bcm2711bcm) Close() error {
}
// Init initialises GPIOs and sets sane defaults
func (bcm *bcm2711bcm) Init() {
func (bcm *bcm2711) Init() {
bcm.InitGPIO()
// bcm.SetFanSpeed(bcm.opts.DefaultFanSpeed)
bcm.SetStealthMode(bcm.opts.DefaultStealthModeEnabled)
bcm.SetFanSpeed(bcm.opts.Defaults.FanSpeed)
bcm.SetStealthMode(bcm.opts.Defaults.StealthModeEnabled)
bcm.SetLEDs(bcm.opts.Defaults.TopLedColor, bcm.opts.Defaults.EdgeLedColor)
}
// InitGPIO initalises GPIO configuration
func (bcm *bcm2711bcm) InitGPIO() {
func (bcm *bcm2711) InitGPIO() {
// based on https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf
bcm.wrMutex.Lock()
defer bcm.wrMutex.Unlock()
// Edge Button (GPIO 20)
// -> GPFSEL2 2:0, input
bcm.gpioMem[GPFSEL2] = (bcm.gpioMem[GPFSEL2] &^ (0b111 << 0)) | (0b000 << 0)
// -> bcm2711RegGpfsel2 2:0, input
bcm.gpioMem[bcm2711RegGpfsel2] = (bcm.gpioMem[bcm2711RegGpfsel2] &^ (0b111 << 0)) | (0b000 << 0)
// PoE at detection (GPIO 23)
// -> GPFSEL2 2:0, input
bcm.gpioMem[GPFSEL2] = (bcm.gpioMem[GPFSEL2] &^ (0b111 << 0)) | (0b000 << 0)
// -> bcm2711RegGpfsel2 2:0, input
bcm.gpioMem[bcm2711RegGpfsel2] = (bcm.gpioMem[bcm2711RegGpfsel2] &^ (0b111 << 9)) | (0b000 << 9)
// Stealth Mode Output (GPIO 21)
// -> GPFSEL2 5:3, output
bcm.gpioMem[GPFSEL2] = (bcm.gpioMem[GPFSEL2] &^ (0b111 << 3)) | (0b001 << 3)
// -> bcm2711RegGpfsel2 5:3, output
bcm.gpioMem[bcm2711RegGpfsel2] = (bcm.gpioMem[bcm2711RegGpfsel2] &^ (0b111 << 3)) | (0b001 << 3)
// FAN PWM output for standard fan unit (GPIO 12)
if bcm.opts.FanUnit == hal.FAN_UNIT_STANDARD {
// -> GPFSEL1 8:6, alt0
bcm.gpioMem[GPFSEL1] = (bcm.gpioMem[GPFSEL1] &^ (0b111 << 6)) | (0b100 << 6)
bcm.setFanSpeedPWM(bcm.opts.DefaultFanSpeed)
if bcm.opts.FanUnit == hal.FanUnitStandard {
// -> bcm2711RegGpfsel1 8:6, alt0
bcm.gpioMem[bcm2711RegGpfsel1] = (bcm.gpioMem[bcm2711RegGpfsel1] &^ (0b111 << 6)) | (0b100 << 6)
}
// FAN TACH input for standard fan unit (GPIO 13)
if bcm.opts.FanUnit == hal.FAN_UNIT_STANDARD {
// -> GPFSEL1 11:9, input
bcm.gpioMem[GPFSEL1] = (bcm.gpioMem[GPFSEL1] &^ (0b111 << 9)) | (0b000 << 9)
if bcm.opts.FanUnit == hal.FanUnitStandard {
// -> bcm2711RegGpfsel1 11:9, input
bcm.gpioMem[bcm2711RegGpfsel1] = (bcm.gpioMem[bcm2711RegGpfsel1] &^ (0b111 << 9)) | (0b000 << 9)
}
// Set WS2812 output (GPIO 18)
// -> GPFSEL1 24:26, set as regular output by default. On-demand, it's mapped to pwm0
bcm.gpioMem[GPFSEL1] = (bcm.gpioMem[GPFSEL1] &^ (0b111 << 24)) | (0b001 << 24)
// FIXME add edge button
// -> bcm2711RegGpfsel1 24:26, set as regular output by default. On-demand, it's mapped to pwm0
bcm.gpioMem[bcm2711RegGpfsel1] = (bcm.gpioMem[bcm2711RegGpfsel1] &^ (0b111 << 24)) | (0b001 << 24)
}
func (bcm *bcm2711bcm) setPwm0Freq(targetFrequency uint64) error {
func (bcm *bcm2711) GetPoeStatus() {
}
func (bcm *bcm2711) setPwm0Freq(targetFrequency uint64) error {
// Calculate PWM divisor based on target frequency
divisor := 54000000 / targetFrequency
realDivisor := divisor & 0xfff // 12 bits
@@ -181,42 +171,42 @@ func (bcm *bcm2711bcm) setPwm0Freq(targetFrequency uint64) error {
}
// Stop pwm for both channels; this is required to set the new configuration
bcm.pwmMem[PWM_CTL] &^= (1 << PWM_CTL_PWEN1) | (1 << PWM_CTL_PWEN2)
bcm.pwmMem[bcm2711RegPwmCtl] &^= (1 << bcm2711RegPwmCtlBitPwen1) | (1 << bcm2711RegPwmCtlBitPwen2)
time.Sleep(time.Microsecond * 10)
// Stop clock w/o any changes, they cannot be made in the same step
bcm.clkMem[PWMCLK_CNTL] = bcm2711ClkManagerPwd | (bcm.clkMem[PWMCLK_CNTL] &^ (1 << 4))
bcm.clkMem[bcm2711RegPwmclkCntrl] = bcm2711ClkManagerPwd | (bcm.clkMem[bcm2711RegPwmclkCntrl] &^ (1 << 4))
time.Sleep(time.Microsecond * 10)
// Wait for the clock to not be busy so we can perform the changes
for bcm.clkMem[PWMCLK_CNTL]&(1<<7) != 0 {
for bcm.clkMem[bcm2711RegPwmclkCntrl]&(1<<7) != 0 {
time.Sleep(time.Microsecond * 10)
}
// passwd, disabled, source (oscillator)
bcm.clkMem[PWMCLK_CNTL] = bcm2711ClkManagerPwd | (0 << PWMCLK_CNTL_ENABLE) | (1 << PWMCLK_CNTL_SRC_OSC)
bcm.clkMem[bcm2711RegPwmclkCntrl] = bcm2711ClkManagerPwd | (0 << bcm2711RegPwmclkCntrlBitEnable) | (1 << bcm2711RegPwmclkCntrlBitSrcOsc)
time.Sleep(time.Microsecond * 10)
bcm.clkMem[PWMCLK_DIV] = bcm2711ClkManagerPwd | (uint32(divisor) << 12)
bcm.clkMem[bcm2711RegPwmclkDiv] = bcm2711ClkManagerPwd | (uint32(divisor) << 12)
time.Sleep(time.Microsecond * 10)
// Start clock (passwd, enable, source)
bcm.clkMem[PWMCLK_CNTL] = bcm2711ClkManagerPwd | (1 << PWMCLK_CNTL_ENABLE) | (1 << PWMCLK_CNTL_SRC_OSC)
bcm.clkMem[bcm2711RegPwmclkCntrl] = bcm2711ClkManagerPwd | (1 << bcm2711RegPwmclkCntrlBitEnable) | (1 << bcm2711RegPwmclkCntrlBitSrcOsc)
time.Sleep(time.Microsecond * 10)
// Start pwm for both channels again
bcm.pwmMem[PWM_CTL] &= (1 << PWM_CTL_PWEN1)
bcm.pwmMem[bcm2711RegPwmCtl] &= (1 << bcm2711RegPwmCtlBitPwen1)
time.Sleep(time.Microsecond * 10)
return nil
}
// SetFanSpeed sets the fanspeed of a blade in percent (standard fan unit)
func (bcm *bcm2711bcm) SetFanSpeed(speed uint8) {
func (bcm *bcm2711) SetFanSpeed(speed uint8) {
bcm.setFanSpeedPWM(speed)
}
func (bcm *bcm2711bcm) setFanSpeedPWM(speed uint8) {
func (bcm *bcm2711) setFanSpeedPWM(speed uint8) {
// Noctua fans are expecting a 25khz signal, where duty cycle controls fan on/speed/off
// With the usage of the FIFO, we can alter the duty cycle by the number of bits set in the FIFO, maximum of 32.
// We therefore need a frequency of 32*25khz = 800khz, which is a divisor of 67.5 (thus we'll use 68).
@@ -240,23 +230,17 @@ func (bcm *bcm2711bcm) setFanSpeedPWM(speed uint8) {
}
// Use fifo, repeat, ...
bcm.pwmMem[PWM_CTL] = (1 << PWM_CTL_PWEN1) | (1 << PWM_CTL_MODE1) | (1 << PWM_CTL_RPTL1) | (1 << PWM_CTL_USEF1)
bcm.pwmMem[bcm2711RegPwmCtl] = (1 << bcm2711RegPwmCtlBitPwen1) | (1 << bcm2711RegPwmCtlBitMode1) | (1 << bcm2711RegPwmCtlBitRptl1) | (1 << bcm2711RegPwmCtlBitUsef1)
time.Sleep(10 * time.Microsecond)
bcm.pwmMem[PWM_RNG1] = 32
bcm.pwmMem[bcm2711RegPwmRng1] = 32
time.Sleep(10 * time.Microsecond)
bcm.pwmMem[PWM_FIF1] = targetvalue
bcm.pwmMem[bcm2711RegPwmFif1] = targetvalue
// Store fan speed for later use
bcm.currFanSpeed = speed
}
type LedColor struct {
Red uint8
Green uint8
Blue uint8
}
func (bcm *bcm2711bcm) SetStealthMode(enable bool) {
func (bcm *bcm2711) SetStealthMode(enable bool) {
bcm.wrMutex.Lock()
defer bcm.wrMutex.Unlock()
@@ -286,7 +270,7 @@ func serializePwmDataFrame(data uint8) uint32 {
}
// SetLEDs sets the color of the WS281x LEDs
func (bcm *bcm2711bcm) SetLEDs(top LedColor, edge LedColor) {
func (bcm *bcm2711) SetLEDs(top hal.LedColor, edge hal.LedColor) {
bcm.wrMutex.Lock()
defer bcm.wrMutex.Unlock()
@@ -296,41 +280,42 @@ func (bcm *bcm2711bcm) SetLEDs(top LedColor, edge LedColor) {
time.Sleep(10 * time.Microsecond)
// WS281x Output (GPIO 18)
// -> GPFSEL1 24:26, regular output; it's configured as alt5 whenever pixel data is sent.
// -> bcm2711RegGpfsel1 24:26, regular output; it's configured as alt5 whenever pixel data is sent.
// This is not optimal but required as the pwm0 peripheral is shared between fan and data line for the LEDs.
time.Sleep(10 * time.Microsecond)
bcm.gpioMem[GPFSEL1] = (bcm.gpioMem[GPFSEL1] &^ (0b111 << 24)) | (0b010 << 24)
bcm.gpioMem[bcm2711RegGpfsel1] = (bcm.gpioMem[bcm2711RegGpfsel1] &^ (0b111 << 24)) | (0b010 << 24)
time.Sleep(10 * time.Microsecond)
defer func() {
// Set to regular output again so the PWM signal doesn't confuse the WS2812
bcm.gpioMem[GPFSEL1] = (bcm.gpioMem[GPFSEL1] &^ (0b111 << 24)) | (0b001 << 24)
bcm.gpioMem[bcm2711RegGpfsel1] = (bcm.gpioMem[bcm2711RegGpfsel1] &^ (0b111 << 24)) | (0b001 << 24)
bcm.setFanSpeedPWM(bcm.currFanSpeed)
}()
bcm.pwmMem[PWM_CTL] = (1 << PWM_CTL_MODE1) | (1 << PWM_CTL_RPTL1) | (0 << PWM_CTL_SBIT1) | (1 << PWM_CTL_USEF1) | (1 << PWM_CTL_CLRF1)
bcm.pwmMem[bcm2711RegPwmCtl] = (1 << bcm2711RegPwmCtlBitMode1) | (1 << bcm2711RegPwmCtlBitRptl1) | (0 << bcm2711RegPwmCtlBitSbit1) | (1 << bcm2711RegPwmCtlBitUsef1) | (1 << bcm2711RegPwmCtlBitClrf1)
time.Sleep(10 * time.Microsecond)
// bcm.pwmMem[PWM_RNG1] = 32
bcm.pwmMem[PWM_RNG1] = 24 // we only need 24 bits per LED
// bcm.pwmMem[bcm2711RegPwmRng1] = 32
bcm.pwmMem[bcm2711RegPwmRng1] = 24 // we only need 24 bits per LED
time.Sleep(10 * time.Microsecond)
// Add sufficient padding to clear
bcm.pwmMem[PWM_FIF1] = 0
bcm.pwmMem[PWM_FIF1] = 0
bcm.pwmMem[PWM_FIF1] = 0
// Add sufficient padding to clear 50us of silence with ~412.5ns per bit -> at least 121 bits -> let's be safe and send 6*24=144 bits of silence
bcm.pwmMem[bcm2711RegPwmFif1] = 0
bcm.pwmMem[bcm2711RegPwmFif1] = 0
bcm.pwmMem[bcm2711RegPwmFif1] = 0
bcm.pwmMem[bcm2711RegPwmFif1] = 0
bcm.pwmMem[bcm2711RegPwmFif1] = 0
bcm.pwmMem[bcm2711RegPwmFif1] = 0
// Write top LED data
bcm.pwmMem[PWM_FIF1] = serializePwmDataFrame(top.Red) << 8
bcm.pwmMem[PWM_FIF1] = serializePwmDataFrame(top.Green) << 8
bcm.pwmMem[PWM_FIF1] = serializePwmDataFrame(top.Blue) << 8
bcm.pwmMem[bcm2711RegPwmFif1] = serializePwmDataFrame(top.Red) << 8
bcm.pwmMem[bcm2711RegPwmFif1] = serializePwmDataFrame(top.Green) << 8
bcm.pwmMem[bcm2711RegPwmFif1] = serializePwmDataFrame(top.Blue) << 8
// Write edge LED data
bcm.pwmMem[PWM_FIF1] = serializePwmDataFrame(edge.Red) << 8
bcm.pwmMem[PWM_FIF1] = serializePwmDataFrame(edge.Green) << 8
bcm.pwmMem[PWM_FIF1] = serializePwmDataFrame(edge.Blue) << 8
bcm.pwmMem[bcm2711RegPwmFif1] = serializePwmDataFrame(edge.Red) << 8
bcm.pwmMem[bcm2711RegPwmFif1] = serializePwmDataFrame(edge.Green) << 8
bcm.pwmMem[bcm2711RegPwmFif1] = serializePwmDataFrame(edge.Blue) << 8
// make sure there's >50us of silence
bcm.pwmMem[PWM_FIF1] = 0
bcm.pwmMem[PWM_FIF1] = 0
bcm.pwmMem[PWM_FIF1] = 0
bcm.pwmMem[bcm2711RegPwmFif1] = 0 // auto-repeated, so no need to feed the FIFO further.
bcm.pwmMem[PWM_CTL] = (1 << PWM_CTL_PWEN1) | (1 << PWM_CTL_MODE1) | (1 << PWM_CTL_RPTL1) | (0 << PWM_CTL_SBIT1) | (1 << PWM_CTL_USEF1)
// sleep for 4*50us to ensure the data is sent.
bcm.pwmMem[bcm2711RegPwmCtl] = (1 << bcm2711RegPwmCtlBitPwen1) | (1 << bcm2711RegPwmCtlBitMode1) | (1 << bcm2711RegPwmCtlBitRptl1) | (0 << bcm2711RegPwmCtlBitSbit1) | (1 << bcm2711RegPwmCtlBitUsef1)
// sleep for 4*50us to ensure the data is sent. This is probably a bit too gracious but does not have a significant impact, so let's be safe data gets out.
time.Sleep(200 * time.Microsecond)
}

View File

@@ -2,16 +2,34 @@ package hal
type FanUnit uint8
type ComputeModule uint8
type PowerStatus uint8
const (
FAN_UNIT_STANDARD = iota
FAN_UNIT_ADVANCED
FanUnitStandard = iota
FanUnitSmart
)
const (
PoeOrUsbC = iota
Poe802at
)
type LedColor struct {
Red uint8
Green uint8
Blue uint8
}
type ComputeBladeHalOptsDefault struct {
StealthModeEnabled bool
FanSpeed uint8
TopLedColor LedColor
EdgeLedColor LedColor
}
type ComputeBladeHalOpts struct {
FanUnit FanUnit
DefaultFanSpeed uint8
DefaultStealthModeEnabled bool
FanUnit FanUnit
Defaults ComputeBladeHalOptsDefault
}
// COmputeBladeHal abstracts hardware details of the Compute Blade and provides a simple interface
@@ -20,4 +38,6 @@ type ComputeBladeHal interface {
Close() error
SetFanSpeed(speed uint8)
SetStealthMode(enabled bool)
GetPowerStatus() PowerStatus
SetLEDs(top, edge LedColor)
}