[U-Boot] [PATCH 00/10] Add support for Rockchip RK3288 Ethernet

This series adds support for the GMAC Ethernet interface on RK3288 SoCs.
To add support I've taken a slightly different approach then some of the other boards with a designware IP block, by creating a new driver to take care of the platfrom glue which subclasses the main designware driver instead of adding the compatibility string the designware driver directly and doing the SoC specific setup in the board files. This seems quite a bit more elegant in a device model based world.
As the pinctrl and clock drivers are quite simple at the moment (hardcoded settings rather then retrieved from device-tree) the pinctrl and clock settings added in this series assume the setup for the ethernet interface used is for Firefly and Radxa Rock 2. Specifically It assumes the gmac is driven by an external clock, GPIO4B0 is the phy reset and the phy interface mode is RGMII.
I've only tested this series on a Radxa Rock 2 board, it would be great if someone could test this on other boards with the designware IP especially for those with the reset GPIO in devicetree (e.g. some of the Allwinner boards).
Sjoerd Simons (10): rockchip: rk3288: Add pinctrl support for the gmac ethernet interface rockchip: rk3288: Add clock support for the gmac ethernet interface net: designware: support phy reset device-tree bindings net: designware: Export various functions/struct to allow subclassing net: designware: Add a post-started hook net: gmac_rk3288: Add RK3288 GMAC driver rockchip: rk3288-firefly: Add gmac definition rockchip: firefly: Enable networking support rockchip: Add PXE and DHCP to the default boot targets rockchip: Drop Ethernet from the TODO
arch/arm/dts/rk3288-firefly.dtsi | 16 ++ arch/arm/include/asm/arch-rockchip/cru_rk3288.h | 17 ++ arch/arm/include/asm/arch-rockchip/grf_rk3288.h | 228 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/periph.h | 1 + configs/firefly-rk3288_defconfig | 5 + doc/README.rockchip | 1 - drivers/clk/clk_rk3288.c | 16 ++ drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/designware.c | 91 ++++++++-- drivers/net/designware.h | 19 ++ drivers/net/gmac_rk3288.c | 140 +++++++++++++++ drivers/pinctrl/rockchip/pinctrl_rk3288.c | 102 +++++++++++ include/configs/firefly-rk3288.h | 3 + include/configs/rk3288_common.h | 4 +- 15 files changed, 639 insertions(+), 12 deletions(-) create mode 100644 drivers/net/gmac_rk3288.c

