diff mbox

[V2,6/7] ARM: SPEAr13xx: Add auxdata for Ethernet controller.

Message ID 214127499f10b0099e6f3542e1e879fdd8c1bdcf.1342171151.git.vipulkumar.samar@st.com (mailing list archive)
State New, archived
Headers show

Commit Message

vipul kumar samar July 13, 2012, 9:23 a.m. UTC
Use AUXDATA to pass platform data for Ethernet controller.

Signed-off-by: Vipul Kumar Samar <vipulkumar.samar@st.com>
---
 arch/arm/mach-spear13xx/include/mach/generic.h |    2 +
 arch/arm/mach-spear13xx/include/mach/spear.h   |    1 +
 arch/arm/mach-spear13xx/spear1340.c            |   32 +++++++
 arch/arm/mach-spear13xx/spear13xx.c            |  104 ++++++++++++++++++++++++
 4 files changed, 139 insertions(+), 0 deletions(-)

Comments

Viresh Kumar July 13, 2012, 10:30 a.m. UTC | #1
On Fri, Jul 13, 2012 at 10:23 AM, Vipul Kumar Samar
<vipulkumar.samar@st.com> wrote:
> Use AUXDATA to pass platform data for Ethernet controller.

> diff --git a/arch/arm/mach-spear13xx/spear1340.c b/arch/arm/mach-spear13xx/spear1340.c

