diff mbox

[U-Boot,v2,07/12] net: gmac_rk3288: Add RK3288 GMAC driver

Message ID 1456694706-911-8-git-send-email-sjoerd.simons@collabora.co.uk
State Changes Requested
Delegated to: Simon Glass
Headers show

Commit Message

Sjoerd Simons Feb. 28, 2016, 9:25 p.m. UTC
Add a new driver for the GMAC ethernet interface present in Rockchip
RK3288 SOCs. This driver subclasses the generic design-ware driver to
add the glue needed specifically for Rockchip.

Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>

---

Changes in v2:
- Fix various coding style nits
- Adjust to new hook name

 drivers/net/Kconfig       |   7 +++
 drivers/net/Makefile      |   1 +
 drivers/net/gmac_rk3288.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+)
 create mode 100644 drivers/net/gmac_rk3288.c

Comments

Simon Glass March 1, 2016, 2:03 a.m. UTC | #1
Hi Sjoerd,

On 28 February 2016 at 14:25, Sjoerd Simons
<sjoerd.simons@collabora.co.uk> wrote:
> Add a new driver for the GMAC ethernet interface present in Rockchip
> RK3288 SOCs. This driver subclasses the generic design-ware driver to
> add the glue needed specifically for Rockchip.
>
> Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
>
> ---
>
> Changes in v2:
> - Fix various coding style nits
> - Adjust to new hook name
>
>  drivers/net/Kconfig       |   7 +++
>  drivers/net/Makefile      |   1 +
>  drivers/net/gmac_rk3288.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 133 insertions(+)
>  create mode 100644 drivers/net/gmac_rk3288.c
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index bc2f51d..fa49856 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -133,4 +133,11 @@ config PIC32_ETH
>           This driver implements 10/100 Mbps Ethernet and MAC layer for
>           Microchip PIC32 microcontrollers.
>
> +config GMAC_RK3288
> +       bool "Rockchip RK3288 Synopsys Designware Ethernet MAC"
> +       depends on DM_ETH && ETH_DESIGNWARE
> +       help
> +         This driver provides Rockchip RK3288 network support based on the
> +         Synopsys Designware driver.
> +
>  endif # NETDEVICES
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 33a81ee..d0a8009 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_FTGMAC100) += ftgmac100.o
>  obj-$(CONFIG_FTMAC110) += ftmac110.o
>  obj-$(CONFIG_FTMAC100) += ftmac100.o
>  obj-$(CONFIG_GRETH) += greth.o
> +obj-$(CONFIG_GMAC_RK3288) += gmac_rk3288.o
>  obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
>  obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
>  obj-$(CONFIG_LAN91C96) += lan91c96.o
> diff --git a/drivers/net/gmac_rk3288.c b/drivers/net/gmac_rk3288.c
> new file mode 100644
> index 0000000..5400b2c
> --- /dev/null
> +++ b/drivers/net/gmac_rk3288.c
> @@ -0,0 +1,125 @@
> +/*
> + * (C) Copyright 2015 Sjoerd Simons <sjoerd.simons@collabora.co.uk>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +/* * Rockchip GMAC ethernet IP driver for U-Boot */