Add support for the gmac ethernet interface to pinctrl. This hardcodes the setup to match that of the firefly and Radxa Rock2 boards, using the RGMII phy mode for gmac interface and GPIO4B0 as the phy reset GPIO.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk ---
arch/arm/include/asm/arch-rockchip/grf_rk3288.h | 228 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/periph.h | 1 + drivers/pinctrl/rockchip/pinctrl_rk3288.c | 102 +++++++++++ 3 files changed, 331 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h index 0117a17..b7dda47 100644 --- a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h @@ -283,6 +283,163 @@ enum { GPIO3C0_EMMC_CMD, };
+/* GRF_GPIO3DL_IOMUX */ +enum { + GPIO3D3_SHIFT = 12, + GPIO3D3_MASK = 7, + GPIO3D3_GPIO = 0, + GPIO3D3_FLASH1_DATA3, + GPIO3D3_HOST_DOUT3, + GPIO3D3_MAC_RXD3, + GPIO3D3_SDIO1_DATA3, + + GPIO3D2_SHIFT = 8, + GPIO3D2_MASK = 7, + GPIO3D2_GPIO = 0, + GPIO3D2_FLASH1_DATA2, + GPIO3D2_HOST_DOUT2, + GPIO3D2_MAC_RXD2, + GPIO3D2_SDIO1_DATA2, + + GPIO3D1_SHIFT = 4, + GPIO3D1_MASK = 7, + GPIO3D1_GPIO = 0, + GPIO3DL1_FLASH1_DATA1, + GPIO3D1_HOST_DOUT1, + GPIO3D1_MAC_TXD3, + GPIO3D1_SDIO1_DATA1, + + GPIO3D0_SHIFT = 0, + GPIO3D0_MASK = 7, + GPIO3D0_GPIO = 0, + GPIO3D0_FLASH1_DATA0, + GPIO3D0_HOST_DOUT0, + GPIO3D0_MAC_TXD2, + GPIO3D0_SDIO1_DATA0, +}; + +/* GRF_GPIO3HL_IOMUX */ +enum { + GPIO3D7_SHIFT = 12, + GPIO3D7_MASK = 7, + GPIO3D7_GPIO = 0, + GPIO3D7_FLASH1_DATA7, + GPIO3D7_HOST_DOUT7, + GPIO3D7_MAC_RXD1, + GPIO3D7_SDIO1_INTN, + + GPIO3D6_SHIFT = 8, + GPIO3D6_MASK = 7, + GPIO3D6_GPIO = 0, + GPIO3D6_FLASH1_DATA6, + GPIO3D6_HOST_DOUT6, + GPIO3D6_MAC_RXD0, + GPIO3D6_SDIO1_BKPWR, + + GPIO3D5_SHIFT = 4, + GPIO3D5_MASK = 7, + GPIO3D5_GPIO = 0, + GPIO3D5_FLASH1_DATA5, + GPIO3D5_HOST_DOUT5, + GPIO3D5_MAC_TXD1, + GPIO3D5_SDIO1_WRPRT, + + GPIO3D4_SHIFT = 0, + GPIO3D4_MASK = 7, + GPIO3D4_GPIO = 0, + GPIO3D4_FLASH1_DATA4, + GPIO3D4_HOST_DOUT4, + GPIO3D4_MAC_TXD0, + GPIO3D4_SDIO1_DETECTN, +}; + +/* GRF_GPIO4AL_IOMUX */ +enum { + GPIO4A3_SHIFT = 12, + GPIO4A3_MASK = 7, + GPIO4A3_GPIO = 0, + GPIO4A3_FLASH1_ALE, + GPIO4A3_HOST_DOUT9, + GPIO4A3_MAC_CLK, + GPIO4A3_FLASH0_CSN6, + + GPIO4A2_SHIFT = 8, + GPIO4A2_MASK = 7, + GPIO4A2_GPIO = 0, + GPIO4A2_FLASH1_RDN, + GPIO4A2_HOST_DOUT8, + GPIO4A2_MAC_RXER, + GPIO4A2_FLASH0_CSN5, + + GPIO4A1_SHIFT = 4, + GPIO4A1_MASK = 7, + GPIO4A1_GPIO = 0, + GPIO4A1_FLASH1_WP, + GPIO4A1_HOST_CKOUTN, + GPIO4A1_MAC_TXDV, + GPIO4A1_FLASH0_CSN4, + + GPIO4A0_SHIFT = 0, + GPIO4A0_MASK = 3, + GPIO4A0_GPIO = 0, + GPIO4A0_FLASH1_RDY, + GPIO4A0_HOST_CKOUTP, + GPIO4A0_MAC_MDC, +}; + +/* GRF_GPIO4AH_IOMUX */ +enum { + GPIO4A7_SHIFT = 12, + GPIO4A7_MASK = 7, + GPIO4A7_GPIO = 0, + GPIO4A7_FLASH1_CSN1, + GPIO4A7_HOST_DOUT13, + GPIO4A7_MAC_CSR, + GPIO4A7_SDIO1_CLKOUT, + + GPIO4A6_SHIFT = 8, + GPIO4A6_MASK = 7, + GPIO4A6_GPIO = 0, + GPIO4A6_FLASH1_CSN0, + GPIO4A6_HOST_DOUT12, + GPIO4A6_MAC_RXCLK, + GPIO4A6_SDIO1_CMD, + + GPIO4A5_SHIFT = 4, + GPIO4A5_MASK = 3, + GPIO4A5_GPIO = 0, + GPIO4A5_FLASH1_WRN, + GPIO4A5_HOST_DOUT11, + GPIO4A5_MAC_MDIO, + + GPIO4A4_SHIFT = 0, + GPIO4A4_MASK = 7, + GPIO4A4_GPIO = 0, + GPIO4A4_FLASH1_CLE, + GPIO4A4_HOST_DOUT10, + GPIO4A4_MAC_TXEN, + GPIO4A4_FLASH0_CSN7, +}; + +/* GRF_GPIO4BL_IOMUX */ +enum { + GPIO4B1_SHIFT = 4, + GPIO4B1_MASK = 7, + GPIO4B1_GPIO = 0, + GPIO4B1_FLASH1_CSN2, + GPIO4B1_HOST_DOUT15, + GPIO4B1_MAC_TXCLK, + GPIO4B1_SDIO1_PWREN, + + GPIO4B0_SHIFT = 0, + GPIO4B0_MASK = 7, + GPIO4B0_GPIO = 0, + GPIO4B0_FLASH1_DQS, + GPIO4B0_HOST_DOUT14, + GPIO4B0_MAC_COL, + GPIO4B0_FLASH1_CSN3, +}; + /* GRF_GPIO4C_IOMUX */ enum { GPIO4C7_SHIFT = 14, @@ -718,6 +875,40 @@ enum { MSCH0_MAINPARTIALPOP_MASK = 1, };
+/* GRF_SOC_CON1 */ +enum { + RMII_MODE_SHIFT = 0xe, + RMII_MODE_MASK = 1, + RMII_MODE = 1, + + GMAC_CLK_SEL_SHIFT = 0xc, + GMAC_CLK_SEL_MASK = 3, + GMAC_CLK_SEL_125M = 0, + GMAC_CLK_SEL_25M, + GMAC_CLK_SEL_2_5M, + + RMII_CLK_SEL_SHIFT = 0xb, + RMII_CLK_SEL_MASK = 1, + RMII_CLK_SEL_2_5M = 0, + RMII_CLK_SEL_25M, + + GMAC_SPEED_SHIFT = 0xa, + GMAC_SPEED_MASK = 1, + GMAC_SPEED_10M = 0, + GMAC_SPEED_100M, + + GMAC_FLOWCTRL_SHIFT = 0x9, + GMAC_FLOWCTRL_MASK = 1, + + GMAC_PHY_INTF_SEL_SHIFT = 0x6, + GMAC_PHY_INTF_SEL_MASK = 0x7, + GMAC_PHY_INTF_SEL_RGMII = 0x1, + GMAC_PHY_INTF_SEL_RMII = 0x4, + + HOST_REMAP_SHIFT = 0x5, + HOST_REMAP_MASK = 1 +}; + /* GRF_SOC_CON2 */ enum { UPCTL1_LPDDR3_ODT_EN_SHIFT = 0xd, @@ -765,4 +956,41 @@ enum { PWM_PWM = 0, };
+/* GRF_SOC_CON3 */ +enum { + RXCLK_DLY_ENA_GMAC_SHIFT = 0xf, + RXCLK_DLY_ENA_GMAC_MASK = 1, + RXCLK_DLY_ENA_GMAC_DISABLE = 0, + RXCLK_DLY_ENA_GMAC_ENABLE, + + TXCLK_DLY_ENA_GMAC_SHIFT = 0xe, + TXCLK_DLY_ENA_GMAC_MASK = 1, + TXCLK_DLY_ENA_GMAC_DISABLE = 0, + TXCLK_DLY_ENA_GMAC_ENABLE, + + CLK_RX_DL_CFG_GMAC_SHIFT = 0x7, + CLK_RX_DL_CFG_GMAC_MASK = 0x7f, + + CLK_TX_DL_CFG_GMAC_SHIFT = 0x0, + CLK_TX_DL_CFG_GMAC_MASK = 0x7f, +}; + +/* GPIO Bias settings */ +#define GPIO_BIAS_BITS 2 +#define GPIO_BIAS_MASK(x) (0x3 << (GPIO_BIAS_BITS * x)) + +#define GPIO_BIAS_2mA(x) (0x0 << (GPIO_BIAS_BITS * x)) +#define GPIO_BIAS_4mA(x) (0x1 << (GPIO_BIAS_BITS * x)) +#define GPIO_BIAS_8mA(x) (0x2 << (GPIO_BIAS_BITS * x)) +#define GPIO_BIAS_12mA(x) (0x3 << (GPIO_BIAS_BITS * x)) + +/* GPIO PU/PD settings */ +#define GPIO_PULL_BITS 2 +#define GPIO_PULL_MASK(x) (0x3 << (GPIO_PULL_BITS * x)) + +#define GPIO_PULL_NORMAL(x) (0x0 << (GPIO_PULL_BITS * x)) +#define GPIO_PULL_UP(x) (0x1 << (GPIO_PULL_BITS * x)) +#define GPIO_PULL_DOWN(x) (0x2 << (GPIO_PULL_BITS * x)) +#define GPIO_PULL_REPEAT(x) (0x3 << (GPIO_PULL_BITS * x)) + #endif diff --git a/arch/arm/include/asm/arch-rockchip/periph.h b/arch/arm/include/asm/arch-rockchip/periph.h index fa6069b..239a274 100644 --- a/arch/arm/include/asm/arch-rockchip/periph.h +++ b/arch/arm/include/asm/arch-rockchip/periph.h @@ -38,6 +38,7 @@ enum periph_id { PERIPH_ID_SDMMC1, PERIPH_ID_SDMMC2, PERIPH_ID_HDMI, + PERIPH_ID_GMAC,
PERIPH_ID_COUNT,
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index c432a00..e59f771 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -298,6 +298,103 @@ static void pinctrl_rk3288_sdmmc_config(struct rk3288_grf *grf, int mmc_id) } }
+static void pinctrl_rk3288_gmac_config(struct rk3288_grf *grf, int gmac_id) +{ + switch (gmac_id) { + case PERIPH_ID_GMAC: + rk_clrsetreg(&grf->gpio3dl_iomux, + GPIO3D3_MASK << GPIO3D3_SHIFT | + GPIO3D2_MASK << GPIO3D2_SHIFT | + GPIO3D2_MASK << GPIO3D1_SHIFT | + GPIO3D0_MASK << GPIO3D0_SHIFT, + GPIO3D3_MAC_RXD3 << GPIO3D3_SHIFT | + GPIO3D2_MAC_RXD2 << GPIO3D2_SHIFT | + GPIO3D1_MAC_TXD3 << GPIO3D1_SHIFT | + GPIO3D0_MAC_TXD2 << GPIO3D0_SHIFT); + + rk_clrsetreg(&grf->gpio3dh_iomux, + GPIO3D7_MASK << GPIO3D7_SHIFT | + GPIO3D6_MASK << GPIO3D6_SHIFT | + GPIO3D5_MASK << GPIO3D5_SHIFT | + GPIO3D4_MASK << GPIO3D4_SHIFT, + GPIO3D7_MAC_RXD1 << GPIO3D7_SHIFT | + GPIO3D6_MAC_RXD0 << GPIO3D6_SHIFT | + GPIO3D5_MAC_TXD1 << GPIO3D5_SHIFT | + GPIO3D4_MAC_TXD0 << GPIO3D4_SHIFT); + + /* switch the Tx pins to 12ma drive-strength */ + rk_clrsetreg(&grf->gpio1_e[2][3], + GPIO_BIAS_MASK(0) | GPIO_BIAS_MASK(1) | + GPIO_BIAS_MASK(4) | GPIO_BIAS_MASK(5), + GPIO_BIAS_12mA(0) | GPIO_BIAS_12mA(1) | + GPIO_BIAS_12mA(4) | GPIO_BIAS_12mA(5)); + + /* Set normal pull for all GPIO3D pins */ + rk_clrsetreg(&grf->gpio1_p[2][3], + GPIO_PULL_MASK(0) | GPIO_PULL_MASK(1) | + GPIO_PULL_MASK(2) | GPIO_PULL_MASK(3) | + GPIO_PULL_MASK(4) | GPIO_PULL_MASK(5) | + GPIO_PULL_MASK(6) | GPIO_PULL_MASK(7), + GPIO_PULL_NORMAL(0) | GPIO_PULL_NORMAL(1) | + GPIO_PULL_NORMAL(2) | GPIO_PULL_NORMAL(3) | + GPIO_PULL_NORMAL(4) | GPIO_PULL_NORMAL(5) | + GPIO_PULL_NORMAL(6) | GPIO_PULL_NORMAL(7)); + + rk_clrsetreg(&grf->gpio4al_iomux, + GPIO4A3_MASK << GPIO4A3_SHIFT | + GPIO4A1_MASK << GPIO4A1_SHIFT | + GPIO4A0_MASK << GPIO4A0_SHIFT, + GPIO4A3_MAC_CLK << GPIO4A3_SHIFT | + GPIO4A1_MAC_TXDV << GPIO4A1_SHIFT | + GPIO4A0_MAC_MDC << GPIO4A0_SHIFT); + + rk_clrsetreg(&grf->gpio4ah_iomux, + GPIO4A6_MASK << GPIO4A6_SHIFT | + GPIO4A5_MASK << GPIO4A5_SHIFT | + GPIO4A4_MASK << GPIO4A4_SHIFT, + GPIO4A6_MAC_RXCLK << GPIO4A6_SHIFT | + GPIO4A5_MAC_MDIO << GPIO4A5_SHIFT | + GPIO4A4_MAC_TXEN << GPIO4A4_SHIFT); + + /* switch GPIO4A4 to 12ma drive-strength */ + rk_clrsetreg(&grf->gpio1_e[3][0], + GPIO_BIAS_MASK(4), + GPIO_BIAS_12mA(4)); + /* Set normal pull for all GPIO4A pins */ + rk_clrsetreg(&grf->gpio1_p[3][0], + GPIO_PULL_MASK(0) | GPIO_PULL_MASK(1) | + GPIO_PULL_MASK(2) | GPIO_PULL_MASK(3) | + GPIO_PULL_MASK(4) | GPIO_PULL_MASK(5) | + GPIO_PULL_MASK(6) | GPIO_PULL_MASK(7), + GPIO_PULL_NORMAL(0) | GPIO_PULL_NORMAL(1) | + GPIO_PULL_NORMAL(2) | GPIO_PULL_NORMAL(3) | + GPIO_PULL_NORMAL(4) | GPIO_PULL_NORMAL(5) | + GPIO_PULL_NORMAL(6) | GPIO_PULL_NORMAL(7)); + + /* Assuming GPIO4B0_GPIO is phy-reset*/ + rk_clrsetreg(&grf->gpio4bl_iomux, + GPIO4B1_MASK << GPIO4B1_SHIFT | + GPIO4B0_MASK << GPIO4B0_SHIFT, + GPIO4B1_MAC_TXCLK << GPIO4B1_SHIFT| + GPIO4B0_GPIO << GPIO4B0_SHIFT); + + /* switch GPIO4B1 to 12ma drive-strength */ + rk_clrsetreg(&grf->gpio1_e[3][1], + GPIO_BIAS_MASK(1), + GPIO_BIAS_12mA(1)); + + /* Set pull normal for GPIO4B1, pull up for GPIO4B0 */ + rk_clrsetreg(&grf->gpio1_p[3][1], + GPIO_PULL_MASK(0) | GPIO_PULL_MASK(1), + GPIO_PULL_UP(0) | GPIO_PULL_NORMAL(1)); + + break; + default: + debug("gmac id = %d iomux error!\n", gmac_id); + break; + } +} + static void pinctrl_rk3288_hdmi_config(struct rk3288_grf *grf, int hdmi_id) { switch (hdmi_id) { @@ -354,6 +451,9 @@ static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags) case PERIPH_ID_SDMMC1: pinctrl_rk3288_sdmmc_config(priv->grf, func); break; + case PERIPH_ID_GMAC: + pinctrl_rk3288_gmac_config(priv->grf, func); + break; case PERIPH_ID_HDMI: pinctrl_rk3288_hdmi_config(priv->grf, func); break; @@ -376,6 +476,8 @@ static int rk3288_pinctrl_get_periph_id(struct udevice *dev, return -EINVAL;
switch (cell[1]) { + case 27: + return PERIPH_ID_GMAC; case 44: return PERIPH_ID_SPI0; case 45:

On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Add support for the gmac ethernet interface to pinctrl. This hardcodes the setup to match that of the firefly and Radxa Rock2 boards, using the RGMII phy mode for gmac interface and GPIO4B0 as the phy reset GPIO.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
arch/arm/include/asm/arch-rockchip/grf_rk3288.h | 228 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/periph.h | 1 + drivers/pinctrl/rockchip/pinctrl_rk3288.c | 102 +++++++++++ 3 files changed, 331 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h index 0117a17..b7dda47 100644 --- a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h @@ -283,6 +283,163 @@ enum { GPIO3C0_EMMC_CMD, };
+/* GRF_GPIO3DL_IOMUX */ +enum {
GPIO3D3_SHIFT = 12,
GPIO3D3_MASK = 7,
GPIO3D3_GPIO = 0,
GPIO3D3_FLASH1_DATA3,
GPIO3D3_HOST_DOUT3,
GPIO3D3_MAC_RXD3,
GPIO3D3_SDIO1_DATA3,
GPIO3D2_SHIFT = 8,
GPIO3D2_MASK = 7,
GPIO3D2_GPIO = 0,
GPIO3D2_FLASH1_DATA2,
GPIO3D2_HOST_DOUT2,
GPIO3D2_MAC_RXD2,
GPIO3D2_SDIO1_DATA2,
GPIO3D1_SHIFT = 4,
GPIO3D1_MASK = 7,
GPIO3D1_GPIO = 0,
GPIO3DL1_FLASH1_DATA1,
GPIO3D1_HOST_DOUT1,
GPIO3D1_MAC_TXD3,
GPIO3D1_SDIO1_DATA1,
GPIO3D0_SHIFT = 0,
GPIO3D0_MASK = 7,
GPIO3D0_GPIO = 0,
GPIO3D0_FLASH1_DATA0,
GPIO3D0_HOST_DOUT0,
GPIO3D0_MAC_TXD2,
GPIO3D0_SDIO1_DATA0,
+};
+/* GRF_GPIO3HL_IOMUX */ +enum {
GPIO3D7_SHIFT = 12,
GPIO3D7_MASK = 7,
GPIO3D7_GPIO = 0,
GPIO3D7_FLASH1_DATA7,
GPIO3D7_HOST_DOUT7,
GPIO3D7_MAC_RXD1,
GPIO3D7_SDIO1_INTN,
GPIO3D6_SHIFT = 8,
GPIO3D6_MASK = 7,
GPIO3D6_GPIO = 0,
GPIO3D6_FLASH1_DATA6,
GPIO3D6_HOST_DOUT6,
GPIO3D6_MAC_RXD0,
GPIO3D6_SDIO1_BKPWR,
GPIO3D5_SHIFT = 4,
GPIO3D5_MASK = 7,
GPIO3D5_GPIO = 0,
GPIO3D5_FLASH1_DATA5,
GPIO3D5_HOST_DOUT5,
GPIO3D5_MAC_TXD1,
GPIO3D5_SDIO1_WRPRT,
GPIO3D4_SHIFT = 0,
GPIO3D4_MASK = 7,
GPIO3D4_GPIO = 0,
GPIO3D4_FLASH1_DATA4,
GPIO3D4_HOST_DOUT4,
GPIO3D4_MAC_TXD0,
GPIO3D4_SDIO1_DETECTN,
+};
+/* GRF_GPIO4AL_IOMUX */ +enum {
GPIO4A3_SHIFT = 12,
GPIO4A3_MASK = 7,
GPIO4A3_GPIO = 0,
GPIO4A3_FLASH1_ALE,
GPIO4A3_HOST_DOUT9,
GPIO4A3_MAC_CLK,
GPIO4A3_FLASH0_CSN6,
GPIO4A2_SHIFT = 8,
GPIO4A2_MASK = 7,
GPIO4A2_GPIO = 0,
GPIO4A2_FLASH1_RDN,
GPIO4A2_HOST_DOUT8,
GPIO4A2_MAC_RXER,
GPIO4A2_FLASH0_CSN5,
GPIO4A1_SHIFT = 4,
GPIO4A1_MASK = 7,
GPIO4A1_GPIO = 0,
GPIO4A1_FLASH1_WP,
GPIO4A1_HOST_CKOUTN,
GPIO4A1_MAC_TXDV,
GPIO4A1_FLASH0_CSN4,
GPIO4A0_SHIFT = 0,
GPIO4A0_MASK = 3,
GPIO4A0_GPIO = 0,
GPIO4A0_FLASH1_RDY,
GPIO4A0_HOST_CKOUTP,
GPIO4A0_MAC_MDC,
+};
+/* GRF_GPIO4AH_IOMUX */ +enum {
GPIO4A7_SHIFT = 12,
GPIO4A7_MASK = 7,
GPIO4A7_GPIO = 0,
GPIO4A7_FLASH1_CSN1,
GPIO4A7_HOST_DOUT13,
GPIO4A7_MAC_CSR,
GPIO4A7_SDIO1_CLKOUT,
GPIO4A6_SHIFT = 8,
GPIO4A6_MASK = 7,
GPIO4A6_GPIO = 0,
GPIO4A6_FLASH1_CSN0,
GPIO4A6_HOST_DOUT12,
GPIO4A6_MAC_RXCLK,
GPIO4A6_SDIO1_CMD,
GPIO4A5_SHIFT = 4,
GPIO4A5_MASK = 3,
GPIO4A5_GPIO = 0,
GPIO4A5_FLASH1_WRN,
GPIO4A5_HOST_DOUT11,
GPIO4A5_MAC_MDIO,
GPIO4A4_SHIFT = 0,
GPIO4A4_MASK = 7,
GPIO4A4_GPIO = 0,
GPIO4A4_FLASH1_CLE,
GPIO4A4_HOST_DOUT10,
GPIO4A4_MAC_TXEN,
GPIO4A4_FLASH0_CSN7,
+};
+/* GRF_GPIO4BL_IOMUX */ +enum {
GPIO4B1_SHIFT = 4,
GPIO4B1_MASK = 7,
GPIO4B1_GPIO = 0,
GPIO4B1_FLASH1_CSN2,
GPIO4B1_HOST_DOUT15,
GPIO4B1_MAC_TXCLK,
GPIO4B1_SDIO1_PWREN,
GPIO4B0_SHIFT = 0,
GPIO4B0_MASK = 7,
GPIO4B0_GPIO = 0,
GPIO4B0_FLASH1_DQS,
GPIO4B0_HOST_DOUT14,
GPIO4B0_MAC_COL,
GPIO4B0_FLASH1_CSN3,
+};
/* GRF_GPIO4C_IOMUX */ enum { GPIO4C7_SHIFT = 14, @@ -718,6 +875,40 @@ enum { MSCH0_MAINPARTIALPOP_MASK = 1, };
+/* GRF_SOC_CON1 */ +enum {
RMII_MODE_SHIFT = 0xe,
RMII_MODE_MASK = 1,
RMII_MODE = 1,
GMAC_CLK_SEL_SHIFT = 0xc,
GMAC_CLK_SEL_MASK = 3,
GMAC_CLK_SEL_125M = 0,
GMAC_CLK_SEL_25M,
GMAC_CLK_SEL_2_5M,
RMII_CLK_SEL_SHIFT = 0xb,
RMII_CLK_SEL_MASK = 1,
RMII_CLK_SEL_2_5M = 0,
RMII_CLK_SEL_25M,
GMAC_SPEED_SHIFT = 0xa,
GMAC_SPEED_MASK = 1,
GMAC_SPEED_10M = 0,
GMAC_SPEED_100M,
GMAC_FLOWCTRL_SHIFT = 0x9,
GMAC_FLOWCTRL_MASK = 1,
GMAC_PHY_INTF_SEL_SHIFT = 0x6,
GMAC_PHY_INTF_SEL_MASK = 0x7,
GMAC_PHY_INTF_SEL_RGMII = 0x1,
GMAC_PHY_INTF_SEL_RMII = 0x4,
HOST_REMAP_SHIFT = 0x5,
HOST_REMAP_MASK = 1
+};
/* GRF_SOC_CON2 */ enum { UPCTL1_LPDDR3_ODT_EN_SHIFT = 0xd, @@ -765,4 +956,41 @@ enum { PWM_PWM = 0, };
+/* GRF_SOC_CON3 */ +enum {
RXCLK_DLY_ENA_GMAC_SHIFT = 0xf,
RXCLK_DLY_ENA_GMAC_MASK = 1,
RXCLK_DLY_ENA_GMAC_DISABLE = 0,
RXCLK_DLY_ENA_GMAC_ENABLE,
TXCLK_DLY_ENA_GMAC_SHIFT = 0xe,
TXCLK_DLY_ENA_GMAC_MASK = 1,
TXCLK_DLY_ENA_GMAC_DISABLE = 0,
TXCLK_DLY_ENA_GMAC_ENABLE,
CLK_RX_DL_CFG_GMAC_SHIFT = 0x7,
CLK_RX_DL_CFG_GMAC_MASK = 0x7f,
CLK_TX_DL_CFG_GMAC_SHIFT = 0x0,
CLK_TX_DL_CFG_GMAC_MASK = 0x7f,
+};
+/* GPIO Bias settings */ +#define GPIO_BIAS_BITS 2 +#define GPIO_BIAS_MASK(x) (0x3 << (GPIO_BIAS_BITS * x))
+#define GPIO_BIAS_2mA(x) (0x0 << (GPIO_BIAS_BITS * x)) +#define GPIO_BIAS_4mA(x) (0x1 << (GPIO_BIAS_BITS * x)) +#define GPIO_BIAS_8mA(x) (0x2 << (GPIO_BIAS_BITS * x)) +#define GPIO_BIAS_12mA(x) (0x3 << (GPIO_BIAS_BITS * x))
I'd really like to avoid these sorts of things. Instead:
enum { GPIO_BIAS_2MA = 0, GPIO_BIAS_4MA, ...
#define GPIO_BIAS_SHIFT(x) ((x) * 2)
Then:
rk_clrsetreg(&grf->gpio1_e[2][3], + GPIO_BIAS_16MA << GPIO_BIAS_SHIFT(1))
or similar. In other words follow the code that is there.
+/* GPIO PU/PD settings */ +#define GPIO_PULL_BITS 2 +#define GPIO_PULL_MASK(x) (0x3 << (GPIO_PULL_BITS * x))
+#define GPIO_PULL_NORMAL(x) (0x0 << (GPIO_PULL_BITS * x)) +#define GPIO_PULL_UP(x) (0x1 << (GPIO_PULL_BITS * x)) +#define GPIO_PULL_DOWN(x) (0x2 << (GPIO_PULL_BITS * x)) +#define GPIO_PULL_REPEAT(x) (0x3 << (GPIO_PULL_BITS * x))
#endif diff --git a/arch/arm/include/asm/arch-rockchip/periph.h b/arch/arm/include/asm/arch-rockchip/periph.h index fa6069b..239a274 100644 --- a/arch/arm/include/asm/arch-rockchip/periph.h +++ b/arch/arm/include/asm/arch-rockchip/periph.h @@ -38,6 +38,7 @@ enum periph_id { PERIPH_ID_SDMMC1, PERIPH_ID_SDMMC2, PERIPH_ID_HDMI,
PERIPH_ID_GMAC, PERIPH_ID_COUNT,
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index c432a00..e59f771 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -298,6 +298,103 @@ static void pinctrl_rk3288_sdmmc_config(struct rk3288_grf *grf, int mmc_id) } }
+static void pinctrl_rk3288_gmac_config(struct rk3288_grf *grf, int gmac_id) +{
switch (gmac_id) {
case PERIPH_ID_GMAC:
rk_clrsetreg(&grf->gpio3dl_iomux,
GPIO3D3_MASK << GPIO3D3_SHIFT |
GPIO3D2_MASK << GPIO3D2_SHIFT |
GPIO3D2_MASK << GPIO3D1_SHIFT |
GPIO3D0_MASK << GPIO3D0_SHIFT,
GPIO3D3_MAC_RXD3 << GPIO3D3_SHIFT |
GPIO3D2_MAC_RXD2 << GPIO3D2_SHIFT |
GPIO3D1_MAC_TXD3 << GPIO3D1_SHIFT |
GPIO3D0_MAC_TXD2 << GPIO3D0_SHIFT);
rk_clrsetreg(&grf->gpio3dh_iomux,
GPIO3D7_MASK << GPIO3D7_SHIFT |
GPIO3D6_MASK << GPIO3D6_SHIFT |
GPIO3D5_MASK << GPIO3D5_SHIFT |
GPIO3D4_MASK << GPIO3D4_SHIFT,
GPIO3D7_MAC_RXD1 << GPIO3D7_SHIFT |
GPIO3D6_MAC_RXD0 << GPIO3D6_SHIFT |
GPIO3D5_MAC_TXD1 << GPIO3D5_SHIFT |
GPIO3D4_MAC_TXD0 << GPIO3D4_SHIFT);
/* switch the Tx pins to 12ma drive-strength */
rk_clrsetreg(&grf->gpio1_e[2][3],
GPIO_BIAS_MASK(0) | GPIO_BIAS_MASK(1) |
GPIO_BIAS_MASK(4) | GPIO_BIAS_MASK(5),
GPIO_BIAS_12mA(0) | GPIO_BIAS_12mA(1) |
GPIO_BIAS_12mA(4) | GPIO_BIAS_12mA(5));
/* Set normal pull for all GPIO3D pins */
rk_clrsetreg(&grf->gpio1_p[2][3],
GPIO_PULL_MASK(0) | GPIO_PULL_MASK(1) |
GPIO_PULL_MASK(2) | GPIO_PULL_MASK(3) |
GPIO_PULL_MASK(4) | GPIO_PULL_MASK(5) |
GPIO_PULL_MASK(6) | GPIO_PULL_MASK(7),
GPIO_PULL_NORMAL(0) | GPIO_PULL_NORMAL(1) |
GPIO_PULL_NORMAL(2) | GPIO_PULL_NORMAL(3) |
GPIO_PULL_NORMAL(4) | GPIO_PULL_NORMAL(5) |
GPIO_PULL_NORMAL(6) | GPIO_PULL_NORMAL(7));
rk_clrsetreg(&grf->gpio4al_iomux,
GPIO4A3_MASK << GPIO4A3_SHIFT |
GPIO4A1_MASK << GPIO4A1_SHIFT |
GPIO4A0_MASK << GPIO4A0_SHIFT,
GPIO4A3_MAC_CLK << GPIO4A3_SHIFT |
GPIO4A1_MAC_TXDV << GPIO4A1_SHIFT |
GPIO4A0_MAC_MDC << GPIO4A0_SHIFT);
rk_clrsetreg(&grf->gpio4ah_iomux,
GPIO4A6_MASK << GPIO4A6_SHIFT |
GPIO4A5_MASK << GPIO4A5_SHIFT |
GPIO4A4_MASK << GPIO4A4_SHIFT,
GPIO4A6_MAC_RXCLK << GPIO4A6_SHIFT |
GPIO4A5_MAC_MDIO << GPIO4A5_SHIFT |
GPIO4A4_MAC_TXEN << GPIO4A4_SHIFT);
/* switch GPIO4A4 to 12ma drive-strength */
rk_clrsetreg(&grf->gpio1_e[3][0],
GPIO_BIAS_MASK(4),
GPIO_BIAS_12mA(4));
/* Set normal pull for all GPIO4A pins */
rk_clrsetreg(&grf->gpio1_p[3][0],
GPIO_PULL_MASK(0) | GPIO_PULL_MASK(1) |
GPIO_PULL_MASK(2) | GPIO_PULL_MASK(3) |
GPIO_PULL_MASK(4) | GPIO_PULL_MASK(5) |
GPIO_PULL_MASK(6) | GPIO_PULL_MASK(7),
GPIO_PULL_NORMAL(0) | GPIO_PULL_NORMAL(1) |
GPIO_PULL_NORMAL(2) | GPIO_PULL_NORMAL(3) |
GPIO_PULL_NORMAL(4) | GPIO_PULL_NORMAL(5) |
GPIO_PULL_NORMAL(6) | GPIO_PULL_NORMAL(7));
/* Assuming GPIO4B0_GPIO is phy-reset*/
Space before */
rk_clrsetreg(&grf->gpio4bl_iomux,
GPIO4B1_MASK << GPIO4B1_SHIFT |
GPIO4B0_MASK << GPIO4B0_SHIFT,
GPIO4B1_MAC_TXCLK << GPIO4B1_SHIFT|
GPIO4B0_GPIO << GPIO4B0_SHIFT);
Would this normally be handled by a GPIO? Does it belong in pinmux?
/* switch GPIO4B1 to 12ma drive-strength */
rk_clrsetreg(&grf->gpio1_e[3][1],
GPIO_BIAS_MASK(1),
GPIO_BIAS_12mA(1));
/* Set pull normal for GPIO4B1, pull up for GPIO4B0 */
rk_clrsetreg(&grf->gpio1_p[3][1],
GPIO_PULL_MASK(0) | GPIO_PULL_MASK(1),
GPIO_PULL_UP(0) | GPIO_PULL_NORMAL(1));
break;
default:
debug("gmac id = %d iomux error!\n", gmac_id);
break;
}
+}
static void pinctrl_rk3288_hdmi_config(struct rk3288_grf *grf, int hdmi_id) { switch (hdmi_id) { @@ -354,6 +451,9 @@ static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags) case PERIPH_ID_SDMMC1: pinctrl_rk3288_sdmmc_config(priv->grf, func); break;
case PERIPH_ID_GMAC:
pinctrl_rk3288_gmac_config(priv->grf, func);
break; case PERIPH_ID_HDMI: pinctrl_rk3288_hdmi_config(priv->grf, func); break;
@@ -376,6 +476,8 @@ static int rk3288_pinctrl_get_periph_id(struct udevice *dev, return -EINVAL;
switch (cell[1]) {
case 27:
return PERIPH_ID_GMAC; case 44: return PERIPH_ID_SPI0; case 45:
-- 2.5.3
Regards, Simon

On Sat, 2015-10-03 at 15:29 +0100, Simon Glass wrote:
On 1 October 2015 at 10:48, Sjoerd Simons < sjoerd.simons@collabora.co.uk> wrote:Add support for the gmac ethernet interface to pinctrl. This hardcodes
the setup to match that of the firefly and Radxa Rock2 boards, using the RGMII phy mode for gmac interface and GPIO4B0 as the phy reset GPIO.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
arch/arm/include/asm/arch-rockchip/grf_rk3288.h | 228 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/periph.h | 1 + drivers/pinctrl/rockchip/pinctrl_rk3288.c | 102 +++++++++++ 3 files changed, 331 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h index 0117a17..b7dda47 100644 --- a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h
/* Assuming GPIO4B0_GPIO is phy-reset*/
Space before */
GPIO4B1_MASK << GPIO4B1_SHIFT |
Would this normally be handled by a GPIO? Does it belong in pinmux?
Hrm, i'm changing the wrong pin there aren't I, woops (well either that or the comment is wrong)? Anyway, yes the PHY reset is typically a GPIO, this should just set up the respective pin in GPIO mode which is the job of pinmuxing right ? :)
Or maybe i'm misunderstanding your comment here?

Hi Sjoerd,
On 5 October 2015 at 10:04, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
On Sat, 2015-10-03 at 15:29 +0100, Simon Glass wrote:
On 1 October 2015 at 10:48, Sjoerd Simons < sjoerd.simons@collabora.co.uk> wrote:Add support for the gmac ethernet interface to pinctrl. This hardcodes
the setup to match that of the firefly and Radxa Rock2 boards, using the RGMII phy mode for gmac interface and GPIO4B0 as the phy reset GPIO.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
arch/arm/include/asm/arch-rockchip/grf_rk3288.h | 228 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/periph.h | 1 + drivers/pinctrl/rockchip/pinctrl_rk3288.c | 102 +++++++++++ 3 files changed, 331 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h index 0117a17..b7dda47 100644 --- a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h
/* Assuming GPIO4B0_GPIO is phy-reset*/
Space before */
GPIO4B1_MASK << GPIO4B1_SHIFT |
Would this normally be handled by a GPIO? Does it belong in pinmux?
Hrm, i'm changing the wrong pin there aren't I, woops (well either that or the comment is wrong)? Anyway, yes the PHY reset is typically a GPIO, this should just set up the respective pin in GPIO mode which is the job of pinmuxing right ? :)
Or maybe i'm misunderstanding your comment here?
I would hope that this would use gpio_request_by_name() instead, with the GPIO specified in the device tree. See for example:
vcc_sd: sdmmc-regulator { compatible = "regulator-fixed"; gpio = <&gpio7 11 GPIO_ACTIVE_LOW>; ... };
Regards, Simon

On Fri, 2015-10-09 at 10:36 +0100, Simon Glass wrote:
Hi Sjoerd,
On 5 October 2015 at 10:04, Sjoerd Simons < sjoerd.simons@collabora.co.uk> wrote:
On Sat, 2015-10-03 at 15:29 +0100, Simon Glass wrote:
On 1 October 2015 at 10:48, Sjoerd Simons < sjoerd.simons@collabora.co.uk> wrote:Add support for the gmac ethernet interface to pinctrl. This hardcodes
the setup to match that of the firefly and Radxa Rock2 boards, using the RGMII phy mode for gmac interface and GPIO4B0 as the phy reset GPIO.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
arch/arm/include/asm/arch-rockchip/grf_rk3288.h | 228 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/periph.h | 1 + drivers/pinctrl/rockchip/pinctrl_rk3288.c | 102 +++++++++++ 3 files changed, 331 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h index 0117a17..b7dda47 100644 --- a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h
/* Assuming GPIO4B0_GPIO is phy-reset*/
Space before */
GPIO4B1_MASK << GPIO4B1_SHIFT |
Would this normally be handled by a GPIO? Does it belong in pinmux?
Hrm, i'm changing the wrong pin there aren't I, woops (well either that or the comment is wrong)? Anyway, yes the PHY reset is typically a GPIO, this should just set up the respective pin in GPIO mode which is the job of pinmuxing right ? :)
Or maybe i'm misunderstanding your comment here?
I would hope that this would use gpio_request_by_name() instead, with the GPIO specified in the device tree. See for example:
vcc_sd: sdmmc-regulator { compatible = "regulator-fixed"; gpio = <&gpio7 11 GPIO_ACTIVE_LOW>; ... };
Sure and _that_ part is done via: snps,reset-gpio = <&gpio4 8 GPIO_ACTIVE_LOW>;
Which gets handled by the core designware driver in my patchset.
What this code is doing the equivalent of (in your example):
vcc_sd: sdmmc-regulator { ... pinctrl-names = "default"; pinctrl-0 = <&sdmmc_pwr>; ... };
sdmmc_pwr: sdmmc-pwr { rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>; };
In other words, it sets the function of the respective pin to be used for GPIO. However it doesn't do any control of it.

Hi Sjoerd,
On 9 October 2015 at 10:51, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
On Fri, 2015-10-09 at 10:36 +0100, Simon Glass wrote:
Hi Sjoerd,
On 5 October 2015 at 10:04, Sjoerd Simons < sjoerd.simons@collabora.co.uk> wrote:
On Sat, 2015-10-03 at 15:29 +0100, Simon Glass wrote:
On 1 October 2015 at 10:48, Sjoerd Simons < sjoerd.simons@collabora.co.uk> wrote:Add support for the gmac ethernet interface to pinctrl. This hardcodes
the setup to match that of the firefly and Radxa Rock2 boards, using the RGMII phy mode for gmac interface and GPIO4B0 as the phy reset GPIO.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
arch/arm/include/asm/arch-rockchip/grf_rk3288.h | 228 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/periph.h | 1 + drivers/pinctrl/rockchip/pinctrl_rk3288.c | 102 +++++++++++ 3 files changed, 331 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h index 0117a17..b7dda47 100644 --- a/arch/arm/include/asm/arch-rockchip/grf_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3288.h
/* Assuming GPIO4B0_GPIO is phy-reset*/
Space before */
GPIO4B1_MASK << GPIO4B1_SHIFT |
Would this normally be handled by a GPIO? Does it belong in pinmux?
Hrm, i'm changing the wrong pin there aren't I, woops (well either that or the comment is wrong)? Anyway, yes the PHY reset is typically a GPIO, this should just set up the respective pin in GPIO mode which is the job of pinmuxing right ? :)
Or maybe i'm misunderstanding your comment here?
I would hope that this would use gpio_request_by_name() instead, with the GPIO specified in the device tree. See for example:
vcc_sd: sdmmc-regulator { compatible = "regulator-fixed"; gpio = <&gpio7 11 GPIO_ACTIVE_LOW>; ... };
Sure and _that_ part is done via: snps,reset-gpio = <&gpio4 8 GPIO_ACTIVE_LOW>;
Which gets handled by the core designware driver in my patchset.
What this code is doing the equivalent of (in your example):
vcc_sd: sdmmc-regulator { ... pinctrl-names = "default"; pinctrl-0 = <&sdmmc_pwr>; ... };
sdmmc_pwr: sdmmc-pwr { rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>; };
In other words, it sets the function of the respective pin to be used for GPIO. However it doesn't do any control of it.
I see. In that case I suspect we should create a full pinctrl driver for Rockchip. The framework is there - Masahiro has sent patches for an implementation for Uniphier.
Regards, Simon

Setup the clocks for the gmac ethernet interface. This assumes the mac clock is fed by an external clock which is common on RK3288 based devices.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk ---
arch/arm/include/asm/arch-rockchip/cru_rk3288.h | 17 +++++++++++++++++ drivers/clk/clk_rk3288.c | 16 ++++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3288.h b/arch/arm/include/asm/arch-rockchip/cru_rk3288.h index 7ebcc40..69ec168 100644 --- a/arch/arm/include/asm/arch-rockchip/cru_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3288.h @@ -90,6 +90,23 @@ enum { SDIO0_DIV_MASK = 0x3f, };
+/* CRU_CLKSEL21_CON */ +enum { + MAC_DIV_CON_SHIFT = 0xf, + MAC_DIV_CON_MASK = 0x1f, + + RMII_EXTCLK_SHIFT = 4, + RMII_EXTCLK_MASK = 1, + RMII_EXTCLK_SELECT_INT_DIV_CLK = 0, + RMII_EXTCLK_SELECT_EXT_CLK = 1, + + EMAC_PLL_SHIFT = 0, + EMAC_PLL_MASK = 0x3, + EMAC_PLL_SELECT_NEW = 0x0, + EMAC_PLL_SELECT_CODEC = 0x1, + EMAC_PLL_SELECT_GENERAL = 0x2, +}; + /* CRU_CLKSEL25_CON */ enum { SPI1_PLL_SHIFT = 0xf, diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 54d4930..22f53d9 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -442,6 +442,18 @@ static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint clk_general_rate, return rockchip_mmc_get_clk(cru, clk_general_rate, periph); }
+static ulong rockchip_gmac_set_clk(struct rk3288_cru *cru, + uint clk_general_rate, + enum periph_id periph, uint freq) +{ + /* Assuming mac_clk is fed by an external clock */ + rk_clrsetreg(&cru->cru_clksel_con[21], + RMII_EXTCLK_MASK << RMII_EXTCLK_SHIFT, + RMII_EXTCLK_SELECT_EXT_CLK << RMII_EXTCLK_SHIFT); + + return 0; +} + static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint clk_general_rate, enum periph_id periph) { @@ -514,6 +526,10 @@ ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate) ulong new_rate;
switch (periph) { + case PERIPH_ID_GMAC: + new_rate = rockchip_gmac_set_clk(priv->cru, clk_get_rate(dev), + periph, rate); + break; case PERIPH_ID_EMMC: case PERIPH_ID_SDCARD: new_rate = rockchip_mmc_set_clk(priv->cru, clk_get_rate(dev),

On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Setup the clocks for the gmac ethernet interface. This assumes the mac clock is fed by an external clock which is common on RK3288 based devices.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
arch/arm/include/asm/arch-rockchip/cru_rk3288.h | 17 +++++++++++++++++ drivers/clk/clk_rk3288.c | 16 ++++++++++++++++ 2 files changed, 33 insertions(+)
Acked-by: Simon Glass sjg@chromium.org

Add support for the snps,reset-gpio, snps,reset-active-low (optional) and snps,reset-delays-us device-tree bindings. The combination of these three define how the PHY should be reset to ensure it's in a sane state.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk ---
drivers/net/designware.c | 74 ++++++++++++++++++++++++++++++++++++++++++++---- drivers/net/designware.h | 11 +++++++ 2 files changed, 79 insertions(+), 6 deletions(-)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 6433896..f9ceec2 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -28,7 +28,12 @@ DECLARE_GLOBAL_DATA_PTR;
static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) { +#ifdef CONFIG_DM_ETH + struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv); + struct eth_mac_regs *mac_p = priv->mac_regs_p; +#else struct eth_mac_regs *mac_p = bus->priv; +#endif ulong start; u16 miiaddr; int timeout = CONFIG_MDIO_TIMEOUT; @@ -51,7 +56,12 @@ static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val) { +#ifdef CONFIG_DM_ETH + struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv); + struct eth_mac_regs *mac_p = priv->mac_regs_p; +#else struct eth_mac_regs *mac_p = bus->priv; +#endif ulong start; u16 miiaddr; int ret = -ETIMEDOUT, timeout = CONFIG_MDIO_TIMEOUT; @@ -74,7 +84,40 @@ static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, return ret; }
-static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p) +#if CONFIG_DM_ETH +static int dw_mdio_reset(struct mii_dev *bus) +{ + struct udevice *dev = bus->priv; + struct dw_eth_pdata *pdata = dev_get_platdata(dev); + int ret; + + if (pdata->reset_gpio.dev == NULL) + return 0; + + /* reset the phy */ + ret = dm_gpio_set_value(&pdata->reset_gpio, 0); + if (ret) + return ret; + + udelay(pdata->reset_delays[0]); + + ret = dm_gpio_set_value(&pdata->reset_gpio, 1); + if (ret) + return ret; + + udelay(pdata->reset_delays[1]); + + ret = dm_gpio_set_value(&pdata->reset_gpio, 0); + if (ret) + return ret; + + udelay(pdata->reset_delays[2]); + + return 0; +} +#endif + +static int dw_mdio_init(const char *name, void *priv) { struct mii_dev *bus = mdio_alloc();
@@ -85,9 +128,12 @@ static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p)
bus->read = dw_mdio_read; bus->write = dw_mdio_write; +#ifdef CONFIG_DM_ETH + bus->reset = dw_mdio_reset; +#endif snprintf(bus->name, sizeof(bus->name), name);
- bus->priv = (void *)mac_regs_p; + bus->priv = priv;
return mdio_register(bus); } @@ -604,7 +650,7 @@ static int designware_eth_probe(struct udevice *dev) priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET); priv->interface = pdata->phy_interface;
- dw_mdio_init(dev->name, priv->mac_regs_p); + dw_mdio_init(dev->name, dev); priv->bus = miiphy_get_dev_by_name(dev->name);
ret = dw_phy_init(priv, dev); @@ -624,8 +670,11 @@ static const struct eth_ops designware_eth_ops = {
static int designware_eth_ofdata_to_platdata(struct udevice *dev) { - struct eth_pdata *pdata = dev_get_platdata(dev); + struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev); + struct eth_pdata *pdata = &dw_pdata->eth_pdata; const char *phy_mode; + int reset_flags = GPIOD_IS_OUT; + int ret = 0;
pdata->iobase = dev_get_addr(dev); pdata->phy_interface = -1; @@ -637,7 +686,20 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev) return -EINVAL; }
- return 0; + if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, + "snps,reset-active-low")) + reset_flags |= GPIOD_ACTIVE_LOW; + + ret = gpio_request_by_name(dev, "snps,reset-gpio", 0, + &dw_pdata->reset_gpio, reset_flags); + if (ret == 0) { + ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, + "snps,reset-delays-us", dw_pdata->reset_delays, 3); + } else if (ret == -ENOENT) { + ret = 0; + } + + return ret; }
static const struct udevice_id designware_eth_ids[] = { @@ -655,7 +717,7 @@ U_BOOT_DRIVER(eth_designware) = { .probe = designware_eth_probe, .ops = &designware_eth_ops, .priv_auto_alloc_size = sizeof(struct dw_eth_dev), - .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .platdata_auto_alloc_size = sizeof(struct dw_eth_pdata), .flags = DM_FLAG_ALLOC_PRIV_DMA, };
diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 4b9ec39..f34263b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -8,6 +8,9 @@ #ifndef _DW_ETH_H #define _DW_ETH_H
+#include <common.h> +#include <asm/gpio.h> + #define CONFIG_TX_DESCR_NUM 16 #define CONFIG_RX_DESCR_NUM 16 #define CONFIG_ETH_BUFSIZE 2048 @@ -235,4 +238,12 @@ struct dw_eth_dev { struct mii_dev *bus; };
+#ifdef CONFIG_DM_ETH +struct dw_eth_pdata { + struct eth_pdata eth_pdata; + struct gpio_desc reset_gpio; + u32 reset_delays[3]; +}; +#endif + #endif

Hi Sjoerd,
On Thu, Oct 1, 2015 at 5:48 PM, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Add support for the snps,reset-gpio, snps,reset-active-low (optional) and snps,reset-delays-us device-tree bindings. The combination of these three define how the PHY should be reset to ensure it's in a sane state.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
drivers/net/designware.c | 74 ++++++++++++++++++++++++++++++++++++++++++++---- drivers/net/designware.h | 11 +++++++ 2 files changed, 79 insertions(+), 6 deletions(-)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 6433896..f9ceec2 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -28,7 +28,12 @@ DECLARE_GLOBAL_DATA_PTR;
static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) { +#ifdef CONFIG_DM_ETH
struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv);
struct eth_mac_regs *mac_p = priv->mac_regs_p;
+#else struct eth_mac_regs *mac_p = bus->priv; +#endif ulong start; u16 miiaddr; int timeout = CONFIG_MDIO_TIMEOUT; @@ -51,7 +56,12 @@ static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val) { +#ifdef CONFIG_DM_ETH
struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv);
struct eth_mac_regs *mac_p = priv->mac_regs_p;
+#else struct eth_mac_regs *mac_p = bus->priv; +#endif ulong start; u16 miiaddr; int ret = -ETIMEDOUT, timeout = CONFIG_MDIO_TIMEOUT; @@ -74,7 +84,40 @@ static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, return ret; }
-static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p) +#if CONFIG_DM_ETH +static int dw_mdio_reset(struct mii_dev *bus) +{
struct udevice *dev = bus->priv;
struct dw_eth_pdata *pdata = dev_get_platdata(dev);
int ret;
if (pdata->reset_gpio.dev == NULL)
return 0;
/* reset the phy */
ret = dm_gpio_set_value(&pdata->reset_gpio, 0);
if (ret)
return ret;
Is this PHY reset a must every time we start the MAC? If this is just one-time reset, can it be moved to board-specific codes?
udelay(pdata->reset_delays[0]);
ret = dm_gpio_set_value(&pdata->reset_gpio, 1);
if (ret)
return ret;
udelay(pdata->reset_delays[1]);
ret = dm_gpio_set_value(&pdata->reset_gpio, 0);
if (ret)
return ret;
udelay(pdata->reset_delays[2]);
return 0;
+} +#endif
+static int dw_mdio_init(const char *name, void *priv) { struct mii_dev *bus = mdio_alloc();
@@ -85,9 +128,12 @@ static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p)
bus->read = dw_mdio_read; bus->write = dw_mdio_write;
+#ifdef CONFIG_DM_ETH
bus->reset = dw_mdio_reset;
+#endif snprintf(bus->name, sizeof(bus->name), name);
bus->priv = (void *)mac_regs_p;
bus->priv = priv; return mdio_register(bus);
} @@ -604,7 +650,7 @@ static int designware_eth_probe(struct udevice *dev) priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET); priv->interface = pdata->phy_interface;
dw_mdio_init(dev->name, priv->mac_regs_p);
dw_mdio_init(dev->name, dev); priv->bus = miiphy_get_dev_by_name(dev->name); ret = dw_phy_init(priv, dev);
@@ -624,8 +670,11 @@ static const struct eth_ops designware_eth_ops = {
static int designware_eth_ofdata_to_platdata(struct udevice *dev) {
struct eth_pdata *pdata = dev_get_platdata(dev);
struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev);
struct eth_pdata *pdata = &dw_pdata->eth_pdata; const char *phy_mode;
int reset_flags = GPIOD_IS_OUT;
int ret = 0; pdata->iobase = dev_get_addr(dev); pdata->phy_interface = -1;
@@ -637,7 +686,20 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev) return -EINVAL; }
return 0;
if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
"snps,reset-active-low"))
reset_flags |= GPIOD_ACTIVE_LOW;
ret = gpio_request_by_name(dev, "snps,reset-gpio", 0,
&dw_pdata->reset_gpio, reset_flags);
if (ret == 0) {
ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
"snps,reset-delays-us", dw_pdata->reset_delays, 3);
} else if (ret == -ENOENT) {
ret = 0;
}
return ret;
}
static const struct udevice_id designware_eth_ids[] = { @@ -655,7 +717,7 @@ U_BOOT_DRIVER(eth_designware) = { .probe = designware_eth_probe, .ops = &designware_eth_ops, .priv_auto_alloc_size = sizeof(struct dw_eth_dev),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
.platdata_auto_alloc_size = sizeof(struct dw_eth_pdata), .flags = DM_FLAG_ALLOC_PRIV_DMA,
};
diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 4b9ec39..f34263b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -8,6 +8,9 @@ #ifndef _DW_ETH_H #define _DW_ETH_H
+#include <common.h>
<common.h> should not be in a header file.
+#include <asm/gpio.h>
#define CONFIG_TX_DESCR_NUM 16 #define CONFIG_RX_DESCR_NUM 16 #define CONFIG_ETH_BUFSIZE 2048 @@ -235,4 +238,12 @@ struct dw_eth_dev { struct mii_dev *bus; };
+#ifdef CONFIG_DM_ETH +struct dw_eth_pdata {
struct eth_pdata eth_pdata;
struct gpio_desc reset_gpio;
u32 reset_delays[3];
+}; +#endif
#endif
Regards, Bin

