User:Slersgoevy/Clocks

= Clocks =

This page is an attempt to somewhat systematize what I've learned about so-called "clocks". This is not real documentation, this may be blatantly wrong, take anything written here with a grain of salt.

I'm playing with Samsung Exynos7870, so that's what I'm going to write about. Other platforms may be different, I don't know.

What is this clock stuff about, and why do I care?
These "clocks" are hardware that emits a pulse signal with some frequency. Many buses, such as I2C or UART, have the concept of a baud rate, and it is very likely (read: always) that they'll use these "clocks" to configure a specific baud rate. When mainlining a device, even if you already have drivers for all those bus controllers, stuff won't work unless you have a driver for your clock controller, and configure the right clocks in your DTB.

Types of clocks (on Exynos)
Generally speaking, a "clock" in the Linux kernel may refer to one of the following hardware:

1. A pulse generator that pulls the pulse out of thin air. These clocks do not have parent clocks.

2. A circuit that somehow alters a signal of another "clock". These clocks may have one or more parent clocks, and do not oscillate themselves.

The following types are what can be found inside of the vendor driver for Exynos7870:

Fixed rate clock
This type of clock only outputs one hardcoded frequency. It may have a gate attached, in which case the gate affects whether the clock is emitting signal.

Does not have parents.

Fixed factor clock
This type of clock emits the frequency of its parent clock, divided by a hardcoded constant. Also can have a gate attached.

PLL
This type of clock is a configurable oscillator that can be configured for a few hardcoded frequencies. Cannot have a gate attached.

Does not have parents. This type of clocks comes in multiple models with slightly different driver code.

Multiplexer (MUX)
This type of clock acts like a switch, that chooses the signal of one of its parents (which one is configurable from software). Can have a gate attached.

Has multiple parents, the driver choses which one gets output.

Divisor (DIV)
This type of clock is the same as "fixed factor", except that the division coefficient is configurable.

Gate
This type of clock copies the signal of its parent, but can be disabled separately if necessary. Basically an AND gate between the incoming signal and the configurable enable bit.

How the vendor driver handles clocks (Exynos)
Clocks exported by the driver do not correspond 1:1 to the hardware registers. Instead Samsung has put a "virtual clock" layer, where each virtual clock may be toggling multiple physical clocks (ones that map 1:1 to hardware).

Each physical clock is described in struct pwrcal_clk in its own static variable. Links between clocks (parent-child relationship) are written as pointers. Each clock may have up to 3 registers configured (main, "status", and "enable"), each is specified as a bitfield (register address + bit offset + bit width). Most clocks only use main, some use main and enable.

The actual structures are in drivers/soc/samsung/pwrcal/S5E7870/S5E7870-cmu.c (will probably be the same or similar path for other Exynos SoCs). The addresses written there are 32-bit, and have the "plane index" in the top 16 bits and offset in the bottom 16 bits. Mapping between "plane indices" and hardware addresses is stored in the v2psfrmap array in drivers/soc/samsung/pwrcal/S5E7870/S5E7870-rae.c.

How the mainline driver handles clocks (Exynos)
The mainline driver seems to have no concept of the "enable" bit, all clocks are considered enabled by default. Clocks that require this feature are represented as the "main" clock (which is considered always enabled), and the "gate" clock having the main clock as parent.

Clock data is stored in drivers/clk/samsung/clk-exynosXXXX.c as a bunch of arrays, 1 for 1 clock type. Additionally clocks are divided by "domains", which probably correspond to the different banks of MMIO registers used to access them. Parent-child relationship between clocks is specified by giving each clock a name, and referencing these names whenever appropriate.

Note: vendor kernels also have driver files at the same path, but these are just front-ends to the virtual clock subsystem. Do not blow up your mind trying to directly compare these.

Next are some notes on how vendor clock configuration corresponds to mainline.

PLL
"main" is the con0 offset, "status" is the locktime offset. "enable" is not used by vendor driver.

MUX
"main" is the mux's offset, "enable" is the gate's offset. "status" seems to be unsupported in mainline.

DIV
"main" is the con0 offset, "enable" is not used by vendor driver. "status" seems to be unsupported in mainline.