/* Rockchip...

> +#include <common.h>
> +#include <dm.h>
> +#include <dm/pinctrl.h>
> +#include <asm/gpio.h>
> +#include <clk.h>
> +#include <phy.h>
> +#include <syscon.h>
> +#include <asm/io.h>
> +#include <asm/arch/periph.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/grf_rk3288.h>
> +#include "designware.h"
> +#include <dt-bindings/clock/rk3288-cru.h>

Can you sort these?

http://www.denx.de/wiki/U-Boot/CodingStyle

> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct gmac_rk3288_platdata {
> +       struct dw_eth_pdata dw_eth_pdata;
> +       int tx_delay;
> +       int rx_delay;
> +};
> +
> +static int gmac_rk3288_ofdata_to_platdata(struct udevice *dev)
> +{
> +       struct gmac_rk3288_platdata *pdata = dev_get_platdata(dev);
> +
> +       pdata->tx_delay = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
> +                                        "tx_delay", 0x30);
> +       pdata->rx_delay = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
> +                                        "rx_delay", 0x10);
> +
> +       return designware_eth_ofdata_to_platdata(dev);
> +}
> +
> +static int gmac_rk3288_fix_mac_speed(struct dw_eth_dev *priv)
> +{
> +       struct rk3288_grf *grf;
> +       int clk;
> +
> +       switch (priv->phydev->speed) {
> +       case 10:
> +               clk = GMAC_CLK_SEL_2_5M;
> +               break;
> +       case 100:
> +               clk = GMAC_CLK_SEL_25M;
> +               break;
> +       case 1000:
> +               clk = GMAC_CLK_SEL_125M;
> +               break;
> +       default:
> +               printf("Unknown phy speed: %d\n", priv->phydev->speed);
> +               return -EINVAL;
> +       }
> +
> +       grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> +
> +       rk_clrsetreg(&grf->soc_con1,
> +                    GMAC_CLK_SEL_MASK << GMAC_CLK_SEL_SHIFT,
> +                    clk << GMAC_CLK_SEL_SHIFT);
> +
> +       return 0;
> +}
> +
> +static int gmac_rk3288_probe(struct udevice *dev)
> +{
> +       int ret;
> +       struct gmac_rk3288_platdata *pdata = dev_get_platdata(dev);
> +       struct dw_eth_dev *priv = dev_get_priv(dev);
> +       struct rk3288_grf *grf;
> +       struct udevice *clk;
> +
> +

Remove extra blank line

> +       ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &clk);
> +       if (ret)
> +               return ret;

Can you use clk_get_by_index() ?

> +
> +       ret = clk_set_periph_rate(clk, SCLK_MAC, 0);
> +       if (ret)
> +               return ret;
> +
> +       /* Set to RGMII mode */
> +       grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> +       rk_clrsetreg(&grf->soc_con1,
> +                    RMII_MODE_MASK << RMII_MODE_SHIFT |
> +                    GMAC_PHY_INTF_SEL_MASK << GMAC_PHY_INTF_SEL_SHIFT,
> +                    GMAC_PHY_INTF_SEL_RGMII << GMAC_PHY_INTF_SEL_SHIFT);
> +
> +       rk_clrsetreg(&grf->soc_con3,
> +                    RXCLK_DLY_ENA_GMAC_MASK <<  RXCLK_DLY_ENA_GMAC_SHIFT |
> +                    TXCLK_DLY_ENA_GMAC_MASK <<  TXCLK_DLY_ENA_GMAC_SHIFT |
> +                    CLK_RX_DL_CFG_GMAC_MASK <<  CLK_RX_DL_CFG_GMAC_SHIFT |
> +                    CLK_TX_DL_CFG_GMAC_MASK <<  CLK_TX_DL_CFG_GMAC_SHIFT,
> +                    RXCLK_DLY_ENA_GMAC_ENABLE << RXCLK_DLY_ENA_GMAC_SHIFT |
> +                    TXCLK_DLY_ENA_GMAC_ENABLE << TXCLK_DLY_ENA_GMAC_SHIFT |
> +                    pdata->rx_delay << CLK_RX_DL_CFG_GMAC_SHIFT |
> +                    pdata->tx_delay << CLK_TX_DL_CFG_GMAC_SHIFT);
> +
> +       priv->fix_mac_speed = gmac_rk3288_fix_mac_speed;
> +
> +       return designware_eth_probe(dev);

This presumably called gmac_rk3288_fix_mac_speed(). Is it possible to
split the init so that you can call gmac_rk3288_fix_mac_speed()
directly here?

