Skip to content

Clocks and resets

Jonathan Neuschäfer edited this page Apr 8, 2022 · 13 revisions
MMIO description
0xb0000200 clock and reset controller

Registers

offset type name description
0x00 u32 CLKEN clock enable
0x04 u32 CLKSEL clock select
0x08 u32 CLKDIV clock divide
0x0c u32 PLLCON0 PLL0 configuration
0x10 u32 PLLCON1 PLL1 configuration
0x14 u32 PMCON power management control
0x18 u32 IRQWAKECON IRQ wake-up control
0x1c u32 IRQWAKEFLAG IRQ wake-up flags
0x20 u32 IPSRST reset lines
0x24 u32 ??? undocumented PLL

Clocks

The clock tree of the WPCM450 consists of:

PLLs (PLLCONx)

 reference  +---------+             +---------------+       +---------+  output
 ---------->| input   |------------>|               |---.-->| output  |------->
 (48 MHz)   | divider |             |  comparator   |   |   | divider |
            +---------+             |    and        |   |   +---------+
                        feedback    |  oscillator   |   |
                       .----------->|               |   |
                       |            +---------------+   |
                       |                                |
                       |              +----------+      |
                       '--------------| feedback |<-----'
                                      | divider  |
                                      +----------+

The two PLLs are each controlled by a 32-bit register containing multiple fields:

bits name description
0:5 INDV input divider
8:10 OTDV output divider
12 PWDEN powerdown enable
13 PRST PLL reset mode
16:24 FBDV feedback divider

The output frequency is calculated as:

 Fout  =  Fref  / (INDV+1)  * (FBDV+1)  / (OTDV+1)

Intermediate clocks (CLKSEL and CLKDIV)

Between the 48 MHz reference oscillator and the PLLs on one side, and peripherals on the other side, there are intermediate clocks, that allow selecting their parent clock (CLKSEL) or setting a divider (CLKDIV).

Most of these clocks correspond to memory buses in the SoC.

clock parent(s) CLKSEL divider CLKDIV description
CPU PLL0, PLL1, REF 0:1 2 -- CPU clock
CLKOUT PLL0, PLL1, REF 2:3 1 -- clock output
USBPHY PLL0, PLL1, REF 6:7 1 -- USB 1.1 PHY clock, should be 60 MHz
UART PLL0, PLL1, REF 8:9 DIV+1 16:19 UART reference clock
HUART REF, REF/2 10 1 -- Host UART reference clock
AHB CPU -- 1,2 24:25
AHB3 AHB -- 1,2,4,8 8:9
AHB1,2 AHB -- 1 --
APB AHB -- 1,2,4,8 26:27
ADC REF -- 1,2,4,8 28:29

Unless otherwise noted, two-bit fields can take the following values:

value CLKDIV CLKSEL
0 divide by 1 PLL0
1 divide by 2 PLL1
2 divide by 4 REF (48 MHz)
3 divide by 8 REF or reserved

Caveats

Clock domain crossing

When reconfiguring the CPU clock, you must ensure that the bus clocks don't run slower then the connected peripherals. For example, in a fairly standard configuration, we have these values:

  • PLL0 = 400 MHz
  • CPU = 200 MHz (PLL0/2)
  • AHB = 100 MHz (CPU/2)
  • APB = 50 MHz (AHB/2)
  • UART = 24 MHz (REF/2)

Switching the CPU clock to 100 MHz works, because the APB clock (25 MHz) runs slightly faster than the UART clock (24 MHz). Switching the CPU clock to 66.6 MHz induces malfunction in the UART peripheral, probably at the interface between the APB bus and the UART peripheral.

Unknnoowwn coommmmand  wwbb0000000
>

Thus, when switching the CPU to a clock slower than 96 MHz, the AHB and APB clock dividers should be adjusted before using the UART.

Memory controller

When you set the CPU clock rate to 24 MHz (REF/2), a few different malfunctions can happen:

Zeroes

The external DRAM is no longer able to hold data properly: Every byte reads back as 0x00.