On Thu, 2015-10-01 at 19:02 +0800, Bin Meng wrote:
Hi Sjoerd,
On Thu, Oct 1, 2015 at 5:48 PM, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
-static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p) +#if CONFIG_DM_ETH +static int dw_mdio_reset(struct mii_dev *bus) +{
struct udevice *dev = bus->priv;
struct dw_eth_pdata *pdata = dev_get_platdata(dev);
int ret;
if (pdata->reset_gpio.dev == NULL)
return 0;
/* reset the phy */
ret = dm_gpio_set_value(&pdata->reset_gpio, 0);
if (ret)
return ret;
Is this PHY reset a must every time we start the MAC? If this is just one-time reset, can it be moved to board-specific codes?
The MDIO bus reset is only triggered from dw_phy_init, which is called by the probe function in a DM build. So that should already only run once, instead of at every MAC start.
In any case, the whole point of implementing it here is that it's a common device-tree binding for all designware macs so it's much nice to implement it in a central place rather then duplicating it for all boards in board-specific code :)

Hi Sjoerd,
On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Add support for the snps,reset-gpio, snps,reset-active-low (optional) and snps,reset-delays-us device-tree bindings. The combination of these three define how the PHY should be reset to ensure it's in a sane state.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
drivers/net/designware.c | 74 ++++++++++++++++++++++++++++++++++++++++++++---- drivers/net/designware.h | 11 +++++++ 2 files changed, 79 insertions(+), 6 deletions(-)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 6433896..f9ceec2 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -28,7 +28,12 @@ DECLARE_GLOBAL_DATA_PTR;
static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) { +#ifdef CONFIG_DM_ETH
struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv);
struct eth_mac_regs *mac_p = priv->mac_regs_p;
+#else struct eth_mac_regs *mac_p = bus->priv; +#endif ulong start; u16 miiaddr; int timeout = CONFIG_MDIO_TIMEOUT; @@ -51,7 +56,12 @@ static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val) { +#ifdef CONFIG_DM_ETH
struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv);
struct eth_mac_regs *mac_p = priv->mac_regs_p;
+#else struct eth_mac_regs *mac_p = bus->priv; +#endif ulong start; u16 miiaddr; int ret = -ETIMEDOUT, timeout = CONFIG_MDIO_TIMEOUT; @@ -74,7 +84,40 @@ static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, return ret; }
-static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p) +#if CONFIG_DM_ETH +static int dw_mdio_reset(struct mii_dev *bus) +{
struct udevice *dev = bus->priv;
struct dw_eth_pdata *pdata = dev_get_platdata(dev);
int ret;
if (pdata->reset_gpio.dev == NULL)
!dm_gpio_is_valid(&pdata->reset_gpio)
return 0;
/* reset the phy */
ret = dm_gpio_set_value(&pdata->reset_gpio, 0);
if (ret)
return ret;
udelay(pdata->reset_delays[0]);
ret = dm_gpio_set_value(&pdata->reset_gpio, 1);
if (ret)
return ret;
udelay(pdata->reset_delays[1]);
ret = dm_gpio_set_value(&pdata->reset_gpio, 0);
if (ret)
return ret;
udelay(pdata->reset_delays[2]);
return 0;
+} +#endif
+static int dw_mdio_init(const char *name, void *priv) { struct mii_dev *bus = mdio_alloc();
@@ -85,9 +128,12 @@ static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p)
bus->read = dw_mdio_read; bus->write = dw_mdio_write;
+#ifdef CONFIG_DM_ETH
bus->reset = dw_mdio_reset;
+#endif snprintf(bus->name, sizeof(bus->name), name);
bus->priv = (void *)mac_regs_p;
bus->priv = priv; return mdio_register(bus);
} @@ -604,7 +650,7 @@ static int designware_eth_probe(struct udevice *dev) priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET); priv->interface = pdata->phy_interface;
dw_mdio_init(dev->name, priv->mac_regs_p);
dw_mdio_init(dev->name, dev); priv->bus = miiphy_get_dev_by_name(dev->name); ret = dw_phy_init(priv, dev);
@@ -624,8 +670,11 @@ static const struct eth_ops designware_eth_ops = {
static int designware_eth_ofdata_to_platdata(struct udevice *dev) {
struct eth_pdata *pdata = dev_get_platdata(dev);
struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev);
struct eth_pdata *pdata = &dw_pdata->eth_pdata; const char *phy_mode;
int reset_flags = GPIOD_IS_OUT;
int ret = 0; pdata->iobase = dev_get_addr(dev); pdata->phy_interface = -1;
@@ -637,7 +686,20 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev) return -EINVAL; }
return 0;
if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
"snps,reset-active-low"))
reset_flags |= GPIOD_ACTIVE_LOW;
ret = gpio_request_by_name(dev, "snps,reset-gpio", 0,
&dw_pdata->reset_gpio, reset_flags);
It's odd to put a probed gpio into platdata. Should you use private data instead? (dev_get_priv())
if (ret == 0) {
ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
"snps,reset-delays-us", dw_pdata->reset_delays, 3);
} else if (ret == -ENOENT) {
ret = 0;
}
return ret;
}
static const struct udevice_id designware_eth_ids[] = { @@ -655,7 +717,7 @@ U_BOOT_DRIVER(eth_designware) = { .probe = designware_eth_probe, .ops = &designware_eth_ops, .priv_auto_alloc_size = sizeof(struct dw_eth_dev),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
.platdata_auto_alloc_size = sizeof(struct dw_eth_pdata), .flags = DM_FLAG_ALLOC_PRIV_DMA,
};
diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 4b9ec39..f34263b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -8,6 +8,9 @@ #ifndef _DW_ETH_H #define _DW_ETH_H
+#include <common.h>
Drop that one...
+#include <asm/gpio.h>
#define CONFIG_TX_DESCR_NUM 16 #define CONFIG_RX_DESCR_NUM 16 #define CONFIG_ETH_BUFSIZE 2048 @@ -235,4 +238,12 @@ struct dw_eth_dev { struct mii_dev *bus; };
+#ifdef CONFIG_DM_ETH
Do you need this #ifdef
+struct dw_eth_pdata {
struct eth_pdata eth_pdata;
struct gpio_desc reset_gpio;
u32 reset_delays[3];
+}; +#endif
#endif
2.5.3
Regards, Simon

To allow other DM drivers to subclass the designware driver various functions and structures need to be exported. Export these.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk ---
drivers/net/designware.c | 6 +++--- drivers/net/designware.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c index f9ceec2..0b7adc9 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -621,7 +621,7 @@ static int designware_eth_bind(struct udevice *dev) return 0; }
-static int designware_eth_probe(struct udevice *dev) +int designware_eth_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct dw_eth_dev *priv = dev_get_priv(dev); @@ -659,7 +659,7 @@ static int designware_eth_probe(struct udevice *dev) return ret; }
-static const struct eth_ops designware_eth_ops = { +const struct eth_ops designware_eth_ops = { .start = designware_eth_start, .send = designware_eth_send, .recv = designware_eth_recv, @@ -668,7 +668,7 @@ static const struct eth_ops designware_eth_ops = { .write_hwaddr = designware_eth_write_hwaddr, };
-static int designware_eth_ofdata_to_platdata(struct udevice *dev) +int designware_eth_ofdata_to_platdata(struct udevice *dev) { struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev); struct eth_pdata *pdata = &dw_pdata->eth_pdata; diff --git a/drivers/net/designware.h b/drivers/net/designware.h index f34263b..47e727b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -239,6 +239,10 @@ struct dw_eth_dev { };
#ifdef CONFIG_DM_ETH +int designware_eth_ofdata_to_platdata(struct udevice *dev); +int designware_eth_probe(struct udevice *dev); +extern const struct eth_ops designware_eth_ops; + struct dw_eth_pdata { struct eth_pdata eth_pdata; struct gpio_desc reset_gpio;

On Thu, Oct 1, 2015 at 5:48 PM, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
To allow other DM drivers to subclass the designware driver various functions and structures need to be exported. Export these.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
drivers/net/designware.c | 6 +++--- drivers/net/designware.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c index f9ceec2..0b7adc9 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -621,7 +621,7 @@ static int designware_eth_bind(struct udevice *dev) return 0; }
-static int designware_eth_probe(struct udevice *dev) +int designware_eth_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct dw_eth_dev *priv = dev_get_priv(dev); @@ -659,7 +659,7 @@ static int designware_eth_probe(struct udevice *dev) return ret; }
-static const struct eth_ops designware_eth_ops = { +const struct eth_ops designware_eth_ops = { .start = designware_eth_start, .send = designware_eth_send, .recv = designware_eth_recv, @@ -668,7 +668,7 @@ static const struct eth_ops designware_eth_ops = { .write_hwaddr = designware_eth_write_hwaddr, };
-static int designware_eth_ofdata_to_platdata(struct udevice *dev) +int designware_eth_ofdata_to_platdata(struct udevice *dev) { struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev); struct eth_pdata *pdata = &dw_pdata->eth_pdata; diff --git a/drivers/net/designware.h b/drivers/net/designware.h index f34263b..47e727b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -239,6 +239,10 @@ struct dw_eth_dev { };
#ifdef CONFIG_DM_ETH +int designware_eth_ofdata_to_platdata(struct udevice *dev); +int designware_eth_probe(struct udevice *dev); +extern const struct eth_ops designware_eth_ops;
struct dw_eth_pdata { struct eth_pdata eth_pdata; struct gpio_desc reset_gpio; --
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
To allow other DM drivers to subclass the designware driver various functions and structures need to be exported. Export these.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
drivers/net/designware.c | 6 +++--- drivers/net/designware.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-)
Acked-by: Simon Glass sjg@chromium.org

Add the ability for e.g. drivers subclassing to register a function to be called after ethernet initialisation. This is useful if e.g. the driver needs to change configuration based on the negotiated speed.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk ---
drivers/net/designware.c | 11 ++++++++++- drivers/net/designware.h | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 0b7adc9..da27041 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -564,8 +564,17 @@ int designware_initialize(ulong base_addr, u32 interface) static int designware_eth_start(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); + struct dw_eth_dev *priv = dev_get_priv(dev); + int ret;
- return _dw_eth_init(dev->priv, pdata->enetaddr); + ret = _dw_eth_init(priv, pdata->enetaddr); + if (ret) + return ret; + + if (priv->started) + ret = priv->started(dev); + + return ret; }
static int designware_eth_send(struct udevice *dev, void *packet, int length) diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 47e727b..b45599b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -236,6 +236,10 @@ struct dw_eth_dev { #endif struct phy_device *phydev; struct mii_dev *bus; + +#ifdef CONFIG_DM_ETH + int (*started)(struct udevice *dev); +#endif };
#ifdef CONFIG_DM_ETH

Hi Sjoerd,
On Thu, Oct 1, 2015 at 5:48 PM, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Add the ability for e.g. drivers subclassing to register a function to be called after ethernet initialisation. This is useful if e.g. the driver needs to change configuration based on the negotiated speed.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
drivers/net/designware.c | 11 ++++++++++- drivers/net/designware.h | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 0b7adc9..da27041 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -564,8 +564,17 @@ int designware_initialize(ulong base_addr, u32 interface) static int designware_eth_start(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev);
struct dw_eth_dev *priv = dev_get_priv(dev);
int ret;
return _dw_eth_init(dev->priv, pdata->enetaddr);
ret = _dw_eth_init(priv, pdata->enetaddr);
if (ret)
return ret;
if (priv->started)
ret = priv->started(dev);
It looks to me a better approach to set up the MAC clock is to insert the hook in dw_adjust_link(). And see below ..
return ret;
}
static int designware_eth_send(struct udevice *dev, void *packet, int length) diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 47e727b..b45599b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -236,6 +236,10 @@ struct dw_eth_dev { #endif struct phy_device *phydev; struct mii_dev *bus;
+#ifdef CONFIG_DM_ETH
int (*started)(struct udevice *dev);
+#endif
We can name this as something like (*clk_set) to be clearer. (*started) is not that intuitive.
};
#ifdef CONFIG_DM_ETH
Regards, Bin

Hi Sjoerd,
On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Add the ability for e.g. drivers subclassing to register a function to be called after ethernet initialisation. This is useful if e.g. the driver needs to change configuration based on the negotiated speed.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
drivers/net/designware.c | 11 ++++++++++- drivers/net/designware.h | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 0b7adc9..da27041 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -564,8 +564,17 @@ int designware_initialize(ulong base_addr, u32 interface) static int designware_eth_start(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev);
struct dw_eth_dev *priv = dev_get_priv(dev);
int ret;
return _dw_eth_init(dev->priv, pdata->enetaddr);
ret = _dw_eth_init(priv, pdata->enetaddr);
if (ret)
return ret;
if (priv->started)
ret = priv->started(dev);
return ret;
}
static int designware_eth_send(struct udevice *dev, void *packet, int length) diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 47e727b..b45599b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -236,6 +236,10 @@ struct dw_eth_dev { #endif struct phy_device *phydev; struct mii_dev *bus;
+#ifdef CONFIG_DM_ETH
int (*started)(struct udevice *dev);
+#endif
With driver model we should not need to add such hooks. is this needed because we don't have a PHY uclass yet?
};
#ifdef CONFIG_DM_ETH
2.5.3
Regards, Simon