> +static struct plat_stmmacenet_data eth_data = {
> +       .bus_id = 0,
> +       .phy_addr = -1,
> +       .interface = PHY_INTERFACE_MODE_RGMII,
> +       .has_gmac = 1,
> +       .enh_desc = 1,
> +       .tx_coe = 1,
> +       .dma_cfg = &dma0_private_data,
> +       .rx_coe = STMMAC_RX_COE_TYPE2,
> +       .bugged_jumbo = 1,
> +       .pmt = 1,
> +       .mdio_bus_data = &mdio0_private_data,
> +       .init = spear13xx_eth_phy_clk_cfg,
> +       .clk_csr = STMMAC_CSR_150_250M,
> +};
> +
>  /* SATA device registration */
>  static int sata_miphy_init(struct device *dev, void __iomem *addr)
>  {
> @@ -166,6 +197,7 @@ static struct of_dev_auxdata spear1340_auxdata_lookup[] __initdata = {
>         OF_DEV_AUXDATA("snps,spear-ahci", SPEAR1340_SATA_BASE, NULL,
>                         &sata_pdata),
>         OF_DEV_AUXDATA("arm,pl011", SPEAR1340_UART1_BASE, NULL, &uart1_data),
> +       OF_DEV_AUXDATA("st,spear600-gmac", SPEAR13XX_GETH_BASE, NULL, &eth_data),
>         {}
>  };

Adding Stefan and Peppe.

I understand why you can't send all platform data from DT.
Let me elaborate the problem statement

stmmac is used by platforms with and without DT.
- Without DT will pass platform data directly, without any issues.
- With DT have to pass all data, some of that via DT and other without
DT, like routines
  (atleast for now)

For now what I suggest is, update DT support for whatever we can..
i.e. support Maximum
properties there. As finally we will support everything via DT, no
platform data.

Whatever is left, that can't be passed via DT, like routine, pass it
from platform data
and merge both these versions of platform data in driver, keeping DT
ones in priority.

i.e. Whatever is defined in DT properties must come from there and
left outs from
platform data.

--
viresh
Arnd Bergmann July 13, 2012, 2:22 p.m. UTC | #2
On Friday 13 July 2012, viresh kumar wrote:
> Adding Stefan and Peppe.
> 
> I understand why you can't send all platform data from DT.
> Let me elaborate the problem statement
> 
> stmmac is used by platforms with and without DT.
> - Without DT will pass platform data directly, without any issues.
> - With DT have to pass all data, some of that via DT and other without
> DT, like routines
>   (atleast for now)
> 
> For now what I suggest is, update DT support for whatever we can..
> i.e. support Maximum
> properties there. As finally we will support everything via DT, no
> platform data.
> 
> Whatever is left, that can't be passed via DT, like routine, pass it
> from platform data
> and merge both these versions of platform data in driver, keeping DT
> ones in priority.
> 
> i.e. Whatever is defined in DT properties must come from there and
> left outs from
> platform data.

Absolutely agreed.

The one part I think you both have wrong is the idea that the
spear13xx_eth_phy_clk_cfg function is needed.

I believe the correct answer for this is to introduce a driver for
the phy in drivers/net/phy/, and have the phy be described correctly
in the device tree and referenced found using the of_phy_find_device()
function.

	Arnd
Jean-Christophe PLAGNIOL-VILLARD July 14, 2012, 11:41 a.m. UTC | #3
On 14:53 Fri 13 Jul     , Vipul Kumar Samar wrote:
> Use AUXDATA to pass platform data for Ethernet controller.
> 
> Signed-off-by: Vipul Kumar Samar <vipulkumar.samar@st.com>
> ---
>  arch/arm/mach-spear13xx/include/mach/generic.h |    2 +
>  arch/arm/mach-spear13xx/include/mach/spear.h   |    1 +
>  arch/arm/mach-spear13xx/spear1340.c            |   32 +++++++
>  arch/arm/mach-spear13xx/spear13xx.c            |  104 ++++++++++++++++++++++++
>  4 files changed, 139 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-spear13xx/include/mach/generic.h b/arch/arm/mach-spear13xx/include/mach/generic.h
> index dac57fd..8c8fbaa 100644
> --- a/arch/arm/mach-spear13xx/include/mach/generic.h
> +++ b/arch/arm/mach-spear13xx/include/mach/generic.h
> @@ -15,6 +15,7 @@
>  #define __MACH_GENERIC_H
>  
>  #include <linux/dmaengine.h>
> +#include <linux/platform_device.h>
>  #include <asm/mach/time.h>
>  
>  /* Add spear13xx structure declarations here */
> @@ -31,6 +32,7 @@ void __init spear13xx_map_io(void);
>  void __init spear13xx_dt_init_irq(void);
>  void __init spear13xx_l2x0_init(void);
>  bool dw_dma_filter(struct dma_chan *chan, void *slave);
> +int spear13xx_eth_phy_clk_cfg(struct platform_device *pdev);
>  void spear_restart(char, const char *);
>  void spear13xx_secondary_startup(void);
>  
> diff --git a/arch/arm/mach-spear13xx/include/mach/spear.h b/arch/arm/mach-spear13xx/include/mach/spear.h
> index 65f27de..b0b6f91 100644
> --- a/arch/arm/mach-spear13xx/include/mach/spear.h
> +++ b/arch/arm/mach-spear13xx/include/mach/spear.h
> @@ -46,6 +46,7 @@
>  #define DMAC0_BASE				UL(0xEA800000)
>  #define DMAC1_BASE				UL(0xEB000000)
>  #define MCIF_CF_BASE				UL(0xB2800000)
> +#define SPEAR13XX_GETH_BASE			UL(0xE2000000)
>  
>  /* Devices present in SPEAr1310 */
>  #ifdef CONFIG_MACH_SPEAR1310
> diff --git a/arch/arm/mach-spear13xx/spear1340.c b/arch/arm/mach-spear13xx/spear1340.c
> index 81e4ed7..ab282ed 100644
> --- a/arch/arm/mach-spear13xx/spear1340.c
> +++ b/arch/arm/mach-spear13xx/spear1340.c
> @@ -18,6 +18,9 @@
>  #include <linux/delay.h>
>  #include <linux/dw_dmac.h>
>  #include <linux/of_platform.h>
> +#include <linux/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/stmmac.h>
>  #include <asm/hardware/gic.h>
>  #include <asm/mach/arch.h>
>  #include <mach/dma.h>
> @@ -100,6 +103,34 @@ static struct amba_pl011_data uart1_data = {
>  	.dma_rx_param = &uart1_dma_param[1],
>  };
>  
> +/* Ethernet platform data */
> +static struct stmmac_mdio_bus_data mdio0_private_data = {
> +	.bus_id = 0,
> +	.phy_mask = 0,
> +};
> +
> +static struct stmmac_dma_cfg dma0_private_data = {
> +	.pbl = 16,
> +	.fixed_burst = 1,
> +	.burst_len = DMA_AXI_BLEN_ALL,
> +};
> +
> +static struct plat_stmmacenet_data eth_data = {
> +	.bus_id = 0,
> +	.phy_addr = -1,
> +	.interface = PHY_INTERFACE_MODE_RGMII,
> +	.has_gmac = 1,
> +	.enh_desc = 1,
> +	.tx_coe = 1,
> +	.dma_cfg = &dma0_private_data,
> +	.rx_coe = STMMAC_RX_COE_TYPE2,
> +	.bugged_jumbo = 1,
> +	.pmt = 1,
> +	.mdio_bus_data = &mdio0_private_data,
> +	.init = spear13xx_eth_phy_clk_cfg,
> +	.clk_csr = STMMAC_CSR_150_250M,
> +};
sorry I see no reason to do not pass this via DT

I agreed that the pbl is quite sensitive but you do need to pass them via DT

Best Regards,
J.
deepaksi July 17, 2012, 10 a.m. UTC | #4
Viresh,



On 7/13/2012 4:00 PM, viresh kumar wrote:
> On Fri, Jul 13, 2012 at 10:23 AM, Vipul Kumar Samar
> <vipulkumar.samar@st.com>  wrote:
>> Use AUXDATA to pass platform data for Ethernet controller.
> Adding Stefan and Peppe.
>
> I understand why you can't send all platform data from DT.
> Let me elaborate the problem statement
>
> stmmac is used by platforms with and without DT.
> - Without DT will pass platform data directly, without any issues.
> - With DT have to pass all data, some of that via DT and other without
> DT, like routines
>    (atleast for now)
>
> For now what I suggest is, update DT support for whatever we can..
> i.e. support Maximum
> properties there. As finally we will support everything via DT, no
> platform data.
>
> Whatever is left, that can't be passed via DT, like routine, pass it
> from platform data
> and merge both these versions of platform data in driver, keeping DT
> ones in priority.
>
> i.e. Whatever is defined in DT properties must come from there and
> left outs from
> platform data.

I do differ on the point over here. I do believe that the code for now 
should be left as into mutually
exclusive sections.
As you said, without DT, the platform data would exist without any 
problem, Thats fine

But with DT also, as of now since the DT is still evolving we should not 
merge the data and keep it at
two places. The reasons being.
The stmmac driver is being used by multiple platforms, lets say within 
spear we have different variants
requiring different configurations and dividing those configurations at 
two different places will require larger
maintenance.Any more changes in driver that has dependency on the 
platform data will require updates,
and more such conflicts will arrive related to maintenance.

Lets keep the platform data as a part of AUXDATA for now, till the tree 
evolves fully specifically if DT is being
used.

Deepak




> --
> viresh
> .
>
deepaksi July 17, 2012, 10:25 a.m. UTC | #5
Hi Arnd,


On 7/13/2012 7:52 PM, Arnd Bergmann wrote:
> On Friday 13 July 2012, viresh kumar wrote:
>> Adding Stefan and Peppe.
>>
>> I understand why you can't send all platform data from DT.
>> Let me elaborate the problem statement
>>
>> stmmac is used by platforms with and without DT.
>> - Without DT will pass platform data directly, without any issues.
>> - With DT have to pass all data, some of that via DT and other without
>> DT, like routines
>>    (atleast for now)
>>
>> For now what I suggest is, update DT support for whatever we can..
>> i.e. support Maximum
>> properties there. As finally we will support everything via DT, no
>> platform data.
>>
>> Whatever is left, that can't be passed via DT, like routine, pass it
>> from platform data
>> and merge both these versions of platform data in driver, keeping DT
>> ones in priority.
>>
>> i.e. Whatever is defined in DT properties must come from there and
>> left outs from
>> platform data.
> Absolutely agreed.
>
> The one part I think you both have wrong is the idea that the
> spear13xx_eth_phy_clk_cfg function is needed.
>
> I believe the correct answer for this is to introduce a driver for
> the phy in drivers/net/phy/, and have the phy be described correctly
> in the device tree and referenced found using the of_phy_find_device()
> function.

SPEAr platform has been using the generic phy framework, and it just 
requires a register into mdio
bus and provide the necessary callback w.r.t mdio read and write. These 
mdio read and write are more
into the GMAC registers, and hence a part of stmmac driver.

As far as my understanding is concerned, addition to the phy framework 
could have been done had it been
some phy from stmicro, which requires some special addressing to be done.
The function we are talking about is more related to handling the 
interface that phy has. The stmmac core has
been configured as rmii/smii/rgmii and requires the system to generate 
corresponding clock to support data
transfers over PHY.
This was specifically the reason of aligning the phy clock configuration 
function with stmmac driver, and could
well be taken as functional interface clock for mac core.
I do think that we should not add a new driver for aligning the clock 
settings of the interfaces.


Regards
Deepak



>
> 	Arnd
> .
>
Jean-Christophe PLAGNIOL-VILLARD July 17, 2012, 10:41 a.m. UTC | #6
On 15:55 Tue 17 Jul     , deepaksi wrote:
> Hi Arnd,
> 
> 
> On 7/13/2012 7:52 PM, Arnd Bergmann wrote:
> >On Friday 13 July 2012, viresh kumar wrote:
> >>Adding Stefan and Peppe.
> >>
> >>I understand why you can't send all platform data from DT.
> >>Let me elaborate the problem statement
> >>
> >>stmmac is used by platforms with and without DT.
> >>- Without DT will pass platform data directly, without any issues.
> >>- With DT have to pass all data, some of that via DT and other without
> >>DT, like routines
> >>   (atleast for now)
> >>
> >>For now what I suggest is, update DT support for whatever we can..
> >>i.e. support Maximum
> >>properties there. As finally we will support everything via DT, no
> >>platform data.
> >>
> >>Whatever is left, that can't be passed via DT, like routine, pass it
> >>from platform data
> >>and merge both these versions of platform data in driver, keeping DT
> >>ones in priority.
> >>
> >>i.e. Whatever is defined in DT properties must come from there and
> >>left outs from
> >>platform data.
> >Absolutely agreed.
> >
> >The one part I think you both have wrong is the idea that the
> >spear13xx_eth_phy_clk_cfg function is needed.
> >
> >I believe the correct answer for this is to introduce a driver for
> >the phy in drivers/net/phy/, and have the phy be described correctly
> >in the device tree and referenced found using the of_phy_find_device()
> >function.
> 
> SPEAr platform has been using the generic phy framework, and it just
> requires a register into mdio
> bus and provide the necessary callback w.r.t mdio read and write.
> These mdio read and write are more
> into the GMAC registers, and hence a part of stmmac driver.
> 
> As far as my understanding is concerned, addition to the phy
> framework could have been done had it been
> some phy from stmicro, which requires some special addressing to be done.
> The function we are talking about is more related to handling the
> interface that phy has. The stmmac core has
> been configured as rmii/smii/rgmii and requires the system to
> generate corresponding clock to support data
> transfers over PHY.
> This was specifically the reason of aligning the phy clock
> configuration function with stmmac driver, and could
> well be taken as functional interface clock for mac core.
> I do think that we should not add a new driver for aligning the
> clock settings of the interfaces.
this is not spear related but IP related this need to move the stmmac

IIRC I see it on other ST SoC

Best Regards,
J.
Arnd Bergmann July 17, 2012, 4:53 p.m. UTC | #7
On Tuesday 17 July 2012, deepaksi wrote:
> I do differ on the point over here. I do believe that the code for now 
> should be left as into mutually
> exclusive sections.
> As you said, without DT, the platform data would exist without any 
> problem, Thats fine
> 
> But with DT also, as of now since the DT is still evolving we should not 
> merge the data and keep it at
> two places. The reasons being.
> The stmmac driver is being used by multiple platforms, lets say within 
> spear we have different variants
> requiring different configurations and dividing those configurations at 
> two different places will require larger
> maintenance.

I don't think that the STMMAC_PLATFORM part is used by any other
platform in the mainline kernel, so we are definitely free to
rip out (parts of) the platform_data and replace them with DT
properties.
There is also no platform defining plat_stmmacenet_data
yet, which means that the code is completely untested at
the moment.

Don't worry about any out-of-tree platforms, they can keep
their out of tree patches to add back the platform data if
they don't want to move to DT booting.

Since all the data you are adding to spear1340.c is constant
anyway, I suppose that means this data is specific to
the spear1340 soc, not to a particular board or configuration.
I would suggest you add a preset like

static const struct of_device_id stmmac_dt_ids[] = {
        { .compatible = "st,spear600-gmac", .data = &spear600_data},
        { .compatible = "st,spear1340-gmac", .data = &spear1340_data}
};

that contains all the soc-specific data. You can probably make
that "const" and just kill off the platform_data path in the
driver.

> Any more changes in driver that has dependency on the 
> platform data will require updates,
> and more such conflicts will arrive related to maintenance.
> 
> Lets keep the platform data as a part of AUXDATA for now, till the tree 
> evolves fully specifically if DT is being
> used.

SPEAr is already fully using DT for everything except DMA channels.
Please don't add any more such exceptions.

	Arnd
deepaksi July 18, 2012, 9:21 a.m. UTC | #8
Hi Arnd,

On 7/17/2012 10:23 PM, Arnd Bergmann wrote:
> On Tuesday 17 July 2012, deepaksi wrote:
>> I do differ on the point over here. I do believe that the code for now
>> should be left as into mutually
>> exclusive sections.
>> As you said, without DT, the platform data would exist without any
>> problem, Thats fine
>>
>> But with DT also, as of now since the DT is still evolving we should not
>> merge the data and keep it at
>> two places. The reasons being.
>> The stmmac driver is being used by multiple platforms, lets say within
>> spear we have different variants
>> requiring different configurations and dividing those configurations at
>> two different places will require larger
>> maintenance.
> I don't think that the STMMAC_PLATFORM part is used by any other
> platform in the mainline kernel, so we are definitely free to
> rip out (parts of) the platform_data and replace them with DT
> properties.
> There is also no platform defining plat_stmmacenet_data
> yet, which means that the code is completely untested at
> the moment.
>
> Don't worry about any out-of-tree platforms, they can keep
> their out of tree patches to add back the platform data if
> they don't want to move to DT booting.
>
> Since all the data you are adding to spear1340.c is constant
> anyway, I suppose that means this data is specific to
> the spear1340 soc, not to a particular board or configuration.
> I would suggest you add a preset like
>
> static const struct of_device_id stmmac_dt_ids[] = {
>          { .compatible = "st,spear600-gmac", .data =&spear600_data},
>          { .compatible = "st,spear1340-gmac", .data =&spear1340_data}
> };
>
> that contains all the soc-specific data. You can probably make
> that "const" and just kill off the platform_data path in the
> driver.

Sure, we will do it as per the suggestions.

Regards
Deepak

>> Any more changes in driver that has dependency on the
>> platform data will require updates,
>> and more such conflicts will arrive related to maintenance.
>>
>> Lets keep the platform data as a part of AUXDATA for now, till the tree
>> evolves fully specifically if DT is being
>> used.
> SPEAr is already fully using DT for everything except DMA channels.
> Please don't add any more such exceptions.
>
> 	Arnd
> .
>
deepaksi July 25, 2012, 4:33 a.m. UTC | #9
Hi Arnd,

>>>
>> I don't think that the STMMAC_PLATFORM part is used by any other
>> platform in the mainline kernel, so we are definitely free to
>> rip out (parts of) the platform_data and replace them with DT
>> properties.
>> There is also no platform defining plat_stmmacenet_data
>> yet, which means that the code is completely untested at
>> the moment.
>>
>> Don't worry about any out-of-tree platforms, they can keep
>> their out of tree patches to add back the platform data if
>> they don't want to move to DT booting.
>>
>> Since all the data you are adding to spear1340.c is constant
>> anyway, I suppose that means this data is specific to
>> the spear1340 soc, not to a particular board or configuration.
>> I would suggest you add a preset like
>>
>> static const struct of_device_id stmmac_dt_ids[] = {
>>          { .compatible = "st,spear600-gmac", .data =&spear600_data},
>>          { .compatible = "st,spear1340-gmac", .data =&spear1340_data}
>> };
>>
>> that contains all the soc-specific data. You can probably make
>> that "const" and just kill off the platform_data path in the
>> driver.
>

I am sorry but bringing alive this discussion once again, as we have 
some implementation
specific open points.

1. In case we go by the above proposal, it kind of solves a few things 
for us, such as

- Through the DT blob it was difficult to plug in some of the platform 
specific callbacks
which kind of did few things that driver needed before it could be 
operational. In SPEAr
architecture we have a miscellaneous space which provides SOC specific
initializations used by devices which can be handled by these callbacks.

Now with the approach suggested, we have the flexibility to add on these 
callbacks,
where DT is not sufficient and move further.

*But there are few catches/ query I have with me.*

1. Within the driver space now, even if it is a stmmac_platform.c file 
we are kind of adding
a non driver related miscellaneous space (SoC specific) to do some 
initializations.
Will that be fine to do all such initializations in driver ?

2. If yes, then it is kind of moving all the platform related 
initializations into driver, and these
could be varying across machines, for example with SPEAr, 6xx /3xx/13xx 
may all have
different callbacks; and then take it to next level when the stmmac 
driver would be shared
across the platforms, and all initializations will plug into this file.
It sounds more of collaborating of all the ethernet driver information 
which previously existed
across platforms into one area, and making the driver space untidy.
I would seek your opinion and suggestions on this.

Regards
Deepak
Arnd Bergmann July 25, 2012, 6:31 a.m. UTC | #10
On Wednesday 25 July 2012, deepaksi wrote:

> *But there are few catches/ query I have with me.*
> 
> 1. Within the driver space now, even if it is a stmmac_platform.c file 
> we are kind of adding
> a non driver related miscellaneous space (SoC specific) to do some 
> initializations.
> Will that be fine to do all such initializations in driver ?

It depends a lot on what you want to do with those callbacks.
We generally try hard to make those callbacks unnecessary, but
I agree that this is not always easy or obvious how to do it.

There are cases where you have one SoC doing something very
obscure with an otherwise generic piece of hardware, and in
that case, it may be better to keep a callback in platform
code and use some method (auxdata or a notifier) to hand a
pointer to the driver.

In other cases, you have a number of platforms that essentially
want to do the same thing (set up clocks or voltages, pick a
PHY, ...) and in that case you should not be using callback
functions at all but instead describe the differences in the
device tree using the bindings for whatever you want to do
(adding bindings if necessary).

You can also have a case where the callback is just doing
something that is part of that driver in different ways,
and in that case using the "compatible" property to determine
which way is right is the best option.

Can you post here the complete set of callback implementations
that you have in your development trees at the moment? That should
help us determine which case we're talking about here.

	Arnd
Shiraz HASHIM July 25, 2012, 7:34 a.m. UTC | #11
Hi Arnd,

On Wed, Jul 25, 2012 at 06:31:53AM +0000, Arnd Bergmann wrote:
> Can you post here the complete set of callback implementations
> that you have in your development trees at the moment? That should
> help us determine which case we're talking about here.

There are following types of callbacks (involving SoC/platform) seen
generally in our case,

  * parent clk selection -
        driver is not aware about various clock sources (which also
        varies from platform to platform) and hence can only be
        programmed by corresponding platform.

        This is the case in Ethernet, audio, etc.

  * spi controller
        This is little hack in the h/w. As part of s/w controlled chip
        select/deselect in spi-pl022, we need to write to some system
        specific register.

  * OTG controller
        phy clock initialization which involves series of steps
        including powering down, etc.

  * NAND controller
        bank selection on runtime by writing to system registers

  * sata controller
        Similar to OTG case which involves clock initialization.

--
regards
Shiraz
Arnd Bergmann July 25, 2012, 5:10 p.m. UTC | #12
On Wednesday 25 July 2012, Shiraz Hashim wrote:
> 
> On Wed, Jul 25, 2012 at 06:31:53AM +0000, Arnd Bergmann wrote:
> > Can you post here the complete set of callback implementations
> > that you have in your development trees at the moment? That should
> > help us determine which case we're talking about here.
> 
> There are following types of callbacks (involving SoC/platform) seen
> generally in our case,
> 
>   * parent clk selection -
>         driver is not aware about various clock sources (which also
>         varies from platform to platform) and hence can only be
>         programmed by corresponding platform.
> 
>         This is the case in Ethernet, audio, etc.
>
>   * sata controller
>         Similar to OTG case which involves clock initialization.
 
This should definitely be moved into the drivers. A lot of drivers
enable and program clocks using the generic clock interfaces, so
there is no point using a callback.

Note that since stmmac is an architecture independent driver, this
depends on Mark Brown's patch to provide empty stubs for
the clock management functions on architectures that don't yet
use it.

>   * spi controller
>         This is little hack in the h/w. As part of s/w controlled chip
>         select/deselect in spi-pl022, we need to write to some system
>         specific register.
> 
>   * OTG controller
>         phy clock initialization which involves series of steps
>         including powering down, etc.
> 
>   * NAND controller
>         bank selection on runtime by writing to system registers

I don't understand any of these, so unless you post the code
that you want help with as I asked above, I'll assume that you find
the solution yourself and don't need a callback ;-)

	Arnd
Shiraz HASHIM July 26, 2012, 4:51 a.m. UTC | #13
Hi Arnd,

On Wed, Jul 25, 2012 at 05:10:53PM +0000, Arnd Bergmann wrote:
> On Wednesday 25 July 2012, Shiraz Hashim wrote:
> > On Wed, Jul 25, 2012 at 06:31:53AM +0000, Arnd Bergmann wrote:
> > > Can you post here the complete set of callback implementations
> > > that you have in your development trees at the moment? That should
> > > help us determine which case we're talking about here.
> > 
> > There are following types of callbacks (involving SoC/platform) seen
> > generally in our case,
> > 
> >   * parent clk selection -
> >         driver is not aware about various clock sources (which also
> >         varies from platform to platform) and hence can only be
> >         programmed by corresponding platform.
> > 
> >         This is the case in Ethernet, audio, etc.
> >
> >   * sata controller
> >         Similar to OTG case which involves clock initialization.
>  
> This should definitely be moved into the drivers. A lot of drivers
> enable and program clocks using the generic clock interfaces, so
> there is no point using a callback.
>
> Note that since stmmac is an architecture independent driver, this
> depends on Mark Brown's patch to provide empty stubs for
> the clock management functions on architectures that don't yet
> use it.

Yes, this is true for clocks associated with devices and we do handle
that in this way.

I was talking more of cases where, we need to

   * select clock sources (parents) about which driver has no
     knowledge and may vary across boards.
   * perform initializations which are more than clock, like phy
     initialization/programming etc. This is SoC dependant.

> >   * spi controller
> >         This is little hack in the h/w. As part of s/w controlled chip
> >         select/deselect in spi-pl022, we need to write to some system
> >         specific register.
> > 
> >   * OTG controller
> >         phy clock initialization which involves series of steps
> >         including powering down, etc.
> > 
> >   * NAND controller
> >         bank selection on runtime by writing to system registers
> 
> I don't understand any of these, so unless you post the code
> that you want help with as I asked above, I'll assume that you find
> the solution yourself and don't need a callback ;-)

Some of them are,

- fsmc NAND controller 

        -- include/linux/mtd/fsmc.h

        struct fsmc_nand_platform_data {
                ...

                void (*select_bank)(uint32_t bank, uint32_t busw);

                ...

        };


        -- arch/arm/mach-spear13xx/spear13xx.c

        void nand_select_bank(u32 bank, u32 busw)
        {
                u32 fsmc_cfg;

                if (cpu_is_spear1340()) {
        #ifdef CONFIG_CPU_SPEAR1340
                        fsmc_cfg = readl(VA_SPEAR1340_FSMC_CFG);
        #endif
                } else 
                        fsmc_cfg = readl(VA_FSMC_CFG);

                fsmc_cfg &= ~(NAND_BANK_MASK << NAND_BANK_SHIFT);
                fsmc_cfg |= (bank << NAND_BANK_SHIFT);

                if (busw)
                        fsmc_cfg |= 1 << NAND_DEV_WIDTH16;
                else
                        fsmc_cfg &= ~(1 << NAND_DEV_WIDTH16);

                if (cpu_is_spear1340()) {
        #ifdef CONFIG_CPU_SPEAR1340
                        writel(fsmc_cfg, VA_SPEAR1340_FSMC_CFG);
        #endif
                } else
                        writel(fsmc_cfg, VA_FSMC_CFG);
        }


- SATA Controller

        -- include/linux/ahci_platform.h

        struct ahci_platform_data {
                int (*init)(struct device *dev, void __iomem *addr);
                void (*exit)(struct device *dev);
                const struct ata_port_info *ata_port_info;
                unsigned int force_port_map;
                unsigned int mask_port_map;
        };


        -- arch/arm/mach-spear13xx/spear1340.c

        void sata_miphy_exit(struct device *dev)
        {
                writel(0, VA_SPEAR1340_PCIE_SATA_CFG);
                writel(0, VA_SPEAR1340_PCIE_MIPHY_CFG);

                /* Enable PCIE SATA Controller reset */
                writel((readl(VA_SPEAR1340_PERIP1_SW_RST) | (0x1000)),
                                VA_SPEAR1340_PERIP1_SW_RST);
                msleep(20);

                /* Switch off sata power domain */
                writel((readl(VA_SPEAR1340_PCM_CFG) & (~0x800)),
                                VA_SPEAR1340_PCM_CFG);
                msleep(20);
        }

        static int sata_miphy_init(struct device *dev, void __iomem *addr)
        {
                writel(SPEAR1340_SATA_CFG_VAL, VA_SPEAR1340_PCIE_SATA_CFG);
                writel(SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK,
                                VA_SPEAR1340_PCIE_MIPHY_CFG);
                /* Switch on sata power domain */
                writel((readl(VA_SPEAR1340_PCM_CFG) | (0x800)),
                                VA_SPEAR1340_PCM_CFG);
                msleep(20);
                /* Disable PCIE SATA Controller reset */
                writel((readl(VA_SPEAR1340_PERIP1_SW_RST) & (~0x1000)),
                                VA_SPEAR1340_PERIP1_SW_RST);
                msleep(20);

                return 0;
        }

        static struct ahci_platform_data sata_pdata = {
                .init = sata_miphy_init,
                .exit = sata_miphy_exit,
        };

--
regards
Shiraz
Arnd Bergmann July 26, 2012, 9:44 p.m. UTC | #14
On Thursday 26 July 2012, Shiraz Hashim wrote:
> Hi Arnd,
> 
> On Wed, Jul 25, 2012 at 05:10:53PM +0000, Arnd Bergmann wrote:
> > On Wednesday 25 July 2012, Shiraz Hashim wrote:
> > > On Wed, Jul 25, 2012 at 06:31:53AM +0000, Arnd Bergmann wrote:
> > > > Can you post here the complete set of callback implementations
> > > > that you have in your development trees at the moment? That should
> > > > help us determine which case we're talking about here.
> > > 
> > > There are following types of callbacks (involving SoC/platform) seen
> > > generally in our case,
> > > 
> > >   * parent clk selection -
> > >         driver is not aware about various clock sources (which also
> > >         varies from platform to platform) and hence can only be
> > >         programmed by corresponding platform.
> > > 
> > >         This is the case in Ethernet, audio, etc.
> > >
> > >   * sata controller
> > >         Similar to OTG case which involves clock initialization.
> >  
> > This should definitely be moved into the drivers. A lot of drivers
> > enable and program clocks using the generic clock interfaces, so
> > there is no point using a callback.
> >
> > Note that since stmmac is an architecture independent driver, this
> > depends on Mark Brown's patch to provide empty stubs for
> > the clock management functions on architectures that don't yet
> > use it.
> 
> Yes, this is true for clocks associated with devices and we do handle
> that in this way.
> 
> I was talking more of cases where, we need to
> 
>    * select clock sources (parents) about which driver has no
>      knowledge and may vary across boards.

I think we should be able to describe this now with the clock bindings
for device tree. If not, then we need to update those bindings rather
than work around the shortcomings.

>    * perform initializations which are more than clock, like phy
>      initialization/programming etc. This is SoC dependant.

Setting up the phy is different, but again I think there is a better
way than using callbacks if you put the initialization for the
phy into the driver that deals with that phy.

> > >   * spi controller
> > >         This is little hack in the h/w. As part of s/w controlled chip
> > >         select/deselect in spi-pl022, we need to write to some system
> > >         specific register.
> > > 
> > >   * OTG controller
> > >         phy clock initialization which involves series of steps
> > >         including powering down, etc.
> > > 
> > >   * NAND controller
> > >         bank selection on runtime by writing to system registers
> > 
> > I don't understand any of these, so unless you post the code
> > that you want help with as I asked above, I'll assume that you find
> > the solution yourself and don't need a callback ;-)
> 
> Some of them are,
> 
> - fsmc NAND controller 
> 
>         -- include/linux/mtd/fsmc.h
> 
>         struct fsmc_nand_platform_data {
>                 ...
> 
>                 void (*select_bank)(uint32_t bank, uint32_t busw);
> 
>                 ...
> 
>         };
> 
> 
>         -- arch/arm/mach-spear13xx/spear13xx.c
> 
>         void nand_select_bank(u32 bank, u32 busw)
>         {
>                 u32 fsmc_cfg;
> 
>                 if (cpu_is_spear1340()) {
>         #ifdef CONFIG_CPU_SPEAR1340
>                         fsmc_cfg = readl(VA_SPEAR1340_FSMC_CFG);
>         #endif
>                 } else 
>                         fsmc_cfg = readl(VA_FSMC_CFG);
> 
>                 fsmc_cfg &= ~(NAND_BANK_MASK << NAND_BANK_SHIFT);
>                 fsmc_cfg |= (bank << NAND_BANK_SHIFT);
> 
>                 if (busw)
>                         fsmc_cfg |= 1 << NAND_DEV_WIDTH16;
>                 else
>                         fsmc_cfg &= ~(1 << NAND_DEV_WIDTH16);
> 
>                 if (cpu_is_spear1340()) {
>         #ifdef CONFIG_CPU_SPEAR1340
>                         writel(fsmc_cfg, VA_SPEAR1340_FSMC_CFG);
>         #endif
>                 } else
>                         writel(fsmc_cfg, VA_FSMC_CFG);
>         }

The FSMC driver is ST Microelectronics specific, and this function looks fairly
straightforward. I think this can easily go into the driver, with a few
modifications:

* Find the FSMC_CFG address using the device tree. You should never have
any hardcoded virtual addresses like the one in this file, but instead
ioremap a resource that gets passed from the device tree. Where is this
register located? I assume that it's not part of the normal fsmc registers,
but how to get to this address depends a bit on where it's located.

* Remove the cpu_is_spear1340() hacks. If you have to tell the difference
between variations, make it depend on different "compatible" properties
on the presence or absence of some other property or register range.


> 
> 
>         -- arch/arm/mach-spear13xx/spear1340.c
> 
>         void sata_miphy_exit(struct device *dev)
>         {
>                 writel(0, VA_SPEAR1340_PCIE_SATA_CFG);
>                 writel(0, VA_SPEAR1340_PCIE_MIPHY_CFG);
> 
>                 /* Enable PCIE SATA Controller reset */
>                 writel((readl(VA_SPEAR1340_PERIP1_SW_RST) | (0x1000)),
>                                 VA_SPEAR1340_PERIP1_SW_RST);
>                 msleep(20);
> 
>                 /* Switch off sata power domain */
>                 writel((readl(VA_SPEAR1340_PCM_CFG) & (~0x800)),
>                                 VA_SPEAR1340_PCM_CFG);
>                 msleep(20);
>         }

Again, you should move the accesses to VA_SPEAR1340_PERIP1_SW_RST etc to some
device driver that deals with the specific register range. This can be
the driver for the actual peripheral itself, or it can be some kind of
"system controller" that exports an interface.
In the case of power domains and getting stuff in and out of reset,
the subsystems that you most likely should be using do do this are the
regulator and the powerdomain framework. Regulators already have device
tree bindings, while the power domains still need them.

	Arnd
diff mbox

Patch

diff --git a/arch/arm/mach-spear13xx/include/mach/generic.h b/arch/arm/mach-spear13xx/include/mach/generic.h
index dac57fd..8c8fbaa 100644
--- a/arch/arm/mach-spear13xx/include/mach/generic.h
+++ b/arch/arm/mach-spear13xx/include/mach/generic.h
@@ -15,6 +15,7 @@ 
 #define __MACH_GENERIC_H
 
 #include <linux/dmaengine.h>
+#include <linux/platform_device.h>
 #include <asm/mach/time.h>
 
 /* Add spear13xx structure declarations here */
@@ -31,6 +32,7 @@  void __init spear13xx_map_io(void);
 void __init spear13xx_dt_init_irq(void);
 void __init spear13xx_l2x0_init(void);
 bool dw_dma_filter(struct dma_chan *chan, void *slave);
+int spear13xx_eth_phy_clk_cfg(struct platform_device *pdev);
 void spear_restart(char, const char *);
 void spear13xx_secondary_startup(void);
 
diff --git a/arch/arm/mach-spear13xx/include/mach/spear.h b/arch/arm/mach-spear13xx/include/mach/spear.h
index 65f27de..b0b6f91 100644
--- a/arch/arm/mach-spear13xx/include/mach/spear.h
+++ b/arch/arm/mach-spear13xx/include/mach/spear.h
@@ -46,6 +46,7 @@ 
 #define DMAC0_BASE				UL(0xEA800000)
 #define DMAC1_BASE				UL(0xEB000000)
 #define MCIF_CF_BASE				UL(0xB2800000)
+#define SPEAR13XX_GETH_BASE			UL(0xE2000000)
 
 /* Devices present in SPEAr1310 */
 #ifdef CONFIG_MACH_SPEAR1310
diff --git a/arch/arm/mach-spear13xx/spear1340.c b/arch/arm/mach-spear13xx/spear1340.c
index 81e4ed7..ab282ed 100644
--- a/arch/arm/mach-spear13xx/spear1340.c
+++ b/arch/arm/mach-spear13xx/spear1340.c
@@ -18,6 +18,9 @@ 
 #include <linux/delay.h>
 #include <linux/dw_dmac.h>
 #include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/stmmac.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
 #include <mach/dma.h>
@@ -100,6 +103,34 @@  static struct amba_pl011_data uart1_data = {
 	.dma_rx_param = &uart1_dma_param[1],
 };
 
+/* Ethernet platform data */
+static struct stmmac_mdio_bus_data mdio0_private_data = {
+	.bus_id = 0,
+	.phy_mask = 0,
+};
+
+static struct stmmac_dma_cfg dma0_private_data = {
+	.pbl = 16,
+	.fixed_burst = 1,
+	.burst_len = DMA_AXI_BLEN_ALL,
+};
+
+static struct plat_stmmacenet_data eth_data = {
+	.bus_id = 0,
+	.phy_addr = -1,
+	.interface = PHY_INTERFACE_MODE_RGMII,
+	.has_gmac = 1,
+	.enh_desc = 1,
+	.tx_coe = 1,
+	.dma_cfg = &dma0_private_data,
+	.rx_coe = STMMAC_RX_COE_TYPE2,
+	.bugged_jumbo = 1,
+	.pmt = 1,
+	.mdio_bus_data = &mdio0_private_data,
+	.init = spear13xx_eth_phy_clk_cfg,
+	.clk_csr = STMMAC_CSR_150_250M,
+};
+
 /* SATA device registration */
 static int sata_miphy_init(struct device *dev, void __iomem *addr)
 {
@@ -166,6 +197,7 @@  static struct of_dev_auxdata spear1340_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("snps,spear-ahci", SPEAR1340_SATA_BASE, NULL,
 			&sata_pdata),
 	OF_DEV_AUXDATA("arm,pl011", SPEAR1340_UART1_BASE, NULL, &uart1_data),
+	OF_DEV_AUXDATA("st,spear600-gmac", SPEAR13XX_GETH_BASE, NULL, &eth_data),
 	{}
 };
 
diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index cf936b1..9ab3b47 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -18,6 +18,9 @@ 
 #include <linux/dw_dmac.h>
 #include <linux/err.h>
 #include <linux/of_irq.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/stmmac.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
@@ -80,6 +83,107 @@  struct dw_dma_platform_data dmac_plat_data = {
 	.chan_priority = CHAN_PRIORITY_DESCENDING,
 };
 
+/* Ethernet clock initialization */
+int spear13xx_eth_phy_clk_cfg(struct platform_device *pdev)
+{
+	int ret;
+	struct clk *input_clk, *input_pclk, *phy_pclk, *phy_clk;
+	struct plat_stmmacenet_data *pdata = dev_get_platdata(&pdev->dev);
+	const char *phy_clk_src_name[] = {
+		"phy_input_mclk",
+		"phy_syn_gclk",
+	};
+	const char *input_clk_src_name[] = {
+		"pll2_clk",
+		"gmii_pad_clk",
+		"osc_25m_clk",
+	};
+	const char *phy_clk_name[] = {
+		"stmmacphy.0"
+	};
+
+	if (!pdata)
+		return -EINVAL;
+
+	/* Get the Pll-2 Clock as parent for PHY Input Clock Source */
+	input_pclk = clk_get(NULL, input_clk_src_name[0]);
+	if (IS_ERR(input_pclk)) {
+		ret = PTR_ERR(input_pclk);
+		goto fail_get_input_pclk;
+	}
+
+	/*
+	 * Get the Phy Input clock source as parent for Phy clock. Default
+	 * selection is gmac_phy_input_clk. This selection would be driving both
+	 * the synthesizer and phy clock.
+	 */
+	input_clk = clk_get(NULL, phy_clk_src_name[0]);
+	if (IS_ERR(input_clk)) {
+		ret = PTR_ERR(input_clk);
+		goto fail_get_input_clk;
+	}
+
+	/* Fetch the phy clock */
+	phy_clk = clk_get(NULL, phy_clk_name[pdata->bus_id]);
+	if (IS_ERR(phy_clk)) {
+		ret = PTR_ERR(phy_clk);
+		goto fail_get_phy_clk;
+	}
+
+	/* Set the pll-2 to 125 MHz */
+	ret = clk_set_rate(input_pclk, 125000000);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("%s:couldn't set rate for input phy clk\n", __func__);
+		goto fail_set_rate;
+	}
+
+	/* Set the Pll-2 as parent for gmac_phy_input_clk */
+	ret = clk_set_parent(input_clk, input_pclk);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("%s:couldn't set parent for inout phy clk \n", __func__);
+		goto fail_set_rate;
+	}
+	if (pdata->interface == PHY_INTERFACE_MODE_RMII) {
+		/*
+		 * For the rmii interface select gmac_phy_synth_clk
+		 * as the parent and set the clock to 50 Mhz
+		 */
+		phy_pclk = clk_get(NULL, phy_clk_src_name[1]);
+		ret = clk_set_rate(phy_pclk, 50000000);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("%s:couldn't set rate for phy synth clk\n",
+					__func__);
+			goto fail_set_rate;
+		}
+	} else {
+		/*
+		 * Set the gmac_phy_input_clk as the parent,
+		 * and pll-2 is already running as parent of
+		 * gmac_phy_input_clk at 125 Mhz
+		 */
+		phy_pclk = input_clk;
+	}
+
+	/* Select the parent for phy clock */
+	ret = clk_set_parent(phy_clk, phy_pclk);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("%s:couldn't set parent for phy clk \n", __func__);
+		goto fail_set_rate;
+	}
+
+	ret = clk_prepare_enable(phy_clk);
+
+	return ret;
+fail_set_rate:
+	clk_put(phy_clk);
+fail_get_phy_clk:
+	clk_put(input_clk);
+fail_get_input_clk:
+	clk_put(input_pclk);
+fail_get_input_pclk:
+	return ret;
+}
+
 void __init spear13xx_l2x0_init(void)
 {
 	/*