Weird reordering
> ww 3000 1 2 3 4
> rw 3000 4
00003000: 00000002 00000001 00000004 00000003

There are additional random errors, though:

>>> l.write32(0x2000, [x for x in range(0x100)])
>>> l.read32(0x2000, 0x100) == [x^1 for x in range(0x100)]
False
>>> l.read32(0x2000, 0x100) == [x^1 for x in range(0x100)]
True
>>> l.read32(0x2000, 0x100) == [x^1 for x in range(0x100)]
True
>>> l.read32(0x2000, 0x100) == [x^1 for x in range(0x100)]
False
>>> a = l.read32(0x2000, 0x100); b = [x^1 for x in range(0x100)]; print(a==b); [(i, a[i] ^ b[i]) for i in range(0x100) if a[i]!=b[i]]
False
[(124, 21), (204, 4)]
>>> a = l.read32(0x2000, 0x100); b = [x^1 for x in range(0x100)]; print(a==b); [(i, a[i] ^ b[i]) for i in range(0x100) if a[i]!=b[i]]
False
[(7, 4)]

Clock gates (CLKEN)

bit name parent clk description
0 FIU AHB3 SPI flash controller
1 XBUS AHB3 XBUS
2 KCS APB?
3 GDMA DMA engine (?) (reserved)
4 SHM AHB3?
5 USB1 AHB1? USB 1.1 controller
6 EMC0 AHB1 Ethernet MAC 0
7 EMC1 AHB1 Ethernet MAC 1
8 USB0 AHB1 USB 2.0 controller
9 PECI APB?
10 AES APB?
11 UART0 UART? UART 0
12 UART1 UART? UART 1
13 SMB2 APB? I2C/SMBus 2
14 SMB3 APB? I2C/SMBus 3
15 SMB4 APB? I2C/SMBus 4
16 SMB5 APB? I2C/SMBus 5
17 HUART HUART?
18 PWM APB? PWM
19 TIMER0 REF/2
20 TIMER1 REF/2
21 TIMER2 REF/2
22 TIMER3 REF/2
23 TIMER4 REF/2
24 MFT0 APB? Multi-function timer 0
25 MFT1 APB? Multi-function timer 1
26 WDT REF/2
27 ADC ADC?
28 SDIO AHB1? SD card interface — note that the SDIO clock speed is based on 48 MHz
29 SSPI APB?
30 SMB0 APB? I2C/SMBus 0
31 SMB1 APB? I2C/SMBus 1

Resets (IPSRST)

In addition, the clock controller controls the reset lines of different parts of the chip.

bit name description
0 FIU SPI flash controller
1 --
2 --
3 GDMA DMA engine (?) (reserved)
4 --
5 RNG Random number generator (reserved)
6 EMC0 Ethernet MAC 0
7 EMC1 Ethernet MAC 1
8 USB0 USB 2.0 controller
9 USB1 USB 1.1 controller
10 AES/PECI AES engine and PECI controller
11 UART both UARTs
12 MC Memory controller
13 SMB2 ? I2C/SMBus 2
14 SMB3 ? I2C/SMBus 3
15 SMB4 ? I2C/SMBus 4
16 SMB5 ? I2C/SMBus 5
17 --
18 PWM PWM
19 TIMER ? Timers
20 --
21 --
22 --
23 --
24 --
25 --
26 --
27 ADC ? ADC
28 SDIO ? SDIO controller
29 SSPI ? Secondary SPI controller
30 SMB0 ? I2C/SMBus 0
31 SMB1 ? I2C/SMBus 1

Observations

  • When FIU is clock-gated, its register and flash windows read 0. After ungating, the old state is restored.
  • When FIU is reset, its register and flash windows read ff. When it is released from reset, the registers have their initial values.
  • Ethernet
    • reset: read 0, release: read 0 (initial values)
    • gate: read 0, ungate: read values
  • Some register spaces, such as the one of the AES engine, do not read all-0 when held in reset

References