On Sat, 2015-10-03 at 15:30 +0100, Simon Glass wrote:
Hi Sjoerd,
static int designware_eth_send(struct udevice *dev, void *packet, int length) diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 47e727b..b45599b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -236,6 +236,10 @@ struct dw_eth_dev { #endif struct phy_device *phydev; struct mii_dev *bus;
+#ifdef CONFIG_DM_ETH
int (*started)(struct udevice *dev);
+#endif
With driver model we should not need to add such hooks. is this needed because we don't have a PHY uclass yet?
Essentially I need to be able to configure one of the GMAC clocks depending on the result of the phy negotiation. Looking at the linux kernel this seems a rather common item for the dw gmac interface.
I guess, I could do without that hook by exporting all functions required to fill the eth_ops struct and override the start function. Would you prefer that?
I guess a PHY uclass would also help here, assuming such a uclass would provide a callback for link state changes (e.g. like of_phy_connect in Linux).
};
#ifdef CONFIG_DM_ETH
2.5.3
Regards, Simon

Hi Sjoerd,
On Mon, Oct 5, 2015 at 3:55 AM, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
On Sat, 2015-10-03 at 15:30 +0100, Simon Glass wrote:
Hi Sjoerd,
static int designware_eth_send(struct udevice *dev, void *packet, int length) diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 47e727b..b45599b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -236,6 +236,10 @@ struct dw_eth_dev { #endif struct phy_device *phydev; struct mii_dev *bus;
+#ifdef CONFIG_DM_ETH
int (*started)(struct udevice *dev);
+#endif
With driver model we should not need to add such hooks. is this needed because we don't have a PHY uclass yet?
Essentially I need to be able to configure one of the GMAC clocks depending on the result of the phy negotiation. Looking at the linux kernel this seems a rather common item for the dw gmac interface.
I guess, I could do without that hook by exporting all functions required to fill the eth_ops struct and override the start function. Would you prefer that?
I prefer the hook.
I guess a PHY uclass would also help here, assuming such a uclass would provide a callback for link state changes (e.g. like of_phy_connect in Linux).
I agree that once we have the phy uclass then we should handle it much more like Linux, but for now the hook seems cleaner.
};
#ifdef CONFIG_DM_ETH
2.5.3
Regards, Simon
-- Sjoerd Simons Collabora Ltd. _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi,
On Tue, Oct 6, 2015 at 12:39 AM, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Sjoerd,
On Mon, Oct 5, 2015 at 3:55 AM, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
On Sat, 2015-10-03 at 15:30 +0100, Simon Glass wrote:
Hi Sjoerd,
static int designware_eth_send(struct udevice *dev, void *packet, int length) diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 47e727b..b45599b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -236,6 +236,10 @@ struct dw_eth_dev { #endif struct phy_device *phydev; struct mii_dev *bus;
+#ifdef CONFIG_DM_ETH
int (*started)(struct udevice *dev);
+#endif
With driver model we should not need to add such hooks. is this needed because we don't have a PHY uclass yet?
Essentially I need to be able to configure one of the GMAC clocks depending on the result of the phy negotiation. Looking at the linux kernel this seems a rather common item for the dw gmac interface.
I guess, I could do without that hook by exporting all functions required to fill the eth_ops struct and override the start function. Would you prefer that?
I prefer the hook.
I guess a PHY uclass would also help here, assuming such a uclass would provide a callback for link state changes (e.g. like of_phy_connect in Linux).
From what I read to this codes, the work done in the hook is to
program the MAC's clock, not the PHY. So not sure if the PHY uclass can help here.
I agree that once we have the phy uclass then we should handle it much more like Linux, but for now the hook seems cleaner.
Has anyone looked at my suggestion about where we should insert the hook?
Regards, Bin

Hi Bin,
On Wed, Oct 7, 2015 at 4:45 AM, Bin Meng bmeng.cn@gmail.com wrote:
Hi,
On Tue, Oct 6, 2015 at 12:39 AM, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Sjoerd,
On Mon, Oct 5, 2015 at 3:55 AM, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
On Sat, 2015-10-03 at 15:30 +0100, Simon Glass wrote:
Hi Sjoerd,
static int designware_eth_send(struct udevice *dev, void *packet, int length) diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 47e727b..b45599b 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -236,6 +236,10 @@ struct dw_eth_dev { #endif struct phy_device *phydev; struct mii_dev *bus;
+#ifdef CONFIG_DM_ETH
int (*started)(struct udevice *dev);
+#endif
With driver model we should not need to add such hooks. is this needed because we don't have a PHY uclass yet?
Essentially I need to be able to configure one of the GMAC clocks depending on the result of the phy negotiation. Looking at the linux kernel this seems a rather common item for the dw gmac interface.
I guess, I could do without that hook by exporting all functions required to fill the eth_ops struct and override the start function. Would you prefer that?
I prefer the hook.
I guess a PHY uclass would also help here, assuming such a uclass would provide a callback for link state changes (e.g. like of_phy_connect in Linux).
From what I read to this codes, the work done in the hook is to program the MAC's clock, not the PHY. So not sure if the PHY uclass can help here.
I agree that once we have the phy uclass then we should handle it much more like Linux, but for now the hook seems cleaner.
Has anyone looked at my suggestion about where we should insert the hook?
I looked at this today and agree that for the DW driver, that is a more appropriate place to put this hook (especially if renamed as you proposed).
Ultimately I still think it will be better to have a hook added to UCLASS_ETH that is invoked by UCLASS_ETH_PHY on link change. This way it is available to other eth drivers as well. I know that we will also need this for the macb driver.
-Joe

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 ---
drivers/net/Kconfig | 7 +++ drivers/net/Makefile | 1 + drivers/net/gmac_rk3288.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 drivers/net/gmac_rk3288.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bbec6a6..312c660 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -92,4 +92,11 @@ config PCH_GBE This MAC is present in Intel Platform Controller Hub EG20T. It supports 10/100/1000 Mbps operation.
+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 150470c..f0a3992 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..6e92c8e --- /dev/null +++ b/drivers/net/gmac_rk3288.c @@ -0,0 +1,140 @@ +/* + * (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" + +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_started(struct udevice *dev) +{ + struct rk3288_grf *grf; + struct dw_eth_dev *priv = dev_get_priv(dev); + 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); + enum periph_id periph_id; + struct udevice *pinctrl, *clk; + struct rk3288_grf *grf; + + ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl); + if (ret) + return ret; + + ret = pinctrl_get_periph_id(pinctrl, dev); + if (ret < 0) + return ret; + + periph_id = ret; + ret = pinctrl_request(pinctrl, periph_id, 0); + if (ret) + return ret; + + ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &clk); + if (ret) + return ret; + + ret = clk_set_periph_rate(clk, periph_id, 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->started = gmac_rk3288_started; + + 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, +};

Hi Sjoerd,
On Thu, Oct 1, 2015 at 5:48 PM, 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
drivers/net/Kconfig | 7 +++ drivers/net/Makefile | 1 + drivers/net/gmac_rk3288.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 drivers/net/gmac_rk3288.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bbec6a6..312c660 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -92,4 +92,11 @@ config PCH_GBE This MAC is present in Intel Platform Controller Hub EG20T. It supports 10/100/1000 Mbps operation.
+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 150470c..f0a3992 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..6e92c8e --- /dev/null +++ b/drivers/net/gmac_rk3288.c @@ -0,0 +1,140 @@ +/*
- (C) Copyright 2015 Sjoerd Simons sjoerd.simons@collabora.co.uk
- SPDX-License-Identifier: GPL-2.0+
- */
+/*
- Rockchip GMAC ethernet IP driver for U-Boot
- */
nits: please use one-line comment format for this.
+#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"
+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,
nits: please remove the space after fdtdec_get_int
"tx_delay", 0x30);
nits: and to make this indention match the opening ( above
pdata->rx_delay = fdtdec_get_int (gd->fdt_blob, dev->of_offset,
"rx_delay", 0x10);
nits: ditto
return designware_eth_ofdata_to_platdata(dev);
+}
+static int gmac_rk3288_started(struct udevice *dev) +{
struct rk3288_grf *grf;
struct dw_eth_dev *priv = dev_get_priv(dev);
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);
enum periph_id periph_id;
struct udevice *pinctrl, *clk;
struct rk3288_grf *grf;
ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
if (ret)
return ret;
ret = pinctrl_get_periph_id(pinctrl, dev);
if (ret < 0)
return ret;
periph_id = ret;
ret = pinctrl_request(pinctrl, periph_id, 0);
if (ret)
return ret;
ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &clk);
if (ret)
return ret;
ret = clk_set_periph_rate(clk, periph_id, 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->started = gmac_rk3288_started;
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,
nits: please indent.
+};
Regards, Bin