> +}
> +
> +static const struct udevice_id rk3288_gmac_ids[] = {
> +       { .compatible = "rockchip,rk3288-gmac" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(eth_gmac_rk3288) = {
> +       .name   = "gmac_rk3288",
> +       .id     = UCLASS_ETH,
> +       .of_match = rk3288_gmac_ids,
> +       .ofdata_to_platdata = gmac_rk3288_ofdata_to_platdata,
> +       .probe  = gmac_rk3288_probe,
> +       .ops    = &designware_eth_ops,
> +       .priv_auto_alloc_size = sizeof(struct dw_eth_dev),
> +       .platdata_auto_alloc_size = sizeof(struct gmac_rk3288_platdata),
> +       .flags = DM_FLAG_ALLOC_PRIV_DMA,
> +};
> --
> 2.7.0
>

Regards,
Simon
Sjoerd Simons March 11, 2016, 9:56 p.m. UTC | #2
On Mon, 2016-02-29 at 19:03 -0700, Simon Glass wrote:
> Hi Sjoerd,
> 
> On 28 February 2016 at 14:25, Sjoerd Simons
> <sjoerd.simons@collabora.co.uk> wrote:
> > 
> > 
> > diff --git a/drivers/net/gmac_rk3288.c b/drivers/net/gmac_rk3288.c
> > new file mode 100644
> > index 0000000..5400b2c
> > --- /dev/null
> > +++ b/drivers/net/gmac_rk3288.c
> > @@ -0,0 +1,125 @@
> > 
> > +       priv->fix_mac_speed = gmac_rk3288_fix_mac_speed;
> > +
> > +       return designware_eth_probe(dev);
> This presumably called gmac_rk3288_fix_mac_speed(). Is it possible to
> split the init so that you can call gmac_rk3288_fix_mac_speed()
> directly here?

No it gets called down the line from dw eth_ops start function once the
ethernet driver is started and the phy speed is known so the mac can be
adjust to match.

So to do it in the driver, it would need to override the eth start op
from its parent. Possible by exporting more of the designwares
implementation so specific ops can be overridden. 

Seems less elegant then having a hook in the semantically right spot
(e.g. after the link speed is determined)?

Ooi what's your worry with function pointers in DM ?
Simon Glass March 13, 2016, 1:54 a.m. UTC | #3
Hi Sjeord,

On 11 March 2016 at 14:56, Sjoerd Simons <sjoerd.simons@collabora.co.uk> wrote:
> On Mon, 2016-02-29 at 19:03 -0700, Simon Glass wrote:
>> Hi Sjoerd,
>>
>> On 28 February 2016 at 14:25, Sjoerd Simons
>> <sjoerd.simons@collabora.co.uk> wrote:
>> >
>> >
>> > diff --git a/drivers/net/gmac_rk3288.c b/drivers/net/gmac_rk3288.c
>> > new file mode 100644
>> > index 0000000..5400b2c
>> > --- /dev/null
>> > +++ b/drivers/net/gmac_rk3288.c
>> > @@ -0,0 +1,125 @@
>> >
>> > +       priv->fix_mac_speed = gmac_rk3288_fix_mac_speed;
>> > +
>> > +       return designware_eth_probe(dev);
>> This presumably called gmac_rk3288_fix_mac_speed(). Is it possible to
>> split the init so that you can call gmac_rk3288_fix_mac_speed()
>> directly here?
>
> No it gets called down the line from dw eth_ops start function once the
> ethernet driver is started and the phy speed is known so the mac can be
> adjust to match.
>
> So to do it in the driver, it would need to override the eth start op
> from its parent. Possible by exporting more of the designwares
> implementation so specific ops can be overridden.
>
> Seems less elegant then having a hook in the semantically right spot
> (e.g. after the link speed is determined)?
>
> Ooi what's your worry with function pointers in DM ?

I'm trying to avoid them. It is effectively an unofficial API that
doesn't go through DM. It suggests there is an extra layer of
software, but not quite...it is messy.

In the same vein I'm not keen on weak functions.

It looks to me as if the designware driver, which is currently
stand-alone, is being extended into a slightly different driver by
your patch. We really avoid that because we'll end up with more and
more fiddling for each SoC to make it work the way we want. This is
the kind of thing that driver model aims to avoid.

In that case here's my suggestion:
- Turn designware.c into a code library instead of a driver, and
export various functions
- Add a new dw_mac.c or something, which has the compatible strings
and the U_BOOT_DRIVER() declaration, and uses the
designware_eth_start(), etc. calls from designware.c
- Make your new driver do the same, except use your own start function

I see at the end of _dw_eth_init() there is a writel() that might need
to happen after your link adjustment. In that case this could be moved
into a separate function perhaps.

Regards,
Simon
diff mbox

Patch

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bc2f51d..fa49856 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -133,4 +133,11 @@  config PIC32_ETH
 	  This driver implements 10/100 Mbps Ethernet and MAC layer for
 	  Microchip PIC32 microcontrollers.
 
+config GMAC_RK3288
+	bool "Rockchip RK3288 Synopsys Designware Ethernet MAC"
+	depends on DM_ETH && ETH_DESIGNWARE
+	help
+	  This driver provides Rockchip RK3288 network support based on the
+	  Synopsys Designware driver.
+
 endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 33a81ee..d0a8009 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -32,6 +32,7 @@  obj-$(CONFIG_FTGMAC100) += ftgmac100.o
 obj-$(CONFIG_FTMAC110) += ftmac110.o
 obj-$(CONFIG_FTMAC100) += ftmac100.o
 obj-$(CONFIG_GRETH) += greth.o
+obj-$(CONFIG_GMAC_RK3288) += gmac_rk3288.o
 obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
 obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
 obj-$(CONFIG_LAN91C96) += lan91c96.o
diff --git a/drivers/net/gmac_rk3288.c b/drivers/net/gmac_rk3288.c
new file mode 100644
index 0000000..5400b2c
--- /dev/null
+++ b/drivers/net/gmac_rk3288.c
@@ -0,0 +1,125 @@ 
+/*
+ * (C) Copyright 2015 Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* * Rockchip GMAC ethernet IP driver for U-Boot */
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <asm/gpio.h>
+#include <clk.h>
+#include <phy.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch/periph.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/grf_rk3288.h>
+#include "designware.h"
+#include <dt-bindings/clock/rk3288-cru.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct gmac_rk3288_platdata {
+	struct dw_eth_pdata dw_eth_pdata;
+	int tx_delay;
+	int rx_delay;
+};
+
+static int gmac_rk3288_ofdata_to_platdata(struct udevice *dev)
+{
+	struct gmac_rk3288_platdata *pdata = dev_get_platdata(dev);
+
+	pdata->tx_delay = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+					 "tx_delay", 0x30);
+	pdata->rx_delay = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+					 "rx_delay", 0x10);
+
+	return designware_eth_ofdata_to_platdata(dev);
+}
+
+static int gmac_rk3288_fix_mac_speed(struct dw_eth_dev *priv)
+{
+	struct rk3288_grf *grf;
+	int clk;
+
+	switch (priv->phydev->speed) {
+	case 10:
+		clk = GMAC_CLK_SEL_2_5M;
+		break;
+	case 100:
+		clk = GMAC_CLK_SEL_25M;
+		break;
+	case 1000:
+		clk = GMAC_CLK_SEL_125M;
+		break;
+	default:
+		printf("Unknown phy speed: %d\n", priv->phydev->speed);
+		return -EINVAL;
+	}
+
+	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+	rk_clrsetreg(&grf->soc_con1,
+		     GMAC_CLK_SEL_MASK << GMAC_CLK_SEL_SHIFT,
+		     clk << GMAC_CLK_SEL_SHIFT);
+
+	return 0;
+}
+
+static int gmac_rk3288_probe(struct udevice *dev)
+{
+	int ret;
+	struct gmac_rk3288_platdata *pdata = dev_get_platdata(dev);
+	struct dw_eth_dev *priv = dev_get_priv(dev);
+	struct rk3288_grf *grf;
+	struct udevice *clk;
+
+
+	ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &clk);
+	if (ret)
+		return ret;
+
+	ret = clk_set_periph_rate(clk, SCLK_MAC, 0);
+	if (ret)
+		return ret;
+
+	/* Set to RGMII mode */
+	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+	rk_clrsetreg(&grf->soc_con1,
+		     RMII_MODE_MASK << RMII_MODE_SHIFT |
+		     GMAC_PHY_INTF_SEL_MASK << GMAC_PHY_INTF_SEL_SHIFT,
+		     GMAC_PHY_INTF_SEL_RGMII << GMAC_PHY_INTF_SEL_SHIFT);
+
+	rk_clrsetreg(&grf->soc_con3,
+		     RXCLK_DLY_ENA_GMAC_MASK <<  RXCLK_DLY_ENA_GMAC_SHIFT |
+		     TXCLK_DLY_ENA_GMAC_MASK <<  TXCLK_DLY_ENA_GMAC_SHIFT |
+		     CLK_RX_DL_CFG_GMAC_MASK <<  CLK_RX_DL_CFG_GMAC_SHIFT |
+		     CLK_TX_DL_CFG_GMAC_MASK <<  CLK_TX_DL_CFG_GMAC_SHIFT,
+		     RXCLK_DLY_ENA_GMAC_ENABLE << RXCLK_DLY_ENA_GMAC_SHIFT |
+		     TXCLK_DLY_ENA_GMAC_ENABLE << TXCLK_DLY_ENA_GMAC_SHIFT |
+		     pdata->rx_delay << CLK_RX_DL_CFG_GMAC_SHIFT |
+		     pdata->tx_delay << CLK_TX_DL_CFG_GMAC_SHIFT);
+
+	priv->fix_mac_speed = gmac_rk3288_fix_mac_speed;
+
+	return designware_eth_probe(dev);
+}
+
+static const struct udevice_id rk3288_gmac_ids[] = {
+	{ .compatible = "rockchip,rk3288-gmac" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_gmac_rk3288) = {
+	.name	= "gmac_rk3288",
+	.id	= UCLASS_ETH,
+	.of_match = rk3288_gmac_ids,
+	.ofdata_to_platdata = gmac_rk3288_ofdata_to_platdata,
+	.probe	= gmac_rk3288_probe,
+	.ops	= &designware_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct dw_eth_dev),
+	.platdata_auto_alloc_size = sizeof(struct gmac_rk3288_platdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};