All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v1 1/2] sun8i_emac: Set MDC divider for MDIO read/write
Date: Fri, 17 Feb 2017 18:46:52 +0100	[thread overview]
Message-ID: <d867bbeb993517d734f9ec316243c0b4505eb49f.1487340707.git.philipp.tomsich@theobroma-systems.com> (raw)
In-Reply-To: <cover.1487340707.git.philipp.tomsich@theobroma-systems.com>

The IEEE 802.3 standard guarantees operation of the MDIO signals at up
to 2.5MHz (anything above this is a vendor-specific feature, although
most PHYs work at higher frequencies).  With the EMAC being fed by a
(typically) 300MHz clock (e.g. on the A64 this is AHB2, which should
be kept at 300MHz according to the CCU documentation), we need to use
the divide-by-128 setting to get us below 2.5MHz.

The ~2.34MHz clock signal (i.e. assuring that the MDC clock is indeed
derived from the AHB2 clock) has been verified using a A64-uQ7.

Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
---
 drivers/net/sun8i_emac.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index b87210b..5ae17b7 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -1,92 +1,98 @@
 /*
  * (C) Copyright 2016
  * Author: Amit Singh Tomar, amittomer25 at gmail.com
  *
  * SPDX-License-Identifier:     GPL-2.0+
  *
  * Ethernet driver for H3/A64/A83T based SoC's
  *
  * It is derived from the work done by
  * LABBE Corentin & Chen-Yu Tsai for Linux, THANKS!
  *
 */
 
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/gpio.h>
 #include <common.h>
 #include <dm.h>
 #include <fdt_support.h>
 #include <linux/err.h>
 #include <malloc.h>
 #include <miiphy.h>
 #include <net.h>
 
 #define MDIO_CMD_MII_BUSY		BIT(0)
 #define MDIO_CMD_MII_WRITE		BIT(1)
 
 #define MDIO_CMD_MII_PHY_REG_ADDR_MASK	0x000001f0
 #define MDIO_CMD_MII_PHY_REG_ADDR_SHIFT	4
 #define MDIO_CMD_MII_PHY_ADDR_MASK	0x0001f000
 #define MDIO_CMD_MII_PHY_ADDR_SHIFT	12
 
+#define MDIO_CMD_MDC_DIV_RATIO_M_SHIFT  20
+#define MDIO_CMD_MDC_DIV_16             (0 << MDIO_CMD_MDC_DIV_RATIO_M_SHIFT)
+#define MDIO_CMD_MDC_DIV_32             (1 << MDIO_CMD_MDC_DIV_RATIO_M_SHIFT)
+#define MDIO_CMD_MDC_DIV_64             (2 << MDIO_CMD_MDC_DIV_RATIO_M_SHIFT)
+#define MDIO_CMD_MDC_DIV_128            (3 << MDIO_CMD_MDC_DIV_RATIO_M_SHIFT)
+
 #define CONFIG_TX_DESCR_NUM	32
 #define CONFIG_RX_DESCR_NUM	32
 #define CONFIG_ETH_BUFSIZE	2048 /* Note must be dma aligned */
 
 /*
  * The datasheet says that each descriptor can transfers up to 4096 bytes
  * But later, the register documentation reduces that value to 2048,
  * using 2048 cause strange behaviours and even BSP driver use 2047
  */
 #define CONFIG_ETH_RXSIZE	2044 /* Note must fit in ETH_BUFSIZE */
 
 #define TX_TOTAL_BUFSIZE	(CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
 #define RX_TOTAL_BUFSIZE	(CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
 
 #define H3_EPHY_DEFAULT_VALUE	0x58000
 #define H3_EPHY_DEFAULT_MASK	GENMASK(31, 15)
 #define H3_EPHY_ADDR_SHIFT	20
 #define REG_PHY_ADDR_MASK	GENMASK(4, 0)
 #define H3_EPHY_LED_POL		BIT(17)	/* 1: active low, 0: active high */
 #define H3_EPHY_SHUTDOWN	BIT(16)	/* 1: shutdown, 0: power up */
 #define H3_EPHY_SELECT		BIT(15) /* 1: internal PHY, 0: external PHY */
 
 #define SC_RMII_EN		BIT(13)
 #define SC_EPIT			BIT(2) /* 1: RGMII, 0: MII */
 #define SC_ETCS_MASK		GENMASK(1, 0)
 #define SC_ETCS_EXT_GMII	0x1
 #define SC_ETCS_INT_GMII	0x2
 
 #define CONFIG_MDIO_TIMEOUT	(3 * CONFIG_SYS_HZ)
 
 #define AHB_GATE_OFFSET_EPHY	0
 
 #if defined(CONFIG_MACH_SUN8I_H3)
 #define SUN8I_GPD8_GMAC		2
 #else
 #define SUN8I_GPD8_GMAC		4
 #endif
 
 /* H3/A64 EMAC Register's offset */
 #define EMAC_CTL0		0x00
 #define EMAC_CTL1		0x04
 #define EMAC_INT_STA		0x08
 #define EMAC_INT_EN		0x0c
 #define EMAC_TX_CTL0		0x10
 #define EMAC_TX_CTL1		0x14
 #define EMAC_TX_FLOW_CTL	0x1c
 #define EMAC_TX_DMA_DESC	0x20
 #define EMAC_RX_CTL0		0x24
 #define EMAC_RX_CTL1		0x28
 #define EMAC_RX_DMA_DESC	0x34
 #define EMAC_MII_CMD		0x48
 #define EMAC_MII_DATA		0x4c
 #define EMAC_ADDR0_HIGH		0x50
 #define EMAC_ADDR0_LOW		0x54
 #define EMAC_TX_DMA_STA		0xb0
 #define EMAC_TX_CUR_DESC	0xb4
 #define EMAC_TX_CUR_BUF		0xb8
 #define EMAC_RX_DMA_STA		0xc0
 #define EMAC_RX_CUR_DESC	0xc4
 