Hi Sjoerd,
On 1 October 2015 at 10:48, 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
drivers/net/Kconfig | 7 +++ drivers/net/Makefile | 1 + drivers/net/gmac_rk3288.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 drivers/net/gmac_rk3288.c
Apart from Bin's nits:
Acked-by: Simon Glass sjg@chromium.org
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bbec6a6..312c660 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -92,4 +92,11 @@ config PCH_GBE This MAC is present in Intel Platform Controller Hub EG20T. It supports 10/100/1000 Mbps operation.
+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 150470c..f0a3992 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..6e92c8e --- /dev/null +++ b/drivers/net/gmac_rk3288.c @@ -0,0 +1,140 @@ +/*
- (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"
+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_started(struct udevice *dev) +{
struct rk3288_grf *grf;
struct dw_eth_dev *priv = dev_get_priv(dev);
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);
enum periph_id periph_id;
struct udevice *pinctrl, *clk;
struct rk3288_grf *grf;
ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
if (ret)
return ret;
ret = pinctrl_get_periph_id(pinctrl, dev);
if (ret < 0)
return ret;
periph_id = ret;
ret = pinctrl_request(pinctrl, periph_id, 0);
if (ret)
return ret;
ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &clk);
if (ret)
return ret;
ret = clk_set_periph_rate(clk, periph_id, 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->started = gmac_rk3288_started;
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,
+};
2.5.3
Regards, Simon

Add a definition for the gmac interface to the firefly device-tree. Copied verbatim from the linux kernel.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk ---
arch/arm/dts/rk3288-firefly.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/arch/arm/dts/rk3288-firefly.dtsi b/arch/arm/dts/rk3288-firefly.dtsi index 5aec1b8..072eaa6 100644 --- a/arch/arm/dts/rk3288-firefly.dtsi +++ b/arch/arm/dts/rk3288-firefly.dtsi @@ -146,6 +146,22 @@ status = "okay"; };
+&gmac { + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&ext_gmac>; + clock_in_out = "input"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>; + phy-supply = <&vcc_lan>; + phy-mode = "rgmii"; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-gpio = <&gpio4 8 GPIO_ACTIVE_LOW>; + tx_delay = <0x30>; + rx_delay = <0x10>; + status = "okay"; +}; + &hdmi { ddc-i2c-bus = <&i2c5>; status = "okay";

On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Add a definition for the gmac interface to the firefly device-tree. Copied verbatim from the linux kernel.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
arch/arm/dts/rk3288-firefly.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
Acked-by: Simon Glass sjg@chromium.org

Enable the various configuration option required to get the ethernet interface up and running.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk ---
configs/firefly-rk3288_defconfig | 5 +++++ include/configs/firefly-rk3288.h | 3 +++ 2 files changed, 8 insertions(+)
diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index edb2db2..94c59c3 100644 --- a/configs/firefly-rk3288_defconfig +++ b/configs/firefly-rk3288_defconfig @@ -22,6 +22,11 @@ CONFIG_LED_GPIO=y CONFIG_RESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y +CONFIG_DM_ETH=y +CONFIG_NETDEVICES=y +CONFIG_ETH_DESIGNWARE=y +CONFIG_GMAC_RK3288=y +CONFIG_SYS_I2C_ROCKCHIP=y CONFIG_PINCTRL=y # CONFIG_PINCTRL_FULL is not set CONFIG_SPL_PINCTRL=y diff --git a/include/configs/firefly-rk3288.h b/include/configs/firefly-rk3288.h index 4c5c4dd..43d4df9 100644 --- a/include/configs/firefly-rk3288.h +++ b/include/configs/firefly-rk3288.h @@ -10,6 +10,9 @@ #include <configs/rk3288_common.h>
#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_PHYLIB +#define CONFIG_LIB_RAND +#define CONFIG_NET_RANDOM_ETHADDR
#define CONFIG_ENV_IS_IN_MMC #define CONFIG_SYS_MMC_ENV_DEV 0

On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Enable the various configuration option required to get the ethernet interface up and running.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
configs/firefly-rk3288_defconfig | 5 +++++ include/configs/firefly-rk3288.h | 3 +++ 2 files changed, 8 insertions(+)
Acked-by: Simon Glass sjg@chromium.org

Now that at least on the firefly board we have network support, enable PXE and DHCP boot targets by default.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk ---
include/configs/rk3288_common.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index 5b1653e..12f2ce7 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -102,7 +102,9 @@ /* First try to boot from SD (index 0), then eMMC (index 1 */ #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 0) \ - func(MMC, mmc, 1) + func(MMC, mmc, 1) \ + func(PXE, pxe, na) \ + func(DHCP, dchp, na)
#include <config_distro_bootcmd.h>

