Skip to contentSkip to conversation

add COMMON_CLK support for PowerPC MPC512x

PATCH Superseded Gerhard Sittig 12 participants 190 messages Jul 15, 2013 – Aug 28, 2013 Page 1 of 2

Subsystems (15)

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

cover add COMMON_CLK support for PowerPC MPC512x

this series introduces support for the common clock framework (CCF, COMMON_CLK Kconfig option) in the PowerPC based MPC512x platform, a resulting debugfs clk_summary is at the end of the message after the stats

although the series does touch several subsystems -- serial, spi, net (can, fs_enet), mtd (nfc), usb, i2c, media (viu), and dts -- all of the patches are strictly clock related, changes outside of the clock driver in the mpc512x platform are rather small and local to probe and setup

the distribution was chosen such to not spam too many lists, yet reach all the relevant maintainers (there appears to be no clk related list, it's assumed that the clk API is ARM centric, which is why I send the PowerPC related changes to the ARM list as well), but I'd be happy to add more participants if necessary

it appears most appropriate to take this series through either the clk or the powerpc trees after it has passed review and other subsystem maintainers ACKed the clock setup related driver modifications -- splitting the series and taking the parts through several trees might reorder the set (make drivers fail to see the device tree specs) or would create unnecessary dependencies which need to get tracked upon merges and might defer propagation (unless I missed something)

the series passes 'checkpatch.pl --strict' except for one warning which cannot get resolved, since that either breaks compilation (the data type is preset by the clk-provider.h API) or requires a cast which shadows real mismatches:

WARNING: static const char * array should probably be static const char * const #413: FILE: arch/powerpc/platforms/512x/clock-commonclk.c:335:
+static const char *parent_names_mux0[] = {

total: 0 errors, 1 warnings, 0 checks, 836 lines checked

Gerhard Sittig (24):
spi: mpc512x: prepare clocks before enabling them
serial: mpc512x: prepare clocks before enabling them
mtd: mpc5121_nfc: prepare clocks before enabling them
powerpc: mpc512x: array decl for MCLK registers in CCM
clk: wrap I/O access for improved portability
dts: mpc512x: prepare for preprocessor support
dts: mpc512x: introduce dt-bindings/clock/ header
dts: mpc512x: add clock related device tree specs
clk: mpc512x: introduce COMMON_CLK for MPC512x
dts: mpc512x: add clock specs for client lookups
net: can: mscan: add a comment on reg to idx mapping
net: can: mscan: make mpc512x code use common clock
spi: mpc512x: OF clock lookup, use the 'mclk' name powerpc/mpc512x: improve DIU related clock setup
serial: mpc512x: OF clock lookup, use the 'mclk' name
clk: mpc512x: remove now obsolete clkdev registration
serial: mpc512x: setup the PSC FIFO clock as well
i2c: mpc: OF clock lookup for MPC512x
USB: fsl-mph-dr-of: OF clock lookup, prepare and enable
fs_enet: OF clock lookup (non-fatal), prepare and enable [media] fsl-viu: OF clock lookup, prepare before enable powerpc/fsl-pci: OF clock lookup, prepare before enable
clk: mpc512x: switch to COMMON_CLK, remove PPC_CLOCK
net: can: mscan: remove MPC512x non-COMMON_CLK code path

 arch/powerpc/boot/dts/ac14xx.dts                   |    9 +-
 arch/powerpc/boot/dts/include/dt-bindings          |    1 +
 arch/powerpc/boot/dts/mpc5121.dtsi                 |   94 ++-
 arch/powerpc/boot/dts/mpc5121ads.dts               |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts                 |    2 +-
 arch/powerpc/include/asm/mpc5121.h                 |   18 +-
 arch/powerpc/platforms/512x/Kconfig                |    2 +-
 arch/powerpc/platforms/512x/Makefile               |    3 +-
 arch/powerpc/platforms/512x/clock-commonclk.c      |  762 ++++++++++++++++++++
 arch/powerpc/platforms/512x/clock.c                |  753 -------------------
 arch/powerpc/platforms/512x/mpc512x_shared.c       |  165 +++--
 arch/powerpc/sysdev/fsl_pci.c                      |   15 +
 drivers/clk/clk-divider.c                          |    6 +-
 drivers/clk/clk-gate.c                             |    6 +-
 drivers/clk/clk-mux.c                              |    6 +-
 drivers/i2c/busses/i2c-mpc.c                       |    9 +
 drivers/media/platform/fsl-viu.c                   |   12 +-
 drivers/mtd/nand/mpc5121_nfc.c                     |    4 +-
 drivers/net/can/mscan/mpc5xxx_can.c                |  234 +++---
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   27 +-
 drivers/spi/spi-mpc512x-psc.c                      |    6 +-
 drivers/tty/serial/mpc52xx_uart.c                  |   59 +-
 drivers/usb/host/fsl-mph-dr-of.c                   |   24 +-
 include/dt-bindings/clock/mpc512x-clock.h          |   59 ++
 include/linux/clk-provider.h                       |   33 +
 include/linux/fs_enet_pd.h                         |    3 +
 26 files changed, 1299 insertions(+), 1015 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
 delete mode 100644 arch/powerpc/platforms/512x/clock.c
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
$ uname -srm
Linux 3.11.0-rc1-00024-g25dc674 ppc
$ cat /sys/kernel/debug/clk/clk_summary
   clock                        enable_cnt  prepare_cnt  rate
---------------------------------------------------------------------
 ac97                           0           0            24567000
 spdif_rx_in                    0           0            0
 spdif_tx_in                    0           0            0
 psc_mclk_in                    0           0            25000000
 dummy                          1           1            0
 osc                            1           1            25000000
    ref                         1           1            25000000
       sys                      9           9            320000000
          spdif-mux0            0           0            320000000
             spdif-en0          0           0            320000000
                spdif_mclk_div  0           0            80000000
                   spdif_mclk_out 0           0            80000000
                      spdif_mclk 0           0            80000000
          mscan3-mux0           1           1            320000000
             mscan3-en0         1           1            320000000
                mscan3_mclk_div 1           1            80000000
                   mscan3_mclk_out 1           1            80000000
                      mscan3_mclk 1           1            80000000
          mscan2-mux0           1           1            320000000
             mscan2-en0         1           1            320000000
                mscan2_mclk_div 1           1            80000000
                   mscan2_mclk_out 1           1            80000000
                      mscan2_mclk 1           1            80000000
          mscan1-mux0           1           1            320000000
             mscan1-en0         1           1            320000000
                mscan1_mclk_div 1           1            16000000
                   mscan1_mclk_out 1           1            16000000
                      mscan1_mclk 2           2            16000000
          mscan0-mux0           1           1            320000000
             mscan0-en0         1           1            320000000
                mscan0_mclk_div 1           1            16000000
                   mscan0_mclk_out 1           1            16000000
                      mscan0_mclk 2           2            16000000
          psc11-mux0            0           0            320000000
             psc11-en0          0           0            320000000
                psc11_mclk_div  0           0            80000000
                   psc11_mclk_out 0           0            80000000
                      psc11_mclk 0           0            80000000
          psc10-mux0            0           0            320000000
             psc10-en0          0           0            320000000
                psc10_mclk_div  0           0            80000000
                   psc10_mclk_out 0           0            80000000
                      psc10_mclk 0           0            80000000
          psc9-mux0             0           0            320000000
             psc9-en0           0           0            320000000
                psc9_mclk_div   0           0            80000000
                   psc9_mclk_out 0           0            80000000
                      psc9_mclk 0           0            80000000
          psc8-mux0             0           0            320000000
             psc8-en0           0           0            320000000
                psc8_mclk_div   0           0            80000000
                   psc8_mclk_out 0           0            80000000
                      psc8_mclk 0           0            80000000
          psc7-mux0             0           0            320000000
             psc7-en0           0           0            320000000
                psc7_mclk_div   0           0            80000000
                   psc7_mclk_out 0           0            80000000
                      psc7_mclk 0           0            80000000
          psc6-mux0             0           0            320000000
             psc6-en0           0           0            320000000
                psc6_mclk_div   0           0            80000000
                   psc6_mclk_out 0           0            80000000
                      psc6_mclk 0           0            80000000
          psc5-mux0             1           1            320000000
             psc5-en0           1           1            320000000
                psc5_mclk_div   1           1            80000000
                   psc5_mclk_out 1           1            80000000
                      psc5_mclk 1           1            80000000
          psc4-mux0             1           1            320000000
             psc4-en0           1           1            320000000
                psc4_mclk_div   1           1            80000000
                   psc4_mclk_out 1           1            80000000
                      psc4_mclk 1           1            80000000
          psc3-mux0             1           1            320000000
             psc3-en0           1           1            320000000
                psc3_mclk_div   1           1            80000000
                   psc3_mclk_out 1           1            80000000
                      psc3_mclk 1           1            80000000
          psc2-mux0             0           0            320000000
             psc2-en0           0           0            320000000
                psc2_mclk_div   0           0            80000000
                   psc2_mclk_out 0           0            80000000
                      psc2_mclk 0           0            80000000
          psc1-mux0             0           0            320000000
             psc1-en0           0           0            320000000
                psc1_mclk_div   0           0            80000000
                   psc1_mclk_out 0           0            80000000
                      psc1_mclk 0           0            80000000
          psc0-mux0             0           0            320000000
             psc0-en0           0           0            320000000
                psc0_mclk_div   0           0            80000000
                   psc0_mclk_out 0           0            80000000
                      psc0_mclk 0           0            80000000
          ddr-ug                1           1            160000000
             ddr                1           1            160000000
          csb                   4           4            160000000
             viu                0           0            160000000
             iim                0           0            160000000
             usb2               0           0            160000000
             usb1               0           0            160000000
             axe                0           0            160000000
             pci-ug             0           0            26666666
                pci             0           0            26666666
             mbx-bus-ug         0           0            80000000
                mbx-bus         0           0            80000000
                mbx-ug          0           0            80000000
                   mbx          0           0            80000000
                   mbx-3d-ug    0           0            80000000
                      mbx-3d    0           0            80000000
             e300               1           1            400000000
             diu-x4             1           1            640000000
                diu-ug          1           1            2509803
                   diu          2           2            2509803
             sdhc-x4            1           1            640000000
                sdhc-ug         1           1            53333333
                   sdhc-2       0           0            53333333
                   sdhc         1           1            53333333
             ips                7           7            80000000
                i2c             3           3            80000000
                mem             1           1            80000000
                fec             1           1            80000000
                sata            0           0            80000000
                psc-fifo        1           1            80000000
                pata            0           0            80000000
                lpc-ug          1           1            40000000
                   lpc          1           1            40000000
                nfc-ug          0           0            40000000
                   nfc          0           0            40000000
Signature · 1 line
1.7.10.4
#1 lore raw

PATCH 1/24 spi: mpc512x: prepare clocks before enabling them

clocks need to get prepared before they can get enabled, fix the MPC512x PSC SPI master's initialization

---
 drivers/spi/spi-mpc512x-psc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-mpc512x-psc.c +1 -1
index 29fce6a..76b20ea 100644
@@ -395,7 +395,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
 	sprintf(name, "psc%d_mclk", master->bus_num);
 	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
+	clk_prepare_enable(spiclk);
 	mps->mclk = clk_get_rate(spiclk);
 	clk_put(spiclk);
 
Signature · 1 line
1.7.10.4
maintainer
#2 lore raw

PATCH 1/24 spi: mpc512x: prepare clocks before enabling them

Quoted 13 lines · Gerhard Sittig

clocks need to get prepared before they can get enabled, fix the MPC512x PSC SPI master's initialization

---
 drivers/spi/spi-mpc512x-psc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-mpc512x-psc.c +0 -0
index 29fce6a..76b20ea 100644

drivers/spi/spi-mpc512x-psc.c static int mpc512x_psc_spi_port_config(struct spi_master *master, · line 400

Quoted 7 lines
drivers/spi/spi-mpc512x-psc.c +1 -1
@@ -395,7 +395,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
 	sprintf(name, "psc%d_mclk", master->bus_num);
 	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
+	clk_prepare_enable(spiclk);
 	mps->mclk = clk_get_rate(spiclk);
 	clk_put(spiclk);

This code is *clearly* buggy and should be fixed rather than papered
over. Not only is there no matching put the driver is also dropping the
reference to the clock rather than holding on to it while it's in use.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130715/a9b4d8ae/attachment.sig>

#3 lore raw

PATCH 1/24 spi: mpc512x: prepare clocks before enabling them

Quoted 16 lines · Mark Brown
Quoted 14 lines · Gerhard Sittig

clocks need to get prepared before they can get enabled, fix the MPC512x PSC SPI master's initialization

---
 drivers/spi/spi-mpc512x-psc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-mpc512x-psc.c +0 -0
index 29fce6a..76b20ea 100644
@@ -395,7 +395,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
Quoted 10 lines

drivers/spi/spi-mpc512x-psc.c static int mpc512x_psc_spi_port_config(struct spi_master *master, · line 400

Quoted 6 lines
drivers/spi/spi-mpc512x-psc.c +1 -1
 	sprintf(name, "psc%d_mclk", master->bus_num);
 	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
+	clk_prepare_enable(spiclk);
 	mps->mclk = clk_get_rate(spiclk);
 	clk_put(spiclk);

This code is *clearly* buggy and should be fixed rather than papered over. Not only is there no matching put the driver is also dropping the reference to the clock rather than holding on to it while it's in use.

"This code" refers to the driver's original condition, right? I agree that the driver has been suffering from incomplete clock handling since it was born three years ago. And that this issue shall get addressed. The question is just whether it needs to be part of this series which has a different focus.

What the above patch addresses is prevention of an immediate and fatal breakage, when common clock gets used but clocks aren't prepared before getting enabled. So I consider it appropriate as a step in preparation before introducing support for common clock on the platform. (It's funny that I had a comment in this spirit in the commit message, but trimmed it to not be overly verbose.)

What the patch does not address is to fix any other deficiencies in the driver which might have been lurking there for ages. This would be the scope of a different patch or series, as addressing it here as well would mix orthogonal issues within one series, and would complicate review and test (and would delay or even potentially kill the introduction of desirable support for common infrastructure just because other legacy non-fatal issues aren't addressed as well in bypassing).

I will look into what I can do to address your concerns about proper general clock handling in this specific driver. But I'm unable to do this for all other drivers as well which I happen to pass by as I work on platform code (partially due to lack of knowledge). In any case I won't be able to test all of these changes in all subsystems (mostly due to lack of hardware and test setups).

So I suggest to leave these general cleanup activities for a separate series. The current series certainly improves general platform code, transparently brings new drivers into successful operation, and keeps the quality of existing code (doesn't break anything, does even actively prevent breakage). So it shall be acceptable despite its not being perfect (like addressing each and every other aspect which may arise elsewhere). Where would I stop then?

Sorry for the lengthy reply, but I guess it's about just one general aspect which equally applies to other parts of the series, not just the specific SPI driver which the feedback was provided for. And I do appreciate your looking at the submission.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
maintainer
#4 lore raw

PATCH 1/24 spi: mpc512x: prepare clocks before enabling them

Quoted 14 lines · Gerhard Sittig
Quoted 12 lines · Mark Brown

drivers/spi/spi-mpc512x-psc.c static int mpc512x_psc_spi_port_config(struct spi_master *master, · line 400

Quoted 6 lines · Gerhard Sittig
  sprintf(name, "psc%d_mclk", master->bus_num);
drivers/spi/spi-mpc512x-psc.c +1 -1
 	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
+	clk_prepare_enable(spiclk);
 	mps->mclk = clk_get_rate(spiclk);
 	clk_put(spiclk);

This code is *clearly* buggy and should be fixed rather than papered over. Not only is there no matching put the driver is also dropping the reference to the clock rather than holding on to it while it's in use.

Quoted 5 lines

"This code" refers to the driver's original condition, right? I agree that the driver has been suffering from incomplete clock handling since it was born three years ago. And that this issue shall get addressed. The question is just whether it needs to be part of this series which has a different focus.

This is a pretty long e-mail. It'd probably have taken less time to fix the issues than to reply to the e-mail... but anyway.

A big part of the issue with the state of the driver is that there's
obvious clock API abuse going on that isn't corrected here - the main
one is that the sprintf() for the clock name is a fairly clear warning
sign, the driver should be using a fixed value there. This raises a
warning flag for me about the quality of the common clock API
implementation that's being sent and/or the potential for bugs to be
noticed with the common clock framework. I'd not expect this code to
actually work, and looking at the rest of the series I don't see how it
does since I can't see what forces the name.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130717/245057e2/attachment-0001.sig>

#5 lore raw

PATCH 1/24 spi: mpc512x: prepare clocks before enabling them

Quoted 16 lines · Mark Brown
Quoted 13 lines · Gerhard Sittig
Quoted 12 lines · Mark Brown

drivers/spi/spi-mpc512x-psc.c static int mpc512x_psc_spi_port_config(struct spi_master *master, · line 400

Quoted 6 lines · Gerhard Sittig
  sprintf(name, "psc%d_mclk", master->bus_num);
drivers/spi/spi-mpc512x-psc.c +1 -1
 	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
+	clk_prepare_enable(spiclk);
 	mps->mclk = clk_get_rate(spiclk);
 	clk_put(spiclk);

This code is *clearly* buggy and should be fixed rather than papered over. Not only is there no matching put the driver is also dropping the reference to the clock rather than holding on to it while it's in use.

Quoted 8 lines
Quoted 5 lines

"This code" refers to the driver's original condition, right? I agree that the driver has been suffering from incomplete clock handling since it was born three years ago. And that this issue shall get addressed. The question is just whether it needs to be part of this series which has a different focus.

This is a pretty long e-mail. It'd probably have taken less time to fix the issues than to reply to the e-mail... but anyway.

[ this is meta stuff, technical details are after the next quotation ]

Not quite. Please consider that careful submission is as expensive as thorough review is, and that a lot of work is done before v1 gets submitted, which you may not always notice from looking at a concentrated series that may no longer suggest how much it took to get there (especially when prepared carefully).

As mentioned before I did not question the need to fix issues as they get identified. I just asked whether reworking the serial driver is in the scope of this series which provides a different clock driver implementation for the platform. To me these two things are orthogonal, while I did promise to see how I can address your concerns.

Let's provide the technical information you need to judge the quality of the submission and see why it shall be acceptable:

Quoted 9 lines

A big part of the issue with the state of the driver is that there's obvious clock API abuse going on that isn't corrected here - the main one is that the sprintf() for the clock name is a fairly clear warning sign, the driver should be using a fixed value there. This raises a warning flag for me about the quality of the common clock API implementation that's being sent and/or the potential for bugs to be noticed with the common clock framework. I'd not expect this code to actually work, and looking at the rest of the series I don't see how it does since I can't see what forces the name.

Why the code does work:

OK, here is why the driver keeps its state throughout the set and is operational as good or as bad as it was before:

The sprintf() in the SPI driver used to construct a name which includes the PSC index. This applies to the UART driver as well, as they both use the PSC controller hardware to implement their serial communication.

The corresponding clock name was found in the previous PPC_CLOCK implementation since the clock driver provided those names which include the PSC index (fixed strings in a table).

The initial COMMON_CLK implementation in part 09/24 registers clkdev items for compatibility during migration. The string isn't greppable since it's constructed by the preprocessor in the MCLK data setup, see the MCLK_SETUP_DATA_PSC() macro.

Part 13/24 adjusts the SPI driver to no longer construct a name, but instead use a fixed string after OF based clock lookup became available. This shall meet your expectation and simplifies the client side. Part 15/24 does the same for the UART driver.

Part 16/24 removes the clkdev registration in the clock driver after both the UART and SPI clients switched to OF clock lookups.

At this stage things are the way you would expect: The client uses a fixed string in the lookup, while lookup occurs via device tree, and instances are supported without the clients' constructing something based on a component index.

Remaining issues are not with the common clock support of the platform, but in the serial driver and are identical to the previous (actually: the initial) status. While we agree on the existance of the remaining issue and the desire to address it. Just not on which context that fix shall be done in.

The series' status and perspective:

The UART and SPI drivers did work before, while it's true that clock handling wasn't complete (in non-fatal ways). This has been the case in the past, and has been identified just now.

The serial drivers are kept operational during migration, and still are operational after the series. But now they use common clock and OF lookups, which is an improvement for the platform in my eyes.

It's true that the status of the serial driver isn't improved with the series -- but it isn't degraded either, while (additional) breakage actively gets prevented.

Now let me see how I can improve the SPI driver with regard to overall clock handling and beyond mere operation by coincidence in the absence of errors. But please understand that I don't want to stall the common clock support for a whole platform just because some of the drivers it needs to touch to keep them operational have other issues that weren't addressed yet, while these issues aren't introduced with the series but preceed it.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
maintainer
#6 lore raw

PATCH 1/24 spi: mpc512x: prepare clocks before enabling them

Quoted 10 lines · Gerhard Sittig
Quoted 2 lines · Mark Brown

This is a pretty long e-mail. It'd probably have taken less time to fix the issues than to reply to the e-mail... but anyway.

Not quite. Please consider that careful submission is as expensive as thorough review is, and that a lot of work is done before v1 gets submitted, which you may not always notice from looking at a concentrated series that may no longer suggest how much it took to get there (especially when prepared carefully).

This is rather undermined the more time and effort gets spent pushing back against doing trival fixes, of course... besides, the issues here are all really simple to fix and test. It's not a major or risky rewrite of the driver or anything like that - most of this can be tested by just probing the driver.

Quoted 2 lines

As mentioned before I did not question the need to fix issues as they get identified. I just asked whether reworking the serial

OK, so send patches then.

Quoted 4 lines

The initial COMMON_CLK implementation in part 09/24 registers clkdev items for compatibility during migration. The string isn't greppable since it's constructed by the preprocessor in the MCLK data setup, see the MCLK_SETUP_DATA_PSC() macro.

Ugh, right - it didn't show up in searches due to being hidden by the macro.

Quoted 7 lines

Now let me see how I can improve the SPI driver with regard to overall clock handling and beyond mere operation by coincidence in the absence of errors. But please understand that I don't want to stall the common clock support for a whole platform just because some of the drivers it needs to touch to keep them operational have other issues that weren't addressed yet, while these issues aren't introduced with the series but preceed it.

Again, you're not being asked to implement substantial new functionality here. From my point of view I can't test this at all so I'm looking at code that's obviously not good for the standard clock API and wondering if it even works or how robust it's going to be going forward as the common clock code changes which makes me relucatant to say it'll be OK.

The fact that you're switching over to use generic code is itself a
reason to make sure that the API usage is sane, dodgy API usage against
open coded clock implementations is less risky than against the common
code.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130717/df54aed2/attachment.sig>

#7 lore raw

PATCH 2/24 serial: mpc512x: prepare clocks before enabling them

In reply to Gerhard Sittig

clocks need to get prepared before they can get enabled, and after disabling them they can get unprepared

---
 drivers/tty/serial/mpc52xx_uart.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/tty/serial/mpc52xx_uart.c +2 -2
index e1280a2..53c1093 100644
@@ -636,9 +636,9 @@ static int mpc512x_psc_clock(struct uart_port *port, int enable)
 	dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
 
 	if (enable)
-		clk_enable(psc_clk);
+		clk_prepare_enable(psc_clk);
 	else
-		clk_disable(psc_clk);
+		clk_disable_unprepare(psc_clk);
 
 	return 0;
 }
Signature · 1 line
1.7.10.4
#8 lore raw

PATCH 3/24 mtd: mpc5121_nfc: prepare clocks before enabling them

In reply to Gerhard Sittig

must prepare clocks before enabling them, unprepare after disable

---
 drivers/mtd/nand/mpc5121_nfc.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mtd/nand/mpc5121_nfc.c +2 -2
index 3c9cdcb..eb7771d 100644
@@ -618,7 +618,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 	struct mpc5121_nfc_prv *prv = chip->priv;
 
 	if (prv->clk) {
-		clk_disable(prv->clk);
+		clk_disable_unprepare(prv->clk);
 		clk_put(prv->clk);
 	}
 
@@ -737,7 +737,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 		goto error;
 	}
 
-	clk_enable(prv->clk);
+	clk_prepare_enable(prv->clk);
 
 	/* Reset NAND Flash controller */
 	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
Signature · 1 line
1.7.10.4
#9 lore raw

PATCH 4/24 powerpc: mpc512x: array decl for MCLK registers in CCM

In reply to Gerhard Sittig

reword the clock control module's registers declaration such that the MCLK related registers form an array and get indexed by PSC number

this change is in preparation to COMMON_CLK support for the MPC512x platform, the changed declaration remains neutral to existing code since the PSC and MSCAN CCR fields declared here aren't referenced anywhere

---
 arch/powerpc/include/asm/mpc5121.h |   18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)
arch/powerpc/include/asm/mpc5121.h +2 -16
index 8ae133e..887d3d6 100644
@@ -32,25 +32,11 @@ struct mpc512x_ccm {
 	u32	scfr2;	/* System Clock Frequency Register 2 */
 	u32	scfr2s;	/* System Clock Frequency Shadow Register 2 */
 	u32	bcr;	/* Bread Crumb Register */
-	u32	p0ccr;	/* PSC0 Clock Control Register */
-	u32	p1ccr;	/* PSC1 CCR */
-	u32	p2ccr;	/* PSC2 CCR */
-	u32	p3ccr;	/* PSC3 CCR */
-	u32	p4ccr;	/* PSC4 CCR */
-	u32	p5ccr;	/* PSC5 CCR */
-	u32	p6ccr;	/* PSC6 CCR */
-	u32	p7ccr;	/* PSC7 CCR */
-	u32	p8ccr;	/* PSC8 CCR */
-	u32	p9ccr;	/* PSC9 CCR */
-	u32	p10ccr;	/* PSC10 CCR */
-	u32	p11ccr;	/* PSC11 CCR */
+	u32	psc_ccr[12];	/* PSC Clock Control Registers */
 	u32	spccr;	/* SPDIF Clock Control Register */
 	u32	cccr;	/* CFM Clock Control Register */
 	u32	dccr;	/* DIU Clock Control Register */
-	u32	m1ccr;	/* MSCAN1 CCR */
-	u32	m2ccr;	/* MSCAN2 CCR */
-	u32	m3ccr;	/* MSCAN3 CCR */
-	u32	m4ccr;	/* MSCAN4 CCR */
+	u32	mscan_ccr[4];	/* MSCAN Clock Control Registers */
 	u8	res[0x98]; /* Reserved */
 };
 
Signature · 1 line
1.7.10.4
#10 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

In reply to Gerhard Sittig

the common clock drivers were motivated/initiated by ARM development and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux) in preparation of adding COMMON_CLK support for other platforms

---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
drivers/clk/clk-divider.c +3 -3
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);
 
 	div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
 		val = div_mask(divider) << (divider->shift + 16);
 	} else {
-		val = readl(divider->reg);
+		val = clk_readl(divider->reg);
 		val &= ~(div_mask(divider) << divider->shift);
 	}
 	val |= value << divider->shift;
-	writel(val, divider->reg);
+	clk_writel(val, divider->reg);
 
 	if (divider->lock)
 		spin_unlock_irqrestore(divider->lock, flags);
drivers/clk/clk-gate.c +3 -3
index 790306e..b7fbd96 100644
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		if (set)
 			reg |= BIT(gate->bit_idx);
 	} else {
-		reg = readl(gate->reg);
+		reg = clk_readl(gate->reg);
 
 		if (set)
 			reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 			reg &= ~BIT(gate->bit_idx);
 	}
 
-	writel(reg, gate->reg);
+	clk_writel(reg, gate->reg);
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 	u32 reg;
 	struct clk_gate *gate = to_clk_gate(hw);
 
-	reg = readl(gate->reg);
+	reg = clk_readl(gate->reg);
 
 	/* if a set bit disables this clk, flip it before masking */
 	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
drivers/clk/clk-mux.c +3 -3
index 614444c..02ef506 100644
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
 	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
 	 * val = 0x4 really means "bit 2, index starts at bit 0"
 	 */
-	val = readl(mux->reg) >> mux->shift;
+	val = clk_readl(mux->reg) >> mux->shift;
 	val &= mux->mask;
 
 	if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
 		val = mux->mask << (mux->shift + 16);
 	} else {
-		val = readl(mux->reg);
+		val = clk_readl(mux->reg);
 		val &= ~(mux->mask << mux->shift);
 	}
 	val |= index << mux->shift;
-	writel(val, mux->reg);
+	clk_writel(val, mux->reg);
 
 	if (mux->lock)
 		spin_unlock_irqrestore(mux->lock, flags);
include/linux/clk-provider.h +17 -0
index 1ec14a7..c4f7799 100644
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
 	{ while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4
#11 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

drivers/clk/clk-divider.c static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, · line 108

Quoted 11 lines · Gerhard Sittig
drivers/clk/clk-divider.c +1 -1
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);

Would it be an option to use regmap for the generic dividers/muxes instead? This should be suitable for ppc and also for people who want to use the generic clocks on i2c devices.

Sascha

Signature · 4 lines
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
#12 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

Quoted 10 lines · Sascha Hauer
Quoted 8 lines · Gerhard Sittig
drivers/clk/clk-divider.c +0 -0
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
Quoted 7 lines

drivers/clk/clk-divider.c static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, · line 108

Quoted 3 lines
drivers/clk/clk-divider.c +1 -1
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);

Would it be an option to use regmap for the generic dividers/muxes instead? This should be suitable for ppc and also for people who want to use the generic clocks on i2c devices.

Does regmap assume that those registers form a (dense) array of equal sized items? Does it introduce unconditional indirection and requirement for explicit setup beyond mere mapping? What's the overhead compared to the readl/inbe32 approach that's currently resolved at compile time?

Neither of the above needs to be a blocker, just needs to be acceptable after consideration. So far nobody appears to have felt pain with the LE32 register assumption.

BTW does the common clock support that I introduce for MPC512x only cover those parts from crystal over internal busses to internal peripherals (register files).

It does not include bitrate generation within the peripherals -- this appears to remain the domain of individual drivers, which keep manipulating register fields to derive wire bitrates from internal references. Sharing drivers between platforms with and without common clock support forbids the switch anyway, or both CCF abstraction as well as local register manipulation need to get implemented in parallel, as I did for the mscan(4) driver.

Some of these bitrate related registers aren't 32bit entities and thus could not get managed by the common clock primitives in their current form. Some of the IP blocks may even spread integer values across several non-adjacent bit fields for legacy reasons, but I guess that these aren't in the scope of the shared primitives either (and they may not be popular either).

While we are at improvements for the common clock primitives:

What I missed was support for fractional dividers, i.e. dividers with a register bitfield backed divider part but a fixed factor multiplier part. Currently there's only dividers (bitfield factor or bitfield with table lookup for the factor) and fixed-factor (multiplier and divider, but both of them fixed and not adjustable by register manipulation). This was addressed by "intermediate" clock items ("ungated", "x4")

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#13 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

In reply to Sascha Hauer
Quoted 10 lines · Sascha Hauer
Quoted 8 lines · Gerhard Sittig
drivers/clk/clk-divider.c +0 -0
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
Quoted 7 lines

drivers/clk/clk-divider.c static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, · line 108

Quoted 3 lines
drivers/clk/clk-divider.c +1 -1
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);

Would it be an option to use regmap for the generic dividers/muxes instead? This should be suitable for ppc and also for people who want to use the generic clocks on i2c devices.

Some other thought crossed my mind regarding access to clock control registers that reside behind some communication channel like I2C:

The common clock API assumes (it's part of the contract) that there are potentially expensive operations like get, put, prepare and unprepare, as well as swift and non-blocking operations like enable and disable.

Would the regmap abstraction hide the potentially blocking nature of a register access (I understand that you can implement "local" as well as "remote" register sets by this mechanism)? Or could you still meet the assumptions or requirements of the common clock API?

It might as well be the responsibility of the clock driver's implementor to arrange for the availability of non-blocking enable/disable operations, just as it is today. Such that expensive register access need not be forbidden in general.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#14 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

Quoted 34 lines · Gerhard Sittig
Quoted 10 lines · Sascha Hauer
Quoted 8 lines · Gerhard Sittig
drivers/clk/clk-divider.c +0 -0
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
Quoted 7 lines

drivers/clk/clk-divider.c static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, · line 108

Quoted 3 lines
drivers/clk/clk-divider.c +1 -1
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);

Would it be an option to use regmap for the generic dividers/muxes instead? This should be suitable for ppc and also for people who want to use the generic clocks on i2c devices.

Some other thought crossed my mind regarding access to clock control registers that reside behind some communication channel like I2C:

The common clock API assumes (it's part of the contract) that there are potentially expensive operations like get, put, prepare and unprepare, as well as swift and non-blocking operations like enable and disable.

Would the regmap abstraction hide the potentially blocking nature of a register access (I understand that you can implement "local" as well as "remote" register sets by this mechanism)? Or could you still meet the assumptions or requirements of the common clock API?

Quoted 4 lines

It might as well be the responsibility of the clock driver's implementor to arrange for the availability of non-blocking enable/disable operations, just as it is today. Such that expensive register access need not be forbidden in general.

regmap for mmio uses a spinlock for read/modify/write operations, just like you have to use a spinlock in the common clk dividers/gates. This part wouldn't change with regmap.

For i2c connected clocks where a spinlock doesn't work due to the nonatomic nature of i2c devices we would have to move the enable/disble stuff to prepare/unprepare in the common gate code. This can be left for someone who works on i2c clocks though.

I think regmap has the potential to solve a number of issues like the hardcoded readl/writel in the common clock blocks, issues with i2c clocks and your endianess issue. The biggest question probably is how to get there without putting too much of a burden on you. It's probably not an option to convert all users to regmap, so it seems additional functions like clk_register_gate_regmap are better to handle.

Sascha

Signature · 4 lines
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
maintainer
#15 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

Quoted 6 lines · Sascha Hauer

I think regmap has the potential to solve a number of issues like the hardcoded readl/writel in the common clock blocks, issues with i2c clocks and your endianess issue. The biggest question probably is how to get there without putting too much of a burden on you. It's probably not an option to convert all users to regmap, so it seems additional functions like clk_register_gate_regmap are better to handle.

That's basically what regulator does. There's versions of the ops that
all the drivers can use.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130718/43ffb513/attachment.sig>

#16 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

In reply to Gerhard Sittig
Quoted 4 lines · Gerhard Sittig

The common clock API assumes (it's part of the contract) that there are potentially expensive operations like get, put, prepare and unprepare, as well as swift and non-blocking operations like enable and disable.

Let's get something straight here, because what you've said above is wrong.

1. clk_get() and clk_put() are NOT part of the common clock API. They're separate - they're part of the clk API, and the infrastructure behind that is clkdev, which is a separately owned thing (by me.)

2. The "contract" of the clk API is defined by the clk API, not by some random implementation like the common clock API. The clk API is maintained by myself, and is described in include/linux/clk.h

3. clk_prepare() and clk_unprepare() are functions MUST only be called from contexts where sleeping is permitted. These functions MAY sleep for whatever reason they require to, and as long as they require to. (This is the whole reason these two functions were created in the first place.)

4. clk_enable() and clk_disable() MAY be called from any context, but MUST never sleep. If you need to talk over a non-atomic bus for these, then these functions should be no-ops, and the code which does that must be executed from the clk_prepare()/clk_unprepare() operations.

That is the "clk API" contract. The CCF has no bearing on this; if it disagrees, then the CCF is buggy and is non-conformant.

#17 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

Quoted 14 lines · Russell King - ARM Linux

1. clk_get() and clk_put() are NOT part of the common clock API. They're separate - they're part of the clk API, and the infrastructure behind that is clkdev, which is a separately owned thing (by me.)

2. The "contract" of the clk API is defined by the clk API, not by some random implementation like the common clock API. The clk API is maintained by myself, and is described in include/linux/clk.h

3. clk_prepare() and clk_unprepare() are functions MUST only be called from contexts where sleeping is permitted. These functions MAY sleep for whatever reason they require to, and as long as they require to. (This is the whole reason these two functions were created in the first place.)

Quoted 4 lines

4. clk_enable() and clk_disable() MAY be called from any context, but MUST never sleep. If you need to talk over a non-atomic bus for these, then these functions should be no-ops, and the code which does that must be executed from the clk_prepare()/clk_unprepare() operations.

Could the above be included in some form in Documentation/clk.txt (this is likely one of the first location people look for information) and elsewhere if appropriate please?

A *lot* of people are confused by the prepare-enable-disable-unprepare sequence and when I try to find some rational for the prepare/enable split I can only direct them to mail archive posts since this is nowhere to be found in the kernel.

The comments in include/linux/clk.h, while correct, are very terse and don't provide any insight to the reason why there is a split in the API.

The content of Documentation/clk.txt does refer to prepare and enable (and their counterparts) but again doesn't provide any clue about the reason for their existence.

Since there've been several good posts with usage example now buried into list archives, I think this would go a long way helping people get it right if those were part of the kernel documentation as well.

Nicolas

#18 lore raw

PATCH 5/24 clk: wrap I/O access for improved portability

Quoting Nicolas Pitre (2013-07-18 10:47:22)

Quoted 33 lines · Russell King - ARM Linux
Quoted 15 lines

1. clk_get() and clk_put() are NOT part of the common clock API. They're separate - they're part of the clk API, and the infrastructure behind that is clkdev, which is a separately owned thing (by me.)

2. The "contract" of the clk API is defined by the clk API, not by some random implementation like the common clock API. The clk API is maintained by myself, and is described in include/linux/clk.h

3. clk_prepare() and clk_unprepare() are functions MUST only be called from contexts where sleeping is permitted. These functions MAY sleep for whatever reason they require to, and as long as they require to. (This is the whole reason these two functions were created in the first place.)

Quoted 4 lines

4. clk_enable() and clk_disable() MAY be called from any context, but MUST never sleep. If you need to talk over a non-atomic bus for these, then these functions should be no-ops, and the code which does that must be executed from the clk_prepare()/clk_unprepare() operations.

Could the above be included in some form in Documentation/clk.txt (this is likely one of the first location people look for information) and elsewhere if appropriate please?

A *lot* of people are confused by the prepare-enable-disable-unprepare sequence and when I try to find some rational for the prepare/enable split I can only direct them to mail archive posts since this is nowhere to be found in the kernel.

The comments in include/linux/clk.h, while correct, are very terse and don't provide any insight to the reason why there is a split in the API.

Quoted 7 lines

The content of Documentation/clk.txt does refer to prepare and enable (and their counterparts) but again doesn't provide any clue about the reason for their existence.

Since there've been several good posts with usage example now buried into list archives, I think this would go a long way helping people get it right if those were part of the kernel documentation as well.

I'll update Documentation/clk.txt with more verbosity. The document was originally intended as a "porting guide" to help migrate from legacy frameworks to the common struct clk implementation. However the scope of the document should probably be generalized a bit more.

Regards,
Mike

Quoted 3 lines

Nicolas

#19 lore raw

PATCH 6/24 dts: mpc512x: prepare for preprocessor support

In reply to Gerhard Sittig

prepare C preprocessor support when processing MPC512x DTS files
- switch from DTS syntax to CPP syntax for include specs
- create a symlink such that DTS processing can reference includes

---
 arch/powerpc/boot/dts/ac14xx.dts          |    2 +-
 arch/powerpc/boot/dts/include/dt-bindings |    1 +
 arch/powerpc/boot/dts/mpc5121ads.dts      |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts        |    2 +-
 4 files changed, 4 insertions(+), 3 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
arch/powerpc/boot/dts/ac14xx.dts +1 -1
index a27a460..a543c40 100644
@@ -10,7 +10,7 @@
  */
 
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "ac14xx";
arch/powerpc/boot/dts/include/dt-bindings new file +1 -0
new file mode 120000
index 0000000..08c00e4
@@ -0,0 +1 @@
+../../../../../include/dt-bindings
\ No newline at end of file
arch/powerpc/boot/dts/mpc5121ads.dts +1 -1
index 7d3cb79..c228a0a 100644
@@ -9,7 +9,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "mpc5121ads";
arch/powerpc/boot/dts/pdm360ng.dts +1 -1
index 7433740..871c16d 100644
@@ -13,7 +13,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "pdm360ng";
Signature · 1 line
1.7.10.4
#20 lore raw

PATCH 7/24 dts: mpc512x: introduce dt-bindings/clock/ header

In reply to Gerhard Sittig

introduce a dt-bindings/ header file for MPC512x clocks, providing symbolic identifiers for those SoC clocks which clients will reference from their device tree nodes

---
 include/dt-bindings/clock/mpc512x-clock.h |   59 +++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
include/dt-bindings/clock/mpc512x-clock.h new file +59 -0
new file mode 100644
index 0000000..46c560e
@@ -0,0 +1,59 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ *
+ * Unfortunately the clock number declaration cannot be an enum but
+ * needs to be a list of #define directives since when referenced from
+ * within DTS files they need to get resolved "at compile time".
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY		0
+#define MPC512x_CLK_REF			1
+#define MPC512x_CLK_SYS			2
+#define MPC512x_CLK_DIU			3
+#define MPC512x_CLK_VIU			4
+#define MPC512x_CLK_CSB			5
+#define MPC512x_CLK_E300		6
+#define MPC512x_CLK_IPS			7
+#define MPC512x_CLK_FEC			8
+#define MPC512x_CLK_SATA		9
+#define MPC512x_CLK_PATA		10
+#define MPC512x_CLK_NFC			11
+#define MPC512x_CLK_LPC			12
+#define MPC512x_CLK_MBX_BUS		13
+#define MPC512x_CLK_MBX			14
+#define MPC512x_CLK_MBX_3D		15
+#define MPC512x_CLK_AXE			16
+#define MPC512x_CLK_USB1		17
+#define MPC512x_CLK_USB2		18
+#define MPC512x_CLK_I2C			19
+#define MPC512x_CLK_MSCAN0_MCLK		20
+#define MPC512x_CLK_MSCAN1_MCLK		21
+#define MPC512x_CLK_MSCAN2_MCLK		22
+#define MPC512x_CLK_MSCAN3_MCLK		23
+#define MPC512x_CLK_SDHC		24
+#define MPC512x_CLK_PCI			25
+#define MPC512x_CLK_PSC_MCLK_IN		26
+#define MPC512x_CLK_SPDIF_TX		27
+#define MPC512x_CLK_SPDIF_RX		28
+#define MPC512x_CLK_SPDIF_MCLK		29
+#define MPC512x_CLK_AC97		30
+#define MPC512x_CLK_PSC0_MCLK		31
+#define MPC512x_CLK_PSC1_MCLK		32
+#define MPC512x_CLK_PSC2_MCLK		33
+#define MPC512x_CLK_PSC3_MCLK		34
+#define MPC512x_CLK_PSC4_MCLK		35
+#define MPC512x_CLK_PSC5_MCLK		36
+#define MPC512x_CLK_PSC6_MCLK		37
+#define MPC512x_CLK_PSC7_MCLK		38
+#define MPC512x_CLK_PSC8_MCLK		39
+#define MPC512x_CLK_PSC9_MCLK		40
+#define MPC512x_CLK_PSC10_MCLK		41
+#define MPC512x_CLK_PSC11_MCLK		42
+#define MPC512x_CLK_PSC_FIFO		43
+
+#define MPC512x_CLK_LAST_PUBLIC		43
+
+#endif
Signature · 1 line
1.7.10.4
#21 lore raw

PATCH 8/24 dts: mpc512x: add clock related device tree specs

In reply to Gerhard Sittig

this addresses the clock driver aka provider's side of clocks
- prepare for future '<&clks ID>' phandle references for device tree based clock lookup in client drivers
- introduce a 'clocks' subtree with an 'osc' node for the crystal or oscillator SoC input (fixed frequency)
- provide default values with 33MHz oscillator frequency in the common include (the 66MHz IPS bus already was there), add override values for the ifm AC14xx board which deviates from the reference design (25MHz xtal, 80MHz IPS bus)

---
 arch/powerpc/boot/dts/ac14xx.dts   |    7 +++++++
 arch/powerpc/boot/dts/mpc5121.dtsi |   15 ++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
arch/powerpc/boot/dts/ac14xx.dts +7 -0
index a543c40..a1b8837 100644
@@ -139,7 +139,14 @@
 		};
 	};
 
+	clocks {
+		osc {
+			clock-frequency = <25000000>;
+		};
+	};
+
 	soc at 80000000 {
+		bus-frequency = <80000000>;	/* 80 MHz ips bus */
 
 		clock at f00 {
 			compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
arch/powerpc/boot/dts/mpc5121.dtsi +14 -1
index bd14c00..8f4cba0 100644
@@ -9,6 +9,8 @@
  * option) any later version.
  */
 
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 
 / {
@@ -73,6 +75,16 @@
 		ranges = <0x0 0x0 0xfc000000 0x04000000>;
 	};
 
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		osc {
+			compatible = "fsl,mpc512x-osc", "fixed-clock";
+			clock-frequency = <33000000>;
+		};
+	};
+
 	soc at 80000000 {
 		compatible = "fsl,mpc5121-immr";
 		#address-cells = <1>;
@@ -118,9 +130,10 @@
 		};
 
 		/* Clock control */
-		clock at f00 {
+		clks: clock at f00 {
 			compatible = "fsl,mpc5121-clock";
 			reg = <0xf00 0x100>;
+			#clock-cells = <1>;
 		};
 
 		/* Power Management Controller */
Signature · 1 line
1.7.10.4
#22 lore raw

PATCH 9/24 clk: mpc512x: introduce COMMON_CLK for MPC512x

In reply to Gerhard Sittig

this change introduces a clock infrastructure implementation for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

this driver implements the publicly announced set of clocks (which can get referenced by means of symbolic identifiers from the dt-bindings header file), as well as generates additional 'struct clk' items where the SoC hardware cannot easily get mapped to the common primitives of the clock API, or requires "intermediate" clock nodes to represent clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and resides in parallel to the common clock implementation for test and comparison during migration, a compile time option picks one of the two alternatives (Kconfig switch, common clock used by default)

---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  777 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 809 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
arch/powerpc/platforms/512x/Kconfig +13 -1
index fc9c1cb..c5fcdd0 100644
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+	bool "MPC512x platform uses COMMON_CLK"
+	default y
+	depends on PPC_MPC512x
+	help
+	  This option is only here to support tests and comparison
+	  during development and migration.  This option will get
+	  removed after the COMMON_CLK support for MPC512x has become
+	  fully operational and all drivers were adjusted to explicitly
+	  acquire their required clocks.
+
 config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
 	select FSL_SOC
 	select IPIC
-	select PPC_CLOCK
+	select PPC_CLOCK if !MPC512x_COMMON_CLK
+	select COMMON_CLK if MPC512x_COMMON_CLK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
arch/powerpc/platforms/512x/Makefile +3 -1
index 72fb934..1e05f9d 100644
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y				+= clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)		+= clock.o
+obj-$(CONFIG_COMMON_CLK)	+= clock-commonclk.o
+obj-y				+= mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)	+= mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)		+= pdm360ng.o
arch/powerpc/platforms/512x/clock-commonclk.c new file +777 -0

777 lines not on this page · raw message

include/linux/clk-provider.h +16 -0
index c4f7799..7f8fc64 100644
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	iowrite32be(val, reg);
+}
+
+#else	/* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
 	return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
 	writel(val, reg);
 }
 
+#endif	/* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4
#23 lore raw

PATCH 10/24 dts: mpc512x: add clock specs for client lookups

In reply to Gerhard Sittig

this addresses the client side of device tree based clock lookups:
add clock specifiers to the mbx, nfc, mscan, sdhc, i2c, axe, diu, viu, mdio, fec, usb, pata, psc, psc fifo, and pci nodes in the shared mpc5121.dtsi include

these specs map 'clock-names' encoded in drivers to their respective 'struct clk' items in the platform's clock driver; some drivers still need to learn how to lookup OF clocks, other drivers will transparently probe successfully on MPC512x as well (sdhc)

few 'clock-names' (nfc, viu) use strings that are encoded in their respective drivers to keep up compatibility, an alternative approach would be to register clkdev items in the platform's clock driver for the migration period

---
 arch/powerpc/boot/dts/mpc5121.dtsi |   79 ++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
arch/powerpc/boot/dts/mpc5121.dtsi +79 -0
index 8f4cba0..983da9c 100644
@@ -51,6 +51,10 @@
 		compatible = "fsl,mpc5121-mbx";
 		reg = <0x20000000 0x4000>;
 		interrupts = <66 0x8>;
+		clocks = <&clks MPC512x_CLK_MBX_BUS>,
+			 <&clks MPC512x_CLK_MBX_3D>,
+			 <&clks MPC512x_CLK_MBX>;
+		clock-names = "mbx-bus", "mbx-3d", "mbx";
 	};
 
 	sram at 30000000 {
@@ -64,6 +68,8 @@
 		interrupts = <6 8>;
 		#address-cells = <1>;
 		#size-cells = <1>;
+		clocks = <&clks MPC512x_CLK_NFC>;
+		clock-names = "nfc_clk";	/* backwards compat */
 	};
 
 	localbus at 80000020 {
@@ -153,12 +159,22 @@
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1300 0x80>;
 			interrupts = <12 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN0_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can at 1380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1380 0x80>;
 			interrupts = <13 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN1_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		sdhc at 1500 {
@@ -167,6 +183,9 @@
 			interrupts = <8 0x8>;
 			dmas = <&dma0 30>;
 			dma-names = "rx-tx";
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SDHC>;
+			clock-names = "ipg", "per";
 		};
 
 		i2c at 1700 {
@@ -175,6 +194,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1700 0x20>;
 			interrupts = <9 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c at 1720 {
@@ -183,6 +204,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1720 0x20>;
 			interrupts = <10 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c at 1740 {
@@ -191,6 +214,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1740 0x20>;
 			interrupts = <11 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2ccontrol at 1760 {
@@ -202,30 +227,46 @@
 			compatible = "fsl,mpc5121-axe";
 			reg = <0x2000 0x100>;
 			interrupts = <42 0x8>;
+			clocks = <&clks MPC512x_CLK_AXE>;
+			clock-names = "per";
 		};
 
 		display at 2100 {
 			compatible = "fsl,mpc5121-diu";
 			reg = <0x2100 0x100>;
 			interrupts = <64 0x8>;
+			clocks = <&clks MPC512x_CLK_DIU>;
+			clock-names = "per";
 		};
 
 		can at 2300 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2300 0x80>;
 			interrupts = <90 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN2_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can at 2380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2380 0x80>;
 			interrupts = <91 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN3_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		viu at 2400 {
 			compatible = "fsl,mpc5121-viu";
 			reg = <0x2400 0x400>;
 			interrupts = <67 0x8>;
+			clocks = <&clks MPC512x_CLK_VIU>;
+			clock-names = "viu_clk";	/* backwards compat */
 		};
 
 		mdio at 2800 {
@@ -233,6 +274,8 @@
 			reg = <0x2800 0x800>;
 			#address-cells = <1>;
 			#size-cells = <0>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		eth0: ethernet at 2800 {
@@ -241,6 +284,8 @@
 			reg = <0x2800 0x800>;
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <4 0x8>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		/* USB1 using external ULPI PHY */
@@ -252,6 +297,8 @@
 			interrupts = <43 0x8>;
 			dr_mode = "otg";
 			phy_type = "ulpi";
+			clocks = <&clks MPC512x_CLK_USB1>;
+			clock-names = "per";
 		};
 
 		/* USB0 using internal UTMI PHY */
@@ -263,6 +310,8 @@
 			interrupts = <44 0x8>;
 			dr_mode = "otg";
 			phy_type = "utmi_wide";
+			clocks = <&clks MPC512x_CLK_USB2>;
+			clock-names = "per";
 		};
 
 		/* IO control */
@@ -281,6 +330,8 @@
 			compatible = "fsl,mpc5121-pata";
 			reg = <0x10200 0x100>;
 			interrupts = <5 0x8>;
+			clocks = <&clks MPC512x_CLK_PATA>;
+			clock-names = "per";
 		};
 
 		/* 512x PSCs are not 52xx PSC compatible */
@@ -292,6 +343,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC0_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC1 */
@@ -301,6 +354,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC1_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC2 */
@@ -310,6 +365,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC2_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC3 */
@@ -319,6 +376,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC3_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC4 */
@@ -328,6 +387,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC4_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC5 */
@@ -337,6 +398,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC5_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC6 */
@@ -346,6 +409,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC6_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC7 */
@@ -355,6 +420,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC7_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC8 */
@@ -364,6 +431,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC8_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC9 */
@@ -373,6 +442,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC9_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC10 */
@@ -382,6 +453,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC10_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC11 */
@@ -391,12 +464,16 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC11_MCLK>;
+			clock-names = "mclk";
 		};
 
 		pscfifo at 11f00 {
 			compatible = "fsl,mpc5121-psc-fifo";
 			reg = <0x11f00 0x100>;
 			interrupts = <40 0x8>;
+			clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+			clock-names = "per";
 		};
 
 		dma0: dma at 14000 {
@@ -414,6 +491,8 @@
 		#address-cells = <3>;
 		#size-cells = <2>;
 		#interrupt-cells = <1>;
+		clocks = <&clks MPC512x_CLK_PCI>;
+		clock-names = "per";
 
 		reg = <0x80008500 0x100	/* internal registers */
 		       0x80008300 0x8>;	/* config space access registers */
Signature · 1 line
1.7.10.4
#24 lore raw

PATCH 11/24 net: can: mscan: add a comment on reg to idx mapping

In reply to Gerhard Sittig

add a comment about the magic of deriving an MSCAN component index from the peripheral's physical address / register offset

---
 drivers/net/can/mscan/mpc5xxx_can.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/can/mscan/mpc5xxx_can.c +4 -1
index 5b0ee8e..bc422ba 100644
@@ -148,7 +148,10 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		goto exit_put;
 	}
 
-	/* Determine the MSCAN device index from the physical address */
+	/* Determine the MSCAN device index from the peripheral's
+	 * physical address. Register address offsets against the
+	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
+	 */
 	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
 	BUG_ON(!pval || plen < sizeof(*pval));
 	clockidx = (*pval & 0x80) ? 1 : 0;
Signature · 1 line
1.7.10.4
#25 lore raw

PATCH 12/24 net: can: mscan: make mpc512x code use common clock

In reply to Gerhard Sittig

extend the mscan(4) driver with alternative support for the COMMON_CLK approach which is an option in the MPC512x platform, keep the existing clock support implementation in place since the driver is shared with other MPC5xxx SoCs which don't have common clock support

one byproduct of this change is that the CAN driver no longer needs to access the SoC's clock control registers, which shall be the domain of the platform's clock driver

---
 drivers/net/can/mscan/mpc5xxx_can.c |  139 +++++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)
drivers/net/can/mscan/mpc5xxx_can.c +139 -0
index bc422ba..dd26ab6 100644
@@ -108,6 +108,143 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
+
+#if IS_ENABLED(CONFIG_COMMON_CLK)
+
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+				 const char *clock_source, int *mscan_clksrc)
+{
+	struct device_node *np;
+	u32 clockdiv;
+	enum {
+		CLK_FROM_AUTO,
+		CLK_FROM_IPS,
+		CLK_FROM_SYS,
+		CLK_FROM_REF,
+	} clk_from;
+	struct clk *clk_in, *clk_can;
+	unsigned long freq_calc;
+
+	/* the caller passed in the clock source spec that was read from
+	 * the device tree, get the optional clock divider as well
+	 */
+	np = ofdev->dev.of_node;
+	clockdiv = 1;
+	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+		clock_source ? clock_source : "<NULL>", clockdiv);
+
+	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+	 * get set, and the 'ips' clock is the input to the MSCAN
+	 * component
+	 *
+	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+	 * bit needs to get cleared, an optional clock-divider may have
+	 * been specified (the default value is 1), the appropriate
+	 * MSCAN related MCLK is the input to the MSCAN component
+	 *
+	 * in the absence of a clock-source spec, first an optimal clock
+	 * gets determined based on the 'sys' clock, if that fails the
+	 * 'ref' clock is used
+	 */
+	clk_from = CLK_FROM_AUTO;
+	if (clock_source) {
+		/* interpret the device tree's spec for the clock source */
+		if (!strcmp(clock_source, "ip"))
+			clk_from = CLK_FROM_IPS;
+		else if (!strcmp(clock_source, "sys"))
+			clk_from = CLK_FROM_SYS;
+		else if (!strcmp(clock_source, "ref"))
+			clk_from = CLK_FROM_REF;
+		else
+			goto err_invalid;
+		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, try the 'sys' clock; round to the
+		 * next MHz and see if we can get a multiple of 16MHz
+		 */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+		clk_in = clk_get(&ofdev->dev, "sys");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc +=  499999;
+		freq_calc /= 1000000;
+		freq_calc *= 1000000;
+		if ((freq_calc % 16000000) == 0) {
+			clk_from = CLK_FROM_SYS;
+			clockdiv = freq_calc / 16000000;
+			dev_dbg(&ofdev->dev,
+				"clk fit, sys[%lu] div[%d] freq[%lu]\n",
+				freq_calc, clockdiv, freq_calc / clockdiv);
+		}
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, use the 'ref' clock */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+		clk_in = clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_from = CLK_FROM_REF;
+		freq_calc = clk_get_rate(clk_in);
+		dev_dbg(&ofdev->dev,
+			"clk fit, ref[%lu] (no div) freq[%lu]\n",
+			freq_calc, freq_calc);
+	}
+
+	/* select IPS or MCLK as the MSCAN input (returned to the caller),
+	 * setup the MCLK mux source and rate if applicable, apply the
+	 * optionally specified or derived above divider, and determine
+	 * the actual resulting clock rate to return to the caller
+	 */
+	switch (clk_from) {
+	case CLK_FROM_IPS:
+		clk_can = clk_get(&ofdev->dev, "ips");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_IPS;
+		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	case CLK_FROM_SYS:
+	case CLK_FROM_REF:
+		clk_can = clk_get(&ofdev->dev, "mclk");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);
+		if (clk_from == CLK_FROM_SYS)
+			clk_in = clk_get(&ofdev->dev, "sys");
+		if (clk_from == CLK_FROM_REF)
+			clk_in = clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_set_parent(clk_can, clk_in);
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc /= clockdiv;
+		clk_set_rate(clk_can, freq_calc);
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_BUS;
+		dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	default:
+		goto err_invalid;
+	}
+
+	return freq_calc;
+
+err_invalid:
+	dev_err(&ofdev->dev, "invalid clock source specification\n");
+	return 0;
+
+err_notavail:
+	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
+	return 0;
+}
+#else	/* COMMON_CLK */
 struct mpc512x_clockctl {
 	u32 spmr;		/* System PLL Mode Reg */
 	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
@@ -238,6 +375,8 @@ exit_put:
 	of_node_put(np_clock);
 	return freq;
 }
+#endif	/* COMMON_CLK */
+
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
Signature · 1 line
1.7.10.4
#26 lore raw

PATCH 13/24 spi: mpc512x: OF clock lookup, use the 'mclk' name

In reply to Gerhard Sittig

after PSC related clock specifiers were added to the device tree, the former 'psc%d_mclk' isn't needed any longer to lookup clock items

---
 drivers/spi/spi-mpc512x-psc.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/spi/spi-mpc512x-psc.c +1 -3
index 76b20ea..3e30e52 100644
@@ -388,13 +388,11 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
 	struct clk *spiclk;
 	int ret = 0;
-	char name[32];
 	u32 sicr;
 	u32 ccr;
 	u16 bclkdiv;
 
-	sprintf(name, "psc%d_mclk", master->bus_num);
-	spiclk = clk_get(&master->dev, name);
+	spiclk = clk_get(&master->dev, "mclk");
 	clk_prepare_enable(spiclk);
 	mps->mclk = clk_get_rate(spiclk);
 	clk_put(spiclk);
Signature · 1 line
1.7.10.4
#27 lore raw

PATCH 14/24 powerpc/mpc512x: improve DIU related clock setup

In reply to Gerhard Sittig

adapt the DIU clock initialization to the COMMON_CLK approach: device tree based clock lookup, prepare and unprepare for clocks, work with frequencies not dividers, call the appropriate clk_*() routines and don't access CCM registers, remove the pre-enable workaround in the platform's clock driver

the "best clock" determination now completely relies on the platform's clock driver to pick a frequency close to what the caller requests, and merely checks whether the desired frequency was met (is acceptable since it meets the tolerance of the monitor) -- this approach shall succeed upon first try in the usual case, will test a few less desirable yet acceptable frequencies in edge cases, and will fallback to "best effort" if none of the previously tried frequencies pass the test

---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 arch/powerpc/platforms/512x/mpc512x_shared.c  |  165 +++++++++++++------------
 2 files changed, 88 insertions(+), 78 deletions(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -1
index 218f55b..f31f895 100644
@@ -705,7 +705,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
-	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
 	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
 	/*
 	 * some have their individual clock subtree with separate clock
arch/powerpc/platforms/512x/mpc512x_shared.c +88 -77

192 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#28 lore raw

PATCH 15/24 serial: mpc512x: OF clock lookup, use the 'mclk' name

In reply to Gerhard Sittig

with device tree based clock lookup, the MCLK name no longer depends on the PSC index

---
 drivers/tty/serial/mpc52xx_uart.c |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/tty/serial/mpc52xx_uart.c +2 -6
index 53c1093..221fb89 100644
@@ -619,21 +619,17 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
 static int mpc512x_psc_clock(struct uart_port *port, int enable)
 {
 	struct clk *psc_clk;
-	int psc_num;
-	char clk_name[10];
 
 	if (uart_console(port))
 		return 0;
 
-	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	psc_clk = clk_get(port->dev, clk_name);
+	psc_clk = clk_get(port->dev, "mclk");
 	if (IS_ERR(psc_clk)) {
 		dev_err(port->dev, "Failed to get PSC clock entry!\n");
 		return -ENODEV;
 	}
 
-	dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
+	dev_dbg(port->dev, "mclk %sable\n", enable ? "en" : "dis");
 
 	if (enable)
 		clk_prepare_enable(psc_clk);
Signature · 1 line
1.7.10.4
#29 lore raw

PATCH 15/24 serial: mpc512x: OF clock lookup, use the 'mclk' name

Quoted 16 lines · Gerhard Sittig

with device tree based clock lookup, the MCLK name no longer depends on the PSC index

---
 drivers/tty/serial/mpc52xx_uart.c |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/tty/serial/mpc52xx_uart.c +0 -0
index 53c1093..221fb89 100644
@@ -619,21 +619,17 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
 static int mpc512x_psc_clock(struct uart_port *port, int enable)
 {
 	struct clk *psc_clk;

drivers/tty/serial/mpc52xx_uart.c static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) · line 626

Quoted 10 lines
drivers/tty/serial/mpc52xx_uart.c +1 -5
-	int psc_num;
-	char clk_name[10];
 
 	if (uart_console(port))
 		return 0;
 
-	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	psc_clk = clk_get(port->dev, clk_name);
+	psc_clk = clk_get(port->dev, "mclk");

Same comment applies here as Mark made to the spi driver.

Sascha

Signature · 4 lines
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
#30 lore raw

PATCH 15/24 serial: mpc512x: OF clock lookup, use the 'mclk' name

Quoted 24 lines · Sascha Hauer
Quoted 22 lines · Gerhard Sittig

with device tree based clock lookup, the MCLK name no longer depends on the PSC index

---
 drivers/tty/serial/mpc52xx_uart.c |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/tty/serial/mpc52xx_uart.c +0 -2
index 53c1093..221fb89 100644
@@ -619,21 +619,17 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
 static int mpc512x_psc_clock(struct uart_port *port, int enable)
 {
 	struct clk *psc_clk;
-	int psc_num;
-	char clk_name[10];
 
 	if (uart_console(port))
 		return 0;
 
Quoted 6 lines

drivers/tty/serial/mpc52xx_uart.c static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) · line 626

Quoted 4 lines
drivers/tty/serial/mpc52xx_uart.c +1 -3
-	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	psc_clk = clk_get(port->dev, clk_name);
+	psc_clk = clk_get(port->dev, "mclk");

Same comment applies here as Mark made to the spi driver.

So I'd like to respond in the same way as I did for the SPI driver. :)

The scope of this series is the introduction of support for the common clock framework. Addressing other (legacy non-fatal and previously accepted) issues as they get identified in bypassing would be the scope of a separate patch or series.

I'm not questioning the need to fix other additionally identified issues. I'm just asking whether they shall be in the scope of this very series.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#31 lore raw

PATCH 16/24 clk: mpc512x: remove now obsolete clkdev registration

In reply to Gerhard Sittig

after the PSC drivers for UART and SPI mode got converted to device tree based clock lookup, the former MCLK name which depends on the PSC index isn't needed any longer -- remove the clk_register_clkdev() invocation

---
 arch/powerpc/platforms/512x/clock-commonclk.c |   10 ----------
 1 file changed, 10 deletions(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -10
index f31f895..31707b5 100644
@@ -529,16 +529,6 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
 				entry->name_mclk,
 				entry->name_mux1, 1, 1);
 	}
-
-	/*
-	 * without this "clock device" registration, "simple" lookups in
-	 * the SPI master initialization and serial port setup will fail
-	 *
-	 * those drivers need to get adjusted to lookup their required
-	 * clocks from OF specs, before this clkdev registration becomes
-	 * obsolete
-	 */
-	clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
 }
 
 static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
Signature · 1 line
1.7.10.4
#32 lore raw

PATCH 17/24 serial: mpc512x: setup the PSC FIFO clock as well

In reply to Gerhard Sittig

prepare and enable the FIFO clock upon PSC FIFO initialization, disable and unprepare the FIFO clock upon PSC FIFO uninitialization, remove the pre-enable workaround from the platform's clock driver

---
 arch/powerpc/platforms/512x/clock-commonclk.c |    2 --
 drivers/tty/serial/mpc52xx_uart.c             |   47 +++++++++++++++++++++----
 2 files changed, 41 insertions(+), 8 deletions(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -2
index 31707b5..2c6da07 100644
@@ -690,8 +690,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
 	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
 	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
-	/* some are required yet no dependencies were declared */
-	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
drivers/tty/serial/mpc52xx_uart.c +41 -6

76 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#33 lore raw

PATCH 18/24 i2c: mpc: OF clock lookup for MPC512x

In reply to Gerhard Sittig

make the MPC I2C driver prepare and enable the peripheral clock ('per' for register access) in the MPC512x setup routine, make this clock setup non-fatal to allow for a migration period, remove the pre-enabling hack in the platform's clock driver

---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 drivers/i2c/busses/i2c-mpc.c                  |    9 +++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -1
index 2c6da07..29c51a5 100644
@@ -693,7 +693,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
-	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
drivers/i2c/busses/i2c-mpc.c +9 -0
index 7607dc0..13d6822 100644
@@ -21,6 +21,7 @@
 #include <linux/of_i2c.h>
 #include <linux/slab.h>
 
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/fsl_devices.h>
 #include <linux/i2c.h>
@@ -264,11 +265,19 @@ static void mpc_i2c_setup_512x(struct device_node *node,
 					 struct mpc_i2c *i2c,
 					 u32 clock, u32 prescaler)
 {
+	struct clk *clk;
 	struct device_node *node_ctrl;
 	void __iomem *ctrl;
 	const u32 *pval;
 	u32 idx;
 
+	/* enable clock for the I2C peripheral (non fatal) */
+	clk = of_clk_get_by_name(node, "per");
+	if (!IS_ERR(clk)) {
+		clk_prepare_enable(clk);
+		clk_put(clk);
+	}
+
 	/* Enable I2C interrupts for mpc5121 */
 	node_ctrl = of_find_compatible_node(NULL, NULL,
 					    "fsl,mpc5121-i2c-ctrl");
Signature · 1 line
1.7.10.4
#34 lore raw

PATCH 19/24 USB: fsl-mph-dr-of: OF clock lookup, prepare and enable

In reply to Gerhard Sittig

device tree based clock lookup in the MPC512x initialization (lookup 'per' for register access), add error check in the clock setup, must prepare clocks before they can get enabled, unprepare after disable

---
 drivers/usb/host/fsl-mph-dr-of.c |   24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)
drivers/usb/host/fsl-mph-dr-of.c +9 -15
index 11e0b79..eb564f3 100644
@@ -260,25 +260,19 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 	struct clk *clk;
-	char clk_name[10];
-	int base, clk_num;
-
-	base = pdev->resource->start & 0xf000;
-	if (base == 0x3000)
-		clk_num = 1;
-	else if (base == 0x4000)
-		clk_num = 2;
-	else
-		return -ENODEV;
+	int err;
 
-	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
-	clk = clk_get(&pdev->dev, clk_name);
+	clk = clk_get(&pdev->dev, "per");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clk\n");
 		return PTR_ERR(clk);
 	}
-
-	clk_enable(clk);
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(&pdev->dev, "failed to enable clk\n");
+		clk_put(clk);
+		return err;
+	}
 	pdata->clk = clk;
 
 	if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
@@ -303,7 +297,7 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
 	pdata->regs = NULL;
 
 	if (pdata->clk) {
-		clk_disable(pdata->clk);
+		clk_disable_unprepare(pdata->clk);
 		clk_put(pdata->clk);
 	}
 }
Signature · 1 line
1.7.10.4
#35 lore raw

PATCH 20/24 fs_enet: OF clock lookup (non-fatal), prepare and enable

In reply to Gerhard Sittig

device tree based clock lookup, must prepare clocks before enabling them, unprepare after disable, error check in the clock setup, remove the pre-enable workaround in the MPC512x platform's clock driver

this change implements non-fatal clock lookup since not all platforms provide device tree specs for clocks, but failure to enable a specified clock is considered fatal

---
 arch/powerpc/platforms/512x/clock-commonclk.c      |    1 -
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   27 +++++++++++++++++++-
 include/linux/fs_enet_pd.h                         |    3 +++
 3 files changed, 29 insertions(+), 2 deletions(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -1
index 29c51a5..31d0cf3 100644
@@ -692,7 +692,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
-	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +26 -1
index 8de53a1..df92e12 100644
@@ -1020,6 +1020,21 @@ static int fs_enet_probe(struct platform_device *ofdev)
 		fpi->cp_command = *data;
 	}
 
+	/* make clock lookup non-fatal (the driver is shared among platforms),
+	 * but require enable to succeed when a clock was specified/found
+	 */
+	fpi->clk_per = clk_get(&ofdev->dev, "per");
+	if (IS_ERR(fpi->clk_per))
+		fpi->clk_per = NULL;
+	if (fpi->clk_per) {
+		int err;
+		err = clk_prepare_enable(fpi->clk_per);
+		if (err) {
+			ret = err;
+			goto out_clk_put;
+		}
+	}
+
 	fpi->rx_ring = 32;
 	fpi->tx_ring = 32;
 	fpi->rx_copybreak = 240;
@@ -1028,7 +1043,7 @@ static int fs_enet_probe(struct platform_device *ofdev)
 	fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0);
 	if ((!fpi->phy_node) && (!of_get_property(ofdev->dev.of_node, "fixed-link",
 						  NULL)))
-		goto out_free_fpi;
+		goto out_clk_dis;
 
 	if (of_device_is_compatible(ofdev->dev.of_node, "fsl,mpc5125-fec")) {
 		phy_connection_type = of_get_property(ofdev->dev.of_node,
@@ -1108,6 +1123,12 @@ out_free_dev:
 	free_netdev(ndev);
 out_put:
 	of_node_put(fpi->phy_node);
+out_clk_dis:
+	if (fpi->clk_per)
+		clk_disable_unprepare(fpi->clk_per);
+out_clk_put:
+	if (fpi->clk_per)
+		clk_put(fpi->clk_per);
 out_free_fpi:
 	kfree(fpi);
 	return ret;
@@ -1124,6 +1145,10 @@ static int fs_enet_remove(struct platform_device *ofdev)
 	fep->ops->cleanup_data(ndev);
 	dev_set_drvdata(fep->dev, NULL);
 	of_node_put(fep->fpi->phy_node);
+	if (fep->fpi->clk_per) {
+		clk_disable_unprepare(fep->fpi->clk_per);
+		clk_put(fep->fpi->clk_per);
+	}
 	free_netdev(ndev);
 	return 0;
 }
include/linux/fs_enet_pd.h +3 -0
index 51b7934..a978d0d 100644
@@ -16,6 +16,7 @@
 #ifndef FS_ENET_PD_H
 #define FS_ENET_PD_H
 
+#include <linux/clk.h>
 #include <linux/string.h>
 #include <linux/of_mdio.h>
 #include <asm/types.h>
@@ -142,6 +143,8 @@ struct fs_platform_info {
 
 	int use_rmii;		/* use RMII mode 	       */
 	int has_phy;            /* if the network is phy container as well...*/
+
+	struct clk *clk_per;	/* 'per' clock for register access */
 };
 struct fs_mii_fec_platform_info {
 	u32 irq[32];
Signature · 1 line
1.7.10.4
#36 lore raw

PATCH 21/24 fsl-viu: OF clock lookup, prepare before enable

In reply to Gerhard Sittig

device tree based clock lookup, must prepare clocks before enabling them, unprepare after disable, error check in the clock setup

---
 drivers/media/platform/fsl-viu.c |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/media/platform/fsl-viu.c +8 -4
index 221ec42..b95aa43 100644
@@ -1582,8 +1582,11 @@ static int viu_of_probe(struct platform_device *op)
 		dev_err(&op->dev, "failed to find the clock module!\n");
 		ret = -ENODEV;
 		goto err_clk;
-	} else {
-		clk_enable(viu_dev->clk);
+	}
+	ret = clk_prepare_enable(viu_dev->clk);
+	if (ret) {
+		dev_err(&op->dev, "failed to enable the clock!\n");
+		goto err_clk_put;
 	}
 
 	/* reset VIU module */
@@ -1602,7 +1605,8 @@ static int viu_of_probe(struct platform_device *op)
 	return ret;
 
 err_irq:
-	clk_disable(viu_dev->clk);
+	clk_disable_unprepare(viu_dev->clk);
+err_clk_put:
 	clk_put(viu_dev->clk);
 err_clk:
 	video_unregister_device(viu_dev->vdev);
@@ -1626,7 +1630,7 @@ static int viu_of_remove(struct platform_device *op)
 	free_irq(dev->irq, (void *)dev);
 	irq_dispose_mapping(dev->irq);
 
-	clk_disable(dev->clk);
+	clk_disable_unprepare(dev->clk);
 	clk_put(dev->clk);
 
 	video_unregister_device(dev->vdev);
Signature · 1 line
1.7.10.4
#37 lore raw

PATCH 22/24 powerpc/fsl-pci: OF clock lookup, prepare before enable

In reply to Gerhard Sittig

device tree based clock lookup, must prepare clocks before enabling them, error check in the clock setup

this change implements non-fatal clock lookup for compatibility with platforms that don't provide OF clock specs, but failure to enable a specified clock is considered fatal

---
 arch/powerpc/sysdev/fsl_pci.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/powerpc/sysdev/fsl_pci.c +15 -0
index 46ac1dd..cb2ed92 100644
@@ -17,6 +17,8 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
+
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -741,6 +743,7 @@ err0:
 
 int __init mpc83xx_add_bridge(struct device_node *dev)
 {
+	struct clk *clk;
 	int ret;
 	int len;
 	struct pci_controller *hose;
@@ -758,6 +761,18 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
 	}
 	pr_debug("Adding PCI host bridge %s\n", dev->full_name);
 
+	/* non-fatal OF clock lookup, but fatal when a clock
+	 * was specified yet could not get enabled */
+	clk = of_clk_get_by_name(dev, "per");
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		clk_put(clk);
+		if (ret) {
+			pr_err("Could not enable peripheral clock\n");
+			return ret;
+		}
+	}
+
 	/* Fetch host bridge registers address */
 	if (of_address_to_resource(dev, 0, &rsrc_reg)) {
 		printk(KERN_WARNING "Can't get pci register base!\n");
Signature · 1 line
1.7.10.4
#38 lore raw

PATCH 23/24 clk: mpc512x: switch to COMMON_CLK, remove PPC_CLOCK

In reply to Gerhard Sittig

completely switch to, i.e. unconditionally use COMMON_CLK for the MPC512x platform, and retire the PPC_CLOCK implementation for that platform after the transition has completed

---
 arch/powerpc/platforms/512x/Kconfig  |   14 +-
 arch/powerpc/platforms/512x/Makefile |    3 +-
 arch/powerpc/platforms/512x/clock.c  |  753 ----------------------------------
 3 files changed, 2 insertions(+), 768 deletions(-)
 delete mode 100644 arch/powerpc/platforms/512x/clock.c
arch/powerpc/platforms/512x/Kconfig +1 -13
index c5fcdd0..5aa3f4b 100644
@@ -1,21 +1,9 @@
-config MPC512x_COMMON_CLK
-	bool "MPC512x platform uses COMMON_CLK"
-	default y
-	depends on PPC_MPC512x
-	help
-	  This option is only here to support tests and comparison
-	  during development and migration.  This option will get
-	  removed after the COMMON_CLK support for MPC512x has become
-	  fully operational and all drivers were adjusted to explicitly
-	  acquire their required clocks.
-
 config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
+	select COMMON_CLK
 	select FSL_SOC
 	select IPIC
-	select PPC_CLOCK if !MPC512x_COMMON_CLK
-	select COMMON_CLK if MPC512x_COMMON_CLK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
arch/powerpc/platforms/512x/Makefile +1 -2
index 1e05f9d..bb20116 100644
@@ -1,8 +1,7 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-$(CONFIG_PPC_CLOCK)		+= clock.o
-obj-$(CONFIG_COMMON_CLK)	+= clock-commonclk.o
+obj-y				+= clock-commonclk.o
 obj-y				+= mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)	+= mpc512x_generic.o
arch/powerpc/platforms/512x/clock.c deleted +0 -753

753 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#39 lore raw

PATCH 24/24 net: can: mscan: remove MPC512x non-COMMON_CLK code path

In reply to Gerhard Sittig

transition to the COMMON_CLK framework has completed for the MPC512x platform, remove the now obsolete code path of the mpc5xxx mscan driver which accessed clock control module registers directly

---
 drivers/net/can/mscan/mpc5xxx_can.c |  136 -----------------------------------
 1 file changed, 136 deletions(-)
drivers/net/can/mscan/mpc5xxx_can.c +0 -136
index dd26ab6..cf5e4cfc 100644
@@ -108,9 +108,6 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
-
-#if IS_ENABLED(CONFIG_COMMON_CLK)
-
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_source, int *mscan_clksrc)
 {
@@ -244,139 +241,6 @@ err_notavail:
 	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
 	return 0;
 }
-#else	/* COMMON_CLK */
-struct mpc512x_clockctl {
-	u32 spmr;		/* System PLL Mode Reg */
-	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
-	u32 scfr1;		/* System Clk Freq Reg 1 */
-	u32 scfr2;		/* System Clk Freq Reg 2 */
-	u32 reserved;
-	u32 bcr;		/* Bread Crumb Reg */
-	u32 pccr[12];		/* PSC Clk Ctrl Reg 0-11 */
-	u32 spccr;		/* SPDIF Clk Ctrl Reg */
-	u32 cccr;		/* CFM Clk Ctrl Reg */
-	u32 dccr;		/* DIU Clk Cnfg Reg */
-	u32 mccr[4];		/* MSCAN Clk Ctrl Reg 1-3 */
-};
-
-static struct of_device_id mpc512x_clock_ids[] = {
-	{ .compatible = "fsl,mpc5121-clock", },
-	{}
-};
-
-static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
-				 const char *clock_name, int *mscan_clksrc)
-{
-	struct mpc512x_clockctl __iomem *clockctl;
-	struct device_node *np_clock;
-	struct clk *sys_clk, *ref_clk;
-	int plen, clockidx, clocksrc = -1;
-	u32 sys_freq, val, clockdiv = 1, freq = 0;
-	const u32 *pval;
-
-	np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
-	if (!np_clock) {
-		dev_err(&ofdev->dev, "couldn't find clock node\n");
-		return 0;
-	}
-	clockctl = of_iomap(np_clock, 0);
-	if (!clockctl) {
-		dev_err(&ofdev->dev, "couldn't map clock registers\n");
-		goto exit_put;
-	}
-
-	/* Determine the MSCAN device index from the peripheral's
-	 * physical address. Register address offsets against the
-	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
-	 */
-	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
-	BUG_ON(!pval || plen < sizeof(*pval));
-	clockidx = (*pval & 0x80) ? 1 : 0;
-	if (*pval & 0x2000)
-		clockidx += 2;
-
-	/*
-	 * Clock source and divider selection: 3 different clock sources
-	 * can be selected: "ip", "ref" or "sys". For the latter two, a
-	 * clock divider can be defined as well. If the clock source is
-	 * not specified by the device tree, we first try to find an
-	 * optimal CAN source clock based on the system clock. If that
-	 * is not posslible, the reference clock will be used.
-	 */
-	if (clock_name && !strcmp(clock_name, "ip")) {
-		*mscan_clksrc = MSCAN_CLKSRC_IPS;
-		freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
-	} else {
-		*mscan_clksrc = MSCAN_CLKSRC_BUS;
-
-		pval = of_get_property(ofdev->dev.of_node,
-				       "fsl,mscan-clock-divider", &plen);
-		if (pval && plen == sizeof(*pval))
-			clockdiv = *pval;
-		if (!clockdiv)
-			clockdiv = 1;
-
-		if (!clock_name || !strcmp(clock_name, "sys")) {
-			sys_clk = clk_get(&ofdev->dev, "sys_clk");
-			if (IS_ERR(sys_clk)) {
-				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
-				goto exit_unmap;
-			}
-			/* Get and round up/down sys clock rate */
-			sys_freq = 1000000 *
-				((clk_get_rate(sys_clk) + 499999) / 1000000);
-
-			if (!clock_name) {
-				/* A multiple of 16 MHz would be optimal */
-				if ((sys_freq % 16000000) == 0) {
-					clocksrc = 0;
-					clockdiv = sys_freq / 16000000;
-					freq = sys_freq / clockdiv;
-				}
-			} else {
-				clocksrc = 0;
-				freq = sys_freq / clockdiv;
-			}
-		}
-
-		if (clocksrc < 0) {
-			ref_clk = clk_get(&ofdev->dev, "ref_clk");
-			if (IS_ERR(ref_clk)) {
-				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
-				goto exit_unmap;
-			}
-			clocksrc = 1;
-			freq = clk_get_rate(ref_clk) / clockdiv;
-		}
-	}
-
-	/* Disable clock */
-	out_be32(&clockctl->mccr[clockidx], 0x0);
-	if (clocksrc >= 0) {
-		/* Set source and divider */
-		val = (clocksrc << 14) | ((clockdiv - 1) << 17);
-		out_be32(&clockctl->mccr[clockidx], val);
-		/* Enable clock */
-		out_be32(&clockctl->mccr[clockidx], val | 0x10000);
-	}
-
-	/* Enable MSCAN clock domain */
-	val = in_be32(&clockctl->sccr[1]);
-	if (!(val & (1 << 25)))
-		out_be32(&clockctl->sccr[1], val | (1 << 25));
-
-	dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
-		*mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
-		clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
-
-exit_unmap:
-	iounmap(clockctl);
-exit_put:
-	of_node_put(np_clock);
-	return freq;
-}
-#endif	/* COMMON_CLK */
-
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
Signature · 1 line
1.7.10.4
#40 lore raw

v2 cover add COMMON_CLK support for PowerPC MPC512x

In reply to Gerhard Sittig

this series introduces support for the common clock framework (CCF, COMMON_CLK Kconfig option) in the PowerPC based MPC512x platform

although the series does touch several subsystems -- serial, spi, net (can, fs_enet), mtd (nfc), usb, i2c, media (viu), and dts -- all of the patches are strictly clock related

it appears most appropriate to take this series through either the clk or the powerpc trees after it has passed review and other subsystem maintainers ACKed the clock setup related driver modifications

the series passes 'checkpatch.pl --strict' except for one warning which cannot get resolved, since that either breaks compilation (the data type is preset by the clk-provider.h API) or requires a cast which shadows real mismatches:

WARNING: static const char * array should probably be static const char * const #413: FILE: arch/powerpc/platforms/512x/clock-commonclk.c:335:
+static const char *parent_names_mux0[] = {

total: 0 errors, 1 warnings, 0 checks, 836 lines checked

each step in the series was build and run tested (with a display that is attached to the DIU as well as SPI, with an SPI attached NOR flash, with multiple UART ports such that one is not the boot console, with EEPROMs attached to I2C, with an SD card, booting from network)

changes in v2:
- cleanup of the UART and SPI clock handling before the introduction of common clock support for the platform, as incomplete clock handling becomes fatal or more dangerous later (which in turn changes the context of the "device tree lookup only" followup patch later)
- reordered the sequence of patches to keep the serial communication related parts together (UART, SPI, and PSC FIFO changes after common clock support was introduced)
- updated commit messages for the clock API use cleanup in the serial communication drivers, updated comments and reworded commit messages in the core clock driver to expand on the pre-enable workaround and clkdev registration
- keep a reference to the PSC FIFO clock during use instead of looking up the clock again in the uninit() routine
- remove the clkdev.h header file inclusion directive with the removal of the clkdev registration call

Gerhard Sittig (24):
spi: mpc512x: cleanup clock API use
serial: mpc512x: cleanup clock API use
mtd: mpc5121_nfc: prepare clocks before enabling them
powerpc: mpc512x: array decl for MCLK registers in CCM
clk: wrap I/O access for improved portability
dts: mpc512x: prepare for preprocessor support
dts: mpc512x: introduce dt-bindings/clock/ header
dts: mpc512x: add clock related device tree specs
clk: mpc512x: introduce COMMON_CLK for MPC512x
dts: mpc512x: add clock specs for client lookups
spi: mpc512x: remove now obsolete clock lookup name
serial: mpc512x: remove now obsolete clock lookup name
clk: mpc512x: remove now obsolete clkdev registration
serial: mpc512x: setup the PSC FIFO clock as well
net: can: mscan: add a comment on reg to idx mapping
net: can: mscan: make mpc512x code use common clock powerpc/mpc512x: improve DIU related clock setup
i2c: mpc: OF clock lookup for MPC512x
USB: fsl-mph-dr-of: OF clock lookup, prepare and enable
fs_enet: OF clock lookup (non-fatal), prepare and enable [media] fsl-viu: OF clock lookup, prepare before enable powerpc/fsl-pci: OF clock lookup, prepare before enable
clk: mpc512x: switch to COMMON_CLK, remove PPC_CLOCK
net: can: mscan: remove MPC512x non-COMMON_CLK code path

 arch/powerpc/boot/dts/ac14xx.dts                   |    9 +-
 arch/powerpc/boot/dts/include/dt-bindings          |    1 +
 arch/powerpc/boot/dts/mpc5121.dtsi                 |   94 ++-
 arch/powerpc/boot/dts/mpc5121ads.dts               |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts                 |    2 +-
 arch/powerpc/include/asm/mpc5121.h                 |   18 +-
 arch/powerpc/platforms/512x/Kconfig                |    2 +-
 arch/powerpc/platforms/512x/Makefile               |    3 +-
 arch/powerpc/platforms/512x/clock-commonclk.c      |  761 ++++++++++++++++++++
 arch/powerpc/platforms/512x/clock.c                |  753 -------------------
 arch/powerpc/platforms/512x/mpc512x_shared.c       |  165 +++--
 arch/powerpc/sysdev/fsl_pci.c                      |   15 +
 drivers/clk/clk-divider.c                          |    6 +-
 drivers/clk/clk-gate.c                             |    6 +-
 drivers/clk/clk-mux.c                              |    6 +-
 drivers/i2c/busses/i2c-mpc.c                       |    9 +
 drivers/media/platform/fsl-viu.c                   |   12 +-
 drivers/mtd/nand/mpc5121_nfc.c                     |    4 +-
 drivers/net/can/mscan/mpc5xxx_can.c                |  234 +++---
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   27 +-
 drivers/spi/spi-mpc512x-psc.c                      |   45 +-
 drivers/tty/serial/mpc52xx_uart.c                  |  137 +++-
 drivers/usb/host/fsl-mph-dr-of.c                   |   24 +-
 include/dt-bindings/clock/mpc512x-clock.h          |   59 ++
 include/linux/clk-provider.h                       |   33 +
 include/linux/fs_enet_pd.h                         |    3 +
 26 files changed, 1392 insertions(+), 1038 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
 delete mode 100644 arch/powerpc/platforms/512x/clock.c
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
# uname -srm
Linux 3.11.0-rc1-00024-g96ff9fe ppc
# cat /sys/kernel/debug/clk/clk_summary
   clock                        enable_cnt  prepare_cnt  rate
---------------------------------------------------------------------
 ac97                           0           0            24567000
 spdif_rx_in                    0           0            0
 spdif_tx_in                    0           0            0
 psc_mclk_in                    0           0            25000000
 dummy                          1           1            0
 osc                            1           1            25000000
    ref                         1           1            25000000
       sys                      10          10           320000000
          spdif-mux0            0           0            320000000
             spdif-en0          0           0            320000000
                spdif_mclk_div  0           0            80000000
                   spdif_mclk_out 0           0            80000000
                      spdif_mclk 0           0            80000000
          mscan3-mux0           1           1            320000000
             mscan3-en0         1           1            320000000
                mscan3_mclk_div 1           1            80000000
                   mscan3_mclk_out 1           1            80000000
                      mscan3_mclk 1           1            80000000
          mscan2-mux0           1           1            320000000
             mscan2-en0         1           1            320000000
                mscan2_mclk_div 1           1            80000000
                   mscan2_mclk_out 1           1            80000000
                      mscan2_mclk 1           1            80000000
          mscan1-mux0           1           1            320000000
             mscan1-en0         1           1            320000000
                mscan1_mclk_div 1           1            16000000
                   mscan1_mclk_out 1           1            16000000
                      mscan1_mclk 2           2            16000000
          mscan0-mux0           1           1            320000000
             mscan0-en0         1           1            320000000
                mscan0_mclk_div 1           1            16000000
                   mscan0_mclk_out 1           1            16000000
                      mscan0_mclk 2           2            16000000
          psc11-mux0            0           0            320000000
             psc11-en0          0           0            320000000
                psc11_mclk_div  0           0            80000000
                   psc11_mclk_out 0           0            80000000
                      psc11_mclk 0           0            80000000
          psc10-mux0            0           0            320000000
             psc10-en0          0           0            320000000
                psc10_mclk_div  0           0            80000000
                   psc10_mclk_out 0           0            80000000
                      psc10_mclk 0           0            80000000
          psc9-mux0             0           0            320000000
             psc9-en0           0           0            320000000
                psc9_mclk_div   0           0            80000000
                   psc9_mclk_out 0           0            80000000
                      psc9_mclk 0           0            80000000
          psc8-mux0             0           0            320000000
             psc8-en0           0           0            320000000
                psc8_mclk_div   0           0            80000000
                   psc8_mclk_out 0           0            80000000
                      psc8_mclk 0           0            80000000
          psc7-mux0             1           1            320000000
             psc7-en0           1           1            320000000
                psc7_mclk_div   1           1            80000000
                   psc7_mclk_out 1           1            80000000
                      psc7_mclk 1           1            80000000
          psc6-mux0             0           0            320000000
             psc6-en0           0           0            320000000
                psc6_mclk_div   0           0            80000000
                   psc6_mclk_out 0           0            80000000
                      psc6_mclk 0           0            80000000
          psc5-mux0             1           1            320000000
             psc5-en0           1           1            320000000
                psc5_mclk_div   1           1            80000000
                   psc5_mclk_out 1           1            80000000
                      psc5_mclk 1           1            80000000
          psc4-mux0             1           1            320000000
             psc4-en0           1           1            320000000
                psc4_mclk_div   1           1            80000000
                   psc4_mclk_out 1           1            80000000
                      psc4_mclk 1           1            80000000
          psc3-mux0             1           1            320000000
             psc3-en0           1           1            320000000
                psc3_mclk_div   1           1            80000000
                   psc3_mclk_out 1           1            80000000
                      psc3_mclk 2           2            80000000
          psc2-mux0             0           0            320000000
             psc2-en0           0           0            320000000
                psc2_mclk_div   0           0            80000000
                   psc2_mclk_out 0           0            80000000
                      psc2_mclk 0           0            80000000
          psc1-mux0             0           0            320000000
             psc1-en0           0           0            320000000
                psc1_mclk_div   0           0            80000000
                   psc1_mclk_out 0           0            80000000
                      psc1_mclk 0           0            80000000
          psc0-mux0             0           0            320000000
             psc0-en0           0           0            320000000
                psc0_mclk_div   0           0            80000000
                   psc0_mclk_out 0           0            80000000
                      psc0_mclk 0           0            80000000
          ddr-ug                1           1            160000000
             ddr                1           1            160000000
          csb                   4           4            160000000
             viu                0           0            160000000
             iim                0           0            160000000
             usb2               0           0            160000000
             usb1               0           0            160000000
             axe                0           0            160000000
             pci-ug             0           0            26666666
                pci             0           0            26666666
             mbx-bus-ug         0           0            80000000
                mbx-bus         0           0            80000000
                mbx-ug          0           0            80000000
                   mbx          0           0            80000000
                   mbx-3d-ug    0           0            80000000
                      mbx-3d    0           0            80000000
             e300               1           1            400000000
             diu-x4             1           1            640000000
                diu-ug          1           1            2509803
                   diu          2           2            2509803
             sdhc-x4            1           1            640000000
                sdhc-ug         1           1            53333333
                   sdhc-2       0           0            53333333
                   sdhc         1           1            53333333
             ips                7           7            80000000
                i2c             3           3            80000000
                mem             1           1            80000000
                fec             1           1            80000000
                sata            0           0            80000000
                psc-fifo        1           1            80000000
                pata            0           0            80000000
                lpc-ug          1           1            40000000
                   lpc          1           1            40000000
                nfc-ug          0           0            40000000
                   nfc          0           0            40000000
Signature · 1 line
1.7.10.4
#41 lore raw

PATCH v2 1/24 spi: mpc512x: cleanup clock API use

cleanup the MPC512x SoC's SPI master's use of the clock API
- get, prepare, and enable the MCLK during probe; disable, unprepare and put the MCLK upon remove; hold a reference to the clock over the period of use
- fetch MCLK rate (reference) once during probe and slightly reword BCLK (bitrate) determination to reduce redundancy as well as to not exceed the maximum text line length
- stick with the PPC_CLOCK 'psc%d_mclk' name for clock lookup, only switch to a fixed string later after device tree based clock lookup will have become available

the omission in the clock handling previously went unnoticed, but will become fatal in the common clock scenario

---
 drivers/spi/spi-mpc512x-psc.c |   49 ++++++++++++++++++++++++++---------------
 1 file changed, 31 insertions(+), 18 deletions(-)
drivers/spi/spi-mpc512x-psc.c +31 -18
index 29fce6a..7a32373 100644
@@ -38,7 +38,8 @@ struct mpc512x_psc_spi {
 	struct mpc512x_psc_fifo __iomem *fifo;
 	unsigned int irq;
 	u8 bits_per_word;
-	u32 mclk;
+	struct clk *clk_mclk;
+	u32 mclk_rate;
 
 	struct completion txisrdone;
 };
@@ -72,6 +73,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
 	struct mpc52xx_psc __iomem *psc = mps->psc;
 	u32 sicr;
 	u32 ccr;
+	int speed;
 	u16 bclkdiv;
 
 	sicr = in_be32(&psc->sicr);
@@ -95,10 +97,10 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
 
 	ccr = in_be32(&psc->ccr);
 	ccr &= 0xFF000000;
-	if (cs->speed_hz)
-		bclkdiv = (mps->mclk / cs->speed_hz) - 1;
-	else
-		bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	speed = cs->speed_hz;
+	if (!speed)
+		speed = 1000000;	/* default 1MHz */
+	bclkdiv = (mps->mclk_rate / speed) - 1;
 
 	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
 	out_be32(&psc->ccr, ccr);
@@ -386,19 +388,11 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 {
 	struct mpc52xx_psc __iomem *psc = mps->psc;
 	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
-	struct clk *spiclk;
-	int ret = 0;
-	char name[32];
 	u32 sicr;
 	u32 ccr;
+	int speed;
 	u16 bclkdiv;
 
-	sprintf(name, "psc%d_mclk", master->bus_num);
-	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
-	mps->mclk = clk_get_rate(spiclk);
-	clk_put(spiclk);
-
 	/* Reset the PSC into a known state */
 	out_8(&psc->command, MPC52xx_PSC_RST_RX);
 	out_8(&psc->command, MPC52xx_PSC_RST_TX);
@@ -425,7 +419,8 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
 	ccr = in_be32(&psc->ccr);
 	ccr &= 0xFF000000;
-	bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	speed = 1000000;	/* default 1MHz */
+	bclkdiv = (mps->mclk_rate / speed) - 1;
 	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
 	out_be32(&psc->ccr, ccr);
 
@@ -445,7 +440,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
 	mps->bits_per_word = 8;
 
-	return ret;
+	return 0;
 }
 
 static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
@@ -479,6 +474,8 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 	struct spi_master *master;
 	int ret;
 	void *tempp;
+	int psc_num;
+	char clk_name[16];
 
 	master = spi_alloc_master(dev, sizeof *mps);
 	if (master == NULL)
@@ -521,16 +518,30 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 		goto free_master;
 	init_completion(&mps->txisrdone);
 
+	psc_num = master->bus_num;
+	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+	mps->clk_mclk = clk_get(dev, clk_name);
+	if (IS_ERR(mps->clk_mclk))
+		goto free_irq;
+	ret = clk_prepare_enable(mps->clk_mclk);
+	if (ret)
+		goto free_putclk;
+	mps->mclk_rate = clk_get_rate(mps->clk_mclk);
+
 	ret = mpc512x_psc_spi_port_config(master, mps);
 	if (ret < 0)
-		goto free_irq;
+		goto free_disclk;
 
 	ret = spi_register_master(master);
 	if (ret < 0)
-		goto free_irq;
+		goto free_disclk;
 
 	return ret;
 
+free_disclk:
+	clk_disable_unprepare(mps->clk_mclk);
+free_putclk:
+	clk_put(mps->clk_mclk);
 free_irq:
 	free_irq(mps->irq, mps);
 free_master:
@@ -547,6 +558,8 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
 	struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
 
 	spi_unregister_master(master);
+	clk_disable_unprepare(mps->clk_mclk);
+	clk_put(mps->clk_mclk);
 	free_irq(mps->irq, mps);
 	if (mps->psc)
 		iounmap(mps->psc);
Signature · 1 line
1.7.10.4
maintainer
#42 lore raw

PATCH v2 1/24 spi: mpc512x: cleanup clock API use

drivers/spi/spi-mpc512x-psc.c static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, · line 525

Quoted 5 lines · Gerhard Sittig
drivers/spi/spi-mpc512x-psc.c +5 -0
+	psc_num = master->bus_num;
+	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+	mps->clk_mclk = clk_get(dev, clk_name);
+	if (IS_ERR(mps->clk_mclk))
+		goto free_irq;

Should be using devm_clk_get().
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130718/5428dd8f/attachment.sig>

#43 lore raw

PATCH v2 2/24 serial: mpc512x: cleanup clock API use

In reply to Gerhard Sittig

cleanup the clock API use of the UART driver which is shared among the MPC512x and the MPC5200 platforms
- get, prepare, and enable the MCLK during port allocation; disable, unprepare and put the MCLK upon port release; hold a reference to the clock over the period of use; check for and propagate enable errors
- fix a buffer overflow for clock names with two digit PSC index numbers
- stick with the PPC_CLOCK 'psc%d_mclk' name for clock lookup, only switch to a fixed string later after device tree based clock lookup will have become available

the omission in the clock handling previously went unnoticed, but will become fatal in the common clock scenario

to achieve support for MPC512x which is neutral to MPC5200, the modification was done as follows
- introduce "clock alloc" and "clock release" routines in addition to the previous "clock enable/disable" routine in the psc_ops struct
- make the clock allocation a part of the port request (resource allocation), and make clock release a part of the port release, such that essential resources get allocated early
- just enable/disable the clock from within the .clock() callback without any allocation or preparation as the former implementation did, since this routine is called from within the startup and shutdown callbacks
- all of the above remains a NOP for the MPC5200 platform (no callbacks are provided on that platform)
- implementation note: the clock gets enabled upon allocation already just in case the clock is not only required for bitrate generation but for register access as well

---
 drivers/tty/serial/mpc52xx_uart.c |  100 ++++++++++++++++++++++++++++++-------
 1 file changed, 83 insertions(+), 17 deletions(-)
drivers/tty/serial/mpc52xx_uart.c +83 -17
index e1280a2..98a1f43 100644
@@ -107,6 +107,8 @@ struct psc_ops {
 	unsigned int	(*set_baudrate)(struct uart_port *port,
 					struct ktermios *new,
 					struct ktermios *old);
+	int		(*clock_alloc)(struct uart_port *port);
+	void		(*clock_relse)(struct uart_port *port);
 	int		(*clock)(struct uart_port *port, int enable);
 	int		(*fifoc_init)(void);
 	void		(*fifoc_uninit)(void);
@@ -616,31 +618,75 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
 	return IRQ_NONE;
 }
 
-static int mpc512x_psc_clock(struct uart_port *port, int enable)
+static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
+
+/* called from within the .request_port() callback (allocation) */
+static int mpc512x_psc_alloc_clock(struct uart_port *port)
 {
-	struct clk *psc_clk;
 	int psc_num;
-	char clk_name[10];
+	char clk_name[16];
+	struct clk *clk;
+	int err;
+
+	psc_num = (port->mapbase & 0xf00) >> 8;
+	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+	clk = clk_get(port->dev, clk_name);
+	if (IS_ERR(clk)) {
+		dev_err(port->dev, "Failed to get MCLK!\n");
+		return PTR_ERR(clk);
+	}
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(port->dev, "Failed to enable MCLK!\n");
+		clk_put(clk);
+		return err;
+	}
+	psc_mclk_clk[psc_num] = clk;
+	return 0;
+}
+
+/* called from within the .release_port() callback (release) */
+static void mpc512x_psc_relse_clock(struct uart_port *port)
+{
+	int psc_num;
+	struct clk *clk;
+
+	psc_num = (port->mapbase & 0xf00) >> 8;
+	clk = psc_mclk_clk[psc_num];
+	if (clk) {
+		clk_disable_unprepare(clk);
+		clk_put(clk);
+		psc_mclk_clk[psc_num] = NULL;
+	}
+}
+
+/* implementation of the .clock() callback (enable/disable) */
+static int mpc512x_psc_endis_clock(struct uart_port *port, int enable)
+{
+	int psc_num;
+	struct clk *psc_clk;
+	int ret;
 
 	if (uart_console(port))
 		return 0;
 
 	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	psc_clk = clk_get(port->dev, clk_name);
-	if (IS_ERR(psc_clk)) {
+	psc_clk = psc_mclk_clk[psc_num];
+	if (!psc_clk) {
 		dev_err(port->dev, "Failed to get PSC clock entry!\n");
 		return -ENODEV;
 	}
 
-	dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
-
-	if (enable)
-		clk_enable(psc_clk);
-	else
+	dev_dbg(port->dev, "mclk %sable\n", enable ? "en" : "dis");
+	if (enable) {
+		ret = clk_enable(psc_clk);
+		if (ret)
+			dev_err(port->dev, "Failed to enable MCLK!\n");
+		return ret;
+	} else {
 		clk_disable(psc_clk);
-
-	return 0;
+		return 0;
+	}
 }
 
 static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
@@ -873,7 +919,9 @@ static struct psc_ops mpc5125_psc_ops = {
 	.cw_disable_ints = mpc5125_psc_cw_disable_ints,
 	.cw_restore_ints = mpc5125_psc_cw_restore_ints,
 	.set_baudrate = mpc5125_psc_set_baudrate,
-	.clock = mpc512x_psc_clock,
+	.clock_alloc = mpc512x_psc_alloc_clock,
+	.clock_relse = mpc512x_psc_relse_clock,
+	.clock = mpc512x_psc_endis_clock,
 	.fifoc_init = mpc512x_psc_fifoc_init,
 	.fifoc_uninit = mpc512x_psc_fifoc_uninit,
 	.get_irq = mpc512x_psc_get_irq,
@@ -906,7 +954,9 @@ static struct psc_ops mpc512x_psc_ops = {
 	.cw_disable_ints = mpc512x_psc_cw_disable_ints,
 	.cw_restore_ints = mpc512x_psc_cw_restore_ints,
 	.set_baudrate = mpc512x_psc_set_baudrate,
-	.clock = mpc512x_psc_clock,
+	.clock_alloc = mpc512x_psc_alloc_clock,
+	.clock_relse = mpc512x_psc_relse_clock,
+	.clock = mpc512x_psc_endis_clock,
 	.fifoc_init = mpc512x_psc_fifoc_init,
 	.fifoc_uninit = mpc512x_psc_fifoc_uninit,
 	.get_irq = mpc512x_psc_get_irq,
@@ -1166,6 +1216,9 @@ mpc52xx_uart_type(struct uart_port *port)
 static void
 mpc52xx_uart_release_port(struct uart_port *port)
 {
+	if (psc_ops->clock_relse)
+		psc_ops->clock_relse(port);
+
 	/* remapped by us ? */
 	if (port->flags & UPF_IOREMAP) {
 		iounmap(port->membase);
@@ -1190,11 +1243,24 @@ mpc52xx_uart_request_port(struct uart_port *port)
 	err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
 			"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
 
-	if (err && (port->flags & UPF_IOREMAP)) {
+	if (err)
+		goto out_membase;
+
+	if (psc_ops->clock_alloc) {
+		err = psc_ops->clock_alloc(port);
+		if (err)
+			goto out_mapregion;
+	}
+
+	return 0;
+
+out_mapregion:
+	release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+out_membase:
+	if (port->flags & UPF_IOREMAP) {
 		iounmap(port->membase);
 		port->membase = NULL;
 	}
-
 	return err;
 }
 
Signature · 1 line
1.7.10.4
#44 lore raw

PATCH v2 3/24 mtd: mpc5121_nfc: prepare clocks before enabling them

In reply to Gerhard Sittig

must prepare clocks before enabling them, unprepare after disable

---
 drivers/mtd/nand/mpc5121_nfc.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mtd/nand/mpc5121_nfc.c +2 -2
index 3c9cdcb..eb7771d 100644
@@ -618,7 +618,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 	struct mpc5121_nfc_prv *prv = chip->priv;
 
 	if (prv->clk) {
-		clk_disable(prv->clk);
+		clk_disable_unprepare(prv->clk);
 		clk_put(prv->clk);
 	}
 
@@ -737,7 +737,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 		goto error;
 	}
 
-	clk_enable(prv->clk);
+	clk_prepare_enable(prv->clk);
 
 	/* Reset NAND Flash controller */
 	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
Signature · 1 line
1.7.10.4
#45 lore raw

PATCH v2 4/24 powerpc: mpc512x: array decl for MCLK registers in CCM

In reply to Gerhard Sittig

reword the clock control module's registers declaration such that the MCLK related registers form an array and get indexed by PSC number

this change is in preparation to COMMON_CLK support for the MPC512x platform, the changed declaration remains neutral to existing code since the PSC and MSCAN CCR fields declared here aren't referenced anywhere

---
 arch/powerpc/include/asm/mpc5121.h |   18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)
arch/powerpc/include/asm/mpc5121.h +2 -16
index 8ae133e..887d3d6 100644
@@ -32,25 +32,11 @@ struct mpc512x_ccm {
 	u32	scfr2;	/* System Clock Frequency Register 2 */
 	u32	scfr2s;	/* System Clock Frequency Shadow Register 2 */
 	u32	bcr;	/* Bread Crumb Register */
-	u32	p0ccr;	/* PSC0 Clock Control Register */
-	u32	p1ccr;	/* PSC1 CCR */
-	u32	p2ccr;	/* PSC2 CCR */
-	u32	p3ccr;	/* PSC3 CCR */
-	u32	p4ccr;	/* PSC4 CCR */
-	u32	p5ccr;	/* PSC5 CCR */
-	u32	p6ccr;	/* PSC6 CCR */
-	u32	p7ccr;	/* PSC7 CCR */
-	u32	p8ccr;	/* PSC8 CCR */
-	u32	p9ccr;	/* PSC9 CCR */
-	u32	p10ccr;	/* PSC10 CCR */
-	u32	p11ccr;	/* PSC11 CCR */
+	u32	psc_ccr[12];	/* PSC Clock Control Registers */
 	u32	spccr;	/* SPDIF Clock Control Register */
 	u32	cccr;	/* CFM Clock Control Register */
 	u32	dccr;	/* DIU Clock Control Register */
-	u32	m1ccr;	/* MSCAN1 CCR */
-	u32	m2ccr;	/* MSCAN2 CCR */
-	u32	m3ccr;	/* MSCAN3 CCR */
-	u32	m4ccr;	/* MSCAN4 CCR */
+	u32	mscan_ccr[4];	/* MSCAN Clock Control Registers */
 	u8	res[0x98]; /* Reserved */
 };
 
Signature · 1 line
1.7.10.4
#46 lore raw

PATCH v2 5/24 clk: wrap I/O access for improved portability

In reply to Gerhard Sittig

the common clock drivers were motivated/initiated by ARM development and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux) in preparation of adding COMMON_CLK support for other platforms

---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
drivers/clk/clk-divider.c +3 -3
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);
 
 	div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
 		val = div_mask(divider) << (divider->shift + 16);
 	} else {
-		val = readl(divider->reg);
+		val = clk_readl(divider->reg);
 		val &= ~(div_mask(divider) << divider->shift);
 	}
 	val |= value << divider->shift;
-	writel(val, divider->reg);
+	clk_writel(val, divider->reg);
 
 	if (divider->lock)
 		spin_unlock_irqrestore(divider->lock, flags);
drivers/clk/clk-gate.c +3 -3
index 790306e..b7fbd96 100644
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		if (set)
 			reg |= BIT(gate->bit_idx);
 	} else {
-		reg = readl(gate->reg);
+		reg = clk_readl(gate->reg);
 
 		if (set)
 			reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 			reg &= ~BIT(gate->bit_idx);
 	}
 
-	writel(reg, gate->reg);
+	clk_writel(reg, gate->reg);
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 	u32 reg;
 	struct clk_gate *gate = to_clk_gate(hw);
 
-	reg = readl(gate->reg);
+	reg = clk_readl(gate->reg);
 
 	/* if a set bit disables this clk, flip it before masking */
 	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
drivers/clk/clk-mux.c +3 -3
index 614444c..02ef506 100644
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
 	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
 	 * val = 0x4 really means "bit 2, index starts at bit 0"
 	 */
-	val = readl(mux->reg) >> mux->shift;
+	val = clk_readl(mux->reg) >> mux->shift;
 	val &= mux->mask;
 
 	if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
 		val = mux->mask << (mux->shift + 16);
 	} else {
-		val = readl(mux->reg);
+		val = clk_readl(mux->reg);
 		val &= ~(mux->mask << mux->shift);
 	}
 	val |= index << mux->shift;
-	writel(val, mux->reg);
+	clk_writel(val, mux->reg);
 
 	if (mux->lock)
 		spin_unlock_irqrestore(mux->lock, flags);
include/linux/clk-provider.h +17 -0
index 1ec14a7..c4f7799 100644
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
 	{ while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4
#47 lore raw

PATCH v2 6/24 dts: mpc512x: prepare for preprocessor support

In reply to Gerhard Sittig

prepare C preprocessor support when processing MPC512x DTS files
- switch from DTS syntax to CPP syntax for include specs
- create a symlink such that DTS processing can reference includes

---
 arch/powerpc/boot/dts/ac14xx.dts          |    2 +-
 arch/powerpc/boot/dts/include/dt-bindings |    1 +
 arch/powerpc/boot/dts/mpc5121ads.dts      |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts        |    2 +-
 4 files changed, 4 insertions(+), 3 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
arch/powerpc/boot/dts/ac14xx.dts +1 -1
index a27a460..a543c40 100644
@@ -10,7 +10,7 @@
  */
 
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "ac14xx";
arch/powerpc/boot/dts/include/dt-bindings new file +1 -0
new file mode 120000
index 0000000..08c00e4
@@ -0,0 +1 @@
+../../../../../include/dt-bindings
\ No newline at end of file
arch/powerpc/boot/dts/mpc5121ads.dts +1 -1
index 7d3cb79..c228a0a 100644
@@ -9,7 +9,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "mpc5121ads";
arch/powerpc/boot/dts/pdm360ng.dts +1 -1
index 7433740..871c16d 100644
@@ -13,7 +13,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "pdm360ng";
Signature · 1 line
1.7.10.4
#48 lore raw

PATCH v2 7/24 dts: mpc512x: introduce dt-bindings/clock/ header

In reply to Gerhard Sittig

introduce a dt-bindings/ header file for MPC512x clocks, providing symbolic identifiers for those SoC clocks which clients will reference from their device tree nodes

---
 include/dt-bindings/clock/mpc512x-clock.h |   59 +++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
include/dt-bindings/clock/mpc512x-clock.h new file +59 -0
new file mode 100644
index 0000000..46c560e
@@ -0,0 +1,59 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ *
+ * Unfortunately the clock number declaration cannot be an enum but
+ * needs to be a list of #define directives since when referenced from
+ * within DTS files they need to get resolved "at compile time".
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY		0
+#define MPC512x_CLK_REF			1
+#define MPC512x_CLK_SYS			2
+#define MPC512x_CLK_DIU			3
+#define MPC512x_CLK_VIU			4
+#define MPC512x_CLK_CSB			5
+#define MPC512x_CLK_E300		6
+#define MPC512x_CLK_IPS			7
+#define MPC512x_CLK_FEC			8
+#define MPC512x_CLK_SATA		9
+#define MPC512x_CLK_PATA		10
+#define MPC512x_CLK_NFC			11
+#define MPC512x_CLK_LPC			12
+#define MPC512x_CLK_MBX_BUS		13
+#define MPC512x_CLK_MBX			14
+#define MPC512x_CLK_MBX_3D		15
+#define MPC512x_CLK_AXE			16
+#define MPC512x_CLK_USB1		17
+#define MPC512x_CLK_USB2		18
+#define MPC512x_CLK_I2C			19
+#define MPC512x_CLK_MSCAN0_MCLK		20
+#define MPC512x_CLK_MSCAN1_MCLK		21
+#define MPC512x_CLK_MSCAN2_MCLK		22
+#define MPC512x_CLK_MSCAN3_MCLK		23
+#define MPC512x_CLK_SDHC		24
+#define MPC512x_CLK_PCI			25
+#define MPC512x_CLK_PSC_MCLK_IN		26
+#define MPC512x_CLK_SPDIF_TX		27
+#define MPC512x_CLK_SPDIF_RX		28
+#define MPC512x_CLK_SPDIF_MCLK		29
+#define MPC512x_CLK_AC97		30
+#define MPC512x_CLK_PSC0_MCLK		31
+#define MPC512x_CLK_PSC1_MCLK		32
+#define MPC512x_CLK_PSC2_MCLK		33
+#define MPC512x_CLK_PSC3_MCLK		34
+#define MPC512x_CLK_PSC4_MCLK		35
+#define MPC512x_CLK_PSC5_MCLK		36
+#define MPC512x_CLK_PSC6_MCLK		37
+#define MPC512x_CLK_PSC7_MCLK		38
+#define MPC512x_CLK_PSC8_MCLK		39
+#define MPC512x_CLK_PSC9_MCLK		40
+#define MPC512x_CLK_PSC10_MCLK		41
+#define MPC512x_CLK_PSC11_MCLK		42
+#define MPC512x_CLK_PSC_FIFO		43
+
+#define MPC512x_CLK_LAST_PUBLIC		43
+
+#endif
Signature · 1 line
1.7.10.4
#49 lore raw

PATCH v2 8/24 dts: mpc512x: add clock related device tree specs

In reply to Gerhard Sittig

this addresses the clock driver aka provider's side of clocks
- prepare for future '<&clks ID>' phandle references for device tree based clock lookup in client drivers
- introduce a 'clocks' subtree with an 'osc' node for the crystal or oscillator SoC input (fixed frequency)
- provide default values with 33MHz oscillator frequency in the common include (the 66MHz IPS bus already was there), add override values for the ifm AC14xx board which deviates from the reference design (25MHz xtal, 80MHz IPS bus)

---
 arch/powerpc/boot/dts/ac14xx.dts   |    7 +++++++
 arch/powerpc/boot/dts/mpc5121.dtsi |   15 ++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
arch/powerpc/boot/dts/ac14xx.dts +7 -0
index a543c40..a1b8837 100644
@@ -139,7 +139,14 @@
 		};
 	};
 
+	clocks {
+		osc {
+			clock-frequency = <25000000>;
+		};
+	};
+
 	soc at 80000000 {
+		bus-frequency = <80000000>;	/* 80 MHz ips bus */
 
 		clock at f00 {
 			compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
arch/powerpc/boot/dts/mpc5121.dtsi +14 -1
index bd14c00..8f4cba0 100644
@@ -9,6 +9,8 @@
  * option) any later version.
  */
 
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 
 / {
@@ -73,6 +75,16 @@
 		ranges = <0x0 0x0 0xfc000000 0x04000000>;
 	};
 
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		osc {
+			compatible = "fsl,mpc512x-osc", "fixed-clock";
+			clock-frequency = <33000000>;
+		};
+	};
+
 	soc at 80000000 {
 		compatible = "fsl,mpc5121-immr";
 		#address-cells = <1>;
@@ -118,9 +130,10 @@
 		};
 
 		/* Clock control */
-		clock at f00 {
+		clks: clock at f00 {
 			compatible = "fsl,mpc5121-clock";
 			reg = <0xf00 0x100>;
+			#clock-cells = <1>;
 		};
 
 		/* Power Management Controller */
Signature · 1 line
1.7.10.4
#50 lore raw

PATCH v2 9/24 clk: mpc512x: introduce COMMON_CLK for MPC512x

In reply to Gerhard Sittig

this change introduces a clock infrastructure implementation for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

this driver implements the publicly announced set of clocks (which can get referenced by means of symbolic identifiers from the dt-bindings header file), as well as generates additional 'struct clk' items where the SoC hardware cannot easily get mapped to the common primitives of the clock API, or requires "intermediate" clock nodes to represent clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and resides in parallel to the common clock implementation for test and comparison during migration, a compile time option picks one of the two alternatives (Kconfig switch, common clock used by default)

since not all drivers for peripherals were adjusted yet to properly allocate and release their clock items, this platform clock driver implementation pre-enables some of the clock items to not break peripheral drivers during migration -- these clock pre-enable workarounds will get removed as peripheral drivers get adjusted

to provide clock names which the serial communication drivers are using and where the PSC index number is encoded into, clkdev registration is done to not break these peripheral drivers -- this workaround will get removed as these drivers get adjusted after device tree based clock lookup has become available

---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  778 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 810 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
arch/powerpc/platforms/512x/Kconfig +13 -1
index fc9c1cb..c5fcdd0 100644
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+	bool "MPC512x platform uses COMMON_CLK"
+	default y
+	depends on PPC_MPC512x
+	help
+	  This option is only here to support tests and comparison
+	  during development and migration.  This option will get
+	  removed after the COMMON_CLK support for MPC512x has become
+	  fully operational and all drivers were adjusted to explicitly
+	  acquire their required clocks.
+
 config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
 	select FSL_SOC
 	select IPIC
-	select PPC_CLOCK
+	select PPC_CLOCK if !MPC512x_COMMON_CLK
+	select COMMON_CLK if MPC512x_COMMON_CLK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
arch/powerpc/platforms/512x/Makefile +3 -1
index 72fb934..1e05f9d 100644
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y				+= clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)		+= clock.o
+obj-$(CONFIG_COMMON_CLK)	+= clock-commonclk.o
+obj-y				+= mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)	+= mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)		+= pdm360ng.o
arch/powerpc/platforms/512x/clock-commonclk.c new file +778 -0

778 lines not on this page · raw message

include/linux/clk-provider.h +16 -0
index c4f7799..7f8fc64 100644
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	iowrite32be(val, reg);
+}
+
+#else	/* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
 	return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
 	writel(val, reg);
 }
 
+#endif	/* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4
#51 lore raw

PATCH v2 10/24 dts: mpc512x: add clock specs for client lookups

In reply to Gerhard Sittig

this addresses the client side of device tree based clock lookups:
add clock specifiers to the mbx, nfc, mscan, sdhc, i2c, axe, diu, viu, mdio, fec, usb, pata, psc, psc fifo, and pci nodes in the shared mpc5121.dtsi include

these specs map 'clock-names' encoded in drivers to their respective 'struct clk' items in the platform's clock driver; some drivers still need to learn how to lookup OF clocks, other drivers will transparently probe successfully on MPC512x as well (sdhc)

few 'clock-names' (nfc, viu) use strings that are encoded in their respective drivers to keep up compatibility, an alternative approach would be to register clkdev items in the platform's clock driver for the migration period

---
 arch/powerpc/boot/dts/mpc5121.dtsi |   79 ++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
arch/powerpc/boot/dts/mpc5121.dtsi +79 -0
index 8f4cba0..983da9c 100644
@@ -51,6 +51,10 @@
 		compatible = "fsl,mpc5121-mbx";
 		reg = <0x20000000 0x4000>;
 		interrupts = <66 0x8>;
+		clocks = <&clks MPC512x_CLK_MBX_BUS>,
+			 <&clks MPC512x_CLK_MBX_3D>,
+			 <&clks MPC512x_CLK_MBX>;
+		clock-names = "mbx-bus", "mbx-3d", "mbx";
 	};
 
 	sram at 30000000 {
@@ -64,6 +68,8 @@
 		interrupts = <6 8>;
 		#address-cells = <1>;
 		#size-cells = <1>;
+		clocks = <&clks MPC512x_CLK_NFC>;
+		clock-names = "nfc_clk";	/* backwards compat */
 	};
 
 	localbus at 80000020 {
@@ -153,12 +159,22 @@
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1300 0x80>;
 			interrupts = <12 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN0_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can at 1380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1380 0x80>;
 			interrupts = <13 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN1_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		sdhc at 1500 {
@@ -167,6 +183,9 @@
 			interrupts = <8 0x8>;
 			dmas = <&dma0 30>;
 			dma-names = "rx-tx";
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SDHC>;
+			clock-names = "ipg", "per";
 		};
 
 		i2c at 1700 {
@@ -175,6 +194,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1700 0x20>;
 			interrupts = <9 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c at 1720 {
@@ -183,6 +204,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1720 0x20>;
 			interrupts = <10 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c at 1740 {
@@ -191,6 +214,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1740 0x20>;
 			interrupts = <11 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2ccontrol at 1760 {
@@ -202,30 +227,46 @@
 			compatible = "fsl,mpc5121-axe";
 			reg = <0x2000 0x100>;
 			interrupts = <42 0x8>;
+			clocks = <&clks MPC512x_CLK_AXE>;
+			clock-names = "per";
 		};
 
 		display at 2100 {
 			compatible = "fsl,mpc5121-diu";
 			reg = <0x2100 0x100>;
 			interrupts = <64 0x8>;
+			clocks = <&clks MPC512x_CLK_DIU>;
+			clock-names = "per";
 		};
 
 		can at 2300 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2300 0x80>;
 			interrupts = <90 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN2_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can at 2380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2380 0x80>;
 			interrupts = <91 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN3_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		viu at 2400 {
 			compatible = "fsl,mpc5121-viu";
 			reg = <0x2400 0x400>;
 			interrupts = <67 0x8>;
+			clocks = <&clks MPC512x_CLK_VIU>;
+			clock-names = "viu_clk";	/* backwards compat */
 		};
 
 		mdio at 2800 {
@@ -233,6 +274,8 @@
 			reg = <0x2800 0x800>;
 			#address-cells = <1>;
 			#size-cells = <0>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		eth0: ethernet at 2800 {
@@ -241,6 +284,8 @@
 			reg = <0x2800 0x800>;
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <4 0x8>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		/* USB1 using external ULPI PHY */
@@ -252,6 +297,8 @@
 			interrupts = <43 0x8>;
 			dr_mode = "otg";
 			phy_type = "ulpi";
+			clocks = <&clks MPC512x_CLK_USB1>;
+			clock-names = "per";
 		};
 
 		/* USB0 using internal UTMI PHY */
@@ -263,6 +310,8 @@
 			interrupts = <44 0x8>;
 			dr_mode = "otg";
 			phy_type = "utmi_wide";
+			clocks = <&clks MPC512x_CLK_USB2>;
+			clock-names = "per";
 		};
 
 		/* IO control */
@@ -281,6 +330,8 @@
 			compatible = "fsl,mpc5121-pata";
 			reg = <0x10200 0x100>;
 			interrupts = <5 0x8>;
+			clocks = <&clks MPC512x_CLK_PATA>;
+			clock-names = "per";
 		};
 
 		/* 512x PSCs are not 52xx PSC compatible */
@@ -292,6 +343,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC0_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC1 */
@@ -301,6 +354,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC1_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC2 */
@@ -310,6 +365,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC2_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC3 */
@@ -319,6 +376,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC3_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC4 */
@@ -328,6 +387,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC4_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC5 */
@@ -337,6 +398,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC5_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC6 */
@@ -346,6 +409,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC6_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC7 */
@@ -355,6 +420,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC7_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC8 */
@@ -364,6 +431,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC8_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC9 */
@@ -373,6 +442,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC9_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC10 */
@@ -382,6 +453,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC10_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC11 */
@@ -391,12 +464,16 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC11_MCLK>;
+			clock-names = "mclk";
 		};
 
 		pscfifo at 11f00 {
 			compatible = "fsl,mpc5121-psc-fifo";
 			reg = <0x11f00 0x100>;
 			interrupts = <40 0x8>;
+			clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+			clock-names = "per";
 		};
 
 		dma0: dma at 14000 {
@@ -414,6 +491,8 @@
 		#address-cells = <3>;
 		#size-cells = <2>;
 		#interrupt-cells = <1>;
+		clocks = <&clks MPC512x_CLK_PCI>;
+		clock-names = "per";
 
 		reg = <0x80008500 0x100	/* internal registers */
 		       0x80008300 0x8>;	/* config space access registers */
Signature · 1 line
1.7.10.4
#52 lore raw

PATCH v2 11/24 spi: mpc512x: remove now obsolete clock lookup name

In reply to Gerhard Sittig

after device tree based clock lookup became available, the peripheral driver need no longer construct clock names which include the PSC index, remove the "psc%d_mclk" template and unconditionally use "mclk"

---
 drivers/spi/spi-mpc512x-psc.c |    6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/spi/spi-mpc512x-psc.c +1 -5
index 7a32373..b04f094 100644
@@ -474,8 +474,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 	struct spi_master *master;
 	int ret;
 	void *tempp;
-	int psc_num;
-	char clk_name[16];
 
 	master = spi_alloc_master(dev, sizeof *mps);
 	if (master == NULL)
@@ -518,9 +516,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 		goto free_master;
 	init_completion(&mps->txisrdone);
 
-	psc_num = master->bus_num;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	mps->clk_mclk = clk_get(dev, clk_name);
+	mps->clk_mclk = clk_get(dev, "mclk");
 	if (IS_ERR(mps->clk_mclk))
 		goto free_irq;
 	ret = clk_prepare_enable(mps->clk_mclk);
Signature · 1 line
1.7.10.4
#53 lore raw

PATCH v2 12/24 serial: mpc512x: remove now obsolete clock lookup name

In reply to Gerhard Sittig

after device tree based clock lookup became available, the peripheral driver need no longer construct clock names which include the PSC index, remove the "psc%d_mclk" template and unconditionally use "mclk"

---
 drivers/tty/serial/mpc52xx_uart.c |    8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/tty/serial/mpc52xx_uart.c +3 -5
index 98a1f43..8643dcf 100644
@@ -623,14 +623,11 @@ static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
 /* called from within the .request_port() callback (allocation) */
 static int mpc512x_psc_alloc_clock(struct uart_port *port)
 {
-	int psc_num;
-	char clk_name[16];
 	struct clk *clk;
 	int err;
+	int psc_num;
 
-	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	clk = clk_get(port->dev, clk_name);
+	clk = clk_get(port->dev, "mclk");
 	if (IS_ERR(clk)) {
 		dev_err(port->dev, "Failed to get MCLK!\n");
 		return PTR_ERR(clk);
@@ -641,6 +638,7 @@ static int mpc512x_psc_alloc_clock(struct uart_port *port)
 		clk_put(clk);
 		return err;
 	}
+	psc_num = (port->mapbase & 0xf00) >> 8;
 	psc_mclk_clk[psc_num] = clk;
 	return 0;
 }
Signature · 1 line
1.7.10.4
#54 lore raw

PATCH v2 13/24 clk: mpc512x: remove now obsolete clkdev registration

In reply to Gerhard Sittig

after the peripheral drivers for UART and SPI mode (both using the PSC controller) got converted to device tree based clock lookups, the platform clock driver need no longer provide the "psc%d_mclk" name which depends on the PSC index number -- remove the clk_register_clkdev() call

---
 arch/powerpc/platforms/512x/clock-commonclk.c |   12 ------------
 1 file changed, 12 deletions(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -12
index 6627957..b822469 100644
@@ -12,7 +12,6 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/clkdev.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/io.h>
@@ -529,17 +528,6 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
 				entry->name_mclk,
 				entry->name_mux1, 1, 1);
 	}
-
-	/*
-	 * without this "clock device" registration, "simple" lookups in
-	 * the SPI master initialization and serial port setup will fail
-	 *
-	 * those drivers need to get adjusted to lookup their required
-	 * clocks from device tree specs, and device tree nodes need to
-	 * provide the clock specs, before this clkdev registration
-	 * becomes obsolete
-	 */
-	clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
 }
 
 static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
Signature · 1 line
1.7.10.4
#55 lore raw

PATCH v2 14/24 serial: mpc512x: setup the PSC FIFO clock as well

In reply to Gerhard Sittig

prepare and enable the FIFO clock upon PSC FIFO initialization, disable and unprepare the FIFO clock upon PSC FIFO uninitialization, remove the pre-enable workaround from the platform's clock driver

---
 arch/powerpc/platforms/512x/clock-commonclk.c |    2 --
 drivers/tty/serial/mpc52xx_uart.c             |   39 +++++++++++++++++++++----
 2 files changed, 33 insertions(+), 8 deletions(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -2
index b822469..99d197d 100644
@@ -689,8 +689,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
 	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
 	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
-	/* some are required yet no dependencies were declared */
-	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
drivers/tty/serial/mpc52xx_uart.c +33 -6
index 8643dcf..3fdadf9 100644
@@ -421,6 +421,7 @@ struct psc_fifoc {
 
 static struct psc_fifoc __iomem *psc_fifoc;
 static unsigned int psc_fifoc_irq;
+static struct clk *psc_fifoc_clk;
 
 static void mpc512x_psc_fifo_init(struct uart_port *port)
 {
@@ -574,30 +575,56 @@ static int __init mpc512x_psc_fifoc_init(void)
 				     "fsl,mpc5121-psc-fifo");
 	if (!np) {
 		pr_err("%s: Can't find FIFOC node\n", __func__);
-		return -ENODEV;
+		goto out_err;
+	}
+
+	psc_fifoc_clk = of_clk_get_by_name(np, "per");
+	if (IS_ERR(psc_fifoc_clk)) {
+		pr_err("%s: Can't lookup FIFO clock\n", __func__);
+		goto out_ofnode_put;
+	}
+	if (clk_prepare_enable(psc_fifoc_clk)) {
+		pr_err("%s: Can't enable FIFO clock\n", __func__);
+		goto out_clk_put;
 	}
 
 	psc_fifoc = of_iomap(np, 0);
 	if (!psc_fifoc) {
 		pr_err("%s: Can't map FIFOC\n", __func__);
-		of_node_put(np);
-		return -ENODEV;
+		goto out_clk_disable;
 	}
 
 	psc_fifoc_irq = irq_of_parse_and_map(np, 0);
-	of_node_put(np);
 	if (psc_fifoc_irq == 0) {
 		pr_err("%s: Can't get FIFOC irq\n", __func__);
-		iounmap(psc_fifoc);
-		return -ENODEV;
+		goto out_unmap;
 	}
 
+	of_node_put(np);
 	return 0;
+
+out_unmap:
+	iounmap(psc_fifoc);
+out_clk_disable:
+	clk_disable_unprepare(psc_fifoc_clk);
+out_clk_put:
+	clk_put(psc_fifoc_clk);
+out_ofnode_put:
+	of_node_put(np);
+out_err:
+	return -ENODEV;
 }
 
 static void __exit mpc512x_psc_fifoc_uninit(void)
 {
 	iounmap(psc_fifoc);
+
+	/* disable the clock, errors are not fatal */
+	if (psc_fifoc_clk && !IS_ERR(psc_fifoc_clk)) {
+		clk_disable_unprepare(psc_fifoc_clk);
+		clk_put(psc_fifoc_clk);
+		psc_fifoc_clk = NULL;
+	}
 }
 
 /* 512x specific interrupt handler. The caller holds the port lock */
Signature · 1 line
1.7.10.4
#56 lore raw

PATCH v2 15/24 net: can: mscan: add a comment on reg to idx mapping

In reply to Gerhard Sittig

add a comment about the magic of deriving an MSCAN component index from the peripheral's physical address / register offset

---
 drivers/net/can/mscan/mpc5xxx_can.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/can/mscan/mpc5xxx_can.c +4 -1
index 5b0ee8e..bc422ba 100644
@@ -148,7 +148,10 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		goto exit_put;
 	}
 
-	/* Determine the MSCAN device index from the physical address */
+	/* Determine the MSCAN device index from the peripheral's
+	 * physical address. Register address offsets against the
+	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
+	 */
 	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
 	BUG_ON(!pval || plen < sizeof(*pval));
 	clockidx = (*pval & 0x80) ? 1 : 0;
Signature · 1 line
1.7.10.4
#57 lore raw

PATCH v2 16/24 net: can: mscan: make mpc512x code use common clock

In reply to Gerhard Sittig

extend the mscan(4) driver with alternative support for the COMMON_CLK approach which is an option in the MPC512x platform, keep the existing clock support implementation in place since the driver is shared with other MPC5xxx SoCs which don't have common clock support

one byproduct of this change is that the CAN driver no longer needs to access the SoC's clock control registers, which shall be the domain of the platform's clock driver

---
 drivers/net/can/mscan/mpc5xxx_can.c |  139 +++++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)
drivers/net/can/mscan/mpc5xxx_can.c +139 -0
index bc422ba..dd26ab6 100644
@@ -108,6 +108,143 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
+
+#if IS_ENABLED(CONFIG_COMMON_CLK)
+
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+				 const char *clock_source, int *mscan_clksrc)
+{
+	struct device_node *np;
+	u32 clockdiv;
+	enum {
+		CLK_FROM_AUTO,
+		CLK_FROM_IPS,
+		CLK_FROM_SYS,
+		CLK_FROM_REF,
+	} clk_from;
+	struct clk *clk_in, *clk_can;
+	unsigned long freq_calc;
+
+	/* the caller passed in the clock source spec that was read from
+	 * the device tree, get the optional clock divider as well
+	 */
+	np = ofdev->dev.of_node;
+	clockdiv = 1;
+	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+		clock_source ? clock_source : "<NULL>", clockdiv);
+
+	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+	 * get set, and the 'ips' clock is the input to the MSCAN
+	 * component
+	 *
+	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+	 * bit needs to get cleared, an optional clock-divider may have
+	 * been specified (the default value is 1), the appropriate
+	 * MSCAN related MCLK is the input to the MSCAN component
+	 *
+	 * in the absence of a clock-source spec, first an optimal clock
+	 * gets determined based on the 'sys' clock, if that fails the
+	 * 'ref' clock is used
+	 */
+	clk_from = CLK_FROM_AUTO;
+	if (clock_source) {
+		/* interpret the device tree's spec for the clock source */
+		if (!strcmp(clock_source, "ip"))
+			clk_from = CLK_FROM_IPS;
+		else if (!strcmp(clock_source, "sys"))
+			clk_from = CLK_FROM_SYS;
+		else if (!strcmp(clock_source, "ref"))
+			clk_from = CLK_FROM_REF;
+		else
+			goto err_invalid;
+		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, try the 'sys' clock; round to the
+		 * next MHz and see if we can get a multiple of 16MHz
+		 */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+		clk_in = clk_get(&ofdev->dev, "sys");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc +=  499999;
+		freq_calc /= 1000000;
+		freq_calc *= 1000000;
+		if ((freq_calc % 16000000) == 0) {
+			clk_from = CLK_FROM_SYS;
+			clockdiv = freq_calc / 16000000;
+			dev_dbg(&ofdev->dev,
+				"clk fit, sys[%lu] div[%d] freq[%lu]\n",
+				freq_calc, clockdiv, freq_calc / clockdiv);
+		}
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, use the 'ref' clock */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+		clk_in = clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_from = CLK_FROM_REF;
+		freq_calc = clk_get_rate(clk_in);
+		dev_dbg(&ofdev->dev,
+			"clk fit, ref[%lu] (no div) freq[%lu]\n",
+			freq_calc, freq_calc);
+	}
+
+	/* select IPS or MCLK as the MSCAN input (returned to the caller),
+	 * setup the MCLK mux source and rate if applicable, apply the
+	 * optionally specified or derived above divider, and determine
+	 * the actual resulting clock rate to return to the caller
+	 */
+	switch (clk_from) {
+	case CLK_FROM_IPS:
+		clk_can = clk_get(&ofdev->dev, "ips");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_IPS;
+		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	case CLK_FROM_SYS:
+	case CLK_FROM_REF:
+		clk_can = clk_get(&ofdev->dev, "mclk");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);
+		if (clk_from == CLK_FROM_SYS)
+			clk_in = clk_get(&ofdev->dev, "sys");
+		if (clk_from == CLK_FROM_REF)
+			clk_in = clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_set_parent(clk_can, clk_in);
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc /= clockdiv;
+		clk_set_rate(clk_can, freq_calc);
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_BUS;
+		dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	default:
+		goto err_invalid;
+	}
+
+	return freq_calc;
+
+err_invalid:
+	dev_err(&ofdev->dev, "invalid clock source specification\n");
+	return 0;
+
+err_notavail:
+	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
+	return 0;
+}
+#else	/* COMMON_CLK */
 struct mpc512x_clockctl {
 	u32 spmr;		/* System PLL Mode Reg */
 	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
@@ -238,6 +375,8 @@ exit_put:
 	of_node_put(np_clock);
 	return freq;
 }
+#endif	/* COMMON_CLK */
+
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
Signature · 1 line
1.7.10.4
#58 lore raw

PATCH v2 16/24 net: can: mscan: make mpc512x code use common clock

Quoted 108 lines · Gerhard Sittig

extend the mscan(4) driver with alternative support for the COMMON_CLK approach which is an option in the MPC512x platform, keep the existing clock support implementation in place since the driver is shared with other MPC5xxx SoCs which don't have common clock support

one byproduct of this change is that the CAN driver no longer needs to access the SoC's clock control registers, which shall be the domain of the platform's clock driver

---
 drivers/net/can/mscan/mpc5xxx_can.c |  139 +++++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)
drivers/net/can/mscan/mpc5xxx_can.c +86 -0
index bc422ba..dd26ab6 100644
@@ -108,6 +108,143 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
+
+#if IS_ENABLED(CONFIG_COMMON_CLK)
+
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+				 const char *clock_source, int *mscan_clksrc)
+{
+	struct device_node *np;
+	u32 clockdiv;
+	enum {
+		CLK_FROM_AUTO,
+		CLK_FROM_IPS,
+		CLK_FROM_SYS,
+		CLK_FROM_REF,
+	} clk_from;
+	struct clk *clk_in, *clk_can;
+	unsigned long freq_calc;
+
+	/* the caller passed in the clock source spec that was read from
+	 * the device tree, get the optional clock divider as well
+	 */
+	np = ofdev->dev.of_node;
+	clockdiv = 1;
+	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+		clock_source ? clock_source : "<NULL>", clockdiv);
+
+	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+	 * get set, and the 'ips' clock is the input to the MSCAN
+	 * component
+	 *
+	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+	 * bit needs to get cleared, an optional clock-divider may have
+	 * been specified (the default value is 1), the appropriate
+	 * MSCAN related MCLK is the input to the MSCAN component
+	 *
+	 * in the absence of a clock-source spec, first an optimal clock
+	 * gets determined based on the 'sys' clock, if that fails the
+	 * 'ref' clock is used
+	 */
+	clk_from = CLK_FROM_AUTO;
+	if (clock_source) {
+		/* interpret the device tree's spec for the clock source */
+		if (!strcmp(clock_source, "ip"))
+			clk_from = CLK_FROM_IPS;
+		else if (!strcmp(clock_source, "sys"))
+			clk_from = CLK_FROM_SYS;
+		else if (!strcmp(clock_source, "ref"))
+			clk_from = CLK_FROM_REF;
+		else
+			goto err_invalid;
+		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, try the 'sys' clock; round to the
+		 * next MHz and see if we can get a multiple of 16MHz
+		 */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+		clk_in = clk_get(&ofdev->dev, "sys");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc +=  499999;
+		freq_calc /= 1000000;
+		freq_calc *= 1000000;
+		if ((freq_calc % 16000000) == 0) {
+			clk_from = CLK_FROM_SYS;
+			clockdiv = freq_calc / 16000000;
+			dev_dbg(&ofdev->dev,
+				"clk fit, sys[%lu] div[%d] freq[%lu]\n",
+				freq_calc, clockdiv, freq_calc / clockdiv);
+		}
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, use the 'ref' clock */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+		clk_in = clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_from = CLK_FROM_REF;
+		freq_calc = clk_get_rate(clk_in);
+		dev_dbg(&ofdev->dev,
+			"clk fit, ref[%lu] (no div) freq[%lu]\n",
+			freq_calc, freq_calc);
+	}
+
+	/* select IPS or MCLK as the MSCAN input (returned to the caller),

drivers/net/can/mscan/mpc5xxx_can.c static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, · line 206

Quoted 10 lines
drivers/net/can/mscan/mpc5xxx_can.c +10 -0
+	 * setup the MCLK mux source and rate if applicable, apply the
+	 * optionally specified or derived above divider, and determine
+	 * the actual resulting clock rate to return to the caller
+	 */
+	switch (clk_from) {
+	case CLK_FROM_IPS:
+		clk_can = clk_get(&ofdev->dev, "ips");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);

Where is the corresponding clk_disable_unprepare()?a

drivers/net/can/mscan/mpc5xxx_can.c static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, · line 217

Quoted 11 lines
drivers/net/can/mscan/mpc5xxx_can.c +11 -0
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_IPS;
+		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
+	case CLK_FROM_SYS:
+	case CLK_FROM_REF:
+		clk_can = clk_get(&ofdev->dev, "mclk");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);

dito

Marc

Signature · 12 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130719/2115e02f/attachment.sig>
#59 lore raw

PATCH v2 16/24 net: can: mscan: make mpc512x code use common clock

Quoted 114 lines · Marc Kleine-Budde
Quoted 112 lines · Gerhard Sittig

extend the mscan(4) driver with alternative support for the COMMON_CLK approach which is an option in the MPC512x platform, keep the existing clock support implementation in place since the driver is shared with other MPC5xxx SoCs which don't have common clock support

one byproduct of this change is that the CAN driver no longer needs to access the SoC's clock control registers, which shall be the domain of the platform's clock driver

---
 drivers/net/can/mscan/mpc5xxx_can.c |  139 +++++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)
drivers/net/can/mscan/mpc5xxx_can.c +90 -0
index bc422ba..dd26ab6 100644
@@ -108,6 +108,143 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
+
+#if IS_ENABLED(CONFIG_COMMON_CLK)
+
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+				 const char *clock_source, int *mscan_clksrc)
+{
+	struct device_node *np;
+	u32 clockdiv;
+	enum {
+		CLK_FROM_AUTO,
+		CLK_FROM_IPS,
+		CLK_FROM_SYS,
+		CLK_FROM_REF,
+	} clk_from;
+	struct clk *clk_in, *clk_can;
+	unsigned long freq_calc;
+
+	/* the caller passed in the clock source spec that was read from
+	 * the device tree, get the optional clock divider as well
+	 */
+	np = ofdev->dev.of_node;
+	clockdiv = 1;
+	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+		clock_source ? clock_source : "<NULL>", clockdiv);
+
+	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+	 * get set, and the 'ips' clock is the input to the MSCAN
+	 * component
+	 *
+	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+	 * bit needs to get cleared, an optional clock-divider may have
+	 * been specified (the default value is 1), the appropriate
+	 * MSCAN related MCLK is the input to the MSCAN component
+	 *
+	 * in the absence of a clock-source spec, first an optimal clock
+	 * gets determined based on the 'sys' clock, if that fails the
+	 * 'ref' clock is used
+	 */
+	clk_from = CLK_FROM_AUTO;
+	if (clock_source) {
+		/* interpret the device tree's spec for the clock source */
+		if (!strcmp(clock_source, "ip"))
+			clk_from = CLK_FROM_IPS;
+		else if (!strcmp(clock_source, "sys"))
+			clk_from = CLK_FROM_SYS;
+		else if (!strcmp(clock_source, "ref"))
+			clk_from = CLK_FROM_REF;
+		else
+			goto err_invalid;
+		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, try the 'sys' clock; round to the
+		 * next MHz and see if we can get a multiple of 16MHz
+		 */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+		clk_in = clk_get(&ofdev->dev, "sys");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc +=  499999;
+		freq_calc /= 1000000;
+		freq_calc *= 1000000;
+		if ((freq_calc % 16000000) == 0) {
+			clk_from = CLK_FROM_SYS;
+			clockdiv = freq_calc / 16000000;
+			dev_dbg(&ofdev->dev,
+				"clk fit, sys[%lu] div[%d] freq[%lu]\n",
+				freq_calc, clockdiv, freq_calc / clockdiv);
+		}
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, use the 'ref' clock */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+		clk_in = clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_from = CLK_FROM_REF;
+		freq_calc = clk_get_rate(clk_in);
+		dev_dbg(&ofdev->dev,
+			"clk fit, ref[%lu] (no div) freq[%lu]\n",
+			freq_calc, freq_calc);
+	}
+
+	/* select IPS or MCLK as the MSCAN input (returned to the caller),
+	 * setup the MCLK mux source and rate if applicable, apply the
+	 * optionally specified or derived above divider, and determine
+	 * the actual resulting clock rate to return to the caller
+	 */
Quoted 8 lines

drivers/net/can/mscan/mpc5xxx_can.c static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, · line 206

Quoted 6 lines
drivers/net/can/mscan/mpc5xxx_can.c +6 -0
+	switch (clk_from) {
+	case CLK_FROM_IPS:
+		clk_can = clk_get(&ofdev->dev, "ips");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);

Where is the corresponding clk_disable_unprepare()?a

It's missing, as I could not find the counterpart of the .get_clock() callback where the get and prepare/enable was added to. And it appears that neither are enable errors checked for. This patch clearly needs an update as well, but already should be the last part of the series in a currently inacceptable state.

This .get_clock() routine is supposed to determine the clock source, setup the desired rate and return the actual rate. The callback's API is rather limited in that it does communicate clock rate values, but cannot access a location to store handles to.

Are the introduction of a .put_clock() callback and passing the 'priv' handle to both get and put routines acceptable? As this would hook up clock handling to probe() and remove() just as memory mapping gets approached.

Below is a patch on top of the CAN related patch in v2 of the series. If this approach is acceptable (maybe modulo how the "unused" warnings get silenced), I'll fold it into the introduction of common clock support in the mscan(4) driver.

drivers/net/can/mscan/mpc5xxx_can.c +52 -8
index cf5e4cfc..16ca712 100644
@@ -39,7 +39,9 @@
 struct mpc5xxx_can_data {
 	unsigned int type;
 	u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
-			 int *mscan_clksrc);
+			 int *mscan_clksrc, struct mscan_priv *priv);
+	void (*put_clock)(struct platform_device *ofdev,
+			  struct mscan_priv *priv);
 };
 
 #ifdef CONFIG_PPC_MPC52xx
@@ -49,7 +51,8 @@ static struct of_device_id mpc52xx_cdm_ids[] = {
 };
 
 static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
-				 const char *clock_name, int *mscan_clksrc)
+				 const char *clock_name, int *mscan_clksrc,
+				 struct mscan_priv *priv)
 {
 	unsigned int pvr;
 	struct mpc52xx_cdm  __iomem *cdm;
@@ -101,15 +104,24 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 }
 #else /* !CONFIG_PPC_MPC52xx */
 static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
-				 const char *clock_name, int *mscan_clksrc)
+				 const char *clock_name, int *mscan_clksrc,
+				 struct mscan_priv *priv)
 {
 	return 0;
 }
 #endif /* CONFIG_PPC_MPC52xx */
+static void mpc52xx_can_put_clock(struct platform_device *ofdev,
+				  struct mscan_priv *priv)
+{
+	/* EMPTY */
+	(void)ofdev;
+	(void)priv;
+}
 
 #ifdef CONFIG_PPC_MPC512x
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
-				 const char *clock_source, int *mscan_clksrc)
+				 const char *clock_source, int *mscan_clksrc,
+				 struct mscan_priv *priv)
 {
 	struct device_node *np;
 	u32 clockdiv;
@@ -200,7 +212,9 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		clk_can = clk_get(&ofdev->dev, "ips");
 		if (IS_ERR(clk_can))
 			goto err_notavail;
-		clk_prepare_enable(clk_can);
+		if (clk_prepare_enable(clk_can))
+			goto err_notavail;
+		priv->clk_can = clk_can;
 		freq_calc = clk_get_rate(clk_can);
 		*mscan_clksrc = MSCAN_CLKSRC_IPS;
 		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
@@ -211,7 +225,9 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		clk_can = clk_get(&ofdev->dev, "mclk");
 		if (IS_ERR(clk_can))
 			goto err_notavail;
-		clk_prepare_enable(clk_can);
+		if (clk_prepare_enable(clk_can))
+			goto err_notavail;
+		priv->clk_can = clk_can;
 		if (clk_from == CLK_FROM_SYS)
 			clk_in = clk_get(&ofdev->dev, "sys");
 		if (clk_from == CLK_FROM_REF)
@@ -241,12 +257,31 @@ err_notavail:
 	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
 	return 0;
 }
+
+static void mpc512x_can_put_clock(struct platform_device *ofdev,
+				  struct mscan_priv *priv)
+{
+	(void)ofdev;
+	if (priv->clk_can) {
+		clk_disable_unprepare(priv->clk_can);
+		clk_put(priv->clk_can);
+	}
+}
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
-				 const char *clock_name, int *mscan_clksrc)
+				 const char *clock_name, int *mscan_clksrc,
+				 struct mscan_priv *priv)
 {
 	return 0;
 }
+
+static void mpc512x_can_put_clock(struct platform_device *ofdev,
+				  struct mscan_priv *priv)
+{
+	(void)ofdev;
+	(void)priv;
+	/* EMPTY */
+}
 #endif /* CONFIG_PPC_MPC512x */
 
 static const struct of_device_id mpc5xxx_can_table[];
@@ -293,7 +328,7 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 	BUG_ON(!data);
 	priv->type = data->type;
 	priv->can.clock.freq = data->get_clock(ofdev, clock_name,
-					       &mscan_clksrc);
+					       &mscan_clksrc, priv);
 	if (!priv->can.clock.freq) {
 		dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n");
 		goto exit_free_mscan;
@@ -327,10 +362,17 @@ exit_unmap_mem:
 
 static int mpc5xxx_can_remove(struct platform_device *ofdev)
 {
+	const struct of_device_id *match;
+	const struct mpc5xxx_can_data *data;
 	struct net_device *dev = platform_get_drvdata(ofdev);
 	struct mscan_priv *priv = netdev_priv(dev);
 
+	match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
+	data = match ? match->data : NULL;
+
 	unregister_mscandev(dev);
+	if (data)
+		data->put_clock(ofdev, priv);
 	iounmap(priv->reg_base);
 	irq_dispose_mapping(dev->irq);
 	free_candev(dev);
@@ -383,11 +425,13 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
 static const struct mpc5xxx_can_data mpc5200_can_data = {
 	.type = MSCAN_TYPE_MPC5200,
 	.get_clock = mpc52xx_can_get_clock,
+	.put_clock = mpc52xx_can_put_clock,
 };
 
 static const struct mpc5xxx_can_data mpc5121_can_data = {
 	.type = MSCAN_TYPE_MPC5121,
 	.get_clock = mpc512x_can_get_clock,
+	.put_clock = mpc512x_can_put_clock,
 };
 
 static const struct of_device_id mpc5xxx_can_table[] = {
drivers/net/can/mscan/mscan.h +2 -0
index af2ed8b..f32e190 100644
@@ -21,6 +21,7 @@
 #ifndef __MSCAN_H__
 #define __MSCAN_H__
 
+#include <linux/clk.h>
 #include <linux/types.h>
 
 /* MSCAN control register 0 (CANCTL0) bits */
@@ -283,6 +284,7 @@ struct mscan_priv {
 	unsigned int type; 	/* MSCAN type variants */
 	unsigned long flags;
 	void __iomem *reg_base;	/* ioremap'ed address to registers */
+	struct clk *clk_can;	/* clock for registers or bitrates */
 	u8 shadow_statflg;
 	u8 shadow_canrier;
 	u8 cur_pri;
Quoted 5 lines
Quoted 5 lines
drivers/net/can/mscan/mpc5xxx_can.c +5 -0
+		freq_calc = clk_get_rate(clk_can);
+		*mscan_clksrc = MSCAN_CLKSRC_IPS;
+		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
+			*mscan_clksrc, freq_calc);
+		break;
Quoted 8 lines

drivers/net/can/mscan/mpc5xxx_can.c static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, · line 217

Quoted 6 lines
drivers/net/can/mscan/mpc5xxx_can.c +6 -0
+	case CLK_FROM_SYS:
+	case CLK_FROM_REF:
+		clk_can = clk_get(&ofdev->dev, "mclk");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);

dito

yes, both problems of not checking for errors and dropping the reference, will address this as well

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#60 lore raw

PATCH v2 16/24 net: can: mscan: make mpc512x code use common clock

Quoted 130 lines · Gerhard Sittig
Quoted 114 lines · Marc Kleine-Budde
Quoted 112 lines · Gerhard Sittig

extend the mscan(4) driver with alternative support for the COMMON_CLK approach which is an option in the MPC512x platform, keep the existing clock support implementation in place since the driver is shared with other MPC5xxx SoCs which don't have common clock support

one byproduct of this change is that the CAN driver no longer needs to access the SoC's clock control registers, which shall be the domain of the platform's clock driver

---
 drivers/net/can/mscan/mpc5xxx_can.c |  139 +++++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)
drivers/net/can/mscan/mpc5xxx_can.c +90 -0
index bc422ba..dd26ab6 100644
@@ -108,6 +108,143 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
+
+#if IS_ENABLED(CONFIG_COMMON_CLK)
+
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+				 const char *clock_source, int *mscan_clksrc)
+{
+	struct device_node *np;
+	u32 clockdiv;
+	enum {
+		CLK_FROM_AUTO,
+		CLK_FROM_IPS,
+		CLK_FROM_SYS,
+		CLK_FROM_REF,
+	} clk_from;
+	struct clk *clk_in, *clk_can;
+	unsigned long freq_calc;
+
+	/* the caller passed in the clock source spec that was read from
+	 * the device tree, get the optional clock divider as well
+	 */
+	np = ofdev->dev.of_node;
+	clockdiv = 1;
+	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+		clock_source ? clock_source : "<NULL>", clockdiv);
+
+	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+	 * get set, and the 'ips' clock is the input to the MSCAN
+	 * component
+	 *
+	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+	 * bit needs to get cleared, an optional clock-divider may have
+	 * been specified (the default value is 1), the appropriate
+	 * MSCAN related MCLK is the input to the MSCAN component
+	 *
+	 * in the absence of a clock-source spec, first an optimal clock
+	 * gets determined based on the 'sys' clock, if that fails the
+	 * 'ref' clock is used
+	 */
+	clk_from = CLK_FROM_AUTO;
+	if (clock_source) {
+		/* interpret the device tree's spec for the clock source */
+		if (!strcmp(clock_source, "ip"))
+			clk_from = CLK_FROM_IPS;
+		else if (!strcmp(clock_source, "sys"))
+			clk_from = CLK_FROM_SYS;
+		else if (!strcmp(clock_source, "ref"))
+			clk_from = CLK_FROM_REF;
+		else
+			goto err_invalid;
+		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, try the 'sys' clock; round to the
+		 * next MHz and see if we can get a multiple of 16MHz
+		 */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+		clk_in = clk_get(&ofdev->dev, "sys");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		freq_calc = clk_get_rate(clk_in);
+		freq_calc +=  499999;
+		freq_calc /= 1000000;
+		freq_calc *= 1000000;
+		if ((freq_calc % 16000000) == 0) {
+			clk_from = CLK_FROM_SYS;
+			clockdiv = freq_calc / 16000000;
+			dev_dbg(&ofdev->dev,
+				"clk fit, sys[%lu] div[%d] freq[%lu]\n",
+				freq_calc, clockdiv, freq_calc / clockdiv);
+		}
+	}
+	if (clk_from == CLK_FROM_AUTO) {
+		/* no spec so far, use the 'ref' clock */
+		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+		clk_in = clk_get(&ofdev->dev, "ref");
+		if (IS_ERR(clk_in))
+			goto err_notavail;
+		clk_from = CLK_FROM_REF;
+		freq_calc = clk_get_rate(clk_in);
+		dev_dbg(&ofdev->dev,
+			"clk fit, ref[%lu] (no div) freq[%lu]\n",
+			freq_calc, freq_calc);
+	}
+
+	/* select IPS or MCLK as the MSCAN input (returned to the caller),
+	 * setup the MCLK mux source and rate if applicable, apply the
+	 * optionally specified or derived above divider, and determine
+	 * the actual resulting clock rate to return to the caller
+	 */
Quoted 8 lines

drivers/net/can/mscan/mpc5xxx_can.c static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, · line 206

Quoted 6 lines
drivers/net/can/mscan/mpc5xxx_can.c +6 -0
+	switch (clk_from) {
+	case CLK_FROM_IPS:
+		clk_can = clk_get(&ofdev->dev, "ips");
+		if (IS_ERR(clk_can))
+			goto err_notavail;
+		clk_prepare_enable(clk_can);

Where is the corresponding clk_disable_unprepare()?a

It's missing, as I could not find the counterpart of the .get_clock() callback where the get and prepare/enable was added to. And it appears that neither are enable errors checked for. This patch clearly needs an update as well, but already should be the last part of the series in a currently inacceptable state.

Quoted 5 lines

This .get_clock() routine is supposed to determine the clock source, setup the desired rate and return the actual rate. The callback's API is rather limited in that it does communicate clock rate values, but cannot access a location to store handles to.

I think the API is sufficient, the ofdev links via drv data to the netdev
(http://lxr.free-electrons.com/source/drivers/net/can/mscan/mpc5xxx_can.c#L305)
and you get from the netdev to the mscan_priv
(http://lxr.free-electrons.com/source/drivers/net/can/mscan/mpc5xxx_can.c#L281).

BTW: You should prepare_enable the clock in the ndo_open() callback, i.e. mscan_open() and disable_unprepare in mscan_close(). Doing this you maximize the power saving effect by not powering the mscan IP core if the CAN device is not up.

Quoted 4 lines

Are the introduction of a .put_clock() callback and passing the 'priv' handle to both get and put routines acceptable? As this would hook up clock handling to probe() and remove() just as memory mapping gets approached.

I think an additional priv parameter is not needed. get_ and put_clock() in probe() and remove() is good, but put the prepare_enable()/disable_unprepare() in open()/close().

Quoted 4 lines

Below is a patch on top of the CAN related patch in v2 of the series. If this approach is acceptable (maybe modulo how the "unused" warnings get silenced), I'll fold it into the introduction of common clock support in the mscan(4) driver.

Marc

Signature · 12 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130719/a63fef52/attachment-0001.sig>
#61 lore raw

PATCH v2 17/24 powerpc/mpc512x: improve DIU related clock setup

In reply to Gerhard Sittig

adapt the DIU clock initialization to the COMMON_CLK approach: device tree based clock lookup, prepare and unprepare for clocks, work with frequencies not dividers, call the appropriate clk_*() routines and don't access CCM registers, remove the pre-enable workaround in the platform's clock driver

the "best clock" determination now completely relies on the platform's clock driver to pick a frequency close to what the caller requests, and merely checks whether the desired frequency was met (is acceptable since it meets the tolerance of the monitor) -- this approach shall succeed upon first try in the usual case, will test a few less desirable yet acceptable frequencies in edge cases, and will fallback to "best effort" if none of the previously tried frequencies pass the test

---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 arch/powerpc/platforms/512x/mpc512x_shared.c  |  165 +++++++++++++------------
 2 files changed, 88 insertions(+), 78 deletions(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -1
index 99d197d..b8963b7 100644
@@ -692,7 +692,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
-	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
 	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
 	/*
 	 * some have their individual clock subtree with separate clock
arch/powerpc/platforms/512x/mpc512x_shared.c +88 -77

192 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#62 lore raw

PATCH v2 18/24 i2c: mpc: OF clock lookup for MPC512x

In reply to Gerhard Sittig

make the MPC I2C driver prepare and enable the peripheral clock ('per' for register access) in the MPC512x setup routine, make this clock setup non-fatal to allow for a migration period, remove the pre-enabling hack in the platform's clock driver

---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 drivers/i2c/busses/i2c-mpc.c                  |    9 +++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -1
index b8963b7..49c52bc 100644
@@ -692,7 +692,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
-	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
drivers/i2c/busses/i2c-mpc.c +9 -0
index 7607dc0..13d6822 100644
@@ -21,6 +21,7 @@
 #include <linux/of_i2c.h>
 #include <linux/slab.h>
 
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/fsl_devices.h>
 #include <linux/i2c.h>
@@ -264,11 +265,19 @@ static void mpc_i2c_setup_512x(struct device_node *node,
 					 struct mpc_i2c *i2c,
 					 u32 clock, u32 prescaler)
 {
+	struct clk *clk;
 	struct device_node *node_ctrl;
 	void __iomem *ctrl;
 	const u32 *pval;
 	u32 idx;
 
+	/* enable clock for the I2C peripheral (non fatal) */
+	clk = of_clk_get_by_name(node, "per");
+	if (!IS_ERR(clk)) {
+		clk_prepare_enable(clk);
+		clk_put(clk);
+	}
+
 	/* Enable I2C interrupts for mpc5121 */
 	node_ctrl = of_find_compatible_node(NULL, NULL,
 					    "fsl,mpc5121-i2c-ctrl");
Signature · 1 line
1.7.10.4
#63 lore raw

PATCH v2 18/24 i2c: mpc: OF clock lookup for MPC512x

drivers/i2c/busses/i2c-mpc.c static void mpc_i2c_setup_512x(struct device_node *node, · line 280

Quoted 7 lines · Gerhard Sittig
drivers/i2c/busses/i2c-mpc.c +7 -0
+	/* enable clock for the I2C peripheral (non fatal) */
+	clk = of_clk_get_by_name(node, "per");
+	if (!IS_ERR(clk)) {
+		clk_prepare_enable(clk);
+		clk_put(clk);
+	}
+

This kind of hacked up approach to the clk API is exactly the thing I really don't like seeing. I don't know what it is... is the clk API somehow difficult to use or what's the problem with doing stuff correctly?

1. Get the clock in your probe function.
2. Prepare it at the appropriate time.
3. Enable it appropriately. (or if you want to combine 2 and 3, use clk_prepare_enable().)
4. Ensure that enables/disables and prepares/unprepares are appropriately balanced.
5. 'put' the clock in your remove function.

Certainly do not get-enable-put a clock. You're supposed to hold on to the clock all the time that you're actually using it.

Final point - if you want to make it non-fatal, don't play games like:

	clk = clk_get(whatever);
	if (IS_ERR(clk))
		clk = NULL;

	...
	if (clk)
		clk_prepare(clk);

Do this instead:

	clk = clk_get(whatever);
	...

	if (!IS_ERR(clk))
		clk_prepare(clk);

etc.

(And on this subject, I'm considering whether to make a change to the clk API where clk_prepare() and clk_enable() return zero when passed an error pointer - this means drivers with optional clocks don't have to burden themselves with these kinds of checks.)

#64 lore raw

PATCH v2 18/24 i2c: mpc: OF clock lookup for MPC512x

Quoted 22 lines · Russell King - ARM Linux

drivers/i2c/busses/i2c-mpc.c static void mpc_i2c_setup_512x(struct device_node *node, · line 280

Quoted 7 lines · Gerhard Sittig
drivers/i2c/busses/i2c-mpc.c +7 -0
+	/* enable clock for the I2C peripheral (non fatal) */
+	clk = of_clk_get_by_name(node, "per");
+	if (!IS_ERR(clk)) {
+		clk_prepare_enable(clk);
+		clk_put(clk);
+	}
+

This kind of hacked up approach to the clk API is exactly the thing I really don't like seeing. I don't know what it is... is the clk API somehow difficult to use or what's the problem with doing stuff correctly?

1. Get the clock in your probe function.
2. Prepare it at the appropriate time.
3. Enable it appropriately. (or if you want to combine 2 and 3, use clk_prepare_enable().)
4. Ensure that enables/disables and prepares/unprepares are appropriately balanced.
5. 'put' the clock in your remove function.

Quoted 2 lines

Certainly do not get-enable-put a clock. You're supposed to hold on to the clock all the time that you're actually using it.

Russel, thank you for the feedback! I agree that your outline of steps to take is simple and should not be a problem to do.

I noticed that I kept looking at the wrong spot in the driver, hooked up to some setup routine which lacks a counter part. You made me re-visit the drivers and find better locations to hook up to (probe and remove). Part of my sloppiness with immediate put after enable was caused by put being a NOP at the moment, and the assumption that clocks without references but in the enabled state won't go away. But I saw your recent message as well about how clocks shall get reference counted and keep their provider's module loaded.

I've queued an update to the I2C, ethernet, and PCI drivers, which addresses your concerns. I2C and ethernet clock handling will become correctly balanced, while PCI won't since the existing driver already lacks a remove() routine. These changes will be part of v3 of the series.

Mark, Greg, v2 of the series already addresses the above concerns for the serial communication with the PSC hardware (UART and SPI). See how 01/24 and 02/24 became much more complex than in v1, yet should result in appropriate clock handling in these drivers.

In the very minute I wanted to send out v3, I received feedback on the CAN driver manipulation from Marc. Apparently it suffers from the same problem (my blindness to locate the best spot for resource release), but CAN shall be the last driver in the series which is not acceptable yet.

Quoted 10 lines

Final point - if you want to make it non-fatal, don't play games like:

	clk = clk_get(whatever);
	if (IS_ERR(clk))
		clk = NULL;

	...
	if (clk)
		clk_prepare(clk);
Quoted 8 lines

Do this instead:

	clk = clk_get(whatever);
	...

	if (!IS_ERR(clk))
		clk_prepare(clk);

etc.

You saw this in the ethernet driver, right? This "interesting" style of "normalization to NULL" in the setup path was meant to simplify the cleanup path, but that point has become obsolete by now. Your example doesn't reflect that 'clk' was a more complex to access member in the driver's private data.

It seems that doing the setup in steps with a local variable, to only store the reference when all steps were successful, cleans up the release code paths.

Immediately putting the clock and not having stored the reference when enable failed is one more instruction before jumping to the bailout label, but eliminates the pain of tracking get and enable separately, and needing two labels for disable and put (you cannot disable a clock that wasn't enabled).

As mentioned, both the I2C driver you responded to as well as the ethernet driver you reference here got adjusted. v3 will get sent when I could address the remaining CAN driver issue.

Quoted 4 lines

(And on this subject, I'm considering whether to make a change to the clk API where clk_prepare() and clk_enable() return zero when passed an error pointer - this means drivers with optional clocks don't have to burden themselves with these kinds of checks.)

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#65 lore raw

PATCH v2 19/24 USB: fsl-mph-dr-of: OF clock lookup, prepare and enable

In reply to Gerhard Sittig

device tree based clock lookup in the MPC512x initialization (lookup 'per' for register access), add error check in the clock setup, must prepare clocks before they can get enabled, unprepare after disable

---
 drivers/usb/host/fsl-mph-dr-of.c |   24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)
drivers/usb/host/fsl-mph-dr-of.c +9 -15
index 11e0b79..eb564f3 100644
@@ -260,25 +260,19 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 	struct clk *clk;
-	char clk_name[10];
-	int base, clk_num;
-
-	base = pdev->resource->start & 0xf000;
-	if (base == 0x3000)
-		clk_num = 1;
-	else if (base == 0x4000)
-		clk_num = 2;
-	else
-		return -ENODEV;
+	int err;
 
-	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
-	clk = clk_get(&pdev->dev, clk_name);
+	clk = clk_get(&pdev->dev, "per");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clk\n");
 		return PTR_ERR(clk);
 	}
-
-	clk_enable(clk);
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(&pdev->dev, "failed to enable clk\n");
+		clk_put(clk);
+		return err;
+	}
 	pdata->clk = clk;
 
 	if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
@@ -303,7 +297,7 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
 	pdata->regs = NULL;
 
 	if (pdata->clk) {
-		clk_disable(pdata->clk);
+		clk_disable_unprepare(pdata->clk);
 		clk_put(pdata->clk);
 	}
 }
Signature · 1 line
1.7.10.4
#66 lore raw

PATCH v2 20/24 fs_enet: OF clock lookup (non-fatal), prepare and enable

In reply to Gerhard Sittig

device tree based clock lookup, must prepare clocks before enabling them, unprepare after disable, error check in the clock setup, remove the pre-enable workaround in the MPC512x platform's clock driver

this change implements non-fatal clock lookup since not all platforms provide device tree specs for clocks, but failure to enable a specified clock is considered fatal

---
 arch/powerpc/platforms/512x/clock-commonclk.c      |    1 -
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   27 +++++++++++++++++++-
 include/linux/fs_enet_pd.h                         |    3 +++
 3 files changed, 29 insertions(+), 2 deletions(-)
arch/powerpc/platforms/512x/clock-commonclk.c +0 -1
index 49c52bc..e9451a7 100644
@@ -691,7 +691,6 @@ static void mpc512x_clk_setup_clock_tree(int busfreq)
 	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
-	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +26 -1
index 8de53a1..df92e12 100644
@@ -1020,6 +1020,21 @@ static int fs_enet_probe(struct platform_device *ofdev)
 		fpi->cp_command = *data;
 	}
 
+	/* make clock lookup non-fatal (the driver is shared among platforms),
+	 * but require enable to succeed when a clock was specified/found
+	 */
+	fpi->clk_per = clk_get(&ofdev->dev, "per");
+	if (IS_ERR(fpi->clk_per))
+		fpi->clk_per = NULL;
+	if (fpi->clk_per) {
+		int err;
+		err = clk_prepare_enable(fpi->clk_per);
+		if (err) {
+			ret = err;
+			goto out_clk_put;
+		}
+	}
+
 	fpi->rx_ring = 32;
 	fpi->tx_ring = 32;
 	fpi->rx_copybreak = 240;
@@ -1028,7 +1043,7 @@ static int fs_enet_probe(struct platform_device *ofdev)
 	fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0);
 	if ((!fpi->phy_node) && (!of_get_property(ofdev->dev.of_node, "fixed-link",
 						  NULL)))
-		goto out_free_fpi;
+		goto out_clk_dis;
 
 	if (of_device_is_compatible(ofdev->dev.of_node, "fsl,mpc5125-fec")) {
 		phy_connection_type = of_get_property(ofdev->dev.of_node,
@@ -1108,6 +1123,12 @@ out_free_dev:
 	free_netdev(ndev);
 out_put:
 	of_node_put(fpi->phy_node);
+out_clk_dis:
+	if (fpi->clk_per)
+		clk_disable_unprepare(fpi->clk_per);
+out_clk_put:
+	if (fpi->clk_per)
+		clk_put(fpi->clk_per);
 out_free_fpi:
 	kfree(fpi);
 	return ret;
@@ -1124,6 +1145,10 @@ static int fs_enet_remove(struct platform_device *ofdev)
 	fep->ops->cleanup_data(ndev);
 	dev_set_drvdata(fep->dev, NULL);
 	of_node_put(fep->fpi->phy_node);
+	if (fep->fpi->clk_per) {
+		clk_disable_unprepare(fep->fpi->clk_per);
+		clk_put(fep->fpi->clk_per);
+	}
 	free_netdev(ndev);
 	return 0;
 }
include/linux/fs_enet_pd.h +3 -0
index 51b7934..a978d0d 100644
@@ -16,6 +16,7 @@
 #ifndef FS_ENET_PD_H
 #define FS_ENET_PD_H
 
+#include <linux/clk.h>
 #include <linux/string.h>
 #include <linux/of_mdio.h>
 #include <asm/types.h>
@@ -142,6 +143,8 @@ struct fs_platform_info {
 
 	int use_rmii;		/* use RMII mode 	       */
 	int has_phy;            /* if the network is phy container as well...*/
+
+	struct clk *clk_per;	/* 'per' clock for register access */
 };
 struct fs_mii_fec_platform_info {
 	u32 irq[32];
Signature · 1 line
1.7.10.4
#67 lore raw

PATCH v2 21/24 fsl-viu: OF clock lookup, prepare before enable

In reply to Gerhard Sittig

device tree based clock lookup, must prepare clocks before enabling them, unprepare after disable, error check in the clock setup

---
 drivers/media/platform/fsl-viu.c |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/media/platform/fsl-viu.c +8 -4
index 221ec42..b95aa43 100644
@@ -1582,8 +1582,11 @@ static int viu_of_probe(struct platform_device *op)
 		dev_err(&op->dev, "failed to find the clock module!\n");
 		ret = -ENODEV;
 		goto err_clk;
-	} else {
-		clk_enable(viu_dev->clk);
+	}
+	ret = clk_prepare_enable(viu_dev->clk);
+	if (ret) {
+		dev_err(&op->dev, "failed to enable the clock!\n");
+		goto err_clk_put;
 	}
 
 	/* reset VIU module */
@@ -1602,7 +1605,8 @@ static int viu_of_probe(struct platform_device *op)
 	return ret;
 
 err_irq:
-	clk_disable(viu_dev->clk);
+	clk_disable_unprepare(viu_dev->clk);
+err_clk_put:
 	clk_put(viu_dev->clk);
 err_clk:
 	video_unregister_device(viu_dev->vdev);
@@ -1626,7 +1630,7 @@ static int viu_of_remove(struct platform_device *op)
 	free_irq(dev->irq, (void *)dev);
 	irq_dispose_mapping(dev->irq);
 
-	clk_disable(dev->clk);
+	clk_disable_unprepare(dev->clk);
 	clk_put(dev->clk);
 
 	video_unregister_device(dev->vdev);
Signature · 1 line
1.7.10.4
#68 lore raw

PATCH v2 22/24 powerpc/fsl-pci: OF clock lookup, prepare before enable

In reply to Gerhard Sittig

device tree based clock lookup, must prepare clocks before enabling them, error check in the clock setup

this change implements non-fatal clock lookup for compatibility with platforms that don't provide OF clock specs, but failure to enable a specified clock is considered fatal

---
 arch/powerpc/sysdev/fsl_pci.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/powerpc/sysdev/fsl_pci.c +15 -0
index 46ac1dd..cb2ed92 100644
@@ -17,6 +17,8 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
+
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -741,6 +743,7 @@ err0:
 
 int __init mpc83xx_add_bridge(struct device_node *dev)
 {
+	struct clk *clk;
 	int ret;
 	int len;
 	struct pci_controller *hose;
@@ -758,6 +761,18 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
 	}
 	pr_debug("Adding PCI host bridge %s\n", dev->full_name);
 
+	/* non-fatal OF clock lookup, but fatal when a clock
+	 * was specified yet could not get enabled */
+	clk = of_clk_get_by_name(dev, "per");
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		clk_put(clk);
+		if (ret) {
+			pr_err("Could not enable peripheral clock\n");
+			return ret;
+		}
+	}
+
 	/* Fetch host bridge registers address */
 	if (of_address_to_resource(dev, 0, &rsrc_reg)) {
 		printk(KERN_WARNING "Can't get pci register base!\n");
Signature · 1 line
1.7.10.4
#69 lore raw

PATCH v2 23/24 clk: mpc512x: switch to COMMON_CLK, remove PPC_CLOCK

In reply to Gerhard Sittig

completely switch to, i.e. unconditionally use COMMON_CLK for the MPC512x platform, and retire the PPC_CLOCK implementation for that platform after the transition has completed

---
 arch/powerpc/platforms/512x/Kconfig  |   14 +-
 arch/powerpc/platforms/512x/Makefile |    3 +-
 arch/powerpc/platforms/512x/clock.c  |  753 ----------------------------------
 3 files changed, 2 insertions(+), 768 deletions(-)
 delete mode 100644 arch/powerpc/platforms/512x/clock.c
arch/powerpc/platforms/512x/Kconfig +1 -13
index c5fcdd0..5aa3f4b 100644
@@ -1,21 +1,9 @@
-config MPC512x_COMMON_CLK
-	bool "MPC512x platform uses COMMON_CLK"
-	default y
-	depends on PPC_MPC512x
-	help
-	  This option is only here to support tests and comparison
-	  during development and migration.  This option will get
-	  removed after the COMMON_CLK support for MPC512x has become
-	  fully operational and all drivers were adjusted to explicitly
-	  acquire their required clocks.
-
 config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
+	select COMMON_CLK
 	select FSL_SOC
 	select IPIC
-	select PPC_CLOCK if !MPC512x_COMMON_CLK
-	select COMMON_CLK if MPC512x_COMMON_CLK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
arch/powerpc/platforms/512x/Makefile +1 -2
index 1e05f9d..bb20116 100644
@@ -1,8 +1,7 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-$(CONFIG_PPC_CLOCK)		+= clock.o
-obj-$(CONFIG_COMMON_CLK)	+= clock-commonclk.o
+obj-y				+= clock-commonclk.o
 obj-y				+= mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)	+= mpc512x_generic.o
arch/powerpc/platforms/512x/clock.c deleted +0 -753

753 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#70 lore raw

PATCH v2 24/24 net: can: mscan: remove MPC512x non-COMMON_CLK code path

In reply to Gerhard Sittig

transition to the COMMON_CLK framework has completed for the MPC512x platform, remove the now obsolete code path of the mpc5xxx mscan driver which accessed clock control module registers directly

---
 drivers/net/can/mscan/mpc5xxx_can.c |  136 -----------------------------------
 1 file changed, 136 deletions(-)
drivers/net/can/mscan/mpc5xxx_can.c +0 -136
index dd26ab6..cf5e4cfc 100644
@@ -108,9 +108,6 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
-
-#if IS_ENABLED(CONFIG_COMMON_CLK)
-
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_source, int *mscan_clksrc)
 {
@@ -244,139 +241,6 @@ err_notavail:
 	dev_err(&ofdev->dev, "cannot acquire or setup clock source\n");
 	return 0;
 }
-#else	/* COMMON_CLK */
-struct mpc512x_clockctl {
-	u32 spmr;		/* System PLL Mode Reg */
-	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
-	u32 scfr1;		/* System Clk Freq Reg 1 */
-	u32 scfr2;		/* System Clk Freq Reg 2 */
-	u32 reserved;
-	u32 bcr;		/* Bread Crumb Reg */
-	u32 pccr[12];		/* PSC Clk Ctrl Reg 0-11 */
-	u32 spccr;		/* SPDIF Clk Ctrl Reg */
-	u32 cccr;		/* CFM Clk Ctrl Reg */
-	u32 dccr;		/* DIU Clk Cnfg Reg */
-	u32 mccr[4];		/* MSCAN Clk Ctrl Reg 1-3 */
-};
-
-static struct of_device_id mpc512x_clock_ids[] = {
-	{ .compatible = "fsl,mpc5121-clock", },
-	{}
-};
-
-static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
-				 const char *clock_name, int *mscan_clksrc)
-{
-	struct mpc512x_clockctl __iomem *clockctl;
-	struct device_node *np_clock;
-	struct clk *sys_clk, *ref_clk;
-	int plen, clockidx, clocksrc = -1;
-	u32 sys_freq, val, clockdiv = 1, freq = 0;
-	const u32 *pval;
-
-	np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
-	if (!np_clock) {
-		dev_err(&ofdev->dev, "couldn't find clock node\n");
-		return 0;
-	}
-	clockctl = of_iomap(np_clock, 0);
-	if (!clockctl) {
-		dev_err(&ofdev->dev, "couldn't map clock registers\n");
-		goto exit_put;
-	}
-
-	/* Determine the MSCAN device index from the peripheral's
-	 * physical address. Register address offsets against the
-	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
-	 */
-	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
-	BUG_ON(!pval || plen < sizeof(*pval));
-	clockidx = (*pval & 0x80) ? 1 : 0;
-	if (*pval & 0x2000)
-		clockidx += 2;
-
-	/*
-	 * Clock source and divider selection: 3 different clock sources
-	 * can be selected: "ip", "ref" or "sys". For the latter two, a
-	 * clock divider can be defined as well. If the clock source is
-	 * not specified by the device tree, we first try to find an
-	 * optimal CAN source clock based on the system clock. If that
-	 * is not posslible, the reference clock will be used.
-	 */
-	if (clock_name && !strcmp(clock_name, "ip")) {
-		*mscan_clksrc = MSCAN_CLKSRC_IPS;
-		freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
-	} else {
-		*mscan_clksrc = MSCAN_CLKSRC_BUS;
-
-		pval = of_get_property(ofdev->dev.of_node,
-				       "fsl,mscan-clock-divider", &plen);
-		if (pval && plen == sizeof(*pval))
-			clockdiv = *pval;
-		if (!clockdiv)
-			clockdiv = 1;
-
-		if (!clock_name || !strcmp(clock_name, "sys")) {
-			sys_clk = clk_get(&ofdev->dev, "sys_clk");
-			if (IS_ERR(sys_clk)) {
-				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
-				goto exit_unmap;
-			}
-			/* Get and round up/down sys clock rate */
-			sys_freq = 1000000 *
-				((clk_get_rate(sys_clk) + 499999) / 1000000);
-
-			if (!clock_name) {
-				/* A multiple of 16 MHz would be optimal */
-				if ((sys_freq % 16000000) == 0) {
-					clocksrc = 0;
-					clockdiv = sys_freq / 16000000;
-					freq = sys_freq / clockdiv;
-				}
-			} else {
-				clocksrc = 0;
-				freq = sys_freq / clockdiv;
-			}
-		}
-
-		if (clocksrc < 0) {
-			ref_clk = clk_get(&ofdev->dev, "ref_clk");
-			if (IS_ERR(ref_clk)) {
-				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
-				goto exit_unmap;
-			}
-			clocksrc = 1;
-			freq = clk_get_rate(ref_clk) / clockdiv;
-		}
-	}
-
-	/* Disable clock */
-	out_be32(&clockctl->mccr[clockidx], 0x0);
-	if (clocksrc >= 0) {
-		/* Set source and divider */
-		val = (clocksrc << 14) | ((clockdiv - 1) << 17);
-		out_be32(&clockctl->mccr[clockidx], val);
-		/* Enable clock */
-		out_be32(&clockctl->mccr[clockidx], val | 0x10000);
-	}
-
-	/* Enable MSCAN clock domain */
-	val = in_be32(&clockctl->sccr[1]);
-	if (!(val & (1 << 25)))
-		out_be32(&clockctl->sccr[1], val | (1 << 25));
-
-	dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
-		*mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
-		clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
-
-exit_unmap:
-	iounmap(clockctl);
-exit_put:
-	of_node_put(np_clock);
-	return freq;
-}
-#endif	/* COMMON_CLK */
-
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 				 const char *clock_name, int *mscan_clksrc)
Signature · 1 line
1.7.10.4
#71 lore raw

v3 cover add COMMON_CLK support for PowerPC MPC512x

In reply to Gerhard Sittig

this series
- fixes several drivers that are used in the MPC512x platform (UART, SPI, ethernet, PCI, USB, CAN, NAND flash, video capture) in how they handle clocks (appropriately acquire and setup them, hold references during use, release clocks after use)
- introduces support for the common clock framework (CCF, COMMON_CLK Kconfig option) in the PowerPC based MPC512x platform, which brings device tree based clock lookup as well

although the series does touch several subsystems -- tty (serial), spi, net (can, fs_enet), mtd (nfc), usb, i2c, media (viu), and dts -- all of the patches are strictly clock related

it appears most appropriate to take this series through either the clk or the powerpc trees after it has passed review and other subsystem maintainers ACKed the clock setup related driver modifications

the series passes 'checkpatch.pl --strict' except for one warning which cannot get resolved, since that either breaks compilation (the data type is preset by the clk-provider.h API) or requires a cast which shadows real mismatches:

WARNING: static const char * array should probably be static const char * const #436: FILE: arch/powerpc/platforms/512x/clock-commonclk.c:335:
+static const char *parent_names_mux0[] = {

total: 0 errors, 1 warnings, 0 checks, 845 lines checked

each step in the series was build and run tested (with a display that is attached to the DIU as well as SPI, with an SPI attached NOR flash, with multiple UART ports such that one is not the boot console, with EEPROMs attached to I2C, with an SD card, booting from network)

changes in v3:
- rebase the series against v3.11-rc2
- re-ordered the series to first address all general clock handling concerns in existing drivers, before introducing common clock support in the platform's clock driver
- slightly rework the SPI (01/31), UART (02/31), and PSC FIFO (23/31) clock handling in comparison to v2 which introduced those fixes (devm_{get,put}_clk() calls, fewer goto labels in error paths)
- fix and improve clock handling (balance allocation and release of clocks, check for errors during setup) in all of the other drivers which this series has touched before in naive ways: USB (03/31), NAND flash (04/31), video capture (05/31), I2C (06/31), ethernet (08/31), PCI (09/31), CAN (11/31)
- silence a build warning in the ethernet driver (07/31)
- eliminate all PPC_CLOCK references, use 'per' clock names for NAND flash (25/31) and VIU (26/31) as well
- unbreak CAN operation for the period between introducing common clock support in the platform's clock driver and introducing common clock support in the CAN peripheral driver as well as providing clock specs in the device tree (provide clkdev aliases for SYS and REF)
- improve common clock support for CAN (devm_{get,put}_clk() calls, check enable() errors, keep a reference to used clocks, disable and put clocks after use)
- reworded several commit messages to better reflect the kind of change and because fixes were applied before adding common infrastructure support
- point to individual numbered patches of the series in the list of changes for v2 as well

changes in v2:
- cleanup of the UART (02/24) and SPI (01/24) clock handling before the introduction of common clock support for the platform, as incomplete clock handling becomes fatal or more dangerous later (which in turn changes the context of the "device tree lookup only" followup patch later)
- reordered the sequence of patches to keep the serial communication related parts together (UART, SPI, and PSC FIFO changes after common clock support was introduced, which have become 11-14/24 now)
- updated commit messages for the clock API use cleanup in the serial communication drivers, updated comments and reworded commit messages in the core clock driver to expand on the pre-enable workaround and clkdev registration (09/24)
- keep a reference to the PSC FIFO clock during use instead of looking up the clock again in the uninit() routine (14/24)
- remove the clkdev.h header file inclusion directive with the removal of the clkdev registration call (13/24)

Gerhard Sittig (31):
spi: mpc512x: cleanup clock API use
serial: mpc512x: cleanup clock API use
USB: fsl-mph-dr-of: cleanup clock API use
mtd: mpc5121_nfc: cleanup clock API use
[media] fsl-viu: cleanup clock API use
i2c: mpc: cleanup clock API use
fs_enet: silence a build warning (unused variable)
fs_enet: cleanup clock API use
powerpc/fsl-pci: improve clock API use
net: can: mscan: add a comment on reg to idx mapping
net: can: mscan: improve clock API use
powerpc: mpc512x: array decl for MCLK registers in CCM
clk: wrap I/O access for improved portability
dts: mpc512x: prepare for preprocessor support
dts: mpc512x: introduce dt-bindings/clock/ header
dts: mpc512x: add clock related device tree specs
clk: mpc512x: introduce COMMON_CLK for MPC512x
dts: mpc512x: add clock specs for client lookups
clk: mpc512x: don't pre-enable FEC and I2C clocks
spi: mpc512x: remove now obsolete clock lookup name
serial: mpc512x: remove now obsolete clock lookup name
clk: mpc512x: remove clkdev registration (uart, spi)
serial: mpc512x: setup the PSC FIFO clock as well
USB: fsl-mph-dr-of: remove now obsolete clock lookup name
mtd: mpc5121_nfc: remove now obsolete clock lookup name [media] fsl-viu: remove now obsolete clock lookup name
net: can: mscan: add common clock support for mpc512x powerpc/mpc512x: improve DIU related clock setup
clk: mpc512x: switch to COMMON_CLK, remove PPC_CLOCK
net: can: mscan: remove non-common_clock code for MPC512x
clk: mpc512x: remove clkdev registration (sys/ref, header)

 arch/powerpc/boot/dts/ac14xx.dts                   |    9 +-
 arch/powerpc/boot/dts/include/dt-bindings          |    1 +
 arch/powerpc/boot/dts/mpc5121.dtsi                 |   94 ++-
 arch/powerpc/boot/dts/mpc5121ads.dts               |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts                 |    2 +-
 arch/powerpc/include/asm/mpc5121.h                 |   18 +-
 arch/powerpc/platforms/512x/Kconfig                |    2 +-
 arch/powerpc/platforms/512x/Makefile               |    3 +-
 arch/powerpc/platforms/512x/clock-commonclk.c      |  761 ++++++++++++++++++++
 arch/powerpc/platforms/512x/clock.c                |  753 -------------------
 arch/powerpc/platforms/512x/mpc512x_shared.c       |  165 +++--
 arch/powerpc/sysdev/fsl_pci.c                      |   23 +
 drivers/clk/clk-divider.c                          |    6 +-
 drivers/clk/clk-gate.c                             |    6 +-
 drivers/clk/clk-mux.c                              |    6 +-
 drivers/i2c/busses/i2c-mpc.c                       |   28 +
 drivers/media/platform/fsl-viu.c                   |   26 +-
 drivers/mtd/nand/mpc5121_nfc.c                     |   20 +-
 drivers/net/can/mscan/mpc5xxx_can.c                |  271 ++++---
 drivers/net/can/mscan/mscan.c                      |    9 +
 drivers/net/can/mscan/mscan.h                      |    2 +
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   26 +-
 drivers/spi/spi-mpc512x-psc.c                      |   48 +-
 drivers/tty/serial/mpc52xx_uart.c                  |  144 +++-
 drivers/usb/host/fsl-mph-dr-of.c                   |   26 +-
 include/dt-bindings/clock/mpc512x-clock.h          |   59 ++
 include/linux/clk-provider.h                       |   33 +
 include/linux/fs_enet_pd.h                         |    3 +
 28 files changed, 1493 insertions(+), 1053 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
 delete mode 100644 arch/powerpc/platforms/512x/clock.c
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
# uname -srm
Linux 3.11.0-rc2-00031-ge72cd55 ppc
# cat /sys/kernel/debug/clk/clk_summary
   clock                        enable_cnt  prepare_cnt  rate
---------------------------------------------------------------------
 ac97                           0           0            24567000
 spdif_rx_in                    0           0            0
 spdif_tx_in                    0           0            0
 psc_mclk_in                    0           0            25000000
 dummy                          1           1            0
 osc                            1           1            25000000
    ref                         1           1            25000000
       sys                      10          10           320000000
          spdif-mux0            0           0            320000000
             spdif-en0          0           0            320000000
                spdif_mclk_div  0           0            80000000
                   spdif_mclk_out 0           0            80000000
                      spdif_mclk 0           0            80000000
          mscan3-mux0           1           1            320000000
             mscan3-en0         1           1            320000000
                mscan3_mclk_div 1           1            80000000
                   mscan3_mclk_out 1           1            80000000
                      mscan3_mclk 1           1            80000000
          mscan2-mux0           1           1            320000000
             mscan2-en0         1           1            320000000
                mscan2_mclk_div 1           1            80000000
                   mscan2_mclk_out 1           1            80000000
                      mscan2_mclk 1           1            80000000
          mscan1-mux0           1           1            320000000
             mscan1-en0         1           1            320000000
                mscan1_mclk_div 1           1            16000000
                   mscan1_mclk_out 1           1            16000000
                      mscan1_mclk 1           2            16000000
          mscan0-mux0           1           1            320000000
             mscan0-en0         1           1            320000000
                mscan0_mclk_div 1           1            16000000
                   mscan0_mclk_out 1           1            16000000
                      mscan0_mclk 1           2            16000000
          psc11-mux0            0           0            320000000
             psc11-en0          0           0            320000000
                psc11_mclk_div  0           0            80000000
                   psc11_mclk_out 0           0            80000000
                      psc11_mclk 0           0            80000000
          psc10-mux0            0           0            320000000
             psc10-en0          0           0            320000000
                psc10_mclk_div  0           0            80000000
                   psc10_mclk_out 0           0            80000000
                      psc10_mclk 0           0            80000000
          psc9-mux0             0           0            320000000
             psc9-en0           0           0            320000000
                psc9_mclk_div   0           0            80000000
                   psc9_mclk_out 0           0            80000000
                      psc9_mclk 0           0            80000000
          psc8-mux0             0           0            320000000
             psc8-en0           0           0            320000000
                psc8_mclk_div   0           0            80000000
                   psc8_mclk_out 0           0            80000000
                      psc8_mclk 0           0            80000000
          psc7-mux0             1           1            320000000
             psc7-en0           1           1            320000000
                psc7_mclk_div   1           1            80000000
                   psc7_mclk_out 1           1            80000000
                      psc7_mclk 1           1            80000000
          psc6-mux0             0           0            320000000
             psc6-en0           0           0            320000000
                psc6_mclk_div   0           0            80000000
                   psc6_mclk_out 0           0            80000000
                      psc6_mclk 0           0            80000000
          psc5-mux0             1           1            320000000
             psc5-en0           1           1            320000000
                psc5_mclk_div   1           1            80000000
                   psc5_mclk_out 1           1            80000000
                      psc5_mclk 1           1            80000000
          psc4-mux0             1           1            320000000
             psc4-en0           1           1            320000000
                psc4_mclk_div   1           1            80000000
                   psc4_mclk_out 1           1            80000000
                      psc4_mclk 1           1            80000000
          psc3-mux0             1           1            320000000
             psc3-en0           1           1            320000000
                psc3_mclk_div   1           1            80000000
                   psc3_mclk_out 1           1            80000000
                      psc3_mclk 2           2            80000000
          psc2-mux0             0           0            320000000
             psc2-en0           0           0            320000000
                psc2_mclk_div   0           0            80000000
                   psc2_mclk_out 0           0            80000000
                      psc2_mclk 0           0            80000000
          psc1-mux0             0           0            320000000
             psc1-en0           0           0            320000000
                psc1_mclk_div   0           0            80000000
                   psc1_mclk_out 0           0            80000000
                      psc1_mclk 0           0            80000000
          psc0-mux0             0           0            320000000
             psc0-en0           0           0            320000000
                psc0_mclk_div   0           0            80000000
                   psc0_mclk_out 0           0            80000000
                      psc0_mclk 0           0            80000000
          ddr-ug                1           1            160000000
             ddr                1           1            160000000
          csb                   4           4            160000000
             viu                0           0            160000000
             iim                0           0            160000000
             usb2               0           0            160000000
             usb1               0           0            160000000
             axe                0           0            160000000
             pci-ug             0           0            26666666
                pci             0           0            26666666
             mbx-bus-ug         0           0            80000000
                mbx-bus         0           0            80000000
                mbx-ug          0           0            80000000
                   mbx          0           0            80000000
                   mbx-3d-ug    0           0            80000000
                      mbx-3d    0           0            80000000
             e300               1           1            400000000
             diu-x4             1           1            640000000
                diu-ug          1           1            2509803
                   diu          2           2            2509803
             sdhc-x4            1           1            640000000
                sdhc-ug         1           1            53333333
                   sdhc-2       0           0            53333333
                   sdhc         1           1            53333333
             ips                7           7            80000000
                i2c             3           3            80000000
                mem             1           1            80000000
                fec             1           1            80000000
                sata            0           0            80000000
                psc-fifo        1           1            80000000
                pata            0           0            80000000
                lpc-ug          1           1            40000000
                   lpc          1           1            40000000
                nfc-ug          0           0            40000000
                   nfc          0           0            40000000
Signature · 1 line
1.7.10.4
#72 lore raw

PATCH v3 1/31 spi: mpc512x: cleanup clock API use

cleanup the MPC512x SoC's SPI master's use of the clock API
- get, prepare, and enable the MCLK during probe; disable, unprepare and put the MCLK upon remove; hold a reference to the clock over the period of use
- fetch MCLK rate (reference) once during probe and slightly reword BCLK (bitrate) determination to reduce redundancy as well as to not exceed the maximum text line length
- stick with the PPC_CLOCK 'psc%d_mclk' name for clock lookup, only switch to a fixed string later after device tree based clock lookup will have become available

---
 drivers/spi/spi-mpc512x-psc.c |   52 +++++++++++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 18 deletions(-)
drivers/spi/spi-mpc512x-psc.c +34 -18
index 29fce6a..823e5e0 100644
@@ -38,7 +38,8 @@ struct mpc512x_psc_spi {
 	struct mpc512x_psc_fifo __iomem *fifo;
 	unsigned int irq;
 	u8 bits_per_word;
-	u32 mclk;
+	struct clk *clk_mclk;
+	u32 mclk_rate;
 
 	struct completion txisrdone;
 };
@@ -72,6 +73,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
 	struct mpc52xx_psc __iomem *psc = mps->psc;
 	u32 sicr;
 	u32 ccr;
+	int speed;
 	u16 bclkdiv;
 
 	sicr = in_be32(&psc->sicr);
@@ -95,10 +97,10 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
 
 	ccr = in_be32(&psc->ccr);
 	ccr &= 0xFF000000;
-	if (cs->speed_hz)
-		bclkdiv = (mps->mclk / cs->speed_hz) - 1;
-	else
-		bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	speed = cs->speed_hz;
+	if (!speed)
+		speed = 1000000;	/* default 1MHz */
+	bclkdiv = (mps->mclk_rate / speed) - 1;
 
 	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
 	out_be32(&psc->ccr, ccr);
@@ -386,19 +388,11 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 {
 	struct mpc52xx_psc __iomem *psc = mps->psc;
 	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
-	struct clk *spiclk;
-	int ret = 0;
-	char name[32];
 	u32 sicr;
 	u32 ccr;
+	int speed;
 	u16 bclkdiv;
 
-	sprintf(name, "psc%d_mclk", master->bus_num);
-	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
-	mps->mclk = clk_get_rate(spiclk);
-	clk_put(spiclk);
-
 	/* Reset the PSC into a known state */
 	out_8(&psc->command, MPC52xx_PSC_RST_RX);
 	out_8(&psc->command, MPC52xx_PSC_RST_TX);
@@ -425,7 +419,8 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
 	ccr = in_be32(&psc->ccr);
 	ccr &= 0xFF000000;
-	bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	speed = 1000000;	/* default 1MHz */
+	bclkdiv = (mps->mclk_rate / speed) - 1;
 	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
 	out_be32(&psc->ccr, ccr);
 
@@ -445,7 +440,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
 
 	mps->bits_per_word = 8;
 
-	return ret;
+	return 0;
 }
 
 static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
@@ -479,6 +474,9 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 	struct spi_master *master;
 	int ret;
 	void *tempp;
+	int psc_num;
+	char clk_name[16];
+	struct clk *clk;
 
 	master = spi_alloc_master(dev, sizeof *mps);
 	if (master == NULL)
@@ -521,16 +519,32 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 		goto free_master;
 	init_completion(&mps->txisrdone);
 
+	psc_num = master->bus_num;
+	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+	clk = devm_clk_get(dev, clk_name);
+	if (IS_ERR(clk))
+		goto free_irq;
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		devm_clk_put(dev, clk);
+		goto free_irq;
+	}
+	mps->clk_mclk = clk;
+	mps->mclk_rate = clk_get_rate(clk);
+
 	ret = mpc512x_psc_spi_port_config(master, mps);
 	if (ret < 0)
-		goto free_irq;
+		goto free_clock;
 
 	ret = spi_register_master(master);
 	if (ret < 0)
-		goto free_irq;
+		goto free_clock;
 
 	return ret;
 
+free_clock:
+	clk_disable_unprepare(mps->clk_mclk);
+	devm_clk_put(dev, mps->clk_mclk);
 free_irq:
 	free_irq(mps->irq, mps);
 free_master:
@@ -547,6 +561,8 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
 	struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
 
 	spi_unregister_master(master);
+	clk_disable_unprepare(mps->clk_mclk);
+	devm_clk_put(dev, mps->clk_mclk);
 	free_irq(mps->irq, mps);
 	if (mps->psc)
 		iounmap(mps->psc);
Signature · 1 line
1.7.10.4
maintainer
#73 lore raw

PATCH v3 1/31 spi: mpc512x: cleanup clock API use

drivers/spi/spi-mpc512x-psc.c static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, · line 530

Quoted 4 lines · Gerhard Sittig
drivers/spi/spi-mpc512x-psc.c +4 -0
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		devm_clk_put(dev, clk);
+		goto free_irq;

The main point of the devm_ APIs is to avoid the need for explicit
freeing so you should just remove these puts.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130722/d3cc5152/attachment.sig>

#74 lore raw

PATCH v3 1/31 spi: mpc512x: cleanup clock API use

[ devicetree at vger adjusted ]

Quoted 10 lines · Mark Brown

drivers/spi/spi-mpc512x-psc.c static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, · line 530

Quoted 4 lines · Gerhard Sittig
drivers/spi/spi-mpc512x-psc.c +4 -0
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		devm_clk_put(dev, clk);
+		goto free_irq;

The main point of the devm_ APIs is to avoid the need for explicit freeing so you should just remove these puts.

OK, will do in v4.

Shall these get removed everywhere including regular shutdown paths, or just from error paths during setup?

[ the same topic came up for the CAN patch, might answer there ]

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#75 lore raw

PATCH v3 2/31 serial: mpc512x: cleanup clock API use

In reply to Gerhard Sittig

cleanup the clock API use of the UART driver which is shared among the MPC512x and the MPC5200 platforms
- get, prepare, and enable the MCLK during port allocation; disable, unprepare and put the MCLK upon port release; hold a reference to the clock over the period of use; check for and propagate enable errors
- fix a buffer overflow for clock names with two digit PSC index numbers
- stick with the PPC_CLOCK 'psc%d_mclk' name for clock lookup, only switch to a fixed string later after device tree based clock lookup will have become available

to achieve support for MPC512x which is neutral to MPC5200, the modification was done as follows
- introduce "clock alloc" and "clock release" routines in addition to the previous "clock enable/disable" routine in the psc_ops struct
- make the clock allocation a part of the port request (resource allocation), and make clock release a part of the port release, such that essential resources get allocated early
- just enable/disable the clock from within the .clock() callback without any allocation or preparation as the former implementation did, since this routine is called from within the startup and shutdown callbacks
- all of the above remains a NOP for the MPC5200 platform (no callbacks are provided on that platform)
- implementation note: the clock gets enabled upon allocation already just in case the clock is not only required for bitrate generation but for register access as well

---
 drivers/tty/serial/mpc52xx_uart.c |  100 ++++++++++++++++++++++++++++++-------
 1 file changed, 83 insertions(+), 17 deletions(-)
drivers/tty/serial/mpc52xx_uart.c +83 -17
index e1280a2..8f16ed9 100644
@@ -107,6 +107,8 @@ struct psc_ops {
 	unsigned int	(*set_baudrate)(struct uart_port *port,
 					struct ktermios *new,
 					struct ktermios *old);
+	int		(*clock_alloc)(struct uart_port *port);
+	void		(*clock_relse)(struct uart_port *port);
 	int		(*clock)(struct uart_port *port, int enable);
 	int		(*fifoc_init)(void);
 	void		(*fifoc_uninit)(void);
@@ -616,31 +618,75 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
 	return IRQ_NONE;
 }
 
-static int mpc512x_psc_clock(struct uart_port *port, int enable)
+static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
+
+/* called from within the .request_port() callback (allocation) */
+static int mpc512x_psc_alloc_clock(struct uart_port *port)
 {
-	struct clk *psc_clk;
 	int psc_num;
-	char clk_name[10];
+	char clk_name[16];
+	struct clk *clk;
+	int err;
+
+	psc_num = (port->mapbase & 0xf00) >> 8;
+	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+	clk = devm_clk_get(port->dev, clk_name);
+	if (IS_ERR(clk)) {
+		dev_err(port->dev, "Failed to get MCLK!\n");
+		return PTR_ERR(clk);
+	}
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(port->dev, "Failed to enable MCLK!\n");
+		devm_clk_put(port->dev, clk);
+		return err;
+	}
+	psc_mclk_clk[psc_num] = clk;
+	return 0;
+}
+
+/* called from within the .release_port() callback (release) */
+static void mpc512x_psc_relse_clock(struct uart_port *port)
+{
+	int psc_num;
+	struct clk *clk;
+
+	psc_num = (port->mapbase & 0xf00) >> 8;
+	clk = psc_mclk_clk[psc_num];
+	if (clk) {
+		clk_disable_unprepare(clk);
+		devm_clk_put(port->dev, clk);
+		psc_mclk_clk[psc_num] = NULL;
+	}
+}
+
+/* implementation of the .clock() callback (enable/disable) */
+static int mpc512x_psc_endis_clock(struct uart_port *port, int enable)
+{
+	int psc_num;
+	struct clk *psc_clk;
+	int ret;
 
 	if (uart_console(port))
 		return 0;
 
 	psc_num = (port->mapbase & 0xf00) >> 8;
-	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-	psc_clk = clk_get(port->dev, clk_name);
-	if (IS_ERR(psc_clk)) {
+	psc_clk = psc_mclk_clk[psc_num];
+	if (!psc_clk) {
 		dev_err(port->dev, "Failed to get PSC clock entry!\n");
 		return -ENODEV;
 	}
 
-	dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
-
-	if (enable)
-		clk_enable(psc_clk);
-	else
+	dev_dbg(port->dev, "mclk %sable\n", enable ? "en" : "dis");
+	if (enable) {
+		ret = clk_enable(psc_clk);
+		if (ret)
+			dev_err(port->dev, "Failed to enable MCLK!\n");
+		return ret;
+	} else {
 		clk_disable(psc_clk);
-
-	return 0;
+		return 0;
+	}
 }
 
 static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
@@ -873,7 +919,9 @@ static struct psc_ops mpc5125_psc_ops = {
 	.cw_disable_ints = mpc5125_psc_cw_disable_ints,
 	.cw_restore_ints = mpc5125_psc_cw_restore_ints,
 	.set_baudrate = mpc5125_psc_set_baudrate,
-	.clock = mpc512x_psc_clock,
+	.clock_alloc = mpc512x_psc_alloc_clock,
+	.clock_relse = mpc512x_psc_relse_clock,
+	.clock = mpc512x_psc_endis_clock,
 	.fifoc_init = mpc512x_psc_fifoc_init,
 	.fifoc_uninit = mpc512x_psc_fifoc_uninit,
 	.get_irq = mpc512x_psc_get_irq,
@@ -906,7 +954,9 @@ static struct psc_ops mpc512x_psc_ops = {
 	.cw_disable_ints = mpc512x_psc_cw_disable_ints,
 	.cw_restore_ints = mpc512x_psc_cw_restore_ints,
 	.set_baudrate = mpc512x_psc_set_baudrate,
-	.clock = mpc512x_psc_clock,
+	.clock_alloc = mpc512x_psc_alloc_clock,
+	.clock_relse = mpc512x_psc_relse_clock,
+	.clock = mpc512x_psc_endis_clock,
 	.fifoc_init = mpc512x_psc_fifoc_init,
 	.fifoc_uninit = mpc512x_psc_fifoc_uninit,
 	.get_irq = mpc512x_psc_get_irq,
@@ -1166,6 +1216,9 @@ mpc52xx_uart_type(struct uart_port *port)
 static void
 mpc52xx_uart_release_port(struct uart_port *port)
 {
+	if (psc_ops->clock_relse)
+		psc_ops->clock_relse(port);
+
 	/* remapped by us ? */
 	if (port->flags & UPF_IOREMAP) {
 		iounmap(port->membase);
@@ -1190,11 +1243,24 @@ mpc52xx_uart_request_port(struct uart_port *port)
 	err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
 			"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
 
-	if (err && (port->flags & UPF_IOREMAP)) {
+	if (err)
+		goto out_membase;
+
+	if (psc_ops->clock_alloc) {
+		err = psc_ops->clock_alloc(port);
+		if (err)
+			goto out_mapregion;
+	}
+
+	return 0;
+
+out_mapregion:
+	release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+out_membase:
+	if (port->flags & UPF_IOREMAP) {
 		iounmap(port->membase);
 		port->membase = NULL;
 	}
-
 	return err;
 }
 
Signature · 1 line
1.7.10.4
#76 lore raw

PATCH v3 3/31 USB: fsl-mph-dr-of: cleanup clock API use

In reply to Gerhard Sittig

error check in the clock setup, must prepare clocks before they can get enabled, unprepare after disable, use devm_{get,put}_clk()

---
 drivers/usb/host/fsl-mph-dr-of.c |   15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/usb/host/fsl-mph-dr-of.c +10 -5
index 11e0b79..5e51384 100644
@@ -260,6 +260,7 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 	struct clk *clk;
+	int err;
 	char clk_name[10];
 	int base, clk_num;
 
@@ -272,13 +273,17 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 		return -ENODEV;
 
 	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
-	clk = clk_get(&pdev->dev, clk_name);
+	clk = devm_clk_get(&pdev->dev, clk_name);
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clk\n");
 		return PTR_ERR(clk);
 	}
-
-	clk_enable(clk);
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(&pdev->dev, "failed to enable clk\n");
+		devm_clk_put(&pdev->dev, clk);
+		return err;
+	}
 	pdata->clk = clk;
 
 	if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
@@ -303,8 +308,8 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
 	pdata->regs = NULL;
 
 	if (pdata->clk) {
-		clk_disable(pdata->clk);
-		clk_put(pdata->clk);
+		clk_disable_unprepare(pdata->clk);
+		devm_clk_put(&pdev->dev, pdata->clk);
 	}
 }
 
Signature · 1 line
1.7.10.4
#77 lore raw

PATCH v3 4/31 mtd: mpc5121_nfc: cleanup clock API use

In reply to Gerhard Sittig

prepare before enable isn't optional, do check for and propagate clock setup errors, adjust error code paths to correctly balance get/put and prepare/unprepare and enable/disable, use devm_{get,put}_clk()

---
 drivers/mtd/nand/mpc5121_nfc.c |   20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
drivers/mtd/nand/mpc5121_nfc.c +13 -7
index 3c9cdcb..9c0b8fe 100644
@@ -618,8 +618,8 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 	struct mpc5121_nfc_prv *prv = chip->priv;
 
 	if (prv->clk) {
-		clk_disable(prv->clk);
-		clk_put(prv->clk);
+		clk_disable_unprepare(prv->clk);
+		devm_clk_put(dev, prv->clk);
 	}
 
 	if (prv->csreg)
@@ -629,6 +629,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 static int mpc5121_nfc_probe(struct platform_device *op)
 {
 	struct device_node *rootnode, *dn = op->dev.of_node;
+	struct clk *clk;
 	struct device *dev = &op->dev;
 	struct mpc5121_nfc_prv *prv;
 	struct resource res;
@@ -730,14 +731,19 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 	of_node_put(rootnode);
 
 	/* Enable NFC clock */
-	prv->clk = clk_get(dev, "nfc_clk");
-	if (IS_ERR(prv->clk)) {
+	clk = devm_clk_get(dev, "nfc_clk");
+	if (IS_ERR(clk)) {
 		dev_err(dev, "Unable to acquire NFC clock!\n");
-		retval = PTR_ERR(prv->clk);
+		retval = PTR_ERR(clk);
 		goto error;
 	}
-
-	clk_enable(prv->clk);
+	retval = clk_prepare_enable(clk);
+	if (retval) {
+		dev_err(dev, "Unable to enable NFC clock!\n");
+		devm_clk_put(dev, clk);
+		goto error;
+	}
+	prv->clk = clk;
 
 	/* Reset NAND Flash controller */
 	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
Signature · 1 line
1.7.10.4
#78 lore raw

PATCH v3 5/31 fsl-viu: cleanup clock API use

In reply to Gerhard Sittig

prepare clocks before enabling them, check for and propagate enable errors, balance get/put and prepare/unprepare and enable/disable, use devm_{get,put}_clk()

---
 drivers/media/platform/fsl-viu.c |   26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)
drivers/media/platform/fsl-viu.c +16 -10
index 221ec42..48fced4 100644
@@ -1485,6 +1485,7 @@ static int viu_of_probe(struct platform_device *op)
 	struct viu_reg __iomem *viu_regs;
 	struct i2c_adapter *ad;
 	int ret, viu_irq;
+	struct clk *clk;
 
 	ret = of_address_to_resource(op->dev.of_node, 0, &r);
 	if (ret) {
@@ -1577,14 +1578,19 @@ static int viu_of_probe(struct platform_device *op)
 	}
 
 	/* enable VIU clock */
-	viu_dev->clk = clk_get(&op->dev, "viu_clk");
-	if (IS_ERR(viu_dev->clk)) {
-		dev_err(&op->dev, "failed to find the clock module!\n");
-		ret = -ENODEV;
+	clk = devm_clk_get(&op->dev, "viu_clk");
+	if (IS_ERR(clk)) {
+		dev_err(&op->dev, "failed to lookup the clock!\n");
+		ret = PTR_ERR(clk);
+		goto err_clk;
+	}
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		dev_err(&op->dev, "failed to enable the clock!\n");
+		devm_clk_put(&op->dev, clk);
 		goto err_clk;
-	} else {
-		clk_enable(viu_dev->clk);
 	}
+	viu_dev->clk = clk;
 
 	/* reset VIU module */
 	viu_reset(viu_dev->vr);
@@ -1602,8 +1608,8 @@ static int viu_of_probe(struct platform_device *op)
 	return ret;
 
 err_irq:
-	clk_disable(viu_dev->clk);
-	clk_put(viu_dev->clk);
+	clk_disable_unprepare(viu_dev->clk);
+	devm_clk_put(&op->dev, viu_dev->clk);
 err_clk:
 	video_unregister_device(viu_dev->vdev);
 err_vdev:
@@ -1626,8 +1632,8 @@ static int viu_of_remove(struct platform_device *op)
 	free_irq(dev->irq, (void *)dev);
 	irq_dispose_mapping(dev->irq);
 
-	clk_disable(dev->clk);
-	clk_put(dev->clk);
+	clk_disable_unprepare(dev->clk);
+	devm_clk_put(&op->dev, dev->clk);
 
 	video_unregister_device(dev->vdev);
 	i2c_put_adapter(client->adapter);
Signature · 1 line
1.7.10.4
#79 lore raw

PATCH v3 6/31 i2c: mpc: cleanup clock API use

In reply to Gerhard Sittig

make the MPC I2C driver get, prepare and enable the peripheral clock ('per' for access to the peripheral's registers) during probe; disable, unprepare and put the clock upon remove(); hold a reference to the clock over the period of use

clock lookup is non-fatal in this implementation as not all platforms may provide clock specs in their device tree, but enable errors for specified clocks are considered fatal

---
 drivers/i2c/busses/i2c-mpc.c |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
drivers/i2c/busses/i2c-mpc.c +28 -0
index 7607dc0..9e837be 100644
@@ -21,6 +21,7 @@
 #include <linux/of_i2c.h>
 #include <linux/slab.h>
 
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/fsl_devices.h>
 #include <linux/i2c.h>
@@ -67,6 +68,7 @@ struct mpc_i2c {
 #ifdef CONFIG_PM
 	u8 fdr, dfsrr;
 #endif
+	struct clk *clk_per;
 };
 
 struct mpc_i2c_divider {
@@ -623,6 +625,8 @@ static int fsl_i2c_probe(struct platform_device *op)
 	u32 clock = MPC_I2C_CLOCK_LEGACY;
 	int result = 0;
 	int plen;
+	struct clk *clk;
+	int err;
 
 	match = of_match_device(mpc_i2c_of_match, &op->dev);
 	if (!match)
@@ -653,6 +657,21 @@ static int fsl_i2c_probe(struct platform_device *op)
 		}
 	}
 
+	/*
+	 * enable clock for the I2C peripheral (non fatal),
+	 * keep a reference upon successful allocation
+	 */
+	clk = devm_clk_get(&op->dev, "per");
+	if (!IS_ERR(clk)) {
+		err = clk_prepare_enable(clk);
+		if (err) {
+			dev_err(&op->dev, "failed to enable clock\n");
+			devm_clk_put(&op->dev, clk);
+		} else {
+			i2c->clk_per = clk;
+		}
+	}
+
 	if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) {
 		clock = MPC_I2C_CLOCK_PRESERVE;
 	} else {
@@ -696,6 +715,10 @@ static int fsl_i2c_probe(struct platform_device *op)
 	return result;
 
  fail_add:
+	if (i2c->clk_per) {
+		clk_disable_unprepare(i2c->clk_per);
+		devm_clk_put(&op->dev, i2c->clk_per);
+	}
 	free_irq(i2c->irq, i2c);
  fail_request:
 	irq_dispose_mapping(i2c->irq);
@@ -711,6 +734,11 @@ static int fsl_i2c_remove(struct platform_device *op)
 
 	i2c_del_adapter(&i2c->adap);
 
+	if (i2c->clk_per) {
+		clk_disable_unprepare(i2c->clk_per);
+		devm_clk_put(&op->dev, i2c->clk_per);
+	}
+
 	if (i2c->irq)
 		free_irq(i2c->irq, i2c);
 
Signature · 1 line
1.7.10.4
#80 lore raw

PATCH v3 7/31 fs_enet: silence a build warning (unused variable)

In reply to Gerhard Sittig
---
 drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c |    1 -
 1 file changed, 1 deletion(-)
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +0 -1
index 8de53a1..c04eb3a 100644
@@ -583,7 +583,6 @@ static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
 					       struct sk_buff *skb)
 {
 	struct sk_buff *new_skb;
-	struct fs_enet_private *fep = netdev_priv(dev);
 
 	/* Alloc new skb */
 	new_skb = netdev_alloc_skb(dev, skb->len + 4);
Signature · 1 line
1.7.10.4
#81 lore raw

PATCH v3 8/31 fs_enet: cleanup clock API use

In reply to Gerhard Sittig

make the Freescale ethernet driver get, prepare and enable the FEC clock during probe(); disable, unprepare and put the clock upon remove(); hold a reference to the clock over the period of use; use devm_{get,put}_clk()

clock lookup is non-fatal as not all platforms provide clock specs in their device tree; failure to enable specified clocks is fatal

---
 .../net/ethernet/freescale/fs_enet/fs_enet-main.c  |   25 ++++++++++++++++++++
 include/linux/fs_enet_pd.h                         |    3 +++
 2 files changed, 28 insertions(+)
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +25 -0
index c04eb3a..1f58f57 100644
@@ -999,6 +999,8 @@ static int fs_enet_probe(struct platform_device *ofdev)
 	struct fs_enet_private *fep;
 	struct fs_platform_info *fpi;
 	const u32 *data;
+	struct clk *clk;
+	int err;
 	const u8 *mac_addr;
 	const char *phy_connection_type;
 	int privsize, len, ret = -ENODEV;
@@ -1036,6 +1038,21 @@ static int fs_enet_probe(struct platform_device *ofdev)
 			fpi->use_rmii = 1;
 	}
 
+	/* make clock lookup non-fatal (the driver is shared among platforms),
+	 * but require enable to succeed when a clock was specified/found,
+	 * keep a reference to the clock upon successful acquisition
+	 */
+	clk = devm_clk_get(&ofdev->dev, "per");
+	if (!IS_ERR(clk)) {
+		err = clk_prepare_enable(clk);
+		if (err) {
+			devm_clk_put(&ofdev->dev, clk);
+			ret = err;
+			goto out_free_fpi;
+		}
+		fpi->clk_per = clk;
+	}
+
 	privsize = sizeof(*fep) +
 	           sizeof(struct sk_buff **) *
 	           (fpi->rx_ring + fpi->tx_ring);
@@ -1107,6 +1124,10 @@ out_free_dev:
 	free_netdev(ndev);
 out_put:
 	of_node_put(fpi->phy_node);
+	if (fpi->clk_per) {
+		clk_disable_unprepare(fpi->clk_per);
+		devm_clk_put(&ofdev->dev, fpi->clk_per);
+	}
 out_free_fpi:
 	kfree(fpi);
 	return ret;
@@ -1123,6 +1144,10 @@ static int fs_enet_remove(struct platform_device *ofdev)
 	fep->ops->cleanup_data(ndev);
 	dev_set_drvdata(fep->dev, NULL);
 	of_node_put(fep->fpi->phy_node);
+	if (fep->fpi->clk_per) {
+		clk_disable_unprepare(fep->fpi->clk_per);
+		devm_clk_put(&ofdev->dev, fep->fpi->clk_per);
+	}
 	free_netdev(ndev);
 	return 0;
 }
include/linux/fs_enet_pd.h +3 -0
index 51b7934..a978d0d 100644
@@ -16,6 +16,7 @@
 #ifndef FS_ENET_PD_H
 #define FS_ENET_PD_H
 
+#include <linux/clk.h>
 #include <linux/string.h>
 #include <linux/of_mdio.h>
 #include <asm/types.h>
@@ -142,6 +143,8 @@ struct fs_platform_info {
 
 	int use_rmii;		/* use RMII mode 	       */
 	int has_phy;            /* if the network is phy container as well...*/
+
+	struct clk *clk_per;	/* 'per' clock for register access */
 };
 struct fs_mii_fec_platform_info {
 	u32 irq[32];
Signature · 1 line
1.7.10.4
#82 lore raw

PATCH v3 8/31 fs_enet: cleanup clock API use

Quoted 3 lines · Gerhard Sittig

make the Freescale ethernet driver get, prepare and enable the FEC clock during probe(); disable, unprepare and put the clock upon remove(); hold a reference to the clock over the period of use; use devm_{get,put}_clk()

There's no need for devm_clk_put(), devm will take care of this.

Marc

Signature · 12 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130722/3ac63ea1/attachment.sig>
#83 lore raw

PATCH v3 9/31 powerpc/fsl-pci: improve clock API use

In reply to Gerhard Sittig

make the Freescale PCI driver get, prepare and enable the PCI clock during probe()

clock lookup is non-fatal as not all platforms may provide clock specs in their device tree, but failure to enable specified clocks are fatal

the driver appears to not have a remove() routine, so no reference to the clock is kept during use, and the clock isn't released (the devm approach will put the clock, but it won't get disabled or unprepared)

---
 arch/powerpc/sysdev/fsl_pci.c |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
arch/powerpc/sysdev/fsl_pci.c +23 -0
index 46ac1dd..5e2f411 100644
@@ -17,6 +17,8 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
+
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -926,12 +928,33 @@ void fsl_pci_assign_primary(void)
 
 static int fsl_pci_probe(struct platform_device *pdev)
 {
+	struct clk *clk;
 	int ret;
 	struct device_node *node;
 #ifdef CONFIG_SWIOTLB
 	struct pci_controller *hose;
 #endif
 
+	/*
+	 * clock lookup is non-fatal since the driver is shared among
+	 * platforms and not all of them provide clocks specs in their
+	 * device tree, but failure to enable a specified clock is
+	 * considered fatal
+	 */
+	clk = devm_clk_get(&pdev->dev, "per");
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			dev_err(dev, "Could not enable peripheral clock\n");
+			devm_clk_put(&pdev->dev, clk);
+			return ret;
+		}
+		/*
+		 * TODO where to store the 'clk' reference?  there appears
+		 * to be no remove() routine which undoes what probe() does
+		 */
+	}
+
 	node = pdev->dev.of_node;
 	ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
 
Signature · 1 line
1.7.10.4
#84 lore raw

PATCH v3 10/31 net: can: mscan: add a comment on reg to idx mapping

In reply to Gerhard Sittig

add a comment about the magic of deriving an MSCAN component index from the peripheral's physical address / register offset

---
 drivers/net/can/mscan/mpc5xxx_can.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/can/mscan/mpc5xxx_can.c +4 -1
index 5b0ee8e..bc422ba 100644
@@ -148,7 +148,10 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		goto exit_put;
 	}
 
-	/* Determine the MSCAN device index from the physical address */
+	/* Determine the MSCAN device index from the peripheral's
+	 * physical address. Register address offsets against the
+	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
+	 */
 	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
 	BUG_ON(!pval || plen < sizeof(*pval));
 	clockidx = (*pval & 0x80) ? 1 : 0;
Signature · 1 line
1.7.10.4
#85 lore raw

PATCH v3 11/31 net: can: mscan: improve clock API use

In reply to Gerhard Sittig

the .get_clock() callback is run from probe() and might allocate resources, introduce a .put_clock() callback that is run from remove() to undo any allocation activities

use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put upon driver unload

assume that resources get prepared but not necessarily enabled in the setup phase, make the open() and close() callbacks of the CAN network device enable and disable a previously acquired and prepared clock

store pointers to data structures upon successful allocation already instead of deferral until complete setup, such that subroutines in the setup sequence may access those data structures as well to track their resource acquisition

since clock allocation remains optional, the release callback as well as the enable/disable calls in open/close are optional as well

---
 drivers/net/can/mscan/mpc5xxx_can.c |   18 ++++++++++++------
 drivers/net/can/mscan/mscan.c       |    9 +++++++++
 drivers/net/can/mscan/mscan.h       |    2 ++
 3 files changed, 23 insertions(+), 6 deletions(-)
drivers/net/can/mscan/mpc5xxx_can.c +12 -6
index bc422ba..e59b3a3 100644
@@ -40,6 +40,7 @@ struct mpc5xxx_can_data {
 	unsigned int type;
 	u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
 			 int *mscan_clksrc);
+	void (*put_clock)(struct platform_device *ofdev);
 };
 
 #ifdef CONFIG_PPC_MPC52xx
@@ -180,7 +181,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 			clockdiv = 1;
 
 		if (!clock_name || !strcmp(clock_name, "sys")) {
-			sys_clk = clk_get(&ofdev->dev, "sys_clk");
+			sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
 			if (IS_ERR(sys_clk)) {
 				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
 				goto exit_unmap;
@@ -203,7 +204,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		}
 
 		if (clocksrc < 0) {
-			ref_clk = clk_get(&ofdev->dev, "ref_clk");
+			ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
 			if (IS_ERR(ref_clk)) {
 				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
 				goto exit_unmap;
@@ -280,6 +281,8 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 	dev = alloc_mscandev();
 	if (!dev)
 		goto exit_dispose_irq;
+	platform_set_drvdata(ofdev, dev);
+	SET_NETDEV_DEV(dev, &ofdev->dev);
 
 	priv = netdev_priv(dev);
 	priv->reg_base = base;
@@ -296,8 +299,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 		goto exit_free_mscan;
 	}
 
-	SET_NETDEV_DEV(dev, &ofdev->dev);
-
 	err = register_mscandev(dev, mscan_clksrc);
 	if (err) {
 		dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
@@ -305,8 +306,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 		goto exit_free_mscan;
 	}
 
-	platform_set_drvdata(ofdev, dev);
-
 	dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
 		 priv->reg_base, dev->irq, priv->can.clock.freq);
 
@@ -324,10 +323,17 @@ exit_unmap_mem:
 
 static int mpc5xxx_can_remove(struct platform_device *ofdev)
 {
+	const struct of_device_id *match;
+	const struct mpc5xxx_can_data *data;
 	struct net_device *dev = platform_get_drvdata(ofdev);
 	struct mscan_priv *priv = netdev_priv(dev);
 
+	match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
+	data = match ? match->data : NULL;
+
 	unregister_mscandev(dev);
+	if (data && data->put_clock)
+		data->put_clock(ofdev);
 	iounmap(priv->reg_base);
 	irq_dispose_mapping(dev->irq);
 	free_candev(dev);
drivers/net/can/mscan/mscan.c +9 -0
index e6b4095..1c08ffe 100644
@@ -573,6 +573,12 @@ static int mscan_open(struct net_device *dev)
 	struct mscan_priv *priv = netdev_priv(dev);
 	struct mscan_regs __iomem *regs = priv->reg_base;
 
+	if (priv->clk_can) {
+		ret = clk_enable(priv->clk_can);
+		if (ret)
+			return ret;
+	}
+
 	/* common open */
 	ret = open_candev(dev);
 	if (ret)
@@ -621,6 +627,9 @@ static int mscan_close(struct net_device *dev)
 	close_candev(dev);
 	free_irq(dev->irq, dev);
 
+	if (priv->clk_can)
+		clk_disable(priv->clk_can);
+
 	return 0;
 }
 
drivers/net/can/mscan/mscan.h +2 -0
index af2ed8b..f32e190 100644
@@ -21,6 +21,7 @@
 #ifndef __MSCAN_H__
 #define __MSCAN_H__
 
+#include <linux/clk.h>
 #include <linux/types.h>
 
 /* MSCAN control register 0 (CANCTL0) bits */
@@ -283,6 +284,7 @@ struct mscan_priv {
 	unsigned int type; 	/* MSCAN type variants */
 	unsigned long flags;
 	void __iomem *reg_base;	/* ioremap'ed address to registers */
+	struct clk *clk_can;	/* clock for registers or bitrates */
 	u8 shadow_statflg;
 	u8 shadow_canrier;
 	u8 cur_pri;
Signature · 1 line
1.7.10.4
#86 lore raw

PATCH v3 11/31 net: can: mscan: improve clock API use

Quoted 3 lines · Gerhard Sittig

the .get_clock() callback is run from probe() and might allocate resources, introduce a .put_clock() callback that is run from remove() to undo any allocation activities

looks good

Quoted 2 lines

use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put upon driver unload

fine

Quoted 3 lines

assume that resources get prepared but not necessarily enabled in the setup phase, make the open() and close() callbacks of the CAN network device enable and disable a previously acquired and prepared clock

I think you should call prepare_enable and disable_unprepare in the open/close functions.

Marc

Signature · 12 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130722/2eeb3687/attachment.sig>
#87 lore raw

PATCH v3 11/31 net: can: mscan: improve clock API use

Quoted 11 lines · Marc Kleine-Budde
Quoted 3 lines · Gerhard Sittig

the .get_clock() callback is run from probe() and might allocate resources, introduce a .put_clock() callback that is run from remove() to undo any allocation activities

looks good

Quoted 2 lines

use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put upon driver unload

Quoted 8 lines

fine

Quoted 3 lines

assume that resources get prepared but not necessarily enabled in the setup phase, make the open() and close() callbacks of the CAN network device enable and disable a previously acquired and prepared clock

I think you should call prepare_enable and disable_unprepare in the open/close functions.

After more local research, which totally eliminated the need to pre-enable the CAN related clocks, but might need more discussion as it touches the common gate support, I've learned something more:

The CAN clock needs to get enabled during probe() already, since registers get accessed between probe() for the driver and open() for the network device -- while access to peripheral registers crashes the kernel when clocks still are disabled (other hardware may just hang or provide fake data, neither of this is OK).

But I see the point in your suggestion to prepare _and_ enable the clock during open() as well -- to have open() cope with whatever probe() did, after all the driver is shared among platforms, which may differ in what they do during probe().

So I will:
- make open() of the network device prepare _and_ enable the clock for the peripheral (if acquired during probe())
- adjust open() because ATM it leaves the clock enabled when the network device operation fails (the error path is incomplete in v3)
- make the MPC512x specific probe() time .get_clock() routine not just prepare but enable the clock as well
- and of course address all the shutdown counter parts of the above setup paths

This results in:
- specific chip drivers only need to balance their private get and put clock routines which are called from probe and remove, common paths DTRT for all of them
- correct operation for MPC512x, where common clock is used
- still everything is neutral for MPC5200 where common clock isn't used, behaviour is identical to before the change
- no assumptions are made about what occurs or doesn't occur during probe(), when the network device is used then the clock is fully setup and operational
- when the CAN network device isn't setup (because device tree doesn't describe it, or disables that node), then its clock remains idle (neither gets setup nor enabled)
- complete preparation for future improvement wrt power consumption, where potential changes remain isolated to the specific chip (probe() time setup, get_clock() routine) while the ndo part need not get touched any more

So this is the most appropriate approach I can come up with.

Removing unnecessary devm_put_clk() calls is orthogonal to that. Putting these in isn't totally wrong (they won't harm, and they do signal "visual balance" more clearly such that the next person won't stop and wonder), but it's true that they are redundant. "Trained persons" will wonder as much about their presence as untrained persons wonder about their absence. :) Apparently I'm not well trained yet.

I thought that being explicit and cautious would be good, but the feedback I got suggests that encoding unnecessary instructions isn't desirable. So I will remove those devm_put_clk() in v4.

To save us one more iteration, shall I remove those calls only from error paths during setup? Or shall I remove them from regular shutdown paths as well? How much pain does the community feel with harmless yet unnecessary instructions? :)

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#88 lore raw

PATCH v3 11/31 net: can: mscan: improve clock API use

Quoted 26 lines · Gerhard Sittig
Quoted 11 lines · Marc Kleine-Budde
Quoted 3 lines · Gerhard Sittig

the .get_clock() callback is run from probe() and might allocate resources, introduce a .put_clock() callback that is run from remove() to undo any allocation activities

looks good

Quoted 2 lines

use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put upon driver unload

Quoted 8 lines

fine

Quoted 3 lines

assume that resources get prepared but not necessarily enabled in the setup phase, make the open() and close() callbacks of the CAN network device enable and disable a previously acquired and prepared clock

I think you should call prepare_enable and disable_unprepare in the open/close functions.

After more local research, which totally eliminated the need to pre-enable the CAN related clocks, but might need more discussion as it touches the common gate support, I've learned something more:

Quoted 5 lines

The CAN clock needs to get enabled during probe() already, since registers get accessed between probe() for the driver and open() for the network device -- while access to peripheral registers crashes the kernel when clocks still are disabled (other hardware may just hang or provide fake data, neither of this is OK).

Then call prepare_enable(); before and disable_unprepare(); after accessing the registers. Have a look at the flexcan driver.

Quoted 4 lines

But I see the point in your suggestion to prepare _and_ enable the clock during open() as well -- to have open() cope with whatever probe() did, after all the driver is shared among platforms, which may differ in what they do during probe().

If you enable a clock to access the registers before open() (and disable it afterwards), it should not harm any architecture that doesn't need this clock enabled.

Quoted 3 lines

So I will:
- make open() of the network device prepare _and_ enable the clock for the peripheral (if acquired during probe())

good

Quoted 3 lines

- adjust open() because ATM it leaves the clock enabled when the network device operation fails (the error path is incomplete in v3)

yes, clock should be disabled if open() fails.

Quoted 2 lines

- make the MPC512x specific probe() time .get_clock() routine not just prepare but enable the clock as well

If needed enable the clock, but disable after probe() has finished.

Quoted 7 lines

- and of course address all the shutdown counter parts of the above setup paths

This results in:
- specific chip drivers only need to balance their private get and put clock routines which are called from probe and remove, common paths DTRT for all of them

Yes, but clock should not stay enabled between probe() and open().

[...]

Quoted 7 lines

Removing unnecessary devm_put_clk() calls is orthogonal to that. Putting these in isn't totally wrong (they won't harm, and they do signal "visual balance" more clearly such that the next person won't stop and wonder), but it's true that they are redundant. "Trained persons" will wonder as much about their presence as untrained persons wonder about their absence. :) Apparently I'm not well trained yet.

The whole point about devm_* is to get rid of auto manually tear down functions. So please remove all devm_put_clk() calls, as it will be called automatically if a driver instance is removed.

Marc

Signature · 12 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130723/b5b60aaf/attachment-0001.sig>
#89 lore raw

PATCH v3 11/31 net: can: mscan: improve clock API use

[ trimming the CC: list a bit, as this is CAN and clock specific,
keeping Mark Brown and Greg KH for the UART and SPI part ]

Quoted 28 lines · Marc Kleine-Budde
Quoted 26 lines · Gerhard Sittig
Quoted 11 lines · Marc Kleine-Budde
Quoted 3 lines · Gerhard Sittig

the .get_clock() callback is run from probe() and might allocate resources, introduce a .put_clock() callback that is run from remove() to undo any allocation activities

looks good

Quoted 2 lines

use devm_get_clk() upon lookup (for SYS and REF) to have the clocks put upon driver unload

Quoted 8 lines

fine

Quoted 3 lines

assume that resources get prepared but not necessarily enabled in the setup phase, make the open() and close() callbacks of the CAN network device enable and disable a previously acquired and prepared clock

I think you should call prepare_enable and disable_unprepare in the open/close functions.

After more local research, which totally eliminated the need to pre-enable the CAN related clocks, but might need more discussion as it touches the common gate support, I've learned something more:

Quoted 8 lines
Quoted 5 lines

The CAN clock needs to get enabled during probe() already, since registers get accessed between probe() for the driver and open() for the network device -- while access to peripheral registers crashes the kernel when clocks still are disabled (other hardware may just hang or provide fake data, neither of this is OK).

Then call prepare_enable(); before and disable_unprepare(); after accessing the registers. Have a look at the flexcan driver.

OK, your feedback made me notice that I mentally have mixed peripheral access clocks ('ipg') and bitrate clocks ('per') in the past versions of the driver.

Fixing this, telling 'ipg' and 'per' apart, "in bypassing" eliminates the need for "shared clock gates". Since the MCLK subtree of the clock tree apply to both the CAN controller and the PSC controller, I will have to adjust all of the following:
- the platform's clock driver, telling the gate for the registers and the mux/div for the bitrate apart
- the CAN driver, acquiring both the 'ipg' clock item for register access and the "can" clock for the bitrate, the latter may get derived from either 'ips' or 'mclk', while 'mclk' may be derived from either 'sys' or 'ref' (or 'ips' in this hardware while the mscan(4) driver doesn't use this feature)
- the UART and SPI drivers, acquiring both the 'ipg' clock item for register access and the 'mclk' item for the bitrate

This obsoletes the request for "shared gates" and eliminates another pre-enable workaround in the clock driver backend.

It also is an improvement for the MPC512x platform, and remains neutral to the MPC52xx platform. It's clearly desirable and useful, and doesn't break anything. So I will do it.

[ the above applied to CAN, SPI, and UART; the remainder is
specific to CAN only ]

But I won't try to even further widen the scope of the series, I won't try to address each and every potential for improvement which drivers may have had for several years and which happened to not have been addressed yet. This needs to stop at some reasonable point. I'm not refusing to improve, but I'm asking to check what is reasonable and what needs to get avoided.

I already introduced a bug in a recent version of the series which went unnoticed during review (the unbalanced error path in the network device open routine). I'd rather not mess with power management aspects "in bypassing" in a driver that I'm unable to test thoroughly. Not when I'm trying to work on something totally different (introducing proper common clock support) and try to minimize risk and avoid damage.

Quoted 8 lines
Quoted 4 lines

But I see the point in your suggestion to prepare _and_ enable the clock during open() as well -- to have open() cope with whatever probe() did, after all the driver is shared among platforms, which may differ in what they do during probe().

If you enable a clock to access the registers before open() (and disable it afterwards), it should not harm any architecture that doesn't need this clock enabled.

You suggest to turn on the clock during initialization, and turn it off until the network device actually gets used? I had a look at the flexcan driver, saw that it used two clock items, as outlined above for register access and for wired communication. This is good. But I somehow doubt that the flexcan driver will work if the ipg clock gets disabled (I assume it's a shared clock that happens to remain enabled since others use it as well).

I'd rather not open that can of worms, too. My gut is telling me that either the peripheral does weird things or will lose data when its (register access) clock gets disabled. I won't try to address power management and save/restore issues in that driver now, and I won't try to hunt down and instrument any register access in the shared code paths of a driver for multiple platforms which is full of callbacks.

That's just out of the scope of the series. It may be desirable to address this issue as well, but it shall be done in a separate action, not now "in bypassing". Thank you for understanding. :) And I do appreciate your feedback and desire for even better drivers, just disagree on what to do now in this very moment.

What we already have is:
- probe() and remove() for the driver, calling into clock setup and allocation and deallocation routines
- no allocation for MPC52xx and thus no deallocation, keeping the status of how things used to be
- allocation of a "can" clock for MPC512x and the respective deallocation
- open() and close() for the network device, which prepare/enable and disable/unprepare the allocated clocks

What I will add is:
- allocation and release of both the 'ipg' and a "can" clock for the MPC512x case
- handling of all allocated clocks in open() and close() (such that no assumption is made what occurs at probe() and remove() time)
- permanently enabled 'ipg' clock when allocated, such that the driver may happily access the controller's registers and may assume things remain there
- usually disabled 'can' clock, but enable/disable between open() and close()

This shall result in:
- no change in behaviour for MPC52xx
- disabled clocks and hardware for MPC512x when CAN isn't probed (not listed in the device tree, or disabled)
- enabled internal peripherals but wire disabled for MPC512x when CAN is probed and attached but not in use
- only enabled wire related clock when the network device is open and in actual use

The above goal of the next update in the series won't break any operation of peripherals, will be a clear improvement in that the driver finally does properly use the clock API, and will result in an appropriate use of hardware. There may be potential to conserve even more power, but it's not essential given the previous status of the driver, and it's out of the scope for the very series we are talking about.

Quoted 20 lines
Quoted 3 lines

So I will:
- make open() of the network device prepare _and_ enable the clock for the peripheral (if acquired during probe())

good

Quoted 3 lines

- adjust open() because ATM it leaves the clock enabled when the network device operation fails (the error path is incomplete in v3)

yes, clock should be disabled if open() fails.

Quoted 2 lines

- make the MPC512x specific probe() time .get_clock() routine not just prepare but enable the clock as well

If needed enable the clock, but disable after probe() has finished.

Quoted 2 lines

- and of course address all the shutdown counter parts of the above setup paths

Quoted 6 lines
Quoted 4 lines

This results in:
- specific chip drivers only need to balance their private get and put clock routines which are called from probe and remove, common paths DTRT for all of them

Yes, but clock should not stay enabled between probe() and open().

For this one I offered the compromise of only enabling the "can" clock during network device operation, but keeping the 'ipg' clock active over the driver's complete attachment period. This shall be acceptable. Anything else can be done later and independently.

Quoted 10 lines

[...]

Quoted 7 lines

Removing unnecessary devm_put_clk() calls is orthogonal to that. Putting these in isn't totally wrong (they won't harm, and they do signal "visual balance" more clearly such that the next person won't stop and wonder), but it's true that they are redundant. "Trained persons" will wonder as much about their presence as untrained persons wonder about their absence. :) Apparently I'm not well trained yet.

Quoted 3 lines

The whole point about devm_* is to get rid of auto manually tear down functions. So please remove all devm_put_clk() calls, as it will be called automatically if a driver instance is removed.

Ah, yes, the devm_*() feedback was processed as well. Release won't occur explicitly, as it's done implicitly by common code.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#90 lore raw

PATCH v3 12/31 powerpc: mpc512x: array decl for MCLK registers in CCM

In reply to Gerhard Sittig

reword the clock control module's registers declaration such that the MCLK related registers form an array and get indexed by PSC number

this change is in preparation to COMMON_CLK support for the MPC512x platform, the changed declaration remains neutral to existing code since the PSC and MSCAN CCR fields declared here aren't referenced anywhere

---
 arch/powerpc/include/asm/mpc5121.h |   18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)
arch/powerpc/include/asm/mpc5121.h +2 -16
index 8ae133e..887d3d6 100644
@@ -32,25 +32,11 @@ struct mpc512x_ccm {
 	u32	scfr2;	/* System Clock Frequency Register 2 */
 	u32	scfr2s;	/* System Clock Frequency Shadow Register 2 */
 	u32	bcr;	/* Bread Crumb Register */
-	u32	p0ccr;	/* PSC0 Clock Control Register */
-	u32	p1ccr;	/* PSC1 CCR */
-	u32	p2ccr;	/* PSC2 CCR */
-	u32	p3ccr;	/* PSC3 CCR */
-	u32	p4ccr;	/* PSC4 CCR */
-	u32	p5ccr;	/* PSC5 CCR */
-	u32	p6ccr;	/* PSC6 CCR */
-	u32	p7ccr;	/* PSC7 CCR */
-	u32	p8ccr;	/* PSC8 CCR */
-	u32	p9ccr;	/* PSC9 CCR */
-	u32	p10ccr;	/* PSC10 CCR */
-	u32	p11ccr;	/* PSC11 CCR */
+	u32	psc_ccr[12];	/* PSC Clock Control Registers */
 	u32	spccr;	/* SPDIF Clock Control Register */
 	u32	cccr;	/* CFM Clock Control Register */
 	u32	dccr;	/* DIU Clock Control Register */
-	u32	m1ccr;	/* MSCAN1 CCR */
-	u32	m2ccr;	/* MSCAN2 CCR */
-	u32	m3ccr;	/* MSCAN3 CCR */
-	u32	m4ccr;	/* MSCAN4 CCR */
+	u32	mscan_ccr[4];	/* MSCAN Clock Control Registers */
 	u8	res[0x98]; /* Reserved */
 };
 
Signature · 1 line
1.7.10.4
#91 lore raw

PATCH v3 13/31 clk: wrap I/O access for improved portability

In reply to Gerhard Sittig

the common clock drivers were motivated/initiated by ARM development and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux) in preparation of adding COMMON_CLK support for other platforms

---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
drivers/clk/clk-divider.c +3 -3
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
-	val = readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg) >> divider->shift;
 	val &= div_mask(divider);
 
 	div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
 		val = div_mask(divider) << (divider->shift + 16);
 	} else {
-		val = readl(divider->reg);
+		val = clk_readl(divider->reg);
 		val &= ~(div_mask(divider) << divider->shift);
 	}
 	val |= value << divider->shift;
-	writel(val, divider->reg);
+	clk_writel(val, divider->reg);
 
 	if (divider->lock)
 		spin_unlock_irqrestore(divider->lock, flags);
drivers/clk/clk-gate.c +3 -3
index 790306e..b7fbd96 100644
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		if (set)
 			reg |= BIT(gate->bit_idx);
 	} else {
-		reg = readl(gate->reg);
+		reg = clk_readl(gate->reg);
 
 		if (set)
 			reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 			reg &= ~BIT(gate->bit_idx);
 	}
 
-	writel(reg, gate->reg);
+	clk_writel(reg, gate->reg);
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 	u32 reg;
 	struct clk_gate *gate = to_clk_gate(hw);
 
-	reg = readl(gate->reg);
+	reg = clk_readl(gate->reg);
 
 	/* if a set bit disables this clk, flip it before masking */
 	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
drivers/clk/clk-mux.c +3 -3
index 614444c..02ef506 100644
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
 	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
 	 * val = 0x4 really means "bit 2, index starts at bit 0"
 	 */
-	val = readl(mux->reg) >> mux->shift;
+	val = clk_readl(mux->reg) >> mux->shift;
 	val &= mux->mask;
 
 	if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
 		val = mux->mask << (mux->shift + 16);
 	} else {
-		val = readl(mux->reg);
+		val = clk_readl(mux->reg);
 		val &= ~(mux->mask << mux->shift);
 	}
 	val |= index << mux->shift;
-	writel(val, mux->reg);
+	clk_writel(val, mux->reg);
 
 	if (mux->lock)
 		spin_unlock_irqrestore(mux->lock, flags);
include/linux/clk-provider.h +17 -0
index 1ec14a7..c4f7799 100644
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
 	{ while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4
#92 lore raw

PATCH v3 13/31 clk: wrap I/O access for improved portability

Quoting Gerhard Sittig (2013-07-22 05:14:40)

Quoted 7 lines

the common clock drivers were motivated/initiated by ARM development and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux) in preparation of adding COMMON_CLK support for other platforms

I've taken this into clk-next for testing. regmap deserves investigation but I don't think your series should be blocked on that. We can always overhaul the basic clock primitives with regmap support later on if that makes sense.

Regards,
Mike

Quoted 128 lines
---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
drivers/clk/clk-divider.c +3 -3
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
        struct clk_divider *divider = to_clk_divider(hw);
        unsigned int div, val;
 
-       val = readl(divider->reg) >> divider->shift;
+       val = clk_readl(divider->reg) >> divider->shift;
        val &= div_mask(divider);
 
        div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
                val = div_mask(divider) << (divider->shift + 16);
        } else {
-               val = readl(divider->reg);
+               val = clk_readl(divider->reg);
                val &= ~(div_mask(divider) << divider->shift);
        }
        val |= value << divider->shift;
-       writel(val, divider->reg);
+       clk_writel(val, divider->reg);
 
        if (divider->lock)
                spin_unlock_irqrestore(divider->lock, flags);
drivers/clk/clk-gate.c +3 -3
index 790306e..b7fbd96 100644
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                if (set)
                        reg |= BIT(gate->bit_idx);
        } else {
-               reg = readl(gate->reg);
+               reg = clk_readl(gate->reg);
 
                if (set)
                        reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                        reg &= ~BIT(gate->bit_idx);
        }
 
-       writel(reg, gate->reg);
+       clk_writel(reg, gate->reg);
 
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
        u32 reg;
        struct clk_gate *gate = to_clk_gate(hw);
 
-       reg = readl(gate->reg);
+       reg = clk_readl(gate->reg);
 
        /* if a set bit disables this clk, flip it before masking */
        if (gate->flags & CLK_GATE_SET_TO_DISABLE)
drivers/clk/clk-mux.c +3 -3
index 614444c..02ef506 100644
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
         * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
         * val = 0x4 really means "bit 2, index starts at bit 0"
         */
-       val = readl(mux->reg) >> mux->shift;
+       val = clk_readl(mux->reg) >> mux->shift;
        val &= mux->mask;
 
        if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
        if (mux->flags & CLK_MUX_HIWORD_MASK) {
                val = mux->mask << (mux->shift + 16);
        } else {
-               val = readl(mux->reg);
+               val = clk_readl(mux->reg);
                val &= ~(mux->mask << mux->shift);
        }
        val |= index << mux->shift;
-       writel(val, mux->reg);
+       clk_writel(val, mux->reg);
 
        if (mux->lock)
                spin_unlock_irqrestore(mux->lock, flags);
include/linux/clk-provider.h +17 -0
index 1ec14a7..c4f7799 100644
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
        { while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4
#93 lore raw

PATCH v3 13/31 clk: wrap I/O access for improved portability

[ trimming the CC: list for this strictly clock related and
source code adjusting change, to not spam the device tree ML or other subsystem maintainers, just keeping ARM (for clock) and PPC lists and people in the loop ]

Quoted 10 lines · Mike Turquette

Quoting Gerhard Sittig (2013-07-22 05:14:40)

Quoted 7 lines

the common clock drivers were motivated/initiated by ARM development and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux) in preparation of adding COMMON_CLK support for other platforms

Quoted 7 lines

I've taken this into clk-next for testing. regmap deserves investigation but I don't think your series should be blocked on that. We can always overhaul the basic clock primitives with regmap support later on if that makes sense.

Regards,
Mike

That's fine. Though I will re-post this change when updating the series, but this should not harm (won't conflict) as this specific patch is stable and won't change any longer. Keeping this one patch in the series keeps the series applicable on top of v3.11-rcN as well as clk-next.

Note that this patch only changes those parts of the code under drivers/clk/ which get shared among platforms (div, gate, mux). It doesn't touch non-shared and platform specific drivers. I felt this was the most appropriate thing to do.

Quoted 120 lines
Quoted 120 lines
---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   17 +++++++++++++++++
 4 files changed, 26 insertions(+), 9 deletions(-)
drivers/clk/clk-divider.c +3 -3
index 6d55eb2..2c07061 100644
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
        struct clk_divider *divider = to_clk_divider(hw);
        unsigned int div, val;
 
-       val = readl(divider->reg) >> divider->shift;
+       val = clk_readl(divider->reg) >> divider->shift;
        val &= div_mask(divider);
 
        div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
                val = div_mask(divider) << (divider->shift + 16);
        } else {
-               val = readl(divider->reg);
+               val = clk_readl(divider->reg);
                val &= ~(div_mask(divider) << divider->shift);
        }
        val |= value << divider->shift;
-       writel(val, divider->reg);
+       clk_writel(val, divider->reg);
 
        if (divider->lock)
                spin_unlock_irqrestore(divider->lock, flags);
drivers/clk/clk-gate.c +3 -3
index 790306e..b7fbd96 100644
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                if (set)
                        reg |= BIT(gate->bit_idx);
        } else {
-               reg = readl(gate->reg);
+               reg = clk_readl(gate->reg);
 
                if (set)
                        reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                        reg &= ~BIT(gate->bit_idx);
        }
 
-       writel(reg, gate->reg);
+       clk_writel(reg, gate->reg);
 
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
        u32 reg;
        struct clk_gate *gate = to_clk_gate(hw);
 
-       reg = readl(gate->reg);
+       reg = clk_readl(gate->reg);
 
        /* if a set bit disables this clk, flip it before masking */
        if (gate->flags & CLK_GATE_SET_TO_DISABLE)
drivers/clk/clk-mux.c +3 -3
index 614444c..02ef506 100644
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
         * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
         * val = 0x4 really means "bit 2, index starts at bit 0"
         */
-       val = readl(mux->reg) >> mux->shift;
+       val = clk_readl(mux->reg) >> mux->shift;
        val &= mux->mask;
 
        if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
        if (mux->flags & CLK_MUX_HIWORD_MASK) {
                val = mux->mask << (mux->shift + 16);
        } else {
-               val = readl(mux->reg);
+               val = clk_readl(mux->reg);
                val &= ~(mux->mask << mux->shift);
        }
        val |= index << mux->shift;
-       writel(val, mux->reg);
+       clk_writel(val, mux->reg);
 
        if (mux->lock)
                spin_unlock_irqrestore(mux->lock, flags);
include/linux/clk-provider.h +13 -0
index 1ec14a7..c4f7799 100644
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -490,5 +491,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
        { while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
Quoted 8 lines
Quoted 8 lines
include/linux/clk-provider.h +4 -0
+{
+       writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#94 lore raw

PATCH v3 13/31 clk: wrap I/O access for improved portability

In reply to Mike Turquette
Quoted 7 lines · On Fri, 02 Aug 2013 15:30:00 -0700 Mike Turquette <[email protected]> wrote:

Quoting Gerhard Sittig (2013-07-22 05:14:40)

Quoted 6 lines

the common clock drivers were motivated/initiated by ARM development and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux) in preparation of adding COMMON_CLK support for other platforms

Quoted 6 lines
Quoted 1 line

I've taken this into clk-next for testing. regmap deserves investigation but I don't think your series should be blocked on that. We can always overhaul the basic clock primitives with regmap support later on if that makes sense.

Mike, I cannot see it in clk-next branch of
git://git.linaro.org/people/mturquette/linux.git

Can you please check? Or am I looking in the wrong place?

Thanks,
Anatolij

#95 lore raw

PATCH v3 13/31 clk: wrap I/O access for improved portability

Quoting Anatolij Gustschin (2013-08-23 15:05:39)

Quoted 17 lines
Quoted 7 lines · On Fri, 02 Aug 2013 15:30:00 -0700 Mike Turquette <[email protected]> wrote:

Quoting Gerhard Sittig (2013-07-22 05:14:40)

Quoted 6 lines

the common clock drivers were motivated/initiated by ARM development and apparently assume little endian peripherals

wrap register/peripherals access in the common code (div, gate, mux) in preparation of adding COMMON_CLK support for other platforms

Quoted 6 lines
Quoted 1 line

I've taken this into clk-next for testing. regmap deserves investigation but I don't think your series should be blocked on that. We can always overhaul the basic clock primitives with regmap support later on if that makes sense.

Quoted 4 lines

Mike, I cannot see it in clk-next branch of
git://git.linaro.org/people/mturquette/linux.git

Can you please check? Or am I looking in the wrong place?

You were looking in the right place but I had not pushed out the latest patches from my local branch. It should be there now.

Regards,
Mike

Quoted 3 lines

Thanks,
Anatolij

#96 lore raw

PATCH v3 14/31 dts: mpc512x: prepare for preprocessor support

In reply to Gerhard Sittig

prepare C preprocessor support when processing MPC512x DTS files
- switch from DTS syntax to CPP syntax for include specs
- create a symlink such that DTS processing can reference includes

---
 arch/powerpc/boot/dts/ac14xx.dts          |    2 +-
 arch/powerpc/boot/dts/include/dt-bindings |    1 +
 arch/powerpc/boot/dts/mpc5121ads.dts      |    2 +-
 arch/powerpc/boot/dts/pdm360ng.dts        |    2 +-
 4 files changed, 4 insertions(+), 3 deletions(-)
 create mode 120000 arch/powerpc/boot/dts/include/dt-bindings
arch/powerpc/boot/dts/ac14xx.dts +1 -1
index a27a460..a543c40 100644
@@ -10,7 +10,7 @@
  */
 
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "ac14xx";
arch/powerpc/boot/dts/include/dt-bindings new file +1 -0
new file mode 120000
index 0000000..08c00e4
@@ -0,0 +1 @@
+../../../../../include/dt-bindings
\ No newline at end of file
arch/powerpc/boot/dts/mpc5121ads.dts +1 -1
index 7d3cb79..c228a0a 100644
@@ -9,7 +9,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "mpc5121ads";
arch/powerpc/boot/dts/pdm360ng.dts +1 -1
index 7433740..871c16d 100644
@@ -13,7 +13,7 @@
  * option) any later version.
  */
 
-/include/ "mpc5121.dtsi"
+#include <mpc5121.dtsi>
 
 / {
 	model = "pdm360ng";
Signature · 1 line
1.7.10.4
#97 lore raw

PATCH v3 15/31 dts: mpc512x: introduce dt-bindings/clock/ header

In reply to Gerhard Sittig

introduce a dt-bindings/ header file for MPC512x clocks, providing symbolic identifiers for those SoC clocks which clients will reference from their device tree nodes

---
 include/dt-bindings/clock/mpc512x-clock.h |   59 +++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
include/dt-bindings/clock/mpc512x-clock.h new file +59 -0
new file mode 100644
index 0000000..46c560e
@@ -0,0 +1,59 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ *
+ * Unfortunately the clock number declaration cannot be an enum but
+ * needs to be a list of #define directives since when referenced from
+ * within DTS files they need to get resolved "at compile time".
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY		0
+#define MPC512x_CLK_REF			1
+#define MPC512x_CLK_SYS			2
+#define MPC512x_CLK_DIU			3
+#define MPC512x_CLK_VIU			4
+#define MPC512x_CLK_CSB			5
+#define MPC512x_CLK_E300		6
+#define MPC512x_CLK_IPS			7
+#define MPC512x_CLK_FEC			8
+#define MPC512x_CLK_SATA		9
+#define MPC512x_CLK_PATA		10
+#define MPC512x_CLK_NFC			11
+#define MPC512x_CLK_LPC			12
+#define MPC512x_CLK_MBX_BUS		13
+#define MPC512x_CLK_MBX			14
+#define MPC512x_CLK_MBX_3D		15
+#define MPC512x_CLK_AXE			16
+#define MPC512x_CLK_USB1		17
+#define MPC512x_CLK_USB2		18
+#define MPC512x_CLK_I2C			19
+#define MPC512x_CLK_MSCAN0_MCLK		20
+#define MPC512x_CLK_MSCAN1_MCLK		21
+#define MPC512x_CLK_MSCAN2_MCLK		22
+#define MPC512x_CLK_MSCAN3_MCLK		23
+#define MPC512x_CLK_SDHC		24
+#define MPC512x_CLK_PCI			25
+#define MPC512x_CLK_PSC_MCLK_IN		26
+#define MPC512x_CLK_SPDIF_TX		27
+#define MPC512x_CLK_SPDIF_RX		28
+#define MPC512x_CLK_SPDIF_MCLK		29
+#define MPC512x_CLK_AC97		30
+#define MPC512x_CLK_PSC0_MCLK		31
+#define MPC512x_CLK_PSC1_MCLK		32
+#define MPC512x_CLK_PSC2_MCLK		33
+#define MPC512x_CLK_PSC3_MCLK		34
+#define MPC512x_CLK_PSC4_MCLK		35
+#define MPC512x_CLK_PSC5_MCLK		36
+#define MPC512x_CLK_PSC6_MCLK		37
+#define MPC512x_CLK_PSC7_MCLK		38
+#define MPC512x_CLK_PSC8_MCLK		39
+#define MPC512x_CLK_PSC9_MCLK		40
+#define MPC512x_CLK_PSC10_MCLK		41
+#define MPC512x_CLK_PSC11_MCLK		42
+#define MPC512x_CLK_PSC_FIFO		43
+
+#define MPC512x_CLK_LAST_PUBLIC		43
+
+#endif
Signature · 1 line
1.7.10.4
#98 lore raw

PATCH v3 15/31 dts: mpc512x: introduce dt-bindings/clock/ header

Quoting Gerhard Sittig (2013-07-22 05:14:42)

Quoted 16 lines

introduce a dt-bindings/ header file for MPC512x clocks, providing symbolic identifiers for those SoC clocks which clients will reference from their device tree nodes

---
 include/dt-bindings/clock/mpc512x-clock.h |   59 +++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
include/dt-bindings/clock/mpc512x-clock.h new file +0 -0
new file mode 100644
index 0000000..46c560e

include/dt-bindings/clock/mpc512x-clock.h line 6

Quoted 6 lines
include/dt-bindings/clock/mpc512x-clock.h new file +6 -0
@@ -0,0 +1,59 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ *
+ * Unfortunately the clock number declaration cannot be an enum but
+ * needs to be a list of #define directives since when referenced from
+ * within DTS files they need to get resolved "at compile time".

Above comment is not really necessary. Otherwise,

Quoted 55 lines
include/dt-bindings/clock/mpc512x-clock.h new file +53 -0
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY              0
+#define MPC512x_CLK_REF                        1
+#define MPC512x_CLK_SYS                        2
+#define MPC512x_CLK_DIU                        3
+#define MPC512x_CLK_VIU                        4
+#define MPC512x_CLK_CSB                        5
+#define MPC512x_CLK_E300               6
+#define MPC512x_CLK_IPS                        7
+#define MPC512x_CLK_FEC                        8
+#define MPC512x_CLK_SATA               9
+#define MPC512x_CLK_PATA               10
+#define MPC512x_CLK_NFC                        11
+#define MPC512x_CLK_LPC                        12
+#define MPC512x_CLK_MBX_BUS            13
+#define MPC512x_CLK_MBX                        14
+#define MPC512x_CLK_MBX_3D             15
+#define MPC512x_CLK_AXE                        16
+#define MPC512x_CLK_USB1               17
+#define MPC512x_CLK_USB2               18
+#define MPC512x_CLK_I2C                        19
+#define MPC512x_CLK_MSCAN0_MCLK                20
+#define MPC512x_CLK_MSCAN1_MCLK                21
+#define MPC512x_CLK_MSCAN2_MCLK                22
+#define MPC512x_CLK_MSCAN3_MCLK                23
+#define MPC512x_CLK_SDHC               24
+#define MPC512x_CLK_PCI                        25
+#define MPC512x_CLK_PSC_MCLK_IN                26
+#define MPC512x_CLK_SPDIF_TX           27
+#define MPC512x_CLK_SPDIF_RX           28
+#define MPC512x_CLK_SPDIF_MCLK         29
+#define MPC512x_CLK_AC97               30
+#define MPC512x_CLK_PSC0_MCLK          31
+#define MPC512x_CLK_PSC1_MCLK          32
+#define MPC512x_CLK_PSC2_MCLK          33
+#define MPC512x_CLK_PSC3_MCLK          34
+#define MPC512x_CLK_PSC4_MCLK          35
+#define MPC512x_CLK_PSC5_MCLK          36
+#define MPC512x_CLK_PSC6_MCLK          37
+#define MPC512x_CLK_PSC7_MCLK          38
+#define MPC512x_CLK_PSC8_MCLK          39
+#define MPC512x_CLK_PSC9_MCLK          40
+#define MPC512x_CLK_PSC10_MCLK         41
+#define MPC512x_CLK_PSC11_MCLK         42
+#define MPC512x_CLK_PSC_FIFO           43
+
+#define MPC512x_CLK_LAST_PUBLIC                43
+
+#endif
Signature · 1 line
1.7.10.4
#99 lore raw

PATCH v3 15/31 dts: mpc512x: introduce dt-bindings/clock/ header

Quoted 27 lines · Mike Turquette

Quoting Gerhard Sittig (2013-07-22 05:14:42)

Quoted 16 lines

introduce a dt-bindings/ header file for MPC512x clocks, providing symbolic identifiers for those SoC clocks which clients will reference from their device tree nodes

---
 include/dt-bindings/clock/mpc512x-clock.h |   59 +++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 include/dt-bindings/clock/mpc512x-clock.h
include/dt-bindings/clock/mpc512x-clock.h new file +0 -0
new file mode 100644
index 0000000..46c560e

include/dt-bindings/clock/mpc512x-clock.h line 6

Quoted 6 lines
include/dt-bindings/clock/mpc512x-clock.h new file +6 -0
@@ -0,0 +1,59 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ *
+ * Unfortunately the clock number declaration cannot be an enum but
+ * needs to be a list of #define directives since when referenced from
+ * within DTS files they need to get resolved "at compile time".

Above comment is not really necessary. Otherwise,

Quoted 1 line

OK, the next update of the series will remove this comment.

Quoted 47 lines
Quoted 47 lines
include/dt-bindings/clock/mpc512x-clock.h new file +47 -0
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY              0
+#define MPC512x_CLK_REF                        1
+#define MPC512x_CLK_SYS                        2
+#define MPC512x_CLK_DIU                        3
+#define MPC512x_CLK_VIU                        4
+#define MPC512x_CLK_CSB                        5
+#define MPC512x_CLK_E300               6
+#define MPC512x_CLK_IPS                        7
+#define MPC512x_CLK_FEC                        8
+#define MPC512x_CLK_SATA               9
+#define MPC512x_CLK_PATA               10
+#define MPC512x_CLK_NFC                        11
+#define MPC512x_CLK_LPC                        12
+#define MPC512x_CLK_MBX_BUS            13
+#define MPC512x_CLK_MBX                        14
+#define MPC512x_CLK_MBX_3D             15
+#define MPC512x_CLK_AXE                        16
+#define MPC512x_CLK_USB1               17
+#define MPC512x_CLK_USB2               18
+#define MPC512x_CLK_I2C                        19
+#define MPC512x_CLK_MSCAN0_MCLK                20
+#define MPC512x_CLK_MSCAN1_MCLK                21
+#define MPC512x_CLK_MSCAN2_MCLK                22
+#define MPC512x_CLK_MSCAN3_MCLK                23
+#define MPC512x_CLK_SDHC               24
+#define MPC512x_CLK_PCI                        25
+#define MPC512x_CLK_PSC_MCLK_IN                26
+#define MPC512x_CLK_SPDIF_TX           27
+#define MPC512x_CLK_SPDIF_RX           28
+#define MPC512x_CLK_SPDIF_MCLK         29
+#define MPC512x_CLK_AC97               30
+#define MPC512x_CLK_PSC0_MCLK          31
+#define MPC512x_CLK_PSC1_MCLK          32
+#define MPC512x_CLK_PSC2_MCLK          33
+#define MPC512x_CLK_PSC3_MCLK          34
+#define MPC512x_CLK_PSC4_MCLK          35
+#define MPC512x_CLK_PSC5_MCLK          36
+#define MPC512x_CLK_PSC6_MCLK          37
+#define MPC512x_CLK_PSC7_MCLK          38
+#define MPC512x_CLK_PSC8_MCLK          39
+#define MPC512x_CLK_PSC9_MCLK          40
+#define MPC512x_CLK_PSC10_MCLK         41
Quoted 8 lines
Quoted 8 lines
include/dt-bindings/clock/mpc512x-clock.h new file +6 -0
+#define MPC512x_CLK_PSC11_MCLK         42
+#define MPC512x_CLK_PSC_FIFO           43
+
+#define MPC512x_CLK_LAST_PUBLIC                43
+
+#endif
Signature · 1 line
1.7.10.4

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#100 lore raw

PATCH v3 16/31 dts: mpc512x: add clock related device tree specs

In reply to Gerhard Sittig

this addresses the clock driver aka provider's side of clocks
- prepare for future '<&clks ID>' phandle references for device tree based clock lookup in client drivers
- introduce a 'clocks' subtree with an 'osc' node for the crystal or oscillator SoC input (fixed frequency)
- provide default values with 33MHz oscillator frequency in the common include (the 66MHz IPS bus already was there), add override values for the ifm AC14xx board which deviates from the reference design (25MHz xtal, 80MHz IPS bus)

---
 arch/powerpc/boot/dts/ac14xx.dts   |    7 +++++++
 arch/powerpc/boot/dts/mpc5121.dtsi |   15 ++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
arch/powerpc/boot/dts/ac14xx.dts +7 -0
index a543c40..a1b8837 100644
@@ -139,7 +139,14 @@
 		};
 	};
 
+	clocks {
+		osc {
+			clock-frequency = <25000000>;
+		};
+	};
+
 	soc at 80000000 {
+		bus-frequency = <80000000>;	/* 80 MHz ips bus */
 
 		clock at f00 {
 			compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
arch/powerpc/boot/dts/mpc5121.dtsi +14 -1
index bd14c00..8f4cba0 100644
@@ -9,6 +9,8 @@
  * option) any later version.
  */
 
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 
 / {
@@ -73,6 +75,16 @@
 		ranges = <0x0 0x0 0xfc000000 0x04000000>;
 	};
 
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		osc {
+			compatible = "fsl,mpc512x-osc", "fixed-clock";
+			clock-frequency = <33000000>;
+		};
+	};
+
 	soc at 80000000 {
 		compatible = "fsl,mpc5121-immr";
 		#address-cells = <1>;
@@ -118,9 +130,10 @@
 		};
 
 		/* Clock control */
-		clock at f00 {
+		clks: clock at f00 {
 			compatible = "fsl,mpc5121-clock";
 			reg = <0xf00 0x100>;
+			#clock-cells = <1>;
 		};
 
 		/* Power Management Controller */
Signature · 1 line
1.7.10.4
#101 lore raw

PATCH v3 16/31 dts: mpc512x: add clock related device tree specs

Quoting Gerhard Sittig (2013-07-22 05:14:43)

Quoted 11 lines

this addresses the clock driver aka provider's side of clocks
- prepare for future '<&clks ID>' phandle references for device tree based clock lookup in client drivers
- introduce a 'clocks' subtree with an 'osc' node for the crystal or oscillator SoC input (fixed frequency)
- provide default values with 33MHz oscillator frequency in the common include (the 66MHz IPS bus already was there), add override values for the ifm AC14xx board which deviates from the reference design (25MHz xtal, 80MHz IPS bus)

Quoted 68 lines
---
 arch/powerpc/boot/dts/ac14xx.dts   |    7 +++++++
 arch/powerpc/boot/dts/mpc5121.dtsi |   15 ++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
arch/powerpc/boot/dts/ac14xx.dts +7 -0
index a543c40..a1b8837 100644
@@ -139,7 +139,14 @@
                };
        };
 
+       clocks {
+               osc {
+                       clock-frequency = <25000000>;
+               };
+       };
+
        soc at 80000000 {
+               bus-frequency = <80000000>;     /* 80 MHz ips bus */
 
                clock at f00 {
                        compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
arch/powerpc/boot/dts/mpc5121.dtsi +14 -1
index bd14c00..8f4cba0 100644
@@ -9,6 +9,8 @@
  * option) any later version.
  */
 
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 
 / {
@@ -73,6 +75,16 @@
                ranges = <0x0 0x0 0xfc000000 0x04000000>;
        };
 
+       clocks {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               osc {
+                       compatible = "fsl,mpc512x-osc", "fixed-clock";
+                       clock-frequency = <33000000>;
+               };
+       };
+
        soc at 80000000 {
                compatible = "fsl,mpc5121-immr";
                #address-cells = <1>;
@@ -118,9 +130,10 @@
                };
 
                /* Clock control */
-               clock at f00 {
+               clks: clock at f00 {
                        compatible = "fsl,mpc5121-clock";
                        reg = <0xf00 0x100>;
+                       #clock-cells = <1>;
                };
 
                /* Power Management Controller */
Signature · 1 line
1.7.10.4
#102 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

In reply to Gerhard Sittig

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

this driver implements the publicly announced set of clocks (which can get referenced by means of symbolic identifiers from the dt-bindings header file), as well as generates additional 'struct clk' items where the SoC hardware cannot easily get mapped to the common primitives of the clock API, or requires "intermediate" clock nodes to represent clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and remains in parallel to the common clock implementation for test and comparison during migration, a compile time option picks one of the two alternatives (Kconfig switch, common clock used by default)

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information despite their not getting claimed by any drivers (CPU, internal and external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet, either because of missing driver support or because device tree specs aren't available yet (but the workarounds will get removed as the drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after device tree based clock lookup has become available

---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
arch/powerpc/platforms/512x/Kconfig +13 -1
index fc9c1cb..c5fcdd0 100644
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+	bool "MPC512x platform uses COMMON_CLK"
+	default y
+	depends on PPC_MPC512x
+	help
+	  This option is only here to support tests and comparison
+	  during development and migration.  This option will get
+	  removed after the COMMON_CLK support for MPC512x has become
+	  fully operational and all drivers were adjusted to explicitly
+	  acquire their required clocks.
+
 config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
 	select FSL_SOC
 	select IPIC
-	select PPC_CLOCK
+	select PPC_CLOCK if !MPC512x_COMMON_CLK
+	select COMMON_CLK if MPC512x_COMMON_CLK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
arch/powerpc/platforms/512x/Makefile +3 -1
index 72fb934..1e05f9d 100644
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y				+= clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)		+= clock.o
+obj-$(CONFIG_COMMON_CLK)	+= clock-commonclk.o
+obj-y				+= mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)	+= mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)		+= pdm360ng.o
arch/powerpc/platforms/512x/clock-commonclk.c new file +786 -0

786 lines not on this page · raw message

include/linux/clk-provider.h +16 -0
index c4f7799..7f8fc64 100644
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+	return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+	iowrite32be(val, reg);
+}
+
+#else	/* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
 	return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
 	writel(val, reg);
 }
 
+#endif	/* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4
#103 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

[ summary: "shared gate" support desirable? approach acceptable? ]

Quoted 7 lines · Gerhard Sittig

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

[ ... ]

Quoted 8 lines

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
[ ... ]
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

This remark was related to the CAN clocks of the MPC512x SoC.

The clock subtrees which are involved in generating CAN bitrates include one path from the XTAL to an internal MCLK (this is part of the CCF support for the platform), and another path from the MCLK or yet another IP bus clock to the actual bitrate on the wire (this is taken care of within the mscan(4) driver).

The MCLK generation for CAN is documented in the MPC5121e Reference Manual, chapter 5, section 5.2.5 "MSCAN Clock Generation". SYS, REF (both internal), PSC_MCLK_IN, and SPDIF_TX (both external) are muxed, gated, and divided. The result is muxed with IP. The result is fed into the MSCAN component and gets muxed with IP again (can't tell why, maybe for backwards compatibility).

In parallel to this MCLK block there is SCCR2[25], the "BDLC and MSCAN clock enable", documented in section 5.3.1.3 "System Clock Control Register 2". So there is a gate that "somehow needs to get setup" yet isn't part of the visible MCLK chain.

The series up to and including v3 approaches the problem by
- adding a gate after the second MCLK mux, which gets exported for client lookups and is the MCLK input for the mscan(4) driver
- creating that gate for each of the four MSCAN clocks of the SoC, all of them referencing the single "enable" bit in the SCCR2 register
- pre-enabling the MSCAN clocks from within the clock driver, and thus avoid having the clock disabled from the common infrastructure, because disabling one of these clocks had closed the shared gate and thus had broken all other clock uses

Quoted 3 lines

clkdev registration provides "alias names" for few clock items [ ... ]

[ ... ]

Quoted 119 lines
(quoted diff) +119 -0
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+	size_t clks_idx_pub, clks_idx_int;
+	u32 __iomem *mccr_reg;	/* MCLK control register (mux, en, div) */
+	u32 __iomem *sccr_reg;	/* system clock control register (enable) */
+	int sccr_bit;
+	int div;
+
+	/* derive a few parameters from the component type and index */
+	switch (entry->type) {
+	case MCLK_TYPE_PSC:
+		clks_idx_pub = MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (entry->comp_idx) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->psc_ccr[entry->comp_idx];
+		break;
+	case MCLK_TYPE_MSCAN:
+		clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + entry->comp_idx;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->mscan_ccr[entry->comp_idx];
+		break;
+	case MCLK_TYPE_SPDIF:
+		clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+			     + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+		mccr_reg = &clkregs->spccr;
+		break;
+	default:
+		return;
+	}
+	if (entry->bit_sccr1 >= 0) {
+		sccr_reg = &clkregs->sccr1;
+		sccr_bit = entry->bit_sccr1;
+	} else if (entry->bit_sccr2 >= 0) {
+		sccr_reg = &clkregs->sccr2;
+		sccr_bit = entry->bit_sccr2;
+	} else {
+		sccr_reg = NULL;
+	}
+
+	/*
+	 * this was grabbed from the PPC_CLOCK implementation, which
+	 * enforced a specific MCLK divider while the clock was gated
+	 * during setup (that's a documented hardware requirement)
+	 *
+	 * the PPC_CLOCK implementation might even have violated the
+	 * "MCLK <= IPS" constraint, the fixed divider value of 1
+	 * results in a divider of 2 and thus MCLK = SYS/2 which equals
+	 * CSB which is greater than IPS; the serial port setup may have
+	 * adjusted the divider which the clock setup might have left in
+	 * an undesirable state
+	 *
+	 * initial setup is:
+	 * - MCLK 0 from SYS
+	 * - MCLK DIV such to not exceed the IPS clock
+	 * - MCLK 0 enabled
+	 * - MCLK 1 from MCLK DIV
+	 */
+	div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+	div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+	out_be32(mccr_reg, (0 << 16));
+	out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+	out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+	/*
+	 * create the 'struct clk' items of the MCLK's clock subtree
+	 *
+	 * note that by design we always create all nodes and won't take
+	 * shortcuts here, because
+	 * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+	 *   selectable inputs to the CFM while those who "actually use"
+	 *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+	 *   for their bitrate
+	 * - in the absence of "aliases" for clocks we need to create
+	 *   individial 'struct clk' items for whatever might get
+	 *   referenced or looked up, even if several of those items are
+	 *   identical from the logical POV (their rate value)
+	 * - for easier future maintenance and for better reflection of
+	 *   the SoC's documentation, it appears appropriate to generate
+	 *   clock items even for those muxers which actually are NOPs
+	 *   (those with two inputs of which one is reserved)
+	 */
+	clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+			entry->name_mux0,
+			&parent_names_mux0[0], ARRAY_SIZE(parent_names_mux0),
+			mccr_reg, 14, 2);
+	clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+			entry->name_en0, entry->name_mux0,
+			mccr_reg, 16);
+	clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+			entry->name_div0,
+			entry->name_en0, CLK_SET_RATE_GATE,
+			mccr_reg, 17, 15, 0);
+	if (entry->has_mclk1) {
+		clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_muxed(
+				entry->name_mux1,
+				&entry->parent_names_mux1[0],
+				ARRAY_SIZE(entry->parent_names_mux1),
+				mccr_reg, 7, 1);
+	} else {
+		clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_factor(
+				entry->name_mux1, entry->parent_names_mux1[0],
+				1, 1);
+	}
+	if (sccr_reg) {
+		clks[clks_idx_pub] = mpc512x_clk_gated(
+				entry->name_mclk,
+				entry->name_mux1, sccr_reg, sccr_bit);
+	} else {
+		clks[clks_idx_pub] = mpc512x_clk_factor(
+				entry->name_mclk,
+				entry->name_mux1, 1, 1);
+	}
+
+	/*
+	 * without this "clock device" registration, "simple" lookups in

Review

Quoted 10 lines
(quoted diff) +9 -0
+	 * the SPI master initialization and serial port setup will fail
+	 *
+	 * those drivers need to get adjusted to lookup their required
+	 * clocks from device tree specs, and device tree nodes need to
+	 * provide the clock specs, before this clkdev registration
+	 * becomes obsolete
+	 */
+	clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
[ ... ]

This was the routine which sets up _one_ MCLK block, note the assignment at the routine's end to the "published" clock item that's the gate's output after the second mux stage.

Review

Quoted 8 lines

[ ... ]

(quoted diff) +6 -0
+	clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+						  &clkregs->sccr2, 26);
+	mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_data));
+	clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+						   &clkregs->sccr2, 24);
+	mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_data));
[ ... ]

This is the invocation of the routine which sets up four MCLK blocks for the MSCAN components, while all of them refer to bit 25 of SCCR2.

Quoted 24 lines

[ ... ]

(quoted diff) +23 -0
+
+	/* enable some of the clocks here unconditionally because ... */
+	pr_debug("automatically enabling some clocks\n");
+	/* some are essential yet never get claimed by any driver */
+	clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+	clk_prepare_enable(clks[MPC512x_CLK_E300]);	/* PowerPC CPU */
+	clk_prepare_enable(clks[MPC512x_CLK_DDR]);	/* DRAM */
+	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
+	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
+	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
+	/* some are required yet no dependencies were declared */
+	clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+	/* some are not yet acquired by their respective drivers */
+	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
+	clk_prepare_enable(clks[MPC512x_CLK_DIU]);	/* display */
+	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+	/*
+	 * some have their individual clock subtree with separate clock
+	 * items and their individual enable counters, yet share a
+	 * common gate (refer to the same register location) while the
+	 * common clock driver code is not aware of the fact and the
+	 * platform's code doesn't provide specific support either

Review

Quoted 10 lines
(quoted diff) +10 -0
+	 *
+	 * what might happen is that e.g. enabling two MSCAN clock items
+	 * and disabling one of them will disable the common gate and
+	 * thus break the other MSCAN clock as well
+	 */
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+	clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}

This is the pre-enable workaround for the MSCAN0 to MSCAN3 clock items.

The above approach does work in that it introduces complete support for common clock on the MPC512x platform, with the CAN component being operational, and the clock driver using shared logic across platforms.

The remaining issue is that regardless of whether CAN is used, the (chip internal) clock is enabled. This may not be a problem when bitrates aren't generated and the wire isn't driven.

The question now is how to correctly support the situation where a gate is shared between subtrees yet isn't really part of any path within the subtrees. I really cannot find a single spot where to introduce the gate such that it's not duplicated.

The appropriate solution would not be to pre-enable those clocks, but to either introduce another gate clock type which supports a shared reference, or to add support for the shared reference to the existing gate code.

I'd rather not duplicate most or all of the code of clk-gate.c, instead I looked into how to add "shared gate" support to the existing driver.

My question is whether the approach is acceptable. It adds minimal overhead and shall be OK for the enable/disable path from a technical POV. And it doesn't feel like too much of a stretch. But there may be non-technical reasons to reject the approach. I'd like to learn whether to follow that path before preparing another version of the patch series.

The diffs were taken with the '-w -b' options to demonstrate their essence and not drown it in whitespace changes. The implementation assumes that the caller which registers the gate (the platform's clock driver) provides both the counter cell and the lock. And that all gates with a "shared use counter" use the same lock (which is satisfied as they all get registered from the same spot in the platform's clock driver).

The CLK_IGNORE_UNUSED flag addresses a different problem. The SoC has four MSCAN components, while two of them are enabled in the device tree (the other two are present but disabled). So during probe two of the clocks get enabled. After probe all unused clocks automatically get disabled (that's another two). So the "shared use counter" drops to zero although components are in use, because "disable, it's unused" isn't told from "disable after enable, regular use". The flag would become obsolete if the common gate logic would implement a separate disable_unused() routine, but I guess this isn't necessary and the use of the flag is appropriate.

That the example use creates a field for just one counter is to better demonstrate the use and potential extension as need arises. Reducing this to a mere integer variable would be a micro optimization.

The extension of the existing clk_gate implementation:

drivers/clk/clk-gate.c +31 -2
@@ -46,6 +46,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 	struct clk_gate *gate = to_clk_gate(hw);
 	int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
 	unsigned long flags = 0;
+	int need_reg_access;
 	u32 reg;
 
 	set ^= enable;
@@ -53,6 +54,20 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 	if (gate->lock)
 		spin_lock_irqsave(gate->lock, flags);
 
+	/*
+	 * if a "shared use counter" was specified, keep track of enable
+	 * and disable calls and only access hardware registers upon the
+	 * very first enable or very last disable call
+	 */
+	if (!gate->share_count) {
+		need_reg_access = 1;
+	} else if (enable) {
+		need_reg_access = (*gate->share_count)++ == 0;
+	} else {
+		need_reg_access = --(*gate->share_count) == 0;
+	}
+
+	if (need_reg_access) {
 		if (gate->flags & CLK_GATE_HIWORD_MASK) {
 			reg = BIT(gate->bit_idx + 16);
 			if (set)
@@ -67,6 +82,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		}
 
 		clk_writel(reg, gate->reg);
+	}
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -118,10 +134,11 @@ EXPORT_SYMBOL_GPL(clk_gate_ops);
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 bit_idx,
-		u8 clk_gate_flags, spinlock_t *lock)
+		u8 clk_gate_flags, spinlock_t *lock,
+		int *share_count)
 {
 	struct clk_gate *gate;
 	struct clk *clk;
@@ -152,6 +169,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 	gate->bit_idx = bit_idx;
 	gate->flags = clk_gate_flags;
 	gate->lock = lock;
+	gate->share_count = share_count;
 	gate->hw.init = &init;
 
 	clk = clk_register(dev, &gate->hw);
@@ -161,3 +179,14 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
 	return clk;
 }
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+
+	return clk_register_gate_shared(dev, name, parent_name, flags,
+					reg, bit_idx, clk_gate_flags,
+					lock, NULL);
+}
include/linux/clk-provider.h +6 -0
@@ -222,6 +222,7 @@ struct clk_gate {
 	u8		bit_idx;
 	u8		flags;
 	spinlock_t	*lock;
+	int		*share_count;
 };
 
 #define CLK_GATE_SET_TO_DISABLE		BIT(0)
@@ -232,6 +233,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 bit_idx,
 		u8 clk_gate_flags, spinlock_t *lock);
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock,
+		int *share_count);
 
 struct clk_div_table {
 	unsigned int	val;

How to use these shared gates:

arch/powerpc/platforms/512x/clock-commonclk.c +0 -0
@@ -123,6 +123,39 @@ static inline struct clk *mpc512x_clk_gated(
				 reg, pos, 0, &clklock);

}

+enum mpc512x_clk_shared_gate_id_t {
+ MPC512x_CLK_SHARED_GATE_MSCAN,
+ MPC512x_CLK_SHARED_GATE_MAX,
+};
+
+static int mpc512x_clk_gate_counters[MPC512x_CLK_SHARED_GATE_MAX]; +
+/*
+ * implementor's note: since clk_gate items don't implement a separate
+ * .disable_unused() callback, their .disable() routine gets called and
+ * "disable the clock as we can't see it's in use" cannot be told from
+ * "regular disable, count these events please"
+ *
+ * passing the CLK_IGNORE_UNUSED flag upon clock creation will suppress
+ * the "disable, unused" call, so use counts won't get unbalanced, the
+ * clock either never got enabled and thus need not get disabled, or
+ * part of the hardware got enabled while disabling the other part isn't
+ * wanted
+ */
+static inline struct clk *mpc512x_clk_gated_shared(
+ const char *name, const char *parent_name,
+ u32 __iomem *reg, u8 pos,
+ enum mpc512x_clk_shared_gate_id_t share_id)
+{
+ int clkflags;
+
+ clkflags = CLK_SET_RATE_PARENT;
+ clkflags |= CLK_IGNORE_UNUSED;
+ return clk_register_gate_shared(NULL, name, parent_name, clkflags,
+ reg, pos, 0, &clklock,
+ &mpc512x_clk_gate_counters[share_id]);
+}
+
static inline struct clk *mpc512x_clk_muxed(const char *name,

	const char **parent_names, int parent_count,
	u32 __iomem *reg, u8 pos, u8 len)
@@ -520,9 +553,16 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
				1, 1);
	}
	if (sccr_reg) {

+ if (entry->type == MCLK_TYPE_MSCAN) {
+ clks[clks_idx_pub] = mpc512x_clk_gated_shared(
+ entry->name_mclk,
+ entry->name_mux1, sccr_reg, sccr_bit,
+ MPC512x_CLK_SHARED_GATE_MSCAN);

+		} else {
			clks[clks_idx_pub] = mpc512x_clk_gated(
					entry->name_mclk,
					entry->name_mux1, sccr_reg, sccr_bit);
+		}
	} else {
		clks[clks_idx_pub] = mpc512x_clk_factor(
				entry->name_mclk,

Local tests have shown that the extension solves the problem of how to satisfy the SoC's constraints on the MPC512x platform. The MSCAN clocks no longer need to get pre-enabled, instead they get setup and enabled only as the mscan(4) driver probes devices according to how it was instructed (device tree nodes).

What do you think? Is the "shared gate" support in the common logic appropriate? I'd rather not duplicate all of this code just to introduce the specific gate I need, while most of the logic is identical to the existing gate implementation. The desire isn't to override the gate's operations, but to wrap them and to consult a counter in addition, while the register access still applies.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#104 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

Quoting Gerhard Sittig (2013-07-23 06:14:06)

Quoted 19 lines

[ summary: "shared gate" support desirable? approach acceptable? ]

Quoted 7 lines · Gerhard Sittig

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

[ ... ]

Quoted 8 lines

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
[ ... ]
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

Quoted 1 line

This remark was related to the CAN clocks of the MPC512x SoC.

Gerhard,

Thanks for the patch (way far down below here). I'll check into it to see if that implementation looks OK. It would be helpful if another platform with shared gates could weigh in on whether the implementation works for them.

Still, a shared gate solution is not a prerequisite for this series, correct?

Regards,
Mike

Quoted 465 lines

The clock subtrees which are involved in generating CAN bitrates include one path from the XTAL to an internal MCLK (this is part of the CCF support for the platform), and another path from the MCLK or yet another IP bus clock to the actual bitrate on the wire (this is taken care of within the mscan(4) driver).

The MCLK generation for CAN is documented in the MPC5121e Reference Manual, chapter 5, section 5.2.5 "MSCAN Clock Generation". SYS, REF (both internal), PSC_MCLK_IN, and SPDIF_TX (both external) are muxed, gated, and divided. The result is muxed with IP. The result is fed into the MSCAN component and gets muxed with IP again (can't tell why, maybe for backwards compatibility).

In parallel to this MCLK block there is SCCR2[25], the "BDLC and MSCAN clock enable", documented in section 5.3.1.3 "System Clock Control Register 2". So there is a gate that "somehow needs to get setup" yet isn't part of the visible MCLK chain.

The series up to and including v3 approaches the problem by
- adding a gate after the second MCLK mux, which gets exported for client lookups and is the MCLK input for the mscan(4) driver
- creating that gate for each of the four MSCAN clocks of the SoC, all of them referencing the single "enable" bit in the SCCR2 register
- pre-enabling the MSCAN clocks from within the clock driver, and thus avoid having the clock disabled from the common infrastructure, because disabling one of these clocks had closed the shared gate and thus had broken all other clock uses

Quoted 3 lines

clkdev registration provides "alias names" for few clock items [ ... ]

[ ... ]

Quoted 119 lines
(quoted diff) +119 -0
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+     size_t clks_idx_pub, clks_idx_int;
+     u32 __iomem *mccr_reg;  /* MCLK control register (mux, en, div) */
+     u32 __iomem *sccr_reg;  /* system clock control register (enable) */
+     int sccr_bit;
+     int div;
+
+     /* derive a few parameters from the component type and index */
+     switch (entry->type) {
+     case MCLK_TYPE_PSC:
+             clks_idx_pub = MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+             clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                          + (entry->comp_idx) * MCLK_MAX_IDX;
+             mccr_reg = &clkregs->psc_ccr[entry->comp_idx];
+             break;
+     case MCLK_TYPE_MSCAN:
+             clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + entry->comp_idx;
+             clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                          + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+             mccr_reg = &clkregs->mscan_ccr[entry->comp_idx];
+             break;
+     case MCLK_TYPE_SPDIF:
+             clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+             clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                          + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+             mccr_reg = &clkregs->spccr;
+             break;
+     default:
+             return;
+     }
+     if (entry->bit_sccr1 >= 0) {
+             sccr_reg = &clkregs->sccr1;
+             sccr_bit = entry->bit_sccr1;
+     } else if (entry->bit_sccr2 >= 0) {
+             sccr_reg = &clkregs->sccr2;
+             sccr_bit = entry->bit_sccr2;
+     } else {
+             sccr_reg = NULL;
+     }
+
+     /*
+      * this was grabbed from the PPC_CLOCK implementation, which
+      * enforced a specific MCLK divider while the clock was gated
+      * during setup (that's a documented hardware requirement)
+      *
+      * the PPC_CLOCK implementation might even have violated the
+      * "MCLK <= IPS" constraint, the fixed divider value of 1
+      * results in a divider of 2 and thus MCLK = SYS/2 which equals
+      * CSB which is greater than IPS; the serial port setup may have
+      * adjusted the divider which the clock setup might have left in
+      * an undesirable state
+      *
+      * initial setup is:
+      * - MCLK 0 from SYS
+      * - MCLK DIV such to not exceed the IPS clock
+      * - MCLK 0 enabled
+      * - MCLK 1 from MCLK DIV
+      */
+     div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+     div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+     out_be32(mccr_reg, (0 << 16));
+     out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+     out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+     /*
+      * create the 'struct clk' items of the MCLK's clock subtree
+      *
+      * note that by design we always create all nodes and won't take
+      * shortcuts here, because
+      * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+      *   selectable inputs to the CFM while those who "actually use"
+      *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+      *   for their bitrate
+      * - in the absence of "aliases" for clocks we need to create
+      *   individial 'struct clk' items for whatever might get
+      *   referenced or looked up, even if several of those items are
+      *   identical from the logical POV (their rate value)
+      * - for easier future maintenance and for better reflection of
+      *   the SoC's documentation, it appears appropriate to generate
+      *   clock items even for those muxers which actually are NOPs
+      *   (those with two inputs of which one is reserved)
+      */
+     clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+                     entry->name_mux0,
+                     &parent_names_mux0[0], ARRAY_SIZE(parent_names_mux0),
+                     mccr_reg, 14, 2);
+     clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+                     entry->name_en0, entry->name_mux0,
+                     mccr_reg, 16);
+     clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+                     entry->name_div0,
+                     entry->name_en0, CLK_SET_RATE_GATE,
+                     mccr_reg, 17, 15, 0);
+     if (entry->has_mclk1) {
+             clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_muxed(
+                             entry->name_mux1,
+                             &entry->parent_names_mux1[0],
+                             ARRAY_SIZE(entry->parent_names_mux1),
+                             mccr_reg, 7, 1);
+     } else {
+             clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_factor(
+                             entry->name_mux1, entry->parent_names_mux1[0],
+                             1, 1);
+     }
+     if (sccr_reg) {
+             clks[clks_idx_pub] = mpc512x_clk_gated(
+                             entry->name_mclk,
+                             entry->name_mux1, sccr_reg, sccr_bit);
+     } else {
+             clks[clks_idx_pub] = mpc512x_clk_factor(
+                             entry->name_mclk,
+                             entry->name_mux1, 1, 1);
+     }
+
+     /*
+      * without this "clock device" registration, "simple" lookups in

Review

Quoted 10 lines
(quoted diff) +9 -0
+      * the SPI master initialization and serial port setup will fail
+      *
+      * those drivers need to get adjusted to lookup their required
+      * clocks from device tree specs, and device tree nodes need to
+      * provide the clock specs, before this clkdev registration
+      * becomes obsolete
+      */
+     clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
[ ... ]

This was the routine which sets up _one_ MCLK block, note the assignment at the routine's end to the "published" clock item that's the gate's output after the second mux stage.

Review

Quoted 8 lines

[ ... ]

(quoted diff) +6 -0
+     clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+                                               &clkregs->sccr2, 26);
+     mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_data));
+     clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+                                                &clkregs->sccr2, 24);
+     mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_data));
[ ... ]

This is the invocation of the routine which sets up four MCLK blocks for the MSCAN components, while all of them refer to bit 25 of SCCR2.

Quoted 24 lines

[ ... ]

(quoted diff) +23 -0
+
+     /* enable some of the clocks here unconditionally because ... */
+     pr_debug("automatically enabling some clocks\n");
+     /* some are essential yet never get claimed by any driver */
+     clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+     clk_prepare_enable(clks[MPC512x_CLK_E300]);     /* PowerPC CPU */
+     clk_prepare_enable(clks[MPC512x_CLK_DDR]);      /* DRAM */
+     clk_prepare_enable(clks[MPC512x_CLK_MEM]);      /* SRAM */
+     clk_prepare_enable(clks[MPC512x_CLK_IPS]);      /* SoC periph */
+     clk_prepare_enable(clks[MPC512x_CLK_LPC]);      /* boot media */
+     /* some are required yet no dependencies were declared */
+     clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+     /* some are not yet acquired by their respective drivers */
+     clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+     clk_prepare_enable(clks[MPC512x_CLK_FEC]);      /* network, NFS */
+     clk_prepare_enable(clks[MPC512x_CLK_DIU]);      /* display */
+     clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+     /*
+      * some have their individual clock subtree with separate clock
+      * items and their individual enable counters, yet share a
+      * common gate (refer to the same register location) while the
+      * common clock driver code is not aware of the fact and the
+      * platform's code doesn't provide specific support either

Review

Quoted 10 lines
(quoted diff) +10 -0
+      *
+      * what might happen is that e.g. enabling two MSCAN clock items
+      * and disabling one of them will disable the common gate and
+      * thus break the other MSCAN clock as well
+      */
+     clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+     clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+     clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+     clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}

This is the pre-enable workaround for the MSCAN0 to MSCAN3 clock items.

The above approach does work in that it introduces complete support for common clock on the MPC512x platform, with the CAN component being operational, and the clock driver using shared logic across platforms.

The remaining issue is that regardless of whether CAN is used, the (chip internal) clock is enabled. This may not be a problem when bitrates aren't generated and the wire isn't driven.

The question now is how to correctly support the situation where a gate is shared between subtrees yet isn't really part of any path within the subtrees. I really cannot find a single spot where to introduce the gate such that it's not duplicated.

The appropriate solution would not be to pre-enable those clocks, but to either introduce another gate clock type which supports a shared reference, or to add support for the shared reference to the existing gate code.

I'd rather not duplicate most or all of the code of clk-gate.c, instead I looked into how to add "shared gate" support to the existing driver.

My question is whether the approach is acceptable. It adds minimal overhead and shall be OK for the enable/disable path from a technical POV. And it doesn't feel like too much of a stretch. But there may be non-technical reasons to reject the approach. I'd like to learn whether to follow that path before preparing another version of the patch series.

The diffs were taken with the '-w -b' options to demonstrate their essence and not drown it in whitespace changes. The implementation assumes that the caller which registers the gate (the platform's clock driver) provides both the counter cell and the lock. And that all gates with a "shared use counter" use the same lock (which is satisfied as they all get registered from the same spot in the platform's clock driver).

The CLK_IGNORE_UNUSED flag addresses a different problem. The SoC has four MSCAN components, while two of them are enabled in the device tree (the other two are present but disabled). So during probe two of the clocks get enabled. After probe all unused clocks automatically get disabled (that's another two). So the "shared use counter" drops to zero although components are in use, because "disable, it's unused" isn't told from "disable after enable, regular use". The flag would become obsolete if the common gate logic would implement a separate disable_unused() routine, but I guess this isn't necessary and the use of the flag is appropriate.

That the example use creates a field for just one counter is to better demonstrate the use and potential extension as need arises. Reducing this to a mere integer variable would be a micro optimization.

The extension of the existing clk_gate implementation:

drivers/clk/clk-gate.c +31 -2
@@ -46,6 +46,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        struct clk_gate *gate = to_clk_gate(hw);
        int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
        unsigned long flags = 0;
+       int need_reg_access;
        u32 reg;
 
        set ^= enable;
@@ -53,6 +54,20 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        if (gate->lock)
                spin_lock_irqsave(gate->lock, flags);
 
+       /*
+        * if a "shared use counter" was specified, keep track of enable
+        * and disable calls and only access hardware registers upon the
+        * very first enable or very last disable call
+        */
+       if (!gate->share_count) {
+               need_reg_access = 1;
+       } else if (enable) {
+               need_reg_access = (*gate->share_count)++ == 0;
+       } else {
+               need_reg_access = --(*gate->share_count) == 0;
+       }
+
+       if (need_reg_access) {
                if (gate->flags & CLK_GATE_HIWORD_MASK) {
                        reg = BIT(gate->bit_idx + 16);
                        if (set)
@@ -67,6 +82,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                }
 
                clk_writel(reg, gate->reg);
+       }
 
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -118,10 +134,11 @@ EXPORT_SYMBOL_GPL(clk_gate_ops);
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
-               u8 clk_gate_flags, spinlock_t *lock)
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count)
 {
        struct clk_gate *gate;
        struct clk *clk;
@@ -152,6 +169,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
        gate->bit_idx = bit_idx;
        gate->flags = clk_gate_flags;
        gate->lock = lock;
+       gate->share_count = share_count;
        gate->hw.init = &init;
 
        clk = clk_register(dev, &gate->hw);
@@ -161,3 +179,14 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
        return clk;
 }
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock)
+{
+
+       return clk_register_gate_shared(dev, name, parent_name, flags,
+                                       reg, bit_idx, clk_gate_flags,
+                                       lock, NULL);
+}
include/linux/clk-provider.h +6 -0
@@ -222,6 +222,7 @@ struct clk_gate {
        u8              bit_idx;
        u8              flags;
        spinlock_t      *lock;
+       int             *share_count;
 };
 
 #define CLK_GATE_SET_TO_DISABLE                BIT(0)
@@ -232,6 +233,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
                u8 clk_gate_flags, spinlock_t *lock);
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count);
 
 struct clk_div_table {
        unsigned int    val;

How to use these shared gates:

arch/powerpc/platforms/512x/clock-commonclk.c +40 -0
@@ -123,6 +123,39 @@ static inline struct clk *mpc512x_clk_gated(
                                 reg, pos, 0, &clklock);
 }
 
+enum mpc512x_clk_shared_gate_id_t {
+       MPC512x_CLK_SHARED_GATE_MSCAN,
+       MPC512x_CLK_SHARED_GATE_MAX,
+};
+
+static int mpc512x_clk_gate_counters[MPC512x_CLK_SHARED_GATE_MAX];
+
+/*
+ * implementor's note:  since clk_gate items don't implement a separate
+ * .disable_unused() callback, their .disable() routine gets called and
+ * "disable the clock as we can't see it's in use" cannot be told from
+ * "regular disable, count these events please"
+ *
+ * passing the CLK_IGNORE_UNUSED flag upon clock creation will suppress
+ * the "disable, unused" call, so use counts won't get unbalanced, the
+ * clock either never got enabled and thus need not get disabled, or
+ * part of the hardware got enabled while disabling the other part isn't
+ * wanted
+ */
+static inline struct clk *mpc512x_clk_gated_shared(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos,
+       enum mpc512x_clk_shared_gate_id_t share_id)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       clkflags |= CLK_IGNORE_UNUSED;
+       return clk_register_gate_shared(NULL, name, parent_name, clkflags,
+                                       reg, pos, 0, &clklock,
+                                       &mpc512x_clk_gate_counters[share_id]);
+}
+
 static inline struct clk *mpc512x_clk_muxed(const char *name,
        const char **parent_names, int parent_count,
        u32 __iomem *reg, u8 pos, u8 len)
@@ -520,9 +553,16 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
                                1, 1);
        }
        if (sccr_reg) {
+               if (entry->type == MCLK_TYPE_MSCAN) {
+                       clks[clks_idx_pub] = mpc512x_clk_gated_shared(
+                                       entry->name_mclk,
+                                       entry->name_mux1, sccr_reg, sccr_bit,
+                                       MPC512x_CLK_SHARED_GATE_MSCAN);
+               } else {
                        clks[clks_idx_pub] = mpc512x_clk_gated(
                                        entry->name_mclk,
                                        entry->name_mux1, sccr_reg, sccr_bit);
+               }
        } else {
                clks[clks_idx_pub] = mpc512x_clk_factor(
                                entry->name_mclk,

Local tests have shown that the extension solves the problem of how to satisfy the SoC's constraints on the MPC512x platform. The MSCAN clocks no longer need to get pre-enabled, instead they get setup and enabled only as the mscan(4) driver probes devices according to how it was instructed (device tree nodes).

What do you think? Is the "shared gate" support in the common logic appropriate? I'd rather not duplicate all of this code just to introduce the specific gate I need, while most of the logic is identical to the existing gate implementation. The desire isn't to override the gate's operations, but to wrap them and to consult a counter in addition, while the register access still applies.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#105 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

[ we are strictly talking about clocks and source code again,
I have trimmed the CC: list to not spam the device tree ML or subsystem maintainers ]

Quoted 25 lines · Mike Turquette

Quoting Gerhard Sittig (2013-07-23 06:14:06)

Quoted 19 lines

[ summary: "shared gate" support desirable? approach acceptable? ]

Quoted 7 lines · Gerhard Sittig

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

[ ... ]

Quoted 8 lines

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
[ ... ]
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

Quoted 1 line

This remark was related to the CAN clocks of the MPC512x SoC.

Gerhard,

Quoted 7 lines

Thanks for the patch (way far down below here). I'll check into it to see if that implementation looks OK. It would be helpful if another platform with shared gates could weigh in on whether the implementation works for them.

Still, a shared gate solution is not a prerequisite for this series, correct?

Well, the recent CAN driver related discussion suggested that I had a mental misconception there. The need for "shared gates" was felt because of mixing up unrelated paths in the clock tree. But the MCLK subtree is for bitrate generation, while the BDLC gate is for register access into the peripheral controller.

Currently I'm investigating how I can cleanly tell those individual aspects apart. Telling the gate for register access (in ARM speak often referred to as 'ipg') from the bitrate generation (the 'per' clock, or 'mclk' here) seems so much more appropriate.

After clean separation, and more testing to make sure nothing gets broken throughout the series, there will be v4.

So "shared gate" support might have become obsolete for the MPC512x platform. But if others need it, the outlined approach (patch below) may be viable. The change to the common code is minimal. The use in the platform's clock driver was kind of overengineered for the case of exactly one such gate, but this immediately makes it a working approach for several gates, if others need it.

I'll trim the motivation and just leave the suggested approach for "shared gates" here. Feel free to drop it or to only resurrect it as the need may re-arise later. So far nobody appears to have felt the need up to now ...

Quoted 220 lines
Quoted 220 lines

[ ... ]

The question now is how to correctly support the situation where a gate is shared between subtrees yet isn't really part of any path within the subtrees. I really cannot find a single spot where to introduce the gate such that it's not duplicated.

The appropriate solution would not be to pre-enable those clocks, but to either introduce another gate clock type which supports a shared reference, or to add support for the shared reference to the existing gate code.

I'd rather not duplicate most or all of the code of clk-gate.c, instead I looked into how to add "shared gate" support to the existing driver.

My question is whether the approach is acceptable. It adds minimal overhead and shall be OK for the enable/disable path from a technical POV. And it doesn't feel like too much of a stretch. But there may be non-technical reasons to reject the approach. I'd like to learn whether to follow that path before preparing another version of the patch series.

The diffs were taken with the '-w -b' options to demonstrate their essence and not drown it in whitespace changes. The implementation assumes that the caller which registers the gate (the platform's clock driver) provides both the counter cell and the lock. And that all gates with a "shared use counter" use the same lock (which is satisfied as they all get registered from the same spot in the platform's clock driver).

The CLK_IGNORE_UNUSED flag addresses a different problem. The SoC has four MSCAN components, while two of them are enabled in the device tree (the other two are present but disabled). So during probe two of the clocks get enabled. After probe all unused clocks automatically get disabled (that's another two). So the "shared use counter" drops to zero although components are in use, because "disable, it's unused" isn't told from "disable after enable, regular use". The flag would become obsolete if the common gate logic would implement a separate disable_unused() routine, but I guess this isn't necessary and the use of the flag is appropriate.

That the example use creates a field for just one counter is to better demonstrate the use and potential extension as need arises. Reducing this to a mere integer variable would be a micro optimization.

The extension of the existing clk_gate implementation:

drivers/clk/clk-gate.c +31 -2
@@ -46,6 +46,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        struct clk_gate *gate = to_clk_gate(hw);
        int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
        unsigned long flags = 0;
+       int need_reg_access;
        u32 reg;
 
        set ^= enable;
@@ -53,6 +54,20 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        if (gate->lock)
                spin_lock_irqsave(gate->lock, flags);
 
+       /*
+        * if a "shared use counter" was specified, keep track of enable
+        * and disable calls and only access hardware registers upon the
+        * very first enable or very last disable call
+        */
+       if (!gate->share_count) {
+               need_reg_access = 1;
+       } else if (enable) {
+               need_reg_access = (*gate->share_count)++ == 0;
+       } else {
+               need_reg_access = --(*gate->share_count) == 0;
+       }
+
+       if (need_reg_access) {
                if (gate->flags & CLK_GATE_HIWORD_MASK) {
                        reg = BIT(gate->bit_idx + 16);
                        if (set)
@@ -67,6 +82,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                }
 
                clk_writel(reg, gate->reg);
+       }
 
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -118,10 +134,11 @@ EXPORT_SYMBOL_GPL(clk_gate_ops);
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
-               u8 clk_gate_flags, spinlock_t *lock)
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count)
 {
        struct clk_gate *gate;
        struct clk *clk;
@@ -152,6 +169,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
        gate->bit_idx = bit_idx;
        gate->flags = clk_gate_flags;
        gate->lock = lock;
+       gate->share_count = share_count;
        gate->hw.init = &init;
 
        clk = clk_register(dev, &gate->hw);
@@ -161,3 +179,14 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
        return clk;
 }
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock)
+{
+
+       return clk_register_gate_shared(dev, name, parent_name, flags,
+                                       reg, bit_idx, clk_gate_flags,
+                                       lock, NULL);
+}
include/linux/clk-provider.h +6 -0
@@ -222,6 +222,7 @@ struct clk_gate {
        u8              bit_idx;
        u8              flags;
        spinlock_t      *lock;
+       int             *share_count;
 };
 
 #define CLK_GATE_SET_TO_DISABLE                BIT(0)
@@ -232,6 +233,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
                u8 clk_gate_flags, spinlock_t *lock);
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count);
 
 struct clk_div_table {
        unsigned int    val;

How to use these shared gates:

arch/powerpc/platforms/512x/clock-commonclk.c +40 -0
@@ -123,6 +123,39 @@ static inline struct clk *mpc512x_clk_gated(
                                 reg, pos, 0, &clklock);
 }
 
+enum mpc512x_clk_shared_gate_id_t {
+       MPC512x_CLK_SHARED_GATE_MSCAN,
+       MPC512x_CLK_SHARED_GATE_MAX,
+};
+
+static int mpc512x_clk_gate_counters[MPC512x_CLK_SHARED_GATE_MAX];
+
+/*
+ * implementor's note:  since clk_gate items don't implement a separate
+ * .disable_unused() callback, their .disable() routine gets called and
+ * "disable the clock as we can't see it's in use" cannot be told from
+ * "regular disable, count these events please"
+ *
+ * passing the CLK_IGNORE_UNUSED flag upon clock creation will suppress
+ * the "disable, unused" call, so use counts won't get unbalanced, the
+ * clock either never got enabled and thus need not get disabled, or
+ * part of the hardware got enabled while disabling the other part isn't
+ * wanted
+ */
+static inline struct clk *mpc512x_clk_gated_shared(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos,
+       enum mpc512x_clk_shared_gate_id_t share_id)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       clkflags |= CLK_IGNORE_UNUSED;
+       return clk_register_gate_shared(NULL, name, parent_name, clkflags,
+                                       reg, pos, 0, &clklock,
+                                       &mpc512x_clk_gate_counters[share_id]);
+}
+
 static inline struct clk *mpc512x_clk_muxed(const char *name,
        const char **parent_names, int parent_count,
        u32 __iomem *reg, u8 pos, u8 len)
@@ -520,9 +553,16 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
                                1, 1);
        }
        if (sccr_reg) {
+               if (entry->type == MCLK_TYPE_MSCAN) {
+                       clks[clks_idx_pub] = mpc512x_clk_gated_shared(
+                                       entry->name_mclk,
+                                       entry->name_mux1, sccr_reg, sccr_bit,
+                                       MPC512x_CLK_SHARED_GATE_MSCAN);
+               } else {
                        clks[clks_idx_pub] = mpc512x_clk_gated(
                                        entry->name_mclk,
                                        entry->name_mux1, sccr_reg, sccr_bit);
+               }
        } else {
                clks[clks_idx_pub] = mpc512x_clk_factor(
                                entry->name_mclk,

Local tests have shown that the extension solves the problem of how to satisfy the SoC's constraints on the MPC512x platform. The MSCAN clocks no longer need to get pre-enabled, instead they get setup and enabled only as the mscan(4) driver probes devices according to how it was instructed (device tree nodes).

Quoted 7 lines
Quoted 7 lines

What do you think? Is the "shared gate" support in the common logic appropriate? I'd rather not duplicate all of this code just to introduce the specific gate I need, while most of the logic is identical to the existing gate implementation. The desire isn't to override the gate's operations, but to wrap them and to consult a counter in addition, while the register access still applies.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#106 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

Quoting Gerhard Sittig (2013-08-03 07:39:56)

Quoted 62 lines

[ we are strictly talking about clocks and source code again,
I have trimmed the CC: list to not spam the device tree ML or subsystem maintainers ]

Quoted 25 lines · Mike Turquette

Quoting Gerhard Sittig (2013-07-23 06:14:06)

Quoted 19 lines

[ summary: "shared gate" support desirable? approach acceptable? ]

Quoted 7 lines · Gerhard Sittig

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

[ ... ]

Quoted 8 lines

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
[ ... ]
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

Quoted 1 line

This remark was related to the CAN clocks of the MPC512x SoC.

Gerhard,

Quoted 7 lines

Thanks for the patch (way far down below here). I'll check into it to see if that implementation looks OK. It would be helpful if another platform with shared gates could weigh in on whether the implementation works for them.

Still, a shared gate solution is not a prerequisite for this series, correct?

Well, the recent CAN driver related discussion suggested that I had a mental misconception there. The need for "shared gates" was felt because of mixing up unrelated paths in the clock tree. But the MCLK subtree is for bitrate generation, while the BDLC gate is for register access into the peripheral controller.

Currently I'm investigating how I can cleanly tell those individual aspects apart. Telling the gate for register access (in ARM speak often referred to as 'ipg') from the bitrate generation (the 'per' clock, or 'mclk' here) seems so much more appropriate.

After clean separation, and more testing to make sure nothing gets broken throughout the series, there will be v4.

So "shared gate" support might have become obsolete for the MPC512x platform. But if others need it, the outlined approach (patch below) may be viable. The change to the common code is minimal. The use in the platform's clock driver was kind of overengineered for the case of exactly one such gate, but this immediately makes it a working approach for several gates, if others need it.

Quoted 4 lines

I'll trim the motivation and just leave the suggested approach for "shared gates" here. Feel free to drop it or to only resurrect it as the need may re-arise later. So far nobody appears to have felt the need up to now ...

You can drop it. If your platform does not need it and nobody else has said that they require shared gates then there is no reason to spend more time on it.

Regards,
Mike

Quoted 236 lines
Quoted 221 lines
Quoted 221 lines

[ ... ]

The question now is how to correctly support the situation where a gate is shared between subtrees yet isn't really part of any path within the subtrees. I really cannot find a single spot where to introduce the gate such that it's not duplicated.

The appropriate solution would not be to pre-enable those clocks, but to either introduce another gate clock type which supports a shared reference, or to add support for the shared reference to the existing gate code.

I'd rather not duplicate most or all of the code of clk-gate.c, instead I looked into how to add "shared gate" support to the existing driver.

My question is whether the approach is acceptable. It adds minimal overhead and shall be OK for the enable/disable path from a technical POV. And it doesn't feel like too much of a stretch. But there may be non-technical reasons to reject the approach. I'd like to learn whether to follow that path before preparing another version of the patch series.

The diffs were taken with the '-w -b' options to demonstrate their essence and not drown it in whitespace changes. The implementation assumes that the caller which registers the gate (the platform's clock driver) provides both the counter cell and the lock. And that all gates with a "shared use counter" use the same lock (which is satisfied as they all get registered from the same spot in the platform's clock driver).

The CLK_IGNORE_UNUSED flag addresses a different problem. The SoC has four MSCAN components, while two of them are enabled in the device tree (the other two are present but disabled). So during probe two of the clocks get enabled. After probe all unused clocks automatically get disabled (that's another two). So the "shared use counter" drops to zero although components are in use, because "disable, it's unused" isn't told from "disable after enable, regular use". The flag would become obsolete if the common gate logic would implement a separate disable_unused() routine, but I guess this isn't necessary and the use of the flag is appropriate.

That the example use creates a field for just one counter is to better demonstrate the use and potential extension as need arises. Reducing this to a mere integer variable would be a micro optimization.

The extension of the existing clk_gate implementation:

drivers/clk/clk-gate.c +31 -2
@@ -46,6 +46,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        struct clk_gate *gate = to_clk_gate(hw);
        int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
        unsigned long flags = 0;
+       int need_reg_access;
        u32 reg;
 
        set ^= enable;
@@ -53,6 +54,20 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        if (gate->lock)
                spin_lock_irqsave(gate->lock, flags);
 
+       /*
+        * if a "shared use counter" was specified, keep track of enable
+        * and disable calls and only access hardware registers upon the
+        * very first enable or very last disable call
+        */
+       if (!gate->share_count) {
+               need_reg_access = 1;
+       } else if (enable) {
+               need_reg_access = (*gate->share_count)++ == 0;
+       } else {
+               need_reg_access = --(*gate->share_count) == 0;
+       }
+
+       if (need_reg_access) {
                if (gate->flags & CLK_GATE_HIWORD_MASK) {
                        reg = BIT(gate->bit_idx + 16);
                        if (set)
@@ -67,6 +82,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                }
 
                clk_writel(reg, gate->reg);
+       }
 
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -118,10 +134,11 @@ EXPORT_SYMBOL_GPL(clk_gate_ops);
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
-               u8 clk_gate_flags, spinlock_t *lock)
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count)
 {
        struct clk_gate *gate;
        struct clk *clk;
@@ -152,6 +169,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
        gate->bit_idx = bit_idx;
        gate->flags = clk_gate_flags;
        gate->lock = lock;
+       gate->share_count = share_count;
        gate->hw.init = &init;
 
        clk = clk_register(dev, &gate->hw);
@@ -161,3 +179,14 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
        return clk;
 }
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock)
+{
+
+       return clk_register_gate_shared(dev, name, parent_name, flags,
+                                       reg, bit_idx, clk_gate_flags,
+                                       lock, NULL);
+}
include/linux/clk-provider.h +6 -0
@@ -222,6 +222,7 @@ struct clk_gate {
        u8              bit_idx;
        u8              flags;
        spinlock_t      *lock;
+       int             *share_count;
 };
 
 #define CLK_GATE_SET_TO_DISABLE                BIT(0)
@@ -232,6 +233,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
                u8 clk_gate_flags, spinlock_t *lock);
+struct clk *clk_register_gate_shared(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock,
+               int *share_count);
 
 struct clk_div_table {
        unsigned int    val;

How to use these shared gates:

arch/powerpc/platforms/512x/clock-commonclk.c +40 -0
@@ -123,6 +123,39 @@ static inline struct clk *mpc512x_clk_gated(
                                 reg, pos, 0, &clklock);
 }
 
+enum mpc512x_clk_shared_gate_id_t {
+       MPC512x_CLK_SHARED_GATE_MSCAN,
+       MPC512x_CLK_SHARED_GATE_MAX,
+};
+
+static int mpc512x_clk_gate_counters[MPC512x_CLK_SHARED_GATE_MAX];
+
+/*
+ * implementor's note:  since clk_gate items don't implement a separate
+ * .disable_unused() callback, their .disable() routine gets called and
+ * "disable the clock as we can't see it's in use" cannot be told from
+ * "regular disable, count these events please"
+ *
+ * passing the CLK_IGNORE_UNUSED flag upon clock creation will suppress
+ * the "disable, unused" call, so use counts won't get unbalanced, the
+ * clock either never got enabled and thus need not get disabled, or
+ * part of the hardware got enabled while disabling the other part isn't
+ * wanted
+ */
+static inline struct clk *mpc512x_clk_gated_shared(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos,
+       enum mpc512x_clk_shared_gate_id_t share_id)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       clkflags |= CLK_IGNORE_UNUSED;
+       return clk_register_gate_shared(NULL, name, parent_name, clkflags,
+                                       reg, pos, 0, &clklock,
+                                       &mpc512x_clk_gate_counters[share_id]);
+}
+
 static inline struct clk *mpc512x_clk_muxed(const char *name,
        const char **parent_names, int parent_count,
        u32 __iomem *reg, u8 pos, u8 len)
@@ -520,9 +553,16 @@ static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
                                1, 1);
        }
        if (sccr_reg) {
+               if (entry->type == MCLK_TYPE_MSCAN) {
+                       clks[clks_idx_pub] = mpc512x_clk_gated_shared(
+                                       entry->name_mclk,
+                                       entry->name_mux1, sccr_reg, sccr_bit,
+                                       MPC512x_CLK_SHARED_GATE_MSCAN);
+               } else {
                        clks[clks_idx_pub] = mpc512x_clk_gated(
                                        entry->name_mclk,
                                        entry->name_mux1, sccr_reg, sccr_bit);
+               }
        } else {
                clks[clks_idx_pub] = mpc512x_clk_factor(
                                entry->name_mclk,

Local tests have shown that the extension solves the problem of how to satisfy the SoC's constraints on the MPC512x platform. The MSCAN clocks no longer need to get pre-enabled, instead they get setup and enabled only as the mscan(4) driver probes devices according to how it was instructed (device tree nodes).

Quoted 7 lines
Quoted 7 lines

What do you think? Is the "shared gate" support in the common logic appropriate? I'd rather not duplicate all of this code just to introduce the specific gate I need, while most of the logic is identical to the existing gate implementation. The desire isn't to override the gate's operations, but to wrap them and to consult a counter in addition, while the register access still applies.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#107 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

In reply to Gerhard Sittig

Quoting Gerhard Sittig (2013-07-22 05:14:44)

Quoted 39 lines

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

this driver implements the publicly announced set of clocks (which can get referenced by means of symbolic identifiers from the dt-bindings header file), as well as generates additional 'struct clk' items where the SoC hardware cannot easily get mapped to the common primitives of the clock API, or requires "intermediate" clock nodes to represent clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and remains in parallel to the common clock implementation for test and comparison during migration, a compile time option picks one of the two alternatives (Kconfig switch, common clock used by default)

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information despite their not getting claimed by any drivers (CPU, internal and external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet, either because of missing driver support or because device tree specs aren't available yet (but the workarounds will get removed as the drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after device tree based clock lookup has become available

Quoted 1 line

Hi Gerhard,

This looks OK to me. Do you want me to take it or will you keep the series together? Note that I took "clk: wrap I/O access for improved portability" into the clk tree already.

Regards,
Mike

Quoted 877 lines
---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
arch/powerpc/platforms/512x/Kconfig +13 -1
index fc9c1cb..c5fcdd0 100644
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+       bool "MPC512x platform uses COMMON_CLK"
+       default y
+       depends on PPC_MPC512x
+       help
+         This option is only here to support tests and comparison
+         during development and migration.  This option will get
+         removed after the COMMON_CLK support for MPC512x has become
+         fully operational and all drivers were adjusted to explicitly
+         acquire their required clocks.
+
 config PPC_MPC512x
        bool "512x-based boards"
        depends on 6xx
        select FSL_SOC
        select IPIC
-       select PPC_CLOCK
+       select PPC_CLOCK if !MPC512x_COMMON_CLK
+       select COMMON_CLK if MPC512x_COMMON_CLK
        select PPC_PCI_CHOICE
        select FSL_PCI if PCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
arch/powerpc/platforms/512x/Makefile +3 -1
index 72fb934..1e05f9d 100644
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y                          += clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)                += clock.o
+obj-$(CONFIG_COMMON_CLK)       += clock-commonclk.o
+obj-y                          += mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)      += mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)  += mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)         += pdm360ng.o
arch/powerpc/platforms/512x/clock-commonclk.c new file +786 -0
new file mode 100644
index 0000000..762ee85
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2013 DENX Software Engineering
+ *
+ * Gerhard Sittig, <[email protected]>
+ *
+ * common clock driver support for the MPC512x platform
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/mpc5121.h>
+#include <dt-bindings/clock/mpc512x-clock.h>
+
+#include "mpc512x.h"           /* our public mpc5121_clk_init() API */
+
+/* helpers to keep the MCLK intermediates "somewhere" in our table */
+enum {
+       MCLK_IDX_MUX0,
+       MCLK_IDX_EN0,
+       MCLK_IDX_DIV0,
+       MCLK_IDX_MUX1,
+       MCLK_MAX_IDX,
+};
+
+#define NR_PSCS                        12
+#define NR_MSCANS              4
+#define NR_SPDIFS              1
+#define NR_MCLKS               (NR_PSCS + NR_MSCANS + NR_SPDIFS)
+
+/* extend the public set of clocks by adding internal slots for management */
+enum {
+       /* arrange for adjacent numbers after the public set */
+       MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC,
+       /* clocks which aren't announced to the public */
+       MPC512x_CLK_DDR,
+       MPC512x_CLK_MEM,
+       MPC512x_CLK_IIM,
+       MPC512x_CLK_SDHC_2,
+       /* intermediates in div+gate combos or fractional dividers */
+       MPC512x_CLK_DDR_UG,
+       MPC512x_CLK_SDHC_x4,
+       MPC512x_CLK_SDHC_UG,
+       MPC512x_CLK_DIU_x4,
+       MPC512x_CLK_DIU_UG,
+       MPC512x_CLK_MBX_BUS_UG,
+       MPC512x_CLK_MBX_UG,
+       MPC512x_CLK_MBX_3D_UG,
+       MPC512x_CLK_PCI_UG,
+       MPC512x_CLK_NFC_UG,
+       MPC512x_CLK_LPC_UG,
+       MPC512x_CLK_SPDIF_TX_IN,
+       /* intermediates for the mux+gate+div+mux MCLK generation */
+       MPC512x_CLK_MCLKS_FIRST,
+       MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST
+                               + NR_MCLKS * MCLK_MAX_IDX,
+       /* internal, symbolic spec for the number of slots */
+       MPC512x_CLK_LAST_PRIVATE,
+};
+
+/* data required for the OF clock provider registration */
+static struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
+static struct clk_onecell_data clk_data;
+
+/* CCM register access */
+static struct mpc512x_ccm __iomem *clkregs;
+static DEFINE_SPINLOCK(clklock);
+
+/* convenience wrappers around the common clk API */
+static inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
+{
+       return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+}
+
+static inline struct clk *mpc512x_clk_factor(
+       const char *name, const char *parent_name,
+       int mul, int div)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       return clk_register_fixed_factor(NULL, name, parent_name, clkflags,
+                                        mul, div);
+}
+
+static inline struct clk *mpc512x_clk_divider(
+       const char *name, const char *parent_name, u8 clkflags,
+       u32 __iomem *reg, u8 pos, u8 len, int divflags)
+{
+       return clk_register_divider(NULL, name, parent_name, clkflags,
+                                   reg, pos, len, divflags, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_divtable(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos, u8 len,
+       const struct clk_div_table *divtab)
+{
+       u8 divflags;
+
+       divflags = 0;
+       return clk_register_divider_table(NULL, name, parent_name, 0,
+                                         reg, pos, len, divflags,
+                                         divtab, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_gated(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       return clk_register_gate(NULL, name, parent_name, clkflags,
+                                reg, pos, 0, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_muxed(const char *name,
+       const char **parent_names, int parent_count,
+       u32 __iomem *reg, u8 pos, u8 len)
+{
+       int clkflags;
+       u8 muxflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       muxflags = 0;
+       return clk_register_mux(NULL, name,
+                               parent_names, parent_count, clkflags,
+                               reg, pos, len, muxflags, &clklock);
+}
+
+/* helper to isolate a bit field from a register */
+static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len)
+{
+       uint32_t val;
+
+       val = in_be32(reg);
+       val >>= pos;
+       val &= (1 << len) - 1;
+       return val;
+}
+
+/* get the SPMF and translate it into the "sys pll" multiplier */
+static int get_spmf_mult(void)
+{
+       static int spmf_to_mult[] = {
+               68, 1, 12, 16, 20, 24, 28, 32,
+               36, 40, 44, 48, 52, 56, 60, 64,
+       };
+       int spmf;
+
+       spmf = get_bit_field(&clkregs->spmr, 24, 4);
+       return spmf_to_mult[spmf];
+}
+
+/*
+ * get the SYS_DIV value and translate it into a divide factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * divide ratio is fractional
+ */
+static int get_sys_div_x2(void)
+{
+       static int sysdiv_code_to_x2[] = {
+               4, 5, 6, 7, 8, 9, 10, 14,
+               12, 16, 18, 22, 20, 24, 26, 30,
+               28, 32, 34, 38, 36, 40, 42, 46,
+               44, 48, 50, 54, 52, 56, 58, 62,
+               60, 64, 66,
+       };
+       int divcode;
+
+       divcode = get_bit_field(&clkregs->scfr2, 26, 6);
+       return sysdiv_code_to_x2[divcode];
+}
+
+/*
+ * get the CPMF value and translate it into a multiplier factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * multiplier ratio is fractional
+ */
+static int get_cpmf_mult_x2(void)
+{
+       static int cpmf_to_mult[] = {
+               72, 2, 2, 3, 4, 5, 6, 7,
+       };
+       int cpmf;
+
+       cpmf = get_bit_field(&clkregs->spmr, 16, 4);
+       return cpmf_to_mult[cpmf];
+}
+
+/*
+ * some of the clock dividers do scale in a linear way, yet not all of
+ * their bit combinations are legal; use a divider table to get a
+ * resulting set of applicable divider values
+ */
+
+/* applies to the IPS_DIV, and PCI_DIV values */
+static struct clk_div_table divtab_2346[] = {
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .val = 6, .div = 6, },
+       { .div = 0, },
+};
+
+/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
+static struct clk_div_table divtab_1234[] = {
+       { .val = 1, .div = 1, },
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .div = 0, },
+};
+
+static int get_freq_from_dt(char *propname)
+{
+       struct device_node *np;
+       const unsigned int *prop;
+       int val;
+
+       val = 0;
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+       if (np) {
+               prop = of_get_property(np, propname, NULL);
+               if (prop)
+                       val = *prop;
+           of_node_put(np);
+       }
+       return val;
+}
+
+static void mpc512x_clk_preset_data(void)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++)
+               clks[i] = ERR_PTR(-ENODEV);
+}
+
+/*
+ * - receives the "bus frequency" from the caller (that's the IPS clock
+ *   rate, the historical source of clock information)
+ * - fetches the system PLL multiplier and divider values as well as the
+ *   IPS divider value from hardware
+ * - determines the REF clock rate either from the XTAL/OSC spec (if
+ *   there is a device tree node describing the oscillator) or from the
+ *   IPS bus clock (supported for backwards compatibility, such that
+ *   setups without XTAL/OSC specs keep working)
+ * - creates the "ref" clock item in the clock tree, such that
+ *   subsequent code can create the remainder of the hierarchy (REF ->
+ *   SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
+ *   values
+ */
+static void mpc512x_clk_setup_ref_clock(int bus_freq,
+       int *sys_mul, int *sys_div, int *ips_div)
+{
+       struct clk *osc_clk;
+       int calc_freq;
+
+       /* fetch mul/div factors from the hardware */
+       *sys_mul = get_spmf_mult();
+       *sys_mul *= 2;          /* compensate for the fractional divider */
+       *sys_div = get_sys_div_x2();
+       *ips_div = get_bit_field(&clkregs->scfr1, 23, 3);
+
+       /* lookup the oscillator node */
+       osc_clk = clk_get(NULL, "osc");
+       if (osc_clk) {
+               /* descend REF directly from OSC, verify the IPS rate */
+               clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1);
+               calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]);
+               calc_freq *= *sys_mul;
+               calc_freq /= *sys_div;
+               calc_freq /= 2;
+               calc_freq /= *ips_div;
+               if (bus_freq && calc_freq != bus_freq)
+                       pr_warn("calc rate %d != OF spec %d\n",
+                               calc_freq, bus_freq);
+       } else {
+               /* calculate OSC rate and create REF from the freq value */
+               calc_freq = bus_freq;   /* start with IPS */
+               calc_freq *= *ips_div;  /* IPS -> CSB */
+               calc_freq *= 2;         /* CSB -> SYS */
+               calc_freq *= *sys_div;  /* SYS -> PLL out */
+               calc_freq /= *sys_mul;  /* PLL out -> REF == OSC */
+               clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq);
+       }
+}
+
+/*
+ * helper code for the MCLK subtree setup
+ *
+ * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
+ * suggests that all instances of the "PSC clock generation" are equal,
+ * and that one might re-use the PSC setup for MSCAN clock generation
+ * (section 5.2.5) as well, at least the logic if not the data for
+ * description
+ *
+ * the details (starting at page 5-20) show differences in the specific
+ * inputs of the first mux stage ("can clk in", "spdif tx"), and the
+ * factual non-availability of the second mux stage (it's present yet
+ * only one input is valid)
+ *
+ * the MSCAN clock related registers (starting at page 5-35) all
+ * reference "spdif clk" at the first mux stage and don't mention any
+ * "can clk" at all, which somehow is unexpected
+ *
+ * TODO re-check the document, and clarify whether the RM is correct in
+ * the overview or in the details, and whether the difference is a
+ * clipboard induced error or results from chip revisions
+ *
+ * it turns out that the RM rev4 as of 2012-06 talks about "can" for the
+ * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
+ * first a doc update is required which better reflects reality in the
+ * SoC before the implementation should follow while no questions remain
+ */
+
+/*
+ * note that this declaration raises a checkpatch warning, but
+ * it's the very data type which <linux/clk-provider.h> expects,
+ * making this declaration pass checkpatch will break compilation
+ */
+static const char *parent_names_mux0[] = {
+       "sys", "ref", "psc-mclk-in", "spdif-tx",
+};
+
+enum mclk_type {
+       MCLK_TYPE_PSC,
+       MCLK_TYPE_MSCAN,
+       MCLK_TYPE_SPDIF,
+};
+
+struct mclk_setup_data {
+       enum mclk_type type;
+       int comp_idx;
+       bool has_mclk1;
+       int bit_sccr1, bit_sccr2;
+       const char *name_mux0;
+       const char *name_en0;
+       const char *name_div0;
+       const char *parent_names_mux1[2];
+       const char *name_mux1;
+       const char *name_mclk;
+};
+
+#define MCLK_SETUP_DATA_PSC(id) { \
+       MCLK_TYPE_PSC, id, \
+       0, 27 - id, -1, \
+       "psc" #id "-mux0", \
+       "psc" #id "-en0", \
+       "psc" #id "_mclk_div", \
+       { "psc" #id "_mclk_div", "dummy", }, \
+       "psc" #id "_mclk_out", \
+       "psc" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_MSCAN(id) { \
+       MCLK_TYPE_MSCAN, id, \
+       0, -1, 25, \
+       "mscan" #id "-mux0", \
+       "mscan" #id "-en0", \
+       "mscan" #id "_mclk_div", \
+       { "mscan" #id "_mclk_div", "dummy", }, \
+       "mscan" #id "_mclk_out", \
+       "mscan" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_SPDIF { \
+       MCLK_TYPE_SPDIF, 0, \
+       1, -1, 23, \
+       "spdif-mux0", \
+       "spdif-en0", \
+       "spdif_mclk_div", \
+       { "spdif_mclk_div", "spdif-rx", }, \
+       "spdif_mclk_out", \
+       "spdif_mclk", \
+}
+
+static struct mclk_setup_data mclk_psc_data[] = {
+       MCLK_SETUP_DATA_PSC(0),
+       MCLK_SETUP_DATA_PSC(1),
+       MCLK_SETUP_DATA_PSC(2),
+       MCLK_SETUP_DATA_PSC(3),
+       MCLK_SETUP_DATA_PSC(4),
+       MCLK_SETUP_DATA_PSC(5),
+       MCLK_SETUP_DATA_PSC(6),
+       MCLK_SETUP_DATA_PSC(7),
+       MCLK_SETUP_DATA_PSC(8),
+       MCLK_SETUP_DATA_PSC(9),
+       MCLK_SETUP_DATA_PSC(10),
+       MCLK_SETUP_DATA_PSC(11),
+};
+
+static struct mclk_setup_data mclk_mscan_data[] = {
+       MCLK_SETUP_DATA_MSCAN(0),
+       MCLK_SETUP_DATA_MSCAN(1),
+       MCLK_SETUP_DATA_MSCAN(2),
+       MCLK_SETUP_DATA_MSCAN(3),
+};
+
+static struct mclk_setup_data mclk_spdif_data[] = {
+       MCLK_SETUP_DATA_SPDIF,
+};
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+       size_t clks_idx_pub, clks_idx_int;
+       u32 __iomem *mccr_reg;  /* MCLK control register (mux, en, div) */
+       u32 __iomem *sccr_reg;  /* system clock control register (enable) */
+       int sccr_bit;
+       int div;
+
+       /* derive a few parameters from the component type and index */
+       switch (entry->type) {
+       case MCLK_TYPE_PSC:
+               clks_idx_pub = MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (entry->comp_idx) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->psc_ccr[entry->comp_idx];
+               break;
+       case MCLK_TYPE_MSCAN:
+               clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + entry->comp_idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->mscan_ccr[entry->comp_idx];
+               break;
+       case MCLK_TYPE_SPDIF:
+               clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->spccr;
+               break;
+       default:
+               return;
+       }
+       if (entry->bit_sccr1 >= 0) {
+               sccr_reg = &clkregs->sccr1;
+               sccr_bit = entry->bit_sccr1;
+       } else if (entry->bit_sccr2 >= 0) {
+               sccr_reg = &clkregs->sccr2;
+               sccr_bit = entry->bit_sccr2;
+       } else {
+               sccr_reg = NULL;
+       }
+
+       /*
+        * this was grabbed from the PPC_CLOCK implementation, which
+        * enforced a specific MCLK divider while the clock was gated
+        * during setup (that's a documented hardware requirement)
+        *
+        * the PPC_CLOCK implementation might even have violated the
+        * "MCLK <= IPS" constraint, the fixed divider value of 1
+        * results in a divider of 2 and thus MCLK = SYS/2 which equals
+        * CSB which is greater than IPS; the serial port setup may have
+        * adjusted the divider which the clock setup might have left in
+        * an undesirable state
+        *
+        * initial setup is:
+        * - MCLK 0 from SYS
+        * - MCLK DIV such to not exceed the IPS clock
+        * - MCLK 0 enabled
+        * - MCLK 1 from MCLK DIV
+        */
+       div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+       div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+       out_be32(mccr_reg, (0 << 16));
+       out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+       out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+       /*
+        * create the 'struct clk' items of the MCLK's clock subtree
+        *
+        * note that by design we always create all nodes and won't take
+        * shortcuts here, because
+        * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+        *   selectable inputs to the CFM while those who "actually use"
+        *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+        *   for their bitrate
+        * - in the absence of "aliases" for clocks we need to create
+        *   individial 'struct clk' items for whatever might get
+        *   referenced or looked up, even if several of those items are
+        *   identical from the logical POV (their rate value)
+        * - for easier future maintenance and for better reflection of
+        *   the SoC's documentation, it appears appropriate to generate
+        *   clock items even for those muxers which actually are NOPs
+        *   (those with two inputs of which one is reserved)
+        */
+       clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+                       entry->name_mux0,
+                       &parent_names_mux0[0], ARRAY_SIZE(parent_names_mux0),
+                       mccr_reg, 14, 2);
+       clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+                       entry->name_en0, entry->name_mux0,
+                       mccr_reg, 16);
+       clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+                       entry->name_div0,
+                       entry->name_en0, CLK_SET_RATE_GATE,
+                       mccr_reg, 17, 15, 0);
+       if (entry->has_mclk1) {
+               clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_muxed(
+                               entry->name_mux1,
+                               &entry->parent_names_mux1[0],
+                               ARRAY_SIZE(entry->parent_names_mux1),
+                               mccr_reg, 7, 1);
+       } else {
+               clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_factor(
+                               entry->name_mux1, entry->parent_names_mux1[0],
+                               1, 1);
+       }
+       if (sccr_reg) {
+               clks[clks_idx_pub] = mpc512x_clk_gated(
+                               entry->name_mclk,
+                               entry->name_mux1, sccr_reg, sccr_bit);
+       } else {
+               clks[clks_idx_pub] = mpc512x_clk_factor(
+                               entry->name_mclk,
+                               entry->name_mux1, 1, 1);
+       }
+
+       /*
+        * without this "clock device" registration, "simple" lookups in
+        * the SPI master initialization and serial port setup will fail
+        *
+        * those drivers need to get adjusted to lookup their required
+        * clocks from device tree specs, and device tree nodes need to
+        * provide the clock specs, before this clkdev registration
+        * becomes obsolete
+        */
+       clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
+
+static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
+{
+       while (count-- > 0)
+               mpc512x_clk_setup_mclk(table++);
+}
+
+static void mpc512x_clk_setup_clock_tree(int busfreq)
+{
+       int sys_mul, sys_div, ips_div;
+       int mul, div;
+       int freq;
+
+       /*
+        * TODO
+        * - consider whether to handle clocks which have both gates and
+        *   dividers via intermediates or by means of composites
+        * - fractional dividers appear to not map well to composites
+        *   since they can be seen as a fixed multiplier and an
+        *   adjustable divider, while composites can only combine at
+        *   most one of a mux, div, and gate each into one 'struct clk'
+        *   item
+        * - PSC/MSCAN/SPDIF clock generation OTOH already is very
+        *   specific and cannot get mapped to componsites (at least not
+        *   a single one, maybe two of them, but see the comment about
+        *   "intermediates are referenced from elsewhere, too")
+        * - trim the list of auto-enabled clocks after drivers acquire
+        *   them correctly as needed
+        */
+
+       /* regardless of whether XTAL/OSC exists, have REF created */
+       mpc512x_clk_setup_ref_clock(busfreq, &sys_mul, &sys_div, &ips_div);
+
+       /* now setup the REF -> SYS -> CSB -> IPS hierarchy */
+       clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
+                                                  sys_mul, sys_div);
+       clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
+       clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
+                                                    &clkregs->scfr1, 23, 3,
+                                                    divtab_2346);
+
+       /* now setup anything below SYS and CSB and IPS */
+       clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
+       clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 4, 1);
+       clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
+                                                       &clkregs->scfr2, 0, 8,
+                                                       CLK_DIVIDER_ONE_BASED);
+       clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
+       clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
+                                                      &clkregs->scfr1, 0, 8,
+                                                      CLK_DIVIDER_ONE_BASED);
+
+       /*
+        * the "power architecture PLL" was setup from data which was
+        * sampled from the reset config word, at this point in time the
+        * configuration can be considered fixed and read only (i.e. no
+        * longer adjustable, or no longer in need of adjustment), which
+        * is why we don't register a PLL here but assume fixed factors
+        */
+       mul = get_cpmf_mult_x2();
+       div = 2;        /* compensate for the fractional factor */
+       clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
+
+       clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor("mbx-bus-ug", "csb",
+                                                         1, 2);
+       clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable("mbx-ug", "mbx-bus-ug",
+                                                       &clkregs->scfr1, 14, 3,
+                                                       divtab_1234);
+       clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor("mbx-3d-ug", "mbx-ug",
+                                                        1, 1);
+       clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable("pci-ug", "csb",
+                                                       &clkregs->scfr1, 20, 3,
+                                                       divtab_2346);
+       clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable("nfc-ug", "ips",
+                                                       &clkregs->scfr1, 8, 3,
+                                                       divtab_1234);
+       clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
+                                                       &clkregs->scfr1, 11, 3,
+                                                       divtab_1234);
+
+       clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
+                                                 &clkregs->sccr1, 30);
+       clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
+                                                 &clkregs->sccr1, 29);
+       clks[MPC512x_CLK_PATA] = mpc512x_clk_gated("pata", "ips",
+                                                  &clkregs->sccr1, 28);
+       mpc512x_clk_setup_mclks(mclk_psc_data, ARRAY_SIZE(mclk_psc_data));
+       clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
+                                                      &clkregs->sccr1, 15);
+       clks[MPC512x_CLK_SATA] = mpc512x_clk_gated("sata", "ips",
+                                                  &clkregs->sccr1, 14);
+       clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
+                                                 &clkregs->sccr1, 13);
+       clks[MPC512x_CLK_PCI] = mpc512x_clk_gated("pci", "pci-ug",
+                                                 &clkregs->sccr1, 11);
+       clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
+                                                 &clkregs->sccr1, 10);
+
+       clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
+                                                 &clkregs->sccr2, 31);
+       clks[MPC512x_CLK_AXE] = mpc512x_clk_gated("axe", "csb",
+                                                 &clkregs->sccr2, 30);
+       clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
+                                                 &clkregs->sccr2, 29);
+       clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
+                                                  &clkregs->sccr2, 28);
+       clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
+                                                  &clkregs->sccr2, 27);
+       clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+                                                 &clkregs->sccr2, 26);
+       mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_data));
+       clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+                                                  &clkregs->sccr2, 24);
+       mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_data));
+       clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated("mbx-bus", "mbx-bus-ug",
+                                                     &clkregs->sccr2, 22);
+       clks[MPC512x_CLK_MBX] = mpc512x_clk_gated("mbx", "mbx-ug",
+                                                 &clkregs->sccr2, 21);
+       clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated("mbx-3d", "mbx-3d-ug",
+                                                    &clkregs->sccr2, 20);
+       clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
+                                                 &clkregs->sccr2, 19);
+       clks[MPC512x_CLK_VIU] = mpc512x_clk_gated("viu", "csb",
+                                                 &clkregs->sccr2, 18);
+       clks[MPC512x_CLK_SDHC_2] = mpc512x_clk_gated("sdhc-2", "sdhc-ug",
+                                                    &clkregs->sccr2, 17);
+
+       /*
+        * externally provided clocks (when implemented in hardware,
+        * device tree may specify values which otherwise were unknown)
+        */
+       freq = get_freq_from_dt("psc_mclk_in");
+       if (!freq)
+               freq = 25000000;
+       clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+       freq = get_freq_from_dt("spdif_tx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_tx_in", freq);
+       freq = get_freq_from_dt("spdif_rx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_rx_in", freq);
+
+       /* fixed frequency for AC97, always 24.567MHz */
+       clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
+
+       /* clkdev registration for compatibility reasons */
+       clk_register_clkdev(clks[MPC512x_CLK_REF], "ref_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_VIU], "viu_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_NFC], "nfc_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_USB1], "usb1_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_USB2], "usb2_clk", NULL);
+
+       pr_debug("clock tree setup complete\n");
+       freq = clk_get_rate(clks[MPC512x_CLK_E300]);
+       pr_debug("derived PPC freq [%d]\n", freq);
+       freq = clk_get_rate(clks[MPC512x_CLK_IPS]);
+       pr_debug("derived IPS freq [%d]\n", freq);
+       freq = clk_get_rate(clks[MPC512x_CLK_LPC]);
+       pr_debug("derived LPC freq [%d]\n", freq);
+
+       /* enable some of the clocks here unconditionally because ... */
+       pr_debug("automatically enabling some clocks\n");
+       /* some are essential yet never get claimed by any driver */
+       clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+       clk_prepare_enable(clks[MPC512x_CLK_E300]);     /* PowerPC CPU */
+       clk_prepare_enable(clks[MPC512x_CLK_DDR]);      /* DRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_MEM]);      /* SRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_IPS]);      /* SoC periph */
+       clk_prepare_enable(clks[MPC512x_CLK_LPC]);      /* boot media */
+       /* some are required yet no dependencies were declared */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+       /* some are not yet acquired by their respective drivers */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+       clk_prepare_enable(clks[MPC512x_CLK_FEC]);      /* network, NFS */
+       clk_prepare_enable(clks[MPC512x_CLK_DIU]);      /* display */
+       clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+       /*
+        * some have their individual clock subtree with separate clock
+        * items and their individual enable counters, yet share a
+        * common gate (refer to the same register location) while the
+        * common clock driver code is not aware of the fact and the
+        * platform's code doesn't provide specific support either
+        *
+        * what might happen is that e.g. enabling two MSCAN clock items
+        * and disabling one of them will disable the common gate and
+        * thus break the other MSCAN clock as well
+        */
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}
+
+/*
+ * registers the set of public clocks (those listed in the dt-bindings/
+ * header file) for OF lookups, keeps the intermediates private to us
+ */
+static void mpc5121_clk_register_of_provider(struct device_node *np)
+{
+       clk_data.clks = clks;
+       clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1; /* _not_ ARRAY_SIZE() */
+       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+int __init mpc5121_clk_init(void)
+{
+       struct device_node *clk_np;
+       int busfreq;
+
+       /* map the clock control registers */
+       clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+       if (!clk_np)
+               return -ENODEV;
+       clkregs = of_iomap(clk_np, 0);
+       WARN_ON(!clkregs);
+
+       /* invalidate all not yet registered clock slots */
+       mpc512x_clk_preset_data();
+
+       /*
+        * have the device tree scanned for "fixed-clock" nodes (which
+        * includes the oscillator node if the board's DT provides one)
+        */
+       of_clk_init(NULL);
+
+       /*
+        * add a dummy clock for those situations where a clock spec is
+        * required yet no real clock is involved
+        */
+       clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0);
+
+       /*
+        * have all the real nodes in the clock tree populated from REF
+        * down to all leaves, either starting from the OSC node or from
+        * a REF root that was created from the IPS bus clock input
+        */
+       busfreq = get_freq_from_dt("bus-frequency");
+       mpc512x_clk_setup_clock_tree(busfreq);
+
+       /* register as an OF clock provider */
+       mpc5121_clk_register_of_provider(clk_np);
+
+       return 0;
+}
include/linux/clk-provider.h +16 -0
index c4f7799..7f8fc64 100644
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       iowrite32be(val, reg);
+}
+
+#else  /* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
        return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
        writel(val, reg);
 }
 
+#endif /* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4
#108 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

[ this is about the MPC512x platform's clock driver, the core of
the series; trim the CC: list and only keep ARM (for clock) and PPC lists and people ]

Quoted 43 lines · Mike Turquette

Quoting Gerhard Sittig (2013-07-22 05:14:44)

Quoted 39 lines

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

this driver implements the publicly announced set of clocks (which can get referenced by means of symbolic identifiers from the dt-bindings header file), as well as generates additional 'struct clk' items where the SoC hardware cannot easily get mapped to the common primitives of the clock API, or requires "intermediate" clock nodes to represent clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and remains in parallel to the common clock implementation for test and comparison during migration, a compile time option picks one of the two alternatives (Kconfig switch, common clock used by default)

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information despite their not getting claimed by any drivers (CPU, internal and external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet, either because of missing driver support or because device tree specs aren't available yet (but the workarounds will get removed as the drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after device tree based clock lookup has become available

Quoted 1 line
Quoted 8 lines

Hi Gerhard,

This looks OK to me. Do you want me to take it or will you keep the series together? Note that I took "clk: wrap I/O access for improved portability" into the clk tree already.

Regards,
Mike

Thank you for the feedback and for the interest! It's nice to hear that you like the central part of the series. :)

There will be another version of the series (v4), addressing the remaining feedback, further reducing pre-enable workarounds, eliminating the need for "shared gates" by adding more 'ipg' clocks for serial communication (UART, SPI, CAN). It's true that the series has widened its scope after initial submission, but it as well has much improved from the feedback.

This specific patch introduces an alternative clock driver which is enabled by default, so it depends on the device tree data being available before the code becomes operational. And the common clock platform driver might break those peripheral drivers which haven't received their clock API use cleanup yet (earlier parts of the series).

So I'd like to keep the series together until it has passed review. I will make sure that the series remains bisectable and always keeps working when applied in sequence, and would prefer to only start splitting it or staging parts of it later if needed.

Quoted 871 lines
Quoted 871 lines
---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c
arch/powerpc/platforms/512x/Kconfig +13 -1
index fc9c1cb..c5fcdd0 100644
@@ -1,9 +1,21 @@
+config MPC512x_COMMON_CLK
+       bool "MPC512x platform uses COMMON_CLK"
+       default y
+       depends on PPC_MPC512x
+       help
+         This option is only here to support tests and comparison
+         during development and migration.  This option will get
+         removed after the COMMON_CLK support for MPC512x has become
+         fully operational and all drivers were adjusted to explicitly
+         acquire their required clocks.
+
 config PPC_MPC512x
        bool "512x-based boards"
        depends on 6xx
        select FSL_SOC
        select IPIC
-       select PPC_CLOCK
+       select PPC_CLOCK if !MPC512x_COMMON_CLK
+       select COMMON_CLK if MPC512x_COMMON_CLK
        select PPC_PCI_CHOICE
        select FSL_PCI if PCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
arch/powerpc/platforms/512x/Makefile +3 -1
index 72fb934..1e05f9d 100644
@@ -1,7 +1,9 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y                          += clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_CLOCK)                += clock.o
+obj-$(CONFIG_COMMON_CLK)       += clock-commonclk.o
+obj-y                          += mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)      += mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)  += mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)         += pdm360ng.o
arch/powerpc/platforms/512x/clock-commonclk.c new file +786 -0
new file mode 100644
index 0000000..762ee85
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2013 DENX Software Engineering
+ *
+ * Gerhard Sittig, <[email protected]>
+ *
+ * common clock driver support for the MPC512x platform
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/mpc5121.h>
+#include <dt-bindings/clock/mpc512x-clock.h>
+
+#include "mpc512x.h"           /* our public mpc5121_clk_init() API */
+
+/* helpers to keep the MCLK intermediates "somewhere" in our table */
+enum {
+       MCLK_IDX_MUX0,
+       MCLK_IDX_EN0,
+       MCLK_IDX_DIV0,
+       MCLK_IDX_MUX1,
+       MCLK_MAX_IDX,
+};
+
+#define NR_PSCS                        12
+#define NR_MSCANS              4
+#define NR_SPDIFS              1
+#define NR_MCLKS               (NR_PSCS + NR_MSCANS + NR_SPDIFS)
+
+/* extend the public set of clocks by adding internal slots for management */
+enum {
+       /* arrange for adjacent numbers after the public set */
+       MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC,
+       /* clocks which aren't announced to the public */
+       MPC512x_CLK_DDR,
+       MPC512x_CLK_MEM,
+       MPC512x_CLK_IIM,
+       MPC512x_CLK_SDHC_2,
+       /* intermediates in div+gate combos or fractional dividers */
+       MPC512x_CLK_DDR_UG,
+       MPC512x_CLK_SDHC_x4,
+       MPC512x_CLK_SDHC_UG,
+       MPC512x_CLK_DIU_x4,
+       MPC512x_CLK_DIU_UG,
+       MPC512x_CLK_MBX_BUS_UG,
+       MPC512x_CLK_MBX_UG,
+       MPC512x_CLK_MBX_3D_UG,
+       MPC512x_CLK_PCI_UG,
+       MPC512x_CLK_NFC_UG,
+       MPC512x_CLK_LPC_UG,
+       MPC512x_CLK_SPDIF_TX_IN,
+       /* intermediates for the mux+gate+div+mux MCLK generation */
+       MPC512x_CLK_MCLKS_FIRST,
+       MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST
+                               + NR_MCLKS * MCLK_MAX_IDX,
+       /* internal, symbolic spec for the number of slots */
+       MPC512x_CLK_LAST_PRIVATE,
+};
+
+/* data required for the OF clock provider registration */
+static struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
+static struct clk_onecell_data clk_data;
+
+/* CCM register access */
+static struct mpc512x_ccm __iomem *clkregs;
+static DEFINE_SPINLOCK(clklock);
+
+/* convenience wrappers around the common clk API */
+static inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
+{
+       return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+}
+
+static inline struct clk *mpc512x_clk_factor(
+       const char *name, const char *parent_name,
+       int mul, int div)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       return clk_register_fixed_factor(NULL, name, parent_name, clkflags,
+                                        mul, div);
+}
+
+static inline struct clk *mpc512x_clk_divider(
+       const char *name, const char *parent_name, u8 clkflags,
+       u32 __iomem *reg, u8 pos, u8 len, int divflags)
+{
+       return clk_register_divider(NULL, name, parent_name, clkflags,
+                                   reg, pos, len, divflags, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_divtable(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos, u8 len,
+       const struct clk_div_table *divtab)
+{
+       u8 divflags;
+
+       divflags = 0;
+       return clk_register_divider_table(NULL, name, parent_name, 0,
+                                         reg, pos, len, divflags,
+                                         divtab, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_gated(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       return clk_register_gate(NULL, name, parent_name, clkflags,
+                                reg, pos, 0, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_muxed(const char *name,
+       const char **parent_names, int parent_count,
+       u32 __iomem *reg, u8 pos, u8 len)
+{
+       int clkflags;
+       u8 muxflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       muxflags = 0;
+       return clk_register_mux(NULL, name,
+                               parent_names, parent_count, clkflags,
+                               reg, pos, len, muxflags, &clklock);
+}
+
+/* helper to isolate a bit field from a register */
+static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len)
+{
+       uint32_t val;
+
+       val = in_be32(reg);
+       val >>= pos;
+       val &= (1 << len) - 1;
+       return val;
+}
+
+/* get the SPMF and translate it into the "sys pll" multiplier */
+static int get_spmf_mult(void)
+{
+       static int spmf_to_mult[] = {
+               68, 1, 12, 16, 20, 24, 28, 32,
+               36, 40, 44, 48, 52, 56, 60, 64,
+       };
+       int spmf;
+
+       spmf = get_bit_field(&clkregs->spmr, 24, 4);
+       return spmf_to_mult[spmf];
+}
+
+/*
+ * get the SYS_DIV value and translate it into a divide factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * divide ratio is fractional
+ */
+static int get_sys_div_x2(void)
+{
+       static int sysdiv_code_to_x2[] = {
+               4, 5, 6, 7, 8, 9, 10, 14,
+               12, 16, 18, 22, 20, 24, 26, 30,
+               28, 32, 34, 38, 36, 40, 42, 46,
+               44, 48, 50, 54, 52, 56, 58, 62,
+               60, 64, 66,
+       };
+       int divcode;
+
+       divcode = get_bit_field(&clkregs->scfr2, 26, 6);
+       return sysdiv_code_to_x2[divcode];
+}
+
+/*
+ * get the CPMF value and translate it into a multiplier factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * multiplier ratio is fractional
+ */
+static int get_cpmf_mult_x2(void)
+{
+       static int cpmf_to_mult[] = {
+               72, 2, 2, 3, 4, 5, 6, 7,
+       };
+       int cpmf;
+
+       cpmf = get_bit_field(&clkregs->spmr, 16, 4);
+       return cpmf_to_mult[cpmf];
+}
+
+/*
+ * some of the clock dividers do scale in a linear way, yet not all of
+ * their bit combinations are legal; use a divider table to get a
+ * resulting set of applicable divider values
+ */
+
+/* applies to the IPS_DIV, and PCI_DIV values */
+static struct clk_div_table divtab_2346[] = {
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .val = 6, .div = 6, },
+       { .div = 0, },
+};
+
+/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
+static struct clk_div_table divtab_1234[] = {
+       { .val = 1, .div = 1, },
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .div = 0, },
+};
+
+static int get_freq_from_dt(char *propname)
+{
+       struct device_node *np;
+       const unsigned int *prop;
+       int val;
+
+       val = 0;
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+       if (np) {
+               prop = of_get_property(np, propname, NULL);
+               if (prop)
+                       val = *prop;
+           of_node_put(np);
+       }
+       return val;
+}
+
+static void mpc512x_clk_preset_data(void)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++)
+               clks[i] = ERR_PTR(-ENODEV);
+}
+
+/*
+ * - receives the "bus frequency" from the caller (that's the IPS clock
+ *   rate, the historical source of clock information)
+ * - fetches the system PLL multiplier and divider values as well as the
+ *   IPS divider value from hardware
+ * - determines the REF clock rate either from the XTAL/OSC spec (if
+ *   there is a device tree node describing the oscillator) or from the
+ *   IPS bus clock (supported for backwards compatibility, such that
+ *   setups without XTAL/OSC specs keep working)
+ * - creates the "ref" clock item in the clock tree, such that
+ *   subsequent code can create the remainder of the hierarchy (REF ->
+ *   SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
+ *   values
+ */
+static void mpc512x_clk_setup_ref_clock(int bus_freq,
+       int *sys_mul, int *sys_div, int *ips_div)
+{
+       struct clk *osc_clk;
+       int calc_freq;
+
+       /* fetch mul/div factors from the hardware */
+       *sys_mul = get_spmf_mult();
+       *sys_mul *= 2;          /* compensate for the fractional divider */
+       *sys_div = get_sys_div_x2();
+       *ips_div = get_bit_field(&clkregs->scfr1, 23, 3);
+
+       /* lookup the oscillator node */
+       osc_clk = clk_get(NULL, "osc");
+       if (osc_clk) {
+               /* descend REF directly from OSC, verify the IPS rate */
+               clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1);
+               calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]);
+               calc_freq *= *sys_mul;
+               calc_freq /= *sys_div;
+               calc_freq /= 2;
+               calc_freq /= *ips_div;
+               if (bus_freq && calc_freq != bus_freq)
+                       pr_warn("calc rate %d != OF spec %d\n",
+                               calc_freq, bus_freq);
+       } else {
+               /* calculate OSC rate and create REF from the freq value */
+               calc_freq = bus_freq;   /* start with IPS */
+               calc_freq *= *ips_div;  /* IPS -> CSB */
+               calc_freq *= 2;         /* CSB -> SYS */
+               calc_freq *= *sys_div;  /* SYS -> PLL out */
+               calc_freq /= *sys_mul;  /* PLL out -> REF == OSC */
+               clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq);
+       }
+}
+
+/*
+ * helper code for the MCLK subtree setup
+ *
+ * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
+ * suggests that all instances of the "PSC clock generation" are equal,
+ * and that one might re-use the PSC setup for MSCAN clock generation
+ * (section 5.2.5) as well, at least the logic if not the data for
+ * description
+ *
+ * the details (starting at page 5-20) show differences in the specific
+ * inputs of the first mux stage ("can clk in", "spdif tx"), and the
+ * factual non-availability of the second mux stage (it's present yet
+ * only one input is valid)
+ *
+ * the MSCAN clock related registers (starting at page 5-35) all
+ * reference "spdif clk" at the first mux stage and don't mention any
+ * "can clk" at all, which somehow is unexpected
+ *
+ * TODO re-check the document, and clarify whether the RM is correct in
+ * the overview or in the details, and whether the difference is a
+ * clipboard induced error or results from chip revisions
+ *
+ * it turns out that the RM rev4 as of 2012-06 talks about "can" for the
+ * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
+ * first a doc update is required which better reflects reality in the
+ * SoC before the implementation should follow while no questions remain
+ */
+
+/*
+ * note that this declaration raises a checkpatch warning, but
+ * it's the very data type which <linux/clk-provider.h> expects,
+ * making this declaration pass checkpatch will break compilation
+ */
+static const char *parent_names_mux0[] = {
+       "sys", "ref", "psc-mclk-in", "spdif-tx",
+};
+
+enum mclk_type {
+       MCLK_TYPE_PSC,
+       MCLK_TYPE_MSCAN,
+       MCLK_TYPE_SPDIF,
+};
+
+struct mclk_setup_data {
+       enum mclk_type type;
+       int comp_idx;
+       bool has_mclk1;
+       int bit_sccr1, bit_sccr2;
+       const char *name_mux0;
+       const char *name_en0;
+       const char *name_div0;
+       const char *parent_names_mux1[2];
+       const char *name_mux1;
+       const char *name_mclk;
+};
+
+#define MCLK_SETUP_DATA_PSC(id) { \
+       MCLK_TYPE_PSC, id, \
+       0, 27 - id, -1, \
+       "psc" #id "-mux0", \
+       "psc" #id "-en0", \
+       "psc" #id "_mclk_div", \
+       { "psc" #id "_mclk_div", "dummy", }, \
+       "psc" #id "_mclk_out", \
+       "psc" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_MSCAN(id) { \
+       MCLK_TYPE_MSCAN, id, \
+       0, -1, 25, \
+       "mscan" #id "-mux0", \
+       "mscan" #id "-en0", \
+       "mscan" #id "_mclk_div", \
+       { "mscan" #id "_mclk_div", "dummy", }, \
+       "mscan" #id "_mclk_out", \
+       "mscan" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_SPDIF { \
+       MCLK_TYPE_SPDIF, 0, \
+       1, -1, 23, \
+       "spdif-mux0", \
+       "spdif-en0", \
+       "spdif_mclk_div", \
+       { "spdif_mclk_div", "spdif-rx", }, \
+       "spdif_mclk_out", \
+       "spdif_mclk", \
+}
+
+static struct mclk_setup_data mclk_psc_data[] = {
+       MCLK_SETUP_DATA_PSC(0),
+       MCLK_SETUP_DATA_PSC(1),
+       MCLK_SETUP_DATA_PSC(2),
+       MCLK_SETUP_DATA_PSC(3),
+       MCLK_SETUP_DATA_PSC(4),
+       MCLK_SETUP_DATA_PSC(5),
+       MCLK_SETUP_DATA_PSC(6),
+       MCLK_SETUP_DATA_PSC(7),
+       MCLK_SETUP_DATA_PSC(8),
+       MCLK_SETUP_DATA_PSC(9),
+       MCLK_SETUP_DATA_PSC(10),
+       MCLK_SETUP_DATA_PSC(11),
+};
+
+static struct mclk_setup_data mclk_mscan_data[] = {
+       MCLK_SETUP_DATA_MSCAN(0),
+       MCLK_SETUP_DATA_MSCAN(1),
+       MCLK_SETUP_DATA_MSCAN(2),
+       MCLK_SETUP_DATA_MSCAN(3),
+};
+
+static struct mclk_setup_data mclk_spdif_data[] = {
+       MCLK_SETUP_DATA_SPDIF,
+};
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry)
+{
+       size_t clks_idx_pub, clks_idx_int;
+       u32 __iomem *mccr_reg;  /* MCLK control register (mux, en, div) */
+       u32 __iomem *sccr_reg;  /* system clock control register (enable) */
+       int sccr_bit;
+       int div;
+
+       /* derive a few parameters from the component type and index */
+       switch (entry->type) {
+       case MCLK_TYPE_PSC:
+               clks_idx_pub = MPC512x_CLK_PSC0_MCLK + entry->comp_idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (entry->comp_idx) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->psc_ccr[entry->comp_idx];
+               break;
+       case MCLK_TYPE_MSCAN:
+               clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + entry->comp_idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + entry->comp_idx) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->mscan_ccr[entry->comp_idx];
+               break;
+       case MCLK_TYPE_SPDIF:
+               clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->spccr;
+               break;
+       default:
+               return;
+       }
+       if (entry->bit_sccr1 >= 0) {
+               sccr_reg = &clkregs->sccr1;
+               sccr_bit = entry->bit_sccr1;
+       } else if (entry->bit_sccr2 >= 0) {
+               sccr_reg = &clkregs->sccr2;
+               sccr_bit = entry->bit_sccr2;
+       } else {
+               sccr_reg = NULL;
+       }
+
+       /*
+        * this was grabbed from the PPC_CLOCK implementation, which
+        * enforced a specific MCLK divider while the clock was gated
+        * during setup (that's a documented hardware requirement)
+        *
+        * the PPC_CLOCK implementation might even have violated the
+        * "MCLK <= IPS" constraint, the fixed divider value of 1
+        * results in a divider of 2 and thus MCLK = SYS/2 which equals
+        * CSB which is greater than IPS; the serial port setup may have
+        * adjusted the divider which the clock setup might have left in
+        * an undesirable state
+        *
+        * initial setup is:
+        * - MCLK 0 from SYS
+        * - MCLK DIV such to not exceed the IPS clock
+        * - MCLK 0 enabled
+        * - MCLK 1 from MCLK DIV
+        */
+       div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+       div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+       out_be32(mccr_reg, (0 << 16));
+       out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+       out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+       /*
+        * create the 'struct clk' items of the MCLK's clock subtree
+        *
+        * note that by design we always create all nodes and won't take
+        * shortcuts here, because
+        * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+        *   selectable inputs to the CFM while those who "actually use"
+        *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+        *   for their bitrate
+        * - in the absence of "aliases" for clocks we need to create
+        *   individial 'struct clk' items for whatever might get
+        *   referenced or looked up, even if several of those items are
+        *   identical from the logical POV (their rate value)
+        * - for easier future maintenance and for better reflection of
+        *   the SoC's documentation, it appears appropriate to generate
+        *   clock items even for those muxers which actually are NOPs
+        *   (those with two inputs of which one is reserved)
+        */
+       clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+                       entry->name_mux0,
+                       &parent_names_mux0[0], ARRAY_SIZE(parent_names_mux0),
+                       mccr_reg, 14, 2);
+       clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+                       entry->name_en0, entry->name_mux0,
+                       mccr_reg, 16);
+       clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+                       entry->name_div0,
+                       entry->name_en0, CLK_SET_RATE_GATE,
+                       mccr_reg, 17, 15, 0);
+       if (entry->has_mclk1) {
+               clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_muxed(
+                               entry->name_mux1,
+                               &entry->parent_names_mux1[0],
+                               ARRAY_SIZE(entry->parent_names_mux1),
+                               mccr_reg, 7, 1);
+       } else {
+               clks[clks_idx_int + MCLK_IDX_MUX1] = mpc512x_clk_factor(
+                               entry->name_mux1, entry->parent_names_mux1[0],
+                               1, 1);
+       }
+       if (sccr_reg) {
+               clks[clks_idx_pub] = mpc512x_clk_gated(
+                               entry->name_mclk,
+                               entry->name_mux1, sccr_reg, sccr_bit);
+       } else {
+               clks[clks_idx_pub] = mpc512x_clk_factor(
+                               entry->name_mclk,
+                               entry->name_mux1, 1, 1);
+       }
+
+       /*
+        * without this "clock device" registration, "simple" lookups in
+        * the SPI master initialization and serial port setup will fail
+        *
+        * those drivers need to get adjusted to lookup their required
+        * clocks from device tree specs, and device tree nodes need to
+        * provide the clock specs, before this clkdev registration
+        * becomes obsolete
+        */
+       clk_register_clkdev(clks[clks_idx_pub], entry->name_mclk, NULL);
+}
+
+static void mpc512x_clk_setup_mclks(struct mclk_setup_data *table, size_t count)
+{
+       while (count-- > 0)
+               mpc512x_clk_setup_mclk(table++);
+}
+
+static void mpc512x_clk_setup_clock_tree(int busfreq)
+{
+       int sys_mul, sys_div, ips_div;
+       int mul, div;
+       int freq;
+
+       /*
+        * TODO
+        * - consider whether to handle clocks which have both gates and
+        *   dividers via intermediates or by means of composites
+        * - fractional dividers appear to not map well to composites
+        *   since they can be seen as a fixed multiplier and an
+        *   adjustable divider, while composites can only combine at
+        *   most one of a mux, div, and gate each into one 'struct clk'
+        *   item
+        * - PSC/MSCAN/SPDIF clock generation OTOH already is very
+        *   specific and cannot get mapped to componsites (at least not
+        *   a single one, maybe two of them, but see the comment about
+        *   "intermediates are referenced from elsewhere, too")
+        * - trim the list of auto-enabled clocks after drivers acquire
+        *   them correctly as needed
+        */
+
+       /* regardless of whether XTAL/OSC exists, have REF created */
+       mpc512x_clk_setup_ref_clock(busfreq, &sys_mul, &sys_div, &ips_div);
+
+       /* now setup the REF -> SYS -> CSB -> IPS hierarchy */
+       clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
+                                                  sys_mul, sys_div);
+       clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
+       clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
+                                                    &clkregs->scfr1, 23, 3,
+                                                    divtab_2346);
+
+       /* now setup anything below SYS and CSB and IPS */
+       clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
+       clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 4, 1);
+       clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
+                                                       &clkregs->scfr2, 0, 8,
+                                                       CLK_DIVIDER_ONE_BASED);
+       clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
+       clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
+                                                      &clkregs->scfr1, 0, 8,
+                                                      CLK_DIVIDER_ONE_BASED);
+
+       /*
+        * the "power architecture PLL" was setup from data which was
+        * sampled from the reset config word, at this point in time the
+        * configuration can be considered fixed and read only (i.e. no
+        * longer adjustable, or no longer in need of adjustment), which
+        * is why we don't register a PLL here but assume fixed factors
+        */
+       mul = get_cpmf_mult_x2();
+       div = 2;        /* compensate for the fractional factor */
+       clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
+
+       clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor("mbx-bus-ug", "csb",
+                                                         1, 2);
+       clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable("mbx-ug", "mbx-bus-ug",
+                                                       &clkregs->scfr1, 14, 3,
+                                                       divtab_1234);
+       clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor("mbx-3d-ug", "mbx-ug",
+                                                        1, 1);
+       clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable("pci-ug", "csb",
+                                                       &clkregs->scfr1, 20, 3,
+                                                       divtab_2346);
+       clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable("nfc-ug", "ips",
+                                                       &clkregs->scfr1, 8, 3,
+                                                       divtab_1234);
+       clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
+                                                       &clkregs->scfr1, 11, 3,
+                                                       divtab_1234);
+
+       clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
+                                                 &clkregs->sccr1, 30);
+       clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
+                                                 &clkregs->sccr1, 29);
+       clks[MPC512x_CLK_PATA] = mpc512x_clk_gated("pata", "ips",
+                                                  &clkregs->sccr1, 28);
+       mpc512x_clk_setup_mclks(mclk_psc_data, ARRAY_SIZE(mclk_psc_data));
+       clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
+                                                      &clkregs->sccr1, 15);
+       clks[MPC512x_CLK_SATA] = mpc512x_clk_gated("sata", "ips",
+                                                  &clkregs->sccr1, 14);
+       clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
+                                                 &clkregs->sccr1, 13);
+       clks[MPC512x_CLK_PCI] = mpc512x_clk_gated("pci", "pci-ug",
+                                                 &clkregs->sccr1, 11);
+       clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
+                                                 &clkregs->sccr1, 10);
+
+       clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
+                                                 &clkregs->sccr2, 31);
+       clks[MPC512x_CLK_AXE] = mpc512x_clk_gated("axe", "csb",
+                                                 &clkregs->sccr2, 30);
+       clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
+                                                 &clkregs->sccr2, 29);
+       clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
+                                                  &clkregs->sccr2, 28);
+       clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
+                                                  &clkregs->sccr2, 27);
+       clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+                                                 &clkregs->sccr2, 26);
+       mpc512x_clk_setup_mclks(mclk_mscan_data, ARRAY_SIZE(mclk_mscan_data));
+       clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+                                                  &clkregs->sccr2, 24);
+       mpc512x_clk_setup_mclks(mclk_spdif_data, ARRAY_SIZE(mclk_spdif_data));
+       clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated("mbx-bus", "mbx-bus-ug",
+                                                     &clkregs->sccr2, 22);
+       clks[MPC512x_CLK_MBX] = mpc512x_clk_gated("mbx", "mbx-ug",
+                                                 &clkregs->sccr2, 21);
+       clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated("mbx-3d", "mbx-3d-ug",
+                                                    &clkregs->sccr2, 20);
+       clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
+                                                 &clkregs->sccr2, 19);
+       clks[MPC512x_CLK_VIU] = mpc512x_clk_gated("viu", "csb",
+                                                 &clkregs->sccr2, 18);
+       clks[MPC512x_CLK_SDHC_2] = mpc512x_clk_gated("sdhc-2", "sdhc-ug",
+                                                    &clkregs->sccr2, 17);
+
+       /*
+        * externally provided clocks (when implemented in hardware,
+        * device tree may specify values which otherwise were unknown)
+        */
+       freq = get_freq_from_dt("psc_mclk_in");
+       if (!freq)
+               freq = 25000000;
+       clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+       freq = get_freq_from_dt("spdif_tx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_tx_in", freq);
+       freq = get_freq_from_dt("spdif_rx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_rx_in", freq);
+
+       /* fixed frequency for AC97, always 24.567MHz */
+       clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
+
+       /* clkdev registration for compatibility reasons */
+       clk_register_clkdev(clks[MPC512x_CLK_REF], "ref_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_VIU], "viu_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_NFC], "nfc_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_USB1], "usb1_clk", NULL);
+       clk_register_clkdev(clks[MPC512x_CLK_USB2], "usb2_clk", NULL);
+
+       pr_debug("clock tree setup complete\n");
+       freq = clk_get_rate(clks[MPC512x_CLK_E300]);
+       pr_debug("derived PPC freq [%d]\n", freq);
+       freq = clk_get_rate(clks[MPC512x_CLK_IPS]);
+       pr_debug("derived IPS freq [%d]\n", freq);
+       freq = clk_get_rate(clks[MPC512x_CLK_LPC]);
+       pr_debug("derived LPC freq [%d]\n", freq);
+
+       /* enable some of the clocks here unconditionally because ... */
+       pr_debug("automatically enabling some clocks\n");
+       /* some are essential yet never get claimed by any driver */
+       clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+       clk_prepare_enable(clks[MPC512x_CLK_E300]);     /* PowerPC CPU */
+       clk_prepare_enable(clks[MPC512x_CLK_DDR]);      /* DRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_MEM]);      /* SRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_IPS]);      /* SoC periph */
+       clk_prepare_enable(clks[MPC512x_CLK_LPC]);      /* boot media */
+       /* some are required yet no dependencies were declared */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC_FIFO]);
+       /* some are not yet acquired by their respective drivers */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+       clk_prepare_enable(clks[MPC512x_CLK_FEC]);      /* network, NFS */
+       clk_prepare_enable(clks[MPC512x_CLK_DIU]);      /* display */
+       clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+       /*
+        * some have their individual clock subtree with separate clock
+        * items and their individual enable counters, yet share a
+        * common gate (refer to the same register location) while the
+        * common clock driver code is not aware of the fact and the
+        * platform's code doesn't provide specific support either
+        *
+        * what might happen is that e.g. enabling two MSCAN clock items
+        * and disabling one of them will disable the common gate and
+        * thus break the other MSCAN clock as well
+        */
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN0_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN1_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN2_MCLK]);
+       clk_prepare_enable(clks[MPC512x_CLK_MSCAN3_MCLK]);
+}
+
+/*
+ * registers the set of public clocks (those listed in the dt-bindings/
+ * header file) for OF lookups, keeps the intermediates private to us
+ */
+static void mpc5121_clk_register_of_provider(struct device_node *np)
+{
+       clk_data.clks = clks;
+       clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1; /* _not_ ARRAY_SIZE() */
+       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+int __init mpc5121_clk_init(void)
+{
+       struct device_node *clk_np;
+       int busfreq;
+
+       /* map the clock control registers */
+       clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+       if (!clk_np)
+               return -ENODEV;
+       clkregs = of_iomap(clk_np, 0);
+       WARN_ON(!clkregs);
+
+       /* invalidate all not yet registered clock slots */
+       mpc512x_clk_preset_data();
+
+       /*
+        * have the device tree scanned for "fixed-clock" nodes (which
+        * includes the oscillator node if the board's DT provides one)
+        */
+       of_clk_init(NULL);
+
+       /*
+        * add a dummy clock for those situations where a clock spec is
+        * required yet no real clock is involved
+        */
+       clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0);
+
+       /*
+        * have all the real nodes in the clock tree populated from REF
+        * down to all leaves, either starting from the OSC node or from
+        * a REF root that was created from the IPS bus clock input
+        */
+       busfreq = get_freq_from_dt("bus-frequency");
+       mpc512x_clk_setup_clock_tree(busfreq);
+
+       /* register as an OF clock provider */
+       mpc5121_clk_register_of_provider(clk_np);
+
+       return 0;
+}
include/linux/clk-provider.h +14 -0
index c4f7799..7f8fc64 100644
@@ -497,6 +497,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       iowrite32be(val, reg);
+}
+
+#else  /* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
        return readl(reg);
@@ -507,5 +521,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
        writel(val, reg);
 }
 
Quoted 6 lines
Quoted 6 lines
include/linux/clk-provider.h +2 -0
+#endif /* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
Signature · 1 line
1.7.10.4

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#109 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

In reply to Gerhard Sittig
Quoted 48 lines · Gerhard Sittig

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

this driver implements the publicly announced set of clocks (which can get referenced by means of symbolic identifiers from the dt-bindings header file), as well as generates additional 'struct clk' items where the SoC hardware cannot easily get mapped to the common primitives of the clock API, or requires "intermediate" clock nodes to represent clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and remains in parallel to the common clock implementation for test and comparison during migration, a compile time option picks one of the two alternatives (Kconfig switch, common clock used by default)

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information despite their not getting claimed by any drivers (CPU, internal and external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet, either because of missing driver support or because device tree specs aren't available yet (but the workarounds will get removed as the drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after device tree based clock lookup has become available

---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c

[...]

Quoted 6 lines
arch/powerpc/platforms/512x/clock-commonclk.c new file +6 -0
+static int get_freq_from_dt(char *propname)
+{
+       struct device_node *np;
+       const unsigned int *prop;
+       int val;
+

arch/powerpc/platforms/512x/clock-commonclk.c line 242

Quoted 10 lines
arch/powerpc/platforms/512x/clock-commonclk.c new file +10 -0
+       val = 0;
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+       if (np) {
+               prop = of_get_property(np, propname, NULL);
+               if (prop)
+                       val = *prop;
+           of_node_put(np);
+       }
+       return val;
+}

Can you not use of_property_read_u32 here rather than of_get_property?

Also, this seems rather unlike the common clock bindings method for describing frequencies in the dt. Given there's nothing in mainline using this yet, we can do it 'right' from the start.

[...]

arch/powerpc/platforms/512x/clock-commonclk.c line 682

Quoted 12 lines
arch/powerpc/platforms/512x/clock-commonclk.c new file +12 -0
+       /*
+        * externally provided clocks (when implemented in hardware,
+        * device tree may specify values which otherwise were unknown)
+        */
+       freq = get_freq_from_dt("psc_mclk_in");
+       if (!freq)
+               freq = 25000000;
+       clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+       freq = get_freq_from_dt("spdif_tx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_tx_in", freq);
+       freq = get_freq_from_dt("spdif_rx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_rx_in", freq);

Can we not just use fixed-clocks for these in the dt? It feels odd to describe them in a compeltely differnet way in the dt, especially as we'll have to maintain some backwards compatibility for a while...

I see for psc_mclk_in we assume a default value if not present. I'm not sure how to handle that, but I assume there's some way of finding out if we've already registered a clock output with the same name?

Thanks,
Mark.

#110 lore raw

PATCH v3 17/31 clk: mpc512x: introduce COMMON_CLK for MPC512x

Quoted 72 lines · Mark Rutland
Quoted 48 lines · Gerhard Sittig

this change implements a clock driver for the MPC512x PowerPC platform which follows the COMMON_CLK approach and uses common clock drivers shared with other platforms

this driver implements the publicly announced set of clocks (which can get referenced by means of symbolic identifiers from the dt-bindings header file), as well as generates additional 'struct clk' items where the SoC hardware cannot easily get mapped to the common primitives of the clock API, or requires "intermediate" clock nodes to represent clocks that have both gates and dividers

the previous PPC_CLOCK implementation is kept in place and remains in parallel to the common clock implementation for test and comparison during migration, a compile time option picks one of the two alternatives (Kconfig switch, common clock used by default)

some of the clock items get pre-enabled in the clock driver to not have them automatically disabled by the underlying clock subsystem because of their being unused -- this approach is desirable because
- some of the clocks are useful to have for diagnostics and information despite their not getting claimed by any drivers (CPU, internal and external RAM, internal busses, boot media)
- some of the clocks aren't claimed by their peripheral drivers yet, either because of missing driver support or because device tree specs aren't available yet (but the workarounds will get removed as the drivers get adjusted and the device tree provides the clock specs)
- some help introduce support for and migrate to the common infrastructure, while more appropriate support for specific hardware constraints isn't available yet (remaining changes are strictly internal to the clock driver and won't affect peripheral drivers)

clkdev registration provides "alias names" for few clock items
- to not break those peripheral drivers which encode their component index into the name that is used for clock lookup (UART, SPI, USB)
- to not break those drivers which use names for the clock lookup which were encoded in the previous PPC_CLOCK implementation (NFC, VIU, CAN)
this workaround will get removed as these drivers get adjusted after device tree based clock lookup has become available

---
 arch/powerpc/platforms/512x/Kconfig           |   14 +-
 arch/powerpc/platforms/512x/Makefile          |    4 +-
 arch/powerpc/platforms/512x/clock-commonclk.c |  786 +++++++++++++++++++++++++
 include/linux/clk-provider.h                  |   16 +
 4 files changed, 818 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/clock-commonclk.c

[...]

Quoted 6 lines
arch/powerpc/platforms/512x/clock-commonclk.c new file +6 -0
+static int get_freq_from_dt(char *propname)
+{
+       struct device_node *np;
+       const unsigned int *prop;
+       int val;
+

arch/powerpc/platforms/512x/clock-commonclk.c line 242

Quoted 10 lines
arch/powerpc/platforms/512x/clock-commonclk.c new file +10 -0
+       val = 0;
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+       if (np) {
+               prop = of_get_property(np, propname, NULL);
+               if (prop)
+                       val = *prop;
+           of_node_put(np);
+       }
+       return val;
+}

Can you not use of_property_read_u32 here rather than of_get_property?

Quoted 3 lines

Also, this seems rather unlike the common clock bindings method for describing frequencies in the dt. Given there's nothing in mainline using this yet, we can do it 'right' from the start.

This specific routine was taken in verbatim form from the former PPC_CLOCK implementation. Although I could re-implement it in other ways if that was considered necessary.

Quoted 16 lines

[...]

arch/powerpc/platforms/512x/clock-commonclk.c line 682

Quoted 12 lines
arch/powerpc/platforms/512x/clock-commonclk.c new file +12 -0
+       /*
+        * externally provided clocks (when implemented in hardware,
+        * device tree may specify values which otherwise were unknown)
+        */
+       freq = get_freq_from_dt("psc_mclk_in");
+       if (!freq)
+               freq = 25000000;
+       clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+       freq = get_freq_from_dt("spdif_tx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_tx_in", freq);
+       freq = get_freq_from_dt("spdif_rx_in");
+       clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed("spdif_rx_in", freq);
Quoted 7 lines

Can we not just use fixed-clocks for these in the dt? It feels odd to describe them in a compeltely differnet way in the dt, especially as we'll have to maintain some backwards compatibility for a while...

I see for psc_mclk_in we assume a default value if not present. I'm not sure how to handle that, but I assume there's some way of finding out if we've already registered a clock output with the same name?

I guess using fixed-clocks (i.e. clock items that completely get described in the device tree, and are taken care of by a common driver which attaches to anything that is said to be compatible) would change behaviour, which I did not intend to introduce.

The above code does what the PPC_CLOCK implementation did: Always create the clock items, while their _rate_ may or may not be specified or overridden from device tree specs, and defaults (non-zero or zero) always apply.

Thank you for the feedback and suggestions. I've yet to find out how much compatibility I'm allowed to break. :) ATM I assume that my changes do keep compatibility where appropriate, and only change the device tree or its interpretation where the device tree may be considered wrong (not that it would provide false information, but it certainly lacked essential information about the hardware, like clock related information, and thus it shall be acceptable to require an update of the dtb to fix that gap).

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#111 lore raw

PATCH v3 18/31 dts: mpc512x: add clock specs for client lookups

In reply to Gerhard Sittig

this addresses the client side of device tree based clock lookups

add clock specifiers to the mbx, nfc, mscan, sdhc, i2c, axe, diu, viu, mdio, fec, usb, pata, psc, psc fifo, and pci nodes in the shared mpc5121.dtsi include

these specs map 'clock-names' encoded in drivers to their respective 'struct clk' items in the platform's clock driver

---
 arch/powerpc/boot/dts/mpc5121.dtsi |   79 ++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
arch/powerpc/boot/dts/mpc5121.dtsi +79 -0
index 8f4cba0..3657ae6 100644
@@ -51,6 +51,10 @@
 		compatible = "fsl,mpc5121-mbx";
 		reg = <0x20000000 0x4000>;
 		interrupts = <66 0x8>;
+		clocks = <&clks MPC512x_CLK_MBX_BUS>,
+			 <&clks MPC512x_CLK_MBX_3D>,
+			 <&clks MPC512x_CLK_MBX>;
+		clock-names = "mbx-bus", "mbx-3d", "mbx";
 	};
 
 	sram at 30000000 {
@@ -64,6 +68,8 @@
 		interrupts = <6 8>;
 		#address-cells = <1>;
 		#size-cells = <1>;
+		clocks = <&clks MPC512x_CLK_NFC>;
+		clock-names = "per";
 	};
 
 	localbus at 80000020 {
@@ -153,12 +159,22 @@
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1300 0x80>;
 			interrupts = <12 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN0_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can at 1380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x1380 0x80>;
 			interrupts = <13 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN1_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		sdhc at 1500 {
@@ -167,6 +183,9 @@
 			interrupts = <8 0x8>;
 			dmas = <&dma0 30>;
 			dma-names = "rx-tx";
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SDHC>;
+			clock-names = "ipg", "per";
 		};
 
 		i2c at 1700 {
@@ -175,6 +194,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1700 0x20>;
 			interrupts = <9 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c at 1720 {
@@ -183,6 +204,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1720 0x20>;
 			interrupts = <10 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2c at 1740 {
@@ -191,6 +214,8 @@
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
 			reg = <0x1740 0x20>;
 			interrupts = <11 0x8>;
+			clocks = <&clks MPC512x_CLK_I2C>;
+			clock-names = "per";
 		};
 
 		i2ccontrol at 1760 {
@@ -202,30 +227,46 @@
 			compatible = "fsl,mpc5121-axe";
 			reg = <0x2000 0x100>;
 			interrupts = <42 0x8>;
+			clocks = <&clks MPC512x_CLK_AXE>;
+			clock-names = "per";
 		};
 
 		display at 2100 {
 			compatible = "fsl,mpc5121-diu";
 			reg = <0x2100 0x100>;
 			interrupts = <64 0x8>;
+			clocks = <&clks MPC512x_CLK_DIU>;
+			clock-names = "per";
 		};
 
 		can at 2300 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2300 0x80>;
 			interrupts = <90 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN2_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		can at 2380 {
 			compatible = "fsl,mpc5121-mscan";
 			reg = <0x2380 0x80>;
 			interrupts = <91 0x8>;
+			clocks = <&clks MPC512x_CLK_IPS>,
+				 <&clks MPC512x_CLK_SYS>,
+				 <&clks MPC512x_CLK_REF>,
+				 <&clks MPC512x_CLK_MSCAN3_MCLK>;
+			clock-names = "ips", "sys", "ref", "mclk";
 		};
 
 		viu at 2400 {
 			compatible = "fsl,mpc5121-viu";
 			reg = <0x2400 0x400>;
 			interrupts = <67 0x8>;
+			clocks = <&clks MPC512x_CLK_VIU>;
+			clock-names = "per";
 		};
 
 		mdio at 2800 {
@@ -233,6 +274,8 @@
 			reg = <0x2800 0x800>;
 			#address-cells = <1>;
 			#size-cells = <0>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		eth0: ethernet at 2800 {
@@ -241,6 +284,8 @@
 			reg = <0x2800 0x800>;
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <4 0x8>;
+			clocks = <&clks MPC512x_CLK_FEC>;
+			clock-names = "per";
 		};
 
 		/* USB1 using external ULPI PHY */
@@ -252,6 +297,8 @@
 			interrupts = <43 0x8>;
 			dr_mode = "otg";
 			phy_type = "ulpi";
+			clocks = <&clks MPC512x_CLK_USB1>;
+			clock-names = "per";
 		};
 
 		/* USB0 using internal UTMI PHY */
@@ -263,6 +310,8 @@
 			interrupts = <44 0x8>;
 			dr_mode = "otg";
 			phy_type = "utmi_wide";
+			clocks = <&clks MPC512x_CLK_USB2>;
+			clock-names = "per";
 		};
 
 		/* IO control */
@@ -281,6 +330,8 @@
 			compatible = "fsl,mpc5121-pata";
 			reg = <0x10200 0x100>;
 			interrupts = <5 0x8>;
+			clocks = <&clks MPC512x_CLK_PATA>;
+			clock-names = "per";
 		};
 
 		/* 512x PSCs are not 52xx PSC compatible */
@@ -292,6 +343,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC0_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC1 */
@@ -301,6 +354,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC1_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC2 */
@@ -310,6 +365,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC2_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC3 */
@@ -319,6 +376,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC3_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC4 */
@@ -328,6 +387,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC4_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC5 */
@@ -337,6 +398,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC5_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC6 */
@@ -346,6 +409,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC6_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC7 */
@@ -355,6 +420,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC7_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC8 */
@@ -364,6 +431,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC8_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC9 */
@@ -373,6 +442,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC9_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC10 */
@@ -382,6 +453,8 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC10_MCLK>;
+			clock-names = "mclk";
 		};
 
 		/* PSC11 */
@@ -391,12 +464,16 @@
 			interrupts = <40 0x8>;
 			fsl,rx-fifo-size = <16>;
 			fsl,tx-fifo-size = <16>;
+			clocks = <&clks MPC512x_CLK_PSC11_MCLK>;
+			clock-names = "mclk";
 		};
 
 		pscfifo at 11f00 {
 			compatible = "fsl,mpc5121-psc-fifo";
 			reg = <0x11f00 0x100>;
 			interrupts = <40 0x8>;
+			clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+			clock-names = "per";
 		};
 
 		dma0: dma at 14000 {
@@ -414,6 +491,8 @@
 		#address-cells = <3>;
 		#size-cells = <2>;
 		#interrupt-cells = <1>;
+		clocks = <&clks MPC512x_CLK_PCI>;
+		clock-names = "per";
 
 		reg = <0x80008500 0x100	/* internal registers */
 		       0x80008300 0x8>;	/* config space access registers */
Signature · 1 line
1.7.10.4
#112 lore raw

PATCH v3 18/31 dts: mpc512x: add clock specs for client lookups

Quoting Gerhard Sittig (2013-07-22 05:14:45)

Quoted 10 lines

this addresses the client side of device tree based clock lookups

add clock specifiers to the mbx, nfc, mscan, sdhc, i2c, axe, diu, viu, mdio, fec, usb, pata, psc, psc fifo, and pci nodes in the shared mpc5121.dtsi include

these specs map 'clock-names' encoded in drivers to their respective 'struct clk' items in the platform's clock driver

Quoted 307 lines
---
 arch/powerpc/boot/dts/mpc5121.dtsi |   79 ++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
arch/powerpc/boot/dts/mpc5121.dtsi +79 -0
index 8f4cba0..3657ae6 100644
@@ -51,6 +51,10 @@
                compatible = "fsl,mpc5121-mbx";
                reg = <0x20000000 0x4000>;
                interrupts = <66 0x8>;
+               clocks = <&clks MPC512x_CLK_MBX_BUS>,
+                        <&clks MPC512x_CLK_MBX_3D>,
+                        <&clks MPC512x_CLK_MBX>;
+               clock-names = "mbx-bus", "mbx-3d", "mbx";
        };
 
        sram at 30000000 {
@@ -64,6 +68,8 @@
                interrupts = <6 8>;
                #address-cells = <1>;
                #size-cells = <1>;
+               clocks = <&clks MPC512x_CLK_NFC>;
+               clock-names = "per";
        };
 
        localbus at 80000020 {
@@ -153,12 +159,22 @@
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x1300 0x80>;
                        interrupts = <12 0x8>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN0_MCLK>;
+                       clock-names = "ips", "sys", "ref", "mclk";
                };
 
                can at 1380 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x1380 0x80>;
                        interrupts = <13 0x8>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN1_MCLK>;
+                       clock-names = "ips", "sys", "ref", "mclk";
                };
 
                sdhc at 1500 {
@@ -167,6 +183,9 @@
                        interrupts = <8 0x8>;
                        dmas = <&dma0 30>;
                        dma-names = "rx-tx";
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SDHC>;
+                       clock-names = "ipg", "per";
                };
 
                i2c at 1700 {
@@ -175,6 +194,8 @@
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1700 0x20>;
                        interrupts = <9 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "per";
                };
 
                i2c at 1720 {
@@ -183,6 +204,8 @@
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1720 0x20>;
                        interrupts = <10 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "per";
                };
 
                i2c at 1740 {
@@ -191,6 +214,8 @@
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1740 0x20>;
                        interrupts = <11 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "per";
                };
 
                i2ccontrol at 1760 {
@@ -202,30 +227,46 @@
                        compatible = "fsl,mpc5121-axe";
                        reg = <0x2000 0x100>;
                        interrupts = <42 0x8>;
+                       clocks = <&clks MPC512x_CLK_AXE>;
+                       clock-names = "per";
                };
 
                display at 2100 {
                        compatible = "fsl,mpc5121-diu";
                        reg = <0x2100 0x100>;
                        interrupts = <64 0x8>;
+                       clocks = <&clks MPC512x_CLK_DIU>;
+                       clock-names = "per";
                };
 
                can at 2300 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x2300 0x80>;
                        interrupts = <90 0x8>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN2_MCLK>;
+                       clock-names = "ips", "sys", "ref", "mclk";
                };
 
                can at 2380 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x2380 0x80>;
                        interrupts = <91 0x8>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN3_MCLK>;
+                       clock-names = "ips", "sys", "ref", "mclk";
                };
 
                viu at 2400 {
                        compatible = "fsl,mpc5121-viu";
                        reg = <0x2400 0x400>;
                        interrupts = <67 0x8>;
+                       clocks = <&clks MPC512x_CLK_VIU>;
+                       clock-names = "per";
                };
 
                mdio at 2800 {
@@ -233,6 +274,8 @@
                        reg = <0x2800 0x800>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       clocks = <&clks MPC512x_CLK_FEC>;
+                       clock-names = "per";
                };
 
                eth0: ethernet at 2800 {
@@ -241,6 +284,8 @@
                        reg = <0x2800 0x800>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <4 0x8>;
+                       clocks = <&clks MPC512x_CLK_FEC>;
+                       clock-names = "per";
                };
 
                /* USB1 using external ULPI PHY */
@@ -252,6 +297,8 @@
                        interrupts = <43 0x8>;
                        dr_mode = "otg";
                        phy_type = "ulpi";
+                       clocks = <&clks MPC512x_CLK_USB1>;
+                       clock-names = "per";
                };
 
                /* USB0 using internal UTMI PHY */
@@ -263,6 +310,8 @@
                        interrupts = <44 0x8>;
                        dr_mode = "otg";
                        phy_type = "utmi_wide";
+                       clocks = <&clks MPC512x_CLK_USB2>;
+                       clock-names = "per";
                };
 
                /* IO control */
@@ -281,6 +330,8 @@
                        compatible = "fsl,mpc5121-pata";
                        reg = <0x10200 0x100>;
                        interrupts = <5 0x8>;
+                       clocks = <&clks MPC512x_CLK_PATA>;
+                       clock-names = "per";
                };
 
                /* 512x PSCs are not 52xx PSC compatible */
@@ -292,6 +343,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC0_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC1 */
@@ -301,6 +354,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC1_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC2 */
@@ -310,6 +365,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC2_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC3 */
@@ -319,6 +376,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC3_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC4 */
@@ -328,6 +387,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC4_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC5 */
@@ -337,6 +398,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC5_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC6 */
@@ -346,6 +409,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC6_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC7 */
@@ -355,6 +420,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC7_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC8 */
@@ -364,6 +431,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC8_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC9 */
@@ -373,6 +442,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC9_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC10 */
@@ -382,6 +453,8 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC10_MCLK>;
+                       clock-names = "mclk";
                };
 
                /* PSC11 */
@@ -391,12 +464,16 @@
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC11_MCLK>;
+                       clock-names = "mclk";
                };
 
                pscfifo at 11f00 {
                        compatible = "fsl,mpc5121-psc-fifo";
                        reg = <0x11f00 0x100>;
                        interrupts = <40 0x8>;
+                       clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+                       clock-names = "per";
                };
 
                dma0: dma at 14000 {
@@ -414,6 +491,8 @@
                #address-cells = <3>;
                #size-cells = <2>;
                #interrupt-cells = <1>;
+               clocks = <&clks MPC512x_CLK_PCI>;
+               clock-names = "per";
 
                reg = <0x80008500 0x100 /* internal registers */
                       0x80008300 0x8>; /* config space access registers */
Signature · 1 line
1.7.10.4