@@ -133,66 +139,74 @@ struct emac_eth_dev {
 static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 {
 	struct emac_eth_dev *priv = bus->priv;
 	ulong start;
 	u32 miiaddr = 0;
 	int timeout = CONFIG_MDIO_TIMEOUT;
 
 	miiaddr &= ~MDIO_CMD_MII_WRITE;
 	miiaddr &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
 	miiaddr |= (reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
 		MDIO_CMD_MII_PHY_REG_ADDR_MASK;
 
 	miiaddr &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
 
 	miiaddr |= (addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
 		MDIO_CMD_MII_PHY_ADDR_MASK;
 
+	/* The MAC block is fed by a 300MHz clock, so we need to divide by 128
+	   to bring the MDC into the range permissible by the IEEE standard. */
+	miiaddr |= MDIO_CMD_MDC_DIV_128;
+
 	miiaddr |= MDIO_CMD_MII_BUSY;
 
 	writel(miiaddr, priv->mac_reg + EMAC_MII_CMD);
 
 	start = get_timer(0);
 	while (get_timer(start) < timeout) {
 		if (!(readl(priv->mac_reg + EMAC_MII_CMD) & MDIO_CMD_MII_BUSY))
 			return readl(priv->mac_reg + EMAC_MII_DATA);
 		udelay(10);
 	};
 
 	return -1;
 }
 
 static int sun8i_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
 			    u16 val)
 {
 	struct emac_eth_dev *priv = bus->priv;
 	ulong start;
 	u32 miiaddr = 0;
 	int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
 
 	miiaddr &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
 	miiaddr |= (reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
 		MDIO_CMD_MII_PHY_REG_ADDR_MASK;
 
 	miiaddr &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
 	miiaddr |= (addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
 		MDIO_CMD_MII_PHY_ADDR_MASK;
 
 	miiaddr |= MDIO_CMD_MII_WRITE;
 	miiaddr |= MDIO_CMD_MII_BUSY;
 
+	/* The MAC block is fed by a 300MHz clock, so we need to divide by 128
+	   to bring the MDC into the range permissible by the IEEE standard. */
+	miiaddr |= MDIO_CMD_MDC_DIV_128;
+
 	writel(val, priv->mac_reg + EMAC_MII_DATA);
 	writel(miiaddr, priv->mac_reg + EMAC_MII_CMD);
 
 	start = get_timer(0);
 	while (get_timer(start) < timeout) {
 		if (!(readl(priv->mac_reg + EMAC_MII_CMD) &
 					MDIO_CMD_MII_BUSY)) {
 			ret = 0;
 			break;
 		}
 		udelay(10);
 	};
 
 	return ret;
 }
 
-- 
1.9.1

  reply	other threads:[~2017-02-17 17:46 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-17 17:46 [U-Boot] [PATCH v1 0/2] sun8i_emac: set MDC divider for MDIO read/write Philipp Tomsich
2017-02-17 17:46 ` Philipp Tomsich [this message]
2017-02-17 17:46 ` [U-Boot] [PATCH v1 2/2] sun8i_emac: remove unnecessary bit-masking for mdio_read/write Philipp Tomsich
2017-02-17 23:49   ` André Przywara
2017-02-21 17:59 ` [U-Boot] [PATCH v1 0/2] sun8i_emac: set MDC divider for MDIO read/write Maxime Ripard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d867bbeb993517d734f9ec316243c0b4505eb49f.1487340707.git.philipp.tomsich@theobroma-systems.com \
    --to=philipp.tomsich@theobroma-systems.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.