On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Now that at least on the firefly board we have network support, enable PXE and DHCP boot targets by default.
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
include/configs/rk3288_common.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Acked-by: Simon Glass sjg@chromium.org

Now that ethernet support works, it can be dropped from the rockchip TODO
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
---
doc/README.rockchip | 1 - 1 file changed, 1 deletion(-)
diff --git a/doc/README.rockchip b/doc/README.rockchip index 87ce9d2..bb5e234 100644 --- a/doc/README.rockchip +++ b/doc/README.rockchip @@ -170,7 +170,6 @@ Immediate priorities are: - PMIC and regulators (only ACT8846 is supported at present) - LCD and HDMI - Run CPU at full speed -- Ethernet - NAND flash - Support for other Rockchip parts - Boot U-Boot proper over USB OTG (at present only SPL works)

On 1 October 2015 at 10:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
Now that ethernet support works, it can be dropped from the rockchip TODO
Signed-off-by: Sjoerd Simons sjoerd.simons@collabora.co.uk
doc/README.rockchip | 1 - 1 file changed, 1 deletion(-)
Acked-by: Simon Glass sjg@chromium.org

Hi Sjoerd,
On 1 October 2015 at 03:48, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
This series adds support for the GMAC Ethernet interface on RK3288 SoCs.
To add support I've taken a slightly different approach then some of the other boards with a designware IP block, by creating a new driver to take care of the platfrom glue which subclasses the main designware driver instead of adding the compatibility string the designware driver directly and doing the SoC specific setup in the board files. This seems quite a bit more elegant in a device model based world.
As the pinctrl and clock drivers are quite simple at the moment (hardcoded settings rather then retrieved from device-tree) the pinctrl and clock settings added in this series assume the setup for the ethernet interface used is for Firefly and Radxa Rock 2. Specifically It assumes the gmac is driven by an external clock, GPIO4B0 is the phy reset and the phy interface mode is RGMII.
I've only tested this series on a Radxa Rock 2 board, it would be great if someone could test this on other boards with the designware IP especially for those with the reset GPIO in devicetree (e.g. some of the Allwinner boards).
Sjoerd Simons (10): rockchip: rk3288: Add pinctrl support for the gmac ethernet interface rockchip: rk3288: Add clock support for the gmac ethernet interface net: designware: support phy reset device-tree bindings net: designware: Export various functions/struct to allow subclassing net: designware: Add a post-started hook net: gmac_rk3288: Add RK3288 GMAC driver rockchip: rk3288-firefly: Add gmac definition rockchip: firefly: Enable networking support rockchip: Add PXE and DHCP to the default boot targets rockchip: Drop Ethernet from the TODO
arch/arm/dts/rk3288-firefly.dtsi | 16 ++ arch/arm/include/asm/arch-rockchip/cru_rk3288.h | 17 ++ arch/arm/include/asm/arch-rockchip/grf_rk3288.h | 228 ++++++++++++++++++++++++ arch/arm/include/asm/arch-rockchip/periph.h | 1 + configs/firefly-rk3288_defconfig | 5 + doc/README.rockchip | 1 - drivers/clk/clk_rk3288.c | 16 ++ drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/designware.c | 91 ++++++++-- drivers/net/designware.h | 19 ++ drivers/net/gmac_rk3288.c | 140 +++++++++++++++ drivers/pinctrl/rockchip/pinctrl_rk3288.c | 102 +++++++++++ include/configs/firefly-rk3288.h | 3 + include/configs/rk3288_common.h | 4 +- 15 files changed, 639 insertions(+), 12 deletions(-) create mode 100644 drivers/net/gmac_rk3288.c
Are you planning to respin this series? I'd like to pick it up for rockchip at some point. There were a few comments I think, mostly minor.
FYI there is some additional work at u-boot-rockchip/rkd-working. It includes some pinctrl and clock additions that might be useful.
Regards, Simon

