diff mbox

[v1,09/14] clk: msm: Add support for MSM8960's global clock controller (GCC)

Message ID 1374713022-6049-10-git-send-email-sboyd@codeaurora.org (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Stephen Boyd July 25, 2013, 12:43 a.m. UTC
Fill in the data and wire up the global clock controller to the
MSM clock driver. This should allow most non-multimedia device
drivers to control their clocks on 8960 based platforms.

Cc: devicetree@vger.kernel.org
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 .../devicetree/bindings/clock/qcom,gcc.txt         |  55 +++++++
 drivers/clk/msm/Kconfig                            |  10 ++
 drivers/clk/msm/Makefile                           |   2 +
 drivers/clk/msm/core.c                             |   3 +
 drivers/clk/msm/gcc-8960.c                         | 174 +++++++++++++++++++++
 drivers/clk/msm/internal.h                         |   2 +
 6 files changed, 246 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/qcom,gcc.txt
 create mode 100644 drivers/clk/msm/gcc-8960.c

Comments

Mark Rutland Aug. 8, 2013, 5 p.m. UTC | #1
Hi Stephen,

On Thu, Jul 25, 2013 at 01:43:37AM +0100, Stephen Boyd wrote:
> Fill in the data and wire up the global clock controller to the
> MSM clock driver. This should allow most non-multimedia device
> drivers to control their clocks on 8960 based platforms.
> 
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
>  .../devicetree/bindings/clock/qcom,gcc.txt         |  55 +++++++
>  drivers/clk/msm/Kconfig                            |  10 ++
>  drivers/clk/msm/Makefile                           |   2 +
>  drivers/clk/msm/core.c                             |   3 +
>  drivers/clk/msm/gcc-8960.c                         | 174 +++++++++++++++++++++
>  drivers/clk/msm/internal.h                         |   2 +
>  6 files changed, 246 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/qcom,gcc.txt
>  create mode 100644 drivers/clk/msm/gcc-8960.c
> 
> diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> new file mode 100644
> index 0000000..2311e1a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> @@ -0,0 +1,55 @@
> +MSM Global Clock Controller Binding
> +-----------------------------------
> +
> +Required properties :
> +- compatible : shall contain at least "qcom,gcc" and only one of the
> +              following:
> +
> +                       "qcom,gcc-8660"
> +                       "qcom,gcc-8960"
> +
> +- reg : shall contain base register location and length
> +- clocks : shall contain clocks supplied by the clock controller
> +
> +Example:
> +       clock-controller@900000 {
> +               compatible = "qcom,gcc-8960", "qcom,gcc";
> +               reg = <0x900000 0x4000>;
> +
> +               clocks {
> +                       pxo: pxo {
> +                               #clock-cells = <0>;
> +                               compatible = "fixed-clock";
> +                               clock-frequency = <27000000>;
> +                       };
> +
> +                       pll8: pll8 {
> +                               #clock-cells = <0>;
> +                               compatible = "qcom,pll";
> +                               clocks = <&pxo>;
> +                       };
> +
> +                       vpll8: vpll8 {
> +                               #clock-cells = <0>;
> +                               compatible = "qcom,pll-vote";
> +                               clocks = <&pll8>;
> +                       };
> +
> +                       gsbi5_uart_rcg: gsbi5_uart_rcg {
> +                               #clock-cells = <0>;
> +                               compatible = "qcom,p2-mn16-clock";
> +                               clocks = <&pxo>, <&vpll8>;
> +                       };
> +
> +                       gsbi5_uart_clk: gsbi5_uart_cxc {
> +                               #clock-cells = <0>;
> +                               compatible = "qcom,cxc-clock";
> +                               clocks = <&gsbi5_uart_rcg>;
> +                       };
> +
> +                       gsbi5_uart_ahb: gsbi5_uart_ahb {
> +                               #clock-cells = <0>;
> +                               compatible = "qcom,cxc-hg-clock";
> +                       };
> +               };
> +       };

I'm slightly confused by this. How is each of the clocks described in
the clocks node related to a portion of the register set?

If the set of clocks is fixed, surely the gcc node gives you enough
information alone, and the whole block can be modelled as a single
provider of multiple clock outputs, or it's not fixed, and some linkage
needs to be defined?

The code seems to imply the former, unless only a subset of clocks may
be present? In that case, the set of clocks which might be present
should be described in the binding.

Thanks,
Mark.

> diff --git a/drivers/clk/msm/Kconfig b/drivers/clk/msm/Kconfig
> index bf7e3d2..3eaffb6 100644
> --- a/drivers/clk/msm/Kconfig
> +++ b/drivers/clk/msm/Kconfig
> @@ -2,3 +2,13 @@ menuconfig COMMON_CLK_MSM
>         tristate "Support for Qualcomm's MSM designs"
>         depends on OF
> 
> +if COMMON_CLK_MSM
> +
> +config MSM_GCC_8960
> +       bool "MSM8960 Global Clock Controller"
> +       help
> +         Support for the global clock controller on msm8960 devices.
> +         Say Y if you want to use peripheral devices such as UART, SPI,
> +         i2c, USB, SD/eMMC, SATA, PCIe, etc.
> +
> +endif
> diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile
> index 9cfd0d7..c785943 100644
> --- a/drivers/clk/msm/Makefile
> +++ b/drivers/clk/msm/Makefile
> @@ -6,3 +6,5 @@ clk-msm-$(CONFIG_COMMON_CLK_MSM) += clk-rcg2.o
>  clk-msm-$(CONFIG_COMMON_CLK_MSM) += clk-branch.o
> 
>  clk-msm-$(CONFIG_COMMON_CLK_MSM) += core.o
> +
> +clk-msm-$(CONFIG_MSM_GCC_8960) += gcc-8960.o
> diff --git a/drivers/clk/msm/core.c b/drivers/clk/msm/core.c
> index b1904c0..b8e702b 100644
> --- a/drivers/clk/msm/core.c
> +++ b/drivers/clk/msm/core.c
> @@ -173,6 +173,9 @@ typedef struct clk *
>                 struct cc_data *cc);
> 
>  static const struct of_device_id msm_cc_match_table[] = {
> +#ifdef CONFIG_MSM_GCC_8960
> +       { .compatible = "qcom,gcc-8960", .data = &msm_gcc_8960_matches },
> +#endif
>         { }
>  };
>  MODULE_DEVICE_TABLE(of, msm_cc_match_table);
> diff --git a/drivers/clk/msm/gcc-8960.c b/drivers/clk/msm/gcc-8960.c
> new file mode 100644
> index 0000000..b57d2dd
> --- /dev/null
> +++ b/drivers/clk/msm/gcc-8960.c
> @@ -0,0 +1,174 @@
> +/*
> + * Copyright (c) 2013, The Linux Foundation. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk-provider.h>
> +
> +#include "internal.h"
> +#include "clk-pll.h"
> +#include "clk-rcg.h"
> +#include "clk-branch.h"
> +
> +static struct pll_desc pll8_desc = {
> +       .l_reg = 0x3144,
> +       .m_reg = 0x3148,
> +       .n_reg = 0x314c,
> +       .config_reg = 0x3154,
> +       .mode_reg = 0x3140,
> +       .status_reg = 0x3158,
> +       .status_bit = 16,
> +};
> +
> +static struct pll_vote_desc pll8_vote_desc = {
> +       .vote_reg = 0x34c0,
> +       .vote_bit = 8,
> +};
> +
> +#define PXO    0
> +#define PLL8   1
> +
> +static u8 gcc_pxo_pll8_map[] = {
> +       [PXO]   = 0,
> +       [PLL8]  = 3,
> +};
> +
> +static struct freq_tbl clk_tbl_gsbi_uart[] = {
> +       {  1843200, PLL8, 2,  6, 625 },
> +       {  3686400, PLL8, 2, 12, 625 },
> +       {  7372800, PLL8, 2, 24, 625 },
> +       { 14745600, PLL8, 2, 48, 625 },
> +       { 16000000, PLL8, 4,  1,   6 },
> +       { 24000000, PLL8, 4,  1,   4 },
> +       { 32000000, PLL8, 4,  1,   3 },
> +       { 40000000, PLL8, 1,  5,  48 },
> +       { 46400000, PLL8, 1, 29, 240 },
> +       { 48000000, PLL8, 4,  1,   2 },
> +       { 51200000, PLL8, 1,  2,  15 },
> +       { 56000000, PLL8, 1,  7,  48 },
> +       { 58982400, PLL8, 1, 96, 625 },
> +       { 64000000, PLL8, 2,  1,   3 },
> +       { }
> +};
> +
> +static struct rcg_desc gsbi5_uart_rcg = {
> +       .ctl_reg = 0x2a54,
> +       .ns_reg = 0x2a54,
> +       .md_reg = 0x2a50,
> +       .ctl_bit = 11,
> +       .mnctr_en_bit = 8,
> +       .mnctr_reset_bit = 7,
> +       .mnctr_mode_shift = 5,
> +       .pre_div_shift = 3,
> +       .src_sel_shift = 0,
> +       .n_val_shift = 16,
> +       .m_val_shift = 16,
> +       .parent_map = gcc_pxo_pll8_map,
> +       .freq_tbl = clk_tbl_gsbi_uart,
> +};
> +
> +static struct branch_desc gsbi5_uart_cxc = {
> +       .ctl_reg = 0x2a54,
> +       .halt_reg = 0x2fd0,
> +       .ctl_bit = 9,
> +       .halt_bit = 22,
> +       .halt_check = BRANCH_HALT,
> +};
> +
> +static struct rcg_desc gsbi6_uart_rcg = {
> +       .ctl_reg = 0x2a74,
> +       .ns_reg = 0x2a74,
> +       .md_reg = 0x2a70,
> +       .ctl_bit = 11,
> +       .mnctr_en_bit = 8,
> +       .mnctr_reset_bit = 7,
> +       .mnctr_mode_shift = 5,
> +       .pre_div_shift = 3,
> +       .src_sel_shift = 0,
> +       .n_val_shift = 16,
> +       .m_val_shift = 16,
> +       .parent_map = gcc_pxo_pll8_map,
> +       .freq_tbl = clk_tbl_gsbi_uart,
> +};
> +
> +static struct branch_desc gsbi6_uart_cxc = {
> +       .ctl_reg = 0x2a74,
> +       .halt_reg = 0x2fd0,
> +       .ctl_bit = 9,
> +       .halt_bit = 18,
> +       .halt_check = BRANCH_HALT,
> +};
> +
> +static struct branch_desc gsbi5_uart_ahb = {
> +       .ctl_reg = 0x2a40,
> +       .halt_reg = 0x2fd0,
> +       .hwcg_reg = 0x2a40,
> +       .ctl_bit = 4,
> +       .hwcg_bit = 6,
> +       .halt_bit = 23,
> +       .halt_check = BRANCH_HALT,
> +};
> +
> +static struct freq_tbl clk_tbl_gsbi_qup[] = {
> +       {  1100000, PXO,  1, 2, 49 },
> +       {  5400000, PXO,  1, 1,  5 },
> +       { 10800000, PXO,  1, 2,  5 },
> +       { 15060000, PLL8, 1, 2, 51 },
> +       { 24000000, PLL8, 4, 1,  4 },
> +       { 25600000, PLL8, 1, 1, 15 },
> +       { 27000000, PXO,  1, 0,  0 },
> +       { 48000000, PLL8, 4, 1,  2 },
> +       { 51200000, PLL8, 1, 2, 15 },
> +       { }
> +};
> +
> +static struct rcg_desc gsbi5_qup_rcg = {
> +       .ctl_reg = 0x2a4c,
> +       .ns_reg = 0x2a4c,
> +       .md_reg = 0x2a48,
> +       .ctl_bit = 11,
> +       .mnctr_en_bit = 8,
> +       .mnctr_reset_bit = 7,
> +       .mnctr_mode_shift = 5,
> +       .pre_div_shift = 3,
> +       .src_sel_shift = 0,
> +       .n_val_shift = 16,
> +       .m_val_shift = 16,
> +       .parent_map = gcc_pxo_pll8_map,
> +       .freq_tbl = clk_tbl_gsbi_qup,
> +};
> +
> +static struct branch_desc gsbi5_qup_cxc = {
> +       .ctl_reg = 0x2a4c,
> +       .halt_reg = 0x2fd0,
> +       .ctl_bit = 9,
> +       .halt_bit = 20,
> +       .halt_check = BRANCH_HALT,
> +};
> +
> +static struct of_clk_match msm_gcc_clk_match[] = {
> +       { .name = "cxo" },
> +       { .name = "pxo" },
> +       { .name = "pll8", .driver_data = &pll8_desc },
> +       { .name = "vpll8", .driver_data = &pll8_vote_desc },
> +       { .name = "gsbi5_uart_rcg", .driver_data = &gsbi5_uart_rcg },
> +       { .name = "gsbi5_uart_cxc", .driver_data = &gsbi5_uart_cxc },
> +       { .name = "gsbi6_uart_rcg", .driver_data = &gsbi6_uart_rcg },
> +       { .name = "gsbi6_uart_cxc", .driver_data = &gsbi6_uart_cxc },
> +       { .name = "gsbi5_uart_ahb", .driver_data = &gsbi5_uart_ahb },
> +       { .name = "gsbi5_qup_rcg", .driver_data = &gsbi5_qup_rcg },
> +       { .name = "gsbi5_qup_cxc", .driver_data = &gsbi5_qup_cxc },
> +};
> +
> +const struct msm_clk_match msm_gcc_8960_matches = {
> +       .matches = msm_gcc_clk_match,
> +       .size = ARRAY_SIZE(msm_gcc_clk_match)
> +};
> diff --git a/drivers/clk/msm/internal.h b/drivers/clk/msm/internal.h
> index 177bd3b..b0ffda7 100644
> --- a/drivers/clk/msm/internal.h
> +++ b/drivers/clk/msm/internal.h
> @@ -21,4 +21,6 @@ struct msm_clk_match {
>         size_t size;
>  };
> 
> +extern const struct msm_clk_match msm_gcc_8960_matches;
> +
>  #endif
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Boyd Aug. 13, 2013, 5:03 a.m. UTC | #2
On 08/08, Mark Rutland wrote:
> Hi Stephen,
> 
> On Thu, Jul 25, 2013 at 01:43:37AM +0100, Stephen Boyd wrote:
> > Fill in the data and wire up the global clock controller to the
> > MSM clock driver. This should allow most non-multimedia device
> > drivers to control their clocks on 8960 based platforms.
> > 
> > Cc: devicetree@vger.kernel.org
> > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> > ---
> >  .../devicetree/bindings/clock/qcom,gcc.txt         |  55 +++++++
> >  drivers/clk/msm/Kconfig                            |  10 ++
> >  drivers/clk/msm/Makefile                           |   2 +
> >  drivers/clk/msm/core.c                             |   3 +
> >  drivers/clk/msm/gcc-8960.c                         | 174 +++++++++++++++++++++
> >  drivers/clk/msm/internal.h                         |   2 +
> >  6 files changed, 246 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/clock/qcom,gcc.txt
> >  create mode 100644 drivers/clk/msm/gcc-8960.c
> > 
> > diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> > new file mode 100644
> > index 0000000..2311e1a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> > @@ -0,0 +1,55 @@
> > +MSM Global Clock Controller Binding
> > +-----------------------------------
> > +
> > +Required properties :
> > +- compatible : shall contain at least "qcom,gcc" and only one of the
> > +              following:
> > +
> > +                       "qcom,gcc-8660"
> > +                       "qcom,gcc-8960"
> > +
> > +- reg : shall contain base register location and length
> > +- clocks : shall contain clocks supplied by the clock controller
> > +
> > +Example:
> > +       clock-controller@900000 {
> > +               compatible = "qcom,gcc-8960", "qcom,gcc";
> > +               reg = <0x900000 0x4000>;
> > +
> > +               clocks {
> > +                       pxo: pxo {
> > +                               #clock-cells = <0>;
> > +                               compatible = "fixed-clock";
> > +                               clock-frequency = <27000000>;
> > +                       };
> > +
> > +                       pll8: pll8 {
> > +                               #clock-cells = <0>;
> > +                               compatible = "qcom,pll";
> > +                               clocks = <&pxo>;
> > +                       };
> > +
> > +                       vpll8: vpll8 {
> > +                               #clock-cells = <0>;
> > +                               compatible = "qcom,pll-vote";
> > +                               clocks = <&pll8>;
> > +                       };
> > +
> > +                       gsbi5_uart_rcg: gsbi5_uart_rcg {
> > +                               #clock-cells = <0>;
> > +                               compatible = "qcom,p2-mn16-clock";
> > +                               clocks = <&pxo>, <&vpll8>;
> > +                       };
> > +
> > +                       gsbi5_uart_clk: gsbi5_uart_cxc {
> > +                               #clock-cells = <0>;
> > +                               compatible = "qcom,cxc-clock";
> > +                               clocks = <&gsbi5_uart_rcg>;
> > +                       };
> > +
> > +                       gsbi5_uart_ahb: gsbi5_uart_ahb {
> > +                               #clock-cells = <0>;
> > +                               compatible = "qcom,cxc-hg-clock";
> > +                       };
> > +               };
> > +       };
> 
> I'm slightly confused by this. How is each of the clocks described in
> the clocks node related to a portion of the register set?

The registers to control clocks and determine their state are
scattered throughout the registers in the gcc (in this example
from 0x900000 to 0x903fff). If you match up gsbi5_uart_rcg with
its C struct counterpart you'll notice that there are multiple
registers used to configure the clock. It isn't as simple as one
reg property per clock even for the case where we're just
toggling a bit to turn a clock on and off either. And it isn't as
simple as saying the clock has a base register that we can offset
from because offsets are almost always different (we've tried
to correct this in future chip versions).

> 
> If the set of clocks is fixed, surely the gcc node gives you enough
> information alone, and the whole block can be modelled as a single
> provider of multiple clock outputs, or it's not fixed, and some linkage
> needs to be defined?
> 
> The code seems to imply the former, unless only a subset of clocks may
> be present? In that case, the set of clocks which might be present
> should be described in the binding.

The clock controller is hardware and the number of clock outputs
is fixed. Isn't all hardware fixed until you start talking about
FPGAs? The next minor revision of the clock controller may add
more clocks or remove clocks from that base design, but otherwise
the two are 90% the same and generally software compatible. It
isn't until we start a new generation of chips that we make major
changes to the design. Is that loose enough to qualify?

These bindings attempt to follow the regulator bindings. With
regulators there is a node for each regulator and we describe
physical characteristics of those regulators within the nodes but
we don't describe the software interface (bits, masks, shifts,
etc). I imagine we could extend these clock nodes to describe
physical characteristics such as min/max frequency or if the
bootloader has left the clocks on. Right now we're using the
nodes to describe what types of clocks there are and how the
clock tree is layed out.

Or perhaps you're talking about clock sharing? We share the clock
controller with multiple masters (processors running other OSes)
and the partitioning of the clocks is mostly predefined. We just
won't use some clocks because they're reserved for other
processors. They're still part of the same clock controller
hardware block but we don't want to control them on Linux because
we'll trample over other processors and most likely hang the
system. I wonder how this would work for hexagon and krait both
running linux on the same SoC. If all DT says is that there is a
gcc here at this address how are we supposed to know that we
shouldn't use some clock? In fact we have some clocks that are
"voteable" in the sense that each master has its own register to
vote for a clock to be on or off. The registers are all ORed
together by hardware to determine if the clock should be on or
not. I should probably rename those clocks to have a _krait or
_apps at the end so that it's clear we want to instantiate the
krait version of the clock and not the hexagon version. I suppose
the other solution there is to say we have gcc-8960-krait and
gcc-8960-hexagon so we know which voting registers to use or put
an ifdef ARCH_HEXAGON/ARCH_ARM. Is that the right solution?
Mike Turquette Aug. 13, 2013, 2:24 p.m. UTC | #3
Quoting Stephen Boyd (2013-08-12 22:03:34)
> On 08/08, Mark Rutland wrote:
> > Hi Stephen,
> > 
> > On Thu, Jul 25, 2013 at 01:43:37AM +0100, Stephen Boyd wrote:
> > > Fill in the data and wire up the global clock controller to the
> > > MSM clock driver. This should allow most non-multimedia device
> > > drivers to control their clocks on 8960 based platforms.
> > > 
> > > Cc: devicetree@vger.kernel.org
> > > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> > > ---
> > >  .../devicetree/bindings/clock/qcom,gcc.txt         |  55 +++++++
> > >  drivers/clk/msm/Kconfig                            |  10 ++
> > >  drivers/clk/msm/Makefile                           |   2 +
> > >  drivers/clk/msm/core.c                             |   3 +
> > >  drivers/clk/msm/gcc-8960.c                         | 174 +++++++++++++++++++++
> > >  drivers/clk/msm/internal.h                         |   2 +
> > >  6 files changed, 246 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/clock/qcom,gcc.txt
> > >  create mode 100644 drivers/clk/msm/gcc-8960.c
> > > 
> > > diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> > > new file mode 100644
> > > index 0000000..2311e1a
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> > > @@ -0,0 +1,55 @@
> > > +MSM Global Clock Controller Binding
> > > +-----------------------------------
> > > +
> > > +Required properties :
> > > +- compatible : shall contain at least "qcom,gcc" and only one of the
> > > +              following:
> > > +
> > > +                       "qcom,gcc-8660"
> > > +                       "qcom,gcc-8960"
> > > +
> > > +- reg : shall contain base register location and length
> > > +- clocks : shall contain clocks supplied by the clock controller
> > > +
> > > +Example:
> > > +       clock-controller@900000 {
> > > +               compatible = "qcom,gcc-8960", "qcom,gcc";
> > > +               reg = <0x900000 0x4000>;
> > > +
> > > +               clocks {
> > > +                       pxo: pxo {
> > > +                               #clock-cells = <0>;
> > > +                               compatible = "fixed-clock";
> > > +                               clock-frequency = <27000000>;
> > > +                       };
> > > +
> > > +                       pll8: pll8 {
> > > +                               #clock-cells = <0>;
> > > +                               compatible = "qcom,pll";
> > > +                               clocks = <&pxo>;
> > > +                       };
> > > +
> > > +                       vpll8: vpll8 {
> > > +                               #clock-cells = <0>;
> > > +                               compatible = "qcom,pll-vote";
> > > +                               clocks = <&pll8>;
> > > +                       };
> > > +
> > > +                       gsbi5_uart_rcg: gsbi5_uart_rcg {
> > > +                               #clock-cells = <0>;
> > > +                               compatible = "qcom,p2-mn16-clock";
> > > +                               clocks = <&pxo>, <&vpll8>;
> > > +                       };
> > > +
> > > +                       gsbi5_uart_clk: gsbi5_uart_cxc {
> > > +                               #clock-cells = <0>;
> > > +                               compatible = "qcom,cxc-clock";
> > > +                               clocks = <&gsbi5_uart_rcg>;
> > > +                       };
> > > +
> > > +                       gsbi5_uart_ahb: gsbi5_uart_ahb {
> > > +                               #clock-cells = <0>;
> > > +                               compatible = "qcom,cxc-hg-clock";
> > > +                       };
> > > +               };
> > > +       };
> > 
> > I'm slightly confused by this. How is each of the clocks described in
> > the clocks node related to a portion of the register set?
> 
> The registers to control clocks and determine their state are
> scattered throughout the registers in the gcc (in this example
> from 0x900000 to 0x903fff). If you match up gsbi5_uart_rcg with
> its C struct counterpart you'll notice that there are multiple
> registers used to configure the clock. It isn't as simple as one
> reg property per clock even for the case where we're just
> toggling a bit to turn a clock on and off either. And it isn't as
> simple as saying the clock has a base register that we can offset
> from because offsets are almost always different (we've tried
> to correct this in future chip versions).
> 
> > 
> > If the set of clocks is fixed, surely the gcc node gives you enough
> > information alone, and the whole block can be modelled as a single
> > provider of multiple clock outputs, or it's not fixed, and some linkage
> > needs to be defined?
> > 
> > The code seems to imply the former, unless only a subset of clocks may
> > be present? In that case, the set of clocks which might be present
> > should be described in the binding.
> 
> The clock controller is hardware and the number of clock outputs
> is fixed. Isn't all hardware fixed until you start talking about
> FPGAs? The next minor revision of the clock controller may add
> more clocks or remove clocks from that base design, but otherwise
> the two are 90% the same and generally software compatible. It
> isn't until we start a new generation of chips that we make major
> changes to the design. Is that loose enough to qualify?
> 
> These bindings attempt to follow the regulator bindings. With
> regulators there is a node for each regulator and we describe
> physical characteristics of those regulators within the nodes but
> we don't describe the software interface (bits, masks, shifts,
> etc). I imagine we could extend these clock nodes to describe
> physical characteristics such as min/max frequency or if the
> bootloader has left the clocks on. Right now we're using the
> nodes to describe what types of clocks there are and how the
> clock tree is layed out.
> 
> Or perhaps you're talking about clock sharing? We share the clock
> controller with multiple masters (processors running other OSes)
> and the partitioning of the clocks is mostly predefined. We just
> won't use some clocks because they're reserved for other
> processors. They're still part of the same clock controller
> hardware block but we don't want to control them on Linux because
> we'll trample over other processors and most likely hang the
> system. I wonder how this would work for hexagon and krait both
> running linux on the same SoC. If all DT says is that there is a
> gcc here at this address how are we supposed to know that we
> shouldn't use some clock? 

Do Krait and Hexagon have the same register map? On the ARM SoCs I am
familiar with the masters have differing views of register addresses for
the same peripherals and hardware blocks. So you couldn't use the same
DTS in a straightforward way if this is true for your system.

Regards,
Mike

> In fact we have some clocks that are
> "voteable" in the sense that each master has its own register to
> vote for a clock to be on or off. The registers are all ORed
> together by hardware to determine if the clock should be on or
> not. I should probably rename those clocks to have a _krait or
> _apps at the end so that it's clear we want to instantiate the
> krait version of the clock and not the hexagon version. I suppose
> the other solution there is to say we have gcc-8960-krait and
> gcc-8960-hexagon so we know which voting registers to use or put
> an ifdef ARCH_HEXAGON/ARCH_ARM. Is that the right solution?
> 
> -- 
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Boyd Aug. 13, 2013, 6:42 p.m. UTC | #4
On 08/13, Mike Turquette wrote:
> Quoting Stephen Boyd (2013-08-12 22:03:34)
> > The clock controller is hardware and the number of clock outputs
> > is fixed. Isn't all hardware fixed until you start talking about
> > FPGAs? The next minor revision of the clock controller may add
> > more clocks or remove clocks from that base design, but otherwise
> > the two are 90% the same and generally software compatible. It
> > isn't until we start a new generation of chips that we make major
> > changes to the design. Is that loose enough to qualify?
> > 
> > These bindings attempt to follow the regulator bindings. With
> > regulators there is a node for each regulator and we describe
> > physical characteristics of those regulators within the nodes but
> > we don't describe the software interface (bits, masks, shifts,
> > etc). I imagine we could extend these clock nodes to describe
> > physical characteristics such as min/max frequency or if the
> > bootloader has left the clocks on. Right now we're using the
> > nodes to describe what types of clocks there are and how the
> > clock tree is layed out.
> > 
> > Or perhaps you're talking about clock sharing? We share the clock
> > controller with multiple masters (processors running other OSes)
> > and the partitioning of the clocks is mostly predefined. We just
> > won't use some clocks because they're reserved for other
> > processors. They're still part of the same clock controller
> > hardware block but we don't want to control them on Linux because
> > we'll trample over other processors and most likely hang the
> > system. I wonder how this would work for hexagon and krait both
> > running linux on the same SoC. If all DT says is that there is a
> > gcc here at this address how are we supposed to know that we
> > shouldn't use some clock? 
> 
> Do Krait and Hexagon have the same register map? On the ARM SoCs I am
> familiar with the masters have differing views of register addresses for
> the same peripherals and hardware blocks. So you couldn't use the same
> DTS in a straightforward way if this is true for your system.
> 

They both have the same view of the register map.
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
new file mode 100644
index 0000000..2311e1a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -0,0 +1,55 @@ 
+MSM Global Clock Controller Binding
+-----------------------------------
+
+Required properties :
+- compatible : shall contain at least "qcom,gcc" and only one of the
+	       following:
+
+			"qcom,gcc-8660"
+			"qcom,gcc-8960"
+
+- reg : shall contain base register location and length
+- clocks : shall contain clocks supplied by the clock controller
+
+Example:
+	clock-controller@900000 {
+		compatible = "qcom,gcc-8960", "qcom,gcc";
+		reg = <0x900000 0x4000>;
+
+		clocks {
+			pxo: pxo {
+				#clock-cells = <0>;
+				compatible = "fixed-clock";
+				clock-frequency = <27000000>;
+			};
+
+			pll8: pll8 {
+				#clock-cells = <0>;
+				compatible = "qcom,pll";
+				clocks = <&pxo>;
+			};
+
+			vpll8: vpll8 {
+				#clock-cells = <0>;
+				compatible = "qcom,pll-vote";
+				clocks = <&pll8>;
+			};
+
+			gsbi5_uart_rcg: gsbi5_uart_rcg {
+				#clock-cells = <0>;
+				compatible = "qcom,p2-mn16-clock";
+				clocks = <&pxo>, <&vpll8>;
+			};
+
+			gsbi5_uart_clk: gsbi5_uart_cxc {
+				#clock-cells = <0>;
+				compatible = "qcom,cxc-clock";
+				clocks = <&gsbi5_uart_rcg>;
+			};
+
+			gsbi5_uart_ahb: gsbi5_uart_ahb {
+				#clock-cells = <0>;
+				compatible = "qcom,cxc-hg-clock";
+			};
+		};
+	};
diff --git a/drivers/clk/msm/Kconfig b/drivers/clk/msm/Kconfig
index bf7e3d2..3eaffb6 100644
--- a/drivers/clk/msm/Kconfig
+++ b/drivers/clk/msm/Kconfig
@@ -2,3 +2,13 @@  menuconfig COMMON_CLK_MSM
 	tristate "Support for Qualcomm's MSM designs"
 	depends on OF
 
+if COMMON_CLK_MSM
+
+config MSM_GCC_8960
+	bool "MSM8960 Global Clock Controller"
+	help
+	  Support for the global clock controller on msm8960 devices.
+	  Say Y if you want to use peripheral devices such as UART, SPI,
+	  i2c, USB, SD/eMMC, SATA, PCIe, etc.
+
+endif
diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile
index 9cfd0d7..c785943 100644
--- a/drivers/clk/msm/Makefile
+++ b/drivers/clk/msm/Makefile
@@ -6,3 +6,5 @@  clk-msm-$(CONFIG_COMMON_CLK_MSM) += clk-rcg2.o
 clk-msm-$(CONFIG_COMMON_CLK_MSM) += clk-branch.o
 
 clk-msm-$(CONFIG_COMMON_CLK_MSM) += core.o
+
+clk-msm-$(CONFIG_MSM_GCC_8960) += gcc-8960.o
diff --git a/drivers/clk/msm/core.c b/drivers/clk/msm/core.c
index b1904c0..b8e702b 100644
--- a/drivers/clk/msm/core.c
+++ b/drivers/clk/msm/core.c
@@ -173,6 +173,9 @@  typedef struct clk *
 		struct cc_data *cc);
 
 static const struct of_device_id msm_cc_match_table[] = {
+#ifdef CONFIG_MSM_GCC_8960
+	{ .compatible = "qcom,gcc-8960", .data = &msm_gcc_8960_matches },
+#endif
 	{ }
 };
 MODULE_DEVICE_TABLE(of, msm_cc_match_table);
diff --git a/drivers/clk/msm/gcc-8960.c b/drivers/clk/msm/gcc-8960.c
new file mode 100644
index 0000000..b57d2dd
--- /dev/null
+++ b/drivers/clk/msm/gcc-8960.c
@@ -0,0 +1,174 @@ 
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "internal.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+
+static struct pll_desc pll8_desc = {
+	.l_reg = 0x3144,
+	.m_reg = 0x3148,
+	.n_reg = 0x314c,
+	.config_reg = 0x3154,
+	.mode_reg = 0x3140,
+	.status_reg = 0x3158,
+	.status_bit = 16,
+};
+
+static struct pll_vote_desc pll8_vote_desc = {
+	.vote_reg = 0x34c0,
+	.vote_bit = 8,
+};
+
+#define PXO	0
+#define PLL8	1
+
+static u8 gcc_pxo_pll8_map[] = {
+	[PXO]	= 0,
+	[PLL8]	= 3,
+};
+
+static struct freq_tbl clk_tbl_gsbi_uart[] = {
+	{  1843200, PLL8, 2,  6, 625 },
+	{  3686400, PLL8, 2, 12, 625 },
+	{  7372800, PLL8, 2, 24, 625 },
+	{ 14745600, PLL8, 2, 48, 625 },
+	{ 16000000, PLL8, 4,  1,   6 },
+	{ 24000000, PLL8, 4,  1,   4 },
+	{ 32000000, PLL8, 4,  1,   3 },
+	{ 40000000, PLL8, 1,  5,  48 },
+	{ 46400000, PLL8, 1, 29, 240 },
+	{ 48000000, PLL8, 4,  1,   2 },
+	{ 51200000, PLL8, 1,  2,  15 },
+	{ 56000000, PLL8, 1,  7,  48 },
+	{ 58982400, PLL8, 1, 96, 625 },
+	{ 64000000, PLL8, 2,  1,   3 },
+	{ }
+};
+
+static struct rcg_desc gsbi5_uart_rcg = {
+	.ctl_reg = 0x2a54,
+	.ns_reg = 0x2a54,
+	.md_reg = 0x2a50,
+	.ctl_bit = 11,
+	.mnctr_en_bit = 8,
+	.mnctr_reset_bit = 7,
+	.mnctr_mode_shift = 5,
+	.pre_div_shift = 3,
+	.src_sel_shift = 0,
+	.n_val_shift = 16,
+	.m_val_shift = 16,
+	.parent_map = gcc_pxo_pll8_map,
+	.freq_tbl = clk_tbl_gsbi_uart,
+};
+
+static struct branch_desc gsbi5_uart_cxc = {
+	.ctl_reg = 0x2a54,
+	.halt_reg = 0x2fd0,
+	.ctl_bit = 9,
+	.halt_bit = 22,
+	.halt_check = BRANCH_HALT,
+};
+
+static struct rcg_desc gsbi6_uart_rcg = {
+	.ctl_reg = 0x2a74,
+	.ns_reg = 0x2a74,
+	.md_reg = 0x2a70,
+	.ctl_bit = 11,
+	.mnctr_en_bit = 8,
+	.mnctr_reset_bit = 7,
+	.mnctr_mode_shift = 5,
+	.pre_div_shift = 3,
+	.src_sel_shift = 0,
+	.n_val_shift = 16,
+	.m_val_shift = 16,
+	.parent_map = gcc_pxo_pll8_map,
+	.freq_tbl = clk_tbl_gsbi_uart,
+};
+
+static struct branch_desc gsbi6_uart_cxc = {
+	.ctl_reg = 0x2a74,
+	.halt_reg = 0x2fd0,
+	.ctl_bit = 9,
+	.halt_bit = 18,
+	.halt_check = BRANCH_HALT,
+};
+
+static struct branch_desc gsbi5_uart_ahb = {
+	.ctl_reg = 0x2a40,
+	.halt_reg = 0x2fd0,
+	.hwcg_reg = 0x2a40,
+	.ctl_bit = 4,
+	.hwcg_bit = 6,
+	.halt_bit = 23,
+	.halt_check = BRANCH_HALT,
+};
+
+static struct freq_tbl clk_tbl_gsbi_qup[] = {
+	{  1100000, PXO,  1, 2, 49 },
+	{  5400000, PXO,  1, 1,  5 },
+	{ 10800000, PXO,  1, 2,  5 },
+	{ 15060000, PLL8, 1, 2, 51 },
+	{ 24000000, PLL8, 4, 1,  4 },
+	{ 25600000, PLL8, 1, 1, 15 },
+	{ 27000000, PXO,  1, 0,  0 },
+	{ 48000000, PLL8, 4, 1,  2 },
+	{ 51200000, PLL8, 1, 2, 15 },
+	{ }
+};
+
+static struct rcg_desc gsbi5_qup_rcg = {
+	.ctl_reg = 0x2a4c,
+	.ns_reg = 0x2a4c,
+	.md_reg = 0x2a48,
+	.ctl_bit = 11,
+	.mnctr_en_bit = 8,
+	.mnctr_reset_bit = 7,
+	.mnctr_mode_shift = 5,
+	.pre_div_shift = 3,
+	.src_sel_shift = 0,
+	.n_val_shift = 16,
+	.m_val_shift = 16,
+	.parent_map = gcc_pxo_pll8_map,
+	.freq_tbl = clk_tbl_gsbi_qup,
+};
+
+static struct branch_desc gsbi5_qup_cxc = {
+	.ctl_reg = 0x2a4c,
+	.halt_reg = 0x2fd0,
+	.ctl_bit = 9,
+	.halt_bit = 20,
+	.halt_check = BRANCH_HALT,
+};
+
+static struct of_clk_match msm_gcc_clk_match[] = {
+	{ .name = "cxo" },
+	{ .name = "pxo" },
+	{ .name = "pll8", .driver_data = &pll8_desc },
+	{ .name = "vpll8", .driver_data = &pll8_vote_desc },
+	{ .name = "gsbi5_uart_rcg", .driver_data = &gsbi5_uart_rcg },
+	{ .name = "gsbi5_uart_cxc", .driver_data = &gsbi5_uart_cxc },
+	{ .name = "gsbi6_uart_rcg", .driver_data = &gsbi6_uart_rcg },
+	{ .name = "gsbi6_uart_cxc", .driver_data = &gsbi6_uart_cxc },
+	{ .name = "gsbi5_uart_ahb", .driver_data = &gsbi5_uart_ahb },
+	{ .name = "gsbi5_qup_rcg", .driver_data = &gsbi5_qup_rcg },
+	{ .name = "gsbi5_qup_cxc", .driver_data = &gsbi5_qup_cxc },
+};
+
+const struct msm_clk_match msm_gcc_8960_matches = {
+	.matches = msm_gcc_clk_match,
+	.size = ARRAY_SIZE(msm_gcc_clk_match)
+};
diff --git a/drivers/clk/msm/internal.h b/drivers/clk/msm/internal.h
index 177bd3b..b0ffda7 100644
--- a/drivers/clk/msm/internal.h
+++ b/drivers/clk/msm/internal.h
@@ -21,4 +21,6 @@  struct msm_clk_match {
 	size_t size;
 };
 
+extern const struct msm_clk_match msm_gcc_8960_matches;
+
 #endif