adsp: Introduce ADSP SoC CDU clock driver - #3456
Conversation
|
Tested the driver on all SoCs, boots successully and clock trees seem valid. Clock tree dumps for all SoCs below: POSTreserved sel parents in original is wrong, mine fixes: |
|
@ukleinek just so you're aware of this since it is a big change and may impact your work |
|
@qasim-ijaz Check https://github.com/analogdevicesinc/linux/actions/runs/29926080863/job/88943461564?pr=3456#step:9:72 for checkpatch, cocci, etc |
|
Not sure if checkpatch can check for it, but it looks like the commit descriptions are wrapped at 50 characters. |
LLM reviewThis series adds a shared ADSP SoC CDU (Clock Distribution Unit) clock run: 29930235555
|
79662d5 to
55209e3
Compare
|
tested with RevE+RevD boots, and clock tree in clk_summary looks ok |
b546642 to
3080660
Compare
The SC594 clock ID namespace currently represents each CDU output as two separate clocks: a _SEL clock for the input mux and a second clock for the output gate. This reflects the implementation of the old combined CGU/CDU clock driver. A CDU output is controlled by a single CDU_CFG register, with the SEL field selecting its parent and the EN field controlling the output gate. The common CDU driver therefore models each output as one CCF clock instead of exposing separate mux and gate clocks. Remove the legacy SC594 CDU mux and gate IDs and reduce ADSP_SC594_CLK_END accordingly. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC598 clock ID namespace currently represents each CDU output as two separate clocks: a _SEL clock for the input mux and a second clock for the output gate. Each CDU output is controlled through a single CDU_CFG register, where the SEL field selects the parent clock and the EN field controls the output gate. The common CDU driver therefore models both functions as a single CCF clock. Remove the legacy SC598 CDU mux and gate IDs. These clocks will instead be exported by the dedicated CDU clock provider using the common ADSP_CLK_CDU_* IDs and the SC598-specific ADSP_SC598_CLK_CDU_* IDs. Renumber the remaining SC598 PLL3 clocks and update ADSP_SC598_CLK_END accordingly. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC58X clock provider namespace currently exposes each CDU output as two clocks: a _SEL clock for the input mux and a second clock for the output gate. Each CDU output is controlled by one CDU_CFG register, where the SEL field selects the parent clock and the EN field controls the output gate. The common CDU driver models these functions as a single CCF clock, so separate mux and gate IDs are no longer required. Remove the legacy CDU mux and gate clock IDs from the SC58X clock provider namespace and reduce ADSP_SC58X_CLK_END accordingly. The CDU outputs will instead be exported by the dedicated CDU provider. Outputs common across the supported SoCs use ADSP_CLK_CDU_* IDs, while SC58X specific outputs use ADSP_SC58X_CLK_CDU_* IDs. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC57X clock provider namespace currently exposes each CDU output as two clocks: a _SEL clock for the input mux and a second clock for the output gate. Each CDU output is controlled by one CDU_CFG register, where the SEL field selects the parent clock and the EN field controls the output gate. The common CDU driver models these functions as a single CCF clock, so separate mux and gate IDs are no longer required. Remove the legacy CDU mux and gate clock IDs from the SC57X clock provider namespace and reduce ADSP_SC57X_CLK_END accordingly. The CDU outputs will instead be exported by the dedicated CDU provider. Outputs common across the supported SoCs use ADSP_CLK_CDU_* IDs, while SC57X-specific outputs use ADSP_SC57X_CLK_CDU_* IDs. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Add dedicated clock IDs for the common ADSP CDU clock provider. Instead of duplicating IDs multiple times for every single device family, use "ADSP_CLK_CDU_*" IDs for CDU clocks that are present across all supported SoCs, and use SoC specific "ADSP_SC*_CLK_CDU_*" IDs for outputs that are only present on a particular device family (We could reduce duplication even more but it might not be worth it since its only a few IDs). The same numeric IDs are intentionally reused between SoCs because each CDU node is an independent clock provider and interprets its own clock specifiers. Each ID represents one CDU output clock, combining the input clock selection and output gate controlled by the corresponding CDU_CFG register. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The CDU_CFG registers are laid out as a contiguous array of 32 bit registers. The new CDU driver calculates each register address from the CDU output index (CLKOn), so the individual CDU_CFG0 through CDU_CFG14 offset definitions are no longer needed. Remove these obsolete definitions from the common ADI clock header. Also declare adsp_lock in the common header so the ADI clock drivers can share the same lock. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC598 clock controller node currently describes both the Clock Generation Units and the Clock Distribution Unit as a single controller. This does not reflect the hardware layout because the CGUs and CDU are distinct hardware blocks with separate register regions and different functions. Describe the CDU as a separate clock controller so that it can be managed by the common ADSP CDU driver shared across the ADSP SoC family. Remove the CDU register range from the existing CGU clock node, add a standalone CDU node with its required input clocks, and update the CPU ARM clock and the SPI, OSPI, Ethernet, and eMMC consumers to use the new CDU provider. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Add a Makefile entry for clk-adi-cdu.o so the common ADI Clock Distribution Unit driver is compiled when CONFIG_COMMON_CLK_ADI_CDU is enabled. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Add COMMON_CLK_ADI_CDU to provide configuration support for the common Analog Devices Clock Distribution Unit driver. The CDU selects and routes core system clocks to SoC specific peripherals. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Select COMMON_CLK_ADI_CDU from COMMON_CLK_ADI_SC598 so the common Clock Distribution Unit driver is built with SC598 clock support. Also correct the SC598 help text, which incorrectly referred to the SC594 clock driver. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC598 clock driver currently maps the CDU register block alongside CGU0, CGU1, and the third PLL. It also registers the CDU CLKINSEL mux and the mux and gate clocks for the CDU outputs. These clocks are now registered by the common ADSP CDU driver. Update the SC598 clock driver to: - remove the third MMIO resource mapping for the CDU, since the common CDU driver now owns that register block - update the third PLL resource index after removing the CDU resource - remove the local cdu_lock and use the shared adsp_lock across the driver - change the parents of the CGU1 and third PLL input dividers from the locally registered "cgu1_in_sel" clock to the "cdu_clkinsel" clock registered by the common CDU driver - remove the CDU CLKINSEL registration since this is registered by the CDU driver - remove the SC598 CDU output mux and gate clock registrations since these are now registered by the CDU driver - remove the parent arrays used by the legacy CDU mux registrations After this change, clk-adi-sc598 registers the SC598 CGU0, CGU1 and third PLL clocks, while ADSP CDU driver owns the CDU register block, CLKINSEL mux, and CDU output clocks. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Fixed most of the checkpatch issues:
As for the rest they seem to be about 1) line lengths of 101/102/103 exceeding the 100 line max, i think this should be fine since its only 1-2 chars extra (if i was to change this i'd probably have to make the names shorter or something so I think readability > worrying about 1-2 extra chars, also it seems other clock drivers also exceed this limit upstream) 2) parenthesis alignment, once again i think this is fine since this is a style employed by other upstream clock drivers (https://github.com/torvalds/linux/blob/master/drivers/clk/rockchip/clk-rk3588.c for example) and i think the current styling looks quite clean. |
|
The wrapping of the commit descriptions should be made consistent. The description of |
Introduce the ADSP CDU (Clock Distribution Unit) clock
driver. The current clock drivers model the core hardware
blocks (CGUs/CDU/PLLs) as a single clock controller even
though each block has separate register blocks, separate
functionality and uses.
This driver improves on and introduces various changes:
- The current ADSP clock drivers incorrectly model each CDU output by
using the generic clk_register_mux() implementation. However, this is
not suitable for the ADSP CDU because the generic kernel mux
implementation does not account for hardware specific requirements
such as polling and waiting for the corresponding CLKOn bit or
checking whether the LOCK bit is set. Furthermore, the generic mux
set_parent operation performs the register update and returns
success without waiting for CDU configuration completion,
checking the LOCK bit, or verifying the selector readback.
As a result, hardware timeouts, locked registers, and failed
selector updates cannot be detected or reported to CCF.
- The current driver registers every CDU mux and gate clock as
an early clock, this is not needed because there are no early mux clock
consumers. Generally we should limit the number of early clocks we register
since the core driver model (and all the benefits which come with it) is not
available at early clock registration time, the idiomatic thing to do is
convert this to a platform driver, taking advantage of modern
kernel APIs and limiting which clocks are registered early.
- The current clock driver marks almost all clocks with CLK_SET_RATE_PARENT,
this causes major issues because if a rate change request is made to a mux
clock that request is essentially propagated upwards to the upstream PLL
and divider clocks meaning other system clocks may inadvertently also change.
This is something I tested myself on the ADSP SC598 where I requested a rate
change on the TRACE CDU mux, TRACE shares parents clocks with GIGE, LP and other
core peripherals and this rate request affected those as a side effect, crashing
my system and making it unusable.
- Another useful addition is adding a debugfs interface to dump
CDU related registers, such as EN, SEL, LOCK, LWERR, etc. This can
be useful for general clock related debugging. Furthermore the
CDU revision IDs are printed during probe, before these were
simply ignored.
- The current clock driver models the grounded input clocks ("N/A") as
dummy clocks however this is not needed because the SoC docs state
"Unused input clocks are grounded internally and never selected".
Adding them is not needed because they are not used or selected,
a cleaner design is to simply expose the input clocks which can
be selected. Furthermore introduce MUX_TABLES which map parent
clocks to CLKOn input SELs, this nicely fits into what the CCF
mux APIs already expose and expect.
- Another small but important improvement is the addition of kernel doc
throughout the driver, this aims to explain how the CDU operates at a high
level and just makes for a better driver overall.
- The old driver utilises string based parents which is the "legacy" way
to define and let CCF know about clock parents, it has various issues and
can be brittle. The modern and more preferred way (especially when the
parent clock is owned by an external clock controller as in our case) is
to use struct clk_parent_data.fw_name which introduces a closer coupling
with the device tree where clocks are resolved directly through DT phandles
to clock controllers instead of relying on globally unique internal clock names.
- The old driver's provider clock IDs were heavily duplicated which was
quite messy, to clean this up I have split the CDU clock IDs into two groups:
ADSP_CLK_CDU_* and ADSP_*_CLK_CDU_*, aka group the common IDs which are
present across all SoCs and then add per SoC specific IDs. Also since
the CDU is now modelled as a single HW block (and not split by SEL and gate)
this greatly reduces the number of provider IDs required.
Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC594 clock controller node currently describes both the Clock Generation Units and the Clock Distribution Unit as a single controller. This does not reflect the hardware layout because the CGUs and CDU are distinct hardware blocks with separate register blocks and different functions. Describe the CDU as a separate clock controller so that it can be managed by the common ADSP CDU driver shared across the ADSP SoC family. Remove the CDU register range from the existing clock node, add a standalone CDU node with its required CGU input clocks, and update the CPU, SPI, OSPI, and Ethernet nodes to consume clocks from the new CDU provider. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC594 clock driver currently maps the CDU register block alongside CGU0 and CGU1. It also registers the CDU CLKINSEL mux and the mux and gate clocks for the CDU outputs. These clocks are now registered by the common ADSP CDU driver. Update the SC594 clock driver to: - remove the third MMIO resource mapping for the CDU, since the common CDU driver now owns that register block - remove the local cdu_lock and use the shared adsp_lock for the remaining CGU clock register accesses (the lock has been renamed because it is used across multiple HW blocks, not just the CDU as the name implies) - change the parent of the CGU1 DF divider from the locally registered "cgu1_in_sel" clock to the "cdu_clkinsel" clock registered by the common CDU driver - remove the SC594 CDU output mux and gate clock registrations - remove the parent arrays used by the old CDU output mux registrations After this change, clk-adi-sc594 registers the SC594 CGU clocks, while clk-adi-cdu owns the CDU register block, CLKINSEL mux, and CDU output clocks. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Select COMMON_CLK_ADI_CDU from COMMON_CLK_ADI_SC594 so the common Clock Distribution Unit driver is built with SC594 clock support. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Select COMMON_CLK_ADI_CDU from COMMON_CLK_ADI_SC58X so the common Clock Distribution Unit driver is built with SC589 clock support. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC589 clock driver currently maps the CDU register block alongside CGU0 and CGU1. It also registers the CDU CLKINSEL mux and the mux and gate clocks for the CDU outputs. These clocks are now registered by the common ADSP CDU driver. Update the SC589 clock driver to: - remove the third MMIO resource mapping for the CDU, since the common CDU driver now owns that register block - remove the local "cdu_lock" and use the shared "adsp_lock" for the remaining CGU clock registrations, this lock is defined in the common CDU driver - change the parent of the CGU1 DF divider from the locally registered "cgu1_in_sel" clock to the "cdu_clkinsel" clock registered by the common CDU driver - remove the local CDU CLKINSEL mux registration - remove the SC589 CDU output mux and gate clock registrations since these are now registered by the common CDU driver - remove the parent arrays used by the old CDU output mux registrations, since these are no longer needed and are handled by the common CDU driver After this change, clk-adi-sc58x registers the SC589 CGU clocks, while clk-adi-cdu owns the CDU register block, CLKINSEL mux, and CDU output clocks. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC589 clock controller node currently describes both the Clock Generation Units and the Clock Distribution Unit as a single controller. This does not reflect the hardware layout because the CGUs and CDU are distinct hardware blocks with separate register blocks and functions. Describe the CDU as a separate clock controller so that it can be managed by the common ADSP CDU driver shared across the ADSP SoC family. Remove the CDU register range from the existing clock node and add a standalone CDU node with the required SYS_CLKIN and CGU input clocks. Update the CPU, Ethernet, and MMC nodes to consume their CDU output clocks from the new provider. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC57X clock driver currently maps the CDU register block alongside CGU0 and CGU1. It also registers the CDU CLKINSEL mux and the mux and gate clocks for the CDU outputs. These clocks are now registered by the common ADSP CDU driver. Update the SC57X clock driver to: - remove the third MMIO resource mapping for the CDU, since the common CDU driver now owns that register block - remove the local "cdu_lock" and use the shared "adsp_lock" for the remaining CGU clock registrations - change the parent of the CGU1 DF divider from the locally registered "cgu1_in_sel" clock to the "cdu_clkinsel" clock registered by the common CDU driver - remove the local CDU CLKINSEL mux registration - remove the SC57X CDU output mux and gate clock registrations since these are now handled by the common CDU driver - remove the parent arrays used by the old CDU output mux registrations After this change, clk-adi-sc57x registers the SC57X CGU clocks, while clk-adi-cdu owns the CDU register block, CLKINSEL mux, and CDU output clocks. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Select COMMON_CLK_ADI_CDU from COMMON_CLK_ADI_SC57X so the common Clock Distribution Unit driver is built with SC573 clock support. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC573 clock controller node currently describes both the Clock Generation Units and the Clock Distribution Unit as a single controller. This does not reflect the hardware layout because the CGUs and CDU are distinct hardware blocks with separate register blocks and functions. Describe the CDU as a separate clock controller so that it can be managed by the common ADSP CDU driver. Remove the CDU register range from the existing clock node and add a standalone CDU node with the required SYS_CLKIN and CGU input clocks. Update the CPU, Ethernet, and MMC nodes to consume their CDU output clocks from the new provider. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The legacy CDU mux clock registration used a zero
rate dummy clock for grounded ("N/A") mux input clocks.
The common ADSP CDU driver represents only valid
parent clocks and no longer requires the dummy clock.
Remove the unused dummy fixed rate clock registrations
from the SC573, SC589, SC594, and SC598 clock drivers.
Keep the existing clock binding IDs unchanged for now.
Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
The SC5xx clock controller binding currently describes the Clock Generation Units and Clock Distribution Unit as a single provider. The CDU is now described as a separate clock controller with its own register region and binding. Update the existing binding to describe only the CGU and PLL register blocks. Remove the CDU register region from the examples and adjust the allowed register count for the SC57x, SC58x, SC594, and SC598 clock controllers. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
Add a binding for the CDU on the ADSP-SC573, ADSP-SC589, ADSP-SC594, and ADSP-SC598 SoCs. Describe the register region, input clocks, and clock outputs provided by the CDU. Add the new binding file to the MAINTAINERS entry for the ADI SC5xx platform. Signed-off-by: Qasim Ijaz <Qasim.Ijaz@analog.com>
PR Description
This PR introduces a common Clock Distribution Unit (CDU) driver for the Analog Devices ADSP-SC573, ADSP-SC589, ADSP-SC594, and ADSP-SC598 SoCs. The CDU is separated into its own platform driver, with each configurable output modelled as a single CCF clock combining the input selector mux and output gate. New Device Tree nodes describe the CDU controller, its input clocks, and how those clocks are routed to peripherals across the SoC.
These changes also modernise the ADI clock infrastructure and align it with current upstream APIs and practices, making future Linux kernel upstream submission easier (which will come soon hopefully).
The driver was boot tested on ADSP-SC573, ADSP-SC589, ADSP-SC594, and ADSP-SC598 hardware. Before and after clk_summary dumps were compared on each platform. The new CDU clocks seem to preserve the existing clock rates, selected parents, enable states, and peripheral consumers, the clk_summary pre and post changes can be found below
PR Type
PR Checklist