On Sun, 2016-01-03 at 12:52 -0700, Simon Glass wrote:
Hi Sjoerd,
On 1 October 2015 at 03:48, Sjoerd Simons <sjoerd.simons@collabora.co .uk> wrote:
This series adds support for the GMAC Ethernet interface on RK3288 SoC
Are you planning to respin this series? I'd like to pick it up for rockchip at some point. There were a few comments I think, mostly minor.
FYI there is some additional work at u-boot-rockchip/rkd-working. It includes some pinctrl and clock additions that might be useful.
Yeah I'd like to respin this, unfortunately the end of last year was silly busy for me hence not getting round to it (Typical end-of-year situation as most projects want things finished before everyone disappears for a few weeks over christmas etc)
Wrt. the series IIRC the biggest comment was that it should use the proper pinctrl infrastructure, for which it seems you may have already laid the groundwork \o/ :) So yes more then happy to respin on rkd- working in the next week or so.
Regards, Simon

Hi Sjoerd,
On 4 January 2016 at 01:32, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
On Sun, 2016-01-03 at 12:52 -0700, Simon Glass wrote:
Hi Sjoerd,
On 1 October 2015 at 03:48, Sjoerd Simons <sjoerd.simons@collabora.co .uk> wrote:
This series adds support for the GMAC Ethernet interface on RK3288 SoC
Are you planning to respin this series? I'd like to pick it up for rockchip at some point. There were a few comments I think, mostly minor.
FYI there is some additional work at u-boot-rockchip/rkd-working. It includes some pinctrl and clock additions that might be useful.
Yeah I'd like to respin this, unfortunately the end of last year was silly busy for me hence not getting round to it (Typical end-of-year situation as most projects want things finished before everyone disappears for a few weeks over christmas etc)
Wrt. the series IIRC the biggest comment was that it should use the proper pinctrl infrastructure, for which it seems you may have already laid the groundwork \o/ :) So yes more then happy to respin on rkd- working in the next week or so.
Great! I hope to get patches out for some of this work in the two weeks. But feel free to base on any of the patches and we can sort it out later.
Regards, Simon
participants (4)
-
Bin Meng
-
Joe Hershberger
-
Simon Glass
-
Sjoerd Simons